行为树(Behavior Tree):从 ROS 机器人到 Unity 游戏 AI 的统一决策范式

作者按:本文是"每日一学"系列之一。今天我们聊一个在机器人和游戏 AI 领域都被广泛使用的决策架构——行为树(Behavior Tree, BT)。我们将以 ROS 机器人编程为主线,再延伸到 Unity 中的实践。


一、为什么需要行为树?

在早期的游戏 AI 和机器人决策系统中,有限状态机(Finite State Machine, FSM) 是最常用的方案。它简单直观:定义若干状态,再定义状态之间的跳转条件。

但 FSM 存在一个致命问题:状态数量增加时,跳转边会以平方级膨胀。当你的机器人需要"巡逻 → 发现目标 → 追踪 → 抓取 → 返航 → 充电"等一系列复杂行为时,FSM 会变成一张难以维护的"意大利面图"。

行为树则用树形结构 + 组合节点优雅地解决了这个问题,具备三大优势:

  • 模块化:每个节点是独立的行为单元,可复用、可组合。
  • 可读性强:树形结构天然适合可视化编辑与调试。
  • 响应式(Reactive):每个 tick 都重新评估,能实时响应环境变化。

二、行为树的核心概念

2.1 节点类型

行为树的节点主要分为四大类:

节点类型 作用 典型代表
控制节点(Control) 控制子节点的执行流程 Sequence、Selector、Parallel
装饰节点(Decorator) 修饰单个子节点的行为 Inverter、Retry、Timeout
条件节点(Condition) 判断某种条件 IsBatteryLow、IsObstacleAhead
动作节点(Action) 执行具体行为 MoveTo、Grasp、Speak

2.2 三种状态返回值

每个节点在被 tick 时会返回以下三种状态之一:

  • SUCCESS:执行成功
  • FAILURE:执行失败
  • RUNNING:仍在执行中

2.3 两个最重要的控制节点

Sequence(顺序节点):相当于逻辑"AND",从左到右依次执行子节点,遇到 FAILURE 立即返回失败,全部成功才返回成功。

Selector / Fallback(选择节点):相当于逻辑"OR",从左到右依次执行子节点,遇到 SUCCESS 立即返回成功,全部失败才返回失败。


三、ROS 中的行为树:BehaviorTree.CPP 与 Nav2

在 ROS 2 生态中,最主流的行为树库是 BehaviorTree.CPP,它也是 Nav2(导航栈) 的核心调度引擎。Nav2 中的路径规划、避障恢复、目标重试等行为,全部由行为树编排。

3.1 一个机器人巡逻的 XML 示例

BehaviorTree.CPP 支持用 XML 描述行为树:

<root main_tree_to_execute="MainTree">
    <BehaviorTree ID="MainTree">
        <Fallback name="root">
            <Sequence name="LowBatteryRecovery">
                <IsBatteryLow/>
                <MoveTo goal="charging_station"/>
                <Charge/>
            </Sequence>
            <Sequence name="Patrol">
                <MoveTo goal="waypoint_A"/>
                <MoveTo goal="waypoint_B"/>
                <MoveTo goal="waypoint_C"/>
            </Sequence>
        </Fallback>
    </BehaviorTree>
</root>

这棵树的逻辑非常清晰:优先检查电量,低电量则回去充电;否则按 A→B→C 巡逻

3.2 自定义动作节点(C++)

#include "behaviortree_cpp/bt_factory.h"

using namespace BT;

class MoveTo : public SyncActionNode {
public:
    MoveTo(const std::string& name, const NodeConfig& config)
        : SyncActionNode(name, config) {}

    static PortsList providedPorts() {
        return { InputPort<std::string>("goal") };
    }

    NodeStatus tick() override {
        std::string goal;
        if (!getInput("goal", goal)) {
            return NodeStatus::FAILURE;
        }
        // 这里调用 ROS 2 的 Action Client,发送导航目标
        ROS_INFO("Moving to: %s", goal.c_str());
        // ... 省略实际导航调用 ...
        return NodeStatus::SUCCESS;
    }
};

int main(int argc, char** argv) {
    BehaviorTreeFactory factory;
    factory.registerNodeType<MoveTo>("MoveTo");

    auto tree = factory.createTreeFromFile("./patrol.xml");
    tree.tickWhileRunning();
    return 0;
}

3.3 Nav2 中的实战应用

Nav2 的默认导航行为树(navigate_to_pose_w_replanning_and_recovery.xml)包含:

  • 主流程:周期性重新规划 → 跟随路径
  • 恢复行为:当导航失败时,依次尝试清除局部代价地图 → 清除全局代价地图 → 原地旋转 → 后退

这种"主行为 + 恢复行为"的模式正是行为树的经典应用:用 Fallback 把"成功路径"和"恢复策略"组合在一起。

3.4 调试利器:Groot2

Groot2 是 BehaviorTree.CPP 配套的可视化编辑器,可以拖拽设计行为树,并在运行时实时高亮当前 tick 的节点,对调试复杂机器人行为极其有用。


四、Unity 中的行为树:游戏 AI 的另一面

行为树在游戏行业的应用其实更早,育碧、Bungie 等大厂在《光环 2》《刺客信条》等作品中都广泛使用。

4.1 Unity 常用方案

  • Behavior Designer(Asset Store 付费):功能最全,支持可视化编辑、变量共享、协程动作。
  • NPBehave(开源):基于代码声明式构建,轻量级。
  • Unity Behavior(官方包,2024 起):Unity 官方推出的 muse 行为图,逐渐成为新标准。

4.2 NPBehave 代码示例

using NPBehave;

public class EnemyAI : MonoBehaviour {
    private Root behaviorTree;

    void Start() {
        behaviorTree = new Root(
            new Selector(
                // 分支1:看到玩家就追击攻击
                new Sequence(
                    new Condition(() => CanSeePlayer()),
                    new Action(() => ChasePlayer()),
                    new Condition(() => InAttackRange()),
                    new Action(() => Attack())
                ),
                // 分支2:默认巡逻
                new Sequence(
                    new Action(() => PatrolNextWaypoint()),
                    new Wait(2.0f)
                )
            )
        );
        behaviorTree.Start();
    }
}

4.3 ROS vs Unity:同一思想的两种语境

维度 ROS 机器人 Unity 游戏
典型动作 导航、抓取、传感器读取 追击、攻击、寻路
Tick 频率 通常 10–50 Hz 与帧率绑定(60+ Hz)
执行模型 异步 Action(长耗时) 协程 / 帧驱动
黑板共享 ROS 参数 / Topic ScriptableObject / 内置 Blackboard
调试工具 Groot2 Behavior Designer Inspector

值得注意的是,Unity Robotics Hub 项目把 ROS 和 Unity 连接起来,可以用 Unity 做机器人仿真,再用 ROS 端的行为树驱动决策——两个世界正在融合。


五、行为树的进阶话题

掌握基础后,可以继续学习以下几个进阶方向:

  1. 黑板(Blackboard):节点之间通过共享的键值存储传递数据,避免硬耦合。
  2. 并行节点(Parallel):同时执行多个子节点,在"边走边说话"这类场景中很有用。
  3. 响应式 vs 一次性:是每个 tick 都重新评估条件,还是仅在状态切换时评估?
  4. 行为树 + 效用函数(Utility AI):用打分机制选择最优分支,比纯优先级更智能。
  5. 行为树 + LLM:2024 年起,已经有研究用大模型动态生成行为树,让机器人具备"听人话办事"的能力。

六、今日小结

行为树本质上是一种用树形结构组织"决策—执行"流程的范式。它在 ROS 机器人(Nav2、BehaviorTree.CPP)和 Unity 游戏 AI 中都是事实标准,因为它同时满足了模块化、可视化、可响应这三大需求。

给你的一个动手作业 🛠️:

用 BehaviorTree.CPP(或 NPBehave)实现一个"扫地机器人"行为树:在电量充足时清扫 → 检测到障碍则绕行 → 电量低于 20% 自动返航充电。先画 XML / 树图,再用代码实现,体验"先设计后编码"的流程。

明天见,继续我们的"每日一学"!🚀

Logo

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

更多推荐