Apollo 11.0
自动驾驶开放平台
kalman_motion_fusion.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2018 The Apollo Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of 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,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
17
18#include <algorithm>
19#include <iomanip>
20#include <limits>
21
25
26namespace {
27constexpr double kDoubleEpsilon = std::numeric_limits<double>::epsilon();
28}
29
30namespace apollo {
31namespace perception {
32namespace fusion {
33
34int KalmanMotionFusion::s_eval_window_ = 3;
35size_t KalmanMotionFusion::s_history_size_maximum_ = 20;
36
38 if (track_ref_ == nullptr) {
39 return false;
40 }
41 if (track_ref_->GetLatestLidarObject() != nullptr) {
42 filter_init_ = InitFilter(track_ref_->GetLatestLidarObject());
43 } else if (track_ref_->GetLatestRadarObject() != nullptr) {
44 filter_init_ = InitFilter(track_ref_->GetLatestRadarObject());
45 }
46 return true;
47}
48
49bool KalmanMotionFusion::InitFilter(const SensorObjectConstPtr& sensor_object) {
50 const std::vector<bool> gain_break_down = {0, 0, 0, 0, 1, 1};
51 const std::vector<bool> value_break_down = {0, 0, 1, 1, 0, 0};
52 const float gain_break_down_threshold = 2.0f;
53 const float value_break_down_threshold = 0.05f;
54 Eigen::MatrixXd global_uncertainty;
55 Eigen::VectorXd global_states;
56 // global_states: center(2), velocity(2), acceleration(2)
57 global_uncertainty.setIdentity(6, 6);
58 global_states.setZero(6, 1);
59
60 fused_anchor_point_ =
61 sensor_object->GetBaseObject()->anchor_point.cast<double>();
62 fused_velocity_ = sensor_object->GetBaseObject()->velocity.cast<double>();
63 fused_acceleration_ = Eigen::Vector3d(0, 0, 0);
64
65 global_states(0) = sensor_object->GetBaseObject()->anchor_point(0);
66 global_states(1) = sensor_object->GetBaseObject()->anchor_point(1);
67 global_states(2) = sensor_object->GetBaseObject()->velocity(0);
68 global_states(3) = sensor_object->GetBaseObject()->velocity(1);
69 global_states(4) = 0.0;
70 global_states(5) = 0.0;
71 global_uncertainty.topLeftCorner(2, 2) =
72 sensor_object->GetBaseObject()
73 ->center_uncertainty.topLeftCorner(2, 2)
74 .cast<double>();
75 global_uncertainty.block<2, 2>(2, 2) =
76 sensor_object->GetBaseObject()
77 ->velocity_uncertainty.topLeftCorner(2, 2)
78 .cast<double>();
79 global_uncertainty.bottomRightCorner(2, 2) =
80 sensor_object->GetBaseObject()
81 ->velocity_uncertainty.topLeftCorner(2, 2)
82 .cast<double>();
83
84 if (sensor_object->GetBaseObject()->velocity_converged) {
85 UpdateSensorHistory(sensor_object->GetSensorType(),
86 sensor_object->GetBaseObject()->velocity.cast<double>(),
87 sensor_object->GetTimestamp());
88 }
89
90 if (!kalman_filter_.Init(global_states, global_uncertainty)) {
91 return false;
92 }
93 if (!kalman_filter_.SetGainBreakdownThresh(gain_break_down,
94 gain_break_down_threshold) ||
95 !kalman_filter_.SetValueBreakdownThresh(value_break_down,
96 value_break_down_threshold)) {
97 return false;
98 }
99
100 return true;
101}
102
103void KalmanMotionFusion::GetStates(Eigen::Vector3d* anchor_point,
104 Eigen::Vector3d* velocity) {
105 *anchor_point = fused_anchor_point_;
106 *velocity = fused_velocity_;
107}
108
109void KalmanMotionFusion::UpdateWithoutMeasurement(const std::string& sensor_id,
110 double measurement_timestamp,
111 double target_timestamp) {
112 SensorObjectConstPtr lidar_ptr = track_ref_->GetLatestLidarObject();
113 SensorObjectConstPtr radar_ptr = track_ref_->GetLatestRadarObject();
114 SensorObjectConstPtr camera_ptr = track_ref_->GetLatestCameraObject();
115 bool is_alive =
116 (lidar_ptr != nullptr || radar_ptr != nullptr || camera_ptr != nullptr);
117 if (filter_init_ && is_alive) {
118 double time_diff =
119 measurement_timestamp - track_ref_->GetFusedObject()->GetTimestamp();
120 MotionFusionWithoutMeasurement(time_diff);
121 fused_anchor_point_(0) = kalman_filter_.GetStates()(0);
122 fused_anchor_point_(1) = kalman_filter_.GetStates()(1);
123 fused_velocity_(0) = kalman_filter_.GetStates()(2);
124 fused_velocity_(1) = kalman_filter_.GetStates()(3);
125 fused_acceleration_(0) = kalman_filter_.GetStates()(4);
126 fused_acceleration_(1) = kalman_filter_.GetStates()(5);
127 }
128 // Originally, we would reset filter_init_ to false, when there is no
129 // valid lidar & radar measurement. now, as the quality of estimation
130 // of camera improved, this step is not needed.
131 UpdateMotionState();
132}
133
135 const SensorObjectConstPtr& measurement, double target_timestamp) {
136 fused_anchor_point_ =
137 measurement->GetBaseObject()->anchor_point.cast<double>();
138 fused_velocity_ = measurement->GetBaseObject()->velocity.cast<double>();
139 fused_acceleration_ =
140 measurement->GetBaseObject()->acceleration.cast<double>();
141 center_uncertainty_ = measurement->GetBaseObject()->center_uncertainty;
142 velo_uncertainty_ = measurement->GetBaseObject()->velocity_uncertainty;
143 acc_uncertainty_ = measurement->GetBaseObject()->acceleration_uncertainty;
144
145 double time_diff = measurement->GetTimestamp() -
146 track_ref_->GetFusedObject()->GetTimestamp();
147 bool is_lidar = IsLidar(measurement);
148 bool is_radar = IsRadar(measurement);
149 bool is_camera = IsCamera(measurement);
150 SensorObjectConstPtr lidar_ptr = track_ref_->GetLatestLidarObject();
151 SensorObjectConstPtr radar_ptr = track_ref_->GetLatestRadarObject();
152 SensorObjectConstPtr camera_ptr = track_ref_->GetLatestCameraObject();
153 // Motion fusion
154 if (is_lidar || is_radar || is_camera) {
155 if (filter_init_) {
156 MotionFusionWithMeasurement(measurement, time_diff);
157 } else {
158 filter_init_ = InitFilter(measurement);
159 }
160 if (!filter_init_) {
161 // No kalman result, no matter which sensortype
162 // of measurement, use measurement's
163 // anchor point and velocity
164 return;
165 }
166 }
167 // shape & location fusion
168 if (is_lidar || is_radar) {
169 if (is_lidar || (is_radar && lidar_ptr == nullptr)) {
170 // 1) measurement is lidar: use lidar's anchor point
171 // , use fused velocity
172 // 2) measurement is radar, and has no history lidar:
173 // use radar's anchor point, use fused velocity
174 fused_velocity_(0) = kalman_filter_.GetStates()(2);
175 fused_velocity_(1) = kalman_filter_.GetStates()(3);
176 }
177 if (is_radar && lidar_ptr != nullptr) {
178 // measurement is radar, has history lidar:
179 // use fused achor point, use fused velocity
180 fused_anchor_point_(0) = kalman_filter_.GetStates()(0);
181 fused_anchor_point_(1) = kalman_filter_.GetStates()(1);
182 fused_velocity_(0) = kalman_filter_.GetStates()(2);
183 fused_velocity_(1) = kalman_filter_.GetStates()(3);
184 }
185 } else if (is_camera) {
186 if (filter_init_) {
187 if (lidar_ptr != nullptr) {
188 // measurement is camera, has history lidar
189 // use fused position, use fused velocity
190 fused_anchor_point_(0) = kalman_filter_.GetStates()(0);
191 fused_anchor_point_(1) = kalman_filter_.GetStates()(1);
192 fused_velocity_(0) = kalman_filter_.GetStates()(2);
193 fused_velocity_(1) = kalman_filter_.GetStates()(3);
194 } else if (radar_ptr != nullptr) {
195 // measurement is camera, has no history lidar, but
196 // has history radar, use history radar's position
197 // use fused velocity
198 fused_anchor_point_ =
199 radar_ptr->GetBaseObject()->anchor_point.cast<double>();
200 fused_velocity_(0) = kalman_filter_.GetStates()(2);
201 fused_velocity_(1) = kalman_filter_.GetStates()(3);
202 } else {
203 // measurement is camera, has no history lidar
204 // or radar, use measurement's anchor point and
205 // velocity, do nothing(at the beginning of this
206 // function, fused velocity/anchor point has been
207 // set to as same as measurement)
208 }
209 }
210 }
211 fused_acceleration_(0) = kalman_filter_.GetStates()(4);
212 fused_acceleration_(1) = kalman_filter_.GetStates()(5);
213 // Originally, we would reset filter_init_ to false, when there is no
214 // valid lidar & radar measurement. now, as the quality of estimation
215 // of camera improved, this step is not needed.
216 UpdateMotionState();
217}
218
219void KalmanMotionFusion::MotionFusionWithoutMeasurement(
220 const double time_diff) {
221 Eigen::MatrixXd transform_matrix;
222 Eigen::MatrixXd env_uncertainty;
223 transform_matrix.setIdentity(6, 6);
224 transform_matrix(0, 2) = time_diff;
225 transform_matrix(1, 3) = time_diff;
226 env_uncertainty.setZero(6, 6);
227 kalman_filter_.Predict(transform_matrix, env_uncertainty);
228}
229
230void KalmanMotionFusion::MotionFusionWithMeasurement(
231 const SensorObjectConstPtr& measurement, double time_diff) {
232 // we use kalman filter to update our tracker.
233 // The pipeline is detailed as follows:
234 // 1) compute the time diff to predict the tracker
235 // (although we introduce the acceleration, we
236 // doesn't use it to update the position)
237 // 2) DeCorrelation the uncertainty matrix (we belief
238 // that the velocity won`t be affected by position)
239 // 3) compute the acceleration of the measurement
240 // 4) use the history radar or lidar(depend on which sensor
241 // type in current) to correct the observation
242 // 5) set r_matrix according to converged or not
243 // 6) use kalman to correct the predict before
244 // 7) use correction breakdown to eliminate the unreasonable
245 // acceleration gain or velocity noise
246 Eigen::MatrixXd transform_matrix;
247 Eigen::MatrixXd env_uncertainty;
248
249 transform_matrix.setIdentity(6, 6);
250 transform_matrix(0, 2) = time_diff;
251 transform_matrix(1, 3) = time_diff;
252 transform_matrix(2, 4) = time_diff;
253 transform_matrix(3, 5) = time_diff;
254
255 env_uncertainty.setIdentity(6, 6);
256 env_uncertainty *= 0.5;
257
258 kalman_filter_.Predict(transform_matrix, env_uncertainty);
259
260 Eigen::Vector3d measured_acceleration = Eigen::Vector3d::Zero();
261 measured_acceleration = ComputeAccelerationMeasurement(
262 measurement->GetSensorType(),
263 measurement->GetBaseObject()->velocity.cast<double>(),
264 measurement->GetTimestamp());
265
266 Eigen::VectorXd observation;
267 observation.setZero(6, 1);
268 observation(0) = measurement->GetBaseObject()->center(0);
269 observation(1) = measurement->GetBaseObject()->center(1);
270 observation(2) = measurement->GetBaseObject()->velocity(0);
271 observation(3) = measurement->GetBaseObject()->velocity(1);
272 observation(4) = measured_acceleration(0);
273 observation(5) = measured_acceleration(1);
274
275 Eigen::MatrixXd r_matrix;
276 r_matrix.setIdentity(6, 6);
277 r_matrix.topLeftCorner(2, 2) = measurement->GetBaseObject()
278 ->center_uncertainty.topLeftCorner(2, 2)
279 .cast<double>();
280 r_matrix.block<2, 2>(2, 2) = measurement->GetBaseObject()
281 ->velocity_uncertainty.topLeftCorner(2, 2)
282 .cast<double>();
283
284 ADEBUG << "fusion_original_measurement@(" << std::setprecision(10)
285 << observation(0) << "," << observation(1) << "," << observation(2)
286 << "," << observation(3) << ")";
287 ADEBUG << "fusion_original_measurement_covariance@(" << r_matrix(0, 0) << ","
288 << r_matrix(0, 1) << "," << r_matrix(1, 0) << "," << r_matrix(1, 1)
289 << "," << r_matrix(2, 2) << "," << r_matrix(2, 3) << ","
290 << r_matrix(3, 2) << "," << r_matrix(3, 3) << ")";
291
292 // Compute pseudo measurement
293 Eigen::Vector4d temp_observation = observation.head(4);
294 Eigen::Vector4d pseudo_measurement =
295 ComputePseudoMeasurement(temp_observation, measurement->GetSensorType());
296 observation.head(4) = pseudo_measurement;
297
298 if (measurement->GetBaseObject()->velocity_converged) {
299 UpdateSensorHistory(measurement->GetSensorType(),
300 measurement->GetBaseObject()->velocity.cast<double>(),
301 measurement->GetTimestamp());
302 }
303
304 // Adapt noise level to rewarding status
305 RewardRMatrix(measurement->GetSensorType(),
306 measurement->GetBaseObject()->velocity_converged, &r_matrix);
307
308 ADEBUG << "fusion_pseudo_measurement@(" << std::setprecision(10)
309 << observation(0) << "," << observation(1) << "," << observation(2)
310 << "," << observation(3) << ")";
311 ADEBUG << "fusion_pseudo_measurement_covariance@(" << r_matrix(0, 0) << ","
312 << r_matrix(0, 1) << "," << r_matrix(1, 0) << "," << r_matrix(1, 1)
313 << "," << r_matrix(2, 2) << "," << r_matrix(2, 3) << ","
314 << r_matrix(3, 2) << "," << r_matrix(3, 3) << ")";
315
316 kalman_filter_.DeCorrelation(2, 0, 2, 2);
317 kalman_filter_.Correct(observation, r_matrix);
318 kalman_filter_.CorrectionBreakdown();
319
320 ADEBUG << "fusion_filter_belief@(" << std::setprecision(10)
321 << kalman_filter_.GetStates()(0) << ","
322 << kalman_filter_.GetStates()(1) << ","
323 << kalman_filter_.GetStates()(2) << ","
324 << kalman_filter_.GetStates()(3) << ")";
325 ADEBUG << "fusion_filter_belief_covariance@("
326 << kalman_filter_.GetUncertainty()(0, 0) << ","
327 << kalman_filter_.GetUncertainty()(0, 1) << ","
328 << kalman_filter_.GetUncertainty()(1, 0) << ","
329 << kalman_filter_.GetUncertainty()(1, 1) << ","
330 << kalman_filter_.GetUncertainty()(2, 2) << ","
331 << kalman_filter_.GetUncertainty()(2, 3) << ","
332 << kalman_filter_.GetUncertainty()(3, 2) << ","
333 << kalman_filter_.GetUncertainty()(3, 3) << ")";
334}
335
336void KalmanMotionFusion::UpdateMotionState() {
337 base::ObjectPtr obj = track_ref_->GetFusedObject()->GetBaseObject();
338 obj->anchor_point = fused_anchor_point_.cast<double>();
339 // it seems that it is the only place to update the FusedObject's `center`
340 // who will be used in CollectFusedObjects
341 obj->center = obj->anchor_point;
342 obj->velocity = fused_velocity_.cast<float>();
343 obj->acceleration = fused_acceleration_.cast<float>();
344 // Previously, obj velocity uncertainty would be updated according to the
345 // uncertainty within kalman filter. however, rewarding strategy within
346 // motion fusion could change kalman filter's uncertainty, which could
347 // not reflect the reality of cov.
348 // TEMPORARYLY, we keep obj's velocity covariance as it computed in
349 // single sensor. THIS IS AS SAME AS 2-1-19-1.
350 // a more general probabilisitic method would be try in this week, and
351 // codes would be updated after benchmarking.
352 obj->center_uncertainty = center_uncertainty_;
353 obj->velocity_uncertainty = velo_uncertainty_;
354 obj->acceleration_uncertainty = acc_uncertainty_;
355}
356
357Eigen::VectorXd KalmanMotionFusion::ComputeAccelerationMeasurement(
358 const base::SensorType& sensor_type, const Eigen::Vector3d& velocity,
359 const double& timestamp) {
360 Eigen::Vector3d acceleration_measurement = Eigen::Vector3d::Zero();
361 if (algorithm::SensorManager::Instance()->IsCamera(sensor_type)) {
362 acceleration_measurement(0) = kalman_filter_.GetStates()(4);
363 acceleration_measurement(1) = kalman_filter_.GetStates()(5);
364 return acceleration_measurement;
365 }
366 if (GetSensorHistoryLength(sensor_type) >= s_eval_window_) {
367 size_t history_index = GetSensorHistoryIndex(sensor_type, s_eval_window_);
368 if (history_index >= history_velocity_.size()) {
369 AERROR << "illegal history index";
370 return Eigen::Vector3d::Zero();
371 }
372 acceleration_measurement = velocity - history_velocity_[history_index];
373 acceleration_measurement /= (timestamp - history_timestamp_[history_index]);
374 }
375 return acceleration_measurement;
376}
377
378void KalmanMotionFusion::RewardRMatrix(const base::SensorType& sensor_type,
379 const bool& converged,
380 Eigen::MatrixXd* r_matrix) {
381 algorithm::SensorManager* sensor_manager =
382 algorithm::SensorManager::Instance();
383 const float converged_scale = 0.01f;
384 const float unconverged_scale = 1000.0f;
385 if (sensor_manager->IsLidar(sensor_type)) {
386 if (converged) {
387 r_matrix->setIdentity();
388 r_matrix->block<4, 4>(0, 0) *= converged_scale;
389 } else {
390 r_matrix->setIdentity();
391 r_matrix->block<2, 2>(0, 0) *= converged_scale;
392 r_matrix->block<2, 2>(2, 2) *= unconverged_scale;
393 }
394 } else if (sensor_manager->IsRadar(sensor_type) ||
395 sensor_manager->IsCamera(sensor_type)) {
396 r_matrix->block<4, 4>(0, 0) *= 2.0;
397 int lidar_history_length =
398 GetSensorHistoryLength(base::SensorType::VELODYNE_64);
399 if (lidar_history_length > 0) {
400 r_matrix->block<2, 2>(2, 2).setIdentity();
401 r_matrix->block<2, 2>(2, 2) *= unconverged_scale;
402 }
403 }
404 r_matrix->block<2, 2>(4, 4) *= 0.5;
405}
406
407Eigen::Vector4d KalmanMotionFusion::ComputePseudoMeasurement(
408 const Eigen::Vector4d& measurement, const base::SensorType& sensor_type) {
409 // What is a pseudo-lidar estimation? if given lidar estimation could trace
410 // a good radar estimation within a short window, then project radar
411 // estimation on given lidar one. otherwise, use original lidar estimation.
412 // what is a pseudo-radar estimation? if given radar estimation is good,
413 // project it on its last good lidar estimation within a short window.
414 // otherwise, use current belief
415 algorithm::SensorManager* sensor_manager =
416 algorithm::SensorManager::Instance();
417 if (sensor_manager->IsLidar(sensor_type)) {
418 return ComputePseudoLidarMeasurement(measurement);
419 }
420 if (sensor_manager->IsRadar(sensor_type)) {
421 return ComputePseudoRadarMeasurement(measurement);
422 }
423 if (sensor_manager->IsCamera(sensor_type)) {
424 return ComputePseudoCameraMeasurement(measurement);
425 }
426 AINFO << "unsupport sensor type for pseudo measurement computation!";
427 Eigen::Vector4d pseudo_measurement = measurement;
428 return pseudo_measurement;
429}
430
431Eigen::Vector4d KalmanMotionFusion::ComputePseudoLidarMeasurement(
432 const Eigen::Vector4d& measurement) {
433 // Initialize status variables
434 int trace_count = 0;
435 const float velocity_angle_change_thresh_ = static_cast<float>(M_PI / 20.0);
436 const float acceleration_angle_change_thresh_ =
437 static_cast<float>(M_PI / 3.0);
438 Eigen::Vector4d pseudo_measurement = measurement;
439 Eigen::Vector3d lidar_velocity =
440 Eigen::Vector3d(measurement(2), measurement(3), 0);
441 Eigen::Vector3d fused_acceleration = Eigen::Vector3d::Zero();
442 fused_acceleration(0) = kalman_filter_.GetStates()(4);
443 fused_acceleration(1) = kalman_filter_.GetStates()(5);
444 // Return if lidar velocity is already small enough
445 double lidar_velocity_norm = lidar_velocity.norm();
446 if (lidar_velocity_norm < kDoubleEpsilon) {
447 return pseudo_measurement;
448 }
449 // Trace back radar velocity history, try to find good radar measurement
450 // which could help lidar velocity get a more accurate pseudo measurement
451 for (size_t count = 1; count < history_sensor_type_.size(); ++count) {
452 size_t history_index = history_sensor_type_.size() - count;
453 base::SensorType& history_type = history_sensor_type_[history_index];
454 if (algorithm::SensorManager::Instance()->IsRadar(history_type)) {
455 trace_count++;
456 Eigen::Vector3d radar_velocity = history_velocity_[history_index];
457 double radar_velocity_norm = radar_velocity.norm();
458 // Abandon radar history, if their velocity lengths are too different
459 if (fabs(radar_velocity_norm - lidar_velocity_norm) >
460 velocity_length_change_thresh_) {
461 continue;
462 }
463 // Abandon radar history, if its velocity angle change is too large
464 double velocity_angle_change =
465 algorithm::CalculateTheta2DXY(radar_velocity, lidar_velocity);
466 if (fabs(velocity_angle_change) > velocity_angle_change_thresh_) {
467 continue;
468 }
469 // Abandon radar history, if its acceleration angle change is too large
470 Eigen::Vector3d radar_velocity_project_on_lidar_velocity =
471 algorithm::Calculate2DXYProjectVector(radar_velocity, lidar_velocity);
472 Eigen::Vector3d radar_velocity_project_on_lidar_velocity_gain =
473 radar_velocity_project_on_lidar_velocity - lidar_velocity;
474 double acceleration_angle_change = algorithm::CalculateTheta2DXY(
475 fused_acceleration, radar_velocity_project_on_lidar_velocity_gain);
476 if (fabs(acceleration_angle_change) > acceleration_angle_change_thresh_) {
477 continue;
478 }
479 // Compute normalized velocity gain
480 double normalized_radar_velocity_project_on_lidar_velocity_gain =
481 radar_velocity_project_on_lidar_velocity_gain.head(2).norm() /
482 std::max(radar_velocity_project_on_lidar_velocity.head(2).norm(),
483 lidar_velocity.head(2).norm());
484 // Compute normalized velocity angle change
485 double normalized_velocity_angle_change =
486 fabs(velocity_angle_change) / velocity_angle_change_thresh_;
487 // Abandon radar history, if normalized diff is too large
488 if (normalized_radar_velocity_project_on_lidar_velocity_gain *
489 normalized_velocity_angle_change >
490 0.5) {
491 continue;
492 }
493 pseudo_measurement(2) = radar_velocity_project_on_lidar_velocity(0);
494 pseudo_measurement(3) = radar_velocity_project_on_lidar_velocity(1);
495 return pseudo_measurement;
496 }
497 if (trace_count == s_eval_window_) {
498 pseudo_measurement = measurement;
499 return pseudo_measurement;
500 }
501 }
502 pseudo_measurement = measurement;
503 return pseudo_measurement;
504}
505
506Eigen::Vector4d KalmanMotionFusion::ComputePseudoCameraMeasurement(
507 const Eigen::Vector4d& measurement) {
508 // Initialize status variables
509 int trace_count = 0;
510 const float velocity_angle_change_thresh_ = static_cast<float>(M_PI / 10.0);
511 const float acceleration_angle_change_thresh_ =
512 static_cast<float>(M_PI / 3.0);
513 Eigen::Vector4d pseudo_measurement = measurement;
514 Eigen::Vector3d camera_velocity =
515 Eigen::Vector3d(measurement(2), measurement(3), 0);
516 Eigen::Vector3d fused_acceleration = Eigen::Vector3d::Zero();
517 fused_acceleration(0) = kalman_filter_.GetStates()(4);
518 fused_acceleration(1) = kalman_filter_.GetStates()(5);
519 // Return if camera velocity is already small enough
520 double camera_velocity_norm = camera_velocity.norm();
521 if (camera_velocity_norm < kDoubleEpsilon) {
522 return pseudo_measurement;
523 }
524 // Trace back radar velocity history, try to find good radar measurement
525 // which could help camera velocity get a more accurate pseudo measurement
526 for (size_t count = 1; count < history_sensor_type_.size(); ++count) {
527 size_t history_index = history_sensor_type_.size() - count;
528 base::SensorType& history_type = history_sensor_type_[history_index];
529 if (algorithm::SensorManager::Instance()->IsRadar(history_type)) {
530 trace_count++;
531 Eigen::Vector3d radar_velocity = history_velocity_[history_index];
532 double radar_velocity_norm = radar_velocity.norm();
533 // Abandon radar history, if their velocity lengths are too different
534 if (fabs(radar_velocity_norm - camera_velocity_norm) >
535 velocity_length_change_thresh_) {
536 continue;
537 }
538 // Abandon radar history, if its velocity angle change is too large
539 double velocity_angle_change =
540 algorithm::CalculateTheta2DXY(radar_velocity, camera_velocity);
541 if (fabs(velocity_angle_change) > velocity_angle_change_thresh_) {
542 continue;
543 }
544 // Abandon radar history, if its acceleration angle change is too large
545 Eigen::Vector3d radar_velocity_project_on_camera_velocity =
547 camera_velocity);
548 Eigen::Vector3d radar_velocity_project_on_camera_velocity_gain =
549 radar_velocity_project_on_camera_velocity - camera_velocity;
550 double acceleration_angle_change = algorithm::CalculateTheta2DXY(
551 fused_acceleration, radar_velocity_project_on_camera_velocity_gain);
552 if (fabs(acceleration_angle_change) > acceleration_angle_change_thresh_) {
553 continue;
554 }
555 // Compute normalized velocity gain
556 double normalized_radar_velocity_project_on_camera_velocity_gain =
557 radar_velocity_project_on_camera_velocity_gain.head(2).norm() /
558 std::max(radar_velocity_project_on_camera_velocity.head(2).norm(),
559 camera_velocity.head(2).norm());
560 // Compute normalized velocity angle change
561 double normalized_velocity_angle_change =
562 fabs(velocity_angle_change) / velocity_angle_change_thresh_;
563 // Abandon radar history, if normalized diff is too large
564 if (normalized_radar_velocity_project_on_camera_velocity_gain *
565 normalized_velocity_angle_change >
566 0.3) {
567 continue;
568 }
569 pseudo_measurement(2) = radar_velocity_project_on_camera_velocity(0);
570 pseudo_measurement(3) = radar_velocity_project_on_camera_velocity(1);
571 return pseudo_measurement;
572 }
573 if (trace_count == s_eval_window_) {
574 pseudo_measurement = measurement;
575 return pseudo_measurement;
576 }
577 }
578 pseudo_measurement = measurement;
579 return pseudo_measurement;
580}
581
582Eigen::Vector4d KalmanMotionFusion::ComputePseudoRadarMeasurement(
583 const Eigen::Vector4d& measurement) {
584 // Initialize status variables
585 int lidar_trace_count = 0;
586 int camera_trace_count = 0;
587 Eigen::Vector4d pseudo_measurement = measurement;
588 int lidar_camera_history_length =
589 GetSensorHistoryLength(base::SensorType::VELODYNE_64) +
590 GetSensorHistoryLength(base::SensorType::MONOCULAR_CAMERA);
591 // Keep motion if lidar & camera history is empty
592 if (lidar_camera_history_length == 0) {
593 pseudo_measurement(2) = kalman_filter_.GetStates()(2);
594 pseudo_measurement(3) = kalman_filter_.GetStates()(3);
595 return pseudo_measurement;
596 }
597 Eigen::Vector3d radar_velocity =
598 Eigen::Vector3d(measurement(2), measurement(3), 0);
599 Eigen::Vector3d fused_acceleration = Eigen::Vector3d::Zero();
600 fused_acceleration(0) = kalman_filter_.GetStates()(4);
601 fused_acceleration(1) = kalman_filter_.GetStates()(5);
602 algorithm::SensorManager* sensor_manager =
603 algorithm::SensorManager::Instance();
604 // Trace back lidar and camera history, try to find good lidar/camera
605 // measurement which could help radar velocity get a more robust pseudo
606 // measurement.
607 for (size_t count = 1; count < history_sensor_type_.size(); ++count) {
608 size_t history_index = history_sensor_type_.size() - count;
609 base::SensorType& history_type = history_sensor_type_[history_index];
610 if (!sensor_manager->IsLidar(history_type) &&
611 !sensor_manager->IsCamera(history_type)) {
612 continue;
613 }
614 // Keep motion, if no good history been found
615 if (lidar_trace_count == s_eval_window_ ||
616 camera_trace_count == s_eval_window_) {
617 pseudo_measurement(2) = kalman_filter_.GetStates()(2);
618 pseudo_measurement(3) = kalman_filter_.GetStates()(3);
619 return pseudo_measurement;
620 }
621 Eigen::Vector3d history_velocity = history_velocity_[history_index];
622 // Abandon history measurement, if its speed is too small
623 if (history_velocity.norm() < kDoubleEpsilon) {
624 pseudo_measurement(2) = history_velocity(0);
625 pseudo_measurement(3) = history_velocity(1);
626 return pseudo_measurement;
627 }
628 // Compute velocity angle change and acceleration angle change
629 double velocity_angle_change =
630 algorithm::CalculateTheta2DXY(radar_velocity, history_velocity);
631 Eigen::Vector3d radar_velocity_project_on_history_velocity =
632 algorithm::Calculate2DXYProjectVector(radar_velocity, history_velocity);
633 Eigen::Vector3d radar_velocity_project_on_history_velocity_gain =
634 radar_velocity_project_on_history_velocity - history_velocity;
635 double acceleration_angle_change = algorithm::CalculateTheta2DXY(
636 fused_acceleration, radar_velocity_project_on_history_velocity_gain);
637 // Compute normalized velocity gain
638 double normalized_radar_velocity_project_on_history_velocity_gain =
639 radar_velocity_project_on_history_velocity_gain.head(2).norm() /
640 std::max(radar_velocity_project_on_history_velocity.head(2).norm(),
641 history_velocity.head(2).norm());
642 // Handle lidar history
643 if (sensor_manager->IsLidar(history_type)) {
644 lidar_trace_count++;
645 // Abandon lidar measurement, if its velocity angle change is too big
646 if (fabs(velocity_angle_change) > M_PI / 20) {
647 continue;
648 }
649 // Abandon lidar measurement, if its acceleration angle change is too
650 // big
651 if (fabs(acceleration_angle_change) > M_PI / 3) {
652 continue;
653 }
654 // Compute normalized velocity angle change
655 double normalized_velocity_angle_change =
656 fabs(velocity_angle_change) / (M_PI / 20);
657 // Abandon lidar measurement, if normalized diff is too big
658 if (normalized_radar_velocity_project_on_history_velocity_gain *
659 normalized_velocity_angle_change >
660 0.5) {
661 continue;
662 }
663 pseudo_measurement(2) = radar_velocity_project_on_history_velocity(0);
664 pseudo_measurement(3) = radar_velocity_project_on_history_velocity(1);
665 return pseudo_measurement;
666 } else {
667 ++camera_trace_count;
668 // Abandon camera measurement, if its velocity angle change is too big
669 if (fabs(velocity_angle_change) > M_PI / 10) {
670 continue;
671 }
672 // Abandon camera measurement, if its acceleration angle change is too
673 // big
674 if (fabs(acceleration_angle_change) > M_PI / 3) {
675 continue;
676 }
677 // Compute normalized velocity angle change
678 double normalized_velocity_angle_change =
679 fabs(velocity_angle_change) / (M_PI / 10);
680 // Abandon lidar measurement, if normalized diff is too big
681 if (normalized_radar_velocity_project_on_history_velocity_gain *
682 normalized_velocity_angle_change >
683 0.3) {
684 continue;
685 }
686 pseudo_measurement(2) = radar_velocity_project_on_history_velocity(0);
687 pseudo_measurement(3) = radar_velocity_project_on_history_velocity(1);
688 return pseudo_measurement;
689 }
690 }
691 // Use original measurement, if history is not enough
692 pseudo_measurement = measurement;
693 return pseudo_measurement;
694}
695
696void KalmanMotionFusion::UpdateSensorHistory(
697 const base::SensorType& sensor_type, const Eigen::Vector3d& velocity,
698 const double& timestamp) {
699 int lidar_history_length =
700 GetSensorHistoryLength(base::SensorType::VELODYNE_64);
701 int radar_history_length =
702 GetSensorHistoryLength(base::SensorType::LONG_RANGE_RADAR);
703 if ((lidar_history_length >= s_eval_window_ &&
704 radar_history_length >= s_eval_window_) ||
705 history_velocity_.size() > s_history_size_maximum_) {
706 history_velocity_.pop_front();
707 history_timestamp_.pop_front();
708 history_sensor_type_.pop_front();
709 }
710 history_velocity_.push_back(velocity);
711 history_timestamp_.push_back(timestamp);
712 history_sensor_type_.push_back(sensor_type);
713}
714
715int KalmanMotionFusion::GetSensorHistoryLength(
716 const base::SensorType& sensor_type) {
717 int sensor_history_length = 0;
718 for (size_t i = 0; i < history_sensor_type_.size(); ++i) {
719 if (history_sensor_type_[i] == sensor_type) {
720 ++sensor_history_length;
721 }
722 }
723 return sensor_history_length;
724}
725
726int KalmanMotionFusion::GetSensorHistoryIndex(
727 const base::SensorType& sensor_type, const int& trace_length) {
728 int history_index = 0;
729 int history_count = 0;
730 for (size_t i = 1; i <= history_sensor_type_.size(); ++i) {
731 history_index = static_cast<int>(history_sensor_type_.size() - i);
732 if (history_sensor_type_[history_index] == sensor_type) {
733 ++history_count;
734 }
735 if (history_count == trace_length) {
736 return history_index;
737 }
738 }
739
740 return -1;
741}
742
743} // namespace fusion
744} // namespace perception
745} // namespace apollo
bool DeCorrelation(int x, int y, int x_len, int y_len)
bool Predict(const Eigen::MatrixXd &transform_matrix, const Eigen::MatrixXd &env_uncertainty_matrix)
bool SetValueBreakdownThresh(const std::vector< bool > &break_down, const float threshold=0.05f)
bool Correct(const Eigen::VectorXd &cur_observation, const Eigen::MatrixXd &cur_observation_uncertainty)
bool SetGainBreakdownThresh(const std::vector< bool > &break_down, const float threshold=2.0f)
bool Init(const Eigen::VectorXd &initial_belief_states, const Eigen::MatrixXd &initial_uncertainty)
void GetStates(Eigen::Vector3d *anchor_point, Eigen::Vector3d *velocity)
Get states
bool Init() override
Init base data association config
void UpdateWithMeasurement(const SensorObjectConstPtr &measurement, double target_timestamp) override
update track motion state with measurement
void UpdateWithoutMeasurement(const std::string &sensor_id, double measurement_timestamp, double target_timestamp) override
update track motion state without measurement
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
const double kDoubleEpsilon
Eigen::Matrix< T, 3, 1 > Calculate2DXYProjectVector(const Eigen::Matrix< T, 3, 1 > &projected_vector, const Eigen::Matrix< T, 3, 1 > &project_vector)
Definition basic.h:138
T CalculateTheta2DXY(const Eigen::Matrix< T, 3, 1 > &v1, const Eigen::Matrix< T, 3, 1 > &v2)
Definition basic.h:92
SensorType
Sensor types are set in the order of lidar, radar, camera, ultrasonic Please make sure SensorType has...
Definition sensor_meta.h:29
std::shared_ptr< Object > ObjectPtr
Definition object.h:127
std::shared_ptr< const SensorObject > SensorObjectConstPtr
bool IsCamera(const SensorObjectConstPtr &obj)
bool IsLidar(const SensorObjectConstPtr &obj)
bool IsRadar(const SensorObjectConstPtr &obj)
class register implement
Definition arena_queue.h:37