Navigation2中引入了行为树来组织机器人的工作流程和动作执行。
行为树本身并不具体实现机器人的执行内容,它只负责将执行内容进行编排。以Navigation2为例,具体的执行内容实现是放在各个server中的。行为树上的节点与server进行通信,请求具体的执行内容,然后获得反馈。根据反馈结果又可以请求另外的执行内容。这些不同执行内容间的跳转就是由行为树控制的。
另一种比较常见的组织机器人行为的方式是状态机。ROS1中的move_base就是基于状态机的。它与行为树最显著的区别是状态与执行内容是绑定在一起的。当执行内容需要在多个状态中执行时,各个状态下都需要放置执行内容的逻辑。当业务逻辑代码分散在各处时就不太好维护了
ROS2行为树动态库默认安装在/opt/ros/galactic/lib/libbehaviortree_cpp_v3.so
,头文件在/opt/ros/foxy/include/behaviortree_cpp_v3
行为树并不执行特定的功能代码,它只是把各个业务逻辑代码组织起来。通过不同的组织方式和少量代码的修改可以实现截然不同的功能
Model
Sequence树节点的特点是它的children必须全部返回SUCCESS才认为执行成功,有一个child返回FAILURE就导致这个树节点执行失败。
- Before ticking the first child, the node status becomes RUNNING.
If a child returns SUCCESS, it ticks the next child.
action
动作节点通常实现服务客户端和动作客户端,也可以是一些简单的执行程序。他们通过向Planner server,Controller server,Recovery server发送请求来启动相应的功能程序。action通常作为行为树中的叶子节点,负责具体行为和功能的实现。但这些具体的功能代码并没有在叶子节点中而是在对应的服务端。
- condition
这是条件控制节点。比如判断电池电量,某一开关信号等等。
- control
这是行为树中的控制流。类似c++语言中的if else,switch等等。它负责构建行为树的逻辑结构。sequeence,fallback等等就属于这个范畴。
- decorator
decorator是节点装饰器。它只能有一个子节点。负责将子节点的结果进行修饰。比如将子节点的结果进行反向,约束子节点的执行次数等等。
ControlNode
至少有1个子节点,DecoratorNode
只有1个子节点,Subtree
没有子节点
黑板
行为树中的共有数据是存放在Blackboard中的。Blackboard是以键值对
的形式存储数据的。各个行为树的叶子节点均可以通过key访问到需要的数据。节点的输入端口可以从黑板读取数据,节点的输出端口可以写入黑板。
Ports是用于在节点间交换数据而存在的。一个行为树叶子节点可以定义输入的Ports和输出的Ports。当不同叶子节点的Port有相同的key名称时,可以认为它们是相通的。当在行为树叶子节点中声明了这些Ports时,也需要同时在xml文件中描述这些Ports。
注意设置子树的__shared_blackboard
属性为true,否则C++程序可能报错
xml 文件
xml格式有以下几个要点
- root这个tag是必须的,而且它需要有
main_tree_to_execute
的属性,表示执行哪颗树 - root的子元素必须有BehaviorTree,BehaviorTree必须有ID属性
- 如果root拥有多个BehaviorTree,那么
BehaviorTree
的ID的属性值必须是不同的,此时必须指定main_tree_to_execute
标签 - 如果root只有一个BehaviorTree,那么
main_tree_to_execute
属性可有可无 - BehaviorTree的子元素就是树节点(tree nodes)
TreeNodesModel
标签,主要用于Groot可视化。对于C++程序来说,可以没有。
createTreeFromFile
的文件路径错误时,会报错 what(): Internal error in realpath(): No such file or directory
调试
Groot1的日志工具很不好用,在fbl
文件比较大的时候,很容易卡死。如果总的行为树很大,需要放大才能观看流程,十分不方便。Groot2的日志工具据说很好用,但是收费。
拆分行为树后,在Groot里不方便直接打开子树,只能再开一个Groot打开子树的xml文件. 后来Groot2解决了这个问题,在设置的Editor标签里还可设置是否每次都加载<include>
标签对应的文件。