ECUs and Tuning Discuss Engine Management, Tuning, & Programming

Arduino as ECU?

Thread Tools
 
Search this Thread
 
Old 09-25-2010, 03:34 PM
  #61  
Boost Pope
iTrader: (8)
 
Joe Perez's Avatar
 
Join Date: Sep 2005
Location: Chicago. (The less-murder part.)
Posts: 33,020
Total Cats: 6,588
Default

Originally Posted by bloodline
If I still want a throttle servo, I'll need to serve it at least every 40milliseconds
Right, I'd forgotten you were wanting to do throttle-by-wire. In that case, you'll have, at an absolute minimum, two TPSs (one on the pedal, one on the throttle shaft), and if you're smart and enjoy being alive, you'll have two on the pedal and two on the shaft, with cross-checking between them.

Why not use external A-D converters? Take the burden off the processor and just fetch the values in a single read operation. You can get very high quality 10 and 12 bit multi-channel converters quite cheaply these days. With the servo throttle in particular, I'd want the main and redundant sensors to be on separate A-D converters anyway.

Don't get me wrong, I still think that you're going to die as a result of this, and probably take a lot of other people out with you. But you'll definitely get mentioned in EE Times and The SAE International Journal.


I understand the mechanics, I need to know the flow rate per microsecond (I have found a webpage that claims 212cc per min on a standard injector, is this right?),
There's a fairly comprehensive list of injector flowrates in the third post here: https://www.miataturbo.net/diy-turbo-discussion-14/diy-faq-all-your-answers-one-big-post-4288/

You'll get slightly different values from different sources, which probably reflects the use of different fuel pressures.

Also, in a pulsed environment, you have to take into account the lag time on both opening and closing. In general, we tend to figure that for a high-impedance injector of the type we tend commonly to encounter, the actual flow time tends to be around 1 to 1.25ms less than the commanded on time, give or take.



what voltage/amperage they run at, and also if they need to be pulsed (i.e. if I supply continuous power will it burn out the solenoid?).
While there are many variations in physical construction, there are only two broad classes of fuel injector, from an electrical standpoint anyway: high impedance and low impedance, or hi-z and lo-z. (Well, there's a third style used in direct-injection applications, but they're not relevant to us.)


The vast majority of all fuel injectors in the world today are high impedance, including all injectors found as OEM on '89-'05 MX5s. These were the first to be invented, and are still the most common in the sum of extant passenger cars today.

High impedance injectors typically have a winding resistance in the general neighborhood of 10-14 ohms. Assuming a supply voltage of 12 volts, you'll have around 1 amp of current passing through each on, give or take. It's not necessary to regulate the supply voltage, you just put battery on one end and provide a switched closure to ground on the other. You can run them at 100% duty cycle and they will be just fine. Hi-z injectors are commonly referred to as saturated injectors, as their coils are designed to run in full saturation all the time.



Low impedance injectors are rapidly gaining in popularity. They are often found in high-performance applications using very large flowrates, and are starting to show up as OEM equipment on more and more cars, as they also have a beneficial effect on emissions at idle and very low duty cycle.

In a lo-z injector, the coil winding is generally in the 2-3 ohm neighborhood. Obviously this necessitates a more complex control scheme than simple on or off, or they'd just melt down. Also known as "peak and hold" injectors, you drive these by applying full voltage for the first millisecond or two, and then throttling them back to a much lower holding voltage. The idea is to slam the pintle open as quickly as possible by throwing gobs of current at it, and then, once it's open, restricting the current to only the level necessary to prevent it from closing without burning up the coil.

This can be accomplished in one of two ways. You can either PWM it, or you can use a linear analog circuit to control it. PWM is the method implemented in the MS, and while it's easy to do and very efficient, it has the disadvantage of generating a lot of electrical noise. The National LM1949 is an example of a chip designed for linear control, as used by JBPerf in their Peak & Hold driver board. While going this route raises the parts count and also generates a lot more heat, it doesn't produce a lot of noise and offloads the burden of worrying about injector control from the CPU. It's a closed-loop device using a current-sense resistor, so you just give it a simple on/off pulse and it figures out the rest.

