CE 432 Robotics II Fall 2021
Self Balancing Robot Project
Sean Eaton

Self Balancing Robot Project


For the final project of Robotics II we were tasked with creating a self-balancing robot car using our experience with the NEMA17 stepper motors and incorporating a MPU6050 which is an accelerometer and gyroscope sensor. This robot was split into two parts, the first of which dealt with learning how to use the MPU6050. We were required to learn how to use the I2C protocol to interface with the MPU6050 and become familiar with reading from the MPU6050's relevant registers. During this process a frame for the robot also had to be constructed using sheets of plexiglass and threaded screw rods. These were cut to size and assembled into a frame capable of securing the stepper motors and Arduino circuit. In part two the interrupt service routine (ISR) of the ATMega328P was introduced as a method of providing feedback to the stepper motors every 20 us. By doing this the stepper motors are able to move accordingly in order to self-balance the robot car. The feedback provided to the ISR is in the form of a Proportional-Integrative-Derivative or PID controller. Using the methods used in part one to get accurate MPU6050 values, the PID controller does further processing to provide an accurate measurement of the robot's pitch which is necessary to balance the robot.

Self Balancing Robot Part 1:

Due to the class having done portions of part one previously in the semester, the tasks in part one begin at Task 5.

Task 5: Modify the MPU's code to display the raw acceleration data of the X axis.

The MPU6050's raw acceleration data was displayed by modifying the provided MPU6050 example code. The Arduino circuit for the MPU6050 is shown below in Figure 1. The MPU6050 and breadboard were orientated perpendicularly to the table so that the raw z acceleration of the data is in the 8000 range as shown in the project's webpage. The raw acceleration data was printed to the Serial Monitor and can be seen in Figure 2 below.

Figure 1. MPU6050 connected to the Arduino Uno.

Figure 2. Serial Monitor output displaying raw z acceleration data.

Task 6: Calculate a gyro pitch calibration value and report it to the Serial Monitor.

A gyro pitch calibration value can be calculated by averaging reported values when the gyroscope is at rest. This can be done by creating a for loop and adding together the read values before dividing the sum by the number of for loop iterations. The results can be seen below in Figure 3. There is some variation to the values being reported after calculating the calibration value but its likely due to the scale on the y axis. On the project webpage the y axis scale is from -6 to 6 so the variation in reported values looks much smaller.

Figure 3. Gyro pitch calibration values after calculating a gyro pitch calibration value.

Task 7: Blink an LED at 1 Hz using a loop timer variable.

A loop timer can be created by implementing a while loop with the condition that a certain amount of time has to pass before the while loop breaks. The loop timer is necessary for implementing a PID controller so that the change in time can be accurately used. A video was created to display the LED light blinking on and off every second.

Task 8: Mount the MPU6050 sensor/breadboard on top of the car. Gently lean the car from 0 degrees to 90 degrees and -90 degrees. Check if you are receiving 90 or -90 on the serial monitor.

For task 8 we needed to implement an angle calculator so that the MPU6050's values can be used to determine the robot car's orientation. This task was also split into two parts. In part one we were required to calculate the angle using the gyroscope pitch values in addition to calculating the angle using the accelerometer in the Z direction values. The accelerometer values are able to be used to calculate the angle by using trigonometry to solve for the angle. In part two we were required to calculate the angle using only the Z accelerometer values.

The video displaying the use of the gyrscope and accelerometer for the angle calculations is shown below. For some reason the angle updates a bit slowly when using this method. When at rest the reported angle is consistently near zero and when rotating the car forward or backward the angle adjusts accordingly. Once the angles get closer to 90 degrees or -90 degrees the reported angle needs to catch up to the car's position. After waiting shortly the reported angle will then be close to the expected values of +/- 90 degrees.

Next is the video displaying the use of the accelerometer only. This code is based off of the previous code and it turns out to be much more responsive to changes in angle compared to when the gyroscope was being used. The reported angle updates to +/- 90 degrees more quickly than previously. There used to be nan outputs when the robot reached near +/- 90 degrees rotation. This was able to be fixed by limiting the raw values to +/- 8192.

Self Balancing Robot Part 2:

Task 1: Complete the simplified version of the project shown in the video demonstration.

