Dependencies:   mbed Servo LSM9DS1 Clock PidCombine

main.cpp

Committer:
JamB
Date:
2019-04-11
Revision:
0:4cf11edf30cf

File content as of revision 0:4cf11edf30cf:

#include "mbed.h"
#include "LSM9DS1.h"
#include "Servo.h"
#include "clock.h"

#define PI 3.14159
#define DECLINATION -2.44
#define deltat_ 0.004f //250Hz

//Setup Patameters
Servo servo_1(p24); //left servo
Servo servo_2(p25); //right servo
DigitalOut myled(LED1);
Serial pc(USBTX, USBRX);

AnalogIn ain(A0);
AnalogIn ain1(A1);

void Setup()
{
    set_tick_(deltat_);  
}

int main()
{
    Setup();
    //Display Setup
        Timer timer;
        Timer timer2;
     //   int timee =0;
    int i=50;
    int j =0;
   // int begin, end;
    // PID config Roll
    float error=0.0;
    float P =0.0;   //Proportional term 
    float I =0.0;   //Intergral term
    float prevD =0.0;
    //float prevDy=0.0l;
    float D =0.0;   //Derivative term
    float k1 = -0.9776;      //Proportaional PID weight
    float k2 = -0.5656;      //Integral PID
    float k3 = -4.2247;      //Derivative PID
    float PV=0.0;           //Process variable
    float SP=0;         //Set Point (Desired Roll in degerees)
    // PID config Pitch
    float errorp =0.0;   //Proportional term 
    float Pp =0.0;   //Proportional term 
    float Ip =0.0; //Intergral term
    float prevDp =0.0;
    float Dp =0.0;   //Derivative term
    float k1p = -1;        //PID weights
    float k2p = 0.5;
    float k3p = 10;
    float PVp=0.0;       //Process variable
    float SPp=0;       //Set Point    
    //PID combine setup 
    float rollc;
    float pitchc;
    float top;
    float bot;
    float centre;
    float diff;
    //Servo initial conditions
    float range = 0.0005;
    float roll_correct = 0;
    float pitch_correct= 0; //Range 0-1
    float left_servo=0;  
    float right_servo=0;
    servo_1.calibrate(range, 45.0);  
    servo_2.calibrate(range, 45.0);
    //PWM conversion
    float left_scale = 0.01778; //convert degrees to PWM. Assumes linear realtionship (is not). optimised for linearity around neutral.
    float right_scale = -0.01778;
    float left_neutral = 0.39; //neutral position PWM
    float right_neutral = 0.61;  
    //IMU
    LSM9DS1 IMU(p9, p10, 0xD6, 0x3C);//SDA, SDL
    IMU.begin();
    if (!IMU.begin()) {
        pc.printf("Failed to communicate with LSM9DS1.\n");
    }
    IMU.calibrate(0); //If this is set to 1 the Glider will assume it starts level
    
    printf("Start");
    while(1) 
    {
        if(tock())
        {   

            //Attitude     
            while(!IMU.accelAvailable());
            IMU.readAccel();
            float roll = atan2((double)IMU.ax, (double)IMU.az); //swtiched the roll and pitch eqautions round
            float pitch = atan2(-(double)IMU.ay, sqrt((double)IMU.ax * (double)IMU.ax + (double)IMU.az * (double)IMU.az));
            pitch *= 180.0 / PI;
            roll  *= 180.0 / PI;
           // printf("%f  %f\n", roll, pitch);
            
             //If moving up or down adjust the SPp for pitch. Tether should deal with this
            //shift_SPp=IMU.az;//scale with time and shift by 9.81. 
            //SPp+=shift_SPp ; Adjusting the setpoint would require new PID values.
            
            //PID for Roll
            PV =roll; 
            error= PV-SP; //in degrees           
            P = k1*error;
            I += k2*error;
            D = k3*error - prevD; //change in glider's roll in degrees since last sample
            //float N=5.3;
            //D = (k3*error -prevD)*N -(N-1)*prevDy;
            prevD =k3*error;
            //prevDy = D;
            roll_correct = P + I + D ; //Try PID
            //Clamp if PID has saturated integral.
            if(roll_correct<-18 || roll_correct>48) { //Is the PID saturated?
                if(!((k2*error>0)^(roll_correct>0)))  //Is the new intergral contributing to saturation?   
                {
                    I -=k2*error; //Don let accError increase, its saturated
                    roll_correct = P + I + D ; //Update PID
                }
            }
            
            //PID for pitch 
            PVp =pitch; 
            errorp= PVp-SPp; //in degrees           
            Pp = k1p*errorp;
            Ip += k2p*errorp;
            Dp = k3p*errorp - prevDp; //change in glider's roll in degrees since last sample
            prevDp =k3p*errorp;
            pitch_correct = Pp + Ip + Dp ; //Try PID
            //Clamp if PID has saturated integral.
            if(pitch_correct<-18 || pitch_correct>48) { //Is the PID saturated?
                if(!((k2p*errorp>0)^(pitch_correct>0)))  //Is the new intergral contributing to saturation?   
                {
                    Ip -=k2p*errorp; //Don let accError increase, its saturated
                    pitch_correct = Pp + Ip + Dp ; //Update PID
                }
            }
            
            //Update Servos, left and right
            //left_servo = pitch_correct + roll_correct; //Angle deg from -18 to (18)
            //right_servo = pitch_correct +(1 - roll_correct); //Angle deg from -18 to (18)
            
            //Take in the corrects and combine them for Left and Right elevator
                rollc = (roll_correct/2);
                pitchc = (-pitch_correct-15);
                top = rollc+15;
                bot = 15-rollc;
                centre = 15;
                
                while (pitchc != 0)
                {
                    if (pitchc > 0)
                    {
                        if (top<48)
                        {
                            centre = centre+1;
                            pitchc = pitchc-1;
                            top=top+1;
                        }else{
                            pitchc=0;
                        }
                    }else{
                        if (bot>-18)
                        {
                            centre=centre-1;
                            pitchc=pitchc+1;
                            bot=bot-1;
                        }else{
                            pitchc=0;
                        }
                    }
                }
                    
                diff=rollc*2;
                centre=centre;
                
            //Convert to PWM           
            left_servo = left_neutral + (centre + diff) * left_scale;
            right_servo = right_neutral + (centre - diff) * right_scale;
            
            //Saturate outputs(For Safety) -18 to 48deg
            if(left_servo>0.94){left_servo=0.94;}//0.54
            if(left_servo<0.07){left_servo=0.07;}
            if(right_servo>0.93){right_servo=0.93;}
            if(right_servo<0.06){right_servo=0.06;}//0.41
            
            //Output to Servos
            servo_1 = left_servo; //0.07 - 0.59
            servo_2 = right_servo;//0.93 - 0.41
             
                        //timer.reset();
            //timer.start();
           // begin = timer.read_us();   
            //Display
            if (i>0) //5 every second at 250Hz =5Hz (50)
            {
                //pc.printf("(Roll %f)   (Pitch %f)         \r",roll,pitch);
                //pc.printf("%f         %f                \r",roll,pitch);
                pc.printf("%d         %d        %d         %f        %f      %f         %f        %f      %f        %f      %f \r",IMU.ax,IMU.ay,IMU.az,roll, pitch,roll_correct,pitch_correct,left_servo, right_servo, (float)ain.read(), (float)ain1.read());
                //pc.printf("%f         %f        %f\r",P,I,D);
                //pc.printf("%f         %f        %f         %f         %f         %f\r",P,I,D,Pp,Ip,Dp);
                i=0;
            }
            i++;
            j++;   
            //end = timer.read_us();
            //timee=end-begin;
         
        }    
    }
}