Dependencies:   MODSERIAL QEI biquadFilter mbed

Fork of BioRobotics_Main by Casper Berkhout

main.cpp

Committer:
s1680897
Date:
2018-09-28
Revision:
5:224c1fe73a8f
Parent:
4:de0923cf6bcc

File content as of revision 5:224c1fe73a8f:

#include "QEI.h"
#include "math.h"
#include "mbed.h"
//#include "HIDScope.h" //set mbed library version to 119 for HIDScope to work
#include "MODSERIAL.h"
#include "BiQuad.h"

//left pot to set reference position.
//right pot to set Kp, right pot sets Ki when (right)button is pressed down


//--------------object creation------------------ 
Serial pc(USBTX, USBRX);
//Use X4 encoding.
//QEI wheel(p29, p30, NC, 624, QEI::X4_ENCODING);
//Use X2 encoding by default.
QEI enc1(D13, D12, NC, 32); //enable the encoder
QEI enc2(D15, D14, NC, 32); //enable the encoder
PwmOut M1_speed(D6);
PwmOut M2_speed(D5);
DigitalOut M1_direction(D7);
DigitalOut M2_direction(D4);
AnalogIn potmeter(A0);      //left pot
AnalogIn potmeter2(A1);     //right pot
InterruptIn button1(D2);       //hardware interrupt for stopping motors - right button
DigitalIn LimSW1(D9);
DigitalIn LimSW2(D8);
DigitalIn HomStart(D3); // - left button

BiQuad bqlowpass(0.4354, 0.8709, 0.4354, 0.5179, 0.2238);
//create scope objects - note: script won't run when HID usb port is not connected
//HIDScope scope(5); //set # of channels

Ticker motor_update1;
Ticker motor_update2;
Ticker error_update;

//Define objects EMG filter
AnalogIn    emg2( A2 );
AnalogIn    emg3( A3 );
AnalogIn    emg4( A4 );
AnalogIn    emg5( A5 );


Ticker      sample_timer;
Ticker      scope_timer;

DigitalOut  ledred(LED_RED);
DigitalOut  ledblue(LED_BLUE);
DigitalOut  ledgreen(LED_GREEN);
DigitalOut  led2(LED_RED);
DigitalIn   button_cal (SW2);


//-----------------variable declaration----------------
int pwm_freq = 500;
float set_speed;
float reference_pos;



double M1_home; 
double M1_error_pos = 0;
float M1_Kp = 2;
float M1_Ki = 4;
float M1_Kd = 0.19;
double M1_e_int=0;
double M1_e_prior=0;

double M2_home; 
double M2_error_pos = 0;
float M2_Kp = 1.5;
float M2_Ki = 0.5;
float M2_Kd = 0;
double M2_e_int=0;
double M2_e_prior=0;

double setpoint = 0;

double M1_rel_pos;
double M2_rel_pos;

float Ts = 0.002; //500hz sample freq

float gain_factor = 1.5;
double x_vel;
double y_vel;

bool M1homflag;
bool M2homflag;
bool Homstartflag;
  
/** Sample function
 * this function samples the emg and sends it to HIDScope
 **/
 int P= 200;
 double A[200];
 
 double sig_2_abs;
 double sig_3_abs;
 double sig_4_abs;
 double sig_5_abs;
 double movmean2;
 double movmean3;
 double movmean4;
 double movmean5;
 double emgsample2;
 double emgsample3;
 double emgsample4;
 double emgsample5;
 
enum        States {cal2,cal3,cal4,cal5};
int         state;

double      movmean_cal[5000];
double      movmean_max2=0;
double      movmean_max3=0;
double      movmean_max4=0;
double      movmean_max5=0; 


// Filters 
BiQuadChain bqc;
BiQuad bq1( 0.6844323315947305,1.368864663189461, 0.6844323315947305,1.2243497755555954,0.5133795508233265); //lp?
BiQuad bq2( 0.6844323315947306, -1.3688646631894612,  0.6844323315947306,   -1.2243497755555959, 0.5133795508233266); //hp?
BiQuad bq3(  0.7566897754116633, -1.2243497755555959,  0.7566897754116633,   -1.2243497755555959, 0.5133795508233266); // notch
    
    
//Function emgfilter signal 2
    double emgfilter2(double emgsample2)
        {
        //filter and take abs of input
        double sig_2_filt = bqc.step(emgsample2);
        sig_2_abs = abs(sig_2_filt);
        //calculate moving mean of the filtered signal
        for(int i = P-1; i >= 0; i--){
            if (i == 0) {
            A[i] = sig_2_abs;
            }
            else {
             A[i] = A[i-1];
             }   
                                    }
            double sum2 = 0;
            // deze for-loop sommeert de array
            for (int n = 0; n < P-1; n++) 
                {
                sum2 = sum2 + A[n];
                movmean2 = sum2/P; //dit is de moving average waarde  
                }
                double set_speed2=movmean2/movmean_max2;
                return(set_speed2);
                }
            
    
//Signal 3
    double emgfilter3(double emgsample3){
        //filter and take abs of input
        double sig_3_filt = bqc.step(emgsample3);
        sig_3_abs = abs(sig_3_filt);
    
        //calculate moving mean of the filtered signal
        for(int i = P-1; i >= 0; i--){
        if (i == 0) {
            A[i] = sig_3_abs;
            }
         else {
             A[i] = A[i-1];
             }   
            }
    double sum3 = 0;
    // deze for-loop sommeert de array
    for (int n = 0; n < P-1; n++) {
    sum3 = sum3 + A[n];
    movmean3 = sum3/P; //dit is de moving average waarde    
        }
    double set_speed3=movmean3/movmean_max3;
                return(set_speed3);
    }
//Signal 4
    double emgfilter4(double emgsample4)
    {
        //filter and take abs of input
        double sig_4_filt = bqc.step(emgsample4);
        sig_4_abs = abs(sig_4_filt);
    
        //calculate moving mean of the filtered signal
        for(int i = P-1; i >= 0; i--){
             if (i == 0) {
                A[i] = sig_4_abs;
                }
            else {
                A[i] = A[i-1];
                }   
                                    }
    double sum4 = 0;
    // deze for-loop sommeert de array
    for (int n = 0; n < P-1; n++) {
    sum4 = sum4 + A[n];
    movmean4 = sum4/P; //dit is de moving average waarde    
        }
    double set_speed4=movmean4/movmean_max4;
    return(set_speed4);
    }
    //Signal 5  
    double emgfilter5(double emgsample5)
    {
        //filter and take abs of input
        double sig_5_filt = bqc.step(emgsample5);
        sig_5_abs = abs(sig_5_filt);
    
        //calculate moving mean of the filtered signal
        for(int i = P-1; i >= 0; i--){
            if (i == 0) {
                A[i] = sig_5_abs;
                }
            else {
                A[i] = A[i-1];
             }   
                }
    double sum5 = 0;
    // deze for-loop sommeert de array
    for (int n = 0; n < P-1; n++) {
    sum5 = sum5 + A[n];
    movmean5 = sum5/P; //dit is de moving average waarde    
    }
    double set_speed5=movmean5/movmean_max5;
    return(set_speed5);
}

void sample(){
    emgsample2 = emg2.read();
    emgsample3 = emg3.read();
    emgsample4 = emg4.read();
    emgsample5 = emg5.read();
    double x_vel = emgfilter2(emgsample2)-emgfilter3(emgsample3); 
    double y_vel  = emgfilter4(emgsample4)-emgfilter5(emgsample5);
    }
    
