Controlling Stepper using incrimental rotary encoder and arduino

Hello,
I am working on a project in which need to rotate stepper motor at different speed (variable speed ratio between encoder and stepper) for a constant speed of rotary encoder by feeding a multiplayer through keyboard.
I have NEMA 17stepper motor with A4988 driver, Incrimental rotary encoder (Orange, 400 PPR), Arduino, Keypad, LCD.

Please read and follow this link: How to get the best out of this forum - Using Arduino / Project Guidance - Arduino Forum

Your words are not enough at all to give precise answers.

The schematic diagram is the language that we use to describe electronic circuits. A hand drawn, photographed and posted schematic is perfectly acceptable. Include all components, their part numbers and/or values and all power supplies. If you would like to do a CAD generated schematic the how to make a schematic you can post tutorial will get you started.

Also include the technical data (data sheets, manuals) for the components.

Post the code. All of the code. Read the forum guidelines to see how to properly post code and some good information on making a good post.
Use the IDE autoformat tool (ctrl-t or Tools, Auto format) before posting code in code tags.

If the code will not compile because of errors, please include the entire error message. It is easy to do. There is a button (lower right of the IDE window) called "copy error message". Copy the error and paste into a post in code tags. Paraphrasing the error message leaves out important information.

If the code does compile but does not do what you want, tell us what the code actually does and how that differs from what you want.

The more information that we have the faster you will get help.

In my project I am using:

  1. An Arduino mega board
  2. A incremental rotary encoder for sensing the ground speed (Orange 400 PPR 2-Phase Incremental Optical Rotary Encoder)
  3. According to the RPM of encoder shaft I need to rotate NEMA 17 stepper motor with A4988 driver
  4. Here the RPM of rotary encoder shaft is fixed say 50 RPM and I need to change the RPM of stepper motor using a input value through keypad/Android application
  5. like
    if we want RPM of stepper motor and encoder be same i.e. 1:1 speed ratio then multiplier will be 1;
    If we need to rotate stepper motor 0.8 turn for one revolution of encoder then multiplier will be 0.8.
    and so on for other multiplier.

More words... Pay attention to the reply by groundFungus.

This code is working


#include <AccelStepper.h>
#define dirPin 4
#define stepPin 5
#define motorInterfaceType 1

// Create a new instance of the AccelStepper class:
AccelStepper stepper = AccelStepper(motorInterfaceType, stepPin, dirPin);

volatile unsigned int counter = 0;  //This variable will increase on the rotation of encoder

unsigned long lastTime = 0;         // will store last time value was sendt
const long interval = 100;
float speedOut;
int spacing;


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

  pinMode(2, INPUT);           // set pin to input
  digitalWrite(2, HIGH);       // turn on pullup resistors

  //Setting up interrupt
  //A rising pulse from encodenren activated ai0(). AttachInterrupt 0 is DigitalPin nr 2 on moust Arduino.
  attachInterrupt(0, ai0, RISING);

  stepper.setMaxSpeed(1000);
}

void loop() {
  stepper.setCurrentPosition(0);
  stepper.setSpeed(speedOut * 1.55);
  stepper.runSpeed();

  // Chedk if it's time to sendt data
  if (timeIntervall()) {
    sendData();
    resetSampling();
  }
}

void ai0() {
  // ai0 is activated if DigitalPin nr 2 is going from LOW to HIGH

  counter++;
}

void sendData() {


  speedOut = map(counter, 0, 400, 0, 2000);      // change from 400 pulse pr / second to 100 m/h


}

void resetSampling() {
  counter = 0;

}

boolean timeIntervall() {
  unsigned long currentTime = millis();

  // Chedk if it's time to make an interupt
  if (currentTime - lastTime >= interval) {
    lastTime = lastTime + interval;

    return true;
  } else if (currentTime < lastTime) {
    // After 50 day millis() will start 0 again
    lastTime = 0;

  } else {
    return false;
  }

}

But same was tried for multiple inputs from mobile app doesn't work.


#include <AccelStepper.h>
#define dirPin 4
#define stepPin 5
#define motorInterfaceType 1

// Create a new instance of the AccelStepper class:
AccelStepper stepper = AccelStepper(motorInterfaceType, stepPin, dirPin);

volatile unsigned int counter = 0;  //This variable will increase on the rotation of encoder

unsigned long lastTime = 0;         // will store last time value was sendt
const long interval = 100;
float speedOut;
char Value = 0;


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

  pinMode(2, INPUT);           // set pin to input
  digitalWrite(2, HIGH);       // turn on pullup resistors

  //Setting up interrupt
  //A rising pulse from encodenren activated ai0(). AttachInterrupt 0 is DigitalPin nr 2 on moust Arduino.
  attachInterrupt(0, ai0, RISING);

  stepper.setMaxSpeed(1000);
}

void loop()
{
  if (timeIntervall())
  {
    sendData();
    resetSampling();
  }

  if (Serial.available() > 0)
  {
    Value = Serial.read();
    if (Value == 'A')
    {
      Serial.println("The seed spacing is 5 cm ");
      stepper.setSpeed(speedOut * 3.13);
      stepper.runSpeed();
    }
    else if (Value == 'B')
    {
      Serial.println("The seed spacing is 10 cm ");
      stepper.setSpeed(speedOut * 1.56);
      stepper.runSpeed();

    }
    else if (Value == 'C')
    {
      Serial.println("The seed spacing is 15 cm ");
      stepper.setSpeed(speedOut * 1.04);
      stepper.runSpeed();

    }
    else if (Value == 'D')
    {
      Serial.println("The seed spacing is 20 cm ");
      stepper.setSpeed(speedOut * 0.78);
      stepper.runSpeed();

    }
    else if (Value == 'E')
    {
      Serial.println("The seed spacing is 25 cm ");
      stepper.setSpeed(speedOut * 0.625);
      stepper.runSpeed();

    }
    else if (Value == 'F')
    {
      Serial.println("The seed spacing is 30 cm ");
      stepper.setSpeed(speedOut * 0.52);
      stepper.runSpeed();

    }
    else if (Value == 'G')
    {
      Serial.println("The seed spacing is 35 cm ");
      stepper.setSpeed(speedOut * 0.446);
      stepper.runSpeed();

    }
    else if (Value == 'H')
    {
      Serial.println("The seed spacing is 40 cm ");
      stepper.setSpeed(speedOut * 0.39);
      stepper.runSpeed();

    }
    else if (Value == 'I')
    {
      Serial.println("The seed spacing is 45 cm ");
      stepper.setSpeed(speedOut * 0.35);
      stepper.runSpeed();

    }
    else if (Value == 'J')
    {
      Serial.println("The seed spacing is 50 cm ");
      stepper.setSpeed(speedOut * 0.31);
      stepper.runSpeed();

    }
    else if (Value == 'K')
    {
      Serial.println("The seed spacing is 55 cm ");
      stepper.setSpeed(speedOut * 0.28);
      stepper.runSpeed();

    }
    else if (Value == 'L')
    {
      Serial.println("The seed spacing is 60 cm ");
      stepper.setSpeed(speedOut * 0.26);
      stepper.runSpeed();

    }
  }
}

void ai0() {
  // ai0 is activated if DigitalPin nr 2 is going from LOW to HIGH

  counter++;
}

void sendData() {


  speedOut = map(counter, 0, 400, 0, 2000);      // change from 400 pulse pr / second to 100 m/h


}

void resetSampling() {
  counter = 0;

}

boolean timeIntervall() {
  unsigned long currentTime = millis();

  // Chedk if it's time to make an interupt
  if (currentTime - lastTime >= interval) {
    lastTime = lastTime + interval;

    return true;
  } else if (currentTime < lastTime) {
    // After 50 day millis() will start 0 again
    lastTime = 0;

  } else {
    return false;
  }

}

