ROS 2中的实时编程 [待校准@7931]

背景

实时计算是许多机器人系统的关键特征,尤其是安全和关键任务应用,如自动驾驶汽车、宇宙飞船和工业制造。我们在设计和制作ROS 2时考虑到了实时性能限制,因为这是在ROS 1的早期阶段没有考虑的要求,现在很难将ROS 1重构为实时友好。 [待校准@7932]

[需手动修复的语法] This document 概述了软件工程师对实时计算的要求和最佳实践。简而言之: [待校准@7933]

为了制作实时计算机系统,我们的实时循环必须更新周期调用y以满足截止日期。我们只能容忍这些截止日期上的微小误差 (我们允许的最大抖动)。为此,我们必须避免执行路径中的非确定性操作,例如: 页面错误事件、动态内存分配/解除分配以及无限期阻塞的同步原语。 [待校准@7934]

通常通过实时计算解决的控制问题的一个典型例子是平衡 inverted pendulum 。如果控制器意外地阻塞了很长时间,钟摆会掉落或变得不稳定。但是如果控制器可靠地以比控制钟摆的电机运行速度更快的速度更新,钟摆将成功地适应传感器数据以平衡钟摆。 [待校准@7935]

既然你已经了解了实时计算的一切,让我们试试例程吧! [待校准@7936]

安装并运行例程 [待校准@7937]

实时例程的编写考虑到了Linux操作系统,因为许多进行实时计算的ROS社区成员使用Xenomai或RT_PREEMPT作为他们的实时解决方案。由于例程中执行的许多操作都是为了优化性能或特定于操作系统,因此例程仅在Linux系统上构建和运行。So因此,如果您是OSX或Windows用户,请不要尝试此部分!** [待校准@7938]

此外,这必须使用静态DDS API从源文件构建。目前唯一支持的实现是Connext。 [待校准@7939]

首先,按照说明使用Connext DDS作为中间件来构建ROS 2 from source[待校准@7940]

运行测试 [待校准@7941]

run在运行之前,请确保您至少有8Gb的可用内存。由于内存锁定,交换将不再起作用。** [待校准@7942]

获取您的ROS 2设置.bash。 [待校准@7943]

运行二进制例程,并重定向输出。如果出现权限错误,您可能需要使用 sudo : [待校准@7944]

pendulum_demo > output.txt

刚才到底发生了什么? [待校准@7945]

首先,即使您重定向了stdout,您也会看到一些输出到控制台 (从stderr): [待校准@7946]

mlockall failed: Cannot allocate memory
Couldn't lock all cached virtual memory.
Pagefaults from reading pages not yet mapped into RAM will be recorded.

在例程prog内存的初始化阶段之后,它将尝试将所有缓存的内存锁定到内存中,并防止将来使用 mlockall 进行动态内存分配。这是为了防止页面错误将大量新内存加载到内存中。(更多信息见 the realtime design article 。) [待校准@7947]

发生这种情况时,例程将照常继续。在例程生成的output.txt文件的底部,您将看到执行过程中遇到的页面错误数量: [待校准@7948]

rttest statistics:
  - Minor pagefaults: 20
  - Major pagefaults: 0

如果我们想让那些页面错误消失,我们必须... [待校准@7949]

调整内存锁定权限 [待校准@7950]

添加到 /etc/security/limits.conf (作为sudo): [待校准@7951]

<your username>    -   memlock   <limit in kB>

[需手动修复的语法] -1 的限制是无限的。如果你选择这个,你可能需要在编辑文件后与 ulimit -l unlimited 一起。 [待校准@7952]

保存文件后,注销并重新登录。然后重新运行 pendulum_demo 调用。 [待校准@7953]

您将在输出文件中看到零页面错误,或者看到一个错误,说明捕获了bad_alloc异常。如果发生这种情况,您没有足够的可用内存将分配给进程的内存锁定到内存中。您需要在计算机中安装更多内存才能看到零页面错误! [待校准@7954]

输出概述 [待校准@7955]

要查看更多输出,我们必须运行 pendulum_logger 节点。 [待校准@7956]

在带有 install/setup.bash 源文件d的一个外壳中,调用: [待校准@7957]

pendulum_logger

您应该会看到输出消息: [待校准@7958]

Logger node initialized.

在另一个带有setup.bash源文件d的外壳中,再次调用 pendulum_demo[待校准@7959]

此可执行文件启动后,您应该会看到另一个shell不断打印输出: [待校准@7960]

Commanded motor angle: 1.570796
Actual motor angle: 1.570796
Mean latency: 210144.000000 ns
Min latency: 4805 ns
Max latency: 578137 ns
Minor pagefaults during execution: 0
Major pagefaults during execution: 0

该例程控制着一个非常简单的倒立摆仿真。摆锤仿真计算其在自己螺纹中的位置。ROS节点模拟钟摆的电机编码器传感器并发布其位置。另一个ROS节点充当简单的PID控制器,并计算下一个命令消息。 [待校准@7961]

日志记录器节点周期调用y打印出钟摆的状态和例程在其执行阶段的运行时性能统计信息。 [待校准@7962]

[需手动修复的语法] pendulum_demo 完成后,您必须按CTRL-C退出日志记录器节点才能退出。 [待校准@7963]

延迟 [待校准@7964]

在执行 pendulum_demo 时,您将看到为例程收集的最终统计信息: [待校准@7965]

rttest statistics:
  - Minor pagefaults: 0
  - Major pagefaults: 0
  Latency (time after deadline was missed):
    - Min: 3354 ns
    - Max: 2752187 ns
    - Mean: 19871.8 ns
    - Standard deviation: 1.35819e+08

PendulumMotor received 985 messages
PendulumController received 987 messages

延迟字段以纳秒为单位显示更新循环的最小、最大和平均延迟。这里,延迟是指预期发生更新后的时间量。 [待校准@7966]

实时系统的要求取决于应用程序,但是假设在这个例程中我们有一个1kHz (1毫秒) 的更新环路,我们的目标是更新周期的最大允许延迟为5%。 [待校准@7967]

因此,我们的平均延迟在这次运行中确实很好,但是最大延迟是不可接受的,因为它实际上超过了我们的更新循环!发生什么事了? [待校准@7968]

我们可能正遭受一个不确定的调度器。如果你're running a vanilla Linux system and you don't有RT_PREEMPT内核安装,你可能无法满足实时目标我们自己,因为Linux调度程序不允许您在用户级别任意抢占线程。 [待校准@7969]

有关更多信息,请参见 realtime design article[待校准@7970]

例程尝试将例程的调度程序和线程优先级设置为适合实时性能。如果此操作失败,您将看到一条错误消息: “无法设置调度优先级和策略: 不允许操作”。按照下一节中的说明,您可以获得更好的性能: [待校准@7971]

设置调度程序的权限 [待校准@7972]

添加到 /etc/security/limits.conf (作为sudo): [待校准@7951]

<your username>    -   rtprio   98

rtprio (实时优先级) 字段的范围是0-99。但是,不要将限制设置为99,因为这样您的进程可能会干扰以最高优先级运行的重要系统进程 (例如,看门狗)。此例程将尝试以优先级98运行控制循环。 [待校准@7973]

绘制结果 [待校准@7974]

您可以绘制例程运行后在此例程中收集的延迟和页面错误统计信息。 [待校准@7975]

因为代码是用 rttest 检测的,所以有有用的命令行参数可用: [待校准@7976]

命令 [待校准@7977]

描述 [待校准@7978]

默认值 [待校准@7979]

-我 [待校准@7980]

指定运行实时循环的迭代次数 [待校准@7981]

1000 [待校准@7982]

-u [待校准@7983]

指定更新周期,默认单位为微秒。 [待校准@7984]

使用后缀 "s" 几秒钟, "ms" 几毫秒, [待校准@7985]

[需手动修复的语法] "us" 微秒, "ns" 纳秒。 [待校准@7986]

1毫秒 [待校准@7987]

-f [待校准@7988]

指定用于写入收集的数据的文件的名称。 [待校准@7989]

使用文件名再次运行该例程以保存结果: [待校准@7990]

pendulum_demo -f pendulum_demo_results

然后对生成的文件运行 rttest_plot 脚本: [待校准@7991]

rttest_plot pendulum_demo_results

此脚本将生成三个文件: [待校准@7992]

pendulum_demo_results_plot_latency.svg
pendulum_demo_results_plot_majflts.svg
pendulum_demo_results_plot_minflts.svg

您可以在您选择的图像查看器中查看这些绘图。 [待校准@7993]