00001 #include <convenience_ros_functions/ROSFunctions.h>
00002 #include <convenience_math_functions/MathFunctions.h>
00003 #include <algorithm>
00004
00005 #include <Eigen/Core>
00006 #include <Eigen/Geometry>
00007 #include <eigen_conversions/eigen_msg.h>
00008
00009 #define INIT_SINGLETON_SLEEP_SECS 0.5
00010
00011 using convenience_ros_functions::ROSFunctions;
00012
00013 ROSFunctions::ROSFunctionsPtr ROSFunctions::_singleton;
00014 baselib_binding::recursive_mutex ROSFunctions::slock;
00015
00016 ROSFunctions::ROSFunctions(float tf_max_cache_time):
00017 tf_listener(ros::Duration(tf_max_cache_time))
00018 {
00019 }
00020
00021 void ROSFunctions::initSingleton()
00022 {
00023 slock.lock();
00024 if (!_singleton.get())
00025 {
00026 _singleton = ROSFunctionsPtr(new ROSFunctions());
00027 if (!ros::ok())
00028 {
00029 ROS_ERROR("Calling ROSFunctions::initSingleton() outside a valid ROS context. This will likely lead to problems.");
00030 return;
00031 }
00032 ros::Duration(INIT_SINGLETON_SLEEP_SECS).sleep();
00033 }
00034 slock.unlock();
00035 }
00036 void ROSFunctions::destroySingleton()
00037 {
00038 slock.lock();
00039 if (_singleton.get()) _singleton = ROSFunctionsPtr((ROSFunctions*)NULL);
00040 slock.unlock();
00041 }
00042
00043 ROSFunctions::ROSFunctionsPtr ROSFunctions::Singleton()
00044 {
00045 slock.lock();
00046 if (!_singleton.get())
00047 {
00048 ROS_WARN_STREAM("Calling ROSFunctions::Singleton() without having called ROSFunctions::initSingleton()"
00049 <<" before. This will incur a small wait by ROSFunctions::initSingleton() which is required"
00050 <<" to wait a bit for the tf listener to get running and avoid problems with tf transforms.");
00051 initSingleton();
00052 }
00053 slock.unlock();
00054 return ROSFunctionsPtr(_singleton);
00055 }
00056
00057
00058 void ROSFunctions::applyTransform(const geometry_msgs::Pose& transform, geometry_msgs::Pose& pose)
00059 {
00060 pose.position.x += transform.position.x;
00061 pose.position.y += transform.position.y;
00062 pose.position.z += transform.position.z;
00063
00064 Eigen::Quaterniond qPose, qTrans, qRes;
00065 tf::quaternionMsgToEigen(pose.orientation, qPose);
00066 tf::quaternionMsgToEigen(transform.orientation, qTrans);
00067
00068 qRes = qPose * qTrans;
00069
00070 tf::quaternionEigenToMsg(qTrans, pose.orientation);
00071 }
00072
00073 bool ROSFunctions::canGetTransform(const std::string& f1, const std::string& f2,
00074 const ros::Time& useTime, bool printError) const
00075 {
00076
00077 if (f1.empty() || f2.empty())
00078 {
00079 if (printError) ROS_ERROR("Frame ID's must be both set");
00080 return false;
00081 }
00082
00083 if (!tf_listener.frameExists(f1) || !tf_listener.frameExists(f2))
00084 {
00085
00086 return false;
00087 }
00088
00089 std::string error_msg;
00090 if (!tf_listener.canTransform(f1, f2, useTime, &error_msg))
00091 {
00092
00093 return false;
00094 }
00095
00096 return true;
00097 }
00098
00099 bool ROSFunctions::canGetTransform(const std_msgs::Header& p1, const std_msgs::Header& p2,
00100 bool latest, bool printError) const
00101 {
00102 float _time;
00103 if (latest) _time = std::max(p1.stamp.toSec(), p2.stamp.toSec());
00104 else _time = 0;
00105 ros::Time useTime(_time);
00106 return canGetTransform(p1.frame_id, p2.frame_id, useTime, printError);
00107 }
00108
00109
00110 bool ROSFunctions::waitForTransform(const std::string& f1, const std::string& f2,
00111 const ros::Time& useTime, const float& timeout, bool printError)
00112 {
00113 if (f1.empty() || f2.empty())
00114 {
00115 if (printError) ROS_ERROR("Frame ID's must be both set");
00116 return false;
00117 }
00118
00119 ros::Time start = ros::Time::now();
00120 float waited = 0;
00121 std::string error_msg;
00122
00123 if (!tf_listener.waitForTransform(f1, f2, useTime, ros::Duration(timeout), ros::Duration(0.01), &error_msg))
00124 {
00125 if (printError) ROS_ERROR("Failed to wait for transform between frames %s and %s: tf error msg=%s", f1.c_str(), f2.c_str(), error_msg.c_str());
00126 return false;
00127 }
00128
00129 while (!tf_listener.frameExists(f1) || !tf_listener.frameExists(f2))
00130 {
00131 ros::Duration(0.05).sleep();
00132 ros::Time t = ros::Time::now();
00133 waited += (t - start).toSec();
00134 if (timeout > 1e-04)
00135 {
00136 if (waited > timeout) break;
00137 }
00138 if (!tf_listener.waitForTransform(f1, f2, useTime,
00139 ros::Duration(timeout > 1e-04 ? timeout - waited : timeout), ros::Duration(0.01), &error_msg))
00140 {
00141 if (printError)
00142 ROS_ERROR("Failed to wait for transform between NEW frames %s and %s: %s",
00143 f1.c_str(), f2.c_str(), error_msg.c_str());
00144 return false;
00145 }
00146 }
00147
00148 return true;
00149 }
00150
00151
00152
00153 bool ROSFunctions::waitForTransform(const std_msgs::Header& p1, const std_msgs::Header& p2,
00154 const float& timeout, bool latest, bool printError)
00155 {
00156 float _time;
00157 if (latest) _time = std::max(p1.stamp.toSec(), p2.stamp.toSec());
00158 else _time = 0;
00159 ros::Time useTime(_time);
00160
00161 return waitForTransform(p1.frame_id, p2.frame_id, useTime, timeout, printError);
00162 }
00163
00164
00165
00166
00167 int ROSFunctions::equalPoses(const geometry_msgs::PoseStamped& p1, const geometry_msgs::PoseStamped& p2, float accuracy_pose,
00168 float accuracy_rad, bool useLatestTime, float maxWaitTransform, bool printErrors)
00169 {
00170 geometry_msgs::Pose rel;
00171 int ret = relativePose(p1, p2, rel, useLatestTime, maxWaitTransform, printErrors);
00172 if (ret < 0) return ret;
00173
00174
00175
00176 Eigen::Vector3d dist;
00177 Eigen::Quaterniond ori;
00178 tf::pointMsgToEigen(rel.position, dist);
00179 tf::quaternionMsgToEigen(rel.orientation, ori);
00180
00181 double angleDist = convenience_math_functions::MathFunctions::capToPI(Eigen::AngleAxisd(ori).angle());
00182
00183
00184
00185
00186
00187 return (dist.norm() <= accuracy_pose) && (fabs(angleDist) <= accuracy_rad) ? 1 : 0;
00188 }
00189
00190 int ROSFunctions::poseDistance(const geometry_msgs::PoseStamped& p1, const geometry_msgs::PoseStamped& p2, float& posDist, float& angleDist,
00191 bool useLatestTime, float maxWaitTransform, bool printErrors)
00192 {
00193
00194
00195 geometry_msgs::Pose rel;
00196 int ret = relativePose(p1, p2, rel, useLatestTime, maxWaitTransform, printErrors);
00197 if (ret < 0) return ret;
00198
00199
00200
00201 Eigen::Vector3d dist;
00202 Eigen::Quaterniond ori;
00203 tf::pointMsgToEigen(rel.position, dist);
00204 tf::quaternionMsgToEigen(rel.orientation, ori);
00205
00206 angleDist = convenience_math_functions::MathFunctions::capToPI(Eigen::AngleAxisd(ori).angle());
00207 posDist = dist.norm();
00208
00209
00210
00211 return 0;
00212 }
00213
00214 int ROSFunctions::relativePose(const geometry_msgs::PoseStamped& origin, const geometry_msgs::PoseStamped& other,
00215 geometry_msgs::Pose& result, bool useLatestTime, float maxWaitTransform, bool printErrors)
00216 {
00217
00218 if (origin.header.frame_id.empty() || other.header.frame_id.empty())
00219 {
00220 if (printErrors) ROS_ERROR("Frame ID's must be both set");
00221 return -1;
00222 }
00223
00224 float _time;
00225 if (useLatestTime)
00226 _time = std::max(origin.header.stamp.toSec(), other.header.stamp.toSec());
00227 else _time = 0;
00228 ros::Time useTime(_time);
00229
00230
00231 if (!canGetTransform(origin.header.frame_id, other.header.frame_id, useTime, printErrors))
00232 {
00233 if (maxWaitTransform > 0)
00234 {
00235
00236 if (!waitForTransform(origin.header.frame_id, other.header.frame_id, useTime, maxWaitTransform, printErrors))
00237 {
00238 if (printErrors) ROS_ERROR("Could not wait for the transform");
00239 return -2;
00240 }
00241
00242 }
00243 else
00244 {
00245 if (printErrors) ROS_ERROR("Could not get the transform to get the relative pose");
00246 return -1;
00247 }
00248 }
00249
00250 geometry_msgs::PoseStamped transTo;
00251 geometry_msgs::PoseStamped _other = other;
00252 _other.header.stamp = useTime;
00253 try
00254 {
00255 tf_listener.transformPose(origin.header.frame_id, _other, transTo);
00256 }
00257 catch (tf::TransformException ex)
00258 {
00259 if (printErrors) ROS_ERROR("Could not get transform: %s", ex.what());
00260 return -3;
00261 }
00262
00263 result.position.x = transTo.pose.position.x - origin.pose.position.x;
00264 result.position.y = transTo.pose.position.y - origin.pose.position.y;
00265 result.position.z = transTo.pose.position.z - origin.pose.position.z;
00266
00267 Eigen::Quaterniond ori1, ori2;
00268 tf::quaternionMsgToEigen(origin.pose.orientation, ori1);
00269 tf::quaternionMsgToEigen(transTo.pose.orientation, ori2);
00270 Eigen::Quaterniond relOri = convenience_math_functions::MathFunctions::getRotationFromTo(ori1, ori2);
00271 tf::quaternionEigenToMsg(relOri, result.orientation);
00272
00273 return 0;
00274
00275 }
00276
00277 int ROSFunctions::transformPose(const geometry_msgs::PoseStamped& p, const std::string& frame_id,
00278 geometry_msgs::PoseStamped& result, float maxWaitTransform, bool printErrors)
00279 {
00280 if (p.header.frame_id.empty() || frame_id.empty())
00281 {
00282 if (printErrors) ROS_ERROR("Frame ID's must be both set");
00283 return -1;
00284 }
00285 if (!canGetTransform(p.header.frame_id, frame_id, ros::Time(0), printErrors))
00286 {
00287 if (maxWaitTransform > 0)
00288 {
00289
00290 if (!waitForTransform(p.header.frame_id, frame_id, ros::Time(0), maxWaitTransform, printErrors))
00291 {
00292 if (printErrors) ROS_ERROR("transformPose(): Could not wait for the transform");
00293 return -2;
00294 }
00295
00296 }
00297 else
00298 {
00299 if (printErrors) ROS_ERROR("transformPose(): Could not get the transform.");
00300 return -1;
00301 }
00302 }
00303
00304 geometry_msgs::PoseStamped transTo;
00305 try
00306 {
00307 tf_listener.transformPose(frame_id, p, transTo);
00308 }
00309 catch (tf::TransformException ex)
00310 {
00311 if (printErrors) ROS_ERROR("ROSFunctions::transformPose(): Could not get transform: %s", ex.what());
00312 return -3;
00313 }
00314 result = transTo;
00315 return 0;
00316 }
00317
00318
00319 int ROSFunctions::getTransform(const std::string& f1, const std::string& f2, geometry_msgs::Pose& result,
00320 const ros::Time& useTime, float maxWaitTransform, bool printErrors)
00321 {
00322 if (f1.empty() || f2.empty())
00323 {
00324 if (printErrors) ROS_ERROR("Frame ID's must be both set");
00325 return -1;
00326 }
00327 if (!canGetTransform(f1, f2, useTime, printErrors))
00328 {
00329 if (maxWaitTransform > 0)
00330 {
00331
00332 if (!waitForTransform(f1, f2, useTime, maxWaitTransform, printErrors))
00333 {
00334 if (printErrors) ROS_ERROR("Could not wait for the transform");
00335 return -2;
00336 }
00337
00338 }
00339 else
00340 {
00341 if (printErrors) ROS_ERROR("Could not get the transform to get the relative pose");
00342 return -1;
00343 }
00344 }
00345
00346 tf::StampedTransform transform;
00347
00348 try
00349 {
00350 tf_listener.lookupTransform(f1, f2, useTime, transform);
00351 }
00352 catch (tf::TransformException ex)
00353 {
00354 if (printErrors) ROS_ERROR("Could not get transform: %s", ex.what());
00355 return -3;
00356 }
00357
00358 result.position.x = transform.getOrigin().x();
00359 result.position.y = transform.getOrigin().y();
00360 result.position.z = transform.getOrigin().z();
00361 result.orientation.x = transform.getRotation().x();
00362 result.orientation.y = transform.getRotation().y();
00363 result.orientation.z = transform.getRotation().z();
00364 result.orientation.w = transform.getRotation().w();
00365
00366 return 0;
00367
00368 }
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378 void ROSFunctions::assignJointState(const sensor_msgs::JointState& target_joints, sensor_msgs::JointState& joint_state)
00379 {
00380 for (int i = 0; i < joint_state.name.size(); ++i)
00381 {
00382 int idx = hasVal(joint_state.name[i], target_joints.name);
00383 if (idx < 0) continue;
00384 joint_state.position[i] = target_joints.position[idx];
00385 joint_state.velocity[i] = target_joints.velocity[idx];
00386 joint_state.effort[i] = target_joints.effort[idx];
00387 }
00388
00389 for (int i = 0; i < target_joints.name.size(); ++i)
00390 {
00391 int idx = hasVal(target_joints.name[i], joint_state.name);
00392 if (idx >= 0) continue;
00393
00394 joint_state.name.push_back(target_joints.name[i]);
00395 joint_state.position.push_back(target_joints.position[i]);
00396 joint_state.velocity.push_back(target_joints.velocity[i]);
00397 joint_state.effort.push_back(target_joints.effort[i]);
00398 }
00399
00400 }
00401
00402
00403 bool ROSFunctions::intersectJointState(const sensor_msgs::JointState& s1, const sensor_msgs::JointState& s2, sensor_msgs::JointState& result,
00404 bool init_s1, bool s2_is_subset)
00405 {
00406 result = s1;
00407 for (int i = 0; i < s1.name.size(); ++i)
00408 {
00409 int idx = hasVal(s1.name[i], s2.name);
00410 if (idx < 0)
00411 {
00412 if (s2_is_subset)
00413 {
00414 ROS_ERROR_STREAM("Joint states do not have name " << s1.name[i]);
00415 return false;
00416 }
00417 continue;
00418 }
00419 if (result.name[i] != s2.name[idx])
00420 {
00421 ROS_ERROR("ROSFunctions::copyJointStates consistency error!");
00422 return false;
00423 }
00424
00425 if (init_s1)
00426 {
00427 continue;
00428 }
00429
00430 result.position[i] = s2.position[idx];
00431 result.velocity[i] = s2.velocity[idx];
00432 result.effort[i] = s2.effort[idx];
00433 }
00434 return true;
00435 }
00436
00437 bool ROSFunctions::intersectJointStates(const sensor_msgs::JointState& s1, const sensor_msgs::JointState& s2,
00438 sensor_msgs::JointState& result, bool s2_is_subset)
00439 {
00440 result = s1;
00441 for (int i = 0; i < s1.name.size(); ++i)
00442 {
00443 int idx = hasVal(s1.name[i], s2.name);
00444 if (idx < 0)
00445 {
00446 if (s2_is_subset)
00447 {
00448 ROS_ERROR_STREAM("Joint states do not have name " << s1.name[i]);
00449 return false;
00450 }
00451 continue;
00452 }
00453 if (result.name[i] != s2.name[idx])
00454 {
00455 ROS_ERROR("ROSFunctions::copyJointStates consistency error!");
00456 return false;
00457 }
00458 result.position[i] = s2.position[idx];
00459 result.velocity[i] = s2.velocity[idx];
00460 result.effort[i] = s2.effort[idx];
00461 }
00462 return true;
00463 }
00464
00465
00466 bool ROSFunctions::equalJointPositionsSimple(const sensor_msgs::JointState& j1,
00467 const sensor_msgs::JointState& j2, const float pos_tolerance)
00468 {
00469 for (int i = 0; i < j1.name.size(); ++i)
00470 {
00471 if (i >= j2.name.size()) break;
00472 if (j1.name[i] != j2.name[i]) return false;
00473 if (fabs(j1.position[i] - j2.position[i]) > pos_tolerance) return false;
00474 }
00475 return true;
00476 }
00477
00478 int ROSFunctions::equalJointPositions(const sensor_msgs::JointState& j1,
00479 const sensor_msgs::JointState& j2, const float pos_tolerance)
00480 {
00482
00483 sensor_msgs::JointState intersectJS;
00484
00485 if (!intersectJointState(j1, j2, intersectJS, true, true))
00486 {
00487 return -2;
00488 }
00489
00490
00491
00492
00493
00494
00495
00496 if (intersectJS.position.size() != j2.position.size())
00497 {
00498 return -3;
00499 }
00500 if (!ROSFunctions::equalJointPositionsSimple(intersectJS, j2, pos_tolerance))
00501 {
00502 return -1;
00503 }
00504 return 1;
00505 }
00506
00507 bool ROSFunctions::getJointStateAt(int idx, const trajectory_msgs::JointTrajectory& traj,
00508 sensor_msgs::JointState& result)
00509 {
00510 if (traj.points.size() <= idx) return false;
00511 trajectory_msgs::JointTrajectoryPoint p;
00512 p = traj.points[idx];
00513 result.name = traj.joint_names;
00514 result.position = p.positions;
00515 result.velocity = p.velocities;
00516 result.effort = p.effort;
00517
00518 if (result.position.size() != result.name.size())
00519 {
00520 ROS_ERROR("ROSFunctions: Joint state has to have at least positions!");
00521 return false;
00522 }
00523 if (result.velocity.empty())
00524 {
00525 for (int i = 0; i < result.name.size(); ++i) result.velocity.push_back(0);
00526 }
00527 if (result.effort.empty())
00528 {
00529 for (int i = 0; i < result.name.size(); ++i) result.effort.push_back(0);
00530 }
00531 if (result.velocity.size() != result.name.size())
00532 {
00533 ROS_ERROR("ROSFunctions: Joint state velocities have to be equal size.");
00534 return false;
00535 }
00536 if (result.effort.size() != result.name.size())
00537 {
00538 ROS_ERROR("ROSFunctions: Joint state efforts have to be equal size.");
00539 return false;
00540 }
00541 return true;
00542 }
00543
00544 int ROSFunctions::hasVal(const std::string& val, const std::vector<std::string>& vec)
00545 {
00546 for (int i = 0; i < vec.size(); ++i) if (vec[i] == val) return i;
00547 return -1;
00548 }
00549
00550