EEVblog Electronics Community Forum

Products => Computers => Programming => Topic started by: bkukuk62 on September 18, 2019, 07:15:53 pm

Title: Arduino Stepper Encoder programming question
Post by: bkukuk62 on September 18, 2019, 07:15:53 pm
The code below is supposed to rotate a stepper motor to match the encoder rotation but I have an if-else if-else if statement where the code uses both a library (Stepper.h) and literal pin settings for the encoder pinout and stepper pinout.
The first part of the if statement is supposed to look for a button push and rotate the stepper 5 full rotations otherwise do the first statement on this where the stepper motor matches the encoder.

This compiles but I am not sure if what I did is the best approach.

I would like any and all comments.
thanks,
bkukuk62

// Modified code for Arduino, Quadrature Optical Encoder, Stepper Motor 9-18-2019

#include <Stepper.h>

  const int InputPinStart = 8;  //  Input pin 8 to start auto rotation of rotor

  const int stepsPerRevolution = 200;  // Number of steps per revolution for the Stepper Motor

 #define encoder_a 2    //encoder a = arduino pin 2
 #define encoder_b 3    //encoder b = arduino pin 3
 #define motor_step 4    //motor step = arduino pin 4
 #define motor_direction 5    //motor direction = arduino pin 5

Stepper myStepper(stepsPerRevolution, 2, 3, 4, 5);

int stepCount = 0; //  number of steps the motor has taken
int val = 0;  // variable for reading input pin 8

volatile long motor_position, encoder;

void setup ()
{
    //set up the various outputs
    pinMode(motor_step, OUTPUT);
    pinMode(motor_direction, OUTPUT);
    // then the encoder inputs
    pinMode(encoder_a, INPUT);
    pinMode(encoder_b, INPUT);
    digitalWrite(encoder_a, HIGH);
    digitalWrite(encoder_b, HIGH);
    // encoder pin on interrupt 0 (pin 2)
    attachInterrupt(0, encoderPinChangeA, CHANGE);
    // encoder pin on interrupt 1 (pin 3)
    attachInterrupt(1, encoderPinChangeB, CHANGE);
    encoder = 0;
    pinMode (InputPinStart, INPUT);  //  Declare pushbutton as input to start rotation
}

void encoderPinChangeA()
{
    if (digitalRead(encoder_a) == digitalRead(encoder_b))
    {
        encoder--;
    }
    else
    {
        encoder++;
    }
}

void encoderPinChangeB()
{
    if (digitalRead(encoder_a) != digitalRead(encoder_b))
    {
        encoder--;
    }
    else
    {
        encoder++;
    }
}


void loop()
{
//do stuff dependent on encoder position here
//such as move a stepper motor to match encoder position
//if you want to make it 1:1 ensure the encoder res matches the motor res by dividing/multiplying
  int sensorReading = analogRead(A0);  //  Read the sensor value from potentiometer on pin A0
  int motorSpeed = map(sensorReading, 0, 1023, 0, 100);  //  Map sensor range from 0 to 100
  if (motorSpeed > 0) {
    myStepper.setSpeed(motorSpeed);
    // step 1/100 of a revolution:
    myStepper.step(stepsPerRevolution / 100);     
  }

  val = digitalRead(InputPinStart);
  if (InputPinStart == HIGH) {
    myStepper.step(stepsPerRevolution*5);  //  Turn stepper motor 5 full rotations     
    }
   
    else if (encoder > 0) {
        digitalWrite(motor_direction, HIGH);
        digitalWrite(motor_step, HIGH);
        digitalWrite(motor_step, LOW);
        _delay_us(200);
        motor_position++;
        encoder = 0;
    }
    else if (encoder < 0) {
        digitalWrite(motor_direction, LOW);
        digitalWrite(motor_step, HIGH);
        digitalWrite(motor_step, LOW);
        _delay_us(200);
        motor_position--;
        encoder = 0;
    }
}
Title: Re: Arduino Stepper Encoder programming question
Post by: ledtester on September 18, 2019, 08:53:07 pm
(btw - you can use the code tag to format code blocks)

