Dependencies:   mbed QEI HIDScope biquadFilter MODSERIAL FastPWM

Files at this revision

API Documentation at this revision

Comitter:
Renate
Date:
Tue Dec 10 21:05:59 2019 +0000
Parent:
1:b862262a9d14
Commit message:
Werkend script mbv Laurens

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
diff -r b862262a9d14 -r 25d2d6a5e212 main.cpp
--- a/main.cpp	Wed Sep 04 15:30:13 2019 +0000
+++ b/main.cpp	Tue Dec 10 21:05:59 2019 +0000
@@ -1,23 +1,487 @@
 #include "mbed.h"
-//#include "HIDScope.h"
-//#include "QEI.h"
-#include "MODSERIAL.h"
-//#include "BiQuad.h"
-//#include "FastPWM.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;
 
-DigitalOut led(LED_RED);
+    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();
 
-MODSERIAL pc(USBTX, USBRX);
+    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) {
-        
-        led = !led;
-        
-        wait_ms(500);
     }
 }