Skip to content

Robot Behavior Tree Demo

This is a demo of a behavior tree for a robot. It has no practical use for Vultron, rather it's an introduction to how to use the behavior tree framework we've built.

We're providing this as an example to show how to build a behavior tree that can be used to implement some context-aware behavior.

Behaviors

The robot has a number of behaviors:

  • If the ball is in the bin, it will stop.
  • If the ball is in the robot's grasp and it is near the bin, it will put it in the bin.
  • If the ball is in the robot's grasp and it is not near the bin, it will move toward the bin.
  • If the ball is nearby, it will try to pick it up (and sometimes fail)
  • If the ball is not nearby, it will move toward the ball.
  • If the ball is not found, it will search for it.
  • If it fails to complete its task, it will ask for help.

The Behavior Tree

The tree structure is shown below.

graph LR
  Robot_1["? Robot"]
  BallPlaced_2(["#11052; BallPlaced"])
  Robot_1 --> BallPlaced_2
  MainSequence_3["→ MainSequence"]
  Robot_1 --> MainSequence_3
  EnsureBallFound_4["? EnsureBallFound"]
  MainSequence_3 --> EnsureBallFound_4
  BallFound_5(["#11052; BallFound"])
  EnsureBallFound_4 --> BallFound_5
  FindBall_6["→ FindBall"]
  EnsureBallFound_4 --> FindBall_6
  UsuallySucceed_7["#127922; UsuallySucceed"]
  FindBall_6 --> UsuallySucceed_7
  SetBallFound_8["#9648; SetBallFound"]
  FindBall_6 --> SetBallFound_8
  EnsureBallClose_9["? EnsureBallClose"]
  MainSequence_3 --> EnsureBallClose_9
  BallClose_10(["#11052; BallClose"])
  EnsureBallClose_9 --> BallClose_10
  ApproachBall_11["→ ApproachBall"]
  EnsureBallClose_9 --> ApproachBall_11
  UsuallySucceed_12["#127922; UsuallySucceed"]
  ApproachBall_11 --> UsuallySucceed_12
  SetBallClose_13["#9648; SetBallClose"]
  ApproachBall_11 --> SetBallClose_13
  EnsureBallGrasped_14["? EnsureBallGrasped"]
  MainSequence_3 --> EnsureBallGrasped_14
  BallGrasped_15(["#11052; BallGrasped"])
  EnsureBallGrasped_14 --> BallGrasped_15
  GraspBall_16["→ GraspBall"]
  EnsureBallGrasped_14 --> GraspBall_16
  OftenFail_17["#127922; OftenFail"]
  GraspBall_16 --> OftenFail_17
  SetBallGrasped_18["#9648; SetBallGrasped"]
  GraspBall_16 --> SetBallGrasped_18
  EnsureBinClose_19["? EnsureBinClose"]
  MainSequence_3 --> EnsureBinClose_19
  BinClose_20(["#11052; BinClose"])
  EnsureBinClose_19 --> BinClose_20
  ApproachBin_21["→ ApproachBin"]
  EnsureBinClose_19 --> ApproachBin_21
  UsuallySucceed_22["#127922; UsuallySucceed"]
  ApproachBin_21 --> UsuallySucceed_22
  SetBinClose_23["#9648; SetBinClose"]
  ApproachBin_21 --> SetBinClose_23
  EnsureBallPlaced_24["? EnsureBallPlaced"]
  MainSequence_3 --> EnsureBallPlaced_24
  BallPlaced_25(["#11052; BallPlaced"])
  EnsureBallPlaced_24 --> BallPlaced_25
  PlaceBall_26["→ PlaceBall"]
  EnsureBallPlaced_24 --> PlaceBall_26
  UsuallySucceed_27["#127922; UsuallySucceed"]
  PlaceBall_26 --> UsuallySucceed_27
  SetBallPlaced_28["#9648; SetBallPlaced"]
  PlaceBall_26 --> SetBallPlaced_28
  MaybeAskForHelp_29["→ MaybeAskForHelp"]
  Robot_1 --> MaybeAskForHelp_29
  TimeToAskForHelp_30(["#11052; TimeToAskForHelp"])
  MaybeAskForHelp_29 --> TimeToAskForHelp_30
  AskForHelp_31["#9648; AskForHelp"]
  MaybeAskForHelp_29 --> AskForHelp_31

Legend:

Symbol Meaning
? FallbackNode
SequenceNode
Invert
ActionNode
ConditionNode
🎲 Fuzzer node (randomly succeeds or fails some percentage of the time)

Demo Output

Example

 # if vultron package is installed
# run the demo
$ vultrabot --robot

# print the tree and exit
$ vultrabot --robot --print-tree

# if vultron package is not installed
python -m vultron.bt.base.demo.robot

