使用时间(C++)

目标: 学习如何使用 lookupTransform() 函数在特定时间获取变换,并等待 tf2 树上的变换可用。

教程级别: 中级

时间: 10分钟

背景

在之前的教程中,我们通过编写 tf2 广播器tf2 监听器 来重新创建了乌龟演示。我们还学习了如何 向变换树中添加新帧,以及如何使用 tf2 来跟踪坐标帧的树结构。这个树随着时间的推移而改变,tf2 为每个变换存储了一个时间快照(默认为最近的 10 秒)。到目前为止,我们使用 lookupTransform() 函数来获取在 tf2 树中最新可用的变换,而不知道该变换是在何时记录的。本教程将教你如何在特定时间获取变换。

任务

1 tf2 和时间

让我们回到上一个教程 添加一个帧 结束的地方。打开 learning_tf2_cpp 包中的 turtle_tf2_listener.cpp,并查看 lookupTransform() 的调用:

transformStamped = tf_buffer_->lookupTransform(
   toFrameRel,
   fromFrameRel,
   tf2::TimePointZero);

你可以看到我们通过调用 tf2::TimePointZero 指定了时间为 0。

注解

tf2 包有自己的时间类型 tf2::TimePoint,与 rclcpp::Time 不同。在 tf2_ros 包中,许多 API 自动在 rclcpp::Timetf2::TimePoint 之间进行转换。

rclcpp::Time(0, 0, this->get_clock()->get_clock_type()) 可以在此处使用,但它最终会被转换为 tf2::TimePointZero

对于 tf2,时间 0 表示缓冲区中的“最新可用”变换。现在,将此行更改为获取当前时间的变换,即 this->get_clock()->now():

rclcpp::Time now = this->get_clock()->now();
transformStamped = tf_buffer_->lookupTransform(
   toFrameRel,
   fromFrameRel,
   now);

现在尝试运行启动文件。

ros2 launch learning_tf2_cpp turtle_tf2_demo.launch.py

您会注意到它失败并输出类似于以下内容:

[INFO] [1629873136.345688064] [listener]: Could not transform turtle1 to turtle2: Lookup would
require extrapolation into the future.  Requested time 1629873136.345539 but the latest data
is at time 1629873136.338804, when looking up transform from frame [turtle1] to frame [turtle2]

它告诉您该帧不存在或数据位于未来。

要理解为什么会发生这种情况,我们需要了解缓冲区的工作原理。首先,每个监听器都有一个缓冲区,用于存储来自不同tf2广播器的所有坐标转换。其次,当广播器发送一个转换时,需要一些时间才能将该转换放入缓冲区(通常需要几毫秒)。因此,当您在“现在”时间请求帧转换时,您应该等待几毫秒,以便该信息到达。

2 等待转换

tf2提供了一个很好的工具,可以等待直到转换可用。您可以通过向“lookupTransform()”添加一个超时参数来使用该工具。要修复这个问题,请按照下面的代码进行编辑(添加最后一个超时参数):

rclcpp::Time now = this->get_clock()->now();
transformStamped = tf_buffer_->lookupTransform(
   toFrameRel,
   fromFrameRel,
   now,
   50ms);

``lookupTransform()``可以接受四个参数,其中最后一个是可选的超时参数。它会阻塞最多该持续时间,直到超时。

3 检查结果

现在您可以运行启动文件。

ros2 launch learning_tf2_cpp turtle_tf2_demo.launch.py

请注意,lookupTransform() 函数将阻塞直到两个乌龟之间的变换可用(通常需要几毫秒)。一旦超时时间到达(此例中为50毫秒),仅当变换仍不可用时才会引发异常。

总结

在本教程中,您学会了如何在特定时间戳获取变换,并在使用``lookupTransform()``函数时等待变换在tf2树上可用。