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).
- A positive
- 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.
- The script outputs the encoder counts sampled in
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
-
Calculate Distance Per Count (DPC):
-
Calculate Speed:
- Counts Per Second (CPS):
- Speed (V; units of distance per second (e.g., meters per second)):
-
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
-
Wheel Circumference:
-
Distance Per Count:
-
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
.
- Negative
- 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.
- The
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:
-
Setup Pin to Receive exposure signal as Input:
pinMode(4, INPUT);
-
Monitor Exposure Signal state (HIGH vs LOW):
static bool exposureState = LOW; bool currentExposureState = digitalRead(4);
-
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; }
-
Replaces Time-Based Sampling:
- The previous time-based sampling using
millis()
andsampleWindow
has been removed since the exposure signal now defines the sampling window.
- The previous time-based sampling using