第三章 使用ROS任务执行
正如我们在卷一讲述的,机器人的程序相对简单来运行一个特定的行为,例如人脸跟踪、位置导航、或跟随一个人。但是一个期望的完全自主机器人从一个巨大的行为列表中选择一个自己的行为取决于手头的任务和当前的条件。
在本章节中,我们将学习如何使用两个不同启用ROS任务执行框架:SMACH(使用状态机和宣言“smash”)和pi_trees(行为树)。每一种方法都有其有点和缺点,并且一个是否容易取决于你的编程背景。但相比于写一个巨大的if-then语句列表来说,这两种方式都提供了一个更结构化的方法进行任务管理。
整个任务控制器通常被称为任务执行,并且大多数这样期望的控制器至少包括以下主要特点:
- l 任务优先级:如果一个更高的优先级任务要求同样的资源(例如驱动电机),一个低的优先级任务应该等待。
- l 暂停和恢复:当一个高优先级的给定任务是控制,那么通常需要暂停当前运行的任务(或多个任务),然后当进程返回控制时,应当恢复被抢占(preempted)的任务。例如Neato吸尘器在充电完成后,能够返回离开的位置。
- l 任务层次结构:任务通常可以分解成子任务来处理细节。例如,一个称为再充电的高级任务可能包含三个子任务:导航到充电桩、对接机器人和插上电池充电。同样的,对接任务可以分解成:匹配信标、驱动前进、对接停止。
- l 条件:传感器数据和内部编程变量可以限制何时以及如何执行一个任务、在ROS中,这些变量通常通过各个节点以消息的形式发布。例如,电池监控任务订阅一个诊断话题,该话题包含当前电池状态。当检测到电池电量过低时,一个检查电池条件应该被触发并暂停或终止其他任务,执行再充电任务。
- l 并发性:多个任务可以并行。例如,导航任务(到下一个地点)和电池监控任务必须同时运行。
为了保持这个整体,我们使用两个贯穿章节的示例场景:一个“巡逻机器人”必须按顺序访问一系列位置,同时保持电池检测。和一个“家庭清洁机器人”必须访问一组房间,并且在每一个房间执行各种清洁相关的任务。
3.1 虚拟电池仿真
一个永远运行的机器需要监控它自己的电池状态,并且必要时再充电。为了使我们的示例更真实,因此,我们将使用一个节点来模拟一个电池,通过在一个电池状态ROS话题上发布一个实时减少的值。其他节点可以订阅这个话题并且当电池电量过低时可以做出反应。
电池模拟节点battery_simulator.py可以在rbx2_utils/nodes目录下找到。这个脚本相当简单除了部分设计到的动态重新配置,关于细节我们将在第7章详细介绍。现在,我们只需要注意以下:
这个节点需要三个参数:
- l rate:(默认1Hz)——多久发布电池状态
- l battery_runtime:(默认60秒)——电池需要多少秒减少到0
- l initial_batery_level:(默认100)——当开始运行节点时,初始化电池容量。
节点使用initial_batery_level这个浮点型开始在/battery_level话题发布,随后通过给定battery_runtime参数在一定时间内计数到0。正如我们在