AutoAPMS
Resilient Robot Mission Management
All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Modules Pages
goto.cpp
1// Copyright 2024 Robin Müller
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// https://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#include "px4_ros2/control/setpoint_types/goto.hpp"
16
17#include <Eigen/Core>
18
19#include "auto_apms_interfaces/action/go_to.hpp"
20#include "auto_apms_px4/mode_executor.hpp"
21#include "px4_ros2/utils/geodesic.hpp"
22#include "tf2_eigen/tf2_eigen.hpp"
23
24namespace auto_apms_px4
25{
26
27using GoToActionType = auto_apms_interfaces::action::GoTo;
28
29class GoToGlobalMode : public PositionAwareMode<GoToActionType>
30{
31 std::shared_ptr<px4_ros2::GotoGlobalSetpointType> goto_global_setpoint_ptr_;
32 Eigen::Vector3d position_target_f_glob_;
33 float heading_target_rad_;
34
35public:
36 GoToGlobalMode(
37 rclcpp::Node & node, const px4_ros2::ModeBase::Settings & settings, const std::string & topic_namespace_prefix,
38 std::shared_ptr<ActionContextType> action_context_ptr)
39 : PositionAwareMode{node, settings, topic_namespace_prefix, action_context_ptr}
40 {
41 goto_global_setpoint_ptr_ = std::make_shared<px4_ros2::GotoGlobalSetpointType>(*this);
42 }
43
44private:
45 void OnActivateWithGoal(std::shared_ptr<const Goal> goal_ptr) final
46 {
47 position_target_f_glob_ = Eigen::Vector3d(goal_ptr->pos.x, goal_ptr->pos.y, goal_ptr->pos.z);
48
49 // Heading target has to be in rad clockwise from north
50 if (goal_ptr->head_towards_destination) {
51 // Heading target needs to be in interval [-pi, pi] (from north)
52 heading_target_rad_ =
53 px4_ros2::headingToGlobalPosition(vehicle_global_position_ptr_->position(), position_target_f_glob_);
54 } else {
55 heading_target_rad_ = px4_ros2::wrapPi(px4_ros2::degToRad(goal_ptr->heading_clockwise_from_north_deg));
56 }
57
58 auto double_to_string = [](double num, int decimals) {
59 std::stringstream stream;
60 stream << std::fixed << std::setprecision(decimals) << num;
61 return stream.str();
62 };
63
64 RCLCPP_DEBUG(
65 node().get_logger(), "GoToGlobal target: Position: [%s°, %s°, %sm] - Heading: %f°",
66 double_to_string(position_target_f_glob_.x(), 10).c_str(),
67 double_to_string(position_target_f_glob_.y(), 10).c_str(),
68 double_to_string(position_target_f_glob_.z(), 2).c_str(), px4_ros2::radToDeg(heading_target_rad_));
69 }
70
71 void UpdateSetpointWithGoal(
72 float /*dt_s*/, std::shared_ptr<const Goal> goal_ptr, std::shared_ptr<Feedback> feedback_ptr,
73 std::shared_ptr<Result> result_ptr) final
74 {
75 goto_global_setpoint_ptr_->update(
76 position_target_f_glob_, heading_target_rad_, goal_ptr->max_horizontal_vel_m_s, goal_ptr->max_vertical_vel_m_s,
77 px4_ros2::degToRad(goal_ptr->max_heading_rate_deg_s));
78
79 // Remaining distance to target
80 Eigen::Vector3d distance_f_ned =
81 px4_ros2::vectorToGlobalPosition(vehicle_global_position_ptr_->position(), position_target_f_glob_)
82 .cast<double>();
83 tf2::convert(distance_f_ned, feedback_ptr->remaining_dist);
84
85 // Remaining degrees until target heading
86 feedback_ptr->remaining_heading_deg =
87 px4_ros2::radToDeg(px4_ros2::wrapPi(heading_target_rad_ - vehicle_attitude_ptr_->yaw()));
88
89 // Estimated remaining time. Use only velocity in direction of target for estimation.
90 feedback_ptr->remaining_time_s =
91 distance_f_ned.norm() /
92 (vehicle_local_position_ptr_->velocityNed().cast<double>().dot(distance_f_ned.normalized()));
93
94 if (
95 IsGlobalPositionReached(
96 position_target_f_glob_, goal_ptr->reached_thresh_pos_m, goal_ptr->reached_thresh_vel_m_s) &&
97 IsHeadingReached(heading_target_rad_, px4_ros2::degToRad(goal_ptr->reached_thresh_heading_deg))) {
98 result_ptr->remaining_dist = feedback_ptr->remaining_dist;
99 result_ptr->remaining_heading_deg = feedback_ptr->remaining_heading_deg;
100 completed(px4_ros2::Result::Success);
101 }
102 }
103};
104
105class GoToLocalMode : public PositionAwareMode<GoToActionType>
106{
107 std::shared_ptr<px4_ros2::GotoSetpointType> goto_local_setpoint_ptr_;
108 Eigen::Vector3d position_target_f_ned_;
109 float heading_target_rad_;
110
111public:
112 GoToLocalMode(
113 rclcpp::Node & node, const px4_ros2::ModeBase::Settings & settings, const std::string & topic_namespace_prefix,
114 std::shared_ptr<ActionContextType> action_context_ptr)
115 : PositionAwareMode{node, settings, topic_namespace_prefix, action_context_ptr}
116 {
117 goto_local_setpoint_ptr_ = std::make_shared<px4_ros2::GotoSetpointType>(*this);
118 }
119
120private:
121 void OnActivateWithGoal(std::shared_ptr<const Goal> goal_ptr) final
122 {
123 position_target_f_ned_ = Eigen::Vector3d(goal_ptr->pos.x, goal_ptr->pos.y, goal_ptr->pos.z);
124
125 // Heading target has to be in rad clockwise from north
126 if (goal_ptr->head_towards_destination) {
127 // Heading target needs to be in interval [-pi, pi] (from north)
128 const px4_msgs::msg::VehicleLocalPosition & pos = vehicle_local_position_ptr_->last();
129 const Eigen::Vector2d pos_vec(pos.x, pos.y);
130 const Eigen::Vector2d d = position_target_f_ned_.head<2>() - pos_vec;
131 heading_target_rad_ = px4_ros2::wrapPi(atan2(d.y(), d.x()));
132 } else {
133 heading_target_rad_ = px4_ros2::wrapPi(px4_ros2::degToRad(goal_ptr->heading_clockwise_from_north_deg));
134 }
135
136 auto double_to_string = [](double num, int decimals) {
137 std::stringstream stream;
138 stream << std::fixed << std::setprecision(decimals) << num;
139 return stream.str();
140 };
141
142 RCLCPP_DEBUG(
143 node().get_logger(), "GoToLocal target: Position: [%sm, %sm, %sm] - Heading: %f°",
144 double_to_string(position_target_f_ned_.x(), 2).c_str(), double_to_string(position_target_f_ned_.y(), 2).c_str(),
145 double_to_string(position_target_f_ned_.z(), 2).c_str(), px4_ros2::radToDeg(heading_target_rad_));
146 }
147
148 void UpdateSetpointWithGoal(
149 float /*dt_s*/, std::shared_ptr<const Goal> goal_ptr, std::shared_ptr<Feedback> feedback_ptr,
150 std::shared_ptr<Result> result_ptr) final
151 {
152 goto_local_setpoint_ptr_->update(
153 position_target_f_ned_.cast<float>(), heading_target_rad_, goal_ptr->max_horizontal_vel_m_s, goal_ptr->max_vertical_vel_m_s,
154 px4_ros2::degToRad(goal_ptr->max_heading_rate_deg_s));
155
156 // Remaining distance to target
157 Eigen::Vector3d distance_f_ned =
158 px4_ros2::vectorToGlobalPosition(vehicle_global_position_ptr_->position(), position_target_f_ned_).cast<double>();
159 tf2::convert(distance_f_ned, feedback_ptr->remaining_dist);
160
161 // Remaining degrees until target heading
162 feedback_ptr->remaining_heading_deg =
163 px4_ros2::radToDeg(px4_ros2::wrapPi(heading_target_rad_ - vehicle_attitude_ptr_->yaw()));
164
165 // Estimated remaining time. Use only velocity in direction of target for estimation.
166 feedback_ptr->remaining_time_s =
167 distance_f_ned.norm() /
168 (vehicle_local_position_ptr_->velocityNed().cast<double>().dot(distance_f_ned.normalized()));
169
170 if (
171 IsLocalPositionReached(
172 position_target_f_ned_, goal_ptr->reached_thresh_pos_m, goal_ptr->reached_thresh_vel_m_s) &&
173 IsHeadingReached(heading_target_rad_, px4_ros2::degToRad(goal_ptr->reached_thresh_heading_deg))) {
174 result_ptr->remaining_dist = feedback_ptr->remaining_dist;
175 result_ptr->remaining_heading_deg = feedback_ptr->remaining_heading_deg;
176 completed(px4_ros2::Result::Success);
177 }
178 }
179};
180
181class GoToGlobalSkill : public ModeExecutorFactory<GoToActionType, GoToGlobalMode>
182{
183public:
184 explicit GoToGlobalSkill(const rclcpp::NodeOptions & options)
185 : ModeExecutorFactory{_AUTO_APMS_PX4__GOTO_GLOBAL_ACTION_NAME, options}
186 {
187 }
188};
189
190class GoToLocalSkill : public ModeExecutorFactory<GoToActionType, GoToLocalMode>
191{
192public:
193 explicit GoToLocalSkill(const rclcpp::NodeOptions & options)
194 : ModeExecutorFactory{_AUTO_APMS_PX4__GOTO_LOCAL_ACTION_NAME, options}
195 {
196 }
197};
198
199} // namespace auto_apms_px4
200
201#include "rclcpp_components/register_node_macro.hpp"
202RCLCPP_COMPONENTS_REGISTER_NODE(auto_apms_px4::GoToGlobalSkill)
203RCLCPP_COMPONENTS_REGISTER_NODE(auto_apms_px4::GoToLocalSkill)
Helper template class that creates a ModeExecutor for a custom PX4 mode implemented by inheriting fro...
Implementation of PX4 mode peers offered by px4_ros2_cpp enabling integration with AutoAPMS.
Definition mode.hpp:26