Governing an electric generator. Using comparator tach. and servo throttle.

Hello! This is my first project with an Arduino. The idea is to keep the engine of a generator at 3600 RPM regardless of load.

This is my plan's vague outline so far:

  • Use a transformer from a wall adapter to step down the generator's output voltage. Further voltage-divide the transformer output for use as a tachometer input to the Arduino's comparator.
  • Use a servo to control throttle position.
  • The particular platform is an Arduino Uno rev. 3.

The problem I seem to have run into is that I can't have both a servo and the comparator trigger an interrupt because they both use the same time/interrupt.

There are other timers though. I figured if timer 1 was tied up on tachometer duty then timer 3 could be utilized to control a servo. I know pins 9 and 10 use timer 1; so what's stopping me from using the other PWM pins?

If all else fails I can just use an external tach. source, e.g., external comparator or a trigger wheel etc.

Thanks in advance! :)

You're lacking an understanding of how the throttle control works with the engine's governor to maintain speed. The throttle doesn't set fuel flow but rather the throttle manipulates tension on the governor to set a desired speed.

If your engine is slowing down when under load there's nothing you can do about that but get a bigger engine. There's only so much fuel you can shove into the engine before it goes to rich and floods.

If by "throttle" you're referring to directly manipulating the butterfly valve on the carburetor... well that's something different. I don't think I've ever seen anyone do that but it would be interesting to see it.

Heh, decided to educate myself.

"The term throttle has come to refer, informally and incorrectly, to any mechanism by which the power or speed of an engine is regulated." -Wikipedia

Guess I'm guilty of that. XD

Yes, what I mean by throttle is controlling the butterfly valve in the carburetor. For extra clarity, this is a small 1 cylinder petrol generator from the '70's. It is capable of handling what loads I need it to (air conditioning mainly), I just need something to give it more throttle when the AC kicks on, then let up when the AC cuts off.

The current solution is to hand set the throttle position for the current load and check the voltage with a cheap multi-meter. Not ideal.

Sorry if I wasn't clear enough.

This has been done before, just not exactly how I plan on doing it. http://mckgyver.pbworks.com/w/page/20654147/Firewood_Processor_Governor An excellent find as a proof of concept.

I plan on my setup being simpler. A single button to activate/deactivate the governor that is pressed while the engine is running.

Thanks for the response! :)

It would probably be simpler (and less exposure to high voltages) to set up a mechanism to measure the RPM of the motor - perhaps a drop of white paint on the flywheel and a photodiode to detect when it goes past and calculate the speed from that. Then your servo could be used to move the throttle lever to adjust.

...R

XplosiveLugnut: This has been done before, just not exactly how I plan on doing it. http://mckgyver.pbworks.com/w/page/20654147/Firewood_Processor_Governor An excellent find as a proof of concept.

Except it's a diesel engine. ;)

I don't mean to be discouraging I just don't know if you can get better performance from the engine than the stock governor is already capable of.

From reading Reply #2 it looks as if the motor has no speed regulation at the moment - so anything would be an improvement.

...R

So it’s taken a while but I’ve had it working. At one point I had the generator loping, so I was getting close. After that though I took a long break from the project and I’ve lost the latest version of my code. The code I’ve got was the version I had just before I started tuning the governor’s sensitivity. This code required a little trouble shooting to get working again; however it’s still acting weird. I believe I’ve got some syntax related issues with my math. This is what I believe is the offending function.

	unsigned int UpdateServo(void)
	{
		unsigned int TimedOut = 0;//"False"
		unsigned long Timer;
		unsigned int NewServoPos = ServoPos;
		long intermidiate = 0;
		unsigned int TeethCount = 0;
		unsigned long Period;
		long Error;
		unsigned long Freq;
	
	////Get Tach Data	
		Timer = millis();//Set TimeOut Timer
		j = 0;
		while((j <= 8) && ((millis() -Timer) < 200))
		{	
			if((EIMSK & B0000001) == 0)
			{
				EIMSK |= B0000001;//Enable Int0
			}
		}
		EIMSK &= B11111110;//Disable Int0
	////Use Tach Data
		if(TachTimeOut() == 0)
		{
			Period = EndTime - StartTime;
			Serial.println("Period");
			Serial.println(Period);
			
			Freq = 16000000UL/Period;
			Serial.println("Freq");
			Serial.println(Freq);
			
			Error = (240L - Freq)/8;
			Serial.println("Error");
			Serial.println(Error);
			
			intermidiate = NewServoPos;
			intermidiate += Error;
			Serial.println("Intermidiate");
			Serial.println(intermidiate);
			
			NewServoPos = intermidiate;
			Serial.println("NewServoPos");
			Serial.println(NewServoPos);
			
			if(NewServoPos < 208)
			{
				NewServoPos = 208;
			}
			else if(NewServoPos > 500)
			{
				NewServoPos = 500;
			}
			return NewServoPos;
		}
		else
		{
			GovState = 0;
			return 208;
		}
	}