For the first task of part 2 the balancing robot should be implemented so that it is able to remain upright on its own. I originally tried to implement the balancing robot by using Joop Brokking's code and tutorials on his Brokking.net website found here. It was useful for understanding how the robot works but the best performing balancing robot mainly uses the example code provided by my instructor Dr. Li here.
The self balancing robot uses the previous angle calculation code to determine the robot's pitch orientation. Using the calculated angle a PID controller provides feedback on if the robot is currently balanced. The interrupt service routine (ISR) runs every 20 us to control the NEMA17 stepper motors. The main configurable part of the code was adjusting the PID gains for the proportional, integrative, and derivative portions of the PID output. I also had to make adjustments to the stepper motor portion of the code so that the stepper motors were rotating in the correct direction in response to the PID output. After experimentally tuning the PID gains the best performing balancing robot can be seen below.

There was also the option to incorporate joystick functionality and attempting the ramp test but these tasks were not accomplished in time.

Task 4: PCB design, fabrication, soldering, and testing. One PCB for the joystick remote and one PCB for the robot car.

Another goal with the self balancing robot project was to design a robot PCB and remote PCB capable of replacing the Arduino breadboard circuit.
The first PCB I designed was the balancing robot PCB. The first part designed was the voltage regulator so that the 12V LiPo battery pack could supply 5V to the ATMega328P. After this I followed a schematic for a barebones ATMega328P setup. After this I added the A4988 stepper motor driver boards and the 2.4 GHz transceivers so I could attach them using female pin headers. The last part added was the MPU6050 and its own separate voltage regulator that takes the 5V down to 3.3V for the MPU6050. The schematic for the balancing robot PCB is shown below in Figure 4. The board layout is shown in Figure 5.

Figure 4. Self balancing robot PCB schematic.

Figure 5. Self balancing car PCB layout.

In addition to designing the self balancing car PCB, I also designed a remote controller PCB. The main components are the voltage regulator for the ATMega328P, a barebones ATMega328P setup, and female pin headers for the transceiver and joystick modules. This PCB was not the one manufactured however, my partner, Audra, had her remote control PCB manufactured.

Figure 6. Remote controller PCB schematic.

Figure 7. Remote controller PCB layout.

Most of the componenets for the self balancing robot PCB were soldered on. Unfortunately the female pin header supply was depleted and so the headers for the A4988 stepper motor drivers and transceiver couldn't be soldered on yet. A major improvement upon this PCB compared to the previous ESP32-CAM PCB is that the correct footprints for the capacitors and inductor were able to be used.

Figure 8. Nearly complete self balancing robot PCB. Appropriate female pin headers still need to be soldered on.

Task 5: Final testing, presentation, and report writing.

For task 5 all we were required to do was create a presentation of the final project, demonstrate the robot's functionality, and finish writing the report.


I enjoyed working on this final project. Part one of the self balancing robot was simple and straight forward, I enjoyed learning about how to use the MPU6050 because I hadn't used one before without a library handling everything for me. It was interesting learning how to use the MPU6050 registers to request raw data from the MPU6050. I also enjoyed studying the provided sample code and the YABR project when trying to get the robot to balance correctly. I had a little experience with a PID controller but I was inexperienced at the time so the provided code was very enlightening for me. I also really liked designing the PCBs and getting more experience with surface mounted devices. The tiny resistors I had to use for the MPU6050 and ATMega328P were definitely the most difficult to solder correctly but I am happy with the results. There is an issue with the PCB that needs to be investigated. After completing the soldering I connected the board to the 12V LiPo battery pack. The LED by the battery connector lit up as expected but the LED that shows the MPU6050 is powered on did not light up. The voltage regulator was also not set properly to output 5V so the MPU6050 voltage regulator was likely destroyed. Later on the PCB was tested again to check if the MPU6050 would turn on but at this point neither of the LEDs powered on. In the future the MPU6050 connections should not be completed until the voltage regulator can be set correctly.
The self balancing robot performance is less than desirable as well. A majority of the time spent on getting the self balancing robot working was spent on experimenting with the PID gain values and the interrupt service routine. I originally followed the YABR tutorial, which was informative on how the robot works, but it also included a different PID controller algorithm and different interrupt service routine. The PID controller and ISR accomodate the robot rotating and being controllable with a remote controller which is why I was interested in using the YABR code as the base. After spending a lot of time on getting the code functioning I decided to use the example code provided by Dr. Li instead because it was simpler and gave better results than I had so far. After much experimenting with the PID gain values the robot was finally able to balance initially but was not resilient to pushes. The PID controller gains will be continued to be adjusted to provide better results.
Overall I learned a lot from this project and I was happy to work on it.