PID controller

Hi, I’m looking for a actual implementation of a PID controller for QNX, I’m particularly interested in the source code. A basic design regarding the timing will be very helpful.
I have all the math formulas so no worries there.
The application I’m working on will control 3 stepper motors with very high accuracy and dynamics

Steppers aren’t very dynamic in nature. All you do is send the required number of pulse at 'em at the right rate and it’s done. In fact they’re usually used exactly because they provide accurate position control with no need of feedback at all.

That is your typical “open-loop” senerio. And can also be very successfully employed using an external servo drive that simply follows the pulse stream, this drive has a feedback transducer for performing the “closed-loop” control and contains all the PID functions. This is common for modern “digital” drives. The motor position can still be fed back in to the computer for display purposes and a final verification but trying to apply a further level of PID control is pointless.

In the typical open-loop design there is often no need for fast response coding so profile generating can be buffered and feed out to the motors in an orderly and synchronous fashion.

However, if there is motor feedback into the computer and a fast motor with dumb amplifier then, yes, closed-loop PID coding is in order. In this senerio the amplifier is torque based and has no real tuning of it’s own, just a simple balance and gain. This is not completely true for modern digital drives that always have fancy features and can be configured to any of torque, velocity, or position for method of control.

Bedtime calls but here’s some thoughts until tommorow …

The basic PID coding should always be put in an ISR because buffering adds delay and this is the enemy in closed-loop design.

I’m a bit of a fan of floating-point myself so the ISR also backs-up the FPU register set for the duration of the ISR. Interrupts can also be free’d up to allow other IRQ’s to be serviced while the sometimes lengthy code path is processed.

There is two approaches used in the hardware here the DAC’s can be buffered or unbuffered. If they are unbuffered then you have to consider the effect of changing the output voltage the moment you have a new number for an axis or waiting until all axes have been processed and then updating them all at once. If the DAC’s are buffered then updating them all at once is best since that’s what the hardware is deisgned to do anyway. In fact some will only perform the transfer from the buffer register to the DAC when the timer triggers for the next interrrupt, this would also apply to the encoder counters if present.

The application is to control a astronomical telescope on 2 axis and one focus drive. The encoders will provide a closed loop to counter imperfections in the high precision worm gears. The drive’s will receive a 0 to 100% position/speed setpoint. Actual position is measured with a highspeed counter card from advantech.

Cool. It’s unlikely you will be needing anything high-speed with this app and certainly using an IRQ is overkill. Also, only the “Integral” component will be of any use as a fine adjust, all other components will just add noise.

The control loop, aka servo, will have modes of operation. Names like JOG, STOP, DISABLE, MOVE, TRACK. And status of mode like JOGGING, MOVING, TRACKING, IDLE, DISABLED, INPOSITION, and various faults. VECTOR is a good name for 2D linear moves, then there is ARC or CIRCLE and whatever else takes your fancy. :slight_smile:

During a move, for example, there is a profile built that ramps the motor up to traversing speed moves a needed distance then ramps back down to zero speed ending at the exact number of steps requested at the start of the move.

One feature I assume you will be wanting is to lock onto a particular star and continuously track it through the night. The way I would do this is perform a vector to the trailing edge of the target star and then engage the tracking mode.

The vector won’t need to monitor the position but it doesn’t hurt to do so. The tracking mode only shifts by one step at a time and then checks it’s position before deciding to move the next step. This is a very simple integral function but will generate the least noise.

The reason for the trailing edge is to “take up” the mechanical slop of the system while the auto tracking winds the telescope on to the target star. Again this is a noise reduction trick.

Now that I’ve written all that, I notice you are saying the drives are not using position stepping as signal input but instead are velocity based, correct?

PS: I don’t have any decent tuition example source code but if you want a particular point illustrated then do ask.

Whow, finally somebody who knows what I’m talking about.
The application will generate pulses to the stepper drive’s, these pulses have to be accurate from zero to 1Khz (depends on the selected gear ratios), I guess this has to be interrupt controlled.
The control loops are more or less the same as you mentioned, only the hour drive is constantly controlled to maintain position relative to the viewers location on earth. This control activity is crucial for the accuracy of the telescope, the vector is great idea! The application will run on a target and will be connected tot a desktop computer via a rs232 connection and communicate with a astronomical program called TheSky.

Thanks but I’m no telescope expert. I’ve had the pleasure of programming a dedicated servo controller, a SmartMove, and writing my own code to replace the SmartMove.

The term “hour drive” is foreign to me. I figure there is two axes for pointing that form a tilt and rotate motion, and the hour drive is tilt?

As for the pulse generating, you look to be bit-bashing an output on a per-interrupt basis. This should be okay and if you want fine control of the higher frequency pulse rates the answer is to temporally dither. This can even help at the lower pulse rates if you need to specify the velocity exactly.

In what ways can the amplifiers accept pulses? My preference is quadrature signaling in the same way as the encoders work, every edge is a step. This is easy enough for code to produce but, obviously, the amp must be able to handle it. Basically, the less I/O accesses the better as they cost about 500 nsecs each.

The tick source can often be the encoder counter card but the system tick can be used. If using the system tick then setting it to a faster rate with ClockPeriod() would be a good idea, 10 kHz should give good resolution I think. Btw: If you are using the PCL-833 then use it’s timer at risk because there is a bug with it that randomly causes the timer to freeze on any subsequent timer accesses until it’s power-cycled. I can’t speak for the other counter cards but if they have same register set then I would be cautious. And advantech.com is down atm so I can’t look for myself. :frowning:

There is one drive that rotates 360 deg every 24hours to keep position on the viewed object, that is a star in this case, planets have different orbits, with means that to track a planet both drive’s could be in operation. Not sure if this is what you mean with tilt.

The amplifier accepts pulse signals, one puls in one step or 1/4, 1/8 etc. stepmode is set on the amplifiers, direction is a one/off signal on the amp. So I only have to provide 1 puls per step.

Can you read my mind? :wink: How do you know I’m using the PCL-833? My good friend freddy martens is developing a driver for that card, or is that no longer necessary because you have one for QNX?
:smiley:

Just did a little googling and found that the axes are not square with the ground and any cover/shield used is also driven independantly of the telescope. I think I have a handle on the hour angle thingy now. :slight_smile: Thinking about this now, it seems silly that I presumed a square mounting, it’s interesting how the mind steps back only so far when considering function of new machinery.

Personally, I’ve used floating point to specify velocities and then accumulate the fractional position error on a tick by tick basis. This creates the desired dithering I mentioned earlier.

That method of stepping, pulse+direction, costs a little more in I/O usage but is simpler to understand. Remember, when changing direction the state of the direction should be updated before outputing the step pulse, ie: Make it a separate out() instruction.

You should experiment with what happens if you only perform a half pulse. ie: Does it step only on one edge and the other edge just completes the cycle or do you get two steps for a whole pulse …?

How many steps per hour are you expecting the hour drive to be doing to stay on track? And what is the resolution (lines) of it’s encoder?

As for the PCL-833, heh pure guess, well not even that. Nah, I never wrote any driver, just simply had it as another source file … not to mention this was all before I started fiddling with QNX.

Small correction about the PCL-833:
When I said subsequent timer accesses, I ment subsequent modifications of the timer settings. Even attempting to disable it can cause it to freeze. Chances of faulting get higher at faster trigger rates but at all rates there is still some chance.