How to Reject an Action Goal
I recently started to learn ROS and I have trouble Rejecting an Action Goal.
In a nutshell: when the goal_callback function in the Action Server returns GoalResponse.REJECT, instead of GoalResponse.ACCEPT, the Action Client hangs.
More details:
ROS2 Humble distro on ubuntu 20.04 in docker container on Raspberry Pi 4B.
Using the Action example in the ROS2 repository : code
commands to run the server and client nodes
ros2 run examples_rclpy_minimal_action_server server ros2 run examples_rclpy_minimal_action_client client
both client and server nodes behave as expected: After the goal successfully completes, the client node is destroyed and I can rerun the client command in the same terminal window. The server node keeps running and successfully handles subsequent client goal requests.
when I modify the goal_callback function in the server.py file from
def goal_callback(self, goal_request): ... return GoalResponse.ACCEPT
to
def goal_callback(self, goal_request): ... return GoalResponse.REJECT
the action server continues to work as expected, and the action client prints 'Goal rejected :(' in the terminal window as expected, BUT the action client node is not destroyed.
ros2 node list
shows that the client node as alive. Also the terminal window used to run the client does not return the prompt.
Questions:
- What does the "return GoalResponse.REJECT" in the goal_callback function trigger ?
- How do I modify the action client code to destroy the client node once the goal is rejected ?
Following are the action client and action server code:
from action_msgs.msg import GoalStatus from example_interfaces.action import Fibonacci import rclpy from rclpy.action import ActionClient from rclpy.node import Node class MinimalActionClient(Node): def __init__(self): super().__init__('minimal_action_client') self._action_client = ActionClient(self, Fibonacci, 'fibonacci') def goal_response_callback(self, future): goal_handle = future.result() if not goal_handle.accepted: self.get_logger().info('Goal rejected :(') return self.get_logger().info('Goal accepted :)') self._get_result_future = goal_handle.get_result_async() self._get_result_future.add_done_callback(self.get_result_callback) def feedback_callback(self, feedback): self.get_logger().info('Received feedback: {0}'.format(feedback.feedback.sequence)) def get_result_callback(self, future): result = future.result().result status = future.result().status if status == GoalStatus.STATUS_SUCCEEDED: self.get_logger().info('Goal succeeded! Result: {0}'.format(result.sequence)) else: self.get_logger().info('Goal failed with status: {0}'.format(status)) # Shutdown after receiving a result rclpy.shutdown() def send_goal(self): self.get_logger().info('Waiting for action server...') self._action_client.wait_for_server() goal_msg = Fibonacci.Goal() goal_msg.order = 10 self.get_logger().info('Sending goal request...') self._send_goal_future = self._action_client.send_goal_async( goal_msg, feedback_callback=self.feedback_callback) self._send_goal_future.add_done_callback(self.goal_response_callback) def main(args=None): rclpy.init(args=args) action_client = MinimalActionClient() action_client.send_goal() rclpy.spin(action_client) if __name__ == '__main__': main()
.
import time from example_interfaces.action import Fibonacci import rclpy from rclpy.action import ActionServer, CancelResponse, GoalResponse from rclpy.callback_groups import ReentrantCallbackGroup from rclpy.executors import MultiThreadedExecutor from rclpy.node import Node class MinimalActionServer(Node): def __init__(self): super().__init__('minimal_action_server') self._action_server = ActionServer( self, Fibonacci, 'fibonacci', execute_callback=self.execute_callback, callback_group=ReentrantCallbackGroup(), goal_callback=self.goal_callback, cancel_callback=self.cancel_callback) def destroy(self): self._action_server.destroy() super().destroy_node() def goal_callback(self, goal_request): """Accept or reject a client request to begin an ...
I have a similar problem but with RCLCPP, following this question