Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/libraries/AP_Common/tests/test_location.cpp
Views: 1799
#include <AP_gtest.h>1#include <AP_Common/Location.h>2#include <AP_Math/AP_Math.h>3#include <AP_AHRS/AP_AHRS.h>4#include <AP_Terrain/AP_Terrain.h>5#include <GCS_MAVLink/GCS_Dummy.h>67const AP_HAL::HAL& hal = AP_HAL::get_HAL();89class DummyVehicle {10public:11bool start_cmd(const AP_Mission::Mission_Command& cmd) { return true; };12bool verify_cmd(const AP_Mission::Mission_Command& cmd) { return true; };13void mission_complete() { };14AP_AHRS ahrs{AP_AHRS::FLAG_ALWAYS_USE_EKF};1516AP_Mission mission{17FUNCTOR_BIND_MEMBER(&DummyVehicle::start_cmd, bool, const AP_Mission::Mission_Command &),18FUNCTOR_BIND_MEMBER(&DummyVehicle::verify_cmd, bool, const AP_Mission::Mission_Command &),19FUNCTOR_BIND_MEMBER(&DummyVehicle::mission_complete, void)};20AP_Terrain terrain;21};2223const struct AP_Param::GroupInfo GCS_MAVLINK_Parameters::var_info[] = {24AP_GROUPEND25};26GCS_Dummy _gcs;2728static DummyVehicle vehicle;2930#define EXPECT_VECTOR2F_EQ(v1, v2) \31do { \32EXPECT_FLOAT_EQ(v1[0], v2[0]); \33EXPECT_FLOAT_EQ(v1[1], v2[1]); \34} while (false);3536#define EXPECT_VECTOR3F_EQ(v1, v2) \37do { \38EXPECT_FLOAT_EQ(v1[0], v2[0]); \39EXPECT_FLOAT_EQ(v1[1], v2[1]); \40EXPECT_FLOAT_EQ(v1[2], v2[2]); \41} while (false);4243#define EXPECT_VECTOR2F_NEAR(v1, v2, acc) \44do { \45EXPECT_NEAR(v1[0], v2[0], acc); \46EXPECT_NEAR(v1[1], v2[1], acc); \47} while (false);4849#define EXPECT_VECTOR3F_NEAR(v1, v2, acc) \50do { \51EXPECT_NEAR(v1[0], v2[0], acc); \52EXPECT_NEAR(v1[1], v2[1], acc); \53EXPECT_NEAR(v1[2], v2[2], acc); \54} while (false);5556TEST(Location, LatLngWrapping)57{58struct {59int32_t start_lat;60int32_t start_lng;61Vector2f delta_metres_ne;62int32_t expected_lat;63int32_t expected_lng;64} tests[] {65{519634000, 1797560000, Vector2f{0, 100000}, 519634000, -1787860777}66};6768for (auto &test : tests) {69// forward70{71Location loc{test.start_lat, test.start_lng, 0, Location::AltFrame::ABOVE_HOME};72loc.offset(test.delta_metres_ne[0], test.delta_metres_ne[1]);73EXPECT_EQ(test.expected_lat, loc.lat);74EXPECT_EQ(test.expected_lng, loc.lng);75EXPECT_EQ(0, loc.alt);76}77// and now reverse78{79Location rev{test.expected_lat, test.expected_lng, 0, Location::AltFrame::ABOVE_HOME};80rev.offset(-test.delta_metres_ne[0], -test.delta_metres_ne[1]);81EXPECT_EQ(rev.lat, test.start_lat);82EXPECT_EQ(rev.lng, test.start_lng);83EXPECT_EQ(0, rev.alt);84}85}86}8788TEST(Location, LocOffsetDouble)89{90struct {91int32_t home_lat;92int32_t home_lng;93Vector2d delta_metres_ne1;94Vector2d delta_metres_ne2;95Vector2d expected_pos_change;96} tests[] {97-353632620, 1491652373,98Vector2d{4682795.4576701336, 5953662.7673837934},99Vector2d{4682797.1904749088, 5953664.1586009059},100Vector2d{1.7365739,1.4261966},101};102103for (auto &test : tests) {104Location home{test.home_lat, test.home_lng, 0, Location::AltFrame::ABOVE_HOME};105Location loc1 = home;106Location loc2 = home;107loc1.offset(test.delta_metres_ne1.x, test.delta_metres_ne1.y);108loc2.offset(test.delta_metres_ne2.x, test.delta_metres_ne2.y);109Vector2d diff = loc1.get_distance_NE_double(loc2);110EXPECT_FLOAT_EQ(diff.x, test.expected_pos_change.x);111EXPECT_FLOAT_EQ(diff.y, test.expected_pos_change.y);112}113}114115TEST(Location, LocOffset3DDouble)116{117Location loc {118-353632620, 1491652373, 60000, Location::AltFrame::ABSOLUTE119};120// this is ned, so our latitude should change, and our new121// location should be above the original:122loc.offset(Vector3d{1000, 0, -10});123EXPECT_EQ(loc.lat, -353542788);124EXPECT_EQ(loc.lng, 1491652373);125EXPECT_EQ(loc.alt, 61000);126}127128TEST(Location, Tests)129{130Location test_location;131EXPECT_TRUE(test_location.is_zero());132EXPECT_FALSE(test_location.initialised());133const Location test_home{-35362938, 149165085, 100, Location::AltFrame::ABSOLUTE};134EXPECT_EQ(-35362938, test_home.lat);135EXPECT_EQ(149165085, test_home.lng);136EXPECT_EQ(100, test_home.alt);137EXPECT_EQ(0, test_home.relative_alt);138EXPECT_EQ(0, test_home.terrain_alt);139EXPECT_EQ(0, test_home.origin_alt);140EXPECT_EQ(0, test_home.loiter_ccw);141EXPECT_EQ(0, test_home.loiter_xtrack);142EXPECT_TRUE(test_home.initialised());143144const Vector3f test_vect{-42, 42, 0};145Location test_location3{test_vect, Location::AltFrame::ABOVE_HOME};146EXPECT_EQ(0, test_location3.lat);147EXPECT_EQ(0, test_location3.lng);148EXPECT_EQ(0, test_location3.alt);149EXPECT_EQ(1, test_location3.relative_alt);150EXPECT_EQ(0, test_location3.terrain_alt);151EXPECT_EQ(0, test_location3.origin_alt);152EXPECT_EQ(0, test_location3.loiter_ccw);153EXPECT_EQ(0, test_location3.loiter_xtrack);154EXPECT_FALSE(test_location3.initialised());155// EXPECT_EXIT(test_location3.change_alt_frame(Location::AltFrame::ABSOLUTE), PANIC something); // TODO check PANIC156157test_location3.set_alt_cm(-420, Location::AltFrame::ABSOLUTE);158EXPECT_EQ(-420, test_location3.alt);159EXPECT_EQ(0, test_location3.relative_alt);160EXPECT_EQ(0, test_location3.terrain_alt);161EXPECT_EQ(0, test_location3.origin_alt);162EXPECT_EQ(Location::AltFrame::ABSOLUTE, test_location3.get_alt_frame());163164test_location3.set_alt_cm(420, Location::AltFrame::ABOVE_HOME);165EXPECT_EQ(420, test_location3.alt);166EXPECT_EQ(1, test_location3.relative_alt);167EXPECT_EQ(0, test_location3.terrain_alt);168EXPECT_EQ(0, test_location3.origin_alt);169EXPECT_EQ(Location::AltFrame::ABOVE_HOME, test_location3.get_alt_frame());170171test_location3.set_alt_cm(-420, Location::AltFrame::ABOVE_ORIGIN);172EXPECT_EQ(-420, test_location3.alt);173EXPECT_EQ(0, test_location3.relative_alt);174EXPECT_EQ(0, test_location3.terrain_alt);175EXPECT_EQ(1, test_location3.origin_alt);176EXPECT_EQ(Location::AltFrame::ABOVE_ORIGIN, test_location3.get_alt_frame());177178test_location3.set_alt_cm(420, Location::AltFrame::ABOVE_TERRAIN);179EXPECT_EQ(420, test_location3.alt);180EXPECT_EQ(1, test_location3.relative_alt);181EXPECT_EQ(1, test_location3.terrain_alt);182EXPECT_EQ(0, test_location3.origin_alt);183EXPECT_EQ(Location::AltFrame::ABOVE_TERRAIN, test_location3.get_alt_frame());184185// No TERRAIN, NO HOME, NO ORIGIN186AP::terrain()->set_enabled(false);187for (auto current_frame = Location::AltFrame::ABSOLUTE;188current_frame <= Location::AltFrame::ABOVE_TERRAIN;189current_frame = static_cast<Location::AltFrame>(190(uint8_t) current_frame + 1)) {191for (auto desired_frame = Location::AltFrame::ABSOLUTE;192desired_frame <= Location::AltFrame::ABOVE_TERRAIN;193desired_frame = static_cast<Location::AltFrame>(194(uint8_t) desired_frame + 1)) {195test_location3.set_alt_cm(420, current_frame);196if (current_frame == desired_frame) {197EXPECT_TRUE(test_location3.change_alt_frame(desired_frame));198continue;199}200if (current_frame == Location::AltFrame::ABOVE_TERRAIN201|| desired_frame == Location::AltFrame::ABOVE_TERRAIN) {202EXPECT_FALSE(test_location3.change_alt_frame(desired_frame));203} else if (current_frame == Location::AltFrame::ABOVE_ORIGIN204|| desired_frame == Location::AltFrame::ABOVE_ORIGIN) {205EXPECT_FALSE(test_location3.change_alt_frame(desired_frame));206} else if (current_frame == Location::AltFrame::ABOVE_HOME207|| desired_frame == Location::AltFrame::ABOVE_HOME) {208EXPECT_FALSE(test_location3.change_alt_frame(desired_frame));209} else {210EXPECT_TRUE(test_location3.change_alt_frame(desired_frame));211}212}213}214// NO TERRAIN, NO ORIGIN215EXPECT_TRUE(vehicle.ahrs.set_home(test_home));216for (auto current_frame = Location::AltFrame::ABSOLUTE;217current_frame <= Location::AltFrame::ABOVE_TERRAIN;218current_frame = static_cast<Location::AltFrame>(219(uint8_t) current_frame + 1)) {220for (auto desired_frame = Location::AltFrame::ABSOLUTE;221desired_frame <= Location::AltFrame::ABOVE_TERRAIN;222desired_frame = static_cast<Location::AltFrame>(223(uint8_t) desired_frame + 1)) {224test_location3.set_alt_cm(420, current_frame);225if (current_frame == desired_frame) {226EXPECT_TRUE(test_location3.change_alt_frame(desired_frame));227continue;228}229if (current_frame == Location::AltFrame::ABOVE_TERRAIN230|| desired_frame == Location::AltFrame::ABOVE_TERRAIN) {231EXPECT_FALSE(test_location3.change_alt_frame(desired_frame));232} else if (current_frame == Location::AltFrame::ABOVE_ORIGIN233|| desired_frame == Location::AltFrame::ABOVE_ORIGIN) {234EXPECT_FALSE(test_location3.change_alt_frame(desired_frame));235} else {236EXPECT_TRUE(test_location3.change_alt_frame(desired_frame));237}238239}240}241// NO Origin242AP::terrain()->set_enabled(true);243for (auto current_frame = Location::AltFrame::ABSOLUTE;244current_frame <= Location::AltFrame::ABOVE_TERRAIN;245current_frame = static_cast<Location::AltFrame>(246(uint8_t) current_frame + 1)) {247for (auto desired_frame = Location::AltFrame::ABSOLUTE;248desired_frame <= Location::AltFrame::ABOVE_TERRAIN;249desired_frame = static_cast<Location::AltFrame>(250(uint8_t) desired_frame + 1)) {251test_location3.set_alt_cm(420, current_frame);252if (current_frame == desired_frame) {253EXPECT_TRUE(test_location3.change_alt_frame(desired_frame));254continue;255}256if (current_frame == Location::AltFrame::ABOVE_ORIGIN257|| desired_frame == Location::AltFrame::ABOVE_ORIGIN) {258EXPECT_FALSE(test_location3.change_alt_frame(desired_frame));259} else {260EXPECT_TRUE(test_location3.change_alt_frame(desired_frame));261}262}263}264265Vector2f test_vec2;266EXPECT_FALSE(test_home.get_vector_xy_from_origin_NE(test_vec2));267Vector3f test_vec3;268EXPECT_FALSE(test_home.get_vector_from_origin_NEU(test_vec3));269270Location test_origin = test_home;271test_origin.offset(2, 2);272const Vector3f test_vecto{200, 200, 10};273const Location test_location4{test_vecto, Location::AltFrame::ABOVE_ORIGIN};274EXPECT_EQ(10, test_location4.alt);275EXPECT_EQ(0, test_location4.relative_alt);276EXPECT_EQ(0, test_location4.terrain_alt);277EXPECT_EQ(1, test_location4.origin_alt);278EXPECT_EQ(0, test_location4.loiter_ccw);279EXPECT_EQ(0, test_location4.loiter_xtrack);280EXPECT_TRUE(test_location4.initialised());281282// test set_alt_m API:283Location loc = test_home;284loc.set_alt_m(1.71, Location::AltFrame::ABSOLUTE);285int32_t alt_in_cm_from_m;286EXPECT_TRUE(loc.get_alt_cm(Location::AltFrame::ABSOLUTE, alt_in_cm_from_m));287EXPECT_EQ(171, alt_in_cm_from_m);288289// can't create a Location using a vector here as there's no origin for the vector to be relative to:290// const Location test_location_empty{test_vect, Location::AltFrame::ABOVE_HOME};291// EXPECT_FALSE(test_location_empty.get_vector_from_origin_NEU(test_vec3));292}293294TEST(Location, Distance)295{296const Location test_home{-35362938, 149165085, 100, Location::AltFrame::ABSOLUTE};297const Location test_home2{-35363938, 149165085, 100, Location::AltFrame::ABSOLUTE};298EXPECT_FLOAT_EQ(11.131885, test_home.get_distance(test_home2));299EXPECT_FLOAT_EQ(0, test_home.get_distance(test_home));300EXPECT_VECTOR2F_EQ(Vector2f(0, 0), test_home.get_distance_NE(test_home));301EXPECT_VECTOR2F_EQ(Vector2f(-11.131885, 0), test_home.get_distance_NE(test_home2));302EXPECT_VECTOR2F_EQ(Vector3f(0, 0, 0), test_home.get_distance_NED(test_home));303EXPECT_VECTOR2F_EQ(Vector3f(-11.131885, 0, 0), test_home.get_distance_NED(test_home2));304Location test_loc = test_home;305test_loc.offset(-11.131886, 0);306EXPECT_TRUE(test_loc.same_latlon_as(test_home2));307test_loc = test_home;308test_loc.offset(-11.131885, 0);309test_loc.offset_bearing(0, 11.131885);310EXPECT_TRUE(test_loc.same_latlon_as(test_home));311312test_loc.offset_bearing_and_pitch(0, 2, -11.14);313EXPECT_TRUE(test_loc.same_latlon_as(test_home2));314EXPECT_EQ(62, test_loc.alt);315316test_loc = Location(-35362633, 149165085, 0, Location::AltFrame::ABOVE_HOME);317int32_t bearing = test_home.get_bearing_to(test_loc);318EXPECT_EQ(0, bearing);319320test_loc = Location(-35363711, 149165085, 0, Location::AltFrame::ABOVE_HOME);321bearing = test_home.get_bearing_to(test_loc);322EXPECT_EQ(18000, bearing);323324test_loc = Location(-35362938, 149166085, 0, Location::AltFrame::ABOVE_HOME);325bearing = test_home.get_bearing_to(test_loc);326EXPECT_EQ(9000, bearing);327328test_loc = Location(-35362938, 149164085, 0, Location::AltFrame::ABOVE_HOME);329bearing = test_home.get_bearing_to(test_loc);330EXPECT_EQ(27000, bearing);331332test_loc = Location(-35361938, 149164085, 0, Location::AltFrame::ABOVE_HOME);333bearing = test_home.get_bearing_to(test_loc);334EXPECT_EQ(31503, bearing);335const float bearing_rad = test_home.get_bearing(test_loc);336EXPECT_FLOAT_EQ(5.4982867, bearing_rad);337338}339340TEST(Location, Sanitize)341{342// we will sanitize test_loc with test_default_loc343// test_home is just for reference344const Location test_home{-35362938, 149165085, 100, Location::AltFrame::ABSOLUTE};345EXPECT_TRUE(vehicle.ahrs.set_home(test_home));346const Location test_default_loc{-35362938, 149165085, 200, Location::AltFrame::ABSOLUTE};347Location test_loc;348test_loc.set_alt_cm(0, Location::AltFrame::ABOVE_HOME);349EXPECT_TRUE(test_loc.sanitize(test_default_loc));350EXPECT_TRUE(test_loc.same_latlon_as(test_default_loc));351int32_t default_loc_alt;352// we should compare test_loc alt and test_default_loc alt in same frame , in this case, ABOVE HOME353EXPECT_TRUE(test_default_loc.get_alt_cm(Location::AltFrame::ABOVE_HOME, default_loc_alt));354EXPECT_EQ(test_loc.alt, default_loc_alt);355test_loc = Location(91*1e7, 0, 0, Location::AltFrame::ABSOLUTE);356EXPECT_TRUE(test_loc.sanitize(test_default_loc));357EXPECT_TRUE(test_loc.same_latlon_as(test_default_loc));358EXPECT_NE(test_default_loc.alt, test_loc.alt);359test_loc = Location(0, 181*1e7, 0, Location::AltFrame::ABSOLUTE);360EXPECT_TRUE(test_loc.sanitize(test_default_loc));361EXPECT_TRUE(test_loc.same_latlon_as(test_default_loc));362EXPECT_NE(test_default_loc.alt, test_loc.alt);363test_loc = Location(42*1e7, 42*1e7, 420, Location::AltFrame::ABSOLUTE);364EXPECT_FALSE(test_loc.sanitize(test_default_loc));365EXPECT_FALSE(test_loc.same_latlon_as(test_default_loc));366EXPECT_NE(test_default_loc.alt, test_loc.alt);367}368369TEST(Location, Line)370{371const Location test_home{35362938, 149165085, 100, Location::AltFrame::ABSOLUTE};372const Location test_wp_last{35362960, 149165085, 100, Location::AltFrame::ABSOLUTE};373Location test_wp{35362940, 149165085, 100, Location::AltFrame::ABSOLUTE};374EXPECT_FALSE(test_wp.past_interval_finish_line(test_home, test_wp_last));375EXPECT_TRUE(test_wp.past_interval_finish_line(test_home, test_home));376test_wp.lat = 35362970;377EXPECT_TRUE(test_wp.past_interval_finish_line(test_home, test_wp_last));378}379380/*381check if we obey basic euclidean geometry rules of position382addition/subtraction383*/384TEST(Location, OffsetError)385{386// test at 10km from origin387const float ofs_ne = 10e3 / sqrtf(2.0);388for (float lat = -80; lat <= 80; lat += 10.0) {389Location origin{int32_t(lat*1e7), 0, 0, Location::AltFrame::ABOVE_HOME};390Location loc = origin;391loc.offset(ofs_ne, ofs_ne);392Location loc2 = loc;393loc2.offset(-ofs_ne, -ofs_ne);394float dist = origin.get_distance(loc2);395EXPECT_FLOAT_EQ(dist, 0);396}397}398399AP_GTEST_MAIN()400401402