Struggles with optical rotary encoders for a DIY CMM

I am severely in need of help. I struggle a bit with arduino and C type codes and I just cant seem to figure out what is going on here (I have been using chatGPT to help me write it). I am trying to write a code that gathers the input of 3 optical rotary encoders (part number lpd3806-600bm). I am going to be using this for a really rudimentary Coordinate Measuring Machine. My issue is that with the code I am using, I am getting the ready serial print and then nothing. I have another code a bit more stripped back that doesn't separate the three encoders so well in the serial print and I get some outputs but it misses signals, and lags in print for some reason. I am using an Arduino mega 2560 so I have 6 interrupt capable pins. I just dont get what is going so wrong here.

#define ENCODER0PINA         20      // pin for Encoder 0 interrupt
#define ENCODER0PINB         21      // pin for Encoder 0
#define ENCODER1PINA         5       // pin for Encoder 1 interrupt
#define ENCODER1PINB         6       // pin for Encoder 1
#define ENCODER2PINA         18      // pin for Encoder 2 interrupt
#define ENCODER2PINB         19      // pin for Encoder 2
#define CPR                  600     // encoder cycles per revolution
#define CLOCKWISE            1       // direction constant
#define COUNTER_CLOCKWISE    2       // direction constant

volatile long encoder0Position = 0;
volatile long encoder1Position = 0;
volatile long encoder2Position = 0;

volatile long interruptsReceived0 = 0;
volatile long interruptsReceived1 = 0;
volatile long interruptsReceived2 = 0;

short currentDirection0 = CLOCKWISE;
short currentDirection1 = CLOCKWISE;
short currentDirection2 = CLOCKWISE;

long previousPosition0 = 0;
long previousPosition1 = 0;
long previousPosition2 = 0;

unsigned long previousMillis = 0;
const int printInterval = 1000; // Print interval in milliseconds

void setup() {
  // Encoder setup code...

  Serial.begin(9600);
  Serial.println("\n\n\n");
  Serial.println("Ready.");
}

void loop() {
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= printInterval) {
    previousMillis = currentMillis;

    if (encoder0Position != previousPosition0 || encoder1Position != previousPosition1 || encoder2Position != previousPosition2) {
      printEncoderPositions(encoder0Position, encoder1Position, encoder2Position);
      previousPosition0 = encoder0Position;
      previousPosition1 = encoder1Position;
      previousPosition2 = encoder2Position;
    }
  }
  // Other necessary code here...
}

void printEncoderPositions(long pos1, long pos2, long pos3) {
  Serial.print("Pos1: ");
  Serial.print(pos1);
  Serial.print("\tPos2: ");
  Serial.print(pos2);
  Serial.print("\tPos3: ");
  Serial.println(pos3);
}

Where's the code which adjusts the encoders?

It's interesting :face_with_monocle:. I had a similar case. I need to investigate more.
greetings

Don't worry. We on the forum know what is wrong:

You will have heard of the expression "the blind leading the blind". (No offense intended to blind people).

You can safely delete that code, it has zero value.

Begin by searching for Arduino libraries for use with encoders. Try out the example code that comes with those libraries.

PaulRB I definately get what your saying. My issue has been that almost all the encoder stuff ive been finding seems to be for the resistive type of encoders and I get no outputs from them. Ive tried probably a dozen different codes and libraries and most have just flat not worked. I had one that worked ok but when i tried expanding to more encoders it just started failing again.

The encoder has NPN open collector outputs, you need a 10k pullup resistor connected from Vcc (5V) to input pin or set the internal pullup with:

pinMode(ENCODER0PINA,INPUT_PULLUP);

Do all of the input pins have a resistor available to code a pullup on? That was one thing that was not talked about on a level i could understand. There is tons of information available out there but its all useless if it takes an immediate dive past what I can understand.

Start with one encoder and the Arduino encoder library.

The on line getting started tutorials (click on Read the documentation in the above link) and one of the encoder library examples are all you need at the moment.

ChatGPT is a complete waste of time for something like this.

Hy there Drake,
For what it's worth and maybe some reading material for the holidays.
I wrote some code a while back to do something similar.

