HeadBot – a Self-Balancing Robot for STEM Learning and Outreach

Introduction: HeadBot – a Self-Balancing Robot for STEM Learning and Outreach

Headbot – a two-foot tall, self-balancing robot – is the brainchild of South Eugene Robotics Team (SERT, FRC 2521), a competitive high school robotics team in the FIRST Robotics Competition, from Eugene, Oregon. This popular outreach robot makes regular appearances at schools and community events where it draws crowds of adults and kids alike. Because the robot is both durable and easy to operate using an Android phone or tablet, children as young as three can drive it successfully. And because the bot can don a wide variety of hats, masks, and other costumes, it’s an entertaining addition to just about any gathering. SERT members use the bot to recruit new team members, and to inspire a general interest in STEM in the community.

The total cost of the project is approximately $200 (assuming that you have a 3D printer and an Android device), although that can be shaved to less than $100 if you have a well-stocked electronics shop with easy access to solder, heat shrink tubing, jumper wires, resistors, capacitors, batteries and a micro USB cable. Construction is straight forward if you have some electronics experience already, and it provides a great opportunity for those willing to learn. For those with a specific interest in robotics, Headbot also provides a good platform for developing skills in Proportional-Integral-Derivative (PID) tuning for feedback control.


Note that the parts list below indicates the number of parts needed of each type, not the number of packages. Some links refer to pages where multiple parts can be purchased as a package (which provides some cost savings) – take care to ensure that you purchase the number of packages necessary to obtain the appropriate numbers of parts.

