Introduction - Deprecated, please reference examples under /example for the usage based on the latest implementation.
Actionlib tutorial based on rclnodejs
.
To continue the tutorial, you should have some basic understanding of the action
term in ROS. If you're not familiar with it, please refer to the description.
You should prepare an action text file. The content is like this:
# Define the goal
uint32 dishwasher_id # Specify which dishwasher we want to use
---
# Define the result
uint32 total_dishes_cleaned
---
# Define a feedback message
float32 percent_complete
# Use a message from another package, to prove that it works
sensor_msgs/Image image
Fortunately, there is a dodishes.action
file that is already available in the test/ros1_actions
directory.
For rclnodejs
, the basic steps of process an action file is separated into 2 steps:
- Generate several msg files and the js message package from the action file.
- Build the shared library from the msg files that will be used in running actionlib-feature-related code.
The generated
directory contains the generated js message package for rclnodejs
. If you have run npm install
, then it should
exist after npm install
was done. However, since your AMENT_PREFIX_PATH
may not include the directory path of the action file, the ros1_actions
package may not be generated. So you need remove the whole generated
directory and regenerate them.
$ rm -fr generated
$ export AMENT_PREFIX_PATH=$AMENT_PREFIX_PATH:$(pwd)/test/ros1_actions
$ node scripts/generate_messages.js
$ cd test/ros1_actions
$ colcon build
After the build, you can run the action example. The action example contains two parts, one is the action server, another is the action client. When running the example, you should launch the server first, and then launch the client.
- Launch a terminal session, load ROS2 environment and go to
rclnodejs
directory.
$ source test/ros1_actions/install/local_setup.bash
$ node example/action-server-example.js
- Launch another terminal session, load ROS2 environment and go to
rclnodejs
directory.
$ source test/ros1_actions/install/local_setup.bash
$ node example/action-client-example.js
Here is the action client output:
The goal was sent, the goal id is 7c28f24a-5ce8-4b13-a2aa-7aa62128fd03
70% of the task has been completed.
The goal, whose id is 7c28f24a-5ce8-4b13-a2aa-7aa62128fd03, has been executed successfully.
10 dishes have been cleaned.
The goal, whose id is 7c28f24a-5ce8-4b13-a2aa-7aa62128fd03, has been executed successfully.
And here is the action server output:
A goal, whose id is 7c28f24a-5ce8-4b13-a2aa-7aa62128fd03, was received.
- Action server For the action server, the skeleton code is like this:
rclnodejs.init().then(() => {
const as = new rclnodejs.ActionLib.ActionServer({
type: 'ros1_actions/msg/DoDishes',
actionServer: 'dishes',
rclnodejs: rclnodejs
});
as.on('goal', function(goal) {
goal.setAccepted('goal accepted');
goal.publishFeedback(feedback);
setTimeout(() => {
goal.setSucceeded({total_dishes_cleaned: 10}, 'done');
}, 500);
});
as.on('cancel', (goalHandle) => {
// cancel handler code
});
as.start();
}).catch((err) => {
console.error(err);
});
First, you should new an ActionServer
with the type
and the actionServer
. The type
is the action package name and the actionServer
is the name of the action server, which should be the same as the action client request to in future.
The ActionServer
can emit 2 type events: goal
and cancel
events.
goal
event: triggered when an action client sends an goal to the action server by calling itssendGoal()
method. In the handler of the this event, you can accept the goal by callinggoal.setAccepted()
. During executing the goal, you can send a feedback to the action client by callinggoal.publishFeedback()
. Once the goal is completed, you should set the goal status by callinggoal.setSucceeded()
, which will trigger theresult
event for the action client.cancel
event: triggered when an action client cancels the the goal after a goal was sent to the action server but not completed yet.
The start()
method must be called to start the action server.
- Action client For the action client, the skeleton code is like this:
rclnodejs.init().then(() => {
const GoalStatus = rclnodejs.require('actionlib_msgs/msg/GoalStatus');
const ac = new rclnodejs.ActionClientInterface({
type: 'ros1_actions/msg/DoDishes',
actionServer: 'dishes',
rclnodejs: rclnodejs
});
let goal = ac.sendGoal({ goal: {dishwasher_id: 1}});
ac.on('feedback', (feedback) => {
// feedback handler
});
ac.on('status', (status) => {
status.status_list.forEach((s) =>{
if (s.goal_id.id === goal.goal_id.id &&
s.status === GoalStatus.SUCCEEDED) {
console.log(`The goal, whose id is ${s.goal_id.id}, has been executed successfully.`);
}
});
});
ac.on('result', (result) => {
// result handler
});
}).catch((err) => {
console.error(err);
});
To construct an action client, use new rclnodejs.ActionClientInterface()
. The action client can emit 3 type events:
status
event: triggered when the action server sends messages to the action client during the goal is executing.feedback
event: triggered after the action server calledpublishFeedback
.result
event: triggered after the action server calledsetSucceeded
.
Notice, the action state transitions must obey some specific order, for more details please refer to this article