//Calibration
void calibration_switch()
{
    switch(state) {
        case cal2:
            ledred=0;
            for (int i=0; i<=3500; i++){
            if (movmean2>movmean_max2) {
                movmean_max2=movmean2;
                }}
                state=cal3;
        break;
                
        case cal3:        
            ledred=1;
            ledblue=0;
            for (int i=0; i<=3500; i++){
            if (movmean3>movmean_max3) {
                movmean_max3=movmean3;
                }}
                state=cal4;
        break;
                
        case cal4:        
            ledblue=1;
            ledgreen=0;
            for (int i=0; i<=3500; i++){
            if (movmean4>movmean_max4) {
                movmean_max4=movmean4;
                }}
                state=cal5;
        break;
                
        case cal5:
            ledgreen=1;
            ledred=0;
            ledblue=0;
            for (int i=0; i<=3500; i++){
            if (movmean5>movmean_max5) {
                movmean_max5=movmean5;
                }}
        break;
} //end switch  
} //end calibration_switch

void calibration () {
         while(button1==0) {
                state=cal2;
                calibration_switch();
                    }
                    }

 
void kinemtaica(double q1, double q2, double vdx, double vdy, double &q1_new, double &q2_new){
  vdx=x_vel*gain_factor;
  vdy=y_vel*gain_factor;
  double q1_dot = (2.5*cos(q1+q2))/(sin(q2)) *vdx + (2.5*sin(q1+q2))/(sin(q2))*vdy;
  double q2_dot = -(0.3*cos(q1+q2)+0.4*cos(q1))/(0.12*sin(q2))*vdx -(0.3*sin(q1+q2)+0.4*sin(q2))/(0.12*sin(q2))*vdy;
  q1_new = q1 +q1_dot*Ts;
  q2_new = q2 +q2_dot*Ts;
 return;
}

float PID(double e, const double Kp, const double Ki, const double Kd, double Ts, double &e_int, double &e_prior){ //PID calculator
    e_int += Ts*e;
    double e_diff = (e-e_prior)/Ts;
    e_prior = e;
    double e_diff_filter = bqlowpass.step(e_diff);
    return(Kp*e+Ki*e_int+Kd*e_diff_filter);
    }

void M1_control(){
    
    //call PID func and set new motor speed
    set_speed = PID(M1_error_pos,M1_Kp,M1_Ki,M1_Kd,Ts,M1_e_int,M1_e_prior);
    if(set_speed > 0){
     M1_speed.write(abs(set_speed));
     M1_direction.write(0);
     }
    else if (set_speed < 0){
     M1_speed.write(abs(set_speed));
     M1_direction.write(1);
     }
    else{M1_speed.write(0);}
    
 }
 
 void M2_control(){
    set_speed = PID(M2_error_pos,M2_Kp,M2_Ki,M2_Kd,Ts,M2_e_int,M2_e_prior);
    if(set_speed > 0){
     M2_speed.write(abs(set_speed));
     M2_direction.write(0);
     }
    else if (set_speed < 0){
     M2_speed.write(abs(set_speed));
     M2_direction.write(1);
     }
    else{M2_speed.write(0);}       
    pc.printf("M2 integral = %f\n\r", M2_e_int);
  }
 
 void homing_system () {
    LimSW1.mode(PullDown);
    LimSW2.mode(PullDown);
    M1_speed.write(0);
    M2_speed.write(0);
    M1_direction.write(0);
    M2_direction.write(1);
    
       while(1){
            if (HomStart.read() == 0){
                  setpoint += 0.003; //move setpoint 0.2 radian per second (at 100hz)
                  pc.printf("Homing... \n\r");
            }     
            
            double M1_rel_pos = enc1.getPulses()/32.0/131.25*2.0*3.1416; 
            double M2_rel_pos = enc2.getPulses()/32.0/131.25*2.0*3.1416;  
            if(LimSW1.read() == 0){
                  M1_error_pos = 1.5*setpoint - M1_rel_pos;
            }
            if(LimSW2.read() == 0){
                M2_error_pos = -(0.5*setpoint - M2_rel_pos);
            }
            M1_control();
            M2_control();
            
        
        if(LimSW1.read() ==  1){
          M1_error_pos = 0;
          M1_speed.write(0);
          M1_home = enc1.getPulses()/32.0/131.25*2.0*3.1416; //in radians
        }    
        if (LimSW2.read() == 1) {
          M2_error_pos = 0;
          M2_speed.write(0);
          M2_home = enc2.getPulses()/32.0/131.25*2.0*3.1416; //in radians
        }
            
        if (LimSW1.read() == 1 && LimSW2.read() ==1) {
                pc.printf("Homing finished \n\r");
                M1_speed.write(0);
                M2_speed.write(0);
                wait(0.5);
                M1_home = enc1.getPulses()/32.0/131.25*2.0*3.1416; //in radians
                M2_home = enc2.getPulses()/32.0/131.25*2.0*3.1416; //in radians
                //break;
                while(1); //stop after homing.
        }
        wait(0.01);
       }

}
 
 void scopesend(){
  
     
     
     }
 void StopMotors(){
     while(1){
         M1_speed.write(0);
         M2_speed.write(0);
         }
    }
 
