Bouke Scheltinga / Mbed 2 deprecated Werk_college_23sept

Dependencies:   Encoder HIDScope MODSERIAL mbed QEI biquadFilter

main.cpp

Committer:
ThomasBNL
Date:
2015-10-22
Revision:
47:926669fe14b1
Parent:
40:7f928b465f8d

File content as of revision 47:926669fe14b1:

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////|
/////                    ////    //////    //////          /////////////////////////////////////////////////////////////////////////////////////////////////////////|
/////                    ////    //////    //////          /////////////////////////////////////////////////////////////////////////////////////////////////////////|
////////////     ////////////    //////    //////    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////|
////////////     ////////////    //////    //////    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////|
////////////     ////////////              //////          /////////////////////////////////////////////////////////////////////////////////////////////////////////|
////////////     ////////////              //////          /////////////////////////////////////////////////////////////////////////////////////////////////////////|
////////////     ////////////              //////    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////|
////////////     ////////////    //////    //////    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////|
////////////     ////////////    //////    //////          /////////////////////////////////////////////////////////////////////////////////////////////////////////|
////////////     ////////////    //////    //////          /////////////////////////////////////////////////////////////////////////////////////////////////////////|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////|
///////                //////    //////    //////          //////     ///////    //////     ///////    //////          /////////////////////////////////////////////|
///////                //////    //////    //////          //////       /////    //////       /////    //////          /////////////////////////////////////////////|
///////     /////////////////    //////    //////    ////////////        ////    //////        ////    //////    ///////////////////////////////////////////////////|
///////     /////////////////    //////    //////    ////////////         ///    //////         ///    //////    ///////////////////////////////////////////////////|
///////     /////////////////              //////          //////          //    //////          //    //////          /////////////////////////////////////////////|
///////     /////////////////              //////          //////     //         //////     //         //////          /////////////////////////////////////////////|
///////     /////////////////              //////    ////////////     ///        //////     ///        //////    ///////////////////////////////////////////////////|
///////     /////////////////    //////    //////    ////////////     ////       //////     ////       //////    ///////////////////////////////////////////////////|
///////                //////    //////    //////          //////     /////      //////     /////      //////          /////////////////////////////////////////////|
///////                //////    //////    //////          //////     //////     //////     //////     //////          /////////////////////////////////////////////|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////|
///////              ///////////////      /////////////     ///////    //////              /////////////////////////////////////////////////////////////////////////|
///////               /////////////        ////////////       /////    //////               ////////////////////////////////////////////////////////////////////////|
///////     //////     ///////////          ///////////        ////    //////     /////      ///////////////////////////////////////////////////////////////////////| 
///////     //////     //////////     //     //////////         ///    //////     /////      ///////////////////////////////////////////////////////////////////////| 
///////                /////////     ////     /////////          //    //////     /////      ///////////////////////////////////////////////////////////////////////| 
///////                ////////     //////     ////////     //         //////     /////      ///////////////////////////////////////////////////////////////////////| 
///////     //////     ///////                  ///////     ///        //////     /////      ///////////////////////////////////////////////////////////////////////| 
///////     //////     //////                    //////     ////       //////     /////      ///////////////////////////////////////////////////////////////////////| 
///////               //////     ////////////     /////     /////      //////               ////////////////////////////////////////////////////////////////////////| 
///////              //////     //////////////     ////     //////     //////              /////////////////////////////////////////////////////////////////////////| 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////| 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////|
// Groep 12: The Chenne Band //
//                                ___________________________
//                              //                           \\
//                             ||     [Table of content]      ||
//                              \\___________________________//
//
//                                       Introduction

//                 Libraries.................................................

//
//
//
//


//============================================================================================================================
//                    ___________________________
//                  //                           \\
//                 ||         [Libraries]         ||
//                  \\___________________________//
//

#include "mbed.h"
#include "HIDScope.h"
#include "QEI.h"
#include "MODSERIAL.h"
#include "biquadFilter.h"
#include "encoder.h"

//============================================================================================================================
//                    ___________________________
//                  //                           \\
//                 ||  [FLOW AND DEBUGGING TOOLS] ||
//                  \\___________________________//

//HIDScope    scope(1);                                                                                 // DEBUG      : HIDSCOPE has the ability to display signals over time and can be used to monitor signals

MODSERIAL  pc(USBTX,USBRX);                                                                           // MODSERIAL  : makes it possible to send messages to the computer (eg. inside Putty)

DigitalOut debug_led_red(LED_RED) , debug_led_green(LED_GREEN) , debug_led_blue(LED_BLUE);            // DEBUG      : Red, Blue and Green LED
DigitalIn  buttonL1(PTC6)  ,  buttonL2(PTA4)  ,  buttonH1(D2)  ,  buttonH2(D1);                       // DEBUG/CALIBRATION: 4 buttons for calibration and debugging
Ticker     looptimer;                                                                                 // FLOW       : Ticker called looptimer to set a looptimerflag that puts the volatile bool control_go to true every sample

volatile bool control_go = false, sample = false, sample_error, sample_error_strike;                  // EMG        : booleans for controlling sample time of moving average and emg signal
volatile bool looptimerflag;                                                                          // CONTROLLER : boolean that controls the sample time of the whole controller
                
double e30, e29, e28, e27, e26, e25, e24, e23, e22, e21, e20,                                         // ACTION     : in the action mechanism these variables calculate a current moving average error
       e19, e18, e17, e16, e15, e14, e13, e12, e11, e10, e9, 
       e8, e7, e6, e5, e4, e3, e2, e1, er, error_count, error_turn_average, error_strike_average;

AnalogIn input1(A0), input2(A1);                                                                      // EMG : Two AnalogIn EMG inputs, input1 (Left bicep), input2 (Right bicep)

double Sample_EMG_L_1, Sample_EMG_L_2, Sample_EMG_L_3, Sample_EMG_L_4, Sample_EMG_L_5, Sample_EMG_L_6,// EMG : Left/Right bicep moving average memory variables (moving average is calculated over ten values)
       Sample_EMG_L_7, Sample_EMG_L_8, Sample_EMG_L_9, Sample_EMG_L_10, moving_average_left;    
double Sample_EMG_R_1, Sample_EMG_R_2, Sample_EMG_R_3, Sample_EMG_R_4, Sample_EMG_R_5, Sample_EMG_R_6,
       Sample_EMG_R_7, Sample_EMG_R_8, Sample_EMG_R_9, Sample_EMG_R_10, moving_average_right;

double minimum_L, maximum_L, EMG_L_min, EMG_L_max;                                                    // EMG CALIBRATION: variables that are used during the EMG calibration                                                                                                                         
double minimum_R, maximum_R, EMG_R_min, EMG_R_max;                                                    
                                                                                                                 
double EMG_left_Bicep,  EMG_Left_Bicep_filtered,         
       EMG_Left_Bicep_filtered_notch_1, EMG_Right_Bicep_filtered_notch_1;                  
double EMG_Right_Bicep, EMG_Left_Bicep_filtered_notch_2, 
       EMG_Right_Bicep_filtered_notch_2, EMG_Right_Bicep_filtered;         

double Threshold_Bicep_Left_1, Threshold_Bicep_Left_2,                                                // EMG ACTION: variables to witch the threshold values calculated after the calibration get asigned to
       Threshold_Bicep_Right_1, Threshold_Bicep_Right_2;

double n=0; double c=0; double k=0; double p=0;                                                       // FLOW : these flow variables are assigned to certain values through out the script values in order to regulate the flow of the script 

// FILTERS EMG
const double low_b0     = 0.05892937945281792  , low_b1     = 0.11785875890563584  , low_b2     = 0.05892937945281792,                    // Notch 1 LOW :  VIA online biquad calculator Lowpass 520-48-0.7071-6
             low_a1     = -1.205716572226748   , low_a2     = 0.44143409003801976  ;                          
const double high_b0    = 0.6389437261127494   , high_b1    = -1.2778874522254988  , high_b2    = 0.6389437261127494,                     // Notch 2 HIGH: VIA online biquad calculator Highpass 520-52-0.7071-6   
             high_a1    = -1.1429772843080923  , high_a2    = 0.41279762014290533  ;                         
const double high_b0_HP = 0.84855234544818812  , high_b1_HP = -1.6970469089637623  , high_b2_HP = 0.8485234544818812,                     // HIGHPASS    : NOG OPZOEKEN!! : >25Hz? sample rate 512Hz
             high_a1_HP = -1.6564788473046559  , high_a2_HP = 0.7376149706228688   ;                        
const double low_b0_LP  = 0.0013067079602315681, low_b1_LP  = 0.0026134159204631363, low_b2_LP  = 0.0013067079602315681,                  // LOWPASS     : NOG OPZOEKEN!! <5-10 Hz? sample rate 512Hz
             low_a1_LP  = -1.9238184798980429  , low_a2_LP  = 0.9290453117389691   ;  

//Left bicep Filters
biquadFilter highpassfilter_1(high_a1_HP, high_a2_HP, high_b0_HP, high_b1_HP, high_b2_HP);            // EMG : moeten nog waardes voor gemaakt worden? (>25Hz doorlaten)
biquadFilter notchL1(high_a1, high_a2, high_b0, high_b1, high_b2);                                    // EMG : moeten nog waardes voor gemaakt worden (>52Hz doorlaten)
biquadFilter notchL2(low_a1, low_a2, low_b0, low_b1, low_b2);                                         // EMG : moeten nog waardes voor gemaakt worden (<48Hz doorlaten)
biquadFilter lowpassfilter_1(low_a1_LP, low_a2_LP, low_b0_LP, low_b1_LP, low_b2_LP); 

// Right bicep Filters
biquadFilter highpassfilter_2(high_a1_HP, high_a2_HP, high_b0_HP, high_b1_HP, high_b2_HP);            // EMG : moeten nog waardes voor gemaakt worden?
biquadFilter notchR1(high_a1, high_a2, high_b0, high_b1, high_b2);                                    // EMG : moeten nog waardes voor gemaakt worden
biquadFilter notchR2(low_a1, low_a2, low_b0, low_b1, low_b2);                                         // EMG : moeten nog waardes voor gemaakt worden
biquadFilter lowpassfilter_2(low_a1_LP, low_a2_LP, low_b0_LP, low_b1_LP, low_b2_LP);                  // EMG : moeten nog waardes voor gemaakt worden


// MOTORS               
QEI          motor_turn(D12,D13,NC,32);                           QEI        motor_strike(D9,D10,NC,32);                                // TURN - STRIKE : Encoder for motor
PwmOut       pwm_motor_turn(D5);                                  PwmOut     pwm_motor_strike(D6);                                      // TURN - STRIKE : Pwm for motor
DigitalOut   motordirection_turn(D4);                             DigitalOut motordirection_strike(D7);                                 // TURN - STRIKE : Direction of the motor
            
double integrate_error_turn=0, previous_error_turn=0;           double integrate_error_strike=0, previous_error_strike=0;               // TURN - STRIKE : previous error and integration error motor
          
double position_turn, error_turn, reference_turn;               double position_strike, error_strike, reference_strike;         
double P_gain_turn; double I_gain_turn; double D_gain_turn;     double P_gain_strike; double I_gain_strike; double D_gain_strike;       // TURN - STRIKE : these gains get multiplied with the error inside the PID controller                // TURN: these gains get multiplied with the error inside the PID controller
double pwm_motor_turn_P, pwm_motor_turn_I, pwm_motor_turn_D;    double pwm_motor_strike_P, pwm_motor_strike_I, pwm_motor_strike_D;      // TURN - STRIKE : variables that store the P, I and D action part of the error
double pwm_to_motor_turn;                                       double pwm_to_motor_strike;                                             // TURN - STRIKE : variable that is constructed by summing the values of the P, I and D action 
    