/*
  Update:   ver.03  08/02/2019
            Clean up unused variables
            Clean up layout
*/            
/*
  Purpose:  Double 4x Bi-directional encoding
            to represent the X-Y axis of a 2d object
            and log it in .csv format.
  Board:    Arduino Mega 2560
            Optical encoder open collector

  Author:   Gij Kieken
  Date:     22/01/2019
  Info:     I am using two diferent methods to determine
            the X and Y position
            One with a switch case construction and one
            with an array.
*/
// Used functions
/* myDebounceShortLongPress
    Purpose:  Debounce an array of push buttons and determine if they
              where pressed a short or long time.(micro seconds)
              In setup use pinMode(pin, INPUT_PULLUP) so no external
              components are necessary.
              Buttons connected 1-side to gnd the other to Arduino pin.
              Author: Gij Kieken
*/
const byte maxButton = 3;                        //Number of buttons
const byte pinPushButton[maxButton] = {4, 5, 6}; //Arduino IN pins
const byte maxOutput = 4;                        //Number of outputs
const byte LED[maxOutput] = {9, 10, 11, 12};     //Arduino OUT pins

volatile long countX = 0;
volatile long countY = 0;

boolean A, B;
boolean C, D;
boolean modeStatus = false;        // Keep track of Hole or Line mode
boolean printHeaderHole = true;    // Print header once
boolean printHeaderLine = false;   // Print header once
boolean printHeaderStop = false;   // Print header once
//**********************
const unsigned long interval = 500000;
unsigned long previousStartMicros;
unsigned long previousStopMicros;
boolean enabledStop = false;
boolean enabledStart = false;
//***********************
byte stateX, statepX;
byte stateY, statepY;
//Quadrature Encoder Matrix
const byte QEM[16] = {0, -1, 0, 1, 1, 0, -1, 0, 0, 1, 0, -1, -1, 0, 1, 0};
byte index = 0;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(2, INPUT);//Channel A
  pinMode(3, INPUT);//Channel B
  pinMode(21, INPUT);//Channel C
  pinMode(20, INPUT); //Channel D
  //Initialize push button pins as inputs with pull-ups
  // button[0]=startButton, button[1]=stopButton, button[2]=modeButton
  for (byte i = 0; i < maxButton; i++) {
    pinMode(pinPushButton[i], INPUT_PULLUP);
  }
  //Initialize LED pins as outputs
  // LED[0]=HoleLed, LED[1]= LineLed, LED[2]=StartLed, LED[3]=StopLed
  for (byte j = 0; j < maxOutput; j++) {
    pinMode(LED[j], OUTPUT);
  }
  digitalWrite(LED[0], !modeStatus);   //We start in hole mode
  digitalWrite(LED[1], modeStatus);    //LineLED=OFF
  digitalWrite(LED[2], LOW);           //StartLed=OFF
  digitalWrite(LED[3], LOW);           //StopLed=OFF
  attachInterrupt(digitalPinToInterrupt(2), Achange, CHANGE);   //Int 0
  attachInterrupt(digitalPinToInterrupt(3), Bchange, CHANGE);   //Int 1
  attachInterrupt(digitalPinToInterrupt(21), Cchange, CHANGE);  //Int 2
  attachInterrupt(digitalPinToInterrupt(20), Dchange, CHANGE);  //Int 3
  //read the initial value of A & B
  A = digitalRead(2);
  B = digitalRead(3);
  //read the initial value of C & D
  C = digitalRead(21);
  D = digitalRead(20);
  //set initial stateX value
  if ((A == HIGH) && (B == HIGH)) statepX = 1;
  if ((A == HIGH) && (B == LOW)) statepX = 2;
  if ((A == LOW) && (B == LOW)) statepX = 3;
  if ((A == LOW) && (B == HIGH)) statepX = 4;
  //set initial stateY value
  if ((C == HIGH) && (D == HIGH)) statepY = 1;
  if ((C == HIGH) && (D == LOW)) statepY = 2;
  if ((C == LOW) && (D == LOW)) statepY = 3;
  if ((C == LOW) && (D == HIGH)) statepY = 4;
  // Start communication with Excel
  Serial.println("CLEARSHEET");
  Serial.println("LABEL,X-Pos,Y-Pos");
  Serial.println("CELL,SET,C01, Gij Kieken X-Y pos ");
  Serial.println("CELL,SET,C02, Long press Start to start log.");
  Serial.println("CELL,SET,C03, Short press Start to tween.");
  Serial.println("CELL,SET,C04, Short press mode to toggle.");
  Serial.println("CELL,SET,C05, Short press Stop to stop log.");
  Serial.println("DATA,HOLE-X,HOLE-Y");
}

