MoveIt Pro Behavior Interface
5.2.0
Library for developing custom behaviors for use in MoveIt Pro
|
This package contains the base classes used to create new Behavior plugins that can be executed as part of Objectives.
Refer to the Behavior Trees documentation for more information.
The test
directory contains various helper classes and macros for Behavior testing. These helpers can:
The test file is the source of truth about the Behavior, and the Behavior code will have to comply with the port definition in the test file, so the first thing to do is defining the input and output ports of the Behavior under test.
The following example defines a map of input ports named "myExpectedInputPorts" and a map of output ports named "myExpectedOutputPorts". In each line of the map definition, a port ID is associated with the value the port will take in that map. Note that, if a port is both an input and an output, we just need to include it in both maps.
Now, to test the Behavior, our test fixture will have to inherit from a helper class (in addition to its base test fixture). There are helper classes for Behaviors with and without context, also known as shared resources. If the Behavior has context, the most common case, our fixture must inherit from WithBehavior<>
. In either case, we then must call initBehavior()
from the fixture's SetUp()
, or from any other setup function the fixture offers. The following example shows this case. Note how initBehavior()
gets the expected input and output ports we defined above.
For behaviors without context, the pattern is the same, but uses the WithBehaviorWithoutContext
helper class instead.
There are macros to automatically generate tests to check if your Behavior handles the situation in which one port has no value set in the blackboard when it is run. There are macros for synchronous and asynchronous Behaviors, with and without context.
If the Behavior is synchronous and has context:
If the Behavior is asynchronous and has context:
If the Behavior is synchronous and does not have context:
If the Behavior is asynchronous and does not have context:
These macros generate one test per input port, in which the port is the only one not set. The test expects the Behavior to fail after logging a failure message pointing at the port.
But what if a Behavior is ok with an input port not being set? We can simply define the port as optional as below. Optional ports must be created by the Behavior, but no specific outcome will be enforced by the "port no set" tests.
Let's put everything together in an example where we test an asynchronous Behavior with context:
Behaviors communicating with action servers normally mock those servers in the test fixture. The WithActionBehavior
base class lets us pass a mock when initializing the action Behavior:
The macros that automatically instantiate "port not set" tests use their own test fixture internally and won't set up any action server mocks. In that case, we can use another flavor of the macro:
Note that the only novelty is that the first parameter is the test fixture itself. The macro will instantiate all tests as usual, but they will use the passed fixture, which will set up all action server mocks appropriately before each test.
We provide generic LoadFromYaml
and LoadMultipleFromYaml
templates that can be used to create behaviors that need to load data types from a YAML file.
All that is needed is to:
To use the LoadFromYaml
and LoadMultipleFromYaml
Behavior templates, a YAML conversion function needs to exist for the data type being loaded.
YAML conversion functions for common types, including generic ROS messages can be found in yaml_parsing_tools.hpp
.
We offer a ROS_MESSAGE_YAML_PARSER
macro to automatically add support for any ROS message. It just needs to be instantiated for you particular type. For instance, adding this line will create a YAML conversion function for trajectory_msgs::msg::JointTrajectory
messages:
After this, LoadFromYaml
and LoadMultipleFromYaml
can be used with this type.
Once a YAML conversion function exists for the type you want to load, you can register your Behavior using the provided LoadFromYaml
or LoadMultipleFromYaml
templates.
For instance, this line will register a new Behavior, called LoadJointTrajectoryFromYaml
, to load a trajectory_msgs::msg::JointTrajectory
ROS message from a YAML file.
If you need a Behavior to load a vector of a given data type, use LoadMultipleFromYaml
instead. For instance, this line will register a new Behavior, called LoadPoseStampedVectorFromYaml
, to load a vector of geometry_msgs::msg::PoseStamped
messages from a YAML file:
In this case, the YAML file needs to be formatted as multi-document YAML, e.g.: