ROS tf监听编写
博客转载自:https://www.ncnynl.com/archives/201702/1311.html
ROS与C++入门教程-tf-编写tf listener(监听)
说明:
- 介绍如何使用tf访问坐标系转换
创建tf的监听
- 新建文件turtle_tf_listener.cpp 参考源码:
$ roscd learning_tf $ touch src/turtle_tf_listener.cpp $ vim src/turtle_tf_listener.cpp
- 代码如下:
#include <ros/ros.h>
#include <tf/transform_listener.h>
#include <geometry_msgs/Twist.h>
#include <turtlesim/Spawn.h>
int main(int argc, char** argv){
  ros::init(argc, argv, "my_tf_listener");
  ros::NodeHandle node;
  ros::service::waitForService("spawn");
  ros::ServiceClient add_turtle =
    node.serviceClient<turtlesim::Spawn>("spawn");
  turtlesim::Spawn srv;
  add_turtle.call(srv);
  ros::Publisher turtle_vel =
    node.advertise<geometry_msgs::Twist>("turtle2/cmd_vel", 10);
  tf::TransformListener listener;
  ros::Rate rate(10.0);
  while (node.ok()){
    tf::StampedTransform transform;
    try{
      listener.lookupTransform("/turtle2", "/turtle1",
                               ros::Time(0), transform);
    }
    catch (tf::TransformException &ex) {
      ROS_ERROR("%s",ex.what());
      ros::Duration(1.0).sleep();
      continue;
    }
    geometry_msgs::Twist vel_msg;
    vel_msg.angular.z = 4.0 * atan2(transform.getOrigin().y(),
                                    transform.getOrigin().x());
    vel_msg.linear.x = 0.5 * sqrt(pow(transform.getOrigin().x(), 2) +
                                  pow(transform.getOrigin().y(), 2));
    turtle_vel.publish(vel_msg);
    rate.sleep();
  }
  return 0;
};
- 如果在运行时遇到错误"Lookup would require extrapolation into the past",您可以尝试此替代代码来调用侦听器:
try {
    listener.waitForTransform(destination_frame, original_frame, ros::Time(0), ros::Duration(10.0) );
    listener.lookupTransform(destination_frame, original_frame, ros::Time(0), transform);
} catch (tf::TransformException ex) {
    ROS_ERROR("%s",ex.what());
}
代码解释:
- 代码: #include <tf/transform_listener.h>
- 作用:
- tf包提供了TransformListener的实现,以帮助使接收变换的任务更容易。
- 要使用TransformListener,我们需要包括tf/transform_listener.h头文件。
 
- 
代码:tf::TransformListener listener; 
- 
作用: - 这里,我们创建一个TransformListener对象。
- 一旦监听器被创建,它开始接收tf转换,并缓冲它们长达10秒。
- TransformListener对象应该被限定为持久化,否则它的缓存将无法填充,并且几乎每个查询都将失败。
- 一个常见的方法是使TransformListener对象成为一个类的成员变量。
 
- 
代码: 
try{
    listener.lookupTransform("/turtle2", "/turtle1",
                               ros::Time(0), transform);
}
- 
作用:这里,真正的工作完成了,我们查询监听器进行特定的转换。 
- 
让我们来看看四个参数: 
- 
1.我们想从/turtle2坐标系开始 
- 
2.变换到/turtle1坐标系 
- 
3.变换的时间,提供ros::Time(0)即会给出最近的可用的变换。 
- 
4.结果存放的变换对象。 
- 
这个代码放在try-catch结构,可以获取抛出的异常 
- 
代码: 
geometry_msgs::Twist vel_msg;
vel_msg.angular.z = 4.0 * atan2(transform.getOrigin().y(),
                                    transform.getOrigin().x());
vel_msg.linear.x = 0.5 * sqrt(pow(transform.getOrigin().x(), 2) +
- 作用:
- 这里,变换用于计算龟的新的线性和角速度,基于它与龟的距离和角度。
- 新的速度发布在话题"turtle2/cmd_vel"中,turtlesim将使用它来更新turtle2的运动。
 
运行监听
- 打开CMakeLists.txt文件,并在底部添加以下行:
add_executable(turtle_tf_listener src/turtle_tf_listener.cpp)
target_link_libraries(turtle_tf_listener ${catkin_LIBRARIES})
- 编译:
$ cd ~/catkin_ws $ catkin_make
- 如果一切顺利,你应该在devel/lib/learning_tf文件夹中有一个名为turtle_tf_listener的二进制文件。
- 之前已经创建start_demo.launch,在 块,合并代码:
 <launch>
    ...
    <node pkg="learning_tf" type="turtle_tf_listener"
          name="listener" />
  </launch>
- 启动:
$ roslaunch learning_tf start_demo.launch
- 你应该看到turtlesim有两只海龟。
检查结果:
- 要查看是否有效,只需使用箭头键(确保您的终端窗口处于活动状态,而不是模拟器窗口)绕过第一只乌龟,您会在第一只乌龟之后看到第二只乌龟!
- 当turtlesim启动时,你可能会看到:
[ERROR] 1253915565.300572000: Frame id /turtle2 does not exist! When trying to transform between /turtle1 and /turtle2. [ERROR] 1253915565.401172000: Frame id /turtle2 does not exist! When trying to transform between /turtle1 and /turtle2.
- 这是因为我们的监听器试图在接收关于龟2的消息之前计算变换,因为它需要一点时间在turtlesim中生成并开始广播一个tf坐标系。
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号