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

Make sure robot.cancel_actions will return #314

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

robin-mueller
Copy link
Contributor

@robin-mueller robin-mueller commented Dec 25, 2024

Currently, the Robot.cancel_actions() method will wait for the Robot.canceling_execution flag becoming False indefinitely when Robot.execute_action() fails to set self.executing_action = False before Robot.cancel_actions() (e.g. running in a separate thread) checks that in the if statement.

if self.executing_action or self.executing_plan:
self.canceling_execution = True
while self.canceling_execution:
time.sleep(0.1)

This is because Robot.canceling_execution is only updated by Robot.execute_plan() and not Robot.execute_action().

In this PR I suggest an alternative function design for canceling actions as well as plans using Robot.cancel_actions() that ensures it will complete when the respective execution callback returns.

self.path_executor.cancel_execution = True
while self.executing_nav:
if self.executing_action:
if self.executing_nav and self.path_executor is not None:
Copy link
Owner

@sea-bass sea-bass Dec 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there are cases in which self.executing_action is false but self.executing_nav is true.

Basically, there are actions that can directly tell a robot to follow a path without going through the high-level action interface.

It essentially involves running Robot.follow_path() directly:

Which is done here:

def robot_path_follow_callback(self, goal_handle, robot=None):

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, I wasn't thinking of that. So is it better to add self.canceling_execution = False to the end of Robot.execute_actions()?

Since Robot.cancel_actions() is executed within a separate thread when using the ROS interface, it's difficult to make sure that self.canceling_execution is set to True before the execution callback resets the flag to False. If the cancellation thread does this after the execution callback performs self.canceling_execution = False, we enter an infinite loop.

Copy link
Owner

@sea-bass sea-bass left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes look good now.

Agree with you that cancellation is not thread safe, so there could be weird timing.

Maybe one easy, but not too hacky, option is to have a blocking version of cancellation (as is done now) for use outside ROS, and one that is not blocking which just sets a boolean value and returns immediately. So no infinitely running thread.

@robin-mueller
Copy link
Contributor Author

robin-mueller commented Dec 26, 2024

Probably an async cancellation method would be nice to have yes, but I guess cancel_actions would be thread safe with this PR since the cancellation flags are set properly now.

At least the modified test and my application work correctly.

The crucial change is that cancel_actions now only waits for the respective flag if it hasn't been set before by another thread (e.g. the execution thread). I assume that with python's interpreter lock, checking a boolean flag can be considered thread safe.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants