mbed motor control with emg

Dependencies:   Encoder HIDScope MODSERIAL QEI TextLCD biquadFilter mbed

Fork of 2MotorPID by Adam Bako

Revision:
3:c63c0a23ea21
Parent:
2:69bfc537508f
Child:
4:ca797e7daaf4
--- a/main.cpp	Thu Nov 02 18:37:18 2017 +0000
+++ b/main.cpp	Fri Nov 03 11:09:30 2017 +0000
@@ -7,6 +7,8 @@
 #include "QEI.h"
 #include "math.h"
 #include "iostream"
+#include "BiQuad.h"
+#include "TextLCD.h"
 #include "MODSERIAL.h"
 
 //intialize all pins
@@ -18,8 +20,15 @@
 QEI motor2Encoder (D12,D13, NC, 624,QEI::X4_ENCODING);
 DigitalIn button1(D8); //button to move cw
 DigitalIn button2(D9); //button to move ccw
-DigitalIn button3(D2);
-DigitalIn button4(D3);
+//DigitalIn button3(D2);
+//DigitalIn button4(D3);
+AnalogIn bicepsEMG(A0);
+AnalogIn tricepsEMG(A1);
+AnalogIn carpiFlexEMG(A2);
+AnalogIn palmarisEMG(A3);
+DigitalOut bit1(D2);
+DigitalOut bit2(D14);
+DigitalOut bit3(D15);
 MODSERIAL pc(USBTX, USBRX);
 
 //initialize variables
@@ -30,9 +39,9 @@
 const double motor1KI=3.0; //Integral gain of motor1 PI control
 const double motor1KD=3.0; // Differential gain of motor1 PID control
 
-const double motor2KP=1.3; //Proportional gain of motor1 PI control
-const double motor2KI=0.5; //Integral gain of motor1 PI control
-const double motor2KD=1.0; // Differential gain of motor1 PID control
+const double motor2KP=1.3; //Proportional gain of motor2 PI control
+const double motor2KI=0.5; //Integral gain of motor2 PI control
+const double motor2KD=1.0; // Differential gain of motor2 PID control
 
 const double N=100; //LP filter coefficient
 const double encoderToMotor= 0.000119047619047619; //proportion of the rotation of the motor to the rotation of the encoder
@@ -44,10 +53,99 @@
 
 double motor2ErrorInt=0; //error of motor1 for the integrating part of PI controller
 double motor2ErrorDif=0; //error of motor1 for the integrating part of PI controller
-double desiredAngle2 =0; //desired position of motor1
+double desiredAngle2 =0; //desired position of motor2
 //initialize ticker for checking and correcting the angle
 Ticker myControllerTicker;
 
