Robotics StackExchange | Archived questions

Easy way to cancel a ROS2 action

For quick testing, what's the easiest way to cancel a ROS2 action? Preferably something that I can run external to my program, without having to hack its source code.

It looks like rclpy does not have a way to cancel an action without having a goal handle. https://github.com/ros2/rclpy/blob/master/rclpy/rclpy/action/client.py So we can rule out Python.

I don't see a command line option.

The best I have so far is this C++ script. It goes with the examples here.

#include "example_interfaces/action/fibonacci.hpp"

#include "rclcpp/rclcpp.hpp"
#include "rclcpp_action/rclcpp_action.hpp"

namespace {
  using Fibonacci = example_interfaces::action::Fibonacci;
}

int main(int argc, char ** argv)
{
  rclcpp::init(argc, argv);
  rclcpp::NodeOptions node_options;
  auto node = rclcpp::Node::make_shared("action_server_cancellation", "", node_options);

rclcpp_action::Client<Fibonacci>::SharedPtr client_ptr = rclcpp_action::create_client<Fibonacci>(node, "fibonacci");
  if (!client_ptr->wait_for_action_server(std::chrono::seconds(5))) {
    RCLCPP_ERROR(node->get_logger(), "Action server not available after waiting");
    rclcpp::shutdown();
  }
  client_ptr->async_cancel_all_goals();
  RCLCPP_ERROR(node->get_logger(), "Cancellation was requested.");

  rclcpp::spin(node);
  rclcpp::shutdown();
  return 0;
}

Asked by AndyZe on 2022-05-24 10:57:02 UTC

Comments

So .. what's your question?

Asked by gvdhoorn on 2022-05-24 12:08:45 UTC

vaguely hoping there is an easier way while realizing that the ROS2 default implementation is a memory violation ;)

But maybe this will be useful to other people

Asked by AndyZe on 2022-05-24 12:11:22 UTC

Answers

Tbh, personally I find it really weird a random client can cancel all goals currently being processed by an action server, but it appears it's part of the service spec (from here):

# Cancel one or more goals with the following policy:
#
# - If the goal ID is zero and timestamp is zero, cancel all goals.
# - If the goal ID is zero and timestamp is not zero, cancel all goals accepted
#   at or before the timestamp.
# - If the goal ID is not zero and timestamp is zero, cancel the goal with the
#   given ID regardless of the time it was accepted.
# - If the goal ID is not zero and timestamp is not zero, cancel the goal with
#   the given ID and all goals accepted at or before the timestamp.

I've not checked it, but from the documentation, it would appear submitting a new goal with ID 0 and stamp 0 would result in all goals getting cancelled (this is actually how async_cancel_all_goals(..) is implemented.

You might even be able to achieve the same thing by invoking the (hidden) service which is used to submit goals directly.

That should be doable using ros2 service ....

Asked by gvdhoorn on 2022-05-24 12:29:16 UTC

Comments

Thanks for the answer. I'll try it soon.

Tbh, personally I find it really weird a random client can cancel all goals

^I like this. It is nice for things like protective stops, where you just want to stop whatever's running.

Asked by AndyZe on 2022-05-24 14:34:51 UTC

Without any additional authentication or authorisation, this makes it trivial to implement a DoS attack against action servers, from any client (if it works as the documentation implies it does).

It is nice for things like protective stops, where you just want to stop whatever's running.

as long as you're not using it for actual safety-related purposes.

Asked by gvdhoorn on 2022-05-25 02:01:05 UTC

Did it work?

Asked by gvdhoorn on 2022-05-25 09:02:35 UTC

I haven't thoroughly tested it because filling out an action request from command line in ROS2 is burdensome. Tab-complete doesn't work. I'm sure it would work but the C++ executable is almost easier.

Asked by AndyZe on 2022-05-25 09:12:55 UTC

I'm confused. Action goals are submitted using a service.

The idea would be to invoke that service directly.

Not to construct a goal.

Asked by gvdhoorn on 2022-05-25 09:23:00 UTC

@AndyZe

To find your <service-name>: ros2 node info <your-action-server-node> --include-hidden

To cancel all goals: ros2 service call <service-name> action_msgs/srv/CancelGoal

The <service-name> should look something like that: <node-name>/_action/cancel_goal

Asked by tnajjar on 2022-08-29 08:00:37 UTC