lololololol

Dependencies:   mbed QEI HIDScope biquadFilter MODSERIAL FastPWM

main.cpp

Committer:
sembert
Date:
2019-10-31
Revision:
36:66f500e387c4
Parent:
35:ab9b1c9b6d08

File content as of revision 36:66f500e387c4:

#include "QEI.h"
#include "mbed.h"
#include "BiQuad.h"
#include "FastPWM.h"
#include "HIDScope.h"
#include "MODSERIAL.h"

// Pins
MODSERIAL pc(USBTX, USBRX);

QEI encoder_1(D10,D11,NC,8400,QEI::X4_ENCODING);
QEI encoder_2(D12,D13,NC,8400,QEI::X4_ENCODING);

FastPWM     PWM_motor_1(D6);
FastPWM     PWM_motor_2(D5);

DigitalOut  direction_motor_1(D7);
DigitalOut  direction_motor_2(D4);

DigitalOut  led_red(LED1);
DigitalOut  led_green(LED2);
DigitalOut  led_blue(LED3);

AnalogIn    emg_bl(A0);
AnalogIn    emg_br(A1);
AnalogIn    emg_leg(A2);

InterruptIn button_1(SW2);
InterruptIn button_2(SW3);


// variables
int m = 0;

const float pi = 3.1416f;
const float l = 0.535f;
Ticker          TickerStateMachine;
Ticker          motor_control;
Ticker          write_scope;
Timer           sinus_time;
Timeout         rest_timeout;
Timeout         mvc_timeout;
Timeout         led_timeout;
enum    states  {start, motor_calibration, demo_mode, emg_calibration, vertical_movement, horizontal_movement};
states  CurrentState = start;
bool    StateChanged = true;
enum    substates {rest_biceps_left, mvc_biceps_left, rest_biceps_right, mvc_biceps_right, rest_biceps_leg, mvc_biceps_leg};
substates CurrentSubstate = rest_biceps_left;
bool    SubstateChanged = true;
volatile bool    pressed_1    = false;
volatile bool    pressed_2    = false;
HIDScope scope(6);

volatile float  theta_ref1 = 0.5f*pi;
volatile float  theta_ref2 = 3.0f*pi/4.0f;
float Ts    = 0.1f;
float Kp0;
float Ki0;
float Kd0;
float Kp1;
float Ki1;
float Kd1;
float theta_1;
float theta_2;
float theta_error1;
float theta_error2;
float torque_1;
float torque_2;
float x;
float y;
volatile float EMGx_velocity = 0.0f;
volatile float EMGy_velocity = 0.0f;

BiQuad Lowpass_bl ( 1.55148e-04, 3.10297e-04, 1.55148e-04, -1.96446e+00, 9.65081e-01 );
BiQuad Highpass_bl ( 9.40809e-01, -9.40809e-01, 0.00000e+00, -8.81619e-01, 0.00000e+00);
BiQuad notch_bl (9.98432e-01, -1.89913e+00, 9.98432e-01, -1.89913e+00, 9.96886e-01);
BiQuad Lowpass_br ( 1.55148e-04, 3.10297e-04, 1.55148e-04, -1.96446e+00, 9.65081e-01 );
BiQuad Highpass_br ( 9.40809e-01, -9.40809e-01, 0.00000e+00, -8.81619e-01, 0.00000e+00);
BiQuad notch_br (9.98432e-01, -1.89913e+00, 9.98432e-01, -1.89913e+00, 9.96886e-01);
BiQuad Lowpass_leg ( 1.55148e-04, 3.10297e-04, 1.55148e-04, -1.96446e+00, 9.65081e-01 );
BiQuad Highpass_leg ( 9.40809e-01, -9.40809e-01, 0.00000e+00, -8.81619e-01, 0.00000e+00);
BiQuad notch_leg (9.98432e-01, -1.89913e+00, 9.98432e-01, -1.89913e+00, 9.96886e-01);

int n = 0;

