利用时间 (C++)

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

教程级别: 中级

时间: 10 分钟

背景

在之前的教程中,我们通过编写 tf2 广播器tf2 监听器 重新创建了 turtle 演示。 我们还学习了如何 向转换树添加新框架,并学习了 tf2 如何跟踪坐标系树。 这棵树会随着时间而变化,并且 tf2 会为每个转换存储一个时间快照(默认情况下最多 10 秒)。 到目前为止,我们使用 lookupTransform() 函数来访问该 tf2 树中最新的可用转换,而不知道该转换是在什么时候记录的。 本教程将教您如何在特定时间获取转换。

任务

1 更新侦听器节点

让我们回到 添加框架教程 中结束的地方。

转到 learning_tf2_cpp 包。

打开 turtle_tf2_listener.cpp 并查看 lookupTransform() 调用:

try {
    t = tf_buffer_->lookupTransform(
       toFrameRel,
       fromFrameRel,
       tf2::TimePointZero);
} catch (const tf2::TransformException & ex) {

您可以看到,我们通过调用“tf2::TimePointZero”指定了等于 0 的时间。

Note

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();
try {
    t = tf_buffer_->lookupTransform(
        toFrameRel, fromFrameRel,
        now);
} catch (const tf2::TransformException & ex) {

现在构建包并尝试运行启动文件。

ros2 launch learning_tf2_cpp turtle_tf2_demo_launch.py

您会注意到它失败了并输出类似这样的内容:

[INFO] [1629873136.345688064] [listener]: Could not transform turtle2 to turtle1: 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();
try {
    t = tf_buffer_->lookupTransform(
        toFrameRel,
        fromFrameRel,
        now,
        50ms);
} catch (const tf2::TransformException & ex) {

lookupTransform() 可以接受四个参数,其中最后一个是可选的超时。

它将阻塞最多该时间,直到超时。

3 检查结果

您现在可以构建包并运行启动文件。

ros2 launch learning_tf2_cpp turtle_tf2_demo_launch.py

您应该注意到 lookupTransform() 实际上会阻塞,直到两个海龟之间的变换可用(这通常需要几毫秒)。 一旦达到超时(在这种情况下为 50 毫秒),只有当变换仍然不可用时才会引发异常。

摘要

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