Writing sensor value as a ratio

Ok. So, I want to control the speed of a stepper motor with a potentiometer. I’ve got it working “somewhat” but it’s really squirrelly and doesn’t replicate the actual speed capabilities of the motor.

Basically all I’m doing is reading the sensorValue of the pot and making that the microsecond delay.

I’m basing some of the programming on Daniel Thompson’s sketch for stepper w/ the Easy Driver:

////////////////////////////////////////////////////////
// Stepper Motor skecth for use with the EasyDriver 3.1
////////////////////////////////////////////////////////

// Dan Thompson 2008
//
// Inpired by the code and chat on this thread.
// http://forum.sparkfun.com/viewtopic.php?t=10378&highlight=easydriver
//
// Use this code at your own risk.
// For all the product details visit http://greta.dhs.org/EasyDriver/
// For the full tutorial visit http://danthompsonsblog.blogspot.com/
//

int dirpin = 3;
int steppin = 12;

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

pinMode(dirpin, OUTPUT);
pinMode(steppin, OUTPUT);
}
void loop()
{

int i;

digitalWrite(dirpin, LOW); // Set the direction.
delay(100);

Serial.println(">>");
for (i = 0; i<4000; i++) // Iterate for 4000 microsteps.
{
digitalWrite(steppin, LOW); // This LOW to HIGH change is what creates the
digitalWrite(steppin, HIGH); // “Rising Edge” so the easydriver knows to when to step.
delayMicroseconds(200); // This delay time is close to top speed for this
} // particular motor. Any faster the motor stalls.

digitalWrite(dirpin, HIGH); // Change direction.
delay(100);

Serial.println("<<");
for (i = 0; i<4000; i++) // Iterate for 4000 microsteps
{
digitalWrite(steppin, LOW); // This LOW to HIGH change is what creates the
digitalWrite(steppin, HIGH); // “Rising Edge” so the easydriver knows to when to step.
delayMicroseconds(200); // This delay time is close to top speed for this
} // particular motor. Any faster the motor stalls.

}

Dan uses the “delayMicroseconds(200)” command to set the speed at 200 microsteps. I’ve replaced the “200” w/ “sensorValue” for the pot.

This kind of work, but it doesn’t replicate the actual speed capabilities of the motor. What I think I want to do is multiply the sensor value by 0.195. This equates to the ratio between the default maximum value of the arduino’s input (1023) and the approximate maximum speed of the motor (200).

So, what I think I want to do is somehow write after the “delayMicroseconds” command the ratio “sensorValue * 0.195” But I’m not sure exactly how to do that. I’ve tried a few different ways of writing the math, but to no avail.

Any advice on how to do this? Am I barking up the wrong tree?

Have you looked at “map” ?
http://arduino.cc/en/Reference/Map

