Quad X Type Multicopter

Dependencies:   IAP

main.cpp

Committer:
komaida424
Date:
2013-11-15
Revision:
2:59ac9df97701
Parent:
0:cca1c4e84da4
Child:
3:27407c4984cf

File content as of revision 2:59ac9df97701:

#include "mbed.h"
#include "math.h"
#include "I2cPeripherals.h"
#include "InterruptIn.h"
#include "config.h"
#include "PulseWidthCounter.h"
#include "string"
#include "SerialLcd.h"
#include  "IAP.h"
#include "PID.h"
#include "SoftPWM.h"

//Serial pc(USBTX, USBRX); 

//Gravity at Earth's surface in m/s/s
#define g0 9.812865328
//Convert from radians to degrees.
#define toDegrees(x) (x * 57.2957795)
//Convert from degrees to radians.
#define toRadians(x) (x * 0.01745329252)
//ITG-3200 sensitivity is 14.375 LSB/(degrees/sec).
#define GYROSCOPE_GAIN (1 / 14.375)
//Full scale resolution on the ADXL345 is 4mg/LSB.
#define ACCELEROMETER_GAIN (0.004 * g0)
//Updating filter at 40Hz.
#define FILTER_RATE 0.05
//At rest the gyroscope is centred around 0 and goes between about
//-5 and 5 counts. As 1 degrees/sec is ~15 LSB, error is roughly
//5/15 = 0.3 degrees/sec.

#ifdef TARGET_LPC1114   // LPC1114
//    PulseOut pwm[4] = { dp1,dp2,dp18,dp24 );
    #define LED1 dp28
    #define p5 dp4
    #define p6 dp9
    #define p7 dp10
    #define p8 dp11
    #define p9 dp25
    #define p10 dp26
    #define p13 dp16
    #define p21 dp1
    #define p22 dp2
    #define p23 dp18
    #define p24 dp24
    #define p27 dp27
    #define p28 dp5
#else                   //LPC1768
    #ifdef LPCXpresso
        #define LED1 P0_22
    #endif
#endif
DigitalInOut pwmpin[] = { p21,p22,p23,p24 };
DigitalOut led1(LED1);
DigitalOut led2(LED2);
InterruptIn ch1(p5);
PulseWidthCounter ch[5] = { p6,p7,p8,p9,p10 };
#if defined(SOFT_PWM) || defined(TARGET_LPC1114)
SoftPWM pwm[4] = { p21,p22,p23,p24 };
#else
PwmOut pwm[4] = { p21,p22,p23,p24 };
#endif
SoftPWM buzz(p26);
Timer CurTime;
//Timer ElapTime;
Timer CycleTime;
Timer FlyghtTime;
//Ticker tick;
//Ticker tick100ms;
//Ticker mixTime;
I2cPeripherals i2c(p28,p27); //sda scl
SerialLcd lcd(p13);
config conf;
PID pid[3];
#ifdef TARGET_LPC1114
//LPC1114 Flash Memory read/write
    #define MEM_SIZE        256
    #define TARGET_SECTOR   7     //  use sector 29 as target sector if it is on LPC1768
#else
//LPC1768 Flash Memory read/write
    #define MEM_SIZE        256
    #define TARGET_SECTOR   29     //  use sector 29 as target sector if it is on LPC1768
#endif
#ifndef LocalFileOut
IAP iap;
#endif
float TotalTime = 0;;
int channel = 0;
//int intrupt_cnt = 0;
//int intrupt_cnt2 = 0;
volatile int CH[5];
volatile int M[6];
volatile float Gyro[3];
volatile float Accel[3];
volatile float Angle[3];
volatile float Gyro_Ref[3];
volatile float Gyro_Save[3];
volatile int Stick[5];
volatile int Stick_Save[3];
//int Stick_Max[3];
float Press;
char InPulseMode;               //Receiver Signal Type    's':Serial, 'P':Parallel
//volatile bool tick_flag;
//volatile bool buzz_flag;
float interval;
int pid_reg[3];
int loop_cnt;

void initialize();
void FlashLED(int );
void SetUp();
void SetUpPrompt(config&,I2cPeripherals&);
void PWM_Out(bool);
void Get_Stick_Pos();
void CalibrateGyros(void);
void CalibrateAccel(void);
void Get_Gyro();
bool Get_Accel();
void Get_Angle(float);
void ReadConfig();
void WriteConfig();
void Interrupt_Check(bool&,int &,DigitalOut &);
void ESC_SetUp(void);
void Flight_SetUp();
//void IMUfilter_Reset(void);
void LCD_printf(char *);
void LCD_cls();
void LCD_locate(int,int);
/*
void tick_interrupt()
{
    tick_flag = true;    
}
*/
void PulseCheck()
{
    channel++;
}

void PulseAnalysis()            //Interrupt Pin5
{
    CurTime.stop();
    int PulseWidth =  CurTime.read_us();
    CurTime.reset();
    CurTime.start();
    if ( PulseWidth > 3000 ) channel = 0;      //reset pulse count
    else {
        if ( PulseWidth > Pulse_Min && PulseWidth < Pulse_Max ) {
            switch( channel ) {
                case IR_THR:
                    THR = PulseWidth;
                    break;
                case IR_AIL:
                    AIL = PulseWidth;
                    break;
                case IR_ELE:
                    ELE = PulseWidth;
                    break;
                case IR_RUD:
                    RUD = PulseWidth;
                    break;
                case IR_AUX:
                    AUX = PulseWidth;
                    break;
            }
        }
    }
    channel++;
}

int main()
{
    int i=0;
    
    wait(0.5);
    initialize();

    Get_Stick_Pos();
    while (  Stick[COL] > Thro_Zero || conf.StartMode == 'C' )          //Shrottol Low
    {
        if ( Stick[COL] > 890 && -Stick[YAW] < Stick_Limit )              // Shrottle High
            ESC_SetUp();
        if ( Stick[COL] > 890 || conf.StartMode == 'C' )              // Shrottle High
        {
            loop_cnt = 0;
            SetUpPrompt(conf,i2c);
            break;
        }
        FlashLED(3);
        wait(0.3);
        Get_Stick_Pos();
    }
    Flight_SetUp();
    while (1)
    {
        if ( Stick[COL] < Thro_Zero )
        {
            i = 0;
            while ( Stick[YAW] < -Stick_Limit && Stick[COL] < Thro_Zero )      //Rudder Left
            {
                if ( i > 100 )                          //wait 2 sec
                {
                    FlyghtTime.stop();
                    if ( Stick[PIT] < -Stick_Limit )    {       //Elevetor Down
                        loop_cnt = 0;
                        FlashLED(5);
                        for ( i=0;i<4;i++ ) pwm[i].pulsewidth_us(Pulse_Min);
                        i2c.start(conf.LCD_Contrast);
                        SetUpPrompt(conf,i2c);
                    }                   
                    CalibrateGyros();
                    Flight_SetUp();
                    break;
                }
                wait(0.01);                           // wait 10 msec
                Get_Stick_Pos();
                i++;
            }
        }
        PWM_Out(true);
    }

}

void  initialize()
{
    buzz.period_us(500);
    ReadConfig();               //config.inf file read

    i2c.start(conf.LCD_Contrast);
    channel = 0;
    ch1.rise(&PulseCheck);      //input pulse count
    wait(0.2);
    if ( channel > 50 )    {
        ch1.rise(&PulseAnalysis);
        InPulseMode = 'S';
    }
    else InPulseMode = 'P';
    led1 = 0;
    CycleTime.start();
    for ( int i=0;i<4;i++ ) pwm[i].period_us(conf.PWM_Interval);
    FlashLED(3);
}

void FlashLED(int cnt)
{
    for ( int i = 0 ; i < cnt ; i++ ) {
        led1 = !led1;
        buzz = 0.5f;
        wait(0.1);
        led1 = !led1;
        buzz = 0.0f;
        wait(0.1);
    }
}

