Paparazzi UAS  v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
air_data.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2013 Gautier Hattenberger
3  * 2014 Felix Ruess <felix.ruess@gmail.com>
4  *
5  * This file is part of paparazzi
6  *
7  * paparazzi is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * paparazzi is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with paparazzi; see the file COPYING. If not, see
19  * <http://www.gnu.org/licenses/>.
20  */
21 
32 #include "modules/core/abi.h"
33 #include "math/pprz_isa.h"
34 #include "state.h"
35 #include "generated/airframe.h"
36 #include "generated/modules.h"
37 #include "pprzlink/dl_protocol.h"
38 
41 struct AirData air_data;
42 
45 #ifndef AIR_DATA_BARO_ABS_ID
46 #define AIR_DATA_BARO_ABS_ID ABI_BROADCAST
47 #endif
49 
52 #ifndef AIR_DATA_BARO_DIFF_ID
53 #define AIR_DATA_BARO_DIFF_ID ABI_BROADCAST
54 #endif
56 
59 #ifndef AIR_DATA_TEMPERATURE_ID
60 #define AIR_DATA_TEMPERATURE_ID ABI_BROADCAST
61 #endif
63 
66 #ifndef AIR_DATA_AIRSPEED_ID
67 #define AIR_DATA_AIRSPEED_ID ABI_BROADCAST
68 #endif
70 
73 #ifndef AIR_DATA_INCIDENCE_ID
74 #define AIR_DATA_INCIDENCE_ID ABI_BROADCAST
75 #endif
77 
79 #ifndef AIR_DATA_TAS_FACTOR
80 #define AIR_DATA_TAS_FACTOR 1.0
81 #endif
82 
84 #ifndef AIR_DATA_CALC_AIRSPEED
85 #define AIR_DATA_CALC_AIRSPEED TRUE
86 #endif
87 
89 #ifndef AIR_DATA_CALC_TAS_FACTOR
90 #define AIR_DATA_CALC_TAS_FACTOR TRUE
91 #endif
92 
94 #ifndef AIR_DATA_CALC_AMSL_BARO
95 #define AIR_DATA_CALC_AMSL_BARO FALSE
96 #endif
97 
98 
99 #ifndef USE_AIRSPEED_AIR_DATA
100 #if USE_AIRSPEED
101 #define USE_AIRSPEED_AIR_DATA TRUE
102 PRINT_CONFIG_MSG("USE_AIRSPEED_AIR_DATA automatically set to TRUE")
103 #endif
104 #endif
105 
106 /*
107  * Internal variable to keep track of validity.
108  */
109 
112 
113 
114 static void pressure_abs_cb(uint8_t __attribute__((unused)) sender_id, uint32_t __attribute__((unused)) stamp, float pressure)
115 {
117 
118  // calculate QNH from pressure and absolute altitude if that is available
121  // in the meantime use geoid separation at local reference frame origin
122  float geoid_separation = 0;
123  if (state.ned_initialized_f) {
124  geoid_separation = stateGetLlaOrigin_f().alt - stateGetHmslOrigin_f();
125  }
126  float h = stateGetPositionLla_f()->alt - geoid_separation;
128  air_data.calc_qnh_once = false;
129  }
130 
131  if (air_data.calc_amsl_baro && air_data.qnh > 0) {
133  air_data.qnh * 100.f);
134  air_data.amsl_baro_valid = true;
135  }
136 
137  /* reset baro health counter */
138  baro_health_counter = 10;
139 }
140 
141 static void pressure_diff_cb(uint8_t __attribute__((unused)) sender_id, float pressure)
142 {
144  if (air_data.calc_airspeed) {
147 #if USE_AIRSPEED_AIR_DATA
148  stateSetAirspeed_f(MODULE_AIR_DATA_ID, air_data.airspeed);
149 #endif
150  }
151 }
152 
153 static void temperature_cb(uint8_t __attribute__((unused)) sender_id, float temp)
154 {
155  air_data.temperature = temp;
156  /* only calculate tas factor if enabled and we have airspeed and valid data */
158  air_data.pressure > 0) {
160  }
161 }
162 
163 static void airspeed_cb(uint8_t __attribute__((unused)) sender_id, float eas)
164 {
165  air_data.airspeed = eas;
166  if (air_data.calc_airspeed) {
168 #if USE_AIRSPEED_AIR_DATA
169  stateSetAirspeed_f(MODULE_AIR_DATA_ID, air_data.airspeed);
170 #endif
171  }
172 }
173 
174 static void incidence_cb(uint8_t __attribute__((unused)) sender_id, uint8_t flag, float aoa, float sideslip)
175 {
176  if (bit_is_set(flag, 0)) {
177  // update angle of attack
178  air_data.aoa = aoa;
179  stateSetAngleOfAttack_f(MODULE_AIR_DATA_ID, aoa);
180  }
181  if (bit_is_set(flag, 1)) {
182  // update sideslip angle
184  stateSetSideslip_f(MODULE_AIR_DATA_ID, sideslip);
185  }
186 }
187 
188 #if PERIODIC_TELEMETRY
190 
191 static void send_baro_raw(struct transport_tx *trans, struct link_device *dev)
192 {
193  pprz_msg_send_BARO_RAW(trans, dev, AC_ID,
195 }
196 
197 static void send_air_data(struct transport_tx *trans, struct link_device *dev)
198 {
199  pprz_msg_send_AIR_DATA(trans, dev, AC_ID,
203  &air_data.tas);
204 }
205 
206 static void send_amsl(struct transport_tx *trans, struct link_device *dev)
207 {
208  const float MeterPerFeet = 0.3048;
209  float amsl_baro_ft = air_data.amsl_baro / MeterPerFeet;
210  float amsl_gps_ft = stateGetPositionLla_f()->alt / MeterPerFeet;
211  pprz_msg_send_AMSL(trans, dev, AC_ID, &amsl_baro_ft, &amsl_gps_ft);
212 }
213 #endif
214 
218 void air_data_init(void)
219 {
224  air_data.calc_qnh_once = true;
225  air_data.amsl_baro_valid = false;
226 
227  /* initialize the output variables
228  * pressure, qnh, temperature and airspeed to invalid values,
229  * rest to zero
230  */
231  air_data.pressure = -1.0f;
232  air_data.qnh = -1.0f;
233  air_data.airspeed = -1.0f;
234  air_data.tas = -1.0f;
235  air_data.temperature = -1000.0f;
236  air_data.differential = 0.0f;
237  air_data.amsl_baro = 0.0f;
238  air_data.aoa = 0.0f;
239  air_data.sideslip = 0.0f;
240  air_data.wind_speed = 0.0f;
241  air_data.wind_dir = 0.0f;
242 
243  /* internal variables */
245 
248  AbiBindMsgTEMPERATURE(AIR_DATA_TEMPERATURE_ID, &temperature_ev, temperature_cb);
249  AbiBindMsgAIRSPEED(AIR_DATA_AIRSPEED_ID, &airspeed_ev, airspeed_cb);
250  AbiBindMsgINCIDENCE(AIR_DATA_INCIDENCE_ID, &incidence_ev, incidence_cb);
251 
252 #if PERIODIC_TELEMETRY
256 #endif
257 }
258 
259 float air_data_get_amsl(void)
260 {
261  // If it has be calculated and baro is OK
263  return air_data.amsl_baro;
264  }
265  // Otherwise use real altitude (from GPS)
266  return stateGetPositionLla_f()->alt;
267 }
268 
270 {
271  // Watchdog on baro
272  if (baro_health_counter > 0) {
274  } else {
275  air_data.amsl_baro_valid = false;
276  }
277 }
278 
279 void air_data_parse_WIND_INFO(struct link_device *dev __attribute__((unused)), struct transport_tx *trans __attribute__((unused)), uint8_t *buf)
280 {
281  if (DL_WIND_INFO_ac_id(buf) != AC_ID) { return; }
282  uint8_t flags = DL_WIND_INFO_flags(buf);
283  struct FloatVect2 wind = { 0.f, 0.f };
284  float upwind = 0.f;
285  if (bit_is_set(flags, 0)) {
286  wind.x = DL_WIND_INFO_north(buf);
287  wind.y = DL_WIND_INFO_east(buf);
288  stateSetHorizontalWindspeed_f(MODULE_AIR_DATA_ID, &wind);
290  air_data.wind_dir = atan2f(wind.y, wind.x);
291  }
292  if (bit_is_set(flags, 1)) {
293  upwind = DL_WIND_INFO_up(buf);
294  stateSetVerticalWindspeed_f(MODULE_AIR_DATA_ID, upwind);
295  }
296 #if !USE_AIRSPEED
297  if (bit_is_set(flags, 2)) {
298  air_data.tas = DL_WIND_INFO_airspeed(buf);
300  stateSetAirspeed_f(MODULE_AIR_DATA_ID, air_data.airspeed);
301  }
302 #endif
303 #ifdef WIND_INFO_RET
304  float airspeed = stateGetAirspeed_f();
305  pprz_msg_send_WIND_INFO_RET(trans, dev, AC_ID, &flags, &wind.y, &wind.x, &upwind, &airspeed);
306 #endif
307 }
308 
323 {
324  /* q (dynamic pressure) = total pressure - static pressure
325  * q = 1/2*rho*speed^2
326  * speed = sqrt(2*q/rho)
327  * With rho = air density at sea level.
328  * Lower bound of q at zero, no flying backwards guys...
329  */
330  const float two_div_rho_0 = 2.0 / PPRZ_ISA_AIR_DENSITY;
331  float sign = 1.0f;
332  if (q < 0) {
333  sign = -1.0f;
334  q = -q;
335  }
336  return sqrtf(q * two_div_rho_0) * sign;
337 }
338 
355 float get_tas_factor(float p, float t)
356 {
357  /* factor to convert EAS to TAS:
358  * sqrt(rho0 / rho) = sqrt((p0 * T) / (p * T0))
359  * convert input temp to Kelvin
360  */
361  return sqrtf((PPRZ_ISA_SEA_LEVEL_PRESSURE * KelvinOfCelsius(t)) /
363 }
364 
368 static void compute_tas_factor(void)
369 {
370  // update tas factor if requested
372  if (air_data.pressure > 0.f && air_data.temperature > -900.f) {
373  // compute air density from pressure and temperature
375  }
376  else {
377  // compute air density from altitude in ISA condition
378  const float z = air_data_get_amsl();
379  const float p = pprz_isa_pressure_of_altitude(z);
380  const float t = pprz_isa_temperature_of_altitude(z);
382  }
383  }
384 }
385 
395 float tas_from_eas(float eas)
396 {
398  return air_data.tas_factor * eas;
399 }
400 
410 float eas_from_tas(float tas)
411 {
413  return tas / air_data.tas_factor;
414 }
415 
425 {
427 }
static void h(const real32_T x[7], const real32_T q[4], real32_T y[6])
Main include for ABI (AirBorneInterface).
Event structure to store callbacks in a linked list.
Definition: abi_common.h:67
float eas_from_dynamic_pressure(float q)
Calculate equivalent airspeed from dynamic pressure.
Definition: air_data.c:322
void air_data_periodic(void)
Check health.
Definition: air_data.c:269
static abi_event airspeed_ev
Definition: air_data.c:69
static abi_event temperature_ev
Definition: air_data.c:62
static uint8_t baro_health_counter
counter to check baro health
Definition: air_data.c:111
static void compute_tas_factor(void)
Internal utility function to compute current tas factor if needed.
Definition: air_data.c:368
#define AIR_DATA_AIRSPEED_ID
ABI binding for airspeed.
Definition: air_data.c:67
struct AirData air_data
global AirData state
Definition: air_data.c:41
float air_data_get_amsl(void)
Return AMSL (altitude AboveSeaLevel).
Definition: air_data.c:259
#define AIR_DATA_TAS_FACTOR
Default factor to convert estimated airspeed (EAS) to true airspeed (TAS)
Definition: air_data.c:80
#define AIR_DATA_CALC_TAS_FACTOR
Calculate tas_factor from temp and pressure by default.
Definition: air_data.c:90
static void pressure_diff_cb(uint8_t sender_id, float pressure)
Definition: air_data.c:141
#define AIR_DATA_CALC_AMSL_BARO
Don't calculate AMSL from baro and QNH by default.
Definition: air_data.c:95
static void send_air_data(struct transport_tx *trans, struct link_device *dev)
Definition: air_data.c:197
static abi_event pressure_diff_ev
Definition: air_data.c:55
#define AIR_DATA_CALC_AIRSPEED
Calculate Airspeed from differential pressure by default.
Definition: air_data.c:85
float eas_from_tas(float tas)
Calculate equivalent airspeed from true airspeed.
Definition: air_data.c:410
static void temperature_cb(uint8_t sender_id, float temp)
Definition: air_data.c:153
#define AIR_DATA_TEMPERATURE_ID
ABI binding for temperature.
Definition: air_data.c:60
float tas_from_dynamic_pressure(float q)
Calculate true airspeed from dynamic pressure.
Definition: air_data.c:424
static void incidence_cb(uint8_t sender_id, uint8_t flag, float aoa, float sideslip)
Definition: air_data.c:174
#define AIR_DATA_BARO_ABS_ID
ABI binding for absolute pressure.
Definition: air_data.c:46
#define AIR_DATA_BARO_DIFF_ID
ABI binding for differential pressure.
Definition: air_data.c:53
static abi_event incidence_ev
Definition: air_data.c:76
static void send_amsl(struct transport_tx *trans, struct link_device *dev)
Definition: air_data.c:206
void air_data_parse_WIND_INFO(struct link_device *dev, struct transport_tx *trans, uint8_t *buf)
Parse datalink wind info message.
Definition: air_data.c:279
static abi_event pressure_abs_ev
Definition: air_data.c:48
static void pressure_abs_cb(uint8_t sender_id, uint32_t stamp, float pressure)
Definition: air_data.c:114
#define AIR_DATA_INCIDENCE_ID
ABI binding for incidence angles.
Definition: air_data.c:74
static void send_baro_raw(struct transport_tx *trans, struct link_device *dev)
Definition: air_data.c:191
void air_data_init(void)
AirData initialization.
Definition: air_data.c:218
float get_tas_factor(float p, float t)
Calculate true airspeed (TAS) factor.
Definition: air_data.c:355
float tas_from_eas(float eas)
Calculate true airspeed from equivalent airspeed.
Definition: air_data.c:395
static void airspeed_cb(uint8_t sender_id, float eas)
Definition: air_data.c:163
Air Data interface.
bool calc_amsl_baro
if TRUE, calculate amsl_baro
Definition: air_data.h:52
float sideslip
sideslip angle (rad)
Definition: air_data.h:56
float wind_dir
wind direction (rad, 0 north, >0 clockwise)
Definition: air_data.h:58
bool calc_tas_factor
if TRUE, calculate tas_factor when getting a temp measurement
Definition: air_data.h:53
float tas_factor
factor to convert equivalent airspeed (EAS) to true airspeed (TAS)
Definition: air_data.h:46
float temperature
temperature in degrees Celcius, -1000 if unknown
Definition: air_data.h:42
float aoa
angle of attack (rad)
Definition: air_data.h:55
float wind_speed
wind speed (m/s)
Definition: air_data.h:57
bool calc_airspeed
if TRUE, calculate airspeed from differential pressure
Definition: air_data.h:50
bool calc_qnh_once
flag to calculate QNH with next pressure measurement
Definition: air_data.h:51
float airspeed
Equivalent Air Speed (equals to Calibrated Air Speed at low speed/altitude) (in m/s,...
Definition: air_data.h:44
float differential
Differential pressure (total - static pressure) (Pa)
Definition: air_data.h:41
float pressure
Static atmospheric pressure (Pa), -1 if unknown.
Definition: air_data.h:40
float amsl_baro
altitude above sea level in m from pressure and QNH
Definition: air_data.h:48
float tas
True Air Speed (TAS) in m/s, -1 if unknown.
Definition: air_data.h:45
bool amsl_baro_valid
TRUE if amsl_baro is currently valid.
Definition: air_data.h:49
float qnh
Barometric pressure adjusted to sea level in hPa, -1 if unknown.
Definition: air_data.h:47
Air Data strucute.
Definition: air_data.h:39
static float float_vect2_norm(struct FloatVect2 *v)
#define KelvinOfCelsius(_t)
Convert temperature from Celsius to Kelvin.
Definition: pprz_isa.h:73
#define PPRZ_ISA_SEA_LEVEL_TEMP
ISA sea level standard temperature in Kelvin.
Definition: pprz_isa.h:52
static float pprz_isa_pressure_of_altitude(float altitude)
Get pressure in Pa from absolute altitude (using simplified equation).
Definition: pprz_isa.h:117
#define PPRZ_ISA_AIR_DENSITY
standard air density in kg/m^3
Definition: pprz_isa.h:64
static float pprz_isa_temperature_of_altitude(float alt)
Get ISA temperature from a MSL altitude.
Definition: pprz_isa.h:181
#define CelsiusOfKelvin(_t)
Convert temperature from Kelvin to Celsius.
Definition: pprz_isa.h:71
#define PPRZ_ISA_SEA_LEVEL_PRESSURE
ISA sea level standard atmospheric pressure in Pascal.
Definition: pprz_isa.h:50
static float pprz_isa_height_of_pressure_full(float pressure, float ref_p)
Get relative altitude from pressure (using full equation).
Definition: pprz_isa.h:146
static float pprz_isa_ref_pressure_of_height_full(float pressure, float height)
Get reference pressure (QFE or QNH) from current pressure and height.
Definition: pprz_isa.h:166
struct State state
Definition: state.c:36
bool ned_initialized_f
True if local float coordinate frame is initialsed.
Definition: state.h:251
static bool stateIsGlobalCoordinateValid(void)
Test if global coordinates are valid.
Definition: state.h:620
float stateGetHmslOrigin_f(void)
Get the HMSL of the frame origin (float)
Definition: state.c:204
static struct LlaCoor_f * stateGetPositionLla_f(void)
Get position in LLA coordinates (float).
Definition: state.h:857
struct LlaCoor_f stateGetLlaOrigin_f(void)
Get the LLA position of the frame origin (float)
Definition: state.c:143
static void stateSetAngleOfAttack_f(uint16_t id, float aoa)
Set angle of attack in radians (float).
Definition: state.h:1497
static void stateSetSideslip_f(uint16_t id, float sideslip)
Set sideslip angle in radians (float).
Definition: state.h:1508
static void stateSetVerticalWindspeed_f(uint16_t id, float v_windspeed)
Set vertical windspeed (float).
Definition: state.h:1475
static float stateGetAirspeed_f(void)
Get airspeed (float).
Definition: state.h:1590
static void stateSetHorizontalWindspeed_f(uint16_t id, struct FloatVect2 *h_windspeed)
Set horizontal windspeed (float).
Definition: state.h:1464
static void stateSetAirspeed_f(uint16_t id, float airspeed)
Set airspeed (float).
Definition: state.h:1486
static float p[2][2]
PRINT_CONFIG_MSG("USE_INS_NAV_INIT defaulting to TRUE")
static float sign(float x)
sign function
Definition: nav_fish.c:232
float alt
in meters (normally above WGS84 reference ellipsoid)
Paparazzi atmospheric pressure conversion utilities.
API to get/set the generic vehicle states.
static const struct usb_device_descriptor dev
Definition: usb_ser_hw.c:74
int8_t register_periodic_telemetry(struct periodic_telemetry *_pt, uint8_t _id, telemetry_cb _cb)
Register a telemetry callback function.
Definition: telemetry.c:51
Periodic telemetry system header (includes downlink utility and generated code).
#define DefaultPeriodic
Set default periodic telemetry.
Definition: telemetry.h:66
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
Definition: vl53l1_types.h:78
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98