Rotary encoder and VL53L1X clash

I am using the very nice rotary encoder code using no debouncing from pinteric. It works fine until I uncomment the Distance_Sensor.read(); aftr which I just stops working.

I have tried using different interrups on a Mega but am now at a loss as to what the problem is.

Any guidance greatly appreciated.

[code]
/*
  Reading distance from the laser based VL53L1X
  By: kaloha
  CQRobot
  VL53L1X Distance Sensor from CQRobot: http://www.cqrobot.wiki/index.php/VL53L1X_Distance_Sensor
  This example demonstrates how to read the distance in short mode(up to 1.3m) and the measurement status.
*/

#include <Wire.h>
#include "VL53L1X.h"
VL53L1X Distance_Sensor;

// Rotary encoder pins
//const byte PIN_A = 2;
//const byte PIN_B = 3;
const byte PIN_A = 2;      //2 for Uno; 2 or 18 for Mega
const byte PIN_B = 3;      //3 for Uno; 2 or 19 for Meg

// A turn counter for the rotary encoder (negative = anti-clockwise)
int rotationCounter = 200;
int counterLast = 0;

// Flag from interrupt routine (moved=true)
volatile bool rotaryEncoder = false;

// Rotary encoder has moved (interrupt tells us) but what happened?
// See https://www.pinteric.com/rotary.html

int8_t checkRotaryEncoder() {
  // Reset the flag that brought us here (from ISR)
  rotaryEncoder = false;

  static uint8_t lrmem = 3;
  static int lrsum = 0;
  static int8_t TRANS[] = {0, -1, 1, 14, 1, 0, 14, -1, -1, 14, 0, 1, 14, 1, -1, 0};

  // Read BOTH pin states to deterimine validity of rotation (ie not just switch bounce)
  int8_t l = digitalRead(PIN_A);
  int8_t r = digitalRead(PIN_B);


  Serial.print(l);
  Serial.print(r);

  // Move previous value 2 bits to the left and add in our new values
  lrmem = ((lrmem & 0x03) << 2) + (2 * l) + r;

  Serial.print("\tlrmem : ");
  Serial.print(lrmem);

  // Convert the bit pattern to a movement indicator (14 = impossible, ie switch bounce)
  lrsum += TRANS[lrmem];

  Serial.print("\tlrsum : ");
  Serial.print(lrsum);

  /* encoder not in the neutral (detent) state */
  if (lrsum % 4 != 0)   {
    Serial.println("\tNOT");
    return 0;
  }

  /* encoder in the neutral state - clockwise rotation*/
  if (lrsum == 4) {
    Serial.println("\tCW ");
    lrsum = 0;
    return 1;
  }

  /* encoder in the neutral state - anti-clockwise rotation*/
  if (lrsum == -4)   {
    Serial.println("\tCCW ");
    lrsum = 0;
    return -1;
  }

  // An impossible rotation has been detected - ignore the movement
  lrsum = 0;
  Serial.println("\tIMP ");
  return 0;
}

// Interrupt routine just sets a flag when rotation is detected
void rotary() {
  rotaryEncoder = true;
}

void setup() {
  Wire.begin();
  Wire.setClock(400000); // originally 400 kHz I2C
  Serial.begin(9600);
  Serial.println("VL53L1X Distance Sensor tests in short distance mode(up to 1.3m).");

  Distance_Sensor.setTimeout(500);
  if (!Distance_Sensor.init())
  {
    Serial.println("Failed to initialize VL53L1X Distance_Sensor!");
    while (1);
  }

  // Use long distance mode and allow up to 50000 us (50 ms) for a measurement.
  // You can change these settings to adjust the performance of the sensor, but
  // the minimum timing budget is 20 ms for short distance mode
  Distance_Sensor.setDistanceMode(VL53L1X::Short);
  Distance_Sensor.setMeasurementTimingBudget(25000);

  // Start continuous readings at a rate of one measurement every 50 ms (the
  // inter-measurement period). This period should be at least as long as the
  // timing budget.
  
  Distance_Sensor.startContinuous(25);

  // The module already has pullup resistors on board
  pinMode(PIN_A, INPUT);
  pinMode(PIN_B, INPUT);

  // We need to monitor both pins, rising and falling for all states
  attachInterrupt(digitalPinToInterrupt(PIN_A), rotary, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PIN_B), rotary, CHANGE);
}

void loop() {
 
 //!!!!!!! Uncomment the following and the rotary encoder stops working !!!!!!
 // Distance_Sensor.read();

  // Has rotary encoder moved?
  if (rotaryEncoder == true) {
    // Get the movement (if valid)
    int8_t rotationValue = checkRotaryEncoder();
    rotationCounter += rotationValue;
    if (rotationCounter != counterLast) {
      counterLast = rotationCounter;
      Serial.print("\nEncoder : ");
      Serial.print(rotationCounter);
      Serial.print("\tDistance : ");
      Serial.println(Distance_Sensor.ranging_data.range_mm);
    }

  }
}
[/code]

The Pololu library you're probably using (you failed to link to it) does wait for the result if you just call the read() method (with parameter). During that wait your loop code isn't called anymore so you might loose some encoder ticks. You have two options:

  • call the read() method with a false parameter to return immediately if no result is available
  • move the rotationCounter in-/decrement to the interrupt handler (but take care to mark the used variables volatile).

pylon,

Many thanks for the insight. I amended the code as below and it now performs as expected. Greatly appreciate your time and help. Thank you.

 if (Distance_Sensor.dataReady() == true) {                //Check if data available
      mmRaw = readDistanceSensor();                           //Position subject to some noise
    }

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