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.
object_visualizer_node.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 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
18namespace object_visualizer
19{
20 namespace std_ph = std::placeholders;
21
22 Node::Node(const rclcpp::NodeOptions &options)
23 : carma_ros2_utils::CarmaLifecycleNode(options)
24 {
25 // Create initial config
26 config_ = Config();
27
28 // Declare parameters
29 config_.enable_external_objects_viz = declare_parameter<bool>("enable_external_objects_viz", config_.enable_external_objects_viz);
30 config_.enable_roadway_objects_viz = declare_parameter<bool>("enable_roadway_objects_viz", config_.enable_roadway_objects_viz);
31 config_.external_objects_viz_ns = declare_parameter<std::string>("external_objects_viz_ns", config_.external_objects_viz_ns);
32 config_.roadway_obstacles_viz_ns = declare_parameter<std::string>("roadway_obstacles_viz_ns", config_.roadway_obstacles_viz_ns);
33 config_.marker_shape = declare_parameter<uint8_t>("marker_shape", config_.marker_shape);
34
35 // Declare new parameters for pedestrian visualization
36 config_.use_pedestrian_icon = declare_parameter<bool>("use_pedestrian_icon", config_.use_pedestrian_icon);
37 config_.pedestrian_icon_path = declare_parameter<std::string>("pedestrian_icon_path", config_.pedestrian_icon_path);
38 config_.pedestrian_icon_scale = declare_parameter<double>("pedestrian_icon_scale", config_.pedestrian_icon_scale);
39 }
40
41 rcl_interfaces::msg::SetParametersResult Node::parameter_update_callback(const std::vector<rclcpp::Parameter> &parameters)
42 {
43 // Update parameters
44 auto error = update_params<bool>(
45 {
46 {"enable_external_objects_viz", config_.enable_external_objects_viz},
47 {"enable_roadway_objects_viz", config_.enable_roadway_objects_viz},
48 {"use_pedestrian_icon", config_.use_pedestrian_icon}
49 }, parameters);
50
51 auto error2 = update_params<std::string>(
52 {
53 {"external_objects_viz_ns", config_.external_objects_viz_ns},
54 {"roadway_obstacles_viz_ns", config_.roadway_obstacles_viz_ns},
55 {"pedestrian_icon_path", config_.pedestrian_icon_path}
56 }, parameters);
57
58 auto error3 = update_params<uint8_t>(
59 {
60 {"marker_shape", config_.marker_shape}
61 }, parameters);
62
63 auto error4 = update_params<double>(
64 {
65 {"pedestrian_icon_scale", config_.pedestrian_icon_scale}
66 }, parameters);
67
68 rcl_interfaces::msg::SetParametersResult result;
69
70 result.successful = !error && !error2 && !error3 && !error4;
71
72 return result;
73 }
74
75 carma_ros2_utils::CallbackReturn Node::handle_on_configure(const rclcpp_lifecycle::State &)
76 {
77 // Reset config
78 config_ = Config();
79
80 // Load parameters
81 get_parameter<bool>("enable_external_objects_viz", config_.enable_external_objects_viz);
82 get_parameter<bool>("enable_roadway_objects_viz", config_.enable_roadway_objects_viz);
83 get_parameter<std::string>("external_objects_viz_ns", config_.external_objects_viz_ns);
84 get_parameter<std::string>("roadway_obstacles_viz_ns", config_.roadway_obstacles_viz_ns);
85 get_parameter<uint8_t>("marker_shape", config_.marker_shape);
86 get_parameter<bool>("use_pedestrian_icon", config_.use_pedestrian_icon);
87 get_parameter<std::string>("pedestrian_icon_path", config_.pedestrian_icon_path);
88 get_parameter<double>("pedestrian_icon_scale", config_.pedestrian_icon_scale);
89
90 // Register runtime parameter update callback
91 add_on_set_parameters_callback(std::bind(&Node::parameter_update_callback, this, std_ph::_1));
92
93 // Setup subscribers
94 external_objects_sub_ = create_subscription<carma_perception_msgs::msg::ExternalObjectList>("external_objects", 10,
95 std::bind(&Node::external_objects_callback, this, std_ph::_1));
96
97 roadway_obstacles_sub_ = create_subscription<carma_perception_msgs::msg::RoadwayObstacleList>("roadway_obstacles", 10,
98 std::bind(&Node::roadway_obstacles_callback, this, std_ph::_1));
99
100 // Setup publishers
101 external_objects_viz_pub_ = create_publisher<visualization_msgs::msg::MarkerArray>("external_objects_viz", 10);
102 roadway_obstacles_viz_pub_ = create_publisher<visualization_msgs::msg::MarkerArray>("roadway_obstacles_viz", 10);
103
104 // Return success if everthing initialized successfully
105 return CallbackReturn::SUCCESS;
106 }
107
108 void Node::createPedestrianMarker(visualization_msgs::msg::Marker& marker,
109 const std_msgs::msg::Header& header,
110 const geometry_msgs::msg::Pose& pose,
111 size_t id,
112 const std::string& ns,
113 const geometry_msgs::msg::Vector3& size)
114 {
115 marker.header = header;
116 marker.ns = ns;
117 marker.id = id;
118 marker.pose = pose;
119
121 // Use a mesh resource marker for pedestrian representation
122 marker.type = visualization_msgs::msg::Marker::MESH_RESOURCE;
123 marker.mesh_resource = config_.pedestrian_icon_path;
124 marker.mesh_use_embedded_materials = true;
125
126 // Scale the pedestrian mesh appropriately
127 marker.scale.x = config_.pedestrian_icon_scale;
128 marker.scale.y = - config_.pedestrian_icon_scale; // Invert Y to fix the STL orientation
129 marker.scale.z = config_.pedestrian_icon_scale;
130
131 // White color for the pedestrian icon
132 marker.color.r = 1.0;
133 marker.color.g = 1.0;
134 marker.color.b = 1.0;
135 marker.color.a = 1.0;
136 } else {
137 // Fallback to a person-shaped marker using cylinder (if mesh isn't available)
138 marker.type = visualization_msgs::msg::Marker::CYLINDER;
139
140 // Use the provided size or default to a human-like proportion
141 marker.scale.x = std::max(0.5, size.x * 2.0); // Width
142 marker.scale.y = std::max(0.5, size.y * 2.0); // Depth
143 marker.scale.z = std::max(1.7, size.z * 2.0); // Height - typical human height
144
145 // Set the color to red for the pedestrian marker
146 marker.color.r = 1.0;
147 marker.color.g = 0.0;
148 marker.color.b = 0.0;
149 marker.color.a = 1.0;
150 }
151
152 marker.action = visualization_msgs::msg::Marker::ADD;
153 }
154
155 void Node::external_objects_callback(carma_perception_msgs::msg::ExternalObjectList::UniquePtr msg)
156 {
157 RCLCPP_DEBUG_STREAM(get_logger(), "external_objects_callback called");
158
160 RCLCPP_DEBUG_STREAM(get_logger(), "external_objects_callback called, but visualization is not enabled.");
161 return;
162 }
163
164 visualization_msgs::msg::MarkerArray viz_msg;
165 //delete all markers before adding new ones
166 visualization_msgs::msg::Marker marker;
167 viz_msg.markers.reserve(msg->objects.size() + 1); //+1 to account for delete all marker
168 marker.id = 0;
169 marker.action = visualization_msgs::msg::Marker::DELETEALL;
170 viz_msg.markers.push_back(marker);
171
172
173 size_t id = 0; // We always count the id from zero so we can delete markers later in a consistent manner
174
175 for (auto obj : msg->objects) {
176 visualization_msgs::msg::Marker marker;
177
178 // Pedestrian's will be represented as specialized icon/marker
179 if (obj.object_type == carma_perception_msgs::msg::ExternalObject::PEDESTRIAN) {
180 createPedestrianMarker(marker, msg->header, obj.pose.pose, id, config_.external_objects_viz_ns, obj.size);
181
182 // Adjust Z position to prevent clipping with ground
183 marker.pose.position.z = std::max(1.0, obj.size.z);
184 }
185 // All other detected objects will use the configured marker shape
186 else {
187 marker.header = msg->header;
189 marker.color.r = 0.0;
190 marker.color.g = 0.0;
191 marker.color.b = 1.0;
192 marker.color.a = 1.0;
193
194 marker.pose = obj.pose.pose;
195 marker.pose.position.z = std::max(1.0, obj.size.z); // lifts the marker above ground so that it doesn't clip
196
197 marker.id = id;
198 if (static_cast<int>(config_.marker_shape) < 1 || static_cast<int>(config_.marker_shape) > 3)
199 {
200 throw std::invalid_argument("Marker shape is not valid: " + std::to_string(static_cast<int>(config_.marker_shape)) + ". Please choose from 1: CUBE, 2: SPHERE, 3: CYLINDER");
201 }
202 marker.type = config_.marker_shape;
203 marker.action = visualization_msgs::msg::Marker::ADD;
204
205 // overwrite size in case any previous stack doesn't provide size
206 // such as carma_cooperative_perception at the moment
207 marker.scale.x = std::max(1.0, obj.size.x) * 2; // Size in carma is half the length/width/height
208 marker.scale.y = std::max(1.0, obj.size.y) * 2;
209 marker.scale.z = std::max(1.0, obj.size.z) * 2;
210 }
211
212 viz_msg.markers.push_back(marker);
213 id++;
214 }
215
217 external_objects_viz_pub_->publish(viz_msg);
218 }
219
220 void Node::clear_and_update_old_objects(visualization_msgs::msg::MarkerArray &viz_msg, size_t &old_size)
221 {
222 size_t size_swap = viz_msg.markers.size();
223
224 // Delete any markers from the previous message that are no longer in the current message
225 if (viz_msg.markers.size() < old_size) {
226 for (size_t i = viz_msg.markers.size(); i < old_size; ++i) {
227 visualization_msgs::msg::Marker marker;
228 marker.id = i;
229 marker.action = visualization_msgs::msg::Marker::DELETE;
230 viz_msg.markers.push_back(marker);
231 }
232 }
233
234 old_size = size_swap; // Assign the new size of added objects to the old size
235 }
236
237 void Node::roadway_obstacles_callback(carma_perception_msgs::msg::RoadwayObstacleList::UniquePtr msg)
238 {
239 RCLCPP_DEBUG_STREAM(get_logger(), "roadway_obstacles_callback called");
240
242 RCLCPP_DEBUG_STREAM(get_logger(), "roadway_obstacles_callback called, but visualization is not enabled.");
243 return;
244 }
245
246 visualization_msgs::msg::MarkerArray viz_msg;
247 //delete all markers before adding new ones
248 visualization_msgs::msg::Marker marker;
249 viz_msg.markers.reserve(msg->roadway_obstacles.size() + 1); //+1 to account for delete all marker
250 marker.id = 0;
251 marker.action = visualization_msgs::msg::Marker::DELETEALL;
252 viz_msg.markers.push_back(marker);
253
254 size_t id = 0; // We always count the id from zero so we can delete markers later in a consistent manner
255 for (auto obj : msg->roadway_obstacles) {
256 visualization_msgs::msg::Marker marker;
257
258 // Pedestrian's will be represented with a specialized icon
259 if (obj.object.object_type == carma_perception_msgs::msg::ExternalObject::PEDESTRIAN) {
260 createPedestrianMarker(marker, obj.object.header, obj.object.pose.pose, id,
261 config_.roadway_obstacles_viz_ns, obj.object.size);
262 }
263 // Connected vehicles will be green
264 else if (obj.connected_vehicle_type.type != carma_perception_msgs::msg::ConnectedVehicleType::NOT_CONNECTED) {
265 marker.header = obj.object.header;
267 marker.color.r = 0.0;
268 marker.color.g = 1.0;
269 marker.color.b = 0.0;
270 marker.color.a = 1.0;
271
272 marker.id = id;
273 marker.type = visualization_msgs::msg::Marker::CUBE;
274 marker.action = visualization_msgs::msg::Marker::ADD;
275 marker.pose = obj.object.pose.pose;
276 marker.scale.x = obj.object.size.x * 2.0; // Size in carma is half the length/width/height
277 marker.scale.y = obj.object.size.y * 2.0;
278 marker.scale.z = obj.object.size.z * 2.0;
279 }
280 // All other detected objects will be blue
281 else {
282 marker.header = obj.object.header;
284 marker.color.r = 0.0;
285 marker.color.g = 0.0;
286 marker.color.b = 1.0;
287 marker.color.a = 1.0;
288
289 marker.id = id;
290 marker.type = visualization_msgs::msg::Marker::CUBE;
291 marker.action = visualization_msgs::msg::Marker::ADD;
292 marker.pose = obj.object.pose.pose;
293 marker.scale.x = obj.object.size.x * 2.0;
294 marker.scale.y = obj.object.size.y * 2.0;
295 marker.scale.z = obj.object.size.z * 2.0;
296 }
297
298 viz_msg.markers.push_back(marker);
299 id++;
300 }
301
303 roadway_obstacles_viz_pub_->publish(viz_msg);
304 }
305
306} // object_visualizer
307
308#include "rclcpp_components/register_node_macro.hpp"
309
310// Register the component with class_loader
311RCLCPP_COMPONENTS_REGISTER_NODE(object_visualizer::Node)
This node provides RViz visualization messages for recieved ExternalObject and RoadwayObstacle messag...
void roadway_obstacles_callback(carma_perception_msgs::msg::RoadwayObstacleList::UniquePtr msg)
Roadway obstacles callback. Converts the message to a visualization message to republish.
void createPedestrianMarker(visualization_msgs::msg::Marker &marker, const std_msgs::msg::Header &header, const geometry_msgs::msg::Pose &pose, size_t id, const std::string &ns, const geometry_msgs::msg::Vector3 &size)
Creates a pedestrian marker with specialized visualization.
rcl_interfaces::msg::SetParametersResult parameter_update_callback(const std::vector< rclcpp::Parameter > &parameters)
Example callback for dynamic parameter updates.
carma_ros2_utils::CallbackReturn handle_on_configure(const rclcpp_lifecycle::State &)
carma_ros2_utils::PubPtr< visualization_msgs::msg::MarkerArray > roadway_obstacles_viz_pub_
void clear_and_update_old_objects(visualization_msgs::msg::MarkerArray &viz_msg, size_t &old_size)
Adds a marker deletion for a number of markers which is the delta between the new marker count and th...
carma_ros2_utils::SubPtr< carma_perception_msgs::msg::ExternalObjectList > external_objects_sub_
Node(const rclcpp::NodeOptions &)
Node constructor.
carma_ros2_utils::SubPtr< carma_perception_msgs::msg::RoadwayObstacleList > roadway_obstacles_sub_
carma_ros2_utils::PubPtr< visualization_msgs::msg::MarkerArray > external_objects_viz_pub_
void external_objects_callback(carma_perception_msgs::msg::ExternalObjectList::UniquePtr msg)
External objects callback. Converts the message to a visualization message to republish.
auto to_string(const UtmZone &zone) -> std::string
Definition: utm_zone.cpp:21
Stuct containing the algorithm configuration values for object_visualizer.
std::string pedestrian_icon_path
Path to the model file for pedestrian visualization.
double pedestrian_icon_scale
Scale factor to apply to the pedestrian icon model.
std::string external_objects_viz_ns
External Objects marker rviz namespace.
bool enable_roadway_objects_viz
If true then RViz markers will be forwarded for received carma_perception_msgs/RoadwayObstacleList me...
bool enable_external_objects_viz
If true then RViz markers will be forwarded for received carma_perception_msgs/ExternalObjectList mes...
bool use_pedestrian_icon
If true, pedestrians will be visualized using specialized icons/models instead of basic markers.
std::string roadway_obstacles_viz_ns
Roadway Obstacles marker rviz namespace.