4 directional EMG control of the XY table. Made during my bachelor end assignment.

Dependencies:   C12832_lcd HIDScope mbed-dsp mbed

Files at this revision

API Documentation at this revision

Comitter:
jessekaiser
Date:
Fri Jun 05 14:46:15 2015 +0000
Parent:
47:150924ff4b2c
Child:
49:056c4de3591e
Commit message:
Wat gedebugged, 2 motoren 4 emg;

Changed in this revision

HIDScope.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-dsp.lib Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HIDScope.lib	Fri Jun 05 14:46:15 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/tomlankhorst/code/HIDScope/#e44574634162
--- a/main.cpp	Fri Jun 05 13:37:58 2015 +0000
+++ b/main.cpp	Fri Jun 05 14:46:15 2015 +0000
@@ -1,55 +1,271 @@
+/*Code by Jesse Kaiser, s1355783 for control of the 2DOF Planar Table
+Some variables are also numbered at the end. The numbers stands for the muscle that controls it.
+Biceps =            1
+Triceps =           2
+Pectoralis Major =  3
+Deltoid =           4
+The "x" and "y" at the end of variables stand for the X-Spindle or Y-Spindle respectivly. 
+*/
+
 #include "mbed.h"
 #include "C12832_lcd.h"
+#include "arm_math.h"
+#include "HIDScope.h"
 
-#define P_GAIN 0.998
+#define K_Gain      14      //Gain of the filtered EMG signal
+#define Damp        5       //Deceleration of the motor
+#define Mass        1       // Mass value
+#define dt          0.002   //Sample frequency
+#define MAX_bi      0.09    //Can be used for normalisation of the EMG signal of the biceps
+#define MAX_tri     0.09
+#define MAX_pect    0.09
+#define MAX_delt    0.09
+#define MIN_freq    500     //The motor turns off below this frequency
+#define EMG_tresh   0.02
 
-DigitalOut Dir1(p21);
-PwmOut Step1(p22);
-DigitalOut Dir2(p23);
-PwmOut Step2(p24);
-DigitalOut Enable2(p25);
-DigitalOut Enable1(p26);
+//Motor control
+DigitalOut Dirx(p12);
+DigitalOut Diry(p13);
+PwmOut Stepx(p21);
+PwmOut Stepy(p22);
+
+//Signal to and from computer
+Serial pc(USBTX, USBRX);
+
+DigitalOut Enablex(p24); //Connected to green led
+DigitalOut Enabley(p25); //Connected to blue led 
+
+//Microstepping
 DigitalOut MS1(p27);
 DigitalOut MS2(p28);
 DigitalOut MS3(p29);
+
+//Potmeter and EMG
 AnalogIn Pot1(p19);
 AnalogIn Pot2(p20);
+
+AnalogIn emg1(p15); //EMG bordje bovenop, biceps
+AnalogIn emg2(p16); //triceps
+AnalogIn emg3(p17);
+AnalogIn emg4(p18);
+
+HIDScope scope(4);
+Ticker   scopeTimer;
+
+//lcd
 C12832_LCD lcd;
 
-BusIn Joystick(p12,p13,p14,p15,p16);
-DigitalIn Up(p15);
-DigitalIn Down(p12);
+//Variables for motor control
+float setpoint = 1000; //Frequentie setpint
+float step_freq1 = 1;
+float step_freq2 = 1;
+float step_freq3 = 1;
+float step_freq4 = 1; 
+
+//EMG filter
+arm_biquad_casd_df1_inst_f32 lowpass_biceps;
+arm_biquad_casd_df1_inst_f32 lowpass_triceps;
+arm_biquad_casd_df1_inst_f32 lowpass_pect;
+arm_biquad_casd_df1_inst_f32 lowpass_deltoid;
+//lowpass filter settings: Fc = 2 Hz, Fs = 500 Hz, Gain = -3 dB
+float lowpass_const[] = {0.00015514839749793376, 0.00031029679499586753, 0.00015514839749793376, 1.9644602512795832, -0.9650808448695751};
+arm_biquad_casd_df1_inst_f32 highnotch_biceps;
+arm_biquad_casd_df1_inst_f32 highnotch_triceps;
+arm_biquad_casd_df1_inst_f32 highnotch_pect;
+arm_biquad_casd_df1_inst_f32 highnotch_deltoid;
+//highpass filter settings: Fc = 20 Hz, Fs = 500 Hz, notch Fc = 50, Fs = 500 Hz
+float highnotch_const[] = {0.8370879899975344, -1.6741759799950688, 0.8370879899975344, 1.6474576182593796, -0.7008943417307579, 0.7063988100714527, -1.1429772843080923, 0.7063988100714527, 1.1429772843080923, -0.41279762014290533};
+
+//state values
+float lowpass_biceps_states[4];
+float highnotch_biceps_states[8];
+float lowpass_triceps_states[4];
+float highnotch_triceps_states[8];
+float lowpass_pect_states[4];
+float highnotch_pect_states[8];
+float lowpass_deltoid_states[4];
+float highnotch_deltoid_states[8];
+
+//global variabels
+float filtered_biceps, filtered_triceps, filtered_pect, filtered_deltoid;
+float speed_old1, speed_old2, speed_old3, speed_old4;
+float acc1, acc2, acc3, acc4;
+float force1, force2, force3, force4;
+float speed1, speed2, speed3, speed4;
+float damping1, damping2, damping3, damping4;
+
+void looper_emg()
+{
+    float emg_value1_f32, emg_value2_f32, emg_value3_f32, emg_value4_f32;
+    emg_value1_f32 = emg1.read();
+    emg_value2_f32 = emg2.read();
+    emg_value3_f32 = emg3.read();
+    emg_value4_f32 = emg4.read();
+
+    //process emg biceps
+    arm_biquad_cascade_df1_f32(&highnotch_biceps, &emg_value1_f32, &filtered_biceps, 1 );   //High pass and notch filter
+    filtered_biceps = fabs(filtered_biceps);                                                //Rectifier
+    arm_biquad_cascade_df1_f32(&lowpass_biceps, &filtered_biceps, &filtered_biceps, 1 );    //low pass filter
+
+    //process emg triceps
+    arm_biquad_cascade_df1_f32(&highnotch_triceps, &emg_value2_f32, &filtered_triceps, 1 );
+    filtered_triceps = fabs(filtered_triceps);
+    arm_biquad_cascade_df1_f32(&lowpass_triceps, &filtered_triceps, &filtered_triceps, 1 );
+
+    //process emg pectoralis major
+    arm_biquad_cascade_df1_f32(&highnotch_pect, &emg_value3_f32, &filtered_pect, 1 );
+    filtered_pect = fabs(filtered_pect);
+    arm_biquad_cascade_df1_f32(&lowpass_pect, &filtered_pect, &filtered_pect, 1 );
+
+    //process emg deltoid
+    arm_biquad_cascade_df1_f32(&highnotch_deltoid, &emg_value4_f32, &filtered_deltoid, 1 );
+    filtered_deltoid = fabs(filtered_deltoid);
+    arm_biquad_cascade_df1_f32(&lowpass_deltoid, &filtered_deltoid, &filtered_deltoid, 1 );
+
+    /*send value to PC. */
+    scope.set(0,filtered_biceps); //Filtered EMG signal
+    scope.set(1,filtered_triceps);
+    scope.set(2,filtered_pect);
+    scope.set(3,filtered_deltoid); 
+}
+
+void looper_motory()
+{
+    //Vooruit
+    force1 = K_Gain*(filtered_biceps/MAX_bi);
+    force1 = force1 - damping1;
+    acc1 = force1/Mass;
+    speed1 = speed_old1 + (acc1 * dt);
+    damping1 = speed1 * Damp;
+    step_freq1 = (setpoint*speed1);
+    speed_old1 = speed1;
+    
+    //Achteruit triceps
+    force2 = K_Gain*(filtered_triceps/MAX_tri);
+    force2 = force2 - damping2;
+    acc2 = force2/Mass;
+    speed2 = speed_old2 + (acc2 * dt);
+    damping2 = speed2 * Damp;
+    step_freq2 = (setpoint*speed2);
+    speed_old2 = speed2;
+    if (filtered_biceps > filtered_triceps) {
+        Diry = 0;
+        speed2 = 0.01;
+        speed_old2 = 0.01;
+        Stepy.period(1.0/step_freq1);
+    } if (filtered_triceps > filtered_biceps) {
+        Diry = 1;
+        speed1 = 0.01;
+        speed_old1 = 0.01;  
+        Stepy.period(1.0/step_freq2);
+    }
+    //Speed limit
+    if (speed1 > 1) {
+        speed1 = 1;
+        step_freq1 = setpoint;
+    }
+    if (speed2 > 1) {
+        speed2 = 1;
+        step_freq2 = setpoint;
+    }
+    //EMG treshold
+    if (filtered_biceps < EMG_tresh && filtered_triceps < EMG_tresh) {
+        Enabley = 1; //Enable = 1 turns the motor off. 
+        speed1 = 0.01;
+        speed_old1 = 0.01;
+        speed2 = 0.01;
+        speed_old2 = 0.01;
+    } else {
+        Enabley = 0;
+    }
+
+}
+
+void looper_motorx()
+{
+    //To the left
+    force3 = K_Gain*(filtered_pect/MAX_pect);
+    force3 = force3 - damping3;
+    acc3 = force3/Mass;
+    speed3 = speed_old3 + (acc3 * dt);
+    damping3 = speed3 * Damp;
+    step_freq3 = (setpoint*speed3);
+    speed_old3 = speed3;
+    
+    //To the right
+    force4 = K_Gain*(filtered_deltoid/MAX_delt);
+    force4 = force4 - damping4;
+    acc4 = force4/Mass;
+    speed4 = speed_old4 + (acc4 * dt);
+    damping4 = speed4 * Damp;
+    step_freq4 = (setpoint*speed4);
+    speed_old4 = speed4;
+    if (filtered_pect > filtered_deltoid) {
+        Dirx = 0;
+        speed4 = 0.01;
+        speed_old4 = 0.01;
+        Stepx.period(1.0/step_freq3);
+    } if (filtered_deltoid > filtered_pect) {
+        Dirx = 1;
+        speed3 = 0.01;
+        speed_old3 = 0.01;  
+        Stepx.period(1.0/step_freq4);
+    }
+    //Speed limit
+    if (speed3 > 1) {
+        speed3 = 1;
+        step_freq3 = setpoint;
+    }
+    if (speed4 > 1) {
+        speed4 = 1;
+        step_freq4 = setpoint;
+    }
+    //EMG treshold
+    if (filtered_pect < EMG_tresh && filtered_deltoid < EMG_tresh) {
+        Enablex = 1; //Enable = 1 turns the motor off. 
+        speed3 = 0.01;
+        speed_old3 = 0.01;
+        speed4 = 0.01;
+        speed_old4 = 0.01;
+    } else {
+        Enablex = 0;
+    }
+
+}
 int main()
 {
-    Enable1 = 1;
-    Enable2 = 1;
-    float setpoint = 1500; //Frequentie
-    float step_freq1 = 1;
-    float step_freq2 = 1;
+    // Attach the HIDScope::send method from the scope object to the timer at 500Hz. Hier wordt de sample freq aangegeven.
+    scopeTimer.attach_us(&scope, &HIDScope::send, 2e3);
+
+    Ticker emgtimer;    //biceps
+    arm_biquad_cascade_df1_init_f32(&lowpass_biceps, 1 , lowpass_const, lowpass_biceps_states);
+    arm_biquad_cascade_df1_init_f32(&highnotch_biceps, 2 , highnotch_const, highnotch_biceps_states);
+    //triceps
+    arm_biquad_cascade_df1_init_f32(&lowpass_triceps, 1 , lowpass_const, lowpass_triceps_states);
+    arm_biquad_cascade_df1_init_f32(&highnotch_triceps, 2 , highnotch_const, highnotch_triceps_states);
+    //pectoralis major   
+    arm_biquad_cascade_df1_init_f32(&lowpass_pect, 1 , lowpass_const, lowpass_pect_states);
+    arm_biquad_cascade_df1_init_f32(&highnotch_pect, 2 , highnotch_const, highnotch_pect_states);
+    //deltoid
+    arm_biquad_cascade_df1_init_f32(&lowpass_deltoid, 1 , lowpass_const, lowpass_deltoid_states);
+    arm_biquad_cascade_df1_init_f32(&highnotch_deltoid, 2 , highnotch_const, highnotch_deltoid_states);
+    emgtimer.attach(looper_emg, 0.002);
+
+    Ticker looptimer;
+    looptimer.attach(looper_motorx, 0.01); //X-Spindle motor, why this freq?
+    //looptimer.attach(looper_motory, 0.01); //Y-Spindle motor
+    
+    //Microstepping control, now configured as half stepping (MS1=1,MS2=0,MS3=0)
     MS1 = 1;
     MS2 = 0;
     MS3 = 0;
-    //Step.period(1./step_freq); // 1 kHz, vanaf 2,5 kHz doet de motor het niet meer.
-    Step1.write(0.5); // Duty cycle van 50%
-    Step2.write(0.5);
-    // Dir = Pot1; // Dir 1 is naar boven, Dir 0 naar onder.
-    Enable1 = 0;
-    Enable2 = 0;
+    Stepx.write(0.5); // Duty cycle of 50%
+    Stepy.write(0.5);
+
     while (1) {
-        Dir1 = 0; //0 Naar links (grote motor)
-        float new_step_freq1;
-        new_step_freq1 = ((1-P_GAIN)*setpoint) + (P_GAIN*step_freq1);
-        step_freq1 = new_step_freq1;
-        Step1.period(1.0/step_freq1);
 
-        Dir2 = 0; //0 Naar onder (kleine motor)
-        float new_step_freq2;
-        new_step_freq2 = ((1-P_GAIN)*setpoint) + (P_GAIN*step_freq2);
-        step_freq2 = new_step_freq2;
-        Step2.period(1.0/step_freq2);
-
-        lcd.printf("freq : %.0f, %.0f \n", step_freq1, step_freq2);
-        wait(0.01); //Hier nog ticker inbouwen
-
+        //lcd.printf("Bi %.2f ,Tri %.2f \n", filtered_biceps, filtered_triceps); Filtered EMG values 
+        lcd.printf("1 %.0f, 2 %.0f, 3 %.0f, 4 %.0f \n", step_freq1, step_freq2, step_freq3, step_freq4); //step_freq value of every EMG sensor
+        wait(0.01);
     }
-}
\ No newline at end of file
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-dsp.lib	Fri Jun 05 14:46:15 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/teams/mbed-official/code/mbed-dsp/#7a284390b0ce