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 彻底退出该过程。

解释结果

一旦获得“callgrind”结果,无论您是通过节点、启动文件、Nav2 还是其他地方执行此操作,现在我们都可以分析探查器的结果,以识别瓶颈或潜在的改进领域。使用“kcachegrind”:

kcachegrind callgrind.out.XXX

这应该会打开一个如下所示的窗口。左侧显示所有调用及其及其子函数所使用的计算时间的相对百分比。

如果您选择左侧边栏的顶级条目,然后选择右侧工作区底部的“调用图”,它应该以方法调用图的形式显示计算时间花费的调用图。这对于查找花费最多时间的方法非常有帮助。