Skip to content

Commit b6e918a

Browse files
committed
new version
1 parent 4acabf6 commit b6e918a

File tree

5 files changed

+120
-260
lines changed

5 files changed

+120
-260
lines changed

README.md

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22

33
This wrap uses the spin of an executor in a new thread. As a result, the calls of services and actions can be used synchronously. Besides, this node also includes predefined action servers and one client to make its use more user-friendly to developers.
44

5-
65
## Examples
76

87
### Node
98

10-
This example shows how to create a node. To block the node, ```join_spin``` is used, which blocks the main thread till the thread of the spin ends.
9+
This example shows how to create a node. To block the node, `join_spin` is used, which blocks the main thread till the thread of the spin ends.
1110

1211
```python
1312
from simple_node import Node
@@ -17,13 +16,10 @@ class MyNode(Node):
1716
def __init__(self):
1817
super().__init__("my_node")
1918

20-
def main(args=None):
21-
rclpy.init(args=args)
22-
19+
def main():
20+
rclpy.init()
2321
node = MyNode()
24-
2522
node.join_spin()
26-
2723
rclpy.shutdown()
2824

2925

simple_node/include/simple_node/actions/action_client.hpp

Lines changed: 57 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,30 @@
1616
#ifndef ACTION_CLIENT_HPP
1717
#define ACTION_CLIENT_HPP
1818

19-
#include <chrono>
20-
#include <future>
19+
#include <condition_variable>
2120
#include <memory>
2221
#include <string>
23-
#include <thread>
2422

2523
#include "rclcpp/rclcpp.hpp"
2624
#include "rclcpp_action/client_goal_handle.hpp"
2725
#include "rclcpp_action/rclcpp_action.hpp"
2826

29-
#include <action_msgs/msg/goal_status.hpp>
27+
using namespace std::placeholders;
3028

3129
namespace simple_node {
3230
namespace actions {
3331

3432
template <typename ActionT>
3533
class ActionClient : public rclcpp_action::Client<ActionT> {
3634

37-
using Goal = typename ActionT::Goal;
38-
using Feedback = typename ActionT::Feedback;
35+
using SendGoalOptions =
36+
typename rclcpp_action::Client<ActionT>::SendGoalOptions;
3937
using GoalHandle = rclcpp_action::ClientGoalHandle<ActionT>;
38+
39+
using Goal = typename ActionT::Goal;
4040
using Result = typename GoalHandle::Result::SharedPtr;
41+
42+
using Feedback = typename ActionT::Feedback;
4143
using FeedbackCallback = std::function<void(
4244
typename GoalHandle::SharedPtr, const std::shared_ptr<const Feedback>)>;
4345

@@ -48,172 +50,113 @@ class ActionClient : public rclcpp_action::Client<ActionT> {
4850
node->get_node_base_interface(), node->get_node_graph_interface(),
4951
node->get_node_logging_interface(), action_name) {
5052

51-
this->status = action_msgs::msg::GoalStatus::STATUS_UNKNOWN;
53+
this->result = nullptr;
54+
this->status = rclcpp_action::ResultCode::UNKNOWN;
5255

5356
this->goal_handle = nullptr;
54-
this->goal_thread = nullptr;
55-
this->result = nullptr;
5657
this->feedback_cb = feedback_cb;
5758
}
5859

59-
~ActionClient() { delete this->goal_thread; }
60+
~ActionClient() {}
6061

61-
void wait_for_result() { this->goal_thread->join(); }
62+
void wait_for_result() {
63+
std::unique_lock<std::mutex> lock(this->action_done_mutex);
64+
this->action_done_cond.wait(lock);
65+
}
6266

6367
Result get_result() { return this->result; }
6468

6569
void send_goal(Goal goal, FeedbackCallback feedback_cb = nullptr) {
6670

71+
this->result = nullptr;
72+
this->set_status(rclcpp_action::ResultCode::UNKNOWN);
73+
6774
FeedbackCallback _feedback_cb = this->feedback_cb;
6875

6976
if (feedback_cb != nullptr) {
7077
_feedback_cb = feedback_cb;
7178
}
7279

73-
this->set_status(action_msgs::msg::GoalStatus::STATUS_UNKNOWN);
74-
this->goal_thread =
75-
new std::thread(&ActionClient::_send_goal, this, goal, _feedback_cb);
80+
auto send_goal_options = SendGoalOptions();
81+
82+
send_goal_options.goal_response_callback =
83+
std::bind(&ActionClient::goal_response_callback, this, _1);
84+
85+
send_goal_options.result_callback =
86+
std::bind(&ActionClient::result_callback, this, _1);
87+
88+
send_goal_options.feedback_callback = _feedback_cb;
89+
90+
this->async_send_goal(goal, send_goal_options);
7691
}
7792

78-
bool cancel_goal() {
79-
if (this->goal_handle != nullptr) {
80-
return this->_cancel_goal();
81-
} else {
82-
return false;
93+
void cancel_goal() {
94+
std::lock_guard<std::mutex> lock(this->goal_handle_mutex);
95+
if (this->goal_handle) {
96+
this->async_cancel_goal(this->goal_handle);
8397
}
8498
}
8599

86100
// **************
87101
// STATUS
88102
// **************
89-
int8_t get_status() {
103+
rclcpp_action::ResultCode get_status() {
90104
const std::lock_guard<std::mutex> lock(this->status_mtx);
91105
return this->status;
92106
}
93107

94-
bool is_accepted() {
95-
return this->get_status() == action_msgs::msg::GoalStatus::STATUS_ACCEPTED;
96-
}
97-
98-
bool is_executing() {
99-
return this->get_status() == action_msgs::msg::GoalStatus::STATUS_EXECUTING;
100-
}
101-
102-
bool is_canceling() {
103-
return this->get_status() == action_msgs::msg::GoalStatus::STATUS_CANCELING;
104-
}
105-
106108
bool is_succeeded() {
107-
return this->get_status() == action_msgs::msg::GoalStatus::STATUS_SUCCEEDED;
109+
return this->get_status() == rclcpp_action::ResultCode::SUCCEEDED;
108110
}
109111

110112
bool is_canceled() {
111-
return this->get_status() == action_msgs::msg::GoalStatus::STATUS_CANCELED;
113+
return this->get_status() == rclcpp_action::ResultCode::CANCELED;
112114
}
113115

114116
bool is_aborted() {
115-
return this->get_status() == action_msgs::msg::GoalStatus::STATUS_ABORTED;
117+
return this->get_status() == rclcpp_action::ResultCode::ABORTED;
116118
}
117119

118120
bool is_working() {
119-
return (this->is_executing() || this->is_canceling() ||
120-
this->is_accepted());
121+
return !this->is_terminated() &&
122+
this->get_status() != rclcpp_action::ResultCode::UNKNOWN;
121123
}
122124

123125
bool is_terminated() {
124126
return (this->is_succeeded() || this->is_canceled() || this->is_aborted());
125127
}
126128

127129
private:
128-
int8_t status;
129-
std::mutex status_mtx;
130-
std::thread *goal_thread;
130+
std::condition_variable action_done_cond;
131+
std::mutex action_done_mutex;
132+
131133
Result result;
134+
rclcpp_action::ResultCode status;
135+
std::mutex status_mtx;
136+
132137
std::shared_ptr<GoalHandle> goal_handle;
138+
std::mutex goal_handle_mutex;
139+
133140
FeedbackCallback feedback_cb;
134141

135-
void set_status(int8_t status) {
142+
void set_status(rclcpp_action::ResultCode status) {
136143
const std::lock_guard<std::mutex> lock(this->status_mtx);
137144
this->status = status;
138145
}
139146

140-
void _send_goal(Goal goal, FeedbackCallback feedback_cb) {
141-
142-
this->result = nullptr;
143-
144-
auto send_goal_options =
145-
typename rclcpp_action::Client<ActionT>::SendGoalOptions();
146-
send_goal_options.feedback_callback = feedback_cb;
147-
148-
auto send_goal_future = this->async_send_goal(goal, send_goal_options);
149-
150-
// wait for acceptance
151-
while (send_goal_future.wait_for(std::chrono::seconds(1)) !=
152-
std::future_status::ready) {
153-
}
154-
155-
// check acceptance
156-
this->goal_handle = send_goal_future.get();
157-
if (!this->goal_handle) {
158-
159-
// change status
160-
if (this->is_canceled()) {
161-
return;
162-
}
163-
this->set_status(action_msgs::msg::GoalStatus::STATUS_ABORTED);
164-
return;
165-
}
166-
167-
// change status
168-
if (this->is_canceled()) {
169-
return;
170-
}
171-
this->set_status(action_msgs::msg::GoalStatus::STATUS_ACCEPTED);
172-
173-
// get result
174-
auto get_result_future = this->async_get_result(this->goal_handle);
175-
176-
// change status
177-
if (this->is_canceled()) {
178-
return;
179-
}
180-
this->set_status(action_msgs::msg::GoalStatus::STATUS_EXECUTING);
181-
182-
// wait for result
183-
while (get_result_future.wait_for(std::chrono::seconds(1)) !=
184-
std::future_status::ready) {
185-
}
186-
187-
// change status
188-
if (this->is_canceled()) {
189-
return;
190-
}
191-
192-
this->set_status((uint8_t)get_result_future.get().code);
193-
this->result = get_result_future.get().result;
147+
void
148+
goal_response_callback(const typename GoalHandle::SharedPtr &goal_handle) {
149+
std::lock_guard<std::mutex> lock(this->goal_handle_mutex);
150+
this->goal_handle = goal_handle;
194151
}
195152

196-
bool _cancel_goal() {
197-
int8_t old_status = this->get_status();
198-
199-
auto cancel_goal_future = this->async_cancel_goal(this->goal_handle);
200-
this->set_status(action_msgs::msg::GoalStatus::STATUS_CANCELING);
201-
202-
while (cancel_goal_future.wait_for(std::chrono::seconds(1)) !=
203-
std::future_status::ready) {
204-
}
205-
206-
auto result = cancel_goal_future.get();
207-
if (result->goals_canceling.size() == 0) {
208-
this->set_status(old_status);
209-
return false;
210-
}
211-
212-
this->set_status(action_msgs::msg::GoalStatus::STATUS_CANCELED);
213-
214-
return true;
153+
void result_callback(const typename GoalHandle::WrappedResult &result) {
154+
this->result = result.result;
155+
this->set_status(result.code);
156+
this->action_done_cond.notify_one();
215157
}
216158
};
159+
217160
} // namespace actions
218161
} // namespace simple_node
219162
#endif

simple_node/include/simple_node/actions/action_server.hpp

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -118,23 +118,6 @@ class ActionServer : public rclcpp_action::Server<ActionT> {
118118

119119
void handle_execute(const std::shared_ptr<GoalHandle> goal_handle) {
120120

121-
(void)goal_handle;
122-
123-
std::thread(std::bind(&ActionServer::execute, this)).detach();
124-
125-
while (this->goal_handle != nullptr) {
126-
if (this->goal_handle->is_canceling()) {
127-
128-
if (this->cancel_callback != nullptr) {
129-
this->cancel_callback();
130-
}
131-
break;
132-
}
133-
std::this_thread::sleep_for(std::chrono::seconds(1));
134-
}
135-
}
136-
137-
void execute() {
138121
this->execute_callback(this->goal_handle);
139122
this->goal_handle = nullptr;
140123
}

0 commit comments

Comments
 (0)