1 #ifndef SimTK_SIMBODY_RIGID_BODY_NODE_SPEC_SCREW_H_
2 #define SimTK_SIMBODY_RIGID_BODY_NODE_SPEC_SCREW_H_
3 
4 /* -------------------------------------------------------------------------- *
5  *                               Simbody(tm)                                  *
6  * -------------------------------------------------------------------------- *
7  * This is part of the SimTK biosimulation toolkit originating from           *
8  * Simbios, the NIH National Center for Physics-Based Simulation of           *
9  * Biological Structures at Stanford, funded under the NIH Roadmap for        *
10  * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody.  *
11  *                                                                            *
12  * Portions copyright (c) 2005-12 Stanford University and the Authors.        *
13  * Authors: Michael Sherman                                                   *
14  * Contributors: Derived from IVM code written by Charles Schwieters          *
15  *                                                                            *
16  * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
17  * not use this file except in compliance with the License. You may obtain a  *
18  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
19  *                                                                            *
20  * Unless required by applicable law or agreed to in writing, software        *
21  * distributed under the License is distributed on an "AS IS" BASIS,          *
22  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
23  * See the License for the specific language governing permissions and        *
24  * limitations under the License.                                             *
25  * -------------------------------------------------------------------------- */
26 
27 /**@file
28  * Define the RigidBodyNode that implements a Screw mobilizer.
29  */
30 
31 #include "SimbodyMatterSubsystemRep.h"
32 #include "RigidBodyNode.h"
33 #include "RigidBodyNodeSpec.h"
34 
35 
36     // SCREW //
37 
38 // This is a one-dof "screw" joint, meaning one degree of rotational freedom
39 // about a particular axis, coupled to translation along that same axis.
40 // Here we use the common z axis of the F and M frames, which remains
41 // aligned forever. For the generalized coordinate q, we use the rotation
42 // angle. For the generalized speed u we use the rotation rate, which is also
43 // the angular velocity of M in F (about the z axis). We compute the
44 // translational position as pitch*q, and the translation rate as pitch*u.
45 template<bool noX_MB, bool noR_PF>
46 class RBNodeScrew : public RigidBodyNodeSpec<1, false, noX_MB, noR_PF> {
47     Real pitch;
48 public:
49 typedef typename RigidBodyNodeSpec<1, false, noX_MB, noR_PF>::HType HType;
type()50 virtual const char* type() { return "screw"; }
51 
RBNodeScrew(const MassProperties & mProps_B,const Transform & X_PF,const Transform & X_BM,Real p,bool isReversed,UIndex & nextUSlot,USquaredIndex & nextUSqSlot,QIndex & nextQSlot)52 RBNodeScrew(const MassProperties& mProps_B,
53             const Transform&      X_PF,
54             const Transform&      X_BM,
55             Real                  p,  // the pitch
56             bool                  isReversed,
57             UIndex&               nextUSlot,
58             USquaredIndex&        nextUSqSlot,
59             QIndex&               nextQSlot)
60 :   RigidBodyNodeSpec<1, false, noX_MB, noR_PF>(mProps_B,X_PF,X_BM,nextUSlot,nextUSqSlot,nextQSlot,
61                          RigidBodyNode::QDotIsAlwaysTheSameAsU, RigidBodyNode::QuaternionIsNeverUsed,
62                          isReversed),
63     pitch(p)
64 {
65     this->updateSlots(nextUSlot,nextUSqSlot,nextQSlot);
66 }
67 
setQToFitRotationImpl(const SBStateDigest & sbs,const Rotation & R_FM,Vector & q)68 void setQToFitRotationImpl(const SBStateDigest& sbs, const Rotation& R_FM,
69                            Vector& q) const {
70     // The only rotation our screw joint can handle is about z.
71     // TODO: should use 321 to deal with singular configuration (angle2==pi/2)
72     // better; in that case 1 and 3 are aligned and the conversion routine
73     // allocates all the rotation to whichever comes first.
74     // TODO: isn't there a better way to come up with "the rotation around z
75     // that best approximates a rotation R"?
76     const Vec3 angles123 = R_FM.convertRotationToBodyFixedXYZ();
77     this->to1Q(q) = angles123[2];
78 }
79 
setQToFitTranslationImpl(const SBStateDigest & sbs,const Vec3 & p_FM,Vector & q)80 void setQToFitTranslationImpl(const SBStateDigest& sbs, const Vec3& p_FM,
81                               Vector& q) const {
82     this->to1Q(q) = p_FM[2]/pitch;
83 }
84 
setUToFitAngularVelocityImpl(const SBStateDigest & sbs,const Vector &,const Vec3 & w_FM,Vector & u)85 void setUToFitAngularVelocityImpl(const SBStateDigest& sbs, const Vector&,
86                                   const Vec3& w_FM, Vector& u) const {
87     // We can only represent an angular velocity along z with this joint.
88     this->to1U(u) = w_FM[2]; // project angular velocity onto z axis
89 }
90 
setUToFitLinearVelocityImpl(const SBStateDigest & sbs,const Vector &,const Vec3 & v_FM,Vector & u)91 void setUToFitLinearVelocityImpl
92    (const SBStateDigest& sbs, const Vector&, const Vec3& v_FM, Vector& u) const
93 {
94     this->to1U(u) = v_FM[2]/pitch;
95 }
96 
97 // We're currently using an angle as the generalized coordinate for the
98 // screw joint but could just as easily have used translation or some
99 // non-physical coordinate. It might make sense to offer a Model stage
100 // option to set the coordinate meaning.
101 
102 enum {PoolSize=2}; // number of Reals
103 enum {CosQ=0, SinQ=1};
104 // We want space for cos(q) and sin(q).
calcQPoolSize(const SBModelVars &)105 int calcQPoolSize(const SBModelVars&) const
106 {   return PoolSize; }
107 
108 // Precalculation of sin/cos costs around 50 flops.
performQPrecalculations(const SBStateDigest & sbs,const Real * q,int nq,Real * qCache,int nQCache,Real * qErr,int nQErr)109 void performQPrecalculations(const SBStateDigest& sbs,
110                              const Real* q, int nq,
111                              Real* qCache,  int nQCache,
112                              Real* qErr,    int nQErr) const
113 {
114     assert(q && nq==1 && qCache && nQCache==PoolSize && nQErr==0);
115     qCache[CosQ] = std::cos(q[0]);
116     qCache[SinQ] = std::sin(q[0]);
117 }
118 
119 // This is nearly free since we already calculated sin/cos.
calcX_FM(const SBStateDigest & sbs,const Real * q,int nq,const Real * qCache,int nQCache,Transform & X_FM)120 void calcX_FM(const SBStateDigest& sbs,
121                 const Real* q,      int nq,
122                 const Real* qCache, int nQCache,
123                 Transform&  X_FM) const
124 {
125     assert(q && nq==1 && qCache && nQCache==PoolSize);
126     X_FM.updR().setRotationFromAngleAboutZ(qCache[CosQ], qCache[SinQ]);
127     // Note that we're using the same coordinate to control
128     // translation, using "pitch" as a conversion from radians to
129     // length units.
130     X_FM.updP() = Vec3(0,0,q[0]*pitch);
131 }
132 
133 // The generalized speed is the angular velocity of M in the F frame,
134 // about F's z axis, expressed in F. (This axis is also constant in M.)
calcAcrossJointVelocityJacobian(const SBStateDigest & sbs,HType & H_FM)135 void calcAcrossJointVelocityJacobian(
136     const SBStateDigest& sbs,
137     HType&               H_FM) const
138 {
139     H_FM(0) = SpatialVec( Vec3(0,0,1), Vec3(0,0,pitch) );
140 }
141 
142 // Since the Jacobian above is constant in F, its time derivative in F is zero.
calcAcrossJointVelocityJacobianDot(const SBStateDigest & sbs,HType & HDot_FM)143 void calcAcrossJointVelocityJacobianDot(
144     const SBStateDigest& sbs,
145     HType&               HDot_FM) const
146 {
147     HDot_FM(0) = SpatialVec( Vec3(0), Vec3(0) );
148 }
149 
150 // Override the computation of reverse-H for this simple mobilizer.
calcReverseMobilizerH_FM(const SBStateDigest & sbs,HType & H_FM)151 void calcReverseMobilizerH_FM(
152     const SBStateDigest& sbs,
153     HType&               H_FM) const
154 {
155     H_FM(0) = SpatialVec( Vec3(0,0,-1), Vec3(0,0,-pitch) );
156 }
157 
158 // Override the computation of reverse-HDot for this simple mobilizer.
calcReverseMobilizerHDot_FM(const SBStateDigest & sbs,HType & HDot_FM)159 void calcReverseMobilizerHDot_FM(
160     const SBStateDigest& sbs,
161     HType&               HDot_FM) const
162 {
163     HDot_FM(0) = SpatialVec( Vec3(0), Vec3(0) );
164 }
165 
166 };
167 
168 
169 
170 #endif // SimTK_SIMBODY_RIGID_BODY_NODE_SPEC_SCREW_H_
171 
172