Deploying Behaviors
In this tutorial we're going to describe everything that you need to know when using AutoAPMS's behavior tree executor.
For deploying a behavior you need to build a behavior tree beforehand. Read the corresponding tutorial if you're not familiar with this process.
Using a Suitable Build Handler
To define how the executor builds the behavior tree to be executed, you must tell it which build handler implementation to use. This can be done by in two ways:
- Setting the executor's ROS 2 parameter named
build_handler
. - Using the
build_handler
field of aStartTreeExecutor
action goal.
The user is expected to provide a resource identity in order to specify the build handler to be used. Visit this page to learn more about build handler resources and the standard implementations we provide.
Spinning the Executor
Users may spawn the behavior tree executor as it's done with any other ROS 2 node. We provide a minimal executable called tree_executor
which simply spins the node. It can be used from the terminal or inside a ROS 2 launch file like this:
ros2 run auto_apms_behavior_tree tree_executor
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription(
[
Node(
package="auto_apms_behavior_tree",
executable="tree_executor"
)
]
)
If you're using ROS 2 Composition, the corresponding component can be found under the name auto_apms_behavior_tree::TreeExecutorNode
and spawned like this:
# Spawn the component container
ros2 run rclcpp_components component_container
# Add the executor node to the container (from another terminal)
ros2 component load /ComponentManager auto_apms_behavior_tree auto_apms_behavior_tree::TreeExecutorNode
from launch import LaunchDescription
from launch_ros.actions import ComposableNodeContainer
from launch_ros.descriptions import ComposableNode
def generate_launch_description():
return LaunchDescription(
[
ComposableNodeContainer(
name="my_container",
namespace="my_namespace",
package="rclcpp_components",
executable="component_container",
composable_node_descriptions=[
ComposableNode(
package="auto_apms_behavior_tree",
plugin="auto_apms_behavior_tree::TreeExecutorNode"
)
]
)
]
)
The package auto_apms_behavior_tree
additionally offers an executable called run_tree
which automatically spawns the executor and starts executing a specific behavior tree directly afterwards. It implements a custom runtime and handles SIGINT signals appropriately. Use it like this:
ros2 run auto_apms_behavior_tree run_tree -h # Prints help information
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription(
[
Node(
package="auto_apms_behavior_tree",
executable="run_tree",
arguments=["-h"] # Prints help information
)
]
)
It accepts one argument: The build request for the underlying build handler. By default, you can simply pass a behavior tree resource identity and the corresponding behavior tree will be executed immediately. This is because the behavior executor loads TreeFromResourceBuildHandler
on startup. You can customize which build handler should be loaded initially by setting the corresponding ROS 2 parameter like this:
ros2 run auto_apms_behavior_tree run_tree "<build_request>" --ros-args -p build_handler:=my_namespace::MyBuildHandlerClass
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription(
[
Node(
package="auto_apms_behavior_tree",
executable="run_tree",
arguments=["<build_request>"],
parameters=[{
"build_handler": "my_namespace::MyBuildHandlerClass"
}]
)
]
)
INFO
If you cannot use run_tree
for some reason (e.g. when applying ROS 2 composition), you should first spawn the node and then, in a separate step, send a StartTreeExecutor
action goal.
As a last resort, you can also pass a build request as the first command line argument of tree_executor
which populates the arguments
member of rclcpp::NodeOptions
. This will also cause the executor to automatically start ticking the behavior tree but the runtime doesn't handle interrupt signals very well.
Interacting with the Executor
Users may communicate with a spinning executor node by creating ROS 2 action clients and sending goals to the corresponding actions:
The former action allows to initiate the execution of a particular behavior tree and the latter offers a way to interrupt/restart this process.
We conveniently provide behavior tree nodes associated with these actions:
Since a behavior tree executor implements the same standard interfaces as any other ROS 2 node, it's also possible to query or manipulate parameters at runtime. Besides the statically declared executor parameters you may additionally use scripting enum parameters or global blackboard parameters.
The following nodes allow for interacting with ROS 2 parameters from within a behavior tree:
HasParameter
GetParameter
GetParameter<TypeName>
(implemented for each ROS 2 parameter type)SetParameter
SetParameter<TypeName>
(implemented for each ROS 2 parameter type)
Nesting Behaviors
The flexible action interface introduced by the behavior tree executor makes it possible to deploy behaviors remotely. This architecture also allows for multiple behavior trees being executed in real parallelism by different executor nodes communicating with each other. Therefore, this functionality empowers users of AutoAPMS to design arbitrarily complex systems and spawn deeply nested behaviors trees.
By using StartExecutor
and the other behavior tree nodes designed for interacting with TreeExecutorNode
, the user is not limited to including subtrees locally but profits significantly from increased modularity. With the attach
field, you can control whether to attach to a behavior tree and wait for it to be completed or detach one behavior from another. In detached mode, you're able to do work asynchronously but must manually make sure to not leave the remote executor running after the parent behavior completed (for example by ticking TerminateExecutor
last thing).
The next tutorial explains how nested behaviors are used in AutoAPMS to create reactive behaviors. We specifically organize multiple behavior trees and create an even higher level of abstraction: Missions.