/
fly_qgc_mission.cpp
214 lines (180 loc) · 7.6 KB
/
fly_qgc_mission.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/**
* @file fly_qgc_mission.cpp
*
* @brief Demonstrates how to import mission items from QGroundControl plan,
* and fly them using the MAVSDK.
*
* Steps to run this example:
* 1. (a) Create a Mission in QGroundControl and save them to a file (.plan) (OR)
* (b) Use a pre-created sample mission plan in "plugins/mission/qgroundcontrol_sample.plan".
* Click
* [here](https://user-images.githubusercontent.com/26615772/31763673-972c5bb6-b4dc-11e7-8ff0-f8b39b6b88c3.png)
* to see what sample mission plan in QGroundControl looks like.
* 2. Run the example by passing path of the QGC mission plan as argument (By default, sample
* mission plan is imported).
*
* Example description:
* 1. Imports QGC mission items from .plan file.
* 2. Uploads mission items to vehicle.
* 3. Starts mission from first mission item.
* 4. Commands RTL once QGC Mission is accomplished.
*
* @author Shakthi Prashanth M <shakthi.prashanth.m@intel.com>,
* Julian Oes <julian@oes.ch>
* @date 2018-02-04
*/
#include <mavsdk/mavsdk.h>
#include <mavsdk/plugins/action/action.h>
#include <mavsdk/plugins/mission/mission.h>
#include <mavsdk/plugins/telemetry/telemetry.h>
#include <functional>
#include <future>
#include <iostream>
#include <memory>
#define ERROR_CONSOLE_TEXT "\033[31m" // Turn text on console red
#define TELEMETRY_CONSOLE_TEXT "\033[34m" // Turn text on console blue
#define NORMAL_CONSOLE_TEXT "\033[0m" // Restore normal console colour
using namespace mavsdk;
using namespace std::chrono; // for seconds(), milliseconds()
using namespace std::this_thread; // for sleep_for()
// Handles Action's result
inline void handle_action_err_exit(Action::Result result, const std::string& message);
// Handles Mission's result
inline void handle_mission_err_exit(Mission::Result result, const std::string& message);
// Handles Connection result
inline void handle_connection_err_exit(ConnectionResult result, const std::string& message);
void usage(std::string bin_name)
{
std::cout << NORMAL_CONSOLE_TEXT << "Usage : " << bin_name
<< " <connection_url> [path of QGC Mission plan]" << std::endl
<< "Connection URL format should be :" << std::endl
<< " For TCP : tcp://[server_host][:server_port]" << std::endl
<< " For UDP : udp://[bind_host][:bind_port]" << std::endl
<< " For Serial : serial:///path/to/serial/dev[:baudrate]" << std::endl
<< "For example, to connect to the simulator use URL: udp://:14540" << std::endl;
}
int main(int argc, char** argv)
{
Mavsdk mavsdk;
std::string connection_url;
ConnectionResult connection_result;
// Locate path of QGC Sample plan
std::string qgc_plan = "../../../plugins/mission/qgroundcontrol_sample.plan";
if (argc != 2 && argc != 3) {
usage(argv[0]);
return 1;
}
connection_url = argv[1];
if (argc == 3) {
qgc_plan = argv[2];
}
std::cout << "Connection URL: " << connection_url << std::endl;
std::cout << "Importing mission from mission plan: " << qgc_plan << std::endl;
{
auto prom = std::make_shared<std::promise<void>>();
auto future_result = prom->get_future();
std::cout << "Waiting to discover system..." << std::endl;
mavsdk.subscribe_on_new_system([&mavsdk, prom]() {
const auto system = mavsdk.systems().at(0);
if (system->is_connected()) {
std::cout << "Discovered system" << std::endl;
prom->set_value();
} else {
std::cout << "System timed out" << std::endl;
std::cout << "Exiting." << std::endl;
exit(0);
}
});
connection_result = mavsdk.add_any_connection(connection_url);
handle_connection_err_exit(connection_result, "Connection failed: ");
future_result.get();
}
auto system = mavsdk.systems().at(0);
auto action = Action{system};
auto mission = Mission{system};
auto telemetry = Telemetry{system};
while (!telemetry.health_all_ok()) {
std::cout << "Waiting for system to be ready" << std::endl;
sleep_for(seconds(1));
}
std::cout << "System ready" << std::endl;
// Import Mission items from QGC plan
std::pair<Mission::Result, Mission::MissionPlan> import_res =
mission.import_qgroundcontrol_mission(qgc_plan);
handle_mission_err_exit(import_res.first, "Failed to import mission items: ");
if (import_res.second.mission_items.size() == 0) {
std::cerr << "No missions! Exiting..." << std::endl;
exit(EXIT_FAILURE);
}
std::cout << "Found " << import_res.second.mission_items.size()
<< " mission items in the given QGC plan." << std::endl;
{
std::cout << "Uploading mission..." << std::endl;
// Wrap the asynchronous upload_mission function using std::future.
auto prom = std::make_shared<std::promise<Mission::Result>>();
auto future_result = prom->get_future();
mission.upload_mission_async(
import_res.second, [prom](Mission::Result result) { prom->set_value(result); });
const Mission::Result result = future_result.get();
handle_mission_err_exit(result, "Mission upload failed: ");
std::cout << "Mission uploaded." << std::endl;
}
std::cout << "Arming..." << std::endl;
const Action::Result arm_result = action.arm();
handle_action_err_exit(arm_result, "Arm failed: ");
std::cout << "Armed." << std::endl;
// Before starting the mission subscribe to the mission progress.
mission.subscribe_mission_progress([](Mission::MissionProgress mission_progress) {
std::cout << "Mission status update: " << mission_progress.current << " / "
<< mission_progress.total << std::endl;
});
{
std::cout << "Starting mission." << std::endl;
auto prom = std::make_shared<std::promise<Mission::Result>>();
auto future_result = prom->get_future();
mission.start_mission_async([prom](Mission::Result result) {
prom->set_value(result);
std::cout << "Started mission." << std::endl;
});
const Mission::Result result = future_result.get();
handle_mission_err_exit(result, "Mission start failed: ");
}
while (!mission.is_mission_finished().second) {
sleep_for(seconds(1));
}
// Wait for some time.
sleep_for(seconds(5));
{
// Mission complete. Command RTL to go home.
std::cout << "Commanding RTL..." << std::endl;
const Action::Result result = action.return_to_launch();
if (result != Action::Result::Success) {
std::cout << "Failed to command RTL (" << result << ")" << std::endl;
} else {
std::cout << "Commanded RTL." << std::endl;
}
}
return 0;
}
inline void handle_action_err_exit(Action::Result result, const std::string& message)
{
if (result != Action::Result::Success) {
std::cerr << ERROR_CONSOLE_TEXT << message << result << NORMAL_CONSOLE_TEXT << std::endl;
exit(EXIT_FAILURE);
}
}
inline void handle_mission_err_exit(Mission::Result result, const std::string& message)
{
if (result != Mission::Result::Success) {
std::cerr << ERROR_CONSOLE_TEXT << message << result << NORMAL_CONSOLE_TEXT << std::endl;
exit(EXIT_FAILURE);
}
}
// Handles connection result
inline void handle_connection_err_exit(ConnectionResult result, const std::string& message)
{
if (result != ConnectionResult::Success) {
std::cerr << ERROR_CONSOLE_TEXT << message << result << NORMAL_CONSOLE_TEXT << std::endl;
exit(EXIT_FAILURE);
}
}