Ironcup Mar 2020

Dependencies:   mbed mbed-rtos MotionSensor EthernetInterface

main.cpp

Committer:
starling
Date:
2020-09-21
Revision:
22:b7cca3089dfe
Parent:
20:7138ab2f93f7

File content as of revision 22:b7cca3089dfe:

#include "FXAS21002.h"
#include "FXOS8700Q.h"  
#include "mbed.h"
#include "CarPWM.h"
#include "receiver.h"
#include "Motor.h"
#include "rtos.h"

#define PI 3.141593
#define Ts 0.02                         // Controller period(Seconds)
#define PWM_PERIOD 13.5                 // ms
#define INITIAL_P 0.452531214933414
#define INITIAL_I 5.45748932024049
#define INITIAL_D 0.000233453623255507
#define INITIAL_N 51.0605584484153
#define END_THRESH 4                    //For magnetometer calibration
#define START_THRESH 10                 //For magnetometer calibration
#define MINIMUM_VELOCITY 15
#define MINIMUM_CURVE_VELOCITY 19
#define ERROR_THRESH    PI/5
#define GYRO_PERIOD 15000               //us
#define RGB_LED_ON 0                    //active Low
#define RGB_LED_OFF 1                   //active Low

#define MIN -1.5
#define MAX 1.5

enum{
    BLACK,
    RED,
    GREEN,
    BLUE,
    PURPLE,
    YELLOW,
    AQUA,
    WHITE};


//Control Objetcs
PwmOut servo(PTD1);         // Servo connected to pin PTD3
Motor motor;
FXOS8700Q_mag mag(PTE25,PTE24,FXOS8700CQ_SLAVE_ADDR1);
FXOS8700Q_acc acc( PTE25, PTE24, FXOS8700CQ_SLAVE_ADDR1);
FXAS21002 gyro(PTE25,PTE24);
//Leds Objects
DigitalOut red_led(LED_RED);
DigitalOut green_led(LED_GREEN);
DigitalOut blue_led(LED_BLUE);
DigitalOut red_led_s(PTD0);
DigitalOut green_led_s(PTB2); //PTC4
DigitalOut blue_led_s(PTC12);
DigitalOut main_led(PTC4);
//Protocol Objects
Receiver rcv;
EthernetInterface eth;

// PID controller parameters and functions
float e[2], u, up[1],ui[2], ud[2]; // The vector coeficient means a time delay, for exemple e[a] = e(k-a) -> z^(-a)e(k)
float P, I, D, N, reference = 0;
void controlAnglePID(float P, float I, float D, float N);
void initializeController();
void control();
Ticker controller_ticker;

// Motor and servo variables
float saved_velocity = 0;
bool brake = false;

// Magnetometer/Gyro variables and functions
float max_x=0, max_y=0, min_x=0, min_y=0,x,y;
MotionSensorDataUnits mag_data;
MotionSensorDataCounts mag_raw;
float processMagAngle();
float gyro_reference = 0;
void magCal();

// Protocol
void readProtocol();
int contp = 0; // for debug only

// NXP RGB_LEDs control
void set_leds_color(int color);
void turn_leds_off();

