advice needed for arduino as diesel injection brain...

int posPin = A1;          // the input pin for position sensor
int posValue = 0;         // variable to store the value from the sensor
int injectorpin1 = 13;        // the pin for the injector solenoid1

Consistency is good. If you were consistent, the 3rd variable would be named injectorPin1, which would be much easier to read, in my opinion.

long previousMillis = 0;     // will store last time injection time was updated

Time variables are unsigned long. You don't normally need to accommodate time running backwards. At least not in our universe.

  if(posPin == 0) // of camshaft position is 0 degrees then fire cylinder 1
  if(posPin == 256) // of camshaft position is 90 degrees then fire cylinder 3
  if(posPin == 512) // of camshaft position is 180 degrees then fire cylinder 4
  if(posPin == 768) // of camshaft position is 270 degrees then fire cylinder 2

I don't know what kind of analog device you are reading, but depending on exact values from an ADC with a resolution of +/- 1 is not a good idea. Your injectors are going to not fire when they are supposed to, a lot.

When to fire the injector. with respect to cam position, is typically a function of load, engine RPM, and a host of other sensor readings. I fear that you are oversimplifying a very complex process.

I don't understand.
In bash to would mean "if $currentTime minus $previousTime is larger then Interval (throttle position) stop injecting"???

It means, without the $, exactly the same thing in C.

PaulS:

long previousMillis = 0;     // will store last time injection time was updated

Time variables are unsigned long. You don't normally need to accommodate time running backwards. At least not in our universe.

I don't understand.
In bash to would mean "if $currentTime minus $previousTime is larger then Interval (throttle position) stop injecting"???

It means, without the $, exactly the same thing in C.

I new that but I wanted to know what cyclegadgets reason was with that...

PaulS:

  if(posPin == 0) // of camshaft position is 0 degrees then fire cylinder 1

if(posPin == 256) // of camshaft position is 90 degrees then fire cylinder 3
  if(posPin == 512) // of camshaft position is 180 degrees then fire cylinder 4
  if(posPin == 768) // of camshaft position is 270 degrees then fire cylinder 2



I don't know what kind of analog device you are reading, but depending on exact values from an ADC with a resolution of +/- 1 is not a good idea. Your injectors are going to not fire when they are supposed to, a lot.

When to fire the injector. with respect to cam position, is typically a function of load, engine RPM, and a host of other sensor readings. I fear that you are oversimplifying a very complex process.

I have know clue how to read a rotary encoder so I presumed that it would give me an output from 0-1023 like a potentiometer would. (the documentation of the automotive encoder also was talking about 1024 steps)
You are writing that the injectors will gonna skip firing with that resolution, is that due to the duration of a single encoder step compared to the time the loop lasts?
If so a loop won't work with my timing disc either since at 9K rpm the pulse from that is about 1microsecond. (that is why I tried to use interrupts in my first code)

A combustion engine isn't a very complex process at all, current automotive products make it complex due to drivability, environmental issues and so on.
In tractor pulling we need an engine that runs at idle and at full throttle, we don't shift but open throttle and hold on.
We have a 2.0l diesel engine making 400HP at 8000rpm with a boost pressure of 5bar, when hoocked on we rev up to 4000rpm (3bar of boost) and release the clutch.
This is our conventional injected machine:
https://picasaweb.google.com/lh/photo/4USFns0LHkMvU5lqaYSGmdMTjNZETYmyPJy0liipFm0?feat=directlink
And this is our common-rail, no uC used, ne555, HEF4044 and HEF4081.
https://picasaweb.google.com/lh/photo/do7wdb7tZnFQsgpcPFTMmNMTjNZETYmyPJy0liipFm0?feat=directlink

Throttle controls the injection time, the fuel pressure (800-2500bar) and timing advance (-10 at idle and -35 at full throttle) so the only thing the uC has to do is read an input and opens an output for a throttle defined amount of time. (ok, 4 times in a cycle)

If I understand correctly;
rotation encoder isn't a good idea.
using a loop either.
So back to my first thought with using 4 interrupts and a distributor for giving injection pulses?

I have know clue how to read a rotary encoder so I presumed that it would give me an output from 0-1023 like a potentiometer would.

No, it will not. A rotary encoder is a digital device. It is like a whole bunch of little switches. You need to read the encoder fairly often to detect the direction it is moving, and how many times the little switches have been pressed.

There is an article on the playground explaining rotary encoders.

Throttle controls the injection time, the fuel pressure (800-2500bar) and timing advance (-10 at idle and -35 at full throttle) so the only thing the uC has to do is read an input and opens an output for a throttle defined amount of time. (ok, 4 times in a cycle)

So, when does the uC switch from -10 to -35 degrees? Doing that abruptly sounds like a bad idea to me.

If I understand correctly;
rotation encoder isn't a good idea.

