-
Notifications
You must be signed in to change notification settings - Fork 329
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add README's for action_tutorials. (#576)
Co-authored-by: Audrow Nash <audrow@hey.com>
- Loading branch information
Showing
4 changed files
with
149 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# ROS2 Action Tutorials | ||
|
||
This tutorial demonstrates implementing ROS action servers and action clients. | ||
|
||
The action server in this case takes in an integer value between 0 and 45 named *order* and returns the Fibonacci sequence, a sequence with the form: | ||
$$F_0 = 0$$ | ||
$$F_1 = 1$$ | ||
$$F_{order}=F_{order-1} + F_{order-2}$$ | ||
|
||
The action server calculates each number in the sequence one at a time and returns a partial sequence as feedback at each iteration. | ||
If the action is cancelled before the entire sequence is calculated, the server stops calculating the sequence and no result is returned. | ||
The action client in this tutorial sends a goal to the action server with an order of 10. | ||
It logs each partial sequence returned as feedback. | ||
Once the action is finished executing, the action client logs the resulting sequence. | ||
|
||
## Packages | ||
|
||
- [action_tutorials_cpp](./action_tutorials_cpp) implements the described action server and client using the rclcpp library in C++. | ||
- [action_tutorials_py](./action_tutorials_py) implements the described action server and client using the rclpy library in Python. | ||
- [action_tutorials_interfaces](./action_tutorials_interfaces) defines the interface for the Fibonacci action. | ||
This interface takes an *order* as a goal, returns a *partial sequence* as feedback and a *sequence* as a result. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# Action Server | ||
|
||
In the constructor for `FibonacciActionServer`, an action server is created with callbacks that are called when a goal is received, when the goal is cancelled, and when the goal is accepted: | ||
|
||
```cpp | ||
this->action_server_ = rclcpp_action::create_server<Fibonacci>( | ||
... | ||
"fibonacci", | ||
std::bind(&FibonacciActionServer::handle_goal, this, _1, _2), | ||
std::bind(&FibonacciActionServer::handle_cancel, this, _1), | ||
std::bind(&FibonacciActionServer::handle_accepted, this, _1)); | ||
``` | ||
The `handle_goal` callback is called whenever a goal is sent to the action server by an action client. | ||
In the example code, the goal is accepted as long as the order is less than or equal to 46, otherwise it is rejected. | ||
This is to prevent potential [integer overflow](https://en.wikipedia.org/wiki/Integer_overflow): | ||
```cpp | ||
if (goal->order > 46) { | ||
return rclcpp_action::GoalResponse::REJECT; | ||
} | ||
return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE; | ||
``` | ||
|
||
The `handle_cancelled` callback is called whenever an action client requests to cancel the goal being executed. | ||
In this case, the goal cancel request is always accepted. | ||
|
||
The `handle_accepted` callback is called following the action server's acceptance of a goal. In this example, a thread is started to execute the goal: | ||
```cpp | ||
std::thread{std::bind(&FibonacciActionServer::execute, this, _1), goal_handle}.detach(); | ||
``` | ||
The execution thread calculates the Fibonacci sequence up to *order* and publishes partial sequences as feedback as each item is added to the sequence. | ||
A `rclcpp::Rate` object is used to sleep between the calculation of each item in order to represent a long-running task. | ||
When execution is complete, the full sequence is returned to the action client. | ||
If the goal is cancelled during execution, no result is returned, however the caller may have received partial sequences as feedback up until cancelling. | ||
# Action Client | ||
In the constructor for `FibonacciActionClient`, and action client for the `fibonacci` action is created: | ||
```cpp | ||
this->client_ptr_ = rclcpp_action::create_client<Fibonacci>( | ||
... | ||
"fibonacci"); | ||
``` | ||
|
||
A goal of type `Fibonacci` is created with order 10. | ||
The goal is sent asynchronously with callbacks registered for the goal response, the feedback, and the goal result: | ||
|
||
```cpp | ||
auto send_goal_options = rclcpp_action::Client<Fibonacci>::SendGoalOptions(); | ||
send_goal_options.goal_response_callback = | ||
std::bind(&FibonacciActionClient::goal_response_callback, this, _1); | ||
send_goal_options.feedback_callback = | ||
std::bind(&FibonacciActionClient::feedback_callback, this, _1, _2); | ||
send_goal_options.result_callback = | ||
std::bind(&FibonacciActionClient::result_callback, this, _1); | ||
this->client_ptr_->async_send_goal(goal_msg, send_goal_options); | ||
``` | ||
There are three types of callback functions: | ||
- The `goal_response_callback` is called when the action server accepts or rejects the goal. | ||
- The `feedback_callback` is called whenever the action server sends goal execution feedback. | ||
- The `goal_result_callback` is called when the action server is finished executing the goal and returns the result of the goal which is the full or partial Fibonacci sequence. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Action Tutorials ROS2 Interface | ||
|
||
This tutorial defines the Fibonacci action for use with the action tutorials. | ||
There are three parts of the action: | ||
|
||
- The goal contains an *order* field which determines the length of the returned Fibonacci sequence. | ||
For example, order 2 should return sequence [0, 1] and order 5 should return sequence [0, 1, 1, 2, 3]. | ||
- The feedback consists of a partial sequence that is returned as the Fibonacci sequence is calculated. | ||
For example, for order 5 at some point the partial sequence [0, 1, 1] will be returned. | ||
- The result consists of the complete Fibonacci sequence (ex. [0, 1, 1, 2, ..., 165580141]). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
# Action Server | ||
|
||
In the constructor for `FibonacciActionServer`, an action server is created with a callback that is called when a goal is accepted. | ||
```python | ||
self._action_server = ActionServer( | ||
self, | ||
Fibonacci, | ||
'fibonacci', | ||
self.execute_callback) | ||
``` | ||
|
||
There are three types of callbacks: | ||
|
||
- A `goal_callback` can optionally be added to conditionally accept or reject the goal, however, by default the goal is accepted. | ||
- A `cancel_callback` can also optionally be added to conditionally accept or reject the cancel goal request, however, by default the cancel goal request is accepted. | ||
- The `execute_callback` calculates the Fibonacci sequence up to *order* and publishes partial sequences as feedback as each item is added to the sequence. | ||
|
||
The thread sleeps for 1 second between the calculation of each item in order to represent a long-running task. | ||
When execution is complete, the full sequence is returned to the action client. | ||
|
||
# Action Client | ||
|
||
In the constructor for `FibonacciActionClient`, an action client for the `fibonacci` action is created: | ||
|
||
```python | ||
self._action_client = ActionClient(self, Fibonacci, 'fibonacci') | ||
``` | ||
|
||
A goal of type `Fibonacci` is created with order 10. | ||
The goal is sent asynchronously with callbacks registered for the goal response and the feedback: | ||
|
||
```python | ||
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) | ||
``` | ||
|
||
Within the `goal_response_callback`, if the goal is accepted, the goal result is requested asynchronously. | ||
A callback is registered for receiving the result: | ||
```python | ||
self._get_result_future = goal_handle.get_result_async() | ||
|
||
self._get_result_future.add_done_callback(self.get_result_callback) | ||
``` | ||
|
||
There are two types of callbacks: | ||
|
||
- The `feedback_callback` logs the partial sequences as they are received. | ||
- The `get_result_callback` logs the full Fibonacci sequence. |