SMACC2
Loading...
Searching...
No Matches
cp_nav2_action_interface.hpp
Go to the documentation of this file.
1// Copyright 2024 RobosoftAI 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#pragma once
16
17#include <geometry_msgs/msg/pose_stamped.hpp>
18#include <nav2_msgs/action/navigate_to_pose.hpp>
20#include <smacc2/component.hpp>
22
23#include <functional>
24#include <future>
25
26namespace cl_nav2z
27{
28namespace components
29{
30
32{
33public:
34 // Type aliases for convenience
35 using ActionType = nav2_msgs::action::NavigateToPose;
36 using Goal = ActionType::Goal;
37 using Result = ActionType::Result;
38 using Feedback = ActionType::Feedback;
39 using GoalHandle = rclcpp_action::ClientGoalHandle<ActionType>;
40 using WrappedResult = typename GoalHandle::WrappedResult;
42
43 // Nav2-specific signals for external subscribers
48
49 // Nav2-specific event posting functions (set during orthogonal allocation)
50 std::function<void(const WrappedResult &)> postNavigationSuccessEvent;
51 std::function<void(const WrappedResult &)> postNavigationAbortedEvent;
52 std::function<void(const WrappedResult &)> postNavigationCancelledEvent;
53 std::function<void(const Feedback &)> postNavigationFeedbackEvent;
54
56 virtual ~CpNav2ActionInterface() = default;
57
58 // Public API for behaviors and other components
59 std::shared_future<typename GoalHandle::SharedPtr> sendNavigationGoal(
60 const geometry_msgs::msg::PoseStamped & target)
61 {
62 if (!actionClient_)
63 {
64 RCLCPP_ERROR(getLogger(), "[CpNav2ActionInterface] Action client not available!");
65 throw std::runtime_error("Action client not initialized");
66 }
67
68 auto goal = createNavigationGoal(target);
69
70 RCLCPP_INFO_STREAM(
71 getLogger(), "[CpNav2ActionInterface] Sending navigation goal to: "
72 << "x=" << target.pose.position.x << ", y=" << target.pose.position.y
73 << ", frame=" << target.header.frame_id);
74
75 return actionClient_->sendGoal(goal);
76 }
77
78 std::shared_future<typename GoalHandle::SharedPtr> sendGoal(Goal & goal)
79 {
80 if (!actionClient_)
81 {
82 RCLCPP_ERROR(getLogger(), "[CpNav2ActionInterface] Action client not available!");
83 throw std::runtime_error("Action client not initialized");
84 }
85
86 return actionClient_->sendGoal(goal);
87 }
88
90 {
91 if (!actionClient_)
92 {
93 RCLCPP_WARN(getLogger(), "[CpNav2ActionInterface] Action client not available for cancel!");
94 return false;
95 }
96
97 RCLCPP_INFO(getLogger(), "[CpNav2ActionInterface] Cancelling navigation goal");
98 return actionClient_->cancelGoal();
99 }
100
102
104 {
105 if (actionClient_)
106 {
108 }
109 }
110
111 // Component lifecycle
112 template <typename TOrthogonal, typename TSourceObject>
114 {
115 // Require the underlying action client component
117
118 // Set up nav2-specific event posting functions
119 postNavigationSuccessEvent = [this](const WrappedResult & result)
120 {
122 this->postEvent(ev);
123 };
124
125 postNavigationAbortedEvent = [this](const WrappedResult & result)
126 {
128 this->postEvent(ev);
129 };
130
131 postNavigationCancelledEvent = [this](const WrappedResult & result)
132 {
134 this->postEvent(ev);
135 };
136
137 postNavigationFeedbackEvent = [this](const Feedback & feedback)
138 {
140 ev->feedbackMessage = feedback;
141 this->postEvent(ev);
142 };
143
144 RCLCPP_INFO(getLogger(), "[CpNav2ActionInterface] Component initialized");
145 }
146
147 void onInitialize() override
148 {
149 // Wire up signal connections from action client to nav2-specific signals
150 if (actionClient_)
151 {
152 // Connect action client signals to our nav2-specific signals and event posting using method pointers
157
158 RCLCPP_INFO(getLogger(), "[CpNav2ActionInterface] Signal connections established");
159 }
160 else
161 {
162 RCLCPP_ERROR(
163 getLogger(), "[CpNav2ActionInterface] Action client not found during initialization!");
164 }
165 }
166
167 // Signal connection methods for external subscribers
168 template <typename T>
169 boost::signals2::connection onNavigationSucceeded(
170 void (T::*callback)(const WrappedResult &), T * object)
171 {
173 onNavigationSucceeded_, callback, object);
174 }
175
176 template <typename T>
177 boost::signals2::connection onNavigationAborted(
178 void (T::*callback)(const WrappedResult &), T * object)
179 {
180 return this->getStateMachine()->createSignalConnection(onNavigationAborted_, callback, object);
181 }
182
183 template <typename T>
184 boost::signals2::connection onNavigationCancelled(
185 void (T::*callback)(const WrappedResult &), T * object)
186 {
188 onNavigationCancelled_, callback, object);
189 }
190
191 template <typename T>
192 boost::signals2::connection onNavigationFeedback(
193 void (T::*callback)(const Feedback &), T * object)
194 {
195 return this->getStateMachine()->createSignalConnection(onNavigationFeedback_, callback, object);
196 }
197
198 // Access to underlying action client for advanced usage
200
201private:
203
204 // Event translation callbacks
206 {
207 RCLCPP_INFO(getLogger(), "[CpNav2ActionInterface] Navigation succeeded");
210 {
212 }
213 }
214
216 {
217 RCLCPP_WARN(getLogger(), "[CpNav2ActionInterface] Navigation aborted");
218 onNavigationAborted_(result);
220 {
222 }
223 }
224
226 {
227 RCLCPP_INFO(getLogger(), "[CpNav2ActionInterface] Navigation cancelled");
230 {
232 }
233 }
234
235 void onNavigationFeedback(const Feedback & feedback)
236 {
237 RCLCPP_DEBUG(getLogger(), "[CpNav2ActionInterface] Navigation feedback received");
238 onNavigationFeedback_(feedback);
240 {
242 }
243 }
244
245 // Nav2-specific goal construction
246 Goal createNavigationGoal(const geometry_msgs::msg::PoseStamped & target)
247 {
248 Goal goal;
249 goal.pose = target;
250
251 // Set default behavior_tree if not specified
252 if (goal.behavior_tree.empty())
253 {
254 goal.behavior_tree = ""; // Let Nav2 use default behavior tree
255 }
256
257 return goal;
258 }
259};
260
261} // namespace components
262} // namespace cl_nav2z
void onNavigationSuccess(const WrappedResult &result)
std::function< void(const Feedback &)> postNavigationFeedbackEvent
smacc2::SmaccSignal< void(const WrappedResult &)> onNavigationCancelled_
std::function< void(const WrappedResult &)> postNavigationSuccessEvent
smacc2::SmaccSignal< void(const WrappedResult &)> onNavigationSucceeded_
smacc2::SmaccSignal< void(const WrappedResult &)> onNavigationAborted_
Goal createNavigationGoal(const geometry_msgs::msg::PoseStamped &target)
void onNavigationCancelled(const WrappedResult &result)
boost::signals2::connection onNavigationCancelled(void(T::*callback)(const WrappedResult &), T *object)
smacc2::SmaccSignal< void(const Feedback &)> onNavigationFeedback_
boost::signals2::connection onNavigationSucceeded(void(T::*callback)(const WrappedResult &), T *object)
std::shared_future< typename GoalHandle::SharedPtr > sendGoal(Goal &goal)
std::shared_future< typename GoalHandle::SharedPtr > sendNavigationGoal(const geometry_msgs::msg::PoseStamped &target)
std::function< void(const WrappedResult &)> postNavigationCancelledEvent
void onNavigationAborted(const WrappedResult &result)
rclcpp_action::ClientGoalHandle< ActionType > GoalHandle
boost::signals2::connection onNavigationFeedback(void(T::*callback)(const Feedback &), T *object)
std::function< void(const WrappedResult &)> postNavigationAbortedEvent
boost::signals2::connection onNavigationAborted(void(T::*callback)(const WrappedResult &), T *object)
void requiresComponent(TComponent *&requiredComponentStorage, bool throwExceptionIfNotExist=false)
ISmaccStateMachine * getStateMachine()
rclcpp::Logger getLogger() const
boost::signals2::connection createSignalConnection(TSmaccSignal &signal, TMemberFunctionPrototype callback, TSmaccObjectType *object)
boost::signals2::connection onSucceeded(void(T::*callback)(const WrappedResult &), T *object)
std::shared_future< typename GoalHandle::SharedPtr > sendGoal(Goal &goal, typename smacc2::SmaccSignal< void(const WrappedResult &)>::WeakPtr resultCallback=typename smacc2::SmaccSignal< void(const WrappedResult &)>::WeakPtr())
boost::signals2::connection onCancelled(void(T::*callback)(const WrappedResult &), T *object)
boost::signals2::connection onFeedback(void(T::*callback)(const Feedback &), T *object)
boost::signals2::connection onAborted(void(T::*callback)(const WrappedResult &), T *object)