Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issues when canceling and unadvertising actions #896

Merged
merged 3 commits into from
Dec 14, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

import rclpy
from rclpy.action import ActionServer
from rclpy.action.server import CancelResponse, ServerGoalHandle
from rclpy.callback_groups import ReentrantCallbackGroup
from rosbridge_library.capability import Capability
from rosbridge_library.internal import message_conversion
Expand Down Expand Up @@ -62,6 +63,7 @@ def __init__(
get_action_class(action_type),
action_name,
self.execute_callback,
cancel_callback=self.cancel_callback,
callback_group=ReentrantCallbackGroup(), # https://github.com/ros2/rclpy/issues/834#issuecomment-961331870
)

Expand All @@ -71,6 +73,7 @@ def next_id(self) -> int:
return id

async def execute_callback(self, goal: Any) -> Any:
"""Action server goal callback function."""
# generate a unique ID
goal_id = f"action_goal:{self.action_name}:{self.next_id()}"

Expand Down Expand Up @@ -103,6 +106,20 @@ def done_callback(fut: rclpy.task.Future()) -> None:
del self.goal_futures[goal_id]
del self.goal_handles[goal_id]

def cancel_callback(self, cancel_request: ServerGoalHandle) -> CancelResponse:
"""Action server cancel callback function."""
for goal_id, goal_handle in self.goal_handles.items():
if cancel_request.goal_id == goal_handle.goal_id:
self.protocol.log("warning", f"Canceling action {goal_id}")
self.goal_futures[goal_id].cancel()
cancel_message = {
"op": "cancel_action_goal",
"id": goal_id,
"action": self.action_name,
}
self.protocol.send(cancel_message)
return CancelResponse.ACCEPT

def handle_feedback(self, goal_id: str, feedback: Any) -> None:
"""
Called by the ActionFeedback capability to handle action feedback from the external client.
Expand Down Expand Up @@ -146,7 +163,10 @@ def graceful_shutdown(self) -> None:
for future_id in self.goal_futures:
future = self.goal_futures[future_id]
future.set_exception(RuntimeError(f"Action {self.action_name} was unadvertised"))
self.action_server.destroy()

# Uncommenting this, you may get a segfault.
# See https://github.com/ros2/rclcpp/issues/2163#issuecomment-1850925883
# self.action_server.destroy()


class AdvertiseAction(Capability):
Expand Down