Werkend script mbv Laurens

Dependencies:   mbed QEI HIDScope biquadFilter MODSERIAL FastPWM

main.cpp

Committer:
Renate
Date:
2019-12-10
Revision:
2:25d2d6a5e212
Parent:
1:b862262a9d14

File content as of revision 2:25d2d6a5e212:

#include "mbed.h"
#include "HIDScope.h"
#include "QEI.h"
#include "BiQuad.h"
#include "FastPWM.h"
#define  M_PI 3.14159265358979323846  /* pi */
#include <math.h>
// PC CONNECTIONS
Serial pc(USBTX, USBRX);
HIDScope scope(6);
// DIGITAL OUT





// DIGITAL IN
DigitalIn Power_button_pressed(D1);                                                     // Definiëren van alle buttons, we gebruiken hiervoor geen InterruptIn, maar DigitalIn.
InterruptIn Emergency_button_pressed(D2);
DigitalIn Motor_calib_button_pressed(SW2);
DigitalIn servo_button_pressed(SW3);

// ANALOG IN
AnalogIn EMG_biceps_right_raw (A0);                                                     // Definiëren van de ruwe EMG-signalen die binnenkomen via AnalogIn.
AnalogIn EMG_biceps_left_raw (A1);                                                      // We gebruiken signalen van de kuit en de linker en rechter biceps.
AnalogIn EMG_calf_raw (A2);

// ENCODERS
QEI Encoder1(D13, D12, NC, 64);                                                         // Definities voor de encoders op motor 1 (Encoder1) en 2 (Encoder2). Hiervoor wordt de QEI library gebruikt
QEI Encoder2(D10, D9, NC, 64);                                                          // We gebruiken X2 encoding, wat standaard is en dus niet hoeft worden toegevoegd aan deze defninitie.
// MOTORS
const float PWMfreq = 18000.0;
FastPWM motor1(D6);                                                                      // Definities voor de motorsnelheden door middel van PwmOut. Er kan een getal tussen 0 en 1 worden ingevoerd.
FastPWM motor2(D5);

DigitalOut motor1_dir(D7);                                                              // Definities voor de richtingen van de motoren. Het getal 0 zorgt voor de ene richting, het getal 1 voor de andere.
DigitalOut motor2_dir(D4);                                                                                        // Het aantal counts per omwenteling is gelijk aan 64.


// TICKERS
Ticker loop_ticker;                                                                     // Ticker aanmaken die ervoor zorgt dat de ProcessStateMachine met een frequentie vsn 500 Hz kan worden aangeroepen.
const float main_loop_freq = 500.0;                                                      // Main loop frequency.
// BENODIGD VOOR PROCESS STATE MACHINE
enum states {Motors_off, Calib_motor, Calib_EMG, Homing, Demo, Operation_mode};         // Alle states definiëren.
states currentState = Motors_off;                                                       // State waarin wordt begonnen definiëren.
volatile bool stateChanged = true;                                                               // Toevoegen zodat de initialisatie van de eerste state plaatsvindt.


// VARIABELEN
// Motor encoders
volatile float offset1 = 0.0;
volatile float offset2 = 0.0;
volatile float counts1;
volatile float counts2;
volatile float theta_h_1_rad;                                                                   // Actuele motorhoek in radialen (motor 1).
volatile float theta_h_2_rad;                                                                   // Actuele motorhoek in radialen (motor 2).
volatile float q1;                                                                              // Hoek joint 1 die volgt uit de actuele motorhoeken.
volatile float q2; 
// VARIABELEN VOOR EMG + FILTEREN
volatile float filtered_EMG_biceps_right_1;                                                     // Definities voor ruwe EMG-signalen, gefilterd met de high-pass en notch filter.
volatile float filtered_EMG_biceps_left_1;
volatile float filtered_EMG_calf_1;

volatile float filtered_EMG_biceps_right_abs;                                                   // Definities voor de signalen, waarbij de absolute waarden genomen zijn van de eerste filterketen.
volatile float filtered_EMG_biceps_left_abs;
volatile float filtered_EMG_calf_abs;

