Wednesday, July 2, 2014

Balancing of a Ball on Beam using Arduino as a PID controller

Video





I used Arduino Uno as a PID controller to balance a small ping-pong ball on a 4-bar mechanism. And used Matlab to plot the position of the ball vs time.

In this video:
  • setpoint = 15 cm
  • Kp= 2.5
  • Ki=0
  • Kd=1


Control Loop:




  • An ultrasonic sensor detects the actual position of the ball (the "output ball position" in the above figure). 
  • The output ball position is compared to the "setpoint" (the position where we want the ball to be)
  • A PID algorithm on the arduino is used to compute the angle of the servo motor based on the difference between the output ball position and the setpoint (the error).



Parts used:


  • Arduino Uno
  • Ping))) ultrasonic sensor
  • 20 Kg.cm Digital Servo Motor
  • 5 V DC power supply


Connections:




The dimensions of my 4-bar mechanism 






You can change the dimensions of the mechanism, the weight of the ball, or any other parameter. But then you will have to change the Kp, Ki, and Kd values in the code to get a good system performance.



Arduino code, Matlab code and PID library:

https://drive.google.com/folderview?id=0Bx4uoJmyE27YdGRMYi16dnUxVk0&usp=sharing



  • You must download "PID_v1" library for arduino and move its whole folder to:
        Documents > arduino > libraries 



       





Update:



How to get the values of Kp, Ki, & Kd?


- You can try to guess the values, then apply it in the code and monitor the performance of the system as you change theses values. Don't worry too much about  Ki in this system, you can set it to zero. Firstly, guess the value of Kp, then keep changing the value of Kd until you reach a satisfying performance for the system. This is called manual tuning and it takes a long time. 

- Another thing you can do, is to build a mathematical model on SIMULINK and use its automatic tuner that can give you three values for Kp, Ki, and Kd.  Of course the mathmatical model will not 100% represent the real physical system, therefore, you will have to slightly change  the 3 obtained values, which means you'll have to do some manual tuning anyway.



- If you are familiar with Simulink, you can check out these detailed tutorials: 

LINK 1

LINK 2



The tutorial will teach you how to build a model on simulink for the system and how to tune the Kp, Ki, & Kd values.





