#pragma once
#include "AP_Baro_config.h"
#include <AP_HAL/AP_HAL.h>
#include <AP_Param/AP_Param.h>
#include <AP_Math/AP_Math.h>
#include <Filter/DerivativeFilter.h>
#include <AP_MSP/msp.h>
#include <AP_ExternalAHRS/AP_ExternalAHRS.h>
#ifndef BARO_MAX_INSTANCES
#define BARO_MAX_INSTANCES 3
#endif
#define BARO_MAX_DRIVERS 3
#define BARO_TIMEOUT_MS 500
class AP_Baro_Backend;
class AP_Baro
{
friend class AP_Baro_Backend;
friend class AP_Baro_SITL;
friend class AP_Baro_DroneCAN;
public:
AP_Baro();
CLASS_NO_COPY(AP_Baro);
static AP_Baro *get_singleton(void) {
return _singleton;
}
typedef enum {
BARO_TYPE_AIR,
BARO_TYPE_WATER
} baro_type_t;
__INITFUNC__ void init(void);
void update(void);
bool healthy(void) const { return healthy(_primary); }
bool healthy(uint8_t instance) const;
bool all_healthy(void) const;
bool arming_checks(size_t buflen, char *buffer) const;
uint8_t get_primary(void) const { return _primary; }
float get_pressure(void) const { return get_pressure(_primary); }
float get_pressure(uint8_t instance) const { return sensors[instance].pressure; }
#if HAL_BARO_WIND_COMP_ENABLED
const Vector3f& get_dynamic_pressure(uint8_t instance) const { return sensors[instance].dynamic_pressure; }
#endif
#if (HAL_BARO_WIND_COMP_ENABLED || AP_BARO_THST_COMP_ENABLED)
float get_corrected_pressure(uint8_t instance) const { return sensors[instance].corrected_pressure; }
#endif
float get_temperature(void) const { return get_temperature(_primary); }
float get_temperature(uint8_t instance) const { return sensors[instance].temperature; }
float get_pressure_correction(void) const { return get_pressure_correction(_primary); }
float get_pressure_correction(uint8_t instance) const { return sensors[instance].p_correction; }
void calibrate(bool save=true);
void update_calibration(void);
float get_altitude(void) const { return get_altitude(_primary); }
float get_altitude(uint8_t instance) const { return sensors[instance].altitude; }
float get_altitude_AMSL(uint8_t instance) const { return get_altitude(instance) + _field_elevation_active; }
float get_altitude_AMSL(void) const { return get_altitude_AMSL(_primary); }
uint8_t external_bus() const { return _ext_bus; }
static float geometric_alt_to_geopotential(float alt);
static float geopotential_alt_to_geometric(float alt);
float get_temperature_from_altitude(float alt) const;
float get_altitude_from_pressure(float pressure) const;
static float get_EAS2TAS_for_alt_amsl(float alt_amsl);
#if AP_BARO_1976_STANDARD_ATMOSPHERE_ENABLED
static void get_pressure_temperature_for_alt_amsl(float alt_amsl, float &pressure, float &temperature_K);
#endif
static float get_temperatureC_for_alt_amsl(const float alt_amsl);
static float get_pressure_for_alt_amsl(const float alt_amsl);
static float get_air_density_for_alt_amsl(float alt_amsl);
float get_altitude_difference(float base_pressure, float pressure) const;
float get_sealevel_pressure(float pressure, float altitude) const;
float _get_EAS2TAS(void) const;
float _get_air_density_ratio(void);
float get_climb_rate(void);
float get_ground_temperature(void) const;
float get_ground_pressure(void) const { return get_ground_pressure(_primary); }
float get_ground_pressure(uint8_t i) const { return sensors[i].ground_pressure.get(); }
void set_external_temperature(float temperature);
uint32_t get_last_update(void) const { return get_last_update(_primary); }
uint32_t get_last_update(uint8_t instance) const { return sensors[instance].last_update_ms; }
static const struct AP_Param::GroupInfo var_info[];
float get_external_temperature(void) const { return get_external_temperature(_primary); };
float get_external_temperature(const uint8_t instance) const;
void set_primary_baro(uint8_t primary) { _primary_baro.set_and_save(primary); };
void set_type(uint8_t instance, baro_type_t type) { sensors[instance].type = type; };
baro_type_t get_type(uint8_t instance) { return sensors[instance].type; };
uint8_t register_sensor(void);
uint8_t num_instances(void) const { return _num_sensors; }
void set_baro_drift_altitude(float alt) { _alt_offset.set(alt); }
float get_baro_drift_offset(void) const { return _alt_offset_active; }
static void SimpleUnderWaterAtmosphere(float alt, float &rho, float &delta, float &theta);
void set_pressure_correction(uint8_t instance, float p_correction);
uint8_t get_filter_range() const { return _filter_range; }
void set_log_baro_bit(uint32_t bit) { _log_baro_bit = bit; }
bool should_log() const;
HAL_Semaphore &get_semaphore(void) {
return _rsem;
}
#if AP_BARO_MSP_ENABLED
void handle_msp(const MSP::msp_baro_data_message_t &pkt);
#endif
#if AP_BARO_EXTERNALAHRS_ENABLED
void handle_external(const AP_ExternalAHRS::baro_data_message_t &pkt);
#endif
enum Options : uint16_t {
TreatMS5611AsMS5607 = (1U << 0U),
};
bool option_enabled(const Options option) const
{
return (uint16_t(_options.get()) & uint16_t(option)) != 0;
}
private:
static AP_Baro *_singleton;
uint8_t _num_drivers;
AP_Baro_Backend *drivers[BARO_MAX_DRIVERS];
uint8_t _num_sensors;
uint8_t _primary;
uint32_t _log_baro_bit = -1;
bool init_done;
uint8_t msp_instance_mask;
enum {
PROBE_BMP085=(1<<0),
PROBE_BMP280=(1<<1),
PROBE_MS5611=(1<<2),
PROBE_MS5607=(1<<3),
PROBE_MS5637=(1<<4),
PROBE_FBM320=(1<<5),
PROBE_DPS280=(1<<6),
PROBE_LPS25H=(1<<7),
PROBE_KELLER=(1<<8),
PROBE_MS5837=(1<<9),
PROBE_BMP388=(1<<10),
PROBE_SPL06 =(1<<11),
PROBE_MSP =(1<<12),
PROBE_BMP581=(1<<13),
PROBE_AUAV =(1<<14),
};
#if HAL_BARO_WIND_COMP_ENABLED
class WindCoeff {
public:
static const struct AP_Param::GroupInfo var_info[];
AP_Int8 enable;
AP_Float xp;
AP_Float xn;
AP_Float yp;
AP_Float yn;
AP_Float zp;
AP_Float zn;
};
#endif
struct {
uint32_t last_update_ms;
uint32_t last_change_ms;
float pressure;
float temperature;
float altitude;
AP_Float ground_pressure;
float p_correction;
baro_type_t type;
bool healthy;
bool alt_ok;
bool calibrated;
AP_Int32 bus_id;
#if HAL_BARO_WIND_COMP_ENABLED
WindCoeff wind_coeff;
Vector3f dynamic_pressure;
#endif
#if AP_BARO_THST_COMP_ENABLED
AP_Float mot_scale;
#endif
#if (HAL_BARO_WIND_COMP_ENABLED || AP_BARO_THST_COMP_ENABLED)
float corrected_pressure;
#endif
} sensors[BARO_MAX_INSTANCES];
AP_Float _alt_offset;
float _alt_offset_active;
AP_Float _field_elevation;
float _field_elevation_active;
uint32_t _field_elevation_last_ms;
AP_Int8 _primary_baro;
AP_Int8 _ext_bus;
float _external_temperature;
uint32_t _last_external_temperature_ms;
DerivativeFilterFloat_Size7 _climb_rate_filter;
AP_Float _specific_gravity;
AP_Float _user_ground_temperature;
float _guessed_ground_temperature;
uint32_t _last_notify_ms;
bool _i2c_sensor_is_registered(uint8_t bus_num, uint8_t address) const;
bool _add_backend(AP_Baro_Backend *backend);
void _probe_i2c_barometers(void);
void probe_i2c_dev(AP_Baro_Backend* (*probefn)(AP_Baro&, AP_HAL::Device&), uint8_t bus, uint8_t addr);
void probe_spi_dev(AP_Baro_Backend* (*probefn)(AP_Baro&, AP_HAL::Device&), const char *name);
void probe_dev(AP_Baro_Backend* (*probefn)(AP_Baro&, AP_HAL::Device&), AP_HAL::Device *dev);
#if AP_BARO_ICM20789_ENABLED
void probe_icm20789(uint8_t bus, uint8_t addr, const char *mpu_name);
void probe_icm20789(uint8_t bus, uint8_t addr, uint8_t mpu_bus, uint8_t mpu_addr);
void _probe_icm20789(AP_HAL::I2CDevice *i2c_dev, AP_HAL::Device *mpu_dev);
#endif
#if AP_BARO_LPS2XH_ENABLED
void probe_lps2xh_via_Invensense_IMU(uint8_t bus, uint8_t addr, uint8_t mpu_addr);
#endif
AP_Int8 _filter_range;
AP_Int32 _baro_probe_ext;
#ifndef HAL_BUILD_AP_PERIPH
AP_Float _alt_error_max;
#endif
AP_Int16 _options;
HAL_Semaphore _rsem;
#if HAL_BARO_WIND_COMP_ENABLED
float wind_pressure_correction(uint8_t instance);
#endif
#if AP_BARO_THST_COMP_ENABLED
float thrust_pressure_correction(uint8_t instance);
#endif
void Write_Baro(void);
void Write_Baro_instance(uint64_t time_us, uint8_t baro_instance);
void update_field_elevation();
float get_altitude_difference_extended(float base_pressure, float pressure) const;
float get_EAS2TAS_extended(float pressure) const;
static float get_temperature_by_altitude_layer(float alt, int8_t idx);
float get_altitude_difference_simple(float base_pressure, float pressure) const;
float get_EAS2TAS_simple(float altitude, float pressure) const;
};
namespace AP {
AP_Baro &baro();
};