volatile float filtered_EMG_biceps_right;                                                       // Definities voor de gefilterde EMG-signalen, na de tweede filter keten.
volatile float filtered_EMG_biceps_left;
volatile float filtered_EMG_calf;

// VARIABELEN VOOR (INITIATIE VAN) EMG KALIBRATIE LOOP
volatile bool calib = false;                                                                     // Benodigde bool en 'runner' (i_calib) voor het uitvoeren van de EMG-kalbratie.
volatile int i_calib = 0;

volatile float filtered_EMG_biceps_right_total;                                                 // Benodigde variabelen voor het berekenen van een gemiddelde maximale EMG-waarde tijdens de EMG-kalibratie.
volatile float filtered_EMG_biceps_left_total;                                                  // Dit totaal is een sommatie van de signalen over 5 seconden.
volatile float filtered_EMG_calf_total;

volatile float mean_EMG_biceps_right;                                                           // Global variables definiëren voor het gemiddelde maximale EMG-signaal, verkregen d.m.v. de EMG-kalibratie.
volatile float mean_EMG_biceps_left;
volatile float mean_EMG_calf;
// CONTROLLER
// VARIABELEN VOOR OPERATION MODE (RKI)
volatile float vx;                                                                              // Geeft de definitie voor de 'desired velocity' in x-richting.
volatile float vy;                                                                              // Geeft de definitie voor de 'desired velocity' in y-richting.

volatile float Inverse_jacobian[2][2];                                                          // Matrixen opstellen voor de inverse jacobian en de gewenste snelheden (vx en vy).
volatile float desired_velocity[2][1];
volatile float Jacobian_double_prime[2][2];
volatile float Joint_velocity[2][1] = {{0.0}, {0.0}};                                           // Nulmatrix opstellen voor de joint snelheden, beginwaarden.

const float delta_t = 0.002;                                                           // Tijdsverschil dat wordt gebruikt om de joint velocities te integreren, is gelijk aan de duur van een 'ticker ronde'.

volatile float Joint_1_position = 0.0;                                                          // Begindefinities opstellen voor de joint en motor posities.
volatile float Joint_2_position = 0.0;

volatile float Joint_1_position_prev = 0.0;
volatile float Joint_2_position_prev = 0.0;

volatile float Motor_1_position = 0.0;
volatile float Motor_2_position = 0.0;

volatile float error_M1;                                                                        // Definiëren van de motorerrors, het verschil tussen de daadwerkelijke hoek en de gewenste hoek.
volatile float error_M2;

// VARIABELEN VOOR OPERATION MODE (PI-CONTROLLER)
const float Kp = 25.0;                                                                 // Kp en Ki waarden voor de PI-controller definiëren.
const float Ki = 0.1;                                                                 // Zijn theoretisch getest met goede resultaten, in de praktijk konden geen goede tests worden verricht, doordat de
                                                                                        // robot oncontroleerbaar gedrag vertoonde.
volatile float theta_k_1 = 0.0;                                                                 // Begin definities opstellen voor de motorhoeken na de proportional part.
volatile float theta_k_2 = 0.0;

volatile float error_integral_1 = 0.0;                                                          // Begin definities opstellen voor de integralen van de errors.
volatile float error_integral_2 = 0.0;

volatile float u_i_1;                                                                           // Uitkomst variabelen definiëren voor de vermenigvuldiging van de error integraal met Ki.
volatile float u_i_2;

volatile float theta_t_1;                                                                       // Variabelen opstellen voor de sommatie van theta_k en u_i.
volatile float theta_t_2;

