Switches 2.0

Dependencies:   mbed QEI HIDScope BiQuad4th_order biquadFilter MODSERIAL FastPWM

Revision:
9:0e838367ab6a
Parent:
8:b40067b8a72d
Child:
10:cbcb35182ef1
--- a/main.cpp	Thu Oct 31 18:22:28 2019 +0000
+++ b/main.cpp	Fri Nov 01 10:23:02 2019 +0000
@@ -1,13 +1,53 @@
 #include "mbed.h"
-//#include "HIDScope.h"
+#include "FilterDesign.h"
+#include "HIDScope.h"
 #include "QEI.h"
 #include "MODSERIAL.h"
-//#include "BiQuad.h"
-//#include "FastPWM.h"
+#include "BiQuad4.h"
+#include "BiQuad.h"
+#include "FastPWM.h"
 #include <vector>
 
-using std::vector;
+
+MODSERIAL pc(USBTX, USBRX);
+
+// main() runs in its own thread in the OS
+
+//State machine
+InterruptIn stateSwitch(SW2);
+InterruptIn stepSwitch(SW3);
+
+void stateMachine();
+void switchStep();
+void switchState();
+
+int noStateSteps = 4;
+int stateStep = 0;
+int state = 0;
+
+void EMGState();
+void demoState();
 
+//Shared steps
+void calibrateMotors();
+void waiting();
+
+//Demo steps
+void playDemo();
+
+
+//EMG steps
+void EMGcalibration();
+void moveToInitialPosition();
+void moveWithEMG();
+
+//Calibration
+void moveMotorToStop(DigitalOut *M, PwmOut *E, QEI *Enc, double speed);
+
+//play demo
+void moveAlongPath(double xStart, double yStart, double xEnd, double yEnd, double speed);
+
+//Motors
 double Pi = 3.14159265359;
 
 QEI Enc1(D12, D13, NC, 32);
@@ -24,29 +64,181 @@
 double initRot1 = 0;
 double initRot2 = -gearRatio*(180 - 48.5)/360;
 
-
-MODSERIAL pc(USBTX, USBRX);
+double xCurrent;
+double yCurrent;
 
-
-void moveMotorTo(DigitalOut *M, PwmOut *E, QEI *Enc, double rotDes);
 double calcRot1(double xDes, double yDes);
 double calcRot2(double xDes, double yDes);
-void plotPath(double xStart, double yStart, double xEnd, double yEnd, double *xPath[], double *yPath[]);
-void moveAlongPath(double xStart, double yStart, double xEnd, double yEnd, double speed);
+
+void findDesiredLocation(double xStart, double yStart, double xEnd, double yEnd, double speed, Timer *t, vector<double> *desiredLocation);
 void moveMotorContinuously(DigitalOut *M, PwmOut *E, QEI *Enc, double initRot, double dir, vector<double> *pidInfo, Timer *t, double rotDes);
-double calcX(double rot1, double rot2);
-double calcX(double rot1, double rot2);
+void moveMotorToPoint(DigitalOut *M, PwmOut *E, QEI *Enc, double initRot, double dir, double rotDes);
+void moveWithSpeed(double *xStart, double *yStart, double xSpeed, double ySpeed);
+void flipx();
+void flipy();
+
+//EMG
+AnalogIn emg0( A0 );
+AnalogIn emg1( A3 );
+
+HIDScope scope( 2 );
+
+Ticker ticker_calibration;   // Ticker to send the EMG signals to screen
+
+volatile double emg1_cal = 0.8;
+volatile double emg1_filtered;      //measured value of the first emg
+volatile double emg2_filtered;      //measured value of the second emg
+volatile double emg2_cal = 0.8;
 
-// main() runs in its own thread in the OS
+double speedy = 3;
+double speedx = 3;
+
+double xDir = 1;
+double yDir = 1;
+
+vector<double> pidInfo1 (4);
+vector<double> pidInfo2 (4);
+
+Timer tEMGMove;
+
+InterruptIn xSwitch(D8);
+InterruptIn ySwitch(D9);
+
+void sample();
+
+//Waiting
+DigitalOut r_led(LED_RED);
+
 int main()
 {
+    stateSwitch.rise(switchState);
+    stepSwitch.rise(switchStep);
+
+    xSwitch.mode(PullUp);
+    ySwitch.mode(PullUp);
+
+    xSwitch.fall(flipx);
+    ySwitch.fall(flipy);
+
     pc.baud(115200);
     while(1) {
-        playDemo;
+        stateMachine();
     }
 
 }
 
+void switchState()
+{
+    state++;
+    state = state%2;
+    stateStep = 0;
+    switch(state) {
+        //demo mode
+        case 0:
+            tEMGMove.stop();
+            pc.printf("demo\n\r");
+            noStateSteps = 4;
+            break;
+        case 1:
+            pc.printf("EMG\n\r");
+            noStateSteps = 7;
+            fill(pidInfo1.begin(), pidInfo1.begin()+4, 0);
+            fill(pidInfo2.begin(), pidInfo2.begin()+4, 0);
+            tEMGMove.reset();
+            tEMGMove.start();
+            break;
+    }
+}
+
+void switchStep()
+{
+    stateStep++;
+    stateStep = stateStep%noStateSteps;
+}
+
+void stateMachine()
+{
+    switch (state) {
+        case 0:
+            demoState();
+            break;
+        case 1:
+            EMGState();
+            break;
+    }
+}
+
+void demoState()
+{
+    pc.printf("demo %d\n\r", stateStep);
+    switch (stateStep) {
+        case 0:
+            waiting();
+            break;
+        case 1:
+            calibrateMotors();
+            stateStep++;
+            break;
+        case 2:
+            waiting();
+            break;
+        case 3:
+            playDemo();
+            break;
+    }
+}
+
+void EMGState()
+{
+    pc.printf("EMG %d\n\r", stateStep);
+    switch(stateStep) {
+        case 0:
+            waiting();
+            break;
+        case 1:
+            calibrateMotors();
+            stateStep++;
+            break;
+        case 2:
+            waiting();
+            break;
+        case 3:
+            EMGcalibration();
+            pc.printf("hack");
+            stateStep++;
+            break;
+        case 4:
+            waiting();
+            break;
+        case 5:
+            moveToInitialPosition();
+            xCurrent = 0;
+            yCurrent = 20;
+            break;
+        case 6:
+            moveWithEMG();
+            break;
+    }
+}
+
+void waiting()
+{
+    r_led = 0;
+    E1 =0;
+    E2 =0;
+    r_led = 1;
+}
+
+void calibrateMotors()
+{
+    moveMotorToStop(&M1, &E1, &Enc1, -0.1);
+    moveMotorToStop(&M2, &E2, &Enc2, 0.2);
+    Enc2.reset();
+    moveMotorToStop(&M1, &E1, &Enc1, -0.1);
+    Enc1.reset();
+    pc.printf("%f", Enc1.getPulses());
+}
+
 void playDemo()
 {
     moveAlongPath(10, 30, -10, 30, 3);
@@ -55,18 +247,262 @@
     moveAlongPath(10, 20, 10, 30, 3);
 }
 
+void EMGcalibration()
+{
+    Timer tijd;
+    tijd.start(); 
+    ticker_calibration.attach(&sample, 0.002);  
+    do {
+        //ticker_calibration.attach(&sample, 0.002);
+        if(emg1_cal < emg1_filtered) {
+            emg1_cal = emg1_filtered ;
+            pc.printf("EMG_cal : %g \n\r",emg1_cal);
+        }
+        if(emg2_cal < emg2_filtered) {
+            emg2_cal = emg2_filtered ;
+        }
+        pc.printf("emg1: %f\n\r", emg1_filtered);
+    } while(tijd.read()<10);
+}
 
-//function to mave a motor to a certain number of rotations, counted from the start of the program.
-//parameters:
-//DigitalOut *M = pointer to direction cpntol pin of motor
-//PwmOut *E = pointer to speed contorl pin of motor
-//QEI *Enc = pointer to encoder of motor
-//double rotDes = desired rotation
+
+void moveToInitialPosition()
+{
+    double xStart = 0;
+    double yStart = 20;
+
+    double rot1 = calcRot1(xStart, yStart);
+    double rot2 = calcRot2(xStart, yStart);
+
+    moveMotorToPoint(&M1, &E1, &Enc1, initRot2, 1, -rot2);
+    moveMotorToPoint(&M2, &E2, &Enc2, initRot1, -1, rot1);
+}
+
+void moveWithEMG()
+{
+    if(emg1_filtered >= 0.5*emg1_cal) {
+        speedy = 3;
+        pc.printf("emg1: %f", emg1_filtered);
+    } else {
+        speedy = 0;
+    }
+
+    if(emg2_filtered >= 0.5*emg2_cal) {
+        speedx = 3;
+        pc.printf("emg1: %f\n\r", emg2_filtered);
+    } else {
+        speedx = 0;
+    }
+    pc.printf("speedx: %f speedy: %f\r\n", speedx, speedy);
+    xCurrent = xCurrent + xDir*speedx*0.01;
+    yCurrent = yCurrent + yDir*speedy*0.01;
+    double rot2 = calcRot2(xCurrent, yCurrent);
+    moveMotorContinuously(&M1, &E1, &Enc1, initRot2, 1, &pidInfo2, &tEMGMove, -rot2);
+    double rot1 = calcRot1(xCurrent, yCurrent);
+    moveMotorContinuously(&M2, &E2, &Enc2, initRot1, -1, &pidInfo1, &tEMGMove, rot1);
+    wait(0.01);
+}
+
+void moveMotorToStop(DigitalOut *M, PwmOut *E, QEI *Enc, double speed)
+{
+    Timer t;
+
+    double MotorPWM;
+
+    double posC;
+    double posP = Enc->getPulses()/(32*131.25);
+    double vel = 0;
+
+    int hasNotMoved = 0;
+
+    t.start();
+    do {
+        MotorPWM = speed - vel*0.7;
+        if(MotorPWM > 0) {
+            *M = 0;
+            *E = MotorPWM;
+        } else {
+            *M = 1;
+            *E = -MotorPWM;
+        }
+        wait(0.01);
+        posC = Enc->getPulses()/(32*131.25);
+        vel = (posC - posP)/t.read();
+        t.reset();
+        posP = posC;
+        //pc.printf("v: %f hm: %d\n\r", MotorPWM, hasNotMoved);
+        if(abs(vel) > 0.001) {
+            hasNotMoved = 0;
+        } else {
+            hasNotMoved++;
+        }
+    } while(hasNotMoved < 6);
+    *E = 0;
+}
+
+void moveAlongPath(double xStart, double yStart, double xEnd, double yEnd, double speed)
+{
+    double rot1;
+    double rot2;
+
+    Timer t;
+
+    vector<double> desiredLocation;
+
+    fill(pidInfo1.begin(), pidInfo1.begin()+4, 0);
+    fill(pidInfo2.begin(), pidInfo2.begin()+4, 0);
+
+    double pathLength = sqrt(pow((xStart - xEnd), 2.0)+pow((yStart - yEnd), 2.0));
+
+    //Calculate the rotation of the motors at the start of the path
+    rot1 = calcRot1(xStart, yStart);
+    rot2 = calcRot2(xStart, yStart);
+    pc.printf("r1: %f r2: %f", rot1/6, rot2/6);
+
+    //Move arms to the start of the path
+    //moveMotorToPoint(&M1, &E1, &Enc1, initRot2, 1, -rot2);
+    //moveMotorToPoint(&M2, &E2, &Enc2, initRot1, -1, rot1);
+
+    //start the timer
+    t.start();
+    while(pathLength > speed * t.read()) {
+        findDesiredLocation(xStart, yStart, xEnd, yEnd, speed, &t, &desiredLocation);
+        rot1 = calcRot1(desiredLocation.at(0), desiredLocation.at(1));
+        //pc.printf("\n\r Rot1: %f", rot1);
+        moveMotorContinuously(&M1, &E1, &Enc1, initRot2, 1, &pidInfo2, &t, -rot2);
+        rot2 = calcRot2(desiredLocation.at(0), desiredLocation.at(1));
+        //pc.printf("\n\r X: %f Y: %f Rot1: %f Rot2 %f", desiredLocation.at(0), desiredLocation.at(1), rot1, rot2);
+        moveMotorContinuously(&M2, &E2, &Enc2, initRot1, -1, &pidInfo1, &t, rot1);
+        //pc.printf("\n\r xCalc: %f yCalc: %f", calcX(pidInfo1.at(3), pidInfo2.at(3)), calcY(pidInfo1.at(3), pidInfo2.at(3)));
+        wait(0.01);
+    }
+
+}
+
+double calcRot1(double xDes, double yDes)
+{
+    double alpha = atan(yDes/xDes);
+    if(alpha < 0) {
+        alpha = alpha+Pi;
+    }
+    //pc.printf("alpha: %f", alpha);
+    return gearRatio*((alpha - 0.5*(Pi - acos((pow(xDes, 2.0) + pow(yDes, 2.0) - 2*pow(20.0, 2.0))/(-2*pow(20.0, 2.0)))))/(2*Pi));
+}
+
+double calcRot2(double xDes, double yDes)
+{
+    double alpha = atan(yDes/xDes);
+    if(alpha < 0) {
+        alpha = alpha+Pi;
+    }
+    return gearRatio*((alpha + 0.5*(Pi - acos((pow(xDes, 2.0) + pow(yDes, 2.0) - 2*pow(20.0, 2.0))/(-2*pow(20.0, 2.0)))))/(2*Pi));
+}
+
+void findDesiredLocation(double xStart, double yStart, double xEnd, double yEnd, double speed, Timer *t, vector<double> *desiredLocation)
+{
+    double pathLength = sqrt(pow((xStart - xEnd), 2.0)+pow((yStart - yEnd), 2.0));
+    double traveledDistance = speed * t->read();
+    double ratio = traveledDistance/pathLength;
+
+    desiredLocation->clear();
+    desiredLocation->push_back(xStart + (xEnd - xStart)*ratio);
+    desiredLocation->push_back(yStart + (yEnd - yStart)*ratio);
+
+}
+
+void moveMotorContinuously(DigitalOut *M, PwmOut *E, QEI *Enc, double initRot, double dir, vector<double> *pidInfo, Timer *t, double rotDes)
+{
+    double Kp = 61;  //180 & 10 werkt zonder hulp
+    double Ki = 1;
+    double Kd = 7;
+
+    double rotC = Enc->getPulses()/(32*131.25) + initRot;
+
+    double pErrorC = rotDes - rotC;
+
+    double tieme = t->read();
+    double dt = tieme - pidInfo->at(2);
+
+    double iError = pidInfo->at(1) + pErrorC*dt;
+    double dError = (pErrorC - pidInfo->at(0))/dt;
+
+    double MotorPWM = (pErrorC*Kp + iError*Ki + dError*Kd)*dir;
+
+    if(MotorPWM > 0) {
+        *M = 0;
+        *E = MotorPWM;
+    } else {
+        *M = 1;
+        *E = -MotorPWM;
+    }
+    pidInfo->clear();
+    pidInfo->push_back(pErrorC);
+    pidInfo->push_back(iError);
+    pidInfo->push_back(tieme);
+    pidInfo->push_back(Enc->getPulses()/(32*131.25) + initRot);
+}
+
+void sample()
+{
+    emg1_filtered = FilterDesign(emg0.read());
+    emg2_filtered = FilterDesign(emg1.read());
+    /* 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, emg1_filtered ) ;
+    scope.set(1, emg2_filtered );
+    /* 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();
+    /* To indicate that the function is working, the LED is toggled */
+    //pc.printf("%f", emg1_filtered)
+    //led = !led;
+}
+
+void moveWithSpeed(double *xStart, double *yStart, double xSpeed, double ySpeed)
+{
+    Timer t;
+
+    vector<double> pidInfo1 (4);
+    vector<double> pidInfo2 (4);
+
+    fill(pidInfo1.begin(), pidInfo1.begin()+4, 0);
+    fill(pidInfo2.begin(), pidInfo2.begin()+4, 0);
+
+    double xC = *xStart;
+    double yC = *yStart;
+
+    double rot1;
+    double rot2;
+
+    double tiemeP;
+    double tiemeC;
+    double dt;
+
+    t.start();
+
+    tiemeP = t.read();
+    while(t.read() < 0.1) {
+        tiemeC = t.read();
+        dt = tiemeC - tiemeP;
+        xC = xC+xSpeed*dt;
+        yC = yC+ySpeed*dt;
+        rot1 = calcRot1(xC, yC);
+        rot2 = calcRot2(xC, yC);
+        moveMotorContinuously(&M1, &E1, &Enc1, initRot2, 1, &pidInfo2, &t, -rot2);
+        moveMotorContinuously(&M2, &E2, &Enc2, initRot1, -1, &pidInfo1, &t, rot1);
+        tiemeP = tiemeC;
+        wait(0.01);
+    }
+
+    *xStart = xC;//calcX(pidInfo1.at(3), pidInfo2.at(3));
+    *yStart = yC;//calcY(pidInfo1.at(3), pidInfo2.at(3));
+}
+
 void moveMotorToPoint(DigitalOut *M, PwmOut *E, QEI *Enc, double initRot, double dir, double rotDes)
 {
-    double Kp = 30;  //180 & 10 werkt zonder hulp
+    double Kp = 2;  //180 & 10 werkt zonder hulp
     double Ki = 0;
-    double Kd = 2;
+    double Kd = 0.1;
 
     double pErrorC;
     double pErrorP = 0;
@@ -106,130 +542,20 @@
             *E = -MotorPWM;
         }
         wait(0.01);
-        printf("U_p: %f U_i: %f U_d: %f motorPWM: %f\n\r", pErrorC, iError, dError, MotorPWM);
+        //printf("U_p: %f U_i: %f U_d: %f motorPWM: %f\n\r", pErrorC, iError, dError, MotorPWM);
     } while (abs(MotorPWM) > 0.13|| abs(dError > 0.01));; //pErrorC > 0.02 || pErrorC < -0.02 ||dError > 0.01 || dError < -0.01);
     *E = 0;
     //pc.printf("U_p: %f U_i: %f U_d: %f motorPWM: %f\n\r", pErrorC, iError, dError, MotorPWM);
     t.stop();
 }
 
-void moveMotorContinuously(DigitalOut *M, PwmOut *E, QEI *Enc, double initRot, double dir, vector<double> *pidInfo, Timer *t, double rotDes)
+void flipx()
 {
-    double Kp = 61;  //180 & 10 werkt zonder hulp
-    double Ki = 1;
-    double Kd = 7;
-
-    double rotC = Enc->getPulses()/(32*131.25) + initRot;
-
-    double pErrorC = rotDes - rotC;
-
-    double tieme = t->read();
-    double dt = tieme - pidInfo->at(2);
-
-    double iError = pidInfo->at(1) + pErrorC*dt;
-    double dError = (pErrorC - pidInfo->at(0))/dt;
-
-    double MotorPWM = (pErrorC*Kp + iError*Ki + dError*Kd)*dir;
-
-    if(MotorPWM > 0) {
-        *M = 0;
-        *E = MotorPWM;
-    } else {
-        *M = 1;
-        *E = -MotorPWM;
-    }
-    pidInfo->clear();
-    pidInfo->push_back(pErrorC);
-    pidInfo->push_back(iError);
-    pidInfo->push_back(tieme);
-    pidInfo->push_back(Enc->getPulses()/(32*131.25) + initRot);
-}
-
-
-//double that calculates the rotation of one arm.
-//parameters:
-//double xDes = ofset of the arm's shaft in cm in the x direction
-//double yDes = ofset of the arm's shaft in cm in the y direction
-double calcRot1(double xDes, double yDes)
-{
-    double alpha = atan(yDes/xDes);
-    if(alpha < 0) {
-        alpha = alpha+Pi;
-    }
-    //pc.printf("alpha: %f", alpha);
-    return gearRatio*((alpha - 0.5*(Pi - acos((pow(xDes, 2.0) + pow(yDes, 2.0) - 2*pow(20.0, 2.0))/(-2*pow(20.0, 2.0)))))/(2*Pi));
-}
-
-double calcRot2(double xDes, double yDes)
-{
-    double alpha = atan(yDes/xDes);
-    if(alpha < 0) {
-        alpha = alpha+Pi;
-    }
-    return gearRatio*((alpha + 0.5*(Pi - acos((pow(xDes, 2.0) + pow(yDes, 2.0) - 2*pow(20.0, 2.0))/(-2*pow(20.0, 2.0)))))/(2*Pi));
-}
-
-void findDesiredLocation(double xStart, double yStart, double xEnd, double yEnd, double speed, Timer *t, vector<double> *desiredLocation)
-{
-    double pathLength = sqrt(pow((xStart - xEnd), 2.0)+pow((yStart - yEnd), 2.0));
-    double traveledDistance = speed * t->read();
-    double ratio = traveledDistance/pathLength;
-
-    desiredLocation->clear();
-    desiredLocation->push_back(xStart + (xEnd - xStart)*ratio);
-    desiredLocation->push_back(yStart + (yEnd - yStart)*ratio);
+    xDir = -xDir;
 
 }
 
-double calcX(double rot1, double rot2)
-{
-    return 20*cos((rot1/gearRatio)*2*Pi)+20*cos((-rot2/gearRatio)*2*Pi);
-}
-
-double calcY(double rot1, double rot2)
-{
-    return 20*sin((rot1/gearRatio)*2*Pi)+20*sin((-rot2/gearRatio)*2*Pi);
-}
-
-void moveAlongPath(double xStart, double yStart, double xEnd, double yEnd, double speed)
+void flipy()
 {
-    double rot1;
-    double rot2;
-
-    Timer t;
-
-    vector<double> desiredLocation;
-
-    vector<double> pidInfo1 (4);
-    vector<double> pidInfo2 (4);
-
-    fill(pidInfo1.begin(), pidInfo1.begin()+4, 0);
-    fill(pidInfo2.begin(), pidInfo2.begin()+4, 0);
-
-    double pathLength = sqrt(pow((xStart - xEnd), 2.0)+pow((yStart - yEnd), 2.0));
-
-    //Calculate the rotation of the motors at the start of the path
-    rot1 = calcRot1(xStart, yStart);
-    rot2 = calcRot2(xStart, yStart);
-    pc.printf("r1: %f r2: %f", rot1/6, rot2/6);
-
-    //Move arms to the start of the path
-    //moveMotorToPoint(&M1, &E1, &Enc1, initRot2, 1, -rot2);
-    //moveMotorToPoint(&M2, &E2, &Enc2, initRot1, -1, rot1);
-
-    //start the timer
-    t.start();
-    while(pathLength > speed * t.read()) {
-        findDesiredLocation(xStart, yStart, xEnd, yEnd, speed, &t, &desiredLocation);
-        rot1 = calcRot1(desiredLocation.at(0), desiredLocation.at(1));
-        //pc.printf("\n\r Rot1: %f", rot1);
-        moveMotorContinuously(&M1, &E1, &Enc1, initRot2, 1, &pidInfo2, &t, -rot2);
-        rot2 = calcRot2(desiredLocation.at(0), desiredLocation.at(1));
-        //pc.printf("\n\r X: %f Y: %f Rot1: %f Rot2 %f", desiredLocation.at(0), desiredLocation.at(1), rot1, rot2);
-        moveMotorContinuously(&M2, &E2, &Enc2, initRot1, -1, &pidInfo1, &t, rot1);
-        pc.printf("\n\r xCalc: %f yCalc: %f", calcX(pidInfo1.at(3), pidInfo2.at(3)), calcY(pidInfo1.at(3), pidInfo2.at(3)));
-        wait(0.01);
-    }
-
-}
-
+    yDir = -yDir;
+}
\ No newline at end of file