For Cansat EM

Dependencies:   IMU_I2C IMUfilter SCP1000 SDFileSystem mbed nmea0813 myCAN_logger

main.cpp

Committer:
YSB
Date:
2013-08-16
Revision:
4:008160161171
Parent:
2:137282f468d0

File content as of revision 4:008160161171:

#include "mbed.h"
#include "SDFileSystem.h"
#include "IMUfilter.h"
#include "IMU_I2C.h"
#include "nmea0813.h"
#include "SCP1000.h"
#include "myCAN.h"
#include "IDDATA.h"

//for debug
    DigitalOut myled(LED1);
    Serial pc(USBTX, USBRX);
    Ticker pc_msg;
//for logging
    SDFileSystem sd(p5, p6, p7, p8, "sd");
    DigitalIn SD(p17);
    IMUfilter imuFilter(FILTER_RATE, 0.3);
    IMU_I2C accelerometer(p9, p10);
    GPS gps(p28,p27);
    DigitalOut gps_permission(p26);
    SCP1000 scp1000(p11,p12,p13,p21);
    DigitalOut scp1000_permission(p20);
    Ticker accelerometerTicker;
    Ticker gyroscopeTicker;
    Ticker filterTicker;
    Ticker logging;
//for communication with mission_mbed
    myCAN can(p30, p29);
    Ticker can_msg;

//for pc_msg
    #define PC_BAUD 9600
    #define PC_RATE 0.3
    void pc_flg_on(void);
    char pc_flg = 0;
//for logging
    #define LOG_RATE 0.3//0.04
    char log_flg;
    void log_flg_on(void);
//for can_msg
    #define CAN_RATE 0.1
    void can_flg_on(void);
    char can_flg = 0;

//Offsets for the gyroscope and the accelerometer.
    double w_xBias;
    double w_yBias;
    double w_zBias;
    double a_xBias;
    double a_yBias;
    double a_zBias;

//Accumulators used for oversampling and then averaging.
    volatile double a_xAccumulator = 0;
    volatile double a_yAccumulator = 0;
    volatile double a_zAccumulator = 0;
    volatile double w_xAccumulator = 0;
    volatile double w_yAccumulator = 0;
    volatile double w_zAccumulator = 0;

//Accelerometer and gyroscope readings for x, y, z axes.
    volatile double a_x;
    volatile double a_y;
    volatile double a_z;
    volatile double w_x;
    volatile double w_y;
    volatile double w_z;

//Buffer for accelerometer readings.
int readings[3];
//Number of accelerometer samples we're on.
int accelerometerSamples = 0;
//Number of gyroscope samples we're on.
int gyroscopeSamples = 0;

//Prototypes
void initializeAcceleromter(void);//Set up the ADXL345 appropriately.
void calibrateAccelerometer(void);//Calculate the null bias.
void sampleAccelerometer(void);//Take a set of samples and average them.
void initializeGyroscope(void);//Set up the ITG3200 appropriately.
void calibrateGyroscope(void);//Calculate the null bias.
void sampleGyroscope(void);//Take a set of samples and average them.
void filter(void);//Update the filter and calculate the Euler angles.
void IMU_Init(void);

void initializeAccelerometer(void) {
    //Go into standby mode to configure the device.
    accelerometer.setPowerControl(0x00);
    //Full resolution, +/-16g, 4mg/LSB.
    accelerometer.setDataFormatControl(0x0B);
    //200Hz data rate.
    accelerometer.setDataRate(ADXL345_200HZ);
    //Measurement mode.
    accelerometer.setPowerControl(0x08);
    //See http://www.analog.com/static/imported-files/application_notes/AN-1077.pdf
    wait_ms(22);
}

void sampleAccelerometer(void) {
    //Have we taken enough samples?
    if (accelerometerSamples == SAMPLES) {
        //Average the samples, remove the bias, and calculate the acceleration
        //in m/s/s.
        a_x = ((a_xAccumulator / SAMPLES) - a_xBias) * ACCELEROMETER_GAIN;
        a_y = ((a_yAccumulator / SAMPLES) - a_yBias) * ACCELEROMETER_GAIN;
        a_z = ((a_zAccumulator / SAMPLES) - a_zBias) * ACCELEROMETER_GAIN;

        a_xAccumulator = 0;
        a_yAccumulator = 0;
        a_zAccumulator = 0;
        accelerometerSamples = 0;
    } else {
        //Take another sample.
        accelerometer.getOutput(readings);

        a_xAccumulator += (int16_t) readings[0];
        a_yAccumulator += (int16_t) readings[1];
        a_zAccumulator += (int16_t) readings[2];

        accelerometerSamples++;
    }
}

void calibrateAccelerometer(void) {
    a_xAccumulator = 0;
    a_yAccumulator = 0;
    a_zAccumulator = 0;
    
    for (int i = 0; i < CALIBRATION_SAMPLES; i++) {
        accelerometer.getOutput(readings);

        a_xAccumulator += (int16_t) readings[0];
        a_yAccumulator += (int16_t) readings[1];
        a_zAccumulator += (int16_t) readings[2];

        wait(ACC_RATE);
    }
    a_xAccumulator /= CALIBRATION_SAMPLES;
    a_yAccumulator /= CALIBRATION_SAMPLES;
    a_zAccumulator /= CALIBRATION_SAMPLES;

    //At 4mg/LSB, 250 LSBs is 1g.
    a_xBias = a_xAccumulator;
    a_yBias = a_yAccumulator;
    a_zBias = (a_zAccumulator - 250);

    a_xAccumulator = 0;
    a_yAccumulator = 0;
    a_zAccumulator = 0;
}

void initializeGyroscope(void) {
    accelerometer.setLpBandwidth(LPFBW_42HZ);//Low pass filter bandwidth of 42Hz.
    accelerometer.setSampleRateDivider(4);//Internal sample rate of 200Hz. (1kHz / 5).
}

void calibrateGyroscope(void) {
    w_xAccumulator = 0;
    w_yAccumulator = 0;
    w_zAccumulator = 0;

    for (int i = 0; i < CALIBRATION_SAMPLES; i++) {
        w_xAccumulator += accelerometer.getGyroX();
        w_yAccumulator += accelerometer.getGyroY();
        w_zAccumulator += accelerometer.getGyroZ();
        wait(GYRO_RATE);
    }
    //Average the samples.
    w_xAccumulator /= CALIBRATION_SAMPLES;
    w_yAccumulator /= CALIBRATION_SAMPLES;
    w_zAccumulator /= CALIBRATION_SAMPLES;

    w_xBias = w_xAccumulator;
    w_yBias = w_yAccumulator;
    w_zBias = w_zAccumulator;

    w_xAccumulator = 0;
    w_yAccumulator = 0;
    w_zAccumulator = 0;
}

void sampleGyroscope(void) {
    if (gyroscopeSamples == SAMPLES) {
        //velocity in rad/s.
        w_x = toRadians(((w_xAccumulator / SAMPLES) - w_xBias) * GYROSCOPE_GAIN);
        w_y = toRadians(((w_yAccumulator / SAMPLES) - w_yBias) * GYROSCOPE_GAIN);
        w_z = toRadians(((w_zAccumulator / SAMPLES) - w_zBias) * GYROSCOPE_GAIN);

        w_xAccumulator = 0;
        w_yAccumulator = 0;
        w_zAccumulator = 0;
        gyroscopeSamples = 0;
    } else {
        w_xAccumulator += accelerometer.getGyroX();
        w_yAccumulator += accelerometer.getGyroY();
        w_zAccumulator += accelerometer.getGyroZ();

        gyroscopeSamples++;
    }
}

void filter(void) {
    imuFilter.updateFilter(w_y, w_x, w_z, a_y, a_x, a_z);//Update the filter variables.
    imuFilter.computeEuler();//Calculate the new Euler angles.
}