volatile float abs_theta_t_1;                                                                   // Variabele opstellen voor de absolute waarde van theta_t.
volatile float abs_theta_t_2;
// DEMO MODE
volatile int i_demo;
// EMG FILTERS
// BICEPS-RECHTS
// Definities voor eerste BiQuadChain (High-pass en Notch) opstellen
BiQuadChain bqcbr;
BiQuad bqbr1(0.8006, -1.6012, 0.8006, -1.5610, 0.6414);                                 // High-pass filter met een cut off frequentie van 25 Hz.
BiQuad bqbr2(1, -1.6180, 1, -1.6019, 0.9801);                                           // Notch filter met een frequentie van 50 Hz en een notchwidth van 0.01 Hz.
// Na het nemen van de absolute waarde (later) moet de tweede BiQuadChain worden
// toegepast. Definieer (twee Low-pass filters-> vierde orde filter verkrijgen):
BiQuadChain bqcbr2;
BiQuad bqbr3(1.5515e-4, 3.1030e-4, 1.5515e-4, -1.9645, 0.9651);                         // Twee low-pass filters met een cut off frequentie van 2 Hz.
BiQuad bqbr4(1.5515e-4, 3.1030e-4, 1.5515e-4, -1.9645, 0.9651);

// BICEPS-LINKS
// Definities voor eerste BiQuadChain (High-pass en Notch) opstellen
BiQuadChain bqcbl;
BiQuad bqbl1(0.8006, -1.6012, 0.8006, -1.5610, 0.6414);                                 // High-pass filter met een cut off frequentie van 25 Hz.
BiQuad bqbl2(1, -1.6180, 1, -1.6019, 0.9801);                                           // Notch filter met een frequentie van 50 Hz en een notchwidth van 0.01 Hz.
// Na het nemen van de absolute waarde (later) moet de tweede BiQuadChain worden
// toegepast. Definieer (twee Low-pass filters-> vierde orde filter verkrijgen):
BiQuadChain bqcbl2;
BiQuad bqbl3(1.5515e-4, 3.1030e-4, 1.5515e-4, -1.9645, 0.9651);                         // Twee low-pass filters met een cut off frequentie van 2 Hz.
BiQuad bqbl4(1.5515e-4, 3.1030e-4, 1.5515e-4, -1.9645, 0.9651);

// KUIT
// Definities voor eerste BiQuadChain (High-pass en Notch) opstellen
BiQuadChain bqck;
BiQuad bqk1(0.8006, -1.6012, 0.8006, -1.5610, 0.6414);                                  // High-pass filter met een cut off frequentie van 25 Hz.
BiQuad bqk2(1, -1.6180, 1, -1.6019, 0.9801);                                            // Notch filter met een frequentie van 50 Hz en een notchwidth van 0.01 Hz.
// Na het nemen van de absolute waarde (later) moet de tweede BiQuadChain worden
// toegepast. Definieer (twee Low-pass filters-> vierde orde filter verkrijgen):
BiQuadChain bqck2;
BiQuad bqk3(1.5515e-4, 3.1030e-4, 1.5515e-4, -1.9645, 0.9651);                          // Twee low-pass filters met een cut off frequentie van 2 Hz.
BiQuad bqk4(1.5515e-4, 3.1030e-4, 1.5515e-4, -1.9645, 0.9651);
// Functions
void motors_off()                                                                       // Functie waarbij beide motoren worden uitgezet.
{
    motor1.write(0);
    motor2.write(0);
    pc.printf("Motoren uit functie\r\n");
}

