PID controller that’s able to calibrate tire pressure

Hello guys. I got a project for an automatic tire inflator using an MPX5010 pressure sensor and two ON/OFF solenoid valves, one for inflating and the other for deflating. At first, I tried to manually set times for the valves to stay open based on ranges of difference between the desired pressure and the sensor read like this

void calibrateAutoInflate() {
//read the tire pressure
  sensorValue = (analogRead(A0) * ADC_mV - SensorOffset) / sensitivity / kPa_psi;

//prints tire pressure
   lcd.clear();
   lcd.setCursor(0, 0);
   lcd.print("TIRE");
   lcd.setCursor(7, 1);
   lcd.print("PSI:");
   lcd.setCursor(12, 1);
   lcd.print(sensorValue);

//compare the tire pressure with the desired pressure
  if ((confPsi - sensorValue) < 1)
  {
    digitalWrite(13, HIGH); 
    delay(400);            
    digitalWrite(13, LOW);  
    delay(1000);
  }
  else if (((confPsi - sensorValue) > 1) && ((confPsi - sensorValue) < 2))
  {
    digitalWrite(13, HIGH); 
    delay(560);            
    digitalWrite(13, LOW);  
    delay(1000);
  }
  else if (((confPsi - sensorValue) >= 2) && ((confPsi - sensorValue) <= 3))
  {
    digitalWrite(13, HIGH); 
    delay(784);            
    digitalWrite(13, LOW);  
    delay(1000);
  }
  else if (((confPsi - sensorValue) > 3) && ((confPsi - sensorValue) <= 4))
  {
    digitalWrite(13, HIGH); 
    delay(1097);            
    digitalWrite(13, LOW);  
    delay(1000);
  }
    else if (((confPsi - sensorValue) > 4) && ((confPsi - sensorValue) <= 5))
  {
    digitalWrite(13, HIGH); 
    delay(1536);            
    digitalWrite(13, LOW);  
    delay(1000);
  }
   else if (((confPsi - sensorValue) > 5) && ((confPsi - sensorValue) <= 6))
  {
    digitalWrite(13, HIGH); 
    delay(2151);            
    digitalWrite(13, LOW); 
    delay(1000);
  }
   else if (((confPsi - sensorValue) > 6) && ((confPsi - sensorValue) <= 7))
  {
    digitalWrite(13, HIGH); 
    delay(3000);            
    digitalWrite(13, LOW);  
    delay(1000);
  }
   else if (((confPsi - sensorValue) > 7) && ((confPsi - sensorValue) <= 10))
  {
    digitalWrite(13, HIGH); 
    delay(3000);            
    digitalWrite(13, LOW);  
    delay(1000);
  }
   else if ((confPsi - sensorValue) > 10)
  {
    digitalWrite(13, HIGH); 
    delay(3000);            
    digitalWrite(13, LOW);  
    delay(1000);
  }
}

Whoever, using this method the device works correctly with just one type of tire, so it doesn't work for cars and motorcycles at the same, since motorcycle tire needs less air volume in order to reach the desired pressure. Based on my searches on the web, I guess that a PID (Proportional-Integral-Derivative) would be more suitable for this project, but I can’t realize how to make the PID output the time needed for the solenoids to be open, since the pressure sensor can’t read while solenoids are open and it also needs around 2.5 seconds to stabilize the reading. Could you guys help me to find a solution, please?

If I lower the times in this code above, it takes way too long to calibrate car tires but calibrates motorcycle tires well.

PID generally requires a constant timing interval during the loop. But PID is not necessary for your project.

What you need to do is to make sure that pressure measurement is stable before making a decision whether to continue pumping, and stop when you get the desired value. If that requires pumping in short bursts, live with that.

1 Like

Don't forget temperature sensors! The right tire pressure is very dependent on temperature.

I'd consider a process of:

  1. Measure the pressure
  2. Add a few seconds of ON
  3. Measure the pressure
  4. Estimate the volume of the tire from the two pressures and the added volume, and estimate the required additional air time.
  5. Add more ON & repeat from 3

Can You draw a little picture showing the schematics of the air system? Air supply, valve, pressure and tube?

Suppose You have an air flow limiter between the valve and the pressure measuring, and the tube? That ought to give some reading during filling. Okej some more filling time will be needed.

I guess it could be some kind of code that starts the process by checking if the tire is "big" or "small" by opening one of the valves for 0.5 seconds and then seeing what it does to the tire pressure, if it does a big change in pressure, use slow inflation (more suitable for small tires) else if it does a small change, use faster inflation (more suitable for larger tires). By the way, here is the full code without changes yet.

#include <LiquidCrystal.h>

