Total control sjoel robot

Dependencies:   HIDScope MODSERIAL QEI TextLCD mbed

main.cpp

Committer:
RichardRoos
Date:
2015-10-20
Revision:
37:090ba5b1e655
Parent:
36:549d1ce7b96b

File content as of revision 37:090ba5b1e655:

//--------------------Include files and libraries-------
#include "mbed.h"
#include "QEI.h"
#include "MODSERIAL.h"
#include "TextLCD.h"
#include "HIDScope.h"
#include "Filterdesigns.h"
#include "Kalibratie.h"
#include "Mode.h"
//--------------------Classes------------------------
InterruptIn btnSet(PTC6);           // Kalibration button
DigitalOut ledR(LED_RED), LedB(LED3); // Leds on K64F
MODSERIAL pc(USBTX, USBRX);         // Modserial voor Putty
TextLCD lcd(PTC5, PTC7, PTC0, PTC9, PTC8, PTC1); // LCD screen on inner row of K64F, rs, e, d4-d7
PwmOut servo(D3);                   // PwmOut servo
AnalogIn emgL(A0), emgR(A1);        // Analog input of EMG, left and right
AnalogIn potL(A2), potR(A3);        // Potential meter left and right
AnalogIn KS(A5);                    // Killswitch
HIDScope scope(6);                  // Hidscope, amount of scopes           
Ticker EMGticker, tickerControl, tickerBreak, tickerLcd;   // Ticker for EMG, regulator and break
// QEI Encoder(port 1, port 2, ,counts/rev
    QEI enc1 (D13, D12, NC, 64), enc2 (D11, D10, NC, 64);
// Motor1 met PWM power control and direction
    PwmOut pwmM1(D6);       
    DigitalOut dirM1(D7);
// Motor2 met PWM power control and direction
    PwmOut pwmM2(D5);       
    DigitalOut dirM2(D4);
enum spelfase {CALIBRATE_EMG, CALIBRATE_AIM, CALIBRATE_PEND, AIM, BREAK, FIRE};  // Proframstates, ACKNOWLEDGEMENT switch: BMT groep 4 2014
uint8_t state = CALIBRATE_EMG;     // first state program
enum aimFase {OFF, CW, CCW};         // Aim motor possible states
uint8_t aimState = OFF;              // first state aim motor 
//-------------------------------Variables--------------------------------------------------------------------- 
const int on = 0, off = 1;               // on off
int maxCounts = 13000;                   // max richt motor counts Aim motor
int breakPerc = 0;
const double servoL = 0.001, servoR = 0.0011;    // Range servo,between servoL en servoR  (= pulsewidth pwm servo) 
const double tControl = 0.005, tBreak = 0.1, tLcd = 2;     // tickers  
const double Fs = 50;                           //Sample frequency Hz
double t = 1/ Fs;                               // time EMGticker
double thresholdlowL= 0, thresholdmidL = 0, thresholdhighL= 0;
double thresholdlowR= 0, thresholdmidR = 0, thresholdhighR= 0;
double yL = 0, yR = 0;                      // y values EMG left and right
volatile bool L = false, R = false;         // Booleans for checking if mode. has been 1?
volatile bool btn = false;                  // Button is pressed?
volatile bool controlFlag = false, btnFlag = false, breakFlag = false, emgFlag = false, lcdFlag = false;     // Go flags
//----------------------------Functions-----------------------------------------------------------------------
void flipLed(DigitalOut& led){              //function to flip one LED   
    led.write(on);
    wait(0.2);
    led.write(off);
    }
void PRINT(const char* text){                
    lcd.cls();                              // clear LCD scherm
    lcd.printf(text);                       // print text op lcd    
    }
void EMGkalibratieL(){                       // Determine thresholds left    
    PRINT("EMG LEFT         relax muscle");    
    double ymin = KalibratieMin(emgL, true);    // Minimum value left EMG, boolean indicates left
    wait(1);
    PRINT("EMG LEFT         flex muscle");      // LCD
    double ymax = KalibratieMax(emgL, true);    // Maxium value left EMG, boolean indicates left
    PRINT("EMG LEFT         well done!");       // LCD
    
    if((ymax-ymin) < 0.05){                 // No EMG connected
        ymin = 10;
        ymax = 10;
        }    
    thresholdlowL = 4 * ymin;               // Lowest threshold
    thresholdmidL = 0.5 * ymax;             // Midi threshold
    thresholdhighL = 0.8 * ymax;            // Highest threshold

    pc.printf("ymaxL = %f en yminL = %f \r\n",ymax, ymin);
    }
void EMGkalibratieR(){                       // Determine thresholds right EMG, same as left
    PRINT("EMG RIGHT        relax muscle");        
    double ymin = KalibratieMin(emgR, false);
    wait(1);
    PRINT("EMG RIGHT         flex muscle"); 
    double ymax = KalibratieMax(emgR, false);
    PRINT("EMG LEFT         well done!");
    
    if((ymax-ymin) < 0.05){                 
        ymin = 10;
        ymax = 10;
        }        
    thresholdlowR = 4 * ymin; 
    thresholdmidR = 0.5 * ymax; 
    thresholdhighR = 0.8 * ymax;

    pc.printf("ymaxR = %f en yminR = %f \r\n",ymax, ymin); // terminal
    }
int EMGfilter(AnalogIn& emg, bool side){    
    double u = emg.read();                      // read emg signal (left or right EMG)    
    int mode = 1;
    if(side){
        double y = FilterdesignsLeft(u);                // filter signal left EMG                               
        mode = Mode(y, thresholdlowL, thresholdmidL, thresholdhighL); // Determine mode with thresholds (1, 2, 3)
        }
    else {
        double y = FilterdesignsRight(u);                                               
        mode = Mode(y, thresholdlowR, thresholdmidR, thresholdhighR);   // right EMG
        }          
    return mode;
    }    
int PotReader(AnalogIn& pot){                   // read potentialmeter and determine its mode (1 = default, 2, 3)
    double volt = pot.read();
    int mode = 1;    
    if(volt > 0.8){
        mode = 3;
        }
    else if(volt>0.35 && volt<0.65){
        mode = 2;
        }    
    return mode;    
    }    
int defMode(AnalogIn& emg, AnalogIn& pot, bool side){       // Determine mode both from EMG and Potentialmeter, ONE of them must be ONE!
    int emgMode = EMGfilter(emg, side);
    int potMode = PotReader(pot);
    int mode = 1;    
    if(!(emgMode==1) != !(potMode==1)){                     // emgMode = 1 XOR potMode = 1
        if(emgMode > potMode){                              // maximum of emg and pot
            mode = emgMode;
            }
        else{
            mode = potMode;
            }
        }    
    return mode;       
    }        
void setEmgFlag(){                  // Goflag EMG
    emgFlag = true;
    } 
void setLcdFlag(){                  // Goflag EMG
    lcdFlag = true;
    }  
void btnSetAction(){                // Set knop K64F
    btn = true;                     // GoFlag setknop 
    } 
void setControlFlag(){             // Go flag setButton     
    controlFlag = true;
    }
void setBreakFlag(){                  // Go flag Break 
    breakFlag = true;
    }  
void checkAim(){                    // check if Killswitch is on or max counts is reached
    double volt = KS.read();    
    if(volt> 0.5 || abs(enc2.getPulses()) > (maxCounts -50) || enc2.getPulses() < 0){
        pwmM2.write(0);                                 // Aim motor freeze
        pc.printf("BOEM! CRASH! KASTUK! \r\n");         // Terminal
        PRINT("BOEM! CRASH!");                          // LCD
        }
    }
void motorAim(int dir){            // Rotate Aim motor with given direction
    dirM2.write(dir);              
    pwmM2.write(0.25);              
    }    
bool controlAim(){                  // Function to control aim motor with modes
    bool both = false;              // boolean if both modes are 3       
    int modeL = defMode(emgL, potL, true);
    int modeR = defMode(emgR, potR, false);    
    
    scope.set(0, modeL);
    scope.set(1, modeR);    
    scope.send();                               //send values to HIDScope
    
    if(modeR < 2 && !R){                        // control if mode has been 1
        R = true;        
        }
    if(modeL < 2 && !L){
        L = true;        
        }
                
    if((modeL>2) && (modeR >2 && R && L)) {             // mode L and mode R both 3, and both has been 1 herefore 
        both = true;                                    // Return true
        pwmM2.write(0);                                 // Aim motor freeze
        aimState = OFF;                                 // next state
        }    
    else if((modeR == 2) && (modeL == 2)) {             // modes are both 2
        if(aimState!=OFF){                              // only if aim motor is rotating
            pwmM2.write(0);                             // Aim motor freeze       
            aimState = OFF;                             // motor state is off    
            pc.printf("Motor freeze\r\n");              // LCD
            L = false;                                  // Modes must be first 1 for another action
            R = false;                                  // "" 
            }
        } 
    else if((modeL == 2) && (aimState != CCW && (modeR == 1))) {        // modeL ==2 AND rotation is not CCW AND modeR has been 1
        if(L){                    
            aimState = CCW;                                 // Rotate CCW
            pc.printf("Rotate -, CCW\r\n");
            motorAim(0);
            }
        } 
    else if((modeR == 2) && (aimState != CW && (modeL == 1))) {         // modeR == 2 AND rotation is not CW AND modeL has been 1
        if(R){
            aimState = CW;                                  // Rotate CW
            pc.printf("Rotate +, CW\r\n");
            motorAim(1);
            }
        }    
    return both;            
    }               
int main(){
    flipLed(ledR);                                      // test if code begins    
    btnSet.mode(PullUp);                                // Button mode
    btnSet.rise(&btnSetAction);                         // Connect button to function   
    tickerControl.attach(&setControlFlag,tControl);  // ticker control motor    
    tickerBreak.attach(&setBreakFlag,tBreak);                 // ticker break     
    EMGticker.attach(&setEmgFlag, t);                   // ticker EMG, 500H
    tickerLcd.attach(&setLcdFlag,tLcd);                 // ticker lcd   
        
    pc.printf("\n\n\n\n\n");                            // Terminal
    pc.printf("---NEW GAME---\r\n");                          
    PRINT("--- NEW GAME ---");                          // LCD
    while(1){                                           // Run program
        switch(state){
            case CALIBRATE_EMG: {               
                EMGkalibratieL();                       // calibrate left EMG, determine thresholds                           
                EMGkalibratieR();                       // calibrate right EMG, determine thresholds                                  
                state = CALIBRATE_AIM;                  // Next state
                break;
                }
            case CALIBRATE_AIM: {
                pwmM2.period(1/100000);                 // period motor 2
                printf("Position is kalibrating\r\n");  // terminal
                PRINT("Wait a moment,   please");       // LCD                          
                dirM2.write(0);                         // direction aim motor
                pwmM2.write(0.1);                      // percentage motor power
                bool calibrated = false;                //                       
                while(state==CALIBRATE_AIM){                    
                    pc.printf("Killswitch: %f\r\n", KS.read()); // terminal
                    if(KS.read() > 0.5){                // Killswitch? //2* gedaan, zodat breuk uit de if-statement is
                        pwmM2.write(0);                 // Aim motor freeze
                        enc2.reset();                   // Reset encoder 
                        PRINT("Aim calibrated");        // LCD                        
                        calibrated = true;              // 
                        state = CALIBRATE_PEND;       // next state
                        //dirM2.write(1);                 // direction aim motor
                        //pwmM2.write(0.25);              // percentage motor power, turn it on                     
                        }  
                        /*                  
                    if(controlFlag && calibrated){       // motor regelen op GoFlag
                        controlFlag = false;                    
                        if(enc1.getPulses() > maxCounts/2){  // rotate aim motor to midi position
                            pwmM2.write(0);                 // Aim motor freeze
                            state = CALIBRATE_PEND;       // next state
                            }                      
                        }    */ 
                    }
                break;
                }            
            case CALIBRATE_PEND: {
                pc.printf("Calibrate beam motor with setknop\r\n");     // Terminal       
                pwmM1.period(1/100000);         // period beam motor       
                servo.period(0.02);             // 20ms period servo
                //pwmM1.write(0.25);               // Turn motor on, low power
                btn = false;                    // Button is unpressed
                R = false;                      // modeR must become 1
                L = false;                      // modeL must become 1
                PRINT("Calibrate beam   to 10 o'clock");
                wait(1);                
                PRINT("Flex right half to swing beam");                                  
                while(state==CALIBRATE_PEND){                    
                    if(emgFlag){                        
                        pc.printf("");          // lege regel printen, anders doet setknop het niet
                        emgFlag = false;
                        
                        int modeL = defMode(emgL, potL, true);          // determine modeL
                        int modeR = defMode(emgR, potR, false);         // determine modeR 
                        
                        if(modeR < 2) {           // modeR == 1
                            R = true;
                            }
                        if(modeL < 2) {           // modeL == 1
                            L = true;
                            }                                                                                                                   
                        if (btn || (modeL == 3 && L) || (modeR == 3 && R)){               // If setbutton is on or one mode is 3, and has been 1 
                            pwmM1.write(0);             // Motor 1 freeze
                            enc1.reset();               // encoder 1 reset
                            PRINT("Beam calibrated");
                            btn = false;                // button op false
                            state = AIM;                // next state                          
                            }
                        else if(modeL == 2){
                            pwmM1.write(0);             // beam freeze
                            PRINT("Flex both full  to continue");               // LCD
                            }
                        else if(modeR == 2){
                            pwmM1.write(0.025);         // beam rotate
                            PRINT("Flex left half  to stop beam");              // LCD
                            }
                        }             
                    }
                lcd.cls();
                break;
                }
            case AIM: {                  
                pc.printf("Aim with EMG\r\n");              // terminal                   
                int i = 0;                                  // counter for lcd      
                while(state == AIM){
                    if(lcdFlag){                            // LCD loopje to project 3 texts on lcd
                        lcdFlag = false;
                        if(i%3 == 0){
                            PRINT("Flex left or     right half to aim");
                            }
                        else if(i%3 == 1){
                            PRINT("Flex both half   to freeze");
                            }
                        else {
                            PRINT("Flex both full   to continue");
                            }
                        i++;
                        }           
                                   
                    if(controlFlag){                   // motor control on GoFlag
                        controlFlag = false;                  
                        checkAim();                     // Check position                       
                        }
                    if(emgFlag){                        // Go flag EMG sampel
                        emgFlag = false;                                                            
                        if(controlAim()){                                                                   
                            pc.printf("Position chosen\r\n");       // terminal                        
                            state = BREAK;                // Next state (BREAK)                       
                            }                      
                        }
                    }
                lcd.cls();            
                break;
                }
            case BREAK: {                
                pc.printf("Set break percentage, current is: %.0f\r\n", breakPerc);
                L = false;
                R = false;
                int i = 0;                                  // counter for lcd      
                while(state == BREAK){
                    if(lcdFlag){                            // LCD loop to project text on LCD
                        lcdFlag = false;
                        if(i%2 == 0){
                            PRINT("Flex L or R to   adjust break");
                            }
                        else {
                            PRINT("Flex both        to continue");
                            }
                        i++;
                        }                                    
                    if(emgFlag){            // Go flag EMG sampelen
                        emgFlag = false;                        
                        int modeL = defMode(emgL, potL, true);
                        int modeR = defMode(emgR, potR, false);
                                                                                  
                        if(modeR < 2) {           // modeR is 1
                            R = true;
                            }
                        if(modeL < 2) {           // modeL is 1
                            L = true;
                            }
                        if(L && R){                    
                            if((modeL > 1) && modeR > 1) {     // both modes                                                                                               
                                state = FIRE;
                                R = false;
                                L = false;
                                }
                            else if(modeL > 2 || modeR > 2) {   // left of right mode 3 = fire                      
                                state = FIRE;
                                R = false;
                                L = false;
                                }                            
                            else if((modeL == 2) && L) {      // modeL = BREAK lower with one
                                if(breakPerc>1){
                                    breakPerc--;              
                                    }
                                L = false;                                
                                } 
                            else if((modeR == 2) && R) {      // modeR = Break +1
                                if(breakPerc<10){
                                    breakPerc++;              
                                    }
                                R = false;                        
                                }                         
                            if(modeL > 1 || modeR > 1){               // Print BREAK scale if one of both modes > 1
                                pc.printf("Current breaking scale: %i\r\n", breakPerc);
                                lcd.cls();
                                lcd.printf("Break scale: %i", breakPerc); 
                                }                     
                            }                    
                        }
                    }
                L = false;      // modeL must be one for another action can take place
                R = false;      // modeR ""
                lcd.cls();                            
                break;
                }                    
            case FIRE: {            
                pc.printf("Shooting\r\n");
                PRINT("FIRING");
                servo.pulsewidth(servoL);       // BREAK release
                pwmM1.write(0.25);              // beam motor on               
                bool servoPos = true;                                                
                while(state == FIRE){           // while in FIRE state
                    if(breakFlag && (abs(enc1.getPulses())-100)%4200 < (2100*abs(breakPerc)/10)){             // BREAK goFlag half rotation beam = breaking
                        breakFlag = false;
                        if(servoPos){                        
                            servoPos = false;
                            servo.pulsewidth(servoL);       // left   
                            }
                        else{
                            servoPos = true;
                            servo.pulsewidth(servoR);       // right
                            }            
                        }                                    
                    if(controlFlag){
                        controlFlag = false;                                                                                                                        
                        if((abs(enc1.getPulses())+50)%4200 < 150){    // rotate beam one revolution
                            pwmM1.write(0);                      // motor beam off
                            pc.printf("Beam on startposition\r\n");
                            state = AIM;                        // Next stage
                            }                           
                        }                       
                    }
                lcd.cls();                                                     
                break;
                }
            }
        }
    }