Chris,
I have built exactly what you are thinking about.  It works fine.  My biggest mistake was to add too many bells and whistles.  I would have been better off with just controlling the frequency, I ended up with a system that does everything except feed the cat. You can read the whole story here:
http://martin.nile.googlepages.com/automaticgeneratorcontroller.
As Jens pointed out, the trickiest part of building a PID controller is tuning the gain variables.  Mine is not perfect, There is room for improvement. I stopped tweaking when I got it to hold the frequency close enough to keep my APC ups happy. I'm doing this with a Changfa 195 running at 1800rpm. I haven't tried this on my listeroid. I assume it would take longer for the PID controller to catch any frequency excursions.
Here is a graph that shows how my controller behaves versus the stock spring.
When I add a 5000 watt load, the stock governor (purple line) drops to 1700 rpm (56.6hz) within half a second. Â The PID governor starts picking up at .4 seconds and has recovered to 1800 rpm by 3 seconds.
This graph shows the behavior when the load is removed.
The spring governor behaves nicely and the rpm's return to 1800 within about a second. Â The PID controller overshoots the mark by 60rpm (62 hz) but eventually settles to around 1800rpm within 1.5 seconds.
For your reading enjoyment, here is my fixed point implementation of the PID controller.
/*******************************************************
* pidcontroller -- calculate the adjustment to the stepper position
*
* based on emprical tests: Pc=20, Kc=280
*
* Ziegler-Nichols tuning: pgain=0.65 * Kc = 182
*Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Ti=0.5 * Pc = 10
*Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Td=0.12 * Pc = 2.4
*Â Â Â Â Â Â Â Â Â Â Â Â Â dgain= pgain*Td = 182*2.4=436
*Â Â Â Â Â Â Â Â Â Â Â Â Â igain= pgain/Ti = 18 *4 = 72
 * All gain values are multiplied by 256 so we can do
* the arithmetic in integers. The result is divided by 256
*
******************************************************/
int pidcontroller(void) {
int error;
long pterm; // proportional term. The pterm is long because on startup
// the pterm has a very large error when multiplied by the pgain
// will exceed the size of a normal int.
int iterm; // integral term
int dterm; // derivative term
int temp;
#ifdef PIDTUNE
pgain=(getadc10(3)-8)*2; // pc3 (uco empty) is temporarily used as a pgain control
if(pgain < 0) pgain=0;
igain=getadc(4)-8; // pc4 (diesel empty) is used as igain control
if(igain < 0) igain = 0;
dgain=(getadc10(1)-8)*4; // pc1 (watertemp) is dgain control
if(dgain < 0) dgain = 0;
#endif
error=TARGETRPM-rpm;
// calculate the proportional portion
pterm=((long)error*pgain);
// calculate the integral portion
// If we are at the stepper limit, and still want to go higher,
// do not add any more to the integral
if(!(PINB & LIMITHI) && pterm > 0) {
temp=sumerror;
}
else {
temp = sumerror + error;
}
if(temp > 5000){ // limit the integral windup
temp=5000;
}
else if(temp < -5000){
temp=-5000;
}
sumerror = temp;
iterm = (igain * sumerror)/32; // note!! /32 gives us more fractional resolution for the igain variable
// Calculate the derivative portion
dterm = dgain *Â (rpm - lastrpm);
lastrpm = rpm;
temp = (pterm + iterm + dterm) / 256;
// if the adjustment is less than 2 steps, don't bother
if(abs(temp) < 2) {
temp=0;
}
#ifdef PIDTUNE
putstr("\r\n");
print4(rpm);
putch(' ');
print3(pgain);
putch(' ');
print3(igain);
putch(' ');
print3(dgain);
putch(' ');
print5(temp);
#endif
return(temp);
}
I have been kicking around the idea of building a minimal frequency controller without all of the bells and whistles of my generator controller. I'm thinking of using an 8 pin MCU and the guts of an old 5 1/4" floppy drive to apply a bias to the stock governor spring. Total out of pocket expense should be less than 10 bucks for the CPU and hall effect sensor to pick up rpm. Everything else is sitting in my junk box.
My Listeroid has had all of the water drained and buttoned up for the winter, so I won't be able to do any testing until sometime next year.
--
Martin