00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00026 #include "Model.hpp"
00027 #include "tao_util.hpp"
00028 #include <tao/dynamics/taoNode.h>
00029 #include <tao/dynamics/taoJoint.h>
00030 #include <tao/dynamics/taoDynamics.h>
00031
00032 #undef DEBUG
00033
00034
00035 static deVector3 const zero_gravity(0, 0, 0);
00036 static deVector3 const earth_gravity(0, 0, -9.81);
00037
00038
00039
00040 size_t squareToTriangularIndex(size_t irow, size_t icol, size_t dim)
00041 {
00042 if (0 == irow) {
00043 return icol;
00044 }
00045 if (0 == icol) {
00046 return irow;
00047 }
00048 if (irow > icol) {
00049
00050 return irow + dim * icol - icol * (icol + 1) / 2;
00051 }
00052 return icol + dim * irow - irow * (irow + 1) / 2;
00053 }
00054
00055
00056 namespace jspace {
00057
00058
00059 Model::
00060 Model()
00061 : ndof_(0),
00062 kgm_tree_(0),
00063 cc_tree_(0)
00064 {
00065 }
00066
00067
00068 int Model::
00069 init(tao_tree_info_s * kgm_tree,
00070 tao_tree_info_s * cc_tree,
00071 std::ostream * msg)
00072 {
00073 int const status(tao_consistency_check(kgm_tree->root, msg));
00074 if (0 != status) {
00075 return status;
00076 }
00077
00078 if (kgm_tree_) {
00079 if (msg) {
00080 *msg << "jspace::Model::init(): already initialized\n";
00081 }
00082 return -1;
00083 }
00084
00085 if ( ! kgm_tree->sort()) {
00086 if (msg) {
00087 *msg << "jspace::Model::init(): could not sort KGM nodes according to IDs\n";
00088 }
00089 return -2;
00090 }
00091
00092 if ((0 != cc_tree) && ( ! cc_tree->sort())) {
00093 if (msg) {
00094 *msg << "jspace::Model::init(): could not sort CC nodes according to IDs\n";
00095 }
00096 return -3;
00097 }
00098
00099
00100
00101 ancestry_table_.clear();
00102 typedef tao_tree_info_s::node_info_t::const_iterator cit_t;
00103 cit_t in(kgm_tree->info.begin());
00104 cit_t iend(kgm_tree->info.end());
00105 for (; in != iend; ++in) {
00106
00107 if ( ! in->node) {
00108 if (msg) {
00109 *msg << "jspace::Model::init(): NULL node at entry #" << in->id << "\n";
00110 }
00111 return -4;
00112 }
00113 if (in->id != in->node->getID()) {
00114 if (msg) {
00115 *msg << "jspace::Model::init(): node ID of entry #" << in->id << " is " << in->node->getID() << "\n";
00116 }
00117 return -5;
00118 }
00119 ancestry_list_t & alist(ancestry_table_[in->node]);
00120
00121
00122 for (taoDNode * node(in->node); 0 != node; node = node->getDParent()) {
00123 ancestry_entry_s entry;
00124 entry.id = node->getID();
00125 entry.joint = node->getJointList();
00126 if (0 != entry.joint) {
00127 alist.push_back(entry);
00128 }
00129 }
00130 }
00131
00132 kgm_tree_ = kgm_tree;
00133 cc_tree_ = cc_tree;
00134 ndof_ = kgm_tree->info.size();
00135
00136 return 0;
00137 }
00138
00139
00140 Model::
00141 ~Model()
00142 {
00143 delete kgm_tree_;
00144 delete cc_tree_;
00145 }
00146
00147
00148 void Model::
00149 update(State const & state)
00150 {
00151 setState(state);
00152 updateKinematics();
00153 updateDynamics();
00154 }
00155
00156
00157 void Model::
00158 setState(State const & state)
00159 {
00160 state_ = state;
00161 for (size_t ii(0); ii < ndof_; ++ii) {
00162 taoJoint * joint(kgm_tree_->info[ii].joint);
00163 joint->setQ(&const_cast<State&>(state).position_.coeffRef(ii));
00164 joint->zeroDQ();
00165 joint->zeroDDQ();
00166 joint->zeroTau();
00167 }
00168 if (cc_tree_) {
00169 for (size_t ii(0); ii < ndof_; ++ii) {
00170 taoJoint * joint(cc_tree_->info[ii].joint);
00171 joint->setQ(&const_cast<State&>(state).position_.coeffRef(ii));
00172 joint->setDQ(&const_cast<State&>(state).velocity_.coeffRef(ii));
00173 joint->zeroDDQ();
00174 joint->zeroTau();
00175 }
00176 }
00177 }
00178
00179
00180 size_t Model::
00181 getNNodes() const
00182 {
00183 return ndof_;
00184 }
00185
00186
00187 size_t Model::
00188 getNJoints() const
00189 {
00190
00191 return ndof_;
00192 }
00193
00194
00195 size_t Model::
00196 getNDOF() const
00197 {
00198
00199 return ndof_;
00200 }
00201
00202
00203 std::string Model::
00204 getNodeName(size_t id) const
00205 {
00206 std::string name("");
00207 if (ndof_ > id) {
00208 name = kgm_tree_->info[id].link_name;
00209 }
00210 return name;
00211 }
00212
00213
00214 std::string Model::
00215 getJointName(size_t id) const
00216 {
00217 std::string name("");
00218 if (ndof_ > id) {
00219 name = kgm_tree_->info[id].joint_name;
00220 }
00221 return name;
00222 }
00223
00224
00225 taoDNode * Model::
00226 getNode(size_t id) const
00227 {
00228 if (ndof_ > id) {
00229 return kgm_tree_->info[id].node;
00230 }
00231 return 0;
00232 }
00233
00234
00235 taoDNode * Model::
00236 getNodeByName(std::string const & name) const
00237 {
00238 for (size_t ii(0); ii < ndof_; ++ii) {
00239 if (name == kgm_tree_->info[ii].link_name) {
00240 return kgm_tree_->info[ii].node;
00241 }
00242 }
00243 return 0;
00244 }
00245
00246
00247 taoDNode * Model::
00248 getNodeByJointName(std::string const & name) const
00249 {
00250 for (size_t ii(0); ii < ndof_; ++ii) {
00251 if (name == kgm_tree_->info[ii].joint_name) {
00252 return kgm_tree_->info[ii].node;
00253 }
00254 }
00255 return 0;
00256 }
00257
00258
00259 void Model::
00260 getJointLimits(Vector & joint_limits_lower,
00261 Vector & joint_limits_upper) const
00262 {
00263 joint_limits_lower.resize(ndof_);
00264 joint_limits_upper.resize(ndof_);
00265 for (size_t ii(0); ii < ndof_; ++ii) {
00266 joint_limits_lower[ii] = kgm_tree_->info[ii].limit_lower;
00267 joint_limits_upper[ii] = kgm_tree_->info[ii].limit_upper;
00268 }
00269 }
00270
00271
00272 void Model::
00273 updateKinematics()
00274 {
00275 taoDynamics::updateTransformation(kgm_tree_->root);
00276 taoDynamics::globalJacobian(kgm_tree_->root);
00277 if (cc_tree_) {
00278 taoDynamics::updateTransformation(cc_tree_->root);
00279 taoDynamics::globalJacobian(cc_tree_->root);
00280 }
00281 }
00282
00283
00284 bool Model::
00285 getGlobalFrame(taoDNode const * node,
00286 Transform & global_transform) const
00287 {
00288 if ( ! node) {
00289 return false;
00290 }
00291
00292 deFrame const * tao_frame(node->frameGlobal());
00293 deQuaternion const & tao_quat(tao_frame->rotation());
00294 deVector3 const & tao_trans(tao_frame->translation());
00295
00296 #warning "TO DO: maybe the other way around..."
00297
00298
00299 global_transform = Translation(tao_trans[0], tao_trans[1], tao_trans[2]);
00300 global_transform *= Quaternion(tao_quat[3], tao_quat[0], tao_quat[1], tao_quat[2]);
00301
00302 return true;
00303 }
00304
00305
00306 bool Model::
00307 computeGlobalFrame(taoDNode const * node,
00308 Transform const & local_transform,
00309 Transform & global_transform) const
00310 {
00311 if ( ! getGlobalFrame(node, global_transform)) {
00312 return false;
00313 }
00314 global_transform = global_transform * local_transform;
00315 return true;
00316 }
00317
00318
00319 bool Model::
00320 computeGlobalFrame(taoDNode const * node,
00321 Vector const & local_translation,
00322 Transform & global_transform) const
00323 {
00324 if ( ! getGlobalFrame(node, global_transform)) {
00325 return false;
00326 }
00327 global_transform.translation() += global_transform.linear() * local_translation;
00328 return true;
00329 }
00330
00331
00332 bool Model::
00333 computeGlobalFrame(taoDNode const * node,
00334 double local_x, double local_y, double local_z,
00335 Transform & global_transform) const
00336 {
00337 if ( ! getGlobalFrame(node, global_transform)) {
00338 return false;
00339 }
00340 global_transform.translation() += global_transform.linear() * Eigen::Vector3d(local_x, local_y, local_z);
00341 return true;
00342 }
00343
00344
00345 bool Model::
00346 computeGlobalCOMFrame(taoDNode const * node,
00347 Transform & global_com_transform) const
00348 {
00349 if ( ! node) {
00350 return false;
00351 }
00352
00353 deVector3 const * com(const_cast<taoDNode*>(node)->center());
00354 if ( ! com) {
00355 return getGlobalFrame(node, global_com_transform);
00356 }
00357
00361 return computeGlobalFrame(node, com->elementAt(0), com->elementAt(1), com->elementAt(2), global_com_transform);
00362 }
00363
00364
00365 bool Model::
00366 computeJacobian(taoDNode const * node,
00367 Matrix & jacobian) const
00368 {
00369 if ( ! node) {
00370 return false;
00371 }
00372 deVector3 const & gpos(node->frameGlobal()->translation());
00373 return computeJacobian(node, gpos[0], gpos[1], gpos[2], jacobian);
00374 }
00375
00376
00377 bool Model::
00378 computeJacobian(taoDNode const * node,
00379 double gx, double gy, double gz,
00380 Matrix & jacobian) const
00381 {
00382 if ( ! node) {
00383 return false;
00384 }
00385 ancestry_table_t::const_iterator iae(ancestry_table_.find(const_cast<taoDNode*>(node)));
00386 if (iae == ancestry_table_.end()) {
00387 return false;
00388 }
00389 ancestry_list_t const & alist(iae->second);
00390
00391 #ifdef DEBUG
00392 fprintf(stderr, "computeJacobian()\ng: [% 4.2f % 4.2f % 4.2f]\n", gx, gy, gz);
00393 #endif // DEBUG
00394
00395
00396
00397 jacobian = Matrix::Zero(6, ndof_);
00398 ancestry_list_t::const_iterator ia(alist.begin());
00399 ancestry_list_t::const_iterator iend(alist.end());
00400 for (; ia != iend; ++ia) {
00401 deVector6 Jg_col;
00402 ia->joint->getJgColumns(&Jg_col);
00403 int const icol(ia->id);
00404
00405 #ifdef DEBUG
00406 fprintf(stderr, "iJg[%d]: [ % 4.2f % 4.2f % 4.2f % 4.2f % 4.2f % 4.2f]\n",
00407 icol,
00408 Jg_col.elementAt(0), Jg_col.elementAt(1), Jg_col.elementAt(2),
00409 Jg_col.elementAt(3), Jg_col.elementAt(4), Jg_col.elementAt(5));
00410 #endif // DEBUG
00411
00412 for (size_t irow(0); irow < 6; ++irow) {
00413 jacobian.coeffRef(irow, icol) = Jg_col.elementAt(irow);
00414 }
00415
00416
00417
00418
00419
00420
00421
00422
00423 jacobian.coeffRef(0, icol) -= -gz * Jg_col.elementAt(4) + gy * Jg_col.elementAt(5);
00424 jacobian.coeffRef(1, icol) -= gz * Jg_col.elementAt(3) - gx * Jg_col.elementAt(5);
00425 jacobian.coeffRef(2, icol) -= -gy * Jg_col.elementAt(3) + gx * Jg_col.elementAt(4);
00426
00427 #ifdef DEBUG
00428 fprintf(stderr, "0Jg[%d]: [ % 4.2f % 4.2f % 4.2f % 4.2f % 4.2f % 4.2f]\n",
00429 icol,
00430 jacobian.coeff(0, icol), jacobian.coeff(1, icol), jacobian.coeff(2, icol),
00431 jacobian.coeff(3, icol), jacobian.coeff(4, icol), jacobian.coeff(5, icol));
00432 #endif // DEBUG
00433
00434 }
00435 return true;
00436 }
00437
00438
00439 void Model::
00440 updateDynamics()
00441 {
00442 computeGravity();
00443 computeCoriolisCentrifugal();
00444 computeMassInertia();
00445 computeInverseMassInertia();
00446 }
00447
00448
00449 bool Model::
00450 computeCOM(Vector & com, Matrix * opt_jcom) const
00451 {
00452 com = Vector::Zero(3);
00453 if (opt_jcom) {
00454 *opt_jcom = Matrix::Zero(3, ndof_);
00455 }
00456 double mtotal(0);
00457 for (size_t ii(0); ii < ndof_; ++ii) {
00458 taoDNode * const node(kgm_tree_->info[ii].node);
00459 deVector3 wpos;
00460 wpos.multiply(node->frameGlobal()->rotation(), *(node->center()));
00461 wpos += node->frameGlobal()->translation();
00462 if (opt_jcom) {
00463 Matrix wjcom;
00464 if ( ! computeJacobian(node, wpos[0], wpos[1], wpos[2], wjcom)) {
00465 return false;
00466 }
00467 *opt_jcom += *(node->mass()) * wjcom.block(0, 0, 3, wjcom.cols());
00468 }
00469 wpos *= *(node->mass());
00470 mtotal += *(node->mass());
00471 com += Vector::Map(&wpos[0], 3);
00472 }
00473 if (fabs(mtotal) > 1e-3) {
00474 com /= mtotal;
00475 if (opt_jcom) {
00476 *opt_jcom /= mtotal;
00477 }
00478 }
00479 return true;
00480 }
00481
00482
00483 void Model::
00484 computeGravity()
00485 {
00486 g_torque_.resize(ndof_);
00487 taoDynamics::invDynamics(kgm_tree_->root, &earth_gravity);
00488 for (size_t ii(0); ii < ndof_; ++ii) {
00489 kgm_tree_->info[ii].joint->getTau(&g_torque_[ii]);
00490 }
00491 }
00492
00493
00494 bool Model::
00495 disableGravityCompensation(size_t index, bool disable)
00496 {
00497 if (ndof_ <= index) {
00498 return true;
00499 }
00500
00501 dof_set_t::const_iterator const idof(gravity_disabled_.find(index));
00502
00503 if (idof == gravity_disabled_.end()) {
00504
00505 if (disable) {
00506 gravity_disabled_.insert(index);
00507 }
00508 return false;
00509 }
00510
00511
00512 if ( ! disable) {
00513 gravity_disabled_.erase(idof);
00514 }
00515 return true;
00516 }
00517
00518
00519 bool Model::
00520 getGravity(Vector & gravity) const
00521 {
00522 if (0 == g_torque_.size()) {
00523 return false;
00524 }
00525 gravity = g_torque_;
00526
00527 dof_set_t::const_iterator iend(gravity_disabled_.end());
00528 for (dof_set_t::const_iterator ii(gravity_disabled_.begin()); ii != iend; ++ii) {
00529 gravity[*ii] = 0;
00530 }
00531 return true;
00532 }
00533
00534
00535 void Model::
00536 computeCoriolisCentrifugal()
00537 {
00538 if (cc_tree_) {
00539 cc_torque_.resize(ndof_);
00540 taoDynamics::invDynamics(cc_tree_->root, &zero_gravity);
00541 for (size_t ii(0); ii < ndof_; ++ii) {
00542 cc_tree_->info[ii].joint->getTau(&cc_torque_[ii]);
00543 }
00544 }
00545 }
00546
00547
00548 bool Model::
00549 getCoriolisCentrifugal(Vector & coriolis_centrifugal) const
00550 {
00551 if ( ! cc_tree_) {
00552 return false;
00553 }
00554 if (0 == cc_torque_.size()) {
00555 return false;
00556 }
00557 coriolis_centrifugal = cc_torque_;
00558 return true;
00559 }
00560
00561
00562 void Model::
00563 computeMassInertia()
00564 {
00565 if (a_upper_triangular_.empty()) {
00566 a_upper_triangular_.resize(ndof_ * (ndof_ + 1) / 2);
00567 }
00568
00569 deFloat const one(1);
00570 for (size_t irow(0); irow < ndof_; ++irow) {
00571 taoJoint * joint(kgm_tree_->info[irow].joint);
00572
00573
00574
00575
00576
00577
00578
00579 joint->setDDQ(&one);
00580 taoDynamics::invDynamics(kgm_tree_->root, &zero_gravity);
00581 joint->zeroDDQ();
00582
00583
00584
00585
00586
00587 for (size_t icol(0); icol <= irow; ++icol) {
00588 kgm_tree_->info[icol].joint->getTau(&a_upper_triangular_[squareToTriangularIndex(irow, icol, ndof_)]);
00589 }
00590 }
00591
00592
00593 for (size_t ii(0); ii < ndof_; ++ii) {
00594 kgm_tree_->info[ii].joint->zeroTau();
00595 }
00596 }
00597
00598
00599 bool Model::
00600 getMassInertia(Matrix & mass_inertia) const
00601 {
00602 if (a_upper_triangular_.empty()) {
00603 return false;
00604 }
00605
00606 mass_inertia.resize(ndof_, ndof_);
00607 for (size_t irow(0); irow < ndof_; ++irow) {
00608 for (size_t icol(0); icol <= irow; ++icol) {
00609 mass_inertia.coeffRef(irow, icol) = a_upper_triangular_[squareToTriangularIndex(irow, icol, ndof_)];
00610 if (irow != icol) {
00611 mass_inertia.coeffRef(icol, irow) = mass_inertia.coeff(irow, icol);
00612 }
00613 }
00614 }
00615
00616 return true;
00617 }
00618
00619
00620 void Model::
00621 computeInverseMassInertia()
00622 {
00623 if (ainv_upper_triangular_.empty()) {
00624 ainv_upper_triangular_.resize(ndof_ * (ndof_ + 1) / 2);
00625 }
00626
00627 deFloat const one(1);
00628 for (size_t irow(0); irow < ndof_; ++irow) {
00629 taoJoint * joint(kgm_tree_->info[irow].joint);
00630
00631
00632
00633
00634
00635
00636
00637 joint->setTau(&one);
00638 taoDynamics::fwdDynamics(kgm_tree_->root, &zero_gravity);
00639 joint->zeroTau();
00640
00641
00642
00643
00644 for (size_t icol(0); icol <= irow; ++icol) {
00645 kgm_tree_->info[icol].joint->getDDQ(&ainv_upper_triangular_[squareToTriangularIndex(irow, icol, ndof_)]);
00646 }
00647 }
00648
00649
00650 for (size_t ii(0); ii < ndof_; ++ii) {
00651 kgm_tree_->info[ii].joint->zeroDDQ();
00652 }
00653 }
00654
00655
00656 bool Model::
00657 getInverseMassInertia(Matrix & inverse_mass_inertia) const
00658 {
00659 if (ainv_upper_triangular_.empty()) {
00660 return false;
00661 }
00662
00663 inverse_mass_inertia.resize(ndof_, ndof_);
00664 for (size_t irow(0); irow < ndof_; ++irow) {
00665 for (size_t icol(0); icol <= irow; ++icol) {
00666 inverse_mass_inertia.coeffRef(irow, icol) = ainv_upper_triangular_[squareToTriangularIndex(irow, icol, ndof_)];
00667 if (irow != icol) {
00668 inverse_mass_inertia.coeffRef(icol, irow) = inverse_mass_inertia.coeff(irow, icol);
00669 }
00670 }
00671 }
00672
00673 return true;
00674 }
00675
00676 }