In the video you can see that the robot stays at roughly the same spot on the floor and handles a lighter push without any problem. To achieve this I have two cascade PID controllers and low pass filter on both wheel speed and the robot's angle.
Microprocessors
As an Arduino does not have a lot of processing power, I chose to use a total of 3 microprocessors:
- A standalone Arduino Uno takes pulses from the tachometer on each wheel and converts it to a speed. The speed is sent to the main micro processor.
- One more stand alone Arduino Uno to view and adjust parameters. Also drives the display. The parameters are sent to the main micro processor.
- Arduino Leonardo is the brain. It receives information from the console and the engine speed sensor via I2C.
Basic control theory
Two cascaded PID controllers. The first has speed as setpoint (always 0 in this case) and angle as output. If the robot is moving forward, the controller will have a positive input value and send a negative output value. This means that the robot will want to lean back to slow down.
PID number 2 takes care of the robot's angle relative to the floor. The setpoint is the output of the previous PID controller. Normally the set point will range from -3 till 3. Zero corresponds to the robot standing completely straight up. The output is connected to the engine management and rtos from -100 till 100. -100 corresponds to full voltage to the motors in reverse direction.
To get cleaner inputs I use FIR filters for both angle and wheel speed. Low-pass filter blocks rapid change (for example, sensor noise) from passing through.
For the angle relative to the floor, a IMU with accelerometer and gyro is used. A complementary filters combines the signals to give an useful value.
Source
I had the objective that all code for this project should be open sourced and available for download from github. The readme contains links to libraries I have used.
Improvements that could be made
- Better parameters to the FIR filter. Much could probably be done on the wheel speed.
- On-the-fly programming over the air with Xbee. This means that you can send new code to the robot without USB cable. Will make programming more flexible.
- Radio control would be nice.
Photos
- Building the arduino for sending speed from encoders via I2C
- Motor speed arduino in place
- Arduino Leonardo with motor shield
- IMU with 6 degrees of freedom
- Console for configuring parameters
Components
- 3 plates in carbonate.
- 2 threaded rods, nuts and washers
- Arduino Leonardo
- 2 st A standalone Arduino
- Breadboard 830 seq
- Breadboard 400 seq
- Pololu 12V, 29:1 Gear Motor w / Encoder
- Pololu Wheel 90 x 10mm Black (Pair)
- Pololu Universal Aluminum 6mm Mounting Hub (4-40)
- Pololu 37D mm Metal Gearmotor Bracket (Pair)
- 6 Degrees of Freedom ±2000° / sec ±16g IMU – ITG3200 / ADXL345
- Arduino Motor Shield rev 3
- BAT-01 Battery Pack NiMH 12V 1600mAh
- Nokia 5110 display
- + cables, Button, resistance and other bits
I am also publishing cad and drawings.















Really fun to watch. Good job
Tack!
Fun!
Do you think it would be easier to get the robot to balance “stable” the rods are not flexade as mkt… more shelves?
The bars are fairly stable even though it may not be visible in the video. What I think would make the biggest difference right now is better filtering of the input signal from the wheel speed. Better pass filtering would probably make time more enjoyable.
!!!
You wrote:
–>
The setpoint is the output of the previous PID controller. Normally, the setpoint will vary between -3 och 3 där 0 corresponds to the robot to stand completely straight up.
<–
I don't understand och or dar and a google search hasn't helped. I wonder what these terms mean. Any chance you could point me to a reference or give me a short explanation?
Great project. Thanks for sharing.
It is a bad automatic translation. Should be “Normally the setpoint will vary between -3 and 3 where 0 corresponds to the robot standing completely straight.”. So the output from the first PID will be an angle between -3 and +3 angles.
1. arduino for reading accelerometer and gyro, convert them to angles in degrees then send to the leonardo
2. another arduino for just reading the motor speed and direction, then send it to leonardo
3. the leonardo then read the PID parameters for the wheel and angle, then control motors? is this the way it works? or you can elaborate further?
No but quite close.
1. Arduino for reading motor speed and direction.
2. One arduino for the console. Drives the lcd and the buttons.
3. Arduino Leonardo with motorshield as the brain. Communicates with 1 and 2 via i2c. Reads angle from the IMU (also via i2c). Handles the PIDs and outputs voltage to the motors.
No but quite close.
1. Arduino for reading motor speed and direction.
2. One arduino for the console. Drives the lcd and the buttons.
3. Arduino Leonardo with motorshield as the brain. Communicates with 1 and 2 via i2c. Reads angle from the IMU (also via i2c). Handles the PIDs and outputs voltage to the motors.
——-
If this is the case, I can only use two arduino if I will be using potentiometers to set the PID values and no LCD display.
All PID’s exist in the leonardo and even the reading of the angle from the IMU only the motors has dedicated mcu for interpretation of the wheel encoders..
In your source codes, which is for the 1st arduino, 2nd arduino and for the leonardo? thanks.
Yes you can skip the lcd if you want.
I have added the code for the wheel encoders to github. One folder for each arduino. https://github.com/sebnil/Selfbalancing-robot
I was wondering if you might help me. I have succesfully used my arduino and a 5DOF analog IMU to accurately get my robots tilt with a complimentary filter.
My difficulty is making the thing balance. My first attempt was to simple use the map function input from the IMU to 0 to 255 and sent it to a Sabertooth motor controller. It kind of works but was very jittery.
Then I advance to the PID library. But very hard to tune. It drifts. I can send my code and processing graph. Any tips?
Do you have any feedback from the speed of the robot? Mine drifted a lot and that is why I have two cascaded PIDs instead of just one. Here is a video without feedback from wheel speed http://www.youtube.com/watch?v=gl07a232G98
You can see that it drifts quite a lot.
I do have the ability to get encoder position and but haven’t implimented yet. I’m having a great deal of difficulty with basic balancing. If I could make mine balance like yours in the video link with drift I would consider myself very well off.
I used the PID library developed by Brett but can’t make it work.
What did you use for input, setpoint and tuning.
I used an a mapped quantity from the IMU for input: input = map( compAngle, 57,117,0,255);
That’s 8 bit resolution to an adjusted verticle angle of 87degrees. I used 127 as the setpoint.
Problem is the PID output is zero at verticle and scale for one direction of tilt to 255 but won’t go below zero in the oposite direction.
> What did you use for input, setpoint and tuning.
Input is the angle. 0 means it is standing straight.
Setpoint 0.
For tunings see https://github.com/sebnil/Selfbalancing-robot/blob/master/selfbalancingrobot/configurations.txt
>Problem is the PID output is zero at verticle and scale for one direction of tilt to 255 but won’t go below zero in the oposite direction.
This is a problem. You will not get it working without an input error that is either negative or positive depending on the angle. Try to rotate the dof to see if that solves the problem.
OK I tried again using the raw angle as input and changing setpoint to zero (vertical). The input error as I tip robot side to side has both positive and negative values. But the output increases in value as robot tips to one side but once I reach the setpoint zero and tip to other side the output will not change.
It’s definitely the problem, but it’s the PID. Or a least that’s what the processing graph shows. And correlates to the documentation that output will be 0 to 255. I’m just stuck on how to make zero degree tilt equal 127 output. Which would be balanced for the motors.
The issue is resolved. I just needed to use the SetOutputLimit function. Now the output is scaled.
May I ask how did you tune the PID?
Good to hear! I tuned it with the console on the top just trying new values. I figured that I needed quite large values to keep it stable. Perhaphs I will do a proper mathematical model in the future but probably not.
can u tell me the name of microcontroller gyrometer and accelerometer and pid use in it… so that i easily purchase thm from market.. thanx