PX4 Firmware
PX4 Autopilot Software http://px4.io
mavlink_high_latency2.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2015-2018 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_high_latency2.cpp
36  *
37  * @author Achermann Florian <acfloria@ethz.ch>
38  */
39 
40 #include "mavlink_high_latency2.h"
41 
43 #include <lib/ecl/geo/geo.h>
44 #include <lib/mathlib/mathlib.h>
47 #include <uORB/topics/airspeed.h>
60 #include <uORB/uORB.h>
61 
62 using matrix::wrap_2pi;
63 
65  _actuator_sub_0(_mavlink->add_orb_subscription(ORB_ID(actuator_controls_0))),
66  _actuator_time_0(0),
67  _actuator_sub_1(_mavlink->add_orb_subscription(ORB_ID(actuator_controls_1))),
68  _actuator_time_1(0),
69  _airspeed_sub(_mavlink->add_orb_subscription(ORB_ID(airspeed))),
70  _airspeed_time(0),
71  _attitude_sp_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_attitude_setpoint))),
72  _attitude_sp_time(0),
73  _estimator_status_sub(_mavlink->add_orb_subscription(ORB_ID(estimator_status))),
74  _estimator_status_time(0),
75  _pos_ctrl_status_sub(_mavlink->add_orb_subscription(ORB_ID(position_controller_status))),
76  _pos_ctrl_status_time(0),
77  _geofence_sub(_mavlink->add_orb_subscription(ORB_ID(geofence_result))),
78  _geofence_time(0),
79  _global_pos_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_global_position))),
80  _global_pos_time(0),
81  _gps_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_gps_position))),
82  _gps_time(0),
83  _mission_result_sub(_mavlink->add_orb_subscription(ORB_ID(mission_result))),
84  _mission_result_time(0),
85  _status_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_status))),
86  _status_time(0),
87  _status_flags_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_status_flags))),
88  _status_flags_time(0),
89  _tecs_status_sub(_mavlink->add_orb_subscription(ORB_ID(tecs_status))),
90  _tecs_time(0),
91  _wind_sub(_mavlink->add_orb_subscription(ORB_ID(wind_estimate))),
92  _wind_time(0),
93  _airspeed(SimpleAnalyzer::AVERAGE),
94  _airspeed_sp(SimpleAnalyzer::AVERAGE),
95  _climb_rate(SimpleAnalyzer::MAX),
96  _eph(SimpleAnalyzer::MAX),
97  _epv(SimpleAnalyzer::MAX),
98  _groundspeed(SimpleAnalyzer::AVERAGE),
99  _temperature(SimpleAnalyzer::AVERAGE),
100  _throttle(SimpleAnalyzer::AVERAGE),
101  _windspeed(SimpleAnalyzer::AVERAGE)
102 {
103 
104  for (int i = 0; i < ORB_MULTI_MAX_INSTANCES; i++) {
106  }
107 
108  reset_last_sent();
109 }
110 
112 {
113  // only send the struct if transmitting is allowed
114  // this assures that the stream timer is only reset when actually a message is transmitted
115  if (_mavlink->should_transmit()) {
116  mavlink_high_latency2_t msg = {};
117  set_default_values(msg);
118 
119  bool updated = _airspeed.valid();
120  updated |= _airspeed_sp.valid();
121 
122  for (int i = 0; i < ORB_MULTI_MAX_INSTANCES; i++) {
123  updated |= _batteries[i].analyzer.valid();
124  }
125 
126  updated |= _climb_rate.valid();
127  updated |= _eph.valid();
128  updated |= _epv.valid();
129  updated |= _groundspeed.valid();
130  updated |= _temperature.valid();
131  updated |= _throttle.valid();
132  updated |= _windspeed.valid();
133  updated |= write_airspeed(&msg);
134  updated |= write_attitude_sp(&msg);
135  updated |= write_battery_status(&msg);
136  updated |= write_estimator_status(&msg);
137  updated |= write_fw_ctrl_status(&msg);
138  updated |= write_geofence_result(&msg);
139  updated |= write_global_position(&msg);
140  updated |= write_mission_result(&msg);
141  updated |= write_tecs_status(&msg);
142  updated |= write_vehicle_status(&msg);
143  updated |= write_vehicle_status_flags(&msg);
144  updated |= write_wind_estimate(&msg);
145 
146  if (updated) {
147  msg.timestamp = t / 1000;
148 
149  msg.type = _mavlink->get_system_type();
150  msg.autopilot = MAV_AUTOPILOT_PX4;
151 
152  if (_airspeed.valid()) {
153  _airspeed.get_scaled(msg.airspeed, 5.0f);
154  }
155 
156  if (_airspeed_sp.valid()) {
157  _airspeed_sp.get_scaled(msg.airspeed_sp, 5.0f);
158  }
159 
160  int lowest = 0;
161 
162  for (int i = 1; i < ORB_MULTI_MAX_INSTANCES; i++) {
163  const bool battery_connected = _batteries[i].connected && _batteries[i].analyzer.valid();
164  const bool battery_is_lowest = _batteries[i].analyzer.get_scaled(100.0f) <= _batteries[lowest].analyzer.get_scaled(
165  100.0f);
166 
167  if (battery_connected && battery_is_lowest) {
168  lowest = i;
169  }
170 
171  }
172 
173  if (_batteries[lowest].connected) {
174  _batteries[lowest].analyzer.get_scaled(msg.battery, 100.0f);
175 
176  } else {
177  msg.battery = -1;
178  }
179 
180 
181  if (_climb_rate.valid()) {
182  _climb_rate.get_scaled(msg.climb_rate, 10.0f);
183  }
184 
185  if (_eph.valid()) {
186  _eph.get_scaled(msg.eph, 10.0f);
187  }
188 
189  if (_epv.valid()) {
190  _epv.get_scaled(msg.epv, 10.0f);
191  }
192 
193  if (_groundspeed.valid()) {
194  _groundspeed.get_scaled(msg.groundspeed, 5.0f);
195  }
196 
197  if (_temperature.valid()) {
198  _temperature.get_scaled(msg.temperature_air, 1.0f);
199  }
200 
201  if (_throttle.valid()) {
202  _throttle.get_scaled(msg.throttle, 100.0f);
203  }
204 
205  if (_windspeed.valid()) {
206  _windspeed.get_scaled(msg.windspeed, 5.0f);
207  }
208 
209  reset_analysers(t);
210 
211  mavlink_msg_high_latency2_send_struct(_mavlink->get_channel(), &msg);
212  }
213 
214  return updated;
215 
216  } else {
217  // reset the analysers every 60 seconds if nothing should be transmitted
218  if ((t - _last_reset_time) > 60000000) {
219  reset_analysers(t);
220  PX4_DEBUG("Resetting HIGH_LATENCY2 analysers");
221  }
222 
223  return false;
224  }
225 }
226 
228 {
229  // reset the analyzers
230  _airspeed.reset();
232 
233  for (int i = 0; i < ORB_MULTI_MAX_INSTANCES; i++) {
235  }
236 
237  _climb_rate.reset();
238  _eph.reset();
239  _epv.reset();
242  _throttle.reset();
243  _windspeed.reset();
244 
245  _last_reset_time = t;
246 }
247 
248 bool MavlinkStreamHighLatency2::write_airspeed(mavlink_high_latency2_t *msg)
249 {
250  struct airspeed_s airspeed;
251 
252  const bool updated = _airspeed_sub->update(&_airspeed_time, &airspeed);
253 
254  if (_airspeed_time > 0) {
255  if (airspeed.confidence < 0.95f) { // the same threshold as for the commander
256  msg->failure_flags |= HL_FAILURE_FLAG_DIFFERENTIAL_PRESSURE;
257  }
258  }
259 
260  return updated;
261 }
262 
263 bool MavlinkStreamHighLatency2::write_attitude_sp(mavlink_high_latency2_t *msg)
264 {
265  struct vehicle_attitude_setpoint_s attitude_sp;
266 
267  const bool updated = _attitude_sp_sub->update(&_attitude_sp_time, &attitude_sp);
268 
269  if (_attitude_sp_time > 0) {
270  msg->target_heading = static_cast<uint8_t>(math::degrees(wrap_2pi(attitude_sp.yaw_body)) * 0.5f);
271  }
272 
273  return updated;
274 }
275 
277 {
278  struct battery_status_s battery;
279  bool updated = false;
280 
281  for (int i = 0; i < ORB_MULTI_MAX_INSTANCES; i++) {
282  if (_batteries[i].subscription->update(&_batteries[i].timestamp, &battery)) {
283  updated = true;
284  _batteries[i].connected = battery.connected;
285 
286  if (battery.warning > battery_status_s::BATTERY_WARNING_LOW) {
287  msg->failure_flags |= HL_FAILURE_FLAG_BATTERY;
288  }
289  }
290  }
291 
292  return updated;
293 }
294 
296 {
297  struct estimator_status_s estimator_status;
298 
299  const bool updated = _estimator_status_sub->update(&_estimator_status_time, &estimator_status);
300 
301  if (_estimator_status_time > 0) {
302  if (estimator_status.gps_check_fail_flags > 0 ||
303  estimator_status.filter_fault_flags > 0 ||
304  estimator_status.innovation_check_flags > 0) {
305  msg->failure_flags |= HL_FAILURE_FLAG_ESTIMATOR;
306  }
307  }
308 
309  return updated;
310 }
311 
313 {
314  position_controller_status_s pos_ctrl_status = {};
315 
316  const bool updated = _pos_ctrl_status_sub->update(&_pos_ctrl_status_time, &pos_ctrl_status);
317 
318  if (_pos_ctrl_status_time > 0) {
319  uint16_t target_distance;
320  convert_limit_safe(pos_ctrl_status.wp_dist * 0.1f, target_distance);
321  msg->target_distance = target_distance;
322  }
323 
324  return updated;
325 }
326 
328 {
329  struct geofence_result_s geofence;
330 
331  const bool updated = _geofence_sub->update(&_geofence_time, &geofence);
332 
333  if (_geofence_time > 0) {
334  if (geofence.geofence_violated) {
335  msg->failure_flags |= HL_FAILURE_FLAG_GEOFENCE;
336  }
337  }
338 
339  return updated;
340 }
341 
343 {
344  struct vehicle_global_position_s global_pos;
345 
346  const bool updated = _global_pos_sub->update(&_global_pos_time, &global_pos);
347 
348  if (_global_pos_time > 0) {
349  msg->latitude = global_pos.lat * 1e7;
350  msg->longitude = global_pos.lon * 1e7;
351 
352  int16_t altitude = 0;
353 
354  if (global_pos.alt > 0) {
355  convert_limit_safe(global_pos.alt + 0.5f, altitude);
356 
357  } else {
358  convert_limit_safe(global_pos.alt - 0.5f, altitude);
359  }
360 
361  msg->altitude = altitude;
362 
363  msg->heading = static_cast<uint8_t>(math::degrees(wrap_2pi(global_pos.yaw)) * 0.5f);
364  }
365 
366  return updated;
367 }
368 
370 {
371  struct mission_result_s mission_result;
372 
373  const bool updated = _mission_result_sub->update(&_mission_result_time, &mission_result);
374 
375  if (_mission_result_time > 0) {
376  msg->wp_num = mission_result.seq_current;
377  }
378 
379  return updated;
380 }
381 
382 bool MavlinkStreamHighLatency2::write_tecs_status(mavlink_high_latency2_t *msg)
383 {
384  struct tecs_status_s tecs_status;
385 
386  const bool updated = _tecs_status_sub->update(&_tecs_time, &tecs_status);
387 
388  if (_tecs_time > 0) {
389  int16_t target_altitude;
390  convert_limit_safe(tecs_status.altitude_sp, target_altitude);
391  msg->target_altitude = target_altitude;
392  }
393 
394  return updated;
395 }
396 
398 {
399  struct vehicle_status_s status;
400 
401  const bool updated = _status_sub->update(&_status_time, &status);
402 
403  if (_status_time > 0) {
404  if ((status.onboard_control_sensors_enabled & MAV_SYS_STATUS_SENSOR_ABSOLUTE_PRESSURE)
405  && !(status.onboard_control_sensors_health & MAV_SYS_STATUS_SENSOR_ABSOLUTE_PRESSURE)) {
406  msg->failure_flags |= HL_FAILURE_FLAG_ABSOLUTE_PRESSURE;
407  }
408 
409  if (((status.onboard_control_sensors_enabled & MAV_SYS_STATUS_SENSOR_3D_ACCEL)
410  && !(status.onboard_control_sensors_health & MAV_SYS_STATUS_SENSOR_3D_ACCEL)) ||
411  ((status.onboard_control_sensors_enabled & MAV_SYS_STATUS_SENSOR_3D_ACCEL2) &&
412  !(status.onboard_control_sensors_health & MAV_SYS_STATUS_SENSOR_3D_ACCEL2))) {
413  msg->failure_flags |= HL_FAILURE_FLAG_3D_ACCEL;
414  }
415 
416  if (((status.onboard_control_sensors_enabled & MAV_SYS_STATUS_SENSOR_3D_GYRO)
417  && !(status.onboard_control_sensors_health & MAV_SYS_STATUS_SENSOR_3D_GYRO)) ||
418  ((status.onboard_control_sensors_enabled & MAV_SYS_STATUS_SENSOR_3D_GYRO2) &&
419  !(status.onboard_control_sensors_health & MAV_SYS_STATUS_SENSOR_3D_GYRO2))) {
420  msg->failure_flags |= HL_FAILURE_FLAG_3D_GYRO;
421  }
422 
423  if (((status.onboard_control_sensors_enabled & MAV_SYS_STATUS_SENSOR_3D_MAG)
424  && !(status.onboard_control_sensors_health & MAV_SYS_STATUS_SENSOR_3D_MAG)) ||
425  ((status.onboard_control_sensors_enabled & MAV_SYS_STATUS_SENSOR_3D_MAG2) &&
426  !(status.onboard_control_sensors_health & MAV_SYS_STATUS_SENSOR_3D_MAG2))) {
427  msg->failure_flags |= HL_FAILURE_FLAG_3D_MAG;
428  }
429 
430  if ((status.onboard_control_sensors_enabled & MAV_SYS_STATUS_TERRAIN)
431  && !(status.onboard_control_sensors_health & MAV_SYS_STATUS_TERRAIN)) {
432  msg->failure_flags |= HL_FAILURE_FLAG_TERRAIN;
433  }
434 
435  if (status.rc_signal_lost) {
436  msg->failure_flags |= HL_FAILURE_FLAG_RC_RECEIVER;
437  }
438 
439  if (status.engine_failure) {
440  msg->failure_flags |= HL_FAILURE_FLAG_ENGINE;
441  }
442 
443  if (status.mission_failure) {
444  msg->failure_flags |= HL_FAILURE_FLAG_MISSION;
445  }
446 
447  // flight mode
448  union px4_custom_mode custom_mode;
449  uint8_t mavlink_base_mode;
450  get_mavlink_navigation_mode(&status, &mavlink_base_mode, &custom_mode);
451  msg->custom_mode = custom_mode.custom_mode_hl;
452  }
453 
454  return updated;
455 }
456 
458 {
459  struct vehicle_status_flags_s status_flags;
460 
461  const bool updated = _status_flags_sub->update(&_status_flags_time, &status_flags);
462 
463  if (_status_flags_time > 0) {
464  if (!status_flags.condition_global_position_valid) { //TODO check if there is a better way to get only GPS failure
465  msg->failure_flags |= HL_FAILURE_FLAG_GPS;
466  }
467 
468  if (status_flags.offboard_control_signal_lost && status_flags.offboard_control_signal_found_once) {
469  msg->failure_flags |= HL_FAILURE_FLAG_OFFBOARD_LINK;
470  }
471  }
472 
473  return updated;
474 }
475 
477 {
478  struct wind_estimate_s wind;
479 
480  const bool updated = _wind_sub->update(&_wind_time, &wind);
481 
482  if (_wind_time > 0) {
483  msg->wind_heading = static_cast<uint8_t>(
484  math::degrees(wrap_2pi(atan2f(wind.windspeed_east, wind.windspeed_north))) * 0.5f);
485  }
486 
487  return updated;
488 }
489 
491 {
492  const hrt_abstime t = hrt_absolute_time();
493 
494  if (t > _last_update_time) {
495  // first order low pass filter for the update rate
496  _update_rate_filtered = 0.97f * _update_rate_filtered + 0.03f / ((t - _last_update_time) * 1e-6f);
497  _last_update_time = t;
498  }
499 
500  update_airspeed();
501 
503 
505 
507 
508  update_gps();
509 
511 
513 }
514 
516 {
517  airspeed_s airspeed;
518 
519  if (_airspeed_sub->update(&airspeed)) {
522  }
523 }
524 
526 {
527  tecs_status_s tecs_status;
528 
529  if (_tecs_status_sub->update(&tecs_status)) {
531  }
532 }
533 
535 {
536  battery_status_s battery;
537 
538  for (int i = 0; i < ORB_MULTI_MAX_INSTANCES; i++) {
539  if (_batteries[i].subscription->update(&battery)) {
540  _batteries[i].connected = battery.connected;
542  }
543  }
544 }
545 
547 {
548  vehicle_global_position_s global_pos;
549 
550  if (_global_pos_sub->update(&global_pos)) {
551  _climb_rate.add_value(fabsf(global_pos.vel_d), _update_rate_filtered);
552  _groundspeed.add_value(sqrtf(global_pos.vel_n * global_pos.vel_n + global_pos.vel_e * global_pos.vel_e),
554  }
555 }
556 
558 {
560 
561  if (_gps_sub->update(&gps)) {
564  }
565 }
566 
568 {
570 
571  if (_status_sub->update(&status)) {
572  if (status.arming_state == vehicle_status_s::ARMING_STATE_ARMED) {
573  struct actuator_controls_s actuator = {};
574 
576  if (_actuator_sub_1->update(&actuator)) {
577  _throttle.add_value(actuator.control[actuator_controls_s::INDEX_THROTTLE], _update_rate_filtered);
578  }
579 
580  } else {
581  if (_actuator_sub_0->update(&actuator)) {
582  _throttle.add_value(actuator.control[actuator_controls_s::INDEX_THROTTLE], _update_rate_filtered);
583  }
584  }
585 
586  } else {
588  }
589  }
590 }
591 
593 {
594  wind_estimate_s wind;
595 
596  if (_wind_sub->update(&wind)) {
599  }
600 }
601 
602 void MavlinkStreamHighLatency2::set_default_values(mavlink_high_latency2_t &msg) const
603 {
604  msg.airspeed = 0;
605  msg.airspeed_sp = 0;
606  msg.altitude = 0;
607  msg.autopilot = MAV_AUTOPILOT_ENUM_END;
608  msg.battery = -1;
609  msg.climb_rate = 0;
610  msg.custom0 = INT8_MIN;
611  msg.custom1 = INT8_MIN;
612  msg.custom2 = INT8_MIN;
613  msg.eph = UINT8_MAX;
614  msg.epv = UINT8_MAX;
615  msg.failure_flags = 0;
616  msg.custom_mode = 0;
617  msg.groundspeed = 0;
618  msg.heading = 0;
619  msg.latitude = 0;
620  msg.longitude = 0;
621  msg.target_altitude = 0;
622  msg.target_distance = 0;
623  msg.target_heading = 0;
624  msg.temperature_air = INT8_MIN;
625  msg.throttle = 0;
626  msg.timestamp = 0;
627  msg.type = MAV_TYPE_ENUM_END;
628  msg.wind_heading = 0;
629  msg.windspeed = 0;
630  msg.wp_num = UINT16_MAX;
631 }
#define VEHICLE_TYPE_FIXED_WING
uint32_t onboard_control_sensors_enabled
static struct vehicle_status_s status
Definition: Commander.cpp:138
API for the uORB lightweight object broker.
Definition of geo / math functions to perform geodesic calculations.
SimpleAnalyzer.
float air_temperature_celsius
Definition: airspeed.h:56
uint16_t custom_mode_hl
float altitude_sp
Definition: tecs_status.h:61
constexpr T degrees(T radians)
Definition: Limits.hpp:91
Type wrap_2pi(Type x)
Wrap value in range [0, 2π)
void reset()
Reset the analyzer to the initial state.
static char msg[NUM_MSG][CONFIG_USART1_TXBUFSIZE]
Definition: px4io.c:89
float confidence
Definition: airspeed.h:57
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
Definition: uORB.h:87
float get_scaled(float scalingfactor) const
Get the scaled value of the current result of the analyzer.
uint16_t seq_current
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
float indicated_airspeed_m_s
Definition: airspeed.h:54
__BEGIN_DECLS typedef uint64_t hrt_abstime
Absolute time, in microsecond units.
Definition: drv_hrt.h:58
bool valid() const
Returns true if at least one value has been added to the analyzer.
uint32_t onboard_control_sensors_health
float airspeed_sp
Definition: tecs_status.h:65
PX4 custom flight modes.
#define ORB_MULTI_MAX_INSTANCES
Maximum number of multi topic instances.
Definition: uORB.h:62
static int _gps_sub
Definition: messages.cpp:61
uint16_t innovation_check_flags
#define MAX(a, b)
Definition: crsf.cpp:55
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
void add_value(float val, float update_rate)
Add a new value to the analyzer and update the result according to the mode.
static int _airspeed_sub
Definition: messages.cpp:64