That is not a very good problem description. In fact it tells us nothing that we can use to help you. So, please, describe what the code actually does and how that differs from what you want it to do.

What do your debug prints tell you is happening?

If there are compile errors, please include the entire error message. It is easy to do. There is a button (lower right of the IDE window) called "copy error message". Copy the error and paste into a post in code tags. Paraphrasing the error message leaves out important information.

Problem is when I send the Value i.e. A, B, C, ..............The serial monitor shows the respective output i.e. The seed spacing is ___ cm. But stepper.setSpeed() dosent work.

Actually I want that when I send value A from application the speed of stepper motor will get 3.13 times the speedOut; similarly if I send B the speed of stepper motor will get 1.56 times the speedOut; and so on.

speedOut is obtained from a rotating speed of Rotary encoder.

The runSpeed() function must be called over and over. The stepper will step one time per call to runSpeed() if it is time to step.

Take the runStepper() functions out of each if block and out of the if(Serial.available) block and put it in loop() so that runSpeed() called every time through loop(). RunSpeed() needs to be called as often as possible.

I don't know what that timeIntervall() function is doing. If you use subtraction in the millis() if statement you do not have to worry about roll over. The rest of that code in that function is superfluous.

const long interval = 100;

All variables that are used for millis() timing need to be declared unsigned long.

Non-blocking timing tutorials:
Blink without delay().
Beginner's guide to millis().
Several things at a time.

Not working

Bummer.

Please help me;
Is there any problem of function call inside if-else or other, because the condition is executed as shown on serial monitor but stepper.setSpeed() and stepper.runSpeed(); function are not working.

Hello;
In my programme I am getting the value according to input from serial monitor but the stepper.setSpeed() and stepper.runSpeed() functions inside same if-else are not working.

Please suggest the necessary corrections.


#include <AccelStepper.h>
#define dirPin 4
#define stepPin 5
#define motorInterfaceType 1

// Create a new instance of the AccelStepper class:
AccelStepper stepper = AccelStepper(motorInterfaceType, stepPin, dirPin);

volatile unsigned int counter = 0;  //This variable will increase on the rotation of encoder

unsigned long lastTime = 0;         // will store last time value was sendt
const long interval = 100;
float speedOut;
char Value = 0;


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

  pinMode(2, INPUT);           // set pin to input
  digitalWrite(2, HIGH);       // turn on pullup resistors

  //Setting up interrupt
  //A rising pulse from encodenren activated ai0(). AttachInterrupt 0 is DigitalPin nr 2 on moust Arduino.
  attachInterrupt(0, ai0, RISING);

  stepper.setMaxSpeed(1000);
}

void loop()
{
  if (timeIntervall())
  {
    sendData();
    resetSampling();
  }
  if (Serial.available() > 0)
  {
    Value = Serial.read();
    if (Value == 'A')
    {
     Serial.println("The seed spacing is 5 cm ");
     stepper.setSpeed(speedOut * 3.31);
     stepper.runSpeed();
     }  
    else if (Value == 'B')
    {
      Serial.println("The seed spacing is 10 cm ");
      stepper.setSpeed(speedOut * 1.56);
      stepper.runSpeed();

    }
    else if (Value == 'C')
    {
      Serial.println("The seed spacing is 15 cm ");
      stepper.setSpeed(speedOut * 1.04);
      stepper.runSpeed();

    }
    else if (Value == 'D')
    {
      Serial.println("The seed spacing is 20 cm ");
      stepper.setSpeed(speedOut * 0.78);
      stepper.runSpeed();

    }
    else if (Value == 'E')
    {
      Serial.println("The seed spacing is 25 cm ");
      stepper.setSpeed(speedOut * 0.625);
      stepper.runSpeed();

    }
    else if (Value == 'F')
    {
      Serial.println("The seed spacing is 30 cm ");
      stepper.setSpeed(speedOut * 0.52);
      stepper.runSpeed();

    }
    else if (Value == 'G')
    {
      Serial.println("The seed spacing is 35 cm ");
      stepper.setSpeed(speedOut * 0.446);
      stepper.runSpeed();

    }
    else if (Value == 'H')
    {
      Serial.println("The seed spacing is 40 cm ");
      stepper.setSpeed(speedOut * 0.39);
      stepper.runSpeed();

    }
    else if (Value == 'I')
    {
      Serial.println("The seed spacing is 45 cm ");
      stepper.setSpeed(speedOut * 0.35);
      stepper.runSpeed();

    }
    else if (Value == 'J')
    {
      Serial.println("The seed spacing is 50 cm ");
      stepper.setSpeed(speedOut * 0.31);
      stepper.runSpeed();

    }
    else if (Value == 'K')
    {
      Serial.println("The seed spacing is 55 cm ");
      stepper.setSpeed(speedOut * 0.28);
      stepper.runSpeed();

    }
    else if (Value == 'L')
    {
      Serial.println("The seed spacing is 60 cm ");
      stepper.setSpeed(speedOut * 0.26);
      stepper.runSpeed();

    }
  }

}

void ai0() {
  // ai0 is activated if DigitalPin nr 2 is going from LOW to HIGH

  counter++;
}

void sendData() {


  speedOut = map(counter, 0, 400, 0, 2000);      // change from 400 pulse pr / second to 100 m/h


}

void resetSampling() {
  counter = 0;

}

boolean timeIntervall() {
  unsigned long currentTime = millis();

  // Chedk if it's time to make an interupt
  if (currentTime - lastTime >= interval) {
    lastTime = lastTime + interval;

    return true;
  } else if (currentTime < lastTime) {
    // After 50 day millis() will start 0 again
    lastTime = 0;

  } else {
    return false;
  }

}

Your text "is not working" tells us nothing.
As a beginning I suggest doing a Serial.println of the data read in "value = Serial.read.

Well, that implies one of two things.

  1. The stepper code is not working. Did you try just some code which exercises the stepper with different speeds every few seconds?
  2. The "if" conditions are not met. Is it actually giving you the responses on the serial monitor? Are you typing commands as capitals?

Yes;
Stepper is working at different speed of encoder by using following programme


#include <AccelStepper.h>
#define dirPin 4
#define stepPin 5
#define motorInterfaceType 1

// Create a new instance of the AccelStepper class:
AccelStepper stepper = AccelStepper(motorInterfaceType, stepPin, dirPin);

volatile unsigned int counter = 0;  //This variable will increase on the rotation of encoder

unsigned long lastTime = 0;         // will store last time value was sendt
const long interval = 100;
float speedOut;
int spacing;


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

  pinMode(2, INPUT);           // set pin to input
  digitalWrite(2, HIGH);       // turn on pullup resistors

  //Setting up interrupt
  //A rising pulse from encodenren activated ai0(). AttachInterrupt 0 is DigitalPin nr 2 on moust Arduino.
  attachInterrupt(0, ai0, RISING);

  stepper.setMaxSpeed(1000);
}

void loop() {
  stepper.setCurrentPosition(0);
  stepper.setSpeed(speedOut * 8);
  stepper.runSpeed();

  // Chedk if it's time to sendt data
  if (timeIntervall()) {
    sendData();
    resetSampling();
  }
}

void ai0() {
  // ai0 is activated if DigitalPin nr 2 is going from LOW to HIGH

  counter++;
}

void sendData() {


  speedOut = map(counter, 0, 400, 0, 2000);      // change from 400 pulse pr / second to 100 m/h


}

void resetSampling() {
  counter = 0;

}

boolean timeIntervall() {
  unsigned long currentTime = millis();

  // Chedk if it's time to make an interupt
  if (currentTime - lastTime >= interval) {
    lastTime = lastTime + interval;

    return true;
  } else if (currentTime < lastTime) {
    // After 50 day millis() will start 0 again
    lastTime = 0;

  } else {
    return false;
  }

}

