Encoder Help

Status
Not open for further replies.

orbitronics

Well-known member
Hi,

I have a basic setup, at the moment i'm using an arduino nano, connected to two rotary encoders, and an A4988 stepper driver, that connected to a stepper motor.

i am using one encoder to change the RPM, and the second to manually move the stepper.

I'm running into a peculiar problem, where depending on how great 'steps' is in 'Stepper.move(steps)' for when i'm manually moving the stepper motor with an encoder, turning the knob smoothly in one direction outputs two alternating numbers like:

-8
-7
-8
-7
-6
-7
-6
-5
-6


Making 'steps' lower, even '1' outputs a predicted output (continuously counting in the right direction).

My guess is that the encoder, when actuated, is generating interrupts that is messing with the Stepper objects move function. I've tried to disable interrupts using a locking boolean value when i'm moving the stepper, it's not helping much.

Here's the code

Code:
/*

*/
// This optional setting causes Encoder to use more optimized code,
// It must be defined before Encoder.h is included.
#define ENCODER_OPTIMIZE_INTERRUPTS
#include <Encoder.h>
#include "DRV8825.h"

#define DIR 4
#define STEP 5
#define MAX_RPM 25
#define MIN_RPM 1
#define STOPPER_PIN 6
#define MOTOR_STEPS 4096
#define RPM 10
#define MICROSTEPS 1

boolean is_moving_manually = false;
int debug_flip = 1;
long newPosition0, newPosition1 = 10;
long oldPosition0, oldPosition1  = 10;
DRV8825 stepper(MOTOR_STEPS, DIR, STEP);
Encoder myEnc0(7, 2); // using the two interrupt pins on arduino uno / nano
Encoder myEnc1(8, 3);

void setup() {
  Serial.begin(115200);
  myEnc0.write(10 * 4);
  pinMode(STOPPER_PIN, INPUT_PULLUP);
  stepper.begin(RPM, MICROSTEPS);
  stepper.enable();
  Serial.println("START");
  stepper.stop();
  // stepper.startMove(100 * MOTOR_STEPS * MICROSTEPS);     // in microsteps
  // stepper.startRotate(100 * 360);                     // or in degrees
}

void loop() {
  // first, check if stopper was hit
  if (digitalRead(STOPPER_PIN) == LOW) {
    Serial.println("STOPPER REACHED");
    stepper.stop();
    stepper.disable();
  }

  // motor control loop - send pulse and return how long to wait until next pulse
  unsigned wait_time_micros = stepper.nextAction();
  /**
     position
  */
  //  noInterrupts();
  if (is_moving_manually)
    noInterrupts();
  else
    interrupts();

  newPosition1 = myEnc1.read() / 4; // YUTAKA, this encoder u got is shit, it does 4 increments at a time so i div by 4
  //  interrupts();
  if (newPosition1 != oldPosition1) {
    is_moving_manually = true;
    stepper.move((newPosition1 - oldPosition1) * 100); // * 40
    is_moving_manually = false;
    oldPosition1 = newPosition1;
    Serial.println(newPosition1);
  }

  setRPM_Ben();
  // 0 wait time indicates the motor has stopped
  if (wait_time_micros <= 0) {
    //
    //    Serial.println("wait_time_micros <= 0");
    //    debug_flip = debug_flip * -1;
    //    stepper.startMove(debug_flip * MOTOR_STEPS);
    //    delay(1000);

  }

  // (optional) execute other code if we have enough time
  if (wait_time_micros > 100) {
    // other code here
    //    Serial.println("wait_time_micros > 100");
    setRPM_Ben();
  }
}

void setRPM_Ben() {
  /**
     RPM
  */
  long newPosition0 = myEnc0.read() / 4; 

  if (newPosition0 != oldPosition0) {
    if (newPosition0 < MIN_RPM) {
      myEnc0.write(MIN_RPM * 4);
      newPosition0 = MIN_RPM;
    }
    if (newPosition0 > MAX_RPM) {
      myEnc0.write(MAX_RPM * 4);
      newPosition0 = MAX_RPM;
    }
    oldPosition0 = newPosition0;
    Serial.print("RPM re-set to: ");
    Serial.print(newPosition0);
    stepper.setRPM(newPosition0);
    Serial.print(", stepper RPM: "); Serial.println(stepper.getRPM());
  }
}

Any ideas ?

Oddly enough, the performance of turning the encoder in one direction outputs a more consistent growing number than in the opposite direction, which tends to alternate between two numbers more.
 
Encoder is more reliable when both pins are interrupts.

Do you have a Teensy board? On Teensy 3.x all the digital pins have interrupts, and on Teensy LC most of them do.
 
Encoder is more reliable when both pins are interrupts.

Do you have a Teensy board? On Teensy 3.x all the digital pins have interrupts, and on Teensy LC most of them do.
i *always* use teensy's for my embedded projects, but this guy i'm helping really wanted an arduino. i literally just explained to him how much better teensy's are, and how it's identical to normal arduino programming, i have a convert.

I'll report back if the problem is fixed by using a teensy 3.2

thanks
 
Maybe try that project with just 1 encoder using both the interrupt pins?

Using pin 2 and 3 on the arduino for the high timing requirement function seems to have done the trick in that the numbers are now incrementing / decrementing properly, but it's got a very peculiar behavior on the stepper motor in that it's not turning consistently.

I have switched to a teensy 3.2 and am now having issues with the stepper driver, because (i think) the minimum ON voltage is 3.5V, and i have no logic shifters at hand to confirm. tldr the stepper doesn't move. I do have a DRV8255 at hand, i will try this with the teensy.
 
I seem to have figured out how to get this running nicely but i had to revert back to the arduino since i couldn't get the stepper driver to work with the teensy, i don't doubt it was a problem i introduced and not one with the teensy itself.

Now i'm wondering, because i'm trying to track my steps from a reference point, and don't want to issue new move commands before the last one is finished (which might happen with the interrupt driven encoder). Is there a way to block the encoder when there is a move function ? I would have thought it's something similar to turning off interrupts until the move function is complete?
 
Status
Not open for further replies.
Back
Top