Common
common packages for kyubic
 
Loading...
Searching...
No Matches
ros_action_node.hpp
Go to the documentation of this file.
1
10#ifndef _ROS_ACTION_NODE_HPP
11#define _ROS_ACTION_NODE_HPP
12
13#include <behaviortree_cpp/action_node.h>
14
15#include <future>
16#include <rclcpp_action/rclcpp_action.hpp>
17
18namespace behavior_tree
19{
20
26template <class ActionT>
27class RosActionNode : public BT::StatefulActionNode
28{
29public:
30 using Action = ActionT;
31 using GoalHandle = rclcpp_action::ClientGoalHandle<Action>;
32 using ActionClient = rclcpp_action::Client<Action>;
33 using WrappedResult = typename rclcpp_action::ClientGoalHandle<Action>::WrappedResult;
34 using Feedback = typename Action::Feedback;
35
44 const std::string & name, const BT::NodeConfig & config, rclcpp::Node::SharedPtr ros_node);
45
51 virtual bool setGoal(typename Action::Goal & goal) = 0;
52
58 virtual BT::NodeStatus onResult(const WrappedResult & wr) = 0;
59
63 virtual void onFeedback(const std::shared_ptr<const Feedback> feedback);
64
72 BT::NodeStatus onStart() override;
73
81 BT::NodeStatus onRunning() override;
82
86 void onHalted() override;
87
88protected:
89 rclcpp::Node::SharedPtr ros_node_;
90 typename ActionClient::SharedPtr client_;
91 std::string action_name;
92
93 std::shared_future<typename GoalHandle::SharedPtr> future_goal_handle_;
94 std::shared_future<WrappedResult> future_result_;
95 typename GoalHandle::SharedPtr active_goal_handle_;
96};
97
98// =================================================================================
99// Implementation
100// =================================================================================
101
102template <class ActionT>
104 const std::string & name, const BT::NodeConfig & config, rclcpp::Node::SharedPtr ros_node)
105: BT::StatefulActionNode(name, config), ros_node_(ros_node)
106{
107 if (!this->getInput("action_name", action_name)) {
108 action_name = this->registrationName();
109 }
110
111 client_ = rclcpp_action::create_client<Action>(ros_node_, action_name);
112}
113
114template <class ActionT>
115void RosActionNode<ActionT>::onFeedback(const std::shared_ptr<const Feedback> feedback)
116{
117 // Do nothing by default
118 (void)feedback;
119}
120
121template <class ActionT>
123{
124 if (!client_->wait_for_action_server(std::chrono::seconds(1))) {
125 RCLCPP_ERROR(ros_node_->get_logger(), "Action server '%s' not found", action_name.c_str());
126 return BT::NodeStatus::FAILURE;
127 }
128
129 // Call setGoal() of the derived class
130 typename Action::Goal goal_msg;
131 if (!setGoal(goal_msg)) {
132 RCLCPP_ERROR(ros_node_->get_logger(), "Failed to configure the Goal");
133 return BT::NodeStatus::FAILURE;
134 }
135
136 auto send_goal_options = typename ActionClient::SendGoalOptions();
137 send_goal_options.feedback_callback =
138 [this](typename GoalHandle::SharedPtr, const std::shared_ptr<const Feedback> feedback) {
139 this->onFeedback(feedback);
140 };
141
142 future_goal_handle_ = client_->async_send_goal(goal_msg, send_goal_options);
143 RCLCPP_INFO(ros_node_->get_logger(), "Sending goal: %s", action_name.c_str());
144 return BT::NodeStatus::RUNNING;
145}
146
147template <class ActionT>
149{
150 // 1. Check if the goal was accepted
151 if (!active_goal_handle_) {
152 if (future_goal_handle_.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
153 active_goal_handle_ = future_goal_handle_.get();
154 if (!active_goal_handle_) {
155 RCLCPP_ERROR(ros_node_->get_logger(), "Goal was rejected by the server");
156 return BT::NodeStatus::FAILURE;
157 }
158
159 RCLCPP_INFO(ros_node_->get_logger(), "Goal accepted. Waiting for result.");
160 future_result_ = client_->async_get_result(active_goal_handle_);
161 return BT::NodeStatus::RUNNING;
162 } else {
163 return BT::NodeStatus::RUNNING;
164 }
165 }
166
167 // 2. Check for the result
168 if (future_result_.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
169 WrappedResult wr = future_result_.get();
170 active_goal_handle_.reset();
171
172 // Call onResult() of the derived class
173 return onResult(wr);
174
175 } else {
176 return BT::NodeStatus::RUNNING;
177 }
178}
179
180template <class ActionT>
182{
183 RCLCPP_WARN(ros_node_->get_logger(), "Action was halted");
184 if (active_goal_handle_) {
185 client_->async_cancel_goal(active_goal_handle_);
186 active_goal_handle_.reset();
187 }
188}
189
190} // namespace behavior_tree
191
192#endif // !_ROS_ACTION_NODE_HPP
Template for ROS2 Action with Behavior Tree.
Definition: ros_action_node.hpp:28
typename rclcpp_action::ClientGoalHandle< Action >::WrappedResult WrappedResult
Definition: ros_action_node.hpp:33
ActionT Action
Definition: ros_action_node.hpp:30
virtual void onFeedback(const std::shared_ptr< const Feedback > feedback)
Behavior when recieving feadback.
Definition: ros_action_node.hpp:115
virtual bool setGoal(typename Action::Goal &goal)=0
Configures the Goal message.
RosActionNode(const std::string &name, const BT::NodeConfig &config, rclcpp::Node::SharedPtr ros_node)
Create action client.
Definition: ros_action_node.hpp:103
std::shared_future< typename GoalHandle::SharedPtr > future_goal_handle_
Definition: ros_action_node.hpp:93
rclcpp::Node::SharedPtr ros_node_
Definition: ros_action_node.hpp:89
std::shared_future< WrappedResult > future_result_
Definition: ros_action_node.hpp:94
BT::NodeStatus onStart() override
Called when the node is first ticked. Initiates the ROS 2 action.
Definition: ros_action_node.hpp:122
ActionClient::SharedPtr client_
Definition: ros_action_node.hpp:90
typename Action::Feedback Feedback
Definition: ros_action_node.hpp:34
void onHalted() override
Cancels the currently active goal if one exists.
Definition: ros_action_node.hpp:181
rclcpp_action::Client< Action > ActionClient
Definition: ros_action_node.hpp:32
GoalHandle::SharedPtr active_goal_handle_
Definition: ros_action_node.hpp:95
virtual BT::NodeStatus onResult(const WrappedResult &wr)=0
Processes the final result received from the server.
std::string action_name
Definition: ros_action_node.hpp:91
rclcpp_action::ClientGoalHandle< Action > GoalHandle
Definition: ros_action_node.hpp:31
BT::NodeStatus onRunning() override
This method manages the asynchronous state machine:
Definition: ros_action_node.hpp:148