// FILTER: D-action 
// const double a0 = 0.000332685098529822, a1 = 0.000665370197059644, a2 =  0.000332685098529822, b1 = -1.9625271814290315, b2 = 0.9638579218231508;   
//const double a0 = 0.000021080713160785432, a1 = 0.000042161426321570865, a2 = 0.000021080713160785432, b1 = -1.990754082898736, b2 = 0.9908384057513788;    //(0.75Hz)
 const double a0 = 0.003543360146633312, a1 = 0.007086720293266624, a2 = 0.003543360146633312, b1 = -1.8704759567901301, b2 = 0.8846493973766635; //(10Hz)
// const double a0 = 0.0009129521023626334, a1 = 0.0018259042047252668, a2 = 0.0009129521023626334, b1 = -1.9368516414202819, b2 = 0.9405034498297324; (5Hz) 
biquadFilter Lowpassfilter_derivative(b1,b2,a0,a1,a2);             // BiquadFilter used for the filtering of the Derivative action of the PID-action

const double  cw=0;                             // MOTOR: turn direction zero is clockwise (front view)
const double  ccw=1;                            // MOTOR: turn direction one is counterclockwise (front view)
const double  off=1;                            // Led off
const double  on=0;                             // Led on
const int     Fs = 512;                         // sampling frequency (512 Hz)
const double  sample_time = 0.001953125;        // duration of one sample
double        conversion_counts_to_degrees=0.085877862594198; // Calculation conversion counts to degrees
                                                                 // gear ratio motor = 131
                                                                 // ticks per magnet rotation = 32 (X2 Encoder)
                                                                 // One revolution = 360 degrees
                                                                 // degrees_per_encoder_tick = 360/(gear_ratio*ticks_per_magnet_rotation)=360/131*32=0.085877862594198
const double  change_one_bottle=45; 
const double  Hit=60;                          // position when bottle is hit

                                                                                                                             
//============================================================================================================================  
//                    ___________________________
//                  //                           \\
//                 ||       [FUNCTIONS USED]      ||
//                  \\___________________________//
void execute_plant_turn             ();                                                     // TURN  : Check error -> execute PID controller -> write pwm and direction to motor
void execute_plant_strike           ();
double PID_control                  (double reference, double position, double &integrate_error, 
                                     double sample_time, double &previous_error, 
                                     double P_gain, double I_gain, double D_gain);
                                     
void keep_in_range                  (double * in, double min, double max);                   // Put in a value and makes sure that the value stays between assigned boundary's
void setlooptimerflag               (void);                                                  // Sets looptimerflag volatile bool to true

void deactivate_PID_Controller      (double& P_gain, double& I_gain, double& D_gain);        // STRIKE/TURN: Deactivate PID Controller

void activate_PID_Controller_strike (double& P_gain, double& I_gain, double& D_gain);        // STRIKE: Activate PID Controller
void activate_PID_Controller_turn   (double& P_gain, double& I_gain, double& D_gain);        // TURN  : Activate PID Controller 

void Change_Turn_Position_Left      (double& reference, double change_one_bottle);           // TURN  : Change Reference position one bottle to the left
void Change_Turn_Position_Right     (double& reference, double change_one_bottle);           // TURN  : Change Reference position one bottle to the right

void countdown_from_5();            // PUTTY : 5 second countdown inside
void calibrate_motor();             // MOTOR : Calibrate starting position motor
void calibration();                 // EMG   : Calibrate the EMG signal (calculate min and max signal and determine threshold values) 
void Filter();                      // EMG   : Filter the incoming EMG signals
void sample_filter();               // EMG   : Calculate moving average (10 samples, one sample per 25 samples) using sample_filter => moving average over +-0.5 seconds
void take_sample();                 // EMG   : Take a sample once every 25 samples that's used to calculate the moving average
void ControlGo();                   // EMG   : function that gets a ticker attached and sets a certain loop to true every sample
                
void red();void blue();void green();void white();void yellow();void cyan();void purple(); void black();  // DEBUG: Different color LEDS

void calibrate_potmeter();          // DEBUG/TEST : Calibration thresholds with potmeter

void Action_Controller();           // CONTROLLER : Decides and executes if the robot needs to turn to the left, right or strike based on the currently measured EMG signal
    
//============================================================================================================================
                                           ///////////////////////////////
                                           //                           //
/////////////////////////////////////////////      [MAIN FUNCTION]      /////////////////////////////////////////////////////
                                           //                           //                                                                        
                                           ///////////////////////////////                                                                        
//============================================================================================================================
int main() {
    
    black(); // No LED active    
    pc.printf("Start of code \n\r");
    
    pc.baud(115200);                                           // PC contactspeed  : Set the baudrate    
    
    red();                               
    calibrate_motor();                                         // MOTOR CALIBRATE  : The motor starting position (RED  LED)
     
    blue();  
    //calibration();                                             // EMG CALIBRATE    : The motor starting position (BLUE LED)                            
    
    calibrate_potmeter();                                      // DEBUG/TEST       : Calibration thresholds with potmeter
  
    looptimer.attach(setlooptimerflag,(float)1/Fs);            // CONTROLLER FLOW  : Calls the looptimer flag every sample
    
    black();
    wait (3);                                                  // REST before starting position
    
    green();                                                   // START CONTROLLOOP (GREEN LED)
    
    Action_Controller();                                       // CONTROLLER : Decides and executes if the robot needs to turn to the left, right or strike based on the currently measured EMG signal
}

//============================================================================================================================
                                           ///////////////////////////////
                                           //                           //
/////////////////////////////////////////////   [FUNCTIONS DESCRIBED]   /////////////////////////////////////////////////////
                                           //                           //                                                                        
                                           ///////////////////////////////                                                                        
//============================================================================================================================


