trajectory_optimization v1.3.1
Loading...
Searching...
No Matches
dummy_input_generation_node.cpp
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
4#include <math.h>
5
6#include <chrono>
7#include <functional>
8#include <thread>
9
11
12#include <rclcpp_components/register_node_macro.hpp>
13
14RCLCPP_COMPONENTS_REGISTER_NODE(dummy_input_generation::DummyInputGenerationNode)
15
16
20namespace dummy_input_generation {
21
26DummyInputGenerationNode::DummyInputGenerationNode(const rclcpp::NodeOptions& options)
27 : Node("dummy_input_generation_node", options) {
28 // declare and load node parameters; setup node
29 this->declareAndLoadParameter("publish_frequency", publish_frequency_, "Publish frequency in Hz", true, true, false, 0.01,
30 100.0, 0.01);
31 this->declareAndLoadParameter("message_frame_id", message_frame_id_, "Common frame ID for all published messages");
32
33 this->declareAndLoadParameter("ego_state_model", ego_state_model_, "Ego state model used for published EgoData", true, false,
34 false, std::nullopt, std::nullopt, std::nullopt, "Valid values: ackermann, rws");
35 this->declareAndLoadParameter("ego_vel_lon", ego_vel_lon_, "Ego longitudinal velocity [m/s]", true, false, false, -20.0, 40.0,
36 0.1);
37 this->declareAndLoadParameter("ego_acc_lon", ego_acc_lon_, "Ego longitudinal acceleration [m/s^2]", true, false, false, -10.0,
38 10.0, 0.1);
39 this->declareAndLoadParameter("ego_steering_angle_ack", ego_steering_angle_ack_, "Ackermann steering angle [rad]", true, false,
40 false, -3.14 / 2, 3.14 / 2, 0.01);
41 this->declareAndLoadParameter("ego_steering_angle_front", ego_steering_angle_front_, "Front steering angle for RWS [rad]", true,
42 false, false, -3.14 / 2, 3.14 / 2, 0.01);
43 this->declareAndLoadParameter("ego_steering_angle_rear", ego_steering_angle_rear_, "Rear steering angle for RWS [rad]", true,
44 false, false, -3.14 / 2, 3.14 / 2, 0.01);
45 this->declareAndLoadParameter("ego_translation_to_geometric_center", ego_translation_to_geometric_center_,
46 "Translation from ego reference point to geometric center [x, y, z]");
47
48 this->declareAndLoadParameter("reference_n_states", reference_n_states_, "Number of reference trajectory states", true, true,
49 false, 2.0, 500.0, 1.0);
50 this->declareAndLoadParameter("reference_trajectory_horizon", reference_trajectory_horizon_,
51 "Reference trajectory horizon in seconds", true, true, false, 0.1, 60.0, 0.1);
52 this->declareAndLoadParameter("reference_standstill", reference_standstill_,
53 "Publish reference trajectory with standstill flag");
54 this->declareAndLoadParameter("reference_x0", reference_x0_, "Initial x position of reference trajectory", true, false, false,
55 -5.0, 5.0, 0.5);
56 this->declareAndLoadParameter("reference_y0", reference_y0_, "Initial y position of reference trajectory", true, false, false,
57 -5.0, 5.0, 0.5);
58 this->declareAndLoadParameter("reference_v0", reference_v0_, "Initial velocity of reference trajectory", true, false, false,
59 -10.0, 10.0, 0.5);
60 this->declareAndLoadParameter("reference_a", reference_a_, "Acceleration of reference trajectory", true, false, false, -5.0,
61 5.0, 0.5);
62 this->declareAndLoadParameter("reference_theta0", reference_theta0_, "Initial heading angle of reference trajectory [deg]",
63 true, false, false, -180.0, 180.0, 10.0);
64 this->declareAndLoadParameter("reference_omega", reference_omega_, "Angular velocity of reference trajectory [deg/s]", true,
65 false, false, -45.0, 45.0, 5.0);
66
67 this->declareAndLoadParameter("object_count", object_count_, "Number of objects in object list", true, false, false, 0.0, 100.0,
68 1.0);
69 this->declareAndLoadParameter("object_delta_x", object_delta_x_, "Delta x between objects");
70 this->declareAndLoadParameter("object_delta_y", object_delta_y_, "Delta y between objects");
71 this->declareAndLoadParameter("object_length", object_length_, "Object length [m]", true, false, false, 0.1, 20.0, 0.1);
72 this->declareAndLoadParameter("object_width", object_width_, "Object width [m]", true, false, false, 0.1, 10.0, 0.1);
73 this->declareAndLoadParameter("object_yaw", object_yaw_, "Object yaw [rad]", true, false, false, -3.14, 3.14, 0.01);
74
75 this->setup();
76}
77
78template <typename T>
80 T& param,
81 const std::string& description,
82 const bool add_to_auto_reconfigurable_params,
83 const bool is_required,
84 const bool read_only,
85 const std::optional<double>& from_value,
86 const std::optional<double>& to_value,
87 const std::optional<double>& step_value,
88 const std::string& additional_constraints) {
89 rcl_interfaces::msg::ParameterDescriptor param_desc;
90 param_desc.description = description;
91 param_desc.additional_constraints = additional_constraints;
92 param_desc.read_only = read_only;
93
94 auto type = rclcpp::ParameterValue(param).get_type();
95
96 if (from_value.has_value() && to_value.has_value()) {
97 if constexpr (std::is_integral_v<T>) {
98 rcl_interfaces::msg::IntegerRange range;
99 range.set__from_value(static_cast<T>(from_value.value())).set__to_value(static_cast<T>(to_value.value()));
100 if (step_value.has_value()) range.set__step(static_cast<T>(step_value.value()));
101 param_desc.integer_range = {range};
102 } else if constexpr (std::is_floating_point_v<T>) {
103 rcl_interfaces::msg::FloatingPointRange range;
104 range.set__from_value(static_cast<T>(from_value.value())).set__to_value(static_cast<T>(to_value.value()));
105 if (step_value.has_value()) range.set__step(static_cast<T>(step_value.value()));
106 param_desc.floating_point_range = {range};
107 } else {
108 RCLCPP_WARN(this->get_logger(), "Parameter type of parameter '%s' does not support specifying a range", name.c_str());
109 }
110 }
111
112 this->declare_parameter(name, type, param_desc);
113
114 try {
115 param = this->get_parameter(name).get_value<T>();
116 std::stringstream ss;
117 ss << "Loaded parameter '" << name << "': ";
118 if constexpr (is_vector_v<T>) {
119 ss << "[";
120 for (const auto& element : param) ss << element << (&element != &param.back() ? ", " : "");
121 ss << "]";
122 } else {
123 ss << param;
124 }
125 RCLCPP_INFO_STREAM(this->get_logger(), ss.str());
126 } catch (rclcpp::exceptions::ParameterUninitializedException&) {
127 if (is_required) {
128 RCLCPP_FATAL_STREAM(this->get_logger(), "Missing required parameter '" << name << "', exiting");
129 exit(EXIT_FAILURE);
130 } else {
131 std::stringstream ss;
132 ss << "Missing parameter '" << name << "', using default value: ";
133 if constexpr (is_vector_v<T>) {
134 ss << "[";
135 for (const auto& element : param) ss << element << (&element != &param.back() ? ", " : "");
136 ss << "]";
137 } else {
138 ss << param;
139 }
140 RCLCPP_WARN_STREAM(this->get_logger(), ss.str());
141 this->set_parameters({rclcpp::Parameter(name, rclcpp::ParameterValue(param))});
142 }
143 }
144
145 if (add_to_auto_reconfigurable_params) {
146 std::function<void(const rclcpp::Parameter&)> setter = [&param](const rclcpp::Parameter& p) { param = p.get_value<T>(); };
147 auto_reconfigurable_params_.push_back(std::make_tuple(name, setter));
148 }
149}
150
157rcl_interfaces::msg::SetParametersResult DummyInputGenerationNode::parametersCallback(
158 const std::vector<rclcpp::Parameter>& parameters) {
159 for (const auto& param : parameters) {
160 for (auto& auto_reconfigurable_param : auto_reconfigurable_params_) {
161 if (param.get_name() == std::get<0>(auto_reconfigurable_param)) {
162 std::get<1>(auto_reconfigurable_param)(param);
163 RCLCPP_INFO(this->get_logger(), "Reconfigured parameter '%s' to: %s", param.get_name().c_str(),
164 param.value_to_string().c_str());
165 break;
166 }
167 }
168 if (param.get_name() == "publish_frequency") {
170 }
171 }
172 // mark parameter change successful
173 rcl_interfaces::msg::SetParametersResult result;
174 result.successful = true;
175
176 return result;
177}
178
184 // create a callback for dynamic parameter configuration
186 this->add_on_set_parameters_callback(std::bind(&DummyInputGenerationNode::parametersCallback, this, std::placeholders::_1));
187
188 // set up publishers
189 trajectory_pub_ = this->create_publisher<trajectory_planning_msgs::msg::Trajectory>("~/reference_trajectory", 10);
190 RCLCPP_INFO(this->get_logger(), "Publishing Trajectories to '%s'", trajectory_pub_->get_topic_name());
191
192 egodata_pub_ = this->create_publisher<perception_msgs::msg::EgoData>("~/ego_data", 10);
193 RCLCPP_INFO(this->get_logger(), "Publishing EgoData to '%s'", egodata_pub_->get_topic_name());
194
195 object_list_pub_ = this->create_publisher<perception_msgs::msg::ObjectList>("~/object_list", 10);
196 RCLCPP_INFO(this->get_logger(), "Publishing to '%s'", object_list_pub_->get_topic_name());
197
199}
200
202 if (planning_timer_) {
203 planning_timer_->cancel();
204 planning_timer_.reset();
205 }
206 planning_timer_ = this->create_wall_timer(std::chrono::duration<double>(1.0 / publish_frequency_),
207 std::bind(&DummyInputGenerationNode::publish, this));
208 RCLCPP_INFO(this->get_logger(), "Planning timer updated to %.3f Hz.", publish_frequency_);
209}
210
216 // --- publish ego data ---
217
218 perception_msgs::msg::EgoData::UniquePtr egodata = std::make_unique<perception_msgs::msg::EgoData>();
219 if (ego_state_model_ == "ackermann") {
220 perception_msgs::object_access::initializeState(*egodata, perception_msgs::msg::EGO::MODEL_ID);
221 perception_msgs::object_access::setVelLon(*egodata, ego_vel_lon_);
222 perception_msgs::object_access::setAccLon(*egodata, ego_acc_lon_);
223 perception_msgs::object_access::setSteeringAngleAck(*egodata, ego_steering_angle_ack_);
224 } else if (ego_state_model_ == "rws") {
225 perception_msgs::object_access::initializeState(*egodata, perception_msgs::msg::EGORWS::MODEL_ID);
226 perception_msgs::object_access::setVelLon(*egodata, ego_vel_lon_);
227 perception_msgs::object_access::setVelLat(*egodata, 0.0);
228 perception_msgs::object_access::setAccLon(*egodata, ego_acc_lon_);
229 perception_msgs::object_access::setAccLat(*egodata, 0.0);
230 perception_msgs::object_access::setSteeringAngleFront(*egodata, ego_steering_angle_front_);
231 perception_msgs::object_access::setSteeringAngleRear(*egodata, ego_steering_angle_rear_);
232 } else {
233 RCLCPP_FATAL(this->get_logger(), "Invalid ego_state_model '%s'. Valid values are 'ackermann' and 'rws'.",
234 ego_state_model_.c_str());
235 exit(EXIT_FAILURE);
236 }
237 egodata->length = EGO_LENGTH;
238 egodata->width = EGO_WIDTH;
239 egodata->height = OBJECT_HEIGHT;
240 egodata->state.reference_point.translation_to_geometric_center.x = ego_translation_to_geometric_center_[0];
241 egodata->state.reference_point.translation_to_geometric_center.y = ego_translation_to_geometric_center_[1];
242 egodata->state.reference_point.translation_to_geometric_center.z = ego_translation_to_geometric_center_[2];
243 egodata->header.stamp = this->now();
244 egodata->header.frame_id = message_frame_id_;
245 egodata_pub_->publish(std::move(egodata));
246
247 // --- publish trajectory ---
248
249 trajectory_planning_msgs::msg::Trajectory::UniquePtr trajectory = std::make_unique<trajectory_planning_msgs::msg::Trajectory>();
250 trajectory_planning_msgs::trajectory_access::initializeTrajectory(
251 *trajectory, trajectory_planning_msgs::msg::REFERENCE::TYPE_ID, reference_n_states_);
252
253 trajectory->header.stamp = this->now();
254 trajectory->header.frame_id = message_frame_id_;
255 trajectory_planning_msgs::trajectory_access::setStandstill(*trajectory, reference_standstill_);
256
257 double t = 0.0;
259 double x = reference_x0_;
260 double y = reference_y0_;
261 double theta = reference_theta0_;
262 double v = reference_v0_;
263 std::vector<double> state0 = {t, x, y, v};
264 trajectory_planning_msgs::trajectory_access::setState(*trajectory, state0, 0);
265
266 for (int i = 1; i < reference_n_states_; i++) {
267 double theta_rad = theta * M_PI / 180.0;
268 double vx = v * std::cos(theta_rad);
269 double vy = v * std::sin(theta_rad);
270 double ax = reference_a_ * std::cos(theta_rad);
271 double ay = reference_a_ * std::sin(theta_rad);
272
273 t += dt;
274 x = x + vx * dt + 0.5 * ax * dt * dt;
275 y = y + vy * dt + 0.5 * ay * dt * dt;
276 vx = vx + ax * dt;
277 vy = vy + ay * dt;
278 v = std::sqrt(vx * vx + vy * vy);
279 theta_rad = theta_rad + reference_omega_ * M_PI / 180.0 * dt;
280 theta = theta_rad * 180.0 / M_PI;
281
282 std::vector<double> state = {t, x, y, v};
283 trajectory_planning_msgs::trajectory_access::setState(*trajectory, state, i);
284 }
285
286 trajectory_pub_->publish(std::move(trajectory));
287 RCLCPP_DEBUG(this->get_logger(), "Published trajectory");
288
289 // --- publish object list ---
290
291 perception_msgs::msg::ObjectList::UniquePtr object_list = std::make_unique<perception_msgs::msg::ObjectList>();
292 object_list->header.stamp = this->now();
293 object_list->header.frame_id = message_frame_id_;
294
295 for (int i = 0; i < object_count_; i++) {
296 perception_msgs::msg::Object obj;
297 perception_msgs::object_access::initializeState(obj, perception_msgs::msg::ISCACTR::MODEL_ID);
298 double x = object_delta_x_ * (i + 1);
299 double y = object_delta_y_ * (i + 1);
300 double h = OBJECT_HEIGHT;
301 double z = h / 2;
302 perception_msgs::object_access::setX(obj, x);
303 perception_msgs::object_access::setY(obj, y);
304 perception_msgs::object_access::setZ(obj, z);
305 perception_msgs::object_access::setYaw(obj, object_yaw_);
306 perception_msgs::object_access::setLength(obj, object_length_);
307 perception_msgs::object_access::setWidth(obj, object_width_);
308 perception_msgs::object_access::setHeight(obj, h);
309 object_list->objects.push_back(obj);
310 }
311
312 object_list_pub_->publish(std::move(object_list));
313}
314
315} // namespace dummy_input_generation
Publishes configurable dummy ego, object, and reference trajectory inputs.
void setup()
Sets up subscribers, publishers, etc. to configure the node.
OnSetParametersCallbackHandle::SharedPtr parameters_callback_
void publish()
Publish the current dummy ego state, object list, and reference trajectory.
static constexpr double EGO_WIDTH
Default ego vehicle width used for published EgoData messages in meters.
std::vector< std::tuple< std::string, std::function< void(const rclcpp::Parameter &)> > > auto_reconfigurable_params_
rclcpp::Publisher< trajectory_planning_msgs::msg::Trajectory >::SharedPtr trajectory_pub_
static constexpr double EGO_LENGTH
Default ego vehicle length used for published EgoData messages in meters.
rcl_interfaces::msg::SetParametersResult parametersCallback(const std::vector< rclcpp::Parameter > &parameters)
Handles reconfiguration when a parameter value is changed.
static constexpr double OBJECT_HEIGHT
Default object and ego vehicle height used for published messages in meters.
rclcpp::Publisher< perception_msgs::msg::ObjectList >::SharedPtr object_list_pub_
DummyInputGenerationNode(const rclcpp::NodeOptions &options)
Constructor.
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 and loads a ROS parameter.
void createPlanningTimer()
Recreate the periodic publish timer based on the configured frequency.
rclcpp::Publisher< perception_msgs::msg::EgoData >::SharedPtr egodata_pub_
Namespace for dummy_input_generation package.