BehaviorTree.CPP行为树
现代行为树大多基于 BehaviorTree.CPP,这是一个开源的 C++ 行为树框架,并且ROS2的核心导航框架 Nav2 的整个任务规划器就是完全基于 BehaviorTree.CPP 构建的。
其行为树的执行是基于一种称为 Tick 的周期性调用机制。
每一次 Tick,系统会从树的根节点(Root)开始,自顶向下、从左到右地遍历节点。
每个被遍历到的节点在执行其逻辑后,必须向其父节点返回以下三种状态之一:
-
Success(成功):节点完成了它的目标。
-
Failure(失败):节点无法完成目标或条件不满足。
-
Running(运行中):节点的操作需要持续一段时间(例如:机器人正在走向目标点),当前尚未结束。这是行为树能够处理持续性动作的核心。
其节点主要分为三大类:
A. 控制流节点 (Control Flow Nodes)
这些节点作为树的内部节点(非叶子节点),负责控制执行逻辑的流向。它们通常有多个子节点。
-
顺序节点 (Sequence):相当于逻辑“与 (AND)”。
-
行为:依次执行子节点。
-
示例:
打开门= [Sequence: 走到门前 -> 掏出钥匙 -> 插入钥匙孔 -> 扭动开门]。其中任何一步失败,整个动作就失败。
-
-
选择/回退节点 (Selector / Fallback):相当于逻辑“或 (OR)”。
-
行为:依次执行子节点。
-
示例:
进入房间= [Selector: 从正门进 -> 从窗户进 -> 破门而入]。只要有一个方法成功,目的就达到了。
-
-
并行节点 (Parallel):
-
行为:在同一次 Tick 中“同时”执行所有子节点。
-
规则:根据设定的策略返回状态(例如:“当 N 个子节点成功时返回成功”、“当任意子节点失败时返回失败”等)。常用于一边移动一边开枪,或一边移动一边保持避障。
-
B. 执行节点 / 叶子节点 (Execution / Leaf Nodes)
这些节点位于树的末端,没有子节点,负责与外部系统交互。
-
动作节点 (Action):执行具体的操作,如“移动到坐标(X,Y)”、“播放攻击动画”、“发送网络请求”。它可能返回 Success、Failure,最常见的是在执行过程中持续返回 Running。
-
条件节点 (Condition):查询系统状态或环境信息,如“敌人是否在视野内?”、“电量是否大于20%?”。条件节点通常瞬间执行完毕,只返回 Success 或 Failure,绝不会返回 Running。
C. 装饰节点 (Decorator Nodes)
装饰节点只能拥有一个子节点,它的作用是修改或包装其子节点的返回结果和执行方式。
-
常见类型:反转节点 (Invert)(将 Success 变成 Failure,反之亦然)、循环节点 (Repeat/Loop)(让子节点执行 N 次或无限循环)、时间限制节点 (Timeout)(如果子节点 Running 超过设定时间则强制返回 Failure)。
顺序节点又分为普通顺序节点Sequence和反应式顺序节点ReactiveSequence:
普通 Sequence(带记忆): 如果它有 A、B 两个子节点。Tick 执行时,A 成功了,接着执行 B。如果 B 是一个耗时动作,返回了 RUNNING(运行中),那么在下一次 Tick 时,普通的 Sequence 会直接跳过 A,继续从 B 开始执行。它“记住”了 A 已经成功了。
ReactiveSequence(无记忆,实时反应): 同样是 A、B 两个子节点。B 返回了 RUNNING。但在下一次 Tick 时,ReactiveSequence 会强制重新从第一个节点 A 开始检查!
在动态环境中(比如踢足球),情况瞬息万变,需要用到后者。
如果把整个行为树(Behavior Tree)看作是一个大公司,树上的每一个“节点(Node)”就是一个个独立的员工。员工之间是不能直接在工位上大声喊话互相传递数据的(因为 C++ 类的实例之间是隔离的)。
那么,“黑板(Blackboard)”就是公司走廊上的一块公共白板。
在 BehaviorTree.CPP 中,黑板机制是解决节点间数据共享与通信的绝对核心。它的底层本质是一个带有类型擦除的键值对字典。
核心概念:端口 (Ports) 与 黑板 (Blackboard)
在 BT.CPP 中,节点并不是直接去黑板上乱涂乱画的,它们必须通过端口(Ports)来进行合法的读写操作。
-
Input Port (输入端口): 节点向系统声明:“在执行我的逻辑之前,我需要从黑板上读取一个特定类型的数据。”(比如:
WalkToTarget节点需要读取坐标)。 -
Output Port (输出端口): 节点向系统声明:“我执行完毕后,会往黑板上写入一个数据,供后面的节点使用。”(比如:
FindBall节点会写入球的坐标)。 -
InOut Port (双向端口): 既读又写(比如:更新某个计数器)。
黑板(Blackboard)本身不属于任何一个特定节点,它属于整棵行为树(或子树)。

在Groot界面中,带闪电图标说明这个节点是异步动作节点 (Asynchronous Action Node) 或者是有状态动作节点 (Stateful Action Node)。也就是说意味着它执行的是一个“耗时”的操作,并且它是“可被打断的”。
如果是普通同步节点的话, 当行为树 Tick 到它时,它会完全霸占 CPU。如果机器人跑向球需要 3 秒钟,那么在这个 3 秒内,整个行为树都会被卡死。甚至连急停指令都响应不了。
所以需要将其设置为异步节点,当行为树 Tick 到 SimpleChase 时,这个节点会在后台(通过独立线程或协程)启动底层的运动控制代码,然后瞬间向主树返回 RUNNING(运行中)状态,并交出控制权。 这样,行为树的主干依然可以保持 100Hz 甚至更高的频率高速循环运行。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)