Wiki
BehaviorTree.CPP v3.8.7
本文由簡體中文內容確定性轉換,並受版本化術語表保護。
1.BehaviorTree.CPP v3.8.7
對應 BehaviorTree.CPP 3.8 官方文件:About。
行為樹(Behavior Tree,簡稱 BT)是一種組織機器人任務及其切換的方式。 BehaviorTree.CPP 則是用於實現行為樹的 C++ 庫; 本教程的程式使用 3.8.7 驗證,概念資料按官方 3.8 系列文件學習,官方教程入口在這裡。
已經學過 FSM 後,可以從一個問題開始理解它:當導航、充電、任務取消等需求不斷增加時,怎樣把決策邏輯組織得清楚,並複用已有能力?
本篇先說明行為樹解決什麼問題,以及它與 FSM 的關係。節點狀態、tick 傳播和四類節點將在下一篇“基本概念”集中介紹。
2.從一個簡單的 FSM 開始
假設移動機器人只有等待目標、執行導航、到達目標三個階段:
IDLE → 收到目标 → NAVIGATING → 导航成功 → ARRIVED
└────── 导航失败 → IDLE
用 C++ 風格虛擬碼表示:
enum class RobotState
{
IDLE,
NAVIGATING,
ARRIVED
};
RobotState current_state = RobotState::IDLE;
void Update()
{
switch (current_state)
{
case RobotState::IDLE:
if (HasNavigationGoal())
{
StartNavigation();
current_state = RobotState::NAVIGATING;
}
break;
case RobotState::NAVIGATING:
if (NavigationSucceeded())
{
StopRobot();
current_state = RobotState::ARRIVED;
}
else if (NavigationFailed())
{
current_state = RobotState::IDLE;
}
// 尚未结束时保留当前状态,下次 Update() 再检查
break;
case RobotState::ARRIVED:
// 到达后的处理按具体任务补充
break;
}
}
外部週期性呼叫 Update()。啟動導航的介面快速返回,機器人移動期間,每次更新只檢查當前結果,不在函數里一直等待。
這種任務用 FSM 很容易描述:狀態明確,轉換條件也少。
3.複雜任務需要統一組織決策邏輯
任務增加後,同一條規則可能影響多個狀態:
| 新需求 | 可能影響的任務 | 需要決定什麼 |
|---|---|---|
| 電量不足 | 等待、導航、執行任務 | 是否暫停當前任務,前往充電 |
| 緊急停止請求 | 導航、充電、執行任務 | 是否中止當前操作並停止 |
| 定位丟失 | 導航、返回充電點 | 是否暫停移動、嘗試恢復定位 |
| 收到新目標或取消請求 | 導航 | 是否取消舊請求、切換任務 |
| 導航失敗 | 普通任務、返回充電點 | 是否重試、放棄或採用其他處理 |
例如,低電量發生在導航期間,可能需要先取消導航,再前往充電;發生在等待期間,則沒有正在執行的導航需要取消。
如果每個狀態都各自檢查電量、取消請求和定位,規則就容易分散。修改一條策略時,需要檢查多個狀態及其進入、退出邏輯。
FSM 可以通過公共事件處理、分層組織等方式管理這些需求。學習行為樹,是為了掌握另一種組織複雜任務的工具:用有層次的任務結構表達條件、優先順序和執行關係。
3.1.區分底層能力與任務決策
機器人系統可以先按職責分成兩層:
任务决策层
├── 当前应该执行哪个任务?
├── 应该去普通目标还是充电点?
└── 失败或条件变化后怎样处理?
↓ 调用
能力模块
├── Navigation 导航到指定目标
├── Localization 提供定位及其有效性
├── Battery 提供电量和充电信息
├── Sensors 提供环境数据
└── Actuators 执行运动等指令
導航模組主要解決“給定目標,如何到達”;任務決策層決定“現在是否導航、去哪裡、失敗怎麼辦”。行為樹適合組織這部分任務決策,具體功能仍由相應模組實現。
4.用層次結構表達機器人任務
先用一個概念結構表達任務優先順序:
RobotBehavior
├── EmergencyHandling 有紧急停止请求时,停止机器人
├── EnergyManagement 电量低时,处理充电
├── ExecuteMission 有任务时,执行导航等操作
└── WaitForTask 其余情况下,等待任务
這張圖描述的是預期策略,不是可以直接執行的行為樹。實際哪些條件會重新檢查、怎樣選擇分支、如何中止舊任務,需要由具體節點和執行規則實現。
任務可以繼續逐層展開:
RobotBehavior
├── EmergencyHandling
├── EnergyManagement
│ ├── CheckBattery
│ └── RechargeTask
│ ├── NavigateToChargingStation
│ └── StartCharging
└── ExecuteMission
├── CheckGoal
└── NavigateToGoal
閱讀整體任務時,只看第一層就能知道主要職責;
研究充電流程時,再展開 RechargeTask。
小任務可以組成大任務,一整棵子樹也可以成為更大任務的一部分。
這裡仍只展示任務分解,具體節點型別和成功、失敗時的執行規則後面再補充。
5.模組化、複用與組合怎樣落到程式碼上
官方把節點比作積木:每個節點封裝一種檢查或操作,再把節點組合成任務。各個特點可以對應到具體的設計選擇:
| 特點 | 在移動機器人中的做法 |
|---|---|
模組化 Modularity |
電量檢查、導航請求、停止操作分別封裝 |
可複用性 Reusability |
普通目標導航和返回充電點複用同一種導航節點實現,配置不同目標 |
可組合性 Composability |
將檢查、導航、充電組合成完整充電任務 |
關注點分離 Separation of Concerns |
導航模組負責到達目標,行為樹負責決定何時導航和如何處理結果 |
例如 IsBatteryLow 只檢查電量,NavigateToGoal 負責請求導航,StartCharging 負責啟動充電。這樣可以分別測試和替換各項能力,也能在不同任務中重新組合。
可複用的是節點實現或子樹設計,不意味著多處任務必須共享同一個正在執行的節點物件。具體怎樣建立和配置例項,在後面的程式設計示例中學習。
行為樹的樹形圖也有助於閱讀工作流程。 不過,完整理解仍要結合每種節點的執行語義;僅憑連線無法判斷所有執行細節。
6.反應性來自持續驅動與重新判斷
機器人環境會在任務執行期間變化。例如:
开始导航:电量和定位正常,存在目标
↓
导航过程中:收到取消请求
↓
重新判断:取消当前导航,转入后续处理
反應性(Reactive)指系統能夠在任務尚未完成時,根據變化調整行為。
前面學習的非阻塞 FSM,通過週期執行 Update() 檢查事件和任務進度。
行為樹通過外部持續發起 tick,按照樹的規則推進任務:
| 執行方式 | 一次更新主要做什麼 |
|---|---|
FSM 的 Update() |
根據當前狀態處理事件,決定是否轉移 |
| 行為樹的一次 tick | 從根節點進入,按各節點的規則選擇並執行當前需要的節點 |
對於持續任務,每次呼叫應及時交還控制權,方便後續繼續決策。 導航系統可以在兩次更新之間繼續工作,決策層不必堵在一次呼叫中等待機器人到達。
行為樹能否及時響應條件變化,取決於驅動頻率、哪些條件被重新 tick,以及動作是否支援中止。 把條件節點放進樹裡,不代表它會自動持續監控;具體的響應式規則將在後續示例中學習。
7.狀態機FSM與行為樹BT可以配合使用
選擇組織方式時,可以先看問題的結構:
| 場景 | 常見做法 |
|---|---|
| 裝置具有明確階段,如關閉、啟動、執行、故障 | 使用 FSM 表達階段及其轉換 |
| 任務包含多種條件、優先順序和可複用子流程 | 使用行為樹組織任務 |
| 上層需要組合任務,某個底層模組內部又有明確階段 | 上層使用行為樹,模組內部保留 FSM |
例如:
RobotBehavior 行为树:组织整体任务
└── NavigateToGoal 动作节点:调用导航模块
└── NavigationModule 模块内部:用 FSM 管理运行阶段
這張圖表達軟體呼叫與組織關係。NavigationModule 是外部模組,不是動作節點下面的行為樹子節點。
兩種工具都能組織任務決策,適用範圍也有重疊。 現有 FSM 結構清晰時,可以繼續使用;任務需要更多層次和組合時,再考慮引入行為樹。
8.v3.8.7 教程的學習順序
本篇作為導讀,後面按六個完整主題組織主線。階段 1 集中建立概念,階段 2 從最小程式逐步增加功能,統一使用 BehaviorTree.CPP 3.8.7、C++20 和 VSCode CMake Tools。
| 文件 | 主要內容 | 所在階段 |
|---|---|---|
| 基本概念 | 節點、狀態、tick 傳播和四類節點 | 階段 1 |
| 控制與裝飾規則 | 順序、備選方案、重試、重複和超時 | 階段 1 |
| 第一個完整程式 | 先銜接概念,再從最小 demo 逐步增加條件和埠 | 階段 1 收尾,進入階段 2 |
| 節點之間傳資料 | 輸入輸出、自定義型別和外部 Blackboard | 階段 2 |
| 持續任務與中止 | 持續導航、多次 tick、響應式檢查和取消 | 階段 2 |
| 組合實際任務 | 子樹對映、多 XML 檔案和完整任務的成功、失敗路徑 | 階段 2 收尾 |
實踐按自己的完成情況推進:先運行當前版本,看到輸出並理解執行過程,再增加下一步功能。各篇預留了 VSCode 截圖位置,完整程式使用模擬移動機器人資料。
完成主線後,可以繼續 使用Groot1編輯與除錯,學習圖形編輯、即時觀察和日誌回放。這篇屬於工具實踐,繼續使用相同的 BehaviorTree.CPP 3.8.7 工程。
新讀者也可以從 v4.10.0 教程 開始;已經完成本組實踐後,閱讀 v3 與 v4 區別及遷移,再學習 Groot2。