When the tree is run, it will look something like this:

(?) ?_Robot_1
 | (c) c_BallPlaced_2
 |  | = FAILURE
 | (>) >_MainSequence_3
 |  | (?) ?_EnsureBallFound_4
 |  |  | (c) c_BallFound_5
 |  |  |  | = FAILURE
 |  |  | (>) >_FindBall_6
 |  |  |  | (z) z_UsuallySucceed_7
 |  |  |  |  | = SUCCESS
 |  |  |  | (a) a_SetBallFound_8
 |  |  |  |  | = SUCCESS
 |  |  |  | = SUCCESS
 |  |  | = SUCCESS
 |  | (?) ?_EnsureBallClose_9
 |  |  | (c) c_BallClose_10
 |  |  |  | = FAILURE
 |  |  | (>) >_ApproachBall_11
 |  |  |  | (z) z_UsuallySucceed_12
 |  |  |  |  | = SUCCESS
 |  |  |  | (a) a_SetBallClose_13
 |  |  |  |  | = SUCCESS
 |  |  |  | = SUCCESS
 |  |  | = SUCCESS
 |  | (?) ?_EnsureBallGrasped_14
 |  |  | (c) c_BallGrasped_15
 |  |  |  | = FAILURE
 |  |  | (>) >_GraspBall_16
 |  |  |  | (z) z_OftenFail_17
 |  |  |  |  | = SUCCESS
 |  |  |  | (a) a_SetBallGrasped_18
 |  |  |  |  | = SUCCESS
 |  |  |  | = SUCCESS
 |  |  | = SUCCESS
 |  | (?) ?_EnsureBinClose_19
 |  |  | (c) c_BinClose_20
 |  |  |  | = FAILURE
 |  |  | (>) >_ApproachBin_21
 |  |  |  | (z) z_UsuallySucceed_22
 |  |  |  |  | = SUCCESS
 |  |  |  | (a) a_SetBinClose_23
 |  |  |  |  | = SUCCESS
 |  |  |  | = SUCCESS
 |  |  | = SUCCESS
 |  | (?) ?_EnsureBallPlaced_24
 |  |  | (c) c_BallPlaced_25
 |  |  |  | = FAILURE
 |  |  | (>) >_PlaceBall_26
 |  |  |  | (z) z_UsuallySucceed_27
 |  |  |  |  | = FAILURE
 |  |  |  | = FAILURE
 |  |  | = FAILURE
 |  | = FAILURE
 | (>) >_MaybeAskForHelp_29
 |  | (c) c_TimeToAskForHelp_30
 |  |  | = FAILURE
 |  | = FAILURE
 | = FAILURE
The ball was knocked out of the robot's grasp!
(?) ?_Robot_1
 | (c) c_BallPlaced_2
 |  | = FAILURE
 | (>) >_MainSequence_3
 |  | (?) ?_EnsureBallFound_4
 |  |  | (c) c_BallFound_5
 |  |  |  | = SUCCESS
 |  |  | = SUCCESS
 |  | (?) ?_EnsureBallClose_9
 |  |  | (c) c_BallClose_10
 |  |  |  | = SUCCESS
 |  |  | = SUCCESS
 |  | (?) ?_EnsureBallGrasped_14
 |  |  | (c) c_BallGrasped_15
 |  |  |  | = FAILURE
 |  |  | (>) >_GraspBall_16
 |  |  |  | (z) z_OftenFail_17
 |  |  |  |  | = SUCCESS
 |  |  |  | (a) a_SetBallGrasped_18
 |  |  |  |  | = SUCCESS
 |  |  |  | = SUCCESS
 |  |  | = SUCCESS
 |  | (?) ?_EnsureBinClose_19
 |  |  | (c) c_BinClose_20
 |  |  |  | = SUCCESS
 |  |  | = SUCCESS
 |  | (?) ?_EnsureBallPlaced_24
 |  |  | (c) c_BallPlaced_25
 |  |  |  | = FAILURE
 |  |  | (>) >_PlaceBall_26
 |  |  |  | (z) z_UsuallySucceed_27
 |  |  |  |  | = FAILURE
 |  |  |  | = FAILURE
 |  |  | = FAILURE
 |  | = FAILURE
 | (>) >_MaybeAskForHelp_29
 |  | (c) c_TimeToAskForHelp_30
 |  |  | = FAILURE
 |  | = FAILURE
 | = FAILURE