Is this perhaps a typo?
Code: [Select]
  const int InputPinStart = 8;  //  Input pin 8 to start auto rotation of rotor
  ...
  val = digitalRead(InputPinStart);
  if (InputPinStart == HIGH) {

You are reading the encoder in a non-blocking fashion, so one improvement might be to make the other control code non-blocking as well. Here are some pointers:

- non-blocking ADC reading:

https://www.gammon.com.au/adc (https://www.gammon.com.au/adc)

- non-blocking stepper motor control:

https://reprage.com/post/non-blocking-control-of-stepper-motors-on-arduino (https://reprage.com/post/non-blocking-control-of-stepper-motors-on-arduino)
Title: Re: Arduino Stepper Encoder programming question
Post by: bkukuk62 on September 18, 2019, 10:00:20 pm
ledtester,
I think I have corrected the issues, can you review it again.  I removed the library portions.  I want the code to stop everything while the stepper is rotating 10 full rotations and resume afterward.
ledtester, thanks for helping me out on this.
-bkukuk62

// Modified code for Arduino, Quadrature Optical Encoder, Stepper Motor 9-17-2019

 const int PinStart = 8;  //  Input pin 8 to start auto rotation of rotor

 #define encoder_a 2    //encoder a = arduino pin 2
 #define encoder_b 3    //encoder b = arduino pin 3
 #define motor_step 4    //motor step = arduino pin 4
 #define motor_direction 5    //motor direction = arduino pin 5

volatile long motor_position, encoder;

void setup ()
{
    //set up the various outputs
    pinMode(motor_step, OUTPUT);
    pinMode(motor_direction, OUTPUT);
    // then the encoder inputs
    pinMode(encoder_a, INPUT);
    pinMode(encoder_b, INPUT);
    digitalWrite(encoder_a, HIGH);
    digitalWrite(encoder_b, HIGH);
    // encoder pin on interrupt 0 (pin 2)
    attachInterrupt(0, encoderPinChangeA, CHANGE);
    // encoder pin on interrupt 1 (pin 3)
    attachInterrupt(1, encoderPinChangeB, CHANGE);
    encoder = 0;
    pinMode (PinStart, OUTPUT);  //  Declare pushbutton as input to start rotation
}

void encoderPinChangeA()
{
    if (digitalRead(encoder_a) == digitalRead(encoder_b))
    {
        encoder--;
    }
    else
    {
        encoder++;
    }
}

void encoderPinChangeB()
{
    if (digitalRead(encoder_a) != digitalRead(encoder_b))
    {
        encoder--;
    }
    else
    {
        encoder++;
    }
}

void loop()
{
//if you want to make it 1:1 ensure the encoder res matches the motor res by dividing/multiplying

    if (PinStart == HIGH) {
      digitalWrite(motor_direction, HIGH);
      digitalWrite(motor_step, HIGH);
      _delay_us(200);
      digitalWrite(motor_step, LOW);
      _delay_us(200);
      for (int i = 0; i < 100; i++) {
        step(1000);
      }
   
    else (encoder > 0) {
        digitalWrite(motor_direction, HIGH);
        digitalWrite(motor_step, HIGH);
        digitalWrite(motor_step, LOW);
        _delay_us(200);
        motor_position++;
        encoder = 0;
    }

    else (encoder < 0) {
        digitalWrite(motor_direction, LOW);
        digitalWrite(motor_step, HIGH);
        digitalWrite(motor_step, LOW);
        _delay_us(200);
        motor_position--;
        encoder = 0;
    }
}
Title: Re: Arduino Stepper Encoder programming question
Post by: ledtester on September 18, 2019, 10:08:27 pm
PinStart is a constant - it will always be 8. HIGH is another constant - it will always be 1. Therefore this test:

Code: [Select]
    if (PinStart == HIGH) {

will always fail.

Maybe you want:

Code: [Select]
  if (digitalRead(PinStart) == HIGH)


Title: Re: Arduino Stepper Encoder programming question
Post by: bkukuk62 on September 18, 2019, 10:45:24 pm
ledtester,
thanks for the review and comments.  I reworked it again and got it to compile.
Do you see anything else that I tripped up on?
Code: [Select]
// Modified code for Arduino, Quadrature Optical Encoder, Stepper Motor 9-18-2019


 #define encoder_a 2    //  encoder a = arduino pin 2
 #define encoder_b 3    //  encoder b = arduino pin 3
 #define motor_step 4    //  motor step = arduino pin 4
 #define motor_direction 5    //  motor direction = arduino pin 5
 #define PinStart 8  //  button to start auto rotation of rotor = arduino pin 8

volatile long motor_position, encoder;

void setup () {
    //set up the various outputs
    pinMode(motor_step, OUTPUT);
    pinMode(motor_direction, OUTPUT);
    // then the encoder inputs
    pinMode(encoder_a, INPUT);
    pinMode(encoder_b, INPUT);
    digitalWrite(encoder_a, HIGH);
    digitalWrite(encoder_b, HIGH);
    // encoder pin on interrupt 0 (pin 2)
    attachInterrupt(0, encoderPinChangeA, CHANGE);
    // encoder pin on interrupt 1 (pin 3)
    attachInterrupt(1, encoderPinChangeB, CHANGE);
    encoder = 0;
    pinMode (PinStart, OUTPUT);  //  Declare pushbutton as input to start rotation
}

void step(long stepDelay) {
    digitalWrite(motor_step, HIGH);
    _delay_us(200);
    digitalWrite(motor_step, LOW);
    _delay_us(200);
}


void encoderPinChangeA()
{
    if (digitalRead(encoder_a) == digitalRead(encoder_b))
    {
        encoder--;
    }
    else
    {
        encoder++;
    }
}

void encoderPinChangeB()
{
    if (digitalRead(encoder_a) != digitalRead(encoder_b))
    {
        encoder--;
    }
    else
    {
        encoder++;
    }
}

void loop() {
//if you want to make it 1:1 ensure the encoder res matches the motor res by dividing/multiplying

    if (digitalRead(PinStart) == HIGH) {
      for (int i = 0; i < 100; i++) {
        step(1000);
      }
    }
   
    else if (encoder > 0) {
        digitalWrite(motor_direction, HIGH);
        digitalWrite(motor_step, HIGH);
        digitalWrite(motor_step, LOW);
        _delay_us(200);
        motor_position++;
        encoder = 0;
    }

    else if (encoder < 0) {
        digitalWrite(motor_direction, LOW);
        digitalWrite(motor_step, HIGH);
        digitalWrite(motor_step, LOW);
        _delay_us(200);
        motor_position--;
        encoder = 0;
    }
}
Title: Re: Arduino Stepper Encoder programming question
Post by: ledtester on September 18, 2019, 10:56:35 pm
ledtester,
thanks for the review and comments.  I reworked it again and got it to compile.
Do you see anything else that I tripped up on?

Getting help from an internet forum is going to work a lot better if you test your code first.

Test each individual part of it to see if it works the way you expect it to. Then you can come back and explain what you want it to do and what it is actually doing.
Title: Re: Arduino Stepper Encoder programming question
Post by: bkukuk62 on September 18, 2019, 11:03:48 pm
thanks,
testing tonight.

-bkukuk62
Title: Re: Arduino Stepper Encoder programming question
Post by: FreddieChopin on September 22, 2019, 07:14:43 am
You could use CppUTest library to unit test your code before trying it on actual hardware, it might be faster this way  :-+