0

I'm controlling a mobile robot and I'd like to set up an action (call it back_and_forth) that commands the robot to move forward 1 meter, then move backwards one meter. The interface that I'm using (iRobot create3 ROS 2 API) uses actions to handle movement commands, so I need to call one action (move forward 1m), wait for it to complete, and call another action (move backwards 1m) inside the callback of my own action back_and_forth.

I have found reference to a few approaches for doing this, but none of them seem to work:

  1. Use ActionClient.send_goal() to send the move forwards and backwards actions. If I do this, the node gets stuck on that line and never continues to the move backwards action.
  2. Use ActionClient.send_goal_async(), followed by rclpy.spin_until_future_complete(). But as the documentation says, the future resolves "when the goal request has been accepted or rejected", not when the action completes. So it doesn't wait for the forward action to complete before moving onto the next one.

Something like this answer may work, but seems extremely convoluted and hacky for what should be a simple functionality.

This whole thing begs a broader question: if we can't wait for things (i.e. rclpy.spin) inside a callback, how are we supposed to write a meaningful action server that calls other services, actions, etc. to get things done, and only returns success once they are done?

2 Answers 2

0

As I understand, for each user call to your back_and_forth action server it should in turn make two calls to iRobot API action server. This again is not very straight forward but you can try

  • In your back_and_forth server's handle_accepted callback you may create a new thread and give it an execute function and detach the thread.
  • Inside this function you can create & send a goal for api action server and also wait for its completion in a loop.
  • Once that's done you can create a new goal for backward motion and send it again.
  • You'll also need to pass along goal_handle to the execute function so that you may set the states of user action call from inside the execute function.

Another advise would be to keep your server side callbacks and client side callbacks in independent callback groups or they might end up blocking each other.

1
  • This is helpful, I will give it a shot. It's crazy to me that something so convoluted / handling threads manually is necessary. It seems like handling asynchronous events should be native and simple in ROS Commented Feb 28 at 17:23
0

Here is a Create3 client node which I wrote to call the undock action when the battery is 95% full and then call the /dock action when the battery gets very low. I think it demonstrates the "back and forth" function that you desire.

https://github.com/slowrunner/wali_pi5/blob/main/c3ws/src/wali/wali/wali_node.py

It sets up action clients for the dock, undock, and rotate_angle actions.

It sets up a subscriber to the battery state and dock status topics.

The Wali node sets up a one minute timer to call the wali_main_cb callback which implements a "state machine" (self.state variable {init, docked, undocking, undocked, docking ...}

When the state is init - Wali waits until all subscriptions have received at least one callback.

When the state is docked - Wali watches for the battery to be above 95%, then issues an undock action request and moves to the undocking state.

When the state is undocking - Wali is watches for the dock_state to be undocked and changes the state variable to undocked.

When the state is undocked - Wali watches the battery to be below 15%, then issues a rotate_angle action request (to turn so the dock is visible), and moves to the rotating state.

When the state is rotating - Wali watches for the dock to become visible and moves to the "ready_to_dock" state

When the state is "ready_to_dock", Wali watches for the battery to be below 10%, then issues the dock action request and changes the state variable to "docking"

When the state is "docking", Wali watches for the dock state to become docked, and sets the state to "docked".

Wali is back where it all started and managed his battery by himself.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.