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
3129namespace simple_node {
3230namespace actions {
3331
3432template <typename ActionT>
3533class 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
127129private:
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
0 commit comments