Original solution
stalled_pwm_output = PWM / | ΔE |
PWM = maximum PWM value
ΔE = last_error - new_error
The initial relationship successfully increases the PWM output based on the absence of changes in the engine. See graph for sample output.
This approach does, because for a situation where a non-aggressive PID has stopped. However, it has a sad (and obvious) problem: when a non-aggressive PID is able to reach a given value and tries to slow down, stalled_pwm_output grows. This increase leads to a large overshoot when moving to an unloaded position.

Current solution
Theory
stalled_pwm_output = (kE * PID_PWM) / | ΔE |
kE = scaling constant
PID_PWM = current PWM request from non-aggressive PID
ΔE = last_error - new_error
My current relationship still uses the 1 / ΔE concept, but uses the non-aggressive PWM PID pin to determine stall_pwm_output. This allows the PID to throttle back to stall_pwm_output when it begins to approach the target, but allows 100% PWM output when stopped. The scaling constant kE is necessary to ensure that the PWM reaches its saturation point (above 10,000 in the graphs below).
Pseudo code
Note that the result from cal_stall_pwm is added to the PID PWM pin in my current control logic.
int calc_stall_pwm(int pid_pwm, int new_error) { int ret = 0; int dE = 0; static int last_error = 0; const int kE = 1;
Output
Slow PWM Output 
Please note that when the PWM output schedule is disabled, the sudden drop in PWM by ~ 3400 is a built-in safety function activated because the engine could not reach the position within the set time.
No load output PWM 
source share