BT的经典阐述
从核心来讲,BT是由一小部分简单的组件构成的。
从形式上来讲,BT是一个有向的根树,其内部节点称之为控制流节点,叶节点称之为执行节点。对于每个连接的节点,通常使用术语父节点和子节点进行描述。根就是没有父节点的节点,所有其他的节点都有一个父节点。控制流节点至少有一个子节点。
BT从生成给定频率的时钟信号的根节点开始执行。这些信号允许执行一个 节点,并传递给选中的一个或者多个子节点。当且仅当接受到信号才会执行该节点。如果子节点正在执行中,则立即将“执行”返回到父节点,如果子节点已经实现目标,则立刻返回成功,否则返回失败。
在经典的阐述中,存在四类控制流节点(序列,回退,并行和装饰器)和两类执行节点(动作和条件),其中回退也称选着节点。
节点类型 | 标志 | 成功 | 失败 | 运行中 |
回退(select) | ? | 若有一个子节点 | 所有子节点失败 | 一个子节点返回执行 |
序列(sequence) | 所有子节点返回成功 | 一个子节点返回失败 | 一个子节点返回执行 | |
并行(parallel) | 朝左的双箭头 | 大于等于M个子节点成功 | 大于(N-M)个字节点失败 | 其余情况 |
动作(action) | 文本 | 完成 | 若不可能完成 | 完成期间 |
条件(condition) | 文本 | 若真 | 若假 | 没有 never |
装饰器 | 菱形 | 自定义 | 自定义 | 自定义 |
序列节点
序列节点执行算法,该算法对应将时钟信号从左至右依次发送到子节点,直到找到返回“失败”和“执行”的子节点,然后将“失败”或“执行”相应的返回其父节点。当且仅当所有子节点返回“成功”时,该节点返回“成功”。需要注意的是,当有一个子节点返回“执行”或“失败”时,顺序节点不会将时钟信号路由到下一个子节点(如果存在下一个子节点)。
//具有N个子节点的序列节点伪代码
Function Tick()
for i <- 1 to N do
childStatus <- child(i).Tick()
if childStatus = Running then
return Running
else if childStatus = Failure then
return Failure
return Success
回退节点
回退节点执行算法,该算法对应于将时钟信号从左至右开始发送到其子节点,直到找到返回“成功”或“执行”的子节点,然后将“成功”或“执行”相应的返回到其的父节点。当且仅当所有节点都返回“失败”的时候才返回“失败”。需要注意的是 当有一个子节点返回“执行”或“成功”时,回退节点将不会把时钟信号路由到下一个子节点,但当子节点左侧的子节点返回“执行”或成功时会中断该子节点。
//具有N个子节点的回退节点伪代码
Function Tick()
for i <- 1 to N do
childStatus <- child(i).Tick()
if childStatus = Running then
return Running
else if childStatus = Success then
return Success
return Failure
并行节点
并行节点的执行算法,该算法对应于将时钟信号发送到所有的子节点,如果M个子节点返回“成功”,则返回“成功”。如果N-M+1个子节点返回“失败”,则返回“失败”,否者返回“执行”。这里的N是子节点的数量,M<=N是用户定义的 阈值,并行节点的符号是一个包含标签两个单向箭头的框
//具有N个子节点和成功阈值M的并行节点的伪代码
Function Tick()
for i <- 1 to N do
childStatus <- child(i).Tick()
if 子节点返回成功的个数求和 = N then
return Success
else if 子节点返回失败的求和 > 0 then
return Failure
else
return Running
动作节点
当动作节点接收到时钟信息时,将执行命令。如果动作成功完成,则返回“成功”;如果动作失败,则返回“失败”。当动作失败,则返回“失败”。当动作正在运行时,它返回“执行”。动作节点的算法如下
//动作节点的伪代码
Function Tick()
ExecuteCommand()
if action-succeeded then
return Success
else if action-failed then
return Failure
else
return Running
需要注意的是,在行为树执行的过程中,动作执行的频率可能比执行BT本身的频率更高。例如一个力控机械手臂打开抽屉可能需要100~1000Hz的频率,而BT在抽屉打开后决定要做什么可能需要10Hz。这是通过让动作运行,直到他们成功或者失败,或者由于没有接受到更多时钟信号而显式地接收到中止命令,而不是像上诉动作算法一样等待下一个时钟。因此,机器人BT库使用一个实现特定例程来安全的中止动作,而计算机游戏和模拟器通常不存在这个问题,并且在每一次时钟下执行一个命令。
条件节点
当条件节点接收到时钟信号是。它会检查一个命题,它返回“成功”或“失败”,这取决于命题是否成立。需要注意的是,条件节点永远不会返回“执行”状态。
//条件节点的伪代码
Function Tick()
if condition-true then
return Success
else
return Failure
装饰器节点
装饰器节点是带有一个子节点的控制流节点,该节点根据用户数据定义的规则操纵其子节点的返回状态,并根据预定义的规则有选择性地触发子节点。例如反转装饰器用于反转子节点返回的“成功”或“失败”状态。一个最多尝试N次的装饰器只允许其子节点失败N次,并总是返回“失败”而并不执行子节点:一个最大执行事件为T秒的装饰器节点让其子节点执行T秒,如果子节点还在执行,则装饰器将返回“失败”而不在触发子节点。 装饰器的符号是菱形。
初识行为树到此结束