int main(){
    
    // Initializing sensors:
    main_led = 1;
    acc.enable();
    gyro.gyro_config(MODE_1);
    initializeController();
    
    // Set initial control configurations
    motor.setVelocity(0);
    
    // Protocol initialization
    
    
    
    
    printf("Initializing Ethernet!\r\n");
    set_leds_color(RED);
    eth.init(RECEIVER_IFACE_ADDR, RECEIVER_NETMASK_ADDR, RECEIVER_GATEWAY_ADDR);
    eth.connect();
    printf("Protocol initialized! \r\n");
    gyro.start_measure(GYRO_PERIOD);
    set_leds_color(BLUE);
    rcv.set_socket();
    
    main_led = 0;
    controller_ticker.attach(&control,Ts);
    
    
    
    //main loop
    while(1){
        readProtocol();
      //  printf("%f \r\n",gyro.get_angle());
    }
}
void control(){
    controlAnglePID(P,I,D,N);
}
void readProtocol(){
    if(!rcv.receive())
        return;
    char msg = rcv.get_msg();
    //printf("Message received!");
    //contp++;
    //printf(" %d \r\n",contp);
    switch(msg)
    {
        case NONE:
            break;          
        case BRAKE:
            //printf("BRAKE ");
            float intensity, b_wait;
            rcv.get_brake(&intensity,&b_wait);
            if(!brake){
                set_leds_color(YELLOW);
                motor.stopJogging();
               // printf("BRAKE\r\n");
                setServoPWM(0,servo);
                //reference = 0;
                controller_ticker.detach();
                motor.brakeMotor(intensity,b_wait);
                controller_ticker.attach(&control,Ts);
                saved_velocity = 0;
                brake = true;
                }
            break;
        case GYRO_ZERO:
            gyro.stop_measure();
            wait(0.05);
            gyro.start_measure(GYRO_PERIOD);
            break;
        case ANG_SET:
            set_leds_color(PURPLE);
            //printf("ANG_SET\r\n");
            gyro_reference = gyro.get_angle();
            initializeController();
            break;
        case ANG_RST:
            //printf("ANG_RST\r\n");
            gyro_reference = 0;
            set_leds_color(PURPLE);
            initializeController();
            break;
        case MAG_ANG_REF:
            set_leds_color(BLUE);
            reference = rcv.get_mag_ang_ref() - processMagAngle();
            //printf("New reference: %f \n\r",reference*180/PI);
            if(reference > PI)
                reference = reference - 2*PI;
            else if(reference < -PI)
                reference = reference + 2*PI;  
            break;
        case ABS_ANG_REF:
            set_leds_color(GREEN);
            reference = rcv.get_abs_ang_ref();
            //printf("New reference: %f \n\r",reference*180/PI);
            if(reference > PI)
                reference = reference - 2*PI;
            else if(reference < -PI)
                reference = reference + 2*PI;  
            break;
        case REL_ANG_REF:
            set_leds_color(RED);
            reference = rcv.get_rel_ang_ref() + gyro.get_angle()*PI/180;
            //printf("New reference: %f \n\r",reference*180/PI); 
            if(reference > PI)
                reference = reference - 2*PI;
            else if(reference < -PI)
                reference = reference + 2*PI;
            break;
        case GND_VEL:
            set_leds_color(AQUA);
            saved_velocity = rcv.get_gnd_vel();
            //printf("GND_VEL");
            if(saved_velocity > 0){
                motor.setVelocity(saved_velocity);      
                if(abs(saved_velocity) > MINIMUM_VELOCITY)
                    brake = false;
                //printf("GND_VEL = %f\r\n", saved_velocity);
            }
            break;
        case JOG_VEL:
            set_leds_color(WHITE);
            float p, r;
            rcv.get_jog_vel(&p,&r);
            //printf("Joggin with period %f and duty cycle %f\r\n",p,r);
            if(p == 0 || r == 0)
                motor.stopJogging();
            else
                motor.startJogging(r,p);
            break;
        case PID_PARAMS:
            set_leds_color(WHITE);
            float arr[4];
            rcv.get_pid_params(arr);
            P = arr[0];
            I = arr[1];
            D = arr[2];
            N = arr[3];
           // printf("PID_PARAMS | kp=%f, ki=%f, kd=%f, n=%f\r\n", 
           //     arr[0], arr[1], arr[2], arr[3]);

            break;
        case MAG_CALIB:
            set_leds_color(BLUE);
            printf("MAG_CALIB\r\n");
            float mag[4];
            rcv.get_mag_calib(mag);
            max_x=mag[1];
            max_y=mag[3];
            min_x=mag[0];
            min_y=mag[2];
            //printf(" max_x = %f, max_y= %f, min_x= %f, min_y= %f\r\n",mag[1],mag[3],mag[0],mag[2]);
            break;
        case LED_ON:
            set_leds_color(BLACK);
            main_led = 1;
            break;
        case LED_OFF:
            set_leds_color(BLACK);
            main_led = 0;
            break;
        default:
            //ser.printf("unknown command!\r\n");
    }
}
/* Initialize the controller parameter P, I, D and N with the initial values and set the error and input to 0.          */
void initializeController(){
    for(int i =0; i<2; i++){
        e[i] = 0;
        ui[i] = 0;
        ud[i] = 0;
    }
    P= INITIAL_P;
    I= INITIAL_I;
    D= INITIAL_D;
    N= INITIAL_N;
}