void ReadConfig()
{
#ifdef LocalFileOut
    LocalFileSystem local("local");               // Create the local filesystem under the name "local"
    FILE *fp = fopen("/local/setup.inf", "rb");  // Open "out.txt" on the local file system for writing
    if ( fp != NULL )  {
        float rev = conf.Revision;
        int len = fread(&conf,1,sizeof(config),fp);
        switch ( len ) {
            case  sizeof(config):    // File size ok
                if ( rev == conf.Revision ) break;
            default:
                fclose(fp);
                config init;
                conf = init;
                fp = fopen("/local/setup.inf", "wb");
                fwrite(&conf,1,sizeof(config),fp);
        }
        fclose(fp);
    } else  {
        WriteConfig();
        wait(2);
    }
#else
    char *send;
    char *recv;
    int i,rc;
    config *conf_ptr;
    
    if ( sizeof(config) > 255 ) {
        LCD_printf("config size over");
        wait(3);
        return;
    }
    rc = iap.blank_check( TARGET_SECTOR, TARGET_SECTOR );
    if ( rc == SECTOR_NOT_BLANK ) {
        send = sector_start_adress[TARGET_SECTOR];
        recv = (char*)&conf;
        conf_ptr = (config*)sector_start_adress[TARGET_SECTOR];
        if ( conf_ptr->Revision == conf.Revision && conf_ptr->Struct_Size == sizeof(config) ) {
            for ( i=0;i<sizeof(config);i++ ) recv[i] = send[i];
            return;
        }
    }
    WriteConfig();
#endif
}

void WriteConfig()
{
#ifdef LocalFileOut
    LocalFileSystem local("local");               // Create the local filesystem under the name "local"
    FILE *fp = fopen("/local/setup.inf", "wb");
    fwrite(&conf,1,sizeof(config),fp);
    fclose(fp);
#else
    char mem[MEM_SIZE];
    char *send;
    int i;
    if ( sizeof(config) > 255 ) {
        LCD_printf("config size over");
        wait(3);
        return;
    }
    send = (char*)&conf;
    for ( i=0;i<sizeof(config);i++ ) mem[i] = send[i];
    for ( i=sizeof(config);i<MEM_SIZE;i++ ) mem[i] = 0x00;
    iap.prepare( TARGET_SECTOR, TARGET_SECTOR );
    iap.erase( TARGET_SECTOR, TARGET_SECTOR );
//pc.printf("erase\n");
    iap.prepare( TARGET_SECTOR, TARGET_SECTOR );
    iap.write( mem, sector_start_adress[ TARGET_SECTOR ], MEM_SIZE );
//pc.printf("write\n");
#endif
}

void Get_Stick_Pos(void)
{
    if ( InPulseMode == 'P' ) {
        for (int i=0;i<5;i++) CH[i] = ch[i].count;
    }
//    Stick_Save[ROL] = Stick[ROL];
//    Stick_Save[PIT] = Stick[PIT];
//    Stick_Save[YAW] = Stick[YAW];
    
    Stick[ROL] = AIL - conf.Stick_Ref[ROL];
    Stick[PIT] = ELE - conf.Stick_Ref[PIT];
    Stick[YAW] = RUD - conf.Stick_Ref[YAW];
    Stick[COL] = THR - conf.Stick_Ref[COL];
    Stick[GAIN] = ( AUX - conf.Stick_Ref[GAIN] ) / 4;
}

void Get_Gyro()
{
    float x,y,z;
    bool err;
    Gyro_Save[ROL] = Gyro[ROL];
    Gyro_Save[PIT] = Gyro[PIT];
    Gyro_Save[YAW] = Gyro[YAW];
    
    if ( conf.Gyro_Dir[3] ==1 ) err=i2c.angular(&x,&y,&z);
    else err=i2c.angular(&y,&x,&z);
    if ( err == false ) return;
    Gyro[ROL] = x - Gyro_Ref[0] ;
    Gyro[PIT] = y - Gyro_Ref[1] ;
    Gyro[YAW] = z - Gyro_Ref[2] ;
    
    if ( fabs(Gyro[ROL]) > 300.0 ) Gyro[ROL] = Gyro_Save[ROL];
    if ( fabs(Gyro[PIT]) > 300.0 ) Gyro[PIT] = Gyro_Save[PIT];
    if ( fabs(Gyro[YAW]) > 300.0 ) Gyro[YAW] = Gyro_Save[YAW];       
}

