UAVX Multicopter Flight Controller.

Dependencies:   mbed

accel.c

Committer:
gke
Date:
2011-04-26
Revision:
2:90292f8bd179
Parent:
1:1e3318a30ddd

File content as of revision 2:90292f8bd179:

// ===============================================================================================
// =                              UAVXArm Quadrocopter Controller                                =
// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
// =                           http://code.google.com/p/uavp-mods/                               =
// ===============================================================================================

//    This is part of UAVXArm.

//    UAVXArm 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.

//    UAVXArm 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/

#include "UAVXArm.h"

void ShowAccType(void);
void ReadAccelerometers(void);
void GetAccelerations(void);
void GetNeutralAccelerations(void);
void AccelerometerTest(void);
void InitAccelerometers(void);

real32 Vel[3], AccADC[3], AccADCp[3], AccNoise[3], Acc[3], AccNeutral[3], Accp[3];
int16 NewAccNeutral[3];
uint8 AccelerometerType;
real32 GravityR;

void ShowAccType(void) {
    switch ( AccelerometerType ) {
        case LISLAcc:
            TxString(" LIS3L");
            break;
        case ADXL345Acc:
            TxString(" ADXL345");
            break;
        case AccUnknown:
            TxString(" unknown");
            break;
        default:
            ;
    } // switch
} // ShowAccType

void ReadAccelerometers(void) {
    switch ( AccelerometerType ) {
        case LISLAcc:
            ReadLISLAcc();
            break;
        case ADXL345Acc:
            ReadADXL345Acc();
            break;
            // other accelerometers
        default:
            Acc[BF] = Acc[LR] = 0.0;
            Acc[UD] = 1.0;
            break;
    } // switch

} // ReadAccelerometers

void GetNeutralAccelerations(void) {
    static int16 i;
    static uint8 a;
    static real32 Temp[3] = {0.0, 0.0, 0.0};
    const int16 Samples = 100;

    if ( F.AccelerationsValid ) {
        for ( i = Samples; i; i--) {
            ReadAccelerometers();
            for ( a = 0; a <(uint8)3; a++ )
                Temp[a] += AccADC[a];
        }

        for ( a = 0; a <(uint8)3; a++ )
            Temp[a] /= Samples;

        // removes other accelerations
        GravityR = 1.0/sqrt(Sqr(Temp[BF])+Sqr(Temp[LR])+Sqr(Temp[UD]));
        for ( a = 0; a <(uint8)3; a++ )
            Acc[a] = Temp[a] * GravityR;

        NewAccNeutral[BF] = Limit1((int16)(Acc[BF] * 1000.0 ), 99);
        NewAccNeutral[LR] = Limit1( (int16)(Acc[LR] * 1000.0 ), 99);
        NewAccNeutral[UD] = Limit1( (int16)(( Acc[UD] + 1.0 ) * 1000.0) , 99);

    } else
        for ( a = 0; a <(uint8)3; a++ )
            AccNeutral[a] = 0.0;

} // GetNeutralAccelerations

void GetAccelerations(void) {

    static uint8 a;
    static real32 AccA;

    if ( F.AccelerationsValid ) {
        ReadAccelerometers();

        // Neutral[ {LR, BF, UD} ] pass through UAVPSet
        // and come back as AccMiddle[LR] etc.

        Acc[BF] = AccADC[BF] * GravityR - K[MiddleBF];
        Acc[LR] = AccADC[LR] * GravityR - K[MiddleLR];
        Acc[UD] = AccADC[UD] * GravityR - K[MiddleUD];

#ifndef SUPPRESS_ACC_FILTERS
        AccA = dT / ( 1.0 / ( TWOPI * ACC_FREQ ) + dT );
        for ( a = 0; a < (uint8)3; a++ )
            Acc[a] = LPFilter( Acc[a], Accp[a], AccA );
#endif // !SUPPRESS_ACC_FILTERS
        for ( a = 0; a < (uint8)3; a++ )
            Accp[a] = Acc[a];

    } else {
        Acc[LR] = Acc[BF] = 0;
        Acc[UD] = 1.0;
    }
} // GetAccelerations

