Carma-platform v4.2.0
CARMA Platform is built on robot operating system (ROS) and utilizes open source software (OSS) that enables Cooperative Driving Automation (CDA) features to allow Automated Driving Systems to interact and cooperate with infrastructure and other vehicles through communication.
mobilitypath_publisher.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2019-2022 LEIDOS.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
17
19{
20 namespace std_ph = std::placeholders;
21
22 MobilityPathPublication::MobilityPathPublication(const rclcpp::NodeOptions &options)
23 : carma_ros2_utils::CarmaLifecycleNode(options)
24 {
25 // Create initial config
26 config_ = Config();
27
28 // Declare parameters
29 config_.path_pub_rate = declare_parameter<double>("path_pub_rate", config_.path_pub_rate);
30 config_.vehicle_id = declare_parameter<std::string>("vehicle_id", config_.vehicle_id);
31 }
32
33 rcl_interfaces::msg::SetParametersResult MobilityPathPublication::parameter_update_callback(const std::vector<rclcpp::Parameter> &parameters)
34 {
35 auto error = update_params<double>({{"path_pub_rate", config_.path_pub_rate}}, parameters);
36 auto error_2 = update_params<std::string>({{"vehicle_id", config_.vehicle_id}}, parameters);
37
38 rcl_interfaces::msg::SetParametersResult result;
39
40 result.successful = !error && !error_2;
41
42 return result;
43 }
44
45 carma_ros2_utils::CallbackReturn MobilityPathPublication::handle_on_configure(const rclcpp_lifecycle::State &)
46 {
47 RCLCPP_INFO_STREAM(this->get_logger(), "MobilityPathPublication trying to configure");
48
49 // Reset config
50 config_ = Config();
51
52 // Load parameters
53 get_parameter<double>("path_pub_rate", config_.path_pub_rate);
54 get_parameter<std::string>("vehicle_id", config_.vehicle_id);
55
56 RCLCPP_INFO_STREAM(get_logger(), "Loaded params: " << config_);
57
58 // Register runtime parameter update callback
59 add_on_set_parameters_callback(std::bind(&MobilityPathPublication::parameter_update_callback, this, std_ph::_1));
60
61 // Setup subscribers
62 traj_sub_ = create_subscription<carma_planning_msgs::msg::TrajectoryPlan>("plan_trajectory", 5,
63 std::bind(&MobilityPathPublication::trajectory_cb, this, std_ph::_1));
64 bsm_sub_ = create_subscription<carma_v2x_msgs::msg::BSM>("bsm_outbound", 1,
65 std::bind(&MobilityPathPublication::bsm_cb, this, std_ph::_1));
66
67 guidance_state_sub_ = create_subscription<carma_planning_msgs::msg::GuidanceState>("guidance_state", 5, std::bind(&MobilityPathPublication::guidance_state_cb, this, std::placeholders::_1));
68
69 georeference_sub_ = create_subscription<std_msgs::msg::String>("georeference", 1,
70 std::bind(&MobilityPathPublication::georeference_cb, this, std_ph::_1));
71
72 // Setup publishers
73 path_pub_ = create_publisher<carma_v2x_msgs::msg::MobilityPath>("mobility_path_msg", 5);
74
75
76 // Return success if everthing initialized successfully
77 return CallbackReturn::SUCCESS;
78 }
79
80 void MobilityPathPublication::guidance_state_cb(const carma_planning_msgs::msg::GuidanceState::UniquePtr msg)
81 {
83 }
84
85 carma_ros2_utils::CallbackReturn MobilityPathPublication::handle_on_activate(const rclcpp_lifecycle::State &prev_state)
86 {
87 // Timer setup
88 int path_pub_period_millisecs = (1 / config_.path_pub_rate) * 1000; // Conversion from frequency (Hz) to milliseconds time period
89 path_pub_timer_ = create_timer(get_clock(),
90 std::chrono::milliseconds(path_pub_period_millisecs),
92
93 return CallbackReturn::SUCCESS;
94 }
95
97 {
98 // update timestamp of mobilitypath
99 uint64_t millisecs = get_clock()->now().nanoseconds() / 1000000;
100 latest_mobility_path_.m_header.timestamp = millisecs; //time in millisecond
103 return true;
104 }
105
106 void MobilityPathPublication::georeference_cb(const std_msgs::msg::String::UniquePtr msg)
107 {
108 // Build projector from proj string
109 if (georeference_ != msg->data)
110 {
111 georeference_ = msg->data;
112 map_projector_ = std::make_shared<lanelet::projection::LocalFrameProjector>(msg->data.c_str());
113 }
114 }
115
116 void MobilityPathPublication::trajectory_cb(const carma_planning_msgs::msg::TrajectoryPlan::UniquePtr msg)
117 {
118 latest_trajectory_ = *msg;
120 }
121
122 void MobilityPathPublication::bsm_cb(const carma_v2x_msgs::msg::BSM::UniquePtr msg)
123 {
124 bsm_core_ = msg->core_data;
125 }
126
127 carma_v2x_msgs::msg::MobilityPath MobilityPathPublication::mobility_path_message_generator(const carma_planning_msgs::msg::TrajectoryPlan& trajectory_plan)
128 {
129 carma_v2x_msgs::msg::MobilityPath mobility_path_msg;
130 // TODO this caluclation uses a poor assumption of zero latency see https://github.com/usdot-fhwa-stol/carma-platform/issues/1606
131 uint64_t millisecs = get_clock()->now().nanoseconds() / 1000000;
132 mobility_path_msg.m_header = compose_mobility_header(millisecs);
133
134 if (!map_projector_) {
135 RCLCPP_ERROR_STREAM(this->get_logger(), "MobilityPath cannot be populated as map projection is not available");
136 return mobility_path_msg;
137 }
138
139 carma_v2x_msgs::msg::Trajectory mob_path_traj = trajectory_plan_to_trajectory(trajectory_plan.trajectory_points);
140 mobility_path_msg.trajectory = mob_path_traj;
141
142 return mobility_path_msg;
143 }
144
145 carma_v2x_msgs::msg::MobilityHeader MobilityPathPublication::compose_mobility_header(uint64_t time)
146 {
147 carma_v2x_msgs::msg::MobilityHeader header;
148 header.sender_id = config_.vehicle_id;
149 header.recipient_id = recipient_id;
150 header.sender_bsm_id = BSMHelper::BSMHelper::bsmIDtoString(bsm_core_.id);
151
152 // random GUID that identifies this particular plan for future reference
153 header.plan_id = boost::uuids::to_string(boost::uuids::random_generator()());
154 header.timestamp = time; //time in millisecond
155
156 return header;
157 }
158
159 carma_v2x_msgs::msg::Trajectory MobilityPathPublication::trajectory_plan_to_trajectory(const std::vector<carma_planning_msgs::msg::TrajectoryPlanPoint>& traj_points) const
160 {
161 carma_v2x_msgs::msg::Trajectory traj;
162
163 if (traj_points.empty()) {
164 throw std::invalid_argument("Received an empty vector of Trajectory Plan Points");
165 }
166
167 carma_v2x_msgs::msg::LocationECEF ecef_location = trajectory_point_to_ECEF(traj_points[0]); //m to cm to fit the msg standard
168
169 if (traj_points.size() < 2){
170 RCLCPP_WARN_STREAM(this->get_logger(), "Received Trajectory Plan is too small");
171 traj.offsets = {};
172 }
173 else{
174 carma_v2x_msgs::msg::LocationECEF prev_point = ecef_location;
175 for (size_t i=1; i<traj_points.size(); i++){
176
177 carma_v2x_msgs::msg::LocationOffsetECEF offset;
178 carma_v2x_msgs::msg::LocationECEF new_point = trajectory_point_to_ECEF(traj_points[i]); //m to cm to fit the msg standard
179 offset.offset_x = (int16_t)(new_point.ecef_x - prev_point.ecef_x);
180 offset.offset_y = (int16_t)(new_point.ecef_y - prev_point.ecef_y);
181 offset.offset_z = (int16_t)(new_point.ecef_z - prev_point.ecef_z);
182 prev_point = new_point;
183 traj.offsets.push_back(offset);
184 if( i >= 60 ){ break;};
185 }
186 }
187
188 traj.location = ecef_location;
189
190 return traj;
191 }
192
193 carma_v2x_msgs::msg::LocationECEF MobilityPathPublication::trajectory_point_to_ECEF(const carma_planning_msgs::msg::TrajectoryPlanPoint& traj_point) const
194 {
195 if (!map_projector_) {
196 throw std::invalid_argument("No map projector available for ecef conversion");
197 }
198 carma_v2x_msgs::msg::LocationECEF location;
199
200 lanelet::BasicPoint3d ecef_point = map_projector_->projectECEF({traj_point.x, traj_point.y, 0.0}, 1);
201 location.ecef_x = ecef_point.x() * 100.0;
202 location.ecef_y = ecef_point.y() * 100.0;
203 location.ecef_z = ecef_point.z() * 100.0;
204
205 return location;
206 }
207
208} // mobilitypath_publisher
209
210#include "rclcpp_components/register_node_macro.hpp"
211
212// Register the component with class_loader
213RCLCPP_COMPONENTS_REGISTER_NODE(mobilitypath_publisher::MobilityPathPublication)
The class responsible for publishing MobilityPath messages based on the latest trajectory plan.
void georeference_cb(const std_msgs::msg::String::UniquePtr msg)
Callback for map projection string to define lat/lon -> map conversion.
void guidance_state_cb(const carma_planning_msgs::msg::GuidanceState::UniquePtr msg)
Callback for the Guidance State.
carma_ros2_utils::SubPtr< carma_planning_msgs::msg::GuidanceState > guidance_state_sub_
void trajectory_cb(const carma_planning_msgs::msg::TrajectoryPlan::UniquePtr msg)
Callback for the trajectory plan subscriber, which stores the latest trajectory plan locally and stor...
carma_ros2_utils::SubPtr< std_msgs::msg::String > georeference_sub_
carma_v2x_msgs::msg::MobilityHeader compose_mobility_header(uint64_t time)
Generates a MobilityHeader to be used for a published MobilityPath message.
carma_planning_msgs::msg::TrajectoryPlan latest_trajectory_
carma_ros2_utils::SubPtr< carma_planning_msgs::msg::TrajectoryPlan > traj_sub_
rcl_interfaces::msg::SetParametersResult parameter_update_callback(const std::vector< rclcpp::Parameter > &parameters)
Function callback for dynamic parameter updates.
carma_v2x_msgs::msg::LocationECEF trajectory_point_to_ECEF(const carma_planning_msgs::msg::TrajectoryPlanPoint &traj_point) const
Converts Trajectory Plan Point to ECEF (accepts meters and outputs in cm)
std::shared_ptr< lanelet::projection::LocalFrameProjector > map_projector_
carma_ros2_utils::CallbackReturn handle_on_configure(const rclcpp_lifecycle::State &)
carma_v2x_msgs::msg::MobilityPath latest_mobility_path_
carma_ros2_utils::CallbackReturn handle_on_activate(const rclcpp_lifecycle::State &)
carma_ros2_utils::SubPtr< carma_v2x_msgs::msg::BSM > bsm_sub_
carma_ros2_utils::PubPtr< carma_v2x_msgs::msg::MobilityPath > path_pub_
MobilityPathPublication(const rclcpp::NodeOptions &)
MobilityPathPublication constructor.
bool spin_callback()
Spin callback, which will be called frequently based on the configured spin rate.
void bsm_cb(const carma_v2x_msgs::msg::BSM::UniquePtr msg)
Callback for the BSM subscriber, which stores the BSM's BSMCoreData locally.
carma_v2x_msgs::msg::MobilityPath mobility_path_message_generator(const carma_planning_msgs::msg::TrajectoryPlan &trajectory_plan)
Generates a MobilityPath message from a TrajectoryPlan.
carma_v2x_msgs::msg::Trajectory trajectory_plan_to_trajectory(const std::vector< carma_planning_msgs::msg::TrajectoryPlanPoint > &traj_points) const
Converts a Trajectory Plan to a (Mobility) Trajectory.
auto to_string(const UtmZone &zone) -> std::string
Definition: utm_zone.cpp:21
Stuct containing the algorithm configuration values for mobilitypath_publisher.