Script 15-10-2019

Dependencies:   Servoaansturing mbed QEI HIDScope biquadFilter MODSERIAL FastPWM

main.cpp

Committer:
Renate
Date:
2019-10-24
Revision:
20:a6a5bdd7d118
Parent:
19:1fd39a2afc30
Child:
21:456acc79726c

File content as of revision 20:a6a5bdd7d118:

#include "mbed.h"
#include "HIDScope.h"
#include "QEI.h"
#include "MODSERIAL.h"
#include "BiQuad.h"
#include "FastPWM.h"
#include <math.h>
#include "Servo.h"

// Definieer objecten
Serial pc(USBTX, USBRX);

PwmOut motor1(D6);  // Misschien moeten we hiervoor DigitalOut gebruiken, moet 
PwmOut motor2(D5);  // samen kunnen gaan met de servo motor

DigitalOut motor1_dir(D7);
DigitalOut motor2_dir(D4);
  
DigitalIn Power_button_pressed(D1); // Geen InterruptIn gebruiken!
DigitalIn Emergency_button_pressed(D2);

AnalogIn EMG_biceps_right_raw (A0);
AnalogIn EMG_biceps_left_raw (A1);
AnalogIn EMG_calf_raw (A2);

Ticker loop_ticker;
Ticker HIDScope_ticker;
Ticker emgSampleTicker;

bool calib = false; // MOGELIJK GAAT HET HIER FOUT
int i_calib = 0;

HIDScope scope(3);

float mean_EMG_biceps_right;
float mean_EMG_biceps_left;
float mean_EMG_calf;
float normalized_EMG_biceps_right;
float filtered_EMG_biceps_right;
float normalized_EMG_biceps_left;
float filtered_EMG_biceps_left;
float normalized_EMG_calf;
float filtered_EMG_calf;

// Definities voor eerste BiQuadChain (High-pass en Notch)
BiQuadChain bqc; 
BiQuad bq1(0.8006, -1.6012, 0.8006, -1.5610, 0.6414); // High-pass 
BiQuad bq2(1, -1.6180, 1, -1.6019, 0.9801); // Notch

// Na het nemen van de absolute waarde moet de tweede BiQuadChain worden toegepast.
// Definieer (twee Low-pass -> vierde orde verkrijgen):
BiQuadChain bqc2;
BiQuad bq3(1.5515e-4, 3.1030e-4, 1.5515e-4, -1.9645, 0.9651); // Low-pass
BiQuad bq4(1.5515e-4, 3.1030e-4, 1.5515e-4, -1.9645, 0.9651); // Low-pass