+enum States {off,motorCalib, bicepsCalib, tricepsCalib, carpiCalib, palmarisCalib, demo, EMGControl};
+States state=off;
+bool stateChange=false;
+Timer flex;
+
+double tickerF =0.002;
+double bicepsMOVAG [20];
+double tricepsMOVAG [20];
+double carpiFlexMOVAG [20];
+double palmarisMOVAG [20];
+int MOVAGLength=20;
+
+//Notch Filter 50Hz Q of 0.7
+
+double bicepsNotcha0 = 0.7063988100714527;
+double bicepsNotcha1 = -1.1429772843080923;
+double bicepsNotcha2 = 0.7063988100714527;
+double bicepsNotchb1 = -1.1429772843080923;
+double bicepsNotchb2 = 0.41279762014290533;
+
+double tricepsNotcha0 = 0.7063988100714527;
+double tricepsNotcha1 = -1.1429772843080923;
+double tricepsNotcha2 = 0.7063988100714527;
+double tricepsNotchb1 = -1.1429772843080923;
+double tricepsNotchb2 = 0.41279762014290533;
+
+double carpiFlexNotcha0 = 0.7063988100714527;
+double carpiFlexNotcha1 = -1.1429772843080923;
+double carpiFlexNotcha2 = 0.7063988100714527;
+double carpiFlexNotchb1 = -1.1429772843080923;
+double carpiFlexNotchb2 = 0.41279762014290533;
+
+double palmarisNotcha0 = 0.7063988100714527;
+double palmarisNotcha1 = -1.1429772843080923;
+double palmarisNotcha2 = 0.7063988100714527;
+double palmarisNotchb1 = -1.1429772843080923;
+double palmarisNotchb2 = 0.41279762014290533;
+
+//Highpass filters 20Hz cutoff Q of 0.7
+double bicepsHigha0 = 0.8370879899975344;
+double bicepsHigha1 = -1.6741759799950688;
+double bicepsHigha2 = 0.8370879899975344;
+double bicepsHighb1 = -1.6474576182593796;
+double bicepsHighb2 = 0.7008943417307579;
+
+double tricepsHigha0 = 0.8370879899975344;
+double tricepsHigha1 = -1.6741759799950688;
+double tricepsHigha2 = 0.8370879899975344;
+double tricepsHighb1 = -1.6474576182593796;
+double tricepsHighb2 = 0.7008943417307579;
+
+double carpiFlexHigha0 = 0.8370879899975344;
+double carpiFlexHigha1 = -1.6741759799950688;
+double carpiFlexHigha2 = 0.8370879899975344;
+double carpiFlexHighb1 = -1.6474576182593796;
+double carpiFlexHighb2 = 0.7008943417307579;
+
+double palmarisHigha0 = 0.8370879899975344;
+double palmarisHigha1 = -1.6741759799950688;
+double palmarisHigha2 = 0.8370879899975344;
+double palmarisHighb1 = -1.6474576182593796;
+double palmarisHighb2 = 0.7008943417307579;
+
+BiQuad bicepsNotch (bicepsNotcha0,bicepsNotcha1,bicepsNotcha2,bicepsNotchb1,bicepsNotchb2);
+BiQuad tricepsNotch (tricepsNotcha0,tricepsNotcha1,tricepsNotcha2,tricepsNotchb1,tricepsNotchb2);
+BiQuad carpiFlexNotch (carpiFlexNotcha0,carpiFlexNotcha1,carpiFlexNotcha2,carpiFlexNotchb1,carpiFlexNotchb2);
+BiQuad palmarisNotch (palmarisNotcha0,palmarisNotcha1,palmarisNotcha2, palmarisNotchb1,palmarisNotchb2);
+
+BiQuad bicepsHigh (bicepsHigha0,bicepsHigha1,bicepsHigha2,bicepsHighb1,bicepsHighb2);
+BiQuad tricepsHigh (tricepsHigha0,tricepsHigha1,tricepsHigha2,tricepsHighb1,tricepsHighb2);
+BiQuad carpiFlexHigh (carpiFlexHigha0,carpiFlexHigha1,carpiFlexHigha2,carpiFlexHighb1,carpiFlexHighb2);
+BiQuad palmarisHigh (palmarisHigha0,palmarisHigha1,palmarisHigha2, palmarisHighb1,palmarisHighb2);
+
+double bicepsAvg;
+double tricepsAvg;
+double carpiFlexAvg;
+double palmarisAvg;
+
+double bicepsMax=0;
+double tricepsMax=0;
+double carpiFlexMax=0;
+double palmarisMax=0;
+
+double bicepsMulti=0;
+double tricepsMulti=0;
+double carpiFlexMulti=0;
+double palmarisMulti=0;
+Ticker filterTicker;
+
 const float l1 = 460; //Length of the arm from base to joint 1 (arm1)   ENTER MANUALLY [mm]
 const float l2 = 450; //length of the arm from joint 1 to the end-effector.(arm2)   ENTER MANUALLY [mm]
 float x_des = l1+l2; //(initial)desired x location of the end-effector (ee)
@@ -72,6 +170,158 @@
     return u;
 }
 
+void sendState(States s)
+{
+    if(s==motorCalib) {
+        bit1=1;
+        bit2=0;
+        bit3=0;
+    } else if(s==bicepsCalib) {
+        bit1=0;
+        bit2=1;
+        bit3=0;
+    } else if(s==tricepsCalib) {
+        bit1=1;
+        bit2=1;
+        bit3=0;
+    } else if(s==carpiCalib) {
+        bit1=0;
+        bit2=0;
+        bit3=1;
+    } else if(s==palmarisCalib) {
+        bit1=1;
+        bit2=0;
+        bit3=1;
+    } else if(s==demo) {
+        bit1=0;
+        bit2=1;
+        bit3=1;
+    } else if(s==EMGControl) {
+        bit1=1;
+        bit2=1;
+        bit3=1;
+    }
+}
+
+void filterBiceps()
+{
+    double bicepsSignal = bicepsEMG.read();
+    double bicepsFiltered = bicepsSignal;
+
+    //Filter out 50Hz from all signals
+    bicepsFiltered = bicepsNotch.step(bicepsFiltered);
+
+    //Highpass filtering
+    bicepsFiltered = bicepsHigh.step(bicepsFiltered);
+    //Rectification
+    bicepsFiltered = fabs(bicepsFiltered);
+
+    //caculate moving average
+    for(int i=0; i<MOVAGLength-1; i++) {
+        bicepsMOVAG[i]=bicepsMOVAG[i+1];
+    }
+
+    bicepsMOVAG[MOVAGLength-1]=bicepsFiltered;
+
+    double bicepsSum;
+
+    for(int i=0; i<MOVAGLength; i++) {
+        bicepsSum+= bicepsMOVAG[i];
+    }
+
+    bicepsAvg= bicepsSum/MOVAGLength;
+}
+void filterTriceps()
+{
+    double tricepsSignal = tricepsEMG.read();
+    double tricepsFiltered = tricepsSignal;
+
+    //Filter out 50Hz from all signals
+    tricepsFiltered = tricepsNotch.step(tricepsFiltered);
+
+    //Highpass filtering
+    tricepsFiltered = tricepsHigh.step(tricepsFiltered);
+
+    //Rectification
+    tricepsFiltered = fabs(tricepsFiltered);
+
+    //caculate moving average
+    for(int i=0; i<MOVAGLength-1; i++) {
+        tricepsMOVAG[i]=tricepsMOVAG[i+1];
+    }
+
+    tricepsMOVAG[MOVAGLength-1]=tricepsFiltered;
+
+    double tricepsSum;
+
+    for(int i=0; i<MOVAGLength; i++) {
+        tricepsSum+= tricepsMOVAG[i];
+    }
+    tricepsAvg= tricepsSum/MOVAGLength;
+}
+
+void filterCarpiFlex()
+{
+    double carpiFlexSignal = carpiFlexEMG.read();
+    double carpiFlexFiltered = carpiFlexSignal;
+
+    //Filter out 50Hz from all signals
+    carpiFlexFiltered = carpiFlexNotch.step(carpiFlexFiltered);
+
+    //Highpass filtering
+    carpiFlexFiltered = carpiFlexHigh.step(carpiFlexFiltered);
+
+    //Rectification
+    carpiFlexFiltered = fabs(carpiFlexFiltered);
+
+    //caculate moving average
+    for(int i=0; i<MOVAGLength-1; i++) {
+        carpiFlexMOVAG[i]=carpiFlexMOVAG[i+1];
+    }
+
+    carpiFlexMOVAG[MOVAGLength-1]=carpiFlexFiltered;
+
+    double carpiFlexSum;
+    for(int i=0; i<MOVAGLength; i++) {
+        carpiFlexSum+= carpiFlexMOVAG[i];
+    }
+
+    carpiFlexAvg= carpiFlexSum/MOVAGLength;
+}
+void filterPalmaris()
+{
+    double palmarisSignal = palmarisEMG.read();
+    double palmarisFiltered = palmarisSignal;
+
+    //Filter out 50Hz from all signals
+    palmarisFiltered = palmarisNotch.step(palmarisFiltered);
+
+    //Highpass filtering
+    palmarisFiltered = palmarisHigh.step(palmarisFiltered);
+
+    //Rectification
+    palmarisFiltered = fabs(palmarisFiltered);
+
+    //caculate moving average
+    for(int i=0; i<MOVAGLength-1; i++) {
+        palmarisMOVAG[i]=palmarisMOVAG[i+1];
+    }
+    palmarisMOVAG[MOVAGLength-1]=palmarisFiltered;
+
+    double palmarisSum;
+    for(int i=0; i<MOVAGLength; i++) {
+        palmarisSum+= palmarisMOVAG[i];
+    }
+    palmarisAvg= palmarisSum/MOVAGLength;
+}
+void filter()
+{
+    filterBiceps();
+    filterTriceps();
+    filterCarpiFlex();
+    filterPalmaris();
+}
+
 //Code for motor angles as a function of the length and positions of the arms, for a double revolutional joint arm in 2D plane
 void motorAngle()
 {
@@ -81,40 +331,57 @@
 //Works for all 4 quadrants of the (unit) circle
     xe = x_des;
     ye = y_des;
+    
+   //while(pow(xe, 2)+pow(ye,2) > pow(l1+l2, 2)){ //when attempted to go to a point out of reach
+//       if (y_des == 0){    //make sure you do not divide by 0 if ye == 0
+//           xe = x_des - 1;
+//       } else {
+//           xe = x_des - (x_des/y_des)/10; //go to a smaller xe point on the same line
+//       }
+//       if (x_des == 0){    //make sure you do not divide by 0 if xe == 0
+//           ye = y_des - 1;
+//       } else {
+//           ye = y_des - (y_des/x_des)/10; //go to a smaller ye point on the same line
+//       }
+//       x_des = xe;
+//       y_des = ye;
+//   }
 
-    while(pow(xe, 2)+pow(ye, 2) > pow(l1+l2, 2)) {
-        if (xe > 0) {            //right hand plane
-            if (ye > 0) {        //positive x & y            QUADRANT 1
-                xe = x_des - (x_des/y_des);   //go to a smaller xe point on the same line
-                ye = y_des - (y_des/x_des);   //go to a smaller ye point on the same line
-            } else if (ye < 0) { //positive x, negative y    QUADRANT 2
-                xe = x_des - (x_des/y_des);   //smaller xe
-                ye = y_des + (y_des/x_des);   //greater ye
-            } else if (ye == 0) { //positive x, y == 0
-                xe = x_des - 1;                  //stay on the x-axis but at a smaller value (within reach)
-            }
-        } else if (xe < 0) {     //left hand plane
-            if (ye > 0) {        //negative x, positive y    QUADRANT 4
-                xe = x_des + (x_des/y_des);   //greater xe
-                ye = y_des - (y_des/x_des);   //smaller ye
-            } else if (ye < 0) { //negative x & y            QUADRANT 3
-                xe = x_des + (x_des/y_des);   //greater xe
-                ye = y_des + (y_des/x_des);   //greater ye
-            } else if (ye ==0) { //negative x, y == 0
-                xe = x_des + 1;                  //stay on the x-axis but at a greater value (within reach)
-            }
 
-        } else if (xe == 0) {    //on the y-axis
-            if (ye > 0) {        //x == 0, positive y
-                ye = y_des - 1;                  //stay on the y-axis but at a smaller value (within reach)
-            } else if (ye < 0) { //x == 0, negative y
-                ye = y_des + 1;                  //stay on the y-axis but at a greater value (within reach)
-                //x == 0 & y == 0 is a state that is unable to be reached, no need to cover that case
-            }
-            x_des = xe;
-            y_des = ye;
-        }
-    }
+   // while(pow(xe, 2)+pow(ye, 2) > pow(l1+l2, 2)) {
+//        if (xe > 0) {            //right hand plane
+//            if (ye > 0) {        //positive x & y            QUADRANT 1
+//                xe = x_des - (x_des/y_des);   //go to a smaller xe point on the same line
+//                //(x_des/y_des) can be multiplied or divided to make bigger or smaller steps back if you're trying to exceed max. reach
+//                ye = y_des - (y_des/x_des);   //go to a smaller ye point on the same line
+//            } else if (ye < 0) { //positive x, negative y    QUADRANT 2
+//                xe = x_des - (x_des/y_des);   //smaller xe
+//                ye = y_des + (y_des/x_des);   //greater ye
+//            } else if (ye == 0) { //positive x, y == 0
+//                xe = x_des - 1;                  //stay on the x-axis but at a smaller value (within reach)
+//            }
+//        } else if (xe < 0) {     //left hand plane
+//            if (ye > 0) {        //negative x, positive y    QUADRANT 4
+//                xe = x_des + (x_des/y_des);   //greater xe
+//                ye = y_des - (y_des/x_des);   //smaller ye
+//            } else if (ye < 0) { //negative x & y            QUADRANT 3
+//                xe = x_des + (x_des/y_des);   //greater xe
+//                ye = y_des + (y_des/x_des);   //greater ye
+//            } else if (ye ==0) { //negative x, y == 0
+//                xe = x_des + 1;                  //stay on the x-axis but at a greater value (within reach)
+//            }
+//
+//        } else if (xe == 0) {    //on the y-axis
+//            if (ye > 0) {        //x == 0, positive y
+//                ye = y_des - 1;                  //stay on the y-axis but at a smaller value (within reach)
+//            } else if (ye < 0) { //x == 0, negative y
+//                ye = y_des + 1;                  //stay on the y-axis but at a greater value (within reach)
+//                //x == 0 & y == 0 is a state that is unable to be reached, no need to cover that case
+//            }
+//            x_des = xe;
+//            y_des = ye;
+//        }
+//    }
 
 
 //from here on is the code for setting the angles for the motors
@@ -178,28 +445,154 @@
     pc.printf("xloc = %f, yloc = %f \n \r", xe, ye);
     pc.printf("q1 = %f[rad], desA1 = %f [abs rot], q2 = %f[rad], desA2 = %f[abs rot]\n \r", q1, desiredAngle1, q2, desiredAngle2);
     myControllerTicker.attach(&motorButtonController, controllerTickerTime);
-    while(1) {
+    bit1=0;
+    bit2=0;
+    bit3=0;
+    wait(5);
+    for(int i=0; i<MOVAGLength; i++) {
+        bicepsMOVAG[i]=0;
+        tricepsMOVAG[i]=0;
+        carpiFlexMOVAG[i]=0;
+        palmarisMOVAG[i]=0;
+    }
+    filterTicker.attach(filter,tickerF);
+
+    //start up
+    state=bicepsCalib;
+    stateChange=true;
+
+    while(true) {
         if(!button1) {
-            y_des += positionIncrement;
+            x_des -= positionIncrement;
             motorAngle();
-            wait(0.3f);
+            wait(0.4f);
         }
 
         if(!button2) {
-            y_des -= positionIncrement;
+            x_des += positionIncrement;
             motorAngle();
-            wait(0.3f);
+            wait(0.4f);
         }
-
-        if(button3) {
+        if(bicepsAvg*bicepsMulti > 0.9){
+            x_des -= positionIncrement;
+            motorAngle();
+            wait(0.5f);    
+        }
+        if(tricepsAvg*tricepsMulti > 0.9){
             x_des += positionIncrement;
             motorAngle();
-            wait(0.3f);
+            wait(0.5f);
         }
-        if(button4) {
-            x_des -= positionIncrement;
-            motorAngle();
-            wait(0.3f);
+//
+//        if(button3) {
+//            x_des += positionIncrement;
+//            motorAngle();
+//            wait(0.3f);
+//        }
+//        if(button4) {
+//            x_des -= positionIncrement;
+//            motorAngle();
+//            wait(0.3f);
+//        }
+        if(stateChange) {
+            switch(state) {
+                case motorCalib  :
+                    stateChange=false;
+                    sendState(motorCalib);
+                    break;
+                case bicepsCalib  :
+                    stateChange=false;
+                    sendState(bicepsCalib);
+                    wait(5);
+                    flex.reset();
+                    flex.start();
+                    while(flex.read()<2) {
+                        if(bicepsAvg>bicepsMax) {
+                            bicepsMax=bicepsAvg;
+                        }
+                    }
+                    bit1 = 0;
+                    bit2 = 0;
+                    bit3 = 0;
+                    wait(5);
+                    state=tricepsCalib;
+                    stateChange=true;
+                    break;
+                case tricepsCalib  :
+                    stateChange=false;
+                    sendState(tricepsCalib);
+                    wait(5);
+                    flex.reset();
+                    flex.start();
+                    while(flex.read()<2) {
+                        if(tricepsAvg>tricepsMax) {
+                            tricepsMax=tricepsAvg;
+                        }
+                    }
+                    bit1 = 0;
+                    bit2 = 0;
+                    bit3 = 0;
+                    wait(5);
+                    state=carpiCalib;
+                    stateChange=true;
+                    break;
+                case carpiCalib  :
+                    stateChange=false;
+                    sendState(carpiCalib);
+                    wait(5);
+                    flex.reset();
+                    flex.start();
+                    while(flex.read()<2) {
+                        if(carpiFlexAvg>carpiFlexMax) {
+                            carpiFlexMax=carpiFlexAvg;
+                        }
+                    }
+                    bit1 = 0;
+                    bit2 = 0;
+                    bit3 = 0;
+                    wait(5);
+                    state=palmarisCalib;
+                    stateChange=true;
+                    break;
+                case palmarisCalib  :
+                    stateChange=false;
+                    sendState(palmarisCalib);
+                    wait(5);
+                    flex.reset();
+                    flex.start();
+                    while(flex.read()<2) {
+                        if(palmarisAvg>palmarisMax) {
+                            palmarisMax=palmarisAvg;
+                        }
+                    }
+                    bit1 = 0;
+                    bit2 = 0;
+                    bit3 = 0;
+                    wait(5);
+                    state=EMGControl;
+                    stateChange=true;
+                    break;
+                case demo  :
+                    stateChange=false;
+                    sendState(demo);
+                    break;
+                case EMGControl  :
+                    stateChange=false;
+                    sendState(EMGControl);
+                    if(bicepsMax != 0){
+                    bicepsMulti=1/bicepsMax;
+                    }
+                    if(tricepsMax != 0){
+                    tricepsMulti=1/tricepsMax;
+                    }
+                    if(carpiFlexMax != 0){
+                    carpiFlexMulti=1/carpiFlexMax;
+                    }
+                    if(palmarisMax != 0){
+                    palmarisMulti=1/palmarisMax;
+                    }
+                    break;
+            }
         }
     }
 }
\ No newline at end of file