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_detection_tracking_worker.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2019-2021 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#include <tf2_ros/transform_listener.h>
18#include <tf2_geometry_msgs/tf2_geometry_msgs.h>
19#include <tf2/LinearMath/Quaternion.h>
20#include <tf2/transform_datatypes.h>
21#include <tf2_ros/transform_listener.h>
22#include <tf2_eigen/tf2_eigen.h>
23#include "covariance_helper.h"
24
25namespace object
26{
27
28ObjectDetectionTrackingWorker::ObjectDetectionTrackingWorker(PublishObjectCallback obj_pub, TransformLookupCallback tf_lookup, rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr logger)
29 : obj_pub_(obj_pub), tf_lookup_(tf_lookup), logger_(logger) {}
30
31bool ObjectDetectionTrackingWorker::isClass(const autoware_auto_msgs::msg::TrackedObject& obj, uint8_t class_id) {
32
33 return obj.classification.end() != std::find_if(obj.classification.begin(), obj.classification.end(),
34 [&class_id](auto o){ return o.classification == class_id; }
35 );
36
37}
38
39void ObjectDetectionTrackingWorker::detectedObjectCallback(autoware_auto_msgs::msg::TrackedObjects::UniquePtr obj_array)
40{
41
42 carma_perception_msgs::msg::ExternalObjectList msg;
43 msg.header = obj_array->header;
44 msg.header.frame_id = map_frame_;
45
46
47 auto transform = tf_lookup_(map_frame_, obj_array->header.frame_id, obj_array->header.stamp);
48
49 if (!transform) {
50 RCLCPP_WARN_STREAM(logger_->get_logger(), "Ignoring fix message: Could not locate static transforms exception.");
51 return;
52 }
53
54 geometry_msgs::msg::TransformStamped object_frame_tf = transform.get();
55
56 for (size_t i = 0; i < obj_array->objects.size(); i++)
57 {
58 carma_perception_msgs::msg::ExternalObject obj;
59
60 // Header contains the frame rest of the fields will use
61 obj.header = msg.header;
62
63 // Presence vector message is used to describe objects coming from potentially
64 // different sources. The presence vector is used to determine what items are set
65 // by the producer
66 obj.presence_vector = obj.presence_vector | obj.ID_PRESENCE_VECTOR;
67 obj.presence_vector = obj.presence_vector | obj.POSE_PRESENCE_VECTOR;
68 obj.presence_vector = obj.presence_vector | obj.VELOCITY_PRESENCE_VECTOR;
69 obj.presence_vector = obj.presence_vector | obj.SIZE_PRESENCE_VECTOR;
70 obj.presence_vector = obj.presence_vector | obj.OBJECT_TYPE_PRESENCE_VECTOR;
71 obj.presence_vector = obj.presence_vector | obj.DYNAMIC_OBJ_PRESENCE;
72 obj.presence_vector = obj.presence_vector | obj.CONFIDENCE_PRESENCE_VECTOR;
73
74 // Object id. Matching ids on a topic should refer to the same object within some time period, expanded
75 obj.id = obj_array->objects[i].object_id;
76
77 // Pose of the object within the frame specified in header
78 geometry_msgs::msg::PoseStamped input_object_pose;
79 input_object_pose.header = obj_array->header;
80 input_object_pose.pose.position = obj_array->objects[i].kinematics.centroid_position;
81 input_object_pose.pose.orientation = obj_array->objects[i].kinematics.orientation;
82
83 geometry_msgs::msg::PoseStamped output_pose;
84 // Transform the object input our map frame
85 tf2::doTransform(input_object_pose, output_pose, object_frame_tf);
86
87 obj.pose.pose = output_pose.pose;
88
89 // In ROS2 foxy the doTransform call does not set the covariance, so we need to do it manually
90 // Copy over the position covariance
91 // Variable names used here are row, column so row major order
92 auto xx = obj_array->objects[i].kinematics.position_covariance[0];
93 auto xy = obj_array->objects[i].kinematics.position_covariance[1];
94 auto xz = obj_array->objects[i].kinematics.position_covariance[2];
95 auto yx = obj_array->objects[i].kinematics.position_covariance[3];
96 auto yy = obj_array->objects[i].kinematics.position_covariance[4];
97 auto yz = obj_array->objects[i].kinematics.position_covariance[5];
98 auto zx = obj_array->objects[i].kinematics.position_covariance[6];
99 auto zy = obj_array->objects[i].kinematics.position_covariance[7];
100 auto zz = obj_array->objects[i].kinematics.position_covariance[8];
101
102 // This matrix represents the covariance of the object before transformation
103 std::array<double, 36> input_covariance = {
104 xx, xy, xz, 0, 0, 0,
105 yx, yy, yz, 0, 0, 0,
106 zx, zy, zz, 0, 0, 0,
107 0, 0, 0, 1, 0, 0, // Since no covariance for the orientation is provided we will assume an identity relationship (1s on the diagonal)
108 0, 0, 0, 0, 1, 0, // TODO when autoware suplies this information we should update this to reflect the new covariance
109 0, 0, 0, 0, 0, 1
110 };
111
112 // Transform the covariance matrix
113 tf2::Transform covariance_transform;
114 tf2::fromMsg(object_frame_tf.transform, covariance_transform);
115 obj.pose.covariance = covariance_helper::transformCovariance(input_covariance, covariance_transform);
116
117 // Store the object ovarall confidence
118 obj.confidence = obj_array->objects[i].existence_probability;
119
120 // Average velocity of the object within the frame specified in header
121 obj.velocity = obj_array->objects[i].kinematics.twist;
122
123 // The size of the object aligned along the axis of the object described by the orientation in pose
124 // Dimensions are specified in meters
125 // Autoware provides a set of 2d bounding boxes and supports articulated shapes.
126 // The loop below finds the overall bounding box to ensure information is not lost
127
128 double minX = std::numeric_limits<double>::max();
129 double maxX = std::numeric_limits<double>::lowest();
130 double minY = std::numeric_limits<double>::max();
131 double maxY = std::numeric_limits<double>::lowest();
132 double maxHeight = std::numeric_limits<double>::lowest();
133
134 for(auto shape : obj_array->objects[i].shape) {
135 for (auto point : shape.polygon.points) {
136
137 if (point.x > maxX)
138 maxX = point.x;
139
140 if (point.x < minX)
141 minX = point.x;
142
143 if (point.y > maxY)
144 maxY = point.y;
145
146 if (point.y < minY)
147 minY = point.y;
148 }
149 if (shape.height > maxHeight)
150 maxHeight = shape.height;
151 }
152
153 double dX = maxX - minX;
154 double dY = maxY - minY;
155
156 obj.size.x = dX / 2.0; // Shape in carma is defined by the half delta from the centroid
157 obj.size.y = dY / 2.0;
158
159 // Height provided by autoware is overall height divide by 2 for delta from centroid
160 obj.size.z = maxHeight / 2.0;
161
162 // Update the object type and generate predictions using CV or CTRV vehicle models.
163 // If the object is a bicycle or motor vehicle use CTRV otherwise use CV.
164
165 if (isClass(obj_array->objects[i], autoware_auto_msgs::msg::ObjectClassification::MOTORCYCLE))
166 {
167 obj.object_type = obj.MOTORCYCLE;
168 }
169 else if (isClass(obj_array->objects[i], autoware_auto_msgs::msg::ObjectClassification::BICYCLE))
170 {
171 obj.object_type = obj.MOTORCYCLE; // Currently external object cannot represent bicycles
172 }
173 else if (isClass(obj_array->objects[i], autoware_auto_msgs::msg::ObjectClassification::CAR))
174 {
175 obj.object_type = obj.SMALL_VEHICLE;
176 }
177 else if (isClass(obj_array->objects[i], autoware_auto_msgs::msg::ObjectClassification::TRUCK))
178 {
179 obj.object_type = obj.LARGE_VEHICLE;
180 }
181 else if (isClass(obj_array->objects[i], autoware_auto_msgs::msg::ObjectClassification::TRAILER))
182 {
183 obj.object_type = obj.LARGE_VEHICLE; // Currently external object cannot represent trailers
184 }
185 else if (isClass(obj_array->objects[i], autoware_auto_msgs::msg::ObjectClassification::PEDESTRIAN))
186 {
187 obj.object_type = obj.PEDESTRIAN;
188 }
189 else
190 {
191 obj.object_type = obj.UNKNOWN;
192 }
193
194 // Binary value to show if the object is static or dynamic (1: dynamic, 0: static)
195
196 if ((fabs(obj.velocity.twist.linear.x || obj.velocity.twist.linear.y || obj.velocity.twist.linear.z)) > 0.75)
197 {
198 obj.dynamic_obj = 1;
199 }
200 else
201 {
202 obj.dynamic_obj = 0;
203 }
204
205 msg.objects.emplace_back(obj);
206 }
207
208
209
210 obj_pub_(msg);
211}
212
214{
215 map_frame_ = map_frame;
216}
217
218
219} // namespace object
ObjectDetectionTrackingWorker(PublishObjectCallback obj_pub, TransformLookupCallback tf_lookup, rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr logger)
Constructor.
bool isClass(const autoware_auto_msgs::msg::TrackedObject &obj, uint8_t class_id)
Helper method to check if the provided tracked object has the provided class type.
void detectedObjectCallback(autoware_auto_msgs::msg::TrackedObjects::UniquePtr msg)
detectedObjectCallback populates detected object along with its velocity,yaw, yaw_rate and static/dyn...
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr logger_
std::function< void(const carma_perception_msgs::msg::ExternalObjectList &)> PublishObjectCallback
std::function< boost::optional< geometry_msgs::msg::TransformStamped >(const std::string &, const std::string &, const rclcpp::Time &stamp)> TransformLookupCallback
geometry_msgs::msg::PoseWithCovariance::_covariance_type transformCovariance(const geometry_msgs::msg::PoseWithCovariance::_covariance_type &cov_in, const tf2::Transform &transform)
Transform the covariance matrix of a PoseWithCovariance message to a new frame.