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:
Thu Jun 11 10:07:53 2015 +0000
Parent:
55:fa6d5ee5c854
Child:
57:0a278c60d28b
Commit message:
Endconcept 6. Niks werkt;

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	Thu Jun 11 10:07:53 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/tomlankhorst/code/HIDScope/#e44574634162
--- a/main.cpp	Thu Jun 11 09:22:32 2015 +0000
+++ b/main.cpp	Thu Jun 11 10:07:53 2015 +0000
@@ -1,45 +1,279 @@
+/*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.995
+#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.04    //Can be used for normalisation of the EMG signal of the biceps
+#define MAX_tri     0.04
+#define MAX_pect    0.04
+#define MAX_delt    0.04
+#define MIN_freq    500     //The motor turns off below this frequency
+#define EMG_tresh   0.01
 
-DigitalOut Dir(p23);
-PwmOut Step(p24);
-AnalogIn Pos1(p17); 
-AnalogIn Pos2(p18); 
-DigitalOut Enable(p25);
+//Motor control
+DigitalOut Dirx(p21);
+PwmOut Stepx(p22);
+DigitalOut Diry(p23);
+PwmOut Stepy(p24);
+
+//Signal to and from computer
+Serial pc(USBTX, USBRX);
+
+//Position sensors
+AnalogIn Posx(p19);
+AnalogIn Posy(p20); 
+DigitalOut Enablex(p25); //Connected to green led
+DigitalOut Enabley(p26); //Connected to blue led
+
+//Microstepping
 DigitalOut MS1(p27);
 DigitalOut MS2(p28);
 DigitalOut MS3(p29);
-AnalogIn Pot1(p19);
-AnalogIn Pot2(p20);
+
+//Potmeter and EMG
+
+
+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;
 
-Serial pc(USBTX, USBRX);
+//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()
+{
+    //Forward
+    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 (force1 > force2) {
+        Diry = 1;
+        speed2 = 0.01;
+        speed_old2 = 0.01;
+        Stepy.period(1.0/step_freq1);
+    }
+    if (force2 > force1) {
+        Diry = 0;
+        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 (force3 > force4) {
+        Dirx = 0;
+        speed4 = 0.01;
+        speed_old4 = 0.01;
+        Stepx.period(1.0/step_freq3);
+    }
+    if (force4 > force3) {
+        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()
 {
-    
-    float setpoint = 6500; //Frequentie 
-    float step_freq = 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.01);
+
+    Ticker looptimer1;
+    looptimer1.attach(looper_motorx, 0.01); //X-Spindle motor, why this freq?
+
+    Ticker looptimer2;
+    looptimer2.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.
-    Step.write(0.5); // Duty cycle van 50%
+    Stepx.write(0.5); // Duty cycle of 50%
+    Stepy.write(0.5);
 
     while (1) {
-        Dir = 1;
-        float rpm;
-        float new_step_freq;
-        new_step_freq = ((1-P_GAIN)*setpoint) + (P_GAIN*step_freq);
-        step_freq = new_step_freq;
-        Step.period(1.0/step_freq);
-        rpm = (step_freq/400)*60;
         
-        pc.printf("%.2f %.0f \n", Pos1.read(), rpm);
-        wait(0.01); //Hier nog ticker inbouwen
-
+        lcd.printf("x %.2f, y %.2f \n", Posx.read(), Posy.read());
+        //lcd.printf("%.2f, %.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	Thu Jun 11 10:07:53 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/teams/mbed-official/code/mbed-dsp/#7a284390b0ce