void emergency()                                                                        // Noodfunctie waarbij de motoren uit worden gezet en de ProcessStateMachine wordt losgekoppeld
{                                                                                       // van de ticker. De robot doet dan niks meer. De enige optie is om de mbed te resetten, waarna
    loop_ticker.detach();                                                               // het script opnieuw moet worden opgestart.
    motor1.write(0.0);
    motor2.write(0.0);
    pc.printf("Ik ga exploderen!!!\r\n");
}
void EMG_calibration()                                                                  // Functie die wordt uitgevoerd tijdens de EMG kalibratie. Wordt geinitialiseerd door de bool calib,
{                                                                                       // die alleen waar is tijdens de EMG kalibratie. Er wordt gebruikgemaakt van een runner i_calib, zodat
    if (i_calib == 0) {                                                                 // EMG-waarden tijdens maximale spierspanning gedurende 5 seconden bij elkaar op worden geteld. Het gemiddelde
        filtered_EMG_biceps_right_total=0;                                              // hiervan kan worden bepaald door te delen door het aantal samples dat genomen is in dit interval, namelijk 2500.
        filtered_EMG_biceps_left_total=0;
        filtered_EMG_calf_total=0;
    }
    if (i_calib <= 2500) {
        filtered_EMG_biceps_right_total+=filtered_EMG_biceps_right;
        filtered_EMG_biceps_left_total+=filtered_EMG_biceps_left;
        filtered_EMG_calf_total+=filtered_EMG_calf;
        i_calib++;
    }
    if (i_calib > 2500) {
        mean_EMG_biceps_right=filtered_EMG_biceps_right_total/2500.0;
        mean_EMG_biceps_left=filtered_EMG_biceps_left_total/2500.0;
        mean_EMG_calf=filtered_EMG_calf_total/2500.0;
        pc.printf("Ontspan spieren\r\n");
        pc.printf("Rechterbiceps_max = %f, Linkerbiceps_max = %f, Kuit_max = %f\r\n", mean_EMG_biceps_right, mean_EMG_biceps_left, mean_EMG_calf);
        calib = false;
    }
}
void Inverse_Kinematics()                                                               // Functie die de inverse kinematica uitvoert. De inverse Jacobian is afkosmtig uit eerdere berekeningen in Matlab.
{                                                                                       // The desired velocity komt voort uit de operation mode, waar hier een waarde aan wordt toegekend.
    // Defining joint velocities based on calculations of matlab                        // Outputs van deze functie zijn motorposities, die later worden gebruikt bij het berekenen van een positie error.
    Jacobian_double_prime[0][0] = cos(q1-3.141592653589793/3.0)*(-1.7E+1/4.0E+1)+(cos(q1+q2-atan(sqrt(3.0)*(8.5E+1/1.37E+2)-4.5E+1/1.37E+2))*1.7093510851226E+2)/4.0E+2;
    Jacobian_double_prime[0][1] = (cos(q1+q2-atan(sqrt(3.0)*(8.5E+1/1.37E+2)-4.5E+1/1.37E+2))*1.7093510851226E+2)/4.0E+2;
    Jacobian_double_prime[1][0] = cos(q1+3.141592653589793/6.0)*(1.7E+1/4.0E+1)+(sin(q1+q2-atan(sqrt(3.0)*(8.5E+1/1.37E+2)-4.5E+1/1.37E+2))*2.682835056795381E+3*(sqrt(2.0)*1.7E+1-sqrt(6.0)*3.0))/1.048E+5;
    Jacobian_double_prime[1][1] = (sin(q1+q2-atan(sqrt(3.0)*(8.5E+1/1.37E+2)-4.5E+1/1.37E+2))*2.682835056795381E+3*(sqrt(2.0)*1.7E+1-sqrt(6.0)*3.0))/1.048E+5;
    float detJ  = Jacobian_double_prime[0][0]*Jacobian_double_prime[1][1] - Jacobian_double_prime[0][1]*Jacobian_double_prime[1][0];
    Inverse_jacobian[0][0] = (1.0/float(detJ))*Jacobian_double_prime[1][1];
    Inverse_jacobian[0][1] = -(1.0/float(detJ))*Jacobian_double_prime[0][1];
    Inverse_jacobian[1][0] = -(1.0/float(detJ))*Jacobian_double_prime[1][0];
    Inverse_jacobian[1][1] = (1.0/float(detJ))*Jacobian_double_prime[0][0];
    if (fabs(detJ)<0.01)
    {
        Joint_velocity[0][0] = 0.0;
        Joint_velocity[1][0] = 0.0;
    }
    else
    {
    Joint_velocity[0][0] = Inverse_jacobian[0][0]*vx + Inverse_jacobian[0][1]*vy;
    Joint_velocity[1][0] = Inverse_jacobian[1][0]*vx + Inverse_jacobian[1][1]*vy;
    }
    scope.set(4,Joint_velocity[0][0]);
    scope.set(5,Joint_velocity[1][0]);
    // Integration
    Joint_1_position = Joint_1_position_prev + Joint_velocity[0][0]*delta_t;
    Joint_2_position = Joint_2_position_prev + Joint_velocity[1][0]*delta_t;

    Joint_1_position_prev = Joint_1_position;
    Joint_2_position_prev = Joint_2_position;

    Motor_1_position = Joint_1_position;
    Motor_2_position = Joint_1_position + Joint_2_position;
}
void Read_all_inputs()
{
    // Berekenen van de motorhoeken (in radialen)
    counts1 = Encoder1.getPulses();                                                     // Verkrijgen van het aantal counts uit de encoders
    counts2 = Encoder2.getPulses();
    theta_h_1_rad = ((2.0*M_PI)*(counts1-offset1))/(32.0*131.25);                                // Van het gemeten aantal counts wordt de offset afgetrokken, zodat het aantal counts in de referentie positie gelijk is aan 0.
    theta_h_2_rad = ((2.0*M_PI)*(counts2-offset2))/(32.0*131.25);                                // Vermenigvuldiging met de conversion factor zorgt ervoor dat het aantal counts wordt omgezet naar de huidige motorhoeken.

    // Calculating joint angles based on motor angles (current encoder values)
    q1 = theta_h_1_rad;                                                                 // Relatieve hoek joint 1 in radialen.
    q2 = theta_h_2_rad - theta_h_1_rad;                                                 // Relatieve hoek joint 2 in radialen.

    // Eerste deel van de filters (High-pass + Notch) over het ruwe EMG signaal
    // doen. Het ruwe signaal wordt gelezen binnen een ticker en wordt daardoor 'gesampled'
    filtered_EMG_biceps_right_1=bqbr1.step(EMG_biceps_right_raw.read());
    filtered_EMG_biceps_left_1=bqcbl.step(EMG_biceps_left_raw.read());
    filtered_EMG_calf_1=bqck.step(EMG_calf_raw.read());

    // Vervolgens wordt de absolute waarde hiervan genomen
    filtered_EMG_biceps_right_abs=fabs(filtered_EMG_biceps_right_1);
    filtered_EMG_biceps_left_abs=fabs(filtered_EMG_biceps_left_1);
    filtered_EMG_calf_abs=fabs(filtered_EMG_calf_1);

    // Tenslotte wordt het tweede deel van de filters (twee low-pass, voor 4e orde filter)
    // over het signaal gedaan
    filtered_EMG_biceps_right=bqcbr2.step(filtered_EMG_biceps_right_abs);
    filtered_EMG_biceps_left=bqcbl2.step(filtered_EMG_biceps_left_abs);
    filtered_EMG_calf=bqck2.step(filtered_EMG_calf_abs);
}
void Homing_function()                                                                  // Functie die ervoor zorgt dat homing wordt uitgevoerd. De motoren worden met een lage snelheid bewogen, tot de motorhoeken
{                   
    float home = 0.0;                                                                    // weer in de referentie positie staan (0 in ons geval, doordat we compenseren met een offset voor encoder counts). Wanneer
    if (theta_h_1_rad != home) {                                                         // deze positie is bereikt, wordt de snelheid op nul gezet. In de ProcessStateMachine wordt overgegaan naar de volgende state,
        if (theta_h_1_rad < home) {                                                        // wanneer dit voor beide motoren is gebeurd.
            motor1.write(0.6f);
            motor1_dir = 0;
        } else {
            motor1.write(0.6f);
            motor1_dir = 1;
        }
    }
    if (fabs(theta_h_1_rad-home)<0.02) {
        motor1.write(0);
    }
    if (theta_h_2_rad != home) {
        if (theta_h_2_rad < home) {
            motor2.write(0.6f);
            motor2_dir = 0;
        } else {
            motor2.write(0.6f);
            motor2_dir = 1;
        }
    }
    if (fabs(theta_h_2_rad-home) < 0.02) {
        motor2.write(0.0f);
    }
    if (fabs(theta_h_2_rad-home) < 0.02 && fabs(theta_h_1_rad-home)<0.02)
    {
        motor2.write(0.0f);
        motor1.write(0.0f);
        stateChanged = true;   
    }
}
void PI_controller()                                                                    // De PI-controller zorgt ervoor dat het proportionele en het integrale aandeel worden bepaald.
{                                                                                       // Na sommatie van beide aandelen, wordt theta_t als output verkregen. Deze wordt later als input
// Proportional part:                                                                   // voor de motorsnelheden gebruikt.
    theta_k_1= Kp * error_M1;
    theta_k_2= Kp * error_M2;

// Integral part
    error_integral_1 = error_integral_1+ error_M1*delta_t;
    error_integral_2 = error_integral_2+ error_M2*delta_t;
    u_i_1= Ki * error_integral_1;
    u_i_2= Ki * error_integral_2;

// Sum all parts and return it
    theta_t_1= theta_k_1 + u_i_1;
    theta_t_2= theta_k_2 + u_i_2;
}
void Define_motor_dir()                                                                 // Deze functie bepaalt de output richtingen die aan de motoren worden gegeven tijdens de operation mode.
{           
    if (theta_t_1 >= 0)  motor1_dir = 0;
    else motor1_dir = 1;
    if (theta_t_2 >= 0) motor2_dir = 0;
    else motor2_dir = 1;
}

void Controlling_system()                                                               // Hoofdfunctie die wordt toegepast tijdens de operation mode. Een gewenste snelheid in x- en y-richting wordt
{                                                                                       // hiervoor opgesteld en is vervolgens de input voor de inverse kinematica functie. Door middel van een gewenste
    Inverse_Kinematics();                                                               // motorhoek en de actuele motorhoek wordt een error bepaald. Deze errors worden als input gebruikt voor de
                                                                                        // PI-controller, wiens absolute output wordt gebruikt om de motorsnelheid aan te sturen. Tevens wordt een functie
    error_M1 = Motor_1_position - theta_h_1_rad;                                        // aangeroepen die ervoor zorgt dat de motoren in de juiste richting gaan draaien.
    error_M2 = Motor_2_position - theta_h_2_rad;

    PI_controller();

    abs_theta_t_1 = fabs(theta_t_1);
    abs_theta_t_2 = fabs(theta_t_2);
    Define_motor_dir();
    motor1.write(abs_theta_t_1);
    motor2.write(abs_theta_t_2);
}
void UpdateScope()
{
    // De gefilterde EMG-signalen kunnen tevens visueel worden weergegeven in de HIDScope
    //scope.set(0, normalized_EMG_biceps_right);
    //scope.set(1, normalized_EMG_biceps_left);
    //scope.set(2, normalized_EMG_calf);
    scope.set(0,theta_h_1_rad);
    scope.set(1,theta_h_2_rad);
    scope.set(2,theta_t_1);
    scope.set(3,theta_t_2);
    //scope.set(4,error_M1);
    //scope.set(5,error_M2);
    scope.send();
}
void ProcessStateMachine()
{
        if (calib) {
        EMG_calibration();
    }
    switch(currentState)
    {
        case Motors_off:
            if (stateChanged) {
                motors_off();                                                           // Functie waarbij motoren uitgaan.
                stateChanged = false;
                pc.printf("Motors off state\r\n");
            }
            if  (Emergency_button_pressed.read() == false) {                            // Normaal krijgt de button een waarde 1 bij indrukken, nu nul -> false.
                emergency();                                                            // Bij het indrukken van de emergency button, wordt overgegaan op de emergency functie.
            }
            if  (Power_button_pressed.read() == false) {                                // Normaal krijgt de button een waarde 1 bij indrukken, nu nul -> false.
                currentState = Calib_motor;                                             // Er wordt doorgegaan naar de volgende state, wanneer de power button wordt ingedrukt.
                stateChanged = true;
                pc.printf("Moving to Calib_motor state\r\n");
            }
        break;
        case Calib_motor:
          if (stateChanged) {                                                         // het huidige aantal counts. Door deze offset in de komende metingen af te trekken van het aantal counts
                pc.printf("Zet motoren handmatig in home positie\r\n");                 // op dat moment, wordt ervoor gezorgd dat de motorhoeken in de referentiepositie gelijk zijn aan nul.
                stateChanged = false;
            }

          if  (Emergency_button_pressed.read() == false) {
                emergency();
            }
            if (Motor_calib_button_pressed.read() == false) {
                offset1 = counts1;
                offset2 = counts2;
                pc.printf("\r\n Offset1: %f, Offset2: %f\r\n",offset1,offset2);
                currentState = Calib_EMG;
                stateChanged = true;
                pc.printf("Moving to Calib_EMG state\r\n");
            }
            
        break;
        case Calib_EMG:
        if (stateChanged) {                                                         // wordt doorlopen. De spieren worden tijdens de kalibratie gedurende 5 seconden maximaal aangespannen.
                i_calib = 0;                                                            // Na deze 5 seconden wordt doorgegaan naar de volgende state. De output van deze kalibratie is een gemiddelde
                calib = true;                                                           // waarde van het EMG-signaal tijdens het maximaal aanspannen.
                pc.printf("Span spieren aan\r\n");
                stateChanged = false;
            }

            if  (Emergency_button_pressed.read() == false) {
                emergency();
            }

            if (i_calib > 2500) {
                calib = false;
                currentState = Homing;
                stateChanged = true;
                pc.printf("Moving to Homing state\r\n");
            }
        break;
        case Homing:
            if (stateChanged)
            {
            stateChanged = false;    
            }
            Homing_function();
            if (stateChanged) { 
            currentState = Demo;                                                        // overgegaan naar de volgende state. De eerste keer dat de ProcessStateMachine in de homing state belandt, is dit al het geval,                                                 // waardoor gelijk doorgegaan kan worden naar de operation mode.
            i_demo = 0.0;
            }
        break;
        case Demo:
   
        if (stateChanged)
            {
            stateChanged = false;    
            }
        if (i_demo <= 1*main_loop_freq) {
                    vx = 0;
                    vy = 0;
                }
                else if (i_demo <= 5*main_loop_freq) {
                    vx = 0.05;
                    vy = 0;
                }
                else if (i_demo <= 7*main_loop_freq) {
                    vx = 0;
                    vy = 0.05;
                }
                else if (i_demo <= 8*main_loop_freq) {
                    vx = 0.0;
                    vy = -0.02;
                } else {
                    vx = 0;
                    vy = 0;
                }

                Controlling_system();
                i_demo++; 
        break;
        case Operation_mode:
        
        break;
        
    }    
}

// State machine


void main_loop()
{
    Read_all_inputs();
    ProcessStateMachine();
    UpdateScope();
    //SetPrevious();
}


int main()
{
    pc.baud(115200);
    pc.printf("\r\nStarting...\r\n\r\n");
    Emergency_button_pressed.fall(&emergency);
    loop_ticker.attach(&main_loop,1.0/float(main_loop_freq));
    Power_button_pressed.mode(PullUp);
    Motor_calib_button_pressed.mode(PullUp);
    servo_button_pressed.mode(PullUp);
     bqcbr.add(&bqbr1).add(&bqbr2);                                                      // high-pass filter, gevolgd door een notch filter. Na het nemen van de absolute waarde van het bewerkte EMG-signaal
    bqcbr2.add(&bqbr3).add(&bqbr4);                                                     // moet het tweede gedeelte van de filterketen worden toegepast. Hiervoor moeten twee low-pass filters aan elkaar
    // Chain voor linker biceps                                                         // geketend worden.
    bqcbl.add(&bqbl1).add(&bqbl2);
    bqcbl2.add(&bqbl3).add(&bqbl4);
    // Chain voor kuit
    bqck.add(&bqk1).add(&bqk2);
    bqck2.add(&bqk3).add(&bqk4);
    motor1.period(1.0/float(PWMfreq));
    motor2.period(1.0/float(PWMfreq));
    while (true) {
    }
}