Please use the Code button (#) when posting code.

Sorry about that. I wasn't aware of the Code button. I'll definitely use it in the future.

The "map" looks like it may work. I'll give it a shot. Thanks.

Eh. Not really working. Here’s the code I’m using:

const int togglePin = 2;     // the number of the toggle pin
const int ledPin =  13;      // the number of the LED pin
const int buttonPin = 6;     // the number of the pushbutton pin 

 int buttonState = LOW;           // variable for reading the pushbutton status
 int oldbuttonState = LOW;
 int toggleState = HIGH;         // variable for reading the toggle status
 int oldtoggleState = HIGH;
 int dirpin = 3;              // the number of stepper direction pin
 int steppin = 12;            // the number of stepper input
 int sensorPin = 0;           // select the input pin for the potentiometer
 int sensorValue = analogRead(0);         // variable to store the value coming from the sensor
 int i;
 
 void setup() {
 Serial.begin(9600);
   pinMode(buttonPin, INPUT);    // initialize the pushbutton as an input
   pinMode(ledPin, OUTPUT);      // initialize the LED pin as an output
   pinMode(togglePin, INPUT);    // initialize the toggle pin as an input
   pinMode(dirpin, OUTPUT);      // initialize stepper direction pin as output
   pinMode(steppin, OUTPUT);     // initialize stepper drive pin as output
}

 void loop(){
   buttonState = digitalRead(buttonPin);    // reads the state of the pushbutton value
    if (buttonState != oldbuttonState)      // check if the button is pressed
    {
     if (buttonState == HIGH)               // if it is, buttonState is HIGH
     {
   toggleState = digitalRead(togglePin);  // read the state of the toggle value:
   if (toggleState != oldtoggleState)     // check if the toggle is pressed.
   {       
    if(toggleState == LOW)
     {                                                 // if it is, the toggleState is LOW  
     digitalWrite(ledPin, HIGH);                       // turn LED on   
    sensorValue = map(sensorValue, 0, 1023, 0, 200);   // read state of pot
  digitalWrite(dirpin, LOW);                           // Sets the direction.
  delay(1);                                            // smooths transition

  Serial.println(">>");
  for (i = 0; i<8000; i++)               // Iterate for 8000 microsteps.
  {
    digitalWrite(steppin, LOW);          // This LOW to HIGH change is what creates the
    digitalWrite(steppin, HIGH);         // "Rising Edge" so the easydriver knows to when to step.
    delayMicroseconds(sensorValue);      // Sets the speed based on pot setting
  }  
 }
   else {                                                // if toggle is off
     sensorValue = map(sensorValue, 0, 1023, 0, 200);    // read state of pot
     digitalWrite(ledPin, LOW);                          // turn LED off
     digitalWrite(dirpin, HIGH);                         // Change direction.
  delay(1);

  Serial.println("<<");
  for (i = 0; i<8000; i++)              // Iterate for 8000 microsteps
  {
    digitalWrite(steppin, LOW);        // This LOW to HIGH change is what creates the
    digitalWrite(steppin, HIGH);       // "Rising Edge" so the easydriver knows to when to step.
    delayMicroseconds(sensorValue);    // Sets the speed based on pot setting
   }
   }
   oldtoggleState = toggleState;        // change toggle state back to equal  
 }
 }
  oldbuttonState = buttonState;         // change button state back to equal
 }
 }

Buried in there is the following:

int sensorValue = analogRead(0);
sensorValue = map(sensorValue, 0, 1023, 0, 200);
delayMicroseconds(sensorValue);

It seems to not actually respond to the changes in the pot at all. Rather, it just spins slowly.

What am I doing wrong?

Have you used Serial.print or Serial.println to verify that sensorValue changes as you rotate the potentiometer (i.e. that the potentiometer is wired correctly)?

No, but I've put a meter on the pot and it's working the way it should in that regard.

I've got the outer pins wired to ground and 5V. The center pin is wired to Analog In 0

I've never actually used the Serial.print commands. Not sure exactly how to do that, but I'll give it a try.

In setup, add:

Serial.begin(9600);

In loop(), after the analgRead() call, add these statements:

Serial.print("Potentiometer setting: ");
Serial.println(sensorValue, DEC);

Then, after uploading the sketch, open the Serial Monitor window, and set the baud rate to that in the Serial.begin statement.

As you turn the potentiometer, the values printed should range from 0 to 1023. If they don't, you've found the problem. Fixing it is another matter.

You might want to actually define the potentiometer pin as an input pin, too, in setup.

One final thing, the analogRead of pin 0 needs to happen in loop, not before setup is called.

OK. A lot of info. I'll try and process all that and see what happens.

Thanks a lot for the help.

Start at the bottom, and work up. The digitalRead in the wrong place is the biggest of the problems.

Do you mean analogRead ?

Yes. Damn multi-tasking getting in the way, again.

Alright, making progress. I’m reading the sensor value of the potentiometer and it seems like the map function is actually working. It’s affecting the speed of the stepper, but it’s doing so in an inconsistent manner. Sometimes a lower number makes it go faster than a higher one. Sometimes vice versa. Sometimes it stalls and sputters. I can’t really find a pattern.

Any ideas?

Here’s the code:

const int togglePin = 2;     // the number of the toggle pin
const int ledPin =  13;      // the number of the LED pin
const int buttonPin = 6;     // the number of the pushbutton pin 

 int buttonState = LOW;           // variable for reading the pushbutton status
 int oldbuttonState = LOW;
 int toggleState = HIGH;         // variable for reading the toggle status
 int oldtoggleState = HIGH;
 int dirpin = 3;              // the number of stepper direction pin
 int steppin = 12;            // the number of stepper input
 int sensorPin = 0;           // select the input pin for the potentiometer
 int sensorValue = 0;         // variable to store the value coming from the sensor
 int i;
 
 void setup() {
 Serial.begin(9600);
   pinMode(sensorPin, INPUT);    // initialize the pot as an input
   pinMode(buttonPin, INPUT);    // initialize the pushbutton as an input
   pinMode(ledPin, OUTPUT);      // initialize the LED pin as an output
   pinMode(togglePin, INPUT);    // initialize the toggle pin as an input
   pinMode(dirpin, OUTPUT);      // initialize stepper direction pin as output
   pinMode(steppin, OUTPUT);     // initialize stepper drive pin as output
}

 void loop(){
   buttonState = digitalRead(buttonPin);    // reads the state of the pushbutton value
    if (buttonState != oldbuttonState)      // check if the button is pressed
    {
     if (buttonState == HIGH)               // if it is, buttonState is HIGH
     {
   toggleState = digitalRead(togglePin);  // read the state of the toggle value:
   if (toggleState != oldtoggleState)     // check if the toggle is pressed.
   {       
    if(toggleState == LOW)
     {                                     // if it is, the toggleState is LOW  
     digitalWrite(ledPin, HIGH);           // turn LED on   
                                           // read state of pot
    sensorValue = map(analogRead(sensorPin), 0, 1023, 0, 200);
    Serial.print("Potentiometer setting: ");
    Serial.println(sensorValue, DEC);
  digitalWrite(dirpin, LOW);               // Sets the direction.
  delay(1);                                // smooths transition

  Serial.println(">>");
  for (i = 0; i<20000; i++)               // Iterate for 20000 microsteps.
  {
    digitalWrite(steppin, LOW);          // This LOW to HIGH change is what creates the
    digitalWrite(steppin, HIGH);         // "Rising Edge" so the easydriver knows to when to step.
    delayMicroseconds(sensorValue);      // Sets the speed based on pot setting
  }  
 }
   else {                                    // if toggle is off
                                             // read state of pot
     sensorValue = map(analogRead(sensorPin), 0, 1023, 0, 200);
     Serial.print("Potentiometer setting: ");
     Serial.println(sensorValue);
     digitalWrite(ledPin, LOW);              // turn LED off
     digitalWrite(dirpin, HIGH);             // Change direction.
  delay(1);

  Serial.println("<<");
  for (i = 0; i<20000; i++)              // Iterate for 20000 microsteps
  {
    digitalWrite(steppin, LOW);        // This LOW to HIGH change is what creates the
    digitalWrite(steppin, HIGH);       // "Rising Edge" so the easydriver knows to when to step.
    delayMicroseconds(sensorValue);    // Sets the speed based on pot setting
   }
   }
   oldtoggleState = toggleState;        // change toggle state back to equal  
 }
 }
  oldbuttonState = buttonState;         // change button state back to equal
 }
 }

I would suggest that you work on one issue at a time. Create a new sketch that just controls the stepper motor. No push button, no toggle button, and no potentiometer.

Set a delay value:

define WAIT 100

Then run the stepper motor for some number of steps (20000 is fine). Step in one direction, then step. Use delayMicroseconds(WAIT) after each step.

Run the sketch, and see if the stepper moves smoothly. If it does, change the value of WAIT to a larger number (150, 200, 250 etc.) and see if the motor still moves smoothly, at slower and slower speeds.

Then, change WAIT to smaller numbers (150, 100, 50, etc.) and see if the motor runs smoothly, but faster and faster.

If it does not run smoothly at all speeds, then you might have a wiring issue or a current supply issue.

Once the motror runs smoothly, then add the potentiometer back in, to contro the delay. When that works, add the buttons back in.

I've done the first step. I have a test code that I've been using to check the components that has a defined delay that I change manually. It moves fine at each value.

I've also built the sketch one step at a time, adding components as I go, as you've suggested.

What I haven't done is test the potentiometer alone with the map function, but without the buttons.

Worth a shot.

I can make the stepper run well by manually inputting the delayMicroseconds value from about 150 to about 2000. That’s really as much speed control as I need.

Then, putting the pot back in the mix with mapping to the above values, I can monitor the sensorValue and see that the pot is reading correctly, but the motor responds poorly. At all values it just stutters, haltingly along.

int dirpin = 3;
int steppin = 12;
int sensorPin = 0;           // select the input pin for the potentiometer
int sensorValue = 0;         // variable to store the value coming from the sensor

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

pinMode(sensorPin, INPUT);    // initialize the pot as an input
pinMode(dirpin, OUTPUT);
pinMode(steppin, OUTPUT);
}
void loop()
{

  int i;

  digitalWrite(dirpin, LOW);     // Set the direction.
  delay(1);
  
  Serial.println(">>");
  for (i = 0; i<20000; i++)       // Iterate for 4000 microsteps.
  {
    digitalWrite(steppin, LOW);  // This LOW to HIGH change is what creates the
    digitalWrite(steppin, HIGH); // "Rising Edge" so the easydriver knows to when to step.
    sensorValue = map(analogRead(sensorPin), 1023, 0, 2000, 150);
    Serial.print("Potentiometer setting: ");
    Serial.println(sensorValue, DEC);
    delayMicroseconds(sensorValue);     
  }                             

}
    sensorValue = map(analogRead(sensorPin), 1023, 0, 2000, 150);

I'd try changing the limits in the map function.

    sensorValue = map(analogRead(sensorPin), 0, 1023, 150, 2000);

Yeah, I see the benefit of that.

But it's still doing the same thing as before.

So, try this: Move the code for reading the sensor value, and mapping it, out of the for loop that runs the motor. You need only read and map once, not 20,000 times.