Approaches for measuring and controlling engine speed

Hi all,
I’m looking at adding a PID engine speed control function to my fly-by-wire throttle project. The throttle controller is to be used on my offroad vehicle, not on a road going vehicle.

The code for this will need to measure the actual engine speed and perform PID calculations to find an appropriate throttle output.

I’m currently a little stuck on the best way to measure engine speed. I need a reasonably precise measurement (<1%?)(accuracy is not so important), but I also need to know it at intervals small enough such that the control calculations can be done at least a few times per second to give adequate response. Here lies the problem…(?)

Most examples of tachometers etc. I’ve found use a counter incremented in an interrupt function to count each rev. The main loop waits for either a certain number of revs or a certain length of time, and finds the average engine speed.

I’m not confident this will work well for me. Say I want to maintain the engine at 1000rpm (while driving over rough terrain). My engine computer outputs a pulse two times for each engine revolution, so I have a signal at ~33Hz, or period of 0.03seconds. If I wanted the throttle position to be updated every 0.25 second, that only leaves 8 revs for the average period to be calculated from… Which doesn’t seem ideal.

currently, my plan is for the main loop calulate the current rpm every 6 revs or so ( if revs>=6 period=millis()-previoustime etc.) and run the PID calcs every 0.25seconds (if millis()-prevtime >250 etc.). This should mean that there will always be a rev calculation in a loop where the PID calaulation isn’t being run (i.e. the loop will be very fast) before another calcualtion is done… So it should lead to good rev values.

Does this sound reasonable? Any better suggestions?

I have no evidence for this as I don't even know the size of the engine you are using but would the mass of the various engine components means that making changes that often be a bit redundant.

You may well be correct (FYI, it's a 1300cc SI engine), but I do want the controller to maintain the engine speed under some pretty interesting conditions. It's a fairly twitchey, high performance engine, and I'm trying to get it to crawl along smoothly over rocks in a very low gear at about quarter walking speed (hence the PID control, it's impossible to control it with your foot...). The very low gears mean that the backlash of the various gear sets between the engine and wheels is quite significant, meaning the engine goes on and off load very often.

I'm going to have to experiment with the update interval, hopefully it wont need to be all that often. However, I would like to have my code adaptable to run as fast as possible, in case I do end up needing it.....

Would using a tacho suit you? I'm not so sure of the acquisition times of the onboard ADC in Arduino, but it's a different approach to measure pulse interval or number of pulses. You may also use an external (faster) ADC to provide that info to you. :\

hedgeboar: The code for this will need to measure the actual engine speed and perform PID calculations to find an appropriate throttle output.

IMOHO, this is not a valid approach. Engine speed is determined by a combination of throttle position and load. Setting throttle position without knowing the load is meaningless. Furthermore, throttle position, at a given load, will determine engine RPM. IMO, it appears your chasing it backwards. Furthermore, the above approach doesn't even seem viable during periods of acceleration and deceleration because you're chasing current values rather than desired throttle position.

What is the actual goal you're seeking? What is your desired input? Throttle position? RPM? Vacuum*? Some combination?

  • Please note vacuum is frequently used as a means of load approximation. Its why, for example, ignition timing was frequently driven by vacuum.

I have a similar project where Im measuring speed of an engine. Im counting the pulses which are given by the ignition coil.

The curve is shown in the attachment.

