Arduino pid control system of aerodynamic levitation

Hello, i’ve a problem with pid control my aerodynamic levitation system. If i try to set pid regulator the molitan ball which i use to levitate just go up and aftergo down because my fan
just turn off, but i do not know what i’m doing wrong.
I use pid library by Bread Bearegard.

My constants are: kp = 6.43, ki = 0.0042 and kd is 0 .

Please help the helpers by reading and following the instructions in the "How to get the best out of this forum" post, linked at the head of every forum category.

1 Like

How do you determine the ball position?

A PID is not a solution by itself. You have to adjust the parameters until it works.

I'd start with a steady position and kp only, determine an offset for several stable ball positions. Then gently push the ball up and down and adjust ki and kd.

1 Like

For position i have Hcsr04 ultrasonic sensor. I tried the method what u advise, but it not work..

Check the output you get from the ultrasonic sensor is giving you a changing signal proportional to height .
Post a schematic and your code , maybe a picture of the setup .

The Output from sensor is ok.
The code is:

#include<PID_v1.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

#define Vent 9



char Data;
String serialData;
String serialData_D;


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

int setPoint;
double Distance;

//konstanty PID

double Kp = 50;
double Ki = 100000;
double Kd = 0;

//SENZOR

#define EchoPin 12
#define TrigPin 13

unsigned long start_Time;
unsigned long int count;
unsigned long int RPM;

unsigned long strTime;


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);
  pinMode(TrigPin, OUTPUT);
  pinMode(EchoPin, INPUT);

  Serial.begin(9600);

  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(160, 320);
  myPID.SetTunings(Kp, Ki, Kd);
  myPID.SetSampleTime(1000);


  Input = Distance;

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

  lcd.backlight();

  attachInterrupt(digitalPinToInterrupt(2), RPM_fun, RISING);

}

void loop() {

  /*
    ///////////////////SERIOVÁ KOMUNIKACE////////////////////////////
    Receive_Serial_Data();



    Setpoint = serialData.toDouble();
    Serial.print("setpoint= ");
    Serial.println(serialData);
    delay(750);
  */













  ///////////////////SENZOR HCSR04/////////////////////////////////////////////////


  long Duration; // doba trvání zvukové vlny

  double Distance; // vzdálenost


  //SENZOR
  // vyčistí trigger pin
  digitalWrite(TrigPin, LOW);
  delayMicroseconds(2);

  digitalWrite(TrigPin, HIGH);
  delayMicroseconds(10);

  digitalWrite(TrigPin, LOW);


  //unsigned long Duration_prum = 0;
  //unsigned long Prumer_mereni;
  //// for(int i=0; i<10; i++) {
  //
  // Čte echo a vrací dobu odrazu zvukové vlny v micro s.
  Duration = pulseIn(EchoPin, HIGH, 6000);
  //delay(10);
  //
  //  Duration_prum += Duration;
  // }
  //
  //Prumer_mereni = Duration_prum/10;
  //delay(10);

  Distance = 47 - (Duration * 0.0343 / 2); // rychlost zvukové vlny /2 tam a zpět




  if (Distance > 45) {
    Distance = 47;
  }
  else if (Distance < 0) {
    Distance = 0;
  }

  int distance = Distance;

  lcd.setCursor(0, 1);
  lcd.print("Distance:");
  lcd.print(distance);
  lcd.print("cm");
  Serial.println(Distance);
  /*
    Serial.print("čas =  ");
    Serial.println(  millis());


    Serial.print ("  Vzdálenost = ");
    Serial.println( Distance);
  */



  Setpoint = map(analogRead(A0), 0, 1023, 20, 40);

  setPoint = Setpoint;

  lcd.setCursor(0, 0);
  lcd.print("Setpoint:");
  lcd.print(setPoint);
  //lcd.print("cm");

  /*
      float hod = analogRead(A0);
    analogWrite25k(9,map(hod, 0, 1023, 0, 320));
    hod = (hod *5 /1023);

    Serial.print(" Napětí pot = ");
    Serial.print(hod);
    Serial.print(" V,    ");
  */


  Input = Distance;

  myPID.Compute();
  analogWrite25k(Vent, Output);

  if (Distance <= 17) {

  analogWrite25k(Vent, 160);
 }
















  /*
    analogWrite25k(Vent,map(analogRead(A0),0,1023,0,320));

    Serial.print("A0: ");
    Serial.print(analogRead(A0));
    Serial.print("pwm: ");
    Serial.println(map(analogRead(A0),0,1023,0,320));
  */











  /*
    Serial.print("Input:  ");
    Serial.print(Input);
    Serial.print(" ");
    Serial.print("Output:  ");
    Serial.println(Output);
    Serial.print(" ");
    Serial.print("Setpoint:  ");
    Serial.print(Setpoint);
    Serial.print("  ");
  */
  /*
    for(int pwm=0; pwm<=320; pwm+=32) {
    OCR1A = pwm;
    delay(5000);
    }
  */

  start_Time = millis();
  count = 0;
  while ((millis() - start_Time) <= 1000) {

    RPM = (count * 60) / 4;
    /*
      Serial.print("    otáčky = " );
      Serial.print(RPM);
      Serial.println("rpm,   ");
    */

  }
}
/*
  void Receive_Serial_Data(){

  while(Serial.available()>0){


  Data = Serial.read();
  serialData += Data;


  if (Data == "c") {
  serialData += Data;



   }
    }


  }
*/

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;

  }
}



void RPM_fun() {
  count++;
} 

And my setup is:


When the ball is on Setpoint or more then setpoint fan just turning off.

Hi,
If you are using the ultrasonic sensor to measure distance, don't forget the change in density of air around the ball and rising up to the sensor, will provide a false reading, as the ultrasonic will bounce of the density change and not the ball.

Tom.. :smiley: :+1: :coffee: :australia:

Readings is ok i have correct Distance.

Hi,
Why aren't you using analogWrite, PWM to control the motor speed?
Can you please post a circuit diagram, not a Fritzy?

A hand drawn image would be fine, including all power supplies, component names and pin labels.

Thanks.. Tom... :smiley: :+1: :coffee: :australia:

Because i need Pwm 25KHz and analog write is only 490 Hz. Ok i’ll do it wait please

Hi,
Thanks, so you are using a computer fan with speed control pin.

Did you write your code in stages?
If you did you should have some code to prove you have control over the fan using your input pot.

Does this work, if you haven't then I suggest you make code for each specific I/O device to prove their operation.

What is the power/current rating of your fan?

Tom... :smiley: :+1: :coffee: :australia:

Yes i’ve this code for control fan only with potenciometr. Everything is fuctional only regulation not work and idk why.

Hi,
Your power supply is rated at 12V 1A, what is the fan rated at?

Have you monitored the 12V supply while trying to control the system?

Tom... :smiley: :+1: :coffee: :australia:

Fan rated current is 1,2 A. Yes i try the output from adapter with voltmeter.

Hi,
With fan rated at 1.2A and only a 1A power supply that is also providing current for other devices!
You might need to investigate that.

Tom.... :smiley: :+1: :coffee: :australia:

No, it is ok, i have powerful fan then i need. The only thing i need to fix is pid regulator

More powerful

Do you need a PID at all?

Have you ever tried a pot to control the PWM and then find out manually the duty cycle for various heights (setpoints)?