void emgSampleFilter() // Deze functie wordt aangeroepen dmv een ticker. Het sampled 
                       // hierdoor het EMG signaal en het haalt er een filter overheen.
                       // Het signaal kan tevens via de HIDScope worden gevolgd. 
                       // Tenslotte wordt er een stuk script gerund, wanneer de robot
                       // zich in de kalibratie toestand bevindt. 
{   
    float filtered_EMG_biceps_right_1=bqc.step(EMG_biceps_right_raw.read());
    float filtered_EMG_biceps_left_1=bqc.step(EMG_biceps_left_raw.read());
    float filtered_EMG_calf_1=bqc.step(EMG_calf_raw.read());
    
    float filtered_EMG_biceps_right_abs=abs(filtered_EMG_biceps_right_1);
    float filtered_EMG_biceps_left_abs=abs(filtered_EMG_biceps_left_1);
    float filtered_EMG_calf_abs=abs(filtered_EMG_calf_1);
    
    float filtered_EMG_biceps_right=bqc2.step(filtered_EMG_biceps_right_abs);
    float filtered_EMG_biceps_left=bqc2.step(filtered_EMG_biceps_left_abs);
    float filtered_EMG_calf=bqc2.step(filtered_EMG_calf_abs);
    
    float filtered_EMG_biceps_right_total=filtered_EMG_biceps_right;
    float filtered_EMG_biceps_left_total=filtered_EMG_biceps_left;
    float filtered_EMG_calf_total=filtered_EMG_calf;
    
    //void sendHIDScope() // Deze functie geeft de gefilterde EMG-signalen weer in de HIDScope
                    // Wordt eveneens gerund dmv een ticker
//{
    /* Set the sampled emg values in channel 0 (the first channel) and 1 (the second channel) in the 'HIDScope' instance named 'scope' */
    scope.set(0, filtered_EMG_biceps_right); // Werkt dit zo? Of nog met .read?
    scope.set(1, filtered_EMG_biceps_left);
    scope.set(2, filtered_EMG_calf);
    /* Repeat the step above if required for more channels of required (channel 0 up to 5 = 6 channels) 
    *  Ensure that enough channels are available (HIDScope scope( 2 ))
    *  Finally, send all channels to the PC at once */
    scope.send();
    // Eventueel nog een ledje laten branden
//}
    
    if (calib) // In de kalibratie staat treedt deze loop in werking. De spier wordt
               // dan maximaal aangespannen (gedurende 5 seconden). De EMG waarden
               // worden bij elkaar opgeteld, waarna het gemiddelde wordt bepaald.
        {   
            if (i_calib < 500)
                {
                    filtered_EMG_biceps_right_total=filtered_EMG_biceps_right+filtered_EMG_biceps_right_total;
                    filtered_EMG_biceps_left_total=filtered_EMG_biceps_left+filtered_EMG_biceps_left_total;
                    filtered_EMG_calf_total=filtered_EMG_calf+filtered_EMG_calf_total;
                    i_calib++;
                }
            if (i_calib >= 500)
                {   
                    float mean_EMG_biceps_right=filtered_EMG_biceps_right_total/500;
                    float mean_EMG_biceps_left=filtered_EMG_biceps_left_total/500;
                    float mean_EMG_calf=filtered_EMG_calf_total/500;
                    calib = false; 
                }
         }
}

// Emergency    
void emergency()
    {
        loop_ticker.detach(); 
        motor1.write(0);
        motor2.write(0);
        pc.printf("Ik ga exploderen!!!\r\n");
        // Alles moet uitgaan (evt. een rood LEDje laten branden), moet 
        // opnieuw worden opgestart. Mogelijk kan dit door de ticker te 
        // detachen
    }    

// Motoren uitzetten    
void motors_off()
    {
        motor1.write(0);
        motor2.write(0);
        pc.printf("Motoren uit functie\r\n");
    }  
    
// Motoren aanzetten
void motors_on()
    {
        motor1.write(0.9);
        motor1_dir.write(1);
        motor2.write(0.1);
        motor1_dir.write(1);
        pc.printf("Motoren aan functie\r\n");
    }
        
// EMG kalibreren        
void  emg_calibration()   
     {
        // Gedurende bijv. 5 seconden EMG meten, wanneer de spieren maximaal
        // worden aangespannen -> maximaal potentiaal verkrijgen. Een fractie 
        // hiervan kan als drempel worden gebruikt voor beweging
        
        // *Tijd instellen* 
        // Iets met DOUBLE_MAX? https://docs.microsoft.com/en-us/cpp/c-language/cpp-integer-limits?view=vs-2019
        
        // Ledje van kleur laten veranderen
        
        // MOGELIJK NIET MEER NODIG???
       
     }

// Finite state machine programming (calibration servo motor?)
enum states {Motors_off, Calib_motor, Calib_EMG, Homing, Operation_mode};

states currentState = Motors_off; 
bool stateChanged = true; // Make sure the initialization of first state is executed

void ProcessStateMachine(void) 
{   
    switch (currentState) 
    { 
        case Motors_off:
        
            if (stateChanged) 
            {
                motors_off(); // functie waarbij motoren uitgaan
                stateChanged = false;
                pc.printf("Motors off state\r\n");
            }          
            if  (Power_button_pressed.read() == false) // Normaal waarde 1 bij indrukken, nu nul -> false
            {      
                motors_on();
                currentState = Calib_motor;
                stateChanged = true;
                pc.printf("Moving to Calib_motor state\r\n");
            }
            if  (Emergency_button_pressed.read() == false) // Normaal waarde 1 bij indrukken, nu nul -> false
            { 
                emergency();
            } 
            break;
            
        case Calib_motor:
            
            if (stateChanged)
            {       
                // Hier wordt een kalibratie uitgevoerd, waarbij de motorhoeken worden bepaald
                currentState = Calib_EMG;
                stateChanged = true;
                pc.printf("Moving to Calib_EMG state\r\n");
            }    
            if  (Emergency_button_pressed.read() == false) 
            { 
                emergency();
            } 
            break;
            
         case Calib_EMG:
            
            motors_off();
            if (stateChanged)
            {
                // Hierbij wordt een een kalibratie uitgevoerd, waarbij de maximale EMG-amplitude waarde wordt bepaald

                calib = true;
                emgSampleFilter(); // Gaat dit nu goed? -> moet sws worden toegevoegd bij relevante onderdelen?
                if (i_calib >= 500) // of wait(10);?
                {
                    currentState = Homing;
                    stateChanged = true;
                    pc.printf("Moving to Homing state\r\n");
                }

                currentState = Homing;
                stateChanged = true;
                pc.printf("Moving to Homing state\r\n");
            }

            if  (Emergency_button_pressed.read() == false) 
            { 
                emergency();
            } 
            break; 
            
         case Homing:
            
            motors_on();
            if (stateChanged)
            {   
                // Ervoor zorgen dat de motoren zo bewegen dat de robotarm 
                // (inclusief de end-effector) in de juiste home positie wordt gezet
                currentState = Operation_mode;
                stateChanged = true;
                pc.printf("Moving to operation mode \r\n");
            }
            if  (Emergency_button_pressed.read() == false) 
            { 
                emergency();
            } 
            break; 
            
         case Operation_mode: // Overgaan tot emergency wanneer referentie niet 
                              // overeenkomt met werkelijkheid
        
            if (stateChanged)
             
                // Hier moet een functie worden aangeroepen die ervoor zorgt dat 
                // aan de hand van EMG-signalen de motoren kunnen worden aangestuurd, 
                // zodat de robotarm kan bewegen   
                
                {
                    float normalized_EMG_biceps_right=filtered_EMG_biceps_right/mean_EMG_biceps_right;
                    float normalized_EMG_biceps_left=filtered_EMG_biceps_left/mean_EMG_biceps_left;
                    float normalized_EMG_calf=filtered_EMG_calf/mean_EMG_calf;
                    
                    if (normalized_EMG_biceps_right >= 0.3)
                        {
                            motor1.write(0.5);
                            motor2.write(0);
                        }
                    if (normalized_EMG_biceps_right < 0.3)
                        {       
                            motor1.write(0);
                            motor2.write(0);
                        }
                    if (normalized_EMG_biceps_left >= 0.3)
                        {
                            motor2.write(0.9);
                            motor1.write(0);
                        }
                    if (normalized_EMG_biceps_left < 0.3)
                        {
                            motor2.write(0);
                            motor1.write(0);
                        }              
                    
                    if (Power_button_pressed.read() == false) // Normaal waarde 1 bij indrukken, nu nul -> false
                        {
                            motors_off();
                            currentState = Motors_off;
                            stateChanged = true;
                            pc.printf("Terug naar de state Motors_off\r\n");
                        }
                    if  (Emergency_button_pressed.read() == false) 
                        { 
                            emergency();
                        } 
                    // wait(5);
                    else 
                        { 
                            currentState = Homing; 
                            stateChanged = true; 
                            pc.printf("Terug naar de state Homing\r\n");
                        }
                    break;
                  
                }   
        
        default:
            // Zelfde functie als die eerder is toegepast om motoren uit te schakelen -> safety!
            motors_off();
            pc.printf("Unknown or uninplemented state reached!\r\n");
            
    }
}

int main(void)
    {
        pc.printf("Opstarten\r\n");
        bqc.add(&bq1).add(&bq2);
        bqc2.add(&bq3).add(&bq4);
        emgSampleTicker.attach(&emgSampleFilter, 0.01f);
        loop_ticker.attach(&ProcessStateMachine, 5.0f);  
        while(true) 
        { /* do nothing */}
    }