void IMU_Init(void){
    initializeAccelerometer();
    calibrateAccelerometer();
    initializeGyroscope();
    calibrateGyroscope();

    accelerometerTicker.attach(&sampleAccelerometer, 0.005);//Accelerometer data rate is 200Hz, so we'll sample at this speed.
    gyroscopeTicker.attach(&sampleGyroscope, 0.005);//Gyroscope data rate is 200Hz, so we'll sample at this speed.
    filterTicker.attach(&filter, FILTER_RATE);//Initialize inertial sensors.
}

void pc_flg_on(void){
    pc_flg = 1;
}

void can_flg_on(void){
    can_flg = 1;
}

void log_flg_on(void){
    log_flg = 1;
}

int main() {
    gps_permission = 1;//off
    scp1000_permission = 1;//off
    
    IMU_Init();
    
    a_xBias=0;
    a_yBias=0;
    a_zBias=0;
    w_xBias=0;
    w_yBias=0;
    w_zBias=0;
    
    //wait(1.0);
    
    myled = 1;
    gps_permission = 0;//on
    scp1000_permission = 0;//on
    scp1000.init_scp1000();
    
    //for PC
        pc.baud(PC_BAUD);
        pc_msg.attach(&pc_flg_on,PC_RATE);
        
    //for CAN
        can_msg.attach(&can_flg_on,CAN_RATE);
    
    //for logging
        logging.attach(&log_flg_on,LOG_RATE);
    
    int roll,pitch;
    float g;
    roll = 0;
    pitch = 0;
    
    while(1){
        //for can send
            if(can_flg == 1){
                g = sqrt(a_x*a_x + a_y*a_y + a_z*a_z);
                roll = (int)(acos(a_y/g)*180/3.1415926535 - 90.0); 
                pitch = (int)(acos(a_x/g)*180/3.1415926535 - 90.0); 
                if(roll<0){roll=roll+360.0;}
                if(a_z<0){roll=-1*roll+180.0;} 
                if(roll<0){roll=roll+360.0;}
                can.make_logger_senddata(gps.get_time(),gps.get_satelite_number(),gps.get_str_latitude(),gps.get_str_longitude(),roll,pitch,(int)(scp1000.readTemperature()*20),scp1000.readPressure());
                can.send(LOGGER);
                can_flg = 0;
            }
        //for logging
            if(log_flg == 1){
                if(SD == 1){
                    mkdir("/sd/mydir", 0777);
                    FILE *fp = fopen("/sd/mydir/ver2.txt", "a");
                    if(fp == NULL){
                        //error("Could not open file for write\n");
                        pc.printf("SD_error");
                    }else{
                        fprintf(fp,"%s,%f,%f,",gps.get_time(),gps.get_latitude(),gps.get_longitude());
                        fprintf(fp,"%c,%d,%f,",gps.get_status(),gps.get_satelite_number(),gps.get_speed());
                        fprintf(fp,"%d,%f,", scp1000.readPressure(), scp1000.readTemperature());
                        fprintf(fp,"%f,%f,%f,%f,%f,%f,",w_y, w_x, w_z, a_y, a_x, a_z);
                        fprintf(fp,"%d,%d,",roll,pitch);
                        fprintf(fp,"%d",can.get_mission_status());
                        fprintf(fp,"\r\n",can.get_mission_status());
                        fclose(fp);
                    }
                }
            }
        
        //for pc debug
            if(pc_flg == 1){
                //pc.printf("%f,%f,%f,%f,%f,%f\r\n",w_y, w_x, w_z, a_y, a_x, a_z);
                pc.printf("%d,%d\r\n",roll,pitch);
                //pc.printf("%f,%f,%f,%f,%f,%f\r\n",a_xBias, a_yBias, a_zBias, w_xBias, w_yBias, w_zBias);
                //pc.printf("pressure:%d,temperature:%f\r\n", scp1000.readPressure(), scp1000.readTemperature());
                //pc.printf("time:%s,latitude:%f,longitude:%f,status:%c,satelite:%d,speed:%f\r\n",gps.get_time(),gps.get_latitude(),gps.get_longitude(),gps.get_status(),gps.get_satelite_number(),gps.get_speed());
                //pc.printf("\n\r");
                pc_flg =0;
            }
    }
}