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.
bsm_to_external_object_convertor.cpp
Go to the documentation of this file.
1// Copyright 2019-2023 Leidos
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// http://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 <algorithm>
16#include <string>
17#include <vector>
18
21
22#include <carma_perception_msgs/msg/external_object.hpp>
23
24namespace motion_computation
25{
26namespace conversion
27{
29 const carma_v2x_msgs::msg::BSM & in_msg, carma_perception_msgs::msg::ExternalObject & out_msg,
30 const std::string & map_frame_id, double pred_period, double pred_step_size,
31 const lanelet::projection::LocalFrameProjector & map_projector,
32 tf2::Quaternion ned_in_map_rotation)
33{
34 out_msg.presence_vector |= carma_perception_msgs::msg::ExternalObject::BSM_ID_PRESENCE_VECTOR;
35
36 // assume any BSM is a dynamic object since its sent be a vehicle
37 out_msg.dynamic_obj = true;
38 out_msg.presence_vector |= carma_perception_msgs::msg::ExternalObject::DYNAMIC_OBJ_PRESENCE;
39
41 // Generate a unique object id from the bsm id
42 out_msg.id = 0;
43 for (int i = in_msg.core_data.id.size() - 1; i >= 0;
44 i--) { // using signed iterator to handle empty case
45 // each byte of the bsm id gets placed in one byte of the object id.
46 // This should result in very large numbers which will be unlikely to
47 // conflict with standard detections
48 out_msg.id |= in_msg.core_data.id[i] << (8 * i);
49 }
50 out_msg.presence_vector |= carma_perception_msgs::msg::ExternalObject::ID_PRESENCE_VECTOR;
51
53 out_msg.bsm_id = in_msg.core_data.id;
54 out_msg.presence_vector |= carma_perception_msgs::msg::ExternalObject::BSM_ID_PRESENCE_VECTOR;
55
57 // Compute the timestamp
58 out_msg.header.stamp = in_msg.header.stamp;
59 out_msg.header.frame_id = map_frame_id;
60
62
63 if (
64 in_msg.core_data.size.presence_vector &
65 carma_v2x_msgs::msg::VehicleSize::VEHICLE_LENGTH_AVAILABLE) {
66 // ExternalObject size is half of each dimension
67 out_msg.size.x = in_msg.core_data.size.vehicle_length / 2;
68 } else {
69 out_msg.size.x = 1.0; // value from mob path to external obj conversion
70 }
71
72 if (
73 in_msg.core_data.size.presence_vector &
74 carma_v2x_msgs::msg::VehicleSize::VEHICLE_WIDTH_AVAILABLE) {
75 // ExternalObject size is half of each dimension
76 out_msg.size.y = in_msg.core_data.size.vehicle_width / 2;
77 } else {
78 out_msg.size.y = 1.0; // value from mob path to external obj conversion
79 }
80
81 out_msg.size.z = 2.0; // value from mob path to external obj conversion
82
83 out_msg.object_type = carma_perception_msgs::msg::ExternalObject::SMALL_VEHICLE;
84
86 // Set the velocity
87 if (in_msg.core_data.presence_vector & carma_v2x_msgs::msg::BSMCoreData::SPEED_AVAILABLE) {
88 out_msg.presence_vector |= carma_perception_msgs::msg::ExternalObject::VELOCITY_PRESENCE_VECTOR;
89 float_t speed_mps = in_msg.core_data.speed;
90
91 out_msg.velocity.twist.linear.x = std::min(speed_mps, in_msg.core_data.SPEED_MAX);
92 }
93
94 // NOTE: The velocity covariance is not provided in the BSM. In order to
95 // compute it you need at least two BSM messages
96 // Tracking and associating BSM messages would be an increase in
97 // complexity for this conversion which is not warranted without an
98 // existing use case for the velocity covariance. If a use case is
99 // presented for it, such an addition can be made at that time.
100
102 // Compute the position covariance
103 // For computing confidence we will use the largest provided standard
104 // deviation of position
105 double largest_position_std =
106 std::max(in_msg.core_data.accuracy.semi_major, in_msg.core_data.accuracy.semi_minor);
107
108 double lat_variance = in_msg.core_data.accuracy.semi_minor * in_msg.core_data.accuracy.semi_minor;
109
110 double lon_variance = in_msg.core_data.accuracy.semi_major * in_msg.core_data.accuracy.semi_major;
111
112 double heading_variance =
113 in_msg.core_data.accuracy.orientation * in_msg.core_data.accuracy.orientation;
114
115 double position_confidence = 0.1; // Default will be 10% confidence. If the position accuracy is
116 // available then this value will be updated
117
118 // A standard deviation which is larger than the acceptable value to give
119 // 95% confidence interval on fitting the pedestrian within one 3.7m lane
120 constexpr double MAX_POSITION_STD = 1.85;
121
122 if (
123 (in_msg.core_data.accuracy.presence_vector |
124 carma_v2x_msgs::msg::PositionalAccuracy::ACCURACY_AVAILABLE) &&
125 (in_msg.core_data.accuracy.presence_vector |
126 carma_v2x_msgs::msg::PositionalAccuracy::ACCURACY_ORIENTATION_AVAILABLE)) {
127 // Both accuracies available
128
129 // NOTE: ExternalObject.msg does not clearly define what is meant by
130 // position confidence
131 // Here we are providing a linear scale based on the positional accuracy
132 // where 0 confidence would denote A standard deviation which is larger
133 // than the acceptable value to give 95% confidence interval on fitting
134 // the pedestrian within one 3.7m lane
135 // Set the confidence
136 // Without a way of getting the velocity confidence from the BSM we will use
137 // the position confidence for both
138 out_msg.confidence = 1.0 - std::min(1.0, fabs(largest_position_std / MAX_POSITION_STD));
139 out_msg.presence_vector |=
140 carma_perception_msgs::msg::ExternalObject::CONFIDENCE_PRESENCE_VECTOR;
141 } else if (
142 in_msg.core_data.accuracy.presence_vector |
143 carma_v2x_msgs::msg::PositionalAccuracy::ACCURACY_AVAILABLE) {
144 // Position accuracy available
145
146 heading_variance = 1.0; // Yaw variance is not available so mark as
147 // impossible perfect case
148
149 // Same calculation as shown in above condition. See that for description
150 out_msg.confidence = 1.0 - std::min(1.0, fabs(largest_position_std / MAX_POSITION_STD));
151 out_msg.presence_vector |=
152 carma_perception_msgs::msg::ExternalObject::CONFIDENCE_PRESENCE_VECTOR;
153 } else if (
154 in_msg.core_data.accuracy.presence_vector |
155 carma_v2x_msgs::msg::PositionalAccuracy::ACCURACY_ORIENTATION_AVAILABLE) {
156 // Orientation accuracy available
157
158 lat_variance = 1.0;
159 lon_variance = 1.0;
160 }
161 // Else: No accuracies available
162
164 // Compute the pose
165
166 if (
167 (in_msg.core_data.presence_vector & carma_v2x_msgs::msg::BSMCoreData::LATITUDE_AVAILABLE) &&
168 (in_msg.core_data.presence_vector & carma_v2x_msgs::msg::BSMCoreData::LONGITUDE_AVAILABLE) &&
169 (in_msg.core_data.presence_vector & carma_v2x_msgs::msg::BSMCoreData::ELEVATION_AVAILABLE) &&
170 (in_msg.core_data.presence_vector & carma_v2x_msgs::msg::BSMCoreData::HEADING_AVAILABLE)) {
171 double longitude = std::min(in_msg.core_data.longitude, in_msg.core_data.LONGITUDE_MAX);
172 longitude = std::max(longitude, in_msg.core_data.LONGITUDE_MIN);
173
174 double latitude = std::min(in_msg.core_data.latitude, in_msg.core_data.LATITUDE_MAX);
175 // latitude = std::max(latitude, in_msg.core_data.LATITUDE_MIN);
176
177 double elev = std::min(in_msg.core_data.elev, in_msg.core_data.ELEVATION_MAX);
178 // elev = std::max(elev, (float)in_msg.core_data.ELEVATION_MIN);
179
180 double heading = std::min(in_msg.core_data.heading, in_msg.core_data.HEADING_MAX);
181 // heading = std::max(heading, in_msg.core_data.HEADING_MIN);
182
183 out_msg.pose = impl::pose_from_gnss(
184 map_projector, ned_in_map_rotation, {latitude, longitude, elev}, heading, lat_variance,
185 lon_variance, heading_variance);
186 out_msg.presence_vector |= carma_perception_msgs::msg::ExternalObject::POSE_PRESENCE_VECTOR;
187 }
188 // Else: No pose available
189
190 out_msg.presence_vector |= carma_perception_msgs::msg::ExternalObject::POSE_PRESENCE_VECTOR;
191
193 // Compute predictions
194 // For prediction, if the prediction is available we will sample it
195 // If not then assume linear motion
196
197 std::vector<geometry_msgs::msg::Pose> predicted_poses;
198
199 predicted_poses = impl::sample_2d_linear_motion(
200 out_msg.pose.pose, out_msg.velocity.twist.linear.x, pred_period, pred_step_size);
201
202 out_msg.predictions = impl::predicted_poses_to_predicted_state(
203 predicted_poses, out_msg.velocity.twist.linear.x, rclcpp::Time(out_msg.header.stamp),
204 rclcpp::Duration(pred_step_size * 1e9), map_frame_id, out_msg.confidence, out_msg.confidence);
205 out_msg.presence_vector |= carma_perception_msgs::msg::ExternalObject::PREDICTION_PRESENCE_VECTOR;
206}
207
208} // namespace conversion
209} // namespace motion_computation
geometry_msgs::msg::PoseWithCovariance pose_from_gnss(const lanelet::projection::LocalFrameProjector &projector, const tf2::Quaternion &ned_in_map_rotation, const lanelet::GPSPoint &gps_point, const double &heading, const double lat_variance, const double lon_variance, const double heading_variance)
std::vector< carma_perception_msgs::msg::PredictedState > predicted_poses_to_predicted_state(const std::vector< geometry_msgs::msg::Pose > &poses, double constant_velocity, const rclcpp::Time &start_time, const rclcpp::Duration &step_size, const std::string &frame, double initial_pose_confidence, double initial_vel_confidence)
std::vector< geometry_msgs::msg::Pose > sample_2d_linear_motion(const geometry_msgs::msg::Pose &pose, double velocity, double period, double step_size)
void convert(const carma_v2x_msgs::msg::PSM &in_msg, carma_perception_msgs::msg::ExternalObject &out_msg, const std::string &map_frame_id, double pred_period, double pred_step_size, const lanelet::projection::LocalFrameProjector &map_projector, const tf2::Quaternion &ned_in_map_rotation, rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock)