Rotary Encoder and Stepper motor

Hi to all,

I’m using Motor Shield v2.0 by Seeedstudio with my Arduino UNO R3 since I want to control a stepper motor with a rotary encoder.

I’m able to read values from my rotary encoder and I’m also able to control the stepper motor without problems.

What I want to do is to move the stepper motor within a range between 0 to +90 degrees by moving the rotary encoder.
For example, if I move the encoder +4 then the motor should move clockwise +4 and then stops.
At this point, if I move the encoder -4 then the motor should return to its previous position and then stops.

What happens now is that when I move the encoder +4, the motor move forward clockwise but it does not stop and continue to go forward +4 and so on.

What I have to do in order to stop the motor after each command?
I tried to use a temp var (preValue) and to check if the last value from encoder is equals to the current value, but it seems to not work properly.

This is the code I’m using at the moment.

Thank you!

//  Demo function:The application method to drive the stepper motor.
//  Hareware:Stepper motor - 24BYJ48,Seeed's Motor Shield v2.0
//  Author:Frankie.Chu
//  Date:20 November, 2012
#define MOTOR_CLOCKWISE      0
#define MOTOR_ANTICLOCKWISE  1
/******Pins definitions*************/
#define MOTORSHIELD_IN1	8
#define MOTORSHIELD_IN2	11
#define MOTORSHIELD_IN3	12
#define MOTORSHIELD_IN4	13
#define CTRLPIN_A		9
#define CTRLPIN_B		10

//these pins can not be changed 2/3 are special pins
int encoderPin1 = 2;
int encoderPin2 = 3;
int preValue = 0;

volatile int lastEncoded = 0;
volatile long encoderValue = 0;

long lastencoderValue = 0;

int lastMSB = 0;
int lastLSB = 0;

const unsigned char stepper_ctrl[]={0x27,0x36,0x1e,0x0f};
struct MotorStruct
{
	int8_t speed;
	uint8_t direction;
};
MotorStruct stepperMotor;
unsigned int number_of_steps = 200;
/**********************************************************************/
/*Function: Get the stepper motor rotate                               */
/*Parameter:-int steps,the total steps and the direction the motor rotates.*/
/*			if steps > 0,rotates anticlockwise,			   			   */
/*			if steps < 0,rotates clockwise.           				   */
/*Return:	void                      							      */
void step(int steps)
{
	int steps_left = abs(steps)*4;
	int step_number;
	int millis_delay = 60L * 1000L /number_of_steps/(stepperMotor.speed + 50);
	if (steps > 0) 
	{
		stepperMotor.direction= MOTOR_ANTICLOCKWISE;
		step_number = 0; 
	}
    else if (steps < 0) 
	{
		stepperMotor.direction= MOTOR_CLOCKWISE;
		step_number = number_of_steps;
	}
	else return;
	while(steps_left > 0) 
	{
		PORTB = stepper_ctrl[step_number%4];
		delay(millis_delay);
		if(stepperMotor.direction== MOTOR_ANTICLOCKWISE)
		{
			step_number++;
		    if (step_number == number_of_steps)
		    	step_number = 0;
		}
		else 
		{
			step_number--;
		    if (step_number == 0)
		    	step_number = number_of_steps;
		}
		steps_left --;
		
	}
}
void initialize()
{
	pinMode(MOTORSHIELD_IN1,OUTPUT);
	pinMode(MOTORSHIELD_IN2,OUTPUT);
	pinMode(MOTORSHIELD_IN3,OUTPUT);
	pinMode(MOTORSHIELD_IN4,OUTPUT);
	pinMode(CTRLPIN_A,OUTPUT);
	pinMode(CTRLPIN_B,OUTPUT);
	stop();
	stepperMotor.speed = 25;
	stepperMotor.direction = MOTOR_CLOCKWISE;
}
/*******************************************/
void stop()
{
	/*Unenble the pin, to stop the motor. */
    digitalWrite(CTRLPIN_A,LOW);
    digitalWrite(CTRLPIN_B,LOW);
}

void setup()
{
	initialize();//Initialization for the stepper motor.
  Serial.begin (9600);

 // pinMode(7, INPUT);    
  pinMode(encoderPin1, INPUT); 
  pinMode(encoderPin2, INPUT);

  digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
  digitalWrite(encoderPin2, HIGH); //turn pullup resistor on

  //call updateEncoder() when any high/low changed seen
  //on interrupt 0 (pin 2), or interrupt 1 (pin 3) 
  attachInterrupt(0, updateEncoder, CHANGE); 
  attachInterrupt(1, updateEncoder, CHANGE);
}

void loop()
{
        if (encoderValue >= 15) encoderValue = 15;
        if (encoderValue <= -15) encoderValue = -15;
        if (preValue == encoderValue)
       {
         stop();
       }
       else {
        Serial.print("encoderValue: ");
        Serial.print(encoderValue);
        Serial.print(" preValue: ");
        Serial.println(preValue);
	step(encoderValue);//Stepper motors rotate anticlockwise 200 steps.
	delay(1000);
      	step(encoderValue);//Stepper motors rotate clockwise 200 steps.
	delay(1000);
        preValue = encoderValue;
       }
}


void updateEncoder(){
  int MSB = digitalRead(encoderPin1); //MSB = most significant bit
  int LSB = digitalRead(encoderPin2); //LSB = least significant bit

  int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++;
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --;

  lastEncoded = encoded; //store this value for next time
}

Why do you want to use the rotary encoder? If the motor doesn't skip steps, you simply take as many steps as needed. If the motor does skip steps, using an encoder doesn't guarantee that you can actually move the shaft to the desired position.

I perfer to use the rotary encoder since it can turn in both directions without problem and so I think it's easier to handle for my application.

It is not a problem if I can't control the stepper motor smoothly, I just want to avoid to have the motor to move contonously even when I'm not moving the encoder. I think this happens because the step() function continues to read the previous ecnoder value..

Steppers can be driven from an encoder, but you need an integral number encoder steps per stepper-motor step really. You then drive the motor like a 2-phase brushless servo. Its sometimes used in CNC setups to get the benefits of both a servomotor and a stepper (no mis-steps, high torque so no gearing needed). Rather specialised and such encoders aren't cheap.

Is your encoder on the output shaft of the stepper motor, and fixed to the shaft? Or is it fixed somewhere else?

Assuming the encoder is separate, you need to use the encoder to adjust the value of a variable which represents the desired position of the motor. So if you move the encoder +4 the motor position variable might change from 377 to 381 and if you move the encoder -4 the variable will go back to 377.

Then your motor movement function needs to read that position and move the motor it by stepping forwards or backwards by the appropriate number of steps.

...R

Hi guys I'm trying to achieve a similar thing but using a optical encoder from a old printer I can read the encoder values when it's moved but can't get any code to work to move the motor or my adafruit driver sheld v2 I basicly want to mimic the turns of the encoder and out put to m1-m2 . Does anyone have a basic code they could share that will work so I can tweak it to suit my purpose for the life of me I can't get the encoder to communicate to The motor at all please help me

@marcus barnet: I think I misuderstood your initial post - you are not measuring the motor
position with the encoder at all (which is 99% of the cases using an encoder).

Your code is rather spaghettified - it needs to be split up into small, well-named functions, then
you (and others) can actually read it and understand it.

Very good idea to use a stepper library here, and a variable to hold the current desired position.
I’d recommend AccelStepper and then you can call moveTo() every time the encoder value changes,
very simple.

@Mydakota: post all the details of your encoder and motor please…

Mark, @marcus barnet has been missing for 2 years :)

...R