(?) ?_Robot_1
 | (c) c_BallPlaced_2
 |  | = FAILURE
 | (>) >_MainSequence_3
 |  | (?) ?_EnsureBallFound_4
 |  |  | (c) c_BallFound_5
 |  |  |  | = SUCCESS
 |  |  | = SUCCESS
 |  | (?) ?_EnsureBallClose_9
 |  |  | (c) c_BallClose_10
 |  |  |  | = SUCCESS
 |  |  | = SUCCESS
 |  | (?) ?_EnsureBallGrasped_14
 |  |  | (c) c_BallGrasped_15
 |  |  |  | = SUCCESS
 |  |  | = SUCCESS
 |  | (?) ?_EnsureBinClose_19
 |  |  | (c) c_BinClose_20
 |  |  |  | = SUCCESS
 |  |  | = SUCCESS
 |  | (?) ?_EnsureBallPlaced_24
 |  |  | (c) c_BallPlaced_25
 |  |  |  | = FAILURE
 |  |  | (>) >_PlaceBall_26
 |  |  |  | (z) z_UsuallySucceed_27
 |  |  |  |  | = SUCCESS
 |  |  |  | (a) a_SetBallPlaced_28
 |  |  |  |  | = SUCCESS
 |  |  |  | = SUCCESS
 |  |  | = SUCCESS
 |  | = SUCCESS
 | = SUCCESS
Robot completed its mission in 3 ticks.

Demo Code

vultron.bt.base.demo.robot

This module demonstrates a simple robot behavior tree. The robot has a number of tasks it must perform in order to complete its mission. The robot must find a ball, approach the ball, grasp the ball, approach the bin, and place the ball in the bin. If any of these tasks fail, the robot must ask for help.

Oh, and the first time the robot picks up the ball, we knock it out of the robot's grasp, because we're mean like that.

The implementation also shows how to use the included bt tree fuzzer to exercise the bt tree.

ask_for_help(obj)

Records that the robot has asked for help

Source code in vultron/bt/base/demo/robot.py
267
268
269
270
271
def ask_for_help(obj: BtNode) -> bool:
    """Records that the robot has asked for help"""
    logger.info("I need help!")
    obj.bb.asked_for_help = True
    return True

ball_close(obj)

Checks whether the ball is close

Source code in vultron/bt/base/demo/robot.py
176
177
178
def ball_close(obj: BtNode) -> bool:
    """Checks whether the ball is close"""
    return obj.bb.ball_close

ball_found(obj)

Checks whether the ball is found

Source code in vultron/bt/base/demo/robot.py
236
237
238
def ball_found(obj: BtNode) -> bool:
    """Checks whether the ball is found"""
    return obj.bb.ball_found

ball_grasped(obj)

Checks whether the ball is grasped

Source code in vultron/bt/base/demo/robot.py
137
138
139
def ball_grasped(obj: BtNode) -> bool:
    """Checks whether the ball is grasped"""
    return obj.bb.ball_grasped

ball_placed(obj)

Checks whether the ball is placed in the bin

Source code in vultron/bt/base/demo/robot.py
58
59
60
def ball_placed(obj: BtNode) -> bool:
    """Checks whether the ball is placed in the bin"""
    return obj.bb.ball_placed

bin_close(obj)

Checks whether the bin is close

Source code in vultron/bt/base/demo/robot.py
 98
 99
100
def bin_close(obj: BtNode) -> bool:
    """Checks whether the bin is close"""
    return obj.bb.bin_close

set_ball_close(obj)

Records that the ball is close

Source code in vultron/bt/base/demo/robot.py
187
188
189
190
def set_ball_close(obj: BtNode) -> bool:
    """Records that the ball is close"""
    obj.bb.ball_close = True
    return True

set_ball_found(obj)

Records that the ball has been found

Source code in vultron/bt/base/demo/robot.py
216
217
218
219
def set_ball_found(obj: BtNode) -> bool:
    """Records that the ball has been found"""
    obj.bb.ball_found = True
    return True

set_ball_grasped(obj)

Records that the ball has been grasped

Source code in vultron/bt/base/demo/robot.py
148
149
150
151
def set_ball_grasped(obj: BtNode) -> bool:
    """Records that the ball has been grasped"""
    obj.bb.ball_grasped = True
    return True

set_ball_placed(obj)

Records that the ball has been placed in the bin

Source code in vultron/bt/base/demo/robot.py
69
70
71
72
def set_ball_placed(obj: BtNode) -> bool:
    """Records that the ball has been placed in the bin"""
    obj.bb.ball_placed = True
    return True

set_bin_close(obj)

Records that the bin is close

Source code in vultron/bt/base/demo/robot.py
109
110
111
112
def set_bin_close(obj: BtNode) -> bool:
    """Records that the bin is close"""
    obj.bb.bin_close = True
    return True

time_to_ask_for_help(obj)

Checks if it is time to ask for help

Source code in vultron/bt/base/demo/robot.py
256
257
258
def time_to_ask_for_help(obj: BtNode) -> bool:
    """Checks if it is time to ask for help"""
    return obj.bb.ticks > 10