/* PID controller for angular position */
void controlAnglePID(float P, float I, float D, float N){ 
    /* Getting error */
    float feedback = gyro.get_angle() - gyro_reference;
    e[1] = e[0];
    e[0] = reference - (feedback*PI/180);
    if(e[0] > PI)
      e[0]= e[0] - 2*PI;
    if(e[0] < -PI)
      e[0] = e[0] + 2*PI;
    /* Proportinal Part */
    up[0] = e[0]*P;  
    /* Integral Part */
    ui[1] = ui[0];
    if(abs(u) < PI/8){
      ui[0] = (P*I*Ts)*e[1] + ui[1];    
    }
    else if(u > 0)
      ui[0] = PI/8 - up[0];
    else if(u < 0)
      ui[0] = -PI/8 - up[0];  
    /* Derivative Part */
    ud[1] = ud[0];
    ud[0] = P*D*N*(e[0] - e[1]) - ud[1]*(N*Ts -1); 
    /** Controller **/ 
    u = up[0] + ud[0] + ui[0];
    setServoPWM(u*100/(PI/8), servo);
    if(abs(e[0]) >= ERROR_THRESH && motor.getVelocity() > MINIMUM_CURVE_VELOCITY){
        saved_velocity = motor.getVelocity();
        motor.setVelocity(MINIMUM_CURVE_VELOCITY);
        }
    else if(abs(e[0]) < ERROR_THRESH && motor.getVelocity() != saved_velocity){
        motor.setVelocity(saved_velocity);
        }
}
/* Brake function, braking while the gyroscope is still integrating will cause considerably error in the measurement. */
/* Function to normalize the magnetometer reading */
void magCal(){
        //red_led = 0;
        printf("Starting Calibration");
        mag.enable(); 
        wait(0.01);
        mag.getAxis(mag_data);
        float x0 = max_x = min_y = mag_data.x;
        float y0 = max_y = min_y = mag_data.y;
        bool began = false;
        while(!(began && abs(mag_data.x - x0) < END_THRESH && abs(mag_data.y - y0) < END_THRESH)){
            mag.getAxis(mag_data);
            if(mag_data.x > max_x)
                max_x = mag_data.x;
            if(mag_data.y > max_y)
                max_y = mag_data.y;
            if(mag_data.y < min_y)
                min_y = mag_data.y;
            if(mag_data.x < min_x)
                min_x = mag_data.x;    
            if(abs(mag_data.x-x0)>START_THRESH && abs(mag_data.y-y0) > START_THRESH)
                began = true;   
            printf("began: %d  X-X0: %f , Y-Y0: %f \n\r", began, abs(mag_data.x-x0),abs(mag_data.y-y0));
        }
        printf("Calibration Completed: X_MAX = %f , Y_MAX = %f , X_MIN = %f and Y_MIN = %f \n\r",max_x,max_y,min_x,min_y);
}

/* Function to transform the magnetometer reading in angle(rad/s).*/
float processMagAngle(){
   // printf("starting ProcessMagAngle()\n\r");
    float mag_lpf = 0;
    Timer t1;
    for(int i = 0; i<20; i++){
        //printf("\r\n");
        //wait(0.1);
        t1.start();
        __disable_irq();
        mag.getAxis(mag_data);
        __enable_irq();
        t1.stop();
        x = 2*(mag_data.x-min_x)/float(max_x-min_x) - 1;
        y = 2*(mag_data.y-min_y)/float(max_y-min_y) - 1;
        mag_lpf = mag_lpf + (-atan2(y,x));
        wait(0.015);
        }
   // wait(20*0.01);
   // printf("Finished ProcessMagAngle() %d \n\r",t1.read_us());
    return mag_lpf/20;
}
void turn_leds_off()
{
    red_led = RGB_LED_OFF;
    green_led = RGB_LED_OFF;
    blue_led = RGB_LED_OFF;
}

void set_leds_color(int color)
{
    turn_leds_off();

    switch(color)
    {
        case RED:
            red_led = RGB_LED_ON;
            red_led_s = RGB_LED_ON;                 
            break;
        case GREEN:
            green_led = RGB_LED_ON;
            green_led_s = RGB_LED_ON;
            break;
        case BLUE:
            blue_led = RGB_LED_ON;
            blue_led_s = RGB_LED_ON;
            break;
        case PURPLE:
            red_led = RGB_LED_ON;
            blue_led = RGB_LED_ON;
            red_led_s = RGB_LED_ON;
            blue_led_s = RGB_LED_ON;
            break;
        case YELLOW:
            red_led = RGB_LED_ON;
            green_led = RGB_LED_ON;
            red_led_s = RGB_LED_ON;
            green_led_s = RGB_LED_ON;
            break;
        case AQUA:
            blue_led = RGB_LED_ON;
            green_led = RGB_LED_ON;
            blue_led_s = RGB_LED_ON;
            green_led_s = RGB_LED_ON;
            break;
        case WHITE:
            red_led = RGB_LED_ON;
            green_led = RGB_LED_ON;
            blue_led = RGB_LED_ON;
            red_led_s = RGB_LED_ON;
            green_led_s = RGB_LED_ON;
            blue_led_s = RGB_LED_ON;
            break;
        default:
            break;
    }
}