# Controlling a system with PID that resists backdrive

I'm controlling the angular position of a pendulum using a DC motor with a worm gearbox. Mechanically, worm gears are impossible to backdrive.

Using a PID controller on a pendulum system with a regular DC motor (no worm gear), the integrator would help the motor find the appropriate constant power setting to overcome gravity so the pendulum can hold any arbitrary position. With the worm gear, however, there is no need to apply constant power to the motor once the desired position is achieved. Power to the motor can be cut off and the worm gear will resist gravity's force to backdrive the pendulum to the lowest gravity potential.

It seems to me, then, that the integrator of the PID algorithm will cause large overshoots once the desired position is achieved. I want the integrator initially to help control the pendulum to the desired position. But once the position is achieved, I'd need the integrator to turn off.

The only solution I can come up with is to test for a special condition in the PID algorithm that checks if the position has been reached AND the angular speed is small, then instantaneously reset the integrator to zero. Is there a better way to handle the integrator in a system that resists backdrive?

** EDIT *

When I originally worded my question, I was mostly just interested in the academic approach of backdrive resistance in a PID loop. But it'll help if I explain the actual mechanism I'm building. The device is a robotic arm that rotates on a car window motor. It will also occasionally pick up and drop small weights at the end of the arm. Manufacturing variability in motors and the difference in drive torque when picking up the small weights led to me consider a PID loop.

• What is your feedback? What does your system look like exactly? Whether or not you can backdrive the system shouldn't matter, i.e. it won't affect your overshoot. What may matter is backlash if any (and that again does not related to back-driving). What you're talking about is more overdamped vs. underdamped. – Guy Sirton Jun 30 '14 at 6:14
• I'm using a hall-effect rotary sensor for feedback. I also edited my question to describe what my system looks like. – Dan Laks Jul 1 '14 at 7:22
• And yes, backlash is a problem I'm fighting. I'm hoping to design a sufficiently overdamped control system so that the pendulum doesn't overshoot due to slop in the gears when it slows down suddenly. – Dan Laks Jul 1 '14 at 7:28

This is a picture of my own PID-like regulator of the form:

out = feed + MaxMin(DiffMax, DiffMin, // limit the difference, add feed (can be removed)
+ P*(E=setp-feed)                   // proportional factor, error calculation
+ (A = MaxMin(AccuMax, AccuMin, A   // limit for accumulator
+ I*E - D*(feed-prev)))             // joined integrator and derivator


The big difference from regular PID regulators is in the way of using the accumulator for both I and D - which is a bit similar to that leaking integrator mentioned by ryan0270 (I was experimenting with similar thing as well). The derivator will decrease the accumulator (which can be limited as well to prevent windup and big value when set-point is greatly changed).

blue = output / control signal (force, input to boiler)
white = feedback (regulated value, actual temperature)
green/yellow = set-point (desired value)
red = state of accumulator (centered like being +50%)
navy/dark blue = proportional part

I have designed it for temperature regulation, but it seems to be equally good for your problem. My fade factor of the system is simulating the temperature dissipation / error of equitherm regulator. Your gravity and variable small weights seems similar to me. The integrator can compensate for this, but would normally overshoot and cause oscillation. Derivator applied on the shared accumulator prevents that - it reduces the accumulated error by the change made.

Proportional is strongest at the beginning (startup acceleration), Integrator comes next (error-correcting acceleration) and Derivator will slow it last (like a brake - preventing the overshoot by reducing the accumulator).

### Regulator step:

//  regulator step
float diff = setp - feed
float accu = 0
if pA && !isnan(diff)
//  integrator
accu = *pA + I*diff
//  derivator
if pV
accu += D*(*pV - feed)
*pV = feed
//  accu limits
if accu > aMax; accu = aMax
if accu < aMin; accu = aMin
//  store back
*pA = accu
//  proportional
diff = P*diff + accu
//  diff limits
if diff > dMax; diff = dMax
if diff < dMin; diff = dMin


### Full code:

#include <math.h>
#include "mem/config.h"
#include "device/analog.h"

__packed struct PID
byte    type
char    name[9]
word    period
Timer   tmr
byte    feed, setp
word    flags
ANALOG  output
float   vals[9]

enum
fP          = 1<<0
fI          = 1<<1
fD          = 1<<2
fDiffMax    = 1<<4
fDiffMin    = 1<<5
fAccuMax    = 1<<6
fAccuMin    = 1<<7

void devPid()
if !pid->tmr.reached(pid->period*10u)
return
pid->tmr.start()

//  inputs
float feed = 0.0f
float setp = 0.0f
if pid->feed < ainCount
feed = getxf(ains[pid->feed] + AIN_value)
if pid->setp < ainCount
setp = getxf(ains[pid->setp] + AIN_value)

//  PID factors (multiplicators)
float P = 0.0f
float I = 0.0f
float D = 0.0f
//  difference limits (output-feedback)
float dMax = INFINITY
float dMin = -INFINITY
//  accumulator limits (anti-windup)
float aMax = INFINITY
float aMin = -INFINITY

//  flags and pointers
word flags = pid->flags
float __packed* pf = pid->vals
float __packed* pA = null   // accumulator
float __packed* pV = null   // previous feed

//  parse variable object part
if flags & fP
P = *pf++
if flags & fI
I = *pf++
pA = pf++
if flags & fD
D = *pf++
pV = pf++
if flags & fDiffMax
dMin = -(dMax = *pf++)
if flags & fDiffMin
dMin = *pf++
if flags & fAccuMax
aMin = -(aMax = *pf++)
if flags &fAccuMin
aMin = *pf++

//  regulator step
float diff = setp - feed
float accu = 0
if pA && !isnan(diff)
//  integrator
accu = *pA + I*diff
//  derivator
if pV
accu += D*(*pV - feed)
*pV = feed
//  accu limits
if accu > aMax; accu = aMax
if accu < aMin; accu = aMin
//  store back
*pA = accu
//  proportional
diff = P*diff + accu
//  diff limits
if diff > dMax; diff = dMax
if diff < dMin; diff = dMin

//  final output
feed + diff)


You can tune it a bit and use the error, accumulator and feedback-change to detect the steady state to power it off.

• Maybe I'm still misunderstanding your question (or else you're trying to have it both ways). If more torque is required to raise added weight -- constant force -- then the I term is the only way to achieve that. Keep in mind that as you approach the setpoint, the P term is going to decrease while the I term remains the same; you should not overshoot the target in this case. I think ryan0270's answer might be the one you want. – Ian Jul 2 '14 at 23:37