-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* copy in code * copy in code * fix copyright header comment * __init__ files don't need main() * mark broken test as broken * add docs * fix imports and add docstrings * add todos * update docstrings * update docstrings * add bt doc page * add pytest stanza * refine pacman demo and add to installer * continue to refine pacman demo and docs * move global vars into class vars and blackboard * refactor blackboard into its own module * minor refactor * add type hints * fix some warnings * docs refinement * add robot demo to docs * add type hint * add diagram and sample output * roll in more unit tests * add message simulation * rename blackboard class * add vultron simulator bot * fix unit test * add cvd proto demo * use dataclass for blackboard * make report to others a fuzzer * add context manager to help unwind where exceptions are coming from * fix test * working out bugs in cvd_proto simulator * eliminate separate discovery_capability attribute * add cvd role * move fuzzer things to fuzzer module * fix unit tests * turn on other simulator features * add ADR folder, exclude from site publication * add unit tests for basic CS conditions * ignore node.js stuff * make conditions test cases work * make transition test cases work * clean up obsoleted code * add some docs * add demo output * record decisions to build a bt tree python module * update requirements.txt * add report management test module * test basic conditions * update docstring * add tests for compound nodes * add tests for rm states.py * add tests for rm transitions.py * replace ActorState with mock class in test * format with black * update docstrings * add to_graph method to BtNode * add node graph printer rename module internal classes with _ prefix update docstrings * add tests for message conditions * add log msg test * add cs message tests * clean up tests * remove old experimental code * rename internal classes * add factory methods to consistently generate common node types * start using factory methods instead of subclasses * add adr with explanation of factory method usage * more factory stuff * fix string format * fix type hint * improve factory methods * update demos to use factory * add state_in factory * use condition_check factory * update use of state_in factory * update use of factories * update use of factories * update use of factories * use factories * use factories * use factories * use factories * unit tests for factories * keep track of q_cs history * change demo names * catch potential attribute error when no dm function set * markdownlint -fix * markdownlint --fix * markdown lint fixes * add vultron.bt docs to nav * add example * unify command line demo * unify command line demo * reformat with black * markdownlint
- Loading branch information
1 parent
6282a3b
commit c8a90e1
Showing
145 changed files
with
13,649 additions
and
172 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
--- | ||
status: accepted | ||
date: 2023-10-23 | ||
deciders: adh | ||
--- | ||
# Model Processes with Behavior Trees | ||
|
||
## Context and Problem Statement | ||
|
||
The Vultron protocol is defined as a set of three interacting state machines for each agent: | ||
|
||
- Report Management | ||
- Embargo Management | ||
- Case State Management | ||
|
||
We have a need to simulate the behavior of these state machines in order to test the protocol. | ||
However, the interactions between them can be complex, so we need a way to model those interactions. | ||
|
||
## Decision Drivers | ||
|
||
- Need to simulate complex interactions between state machines | ||
- Need to explore and exercise state space of the protocol even if some states are rarely reached in practice | ||
|
||
## Considered Options | ||
|
||
- Object-oriented Agent implementation | ||
- Behavior Tree Agent implementation | ||
|
||
## Decision Outcome | ||
|
||
Chosen option: "Behavior Tree Agent implementation", because behavior trees allow us to model complex interactions | ||
between state machines. By building in stochastic behaviors, they also allow us to explore and exercise the state space | ||
of the protocol even if some states are rarely reached in practice. | ||
|
||
### Consequences | ||
|
||
- Behavior trees are a new technology for the team, so there will be a learning curve. | ||
- Simulating changes to process logic should be easier with behavior trees than with object-oriented code. | ||
|
||
## Pros and Cons of the Options | ||
|
||
### Object-oriented implementation | ||
|
||
Good, because: | ||
|
||
- Standard OO python approach understood by the team | ||
- State management could be implemented as a set of classes for each state machine | ||
|
||
Bad, because: | ||
|
||
- Complex interactions between state machines would be difficult to model and maintain | ||
- Reactive behaviors (e.g., based on state changes in outside world) would be difficult to model | ||
|
||
## More Information | ||
|
||
- Michele Colledanchise, Petter Ögren: Behavior Trees in Robotics and AI | ||
- [book @ Amazon](https://www.amazon.com/Behavior-Trees-Robotics-Introduction-Intelligence/dp/1138593737) | ||
- [pdf @ arXiv](https://arxiv.org/abs/1709.00084) | ||
- Petter Ögren's YouTube channel has a number of good videos on Behavior Trees | ||
- <https://www.youtube.com/@petterogren7535> | ||
- Wikipedia | ||
- [Behavior Tree (artificial intelligence, robotics and control)](https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
--- | ||
status: accepted | ||
date: 2023-10-23 | ||
deciders: adh | ||
--- | ||
# Build our own Behavior Tree engine in Python | ||
|
||
## Context and Problem Statement | ||
|
||
We need a Behavior Tree engine to support our Behavior Tree Agent implementation. | ||
|
||
## Decision Drivers | ||
|
||
- Need to support stochastic behaviors | ||
- Team is most familiar with Python | ||
- Need to support quick prototyping and experimentation | ||
|
||
## Considered Options | ||
|
||
- BehaviorTree.CPP | ||
- py_trees | ||
- Build our own | ||
|
||
## Decision Outcome | ||
|
||
Chosen option: "Build our own", because | ||
|
||
- It's a good opportunity to learn about Behavior Trees | ||
- py_trees is closely tied to robot operating system (ROS), so it might not be a good fit for our use case | ||
- BehaviorTree.CPP is written in C++, so it would be difficult to integrate with the rest of our Python codebase | ||
|
||
This decision can/should be revisited if | ||
|
||
- the complexity of building our own Behavior Tree engine becomes too high | ||
- we discover that existing Behavior Tree engines already support features that would be difficult for us to build | ||
|
||
In order to mitigate the risk of building our own Behavior Tree engine, we will maintain a modular design | ||
that allows us to swap out our engine for an existing engine if necessary. | ||
|
||
### Consequences | ||
|
||
Good, because: | ||
|
||
- Provides an opportunity to learn more about Behavior Trees | ||
- We can build it in Python, so it should be easy to integrate with the rest of our codebase | ||
- We can build it in a way that supports stochastic behaviors | ||
- We can customize it to our needs | ||
|
||
Neutral, because: | ||
|
||
- We might discover that we need features that are already supported by existing Behavior Tree engines | ||
- We might find that other Behavior Tree engines are better suited to our needs | ||
|
||
Bad, because: | ||
|
||
- We have to build and maintain our own Behavior Tree engine | ||
- It's another dependency we have to own and maintain | ||
|
||
## Pros and Cons of the Options | ||
|
||
### BehaviorTree.CPP | ||
|
||
Good, because: | ||
|
||
- It's a mature, well-tested Behavior Tree engine | ||
|
||
Bad, because: | ||
|
||
- It's written in C++, so it would be difficult to integrate with the rest of our Python codebase | ||
|
||
### py_trees | ||
|
||
Good, because: | ||
|
||
- It's written in Python, so it should be easy to integrate with the rest of our codebase | ||
- It seems to be a mature, well-tested Behavior Tree engine | ||
|
||
Neutral-to-bad, because: | ||
|
||
- It's closely tied to robot operating system (ROS), so it might not be a good fit for our use case | ||
|
||
## More Information | ||
|
||
- [BehaviorTree.CPP](https://www.behaviortree.dev/) [GitHub](https://github.com/BehaviorTree/BehaviorTree.CPP) | ||
- [py_trees](https://py-trees.readthedocs.io/en/devel/) [GitHub](https://github.com/splintered-reality/py_trees) |
70 changes: 70 additions & 0 deletions
70
docs/adr/0004-use-factory-methods-for-common-bt-node-types.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
--- | ||
# These are optional elements. Feel free to remove any of them. | ||
status: accepted | ||
date: 2023-10-24 | ||
deciders: adh | ||
--- | ||
# Use factory methods for common BT node types | ||
|
||
## Context and Problem Statement | ||
|
||
We have a number of common BT node types that are used in multiple trees. We want to be able to create these nodes | ||
in a consistent way, and we want to be able to easily change the implementation of these nodes without having to | ||
change the code that creates them. | ||
|
||
## Decision Drivers | ||
|
||
* We want to be able to create these nodes in a consistent way | ||
* Preserve future flexibility to change the underlying BT node implementation without having to change the code that creates them | ||
|
||
## Considered Options | ||
|
||
* No factory methods, directly subclass the BT node types | ||
* Use factory methods | ||
|
||
## Decision Outcome | ||
|
||
Chosen option: "Use factory methods", because it allows us to create the nodes in a consistent way, and it allows us to | ||
change the underlying implementation without having to change the code that creates them. | ||
|
||
### Consequences | ||
|
||
Good because: | ||
|
||
* retains flexibility to change the underlying implementation without having to change the code that creates them | ||
* allows us to create the nodes in a consistent way | ||
* allows us to keep the `vultron.bt.base` module clean and focused on the base classes | ||
* allows us to keep the rest of the `vultron.bt` module focused on Vultron-specific needs | ||
|
||
Neutral because: | ||
|
||
* Adds a central place to maintain the factory methods | ||
|
||
Bad because: | ||
|
||
* less pythonic than just subclassing the BT node types | ||
|
||
## Pros and Cons of the Options | ||
|
||
### No factory methods | ||
|
||
Good because: | ||
|
||
* more pythonic | ||
* | ||
|
||
Neutral because: | ||
|
||
Bad because: | ||
|
||
* Harder to enforce consistency in how the nodes are created | ||
|
||
## More Information | ||
|
||
This decision was inspired in part by the `py_trees` [documentation](https://py-trees.readthedocs.io/en/devel/the_crazy_hospital.html) | ||
(in the context of composite nodes): | ||
|
||
> Don’t subclass merely to auto-populate it, build a create_<xyz>_subtree() library instead | ||
Which got us thinking about using factory methods to help maintain a clean separation between the `vultron.bt.base` | ||
module and the things that live above it. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Behavior Trees | ||
|
||
::: vultron.bt | ||
|
||
::: vultron.bt.base | ||
|
||
::: vultron.bt.behaviors | ||
|
||
::: vultron.bt.fuzzer | ||
|
||
::: vultron.bt.states | ||
|
||
::: vultron.bt.errors | ||
|
||
::: vultron.bt.common |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Behavior Tree Base | ||
|
||
The Vultron behavior tree base module defines the basic building blocks of any behavior tree. | ||
This page covers the basic Tree and Blackboard classes, as well as the basic error classes. | ||
Detailed descriptions of Node types are provided in [Behavior Tree Basic Node Types](bt_base_nodes.md). | ||
|
||
::: vultron.bt.base | ||
|
||
::: vultron.bt.base.bt | ||
|
||
::: vultron.bt.base.blackboard | ||
|
||
::: vultron.bt.base.errors |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Behavior Tree Basic Node Types | ||
|
||
We have defined a number of basic node types. | ||
These are the building blocks of any behavior tree. | ||
They are defined in the `vultron.bt.base` module. | ||
|
||
::: vultron.bt.base.node_status | ||
|
||
::: vultron.bt.base.bt_node | ||
|
||
::: vultron.bt.base.composites | ||
|
||
::: vultron.bt.base.decorators | ||
|
||
::: vultron.bt.base.fuzzer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Vultron Case State Behaviors | ||
|
||
::: vultron.bt.case_state.conditions | ||
|
||
::: vultron.bt.case_state.transitions |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
# Pacman Bot Behavior Tree Demo | ||
|
||
This is a demo of a behavior tree for a game playing bot. | ||
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. | ||
|
||
It implements a simplified Pacman game with a bot that eats pills and avoids ghosts. | ||
|
||
## Behaviors | ||
|
||
If no ghosts are nearby, Pacman eats one pill per tick. | ||
But if a ghost is nearby, Pacman will chase it if it is scared, otherwise he will avoid it. | ||
If he successfully avoids a ghost, he will eat a pill. | ||
The game ends when Pacman has eaten all the pills or has been eaten by a ghost. | ||
|
||
## Scoring | ||
|
||
Scoring is as follows: | ||
|
||
- 10 points per pill | ||
- 200 points for the first ghost, 400 for the second, 800 for the third, 1600 for the fourth | ||
|
||
There are 240 pills on the board. The max score is | ||
|
||
$$(240 \times 10) + (200 + 400 + 800 + 1600) = 5400$$ | ||
|
||
## Differences from the real thing | ||
|
||
If the game exceeds 1000 ticks, Pacman gets bored and quits (but statistically that should never happen). | ||
|
||
We did not model power pellets, fruit, or the maze. Ghosts just randomly get scared and then randomly | ||
stop being scared. Ghosts and pills are just counters. Ghost location is just a random "nearby" check. | ||
|
||
## The Behavior Tree | ||
|
||
The tree structure is shown below. | ||
|
||
{% include-markdown './pacman_tree_diagram.md' %} | ||
|
||
Legend: | ||
|
||
| Symbol | Meaning | | ||
|----------| ------- | | ||
| ? | FallbackNode | | ||
| → | SequenceNode | | ||
| ⇅ | Invert | | ||
| ▰ | ActionNode | | ||
| ⬬ | ConditionNode | | ||
| 🎲 | Fuzzer node (randomly succeeds or fails some percentage of the time) | | ||
|
||
## Demo Output | ||
|
||
!!! example | ||
|
||
```shell | ||
# if vultron package is installed | ||
# run the demo | ||
$ vultrabot --pacman | ||
|
||
# print tree and exit | ||
$ vultrabot --pacman --print-tree | ||
|
||
# if vultron package is not installed | ||
$ python -m vultron.bt.base.demo.pacman | ||
``` | ||
|
||
When the tree is run, it will look something like this: | ||
|
||
```text | ||
{% include-markdown './pacman_tree_example.txt' %} | ||
``` | ||
|
||
## Demo Code | ||
|
||
::: vultron.bt.base.demo.pacman | ||
options: | ||
heading_level: 3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
```mermaid | ||
graph TD | ||
MaybeEatPills_1["→ MaybeEatPills"] | ||
MaybeChaseOrAvoidGhost_2["? MaybeChaseOrAvoidGhost"] | ||
MaybeEatPills_1 --> MaybeChaseOrAvoidGhost_2 | ||
NoMoreGhosts_3["#8645; NoMoreGhosts"] | ||
MaybeChaseOrAvoidGhost_2 --> NoMoreGhosts_3 | ||
GhostsRemain_4["#11052; GhostsRemain"] | ||
NoMoreGhosts_3 --> GhostsRemain_4 | ||
NoGhostClose_5["#8645; NoGhostClose"] | ||
MaybeChaseOrAvoidGhost_2 --> NoGhostClose_5 | ||
GhostClose_6["#127922; GhostClose"] | ||
NoGhostClose_5 --> GhostClose_6 | ||
ChaseOrAvoidGhost_7["? ChaseOrAvoidGhost"] | ||
MaybeChaseOrAvoidGhost_2 --> ChaseOrAvoidGhost_7 | ||
ChaseIfScared_8["→ ChaseIfScared"] | ||
ChaseOrAvoidGhost_7 --> ChaseIfScared_8 | ||
GhostsScared_9["#11052; GhostsScared"] | ||
ChaseIfScared_8 --> GhostsScared_9 | ||
ChaseGhost_10["#127922; ChaseGhost"] | ||
ChaseIfScared_8 --> ChaseGhost_10 | ||
CaughtGhost_11["→ CaughtGhost"] | ||
ChaseIfScared_8 --> CaughtGhost_11 | ||
DecrGhostCount_12["#9648; DecrGhostCount"] | ||
CaughtGhost_11 --> DecrGhostCount_12 | ||
ScoreGhost_13["#9648; ScoreGhost"] | ||
CaughtGhost_11 --> ScoreGhost_13 | ||
IncrGhostScore_14["#9648; IncrGhostScore"] | ||
CaughtGhost_11 --> IncrGhostScore_14 | ||
GhostsScared_15["#11052; GhostsScared"] | ||
ChaseOrAvoidGhost_7 --> GhostsScared_15 | ||
AvoidGhost_16["#127922; AvoidGhost"] | ||
ChaseOrAvoidGhost_7 --> AvoidGhost_16 | ||
EatPill_17["#9648; EatPill"] | ||
MaybeEatPills_1 --> EatPill_17 | ||
``` |
Oops, something went wrong.