rebos
Published © GPL3+

Air/Fuel controller for LPG engines

Control the air/fuel mixture for a better fuel economy of a engine with a Arduino Nano.

IntermediateShowcase (no instructions)20 hours315
Air/Fuel controller for LPG engines

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
bosch stationairy valve
×1
lambdasonde
×1
air/fuel ratio gauge
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Schematics

O2 valve experiment

Code

O2_valve_in_car_6_public.ino

Arduino
// o2 valve experiment by R.Bos 30-6-2024
//
 #include <GyverPWM.h>


 const int pwm1 = 9;//5;//pwm output to open valve
 const int pwm2 = 10;//6;//pwm output to close valve
 const int pot1  = A2;//potmeter 0V---1V
 const int sensor = A0;//O2 sensor
 const int hall_1 = 2;//hall sensor for rpm
 const int ledPin = A5;//LED_BUILTIN;
 const int dpswitch = 7;
 const int offswitch = 8;//A4;
 const int meter = 11;
 const int rly = 12;
 int valpot = 0;int valpotold = 0;int valpot1 = 0;
 int prcold = 0; int diff = 0;
 int prc = 0;
 int valve1 = 0 ;int valve2 = 64;
 int i; int sft = 0;//shift O2 to lower side 
 int wait = 0;
 unsigned long timeoff;
 unsigned long timeoffold;
 unsigned long timeloop;
 unsigned long timeloopold;
 unsigned long print1time;
////////// for rpmcounter /////////////////////
 unsigned long rpm = 0;
 unsigned long revtime = 0;
 unsigned long revtimeold = 0;
 volatile unsigned long pulses = 0;
 volatile unsigned long rpm1 = 0;
 unsigned int pulses1 = 0;
 unsigned int d1 = 16;// number of pulses before time taken (timerpm)
 float revtime1 = 0;//if d1 = 16 , time is for 4 revolutions
///////////// for o2 ////////////////////////////////
 unsigned long O2;
 int mV10[11];// 10*50mS = 500mS
 int mV200[21];//20*500mS = 10 sec
 unsigned long mV1;
 unsigned long mV2;
 unsigned long mV1ava;
 unsigned long mV2ava;
 unsigned long mV1old;
 unsigned long mV2old;
 int bb = 0; int bbb = 0;
 int Vin = 5000;//4800mV supply voltage , needed for reference , normal 5000mV , laptop only 4740mV
 unsigned long waittime;
//////////////// for switch and led ///////////////////////////////////////////////
 int ledState = LOW;
 unsigned long blinktime;
 int interval = 1500;
 int ll; int dp = 1;int dpx;
 int dpoff = 1;
 unsigned long valout;
 int valin;
////////////////////////////////////////////////////////////////////////////////// 

void setup()//////////////////////////////////////////////////////////////////////
{   
  Serial.begin(9600);
  pinMode(pwm1,OUTPUT);
  pinMode(pwm2,OUTPUT);
  pinMode(hall_1,INPUT);
  pinMode(ledPin,OUTPUT);
  pinMode(dpswitch,INPUT_PULLUP);
  pinMode(offswitch,INPUT_PULLUP);
  pinMode(meter,OUTPUT);
  pinMode(rly,OUTPUT);
  pinMode(pot1,INPUT_PULLUP);
  attachInterrupt(0, rpmcounter, FALLING);
  timeloop = millis();
  PWM_frequency(9, 8000, FAST_PWM);
  PWM_frequency(10, 8000, FAST_PWM);
  PWM_set(pwm1,0);
  PWM_set(pwm2,64);
  digitalWrite(rly,1);
  //analogWrite(pwm1,0); analogWrite(pwm2,64);

}

