Introduction
Hi! I’m Claire, and I’m a rising junior at Castilleja School. I’m interested in engineering and other STEM fields, namely math, computer science, and electrical engineering. My goal with Bluestamp this summer was to really delve as deeply as I could into engineering and to try to understand and learn as much as I could while building an awesome project.
I chose to focus on a self-balancing robot because I thought it would give me a refreshing challenge, because I wanted to build on my initial exposure to closed loop control (where a system’s output is adjusted and refined based on live feedback, such as sensor measurements) during the prior FIRST robotics season, and frankly because it looked super cool! I have to admit I went into this project half having no idea what I was doing, and half thinking it would be a breeze. I came out with a balancing robot that still needs improvements (but what project doesn’t?), and more importantly, I came out with an even greater passion for learning and building. This project taught me humility, patience, and creativity. It taught me that taking risks and making mistakes is far better than sitting still and worrying about change. It taught me to have no regrets – that when something goes wrong, I shouldn’t waste time dwelling on the past, because I can always learn something from every failure, and the only way forward is to keep trying.
Keep reading to see the milestones I reached and problems I solved to build a working robot!
How It Works
My robot balances on two wheels (like a mini-segway) by moving forwards and backwards to compensate for its tilt. It senses this tilt with an IMU, or inertial measurement unit, that contains both an accelerometer (which measures translation) and a gyroscope (which measures rotation). The accelerometer is accurate in the long term because it always as gravity as a reference but is over-sensitive to short term, high frequency changes, while the gyroscope is accurate in the short term but is susceptible to drift over time. When combined, in my case using a sort of weighted average with a complementary filter, these two sensors fill in each other’s shortcomings and give very accurate measurements of the robot’s angular position.
The robot’s measured tilt, along with the robot’s speed as calculated from encoders on the motors, is fed into an Arduino Due and through a bunch of closed loop controllers that finally output a motor PWM command (PWM = pulse width modulation – a rapid on-off signal that changes the duration of the on and off pulses to mimic an analog signal). I used 3 nested PID controllers, a particular type of closed loop control, to do the job of transforming the sensor input to motor output. PID stands for proportional, integral, and derivative; these three terms describe how a PID controller acts on error (how far the system is away from its desired state) to output an appropriate command. The proportional term looks at current error and gives the initial kick to get the system back on track; the integral term looks at accumulated past error and eliminates steady state error (when the system is very close to the desired state but not quite there yet); the derivative term looks at predicted future error and counteracts the proportional term’s kick to bring the system smoothly to its desired state. A PID controller takes a weighted sum of these three terms to calculate an output command.
I decided to use 3 nested PID controllers, as illustrated below, to keep the robot upright and balancing in place. I then added remote control over Bluetooth to make the robot move around as commanded by a PS3 controller.
Code, BOM, Schematics, and more!
Code – A Github repository with all of the sketches I wrote over the course of my 6 weeks at Bluestamp, from my very first blink program to the final code. All of the library files used in the final sketch (including my custom libraries) are included as well.
Bill of Materials – A PDF of the robot’s BOM with all parts used in the project, links to purchase, and price.
Electrical Schematic – This schematic, created in Fritzing, displays all of the wiring for the main electrical components on my robot.
Mechanical Drawings – Google Sketchup top view renderings of the robot’s three boards | 2D front view of the robot
Daily Journal – The journal I kept every day of the program, detailing the problems I encountered, lessons I learned, solutions I came up with, and day to day plans.
Showcase Night Presentation – The slides that went along with my showcase night demo that give a graphical overview of how my robot works (main components, explanation of a PID controller, and control system structure).
End of Main Project: Remote Control, Arduino Uno to Due, and My Final Adventures
My final days at Bluestamp were an exciting rush to the finish line. My main goal was to implement remote control, but I ended up changing a lot of other elements on my robot. First, I realized that the Arduino Uno I was originally using didn’t have enough pins to house the USB Host Shield for adding Bluetooth remote control. So I had to switch out the Uno for the larger, more powerful Due; I had originally planned on using the Due but I had had troubles porting the IMU library onto it. I asked the editor of the IMU library for help, and he kindly responded saying he didn’t quite know what I should do and added that the original author had passed away so the library wasn’t going to be edited for compatibility any time soon. So I decided to ask a school robotics mentor, who is an electronics expert, and he and I worked for an entire Sunday morning to get the library working on the Due (thanks Sasha!). We aren’t entirely sure which of the fixes we made was crucial because I accidentally plugged in the IMU’s data and clock lines backwards to start with, but we disabled the disabling (!) of the 5V internal pullups in the library because the Due only inputs/outputs 3.3V, which is what the IMU likes, and we changed all of the vague int
variables to explicitly sized int16_t
‘s for safety.
The next change I decided to implement was to add 2 additional PID controllers (with a feed forward term) to regulate the difference in the two motors’ performance. The robot had been turning randomly while balancing in place, which was not desirable behavior if I wanted to add remote control. The 2 PID loops, one for the right motor and one for the left, would command a motor speed and output a PWM command to match. I found it extremely difficult to tune these new loops, because they depended on the two outer loops I had originally implemented. In hindsight, I probably could have tuned these by giving the robot a temporary third wheel it could lean on and commanding the robot to move at a certain speed without having to worry about balancing. But instead I opted to roughly tune them individually, add the two outer loops back in, and adjust for any remaining turning then. This approach might have worked, but given the slow code compilation and upload process and the lack of time, it wasn’t extremely successful.
Finally, I added remote control with my PS3 controller. Moving forward and backward was very simple, as it just required an adjusted speed setpoint in the outermost loop. Turning, however, was another issue. When I sent an offset to the motors in an attempt to get them to turn, the robot would snap back to its original heading as soon as I stopped asking it to turn. I tried to solve this by instead sending the motors exact opposite commands, but this made the robot quite unhappy, so I reverted to the original approach. I believe the snapping back is because the robot is reading a net non-zero speed while turning (because I calculate net speed by averaging the right and left speeds), so it attempts to return to what it thinks is zero speed. But when I tried disabling the outermost speed PID loop, the robot acted the same way, so I suspect there is something else going on.
One major issue I had leading up to the completion of my project was the inconsistency of my robot. It would react differently to fluctuating battery voltage, print statements in the code, and other external factors I have yet to identify. The inconsistency, coupled with the excruciatingly slow code upload time for the Arduino Due and Bluestamp crunch time, made it difficult for me to perfect my robot. For example, my robot was working extremely well the morning of the final day, but after a quick lunch break, it resumed oscillating unstably and I spent the entire afternoon trying to get it back to normal. One thing that would have really helped speed up the entire process is using the two XBee modules I had purchased to tune the PID constants live instead of re-uploading code each time (which is why I left the XBees and their adapters on my BOM even though they weren’t officially used in my project). I know some people had used potentiometers to adjust their constants live, but with such a delicate process, I think the XBees and a Processing sketch and being able to see actual numbers would have been the most effective approach. I shied away from setting up my XBees because it seemed like too much of a hassle, but as I continue to work on my robot, I will gladly accept that initial hassle for much speedier future development and testing.
This project is far from finished for me. I would love to make its balancing much more robust and consistent. I’d like to properly mount my IMU and other electrical components (instead of zip ties), make my wiring cleaner and less prone to falling out, and add an additional motor support to prevent the mount from flexing. I’d like to try different control system structures to see how they effect my robot’s sensitivity. I’d like to properly implement remote control turning, and reduce the robot’s drift even more. I’m really proud of what I’ve been able to accomplish and learn in these past 6 weeks. This project is just a base for even more awesome add-ons, and I’m so excited to keep working on it. The possibilities are endless!
Main Project Milestone #2: Balancing!
It took a rough 2 weeks to get to this next milestone, which was assembling my robot mechanically and electrically, and then getting my robot to start balancing on its own.
The first step to achieving this milestone was to debug my robot’s strange behavior — jittering. With my angle to PWM PID loop, the robot would jitter really violently with almost any proportional gain. My instructors and I spent an entire week coming up with many theories and possible band-aid solutions to solve the jittering (as detailed in the video below). The breakthrough came when I decided to graph my serial monitor printouts with a Processing sketch so I could see what was going on (rather than try to decode the numbers flying by on the monitor). When I graphed the pitch measured by my IMU, I saw that it was wildly noisy especially when the motors were running (see below), which in turn caused the robot to respond in the same noisy manner.
Having identified the root problem of my robot’s jittering, I knew I’d have to do a much better job of filtering my IMU. I was using a Kalman filter, which can be powerful but also quite complex to tune (with its Kalman gains, covariance matrices, complicated math I didn’t fully understand yet, etc.). Instead, with the help of a school robotics mentor (thanks Stephen!), I switched to a complementary filter, which was much simpler to understand and tune to get just the right amount of filtering on my IMU readings. In theory, the Kalman filter can do what the complementary filter does, but in practice, it was much easier to write a single line of complementary filter code rather than edit an entire Kalman filter library.
Now that my smoother sensor readings accurately reflected the robot’s movement, I resumed tuning my PID constants. The robot’s jittering was back, but only because of improperly tuned constants. To tune, I increased my proportional gain until the robot began oscillating (jittering); pulled the P gain back a little until the oscillations went away; then brought the integral gain up a teensy bit until the oscillations returned (my I gain could be relatively low because my system didn’t have much steady state error other than fluctuating battery levels); and finally increased the derivative gain in an attempt to dampen the oscillations. The tuning process was largely guess and check because for one, I didn’t have the capabilities or time to mathematically model my system, and the traditional tuning methods used to calculate gains like Ziegler-Nichols were mostly for inherently stable systems, which my robot was obviously not.
I tuned my gains until the robot jittered as steadily as it could. I had a hunch that the jittering was caused by too large of a response near the upright angle setpoint, so with my mentor’s suggestions, I tried dampening the response near vertical by implementing gain scheduling on my proportional gain (adjusting my P gain as my system changed instead of keeping it constant). I tried a linear increase of the P gain, which removed most of the jittering but also made the robot “run away” sometimes when it couldn’t catch up quickly enough past a certain angle. I eventually settled on a custom quadratic function in an attempt to moderate the running away behavior.
The robot was still running away though, so I added an outer PID speed loop, as inspired by previous balancing robot builders, to adjust the angle setpoint slightly when the robot saw it was starting to move around. Another week more of reading encoder values, calculating robot speed, and tuning the outer PID loop, and my robot was balancing in place!
Some awesome things I learned about leading up to this milestone:
- how to graph Serial data in a Processing sketch
- how to revert (albeit messily) with git
- stacks and queues
- analog to digital converters
- low pass, high pass, and complementary filters
- Arduino interrupts, esp. for reading encoders
- calculating speed from encoders by recording time difference between interrupts
- how to write a custom Arduino library (to mimic object-oriented programming)
Main Project Milestone #1: Hooking Up the Sensors and Motors
Hello again! It’s been a little less than 1 week since I started my main project, and things have been going pretty well. My main objective with this first milestone was to gather all of my parts together, play around with them, and hook up the main input (IMU) and output (motors) for my balancing robot.
The journey was relatively smooth, but some issues I ran into leading up to this first milestone were:
1. The FreeSixIMU library doesn’t seem to work with the Arduino Due that I was originally planning on using. When I tried running the library’s included sample sketch on the Due, it would spit out a couple error messages saying so-and-so constant hadn’t been “declared in this scope.” The instructors and I eventually decided to go with an Arduino Uno (for which the library was written). If I find that I really need to switch to a Due (for its more powerful processor), the plan is to go through the library and change it to be compatible with the Due.
2. Making schematics for the robot was harder than I thought it’d be, but definitely worth it. Robin had suggested using EagleCAD to make an electrical schematic for the robot’s wiring, but I had no clue how to use it (sorry Robin!) and eventually switched to Fritzing, which was enough to serve my humble purposes. As for a 3D model of the robot, I gave up after an entire afternoon of juggling Google SketchUp and a free trial of AutoCAD, and settled with making a 2D layout of each of the robot’s 3 levels on SketchUp for reference when machining.
3. I had a little mishap while soldering together the XBee adapter board, which resulted in a lesson on through-hole pin desoldering, broken-off female header pins being stuffed back in, and 2 improvised female header pins out of solid core wire after I permanently damaged or lost the original pins.
Some awesome things I learned about leading up to this milestone:
- how MEMS accelerometers and gyroscopes work
- just plopping a board onto a series of pins isn’t enough, you must solder to create a good enough electrical connection
- making very basic mechanical and electrical schematics using SketchUp and Fritzing, respectively
- removing soldered through-hole components and cleanly desoldering the hole
- basics of how to use an oscilloscope
- why AC can travel further distances than DC
- transistors! BJT and MOSFET
- Kalman and complementary filters (for cleaning up the IMU readings)
- how to use a jigsaw
One final note: the oscilloscope reading of the encoder A and B channel values in the video below is incorrect, so here is a picture I took a little later of the correct readings. I think I connected the oscilloscope probes’ ground pins to something funky and got the AC wave of wall electricity, but I’m not 100% sure.
Starter Project: Ultrasonic Parking Sensor
My starter project was the ultrasonic parking sensor, which detects distance and beeps to notify the user if an object crosses a threshold distance.
I learned a lot about all the different electronic components on the two PCBs, including diodes (rectifier and Zener), capacitors (ceramic and electrolytic), ICs, quartz crystal oscillators, and trim potentiometers. The project also required a lot of soldering; I had soldered before, but never with through-hole components, so it was an interesting experience (I actually enjoyed it quite a bit!). I also learned how to use a power supply provide power to my boards, and I learned (for fun) how to convert AC to DC power using a rectifier, with a diode bridge and a capacitor. That was probably the highlight of the starter project because once I understood how the rectifier worked, everything clicked!
My next step is to begin my main project, a balancing robot.