ECE 4180 ... Final Design Project

Dependencies:   mbed Hovercraft X_NUCLEO_53L0A1 HC_SR04_Ultrasonic_Library

main.cpp

Committer:
spanda38
Date:
2021-04-23
Revision:
0:8c52f4cf12bd

File content as of revision 0:8c52f4cf12bd:

#include "mbed.h"
#include "Servo.h"
#include "ultrasonic.h"
#include "XNucleo53L0A1.h"
#include "math.h"

//Variable Declaration Centre
Servo propeller(p21);
Servo inflator(p22);
Servo rudder1(p23); //Left Rudder
Servo rudder2(p24); //Right Rudder
void goAutonomous(); //Function Prototype
void command(); // Another Function Prototype
float maxPropellerVal = 0.2;

Serial blue(p13, p14);
DigitalOut shdn(p26);
//I2C sensor pins
#define VL53L0_I2C_SDA   p28
#define VL53L0_I2C_SCL   p27


DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

int deploy = 0; // Disable the System
int flag = 0;

//Low Level Actuation Centre
void speedUp()
{
    if (deploy) {
     if (propeller >= maxPropellerVal)
      { 
       propeller = maxPropellerVal; 
      }  else {
          propeller = propeller + 0.01;
      }
    } else {
        propeller = 0;
    }
}

void speedDown()
{
    if (deploy) {
      if (propeller == 0) 
      { 
       propeller = 0; 
      } else { 
       propeller = propeller - 0.01;
      }
    } else {
        propeller = 0;
     }
}

void ventFull()
{
    for (float i = 0; i < 0.17; i += 0.01)
    {
     inflator = i;
     deploy = 1;
     wait(0.5);
    }
}

void ventCutOff()
{
    inflator = 0;
    propeller = 0;
    rudder1 = 0.5;
    rudder2 = 0.5;
    deploy = 0;
    led1 = 0;
    led2 = 0;
    led3 = 0;
    led4 = 0;
}

void rightTurn()
{
    rudder1 = rudder2;
    if (rudder1 == 1)
     {
         rudder1 = 1;
         rudder2 = 1;
      } else {
       rudder1 = rudder1 + 0.05;
       rudder2 = rudder2 + 0.05;
    }
}

void leftTurn()
{
    rudder1 = rudder2;
    if (rudder1 == 0)
     {
         rudder1 = 0;
         rudder2 = 0;
      } else {
       rudder1 = rudder1 - 0.05;
       rudder2 = rudder2 - 0.05;
    }
}

void ledFlashers()
{
    led1 = !led1;
    wait(0.2);
    led2 = !led2;
    wait(0.1);
    led3 = !led3;
    wait(0.1);
    led4 = !led4;
    wait(0.2);
}

//Contingency Trigger...

static XNucleo53L0A1 *board=NULL;
DevI2C *device_i2c = new DevI2C(VL53L0_I2C_SDA, VL53L0_I2C_SCL);
int status;
uint32_t dist;
int old_dist = 0;
int warning = 0;

void distance()
{
    status = board->sensor_centre->get_distance(&dist);
     // If less than 10 cm cut off power sound the alarm flash the LEDS!
     if (dist < 100 && dist != 0 && old_dist < 100 && old_dist != 0) { //No eroneous Warnings
         warning = 1;
     } else {
         warning = 0;
         led1 = 0;
         led2 = 0;
         led3 = 0;
         led4 = 0;
     }
     if (warning == 1)
    {
        
        propeller = 1;
        inflator = 1;
        flag = 0; // Cut out the Power Plant...
        ventCutOff();
        ledFlashers();
    }
    old_dist = dist;
}


    


//Boss Loop
int main()
{
    propeller.calibrate();
    inflator.calibrate();
    rudder1.calibrate();
    rudder2.calibrate();
    
    rudder1 = 0.5;
    rudder2 = 0.5;
    
    //Sensor Set Up
    board = XNucleo53L0A1::instance(device_i2c, A2, D8, D2);
    shdn = 0; 
    wait(0.1);
    shdn = 1;
    wait(0.1);
    status = board->init_board();
    while (status) {
        status = board->init_board();
    }
    
    //End Sensor Set up
    
    while(1)
    {
        distance(); //Check this as much as you want :-)
        if (!flag)
        {
            flag = 1;
            propeller = 1;
            inflator = 1;
            wait(0.5);
            propeller = 0;
            inflator = 0;
        }
        if (blue.readable() && blue.getc() == '!')
        {
            if (blue.getc() == 'B') {
                char bnum = blue.getc();
                if (blue.getc() == '1') 
                {
                 switch(bnum)
                 {
                     case '5' :  speedUp(); break;
                     case '6' :  speedDown(); break;
                     case '1' :  ventFull(); break; //Cushion Deployed
                     case '2' :  ventCutOff();  break; //Cushion Cutoff
                     case '3' :  ventCutOff(); goAutonomous(); break;
                     case '7' :  rightTurn(); break;
                     case '8' :  leftTurn(); break;
                 }
                 blue.getc();
               }
            }
                   
        }

    }
    return 0;
}




float x[4] = {0,0,0,0}; //State Variables.
float u[2][2] = {{0,0}, {0,0}}; //Inputs that translate to rudder and propeller speeds...
float y[4][2] = {{0,0},{0,0},{0,0},{0,0}};  // Log this
int i = 0;
int j = 0;
float I = 1; //You can change this 
//You can modify this as part of a Design Review
//Force parameters
float param1 = 7600; // 7600 RPM/Volt
float param2 = 8659.0135; // Aerodynamic Force
float param3 = 3.3; //Voltage

