Jan 022010

Like many others I am fascinated by two-wheeled, self-balancing robots. I am currently in the process of building a self-balancing robot that should be big enough to allow me to ride on it. However, before I blog about this new project I want to briefly introduce a LEGO prototype that I built a couple of months ago. The structure and the motors are LEGO but as the ‘brain’ I used the Make Controller Kit (see image below). The Make controller board can be seen in the center. Only the larger diameter wheels are used for balancing; the small wheel that is visible in the front (there is another one in the back) is only there to prevent the robot from falling over too far if the power is off or the balancing fails.


The following short video shows the balancing in action. At the end of the video I turn off the power supply, making the robot ‘fall’ as a result.

The tilt sensor consists of the 3-axis accelerometer ADX330 and the dual axis gyroscope IDG300. The x and z accelerations from the ADX330 sensor are used to calculate the raw tilt angle. It is accurate provided the sensor is static; i.e., the acceleration is purely based on the gravitational forces. In a moving robot the actual forces are based on the gravitational forces and the acceleration of the robot itself. To compensate for acceleration the gyroscope sensor is used. The tilt angle is calculated by integrating over the angle velocity that is measured by the gyroscope. This calculated tilt angle is heavily impacted by drift and hence cannot be used in isolation. For this reason the output of the gyroscope and the output of the accelerometer are combined via a Kalman filter.

The following graph shows the difference between the angle that is calculated from the accelerometer (blue) and the angle based on the application of the Kalman filter (red):


The calculated tilt angle is passed into a PID loop that is used to control the motors. For details see the complete controller code. In addition to the code that calculates the tilt angle and drives the motor, the code also contains two asynchronous USB tasks (UsbReceiverTask and UsbSenderTask) that were used to communicate directly with the PC. This allowed for fairly efficient debugging of the code and fine tuning of the various control parameters as can be seen in the screen shot below. The included graph shows the tilt angle (red), the angular rate (black) and the normalized speed (green) over time. It is clearly visible how the speed oscillates in order to keep the robot balanced. Below the graph the PID parameters and parameters that are used to assemble the input into the PID loop are shown.


As a prototype the robot worked very well. The balancing was very stable as long as the robot was not pushed. When pushed the robot would counteract but would start moving in the direction that it was pushed towards. This shortcoming is caused by the fact that the control code has no insight into the speed of the robot. The typical remedy is to add wheel encoders to measure the speed and incorporate the speed signal into the PID algorithm. Since wheel encoders are a bit cumbersome I decided not to bother with them for the prototype. I will use wheel encoders in the ‘official’ project though.


I learned a lot from what other balancing robot builders and Segway clone builders have published. Here is a list of some of the links (in no particular order) that I used:

  11 Responses to “Building a Self-Balancing Robot – The Prototype”

  1. im doing two wheels balancing robot for my final year project using PIC16F877A microcontroller,ADXL330 accelerometer sensor and 1dc motor..for that,i didnt know how to program this robot using PID algorithm as a controller for this robot..please help me to solve my problem…;-(

  2. I suggest that you have a look at the C source code that I reference from the blog article. While the code is for the MakeController, large portions of the code should nevertheless be usable. However, please note that you can’t accomplish stable balancing with just an accelerometer. You also need a gyroscope plus preferably wheel encoders.

  3. Is it possible for you to attach missing header file? I am sorry, I am still new in PID. Your help will be appreciated. Thanks.

  4. Can you please specify what header file you think is missing?

  5. Dr Rainer,

    I downloaded the Python files to plot serial data, but the only scrip working is Realtime.py, which basically is the Eli Bendersky script with some random data. I am currently using Eli’s script Ok , but I was interested on looking at your adaptation to plot the 3 curves.

    Are some configuration files missing or am i doing something wrong ? I am also very new to Python and for example I do not understand why the file Settings.pyc is created when I attempted to run Mainmodel.py?

    I would appreciate any info or direction on this ,

    Thanks a lot for your posting very useful info. I am trying to do same robot using ATmega168 with ADXL322 and ADRS614.



  6. Hi Jose,

    The file Realtime.py is not really part of the application. I left the file in the folder since I used it for testing purposes while learning how to plot data in Python. The correct entry point for the application is MainApp.py. Please note though that the app expects a robot to be connected to the serial port sending the expected information.

    I am very new to Python as well and I am sure I made many mistakes. I developed and tested the app from within Eclipse using the Pydev IDE which took care of the module structure. However, when I run MainApp.py outside of Eclipse I get an import error: No module named Model.MainModel. So, please use my code with caution.

    The Python compiler automatically creates .pyc files for optimization purposes. The file contains the ‘byte-compiled’ version of the Python code in the corresponding .py file.


  7. Dr Rainer,

    Thanks , yes I’ve got same error. I’ve installed eclipse and pydev and same error still there. I will keep trying as there are not many applications for real time display. I am using some with Tcl Tk, but I think this one or or Eli’s are the one I may use as a guidance . Thanks

  8. Hi Jose,

    I fixed the directory structure so that the import statements work. I also fixed a bug in the code that writes the app settings to disk. Please get the latest version of the Python code and try again. You should now be able to start the app by running MainApp.py under the UI folder.


  9. Thanks !

    Yes , it is working OK now, so, no need for Eclipse. I’ve plotted data sent from an AVR. I will only use 3 signals so I am putting dummy values for the motor speeds in order to provide same string. I will now work on changing scales as well as eliminating the need for the extra data.

    Thank you very much for your concern and fixing the code !

  10. Dr. Rainer,

    If you added wheel encoders for velocity of the robot, would you have two separate PID calculations? And then sum both PID outputs to determine the final torque for the motor?

    Thank you,

  11. Andy, sorry for the late response. First let me say that I have not hooked up the wheel encoders for my balancing robot so please don’t take the following as gospel.
    I would just use one PID to determine the required torque to balance the robot. The simple solution is then to use the torque signal for both motors. Since two motors never behave exactly the same this will result in the robot slowly turning. To counteract this you can use a hard coded offset to make sure that the faster motor is slowed down a bit and the slower motor sped up. In my case I use a potentiometer to adjust the offset which allows me to steer the robot.
    The next level would be to integrate the ticks difference between the two wheel encoders and dynamically calculate the offset by multiplying the integral with a constant. This way you essentially use an ‘I’ controller (the second part of a PID controller) to adjust the speed difference. Again, please keep in mind that I have not implemented this myself.

 Leave a Reply



You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>