@@ -43,6 +43,15 @@ ObjectLaneletFilterNode::ObjectLaneletFilterNode(const rclcpp::NodeOptions & nod
43
43
filter_target_.MOTORCYCLE = declare_parameter<bool >(" filter_target_label.MOTORCYCLE" , false );
44
44
filter_target_.BICYCLE = declare_parameter<bool >(" filter_target_label.BICYCLE" , false );
45
45
filter_target_.PEDESTRIAN = declare_parameter<bool >(" filter_target_label.PEDESTRIAN" , false );
46
+ // Set filter settings
47
+ filter_settings_.polygon_overlap_filter =
48
+ declare_parameter<bool >(" filter_settings.polygon_overlap_filter.enabled" );
49
+ filter_settings_.lanelet_direction_filter =
50
+ declare_parameter<bool >(" filter_settings.lanelet_direction_filter.enabled" );
51
+ filter_settings_.lanelet_direction_filter_velocity_yaw_threshold =
52
+ declare_parameter<double >(" filter_settings.lanelet_direction_filter.velocity_yaw_threshold" );
53
+ filter_settings_.lanelet_direction_filter_object_speed_threshold =
54
+ declare_parameter<double >(" filter_settings.lanelet_direction_filter.object_speed_threshold" );
46
55
47
56
// Set publisher/subscriber
48
57
map_sub_ = this ->create_subscription <autoware_auto_mapping_msgs::msg::HADMapBin>(
@@ -52,6 +61,9 @@ ObjectLaneletFilterNode::ObjectLaneletFilterNode(const rclcpp::NodeOptions & nod
52
61
" input/object" , rclcpp::QoS{1 }, std::bind (&ObjectLaneletFilterNode::objectCallback, this , _1));
53
62
object_pub_ = this ->create_publisher <autoware_auto_perception_msgs::msg::DetectedObjects>(
54
63
" output/object" , rclcpp::QoS{1 });
64
+
65
+ debug_publisher_ =
66
+ std::make_unique<tier4_autoware_utils::DebugPublisher>(this , " object_lanelet_filter" );
55
67
}
56
68
57
69
void ObjectLaneletFilterNode::mapCallback (
@@ -93,29 +105,65 @@ void ObjectLaneletFilterNode::objectCallback(
93
105
lanelet::ConstLanelets intersected_shoulder_lanelets =
94
106
getIntersectedLanelets (convex_hull, shoulder_lanelets_);
95
107
96
- int index = 0 ;
97
- for (const auto & object : transformed_objects.objects ) {
98
- const auto footprint = setFootprint (object);
99
- const auto & label = object.classification .front ().label ;
100
- if (filter_target_.isTarget (label)) {
101
- Polygon2d polygon;
102
- for (const auto & point : footprint.points ) {
103
- const geometry_msgs::msg::Point32 point_transformed =
104
- tier4_autoware_utils::transformPoint (point, object.kinematics .pose_with_covariance .pose );
105
- polygon.outer ().emplace_back (point_transformed.x , point_transformed.y );
106
- }
107
- polygon.outer ().push_back (polygon.outer ().front ());
108
- if (isPolygonOverlapLanelets (polygon, intersected_road_lanelets)) {
109
- output_object_msg.objects .emplace_back (input_msg->objects .at (index ));
110
- } else if (isPolygonOverlapLanelets (polygon, intersected_shoulder_lanelets)) {
111
- output_object_msg.objects .emplace_back (input_msg->objects .at (index ));
112
- }
113
- } else {
114
- output_object_msg.objects .emplace_back (input_msg->objects .at (index ));
115
- }
116
- ++index ;
108
+ // filtering process
109
+ for (size_t index = 0 ; index < transformed_objects.objects .size (); ++index ) {
110
+ const auto & transformed_object = transformed_objects.objects .at (index );
111
+ const auto & input_object = input_msg->objects .at (index );
112
+ filterObject (
113
+ transformed_object, input_object, intersected_road_lanelets, intersected_shoulder_lanelets,
114
+ output_object_msg);
117
115
}
118
116
object_pub_->publish (output_object_msg);
117
+
118
+ // Publish debug info
119
+ const double pipeline_latency =
120
+ std::chrono::duration<double , std::milli>(
121
+ std::chrono::nanoseconds (
122
+ (this ->get_clock ()->now () - output_object_msg.header .stamp ).nanoseconds ()))
123
+ .count ();
124
+ debug_publisher_->publish <tier4_debug_msgs::msg::Float64Stamped>(
125
+ " debug/pipeline_latency_ms" , pipeline_latency);
126
+ }
127
+
128
+ bool ObjectLaneletFilterNode::filterObject (
129
+ const autoware_auto_perception_msgs::msg::DetectedObject & transformed_object,
130
+ const autoware_auto_perception_msgs::msg::DetectedObject & input_object,
131
+ const lanelet::ConstLanelets & intersected_road_lanelets,
132
+ const lanelet::ConstLanelets & intersected_shoulder_lanelets,
133
+ autoware_auto_perception_msgs::msg::DetectedObjects & output_object_msg)
134
+ {
135
+ const auto & label = transformed_object.classification .front ().label ;
136
+ if (filter_target_.isTarget (label)) {
137
+ bool filter_pass = true ;
138
+ // 1. is polygon overlap with road lanelets or shoulder lanelets
139
+ if (filter_settings_.polygon_overlap_filter ) {
140
+ const bool is_polygon_overlap =
141
+ isObjectOverlapLanelets (transformed_object, intersected_road_lanelets) ||
142
+ isObjectOverlapLanelets (transformed_object, intersected_shoulder_lanelets);
143
+ filter_pass = filter_pass && is_polygon_overlap;
144
+ }
145
+
146
+ // 2. check if objects velocity is the same with the lanelet direction
147
+ const bool orientation_not_available =
148
+ transformed_object.kinematics .orientation_availability ==
149
+ autoware_auto_perception_msgs::msg::TrackedObjectKinematics::UNAVAILABLE;
150
+ if (filter_settings_.lanelet_direction_filter && !orientation_not_available) {
151
+ const bool is_same_direction =
152
+ isSameDirectionWithLanelets (intersected_road_lanelets, transformed_object) ||
153
+ isSameDirectionWithLanelets (intersected_shoulder_lanelets, transformed_object);
154
+ filter_pass = filter_pass && is_same_direction;
155
+ }
156
+
157
+ // push back to output object
158
+ if (filter_pass) {
159
+ output_object_msg.objects .emplace_back (input_object);
160
+ return true ;
161
+ }
162
+ } else {
163
+ output_object_msg.objects .emplace_back (input_object);
164
+ return true ;
165
+ }
166
+ return false ;
119
167
}
120
168
121
169
geometry_msgs::msg::Polygon ObjectLaneletFilterNode::setFootprint (
@@ -176,6 +224,39 @@ lanelet::ConstLanelets ObjectLaneletFilterNode::getIntersectedLanelets(
176
224
return intersected_lanelets;
177
225
}
178
226
227
+ bool ObjectLaneletFilterNode::isObjectOverlapLanelets (
228
+ const autoware_auto_perception_msgs::msg::DetectedObject & object,
229
+ const lanelet::ConstLanelets & intersected_lanelets)
230
+ {
231
+ // if has bounding box, use polygon overlap
232
+ if (object.shape .type != autoware_auto_perception_msgs::msg::Shape::POLYGON) {
233
+ Polygon2d polygon;
234
+ const auto footprint = setFootprint (object);
235
+ for (const auto & point : footprint.points ) {
236
+ const geometry_msgs::msg::Point32 point_transformed =
237
+ tier4_autoware_utils::transformPoint (point, object.kinematics .pose_with_covariance .pose );
238
+ polygon.outer ().emplace_back (point_transformed.x , point_transformed.y );
239
+ }
240
+ polygon.outer ().push_back (polygon.outer ().front ());
241
+ return isPolygonOverlapLanelets (polygon, intersected_lanelets);
242
+ } else {
243
+ // if object do not have bounding box, check each footprint is inside polygon
244
+ for (const auto & point : object.shape .footprint .points ) {
245
+ const geometry_msgs::msg::Point32 point_transformed =
246
+ tier4_autoware_utils::transformPoint (point, object.kinematics .pose_with_covariance .pose );
247
+ geometry_msgs::msg::Pose point2d;
248
+ point2d.position .x = point_transformed.x ;
249
+ point2d.position .y = point_transformed.y ;
250
+ for (const auto & lanelet : intersected_lanelets) {
251
+ if (lanelet::utils::isInLanelet (point2d, lanelet, 0.0 )) {
252
+ return true ;
253
+ }
254
+ }
255
+ }
256
+ return false ;
257
+ }
258
+ }
259
+
179
260
bool ObjectLaneletFilterNode::isPolygonOverlapLanelets (
180
261
const Polygon2d & polygon, const lanelet::ConstLanelets & intersected_lanelets)
181
262
{
@@ -187,6 +268,42 @@ bool ObjectLaneletFilterNode::isPolygonOverlapLanelets(
187
268
return false ;
188
269
}
189
270
271
+ bool ObjectLaneletFilterNode::isSameDirectionWithLanelets (
272
+ const lanelet::ConstLanelets & lanelets,
273
+ const autoware_auto_perception_msgs::msg::DetectedObject & object)
274
+ {
275
+ const double object_yaw = tf2::getYaw (object.kinematics .pose_with_covariance .pose .orientation );
276
+ const double object_velocity_norm = std::hypot (
277
+ object.kinematics .twist_with_covariance .twist .linear .x ,
278
+ object.kinematics .twist_with_covariance .twist .linear .y );
279
+ const double object_velocity_yaw = std::atan2 (
280
+ object.kinematics .twist_with_covariance .twist .linear .y ,
281
+ object.kinematics .twist_with_covariance .twist .linear .x ) +
282
+ object_yaw;
283
+
284
+ if (object_velocity_norm < filter_settings_.lanelet_direction_filter_object_speed_threshold ) {
285
+ return true ;
286
+ }
287
+ for (const auto & lanelet : lanelets) {
288
+ const bool is_in_lanelet =
289
+ lanelet::utils::isInLanelet (object.kinematics .pose_with_covariance .pose , lanelet, 0.0 );
290
+ if (!is_in_lanelet) {
291
+ continue ;
292
+ }
293
+ const double lane_yaw = lanelet::utils::getLaneletAngle (
294
+ lanelet, object.kinematics .pose_with_covariance .pose .position );
295
+ const double delta_yaw = object_velocity_yaw - lane_yaw;
296
+ const double normalized_delta_yaw = tier4_autoware_utils::normalizeRadian (delta_yaw);
297
+ const double abs_norm_delta_yaw = std::fabs (normalized_delta_yaw);
298
+
299
+ if (abs_norm_delta_yaw < filter_settings_.lanelet_direction_filter_velocity_yaw_threshold ) {
300
+ return true ;
301
+ }
302
+ }
303
+
304
+ return false ;
305
+ }
306
+
190
307
} // namespace object_lanelet_filter
191
308
192
309
#include < rclcpp_components/register_node_macro.hpp>
0 commit comments