EMG Motor Control Using An Arduino.
To get an idea of what this does I made a short video. In this video I am using a PIC18F4520, but an arduino or whatever you have laying around works fine too.
If you are wondering what the signal looks like I printed out the values onto a LCD display and have an oscilloscope reading as well in this video:
First we will need to build our EMG sensor.
First gather up everything that you need.
BOM (For EMG Sensor)
1X RR-ST-MTO-DI
1X ULN2003
2X OPA2604A
1X INA114AP
1X PIC18F4520
1X Shielded cable
2X Alligator Clips (Two double sided wires or just three of the actual clips)
1x IM414
3x T716 Electrode (Bag of disposable electrodes or three reusable ones)
3x 9 volt battery clip
1x 10 k resistor
2x 220 resistor
2x 1K resistor
1x 1M resistor
1x 100 resistor
1x 47k resistor
2x 4.7K resistor
2x .01 uf capacitor
1x 4.7 uf capacitor
1x 10 uf capacitor
1x 1N5817 diode
1x 1N5231B diode
Here is an image of the schematic for it taken from the schematic used in the PIC project.
To prevent confusion I removed the PIC portion of the schematic, hence why it is jagged.
One of the capacitors on this schematic is not labeled, it is 4.7uf.
The white circles are electrodes.
The square around two of the electrode wires means that the cable should be shielded.
I write -9 and +9 however your voltage will be lower. Just consider these positive and negative power supplies. Also not that negative in this case is not referring to ground.
To make your power source take two 9V battery clips. Solder together positive on one clip with ground on the other clip. This will be ground. The positive wire left will be your positive source and the negative wire left will be your negative source. This will drop the voltage to lower than 9V, don't worry about it it is expected. Please check to make sure that your power source gives you positive, ground, and negative with your multimeter before attaching it to anything.
Most EMG circuits give a very noisy signal, this circuit uses filters to give a very clean and smooth circuit that works great for this project. Other projects you may not want to filter and just get the raw signal. To do this remove the 10uf capacitor and everything after it. You may want to adjust the gain using the the resistors on pins 1 and 8 of your instrumentation amp.
Alright the hard part is over and you have a hopefully working EMG lets test it.
1. Take the wire that ends right after the 4.7 kohm resistor and hook it up to an oscilloscope. Also hook ground up to the oscilloscope.
2. Take electrode that connected to your op amp instead of the instrumentation amp and put it on the bony part of the back of your forearm just below your elbow.
3. Place one of the other electrodes on the top/middle of your bicep.
4. Place the other electrode on the bottom of your bicep near where your forearm is about to begin.
5. Look at the signal when flexing your arm, if the signal isn't there check your connections and that you have batteries hooked up. Make sure that when flexing as hard as you can your signal does not exceed 5V. The circuit above should prevent this, but better safe than sorry.
6.If it is safe and working how you want proceed, if not feel free to make any alterations you want.
Get your stepper motor set up.
I recommend getting a stepper motor that is 5V so that you can run it from the Arduino and also getting one that comes with a driver although you can use whatever you want.
I used the RioRand Stepper Motor 5V DC 4-Phase 5-Wire with ULN2003 Driver Board. It will only set you back about $8.00 USD
It needs 4 pins to go from the Arduino to the driver, then hook it up to 5V and ground. Simple.
Code
Stepper Control
void forward()
{
digitalWrite(A, HIGH);
delay(2);
digitalWrite(B, HIGH);
delay(2);
digitalWrite(A, LOW);
delay(2);
digitalWrite(C, HIGH);
delay(2);
digitalWrite(B, LOW);
delay(2);
digitalWrite(D, HIGH);
delay(2);
digitalWrite(C, LOW);
delay(2);
digitalWrite(A, HIGH);
delay(2);
digitalWrite(D, LOW);
delay(2);
digitalWrite(A, LOW);
delay(2);
steps++;
}
void reverse()
{
digitalWrite(A, HIGH);
delay(2);
digitalWrite(D, HIGH);
delay(2);
digitalWrite(A, LOW);
delay(2);
digitalWrite(C, HIGH);
delay(2);
digitalWrite(D, LOW);
delay(2);
digitalWrite(B, HIGH);
delay(2);
digitalWrite(C, LOW);
delay(2);
digitalWrite(A, HIGH);
delay(2);
digitalWrite(B, LOW);
delay(2);
digitalWrite(A, LOW);
delay(2);
steps--;
}
Read the signal from the EMG pin, convert it into the new step you want your motor to be in, keep track of your current step, go in the direction of the new step.
Use the serial monitor see what kind of range you get from an analog read of the EMG in Pin. Very relaxed it was 0-13. Fully flexed it was about 600-800. Relaxed but moving my arm straight to bent it would go from 0 to 200.
This number is arbitrary and may be different for you. I use it to make my new step. I keep track of my current step and if it doesn't match the new step i move in the direction it needs to go.
So, here is the complete code. It is pretty basic but gives you a reference point on how to get started. I recommend making a multi-channel EMG and comparing the bicep to the triceps to get a more accurate idea of your arm's position.
const int A = 12;
const int B = 11;
const int C = 10;
const int D = 9;
const int EMG = A0;
int steps = 0;
int newstep = 0;
float signal;
void forward();
void reverse();
void setup() /*----( SETUP: RUNS ONCE )----*/
{
pinMode(A, OUTPUT);
pinMode(B, OUTPUT);
pinMode(C, OUTPUT);
pinMode(D, OUTPUT);
pinMode(EMG, INPUT);
Serial.begin(9600);
}
void loop() /*----( LOOP: RUNS CONSTANTLY )----*/
{
signal=analogRead(EMG);
Serial.print(" Newstep: ");
Serial.print(newstep);
Serial.print(" Step:");
Serial.print( steps);
newstep=signal;
if (newstep<steps)
{
reverse();
}
if (newstep>steps)
{
forward();
}
}
void forward()
{
digitalWrite(A, HIGH);
delay(2);
digitalWrite(B, HIGH);
delay(2);
digitalWrite(A, LOW);
delay(2);
digitalWrite(C, HIGH);
delay(2);
digitalWrite(B, LOW);
delay(2);
digitalWrite(D, HIGH);
delay(2);
digitalWrite(C, LOW);
delay(2);
digitalWrite(A, HIGH);
delay(2);
digitalWrite(D, LOW);
delay(2);
digitalWrite(A, LOW);
delay(2);
steps++;
}
void reverse()
{
digitalWrite(A, HIGH);
delay(2);
digitalWrite(D, HIGH);
delay(2);
digitalWrite(A, LOW);
delay(2);
digitalWrite(C, HIGH);
delay(2);
digitalWrite(D, LOW);
delay(2);
digitalWrite(B, HIGH);
delay(2);
digitalWrite(C, LOW);
delay(2);
digitalWrite(A, HIGH);
delay(2);
digitalWrite(B, LOW);
delay(2);
digitalWrite(A, LOW);
delay(2);
steps--;
}
Have fun, if you make something cool be sure to share in the comments.