PX4 Firmware
PX4 Autopilot Software http://px4.io
mavlink_messages.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2012-2017 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 /**
35  * @file mavlink_messages.cpp
36  * MAVLink 2.0 message formatters implementation.
37  *
38  * @author Lorenz Meier <lorenz@px4.io>
39  * @author Anton Babushkin <anton.babushkin@me.com>
40  */
41 
42 #include "mavlink_main.h"
43 #include "mavlink_messages.h"
44 #include "mavlink_command_sender.h"
46 #include "mavlink_high_latency2.h"
47 
49 #include <drivers/drv_pwm_output.h>
51 #include <lib/ecl/geo/geo.h>
52 #include <lib/mathlib/mathlib.h>
54 #include <px4_platform_common/time.h>
55 #include <systemlib/mavlink_log.h>
56 #include <math.h>
57 
61 #include <uORB/topics/airspeed.h>
65 #include <uORB/topics/cpuload.h>
68 #include <uORB/topics/debug_vect.h>
75 #include <uORB/topics/input_rc.h>
108 #include <uORB/topics/sensor_gyro.h>
109 #include <uORB/topics/sensor_mag.h>
112 #include <uORB/uORB.h>
113 
114 using matrix::wrap_2pi;
115 
116 static uint16_t cm_uint16_from_m_float(float m);
117 
118 static void get_mavlink_mode_state(const struct vehicle_status_s *const status, uint8_t *mavlink_state,
119  uint8_t *mavlink_base_mode, uint32_t *mavlink_custom_mode);
120 
121 uint16_t
123 {
124  if (m < 0.0f) {
125  return 0;
126 
127  } else if (m > 655.35f) {
128  return 65535;
129  }
130 
131  return (uint16_t)(m * 100.0f);
132 }
133 
134 void get_mavlink_navigation_mode(const struct vehicle_status_s *const status, uint8_t *mavlink_base_mode,
135  union px4_custom_mode *custom_mode)
136 {
137  custom_mode->data = 0;
138  *mavlink_base_mode = 0;
139 
140  /* HIL */
141  if (status->hil_state == vehicle_status_s::HIL_STATE_ON) {
142  *mavlink_base_mode |= MAV_MODE_FLAG_HIL_ENABLED;
143  }
144 
145  /* arming state */
146  if (status->arming_state == vehicle_status_s::ARMING_STATE_ARMED) {
147  *mavlink_base_mode |= MAV_MODE_FLAG_SAFETY_ARMED;
148  }
149 
150  /* main state */
151  *mavlink_base_mode |= MAV_MODE_FLAG_CUSTOM_MODE_ENABLED;
152 
153  const uint8_t auto_mode_flags = MAV_MODE_FLAG_AUTO_ENABLED
154  | MAV_MODE_FLAG_STABILIZE_ENABLED
155  | MAV_MODE_FLAG_GUIDED_ENABLED;
156 
157  switch (status->nav_state) {
158  case vehicle_status_s::NAVIGATION_STATE_MANUAL:
159  *mavlink_base_mode |= MAV_MODE_FLAG_MANUAL_INPUT_ENABLED
160  | (status->vehicle_type == vehicle_status_s::VEHICLE_TYPE_ROTARY_WING ? MAV_MODE_FLAG_STABILIZE_ENABLED : 0);
161  custom_mode->main_mode = PX4_CUSTOM_MAIN_MODE_MANUAL;
162  break;
163 
164  case vehicle_status_s::NAVIGATION_STATE_ACRO:
165  *mavlink_base_mode |= MAV_MODE_FLAG_MANUAL_INPUT_ENABLED;
166  custom_mode->main_mode = PX4_CUSTOM_MAIN_MODE_ACRO;
167  break;
168 
169  case vehicle_status_s::NAVIGATION_STATE_RATTITUDE:
170  *mavlink_base_mode |= MAV_MODE_FLAG_MANUAL_INPUT_ENABLED;
172  break;
173 
174  case vehicle_status_s::NAVIGATION_STATE_STAB:
175  *mavlink_base_mode |= MAV_MODE_FLAG_MANUAL_INPUT_ENABLED
176  | MAV_MODE_FLAG_STABILIZE_ENABLED;
178  break;
179 
180  case vehicle_status_s::NAVIGATION_STATE_ALTCTL:
181  *mavlink_base_mode |= MAV_MODE_FLAG_MANUAL_INPUT_ENABLED
182  | MAV_MODE_FLAG_STABILIZE_ENABLED;
183  custom_mode->main_mode = PX4_CUSTOM_MAIN_MODE_ALTCTL;
184  break;
185 
186  case vehicle_status_s::NAVIGATION_STATE_POSCTL:
187  *mavlink_base_mode |= MAV_MODE_FLAG_MANUAL_INPUT_ENABLED
188  | MAV_MODE_FLAG_STABILIZE_ENABLED
189  | MAV_MODE_FLAG_GUIDED_ENABLED; // TODO: is POSCTL GUIDED?
190  custom_mode->main_mode = PX4_CUSTOM_MAIN_MODE_POSCTL;
191  break;
192 
193  case vehicle_status_s::NAVIGATION_STATE_ORBIT:
194  *mavlink_base_mode |= MAV_MODE_FLAG_MANUAL_INPUT_ENABLED
195  | MAV_MODE_FLAG_STABILIZE_ENABLED
196  | MAV_MODE_FLAG_GUIDED_ENABLED;
197  custom_mode->main_mode = PX4_CUSTOM_MAIN_MODE_POSCTL;
199  break;
200 
201  case vehicle_status_s::NAVIGATION_STATE_AUTO_TAKEOFF:
202  *mavlink_base_mode |= auto_mode_flags;
203  custom_mode->main_mode = PX4_CUSTOM_MAIN_MODE_AUTO;
205  break;
206 
207  case vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION:
208  *mavlink_base_mode |= auto_mode_flags;
209  custom_mode->main_mode = PX4_CUSTOM_MAIN_MODE_AUTO;
211  break;
212 
213  case vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER:
214  *mavlink_base_mode |= auto_mode_flags;
215  custom_mode->main_mode = PX4_CUSTOM_MAIN_MODE_AUTO;
217  break;
218 
219  case vehicle_status_s::NAVIGATION_STATE_AUTO_FOLLOW_TARGET:
220  *mavlink_base_mode |= auto_mode_flags;
221  custom_mode->main_mode = PX4_CUSTOM_MAIN_MODE_AUTO;
223  break;
224 
225  case vehicle_status_s::NAVIGATION_STATE_AUTO_PRECLAND:
226  *mavlink_base_mode |= auto_mode_flags;
227  custom_mode->main_mode = PX4_CUSTOM_MAIN_MODE_AUTO;
229  break;
230 
231  case vehicle_status_s::NAVIGATION_STATE_AUTO_RTL:
232 
233  /* fallthrough */
234  case vehicle_status_s::NAVIGATION_STATE_AUTO_RCRECOVER:
235  *mavlink_base_mode |= auto_mode_flags;
236  custom_mode->main_mode = PX4_CUSTOM_MAIN_MODE_AUTO;
237  custom_mode->sub_mode = PX4_CUSTOM_SUB_MODE_AUTO_RTL;
238  break;
239 
240  case vehicle_status_s::NAVIGATION_STATE_AUTO_LAND:
241  case vehicle_status_s::NAVIGATION_STATE_AUTO_LANDENGFAIL:
242  case vehicle_status_s::NAVIGATION_STATE_AUTO_LANDGPSFAIL:
243 
244  /* fallthrough */
245  case vehicle_status_s::NAVIGATION_STATE_DESCEND:
246  *mavlink_base_mode |= auto_mode_flags;
247  custom_mode->main_mode = PX4_CUSTOM_MAIN_MODE_AUTO;
249  break;
250 
251  case vehicle_status_s::NAVIGATION_STATE_AUTO_RTGS:
252  *mavlink_base_mode |= auto_mode_flags;
253  custom_mode->main_mode = PX4_CUSTOM_MAIN_MODE_AUTO;
255  break;
256 
257  case vehicle_status_s::NAVIGATION_STATE_TERMINATION:
258  *mavlink_base_mode |= MAV_MODE_FLAG_MANUAL_INPUT_ENABLED;
259  custom_mode->main_mode = PX4_CUSTOM_MAIN_MODE_MANUAL;
260  break;
261 
262  case vehicle_status_s::NAVIGATION_STATE_OFFBOARD:
263  *mavlink_base_mode |= auto_mode_flags;
265  break;
266 
267  case vehicle_status_s::NAVIGATION_STATE_MAX:
268  /* this is an unused case, ignore */
269  break;
270 
271  }
272 }
273 
274 void get_mavlink_mode_state(const struct vehicle_status_s *const status, uint8_t *mavlink_state,
275  uint8_t *mavlink_base_mode, uint32_t *mavlink_custom_mode)
276 {
277  *mavlink_state = 0;
278  *mavlink_base_mode = 0;
279  *mavlink_custom_mode = 0;
280 
281  union px4_custom_mode custom_mode;
282  get_mavlink_navigation_mode(status, mavlink_base_mode, &custom_mode);
283  *mavlink_custom_mode = custom_mode.data;
284 
285  /* set system state */
286  if (status->arming_state == vehicle_status_s::ARMING_STATE_INIT
287  || status->arming_state == vehicle_status_s::ARMING_STATE_IN_AIR_RESTORE
288  || status->arming_state == vehicle_status_s::ARMING_STATE_STANDBY_ERROR) { // TODO review
289  *mavlink_state = MAV_STATE_UNINIT;
290 
291  } else if (status->arming_state == vehicle_status_s::ARMING_STATE_ARMED) {
292  *mavlink_state = MAV_STATE_ACTIVE;
293 
294  } else if (status->arming_state == vehicle_status_s::ARMING_STATE_STANDBY) {
295  *mavlink_state = MAV_STATE_STANDBY;
296 
297  } else if (status->arming_state == vehicle_status_s::ARMING_STATE_SHUTDOWN) {
298  *mavlink_state = MAV_STATE_POWEROFF;
299 
300  } else {
301  *mavlink_state = MAV_STATE_CRITICAL;
302  }
303 }
304 
305 
307 {
308 public:
309  const char *get_name() const override
310  {
312  }
313 
314  static const char *get_name_static()
315  {
316  return "HEARTBEAT";
317  }
318 
319  static uint16_t get_id_static()
320  {
321  return MAVLINK_MSG_ID_HEARTBEAT;
322  }
323 
324  uint16_t get_id() override
325  {
326  return get_id_static();
327  }
328 
330  {
331  return new MavlinkStreamHeartbeat(mavlink);
332  }
333 
334  unsigned get_size() override
335  {
336  return MAVLINK_MSG_ID_HEARTBEAT_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
337  }
338 
339  bool const_rate() override
340  {
341  return true;
342  }
343 
344 private:
346 
347  /* do not allow top copying this class */
350 
351 protected:
352  explicit MavlinkStreamHeartbeat(Mavlink *mavlink) : MavlinkStream(mavlink),
353  _status_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_status)))
354  {}
355 
356  bool send(const hrt_abstime t) override
357  {
358  struct vehicle_status_s status = {};
359 
360  /* always send the heartbeat, independent of the update status of the topics */
361  if (!_status_sub->update(&status)) {
362  /* if topic update failed fill it with defaults */
363  memset(&status, 0, sizeof(status));
364  }
365 
366  uint8_t base_mode = 0;
367  uint32_t custom_mode = 0;
368  uint8_t system_status = 0;
369  get_mavlink_mode_state(&status, &system_status, &base_mode, &custom_mode);
370 
371  mavlink_msg_heartbeat_send(_mavlink->get_channel(), _mavlink->get_system_type(), MAV_AUTOPILOT_PX4,
372  base_mode, custom_mode, system_status);
373 
374  return true;
375  }
376 };
377 
379 {
380 public:
381  const char *get_name() const override
382  {
384  }
385 
386  static const char *get_name_static()
387  {
388  return "STATUSTEXT";
389  }
390 
391  static uint16_t get_id_static()
392  {
393  return MAVLINK_MSG_ID_STATUSTEXT;
394  }
395 
396  uint16_t get_id() override
397  {
398  return get_id_static();
399  }
400 
402  {
403  return new MavlinkStreamStatustext(mavlink);
404  }
405 
406  unsigned get_size() override
407  {
408  return _mavlink->get_logbuffer()->empty() ? 0 : (MAVLINK_MSG_ID_STATUSTEXT_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES);
409  }
410 
411 private:
412  /* do not allow top copying this class */
415 
416 protected:
417  explicit MavlinkStreamStatustext(Mavlink *mavlink) : MavlinkStream(mavlink)
418  {}
419 
420  bool send(const hrt_abstime t) override
421  {
422  if (!_mavlink->get_logbuffer()->empty() && _mavlink->is_connected()) {
423 
424  struct mavlink_log_s mavlink_log = {};
425 
426  if (_mavlink->get_logbuffer()->get(&mavlink_log)) {
427 
428  mavlink_statustext_t msg;
429  msg.severity = mavlink_log.severity;
430  strncpy(msg.text, (const char *)mavlink_log.text, sizeof(msg.text));
431  msg.text[sizeof(msg.text) - 1] = '\0';
432 
433  mavlink_msg_statustext_send_struct(_mavlink->get_channel(), &msg);
434 
435  return true;
436  }
437  }
438 
439  return false;
440  }
441 };
442 
444 {
445 public:
446  const char *get_name() const override
447  {
449  }
450 
451  static const char *get_name_static()
452  {
453  return "COMMAND_LONG";
454  }
455 
456  static uint16_t get_id_static()
457  {
458  return MAVLINK_MSG_ID_COMMAND_LONG;
459  }
460 
461  uint16_t get_id() override
462  {
463  return get_id_static();
464  }
465 
467  {
468  return new MavlinkStreamCommandLong(mavlink);
469  }
470 
471  unsigned get_size() override
472  {
473  return 0; // commands stream is not regular and not predictable
474  }
475 
476 private:
478 
479  /* do not allow top copying this class */
482 
483 protected:
484  explicit MavlinkStreamCommandLong(Mavlink *mavlink) : MavlinkStream(mavlink),
485  _cmd_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_command), 0, true))
486  {}
487 
488  bool send(const hrt_abstime t) override
489  {
490  struct vehicle_command_s cmd;
491  bool sent = false;
492 
493  if (_cmd_sub->update_if_changed(&cmd)) {
494 
495  if (!cmd.from_external) {
496  PX4_DEBUG("sending command %d to %d/%d", cmd.command, cmd.target_system, cmd.target_component);
497 
499  sent = true;
500 
501  } else {
502  PX4_DEBUG("not forwarding command %d to %d/%d", cmd.command, cmd.target_system, cmd.target_component);
503  }
504  }
505 
507 
508  return sent;
509  }
510 };
511 
513 {
514 public:
515  const char *get_name() const override
516  {
518  }
519 
520  static const char *get_name_static()
521  {
522  return "SYS_STATUS";
523  }
524 
525  static uint16_t get_id_static()
526  {
527  return MAVLINK_MSG_ID_SYS_STATUS;
528  }
529 
530  uint16_t get_id() override
531  {
532  return get_id_static();
533  }
534 
536  {
537  return new MavlinkStreamSysStatus(mavlink);
538  }
539 
540  unsigned get_size() override
541  {
542  return MAVLINK_MSG_ID_SYS_STATUS_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
543  }
544 
545 private:
549 
550  uint64_t _status_timestamp{0};
551  uint64_t _cpuload_timestamp{0};
552  uint64_t _battery_status_timestamp[ORB_MULTI_MAX_INSTANCES] {};
553 
554  /* do not allow top copying this class */
557 
558 protected:
559  explicit MavlinkStreamSysStatus(Mavlink *mavlink) : MavlinkStream(mavlink),
560  _status_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_status))),
561  _cpuload_sub(_mavlink->add_orb_subscription(ORB_ID(cpuload)))
562  {
563  for (int i = 0; i < ORB_MULTI_MAX_INSTANCES; i++) {
564  _battery_status_sub[i] = _mavlink->add_orb_subscription(ORB_ID(battery_status), i);
565  _battery_status_timestamp[i] = 0;
566  }
567  }
568 
569  bool send(const hrt_abstime t) override
570  {
572  cpuload_s cpuload{};
574 
575  const bool updated_status = _status_sub->update(&_status_timestamp, &status);
576  const bool updated_cpuload = _cpuload_sub->update(&_cpuload_timestamp, &cpuload);
577 
578  bool updated_battery = false;
579 
580  for (int i = 0; i < ORB_MULTI_MAX_INSTANCES; i++) {
581  if (_battery_status_sub[i]->update(&_battery_status_timestamp[i], &battery_status[i])) {
582  updated_battery = true;
583  }
584  }
585 
586  if (updated_status || updated_cpuload || updated_battery) {
587  int lowest_battery_index = 0;
588 
589  for (int i = 0; i < ORB_MULTI_MAX_INSTANCES; i++) {
590  if (battery_status[i].connected && (battery_status[i].remaining < battery_status[lowest_battery_index].remaining)) {
591  lowest_battery_index = i;
592  }
593  }
594 
595  mavlink_sys_status_t msg{};
596 
597  msg.onboard_control_sensors_present = status.onboard_control_sensors_present;
598  msg.onboard_control_sensors_enabled = status.onboard_control_sensors_enabled;
599  msg.onboard_control_sensors_health = status.onboard_control_sensors_health;
600 
601  msg.load = cpuload.load * 1000.0f;
602 
603  // TODO: Determine what data should be put here when there are multiple batteries.
604  // Right now, it uses the lowest battery. This is a safety decision, because if a client is only checking
605  // one battery using this message, it should be the lowest.
606  // In the future, this should somehow determine the "main" battery, or use the "type" field of BATTERY_STATUS
607  // to determine which battery is more important at a given time.
608  const battery_status_s &lowest_battery = battery_status[lowest_battery_index];
609 
610  if (lowest_battery.connected) {
611  msg.voltage_battery = lowest_battery.voltage_filtered_v * 1000.0f;
612  msg.current_battery = lowest_battery.current_filtered_a * 100.0f;
613  msg.battery_remaining = ceilf(lowest_battery.remaining * 100.0f);
614 
615  } else {
616  msg.voltage_battery = UINT16_MAX;
617  msg.current_battery = -1;
618  msg.battery_remaining = -1;
619  }
620 
621  mavlink_msg_sys_status_send_struct(_mavlink->get_channel(), &msg);
622 
623  return true;
624  }
625 
626  return false;
627  }
628 };
629 
631 {
632 public:
633  const char *get_name() const override
634  {
636  }
637 
638  static const char *get_name_static()
639  {
640  return "BATTERY_STATUS";
641  }
642 
643  static uint16_t get_id_static()
644  {
645  return MAVLINK_MSG_ID_BATTERY_STATUS;
646  }
647 
648  uint16_t get_id() override
649  {
650  return get_id_static();
651  }
652 
654  {
655  return new MavlinkStreamBatteryStatus(mavlink);
656  }
657 
658  unsigned get_size() override
659  {
660  return MAVLINK_MSG_ID_BATTERY_STATUS_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
661  }
662 
663 private:
665 
666  uint64_t _battery_status_timestamp[ORB_MULTI_MAX_INSTANCES] {};
667 
668  /* do not allow top copying this class */
671 
672 protected:
673  explicit MavlinkStreamBatteryStatus(Mavlink *mavlink) : MavlinkStream(mavlink)
674  {
675  for (int i = 0; i < ORB_MULTI_MAX_INSTANCES; i++) {
676  _battery_status_sub[i] = _mavlink->add_orb_subscription(ORB_ID(battery_status), i);
677  }
678  }
679 
680  bool send(const hrt_abstime t) override
681  {
682  bool updated = false;
683 
684  for (int i = 0; i < ORB_MULTI_MAX_INSTANCES; i++) {
685 
686  if (!_battery_status_sub[i]) {
687  continue;
688  }
689 
691 
692  if (_battery_status_sub[i]->update(&_battery_status_timestamp[i], &battery_status)) {
693  /* battery status message with higher resolution */
694  mavlink_battery_status_t bat_msg{};
695  bat_msg.id = i;
696  bat_msg.battery_function = MAV_BATTERY_FUNCTION_ALL;
697  bat_msg.type = MAV_BATTERY_TYPE_LIPO;
698  bat_msg.current_consumed = (battery_status.connected) ? battery_status.discharged_mah : -1;
699  bat_msg.energy_consumed = -1;
700  bat_msg.current_battery = (battery_status.connected) ? battery_status.current_filtered_a * 100 : -1;
701  bat_msg.battery_remaining = (battery_status.connected) ? ceilf(battery_status.remaining * 100.0f) : -1;
702 
703  switch (battery_status.warning) {
704  case (battery_status_s::BATTERY_WARNING_NONE):
705  bat_msg.charge_state = MAV_BATTERY_CHARGE_STATE_OK;
706  break;
707 
708  case (battery_status_s::BATTERY_WARNING_LOW):
709  bat_msg.charge_state = MAV_BATTERY_CHARGE_STATE_LOW;
710  break;
711 
712  case (battery_status_s::BATTERY_WARNING_CRITICAL):
713  bat_msg.charge_state = MAV_BATTERY_CHARGE_STATE_CRITICAL;
714  break;
715 
716  case (battery_status_s::BATTERY_WARNING_EMERGENCY):
717  bat_msg.charge_state = MAV_BATTERY_CHARGE_STATE_EMERGENCY;
718  break;
719 
720  case (battery_status_s::BATTERY_WARNING_FAILED):
721  bat_msg.charge_state = MAV_BATTERY_CHARGE_STATE_FAILED;
722  break;
723 
724  default:
725  bat_msg.charge_state = MAV_BATTERY_CHARGE_STATE_UNDEFINED;
726  break;
727  }
728 
729  // check if temperature valid
730  if (battery_status.connected && PX4_ISFINITE(battery_status.temperature)) {
731  bat_msg.temperature = battery_status.temperature * 100.0f;
732 
733  } else {
734  bat_msg.temperature = INT16_MAX;
735  }
736 
737  static constexpr int mavlink_cells_max = (sizeof(bat_msg.voltages) / sizeof(bat_msg.voltages[0]));
738 
739  for (int cell = 0; cell < mavlink_cells_max; cell++) {
740  if ((battery_status.cell_count > 0) && (cell < battery_status.cell_count) && battery_status.connected) {
741  bat_msg.voltages[cell] = (battery_status.voltage_v / battery_status.cell_count) * 1000.0f;
742 
743  } else {
744  bat_msg.voltages[cell] = UINT16_MAX;
745  }
746  }
747 
748  mavlink_msg_battery_status_send_struct(_mavlink->get_channel(), &bat_msg);
749 
750  updated = true;
751  }
752 
753  }
754 
755  return updated;
756  }
757 };
758 
760 {
761 public:
762  const char *get_name() const override
763  {
765  }
766 
767  static const char *get_name_static()
768  {
769  return "HIGHRES_IMU";
770  }
771 
772  static uint16_t get_id_static()
773  {
774  return MAVLINK_MSG_ID_HIGHRES_IMU;
775  }
776 
777  uint16_t get_id() override
778  {
779  return get_id_static();
780  }
781 
783  {
784  return new MavlinkStreamHighresIMU(mavlink);
785  }
786 
787  unsigned get_size() override
788  {
789  return MAVLINK_MSG_ID_HIGHRES_IMU_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
790  }
791 
792 private:
794  uint64_t _sensor_time;
795 
800 
802  uint64_t _gyro_timestamp;
803  uint64_t _mag_timestamp;
804  uint64_t _baro_timestamp;
806 
807  /* do not allow top copying this class */
810 
811 protected:
812  explicit MavlinkStreamHighresIMU(Mavlink *mavlink) : MavlinkStream(mavlink),
813  _sensor_sub(_mavlink->add_orb_subscription(ORB_ID(sensor_combined))),
814  _sensor_time(0),
815  _bias_sub(_mavlink->add_orb_subscription(ORB_ID(sensor_bias))),
816  _differential_pressure_sub(_mavlink->add_orb_subscription(ORB_ID(differential_pressure))),
817  _magnetometer_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_magnetometer))),
818  _air_data_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_air_data))),
819  _accel_timestamp(0),
820  _gyro_timestamp(0),
821  _mag_timestamp(0),
822  _baro_timestamp(0),
823  _dpres_timestamp(0)
824  {}
825 
826  bool send(const hrt_abstime t) override
827  {
828  sensor_combined_s sensor;
829 
830  if (_sensor_sub->update(&_sensor_time, &sensor)) {
831  uint16_t fields_updated = 0;
832 
833  if (_accel_timestamp != sensor.timestamp + sensor.accelerometer_timestamp_relative) {
834  /* mark first three dimensions as changed */
835  fields_updated |= (1 << 0) | (1 << 1) | (1 << 2);
836  _accel_timestamp = sensor.timestamp + sensor.accelerometer_timestamp_relative;
837  }
838 
839  if (_gyro_timestamp != sensor.timestamp) {
840  /* mark second group dimensions as changed */
841  fields_updated |= (1 << 3) | (1 << 4) | (1 << 5);
842  _gyro_timestamp = sensor.timestamp;
843  }
844 
845  vehicle_magnetometer_s magnetometer = {};
846  _magnetometer_sub->update(&magnetometer);
847 
848  if (_mag_timestamp != magnetometer.timestamp) {
849  /* mark third group dimensions as changed */
850  fields_updated |= (1 << 6) | (1 << 7) | (1 << 8);
851  _mag_timestamp = magnetometer.timestamp;
852  }
853 
854  vehicle_air_data_s air_data = {};
855  _air_data_sub->update(&air_data);
856 
857  if (_baro_timestamp != air_data.timestamp) {
858  /* mark fourth group (baro fields) dimensions as changed */
859  fields_updated |= (1 << 9) | (1 << 11) | (1 << 12);
860  _baro_timestamp = air_data.timestamp;
861  }
862 
863  sensor_bias_s bias = {};
864  _bias_sub->update(&bias);
865 
866  differential_pressure_s differential_pressure = {};
867  _differential_pressure_sub->update(&differential_pressure);
868 
869  if (_dpres_timestamp != differential_pressure.timestamp) {
870  /* mark fourth group (dpres field) dimensions as changed */
871  fields_updated |= (1 << 10);
872  _dpres_timestamp = differential_pressure.timestamp;
873  }
874 
875  mavlink_highres_imu_t msg = {};
876 
877  msg.time_usec = sensor.timestamp;
878  msg.xacc = sensor.accelerometer_m_s2[0] - bias.accel_bias[0];
879  msg.yacc = sensor.accelerometer_m_s2[1] - bias.accel_bias[1];
880  msg.zacc = sensor.accelerometer_m_s2[2] - bias.accel_bias[2];
881  msg.xgyro = sensor.gyro_rad[0] - bias.gyro_bias[0];
882  msg.ygyro = sensor.gyro_rad[1] - bias.gyro_bias[1];
883  msg.zgyro = sensor.gyro_rad[2] - bias.gyro_bias[2];
884  msg.xmag = magnetometer.magnetometer_ga[0] - bias.mag_bias[0];
885  msg.ymag = magnetometer.magnetometer_ga[1] - bias.mag_bias[1];
886  msg.zmag = magnetometer.magnetometer_ga[2] - bias.mag_bias[2];
887  msg.abs_pressure = air_data.baro_pressure_pa;
888  msg.diff_pressure = differential_pressure.differential_pressure_raw_pa;
889  msg.pressure_alt = air_data.baro_alt_meter;
890  msg.temperature = air_data.baro_temp_celcius;
891  msg.fields_updated = fields_updated;
892 
893  mavlink_msg_highres_imu_send_struct(_mavlink->get_channel(), &msg);
894 
895  return true;
896  }
897 
898  return false;
899  }
900 };
901 
902 
904 {
905 public:
906  const char *get_name() const override
907  {
909  }
910 
911  static const char *get_name_static()
912  {
913  return "SCALED_IMU";
914  }
915 
916  static uint16_t get_id_static()
917  {
918  return MAVLINK_MSG_ID_SCALED_IMU;
919  }
920 
921  uint16_t get_id() override
922  {
923  return get_id_static();
924  }
925 
927  {
928  return new MavlinkStreamScaledIMU(mavlink);
929  }
930 
931  unsigned get_size() override
932  {
933  return _raw_accel_sub->is_published() ? (MAVLINK_MSG_ID_SCALED_IMU_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES) : 0;
934  }
935 
936 private:
940 
941  uint64_t _raw_accel_time;
942  uint64_t _raw_gyro_time;
943  uint64_t _raw_mag_time;
944 
945  // do not allow top copy this class
948 
949 protected:
950  explicit MavlinkStreamScaledIMU(Mavlink *mavlink) : MavlinkStream(mavlink),
951  _raw_accel_sub(_mavlink->add_orb_subscription(ORB_ID(sensor_accel), 0)),
952  _raw_gyro_sub(_mavlink->add_orb_subscription(ORB_ID(sensor_gyro), 0)),
953  _raw_mag_sub(_mavlink->add_orb_subscription(ORB_ID(sensor_mag), 0)),
954  _raw_accel_time(0),
955  _raw_gyro_time(0),
956  _raw_mag_time(0)
957  {}
958 
959  bool send(const hrt_abstime t) override
960  {
961  sensor_accel_s sensor_accel = {};
962  sensor_gyro_s sensor_gyro = {};
963  sensor_mag_s sensor_mag = {};
964 
965  bool updated = false;
966  updated |= _raw_accel_sub->update(&_raw_accel_time, &sensor_accel);
967  updated |= _raw_gyro_sub->update(&_raw_gyro_time, &sensor_gyro);
968  updated |= _raw_mag_sub->update(&_raw_mag_time, &sensor_mag);
969 
970  if (updated) {
971 
972  mavlink_scaled_imu_t msg = {};
973 
974  msg.time_boot_ms = sensor_accel.timestamp / 1000;
975  msg.xacc = (int16_t)(sensor_accel.x_raw / CONSTANTS_ONE_G); // [milli g]
976  msg.yacc = (int16_t)(sensor_accel.y_raw / CONSTANTS_ONE_G); // [milli g]
977  msg.zacc = (int16_t)(sensor_accel.z_raw / CONSTANTS_ONE_G); // [milli g]
978  msg.xgyro = sensor_gyro.x_raw; // [milli rad/s]
979  msg.ygyro = sensor_gyro.y_raw; // [milli rad/s]
980  msg.zgyro = sensor_gyro.z_raw; // [milli rad/s]
981  msg.xmag = sensor_mag.x_raw; // [milli tesla]
982  msg.ymag = sensor_mag.y_raw; // [milli tesla]
983  msg.zmag = sensor_mag.z_raw; // [milli tesla]
984 
985  mavlink_msg_scaled_imu_send_struct(_mavlink->get_channel(), &msg);
986 
987  return true;
988  }
989 
990  return false;
991  }
992 };
993 
994 
996 {
997 public:
998  const char *get_name() const override
999  {
1001  }
1002 
1003  static const char *get_name_static()
1004  {
1005  return "SCALED_IMU2";
1006  }
1007 
1008  static uint16_t get_id_static()
1009  {
1010  return MAVLINK_MSG_ID_SCALED_IMU2;
1011  }
1012 
1013  uint16_t get_id() override
1014  {
1015  return get_id_static();
1016  }
1017 
1019  {
1020  return new MavlinkStreamScaledIMU2(mavlink);
1021  }
1022 
1023  unsigned get_size() override
1024  {
1025  return _raw_accel_sub->is_published() ? (MAVLINK_MSG_ID_SCALED_IMU2_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES) : 0;
1026  }
1027 
1028 private:
1032 
1034  uint64_t _raw_gyro_time;
1035  uint64_t _raw_mag_time;
1036 
1037  // do not allow top copy this class
1040 
1041 protected:
1042  explicit MavlinkStreamScaledIMU2(Mavlink *mavlink) : MavlinkStream(mavlink),
1043  _raw_accel_sub(_mavlink->add_orb_subscription(ORB_ID(sensor_accel), 1)),
1044  _raw_gyro_sub(_mavlink->add_orb_subscription(ORB_ID(sensor_gyro), 1)),
1045  _raw_mag_sub(_mavlink->add_orb_subscription(ORB_ID(sensor_mag), 1)),
1046  _raw_accel_time(0),
1047  _raw_gyro_time(0),
1048  _raw_mag_time(0)
1049  {}
1050 
1051  bool send(const hrt_abstime t) override
1052  {
1053  sensor_accel_s sensor_accel = {};
1054  sensor_gyro_s sensor_gyro = {};
1055  sensor_mag_s sensor_mag = {};
1056 
1057  bool updated = false;
1058  updated |= _raw_accel_sub->update(&_raw_accel_time, &sensor_accel);
1059  updated |= _raw_gyro_sub->update(&_raw_gyro_time, &sensor_gyro);
1060  updated |= _raw_mag_sub->update(&_raw_mag_time, &sensor_mag);
1061 
1062  if (updated) {
1063 
1064  mavlink_scaled_imu2_t msg = {};
1065 
1066  msg.time_boot_ms = sensor_accel.timestamp / 1000;
1067  msg.xacc = (int16_t)(sensor_accel.x_raw / CONSTANTS_ONE_G); // [milli g]
1068  msg.yacc = (int16_t)(sensor_accel.y_raw / CONSTANTS_ONE_G); // [milli g]
1069  msg.zacc = (int16_t)(sensor_accel.z_raw / CONSTANTS_ONE_G); // [milli g]
1070  msg.xgyro = sensor_gyro.x_raw; // [milli rad/s]
1071  msg.ygyro = sensor_gyro.y_raw; // [milli rad/s]
1072  msg.zgyro = sensor_gyro.z_raw; // [milli rad/s]
1073  msg.xmag = sensor_mag.x_raw; // [milli tesla]
1074  msg.ymag = sensor_mag.y_raw; // [milli tesla]
1075  msg.zmag = sensor_mag.z_raw; // [milli tesla]
1076 
1077  mavlink_msg_scaled_imu2_send_struct(_mavlink->get_channel(), &msg);
1078 
1079  return true;
1080  }
1081 
1082  return false;
1083  }
1084 };
1085 
1087 {
1088 public:
1089  const char *get_name() const override
1090  {
1092  }
1093 
1094  static const char *get_name_static()
1095  {
1096  return "SCALED_IMU3";
1097  }
1098 
1099  static uint16_t get_id_static()
1100  {
1101  return MAVLINK_MSG_ID_SCALED_IMU3;
1102  }
1103 
1104  uint16_t get_id() override
1105  {
1106  return get_id_static();
1107  }
1108 
1110  {
1111  return new MavlinkStreamScaledIMU3(mavlink);
1112  }
1113 
1114  unsigned get_size() override
1115  {
1116  return _raw_accel_sub->is_published() ? (MAVLINK_MSG_ID_SCALED_IMU3_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES) : 0;
1117  }
1118 
1119 private:
1123 
1125  uint64_t _raw_gyro_time;
1126  uint64_t _raw_mag_time;
1127 
1128  // do not allow top copy this class
1131 
1132 protected:
1133  explicit MavlinkStreamScaledIMU3(Mavlink *mavlink) : MavlinkStream(mavlink),
1134  _raw_accel_sub(_mavlink->add_orb_subscription(ORB_ID(sensor_accel), 2)),
1135  _raw_gyro_sub(_mavlink->add_orb_subscription(ORB_ID(sensor_gyro), 2)),
1136  _raw_mag_sub(_mavlink->add_orb_subscription(ORB_ID(sensor_mag), 2)),
1137  _raw_accel_time(0),
1138  _raw_gyro_time(0),
1139  _raw_mag_time(0)
1140  {}
1141 
1142  bool send(const hrt_abstime t) override
1143  {
1144  sensor_accel_s sensor_accel = {};
1145  sensor_gyro_s sensor_gyro = {};
1146  sensor_mag_s sensor_mag = {};
1147 
1148  bool updated = false;
1149  updated |= _raw_accel_sub->update(&_raw_accel_time, &sensor_accel);
1150  updated |= _raw_gyro_sub->update(&_raw_gyro_time, &sensor_gyro);
1151  updated |= _raw_mag_sub->update(&_raw_mag_time, &sensor_mag);
1152 
1153  if (updated) {
1154 
1155  mavlink_scaled_imu3_t msg = {};
1156 
1157  msg.time_boot_ms = sensor_accel.timestamp / 1000;
1158  msg.xacc = (int16_t)(sensor_accel.x_raw / CONSTANTS_ONE_G); // [milli g]
1159  msg.yacc = (int16_t)(sensor_accel.y_raw / CONSTANTS_ONE_G); // [milli g]
1160  msg.zacc = (int16_t)(sensor_accel.z_raw / CONSTANTS_ONE_G); // [milli g]
1161  msg.xgyro = sensor_gyro.x_raw; // [milli rad/s]
1162  msg.ygyro = sensor_gyro.y_raw; // [milli rad/s]
1163  msg.zgyro = sensor_gyro.z_raw; // [milli rad/s]
1164  msg.xmag = sensor_mag.x_raw; // [milli tesla]
1165  msg.ymag = sensor_mag.y_raw; // [milli tesla]
1166  msg.zmag = sensor_mag.z_raw; // [milli tesla]
1167 
1168  mavlink_msg_scaled_imu3_send_struct(_mavlink->get_channel(), &msg);
1169 
1170  return true;
1171  }
1172 
1173  return false;
1174  }
1175 };
1176 
1177 
1179 {
1180 public:
1181  const char *get_name() const override
1182  {
1184  }
1185 
1186  static const char *get_name_static()
1187  {
1188  return "ATTITUDE";
1189  }
1190 
1191  static uint16_t get_id_static()
1192  {
1193  return MAVLINK_MSG_ID_ATTITUDE;
1194  }
1195 
1196  uint16_t get_id() override
1197  {
1198  return get_id_static();
1199  }
1200 
1202  {
1203  return new MavlinkStreamAttitude(mavlink);
1204  }
1205 
1206  unsigned get_size() override
1207  {
1208  return MAVLINK_MSG_ID_ATTITUDE_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
1209  }
1210 
1211 private:
1214  uint64_t _att_time{0};
1215 
1216  /* do not allow top copying this class */
1219 
1220 
1221 protected:
1222  explicit MavlinkStreamAttitude(Mavlink *mavlink) : MavlinkStream(mavlink),
1223  _att_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_attitude))),
1224  _angular_velocity_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_angular_velocity)))
1225  {}
1226 
1227  bool send(const hrt_abstime t) override
1228  {
1229  vehicle_attitude_s att;
1230 
1231  if (_att_sub->update(&_att_time, &att)) {
1232  vehicle_angular_velocity_s angular_velocity{};
1233  _angular_velocity_sub->update(&angular_velocity);
1234 
1235  mavlink_attitude_t msg{};
1236 
1237  const matrix::Eulerf euler = matrix::Quatf(att.q);
1238  msg.time_boot_ms = att.timestamp / 1000;
1239  msg.roll = euler.phi();
1240  msg.pitch = euler.theta();
1241  msg.yaw = euler.psi();
1242 
1243  msg.rollspeed = angular_velocity.xyz[0];
1244  msg.pitchspeed = angular_velocity.xyz[1];
1245  msg.yawspeed = angular_velocity.xyz[2];
1246 
1247  mavlink_msg_attitude_send_struct(_mavlink->get_channel(), &msg);
1248 
1249  return true;
1250  }
1251 
1252  return false;
1253  }
1254 };
1255 
1256 
1258 {
1259 public:
1260  const char *get_name() const override
1261  {
1263  }
1264 
1265  static const char *get_name_static()
1266  {
1267  return "ATTITUDE_QUATERNION";
1268  }
1269 
1270  static uint16_t get_id_static()
1271  {
1272  return MAVLINK_MSG_ID_ATTITUDE_QUATERNION;
1273  }
1274 
1275  uint16_t get_id() override
1276  {
1277  return get_id_static();
1278  }
1279 
1281  {
1282  return new MavlinkStreamAttitudeQuaternion(mavlink);
1283  }
1284 
1285  unsigned get_size() override
1286  {
1287  return MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
1288  }
1289 
1290 private:
1294  uint64_t _att_time{0};
1295 
1296  /* do not allow top copying this class */
1299 
1300 protected:
1302  _att_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_attitude))),
1303  _angular_velocity_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_angular_velocity))),
1304  _status_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_status)))
1305  {}
1306 
1307  bool send(const hrt_abstime t) override
1308  {
1309  vehicle_attitude_s att;
1310 
1311  if (_att_sub->update(&_att_time, &att)) {
1312  vehicle_angular_velocity_s angular_velocity{};
1313  _angular_velocity_sub->update(&angular_velocity);
1314 
1316  _status_sub->update(&status);
1317 
1318  mavlink_attitude_quaternion_t msg{};
1319 
1320  msg.time_boot_ms = att.timestamp / 1000;
1321  msg.q1 = att.q[0];
1322  msg.q2 = att.q[1];
1323  msg.q3 = att.q[2];
1324  msg.q4 = att.q[3];
1325  msg.rollspeed = angular_velocity.xyz[0];
1326  msg.pitchspeed = angular_velocity.xyz[1];
1327  msg.yawspeed = angular_velocity.xyz[2];
1328 
1330  // This is a tailsitter VTOL flying in fixed wing mode:
1331  // indicate that reported attitude should be rotated by
1332  // 90 degrees upward pitch for user display
1334 
1335  } else {
1336  // Normal case
1337  // zero rotation should be [1 0 0 0]:
1338  // `get_rot_quaternion(ROTATION_NONE).copyTo(msg.repr_offset_q);`
1339  // but to save bandwidth, we instead send [0, 0, 0, 0].
1340  msg.repr_offset_q[0] = 0.0f;
1341  msg.repr_offset_q[1] = 0.0f;
1342  msg.repr_offset_q[2] = 0.0f;
1343  msg.repr_offset_q[3] = 0.0f;
1344  }
1345 
1346  mavlink_msg_attitude_quaternion_send_struct(_mavlink->get_channel(), &msg);
1347 
1348  return true;
1349  }
1350 
1351  return false;
1352  }
1353 };
1354 
1356 {
1357 public:
1358 
1359  const char *get_name() const override
1360  {
1362  }
1363 
1364  static const char *get_name_static()
1365  {
1366  return "VFR_HUD";
1367  }
1368 
1369  static uint16_t get_id_static()
1370  {
1371  return MAVLINK_MSG_ID_VFR_HUD;
1372  }
1373 
1374  uint16_t get_id() override
1375  {
1376  return get_id_static();
1377  }
1378 
1380  {
1381  return new MavlinkStreamVFRHUD(mavlink);
1382  }
1383 
1384  unsigned get_size() override
1385  {
1386  return MAVLINK_MSG_ID_VFR_HUD_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
1387  }
1388 
1389 private:
1391  uint64_t _pos_time;
1392 
1394  uint64_t _armed_time;
1395 
1398 
1400  uint64_t _airspeed_time;
1401 
1403 
1404  /* do not allow top copying this class */
1407 
1408 protected:
1409  explicit MavlinkStreamVFRHUD(Mavlink *mavlink) : MavlinkStream(mavlink),
1410  _pos_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_local_position))),
1411  _pos_time(0),
1412  _armed_sub(_mavlink->add_orb_subscription(ORB_ID(actuator_armed))),
1413  _armed_time(0),
1414  _act0_sub(_mavlink->add_orb_subscription(ORB_ID(actuator_controls_0))),
1415  _act1_sub(_mavlink->add_orb_subscription(ORB_ID(actuator_controls_1))),
1416  _airspeed_sub(_mavlink->add_orb_subscription(ORB_ID(airspeed))),
1417  _airspeed_time(0),
1418  _air_data_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_air_data)))
1419  {}
1420 
1421  bool send(const hrt_abstime t) override
1422  {
1423  vehicle_local_position_s pos = {};
1424  actuator_armed_s armed = {};
1425  airspeed_s airspeed = {};
1426 
1427  bool updated = false;
1428  updated |= _pos_sub->update(&_pos_time, &pos);
1429  updated |= _armed_sub->update(&_armed_time, &armed);
1430  updated |= _airspeed_sub->update(&_airspeed_time, &airspeed);
1431 
1432  if (updated) {
1433  mavlink_vfr_hud_t msg = {};
1434  msg.airspeed = airspeed.indicated_airspeed_m_s;
1435  msg.groundspeed = sqrtf(pos.vx * pos.vx + pos.vy * pos.vy);
1436  msg.heading = math::degrees(wrap_2pi(pos.yaw));
1437 
1438  if (armed.armed) {
1439  actuator_controls_s act0 = {};
1440  actuator_controls_s act1 = {};
1441  _act0_sub->update(&act0);
1442  _act1_sub->update(&act1);
1443 
1444  // VFR_HUD throttle should only be used for operator feedback.
1445  // VTOLs switch between actuator_controls_0 and actuator_controls_1. During transition there isn't a
1446  // a single throttle value, but this should still be a useful heuristic for operator awareness.
1447  //
1448  // Use ACTUATOR_CONTROL_TARGET if accurate states are needed.
1449  msg.throttle = 100 * math::max(
1450  act0.control[actuator_controls_s::INDEX_THROTTLE],
1451  act1.control[actuator_controls_s::INDEX_THROTTLE]);
1452 
1453  } else {
1454  msg.throttle = 0.0f;
1455  }
1456 
1457  if (pos.z_valid && pos.z_global) {
1458  /* use local position estimate */
1459  msg.alt = -pos.z + pos.ref_alt;
1460 
1461  } else {
1462  vehicle_air_data_s air_data = {};
1463  _air_data_sub->update(&air_data);
1464 
1465  /* fall back to baro altitude */
1466  if (air_data.timestamp > 0) {
1467  msg.alt = air_data.baro_alt_meter;
1468  }
1469  }
1470 
1471  if (pos.v_z_valid) {
1472  msg.climb = -pos.vz;
1473  }
1474 
1475  mavlink_msg_vfr_hud_send_struct(_mavlink->get_channel(), &msg);
1476 
1477  return true;
1478  }
1479 
1480  return false;
1481  }
1482 };
1483 
1484 
1486 {
1487 public:
1488  const char *get_name() const override
1489  {
1491  }
1492 
1493  static const char *get_name_static()
1494  {
1495  return "GPS_RAW_INT";
1496  }
1497 
1498  static uint16_t get_id_static()
1499  {
1500  return MAVLINK_MSG_ID_GPS_RAW_INT;
1501  }
1502 
1503  uint16_t get_id() override
1504  {
1505  return get_id_static();
1506  }
1507 
1509  {
1510  return new MavlinkStreamGPSRawInt(mavlink);
1511  }
1512 
1513  unsigned get_size() override
1514  {
1515  return MAVLINK_MSG_ID_GPS_RAW_INT_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
1516  }
1517 
1518 private:
1520  uint64_t _gps_time;
1521 
1522  /* do not allow top copying this class */
1525 
1526 protected:
1527  explicit MavlinkStreamGPSRawInt(Mavlink *mavlink) : MavlinkStream(mavlink),
1528  _gps_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_gps_position))),
1529  _gps_time(0)
1530  {}
1531 
1532  bool send(const hrt_abstime t) override
1533  {
1535 
1536  if (_gps_sub->update(&_gps_time, &gps)) {
1537  mavlink_gps_raw_int_t msg = {};
1538 
1539  msg.time_usec = gps.timestamp;
1540  msg.fix_type = gps.fix_type;
1541  msg.lat = gps.lat;
1542  msg.lon = gps.lon;
1543  msg.alt = gps.alt;
1544  msg.alt_ellipsoid = gps.alt_ellipsoid;
1545  msg.eph = gps.hdop * 100;
1546  msg.epv = gps.vdop * 100;
1547  msg.h_acc = gps.eph * 1e3f;
1548  msg.v_acc = gps.epv * 1e3f;
1549  msg.vel_acc = gps.s_variance_m_s * 1e3f;
1550  msg.hdg_acc = gps.c_variance_rad * 1e5f / M_DEG_TO_RAD_F;
1551  msg.vel = cm_uint16_from_m_float(gps.vel_m_s);
1552  msg.cog = math::degrees(wrap_2pi(gps.cog_rad)) * 1e2f;
1553  msg.satellites_visible = gps.satellites_used;
1554 
1555  mavlink_msg_gps_raw_int_send_struct(_mavlink->get_channel(), &msg);
1556 
1557  return true;
1558  }
1559 
1560  return false;
1561  }
1562 };
1563 
1565 {
1566 public:
1567  const char *get_name() const override
1568  {
1570  }
1571 
1572  static const char *get_name_static()
1573  {
1574  return "GPS2_RAW";
1575  }
1576 
1577  static uint16_t get_id_static()
1578  {
1579  return MAVLINK_MSG_ID_GPS2_RAW;
1580  }
1581 
1582  uint16_t get_id() override
1583  {
1584  return get_id_static();
1585  }
1586 
1588  {
1589  return new MavlinkStreamGPS2Raw(mavlink);
1590  }
1591 
1592  unsigned get_size() override
1593  {
1594  return (_gps_time > 0) ? (MAVLINK_MSG_ID_GPS2_RAW_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES) : 0;
1595  }
1596 
1597 private:
1599  uint64_t _gps_time;
1600 
1601  /* do not allow top copying this class */
1604 
1605 protected:
1606  explicit MavlinkStreamGPS2Raw(Mavlink *mavlink) : MavlinkStream(mavlink),
1607  _gps_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_gps_position), 1)),
1608  _gps_time(0)
1609  {}
1610 
1611  bool send(const hrt_abstime t) override
1612  {
1614 
1615  if (_gps_sub->update(&_gps_time, &gps)) {
1616  mavlink_gps2_raw_t msg = {};
1617 
1618  msg.time_usec = gps.timestamp;
1619  msg.fix_type = gps.fix_type;
1620  msg.lat = gps.lat;
1621  msg.lon = gps.lon;
1622  msg.alt = gps.alt;
1623  msg.eph = gps.eph * 1e3f;
1624  msg.epv = gps.epv * 1e3f;
1625  msg.vel = cm_uint16_from_m_float(gps.vel_m_s);
1626  msg.cog = math::degrees(wrap_2pi(gps.cog_rad)) * 1e2f;
1627  msg.satellites_visible = gps.satellites_used;
1628  //msg.dgps_numch = // Number of DGPS satellites
1629  //msg.dgps_age = // Age of DGPS info
1630 
1631  mavlink_msg_gps2_raw_send_struct(_mavlink->get_channel(), &msg);
1632 
1633  return true;
1634  }
1635 
1636  return false;
1637  }
1638 };
1639 
1641 {
1642 public:
1643  const char *get_name() const override
1644  {
1646  }
1647 
1648  static const char *get_name_static()
1649  {
1650  return "SYSTEM_TIME";
1651  }
1652 
1653  static uint16_t get_id_static()
1654  {
1655  return MAVLINK_MSG_ID_SYSTEM_TIME;
1656  }
1657 
1658  uint16_t get_id() override
1659  {
1660  return get_id_static();
1661  }
1662 
1664  {
1665  return new MavlinkStreamSystemTime(mavlink);
1666  }
1667 
1668  unsigned get_size() override
1669  {
1670  return MAVLINK_MSG_ID_SYSTEM_TIME_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
1671  }
1672 
1673 private:
1674  /* do not allow top copying this class */
1677 
1678 protected:
1679  explicit MavlinkStreamSystemTime(Mavlink *mavlink) : MavlinkStream(mavlink)
1680  {}
1681 
1682  bool send(const hrt_abstime t) override
1683  {
1684  mavlink_system_time_t msg = {};
1685  timespec tv;
1686 
1687  px4_clock_gettime(CLOCK_REALTIME, &tv);
1688 
1689  msg.time_boot_ms = hrt_absolute_time() / 1000;
1690  msg.time_unix_usec = (uint64_t)tv.tv_sec * 1000000 + tv.tv_nsec / 1000;
1691 
1692  // If the time is before 2001-01-01, it's probably the default 2000
1693  // and we don't need to bother sending it because it's definitely wrong.
1694  if (msg.time_unix_usec > 978307200000000) {
1695  mavlink_msg_system_time_send_struct(_mavlink->get_channel(), &msg);
1696  return true;
1697  }
1698 
1699  return false;
1700  }
1701 };
1702 
1704 {
1705 public:
1706  const char *get_name() const override
1707  {
1709  }
1710 
1711  static const char *get_name_static()
1712  {
1713  return "TIMESYNC";
1714  }
1715 
1716  static uint16_t get_id_static()
1717  {
1718  return MAVLINK_MSG_ID_TIMESYNC;
1719  }
1720 
1721  uint16_t get_id() override
1722  {
1723  return get_id_static();
1724  }
1725 
1727  {
1728  return new MavlinkStreamTimesync(mavlink);
1729  }
1730 
1731  unsigned get_size() override
1732  {
1733  return MAVLINK_MSG_ID_TIMESYNC_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
1734  }
1735 
1736 private:
1737  /* do not allow top copying this class */
1740 
1741 protected:
1742  explicit MavlinkStreamTimesync(Mavlink *mavlink) : MavlinkStream(mavlink)
1743  {}
1744 
1745  bool send(const hrt_abstime t) override
1746  {
1747  mavlink_timesync_t msg = {};
1748 
1749  msg.tc1 = 0;
1750  msg.ts1 = hrt_absolute_time() * 1000; // boot time in nanoseconds
1751 
1752  mavlink_msg_timesync_send_struct(_mavlink->get_channel(), &msg);
1753 
1754  return true;
1755  }
1756 };
1757 
1759 {
1760 public:
1761  const char *get_name() const override
1762  {
1764  }
1765 
1766  static const char *get_name_static()
1767  {
1768  return "ADSB_VEHICLE";
1769  }
1770 
1771  static uint16_t get_id_static()
1772  {
1773  return MAVLINK_MSG_ID_ADSB_VEHICLE;
1774  }
1775 
1776  uint16_t get_id() override
1777  {
1778  return get_id_static();
1779  }
1780 
1782  {
1783  return new MavlinkStreamADSBVehicle(mavlink);
1784  }
1785 
1786  bool const_rate() override
1787  {
1788  return true;
1789  }
1790 
1791  unsigned get_size() override
1792  {
1793  return (_pos_time > 0) ? MAVLINK_MSG_ID_ADSB_VEHICLE_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES : 0;
1794  }
1795 
1796 private:
1798  uint64_t _pos_time;
1799 
1800  /* do not allow top copying this class */
1803 
1804 protected:
1805  explicit MavlinkStreamADSBVehicle(Mavlink *mavlink) : MavlinkStream(mavlink),
1806  _pos_sub(_mavlink->add_orb_subscription(ORB_ID(transponder_report))),
1807  _pos_time(0)
1808  {}
1809 
1810  bool send(const hrt_abstime t) override
1811  {
1812  struct transponder_report_s pos;
1813  bool sent = false;
1814 
1815  while (_pos_sub->update(&_pos_time, &pos)) {
1816  mavlink_adsb_vehicle_t msg = {};
1817 
1818  if (!(pos.flags & transponder_report_s::PX4_ADSB_FLAGS_RETRANSLATE)) { continue; }
1819 
1820  msg.ICAO_address = pos.icao_address;
1821  msg.lat = pos.lat * 1e7;
1822  msg.lon = pos.lon * 1e7;
1823  msg.altitude_type = pos.altitude_type;
1824  msg.altitude = pos.altitude * 1e3f;
1825  msg.heading = (pos.heading + M_PI_F) / M_PI_F * 180.0f * 100.0f;
1826  msg.hor_velocity = pos.hor_velocity * 100.0f;
1827  msg.ver_velocity = pos.ver_velocity * 100.0f;
1828  memcpy(&msg.callsign[0], &pos.callsign[0], sizeof(msg.callsign));
1829  msg.emitter_type = pos.emitter_type;
1830  msg.tslc = pos.tslc;
1831  msg.squawk = pos.squawk;
1832 
1833  msg.flags = 0;
1834 
1835  if (pos.flags & transponder_report_s::PX4_ADSB_FLAGS_VALID_COORDS) { msg.flags |= ADSB_FLAGS_VALID_COORDS; }
1836 
1837  if (pos.flags & transponder_report_s::PX4_ADSB_FLAGS_VALID_ALTITUDE) { msg.flags |= ADSB_FLAGS_VALID_ALTITUDE; }
1838 
1839  if (pos.flags & transponder_report_s::PX4_ADSB_FLAGS_VALID_HEADING) { msg.flags |= ADSB_FLAGS_VALID_HEADING; }
1840 
1841  if (pos.flags & transponder_report_s::PX4_ADSB_FLAGS_VALID_VELOCITY) { msg.flags |= ADSB_FLAGS_VALID_VELOCITY; }
1842 
1843  if (pos.flags & transponder_report_s::PX4_ADSB_FLAGS_VALID_CALLSIGN) { msg.flags |= ADSB_FLAGS_VALID_CALLSIGN; }
1844 
1845  if (pos.flags & transponder_report_s::PX4_ADSB_FLAGS_VALID_SQUAWK) { msg.flags |= ADSB_FLAGS_VALID_SQUAWK; }
1846 
1847  mavlink_msg_adsb_vehicle_send_struct(_mavlink->get_channel(), &msg);
1848  sent = true;
1849  }
1850 
1851  return sent;
1852  }
1853 };
1854 
1856 {
1857 public:
1858  const char *get_name() const override
1859  {
1861  }
1862 
1863  static const char *get_name_static()
1864  {
1865  return "UTM_GLOBAL_POSITION";
1866  }
1867 
1868  static uint16_t get_id_static()
1869  {
1870  return MAVLINK_MSG_ID_UTM_GLOBAL_POSITION;
1871  }
1872 
1873  uint16_t get_id() override
1874  {
1875  return get_id_static();
1876  }
1877 
1879  {
1880  return new MavlinkStreamUTMGlobalPosition(mavlink);
1881  }
1882 
1883  bool const_rate() override
1884  {
1885  return true;
1886  }
1887 
1888  unsigned get_size() override
1889  {
1890  return _local_pos_time > 0 ? MAVLINK_MSG_ID_UTM_GLOBAL_POSITION_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES : 0;
1891  }
1892 
1893 private:
1895  uint64_t _local_pos_time = 0;
1896  vehicle_local_position_s _local_position = {};
1897 
1899  uint64_t _global_pos_time = 0;
1900  vehicle_global_position_s _global_position = {};
1901 
1903  uint64_t _setpoint_triplet_time = 0;
1904  position_setpoint_triplet_s _setpoint_triplet = {};
1905 
1907  uint64_t _vehicle_status_time = 0;
1908  vehicle_status_s _vehicle_status = {};
1909 
1911  uint64_t _land_detected_time = 0;
1912  vehicle_land_detected_s _land_detected = {};
1913 
1914  /* do not allow top copying this class */
1917 
1918 protected:
1920  _local_pos_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_local_position))),
1921  _global_pos_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_global_position))),
1922  _position_setpoint_triplet_sub(_mavlink->add_orb_subscription(ORB_ID(position_setpoint_triplet))),
1923  _vehicle_status_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_status))),
1924  _land_detected_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_land_detected)))
1925  {}
1926 
1927  bool send(const hrt_abstime t) override
1928  {
1929 
1930  // Check if new uORB messages are available otherwise use the last received
1931  _local_pos_sub->update(&_local_pos_time, &_local_position);
1932  _global_pos_sub->update(&_global_pos_time, &_global_position);
1933  _position_setpoint_triplet_sub->update(&_setpoint_triplet_time, &_setpoint_triplet);
1934  _vehicle_status_sub->update(&_vehicle_status_time, &_vehicle_status);
1935  _land_detected_sub->update(&_land_detected_time, &_land_detected);
1936 
1937  mavlink_utm_global_position_t msg = {};
1938 
1939  // Compute Unix epoch and set time field
1940  timespec tv;
1941  px4_clock_gettime(CLOCK_REALTIME, &tv);
1942  uint64_t unix_epoch = (uint64_t)tv.tv_sec * 1000000 + tv.tv_nsec / 1000;
1943 
1944  // If the time is before 2001-01-01, it's probably the default 2000
1945  if (unix_epoch > 978307200000000) {
1946  msg.time = unix_epoch;
1947  msg.flags |= UTM_DATA_AVAIL_FLAGS_TIME_VALID;
1948  }
1949 
1950 #ifndef BOARD_HAS_NO_UUID
1951  px4_guid_t px4_guid;
1952  board_get_px4_guid(px4_guid);
1953  static_assert(sizeof(px4_guid_t) == sizeof(msg.uas_id), "GUID byte length mismatch");
1954  memcpy(&msg.uas_id, &px4_guid, sizeof(msg.uas_id));
1955  msg.flags |= UTM_DATA_AVAIL_FLAGS_UAS_ID_AVAILABLE;
1956 #else
1957  // TODO Fill ID with something reasonable
1958  memset(&msg.uas_id[0], 0, sizeof(msg.uas_id));
1959 #endif /* BOARD_HAS_NO_UUID */
1960 
1961  // Handle global position
1962  if (_global_pos_time > 0) {
1963  msg.lat = _global_position.lat * 1e7;
1964  msg.lon = _global_position.lon * 1e7;
1965  msg.alt = _global_position.alt_ellipsoid * 1000.0f;
1966 
1967  msg.h_acc = _global_position.eph * 1000.0f;
1968  msg.v_acc = _global_position.epv * 1000.0f;
1969 
1970  msg.flags |= UTM_DATA_AVAIL_FLAGS_POSITION_AVAILABLE;
1971  msg.flags |= UTM_DATA_AVAIL_FLAGS_ALTITUDE_AVAILABLE;
1972  }
1973 
1974  // Handle local position
1975  if (_local_pos_time > 0) {
1976  float evh = 0.0f;
1977  float evv = 0.0f;
1978 
1979  if (_local_position.v_xy_valid) {
1980  msg.vx = _local_position.vx * 100.0f;
1981  msg.vy = _local_position.vy * 100.0f;
1982  evh = _local_position.evh;
1983  msg.flags |= UTM_DATA_AVAIL_FLAGS_HORIZONTAL_VELO_AVAILABLE;
1984  }
1985 
1986  if (_local_position.v_z_valid) {
1987  msg.vz = _local_position.vz * 100.0f;
1988  evv = _local_position.evv;
1989  msg.flags |= UTM_DATA_AVAIL_FLAGS_VERTICAL_VELO_AVAILABLE;
1990  }
1991 
1992  msg.vel_acc = sqrtf(evh * evh + evv * evv) * 100.0f;
1993 
1994  if (_local_position.dist_bottom_valid) {
1995  msg.relative_alt = _local_position.dist_bottom * 1000.0f;
1996  msg.flags |= UTM_DATA_AVAIL_FLAGS_RELATIVE_ALTITUDE_AVAILABLE;
1997  }
1998  }
1999 
2000  bool vehicle_in_auto_mode = _vehicle_status_time > 0
2001  && (_vehicle_status.nav_state == vehicle_status_s::NAVIGATION_STATE_AUTO_FOLLOW_TARGET
2002  || _vehicle_status.nav_state == vehicle_status_s::NAVIGATION_STATE_AUTO_RTGS
2003  || _vehicle_status.nav_state == vehicle_status_s::NAVIGATION_STATE_AUTO_LAND
2004  || _vehicle_status.nav_state == vehicle_status_s::NAVIGATION_STATE_AUTO_LANDENGFAIL
2005  || _vehicle_status.nav_state == vehicle_status_s::NAVIGATION_STATE_AUTO_PRECLAND
2006  || _vehicle_status.nav_state == vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION
2007  || _vehicle_status.nav_state == vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER
2008  || _vehicle_status.nav_state == vehicle_status_s::NAVIGATION_STATE_AUTO_TAKEOFF
2009  || _vehicle_status.nav_state == vehicle_status_s::NAVIGATION_STATE_AUTO_RTL
2010  || _vehicle_status.nav_state == vehicle_status_s::NAVIGATION_STATE_AUTO_RCRECOVER);
2011 
2012  // Handle next waypoint if it is valid
2013  if (vehicle_in_auto_mode && _setpoint_triplet_time > 0 && _setpoint_triplet.current.valid) {
2014  msg.next_lat = _setpoint_triplet.current.lat * 1e7;
2015  msg.next_lon = _setpoint_triplet.current.lon * 1e7;
2016  // HACK We assume that the offset between AMSL and WGS84 is constant between the current
2017  // vehicle position and the the target waypoint.
2018  msg.next_alt = (_setpoint_triplet.current.alt + (_global_position.alt_ellipsoid - _global_position.alt)) * 1000.0f;
2019  msg.flags |= UTM_DATA_AVAIL_FLAGS_NEXT_WAYPOINT_AVAILABLE;
2020  }
2021 
2022  // Handle flight state
2023  if (_vehicle_status_time > 0 && _land_detected_time > 0
2024  && _vehicle_status.arming_state == vehicle_status_s::ARMING_STATE_ARMED) {
2025  if (_land_detected.landed) {
2026  msg.flight_state |= UTM_FLIGHT_STATE_GROUND;
2027 
2028  } else {
2029  msg.flight_state |= UTM_FLIGHT_STATE_AIRBORNE;
2030  }
2031 
2032  } else {
2033  msg.flight_state |= UTM_FLIGHT_STATE_UNKNOWN;
2034  }
2035 
2036  msg.update_rate = 0; // Data driven mode
2037 
2038  mavlink_msg_utm_global_position_send_struct(_mavlink->get_channel(), &msg);
2039 
2040  return true;
2041  }
2042 };
2043 
2045 {
2046 public:
2047  const char *get_name() const override
2048  {
2050  }
2051 
2052  static const char *get_name_static()
2053  {
2054  return "COLLISION";
2055  }
2056 
2057  static uint16_t get_id_static()
2058  {
2059  return MAVLINK_MSG_ID_COLLISION;
2060  }
2061 
2062  uint16_t get_id() override
2063  {
2064  return get_id_static();
2065  }
2066 
2068  {
2069  return new MavlinkStreamCollision(mavlink);
2070  }
2071 
2072  unsigned get_size() override
2073  {
2074  return (_collision_time > 0) ? MAVLINK_MSG_ID_COLLISION_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES : 0;
2075  }
2076 
2077 private:
2080 
2081  /* do not allow top copying this class */
2084 
2085 protected:
2086  explicit MavlinkStreamCollision(Mavlink *mavlink) : MavlinkStream(mavlink),
2087  _collision_sub(_mavlink->add_orb_subscription(ORB_ID(collision_report))),
2088  _collision_time(0)
2089  {}
2090 
2091  bool send(const hrt_abstime t) override
2092  {
2093  struct collision_report_s report;
2094  bool sent = false;
2095 
2096  while (_collision_sub->update(&_collision_time, &report)) {
2097  mavlink_collision_t msg = {};
2098 
2099  msg.src = report.src;
2100  msg.id = report.id;
2101  msg.action = report.action;
2102  msg.threat_level = report.threat_level;
2103  msg.time_to_minimum_delta = report.time_to_minimum_delta;
2104  msg.altitude_minimum_delta = report.altitude_minimum_delta;
2105  msg.horizontal_minimum_delta = report.horizontal_minimum_delta;
2106 
2107  mavlink_msg_collision_send_struct(_mavlink->get_channel(), &msg);
2108  sent = true;
2109  }
2110 
2111  return sent;
2112  }
2113 };
2114 
2116 {
2117 public:
2118  const char *get_name() const override
2119  {
2121  }
2122 
2123  static const char *get_name_static()
2124  {
2125  return "CAMERA_TRIGGER";
2126  }
2127 
2128  static uint16_t get_id_static()
2129  {
2130  return MAVLINK_MSG_ID_CAMERA_TRIGGER;
2131  }
2132 
2133  uint16_t get_id() override
2134  {
2135  return get_id_static();
2136  }
2137 
2139  {
2140  return new MavlinkStreamCameraTrigger(mavlink);
2141  }
2142 
2143  bool const_rate() override
2144  {
2145  return true;
2146  }
2147 
2148  unsigned get_size() override
2149  {
2150  return (_trigger_time > 0) ? MAVLINK_MSG_ID_CAMERA_TRIGGER_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES : 0;
2151  }
2152 
2153 private:
2155  uint64_t _trigger_time;
2156 
2157  /* do not allow top copying this class */
2160 
2161 protected:
2162  explicit MavlinkStreamCameraTrigger(Mavlink *mavlink) : MavlinkStream(mavlink),
2163  _trigger_sub(_mavlink->add_orb_subscription(ORB_ID(camera_trigger))),
2164  _trigger_time(0)
2165  {}
2166 
2167  bool send(const hrt_abstime t) override
2168  {
2169  struct camera_trigger_s trigger;
2170 
2171  if (_trigger_sub->update(&_trigger_time, &trigger)) {
2172  mavlink_camera_trigger_t msg = {};
2173 
2174  msg.time_usec = trigger.timestamp;
2175  msg.seq = trigger.seq;
2176 
2177  /* ensure that only active trigger events are sent */
2178  if (trigger.timestamp > 0) {
2179 
2180  mavlink_msg_camera_trigger_send_struct(_mavlink->get_channel(), &msg);
2181 
2182  vehicle_command_s vcmd = {};
2183  vcmd.timestamp = hrt_absolute_time();
2184  vcmd.param1 = 0.0f; // all cameras
2185  vcmd.param2 = 0.0f; // duration 0 because only taking one picture
2186  vcmd.param3 = 1.0f; // only take one
2187  vcmd.param4 = NAN;
2188  vcmd.param5 = (double)NAN;
2189  vcmd.param6 = (double)NAN;
2190  vcmd.param7 = NAN;
2191  vcmd.command = MAV_CMD_IMAGE_START_CAPTURE;
2192  vcmd.target_system = mavlink_system.sysid;
2193  vcmd.target_component = MAV_COMP_ID_CAMERA;
2194 
2196 
2197  // TODO: move this camera_trigger and publish as a vehicle_command
2198  /* send MAV_CMD_DO_DIGICAM_CONTROL*/
2199  mavlink_command_long_t digicam_ctrl_cmd = {};
2200 
2201  digicam_ctrl_cmd.target_system = 0; // 0 for broadcast
2202  digicam_ctrl_cmd.target_component = MAV_COMP_ID_CAMERA;
2203  digicam_ctrl_cmd.command = MAV_CMD_DO_DIGICAM_CONTROL;
2204  digicam_ctrl_cmd.confirmation = 0;
2205  digicam_ctrl_cmd.param1 = NAN;
2206  digicam_ctrl_cmd.param2 = NAN;
2207  digicam_ctrl_cmd.param3 = NAN;
2208  digicam_ctrl_cmd.param4 = NAN;
2209  digicam_ctrl_cmd.param5 = 1; // take 1 picture
2210  digicam_ctrl_cmd.param6 = NAN;
2211  digicam_ctrl_cmd.param7 = NAN;
2212 
2213  mavlink_msg_command_long_send_struct(_mavlink->get_channel(), &digicam_ctrl_cmd);
2214 
2215  return true;
2216  }
2217  }
2218 
2219  return false;
2220  }
2221 };
2222 
2224 {
2225 public:
2226  const char *get_name() const override
2227  {
2229  }
2230 
2231  static const char *get_name_static()
2232  {
2233  return "CAMERA_IMAGE_CAPTURED";
2234  }
2235 
2236  static uint16_t get_id_static()
2237  {
2238  return MAVLINK_MSG_ID_CAMERA_IMAGE_CAPTURED;
2239  }
2240 
2241  uint16_t get_id() override
2242  {
2243  return get_id_static();
2244  }
2245 
2246  bool const_rate() override
2247  {
2248  return true;
2249  }
2250 
2252  {
2253  return new MavlinkStreamCameraImageCaptured(mavlink);
2254  }
2255 
2256  unsigned get_size() override
2257  {
2258  return (_capture_time > 0) ? MAVLINK_MSG_ID_CAMERA_IMAGE_CAPTURED_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES : 0;
2259  }
2260 
2261 private:
2263  uint64_t _capture_time;
2264 
2265  /* do not allow top copying this class */
2268 
2269 protected:
2271  _capture_sub(_mavlink->add_orb_subscription(ORB_ID(camera_capture))),
2272  _capture_time(0)
2273  {}
2274 
2275  bool send(const hrt_abstime t) override
2276  {
2277  struct camera_capture_s capture;
2278 
2279  if (_capture_sub->update(&_capture_time, &capture)) {
2280 
2281  mavlink_camera_image_captured_t msg;
2282 
2283  msg.time_boot_ms = capture.timestamp / 1000;
2284  msg.time_utc = capture.timestamp_utc;
2285  msg.camera_id = 1; // FIXME : get this from uORB
2286  msg.lat = capture.lat * 1e7;
2287  msg.lon = capture.lon * 1e7;
2288  msg.alt = capture.alt * 1e3f;
2289  msg.relative_alt = capture.ground_distance * 1e3f;
2290  msg.q[0] = capture.q[0];
2291  msg.q[1] = capture.q[1];
2292  msg.q[2] = capture.q[2];
2293  msg.q[3] = capture.q[3];
2294  msg.image_index = capture.seq;
2295  msg.capture_result = capture.result;
2296  msg.file_url[0] = '\0';
2297 
2298  mavlink_msg_camera_image_captured_send_struct(_mavlink->get_channel(), &msg);
2299 
2300  return true;
2301  }
2302 
2303  return false;
2304  }
2305 };
2306 
2308 {
2309 public:
2310  const char *get_name() const override
2311  {
2313  }
2314 
2315  static const char *get_name_static()
2316  {
2317  return "GLOBAL_POSITION_INT";
2318  }
2319 
2320  static uint16_t get_id_static()
2321  {
2322  return MAVLINK_MSG_ID_GLOBAL_POSITION_INT;
2323  }
2324 
2325  uint16_t get_id() override
2326  {
2327  return get_id_static();
2328  }
2329 
2331  {
2332  return new MavlinkStreamGlobalPositionInt(mavlink);
2333  }
2334 
2335  unsigned get_size() override
2336  {
2337  return MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
2338  }
2339 
2340 private:
2342  uint64_t _gpos_time;
2343 
2345  uint64_t _lpos_time;
2346 
2349 
2350  /* do not allow top copying this class */
2353 
2354 protected:
2356  _gpos_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_global_position))),
2357  _gpos_time(0),
2358  _lpos_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_local_position))),
2359  _lpos_time(0),
2360  _home_sub(_mavlink->add_orb_subscription(ORB_ID(home_position))),
2361  _air_data_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_air_data)))
2362  {}
2363 
2364  bool send(const hrt_abstime t) override
2365  {
2366  vehicle_global_position_s gpos = {};
2367  vehicle_local_position_s lpos = {};
2368 
2369  bool gpos_updated = _gpos_sub->update(&_gpos_time, &gpos);
2370  bool lpos_updated = _lpos_sub->update(&_lpos_time, &lpos);
2371 
2372  if (gpos_updated && lpos_updated) {
2373  mavlink_global_position_int_t msg = {};
2374 
2375  if (lpos.z_valid && lpos.z_global) {
2376  msg.alt = (-lpos.z + lpos.ref_alt) * 1000.0f;
2377 
2378  } else {
2379  // fall back to baro altitude
2380  vehicle_air_data_s air_data = {};
2381  _air_data_sub->update(&air_data);
2382 
2383  if (air_data.timestamp > 0) {
2384  msg.alt = air_data.baro_alt_meter * 1000.0f;
2385  }
2386  }
2387 
2388  home_position_s home = {};
2389  _home_sub->update(&home);
2390 
2391  if ((home.timestamp > 0) && home.valid_alt) {
2392  if (lpos.z_valid) {
2393  msg.relative_alt = -(lpos.z - home.z) * 1000.0f;
2394 
2395  } else {
2396  msg.relative_alt = msg.alt - (home.alt * 1000.0f);
2397  }
2398 
2399  } else {
2400  if (lpos.z_valid) {
2401  msg.relative_alt = -lpos.z * 1000.0f;
2402  }
2403  }
2404 
2405  msg.time_boot_ms = gpos.timestamp / 1000;
2406  msg.lat = gpos.lat * 1e7;
2407  msg.lon = gpos.lon * 1e7;
2408 
2409  msg.vx = lpos.vx * 100.0f;
2410  msg.vy = lpos.vy * 100.0f;
2411  msg.vz = lpos.vz * 100.0f;
2412 
2413  msg.hdg = math::degrees(wrap_2pi(lpos.yaw)) * 100.0f;
2414 
2415  mavlink_msg_global_position_int_send_struct(_mavlink->get_channel(), &msg);
2416 
2417  return true;
2418  }
2419 
2420  return false;
2421  }
2422 };
2423 
2425 {
2426 public:
2427  const char *get_name() const override
2428  {
2430  }
2431 
2432  static const char *get_name_static()
2433  {
2434  return "ODOMETRY";
2435  }
2436 
2437  static uint16_t get_id_static()
2438  {
2439  return MAVLINK_MSG_ID_ODOMETRY;
2440  }
2441 
2442  uint16_t get_id() override
2443  {
2444  return get_id_static();
2445  }
2446 
2448  {
2449  return new MavlinkStreamOdometry(mavlink);
2450  }
2451 
2452  unsigned get_size() override
2453  {
2454  return (_odom_time > 0) ? MAVLINK_MSG_ID_ODOMETRY_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES : 0;
2455  }
2456 
2457 private:
2459  uint64_t _odom_time;
2460 
2462  uint64_t _vodom_time;
2463 
2464  /* do not allow top copying this class */
2467 
2468 protected:
2469  explicit MavlinkStreamOdometry(Mavlink *mavlink) : MavlinkStream(mavlink),
2470  _odom_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_odometry))),
2471  _odom_time(0),
2472  _vodom_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_visual_odometry))),
2473  _vodom_time(0)
2474  {}
2475 
2476  bool send(const hrt_abstime t) override
2477  {
2478  vehicle_odometry_s odom;
2479  // check if it is to send visual odometry loopback or not
2480  bool odom_updated = false;
2481 
2482  mavlink_odometry_t msg = {};
2483 
2485  odom_updated = _vodom_sub->update(&_vodom_time, &odom);
2486  // frame matches the external vision system
2487  msg.frame_id = MAV_FRAME_VISION_NED;
2488 
2489  } else {
2490  odom_updated = _odom_sub->update(&_odom_time, &odom);
2491  // frame matches the PX4 local NED frame
2492  msg.frame_id = MAV_FRAME_ESTIM_NED;
2493  }
2494 
2495  if (odom_updated) {
2496  msg.time_usec = odom.timestamp;
2497  msg.child_frame_id = MAV_FRAME_BODY_FRD;
2498 
2499  // Current position
2500  msg.x = odom.x;
2501  msg.y = odom.y;
2502  msg.z = odom.z;
2503 
2504  // Current orientation
2505  msg.q[0] = odom.q[0];
2506  msg.q[1] = odom.q[1];
2507  msg.q[2] = odom.q[2];
2508  msg.q[3] = odom.q[3];
2509 
2510  // Body-FRD frame to local NED frame Dcm matrix
2511  matrix::Dcmf R_body_to_local(matrix::Quatf(odom.q));
2512 
2513  // Rotate linear and angular velocity from local NED to body-NED frame
2514  matrix::Vector3f linvel_body(R_body_to_local.transpose() * matrix::Vector3f(odom.vx, odom.vy, odom.vz));
2515 
2516  // Current linear velocity
2517  msg.vx = linvel_body(0);
2518  msg.vy = linvel_body(1);
2519  msg.vz = linvel_body(2);
2520 
2521  // Current body rates
2522  msg.rollspeed = odom.rollspeed;
2523  msg.pitchspeed = odom.pitchspeed;
2524  msg.yawspeed = odom.yawspeed;
2525 
2526  // get the covariance matrix size
2527 
2528  // pose_covariance
2529  static constexpr size_t POS_URT_SIZE = sizeof(odom.pose_covariance) / sizeof(odom.pose_covariance[0]);
2530  static_assert(POS_URT_SIZE == (sizeof(msg.pose_covariance) / sizeof(msg.pose_covariance[0])),
2531  "Odometry Pose Covariance matrix URT array size mismatch");
2532 
2533  // velocity_covariance
2534  static constexpr size_t VEL_URT_SIZE = sizeof(odom.velocity_covariance) / sizeof(odom.velocity_covariance[0]);
2535  static_assert(VEL_URT_SIZE == (sizeof(msg.velocity_covariance) / sizeof(msg.velocity_covariance[0])),
2536  "Odometry Velocity Covariance matrix URT array size mismatch");
2537 
2538  // copy pose covariances
2539  for (size_t i = 0; i < POS_URT_SIZE; i++) {
2540  msg.pose_covariance[i] = odom.pose_covariance[i];
2541  }
2542 
2543  // copy velocity covariances
2544  //TODO: Apply rotation matrix to transform from body-fixed NED to earth-fixed NED frame
2545  for (size_t i = 0; i < VEL_URT_SIZE; i++) {
2546  msg.velocity_covariance[i] = odom.velocity_covariance[i];
2547  }
2548 
2549  mavlink_msg_odometry_send_struct(_mavlink->get_channel(), &msg);
2550 
2551  return true;
2552  }
2553 
2554  return false;
2555 
2556  }
2557 };
2558 
2560 {
2561 public:
2562  const char *get_name() const override
2563  {
2565  }
2566 
2567  static const char *get_name_static()
2568  {
2569  return "LOCAL_POSITION_NED";
2570  }
2571 
2572  static uint16_t get_id_static()
2573  {
2574  return MAVLINK_MSG_ID_LOCAL_POSITION_NED;
2575  }
2576 
2577  uint16_t get_id() override
2578  {
2579  return get_id_static();
2580  }
2581 
2583  {
2584  return new MavlinkStreamLocalPositionNED(mavlink);
2585  }
2586 
2587  unsigned get_size() override
2588  {
2589  return MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
2590  }
2591 
2592 private:
2594  uint64_t _pos_time;
2595 
2596  /* do not allow top copying this class */
2599 
2600 protected:
2601  explicit MavlinkStreamLocalPositionNED(Mavlink *mavlink) : MavlinkStream(mavlink),
2602  _pos_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_local_position))),
2603  _pos_time(0)
2604  {}
2605 
2606  bool send(const hrt_abstime t) override
2607  {
2609 
2610  if (_pos_sub->update(&_pos_time, &pos)) {
2611  mavlink_local_position_ned_t msg = {};
2612 
2613  msg.time_boot_ms = pos.timestamp / 1000;
2614  msg.x = pos.x;
2615  msg.y = pos.y;
2616  msg.z = pos.z;
2617  msg.vx = pos.vx;
2618  msg.vy = pos.vy;
2619  msg.vz = pos.vz;
2620 
2621  mavlink_msg_local_position_ned_send_struct(_mavlink->get_channel(), &msg);
2622 
2623  return true;
2624  }
2625 
2626  return false;
2627  }
2628 };
2629 
2631 {
2632 public:
2633  const char *get_name() const override
2634  {
2636  }
2637 
2638  static const char *get_name_static()
2639  {
2640  return "ESTIMATOR_STATUS";
2641  }
2642 
2643  static uint16_t get_id_static()
2644  {
2645  return MAVLINK_MSG_ID_VIBRATION;
2646  }
2647 
2648  uint16_t get_id() override
2649  {
2650  return get_id_static();
2651  }
2652 
2654  {
2655  return new MavlinkStreamEstimatorStatus(mavlink);
2656  }
2657 
2658  unsigned get_size() override
2659  {
2660  return MAVLINK_MSG_ID_VIBRATION_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
2661  }
2662 
2663 private:
2665  uint64_t _est_time;
2666 
2667  /* do not allow top copying this class */
2670 
2671 protected:
2672  explicit MavlinkStreamEstimatorStatus(Mavlink *mavlink) : MavlinkStream(mavlink),
2673  _est_sub(_mavlink->add_orb_subscription(ORB_ID(estimator_status))),
2674  _est_time(0)
2675  {}
2676 
2677  bool send(const hrt_abstime t) override
2678  {
2679  estimator_status_s est;
2680 
2681  if (_est_sub->update(&_est_time, &est)) {
2682  // ESTIMATOR_STATUS
2683  mavlink_estimator_status_t est_msg = {};
2684  est_msg.time_usec = est.timestamp;
2685  est_msg.vel_ratio = est.vel_test_ratio;
2686  est_msg.pos_horiz_ratio = est.pos_test_ratio;
2687  est_msg.pos_vert_ratio = est.hgt_test_ratio;
2688  est_msg.mag_ratio = est.mag_test_ratio;
2689  est_msg.hagl_ratio = est.hagl_test_ratio;
2690  est_msg.tas_ratio = est.tas_test_ratio;
2691  est_msg.pos_horiz_accuracy = est.pos_horiz_accuracy;
2692  est_msg.pos_vert_accuracy = est.pos_vert_accuracy;
2693  est_msg.flags = est.solution_status_flags;
2694  mavlink_msg_estimator_status_send_struct(_mavlink->get_channel(), &est_msg);
2695 
2696  // VIBRATION
2697  mavlink_vibration_t msg = {};
2698  msg.time_usec = est.timestamp;
2699  msg.vibration_x = est.vibe[0];
2700  msg.vibration_y = est.vibe[1];
2701  msg.vibration_z = est.vibe[2];
2702  mavlink_msg_vibration_send_struct(_mavlink->get_channel(), &msg);
2703 
2704  return true;
2705  }
2706 
2707  return false;
2708  }
2709 };
2710 
2712 {
2713 public:
2714  const char *get_name() const override
2715  {
2717  }
2718 
2719  static const char *get_name_static()
2720  {
2721  return "ATT_POS_MOCAP";
2722  }
2723 
2724  static uint16_t get_id_static()
2725  {
2726  return MAVLINK_MSG_ID_ATT_POS_MOCAP;
2727  }
2728 
2729  uint16_t get_id() override
2730  {
2731  return get_id_static();
2732  }
2733 
2735  {
2736  return new MavlinkStreamAttPosMocap(mavlink);
2737  }
2738 
2739  unsigned get_size() override
2740  {
2741  return MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
2742  }
2743 
2744 private:
2746  uint64_t _mocap_time;
2747 
2748  /* do not allow top copying this class */
2751 
2752 protected:
2753  explicit MavlinkStreamAttPosMocap(Mavlink *mavlink) : MavlinkStream(mavlink),
2754  _mocap_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_mocap_odometry))),
2755  _mocap_time(0)
2756  {}
2757 
2758  bool send(const hrt_abstime t) override
2759  {
2760  vehicle_odometry_s mocap;
2761 
2762  if (_mocap_sub->update(&_mocap_time, &mocap)) {
2763  mavlink_att_pos_mocap_t msg = {};
2764 
2765  msg.time_usec = mocap.timestamp;
2766  msg.q[0] = mocap.q[0];
2767  msg.q[1] = mocap.q[1];
2768  msg.q[2] = mocap.q[2];
2769  msg.q[3] = mocap.q[3];
2770  msg.x = mocap.x;
2771  msg.y = mocap.y;
2772  msg.z = mocap.z;
2773 
2774  mavlink_msg_att_pos_mocap_send_struct(_mavlink->get_channel(), &msg);
2775 
2776  return true;
2777  }
2778 
2779  return false;
2780  }
2781 };
2782 
2783 
2785 {
2786 public:
2787  const char *get_name() const override
2788  {
2790  }
2791 
2792  static const char *get_name_static()
2793  {
2794  return "HOME_POSITION";
2795  }
2796 
2797  static uint16_t get_id_static()
2798  {
2799  return MAVLINK_MSG_ID_HOME_POSITION;
2800  }
2801 
2802  uint16_t get_id() override
2803  {
2804  return get_id_static();
2805  }
2806 
2808  {
2809  return new MavlinkStreamHomePosition(mavlink);
2810  }
2811 
2812  unsigned get_size() override
2813  {
2814  return _home_sub->is_published() ? (MAVLINK_MSG_ID_HOME_POSITION_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES) : 0;
2815  }
2816 
2817 private:
2819 
2820  /* do not allow top copying this class */
2823 
2824 protected:
2825  explicit MavlinkStreamHomePosition(Mavlink *mavlink) : MavlinkStream(mavlink),
2826  _home_sub(_mavlink->add_orb_subscription(ORB_ID(home_position)))
2827  {}
2828 
2829  bool send(const hrt_abstime t) override
2830  {
2831  /* we're sending the GPS home periodically to ensure the
2832  * the GCS does pick it up at one point */
2833  if (_home_sub->is_published()) {
2834  home_position_s home;
2835 
2836  if (_home_sub->update(&home)) {
2837  if (home.valid_hpos) {
2838  mavlink_home_position_t msg;
2839 
2840  msg.latitude = home.lat * 1e7;
2841  msg.longitude = home.lon * 1e7;
2842  msg.altitude = home.alt * 1e3f;
2843 
2844  msg.x = home.x;
2845  msg.y = home.y;
2846  msg.z = home.z;
2847 
2848  matrix::Quatf q(matrix::Eulerf(0.0f, 0.0f, home.yaw));
2849  msg.q[0] = q(0);
2850  msg.q[1] = q(1);
2851  msg.q[2] = q(2);
2852  msg.q[3] = q(3);
2853 
2854  msg.approach_x = 0.0f;
2855  msg.approach_y = 0.0f;
2856  msg.approach_z = 0.0f;
2857 
2858  msg.time_usec = home.timestamp;
2859 
2860  mavlink_msg_home_position_send_struct(_mavlink->get_channel(), &msg);
2861 
2862  return true;
2863  }
2864  }
2865  }
2866 
2867  return false;
2868  }
2869 };
2870 
2871 
2872 template <int N>
2874 {
2875 public:
2876  const char *get_name() const override
2877  {
2879  }
2880 
2881  static uint16_t get_id_static()
2882  {
2883  return MAVLINK_MSG_ID_SERVO_OUTPUT_RAW;
2884  }
2885 
2886  uint16_t get_id() override
2887  {
2888  return get_id_static();
2889  }
2890 
2891  static const char *get_name_static()
2892  {
2893  switch (N) {
2894  case 0:
2895  return "SERVO_OUTPUT_RAW_0";
2896 
2897  case 1:
2898  return "SERVO_OUTPUT_RAW_1";
2899  }
2900  }
2901 
2903  {
2904  return new MavlinkStreamServoOutputRaw<N>(mavlink);
2905  }
2906 
2907  unsigned get_size() override
2908  {
2909  return MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
2910  }
2911 
2912 private:
2914  uint64_t _act_time;
2915 
2916  /* do not allow top copying this class */
2919 
2920 protected:
2921  explicit MavlinkStreamServoOutputRaw(Mavlink *mavlink) : MavlinkStream(mavlink),
2922  _act_sub(_mavlink->add_orb_subscription(ORB_ID(actuator_outputs), N)),
2923  _act_time(0)
2924  {}
2925 
2926  bool send(const hrt_abstime t) override
2927  {
2928  actuator_outputs_s act;
2929 
2930  if (_act_sub->update(&_act_time, &act)) {
2931  mavlink_servo_output_raw_t msg = {};
2932 
2933  static_assert(sizeof(act.output) / sizeof(act.output[0]) >= 16, "mavlink message requires at least 16 outputs");
2934 
2935  msg.time_usec = act.timestamp;
2936  msg.port = N;
2937  msg.servo1_raw = act.output[0];
2938  msg.servo2_raw = act.output[1];
2939  msg.servo3_raw = act.output[2];
2940  msg.servo4_raw = act.output[3];
2941  msg.servo5_raw = act.output[4];
2942  msg.servo6_raw = act.output[5];
2943  msg.servo7_raw = act.output[6];
2944  msg.servo8_raw = act.output[7];
2945  msg.servo9_raw = act.output[8];
2946  msg.servo10_raw = act.output[9];
2947  msg.servo11_raw = act.output[10];
2948  msg.servo12_raw = act.output[11];
2949  msg.servo13_raw = act.output[12];
2950  msg.servo14_raw = act.output[13];
2951  msg.servo15_raw = act.output[14];
2952  msg.servo16_raw = act.output[15];
2953 
2954  mavlink_msg_servo_output_raw_send_struct(_mavlink->get_channel(), &msg);
2955 
2956  return true;
2957  }
2958 
2959  return false;
2960  }
2961 };
2962 
2963 template <int N>
2965 {
2966 public:
2967  const char *get_name() const override
2968  {
2970  }
2971 
2972  static const char *get_name_static()
2973  {
2974  switch (N) {
2975  case 0:
2976  return "ACTUATOR_CONTROL_TARGET0";
2977 
2978  case 1:
2979  return "ACTUATOR_CONTROL_TARGET1";
2980 
2981  case 2:
2982  return "ACTUATOR_CONTROL_TARGET2";
2983 
2984  case 3:
2985  return "ACTUATOR_CONTROL_TARGET3";
2986  }
2987  }
2988 
2989  static uint16_t get_id_static()
2990  {
2991  return MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET;
2992  }
2993 
2994  uint16_t get_id() override
2995  {
2996  return get_id_static();
2997  }
2998 
3000  {
3001  return new MavlinkStreamActuatorControlTarget<N>(mavlink);
3002  }
3003 
3004  unsigned get_size() override
3005  {
3006  return _act_ctrl_sub->is_published() ? (MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES) : 0;
3007  }
3008 
3009 private:
3011  uint64_t _act_ctrl_time;
3012 
3013  /* do not allow top copying this class */
3016 
3017 protected:
3019  _act_ctrl_sub(nullptr),
3020  _act_ctrl_time(0)
3021  {
3022  // XXX this can be removed once the multiplatform system remaps topics
3023  switch (N) {
3024  case 0:
3025  _act_ctrl_sub = _mavlink->add_orb_subscription(ORB_ID(actuator_controls_0));
3026  break;
3027 
3028  case 1:
3029  _act_ctrl_sub = _mavlink->add_orb_subscription(ORB_ID(actuator_controls_1));
3030  break;
3031 
3032  case 2:
3033  _act_ctrl_sub = _mavlink->add_orb_subscription(ORB_ID(actuator_controls_2));
3034  break;
3035 
3036  case 3:
3037  _act_ctrl_sub = _mavlink->add_orb_subscription(ORB_ID(actuator_controls_3));
3038  break;
3039  }
3040  }
3041 
3042  bool send(const hrt_abstime t) override
3043  {
3044  actuator_controls_s act_ctrl;
3045 
3046  if (_act_ctrl_sub->update(&_act_ctrl_time, &act_ctrl)) {
3047  mavlink_actuator_control_target_t msg = {};
3048 
3049  msg.time_usec = act_ctrl.timestamp;
3050  msg.group_mlx = N;
3051 
3052  for (unsigned i = 0; i < sizeof(msg.controls) / sizeof(msg.controls[0]); i++) {
3053  msg.controls[i] = act_ctrl.control[i];
3054  }
3055 
3056  mavlink_msg_actuator_control_target_send_struct(_mavlink->get_channel(), &msg);
3057 
3058  return true;
3059  }
3060 
3061  return false;
3062  }
3063 };
3064 
3066 {
3067 public:
3068  const char *get_name() const override
3069  {
3071  }
3072 
3073  static const char *get_name_static()
3074  {
3075  return "HIL_ACTUATOR_CONTROLS";
3076  }
3077 
3078  static uint16_t get_id_static()
3079  {
3080  return MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS;
3081  }
3082 
3083  uint16_t get_id() override
3084  {
3085  return get_id_static();
3086  }
3087 
3089  {
3090  return new MavlinkStreamHILActuatorControls(mavlink);
3091  }
3092 
3093  unsigned get_size() override
3094  {
3095  return MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
3096  }
3097 
3098 private:
3100 
3102  uint64_t _act_time;
3103 
3104  /* do not allow top copying this class */
3107 
3108 protected:
3110  _status_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_status))),
3111  _act_sub(_mavlink->add_orb_subscription(ORB_ID(actuator_outputs))),
3112  _act_time(0)
3113  {}
3114 
3115  bool send(const hrt_abstime t) override
3116  {
3117  actuator_outputs_s act;
3118 
3119  if (_act_sub->update(&_act_time, &act)) {
3120  vehicle_status_s status = {};
3121  _status_sub->update(&status);
3122 
3123  if ((status.timestamp > 0) && (status.arming_state == vehicle_status_s::ARMING_STATE_ARMED)) {
3124  /* translate the current system state to mavlink state and mode */
3125  uint8_t mavlink_state;
3126  uint8_t mavlink_base_mode;
3127  uint32_t mavlink_custom_mode;
3128  mavlink_hil_actuator_controls_t msg = {};
3129 
3130  get_mavlink_mode_state(&status, &mavlink_state, &mavlink_base_mode, &mavlink_custom_mode);
3131 
3132  const float pwm_center = (PWM_DEFAULT_MAX + PWM_DEFAULT_MIN) / 2;
3133 
3134  unsigned system_type = _mavlink->get_system_type();
3135 
3136  /* scale outputs depending on system type */
3137  if (system_type == MAV_TYPE_QUADROTOR ||
3138  system_type == MAV_TYPE_HEXAROTOR ||
3139  system_type == MAV_TYPE_OCTOROTOR ||
3140  system_type == MAV_TYPE_VTOL_DUOROTOR ||
3141  system_type == MAV_TYPE_VTOL_QUADROTOR ||
3142  system_type == MAV_TYPE_VTOL_RESERVED2) {
3143 
3144  /* multirotors: set number of rotor outputs depending on type */
3145 
3146  unsigned n;
3147 
3148  switch (system_type) {
3149  case MAV_TYPE_QUADROTOR:
3150  n = 4;
3151  break;
3152 
3153  case MAV_TYPE_HEXAROTOR:
3154  n = 6;
3155  break;
3156 
3157  case MAV_TYPE_VTOL_DUOROTOR:
3158  n = 2;
3159  break;
3160 
3161  case MAV_TYPE_VTOL_QUADROTOR:
3162  n = 4;
3163  break;
3164 
3165  case MAV_TYPE_VTOL_RESERVED2:
3166  n = 8;
3167  break;
3168 
3169  default:
3170  n = 8;
3171  break;
3172  }
3173 
3174  for (unsigned i = 0; i < 16; i++) {
3175  if (act.output[i] > PWM_DEFAULT_MIN / 2) {
3176  if (i < n) {
3177  /* scale PWM out 900..2100 us to 0..1 for rotors */
3178  msg.controls[i] = (act.output[i] - PWM_DEFAULT_MIN) / (PWM_DEFAULT_MAX - PWM_DEFAULT_MIN);
3179 
3180  } else {
3181  /* scale PWM out 900..2100 us to -1..1 for other channels */
3182  msg.controls[i] = (act.output[i] - pwm_center) / ((PWM_DEFAULT_MAX - PWM_DEFAULT_MIN) / 2);
3183  }
3184 
3185  } else {
3186  /* send 0 when disarmed and for disabled channels */
3187  msg.controls[i] = 0.0f;
3188  }
3189  }
3190 
3191  } else {
3192  /* fixed wing: scale throttle to 0..1 and other channels to -1..1 */
3193 
3194  for (unsigned i = 0; i < 16; i++) {
3195  if (act.output[i] > PWM_DEFAULT_MIN / 2) {
3196  if (i != 3) {
3197  /* scale PWM out 900..2100 us to -1..1 for normal channels */
3198  msg.controls[i] = (act.output[i] - pwm_center) / ((PWM_DEFAULT_MAX - PWM_DEFAULT_MIN) / 2);
3199 
3200  } else {
3201  /* scale PWM out 900..2100 us to 0..1 for throttle */
3202  msg.controls[i] = (act.output[i] - PWM_DEFAULT_MIN) / (PWM_DEFAULT_MAX - PWM_DEFAULT_MIN);
3203  }
3204 
3205  } else {
3206  /* set 0 for disabled channels */
3207  msg.controls[i] = 0.0f;
3208  }
3209  }
3210  }
3211 
3212  msg.time_usec = hrt_absolute_time();
3213  msg.mode = mavlink_base_mode;
3214  msg.flags = 0;
3215 
3216  mavlink_msg_hil_actuator_controls_send_struct(_mavlink->get_channel(), &msg);
3217 
3218  return true;
3219  }
3220  }
3221 
3222  return false;
3223  }
3224 };
3225 
3227 {
3228 public:
3229  const char *get_name() const override
3230  {
3232  }
3233 
3234  static const char *get_name_static()
3235  {
3236  return "POSITION_TARGET_GLOBAL_INT";
3237  }
3238 
3239  static uint16_t get_id_static()
3240  {
3241  return MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT;
3242  }
3243 
3244  uint16_t get_id() override
3245  {
3246  return get_id_static();
3247  }
3248 
3250  {
3251  return new MavlinkStreamPositionTargetGlobalInt(mavlink);
3252  }
3253 
3254  unsigned get_size() override
3255  {
3256  return MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
3257  }
3258 
3259 private:
3263 
3264  /* do not allow top copying this class */
3267 
3268 protected:
3270  _control_mode_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_control_mode))),
3271  _lpos_sp_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_local_position_setpoint))),
3272  _pos_sp_triplet_sub(_mavlink->add_orb_subscription(ORB_ID(position_setpoint_triplet)))
3273  {}
3274 
3275  bool send(const hrt_abstime t) override
3276  {
3277  vehicle_control_mode_s control_mode = {};
3278  _control_mode_sub->update(&control_mode);
3279 
3280  if (control_mode.flag_control_position_enabled) {
3281 
3282  position_setpoint_triplet_s pos_sp_triplet = {};
3283  _pos_sp_triplet_sub->update(&pos_sp_triplet);
3284 
3285  if (pos_sp_triplet.timestamp > 0 && pos_sp_triplet.current.valid
3286  && PX4_ISFINITE(pos_sp_triplet.current.lat) && PX4_ISFINITE(pos_sp_triplet.current.lon)) {
3287 
3288  mavlink_position_target_global_int_t msg = {};
3289 
3290  msg.time_boot_ms = hrt_absolute_time() / 1000;
3291  msg.coordinate_frame = MAV_FRAME_GLOBAL_INT;
3292  msg.lat_int = pos_sp_triplet.current.lat * 1e7;
3293  msg.lon_int = pos_sp_triplet.current.lon * 1e7;
3294  msg.alt = pos_sp_triplet.current.alt;
3295 
3297 
3298  if (_lpos_sp_sub->update(&lpos_sp)) {
3299  // velocity
3300  msg.vx = lpos_sp.vx;
3301  msg.vy = lpos_sp.vy;
3302  msg.vz = lpos_sp.vz;
3303 
3304  // acceleration
3305  msg.afx = lpos_sp.acceleration[0];
3306  msg.afy = lpos_sp.acceleration[1];
3307  msg.afz = lpos_sp.acceleration[2];
3308 
3309  // yaw
3310  msg.yaw = lpos_sp.yaw;
3311  msg.yaw_rate = lpos_sp.yawspeed;
3312  }
3313 
3314  mavlink_msg_position_target_global_int_send_struct(_mavlink->get_channel(), &msg);
3315 
3316  return true;
3317  }
3318  }
3319 
3320  return false;
3321  }
3322 };
3323 
3324 
3326 {
3327 public:
3328  const char *get_name() const override
3329  {
3331  }
3332 
3333  static const char *get_name_static()
3334  {
3335  return "POSITION_TARGET_LOCAL_NED";
3336  }
3337 
3338  static uint16_t get_id_static()
3339  {
3340  return MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED;
3341  }
3342 
3343  uint16_t get_id() override
3344  {
3345  return get_id_static();
3346  }
3347 
3349  {
3350  return new MavlinkStreamLocalPositionSetpoint(mavlink);
3351  }
3352 
3353  unsigned get_size() override
3354  {
3355  return MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
3356  }
3357 
3358 private:
3360  uint64_t _pos_sp_time;
3361 
3362  /* do not allow top copying this class */
3365 
3366 protected:
3368  _pos_sp_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_local_position_setpoint))),
3369  _pos_sp_time(0)
3370  {}
3371 
3372  bool send(const hrt_abstime t) override
3373  {
3375 
3376  if (_pos_sp_sub->update(&_pos_sp_time, &pos_sp)) {
3377  mavlink_position_target_local_ned_t msg = {};
3378 
3379  msg.time_boot_ms = pos_sp.timestamp / 1000;
3380  msg.coordinate_frame = MAV_FRAME_LOCAL_NED;
3381  msg.x = pos_sp.x;
3382  msg.y = pos_sp.y;
3383  msg.z = pos_sp.z;
3384  msg.yaw = pos_sp.yaw;
3385  msg.yaw_rate = pos_sp.yawspeed;
3386  msg.vx = pos_sp.vx;
3387  msg.vy = pos_sp.vy;
3388  msg.vz = pos_sp.vz;
3389  msg.afx = pos_sp.acceleration[0];
3390  msg.afy = pos_sp.acceleration[1];
3391  msg.afz = pos_sp.acceleration[2];
3392 
3393  mavlink_msg_position_target_local_ned_send_struct(_mavlink->get_channel(), &msg);
3394 
3395  return true;
3396  }
3397 
3398  return false;
3399  }
3400 };
3401 
3402 
3404 {
3405 public:
3406  const char *get_name() const override
3407  {
3409  }
3410 
3411  static const char *get_name_static()
3412  {
3413  return "ATTITUDE_TARGET";
3414  }
3415 
3416  static uint16_t get_id_static()
3417  {
3418  return MAVLINK_MSG_ID_ATTITUDE_TARGET;
3419  }
3420 
3421  uint16_t get_id() override
3422  {
3423  return get_id_static();
3424  }
3425 
3427  {
3428  return new MavlinkStreamAttitudeTarget(mavlink);
3429  }
3430 
3431  unsigned get_size() override
3432  {
3433  return MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
3434  }
3435 
3436 private:
3439 
3440  uint64_t _att_sp_time;
3441 
3442  /* do not allow top copying this class */
3445 
3446 protected:
3447  explicit MavlinkStreamAttitudeTarget(Mavlink *mavlink) : MavlinkStream(mavlink),
3448  _att_sp_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_attitude_setpoint))),
3449  _att_rates_sp_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_rates_setpoint))),
3450  _att_sp_time(0)
3451  {}
3452 
3453  bool send(const hrt_abstime t) override
3454  {
3456 
3457  if (_att_sp_sub->update(&_att_sp_time, &att_sp)) {
3458 
3459  vehicle_rates_setpoint_s att_rates_sp = {};
3460  _att_rates_sp_sub->update(&att_rates_sp);
3461 
3462  mavlink_attitude_target_t msg = {};
3463 
3464  msg.time_boot_ms = att_sp.timestamp / 1000;
3465 
3466  if (att_sp.q_d_valid) {
3467  memcpy(&msg.q[0], &att_sp.q_d[0], sizeof(msg.q));
3468 
3469  } else {
3470  matrix::Quatf q = matrix::Eulerf(att_sp.roll_body, att_sp.pitch_body, att_sp.yaw_body);
3471 
3472  for (size_t i = 0; i < 4; i++) {
3473  msg.q[i] = q(i);
3474  }
3475  }
3476 
3477  msg.body_roll_rate = att_rates_sp.roll;
3478  msg.body_pitch_rate = att_rates_sp.pitch;
3479  msg.body_yaw_rate = att_rates_sp.yaw;
3480 
3481  msg.thrust = att_sp.thrust_body[0];
3482 
3483  mavlink_msg_attitude_target_send_struct(_mavlink->get_channel(), &msg);
3484 
3485  return true;
3486  }
3487 
3488  return false;
3489  }
3490 };
3491 
3492 
3494 {
3495 public:
3496  const char *get_name() const override
3497  {
3499  }
3500 
3501  static const char *get_name_static()
3502  {
3503  return "RC_CHANNELS";
3504  }
3505 
3506  static uint16_t get_id_static()
3507  {
3508  return MAVLINK_MSG_ID_RC_CHANNELS;
3509  }
3510 
3511  uint16_t get_id() override
3512  {
3513  return get_id_static();
3514  }
3515 
3517  {
3518  return new MavlinkStreamRCChannels(mavlink);
3519  }
3520 
3521  unsigned get_size() override
3522  {
3523  return _rc_sub->is_published() ? (MAVLINK_MSG_ID_RC_CHANNELS_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES) : 0;
3524  }
3525 
3526 private:
3528  uint64_t _rc_time;
3529 
3530  /* do not allow top copying this class */
3533 
3534 protected:
3535  explicit MavlinkStreamRCChannels(Mavlink *mavlink) : MavlinkStream(mavlink),
3536  _rc_sub(_mavlink->add_orb_subscription(ORB_ID(input_rc))),
3537  _rc_time(0)
3538  {}
3539 
3540  bool send(const hrt_abstime t) override
3541  {
3542  input_rc_s rc;
3543 
3544  if (_rc_sub->update(&_rc_time, &rc)) {
3545 
3546  /* send RC channel data and RSSI */
3547  mavlink_rc_channels_t msg = {};
3548 
3549  msg.time_boot_ms = rc.timestamp / 1000;
3550  msg.chancount = rc.channel_count;
3551  msg.chan1_raw = (rc.channel_count > 0) ? rc.values[0] : UINT16_MAX;
3552  msg.chan2_raw = (rc.channel_count > 1) ? rc.values[1] : UINT16_MAX;
3553  msg.chan3_raw = (rc.channel_count > 2) ? rc.values[2] : UINT16_MAX;
3554  msg.chan4_raw = (rc.channel_count > 3) ? rc.values[3] : UINT16_MAX;
3555  msg.chan5_raw = (rc.channel_count > 4) ? rc.values[4] : UINT16_MAX;
3556  msg.chan6_raw = (rc.channel_count > 5) ? rc.values[5] : UINT16_MAX;
3557  msg.chan7_raw = (rc.channel_count > 6) ? rc.values[6] : UINT16_MAX;
3558  msg.chan8_raw = (rc.channel_count > 7) ? rc.values[7] : UINT16_MAX;
3559  msg.chan9_raw = (rc.channel_count > 8) ? rc.values[8] : UINT16_MAX;
3560  msg.chan10_raw = (rc.channel_count > 9) ? rc.values[9] : UINT16_MAX;
3561  msg.chan11_raw = (rc.channel_count > 10) ? rc.values[10] : UINT16_MAX;
3562  msg.chan12_raw = (rc.channel_count > 11) ? rc.values[11] : UINT16_MAX;
3563  msg.chan13_raw = (rc.channel_count > 12) ? rc.values[12] : UINT16_MAX;
3564  msg.chan14_raw = (rc.channel_count > 13) ? rc.values[13] : UINT16_MAX;
3565  msg.chan15_raw = (rc.channel_count > 14) ? rc.values[14] : UINT16_MAX;
3566  msg.chan16_raw = (rc.channel_count > 15) ? rc.values[15] : UINT16_MAX;
3567  msg.chan17_raw = (rc.channel_count > 16) ? rc.values[16] : UINT16_MAX;
3568  msg.chan18_raw = (rc.channel_count > 17) ? rc.values[17] : UINT16_MAX;
3569 
3570  msg.rssi = (rc.channel_count > 0) ? rc.rssi : 0;
3571 
3572  mavlink_msg_rc_channels_send_struct(_mavlink->get_channel(), &msg);
3573  return true;
3574  }
3575 
3576  return false;
3577  }
3578 };
3579 
3580 
3582 {
3583 public:
3584  const char *get_name() const override
3585  {
3587  }
3588 
3589  static const char *get_name_static()
3590  {
3591  return "MANUAL_CONTROL";
3592  }
3593 
3594  static uint16_t get_id_static()
3595  {
3596  return MAVLINK_MSG_ID_MANUAL_CONTROL;
3597  }
3598 
3599  uint16_t get_id() override
3600  {
3601  return get_id_static();
3602  }
3603 
3605  {
3606  return new MavlinkStreamManualControl(mavlink);
3607  }
3608 
3609  unsigned get_size() override
3610  {
3611  return _manual_sub->is_published() ? (MAVLINK_MSG_ID_MANUAL_CONTROL_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES) : 0;
3612  }
3613 
3614 private:
3616  uint64_t _manual_time;
3617 
3618  /* do not allow top copying this class */
3621 
3622 protected:
3623  explicit MavlinkStreamManualControl(Mavlink *mavlink) : MavlinkStream(mavlink),
3624  _manual_sub(_mavlink->add_orb_subscription(ORB_ID(manual_control_setpoint))),
3625  _manual_time(0)
3626  {}
3627 
3628  bool send(const hrt_abstime t) override
3629  {
3631 
3632  if (_manual_sub->update(&_manual_time, &manual)) {
3633  mavlink_manual_control_t msg = {};
3634 
3635  msg.target = mavlink_system.sysid;
3636  msg.x = manual.x * 1000;
3637  msg.y = manual.y * 1000;
3638  msg.z = manual.z * 1000;
3639  msg.r = manual.r * 1000;
3640  unsigned shift = 2;
3641  msg.buttons = 0;
3642  msg.buttons |= (manual.mode_switch << (shift * 0));
3643  msg.buttons |= (manual.return_switch << (shift * 1));
3644  msg.buttons |= (manual.posctl_switch << (shift * 2));
3645  msg.buttons |= (manual.loiter_switch << (shift * 3));
3646  msg.buttons |= (manual.acro_switch << (shift * 4));
3647  msg.buttons |= (manual.offboard_switch << (shift * 5));
3648 
3649  mavlink_msg_manual_control_send_struct(_mavlink->get_channel(), &msg);
3650 
3651  return true;
3652  }
3653 
3654  return false;
3655  }
3656 };
3657 
3659 {
3660 public:
3661  const char *get_name() const override
3662  {
3664  }
3665 
3666  static const char *get_name_static()
3667  {
3668  return "TRAJECTORY_REPRESENTATION_WAYPOINTS";
3669  }
3670 
3671  static uint16_t get_id_static()
3672  {
3673  return MAVLINK_MSG_ID_TRAJECTORY_REPRESENTATION_WAYPOINTS;
3674  }
3675 
3676  uint16_t get_id() override
3677  {
3678  return get_id_static();
3679  }
3680 
3682  {
3684  }
3685 
3686  unsigned get_size() override
3687  {
3688  return _traj_wp_avoidance_sub->is_published() ? (MAVLINK_MSG_ID_TRAJECTORY_REPRESENTATION_WAYPOINTS_LEN +
3689  MAVLINK_NUM_NON_PAYLOAD_BYTES)
3690  : 0;
3691  }
3692 
3693 private:
3696 
3697  /* do not allow top copying this class */
3700 
3701 protected:
3703  _traj_wp_avoidance_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_trajectory_waypoint_desired))),
3704  _traj_wp_avoidance_time(0)
3705  {}
3706 
3707  bool send(const hrt_abstime t) override
3708  {
3709  struct vehicle_trajectory_waypoint_s traj_wp_avoidance_desired;
3710 
3711  if (_traj_wp_avoidance_sub->update(&_traj_wp_avoidance_time, &traj_wp_avoidance_desired)) {
3712  mavlink_trajectory_representation_waypoints_t msg = {};
3713 
3714  msg.time_usec = traj_wp_avoidance_desired.timestamp;
3715  int number_valid_points = 0;
3716 
3717  for (int i = 0; i < vehicle_trajectory_waypoint_s::NUMBER_POINTS; ++i) {
3718  msg.pos_x[i] = traj_wp_avoidance_desired.waypoints[i].position[0];
3719  msg.pos_y[i] = traj_wp_avoidance_desired.waypoints[i].position[1];
3720  msg.pos_z[i] = traj_wp_avoidance_desired.waypoints[i].position[2];
3721 
3722  msg.vel_x[i] = traj_wp_avoidance_desired.waypoints[i].velocity[0];
3723  msg.vel_y[i] = traj_wp_avoidance_desired.waypoints[i].velocity[1];
3724  msg.vel_z[i] = traj_wp_avoidance_desired.waypoints[i].velocity[2];
3725 
3726  msg.acc_x[i] = traj_wp_avoidance_desired.waypoints[i].acceleration[0];
3727  msg.acc_y[i] = traj_wp_avoidance_desired.waypoints[i].acceleration[1];
3728  msg.acc_z[i] = traj_wp_avoidance_desired.waypoints[i].acceleration[2];
3729 
3730  msg.pos_yaw[i] = traj_wp_avoidance_desired.waypoints[i].yaw;
3731  msg.vel_yaw[i] = traj_wp_avoidance_desired.waypoints[i].yaw_speed;
3732 
3733  switch (traj_wp_avoidance_desired.waypoints[i].type) {
3734  case position_setpoint_s::SETPOINT_TYPE_TAKEOFF:
3735  msg.command[i] = vehicle_command_s::VEHICLE_CMD_NAV_TAKEOFF;
3736  break;
3737 
3738  case position_setpoint_s::SETPOINT_TYPE_LOITER:
3739  msg.command[i] = vehicle_command_s::VEHICLE_CMD_NAV_LOITER_UNLIM;
3740  break;
3741 
3742  case position_setpoint_s::SETPOINT_TYPE_LAND:
3743  msg.command[i] = vehicle_command_s::VEHICLE_CMD_NAV_LAND;
3744  break;
3745 
3746  default:
3747  msg.command[i] = UINT16_MAX;
3748  }
3749 
3750  if (traj_wp_avoidance_desired.waypoints[i].point_valid) {
3751  number_valid_points++;
3752  }
3753 
3754  }
3755 
3756  msg.valid_points = number_valid_points;
3757 
3758  mavlink_msg_trajectory_representation_waypoints_send_struct(_mavlink->get_channel(), &msg);
3759 
3760  return true;
3761  }
3762 
3763  return false;
3764  }
3765 };
3766 
3768 {
3769 public:
3770  const char *get_name() const override
3771  {
3773  }
3774 
3775  static const char *get_name_static()
3776  {
3777  return "OPTICAL_FLOW_RAD";
3778  }
3779 
3780  static uint16_t get_id_static()
3781  {
3782  return MAVLINK_MSG_ID_OPTICAL_FLOW_RAD;
3783  }
3784 
3785  uint16_t get_id() override
3786  {
3787  return get_id_static();
3788  }
3789 
3791  {
3792  return new MavlinkStreamOpticalFlowRad(mavlink);
3793  }
3794 
3795  unsigned get_size() override
3796  {
3797  return _flow_sub->is_published() ? (MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES) : 0;
3798  }
3799 
3800 private:
3802  uint64_t _flow_time;
3803 
3804  /* do not allow top copying this class */
3807 
3808 protected:
3809  explicit MavlinkStreamOpticalFlowRad(Mavlink *mavlink) : MavlinkStream(mavlink),
3810  _flow_sub(_mavlink->add_orb_subscription(ORB_ID(optical_flow))),
3811  _flow_time(0)
3812  {}
3813 
3814  bool send(const hrt_abstime t) override
3815  {
3816  optical_flow_s flow;
3817 
3818  if (_flow_sub->update(&_flow_time, &flow)) {
3819  mavlink_optical_flow_rad_t msg = {};
3820 
3821  msg.time_usec = flow.timestamp;
3822  msg.sensor_id = flow.sensor_id;
3823  msg.integrated_x = flow.pixel_flow_x_integral;
3824  msg.integrated_y = flow.pixel_flow_y_integral;
3825  msg.integrated_xgyro = flow.gyro_x_rate_integral;
3826  msg.integrated_ygyro = flow.gyro_y_rate_integral;
3827  msg.integrated_zgyro = flow.gyro_z_rate_integral;
3828  msg.distance = flow.ground_distance_m;
3829  msg.quality = flow.quality;
3830  msg.integration_time_us = flow.integration_timespan;
3831  msg.sensor_id = flow.sensor_id;
3832  msg.time_delta_distance_us = flow.time_since_last_sonar_update;
3833  msg.temperature = flow.gyro_temperature;
3834 
3835  mavlink_msg_optical_flow_rad_send_struct(_mavlink->get_channel(), &msg);
3836 
3837  return true;
3838  }
3839 
3840  return false;
3841  }
3842 };
3843 
3845 {
3846 public:
3847  const char *get_name() const override
3848  {
3850  }
3851 
3852  static const char *get_name_static()
3853  {
3854  return "NAMED_VALUE_FLOAT";
3855  }
3856 
3857  static uint16_t get_id_static()
3858  {
3859  return MAVLINK_MSG_ID_NAMED_VALUE_FLOAT;
3860  }
3861 
3862  uint16_t get_id() override
3863  {
3864  return get_id_static();
3865  }
3866 
3868  {
3869  return new MavlinkStreamNamedValueFloat(mavlink);
3870  }
3871 
3872  unsigned get_size() override
3873  {
3874  return (_debug_time > 0) ? MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES : 0;
3875  }
3876 
3877 private:
3879  uint64_t _debug_time;
3880 
3881  /* do not allow top copying this class */
3884 
3885 protected:
3886  explicit MavlinkStreamNamedValueFloat(Mavlink *mavlink) : MavlinkStream(mavlink),
3887  _debug_sub(_mavlink->add_orb_subscription(ORB_ID(debug_key_value))),
3888  _debug_time(0)
3889  {}
3890 
3891  bool send(const hrt_abstime t) override
3892  {
3893  struct debug_key_value_s debug;
3894 
3895  if (_debug_sub->update(&_debug_time, &debug)) {
3896  mavlink_named_value_float_t msg = {};
3897 
3898  msg.time_boot_ms = debug.timestamp / 1000ULL;
3899  memcpy(msg.name, debug.key, sizeof(msg.name));
3900  /* enforce null termination */
3901  msg.name[sizeof(msg.name) - 1] = '\0';
3902  msg.value = debug.value;
3903 
3904  mavlink_msg_named_value_float_send_struct(_mavlink->get_channel(), &msg);
3905 
3906  return true;
3907  }
3908 
3909  return false;
3910  }
3911 };
3912 
3914 {
3915 public:
3916  const char *get_name() const override
3917  {
3919  }
3920 
3921  static const char *get_name_static()
3922  {
3923  return "DEBUG";
3924  }
3925 
3926  static uint16_t get_id_static()
3927  {
3928  return MAVLINK_MSG_ID_DEBUG;
3929  }
3930 
3931  uint16_t get_id() override
3932  {
3933  return get_id_static();
3934  }
3935 
3937  {
3938  return new MavlinkStreamDebug(mavlink);
3939  }
3940 
3941  unsigned get_size() override
3942  {
3943  return (_debug_time > 0) ? MAVLINK_MSG_ID_DEBUG_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES : 0;
3944  }
3945 
3946 private:
3948  uint64_t _debug_time;
3949 
3950  /* do not allow top copying this class */
3953 
3954 protected:
3955  explicit MavlinkStreamDebug(Mavlink *mavlink) : MavlinkStream(mavlink),
3956  _debug_sub(_mavlink->add_orb_subscription(ORB_ID(debug_value))),
3957  _debug_time(0)
3958  {}
3959 
3960  bool send(const hrt_abstime t) override
3961  {
3962  struct debug_value_s debug = {};
3963 
3964  if (_debug_sub->update(&_debug_time, &debug)) {
3965  mavlink_debug_t msg = {};
3966 
3967  msg.time_boot_ms = debug.timestamp / 1000ULL;
3968  msg.ind = debug.ind;
3969  msg.value = debug.value;
3970 
3971  mavlink_msg_debug_send_struct(_mavlink->get_channel(), &msg);
3972 
3973  return true;
3974  }
3975 
3976  return false;
3977  }
3978 };
3979 
3981 {
3982 public:
3983  const char *get_name() const override
3984  {
3986  }
3987 
3988  static const char *get_name_static()
3989  {
3990  return "DEBUG_VECT";
3991  }
3992 
3993  static uint16_t get_id_static()
3994  {
3995  return MAVLINK_MSG_ID_DEBUG_VECT;
3996  }
3997 
3998  uint16_t get_id() override
3999  {
4000  return get_id_static();
4001  }
4002 
4004  {
4005  return new MavlinkStreamDebugVect(mavlink);
4006  }
4007 
4008  unsigned get_size() override
4009  {
4010  return (_debug_time > 0) ? MAVLINK_MSG_ID_DEBUG_VECT_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES : 0;
4011  }
4012 
4013 private:
4015  uint64_t _debug_time;
4016 
4017  /* do not allow top copying this class */
4020 
4021 protected:
4022  explicit MavlinkStreamDebugVect(Mavlink *mavlink) : MavlinkStream(mavlink),
4023  _debug_sub(_mavlink->add_orb_subscription(ORB_ID(debug_vect))),
4024  _debug_time(0)
4025  {}
4026 
4027  bool send(const hrt_abstime t) override
4028  {
4029  struct debug_vect_s debug = {};
4030 
4031  if (_debug_sub->update(&_debug_time, &debug)) {
4032  mavlink_debug_vect_t msg = {};
4033 
4034  msg.time_usec = debug.timestamp;
4035  memcpy(msg.name, debug.name, sizeof(msg.name));
4036  /* enforce null termination */
4037  msg.name[sizeof(msg.name) - 1] = '\0';
4038  msg.x = debug.x;
4039  msg.y = debug.y;
4040  msg.z = debug.z;
4041 
4042  mavlink_msg_debug_vect_send_struct(_mavlink->get_channel(), &msg);
4043 
4044  return true;
4045  }
4046 
4047  return false;
4048  }
4049 };
4050 
4052 {
4053 public:
4054  const char *get_name() const override
4055  {
4057  }
4058 
4059  static const char *get_name_static()
4060  {
4061  return "DEBUG_FLOAT_ARRAY";
4062  }
4063 
4064  static uint16_t get_id_static()
4065  {
4066  return MAVLINK_MSG_ID_DEBUG_FLOAT_ARRAY;
4067  }
4068 
4069  uint16_t get_id() override
4070  {
4071  return get_id_static();
4072  }
4073 
4075  {
4076  return new MavlinkStreamDebugFloatArray(mavlink);
4077  }
4078 
4079  unsigned get_size() override
4080  {
4081  return (_debug_time > 0) ? MAVLINK_MSG_ID_DEBUG_FLOAT_ARRAY_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES : 0;
4082  }
4083 
4084 private:
4086  uint64_t _debug_time;
4087 
4088  /* do not allow top copying this class */
4091 
4092 protected:
4093  explicit MavlinkStreamDebugFloatArray(Mavlink *mavlink) : MavlinkStream(mavlink),
4094  _debug_array_sub(_mavlink->add_orb_subscription(ORB_ID(debug_array))),
4095  _debug_time(0)
4096  {}
4097 
4098  bool send(const hrt_abstime t) override
4099  {
4100  struct debug_array_s debug = {};
4101 
4102  if (_debug_array_sub->update(&_debug_time, &debug)) {
4103  mavlink_debug_float_array_t msg = {};
4104 
4105  msg.time_usec = debug.timestamp;
4106  msg.array_id = debug.id;
4107  memcpy(msg.name, debug.name, sizeof(msg.name));
4108  /* enforce null termination */
4109  msg.name[sizeof(msg.name) - 1] = '\0';
4110 
4111  for (size_t i = 0; i < debug_array_s::ARRAY_SIZE; i++) {
4112  msg.data[i] = debug.data[i];
4113  }
4114 
4115  mavlink_msg_debug_float_array_send_struct(_mavlink->get_channel(), &msg);
4116 
4117  return true;
4118  }
4119 
4120  return false;
4121  }
4122 };
4123 
4125 {
4126 public:
4127  const char *get_name() const override
4128  {
4130  }
4131 
4132  static const char *get_name_static()
4133  {
4134  return "NAV_CONTROLLER_OUTPUT";
4135  }
4136 
4137  static uint16_t get_id_static()
4138  {
4139  return MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT;
4140  }
4141 
4142  uint16_t get_id() override
4143  {
4144  return get_id_static();
4145  }
4146 
4148  {
4149  return new MavlinkStreamNavControllerOutput(mavlink);
4150  }
4151 
4152  unsigned get_size() override
4153  {
4154  return (_pos_ctrl_status_sub->is_published()) ?
4155  MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES : 0;
4156  }
4157 
4158 private:
4161 
4162  uint64_t _pos_ctrl_status_timestamp{0};
4163  uint64_t _tecs_status_timestamp{0};
4164 
4165  /* do not allow top copying this class */
4168 
4169 protected:
4171  _pos_ctrl_status_sub(_mavlink->add_orb_subscription(ORB_ID(position_controller_status))),
4172  _tecs_status_sub(_mavlink->add_orb_subscription(ORB_ID(tecs_status)))
4173  {}
4174 
4175  bool send(const hrt_abstime t) override
4176  {
4177  position_controller_status_s pos_ctrl_status = {};
4178  tecs_status_s tecs_status = {};
4179 
4180  bool updated = false;
4181  updated |= _pos_ctrl_status_sub->update(&_pos_ctrl_status_timestamp, &pos_ctrl_status);
4182  updated |= _tecs_status_sub->update(&_tecs_status_timestamp, &tecs_status);
4183 
4184  if (updated) {
4185  mavlink_nav_controller_output_t msg = {};
4186 
4187  msg.nav_roll = math::degrees(pos_ctrl_status.nav_roll);
4188  msg.nav_pitch = math::degrees(pos_ctrl_status.nav_pitch);
4189  msg.nav_bearing = (int16_t)math::degrees(pos_ctrl_status.nav_bearing);
4190  msg.target_bearing = (int16_t)math::degrees(pos_ctrl_status.target_bearing);
4191  msg.wp_dist = (uint16_t)pos_ctrl_status.wp_dist;
4192  msg.xtrack_error = pos_ctrl_status.xtrack_error;
4193  msg.alt_error = tecs_status.altitude_filtered - tecs_status.altitude_sp;
4194  msg.aspd_error = tecs_status.airspeed_filtered - tecs_status.airspeed_sp;
4195 
4196  mavlink_msg_nav_controller_output_send_struct(_mavlink->get_channel(), &msg);
4197 
4198  return true;
4199  }
4200 
4201  return false;
4202  }
4203 };
4204 
4206 {
4207 public:
4208  const char *get_name() const override
4209  {
4211  }
4212 
4213  static const char *get_name_static()
4214  {
4215  return "CAMERA_CAPTURE";
4216  }
4217 
4218  static uint16_t get_id_static()
4219  {
4220  return 0;
4221  }
4222 
4223  uint16_t get_id() override
4224  {
4225  return get_id_static();
4226  }
4227 
4229  {
4230  return new MavlinkStreamCameraCapture(mavlink);
4231  }
4232 
4233  unsigned get_size() override
4234  {
4235  return MAVLINK_MSG_ID_COMMAND_LONG_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
4236  }
4237 
4238 private:
4240 
4241  /* do not allow top copying this class */
4244 
4245 protected:
4246  explicit MavlinkStreamCameraCapture(Mavlink *mavlink) : MavlinkStream(mavlink),
4247  _status_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_status)))
4248  {}
4249 
4250  bool send(const hrt_abstime t) override
4251  {
4253 
4254  if (_status_sub->update(&status)) {
4255  mavlink_command_long_t msg = {};
4256 
4257  msg.target_system = 0;
4258  msg.target_component = MAV_COMP_ID_ALL;
4259  msg.command = MAV_CMD_DO_CONTROL_VIDEO;
4260  msg.confirmation = 0;
4261  msg.param1 = 0;
4262  msg.param2 = 0;
4263  msg.param3 = 0;
4264  /* set camera capture ON/OFF depending on arming state */
4265  msg.param4 = (status.arming_state == vehicle_status_s::ARMING_STATE_ARMED) ? 1 : 0;
4266  msg.param5 = 0;
4267  msg.param6 = 0;
4268  msg.param7 = 0;
4269 
4270  mavlink_msg_command_long_send_struct(_mavlink->get_channel(), &msg);
4271  }
4272 
4273  return true;
4274  }
4275 };
4276 
4278 {
4279 public:
4280  const char *get_name() const override
4281  {
4283  }
4284 
4285  static const char *get_name_static()
4286  {
4287  return "DISTANCE_SENSOR";
4288  }
4289 
4290  static uint16_t get_id_static()
4291  {
4292  return MAVLINK_MSG_ID_DISTANCE_SENSOR;
4293  }
4294 
4295  uint16_t get_id() override
4296  {
4297  return get_id_static();
4298  }
4299 
4301  {
4302  return new MavlinkStreamDistanceSensor(mavlink);
4303  }
4304 
4305  unsigned get_size() override
4306  {
4307  return _distance_sensor_sub->is_published() ? (MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES) : 0;
4308  }
4309 
4310 private:
4313 
4314  /* do not allow top copying this class */
4317 
4318 protected:
4319  explicit MavlinkStreamDistanceSensor(Mavlink *mavlink) : MavlinkStream(mavlink),
4320  _distance_sensor_sub(_mavlink->add_orb_subscription(ORB_ID(distance_sensor))),
4321  _dist_sensor_time(0)
4322  {}
4323 
4324  bool send(const hrt_abstime t) override
4325  {
4326  distance_sensor_s dist_sensor;
4327 
4328  if (_distance_sensor_sub->update(&_dist_sensor_time, &dist_sensor)) {
4329  mavlink_distance_sensor_t msg = {};
4330 
4331  msg.time_boot_ms = dist_sensor.timestamp / 1000; /* us to ms */
4332 
4333 
4334  switch (dist_sensor.type) {
4335  case MAV_DISTANCE_SENSOR_ULTRASOUND:
4336  msg.type = MAV_DISTANCE_SENSOR_ULTRASOUND;
4337  break;
4338 
4339  case MAV_DISTANCE_SENSOR_LASER:
4340  msg.type = MAV_DISTANCE_SENSOR_LASER;
4341  break;
4342 
4343  case MAV_DISTANCE_SENSOR_INFRARED:
4344  msg.type = MAV_DISTANCE_SENSOR_INFRARED;
4345  break;
4346 
4347  default:
4348  msg.type = MAV_DISTANCE_SENSOR_LASER;
4349  break;
4350  }
4351 
4352  msg.current_distance = dist_sensor.current_distance * 1e2f; // m to cm
4353  msg.id = dist_sensor.id;
4354  msg.max_distance = dist_sensor.max_distance * 1e2f; // m to cm
4355  msg.min_distance = dist_sensor.min_distance * 1e2f; // m to cm
4356  msg.orientation = dist_sensor.orientation;
4357  msg.covariance = dist_sensor.variance * 1e4f; // m^2 to cm^2
4358 
4359  mavlink_msg_distance_sensor_send_struct(_mavlink->get_channel(), &msg);
4360 
4361  return true;
4362  }
4363 
4364  return false;
4365  }
4366 };
4367 
4369 {
4370 public:
4371  const char *get_name() const override
4372  {
4374  }
4375 
4376  static const char *get_name_static()
4377  {
4378  return "EXTENDED_SYS_STATE";
4379  }
4380 
4381  static uint16_t get_id_static()
4382  {
4383  return MAVLINK_MSG_ID_EXTENDED_SYS_STATE;
4384  }
4385 
4386  uint16_t get_id() override
4387  {
4388  return get_id_static();
4389  }
4390 
4392  {
4393  return new MavlinkStreamExtendedSysState(mavlink);
4394  }
4395 
4396  unsigned get_size() override
4397  {
4398  return MAVLINK_MSG_ID_EXTENDED_SYS_STATE_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
4399  }
4400 
4401 private:
4406  mavlink_extended_sys_state_t _msg;
4407 
4408  /* do not allow top copying this class */
4411 
4412 protected:
4413  explicit MavlinkStreamExtendedSysState(Mavlink *mavlink) : MavlinkStream(mavlink),
4414  _status_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_status))),
4415  _landed_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_land_detected))),
4416  _pos_sp_triplet_sub(_mavlink->add_orb_subscription(ORB_ID(position_setpoint_triplet))),
4417  _control_mode_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_control_mode))),
4418  _msg()
4419  {
4420  _msg.vtol_state = MAV_VTOL_STATE_UNDEFINED;
4421  _msg.landed_state = MAV_LANDED_STATE_ON_GROUND;
4422  }
4423 
4424  bool send(const hrt_abstime t) override
4425  {
4426  bool updated = false;
4427 
4429 
4430  if (_status_sub->update(&status)) {
4431  updated = true;
4432 
4433  if (status.is_vtol) {
4434  if (!status.in_transition_mode && status.vehicle_type == vehicle_status_s::VEHICLE_TYPE_ROTARY_WING) {
4435  _msg.vtol_state = MAV_VTOL_STATE_MC;
4436 
4437  } else if (!status.in_transition_mode) {
4438  _msg.vtol_state = MAV_VTOL_STATE_FW;
4439 
4440  } else if (status.in_transition_mode && status.in_transition_to_fw) {
4441  _msg.vtol_state = MAV_VTOL_STATE_TRANSITION_TO_FW;
4442 
4443  } else if (status.in_transition_mode) {
4444  _msg.vtol_state = MAV_VTOL_STATE_TRANSITION_TO_MC;
4445  }
4446  }
4447  }
4448 
4449  vehicle_land_detected_s land_detected;
4450 
4451  if (_landed_sub->update(&land_detected)) {
4452  updated = true;
4453 
4454  if (land_detected.landed) {
4455  _msg.landed_state = MAV_LANDED_STATE_ON_GROUND;
4456 
4457  } else if (!land_detected.landed) {
4458  _msg.landed_state = MAV_LANDED_STATE_IN_AIR;
4459 
4460  vehicle_control_mode_s control_mode;
4461  position_setpoint_triplet_s pos_sp_triplet;
4462 
4463  if (_control_mode_sub->update(&control_mode) && _pos_sp_triplet_sub->update(&pos_sp_triplet)) {
4464  if (control_mode.flag_control_auto_enabled && pos_sp_triplet.current.valid) {
4465  if (pos_sp_triplet.current.type == position_setpoint_s::SETPOINT_TYPE_TAKEOFF) {
4466  _msg.landed_state = MAV_LANDED_STATE_TAKEOFF;
4467 
4468  } else if (pos_sp_triplet.current.type == position_setpoint_s::SETPOINT_TYPE_LAND) {
4469  _msg.landed_state = MAV_LANDED_STATE_LANDING;
4470  }
4471  }
4472  }
4473  }
4474  }
4475 
4476  if (updated) {
4477  mavlink_msg_extended_sys_state_send_struct(_mavlink->get_channel(), &_msg);
4478  }
4479 
4480  return updated;
4481  }
4482 };
4483 
4485 {
4486 public:
4487  const char *get_name() const override
4488  {
4490  }
4491 
4492  static const char *get_name_static()
4493  {
4494  return "ALTITUDE";
4495  }
4496 
4497  static uint16_t get_id_static()
4498  {
4499  return MAVLINK_MSG_ID_ALTITUDE;
4500  }
4501 
4502  uint16_t get_id() override
4503  {
4504  return get_id_static();
4505  }
4506 
4508  {
4509  return new MavlinkStreamAltitude(mavlink);
4510  }
4511 
4512  unsigned get_size() override
4513  {
4514  return (_local_pos_time > 0) ? MAVLINK_MSG_ID_ALTITUDE_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES : 0;
4515  }
4516 
4517 private:
4521 
4522  uint64_t _local_pos_time{0};
4523 
4524  /* do not allow top copying this class */
4527 
4528 protected:
4529  explicit MavlinkStreamAltitude(Mavlink *mavlink) : MavlinkStream(mavlink),
4530  _local_pos_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_local_position))),
4531  _home_sub(_mavlink->add_orb_subscription(ORB_ID(home_position))),
4532  _air_data_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_air_data)))
4533  {}
4534 
4535  bool send(const hrt_abstime t) override
4536  {
4537  mavlink_altitude_t msg = {};
4538 
4539  msg.altitude_monotonic = NAN;
4540  msg.altitude_amsl = NAN;
4541  msg.altitude_local = NAN;
4542  msg.altitude_relative = NAN;
4543  msg.altitude_terrain = NAN;
4544  msg.bottom_clearance = NAN;
4545 
4546  // always update monotonic altitude
4547  bool air_data_updated = false;
4548  vehicle_air_data_s air_data = {};
4549  _air_data_sub->update(&air_data);
4550 
4551  if (air_data.timestamp > 0) {
4552  msg.altitude_monotonic = air_data.baro_alt_meter;
4553 
4554  air_data_updated = true;
4555  }
4556 
4557  bool lpos_updated = false;
4558 
4559  vehicle_local_position_s local_pos;
4560 
4561  if (_local_pos_sub->update(&_local_pos_time, &local_pos)) {
4562 
4563  if (local_pos.z_valid) {
4564  if (local_pos.z_global) {
4565  msg.altitude_amsl = -local_pos.z + local_pos.ref_alt;
4566 
4567  } else {
4568  msg.altitude_amsl = msg.altitude_monotonic;
4569  }
4570 
4571  msg.altitude_local = -local_pos.z;
4572 
4573  home_position_s home = {};
4574  _home_sub->update(&home);
4575 
4576  if (home.valid_alt) {
4577  msg.altitude_relative = -(local_pos.z - home.z);
4578 
4579  } else {
4580  msg.altitude_relative = -local_pos.z;
4581  }
4582 
4583  if (local_pos.dist_bottom_valid) {
4584  msg.altitude_terrain = -local_pos.z - local_pos.dist_bottom;
4585  msg.bottom_clearance = local_pos.dist_bottom;
4586  }
4587  }
4588 
4589  lpos_updated = true;
4590  }
4591 
4592  // local position timeout after 10 ms
4593  // avoid publishing only baro altitude_monotonic if possible
4594  bool lpos_timeout = (hrt_elapsed_time(&_local_pos_time) > 10000);
4595 
4596  if (lpos_updated || (air_data_updated && lpos_timeout)) {
4597  msg.time_usec = hrt_absolute_time();
4598  mavlink_msg_altitude_send_struct(_mavlink->get_channel(), &msg);
4599 
4600  return true;
4601  }
4602 
4603  return false;
4604  }
4605 };
4606 
4608 {
4609 public:
4610  const char *get_name() const override
4611  {
4613  }
4614 
4615  static const char *get_name_static()
4616  {
4617  return "WIND_COV";
4618  }
4619 
4620  static uint16_t get_id_static()
4621  {
4622  return MAVLINK_MSG_ID_WIND_COV;
4623  }
4624 
4625  uint16_t get_id() override
4626  {
4627  return get_id_static();
4628  }
4629 
4631  {
4632  return new MavlinkStreamWind(mavlink);
4633  }
4634 
4635  unsigned get_size() override
4636  {
4637  return (_wind_estimate_time > 0) ? MAVLINK_MSG_ID_WIND_COV_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES : 0;
4638  }
4639 
4640 private:
4643 
4645 
4646  /* do not allow top copying this class */
4648  MavlinkStreamWind &operator = (const MavlinkStreamWind &) = delete;
4649 
4650 protected:
4651  explicit MavlinkStreamWind(Mavlink *mavlink) : MavlinkStream(mavlink),
4652  _wind_estimate_sub(_mavlink->add_orb_subscription(ORB_ID(wind_estimate))),
4653  _wind_estimate_time(0),
4654  _local_pos_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_local_position)))
4655  {}
4656 
4657  bool send(const hrt_abstime t) override
4658  {
4659  wind_estimate_s wind_estimate;
4660 
4661  if (_wind_estimate_sub->update(&_wind_estimate_time, &wind_estimate)) {
4662  mavlink_wind_cov_t msg = {};
4663 
4664  msg.time_usec = wind_estimate.timestamp;
4665 
4666  msg.wind_x = wind_estimate.windspeed_north;
4667  msg.wind_y = wind_estimate.windspeed_east;
4668  msg.wind_z = 0.0f;
4669 
4670  msg.var_horiz = wind_estimate.variance_north + wind_estimate.variance_east;
4671  msg.var_vert = 0.0f;
4672 
4673  vehicle_local_position_s lpos = {};
4674  _local_pos_sub->update(&lpos);
4675  msg.wind_alt = (lpos.z_valid && lpos.z_global) ? (-lpos.z + lpos.ref_alt) : NAN;
4676 
4677  msg.horiz_accuracy = 0.0f;
4678  msg.vert_accuracy = 0.0f;
4679 
4680  mavlink_msg_wind_cov_send_struct(_mavlink->get_channel(), &msg);
4681 
4682  return true;
4683  }
4684 
4685  return false;
4686  }
4687 };
4688 
4690 {
4691 public:
4692  const char *get_name() const override
4693  {
4695  }
4696 
4697  static const char *get_name_static()
4698  {
4699  return "MOUNT_ORIENTATION";
4700  }
4701 
4702  static uint16_t get_id_static()
4703  {
4704  return MAVLINK_MSG_ID_MOUNT_ORIENTATION;
4705  }
4706 
4707  uint16_t get_id() override
4708  {
4709  return get_id_static();
4710  }
4711 
4713  {
4714  return new MavlinkStreamMountOrientation(mavlink);
4715  }
4716 
4717  unsigned get_size() override
4718  {
4719  return (_mount_orientation_time > 0) ? MAVLINK_MSG_ID_MOUNT_ORIENTATION_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES : 0;
4720  }
4721 
4722 private:
4725 
4726  /* do not allow top copying this class */
4729 
4730 protected:
4731  explicit MavlinkStreamMountOrientation(Mavlink *mavlink) : MavlinkStream(mavlink),
4732  _mount_orientation_sub(_mavlink->add_orb_subscription(ORB_ID(mount_orientation))),
4733  _mount_orientation_time(0)
4734  {}
4735 
4736  bool send(const hrt_abstime t) override
4737  {
4738  struct mount_orientation_s mount_orientation;
4739 
4740  if (_mount_orientation_sub->update(&_mount_orientation_time, &mount_orientation)) {
4741  mavlink_mount_orientation_t msg = {};
4742 
4743  msg.roll = math::degrees(mount_orientation.attitude_euler_angle[0]);
4744  msg.pitch = math::degrees(mount_orientation.attitude_euler_angle[1]);
4745  msg.yaw = math::degrees(mount_orientation.attitude_euler_angle[2]);
4746 
4747  mavlink_msg_mount_orientation_send_struct(_mavlink->get_channel(), &msg);
4748 
4749  return true;
4750  }
4751 
4752  return false;
4753  }
4754 };
4755 
4757 {
4758 public:
4759  const char *get_name() const override
4760  {
4762  }
4763 
4764  static const char *get_name_static()
4765  {
4766  return "GROUND_TRUTH";
4767  }
4768 
4769  static uint16_t get_id_static()
4770  {
4771  return MAVLINK_MSG_ID_HIL_STATE_QUATERNION;
4772  }
4773 
4774  uint16_t get_id() override
4775  {
4776  return get_id_static();
4777  }
4778 
4780  {
4781  return new MavlinkStreamGroundTruth(mavlink);
4782  }
4783 
4784  unsigned get_size() override
4785  {
4786  return (_att_time > 0 || _gpos_time > 0) ? MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN +
4787  MAVLINK_NUM_NON_PAYLOAD_BYTES : 0;
4788  }
4789 
4790 private:
4795 
4796  uint64_t _angular_velocity_time{0};
4797  uint64_t _att_time{0};
4798  uint64_t _gpos_time{0};
4799  uint64_t _lpos_time{0};
4800 
4801  /* do not allow top copying this class */
4804 
4805 protected:
4806  explicit MavlinkStreamGroundTruth(Mavlink *mavlink) : MavlinkStream(mavlink),
4807  _angular_velocity_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_angular_velocity_groundtruth))),
4808  _att_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_attitude_groundtruth))),
4809  _gpos_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_global_position_groundtruth))),
4810  _lpos_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_local_position_groundtruth)))
4811  {}
4812 
4813  bool send(const hrt_abstime t) override
4814  {
4815  bool updated = false;
4816 
4817  vehicle_angular_velocity_s angular_velocity{};
4818  vehicle_attitude_s att{};
4820  vehicle_local_position_s lpos{};
4821 
4822  updated |= _angular_velocity_sub->update(&_angular_velocity_time, &angular_velocity);
4823  updated |= _att_sub->update(&_att_time, &att);
4824  updated |= _gpos_sub->update(&_gpos_time, &gpos);
4825  updated |= _lpos_sub->update(&_lpos_time, &lpos);
4826 
4827  if (updated) {
4828  mavlink_hil_state_quaternion_t msg = {};
4829 
4830  // vehicle_attitude -> hil_state_quaternion
4831  msg.attitude_quaternion[0] = att.q[0];
4832  msg.attitude_quaternion[1] = att.q[1];
4833  msg.attitude_quaternion[2] = att.q[2];
4834  msg.attitude_quaternion[3] = att.q[3];
4835  msg.rollspeed = angular_velocity.xyz[0];
4836  msg.pitchspeed = angular_velocity.xyz[1];
4837  msg.yawspeed = angular_velocity.xyz[2];
4838 
4839  // vehicle_global_position -> hil_state_quaternion
4840  // same units as defined in mavlink/common.xml
4841  msg.lat = gpos.lat * 1e7;
4842  msg.lon = gpos.lon * 1e7;
4843  msg.alt = gpos.alt * 1e3f;
4844  msg.vx = lpos.vx * 1e2f;
4845  msg.vy = lpos.vy * 1e2f;
4846  msg.vz = lpos.vz * 1e2f;
4847  msg.ind_airspeed = 0;
4848  msg.true_airspeed = 0;
4849  msg.xacc = lpos.ax;
4850  msg.yacc = lpos.ay;
4851  msg.zacc = lpos.az;
4852 
4853  mavlink_msg_hil_state_quaternion_send_struct(_mavlink->get_channel(), &msg);
4854 
4855  return true;
4856  }
4857 
4858  return false;
4859  }
4860 };
4861 
4863 {
4864 public:
4865  const char *get_name() const override
4866  {
4868  }
4869 
4870  static const char *get_name_static()
4871  {
4872  return "PING";
4873  }
4874 
4875  static uint16_t get_id_static()
4876  {
4877  return MAVLINK_MSG_ID_PING;
4878  }
4879 
4880  uint16_t get_id() override
4881  {
4882  return get_id_static();
4883  }
4884 
4886  {
4887  return new MavlinkStreamPing(mavlink);
4888  }
4889 
4890  unsigned get_size() override
4891  {
4892  return MAVLINK_MSG_ID_PING_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
4893  }
4894 
4895  bool const_rate() override
4896  {
4897  return true;
4898  }
4899 
4900 private:
4901  uint32_t _sequence;
4902 
4903  /* do not allow top copying this class */
4905  MavlinkStreamPing &operator = (const MavlinkStreamPing &) = delete;
4906 
4907 protected:
4908  explicit MavlinkStreamPing(Mavlink *mavlink) : MavlinkStream(mavlink),
4909  _sequence(0)
4910  {}
4911 
4912  bool send(const hrt_abstime t) override
4913  {
4914  mavlink_ping_t msg = {};
4915 
4916  msg.time_usec = hrt_absolute_time();
4917  msg.seq = _sequence++;
4918  msg.target_system = 0; // All systems
4919  msg.target_component = 0; // All components
4920 
4921  mavlink_msg_ping_send_struct(_mavlink->get_channel(), &msg);
4922 
4923  return true;
4924  }
4925 };
4926 
4928 {
4929 public:
4930  const char *get_name() const override
4931  {
4933  }
4934 
4935  static const char *get_name_static()
4936  {
4937  return "ORBIT_EXECUTION_STATUS";
4938  }
4939 
4940  static uint16_t get_id_static()
4941  {
4942  return MAVLINK_MSG_ID_ORBIT_EXECUTION_STATUS;
4943  }
4944 
4945  uint16_t get_id() override
4946  {
4947  return get_id_static();
4948  }
4949 
4951  {
4952  return new MavlinkStreamOrbitStatus(mavlink);
4953  }
4954 
4955  unsigned get_size() override
4956  {
4957  return MAVLINK_MSG_ID_ORBIT_EXECUTION_STATUS_LEN +
4958  MAVLINK_NUM_NON_PAYLOAD_BYTES;
4959  }
4960 
4961 private:
4964 
4965  /* do not allow top copying this class */
4968 
4969 protected:
4970  explicit MavlinkStreamOrbitStatus(Mavlink *mavlink) : MavlinkStream(mavlink),
4971  _sub(_mavlink->add_orb_subscription(ORB_ID(orbit_status))),
4972  _orbit_status_time(0)
4973  {}
4974 
4975  bool send(const hrt_abstime t) override
4976  {
4977  struct orbit_status_s _orbit_status;
4978 
4979  if (_sub->update(&_orbit_status_time, &_orbit_status)) {
4980  mavlink_orbit_execution_status_t _msg_orbit_execution_status = {};
4981 
4982  _msg_orbit_execution_status.time_usec = _orbit_status.timestamp;
4983  _msg_orbit_execution_status.radius = _orbit_status.radius;
4984  _msg_orbit_execution_status.frame = _orbit_status.frame;
4985  _msg_orbit_execution_status.x = _orbit_status.x * 1e7;
4986  _msg_orbit_execution_status.y = _orbit_status.y * 1e7;
4987  _msg_orbit_execution_status.z = _orbit_status.z;
4988 
4989  mavlink_msg_orbit_execution_status_send_struct(_mavlink->get_channel(), &_msg_orbit_execution_status);
4990  }
4991 
4992  return true;
4993  }
4994 };
4995 
4997 {
4998 public:
4999  const char *get_name() const override
5000  {
5002  }
5003 
5004  static const char *get_name_static()
5005  {
5006  return "OBSTACLE_DISTANCE";
5007  }
5008 
5009  static uint16_t get_id_static()
5010  {
5011  return MAVLINK_MSG_ID_OBSTACLE_DISTANCE;
5012  }
5013 
5014  uint16_t get_id() override
5015  {
5016  return get_id_static();
5017  }
5018 
5020  {
5021  return new MavlinkStreamObstacleDistance(mavlink);
5022  }
5023 
5024  unsigned get_size() override
5025  {
5026  return _obstacle_distance_fused_sub->is_published() ? (MAVLINK_MSG_ID_OBSTACLE_DISTANCE_LEN +
5027  MAVLINK_NUM_NON_PAYLOAD_BYTES) :
5028  0;
5029  }
5030 
5031 private:
5034 
5035  /* do not allow top copying this class */
5038 
5039 protected:
5040  explicit MavlinkStreamObstacleDistance(Mavlink *mavlink) : MavlinkStream(mavlink),
5041  _obstacle_distance_fused_sub(_mavlink->add_orb_subscription(ORB_ID(obstacle_distance_fused))),
5042  _obstacle_distance_time(0)
5043  {}
5044 
5045  bool send(const hrt_abstime t) override
5046  {
5047  obstacle_distance_s obstacke_distance;
5048 
5049  if (_obstacle_distance_fused_sub->update(&_obstacle_distance_time, &obstacke_distance)) {
5050  mavlink_obstacle_distance_t msg = {};
5051 
5052  msg.time_usec = obstacke_distance.timestamp;
5053  msg.sensor_type = obstacke_distance.sensor_type;
5054  memcpy(msg.distances, obstacke_distance.distances, sizeof(msg.distances));
5055  msg.increment = 0;
5056  msg.min_distance = obstacke_distance.min_distance;
5057  msg.max_distance = obstacke_distance.max_distance;
5058  msg.angle_offset = obstacke_distance.angle_offset;
5059  msg.increment_f = obstacke_distance.increment;
5060 
5061  mavlink_msg_obstacle_distance_send_struct(_mavlink->get_channel(), &msg);
5062 
5063  return true;
5064  }
5065 
5066  return false;
5067  }
5068 };
5069 
5070 static const StreamListItem streams_list[] = {
5104  //StreamListItem(&MavlinkStreamActuatorControlTarget<1>::new_instance, &MavlinkStreamActuatorControlTarget<1>::get_name_static, &MavlinkStreamActuatorControlTarget<1>::get_id_static),
5105  //StreamListItem(&MavlinkStreamActuatorControlTarget<2>::new_instance, &MavlinkStreamActuatorControlTarget<2>::get_name_static, &MavlinkStreamActuatorControlTarget<2>::get_id_static),
5106  //StreamListItem(&MavlinkStreamActuatorControlTarget<3>::new_instance, &MavlinkStreamActuatorControlTarget<3>::get_name_static, &MavlinkStreamActuatorControlTarget<3>::get_id_static),
5128 };
5129 
5130 const char *get_stream_name(const uint16_t msg_id)
5131 {
5132  // search for stream with specified msg id in supported streams list
5133  for (const auto &stream : streams_list) {
5134  if (msg_id == stream.get_id()) {
5135  return stream.get_name();
5136  }
5137  }
5138 
5139  return nullptr;
5140 }
5141 
5142 MavlinkStream *create_mavlink_stream(const char *stream_name, Mavlink *mavlink)
5143 {
5144  // search for stream with specified name in supported streams list
5145  if (stream_name != nullptr) {
5146  for (const auto &stream : streams_list) {
5147  if (strcmp(stream_name, stream.get_name()) == 0) {
5148  return stream.new_instance(mavlink);
5149  }
5150  }
5151  }
5152 
5153  return nullptr;
5154 }
#define PWM_DEFAULT_MAX
Default maximum PWM in us.
#define VEHICLE_TYPE_FIXED_WING
uint32_t onboard_control_sensors_enabled
int16_t gyro_temperature
Definition: optical_flow.h:66
uint64_t timestamp
Definition: sensor_accel.h:53
static struct vehicle_status_s status
Definition: Commander.cpp:138
Type theta() const
Definition: Euler.hpp:132
uint64_t timestamp
Definition: home_position.h:53
float gyro_x_rate_integral
Definition: optical_flow.h:56
int32_t rssi
Definition: input_rc.h:72
uint64_t timestamp
Definition: orbit_status.h:53
float mag_bias[3]
Definition: sensor_bias.h:56
API for the uORB lightweight object broker.
Definition of geo / math functions to perform geodesic calculations.
uint64_t timestamp
Definition: optical_flow.h:53
int16_t x_raw
Definition: sensor_gyro.h:65
float pixel_flow_y_integral
Definition: optical_flow.h:55
float airspeed_filtered
Definition: tecs_status.h:66
char name[10]
Definition: debug_vect.h:57
float pixel_flow_x_integral
Definition: optical_flow.h:54
float accelerometer_m_s2[3]
float altitude_sp
Definition: tecs_status.h:61
uint64_t timestamp
Definition: input_rc.h:69
int16_t z_raw
Definition: sensor_gyro.h:67
int16_t y_raw
Definition: sensor_gyro.h:66
float ground_distance_m
Definition: optical_flow.h:59
constexpr T degrees(T radians)
Definition: Limits.hpp:91
void copyTo(Type dst[M *N]) const
Definition: Matrix.hpp:115
Type phi() const
Definition: Euler.hpp:128
uint32_t time_since_last_sonar_update
Definition: optical_flow.h:61
Vector rotation library.
Quaternion class.
Definition: Dcm.hpp:24
Matrix< Type, N, M > transpose() const
Definition: Matrix.hpp:353
float load
Definition: cpuload.h:54
static constexpr float CONSTANTS_ONE_G
Definition: geo.h:51
float velocity_covariance[21]
Type psi() const
Definition: Euler.hpp:136
Type wrap_2pi(Type x)
Wrap value in range [0, 2Ï€)
static char msg[NUM_MSG][CONFIG_USART1_TXBUFSIZE]
Definition: px4io.c:89
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
Definition: uORB.h:87
struct position_setpoint_s current
uint64_t timestamp
Definition: wind_estimate.h:53
uint16_t values[18]
Definition: input_rc.h:76
uint16_t solution_status_flags
char name[10]
Definition: debug_array.h:57
uint32_t channel_count
Definition: input_rc.h:71
static struct actuator_armed_s armed
Definition: Commander.cpp:139
uint16_t id
Definition: debug_array.h:56
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
uint64_t timestamp_utc
static hrt_abstime hrt_elapsed_time(const hrt_abstime *then)
Compute the delta between a timestamp taken in the past and now.
Definition: drv_hrt.h:102
Euler< float > Eulerf
Definition: Euler.hpp:156
uint64_t timestamp
Definition: debug_vect.h:53
float indicated_airspeed_m_s
Definition: airspeed.h:54
Euler angles class.
Definition: AxisAngle.hpp:18
uint64_t timestamp
Definition: debug_value.h:53
__BEGIN_DECLS typedef uint64_t hrt_abstime
Absolute time, in microsecond units.
Definition: drv_hrt.h:58
float gyro_bias[3]
Definition: sensor_bias.h:54
uint64_t timestamp
Definition: debug_array.h:54
float altitude_filtered
Definition: tecs_status.h:62
static int _home_sub
Definition: messages.cpp:62
Vector3< float > Vector3f
Definition: Vector3.hpp:136
uint32_t onboard_control_sensors_health
float airspeed_sp
Definition: tecs_status.h:65
constexpr _Tp max(_Tp a, _Tp b)
Definition: Limits.hpp:60
Quaternion< float > Quatf
Definition: Quaternion.hpp:544
float accel_bias[3]
Definition: sensor_bias.h:55
PX4 custom flight modes.
#define ORB_MULTI_MAX_INSTANCES
Maximum number of multi topic instances.
Definition: uORB.h:62
static struct cpuload_s cpuload
Definition: Commander.cpp:151
int16_t z_raw
Definition: sensor_mag.h:63
uint32_t integration_timespan
Definition: optical_flow.h:60
float data[58]
Definition: debug_array.h:55
struct trajectory_waypoint_s waypoints[5]
int16_t x_raw
Definition: sensor_mag.h:61
#define M_PI_F
Definition: ashtech.cpp:44
uint8_t sensor_id
Definition: optical_flow.h:67
float gyro_z_rate_integral
Definition: optical_flow.h:58
int32_t accelerometer_timestamp_relative
__EXPORT matrix::Quatf get_rot_quaternion(enum Rotation rot)
Get the rotation quaternion.
Definition: rotation.cpp:54
float gyro_y_rate_integral
Definition: optical_flow.h:57
int16_t y_raw
Definition: sensor_mag.h:62
#define PWM_DEFAULT_MIN
Default minimum PWM in us.
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
uint32_t onboard_control_sensors_present
uint8_t quality
Definition: optical_flow.h:68