void print1()///////////////////////////////////////////////////////////////////
////////for coding and debugging only///////////////////////////////////////////
{
  //mV =(( O2 * 473) / 1024) * 10;
  //mV =( O2 * 4730) / 1024);
  if(millis() - print1time >= 500){
  //Serial.print("mV1 =");Serial.print(mV1);
  //Serial.print("     mV2 =");Serial.println(mV2);
  Serial.print("rpm =   ");Serial.println(rpm);
  //Serial.print("             revtime =");Serial.println(revtime);
  //Serial.print("     waittime =");Serial.println(waittime);
  //Serial.print("valin =");Serial.print(valin);
  //Serial.print("              valout =");Serial.println(valout);
  //Serial.print("dp =");Serial.println(dp);
  //Serial.print("prc =");Serial.print(prc);
  //Serial.print("millivolt =");Serial.println(mV);
  //Serial.print("valve1 = ");Serial.print(valve1);
  //Serial.print("      valve2 = ");Serial.println(valve2);
  //Serial.print("timeloopold =");Serial.println(timeloopold);
  //Serial.print("revtime =");Serial.println(revtime);
  print1time = millis(); 
  }
 }

void loop()/////////////////////////////////////////////////////////////////////
{
  rpm = rpm1; revtime = revtime1;// / (d1 / 16);// reactiontime is 4*4 pulses = 4 cycles
  if(rpm == 0 ){revtime = 400;}
  if(revtime < 100){revtime = 100;}//without Rpm input could be set at a fixed timing between 100 and 400ms
  getO2valu();
  //waittimeold = millis() - waittime;
  if(millis() - waittime >= revtime){
    if(rpm < 750){stationair();} else {
    if(mV2 > 520){sft = 30;} else {
    if(mV2 < 490){sft =  0;}}  
    if(mV1 > 500){rich3();}
    if(mV1 < 500){lean3();}}
    mV1old = mV1; mV2old = mV2;}  
  //valpot = analogRead(pot1);
  //prc = map(valpot,0,202,0,100);
  if(digitalRead(offswitch) == 0 || dpoff == 0){digitalWrite(rly,0);if(prcold != 0){prc = prc - 30;} else {prc = 0;}}
  if(digitalRead(offswitch) != 0 || dpoff == 1){digitalWrite(rly,1);}
  if(rpm < 400){if(prcold != 0){prc = prc - 30;} else {prc = 0;}} 
  prc = constrain(prc,0,100);
  if(prc < prcold){diff = prcold - prc; valveclose();waittime = millis();}
  if(prc > prcold){diff = prc - prcold;  valveopen();waittime = millis();}
  if(valve2 < 195 && valve1 < 195){wait = 0;timeoff = 0;} else{valveoff();}
  Select2();
  //if(dp == 1){valout = map(valin,0,234,0,285) ;}
  if(dp == 1){valout = (valin * 5) / 4 ;}               //input O2 sensor = output
  if(dp == 2){valout = (((mV1 * 1024) / Vin) * 5 ) / 4;}//shortterm average output
  if(dp == 3){valout = (((mV2 * 1024) / Vin) * 5 ) / 4;}//longterm average output
  if(dp == 4){valout = map(prc,0,100,13,255);}          //valve position output
  valout = constrain(valout,0,255);analogWrite(meter,valout);//gauge output only
  //print1();//coding and debugging only , it will disturb ISR of hall sensor input
  led1();
  timeloopold = millis() - timeloop;
  if(timeloopold < 50){delay(50 - timeloopold);}//looptime fixed at 50ms
  timeloop = millis();
  
}
void rich3()/////////////////////////////////////////////////////////////////////
{
  if(mV1 < mV1old && mV1 >= 600){prc = prc - 5;} else {
  if(mV1 < mV1old && mV1 <  600){prc = prc - 1;} else {  
  if(mV1 > 550 - sft){prcmin();prc = prc + 1;}
  if(mV1 > 600 - sft){prc = prc + 1;}
  if(mV1 > 650 - sft){prc = prc + 1;}
  if(mV1 > 700 - sft){prc = prc + 2;}
  if(mV1 > 750 - sft){prc = prc + 3;}}}
  if(mV2 < mV2old && mV2 >= 600){prc = prc - 2;} else {
  if(mV2 > 550){prc = prc + 1;}
  if(mV2 > 600){prc = prc + 1;}
  if(mV2 > 650){prc = prc + 1;}
  if(mV2 > 700){prc = prc + 2;}
  if(mV2 > 750){prc = prc + 3;}}
}
void lean3()/////////////////////////////////////////////////////////////////////
{
  //if(mV1 > mV1old && mV1 > 300){prc = prc + 1;} else {
  if(mV1 < 450){prcmax();prc = prc - 1;}
  if(mV1 < 400){prc = prc - 1;} //-1
  if(mV1 < 350){prc = prc - 2;} //-1
  if(mV1 < 300){prc = prc - 3;} //-2
  if(mV1 < 250){prc = prc - 8;} //-3
  if(mV1 < 200){prc = prc = 0;}
  //if(mV2 < 450){prc = prc - 1;} //-1
  if(mV2 < 400){prc = prc - 2;} //-1
  if(mV2 < 350){prc = prc - 2;} //-1
  if(mV2 < 300){prc = prc - 2;} //-2
  if(mV2 < 250){prc = prc - 3;} //-3
  if(mV2 < 200){prc = prc = 0;}
}
void prcmax()////////////////////////////////////////////////////////////////////
{
  if(prcold==100){if(rpm >= 2500){prc = 40;}              else{
                  if(rpm >= 1500 && rpm < 2500){prc = 50;}else{
                  if(rpm  < 1500){prc = 60;}}}}
}  
void prcmin()//////////////////////////////////////////////////////////////////////
{
  if(prcold == 0){if(rpm >= 2500){prc = 40;}              else{
                  if(rpm >= 1500 && rpm < 2500){prc = 30;}else{
                  if(rpm  < 1500){prc = 20;}}}} 
}
void stationair()//////////////////////////////////////////////////////////////////
{
  if(mV1 > 800){prcmin();prc = prc + 1;}
  //if(mV1 > 750){prc = prc + 2;}
  //if(mV1 > 800){prc = prc + 3;}
  if(mV1 > 850){prc = prc + 2;}
  //if(mV2 > 700){prc = prc + 2;}
  //if(mV2 > 750){prc = prc + 2;}
  if(mV2 > 800){prc = prc + 1;}
  if(mV2 > 850){prc = prc + 2;} else{
    if(mV1 < 750){prcmax();prc = prc - 2;}
    if(mV1 < 700){prc = prc - 2;} 
    if(mV1 < 650){prc = prc - 10;} 
    //if(mV1 < 600){prc = prc - 4;}
    if(mV2 < 750){prc = prc - 2;}
    if(mV2 < 700){prc = prc - 2;}
    if(mV2 < 650){prc = 0;}
    //if(mV2 < 600){prc = prc - 4;}  
  }
  if(prc > 60){prc = 60;}
  
}