float emgFiltered_bl;
float emgFiltered_br;
float emgFiltered_leg;
float emg;
float xmvc_value = 1e-11;

float sum = 0;
float xrest_value;
float rest_value_bl;
float rest_value_br;
float rest_value_leg;

float mvc_value_bl;
float mvc_value_br;
float mvc_value_leg;

float treshold_bl = 0.5;
float treshold_br = 0.5;
float treshold_leg = 0.5;

bool previous_value_emg_leg;
bool current_value_emg_leg;

volatile char command;

// functies
void ledred()
{
    led_red = 0;
    led_green = 1;
    led_blue = 1;
}
void ledgreen()
{
    led_green=0;
    led_blue=1;
    led_red=1;
}
void ledblue()
{
    led_green=1;
    led_blue=0;
    led_red=1;
}
void ledyellow()
{
    led_green=0;
    led_blue=1;
    led_red=0;
}
void ledmagenta()
{
    led_green=1;
    led_blue=0;
    led_red=0;
}
void ledcyan()
{
    led_green=0;
    led_blue=0;
    led_red=1;
}
void ledwhite()
{
    led_green=0;
    led_blue=0;
    led_red=0;
}
void ledoff()
{
    led_green=1;
    led_blue=1;
    led_red=1;
}

bool get_command_a() {
    command = pc.getcNb();
    if (command == 'a') {
        pc.printf("a is ingedrukt! \n\r");   
        return true;
    } else {
    return false;
    }
}

bool get_command_d () {
    command = pc.getcNb();
    if (command == 'd') {
        pc.printf("d is ingedrukt! \n\r");   
        return true;
    } else {
    return false;
    }
}

bool get_command_s () {
    command = pc.getcNb();
    if (command == 's') {
        pc.printf("s is ingedrukt! \n\r");   
        return true;
    } else {
    return false;
    }
}

float CalculateError(float theta_reference,float theta)
{
    float theta_error = theta_reference-theta;
    return theta_error;
}

float Controller(float theta_error, bool motor)
{
    if (motor == false) {
        float K0     = 75.0f;
        float ti0    = 5.0f;
        float td0    = 0.1f;
        Kp0    = K0*(1+td0/ti0);
        Ki0    = K0/ti0;
        Kd0    = K0*td0;
        
        static float error_integral0 = 0;
        static float error_prev0 = 0;
        static BiQuad LowPassFilter0(0.0640, 0.1279, 0.0640, -1.1683, 0.4241);
    
        // Proportional part:
        float torque_p0 = Kp0 * theta_error;
    
        // Integral part:
        error_integral0 = error_integral0 + theta_error * Ts;
        float torque_i0 = Ki0 * error_integral0;
    
        // Derivative part:
        float error_derivative0 = (theta_error - error_prev0)/Ts;
        float filtered_error_derivative0 = LowPassFilter0.step(error_derivative0);
        float torque_d0 = Kd0 * filtered_error_derivative0;
        error_prev0 = theta_error;
    
        // Sum all parts and return it
        float torque0 = torque_p0 + torque_i0 + torque_d0;
        return torque0;
    } else {
        float K1     = 75.0f;
        float ti1   = 1.0f;
        float td1    = 0.01f;
        Kp1    = K1*(1+td1/ti1);
        Ki1    = K1/ti1;
        Kd1    = K1*td1;
        
        static float error_integral1 = 0;
        static float error_prev1 = 0;
        static BiQuad LowPassFilter1(0.0640, 0.1279, 0.0640, -1.1683, 0.4241);
    
        // Proportional part:
        float torque_p1 = Kp1 * theta_error;
    
        // Integral part:
        error_integral1 = error_integral1 + theta_error * Ts;
        float torque_i1 = Ki1 * error_integral1;
    
        // Derivative part:
        float error_derivative1 = (theta_error - error_prev1)/Ts;
        float filtered_error_derivative1 = LowPassFilter1.step(error_derivative1);
        float torque_d1 = Kd1 * filtered_error_derivative1;
        error_prev1 = theta_error;
    
        // Sum all parts and return it
        float torque1 = torque_p1 + torque_i1 + torque_d1;
        return torque1;
    }
}

