blob: fb0efa9209c7ff6b69519e952c2309fd86fb5cf1 [file] [log] [blame]
James Kuszmaul04a343c2023-02-20 16:38:22 -08001#include "y2023/localizer/localizer.h"
2
Philipp Schrader790cb542023-07-05 21:06:52 -07003#include "gtest/gtest.h"
4
James Kuszmaul04a343c2023-02-20 16:38:22 -08005#include "aos/events/logging/log_writer.h"
6#include "aos/events/simulated_event_loop.h"
7#include "frc971/control_loops/drivetrain/drivetrain_test_lib.h"
8#include "frc971/control_loops/drivetrain/localizer_generated.h"
9#include "frc971/control_loops/pose.h"
10#include "frc971/vision/target_map_generated.h"
James Kuszmaul04a343c2023-02-20 16:38:22 -080011#include "y2023/constants/simulated_constants_sender.h"
12#include "y2023/control_loops/drivetrain/drivetrain_base.h"
13#include "y2023/localizer/status_generated.h"
James Kuszmaul18008f82023-02-23 20:52:50 -080014#include "y2023/localizer/utils.h"
James Kuszmaul04a343c2023-02-20 16:38:22 -080015
16DEFINE_string(output_folder, "",
17 "If set, logs all channels to the provided logfile.");
milind-u48601192023-03-11 19:44:46 -080018DECLARE_double(max_distance_to_target);
James Kuszmaul04a343c2023-02-20 16:38:22 -080019
20namespace y2023::localizer::testing {
21
22using frc971::control_loops::drivetrain::Output;
23
24class LocalizerTest : public ::testing::Test {
25 protected:
26 static constexpr uint64_t kTargetId = 1;
27 LocalizerTest()
28 : configuration_(aos::configuration::ReadConfig("y2023/aos_config.json")),
29 event_loop_factory_(&configuration_.message()),
30 roborio_node_([this]() {
31 // Get the constants sent before anything else happens.
32 // It has nothing to do with the roborio node.
33 SendSimulationConstants(&event_loop_factory_, 7971,
34 "y2023/constants/test_constants.json");
35 return aos::configuration::GetNode(&configuration_.message(),
36 "roborio");
37 }()),
38 imu_node_(
39 aos::configuration::GetNode(&configuration_.message(), "imu")),
40 camera_node_(
41 aos::configuration::GetNode(&configuration_.message(), "pi1")),
42 dt_config_(frc971::control_loops::drivetrain::testing::
43 GetTestDrivetrainConfig()),
44 localizer_event_loop_(
45 event_loop_factory_.MakeEventLoop("localizer", imu_node_)),
46 localizer_(localizer_event_loop_.get(), dt_config_),
47 drivetrain_plant_event_loop_(event_loop_factory_.MakeEventLoop(
48 "drivetrain_plant", roborio_node_)),
49 drivetrain_plant_imu_event_loop_(
50 event_loop_factory_.MakeEventLoop("drivetrain_plant", imu_node_)),
51 drivetrain_plant_(drivetrain_plant_event_loop_.get(),
52 drivetrain_plant_imu_event_loop_.get(), dt_config_,
53 std::chrono::microseconds(500)),
54 roborio_test_event_loop_(
55 event_loop_factory_.MakeEventLoop("test", roborio_node_)),
56 imu_test_event_loop_(
57 event_loop_factory_.MakeEventLoop("test", imu_node_)),
58 camera_test_event_loop_(
59 event_loop_factory_.MakeEventLoop("test", camera_node_)),
60 logger_test_event_loop_(
61 event_loop_factory_.GetNodeEventLoopFactory("logger")
62 ->MakeEventLoop("test")),
63 constants_fetcher_(imu_test_event_loop_.get()),
64 output_sender_(
65 roborio_test_event_loop_->MakeSender<Output>("/drivetrain")),
66 target_sender_(
67 camera_test_event_loop_->MakeSender<frc971::vision::TargetMap>(
68 "/camera")),
69 control_sender_(roborio_test_event_loop_->MakeSender<
70 frc971::control_loops::drivetrain::LocalizerControl>(
71 "/drivetrain")),
72 output_fetcher_(
73 roborio_test_event_loop_
74 ->MakeFetcher<frc971::controls::LocalizerOutput>("/localizer")),
75 status_fetcher_(
76 imu_test_event_loop_->MakeFetcher<Status>("/localizer")) {
milind-u48601192023-03-11 19:44:46 -080077 FLAGS_max_distance_to_target = 100.0;
James Kuszmaul04a343c2023-02-20 16:38:22 -080078 {
79 aos::TimerHandler *timer = roborio_test_event_loop_->AddTimer([this]() {
80 {
81 auto builder = output_sender_.MakeBuilder();
82 auto output_builder = builder.MakeBuilder<Output>();
83 output_builder.add_left_voltage(output_voltages_(0));
84 output_builder.add_right_voltage(output_voltages_(1));
85 builder.CheckOk(builder.Send(output_builder.Finish()));
86 }
87 });
88 roborio_test_event_loop_->OnRun([timer, this]() {
Philipp Schradera6712522023-07-05 20:25:11 -070089 timer->Schedule(roborio_test_event_loop_->monotonic_now(),
90 std::chrono::milliseconds(5));
James Kuszmaul04a343c2023-02-20 16:38:22 -080091 });
92 }
93 {
94 // Sanity check that the test calibration files look like what we
95 // expect.
96 CHECK_EQ("pi1", constants_fetcher_.constants()
97 .cameras()
98 ->Get(0)
99 ->calibration()
100 ->node_name()
101 ->string_view());
102 const Eigen::Matrix<double, 4, 4> H_robot_camera =
103 frc971::control_loops::drivetrain::FlatbufferToTransformationMatrix(
104 *constants_fetcher_.constants()
105 .cameras()
106 ->Get(0)
107 ->calibration()
108 ->fixed_extrinsics());
109
110 CHECK_EQ(kTargetId, constants_fetcher_.constants()
111 .target_map()
112 ->target_poses()
113 ->Get(0)
114 ->id());
115 const Eigen::Matrix<double, 4, 4> H_field_target = PoseToTransform(
116 constants_fetcher_.constants().target_map()->target_poses()->Get(0));
117 // For reference, the camera should pointed straight forwards on the
118 // robot, offset by 1 meter.
119 aos::TimerHandler *timer = camera_test_event_loop_->AddTimer(
120 [this, H_robot_camera, H_field_target]() {
121 if (!send_targets_) {
122 return;
123 }
124 const frc971::control_loops::Pose robot_pose(
125 {drivetrain_plant_.GetPosition().x(),
126 drivetrain_plant_.GetPosition().y(), 0.0},
milind-ub45c6d92023-03-11 18:56:15 -0800127 drivetrain_plant_.state()(2, 0) + implied_yaw_error_);
James Kuszmaul04a343c2023-02-20 16:38:22 -0800128
129 const Eigen::Matrix<double, 4, 4> H_field_camera =
130 robot_pose.AsTransformationMatrix() * H_robot_camera;
131 const Eigen::Matrix<double, 4, 4> H_camera_target =
132 H_field_camera.inverse() * H_field_target;
133
134 const Eigen::Quaterniond quat(H_camera_target.block<3, 3>(0, 0));
135 const Eigen::Vector3d translation(
136 H_camera_target.block<3, 1>(0, 3));
137
138 auto builder = target_sender_.MakeBuilder();
139 frc971::vision::Quaternion::Builder quat_builder(*builder.fbb());
140 quat_builder.add_w(quat.w());
141 quat_builder.add_x(quat.x());
142 quat_builder.add_y(quat.y());
143 quat_builder.add_z(quat.z());
144 auto quat_offset = quat_builder.Finish();
145 frc971::vision::Position::Builder position_builder(*builder.fbb());
146 position_builder.add_x(translation.x());
147 position_builder.add_y(translation.y());
148 position_builder.add_z(translation.z());
149 auto position_offset = position_builder.Finish();
150
151 frc971::vision::TargetPoseFbs::Builder target_builder(
152 *builder.fbb());
153 target_builder.add_id(send_target_id_);
154 target_builder.add_position(position_offset);
155 target_builder.add_orientation(quat_offset);
milind-u7a7f6662023-02-26 16:41:29 -0800156 target_builder.add_pose_error(pose_error_);
milind-u08fb9722023-03-25 18:23:59 -0700157 target_builder.add_pose_error_ratio(pose_error_ratio_);
James Kuszmaul04a343c2023-02-20 16:38:22 -0800158 auto target_offset = target_builder.Finish();
159
160 auto targets_offset = builder.fbb()->CreateVector({target_offset});
161 frc971::vision::TargetMap::Builder map_builder(*builder.fbb());
162 map_builder.add_target_poses(targets_offset);
163 map_builder.add_monotonic_timestamp_ns(
164 std::chrono::duration_cast<std::chrono::nanoseconds>(
165 camera_test_event_loop_->monotonic_now().time_since_epoch())
166 .count());
167
168 builder.CheckOk(builder.Send(map_builder.Finish()));
169 });
170 camera_test_event_loop_->OnRun([timer, this]() {
Philipp Schradera6712522023-07-05 20:25:11 -0700171 timer->Schedule(camera_test_event_loop_->monotonic_now(),
172 std::chrono::milliseconds(50));
James Kuszmaul04a343c2023-02-20 16:38:22 -0800173 });
174 }
175
176 localizer_control_send_timer_ =
177 roborio_test_event_loop_->AddTimer([this]() {
178 auto builder = control_sender_.MakeBuilder();
179 auto control_builder = builder.MakeBuilder<
180 frc971::control_loops::drivetrain::LocalizerControl>();
181 control_builder.add_x(localizer_control_x_);
182 control_builder.add_y(localizer_control_y_);
183 control_builder.add_theta(localizer_control_theta_);
184 control_builder.add_theta_uncertainty(0.01);
185 control_builder.add_keep_current_theta(false);
186 builder.CheckOk(builder.Send(control_builder.Finish()));
187 });
188
189 // Get things zeroed.
190 event_loop_factory_.RunFor(std::chrono::seconds(10));
191 CHECK(status_fetcher_.Fetch());
192 CHECK(status_fetcher_->imu()->zeroed());
193
194 if (!FLAGS_output_folder.empty()) {
195 logger_event_loop_ =
196 event_loop_factory_.MakeEventLoop("logger", imu_node_);
197 logger_ = std::make_unique<aos::logger::Logger>(logger_event_loop_.get());
198 logger_->StartLoggingOnRun(FLAGS_output_folder);
199 }
200 }
201
202 void SendLocalizerControl(double x, double y, double theta) {
203 localizer_control_x_ = x;
204 localizer_control_y_ = y;
205 localizer_control_theta_ = theta;
Philipp Schradera6712522023-07-05 20:25:11 -0700206 localizer_control_send_timer_->Schedule(
James Kuszmaul04a343c2023-02-20 16:38:22 -0800207 roborio_test_event_loop_->monotonic_now());
208 }
209 ::testing::AssertionResult IsNear(double expected, double actual,
210 double epsilon) {
211 if (std::abs(expected - actual) < epsilon) {
212 return ::testing::AssertionSuccess();
213 } else {
214 return ::testing::AssertionFailure()
215 << "Expected " << expected << " but got " << actual
216 << " with a max difference of " << epsilon
217 << " and an actual difference of " << std::abs(expected - actual);
218 }
219 }
220 ::testing::AssertionResult VerifyEstimatorAccurate(double eps) {
221 const Eigen::Matrix<double, 5, 1> true_state = drivetrain_plant_.state();
222 ::testing::AssertionResult result(true);
223 status_fetcher_.Fetch();
224 if (!(result = IsNear(status_fetcher_->state()->x(), true_state(0), eps))) {
225 return result;
226 }
227 if (!(result = IsNear(status_fetcher_->state()->y(), true_state(1), eps))) {
228 return result;
229 }
230 if (!(result =
231 IsNear(status_fetcher_->state()->theta(), true_state(2), eps))) {
232 return result;
233 }
234 return result;
235 }
236
237 aos::FlatbufferDetachedBuffer<aos::Configuration> configuration_;
238 aos::SimulatedEventLoopFactory event_loop_factory_;
239 const aos::Node *const roborio_node_;
240 const aos::Node *const imu_node_;
241 const aos::Node *const camera_node_;
242 const frc971::control_loops::drivetrain::DrivetrainConfig<double> dt_config_;
243 std::unique_ptr<aos::EventLoop> localizer_event_loop_;
244 Localizer localizer_;
245
246 std::unique_ptr<aos::EventLoop> drivetrain_plant_event_loop_;
247 std::unique_ptr<aos::EventLoop> drivetrain_plant_imu_event_loop_;
248 frc971::control_loops::drivetrain::testing::DrivetrainSimulation
249 drivetrain_plant_;
250
251 std::unique_ptr<aos::EventLoop> roborio_test_event_loop_;
252 std::unique_ptr<aos::EventLoop> imu_test_event_loop_;
253 std::unique_ptr<aos::EventLoop> camera_test_event_loop_;
254 std::unique_ptr<aos::EventLoop> logger_test_event_loop_;
255
256 frc971::constants::ConstantsFetcher<Constants> constants_fetcher_;
257
258 aos::Sender<Output> output_sender_;
259 aos::Sender<frc971::vision::TargetMap> target_sender_;
260 aos::Sender<frc971::control_loops::drivetrain::LocalizerControl>
261 control_sender_;
262 aos::Fetcher<frc971::controls::LocalizerOutput> output_fetcher_;
263 aos::Fetcher<Status> status_fetcher_;
264
265 Eigen::Vector2d output_voltages_ = Eigen::Vector2d::Zero();
266
267 aos::TimerHandler *localizer_control_send_timer_;
268
269 bool send_targets_ = false;
270
271 double localizer_control_x_ = 0.0;
272 double localizer_control_y_ = 0.0;
273 double localizer_control_theta_ = 0.0;
274
275 std::unique_ptr<aos::EventLoop> logger_event_loop_;
276 std::unique_ptr<aos::logger::Logger> logger_;
277
278 uint64_t send_target_id_ = kTargetId;
milind-u7a7f6662023-02-26 16:41:29 -0800279 double pose_error_ = 1e-7;
milind-u08fb9722023-03-25 18:23:59 -0700280 double pose_error_ratio_ = 0.1;
milind-ub45c6d92023-03-11 18:56:15 -0800281 double implied_yaw_error_ = 0.0;
James Kuszmaul04a343c2023-02-20 16:38:22 -0800282
283 gflags::FlagSaver flag_saver_;
284};
285
286// Test a simple scenario with no errors where the robot should just drive
287// straight forwards.
288TEST_F(LocalizerTest, Nominal) {
289 output_voltages_ << 1.0, 1.0;
290 event_loop_factory_.RunFor(std::chrono::seconds(2));
291 CHECK(output_fetcher_.Fetch());
292 CHECK(status_fetcher_.Fetch());
293 // The two can be different because they may've been sent at different
294 // times.
295 EXPECT_NEAR(output_fetcher_->x(), status_fetcher_->state()->x(), 1e-2);
296 EXPECT_NEAR(output_fetcher_->y(), status_fetcher_->state()->y(), 1e-6);
297 EXPECT_NEAR(output_fetcher_->theta(), status_fetcher_->state()->theta(),
298 1e-6);
299 // Confirm that we did indeed drive forwards (and straight), as expected.
300 EXPECT_LT(0.1, output_fetcher_->x());
301 EXPECT_NEAR(0.0, output_fetcher_->y(), 1e-10);
302 EXPECT_NEAR(0.0, output_fetcher_->theta(), 1e-10);
303 EXPECT_NEAR(0.0, status_fetcher_->state()->left_voltage_error(), 1e-1);
304 EXPECT_NEAR(0.0, status_fetcher_->state()->right_voltage_error(), 1e-1);
305
306 // And check that we actually think that we are near where the simulator
307 // says we are.
308 EXPECT_TRUE(VerifyEstimatorAccurate(1e-2));
309}
310
311// Confirm that when the robot drives backwards that we localize correctly.
312TEST_F(LocalizerTest, NominalReverse) {
313 output_voltages_ << -1.0, -1.0;
314 event_loop_factory_.RunFor(std::chrono::seconds(2));
315 CHECK(output_fetcher_.Fetch());
316 CHECK(status_fetcher_.Fetch());
317 // The two can be different because they may've been sent at different
318 // times.
319 EXPECT_NEAR(output_fetcher_->x(), status_fetcher_->state()->x(), 1e-2);
320 EXPECT_NEAR(output_fetcher_->y(), status_fetcher_->state()->y(), 1e-6);
321 EXPECT_NEAR(output_fetcher_->theta(), status_fetcher_->state()->theta(),
322 1e-6);
323 // Confirm that we did indeed drive backwards (and straight), as expected.
324 EXPECT_GT(-0.1, output_fetcher_->x());
325 EXPECT_NEAR(0.0, output_fetcher_->y(), 1e-10);
326 EXPECT_NEAR(0.0, output_fetcher_->theta(), 1e-10);
327 EXPECT_NEAR(0.0, status_fetcher_->state()->left_voltage_error(), 1e-1);
328 EXPECT_NEAR(0.0, status_fetcher_->state()->right_voltage_error(), 1e-1);
329
330 // And check that we actually think that we are near where the simulator
331 // says we are.
332 EXPECT_TRUE(VerifyEstimatorAccurate(1e-2));
333}
334
335// Confirm that when the robot turns counter-clockwise that we localize
336// correctly.
337TEST_F(LocalizerTest, NominalSpinInPlace) {
338 output_voltages_ << -1.0, 1.0;
James Kuszmaul456774b2023-03-08 21:29:15 -0800339 // Go 1 ms over 2 sec to make sure we actually see relatively recent messages
340 // on each channel.
341 event_loop_factory_.RunFor(std::chrono::milliseconds(2001));
James Kuszmaul04a343c2023-02-20 16:38:22 -0800342 CHECK(output_fetcher_.Fetch());
343 CHECK(status_fetcher_.Fetch());
344 // The two can be different because they may've been sent at different
345 // times.
346 EXPECT_NEAR(output_fetcher_->x(), status_fetcher_->state()->x(), 1e-6);
347 EXPECT_NEAR(output_fetcher_->y(), status_fetcher_->state()->y(), 1e-6);
348 EXPECT_NEAR(output_fetcher_->theta(), status_fetcher_->state()->theta(),
349 1e-2);
350 // Confirm that we did indeed turn counter-clockwise.
351 EXPECT_NEAR(0.0, output_fetcher_->x(), 1e-10);
352 EXPECT_NEAR(0.0, output_fetcher_->y(), 1e-10);
353 EXPECT_LT(0.1, output_fetcher_->theta());
354 EXPECT_NEAR(0.0, status_fetcher_->state()->left_voltage_error(), 1e-1);
355 EXPECT_NEAR(0.0, status_fetcher_->state()->right_voltage_error(), 1e-1);
356
357 // And check that we actually think that we are near where the simulator
358 // says we are.
359 EXPECT_TRUE(VerifyEstimatorAccurate(1e-2));
360}
361
362// Confirm that when the robot drives in a curve that we localize
363// successfully.
364TEST_F(LocalizerTest, NominalCurve) {
365 output_voltages_ << 2.0, 3.0;
366 event_loop_factory_.RunFor(std::chrono::seconds(4));
367 CHECK(output_fetcher_.Fetch());
368 CHECK(status_fetcher_.Fetch());
369 // The two can be different because they may've been sent at different
370 // times.
371 EXPECT_NEAR(output_fetcher_->x(), status_fetcher_->state()->x(), 1e-2);
372 EXPECT_NEAR(output_fetcher_->y(), status_fetcher_->state()->y(), 1e-2);
373 EXPECT_NEAR(output_fetcher_->theta(), status_fetcher_->state()->theta(),
374 1e-2);
375 // Confirm that we did indeed drive in a rough, counter-clockwise, curve.
376 EXPECT_LT(0.1, output_fetcher_->x());
377 EXPECT_LT(0.1, output_fetcher_->y());
378 EXPECT_LT(0.1, output_fetcher_->theta());
379
380 // And check that we actually think that we are near where the simulator
381 // says we are.
382 EXPECT_TRUE(VerifyEstimatorAccurate(1e-2));
383}
384
385// Tests that, in the presence of a non-zero voltage error, that we correct
386// for it.
387TEST_F(LocalizerTest, VoltageErrorDisabled) {
388 output_voltages_ << 0.0, 0.0;
389 drivetrain_plant_.set_left_voltage_offset(2.0);
390 drivetrain_plant_.set_right_voltage_offset(2.0);
391
392 event_loop_factory_.RunFor(std::chrono::seconds(2));
393 CHECK(output_fetcher_.Fetch());
394 CHECK(status_fetcher_.Fetch());
395 // We should've just ended up driving straight forwards.
396 EXPECT_LT(0.1, output_fetcher_->x());
397 EXPECT_NEAR(0.0, output_fetcher_->y(), 1e-10);
398 EXPECT_NEAR(0.0, output_fetcher_->theta(), 1e-10);
399 EXPECT_NEAR(2.0, status_fetcher_->state()->left_voltage_error(), 1.0);
400 EXPECT_NEAR(2.0, status_fetcher_->state()->right_voltage_error(), 1.0);
401
402 // And check that we actually think that we are near where the simulator
403 // says we are.
404 EXPECT_TRUE(VerifyEstimatorAccurate(0.05));
405}
406
407// Tests that image corrections in the nominal case (no errors) causes no
408// issues.
409TEST_F(LocalizerTest, NominalImageCorrections) {
410 output_voltages_ << 3.0, 2.0;
411 send_targets_ = true;
412
413 event_loop_factory_.RunFor(std::chrono::seconds(4));
414 CHECK(status_fetcher_.Fetch());
415 EXPECT_TRUE(VerifyEstimatorAccurate(1e-2));
416 ASSERT_TRUE(status_fetcher_->has_statistics());
417 ASSERT_EQ(4u /* number of cameras */, status_fetcher_->statistics()->size());
418 ASSERT_EQ(status_fetcher_->statistics()->Get(0)->total_candidates(),
419 status_fetcher_->statistics()->Get(0)->total_accepted());
420 ASSERT_LT(10, status_fetcher_->statistics()->Get(0)->total_candidates());
421}
422
423// Tests that image corrections when there is an error at the start results
424// in us actually getting corrected over time.
425TEST_F(LocalizerTest, ImageCorrections) {
426 output_voltages_ << 0.0, 0.0;
427 drivetrain_plant_.mutable_state()->x() = 2.0;
428 drivetrain_plant_.mutable_state()->y() = 2.0;
429 SendLocalizerControl(5.0, 3.0, 0.0);
430 event_loop_factory_.RunFor(std::chrono::seconds(4));
431 CHECK(output_fetcher_.Fetch());
432 ASSERT_NEAR(5.0, output_fetcher_->x(), 1e-5);
433 ASSERT_NEAR(3.0, output_fetcher_->y(), 1e-5);
434 ASSERT_NEAR(0.0, output_fetcher_->theta(), 1e-5);
435
436 send_targets_ = true;
437
438 event_loop_factory_.RunFor(std::chrono::seconds(4));
439 CHECK(status_fetcher_.Fetch());
440 EXPECT_TRUE(VerifyEstimatorAccurate(0.1));
441 ASSERT_TRUE(status_fetcher_->has_statistics());
442 ASSERT_EQ(4u /* number of cameras */, status_fetcher_->statistics()->size());
443 ASSERT_EQ(status_fetcher_->statistics()->Get(0)->total_candidates(),
444 status_fetcher_->statistics()->Get(0)->total_accepted());
445 ASSERT_LT(10, status_fetcher_->statistics()->Get(0)->total_candidates());
446}
447
448// Tests that we correctly reject an invalid target.
449TEST_F(LocalizerTest, InvalidTargetId) {
450 output_voltages_ << 0.0, 0.0;
451 send_targets_ = true;
452 send_target_id_ = 100;
453
454 event_loop_factory_.RunFor(std::chrono::seconds(4));
455 CHECK(status_fetcher_.Fetch());
456 ASSERT_TRUE(status_fetcher_->has_statistics());
457 ASSERT_EQ(4u /* number of cameras */, status_fetcher_->statistics()->size());
458 ASSERT_EQ(0, status_fetcher_->statistics()->Get(0)->total_accepted());
459 ASSERT_LT(10, status_fetcher_->statistics()->Get(0)->total_candidates());
460 ASSERT_EQ(status_fetcher_->statistics()
461 ->Get(0)
462 ->rejection_reasons()
463 ->Get(static_cast<size_t>(RejectionReason::NO_SUCH_TARGET))
464 ->count(),
465 status_fetcher_->statistics()->Get(0)->total_candidates());
466}
467
milind-u7a7f6662023-02-26 16:41:29 -0800468// Tests that we correctly reject a detection with a high pose error.
469TEST_F(LocalizerTest, HighPoseError) {
470 output_voltages_ << 0.0, 0.0;
471 send_targets_ = true;
472 // Send the minimum pose error to be rejected
473 constexpr double kEps = 1e-9;
474 pose_error_ = 1e-6 + kEps;
475
476 event_loop_factory_.RunFor(std::chrono::seconds(4));
477 CHECK(status_fetcher_.Fetch());
478 ASSERT_TRUE(status_fetcher_->has_statistics());
479 ASSERT_EQ(4u /* number of cameras */, status_fetcher_->statistics()->size());
480 ASSERT_EQ(0, status_fetcher_->statistics()->Get(0)->total_accepted());
481 ASSERT_LT(10, status_fetcher_->statistics()->Get(0)->total_candidates());
482 ASSERT_EQ(status_fetcher_->statistics()
483 ->Get(0)
484 ->rejection_reasons()
485 ->Get(static_cast<size_t>(RejectionReason::HIGH_POSE_ERROR))
486 ->count(),
487 status_fetcher_->statistics()->Get(0)->total_candidates());
488}
489
milind-ub45c6d92023-03-11 18:56:15 -0800490// Tests that we correctly reject a detection with a high implied yaw error.
491TEST_F(LocalizerTest, HighImpliedYawError) {
492 output_voltages_ << 0.0, 0.0;
493 send_targets_ = true;
494 implied_yaw_error_ = 31.0 * M_PI / 180.0;
495
496 event_loop_factory_.RunFor(std::chrono::seconds(4));
497 CHECK(status_fetcher_.Fetch());
498 ASSERT_TRUE(status_fetcher_->has_statistics());
499 ASSERT_EQ(4u /* number of cameras */, status_fetcher_->statistics()->size());
500 ASSERT_EQ(0, status_fetcher_->statistics()->Get(0)->total_accepted());
501 ASSERT_LT(10, status_fetcher_->statistics()->Get(0)->total_candidates());
502 ASSERT_EQ(
503 status_fetcher_->statistics()
504 ->Get(0)
505 ->rejection_reasons()
506 ->Get(static_cast<size_t>(RejectionReason::HIGH_IMPLIED_YAW_ERROR))
507 ->count(),
508 status_fetcher_->statistics()->Get(0)->total_candidates());
509}
510
milind-u08fb9722023-03-25 18:23:59 -0700511// Tests that we correctly reject a detection with a high pose error ratio.
512TEST_F(LocalizerTest, HighPoseErrorRatio) {
513 output_voltages_ << 0.0, 0.0;
514 send_targets_ = true;
515 // Send the minimum pose error to be rejected
516 constexpr double kEps = 1e-9;
517 pose_error_ratio_ = 0.4 + kEps;
518
519 event_loop_factory_.RunFor(std::chrono::seconds(4));
520 CHECK(status_fetcher_.Fetch());
521 ASSERT_TRUE(status_fetcher_->has_statistics());
522 ASSERT_EQ(4u /* number of cameras */, status_fetcher_->statistics()->size());
523 ASSERT_EQ(0, status_fetcher_->statistics()->Get(0)->total_accepted());
524 ASSERT_LT(10, status_fetcher_->statistics()->Get(0)->total_candidates());
525 ASSERT_EQ(
526 status_fetcher_->statistics()
527 ->Get(0)
528 ->rejection_reasons()
529 ->Get(static_cast<size_t>(RejectionReason::HIGH_POSE_ERROR_RATIO))
530 ->count(),
531 status_fetcher_->statistics()->Get(0)->total_candidates());
532}
533
James Kuszmaul04a343c2023-02-20 16:38:22 -0800534} // namespace y2023::localizer::testing