Yes while typing 'A' on serial monitor result on serial monitor is 'The seed spacing is 5 cm' but stepper motor does not responding.

I think the problem is in calling stepper functions inside condition. Because if we feed 'A' on serial monitor the complete loop get executed at once only; but for rotation of stepper we need continuous input from encoder.

Oh. So you mean the code should be:

#include <AccelStepper.h>
#define dirPin 4
#define stepPin 5
#define motorInterfaceType 1

// Create a new instance of the AccelStepper class:
AccelStepper stepper = AccelStepper(motorInterfaceType, stepPin, dirPin);

volatile unsigned int counter = 0;  //This variable will increase on the rotation of encoder

unsigned long lastTime = 0;         // will store last time value was sendt
const long interval = 100;
float speedOut;
char Value = 0;

void setup() {
  Serial.begin (9600);
  pinMode(2, INPUT);           // set pin to input
  digitalWrite(2, HIGH);       // turn on pullup resistors

  //Setting up interrupt
  //A rising pulse from encodenren activated ai0(). AttachInterrupt 0 is DigitalPin nr 2 on moust Arduino.
  attachInterrupt(0, ai0, RISING);

  stepper.setMaxSpeed(1000);
}

void loop()
{
  if (timeIntervall())
  {
    sendData();
    resetSampling();
  }
  if (Serial.available() > 0)
  {
    Value = Serial.read();
    if (Value == 'A')
    {
     Serial.println("The seed spacing is 5 cm ");
     stepper.setSpeed(speedOut * 3.31);
     }  
    else if (Value == 'B')
    {
      Serial.println("The seed spacing is 10 cm ");
      stepper.setSpeed(speedOut * 1.56);
    }
    else if (Value == 'C')
    {
      Serial.println("The seed spacing is 15 cm ");
      stepper.setSpeed(speedOut * 1.04);
    }
    else if (Value == 'D')
    {
      Serial.println("The seed spacing is 20 cm ");
      stepper.setSpeed(speedOut * 0.78);
    }
    else if (Value == 'E')
    {
      Serial.println("The seed spacing is 25 cm ");
      stepper.setSpeed(speedOut * 0.625);
    }
    else if (Value == 'F')
    {
      Serial.println("The seed spacing is 30 cm ");
      stepper.setSpeed(speedOut * 0.52);
    }
    else if (Value == 'G')
    {
      Serial.println("The seed spacing is 35 cm ");
      stepper.setSpeed(speedOut * 0.446);
    }
    else if (Value == 'H')
    {
      Serial.println("The seed spacing is 40 cm ");
      stepper.setSpeed(speedOut * 0.39);
    }
    else if (Value == 'I')
    {
      Serial.println("The seed spacing is 45 cm ");
      stepper.setSpeed(speedOut * 0.35);
    }
    else if (Value == 'J')
    {
      Serial.println("The seed spacing is 50 cm ");
      stepper.setSpeed(speedOut * 0.31);
    }
    else if (Value == 'K')
    {
      Serial.println("The seed spacing is 55 cm ");
      stepper.setSpeed(speedOut * 0.28);
    }
    else if (Value == 'L')
    {
      Serial.println("The seed spacing is 60 cm ");
      stepper.setSpeed(speedOut * 0.26);
    }
  }
  stepper.runSpeed();
}

void ai0() {
  // ai0 is activated if DigitalPin nr 2 is going from LOW to HIGH
  counter++;
}

void sendData() {
  speedOut = map(counter, 0, 400, 0, 2000);      // change from 400 pulse pr / second to 100 m/h
}

void resetSampling() {
  counter = 0;
}

boolean timeIntervall() {
  unsigned long currentTime = millis();

  // Chedk if it's time to make an interupt
  if (currentTime - lastTime >= interval) {
    lastTime = lastTime + interval;
    return true;
  } else if (currentTime < lastTime) {
    // After 50 day millis() will start 0 again
    lastTime = 0;
  } else {
    return false;
  }
}

yes;
but output is not as expected because stepper motor didn't responding.