void Kinematics()
    {    
    EMGx_velocity = 0.1f;  
    EMGy_velocity = 0.0f; 
    float thetav_1= -(EMGx_velocity*cos(theta_1 + theta_2))/(l*cos(theta_1 + theta_2)*sin(theta_1) - l*sin(theta_1 + theta_2)*cos(theta_1)) - (EMGy_velocity*sin(theta_1 + theta_2))/(l*cos(theta_1 + theta_2)*sin(theta_1) - l*sin(theta_1 + theta_2)*cos(theta_1));
    float thetav_2= (EMGx_velocity*(cos(theta_1 + theta_2) + cos(theta_1)))/(l*cos(theta_1 + theta_2)*sin(theta_1) - l*sin(theta_1 + theta_2)*cos(theta_1)) + (EMGy_velocity*(sin(theta_1 + theta_2) + sin(theta_1)))/(l*cos(theta_1 + theta_2)*sin(theta_1) - l*sin(theta_1 + theta_2)*cos(theta_1));
    theta_ref1 = theta_ref1 + thetav_1*Ts;
    theta_ref2 = theta_ref2 + thetav_2*Ts;
    x = cos(theta_ref1)*l+cos(theta_ref1+theta_ref2)*l;
    y = l*(sin(theta_ref1)+sin(theta_ref1+theta_ref2));  
    if (sqrt(pow(x,2)+pow(y,2))>1.0f) {
        pc.printf("Limit reached!\n\r");
        theta_ref1 = theta_1;
        theta_ref2 = theta_2;
    }
}
void CalculateDirectionMotor()
{
    Kinematics();
    direction_motor_1 = Controller(CalculateError(theta_ref1,theta_1),0) >= 0.0f;
    direction_motor_2 = Controller(CalculateError(theta_ref2,theta_2),1) >= 0.0f;
}

void ReadEncoder()
{
    theta_1 = (0.5f*pi-(((2.0f*pi)/64.0f)*(float)encoder_1.getPulses())/131.25f); // 360/64 voor de 64 CPR Encoder, 131.25 omdat de gear ratio 131.25:1 is. Hiermee is 1 omwenteling 360.
    theta_2 = ((-3.0f*pi/4.0f)+(((2.0f*pi)/64.0f)*(float)encoder_2.getPulses())/131.25f);
}

void MotorControl()
{
    ReadEncoder();
    CalculateDirectionMotor();
    PWM_motor_1.write(fabs(Controller(CalculateError(theta_ref1,theta_1),0))/(2.0f*pi));
    PWM_motor_2.write(fabs(Controller(CalculateError(theta_ref2,theta_2),1))/(2.0f*pi));
}

void go_next_1()
{
    pressed_1 = !pressed_1;
}

void go_next_2()
{
    pressed_2 = !pressed_2;
}

bool emg_switch(float treshold, float emg_input) {
    if(emg_input > treshold){
        current_value_emg_leg = true;
    } else {
        current_value_emg_leg = false;
    }
    if(current_value_emg_leg == true && previous_value_emg_leg == false) {
        previous_value_emg_leg = current_value_emg_leg;
        return true;
    } else {
        previous_value_emg_leg = current_value_emg_leg;
        return false;
    }
}

bool emg_trigger(float treshold, float emg_input) {
    if(emg_input > treshold) {
        return true;
    } else {
        return false;
    }
}

float EmgCalibration(float emgFiltered, float mvc_value, float rest_value)
{
    float emgCalibrated;
    if (emgFiltered <= rest_value) {
        return 0.0f;
        //emgCalibrated = 0;
    }
    
    if (emgFiltered >= mvc_value) {
        return 1.1f;
        //emgCalibrated = 1;
    } else {
        emgCalibrated = (emgFiltered-rest_value)/(mvc_value-rest_value);
    }
    return emgCalibrated;
}

