PID, adjusting the sampling time, meaning of units

Show your code. And also the system you are controlling. If the system being controlled has a wildly different time constant than 10X your sampling time, the time-based terms will have problems.

The way that your code handles time is important. The Arduino PID_v1 library assumes a 1-sec time base for setting Ki and Kd, and then scales the internal ki and kd values to account for the sampling time, making the behavior consistent across sample time changes. Commercial controllers use the Ti and Td parameters to normalize across both sampling time and Kp changes.

Ah, from your code in #7, your time is measured in micros():

So, assuming stuff about the unseen input and outputs, Kinte is in outputUnits/(inputUnitsError*us) and KDiff is in outputUnits/(inputUnits/us).

Your small Ki and large Kd are due to your microsecond timebase. If you were using a second-normalized PID, like the Arduino PID_v1.h then your Ki would be 10 outputUnits/(InputUnitsError*sec) and your Kd would be 1 0.1 output unit/(InputUnitsChange/sec).

Your method of calculation already accommodates changes in sampling time because of your PIDTimeDiff term.

I do not see that the time of the previous sample is calculated, so it looks like the sampling time is same every time a sample taken and sometimes it can be 1 second interval and also 100 second interval.
bear in mind the rules are made on a simple air controller with some bellows in it same as a flapper nozzle system is operating
and they are recalculated to some sort of programming.

I messed up slightly: If your kd is non-zero and you have a fast update rate, you need derivative on measurement to prevent derivative kick. However, proportional on measurement is generally good to include to minimize overshoot.

On trick is to increase the pwm voltage enough to move at low values while reducing the maximum pwm duty cycle enough to prevent overload.

How far are normal motions on your setup? Thousands of degrees? Tens? Millions of microseconds? If long motions cause integral windup/overshoot problems then schemes like conditional integration, proportional zone jacketing, or back calculation could help limit integration induced oscillation and enable quicker/more aggressive integration.

I'm already using derivative on measurement, the anti-kick measure, my Kd term is multiplying by factors related to the change in measurement rather than change in error.