void loop() {
  // put your main code here, to run repeatedly:
  static unsigned long previousTime = 0;
  const byte timeInterval = 2000; //pick a short time interval
  byte button[maxButton] = {}; //array to store the latest readings
  // button[0]=startButton, button[1]=stopButton, button[2]=modeButton
  // LED[0]=HoleLed, LED[1]= LineLed, LED[2]=StartLed, LED[3]=StopLed
  // - check all buttons
  if ((micros() - previousTime) > timeInterval) {
    previousTime = micros();
    for (byte i = 0; i < maxButton; i++) {
      button[i] = checkButtons(i);
    }
    if (button[0] == 1) { // Code, when Start button is short-pushed
      //***Continue to Log***
      if (enabledStart) {
        digitalWrite(LED[2], HIGH);
        Serial.print("DATA,");
        Serial.print(countX);
        Serial.print(",");
        Serial.println(countY); 
        Serial.println("BEEP");
        previousStartMicros = micros();        
      }
    }
    if (button[0] == 2) { // Code, when Start button is long-pushed
      //***Start to Log***
      if (!enabledStart) {
        digitalWrite(LED[2], HIGH);
        enabledStart = true;
        // Reset countX and countY
        countX = 0;
        countY = 0;
        Serial.print("DATA,");
        Serial.print(countX);
        Serial.print(",");
        Serial.println(countY); 
        Serial.println("BEEP");      
        previousStartMicros = micros();
      }
    }
    if (button[1] == 1) { // Code, when Stop button is short-pushed
      //***Stop to Log***
      digitalWrite( LED[3], HIGH);         // turn on led
      if (!printHeaderStop) {
        Serial.println("DATA,STOPPED-X,STOPPED-Y");  // Print header
        // Reset the flags
        modeStatus = LOW;                  // Reset modeStatus to hole mode
        printHeaderLine = false;
        printHeaderStop = true;            // Make sure header is printed only once
        enabledStart = false;              // Reset the start flag
        enabledStop = true;                // Print offset X=0,Y=0 once
        digitalWrite(LED[0], !modeStatus); // Change hole led state
        digitalWrite(LED[1], modeStatus);  // Change line led state
        Serial.println("DATA,HOLE-X,HOLE-Y");
        Serial.println("BEEP");
        Serial.println("SAVEWORKBOOKAS,MyNewX-Y_pos");
        printHeaderHole = true;
        previousStopMicros = micros();
      }
    }
    if (button[2] == 1) { // Code, when Mode button is short-pushed
      //***Select the mode***
      // modeStatus=0 ---> hole-modus, modeStatus=1 ---> line-modus
      modeStatus = !modeStatus;          // Toggle the LED value
      digitalWrite(LED[0], !modeStatus); // Change hole led state
      digitalWrite(LED[1], modeStatus);  // Change line led state
      //***Determine mode Hole or Line and printout appropriate header***
      if (!modeStatus && !printHeaderHole && printHeaderLine) {
        Serial.println("DATA,HOLE-X,HOLE-Y");
        Serial.println("BEEP");
        printHeaderHole = true; // Make sure header is printed only once
        printHeaderLine = false;
      }
      else if (modeStatus && printHeaderHole && !printHeaderLine) {
        Serial.println("DATA,LINE-X,LINE-Y");
        Serial.println("BEEP");
        printHeaderLine = true;
        printHeaderHole = false;
      }
    }
  }
  // Switch off start led
  if ( micros() - previousStartMicros >= interval) {
    digitalWrite( LED[2], LOW);         // turn off led
  }
  // Switch off stop led
  if ( enabledStop)  {                  // software timer is active
    if ( micros() - previousStopMicros >= interval) {
      digitalWrite( LED[3], LOW);      // turn off led
      enabledStop = false;             // stop software timer
      printHeaderStop = false;         // Reset flag
    }
  }
} // End void loop()
//************************************************************************

