Skip to main content

bonsai_bt/
lib.rs

1//!
2//! *Bonsai - Behavior Tree*
3//!
4//! You can serialize the
5//! behavior tree using [Serde](https://crates.io/crates/serde),
6//! [Ron](https://crates.io/crates/ron) and [graphviz](https://graphviz.org/)
7//!
8//! A _Behavior Tree_ (BT) is a data structure in which we can set the rules of how certain _behavior's_ can occur, and the order in which they would execute. BTs are a very efficient way of creating complex systems that are both modular and reactive. These properties are crucial in many applications, which has led to the spread of BT from computer game programming to many branches of AI and Robotics.
9//!
10//! ### How to use a Behavior tree?
11
12//! A Behavior Tree forms a tree structure where each node represents a process.
13//! When the process terminates, it signals `Success` or `Failure`. This can then
14//! be used by the parent node to select the next process.
15//! A signal `Running` is used to tell the process is not done yet.
16
17//! For example, if you have a state `A` and a state `B`:
18
19//! - Move from state `A` to state `B` if `A` succeeds: `Sequence([A, B])`
20//! - Try `A` first and then try `B` if `A` fails: `Select([A, B])`
21//! - If `condition` succeedes do `A`, else do `B` : `If(condition, A, B)`
22//! - If `A` succeeds, return failure (and vice-versa): `Invert(A)`
23//! - Do `B` repeatedly while `A` runs: `While(A, [B])`
24//! - Run `B` while re-checking `A` on every tick (abort `B` if `A` flips): `Sequence([A, B]).memory(false)`
25//! - Do `A`, `B` forever: `While(WaitForever, [A, B])`
26//! - Run `A` and `B` in parallell and wait for both to succeed: `WhenAll([A, B])`
27//! - Run `A` and `B` in parallell and wait for any to succeed: `WhenAny([A, B])`
28//! - Run `A` and `B` in parallell and wait for any to complete regardless of success or failure: `Race([A, B])`
29//! - Run `A` and `B` in parallell, but `A` has to succeed before `B`: `After([A, B])`
30//!
31//! See the `Behavior` enum for more information.
32
33//! ## Example of use
34
35//! This is a simple example with two possible Actions: Increment a number, Decrement a number. We
36//! construct a BT where we increment a number twice, one second apart. Then wait 0.5 seconds before we
37//! then decrement the same number again. Additionally we use a Blackboard to store/persist the immediate
38//! state of the number accessed by the key `count`.
39//!
40//! ```rust
41//! use bonsai_bt::{Event, Float, Success, UpdateArgs, BT};
42//! use std::collections::HashMap;
43//! // Some test actions.
44//! #[derive(Clone, Debug, Copy)]
45//! pub enum Actions {
46//!     ///! Increment accumulator.
47//!     Inc,
48//!     ///! Decrement accumulator.
49//!     Dec,
50//! }
51//!
52//! // A test state machine that can increment and decrement.
53//! fn tick(mut acc: i32, dt: Float, bt: &mut BT<Actions, HashMap<String, i32>>) -> i32 {
54//! let e: Event = UpdateArgs { dt }.into();
55//!
56//!     let (_status, _dt) = bt.tick(&e, &mut |args, blackboard| match *args.action {
57//!         Actions::Inc => {
58//!             acc += 1;
59//!             (Success, args.dt)
60//!         }
61//!         Actions::Dec => {
62//!             acc -= 1;
63//!             (Success, args.dt)
64//!         }
65//!     }).unwrap();
66//!
67//!     // update counter in blackboard
68//!     let bb = bt.blackboard_mut();
69//!
70//!     bb.entry("count".to_string())
71//!         .and_modify(|count| *count = acc)
72//!         .or_insert(0)
73//!         .to_owned();
74//!
75//!     acc
76//! }
77//!
78//! fn main() {
79//!     use crate::Actions::{Inc, Dec};
80//!     use std::collections::HashMap;
81//!     use bonsai_bt::{Action, Sequence, Wait};
82//!
83//!     // create the behavior
84//!     let behavior = Sequence(vec![
85//!         Wait(1.0),
86//!         Action(Inc),
87//!         Wait(1.0),
88//!         Action(Inc),
89//!         Wait(0.5),
90//!         Action(Dec),
91//!     ]);
92//!
93//!     // you have to initialize a blackboard even though you're
94//!     // not necessarily using it for storage
95//!     let mut blackboard: HashMap<String, i32> = HashMap::new();
96//!
97//!     // instantiate the bt
98//!     let mut bt = BT::new(behavior, blackboard);
99//!
100//!     let a: i32 = 0;
101//!     let a = tick(a, 0.5, &mut bt); // have bt advance 0.5 seconds into the future
102//!     assert_eq!(a, 0);
103//!     let a = tick(a, 0.5, &mut bt); // have bt advance another 0.5 seconds into the future
104//!     assert_eq!(a, 1);
105//!     let a = tick(a, 0.5, &mut bt);
106//!     assert_eq!(a, 1);
107//!     let a = tick(a, 0.5, &mut bt);
108//!     assert_eq!(a, 2);
109//!     let a = tick(a, 0.5, &mut bt);
110//!     assert_eq!(a, 1);
111//!
112//!     let bb = bt.blackboard_mut();
113//!     let count = bb.get("count").unwrap();
114//!     assert_eq!(*count, 1);
115//!
116//!     // if the behavior tree concludes (reaches a steady state)
117//!     // you can reset the tree back to it's initial state at t=0.0
118//!     bt.reset_bt();
119//! }
120//! ```
121
122pub use behavior::Behavior::{
123    self, Action, After, AlwaysSucceed, If, Invert, Race, Select, Sequence, Wait, WaitForever, WhenAll, WhenAny, While,
124    WhileAll,
125};
126
127pub use bt::BT;
128pub use event::{Event, Timer, UpdateArgs, UpdateEvent};
129pub use state::{ActionArgs, RUNNING};
130pub use status::Status::{self, Failure, Running, Success};
131
132mod behavior;
133mod bt;
134mod event;
135mod sequence;
136mod state;
137mod status;
138mod tracer;
139mod when_all;
140
141#[cfg(feature = "visualize")]
142pub mod telemetry;
143
144#[cfg(feature = "visualize")]
145mod telemetry_state;
146
147#[cfg(feature = "visualize")]
148mod bt_telemetry;
149
150#[cfg(feature = "visualize")]
151mod visualizer;
152
153#[cfg(feature = "visualize")]
154mod visualizer_server;
155
156#[cfg(feature = "visualize")]
157#[doc(hidden)]
158pub use visualizer_server::spawn_server;
159
160/// Float type used in [`BT::tick()`] and everywhere in the crate.
161///
162/// - If feature `f32` is active => [`f32`]
163/// - Else => [`f64`]
164#[cfg(feature = "f32")]
165pub type Float = f32;
166
167/// Float type used in [`BT::tick()`] and everywhere in the crate.
168///
169/// - If feature `f32` is active => [`f32`]
170/// - Else => [`f64`]
171#[cfg(not(feature = "f32"))]
172pub type Float = f64;