@@ -822,7 +822,10 @@ MapBasedPredictionNode::MapBasedPredictionNode(const rclcpp::NodeOptions & node_
822
822
* parameter control the estimated path length = vx * th * (rate) */
823
823
prediction_time_horizon_rate_for_validate_lane_length_ =
824
824
declare_parameter<double >(" prediction_time_horizon_rate_for_validate_shoulder_lane_length" );
825
-
825
+ match_lost_and_appeared_crosswalk_users_ =
826
+ declare_parameter<bool >(" use_crosswalk_user_history.match_lost_and_appeared_users" );
827
+ remember_lost_crosswalk_users_ =
828
+ declare_parameter<bool >(" use_crosswalk_user_history.remember_lost_users" );
826
829
use_vehicle_acceleration_ = declare_parameter<bool >(" use_vehicle_acceleration" );
827
830
speed_limit_multiplier_ = declare_parameter<double >(" speed_limit_multiplier" );
828
831
acceleration_exponential_half_life_ =
@@ -969,6 +972,14 @@ void MapBasedPredictionNode::objectsCallback(const TrackedObjects::ConstSharedPt
969
972
970
973
auto invalidated_crosswalk_users = removeOldObjectsHistory (
971
974
objects_detected_time, object_buffer_time_length_, crosswalk_users_history_);
975
+ // delete matches that point to invalid object
976
+ for (auto it = known_matches_.begin (); it != known_matches_.end ();) {
977
+ if (invalidated_crosswalk_users.count (it->second )) {
978
+ it = known_matches_.erase (it);
979
+ } else {
980
+ ++it;
981
+ }
982
+ }
972
983
973
984
// result output
974
985
PredictedObjects output;
@@ -978,6 +989,19 @@ void MapBasedPredictionNode::objectsCallback(const TrackedObjects::ConstSharedPt
978
989
// result debug
979
990
visualization_msgs::msg::MarkerArray debug_markers;
980
991
992
+ // get current crosswalk users for later prediction
993
+ std::unordered_map<std::string, TrackedObject> current_crosswalk_users;
994
+ for (const auto & object : in_objects->objects ) {
995
+ const auto label_for_prediction =
996
+ changeLabelForPrediction (object.classification .front ().label , object, lanelet_map_ptr_);
997
+ if (
998
+ label_for_prediction == ObjectClassification::PEDESTRIAN ||
999
+ label_for_prediction == ObjectClassification::BICYCLE) {
1000
+ current_crosswalk_users[tier4_autoware_utils::toHexString (object.object_id )] = object;
1001
+ }
1002
+ }
1003
+ std::unordered_set<std::string> predicted_crosswalk_users_ids;
1004
+
981
1005
for (const auto & object : in_objects->objects ) {
982
1006
std::string object_id = tier4_autoware_utils::toHexString (object.object_id );
983
1007
TrackedObject transformed_object = object;
@@ -998,6 +1022,12 @@ void MapBasedPredictionNode::objectsCallback(const TrackedObjects::ConstSharedPt
998
1022
switch (label) {
999
1023
case ObjectClassification::PEDESTRIAN:
1000
1024
case ObjectClassification::BICYCLE: {
1025
+ std::string object_id = tier4_autoware_utils::toHexString (object.object_id );
1026
+ if (match_lost_and_appeared_crosswalk_users_) {
1027
+ object_id = tryMatchNewObjectToDisappeared (object_id, current_crosswalk_users);
1028
+ }
1029
+ predicted_crosswalk_users_ids.insert (object_id);
1030
+ updateCrosswalkUserHistory (output.header , transformed_object, object_id);
1001
1031
const auto predicted_object_crosswalk =
1002
1032
getPredictedObjectAsCrosswalkUser (transformed_object);
1003
1033
output.objects .push_back (predicted_object_crosswalk);
@@ -1163,6 +1193,19 @@ void MapBasedPredictionNode::objectsCallback(const TrackedObjects::ConstSharedPt
1163
1193
}
1164
1194
}
1165
1195
1196
+ // process lost crosswalk users to tackle unstable detection
1197
+ if (remember_lost_crosswalk_users_) {
1198
+ for (const auto & [id, crosswalk_user] : crosswalk_users_history_) {
1199
+ // get a predicted path for crosswalk users in history who didn't get path yet using latest
1200
+ // message
1201
+ if (predicted_crosswalk_users_ids.count (id) == 0 ) {
1202
+ const auto predicted_object =
1203
+ getPredictedObjectAsCrosswalkUser (crosswalk_user.back ().tracked_object );
1204
+ output.objects .push_back (predicted_object);
1205
+ }
1206
+ }
1207
+ }
1208
+
1166
1209
// Publish Results
1167
1210
pub_objects_->publish (output);
1168
1211
published_time_publisher_->publish_if_subscribed (pub_objects_, output.header .stamp );
@@ -1188,6 +1231,51 @@ void MapBasedPredictionNode::updateCrosswalkUserHistory(
1188
1231
}
1189
1232
}
1190
1233
1234
+ std::string MapBasedPredictionNode::tryMatchNewObjectToDisappeared (
1235
+ const std::string & object_id, std::unordered_map<std::string, TrackedObject> & current_users)
1236
+ {
1237
+ if (known_matches_.count (object_id)) {
1238
+ std::string match_id = known_matches_[object_id];
1239
+ // object in the history is already matched to something (possibly itself)
1240
+ if (crosswalk_users_history_.count (match_id)) {
1241
+ // avoid matching two appeared users to one user in history
1242
+ current_users[match_id] = crosswalk_users_history_[match_id].back ().tracked_object ;
1243
+ return match_id;
1244
+ } else {
1245
+ RCLCPP_WARN_STREAM (
1246
+ get_logger (), " Crosswalk user was " << object_id << " was matched to " << match_id
1247
+ << " but the history has deleted. Rematching" );
1248
+ }
1249
+ }
1250
+ std::string match_id = object_id;
1251
+ double best_score = std::numeric_limits<double >::max ();
1252
+ auto pos0 = current_users[object_id].kinematics .pose_with_covariance .pose .position ;
1253
+ for (const auto & [user_id, user_history] : crosswalk_users_history_) {
1254
+ // user present in current_users and will be matched to itself
1255
+ if (current_users.count (user_id)) {
1256
+ continue ;
1257
+ }
1258
+ // TODO(dkoldaev): implement more sophisticated scoring, for now simply dst to last position in
1259
+ // history
1260
+ auto pos = user_history.back ().tracked_object .kinematics .pose_with_covariance .pose .position ;
1261
+ double score = std::hypot (pos.x - pos0.x , pos.y - pos0.y );
1262
+ if (score < best_score) {
1263
+ best_score = score;
1264
+ match_id = user_id;
1265
+ }
1266
+ }
1267
+
1268
+ if (object_id != match_id) {
1269
+ RCLCPP_INFO_STREAM (
1270
+ get_logger (), " [Map Based Prediction]: Matched " << object_id << " to " << match_id);
1271
+ // avoid matching two appeared users to one user in history
1272
+ current_users[match_id] = crosswalk_users_history_[match_id].back ().tracked_object ;
1273
+ }
1274
+
1275
+ known_matches_[object_id] = match_id;
1276
+ return match_id;
1277
+ }
1278
+
1191
1279
bool MapBasedPredictionNode::doesPathCrossAnyFence (const PredictedPath & predicted_path)
1192
1280
{
1193
1281
const lanelet::ConstLineStrings3d & all_fences =
0 commit comments