This is a simple EMG Controller for a bionic hand prosthesis

Dependencies:   mbed-dsp mbed NOKIA_5110

Galileo Bionic Hand - ST Nucleo Example


This is an example of a simple hybrid sEMG(surface Electromyography) activated controller for the Galileo Bionic Hand Prosthesis implemented with the Galileo EMG Shield. The user has to select the desired posture by sending a special character through serial port (115200 baud rate) and then perform it through sEMG activation by detecting contraction on flexor muscles of the forearm. Contractions on forearm extensor muscles releases the posture and allows the return to the default or rest posture.

Special characters:

  • '1', for "Power Grip" selection
  • '2', for "Point" selection
  • '3', for "Pinch Grip" selection
  • '4', for "Lateral Grip" selection
  • '5' for "Tripod Grip" selection


Galileo EMG Shield - 3 Channels for surface EMG

The electrodes for sEMG are placed on the skin surface and are connected to the input of a precision instrumentation differential amplifier based on Texas Instruments (TI) INA122, then its output is passed through an active low pass filter (LPF) based on TI OPA335 in order to sense the action bio-potentials of the muscular fibers with an output signal span in the range of 0 to 3.3V and a bandwidth between 0 to 500 Hz. The circuit is built-in on a custom PCB with 3 sEMG channels and a bias voltage reference output (1.25 V); furthermore, it is pin compatible with Arduino pin compatible ARM Cortex M4 boards and mbed platform ecosystem (ST Nucleo F411RE, Freescale FRDM K64F, NXP LPCXpresso 4337, ST Discovery F746NG, Renesas GR-Peach, etc), which is ideal for the single ended input of a microcontroller in addition to contributing to low cost development kits. /media/uploads/julioefajardo/shieldbrd.png /media/uploads/julioefajardo/image1.jpg

Electrodes Placement and Connection

Standard surface mounted Ag/AgCl electrodes with wet conductive gels are placed on palmaris longus and extensor digitorum muscles (third channel could be placed on Flexor carpi Ulnaris), focusing only on below elbow disarticulation. These electrodes have been well-characterized and most of its properties are well understood, except for some properties as drifting and low-frequency noise. Nevertheless, with proper preparation of the skin, the sEMG signal is excellent.

Disposable electrodes and snap leads information:

Proper placement of disposable electrodes for two channels of surface EMG is shown below:

/media/uploads/julioefajardo/electrodes.png /media/uploads/julioefajardo/mucles.png

Customizable Postures

You can customize the actions by modifying PWM values (microseconds) on FingerPosition function (values depends on the way that the hand was built it). The prosthesis has five fingers and a thumb rotation mechanism and five actuators in order to perform multiple types of grasping. Wrist rotation will be implement later.

The servo motors have to be connected as shown below:


Function Declaration and Usage Examples

include the mbed library with this snippet

void FingerPosition(float32_t thumb_us, float32_t index_us, float32_t middle_us, float32_t pinky_us, float32_t thumbrot_us);

FingerPosition(2400, 600, 600,2400,2400);   //Close
FingerPosition(2400,2400, 600,2400,2400);   //Point
FingerPosition(2400, 600,2400, 600,2400);   //Pinch
FingerPosition(2400, 600, 600,2400, 600);   //Lateral
FingerPosition(2400, 600, 600, 600,2400);   //Tripod
FingerPosition(1000,2400,2400, 600, 600);   //Open

Serial Oscilloscope Feature

This feature easily allows to watch and log to file the data using serial oscilloscope software (115200 baud rate).

  • Serial_Osciloscope(TRUE,RAW) to watch raw signals, FALSE deactivate this feature
  • Serial_Osciloscope(TRUE,RECTIFIED) to watch rectified signals, FALSE deactivate this feature
  • Serial_Osciloscope(TRUE,SMOOTH) to watch smooth signals, FALSE deactivate this feature


Universal Real-Time Software Oscilloscope GUI information:

Nolia 5110 LCD

Nokia 5110 display implementation for visual feedback will be add later, we have to modify libraries and fonts in order to improve the functionality. The main idea is to change of action by pressing a push button and change thresholds using a potentiometer.



Videos, bill of materials and tutorials to build the Galileo EMG Shield and the Galileo Bionic Hand will be posted soon, more information on:

Wed Sep 02 01:29:02 2015 +0000

Who changed what in which revision?

UserRevisionLine numberNew contents of line
julioefajardo 0:f2b89c6a8a16 1 #include "mbed.h"
julioefajardo 0:f2b89c6a8a16 2 #include "arm_math.h"
julioefajardo 0:f2b89c6a8a16 3
julioefajardo 0:f2b89c6a8a16 4 Ticker EMG_Sampler;
julioefajardo 0:f2b89c6a8a16 5 Serial pc(SERIAL_TX, SERIAL_RX);
julioefajardo 0:f2b89c6a8a16 6 DigitalOut myled(LED1);
julioefajardo 0:f2b89c6a8a16 7 AnalogIn Ref(A0);
julioefajardo 0:f2b89c6a8a16 8 AnalogIn E1(A1);
julioefajardo 0:f2b89c6a8a16 9 AnalogIn E2(A2);
julioefajardo 0:f2b89c6a8a16 10 AnalogIn E3(A3);
julioefajardo 3:f784301a5166 11 PwmOut Thumb(D11);
julioefajardo 3:f784301a5166 12 PwmOut Index(D10);
julioefajardo 3:f784301a5166 13 PwmOut Middle(D9);
julioefajardo 3:f784301a5166 14 PwmOut Pinky(D6);
julioefajardo 3:f784301a5166 15 PwmOut ThumbRot(D5);
julioefajardo 0:f2b89c6a8a16 16
julioefajardo 0:f2b89c6a8a16 17 float32_t EMG1, EMG2, EMG3;
julioefajardo 2:12f979d695db 18 float32_t samples[25];
julioefajardo 2:12f979d695db 19 float32_t samples2[25];
julioefajardo 2:12f979d695db 20 float32_t samples3[25];
julioefajardo 2:12f979d695db 21 float32_t abs_output[25];
julioefajardo 2:12f979d695db 22 float32_t abs_output2[25];
julioefajardo 2:12f979d695db 23 float32_t abs_output3[25];
julioefajardo 0:f2b89c6a8a16 24 float32_t mean = 0.0f, mean2 = 0.0f, mean3 = 0.0f;
julioefajardo 0:f2b89c6a8a16 25 uint8_t COCO = 0;
julioefajardo 0:f2b89c6a8a16 26
julioefajardo 0:f2b89c6a8a16 27 void ADC_Sampler() {
julioefajardo 0:f2b89c6a8a16 28 EMG1 = (*3.3f;
julioefajardo 0:f2b89c6a8a16 29 EMG2 = (*3.3f;
julioefajardo 0:f2b89c6a8a16 30 EMG3 = (*3.3f;
julioefajardo 0:f2b89c6a8a16 31 pc.printf("%.10f,%.10f,%.10f\n\r",EMG1,EMG2,EMG3);
julioefajardo 0:f2b89c6a8a16 32 uint32_t m = __get_PRIMASK();
julioefajardo 0:f2b89c6a8a16 33 __disable_irq();
julioefajardo 0:f2b89c6a8a16 34 for(int j=99;j>0;j--) {
julioefajardo 0:f2b89c6a8a16 35 samples[j]=samples[j-1]; //Fill Array
julioefajardo 0:f2b89c6a8a16 36 samples2[j]=samples2[j-1]; //Fill Array
julioefajardo 0:f2b89c6a8a16 37 samples3[j]=samples3[j-1]; //Fill Array
julioefajardo 0:f2b89c6a8a16 38 }
julioefajardo 0:f2b89c6a8a16 39 samples[0]=EMG1;
julioefajardo 0:f2b89c6a8a16 40 samples2[0]=EMG2;
julioefajardo 0:f2b89c6a8a16 41 samples3[0]=EMG3;
julioefajardo 0:f2b89c6a8a16 42 //copy 25 samples on array
julioefajardo 0:f2b89c6a8a16 43 for(int j=99;j>0;j--){
julioefajardo 0:f2b89c6a8a16 44 samples[j]=samples[j-1];
julioefajardo 0:f2b89c6a8a16 45 samples2[j]=samples2[j-1];
julioefajardo 0:f2b89c6a8a16 46 samples3[j]=samples3[j-1];
julioefajardo 0:f2b89c6a8a16 47 }
julioefajardo 0:f2b89c6a8a16 48 __set_PRIMASK(m);
julioefajardo 0:f2b89c6a8a16 49 COCO = 1;
julioefajardo 0:f2b89c6a8a16 50 }
julioefajardo 0:f2b89c6a8a16 51
julioefajardo 0:f2b89c6a8a16 52 int main() {
julioefajardo 0:f2b89c6a8a16 53 pc.baud(115200); //Serial com at 115200 bauds
julioefajardo 0:f2b89c6a8a16 54 EMG_Sampler.attach(&ADC_Sampler, 0.001); //1ms ticker for ADC Sampler
julioefajardo 3:f784301a5166 55 //Open -> 0.6ms - Close 2.4ms
julioefajardo 3:f784301a5166 56 Thumb.period(0.02f/2.0f);
julioefajardo 3:f784301a5166 57 Thumb.pulsewidth(0.0010f/2.0f);
julioefajardo 3:f784301a5166 58 //Open -> 2.4ms - Close 0.6ms
julioefajardo 3:f784301a5166 59 Index.period(0.02f*2.0f);
julioefajardo 3:f784301a5166 60 Index.pulsewidth(0.0024f*2.0f);
julioefajardo 3:f784301a5166 61 //Open -> 2.4ms - Close 0.6ms
julioefajardo 3:f784301a5166 62 Middle.period(0.02f*2.0f);
julioefajardo 3:f784301a5166 63 Middle.pulsewidth(0.0024f*2.0f);
julioefajardo 3:f784301a5166 64 //Open -> 0.6ms - Close 2.4ms
julioefajardo 3:f784301a5166 65 Pinky.period(0.02f*2.0f);
julioefajardo 3:f784301a5166 66 Pinky.pulsewidth(0.0006f*2.0f);
julioefajardo 3:f784301a5166 67 //Open -> 0.6ms - Close 2.4ms
julioefajardo 3:f784301a5166 68 //ThumbRot.period(0.02f/2.0f);
julioefajardo 3:f784301a5166 69 ThumbRot.pulsewidth(0.0006f*2.0f);
julioefajardo 3:f784301a5166 70
julioefajardo 0:f2b89c6a8a16 71 myled = 1;
julioefajardo 0:f2b89c6a8a16 72 while(1) {
julioefajardo 0:f2b89c6a8a16 73 if(COCO){
julioefajardo 0:f2b89c6a8a16 74 //mean for threshold
julioefajardo 2:12f979d695db 75 arm_abs_f32(samples, abs_output, 25); //rectifier
julioefajardo 2:12f979d695db 76 arm_abs_f32(samples2, abs_output2, 25); //rectifier
julioefajardo 2:12f979d695db 77 arm_abs_f32(samples3, abs_output3, 25); //rectifier
julioefajardo 2:12f979d695db 78 arm_mean_f32(abs_output, 25, &mean);
julioefajardo 2:12f979d695db 79 arm_mean_f32(abs_output, 25, &mean2);
julioefajardo 2:12f979d695db 80 arm_mean_f32(abs_output, 25, &mean3);
julioefajardo 0:f2b89c6a8a16 81 if ((mean>0.009f)&&(mean2>0.007f)&&(mean3>0.007f)) {
julioefajardo 0:f2b89c6a8a16 82 myled = 0;
julioefajardo 3:f784301a5166 83 Thumb.pulsewidth(0.0024f/2.0f);
julioefajardo 3:f784301a5166 84 Index.pulsewidth(0.0006f*2.0f);
julioefajardo 3:f784301a5166 85 Middle.pulsewidth(0.0006f*2.0f);
julioefajardo 3:f784301a5166 86 Pinky.pulsewidth(0.0024f*2.0f);
julioefajardo 3:f784301a5166 87 ThumbRot.pulsewidth(0.0024f*2.0f);
julioefajardo 0:f2b89c6a8a16 88 }
julioefajardo 0:f2b89c6a8a16 89 else {
julioefajardo 0:f2b89c6a8a16 90 myled = 1;
julioefajardo 3:f784301a5166 91 Thumb.pulsewidth(0.0010f/2.0f);
julioefajardo 3:f784301a5166 92 Index.pulsewidth(0.0024f*2.0f);
julioefajardo 3:f784301a5166 93 Middle.pulsewidth(0.0024f*2.0f);
julioefajardo 3:f784301a5166 94 Pinky.pulsewidth(0.0006f*2.0f);
julioefajardo 3:f784301a5166 95 ThumbRot.pulsewidth(0.0006f*2.0f);
julioefajardo 0:f2b89c6a8a16 96 }
julioefajardo 0:f2b89c6a8a16 97 COCO = 0;
julioefajardo 0:f2b89c6a8a16 98 }
julioefajardo 0:f2b89c6a8a16 99 }
julioefajardo 0:f2b89c6a8a16 100 }