// FUNCTION 1                              ___________________________
//                                       //                           \\
//                                      ||     [ACTIONCONTROLLER]      ||
//                                       \\___________________________//
    void Action_Controller()
    {   
       while (1)
        {                                                                                            // Start while loop           
        while(looptimerflag != true);
              looptimerflag  = false;
                                                                                             
        Nieuwe_actie:                   // Return here if action left, right or strike is executed
        green();                        // GREEN LED: ready to fire again
                      
//// sample_filter();            // TIJDELIJK UIT: What is the current EMG value
  
                        // POTMETER: SIMULATE EMG SIGNAL
                        moving_average_left   = (input1.read())*100;    // EMG Right bicep (tussen nul en 100%)          // DEBUG TEST TOOL: substitute EMG input for potmeter inputs
                        moving_average_right  = (input2.read())*100;    // EMG Left bicep  (tussen nul en 100%)          // DEBUG TEST TOOL: substitute EMG input for potmeter inputs
                        pc.printf("mov_r = %f, mov_l = %f \n\r", moving_average_right, moving_average_left);

//                                         ___________________________
//                                        :   [Action 2: Turn Left]  : 
//                                        :___________________________:
//                     
//                                      //Blue (strike) - Yellow (return)\\

                       // TEMPORARY: TO TEST STRIKE MECHANISM 
                       moving_average_left   = 40;        // TIJDELIJK PID TEST
                       moving_average_right  = 40;        // TIJDELIJK PID TEST
       
        if (moving_average_right > Threshold_Bicep_Right_1 && moving_average_left > Threshold_Bicep_Left_1)             // Statement 1 (if both are satisfied execute)
            { // Statement 1 start
                blue(); n=0; k=0; p=0;
                pc.printf("Slag \n\r");
                wait(0.5);  // TIJDELIJK?? 
                
                if(moving_average_left > Threshold_Bicep_Left_1 && moving_average_right > Threshold_Bicep_Right_1)      // Check if statement 1 is still true then continue and start Strike
                        { // Statement 2 start
                                                while(1)
                                                    { // inf while loop strike until finished start
                                                            if (n==0)                                                    // Change the reference point of the PID Strike controller
                                                                    {   reference_strike=90;  n=1;  error_count=0;   }   // Execute once (n is set to one and only gets executed if n equals zero)
                           
                                                            if (looptimerflag == true)                                   // Loop that executes the strike controller every sample (inside the controller the loudness is regulated)
                                                                    {  
                                                                        looptimerflag=false;
                                                                        activate_PID_Controller_strike(P_gain_strike, I_gain_strike, D_gain_strike);
                                                                        execute_plant_strike();
                                                                    }
                                                                    
                                                            if (fabs(position_strike)>Hit)                               // If the bottle is hit (hit if the position is greater than the set hit point) then initiate return                    
                                                                    { // Statement Return start
                                                                        while(1) 
                                                                                { // inf while loop return after strike start 
                                                                                    yellow(); 
                                                                                    if(k==0)                             // Change reference point of the PID Strike controller back to the original position
                                                                                        {  
                                                                                            p=1;  reference_strike=0; error_count=0; k=1;
                                                                                            pc.printf("return \n\r");
                                                                                        }       
                    //pc.printf("ref_t = %f, e_cnt= %f e_av=%f \n\r k=%f, er_cnt= %f", reference_strike, error_strike, error_strike_average, k, error_count); // LINE USED FOR TESTING
                            
                                                                                    if (looptimerflag == true)           // Loop that executes the strike controller every sample (loudness is deactivated by the value of p)
                                                                                        {
                                                                                            looptimerflag=false;
                                                                                            activate_PID_Controller_strike(P_gain_strike, I_gain_strike, D_gain_strike);
                                                                                            execute_plant_strike();
                                                                                        }   
                                    
                     printf(" %f \n\r",error_strike_average);  // LINE USED FOR TESTING
                                    
                                                                                    if (fabs(error_strike_average) < 0.5 && error_count>100)         // If error is small enough and at least 100 samples have passed since the return execute new action
                                                                                        {          
                                                                                            yellow();
                                                                                            pc.printf("new action \n\r");
                                                                                            deactivate_PID_Controller(P_gain_strike, I_gain_strike, D_gain_strike);
                                                                                            execute_plant_strike();
                                                                                            goto Nieuwe_actie;                                   
                                                                                        }
                                                                                }       // inf while loop return after strike end 
                                                                    }                   // Statement Return end
                                                      }                                 // inf while loop strike until finished end
                           }                                                            // Statement 2 end
              }                                                                         // Statement 1 end
//                                         ___________________________
//                                        :   [Action 2: Turn Left]  : 
//                                        :___________________________:
//                     
//                                                 //Yellow\\

            if (moving_average_left > Threshold_Bicep_Left_2 && moving_average_right < Threshold_Bicep_Right_1)
                    {  
                        yellow(); n=0;
                        pc.printf("LEFT \n\r");
                        wait(2);        // TIJDELIJK
                
                            while(moving_average_left > Threshold_Bicep_Left_1 && moving_average_right < Threshold_Bicep_Right_1) 
                                {
                                    if (n==0)                                    
                                            { 
                                                Change_Turn_Position_Left(reference_turn, change_one_bottle);
                                                n=1; error_count=0;
                                            } 
                                                 
                  // pc.printf("ref_t = %f, e_cnt= %f e_av=%f \n\r", reference_turn, error_count, error_turn_average); // LINE USED FOR TESTING
                                    
                                    if (looptimerflag == true)
                                            {
                                                looptimerflag=false;
                                                activate_PID_Controller_turn(P_gain_turn, I_gain_turn, D_gain_turn);
                                                execute_plant_turn();
                                            }
                                    
                                    if (fabs(error_turn_average) < 1 && error_count>250)             
                                            {
                                                pc.printf("new action \n\r");
                                                deactivate_PID_Controller(P_gain_turn, I_gain_turn, D_gain_turn);
                                                execute_plant_turn();
                                                goto Nieuwe_actie;  
                                            }
                                }
                        }
//                                         ___________________________
//                                        :   [Action 3: Turn Right]  : 
//                                        :___________________________:
//                     
//                                                 //Purple\\

        if (moving_average_right > Threshold_Bicep_Right_2 && moving_average_left < Threshold_Bicep_Left_1)
                {  
                    purple(); n=0;
                    pc.printf("Right \n\r");
                    wait(2);  // TIJDELIJK
                    
                        while(moving_average_right > Threshold_Bicep_Right_1 && moving_average_left < Threshold_Bicep_Left_1) 
                            {
                                if (n==0)                                                   
                                        { 
                                            Change_Turn_Position_Right(reference_turn, change_one_bottle);
                                            n=1; error_count=0;
                                        }        
                                       
 // pc.printf("ref_t = %f, e_cnt= %f e_av=%f \n\r", reference_turn, error_count, error_turn_average); // LINE USED FOR TESTING
                                
                                if (looptimerflag == true)
                                        {
                                            looptimerflag=false;
                                            activate_PID_Controller_turn(P_gain_turn, I_gain_turn, D_gain_turn);
                                            execute_plant_turn();
                                        }
                                                      
                                if (fabs(error_turn_average) < 1 && error_count>250)                     
                                        {
                                            pc.printf("new action \n\r");
                                            deactivate_PID_Controller(P_gain_turn, I_gain_turn, D_gain_turn);
                                            execute_plant_turn();
                                            goto Nieuwe_actie;
                                        }
                            }
                    }
                    }
                    }

