现代行为树大多基于 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%?”。条件节点通常瞬间执行完毕,只返回 SuccessFailure,绝不会返回 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 甚至更高的频率高速循环运行。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