Easydriver (stepper) and accelerometer (MMA7260Q)

Hello everyone,

I'm hoping to get some programming help here for my little project. I'm trying to gain experience with the code and the arduino, so please bear with me.

What I'm trying to accomplish is to have my accelerometer detect movement and then have my stepper motor move accordingly (the bigger the acceleration, the bigger the stepper motor movement). Also, if the accelerometer is experiencing a constant G, then the stepper steps the appropriate number of steps, and holds that position. When there is no acceleration, the stepper motor returns to the original position it started. Hopefully this is clear :slight_smile:

The problem that I am experiencing is erattic motor behaviour. It seems like the motor doesn't reliably return to the starting position. Any suggestions would be great! Thanks!

Without further adieu, here is the code I have so far:

//Easydriver pins

int dirPin = 3;
int stepperPin = 12;

//Accelerometer pins (analog)

const int pinx = 1 ;
const int piny = 2 ;
const int pinz = 3 ;
const int SLP = 9;

//variables to store accelerometer output and keep track of stepper position
int valx = 0;
int valy = 0;
int valz = 0;

int last = 0;
int current = 0;
int difference = 0;

//setup

void setup() {
Serial.begin(9600);

pinMode(SLP, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(stepperPin, OUTPUT);
}

//Function for instructing the Easydriver

void step(boolean dir,int steps){
digitalWrite(dirPin,dir); //give Easydriver direction for stepper to move
delay(50);

for(int i=0;i<steps;i++){ //loop through the number of steps that the stepper motor must complete
digitalWrite(stepperPin, LOW);
digitalWrite(stepperPin, HIGH);
delayMicroseconds(1000);
}
}

//Main code body

void loop(){

digitalWrite(SLP, HIGH); //Make sure the accelerometer is "awake"

//Read the values from the accelerometer and assign them to the variables. For this simple program, only the y value will be used for now.
valx = analogRead(pinx);
valy = analogRead(piny);
valz = analogRead(pinz);

if (last == 0) { //For the first time through the loop, set the "last" value to y input from the accelerometer (multiplied by 5 so stepper motor moves more)
last = valy*5;
}

current = valy*5; //Set the "current" value to the y value (multiplied by 5 so stepper motor moves more)

difference = last - current; //Calculate the difference between the last known acceleration and the current acceleration

if (difference > 0) { //If the difference is positive, then it will tell the Easydrive to step the motor counter-clockwise
step(false, difference);

}

if (difference < 0) { //If the difference is a negative number, then it will tell the Easydriver to step the motor clockwise
difference = abs(difference);
step(true, difference);

}

last = current; //Set the last known to acceleration to the current one so it can be compared to the next reading
delay(50);

}

Also, if the accelerometer is experiencing a constant G, then the stepper steps the appropriate number of steps, and holds that position. When there is no acceleration, the stepper motor returns to the original position it started. Hopefully this is clear

I suspect you have a fundamental misunderstanding of accelerometers. You seem to be mistaking motion and acceleration.

Acceleration is the rate of change of velocity, while velocity is a vector that combines position and direction, and changes when either the position changes or the direction changes.

The problem that I am experiencing is erattic motor behaviour. It seems like the motor doesn't reliably return to the starting position.

How can it, with all those delays? You are missing loads of data from the accelerometer, which you are not properly integrating, anyway.

Hi Paul,

thank you for your response. I do know the difference between acceleration and velocity (acceleration being the derivative of velocity with respect to time). When I said "motion" I was referring to acceleration or tilt (accelerometer should detect gravity in whatever axis is experiencing it?).

So technically, if I were to quickly strike the accelerometer, the change in velocity (acceleration) should produce a stepping sequence of lets say, 200 steps for example. I understand that the arduino is busy stepping the motor and will not read any info from the accelerometer during this process. Once the stepping process is done, the next accelerometer reading should be the "baseline" again because there is no acceleration. Therefore, it should step backwards 200 steps to the starting position?

The next condition would be tilting the accelerometer. By tilting it, the y axis should feel gravity, should it not? Then, it should move a prescribed amount. If it is still tilted the same amount when the stepping sequence is done, it should remain in that position. Once it is set back down on the table, and the y axis does not feel gravity, it should go back to the home position?

I hope this is more clear? I would really like to get this working.

Thank you again.

Chris

Forget, for the moment about actually moving the stepper motor. Just print to the serial port the value read from the accelerometer (valy), the value that reading is mapped to (valy*5), along with current, last and difference.

With the accelerometer sitting still, does difference show a nice steady 0? When you move it, does difference return quickly to 0?

Or, are the readings all over the place? Do they tend to return quickly to 0, or do they oscillate all over the place?

Hi Paul,

The values oscillate while the accelerometer is sitting still. I realize this will cause a certain percent error when trying to get the stepper motor to return back to the original position after it is done accelerating. However, I am experiencing the difference of more than a few steps (even by the multiple of 5). Sometimes it appears to have a mind of its own, and not even travel in the right direction.

I took a step back and revisited some simple stepper motor program, and without the accelerometer, the results are similar. This program that I will add next, should only have the stepper motor moving in one direction. However, it sometimes travels in reverse? I'm somewhat frustrated and not sure what is going on. (I also repinned the board, so the pins are not the same as the first program I posted).

int dirPin = 3;
int stepperPin = 2;
int SLEEP = 8;
int MS1 = 7;
int MS2 = 9;

void setup() {
pinMode(dirPin, OUTPUT);
pinMode(stepperPin, OUTPUT);
pinMode(MS1, OUTPUT);
pinMode(MS2, OUTPUT);
pinMode(SLEEP, OUTPUT);
}

void step(boolean dir,int steps){

digitalWrite(SLEEP, HIGH);
digitalWrite(MS1, LOW);
digitalWrite(MS2, LOW);

digitalWrite(dirPin,dir);

delay(50);

for(int i=0;i<steps;i++){
digitalWrite(stepperPin, LOW);
digitalWrite(stepperPin, HIGH);
delayMicroseconds(1000);
}
}

void loop(){
step(true,1600);
delay(1000);

}

Technically, the motor should just keep going around in circles in one direction smoothly. However, it is jerky, sometimes travels in reverse, or changes directions in the middle of a stepping sequence. Not sure what could be wrong?

Have you tried the Stepper library? Stepper - Arduino Reference

I took a look through the stepper library, however isn't that for using the PWM option for Arduino?

I'm using the Easydriver 4.2/4.3 so that I wouldn't have to use the Arduino PWM to control the stepper. I should just have to pass it the direction, and number of steps with the proper sequencing.

I'm noticing that the stepper motor doesn't like it if I try to change the speed. The 1000 microsecond delay is pretty much all it will work with.

Do you happen to know how to properly adjust the current setting on the Easydriver? I have moved it around a little, but don't really notice a difference in my stepper performance or smoothness.

I took a look through the stepper library, however isn't that for using the PWM option for Arduino?

No. It's for driving stepper motors.

I'm noticing that the stepper motor doesn't like it if I try to change the speed. The 1000 microsecond delay is pretty much all it will work with.

Speed is most definitely a function of current, and, to a lesser extent, voltage. Given adequate current, the motors will step faster.

Do you happen to know how to properly adjust the current setting on the Easydriver?

There is a potentiometer that adjusts the amount of current drawn. Of course, this presupposes that there is adequate current available to be drawn. In your situation, this appears to not necessarily be the case.

How are you powering the stepper motors?

Well I figured out part of my problem.

I had the stepper motor wired improperly. It is a cheap stepper from an electronics store to which I could not find the data sheet anywhere online. I did find a picture of one wired, so I wired mine the same. The assumption that someone else wired it properly was a poor decision on my part. I decided to ohm out the motor tonight and I now have it wired correctly, which fixed the erratic behaviour. My basic programs run properly, and the stepper has much more torque and holding torque now.

I'm powering the stepper and the easy driver with a 12V DC supply which has a 5.8A rating. It is plenty for this application. Now that the stepper is wired correctly, I adjusted the potentiometer so that the motor runs smoothly. This may be a silly question, but how can I go about measuring the actual current when I adjust it? Should I just use my multimeter and put it inline with one of the wires for the stepper motor? Would that be the correct process?

Tomorrow I will play around more with the program and see where I can make improvements such that it is more reliable. Thank you for all of your help so far. I truly appreciate it. I will post the new code tomorrow :slight_smile:

I had the stepper motor wired improperly.

Hard to get the software working until the hardware does. Glad you got the hardware sorted out.

suggest you change the stepper code to include a small delay

for(int i=0;i<steps;i++){             
   //loop through the number of steps that the stepper motor must complete
   digitalWrite(stepperPin, LOW);
   [glow]delayMicroseconds(500);[/glow]
   digitalWrite(stepperPin, HIGH);
   delayMicroseconds(1000);
 }

and rather than sleep (to disable the stepper)
why not use the Enable input instead?

I haven't tried adding that delay in there yet with it being wired properly. When it was wired improperly, it didn't like the delay, however that doesn't mean much considering the way it was wired. I can give that a try.

As for the "enable," I see the pin for it, however, what does it do? If I don't send voltage to it, the board already accepts input. If I send it a voltage, is it just for redundancy?

Thanks!

I finally got it to do what I had originally intended. The delays could use some work to speed up the process, and I could filter out some noise a little better, but here is the code I have:

//Arduino Uno, Easydriver, Stepper Motor, Accelerometer Control
//doublec4 2011
//Easydriver pins

int dirPin = 3;
int stepperPin = 2;
int SLEEP = 8;
int MS1 = 7;
int MS2 = 9;

//Accelerometer pins (analog)

const int pinx = 1 ;
const int piny = 2 ;
const int pinz = 3 ;
const int SLP = 10;

//variables to store accelerometer output and keep track of stepper position
int valx = 0;
int valy = 0;
int valz = 0;

int calib = 0;
int position = 0;

int count = 0;

//setup

void setup() {
Serial.begin(9600);

pinMode(SLP, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(stepperPin, OUTPUT);
pinMode(MS1, OUTPUT);
pinMode(MS2, OUTPUT);
pinMode(SLEEP, OUTPUT);
}

void loop(){

digitalWrite(SLP, HIGH); //Make sure the accelerometer is "awake"
digitalWrite(SLEEP, HIGH);
digitalWrite(MS1, LOW);
digitalWrite(MS2, LOW);
valy = analogRead(piny);

if (count > 2) {

if (calib == 0) { //For the first time through the loop, set the "calibration" value to y input from the accelerometer
calib = 300;
position = calib;
}

//while(valy > (position + 5) || valy < (position - 5)) {
//digitalWrite(dirPin,HIGH);

//digitalWrite(stepperPin, LOW);
//digitalWrite(stepperPin, HIGH);
//delayMicroseconds(1500);
//}
Serial.print("Calibration: ");
Serial.print(calib);
Serial.print(" Position: ");
Serial.print(position);
Serial.print(" Valy: ");
Serial.println(valy);

if ((valy > (calib + 10)) || (valy < (calib - 10))) {

if ((valy - position) > 0) { //If the G reading (positive direction) is greater than the current position, move up towards that position

digitalWrite(dirPin,HIGH);

digitalWrite(stepperPin, LOW);

digitalWrite(stepperPin, HIGH);
delayMicroseconds(1200);
position++;
}

if (((calib - valy + calib) - position) > 0) { //If the G reading (negative direction) is greater than the current position, move up towards that position

digitalWrite(dirPin,HIGH);

digitalWrite(stepperPin, LOW);

digitalWrite(stepperPin, HIGH);
delayMicroseconds(1200);
position++;
}

if (((valy - position) < 0) && (position > calib) && (valy > calib)) { //If the G reading (positive direction) is less than the current position, move down towards that position

digitalWrite(dirPin,LOW);

digitalWrite(stepperPin, LOW);

digitalWrite(stepperPin, HIGH);
delayMicroseconds(1200);
position--;
}

if ((((calib - valy + calib) - position) < 0) && (position > calib) && (valy < calib)) { //If the G reading (negative direction) is less than the current position, move down towards that position

digitalWrite(dirPin,LOW);

digitalWrite(stepperPin, LOW);

digitalWrite(stepperPin, HIGH);
delayMicroseconds(1200);
position--;
}
}
if ((valy < (calib + 10)) && (valy > (calib - 10))) {
if (position > calib){

digitalWrite(dirPin,LOW);

digitalWrite(stepperPin, LOW);

digitalWrite(stepperPin, HIGH);
delayMicroseconds(1200);
position--;
}

}

}

count++;

}

Basically, the stepper motor travels in one direction to a position related to a G force. The higher the G, the greater the position away. Right now only using the y axis. When no G is detected, the stepper returns to the original position.

Comments and critiques welcome. Not sure if I could have done this in a more elegant and robust way? I'd love to know! Thanks!

the difference between sleep and enable:

sleep sends the whole board to sleep - it takes a finite time to wake up
enable (or rather NOT enable) is a signal that switches off the output stage

quick look at the data sheet will tell all

as it is a NOT input, by default it is enabled, you can disable by setting it HIGH

Sounds good. So technically, if I have nothing connected to the sleep pin, or the enable pin, it will always be on, and ready for input. Eliminating that amount of time to enable the board?

yup!

disable (NOT enable) is good to switch off the output stages after a period of inactivity
a) keeps power consumed down
b) keeps chips cool

Perfect, thanks.

I guess I don't really need either option then. Whenever the arduino is on, I want to constantly monitor accelerometer input and never have "down time" so to speak with the stepper motor.