byte rpmcount;
 unsigned int rpm;
 unsigned long timeold;
 void setup()
   attachInterrupt(0, rpm_fun, RISING);
   rpmcount = 0;
   rpm = 0;
   timeold = 0;
 void loop()
   if (rpmcount >= 20) { 
     rpm = 60000/(millis() - timeold)*rpmcount;
     timeold = millis();
     rpmcount = 0;
 void rpm_fun()

It is working so far. But regrettably its lightly imprecise, at 6k RPM it gives out just about 5,3k. I don’t know if its to fast for the Arduino but the signal is 100Hz, which should normally easily be done, isn’t it?



The more precision you want, the more samples you will need to be take. You may need to do something to get more pulses per revolution.

If I knew exactly what engine you were using I might have some specific help for you. Using your description "1300cc SI engine", you have either a VW engine or maybe a inline 4 cylinder with spark ignition.

If you had a motorcycle engine you could get far more pulses by reading the crank, whether it is built for CDI or a toothed crank that the newer fuel injected engines have. For instance Suzuki's latest sport bikes use a 24 tooth 2 spaces crank flywheel that gives the computer precise engine position for all events required to run the engine.

Race engines often have a magnetic timing wheel installed on the crank to work with racing style ignition boxes like MSD or Accel brand. Modern fuel injected cars set fuel timing and spark by reading pulses from the flywheel on the crank and not a distributor like carberated older cars.


For my Purpose, im using a Rotax 912 Engine. The Connection of the Electronic-rev Counter is shown on page 118

Im looking for the easiest way to read out the rpm.

EDIT: Its working for me now! Just need to set the baud rate to 115200 and the max rpmcount to 8

From the picture of the waveform on page 118 for the tachometer connection, it appears to be a inductive sensor that generates a positive and a negative pulse when the sensor operates. If you use that, the output voltage is going to change as RPM increases and you will need a circuit to make it work with the Arduino.

It may not be easy but, the engine has a output for a cable tach. If you were able to attach an encoder to that output you could get as many pulses as you see fit.

If you are using an alternator you might be able to get pulses from it but, I not sure what would be the best way.

If the crank would be well protected, I would rather have a toothed wheel to read engine speed from.


Greg, I don't need to know load, that's what the PID loop is for. I'm basically making a cruise control system, except it's keeping a constant engine speed rather than wheel speed. So the only difference is that it wont compensate for gear changes. The whole point of a PID controller is that you don't have to model the system explicitly....

The engine is a 1300cc suzuki car engine (the original engine from the truck it's in, which is a suzuki samurai). Throttle body fuel injection run by a megasquirt. At this stage, the ignition is still run by a distributor, so I don't have a crank/cam angle sensor. The best output I have is a 5v pulse train from the ECU, one pulse per ignition event. I am planning on changing the ignition setup to a wasted spark system, in which case I'll need a crank angle sensor, so if necessary I can mount that up for this project.

tsaG, yes that's pretty myuch exactly what I've got at the moment too. I don't seem to be getting the resolution I think I should be able to though. However, I've just had a thought that this could very well be correct -- I've got it connected to the megasquirt ECU which itself is connected to a simulator/test board which is emulating the vehicle -- the rev signal from that may not vary smoothly.

hedgeboar: Greg, I don't need to know load, that's what the PID loop is for. I'm basically making a cruise control system, except it's keeping a constant engine speed rather than wheel speed. So the only difference is that it wont compensate for gear changes. The whole point of a PID controller is that you don't have to model the system explicitly....

I understand that. And your approach likely will work for very simple cruising - little more. That was entirely my point. You're acknowledging the limitations which was the intent. Your approach is good for maintaining a pre-selected RPM. Once you leave that condition, its limitations start to become very profound. That in turn is why I asked you to review your actual goals. If that is in fact the full extent of your goals, then you'll likely be satisfied in most limitations.

I'll point out this is the first mention of a, "cruise control." Had your goal been a more generalized autonomous control system, again, IMOHO, your approach is deficient - doubly so for an off road vehicle (while making some wild weather and terrain assumptions).

Ah, I see what you were getting at. My only goal is for the controller to keep the engine at a predefined speed while driving over rough terrain.

Hi. While I am not aware of your goal and willing to add/develop more hardware, I am also on the need for a tachometer that would not rely on interrupts. The VCO option well discussed already here is good, but it depends on the precision you need for this reading. Say, if you want to show it on a dashboard, 100rpm error would be quite enough for an efficient visualization. Now, if 1 RPM change is of importance for the matter, then I would say don't use a VCO. If you would use interrupts (ok you don't want to), critical sections of your code can have interrupts disabled. See, for 6500RPM the interrupts frequency would be 108Hz, an ISR with a couple of tests and a variable incrementing or so could be very fast; but let's let this aside.

You know, the option of counting to 256 bits (or whatever X value you wish) would yeld a variable cadence of readings, and if visualization is an issue, this will have negative impacts. If the thing is at 128 rpm you would take 2 minutes to get a reading...

You always will have to live with an expected error (precision if you will). I was thinking myself by adding a counter chip, with a timing sampling controlled by the arduino, that would constantly read the count (SPI, or if you have spare I/O, parallel reading, etc.) then reset it. Say every 300ms, 500, 1s, I don't know it is usually dependant upon the aplication. then you read it and use the value. You could also define a timer for it I think.

Another option, add to it a latch (a hardware buffer) that is constantly updated by the counter circuit, that can also run with a clock generator and be completely standalone. The latch would be constantly updated. and the sensor would be always working. Then when you wan't to know the RPM value, you would just read it on the latch, via SPI (serial), or other method.

It all depends on a cost X benefit scale that should consider your need for performance, data precision, cost, complexity.

If you (sorry if I didn't see it on this thread) state "I wish do build a diesel engine tachometer that will present the value in an LCD, and I also need to compute some other info such as engine temperature, oil temperature, some other light/sensor), then maybe we could also help you to determinate the ranges and precisions involved and reasonable. For a car tachometer as an example, 200rpm scale is quite enough. So why add complexity and try to measure 5rpm steps or so? You may not even get this precision in the sampling... Then you would be able to decide better the solution for it.

One thing learned is that you should not start thinking in HOW to solve/build a thing, before letting your mind fly high, brainstorm, and project that mars rocket of you. After you know exactly what you want to build, then you begin to think how and eventually cut out the expensive/non practical parts of it. Or else, your project will start already being limited more than it should, and you may not see solutions for it.

If you already know all that you wan't to do, maybe sharing it a little more could help us to help you best. Of course if we are talking about intelectual property and business or so, at least some more detailed info should be presented.


-Quick interrupts, with critical sections of the other functions disabling interrupts (for 66.667 Hz I think that an 8MHz risk processor won't loose an interrupt, unless you let yout "other codes" to sleep) to avoid disruption as mentioned. Or even the interrupt may not be so intrusive as you suppose (or you have tested, or have real data figured out about the interrupt impact?)

-VCO (freq to volts converter) - depending on the precision needed, I think is the simplest approach. Also, there are lots of commercial dirty cheap chips to do that, no need to build one)

-External counter. This would add the trick to read the count either by serial or parallel.

Hope I have helped to figure it out a little more. Lissandro :-)

Ah, I see what you were getting at. My only goal is for the controller to keep the engine at a predefined speed >while driving over rough terrain.

..I am a liitle bit in doubt whether a simple measurement of rpm and simple PID would be enough for this task. You must consider the dynamics of the system as well. The roughness of the terrain does represent a random pulses (random period, random intensity, random duration, random shapes) of "resistance" against engine's effort. The engine shall react on that resistance via/based_on: wheels/tyres (flexible, vectored and delayed), tyres grip (complex), suspension (complex, flexible), shock absorbers (complex), gearbox (flexible, delayed), combustion process (complex, delayed), PID??, throttle (complex, delayed), momentum of the vehicle mass (vectored, complex), etc... p.

I think you are over thinking the details a bit. The engine is not likely capable of changing speed more quickly than an Arduino can respond in my opinion. Considering that lawn mowers, tractors, generators and many other engines operate with much more simple speed control systems. The reaction time of the throttle management will likely come down to the precision /speed of the motors running the throttles.

Granted, I would not think I could using an Arduino on a snappy race type engine. Although it should be noted that many race engines are "fly by wire" where the computer "more high tech than Arduino" is making the final decision on how much throttle the engine is given for acceleration and traction control.