Apollo 11.0
自动驾驶开放平台
mlf_direction_filter.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2024 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 "Eigen/Dense"
19
20#include "cyber/common/file.h"
21
25#include "modules/perception/lidar_tracking/tracker/multi_lidar_fusion/proto/multi_lidar_fusion_config.pb.h"
26
27namespace apollo {
28namespace perception {
29namespace lidar {
30
32 std::string config_file = "mlf_direction_filter.conf";
33 if (!options.config_file.empty()) {
34 config_file = options.config_file;
35 }
36 config_file = GetConfigFile(options.config_path, config_file);
38 ACHECK(cyber::common::GetProtoFromFile(config_file, &config));
39
40 init_direction_variance_ = config.init_direction_variance();
41 variance_bound_ = config.variance_bound();
42 max_angular_thresh_ = config.max_angular_thresh();
43 converged_confidence_minimum_ = config.converged_confidence_minimum();
44 angular_scale_ = config.angular_scale();
45 angular_window_size_ = config.angular_window_size();
46 predict_noise_per_sqrsec_ = config.predict_noise_per_sqrsec();
47 angular_confidence_thresh_ = config.angular_confidence_thresh();
48
49 return true;
50}
51
53 const MlfFilterOptions& options, const MlfTrackDataConstPtr& track_data,
54 TrackedObjectPtr new_object) {
55 Eigen::Vector3d ref_center(0, 0, 1.6);
56 if (!track_data->IsForegroundTrack()) {
57 new_object->direction_state_covariance =
58 Eigen::Matrix3d::Identity() * init_direction_variance_;
59 new_object->direction_state(0) = Vec2Angle(new_object->direction);
60 return;
61 }
62
63 if (track_data->age_ == 0) {
64 InitializeTrackState(new_object);
65 return;
66 }
67 // kalman filter for direction
68 TrackedObjectConstPtr latest_object = track_data->GetLatestObject().second;
69 KalmanFilterUpdateDirection(track_data, latest_object, new_object);
70 ComputeConvergenceConfidence(track_data, new_object);
71 GetDirectionState(new_object);
72}
73
75 double timestamp,
76 MlfTrackDataPtr track_data) {}
77
79 new_object->direction_state_covariance =
80 Eigen::Matrix3d::Identity() * init_direction_variance_;
81 new_object->direction_state(0) = Vec2Angle(new_object->direction);
82 new_object->direction_state(1) = 0.0;
83 new_object->direction_state(2) = 0.0;
84 new_object->output_direction = new_object->direction;
85 new_object->output_angular = Eigen::Vector3d::Zero();
86}
87
89 const MlfTrackDataConstPtr& track_data,
90 const TrackedObjectConstPtr& latest_object, TrackedObjectPtr new_object) {
91 if (track_data->age_ > 0) {
92 if (new_object->direction.dot(latest_object->output_direction) < 0) {
93 new_object->direction *= -1;
94 }
95
96 double time_diff = new_object->timestamp - latest_object->timestamp;
97 double angular = 0.0;
98 double direction_measurement_variance = variance_bound_;
99 double angular_measurement_variance = variance_bound_;
100 ComputeVarianceAndAngular(track_data, new_object,
101 &direction_measurement_variance,
102 &angular_measurement_variance, &angular);
103 // initialize measurement
104 Eigen::Vector2d direction_measurement;
105 direction_measurement(0) = Vec2Angle(new_object->direction);
106 direction_measurement(1) = angular;
107 // 1. predict process
108 const auto& last_direction_state = latest_object->direction_state;
109 const auto& last_direction_state_covariance =
110 latest_object->direction_state_covariance;
111
112 Eigen::Matrix3d transition = Eigen::Matrix3d::Identity();
113 transition(0, 1) = time_diff;
114 transition(0, 2) = 0.5 * time_diff * time_diff;
115 transition(1, 2) = time_diff;
116 double direction_predict_noise =
117 variance_bound_ * (1e-1 * time_diff * time_diff);
118
119 auto& direction_state = new_object->direction_state;
120 auto& direction_state_covariance =
121 new_object->direction_state_covariance;
122 Eigen::Matrix3d predict_noise = Eigen::Matrix3d::Identity() *
123 predict_noise_per_sqrsec_ * time_diff;
124 predict_noise(0, 0) = direction_predict_noise;
125
126 direction_state = transition * last_direction_state;
127 direction_state(0) = LegalizeAngle(direction_state(0));
128 direction_state_covariance =
129 transition * last_direction_state_covariance *
130 transition.transpose() + predict_noise;
131
132 // 2. measurement update
133 Eigen::Matrix<double, 2, 3> observation_transform;
134 observation_transform.block<2, 2>(0, 0).setIdentity();
135 observation_transform.block<2, 1>(0, 2).setZero();
136 Eigen::Matrix2d measurement_covariance = Eigen::Matrix2d::Identity();
137 measurement_covariance(0, 0) = direction_measurement_variance;
138 measurement_covariance(1, 1) = angular_measurement_variance;
139 Eigen::Matrix<double, 3, 2> kalman_gain_matrix =
140 direction_state_covariance * observation_transform.transpose() *
141 (observation_transform * direction_state_covariance *
142 observation_transform.transpose() + measurement_covariance).inverse();
143 Eigen::Vector2d observation_transform_state =
144 observation_transform * direction_state;
145 Eigen::Vector2d measurement_residual;
146 measurement_residual(0) = LegalizeAngle(direction_measurement(0) -
147 observation_transform_state(0));
148 measurement_residual(1) = direction_measurement(1) -
149 observation_transform_state(1);
150
151 // compute kalman gain
152 Eigen::Vector3d direction_state_gain =
153 kalman_gain_matrix * measurement_residual;
154 direction_state(0) =
155 LegalizeAngle(direction_state(0) + direction_state_gain(0));
156 direction_state(1) = direction_state(1) + direction_state_gain(1);
157 direction_state(2) = (direction_state(2) + direction_state_gain(2));
158
159 direction_state_covariance =
160 (Eigen::Matrix3d::Identity() - kalman_gain_matrix *
161 observation_transform) * direction_state_covariance;
162 // sync
163 double filter_theta = Degree2Radian(new_object->direction_state(0));
164 double filter_angular = Degree2Radian(new_object->direction_state(1));
165 new_object->output_direction(0) = std::cos(filter_theta);
166 new_object->output_direction(1) = std::sin(filter_theta);
167 new_object->output_direction(2) = 0.0;
168 new_object->output_angular(0) = std::cos(filter_angular);
169 new_object->output_angular(1) = std::sin(filter_angular);
170 new_object->output_angular(2) = 0.0;
171 }
172}
173
175 const MlfTrackDataConstPtr& track_data, TrackedObjectPtr new_object,
176 double* direction_measurement_variance,
177 double* angular_measurement_variance,
178 double* angular) {
179 // get history objects
180 std::vector<TrackedObjectConstPtr> history_objects;
181 track_data->GetObjectsInInterval(
182 new_object->timestamp - 2.0, &history_objects);
183 if (history_objects.size() == 0) {
184 return;
185 }
186 history_objects.insert(history_objects.begin(), new_object);
187 size_t object_num = history_objects.size();
188 size_t history_start_interval = 5;
189 size_t history_end_interval = 15;
190 size_t angular_window_end = std::min(angular_window_size_, object_num - 1);
191 // compute angular in a small window
192 double window_time_diff = history_objects[0]->timestamp -
193 history_objects[angular_window_end]->timestamp;
194 *angular = angular_scale_ * VecDiffAngle(history_objects[0]->direction,
195 history_objects[angular_window_end]->direction) / window_time_diff;
196
197 // compute angular in latest two objects
198 double time_diff = history_objects[0]->timestamp -
199 history_objects[1]->timestamp;
200 double latest_adjacent_frame_angular =
201 std::fabs(VecDiffAngle(history_objects[0]->direction,
202 history_objects[1]->direction)) / time_diff;
203
204 // compute measurement variance
205 double direction_confidence = 0.0;
206 ComputeMeasurementConfidence(new_object, &direction_confidence);
207 *direction_measurement_variance =
208 std::pow((1.0 - direction_confidence) * 45.0, 2.0) + 1.0;
209
210 // supress sudden unnormal direction
211 if (latest_adjacent_frame_angular > 3.0 * max_angular_thresh_) {
212 *direction_measurement_variance = variance_bound_ * variance_bound_;
213 *angular_measurement_variance = variance_bound_ * variance_bound_;;
214 *angular = 0.0;
215 return;
216 }
217
218 // compute angular measurement variance and angular confidence
219 std::vector<size_t> angular_vec;
220 double agreed_dir_num = 0.0;
221 for (size_t i = 0; i < angular_window_end; ++i) {
222 double cur_time_diff = history_objects[i]->timestamp -
223 history_objects[i + 1]->timestamp;
224 double cur_angular = VecDiffAngle(history_objects[i]->direction,
225 history_objects[i + 1]->direction) / cur_time_diff;
226 *angular_measurement_variance +=
227 (*angular - cur_angular) * (*angular - cur_angular);
228
229 size_t start = std::min(object_num - 1, i + history_start_interval);
230 size_t end = std::min(object_num - 1, i + history_end_interval);
231 for (size_t j = start; j < end; ++j) {
232 if (j == i) {
233 continue;
234 }
235 double angle_change = algorithm::CalculateTheta2DXY<double>(
236 history_objects[i]->direction.head(2),
237 history_objects[j]->direction.head(2));
238 if (angle_change >= 0.0) {
239 angular_vec.push_back(1);
240 agreed_dir_num += 1.0;
241 } else {
242 angular_vec.push_back(-1);
243 }
244 }
245 }
246 // use 0.1 to scale angular_measurement_variance
247 *angular_measurement_variance /= (angular_window_end * 10.0);
248
249 // use hstory direction trend to compute angular confidence,
250 // when angular confidence is small, there should no angular
251 agreed_dir_num = agreed_dir_num > 0.5 * angular_vec.size() ?
252 agreed_dir_num : angular_vec.size() - agreed_dir_num;
253 double agreed_dir_ratio = (agreed_dir_num + 1.0) / (angular_vec.size() + 1.0);
254 double angular_confidence = agreed_dir_ratio * agreed_dir_ratio;
255 if (angular_confidence < angular_confidence_thresh_) {
256 *angular = 0.0;
257 *angular_measurement_variance = 1.0;
258 }
259}
260
262 const MlfTrackDataConstPtr& track_data,
263 TrackedObjectPtr new_object) {
264 if (track_data->age_ <= 1) {
265 new_object->direction_convergence_confidence = 0.0;
266 new_object->direction_converged = false;
267 }
268
269 double direction_variance = new_object->direction_state_covariance(0, 0);
270 new_object->direction_convergence_confidence =
271 exp(-0.25 * direction_variance);
272 new_object->direction_converged =
273 new_object->direction_convergence_confidence >
274 converged_confidence_minimum_;
275}
276
278 const TrackedObjectPtr& new_object, double* confidence) {
279 const base::ObjectPtr& object = new_object->object_ptr;
280 Eigen::Vector3f polygon_direction = Eigen::Vector3f::Zero();
281 Eigen::Vector3d ref_center = Eigen::Vector3d::Zero();
282 ComputePolygonDirection(ref_center, object, &polygon_direction);
283 polygon_direction =
284 (new_object->sensor_to_local_pose.rotation()).cast<float>()
285 * polygon_direction;
286 double direction_diff = std::fabs(
287 algorithm::CalculateTheta2DXY<double>(new_object->direction.head(2),
288 polygon_direction.head(2).cast<double>()));
289 direction_diff = direction_diff > M_PI / 2.0 ?
290 M_PI - direction_diff : direction_diff;
291 direction_diff = direction_diff > M_PI / 4.0 ?
292 M_PI / 2.0 - direction_diff : direction_diff;
293 *confidence = 1.0 - direction_diff / (0.25 * M_PI);
294}
295
296double MlfDirectionFilter::VecDiffAngle(const Eigen::Vector3d& vec0,
297 const Eigen::Vector3d& vec1) {
298 double angle =
299 Degree2Angle(std::atan2(vec0(1), vec0(0)) - std::atan2(vec1(1), vec1(0)));
300 return LegalizeAngle(angle);
301}
302
303double MlfDirectionFilter::Vec2Angle(const Eigen::Vector3d& vec) {
304 double degree = std::atan2(vec(1), vec(0));
305 return Degree2Angle(degree);
306}
307
309 angle = std::fmod(angle, 360.0);
310 if (angle > 180.0) {
311 return angle - 360.0;
312 } else if (angle < -180.0) {
313 return angle + 360.0;
314 } else {
315 return angle;
316 }
317}
318
320 new_object->direction = new_object->output_direction;
321}
322
324
325} // namespace lidar
326} // namespace perception
327} // namespace apollo
void ComputeMeasurementConfidence(const TrackedObjectPtr &new_object, double *confidence)
void ComputeConvergenceConfidence(const MlfTrackDataConstPtr &track_data, TrackedObjectPtr new_object)
void GetDirectionState(TrackedObjectPtr &new_object)
void ComputeVarianceAndAngular(const MlfTrackDataConstPtr &track_data, TrackedObjectPtr new_object, double *direction_measurement_variance, double *angular_measurement_variance, double *angular)
void UpdateWithoutObject(const MlfFilterOptions &options, double timestamp, MlfTrackDataPtr track_data) override
Interface for updating filter without object
void UpdateWithObject(const MlfFilterOptions &options, const MlfTrackDataConstPtr &track_data, TrackedObjectPtr new_object) override
Interface for updating filter with object
bool Init(const MlfFilterInitOptions &options=MlfFilterInitOptions()) override
Init mlf fitler
void KalmanFilterUpdateDirection(const MlfTrackDataConstPtr &track_data, const TrackedObjectConstPtr &latest_object, TrackedObjectPtr new_object)
void InitializeTrackState(TrackedObjectPtr new_object)
double VecDiffAngle(const Eigen::Vector3d &vec0, const Eigen::Vector3d &vec1)
#define ACHECK(cond)
Definition log.h:80
#define PERCEPTION_REGISTER_MLFFILTER(name)
bool GetProtoFromFile(const std::string &file_name, google::protobuf::Message *message)
Parses the content of the file specified by the file_name as a representation of protobufs,...
Definition file.cc:132
std::shared_ptr< Object > ObjectPtr
Definition object.h:127
std::shared_ptr< const MlfTrackData > MlfTrackDataConstPtr
std::shared_ptr< const TrackedObject > TrackedObjectConstPtr
std::shared_ptr< MlfTrackData > MlfTrackDataPtr
void ComputePolygonDirection(const Eigen::Vector3d &ref_center, const base::ObjectPtr &object, Eigen::Vector3f *direction)
Compute polygon direction
std::shared_ptr< TrackedObject > TrackedObjectPtr
std::string GetConfigFile(const std::string &config_path, const std::string &config_file)
Definition util.cc:80
class register implement
Definition arena_queue.h:37