Writing a ParallelNode

Overview

This tutorial demonstrates the careBT ParallelNode. Therefore the SimpleParallel node is implemented which has three child nodes of the same type (AddTwoNumbersMultiTickAction). With the input parameters, the amount of ticks can be specified that the children take to complete. As the success_threshold is set to two, the SimpleParallel node succeeds in case that two nodes complete with SUCCESS or FIXED, or fails in case one child node completes with FAILURE or ABORTED. By ‘playing around’ with the input parameters different situation can be provoked.

Create the SimpleParallel node

Create a file named parallel.py with following content. Or use the provided file: parallel.py

 1from carebt import ParallelNode
 2from carebt.examples.longrun_actions import AddTwoNumbersMultiTickActionWithTimeout
 3
 4
 5class SimpleParallel(ParallelNode):
 6    """The `SimpleParallel` example node.
 7
 8    The `SimpleParallel` node has three child nodes of the same type
 9    (`AddTwoNumbersMultiTickActionWithTimeout`). With the three input parameters it can be
10    controlled how many tick each of the nodes take to complete. The
11    `success_threshold` of the `SimpleParallel` node is set to two. That means,
12    that the whole node succeeds as soon as two nodes have completed with
13    `SUCCESS` or `FIXED` or fails as soon as one of the child nodes complete
14    with `FAILURE` or `ABORTED`.
15
16    Input Parameters
17    ----------------
18    ?ticks1 : int
19        The ticks for the first child
20    ?ticks2 : int
21        The ticks for the second child
22    ?ticks3 : int
23        The ticks for the third child
24
25    """
26
27    def __init__(self, bt_runner):
28        super().__init__(bt_runner, 2, '?ticks1 ?ticks2 ?ticks3')
29
30    def on_init(self) -> None:
31        self.add_child(AddTwoNumbersMultiTickActionWithTimeout, '?ticks1 1 1 => ?c1')
32        self.add_child(AddTwoNumbersMultiTickActionWithTimeout, '?ticks2 2 2 => ?c2')
33        self.add_child(AddTwoNumbersMultiTickActionWithTimeout, '?ticks3 3 3 => ?c3')

The code explained

The AddTwoNumbersMultiTickAction node was already introduced in Writing long running ActionNodes and is just reused in this example.

The constructor (__init__) of the SimpleParallel needs to call the constructor (super().__init__) of the ParallelNode and passes the bt_runner, the success_threshold and the signature as arguments. The success_threshold is set to two, and the signature defines three input parameter.

    def __init__(self, bt_runner):
        super().__init__(bt_runner, 2, '?ticks1 ?ticks2 ?ticks3')

In the on_init function the three child nodes are added.

    def on_init(self) -> None:
        self.add_child(AddTwoNumbersMultiTickActionWithTimeout, '?ticks1 1 1 => ?c1')
        self.add_child(AddTwoNumbersMultiTickActionWithTimeout, '?ticks2 2 2 => ?c2')
        self.add_child(AddTwoNumbersMultiTickActionWithTimeout, '?ticks3 3 3 => ?c3')

Run the example

Start the Python interpreter and run the SimpleParallel node:

>>> import carebt
>>> from carebt.examples.parallel import SimpleParallel
>>> bt_runner = carebt.BehaviorTreeRunner()
>>> bt_runner.run(SimpleParallel, '2 4 6')
AddTwoNumbersMultiTickAction: (tick_count = 1/2)
AddTwoNumbersMultiTickAction: (tick_count = 1/4)
AddTwoNumbersMultiTickAction: (tick_count = 1/6)
AddTwoNumbersMultiTickAction: DONE 1 + 1 = 2
AddTwoNumbersMultiTickAction: (tick_count = 2/4)
AddTwoNumbersMultiTickAction: (tick_count = 2/6)
AddTwoNumbersMultiTickAction: (tick_count = 3/4)
AddTwoNumbersMultiTickAction: (tick_count = 3/6)
AddTwoNumbersMultiTickAction: DONE 2 + 2 = 4
AddTwoNumbersMultiTickAction: (tick_count = 4/6)
AddTwoNumbersMultiTickAction: on_abort
>>> bt_runner.run(SimpleParallel, '6 4 2')
AddTwoNumbersMultiTickAction: (tick_count = 1/6)
AddTwoNumbersMultiTickAction: (tick_count = 1/4)
AddTwoNumbersMultiTickAction: (tick_count = 1/2)
AddTwoNumbersMultiTickAction: (tick_count = 2/6)
AddTwoNumbersMultiTickAction: (tick_count = 2/4)
AddTwoNumbersMultiTickAction: DONE 3 + 3 = 6
AddTwoNumbersMultiTickAction: (tick_count = 3/6)
AddTwoNumbersMultiTickAction: (tick_count = 3/4)
AddTwoNumbersMultiTickAction: (tick_count = 4/6)
AddTwoNumbersMultiTickAction: DONE 2 + 2 = 4
AddTwoNumbersMultiTickAction: on_abort

In the first execution the first two nodes complete after two resp. four ticks and thus, the SimpleParallel node also completes. The third node is aborted. In the second execution the third and second node complete after two resp. four ticks. Again, the SimpleParallel node completes as two nodes succedded, and as a consequence the first node is aborted. When aborting a node the on_abort function of this node is called, this is why the message ‘AddTwoNumbersMultiTickAction: on_abort’ is printed on standard output (see implementation of AddTwoNumbersMultiTickAction).