15#include <Eigen/Geometry>
17#include "auto_apms_behavior_tree_core/node.hpp"
18#include "auto_apms_interfaces/action/go_to.hpp"
20#define INPUT_KEY_FRAME "frame"
21#define INPUT_KEY_VEC "vector"
22#define INPUT_KEY_X "x"
23#define INPUT_KEY_Y "y"
24#define INPUT_KEY_Z "z"
25#define INPUT_KEY_YAW "yaw"
26#define INPUT_KEY_MAX_HOR_VEL "max_horizontal_vel"
27#define INPUT_KEY_MAX_VER_VEL "max_vertical_vel"
28#define INPUT_KEY_MAX_HEADING_RATE "max_heading_rate"
29#define INPUT_KEY_REACHED_THRESH_POS "reached_thresh_pos"
30#define INPUT_KEY_REACHED_THRESH_VEL "reached_thresh_vel"
31#define INPUT_KEY_REACHED_THRESH_YAW "reached_thresh_yaw"
36class GoToAction :
public auto_apms_behavior_tree::core::RosActionNode<auto_apms_interfaces::action::GoTo>
39 using RosActionNode::RosActionNode;
41 static BT::PortsList providedPorts()
44 BT::InputPort<std::string>(
45 INPUT_KEY_FRAME,
"global",
46 "Reference frame: 'global' (Latitude, longitude, altitude (AMSL)) or 'local' (North, east, down from start)"),
47 BT::InputPort<Eigen::MatrixXd>(INPUT_KEY_VEC,
"Target position as a row vector (separated by ;)"),
48 BT::InputPort<double>(INPUT_KEY_X,
"Override vector entry X"),
49 BT::InputPort<double>(INPUT_KEY_Y,
"Override vector entry Y"),
50 BT::InputPort<double>(INPUT_KEY_Z,
"Override vector entry Z"),
51 BT::InputPort<double>(INPUT_KEY_YAW,
"Desired yaw position in degree from north (heading) [-180°, 180)"),
52 BT::InputPort<double>(INPUT_KEY_MAX_HOR_VEL, 10.0,
"Maximum horizontal velocity [m/s]"),
53 BT::InputPort<double>(INPUT_KEY_MAX_VER_VEL, 5.0,
"Maximum vertical velocity [m/s]"),
54 BT::InputPort<double>(INPUT_KEY_MAX_HEADING_RATE, 30.0,
"Maximum heading rate [°/s]"),
55 BT::InputPort<double>(
56 INPUT_KEY_REACHED_THRESH_POS, .5,
"Maximum position error [m] under which the position is considered reached"),
57 BT::InputPort<double>(
58 INPUT_KEY_REACHED_THRESH_VEL, .3,
59 "Maximum velocity error [m/s] under which the position is considered reached"),
60 BT::InputPort<double>(
61 INPUT_KEY_REACHED_THRESH_YAW, 7.0,
"Maximum heading error [°] under which the position is considered reached")};
64 bool setGoal(Goal & goal)
67 if (
const BT::Expected<std::string> expected = getInput<std::string>(INPUT_KEY_FRAME)) {
68 const std::string frame_str = expected.value();
69 if (frame_str !=
"global" && frame_str !=
"local") {
71 logger_,
"%s - Invalid reference frame '%s'", context_.getFullyQualifiedTreeNodeName(
this).c_str(),
76 RCLCPP_ERROR(logger_,
"%s - %s", context_.getFullyQualifiedTreeNodeName(
this).c_str(), expected.error().c_str());
80 int position_valid = 0;
81 BT::PortsRemapping::iterator input_port_it = config().input_ports.find(INPUT_KEY_VEC);
82 if (input_port_it != config().input_ports.end() && !input_port_it->second.empty()) {
83 if (
const BT::Expected<Eigen::MatrixXd> expected = getInput<Eigen::MatrixXd>(INPUT_KEY_VEC)) {
84 const Eigen::MatrixXd & mat = expected.value();
85 if (mat.rows() == 1 && mat.cols() == 3) {
86 goal.pos.x = mat(0, 0);
87 goal.pos.y = mat(0, 1);
88 goal.pos.z = mat(0, 2);
92 logger_,
"%s - Input vector has wrong size (Required: 3 - Actual: %i)",
93 context_.getFullyQualifiedTreeNodeName(
this).c_str(),
static_cast<int>(mat.rows()));
98 logger_,
"%s - %s", context_.getFullyQualifiedTreeNodeName(
this).c_str(), expected.error().c_str());
103 input_port_it = config().input_ports.find(INPUT_KEY_X);
104 if (input_port_it != config().input_ports.end() && !input_port_it->second.empty()) {
105 if (
const BT::Expected<double> expected = getInput<double>(INPUT_KEY_X)) {
106 goal.pos.x = expected.value();
110 logger_,
"%s - %s", context_.getFullyQualifiedTreeNodeName(
this).c_str(), expected.error().c_str());
115 input_port_it = config().input_ports.find(INPUT_KEY_Y);
116 if (input_port_it != config().input_ports.end() && !input_port_it->second.empty()) {
117 if (
const BT::Expected<double> expected = getInput<double>(INPUT_KEY_Y)) {
118 goal.pos.y = expected.value();
122 logger_,
"%s - %s", context_.getFullyQualifiedTreeNodeName(
this).c_str(), expected.error().c_str());
127 input_port_it = config().input_ports.find(INPUT_KEY_Z);
128 if (input_port_it != config().input_ports.end() && !input_port_it->second.empty()) {
129 if (
const BT::Expected<double> expected = getInput<double>(INPUT_KEY_Z)) {
130 goal.pos.z = expected.value();
134 logger_,
"%s - %s", context_.getFullyQualifiedTreeNodeName(
this).c_str(), expected.error().c_str());
139 if (position_valid < 3) {
141 logger_,
"%s - Position is not valid. You must provide information for all three vector entries (%i missing)",
142 context_.getFullyQualifiedTreeNodeName(
this).c_str(),
static_cast<int>(3 - position_valid));
146 input_port_it = config().input_ports.find(INPUT_KEY_YAW);
147 if (input_port_it == config().input_ports.end() || input_port_it->second.empty()) {
148 goal.head_towards_destination =
true;
150 if (
const BT::Expected<double> expected = getInput<double>(INPUT_KEY_YAW)) {
151 goal.head_towards_destination =
false;
152 goal.heading_clockwise_from_north_deg = expected.value();
155 logger_,
"%s - %s", context_.getFullyQualifiedTreeNodeName(
this).c_str(), expected.error().c_str());
160 if (
const BT::Expected<double> expected = getInput<double>(INPUT_KEY_MAX_HOR_VEL)) {
161 goal.max_horizontal_vel_m_s = expected.value();
163 RCLCPP_ERROR(logger_,
"%s - %s", context_.getFullyQualifiedTreeNodeName(
this).c_str(), expected.error().c_str());
167 if (
const BT::Expected<double> expected = getInput<double>(INPUT_KEY_MAX_VER_VEL)) {
168 goal.max_vertical_vel_m_s = expected.value();
170 RCLCPP_ERROR(logger_,
"%s - %s", context_.getFullyQualifiedTreeNodeName(
this).c_str(), expected.error().c_str());
174 if (
const BT::Expected<double> expected = getInput<double>(INPUT_KEY_MAX_HEADING_RATE)) {
175 goal.max_heading_rate_deg_s = expected.value();
177 RCLCPP_ERROR(logger_,
"%s - %s", context_.getFullyQualifiedTreeNodeName(
this).c_str(), expected.error().c_str());
181 if (
const BT::Expected<double> expected = getInput<double>(INPUT_KEY_REACHED_THRESH_POS)) {
182 goal.reached_thresh_pos_m = expected.value();
184 RCLCPP_ERROR(logger_,
"%s - %s", context_.getFullyQualifiedTreeNodeName(
this).c_str(), expected.error().c_str());
188 if (
const BT::Expected<double> expected = getInput<double>(INPUT_KEY_REACHED_THRESH_VEL)) {
189 goal.reached_thresh_vel_m_s = expected.value();
191 RCLCPP_ERROR(logger_,
"%s - %s", context_.getFullyQualifiedTreeNodeName(
this).c_str(), expected.error().c_str());
195 if (
const BT::Expected<double> expected = getInput<double>(INPUT_KEY_REACHED_THRESH_YAW)) {
196 goal.reached_thresh_heading_deg = expected.value();
198 RCLCPP_ERROR(logger_,
"%s - %s", context_.getFullyQualifiedTreeNodeName(
this).c_str(), expected.error().c_str());
#define AUTO_APMS_BEHAVIOR_TREE_DECLARE_NODE(type)
Macro for registering a behavior tree node plugin.
Implementation of PX4 mode peers offered by px4_ros2_cpp enabling integration with AutoAPMS.