Visual Servoing Platform  version 3.6.1 under development (2024-11-15)
vpRobotMavsdk.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See https://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Interface to mavlink compatible controller using mavsdk 3rd party
33  *
34  *****************************************************************************/
35 
36 #include <visp3/core/vpConfig.h>
37 
38 // Check if std:c++17 or higher
39 #if defined(VISP_HAVE_MAVSDK) && ((__cplusplus >= 201703L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L))) \
40  && defined(VISP_HAVE_THREADS)
41 
42 #include <iostream>
43 #include <math.h>
44 #include <thread>
45 
46 #include <mavsdk/mavsdk.h>
47 #include <mavsdk/plugins/action/action.h>
48 #include <mavsdk/plugins/calibration/calibration.h>
49 #include <mavsdk/plugins/mavlink_passthrough/mavlink_passthrough.h>
50 #include <mavsdk/plugins/mocap/mocap.h>
51 #include <mavsdk/plugins/offboard/offboard.h>
52 #include <mavsdk/plugins/telemetry/telemetry.h>
53 
54 #include <visp3/core/vpExponentialMap.h> // For velocity computation
55 #include <visp3/robot/vpRobotMavsdk.h>
56 
57 using std::chrono::milliseconds;
58 using std::chrono::seconds;
59 using std::this_thread::sleep_for;
60 using namespace std::chrono_literals;
61 
62 BEGIN_VISP_NAMESPACE
63 #ifndef DOXYGEN_SHOULD_SKIP_THIS
64 class vpRobotMavsdk::vpRobotMavsdkImpl
65 {
66 public:
67  vpRobotMavsdkImpl() : m_takeoffAlt(1.0) { }
68  vpRobotMavsdkImpl(const std::string &connection_info) : m_takeoffAlt(1.0) { connect(connection_info); }
69 
70  virtual ~vpRobotMavsdkImpl()
71  {
72  if (m_has_flying_capability && m_auto_land) {
73  land();
74  }
75  }
76 
77 private:
83  std::shared_ptr<mavsdk::System> getSystem(mavsdk::Mavsdk &mavsdk)
84  {
85  std::cout << "Waiting to discover system..." << std::endl;
86  auto prom = std::promise<std::shared_ptr<mavsdk::System> > {};
87  auto fut = prom.get_future();
88 
89  // We wait for new systems to be discovered, once we find one that has an
90  // autopilot, we decide to use it.
91 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
92  mavsdk::Mavsdk::NewSystemHandle handle = mavsdk.subscribe_on_new_system([&mavsdk, &prom, &handle]() {
93 #else
94  mavsdk.subscribe_on_new_system([&mavsdk, &prom]() {
95 #endif
96  auto system = mavsdk.systems().back();
97 
98  if (system->has_autopilot()) {
99  std::cout << "Discovered autopilot" << std::endl;
100 
101  // Unsubscribe again as we only want to find one system.
102 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
103  mavsdk.unsubscribe_on_new_system(handle);
104 #else
105  mavsdk.subscribe_on_new_system(nullptr);
106 #endif
107  prom.set_value(system);
108  }
109  });
110 
111  // We usually receive heartbeats at 1Hz, therefore we should find a
112  // system after around 3 seconds max, surely.
113  if (fut.wait_for(seconds(3)) == std::future_status::timeout) {
114  std::cerr << "No autopilot found." << std::endl;
115  return {};
116  }
117 
118  // Get discovered system now.
119  return fut.get();
120  }
121 
122  MAV_TYPE getVehicleType()
123  {
124  auto passthrough = mavsdk::MavlinkPassthrough { m_system };
125 
126  auto prom = std::promise<MAV_TYPE> {};
127  auto fut = prom.get_future();
128 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
129  mavsdk::MavlinkPassthrough::MessageHandle handle = passthrough.subscribe_message(
130  MAVLINK_MSG_ID_HEARTBEAT, [&passthrough, &prom, &handle](const mavlink_message_t &message) {
131 #else
132  passthrough.subscribe_message_async(MAVLINK_MSG_ID_HEARTBEAT,
133  [&passthrough, &prom](const mavlink_message_t &message) {
134 #endif
135  // Process only Heartbeat coming from the autopilot
136  if (message.compid != MAV_COMP_ID_AUTOPILOT1) {
137  return;
138  }
139 
140  mavlink_heartbeat_t heartbeat;
141  mavlink_msg_heartbeat_decode(&message, &heartbeat);
142 
143  // Unsubscribe again as we only want to find one system.
144 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
145  passthrough.unsubscribe_message(handle);
146 #else
147  passthrough.subscribe_message_async(MAVLINK_MSG_ID_HEARTBEAT, nullptr);
148 #endif
149 
150  prom.set_value(static_cast<MAV_TYPE>(heartbeat.type));
151  });
152 
153  // We usually receive heartbeats at 1Hz, therefore we should find a
154  // system after around 3 seconds max, surely.
155  if (fut.wait_for(seconds(3)) == std::future_status::timeout) {
156  std::cerr << "No heartbeat received to get vehicle type." << std::endl;
157  return {};
158  }
159 
160  // Get discovered system now.
161  return fut.get();
162  }
163 
164  void calibrate_accelerometer(mavsdk::Calibration &calibration)
165  {
166  std::cout << "Calibrating accelerometer..." << std::endl;
167 
168  std::promise<void> calibration_promise;
169  auto calibration_future = calibration_promise.get_future();
170 
171  calibration.calibrate_accelerometer_async(create_calibration_callback(calibration_promise));
172 
173  calibration_future.wait();
174  }
175 
176  std::function<void(mavsdk::Calibration::Result, mavsdk::Calibration::ProgressData)>
177  create_calibration_callback(std::promise<void> &calibration_promise)
178  {
179  return [&calibration_promise](const mavsdk::Calibration::Result result,
180  const mavsdk::Calibration::ProgressData progress_data) {
181  switch (result) {
182  case mavsdk::Calibration::Result::Success:
183  std::cout << "--- Calibration succeeded!" << std::endl;
184  calibration_promise.set_value();
185  break;
186  case mavsdk::Calibration::Result::Next:
187  if (progress_data.has_progress) {
188  std::cout << " Progress: " << progress_data.progress << std::endl;
189  }
190  if (progress_data.has_status_text) {
191  std::cout << " Instruction: " << progress_data.status_text << std::endl;
192  }
193  break;
194  default:
195  std::cout << "--- Calibration failed with message: " << result << std::endl;
196  calibration_promise.set_value();
197  break;
198  }
199  };
200  }
201 
202  void calibrate_gyro(mavsdk::Calibration &calibration)
203  {
204  std::cout << "Calibrating gyro..." << std::endl;
205 
206  std::promise<void> calibration_promise;
207  auto calibration_future = calibration_promise.get_future();
208 
209  calibration.calibrate_gyro_async(create_calibration_callback(calibration_promise));
210 
211  calibration_future.wait();
212  }
213 
214 public:
215  void connect(const std::string &connectionInfo)
216  {
217  m_address = connectionInfo;
218  mavsdk::ConnectionResult connection_result = m_mavsdk.add_any_connection(connectionInfo);
219 
220  if (connection_result != mavsdk::ConnectionResult::Success) {
221  std::cerr << "Connection failed: " << connection_result << std::endl;
222  return;
223  }
224 
225  m_system = getSystem(m_mavsdk);
226 
227  if (!m_system) {
228  throw vpException(vpException::fatalError, "Unable to connect to: %s", connectionInfo.c_str());
229  }
230 
231  m_mav_type = getVehicleType();
232 
233  m_has_flying_capability = hasFlyingCapability(m_mav_type);
234 
235  std::cout << (m_has_flying_capability ? "Connected to a flying vehicle" : "Connected to a non flying vehicle")
236  << std::endl;
237 
238  m_action = std::make_shared<mavsdk::Action>(m_system);
239  m_telemetry = std::make_shared<mavsdk::Telemetry>(m_system);
240  m_offboard = std::make_shared<mavsdk::Offboard>(m_system);
241  }
242 
243  bool hasFlyingCapability(MAV_TYPE mav_type)
244  {
245  switch (mav_type) {
246  case MAV_TYPE::MAV_TYPE_GROUND_ROVER:
247  case MAV_TYPE::MAV_TYPE_SURFACE_BOAT:
248  case MAV_TYPE::MAV_TYPE_SUBMARINE:
249  return false;
250  default:
251  return true;
252  }
253  }
254 
255  bool isRunning() const
256  {
257  if (m_system == nullptr) {
258  return false;
259  }
260  else {
261  return true;
262  }
263  }
264 
265  std::string getAddress() const
266  {
267  std::string sequence;
268  std::stringstream ss(m_address);
269  std::string actual_address;
270  std::getline(ss, sequence, ':');
271  if (sequence == "serial" || sequence == "udp" || sequence == "tcp") {
272  getline(ss, sequence, ':');
273  for (const char &c : sequence) {
274  if (c != '/') {
275  actual_address.append(1, c);
276  }
277  }
278  return actual_address;
279  }
280  else {
281  std::cout << "ERROR : The address parameter must start with \"serial:\" or \"udp:\" or \"tcp:\"." << std::endl;
282  return std::string();
283  }
284  }
285 
286  float getBatteryLevel() const
287  {
288  mavsdk::Telemetry::Battery battery = m_telemetry.get()->battery();
289  return battery.voltage_v;
290  }
291 
292  void getPosition(vpHomogeneousMatrix &ned_M_frd) const
293  {
294  auto quat = m_telemetry.get()->attitude_quaternion();
295  auto posvel = m_telemetry.get()->position_velocity_ned();
296  vpQuaternionVector q { quat.x, quat.y, quat.z, quat.w };
297  vpTranslationVector t { posvel.position.north_m, posvel.position.east_m, posvel.position.down_m };
298  ned_M_frd.buildFrom(t, q);
299  }
300 
301  void getPosition(float &ned_north, float &ned_east, float &ned_down, float &ned_yaw) const
302  {
303  auto odom = m_telemetry.get()->odometry();
304  auto angles = m_telemetry.get()->attitude_euler();
305  ned_north = odom.position_body.x_m;
306  ned_east = odom.position_body.y_m;
307  ned_down = odom.position_body.z_m;
308  ned_yaw = vpMath::rad(angles.yaw_deg);
309  }
310 
311  std::tuple<float, float> getHome() const
312  {
313  auto position = m_telemetry.get()->home();
314  return { float(position.latitude_deg), float(position.longitude_deg) };
315  }
316 
317  bool sendMocapData(const vpHomogeneousMatrix &enu_M_flu, int display_fps)
318  {
319  static double time_prev = vpTime::measureTimeMs();
320 
321  // We suppose here that the body frame which pose is given by the MoCap is FLU (Front Left Up).
322  // Thus we need to transform this frame to FRD (Front Right Down).
323  vpHomogeneousMatrix flu_M_frd;
324  flu_M_frd.eye();
325  flu_M_frd[1][1] = -1;
326  flu_M_frd[2][2] = -1;
327 
328  vpHomogeneousMatrix enu_M_frd = enu_M_flu * flu_M_frd;
329  auto mocap = mavsdk::Mocap { m_system };
330  mavsdk::Mocap::VisionPositionEstimate pose_estimate;
331 
332  vpHomogeneousMatrix ned_M_frd = vpMath::enu2ned(enu_M_frd);
333  vpRxyzVector ned_rxyz_frd = vpRxyzVector(ned_M_frd.getRotationMatrix());
334  pose_estimate.angle_body.roll_rad = ned_rxyz_frd[0];
335  pose_estimate.angle_body.pitch_rad = ned_rxyz_frd[1];
336  pose_estimate.angle_body.yaw_rad = ned_rxyz_frd[2];
337 
338  vpTranslationVector ned_t_frd = ned_M_frd.getTranslationVector();
339  pose_estimate.position_body.x_m = ned_t_frd[0];
340  pose_estimate.position_body.y_m = ned_t_frd[1];
341  pose_estimate.position_body.z_m = ned_t_frd[2];
342 
343  pose_estimate.pose_covariance.covariance_matrix.push_back(NAN);
344  pose_estimate.time_usec = 0; // We are using the back end timestamp
345 
346  const mavsdk::Mocap::Result set_position_result = mocap.set_vision_position_estimate(pose_estimate);
347  if (set_position_result != mavsdk::Mocap::Result::Success) {
348  std::cerr << "Set position failed: " << set_position_result << '\n';
349  return false;
350  }
351  else {
352  if (display_fps > 0) {
353  double display_time_ms = 1000. / display_fps;
354  if (vpTime::measureTimeMs() - time_prev > display_time_ms) {
355  time_prev = vpTime::measureTimeMs();
356  std::cout << "Send ned_M_frd MoCap data: " << std::endl;
357  std::cout << "Translation [m]: " << pose_estimate.position_body.x_m << " , "
358  << pose_estimate.position_body.y_m << " , " << pose_estimate.position_body.z_m << std::endl;
359  std::cout << "Roll [rad]: " << pose_estimate.angle_body.roll_rad
360  << " , Pitch [rad]: " << pose_estimate.angle_body.pitch_rad
361  << " , Yaw [rad]: " << pose_estimate.angle_body.yaw_rad << " ." << std::endl;
362  }
363  }
364  return true;
365  }
366  }
367 
368  void setTakeOffAlt(double altitude)
369  {
370  if (altitude > 0) {
371  m_takeoffAlt = altitude;
372  }
373  else {
374  std::cerr << "ERROR : The take off altitude must be positive." << std::endl;
375  }
376  }
377 
378  void doFlatTrim()
379  {
380  // Instantiate plugin.
381  auto calibration = mavsdk::Calibration(m_system);
382 
383  // Run calibrations
384  calibrate_accelerometer(calibration);
385  calibrate_gyro(calibration);
386  }
387 
388  bool arm()
389  {
390  // Arm vehicle
391  std::cout << "Arming...\n";
392  const mavsdk::Action::Result arm_result = m_action.get()->arm();
393 
394  if (arm_result != mavsdk::Action::Result::Success) {
395  std::cerr << "Arming failed: " << arm_result << std::endl;
396  return false;
397  }
398  return true;
399  }
400 
401  bool disarm()
402  {
403  // Arm vehicle
404  std::cout << "Disarming...\n";
405  const mavsdk::Action::Result arm_result = m_action.get()->disarm();
406 
407  if (arm_result != mavsdk::Action::Result::Success) {
408  std::cerr << "Disarming failed: " << arm_result << std::endl;
409  return false;
410  }
411  return true;
412  }
413 
414  bool setGPSGlobalOrigin(double latitude, double longitude, double altitude)
415  {
416  auto passthrough = mavsdk::MavlinkPassthrough { m_system };
417  mavlink_set_gps_global_origin_t gps_global_origin;
418  gps_global_origin.latitude = latitude * 10000000;
419  gps_global_origin.longitude = longitude * 10000000;
420  gps_global_origin.altitude = altitude * 1000; // in mm
421  gps_global_origin.target_system = m_system->get_system_id();
422  mavlink_message_t msg;
423  mavlink_msg_set_gps_global_origin_encode(passthrough.get_our_sysid(), passthrough.get_our_compid(), &msg,
424  &gps_global_origin);
425  auto resp = passthrough.send_message(msg);
426  if (resp != mavsdk::MavlinkPassthrough::Result::Success) {
427  std::cerr << "Set GPS global position failed: " << resp << std::endl;
428  return false;
429  }
430  return true;
431  }
432 
433  bool takeControl()
434  {
435  if (m_verbose) {
436  std::cout << "Starting offboard mode..." << std::endl;
437  }
438 
439  if (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Offboard) {
440  const mavsdk::Offboard::VelocityBodyYawspeed stay {};
441  m_offboard.get()->set_velocity_body(stay);
442 
443  mavsdk::Offboard::Result offboard_result = m_offboard.get()->start();
444  if (offboard_result != mavsdk::Offboard::Result::Success) {
445  std::cerr << "Offboard mode failed: " << offboard_result << std::endl;
446  return false;
447  }
448  }
449  else if (m_verbose) {
450  std::cout << "Already in offboard mode" << std::endl;
451  }
452 
453  // Wait to ensure offboard mode active in telemetry
454  double t = vpTime::measureTimeMs();
455  while (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Offboard) {
456  if (vpTime::measureTimeMs() - t > 3. * 1000.) {
457  std::cout << "Time out received in takeControl()" << std::endl;
458  break;
459  }
460  };
461 
462  if (m_verbose) {
463  std::cout << "Offboard mode started" << std::endl;
464  }
465  return true;
466  }
467 
468  void setPositioningIncertitude(float position_incertitude, float yaw_incertitude)
469  {
470  m_position_incertitude = position_incertitude;
471  m_yaw_incertitude = yaw_incertitude;
472  }
473 
474  bool takeOff(bool interactive, int timeout_sec, bool use_gps)
475  {
476  if (!m_has_flying_capability) {
477  std::cerr << "Warning: Cannot takeoff this non flying vehicle" << std::endl;
478  return true;
479  }
480 
481  bool authorize_takeoff = false;
482 
483  if (!interactive) {
484  authorize_takeoff = true;
485  }
486  else {
487  if (m_telemetry.get()->flight_mode() == mavsdk::Telemetry::FlightMode::Offboard) {
488  authorize_takeoff = true;
489  }
490  else {
491  std::string answer;
492  while (answer != "Y" && answer != "y" && answer != "N" && answer != "n") {
493  std::cout << "Current flight mode is not the offboard mode. Do you "
494  "want to force offboard mode ? (y/n)"
495  << std::endl;
496  std::cin >> answer;
497  if (answer == "Y" || answer == "y") {
498  authorize_takeoff = true;
499  }
500  }
501  }
502  }
503 
504  if (m_telemetry.get()->in_air()) {
505  std::cerr << "Cannot take off as the robot is already flying." << std::endl;
506  return true;
507  }
508  else if (authorize_takeoff) {
509  // Arm vehicle
510  if (!arm()) {
511  return false;
512  }
513 
514  vpTime::wait(2000);
515 
516  if (interactive) {
517  std::string answer;
518  while (answer != "Y" && answer != "y" && answer != "N" && answer != "n") {
519  std::cout << "If vehicle armed ? (y/n)" << std::endl;
520  std::cin >> answer;
521  if (answer == "N" || answer == "n") {
522  disarm();
523  kill();
524  return false;
525  }
526  }
527  }
528 
529  // Takeoff
530  if (m_telemetry.get()->gps_info().fix_type == mavsdk::Telemetry::FixType::NoGps || !use_gps) {
531  // No GPS connected.
532  // When using odometry from MoCap, Action::takeoff() behavior is to takeoff at 0,0,0,alt
533  // that is weird when the drone is not placed at 0,0,0.
534  // That's why here use set_position_ned() to takeoff
535 
536  // Start off-board or guided mode
537  takeControl();
538 
539  auto in_air_promise = std::promise<void> {};
540  auto in_air_future = in_air_promise.get_future();
541 
542  mavsdk::Telemetry::Odometry odom = m_telemetry.get()->odometry();
543  vpQuaternionVector q { odom.q.x, odom.q.y, odom.q.z, odom.q.w };
544  vpRotationMatrix R(q);
545  vpRxyzVector rxyz(R);
546 
547  double X_init = odom.position_body.x_m;
548  double Y_init = odom.position_body.y_m;
549  double Z_init = odom.position_body.z_m;
550  double yaw_init = vpMath::deg(rxyz[2]);
551 
552  std::cout << "Takeoff using position NED." << std::endl;
553 
554  mavsdk::Offboard::PositionNedYaw takeoff {};
555  takeoff.north_m = X_init;
556  takeoff.east_m = Y_init;
557  takeoff.down_m = Z_init - m_takeoffAlt;
558  takeoff.yaw_deg = yaw_init;
559  m_offboard.get()->set_position_ned(takeoff);
560  // Possibility is to use set_position_velocity_ned(); to speed up takeoff
561 
562 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
563  Telemetry::LandedStateHandle handle = m_telemetry.get()->subscribe_landed_state(
564  [this, &in_air_promise, &handle](mavsdk::Telemetry::LandedState state) {
565  if (state == mavsdk::Telemetry::LandedState::InAir) {
566  std::cout << "Drone is taking off\n.";
567  m_telemetry.get()->unsubscribe_landed_state(handle);
568  in_air_promise.set_value();
569  }
570  });
571 #else
572  m_telemetry.get()->subscribe_landed_state([this, &in_air_promise](mavsdk::Telemetry::LandedState state) {
573  if (state == mavsdk::Telemetry::LandedState::InAir) {
574  std::cout << "Drone is taking off\n.";
575  m_telemetry.get()->subscribe_landed_state(nullptr);
576  in_air_promise.set_value();
577  }
578  std::cout << "state: " << state << std::endl;
579  });
580 #endif
581  if (in_air_future.wait_for(seconds(timeout_sec)) == std::future_status::timeout) {
582  std::cerr << "Takeoff failed: drone not in air.\n";
583 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
584  m_telemetry.get()->unsubscribe_landed_state(handle);
585 #else
586  m_telemetry.get()->subscribe_landed_state(nullptr);
587 #endif
588  return false;
589  }
590  // Add check with Altitude
591  auto takeoff_finished_promise = std::promise<void> {};
592  auto takeoff_finished_future = takeoff_finished_promise.get_future();
593 
594 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
595  auto handle_odom = m_telemetry.get()->subscribe_odometry(
596  [this, &takeoff_finished_promise, &handle, &Z_init](mavsdk::Telemetry::Odometry odom) {
597  if (odom.position_body.z_m < 0.90 * (Z_init - m_takeoffAlt) + m_position_incertitude) {
598  std::cout << "Takeoff altitude reached\n.";
599  m_telemetry.get()->unsubscribe_odometry(handle_odom);
600  takeoff_finished_promise.set_value();
601  }
602  });
603 #else
604  m_telemetry.get()->subscribe_odometry(
605  [this, &takeoff_finished_promise, &Z_init](mavsdk::Telemetry::Odometry odom) {
606  if (odom.position_body.z_m < 0.90 * (Z_init - m_takeoffAlt) + m_position_incertitude) {
607  std::cout << "Takeoff altitude reached\n.";
608  m_telemetry.get()->subscribe_odometry(nullptr);
609  takeoff_finished_promise.set_value();
610  }
611  });
612 #endif
613  if (takeoff_finished_future.wait_for(seconds(timeout_sec)) == std::future_status::timeout) {
614  std::cerr << "Takeoff failed: altitude not reached.\n";
615 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
616  m_telemetry.get()->unsubscribe_odometry(handle);
617 #else
618  m_telemetry.get()->subscribe_odometry(nullptr);
619 #endif
620  return false;
621  }
622  }
623  else {
624  // GPS connected, we use Action::takeoff()
625  std::cout << "---- DEBUG: GPS detected: use action::takeoff()" << std::endl;
626 
627  mavsdk::Telemetry::Odometry odom = m_telemetry.get()->odometry();
628  double Z_init = odom.position_body.z_m;
629 
630  m_action.get()->set_takeoff_altitude(m_takeoffAlt);
631  const auto takeoff_result = m_action.get()->takeoff();
632  if (takeoff_result != mavsdk::Action::Result::Success) {
633  std::cerr << "Takeoff failed: " << takeoff_result << '\n';
634  return false;
635  }
636 
637  auto in_air_promise = std::promise<void> {};
638  auto in_air_future = in_air_promise.get_future();
639 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
640  Telemetry::LandedStateHandle handle = m_telemetry.get()->subscribe_landed_state(
641  [this, &in_air_promise, &handle](mavsdk::Telemetry::LandedState state) {
642  if (state == mavsdk::Telemetry::LandedState::InAir) {
643  std::cout << "Taking off has finished\n.";
644  m_telemetry.get()->unsubscribe_landed_state(handle);
645  in_air_promise.set_value();
646  }
647  });
648 #else
649  m_telemetry.get()->subscribe_landed_state([this, &in_air_promise](mavsdk::Telemetry::LandedState state) {
650  if (state == mavsdk::Telemetry::LandedState::InAir) {
651  std::cout << "Taking off has finished\n.";
652  m_telemetry.get()->subscribe_landed_state(nullptr);
653  in_air_promise.set_value();
654  }
655  std::cout << "state: " << state << std::endl;
656  });
657 #endif
658  if (in_air_future.wait_for(seconds(timeout_sec)) == std::future_status::timeout) {
659  // Add check with Altitude
660  std::cerr << "Takeoff timed out.\n";
661 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
662  m_telemetry.get()->unsubscribe_landed_state(handle);
663 #else
664  m_telemetry.get()->subscribe_landed_state(nullptr);
665 #endif
666  }
667  // Add check with Altitude
668  auto takeoff_finished_promise = std::promise<void> {};
669  auto takeoff_finished_future = takeoff_finished_promise.get_future();
670 
671 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
672  auto handle_odom = m_telemetry.get()->subscribe_odometry(
673  [this, &takeoff_finished_promise, &handle, &Z_init](mavsdk::Telemetry::Odometry odom) {
674  if (odom.position_body.z_m < 0.90 * (Z_init - m_takeoffAlt) + m_position_incertitude) {
675  std::cout << "Takeoff altitude reached\n.";
676  m_telemetry.get()->unsubscribe_odometry(handle_odom);
677  takeoff_finished_promise.set_value();
678  }
679  });
680 #else
681  m_telemetry.get()->subscribe_odometry(
682  [this, &takeoff_finished_promise, &Z_init](mavsdk::Telemetry::Odometry odom) {
683  if (odom.position_body.z_m < 0.90 * (Z_init - m_takeoffAlt) + m_position_incertitude) {
684  std::cout << "Takeoff altitude reached\n.";
685  m_telemetry.get()->subscribe_odometry(nullptr);
686  takeoff_finished_promise.set_value();
687  }
688  });
689 #endif
690  if (takeoff_finished_future.wait_for(seconds(timeout_sec)) == std::future_status::timeout) {
691  std::cerr << "Takeoff failed: altitude not reached.\n";
692 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
693  m_telemetry.get()->unsubscribe_odometry(handle);
694 #else
695  m_telemetry.get()->subscribe_odometry(nullptr);
696 #endif
697  return false;
698  }
699  // Start off-board or guided mode
700  takeControl();
701  }
702  }
703  return true;
704  }
705 
706  bool land(bool use_buildin = false)
707  {
708  if (!m_has_flying_capability) {
709  std::cerr << "Warning: Cannot land this non flying vehicle" << std::endl;
710  return true;
711  }
712  // Takeoff
713  if (!use_buildin) {
714  // No GPS connected.
715  // When using odometry from MoCap, Action::takeoff() behavior is to
716  // takeoff at 0,0,0,alt that is weird when the drone is not placed at
717  // 0,0,0. That's why here use set_position_ned() to takeoff
718 
719  // Start off-board or guided mode
720  takeControl();
721 
722  mavsdk::Telemetry::Odometry odom = m_telemetry.get()->odometry();
723  vpQuaternionVector q { odom.q.x, odom.q.y, odom.q.z, odom.q.w };
724  vpRotationMatrix R(q);
725  vpRxyzVector rxyz(R);
726 
727  double X_init = odom.position_body.x_m;
728  double Y_init = odom.position_body.y_m;
729  double yaw_init = vpMath::deg(rxyz[2]);
730 
731  std::cout << "Landing using position NED." << std::endl;
732 
733  mavsdk::Offboard::PositionNedYaw landing {};
734  landing.north_m = X_init;
735  landing.east_m = Y_init;
736  landing.down_m = 0.;
737  landing.yaw_deg = yaw_init;
738  m_offboard.get()->set_position_ned(landing);
739  // Possibility is to use set_position_velocity_ned(); to speed up
740  bool success = false;
741 
742  // Add check with Altitude
743  auto landing_finished_promise = std::promise<void> {};
744  auto landing_finished_future = landing_finished_promise.get_future();
745 
746 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
747  auto handle_odom = m_telemetry.get()->subscribe_odometry(
748  [this, &landing_finished_promise, &success, &handle](mavsdk::Telemetry::Odometry odom) {
749  if (odom.position_body.z_m > -0.15) {
750  std::cout << "Landing altitude reached \n.";
751 
752  success = true;
753  m_telemetry.get()->unsubscribe_odometry(handle_odom);
754  landing_finished_promise.set_value();
755  }
756  });
757 #else
758  m_telemetry.get()->subscribe_odometry(
759  [this, &landing_finished_promise, &success](mavsdk::Telemetry::Odometry odom) {
760  if (odom.position_body.z_m > -0.15) {
761  std::cout << "Landing altitude reached\n.";
762 
763  success = true;
764  m_telemetry.get()->subscribe_odometry(nullptr);
765  landing_finished_promise.set_value();
766  }
767  });
768 #endif
769  if (landing_finished_future.wait_for(seconds(10)) == std::future_status::timeout) {
770  std::cerr << "failed: altitude not reached.\n";
771  success = true; // go to automatic landing
772  }
773 
774  while (!success) {
775  std::cout << "Descending\n.";
776  sleep_for(100ms);
777  }
778  }
779 
780  if (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Land) {
781  std::cout << "Landing...\n";
782  const mavsdk::Action::Result land_result = m_action.get()->land();
783  if (land_result != mavsdk::Action::Result::Success) {
784  std::cerr << "Land failed: " << land_result << std::endl;
785  return false;
786  }
787 
788  // Check if vehicle is still in air
789  while (m_telemetry.get()->in_air()) {
790  std::cout << "Vehicle is landing..." << std::endl;
791  sleep_for(seconds(1));
792  }
793  }
794 
795  std::cout << "Landed!" << std::endl;
796  // We are relying on auto-disarming but let's keep watching the telemetry
797  // for a bit longer.
798  sleep_for(seconds(5));
799  std::cout << "Finished..." << std::endl;
800  return true;
801  }
802 
803  bool setPosition(float ned_north, float ned_east, float ned_down, float ned_yaw, bool blocking, int timeout_sec)
804  {
805  mavsdk::Offboard::PositionNedYaw position_target {};
806 
807  position_target.north_m = ned_north;
808  position_target.east_m = ned_east;
809  position_target.down_m = ned_down;
810  position_target.yaw_deg = vpMath::deg(ned_yaw);
811 
812  std::cout << "NED Pos to reach: " << position_target.north_m << " " << position_target.east_m << " "
813  << position_target.down_m << " " << position_target.yaw_deg << std::endl;
814  m_offboard.get()->set_position_ned(position_target);
815 
816  if (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Offboard) {
817  if (m_verbose) {
818  std::cout << "Cannot set vehicle position: offboard mode not started" << std::endl;
819  }
820  return false;
821  }
822 
823  if (blocking) {
824  // Add check with Altitude
825  auto position_reached_promise = std::promise<void> {};
826  auto position_reached_future = position_reached_promise.get_future();
827 
828 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
829  auto handle_odom = m_telemetry.get()->subscribe_odometry(
830  [this, &position_reached_promise, &handle, &position_target](mavsdk::Telemetry::Odometry odom) {
831  vpQuaternionVector q { odom.q.x, odom.q.y, odom.q.z, odom.q.w };
832  vpRotationMatrix R(q);
833  vpRxyzVector rxyz(R);
834  double odom_yaw = vpMath::deg(rxyz[2]);
835  double distance_to_target = std::sqrt(vpMath::sqr(odom.position_body.x_m - position_target.north_m) +
836  vpMath::sqr(odom.position_body.y_m - position_target.east_m) +
837  vpMath::sqr(odom.position_body.z_m - position_target.down_m));
838  if (distance_to_target < m_position_incertitude &&
839  std::fabs(odom_yaw - position_target.yaw_deg) < m_yaw_incertitude) {
840  std::cout << "Position reached\n.";
841  m_telemetry.get()->unsubscribe_odometry(handle_odom);
842  position_reached_promise.set_value();
843  }
844  });
845 #else
846  m_telemetry.get()->subscribe_odometry(
847  [this, &position_reached_promise, &position_target](mavsdk::Telemetry::Odometry odom) {
848  vpQuaternionVector q { odom.q.x, odom.q.y, odom.q.z, odom.q.w };
849  vpRotationMatrix R(q);
850  vpRxyzVector rxyz(R);
851  double odom_yaw = vpMath::deg(rxyz[2]);
852  double distance_to_target = std::sqrt(vpMath::sqr(odom.position_body.x_m - position_target.north_m) +
853  vpMath::sqr(odom.position_body.y_m - position_target.east_m) +
854  vpMath::sqr(odom.position_body.z_m - position_target.down_m));
855  if (distance_to_target < m_position_incertitude &&
856  std::fabs(odom_yaw - position_target.yaw_deg) < m_yaw_incertitude) {
857  std::cout << "Position reached\n.";
858  m_telemetry.get()->subscribe_odometry(nullptr);
859  position_reached_promise.set_value();
860  }
861  });
862 #endif
863  if (position_reached_future.wait_for(seconds(timeout_sec)) == std::future_status::timeout) {
864  std::cerr << "Positioning failed: position not reached.\n";
865  return false;
866  }
867  }
868 
869  std::cout << "---- DEBUG timeout: " << timeout_sec << std::endl;
870  return true;
871  }
872 
873  bool setPositionRelative(float ned_delta_north, float ned_delta_east, float ned_delta_down, float ned_delta_yaw,
874  bool blocking, int timeout_sec)
875  {
876  mavsdk::Telemetry::Odometry odom;
877  mavsdk::Telemetry::EulerAngle angles;
878  mavsdk::Offboard::PositionNedYaw position_target {};
879 
880  position_target.north_m = ned_delta_north;
881  position_target.east_m = ned_delta_east;
882  position_target.down_m = ned_delta_down;
883  position_target.yaw_deg = vpMath::deg(ned_delta_yaw);
884 
885  // Set a relative position
886  odom = m_telemetry.get()->odometry();
887  angles = m_telemetry.get()->attitude_euler();
888 
889  position_target.north_m += odom.position_body.x_m;
890  position_target.east_m += odom.position_body.y_m;
891  position_target.down_m += odom.position_body.z_m;
892  position_target.yaw_deg += angles.yaw_deg;
893 
894  return setPosition(position_target.north_m, position_target.east_m, position_target.down_m,
895  vpMath::rad(position_target.yaw_deg), blocking, timeout_sec);
896  }
897 
898  bool setPosition(const vpHomogeneousMatrix &M, bool absolute, int timeout_sec)
899  {
900  auto XYZvec = vpRxyzVector(M.getRotationMatrix());
901  if (XYZvec[0] != 0.0) {
902  std::cerr << "ERROR : Can't move, rotation around X axis should be 0." << std::endl;
903  return false;
904  }
905  if (XYZvec[1] != 0.0) {
906  std::cerr << "ERROR : Can't move, rotation around Y axis should be 0." << std::endl;
907  return false;
908  }
909  return setPosition(M.getTranslationVector()[0], M.getTranslationVector()[1], M.getTranslationVector()[2], XYZvec[2],
910  absolute, timeout_sec);
911  }
912 
913  bool setPositionRelative(const vpHomogeneousMatrix &M, bool blocking, int timeout_sec)
914  {
915  auto XYZvec = vpRxyzVector(M.getRotationMatrix());
916  if (XYZvec[0] != 0.0) {
917  std::cerr << "ERROR : Can't move, rotation around X axis should be 0." << std::endl;
918  return false;
919  }
920  if (XYZvec[1] != 0.0) {
921  std::cerr << "ERROR : Can't move, rotation around Y axis should be 0." << std::endl;
922  return false;
923  }
924  return setPositionRelative(M.getTranslationVector()[0], M.getTranslationVector()[1], M.getTranslationVector()[2],
925  XYZvec[2], blocking, timeout_sec);
926  }
927 
928  bool setVelocity(const vpColVector &frd_vel_cmd)
929  {
930  if (frd_vel_cmd.size() != 4) {
932  "ERROR : Can't set velocity, dimension of the velocity vector %d should be equal to 4.",
933  frd_vel_cmd.size()));
934  }
935 
936  if (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Offboard) {
937  if (m_verbose) {
938  std::cout << "Cannot set vehicle velocity: offboard mode not started" << std::endl;
939  }
940  return false;
941  }
942  mavsdk::Offboard::VelocityBodyYawspeed velocity_comm {};
943  velocity_comm.forward_m_s = frd_vel_cmd[0];
944  velocity_comm.right_m_s = frd_vel_cmd[1];
945  velocity_comm.down_m_s = frd_vel_cmd[2];
946  velocity_comm.yawspeed_deg_s = vpMath::deg(frd_vel_cmd[3]);
947  m_offboard.get()->set_velocity_body(velocity_comm);
948 
949  return true;
950  }
951 
952  bool kill()
953  {
954  const mavsdk::Action::Result kill_result = m_action.get()->kill();
955  if (kill_result != mavsdk::Action::Result::Success) {
956  std::cerr << "Kill failed: " << kill_result << std::endl;
957  return false;
958  }
959  return true;
960  }
961 
962  bool holdPosition()
963  {
964  if (m_telemetry.get()->in_air()) {
965  if (m_telemetry.get()->gps_info().fix_type != mavsdk::Telemetry::FixType::NoGps) {
966  // Action::hold() doesn't work with PX4 when in offboard mode
967  const mavsdk::Action::Result hold_result = m_action.get()->hold();
968  if (hold_result != mavsdk::Action::Result::Success) {
969  std::cerr << "Hold failed: " << hold_result << std::endl;
970  return false;
971  }
972  }
973  else {
974  if (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Offboard) {
975  if (m_verbose) {
976  std::cout << "Cannot set vehicle velocity: offboard mode not started" << std::endl;
977  }
978  return false;
979  }
980 
981  setPositionRelative(0., 0., 0., 0., false, 10.); // timeout not used
982  }
983  }
984  return true;
985  }
986 
987  bool stopMoving()
988  {
989  if (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Offboard) {
990  if (m_verbose) {
991  std::cout << "Cannot stop moving: offboard mode not started" << std::endl;
992  }
993  return false;
994  }
995 
996  const mavsdk::Offboard::VelocityBodyYawspeed stay {};
997  m_offboard.get()->set_velocity_body(stay);
998 
999  return true;
1000  }
1001 
1002  bool releaseControl()
1003  {
1004  auto offboard_result = m_offboard.get()->stop();
1005  if (offboard_result != mavsdk::Offboard::Result::Success) {
1006  std::cerr << "Offboard stop failed: " << offboard_result << '\n';
1007  return false;
1008  }
1009  std::cout << "Offboard stopped\n";
1010  return true;
1011  }
1012 
1013  void setAutoLand(bool auto_land) { m_auto_land = auto_land; }
1014 
1015  bool setYawSpeed(double body_frd_wz)
1016  {
1017  if (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Offboard) {
1018  if (m_verbose) {
1019  std::cout << "Cannot set vehicle velocity: offboard mode not started" << std::endl;
1020  }
1021  return false;
1022  }
1023  mavsdk::Offboard::VelocityBodyYawspeed velocity_comm {};
1024  velocity_comm.forward_m_s = 0.0;
1025  velocity_comm.right_m_s = 0.0;
1026  velocity_comm.down_m_s = 0.0;
1027  velocity_comm.yawspeed_deg_s = vpMath::deg(body_frd_wz);
1028  m_offboard.get()->set_velocity_body(velocity_comm);
1029 
1030  return true;
1031  }
1032 
1033  bool setForwardSpeed(double body_frd_vx)
1034  {
1035  if (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Offboard) {
1036  if (m_verbose) {
1037  std::cout << "Cannot set vehicle velocity: offboard mode not started" << std::endl;
1038  }
1039  return false;
1040  }
1041 
1042  mavsdk::Offboard::VelocityBodyYawspeed velocity_comm {};
1043  velocity_comm.forward_m_s = body_frd_vx;
1044  velocity_comm.right_m_s = 0.0;
1045  velocity_comm.down_m_s = 0.0;
1046  velocity_comm.yawspeed_deg_s = 0.0;
1047  m_offboard.get()->set_velocity_body(velocity_comm);
1048 
1049  return true;
1050  }
1051 
1052  bool setLateralSpeed(double body_frd_vy)
1053  {
1054  if (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Offboard) {
1055  if (m_verbose) {
1056  std::cout << "Cannot set vehicle velocity: offboard mode not started" << std::endl;
1057  }
1058  return false;
1059  }
1060  mavsdk::Offboard::VelocityBodyYawspeed velocity_comm {};
1061  velocity_comm.forward_m_s = 0.0;
1062  velocity_comm.right_m_s = body_frd_vy;
1063  velocity_comm.down_m_s = 0.0;
1064  velocity_comm.yawspeed_deg_s = 0.0;
1065  m_offboard.get()->set_velocity_body(velocity_comm);
1066 
1067  return true;
1068  }
1069 
1070  bool setVerticalSpeed(double body_frd_vz)
1071  {
1072  if (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Offboard) {
1073  if (m_verbose) {
1074  std::cout << "Cannot set vehicle velocity: offboard mode not started" << std::endl;
1075  }
1076  return false;
1077  }
1078  mavsdk::Offboard::VelocityBodyYawspeed velocity_comm {};
1079  velocity_comm.forward_m_s = 0.0;
1080  velocity_comm.right_m_s = 0.0;
1081  velocity_comm.down_m_s = body_frd_vz;
1082  velocity_comm.yawspeed_deg_s = 0.0;
1083  m_offboard.get()->set_velocity_body(velocity_comm);
1084 
1085  return true;
1086  }
1087 
1088  bool getFlyingCapability() { return m_has_flying_capability; }
1089 
1090  void setVerbose(bool verbose) { m_verbose = verbose; }
1091 
1092 private:
1093  //*** Attributes ***//
1094  std::string m_address {};
1095  mavsdk::Mavsdk m_mavsdk {};
1096  std::shared_ptr<mavsdk::System> m_system;
1097  std::shared_ptr<mavsdk::Action> m_action;
1098  std::shared_ptr<mavsdk::Telemetry> m_telemetry;
1099  std::shared_ptr<mavsdk::Offboard> m_offboard;
1100 
1101  double m_takeoffAlt { 1.0 };
1102 
1103  MAV_TYPE m_mav_type {}; // Vehicle type
1104  bool m_has_flying_capability { false };
1105 
1106  float m_position_incertitude { 0.05 };
1107  float m_yaw_incertitude { 0.09 }; // 5 deg
1108  bool m_verbose { false };
1109  bool m_auto_land { true };
1110  };
1111 #endif // #ifndef DOXYGEN_SHOULD_SKIP_THIS
1112 
1149 vpRobotMavsdk::vpRobotMavsdk(const std::string &connection_info) : m_impl(new vpRobotMavsdkImpl(connection_info))
1150 {
1151  m_impl->setPositioningIncertitude(0.05, vpMath::rad(5));
1152 }
1153 
1168 vpRobotMavsdk::vpRobotMavsdk() : m_impl(new vpRobotMavsdkImpl())
1169 {
1170  m_impl->setPositioningIncertitude(0.05, vpMath::rad(5));
1171 }
1172 
1180 vpRobotMavsdk::~vpRobotMavsdk() { delete m_impl; }
1181 
1194 void vpRobotMavsdk::connect(const std::string &connection_info) { m_impl->connect(connection_info); }
1195 
1199 bool vpRobotMavsdk::isRunning() const { return m_impl->isRunning(); }
1200 
1221 bool vpRobotMavsdk::sendMocapData(const vpHomogeneousMatrix &enu_M_flu, int display_fps)
1222 {
1223  return m_impl->sendMocapData(enu_M_flu, display_fps);
1224 }
1225 
1232 std::string vpRobotMavsdk::getAddress() const { return m_impl->getAddress(); }
1233 
1239 float vpRobotMavsdk::getBatteryLevel() const { return m_impl->getBatteryLevel(); }
1240 
1245 void vpRobotMavsdk::getPosition(vpHomogeneousMatrix &ned_M_frd) const { m_impl->getPosition(ned_M_frd); }
1246 
1254 void vpRobotMavsdk::getPosition(float &ned_north, float &ned_east, float &ned_down, float &ned_yaw) const
1255 {
1256  m_impl->getPosition(ned_north, ned_east, ned_down, ned_yaw);
1257 }
1258 
1265 std::tuple<float, float> vpRobotMavsdk::getHome() const { return m_impl->getHome(); }
1266 
1272 void vpRobotMavsdk::doFlatTrim() { }
1273 
1281 void vpRobotMavsdk::setTakeOffAlt(double altitude) { m_impl->setTakeOffAlt(altitude); }
1282 
1287 bool vpRobotMavsdk::arm() { return m_impl->arm(); }
1288 
1293 bool vpRobotMavsdk::disarm() { return m_impl->disarm(); }
1294 
1309 bool vpRobotMavsdk::takeOff(bool interactive, int timeout_sec, bool use_gps)
1310 {
1311  return m_impl->takeOff(interactive, timeout_sec, use_gps);
1312 }
1313 
1328 bool vpRobotMavsdk::takeOff(bool interactive, double takeoff_altitude, int timeout_sec, bool use_gps)
1329 {
1330  m_impl->setTakeOffAlt(takeoff_altitude);
1331  return m_impl->takeOff(interactive, timeout_sec, use_gps);
1332 }
1333 
1341 bool vpRobotMavsdk::holdPosition() { return m_impl->holdPosition(); };
1342 
1348 bool vpRobotMavsdk::stopMoving() { return m_impl->stopMoving(); };
1349 
1357 bool vpRobotMavsdk::land() { return m_impl->land(); }
1358 
1373 bool vpRobotMavsdk::setPosition(float ned_north, float ned_east, float ned_down, float ned_yaw, bool blocking,
1374  int timeout_sec)
1375 {
1376  return m_impl->setPosition(ned_north, ned_east, ned_down, ned_yaw, blocking, timeout_sec);
1377 }
1378 
1395 bool vpRobotMavsdk::setPosition(const vpHomogeneousMatrix &ned_M_frd, bool blocking, int timeout_sec)
1396 {
1397  return m_impl->setPosition(ned_M_frd, blocking, timeout_sec);
1398 }
1399 
1414 bool vpRobotMavsdk::setPositionRelative(float ned_delta_north, float ned_delta_east, float ned_delta_down,
1415  float ned_delta_yaw, bool blocking, int timeout_sec)
1416 {
1417  return m_impl->setPositionRelative(ned_delta_north, ned_delta_east, ned_delta_down, ned_delta_yaw, blocking,
1418  timeout_sec);
1419 }
1420 
1436 bool vpRobotMavsdk::setPositionRelative(const vpHomogeneousMatrix &delta_frd_M_frd, bool blocking, int timeout_sec)
1437 {
1438  return m_impl->setPositionRelative(delta_frd_M_frd, blocking, timeout_sec);
1439 }
1440 
1450 bool vpRobotMavsdk::setVelocity(const vpColVector &frd_vel_cmd) { return m_impl->setVelocity(frd_vel_cmd); }
1451 
1457 bool vpRobotMavsdk::kill() { return m_impl->kill(); }
1458 
1470 bool vpRobotMavsdk::setYawSpeed(double body_frd_wz) { return m_impl->setYawSpeed(body_frd_wz); }
1471 
1483 bool vpRobotMavsdk::setForwardSpeed(double body_frd_vx) { return m_impl->setForwardSpeed(body_frd_vx); }
1484 
1496 bool vpRobotMavsdk::setLateralSpeed(double body_frd_vy) { return m_impl->setLateralSpeed(body_frd_vy); }
1497 
1506 bool vpRobotMavsdk::setGPSGlobalOrigin(double latitude, double longitude, double altitude)
1507 {
1508  return m_impl->setGPSGlobalOrigin(latitude, longitude, altitude);
1509 }
1510 
1522 bool vpRobotMavsdk::takeControl() { return m_impl->takeControl(); }
1523 
1533 bool vpRobotMavsdk::releaseControl() { return m_impl->releaseControl(); }
1534 
1542 void vpRobotMavsdk::setAutoLand(bool auto_land) { m_impl->setAutoLand(auto_land); }
1543 
1551 void vpRobotMavsdk::setPositioningIncertitude(float position_incertitude, float yaw_incertitude)
1552 {
1553  m_impl->setPositioningIncertitude(position_incertitude, yaw_incertitude);
1554 }
1555 
1567 bool vpRobotMavsdk::setVerticalSpeed(double body_frd_vz) { return m_impl->setVerticalSpeed(body_frd_vz); }
1568 
1574 void vpRobotMavsdk::setVerbose(bool verbose) { m_impl->setVerbose(verbose); }
1575 
1581 bool vpRobotMavsdk::hasFlyingCapability() { return m_impl->getFlyingCapability(); }
1582 #ifdef ENABLE_VISP_NAMESPACE
1583  }
1584 #endif
1585 #elif !defined(VISP_BUILD_SHARED_LIBS)
1586 // Work around to avoid warning: libvisp_robot.a(vpRobotMavsdk.cpp.o) has no symbols
1587 void dummy_vpRobotMavsdk() { };
1588 #endif
unsigned int size() const
Return the number of elements of the 2D array.
Definition: vpArray2D.h:349
Implementation of column vector and the associated operations.
Definition: vpColVector.h:191
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ dimensionError
Bad dimension.
Definition: vpException.h:71
@ fatalError
Fatal error.
Definition: vpException.h:72
Implementation of an homogeneous matrix and operations on such kind of matrices.
vpRotationMatrix getRotationMatrix() const
vpHomogeneousMatrix & buildFrom(const vpTranslationVector &t, const vpRotationMatrix &R)
vpTranslationVector getTranslationVector() const
static double rad(double deg)
Definition: vpMath.h:129
static double sqr(double x)
Definition: vpMath.h:203
static vpHomogeneousMatrix enu2ned(const vpHomogeneousMatrix &enu_M)
Definition: vpMath.cpp:774
static double deg(double rad)
Definition: vpMath.h:119
Implementation of a rotation vector as quaternion angle minimal representation.
const double & x() const
Returns the x-component of the quaternion.
Implementation of a rotation matrix and operations on such kind of matrices.
Implementation of a rotation vector as Euler angle minimal representation.
Definition: vpRxyzVector.h:183
Class that consider the case of a translation vector.
VISP_EXPORT int wait(double t0, double t)
VISP_EXPORT double measureTimeMs()