2011-12-28 05:31:36 -04:00
/// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
2012-10-11 17:48:39 -03:00
# include <AP_Progmem.h>
2011-02-14 00:25:20 -04:00
# include "Compass.h"
2012-02-11 07:53:30 -04:00
const AP_Param : : GroupInfo Compass : : var_info [ ] PROGMEM = {
2012-03-09 22:45:35 -04:00
// index 0 was used for the old orientation matrix
2013-01-02 03:07:33 -04:00
// @Param: OFS_X
// @DisplayName: Compass offsets on the X axis
// @Description: Offset to be added to the compass x-axis values to compensate for metal in the frame
// @Range: -400 400
// @Increment: 1
// @Param: OFS_Y
// @DisplayName: Compass offsets on the Y axis
// @Description: Offset to be added to the compass y-axis values to compensate for metal in the frame
// @Range: -400 400
// @Increment: 1
// @Param: OFS_Z
// @DisplayName: Compass offsets on the Z axis
// @Description: Offset to be added to the compass z-axis values to compensate for metal in the frame
// @Range: -400 400
// @Increment: 1
2013-12-09 02:33:54 -04:00
AP_GROUPINFO ( " OFS " , 1 , Compass , _offset [ 0 ] , 0 ) ,
2013-01-02 03:07:33 -04:00
// @Param: DEC
// @DisplayName: Compass declination
// @Description: An angle to compensate between the true north and magnetic north
// @Range: -3.142 3.142
// @Units: Radians
// @Increment: 0.01
// @User: Standard
2012-08-06 22:02:14 -03:00
AP_GROUPINFO ( " DEC " , 2 , Compass , _declination , 0 ) ,
2013-01-02 03:07:33 -04:00
// @Param: LEARN
// @DisplayName: Learn compass offsets automatically
// @Description: Enable or disable the automatic learning of compass offsets
// @Values: 0:Disabled,1:Enabled
// @User: Advanced
2012-08-06 22:02:14 -03:00
AP_GROUPINFO ( " LEARN " , 3 , Compass , _learn , 1 ) , // true if learning calibration
2013-01-02 03:07:33 -04:00
// @Param: USE
// @DisplayName: Use compass for yaw
// @Description: Enable or disable the use of the compass (instead of the GPS) for determining heading
// @Values: 0:Disabled,1:Enabled
// @User: Advanced
2012-08-06 22:02:14 -03:00
AP_GROUPINFO ( " USE " , 4 , Compass , _use_for_yaw , 1 ) , // true if used for DCM yaw
2013-01-02 03:07:33 -04:00
2012-12-19 22:16:42 -04:00
# if !defined( __AVR_ATmega1280__ )
2013-01-02 03:07:33 -04:00
// @Param: AUTODEC
// @DisplayName: Auto Declination
// @Description: Enable or disable the automatic calculation of the declination based on gps location
// @Values: 0:Disabled,1:Enabled
// @User: Advanced
2012-08-06 22:02:14 -03:00
AP_GROUPINFO ( " AUTODEC " , 5 , Compass , _auto_declination , 1 ) ,
2013-03-01 10:59:53 -04:00
# endif
2013-02-27 03:57:04 -04:00
2013-03-03 10:02:12 -04:00
// @Param: MOTCT
// @DisplayName: Motor interference compensation type
2013-05-11 02:50:36 -03:00
// @Description: Set motor interference compensation type to disabled, throttle or current. Do not change manually.
2013-03-03 10:02:12 -04:00
// @Values: 0:Disabled,1:Use Throttle,2:Use Current
// @Increment: 1
AP_GROUPINFO ( " MOTCT " , 6 , Compass , _motor_comp_type , AP_COMPASS_MOT_COMP_DISABLED ) ,
2013-02-27 03:57:04 -04:00
// @Param: MOT_X
// @DisplayName: Motor interference compensation for body frame X axis
// @Description: Multiplied by the current throttle and added to the compass's x-axis values to compensate for motor interference
2013-03-01 10:59:53 -04:00
// @Range: -1000 1000
2013-05-11 02:50:36 -03:00
// @Units: Offset per Amp or at Full Throttle
2013-02-27 03:57:04 -04:00
// @Increment: 1
// @Param: MOT_Y
// @DisplayName: Motor interference compensation for body frame Y axis
// @Description: Multiplied by the current throttle and added to the compass's y-axis values to compensate for motor interference
2013-03-01 10:59:53 -04:00
// @Range: -1000 1000
2013-05-11 02:50:36 -03:00
// @Units: Offset per Amp or at Full Throttle
2013-02-27 03:57:04 -04:00
// @Increment: 1
// @Param: MOT_Z
// @DisplayName: Motor interference compensation for body frame Z axis
// @Description: Multiplied by the current throttle and added to the compass's z-axis values to compensate for motor interference
2013-03-01 10:59:53 -04:00
// @Range: -1000 1000
2013-05-11 02:50:36 -03:00
// @Units: Offset per Amp or at Full Throttle
2013-02-27 03:57:04 -04:00
// @Increment: 1
2013-12-09 04:45:31 -04:00
AP_GROUPINFO ( " MOT " , 7 , Compass , _motor_compensation [ 0 ] , 0 ) ,
2013-02-27 03:57:04 -04:00
2013-05-01 23:27:35 -03:00
// @Param: ORIENT
// @DisplayName: Compass orientation
2014-02-26 21:46:27 -04:00
// @Description: The orientation of the compass relative to the autopilot board. This will default to the right value for each board type, but can be changed if you have an external compass. See the documentation for your external compass for the right value. The correct orientation should give the X axis forward, the Y axis to the right and the Z axis down. So if your aircraft is pointing west it should show a positive value for the Y axis, and a value close to zero for the X axis. On a PX4 or Pixhawk with an external compass the correct value is zero if the compass is correctly oriented. NOTE: This orientation is combined with any AHRS_ORIENTATION setting.
2013-08-30 01:19:03 -03:00
// @Values: 0:None,1:Yaw45,2:Yaw90,3:Yaw135,4:Yaw180,5:Yaw225,6:Yaw270,7:Yaw315,8:Roll180,9:Roll180Yaw45,10:Roll180Yaw90,11:Roll180Yaw135,12:Pitch180,13:Roll180Yaw225,14:Roll180Yaw270,15:Roll180Yaw315,16:Roll90,17:Roll90Yaw45,18:Roll90Yaw90,19:Roll90Yaw135,20:Roll270,21:Roll270Yaw45,22:Roll270Yaw90,23:Roll270Yaw136,24:Pitch90,25:Pitch270,26:Pitch180Yaw90,27:Pitch180Yaw270,28:Roll90Pitch90,29:Roll180Pitch90,30:Roll270Pitch90,31:Roll90Pitch180,32:Roll270Pitch180,33:Roll90Pitch270,34:Roll180Pitch270,35:Roll270Pitch270,36:Roll90Pitch180Yaw90,37:Roll90Yaw270
2013-05-01 23:27:35 -03:00
AP_GROUPINFO ( " ORIENT " , 8 , Compass , _orientation , ROTATION_NONE ) ,
2013-08-30 01:02:09 -03:00
// @Param: EXTERNAL
// @DisplayName: Compass is attached via an external cable
2014-02-26 21:46:27 -04:00
// @Description: Configure compass so it is attached externally. This is auto-detected on PX4 and Pixhawk, but must be set correctly on an APM2. Set to 1 if the compass is externally connected. When externally connected the COMPASS_ORIENT option operates independently of the AHRS_ORIENTATION board orientation option
2013-08-30 01:02:09 -03:00
// @Values: 0:Internal,1:External
// @User: Advanced
AP_GROUPINFO ( " EXTERNAL " , 9 , Compass , _external , 0 ) ,
2013-12-09 02:33:54 -04:00
# if COMPASS_MAX_INSTANCES > 1
AP_GROUPINFO ( " OFS2 " , 10 , Compass , _offset [ 1 ] , 0 ) ,
2013-12-09 04:45:31 -04:00
AP_GROUPINFO ( " MOT2 " , 11 , Compass , _motor_compensation [ 1 ] , 0 ) ,
2014-05-21 23:52:25 -03:00
// @Param: PRIMARY
// @DisplayName: Choose primary compass
2014-07-10 19:32:06 -03:00
// @Description: If more than one compass is available this selects which compass is the primary. Normally 0=External, 1=Internal. If no External compass is attached this parameter is ignored
2014-07-10 18:19:19 -03:00
// @Values: 0:FirstCompass,1:SecondCompass
2014-05-21 23:52:25 -03:00
// @User: Advanced
AP_GROUPINFO ( " PRIMARY " , 12 , Compass , _primary , 0 ) ,
2013-12-09 02:33:54 -04:00
# endif
2014-07-03 23:07:47 -03:00
# if COMPASS_MAX_INSTANCES > 2
AP_GROUPINFO ( " OFS3 " , 13 , Compass , _offset [ 2 ] , 0 ) ,
AP_GROUPINFO ( " MOT3 " , 14 , Compass , _motor_compensation [ 2 ] , 0 ) ,
# endif
2014-07-07 09:24:18 -03:00
# if COMPASS_MAX_INSTANCES > 1
// @Param: DEV_ID
// @DisplayName: Compass device id
// @Description: Compass device id. Automatically detected, do not set manually
// @User: Advanced
AP_GROUPINFO ( " DEV_ID " , 15 , Compass , _dev_id [ 0 ] , COMPASS_EXPECTED_DEV_ID ) ,
// @Param: DEV_ID2
// @DisplayName: Compass2 device id
// @Description: Second compass's device id. Automatically detected, do not set manually
// @User: Advanced
AP_GROUPINFO ( " DEV_ID2 " , 16 , Compass , _dev_id [ 1 ] , COMPASS_EXPECTED_DEV_ID2 ) ,
# endif
# if COMPASS_MAX_INSTANCES > 2
// @Param: DEV_ID3
// @DisplayName: Compass3 device id
// @Description: Third compass's device id. Automatically detected, do not set manually
// @User: Advanced
AP_GROUPINFO ( " DEV_ID3 " , 17 , Compass , _dev_id [ 2 ] , COMPASS_EXPECTED_DEV_ID3 ) ,
# endif
2012-02-12 03:23:19 -04:00
AP_GROUPEND
2012-02-11 07:53:30 -04:00
} ;
2011-02-14 00:25:20 -04:00
// Default constructor.
// Note that the Vector/Matrix constructors already implicitly zero
// their values.
//
2012-02-11 07:53:30 -04:00
Compass : : Compass ( void ) :
2012-08-17 03:19:22 -03:00
product_id ( AP_COMPASS_TYPE_UNKNOWN ) ,
2014-07-15 00:12:58 -03:00
last_update ( 0 ) ,
_null_init_done ( false ) ,
_thr_or_curr ( 0.0f ) ,
_board_orientation ( ROTATION_NONE )
2011-02-14 00:25:20 -04:00
{
2012-12-12 17:43:51 -04:00
AP_Param : : setup_object_defaults ( this , var_info ) ;
2014-07-10 03:35:40 -03:00
# if COMPASS_MAX_INSTANCES > 1
// default device ids to zero. init() method will overwrite with the actual device ids
2014-07-15 00:12:58 -03:00
for ( uint8_t i = 0 ; i < COMPASS_MAX_INSTANCES ; i + + ) {
2014-07-10 03:35:40 -03:00
_dev_id [ i ] = 0 ;
}
# endif
2011-02-14 00:25:20 -04:00
}
// Default init method, just returns success.
//
bool
Compass : : init ( )
{
return true ;
}
void
2014-07-09 05:09:02 -03:00
Compass : : set_and_save_offsets ( uint8_t i , const Vector3f & offsets )
2011-02-14 00:25:20 -04:00
{
2014-07-10 02:37:27 -03:00
// sanity check compass instance provided
if ( i < COMPASS_MAX_INSTANCES ) {
_offset [ i ] . set ( offsets ) ;
save_offsets ( i ) ;
}
2011-02-14 00:25:20 -04:00
}
void
2014-07-09 05:07:30 -03:00
Compass : : save_offsets ( uint8_t i )
2011-02-14 00:25:20 -04:00
{
2014-07-09 05:07:30 -03:00
_offset [ i ] . save ( ) ; // save offsets
2014-07-07 09:24:18 -03:00
# if COMPASS_MAX_INSTANCES > 1
2014-07-09 05:07:30 -03:00
_dev_id [ i ] . save ( ) ; // save device id corresponding to these offsets
2014-07-07 09:24:18 -03:00
# endif
2014-07-09 05:07:30 -03:00
}
void
Compass : : save_offsets ( void )
{
for ( uint8_t i = 0 ; i < COMPASS_MAX_INSTANCES ; i + + ) {
save_offsets ( i ) ;
2013-12-09 02:33:54 -04:00
}
2011-02-14 00:25:20 -04:00
}
2013-02-27 03:57:04 -04:00
void
2013-12-09 04:45:31 -04:00
Compass : : set_motor_compensation ( const Vector3f & motor_comp_factor , uint8_t i )
2013-02-27 03:57:04 -04:00
{
2013-12-09 04:45:31 -04:00
_motor_compensation [ i ] . set ( motor_comp_factor ) ;
2013-02-27 03:57:04 -04:00
}
void
Compass : : save_motor_compensation ( )
{
2013-03-03 10:02:12 -04:00
_motor_comp_type . save ( ) ;
2013-12-09 04:45:31 -04:00
for ( uint8_t k = 0 ; k < COMPASS_MAX_INSTANCES ; k + + ) {
_motor_compensation [ k ] . save ( ) ;
}
2013-02-27 03:57:04 -04:00
}
2012-03-30 00:18:06 -03:00
void
2012-08-18 08:41:38 -03:00
Compass : : set_initial_location ( int32_t latitude , int32_t longitude )
2012-03-10 19:19:04 -04:00
{
2012-03-30 00:18:06 -03:00
// if automatic declination is configured, then compute
// the declination based on the initial GPS fix
2012-12-19 22:16:42 -04:00
# if !defined( __AVR_ATmega1280__ )
2012-08-17 03:19:22 -03:00
if ( _auto_declination ) {
// Set the declination based on the lat/lng from GPS
2012-10-11 17:48:39 -03:00
_declination . set ( radians (
AP_Declination : : get_declination (
( float ) latitude / 10000000 ,
( float ) longitude / 10000000 ) ) ) ;
2012-08-17 03:19:22 -03:00
}
2012-12-19 22:16:42 -04:00
# endif
2012-03-10 19:19:04 -04:00
}
2011-02-14 00:25:20 -04:00
void
2013-04-15 09:50:44 -03:00
Compass : : set_declination ( float radians , bool save_to_eeprom )
2011-02-14 00:25:20 -04:00
{
2013-04-15 09:50:44 -03:00
if ( save_to_eeprom ) {
_declination . set_and_save ( radians ) ;
} else {
_declination . set ( radians ) ;
}
2011-02-14 00:25:20 -04:00
}
2011-02-18 23:57:53 -04:00
float
2013-05-08 20:22:00 -03:00
Compass : : get_declination ( ) const
2011-02-18 23:57:53 -04:00
{
2012-08-17 03:19:22 -03:00
return _declination . get ( ) ;
2011-02-18 23:57:53 -04:00
}
2013-08-18 08:08:34 -03:00
/*
calculate a compass heading given the attitude from DCM and the mag vector
*/
2012-06-20 06:30:30 -03:00
float
2013-05-08 20:22:00 -03:00
Compass : : calculate_heading ( const Matrix3f & dcm_matrix ) const
2011-02-14 00:25:20 -04:00
{
2013-08-18 08:08:34 -03:00
float cos_pitch_sq = 1.0f - ( dcm_matrix . c . x * dcm_matrix . c . x ) ;
2011-05-08 15:15:29 -03:00
// Tilt compensated magnetic field Y component:
2013-12-09 01:05:57 -04:00
float headY = _field [ 0 ] . y * dcm_matrix . c . z - _field [ 0 ] . z * dcm_matrix . c . y ;
2012-02-23 19:42:03 -04:00
2011-02-14 00:25:20 -04:00
// Tilt compensated magnetic field X component:
2013-12-09 01:05:57 -04:00
float headX = _field [ 0 ] . x * cos_pitch_sq - dcm_matrix . c . x * ( _field [ 0 ] . y * dcm_matrix . c . y + _field [ 0 ] . z * dcm_matrix . c . z ) ;
2013-05-08 20:19:01 -03:00
2011-02-14 00:25:20 -04:00
// magnetic heading
2011-07-08 00:56:04 -03:00
// 6/4/11 - added constrain to keep bad values from ruining DCM Yaw - Jason S.
2013-05-08 20:19:01 -03:00
float heading = constrain_float ( atan2f ( - headY , headX ) , - 3.15f , 3.15f ) ;
2011-02-14 00:25:20 -04:00
// Declination correction (if supplied)
2013-01-10 14:42:24 -04:00
if ( fabsf ( _declination ) > 0.0f )
2011-02-14 00:25:20 -04:00
{
heading = heading + _declination ;
2013-01-10 14:42:24 -04:00
if ( heading > PI ) // Angle normalization (-180 deg, 180 deg)
heading - = ( 2.0f * PI ) ;
else if ( heading < - PI )
heading + = ( 2.0f * PI ) ;
2011-02-14 00:25:20 -04:00
}
2012-06-20 06:30:30 -03:00
return heading ;
2011-02-14 00:25:20 -04:00
}
2014-07-07 09:24:18 -03:00
/// Returns True if the compasses have been configured (i.e. offsets saved)
///
/// @returns True if compass has been configured
///
bool Compass : : configured ( uint8_t i )
{
// exit immediately if instance is beyond the number of compasses we have available
if ( i > get_count ( ) ) {
return false ;
}
// exit immediately if all offsets are zero
if ( get_offsets ( i ) . length ( ) = = 0.0f ) {
return false ;
}
# if COMPASS_MAX_INSTANCES > 1
// backup detected dev_id
int32_t dev_id_orig = _dev_id [ i ] ;
// load dev_id from eeprom
_dev_id [ i ] . load ( ) ;
// if different then the device has not been configured
if ( _dev_id [ i ] ! = dev_id_orig ) {
// restore device id
_dev_id [ i ] = dev_id_orig ;
// return failure
return false ;
}
# endif
2012-03-27 01:16:00 -03:00
2014-07-07 09:24:18 -03:00
// if we got here then it must be configured
return true ;
}
bool Compass : : configured ( void )
{
bool all_configured = true ;
for ( uint8_t i = 0 ; i < get_count ( ) ; i + + ) {
all_configured = all_configured & & configured ( i ) ;
}
return all_configured ;
}