Skip to content

Example does not function as expected #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
fnivek opened this issue Jan 20, 2018 · 3 comments
Closed

Example does not function as expected #16

fnivek opened this issue Jan 20, 2018 · 3 comments

Comments

@fnivek
Copy link

fnivek commented Jan 20, 2018

I'm pretty sure there are some functionality errors in the code, particularly the sequence node. For example the tree example will never get past a starting action 1. The output from one run commented below explains what happens. Note the tree example runs as expected if you replace all sequence nodes with sequence with memory nodes.

// Start the example
rosrun behavior_tree_core tree
// Everything initializes
Action 1 WAIT FOR TICK
Action 2 WAIT FOR TICK
Action 3 WAIT FOR TICK
Start Drawing!
[ INFO] [1516430124.415782852]: Visualization: Start publishing the tree in topic: /bt_dotcode with rate: 50 Hz.

// Start ticking
Ticking the root node !
Action 2 is setting its status to 3
seq1NEEDS TO TICK Action 2
Action 2 is setting its status to 3

// Ticked action 2
Action 2 TICK RECEIVED
Action 2 is setting its status to 0
Action Action 2running! Thread id:139852564367104
Action 2 is setting its status to 0

// It is in state running so sequence nodes halts all nodes to the right
seq1 is HALTING children from 1
seq1 is HALTING children from 1
Action 1 is setting its status to 3
Action 1 is setting its status to 3
NO NEED TO HALT Action 1STATUS3
seq1 is setting its status to 3
seq1 is setting its status to 3
NO NEED TO HALT seq1STATUS3
seq1 is setting its status to 0
Action 2 is setting its status to 0
Action Action 2running! Thread id:139852564367104

// Second tick
Ticking the root node !
Action 2 is setting its status to 0

// Action 2 is still running so halt all future nodes
seq1 is HALTING children from 1
seq1 is HALTING children from 1
Action 1 is setting its status to 3
Action 1 is setting its status to 3
NO NEED TO HALT Action 1STATUS3
seq1 is setting its status to 3
seq1 is setting its status to 3
NO NEED TO HALT seq1STATUS3
seq1 is setting its status to 0
Action 2 is setting its status to 0
Action Action 2running! Thread id:139852564367104

// Tick 3
Ticking the root node !
Action 2 is setting its status to 0

// Still running halt others
seq1 is HALTING children from 1
seq1 is HALTING children from 1
Action 1 is setting its status to 3
Action 1 is setting its status to 3
NO NEED TO HALT Action 1STATUS3
seq1 is setting its status to 3
seq1 is setting its status to 3
NO NEED TO HALT seq1STATUS3
seq1 is setting its status to 0
Action 2 is setting its status to 0
Action 2 is setting its status to 0

// Action 2 returns success!
Action Action 2 Done!

// Action 2 is ready for more
Action 2 WAIT FOR TICK

// Tick 4
Ticking the root node !

// Action 2 is success set to idle and move on
Action 2 is setting its status to 1

// Tick condition 2 and wait
Condition 2 is setting its status to 3
Condition 2 returning Success1!

// Tick condition 1 and wait
Condition 1 is setting its status to 3
Condition 1 returning Success1!

// Tick Action 1
Action 1 is setting its status to 3
seq1NEEDS TO TICK Action 1
Action 1 is setting its status to 3

// Action 1 is now running
Action 1 TICK RECEIVED
Action 1 is setting its status to 0
Action Action 1running! Thread id:139852572759808
Action 1 is setting its status to 0

// Action 1 is running so halt future nodes
seq1 is HALTING children from 3
seq1 is setting its status to 3
seq1 is setting its status to 3
NO NEED TO HALT seq1STATUS3
seq1 is setting its status to 0
Action 1 is setting its status to 0
Action Action 1running! Thread id:139852572759808

// Tick 5 (This is where it breaks)
Ticking the root node !

// Action 2 is idle so we must tick it!!!!!
Action 2 is setting its status to 3
seq1NEEDS TO TICK Action 2
Action 2 is setting its status to 3

// Tick received by action 2
Action 2 TICK RECEIVED
Action 2 is setting its status to 0
Action Action 2running! Thread id:139852564367104
Action 2 is setting its status to 0

