1 tf和时间
在之前的教程中,我们了解了tf如何跟踪坐标系树。
此树随时间变化,并且tf为每个变换存储时间快照(默认情况下最多10秒)。
到目前为止,我们使用lookupTransform()函数来访问该tf树中的最新可用变换,而不知道该变换的记录时间。
本教程将教您如何在特定时间进行转换。
那么让我们回到最后添加框架教程的地方。
转到您的教程包:
$ roscd learning_tf
并打开文件src / turtle_tf_listener.cpp。看看第25-27行:
try{
listener.lookupTransform("/turtle2", "/carrot1",
ros::Time(0), transform);
让我们让第二只龟跟着第一只乌龟,而不是carrot。将您的代码更改为以下内容:
try{
listener.lookupTransform("/turtle2", "/turtle1",
ros::Time(0), transform);
您还可以看到我们指定的时间等于0.
对于tf,时间0表示缓冲区中的“最新可用”变换。现在,更改此行以获取当前时间的变换“ now() ”:
try{
listener.lookupTransform("/turtle2", "/turtle1",
ros::Time::now(), transform);
首先,确保您停止了上一个教程中的启动文件(使用ctrl-c)。编译代码,然后再次运行:
$ catkin_make
$ roslaunch learning_tf start_demo.launch
所以,所有突然的lookupTransform()都失败了,反复告诉你:
[ERROR] [1287871653.885277559]: You requested a transform that is 0.018 miliseconds in the past, but the most recent transform in the tf buffer is 7.681 miliseconds old.
When trying to transform between /turtle1 and /turtle2.
....
这是为什么?好吧,每个监听器都有一个缓冲区,用于存储来自不同广播者的所有坐标转换。
当广播公司发出变换时,变换进入缓冲区需要一些时间(通常是几毫秒)。
因此,当您在“now”时请求帧变换时,您应该等待几毫秒才能到达该信息。
2 等待变换
tf提供了一个很好的工具,它将等待转换变为可用。让我们看一下代码的样子:
try{
ros::Time now = ros::Time::now();
listener.waitForTransform("/turtle2", "/turtle1",
now, ros::Duration(3.0));
listener.lookupTransform("/turtle2", "/turtle1",
now, transform);
该waitForTransform()有四个参数:
- 等待此坐标系的转换......
- ......目的坐标系,
- 时间
- 超时:不要等待超过此最大持续时间
注意:使用ros :: Time :: now()就是这个例子。通常这将是希望转换的数据的时间戳。
所以waitForTransform()实际上会阻塞,直到两只乌龟之间的转换变得可用(这通常需要几毫秒),或者 - 如果转换不可用 - 直到达到超时。
首先,确保您停止了上一个教程中的启动文件(使用ctrl-c)。现在编译代码,然后再次运行:
$ catkin_make
$ roslaunch learning_tf start_demo.launch
但是等等,你可能仍然会看到错误一次(错误信息可能会有所不同):
[ERROR] [1287872014.408401177]: You requested a transform that is 3.009 seconds in the past, but the tf buffer only has a history of 2.688 seconds.
When trying to transform between /turtle1 and /turtle2.
发生这种情况是因为turtle2需要非零时间来生成并开始发布tf坐标系。
所以你第一次要求现在/ turtle2坐标系可能不存在,当请求变换时,变换可能还不存在并且第一次失败。
在第一次转换之后,所有转换都存在,并且乌龟的行为与预期的一样。
3 检查结果
现在再一次你应该能够使用箭头键简单地驾驶第一只乌龟(确保你的终端窗口是活动的,而不是你的模拟器窗口),你会看到第一只乌龟跟随第二只乌龟!
注意到龟的行为没有明显的区别。那是因为实际的时间差仅为几毫秒。但是为什么我们从Time(0) to now()进行此更改?
只是为了教你关于tf缓冲区和与之相关的时间延迟。
对于真实的用例,使用Time(0)通常是完全正常的。