# ESP32 Motor Encoder Test
```cpp=
// Pin definitions
const int encVcc_Pin = 16;
const int dirPin = 17; // Motor direction
const int pwmPin = 18; // Motor PWM
const int brakePin = 19; // Motor brake
const int ledPin = 2; // Onboard LED for many ESP32 dev boards
// Encoder pins (MUST support interrupts!)
const int encA_Pin = 27; // Change if needed
const int encB_Pin = 14; // Change if needed
volatile long encoderTicks = 0;
volatile int direction = 1;
struct RPSMap {
int pwm;
float targetRPS;
};
RPSMap rpsTargets[] = {
{240, 2.2}, {225, 4.7}, {210, 7.3}, {195, 9.7}, {180, 12.2},
{165, 14.6}, {150, 17.1}, {135, 19.6}, {120, 22.1}, {105, 24.6},
{90, 27.1}, {75, 29.6}, {60, 32.0}, {45, 34.5}, {30, 37.0}, {15, 39.5}
};
// ESP32 PWM setup
const int pwmChannel = 0; // Use channel 0
const int pwmFreq = 20000; // 20 kHz PWM
const int pwmResolution = 8; // 8-bit (0-255)
bool hasReachedTargetRPS(float currentRPS, float targetRPS, float tolerance = 0.01) {
return currentRPS >= (targetRPS - tolerance);
}
float getRPS() {
long startTicks = encoderTicks;
delay(100);
long endTicks = encoderTicks;
// 100 ticks per revolution assumed; adjust if different!
return abs(endTicks - startTicks) / 100.0 / 0.1;
}
void brakeAndWait(float stopThresholdRPS = 0.2) {
ledcWrite(pwmChannel, 255); // Stop (min PWM)
digitalWrite(brakePin, LOW); // Engage brake
delay(100); // Let brake engage
// Wait for the motor to stop spinning
while (true) {
float rps = getRPS();
if (rps <= stopThresholdRPS) break;
delay(50);
}
digitalWrite(brakePin, HIGH); // Release brake
delay(100);
}
void setup() {
pinMode(pwmPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(brakePin, OUTPUT);
pinMode(encA_Pin, INPUT_PULLUP);
pinMode(encB_Pin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
// PWM setup for ESP32
ledcSetup(pwmChannel, pwmFreq, pwmResolution);
ledcAttachPin(pwmPin, pwmChannel);
attachInterrupt(digitalPinToInterrupt(encA_Pin), updateEncoder, RISING);
Serial.begin(115200);
ledcWrite(pwmChannel, 255);
digitalWrite(brakePin, LOW);
delay(1500);
digitalWrite(brakePin, HIGH);
digitalWrite(ledPin, HIGH);
Serial.println("Hello, starting RPS sweep.");
}
void loop() {
for (size_t i = 0; i < sizeof(rpsTargets) / sizeof(RPSMap); i++) {
int pwm = rpsTargets[i].pwm;
float targetRPS = rpsTargets[i].targetRPS;
// CW test
brakeAndWait();
encoderTicks = 0;
digitalWrite(dirPin, HIGH);
ledcWrite(pwmChannel, pwm);
unsigned long timeCW = 0;
while (true) {
float rps = getRPS();
if (hasReachedTargetRPS(rps, targetRPS)) {
timeCW = millis();
break;
}
}
// Brake before switching direction
brakeAndWait();
// CCW test
encoderTicks = 0;
digitalWrite(dirPin, LOW);
ledcWrite(pwmChannel, pwm);
unsigned long timeCCW = 0;
while (true) {
float rps = getRPS();
if (hasReachedTargetRPS(rps, targetRPS)) {
timeCCW = millis();
break;
}
}
// Brake at end of step
brakeAndWait();
// Print result
Serial.print("PWM: ");
Serial.print(pwm);
Serial.print(" | Target RPS: ");
Serial.print(targetRPS);
Serial.print(" | CW time: ");
Serial.print(timeCW);
Serial.print(" ms | CCW time: ");
Serial.print(timeCCW);
Serial.print(" ms | Δt: ");
Serial.print(abs((long)timeCCW - (long)timeCW) / 1000.0, 3);
Serial.println(" s");
}
ledcWrite(pwmChannel, 255);
Serial.println("Sweep complete.");
// Blink LED 3 times to indicate end of sweep
for (int i = 0; i < 3; i++) {
digitalWrite(ledPin, LOW); delay(200);
digitalWrite(ledPin, HIGH); delay(200);
}
digitalWrite(ledPin, HIGH); // Leave LED on
while (true); // Halt after sweep
}
void IRAM_ATTR updateEncoder() {
int B = digitalRead(encB_Pin);
if (B == LOW) {
encoderTicks++;
direction = 1;
} else {
encoderTicks--;
direction = -1;
}
}
```