Pid control levitating ball in tube

Hi, is there anybody who have skills in pid on arduino? I’ve a project and my pid not working and i have no idea why can you help me someone please?

Post your code, a few images of your project and the code in code tags. Also, describe what you want it to do and what its doing instead.

Start by posting your best effort sketch and describe what is not working. Details of the project hardware will also be needed in order to provide help


This is my hardware the potentiometer to control a setpoint (height of pingpong ball in tube) and the pingpong ball should be stably at this height. Under my co struction is ventilator 12V 1,5A . On the top of tube is Ultrasound sensor

@Idahowalker @UKHeliBob and there is a code:

  #include<PID_v1.h>
  #include <Wire.h> 
  #include <LiquidCrystal_I2C.h>
 
LiquidCrystal_I2C lcd(0x27, 16, 2);

#define Vent 9

  double Setpoint;   //požadovaná vzdálenost
  double Input;     // uz čidlo
  double Output;    // ventilátor

int setPoint;
int Distance;
  //konstanty PID

  double Kp=4.5;
  double Ki=0.0005;
  double Kd=0;
  
//SENZOR
  #define EchoPin 12
  #define TrigPin 13
  

PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

void setup() {
  
    // Timer1 nastavení pro 25KHz
  TCCR1A = 0; // undo the configuration done by...
  TCCR1B = 0; // ...the Arduino core library
  TCNT1 = 0; // reset timer
  TCCR1A = _BV(COM1A1) // non-inverted PWM on ch. A
           | _BV(COM1B1) // same on ch; B
           | _BV(WGM11); // mode 10: ph. correct PWM, TOP = ICR1
  TCCR1B = _BV(WGM13) // ditto
           | _BV(CS10); // prescaler = 1
  ICR1 = 320; // TOP = 320
  
  // Set the PWM pins as output.
  
  pinMode( Vent, OUTPUT);
  
 Serial.begin(9600);

  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(0, 320);
  myPID.SetTunings(Kp, Kd, Ki);
 myPID.SetSampleTime(100);

 ///////////////LCD////////////////////////////////////////////
  lcd.init();                      // initialize the lcd 
  lcd.init();
  
  lcd.backlight();
  

}

void loop() {
  
 
  lcd.setCursor(0,0);
  lcd.print("Setpoint:");
  lcd.print(setPoint);
  lcd.print("cm");
    

  
 Setpoint = map(analogRead(A0), 0, 1023, 5, 45);
 setPoint = Setpoint;
   
    
 Input = readPosition();
  myPID.Compute();  
 
  analogWrite25k(Vent,Output);

Serial.print("disatnce:  ");
Serial.println(Input);

  /*
  Serial.print("Input:  ");
 Serial.print(Input);
 Serial.print(" ");
  Serial.print("Output:  ");
 Serial.println(Output);
 Serial.print(" ");
 Serial.print("Setpoint:  ");
 Serial.print(Setpoint);
 Serial.print("  ");
 */
}


void analogWrite25k(int pin, int value)
{
  switch (pin)
  {
    case 9:
      OCR1A = value;
      break;
      
    case 10:
      OCR1B = value;
      break;
      
    default: // no other pin will work
      break;
 
  }
}

int readPosition() {
  delay(40);
  
 long Duration; // variable for the duration of sound wave travel
  double Distance; // variable for the distance measurement
  
  pinMode(TrigPin, OUTPUT);
  pinMode(EchoPin, INPUT);

  
//SENZOR
  // Clears the trigPin condition
  digitalWrite(TrigPin, LOW);
  delayMicroseconds(2);
  // Sets the trigPin HIGH (ACTIVE) for 10 microseconds
  digitalWrite(TrigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(TrigPin, LOW);
  // Reads the echoPin, returns the sound wave travel time in microseconds
  Duration = pulseIn(EchoPin, HIGH);
delay(10);

  // Výpočet vzdálenosti
  Distance = Duration * 0.034 / 2; // rychlost zvukové vlny /2 tam a zpět
int distance = Distance;

  
  
  lcd.setCursor(0,1);
  lcd.print("Distance:");
  lcd.print(distance); 
  lcd.print("cm");


return Distance;
}

but the ball just goes all the way up to the sensor and then falls down and immediately up again and stays there.

DIRECT means higher Output causes a higher Input but since your fan is facing up and your distance sensor is facing down, a higher Output will push the ball higher, leading to a LOWER distance. I think you want "REVERSE" in place of "DIRECT". Then the PID will know to reduce the fan speed to get a greater distance from the top.

You should specify a timeout so you don't have to wait for the default 1000000 microseconds if no echo is detected.

Duration = pulseIn(EchoPin, HIGH, 6000);

You should also filter out the Distance = 0 you will get if a timeout occurs.

1 Like

i tried and still now working i think it will be another problem but ive no idea where is the problem :frowning:

Are you sure you are getting plausible readings from the sensor used to determine the ball position?

Test it with a simple program independent of all the PID stuff. Make sure the input to the PID algorithm is not the problem.

a7

This. You may be getting spurious readings because the tube looks pretty narrow and I'd expect reflections.

1 Like

readings is ok i write it on lcd and distance is about 47 cm max and this is correct because tube is 50cm.

What do you get if you manually push it up the tube near the top? In fact it would be interesting to see a range of readings as you raise it.

1 Like

I’ve about 3cm on top of tube. Distance measure is ok.

1 Like

Maybe your PID coeffcients need tuning - how did you choose them.

PID can be tricky to get right, I'd see what you can get just reading the pot and controlling the fan with a simpler algorithm (too low, increase fan; too high, decrease).

I choose them experimentally

Maybe the problem is that when i write the code for the smallest rpm of fan the ball still go to the top of the tube. But i’m looking and people used more powerfull fans so idk.

Put some holes in the tube near the bottom to leak pressure. Or use a wider tube to let more air leak past the ball.

First I'd try to see if how touchy it is. Try bypassing the PID and control directly with your potentiometer:

If you can find a pwm level that's close, maybe it's just tuning, and you'd adjust these:

Uncomment the Serial.print stuff diagnostics, set Ki to zero, cut Kp from in half and post the results, and report what happens.

Maybe Kp should be about 320counts/45cm=8?

I have already tried this option and unfortunately even with potentiometer = 0 or higher, the ball always went to the top.

I put holes to the construction the tube was expensive.

Then the tube is too small or the ball is too big.