void geterror(){ 
    double M1_rel_pos = enc1.getPulses()/32.0/131.25*2.0*3.1416; //relative position in radians
    double M2_rel_pos = enc2.getPulses()/32.0/131.25*2.0*3.1416; //relative position in radians

    float Arm1_home = 122.0/180.0*3.1416;//home position of large link attached to base in radians - 112 degrees
    float Arm2_home = 19.0/180.0*3.1416;//home position of small link attached to base
    
    double M1_actual_pos = Arm1_home + (M1_rel_pos - M1_home)/2; //!!!!!!!Gearing ratio of timing belt = 2!!!!!!!!!! - Also known as angle theta
    double M2_actual_pos = Arm2_home + (M2_rel_pos - M2_home)/2; //!!!!!!!Gearing ratio of timing belt = 2!!!!!!!!!! - Also known as angle Alpha
    
    double q1 = M1_actual_pos;
    double q2 = q1 + M2_actual_pos; //see drawing
    
    //double M1_reference_pos = 1+potmeter.read()*0.5*3.1416; //should cover the right range - radians
    double M1_reference_pos = 0.5*3.1416-potmeter.read(); //should cover the right range - radians
    double M2_reference_pos = 0.5+potmeter2.read()*0.25*3.1416;
        
    
    //M2_error_pos = M2_reference_pos - M2_actual_pos;
    M2_error_pos = 0;
    if(M1_reference_pos > Arm1_home){
        M1_reference_pos = Arm1_home;
    }
    else{
        M1_error_pos = M1_reference_pos - M1_actual_pos;
    }
    if(M2_reference_pos > Arm2_home){
        M2_reference_pos = Arm2_home;
    }
    else{
        M2_error_pos = M2_reference_pos - M2_actual_pos;
    }
}
 
int main() {
    calibration();
    //add biquad sections to the chain
    bqc.add( &bq1 ).add( &bq2 ).add( &bq3 );
    
    sample_timer.attach(&sample, 0.002);
    //scope_timer.attach(&scopesend, 0.002);
                
    /*empty loop, sample() is executed periodically*/
    while(1) {}
    //initialize serial comm and set motor PWM freq
M1_speed.period(1.0/pwm_freq);
M2_speed.period(1.0/pwm_freq);
pc.baud(115200);
pc.printf("starting homing function now. Push button to start procedure \n\r");
//commence homing procedure
homing_system();
pc.printf("Setting home position complete\n\r");
//attach all interrupt
pc.printf("attaching interrupt tickers now \n\r");
button1.fall(StopMotors);     //stop motor interrupt
motor_update1.attach(&M1_control,0.01);
motor_update2.attach(&M2_control,0.01);
error_update.attach(&geterror,0.01);

pc.printf("initialization complete - position control of motors now active\n\r");
    
    while(1){   
        
     
    }
 
}