Using a rotary encoder is a fine idea, if you understand how to read it properly.

So back to my first thought with using 4 interrupts and a distributor for giving injection pulses?

You could do that with a Mega, with more external interrupts. The UNO only has two, and you'll probably want to use those to read the encoder, since that is the critical, time-dependent, input.

Insert Quote
Quote from: PaulS on Today at 07:02:36 AM
Code:

long previousMillis = 0; // will store last time injection time was updated

Time variables are unsigned long. You don't normally need to accommodate time running backwards. At least not in our universe.
Quote
I don't understand.
In bash to would mean "if $currentTime minus $previousTime is larger then Interval (throttle position) stop injecting"???
It means, without the $, exactly the same thing in C.

I new that but I wanted to know what cyclegadgets reason was with that...

That portion of code was based on an example from the Arduino IDE. I mostly just changed variable names. Turns out the example has the error of not using unsigned long for previousMillis and I did not catch it.
Here is the example code link: http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay

PaulS:
So, when does the uC switch from -10 to -35 degrees? Doing that abruptly sounds like a bad idea to me.

The uC won't, the throttle cable is (was in the past) connected to distributor so more throttle means more advance.
Using throttle for advance timing is discussionable but in practice it has proven to work very well, and gives a very responsive engine.

In the pic. the distributor is mounted on the front of the (old) engine directly on the camshaft pulley. (square aluminum box with lots of wires :wink:
Our previous device and schematics are over here: http://www.japie.deserver.nl/ftp/Cuprum/ if your interested.

I have read the playground encoder stuff and I see what you mean, I was expecting it to give a different value for each step but they only give pulses so code is always needed for calculating the position. (and adding error possibility when a pulse is missed or doubled)

I will use the exact setup as in the past with the alternator and a Mega to replace my electronics, thanks for helping me out...

The uC won't, the throttle cable is (was in the past) connected to distributor so more throttle means more advance.
Using throttle for advance timing is discussionable but in practice it has proven to work very well, and gives a very responsive engine.

My point, exactly. The code you posted before had a fixed relationship between cam position and injector firing. The old setup had a variable relationship between cam position and injector firing.

If the uC is to be used, that variable relationship needs to be maintained, or the performance of your engine is going to change. And, probably not for the better.

PaulS:
If the uC is to be used, that variable relationship needs to be maintained, or the performance of your engine is going to change. And, probably not for the better.

That's for sure Paul.
The fun part is that we don't do it this way because it will gain power but mostly because others don't do it this way at all.
Will order a Mega tomorrow and gonna have some fun...

Are there any update's about using Arduino with common rail?

Panther95

For sure there are only 2 External Interrupts.
But almost every pin also supports PCINT, whichNick Gammon has a great page on and even shows them as being a little faster:

japie:
Aren't all digital ports usable as interrupts? Or do I need to add some extra function to accomplish that?

Yes, using Pin Change interrupts, as CrossRoads kindly pointed out, I have a page about that:

Not the way you wrote it though. I certainly think you can react in under 20 uS to an external event, if carefully coded. The interrupt processing itself takes about 3 uS to kick in, and then you need to work out which pin caused the interrupt, if using pin change interrupts.

Panther95:
Are there any update's about using Arduino with common rail?

Not working yet, have been a bit busy with other aspects of the machine but did come somewhat closer.
Currently the electronics for the PWM driver for the pump pressure and the alternator are being made and the alternator housing is finished.
Also have some testing to do since my new injectors are slightly different from my previous ones.

My previous project with timer stuff and injector drivers in it can be found at: http://www.minimumrisk.nl/articles.php?lng=nl&pg=270

Last code looks like this:

/*
  Cuprum-2.0 simplified 1-3-4-2 cylinder common rail injection system for Arduino Mega.
  
  Using interrupts for timing injections cycle, a timing disc (alternator) is mounted to camshaft.
  Throttle position is read from potentiometer.
  
  Base rule for the system is that we want all fuel injected at 10 crank degree before TDP:
  - timer 2 gives pulse for cylinder 1
  - wait (180 degrees in uS at current rpm) - injection time - (10 degrees in uS at current rpm)
  
  Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground, output will be 0-1023.
  Attach timing signals to external interrupts: cyl1 pin 3, cyl2 pin 21, cyl3 pin 20 and cyl4 pin 19.
  Attach injector drivers: cyl1 pin 4, cyl2 pin 5, cyl3 pin 6 and cyl4 pin 7.
*/

// setup pin for throttle potentiometer:
int ThrottlePin = A0;
unsigned long ThrottleValue = 0;
unsigned long ThrottleDuration = 0;
// base idle injectiontime is 100uS
unsigned long IdleDuration = 100;
// define throttle calibration values:
// we like to inject from -45 to -10 TDP making 35 degree injection duration max.
// crank duration in uS: (1000000/(rpm/60))/360*35
// at 10K rpm that is 583uS since the throttle has 1023 steps 1023/583=1.75
float ThrottleCalib = 1.75;
// define injection delay
unsigned long InjectionDelay = 0;
// define microsecond timeframe between 2 injects = duration 90 degree camshaft/ 180 degree crankshaft
unsigned long TimeFrame = 0;
unsigned long TimeOld = 0;
unsigned long Delay = 0;
// setup timer pins for interrupts:
int cyl1 = 1;
int cyl2 = 2;
int cyl3 = 3;
int cyl4 = 4;
volatile int state = LOW;
// setup pins for injector drivers:
int inj1 = 4;
int inj2 = 5;
int inj3 = 6;
int inj4 = 7; 

void setup()
{
  // initialize the digital injector pins as an output:
  pinMode(inj1, OUTPUT);     
  pinMode(inj2, OUTPUT);     
  pinMode(inj3, OUTPUT);     
  pinMode(inj4, OUTPUT);
  // attach action when interrupt gets actived:
  pinMode(cyl1, INPUT);
  attachInterrupt(1, inject1, RISING);
  pinMode(cyl2, INPUT);
  attachInterrupt(2, inject2, RISING);
  pinMode(cyl3, INPUT);
  attachInterrupt(3, inject3, RISING);
  pinMode(cyl4, INPUT);
  attachInterrupt(4, inject4, RISING);
}

void loop()
{
  // read the throttle input on analog pin 0:
  ThrottleValue = analogRead(ThrottlePin);
  // see if we are trying to have fun
  if (ThrottleValue > 5)
    {
    // injection delay uS/180*170 to make sure all juice is injected 10 degree before TDP.
    InjectionDelay = TimeFrame/18*17;
    // recalculate throttle value to wanted microseconds:
    ThrottleDuration = ThrottleValue/ThrottleCalib;
    // check the interrupts:
    digitalWrite(cyl1, state);
    digitalWrite(cyl2, state);
    digitalWrite(cyl3, state);
    digitalWrite(cyl4, state);
    }
  // it seems we are idling
  else
    {
    // on idle we want injecting to stop at TDP not before
    InjectionDelay = TimeFrame;
    // if we are running 900rpm we reduce injection time
    if (TimeFrame > 33333)
      {
      // reduce injection time
      IdleDuration=IdleDuration-5;
      ThrottleDuration = IdleDuration;
      }
    // if we are running 800rpm we inject a bit longer
    else if (TimeFrame < 37500)
      {
      // expand injection time
      IdleDuration=IdleDuration+5;
      ThrottleDuration = IdleDuration;
      }
    // check the interrupts:
    digitalWrite(cyl1, state);
    digitalWrite(cyl2, state);
    digitalWrite(cyl3, state);
    digitalWrite(cyl4, state);
    }
}

void inject1()
{
  // find out how many uS 90 degrees camshaft is
  TimeFrame = (micros() - TimeOld);
  TimeOld = TimeFrame;
  Delay = InjectionDelay-ThrottleDuration;
  // open injector, hold it and close
  digitalWrite(inj1, HIGH);
  delayMicroseconds(ThrottleDuration);
  digitalWrite(inj1, LOW);
}

void inject2()
{
  TimeFrame = (micros() - TimeOld);
  TimeOld = TimeFrame;
  Delay = TimeFrame/18*17-ThrottleDuration;
  digitalWrite(inj2, HIGH);
  delayMicroseconds(ThrottleDuration);
  digitalWrite(inj2, LOW);
}

void inject3()
{
  TimeFrame = (micros() - TimeOld);
  TimeOld = TimeFrame;
  Delay = TimeFrame/18*17-ThrottleDuration;
  digitalWrite(inj3, HIGH);
  delayMicroseconds(ThrottleDuration);
  digitalWrite(inj3, LOW);
}

void inject4()
{
  TimeFrame = (micros() - TimeOld);
  TimeOld = TimeFrame;
  Delay = TimeFrame/18*17-ThrottleDuration;
  digitalWrite(inj4, HIGH);
  delayMicroseconds(ThrottleDuration);
  digitalWrite(inj4, LOW);
}

Thanks for the update. I have been looking around on the net for something like this, and this looks very good.
I have a Hobbysport tractor with a friend. A Same Panther with 6 cyl 6ltr engine and stock it has prf1k90.... pumps in it( each cyl its own 9mm pump).
And they can't be made bigger, only good thing about them is that they start with 700bar can go up to 1200bar of injection pressure.
A Inline would be the first chose for many. I think that Common rail could be "easyer" to build, mechanicly than.
Only the hardest part for now is to find injectors that could fit with the least modifycations.

I found the Cuprum befor the arduino, only my electronics knowledge isn't so good.
Are you using a alternator to replace a rotary encoder? bit like this link Simple Rotary Encoder

Hope to see more here.

Hello Panther,

In the past we drove with our electronics system with injectors from a John Deere 8.5 common rail but they are pretty big.
You could find some injector that fits and then change the nozzle to the desired flow or drill the holes to what you want.
In a common rail the holes aren't much smaller then in a conventional system and when using bosh you can also switch nozzles from conventional to CR and visa versa fine when choosing carefully.
Main problem is finding a pump that delivers enough.
I know that a stock 2.0hdi (as fitted on a PSA engine) Siemens pump can deliver up to 160cc without problems according to the specs. and we can "over" rpm the thing to get more juice, but above 5000 pump rpm it will die.

We have two machines based on a 2.0 engine:
On our current conventional Bosch A-pump we use 10mm. plungers at 160cc. and one P-pump with 12mm. plungers at 240cc. Both machines have a different setup, the 160 was meant to scale from lower to upper until pistons start melting and the other we started very high and work our way downwards until critical temps are reached.

I will post results of the project over here but first I have some other rebuilding stuff to do and will setup a test setup on my workbench to gather data about pump capacity/pressure related to injection time, nozzle size and injection duration.
After that some testing of the main program and IF working I will replace the line-pump...

Hello Japie,

I already thought those injectors where from a John Deere. I repair Same and Claas tractors, Claas use also JD. They won't fit my Same.
Next week I have some injectors to try. Have you drilled a nozzle your self? For this year I'm putting pumps from a "bigger" engine( still 9mm only with bit more delivery) and the nozzles need to be 0.295mm. So we talked about drilling them.
For you to look for a bigger pump would be hard I think, for me would be trucks a good source. Or maybe this could be an idea? http://www.albertazziracing.com/foto-foto1-2009.html
Fun to see some one else doing this, especially when he's doing better :smiley:

Panther95

Drilling nozzles is only good for creating porcupines.

Over here you can find a small list of bosch nozzles usable on a lot of different injectors, mechanical or electronic all exchangeable:

DSLA is the "dimension" type and the 145 is the spray angle, only thing not listed is the injector angle in the head so you have to see before you buy.
If you have some other model it is still possible they can be exchanged, find some nozzle reseller and try.

Truck pumps have the disadvantage for me that they can't handle high rpm's, the 2.0l engine is good for 9000rpm (even with convential mechanical pump) so that means 4500 for the pump, large pumps like on US Cummins diesel pick up trucks can only rev to 2500 or 3000 so they are off. (and heavy since our class may only weight 600kg including driver that is an issue)
For tiny use (up to 200cc) a pump from 3.0l automotive engine will do, for your goal a truck pump will probably do it's job.

When looking at the pics from the Italians I think they can use more juice, no idea what temps and air flow they have but I don't see enough smoke... :wink:

http://www.google.nl/url?sa=t&rct=j&q=&esrc=s&frm=1&source=web&cd=1&ved=0CC4QFjAA&url=http%3A%2F%2Fwww.merlindiesel.com%2Fmedia%2Fboschpumptestplans4web.pdf&ei=nkcEUcXaPKGb0QXsxYGYBg&usg=AFQjCNE1ovvayjAUBz0UuVOi2VzjTzt4OA

He Japie, found this link and if it doesn't work pm me for the pdf. It's a list of CR pumps by bosch number.
If you look for number 0445010046 wich is for a PSA RHY/RHS 2.0 HDi, it looks like it could pump up to 540cc at 1000rpm and 1000bar.

That is great documentation!

Thanks for sharing.

I do have a coding issue I think, since I am not a coder but a mechanic I used an interrupt to drive the injectors directly with timers attached.
I did got a (digital) beating for that and understand why, if a timer connected to an interrupt is still running when a second interrupt is triggered I have trouble right?
Is there a way to let an interrupt trigger a subroutine so it gets freed immediately and the routine keeps running? (like in bash $command &)

Is there a way to let an interrupt trigger a subroutine so it gets freed immediately and the routine keeps running? (like in bash $command &)

I'm not entirely sure what you're asking here, but with regard to running more than one process like a linux box, the arduino isn't going to do it - it's single core, single threaded. You can fake it to some extent (just like a single core linux box does) but you'll have to code it yourself, there is no operating system to help you manage separate threads.

@japie

Your code will most likely work better if you get rid of the delays.

 delayMicroseconds(ThrottleDuration);

You can used the "blink without delay" style with micros() just like you can with millis().

I guess you have a newer code to look at. Here you have an overlap on pin 4.

// setup timer pins for interrupts:
int cyl1 = 1;
int cyl2 = 2;
int cyl3 = 3;
int cyl4 = 4;
volatile int state = LOW;
// setup pins for injector drivers:
int inj1 = 4;
int inj2 = 5;
int inj3 = 6;
int inj4 = 7;