原文地址:http://wiki.ros.org/tf/Tutorials/Adding a frame (C%2B%2B)
在前面的教程中,我们通过添加tf广播器和tf监听器来重新创建turtle demo。本教程将教您如何向tf树中添加额外的坐标系。这与创建tf广播非常相似,并且将展示tf的一些能力。
1 Why adding frames
对于许多任务来说,在本地坐标系内进行思考更容易,例如,在激光扫描器的中心处的坐标系中推断激光扫描更容易。tf允许您为系统中的每个传感器、链接等定义本地坐标系。而且,tf将负责所有引入的额外坐标系的transforms。
2 Where to add frames
tf建立坐标系的树结构;它不允许坐标系结构中的闭环。这意味着一个坐标系只有一个父节点,但是它可以有多个子节点。目前,我们的tf树包含三个坐标系:world、turtle1和turtle2。这两只turtle是world的子坐标系。如果我们想向tf添加新坐标系,三个现有坐标系中的一个需要是父坐标系,并且新坐标系将成为子坐标系。
3 How to add a frame
在我们的turtle 示例中,我们将为turtle1添加一个新坐标系。这个坐标系将是turtle2的“胡萝卜”。
让我们首先创建源文件。转到我们为前面的教程创建的包:
$ roscd learning_tf
3.1 The Code
启动您喜欢的编辑器,并将以下代码粘贴到一个名为src/frame_tf_broadcaster.cpp的新文件中。
1 #include <ros/ros.h>
2 #include <tf/transform_broadcaster.h>
3
4 int main(int argc, char** argv){
5 ros::init(argc, argv, "my_tf_broadcaster");
6 ros::NodeHandle node;
7
8 tf::TransformBroadcaster br;
9 tf::Transform transform;
10
11 ros::Rate rate(10.0);
12 while (node.ok()){
13 transform.setOrigin( tf::Vector3(0.0, 2.0, 0.0) );
14 transform.setRotation( tf::Quaternion(0, 0, 0, 1) );
15 br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "turtle1", "carrot1"));
16 rate.sleep();
17 }
18 return 0;
19 };
代码非常类似于tf broadcaster tutorial 中的示例。
3.2 The Code Explained
让我们看看这段代码中的关键行:
13 transform.setOrigin( tf::Vector3(0.0, 2.0, 0.0) );
14 transform.setRotation( tf::Quaternion(0, 0, 0, 1) );
15 br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "turtle1", "carrot1"));
在这里,我们创建一个新的transform,从父turtle1到新的子carrot1。carrot1坐标系与turtle1坐标系向左偏移2米。
4 Running the frame broadcaster
现在我们已经创建了代码,让我们首先编译它。打开CMakeLists.txt文件,并在底部添加以下行:
add_executable(frame_tf_broadcaster src/frame_tf_broadcaster.cpp)
target_link_libraries(frame_tf_broadcaster ${catkin_LIBRARIES})
在catkin的工作空间的顶部文件夹中编译包:
$ catkin_make
如果一切顺利,则bin文件夹中应该有一个名为frame_tf_broadcaster的二进制文件。如果是这样,我们就可以编辑start_demo.launch启动文件了。只需将下面的node block合并到launch block内::
<launch>
...
<node pkg="learning_tf" type="frame_tf_broadcaster"
name="broadcaster_frame" />
</launch>
首先,确保您停止了前一个教程中的启动文件(使用Ctrl-c)。现在你已经准备好开始播放turtle broadcaster的demo了:
$ roslaunch learning_tf start_demo.launch
5 Checking the results
因此,如果您驱动turtle1四处游荡,您会发现即使我们添加了一个新坐标系,该行为与前一个教程没有改变。这是因为添加额外的坐标系不会影响其他坐标系,并且我们的listener仍然使用之前定义的坐标系。所以,让我们改变listener的行为。
打开 src/turtle_tf_listener.cpp 文件,第26-27行中用“/carrot1”简单替换“/turtle1”:
1 listener.lookupTransform("/turtle2", "/carrot1",
2 ros::Time(0), transform);
现在好的部分是:重新编译并重新启动turtle demo,您将看到turtle2跟随carrot而不是turtle1!记住,carrot离turtle1左边2米。carrot没有视觉上的表示,但是您应该看到turtle2移动到该点。
$ catkin_make
$ roslaunch learning_tf start_demo.launch
6 Broadcasting a moving frame
在本教程中我们发布的额外坐标系是一个固定的坐标系,它不会随着时间而相对于父坐标系发生变化。然而,如果你想发布一个移动坐标系,你可以改变broadcaster让它随时间改变。让我们修改/carrot1坐标系以相对于/turtle1随时间更改。
1 transform.setOrigin( tf::Vector3(2.0*sin(ros::Time::now().toSec()), 2.0*cos(ros::Time::now().toSec()), 0.0) );
2 transform.setRotation( tf::Quaternion(0, 0, 0, 1) );
现在好的部分是:只需重新编译并重新启动turtle demo,您将看到turtle2跟随一个移动的carrot。
$ catkin_make
$ roslaunch learning_tf start_demo.launch
现在,您可以进入下一个关于tf和time的教程了。