I know I should use an argument in this function instead of using a global variable. That’ll be fixed. I’m just wondering about the calculation syntax. I’m measuring the period of 4 revolutions in micro seconds. I’m then dividing 16 million by the period I get. This should give me a frequency that’s 4 times larger than the actual engine speed. I then compare this frequency to 240 which is 4 time 60. This comparison should result in a negative error if it’s going too fast and a positive error if too slow. This error is then divided (by 8 in this case) to further adjust the sensitivity and then added to the servo position. The larger the servo position the more the throttle valve opens.

I’ve been printing all this out to the serial console and every time the error is negative the console displays a very large number. I figured this was just the console not displaying 2’s compliment correctly.

This code acts… strange. It’s very stable but governs too fast. When a load is applied it’s too slow and when the load is removed it runs away. This behavior is completely different from the controlled loping I had last time.

I’m hoping a fresh set of eyes can will see some obvious flaw I’ve missed.

Thanks!

XplosiveLugnut: I know I should use an argument in this function instead of using a global variable. That'll be fixed.

Don't worry about it. I see nothing wrong (and a lot right) with using globals in a small system like the Arduino.

It would take me a long time to figure out what your function does, and it may not be possible without the rest of the code. Perhaps you could give us an explanation in English (rather than code).

I notice that you have several local variables. As you have not declared any of them static their values will be reset every time the function is called. Is that what is meant to happen?

There is a lot of code in your function. Sometimes that is unavoidable, but I try to keep mine short.

I don't see why you are getting tach data in the middle of the function. I would have though that would be in a separate function and would go on all the time.

None of these comments may have any bearing on your problem :)

...R

That code snippet seems to cover several functions that I would expect to be isolated from each other.

I suggest you start by writing the code to measure engine speed, however you plan to achieve that. Preferably design it to be something that is done asynchronously and continuously, rather than requiring your sketch to stop and capture data over a period each time it needs to know the speed. You need to get this working consistently and accurately before you try to do anything with the data.

You need to implement an algorithm to decide the required throttle position based on the actual and target engine speed. That will probably need to be smarter than a simple proportional control - a PID algorithm is a natural fit for this type of problem.

The servo itself would be controlled using the Servo library.

Warning, this ones a doozy.

This function does do a lot but I’ve got it this way because the only time I want to sample the rpm is when I’m going to change the servo position. The servo position is what I’ve prioritized. I’ve got two ISRs that handle the servo position. A timer1 overflow and compare match. The only thing that interferes with these ISRs is the ISR that timestamps the tach signal. The tach detecting ISR is only enabled for brief periods to prevent skewing the servo position.These are the timer1 ISRs.

/*
This ISR Ends the pulse that controls the servo
and sets the new pulse duration
*/

ISR(TIMER1_COMPA_vect)
{
  // interrupt on Timer1 compare match
  
  PORTB &= 0xFD; // Clears pin 9 (PORTB[1])
  OCR1A = ServoPos; // Sets duration of pulse to control servo
  return;
}

/*
This ISR Starts the pulse that controls the servo
and waits between pulses
*/

ISR(TIMER1_OVF_vect)
{
  // interrupt on Timer1 overflow
  
  if (i > 2)
  {
    PORTB |= 0x02; // Sets pin 9 (PORTB[1])
    i=0;
  }
  else
  {
    i++; // Waits long enough before another pulse
  }
  return;
}

The way the tach signal is time stamped uses interupt0. Heres that ISR.

/*
This ISR measures the tach signal
*/

ISR(INT0_vect)
{
	Time = micros(); //acquire current time
	if((Time - TimeOld) < 1000)  //this is a noise filter, ignores any two events that occur within 0.001 secs of each other
	{                                                 //at 2 events (rising and falling edge) per revolution this sets the maximum measurable
		return;                              //engine speed at 500 Hz or 30,000 RPM (I believe this is a non-issue :D )
	}
	TimeOld = Time; //if the engine is still running update "TimeOld" for comparison next time
	if(j == 0)
	{
		StartTime = Time; //sets starttime time stamp if its the first event of this sample set
	}
	else
	{
		EndTime = Time; //updates endtime time stamp for all subsequent events
	}
	j++; // j is controlled from the UpdateServo function
	return;
}