void emgsample()
{
    emgFiltered_bl = Highpass_bl.step(emg_bl.read());
    emgFiltered_bl = notch_bl.step(emgFiltered_bl);
    emgFiltered_bl = fabs(emgFiltered_bl);
    emgFiltered_bl = Lowpass_bl.step(emgFiltered_bl);

    emgFiltered_br = Highpass_br.step(emg_br.read());
    emgFiltered_br = notch_br.step(emgFiltered_br);
    emgFiltered_br = fabs(emgFiltered_br);
    emgFiltered_br = Lowpass_br.step(emgFiltered_br);

    emgFiltered_leg = Highpass_leg.step(emg_leg.read());
    emgFiltered_leg = notch_leg.step(emgFiltered_leg);
    emgFiltered_leg = fabs(emgFiltered_leg);
    emgFiltered_leg = Lowpass_leg.step(emgFiltered_leg);
}

void rest()
{
    if (CurrentSubstate == rest_biceps_left) {
        emg = emgFiltered_bl;
        //pc.printf("emg: %f \n\r",emgFiltered_bl);
    }
    if (CurrentSubstate == rest_biceps_right) {
        emg = emgFiltered_br;
    }
    if (CurrentSubstate == rest_biceps_leg) {
        emg = emgFiltered_leg;
    }
    if (n < 500) {
        ledred();
        sum = sum + emg;
        //pc.printf("sum: %f \n\r",sum);
        n++;
        rest_timeout.attach(rest,0.001f);
    }
    if (n == 500) {
        sum = sum + emg;
        //pc.printf("sum: %f \n\r",sum);
        n++;
        xrest_value = float (sum/n);
        if (CurrentSubstate == rest_biceps_left) {
            rest_value_bl = xrest_value;
            pc.printf("rest_value_bl %f \n\r", rest_value_bl);
            CurrentSubstate = mvc_biceps_left;
            SubstateChanged = true;
            ledblue();
            
        }
        if (CurrentSubstate == rest_biceps_right) {
            rest_value_br = xrest_value;
            pc.printf("rest_value_br %f \n\r", rest_value_br);
            CurrentSubstate = mvc_biceps_right;
            SubstateChanged = true;
            ledmagenta();
        }
        if (CurrentSubstate == rest_biceps_leg) {
            rest_value_leg = xrest_value;
            pc.printf("rest_value_leg %f \n\r", rest_value_leg);
            pc.printf("rest_value_bl %f \n\r", rest_value_bl);
            CurrentSubstate = mvc_biceps_leg;
            SubstateChanged = true;
            ledwhite();
        }
    }
}

void mvc()
{
    if (CurrentSubstate == mvc_biceps_left) {
        emg = emgFiltered_bl;
    }
    if (CurrentSubstate == mvc_biceps_right) {
        emg = emgFiltered_br;
    }
    if (CurrentSubstate == mvc_biceps_leg) {
        emg = emgFiltered_leg;
    }
    if (emg >= xmvc_value) {
        xmvc_value = emg;
    }
    n++;
    if (n < 1000) {
        mvc_timeout.attach(mvc,0.001f);
        ledred();
    }
    if (n == 1000) {
        if (CurrentSubstate == mvc_biceps_left) {
            mvc_value_bl = xmvc_value;
            pc.printf("mvc_value_bl %f \n\r", mvc_value_bl);
            CurrentSubstate = rest_biceps_right;
            SubstateChanged = true;
            ledyellow();
        }
        if (CurrentSubstate == mvc_biceps_right) {
            mvc_value_br = xmvc_value;
            pc.printf("mvc_value_br %f \n\r", mvc_value_br);
            CurrentSubstate = rest_biceps_leg;
            SubstateChanged = true;
            ledcyan();
        }
        if (CurrentSubstate == mvc_biceps_leg) {
            mvc_value_leg = xmvc_value;
            pc.printf("mvc_value_leg %f \n\r", mvc_value_leg);
            CurrentState = vertical_movement;
            StateChanged = true;
            ledoff();
        }
        xmvc_value = 1e-11;
    }
}

void WriteScope()
{
    emgsample();
    scope.set(0, theta_ref1);
    scope.set(1, theta_1);
    scope.set(2, CalculateError(theta_ref1,theta_1));
    scope.set(3, theta_ref2);
    scope.set(4, theta_2);
    scope.set(5, CalculateError(theta_ref2,theta_2));
    scope.send();
}

void SubstateTransition()
{
    if (SubstateChanged == true) {
        SubstateChanged = false;
        pressed_1 = false;
        pressed_2 = false;
        if (CurrentSubstate == rest_biceps_left) {
            ledgreen();
            pc.printf("groen \n\r");
            pc.printf("Initiating rest_biceps_left\n\r");
        }
        if (CurrentSubstate == mvc_biceps_left) {
            //ledblue();
            pc.printf("Initiating mvc_biceps_left\n\r");
        }
        if (CurrentSubstate == rest_biceps_right) {
            //ledyellow();
            pc.printf("Initiating rest_biceps_right\n\r");
        }
        if (CurrentSubstate == mvc_biceps_right) {
            //ledmagenta();
            pc.printf("Initiating mvc_biceps_right\n\r");
        }
        if (CurrentSubstate == rest_biceps_leg) {
            //ledcyan();
            pc.printf("Initiating rest_biceps_leg\n\r");
        }
        if (CurrentSubstate == mvc_biceps_leg) {
            //ledwhite();
            pc.printf("Initiating mvc_biceps_leg\n\r");
        }
    }
}

void while_start()
{
    // Do startup stuff
    CurrentState = motor_calibration;
    StateChanged = true;
}

void while_motor_calibration()
{
    // Do motor calibration stuff
    if (pressed_1) { // bool aanmaken voor demo (switch oid aanmaken)
        CurrentState = demo_mode;
        StateChanged = true;
    }
    if (pressed_2) {  // bool aanmaken voor EMG (switch oid aanmaken)
        CurrentState = emg_calibration;
        StateChanged = true;
    }
}

void while_demo_mode()
{
    EMGx_velocity = 0.1f;
    EMGy_velocity = 0.0f;
    ReadEncoder();
    Kinematics();
    
    pc.printf("X: %f    Y: %f   1: %f    2: %f  \n\r",x,y,theta_1,theta_2);
    /*
    m++;
    
    if (m<5) {
        EMGy_velocity = 0.1f;
        EMGx_velocity = 0.0f;
        pc.printf("beweging in y richting %f \n\r", EMGy_velocity);
        pc.printf("thetav_1 %f \n\r", theta_ref1);
    }
    if (m>=5 && m<10) {
        EMGy_velocity = 0.0f;
        EMGx_velocity = 0.1f;
        pc.printf("beweging in x richting %f \n\r", EMGx_velocity);
        pc.printf("thetav_1 %f \n\r", theta_ref1);
    }
    if (m>=10 && m<15) {
        EMGy_velocity = -0.1f;
        EMGx_velocity = 0.0f;
        pc.printf("beweging in y richting %f \n\r", EMGy_velocity);
    }
    if (m>=15 && m<20) {
        EMGy_velocity = 0.0f;
        EMGx_velocity = -0.1f;
        pc.printf("beweging in x richting %f \n\r", EMGx_velocity);
    }
    if (pressed_1) {
        m=0;
        CurrentState = demo_mode;
        StateChanged = true;
    }
    if ((pressed_2)) {
        CurrentState = emg_calibration;
        StateChanged = true;
    }
    */
}