/*  Function: Checks one button for short or long press (micro seconds)
              Accepts a byte for the button number
              Returns a byte 0-none 1-short 2-long
   Info:      Action is executed when release button
*/
byte checkButtons(byte buttonNo) {
  const unsigned long timeDebounce = 100000;//time to debounce
  const unsigned long timeLong = 1000000;   //minimum time for Long press
  const unsigned long timeBreak = 200000;   //time interval after button release,
  //before ready for next press
  static byte state[maxButton] = {};        //this initializes all elements to zero
  static unsigned long previousTime[maxButton] = {};//this initializes all elements to zero
  byte r = 0;                              // 0:not  1:short  2:long
  if (state[buttonNo] == 0) {  //no button has been pressed - check if
    if (digitalRead(pinPushButton[buttonNo]) == LOW) {
      previousTime[buttonNo] = micros();
      state[buttonNo] = 1;
    }
  } else if (state[buttonNo] == 1) {  //button was pressed - check for how long
    if ( (micros() - previousTime[buttonNo]) > timeDebounce) {
      if ( (micros() - previousTime[buttonNo]) < timeLong) {
        if ( digitalRead(pinPushButton[buttonNo]) == HIGH) { //released -> short press
          previousTime[buttonNo] = micros();
          state[buttonNo] = 3;
          r = 1;
        }
      } else {                        //it was a long press
        state[buttonNo] = 2;
        r = 2;
      }
    }
  } else if (state[buttonNo] == 2) {  //wait for long button press to end
    if (digitalRead(pinPushButton[buttonNo]) == HIGH) {
      previousTime[buttonNo] = micros();
      state[buttonNo] = 3;
    }
  } else if (state[buttonNo] == 3) {  //wait a little while after previous button press
    if ( (micros() - previousTime[buttonNo]) > timeBreak) {
      state[buttonNo] = 0;
    }
  }
  return r;
}

void Achange() {
  A = digitalRead(2);
  B = digitalRead(3);
  //determine state value
  if ((A == HIGH) && (B == HIGH)) stateX = 1;
  if ((A == HIGH) && (B == LOW)) stateX = 2;
  if ((A == LOW) && (B == LOW)) stateX = 3;
  if ((A == LOW) && (B == HIGH)) stateX = 4;
  switch (stateX) {
    case 1:
      {
        if (statepX == 2) countX--;
        if (statepX == 4) countX++;
        break;
      }
    case 2:
      {
        if (statepX == 1) countX++;
        if (statepX == 3) countX--;
        break;
      }
    case 3:
      {
        if (statepX == 2) countX++;
        if (statepX == 4) countX--;
        break;
      }
    default:
      {
        if (statepX == 1) countX--;
        if (statepX == 3) countX++;
      }
  }
  statepX = stateX;
}

void Bchange() {
  A = digitalRead(2);
  B = digitalRead(3);
  //determine state value
  if ((A == HIGH) && (B == HIGH)) stateX = 1;
  if ((A == HIGH) && (B == LOW)) stateX = 2;
  if ((A == LOW) && (B == LOW)) stateX = 3;
  if ((A == LOW) && (B == HIGH)) stateX = 4;
  switch (stateX) {
    case 1:
      {
        if (statepX == 2) countX--;
        if (statepX == 4) countX++;
        break;
      }
    case 2:
      {
        if (statepX == 1) countX++;
        if (statepX == 3) countX--;
        break;
      }
    case 3:
      {
        if (statepX == 2) countX++;
        if (statepX == 4) countX--;
        break;
      }
    default:
      {
        if (statepX == 1) countX--;
        if (statepX == 3) countX++;
      }
  }
  statepX = stateX;
}
//*********************************************

void Cchange() {
  C = digitalRead(21);
  D = digitalRead(20);
  //Determine state value
  if ((C == HIGH) && (D == HIGH)) stateY = 0;
  if ((C == HIGH) && (D == LOW)) stateY = 1;
  if ((C == LOW) && (D == LOW)) stateY = 2;
  if ((C == LOW) && (D == HIGH)) stateY = 3;
  index = 4 * stateY + statepY;
  countY = countY + QEM[index];
  statepY = stateY;
}

void Dchange() {
  C = digitalRead(21);
  D = digitalRead(20);
  //Determine state value
  if ((C == HIGH) && (D == HIGH)) stateY = 0;
  if ((C == HIGH) && (D == LOW)) stateY = 1;
  if ((C == LOW) && (D == LOW)) stateY = 2;
  if ((C == LOW) && (D == HIGH)) stateY = 3;
  index = 4 * stateY + statepY;
  countY = countY + QEM[index];
  statepY = stateY;
}

Have fun,,,

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.