APM:Copter
GCS_Mavlink.cpp
Go to the documentation of this file.
1 #include "Copter.h"
2 
3 #include "GCS_Mavlink.h"
4 
6 {
8 }
9 
11 {
12  gcs().retry_deferred();
13 }
14 
15 /*
16  * !!NOTE!!
17  *
18  * the use of NOINLINE separate functions for each message type avoids
19  * a compiler bug in gcc that would cause it to use far more stack
20  * space than is needed. Without the NOINLINE we use the sum of the
21  * stack needed for each message type. Please be careful to follow the
22  * pattern below when adding any new messages
23  */
24 
26 {
27  return copter.get_frame_mav_type();
28 }
29 
31 {
32  uint8_t _base_mode = MAV_MODE_FLAG_STABILIZE_ENABLED;
33  // work out the base_mode. This value is not very useful
34  // for APM, but we calculate it as best we can so a generic
35  // MAVLink enabled ground station can work out something about
36  // what the MAV is up to. The actual bit values are highly
37  // ambiguous for most of the APM flight modes. In practice, you
38  // only get useful information from the custom_mode, which maps to
39  // the APM flight mode and has a well defined meaning in the
40  // ArduPlane documentation
41  switch (copter.control_mode) {
42  case AUTO:
43  case RTL:
44  case LOITER:
45  case AVOID_ADSB:
46  case FOLLOW:
47  case GUIDED:
48  case CIRCLE:
49  case POSHOLD:
50  case BRAKE:
51  case SMART_RTL:
52  _base_mode |= MAV_MODE_FLAG_GUIDED_ENABLED;
53  // note that MAV_MODE_FLAG_AUTO_ENABLED does not match what
54  // APM does in any mode, as that is defined as "system finds its own goal
55  // positions", which APM does not currently do
56  break;
57  default:
58  break;
59  }
60 
61  // all modes except INITIALISING have some form of manual
62  // override if stick mixing is enabled
63  _base_mode |= MAV_MODE_FLAG_MANUAL_INPUT_ENABLED;
64 
65 #if HIL_MODE != HIL_MODE_DISABLED
66  _base_mode |= MAV_MODE_FLAG_HIL_ENABLED;
67 #endif
68 
69  // we are armed if we are not initialising
70  if (copter.motors != nullptr && copter.motors->armed()) {
71  _base_mode |= MAV_MODE_FLAG_SAFETY_ARMED;
72  }
73 
74  // indicate we have set a custom mode
75  _base_mode |= MAV_MODE_FLAG_CUSTOM_MODE_ENABLED;
76 
77  return (MAV_MODE)_base_mode;
78 }
79 
81 {
82  return copter.control_mode;
83 }
84 
85 
87 {
88  // set system as critical if any failsafe have triggered
89  if (copter.any_failsafe_triggered()) {
90  return MAV_STATE_CRITICAL;
91  }
92 
93  if (copter.ap.land_complete) {
94  return MAV_STATE_STANDBY;
95  }
96 
97  return MAV_STATE_ACTIVE;
98 }
99 
100 
102 {
103  Location_Class target;
104  if (!copter.flightmode->get_wp(target)) {
105  return;
106  }
107  mavlink_msg_position_target_global_int_send(
108  chan,
109  AP_HAL::millis(), // time_boot_ms
110  MAV_FRAME_GLOBAL_INT, // targets are always global altitude
111  0xFFF8, // ignore everything except the x/y/z components
112  target.lat, // latitude as 1e7
113  target.lng, // longitude as 1e7
114  target.alt * 0.01f, // altitude is sent as a float
115  0.0f, // vx
116  0.0f, // vy
117  0.0f, // vz
118  0.0f, // afx
119  0.0f, // afy
120  0.0f, // afz
121  0.0f, // yaw
122  0.0f); // yaw_rate
123 }
124 
125 #if AC_FENCE == ENABLED
126 NOINLINE void Copter::send_fence_status(mavlink_channel_t chan)
127 {
129 }
130 #endif
131 
132 
133 NOINLINE void Copter::send_extended_status1(mavlink_channel_t chan)
134 {
135  int16_t battery_current = -1;
136  int8_t battery_remaining = -1;
137 
138  if (battery.has_current() && battery.healthy()) {
139  battery_remaining = battery.capacity_remaining_pct();
140  battery_current = battery.current_amps() * 100;
141  }
142 
144 
145  mavlink_msg_sys_status_send(
146  chan,
150  (uint16_t)(scheduler.load_average() * 1000),
151  battery.voltage() * 1000, // mV
152  battery_current, // in 10mA units
153  battery_remaining, // in %
154  0, // comm drops %,
155  0, // comm drops in pkts,
156  0, 0, 0, 0);
157 }
158 
159 void NOINLINE Copter::send_nav_controller_output(mavlink_channel_t chan)
160 {
161  const Vector3f &targets = attitude_control->get_att_target_euler_cd();
162  mavlink_msg_nav_controller_output_send(
163  chan,
164  targets.x * 1.0e-2f,
165  targets.y * 1.0e-2f,
166  targets.z * 1.0e-2f,
167  flightmode->wp_bearing() * 1.0e-2f,
168  MIN(flightmode->wp_distance() * 1.0e-2f, UINT16_MAX),
169  pos_control->get_alt_error() * 1.0e-2f,
170  0,
171  0);
172 }
173 
175 {
176  return (int16_t)(copter.motors->get_throttle() * 100);
177 }
178 
179 /*
180  send RPM packet
181  */
182 void NOINLINE Copter::send_rpm(mavlink_channel_t chan)
183 {
184 #if RPM_ENABLED == ENABLED
185  if (rpm_sensor.enabled(0) || rpm_sensor.enabled(1)) {
186  mavlink_msg_rpm_send(
187  chan,
188  rpm_sensor.get_rpm(0),
189  rpm_sensor.get_rpm(1));
190  }
191 #endif
192 }
193 
194 
195 /*
196  send PID tuning message
197  */
198 void Copter::send_pid_tuning(mavlink_channel_t chan)
199 {
200  const Vector3f &gyro = ahrs.get_gyro();
201  if (g.gcs_pid_mask & 1) {
202  const DataFlash_Class::PID_Info &pid_info = attitude_control->get_rate_roll_pid().get_pid_info();
203  mavlink_msg_pid_tuning_send(chan, PID_TUNING_ROLL,
204  pid_info.desired*0.01f,
205  degrees(gyro.x),
206  pid_info.FF*0.01f,
207  pid_info.P*0.01f,
208  pid_info.I*0.01f,
209  pid_info.D*0.01f);
210  if (!HAVE_PAYLOAD_SPACE(chan, PID_TUNING)) {
211  return;
212  }
213  }
214  if (g.gcs_pid_mask & 2) {
215  const DataFlash_Class::PID_Info &pid_info = attitude_control->get_rate_pitch_pid().get_pid_info();
216  mavlink_msg_pid_tuning_send(chan, PID_TUNING_PITCH,
217  pid_info.desired*0.01f,
218  degrees(gyro.y),
219  pid_info.FF*0.01f,
220  pid_info.P*0.01f,
221  pid_info.I*0.01f,
222  pid_info.D*0.01f);
223  if (!HAVE_PAYLOAD_SPACE(chan, PID_TUNING)) {
224  return;
225  }
226  }
227  if (g.gcs_pid_mask & 4) {
228  const DataFlash_Class::PID_Info &pid_info = attitude_control->get_rate_yaw_pid().get_pid_info();
229  mavlink_msg_pid_tuning_send(chan, PID_TUNING_YAW,
230  pid_info.desired*0.01f,
231  degrees(gyro.z),
232  pid_info.FF*0.01f,
233  pid_info.P*0.01f,
234  pid_info.I*0.01f,
235  pid_info.D*0.01f);
236  if (!HAVE_PAYLOAD_SPACE(chan, PID_TUNING)) {
237  return;
238  }
239  }
240  if (g.gcs_pid_mask & 8) {
241  const DataFlash_Class::PID_Info &pid_info = copter.pos_control->get_accel_z_pid().get_pid_info();
242  mavlink_msg_pid_tuning_send(chan, PID_TUNING_ACCZ,
243  pid_info.desired*0.01f,
245  pid_info.FF*0.01f,
246  pid_info.P*0.01f,
247  pid_info.I*0.01f,
248  pid_info.D*0.01f);
249  if (!HAVE_PAYLOAD_SPACE(chan, PID_TUNING)) {
250  return;
251  }
252  }
253 }
254 
256 {
257  return copter.g.sysid_my_gcs;
258 }
259 
261 {
262  return (uint32_t)(copter.g.telem_delay);
263 }
264 
265 // try to send a message, return false if it wasn't sent
267 {
268  if (telemetry_delayed()) {
269  return false;
270  }
271 
272 #if HIL_MODE != HIL_MODE_SENSORS
273  // if we don't have at least 250 micros remaining before the main loop
274  // wants to fire then don't send a mavlink message. We want to
275  // prioritise the main flight control loop over communications
276 
277  // the check for nullptr here doesn't just save a nullptr
278  // dereference; it means that we send messages out even if we're
279  // failing to detect a PX4 board type (see delay(3000) in px_drivers).
280  if (copter.motors != nullptr && copter.scheduler.time_available_usec() < 250 && copter.motors->armed()) {
281  gcs().set_out_of_time(true);
282  return false;
283  }
284 #endif
285 
286  switch(id) {
287 
289  // send extended status only once vehicle has been initialised
290  // to avoid unnecessary errors being reported to user
291  if (copter.ap.initialised) {
292  CHECK_PAYLOAD_SIZE(SYS_STATUS);
293  copter.send_extended_status1(chan);
294  CHECK_PAYLOAD_SIZE(POWER_STATUS);
295  send_power_status();
296  }
297  break;
298 
300  CHECK_PAYLOAD_SIZE(NAV_CONTROLLER_OUTPUT);
301  copter.send_nav_controller_output(chan);
302  break;
303 
304  case MSG_RPM:
305 #if RPM_ENABLED == ENABLED
306  CHECK_PAYLOAD_SIZE(RPM);
307  copter.send_rpm(chan);
308 #endif
309  break;
310 
311  case MSG_TERRAIN:
312 #if AP_TERRAIN_AVAILABLE && AC_TERRAIN
313  CHECK_PAYLOAD_SIZE(TERRAIN_REQUEST);
314  copter.terrain.send_request(chan);
315 #endif
316  break;
317 
318  case MSG_FENCE_STATUS:
319 #if AC_FENCE == ENABLED
320  CHECK_PAYLOAD_SIZE(FENCE_STATUS);
321  copter.send_fence_status(chan);
322 #endif
323  break;
324 
325  case MSG_MOUNT_STATUS:
326 #if MOUNT == ENABLED
327  CHECK_PAYLOAD_SIZE(MOUNT_STATUS);
328  copter.camera_mount.status_msg(chan);
329 #endif // MOUNT == ENABLED
330  break;
331 
332  case MSG_OPTICAL_FLOW:
333 #if OPTFLOW == ENABLED
334  CHECK_PAYLOAD_SIZE(OPTICAL_FLOW);
335  send_opticalflow(copter.optflow);
336 #endif
337  break;
338 
339  case MSG_GIMBAL_REPORT:
340 #if MOUNT == ENABLED
341  CHECK_PAYLOAD_SIZE(GIMBAL_REPORT);
342  copter.camera_mount.send_gimbal_report(chan);
343 #endif
344  break;
345 
347  CHECK_PAYLOAD_SIZE(EKF_STATUS_REPORT);
348  copter.ahrs.send_ekf_status_report(chan);
349  break;
350 
351  case MSG_WIND:
352  case MSG_SERVO_OUT:
353  case MSG_AOA_SSA:
354  case MSG_LANDING:
355  // unused
356  break;
357 
358  case MSG_PID_TUNING:
359  CHECK_PAYLOAD_SIZE(PID_TUNING);
360  copter.send_pid_tuning(chan);
361  break;
362 
363  case MSG_ADSB_VEHICLE:
364 #if ADSB_ENABLED == ENABLED
365  CHECK_PAYLOAD_SIZE(ADSB_VEHICLE);
366  copter.adsb.send_adsb_vehicle(chan);
367 #endif
368  break;
369 
370  default:
372  }
373  return true;
374 }
375 
376 
378  // @Param: RAW_SENS
379  // @DisplayName: Raw sensor stream rate
380  // @Description: Stream rate of RAW_IMU, SCALED_IMU2, SCALED_IMU3, SCALED_PRESSURE, SCALED_PRESSURE2, SCALED_PRESSURE3 and SENSOR_OFFSETS to ground station
381  // @Units: Hz
382  // @Range: 0 10
383  // @Increment: 1
384  // @User: Advanced
385  AP_GROUPINFO("RAW_SENS", 0, GCS_MAVLINK, streamRates[0], 0),
386 
387  // @Param: EXT_STAT
388  // @DisplayName: Extended status stream rate to ground station
389  // @Description: Stream rate of SYS_STATUS, POWER_STATUS, MEMINFO, CURRENT_WAYPOINT, GPS_RAW_INT, GPS_RTK (if available), GPS2_RAW (if available), GPS2_RTK (if available), NAV_CONTROLLER_OUTPUT, and FENCE_STATUS to ground station
390  // @Units: Hz
391  // @Range: 0 10
392  // @Increment: 1
393  // @User: Advanced
394  AP_GROUPINFO("EXT_STAT", 1, GCS_MAVLINK, streamRates[1], 0),
395 
396  // @Param: RC_CHAN
397  // @DisplayName: RC Channel stream rate to ground station
398  // @Description: Stream rate of SERVO_OUTPUT_RAW and RC_CHANNELS to ground station
399  // @Units: Hz
400  // @Range: 0 10
401  // @Increment: 1
402  // @User: Advanced
403  AP_GROUPINFO("RC_CHAN", 2, GCS_MAVLINK, streamRates[2], 0),
404 
405  // @Param: RAW_CTRL
406  // @DisplayName: Raw Control stream rate to ground station
407  // @Description: Stream rate of RC_CHANNELS_SCALED (HIL only) to ground station
408  // @Units: Hz
409  // @Range: 0 10
410  // @Increment: 1
411  // @User: Advanced
412  AP_GROUPINFO("RAW_CTRL", 3, GCS_MAVLINK, streamRates[3], 0),
413 
414  // @Param: POSITION
415  // @DisplayName: Position stream rate to ground station
416  // @Description: Stream rate of GLOBAL_POSITION_INT and LOCAL_POSITION_NED to ground station
417  // @Units: Hz
418  // @Range: 0 10
419  // @Increment: 1
420  // @User: Advanced
421  AP_GROUPINFO("POSITION", 4, GCS_MAVLINK, streamRates[4], 0),
422 
423  // @Param: EXTRA1
424  // @DisplayName: Extra data type 1 stream rate to ground station
425  // @Description: Stream rate of ATTITUDE, SIMSTATE (SITL only), AHRS2 and PID_TUNING to ground station
426  // @Units: Hz
427  // @Range: 0 10
428  // @Increment: 1
429  // @User: Advanced
430  AP_GROUPINFO("EXTRA1", 5, GCS_MAVLINK, streamRates[5], 0),
431 
432  // @Param: EXTRA2
433  // @DisplayName: Extra data type 2 stream rate to ground station
434  // @Description: Stream rate of VFR_HUD to ground station
435  // @Units: Hz
436  // @Range: 0 10
437  // @Increment: 1
438  // @User: Advanced
439  AP_GROUPINFO("EXTRA2", 6, GCS_MAVLINK, streamRates[6], 0),
440 
441  // @Param: EXTRA3
442  // @DisplayName: Extra data type 3 stream rate to ground station
443  // @Description: Stream rate of AHRS, HWSTATUS, SYSTEM_TIME, RANGEFINDER, DISTANCE_SENSOR, TERRAIN_REQUEST, BATTERY2, MOUNT_STATUS, OPTICAL_FLOW, GIMBAL_REPORT, MAG_CAL_REPORT, MAG_CAL_PROGRESS, EKF_STATUS_REPORT, VIBRATION and RPM to ground station
444  // @Units: Hz
445  // @Range: 0 10
446  // @Increment: 1
447  // @User: Advanced
448  AP_GROUPINFO("EXTRA3", 7, GCS_MAVLINK, streamRates[7], 0),
449 
450  // @Param: PARAMS
451  // @DisplayName: Parameter stream rate to ground station
452  // @Description: Stream rate of PARAM_VALUE to ground station
453  // @Units: Hz
454  // @Range: 0 10
455  // @Increment: 1
456  // @User: Advanced
457  AP_GROUPINFO("PARAMS", 8, GCS_MAVLINK, streamRates[8], 0),
458 
459  // @Param: ADSB
460  // @DisplayName: ADSB stream rate to ground station
461  // @Description: ADSB stream rate to ground station
462  // @Units: Hz
463  // @Range: 0 50
464  // @Increment: 1
465  // @User: Advanced
466  AP_GROUPINFO("ADSB", 9, GCS_MAVLINK, streamRates[9], 5),
468 };
469 
471  MSG_RAW_IMU1, // RAW_IMU, SCALED_IMU2, SCALED_IMU3
472  MSG_RAW_IMU2, // SCALED_PRESSURE, SCALED_PRESSURE2, SCALED_PRESSURE3
473  MSG_RAW_IMU3 // SENSOR_OFFSETS
474 };
476  MSG_EXTENDED_STATUS1, // SYS_STATUS, POWER_STATUS
477  MSG_EXTENDED_STATUS2, // MEMINFO
478  MSG_CURRENT_WAYPOINT, // MISSION_CURRENT
479  MSG_GPS_RAW,
480  MSG_GPS_RTK,
481  MSG_GPS2_RAW,
482  MSG_GPS2_RTK,
486 };
488  MSG_LOCATION,
490 };
492 };
495  MSG_RADIO_IN // RC_CHANNELS_RAW, RC_CHANNELS
496 };
497 static const ap_message STREAM_EXTRA1_msgs[] = {
498  MSG_ATTITUDE,
499  MSG_SIMSTATE, // SIMSTATE, AHRS2
500  MSG_PID_TUNING // Up to four PID_TUNING messages are sent, depending on GCS_PID_MASK parameter
501 };
502 static const ap_message STREAM_EXTRA2_msgs[] = {
504 };
505 static const ap_message STREAM_EXTRA3_msgs[] = {
506  MSG_AHRS,
507  MSG_HWSTATUS,
510 #if AP_TERRAIN_AVAILABLE && AC_TERRAIN
511  MSG_TERRAIN,
512 #endif
513  MSG_BATTERY2,
522  MSG_RPM
523 };
524 static const ap_message STREAM_ADSB_msgs[] = {
526 };
527 
528 const struct GCS_MAVLINK::stream_entries GCS_MAVLINK::all_stream_entries[] = {
529  MAV_STREAM_ENTRY(STREAM_RAW_SENSORS),
530  MAV_STREAM_ENTRY(STREAM_EXTENDED_STATUS),
531  MAV_STREAM_ENTRY(STREAM_POSITION),
532 // MAV_STREAM_ENTRY(STREAM_RAW_CONTROLLER),
533  MAV_STREAM_ENTRY(STREAM_RC_CHANNELS),
534  MAV_STREAM_ENTRY(STREAM_EXTRA1),
535  MAV_STREAM_ENTRY(STREAM_EXTRA2),
536  MAV_STREAM_ENTRY(STREAM_EXTRA3),
537  MAV_STREAM_ENTRY(STREAM_ADSB),
538  MAV_STREAM_TERMINATOR // must have this at end of stream_entries
539 };
540 
542 {
543 #if MODE_AUTO_ENABLED == ENABLED
544  return copter.mode_auto.do_guided(cmd);
545 #else
546  return false;
547 #endif
548 }
549 
551 {
552  // add home alt if needed
554  cmd.content.location.alt += copter.ahrs.get_home().alt;
555  }
556 
557  // To-Do: update target altitude for loiter or waypoint controller depending upon nav mode
558 }
559 
560 void GCS_MAVLINK_Copter::packetReceived(const mavlink_status_t &status,
561  mavlink_message_t &msg)
562 {
563 #if ADSB_ENABLED == ENABLED
564  if (copter.g2.dev_options.get() & DevOptionADSBMAVLink) {
565  // optional handling of GLOBAL_POSITION_INT as a MAVLink based avoidance source
566  copter.avoidance_adsb.handle_msg(msg);
567  }
568 #endif
569 #if MODE_FOLLOW_ENABLED == ENABLED
570  // pass message to follow library
571  copter.g2.follow.handle_msg(msg);
572 #endif
573  GCS_MAVLINK::packetReceived(status, msg);
574 }
575 
577 {
579  // we may never have parameters "initialised" in this case
580  return true;
581  }
582  // if we have not yet initialised (including allocating the motors
583  // object) we drop this request. That prevents the GCS from getting
584  // a confusing parameter count during bootup
585  return copter.ap.initialised_params;
586 }
587 
589 {
591  send_text(MAV_SEVERITY_INFO, "Frame: %s", copter.get_frame_string());
592 }
593 
594 
595 void GCS_MAVLINK_Copter::handle_command_ack(const mavlink_message_t* msg)
596 {
597  copter.command_ack_counter++;
599 }
600 
601 MAV_RESULT GCS_MAVLINK_Copter::_handle_command_preflight_calibration(const mavlink_command_long_t &packet)
602 {
603  if (is_equal(packet.param6,1.0f)) {
604  // compassmot calibration
605  return copter.mavlink_compassmot(chan);
606  }
607 
609 }
610 
611 void GCS_MAVLINK_Copter::handleMessage(mavlink_message_t* msg)
612 {
613  MAV_RESULT result = MAV_RESULT_FAILED; // assume failure. Each messages id is responsible for return ACK or NAK if required
614 
615  switch (msg->msgid) {
616 
617  case MAVLINK_MSG_ID_HEARTBEAT: // MAV ID: 0
618  {
619  // We keep track of the last time we received a heartbeat from our GCS for failsafe purposes
620  if(msg->sysid != copter.g.sysid_my_gcs) break;
621  copter.failsafe.last_heartbeat_ms = AP_HAL::millis();
622  break;
623  }
624 
625  case MAVLINK_MSG_ID_PARAM_VALUE:
626  {
627 #if MOUNT == ENABLED
628  copter.camera_mount.handle_param_value(msg);
629 #endif
630  break;
631  }
632 
633  case MAVLINK_MSG_ID_GIMBAL_REPORT:
634  {
635 #if MOUNT == ENABLED
636  handle_gimbal_report(copter.camera_mount, msg);
637 #endif
638  break;
639  }
640 
641  case MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE: // MAV ID: 70
642  {
643  // allow override of RC channel values for HIL
644  // or for complete GCS control of switch position
645  // and RC PWM values.
646  if(msg->sysid != copter.g.sysid_my_gcs) break; // Only accept control from our gcs
647  if (!copter.ap.rc_override_enable) {
648  if (copter.failsafe.rc_override_active) { // if overrides were active previously, disable them
649  copter.failsafe.rc_override_active = false;
651  }
652  break;
653  }
654  mavlink_rc_channels_override_t packet;
655  bool override_active = false;
656  mavlink_msg_rc_channels_override_decode(msg, &packet);
657 
658  override_active |= RC_Channels::set_override(0, packet.chan1_raw);
659  override_active |= RC_Channels::set_override(1, packet.chan2_raw);
660  override_active |= RC_Channels::set_override(2, packet.chan3_raw);
661  override_active |= RC_Channels::set_override(3, packet.chan4_raw);
662  override_active |= RC_Channels::set_override(4, packet.chan5_raw);
663  override_active |= RC_Channels::set_override(5, packet.chan6_raw);
664  override_active |= RC_Channels::set_override(6, packet.chan7_raw);
665  override_active |= RC_Channels::set_override(7, packet.chan8_raw);
666 
667  // record that rc are overwritten so we can trigger a failsafe if we lose contact with groundstation
668  copter.failsafe.rc_override_active = override_active;
669 
670  // a RC override message is considered to be a 'heartbeat' from the ground station for failsafe purposes
671  copter.failsafe.last_heartbeat_ms = AP_HAL::millis();
672  break;
673  }
674 
675  case MAVLINK_MSG_ID_MANUAL_CONTROL:
676  {
677  if (msg->sysid != copter.g.sysid_my_gcs) {
678  break; // only accept control from our gcs
679  }
680 
681  mavlink_manual_control_t packet;
682  mavlink_msg_manual_control_decode(msg, &packet);
683 
684  if (packet.target != copter.g.sysid_this_mav) {
685  break; // only accept control aimed at us
686  }
687 
688  if (packet.z < 0) { // Copter doesn't do negative thrust
689  break;
690  }
691 
692  bool override_active = false;
693  int16_t roll = (packet.y == INT16_MAX) ? 0 : copter.channel_roll->get_radio_min() + (copter.channel_roll->get_radio_max() - copter.channel_roll->get_radio_min()) * (packet.y + 1000) / 2000.0f;
694  int16_t pitch = (packet.x == INT16_MAX) ? 0 : copter.channel_pitch->get_radio_min() + (copter.channel_pitch->get_radio_max() - copter.channel_pitch->get_radio_min()) * (-packet.x + 1000) / 2000.0f;
695  int16_t throttle = (packet.z == INT16_MAX) ? 0 : copter.channel_throttle->get_radio_min() + (copter.channel_throttle->get_radio_max() - copter.channel_throttle->get_radio_min()) * (packet.z) / 1000.0f;
696  int16_t yaw = (packet.r == INT16_MAX) ? 0 : copter.channel_yaw->get_radio_min() + (copter.channel_yaw->get_radio_max() - copter.channel_yaw->get_radio_min()) * (packet.r + 1000) / 2000.0f;
697 
698  override_active |= RC_Channels::set_override(uint8_t(copter.rcmap.roll() - 1), roll);
699  override_active |= RC_Channels::set_override(uint8_t(copter.rcmap.pitch() - 1), pitch);
700  override_active |= RC_Channels::set_override(uint8_t(copter.rcmap.throttle() - 1), throttle);
701  override_active |= RC_Channels::set_override(uint8_t(copter.rcmap.yaw() - 1), yaw);
702 
703  // record that rc are overwritten so we can trigger a failsafe if we lose contact with groundstation
704  copter.failsafe.rc_override_active = override_active;
705 
706  // a manual control message is considered to be a 'heartbeat' from the ground station for failsafe purposes
707  copter.failsafe.last_heartbeat_ms = AP_HAL::millis();
708  break;
709  }
710 
711  case MAVLINK_MSG_ID_COMMAND_INT:
712  {
713  // decode packet
714  mavlink_command_int_t packet;
715  mavlink_msg_command_int_decode(msg, &packet);
716  switch(packet.command)
717  {
718  case MAV_CMD_DO_FOLLOW:
719 #if MODE_FOLLOW_ENABLED == ENABLED
720  // param1: sysid of target to follow
721  if ((packet.param1 > 0) && (packet.param1 <= 255)) {
722  copter.g2.follow.set_target_sysid((uint8_t)packet.param1);
723  result = MAV_RESULT_ACCEPTED;
724  }
725 #endif
726  break;
727 
728  case MAV_CMD_DO_SET_HOME: {
729  // assume failure
730  result = MAV_RESULT_FAILED;
731  if (is_equal(packet.param1, 1.0f)) {
732  // if param1 is 1, use current location
733  if (copter.set_home_to_current_location(true)) {
734  result = MAV_RESULT_ACCEPTED;
735  }
736  break;
737  }
738  // ensure param1 is zero
739  if (!is_zero(packet.param1)) {
740  break;
741  }
742  // check frame type is supported
743  if (packet.frame != MAV_FRAME_GLOBAL &&
744  packet.frame != MAV_FRAME_GLOBAL_INT &&
745  packet.frame != MAV_FRAME_GLOBAL_RELATIVE_ALT &&
746  packet.frame != MAV_FRAME_GLOBAL_RELATIVE_ALT_INT) {
747  break;
748  }
749  // sanity check location
750  if (!check_latlng(packet.x, packet.y)) {
751  break;
752  }
753  Location new_home_loc {};
754  new_home_loc.lat = packet.x;
755  new_home_loc.lng = packet.y;
756  new_home_loc.alt = packet.z * 100;
757  // handle relative altitude
758  if (packet.frame == MAV_FRAME_GLOBAL_RELATIVE_ALT || packet.frame == MAV_FRAME_GLOBAL_RELATIVE_ALT_INT) {
759  if (!AP::ahrs().home_is_set()) {
760  // cannot use relative altitude if home is not set
761  break;
762  }
763  new_home_loc.alt += copter.ahrs.get_home().alt;
764  }
765  if (copter.set_home(new_home_loc, true)) {
766  result = MAV_RESULT_ACCEPTED;
767  }
768  break;
769  }
770 
771  case MAV_CMD_DO_SET_ROI: {
772  // param1 : /* Region of interest mode (not used)*/
773  // param2 : /* MISSION index/ target ID (not used)*/
774  // param3 : /* ROI index (not used)*/
775  // param4 : /* empty */
776  // x : lat
777  // y : lon
778  // z : alt
779  // sanity check location
780  if (!check_latlng(packet.x, packet.y)) {
781  break;
782  }
783  Location roi_loc;
784  roi_loc.lat = packet.x;
785  roi_loc.lng = packet.y;
786  roi_loc.alt = (int32_t)(packet.z * 100.0f);
787  copter.flightmode->auto_yaw.set_roi(roi_loc);
788  result = MAV_RESULT_ACCEPTED;
789  break;
790  }
791 
792  default:
793  result = MAV_RESULT_UNSUPPORTED;
794  break;
795  }
796 
797  // send ACK or NAK
798  mavlink_msg_command_ack_send_buf(msg, chan, packet.command, result);
799  break;
800  }
801 
802  // Pre-Flight calibration requests
803  case MAVLINK_MSG_ID_COMMAND_LONG: // MAV ID: 76
804  {
805  // decode packet
806  mavlink_command_long_t packet;
807  mavlink_msg_command_long_decode(msg, &packet);
808 
809  switch(packet.command) {
810 
811  case MAV_CMD_NAV_TAKEOFF: {
812  // param3 : horizontal navigation by pilot acceptable
813  // param4 : yaw angle (not supported)
814  // param5 : latitude (not supported)
815  // param6 : longitude (not supported)
816  // param7 : altitude [metres]
817 
818  float takeoff_alt = packet.param7 * 100; // Convert m to cm
819 
820  if(copter.do_user_takeoff(takeoff_alt, is_zero(packet.param3))) {
821  result = MAV_RESULT_ACCEPTED;
822  } else {
823  result = MAV_RESULT_FAILED;
824  }
825  break;
826  }
827 
828 
829  case MAV_CMD_NAV_LOITER_UNLIM:
830  if (copter.set_mode(LOITER, MODE_REASON_GCS_COMMAND)) {
831  result = MAV_RESULT_ACCEPTED;
832  }
833  break;
834 
835  case MAV_CMD_NAV_RETURN_TO_LAUNCH:
836  if (copter.set_mode(RTL, MODE_REASON_GCS_COMMAND)) {
837  result = MAV_RESULT_ACCEPTED;
838  }
839  break;
840 
841  case MAV_CMD_NAV_LAND:
842  if (copter.set_mode(LAND, MODE_REASON_GCS_COMMAND)) {
843  result = MAV_RESULT_ACCEPTED;
844  }
845  break;
846 
847  case MAV_CMD_DO_FOLLOW:
848 #if MODE_FOLLOW_ENABLED == ENABLED
849  // param1: sysid of target to follow
850  if ((packet.param1 > 0) && (packet.param1 <= 255)) {
851  copter.g2.follow.set_target_sysid((uint8_t)packet.param1);
852  result = MAV_RESULT_ACCEPTED;
853  }
854 #endif
855  break;
856 
857  case MAV_CMD_CONDITION_YAW:
858  // param1 : target angle [0-360]
859  // param2 : speed during change [deg per second]
860  // param3 : direction (-1:ccw, +1:cw)
861  // param4 : relative offset (1) or absolute angle (0)
862  if ((packet.param1 >= 0.0f) &&
863  (packet.param1 <= 360.0f) &&
864  (is_zero(packet.param4) || is_equal(packet.param4,1.0f))) {
865  copter.flightmode->auto_yaw.set_fixed_yaw(
866  packet.param1,
867  packet.param2,
868  (int8_t)packet.param3,
869  is_positive(packet.param4));
870  result = MAV_RESULT_ACCEPTED;
871  } else {
872  result = MAV_RESULT_FAILED;
873  }
874  break;
875 
876  case MAV_CMD_DO_CHANGE_SPEED:
877  // param1 : unused
878  // param2 : new speed in m/s
879  // param3 : unused
880  // param4 : unused
881  if (packet.param2 > 0.0f) {
882  copter.wp_nav->set_speed_xy(packet.param2 * 100.0f);
883  result = MAV_RESULT_ACCEPTED;
884  } else {
885  result = MAV_RESULT_FAILED;
886  }
887  break;
888 
889  case MAV_CMD_DO_SET_HOME:
890  // param1 : use current (1=use current location, 0=use specified location)
891  // param5 : latitude
892  // param6 : longitude
893  // param7 : altitude (absolute)
894  result = MAV_RESULT_FAILED; // assume failure
895  if (is_equal(packet.param1,1.0f)) {
896  if (copter.set_home_to_current_location(true)) {
897  result = MAV_RESULT_ACCEPTED;
898  }
899  } else {
900  // ensure param1 is zero
901  if (!is_zero(packet.param1)) {
902  break;
903  }
904  // sanity check location
905  if (!check_latlng(packet.param5, packet.param6)) {
906  break;
907  }
908  Location new_home_loc;
909  new_home_loc.lat = (int32_t)(packet.param5 * 1.0e7f);
910  new_home_loc.lng = (int32_t)(packet.param6 * 1.0e7f);
911  new_home_loc.alt = (int32_t)(packet.param7 * 100.0f);
912  if (copter.set_home(new_home_loc, true)) {
913  result = MAV_RESULT_ACCEPTED;
914  }
915  }
916  break;
917 
918  case MAV_CMD_DO_SET_ROI:
919  // param1 : regional of interest mode (not supported)
920  // param2 : mission index/ target id (not supported)
921  // param3 : ROI index (not supported)
922  // param5 : x / lat
923  // param6 : y / lon
924  // param7 : z / alt
925  // sanity check location
926  if (!check_latlng(packet.param5, packet.param6)) {
927  break;
928  }
929  Location roi_loc;
930  roi_loc.lat = (int32_t)(packet.param5 * 1.0e7f);
931  roi_loc.lng = (int32_t)(packet.param6 * 1.0e7f);
932  roi_loc.alt = (int32_t)(packet.param7 * 100.0f);
933  copter.flightmode->auto_yaw.set_roi(roi_loc);
934  result = MAV_RESULT_ACCEPTED;
935  break;
936 
937  case MAV_CMD_DO_MOUNT_CONTROL:
938 #if MOUNT == ENABLED
939  if(!copter.camera_mount.has_pan_control()) {
940  copter.flightmode->auto_yaw.set_fixed_yaw(
941  (float)packet.param3 / 100.0f,
942  0.0f,
943  0,0);
944  }
945  copter.camera_mount.control(packet.param1, packet.param2, packet.param3, (MAV_MOUNT_MODE) packet.param7);
946  result = MAV_RESULT_ACCEPTED;
947 #endif
948  break;
949 
950 #if MODE_AUTO_ENABLED == ENABLED
951  case MAV_CMD_MISSION_START:
952  if (copter.motors->armed() && copter.set_mode(AUTO, MODE_REASON_GCS_COMMAND)) {
953  copter.set_auto_armed(true);
954  if (copter.mission.state() != AP_Mission::MISSION_RUNNING) {
955  copter.mission.start_or_resume();
956  }
957  result = MAV_RESULT_ACCEPTED;
958  }
959  break;
960 #endif
961 
962  case MAV_CMD_COMPONENT_ARM_DISARM:
963  if (is_equal(packet.param1,1.0f)) {
964  // attempt to arm and return success or failure
965  if (copter.init_arm_motors(true)) {
966  result = MAV_RESULT_ACCEPTED;
967  }
968  } else if (is_zero(packet.param1) && (copter.ap.land_complete || is_equal(packet.param2,21196.0f))) {
969  // force disarming by setting param2 = 21196 is deprecated
970  copter.init_disarm_motors();
971  result = MAV_RESULT_ACCEPTED;
972  } else {
973  result = MAV_RESULT_UNSUPPORTED;
974  }
975  break;
976 
977  case MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN:
978  if (is_equal(packet.param1,1.0f) || is_equal(packet.param1,3.0f)) {
980  copter.notify.update();
981  hal.scheduler->delay(200);
982  // when packet.param1 == 3 we reboot to hold in bootloader
983  hal.scheduler->reboot(is_equal(packet.param1,3.0f));
984  result = MAV_RESULT_ACCEPTED;
985  }
986  break;
987 
988  case MAV_CMD_DO_FENCE_ENABLE:
989 #if AC_FENCE == ENABLED
990  result = MAV_RESULT_ACCEPTED;
991  switch ((uint16_t)packet.param1) {
992  case 0:
993  copter.fence.enable(false);
994  break;
995  case 1:
996  copter.fence.enable(true);
997  break;
998  default:
999  result = MAV_RESULT_FAILED;
1000  break;
1001  }
1002 #else
1003  // if fence code is not included return failure
1004  result = MAV_RESULT_FAILED;
1005 #endif
1006  break;
1007 
1008 #if PARACHUTE == ENABLED
1009  case MAV_CMD_DO_PARACHUTE:
1010  // configure or release parachute
1011  result = MAV_RESULT_ACCEPTED;
1012  switch ((uint16_t)packet.param1) {
1013  case PARACHUTE_DISABLE:
1014  copter.parachute.enabled(false);
1015  copter.Log_Write_Event(DATA_PARACHUTE_DISABLED);
1016  break;
1017  case PARACHUTE_ENABLE:
1018  copter.parachute.enabled(true);
1019  copter.Log_Write_Event(DATA_PARACHUTE_ENABLED);
1020  break;
1021  case PARACHUTE_RELEASE:
1022  // treat as a manual release which performs some additional check of altitude
1023  copter.parachute_manual_release();
1024  break;
1025  default:
1026  result = MAV_RESULT_FAILED;
1027  break;
1028  }
1029  break;
1030 #endif
1031 
1032  case MAV_CMD_DO_MOTOR_TEST:
1033  // param1 : motor sequence number (a number from 1 to max number of motors on the vehicle)
1034  // param2 : throttle type (0=throttle percentage, 1=PWM, 2=pilot throttle channel pass-through. See MOTOR_TEST_THROTTLE_TYPE enum)
1035  // param3 : throttle (range depends upon param2)
1036  // param4 : timeout (in seconds)
1037  // param5 : num_motors (in sequence)
1038  // param6 : compass learning (0: disabled, 1: enabled)
1039  result = copter.mavlink_motor_test_start(chan, (uint8_t)packet.param1, (uint8_t)packet.param2, (uint16_t)packet.param3,
1040  packet.param4, (uint8_t)packet.param5);
1041  break;
1042 
1043 #if GRIPPER_ENABLED == ENABLED
1044  case MAV_CMD_DO_GRIPPER:
1045  // param1 : gripper number (ignored)
1046  // param2 : action (0=release, 1=grab). See GRIPPER_ACTIONS enum.
1047  if(!copter.g2.gripper.enabled()) {
1048  result = MAV_RESULT_FAILED;
1049  } else {
1050  result = MAV_RESULT_ACCEPTED;
1051  switch ((uint8_t)packet.param2) {
1052  case GRIPPER_ACTION_RELEASE:
1053  copter.g2.gripper.release();
1054  break;
1055  case GRIPPER_ACTION_GRAB:
1056  copter.g2.gripper.grab();
1057  break;
1058  default:
1059  result = MAV_RESULT_FAILED;
1060  break;
1061  }
1062  }
1063  break;
1064 #endif
1065 
1066 #if WINCH_ENABLED == ENABLED
1067  case MAV_CMD_DO_WINCH:
1068  // param1 : winch number (ignored)
1069  // param2 : action (0=relax, 1=relative length control, 2=rate control). See WINCH_ACTIONS enum.
1070  if (!copter.g2.winch.enabled()) {
1071  result = MAV_RESULT_FAILED;
1072  } else {
1073  result = MAV_RESULT_ACCEPTED;
1074  switch ((uint8_t)packet.param2) {
1075  case WINCH_RELAXED:
1076  copter.g2.winch.relax();
1077  copter.Log_Write_Event(DATA_WINCH_RELAXED);
1078  break;
1079  case WINCH_RELATIVE_LENGTH_CONTROL: {
1080  copter.g2.winch.release_length(packet.param3, fabsf(packet.param4));
1081  copter.Log_Write_Event(DATA_WINCH_LENGTH_CONTROL);
1082  break;
1083  }
1084  case WINCH_RATE_CONTROL: {
1085  if (fabsf(packet.param4) <= copter.g2.winch.get_rate_max()) {
1086  copter.g2.winch.set_desired_rate(packet.param4);
1087  copter.Log_Write_Event(DATA_WINCH_RATE_CONTROL);
1088  } else {
1089  result = MAV_RESULT_FAILED;
1090  }
1091  break;
1092  }
1093  default:
1094  result = MAV_RESULT_FAILED;
1095  break;
1096  }
1097  }
1098  break;
1099 #endif
1100 
1101  /* Solo user presses Fly button */
1102  case MAV_CMD_SOLO_BTN_FLY_CLICK: {
1103  result = MAV_RESULT_ACCEPTED;
1104 
1105  if (copter.failsafe.radio) {
1106  break;
1107  }
1108 
1109  // set mode to Loiter or fall back to AltHold
1110  if (!copter.set_mode(LOITER, MODE_REASON_GCS_COMMAND)) {
1112  }
1113  break;
1114  }
1115 
1116  /* Solo user holds down Fly button for a couple of seconds */
1117  case MAV_CMD_SOLO_BTN_FLY_HOLD: {
1118  result = MAV_RESULT_ACCEPTED;
1119 
1120  if (copter.failsafe.radio) {
1121  break;
1122  }
1123 
1124  if (!copter.motors->armed()) {
1125  // if disarmed, arm motors
1126  copter.init_arm_motors(true);
1127  } else if (copter.ap.land_complete) {
1128  // if armed and landed, takeoff
1129  if (copter.set_mode(LOITER, MODE_REASON_GCS_COMMAND)) {
1130  copter.do_user_takeoff(packet.param1*100, true);
1131  }
1132  } else {
1133  // if flying, land
1134  copter.set_mode(LAND, MODE_REASON_GCS_COMMAND);
1135  }
1136  break;
1137  }
1138 
1139  /* Solo user presses pause button */
1140  case MAV_CMD_SOLO_BTN_PAUSE_CLICK: {
1141  result = MAV_RESULT_ACCEPTED;
1142 
1143  if (copter.failsafe.radio) {
1144  break;
1145  }
1146 
1147  if (copter.motors->armed()) {
1148  if (copter.ap.land_complete) {
1149  // if landed, disarm motors
1150  copter.init_disarm_motors();
1151  } else {
1152  // assume that shots modes are all done in guided.
1153  // NOTE: this may need to change if we add a non-guided shot mode
1154  bool shot_mode = (!is_zero(packet.param1) && (copter.control_mode == GUIDED || copter.control_mode == GUIDED_NOGPS));
1155 
1156  if (!shot_mode) {
1157 #if MODE_BRAKE_ENABLED == ENABLED
1158  if (copter.set_mode(BRAKE, MODE_REASON_GCS_COMMAND)) {
1159  copter.mode_brake.timeout_to_loiter_ms(2500);
1160  } else {
1162  }
1163 #else
1165 #endif
1166  } else {
1167  // SoloLink is expected to handle pause in shots
1168  }
1169  }
1170  }
1171  break;
1172  }
1173 
1174  case MAV_CMD_ACCELCAL_VEHICLE_POS:
1175  result = MAV_RESULT_FAILED;
1176 
1177  if (copter.ins.get_acal()->gcs_vehicle_position(packet.param1)) {
1178  result = MAV_RESULT_ACCEPTED;
1179  }
1180  break;
1181 
1182  default:
1183  result = handle_command_long_message(packet);
1184  break;
1185  }
1186 
1187  // send ACK or NAK
1188  mavlink_msg_command_ack_send_buf(msg, chan, packet.command, result);
1189 
1190  break;
1191  }
1192 
1193 #if MODE_GUIDED_ENABLED == ENABLED
1194  case MAVLINK_MSG_ID_SET_ATTITUDE_TARGET: // MAV ID: 82
1195  {
1196  // decode packet
1197  mavlink_set_attitude_target_t packet;
1198  mavlink_msg_set_attitude_target_decode(msg, &packet);
1199 
1200  // exit if vehicle is not in Guided mode or Auto-Guided mode
1201  if (!copter.flightmode->in_guided_mode()) {
1202  break;
1203  }
1204 
1205  // ensure type_mask specifies to use attitude and thrust
1206  if ((packet.type_mask & ((1<<7)|(1<<6))) != 0) {
1207  break;
1208  }
1209 
1210  // convert thrust to climb rate
1211  packet.thrust = constrain_float(packet.thrust, 0.0f, 1.0f);
1212  float climb_rate_cms = 0.0f;
1213  if (is_equal(packet.thrust, 0.5f)) {
1214  climb_rate_cms = 0.0f;
1215  } else if (packet.thrust > 0.5f) {
1216  // climb at up to WPNAV_SPEED_UP
1217  climb_rate_cms = (packet.thrust - 0.5f) * 2.0f * copter.wp_nav->get_speed_up();
1218  } else {
1219  // descend at up to WPNAV_SPEED_DN
1220  climb_rate_cms = (0.5f - packet.thrust) * 2.0f * -fabsf(copter.wp_nav->get_speed_down());
1221  }
1222 
1223  // if the body_yaw_rate field is ignored, use the commanded yaw position
1224  // otherwise use the commanded yaw rate
1225  bool use_yaw_rate = false;
1226  if ((packet.type_mask & (1<<2)) == 0) {
1227  use_yaw_rate = true;
1228  }
1229 
1230  copter.mode_guided.set_angle(Quaternion(packet.q[0],packet.q[1],packet.q[2],packet.q[3]),
1231  climb_rate_cms, use_yaw_rate, packet.body_yaw_rate);
1232 
1233  break;
1234  }
1235 
1236  case MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED: // MAV ID: 84
1237  {
1238  // decode packet
1239  mavlink_set_position_target_local_ned_t packet;
1240  mavlink_msg_set_position_target_local_ned_decode(msg, &packet);
1241 
1242  // exit if vehicle is not in Guided mode or Auto-Guided mode
1243  if (!copter.flightmode->in_guided_mode()) {
1244  break;
1245  }
1246 
1247  // check for supported coordinate frames
1248  if (packet.coordinate_frame != MAV_FRAME_LOCAL_NED &&
1249  packet.coordinate_frame != MAV_FRAME_LOCAL_OFFSET_NED &&
1250  packet.coordinate_frame != MAV_FRAME_BODY_NED &&
1251  packet.coordinate_frame != MAV_FRAME_BODY_OFFSET_NED) {
1252  break;
1253  }
1254 
1255  bool pos_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_POS_IGNORE;
1256  bool vel_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_VEL_IGNORE;
1257  bool acc_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_ACC_IGNORE;
1258  bool yaw_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_IGNORE;
1259  bool yaw_rate_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_RATE_IGNORE;
1260 
1261  /*
1262  * for future use:
1263  * bool force = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_FORCE;
1264  */
1265 
1266  // prepare position
1267  Vector3f pos_vector;
1268  if (!pos_ignore) {
1269  // convert to cm
1270  pos_vector = Vector3f(packet.x * 100.0f, packet.y * 100.0f, -packet.z * 100.0f);
1271  // rotate to body-frame if necessary
1272  if (packet.coordinate_frame == MAV_FRAME_BODY_NED ||
1273  packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) {
1274  copter.rotate_body_frame_to_NE(pos_vector.x, pos_vector.y);
1275  }
1276  // add body offset if necessary
1277  if (packet.coordinate_frame == MAV_FRAME_LOCAL_OFFSET_NED ||
1278  packet.coordinate_frame == MAV_FRAME_BODY_NED ||
1279  packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) {
1280  pos_vector += copter.inertial_nav.get_position();
1281  } else {
1282  // convert from alt-above-home to alt-above-ekf-origin
1283  pos_vector.z = copter.pv_alt_above_origin(pos_vector.z);
1284  }
1285  }
1286 
1287  // prepare velocity
1288  Vector3f vel_vector;
1289  if (!vel_ignore) {
1290  // convert to cm
1291  vel_vector = Vector3f(packet.vx * 100.0f, packet.vy * 100.0f, -packet.vz * 100.0f);
1292  // rotate to body-frame if necessary
1293  if (packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) {
1294  copter.rotate_body_frame_to_NE(vel_vector.x, vel_vector.y);
1295  }
1296  }
1297 
1298  // prepare yaw
1299  float yaw_cd = 0.0f;
1300  bool yaw_relative = false;
1301  float yaw_rate_cds = 0.0f;
1302  if (!yaw_ignore) {
1303  yaw_cd = ToDeg(packet.yaw) * 100.0f;
1304  yaw_relative = packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED;
1305  }
1306  if (!yaw_rate_ignore) {
1307  yaw_rate_cds = ToDeg(packet.yaw_rate) * 100.0f;
1308  }
1309 
1310  // send request
1311  if (!pos_ignore && !vel_ignore && acc_ignore) {
1312  if (copter.mode_guided.set_destination_posvel(pos_vector, vel_vector, !yaw_ignore, yaw_cd, !yaw_rate_ignore, yaw_rate_cds, yaw_relative)) {
1313  result = MAV_RESULT_ACCEPTED;
1314  } else {
1315  result = MAV_RESULT_FAILED;
1316  }
1317  } else if (pos_ignore && !vel_ignore && acc_ignore) {
1318  copter.mode_guided.set_velocity(vel_vector, !yaw_ignore, yaw_cd, !yaw_rate_ignore, yaw_rate_cds, yaw_relative);
1319  result = MAV_RESULT_ACCEPTED;
1320  } else if (!pos_ignore && vel_ignore && acc_ignore) {
1321  if (copter.mode_guided.set_destination(pos_vector, !yaw_ignore, yaw_cd, !yaw_rate_ignore, yaw_rate_cds, yaw_relative)) {
1322  result = MAV_RESULT_ACCEPTED;
1323  } else {
1324  result = MAV_RESULT_FAILED;
1325  }
1326  } else {
1327  result = MAV_RESULT_FAILED;
1328  }
1329 
1330  break;
1331  }
1332 
1333  case MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT: // MAV ID: 86
1334  {
1335  // decode packet
1336  mavlink_set_position_target_global_int_t packet;
1337  mavlink_msg_set_position_target_global_int_decode(msg, &packet);
1338 
1339  // exit if vehicle is not in Guided mode or Auto-Guided mode
1340  if (!copter.flightmode->in_guided_mode()) {
1341  break;
1342  }
1343 
1344  // check for supported coordinate frames
1345  if (packet.coordinate_frame != MAV_FRAME_GLOBAL &&
1346  packet.coordinate_frame != MAV_FRAME_GLOBAL_INT &&
1347  packet.coordinate_frame != MAV_FRAME_GLOBAL_RELATIVE_ALT && // solo shot manager incorrectly sends RELATIVE_ALT instead of RELATIVE_ALT_INT
1348  packet.coordinate_frame != MAV_FRAME_GLOBAL_RELATIVE_ALT_INT &&
1349  packet.coordinate_frame != MAV_FRAME_GLOBAL_TERRAIN_ALT &&
1350  packet.coordinate_frame != MAV_FRAME_GLOBAL_TERRAIN_ALT_INT) {
1351  break;
1352  }
1353 
1354  bool pos_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_POS_IGNORE;
1355  bool vel_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_VEL_IGNORE;
1356  bool acc_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_ACC_IGNORE;
1357  bool yaw_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_IGNORE;
1358  bool yaw_rate_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_RATE_IGNORE;
1359 
1360  /*
1361  * for future use:
1362  * bool force = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_FORCE;
1363  */
1364 
1365  Vector3f pos_neu_cm; // position (North, East, Up coordinates) in centimeters
1366 
1367  if(!pos_ignore) {
1368  // sanity check location
1369  if (!check_latlng(packet.lat_int, packet.lon_int)) {
1370  result = MAV_RESULT_FAILED;
1371  break;
1372  }
1373  Location loc;
1374  loc.lat = packet.lat_int;
1375  loc.lng = packet.lon_int;
1376  loc.alt = packet.alt*100;
1377  switch (packet.coordinate_frame) {
1378  case MAV_FRAME_GLOBAL_RELATIVE_ALT: // solo shot manager incorrectly sends RELATIVE_ALT instead of RELATIVE_ALT_INT
1379  case MAV_FRAME_GLOBAL_RELATIVE_ALT_INT:
1380  loc.flags.relative_alt = true;
1381  loc.flags.terrain_alt = false;
1382  break;
1383  case MAV_FRAME_GLOBAL_TERRAIN_ALT:
1384  case MAV_FRAME_GLOBAL_TERRAIN_ALT_INT:
1385  loc.flags.relative_alt = true;
1386  loc.flags.terrain_alt = true;
1387  break;
1388  case MAV_FRAME_GLOBAL:
1389  case MAV_FRAME_GLOBAL_INT:
1390  default:
1391  // pv_location_to_vector does not support absolute altitudes.
1392  // Convert the absolute altitude to a home-relative altitude before calling pv_location_to_vector
1393  loc.alt -= copter.ahrs.get_home().alt;
1394  loc.flags.relative_alt = true;
1395  loc.flags.terrain_alt = false;
1396  break;
1397  }
1398  pos_neu_cm = copter.pv_location_to_vector(loc);
1399  }
1400 
1401  // prepare yaw
1402  float yaw_cd = 0.0f;
1403  bool yaw_relative = false;
1404  float yaw_rate_cds = 0.0f;
1405  if (!yaw_ignore) {
1406  yaw_cd = ToDeg(packet.yaw) * 100.0f;
1407  yaw_relative = packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED;
1408  }
1409  if (!yaw_rate_ignore) {
1410  yaw_rate_cds = ToDeg(packet.yaw_rate) * 100.0f;
1411  }
1412 
1413  if (!pos_ignore && !vel_ignore && acc_ignore) {
1414  if (copter.mode_guided.set_destination_posvel(pos_neu_cm, Vector3f(packet.vx * 100.0f, packet.vy * 100.0f, -packet.vz * 100.0f), !yaw_ignore, yaw_cd, !yaw_rate_ignore, yaw_rate_cds, yaw_relative)) {
1415  result = MAV_RESULT_ACCEPTED;
1416  } else {
1417  result = MAV_RESULT_FAILED;
1418  }
1419  } else if (pos_ignore && !vel_ignore && acc_ignore) {
1420  copter.mode_guided.set_velocity(Vector3f(packet.vx * 100.0f, packet.vy * 100.0f, -packet.vz * 100.0f), !yaw_ignore, yaw_cd, !yaw_rate_ignore, yaw_rate_cds, yaw_relative);
1421  result = MAV_RESULT_ACCEPTED;
1422  } else if (!pos_ignore && vel_ignore && acc_ignore) {
1423  if (copter.mode_guided.set_destination(pos_neu_cm, !yaw_ignore, yaw_cd, !yaw_rate_ignore, yaw_rate_cds, yaw_relative)) {
1424  result = MAV_RESULT_ACCEPTED;
1425  } else {
1426  result = MAV_RESULT_FAILED;
1427  }
1428  } else {
1429  result = MAV_RESULT_FAILED;
1430  }
1431 
1432  break;
1433  }
1434 #endif
1435 
1436  case MAVLINK_MSG_ID_DISTANCE_SENSOR:
1437  {
1438  result = MAV_RESULT_ACCEPTED;
1439  copter.rangefinder.handle_msg(msg);
1440 #if PROXIMITY_ENABLED == ENABLED
1441  copter.g2.proximity.handle_msg(msg);
1442 #endif
1443  break;
1444  }
1445 
1446 #if HIL_MODE != HIL_MODE_DISABLED
1447  case MAVLINK_MSG_ID_HIL_STATE: // MAV ID: 90
1448  {
1449  mavlink_hil_state_t packet;
1450  mavlink_msg_hil_state_decode(msg, &packet);
1451 
1452  // sanity check location
1453  if (!check_latlng(packet.lat, packet.lon)) {
1454  break;
1455  }
1456 
1457  // set gps hil sensor
1458  Location loc;
1459  loc.lat = packet.lat;
1460  loc.lng = packet.lon;
1461  loc.alt = packet.alt/10;
1462  Vector3f vel(packet.vx, packet.vy, packet.vz);
1463  vel *= 0.01f;
1464 
1466  packet.time_usec/1000,
1467  loc, vel, 10, 0);
1468 
1469  // rad/sec
1470  Vector3f gyros;
1471  gyros.x = packet.rollspeed;
1472  gyros.y = packet.pitchspeed;
1473  gyros.z = packet.yawspeed;
1474 
1475  // m/s/s
1476  Vector3f accels;
1477  accels.x = packet.xacc * (GRAVITY_MSS/1000.0f);
1478  accels.y = packet.yacc * (GRAVITY_MSS/1000.0f);
1479  accels.z = packet.zacc * (GRAVITY_MSS/1000.0f);
1480 
1481  ins.set_gyro(0, gyros);
1482 
1483  ins.set_accel(0, accels);
1484 
1485  AP::baro().setHIL(packet.alt*0.001f);
1486  copter.compass.setHIL(0, packet.roll, packet.pitch, packet.yaw);
1487  copter.compass.setHIL(1, packet.roll, packet.pitch, packet.yaw);
1488 
1489  break;
1490  }
1491 #endif // HIL_MODE != HIL_MODE_DISABLED
1492 
1493  case MAVLINK_MSG_ID_RADIO:
1494  case MAVLINK_MSG_ID_RADIO_STATUS: // MAV ID: 109
1495  {
1496  handle_radio_status(msg, copter.DataFlash, copter.should_log(MASK_LOG_PM));
1497  break;
1498  }
1499 
1500 #if PRECISION_LANDING == ENABLED
1501  case MAVLINK_MSG_ID_LANDING_TARGET:
1502  result = MAV_RESULT_ACCEPTED;
1503  copter.precland.handle_msg(msg);
1504  break;
1505 #endif
1506 
1507 #if AC_FENCE == ENABLED
1508  // send or receive fence points with GCS
1509  case MAVLINK_MSG_ID_FENCE_POINT: // MAV ID: 160
1510  case MAVLINK_MSG_ID_FENCE_FETCH_POINT:
1511  copter.fence.handle_msg(*this, msg);
1512  break;
1513 #endif // AC_FENCE == ENABLED
1514 
1515 #if MOUNT == ENABLED
1516  //deprecated. Use MAV_CMD_DO_MOUNT_CONFIGURE
1517  case MAVLINK_MSG_ID_MOUNT_CONFIGURE: // MAV ID: 204
1518  copter.camera_mount.configure_msg(msg);
1519  break;
1520  //deprecated. Use MAV_CMD_DO_MOUNT_CONTROL
1521  case MAVLINK_MSG_ID_MOUNT_CONTROL:
1522  if(!copter.camera_mount.has_pan_control()) {
1523  copter.flightmode->auto_yaw.set_fixed_yaw(
1524  mavlink_msg_mount_control_get_input_c(msg)/100.0f,
1525  0.0f,
1526  0,
1527  0);
1528  }
1529  copter.camera_mount.control_msg(msg);
1530  break;
1531 #endif // MOUNT == ENABLED
1532 
1533  case MAVLINK_MSG_ID_TERRAIN_DATA:
1534  case MAVLINK_MSG_ID_TERRAIN_CHECK:
1535 #if AP_TERRAIN_AVAILABLE && AC_TERRAIN
1536  copter.terrain.handle_data(chan, msg);
1537 #endif
1538  break;
1539 
1540  case MAVLINK_MSG_ID_SET_HOME_POSITION:
1541  {
1542  mavlink_set_home_position_t packet;
1543  mavlink_msg_set_home_position_decode(msg, &packet);
1544  if((packet.latitude == 0) && (packet.longitude == 0) && (packet.altitude == 0)) {
1545  copter.set_home_to_current_location(true);
1546  } else {
1547  // sanity check location
1548  if (!check_latlng(packet.latitude, packet.longitude)) {
1549  break;
1550  }
1551  Location new_home_loc;
1552  new_home_loc.lat = packet.latitude;
1553  new_home_loc.lng = packet.longitude;
1554  new_home_loc.alt = packet.altitude / 10;
1555  copter.set_home(new_home_loc, true);
1556  }
1557  break;
1558  }
1559 
1560  case MAVLINK_MSG_ID_ADSB_VEHICLE:
1561  case MAVLINK_MSG_ID_UAVIONIX_ADSB_OUT_CFG:
1562  case MAVLINK_MSG_ID_UAVIONIX_ADSB_OUT_DYNAMIC:
1563  case MAVLINK_MSG_ID_UAVIONIX_ADSB_TRANSCEIVER_HEALTH_REPORT:
1564 #if ADSB_ENABLED == ENABLED
1565  copter.adsb.handle_message(chan, msg);
1566 #endif
1567  break;
1568 
1569 #if TOY_MODE_ENABLED == ENABLED
1570  case MAVLINK_MSG_ID_NAMED_VALUE_INT:
1571  copter.g2.toy_mode.handle_message(msg);
1572  break;
1573 #endif
1574 
1575  default:
1576  handle_common_message(msg);
1577  break;
1578  } // end switch
1579 } // end handle mavlink
1580 
1581 
1582 /*
1583  * a delay() callback that processes MAVLink packets. We set this as the
1584  * callback in long running library initialisation routines to allow
1585  * MAVLink to process packets while waiting for the initialisation to
1586  * complete
1587  */
1589 {
1590  static uint32_t last_1hz, last_50hz, last_5s;
1591  if (!gcs().chan(0).initialised) return;
1592 
1593  DataFlash.EnableWrites(false);
1594 
1595  uint32_t tnow = millis();
1596  if (tnow - last_1hz > 1000) {
1597  last_1hz = tnow;
1600  }
1601  if (tnow - last_50hz > 20) {
1602  last_50hz = tnow;
1603  gcs_check_input();
1606  notify.update();
1607  }
1608  if (tnow - last_5s > 5000) {
1609  last_5s = tnow;
1610  gcs().send_text(MAV_SEVERITY_INFO, "Initialising APM");
1611  }
1612  check_usb_mux();
1613 
1614  DataFlash.EnableWrites(true);
1615 }
1616 
1617 /*
1618  * send data streams in the given rate range on both links
1619  */
1621 {
1622  gcs().data_stream_send();
1623 }
1624 
1625 /*
1626  * look for incoming commands on the GCS links
1627  */
1629 {
1630  gcs().update();
1631 }
1632 
1633 /*
1634  return true if we will accept this packet. Used to implement SYSID_ENFORCE
1635  */
1636 bool GCS_MAVLINK_Copter::accept_packet(const mavlink_status_t &status, mavlink_message_t &msg)
1637 {
1638  if (!copter.g2.sysid_enforce) {
1639  return true;
1640  }
1641  if (msg.msgid == MAVLINK_MSG_ID_RADIO || msg.msgid == MAVLINK_MSG_ID_RADIO_STATUS) {
1642  return true;
1643  }
1644  return (msg.sysid == copter.g.sysid_my_gcs);
1645 }
1646 
1648 {
1649 #if MODE_AUTO_ENABLED == ENABLED
1650  return &copter.mission;
1651 #else
1652  return nullptr;
1653 #endif
1654 }
1655 
1657 {
1658  return &copter.compass;
1659 }
1660 
1662 {
1663 #if CAMERA == ENABLED
1664  return &copter.camera;
1665 #else
1666  return nullptr;
1667 #endif
1668 }
1669 
1671 {
1672 #if ADVANCED_FAILSAFE == ENABLED
1673  return &copter.g2.afs;
1674 #else
1675  return nullptr;
1676 #endif
1677 }
1678 
1680 {
1681 #if VISUAL_ODOMETRY_ENABLED == ENABLED
1682  return &copter.g2.visual_odom;
1683 #else
1684  return nullptr;
1685 #endif
1686 }
1687 
1688 
1689 MAV_RESULT GCS_MAVLINK_Copter::handle_flight_termination(const mavlink_command_long_t &packet) {
1690  MAV_RESULT result = MAV_RESULT_FAILED;
1691 
1692 #if ADVANCED_FAILSAFE == ENABLED
1693  if (GCS_MAVLINK::handle_flight_termination(packet) != MAV_RESULT_ACCEPTED) {
1694 #endif
1695  if (packet.param1 > 0.5f) {
1696  copter.init_disarm_motors();
1697  result = MAV_RESULT_ACCEPTED;
1698  }
1699 #if ADVANCED_FAILSAFE == ENABLED
1700  } else {
1701  result = MAV_RESULT_ACCEPTED;
1702  }
1703 #endif
1704 
1705  return result;
1706 }
1707 
1709 {
1710 #if AC_RALLY == ENABLED
1711  return &copter.rally;
1712 #else
1713  return nullptr;
1714 #endif
1715 }
1716 
1717 bool GCS_MAVLINK_Copter::set_mode(const uint8_t mode)
1718 {
1719 #ifdef DISALLOW_GCS_MODE_CHANGE_DURING_RC_FAILSAFE
1720  if (copter.failsafe.radio) {
1721  // don't allow mode changes while in radio failsafe
1722  return false;
1723  }
1724 #endif
1725  return copter.set_mode((control_mode_t)mode, MODE_REASON_GCS_COMMAND);
1726 }
1727 
1729 {
1730  return copter.fwver;
1731 }
MSG_RANGEFINDER
#define MAVLINK_SET_POS_TYPE_MASK_POS_IGNORE
Definition: defines.h:475
bool enabled(uint8_t instance) const
MSG_BATTERY_STATUS
AP_AHRS_NavEKF ahrs
Definition: Copter.h:255
const Vector3f & get_accel_ef_blended() const override
AC_AttitudeControl_t * attitude_control
Definition: Copter.h:492
MSG_AHRS
void send_extended_status1(mavlink_channel_t chan)
float load_average()
control_mode_t
Definition: defines.h:91
MSG_EXTENDED_STATUS1
MSG_PID_TUNING
#define CHECK_PAYLOAD_SIZE(id)
MSG_ADSB_VEHICLE
float get_rpm(uint8_t instance) const
const Vector3f & get_gyro(void) const override
MSG_MOUNT_STATUS
MSG_RADIO_IN
#define MAVLINK_SET_POS_TYPE_MASK_VEL_IGNORE
Definition: defines.h:476
MSG_RAW_IMU1
float get_alt_error() const
virtual uint8_t capacity_remaining_pct(uint8_t instance) const
MSG_SERVO_OUT
AP_InertialSensor ins
Definition: Copter.h:236
MSG_LANDING
MSG_RAW_IMU2
#define AP_GROUPINFO(name, idx, clazz, element, def)
MSG_RPM
Definition: defines.h:95
Definition: defines.h:106
GCS_Copter & gcs()
Definition: Copter.h:301
void gcs_data_stream_send(void)
AP_Int16 gcs_pid_mask
Definition: Parameters.h:456
ap_message
MSG_WIND
void data_stream_send()
#define MAV_STREAM_ENTRY(stream_name)
Definition: defines.h:96
Definition: defines.h:100
bool use_yaw_rate
Definition: mode_guided.cpp:26
uint32_t control_sensors_health
Definition: Copter.h:460
bool is_positive(const T fVal1)
const char * result
MSG_NAV_CONTROLLER_OUTPUT
MSG_GPS_RAW
int32_t lat
#define MIN(a, b)
#define ToDeg(x)
#define DATA_PARACHUTE_ENABLED
Definition: defines.h:370
bool healthy(uint8_t instance) const
void gcs_send_heartbeat(void)
Definition: GCS_Mavlink.cpp:5
MSG_GPS2_RAW
virtual int32_t wp_bearing() const
Definition: Copter.h:96
virtual void delay(uint16_t ms)=0
void send_message(enum ap_message id)
#define HAVE_PAYLOAD_SPACE(chan, id)
MSG_POSITION_TARGET_GLOBAL_INT
MSG_MAG_CAL_REPORT
#define DATA_WINCH_LENGTH_CONTROL
Definition: defines.h:389
int32_t alt
AP_RPM rpm_sensor
Definition: Copter.h:249
#define GRAVITY_MSS
#define DATA_PARACHUTE_DISABLED
Definition: defines.h:369
bool is_zero(const T fVal1)
Mode * flightmode
Definition: Copter.h:955
#define f(i)
AP_BattMonitor battery
Definition: Copter.h:445
bool has_current(uint8_t instance) const
MSG_AOA_SSA
const AP_HAL::HAL & hal
Definition: Copter.cpp:21
MSG_EXTENDED_STATUS2
#define DATA_WINCH_RELAXED
Definition: defines.h:388
void set_accel(uint8_t instance, const Vector3f &accel)
uint32_t millis()
void send_rpm(mavlink_channel_t chan)
void mavlink_delay_cb()
AP_Notify notify
Definition: Copter.h:215
virtual uint32_t wp_distance() const
Definition: Copter.h:95
void set_out_of_time(bool val)
void update_sensor_status_flags(void)
Definition: sensors.cpp:226
MSG_GPS_RTK
bool check_latlng(float lat, float lng)
void send_fence_status(mavlink_channel_t chan)
MSG_CURRENT_WAYPOINT
int16_t pitch
Definition: defines.h:99
Definition: defines.h:97
float current_amps(uint8_t instance) const
MSG_HWSTATUS
void send_text(MAV_SEVERITY severity, const char *fmt,...)
#define MASK_LOG_PM
Definition: defines.h:317
#define DATA_WINCH_RATE_CONTROL
Definition: defines.h:390
MSG_EKF_STATUS_REPORT
void send_nav_controller_output(mavlink_channel_t chan)
MSG_FENCE_STATUS
Location_Option_Flags flags
DataFlash_Class DataFlash
Definition: Copter.h:227
AP_GPS gps
Definition: Copter.h:229
uint32_t control_sensors_enabled
Definition: Copter.h:459
MSG_SERVO_OUTPUT_RAW
void set_gyro(uint8_t instance, const Vector3f &gyro)
AP_Scheduler scheduler
Definition: Copter.h:212
MSG_VIBRATION
Parameters g
Definition: Copter.h:208
MSG_VFR_HUD
float constrain_float(const float amt, const float low, const float high)
float climb_rate_cms
Definition: mode_guided.cpp:25
AP_AHRS & ahrs()
void setHIL(uint8_t instance, GPS_Status status, uint64_t time_epoch_ms, const Location &location, const Vector3f &velocity, uint8_t num_sats, uint16_t hdop)
virtual void reboot(bool hold_in_bootloader)=0
int32_t lng
MSG_GIMBAL_REPORT
std::enable_if< std::is_integral< typename std::common_type< Arithmetic1, Arithmetic2 >::type >::value, bool >::type is_equal(const Arithmetic1 v_1, const Arithmetic2 v_2)
int16_t roll
static struct notify_flags_and_values_type flags
AP_HAL_MAIN_CALLBACKS & copter
Definition: ArduCopter.cpp:581
AP_HAL::AnalogSource * chan
MSG_LOCAL_POSITION
void gcs_check_input(void)
MSG_OPTICAL_FLOW
void EnableWrites(bool enable)
static bool in_sensor_config_error(void)
void fence_send_mavlink_status(mavlink_channel_t chan)
Definition: fence.cpp:54
AC_PosControl * pos_control
Definition: Copter.h:493
#define NOINLINE
float yaw_cd
Definition: mode_guided.cpp:23
MSG_SYSTEM_TIME
MSG_SIMSTATE
uint32_t control_sensors_present
Definition: Copter.h:458
static void clear_overrides(void)
#define MAVLINK_SET_POS_TYPE_MASK_YAW_RATE_IGNORE
Definition: defines.h:480
MSG_RAW_IMU3
void update()
#define MAVLINK_SET_POS_TYPE_MASK_ACC_IGNORE
Definition: defines.h:477
#define MAVLINK_SET_POS_TYPE_MASK_YAW_IGNORE
Definition: defines.h:479
void update(void)
void gcs_send_deferred(void)
Definition: GCS_Mavlink.cpp:10
#define MAV_STREAM_TERMINATOR
#define degrees(x)
AP_Baro & baro()
float voltage(uint8_t instance) const
bool home_is_set(void) const
MSG_HEARTBEAT
static bool set_override(const uint8_t chan, const int16_t value)
MSG_LOCATION
MSG_BATTERY2
MSG_GPS2_RTK
MSG_ATTITUDE
void retry_deferred()
float yaw_rate_cds
Definition: mode_guided.cpp:24
#define AP_GROUPEND
AP_HAL::Scheduler * scheduler
MSG_MAG_CAL_PROGRESS
MSG_TERRAIN
Definition: defines.h:98
void check_usb_mux(void)
Definition: system.cpp:421
void send_pid_tuning(mavlink_channel_t chan)
void setHIL(float altitude_msl)