Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 8 of 8

Thread: Encoder Help

  1. #1

    Encoder Help

    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.

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,101
    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.

  3. #3
    Quote Originally Posted by PaulStoffregen View Post
    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

  4. #4
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,101
    Maybe try that project with just 1 encoder using both the interrupt pins?

  5. #5
    Quote Originally Posted by PaulStoffregen View Post
    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.

  6. #6
    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?

  7. #7
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,101
    Maybe ask on Arduino's forum?

  8. #8
    Junior Member
    Join Date
    Jun 2018
    Posts
    5
    I am having the same problem with the alternating values. How did you solve it?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •