-
Notifications
You must be signed in to change notification settings - Fork 225
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
Add Action Client #262
Add Action Client #262
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Partial review (I looked at tests). I'll start reviewing the implementation next.
I still have to implement the synchronous methods (meant to do that prior to this PR). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another partial review, this time for the C code. There are not as many comments as it seems, they're mostly repetitive.
With functions for creating and destroying action clients.
* Add boilerplate for send/take functions * Move common conversion function to shared header file (impl/convert.h) * Start implementing Waitable API * Add unit tests
Updated documentation and improved some error handling.
* Reset feedback member between each test * Used timed_spin() instead of spin_once()
* Better error handling * Move common typedef's to common.h * Return Python tuples from C functions instead of lists or custom Python object * Bugfix: pass Capsule objects for QoS profiles when creating an action client
523c403
to
b661737
Compare
rclpy/rclpy/action_client.py
Outdated
from unique_identifier_msgs.msg import UUID | ||
|
||
|
||
class ClientGoalHandle(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The C++ equivalent has a method to get a future for the goal result. Possible to implement that here?
rclpy/rclpy/action_client.py
Outdated
for seq, req_future in pending_requests.items(): | ||
if future == req_future: | ||
try: | ||
del pending_requests[seq] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is anything testing this? I would be surprised if it works since items()
is a generator in python 3. See this SO post. Maybe it needs a request after the one being deleted to to see an error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No explicit tests, but I tried a test sending multiple goals concurrently and still works. It would raise an exception, but the iteration stops on the first deletion because of the return statement below. Anyways, it's probably safer to cast the items to a list as suggested in the SO post.
We might consider doing the same for the service client code as well:
Lines 70 to 76 in 0fafaec
for seq, req_future in self._pending_requests.items(): | |
if future == req_future: | |
try: | |
del self._pending_requests[seq] | |
except KeyError: | |
pass | |
break |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cast to list: 04337c9
rclpy/rclpy/action_client.py
Outdated
|
||
return future | ||
|
||
def get_result(self, goal_handle): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would expect this method to only be on the goal_handle
, like is done in rclcpp_action
rclpy/rclpy/action_client.py
Outdated
|
||
return future | ||
|
||
def cancel_goal(self, goal_handle): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would expect this to be a method on the goal handle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In rclcpp_action
this is done via the action client:
But, I do agree that it is more intuitive to move this to the goal handle. Since the implementation is closely tied to the ActionClient, what do you think about leaving these here as hidden methods and providing a facade in GoalHandle?
Also, after looking at rclcpp, I realized I'm missing functions for "cancel all goals" and "cancel goals before".
Signed-off-by: Jacob Perron <[email protected]>
Signed-off-by: Jacob Perron <[email protected]>
Signed-off-by: Jacob Perron <[email protected]>
Signed-off-by: Jacob Perron <[email protected]>
Signed-off-by: Jacob Perron <[email protected]>
Now it acts as the users interface for canceling goals and getting goal results. Remove the unit tests specific to ClientGoalHandle since it is now closely coupled with the ActionClient and is sufficiently covered in the ActionClient unit tests. Signed-off-by: Jacob Perron <[email protected]>
@sloretz I've addressed all of your comments. I've hidden the Perhaps if we add the notion of a client goal handle to |
Signed-off-by: Jacob Perron <[email protected]>
Signed-off-by: Jacob Perron <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with green CI
Increased to 400 seconds. Signed-off-by: Jacob Perron <[email protected]>
This reverts commit b6c6ca8.
Signed-off-by: Jacob Perron <[email protected]>
I'm not sure why, but the multi-threaded test was timing out on CI machines. I've disabled it and opened an issue (#268) to come back to. |
* Add rclpy_action module With functions for creating and destroying action clients. * Implement action client * Move common conversion function and typedefs to shared header file (impl/common.h) * Add tests using mock action server * Add action module for aggregating action related submodules * Extend Waitable API so executors are aware of Futures * Move check_for_type_support() to its own module Signed-off-by: Jacob Perron <[email protected]>
* Add Action Client (#262) * Add rclpy_action module With functions for creating and destroying action clients. * Implement action client * Move common conversion function and typedefs to shared header file (impl/common.h) * Add tests using mock action server * Add action module for aggregating action related submodules * Extend Waitable API so executors are aware of Futures * Move check_for_type_support() to its own module Signed-off-by: Jacob Perron <[email protected]> * Fix Executor not executing tasks if there are no ready entities in the wait set (#272) If a task is created, then trigger the Executors guard condition. This will wake any blocking call to `rcl_wait()`. In this scenario, no work is yielded, so we also have to move the check for 'in-progress' tasks into the wait loop. Added a unit test to reproduce the issue. This resolves an issue in some cases where the result response from the action server is never processed, therefore never reaching the action client. Signed-off-by: Jacob Perron <[email protected]> * Fix Node's reference to executor (#275) Previously, if a `Node` was added to an `Executor` using the executors `add_node` method, then nodes `executor` property would return `None`. Signed-off-by: Jacob Perron <[email protected]> * Abstract type conversions into functions (#269) * Abstract type conversions into functions This helps with readability and maintainability. Also eliminated use of assertions during conversions, defering to exceptions. * Move common C functions to a shared library 'rclpy_common' Signed-off-by: Jacob Perron <[email protected]> * Add ActionServer (#270) * Add Action server functions to extension module * Separated service related macros into separate request and response calls * Add server goal handle functions to extension module * Update Action extension module to use conversion functions * Add implementation of Python ActionServer * Handles goal and cancel requests, responds, and calls user-defined functions for executing goals. * Handle result requests * Handle expired goals * Publish goal status array and feedback * Add `handle_accepted_callback` to ActionServer Upon accepting a goal, the provided `handle_accepted_callback` is called with a reference to the goal handle. The user can then decide to execute the goal or defer. If `handle_accepted_callback` is not provided, then the default behavior is to execute the goal handle immediately. Signed-off-by: Jacob Perron <[email protected]> * Enable test using MultiThreadedExecutor (#280) Signed-off-by: Jacob Perron <[email protected]> * Guard against failed take when taking action messages (#281) Some middlewares (e.g. Connext and OpenSplice) send invalid messages to indicate an instance has been disposed which results in a 'failed take'. Signed-off-by: Jacob Perron <[email protected]>
Connects to #257
_rclpy_action
extension module for interfacingrcl_action
library andrclpy
I still need to go through and update the code documentation and perhaps add some more unit tests.