Electronic Components


    Recommended Tools

    Step 1: 3D Print the Casing, Cap and Electronics Board

    3D print the casing, cap and electronics board. Download the stl files here. Parts should be printed with PLA at a 0.25mm resolution and a 20% infill, with no rafts or supports necessary.

    Step 2: Add Motors, Wheels and Tape to the Casing

    Motors: Place the stepper motors into the bottom of the casing (with the wires exiting the top of the motors) and secure with M3x8mm screws and M3 lock nut washers, using an appropriate hex wrench or screwdriver. Place the wheel hubs on the axles and secure by tightening the set screws onto the flat part of the axle.

    Wheels: Stretch the rubber rings around the outside of the wheel disk. Attach the wheels onto the wheel hubs with the 6-32x3/8” screws. (Wheels may be a tight fit around the hub. If so, position as well as possible, then slowly tighten the screws a little at a time, moving from screw to screw and repeating, to allow the screws to pull the wheel into place.)

    Prepare the cap and PVC pipe: Add duct or gaff tape to the top of the casing so that the cap slides on with a snug, secure fit. Add tape to one end of the 2.5” piece of ¾” PVC pipe so that it slides into the hole in the cap with a snug, secure fit. If needed, tape can also be added to the other end of the PVC to ensure a snug fit into the hole at the base of the head.

    Step 3: Prepare the Electronics Board

    Apply tape to the electronics board: Add duct or gaff tape to the sides of the electronic board so that it will slide into the rails on the inside of the casing with a snug fit.

    MPU-6050 Gyroscope/Accelerometer: Solder the pins to the MPU-6050 Gyroscope/Accelerometer, with the long side of the pins on the same side of the circuit board as the chips. Use an ample amount of hot glue to secure the MPU to the small shelf protruding from the base of the electrons board, oriented so that the pins are to the left of the board as you face the shelf.

    A4988 Stepper Motor Driver: Use a small screwdriver to turn the small current-limiting potentiometer on each A4988 stepper motor driver clockwise as far as it goes. Peel the paper from the tape on the heat sinks for the motor drivers and apply to cover the chips in the middle of the circuit board. Use ample hot glue to secure the motor drivers (with the potentiometers toward the top) to the side of the electronics board opposite the shelf with the MPU, with the pins protruding through the two pairs of vertical slits on the top of the electronics board (take care not to get glue on the pins, which should protrude on the same side as the MPU). Thread a zip tie through the small holes above each motor driver to further secure it in place.

    ESP32 Microcontroller: Place a micro USB cable into the plug on the ESP32 microcontroller (this will be used to hold the end of the circuit board a small distance off of the electronics board, so that access to the plug can be assured after the ESP32 is glued in place). Position the ESP32 with the plug on the right as you face the chip side, and use ample glue to secure it onto the circuit board, with the pins protruding through the horizontal slits in the middle of the board to the side with the MPU (take care not to get glue on the pins, or the USB cable). After the glue hardens, remove the USB cable.

    Step 4: Electronic Circuitry

    General instructions: Follow the circuit diagram (download the pdf below for a high resolution version) to create the wire harnesses necessary to connect the electronic components. Connections between two pins can be made directly with single female-female jumper wires. Connections between 3 or more pins can be made with the more complex wire harnesses described below. Harnesses can be created by cutting female-female jumpers in half, then soldering them together with other components (resistors, capacitor, plugs, short wires) as appropriate. In all cases, use heat shrink tubing to insulate the solder joint.

    Battery Packs: Ensure that the battery packs can slip into the slots at the base of the 3D printed casing. If they do not fit, use a file to shape them until they do. Clip the wires from two of the female JST SM connector plugs (leaving about an inch), and solder one to the leads from each battery pack.

    Main power harness: The main power harness receives input from two male JST SM connector plugs, with the + lead from one plug joining to the – lead from the other in order to connect the two battery packs in series (resulting in a combined 12v input). The other leads are joined through the 100uF capacitor (to buffer voltage spikes; the shorter leg of that capacitor attaches to the – lead, while the longer leg attaches to the +12v lead) and with a voltage divider made up of a 10kohm resistor (connected to the – lead) and a 26.7kohm resistor (connected to the +12v lead), with a female jumper from between the resistors going to pin SVP on the ESP32 (this provides a scaled input with a 3.3v max that is used to provide a readout of the voltage remaining in the battery packs). Additional female jumpers provide +12v (2 jumpers) and – inputs (2 jumpers) to the VMOT and neighboring GND pins, respectively, on the stepper drivers. Additionally, a Universal Battery Elimination (UBEC) is soldered to +12v and – leads of the main power harness (the input to the UBEC is the side with the barrel-shaped capacitor), with the +5v and – outputs of the UBEC soldered to a female JST SM plug.

    5v input to the ESP32: Solder a male JST SM connector plug to two female jumper plugs, to provide inputs to the 5v and GND inputs to the ESP32 from the UBEC (this plug allows for an easy disconnect when the ESP32 is being powered by the micro USB input, for when code is being loaded onto the microcontroller).

    3.3v power harness: Solder 7 female jumpers to connect the 3.3v pin on the ESP32 to the VCC pin on the MPU, the VDD and MS1 pins on each of the stepper motor drivers, and to the male jumper providing power to the LED eyes (allowing for an easy disconnect of the power to the eyes, when the ESP32 is being powered from the micro USB while code is being loaded).

    Ground harness: Solder 3 female jumpers to connect a GND pin on the ESP32 to the GND pins (next to the VDD pin) on each of the stepper motor drivers.

    Stepper enable harness: Solder 3 female jumpers to connect pin P23 on the ESP32 to the ENABLE pins on each of the stepper motor drivers.

    Single jumper connectors: Single jumpers are used to make the following connections:

    • GND on the ESP32 to GND on the MPU
    • P21 on the ESP32 to SCL on the MPU
    • P22 on the ESP32 to SDA on the MPU
    • P26 on the ESP32 to DIR on the left stepper driver
    • P25 on the ESP32 to STEP on the left stepper driver
    • Jumper SLEEP and RESET on the left stepper driver
    • P33 on the ESP32 to DIR on the right stepper driver
    • P32 on the ESP32 to STEP on the right stepper driver
    • Jumper SLEEP and RESET on the right stepper driver

    Connect the UBEC: The female JST SM plug on the output of the UBEC can be plugged into the matching male plug that supplies power and ground to the 5v and GND inputs on the ESP32. However, this plug should be detached when the ESP32 is being powered by a micro USB (e.g., while loading code), or else a reverse-current from the ESP32 to the main power harness will disrupt proper functioning of the ESP32.

    Install the electronics board: Slide the electronics board into the rails on the inside of the casing.

    Connect motor cables: Connect the leads from the left motor to the left stepper driver, with the blue, red, green and black wires connecting to pins 1B, 1A, 2A and 2B, respectively. Connect the leads from the right motor to the right stepper driver, with the blue, red, green and black wires connecting to pins 2B, 2A, 1A and 1B, respectively (note that the motors are wired in mirror image fashion, since they have opposite orientations). Tuck the excess motor wiring into the lower portion of the casing.

    Connect the battery packs: Slide the battery packs into their pockets in the casing, and connect their female JST SM connector plugs to the matching male plugs on the input to the main power harness (the leads from the front battery pack can be guided through the hole in the center of the electronics board to gain access to the plug in the rear). The battery packs can be disconnected to allow for easy insertion of fresh batteries. Turning the power switch on either battery pack to the off position will disconnect the power to the circuit (since the packs are in series) – switches on bot backs must be on in order for the circuit to be energized.

    Step 5: Prepare the Head and Eyes

    Lengthen the hole at the base of the head: Use the 1” spade bit drill to increase the depth of the hole in the bottom of the head, so that it ends above the height of the eyes (it is useful to put a small piece of tape at an appropriate location on the shaft of the bit to indicate when an appropriate depth has been reached). Push the bit 2-3” into the hole before drilling so as not to damage the opening of the hole (you’ll want a tight fit on the PVC pipe that will secure it to the cap of the casing). Save some of the bigger bits of styrofoam to refill the eyes later.

    Create hooks for pushing/pulling wires: On one end of a stiff metal rod, bend a small N shape (this will be used to push the wires for powering the LED eyes through the styrofoam head). Bend a small hook on the end of the other stiff metal rod (this will be used to fish out the wire from the hole in the bottom of the head).

    Run wires: Tie large loops in the ends of the red, yellow, green and blue wires, using tight knots. Working with one wire at a time, hook the loop on the end of the N shaped hook and push it through the eye of the head, keeping the path horizontal and aiming toward the hole in the center of the head. When the wire is pushed into the hole, use the hooked rod to grasp the loop from the bottom of the head, and pull it from the hole, extracting the other rod from the eye as well (leaving 2-3 inches of wire at the bottom of the head, and hanging out of the eye). Repeat the process with the other three colored wires, following the same path from the eye to the center hole (use a labelled zip tie to secure these wires together and indicate which eye they control). Repeat with 4 more wires in the second eye.

    Attach RGB LEDs: Shorten the leads on the RGB LEDs, making sure to mark the common anode (the longer lead, and note the location of the R (the single lead on one side of the anode, as shown on the circuit diagram) and G and B leads (the two leads on the other side of the anode). Solder the appropriate wires that hang from one of the eyes to the LED (red to the anode, yellow to R, green to G, and blue to B), insulating the connections with heat shrink tubing. Push the leads of the LED into the head, but leaving it to protrude a bit until it can be tested. Repeat the process with the other LED and the wires from the other eye.

    Attach jumper wires: Solder a 220 ohm resistor and a jumper wire with female connector onto each of the yellow, green and blue wires that protrude from the bottom of the head. Join the two red wires, and solder to a jumper with a male connector (note: this is the only male jumper needed in the circuit).

    Connect jumpers and attach head: Route the jumpers through the PVC tube in the cap and slide the PVC into the hole in the head, securing it to the cap. Attach the male power jumper to a female jumper on the 3.3v power harness, and the female RGB jumpers to the ESP32 (yellow, green and blue wires of the left eye to P4, P0 and P2, respectively, and yellow, green and blue wires of the right eye to P12, P14 and P27, respectively). Finally, attach the head/cap onto the main casing.

    Step 6: Upload the Code and Install the Driver Station

    Installing the HeadBot code on the ESP32: Download and install the Arduino IDE on your computer. Visit https://github.com/SouthEugeneRoboticsTeam/ursa and click “Download Zip” under the green “Clone or Download” button. Move the folder zipped inside to anywhere on your computer, and rename it to “ursa”

    Open ursa.ino using the Arduino IDE. In the preferences menu under “File,” add https://dl.espressif.com/dl/package_esp32_index.json to the “Additional Boards Manager URLs.” Install esp32boards by Espressif Systems under Tools>Board manager. Choose “esp32 dev module” under Tools>Board. Install the PID by Brett Beauregard library by clicking on “Manage Libraries” under the “Sketch” menu.

    Connect to the ESP32 using the USB-MicroUSB cable. Select the board under Tools. Press and hold the small button labelled "I00" next to the micro USB connector on the ESP32, then press the upload button on the Arduino IDE, and release the "I00" when the Arduino IDE says that it is "Connecting...". After the upload is complete, the MicroUSB cable can be disconnected.

    Installing the HeadBot driver station: Download and install Processing on your computer. Visit https://github.com/SouthEugeneRoboticsTeam/ursa-ds-prototype and download the code. Open "ursaDSproto.pde" using the Processing IDE. Install the Ketai, Game Control Plus, and UDP libraries via Processing's library manager (Sketch>Import Library). If you are running the drive station on your computer, select Java Mode in the drop down menu in the upper right of the Processing window; to run it on Android, install Android Mode for Processing by clicking on the "Java" dropdown menu in the upper right. Then, connect the device, enable USB debugging, select Android Mode. To run the drive station, click "Run Sketch." If your computer is connected to an Android device, the driver station will be installed onto it.

    Step 7: Start HeadBot and Tune PID Values

    Starting up: Make sure that the battery packs are connected, and that the UBEC output is connected to the ESP32 input connector. With Headbot lying on its side in a stable position, power up by sliding the power switch on both battery packs to the ON position, leaving Headbot stationary for a few seconds while the gyroscope initializes. After a short delay, you should be able to see the Headbot wifi signal (SERT_URSA_00) on the device you’ll be using to control the bot – select it, and enter the password “Headbot”. After a connection is made, run the drive station app on your phone/tablet, or run the drive station script in Processing on your computer. After the program starts up and a connection is made, you should see the “pitch” value start to respond, showing Headbot’s tilt.

    Setting PID values: To be able to control Headbot, you’ll need to tune the PID values. For the version of Headbot described here. Clicking in the square in the upper left of the drive station will bring up sliders for adjusting the values. The top three sliders are for adjusting P, I and D for the Angle (PA, IA and DA) – these values are of primary importance for allowing Headbot to maintain its balance. The bottom three sliders are for adjusting P, I and D for the Speed (PS, IS and DS) – these values are important for allowing Headbot to correctly adjust its driving speed according to the joystick input. Good starting values with this version of Headbot are PA=0.08, IA=0.00, DA=0.035, PS=0.02, IS=0.00, and DS=0.006. After setting these values, click the “Save Setting” box in the upper left of the drive station (this saves the settings in a more durable form that will survive a reboot of the bot).

    Trying things out: Click on the Green Joystick bar in the upper right of the drive station to bring up a joystick for controlling the robot. Stand Headbot up in a near-balanced orientation, and press the dark green Enable square in the upper right (pressing the neighboring red box will Disable the bot). If all goes well, you’ll have a self-balancing Headbot, but more than likely you’ll need to fine tune the PID values. There's usually little I or D compared to P, so start there. Too little, and it will not be responsive. Too much and it will oscillate back and forth. Begin Start with the Angle PID values, making small changes to see how things are affected. Some D term for the angle loop may help minimize oscillations, but a small amount can quickly bring in a lot of jitter, so use sparingly. If the Angle values are correct, Headbot should resist some gentle shoves without falling. Small twitches are to be expected while Headbot is balanced, since the stepper motors are moving in half-steps of 0.9 degrees with each adjustment.

    Once balance is achieved, try driving by making small movements of the joystick, making small adjustments of the Speed PID values so that the bot responds in a smooth, graceful way. Increasing the I term may be helpful to counter the robot not sticking to the set speed. Be warned, though – changes to the Speed PID values will require further adjustments to the Angle PID values (and vice-versa), since the PID loops interact.

    Changes to the overall weight and weight distribution of Headbot (such as when wearing glasses, masks, wigs or hats) will require further tweaking of the PID values. Further, if costumes throw off the balance too much, you might need to tweak the starting pitchOffset value in the ursa.ino code and reload the code onto the ESP32.

    Robotics Contest

    Runner Up in the
    Robotics Contest

    Be the First to Share


      • Make it Real Student Design Challenge #3

        Make it Real Student Design Challenge #3
      • Explore Science Challenge

        Explore Science Challenge
      • Home Decor Challenge

        Home Decor Challenge



      10 months ago

      Hello. This is a wonderful project. I am in the process of reproducing it. I am using the Lolin NodeMCU instead of the esp32 used here. Therefore I made a few changes including the pins for the SCL and SDA from the MPU since the Lolin doesn't have pins up to 21 or 22 like used here. How can I change the pins to another GPIO? I saw that the scl and sda pins are set in the wire.h library. Is there a way for me to modify it?

      South Eugene Robotics Team - FRC2521
      South Eugene Robotics Team - FRC2521

      Reply 10 months ago

      Dear thadeoarlo,
      I'm glad you like the project! You might be able to specify which pins should be used for SDA and SCL by adding them when Wire.begin(); is called (line 5 in mpu.ino in my code), so it looks like Wire.begin(sdaPin,sclPin); https://arduino-esp8266.readthedocs.io/en/latest/l...
      I'd love to get updates as you get your project working, and please don't hesitate to ask if you have any more questions. Good luck!


      1 year ago

      Wow, I loved this! Well done, team. As a former FIRST coach, judge, and mentor, I can tell I would have been stoked to have y'all as a team. Fun fact, I used to be the advisor of South Eugene's original rock climbing and mountain climbing club, SMC (South Mountaineering Club). But that was well before you all were born. Don't know if it's still around. I'm glad FIRST is!


      1 year ago

      Wow, I'm ready to make a horror movie with these fellas!

      Meredith Clark
      Meredith Clark

      1 year ago on Step 7

      Delightfully disturbing. But I really shouldn't have looked at the "head and eye assembly" before bed ... *shudders*


      1 year ago

      This is both creepy and amazing ::slow clap::