在之前的教程中,我们重建了turtle demo,通过添加tf广播器和tf侦听器。
本教程将教您如何向tf树添加额外的坐标系。
这与创建广播者非常相似,并将展示tf的一些强大功能。
1 为什么要添加坐标系
对于许多任务,在局部坐标系更容易找到问题。
例如,更容易分析激光扫描仪中心坐标系中的激光扫描仪。
tf允许您为系统中的每个传感器,链接等定义本地坐标系。
tf能够注意到所有引入的额外坐标变换。
2 在哪里添加坐标系
tf建立了一个树状结构的坐标系 ; 但它不允许坐标系结构中出现闭环。
这意味着一个坐标系只有一个父坐标系,以及可以有多个子坐标系。
目前我们的tf树包含三个框架:world,turtle1和turtle2。这两只乌龟是世界坐标系的子坐标系。
如果我们想要将新坐标系添加到tf,则三个现有坐标系中的一个需要是父坐标系,并且新坐标系将成为子坐标系。
3 如何添加坐标系
在我们的乌龟demo中,我们将向第一只乌龟添加一个新坐标系。这个坐标系将成为第二只乌龟的“carrot”。
我们先创建源文件。转到我们为之前的教程创建的包:
$ roscd learning_tf
3.1 程序
启动您喜欢的编辑器并将以下代码粘贴到名为src / frame_tf_broadcaster.cpp的新文件中。
#include <ros/ros.h>
#include <tf/transform_broadcaster.h>
int main(int argc, char** argv){
ros::init(argc, argv, "my_tf_broadcaster");
ros::NodeHandle node;
tf::TransformBroadcaster br;
tf::Transform transform;
ros::Rate rate(10.0);
while (node.ok()){
transform.setOrigin( tf::Vector3(0.0, 2.0, 0.0) );
transform.setRotation( tf::Quaternion(0, 0, 0, 1) );
br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "turtle1", "carrot1"));
rate.sleep();
}
return 0;
};
该代码与tf广播者教程中的示例非常相似。
3.2 程序解释
我们来看看这段代码中的关键字:
transform.setOrigin( tf::Vector3(0.0, 2.0, 0.0) );
transform.setRotation( tf::Quaternion(0, 0, 0, 1) );
br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "turtle1", "carrot1"));
在这里,我们创建一个新的转换,从父turtle1到新的孩子carrot1。
所述carrot1坐标系相比较左侧turtle1坐标系有2米的偏移。
4 运行坐标系广播者
现在我们创建了代码,让我们先编译它。打开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启动文件了。只需在启动块内合并下面的节点块::
<launch>
...
<node pkg="learning_tf" type="frame_tf_broadcaster"
name="broadcaster_frame" />
</launch>
首先,确保从上一个教程中停止了启动文件(使用Ctrl-c)。现在您已准备好开始海龟广播着Demo:
$ roslaunch learning_tf start_demo.launch
5 检查结果
因此,如果您驾驶第一只乌龟,即使我们添加了一个新坐标系,您会注意到这个乌龟的行为与前一个教程相比没有变化。
这是因为添加额外的坐标系不会影响其他坐标系,我们的Listener仍在使用先前定义的坐标系。
所以,让我们改变监听器的行为。
打开SRC / turtle_tf_listener.cpp文件,简单更换“/ turtle1”与“/ carrot1”在26-27行:
listener.lookupTransform("/turtle2", "/carrot1",
ros::Time(0), transform);
现在好的部分:只需重建并重新启动乌龟演示,你就会看到第二只乌龟跟着carrot而不是第一只乌龟!
请记住,carrot位于turtle1左侧2米处。carrot没有可视化表示,但你应该看到第二只乌龟移动到那一点。
$ catkin_make
$ roslaunch learning_tf start_demo.launch
6 广播移动的帧
我们在本教程中发布的额外坐标系是一个固定坐标系,相对于父坐标系不会随时间变化。
但是,如果要发布移动坐标系,可以更改广播者以随时间更改。
让我们修改/ carrot1坐标系以随着时间的推移相对于/ turtle1进行更改。
transform.setOrigin( tf::Vector3(2.0*sin(ros::Time::now().toSec()), 2.0*cos(ros::Time::now().toSec()), 0.0) );
transform.setRotation( tf::Quaternion(0, 0, 0, 1) );
现在是好的部分:只需重建并重新启动乌龟演示,你就会看到第二只乌龟跟着一只移动的carrot。
$ catkin_make
$ roslaunch learning_tf start_demo.launch