//                                         ___________________________
//                                       //                           \\
//                                      ||         [CALIBRATE]         ||
//                                       \\___________________________//
//                                     Calibrate starting postion (RED LED)
//                                         ___________________________
//                                        : [Starting position motor] : 
//                                        :___________________________:
//                     
    
    void calibrate_motor()
    {
    pc.printf("Button calibration \n\r");
    while(1)
        {
            red();// RED LED                                       
            
            if (buttonL2.read() < 0.5)                                
                        {  motordirection_turn = cw;                       
                           pwm_motor_turn      = 0.02; }
          
            if (buttonL1.read() < 0.5)                             
                        {  motordirection_turn = ccw;                       
                           pwm_motor_turn      = 0.02; }    
                        
            pwm_motor_turn = 0;                   
                                                                   
            if (buttonH2.read() < 0.5)                             
                        {  motordirection_strike = cw;                       
                           pwm_motor_strike      = 0.02; }
         
            if (buttonH1.read() < 0.5)                                   
                        {  motordirection_strike = ccw;                       
                           pwm_motor_strike      = 0.02; } 
                       
            pwm_motor_strike = 0;  
                 
            if ((buttonL2.read() < 0.5) && (buttonL1.read() < 0.5)) // Save current TURN and STRIKE positions as starting position
                        {  
                            motor_turn.reset();                               // TURN   : Starting Position
                            reference_turn=0;                                 // TURN   : Set reference position to zero
                            motor_strike.reset();                             // STRIKE : Starting Position                                           
                            goto calibration_starting_position_complete;      // Calibration complete (exit while loop)
                        }
        }
        calibration_starting_position_complete:
        }
        
//                                          ___________________________
//                                        //                           \\
//                                       ||      [EMG_Calibration]      ||
//                                        \\___________________________//
// 
    void calibration()
    {
//                                      ___________________________________
//                                     : [Minimum value bicep calibration] : 
//                                     :___________________________________:
      
                blue();
                pc.printf("Start minimum calibration in 5 seconds \n\r");
                pc.printf("Keep your biceps as relaxed as possible \n\r");
                
                countdown_from_5();
                c=0;
    
                while(c<2560)                                           // 512Hz -> 2560 is equal to five seconds
                {
                    Filter();                                           // Filter EMG signal
                    minimum_L=EMG_Left_Bicep_filtered+minimum_L;        // Take previous sample EMG_Left_Bicep_filtered and add the new value
                    minimum_R=EMG_Right_Bicep_filtered+minimum_R;   
                    c++;                                                // Every sample c is increased by one until the statement c<2560 is false
                    wait(0.001953125);                                  // wait one sample
                }
    
                pc.printf("Finished minimum calibration \n\r");
    
                EMG_L_min=minimum_L/2560;                               // Divide the summation by the number of measurements (2560 measurements) to get a mean value over 5 seconds
                EMG_R_min=minimum_R/2560;
    
                pc.printf("EMG_L_min = %f \n\r EMG_R_min = %f \n\r", EMG_L_min, EMG_R_min);

                wait (3);                                               // Cooldown
    
//                                      ___________________________________
//                                     : [Maximum value bicep calibration] : 
//                                     :___________________________________:
//          
                pc.printf("start maximum calibration in 5 seconds (start contraction at 3) \n\r");
                
                countdown_from_5();
                c=0;
                
                while(c<2560)                                           // 512Hz -> 2560 is equal to five seconds
                {
                    Filter();                                           // Filter EMG signal
                    maximum_L=EMG_Left_Bicep_filtered+maximum_L;        // Take previous sample EMG_Left_Bicep_filtered and add the new value
                    maximum_R=EMG_Right_Bicep_filtered+maximum_R;     
                    c++;                                                // Every sample c is increased by one until the statement c<2560 is false
                    wait(0.001953125);
                }
    
                pc.printf("Finished minimum calibration \n\r");
    
                EMG_L_max=maximum_L/2560;                               // Divide the summation by the number of measurements (2560 measurements) to get a mean value over 5 seconds
                EMG_R_max=maximum_R/2560;
    
                pc.printf("EMG_L_max = %f \n\r EMG_R_max = %f  \n\r", EMG_L_max, EMG_R_max);

                wait (3);                                               // Cooldown
    
    
//                                      _______________________________________________
//                                     : [THRESHOLDS CALCULATION FROM MIN AND MAX EMG] : 
//                                     :_______________________________________________:
//      

    const float Threshold_Bicep_Left_1=((EMG_L_max-EMG_L_min)*0.2)+EMG_L_min;;     // EMG LEFT: Threshold put at 20% of the EMG range
    const float Threshold_Bicep_Left_2=((EMG_L_max-EMG_L_min)*0.6)+EMG_L_min;      // EMG LEFT: Threshold put at 60% of the EMG range
    const float Threshold_Bicep_Right_1=((EMG_R_max-EMG_R_min)*0.2)+EMG_R_min;     // EMG RIGHT: Threshold put at 20% of the EMG range
    const float Threshold_Bicep_Right_2=((EMG_R_max-EMG_R_min)*0.6)+EMG_R_min;     // EMG RIGHT: Threshold put at 60% of the EMG range

                pc.printf("left 1: %f left 2: %f right 1: %f right 2: %f  \n\r", Threshold_Bicep_Left_1, Threshold_Bicep_Left_2, Threshold_Bicep_Right_1, Threshold_Bicep_Right_2);   
}
        
//                                              ___________________________
//                                            //                           \\
//                                           ||        [TURN PLANT]         ||
//                                            \\___________________________//
  
void execute_plant_turn()
    {   
         if ((motor_turn.getPulses()>4200) || (motor_turn.getPulses()<-4200))                   // If value exceeds -4200 and 4200 (number of counts equal to one revolution) than reset to zero
                { motor_turn.reset(); } 
        
         position_turn = conversion_counts_to_degrees * motor_turn.getPulses();                 // Convert counts to degrees
          
         double pwm_to_motor_turn = PID_control(reference_turn, position_turn, integrate_error_turn, sample_time, previous_error_turn, P_gain_turn, I_gain_turn, D_gain_turn); 
                                                                                                // Execute PID controller and calculate the pwm to put to the motor
        
         keep_in_range(&pwm_to_motor_turn, -1,1);                                               // Pass to the plant but make sure the max and min pwm put to the plant stays between -1 and 1
        
//pc.printf("pwm %f \n\r", pwm_to_motor_turn); // LINE FOR TESTING

         if(pwm_to_motor_turn > 0)                                                               // Check error and decide the direction the motor has to turn
                { motordirection_turn=ccw;}
         else
                { motordirection_turn=cw; }

         pwm_motor_turn=(abs(pwm_to_motor_turn));                                                // Put the absolute value of the PID controller to the pwm (negative pwm does not work)
        
         take_sample();  // TEMPORARY  -> use sample_filter() normally                                      
        
         // sample_filter();
            
         if(sample_error)  // sample_error -- e10;e9;e8;e7;e6;e5:e4;e3;e2;e1 -- error_turn_average --- er 
             {
                    sample_error=false;
                    e1 = (position_turn - reference_turn);
                    e30=e29; e29=e28 ;e28=e27; e27=e26; e26=e25; e25=e24; e24=e23; e23=e22; e22=e21; e21=e20;
                    e20=e19; e19=e18 ;e18=e17; e17=e16; e16=e15; e15=e14; e14=e13; e13=e12; e12=e11; e11=e10;
                    e10=e9 ;e9=e8; e8=e7; e7=e6; e6=e5; e5=e4; e4=e3; e3=e2; e2=e1;
             }
        
         error_turn_average=(e1+e2+e3+e4+e5+e6+e7+e8+e9+e10+e11+e12+e13+e14+e15+e16+e17+e18+e19+e20+e21+e22+e23+e24+e25+e26+e27+e28+e29+e30)/30;
         er++;
         error_count++;
    } 
 
//                                              ___________________________
//                                            //                           \\
//                                           ||       [STRIKE PLANT]        ||
//                                            \\___________________________//
//   
void execute_plant_strike()
    {   
         if ((motor_strike.getPulses()>4200) || (motor_strike.getPulses()<-4200)) // If value is outside -4200 and 4200 (number of counts equal to one revolution) reset to zero
                {
                    motor_strike.reset();
                    pc.printf("RESET \n\r");
                } 
        
         position_strike = conversion_counts_to_degrees * motor_strike.getPulses();
                                            
         double pwm_to_motor_strike=PID_control(reference_strike, position_strike, integrate_error_strike, sample_time, previous_error_strike, P_gain_strike, I_gain_strike, D_gain_strike); 
         keep_in_range(&pwm_to_motor_strike, -1,1);                               // Pass to motor controller but keep it in range!

         if(pwm_to_motor_strike > 0)                                              // Check error and decide direction to turn
                {   motordirection_strike=cw;  }
         else
                {   motordirection_strike=ccw; }
          
          
         if(p==1)                                                                  // p is put to one if return action is put to active
                {  pwm_motor_strike=(abs(pwm_to_motor_strike)); }
        
           
            // TEMPORARY USAGE WHILE POTMETER ACTIVE
        EMG_L_max = 100;                         // Calibreren (max average over 5 seconde?) gemeten integraal EMG over tijd / (tijdsample stappen)=100
        EMG_L_min = 0;
        EMG_R_max = 100;                         // Calibreren
        EMG_R_min = 0;

        const double Threshold_Bicep_Left_1  =((EMG_L_max-EMG_L_min)*0.2)+EMG_L_min;;      //(waarde waarop het gemeten EMG signaal 20% van max het maximale is); // LEFT
        const double Threshold_Bicep_Right_1 =((EMG_R_max-EMG_R_min)*0.2)+EMG_R_min;     //(waarde waarop het gemeten EMG signaal 20% van max het maximale is); // RIGHT
        
                                moving_average_left   = 40;        // TIJDELIJK PID TEST
                                moving_average_right  = 40;        // TIJDELIJK PID TEST
                        double signal_above_threshold=(moving_average_right-Threshold_Bicep_Right_1)+(moving_average_left-Threshold_Bicep_Left_1);
                        double max_signal=(EMG_R_max-Threshold_Bicep_Right_1)+(EMG_L_max-Threshold_Bicep_Left_1);
                        double pwm_strike=signal_above_threshold/max_signal;
                        
//pc.printf("mov_r = %f, mov_l = %f, pwm_strike = %f position = %f \n\r", moving_average_right, moving_average_left, pwm_strike, position_strike); // LINE FOR TESTING

         if(p==0)
                {  pwm_motor_strike=pwm_strike; }
        
         take_sample(); // UITEINDELIJK: UIT
        
        // sample_filter(); --> sample filter aan als EMG
           
        if(sample_error_strike)
            { 
                sample_error_strike=false;
                e1 = fabs(position_strike - reference_strike);
                e30=e29; e29=e28 ;e28=e27; e27=e26; e26=e25; e25=e24; e24=e23; e23=e22; e22=e21; e21=e20;
                e20=e19; e19=e18 ;e18=e17; e17=e16; e16=e15; e15=e14; e14=e13; e13=e12; e12=e11; e11=e10;
                e10=e9 ;e9=e8; e8=e7; e7=e6; e6=e5; e5=e4; e4=e3; e3=e2; e2=e1;
            }
            
        error_strike_average=(e1+e2+e3+e4+e5+e6+e7+e8+e9+e10+e11+e12+e13+e14+e15+e16+e17+e18+e19+e20+e21+e22+e23+e24+e25+e26+e27+e28+e29+e30)/30;
        er++;
        error_count++;
    } 

//                                              ___________________________
//                                            //                           \\
//                                           ||       [PID CONTROLLER]      ||
//                                            \\___________________________//
//                
 double PID_control(double reference, double position, double &integrate_error, double sample_time, double &previous_error, double P_gain, double I_gain, double D_gain) 
        {
        double error=(reference - position);                                        // Current error (input controller)        
        integrate_error=integrate_error_turn + sample_time*error_turn;              // Integral error output
                                                                                            // overwrite previous integrate error by adding the current error 
                                                                                            // multiplied by the sample time.
                                                                                       
        double error_derivative=(error - previous_error)/sample_time;               // Derivative error output
        error_derivative=Lowpassfilter_derivative.step(error_derivative);           // Filter 
        
        previous_error_turn=error_turn;                                                     // current error is saved to memory constant to be used in 
                                                                                            // the next loop for calculating the derivative error  
           
        double pwm_motor_P = error*P_gain;                                          // Output P controller to pwm        
        double pwm_motor_I = integrate_error*I_gain;                                // Output I controller to pwm
        double pwm_motor_D = error_derivative*D_gain;                               // Output D controller to pwm

        double pwm_to_motor = pwm_motor_P + pwm_motor_I + pwm_motor_D;
     
        return pwm_to_motor;
        }

//                                              ___________________________
//                                            //                           \\
//                                           ||           [SAMPLE]          ||
//                                            \\___________________________//
//   
void sample_filter()
{
    Filter();
    take_sample();
    if(sample)
        {
            sample=false;
            Sample_EMG_L_1 = EMG_Left_Bicep_filtered;               Sample_EMG_R_1 = EMG_Right_Bicep_filtered; 
            
            Sample_EMG_L_10= Sample_EMG_L_9;                        Sample_EMG_R_10= Sample_EMG_R_9;
            Sample_EMG_L_9 = Sample_EMG_L_8;                        Sample_EMG_R_9 = Sample_EMG_R_8;
            Sample_EMG_L_8 = Sample_EMG_L_7;                        Sample_EMG_R_8 = Sample_EMG_R_7;
            Sample_EMG_L_7 = Sample_EMG_L_6;                        Sample_EMG_R_7 = Sample_EMG_R_6;
            Sample_EMG_L_6 = Sample_EMG_L_5;                        Sample_EMG_R_6 = Sample_EMG_R_5;
            Sample_EMG_L_5 = Sample_EMG_L_4;                        Sample_EMG_R_5 = Sample_EMG_R_4;
            Sample_EMG_L_4 = Sample_EMG_L_3;                        Sample_EMG_R_4 = Sample_EMG_R_3;
            Sample_EMG_L_3 = Sample_EMG_L_2;                        Sample_EMG_R_3 = Sample_EMG_R_2;
            Sample_EMG_L_2 = Sample_EMG_L_1;                        Sample_EMG_R_2 = Sample_EMG_R_1;
        }
        moving_average_left=Sample_EMG_L_1*0.1+Sample_EMG_L_2*0.1+Sample_EMG_L_3*0.1+Sample_EMG_L_4*0.1+Sample_EMG_L_5*0.1+Sample_EMG_L_6*0.1+Sample_EMG_L_7*0.1+Sample_EMG_L_8*0.1+Sample_EMG_L_9*0.1+Sample_EMG_L_10*0.1;
        moving_average_right=Sample_EMG_R_1*0.1+Sample_EMG_R_2*0.1+Sample_EMG_R_3*0.1+Sample_EMG_R_4*0.1+Sample_EMG_R_5*0.1+Sample_EMG_R_6*0.1+Sample_EMG_R_7*0.1+Sample_EMG_R_8*0.1+Sample_EMG_R_9*0.1+Sample_EMG_R_10*0.1;  
    n++;   
}

//                                              ___________________________
//                                            //                           \\
//                                           ||         [  FILTER  ]        ||
//                                            \\___________________________//
//   
void Filter() // Unfiltered EMG (input) -> highpass filter -> rectify -> lowpass filter -> Filtered EMG (output)
    {
        EMG_left_Bicep = input1;                                                            EMG_Right_Bicep = input2;                                                                // Current input EMG left and right
        
        EMG_Left_Bicep_filtered = highpassfilter_1.step(EMG_left_Bicep);                    EMG_Right_Bicep_filtered = highpassfilter_2.step(EMG_Right_Bicep);                       // Highpassfilter
        EMG_Left_Bicep_filtered = fabs(EMG_Left_Bicep_filtered);                            EMG_Right_Bicep_filtered = fabs(EMG_Right_Bicep_filtered);                               // Rectify
        
        EMG_Left_Bicep_filtered_notch_1 = notchL1.step(EMG_Left_Bicep_filtered);            EMG_Right_Bicep_filtered_notch_1 = notchR1.step(EMG_Right_Bicep_filtered);               // Notch Filter part 1
        EMG_Left_Bicep_filtered_notch_2 = notchL2.step(EMG_Left_Bicep_filtered_notch_1);    EMG_Right_Bicep_filtered_notch_2 = notchR2.step(EMG_Right_Bicep_filtered_notch_1);       // Notch Filter part 2
        
        EMG_Left_Bicep_filtered = lowpassfilter_1.step(EMG_Left_Bicep_filtered_notch_2);    EMG_Right_Bicep_filtered = lowpassfilter_2.step(EMG_Right_Bicep_filtered_notch_2);       // Lowpassfilter
    }