76 comments:

  1. Replies
    1. The m file attached can work fine on Matlab 2010 to Matlab 2013

      Delete
  2. How did you obtain those values? P, I and D?

    ReplyDelete
  3. hii there, could you explain more about the theroical model in SIMULINK?? please

    ReplyDelete
  4. Hi there, thanks for the response. I have a doubt. In your experience is better a broader outputlimit PID, yours is -80 to 80, or narrower like -50 to 50, which implies one and the other?

    ReplyDelete
    Replies
    1. It depends on the maximum angle that your servo motor can make.

      My servomotor's maximum angle is 180 degrees.

      In my code, the output limit is -80 to 80 degrees. Which means, the limit of the output servomotor angle will be either (102+80) degrees or (102-80) degrees.

      Delete
  5. what if i used us100 ultrasonic sensor?? what will happen to the codes?? and the connections??

    ReplyDelete
  6. This comment has been removed by the author.

    ReplyDelete
  7. We have arduino mega + arduino R3 motor shield, with the HC-SR04 ultrasonic sensor.

    Will your code still work? How can it be modified ?

    I'm trying to accomplish the same task and will be using the same setup that you have built with the same dimensions and everything.

    ReplyDelete
  8. Replies
    1. I solved the problem, the code must be modified just a little :)

      Delete
    2. Hello, you can share the modified code , With the sensor HC-SR04 :)

      Delete
    3. Hi i used ultasonic hc_sr04 . I need code please

      Delete
  9. This comment has been removed by the author.

    ReplyDelete
  10. What do I need to modify to use the code on arduino mega?

    ReplyDelete
  11. I am trying to do same experiment via using dc motor and motor driver, in my driver there are three ping one of them for speed, the others one selecting of direction, how can I implement this experiment, I couldnt set my speed, every time motor turns so fast and damage to the system.

    ReplyDelete
  12. Hi there. I just would like to know, what kind of software i need to use other than arduino? I'm interested with your projects.

    ReplyDelete
  13. I wanna ask about the servo.. can i use a standard one instead of the digital? + can u give me your servo's serial number?

    ReplyDelete
  14. hi i would like to knw its practical application i.e. hw this concept can be used in industried n al?

    ReplyDelete
  15. Hello to everyone!

    If someone here is using the HC-SR04 sensor you only have to modify a little part of the code. In this case, I add a constant name it pingPin2 (This constant is my new Input) and the the other one (pingPin) is now only an output.

    Please, search and find this part of the code and replace it:

    const int pingPin = 9;
    const int pingPin2 = 8;

    long duration, cm;
    unsigned long now = millis();
    pinMode(pingPin, OUTPUT);
    digitalWrite(pingPin, LOW);
    delayMicroseconds(2);
    digitalWrite(pingPin, HIGH);
    delayMicroseconds(5);
    digitalWrite(pingPin, LOW);


    pinMode(pingPin2, INPUT);
    duration = pulseIn(pingPin2, HIGH);

    ReplyDelete
    Replies
    1. you connect the trigger to pin 8 and leave echo without a connection?

      Delete
    2. for HC-SR04 :

      #define trigPin 12
      #define echoPin 11

      long duration, cm;
      unsigned long now = millis();

      digitalWrite(trigPin, LOW);
      delayMicroseconds(2);
      digitalWrite(trigPin, HIGH);
      delayMicroseconds(10);
      digitalWrite(trigPin, LOW);


      duration = pulseIn(echoPin, HIGH);

      cm = duration/58;

      Delete
    3. escuse me, this part of the code
      digitalWrite(trigPin, LOW);
      delayMicroseconds(2);
      digitalWrite(trigPin, HIGH);
      delayMicroseconds(10);
      digitalWrite(trigPin, LOW);


      duration = pulseIn(echoPin, HIGH);

      cm = duration/58;

      is add it in void setup o void loop???

      Delete
  16. Hello.. can you helo me?
    Im using an servo (0-180) degrees and my horizontal is 75 degrees, what values of outputlimit PID I can use in my project? If I use iqual to you (-80-80) its correct?

    ReplyDelete
    Replies
    1. I think in your case, you only have to replace the horizontal value (75º) in the code, because the Arduino code add automatically the range. But with that servo you only can go in the "Positive area" 105º more (75º + 80 = 155º [the limit of servo is 180º]) but you can't go in the negative area (75º - 80º = -5º????)

      Delete
    2. How do you got your Horizontal value?

      Delete
  17. What are the materials of the mechanism?

    ReplyDelete
  18. This comment has been removed by the author.

    ReplyDelete
  19. This comment has been removed by the author.

    ReplyDelete
  20. Can I use another servo motor? Another which has less torque? And if yes, how powerful? Thanks

    ReplyDelete
  21. can you send me modified coding plzz
    ch.umer840@gmail.com

    ReplyDelete
  22. I have a servo motor 17 kg.cm High torque servo 1501 MG. But this motor is not digital servo motor. Can I use this motor for this project ???

    ReplyDelete
  23. hola que sustitutos puedo poner en lugar de ese motor

    ReplyDelete
  24. funcionara con un servo motor mg995

    ReplyDelete
  25. Amigo.. tu trabajo es genial.. gracias por tu aporte. :)

    ReplyDelete
  26. Hello i try to make using hc sr 04 anyone can post me ardunio code?
    e_celik93@hotmail.com

    ReplyDelete
  27. it doesnt work for me, it says that 'PID doesnt have a name

    ReplyDelete
  28. *Note: Trig Pin is connected to 7 and Echo Pin is connected to 8


    #include
    #include



    const int servoPin = 9; //Servo Pin

    float Kp = 2.5; //Initial Proportional Gain
    float Ki = 0; //Initial Integral Gain
    float Kd = 1.1; //Intitial Derivative Gain
    double Setpoint, Input, Output, ServoOutput;



    PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT); //Initialize PID object, which is in the class PID.




    Servo myServo; //Initialize Servo.


    void setup()
    {

    Serial.begin(9600); //Begin Serial
    myServo.attach(servoPin); //Attach Servo

    Input = readPosition(); //Calls function readPosition() and sets the balls
    // position as the input to the PID algorithm



    myPID.SetMode(AUTOMATIC); //Set PID object myPID to AUTOMATIC
    myPID.SetOutputLimits(-80,80); //Set Output limits to -80 and 80 degrees.
    }

    void loop()
    {

    Setpoint = 15;
    Input = readPosition();

    myPID.Compute(); //computes Output in range of -80 to 80 degrees

    ServoOutput=102+Output; // 102 degrees is my horizontal
    myServo.write(ServoOutput); //Writes value of Output to servo


    }




    float readPosition() {
    delay(10); //Don't set too low or echos will run into eachother.



    const int pingPin = 7; //Trig Pin Arduino 7
    const int pingPin2 = 6; //Echo Pin Arduino 6


    long duration, cm;
    unsigned long now = millis();
    pinMode(pingPin, OUTPUT);
    digitalWrite(pingPin, LOW);
    delayMicroseconds(2);
    digitalWrite(pingPin, HIGH);
    delayMicroseconds(5);
    digitalWrite(pingPin, LOW);


    pinMode(pingPin, INPUT);
    duration = pulseIn(pingPin2, HIGH);

    cm = duration/(29*2);






    if(cm > 30) // 30 cm is the maximum position for the ball // make 35
    {cm=25;} // make 30


    Serial.println(cm);

    return cm; //Returns distance value.
    }

    ReplyDelete
    Replies
    1. BTW this is to use with the HC-SR04

      Feel free to ask any questions

      Delete
    2. Sir, can you please provide me the connections for the HC SR04 sensor as because I am getting great difficulty in making the connections for the HC SR04 sensor and the ping sensor is not available in my country. Please reply sir. Thanks in advance.

      Delete
    3. Sir, please send Matlab code for your circuit connection

      Delete
  29. I have a problem with real time plotting. Plot is not updating. Still is the straight line even when PID action is running. It can be a problem if i use matlab 2015??

    ReplyDelete
    Replies
    1. Hi
      i am facing the same problem, if you had been solved yours could you help me ?

      Delete
  30. will the code work in matlab R2016a version??

    ReplyDelete
  31. hello, i can´t see the code in the folders.
    can someone please share me the whole code for arduino?

    ReplyDelete
  32. Elinize sağlık.Herseyi harika anlatmışsınız.Benim birkaç sorum olucak 5v u arduniodan versek olur mu?

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
  33. Could you tell me where to get the links used for building the mechanism

    ReplyDelete
  34. What is the make and model of servo used?

    ReplyDelete
  35. Dear Ruben,
    firts of all: thanks to You for this video and for sharing Ardu-sketch!
    Greetings from Germany,
    Wolga

    ReplyDelete
  36. I don't understand how to connect everything together, should I include the PID library somewhere?

    ReplyDelete
  37. This comment has been removed by the author.

    ReplyDelete
  38. Hello Ruben,

    thanks for the useful tutorial, my setup isn't working and I have no idea where to start the debug.
    It looks it's moving without any relation to the ball position.
    I tried to slow it adding a delay(1000) at the bottom but the servo keeps moving even if I fix the ball with the tape.

    kd,ki,kp=0

    Thanks to anyone can help!

    ReplyDelete
  39. This comment has been removed by the author.

    ReplyDelete
  40. 不太懂
    unsigned long now = millis();
    pinMode(pingPin,OUTPUT);
    digitalWrite(pingPin,LOW);
    delayMicroseconds(2);
    digitalWrite(pingPin,HIGH);
    delayMicroseconds(5);
    digitalWrite(pingPin,LOW);

    ReplyDelete
  41. ??? Error using ==> serial.serial at 57
    The serial port object is supported on the Solaris, 32-bit Windows and 32-bit Linux platforms only.
    我arduino是用com8為何會有錯誤

    Error in ==> Matlab_realtime_plotter at 19
    arduino=serial('COM8','BaudRate',9600); % create serial communication object on port COM18

    ReplyDelete
  42. The matlab program you provided can not be executed。
    There are mistakes

    ??? Error using ==> serial.serial at 57
    The serial port object is supported on the Solaris, 32-bit Windows and 32-bit Linux platforms only.

    Error in ==> Matlab_realtime_plotter at 19
    arduino=serial('COM8','BaudRate',9600); % create serial communication object on port COM18

    ReplyDelete
  43. if I want to run a ball and beam system on a bicopter with arduino mega and mpu6050.... can u help me with programming code?

    ReplyDelete

  44. good night I would like to know, how do I perform the servomotor transfer function thanks

    ReplyDelete
  45. Hello, I have a problem with the langlarian formula in the simulink, So it cannot run. It says "syntax error". Do you know whats the problem?

    ReplyDelete
  46. 102 degrees is my horizontal , tell me . if i use servo mortor 360 degrees

    ReplyDelete
  47. hello where did you get the servo arm(horn)

    ReplyDelete
  48. Hello ,

    thanks for the useful tutorial, my setup isn't working and I have no idea where to start the debug.
    It looks it's moving without any relation to the ball position.
    I tried to slow it adding a delay(1000) at the bottom but the servo keeps moving even if I fix the ball with the tape.

    kd=1.1,ki=0,kp=2.5

    Thanks to anyone can help!

    ReplyDelete
  49. Sir my project model is working ,but sir I can't tune ball on right position can you help me what I do so the ball is fix on right position.

    ReplyDelete
  50. i cant run the real time plotter i dont know whats the problem .im using matlab 2014a 64bit .any help?

    ReplyDelete
  51. can anyone explain me the pid_v1 library codes ?

    ReplyDelete
  52. What is the weight of the ball?

    ReplyDelete