void while_emg_calibration()
{
    // Do emg calibration stuff
    switch (CurrentSubstate) {
        case rest_biceps_left:
            SubstateTransition();
            if ((pressed_1) || (pressed_2)) {
                pressed_1 = false;
                pressed_2 = false;
                n = 0;
                sum = 0;
                rest();
            }
            break;
        case mvc_biceps_left:
            SubstateTransition();
            if ((pressed_1) || (pressed_2)) {
                pressed_1 = false;
                pressed_2 = false;
                n = 0;
                mvc();
            }
            break;
        case rest_biceps_right:
            SubstateTransition();
            if ((pressed_1) || (pressed_2)) {
                pressed_1 = false;
                pressed_2 = false;
                n = 0;
                sum = 0;
                rest();
            }
            break;
        case mvc_biceps_right:
            SubstateTransition();
            if ((pressed_1) || (pressed_2)) {
                pressed_1 = false;
                pressed_2 = false;
                n = 0;
                mvc();
            }
            break;
        case rest_biceps_leg:
            SubstateTransition();
            if ((pressed_1) || (pressed_2)) {
                pressed_1 = false;
                pressed_2 = false;
                n = 0;
                sum = 0;
                rest();
            }
            break;
        case mvc_biceps_leg:
            SubstateTransition();
            if ((pressed_1) || (pressed_2)) {
                pressed_1 = false;
                pressed_2 = false;
                n = 0;
                mvc();
            }
            break;
        default:
            pc.printf("Unknown or unimplemented state reached!\n\r");
    }
}

void while_vertical_movement()
{
    // Do vertical movement stuff
    MotorControl();
    if ((pressed_1) || (pressed_2) || (emg_switch(treshold_leg,EmgCalibration(emgFiltered_leg, mvc_value_leg, rest_value_leg)))) { // EMG gebaseerde threshold aanmaken
        CurrentState = horizontal_movement;
        StateChanged = true;  
    }
}


void while_horizontal_movement()
{
    // Do horizontal movement stuff
    MotorControl();
    if ((pressed_1) || (pressed_2) || (emg_switch(treshold_leg,EmgCalibration(emgFiltered_leg, mvc_value_leg, rest_value_leg)))) { // EMG gebaseerde threshold aanmaken
        CurrentState = vertical_movement;
        StateChanged = true;
    }
}    


void StateTransition()
{
    if (StateChanged) {
        pressed_1 = false;
        pressed_2 = false;
        if (CurrentState == start) {
            pc.printf("Initiating start.\n\r");
        }
        if (CurrentState == motor_calibration) {
            pc.printf("Initiating motor_calibration.\n\r");
        }
        if (CurrentState == demo_mode) {
            pc.printf("Initiating demo_mode.\n\r");
        }
        if (CurrentState == emg_calibration) {
            pc.printf("Initiating emg_calibration.\n\r");
        }
        if (CurrentState == vertical_movement) {
            pc.printf("Initiating vertical_movement.\n\r");
        }
        if (CurrentState == horizontal_movement) {
            pc.printf("Initiating horizontal_movement.\n\r");
        }
        StateChanged = false;
    }
}

void StateMachine()
{
    switch(CurrentState) {
        case start:
            StateTransition();
            while_start();
            break;
        case motor_calibration:
            StateTransition();
            while_motor_calibration();
            break;
        case demo_mode:
            StateTransition();
            while_demo_mode();
            break;
        case emg_calibration:
            StateTransition();
            while_emg_calibration();
            break;
        case vertical_movement:
            StateTransition();
            while_vertical_movement();
            break;
        case horizontal_movement:
            StateTransition();
            while_horizontal_movement();
            break;
        default:
            pc.printf("Unknown or unimplemented state reached!\n\r");
    }
}

// main
int main()
{
    pc.baud(115200);
    pc.printf("Hello World!\n\r");
    ledoff();
    button_1.fall(go_next_1);
    button_2.fall(go_next_2);
    sinus_time.start();
    PWM_motor_1.period_ms(1.0f/16.0f);
    PWM_motor_2.period_ms(1.0f/16.0f);
    //motor_control.attach(&MotorControl, Ts);
    write_scope.attach(&WriteScope, 0.01);
    TickerStateMachine.attach(&StateMachine,Ts);
    while(true) {
        return 0;
    }
}