const float ADC_mV = 4.8828125;       // convesion multiplier from Arduino ADC value to voltage in mV
const float SensorOffset = 200.0;     // in mV taken from datasheet
const float sensitivity = 4.5;      // in mV/kPa taken from datasheet
const float kPa_psi = 6.895;         
//Define display pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
float confPsi = 32;

void setup()
{
  wdt_enable(WDTO_8S);
  lcd.begin(16, 2);
  pinMode(6, INPUT_PULLUP ); //button mode
  pinMode(7, INPUT_PULLUP); //button -
  pinMode(10, INPUT_PULLUP); //button +
  pinMode(13, OUTPUT); //inflate solenoid
  pinMode(8, OUTPUT); //deflate solenoid
  pinMode(9, OUTPUT); //buzzer
}

//create the sensor read variable
float sensorValue = (analogRead(A0) * ADC_mV - SensorOffset) / sensitivity / kPa_psi;

//crate a a function to inflate
void calibrateAutoInflate() {
  //read pressure sensor
  sensorValue = (analogRead(A0) * ADC_mV - SensorOffset) / sensitivity / kPa_psi;

//prints tire pressure
   lcd.clear();
   lcd.setCursor(0, 0);
   lcd.print("TIRE");
   lcd.setCursor(7, 1);
   lcd.print("PSI:");
   lcd.setCursor(12, 1);
   lcd.print(sensorValue);

//compare the tire pressure with the desired pressure
  if ((confPsi - sensorValue) < 1)
  {
    digitalWrite(13, HIGH); 
    delay(200);            
    digitalWrite(13, LOW);  
    delay(1000);
  }
  else if (((confPsi - sensorValue) > 1) && ((confPsi - sensorValue) < 4))
  {
    digitalWrite(13, HIGH); 
    delay(300);            
    digitalWrite(13, LOW);  
    delay(1000);
  }
  else if (((confPsi - sensorValue) >= 4) && ((confPsi - sensorValue) <= 6))
  {
    digitalWrite(13, HIGH);
    delay(400);            
    digitalWrite(13, LOW);  
    delay(1000);
  }
  else if (((confPsi - sensorValue) > 6) && ((confPsi - sensorValue) <= 8))
  {
    digitalWrite(13, HIGH); 
    delay(600);            
    digitalWrite(13, LOW);  
    delay(1000);
  }
    else if (((confPsi - sensorValue) > 8) && ((confPsi - sensorValue) <= 10))
  {
    digitalWrite(13, HIGH); 
    delay(700);            
    digitalWrite(13, LOW);  
    delay(1000);
  }
   else if (((confPsi - sensorValue) > 10) && ((confPsi - sensorValue) <= 12))
  {
    digitalWrite(13, HIGH); 
    delay(800);           
    digitalWrite(13, LOW);  
    delay(1000);
  }
   else if (((confPsi - sensorValue) > 12) && ((confPsi - sensorValue) <= 14))
  {
    digitalWrite(13, HIGH); 
    delay(1200);            
    digitalWrite(13, LOW);  
    delay(1000);
  }
   else if (((confPsi - sensorValue) > 14) && ((confPsi - sensorValue) <= 16))
  {
    digitalWrite(13, HIGH); 
    delay(1400);            
    digitalWrite(13, LOW);  
    delay(1000);
  }
   else if (((confPsi - sensorValue) > 16) && ((confPsi - sensorValue) <= 18))
  {
    digitalWrite(13, HIGH); 
    delay(1500);            
    digitalWrite(13, LOW);  
    delay(1000);
  }
   else if ((confPsi - sensorValue) > 18)
  {
    digitalWrite(13, HIGH); 
    delay(2500);            
    digitalWrite(13, LOW);  
    delay(1000);
  }
}

