|
| 1 | +// |
| 2 | +// Example demonstrating how to set GPS global origin after flying to a new location. |
| 3 | +// This takes off, flies 50m north using offboard velocity control, lands, |
| 4 | +// and then sets the GPS global origin at the new location. |
| 5 | +// |
| 6 | + |
| 7 | +#include <chrono> |
| 8 | +#include <cmath> |
| 9 | +#include <future> |
| 10 | +#include <iostream> |
| 11 | +#include <thread> |
| 12 | + |
| 13 | +#include <mavsdk/mavsdk.h> |
| 14 | +#include <mavsdk/plugins/action/action.h> |
| 15 | +#include <mavsdk/plugins/offboard/offboard.h> |
| 16 | +#include <mavsdk/plugins/telemetry/telemetry.h> |
| 17 | + |
| 18 | +using namespace mavsdk; |
| 19 | +using std::chrono::seconds; |
| 20 | +using std::this_thread::sleep_for; |
| 21 | + |
| 22 | +void usage(const std::string& bin_name) |
| 23 | +{ |
| 24 | + std::cerr << "Usage : " << bin_name << " <connection_url>\n" |
| 25 | + << "Connection URL format should be :\n" |
| 26 | + << " For TCP : tcp://[server_host][:server_port]\n" |
| 27 | + << " For UDP : udp://[bind_host][:bind_port]\n" |
| 28 | + << " For Serial : serial:///path/to/serial/dev[:baudrate]\n" |
| 29 | + << "For example, to connect to the simulator use URL: udpin://0.0.0.0:14540\n"; |
| 30 | +} |
| 31 | + |
| 32 | +int main(int argc, char** argv) |
| 33 | +{ |
| 34 | + if (argc != 2) { |
| 35 | + usage(argv[0]); |
| 36 | + return 1; |
| 37 | + } |
| 38 | + |
| 39 | + Mavsdk mavsdk{Mavsdk::Configuration{ComponentType::GroundStation}}; |
| 40 | + ConnectionResult connection_result = mavsdk.add_any_connection(argv[1]); |
| 41 | + |
| 42 | + if (connection_result != ConnectionResult::Success) { |
| 43 | + std::cerr << "Connection failed: " << connection_result << '\n'; |
| 44 | + return 1; |
| 45 | + } |
| 46 | + |
| 47 | + auto system = mavsdk.first_autopilot(3.0); |
| 48 | + if (!system) { |
| 49 | + std::cerr << "Timed out waiting for system\n"; |
| 50 | + return 1; |
| 51 | + } |
| 52 | + |
| 53 | + // Instantiate plugins |
| 54 | + auto action = Action{system.value()}; |
| 55 | + auto offboard = Offboard{system.value()}; |
| 56 | + auto telemetry = Telemetry{system.value()}; |
| 57 | + |
| 58 | + // Wait for system to be ready |
| 59 | + while (!telemetry.health_all_ok()) { |
| 60 | + std::cout << "Waiting for system to be ready\n"; |
| 61 | + sleep_for(seconds(1)); |
| 62 | + } |
| 63 | + std::cout << "System is ready\n"; |
| 64 | + |
| 65 | + // Get initial GPS origin |
| 66 | + auto origin_result = telemetry.get_gps_global_origin(); |
| 67 | + if (origin_result.first == Telemetry::Result::Success) { |
| 68 | + std::cout << "Initial GPS origin: " << origin_result.second << '\n'; |
| 69 | + } |
| 70 | + |
| 71 | + // Get initial position |
| 72 | + auto initial_position = telemetry.position(); |
| 73 | + std::cout << "Initial position: lat=" << initial_position.latitude_deg |
| 74 | + << ", lon=" << initial_position.longitude_deg |
| 75 | + << ", alt=" << initial_position.absolute_altitude_m << "m AMSL\n"; |
| 76 | + |
| 77 | + // Arm |
| 78 | + std::cout << "Arming...\n"; |
| 79 | + const auto arm_result = action.arm(); |
| 80 | + if (arm_result != Action::Result::Success) { |
| 81 | + std::cerr << "Arming failed: " << arm_result << '\n'; |
| 82 | + return 1; |
| 83 | + } |
| 84 | + std::cout << "Armed\n"; |
| 85 | + |
| 86 | + // Take off |
| 87 | + std::cout << "Taking off...\n"; |
| 88 | + const auto takeoff_result = action.takeoff(); |
| 89 | + if (takeoff_result != Action::Result::Success) { |
| 90 | + std::cerr << "Takeoff failed: " << takeoff_result << '\n'; |
| 91 | + return 1; |
| 92 | + } |
| 93 | + |
| 94 | + // Wait until in air |
| 95 | + auto in_air_promise = std::promise<void>{}; |
| 96 | + auto in_air_future = in_air_promise.get_future(); |
| 97 | + Telemetry::LandedStateHandle landed_handle = telemetry.subscribe_landed_state( |
| 98 | + [&telemetry, &in_air_promise, &landed_handle](Telemetry::LandedState state) { |
| 99 | + if (state == Telemetry::LandedState::InAir) { |
| 100 | + std::cout << "Takeoff finished\n"; |
| 101 | + telemetry.unsubscribe_landed_state(landed_handle); |
| 102 | + in_air_promise.set_value(); |
| 103 | + } |
| 104 | + }); |
| 105 | + |
| 106 | + if (in_air_future.wait_for(seconds(10)) == std::future_status::timeout) { |
| 107 | + std::cerr << "Takeoff timed out\n"; |
| 108 | + telemetry.unsubscribe_landed_state(landed_handle); |
| 109 | + return 1; |
| 110 | + } |
| 111 | + |
| 112 | + // Let it stabilize at takeoff altitude |
| 113 | + sleep_for(seconds(2)); |
| 114 | + |
| 115 | + // Start offboard mode and fly 50m north |
| 116 | + std::cout << "Starting offboard mode to fly 50m north...\n"; |
| 117 | + |
| 118 | + // Send setpoint once before starting offboard |
| 119 | + Offboard::VelocityNedYaw stay{}; |
| 120 | + offboard.set_velocity_ned(stay); |
| 121 | + |
| 122 | + Offboard::Result offboard_result = offboard.start(); |
| 123 | + if (offboard_result != Offboard::Result::Success) { |
| 124 | + std::cerr << "Offboard start failed: " << offboard_result << '\n'; |
| 125 | + return 1; |
| 126 | + } |
| 127 | + |
| 128 | + // Fly north at 5 m/s for 10 seconds = 50m |
| 129 | + std::cout << "Flying north at 5 m/s for 10 seconds...\n"; |
| 130 | + Offboard::VelocityNedYaw fly_north{}; |
| 131 | + fly_north.north_m_s = 5.0f; |
| 132 | + fly_north.yaw_deg = 0.0f; |
| 133 | + offboard.set_velocity_ned(fly_north); |
| 134 | + sleep_for(seconds(10)); |
| 135 | + |
| 136 | + // Stop and hover |
| 137 | + std::cout << "Stopping...\n"; |
| 138 | + offboard.set_velocity_ned(stay); |
| 139 | + sleep_for(seconds(2)); |
| 140 | + |
| 141 | + // Stop offboard mode |
| 142 | + offboard_result = offboard.stop(); |
| 143 | + if (offboard_result != Offboard::Result::Success) { |
| 144 | + std::cerr << "Offboard stop failed: " << offboard_result << '\n'; |
| 145 | + return 1; |
| 146 | + } |
| 147 | + |
| 148 | + // Get position before landing |
| 149 | + auto position_before_landing = telemetry.position(); |
| 150 | + std::cout << "Position before landing: lat=" << position_before_landing.latitude_deg |
| 151 | + << ", lon=" << position_before_landing.longitude_deg |
| 152 | + << ", alt=" << position_before_landing.absolute_altitude_m << "m AMSL\n"; |
| 153 | + |
| 154 | + // Land |
| 155 | + std::cout << "Landing...\n"; |
| 156 | + const auto land_result = action.land(); |
| 157 | + if (land_result != Action::Result::Success) { |
| 158 | + std::cerr << "Landing failed: " << land_result << '\n'; |
| 159 | + return 1; |
| 160 | + } |
| 161 | + |
| 162 | + // Wait until landed |
| 163 | + while (telemetry.in_air()) { |
| 164 | + std::cout << "Waiting for landing...\n"; |
| 165 | + sleep_for(seconds(1)); |
| 166 | + } |
| 167 | + std::cout << "Landed!\n"; |
| 168 | + |
| 169 | + // Wait a bit for things to settle |
| 170 | + sleep_for(seconds(2)); |
| 171 | + |
| 172 | + // Get final position |
| 173 | + auto final_position = telemetry.position(); |
| 174 | + std::cout << "Final position: lat=" << final_position.latitude_deg |
| 175 | + << ", lon=" << final_position.longitude_deg |
| 176 | + << ", alt=" << final_position.absolute_altitude_m << "m AMSL\n"; |
| 177 | + |
| 178 | + // Set the GPS global origin at the current position |
| 179 | + std::cout << "Setting GPS global origin at current position...\n"; |
| 180 | + const auto set_origin_result = action.set_gps_global_origin( |
| 181 | + final_position.latitude_deg, |
| 182 | + final_position.longitude_deg, |
| 183 | + final_position.absolute_altitude_m); |
| 184 | + |
| 185 | + if (set_origin_result != Action::Result::Success) { |
| 186 | + std::cerr << "Setting GPS global origin failed: " << set_origin_result << '\n'; |
| 187 | + return 1; |
| 188 | + } |
| 189 | + std::cout << "GPS global origin set successfully!\n"; |
| 190 | + |
| 191 | + // Verify by getting the new origin |
| 192 | + auto new_origin_result = telemetry.get_gps_global_origin(); |
| 193 | + if (new_origin_result.first == Telemetry::Result::Success) { |
| 194 | + std::cout << "New GPS origin: " << new_origin_result.second << '\n'; |
| 195 | + } else { |
| 196 | + std::cerr << "Failed to get new GPS origin: " << new_origin_result.first << '\n'; |
| 197 | + } |
| 198 | + |
| 199 | + // Wait a bit before exiting |
| 200 | + sleep_for(seconds(3)); |
| 201 | + std::cout << "Finished!\n"; |
| 202 | + |
| 203 | + return 0; |
| 204 | +} |
0 commit comments