警告
您正在阅读的 ROS 2 文档版本已达到 EOL(生命周期结束),不再受官方支持。如果您想了解最新信息,请访问 Jazzy.
调试
目标 学习如何使用系统方法调试与 tf2 相关的问题。
辅导水平: 中级
时间 10 分钟
背景介绍
本教程将引导您完成调试典型 tf2 问题的步骤。它还将使用许多 tf2 调试工具,如 tf2_echo
, tf2_monitor
和 视图框架
.本教程假定您已经完成了 学习 tf2 教程。
调试示例
1 设置和启动示例
在本教程中,我们将设置一个存在大量问题的演示应用程序。本教程的目的是采用系统化的方法查找并解决这些问题。首先,让我们创建源文件。
前往 learning_tf2_cpp
中创建的软件包 tf2 教程.内部 来源
目录下复制一份源文件 turtle_tf2_listener.cpp
并将其重命名为 turtle_tf2_listener_debug.cpp
.
使用自己喜欢的文本编辑器打开文件,将第 67 行中的
标准::字符串 toFrameRel = "turtle2";;
至
标准::字符串 toFrameRel = "turtle3";;
和变化 lookupTransform()
在第 75-79 行调用
尝试 {
transformStamped = tf_buffer_->;查找变换(
toFrameRel,
fromFrameRel,
tf2::时间点零);
} 捕捉 (tf2::转换异常 及样品; 从) {
至
尝试 {
transformStamped = tf_buffer_->;查找变换(
toFrameRel,
fromFrameRel,
此->;现在());
} 捕捉 (tf2::转换异常 及样品; 从) {
然后保存对文件的更改。为了运行这个演示,我们需要创建一个启动文件 start_tf2_debug_demo.launch.py
在 启动
子目录 learning_tf2_cpp
:
从 启动 舶来品 启动说明
从 launch.actions 舶来品 声明启动参数
从 launch.substitutions 舶来品 启动配置
从 launch_ros.actions 舶来品 节点
捍卫 生成发射描述():
返回 启动说明([
声明启动参数(
'target_frame', 默认值='turtle1';,
描述='目标帧名称;
),
节点(
包装='turtlesim';,
可执行='turtlesim_node',
名字='sim';,
产量='屏幕';
),
节点(
包装='learning_tf2_cpp',
可执行='turtle_tf2_broadcaster';,
名字='broadcaster1',
参数=[
{'turtlename';: 'turtle1';}
]
),
节点(
包装='learning_tf2_cpp',
可执行='turtle_tf2_broadcaster';,
名字='broadcaster2',
参数=[
{'turtlename';: 'turtle2';}
]
),
节点(
包装='learning_tf2_cpp',
可执行='turtle_tf2_listener_debug';,
名字='listener_debug',
参数=[
{'target_frame': 启动配置('target_frame')}
]
),
])
不要忘记添加 turtle_tf2_listener_debug
可执行 CMakeLists.txt
并构建软件包。
现在让我们运行它,看看会发生什么:
ros2 launch learning_tf2_cpp start_tf2_debug_demo.launch.py
现在你会看到海龟模拟器出现了。同时,如果运行 乌龟遥控钥匙
在另一个终端窗口中,可以使用箭头键来驱动 乌龟1
左右。
ros2 run turtlesim turtle_teleop_key
你还会注意到在左下角有第二只乌龟。如果演示程序运行正常,这第二只乌龟就应该跟在你用方向键指挥的乌龟后面。但事实并非如此,因为我们必须先解决一些问题。你应该注意到以下信息:
[turtle_tf2_listener_debug-4] [INFO] [1630223454.942322623] [listener_debug]:无法
将 turtle3 转换为 turtle1:"turtle3" 传递给 lookupTransform 参数 target_frame
不存在
2 查找 tf2 请求
首先,我们需要弄清楚要求 tf2 做什么。因此,我们要进入使用 tf2 的代码部分。打开 src/turtle_tf2_listener_debug.cpp
文件,并查看第 67 行:
标准::字符串 至框架关系 = "turtle3";;
和第 75-79 行:
尝试 {
transformStamped = tf_buffer_->;查找变换(
toFrameRel,
fromFrameRel,
此->;现在());
} 捕捉 (tf2::转换异常 及样品; 从) {
在这里,我们向 tf2 提出实际请求。三个参数直接告诉了我们向 tf2 提出的请求:从帧变换 乌龟3
框 乌龟1
当时 现在
.
现在,让我们来看看为什么向 tf2 提出的请求会失败。
3 检查框架
首先,要弄清楚 tf2 是否知道我们在 乌龟3
和 乌龟1
我们将使用 tf2_echo
工具
ros2 run tf2_ros tf2_echo turtle3 turtle1
输出结果显示,帧 乌龟3
不存在:
[INFO] [1630223557.477636052] [tf2_echo]:Waiting for transform turtle3 -> turtle1:
传给 canTransform 参数 target_frame 的帧 ID "turtle3"无效。
乌有
那么存在哪些框架呢?如果您想用图形表示,请使用 视图框架
工具
ros2 run tf2_tools view_frames.py
打开生成的 框架.pdf
文件,可以看到以下输出:

很明显,问题在于我们要求从帧 乌龟3
不存在。要修复这个错误,只需替换 乌龟3
与 乌龟2
在第 67 行。
现在停止正在运行的演示,构建它,然后再次运行它:
ros2 launch turtle_tf2 start_debug_demo.launch.py
我们马上就会遇到下一个问题:
[turtle_tf2_listener_debug-4] [INFO] [1630223704.617382464] [listener_debug]:无法
将海龟 2 转换为海龟 1:查找需要推断未来。要求
时间为 1630223704.617054,但最新数据的时间为 1630223704.616726,当查找时
从 [乌龟 1] 帧转换到 [乌龟 2] 帧
4 检查时间戳
现在我们解决了帧名问题,是时候查看时间戳了。请记住,我们正在尝试获取 乌龟2
和 乌龟1
在当前时间(即 现在
).要获取计时统计数据,请调用 tf2_monitor
与相应的帧。
ros2 运行 tf2_ros tf2_monitor turtle2 turtle1
结果应该是这样的
结果:从乌龟 2 到乌龟 1
链为: turtle1
净延迟平均值 = 0.00287347:最大值 = 0.0167241
框架
帧: turtle1, 由 <无授权发布>, 平均延迟:0.000295833, Max Delay:0.000755072
所有广播公司:
节点:<无可用授权> 125.246 Hz,平均延迟:0.000290237 Max Delay:0.000786781
这里的关键部分是链的延迟,从 乌龟2
至 乌龟1
.输出结果显示平均延迟约为 3 毫秒。这意味着只有在 3 毫秒后,tf2 才能在海龟之间进行转换。因此,如果我们要求 tf2 在 3 毫秒前而不是 现在
,tf2 有时就能给出答案。让我们快速测试一下,将第 75-79 行改为
尝试 {
transformStamped = tf_buffer_->;查找变换(
toFrameRel,
fromFrameRel,
此->;现在() - rclcpp::持续时间::从秒(0.1));
} 捕捉 (tf2::转换异常 及样品; 从) {
在新代码中,我们需要 100 毫秒前海龟之间的变换。通常情况下,我们会使用更长的时间段,以确保变换能够到达。停止演示,构建并运行:
ros2 launch turtle_tf2 start_debug_demo.launch.py
你应该终于看到乌龟动了!

我们最后做的修复并不是你真正想要做的,只是为了确保这是我们的问题所在。真正的解决方案是这样的
尝试 {
transformStamped = tf_buffer_->;查找变换(
toFrameRel,
fromFrameRel,
tf2::时间点零);
} 捕捉 (tf2::转换异常 及样品; 从) {
或者像这样
尝试 {
transformStamped = tf_buffer_->;查找变换(
toFrameRel,
fromFrameRel,
tf2::时间点());
} 捕捉 (tf2::转换异常 及样品; 从) {
您可以在 利用时间 教程,使用方法如下:
尝试 {
transformStamped = tf_buffer_->;查找变换(
toFrameRel,
fromFrameRel,
此->;现在(),
rclcpp::持续时间::从秒(0.05));
} 捕捉 (tf2::转换异常 及样品; 从) {
摘要
在本教程中,您将学习如何使用系统方法调试与 tf2 相关的问题。您还学会了如何使用 tf2 调试工具,如 tf2_echo
, tf2_monitor
和 视图框架
来帮你调试这些 TF2 问题。