As a result of all this, lo-z injectors have much shorter lag times than hi-z injectors, meaning you have much better control over fuel delivery at very low duty cycles, such as when trying to idle a 1.8 engine on 750cc injectors. (Don't laugh, some folks here are doing precisely this.)


Whatever you do, don't get taken in by the old trick of just putting 10 ohm resistors in series with lo-z injectors and then driving them with a conventional on/off signal. This is stupid, bad, wasteful, expensive, inefficient, and defeats the whole point of having bought lo-z injectors in the first place.




hmmm, timing from rising and falling edge would be much better... I'll add an option for it in my code, so it can be activated if needed.
I'm torn here...

Traditionally, we start the ignition timer on the leading edge of CKP (75° BTDC) on the principle that this is the shortest amount of time that we can get between the trigger event and the actual ignition event. Less uncertainty.

OTOH, as Jason and others have pointed out, crankshaft angular velocity is not a constant. The crankshaft accelerates during the first quarter revolution after a combustion event has been initiated, but then it starts to decelerate during the second quarter rev as the aforementioned combustion event concludes whilst another cylinder is simultaneously approaching the latter half of its compression cycle and increasingly opposing the movement of the crank.

Would taking a sample at 5° BTDC be better? It means that you're free-running for longer on the timer, but will the crankshaft's velocity when at 5° be closer to its velocity at the time of the ignition event than it would be at 75°?

Is there a physicist in the house?
Joe Perez is offline  
Old 09-25-2010, 05:09 PM
  #62  
Junior Member
 
bloodline's Avatar
 
Join Date: Sep 2010
Location: London, England
Posts: 91
Total Cats: 0
Default

Originally Posted by Joe Perez
Right, I'd forgotten you were wanting to do throttle-by-wire. In that case, you'll have, at an absolute minimum, two TPSs (one on the pedal, one on the throttle shaft), and if you're smart and enjoy being alive, you'll have two on the pedal and two on the shaft, with cross-checking between them.
Well, any DBW system would not be legal in my country anyway... so this is quite an academic exercise

I was thinking about adding a fully redundant backup for the throttle, but that defeats the point of using a lowcost MCU board like the Arduino.

If the entire ECU can be built as cheap as possible, then one could simply run two in parallel, and we have a basic FADEC

Also, would anybody honestly, seriously and actually trust their lives to a £6 RC servo?

Why not use external A-D converters? Take the burden off the processor and just fetch the values in a single read operation. You can get very high quality 10 and 12 bit multi-channel converters quite cheaply these days. With the servo throttle in particular, I'd want the main and redundant sensors to be on separate A-D converters anyway.
MAX do some nice SPI chips, and I did think about using one... but then I though I would rather get back to the simplest possible solution. This is more fun.

Don't get me wrong, I still think that you're going to die as a result of this, and probably take a lot of other people out with you. But you'll definitely get mentioned in EE Times and The SAE International Journal.
I have to agree with you! lol

Nothing I could build would be road legal anyway

There's a fairly comprehensive list of injector flowrates in the third post here: https://www.miataturbo.net/showthread.php?t=4288

You'll get slightly different values from different sources, which probably reflects the use of different fuel pressures.

Also, in a pulsed environment, you have to take into account the lag time on both opening and closing. In general, we tend to figure that for a high-impedance injector of the type we tend commonly to encounter, the actual flow time tends to be around 1 to 1.25ms less than the commanded on time, give or take.



While there are many variations in physical construction, there are only two broad classes of fuel injector, from an electrical standpoint anyway: high impedance and low impedance, or hi-z and lo-z. (Well, there's a third style used in direct-injection applications, but they're not relevant to us.)


The vast majority of all fuel injectors in the world today are high impedance, including all injectors found as OEM on '89-'05 MX5s. These were the first to be invented, and are still the most common in the sum of extant passenger cars today.

High impedance injectors typically have a winding resistance in the general neighborhood of 10-14 ohms. Assuming a supply voltage of 12 volts, you'll have around 1 amp of current passing through each on, give or take. It's not necessary to regulate the supply voltage, you just put battery on one end and provide a switched closure to ground on the other. You can run them at 100% duty cycle and they will be just fine. Hi-z injectors are commonly referred to as saturated injectors, as their coils are designed to run in full saturation all the time.
Ok good, the injectors won't require any special programming... I just switch them on for however long I need to get the desired amount of fuel.

Low impedance injectors are rapidly gaining in popularity. They are often found in high-performance applications using very large flowrates, and are starting to show up as OEM equipment on more and more cars, as they also have a beneficial effect on emissions at idle and very low duty cycle.

In a lo-z injector, the coil winding is generally in the 2-3 ohm neighborhood. Obviously this necessitates a more complex control scheme than simple on or off, or they'd just melt down. Also known as "peak and hold" injectors, you drive these by applying full voltage for the first millisecond or two, and then throttling them back to a much lower holding voltage. The idea is to slam the pintle open as quickly as possible by throwing gobs of current at it, and then, once it's open, restricting the current to only the level necessary to prevent it from closing without burning up the coil.

This can be accomplished in one of two ways. You can either PWM it, or you can use a linear analog circuit to control it. PWM is the method implemented in the MS, and while it's easy to do and very efficient, it has the disadvantage of generating a lot of electrical noise. The National LM1949 is an example of a chip designed for linear control, as used by JBPerf in their Peak & Hold driver board. While going this route raises the parts count and also generates a lot more heat, it doesn't produce a lot of noise and offloads the burden of worrying about injector control from the CPU. It's a closed-loop device using a current-sense resistor, so you just give it a simple on/off pulse and it figures out the rest.

As a result of all this, lo-z injectors have much shorter lag times than hi-z injectors, meaning you have much better control over fuel delivery at very low duty cycles, such as when trying to idle a 1.8 engine on 750cc injectors. (Don't laugh, some folks here are doing precisely this.)


Whatever you do, don't get taken in by the old trick of just putting 10 ohm resistors in series with lo-z injectors and then driving them with a conventional on/off signal. This is stupid, bad, wasteful, expensive, inefficient, and defeats the whole point of having bought lo-z injectors in the first place.
Since my car has hi-z, this is not relevant, but I must say very interesting!


I'm torn here...

Traditionally, we start the ignition timer on the leading edge of CKP (75° BTDC) on the principle that this is the shortest amount of time that we can get between the trigger event and the actual ignition event. Less uncertainty.

OTOH, as Jason and others have pointed out, crankshaft angular velocity is not a constant. The crankshaft accelerates during the first quarter revolution after a combustion event has been initiated, but then it starts to decelerate during the second quarter rev as the aforementioned combustion event concludes whilst another cylinder is simultaneously approaching the latter half of its compression cycle and increasingly opposing the movement of the crank.

Would taking a sample at 5° BTDC be better? It means that you're free-running for longer on the timer, but will the crankshaft's velocity when at 5° be closer to its velocity at the time of the ignition event than it would be at 75°?

Is there a physicist in the house?
I think really, I'd like a 720 toothed encoder... and run that for all MCU timing

But... I'm stuck with what Mazda gave me, and with timing derived from both the rising and falling edge of the CKP, that should give enough accuracy for me... I'm not looking to do anything weird I just want to build an ECU with an Arduino
bloodline is offline  
Old 09-26-2010, 06:34 AM
  #63  
Junior Member
 
bloodline's Avatar
 
Join Date: Sep 2010
Location: London, England
Posts: 91
Total Cats: 0
Default

Ok, I ran my code on a real Arduino today, and the Ignition timing pulse is never more than 0.5 degree late (and never early, as I'm erring on the side of late is better than early at low revs) at 1000RPM and never more than 1.5 degrees early at 8000RPM (with the timing advanced by 36 degrees as per the stock timing table. At 5500 RPM I'm never more than 0.1 of a degree early.

As this is alpha code, I think I can probably optimise it to get tighter timings. What degree of error do we expect/tolerate with respect to timing?

-Edit- Just a quick note to say good call on getting timing from the rising and falling edges of the CKP, the 8000RPM timing would be horrific if I only used the falling edge!

Also, Even though I don't have any injector time calculation in the code yet, the basic structure is built and only use about 4.5K of the AVR's 32K flash... plenty of space for some nice big lookup tables

Last edited by bloodline; 09-26-2010 at 07:08 AM.
bloodline is offline  
Old 09-26-2010, 10:04 AM
  #64  
Junior Member
Thread Starter
iTrader: (3)
 
ctxspy's Avatar
 
Join Date: Jun 2008
Location: NJ
Posts: 428
Total Cats: 0
Default

bloodline, good luck with your project, i hope it succeeds.

If / when you feel the code has reached a presentable stage, set up a project on sourceforge or something so others can contribute as well.
ctxspy is offline  
Old 09-26-2010, 10:15 AM
  #65  
Junior Member
 
bloodline's Avatar
 
Join Date: Sep 2010
Location: London, England
Posts: 91
Total Cats: 0
Default

Originally Posted by ctxspy
bloodline, good luck with your project, i hope it succeeds.

If / when you feel the code has reached a presentable stage, set up a project on sourceforge or something so others can contribute as well.
Hi ctxspy, I should have the basic code together in no time. I think I have the basic spark timing sorted out, with a timing advance based on a table I found on another webpage... I would like to change that to an actual function, which based on the speed of the flame front, adjusts the spark time to give the best possible timing advance at any RPM

I am happy to share the code and my mathematical models with anyone who wants to try this too, hopefully someone with experience interfacing with Real engine sensors and components.
bloodline is offline  
Old 09-26-2010, 11:16 AM
  #66  
Elite Member
 
JasonC SBB's Avatar
 
Join Date: Jul 2005
Posts: 6,420
Total Cats: 84
Default

You should be better than 0.5* accuracy.

When you test the code, also test it with the crank simulator revving up and down at circa 5000 RPM per second squared.

If you need the uC to look away for a bit of time, the best time to do it is right after a spark event, which makes it as far as possible from the next one.

But you are starting to see why a Propeller might be better. One cog would be dedicated to crank angle prediction, and spark. A Prop would need external ADC's tho.

As for reading MAP, I can tell you for certain that you will need at least 50 ms updates, better yet, 25 ms. Any slower and you will have hesitation at low RPMs and at low throttle openings. And, if you only read it once and act on it (i.e. no software filtering), you MUST have analog filtering on it. Software filtering requires that you oversample. And the software filtering needs to be "Bessel" like - (decaying weighting) - simple running averages are not optimal, will suffer from aliasing artifacts and poor performance, and you can't just sample based on crank position (e.g. every 2 revs), because the sampling rate will change 10x from 700 to 7000 RPM. Far from optimal.

The same will be true of all the other sensors. Re: TPS, IMO it *is* important to sample it quickly in order to do off-idle tip-in enrichment properly.
JasonC SBB is offline  
Old 09-26-2010, 11:24 AM
  #67  
Elite Member
 
JasonC SBB's Avatar
 
Join Date: Jul 2005
Posts: 6,420
Total Cats: 84
Default

Re: MAP filtering, look at my post re: my AEM.
The AEM has a software filter, but still, noise got through, until I added analog filtering:

https://www.miataturbo.net/showthrea...ghlight=filter
JasonC SBB is offline  
Old 09-26-2010, 11:39 AM
  #68  
Junior Member
 
bloodline's Avatar
 
Join Date: Sep 2010
Location: London, England
Posts: 91
Total Cats: 0
Default

Originally Posted by JasonC SBB
You should be better than 0.5* accuracy.
Oh, I was feeling quite good about my design until now

I can see loads of room for improvement, so I will have another go... my Interrupt handler was too complex etc, trying to do too much.

When you test the code, also test it with the crank simulator revving up and down at circa 5000 RPM per second squared.
Would I be able to parasite the real signals from a running engine? Any examples how to do that?

If you need the uC to look away for a bit of time, the best time to do it is right after a spark event.
After Joe said that the close point of the injector should be at a set point in the induction stroke, I realised that such a scheme would ensure the largest possible gap between the spark and the injectors, thus leaving room for and other housekeeping tasks.

As a side note, I changed the Arduino's ADC clock to 1Mhz, which drops the acquisition time down to 21microseconds, which is a very nice sample rate of 56Khz Unfortunately this probably won't be compatible with an future boards.

But you are starting to see why a Propeller might be better. One cog would be dedicated to crank angle prediction, and spark. A prop would need external ADC's tho.
The Arduino developers are already talking about an ARM based Arduino... that would be Vastly more powerful, and would make this whole process MUCH easier.
bloodline is offline  
Old 09-26-2010, 04:14 PM
  #69  
Junior Member
 
bloodline's Avatar
 
Join Date: Sep 2010
Location: London, England
Posts: 91
Total Cats: 0
Default

I have been reading this page for some extra info:

http://www.diy-efi.org/efi332/equations/algorith.htm
bloodline is offline  
Old 09-27-2010, 08:26 AM
  #70  
Junior Member
 
bloodline's Avatar
 
Join Date: Sep 2010
Location: London, England
Posts: 91
Total Cats: 0
Default

After running a few tests, and reading the EFI site, I decided to refactor my code and move to a deterministic polling based system to replace my interrupt based code... Turns out this is a much much better idea for running an engine with limited CPU resources an unfortunate side effect is that my code is now far less generic and is Miata NA specific, I was hoping to make it so the timer code would be a "plug in" module and could be easily reused for any other engine.

I want
bloodline is offline  
Old 09-27-2010, 09:06 AM
  #71  
Junior Member
 
bloodline's Avatar
 
Join Date: Sep 2010
Location: London, England
Posts: 91
Total Cats: 0
Default

Does anyone here know what the longest duration injectors are ever left open? I need to know so I can decide if I schedule the close event before or after the CKP goes high. Thanks
bloodline is offline  
Old 09-27-2010, 10:44 AM
  #72  
Boost Pope
iTrader: (8)
 
Joe Perez's Avatar
 
Join Date: Sep 2005
Location: Chicago. (The less-murder part.)
Posts: 33,020
Total Cats: 6,588
Default

Originally Posted by bloodline
Does anyone here know what the longest duration injectors are ever left open?
Seriously?

It's entirely possible (given inadequate injector sizing for the application) for the injectors to be on 100% of the time at very high RPM and load. Or 99%, or 98%....
Joe Perez is offline  
Old 09-27-2010, 12:18 PM
  #73  
Elite Member
 
JasonC SBB's Avatar
 
Join Date: Jul 2005
Posts: 6,420
Total Cats: 84
Default

Originally Posted by bloodline
After running a few tests, and reading the EFI site, I decided to refactor my code and move to a deterministic polling based system to replace my interrupt based code...
Why not switch to the Propeller then?

http://www.diyefi.org/forum/viewtopic.php?f=4&t=832
JasonC SBB is offline  
Old 09-27-2010, 01:23 PM
  #74  
Junior Member
 
bloodline's Avatar
 
Join Date: Sep 2010
Location: London, England
Posts: 91
Total Cats: 0
Default

Originally Posted by Joe Perez
Seriously?
Quite serious, I assure you.

It's entirely possible (given inadequate injector sizing for the application) for the injectors to be on 100% of the time at very high RPM and load. Or 99%, or 98%....
Hmmm, it's not too much of a stretch to have a different injection algorithm at higher revs if need be. I'm my current cycle, there is plenty of time for injectors.

Once I've got this code cleaned up, I will post it here, would that be of use to anyone?
bloodline is offline  
Old 09-27-2010, 01:33 PM
  #75  
Junior Member
 
bloodline's Avatar
 
Join Date: Sep 2010
Location: London, England
Posts: 91
Total Cats: 0
Default

Originally Posted by JasonC SBB
Why not switch to the Propeller then?

http://www.diyefi.org/forum/viewtopic.php?f=4&t=832
The propeller does seem quite a reasonable chip now I've had a play. I could really do with an extra core... But the lack of on chip peripherals (like ADCs and Serial UARTS/USB) make it undesirable for this project... I want the minimum chip count possible.
bloodline is offline  
Old 09-27-2010, 03:07 PM
  #76  
Elite Member
iTrader: (1)
 
richyvrlimited's Avatar
 
Join Date: Jun 2006
Location: Warrington/Birmingham
Posts: 2,642
Total Cats: 42
Default

Originally Posted by bloodline
Quite serious, I assure you.



Hmmm, it's not too much of a stretch to have a different injection algorithm at higher revs if need be. I'm my current cycle, there is plenty of time for injectors.

Once I've got this code cleaned up, I will post it here, would that be of use to anyone?

That seems like an overly complex way of going about it.
richyvrlimited is offline  
Old 09-27-2010, 03:18 PM
  #77  
Junior Member
 
bloodline's Avatar
 
Join Date: Sep 2010
Location: London, England
Posts: 91
Total Cats: 0
Default

Originally Posted by richyvrlimited
That seems like an overly complex way of going about it.
Possibly, but this is my first time developing ECU software... so I expect I have made lots of mistakes

But I have found a few solutions that have bought me more CPU time... Notably, I decided to convert all degrees to 4096ths of a circle... that has allowed me to removed all division operations from my code, and replace them with shifts... I also found a way to speed up Analog conversions on the AVR and found that interrupts aren't actually a great idea in this context. Not to mention all the knowledge and advice provided by the forum members here!

So all in all it has been been a very successful project so far
bloodline is offline  
Old 09-28-2010, 01:20 PM
  #78  
Elite Member
 
JasonC SBB's Avatar
 
Join Date: Jul 2005
Posts: 6,420
Total Cats: 84
Default

Why not 1024th's of a circle? That's 1/3rd degree and good enough precision.
JasonC SBB is offline  
Old 09-29-2010, 11:26 AM
  #79  
Junior Member
 
bloodline's Avatar
 
Join Date: Sep 2010
Location: London, England
Posts: 91
Total Cats: 0
Default

Originally Posted by JasonC SBB
Why not 1024th's of a circle? That's 1/3rd degree and good enough precision.
At 8000RPM the crank travels 1degree every ~20.8us... I was worried that if I used a lower resolution, I could miss a spark event by an unacceptably large amount... 1.8us vs 7.32us. Now that I'm busy waiting the CKP signal change, I guess missing a timing pulse is less likely, so the resolution is less important.

I considered using a 32bit value of 33554432, total over kill I know, but then 1 degree is 91.0 divisions, which is quite a nice value... But 32bit math on an 8bit chip is unpleasant :(

If 4096 proves unworkable in a real situation, then I will try 1024 no doubt I will need to refine the design quite a bit as I test it.
bloodline is offline  
Old 09-29-2010, 11:44 AM
  #80  
Junior Member
 
bloodline's Avatar
 
Join Date: Sep 2010
Location: London, England
Posts: 91
Total Cats: 0
Default

-Edit- looks like you might have a point, on paper at least... The error seems reduced using a lower division size... I might even try 512 per revolution
bloodline is offline  


Quick Reply: Arduino as ECU?



All times are GMT -4. The time now is 08:10 AM.