00001 #ifndef OPENTISSUE_DYNAMICS_MBD_UTIL_JOINTS_MBD_HINGE_JOINT_H
00002 #define OPENTISSUE_DYNAMICS_MBD_UTIL_JOINTS_MBD_HINGE_JOINT_H
00003
00004
00005
00006
00007
00008
00009
00010 #include <OpenTissue/configuration.h>
00011
00012 #include <OpenTissue/dynamics/mbd/interfaces/mbd_joint_interface.h>
00013 #include <OpenTissue/dynamics/mbd/limits/mbd_angular_joint_limit.h>
00014 #include <OpenTissue/dynamics/mbd/motors/mbd_angular_joint_motor.h>
00015 #include <OpenTissue/core/math/math_constants.h>
00016
00017
00018 namespace OpenTissue
00019 {
00020 namespace mbd
00021 {
00022 template< typename mbd_types >
00023 class HingeJoint
00024 : public JointInterface<mbd_types>
00025 {
00026 public:
00027
00028 typedef typename mbd_types::math_policy math_policy;
00029 typedef typename mbd_types::math_policy::index_type size_type;
00030 typedef typename mbd_types::math_policy::real_type real_type;
00031 typedef typename mbd_types::math_policy::vector3_type vector3_type;
00032 typedef typename mbd_types::math_policy::matrix3x3_type matrix3x3_type;
00033 typedef typename mbd_types::math_policy::quaternion_type quaternion_type;
00034 typedef typename mbd_types::math_policy::vector_range vector_range;
00035 typedef typename mbd_types::math_policy::idx_vector_range idx_vector_range;
00036 typedef typename mbd_types::math_policy::matrix_range matrix_range;
00037 typedef typename mbd_types::math_policy::vector_type vector_type;
00038 typedef typename mbd_types::math_policy::value_traits value_traits;
00039
00040 typedef AngularJointLimit<mbd_types> angular_limit_type;
00041 typedef AngularJointMotor<mbd_types> angular_motor_type;
00042
00043
00044 protected:
00045
00046 vector3_type m_s_A_wcs;
00047 vector3_type m_s_B_wcs;
00048 vector3_type m_t1;
00049 vector3_type m_t2;
00050 vector3_type m_u;
00051 matrix3x3_type m_star_anc_A;
00052 matrix3x3_type m_star_anc_B;
00053 vector3_type m_anc_A_wcs;
00054 vector3_type m_anc_B_wcs;
00055 quaternion_type m_Q_initial;
00056 quaternion_type m_Q_initial_conj;
00057 angular_limit_type * m_limit;
00058 angular_motor_type * m_motor;
00059
00060 size_type m_rows;
00061 size_type m_motor_offset;
00062 size_type m_limit_offset;
00063
00064 vector_type m_gamma;
00065 vector_type m_solution;
00066
00067 public:
00068
00107 real_type get_hinge_angle() const
00108 {
00109 assert(this->m_socketA || !"HingeJoint::get_hinge_angle(): socket A was null");
00110 assert(this->m_socketB || !"HingeJoint::get_hinge_angle(): socket B was null");
00111
00112
00113
00114
00115
00116
00117
00118
00119 quaternion_type Q_cur,Q_rel;
00120
00121
00122 quaternion_type Q_A,Q_B;
00123 this->m_socketA->get_body()->get_orientation(Q_A);
00124 this->m_socketB->get_body()->get_orientation(Q_B);
00125
00126 Q_cur = conj(Q_B) % Q_A;
00127
00128
00129
00130
00131
00132
00133
00134
00135 Q_rel = Q_cur % m_Q_initial_conj;
00136
00137 return get_angle(Q_rel,this->m_socketB->get_joint_axis_local());
00138 }
00139
00147 real_type get_hinge_angle_rate() const
00148 {
00149 assert(this->m_socketA || !"HingeJoint::get_hinge_angle_rate(): socket A was null");
00150 assert(this->m_socketB || !"HingeJoint::get_hinge_angle_rate(): socket B was null");
00151
00152 vector3_type s_wcs = this->m_socketA->get_joint_axis_world();
00153
00154 vector3_type w_A,w_B;
00155 this->m_socketA->get_body()->get_spin(w_A);
00156 this->m_socketB->get_body()->get_spin(w_B);
00157 return s_wcs * (w_A - w_B);
00158 }
00159
00160 vector3_type get_hinge_axis_world() const
00161 {
00162 return this->m_socketA->get_joint_axis_world();
00163 }
00164
00165 void set_limit(angular_limit_type const & limit)
00166 {
00167 m_limit = const_cast<angular_limit_type*>(&limit);
00168 }
00169
00170 void set_motor(angular_motor_type const & motor)
00171 {
00172 m_motor = const_cast<angular_motor_type*>(&motor);
00173 }
00174
00175 public:
00176
00177 HingeJoint()
00178 : m_limit(0)
00179 , m_motor(0)
00180 , m_rows(0)
00181 {}
00182
00183 virtual ~HingeJoint() {}
00184
00185 public:
00186
00187 void evaluate()
00188 {
00189 m_rows = 0;
00190 if(!(this->m_socketA && this->m_socketB))
00191 return;
00192
00193 m_s_A_wcs = this->m_socketA->get_joint_axis_world();
00194 m_s_B_wcs = this->m_socketB->get_joint_axis_world();
00195
00196 quaternion_type Q;
00197 this->m_socketA->get_body()->get_orientation(Q);
00198 m_star_anc_A = star( Q.rotate( this->m_socketA->get_anchor_local()) );
00199 this->m_socketB->get_body()->get_orientation(Q);
00200 m_star_anc_B = star( Q.rotate( this->m_socketB->get_anchor_local()) );
00201
00202 m_anc_A_wcs = this->m_socketA->get_anchor_world();
00203 m_anc_B_wcs = this->m_socketB->get_anchor_world();
00204
00205 m_t1 = this->m_socketA->get_axis1_world();
00206 m_t2 = this->m_socketA->get_axis2_world();
00207
00208 m_u = cross(m_s_A_wcs , m_s_B_wcs);
00209
00210 m_rows = 5;
00211 m_limit_offset = 0;
00212 m_motor_offset = 0;
00213 if(m_limit)
00214 {
00215 m_limit->evaluate(get_hinge_axis_world(),get_hinge_angle());
00216 if(m_limit->is_active())
00217 {
00218 m_limit_offset = m_rows;
00219 ++m_rows;
00220 }
00221 }
00222 if(m_motor)
00223 {
00224 m_motor->evaluate(get_hinge_axis_world());
00225 if(m_motor->is_active())
00226 {
00227 m_motor_offset = m_rows;
00228 ++m_rows;
00229 }
00230 }
00231
00232 }
00233
00234 size_type get_number_of_jacobian_rows() const
00235 {
00236 return m_rows;
00237 }
00238
00239 void get_linear_jacobian_A(matrix_range & J)const
00240 {
00241 assert(J.size1()==m_rows || !"HingeJoint::get_linear_jacobian_A(): incorrect dimensions");
00242 assert(J.size2()==3 || !"HingeJoint::get_linear_jacobian_A(): incorrect dimensions");
00243 J(0,0) = value_traits::one(); J(0,1) = value_traits::zero(); J(0,2) = value_traits::zero();
00244 J(1,0) = value_traits::zero(); J(1,1) = value_traits::one(); J(1,2) = value_traits::zero();
00245 J(2,0) = value_traits::zero(); J(2,1) = value_traits::zero(); J(2,2) = value_traits::one();
00246 J(3,0) = value_traits::zero(); J(3,1) = value_traits::zero(); J(3,2) = value_traits::zero();
00247 J(4,0) = value_traits::zero(); J(4,1) = value_traits::zero(); J(4,2) = value_traits::zero();
00248 if(m_limit_offset)
00249 m_limit->get_linear_jacobian_A(J,m_limit_offset);
00250 if(m_motor_offset)
00251 m_motor->get_linear_jacobian_A(J,m_motor_offset);
00252 }
00253
00254 void get_linear_jacobian_B(matrix_range & J)const
00255 {
00256 assert(J.size1()==m_rows || !"HingeJoint::get_linear_jacobian_B(): incorrect dimensions");
00257 assert(J.size2()==3 || !"HingeJoint::get_linear_jacobian_B(): incorrect dimensions");
00258 J(0,0) = -value_traits::one(); J(0,1) = value_traits::zero(); J(0,2) = value_traits::zero();
00259 J(1,0) = value_traits::zero(); J(1,1) = -value_traits::one(); J(1,2) = value_traits::zero();
00260 J(2,0) = value_traits::zero(); J(2,1) = value_traits::zero(); J(2,2) = -value_traits::one();
00261 J(3,0) = value_traits::zero(); J(3,1) = value_traits::zero(); J(3,2) = value_traits::zero();
00262 J(4,0) = value_traits::zero(); J(4,1) = value_traits::zero(); J(4,2) = value_traits::zero();
00263 if(m_limit_offset)
00264 m_limit->get_linear_jacobian_B(J,m_limit_offset);
00265 if(m_motor_offset)
00266 m_motor->get_linear_jacobian_B(J,m_motor_offset);
00267 }
00268
00269 void get_angular_jacobian_A(matrix_range & J)const
00270 {
00271 assert(J.size1()==m_rows || !"HingeJoint::get_angular_jacobian_A(): incorrect dimensions");
00272 assert(J.size2()==3 || !"HingeJoint::get_angular_jacobian_A(): incorrect dimensions");
00273 J(0,0) = -m_star_anc_A(0,0); J(0,1) = -m_star_anc_A(0,1); J(0,2) = -m_star_anc_A(0,2);
00274 J(1,0) = -m_star_anc_A(1,0); J(1,1) = -m_star_anc_A(1,1); J(1,2) = -m_star_anc_A(1,2);
00275 J(2,0) = -m_star_anc_A(2,0); J(2,1) = -m_star_anc_A(2,1); J(2,2) = -m_star_anc_A(2,2);
00276 J(3,0) = m_t1(0); J(3,1) = m_t1(1); J(3,2) = m_t1(2);
00277 J(4,0) = m_t2(0); J(4,1) = m_t2(1); J(4,2) = m_t2(2);
00278 if(m_limit_offset)
00279 m_limit->get_angular_jacobian_A(J,m_limit_offset);
00280 if(m_motor_offset)
00281 m_motor->get_angular_jacobian_A(J,m_motor_offset);
00282 }
00283
00284 void get_angular_jacobian_B(matrix_range & J)const
00285 {
00286 assert(J.size1()==m_rows || !"HingeJoint::get_angular_jacobian_B(): incorrect dimensions");
00287 assert(J.size2()==3 || !"HingeJoint::get_angular_jacobian_B(): incorrect dimensions");
00288 J(0,0) = m_star_anc_B(0,0); J(0,1) = m_star_anc_B(0,1); J(0,2) = m_star_anc_B(0,2);
00289 J(1,0) = m_star_anc_B(1,0); J(1,1) = m_star_anc_B(1,1); J(1,2) = m_star_anc_B(1,2);
00290 J(2,0) = m_star_anc_B(2,0); J(2,1) = m_star_anc_B(2,1); J(2,2) = m_star_anc_B(2,2);
00291 J(3,0) = -m_t1(0); J(3,1) = -m_t1(1); J(3,2) = -m_t1(2);
00292 J(4,0) = -m_t2(0); J(4,1) = -m_t2(1); J(4,2) = -m_t2(2);
00293
00294 if(m_limit_offset)
00295 m_limit->get_angular_jacobian_B(J,m_limit_offset);
00296 if(m_motor_offset)
00297 m_motor->get_angular_jacobian_B(J,m_motor_offset);
00298
00299 }
00300
00301 void get_stabilization_term(vector_range & b_error)const
00302 {
00303 assert(b_error.size()==m_rows || !"HingeJoint::get_stabilization_term(): incorrect dimensions");
00304 real_type k_cor = this->get_frames_per_second()*this->get_error_reduction_parameter();
00305
00306 b_error(0) = k_cor*(m_anc_B_wcs(0) - m_anc_A_wcs(0));
00307 b_error(1) = k_cor*(m_anc_B_wcs(1) - m_anc_A_wcs(1));
00308 b_error(2) = k_cor*(m_anc_B_wcs(2) - m_anc_A_wcs(2));
00309 b_error(3) = k_cor*(m_t1*m_u);
00310 b_error(4) = k_cor*(m_t2*m_u);
00311
00312 if(m_limit_offset)
00313 m_limit->get_stabilization_term(b_error,m_limit_offset);
00314 if(m_motor_offset)
00315 m_motor->get_stabilization_term(b_error,m_motor_offset);
00316 }
00317
00318
00319 void get_low_limits(vector_range & lo)const
00320 {
00321 assert(lo.size()==m_rows || !"HingeJoint::get_low_limits(): incorrect dimensions");
00322 lo(0) = OpenTissue::math::detail::lowest<real_type>();
00323 lo(1) = OpenTissue::math::detail::lowest<real_type>();
00324 lo(2) = OpenTissue::math::detail::lowest<real_type>();
00325 lo(3) = OpenTissue::math::detail::lowest<real_type>();
00326 lo(4) = OpenTissue::math::detail::lowest<real_type>();
00327 if(m_limit_offset)
00328 m_limit->get_low_limits(lo,m_limit_offset);
00329 if(m_motor_offset)
00330 m_motor->get_low_limits(lo,m_motor_offset);
00331
00332 }
00333
00334 void get_high_limits(vector_range & hi)const
00335 {
00336 assert(hi.size()==m_rows || !"HingeJoint::get_high_limits(): incorrect dimensions");
00337 hi(0) = OpenTissue::math::detail::highest<real_type>();
00338 hi(1) = OpenTissue::math::detail::highest<real_type>();
00339 hi(2) = OpenTissue::math::detail::highest<real_type>();
00340 hi(3) = OpenTissue::math::detail::highest<real_type>();
00341 hi(4) = OpenTissue::math::detail::highest<real_type>();
00342
00343 if(m_limit_offset)
00344 m_limit->get_high_limits(hi,m_limit_offset);
00345 if(m_motor_offset)
00346 m_motor->get_high_limits(hi,m_motor_offset);
00347 }
00348
00349 void get_dependency_indices(idx_vector_range & dep)const
00350 {
00351 assert(dep.size()==m_rows || !"HingeJoint::get_dependency_indices(): incorrect dimensions");
00352 for(size_type i=0;i<m_rows;++i)
00353 dep(i) = OpenTissue::math::detail::highest<size_type>();
00354 }
00355
00356 void get_dependency_factors(vector_range & factors)const
00357 {
00358 assert(factors.size()==m_rows || !"HingeJoint::get_dependency_factors(): incorrect dimensions");
00359 for(size_type i=0;i<m_rows;++i)
00360 factors(i) = value_traits::zero();
00361 }
00362
00363 void set_regularization(vector_range const & gamma)
00364 {
00365 assert(gamma.size()==m_rows || !"HingeJoint::set_regularization(): incorrect dimensions");
00366 math_policy::resize( m_gamma, 5);
00367 for(size_type i=0;i<5;++i)
00368 {
00369 assert(gamma(i)<=value_traits::one() || !"HingeJoint::set_regularization(): gamma was greater than 1");
00370 assert(gamma(i)>=value_traits::zero() || !"HingeJoint::set_regularization(): gamma was less than 0");
00371 m_gamma(i) = gamma(i);
00372 }
00373 if(m_limit_offset)
00374 m_limit->set_regularization(gamma,m_limit_offset);
00375 if(m_motor_offset)
00376 m_motor->set_regularization(gamma,m_motor_offset);
00377 }
00378
00379 void get_regularization(vector_range & gamma)const
00380 {
00381 assert(gamma.size()==m_rows || !"HingeJoint::get_regularization(): incorrect dimensions");
00382 if(m_gamma.size()==0)
00383 {
00384 for(size_type i=0;i<5;++i)
00385 gamma(i) = value_traits::zero();
00386 }
00387 else
00388 {
00389 for(size_type i=0;i<5;++i)
00390 gamma(i) = m_gamma(i);
00391 }
00392 if(m_limit_offset)
00393 m_limit->get_regularization(gamma,m_limit_offset);
00394 if(m_motor_offset)
00395 m_motor->get_regularization(gamma,m_motor_offset);
00396 }
00397
00398 void set_solution(vector_range const & solution)
00399 {
00400 assert(solution.size()==m_rows || !"HingeJoint::set_solution(): incorrect dimensions");
00401
00402 math_policy::resize( m_solution, 5);
00403 for(size_type i=0;i<5;++i)
00404 m_solution(i) = solution(i);
00405 if(m_limit_offset)
00406 m_limit->set_solution(solution,m_limit_offset);
00407 if(m_motor_offset)
00408 m_motor->set_solution(solution,m_motor_offset);
00409 }
00410
00411 void get_solution(vector_range & solution)const
00412 {
00413 assert(solution.size()==m_rows || !"HingeJoint::get_solution(): incorrect dimensions");
00414 if(m_solution.size()==0)
00415 {
00416 for(size_type i=0;i<5;++i)
00417 solution(i) = value_traits::zero();
00418 }
00419 else
00420 {
00421 for(size_type i=0;i<5;++i)
00422 solution(i) = m_solution(i);
00423 }
00424 if(m_limit_offset)
00425 m_limit->get_solution(solution,m_limit_offset);
00426 if(m_motor_offset)
00427 m_motor->get_solution(solution,m_motor_offset);
00428 }
00429
00430 void calibration()
00431 {
00432 assert(this->m_socketA || !"HingeJoint::calibration(): socket A was null");
00433 assert(this->m_socketB || !"HingeJoint::calibration(): socket B was null");
00434
00435 quaternion_type Q_A,Q_B;
00436 this->m_socketA->get_body()->get_orientation(Q_A);
00437 this->m_socketB->get_body()->get_orientation(Q_B);
00438
00439
00440 m_Q_initial = conj(Q_B) % Q_A;
00441 m_Q_initial_conj = conj(m_Q_initial);
00442 }
00443
00444 };
00445
00446 }
00447 }
00448
00449 #endif