As far as Proportional on Measurement goes, what makes that any different from a pure ID controller? The PoM term ends up looking just like the diff term (except units are a little different as it doesn't divide by time) with the measurement during the current run of the control loop having the measurement during the previous run subtracted from it. That Brett Beauregard blog (great article series), and other things simply referencing it, seem to be some of the only search-engine-detectable discussion of PoM on the internet. So it is quite hard to find any explanations of PoM beynd the exact wording of that article, which doesn't quite explain why it doesn't act just like a pure ID controller.

Increasing PWM voltage, how can that be done? PWM is just a digital signal feeding to the enable pin of a h-bridge, and the h-bridge's power pin is just getting the voltage of my motor power rail (12V DC). Do you mean something like setting PWM so any non-zero output is atleast larger than some absolute value before adding on the commanded PWM value? I fear this would make oscillation more of a problem though, as to move at all for small angle changes during final settling you'd get motion bursts which would surely always overshoot.

"schemes like conditional integration, proportional zone jacketing, or back calculation"
Can anyone give me a link to easy to follow introductions to those concepts, thanks.

Thanks

It would be interesting to see a plot when using your existing PID controller functions.
If the plot could show input (PV), output (OP), setpoint (SP), p-term, i-term and d-term values, I'm sure a lot could be determined from viewing this.

pid_example

Ignore the dark blue and red (both lines caused by irrelevant other items printed in the serial)

Green is the setpoint

Yellow is the measured position of the shaft

Purple is the PID output (in units of -255 to 255 to set a PWM value)

Light grey is the Proportional term (note that whilst I clamp the total, the integral and the differential (although clamping never occurs for the differential with my Kd value) I do not clamp the proportional, however it is clamped in the graph.)

Light blue is the Integral term (I set it to be disabled except when the current position is within a 100 encoder ticks of the setpoint, note how it slowly starts to grow slightly close to the end of the motion)

Black is the differential term. It is shown opposite to the direction it actually acts in, so in this example it is actually a positive curve subtracting from the proportional where the proportional is outside the scale for much of the motion.

This graph is one of the better examples, in some the differential is a bit noiser but results are still about as good. In others the slight disturbances of purple, light blue and black continue for quite a bit longer at about the same magnitude as shown in this graph.

2 Likes

By increasing the PWM voltage I mean something like doubling the voltage, so there's enough energy in the low PWM numbers to overcome "stiction", but, assuming 12V is the limit for your motors, you would need to limit the high PWM numbers so 24V doesn't burn up your motors. It is built-in to motor drivers like this driver: Pololu - MP6550 Single Brushed DC Motor Driver Carrier but you may be able to do it with your Hbridge and arduino.

Schematic? Pics?

Anti-windup schemes are useful if windup is a problem. I don't know what you need more than Integral windup - Wikipedia but PID Anti-Windup Schemes | Scilab and Integral (Reset) Windup, Jacketing Logic and the Velocity PI Form – Control Guru aren't bad. Per the limited snippet of your code, and limited description of your system, your integrator scheme could possibly be a problem. For instance, if one happens to be driving some ball-screw thing, and one needs to move 500*360degrees at 60rpm, then the ~500 sec movement would start out with an error of 180000 degrees and with Ki=0.00001PWM/(degree*us), the first second would add about 180000*1000000*0.00001= 1800000PWM counts into IntegTerm, that would need to be wound down after passing the setpoint and error becomes negative. Maybe your unseen code handles that somehow.

Code please?

The proportional zone jacketing logic would be switching between the on/off control at the point where the PID would be saturated and become non-linear. Just considering the P-term of Kp = 2, with a max 255PWM, at 255/2=127.5° from the setpoint the PID would become non-linear or non proportional, and could cut out a lot of my hypothetical's 180000°us of integral windup. Perhaps you could wrap your code in some 'jacket logic' like if(MainTerm>255) {output = 255;} else if (MainTerm < -255) {output = 0;} else {...pid code...} to keep the proportional term proportional.

What are the time axis units?

Time axis is arbitrary on the graph I'm afraid. I think it might be related to the rate of serial printing.

Just as an extra note, maybe my usage is wrong, but I've mainly being using the integrating term as a way to force a movement (after time) when it would otherwise be too small a desired movement to be achieved simply by the proportional term. My integral term is there to grow over time to do what, at small errors from the setpoint, the proportional would not be big enough to generate a high enough PWM for motor motion.

FWIW...

For precision control of position, for example an axis drive for a CNC machine, a dual-PID control is typically used. One PID controls speed, the other position. The two are inter-connected so they cooperate with each other. This works extremely well for ANY kind of drive - DC servo, AC servo, stepper motor, hydraulic, voice coil or whatever. With suitable hardware, these systems are capable of extremely high performance and accuracy, with max velocities of several thousand inches per minute, and positional accuracy in the range or one or two ten-thousandths of an inch.

There's a significant time lag (deadtime?) from when the setpoint (green) is changed to when the output (purple) responds.

Perhaps this isn't due to your PID functions, maybe the controllability of your system is inherently in the "difficult" range.

What does the plot of just output vs setpoint look like (with no pid control)?
I might have missed this, but what is your input sensor and how fast does it respond?

Your

Is some anti-windup "jacketing logic" to keep the integral term sane.

Surely you have some idea whether the graph means 2 seconds or 2 minutes. We can't give more than WAGs about tuning without better information.

Once you have settled at the setpoint, the integral term is the only term capable of providing any output, because the error is zero (so Kp *error = 0) and since it is stable, the derivative is zero. If you need any PWM for holding at setpoint, the integral term is the only possible term.

The deadband around 0 PWM and integral oscillations aroubd it is a problem that could possibly be solved with a current limiting motor driver and a higher motor voltage. 3d printers commonly use 12V or 24V through current limiting drivers to drive steppers designed for 2.8V. With higher voltage, current-limited through drivers or by Arduino PWM with your current drivers, you could reduce the deadband oscillations and settling time.

Sorry, yes the axis is arbitrary, but the event shown takes a time on the order of 1 to 3 seconds, plus several seconds afterwards of "humming" on the unlucky (maybe 20%) or runs.

The deadtime might be some mechanical backlash actually. My motor (70rpm approx) and encoder (1200 counts/rev) are separate by various gear systems. Thanks for highlighting that, I hadn't realised the significance of that time gap until mentioned here.

2 Likes

I've done some further investigation:

I tried sending the motor a brief pulse of 1 millisecond of full 255/255 voltage. No motion occurs. i then stepped up the length of that pulse, when I first got to a pulse length of motion for which a motion would occur it would usually go move about 4 encoder steps, or more, in one go. It seems that a combination of gear backlash between the motor and encoder, as well as perhaps certain more stable points in the motor and/or encoder's hardware mean that single encoder count motions are perhaps impossible?

Is trying to control this motor down to the accuracy of its encoder a hopeless cause then? Given the lag time to start the motor moving and the backlash in the gears and the way that the shortest pulse which can move the motor at all moves it by >1 encoder count.

Thanks

Schematic?

How many volts was the 1ms pulse?

How long was the " i then stepped up the length of that pulse, when I first got to a pulse length of motion for which a motion would occur it would usually go move about 4 encoder steps, " pulse?

If you want tiny motor pulses, you need higher than the normal voltages you'd use for 100% duty cycle operation.

Do you understand motors have inductance? The motor voltage can be stepped but the current CANNOT change instantaneously. Rather, it builds up over time. How long it takes to reach max current depends on the applied voltage and the inductance of the motor windings. It would be far more meaningful to drive with a smaller PWM value for a longer time, likely tens or hundreds of milliseconds, allowing some time for current in the motor to build enough to overcome friction and start turning. The same will apply when turning the motor off. Current cannot drop instantly to zero.

Here are some of the results I got

Response time test:
Motor turns on at full power (12V):
54 milliseconds before first change on encoder seen
4 milliseconds before next encoder change seen
3 milliseconds before another encoder change
then motor set to zero power (shorted brake)
19 further encoder counts detected before it has stopped

Brief pulse of 12V test,:
Motor is supplied with 12V, time elapse and then short brake is made. 200ms after the short brake is made (plenty of time for the motor to fully halt) the encoder count is given.

Motor run for 1ms, moved to by 0 counts
Motor run for 2ms, moved to by 0 counts
Motor run for 3ms, moved to by 0 counts
Motor run for 4ms, moved to by 0 counts
Motor run for 5ms, moved to by 0 counts
Motor run for 6ms, moved to by 0 counts
Motor run for 7ms, moved to by -3 counts
Motor run for 8ms, moved to by -4 counts
Motor run for 9ms, moved to by 0 counts
Motor run for 10ms, moved to by -6 counts
Motor run for 11ms, moved to by 0 counts
Motor run for 12ms, moved to by -6 counts
Motor run for 13ms, moved to by 0 counts
Motor run for 14ms, moved to by -9 counts

Inductance, damn! I should have remembered that. Thanks for reminding me.

Positioning to an exact encoder count is simply not going to happen in a system with ANY backlash or flex. Instead, it will dither back and forth over some number of counts. About all you can do is insert hysteresis that makes the PID ignore some number of counts either side of the target. Friction can cause similar problems.

Thank you. I guess I've tuned the performance of the system about as well as is possible then. That will have to be good enough. Thank you for saving me rom an eternal time sink of impossibilities.