simple_planner v1.4.0
Loading...
Searching...
No Matches
utils.hpp
Go to the documentation of this file.
1// Copyright Institute for Automotive Engineering (ika), RWTH Aachen University
2// SPDX-License-Identifier: Apache-2.0
3
4namespace simple_planner {
5
6template <typename T>
7void SimplePlannerNode::declareAndLoadParameter(const std::string& name,
8 T& param,
9 const std::string& description,
10 const bool add_to_auto_reconfigurable_params,
11 const bool is_required,
12 const bool read_only,
13 const std::optional<double>& from_value,
14 const std::optional<double>& to_value,
15 const std::optional<double>& step_value,
16 const std::string& additional_constraints) {
17 rcl_interfaces::msg::ParameterDescriptor param_desc;
18 param_desc.description = description;
19 param_desc.additional_constraints = additional_constraints;
20 param_desc.read_only = read_only;
21
22 auto type = rclcpp::ParameterValue(param).get_type();
23
24 if (from_value.has_value() && to_value.has_value()) {
25 if constexpr (std::is_integral_v<T>) {
26 rcl_interfaces::msg::IntegerRange range;
27 T step = static_cast<T>(step_value.has_value() ? step_value.value() : 1);
28 range.set__from_value(static_cast<T>(from_value.value())).set__to_value(static_cast<T>(to_value.value())).set__step(step);
29 param_desc.integer_range = {range};
30 } else if constexpr (std::is_floating_point_v<T>) {
31 rcl_interfaces::msg::FloatingPointRange range;
32 T step = static_cast<T>(step_value.has_value() ? step_value.value() : 1.0);
33 range.set__from_value(static_cast<T>(from_value.value())).set__to_value(static_cast<T>(to_value.value())).set__step(step);
34 param_desc.floating_point_range = {range};
35 } else {
36 RCLCPP_WARN(this->get_logger(), "Parameter type of parameter '%s' does not support specifying a range", name.c_str());
37 }
38 }
39
40 this->declare_parameter(name, type, param_desc);
41
42 try {
43 param = this->get_parameter(name).get_value<T>();
44 std::stringstream ss;
45 ss << "Loaded parameter '" << name << "': ";
46 if constexpr (is_vector_v<T>) {
47 ss << "[";
48 for (const auto& element : param) ss << element << (&element != &param.back() ? ", " : "");
49 ss << "]";
50 } else {
51 ss << param;
52 }
53 RCLCPP_INFO_STREAM(this->get_logger(), ss.str());
54 } catch (rclcpp::exceptions::ParameterUninitializedException&) {
55 if (is_required) {
56 RCLCPP_FATAL_STREAM(this->get_logger(), "Missing required parameter '" << name << "', exiting");
57 exit(EXIT_FAILURE);
58 } else {
59 std::stringstream ss;
60 ss << "Missing parameter '" << name << "', using default value: ";
61 if constexpr (is_vector_v<T>) {
62 ss << "[";
63 for (const auto& element : param) ss << element << (&element != &param.back() ? ", " : "");
64 ss << "]";
65 } else {
66 ss << param;
67 }
68 RCLCPP_WARN_STREAM(this->get_logger(), ss.str());
69 this->set_parameters({rclcpp::Parameter(name, rclcpp::ParameterValue(param))});
70 }
71 }
72
73 if (add_to_auto_reconfigurable_params) {
74 std::function<void(const rclcpp::Parameter&)> setter = [&param](const rclcpp::Parameter& p) { param = p.get_value<T>(); };
75 auto_reconfigurable_params_.push_back(std::make_tuple(name, setter));
76 }
77}
78
79rcl_interfaces::msg::SetParametersResult SimplePlannerNode::parametersCallback(const std::vector<rclcpp::Parameter>& parameters) {
80 rcl_interfaces::msg::SetParametersResult result;
81 result.successful = false;
82
83 for (const auto& param : parameters) {
84 // check for specific parameter constraints
85 if (param.get_name() == "a_decel") {
86 if (param.as_double() >= 0.0) {
87 result.successful = false;
88 result.reason = "a_decel (" + std::to_string(param.as_double()) + ") must be < 0.0";
89 RCLCPP_WARN(this->get_logger(), "Rejected parameter change for 'a_decel': %s", result.reason.c_str());
90 break;
91 } else if (a_max_decel_ > param.as_double()) {
92 result.successful = false;
93 result.reason =
94 "a_max_decel (" + std::to_string(a_max_decel_) + ") must be <= a_decel (" + std::to_string(param.as_double()) + ")";
95 RCLCPP_WARN(this->get_logger(), "Rejected parameter change for 'a_decel': %s", result.reason.c_str());
96 break;
97 }
98 } else if (param.get_name() == "a_max_decel") {
99 if (param.as_double() >= 0.0) {
100 result.successful = false;
101 result.reason = "a_max_decel (" + std::to_string(param.as_double()) + ") must be < 0.0";
102 RCLCPP_WARN(this->get_logger(), "Rejected parameter change for 'a_max_decel': %s", result.reason.c_str());
103 break;
104 } else if (param.as_double() > a_decel_) {
105 result.successful = false;
106 result.reason =
107 "a_max_decel (" + std::to_string(param.as_double()) + ") must be <= a_decel (" + std::to_string(a_decel_) + ")";
108 RCLCPP_WARN(this->get_logger(), "Rejected parameter change for 'a_max_decel': %s", result.reason.c_str());
109 break;
110 }
111 }
112
113 // apply parameter change
114 for (auto& auto_reconfigurable_param : auto_reconfigurable_params_) {
115 if (param.get_name() == std::get<0>(auto_reconfigurable_param)) {
116 std::get<1>(auto_reconfigurable_param)(param);
117 RCLCPP_INFO(this->get_logger(), "Reconfigured parameter '%s'", param.get_name().c_str());
118 result.successful = true;
119 break;
120 }
121 }
122 }
123
124 return result;
125}
126
127bool SimplePlannerNode::requiresTransform(const std_msgs::msg::Header& source_header,
128 const std_msgs::msg::Header& target_header) {
129 return source_header.frame_id != target_header.frame_id || source_header.stamp.sec != target_header.stamp.sec ||
130 source_header.stamp.nanosec != target_header.stamp.nanosec;
131}
132
140SimplePath SimplePlannerNode::transformPath(const SimplePath& path, const std_msgs::msg::Header& target_header) {
141 SimplePath transformed_path;
142 transformed_path.header = target_header;
143
144 if (path.points.empty()) {
145 return transformed_path;
146 }
147 if (!requiresTransform(path.header, target_header)) {
148 return path;
149 }
150
151 geometry_msgs::msg::TransformStamped tf;
152 try {
153 tf = tf2_buffer_->lookupTransform(target_header.frame_id, target_header.stamp, path.header.frame_id, path.header.stamp,
154 fixed_over_time_frame_id_, rclcpp::Duration::from_seconds(1.0));
155 for (const auto& point : path.points) {
156 geometry_msgs::msg::PointStamped point_msg, transformed_point_msg;
157 point_msg.header = path.header;
158 point_msg.point.x = point.position.x();
159 point_msg.point.y = point.position.y();
160 point_msg.point.z = 0.0;
161 tf2::doTransform(point_msg, transformed_point_msg, tf);
162 SimplePathPoint transformed_point = point;
163 transformed_point.position = Eigen::Vector2d(transformed_point_msg.point.x, transformed_point_msg.point.y);
164 transformed_path.points.push_back(transformed_point);
165 }
166 } catch (tf2::TransformException& ex) {
167 RCLCPP_WARN(this->get_logger(), "Could not transform path: %s. Returning an empty path.", ex.what());
168 }
169
170 return transformed_path;
171}
172
173void SimplePlannerNode::health(diagnostic_updater::DiagnosticStatusWrapper& stat) {
174 stat.summary(health_.status, health_.message);
175 for (const auto& [key, value] : health_.key_value_pairs) {
176 stat.add(key, value);
177 }
178}
179
180void SimplePlannerNode::setHealth(const unsigned char status,
181 const std::string& msg,
182 const std::map<std::string, std::string>& key_value_pairs) {
183 health_.status = status;
184 health_.message = msg;
185 health_.key_value_pairs = key_value_pairs;
186}
187
189 switch (state) {
191 return "NoPublish";
193 return "Standstill";
195 return "SafeStop";
197 return "FollowRoute";
198 default:
199 return "Unknown";
200 }
201}
202
203std::string SimplePlannerNode::turnSignalToString(const uint8_t& turn_signal) {
204 switch (turn_signal) {
205 case route_planning_msgs::msg::LaneElement::SUGGESTED_TURN_SIGNAL_NONE:
206 return "None";
207 case route_planning_msgs::msg::LaneElement::SUGGESTED_TURN_SIGNAL_LEFT:
208 return "Left";
209 case route_planning_msgs::msg::LaneElement::SUGGESTED_TURN_SIGNAL_RIGHT:
210 return "Right";
211 case route_planning_msgs::msg::LaneElement::SUGGESTED_TURN_SIGNAL_HAZARD:
212 return "Hazard";
213 default:
214 return "Unknown";
215 }
216}
217
218} // namespace simple_planner
void declareAndLoadParameter(const std::string &name, T &param, const std::string &description, const bool add_to_auto_reconfigurable_params=true, const bool is_required=false, const bool read_only=false, const std::optional< double > &from_value=std::nullopt, const std::optional< double > &to_value=std::nullopt, const std::optional< double > &step_value=std::nullopt, const std::string &additional_constraints="")
Declares a ROS parameter, loads its value and optionally registers it for runtime updates.
Definition utils.hpp:7
std::unique_ptr< tf2_ros::Buffer > tf2_buffer_
std::vector< std::tuple< std::string, std::function< void(const rclcpp::Parameter &)> > > auto_reconfigurable_params_
Auto-reconfigurable parameters for dynamic reconfiguration.
rcl_interfaces::msg::SetParametersResult parametersCallback(const std::vector< rclcpp::Parameter > &parameters)
Handles reconfiguration when a parameter value is changed.
Definition utils.hpp:79
void health(diagnostic_updater::DiagnosticStatusWrapper &stat)
Function called by diagnostic updater to populate diagnostics status.
Definition utils.hpp:173
static std::string plannerStateToString(const PlannerState &state)
Converts a PlannerState enum to a string representation.
Definition utils.hpp:188
static std::string turnSignalToString(const uint8_t &turn_signal)
Converts a turn signal value to a string representation.
Definition utils.hpp:203
void setHealth(const unsigned char status, const std::string &msg, const std::map< std::string, std::string > &key_value_pairs={})
Sets the health information.
Definition utils.hpp:180
struct simple_planner::SimplePlannerNode::DiagnosticStatus health_
SimplePath transformPath(const SimplePath &path, const std_msgs::msg::Header &target_header)
Transforms a simple path into the requested target frame and timestamp.
Definition utils.hpp:140
static bool requiresTransform(const std_msgs::msg::Header &source_header, const std_msgs::msg::Header &target_header)
Checks whether a transform between two stamped frames is required.
Definition utils.hpp:127
Namespace for simple_planner package.
constexpr bool is_vector_v
std::vector< SimplePathPoint > points
std_msgs::msg::Header header
std::map< std::string, std::string > key_value_pairs