ModelSpace
All Classes Namespaces Functions Variables Enumerations Pages
Frame.hpp
1/******************************************************************************
2* Copyright (c) ATTX LLC 2024. All Rights Reserved.
3*
4* This software and associated documentation (the "Software") are the
5* proprietary and confidential information of ATTX, LLC. The Software is
6* furnished under a license agreement between ATTX and the user organization
7* and may be used or copied only in accordance with the terms of the agreement.
8* Refer to 'license/attx_license.adoc' for standard license terms.
9*
10* EXPORT CONTROL NOTICE: THIS SOFTWARE MAY INCLUDE CONTENT CONTROLLED UNDER THE
11* INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) OR THE EXPORT ADMINISTRATION
12* REGULATIONS (EAR99). No part of the Software may be used, reproduced, or
13* transmitted in any form or by any means, for any purpose, without the express
14* written permission of ATTX, LLC.
15******************************************************************************/
16/*
17Frame header file
18
19Author: Alex Reynolds
20*/
21#ifndef FRAME_HPP
22#define FRAME_HPP
23
24#include "core/clockwerkerrors.h"
25#include "core/vectormath.hpp"
26#include "data_management/GraphTreeObject.h"
27#include "data_management/DataIO.hpp"
28#include "Joint.hpp"
29#include "DCM.hpp"
30#include "Quaternion.hpp"
31#include "MRP.hpp"
32#include "Euler321.hpp"
33#include "attitudemath.hpp"
34
35#define NUM_INTEGRATED_STATES 13
36
37namespace clockwerk {
38
39 /// Forward declaration of frame types
40 template <typename T> class Body;
41 template <typename T> class Node;
42
43 /// @brief Frame class definition
44 ///
45 /// This file defines the frame class, which is the base of all 6-DOF
46 /// kinematics and dynamics. This frame class is designed for recursive
47 /// chaining, and represents the relationship of a frame to its parent.
48 ///
49 /// The frame class tracks the frame's relationship to its parent via the
50 /// following four key parameters:
51 /// pos_f_p__p - The position of the child frame relative to its parent, in PARENT coords
52 /// vel_f_p__p - The velocity of the child frame IN THE PARENT FRAME, in PARENT coords.
53 /// quat_f_p - The attitude quaternion of the child frame relative to its parent
54 /// ang_vel_f_p__f - The angular velocity of the child frame relative to its parent, in FRAME coords
55 ///
56 /// Frame relationships to their parents are also defined by the Joint class,
57 /// which is a method for tracking the degrees of freedom (and thus, which
58 /// channels can have a nonzero velocity value). Each frame has a translational
59 /// and rotational joint, which sets degrees of freedom in the velocity (represented
60 /// in parent coordinates) and angular velocity (represented in frame coordinates).
61 /// The frame joint is set to fully fixed by default, but can be set to free or
62 /// modified later.
63 ///
64 /// Frame states may be set by calling the parent relative states directly (they are
65 /// DataIO objects, but buyer beware that you can set the frame states with almost
66 /// no restrictions.)
67 ///
68 /// Alternatively, users may get and set frame states relative to the root frame
69 /// by calling the root relative functions which are provided by this class. The
70 /// functions rootRelPosition, rootRelVelocity, rootRel... and so on all return
71 /// the frame state relative to root. The functions setRootRel... will set the
72 /// frame's state relative to the root frame. For many applications it is better
73 /// to work with the root functions, rather than parent relative functions.
74 ///
75 /// Naming conventions
76 /// ------------------
77 /// - The naming convention for all vectors is:
78 /// variablename_obj1_obj2__frameN (note the double underscore preceding frame)
79 /// and reads back as:
80 /// "variable variablename representing the relationship between obj1 and obj2
81 /// represented in frameN"
82 /// - The naming convention for attitude representations is the same as the above,
83 /// with the trailing frame representation omitted.
84 /// - The omega vector is sometimes denoted by w and assumed frame consistent with
85 /// the attitude representation. For example, if a DCM represents the
86 /// relative orientation between two frames [BN] the omega vector is
87 /// assumed to be w_(B/N)
88 /// - The frame represented by this class is denoted with "f" for simplicity
89 /// - Unless otherwise noted angles and angular rates are in RADIANS
90 /// - Where relevant and unless otherwise noted, all units are metric
91 template <typename T=double>
92 class Frame : public GraphTreeObject {
93 public:
94 /// @brief Constructor for the frame object
95 /// @param name Name of the frame
96 /// @param par Parent of the frame. Defaults to nullptr
97 /// @param free Boolean indicating whether frame should be free or fixed.
98 Frame(const std::string &name, Frame<T>* par=nullptr, bool free = false);
99
100 /// @brief Function to get reference to the frame's translational joint
101 /// @return The frame's translational joint
102 Joint<T>& tJoint() {return _t_joint;}
103
104 /// @brief Function to get reference to the frame's rotational joint
105 /// @return The frame's rotational joint
106 Joint<T>& rJoint() {return _r_joint;}
107
108 /// @brief Function to assign the frame's parent via pointer
109 /// @param new_parent The new parent to assign the node to
110 /// @return Error code corresponding to success/failure
111 /// @note This function is the only method to ADD or REMOVE a node
112 /// from a tree. To add, pass the address to a GraphTreeObject
113 /// to this function. To remove, pass a nullptr. Note that
114 /// parents for objects on an existing tree can be reassigned
115 int parent(Frame<T>* new_parent);
116 Frame<T>* parent() {return _parent;}
117
118 /** Position of the frame with respect to parent, in parent coordinates */
119 clockwerk::DataIO<CartesianVector<T, 3>> pos_f_p__p =
120 clockwerk::DataIO<CartesianVector<T, 3>>(nullptr, "pos_f_p__p", CartesianVector<T, 3>());
121 /** Velocity of the frame with respect to parent, in parent coordinates.
122 * Note that this is the velocity IN the parent frame, which takes into account rotation. */
123 clockwerk::DataIO<CartesianVector<T, 3>> vel_f_p__p =
124 clockwerk::DataIO<CartesianVector<T, 3>>(nullptr, "vel_f_p__p", CartesianVector<T, 3>());
125 /** Attitude quaternion of the frame with respect to parent */
126 clockwerk::DataIO<Quaternion<T>> quat_f_p =
127 clockwerk::DataIO<Quaternion<T>>(nullptr, "quat_f_p", Quaternion<T>());
128 /** Angular velocity of the frame with respect to parent, in frame coordinates */
129 clockwerk::DataIO<CartesianVector<T, 3>> ang_vel_f_p__f =
130 clockwerk::DataIO<CartesianVector<T, 3>>(nullptr, "ang_vel_f_p__f", CartesianVector<T, 3>());
131
132 /* Nice handle to the frame itself for mapping*/
133 clockwerk::DataIO<Frame<T>*> self_id = clockwerk::DataIO<Frame<T>*>(nullptr, "self_id", this);
134
135 /// @brief Function to set parent relative acceleration of frame
136 /// @param accel acceleration of frame relative to parent in parent frame coords
137 void setParentRelAcceleration(CartesianVector<T, 3> accel) {_acc_f_p__p = _t_joint.freedom()*accel;}
138
139 /// @brief Function to set parent relative angular acceleration
140 /// @param alpha angular accel of the frame relative to parent in parent frame coords
141 void setParentRelAngularAcceleration(CartesianVector<T, 3> alpha) {_alpha_f_p__f = _r_joint.freedom()*alpha;}
142
143 /// @brief Function to get the acceleration of the frame relative to parent expressed in parent coords
144 /// @return Accel relative to parent in parent coords
146
147 /// @brief Function to get angular acceleration relative to parent in frame coords
148 /// @return Angular accel relative to parent in frame coords
149 CartesianVector<T, 3> parentRelAngularAcceleration() {return _r_joint.freedom()*_alpha_f_p__f;}
150
151 /// @brief Returns the position of the frame origin wrt the root origin, in root coordinates
152 /// @param pos_o_root_root Implicit return of position of origin relative to root, in root
153 /// @return Error code corresponding to success/failure
154 /// @note Overloaded for explicit and implicit return
155 void rootRelPosition(CartesianVector<T, 3> &pos_o_root__root);
156 CartesianVector<T, 3> rootRelPosition();
157
158 /// @brief Returns the velocity of the frame origin wrt the root origin, in root coordinates
159 /// @param vel_o_root_root Implicit return of velocity of origin relative to root in root
160 /// @return Error code corresponding to success/failure
161 /// @note Overloaded for explicit and implicit return
162 void rootRelVelocity(CartesianVector<T, 3> &vel_o_root__root);
163 CartesianVector<T, 3> rootRelVelocity();
164
165 /// @brief Returns the acceleration of the frame origin wrt the root origin, in root coordinates
166 /// @param acc_o_root_root Implicit return of acceleration of origin relative to root, in root
167 /// @return Error code corresponding to success/failure
168 /// @note Overloaded for explicit and implicit return
169 void rootRelAcceleration(CartesianVector<T, 3> &acc_o_root__root);
170 CartesianVector<T, 3> rootRelAcceleration();
171
172 /// @brief Returns the quaternion representing the frame origin wrt the root frame
173 /// @param att_f_root Implicit return of attitude relative to root
174 /// @return Error code corresponding to success/failure
175 /// @note Overloaded for explicit and implicit return
176 void rootRelQuaternion(Quaternion<T> &quat_f_root);
177 Quaternion<T> rootRelQuaternion();
178
179 /// @brief Returns the DCM of the frame origin wrt the root frame
180 /// @param att_f_root Implicit return of attitude relative to root
181 /// @return Error code corresponding to success/failure
182 /// @note Overloaded for explicit and implicit return
183 void rootRelDCM(DCM<T> &dcm_f_root);
184 DCM<T> rootRelDCM();
185
186 /// @brief Returns the angular velocity of the frame origin wrt the root, expressed
187 /// in this frame's coordinates
188 /// @param w_f_root__f Implicit return of angular velocity relative to root,
189 /// expressed in f frame
190 /// @return Error code corresponding to success/failure
191 /// @note Overloaded for explicit and implicit return
192 void rootRelAngularVelocity(CartesianVector<T, 3> &w_f_root__f);
193 CartesianVector<T, 3> rootRelAngularVelocity();
194
195 /// @brief Returns the angular acceleration of the frame origin wrt the root, expressed
196 /// in this frame's coordinates
197 /// @param alpha_f_root__f Implicit return of angular acceleration relative to root,
198 /// expressed in f frame
199 /// @return Error code corresponding to success/failure
200 /// @note Overloaded for explicit and implicit return
201 void rootRelAngularAcceleration(CartesianVector<T, 3> &alpha_f_root__f);
202 CartesianVector<T, 3> rootRelAngularAcceleration();
203
204 /// @brief Function to recurse through the body and its children to apply external
205 /// forces and moments to the "correct" body by resolving them to locations
206 /// where there are degrees of freedom.
207 /// @note Specific implementation of this function for body class. Overwrites
208 /// frame class implementation
210
211 /// @brief Function to recurse through the body and its children to resolve applied
212 /// external forces and moments into acceleration and angular acceleration
213 /// @note Implicitly applies acceleration/ang accel to the body frame
214 /// @note Assumes calcBodyTreeForcesMoments has been called to calculate forces/moments
215 /// @note Specific implementation of this function for body class. Overwrites
216 /// frame class implementation
218
219 /// Getter and setter for integrator pointer
220 void integrator(void* integ_ptr) {_integrator_ptr = integ_ptr;}
221 void* integrator() {return _integrator_ptr;}
222
223 /// @brief Function to set frame state based on NUM_INTEGRATED_STATES-element
224 /// state vector
225 /// @param state NUM_INTEGRATED_STATES-element state vector as [pos][vel][quat][omega]
226 void setStateFromStateVector(const std::array<T, NUM_INTEGRATED_STATES> &state_f_p__f);
227
228 /// @brief Function to return frame state as a NUM_INTEGRATED_STATES-element state vector
229 /// @param state Return of NUM_INTEGRATED_STATES-element state vector as [pos][vel][quat][omega]
230 void getStateAsStateVector(std::array<T, NUM_INTEGRATED_STATES> &state_f_p__f);
231
232 /// @brief Function to get the rate of change in the frame state vector
233 /// @param state_dot Rate of change in each element of the state vector
234 void getStateVectorDot(std::array<T, NUM_INTEGRATED_STATES> &state_dot);
235
236 /// @brief Function to set the frame's position relative to root
237 /// @param pos_f_root__root Position of this frame wrt root frame origin,
238 /// as specified in the root frame
239 /// @note If parent is not yet assigned, will throw error
240 /// @note With great power comes great responsibility. This thing will set
241 /// position to whatever you want, minimal questions asked, independent
242 /// of if you later change attitude, etc.
243 int setRootRelPosition(const CartesianVector<T, 3> &pos_f_root__root);
244
245 /// @brief Function to set the frame's velocity relative to root
246 /// @param vel_f_root__root Velocity of this frame wrt root frame origin,
247 /// as specified in the root frame
248 /// @note If parent is not yet assigned, will throw error
249 /// @note With great power comes great responsibility. This thing will set
250 /// velocity to whatever you want, minimal questions asked, independent
251 /// of if you later change attitude, etc.
252 int setRootRelVelocity(const CartesianVector<T, 3> &vel_f_root__root);
253
254 /// @brief Function to set the frame's attitude relative to root
255 /// @param quat_f_root Attitude of this frame wrt root frame
256 /// @note If parent is not yet assigned, will throw error
257 /// @note With great power comes great responsibility. This thing will set
258 /// attitude to whatever you want, minimal questions asked, independent
259 /// of if you later change attitude, etc.
260 int setRootRelAttitude(const Quaternion<T> &quat_f_root);
261
262 /// @brief Function to set the frame's position relative to root
263 /// @param w_f_root__f Angular velocity of this frame wrt root frame origin,
264 /// as specified in this frame
265 /// @note If parent is not yet assigned, will throw error
266 /// @note With great power comes great responsibility. This thing will set
267 /// ang vel to whatever you want, minimal questions asked, independent
268 /// of if you later change attitude, etc.
269 int setRootRelAngularVelocity(const CartesianVector<T, 3> &w_f_root__f);
270
271 /// @brief Function to get a pointer to this frame's root frame
272 /// @return Pointer to root frame. Pointer to self if this frame is root
274 protected:
275 /// Internal variables to store accelerations applied to this frame. Note: these
276 /// are not states. They are temporary variables and treated slightly differently.
278 CartesianVector<T, 3> _alpha_f_p__f;
279
280 /// Translational and rotational joints relating this frame to its
281 /// parent. Set locked by default.
282 Joint<T> _t_joint; /// Translational
283 Joint<T> _r_joint; /// Rotational
284
285 /// Pointer to the integrator that is integrating this frame.
286 /// Nullptr if unused
287 void* _integrator_ptr = nullptr;
288
289 /// Variable to hold our parent
290 Frame<T>* _parent;
291 };
292
293 template<typename T>
294 Frame<T>::Frame(const std::string &name, Frame<T>* par, bool free)
295 : GraphTreeObject(name),
296 _t_joint(free,free,free),
297 _r_joint(free,free,free) {
298
300
301 _parent = nullptr;
302 if(par != nullptr) {
303 parent(par);
304 }
305 }
306
307 template <typename T>
308 int Frame<T>::parent(Frame<T>* new_parent) {
309 /// First, check if our current parent is a nullptr. If not, we need to remove
310 /// this node from it first. Temporarily assign our parent to nullptr once we've
311 /// done this to prevent a possible broken operation where parent is removed
312 /// but can't be reassigned
313
314 /// Ensure we don't have a circular reference
315 GraphTreeObject* ptr = new_parent;
316 while(ptr != nullptr) {
317 /// Ensure that we don't have a circular reference
318 if(ptr == this) {
320 }
321
322 /// Point further up the tree
323 ptr = ptr->parent();
324 }
325
326 /// Type check our frame and the desired parent to ensure
327 /// our setup is valid
328 if(new_parent != nullptr) {
329 switch(_graph_tree_type) {
330 case FRAME:
331 /// Framess can be the children of anything. We're good here
332 break;
333 case BODY:
334 /// Bodies can be the children of frames and other bodies,
335 /// but not of nodes. Type check and verify our parent
336 /// is not a node
337 if(new_parent->type() == NODE) {
339 }
340 break;
341 case NODE:
342 /// Nodes can be the children of bodies only. If our parent
343 /// is a frame or another node, raise an error
344 if(new_parent->type() == FRAME || new_parent->type() == NODE) {
346 }
347 break;
348 default:
349 /// This should be impossible, but return an error
351 break;
352 }
353 }
354
355 /// Remove child from our parent if we're resetting our
356 /// parent
357 int err;
358 if(_parent != nullptr) {
359 err = _parent->removeChild(this);
360 if(err) {return err;}
361 _parent = nullptr;
362 }
363
364 /// Now add our node to its new parent, so long as our new parent is not a nullptr
365 if(new_parent != nullptr) {
366 err = new_parent->addChild(this);
367 if(err) {return err;}
368 }
369
370 /// Otherwise, we're good to go to add this child to parent -- go ahead
371 _parent = new_parent;
372
373 /// Now update frame stuff for nullpointer parent, which means we're root
374 if(_parent == nullptr) {
375 _t_joint.setFreeAxes(false, false, false);
376 _r_joint.setFreeAxes(false, false, false);
379 _acc_f_p__p = CartesianVector<T, 3>({0.0, 0.0, 0.0});
380 quat_f_p(Quaternion<T>());
382 _alpha_f_p__f = CartesianVector<T, 3>({0.0, 0.0, 0.0});
383 }
384
385 /// Finally, recalculate the rank of this object and its children
387
388 return NO_ERROR;
389 }
390
391 template <typename T>
393 if(_parent == nullptr) {
394 return this;
395 } else {
396 return _parent->getFrameRootPointer();
397 }
398 }
399
400 template <typename T>
401 void Frame<T>::getStateVectorDot(std::array<T, NUM_INTEGRATED_STATES> &state_dot) {
402 // First evaluate our rotational degrees of freedom and integrate
403 if(_r_joint.jointType() == FULLY_LOCKED) {
404 // If our joint is locked all state dot values should be zero
405 for(unsigned int i = 6; i < NUM_INTEGRATED_STATES; i++) {
406 state_dot[i] = 0.0;
407 }
408 } else {
409 // Set our quaternion rate of change from
410 Matrix<T, 4, 1> qdot_f_p;
411 quat_f_p().rate(_r_joint.freedom()*ang_vel_f_p__f(), qdot_f_p);
412 state_dot[6] = qdot_f_p[0][0];
413 state_dot[7] = qdot_f_p[1][0];
414 state_dot[8] = qdot_f_p[2][0];
415 state_dot[9] = qdot_f_p[3][0];
416
417 // Now set our omega rate of change from alpha and our parent
418 CartesianVector<T, 3> omega_dot = _alpha_f_p__f;
419 if(_parent != nullptr) {
420 // If our parent is not nothing, subtract parent's angular acceleration if
421 // we're free to account for case where parent accelerates and we do not.
422 omega_dot = omega_dot - _r_joint.freedom()*(quat_f_p()*_parent->rootRelAngularAcceleration());
423 }
424 state_dot[10] = omega_dot[0];
425 state_dot[11] = omega_dot[1];
426 state_dot[12] = omega_dot[2];
427 }
428
429 // Evaluate our translational degrees of freedom and integrate our velocity/accel
430 if(_t_joint.jointType() == FULLY_LOCKED) {
431 // If our joint is locked all state dot values should be zero
432 for(unsigned int i = 0; i < 6; i++) {
433 state_dot[i] = 0.0;
434 }
435 } else {
436 // Our rate of change in position is just an integration of our velocity
437 vel_f_p__p().get(0, state_dot[0]);
438 vel_f_p__p().get(1, state_dot[1]);
439 vel_f_p__p().get(2, state_dot[2]);
440
441 // Calculate rate of change in velo from in-frame acceleration
442 CartesianVector<T, 3> v_dot = _acc_f_p__p;
443
444 // Now account for cases where our frame is free to its parent and the
445 // parent moves "underneath" it. This includes two cases:
446 // 1. Translational acceleration experienced by the parent
447 // 2. Acceleration due to parent's rotation (because we're tracking state IN parent frame)
448 if(_parent != nullptr) {
449 // Get our dcm parent/root
450 DCM<T> dcm_p_root = _parent->rootRelDCM();
451
452 // Account for case 1 - translational accelearation of parent frame origin
453 v_dot = v_dot - dcm_p_root*_parent->rootRelAcceleration();
454
455 // Account for case 2 - acceleration due to rotating parent frame
456 // Angular acceleration
457 v_dot = v_dot - cross(_parent->rootRelAngularAcceleration(), pos_f_p__p());
458
459 // Coriolis acceleration
460 CartesianVector<T, 3> parent_omega = _parent->rootRelAngularVelocity();
461 v_dot = v_dot - 2.0*cross(parent_omega, vel_f_p__p());
462
463 // Centripetal acceleration
464 v_dot = v_dot - cross(parent_omega, cross(parent_omega, pos_f_p__p()));
465 }
466 v_dot = _t_joint.freedom()*v_dot;
467 v_dot.get(0, state_dot[3]);
468 v_dot.get(1, state_dot[4]);
469 v_dot.get(2, state_dot[5]);
470 }
471 }
472
473 template <typename T>
474 void Frame<T>::setStateFromStateVector(const std::array<T, NUM_INTEGRATED_STATES> &state) {
475 pos_f_p__p(CartesianVector<T, 3>({state[0], state[1], state[2]}));
476 vel_f_p__p(_t_joint.freedom()*CartesianVector<T, 3>({state[3], state[4], state[5]}));
477 Quaternion<T> tmp({state[6], state[7], state[8], state[9]});
478 tmp.unitize();
479 quat_f_p(tmp);
480 ang_vel_f_p__f(_r_joint.freedom()*CartesianVector<T, 3>({state[10], state[11], state[12]}));
481 }
482
483 template <typename T>
484 void Frame<T>::getStateAsStateVector(std::array<T, NUM_INTEGRATED_STATES> &state) {
485 /// Position
486 pos_f_p__p().get(0, state[0]);
487 pos_f_p__p().get(1, state[1]);
488 pos_f_p__p().get(2, state[2]);
489
490 /// Velocity
491 vel_f_p__p().get(0, state[3]);
492 vel_f_p__p().get(1, state[4]);
493 vel_f_p__p().get(2, state[5]);
494
495 /// Attitude - includes normalization
496 quat_f_p().get(0, state[6]);
497 quat_f_p().get(1, state[7]);
498 quat_f_p().get(2, state[8]);
499 quat_f_p().get(3, state[9]);
500
501 /// Angular velocity
502 ang_vel_f_p__f().get(0, state[10]);
503 ang_vel_f_p__f().get(1, state[11]);
504 ang_vel_f_p__f().get(2, state[12]);
505 }
506
507 template <typename T>
508 void Frame<T>::rootRelPosition(CartesianVector<T, 3> &pos_f_root__root) {
509 /// First, evaluate if the current frame is root and continue to recurse up the chain if not
510 if(_parent == nullptr) {
511 /// We're the root frame! Set our position to zero and return
512 pos_f_root__root.set(0, 0.0);
513 pos_f_root__root.set(1, 0.0);
514 pos_f_root__root.set(2, 0.0);
515 } else {
516 /// Recursively run up our tree until we find root
517 _parent->rootRelPosition(pos_f_root__root);
518
519 // We're on the return now. Take our contribution and add this frame's
520 DCM<T> dcm_p_root = _parent->rootRelDCM(); // Get our dcm parent/root
521 pos_f_root__root = pos_f_root__root + dcm_p_root.inverse()*pos_f_p__p(); // Add our position in root to total
522 }
523 }
524 template <typename T>
525 CartesianVector<T, 3> Frame<T>::rootRelPosition() {
526 CartesianVector<T, 3> tmp;
527 rootRelPosition(tmp);
528 return tmp;
529 }
530
531 template <typename T>
532 void Frame<T>::rootRelVelocity(CartesianVector<T, 3> &vel_f_root__root) {
533 /// First, evaluate if the current frame is root and continue to recurse up the chain if not
534 if(_parent == nullptr) {
535 /// We're the root frame! Set our velocity to zero and return
536 vel_f_root__root.set(0, 0.0);
537 vel_f_root__root.set(1, 0.0);
538 vel_f_root__root.set(2, 0.0);
539 } else {
540 // Recurse further up the tree until we find root
541 _parent->rootRelVelocity(vel_f_root__root);
542
543 // Now we're on the return. Calculate contribution from this frame in parent coords
544 CartesianVector<T, 3> frame_contrib__p = cross(_parent->rootRelAngularVelocity(), pos_f_p__p());
545 if(_t_joint.jointType() != FULLY_LOCKED) {
546 eAdd(frame_contrib__p, _t_joint.freedom()*vel_f_p__p(), frame_contrib__p);
547 }
548
549 // And add contribution to the total
550 DCM<T> dcm_p_root = _parent->rootRelDCM();
551 vel_f_root__root = vel_f_root__root + dcm_p_root.inverse()*frame_contrib__p;
552 }
553 }
554 template <typename T>
555 CartesianVector<T, 3> Frame<T>::rootRelVelocity() {
556 CartesianVector<T, 3> tmp;
557 rootRelVelocity(tmp);
558 return tmp;
559 }
560
561 template <typename T>
562 void Frame<T>::rootRelAcceleration(CartesianVector<T, 3> &acc_f_root__root) {
563 /// First, evaluate if the current frame is root and continue to recurse up the chain if not
564 if(_parent == nullptr) {
565 /// We're the root frame! Set our acceleration to zero and return
566 acc_f_root__root.set(0, 0.0);
567 acc_f_root__root.set(1, 0.0);
568 acc_f_root__root.set(2, 0.0);
569 } else {
570 // Recurse further up the tree until we find root
571 _parent->rootRelAcceleration(acc_f_root__root);
572
573 // Now we're on the return. Calculate contribution from this frame in parent coords
574 // Contribution due to angular acceleration term alpha cross r
575 CartesianVector<T, 3> frame_contrib__p = cross(_parent->rootRelAngularAcceleration(), pos_f_p__p());
576
577 // Contribution due to coriolis acceleration term
578 frame_contrib__p = frame_contrib__p + 2.0*cross(_parent->rootRelAngularVelocity(), _t_joint.freedom()*vel_f_p__p());
579
580 // Contribution due to centripetal acceleration
581 frame_contrib__p = frame_contrib__p
582 + cross(_parent->rootRelAngularVelocity(), cross(_parent->rootRelAngularVelocity(), pos_f_p__p()));
583
584 // Contribution due to in-frame acceleration
585 if(_t_joint.jointType() != FULLY_LOCKED) {
586 frame_contrib__p = frame_contrib__p + _t_joint.freedom()*_acc_f_p__p;
587 }
588
589 // And add contribution to the total
590 DCM<T> dcm_p_root = _parent->rootRelDCM();
591 acc_f_root__root = acc_f_root__root + dcm_p_root.inverse()*frame_contrib__p;
592 }
593 }
594 template <typename T>
595 CartesianVector<T, 3> Frame<T>::rootRelAcceleration() {
596 CartesianVector<T, 3> tmp;
597 rootRelAcceleration(tmp);
598 return tmp;
599 }
600
601 template <typename T>
602 void Frame<T>::rootRelAngularVelocity(CartesianVector<T, 3> &w_f_root__f) {
603 /// First, evaluate if the current frame is root and continue to recurse up the chain if not
604 if(_parent == nullptr) {
605 /// We're the root frame! Set our angular velocity to zero and return
606 w_f_root__f.set(0, 0.0);
607 w_f_root__f.set(1, 0.0);
608 w_f_root__f.set(2, 0.0);
609 } else {
610 // Recurse further up the tree until we find root
611 _parent->rootRelAngularVelocity(w_f_root__f);
612
613 /// Now, we're returning and our parent frame's result has been calculated. Add this
614 /// frame's contribution (in this frame) and return
615 /// First get the previous position calculation in this frame's coordinates
616 w_f_root__f = quat_f_p()*w_f_root__f + _r_joint.freedom()*ang_vel_f_p__f();
617 }
618 }
619 template <typename T>
620 CartesianVector<T, 3> Frame<T>::rootRelAngularVelocity() {
621 CartesianVector<T, 3> tmp;
622 rootRelAngularVelocity(tmp);
623 return tmp;
624 }
625
626 template <typename T>
627 void Frame<T>::rootRelAngularAcceleration(CartesianVector<T, 3> &alpha_f_root__f) {
628 /// First, evaluate if the current frame is root and continue to recurse up the chain if not
629 if(_parent == nullptr) {
630 /// We're the root frame! Set our angular velocity to zero and return
631 alpha_f_root__f.set(0, 0.0);
632 alpha_f_root__f.set(1, 0.0);
633 alpha_f_root__f.set(2, 0.0);
634 } else {
635 // Recurse further up the tree until we find root
636 _parent->rootRelAngularAcceleration(alpha_f_root__f);
637
638 /// Now, we're returning and our parent frame's result has been calculated. Add this
639 /// frame's contribution (in this frame) and return
640 alpha_f_root__f = quat_f_p()*alpha_f_root__f + _r_joint.freedom()*_alpha_f_p__f;
641 }
642 }
643 template <typename T>
644 CartesianVector<T, 3> Frame<T>::rootRelAngularAcceleration() {
645 CartesianVector<T, 3> tmp;
646 rootRelAngularAcceleration(tmp);
647 return tmp;
648 }
649
650 template <typename T>
651 void Frame<T>::rootRelQuaternion(Quaternion<T> &quat_f_root) {
652 /// Really this function is just a wrapper around our DCM getter... so do that
653 rootRelDCM().toQuaternion(quat_f_root);
654 }
655 template <typename T>
656 Quaternion<T> Frame<T>::rootRelQuaternion() {
657 Quaternion<T> tmp;
658 rootRelQuaternion(tmp);
659 return tmp;
660 }
661
662 template <typename T>
663 void Frame<T>::rootRelDCM(DCM<T> &dcm_f_root) {
664 /// First, evaluate if the current frame is root and continue to recurse up the chain if not
665 if(_parent == nullptr) {
666 /// We're the root frame! Set our angular velocity to zero and return
667 dcm_f_root = DCM<T>();
668 } else {
669 // Recurse further up the tree until we find root
670 _parent->rootRelDCM(dcm_f_root);
671
672 /// Now, we're returning. Add our frame's contribution to the total
673 dcm_f_root = quat_f_p().toDCM()*dcm_f_root;
674 }
675 }
676 template <typename T>
677 DCM<T> Frame<T>::rootRelDCM() {
678 DCM<T> tmp;
679 rootRelDCM(tmp);
680 return tmp;
681 }
682
683 template <typename T>
685 /// This calculation is executed from the tree "leaves" in, so we recurse first and execute
686 /// calculations on our way back out
687 /// If we have children, get their stuff
688 if(this->nChildren()) {
689 for(unsigned int i = 0; i < this->nChildren(); i++) {
690 /// Our pointer is technically stored as graph tree object -- cast to frame
691 Frame<T>* ptr = (Frame<T>*)GraphTreeObject::_children[i];
692 /// We ignore anything that is not a node or a body -- handle both appropriately
693 if(ptr->type() == BODY) {
694 /// Recurse further, but now through body rather than frame
695 Body<T>* body_ptr = (Body<T>*)ptr;
696 body_ptr->calcFrameTreeExtForcesMoments();
697 } else {
698 /// We're looking at a frame. Don't do anything, but recurse
699 /// further to see if its children do anything interesting
700 ptr->calcFrameTreeExtForcesMoments();
701 }
702 /// Note: we should never have a node as the child of a frame,
703 /// but just in case the worst case scenario here is we'll try
704 /// to recurse into it and treat it as a frame
705 }
706 }
707
708 return NO_ERROR;
709 }
710
711 template <typename T>
713 /// Do nothing because frames only apply their internal kinematics.
714 /// They do not have external forces/moments applied by definition
715
716 /// Recurse through children
717 if(this->nChildren()) {
718 for(unsigned int i = 0; i < this->nChildren(); i++) {
719 /// Our pointer is technically stored as graph tree object -- cast to frame
720 Frame<T>* ptr = (Frame<T>*)GraphTreeObject::_children[i];
721 /// We ignore anything that is not a node or a body -- handle both appropriately
722 if(ptr->type() == BODY) {
723 /// Recurse further, but now through body rather than frame
724 Body<T>* body_ptr = (Body<T>*)ptr;
725 body_ptr->calcFrameTreeExtAcceleration();
726 } else {
727 /// We're looking at a frame. Don't do anything, but recurse
728 /// further to see if its children do anything interesting
729 ptr->calcFrameTreeExtAcceleration();
730 }
731 /// Note: we should never have a node as the child of a frame,
732 /// but just in case the worst case scenario here is we'll try
733 /// to recurse into it and treat it as a frame
734 }
735 }
736
737 return NO_ERROR;
738 }
739
740 template <typename T>
741 int Frame<T>::setRootRelPosition(const CartesianVector<T, 3> &pos_f_root__root) {
742 /// First let's make sure we've got a valid parent and the frame isn't locked
743 if(_parent == nullptr) {
745 }
746
747 // Now subtract parent position from desired and set value accordingly
748 DCM<T> dcm_p_root = _parent->rootRelDCM();
749 pos_f_p__p(dcm_p_root*(pos_f_root__root - _parent->rootRelPosition()));
750
751 return NO_ERROR;
752 }
753
754 template <typename T>
755 int Frame<T>::setRootRelVelocity(const CartesianVector<T, 3> &vel_f_root__root) {
756 /// First let's make sure we've got a valid parent and the frame isn't locked
757 if(_parent == nullptr) {
759 }
760
761 // Calculate what fixed frame velocity would be at current point
762 DCM<T> dcm_p_root = _parent->rootRelDCM();
763 CartesianVector<T, 3> ff_vel__p = dcm_p_root*_parent->rootRelVelocity();
764 ff_vel__p = ff_vel__p + cross(_parent->rootRelAngularVelocity(), pos_f_p__p());
765
766 // And set parent relative velocity accounting for that
767 vel_f_p__p(_t_joint.freedom()*dcm_p_root*vel_f_root__root - ff_vel__p);
768
769 return NO_ERROR;
770 }
771
772 template <typename T>
773 int Frame<T>::setRootRelAttitude(const Quaternion<T> &quat_f_root) {
774 /// First let's make sure we've got a valid parent and the frame isn't locked
775 if(_parent == nullptr) {
777 }
778
779 // Now subtract parent position from desired and set value accordingly
780 DCM<T> dcm_p_root = _parent->rootRelDCM();
781 DCM<T> dcm_f_p = quat_f_root.toDCM()*dcm_p_root.inverse();
782 quat_f_p(dcm_f_p.toQuaternion());
783
784 return NO_ERROR;
785 }
786
787 template <typename T>
788 int Frame<T>::setRootRelAngularVelocity(const CartesianVector<T, 3> &w_f_root__f) {
789 /// First let's make sure we've got a valid parent and the frame isn't locked
790 if(_parent == nullptr) {
792 }
793
794 // Now subtract parent angular velocity from desired and set value accordingly
795 ang_vel_f_p__f(_r_joint.freedom()*(w_f_root__f - quat_f_p()*_parent->rootRelAngularVelocity()));
796
797 return NO_ERROR;
798 }
799
800}
801
802#endif
#define NUM_INTEGRATED_STATES
Definition Frame.hpp:35
Standard vector class derived from Matrix.
Definition CartesianVector.hpp:39
Class defining a direction cosine matrix inherited from Matrix.
Definition DCM.hpp:71
Class for inter-object communication.
Definition DataIO.hpp:46
Frame class definition.
Definition Frame.hpp:92
clockwerk::DataIO< CartesianVector< T, 3 > > vel_f_p__p
Definition Frame.hpp:123
clockwerk::DataIO< Quaternion< T > > quat_f_p
Definition Frame.hpp:126
int setRootRelPosition(const CartesianVector< T, 3 > &pos_f_root__root)
Function to set the frame's position relative to root.
Definition Frame.hpp:741
CartesianVector< T, 3 > _acc_f_p__p
Internal variables to store accelerations applied to this frame. Note: these are not states....
Definition Frame.hpp:277
void integrator(void *integ_ptr)
Getter and setter for integrator pointer.
Definition Frame.hpp:220
CartesianVector< T, 3 > parentRelAcceleration()
Function to get the acceleration of the frame relative to parent expressed in parent coords.
Definition Frame.hpp:145
void getStateVectorDot(std::array< T, 13 > &state_dot)
Function to get the rate of change in the frame state vector.
Definition Frame.hpp:401
void setParentRelAngularAcceleration(CartesianVector< T, 3 > alpha)
Function to set parent relative angular acceleration.
Definition Frame.hpp:141
int calcFrameTreeExtForcesMoments()
Function to recurse through the body and its children to apply external forces and moments to the "co...
Definition Frame.hpp:684
clockwerk::DataIO< CartesianVector< T, 3 > > ang_vel_f_p__f
Definition Frame.hpp:129
void rootRelAngularAcceleration(CartesianVector< T, 3 > &alpha_f_root__f)
Returns the angular acceleration of the frame origin wrt the root, expressed in this frame's coordina...
Definition Frame.hpp:627
int setRootRelVelocity(const CartesianVector< T, 3 > &vel_f_root__root)
Function to set the frame's velocity relative to root.
Definition Frame.hpp:755
void setParentRelAcceleration(CartesianVector< T, 3 > accel)
Function to set parent relative acceleration of frame.
Definition Frame.hpp:137
Joint< T > _t_joint
Translational and rotational joints relating this frame to its parent. Set locked by default.
Definition Frame.hpp:282
CartesianVector< T, 3 > parentRelAngularAcceleration()
Function to get angular acceleration relative to parent in frame coords.
Definition Frame.hpp:149
void rootRelVelocity(CartesianVector< T, 3 > &vel_o_root__root)
Returns the velocity of the frame origin wrt the root origin, in root coordinates.
Definition Frame.hpp:532
int setRootRelAttitude(const Quaternion< T > &quat_f_root)
Function to set the frame's attitude relative to root.
Definition Frame.hpp:773
int parent(Frame< T > *new_parent)
Function to assign the frame's parent via pointer.
Definition Frame.hpp:308
clockwerk::DataIO< CartesianVector< T, 3 > > pos_f_p__p
Definition Frame.hpp:119
Frame< T > * getFrameRootPointer()
Function to get a pointer to this frame's root frame.
Definition Frame.hpp:392
void rootRelAcceleration(CartesianVector< T, 3 > &acc_o_root__root)
Returns the acceleration of the frame origin wrt the root origin, in root coordinates.
Definition Frame.hpp:562
int calcFrameTreeExtAcceleration()
Function to recurse through the body and its children to resolve applied external forces and moments ...
Definition Frame.hpp:712
void setStateFromStateVector(const std::array< T, 13 > &state_f_p__f)
Function to set frame state based on NUM_INTEGRATED_STATES-element state vector.
Definition Frame.hpp:474
void getStateAsStateVector(std::array< T, 13 > &state_f_p__f)
Function to return frame state as a NUM_INTEGRATED_STATES-element state vector.
Definition Frame.hpp:484
void rootRelAngularVelocity(CartesianVector< T, 3 > &w_f_root__f)
Returns the angular velocity of the frame origin wrt the root, expressed in this frame's coordinates.
Definition Frame.hpp:602
void rootRelPosition(CartesianVector< T, 3 > &pos_o_root__root)
Returns the position of the frame origin wrt the root origin, in root coordinates.
Definition Frame.hpp:508
Joint< T > & tJoint()
Function to get reference to the frame's translational joint.
Definition Frame.hpp:102
void rootRelDCM(DCM< T > &dcm_f_root)
Returns the DCM of the frame origin wrt the root frame.
Definition Frame.hpp:663
Joint< T > _r_joint
Translational.
Definition Frame.hpp:283
Frame(const std::string &name, Frame< T > *par=nullptr, bool free=false)
Constructor for the frame object.
Definition Frame.hpp:294
Frame< T > * _parent
Variable to hold our parent.
Definition Frame.hpp:290
void * _integrator_ptr
Rotational.
Definition Frame.hpp:287
void rootRelQuaternion(Quaternion< T > &quat_f_root)
Returns the quaternion representing the frame origin wrt the root frame.
Definition Frame.hpp:651
int setRootRelAngularVelocity(const CartesianVector< T, 3 > &w_f_root__f)
Function to set the frame's position relative to root.
Definition Frame.hpp:788
Joint< T > & rJoint()
Function to get reference to the frame's rotational joint.
Definition Frame.hpp:106
Base class for object organization.
Definition GraphTreeObject.h:87
void recalculateRank()
Function to recursively re-calculate the rank of a given node on the tree.
Definition GraphTreeObject.cpp:263
GraphTreeObject * parent()
Functions to get object's parent/children.
Definition GraphTreeObject.h:96
std::vector< GraphTreeObject * > _children
Pointers to the object's children – automatically set to an empty vector, and can be increased to any...
Definition GraphTreeObject.h:234
uint8_t _graph_tree_type
Variable to store graph tree object type.
Definition GraphTreeObject.h:251
Joint class defining relationship between frames.
Definition Joint.hpp:44
Matrix math implementation.
Definition Matrix.hpp:54
#define NO_ERROR
Definition clockwerkerrors.h:31
#define ERROR_FRAME_PARENT_TYPE
Definition clockwerkerrors.h:133
#define ERROR_CIRCULAR_REFERENCE
Definition clockwerkerrors.h:79
#define ERROR_PARENT_NOT_FRAME
Definition clockwerkerrors.h:120