36 #include <visp3/core/vpConfig.h>
38 #if defined(VISP_HAVE_MAVSDK) && (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_17)
44 #include <mavsdk/mavsdk.h>
45 #include <mavsdk/plugins/action/action.h>
46 #include <mavsdk/plugins/calibration/calibration.h>
47 #include <mavsdk/plugins/mavlink_passthrough/mavlink_passthrough.h>
48 #include <mavsdk/plugins/mocap/mocap.h>
49 #include <mavsdk/plugins/offboard/offboard.h>
50 #include <mavsdk/plugins/telemetry/telemetry.h>
52 #include <visp3/core/vpExponentialMap.h>
53 #include <visp3/robot/vpRobotMavsdk.h>
55 using std::chrono::milliseconds;
56 using std::chrono::seconds;
57 using std::this_thread::sleep_for;
58 using namespace std::chrono_literals;
60 #ifndef DOXYGEN_SHOULD_SKIP_THIS
61 class vpRobotMavsdk::vpRobotMavsdkImpl
64 vpRobotMavsdkImpl() : m_takeoffAlt(1.0) {}
65 vpRobotMavsdkImpl(
const std::string &connection_info) : m_takeoffAlt(1.0) { connect(connection_info); }
67 virtual ~vpRobotMavsdkImpl()
69 if (m_has_flying_capability && m_auto_land) {
80 std::shared_ptr<mavsdk::System> getSystem(mavsdk::Mavsdk &mavsdk)
82 std::cout <<
"Waiting to discover system..." << std::endl;
83 auto prom = std::promise<std::shared_ptr<mavsdk::System> >{};
84 auto fut = prom.get_future();
88 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
89 mavsdk::Mavsdk::NewSystemHandle handle = mavsdk.subscribe_on_new_system([&mavsdk, &prom, &handle]() {
91 mavsdk.subscribe_on_new_system([&mavsdk, &prom]() {
93 auto system = mavsdk.systems().back();
95 if (system->has_autopilot()) {
96 std::cout <<
"Discovered autopilot" << std::endl;
99 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
100 mavsdk.unsubscribe_on_new_system(handle);
102 mavsdk.subscribe_on_new_system(nullptr);
104 prom.set_value(system);
110 if (fut.wait_for(seconds(3)) == std::future_status::timeout) {
111 std::cerr <<
"No autopilot found." << std::endl;
119 MAV_TYPE getVehicleType()
121 auto passthrough = mavsdk::MavlinkPassthrough{m_system};
123 auto prom = std::promise<MAV_TYPE>{};
124 auto fut = prom.get_future();
125 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
126 mavsdk::MavlinkPassthrough::MessageHandle handle = passthrough.subscribe_message(
127 MAVLINK_MSG_ID_HEARTBEAT, [&passthrough, &prom, &handle](
const mavlink_message_t &message) {
129 passthrough.subscribe_message_async(MAVLINK_MSG_ID_HEARTBEAT,
130 [&passthrough, &prom](
const mavlink_message_t &message) {
133 if (message.compid != MAV_COMP_ID_AUTOPILOT1) {
137 mavlink_heartbeat_t heartbeat;
138 mavlink_msg_heartbeat_decode(&message, &heartbeat);
141 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
142 passthrough.unsubscribe_message(handle);
144 passthrough.subscribe_message_async(MAVLINK_MSG_ID_HEARTBEAT,
nullptr);
147 prom.set_value(
static_cast<MAV_TYPE
>(heartbeat.type));
152 if (fut.wait_for(seconds(3)) == std::future_status::timeout) {
153 std::cerr <<
"No heartbeat received to get vehicle type." << std::endl;
161 void calibrate_accelerometer(mavsdk::Calibration &calibration)
163 std::cout <<
"Calibrating accelerometer..." << std::endl;
165 std::promise<void> calibration_promise;
166 auto calibration_future = calibration_promise.get_future();
168 calibration.calibrate_accelerometer_async(create_calibration_callback(calibration_promise));
170 calibration_future.wait();
173 std::function<void(mavsdk::Calibration::Result, mavsdk::Calibration::ProgressData)>
174 create_calibration_callback(std::promise<void> &calibration_promise)
176 return [&calibration_promise](
const mavsdk::Calibration::Result result,
177 const mavsdk::Calibration::ProgressData progress_data) {
179 case mavsdk::Calibration::Result::Success:
180 std::cout <<
"--- Calibration succeeded!" << std::endl;
181 calibration_promise.set_value();
183 case mavsdk::Calibration::Result::Next:
184 if (progress_data.has_progress) {
185 std::cout <<
" Progress: " << progress_data.progress << std::endl;
187 if (progress_data.has_status_text) {
188 std::cout <<
" Instruction: " << progress_data.status_text << std::endl;
192 std::cout <<
"--- Calibration failed with message: " << result << std::endl;
193 calibration_promise.set_value();
199 void calibrate_gyro(mavsdk::Calibration &calibration)
201 std::cout <<
"Calibrating gyro..." << std::endl;
203 std::promise<void> calibration_promise;
204 auto calibration_future = calibration_promise.get_future();
206 calibration.calibrate_gyro_async(create_calibration_callback(calibration_promise));
208 calibration_future.wait();
212 void connect(
const std::string &connectionInfo)
214 m_address = connectionInfo;
215 mavsdk::ConnectionResult connection_result = m_mavsdk.add_any_connection(connectionInfo);
217 if (connection_result != mavsdk::ConnectionResult::Success) {
218 std::cerr <<
"Connection failed: " << connection_result << std::endl;
222 m_system = getSystem(m_mavsdk);
228 m_mav_type = getVehicleType();
230 m_has_flying_capability = hasFlyingCapability(m_mav_type);
232 std::cout << (m_has_flying_capability ?
"Connected to a flying vehicle" :
"Connected to a non flying vehicle")
235 m_action = std::make_shared<mavsdk::Action>(m_system);
236 m_telemetry = std::make_shared<mavsdk::Telemetry>(m_system);
237 m_offboard = std::make_shared<mavsdk::Offboard>(m_system);
240 bool hasFlyingCapability(MAV_TYPE mav_type)
243 case MAV_TYPE::MAV_TYPE_GROUND_ROVER:
244 case MAV_TYPE::MAV_TYPE_SURFACE_BOAT:
245 case MAV_TYPE::MAV_TYPE_SUBMARINE:
252 bool isRunning()
const
254 if (m_system == NULL) {
261 std::string getAddress()
const
263 std::string sequence;
264 std::stringstream ss(m_address);
265 std::string actual_address;
266 std::getline(ss, sequence,
':');
267 if (sequence ==
"serial" || sequence ==
"udp" || sequence ==
"tcp") {
268 getline(ss, sequence,
':');
269 for (
const char &c : sequence) {
271 actual_address.append(1, c);
274 return actual_address;
276 std::cout <<
"ERROR : The address parameter must start with \"serial:\" or \"udp:\" or \"tcp:\"." << std::endl;
277 return std::string();
281 float getBatteryLevel()
const
283 mavsdk::Telemetry::Battery battery = m_telemetry.get()->battery();
284 return battery.voltage_v;
289 auto quat = m_telemetry.get()->attitude_quaternion();
290 auto posvel = m_telemetry.get()->position_velocity_ned();
292 vpTranslationVector t{posvel.position.north_m, posvel.position.east_m, posvel.position.down_m};
296 void getPosition(
float &ned_north,
float &ned_east,
float &ned_down,
float &ned_yaw)
const
298 auto odom = m_telemetry.get()->odometry();
299 auto angles = m_telemetry.get()->attitude_euler();
300 ned_north = odom.position_body.x_m;
301 ned_east = odom.position_body.y_m;
302 ned_down = odom.position_body.z_m;
306 std::tuple<float, float> getHome()
const
308 auto position = m_telemetry.get()->home();
309 return {float(position.latitude_deg), float(position.longitude_deg)};
320 flu_M_frd[1][1] = -1;
321 flu_M_frd[2][2] = -1;
324 auto mocap = mavsdk::Mocap{m_system};
325 mavsdk::Mocap::VisionPositionEstimate pose_estimate;
329 pose_estimate.angle_body.roll_rad = ned_rxyz_frd[0];
330 pose_estimate.angle_body.pitch_rad = ned_rxyz_frd[1];
331 pose_estimate.angle_body.yaw_rad = ned_rxyz_frd[2];
334 pose_estimate.position_body.x_m = ned_t_frd[0];
335 pose_estimate.position_body.y_m = ned_t_frd[1];
336 pose_estimate.position_body.z_m = ned_t_frd[2];
338 pose_estimate.pose_covariance.covariance_matrix.push_back(NAN);
339 pose_estimate.time_usec = 0;
341 const mavsdk::Mocap::Result set_position_result = mocap.set_vision_position_estimate(pose_estimate);
342 if (set_position_result != mavsdk::Mocap::Result::Success) {
343 std::cerr <<
"Set position failed: " << set_position_result <<
'\n';
346 if (display_fps > 0) {
347 double display_time_ms = 1000. / display_fps;
350 std::cout <<
"Send ned_M_frd MoCap data: " << std::endl;
351 std::cout <<
"Translation [m]: " << pose_estimate.position_body.x_m <<
" , "
352 << pose_estimate.position_body.y_m <<
" , " << pose_estimate.position_body.z_m << std::endl;
353 std::cout <<
"Roll [rad]: " << pose_estimate.angle_body.roll_rad
354 <<
" , Pitch [rad]: " << pose_estimate.angle_body.pitch_rad
355 <<
" , Yaw [rad]: " << pose_estimate.angle_body.yaw_rad <<
" ." << std::endl;
362 void setTakeOffAlt(
double altitude)
365 m_takeoffAlt = altitude;
367 std::cerr <<
"ERROR : The take off altitude must be positive." << std::endl;
374 auto calibration = mavsdk::Calibration(m_system);
377 calibrate_accelerometer(calibration);
378 calibrate_gyro(calibration);
384 std::cout <<
"Arming...\n";
385 const mavsdk::Action::Result arm_result = m_action.get()->arm();
387 if (arm_result != mavsdk::Action::Result::Success) {
388 std::cerr <<
"Arming failed: " << arm_result << std::endl;
397 std::cout <<
"Disarming...\n";
398 const mavsdk::Action::Result arm_result = m_action.get()->disarm();
400 if (arm_result != mavsdk::Action::Result::Success) {
401 std::cerr <<
"Disarming failed: " << arm_result << std::endl;
407 bool setGPSGlobalOrigin(
double latitude,
double longitude,
double altitude)
409 auto passthrough = mavsdk::MavlinkPassthrough{m_system};
410 mavlink_set_gps_global_origin_t gps_global_origin;
411 gps_global_origin.latitude = latitude * 10000000;
412 gps_global_origin.longitude = longitude * 10000000;
413 gps_global_origin.altitude = altitude * 1000;
414 gps_global_origin.target_system = m_system->get_system_id();
415 mavlink_message_t msg;
416 mavlink_msg_set_gps_global_origin_encode(passthrough.get_our_sysid(), passthrough.get_our_compid(), &msg,
418 auto resp = passthrough.send_message(msg);
419 if (resp != mavsdk::MavlinkPassthrough::Result::Success) {
420 std::cerr <<
"Set GPS global position failed: " << resp << std::endl;
429 std::cout <<
"Starting offboard mode..." << std::endl;
432 if (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Offboard) {
433 const mavsdk::Offboard::VelocityBodyYawspeed stay{};
434 m_offboard.get()->set_velocity_body(stay);
436 mavsdk::Offboard::Result offboard_result = m_offboard.get()->start();
437 if (offboard_result != mavsdk::Offboard::Result::Success) {
438 std::cerr <<
"Offboard mode failed: " << offboard_result << std::endl;
441 }
else if (m_verbose) {
442 std::cout <<
"Already in offboard mode" << std::endl;
447 while (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Offboard) {
449 std::cout <<
"Time out received in takeControl()" << std::endl;
455 std::cout <<
"Offboard mode started" << std::endl;
460 void setPositioningIncertitude(
float position_incertitude,
float yaw_incertitude)
462 m_position_incertitude = position_incertitude;
463 m_yaw_incertitude = yaw_incertitude;
466 bool takeOff(
bool interactive,
int timeout_sec,
bool use_gps)
468 if (!m_has_flying_capability) {
469 std::cerr <<
"Warning: Cannot takeoff this non flying vehicle" << std::endl;
473 bool authorize_takeoff =
false;
476 authorize_takeoff =
true;
478 if (m_telemetry.get()->flight_mode() == mavsdk::Telemetry::FlightMode::Offboard) {
479 authorize_takeoff =
true;
482 while (answer !=
"Y" && answer !=
"y" && answer !=
"N" && answer !=
"n") {
483 std::cout <<
"Current flight mode is not the offboard mode. Do you "
484 "want to force offboard mode ? (y/n)"
487 if (answer ==
"Y" || answer ==
"y") {
488 authorize_takeoff =
true;
494 if (m_telemetry.get()->in_air()) {
495 std::cerr <<
"Cannot take off as the robot is already flying." << std::endl;
497 }
else if (authorize_takeoff) {
507 while (answer !=
"Y" && answer !=
"y" && answer !=
"N" && answer !=
"n") {
508 std::cout <<
"If vehicle armed ? (y/n)" << std::endl;
510 if (answer ==
"N" || answer ==
"n") {
519 if (m_telemetry.get()->gps_info().fix_type == mavsdk::Telemetry::FixType::NoGps || !use_gps) {
528 auto in_air_promise = std::promise<void>{};
529 auto in_air_future = in_air_promise.get_future();
531 mavsdk::Telemetry::Odometry odom = m_telemetry.get()->odometry();
536 double X_init = odom.position_body.x_m;
537 double Y_init = odom.position_body.y_m;
538 double Z_init = odom.position_body.z_m;
541 std::cout <<
"Takeoff using position NED." << std::endl;
543 mavsdk::Offboard::PositionNedYaw takeoff{};
544 takeoff.north_m = X_init;
545 takeoff.east_m = Y_init;
546 takeoff.down_m = Z_init - m_takeoffAlt;
547 takeoff.yaw_deg = yaw_init;
548 m_offboard.get()->set_position_ned(takeoff);
551 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
552 Telemetry::LandedStateHandle handle = m_telemetry.get()->subscribe_landed_state(
553 [
this, &in_air_promise, &handle](mavsdk::Telemetry::LandedState state) {
554 if (state == mavsdk::Telemetry::LandedState::InAir) {
555 std::cout <<
"Drone is taking off\n.";
556 m_telemetry.get()->unsubscribe_landed_state(handle);
557 in_air_promise.set_value();
561 m_telemetry.get()->subscribe_landed_state([
this, &in_air_promise](mavsdk::Telemetry::LandedState state) {
562 if (state == mavsdk::Telemetry::LandedState::InAir) {
563 std::cout <<
"Drone is taking off\n.";
564 m_telemetry.get()->subscribe_landed_state(
nullptr);
565 in_air_promise.set_value();
567 std::cout <<
"state: " << state << std::endl;
570 if (in_air_future.wait_for(seconds(timeout_sec)) == std::future_status::timeout) {
571 std::cerr <<
"Takeoff failed: drone not in air.\n";
572 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
573 m_telemetry.get()->unsubscribe_landed_state(handle);
575 m_telemetry.get()->subscribe_landed_state(
nullptr);
580 auto takeoff_finished_promise = std::promise<void>{};
581 auto takeoff_finished_future = takeoff_finished_promise.get_future();
583 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
584 auto handle_odom = m_telemetry.get()->subscribe_odometry(
585 [
this, &takeoff_finished_promise, &handle, &Z_init](mavsdk::Telemetry::Odometry odom) {
586 if (odom.position_body.z_m < 0.90 * (Z_init - m_takeoffAlt) + m_position_incertitude) {
587 std::cout <<
"Takeoff altitude reached\n.";
588 m_telemetry.get()->unsubscribe_odometry(handle_odom);
589 takeoff_finished_promise.set_value();
593 m_telemetry.get()->subscribe_odometry(
594 [
this, &takeoff_finished_promise, &Z_init](mavsdk::Telemetry::Odometry odom) {
595 if (odom.position_body.z_m < 0.90 * (Z_init - m_takeoffAlt) + m_position_incertitude) {
596 std::cout <<
"Takeoff altitude reached\n.";
597 m_telemetry.get()->subscribe_odometry(nullptr);
598 takeoff_finished_promise.set_value();
602 if (takeoff_finished_future.wait_for(seconds(timeout_sec)) == std::future_status::timeout) {
603 std::cerr <<
"Takeoff failed: altitude not reached.\n";
604 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
605 m_telemetry.get()->unsubscribe_odometry(handle);
607 m_telemetry.get()->subscribe_odometry(
nullptr);
613 std::cout <<
"---- DEBUG: GPS detected: use action::takeoff()" << std::endl;
615 mavsdk::Telemetry::Odometry odom = m_telemetry.get()->odometry();
616 double Z_init = odom.position_body.z_m;
618 m_action.get()->set_takeoff_altitude(m_takeoffAlt);
619 const auto takeoff_result = m_action.get()->takeoff();
620 if (takeoff_result != mavsdk::Action::Result::Success) {
621 std::cerr <<
"Takeoff failed: " << takeoff_result <<
'\n';
625 auto in_air_promise = std::promise<void>{};
626 auto in_air_future = in_air_promise.get_future();
627 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
628 Telemetry::LandedStateHandle handle = m_telemetry.get()->subscribe_landed_state(
629 [
this, &in_air_promise, &handle](mavsdk::Telemetry::LandedState state) {
630 if (state == mavsdk::Telemetry::LandedState::InAir) {
631 std::cout <<
"Taking off has finished\n.";
632 m_telemetry.get()->unsubscribe_landed_state(handle);
633 in_air_promise.set_value();
637 m_telemetry.get()->subscribe_landed_state([
this, &in_air_promise](mavsdk::Telemetry::LandedState state) {
638 if (state == mavsdk::Telemetry::LandedState::InAir) {
639 std::cout <<
"Taking off has finished\n.";
640 m_telemetry.get()->subscribe_landed_state(
nullptr);
641 in_air_promise.set_value();
643 std::cout <<
"state: " << state << std::endl;
646 if (in_air_future.wait_for(seconds(timeout_sec)) == std::future_status::timeout) {
648 std::cerr <<
"Takeoff timed out.\n";
649 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
650 m_telemetry.get()->unsubscribe_landed_state(handle);
652 m_telemetry.get()->subscribe_landed_state(
nullptr);
656 auto takeoff_finished_promise = std::promise<void>{};
657 auto takeoff_finished_future = takeoff_finished_promise.get_future();
659 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
660 auto handle_odom = m_telemetry.get()->subscribe_odometry(
661 [
this, &takeoff_finished_promise, &handle, &Z_init](mavsdk::Telemetry::Odometry odom) {
662 if (odom.position_body.z_m < 0.90 * (Z_init - m_takeoffAlt) + m_position_incertitude) {
663 std::cout <<
"Takeoff altitude reached\n.";
664 m_telemetry.get()->unsubscribe_odometry(handle_odom);
665 takeoff_finished_promise.set_value();
669 m_telemetry.get()->subscribe_odometry(
670 [
this, &takeoff_finished_promise, &Z_init](mavsdk::Telemetry::Odometry odom) {
671 if (odom.position_body.z_m < 0.90 * (Z_init - m_takeoffAlt) + m_position_incertitude) {
672 std::cout <<
"Takeoff altitude reached\n.";
673 m_telemetry.get()->subscribe_odometry(nullptr);
674 takeoff_finished_promise.set_value();
678 if (takeoff_finished_future.wait_for(seconds(timeout_sec)) == std::future_status::timeout) {
679 std::cerr <<
"Takeoff failed: altitude not reached.\n";
680 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
681 m_telemetry.get()->unsubscribe_odometry(handle);
683 m_telemetry.get()->subscribe_odometry(
nullptr);
694 bool land(
bool use_buildin =
false)
696 if (!m_has_flying_capability) {
697 std::cerr <<
"Warning: Cannot land this non flying vehicle" << std::endl;
710 mavsdk::Telemetry::Odometry odom = m_telemetry.get()->odometry();
715 double X_init = odom.position_body.x_m;
716 double Y_init = odom.position_body.y_m;
717 double Z_init = odom.position_body.z_m;
720 std::cout <<
"Landing using position NED." << std::endl;
722 mavsdk::Offboard::PositionNedYaw landing{};
723 landing.north_m = X_init;
724 landing.east_m = Y_init;
726 landing.yaw_deg = yaw_init;
727 m_offboard.get()->set_position_ned(landing);
729 bool success =
false;
732 auto landing_finished_promise = std::promise<void>{};
733 auto landing_finished_future = landing_finished_promise.get_future();
735 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
736 auto handle_odom = m_telemetry.get()->subscribe_odometry(
737 [
this, &landing_finished_promise, &success, &handle](mavsdk::Telemetry::Odometry odom) {
738 if (odom.position_body.z_m > -0.15) {
739 std::cout <<
"Landing altitude reached \n.";
742 m_telemetry.get()->unsubscribe_odometry(handle_odom);
743 landing_finished_promise.set_value();
747 m_telemetry.get()->subscribe_odometry(
748 [
this, &landing_finished_promise, &success](mavsdk::Telemetry::Odometry odom) {
749 if (odom.position_body.z_m > -0.15) {
750 std::cout <<
"Landing altitude reached\n.";
753 m_telemetry.get()->subscribe_odometry(nullptr);
754 landing_finished_promise.set_value();
758 if (landing_finished_future.wait_for(seconds(10)) == std::future_status::timeout) {
759 std::cerr <<
"failed: altitude not reached.\n";
764 std::cout <<
"Descending\n.";
769 if (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Land) {
770 std::cout <<
"Landing...\n";
771 const mavsdk::Action::Result land_result = m_action.get()->land();
772 if (land_result != mavsdk::Action::Result::Success) {
773 std::cerr <<
"Land failed: " << land_result << std::endl;
778 while (m_telemetry.get()->in_air()) {
779 std::cout <<
"Vehicle is landing..." << std::endl;
780 sleep_for(seconds(1));
784 std::cout <<
"Landed!" << std::endl;
787 sleep_for(seconds(5));
788 std::cout <<
"Finished..." << std::endl;
792 bool setPosition(
float ned_north,
float ned_east,
float ned_down,
float ned_yaw,
bool blocking,
int timeout_sec)
794 mavsdk::Offboard::PositionNedYaw position_target{};
796 position_target.north_m = ned_north;
797 position_target.east_m = ned_east;
798 position_target.down_m = ned_down;
801 std::cout <<
"NED Pos to reach: " << position_target.north_m <<
" " << position_target.east_m <<
" "
802 << position_target.down_m <<
" " << position_target.yaw_deg << std::endl;
803 m_offboard.get()->set_position_ned(position_target);
805 if (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Offboard) {
807 std::cout <<
"Cannot set vehicle position: offboard mode not started" << std::endl;
814 auto position_reached_promise = std::promise<void>{};
815 auto position_reached_future = position_reached_promise.get_future();
817 #if (VISP_HAVE_MAVSDK_VERSION > 0x010412)
818 auto handle_odom = m_telemetry.get()->subscribe_odometry(
819 [
this, &position_reached_promise, &handle, &position_target](mavsdk::Telemetry::Odometry odom) {
824 double distance_to_target = std::sqrt(
vpMath::sqr(odom.position_body.x_m - position_target.north_m) +
825 vpMath::sqr(odom.position_body.y_m - position_target.east_m) +
826 vpMath::sqr(odom.position_body.z_m - position_target.down_m));
827 if (distance_to_target < m_position_incertitude &&
828 std::fabs(odom_yaw - position_target.yaw_deg) < m_yaw_incertitude) {
829 std::cout <<
"Position reached\n.";
830 m_telemetry.get()->unsubscribe_odometry(handle_odom);
831 position_reached_promise.set_value();
835 m_telemetry.get()->subscribe_odometry(
836 [
this, &position_reached_promise, &position_target](mavsdk::Telemetry::Odometry odom) {
841 double distance_to_target = std::sqrt(
vpMath::sqr(odom.position_body.x_m - position_target.north_m) +
842 vpMath::sqr(odom.position_body.y_m - position_target.east_m) +
843 vpMath::sqr(odom.position_body.z_m - position_target.down_m));
844 if (distance_to_target < m_position_incertitude &&
845 std::fabs(odom_yaw - position_target.yaw_deg) < m_yaw_incertitude) {
846 std::cout <<
"Position reached\n.";
847 m_telemetry.get()->subscribe_odometry(
nullptr);
848 position_reached_promise.set_value();
852 if (position_reached_future.wait_for(seconds(timeout_sec)) == std::future_status::timeout) {
853 std::cerr <<
"Positioning failed: position not reached.\n";
858 std::cout <<
"---- DEBUG timeout: " << timeout_sec << std::endl;
862 bool setPositionRelative(
float ned_delta_north,
float ned_delta_east,
float ned_delta_down,
float ned_delta_yaw,
863 bool blocking,
int timeout_sec)
865 mavsdk::Telemetry::Odometry odom;
866 mavsdk::Telemetry::EulerAngle angles;
867 mavsdk::Offboard::PositionNedYaw position_target{};
869 position_target.north_m = ned_delta_north;
870 position_target.east_m = ned_delta_east;
871 position_target.down_m = ned_delta_down;
872 position_target.yaw_deg =
vpMath::deg(ned_delta_yaw);
875 odom = m_telemetry.get()->odometry();
876 angles = m_telemetry.get()->attitude_euler();
878 position_target.north_m += odom.position_body.x_m;
879 position_target.east_m += odom.position_body.y_m;
880 position_target.down_m += odom.position_body.z_m;
881 position_target.yaw_deg += angles.yaw_deg;
883 return setPosition(position_target.north_m, position_target.east_m, position_target.down_m,
884 vpMath::rad(position_target.yaw_deg), blocking, timeout_sec);
890 if (XYZvec[0] != 0.0) {
891 std::cerr <<
"ERROR : Can't move, rotation around X axis should be 0." << std::endl;
894 if (XYZvec[1] != 0.0) {
895 std::cerr <<
"ERROR : Can't move, rotation around Y axis should be 0." << std::endl;
899 absolute, timeout_sec);
905 if (XYZvec[0] != 0.0) {
906 std::cerr <<
"ERROR : Can't move, rotation around X axis should be 0." << std::endl;
909 if (XYZvec[1] != 0.0) {
910 std::cerr <<
"ERROR : Can't move, rotation around Y axis should be 0." << std::endl;
914 XYZvec[2], blocking, timeout_sec);
919 if (frd_vel_cmd.
size() != 4) {
921 "ERROR : Can't set velocity, dimension of the velocity vector %d should be equal to 4.",
922 frd_vel_cmd.
size()));
925 if (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Offboard) {
927 std::cout <<
"Cannot set vehicle velocity: offboard mode not started" << std::endl;
931 mavsdk::Offboard::VelocityBodyYawspeed velocity_comm{};
932 velocity_comm.forward_m_s = frd_vel_cmd[0];
933 velocity_comm.right_m_s = frd_vel_cmd[1];
934 velocity_comm.down_m_s = frd_vel_cmd[2];
935 velocity_comm.yawspeed_deg_s =
vpMath::deg(frd_vel_cmd[3]);
936 m_offboard.get()->set_velocity_body(velocity_comm);
943 const mavsdk::Action::Result kill_result = m_action.get()->kill();
944 if (kill_result != mavsdk::Action::Result::Success) {
945 std::cerr <<
"Kill failed: " << kill_result << std::endl;
953 if (m_telemetry.get()->in_air()) {
954 if (m_telemetry.get()->gps_info().fix_type != mavsdk::Telemetry::FixType::NoGps) {
956 const mavsdk::Action::Result hold_result = m_action.get()->hold();
957 if (hold_result != mavsdk::Action::Result::Success) {
958 std::cerr <<
"Hold failed: " << hold_result << std::endl;
962 if (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Offboard) {
964 std::cout <<
"Cannot set vehicle velocity: offboard mode not started" << std::endl;
969 setPositionRelative(0., 0., 0., 0.,
false, 10.);
977 if (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Offboard) {
979 std::cout <<
"Cannot stop moving: offboard mode not started" << std::endl;
984 const mavsdk::Offboard::VelocityBodyYawspeed stay{};
985 m_offboard.get()->set_velocity_body(stay);
990 bool releaseControl()
992 auto offboard_result = m_offboard.get()->stop();
993 if (offboard_result != mavsdk::Offboard::Result::Success) {
994 std::cerr <<
"Offboard stop failed: " << offboard_result <<
'\n';
997 std::cout <<
"Offboard stopped\n";
1001 void setAutoLand(
bool auto_land) { m_auto_land = auto_land; }
1003 bool setYawSpeed(
double body_frd_wz)
1005 if (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Offboard) {
1007 std::cout <<
"Cannot set vehicle velocity: offboard mode not started" << std::endl;
1011 mavsdk::Offboard::VelocityBodyYawspeed velocity_comm{};
1012 velocity_comm.forward_m_s = 0.0;
1013 velocity_comm.right_m_s = 0.0;
1014 velocity_comm.down_m_s = 0.0;
1015 velocity_comm.yawspeed_deg_s =
vpMath::deg(body_frd_wz);
1016 m_offboard.get()->set_velocity_body(velocity_comm);
1021 bool setForwardSpeed(
double body_frd_vx)
1023 if (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Offboard) {
1025 std::cout <<
"Cannot set vehicle velocity: offboard mode not started" << std::endl;
1030 mavsdk::Offboard::VelocityBodyYawspeed velocity_comm{};
1031 velocity_comm.forward_m_s = body_frd_vx;
1032 velocity_comm.right_m_s = 0.0;
1033 velocity_comm.down_m_s = 0.0;
1034 velocity_comm.yawspeed_deg_s = 0.0;
1035 m_offboard.get()->set_velocity_body(velocity_comm);
1040 bool setLateralSpeed(
double body_frd_vy)
1042 if (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Offboard) {
1044 std::cout <<
"Cannot set vehicle velocity: offboard mode not started" << std::endl;
1048 mavsdk::Offboard::VelocityBodyYawspeed velocity_comm{};
1049 velocity_comm.forward_m_s = 0.0;
1050 velocity_comm.right_m_s = body_frd_vy;
1051 velocity_comm.down_m_s = 0.0;
1052 velocity_comm.yawspeed_deg_s = 0.0;
1053 m_offboard.get()->set_velocity_body(velocity_comm);
1058 bool setVerticalSpeed(
double body_frd_vz)
1060 if (m_telemetry.get()->flight_mode() != mavsdk::Telemetry::FlightMode::Offboard) {
1062 std::cout <<
"Cannot set vehicle velocity: offboard mode not started" << std::endl;
1066 mavsdk::Offboard::VelocityBodyYawspeed velocity_comm{};
1067 velocity_comm.forward_m_s = 0.0;
1068 velocity_comm.right_m_s = 0.0;
1069 velocity_comm.down_m_s = body_frd_vz;
1070 velocity_comm.yawspeed_deg_s = 0.0;
1071 m_offboard.get()->set_velocity_body(velocity_comm);
1076 bool getFlyingCapability() {
return m_has_flying_capability; }
1078 void setVerbose(
bool verbose) { m_verbose = verbose; }
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;
1101 double m_takeoffAlt{1.0};
1103 MAV_TYPE m_mav_type{};
1104 bool m_has_flying_capability{
false};
1106 bool m_system_ready{
false};
1107 float m_position_incertitude{0.05};
1108 float m_yaw_incertitude{0.09};
1109 bool m_verbose{
false};
1110 bool m_auto_land{
true};
1152 m_impl->setPositioningIncertitude(0.05,
vpMath::rad(5));
1171 m_impl->setPositioningIncertitude(0.05,
vpMath::rad(5));
1224 return m_impl->sendMocapData(enu_M_flu, display_fps);
1257 m_impl->getPosition(ned_north, ned_east, ned_down, ned_yaw);
1310 return m_impl->takeOff(interactive, timeout_sec, use_gps);
1328 m_impl->setTakeOffAlt(takeoff_altitude);
1329 return m_impl->takeOff(interactive, timeout_sec, use_gps);
1374 return m_impl->setPosition(ned_north, ned_east, ned_down, ned_yaw, blocking, timeout_sec);
1395 return m_impl->setPosition(ned_M_frd, blocking, timeout_sec);
1413 float ned_delta_yaw,
bool blocking,
int timeout_sec)
1415 return m_impl->setPositionRelative(ned_delta_north, ned_delta_east, ned_delta_down, ned_delta_yaw, blocking,
1436 return m_impl->setPositionRelative(delta_frd_M_frd, blocking, timeout_sec);
1506 return m_impl->setGPSGlobalOrigin(latitude, longitude, altitude);
1551 m_impl->setPositioningIncertitude(position_incertitude, yaw_incertitude);
1581 #elif !defined(VISP_BUILD_SHARED_LIBS)
1584 void dummy_vpRobotMavsdk(){};
unsigned int size() const
Return the number of elements of the 2D array.
Implementation of column vector and the associated operations.
error that can be emitted by ViSP classes.
@ dimensionError
Bad dimension.
Implementation of an homogeneous matrix and operations on such kind of matrices.
vpRotationMatrix getRotationMatrix() const
vpTranslationVector getTranslationVector() const
void buildFrom(const vpTranslationVector &t, const vpRotationMatrix &R)
static double rad(double deg)
static double sqr(double x)
static vpHomogeneousMatrix enu2ned(const vpHomogeneousMatrix &enu_M)
static double deg(double rad)
Implementation of a rotation vector as quaternion angle minimal representation.
const double & x() const
Returns the x-component of the quaternion.
float getBatteryLevel() const
std::string getAddress() const
void setPositioningIncertitude(float position_incertitude, float yaw_incertitude)
std::tuple< float, float > getHome() const
bool sendMocapData(const vpHomogeneousMatrix &enu_M_flu, int display_fps=1)
bool takeOff(bool interactive=true, int timeout_sec=10, bool use_gps=false)
void getPosition(float &ned_north, float &ned_east, float &ned_down, float &ned_yaw) const
bool setLateralSpeed(double body_frd_vy)
bool setPositionRelative(float ned_delta_north, float ned_delta_east, float ned_delta_down, float ned_delta_yaw, bool blocking=true, int timeout_sec=10)
bool setVerticalSpeed(double body_frd_vz)
void setAutoLand(bool auto_land)
bool setForwardSpeed(double body_frd_vx)
void setTakeOffAlt(double altitude)
bool hasFlyingCapability()
void setVerbose(bool verbose)
bool setVelocity(const vpColVector &frd_vel_cmd)
void connect(const std::string &connection_info)
bool setGPSGlobalOrigin(double latitude, double longitude, double altitude)
bool setPosition(float ned_north, float ned_east, float ned_down, float ned_yaw, bool blocking=true, int timeout_sec=10)
bool setYawSpeed(double body_frd_wz)
Implementation of a rotation matrix and operations on such kind of matrices.
Implementation of a rotation vector as Euler angle minimal representation.
Class that consider the case of a translation vector.
VISP_EXPORT int wait(double t0, double t)
VISP_EXPORT double measureTimeMs()