123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- //
- // Unit tests for the AP_Math euler code
- //
- #include <AP_HAL/AP_HAL.h>
- #include <AP_Math/AP_Math.h>
- void setup();
- void loop();
- void test_matrix_rotate(void);
- void test_frame_transforms(void);
- void test_conversions(void);
- void test_quaternion_eulers(void);
- void test_matrix_eulers(void);
- const AP_HAL::HAL& hal = AP_HAL::get_HAL();
- #define SHOW_POLES_BREAKDOWN 0
- static float rad_diff(float rad1, float rad2)
- {
- float diff = rad1 - rad2;
- if (diff > M_PI) {
- diff -= 2 * M_PI;
- }
- if (diff < -M_PI) {
- diff += 2 * M_PI;
- }
- return fabsf(diff);
- }
- static void check_result(const char *msg,
- float roll, float pitch, float yaw,
- float roll2, float pitch2, float yaw2)
- {
- if (isnan(roll2) ||
- isnan(pitch2) ||
- isnan(yaw2)) {
- hal.console->printf("%s NAN eulers roll=%f pitch=%f yaw=%f\n",
- msg,
- (double)roll,
- (double)pitch,
- (double)yaw);
- }
- if (rad_diff(roll2,roll) > ToRad(179)) {
- // reverse all 3
- roll2 += fmodf(roll2 + M_PI, 2 * M_PI);
- pitch2 += fmodf(pitch2 + M_PI, 2 * M_PI);
- yaw2 += fmodf(yaw2 + M_PI, 2 * M_PI);
- }
- if (rad_diff(roll2,roll) > 0.01f ||
- rad_diff(pitch2, pitch) > 0.01f ||
- rad_diff(yaw2, yaw) > 0.01f) {
- if (pitch >= M_PI/2 ||
- pitch <= -M_PI/2 ||
- ToDeg(rad_diff(pitch, M_PI/2)) < 1 ||
- ToDeg(rad_diff(pitch, -M_PI/2)) < 1) {
- // we expect breakdown at these poles
- #if SHOW_POLES_BREAKDOWN
- hal.console->printf(
- "%s breakdown eulers roll=%f/%f pitch=%f/%f yaw=%f/%f\n",
- msg,
- (double)ToDeg(roll), (double)ToDeg(roll2),
- (double)ToDeg(pitch), (double)ToDeg(pitch2),
- (double)ToDeg(yaw), (double)ToDeg(yaw2));
- #endif
- } else {
- hal.console->printf(
- "%s incorrect eulers roll=%f/%f pitch=%f/%f yaw=%f/%f\n",
- msg,
- (double)ToDeg(roll), (double)ToDeg(roll2),
- (double)ToDeg(pitch), (double)ToDeg(pitch2),
- (double)ToDeg(yaw), (double)ToDeg(yaw2));
- }
- }
- }
- static void test_euler(float roll, float pitch, float yaw)
- {
- Matrix3f m;
- float roll2, pitch2, yaw2;
- m.from_euler(roll, pitch, yaw);
- m.to_euler(&roll2, &pitch2, &yaw2);
- check_result("test_euler", roll, pitch, yaw, roll2, pitch2, yaw2);
- }
- static const float angles[] = { 0, M_PI/8, M_PI/4, M_PI/2, M_PI,
- -M_PI/8, -M_PI/4, -M_PI/2, -M_PI};
- void test_matrix_eulers(void)
- {
- uint8_t N = ARRAY_SIZE(angles);
- hal.console->printf("rotation matrix unit tests\n\n");
- for (uint8_t i = 0; i < N; i++)
- for (uint8_t j = 0; j < N; j++)
- for (uint8_t k = 0; k < N; k++)
- test_euler(angles[i], angles[j], angles[k]);
- hal.console->printf("tests done\n\n");
- }
- static void test_quaternion(float roll, float pitch, float yaw)
- {
- Quaternion q;
- Matrix3f m;
- float roll2, pitch2, yaw2;
- q.from_euler(roll, pitch, yaw);
- q.to_euler(roll2, pitch2, yaw2);
- check_result("test_quaternion1", roll, pitch, yaw, roll2, pitch2, yaw2);
- m.from_euler(roll, pitch, yaw);
- m.to_euler(&roll2, &pitch2, &yaw2);
- check_result("test_quaternion2", roll, pitch, yaw, roll2, pitch2, yaw2);
- m.from_euler(roll, pitch, yaw);
- q.from_rotation_matrix(m);
- q.to_euler(roll2, pitch2, yaw2);
- check_result("test_quaternion3", roll, pitch, yaw, roll2, pitch2, yaw2);
- q.rotation_matrix(m);
- m.to_euler(&roll2, &pitch2, &yaw2);
- check_result("test_quaternion4", roll, pitch, yaw, roll2, pitch2, yaw2);
- }
- void test_quaternion_eulers(void)
- {
- uint8_t N = ARRAY_SIZE(angles);
- hal.console->printf("quaternion unit tests\n\n");
- test_quaternion(M_PI/4, 0, 0);
- test_quaternion(0, M_PI/4, 0);
- test_quaternion(0, 0, M_PI/4);
- test_quaternion(-M_PI/4, 0, 0);
- test_quaternion(0, -M_PI/4, 0);
- test_quaternion(0, 0, -M_PI/4);
- test_quaternion(-M_PI/4, 1, 1);
- test_quaternion(1, -M_PI/4, 1);
- test_quaternion(1, 1, -M_PI/4);
- test_quaternion(ToRad(89), 0, 0.1f);
- test_quaternion(0, ToRad(89), 0.1f);
- test_quaternion(0.1f, 0, ToRad(89));
- test_quaternion(ToRad(91), 0, 0.1f);
- test_quaternion(0, ToRad(91), 0.1f);
- test_quaternion(0.1f, 0, ToRad(91));
- for (uint8_t i = 0; i < N; i++)
- for (uint8_t j = 0; j < N; j++)
- for (uint8_t k = 0; k < N; k++)
- test_quaternion(angles[i], angles[j], angles[k]);
- hal.console->printf("tests done\n\n");
- }
- static void test_conversion(float roll, float pitch, float yaw)
- {
- Quaternion q;
- Matrix3f m, m2;
- float roll2, pitch2, yaw2;
- float roll3, pitch3, yaw3;
- q.from_euler(roll, pitch, yaw);
- q.to_euler(roll2, pitch2, yaw2);
- check_result("test_conversion1", roll, pitch, yaw, roll2, pitch2, yaw2);
- q.rotation_matrix(m);
- m.to_euler(&roll2, &pitch2, &yaw2);
- m2.from_euler(roll, pitch, yaw);
- m2.to_euler(&roll3, &pitch3, &yaw3);
- if (m.is_nan()) {
- hal.console->printf("NAN matrix roll=%f pitch=%f yaw=%f\n",
- (double)roll,
- (double)pitch,
- (double)yaw);
- }
- check_result("test_conversion2", roll, pitch, yaw, roll2, pitch2, yaw2);
- check_result("test_conversion3", roll, pitch, yaw, roll3, pitch3, yaw3);
- }
- void test_conversions(void)
- {
- uint8_t N = ARRAY_SIZE(angles);
- hal.console->printf("matrix/quaternion tests\n\n");
- test_conversion(1, 1.1f, 1.2f);
- test_conversion(1, -1.1f, 1.2f);
- test_conversion(1, -1.1f, -1.2f);
- test_conversion(-1, 1.1f, -1.2f);
- test_conversion(-1, 1.1f, 1.2f);
- for (uint8_t i = 0; i < N; i++)
- for (uint8_t j = 0; j < N; j++)
- for (uint8_t k = 0; k < N; k++)
- test_conversion(angles[i], angles[j], angles[k]);
- hal.console->printf("tests done\n\n");
- }
- void test_frame_transforms(void)
- {
- Vector3f v, v2;
- Quaternion q;
- Matrix3f m;
- hal.console->printf("frame transform tests\n\n");
- q.from_euler(ToRad(45), ToRad(45), ToRad(45));
- q.normalize();
- m.from_euler(ToRad(45), ToRad(45), ToRad(45));
- v2 = v = Vector3f(0.0f, 0.0f, 1.0f);
- q.earth_to_body(v2);
- hal.console->printf("%f %f %f\n", (double)v2.x, (double)v2.y, (double)v2.z);
- v2 = m * v;
- hal.console->printf("%f %f %f\n\n", (double)v2.x, (double)v2.y, (double)v2.z);
- v2 = v = Vector3f(0.0f, 1.0f, 0.0f);
- q.earth_to_body(v2);
- hal.console->printf("%f %f %f\n", (double)v2.x, (double)v2.y, (double)v2.z);
- v2 = m * v;
- hal.console->printf("%f %f %f\n\n", (double)v2.x, (double)v2.y, (double)v2.z);
- v2 = v = Vector3f(1.0f, 0.0f, 0.0f);
- q.earth_to_body(v2);
- hal.console->printf("%f %f %f\n", (double)v2.x, (double)v2.y, (double)v2.z);
- v2 = m * v;
- hal.console->printf("%f %f %f\n", (double)v2.x, (double)v2.y, (double)v2.z);
- }
- // generate a random float between -1 and 1
- static float rand_num(void)
- {
- return ((2.0f * get_random16()) / 0xFFFF) - 1.0f;
- }
- void test_matrix_rotate(void)
- {
- Matrix3f m1, m2, diff;
- Vector3f r;
- m1.identity();
- m2.identity();
- r.x = rand_num();
- r.y = rand_num();
- r.z = rand_num();
- for (uint16_t i = 0; i < 1000; i++) {
- // old method
- Matrix3f temp_matrix;
- temp_matrix.a.x = 0;
- temp_matrix.a.y = -r.z;
- temp_matrix.a.z = r.y;
- temp_matrix.b.x = r.z;
- temp_matrix.b.y = 0;
- temp_matrix.b.z = -r.x;
- temp_matrix.c.x = -r.y;
- temp_matrix.c.y = r.x;
- temp_matrix.c.z = 0;
- temp_matrix = m1 * temp_matrix;
- m1 += temp_matrix;
- // new method
- m2.rotate(r);
- // check they behave in the same way
- diff = m1 - m2;
- float err = diff.a.length() + diff.b.length() + diff.c.length();
- if (err > 0) {
- hal.console->printf("ERROR: i=%u err=%f\n", (unsigned)i, (double)err);
- }
- }
- }
- /*
- * euler angle tests
- */
- void setup(void)
- {
- hal.console->printf("euler unit tests\n\n");
- test_conversion(0, M_PI, 0);
- test_frame_transforms();
- test_conversions();
- test_quaternion_eulers();
- test_matrix_eulers();
- test_matrix_rotate();
- }
- void loop(void) {}
- AP_HAL_MAIN();
|