|
|
|
![]() |
|
|||||||
|
||||||||
![]() |
| Thread Tools | Rate Thread | Display Modes |
|
#1
|
|||
|
|||
|
WPILibJ PIDController bufTotal Floating Point Error Accumulation
Last year, I posted about a bug due to WPILibJ's use of a running buffer sum in PIDController.onTarget().
Said bug has, indeed, been fixed - but this year, we've found another problem with this particular implementation: it is prone to accumulating floating-point errors, and this can cause a PID-based command to never exit. For those who haven't looked at the WPILib code, onTarget() is a function that is supposed to return TRUE when the average error over the past n loop iterations is below a set tolerance. This is implemented as follows: The PIDController contains a length n buffer of doubles, and a double "bufTotal." Each iteration through the loop, the current error value is placed in the front of the buffer, and its value is added to bufTotal. If the buffer is full, the last value is kicked out of the end of the buffer, and its value is subtracted from bufTotal. Thus, bufTotal can be used to calculate the desired average error. The idea behind this, as far as I can tell, is to reduce the number of calculations needing to be done at each loop iteration from n (the length of the buffer) to 2. This is a rather marginal benefit. A drawback, however, is that due to the nature of floating-point arithmetic, the value added to bufTotal when the error hits the front of the buffer is not necessarily the same as the value subtracted off again when it comes out the other end. Our turn-to-angle loop uses a sizeable buffer length to ensure that we do not accidentally exit the loop if we "swing past" the setpoint in an overshoot. It also uses a "minimum output" to account for the minor nonlinearity introduced by stiction - but this also requires that, to avoid "dancing" or "jittering" around the setpoint, we have a small deadband (slightly smaller than our set PIDController tolerance). A resulting behavior of this confluence of factors is that our loop can turn our robot to within the deadband (which is also within tolerance), but due to accumulated roundoff errors the calculated average error is greater than tolerance, and onTarget() returns FALSE. The robot will thus stay in this position forever, not adjusting its angle but not exiting the loop. We have since implemented a timeout to deal with this contingency, but that is less-than-ideal. I think it would be best to simply sum the buffer every loop iteration. The performance gains from keeping a running total are not worth the problems introduced. |
|
#2
|
||||
|
||||
|
It is probably worth creating an issue in the github repo for wpilib so this gets visibility by the dev.s and can be tracked to completion.
https://github.com/wpilibsuite/allwpilib Sent from my 6045I using Tapatalk |
|
#3
|
|||
|
|||
|
Re: WPILibJ PIDController bufTotal Floating Point Error Accumulation
Quote:
|
![]() |
| Thread Tools | |
| Display Modes | Rate This Thread |
|
|