Skip to content

Commit 1ce447f

Browse files
committed
change pan bt
1 parent 667753c commit 1ce447f

5 files changed

Lines changed: 386 additions & 118 deletions

File tree

bt_nodes/motion/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ find_package(trajectory_msgs REQUIRED)
2828
find_package(sensor_msgs REQUIRED)
2929
find_package(manipulation_interfaces REQUIRED)
3030
find_package(action_msgs REQUIRED)
31+
find_package(control_msgs REQUIRED)
3132

3233
set(CMAKE_CXX_STANDARD 17)
3334

@@ -54,6 +55,7 @@ set(dependencies
5455
sensor_msgs
5556
manipulation_interfaces
5657
action_msgs
58+
control_msgs
5759
)
5860

5961
include_directories(include)
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
// Copyright (c) 2018 Intel Corporation
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+
#ifndef BR2_BT_PATROLLING__CTRL_SUPPORT__BTACTIONNODE_HPP_
16+
#define BR2_BT_PATROLLING__CTRL_SUPPORT__BTACTIONNODE_HPP_
17+
18+
#include <memory>
19+
#include <string>
20+
21+
#include "behaviortree_cpp_v3/action_node.h"
22+
#include "rclcpp/rclcpp.hpp"
23+
#include "rclcpp_action/rclcpp_action.hpp"
24+
#include "rclcpp_cascade_lifecycle/rclcpp_cascade_lifecycle.hpp"
25+
26+
27+
namespace head
28+
{
29+
30+
using namespace std::chrono_literals; // NOLINT
31+
32+
template<class ActionT, class NodeT = rclcpp_cascade_lifecycle::CascadeLifecycleNode>
33+
class BtActionNode : public BT::ActionNodeBase
34+
{
35+
public:
36+
BtActionNode(
37+
const std::string & xml_tag_name, const std::string & action_name,
38+
const BT::NodeConfiguration & conf)
39+
: BT::ActionNodeBase(xml_tag_name, conf), action_name_(action_name)
40+
{
41+
config().blackboard->get<typename NodeT::SharedPtr>("node", node_);
42+
43+
server_timeout_ = 1s;
44+
45+
// Initialize the input and output messages
46+
goal_ = typename ActionT::Goal();
47+
result_ = typename rclcpp_action::ClientGoalHandle<ActionT>::WrappedResult();
48+
49+
std::string remapped_action_name;
50+
if (getInput("server_name", remapped_action_name)) {
51+
action_name_ = remapped_action_name;
52+
}
53+
createActionClient(action_name_);
54+
55+
// Give the derive class a chance to do any initialization
56+
RCLCPP_INFO(node_->get_logger(), "\"%s\" BtActionNode initialized", xml_tag_name.c_str());
57+
}
58+
59+
BtActionNode() = delete;
60+
61+
virtual ~BtActionNode() {}
62+
63+
// Create instance of an action server
64+
void createActionClient(const std::string & action_name)
65+
{
66+
// Now that we have the ROS node to use, create the action client for this
67+
// BT action
68+
action_client_ = rclcpp_action::create_client<ActionT>(node_, action_name);
69+
70+
// Make sure the server is actually there before continuing
71+
RCLCPP_INFO(node_->get_logger(), "Waiting for \"%s\" action server", action_name.c_str());
72+
action_client_->wait_for_action_server();
73+
}
74+
75+
// Any subclass of BtActionNode that accepts parameters must provide a
76+
// providedPorts method and call providedBasicPorts in it.
77+
static BT::PortsList providedBasicPorts(BT::PortsList addition)
78+
{
79+
BT::PortsList basic = {
80+
BT::InputPort<std::string>("server_name", "Action server name"),
81+
BT::InputPort<std::chrono::milliseconds>("server_timeout")};
82+
basic.insert(addition.begin(), addition.end());
83+
84+
return basic;
85+
}
86+
87+
static BT::PortsList providedPorts() {return providedBasicPorts({});}
88+
89+
// Derived classes can override any of the following methods to hook into the
90+
// processing for the action: on_tick, on_wait_for_result, and on_success
91+
92+
// Could do dynamic checks, such as getting updates to values on the
93+
// blackboard
94+
virtual void on_tick() {}
95+
96+
// There can be many loop iterations per tick. Any opportunity to do something
97+
// after a timeout waiting for a result that hasn't been received yet
98+
virtual void on_wait_for_result() {}
99+
100+
// Called upon successful completion of the action. A derived class can
101+
// override this method to put a value on the blackboard, for example.
102+
virtual BT::NodeStatus on_success() {return BT::NodeStatus::SUCCESS;}
103+
104+
// Called when a the action is aborted. By default, the node will return
105+
// FAILURE. The user may override it to return another value, instead.
106+
virtual BT::NodeStatus on_aborted() {return BT::NodeStatus::FAILURE;}
107+
108+
// Called when a the action is cancelled. By default, the node will return
109+
// SUCCESS. The user may override it to return another value, instead.
110+
virtual BT::NodeStatus on_cancelled() {return BT::NodeStatus::FAILURE;}
111+
112+
// The main override required by a BT action
113+
BT::NodeStatus tick() override
114+
{
115+
// first step to be done only at the beginning of the Action
116+
if (status() == BT::NodeStatus::IDLE) {
117+
createActionClient(action_name_);
118+
119+
// setting the status to RUNNING to notify the BT Loggers (if any)
120+
setStatus(BT::NodeStatus::RUNNING);
121+
122+
// user defined callback
123+
on_tick();
124+
125+
on_new_goal_received();
126+
}
127+
128+
// The following code corresponds to the "RUNNING" loop
129+
if (rclcpp::ok() && !goal_result_available_) {
130+
// user defined callback. May modify the value of "goal_updated_"
131+
on_wait_for_result();
132+
133+
auto goal_status = goal_handle_->get_status();
134+
if (
135+
goal_updated_ && (goal_status == action_msgs::msg::GoalStatus::STATUS_EXECUTING ||
136+
goal_status == action_msgs::msg::GoalStatus::STATUS_ACCEPTED))
137+
{
138+
goal_updated_ = false;
139+
on_new_goal_received();
140+
}
141+
142+
rclcpp::spin_some(node_->get_node_base_interface());
143+
144+
// check if, after invoking spin_some(), we finally received the result
145+
if (!goal_result_available_) {
146+
// Yield this Action, returning RUNNING
147+
return BT::NodeStatus::RUNNING;
148+
}
149+
}
150+
151+
switch (result_.code) {
152+
case rclcpp_action::ResultCode::SUCCEEDED:
153+
return on_success();
154+
155+
case rclcpp_action::ResultCode::ABORTED:
156+
return on_aborted();
157+
158+
case rclcpp_action::ResultCode::CANCELED:
159+
return on_cancelled();
160+
161+
default:
162+
throw std::logic_error("BtActionNode::Tick: invalid status value");
163+
}
164+
}
165+
166+
// The other (optional) override required by a BT action. In this case, we
167+
// make sure to cancel the ROS2 action if it is still running.
168+
void halt() override
169+
{
170+
if (should_cancel_goal()) {
171+
auto future_cancel = action_client_->async_cancel_goal(goal_handle_);
172+
if (
173+
rclcpp::spin_until_future_complete(
174+
node_->get_node_base_interface(), future_cancel, server_timeout_) !=
175+
rclcpp::FutureReturnCode::SUCCESS)
176+
{
177+
RCLCPP_ERROR(
178+
node_->get_logger(), "Failed to cancel action server for %s", action_name_.c_str());
179+
}
180+
}
181+
182+
setStatus(BT::NodeStatus::IDLE);
183+
}
184+
185+
protected:
186+
bool should_cancel_goal()
187+
{
188+
// Shut the node down if it is currently running
189+
if (status() != BT::NodeStatus::RUNNING) {
190+
return false;
191+
}
192+
193+
rclcpp::spin_some(node_->get_node_base_interface());
194+
auto status = goal_handle_->get_status();
195+
196+
// Check if the goal is still executing
197+
return status == action_msgs::msg::GoalStatus::STATUS_ACCEPTED ||
198+
status == action_msgs::msg::GoalStatus::STATUS_EXECUTING;
199+
}
200+
201+
void on_new_goal_received()
202+
{
203+
goal_result_available_ = false;
204+
auto send_goal_options = typename rclcpp_action::Client<ActionT>::SendGoalOptions();
205+
send_goal_options.result_callback =
206+
[this](const typename rclcpp_action::ClientGoalHandle<ActionT>::WrappedResult & result) {
207+
// TODO(#1652): a work around until rcl_action interface is updated
208+
// if goal ids are not matched, the older goal call this callback so
209+
// ignore the result if matched, it must be processed (including
210+
// aborted)
211+
if (this->goal_handle_->get_goal_id() == result.goal_id) {
212+
goal_result_available_ = true;
213+
result_ = result;
214+
}
215+
};
216+
217+
auto future_goal_handle = action_client_->async_send_goal(goal_, send_goal_options);
218+
219+
if (
220+
rclcpp::spin_until_future_complete(
221+
node_->get_node_base_interface(), future_goal_handle, server_timeout_) !=
222+
rclcpp::FutureReturnCode::SUCCESS)
223+
{
224+
throw std::runtime_error("send_goal failed");
225+
}
226+
227+
goal_handle_ = future_goal_handle.get();
228+
if (!goal_handle_) {
229+
throw std::runtime_error("Goal was rejected by the action server");
230+
}
231+
}
232+
233+
void increment_recovery_count()
234+
{
235+
int recovery_count = 0;
236+
config().blackboard->get<int>(
237+
"number_recoveries",
238+
recovery_count); // NOLINT
239+
recovery_count += 1;
240+
config().blackboard->set<int>(
241+
"number_recoveries",
242+
recovery_count); // NOLINT
243+
}
244+
245+
std::string action_name_;
246+
typename std::shared_ptr<rclcpp_action::Client<ActionT>> action_client_;
247+
248+
// All ROS2 actions have a goal and a result
249+
typename ActionT::Goal goal_;
250+
bool goal_updated_{false};
251+
bool goal_result_available_{false};
252+
typename rclcpp_action::ClientGoalHandle<ActionT>::SharedPtr goal_handle_;
253+
typename rclcpp_action::ClientGoalHandle<ActionT>::WrappedResult result_;
254+
255+
// The node that will be used for any ROS operations
256+
typename NodeT::SharedPtr node_;
257+
258+
// The timeout value while waiting for response from a server when a
259+
// new action goal is sent or canceled
260+
std::chrono::milliseconds server_timeout_;
261+
};
262+
263+
} // namespace head
264+
265+
#endif // BR2_BT_PATROLLING__CTRL_SUPPORT__BTACTIONNODE_HPP_

bt_nodes/motion/include/motion/head/Pan.hpp

Lines changed: 31 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,57 @@
1-
// Copyright 2024 Intelligent Robotics Lab - Gentlebots
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-
151
#ifndef HEAD__PAN_HPP_
162
#define HEAD__PAN_HPP_
173

18-
#include <cmath>
19-
#include <iostream>
204
#include <string>
5+
#include <vector>
216

227
#include "behaviortree_cpp_v3/behavior_tree.h"
238
#include "behaviortree_cpp_v3/bt_factory.h"
9+
#include "motion/head/BTActionNode.hpp"
2410
#include "rclcpp_cascade_lifecycle/rclcpp_cascade_lifecycle.hpp"
25-
#include "sensor_msgs/msg/joint_state.hpp"
26-
#include "trajectory_msgs/msg/joint_trajectory.hpp"
11+
12+
#include "control_msgs/action/follow_joint_trajectory.hpp"
13+
#include "trajectory_msgs/msg/joint_trajectory_point.hpp"
2714

2815
namespace head
2916
{
3017

31-
class Pan : public BT::ActionNodeBase
18+
class Pan
19+
: public head::BtActionNode<
20+
control_msgs::action::FollowJointTrajectory,
21+
rclcpp_cascade_lifecycle::CascadeLifecycleNode>
3222
{
3323
public:
34-
explicit Pan(const std::string & xml_tag_name, const BT::NodeConfiguration & conf);
24+
explicit Pan(
25+
const std::string & xml_tag_name,
26+
const std::string & action_name,
27+
const BT::NodeConfiguration & conf);
3528

36-
void halt();
37-
BT::NodeStatus tick();
29+
void on_tick() override;
30+
BT::NodeStatus on_success() override;
3831

3932
static BT::PortsList providedPorts()
4033
{
41-
return BT::PortsList(
42-
{
43-
BT::InputPort<double>("range"), // in degrees
44-
BT::InputPort<double>("period"), // in seconds
45-
BT::InputPort<double>("pitch_angle") // in degrees
46-
});
34+
return BT::PortsList({
35+
BT::InputPort<double>("range"), // degrees
36+
BT::InputPort<double>("period"), // seconds
37+
BT::InputPort<double>("pitch_angle") // degrees
38+
});
4739
}
4840

4941
private:
50-
// std::shared_ptr<rclcpp_cascade_lifecycle::CascadeLifecycleNode> node_;
51-
std::shared_ptr<rclcpp_cascade_lifecycle::CascadeLifecycleNode> node_;
52-
rclcpp::Time start_time_;
53-
rclcpp_lifecycle::LifecyclePublisher<trajectory_msgs::msg::JointTrajectory>::SharedPtr
54-
joint_cmd_pub_;
55-
double yaw_limit_{1.3};
56-
double pitch_limit_{0.92};
57-
double pitch_{0.0};
58-
std::vector<double> yaw_positions_{0.0, 0.7, 0.7, 0.7, 0.7, -0.7, -0.7, 0.0};
59-
std::vector<double> pitch_positions_{0.0, 0.0, 0.3, -0.3, 0.3, 0.3, -0.3, 0.0};
60-
std::vector<double> times_from_start_{0.1, 3.0, 6.0, 9.0, 12.0, 15.0, 18.0, 21.0};
61-
rclcpp::Subscription<sensor_msgs::msg::JointState>::SharedPtr joint_state_sub_;
62-
double joint_range_, period_;
63-
double pitch_angle_ = 0.0;
64-
double phase_;
42+
double joint_range_{0.0};
43+
double period_{0.0};
44+
double pitch_angle_{0.0};
45+
46+
const double yaw_limit_{1.3}; // TIAGo limits
47+
const double pitch_limit_{0.92};
48+
std::vector<double> yaw_steps_{ 0.0, -0.3, -0.6, 0.3, 0.6 };
49+
size_t current_step_{0};
50+
6551

66-
int current_position_{0};
6752

68-
double get_joint_yaw(double period, double range, double time, double phase);
53+
void build_trajectory(
54+
std::vector<trajectory_msgs::msg::JointTrajectoryPoint> & points);
6955
};
7056

7157
} // namespace head

0 commit comments

Comments
 (0)