bool Get_Accel()
{
    float x,y,z;
    bool err;
    if ( conf.Gyro_Dir[3] ==1 ) err=i2c.Acceleration(&x,&y,&z);
    else err=i2c.Acceleration(&y,&x,&z);
    if ( err == false ) return false;
    float wx = x - conf.Accel_Ref[0];
    float wy = y - conf.Accel_Ref[1];
    float wz = z - conf.Accel_Ref[2];
    Accel[ROL] = atan(wx/sqrt( pow(wy,2)+pow(wz,2)))*180/3.14;
    Accel[PIT] = atan(wy/sqrt( pow(wx,2)+pow(wz,2)))*180/3.14;
    Accel[YAW] = atan(sqrt( pow(wx,2)+pow(wy,2))/wz)*180/3.14;      
    return true;  
}

void Get_Angle(float interval)
{
    Get_Gyro();
    Get_Accel();
    float x,y,z;

    x = ( (Gyro[ROL] + Gyro_Save[ROL]) ) * 0.5;
    y = ( (Gyro[PIT] + Gyro_Save[PIT]) ) * 0.5;
    z = ( (Gyro[YAW] + Gyro_Save[YAW]) ) * 0.5;
    if ( Get_Accel() == true )  {
        float i =  3.14 * 2 * conf.Cutoff_Freq * interval;
        Angle[ROL] += -Angle[ROL] * i + Accel[ROL] * i + x * interval;
        Angle[PIT] += -Angle[PIT] * i + Accel[PIT] * i + y * interval;
    }
    else    {
        Angle[ROL] += x * interval;
        Angle[PIT] += y * interval;
    }
    Angle[YAW] += z * interval;
}

void Get_Pressure()
{
    Press = i2c.pressure();
}

void CalibrateGyros(void)
{
    int i;
    float x,y,z;
    float k[3]={0,0,0};
    wait(1);
    Angle[0]=Angle[1]=Angle[2]=0;
    for(i=0; i<16; i++) {
        if ( conf.Gyro_Dir[3] ==1 ) i2c.angular(&x,&y,&z);
        else i2c.angular(&y,&x,&z);
        k[0] += x;
        k[1] += y;
        k[2] += z;
        wait(0.01);
    }
    for( i=0; i<3; i++ ) Gyro_Ref[i] = k[i]/16;
//    FlashLED(3);
}

void CalibrateAccel(void)
{
    int i;
    float x,y,z;
    float k[3]={0,0,0};
    conf.Accel_Ref[0]=conf.Accel_Ref[1]=conf.Accel_Ref[2]=0;
    for(i=0; i<16; i++) {
        if ( conf.Gyro_Dir[3] ==1 ) i2c.Acceleration(&x,&y,&z);
        else i2c.Acceleration(&y,&x,&z);
        k[0] += x;
        k[1] += y;
        k[2] += z;
        wait(0.01);
    }
    conf.Accel_Ref[0] = k[0]/16;       
    conf.Accel_Ref[1] = k[1]/16;
    conf.Accel_Ref[2] = k[2]/16-9.8;
//    FlashLED(3);
}

void PWM_Out(bool mode)
{
   int reg[3];
    int i;
    float gain;
    
    Get_Stick_Pos();
    M1 = M2 = M3 = M4 = Stick[COL];
    interval = CycleTime.read();
    CycleTime.reset();
    if ( interval > 0.1 ) return;
    TotalTime += interval;
    if ( TotalTime > 0.5 )    {
        led1 = !led1; 
        if ( ( !buzz ) && ( (float)conf.Flight_Time < FlyghtTime.read() ) ) buzz=0.5f;
        else buzz=0.0;
        TotalTime = 0;
    }
    
    Get_Angle(interval);
    
    for ( i=0;i<3;i++ ) {
            
//      Stick Angle Mixing
        if ( conf.Gyro_Gain_Setting == 1 ) gain = conf.Gyro_Gain[i] * conf.Gyro_Dir[i];
        else gain = ( (float)abs(Stick[GAIN])/100 + conf.Gyro_Gain[i+3] ) * conf.Gyro_Dir[i];
        if ( Stick[GAIN] > 0 
//            || i == YAW 
//            || (fabsf)(Angle[i]) > conf.Control_Exchange_Angle 
            )  {
            reg[i] = Stick[i] * conf.Stick_Mix[i];
            reg[i] += Gyro[i] * gain * GYRO_ADJUST;
        }
        else   {
            if ( (i == YAW) || (i2c.GetAddr(ACCEL_ADDR)==0) )   {
                if ( abs(Stick_Save[i]) <= abs(Stick[i]>>2) )   {
                    Stick_Save[i] = Stick[i]>>2;
                }
                else    {
//                    pc.printf("PID RESET.%3d",i);wait(1);
                    Stick_Save[i] = 0;
                    pid[i].reset();
                    Angle[i] = 0;
                }
            } 
            reg[i] = Stick[i] * conf.Stick_Mix[i];
            reg[i] += pid[i].calc(Angle[i],0,interval);
//            reg[i] = pid[i].calc(Angle[i],-(float)Stick[i]*60/400,interval);
        }
        pid_reg[i] = reg[i];
    }
    //Calculate Roll Pulse Width
    M1 += reg[ROL];
    M2 -= reg[ROL];
    M3 -= reg[ROL];
    M4 += reg[ROL];

    //Calculate Pitch Pulse Width
    M1 += reg[PIT];
    M2 += reg[PIT];
    M3 -= reg[PIT];
    M4 -= reg[PIT];

    //Calculate Yaw Pulse Width
    M1 -= reg[YAW];
    M2 += reg[YAW];
    M3 -= reg[YAW];
    M4 += reg[YAW];
    
    for ( i=0;i<4;i++ )
    {
//        if ( Stick[COL] > 150 && M[i] < 150 )   M[i] = 150; 
        if ( M[i] > Thro_Hi )   M[i] = Thro_Hi; 
        if ( M[i] < Thro_Lo )   M[i] = Thro_Lo;     // this is the motor idle level
    }
    
    if (Stick[COL] < Thro_Zero ) M1=M2=M3=M4=0;
    
    if ( mode ) {
        for ( i=0;i<4;i++ ) {
           while ( !pwmpin[i] );
           if ( conf.PWM_Mode == 1 )
                pwm[i].pulsewidth_us(conf.ESC_Low+M[i]);
           else pwm[i].pulsewidth_us(M[i]);
        }
    }
        
}

void ESC_SetUp(void)    {
    while(1)    {
        Get_Stick_Pos();
        for ( int i=0;i<4;i++ ) pwm[i].pulsewidth_us(conf.Stick_Ref[COL]+Stick[COL]);
        wait(0.015);
    }
}

void Flight_SetUp(void)
{
    int i;
    for ( i=0;i<4;i++ ) pwm[i].pulsewidth_us(0);
    for ( i=0;i<4;i++ ) pwm[i].period_us(conf.PWM_Interval);
    for ( i=0;i<4;i++ ) pwm[i].pulsewidth_us(Pulse_Min);
    for ( i=0;i<4;i++ ) pid[i].init(conf.kp[i],conf.ki[i],conf.kd[i]*(float)abs(Stick[GAIN])*0.02
                                            ,conf.PID_Limit,conf.Integral_Limit);
    Angle[ROL]=Angle[PIT]=Angle[YAW]=0;
    loop_cnt = 0;
    FlyghtTime.start();
    CycleTime.start();
    FlashLED(5);
}

void LCD_locate(int clm,int row)
{
    lcd.locate(clm,row);
    i2c.locate(clm,row);
}

void LCD_cls()
{
    lcd.cls();
    i2c.cls();
}

void LCD_printf(char* str)
{
    lcd.printf(str);
    i2c.printf(str);
}
;