diff --git a/conf/airframes/examples/Twinstar_energyadaptive.xml b/conf/airframes/examples/Twinstar_energyadaptive.xml index 94da6f2457..ceff19d287 100644 --- a/conf/airframes/examples/Twinstar_energyadaptive.xml +++ b/conf/airframes/examples/Twinstar_energyadaptive.xml @@ -58,6 +58,7 @@ twog_1.0 + aspirin + ETS baro + ETS speed + diff --git a/conf/airframes/examples/easystar_ets.xml b/conf/airframes/examples/easystar_ets.xml index 43d1ba1f37..2012c95c80 100644 --- a/conf/airframes/examples/easystar_ets.xml +++ b/conf/airframes/examples/easystar_ets.xml @@ -36,6 +36,7 @@ + diff --git a/conf/airframes/examples/microjet_lisa_m.xml b/conf/airframes/examples/microjet_lisa_m.xml index 491b8367c9..35ce7744c3 100644 --- a/conf/airframes/examples/microjet_lisa_m.xml +++ b/conf/airframes/examples/microjet_lisa_m.xml @@ -47,6 +47,7 @@ + diff --git a/conf/airframes/examples/quadrotor_lisa_mx.xml b/conf/airframes/examples/quadrotor_lisa_mx.xml index 886e4956a0..a65f31df4e 100644 --- a/conf/airframes/examples/quadrotor_lisa_mx.xml +++ b/conf/airframes/examples/quadrotor_lisa_mx.xml @@ -63,6 +63,7 @@ + diff --git a/conf/airframes/examples/separate_fbw_ap.xml b/conf/airframes/examples/separate_fbw_ap.xml index 67fcf963b6..c495509d99 100644 --- a/conf/airframes/examples/separate_fbw_ap.xml +++ b/conf/airframes/examples/separate_fbw_ap.xml @@ -223,7 +223,7 @@ - + diff --git a/conf/firmwares/rotorcraft.makefile b/conf/firmwares/rotorcraft.makefile index 668df46d82..8de4dd47ca 100644 --- a/conf/firmwares/rotorcraft.makefile +++ b/conf/firmwares/rotorcraft.makefile @@ -73,10 +73,8 @@ $(TARGET).srcs += subsystems/commands.c $(TARGET).srcs += state.c # -# AIR DATA and BARO (if needed) +# BARO_BOARD (if existing/configured) # -$(TARGET).srcs += subsystems/air_data.c - include $(CFG_SHARED)/baro_board.makefile diff --git a/conf/firmwares/subsystems/fixedwing/autopilot.makefile b/conf/firmwares/subsystems/fixedwing/autopilot.makefile index c915ba7d93..5af5506c4e 100644 --- a/conf/firmwares/subsystems/fixedwing/autopilot.makefile +++ b/conf/firmwares/subsystems/fixedwing/autopilot.makefile @@ -161,8 +161,6 @@ ap_srcs += state.c ap_srcs += subsystems/settings.c ap_srcs += $(SRC_ARCH)/subsystems/settings_arch.c -# AIR DATA -ap_srcs += subsystems/air_data.c # BARO include $(CFG_SHARED)/baro_board.makefile diff --git a/conf/messages.xml b/conf/messages.xml index e9eeb060c8..64656d8d92 100644 --- a/conf/messages.xml +++ b/conf/messages.xml @@ -1944,8 +1944,21 @@ - - + + + + + + + + + + + + + + + diff --git a/conf/modules/air_data.xml b/conf/modules/air_data.xml new file mode 100644 index 0000000000..0059dab034 --- /dev/null +++ b/conf/modules/air_data.xml @@ -0,0 +1,41 @@ + + + + + + AirData interface. + Provides an interface for baro absolute and differential pressure as well as airspeed. + Subscribes to BARO_ABS, BARO_DIFF and TEMPERATURE ABI messages and calculates QNH and true airspeed from it. + Also enables you to fly on "flight levels" using AMSL (AltitudeAboveSeaLevel) calculated from current pressure and QNH. + + When using this module to provide airspeed you need a differential pressure sensor module publishing the BARO_DIFF ABI message. Make sure to disable other modules which otherwise directly set the airspeed in the state interface. E.g. when using the airspeed_ms45xx.xml module, define USE_AIRSPEED_MS45XX to FALSE. + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + +
diff --git a/sw/airborne/firmwares/fixedwing/main_ap.c b/sw/airborne/firmwares/fixedwing/main_ap.c index 10f872717b..8adbcd02dd 100644 --- a/sw/airborne/firmwares/fixedwing/main_ap.c +++ b/sw/airborne/firmwares/fixedwing/main_ap.c @@ -53,7 +53,6 @@ #if USE_AHRS_ALIGNER #include "subsystems/ahrs/ahrs_aligner.h" #endif -#include "subsystems/air_data.h" #if USE_BARO_BOARD #include "subsystems/sensors/baro.h" PRINT_CONFIG_MSG_VALUE("USE_BARO_BOARD is TRUE, reading onboard baro: ", BARO_BOARD) @@ -205,7 +204,6 @@ void init_ap( void ) { register_periodic_telemetry(DefaultPeriodic, "STATE_FILTER_STATUS", send_filter_status); #endif - air_data_init(); #if USE_BARO_BOARD baro_init(); #endif diff --git a/sw/airborne/firmwares/rotorcraft/main.c b/sw/airborne/firmwares/rotorcraft/main.c index 133b0fe8c4..59d6f37c61 100644 --- a/sw/airborne/firmwares/rotorcraft/main.c +++ b/sw/airborne/firmwares/rotorcraft/main.c @@ -52,7 +52,6 @@ #include "subsystems/imu.h" #include "subsystems/gps.h" -#include "subsystems/air_data.h" #if USE_BARO_BOARD #include "subsystems/sensors/baro.h" @@ -152,7 +151,6 @@ STATIC_INLINE void main_init( void ) { radio_control_init(); - air_data_init(); #if USE_BARO_BOARD baro_init(); #endif diff --git a/sw/airborne/math/pprz_isa.h b/sw/airborne/math/pprz_isa.h index f5a39069ee..03ede60c4f 100644 --- a/sw/airborne/math/pprz_isa.h +++ b/sw/airborne/math/pprz_isa.h @@ -42,20 +42,31 @@ extern "C" { #include // Standard Atmosphere constants +/** ISA sea level standard atmospheric pressure in Pascal */ #define PPRZ_ISA_SEA_LEVEL_PRESSURE 101325.0 +/** ISA sea level standard temperature in Kelvin */ #define PPRZ_ISA_SEA_LEVEL_TEMP 288.15 +/** temperature laps rate in K/m */ #define PPRZ_ISA_TEMP_LAPS_RATE 0.0065 +/** earth-surface gravitational acceleration in m/s^2 */ #define PPRZ_ISA_GRAVITY 9.80665 -#define PPRZ_ISA_AIR_GAS_CONSTANT (8.31447/0.0289644) +/** universal gas constant in J/(mol*K) */ +#define PPRZ_ISA_GAS_CONSTANT 8.31447 +/** molar mass of dry air in kg/mol */ +#define PPRZ_ISA_MOLAR_MASS 0.0289644 +/** universal gas constant / molar mass of dry air in J*kg/K */ +#define PPRZ_ISA_AIR_GAS_CONSTANT (PPRZ_ISA_GAS_CONSTANT/PPRZ_ISA_MOLAR_MASS) +/** standard air density in kg/m^3 */ +#define PPRZ_ISA_AIR_DENSITY 1.225 -static const float PPRZ_ISA_M_OF_P_CONST = (PPRZ_ISA_AIR_GAS_CONSTANT* PPRZ_ISA_SEA_LEVEL_TEMP / PPRZ_ISA_GRAVITY); +static const float PPRZ_ISA_M_OF_P_CONST = (PPRZ_ISA_AIR_GAS_CONSTANT * PPRZ_ISA_SEA_LEVEL_TEMP / PPRZ_ISA_GRAVITY); /** * Get absolute altitude from pressure (using simplified equation). * Referrence pressure is standard pressure at sea level * * @param pressure current pressure in Pascal (Pa) - * @return altitude in pressure in ISA conditions + * @return altitude in m in ISA conditions */ static inline float pprz_isa_altitude_of_pressure(float pressure) { @@ -68,15 +79,19 @@ static inline float pprz_isa_altitude_of_pressure(float pressure) /** * Get relative altitude from pressure (using simplified equation). + * Given the current pressure and a reference pressure (at height=0), + * calculate the height above the reference in meters. + * If you pass QNH as reference pressure, you get the height above sea level. + * Using QFE as reference pressure, you get height above the airfield. * * @param pressure current pressure in Pascal (Pa) - * @param ref reference pressure (QFE) when height = 0 - * @return altitude in pressure in ISA conditions + * @param ref_p reference pressure (QFE) when height=0 or QNH at sea level + * @return height in m above reference in ISA conditions */ -static inline float pprz_isa_height_of_pressure(float pressure, float ref) +static inline float pprz_isa_height_of_pressure(float pressure, float ref_p) { - if (pressure > 0. && ref > 0.) { - return (PPRZ_ISA_M_OF_P_CONST * logf(ref / pressure)); + if (pressure > 0. && ref_p > 0.) { + return (PPRZ_ISA_M_OF_P_CONST * logf(ref_p / pressure)); } else { return 0.; } @@ -86,7 +101,7 @@ static inline float pprz_isa_height_of_pressure(float pressure, float ref) * Get pressure in Pa from absolute altitude (using simplified equation). * * @param altitude current absolute altitude in meters - * @return static pressure in Pa in ISA conditions + * @return static pressure in Pa at given altitude in ISA conditions */ static inline float pprz_isa_pressure_of_altitude(float altitude) { @@ -96,13 +111,54 @@ static inline float pprz_isa_pressure_of_altitude(float altitude) /** * Get pressure in Pa from height (using simplified equation). * - * @param altitude current relative altitude in meters - * @param ref reference pressure (QFE) when height = 0 - * @return static pressure in Pa in ISA conditions + * @param height current height over reference (relative altitude) in meters + * @param ref_p reference pressure (QFE or QNH) when height = 0 + * @return static pressure in Pa at given height in ISA conditions */ -static inline float pprz_isa_pressure_of_height(float altitude, float ref) +static inline float pprz_isa_pressure_of_height(float height, float ref_p) { - return (ref * expf((-1. / PPRZ_ISA_M_OF_P_CONST) * altitude)); + return (ref_p * expf((-1. / PPRZ_ISA_M_OF_P_CONST) * height)); +} + + +/** + * Get relative altitude from pressure (using full equation). + * Given the current pressure and a reference pressure (at height=0), + * calculate the height above the reference in meters. + * If you pass QNH as reference pressure, you get the height above sea level. + * Using QFE as reference pressure, you get height above the airfield. + * + * @param pressure current pressure in Pascal (Pa) + * @param ref_p reference pressure (QFE or QNH) in Pa + * @return height above reference in m in ISA conditions + */ +static inline float pprz_isa_height_of_pressure_full(float pressure, float ref_p) +{ + if (ref_p > 0.) { + const float prel = pressure / ref_p; + const float inv_expo = PPRZ_ISA_GAS_CONSTANT * PPRZ_ISA_TEMP_LAPS_RATE / + PPRZ_ISA_GRAVITY / PPRZ_ISA_MOLAR_MASS; + return (1 - powf(prel, inv_expo)) * PPRZ_ISA_SEA_LEVEL_TEMP / PPRZ_ISA_TEMP_LAPS_RATE; + } else { + return 0.; + } +} + +/** + * Get reference pressure (QFE or QNH) from current pressure and height. + * (using full equation) + * + * @param pressure current pressure in Pascal (Pa) + * @param height height above referece (sea level for QNH, airfield alt for QFE) in m + * @return reference pressure at height=0 in Pa + */ +static inline float pprz_isa_ref_pressure_of_height_full(float pressure, float height) +{ + // Trel = 1 - L*h/T0; + const float Trel = 1.0 - PPRZ_ISA_TEMP_LAPS_RATE * height / PPRZ_ISA_SEA_LEVEL_TEMP; + const float expo = PPRZ_ISA_GRAVITY * PPRZ_ISA_MOLAR_MASS / PPRZ_ISA_GAS_CONSTANT / + PPRZ_ISA_TEMP_LAPS_RATE; + return pressure / pow(Trel, expo); } #ifdef __cplusplus diff --git a/sw/airborne/modules/air_data/air_data.c b/sw/airborne/modules/air_data/air_data.c new file mode 100644 index 0000000000..e387ab9239 --- /dev/null +++ b/sw/airborne/modules/air_data/air_data.c @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2013 Gautier Hattenberger + * 2014 Felix Ruess + * + * This file is part of paparazzi + * + * paparazzi is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * paparazzi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with paparazzi; see the file COPYING. If not, see + * . + */ + +/** + * @file modules/air_data/air_data.c + * Air Data interface + * - pressures + * - airspeed + * - angle of attack and sideslip + * - wind + */ + +#include "modules/air_data/air_data.h" +#include "subsystems/abi.h" +#include "math/pprz_isa.h" +#include "state.h" + + +/** global AirData state + */ +struct AirData air_data; + +/** ABI binding for absolute pressure + */ +#ifndef AIR_DATA_BARO_ABS_ID +#define AIR_DATA_BARO_ABS_ID ABI_BROADCAST +#endif +static abi_event pressure_abs_ev; + +/** ABI binding for differential pressure + */ +#ifndef AIR_DATA_BARO_DIFF_ID +#define AIR_DATA_BARO_DIFF_ID ABI_BROADCAST +#endif +static abi_event pressure_diff_ev; + +/** ABI binding for temperature + */ +#ifndef AIR_DATA_TEMPERATURE_ID +#define AIR_DATA_TEMPERATURE_ID ABI_BROADCAST +#endif +static abi_event temperature_ev; + +/** Default factor to convert estimated airspeed (EAS) to true airspeed (TAS) */ +#ifndef AIR_DATA_TAS_FACTOR +#define AIR_DATA_TAS_FACTOR 1.0 +#endif + +/** Calculate Airspeed from differential pressure by default */ +#ifndef AIR_DATA_CALC_AIRSPEED +#define AIR_DATA_CALC_AIRSPEED TRUE +#endif + +/** Calculate tas_factor from temp and pressure by default */ +#ifndef AIR_DATA_CALC_TAS_FACTOR +#define AIR_DATA_CALC_TAS_FACTOR TRUE +#endif + +/** Don't calculate AMSL from baro and QNH by default */ +#ifndef AIR_DATA_CALC_AMSL_BARO +#define AIR_DATA_CALC_AMSL_BARO FALSE +#endif + + +#ifndef USE_AIRSPEED_AIR_DATA +#if USE_AIRSPEED +#define USE_AIRSPEED_AIR_DATA TRUE +PRINT_CONFIG_MSG("USE_AIRSPEED_AIR_DATA automatically set to TRUE") +#endif +#endif + +/* + * Internal variable to keep track of validity. + */ + +/** counter to check baro health */ +static uint8_t baro_health_counter; + + +static void pressure_abs_cb(uint8_t __attribute__((unused)) sender_id, const float *pressure) +{ + air_data.pressure = *pressure; + + // calculate QNH from pressure and absolute alitude if that is available + if (air_data.calc_qnh_once && stateIsGlobalCoordinateValid()) { + float h = stateGetPositionLla_f()->alt; + air_data.qnh = pprz_isa_ref_pressure_of_height_full(air_data.pressure, h) / 100.f; + air_data.calc_qnh_once = FALSE; + } + + if (air_data.calc_amsl_baro && air_data.qnh > 0) { + air_data.amsl_baro = pprz_isa_height_of_pressure_full(air_data.pressure, + air_data.qnh * 100.f); + air_data.amsl_baro_valid = TRUE; + } + + /* reset baro health counter */ + baro_health_counter = 10; +} + +static void pressure_diff_cb(uint8_t __attribute__((unused)) sender_id, const float *pressure) +{ + air_data.differential = *pressure; + if (air_data.calc_airspeed) { + air_data.airspeed = tas_from_dynamic_pressure(air_data.differential); +#if USE_AIRSPEED_AIR_DATA + stateSetAirspeed_f(&air_data.airspeed); +#endif + } +} + +static void temperature_cb(uint8_t __attribute__((unused)) sender_id, const float *temp) +{ + air_data.temperature = *temp; + if (air_data.calc_tas_factor && baro_health_counter > 0 && air_data.pressure > 0) { + air_data.tas_factor = get_tas_factor(air_data.pressure, air_data.temperature); + } +} + +#if PERIODIC_TELEMETRY +#include "subsystems/datalink/telemetry.h" + +static void send_baro_raw(void) +{ + DOWNLINK_SEND_BARO_RAW(DefaultChannel, DefaultDevice, + &air_data.pressure, &air_data.differential); +} + +static void send_air_data(void) +{ + DOWNLINK_SEND_AIR_DATA(DefaultChannel, DefaultDevice, + &air_data.pressure, &air_data.differential, + &air_data.temperature, &air_data.qnh, + &air_data.amsl_baro, &air_data.airspeed, + &air_data.tas_factor); +} + +static void send_amsl(void) +{ + const float MeterPerFeet = 0.3048; + float amsl_baro_ft = air_data.amsl_baro / MeterPerFeet; + float amsl_gps_ft = stateGetPositionLla_f()->alt / MeterPerFeet; + DOWNLINK_SEND_AMSL(DefaultChannel, DefaultDevice, &amsl_baro_ft, &amsl_gps_ft); +} +#endif + +/** AirData initialization. Called at startup. + * Bind ABI messages + */ +void air_data_init(void) +{ + air_data.calc_airspeed = AIR_DATA_CALC_AIRSPEED; + air_data.calc_tas_factor = AIR_DATA_CALC_TAS_FACTOR; + air_data.calc_amsl_baro = AIR_DATA_CALC_AMSL_BARO; + air_data.tas_factor = AIR_DATA_TAS_FACTOR; + air_data.calc_qnh_once = TRUE; + air_data.amsl_baro_valid = FALSE; + + /* initialize the output variables + * pressure, qnh, temperature and airspeed to invalid values, + * rest to zero + */ + air_data.pressure = -1.0f; + air_data.qnh = -1.0f; + air_data.airspeed = -1.0f; + air_data.temperature = -1000.0f; + air_data.differential = 0.0f; + air_data.amsl_baro = 0.0f; + air_data.aoa = 0.0f; + air_data.sideslip = 0.0f; + air_data.wind_speed = 0.0f; + air_data.wind_dir = 0.0f; + + /* internal variables */ + baro_health_counter = 0; + + AbiBindMsgBARO_ABS(AIR_DATA_BARO_ABS_ID, &pressure_abs_ev, pressure_abs_cb); + AbiBindMsgBARO_DIFF(AIR_DATA_BARO_DIFF_ID, &pressure_diff_ev, pressure_diff_cb); + AbiBindMsgTEMPERATURE(AIR_DATA_TEMPERATURE_ID, &temperature_ev, temperature_cb); + +#if PERIODIC_TELEMETRY + register_periodic_telemetry(DefaultPeriodic, "BARO_RAW", send_baro_raw); + register_periodic_telemetry(DefaultPeriodic, "AIR_DATA", send_air_data); + register_periodic_telemetry(DefaultPeriodic, "AMSL", send_amsl); +#endif +} + +float air_data_get_amsl(void) +{ + // If it has be calculated and baro is OK + if (air_data.amsl_baro_valid) { + return air_data.amsl_baro; + } + // Otherwise use real altitude (from GPS) + return stateGetPositionLla_f()->alt; +} + +void air_data_periodic(void) +{ + // Watchdog on baro + if (baro_health_counter > 0) { + baro_health_counter--; + } + else { + air_data.amsl_baro_valid = FALSE; + } +} + + +/** + * Calculate equivalent airspeed from dynamic pressure. + * Dynamic pressure @f$q@f$ (also called impact pressure) is the + * difference between total(pitot) and static pressure. + * + * Airspeed from dynamic pressure: + * @f[ v = \frac12 \sqrt{\frac{2q}{\rho}} @f] + * with @f$\rho@f$ as air density. + * Using standard sea level air density @f$\rho_0@f$ gives you equivalent airspeed (EAS). + * + * @param q dynamic pressure in Pa + * @return equivalent airspeed in m/s + */ +float eas_from_dynamic_pressure(float q) +{ + /* q (dynamic pressure) = total pressure - static pressure + * q = 1/2*rho*speed^2 + * speed = sqrt(2*q/rho) + * With rho = air density at sea level. + * Lower bound of q at zero, no flying backwards guys... + */ + const float two_div_rho_0 = 2.0 / PPRZ_ISA_AIR_DENSITY; + return sqrtf(Max(q * two_div_rho_0, 0)); +} + +/** + * Calculate true airspeed (TAS) factor. + * TAS = tas_factor * EAS + * + * True airspeed (TAS) from equivalent airspeed (EAS): + * @f[\mbox{TAS} = \mbox{EAS} \sqrt{\frac{\rho_0}{\rho}}@f] + * and @f$ \frac{\rho_0}{\rho} = \frac{p_0T}{pT_0}@f$ where + * - @f$p@f$ is the air pressure at the flight condition + * - @f$p_0@f$ is the air pressure at sea level = 101325 Pa + * - @f$T@f$ is the air temperature at the flight condition + * - @f$T_0@f$ is the air temperature at sea level = 288.15 K + * + * @param p current air pressure in Pa + * @param t current air temperature in degrees Celcius + * @return tas factor + */ +float get_tas_factor(float p, float t) +{ + /* factor to convert EAS to TAS: + * sqrt(rho0 / rho) = sqrt((p0 * T) / (p * T0)) + * convert input temp to Kelvin + */ + return sqrtf((PPRZ_ISA_SEA_LEVEL_PRESSURE * (t + 274.15)) / + (p * PPRZ_ISA_SEA_LEVEL_TEMP)); +} + +/** + * Calculate true airspeed from equivalent airspeed. + * + * True airspeed (TAS) from EAS: + * TAS = air_data.tas_factor * EAS + * + * @param eas equivalent airspeed (EAS) in m/s + * @return true airspeed in m/s + */ +float tas_from_eas(float eas) +{ + return air_data.tas_factor * eas; +} + +/** + * Calculate true airspeed from dynamic pressure. + * Dynamic pressure @f$q@f$ (also called impact pressure) is the + * difference between total(pitot) and static pressure. + * + * @param q dynamic pressure in Pa + * @return true airspeed in m/s + */ +float tas_from_dynamic_pressure(float q) +{ + return tas_from_eas(eas_from_dynamic_pressure(q)); +} diff --git a/sw/airborne/modules/air_data/air_data.h b/sw/airborne/modules/air_data/air_data.h new file mode 100644 index 0000000000..5d7bc90a70 --- /dev/null +++ b/sw/airborne/modules/air_data/air_data.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2013 Gautier Hattenberger + * 2014 Felix Ruess + * + * This file is part of paparazzi + * + * paparazzi is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * paparazzi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with paparazzi; see the file COPYING. If not, see + * . + */ + +/** + * @file modules/air_data/air_data.h + * Air Data interface + * - pressures + * - airspeed + * - angle of attack and sideslip + * - wind + */ + +#ifndef AIR_DATA_H +#define AIR_DATA_H + +#include "std.h" + +/** Air Data strucute */ +struct AirData { + float pressure; ///< Static atmospheric pressure (Pa), -1 if unknown + float differential; ///< Differential pressure (total - static pressure) (Pa) + float temperature; ///< temperature in degrees Celcius, -1000 if unknown + + float airspeed; ///< Conventional Air Speed in m/s, -1 if unknown + float tas_factor; ///< factor to convert equivalent airspeed (EAS) to true airspeed (TAS) + float qnh; ///< Barometric pressure adjusted to sea level in hPa, -1 if unknown + float amsl_baro; ///< altitude above sea level in m from pressure and QNH + bool_t amsl_baro_valid; ///< TRUE if #amsl_baro is currently valid + bool_t calc_airspeed; ///< if TRUE, calculate airspeed from differential pressure + bool_t calc_qnh_once; ///< flag to calculate QNH with next pressure measurement + bool_t calc_amsl_baro; ///< if TRUE, calculate #amsl_baro + bool_t calc_tas_factor; ///< if TRUE, calculate #tas_factor when getting a temp measurement + + float aoa; ///< angle of attack (rad) + float sideslip; ///< sideslip angle (rad) + float wind_speed; ///< wind speed (m/s) + float wind_dir; ///< wind direction (rad, 0 north, >0 clockwise) +}; + +/** global AirData state + */ +extern struct AirData air_data; + +/** AirData initialization. Called at startup. + */ +extern void air_data_init(void); + +/** Check health. Needs to be called periodically. + */ +extern void air_data_periodic(void); + +/** Return AMSL (altitude AboveSeaLevel). + * If AMSL from baro is valid, return that, otherwise from gps. + */ +extern float air_data_get_amsl(void); + +/** + * Calculate equivalent airspeed from dynamic pressure. + * Dynamic pressure @f$q@f$ (also called impact pressure) is the + * difference between total(pitot) and static pressure. + * + * @param q dynamic pressure in Pa + * @return equivalent airspeed in m/s + */ +extern float eas_from_dynamic_pressure(float q); + +/** + * Calculate true airspeed (TAS) factor. + * TAS = tas_factor * EAS + * + * @param p current air pressure in Pa + * @param t current air temperature in degrees Celcius + * @return tas factor + */ +extern float get_tas_factor(float p, float t); + +/** + * Calculate true airspeed from equivalent airspeed. + * + * @param eas equivalent airspeed (EAS) in m/s + * @return true airspeed in m/s + */ +extern float tas_from_eas(float eas); + +/** + * Calculate true airspeed from dynamic pressure. + * Dynamic pressure @f$q@f$ (also called impact pressure) is the + * difference between total(pitot) and static pressure. + * + * @param q dynamic pressure in Pa + * @return true airspeed in m/s + */ +extern float tas_from_dynamic_pressure(float q); + + +#endif diff --git a/sw/airborne/subsystems/air_data.c b/sw/airborne/subsystems/air_data.c deleted file mode 100644 index cba562d78e..0000000000 --- a/sw/airborne/subsystems/air_data.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2013 Gautier Hattenberger - * - * This file is part of paparazzi. - * - * paparazzi is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * paparazzi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with paparazzi; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/** - * @file subsystems/air_data.c - * Air Data interface - * - pressures - * - airspeed - * - angle of attack and sideslip - * - wind - */ - -#include "subsystems/air_data.h" -#include "subsystems/abi.h" - -/** global AirData state - */ -struct AirData air_data; - -/** ABI bindings - */ -#ifndef AIR_DATA_BARO_ABS_ID -#define AIR_DATA_BARO_ABS_ID ABI_BROADCAST -#endif -static abi_event pressure_abs_ev; - -static void pressure_abs_cb(uint8_t __attribute__((unused)) sender_id, const float * pressure) { - air_data.pressure = *pressure; -} - -#if PERIODIC_TELEMETRY -#include "subsystems/datalink/telemetry.h" - -static void send_baro_raw(void) { - DOWNLINK_SEND_BARO_RAW(DefaultChannel, DefaultDevice, - &air_data.pressure, &air_data.differential); -} -#endif - -/** AirData initialization. Called at startup. - * Bind ABI messages - */ -void air_data_init( void ) { - AbiBindMsgBARO_ABS(AIR_DATA_BARO_ABS_ID, &pressure_abs_ev, pressure_abs_cb); - -#if PERIODIC_TELEMETRY - register_periodic_telemetry(DefaultPeriodic, "BARO_RAW", send_baro_raw); -#endif -} - diff --git a/sw/airborne/subsystems/air_data.h b/sw/airborne/subsystems/air_data.h deleted file mode 100644 index b4963c4832..0000000000 --- a/sw/airborne/subsystems/air_data.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2013 Gautier Hattenberger - * - * This file is part of paparazzi. - * - * paparazzi is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * paparazzi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with paparazzi; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/** - * @file subsystems/air_data.h - * Air Data interface - * - pressures - * - airspeed - * - angle of attack and sideslip - * - wind - */ - -#ifndef AIR_DATA_H -#define AIR_DATA_H - -#include "std.h" - -/** Air Data strucute */ -struct AirData { - float pressure; ///< Static atmospheric pressure (Pa) - float differential; ///< Differential pressure (dynamic - static pressure) (Pa) - float airspeed; ///< Conventional Air Speed (m/s) - float aoa; ///< angle of attack (rad) - float sideslip; ///< sideslip angle (rad) - float wind_speed; ///< wind speed (m/s) - float wind_dir; ///< wind direction (rad, 0 north, >0 clockwise) -}; - -/** global AirData state - */ -extern struct AirData air_data; - -/** AirData initialization. Called at startup. - */ -extern void air_data_init( void ); - -#endif /* AIR_DATA_H */ -