ROSFunctions.cpp
Go to the documentation of this file.
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(); //_singleton = ROSFunctionsPtr(new ROSFunctions()); //first access to helpers, so create it
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         //if (printError) ROS_ERROR("Can't transform, as a frame does not exist (yet): %i, %i",tf_listener.frameExists(f1),tf_listener.frameExists(f2));
00086         return false;
00087     }
00088 
00089     std::string error_msg;
00090     if (!tf_listener.canTransform(f1, f2, useTime, &error_msg))
00091     {
00092         //if (printError) ROS_ERROR("Can't transform between frames %s and %s: %s",f1.c_str(),f2.c_str(),error_msg.c_str());
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; //std::min(p1.stamp.toSec(),p2.stamp.toSec());
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     //ROS_INFO_STREAM("Waiting for transform using time "<<useTime);
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     //if the frames don't exist yet, the wait will just return true, in which case we have to double-wait here.
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; //std::min(p1.stamp.toSec(),p2.stamp.toSec());
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     //ROS_INFO_STREAM("Relative pose: "<<rel);
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     //double angleDist = convenience_math_functions::MathFunctions::quatAngularDistance(p1.pose.orientation, p2.pose.orientation);
00183 
00184     //ROS_INFO("Rotation is %f %f %f %f",transform.getRotation().x(),transform.getRotation().y(),transform.getRotation().z(),transform.getRotation().w());
00185     //ROS_INFO("ROSFunctions::equalPoses Distances: %f / %f",dist.norm(),angleDist);
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     //ROS_INFO_STREAM("Relative pose: "<<rel);
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     //ROS_INFO("Rotation is %f %f %f %f",transform.getRotation().x(),transform.getRotation().y(),transform.getRotation().z(),transform.getRotation().w());
00209     //ROS_INFO("ROSFunctions::equalPoses Distances: %f / %f",dist.norm(),angleDist);
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; //std::min(origin.header.stamp.toSec(),other.header.stamp.toSec());
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             //ROS_INFO("ROSFunctions::relativePose: Waiting for tf transform");
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             //ROS_INFO("Transform arrived.");
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)    //tf::LookupException, tf::ConnectivityException, tf::MaxDepthException, tf::ExtrapolationException  tf::InvalidArgument
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             //ROS_INFO("ROSFunctions::relativePose: Waiting for tf transform");
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             //ROS_INFO("Transform arrived.");
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)    //tf::LookupException, tf::ConnectivityException, tf::MaxDepthException, tf::ExtrapolationException  tf::InvalidArgument
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             //ROS_INFO("ROSFunctions::getTransform: Waiting for tf transform");
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             //ROS_INFO("Transform arrived.");
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)    //tf::LookupException, tf::ConnectivityException, tf::MaxDepthException, tf::ExtrapolationException  tf::InvalidArgument
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 /*tf::Quaternion getTFRotationFromTo(const tf::Quaternion& q1, const tf::Quaternion& q2) {
00372     tf::Quaternion ret= q2*q1.inverse();
00373     ret.normalize();
00374     return ret;
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)   //no need to continue because result already has values of 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     // ROS_INFO_STREAM("Input1: "<<std::endl<<j1<<" Input2: "<<std::endl<<j2<<" intersection "<<std::endl<<intersectJS);
00491 
00492     // intersectJS is not initialized with values in j1.
00493     // because j2 was required to be subset of j1 in intersectJointState(),
00494     // now intersectJS and j2 have to be of same size, and have same order of
00495     // joints as j1.
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     //result.acceleration=lastPoint.accelerations;
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 


convenience_ros_functions
Author(s): Jennifer Buehler
autogenerated on Sat Mar 2 2019 03:21:42