状态机与行为树

(4 mins to read)

状态机

  • 状态、事件、转换、行为
  • 扩展状态(允许额外的变量)、层级状态、守卫条件
  • 事件触发、周期条件触发

状态机可以将问题分解为若干个状态,只需要考虑处于某个状态时的事件、转换以及行为即可,更容易思考。

行为树

Behavior Trees (BTs)

行为树是一棵包含控制节点(非叶节点)和行为节点(叶子节点)的树(类似决策树,通过控制节点选择执行哪个叶子节点)。

每一次更新称为一次tick,从根节点开始传播。收到tick的节点会运行并返回成功、失败、运行中的状态信息给父节点。

  • 执行节点包括动作节点(可以执行复杂的动作)和条件节点(仅仅只是检查条件然后返回成功或失败的状态)。执行节点是连接行为树和具体应用代码的地方。
  • 控制节点,定义了自顶向下遍历的方式,通过接受子节点的状态信息,并应用自己的规则来决定接下去的遍历方式,具体包括顺序(按序执行各个子节点,直到全部成功或一个失败)、备选(按序执行各个子节点,直到一个成功或全部失败)、并行(同时执行各个子节点,直到M个成功或全部失败)、装饰节点(修改唯一的子节点的行为,如反转状态)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
static const char* xml_text = R"(

<root BTCPP_format="4" >

<BehaviorTree ID="MainTree">
<Sequence name="root_sequence">
<CheckBattery name="battery_ok"/>
<OpenGripper name="open_gripper"/>
<ApproachObject name="approach_object"/>
<CloseGripper name="close_gripper"/>
</Sequence>
</BehaviorTree>

</root>
)";

BehaviorTreeFactory factory;
factory.registerNodeType<ApproachObject>("ApproachObject");
factory.registerSimpleCondition("CheckBattery",
[&](TreeNode&) { return CheckBattery(); });
GripperInterface gripper;
factory.registerSimpleAction("OpenGripper", [&](TreeNode&) { return gripper.open(); });
factory.registerSimpleAction("CloseGripper",
[&](TreeNode&) { return gripper.close(); });
auto tree = factory.createTreeFromText(xml_text);
// To "execute" a Tree you need to "tick" it.
// The tick is propagated to the children based on the logic of the tree.
// In this case, the entire sequence is executed, because all the children
// of the Sequence return SUCCESS.
tree.tickWhileRunning();

对比

行为树和状态机的表达能力是相同的,但行为树更便于组合修改,偏向模块化;而状态机更便于反应式设计(if event then action),偏向反应式。

bt-fsm