Behavior Specialization and Usage Examples
This guide discusses advanced Behavior usage and assumes an understanding of C++ template specialization.
For preliminary reading, please refer to:
Behavior Examples
A comprehensive collection of example Behaviors can be found in the example_behaviors package.
To edit, build, test, and run them, ensure there is no COLCON_IGNORE present in the example_behaviors package while using the moveit_pro_example_ws.
They can then be built and added to an Objective of your choosing.
Using Custom ROS 2 Message, Service, and Action types
Behaviors that require interaction with ROS interfaces (such as Topics, Services, and Actions) must have their interface type defined at compile time. The majority of the code to interact with these interfaces can be considered boilerplate, so we provide convenience classes. The classes are templated, allowing you to specialze them with any types you have available in your workspace.
In this how to guide, we will discuss the following ROS interactions:
- Publishing a Message to a Topic
- Getting a Message from a Topic and placing it on the Blackboard
- Calling a Service and placing the response on the Blackboard
- Calling an Action
Using MoveIt Pro Behavior Templates
Publish a Message to a Topic
Publishing a message does not require any template specialization, simply add a std::shared_ptr<rclcpp::Publisher<MESSAGE_TYPE>> class member variable to an AsyncBehaviorBase and publish a message in the doWork() method.
The API documentation for the AsyncBehaviorBase class is here.
Get a Message from a Topic
The API documentation for the GetMessageFromTopicBehaviorBase class is here.
It can be specialized to to create a custom Behavior that subscribes to a topic, waits until it receives a message on that topic, and then sets the message it received as an output data port.
The GetMessageFromTopicBehaviorBase class itself inherits from AsyncBehaviorBase, which has the following virtual functions that must be implemented in the new class as well.
getWaitForMessageTimeoutis an optional function used to set the timeout used when waiting for a message to be received on the topic. This is left as default in this example (no timeout).getFuturemust be implemented for all classes derived fromAsyncBehaviorBase. It returns ashared_futureclass member.
Call a Service
To create a custom Behavior that creates a service request, waits until it receives a response from the service server, and then sets the response it received as an output data port, you can specialize the ServiceClientBehaviorBase class for the service type of your choice.
The API documentation for the ServiceClientBehaviorBase class is here.
The ServiceClientBehaviorBase class itself inherits from AsyncBehaviorBase, which has the following virtual functions that must be implemented in the new class as well:
getServiceNameis used to get the name of the service when initializing the service client.createRequestis used to to create the service request. In this example, we will make the request from data specified from input ports.getResponseTimeoutis an optional function used to set the timeout used when waiting for the service response. This is left as default in this example (no timeout).processResponseis an optional function used to process the service response after the service has finished. In this example, we will make the response available on an output port.getFuturemust be implemented for all classes derived fromAsyncBehaviorBase. It returns ashared_futureclass member.
Call an Action
To create a custom Behavior that creates an action goal request, processes feedback, and processes results, you can specialize the ActionClientBehaviorBase class for the action type of your choice.
The API documentation for the ActionClientBehaviorBase class is here.
The ActionClientBehaviorBase class itself inherits from AsyncBehaviorBase, which has the following virtual functions that must be implemented in the new class as well.
getActionNameis used to get the name of the action when initializing the action client.createGoalis used to function to create the action goal. In this example, we will make the goal from data specified from an input port.getResultTimeoutis an optional function used to set the timeout used when waiting for the action result. This is left as default in this example (no timeout).processResultis used to process the result from the action server. In this example, we will log the result and make it available on an output port.processFeedbackis used to process the feedback from the action server. In this example, we will log the feedback and make it available on an output port.getFuturemust be implemented for all classes derived fromAsyncBehaviorBase. It returns ashared_futureclass member.
Conclusion
The examples above illustrate the best approach to interacting with ROS interfaces in MoveIt Pro. For a deeper dive in to the implementation details of Behaviors, please consult the API documentation. For a discussion of best practices when writing Behavior Tree Nodes, consult the Behavior Tree and Behavior Concepts page.