// Action 2 is running so halt all future nodes
seq1 is HALTING children from 1
seq1 is HALTING children from 1
Action 1 is setting its status to 0

// Action one is still running so we must halt it!!!!!!!!!!!!!!!!!!!!!!
// Action 1 will never complete it will always be halted
SENDING HALT TO CHILD Action 1
HALTED state set!
seq1 is setting its status to 3
seq1 is setting its status to 3
NO NEED TO HALT seq1STATUS3
seq1 is setting its status to 0

// Action one halted so it restarts
Action 1 is setting its status to 4
Action 1 is setting its status to 4
Action 1 WAIT FOR TICK
Action 2 is setting its status to 0
Action Action 2running! Thread id:139852564367104

// Tick 6 We now start the whole process over again
Ticking the root node !
Action 2 is setting its status to 0
seq1 is HALTING children from 1
seq1 is HALTING children from 1
Action 1 is setting its status to 4
Action 1 is setting its status to 4
NO NEED TO HALT Action 1STATUS4
seq1 is setting its status to 3
seq1 is setting its status to 3
NO NEED TO HALT seq1STATUS3
seq1 is setting its status to 0
Action 2 is setting its status to 0
Action Action 2running! Thread id:139852564367104
Ticking the root node !
Action 2 is setting its status to 0
seq1 is HALTING children from 1
seq1 is HALTING children from 1
Action 1 is setting its status to 4
Action 1 is setting its status to 4
NO NEED TO HALT Action 1STATUS4
seq1 is setting its status to 3
seq1 is setting its status to 3
NO NEED TO HALT seq1STATUS3
seq1 is setting its status to 0`

@miccol
Copy link
Owner

miccol commented Jan 20, 2018

Hi fnivek,

thank you for highlighting this.

The fundamental difference between a "regular" sequence node and a sequence node with memory is how they deal with a child when this returns Success.

A sequence node with memory, when receives a tick from its parent, ticks the first child. If the first child return Success, the Sequence with memory starts ticking the second child. When the Sequence with memory receives subsequent will tick from its parent it will tick directly the second child.

A regular sequence node (no memory), when receives a tick from its parent, ticks the first child. If the first child return Success, the Sequence starts ticking the second child. When the Sequence receives subsequent ticks from its parent it will tick the first child and if this still returns Success will tick the
second child.

The reason one should use the regular Sequence node is to have a reactive and closed loop execution.
Imagine the task described by the Behavior Tree below:

closedexample-1

The task to perform is composed of the subtasks: pick object if not picked,
assemble object if not assembled, and place object if not placed. The Behavior Tree above can reactively handle unexpected changes, possibly produced by a human or the object slipping out of the robot gripper while the robot is moving it. If we had instead chosen to aggregate the actions pick object, assemble object, and place object into Sequence node with memory we would lose reactiveness when, for example, the robot has to re-pick an assembled object that slipped out from the robot’s grippers while the robot is assembling it. A node with memory would assume that once the object is picked, it stays picked for the whole execution of the task.

Hence, in regular sequence node, the first action will be always executed unless it returns Success when its execution is not needed.
I prefer to avoid to add this checks inside the action itself and create a Fallback composition of the condition that the action is meant to satisfy and the action itself, as in the Behavior Tree above (e.g. Fallback(Object Picked, Pick Object)).

The argument is extended N children and a similar argument can be done for the Fallback node but considering the Failure status.

I know that in literature sometimes there is confusion between regular nodes and nodes with memory. I tried to make a unified picture of Behavior Trees
here. I also talk about design principles and best practices.

I hope this clarifies the functionality of the Sequence node.
If you have further questions, do not hesitate to ask them.

Best,

Michele

@fnivek
Copy link
Author

fnivek commented Jan 20, 2018

Thank you very much for the explanation. The book will also be very helpful for designing our own behavior trees.

As a suggestion it might be a good idea to explain the expected results of the examples to avoid confusion in the future.

Good luck with your research and happy codding.

@fnivek fnivek closed this as completed Jan 20, 2018
@miccol
Copy link
Owner

miccol commented Jan 21, 2018

I agree. I will add a note on that.

Thank you for using the library. If you like it, please put a star on it. So more people have the chance to know it and improve it.

Best,
Michele

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants