Encoder

Interpreting the Output of the Arduino Encoder in the Context of a Running Wheel

  • Counts Per Revolution (CPR):
    • Number of counts (pulses) per full revolution of the encoder knob.
    • Each count corresponds to a small increment of rotation.
  • Which direction is the wheel turning?
    • A positive positionChange indicates rotation in one direction (e.g., forward), while a negative value indicates rotation in the opposite direction (e.g., backward).
  • Output:
    • The script outputs the encoder counts sampled in positionChange within the 100 millisecond time window.
    • Used to determine how fast the wheel is turning and in which direction.

Calculating Speed and Distance

To calculate speed and distance from the encoder output, you’ll need to perform the following steps:

Necessary Parameters:

Wheel Circumference (C):

  • This can also be thought of as “Distance Per Revolution” Encoder Counts Per Revolution (CPR): encoder counts generated by one full rotation. Sample Window Duration (T): time interval between readings
  1. Calculate Distance Per Count (DPC):

  2. Calculate Speed:

    • Counts Per Second (CPS):
    • Speed (V; units of distance per second (e.g., meters per second)):
  3. Calculate Distance Traveled:

    • Distance for Each Sample Interval:
    • Total Distance:
      • Sum the distances calculated for each sample interval over time.

Example Calculation

Assuming:

  • Wheel Diameter (D) = 0.5 meters
  • Encoder CPR = 1024 counts/revolution
  • Sample Window Duration (T) = 0.1 seconds
  1. Wheel Circumference:

  2. Distance Per Count:

  3. Assuming a positionChange of 150 counts:

    • Counts Per Second:
    • Speed:
    • Distance Traveled in Sample Interval:

Considerations

  • Direction of Rotation:
    • Negative positionChange values indicate reverse rotation.
    • Ensure calculations account for the sign of positionChange.
  • Encoder Resolution:
    • Higher CPR provides more precise measurements but may require handling larger numbers.
  • Sampling Rate:
    • The sampleWindow should be chosen based on the expected speed of the wheel and the encoder’s capabilities.
    • A shorter sampleWindow provides more frequent updates but may be more susceptible to noise.

Synchronization with camera

Read from data pin (connected to the camera’s exposure out signal) to define the sampleWindow The code captures the encoder’s position change during each camera exposure:

// Author: jgronemeyer 2024
 
#include <Encoder.h>
 
// Define the encoder pins
Encoder rotary(2, 3);
 
// Initialize variables
long previousPosition = 0;
long currentPosition;
long positionChange;
 
void setup() {
  // Initialize serial communication at a baud rate of 57600
  Serial.begin(57600);
 
  // Set pin 4 as input for the exposure signal
  pinMode(4, INPUT);
}
 
void loop() {
  static bool exposureState = LOW;
  bool currentExposureState = digitalRead(4);
 
  if (currentExposureState == HIGH && exposureState == LOW) {
    // Exposure has started
    previousPosition = rotary.read();
  } else if (currentExposureState == LOW && exposureState == HIGH) {
    // Exposure has ended
    currentPosition = rotary.read();
    positionChange = currentPosition - previousPosition;
 
    // Optionally, check for unusually large position changes
    const long MAX_POSITION_CHANGE = 1000; // Adjust based on expected max change
    if (abs(positionChange) > MAX_POSITION_CHANGE) {
      // Handle or ignore the unexpected large change
      Serial.println("Warning: Unusually large position change detected.");
      positionChange = 0; // Ignore the change or set to zero
    } else {
      // Print the position change to the serial monitor
      Serial.println(positionChange);
    }
  }
 
  // Update the exposure state
  exposureState = currentExposureState;
}

Explanation of Modifications:

  1. Setup Pin to Receive exposure signal as Input:

    pinMode(4, INPUT);
  2. Monitor Exposure Signal state (HIGH vs LOW):

    static bool exposureState = LOW;
    bool currentExposureState = digitalRead(4);
  3. Detect Exposure Start and End: When the signal goes from HIGH to LOW, it indicates the end of an exposure. The encoder position is recorded again, and the change is calculated.

    //if exposure has started
    if (currentExposureState == HIGH && exposureState == LOW) {
      // Exposure has started
      previousPosition = rotary.read();
    } else if (currentExposureState == LOW && exposureState == HIGH) {
      // Exposure has ended
      currentPosition = rotary.read();
      positionChange = currentPosition - previousPosition;
    }
  4. Replaces Time-Based Sampling:

    • The previous time-based sampling using millis() and sampleWindow has been removed since the exposure signal now defines the sampling window.