presentatie versie met potmeters enabled

Dependencies:   Encoder HIDScope mbed

Revision:
0:b0e2b38ab272
Child:
1:4c9994ac229c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Oct 27 12:20:03 2015 +0000
@@ -0,0 +1,599 @@
+#include "mbed.h"
+#include "MODSERIAL.h"
+#include "encoder.h"
+#include "HIDScope.h"
+#include "math.h"
+
+Serial pc(USBTX,USBRX);     // MODSERIAL output
+HIDScope scope(4);          // definieerd het aantal kanalen van de scope
+
+// Define Tickers and control frequencies
+Ticker          controller1, controller2, main_filter, cartesian, send;
+    // Go flag variables belonging to Tickers
+    volatile bool motor1_go = false, motor2_go = false, emg_go = false, cart_go = false;
+
+// Frequency control
+    double controlfreq = 50 ;    // controlloops frequentie (Hz)
+    double controlstep = 1/controlfreq; // timestep derived from controlfreq
+    
+    double EMG_freq = 200;
+    double EMG_step = 1/EMG_freq;
+
+//////////////////////// IN-OUTPUT /////////////////////////////////////////////
+//MOTOR OUTPUTPINS
+    PwmOut motor1_aan(D6), motor2_aan(D5);      // PWM signaal motor 2 (uit sheets)
+    DigitalOut motor1_rich(D7), motor2_rich(D4); // digitaal signaal voor richting
+
+// ENCODER INPUTPINS
+    Encoder motor1_enc(D12,D11), motor2_enc(D10,D9);        // encoder outputpins
+
+// EXTRA INPUTS AND REQUIRED VARIABLES
+//POTMETERS (used for debugging purposes, not reliable anymore)
+    AnalogIn potright(A4);      // define the potmeter outputpins
+    AnalogIn potleft(A5);
+    
+// Analoge input signalen defineren
+    AnalogIn    EMG_in(A0);                 // EMG_in.read kan je nu gebruiken om het analoge signaal A2 uit te lezen
+    AnalogIn    EMG_int(A2);                // deze leest A3 uit
+
+// BUTTONS 
+    // control flow             
+    DigitalIn   buttonlinks(PTA4);       
+    DigitalIn   buttonrechts(PTC6);
+    DigitalIn   reset_button(D1);
+        // init values
+        bool loop_start = false;
+        bool calib_start = false;
+        bool reset = false;
+        
+    // axis control
+    DigitalIn   switch_xy_button(D0);
+        // init values
+        bool switch_xy = false;
+// LED outputs on bioshield
+    DigitalOut led_right(D2);
+// LED outputs on dev-board
+    DigitalOut ledred(LED1);
+    DigitalOut ledgreen(LED2);
+    DigitalOut ledblue(LED3);
+    
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////// GLOBAL VARIABLES ///////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////
+
+double t = 0;       // used for circle movement
+// physical constants
+    const double L = 36;           // lenght of arms
+    const double pi = 3.1415926535897;      // pi
+
+    // angle limitations (in radians)
+    // motor1
+    const double limlow1 = 0.5;             // min height in rad
+    const double limhigh1 = 6.3;            // max height in rad
+    // motor 2
+    const double limlow2 = -4.0;            // maximum height, motor has been inverted due to transmission
+    const double limhigh2 = 2.5;              // minimum height in rad
+    
+    // offset angle (radians needed to change the arms to horizontal position from reset position)
+    const double phi_one_offset = 2.8;
+    const double phi_two_offset = 1.85;
+
+///////////////////////////
+// Main control loop transfer variables
+// here all variables that transfer bewtween the primary control functions
+
+// filter to calibration
+    double output1;
+    double output2;
+// filter to x-y
+    double output1_amp;
+    double output2_amp;
+// x-y to motor control
+    double phi_one;
+    double phi_two;
+
+////////////////////////////
+// NOTE: start position is [x,y] = [60,0], reset position is [phi1,phi2] = [0,0]
+// define smooth variables (is to create a slowed movement instead of going to ref value inmediately)
+    double start_up_time = 3;
+    double start_loops = start_up_time*controlfreq;
+    int rc1 = 0;            // counters in function to enable relatively smooth movement
+    int rc2 = 0;
+    
+// define return to start variables
+double reset_phi_one = 0;
+double reset_phi_two = 0;
+
+// storage variables to store the location at the beginning of the smoothed movement (0 on startup)
+double phi_one_curr = 0;
+double phi_two_curr = 0;
+
+// REFERENCE SETTINGS
+    double input_threshold = 0.25;   // the minimum value the signal must have in order to change the reference.
+ // Define storage variables for reference values (also start position)
+    double c_reference_x = 60, c_reference_y = 0;
+// x-settings   (no y-settings because these are calculated from the current x-position)
+    double x_min = 47, x_max = 70, y_min_max = -40;
+    double xx,yy,y_min,y_max;
+    // Define the maximum rate of change for the x and y reference signals (velocity)
+    double Vmax_x = 15, Vmax_y = 15;  // [cm/s]          
+
+
+// CONTROLLER SETTINGS
+    // motor 1
+    const double m1_Kp = 5;         // Proportional constant     
+    const double m1_Ki = 0.5;         // integration constant
+    const double m1_Kd = 0.4;         // differentiation constant
+    // motor 2
+    const double m2_Kp = 3;
+    const double m2_Ki = 0.5;
+    const double m2_Kd = 0.3;
+// storage variables.   these variables are used to store data between controller iterations
+    // motor 1
+    double m1_err_int = 0; 
+    double m1_prev_err = 0;
+    // motor 2
+    double m2_err_int = 0;
+    double m2_prev_err = 0;
+
+// EMG calibration variables
+double emg_gain1 = 7;       
+double emg_gain2 = 7;
+
+double cal_time = 2.5;       // amount of time calibration should take (seconds)
+double cal_samples = controlfreq*cal_time;  // amount of samples that is used (dependent on the frequency of the filter)
+double normalize_emg_value = 1;      // set the desired value to calibrate the signal to (eg max signal = 1)
+
+// FILTER VARIABLES
+    // storage variables
+        // differential action filter, same is used for both PID controllers
+            double m_f_v1 = 0, m_f_v2 = 0;
+        // input filter to smooth angle reference signals
+            double r1_f_v1 = 0, r1_f_v2 = 0, r2_f_v1 = 0, r2_f_v2 = 0;
+        // Define the storage variables and filter coeficients for eight filters
+        // EMG filter 1
+            double f1_v1 = 0, f1_v2 = 0, f2_v1 = 0, f2_v2 = 0, f3_v1 = 0, f3_v2 = 0,f4_v1 = 0, f4_v2 = 0;
+        // EMG filter 2
+            double f1_v1t = 0, f1_v2t = 0, f2_v1t = 0, f2_v2t = 0, f3_v1t = 0, f3_v2t = 0,f4_v1t = 0, f4_v2t = 0;
+        
+    // Filter coefficients
+        // differential action filter (lowpass 5Hz at 50Hz)
+            const double m_f_a1 = -1.1430, m_f_a2 = 0.4128, m_f_b0 = 0.0675, m_f_b1 = 0.1349, m_f_b2 = 0.0675;
+        // input filter (lowpass 1Hz at 50samples) (used to make the angle signals smooth)
+            const double r1_f_a1 = -1.6475, r1_f_a2 = 0.7009, r1_f_b0 = 0.0134, r1_f_b1 = 0.0267, r1_f_b2 = 0.0134;    
+
+    // EMG-Filter (calculated for 200)
+    
+    const double numnotch50biq1_1 = 1;
+    const double numnotch50biq1_2 = 1.11568254634875e-11;
+    const double numnotch50biq1_3 = 1.00000002278002;
+    const double dennotch50biq1_2 = -0.0434777721916752;
+    const double dennotch50biq1_3 = 0.956543692050407;
+    // biquad 2 coefficienten
+    const double numnotch50biq2_1 = 1;
+    const double numnotch50biq2_2 = -1.11571030192437e-11;
+    const double numnotch50biq2_3 = 0.999999977219980;
+    const double dennotch50biq2_2 = 0.0434777721916751;
+    const double dennotch50biq2_3 = 0.956543692050417;
+ 
+    // highpass filter 20 Hz coefficienten
+    const double numhigh20_1 = 0.638945525159022;
+    const double numhigh20_2 = -1.27789105031804;
+    const double numhigh20_3 = 0.638945525159022;
+    const double denhigh20_2 = -1.14298050253990;
+    const double denhigh20_3 = 0.412801598096189;
+ 
+    // lowpass 5 Hz coefficienten
+    const double numlow5_1 =0.000241359049041961;
+    const double numlow5_2 =0.000482718098083923;
+    const double numlow5_3 =0.000241359049041961;
+    const double denlow5_2 =-1.95557824031504;
+    const double denlow5_3 =0.956543676511203;      
+     
+////////////////////////////////////////////////////////////////
+/////////////////// START OF SIDE FUNCTIONS ////////////////////
+//////////////////////////////////////////////////////////////
+// these functions are tailored to perform 1 specific function
+
+// this funtion flips leds on and off accordin to input with 0 being on
+void LED(int red,int green,int blue)
+{
+    ledred.write(red);
+    ledgreen.write(green);
+    ledblue.write(blue);
+}    
+    
+// counts 2 radians
+// this function takes counts from the encoder and converts it to the amount of radians from the zero position. 
+// It has been set up for standard 2X DECODING!!!
+double get_radians(double counts)       
+{
+    double radians = (counts/4200)*2*pi;        // 2X DECODING!!!!! ((32 counts/rotation, last warning)
+    return radians;
+}
+
+
+// This functions takes a 0->1 input, uses passing by reference (&c_reference)
+// to create a reference that moves with a variable speed. It is meant for -1->1 values
+double reference_f(double input, double &c_reference, double limlow, double limhigh, double Vmax)
+{
+    double reference = c_reference + input * controlstep * Vmax ;
+            //  two if statements check if the reference exceeds the limits placed upon the arms
+            if(reference < limlow){reference = limlow;}
+            if(reference > limhigh){reference = limhigh;}
+           c_reference = reference; // change the global variable to the latest location.
+    return reference;
+}
+
+
+// This function takes the controller outputvalue and ensures it is between -1 and 1
+// this is done to limit the motor input to possible values (the motor takes 0 to 1 and the sign changes the direction).
+double outputlimiter (double output, double limit)
+{
+    if(output> limit)                                
+    {
+        output = 1;
+    }
+    else if(output < limit && output > 0)
+    {
+        output = output;
+    }
+    else if(output > -limit && output < 0)
+    {
+        output = output;
+    }
+    else if(output < -limit)
+    {
+        (output = -1);
+    }
+    return output;
+}
+
+
+// BIQUADFILTER CODE GIVEN IN SHEETS (input format: den, den, nom, nom, nom)
+double biquadfilter(double u, double &v1, double &v2, const double a1, const double a2, const double b0, const double b1, const double b2)
+{
+    double v = u - a1*v1 - a2*v2;
+    double y = b0*v + b1*v1 + b2*v2;
+    v2 = v1;
+    v1 = v;
+    return y;
+    }
+
+// PID Controller given in sheets
+// adapted to use the same differential filter, and to split the different terms
+double PID(double e, const double Kp, const double Ki, const double Kd, double Ts,double &e_int, double &e_prev)
+{
+// Proportional
+double P = Kp * e;
+// Integral
+e_int = e_int + Ts * e;
+double I = e_int * Ki;
+// Derivative   
+double e_derr = (e - e_prev)/Ts;
+e_derr = biquadfilter(e_derr, m_f_v1, m_f_v2, m_f_a1, m_f_a2, m_f_b0, m_f_b1, m_f_b2);
+// 
+e_prev = e;
+double D = Kd* e_derr;
+// PID
+double output = P + I + D;
+return output;
+}
+
+
+// function that limits the angles that can be used in the motor reference signal
+ double angle_limits(double phi, double limlow, double limhigh)
+{
+    if(phi < limlow)
+    {
+        phi = limlow;
+    }
+    if(phi > limhigh)
+    {
+        phi = limhigh;
+    }
+    return phi;
+}
+
+// this function adapts the filtered emg signal for use in the reference generation
+// adds threshold value and normalizes between 0 and 1
+double adapt_signal(double input)
+{
+    // add threshold value for outputs
+    if(input < input_threshold){input = 0;}
+        
+    // return the input to a value between 0 and 1 (otherwise you will get jumps in input)
+    input = (input-input_threshold) * (1/(1-input_threshold));
+     
+    // if below 0 = 0       (otherwise values like -input_threshold start popping up)
+    if(input < 0){input = 0;}
+      
+    // limit signal maximum to 1
+    if(input > 1){input = 1;}
+    return input;
+}
+    
+// send stuff to putty to check things
+void mod_send()
+{
+    pc.printf("xx = %f, yy = %f, phi1 = %f, phi2 = %f \n",xx,yy,phi_one,phi_two);
+}
+/////////////////////////////////////////////////////////////////////
+////////////////// PRIMARY CONTROL FUNCTIONS ///////////////////////
+///////////////////////////////////////////////////////////////////
+// these functions are called by go-flags and are used to update main variables and send signals to motor
+
+// function that updates the values of the filtered emg-signal
+void EMG_filter()
+{
+// filteren van EMG signaal 1 (A0) eerst notch(2 biquads), dan highpass, rectify(abs()), lowpass
+    double u1 = EMG_in.read();
+    double y1 = biquadfilter( u1, f1_v1, f1_v2,dennotch50biq1_2, dennotch50biq1_3,numnotch50biq1_1,numnotch50biq1_2,numnotch50biq1_3);
+    double y2 = biquadfilter( y1, f2_v1, f2_v2,dennotch50biq2_2, dennotch50biq2_3,numnotch50biq2_1,numnotch50biq2_2,numnotch50biq2_3);
+    double y3 = biquadfilter( y2, f3_v1, f3_v2, denhigh20_2,denhigh20_3,numhigh20_1, numhigh20_2, numhigh20_3);
+    double y4 = abs(y3);
+    double y5 = biquadfilter( y4, f4_v1, f4_v2, denlow5_2,denlow5_3,numlow5_1, numlow5_2, numlow5_3);
+    // update global variables
+    output1 = y5;
+    output1_amp = y5*emg_gain1;   // update global variable
+
+// filteren van EMG signaal 2 (A2), zelfde proces als signaal 1
+    double u1t = EMG_int.read();
+    double y1t = biquadfilter( u1t, f1_v1t, f1_v2t,dennotch50biq1_2, dennotch50biq1_3,numnotch50biq1_1,numnotch50biq1_2,numnotch50biq1_3);
+    double y2t = biquadfilter( y1t, f2_v1t, f2_v2t,dennotch50biq2_2, dennotch50biq2_3,numnotch50biq2_1,numnotch50biq2_2,numnotch50biq2_3);
+    double y3t = biquadfilter( y2t, f3_v1t, f3_v2t, denhigh20_2,denhigh20_3,numhigh20_1, numhigh20_2, numhigh20_3);
+    double y4t = abs(y3t);
+    double y5t = biquadfilter( y4t, f4_v1t, f4_v2t, denlow5_2,denlow5_3,numlow5_1, numlow5_2, numlow5_3);
+    // update global variables
+    output2 = y5t;
+    output2_amp = y5t*emg_gain2; 
+ }
+ 
+ 
+ // function that updates the required motor angles from the current filtered emg
+ void det_angles()
+{
+    // convert global to local variable
+    double xy_input1 = output1_amp;
+    double xy_input2 = output2_amp;
+
+    // use potmeter for debugging purposes (note: does not give a smooth signal due to mechanical breakdown)
+    xy_input1 = potright.read();
+    xy_input2 = potleft.read();
+    
+    xy_input1 = adapt_signal(xy_input1);
+    xy_input2 = adapt_signal(xy_input2);
+
+    double xy_main_input = xy_input1 - xy_input2 ;    // subtract inputs to create a signal that can go from -1 to 1
+ 
+    //scope.set(0,xy_main_input);
+    // limit the output between -1 and 1 (signal is not supposed to be able to go above but last check)
+    if(xy_main_input>1) {xy_main_input = 1;}
+    if(xy_main_input<-1) {xy_main_input = -1;}
+ 
+    if(switch_xy == false)          // use the signal to change the x-reference
+    {
+        xx = reference_f(xy_main_input,c_reference_x,x_min,x_max,Vmax_x);        // change the global x-reference
+        // calculate the y limits belonging to that particular x coordinate and update global variables
+        y_min = - sqrt(4900 - pow(xx,2));
+        if(y_min<y_min_max){y_min = y_min_max;} // make sure the arm cannot hit the table (may later be removed)
+        y_max = sqrt(4900 - pow(xx,2));
+       
+    }
+    if(switch_xy == true)           // use the signal to change the y-reference
+    {
+        yy = reference_f(xy_main_input,c_reference_y,y_min,y_max,Vmax_y);        // change the y-reference
+        
+    }
+    // check the y-reference (otherwise if x is controlled after y has been controlled, the circle is not followed).
+    if(yy < y_min){yy = y_min;}
+    if(yy > y_max){yy = y_max;}
+    
+    // let the arm make a circle (testing)
+    // xx = 60 + 5*cos(t);
+    // yy = 5*sin(t);
+    // t = t + 0.01;
+   
+    // x-y to arm-angles math
+    double r = sqrt(pow(xx,2)+pow(yy,2)); // vector naar end effector
+    double alfa = acos((2*pow(L,2)-pow(r,2))/(2*pow(L,2))); // alfa is de hoek tussen upper en lower arm
+    double beta = acos((pow(r,2))/(2*L*r)); // beta is de hoek tussen upper arm en r
+    double theta_one = (atan2(yy,xx)+beta); 
+    double theta_two = (-pi + alfa); 
+    
+    // convert arm-angles to motor angles( (x transmission) and offset (+ offset) to account for reset position)
+    double phi1 = 4*(theta_one) + phi_one_offset;
+    double phi2 = 4*(theta_one+theta_two) + phi_two_offset;       // math assumes angle relative to first arm. motor does not change relative orientation, so angle wrt horizontal position is needed.
+    phi2 = -phi2;   // reverse angle because of transmission.
+
+    // check the angles and apply the limits
+    phi1 = angle_limits(phi1,limlow1,limhigh1);
+    phi2 = angle_limits(phi2,limlow2,limhigh2);
+    
+    // smooth the input signal (lowpass 1Hz). (to reduce the freq content after reaching limits and to make the signal less jittery)   
+    phi1 = biquadfilter(phi1, r1_f_v1, r1_f_v2, r1_f_a1, r1_f_a2, r1_f_b0, r1_f_b1, r1_f_b2);
+    phi2 = biquadfilter(phi2, r2_f_v1, r2_f_v2, r1_f_a1, r1_f_a2, r1_f_b0, r1_f_b1, r1_f_b2);
+    
+    // write into global variables
+    phi_one = phi1;
+    phi_two = phi2;
+
+    // if the reset button has been pressed, continiously write the start position into the global variables to reset the arm  
+    if(reset == true)
+    {
+        phi_one = reset_phi_one;
+        phi_two = reset_phi_two;
+    }
+}
+
+
+// MOTOR 1
+void motor1_control()
+{
+     // change global into local variable  
+    double reference1 = phi_one;  
+    
+    // add smooth start up
+    // for a certain amount of function iterations slowly add the delta phi between positions
+    // (used to gently move to start position or move to reset position)
+    if(rc1 < start_loops)
+    {
+        rc1++;
+        reference1 = phi_one_curr + ((double) rc1/start_loops)*(reference1-phi_one_curr);
+    }
+  
+    double rads1 = get_radians(motor1_enc.getPosition());    // determine the position of the motor
+    double error1 = (reference1 - rads1);                       // determine the error (reference - position)
+    double m_output1 = PID(error1, m1_Kp, m1_Ki, m1_Kd, controlstep, m1_err_int, m1_prev_err);
+    // check the real angles and stop if exceeded (NaN protection) // doesnt work because start angle is lower so output stays 0
+        // if(rads1 < (limlow1 - 0.05)){m_output1 = 0;}
+        // if(rads1 > (limhigh1 + 0.05)){m_output1 = 0;}
+        m_output1 = outputlimiter(m_output1,1); // relimit the output between -1 and 1 for safety
+    if(m_output1 > 0) {                    // uses the calculated output to determine the direction  of the motor
+        motor1_rich.write(0);
+        motor1_aan.write(m_output1);
+    } else if(m_output1 < 0) {
+        motor1_rich.write(1);
+        motor1_aan.write(abs(m_output1));
+    }
+}
+
+// MOTOR 2
+void motor2_control()
+{
+    double reference2 = phi_two;
+      
+    // add smooth start up
+    // for a certain amount of function iterations slowly add the delta phi between positions
+    // (used to gently move to start position [x,y] = [60,0] or move to the reset position [phi1,phi2] = (0,0)
+    if(rc2 < start_loops)
+    {
+        rc2++;
+        reference2 = phi_two_curr + ((double) rc2/start_loops)*(reference2-phi_two_curr);
+    }
+    
+    double rads2 = get_radians(motor2_enc.getPosition());    // determine the position of the motor
+    double error2 = (reference2 - rads2);                    // determine the error (reference - position)   
+    double m_output2 = PID(error2, m2_Kp, m2_Ki, m2_Kd, controlstep, m2_err_int, m2_prev_err);
+       // check the real angles and stop if exceeded
+        // if(rads2 < limlow2 - 0.05){m_output2 = 0;}
+        // if(rads2 > limhigh2 + 0.05){m_output2 = 0;}
+    m_output2 = outputlimiter(m_output2,1);     // final output limit (not really needed, is for safety)
+    if(m_output2 > 0) {                    // uses the calculated output to determine the direction  of the motor
+        motor2_rich.write(0);
+        motor2_aan.write(m_output2);
+    } else if(m_output2 < 0) {
+        motor2_rich.write(1);
+        motor2_aan.write(abs(m_output2));
+    }
+}
+
+// calibrate the emg-signal
+// works bij taking a certain amount of samples taking the max then normalize to the desired value
+// went to max-value type. must be tested.!
+void calibrate_amp()
+{
+    double max1 = 0;
+    double max2 = 0;
+    for(int i = 0; i<cal_samples; i++)
+    {
+        EMG_filter();       // run filter
+        double input1 = output1;        // take data from global variable
+        if(input1>max1){max1 = input1;}       // take max input
+        double input2 = output2;
+        if(input2>max2){max2 = input2;}       // take max input
+        wait(controlstep);      // !! has to run at same interval as filter in main loop !! otherwise a 'different' signal will be used for calibration
+    }
+    emg_gain1 = normalize_emg_value/max1;  // normalize the amplification so that the maximum signal hits the desired one
+    emg_gain2 = normalize_emg_value/max2;
+   pc.printf("gain1 = %f, gain2 = %f",emg_gain1,emg_gain2); // print the calculated gains to putty
+
+}
+//////////////////////////////////////////////////////////////////
+//////////// DEFINE GO-FLAG FUNCTIONS ///////////////////////////
+////////////////////////////////////////////////////////////////
+
+
+void EMG_activate(){emg_go = true;}
+void angle_activate(){cart_go = true;}
+void motor1_activate(){motor1_go = true;}
+void motor2_activate(){motor2_go = true;}
+
+int main()
+{
+    pc.baud(115200);
+    main_filter.attach(&EMG_activate, EMG_step);
+    cartesian.attach(&angle_activate, controlstep);
+    controller1.attach(&motor1_activate, controlstep);      // call a go-flag
+    controller2.attach(&motor2_activate, controlstep); 
+    send.attach(&mod_send, 1);      // send data (only global variables) to putty
+    while(true) 
+    {
+        // button press functions
+        // flow buttons
+        if(buttonlinks.read() == 0)
+        {
+            loop_start = !loop_start;     
+            wait(buttonlinks.read() == 1);
+            wait(0.2);             
+        }
+        if(buttonrechts.read() == 0)
+        {
+            calib_start = !calib_start;     
+            wait(buttonrechts.read() == 1);
+            wait(0.2);             
+        }
+        // reverse buttons
+        if(switch_xy_button.read() == 0)
+        {
+           switch_xy = !switch_xy;     
+           wait(switch_xy_button.read() == 1);
+           led_right.write(!led_right.read());  // turn on led when switched to y control
+           wait(0.2);             
+        }
+        if(reset_button.read() == 0)
+        {
+            reset = !reset;     
+            wait(reset_button.read() == 1);
+            phi_one_curr = phi_one;
+            phi_two_curr = phi_two;
+            rc1 = 0;
+            rc2 = 0;     
+            wait(0.2);
+        
+        }
+        //////////////////////////////////////////////////
+        // Main Control stuff and options
+        if(loop_start == true && calib_start == false)        // check if start button = true then start the main control loops
+        {
+            LED(1,1,0); // turn blue led on
+            if(cart_go)   { cart_go = false; det_angles();}
+            if(emg_go)    { emg_go = false; EMG_filter();}
+            if(motor1_go) { motor1_go = false; motor1_control();}
+            if(motor2_go) { motor2_go = false; motor2_control();}
+        }
+        // shut off both motors 
+        if(loop_start == false) {motor1_aan.write(0); motor2_aan.write(0);}
+        
+        // turn green led on // start calibration procedures
+        if(loop_start == false && calib_start == true) 
+        {   LED(1,0,1); 
+            motor1_aan.write(0); 
+            motor2_aan.write(0);
+            calibrate_amp();        // 10 second calibration
+            calib_start = false;    // turn calibration mode off
+        }
+        
+        // turn red led on (show both buttons have been pressed)
+        if(loop_start == true && calib_start == true) 
+        { 
+        LED(0,1,1); 
+        motor1_aan.write(0); 
+        motor2_aan.write(0);
+        }
+        
+        // turn leds off (both buttons false)
+        else { LED(1,1,1);}
+    }
+}
\ No newline at end of file