ROS机器人的开发过程中,经常需要用到tf坐标变换。简单来讲,tf定义了两个不同坐标系之间的旋转变换关系。
1. 一个简单的demo
$ roslaunch turtle_tf turtle_tf_demo.launch这时候屏幕中会出现两个turtle, 可以通过控制前面的turtle来引导后面的turtle
$ rosrun turtlesim turtle_teleop_key
$ evince frames.pdf
从上面我们可以清楚地看到三个坐标系之间的关系。
我们还可以使用tf_echo来看两个坐标系之间是如何变换的
rosrun tf tf_echo [reference_frame] [target_frame]也可以通过rviz来查看坐标系的变换及移动情况。
$ rosrun rviz rviz -d `rospack find turtle_tf`/rviz/turtle_rviz.rviz
2.写一个简单的tf broadcaster程序
$ catkin_create_pkg learning_tf tf roscpp rospy turtlesim
$ catkin_make $ source ./devel/setup.bash
$ roscd learning_tfsrc/turtle_tf_broadcaster.cpp
https://raw.githubusercontent.com/ros/geometry_tutorials/hydro-devel/turtle_tf/src/turtle_tf_broadcaster.cpp
16 br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "world", turtle_name));
这里的后两个参数即为父坐标系和子坐标系。
修改CMakeLists.txt,在最后加上
add_executable(turtle_tf_broadcaster src/turtle_tf_broadcaster.cpp) target_link_libraries(turtle_tf_broadcaster ${catkin_LIBRARIES})
$ catkin_make添加 start_demo.launch
args="/turtle1" name="turtle1_tf_broadcaster" /> args="/turtle2" name="turtle2_tf_broadcaster" />
$ roslaunch learning_tf start_demo.launch
$ rosrun tf tf_echo /world /turtle1
$ rosrun turtlesim turtle_teleop_key这时候移动turtle可以看到坐标系的变化
3.写一个简单的tf listener
$ roscd learning_tfsrc/turtle_tf_listener.cpp
https://raw.github.com/ros/geometry_tutorials/hydro-devel/turtle_tf/src/turtle_tf_listener.cpp
25 try{ 26 listener.lookupTransform("/turtle2", "/turtle1", 27 ros::Time(0), transform); 28 }这个代码段将坐标系由turtle1变换成turtle2。
35 geometry_msgs::Twist vel_msg; 36 vel_msg.angular.z = 4.0 * atan2(transform.getOrigin().y(), 37 transform.getOrigin().x()); 38 vel_msg.linear.x = 0.5 * sqrt(pow(transform.getOrigin().x(), 2) +根据与turtle1的距离和角度差来计算turtle2的线速度和角速度。
编写CMakeLists.txt
add_executable(turtle_tf_listener src/turtle_tf_listener.cpp) target_link_libraries(turtle_tf_listener ${catkin_LIBRARIES})
$ catkin_make编写launch 文件,在原launch的后面添加
启动name="listener" />
$ roslaunch learning_tf start_demo.launch同样,通过启动键盘控制前面的turtle1可以控制后面的turtle2
在这里需要注意的是,有可能回出现如下错误
[ERROR] [1505742896.803000722]: "turtle2" passed to lookupTransform argument target_frame does not exist.
事实上,这并不是程序的错误,只是因为通信的时延导致turtle2开始的时候无法找到turtle1,因此无法进行计算。