Firmware flow
Ramp a PWM command from throttle and brake inputs
Selected ESP32 control fragment; input scaling and elapsed-time calculation occur earlier in the loop.
Braking takes priority over throttle tracking. Without a brake request, the command rises or falls toward the target. A deadzone then removes very small commands before the same integer duty is written to both outputs.
This is open-loop PWM command generation. It does not establish speed regulation, physical braking, driver compatibility or tested motor operation.
Read the implementation
code2.txt — throttle/brake-dependent duty ramp and two PWM outputs.
// 4) update currentPWM with smooth accel/decel
if (brRatio > 0.01f) {
float decel = BASE_DECEL + brRatio * (MAX_DECEL - BASE_DECEL);
currentPWM = max(0.0f, currentPWM - decel * dt);
}
else if (currentPWM < targetPWMf) {
currentPWM = min(currentPWM + ACCEL_RATE * dt, targetPWMf);
}
else {
currentPWM = max(currentPWM - BASE_DECEL * dt, targetPWMf);
}
// 5) deadzone
if (currentPWM < DEADZONE) currentPWM = 0.0f;
// 6) output to both drivers
uint32_t duty = uint32_t(currentPWM);
ledcWrite(MOTOR_A_PWM_PIN, duty);
ledcWrite(MOTOR_B_PWM_PIN, duty);Technical notes
Inputs become a target
The sketch constrains the throttle reading to configured ADC bounds and maps it to a PWM target. A second analog input is normalized to a brake ratio. These bounds are configuration values, not a demonstrated calibration.
Three command paths
A brake input above the threshold reduces the current command at a brake-dependent rate. Otherwise the code ramps upward toward the throttle target or coasts downward toward it, using elapsed time from micros().
One command, two outputs
After a small-command deadzone, the duty is converted to an integer and written to both PWM outputs. This excerpt establishes requested duty only: it contains no measured motor-speed feedback, direction output or separate stop/brake control signal, and hardware operation was not tested.