2012-06-19 23:25:19 -03:00
/// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
2013-08-29 02:34:34 -03:00
/*
This program 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 3 of the License , or
( at your option ) any later version .
This program 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 this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2012-06-19 23:25:19 -03:00
/*
2012-08-17 03:09:23 -03:00
* APM_Baro . cpp - barometer driver
*
*/
2012-06-19 23:25:19 -03:00
2013-01-10 15:22:37 -04:00
# include <AP_Math.h>
2012-06-19 23:25:19 -03:00
# include <AP_Common.h>
# include <AP_Baro.h>
2012-10-11 14:53:21 -03:00
# include <AP_HAL.h>
extern const AP_HAL : : HAL & hal ;
2012-06-19 23:25:19 -03:00
2012-06-27 02:59:52 -03:00
// table of user settable parameters
const AP_Param : : GroupInfo AP_Baro : : var_info [ ] PROGMEM = {
2012-07-06 02:11:22 -03:00
// NOTE: Index numbers 0 and 1 were for the old integer
// ground temperature and pressure
2012-08-17 03:09:23 -03:00
// @Param: ABS_PRESS
// @DisplayName: Absolute Pressure
2013-06-26 05:32:20 -03:00
// @Description: calibrated ground pressure in Pascals
2014-10-14 00:42:27 -03:00
// @Units: pascals
2012-08-17 03:09:23 -03:00
// @Increment: 1
2012-08-06 22:02:14 -03:00
AP_GROUPINFO ( " ABS_PRESS " , 2 , AP_Baro , _ground_pressure , 0 ) ,
2012-06-27 02:59:52 -03:00
2013-06-17 23:28:08 -03:00
// @Param: TEMP
2012-08-17 03:09:23 -03:00
// @DisplayName: ground temperature
2013-06-26 05:32:20 -03:00
// @Description: calibrated ground temperature in degrees Celsius
2014-10-14 00:42:27 -03:00
// @Units: degrees celsius
2012-08-17 03:09:23 -03:00
// @Increment: 1
2012-08-06 22:02:14 -03:00
AP_GROUPINFO ( " TEMP " , 3 , AP_Baro , _ground_temperature , 0 ) ,
2013-06-26 05:32:20 -03:00
2013-07-10 01:38:57 -03:00
// @Param: ALT_OFFSET
// @DisplayName: altitude offset
// @Description: altitude offset in meters added to barometric altitude. This is used to allow for automatic adjustment of the base barometric altitude by a ground station equipped with a barometer. The value is added to the barometric altitude read by the aircraft. It is automatically reset to 0 when the barometer is calibrated on each reboot or when a preflight calibration is performed.
// @Units: meters
// @Range: -128 127
// @Increment: 1
AP_GROUPINFO ( " ALT_OFFSET " , 4 , AP_Baro , _alt_offset , 0 ) ,
2012-06-27 02:59:52 -03:00
AP_GROUPEND
} ;
2012-06-19 23:25:19 -03:00
// calibrate the barometer. This must be called at least once before
// the altitude() or climb_rate() interfaces can be used
2012-10-11 14:53:21 -03:00
void AP_Baro : : calibrate ( )
2012-06-19 23:25:19 -03:00
{
2012-08-17 03:09:23 -03:00
float ground_pressure = 0 ;
float ground_temperature = 0 ;
2013-07-10 01:38:57 -03:00
// reset the altitude offset when we calibrate. The altitude
// offset is supposed to be for within a flight
_alt_offset . set_and_save ( 0 ) ;
2012-12-05 21:18:04 -04:00
{
uint32_t tstart = hal . scheduler - > millis ( ) ;
2014-08-13 09:42:14 -03:00
while ( ground_pressure = = 0 | | ! _flags . healthy ) {
2012-12-05 21:18:04 -04:00
read ( ) ; // Get initial data from absolute pressure sensor
if ( hal . scheduler - > millis ( ) - tstart > 500 ) {
2012-12-17 20:29:05 -04:00
hal . scheduler - > panic ( PSTR ( " PANIC: AP_Baro::read unsuccessful "
2012-12-05 21:18:04 -04:00
" for more than 500ms in AP_Baro::calibrate [1] \r \n " ) ) ;
}
ground_pressure = get_pressure ( ) ;
ground_temperature = get_temperature ( ) ;
hal . scheduler - > delay ( 20 ) ;
}
2012-08-17 03:09:23 -03:00
}
2012-07-06 02:11:22 -03:00
// let the barometer settle for a full second after startup
// the MS5611 reads quite a long way off for the first second,
2012-08-17 03:09:23 -03:00
// leading to about 1m of error if we don't wait
2012-12-05 21:18:04 -04:00
for ( uint8_t i = 0 ; i < 10 ; i + + ) {
uint32_t tstart = hal . scheduler - > millis ( ) ;
2012-08-17 03:09:23 -03:00
do {
read ( ) ;
2012-12-05 21:18:04 -04:00
if ( hal . scheduler - > millis ( ) - tstart > 500 ) {
2012-12-17 20:29:05 -04:00
hal . scheduler - > panic ( PSTR ( " PANIC: AP_Baro::read unsuccessful "
2012-12-05 21:18:04 -04:00
" for more than 500ms in AP_Baro::calibrate [2] \r \n " ) ) ;
}
2014-08-13 09:42:14 -03:00
} while ( ! _flags . healthy ) ;
2012-12-05 21:18:04 -04:00
ground_pressure = get_pressure ( ) ;
ground_temperature = get_temperature ( ) ;
2012-10-11 14:53:21 -03:00
hal . scheduler - > delay ( 100 ) ;
2012-07-06 02:11:22 -03:00
}
2012-06-19 23:25:19 -03:00
2012-07-06 02:11:22 -03:00
// now average over 5 values for the ground pressure and
2012-08-17 03:09:23 -03:00
// temperature settings
for ( uint16_t i = 0 ; i < 5 ; i + + ) {
2012-12-05 21:18:04 -04:00
uint32_t tstart = hal . scheduler - > millis ( ) ;
2012-08-17 03:09:23 -03:00
do {
read ( ) ;
2012-12-05 21:18:04 -04:00
if ( hal . scheduler - > millis ( ) - tstart > 500 ) {
2012-12-17 20:29:05 -04:00
hal . scheduler - > panic ( PSTR ( " PANIC: AP_Baro::read unsuccessful "
2012-12-05 21:18:04 -04:00
" for more than 500ms in AP_Baro::calibrate [3] \r \n " ) ) ;
}
2014-08-13 09:42:14 -03:00
} while ( ! _flags . healthy ) ;
2013-01-10 14:42:24 -04:00
ground_pressure = ( ground_pressure * 0.8f ) + ( get_pressure ( ) * 0.2f ) ;
ground_temperature = ( ground_temperature * 0.8f ) +
( get_temperature ( ) * 0.2f ) ;
2012-12-05 21:18:04 -04:00
2012-10-11 14:53:21 -03:00
hal . scheduler - > delay ( 100 ) ;
2012-08-17 03:09:23 -03:00
}
_ground_pressure . set_and_save ( ground_pressure ) ;
2013-09-21 08:30:41 -03:00
_ground_temperature . set_and_save ( ground_temperature ) ;
2012-06-19 23:25:19 -03:00
}
2013-10-05 05:44:00 -03:00
/**
update the barometer calibration
this updates the baro ground calibration to the current values . It
can be used before arming to keep the baro well calibrated
*/
void AP_Baro : : update_calibration ( )
{
2014-07-22 05:07:48 -03:00
float pressure = get_pressure ( ) ;
_ground_pressure . set ( pressure ) ;
2013-10-05 05:44:00 -03:00
_ground_temperature . set ( get_temperature ( ) ) ;
}
2014-04-11 03:34:02 -03:00
// return altitude difference in meters between current pressure and a
// given base_pressure in Pascal
2014-08-13 03:21:52 -03:00
float AP_Baro : : get_altitude_difference ( float base_pressure , float pressure ) const
2014-04-11 03:34:02 -03:00
{
float ret ;
# if HAL_CPU_CLASS <= HAL_CPU_CLASS_16
// on slower CPUs use a less exact, but faster, calculation
float scaling = base_pressure / pressure ;
float temp = _ground_temperature + 273.15f ;
ret = logf ( scaling ) * temp * 29.271267f ;
# else
// on faster CPUs use a more exact calculation
float scaling = pressure / base_pressure ;
float temp = _ground_temperature + 273.15f ;
// This is an exact calculation that is within +-2.5m of the standard atmosphere tables
// in the troposphere (up to 11,000 m amsl).
ret = 153.8462f * temp * ( 1.0f - expf ( 0.190259f * logf ( scaling ) ) ) ;
# endif
return ret ;
}
2012-06-19 23:25:19 -03:00
// return current altitude estimate relative to time that calibrate()
// was called. Returns altitude in meters
// note that this relies on read() being called regularly to get new data
float AP_Baro : : get_altitude ( void )
{
2014-01-05 01:36:12 -04:00
if ( _ground_pressure = = 0 ) {
// called before initialisation
return 0 ;
}
2012-06-19 23:25:19 -03:00
if ( _last_altitude_t = = _last_update ) {
// no new information
2013-07-10 01:38:57 -03:00
return _altitude + _alt_offset ;
2012-06-19 23:25:19 -03:00
}
2014-07-22 05:07:48 -03:00
float pressure = get_pressure ( ) ;
2014-08-13 09:42:14 -03:00
float alt = get_altitude_difference ( _ground_pressure , pressure ) ;
2012-06-19 23:25:19 -03:00
2014-08-13 09:42:14 -03:00
// record that we have consumed latest data
2012-06-19 23:25:19 -03:00
_last_altitude_t = _last_update ;
2012-07-06 02:11:22 -03:00
2014-08-13 09:42:14 -03:00
// sanity check altitude
if ( isnan ( alt ) | | isinf ( alt ) ) {
_flags . alt_ok = false ;
} else {
_altitude = alt ;
_flags . alt_ok = true ;
}
2012-07-06 02:11:22 -03:00
// ensure the climb rate filter is updated
_climb_rate_filter . update ( _altitude , _last_update ) ;
2013-07-10 01:38:57 -03:00
return _altitude + _alt_offset ;
2012-06-19 23:25:19 -03:00
}
2013-06-26 05:32:37 -03:00
// return current scale factor that converts from equivalent to true airspeed
// valid for altitudes up to 10km AMSL
// assumes standard atmosphere lapse rate
float AP_Baro : : get_EAS2TAS ( void )
{
2014-07-08 07:26:54 -03:00
if ( ( fabsf ( _altitude - _last_altitude_EAS2TAS ) < 100.0f ) & & ( _EAS2TAS ! = 0.0f ) ) {
2013-06-26 05:32:37 -03:00
// not enough change to require re-calculating
return _EAS2TAS ;
}
float tempK = ( ( float ) _ground_temperature ) + 273.15f - 0.0065f * _altitude ;
_EAS2TAS = safe_sqrt ( 1.225f / ( ( float ) get_pressure ( ) / ( 287.26f * tempK ) ) ) ;
_last_altitude_EAS2TAS = _altitude ;
return _EAS2TAS ;
}
2012-06-19 23:25:19 -03:00
// return current climb_rate estimeate relative to time that calibrate()
// was called. Returns climb rate in meters/s, positive means up
// note that this relies on read() being called regularly to get new data
float AP_Baro : : get_climb_rate ( void )
{
2012-07-06 02:11:22 -03:00
// we use a 7 point derivative filter on the climb rate. This seems
2012-06-19 23:25:19 -03:00
// to produce somewhat reasonable results on real hardware
2013-01-10 14:42:24 -04:00
return _climb_rate_filter . slope ( ) * 1.0e3 f ;
2012-06-19 23:25:19 -03:00
}
2012-08-07 22:29:53 -03:00