$search
00001 /* 00002 * Copyright (c) 2008, Willow Garage, Inc. 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of the Willow Garage, Inc. nor the names of its 00014 * contributors may be used to endorse or promote products derived from 00015 * this software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00018 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00021 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00022 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00023 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00024 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00025 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00026 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00027 * POSSIBILITY OF SUCH DAMAGE. 00028 */ 00029 00030 /* 00031 * Author: Stuart Glaser 00032 */ 00033 00034 /* 00035 * propagatePosition (from as to js) 00036 * as position and velocity are doubled to get js, since gripper is two sided 00037 * as torque is directly converted to gap_effort 00038 * as torque to passive joint is /4 since there are 4 links 00039 * propagateEffort (from js to as) 00040 * popluate only as->commanded_.effort_ 00041 * this is directly transferred as torque and gap effort is 1to1 00042 * 00043 * below only for simulation 00044 * 00045 * propagatePositionBackwards (from js to as) 00046 * as position and velocity transfers 1to1 to joint_angle (1-sided) 00047 * as last_measured_effort_ should be 1to1 gap_effort of non-passive js->commanded_effort 00048 * propagateEffortBackwards 00049 * non-passive js->commanded_effort_ is 1to1 with MT 00050 * passive js->commanded_effort_ is 1/2?? of MT converted to joint torques 00051 */ 00052 #include "pr2_mechanism_model/pr2_gripper_transmission.h" 00053 #include <pluginlib/class_list_macros.h> 00054 #include <algorithm> 00055 #include <numeric> 00056 #include <angles/angles.h> 00057 #include <boost/lexical_cast.hpp> 00058 00059 using namespace pr2_hardware_interface; 00060 using namespace pr2_mechanism_model; 00061 00062 PLUGINLIB_DECLARE_CLASS(pr2_mechanism_model, PR2GripperTransmission, 00063 pr2_mechanism_model::PR2GripperTransmission, 00064 pr2_mechanism_model::Transmission) 00065 00066 bool PR2GripperTransmission::initXml(TiXmlElement *config, Robot *robot) 00067 { 00068 const char *name = config->Attribute("name"); 00069 name_ = name ? name : ""; 00070 //myfile.open("transmission_data.txt"); 00071 TiXmlElement *ael = config->FirstChildElement("actuator"); 00072 const char *actuator_name = ael ? ael->Attribute("name") : NULL; 00073 if (!actuator_name || !robot->getActuator(actuator_name)) 00074 { 00075 ROS_ERROR("PR2GripperTransmission could not find actuator named \"%s\"", actuator_name); 00076 return false; 00077 } 00078 robot->getActuator(actuator_name)->command_.enable_ = true; 00079 actuator_names_.push_back(actuator_name); 00080 00081 for (TiXmlElement *j = config->FirstChildElement("gap_joint"); j; j = j->NextSiblingElement("gap_joint")) 00082 { 00083 const char *joint_name = j->Attribute("name"); 00084 if (!joint_name) 00085 { 00086 ROS_ERROR("PR2GripperTransmission did not specify joint name"); 00087 return false; 00088 } 00089 00090 const boost::shared_ptr<const urdf::Joint> joint = robot->robot_model_.getJoint(joint_name); 00091 if (!joint) 00092 { 00093 ROS_ERROR("PR2GripperTransmission could not find joint named \"%s\"", joint_name); 00094 return false; 00095 } 00096 gap_joint_ = std::string(joint_name); 00097 joint_names_.push_back(joint_name); // The first joint is the gap joint 00098 00099 // get the mechanical reduction 00100 const char *joint_reduction = j->Attribute("mechanical_reduction"); 00101 if (!joint_reduction) 00102 { 00103 ROS_ERROR("PR2GripperTransmission's joint \"%s\" has no coefficient: mechanical reduction.", joint_name); 00104 return false; 00105 } 00106 try 00107 { 00108 gap_mechanical_reduction_ = boost::lexical_cast<double>(joint_reduction); 00109 } 00110 catch (boost::bad_lexical_cast &e) 00111 { 00112 ROS_ERROR("joint_reduction (%s) is not a float",joint_reduction); 00113 return false; 00114 } 00115 00116 // get the screw drive reduction 00117 const char *screw_reduction_str = j->Attribute("screw_reduction"); 00118 if (screw_reduction_str == NULL) 00119 { 00120 screw_reduction_ = 2.0/1000.0; 00121 ROS_WARN("PR2GripperTransmission's joint \"%s\" has no coefficient: screw drive reduction, using default for PR2 alpha2.", joint_name); 00122 } 00123 else 00124 try 00125 { 00126 screw_reduction_ = boost::lexical_cast<double>(screw_reduction_str); 00127 } 00128 catch (boost::bad_lexical_cast &e) 00129 { 00130 ROS_ERROR("screw_reduction (%s) is not a float",screw_reduction_str); 00131 return false; 00132 } 00133 00134 00135 // get the gear_ratio 00136 const char *gear_ratio_str = j->Attribute("gear_ratio"); 00137 if (gear_ratio_str == NULL) 00138 { 00139 gear_ratio_ = 29.16; 00140 ROS_WARN("PR2GripperTransmission's joint \"%s\" has no coefficient: gear_ratio, using default for PR2 alpha2.", joint_name); 00141 } 00142 else 00143 try 00144 { 00145 gear_ratio_ = boost::lexical_cast<double>(gear_ratio_str); 00146 } 00147 catch (boost::bad_lexical_cast &e) 00148 { 00149 ROS_ERROR("gear_ratio (%s) is not a float",gear_ratio_str); 00150 return false; 00151 } 00152 00153 // get the theta0 coefficient 00154 const char *theta0_str = j->Attribute("theta0"); 00155 if (theta0_str == NULL) 00156 { 00157 theta0_ = 2.97571*M_PI/180.0; 00158 ROS_WARN("PR2GripperTransmission's joint \"%s\" has no coefficient: theta0, using default for PR2 alpha2.", joint_name); 00159 } 00160 else 00161 try 00162 { 00163 theta0_ = boost::lexical_cast<double>(theta0_str); 00164 } 00165 catch (boost::bad_lexical_cast &e) 00166 { 00167 ROS_ERROR("theta0 (%s) is not a float",theta0_str); 00168 return false; 00169 } 00170 // get the phi0 coefficient 00171 const char *phi0_str = j->Attribute("phi0"); 00172 if (phi0_str == NULL) 00173 { 00174 phi0_ = 29.98717*M_PI/180.0; 00175 ROS_WARN("PR2GripperTransmission's joint \"%s\" has no coefficient: phi0, using default for PR2 alpha2.", joint_name); 00176 } 00177 else 00178 try 00179 { 00180 phi0_ = boost::lexical_cast<double>(phi0_str); 00181 } 00182 catch (boost::bad_lexical_cast &e) 00183 { 00184 ROS_ERROR("phi0 (%s) is not a float",phi0_str); 00185 return false; 00186 } 00187 // get the t0 coefficient 00188 const char *t0_str = j->Attribute("t0"); 00189 if (t0_str == NULL) 00190 { 00191 t0_ = -0.19543/1000.0; 00192 ROS_WARN("PR2GripperTransmission's joint \"%s\" has no coefficient: t0, using default for PR2 alpha2.", joint_name); 00193 } 00194 else 00195 try 00196 { 00197 t0_ = boost::lexical_cast<double>(t0_str); 00198 } 00199 catch (boost::bad_lexical_cast &e) 00200 { 00201 ROS_ERROR("t0 (%s) is not a float",t0_str); 00202 return false; 00203 } 00204 // get the L0 coefficient 00205 const char *L0_str = j->Attribute("L0"); 00206 if (L0_str == NULL) 00207 { 00208 L0_ = 34.70821/1000.0; 00209 ROS_WARN("PR2GripperTransmission's joint \"%s\" has no coefficient: L0, using default for PR2 alpha2.", joint_name); 00210 } 00211 else 00212 try 00213 { 00214 L0_ = boost::lexical_cast<double>(L0_str); 00215 } 00216 catch (boost::bad_lexical_cast &e) 00217 { 00218 ROS_ERROR("L0 (%s) is not a float",L0_str); 00219 return false; 00220 } 00221 // get the h coefficient 00222 const char *h_str = j->Attribute("h"); 00223 if (h_str == NULL) 00224 { 00225 h_ = 5.200/1000.0; 00226 ROS_WARN("PR2GripperTransmission's joint \"%s\" has no coefficient: h, using default for PR2 alpha2.", joint_name); 00227 } 00228 else 00229 try 00230 { 00231 h_ = boost::lexical_cast<double>(h_str); 00232 } 00233 catch (boost::bad_lexical_cast &e) 00234 { 00235 ROS_ERROR("h (%s) is not a float",h_str); 00236 return false; 00237 } 00238 // get the a coefficient 00239 const char *a_str = j->Attribute("a"); 00240 if (a_str == NULL) 00241 { 00242 a_ = 67.56801/1000.0; 00243 ROS_WARN("PR2GripperTransmission's joint \"%s\" has no coefficient: a, using default for PR2 alpha2.", joint_name); 00244 } 00245 else 00246 try 00247 { 00248 a_ = boost::lexical_cast<double>(a_str); 00249 } 00250 catch (boost::bad_lexical_cast &e) 00251 { 00252 ROS_ERROR("a (%s) is not a float",a_str); 00253 return false; 00254 } 00255 // get the b coefficient 00256 const char *b_str = j->Attribute("b"); 00257 if (b_str == NULL) 00258 { 00259 b_ = 48.97193/1000.0; 00260 ROS_WARN("PR2GripperTransmission's joint \"%s\" has no coefficient: b, using default for PR2 alpha2.", joint_name); 00261 } 00262 else 00263 try 00264 { 00265 b_ = boost::lexical_cast<double>(b_str); 00266 } 00267 catch (boost::bad_lexical_cast &e) 00268 { 00269 ROS_ERROR("b (%s) is not a float",b_str); 00270 return false; 00271 } 00272 // get the r coefficient 00273 const char *r_str = j->Attribute("r"); 00274 if (r_str == NULL) 00275 { 00276 r_ = 91.50000/1000.0; 00277 ROS_WARN("PR2GripperTransmission's joint \"%s\" has no coefficient: r, using default for PR2 alpha2.", joint_name); 00278 } 00279 else 00280 try 00281 { 00282 r_ = boost::lexical_cast<double>(r_str); 00283 } 00284 catch (boost::bad_lexical_cast &e) 00285 { 00286 ROS_ERROR("r (%s) is not a float",r_str); 00287 return false; 00288 } 00289 } 00290 00291 // Print all coefficients 00292 ROS_DEBUG("Gripper transmission parameters for %s: a=%f, b=%f, r=%f, h=%f, L0=%f, t0=%f, theta0=%f, phi0=%f, gear_ratio=%f, screw_red=%f", 00293 name_.c_str(), a_, b_, r_, h_, L0_, t0_, theta0_, phi0_, gear_ratio_, screw_reduction_); 00294 00295 // Get passive joint informations 00296 for (TiXmlElement *j = config->FirstChildElement("passive_joint"); j; j = j->NextSiblingElement("passive_joint")) 00297 { 00298 const char *joint_name = j->Attribute("name"); 00299 if (!joint_name) 00300 { 00301 ROS_ERROR("PR2GripperTransmission did not specify joint name"); 00302 return false; 00303 } 00304 const boost::shared_ptr<const urdf::Joint> joint = robot->robot_model_.getJoint(joint_name); 00305 00306 if (!joint) 00307 { 00308 ROS_ERROR("PR2GripperTransmission could not find joint named \"%s\"", joint_name); 00309 return false; 00310 } 00311 00312 // add joint name to list 00313 joint_names_.push_back(joint_name); // Adds the passive joints after the gap joint 00314 passive_joints_.push_back(joint_name); 00315 } 00316 00317 // Get screw joint informations 00318 for (TiXmlElement *j = config->FirstChildElement("simulated_actuated_joint"); j; j = j->NextSiblingElement("simulated_actuated_joint")) 00319 { 00320 const char *joint_name = j->Attribute("name"); 00321 if (!joint_name) 00322 { 00323 ROS_ERROR("PR2GripperTransmission simulated_actuated_joint did snot specify joint name"); 00324 use_simulated_actuated_joint_=false; 00325 } 00326 else 00327 { 00328 const boost::shared_ptr<const urdf::Joint> joint = robot->robot_model_.getJoint(joint_name); 00329 if (!joint) 00330 { 00331 ROS_ERROR("PR2GripperTransmission could not find joint named \"%s\"", joint_name); 00332 use_simulated_actuated_joint_=false; 00333 } 00334 else 00335 { 00336 use_simulated_actuated_joint_=true; 00337 joint_names_.push_back(joint_name); // The first joint is the gap joint 00338 00339 // get the thread pitch 00340 const char *simulated_reduction = j->Attribute("simulated_reduction"); 00341 if (!simulated_reduction) 00342 { 00343 ROS_ERROR("PR2GripperTransmission's joint \"%s\" has no coefficient: simulated_reduction.", joint_name); 00344 return false; 00345 } 00346 try 00347 { 00348 simulated_reduction_ = boost::lexical_cast<double>(simulated_reduction); 00349 } 00350 catch (boost::bad_lexical_cast &e) 00351 { 00352 ROS_ERROR("simulated_reduction (%s) is not a float",simulated_reduction); 00353 return false; 00354 } 00355 00356 // get any additional joint introduced from this screw joint implementation 00357 // for the gripper, this is due to the limitation that screw constraint 00358 // requires axis of rotation to be aligned with line between CG's of the two 00359 // connected bodies. For this reason, an additional slider joint was introduced 00360 // thus, requiring joint state to be published for motion planning packages 00361 // and that's why we're here. 00362 const char *passive_actuated_joint_name = j->Attribute("passive_actuated_joint"); 00363 if (passive_actuated_joint_name) 00364 { 00365 const boost::shared_ptr<const urdf::Joint> passive_actuated_joint = robot->robot_model_.getJoint(passive_actuated_joint_name); 00366 if (passive_actuated_joint) 00367 { 00368 has_simulated_passive_actuated_joint_ = true; 00369 joint_names_.push_back(passive_actuated_joint_name); // The first joint is the gap joint 00370 } 00371 } 00372 00373 } 00374 } 00375 } 00376 00377 // assuming simulated gripper prismatic joint exists, use it 00378 00379 return true; 00380 } 00381 00382 bool PR2GripperTransmission::initXml(TiXmlElement *config) 00383 { 00384 const char *name = config->Attribute("name"); 00385 name_ = name ? name : ""; 00386 //myfile.open("transmission_data.txt"); 00387 TiXmlElement *ael = config->FirstChildElement("actuator"); 00388 const char *actuator_name = ael ? ael->Attribute("name") : NULL; 00389 if (!actuator_name) 00390 { 00391 ROS_ERROR("PR2GripperTransmission could not find actuator named \"%s\"", actuator_name); 00392 return false; 00393 } 00394 actuator_names_.push_back(actuator_name); 00395 00396 for (TiXmlElement *j = config->FirstChildElement("gap_joint"); j; j = j->NextSiblingElement("gap_joint")) 00397 { 00398 const char *joint_name = j->Attribute("name"); 00399 if (!joint_name) 00400 { 00401 ROS_ERROR("PR2GripperTransmission did not specify joint name"); 00402 return false; 00403 } 00404 gap_joint_ = std::string(joint_name); 00405 joint_names_.push_back(joint_name); // The first joint is the gap joint 00406 00407 // get the mechanical reduction 00408 const char *joint_reduction = j->Attribute("mechanical_reduction"); 00409 if (!joint_reduction) 00410 { 00411 ROS_ERROR("PR2GripperTransmission's joint \"%s\" has no coefficient: mechanical reduction.", joint_name); 00412 return false; 00413 } 00414 try 00415 { 00416 gap_mechanical_reduction_ = boost::lexical_cast<double>(joint_reduction); 00417 } 00418 catch (boost::bad_lexical_cast &e) 00419 { 00420 ROS_ERROR("joint_reduction (%s) is not a float",joint_reduction); 00421 return false; 00422 } 00423 00424 // get the screw drive reduction 00425 const char *screw_reduction_str = j->Attribute("screw_reduction"); 00426 if (screw_reduction_str == NULL) 00427 { 00428 screw_reduction_ = 2.0/1000.0; 00429 ROS_WARN("PR2GripperTransmission's joint \"%s\" has no coefficient: screw drive reduction, using default for PR2 alpha2.", joint_name); 00430 } 00431 else 00432 try 00433 { 00434 screw_reduction_ = boost::lexical_cast<double>(screw_reduction_str); 00435 } 00436 catch (boost::bad_lexical_cast &e) 00437 { 00438 ROS_ERROR("screw_reduction (%s) is not a float",screw_reduction_str); 00439 return false; 00440 } 00441 //ROS_INFO("screw drive reduction. %f", screw_reduction_); 00442 00443 // get the gear_ratio 00444 const char *gear_ratio_str = j->Attribute("gear_ratio"); 00445 if (gear_ratio_str == NULL) 00446 { 00447 gear_ratio_ = 29.16; 00448 ROS_WARN("PR2GripperTransmission's joint \"%s\" has no coefficient: gear_ratio, using default for PR2 alpha2.", joint_name); 00449 } 00450 else 00451 try 00452 { 00453 gear_ratio_ = boost::lexical_cast<double>(gear_ratio_str); 00454 } 00455 catch (boost::bad_lexical_cast &e) 00456 { 00457 ROS_ERROR("gear_ratio (%s) is not a float",gear_ratio_str); 00458 return false; 00459 } 00460 //ROS_INFO("gear_ratio. %f", gear_ratio_); 00461 00462 // get the theta0 coefficient 00463 const char *theta0_str = j->Attribute("theta0"); 00464 if (theta0_str == NULL) 00465 { 00466 theta0_ = 2.97571*M_PI/180.0; 00467 ROS_WARN("PR2GripperTransmission's joint \"%s\" has no coefficient: theta0, using default for PR2 alpha2.", joint_name); 00468 } 00469 else 00470 try 00471 { 00472 theta0_ = boost::lexical_cast<double>(theta0_str); 00473 } 00474 catch (boost::bad_lexical_cast &e) 00475 { 00476 ROS_ERROR("theta0 (%s) is not a float",theta0_str); 00477 return false; 00478 } 00479 // get the phi0 coefficient 00480 const char *phi0_str = j->Attribute("phi0"); 00481 if (phi0_str == NULL) 00482 { 00483 phi0_ = 29.98717*M_PI/180.0; 00484 ROS_WARN("PR2GripperTransmission's joint \"%s\" has no coefficient: phi0, using default for PR2 alpha2.", joint_name); 00485 } 00486 else 00487 try 00488 { 00489 phi0_ = boost::lexical_cast<double>(phi0_str); 00490 } 00491 catch (boost::bad_lexical_cast &e) 00492 { 00493 ROS_ERROR("phi0 (%s) is not a float",phi0_str); 00494 return false; 00495 } 00496 // get the t0 coefficient 00497 const char *t0_str = j->Attribute("t0"); 00498 if (t0_str == NULL) 00499 { 00500 t0_ = -0.19543/1000.0; 00501 ROS_WARN("PR2GripperTransmission's joint \"%s\" has no coefficient: t0, using default for PR2 alpha2.", joint_name); 00502 } 00503 else 00504 try 00505 { 00506 t0_ = boost::lexical_cast<double>(t0_str); 00507 } 00508 catch (boost::bad_lexical_cast &e) 00509 { 00510 ROS_ERROR("t0 (%s) is not a float",t0_str); 00511 return false; 00512 } 00513 // get the L0 coefficient 00514 const char *L0_str = j->Attribute("L0"); 00515 if (L0_str == NULL) 00516 { 00517 L0_ = 34.70821/1000.0; 00518 ROS_WARN("PR2GripperTransmission's joint \"%s\" has no coefficient: L0, using default for PR2 alpha2.", joint_name); 00519 } 00520 else 00521 try 00522 { 00523 L0_ = boost::lexical_cast<double>(L0_str); 00524 } 00525 catch (boost::bad_lexical_cast &e) 00526 { 00527 ROS_ERROR("L0 (%s) is not a float",L0_str); 00528 return false; 00529 } 00530 // get the h coefficient 00531 const char *h_str = j->Attribute("h"); 00532 if (h_str == NULL) 00533 { 00534 h_ = 5.200/1000.0; 00535 ROS_WARN("PR2GripperTransmission's joint \"%s\" has no coefficient: h, using default for PR2 alpha2.", joint_name); 00536 } 00537 else 00538 try 00539 { 00540 h_ = boost::lexical_cast<double>(h_str); 00541 } 00542 catch (boost::bad_lexical_cast &e) 00543 { 00544 ROS_ERROR("h (%s) is not a float",h_str); 00545 return false; 00546 } 00547 // get the a coefficient 00548 const char *a_str = j->Attribute("a"); 00549 if (a_str == NULL) 00550 { 00551 a_ = 67.56801/1000.0; 00552 ROS_WARN("PR2GripperTransmission's joint \"%s\" has no coefficient: a, using default for PR2 alpha2.", joint_name); 00553 } 00554 else 00555 try 00556 { 00557 a_ = boost::lexical_cast<double>(a_str); 00558 } 00559 catch (boost::bad_lexical_cast &e) 00560 { 00561 ROS_ERROR("a (%s) is not a float",a_str); 00562 return false; 00563 } 00564 // get the b coefficient 00565 const char *b_str = j->Attribute("b"); 00566 if (b_str == NULL) 00567 { 00568 b_ = 48.97193/1000.0; 00569 ROS_WARN("PR2GripperTransmission's joint \"%s\" has no coefficient: b, using default for PR2 alpha2.", joint_name); 00570 } 00571 else 00572 try 00573 { 00574 b_ = boost::lexical_cast<double>(b_str); 00575 } 00576 catch (boost::bad_lexical_cast &e) 00577 { 00578 ROS_ERROR("b (%s) is not a float",b_str); 00579 return false; 00580 } 00581 // get the r coefficient 00582 const char *r_str = j->Attribute("r"); 00583 if (r_str == NULL) 00584 { 00585 r_ = 91.50000/1000.0; 00586 ROS_WARN("PR2GripperTransmission's joint \"%s\" has no coefficient: r, using default for PR2 alpha2.", joint_name); 00587 } 00588 else 00589 try 00590 { 00591 r_ = boost::lexical_cast<double>(r_str); 00592 } 00593 catch (boost::bad_lexical_cast &e) 00594 { 00595 ROS_ERROR("r (%s) is not a float",r_str); 00596 return false; 00597 } 00598 } 00599 00600 // Print all coefficients 00601 ROS_DEBUG("Gripper transmission parameters for %s: a=%f, b=%f, r=%f, h=%f, L0=%f, t0=%f, theta0=%f, phi0=%f, gear_ratio=%f, screw_red=%f", 00602 name_.c_str(), a_, b_, r_, h_, L0_, t0_, theta0_, phi0_, gear_ratio_, screw_reduction_); 00603 00604 // Get passive joint informations 00605 for (TiXmlElement *j = config->FirstChildElement("passive_joint"); j; j = j->NextSiblingElement("passive_joint")) 00606 { 00607 const char *joint_name = j->Attribute("name"); 00608 if (!joint_name) 00609 { 00610 ROS_ERROR("PR2GripperTransmission did not specify joint name"); 00611 return false; 00612 } 00613 00614 // add joint name to list 00615 joint_names_.push_back(joint_name); // Adds the passive joints after the gap joint 00616 passive_joints_.push_back(joint_name); 00617 } 00618 00619 // Get screw joint informations 00620 for (TiXmlElement *j = config->FirstChildElement("simulated_actuated_joint"); j; j = j->NextSiblingElement("simulated_actuated_joint")) 00621 { 00622 const char *joint_name = j->Attribute("name"); 00623 if (!joint_name) 00624 { 00625 ROS_ERROR("PR2GripperTransmission screw joint did not specify joint name"); 00626 use_simulated_actuated_joint_=false; 00627 } 00628 else 00629 { 00630 use_simulated_actuated_joint_=true; 00631 joint_names_.push_back(joint_name); // The first joint is the gap joint 00632 00633 // get the thread pitch 00634 const char *simulated_reduction = j->Attribute("simulated_reduction"); 00635 if (!simulated_reduction) 00636 { 00637 ROS_ERROR("PR2GripperTransmission's joint \"%s\" has no coefficient: simulated_reduction.", joint_name); 00638 return false; 00639 } 00640 try 00641 { 00642 simulated_reduction_ = boost::lexical_cast<double>(simulated_reduction); 00643 } 00644 catch (boost::bad_lexical_cast &e) 00645 { 00646 ROS_ERROR("simulated_reduction (%s) is not a float",simulated_reduction); 00647 return false; 00648 } 00649 00650 // get any additional joint introduced from this screw joint implementation 00651 // for the gripper, this is due to the limitation that screw constraint 00652 // requires axis of rotation to be aligned with line between CG's of the two 00653 // connected bodies. For this reason, an additional slider joint was introduced 00654 // thus, requiring joint state to be published for motion planning packages 00655 // and that's why we're here. 00656 const char *passive_actuated_joint_name = j->Attribute("passive_actuated_joint"); 00657 if (passive_actuated_joint_name) 00658 { 00659 has_simulated_passive_actuated_joint_ = true; 00660 joint_names_.push_back(passive_actuated_joint_name); // The first joint is the gap joint 00661 } 00662 00663 } 00664 } 00665 00666 // assuming simulated gripper prismatic joint exists, use it 00667 00668 return true; 00669 } 00670 00673 void PR2GripperTransmission::computeGapStates( 00674 double MR,double MR_dot,double MT, 00675 double &theta,double &dtheta_dMR,double &dt_dtheta,double &dt_dMR,double &gap_size,double &gap_velocity,double &gap_effort) 00676 { 00677 // 00678 // below transforms from encoder value to gap size, based on 090224_link_data.xls provided by Functions Engineering 00679 // 00680 double u = (a_*a_+b_*b_-h_*h_ 00681 -pow(L0_+MR*screw_reduction_/gear_ratio_,2))/(2.0*a_*b_); 00682 u = u < -1.0 ? -1.0 : u > 1.0 ? 1.0 : u; 00683 theta = theta0_ - phi0_ + acos(u); 00684 // limit theta 00685 //theta = theta > 0 ? theta : 0; 00686 // force theta to be greater than theta0_ 00687 //theta = angles::normalize_angle_positive(angles::shortest_angular_distance(theta0_,theta))+theta0_; 00688 00689 gap_size = t0_ + r_ * ( sin(theta) - sin(theta0_) ); 00690 00691 // 00692 // compute jacobians based on transforms, get the velocity of the gripper gap size based on encoder velocity 00693 // 00694 // for jacobian, we want to limit MR >= 0 00695 MR = MR >= 0.0 ? MR : 0.0; 00696 // then recompute u and theta based on restricted MR 00697 u = (a_*a_+b_*b_-h_*h_ 00698 -pow(L0_+MR*screw_reduction_/gear_ratio_,2))/(2.0*a_*b_); 00699 u = u < -1.0 ? -1.0 : u > 1.0 ? 1.0 : u; 00700 double tmp_theta = theta0_ - phi0_ + acos(u); 00701 00702 // 00703 double arg = 1.0 - pow(u,2); 00704 arg = arg > TOL ? arg : TOL; //LIMIT: CAP u at TOL artificially 00705 00706 double du_dMR = -(L0_ * screw_reduction_)/(gear_ratio_*a_*b_) // d(arg)/d(MR) 00707 -MR/(a_*b_)*pow(screw_reduction_/gear_ratio_,2); 00708 00709 dtheta_dMR = -1.0/sqrt(arg) * du_dMR; // derivative of acos 00710 00711 dt_dtheta = r_ * cos( tmp_theta ); 00712 dt_dMR = dt_dtheta * dtheta_dMR; 00713 gap_velocity = MR_dot * dt_dMR; 00714 00715 // 00716 // get the effort at the gripper gap based on torque at the motor 00717 // gap effort = motor torque * dmotor_theta/dt 00718 // = MT * dmotor_theta_dt 00719 // = MT * dMR_dt / (2*pi) 00720 // = MT / dt_dMR * 2*pi 00721 // 00722 gap_effort = MT / dt_dMR / RAD2MR ; 00723 //ROS_WARN("debug: %f %f %f",gap_effort,MT,dt_dMR,RAD2MR); 00724 } 00725 00730 void PR2GripperTransmission::inverseGapStates( 00731 double gap_size,double &MR,double &dMR_dtheta,double &dtheta_dt,double &dMR_dt) 00732 { 00733 // get theta for jacobian calculation 00734 double sin_theta = (gap_size - t0_)/r_ + sin(theta0_); 00735 sin_theta = sin_theta > 1.0 ? 1.0 : sin_theta < -1.0 ? -1.0 : sin_theta; 00736 double theta = asin(sin_theta); 00737 00738 // compute inverse transform for the gap joint, returns MR and dMR_dtheta 00739 inverseGapStates1(theta,MR,dMR_dtheta,dtheta_dt,dMR_dt); 00740 } 00741 00746 void PR2GripperTransmission::inverseGapStates1( 00747 double theta,double &MR,double &dMR_dtheta,double &dtheta_dt,double &dMR_dt) 00748 { 00749 // limit theta 00750 //theta = theta > 0 ? theta : 0; 00751 // force theta to be greater than theta0_ 00752 //theta = angles::normalize_angle_positive(angles::shortest_angular_distance(theta0_,theta))+theta0_; 00753 00754 // now do the reverse transform 00755 double arg = -2.0*a_*b_*cos(theta-theta0_+phi0_) 00756 -h_*h_+a_*a_+b_*b_; 00757 if (arg > 0.0) 00758 { 00759 MR = gear_ratio_/screw_reduction_ * ( sqrt(arg) - L0_ ); 00760 dMR_dtheta = gear_ratio_/(2.0 * screw_reduction_) / sqrt(arg) 00761 * 2.0 * a_ * b_ * sin(theta + phi0_ - theta0_); 00762 } 00763 else 00764 { 00765 MR = gear_ratio_/screw_reduction_ * ( 0.0 - L0_ ); 00766 dMR_dtheta = 0.0; 00767 } 00768 00769 // compute gap_size from theta 00770 double gap_size = t0_ + r_ * ( sin(theta) - sin(theta0_) ); // in mm 00771 00772 // compute inverse jacobians for the transform 00773 // for this, enforce dMR_dtheta >= 0 00774 // since there are two roots, take the positive root 00775 // @todo: this affects sim only, need to check this for sim. 00776 double tmp_dMR_dtheta = fabs(dMR_dtheta); 00777 00778 double u = (gap_size - t0_)/r_ + sin(theta0_); 00779 double arg2 = 1.0 - pow(u,2); 00780 arg2 = arg2 > TOL ? arg2 : TOL; //LIMIT: CAP arg2 at TOL artificially 00781 dtheta_dt = 1.0 / sqrt( arg2 ) / r_; // derivative of asin 00782 dMR_dt = tmp_dMR_dtheta * dtheta_dt; // remember, here, t is gap_size 00783 } 00784 00785 00789 void PR2GripperTransmission::propagatePosition( 00790 std::vector<Actuator*>& as, std::vector<JointState*>& js) 00791 { 00792 00793 ROS_ASSERT(as.size() == 1); 00794 // js has passive joints and 1 gap joint and 1 screw joint 00795 if (use_simulated_actuated_joint_ && has_simulated_passive_actuated_joint_) 00796 {ROS_ASSERT(js.size() == 1 + passive_joints_.size() + 2);} 00797 else if (use_simulated_actuated_joint_) {ROS_ASSERT(js.size() == 1 + passive_joints_.size() + 1);} 00798 else {ROS_ASSERT(js.size() == 1 + passive_joints_.size());} 00799 00803 double MR = as[0]->state_.position_ / gap_mechanical_reduction_ * RAD2MR ; 00804 00806 double MR_dot = as[0]->state_.velocity_ / gap_mechanical_reduction_ * RAD2MR ; 00807 00817 //double MT = as[0]->state_.last_measured_effort_ / gap_mechanical_reduction_ * RAD2MR ; 00818 00819 00821 double MT = as[0]->state_.last_measured_effort_ / gap_mechanical_reduction_; 00822 00824 double theta, dtheta_dMR, dt_dtheta, dt_dMR; 00826 double gap_size,gap_velocity,gap_effort; 00827 00828 // compute gap position, velocity, measured_effort from actuator states 00829 computeGapStates(MR,MR_dot,MT,theta,dtheta_dMR, dt_dtheta, dt_dMR,gap_size,gap_velocity,gap_effort); 00830 00831 // Determines the state of the gap joint. 00832 js[0]->position_ = gap_size*2.0; // function engineering's transmission give half the total gripper size 00833 js[0]->velocity_ = gap_velocity*2.0; 00834 js[0]->measured_effort_ = gap_effort/2.0; 00835 //ROS_ERROR("prop pos eff=%f",js[0]->measured_effort_); 00836 00837 // Determines the states of the passive joints. 00838 // we need to do this for each finger, in simulation, each finger has it's state filled out 00839 for (size_t i = 1; i < passive_joints_.size()+1; ++i) 00840 { 00841 js[i]->position_ = theta - theta0_; 00842 js[i]->velocity_ = dtheta_dMR * MR_dot; 00843 js[i]->measured_effort_ = MT / dtheta_dMR / RAD2MR; 00844 js[i]->reference_position_ = MT / dtheta_dMR / RAD2MR; 00845 } 00846 00847 if (use_simulated_actuated_joint_) 00848 { 00849 // screw joint state is not important to us, fill with zeros 00850 js[passive_joints_.size()+1]->position_ = 0.0; 00851 js[passive_joints_.size()+1]->velocity_ = 0.0; 00852 js[passive_joints_.size()+1]->measured_effort_ = 0.0; 00853 js[passive_joints_.size()+1]->reference_position_ = 0.0; 00854 js[passive_joints_.size()+1]->calibrated_ = true; // treat passive simulation joints as "calibrated" 00855 } 00856 if (has_simulated_passive_actuated_joint_) 00857 { 00858 // screw joint state is not important to us, fill with zeros 00859 js[passive_joints_.size()+2]->position_ = 0.0; 00860 js[passive_joints_.size()+2]->velocity_ = 0.0; 00861 js[passive_joints_.size()+2]->measured_effort_ = 0.0; 00862 js[passive_joints_.size()+2]->reference_position_ = 0.0; 00863 js[passive_joints_.size()+2]->calibrated_ = true; // treat passive simulation joints as "calibrated" 00864 } 00865 } 00866 00867 // this is needed for simulation, so we can recover encoder value given joint angles 00868 void PR2GripperTransmission::propagatePositionBackwards( 00869 std::vector<JointState*>& js, std::vector<Actuator*>& as) 00870 { 00871 ROS_ASSERT(as.size() == 1); 00872 if (use_simulated_actuated_joint_) {ROS_ASSERT(js.size() == 1 + passive_joints_.size() + 1);} 00873 else {ROS_ASSERT(js.size() == 1 + passive_joints_.size());} 00874 00875 // keep the simulation stable by using the minimum rate joint to compute gripper gap rate 00876 double MR,dMR_dtheta,dtheta_dt,dMR_dt; 00877 double joint_rate; 00878 { 00879 // new gripper model has an actual physical slider joint in simulation 00880 // use the new slider joint for determining gipper position, so forward/backward are consistent 00881 double gap_size = js[0]->position_/2.0; // js position should be normalized 00882 // compute inverse transform for the gap joint, returns MR and dMR_dtheta 00883 inverseGapStates(gap_size,MR,dMR_dtheta,dtheta_dt,dMR_dt); 00884 double gap_rate = js[0]->velocity_/2.0; 00885 joint_rate = gap_rate * dtheta_dt; 00886 } 00887 double gap_effort = js[0]->commanded_effort_; 00888 00889 //ROS_ERROR("prop pos back eff=%f",gap_effort); 00890 00892 as[0]->state_.position_ = MR * gap_mechanical_reduction_ / RAD2MR ; 00893 00896 as[0]->state_.velocity_ = joint_rate * dMR_dtheta * gap_mechanical_reduction_ / RAD2MR ; 00897 00901 as[0]->state_.last_measured_effort_ = 2.0*gap_effort / dMR_dt * RAD2MR * gap_mechanical_reduction_; 00902 00903 // Update the timing (making sure it's initialized). 00904 if (! simulated_actuator_timestamp_initialized_) 00905 { 00906 // Set the time stamp to zero (it is measured relative to the start time). 00907 as[0]->state_.sample_timestamp_ = ros::Duration(0); 00908 00909 // Try to set the start time. Only then do we claim initialized. 00910 if (ros::isStarted()) 00911 { 00912 simulated_actuator_start_time_ = ros::Time::now(); 00913 simulated_actuator_timestamp_initialized_ = true; 00914 } 00915 } 00916 else 00917 { 00918 // Measure the time stamp relative to the start time. 00919 as[0]->state_.sample_timestamp_ = ros::Time::now() - simulated_actuator_start_time_; 00920 } 00921 // Set the historical (double) timestamp accordingly. 00922 as[0]->state_.timestamp_ = as[0]->state_.sample_timestamp_.toSec(); 00923 00924 // simulate calibration sensors by filling out actuator states 00925 this->joint_calibration_simulator_.simulateJointCalibration(js[0],as[0]); 00926 } 00927 00928 void PR2GripperTransmission::propagateEffort( 00929 std::vector<JointState*>& js, std::vector<Actuator*>& as) 00930 { 00931 ROS_ASSERT(as.size() == 1); 00932 if (use_simulated_actuated_joint_ && has_simulated_passive_actuated_joint_) 00933 {ROS_ASSERT(js.size() == 1 + passive_joints_.size() + 2);} 00934 else if (use_simulated_actuated_joint_) {ROS_ASSERT(js.size() == 1 + passive_joints_.size() + 1);} 00935 else {ROS_ASSERT(js.size() == 1 + passive_joints_.size());} 00936 00937 // 00938 // in hardware, the position of passive joints are set by propagatePosition, so they should be identical and 00939 // the inverse transform should be consistent. 00940 // note for simulation: 00941 // new gripper model has an actual physical slider joint in simulation 00942 // use the new slider joint for determining gipper position, so forward/backward are consistent 00943 double gap_size = js[0]->position_/2.0; // js position should be normalized 00944 00945 // now do the reverse transform 00946 double MR,dMR_dtheta,dtheta_dt,dMR_dt; 00947 // compute inverse transform for the gap joint, returns MR and dMR_dtheta 00948 inverseGapStates(gap_size,MR,dMR_dtheta,dtheta_dt,dMR_dt); 00949 00950 double gap_effort = js[0]->commanded_effort_; 00951 00952 //ROS_ERROR("prop eff eff=%f",gap_effort); 00953 00955 as[0]->command_.enable_ = true; 00956 as[0]->command_.effort_ = 2.0*gap_effort / dMR_dt * RAD2MR * gap_mechanical_reduction_; 00957 } 00958 00959 void PR2GripperTransmission::propagateEffortBackwards( 00960 std::vector<Actuator*>& as, std::vector<JointState*>& js) 00961 { 00962 ROS_ASSERT(as.size() == 1); 00963 if (use_simulated_actuated_joint_) {ROS_ASSERT(js.size() == 1 + passive_joints_.size() + 1);} 00964 else {ROS_ASSERT(js.size() == 1 + passive_joints_.size());} 00965 ROS_ASSERT(simulated_reduction_>0.0); 00966 00967 // 00968 // below transforms from encoder value to gap size, based on 090224_link_data.xls provided by Functions Engineering 00969 // 00971 double MR = as[0]->state_.position_ / gap_mechanical_reduction_ * RAD2MR ; 00972 double MR_dot = as[0]->state_.velocity_ / gap_mechanical_reduction_ * RAD2MR ; 00973 double MT = as[0]->command_.effort_ / gap_mechanical_reduction_; 00974 00976 double theta, dtheta_dMR, dt_dtheta, dt_dMR; 00978 double gap_size,gap_velocity,gap_effort; 00979 00980 // compute gap position, velocity, measured_effort from actuator states 00981 computeGapStates(MR,MR_dot,MT,theta,dtheta_dMR, dt_dtheta, dt_dMR,gap_size,gap_velocity,gap_effort); 00982 00983 { 00984 // propagate fictitious joint effort backwards 00985 //ROS_ERROR("prop eff back eff=%f",js[0]->commanded_effort_); 00986 if (use_simulated_actuated_joint_) 00987 { 00988 // set screw joint effort if simulated 00989 js[passive_joints_.size()+1]->commanded_effort_ = gap_effort/simulated_reduction_; 00990 } 00991 else 00992 { 00993 // an ugly hack to lessen instability due to gripper gains 00994 double eps=0.01; 00995 js[0]->commanded_effort_ = (1.0-eps)*js[0]->commanded_effort_ + eps*gap_effort/2.0; // skip slider joint effort 00996 } 00997 } 00998 } 00999