That ISR is called in my UpdateServo function I posted.

So that’s how I’m controlling the servo and measuring my generator’s engine speed.

The way I’m correcting for speed error like you said is just using a proportional controller. This is because the servo takes time to acquire its new position. I then have to wait (a very small amount of time) for the engine to respond to the new throttle position. I use the delays after my UpdateServo function finishes to account for this. I’ve got it waiting half a second after each correction at the moment.

Anyway my original question had more to do with these calculations in the UpdateServo function:

/* How everything is being declared

		unsigned int NewServoPos = ServoPos; //ServoPos is the current servo position being used by the servo controlling ISRs
		long intermidiate = 0;
		unsigned long Period;
		long Error;
		unsigned long Freq;
                unsigned long StartTime = 0;
                unsigned long EndTime = 0;

*/
//The calculations...

                        Period = EndTime - StartTime;

			Freq = 16000000UL/Period;

			Error = (240L - Freq)/8;

			intermidiate = NewServoPos;

			intermidiate += Error;
			
			NewServoPos = intermidiate;

I’m concerned with what I get when " 240L - Freq " results in a negative number and what dividing that by 8 will yield. Does this look like it would come out right?

Also, full code attached. Commenting may vary, working on it.

Yeah_Finished_1.0.0 (6.52 KB)

I haven't looked at your code yet but I am pretty certain you don't need ISRs to move servos.

I could understand an ISR to record the time when the tach trigger is fired - something like this

void myTachISR() { tachFiredMicros = micros(); }

but the rest of the code should work perfectly well without other ISRs if it is organized properly.

I will have a look at your code later today, but, be warned, I am lazy and look for the simplest solution.

...R

XplosiveLugnut: I've got two ISRs that handle the servo position. A timer1 overflow and compare match

Why aren't you using the Servo library?

I've now had a look at your code. It would take me at least an hour to make any sense of it and I'm sorry but I'm too lazy for that.

In principle this seems to be a simple project.

Use a short ISR like I suggested earlier to capture the time (in micros) when the tach pulse occurs. Use the difference between this time and the previous time to calculate the RPM (perhaps average a few readings to smooth things) Use the difference between the measured RPM and the target RPM to determine the new position for the servo Move the servo using the servo library.

...R

PeterH: Why aren't you using the Servo library?

While trying to fully understand how servos are controlled I stumbled across this guys method...

http://scolton.blogspot.com/2010/07/arduino-interrupt-driven-servo-routine.html

...and liked it because it's completely passive. The ISRs do everything in the background. The only thing you actually do in the main program loop is change the servo position variable. I was also able to manually find my particular servo's limits. The servo I've picked up has a slightly larger than normal sweep.

XplosiveLugnut: ...and liked it because it's completely passive. The ISRs do everything in the background. The only thing you actually do in the main program loop is change the servo position variable.

So far I don't see any advantage over using the Servo library, and it means you're messing around with interrupts yourself. Have you actually looked at the library?

Calculate RPM with interruppts and millis,
Feed RPM into PID.
Adjust servo with PID Output.

Old thread but I'll post anyway. Here is my project on this topic:

http://www.instructables.com/id/Generator-Governor/

This is project uses polling for RPM and computes a correction. You can use interrupts or other techniques for RPM computation but you cannot control your "system" faster than it will respond.

Additionally to do this, your system or engine for this thread, must be in very good running order. This was ultimately why my project would not control as desired.

If I had it to do again the RPM method I used was fine but I would use something else to compute RPM change.

Try using a dedicated RPM chip- will give you an analogue voltage output proportional to RPM for frequency which you can instantly "read" in the sketch. How are you controlling excitation for voltage?

This is called electronic governor in diesel engine. check below link.

http://www.dieselduck.info/machine/01%20prime%20movers/MAN%20-Woodward%20Basic%20electronic%20speed%20governors.pdf

XplosiveLugnut: "The term throttle has come to refer, informally and incorrectly, to any mechanism by which the power or speed of an engine is regulated." -Wikipedia

Throttle. literally, means to restrict airflow, as in choking someone. Early petrol engines did just that. That evolved into carburettors which included dashpots to give a richer mixture when a rapid increase in power was needed. Now, a computer controls both the amount of fuel being injected into the engine, and the airflow. Diesel engines are "free breathing", which means that there is no air control. For a petrol fired generator, all you need do is control the airflow, and the metering needle will adjust the fuel automatically. On a diesel engine, you only need to control the amount of fuel being injected by adjusting the power lever.