void AccelerometerTest(void) {
    TxString("\r\nAccelerometer test -");
    ShowAccType();
    TxString("\r\nRead once - no averaging\r\n");

    InitAccelerometers();

    if ( F.AccelerationsValid ) {
        GetAccelerations();

        TxString("Sensor & Max Delta\r\n");

        TxString("\tL->R: \t");
        TxVal32( AccADC[LR], 0, HT);
        TxVal32( AccNoise[LR], 0, 0);
        if ( fabs(Acc[LR]) > 0.2 )
            TxString(" fault?");
        TxNextLine();

        TxString("\tB->F: \t");
        TxVal32( AccADC[BF], 0, HT);
        TxVal32( AccNoise[BF], 0, 0);
        if ( fabs(Acc[BF]) > 0.2 )
            TxString(" fault?");
        TxNextLine();

        TxString("\tU->D:    \t");
        TxVal32( AccADC[UD], 0, HT);
        TxVal32( AccNoise[UD], 0, 0);
        if ( fabs(Acc[UD]) > 1.2 )
            TxString(" fault?");
        TxNextLine();
    }
} // AccelerometerTest

void InitAccelerometers(void) {
    static uint8 a;

    F.AccelerationsValid = true; // optimistic

    for ( a = 0; a < (uint8)3; a++ ) 
        NewAccNeutral[a] = AccADC[a] = AccADCp[a] = AccNoise[a] = Acc[a] = Accp[a] = Vel[a] = 0.0;

    Acc[2] = Accp[2] = 1.0;
    if ( ADXL345AccActive() ) {
        InitADXL345Acc();
        AccelerometerType = ADXL345Acc;

    } else
        if ( LISLAccActive() ) {
            InitLISLAcc();
            AccelerometerType = LISLAcc;
        } else
            // check for other accs in preferred order
        {
            AccelerometerType = AccUnknown;
            F.AccelerationsValid = false;
        }

    if ( F.AccelerationsValid ) {
        LEDYellow_ON;
        GetNeutralAccelerations();
        LEDYellow_OFF;
    } else
        F.AccFailure = true;
} // InitAccelerometers

//________________________________________________________________________________________

// ADXL345 3 Axis Accelerometer

void ReadADXL345Acc(void);
void InitADXL345Acc(void);
boolean ADXL345AccActive(void);

void ReadADXL345Acc(void) {

    static uint8 a;
    static char b[6];
    static i16u X, Y, Z;
    static real32 d;

    I2CACC.start();
    if ( I2CACC.write(ADXL345_WR) != I2C_ACK ) goto ADXL345Error; // point to acc data
    if ( I2CACC.write(0x32) != I2C_ACK ) goto ADXL345Error; // point to acc data
    I2CACC.stop();

    if ( I2CACC.blockread(ADXL345_ID, b, 6) ) goto ADXL345Error;

    X.b1 = b[1];
    X.b0 = b[0];
    Y.b1 = b[3];
    Y.b0  =b[2];
    Z.b1 = b[5];
    Z.b0 = b[4];

    if ( F.Using9DOF ) { // SparkFun/QuadroUFO 9DOF breakouts pins forward components up
        AccADC[BF] = -Y.i16;
        AccADC[LR] = -X.i16;
        AccADC[UD] = -Z.i16;
    } else {// SparkFun 6DOF breakouts pins forward components down
        AccADC[BF] = -X.i16;
        AccADC[LR] = -Y.i16;
        AccADC[UD] = Z.i16;
    }

    for ( a = 0; a < (int8)3; a++ ) {
        d = fabs(AccADC[a]-AccADCp[a]);
        if ( d>AccNoise[a] ) AccNoise[a] = d;
    }

    return;

ADXL345Error:
    I2CACC.stop();

    I2CError[ADXL345_ID]++;
    if ( State == InFlight ) {
        Stats[AccFailS]++;    // data over run - acc out of range
        // use neutral values!!!!
        F.AccFailure = true;
    }

} // ReadADXL345Acc

void InitADXL345Acc() {

    I2CACC.start();
    if ( I2CACC.write(ADXL345_WR) != I2C_ACK ) goto ADXL345Error;;
    if ( I2CACC.write(0x2D) != I2C_ACK ) goto ADXL345Error;  // power register
    if ( I2CACC.write(0x08) != I2C_ACK ) goto ADXL345Error;  // measurement mode
    I2CACC.stop();

    Delay1mS(5);

    I2CACC.start();
    if ( I2CACC.write(ADXL345_WR) != I2C_ACK ) goto ADXL345Error;
    if ( I2CACC.write(0x31) != I2C_ACK ) goto ADXL345Error;  // format
    if ( I2CACC.write(0x08) != I2C_ACK ) goto ADXL345Error;  // full resolution, 2g
    I2CACC.stop();

    Delay1mS(5);

    I2CACC.start();
    if ( I2CACC.write(ADXL345_WR) != I2C_ACK ) goto ADXL345Error;
    if ( I2CACC.write(0x2C) != I2C_ACK ) goto ADXL345Error;  // Rate
    if ( I2CACC.write(0x09) != I2C_ACK ) goto ADXL345Error;  // 50Hz, 400Hz 0x0C
    I2CACC.stop();

    Delay1mS(5);

    return;

ADXL345Error:
    I2CACC.stop();

    I2CError[ADXL345_ID]++;

} // InitADXL345Acc

boolean ADXL345AccActive(void) {

    F.AccelerationsValid = I2CACCAddressResponds(ADXL345_ID);

    if ( F.AccelerationsValid)
        TrackMinI2CRate(400000);

    return( F.AccelerationsValid );

} // ADXL345AccActive

//________________________________________________________________________________________

// LIS3LV02DG Accelerometer 400KHz

boolean WriteLISL(uint8, uint8);
void ReadLISLAcc(void);
void InitLISLAcc(void);
boolean LISLAccActive(void);

void ReadLISLAcc(void) {

    static uint8 a;
    static real32 d;
    static char b[6];
    static i16u X, Y, Z;

    F.AccelerationsValid = I2CACCAddressResponds( LISL_ID ); // Acc still there?

    if ( !F.AccelerationsValid ) goto LISLError;

    I2CACC.start();
    if ( I2CACC.write(LISL_WR) != I2C_ACK ) goto LISLError;
    if ( I2CACC.write(LISL_OUTX_L | 0x80 ) != I2C_ACK ) goto LISLError; // auto increment address
    I2CACC.stop();

    if ( I2CACC.blockread(LISL_RD, b, 6) ) goto LISLError;

    X.b1 = b[1];
    X.b0 = b[0];
    Y.b1 = b[3];
    Y.b0 = b[2];
    Z.b1 = b[5];
    Z.b0 = b[4];

    // UAVP Breakout Board pins to the rear components up
    AccADC[BF] = Y.i16;
    AccADC[LR] = X.i16;
    AccADC[UD] = -Z.i16;

    for ( a = 0; a < (int8)3; a++ ) {
        d = fabs(AccADC[a]-AccADCp[a]);
        if ( d>AccNoise[a] ) AccNoise[a] = d;
    }

    return;

LISLError:
    I2CACC.stop();

    I2CError[LISL_ID]++;

    if ( State == InFlight ) {
        Stats[AccFailS]++;    // data over run - acc out of range
        // use neutral values!!!!
        F.AccFailure = true;
    }

} // ReadLISLAccelerometers

boolean WriteLISL(uint8 d, uint8 a) {

    I2CACC.start();
    if ( I2CACC.write(LISL_WR) != I2C_ACK ) goto LISLError;
    if ( I2CACC.write(a) != I2C_ACK ) goto LISLError;
    if ( I2CACC.write(d) != I2C_ACK ) goto LISLError;
    I2CACC.stop();

    return(false);

LISLError:
    I2CACC.stop();

    I2CError[LISL_ID]++;

    return(true);

} // WriteLISL

void InitLISLAcc(void) {

    if ( WriteLISL(0x4a, LISL_CTRLREG_2) ) goto LISLError; // enable 3-wire, BDU=1, +/-2g
    if ( WriteLISL(0xc7, LISL_CTRLREG_1) ) goto LISLError; // on always, 40Hz sampling rate,  10Hz LP cutoff, enable all axes
    if ( WriteLISL(0, LISL_CTRLREG_3) ) goto LISLError;
    if ( WriteLISL(0x40, LISL_FF_CFG) ) goto LISLError;    // latch, no interrupts;
    if ( WriteLISL(0, LISL_FF_THS_L) ) goto LISLError;
    if ( WriteLISL(0xFC, LISL_FF_THS_H) ) goto LISLError;  // -0,5g threshold
    if ( WriteLISL(255, LISL_FF_DUR) ) goto LISLError;
    if ( WriteLISL(0, LISL_DD_CFG) ) goto LISLError;

    TrackMinI2CRate(400000);
    F.AccelerationsValid = true;

    return;

LISLError:
    F.AccelerationsValid = false;

} // InitLISLAcc

boolean LISLAccActive(void) {

    F.AccelerationsValid = I2CACCAddressResponds( LISL_ID );

    return ( F.AccelerationsValid );

} // LISLAccActive