ROS 2 / Nav2 中的分析
概述
本文档介绍了在 ROS 2 / Nav2 中分析应用程序的一种方法。分析的目的是生成可分析的文件,以了解程序执行期间计算时间和资源的消耗情况。这对于确定程序中存在瓶颈以及可以改进的地方非常有用。
以下步骤向 ROS 2 用户展示了如何修改 Nav2 堆栈,以便在遇到想要更好地了解的情况时获取有关特定服务器/算法的分析信息。本教程适用于模拟机器人和物理机器人。
预赛
本教程使用两个工具,“Valgrind”工具集中的 callgrind 和“kcachegrind”。 Valgrind 用于获取有关程序的分析信息,kcachegrind 是用于解释此信息以完成有用工作的可视化引擎。
因此,我们必须安装它们。
sudo apt install valgrind kcachegrind
更多信息可以在“Valgrind 手册 <https://valgrind.org/docs/manual/cl-manual.html>”中找到,包括可用于指定更多信息的其他 valgrind 参数。
一般来说,要使用valgrind,我们需要使用调试信息进行编译。这可以通过传递“-g”作为编译选项或将“CMAKE_BUILD_TYPE”编译为“Debug”或“RelWithDebInfo”来完成。然后,我们使用 valgrind 运行程序来捕获运行时统计信息以供以后分析。这些存储在``callgrind.out.XXX``文件中,其中后缀是进程的PID。 kcachegrind 用于可视化和分析程序执行的结果。
# CMakeLists.txt
add_compile_options(-g)
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo
valgrind --tool=callgrind [your-program] [program options]
kcachegrind callgrind.out.XXX
来自节点的配置文件
正如在我们的通用示例中一样,对于给定的节点,我们需要使用调试标志进行编译,以捕获用于使用 Valgrind 进行分析的信息。这可以通过命令行轻松完成。请注意,我们使用“–packages-select”仅使用此标志来编译我们想要分析其中节点的包。
colcon build --packages-select <packages of interest> --cmake-args -DCMAKE_BUILD_TYPE=RelWithDebInfo
或者,您可以将以下行添加到您要分析的包的“CMakeLists.txt”中。当您的工作区包含许多包但只想使用单个“colcon build”调用来编译带有调试信息的子集时,这可能更可取。
如果您想要插件运行时配置文件的结果,则应将其添加到主机服务器和插件包中,这一点很重要。
add_compile_options(-pg)
无论采用哪种编译方法,该节点都应在其自己的终端中运行,以将其与系统的其余部分隔离,因此,不应将其与其他节点放在同一进程中。要使用 valgrind 运行 ROS 2 节点,可以通过以下方式从命令行完成:
ros2 run --prefix 'valgrind --tool=callgrind' <pkg> <node> --all-other-launch arguments
此类示例可用于分析加载了特定控制器插件的控制器服务器。 nav2_controller
和感兴趣的插件包都是用调试标志编译的。在下面的示例中,我们正在运行一个 ROS 2 节点,其中包含重新映射的主题及其参数文件的路径:
ros2 run --prefix 'valgrind --tool=callgrind' nav2_controller controller_server --ros-args -r __node:=controller_server -r cmd_vel:=cmd_vel_nav --params-file /path/to/nav2_bringup/params/nav2_params.yaml
收集到足够的数据后,使用 Control+C 彻底退出该过程。
来自启动文件的配置文件
正如在 Node 示例中一样,在从启动时分析节点时,我们还必须使用调试标志进行编译。我们可以使用启动前缀在启动文件中完成与命令行相同的 valgrind 调用。
正如我们之前的示例,这就是我们从启动文件中启动“controller_server”节点的方式。
start_controller_server_node = Node(
parameters=[
get_package_share_directory("nav2_bringup") + '/params/nav2_params.yaml',
{'use_sim_time': use_sim_time}
],
package='nav2_controller',
executable='controller_server',
name='controller_server',
prefix=['xterm -e valgrind --tool=callgrind'],
output='screen')
请注意,就像以前一样,我们应该将此进程与其他进程隔离。因此,不应与此启动文件中的任何其他节点一起运行,也不应在分析特定节点时使用节点组合。
收集到足够的数据后,使用 Control+C 彻底退出该过程。
来自 Nav2 启动
由于 Nav2 Bringup 每个启动文件有多个节点(在“use_composition=true”的情况下,每个进程有多个节点),因此有必要将您感兴趣的特定节点与其余节点分开如前所述,一旦将它们隔离在启动文件中或作为要在命令行上启动的节点,就可以轻松运行它们来收集 callgrind 信息。
Nav2 中的步骤如下:
从“navigation_launch.py”中删除服务器节点,确保从文件中的组合和非组合选项中删除
在单独的启动文件中或使用“ros2 run”CLI,按照上述说明启动您想要分析的节点
像往常一样启动缺少节点的 Nav2
收集数据后,按 Control+C 并干净地完成分析过程和其余导航
重要的是,Profiler 节点在 Nav2 之前启动,以便它可以从生命周期管理器获取信号进行转换。
解释结果
一旦获得“callgrind”结果,无论您是通过节点、启动文件、Nav2 还是其他地方执行此操作,现在我们都可以分析探查器的结果,以识别瓶颈或潜在的改进领域。使用“kcachegrind”:
kcachegrind callgrind.out.XXX
这应该会打开一个如下所示的窗口。左侧显示所有调用及其及其子函数所使用的计算时间的相对百分比。
如果您选择左侧边栏的顶级条目,然后选择右侧工作区底部的“调用图”,它应该以方法调用图的形式显示计算时间花费的调用图。这对于查找花费最多时间的方法非常有帮助。