In 2007, I helped with this other self-balancing scooter build at the MIT Edgerton Center, and since then we've gotten many interesting questions by email about how it works. Baseline self-balancing functionality is actually surprisingly simple, and maybe the purpose of this Instructable is to take this simplicity to the extreme. To that end, I present: Seg...stick.
Segstick is a self-balancing...well, literally some kind of broomstick I found in the MITERS workshop. It is powered directly by two DeWalt cordless drills chucked to two 6" wheels. The controller is an Arduino. Additional supporting devices include an Inertial Measurement Unit (IMU) from Sparkfun and two motor drivers from Pololu.
Is it the best DIY self-balancing vehicle ever? No, not even close. But it only took about two days to build, and it is stripped down to the bare necessities. Thus, I hope to point out the modules and concepts involved in making any self-balancing vehicle rather than the specifics of this one. To start with, some physics...
Step 1: Physics Says It's Easier to Build a Full-size Self-balancing Thing.
For one, the mechanical time constant of a small self-balancing robot is faster. Imagine the difference between trying to balance a broomstick on your finger and trying to balance a pencil on your finger. The controller for a small robot has to be that much faster to keep up with the physical system.
Additionally, a human rider takes some of the burden off the electronic controller, since the human mind is a pretty good controller too. For example, the accelerometers used on self-balancing platforms can't distinguish between standing still and moving at a constant velocity, but a human rider can. The human rider can adjust by leaning forwards or backwards to speed up or slow down.
So, this Instructable focuses on a full-size vehicle, albeit a relatively small one. In the final step, there are some links to balancing robots.
Step 2: Gathering.
Big-Ticket Items ($411):
2x DeWalt DC759 18V Cordless Drill (eBay, $60ea new w/o battery or case)
1x DeWalt DC9096 18V Battery (eBay, $40)
2x Polulu High-Power 18v25 Motor Driver ($50ea)
1x Gravitech Arduino Nano 3.0 ($35)
1x Sparkfun Razor 6DOF IMU ($60)
2x AndyMark 6" FIRST Wheel ($13ea)
2x AndyMark 1/2" Keyed Hub ($15ea)
2x Mounted 1/2" Bearings (5913K61)
4x 1/2" Shaft Collar (9414T11)
1x Precision 1/2" Keyed Shaft (1497K131)
1x 1/8" Key Stock (98535A130)
- Plywood (3/4", 1/2")
- Hose Clamps or Extremely Large Zip Ties.
- 1/4-20 Bolts and Nuts
- Breadboard or Protoboard
- Wire, Heat Shrink, Solder
- 5k or 10k Potentiometer.
- Polarized 2-Pin Power Connectors (e.g. Deans)
- Heat Sink Material
And Most Importantly:
- A Stick.
Step 3: Drive Motors, Choosing.
Cordless drills are not so great because the chuck often has a lot of backlash, which makes controlling the vehicle difficult. I've been informed that some low-end drills actually have less backlash because they don't have an anti-backdrive feature on the chuck. You might also be more willing to sacrifice a cheap drill like this than a nice, working DeWalt.
Another option is to use gearmotors from the robotics market, such as the BaneBots P80. You can see these deployed on our first balancing vehicle, as well as Charles Guan's Segfault. These gearboxes give you considerably more gear ratio options (12:1, 16:1, 27:1) and will have less backlash than the DeWalts. The downsides are a higher price and more fabrication required for mounting and attaching a wheel.
Step 4: Drive Motors, Modding.
The mod is pretty quick: After opening the drill case (you will need a Torx driver for the DeWalt case), disconnect the motor leads from the trigger controller. File down a slot in the two halves of the case through which these leads can be passed. Then, reassemble.
Step 5: Drive Wheels.
It can be tricky to find good drive wheels for a project like this. The vast majority of wheels you might find lying around are caster wheels, with bearings built in. Drive wheels have some way of transmitting torque from a rotating shaft to the wheel, such as a key. The DeWalt drill chucks can accept up to a 1/2" keyed shaft. Some other drills may only go up to 3/8"...avoid these.
Here are some good places to look for drive wheels:
AndyMark, a supplier for FIRST robotics parts. Segstick use 6" AndyMark wheels with a keyed 1/2" hub.
Skyway also sells nice drive wheels in larger sizes.
Of course, you can also make a caster wheel into a drive wheel by fabricating and/or attaching a hub. Depending on your level of machining experience, this may be easier than trying to find a drive wheel exactly the size you want.
Step 6: It's Starting to Look Like A...something.
The process: Cut a piece of 3/4" plywood to the dimensions for the deck (where you put your feet), which will also hold the drills, bearings, and eventually the electronics. Then, mark out some holes for the bearings and for extra-extra-large zip ties to hold the drill in place. Hose clamps might work too. Then, drilled all those holes.
Pro Tip: If you leave one drill unmodified until the very end, you can use it to make everything else. ;)
The bearings are attached with 1/4-20 bolts. In this case, they require 1/2" spacers to match the height of the drill. While fastening everything down, it's useful to put the drive shaft into the bearing and drill chuck, and possibly even to have the drill motor running. This ensures good alignment as things are zip-tied/screwed/bolted/what have you.
When everything is ready to go, the wheels go on with locking collars on either side to constrain them axially. Don't forget the key! And don't forget to tighten the chuck...a lot!
Step 7: And Now, the Hard Part.
Usually, the controller is some kind of microprocessor. In some rare cases, one might be compelled for unknown reasons to do it entirely with analog circuitry. Segstick instead uses a more conventional digital controller implemented on everybody's favorite: the Arduino. Specifically, it uses the Arduino Nano 3.0 from Gravitech. But any Arduino will do.
For sensing, Segstick uses the Sparkfun Razor 6DOF IMU. Really, you only need one accelerometer axis and one gyro axis, as will be discussed in the next step, but this package is so convenient and allows you to mount the board any way you want. Since it uses all 3.3V sensors, it will need to be powered from the Arduino's 3.3V output. Each sensor outputs an analog voltage which is read in by the Arduino's analog to digital converter (ADC). More on that in the next step.
For controlling the motors, Segstick uses two Polulu High-Power 18v25 motor drivers. These are tiny but powerful reversible motor controllers capable of providing up to 25A each. I decided to add a heat sink to them, but they seem to run cool enough without it. They do require large-gauge wiring to the battery and to the drill motor leads.
The circuit schematic is shown below. How you implement it (breadboard, protoboard, printed circuit board) is up to you. I did it on a vector board that I later cut to size. Soldered connections will generally be more reliable than breadboard-type connections on a moving vehicle, so I'd recommend using sockets for the components but directly soldering wired connections.
Step 8: Software Overview.
The feedback controller really has two critical components: a digital filter that merges signals from the accelerometer and the gyro into a reliable angle estimate, and a proportional-derivative (PD) control algorithm that determines the corrective action to create by outputting voltage to the motors. These two components are the key to making a good self-balancing platform.
Other less glamorous but also important ancillary functions are signal input and scaling, steering, PWM generation, output limiting, and debugging. I'll briefly mention these, too, in the next few steps.
Step 9: Two Sensors, One Angle.
The reason for using two sensors even though there is only one relevant physical variable (angle) is because each type of sensor has advantages and disadvantages by itself. By mixing the best parts of each together, a better overall estimate of the angle is achieved. I wrote this all up in this white paper, but here I will give a brief summary.
It measures acceleration, right? Well, not really. It measure force per unit mass. So it will measure the force due to gravity as if it were an actual acceleration. The sensitivity for the Sparkfun Razor IMU is given as 300mV/g, meaning the output will change by 0.3V per 9.8m/s^2 of acceleration.
How is this converted into an angle? Well imagine using the accelerometer axis that is pointed in the direction of travel of the vehicle. As the vehicle pitches forward, the axis sees positive force due to gravity. As the vehicle pitches backwards, it sees negative force. It's tempting to say that the gain should be 300mV/90º, since pitching 90º corresponds to 1g. However, it's the slope of the output near 0º that matters, and thanks to trigonometry this slope happens to be 300mV/rad or 300mV/57.3º. See the image below for an illustration of this.
Since the Arduino's ADC gives a 10-bit value based on a 5V reference, you can calculate the gain on the raw ADC value by:
(57.3º/0.3V)*(5V/1024LSB) = 0.932º/LSB
LSB (least significant bit) is just a way of saying one bit. This is the value by which to multiply the raw analog value to get an angle in degrees. Note that you also need to subtract the zero angle offset from the analog signal. This is best found experimentally, by holding the platform at zero angle and reading off the value.
So why not just use the accelerometer to measure the angle and be done? The problem is that the accelerometer can't tell the difference between gravity and actual acceleration. So, if the platform is perfectly level but the vehicle accelerates forwards, it will register the same as tilting backwards. Taking a long-term average, though, the only "acceleration" that remains is gravity. Unfortunately, long-term averaging is not conducive to snappy feedback control. Enter...
More accurately it should be called an angular rate sensor, since it has little to do with an actual flywheel-based gyroscope. It reports back a signal proportional to the rate of rotation. On a balancing platform, its sensitive axis would be parallel to the axis of rotation of the wheels. The Sparkfun IMU gyros have a sensitivity of 3.33mV/º/s on the 4x channels, meaning the output changes 3.33mV for every º/s of rotation.
Since the Arduino's ADC gives a 10-bit value based on a 5V reference, you can calculate the gain on the raw ADC value by:
[(1º/s)/0.00333V]*(5V/1024LSB) = 1.466(º/s)/LSB
This is the value by which to multiply the raw analog input to get an angular velocity in degrees-per-second. Like the accelerometer, the zero offset for the gyro must be subtracted first. It can be found by holding the platform stationary and reading off the analog value.
To get from degrees-per-second to degrees, the gyro signal can be integrated. For every step in time, the gyro signal multiplied by the duration of time between steps gives an incremental change in angle. The total angle is the running sum of these increments. This causes a problem, though: If the gyro signal is not exactly zero when the platform isn't rotating (and it never will be) the integration will drift. With no absolute reference, there is no way to correct for this drift with the gyro signal alone. However, for short durations, the gyro provides a very sensitive angle estimate that is immune to noise from horizontal acceleration of the vehicle
So one sensor is great for short-term, fast-response angle estimates. The other is great for long term, drift-free absolute angle averages. Are you starting to see where this is going?...
Step 10: A Very Flattering Filter.
angle = A * (angle + rate * DT) + (1 - A) * (float) accel_raw * A_GAIN;
Okay, so it's a long line. You can also do it with an op-amp or two.
This filter does exactly what is necessary in this scenario: it favors the gyroscope reading for short time durations and the accelerometer average reading for long time durations. Let's break it down:
A is the factor that determines the cutoff time for trusting the gyro and filtering in the accelerometer. It's always between 0 and 1, usually close to 1. In this case, A is defined to be 0.962. This means that at every time step, 96.2% of the new angle measurement comes from the old angle measurement plus the integrated gyro measurement. The remaining 3.8% comes from the accelerometer. This slowly averages in the accelerometer over many time steps.
DT is the time in seconds between program loops, the time step. Here it is defined to be 0.020 and is set by delay(20) at the end of the loop. The code in the loop itself take much less than 20ms, so the delay dominates the time step.
rate is the gyro reading, converted to degrees per second.
accel_raw*A_GAIN is the accelerometer reading, converted to degrees. It is very important that these two be in the same unit base before adding together. (You can't add apples to oranges.)
The time constant of the filter is the duration of time at which the gyroscope reading starts to be filtered out heavily and the accelerometer reading starts to be averaged in heavily. It's actually a continuous process, but the time constant is a single measure of where the balance begins to shift. The time constant is:
tau = DT*(A)/(1-A) = 0.5s
So, for this filter, the gyro is trusted for about 0.5 seconds and the accelerometer start to average in significantly after that. This value can be tweaked by changing A.
Step 11: The Control Part of the Controller.
Proportional. This is a corrective action that scales proportionally to the angle. If the stick leans forward twice as far, the corrective action is twice as great. This is like the "spring constant" of the system, applying a restoring force as the stick moves away from vertical.
Derivative. This is a corrective action that scales proportionally to the derivative of the angle, or the angular rate. If the stick is falling twice as fast, the corrective action is twice as great. This is like the "damping constant" of the system, applying a force that resists rotation in either direction.
Together, this forms a mass-spring-damper system, except with virtual springs and dampers. The relative spring constant and damping constant affect how much the system oscillates as it corrects for angular displacement. Simple, right? Here's the code:
output += angle * KP + rate * KD;
Yep, simple. output is the command to be sent to the motors. KP and KD are tweaked until it balances (or goes goes totally unstable). One subtlety here is that the output command is incremented by the value output by the PD controller. So, if the angle is held at some offset from vertical, the motor command will keep increasing. It's like adding an extra integral to the system, as shown in the block diagram below.
Usually in feedback diagrams, the feedback path has a negative sign, but it really depends on the way the motors are set up. Choosing the sign for output can either be done in software (-= instead of +=) or in hardware by just swapping the motor leads. If both wheels start moving the wrong way in response to the angle, you can flip the sign. If one wheel starts moving the wrong way, you can just swap its motor leads.
Step 12: Steering, and Other Loose Ends.
Outputting to the motors is done by setting a pulse width modulated (PWM) signal on the motor controller inputs. In Arduino land, this is done with analogWrite(). However, the default Arduino PWM frequency is way too low for motor control, so I added some direct register manipulation to force it to be 15.625kHz. Since the controllers are reversible, I use a small forest of if statements to figure out what to put on the DIR pins and whether or not to invert the output command.
One very important part of writing good control software is managing data types. You can see in the code that I often explicitly typecast to make sure I'm getting exactly the data type I want at every step of the calculation. Nothing is worse than having your controller freak out because a variable overflowed. For that reason, I also apply limiting at each step to ensure that the variables stay within appropriate ranges. For example, analogWrite() takes an integer value between 0 and 255, so I limit the outputs to this range at every step of the calculation.
Step 13: Sticking It All Together.
Here's a quick video of the Segstick jerkily wandering around:
Step 14: Links to Better Self-balancing Things.
Self balancing one wheeled electric skateboard - Awesome build by XenonJohn.
Easy build self balancing skateboard/robot/segway platform - also XenonJohn.
Angle measurement using gyro, accelerometer and Arduino - More complementary filter.
Some close to home:
The DIY Segway - MIT Edgerton Center Summer Engineering Workshop, 2007.
Segfault - Charles Guan's totally analog balancing scooter.
The Uno - By BPG Motors.
The original [copy]:
Building a Balancing Scooter - Trevor Blackwell.
Balancing robot Wheeley - I like the technical explanation.