//create a function to deflate
void calibrateAutoDeflate() {

  //read tire pressure
  sensorValue = (analogRead(A0) * ADC_mV - SensorOffset) / sensitivity / kPa_psi;

  //print tire pressure
   lcd.clear();
   lcd.setCursor(0, 0);
   lcd.print("TIRE");
   lcd.setCursor(7, 1);
   lcd.print("PSI:");
   lcd.setCursor(12, 1);
   lcd.print(sensorValue);

  //compare the tire pressure with the desired pressure
  if ((sensorValue - confPsi) < 1)
  {
    digitalWrite(8, HIGH); 
    delay(200);           
    digitalWrite(8, LOW);  
    delay(1000);
  }
  else if (((sensorValue - confPsi) > (1)) && ((sensorValue - confPsi) < (2)))
  {
    digitalWrite(8, HIGH); 
    delay(300);            
    digitalWrite(8, LOW);  
    delay(1000);
  }
  else if (((sensorValue - confPsi) > (2)) && ((sensorValue - confPsi) < (3)))
  {
    digitalWrite(8, HIGH); 
    delay(400);            
    digitalWrite(8, LOW);  
    delay(1000);
  }
  else if (((sensorValue - confPsi) > (3)) && ((sensorValue - confPsi) < (4)))
  {
    digitalWrite(8, HIGH); 
    delay(500);            
    digitalWrite(8, LOW);  
    delay(1000);
  }
  else if (((sensorValue - confPsi) > (4)) && ((sensorValue - confPsi) < (5)))
  {
    digitalWrite(8, HIGH); 
    delay(600);            
    digitalWrite(8, LOW);  
    delay(1000);
  }
  else if (((sensorValue - confPsi) > (5)) && ((sensorValue - confPsi) < (6)))
  {
    digitalWrite(8, HIGH); 
    delay(700);            
    digitalWrite(8, LOW);  
    delay(1000);
  }
  else if (((sensorValue - confPsi) > (6)) && ((sensorValue - confPsi) < (7)))
  {
    digitalWrite(8, HIGH); 
    delay(800);            
    digitalWrite(8, LOW);  
    delay(1000);
  }
  else if (((sensorValue - confPsi) > (7)) && ((sensorValue - confPsi) < (8)))
  {
    digitalWrite(8, HIGH);
    delay(1000);           
    digitalWrite(8, LOW);  
    delay(1000);
  }
  else if (((sensorValue - confPsi) > (8)) && ((sensorValue - confPsi) < (9)))
  {
    digitalWrite(8, HIGH); 
    delay(1500);            
    digitalWrite(8, LOW);  
    delay(1000);
  }
  else if (((sensorValue - confPsi) > (9)) && ((sensorValue - confPsi) < (10)))
  {
    digitalWrite(8, HIGH); 
    delay(2000);            
    digitalWrite(8, LOW);  
    delay(1000);
  }

  else if ((sensorValue - confPsi) > 10)
  {
    digitalWrite(8, HIGH); 
    delay(2500);            
    digitalWrite(8, LOW);  
    delay(1000);
  }
}

//set a mode for empty tire. Works only if a button is pressed.
void emptyMode() {
  
    //read and print tire pressure
    sensorValue = (analogRead(A0) * ADC_mV - SensorOffset) / sensitivity / kPa_psi;
    
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("EMPTY");
    lcd.setCursor(7, 1);
    lcd.print("PSI:");
    lcd.setCursor(12, 1);
    lcd.print(sensorValue);
    delay(3000);
    
    wdt_reset();
    
    digitalWrite(13, HIGH);
    delay(7000);  
    digitalWrite(13, LOW);
    delay(500);
  } //returns to auto mode


void loop() {
  wdt_reset();

  //read the buttons
bool vazio = digitalRead(6);
bool minus = digitalRead(7);
bool plus = digitalRead(10);

//print desired PSI
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("AUTO");
    lcd.setCursor(6, 1);
    lcd.print("PSI:");
    lcd.setCursor(11, 1);
    lcd.print(confPsi);

//Analyse buttons information
  if (digitalRead(6) == 0){
    emptyMode();
  }
    
  if ((plus == 0) and (confPsi < 70)) {
    //change desired PSI
    ++confPsi;
    //sonorous feedback
    digitalWrite(9, HIGH);
    delay(200);
    digitalWrite(9, LOW);
  }
  else if ((minus == 0) and (confPsi > 5.0)) {
    //change desired PSI
    --confPsi;
    //sonorous feedback
    digitalWrite(9, HIGH);
    delay(200);
    digitalWrite(9, LOW);
  }
  //reset sensorValue
  sensorValue = 0;
  //read sensorValue just to detect a tire
  sensorValue = (analogRead(A0) * ADC_mV - SensorOffset) / sensitivity / kPa_psi;

  //see if a tire is conected
  if (sensorValue > 3) { 
    delay(3000); //delay the reading in order to make sure its already stable
    sensorValue = (analogRead(A0) * ADC_mV - SensorOffset) / sensitivity / kPa_psi;
  }

//for when the tire is on the desired pressure
  if (((sensorValue) >= (confPsi - 0.7)) and ((sensorValue) <= (confPsi + 0.7)))
  {
    digitalWrite(9, HIGH);
    delay(500);
    digitalWrite(9, LOW);
    delay(500);
    digitalWrite(9, HIGH);
    delay(500);
    digitalWrite(9, LOW);
    delay(500);
    digitalWrite(9, HIGH);
    delay(500);
    digitalWrite(9, LOW);
    delay(2000);
  }

//runs the inflation process
  else if (((sensorValue) > (3.0)) and ((sensorValue) < (confPsi)))
  {
    calibrateAutoInflate();
  }

//runs the deflation process
  else if (((sensorValue) > (3.0)) and ((sensorValue) > (confPsi)))
  {
    calibrateAutoDeflate();
  }
  delay(20);
}
1 Like

Yes, That's how you'd do it by hand.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.