//                                              ___________________________
//                                            //                           \\
//                                           ||        [TAKE SAMPLE]        ||
//                                            \\___________________________//
//      
void take_sample() // Take a sample every 25th sample for moving average, every 5th sample ....
{
        if(n==25)
                 {sample = true; n=0;}
        
        if(er==5)
                 {sample_error = true; er=0;}
        
        sample_error_strike = true;
}

//                                              ___________________________
//                                            //                           \\
//                                           ||     [CHANGE REFERENCE]      ||
//                                            \\___________________________//
//  
void Change_Turn_Position_Right (double& reference, double change_one_bottle)
    {
        if(reference==90)                                   // If reference value at right boundary bottle and function is executed than immediatly turn 5 bottles to the left (ref to -90)
                { reference=-90; }
        else
            {   reference = reference + change_one_bottle;
                keep_in_range(&reference, -90, 90);       } // reference position stays between -90 and 90 degrees (IF bottles at -90, -45, 0, 45, 90 degrees)
    }
    
void Change_Turn_Position_Left (double& reference, double change_one_bottle)
    {
        if(reference==-90)                                  // If reference value at left boundary bottle and function is executed than immediatly turn 5 bottles to the left (ref to +90)
                { reference=90; }
        else
            {   reference = reference - change_one_bottle;
                keep_in_range(&reference, -90, 90);       }
    }

//                                              ___________________________
//                                            //                           \\
//                                           | [(DE)ACTIVATE PID CONTROLLERS] |
//                                            \\___________________________//
//  
void deactivate_PID_Controller(double& P_gain, double& I_gain, double& D_gain)
{
    P_gain=0;         I_gain=0;            D_gain=0;        // Deactivating values of PID controller
    pwm_motor_turn=0; pwm_motor_strike=0;
}

void activate_PID_Controller_turn(double& P_gain, double& I_gain, double& D_gain)
{
    P_gain_turn=0.02;                                       // Change P,I,D values (activate)
    I_gain_turn=0.1; 
    D_gain_turn=0;
}

void activate_PID_Controller_strike(double& P_gain, double& I_gain, double& D_gain)
{
        double Ku  = (input1.read())*1;    // EMG Right bicep (tussen nul en 100%)          // DEBUG TEST TOOL: substitute EMG input for potmeter inputs
        double Pu  = (input2.read())*1;    // EMG Left bicep  (tussen nul en 100%)  

    P_gain_strike=0.8*Ku;      // Ku=0.2 (ultimate gain Ziegler-Nichols method)
                               // Pu=0.25 (ultimate period) (4Hz)
                        
                        pc.printf("Ku=%f Pu=%f \n\r", Ku, Pu); 
     //0.09090909;   
                        //PI tyreus luyben : 0.0625, 0.55;  
                        //PID tyreus luyben : 0.09090909, 0.55, 0.0396825;  
                        // Ku=0.2 (ultimate gain Ziegler-Nichols method)
                        // Pu=0.25 (ultimate period) (4Hz)
     // hier waardes P,I,D veranderen (waardes bovenaan doen (tijdelijk) niks meer        // 0.00045 // 0.03
    I_gain_strike=0;      //0.55; 
    D_gain_strike=Pu/8;      //0.0396825;
}

//                                              ___________________________
//                                            //                           \\
//                                           ||      [OTHER FUNCTIONS]      ||
//                                            \\___________________________//
// 
void countdown_from_5() // Countdown from 5 till 0 inside Putty (interface)
    {
    wait(1); pc.printf("5 \n\r"); wait(1); pc.printf("4 \n\r"); wait(1); pc.printf("3 \n\r"); wait(1); pc.printf("2 Ready \n\r");
    wait(1); pc.printf("1 Set \n\r"); wait(1); pc.printf("Go \n\r");
    }                      
                        
void ControlGo()                        // Control flag
            { control_go = true; }

void setlooptimerflag(void)             // Looptimerflag function
            { looptimerflag = true; }

void red()      { debug_led_red=on;     debug_led_blue=off;  debug_led_green=off;   }
void blue()     { debug_led_red=off;    debug_led_blue=on;   debug_led_green=off;   }
void green()    { debug_led_red=off;    debug_led_blue=off;  debug_led_green=on;    }
void white()    { debug_led_red=on;     debug_led_blue=on;   debug_led_green=on;    }
void yellow()   { debug_led_red=on;     debug_led_blue=off;  debug_led_green=on;    }
void cyan()     { debug_led_red=off;    debug_led_blue=on;   debug_led_green=on;    }
void purple()   { debug_led_red=on;     debug_led_blue=on;   debug_led_green=off;   }
void black()    { debug_led_red=off;    debug_led_blue=off;  debug_led_green=off;   }


void calibrate_potmeter() // DEBUG/TEST: Calibration thresholds with potmeter
     {
        // TEMPORARY USAGE WHILE POTMETER ACTIVE
        EMG_L_max = 100;                      
        EMG_L_min = 0;
        EMG_R_max = 100;
        EMG_R_min = 0;
        Threshold_Bicep_Left_1  =((EMG_L_max-EMG_L_min)*0.2)+EMG_L_min;;      //(waarde waarop het gemeten EMG signaal 20% van max het maximale is); // LEFT
        Threshold_Bicep_Left_2  =((EMG_L_max-EMG_L_min)*0.6)+EMG_L_min;      //(waarde waarop het gemeten EMG signaal 60% van max het maximale is); 
        Threshold_Bicep_Right_1 =((EMG_R_max-EMG_R_min)*0.2)+EMG_R_min;     //(waarde waarop het gemeten EMG signaal 20% van max het maximale is); // RIGHT
        Threshold_Bicep_Right_2 =((EMG_R_max-EMG_R_min)*0.6)+EMG_R_min;     //(waarde waarop het gemeten EMG signaal 60% van max het maximale is);
    }
    
// Keep in range function
void keep_in_range(double * in, double min, double max)                             // Put in certain min and max values that the input needs to stay within
{
    *in > min ? *in < max? : *in = max: *in = min;
}