SMACC2
Loading...
Searching...
No Matches
smacc_action_client_base.hpp
Go to the documentation of this file.
1// Copyright 2025 Robosoft Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15/*****************************************************************************************************************
16 *
17 * Authors: Pablo Inigo Blasco, Brett Aldrich
18 *
19 ******************************************************************************************************************/
20
21#pragma once
22
26
27#include <optional>
28#include <rclcpp_action/rclcpp_action.hpp>
29
30namespace smacc2
31{
32namespace client_bases
33{
34using namespace smacc2::default_events;
35
36template <typename ActionType>
38{
39public:
40 // Inside this macro you can find the typedefs for Goal and other types
41 typedef rclcpp_action::Client<ActionType> ActionClient;
42
43 using Goal = typename ActionClient::Goal;
44 using Feedback = typename ActionClient::Feedback;
45 using GoalHandle = rclcpp_action::ClientGoalHandle<ActionType>;
46 typedef typename GoalHandle::WrappedResult WrappedResult;
47
48 using SendGoalOptions = typename ActionClient::SendGoalOptions;
50 std::function<void(std::shared_future<typename GoalHandle::SharedPtr>)>;
51 using FeedbackCallback = typename GoalHandle::FeedbackCallback;
52 using ResultCallback = typename GoalHandle::ResultCallback;
53 using CancelRequest = typename ActionType::Impl::CancelGoalService::Request;
54 using CancelResponse = typename ActionType::Impl::CancelGoalService::Response;
55 using CancelCallback = std::function<void(typename CancelResponse::SharedPtr)>;
56
58
59 std::string action_endpoint_;
60 SmaccActionClientBase(std::string actionServerName) : ISmaccActionClient()
61 {
62 action_endpoint_ = actionServerName;
63 }
64
66
68
69 virtual std::shared_ptr<rclcpp_action::ClientBase> getClientBase() override { return client_; }
70
71 void onInitialize() override
72 {
73 if (name_ == "") name_ = smacc2::demangleSymbol(typeid(*this).name());
74 this->client_ = rclcpp_action::create_client<ActionType>(getNode(), action_endpoint_);
75 // RCLCPP_INFO_STREAM(
76 // this->getLogger(),
77 // "Waiting for action server '" << name_ << "' of type: " << demangledTypeName<ActionType>());
78 //client_->wait_for_action_server();
79 }
80
82 {
83 RCLCPP_INFO_STREAM(
84 this->getLogger(),
85 "Waiting for action server '" << name_ << "' of type: " << demangledTypeName<ActionType>());
86 client_->wait_for_action_server();
87 }
88
89 static std::string getEventLabel()
90 {
92 return type->getNonTemplatedTypeName();
93 }
94
95 std::optional<std::shared_future<typename GoalHandle::SharedPtr>> lastRequest_;
96 std::optional<std::shared_future<typename CancelResponse::SharedPtr>> lastCancelResponse_;
97
100 // SmaccActionResultSignal onPreempted_;
101 // SmaccActionResultSignal onRejected_;
103
104 // event creation/posting factory functions
105 std::function<void(WrappedResult)> postSuccessEvent;
106 std::function<void(WrappedResult)> postAbortedEvent;
107 std::function<void(WrappedResult)> postCancelledEvent;
108 // std::function<void(WrappedResult)> postPreemptedEvent;
109 // std::function<void(WrappedResult)> postRejectedEvent;
110
111 std::function<void(const Feedback &)> postFeedbackEvent;
112
114
115 template <typename EvType>
117 {
118 auto * ev = new EvType();
119 RCLCPP_INFO(
120 getLogger(), "Action client Posting EVENT %s", demangleSymbol(typeid(ev).name()).c_str());
121 this->postEvent(ev);
122 }
123
124 template <typename TOrthogonal, typename TSourceObject>
126 {
127 // we create here all the event factory functions capturing the TOrthogonal
128 postSuccessEvent = [this](auto msg)
130 postAbortedEvent = [this](auto msg)
132
133 postCancelledEvent = [this](auto msg)
135
136 postFeedbackEvent = [this](auto msg)
137 {
138 auto actionFeedbackEvent = new EvActionFeedback<Feedback, TOrthogonal>();
139 actionFeedbackEvent->client = this;
140 actionFeedbackEvent->feedbackMessage = msg;
141 this->postEvent(actionFeedbackEvent);
142 RCLCPP_DEBUG(getLogger(), "[%s] FEEDBACK EVENT", demangleType(typeid(*this)).c_str());
143 };
144
145 feedback_cb = [this](auto client, auto feedback) { this->onFeedback(client, feedback); };
146 }
147
148 template <typename T>
149 smacc2::SmaccSignalConnection onSucceeded(void (T::*callback)(WrappedResult &), T * object)
150 {
151 return this->getStateMachine()->createSignalConnection(onSucceeded_, callback, object);
152 }
153
154 template <typename T>
156 {
157 return this->getStateMachine()->createSignalConnection(onSucceeded_, callback);
158 }
159
160 template <typename T>
161 smacc2::SmaccSignalConnection onAborted(void (T::*callback)(WrappedResult &), T * object)
162 {
163 return this->getStateMachine()->createSignalConnection(onAborted_, callback, object);
164 }
165
166 template <typename T>
168 {
169 return this->getStateMachine()->createSignalConnection(onAborted_, callback);
170 }
171
172 template <typename T>
173 smacc2::SmaccSignalConnection onCancelled(void (T::*callback)(WrappedResult &), T * object)
174 {
175 return this->getStateMachine()->createSignalConnection(onCancelled_, callback, object);
176 }
177
178 template <typename T>
180 {
181 return this->getStateMachine()->createSignalConnection(onCancelled_, callback);
182 }
183
184 virtual bool cancelGoal() override
185 {
186 lastCancelResponse_ = this->client_->async_cancel_all_goals();
187
188 return true;
189 }
190
191 std::shared_future<typename GoalHandle::SharedPtr> sendGoal(
192 Goal & goal, typename SmaccActionResultSignal::WeakPtr resultCallback =
194 {
195 SendGoalOptions options;
196
197 options.feedback_callback = feedback_cb;
198
199 options.result_callback =
200 [this, resultCallback](
201 const typename rclcpp_action::ClientGoalHandle<ActionType>::WrappedResult & result)
202 {
203 RCLCPP_INFO_STREAM(
204 getLogger(), "[" << getName() << "] Action result callback, getting shared future");
205 RCLCPP_INFO_STREAM(
206 getLogger(), "[" << getName() << "] Action client Result goal id: "
207 << rclcpp_action::to_string(result.goal_id));
208
209 auto resultCallbackPtr = resultCallback.lock();
210
211 if (resultCallbackPtr != nullptr)
212 {
213 RCLCPP_INFO_STREAM(
214 getLogger(), "[" << getName() << "] Result CB calling user callback:"
215 << demangleSymbol(typeid(*resultCallbackPtr).name()));
216 (*resultCallbackPtr)(result);
217 }
218 else
219 {
220 RCLCPP_INFO_STREAM(
221 getLogger(), "[" << getName() << "] Result CB calling default callback");
222 this->onResult(result);
223 }
224 };
225
226 RCLCPP_INFO_STREAM(
227 getLogger(), "[" << getName() << "] client ready clients: "
228 << this->client_->get_number_of_ready_clients());
229 RCLCPP_INFO_STREAM(
230 getLogger(),
231 "[" << getName() << "] Waiting it is ready? " << client_->action_server_is_ready());
232
233 RCLCPP_INFO_STREAM(getLogger(), getName() << ": async send goal.");
234 auto lastRequest = this->client_->async_send_goal(goal, options);
235 this->lastRequest_ = lastRequest;
236
237 RCLCPP_INFO_STREAM(getLogger(), "[" << getName() << "] Action request");
238
239 return lastRequest;
240 }
241
242protected:
243 typename ActionClient::SharedPtr client_;
244
246 typename GoalHandle::SharedPtr /*goalhandle*/,
247 const std::shared_ptr<const Feedback> feedback_msg)
248 {
249 postFeedbackEvent(*feedback_msg);
250 }
251
252 void onResult(const WrappedResult & result_msg)
253 {
254 const auto & resultType = result_msg.code;
255
256 RCLCPP_INFO_STREAM(
257 getLogger(), "[" << this->getName() << "] response result ["
258 << rclcpp_action::to_string(result_msg.goal_id) << "]: " << (int)resultType);
259
260 if (resultType == rclcpp_action::ResultCode::SUCCEEDED)
261 {
262 RCLCPP_INFO(getLogger(), "[%s] request result: Success", this->getName().c_str());
263 onSucceeded_(result_msg);
264 postSuccessEvent(result_msg);
265 }
266 else if (resultType == rclcpp_action::ResultCode::ABORTED)
267 {
268 RCLCPP_INFO(getLogger(), "[%s] request result: Aborted", this->getName().c_str());
269 onAborted_(result_msg);
270 postAbortedEvent(result_msg);
271 }
272 else if (resultType == rclcpp_action::ResultCode::CANCELED)
273 {
274 RCLCPP_INFO(getLogger(), "[%s] request result: Cancelled", this->getName().c_str());
275 onCancelled_(result_msg);
276 postCancelledEvent(result_msg);
277 }
278 else
279 {
280 RCLCPP_INFO(
281 getLogger(), "[%s] request result: NOT HANDLED TYPE: %d", this->getName().c_str(),
282 (int)resultType);
283 }
284 }
285};
286
287} // namespace client_bases
288
289} // namespace smacc2
rclcpp::Node::SharedPtr getNode()
Definition client.cpp:60
ISmaccStateMachine * getStateMachine()
rclcpp::Logger getLogger()
smacc2::SmaccSignalConnection createSignalConnection(TSmaccSignal &signal, TMemberFunctionPrototype callback, TSmaccObjectType *object)
std::weak_ptr< SmaccSignal< void(const WrappedResult &), optional_last_value< typename boost::function_traits< void(const WrappedResult &)>::result_type >, int, std::less< int >, function< void(const WrappedResult &)>, typename extended_signature< function_traits< void(const WrappedResult &)>::arity, void(const WrappedResult &)>::function_type, boost::signals2::mutex > > WeakPtr
std::optional< std::shared_future< typename CancelResponse::SharedPtr > > lastCancelResponse_
typename ActionType::Impl::CancelGoalService::Response CancelResponse
typename ActionType::Impl::CancelGoalService::Request CancelRequest
std::function< void(typename CancelResponse::SharedPtr)> CancelCallback
typename ActionClient::SendGoalOptions SendGoalOptions
smacc2::SmaccSignalConnection onCancelled(std::function< void(WrappedResult &)> callback)
void onFeedback(typename GoalHandle::SharedPtr, const std::shared_ptr< const Feedback > feedback_msg)
smacc2::SmaccSignal< void(const WrappedResult &)> SmaccActionResultSignal
virtual std::shared_ptr< rclcpp_action::ClientBase > getClientBase() override
std::function< void(WrappedResult)> postCancelledEvent
smacc2::SmaccSignalConnection onSucceeded(void(T::*callback)(WrappedResult &), T *object)
std::function< void(WrappedResult)> postSuccessEvent
smacc2::SmaccSignalConnection onAborted(std::function< void(WrappedResult &)> callback)
smacc2::SmaccSignalConnection onCancelled(void(T::*callback)(WrappedResult &), T *object)
rclcpp_action::ClientGoalHandle< ActionType > GoalHandle
rclcpp_action::Client< ActionType > ActionClient
std::function< void(std::shared_future< typename GoalHandle::SharedPtr >)> GoalResponseCallback
std::function< void(WrappedResult)> postAbortedEvent
void onResult(const WrappedResult &result_msg)
std::function< void(const Feedback &)> postFeedbackEvent
std::shared_future< typename GoalHandle::SharedPtr > sendGoal(Goal &goal, typename SmaccActionResultSignal::WeakPtr resultCallback=typename SmaccActionResultSignal::WeakPtr())
smacc2::SmaccSignalConnection onAborted(void(T::*callback)(WrappedResult &), T *object)
smacc2::SmaccSignalConnection onSucceeded(std::function< void(WrappedResult &)> callback)
typename GoalHandle::ResultCallback ResultCallback
std::optional< std::shared_future< typename GoalHandle::SharedPtr > > lastRequest_
typename GoalHandle::FeedbackCallback FeedbackCallback
static TypeInfo::Ptr getTypeInfoFromType()
std::string demangleSymbol()
std::string demangledTypeName()
std::string demangleType(const std::type_info *tinfo)
boost::signals2::connection SmaccSignalConnection