CARLA
Loading...
Searching...
No Matches
test_imu_compass.cpp
Go to the documentation of this file.
1// Copyright (c) 2026 Computer Vision Center (CVC) at the Universitat Autonoma
2// de Barcelona (UAB).
3//
4// This work is licensed under the terms of the MIT license.
5// For a copy, see <https://opensource.org/licenses/MIT>.
6
7#include "test.h"
8
10
11#include <cmath>
12
13namespace {
14
15constexpr float kEps = 1e-5f;
16
17// Recover yaw (radians, REP-103) from a (w, x, y, z) quaternion that is known
18// to be yaw-only (x == y == 0).
19float YawFrom(const std::array<float, 4> &q) {
20 return 2.0f * std::atan2(q[3], q[0]);
21}
22
23} // namespace
24
25TEST(ImuMath, north_is_pi_over_two) {
26 // Compass = 0 means the vehicle faces magnetic North. REP-103 yaw measured
27 // counter-clockwise from East should be +pi/2.
28 const auto q = carla::ros2::OrientationFromCompass(0.0f);
29
30 ASSERT_NEAR(q[1], 0.0f, kEps);
31 ASSERT_NEAR(q[2], 0.0f, kEps);
32 ASSERT_NEAR(q[0], std::cos(static_cast<float>(M_PI) / 4.0f), kEps);
33 ASSERT_NEAR(q[3], std::sin(static_cast<float>(M_PI) / 4.0f), kEps);
34 ASSERT_NEAR(YawFrom(q), static_cast<float>(M_PI) / 2.0f, kEps);
35}
36
37TEST(ImuMath, east_is_zero_yaw) {
38 // Compass = pi/2 means the vehicle faces magnetic East. REP-103 yaw = 0.
39 const auto q = carla::ros2::OrientationFromCompass(static_cast<float>(M_PI) / 2.0f);
40
41 ASSERT_NEAR(q[1], 0.0f, kEps);
42 ASSERT_NEAR(q[2], 0.0f, kEps);
43 ASSERT_NEAR(q[0], 1.0f, kEps);
44 ASSERT_NEAR(q[3], 0.0f, kEps);
45 ASSERT_NEAR(YawFrom(q), 0.0f, kEps);
46}
47
48TEST(ImuMath, south_is_negative_pi_over_two) {
49 // Compass = pi means the vehicle faces magnetic South. REP-103 yaw = -pi/2.
50 const auto q = carla::ros2::OrientationFromCompass(static_cast<float>(M_PI));
51
52 ASSERT_NEAR(q[1], 0.0f, kEps);
53 ASSERT_NEAR(q[2], 0.0f, kEps);
54 ASSERT_NEAR(YawFrom(q), -static_cast<float>(M_PI) / 2.0f, kEps);
55}
56
57TEST(ImuMath, west_is_pi) {
58 // Compass = 3*pi/2 means the vehicle faces magnetic West. REP-103 yaw is
59 // pi/2 - 3*pi/2 = -pi (equivalently +pi); compare on |yaw| to avoid the
60 // atan2 wrap-around at the +/-pi seam.
62 3.0f * static_cast<float>(M_PI) / 2.0f);
63
64 ASSERT_NEAR(q[1], 0.0f, kEps);
65 ASSERT_NEAR(q[2], 0.0f, kEps);
66 ASSERT_NEAR(std::abs(YawFrom(q)), static_cast<float>(M_PI), kEps);
67}
68
69TEST(ImuMath, accel_mirrors_y_only) {
70 // Ordinary vector: left-handed -> right-handed is a plain y negation.
71 const auto a = carla::ros2::AccelToRos(1.0f, 2.0f, 3.0f);
72 ASSERT_NEAR(a[0], 1.0f, kEps);
73 ASSERT_NEAR(a[1], -2.0f, kEps);
74 ASSERT_NEAR(a[2], 3.0f, kEps);
75}
76
77TEST(ImuMath, gyro_negates_x_and_z_keeps_y) {
78 // Pseudovector: mirroring y flips the in-plane components (x and z).
79 const auto g = carla::ros2::GyroToRos(1.0f, 2.0f, 3.0f);
80 ASSERT_NEAR(g[0], -1.0f, kEps);
81 ASSERT_NEAR(g[1], 2.0f, kEps);
82 ASSERT_NEAR(g[2], -3.0f, kEps);
83}
84
85TEST(ImuMath, gyro_left_turn_yields_positive_ros_yaw_rate) {
86 // A vehicle turning left reports a negative wz in CARLA/UE's left-handed
87 // frame; REP-103 wants a positive yaw rate (CCW from above).
88 const auto g = carla::ros2::GyroToRos(0.0f, 0.0f, -0.5f);
89 ASSERT_GT(g[2], 0.0f);
90}
91
92TEST(ImuMath, is_not_the_regressed_pi_over_four) {
93 // Regression guard: the spelling shipped on ue5-dev before this fix
94 // returned pi/4 - compass instead of pi/2 - compass. With compass = 0 the
95 // buggy yaw is pi/4. Verify the helper does not produce that anymore.
96 const auto q = carla::ros2::OrientationFromCompass(0.0f);
97 ASSERT_GT(std::abs(YawFrom(q) - static_cast<float>(M_PI) / 4.0f), 1e-3f);
98}
std::array< float, 3 > AccelToRos(float ax, float ay, float az)
Definition ImuMath.h:34
std::array< float, 3 > GyroToRos(float gx, float gy, float gz)
Definition ImuMath.h:51
std::array< float, 4 > OrientationFromCompass(float compass)
Definition ImuMath.h:23
TEST(ImuMath, north_is_pi_over_two)