void getO2valu()////////////////////////////////////////////////////////////////
{
  O2 = analogRead(sensor); valpot = O2; valin = O2; O2 = ( O2 * Vin) / 1024;
  //O2 = map(O2,0,1024,0,Vin);
  bb++; 
  mV1ava =(mV1ava + O2) - mV10[bb];
  mV1 = mV1ava / 10; //
  mV10[bb] = O2;
  if(bb >= 10){bb = 0;bbb++;
  mV2ava =(mV2ava + mV1) - mV200[bbb];
  mV2 = mV2ava / 20;
  mV200[bbb] = mV1;
  if(bbb >= 20){bbb = 0;}
  }
}

void valveclose()//////////////////////////////////////////////////////////////
{
  for(i = 0; i < (diff + 1);i++)
  {valve1 = map(prcold,0,100,60,195);valve1 = constrain(valve1,0,255);
   valve2 = map(prcold,0,100,195,60);valve2 = constrain(valve2,0,255);
   PWM_set(pwm1,valve1);PWM_set(pwm2,valve2);
   //analogWrite(pwm2,valve2);analogWrite(pwm1,valve1);
   prcold--;}
   //delay(1);}
   prcold = prc;
}
void valveopen()///////////////////////////////////////////////////////////////
{
  for(i = 0; i < (diff + 1);i++)
  {valve1 = map(prcold,0,100,60,195);valve1 = constrain(valve1,0,255);
   valve2 = map(prcold,0,100,195,60);valve2 = constrain(valve2,0,255);
   PWM_set(pwm1,valve1);PWM_set(pwm2,valve2);
   //analogWrite(pwm1,valve1); analogWrite(pwm2,valve2);
   prcold++;}
   //delay(1);}
   prcold = prc;
}   
void valveoff()////////////////////////////////////////////////////////
{
  if(valve2 == 195 && wait == 0){timeoffold = millis();wait = 1;}
  if(valve2 == 195 && timeoff >= 1000){wait = 0;timeoff = 0;
  valve1 = 0;valve2 = 64;
  PWM_set(pwm1,valve1);PWM_set(pwm2,valve2);}
  //analogWrite(pwm1,valve1); delay(3);analogWrite(pwm2,valve2);}//valve close
  if(valve1 == 195 && wait == 0){timeoffold = millis();wait = 1;}
  if(valve1 == 195 && timeoff >= 1000){wait = 0;timeoff = 0;
  valve1 = 64;valve2 = 0;
  PWM_set(pwm1,valve1);PWM_set(pwm2,valve2);}
  //analogWrite(pwm2,valve2); delay(3);analogWrite(pwm1,valve1);}//valve open
  if(wait == 1){timeoff = millis() - timeoffold;}
  
}
void rpmcounter()//////////////////////////////////////////////////////
{
  pulses++;
  if(pulses >= d1){
  revtime1 = (millis() - revtimeold);
  revtimeold = millis();
  //pulses1 = pulses;
  pulses = 0;
  rpm1 = (1000.0/revtime1)*60.0;
  rpm1 = rpm1 * (d1/4);
  //d1time();
  }
}
void d1time()/////////////////////////////////
//not used in this code , was to stabilize rpm output on oled display
{
  if(rpm1 <   400){d1 = 16;}
  if(rpm1 >=  400){d1 = 16;}
  if(rpm1 >= 1000){d1 = 32;}
  if(rpm1 >= 2000){d1 = 48;}
  if(rpm1 >= 3000){d1 = 64;}
}
void Select()////////////////////////////////////////////////////////// 
{
  if(digitalRead(dpswitch) == 0 && dpx >= 1){delay(10);dpx = 2;}
  if(digitalRead(dpswitch) == 0 && dpx == 0){delay(10);
    dp++; dpx++;
  if(dp > 4){dp = 1;}   
}
  if(digitalRead(dpswitch) != 0 && dpx != 0){
    dpx = 0;} 
}
void Select2()/////////////////////////////////////////////////////////
{
  valpot = analogRead(pot1);  
  if (valpot < 99) {                  // groud 0 ohm  
    dp = 1; dpoff = 1;
  }
  if (valpot > 110 && valpot < 150) { // resistor 4K7 = 130 
    dp = 2; dpoff = 1;
  }
  if (valpot > 320 && valpot < 360) {  // resistor 18K = 340    
    dp = 3; dpoff = 1;
  }
  if (valpot > 545 && valpot < 585) {  // resistor 47K = 565    
    dp = 4; dpoff = 1;
  }
  if (valpot > 715 && valpot < 755) {  // resistor 100K = 735    
    dp = 4; dpoff = 0;
  }
  if (valpot > 995) {                  // open , pullup only = 1015 
    dp = 1; dpoff = 0;
  }
} 
void led1()////////////////////////////////////////////////////////////
{
  if(dpoff == 0){digitalWrite(ledPin,0);} else {
  if(millis() - blinktime >= interval){blinktime = millis();
    if(ledState == LOW){ledState = HIGH; interval = 150;} else{
      ledState = LOW; interval = 300;ll++;}
      digitalWrite(ledPin,ledState);}
  if(ll >= dp){ll = 0;interval = 2000;}}  
  
}

Credits

rebos

rebos

1 project • 1 follower

Comments