//Torque Parameters
float param4 = 0.0044;
float param5 = 90; //Range of the servo ... 

void command(float torque, float force)
{
    //The actual place where the force and torque and converted to forms the low level controllers can understand
    float prop_control = force / (param1 * param2 * param3);                   //(propeller * 3.3) * 7600 * 0.00086590135
    float rudder_control = torque / (param4 * param5);                                  //(rudder1.position() * 0.0644); //Torque Value 
    printf("%f \n", prop_control);
    
    //Do a saturation check...
    if (rudder_control > 1)
    {
        rudder1 = rudder2 = 1;
        wait(0.2);
    } else {
        rudder1 = rudder2 = fabs(rudder_control);
        wait(0.6);
    }
    
     wait(0.2);
    
    if (prop_control > maxPropellerVal)
    {
        propeller = 0;
        propeller = maxPropellerVal - 0.04;
    }
    else if (prop_control <= 0) {

        propeller = 0.14;
    } else {
        propeller = prop_control;
    }

} // Done! Enforce the Safety Envelope!
        

void goAutonomous() 
{
    //Sensor Set Up
    while(1)
    {
        distance();
        if (blue.readable() && blue.getc() == '!')
        {
            if (blue.getc() == 'B') {
                char bnum = blue.getc();
                if (blue.getc() == '1' && bnum == '4') 
                {
                    break; //Go back if 4 is pressed!
                }
            }
        }
        
        //Implement the controls aspect here...
        // Get me the output variables...
        //dist is y 
        float T = 0.1;
        float F = (propeller * param3) * param1 * param2; //This is the force
        float tau = (rudder1.read() * param4 * param5); //Torque Value
        float alpha = dist * T + 0.5 * (tau / I) * T * T; //Thats y and alpha ...
 
        int k = (i + 1) % 4;
        y[k][0] = y[i][0];
        y[k][1] = y[i][1];
        y[i][0] =  dist;
        y[i][1] = alpha; //Log in the data
        i = k;
        
        int w = (j + 1) % 2;
        u[w][0] = u[j][0];
        u[w][1] = u[j][1];
        u[j][0] =  dist;
        u[j][1] = alpha; //Log in the data
        j = w;

        
        //Hybrid Control Algorithms ...
        
        if(warning == 1)
        {
            ventCutOff();
        } //Dont move if there is a contingency
        
        if (warning == 0) {
            //There is no obstacle
            //Plow ahead at optimal speed
            //propeller = 0.15; //Fill up the cushions
            if (inflator == 0) {
              ventFull();
            }
            rudder1 = 0.5; //Keep Rudder Positions Straight
            deploy = 1;
            //Move now
            if (propeller != 0.15) {
               if (propeller == 0) {
               propeller = 1;
               propeller = 0;
               }
               wait(0.5);
               propeller = 0.15;
            } 
        } if (dist > 100 && dist < 300 && old_dist > 100 && old_dist < 300) {
            // Now you are in a situation where there is something ahead but not a danger to stop
            // Rover should make some predictive driving and try to turn
            float ref_y = dist + 50;
            float ref_alpha = alpha; //You can change these!
            
            float ref_F;
            float ref_tau; 
            //Need to compute these and set these as the required angles and rotation RPMs to the controllers...
            // You can change the parameters on top if needed! No problems with that...
            // Get the x from there
            
            x[0] = -8.5899 * ref_F + 8.5899 * y[2][0] - 8.5899 * y[3][0];
            x[1] = 0.0307 * ref_F - 0.0234 * y[1][0] - 0.0140 * y[2][0];
            x[2] = -8.5899 * ref_tau + 8.5899 * y[2][1] - 8.5899 * y[3][1];
            x[3] = 0.0307 * ref_tau - 0.0234 * y[1][1] - 0.0140 * y[2][1]; // Least Sq Approx Solution BEST LINEAR UNBIASED ESTIMATOR
   /*      
   -8.5899         0         0         0    8.5899         0   -8.5899         0
    0.0307         0   -0.0234         0   -0.0140         0         0         0   = Observability Matrix Least Sq Approx Matrix
         0   -8.5899         0         0         0    8.5899         0   -8.5899
         0    0.0307         0   -0.0234         0   -0.0140         0         0

    2.8091    0.0127         0         0
         0         0    2.8091    0.0127
   -9.1215    0.0602         0         0
         0         0   -9.1215    0.0602     = Controllability Matrix Least Norm Matrix
   -0.1843    0.0065         0         0
         0         0   -0.1843    0.0065
    6.4967   -0.0132         0         0
         0         0    6.4967   -0.0132
*/
             ref_tau = 0.4967 * x[2] - 0.0132 * x[3];
             ref_F = 6.4967 * x[0] - 0.0132 * x[1];
             command(ref_tau, ref_F); //Computes the values and compensates...
             
             ref_tau = 0 * x[0] + 0 * x[1] + (-0.01843) * x[2] + 0.0065 * x[3];
             ref_F =-0.1843 * x[0] + 0.0065 * x[1] + 0 * x[2] + 0 * x[3];
             command(ref_tau, ref_F);
             
             ref_F = -9.1215 * x[0] + 0.0602  * x[1] + 0 * x[2] + 0 * x[3];
             ref_tau = 0 * x[0] + 0 * x[1] + (-0.1215) * x[2] + 0.0602 * x[3];
             command(ref_tau, ref_F);
             
             ref_tau = 0 * x[0] + 0 * x[1] + 0.8091 * x[2] + 0.0127 * x[3];
             ref_F = 2.8091 * x[0] + 0.0127 * x[1] + 0 * x[2] + 0 * x[3];
             command(ref_tau, ref_F);
        }       
    }
}