AHRS based on MatrixPilot DCM algorithm; ported from Pololu MinIMU-9 example code in turn based on ArduPilot 1.5

DCM.h

Committer:
shimniok
Date:
2012-01-24
Revision:
0:62284d27d75e

File content as of revision 0:62284d27d75e:

/*
MinIMU-9-mbed-AHRS
Pololu MinIMU-9 + mbed AHRS (Attitude and Heading Reference System)

Modified and ported to mbed environment by Michael Shimniok
http://www.bot-thoughts.com/

Basedd on MinIMU-9-Arduino-AHRS
Pololu MinIMU-9 + Arduino AHRS (Attitude and Heading Reference System)

Copyright (c) 2011 Pololu Corporation.
http://www.pololu.com/

MinIMU-9-Arduino-AHRS is based on sf9domahrs by Doug Weibel and Jose Julio:
http://code.google.com/p/sf9domahrs/

sf9domahrs is based on ArduIMU v1.5 by Jordi Munoz and William Premerlani, Jose
Julio and Doug Weibel:
http://code.google.com/p/ardu-imu/

MinIMU-9-Arduino-AHRS is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your option)
any later version.

MinIMU-9-Arduino-AHRS 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 Lesser General Public License for
more details.

You should have received a copy of the GNU Lesser General Public License along
with MinIMU-9-Arduino-AHRS. If not, see <http://www.gnu.org/licenses/>.

*/
#ifndef __DCM_H
#define __DCM_H

#define GRAVITY 1024  //this equivalent to 1G in the raw data coming from the accelerometer 
#define Accel_Scale(x) x*(GRAVITY/9.81)//Scaling the raw data of the accel to actual acceleration in meters for seconds square

#define ToRad(x) ((x)*0.01745329252)  // *pi/180
#define ToDeg(x) ((x)*57.2957795131)  // *180/pi

//#define Kp_ROLLPITCH 0.02
//#define Ki_ROLLPITCH 0.00002
//#define Kp_YAW 1.2
//#define Ki_YAW 0.00002
#define Kp_ROLLPITCH 0.02
#define Ki_ROLLPITCH 0.00002
#define Kp_YAW 1.2
#define Ki_YAW 0.00002

#define OUTPUTMODE 1 // enable drift correction

// TODO: move elsewhere
// Gyro sensor hardware-specific stuff
#define Gyro_Gain_X 0.07 //X axis Gyro gain
#define Gyro_Gain_Y 0.07 //Y axis Gyro gain
#define Gyro_Gain_Z 0.07 //Z axis Gyro gain
#define Gyro_Scaled_X(x) ((x)*ToRad(Gyro_Gain_X)) //Return the scaled ADC raw data of the gyro in radians per second
#define Gyro_Scaled_Y(x) ((x)*ToRad(Gyro_Gain_Y)) //Return the scaled ADC raw data of the gyro in radians per second
#define Gyro_Scaled_Z(x) ((x)*ToRad(Gyro_Gain_Z)) //Return the scaled ADC raw data of the gyro in radians per second

/** DCM AHRS algorithm ported to mbed from Pololu MinIMU-9 in turn ported from ArduPilot 1.5
 * revised in a more OO style, though no done yet.
 *
 * Early version. There's more to do here but it's a start, at least.
 *
 * Warning: Interface will most likely change.
 *
 * Expects to see a Sensors.h in your project, as follows, with functions that read sensors and set the appropriate 
 * "input" member variables below. Eventually I'll change this to a better encapsulated OOP approach. 
 *
 * This approach of an external Sensors.* is an abstraction layer that makes it much, much easier to
 * swap in a different sensor suite versus the original code. You can use Serial, I2C, SPI, Analog,
 * whatever you want, whatever it takes as long as you populate the gyro, accel, and mag vectors before
 * calling Update_step()
 *
 * @code
 * #ifndef __SENSORS_H
 * #define __SENSORS_H
 *
 * void Gyro_Init(void);
 * void Read_Gyro(void);
 * void Accel_Init(void);
 * void Read_Accel(void);
 * void Compass_Init(void);
 * void Read_Compass(void);
 * void Calculate_Offsets(void);
 * void Compass_Heading(void);
 * 
 * #endif
 * @endcode
 *
 */
class DCM {
    public:
        /** Output: Euler angle: roll */
        float roll;
        /** Output:  Euler angle: pitch */
        float pitch;
        /** Output:  Euler angle: yaw */
        float yaw;
        
        /** Input gyro sensor reading X-axis */
        int gyro_x;
        /** Input gyro sensor reading Y-axis */
        int gyro_y;
        /** Input gyro sensor reading Z-axis */
        int gyro_z;
        /** Input accelerometer sensor reading X-axis */
        int accel_x;
        /** Input accelerometer sensor reading Y-axis */
        int accel_y;
        /** Input accelerometer sensor reading Z-axis */
        int accel_z;
        /*
        int magnetom_x;
        int magnetom_y;
        int magnetom_z;
        */
        /** Input for the offset corrected & scaled magnetometer reading, X-axis */
        float c_magnetom_x;
        /** Input for the offset corrected & scaled magnetometer reading, Y-axis */
        float c_magnetom_y;
        /** Input for the offset corrected & scaled magnetometer reading, Z-axis */
        float c_magnetom_z;
        /** Input for the calculated magnetic heading */
        float MAG_Heading;
        /** Input for the speed (ie, the magnitude of the 3d velocity vector */
        float speed_3d;
        /** Input for the integration time (DCM algorithm) */
        float G_Dt;

        /** Creates a new DCM AHRS algorithm object
         */
        DCM(void);

        /** A single update cycle for the algorithm; updates the matrix, normalizes it, corrects for gyro
         * drift on 3 axes, (does not yet adjust for acceleration). Magnetometer update is run less often
         * than gyro/accelerometer-based update
         */
        void Update_step(void);
        
    private:        
        float Accel_Vector[3];  // Store the acceleration in a vector
        float Gyro_Vector[3];   // Store the gyros turn rate in a vector
        float dcm[3][3];        // The Direction Cosine Matrix
        float errorRollPitch[3]; 
        float errorYaw[3];
        float Omega_Vector[3];  // Corrected Gyro_Vector data
        float Omega_P[3];       // Omega Proportional correction
        float Omega_I[3];       // Omega Integrator
        float Omega[3];         // Omega
        float Temporary_Matrix[3][3];
        float Update_Matrix[3][3];
        int update_count;   // call Update_mag() every update_count calls to Update_step()
        float constrain(float x, float a, float b);
        void Normalize(void);
        void Drift_correction(void);
        void Accel_adjust(void);
        void Matrix_update(void);
        void Euler_angles(void);
        void Update_mag(void);
        
};

#endif