How to Troubleshoot Pedal Oscillation and Control Loop Stability in DIY Sim-Racing FFB Pedals
Eliminate pedal oscillation by disabling servo command smoothing (PR2.22/PR2.23), tuning PID gains in StepperMovementStrategy.h, and enabling oscillation detection (Pr6.37) via the SimHub plugin or firmware configuration.
Pedal oscillation—characterized by the pedal "wiggling," hunting around set points, or sudden snapping movements—indicates instability in the feedback control loop of the chrgri/diy-sim-racing-ffb-pedal project. This open-source force-feedback pedal uses a PID or MPC controller to drive an iSV-57 servo, and instability typically stems from mismatches between the controller gains, servo drive parameters, and mechanical stiffness settings. Understanding how to troubleshoot pedal oscillation and control loop stability requires examining the interaction between the firmware's payloadPedalConfig parameters and the low-level servo registers configured in isv57communication.cpp.
Common Causes of Instability
High-Frequency Pedal Jitter (Command Smoothing)
The most common source of rapid pedal oscillation is position-command smoothing active in the servo drive. Registers PR2.22 and PR2.23 apply digital filtering to step commands, introducing lag that causes the controller to over-compensate.
According to StepperParameterization/ServoParameterization.md, these registers must be set to 0 to deactivate smoothing. The source documentation explicitly warns: "PR2.22 = 0 (deactivate position command smoothing, as it lead to pedal oscillations…)".
In isv57communication.cpp (around line 294), the initialization sequence sets these parameters:
// Disable position command smoothing to prevent oscillation
retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_2_00+22, 0); // PR2.22
retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_2_00+23, 0); // PR2.23
Aggressive PID Tuning
When the pedal "sticks" or drifts slowly before snapping back, the PID gains are likely too aggressive or the output limit is too restrictive. The controller implementation in Firmware_for_V3/PedalFirmware/include/StepperMovementStrategy.h exposes tunings via tunePidValues() and myPID.SetTunings().
Solution: Reduce Kp (proportional gain) first, then Ki (integral gain). Keep Kd (derivative gain) at 0 or a small positive value. If the stepper hits the hard stop, increase PID_OUTPUT_LIMIT_FL32 (default is 0.5f).
// Conservative starting values in StepperMovementStrategy.h
#define PID_OUTPUT_LIMIT_FL32 0.5f
// Recommended initial tunings: Kp = 0.1, Ki = 20, Kd = 0
cfg.payLoadPedalConfig_.PID_p_gain = 0.1f;
cfg.payLoadPedalConfig_.PID_i_gain = 20.0f;
cfg.payLoadPedalConfig_.PID_d_gain = 0.0f;
myPID.SetTunings(Kp, Ki, Kd);
Oscillations During ABS or Traction Control Activation
If oscillation occurs only when ABS or traction control is active, the oscillation-detection level register (Pr6.37) is likely set to 0. This prevents the servo from signaling overload conditions, causing the controller to push continuously against mechanical limits.
In isv57communication.cpp, uncomment and set a non-zero detection threshold:
// Enable 0.1% oscillation detection (value = 10)
retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_6_00+37, 10);
Soft Pedal Feel and Sudden Snapback
A pedal that feels "soft" then suddenly stiffens indicates excessive Ratio-of-Inertia (Pr0.04). This parameter, controlled via the SimHub plugin's GeneralSetting_Servo.xaml slider, scales the effective mechanical stiffness.
Warning: The UI tooltip states: "Increase the value for stiffer pedal. Will increase likelihood of pedal oscillation." Keep this value near 1% (default) for stability; increasing it amplifies latency and reduces damping.
MPC-Specific Instability
For pedals using Model Predictive Control (MPC), wiggling indicates gains mismatched to the mechanical spring rate. The MPC implementation in StepperMovementStrategy.h uses three coefficients:
- MPC_0th_order_gain: Position gain
- MPC_1st_order_gain: Velocity gain
- MPC_2nd_order_gain: Acceleration gain
Tuning strategy: Reduce MPC_1st_order_gain first, then MPC_0th_order_gain. Keep the second-order gain near zero unless using a very light spring.
Axis Enable Sequence Failures
Unexpected step command jumps often occur when the servo axis is not properly enabled at startup. The axis-enable logic in isv57communication.cpp (around line 1290) must complete successfully before commands are valid:
// Enable servo axis (0x0303 = enable command)
retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_4_00+8, 0x0303);
If you observe the message "Servo registered in NVM have been updated!" after flashing, a power cycle of both the servo and ESP32 is required to apply the new register values.
How the Control Loop Functions
Understanding the signal flow helps diagnose where instability originates:
- Sensor Acquisition: The load-cell reading (
loadCellReadingKg) passes through an optional exponential filter at the top ofStepperMovementStrategy.h. - Setpoint Generation: The
ForceCurve_Interpolatedspline calculates target force based on current pedal position (stepperPosFraction). - Controller Execution:
- PID Path:
MoveByPidStrategynormalizes error and callsmyPID.Compute(), outputting a fractional position change. - MPC Path:
MoveByInterpolatedStrategyperforms a Newton-method solve (MAX_NUMBER_OF_NEWTON_STEPS) using the foot-spring model and MPC gains.
- PID Path:
- Actuation: The resulting position (
posStepperNew) writes to the iSV-57 viamodbus.holdingRegisterWriteinisv57communication.cpp. - Safety Hooks: Oscillation detection (
pr_6_00+37) and position smoothing (PR2.22/PR2.23) operate at the servo level.
Practical Configuration Examples
Disabling Command Smoothing via Firmware
// isv57communication.cpp - servo initialization
bool configureServo(uint8_t slaveId) {
bool success = true;
// Critical: Disable FIR filters that cause phase lag
success |= modbus.checkAndReplaceParameter(slaveId, pr_2_00+22, 0);
success |= modbus.checkAndReplaceParameter(slaveId, pr_2_00+23, 0);
return success;
}
Runtime PID Adjustment
The SimHub plugin (GeneralSetting_PID.xaml.cs) provides sliders, but you can also adjust programmatically:
void adjustStability(DAP_config_st& cfg) {
// Reduce proportional gain by 50% to eliminate hunting
cfg.payLoadPedalConfig_.PID_p_gain *= 0.5f;
// Re-apply to active controller
myPID.SetTunings(
cfg.payLoadPedalConfig_.PID_p_gain,
cfg.payLoadPedalConfig_.PID_i_gain,
cfg.payLoadPedalConfig_.PID_d_gain
);
}
Enabling Oscillation Detection
// isv57communication.cpp
// Set detection threshold to 1% (value = 100) or 0.1% (value = 10)
retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_6_00 + 37, 10);
Adjusting Mechanical Stiffness
In GeneralSetting_Servo.xaml.cs, the slider event handler updates the payload:
private void Slider_ServoRatioOfInertia_ValueChanged(object sender,
RoutedPropertyChangedEventArgs<double> e)
{
// Constrain to safe range (1-100, where 1 = safest)
tmp_config.payloadPedalConfig_.RatioOfInertia = Mathf.Clamp((float)e.NewValue, 1.0f, 100.0f);
SendConfigToPedal(tmp_config);
}
Key Files for Stability Tuning
| File Path | Purpose | Stability Relevance |
|---|---|---|
Firmware_for_V3/PedalFirmware/include/StepperMovementStrategy.h |
PID/MPC implementations, tunePidValues() |
Core control algorithms and gain limits |
Firmware_for_V3/PedalFirmware/include/DiyActivePedal_types.h |
payloadPedalConfig struct definition |
Container for all tunable parameters |
Firmware_for_V3/PedalFirmware/src/isv57communication.cpp |
Servo register initialization | PR2.22/PR2.23 smoothing, Pr6.37 detection, axis enable |
StepperParameterization/ServoParameterization.md |
Default servo parameters | Documentation of anti-oscillation settings |
SimHubPlugin/UIFunction/GeneralSetting_PID.xaml.cs |
UI bindings for PID gains | Runtime tuning without reflashing |
SimHubPlugin/UIFunction/GeneralSetting_Servo.xaml |
Ratio of Inertia slider | Mechanical stiffness adjustment |
Firmware_for_V3/PedalFirmware/src/Main.cpp |
High-level pedal logic | Line ~991 contains oscillation computation placeholder |
Quick Stability Checklist
- Disable smoothing: Verify PR2.22 = 0 and PR2.23 = 0 in
isv57communication.cpp. - Enable protection: Set
pr_6_00+37to 10 (0.1% detection) to prevent runaway commands. - Conservative PID start: Begin with Kp = 0.1, Ki = 20, Kd = 0; increase gradually.
- Check output limits: Ensure
PID_OUTPUT_LIMIT_FL32is 0.5f or higher to prevent clipping. - Minimize inertia ratio: Keep
RatioOfInertianear 1% for maximum damping. - MPC tuning: Start with
MPC_0th_order_gain= 1,MPC_1st_order_gain= 0.1,MPC_2nd_order_gain= 0. - Power cycle: After any firmware flash showing "Servo registered in NVM have been updated!", reboot both servo and controller.
Summary
- Command smoothing (PR2.22/PR2.23) is the primary cause of high-frequency oscillation and must be disabled by setting both registers to 0.
- PID stability relies on conservative gains and adequate output limits defined in
StepperMovementStrategy.h. - Oscillation detection (Pr6.37) protects against ABS/TC-induced hunting when set to a non-zero value (e.g., 10).
- Mechanical stiffness via
RatioOfInertiashould remain near 1% unless the pedal requires specific compliance characteristics. - Axis initialization must complete successfully in
isv57communication.cppbefore stable control is possible.
Frequently Asked Questions
What causes the DIY Sim-Racing FFB pedal to vibrate or jitter at high frequencies?
High-frequency jitter typically results from position-command smoothing filters (PR2.22 and PR2.23) active in the iSV-57 servo drive. These filters introduce phase lag that destabilizes the PID controller. Disable them by setting both registers to 0 in isv57communication.cpp or via the SimHub Servo Settings panel.
Why does my pedal oscillate only when ABS or traction control activates?
This indicates the oscillation-detection register (Pr6.37) is set to 0, preventing the servo from reporting overload conditions. The controller continues applying force against the mechanical stop, causing hunting. Set pr_6_00+37 to 10 (0.1% threshold) in the firmware to enable automatic backoff during overload events.
How do I tune PID gains if the pedal feels soft then suddenly snaps?
Start with conservative values: Kp = 0.1, Ki = 20, Kd = 0. If the pedal drifts or sticks, reduce Kp by 50%. If the stepper hits hard stops, increase PID_OUTPUT_LIMIT_FL32 above 0.5f in StepperMovementStrategy.h. Adjust the Ratio of Inertia slider in SimHub to 1% to increase effective damping.
What is the correct startup sequence after flashing new servo parameters?
After flashing firmware that updates servo registers (indicated by the message "Servo registered in NVM have been updated!"), you must power cycle both the ESP32 microcontroller and the iSV-57 servo. This ensures the axis-enable sequence (pr_4_00+8 = 0x0303) runs correctly and applies the new anti-oscillation settings.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →