Introduction: Self-Balancing Robot

First of all I want to apologize for my English, if you don't understand something, please, ask.

I know that a self-balancing robot is not new, but when i started this project i found a lot of information, but never in the same site, i had to search a lot to join all information in a single project. Becouse of that i'm making this instrucctable, to show you all the information i get, with all detail, to make that robot.

This project is for all of you that like's to make robots but don't have many things, and by things i mean time, money and robotics knowledge. In this project i'm gonna show you the easiest way to do a simple, cheap and useless two wheels self-balancing robot.

I explain the materials and electronics used in the project, how and where to buy or create it and i'm gonna tell you my experience and tips along the way to create this project.

Step 1: Materials

The materials i used for this projects were the cheapest i could get, but there are even cheaper. Principally i buy from two places: DX, a Chinese online store with lots of very cheap electronic (arduino, drivers, sensors,...) and free shipping (that's a good point); and Robot-Italy, an Italian store specialized in kits for robotics.

From Robot-Italy i get the chassis from a kit for a 3 wheeled robot and the battery, a LiPo of 1300mAh

Chassis:

http://www.robot-italy.com/en/magician-chassis-kit...

Batery:

http://www.robot-italy.com/en/fullpower-batteria-l...

You can buy the Arduino form both stores, in Robot-Italy have the official version (23€) and in DX have the Chinese version (10€), in not gonna open a debate but i used both and they just work fine:

http://www.robot-italy.com/en/arduino-uno-r3.html

http://www.dx.com/p/uno-r3-development-board-micro...

The last two thing left are the IMU sensor and the motor driver, both bought from DX:

Motor driver:

http://www.dx.com/p/l298n-stepper-motor-driver-con...

IMU sensor:

http://www.dx.com/p/gy-80-bmp085-9-axis-magnetic-a...

Making a price summary:

Arduino UNO --------------------> 10-20 €

IMU sensor --------------------> 15 €

Motor driver --------------------> 4 €

Chassis --------------------> 19 €

Battery --------------------> 10 €

______________________________________

TOTAL : 58-68 €

I used materials as cheap if i could but you can use whatever you have, i saw people using servo motors and stepper motors with a good result. This motor driver maybe is much bigger than the needed one, with an L293 it can work, you can make your own chassis and use other type of sensors.

Step 2: Phisics

The physics for this robot are simple, the robot stand in two points lined, the wheel, and i tends to fall and lose his verticality, the movement of the wheel in the direction of the falling rises the robot for recover the vertical position.

A Segway-type vehicle is a classic inverted pendulum control problem that is solvable in two degrees of freedom for the simplest models. The vehicle attempts to correct for an induced lean angle by moving forward or backwards, and the goal is to return itself to vertical. Or at least not fall over.

For that objective we have two things to do, in one hand we have to measure the angle of inclination (Roll) that have the vehicle, and in the other hand we have to control the motors for going forward or backwards to make that angle 0, maintaining his verticality.

Angle Measurement:

For measure the angle we have two sensors, accelerometer and gyroscope, both have his advantages and disadvantages. The accelerometer can measure the force of the gravity, and with that information we can obtain the angle of the robot, the problem of the accelerometer is that it can also measure the rest of the forces the vehicle is someted, so it has lot of error and noise. The gyroscope measure the angular velocity, so if we integrate this measure we can obtain the angle the robot is moved, the problem of this measure is that is not perfect and the integration has a deviation, that means that in short time the measure is so good, but for long time terms the angle will deviate much form the real angle.

Those problems can be resolved be the combination of both sensors, that's called sensor fusion, and there are a lot of methods to combine it. In this project i try two of them: Kalman Filter, and complementary filter.

  • The Kalman filter is an algorithm very extended in robotics, and offers a good result with low computational cost. There is a library for arduino that implements this method, but if you want to learn more about that method or implement it by yourself look at this page.
  • The Complementary filter is a combination of two or more filters that combines the information from different sources and gets the best value you want. It can be implement in only one line of code .For more information visit this page.

angle = A * (angle + gyro * dt) + (1 - A) * accel;

where A is normally equals to 0.98.

First i tried to use Kalman filter but i don't obtain good results, my angle was calculated with a little delay and it affect the control. The Kalman filter has three variables you can change based on the parameter of your sensor, and varying this you can obtain better result, i tried to change that values, but i don't get better results so i decided to implement the complementary filter, so much easier and it have less computational cost. The complementary filter works fine for me.

Step 3: Chasis

For create the main structure of the robot i used the kit previously mentioned, this kit contains a simple plastic chassis with some nuts and screws, two wheels with two motors, one battery socket, one caster wheel, and even 2 little wheels for encoders. The last time i checked the price was 19€.

Tip: If you like to make your own chassis with wood, aluminium, or other materials and if you have old DC motors and wheels you can save some money.

This kit is prepared to make a 3 wheel vehicle but we gonna change the plans a little to adapt it to our project.

From the kit there are part i don't use, like the caster wheel, two motor fastenings and some nuts and screws. I put the two motor in the lower part of the structure and closed it with the two grat plastic parts, keeping it together with the screws.

The electronics and the battery creates a tower in the upper part of the structure, i used Meccano to build the tower where the PCBs and the battery were located, but you can use other materials, like plastic, wood metal, or even only tape surrounding everywhere, like a gigant ball of tape.

And Voila! chassis done, not so difficult for the moment, let's see next step.

Tip: When you build your robot you have to try to put the mass center the higher you can, putting heavy things in the upper part of the robot, like batteries. Remember that the more height of the center of mass the more stability the robot will have.

Step 4: Electronics

The electronics we are going to use in the project are simply three, an arduino UNO (you can use whatever arduino you have, doesn't matter if isn't arduino UNO), a motor driver, in this case a L298, and finally an IMU.

We use a commercial motor driver based on the chip L298, maybe much powerful that we need for these motors but i have it and it works fine. If you want to make you own DC motor driver you can use some transistors and make a H-bridge or use a L293, cheap and easy to use, there is an instructable where you can find information how to do it.

For the IMU i used the cheapest 10DOF (10 Degrees Of Freedom) i find, the chinese GY-80 with 3-axis accelerometer, 3-axis gyroscope, magnetometer, barometer and temperature sensors. We use only accelerometer and gyro so you can save money buying another IMU, like the MPU-6050, a 6DOF IMU for only 3.63€!!!!, or accelerometer and gyro for separate.

The IMU is connected to the arduino using I2C bus (If you want to lerarn more about I2C look this instructable), so we need 2 wires for communication (SDA and SCL) and 2 wires for power, it use 3.3V so we need 3.3V wire and GND.

The motor driver take power directly form the battery so don't have to connect arduino's power to it (i mean the 5V form the arduino), but we need 6 wires to control it, 3 for each motor, one for send the PWM signal for control the motor velocity, and for indicate the direction we want the motor to spin.

Tip: Try to position the IMU sensor (or accelerometer) in the line of the axis of the motors because if you locate the IMU far form this you can obtain much error in the accelerometer measure, remember that it measure linear acceleration, if you locate it to a distance R from the axis when the robot falls form vertical the acceleration of the accelerometer is the gravity plus R*dAngle/dt that means that it introduce an error in the measurement.

Step 5: Code

I'm not going to explain every single line of code for the project (i commented the code, if you download it i think u will have no problems to understand it), but i'm gonna show you how i organize it.

The code has 4 files: one the main code, a second one for the motors, the third is for the PID, and the last one is for the sensor code.

In the main code first i initialize the entire robot: pins, sensors, communications, ... Then i calculate the error of the sensors. This part it's very important because in this part we take the initial angle and we make it zero, it means that the sensor have an initial deviation, when we place the robot vertically the sensor don't show that the angle is zero, instead send a deviation angle, this initial angle is used to subtract it from the posterior measurements of the sensors, to obtain the real angle. So when we initiate the robot we have to maintain it vertically until it starts to move the wheels.

The next part of code is the loop where we take the sensor values every 10 millisecond, that mean the frequency of sampling is 100Hz (you can use whatever frequency , but remember that very low and very high frequencies could not work), and we calculate the angle of the robot using, in this case, the complementary filter previously explained. We have the angle, now we can use that information to control our motors, this uses an intermediate PID, the simplest way to control things efficiently, there is an arduino library for the PID but is simple to implement it, you can code it in no more than 10-20 lines of code.

In order to use the accelerometer, in this case the ADXL345, we have to use its libraries. I used the next adafruit libraries: Adafruit_ADXL345 library and Adafruit_Sensor library.

And that's all, simple code for simple robot, but it woks fine for me. You can implement so many more things if you want, like LCD screen, more sensors, better control, ... That the magic of robots, you make one and improve it as much as you want.

Some of you have troubles using the code, i uploaded a single file with the entire project (Balacing_single_file).

Link to the google drive folder:

https://drive.google.com/folderview?id=0B7kBdG1oQk...

Step 6: Tests

I made a lot of test in the long way for this project, first i prove the motors: direction, velocity, ... Then the sensors and the sensor fusion, that was a lot of time for find the right way to use it, i made a simple processing program (included in the code file) to show the values of the sensors graphically:

That help me to understand and to get the right form to take the real angle using Kalman or complementary filter.

At the end i prove the robot itself, the first prove was no as expected but it seems like we can achieve it

After some PID adjust and some code cleaning i reach the goal, maintain the robot vertically all the time, and even recover from pushing it with a little force. As you can see the robot walks with no control, drifting around without sense, but always vertical, that's we wanted (for now).

Step 7: Improvements

There are some much improvements to do with this robot, this is the first step of many more:

  1. The first i want to implement is the position recovery, i don't want my robot to walk around the room like a zombie although my cat like it, not me :D. For that we need encoders for measure the movement of the wheel and use it for bring the robot back to the initial position.
  2. Control the movement of the robot, forward, backward and turning , that is easy, the only thing we have to do is change the angle we want the robots stay then the gravity will do his work and the robot will move in the direction of the angle, then we put the angle to zero again and the robot stops. For turning we have to put some offset in the motor velocity, for turning right we subtract the offset to the velocity in right wheel and sum it to the velocity of the left wheel.
  3. Adding a WiFi shield to control it via internet.
  4. Implementation with Raspberry Pi to allow the robot to use a camera.
  5. Implementation of a camera and artificial vision for the robot.
  6. Use a ball instead of wheels, so hard, but we'll try.

Comments

author
malcolmpalmer.uk (author)2017-07-23

What is the voltage of the Lipo 13000mAh pack you are using?

author
chanuda_ranwelage (author)2017-07-04

can someone help me with the following code?

#include
#include
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"

#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif

#define MIN_ABS_SPEED 20

MPU6050 mpu;

// MPU control/status vars
bool dmpReady = false; // set true if DMP init was successful
uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount; // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer

// orientation/motion vars
Quaternion q; // [w, x, y, z] quaternion container
VectorFloat gravity; // [x, y, z] gravity vector
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector

//PID
double originalSetpoint = 173;
double setpoint = originalSetpoint;
double movingAngleOffset = 0.1;
double input, output;

//adjust these values to fit your own design
double Kp = 50;
double Kd = 1.4;
double Ki = 60;
PID pid(&input, &output, &setpoint, Kp, Ki, Kd, DIRECT);

double motorSpeedFactorLeft = 0.6;
double motorSpeedFactorRight = 0.5;
//MOTOR CONTROLLER
int ENA = 5;
int IN1 = 6;
int IN2 = 7;
int IN3 = 8;
int IN4 = 9;
int ENB = 10;
LMotorController motorController(ENA, IN1, IN2, ENB, IN3, IN4, motorSpeedFactorLeft, motorSpeedFactorRight);

volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high
void dmpDataReady()
{
mpuInterrupt = true;
}
void setup()
{
// join I2C bus (I2Cdev library doesn't do this automatically)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif

mpu.initialize();

devStatus = mpu.dmpInitialize();

// supply your own gyro offsets here, scaled for min sensitivity
mpu.setXGyroOffset(220);
mpu.setYGyroOffset(76);
mpu.setZGyroOffset(-85);
mpu.setZAccelOffset(1788); // 1688 factory default for my test chip

// make sure it worked (returns 0 if so)
if (devStatus == 0)
{
// turn on the DMP, now that it's ready
mpu.setDMPEnabled(true);

// enable Arduino interrupt detection
attachInterrupt(0, dmpDataReady, RISING);
mpuIntStatus = mpu.getIntStatus();

// set our DMP Ready flag so the main loop() function knows it's okay to use it
dmpReady = true;

// get expected DMP packet size for later comparison
packetSize = mpu.dmpGetFIFOPacketSize();

//setup PID
pid.SetMode(AUTOMATIC);
pid.SetSampleTime(10);
pid.SetOutputLimits(-255, 255);
}
else
{
// ERROR!
// 1 = initial memory load failed
// 2 = DMP configuration updates failed
// (if it's going to break, usually the code will be 1)
Serial.print(F("DMP Initialization failed (code "));
Serial.print(devStatus);
Serial.println(F(")"));
}
}
void loop()
{
// if programming failed, don't try to do anything
if (!dmpReady) return;

// wait for MPU interrupt or extra packet(s) available
while (!mpuInterrupt && fifoCount < packetSize)
{
//no mpu data - performing PID calculations and output to motors
pid.Compute();
motorController.move(output, MIN_ABS_SPEED);

}

// reset interrupt flag and get INT_STATUS byte
mpuInterrupt = false;
mpuIntStatus = mpu.getIntStatus();

// get current FIFO count
fifoCount = mpu.getFIFOCount();

// check for overflow (this should never happen unless our code is too inefficient)
if ((mpuIntStatus & 0x10) || fifoCount == 1024)
{
// reset so we can continue cleanly
mpu.resetFIFO();
Serial.println(F("FIFO overflow!"));

// otherwise, check for DMP data ready interrupt (this should happen frequently)
}
else if (mpuIntStatus & 0x02)
{
// wait for correct available data length, should be a VERY short wait
while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();

// read a packet from FIFO
mpu.getFIFOBytes(fifoBuffer, packetSize);

// track FIFO count here in case there is > 1 packet available
// (this lets us immediately read more without waiting for an interrupt)
fifoCount -= packetSize;

mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
input = ypr[1] * 180/M_PI + 180;
}
}

author
ChamiraW (author)2017-06-13

Hi,

can't find the code for mpu6050... it has only for ADXL345

pls send the code dilwicg@gmail.com

author
maluSnypa (author)2017-03-29

Someone share the code please at malumbosnyper78@gmail.com

author
Prakash ganesan (author)2017-03-22

I can't understand the following line in the code Balancing single file, Can anyone explain?

#define runEvery(t) for (static long _lasttime;\
(uint16_t)((uint16_t)millis() - _lasttime) >= (t);\
_lasttime += (t))

author
Prakash ganesan (author)2017-03-22

I can't understand this line in code, Can anyone explain?

#define runEvery(t) for (static long _lasttime;\
(uint16_t)((uint16_t)millis() - _lasttime) >= (t);\
_lasttime += (t))

author
AtharvaA3 (author)2017-03-21

someone send me the code please at atharva.ach@gmail.com

author
RichardL248 (author)2017-03-21

Can you please send me the code for this robot using MPU6050 sensor ?

my email is: richardlopes87@gmail.com

Thanks

author
renataguirre (author)2017-03-17

Can someone please send me the code too? My email is 17renaguirre@asfg.edu.mx

author
Hesham Serry (author)2017-03-17

Can any one please send me the code

my email:

enghesham110@yahoo.com

author
Hesham Serry (author)2017-03-17

Can you please send me the code for this robot using MPU6050 sensor ?

my email is:

enghesham110@yahoo.com

author
RickM173 (author)2017-03-01

Can you email me the downloadable PDF (lazerbeamfocus@icloud.com). Does that also have the controller design...

author
clearyw (author)2017-02-26

I use the GY-521 breakout board for MPU-6050, but the Serial Monitor shows the error from this line:

Serial.println("Ooops, no ADXL345 detected ... Check your wiring!");

Can you please also send me the code for this robot using MPU6050 sensor ?

My email is: cleary_w@yahoo.com

Thanks.

author
Visheshrockstar (author)2017-02-18

i don't understand what is please.please explain.

author
CristianoC7 (author)2017-01-29

Can you please send me the code for using MPU6050?

my email is cristianonitruz@gmail.com

Thanks

author
swapnilchaure (author)2017-01-27

CAN L298N (GY-61) USED INSTEAD GY-80???

author
abdelrahman eid (author)2017-01-21

Can you please send me the code for this robot using MPU6050 sensor ?

my email is ab.ie@hotmail.com

Thanks in Advance

author
miniscientist (author)2017-01-01

can u send me your code for for MPU6050?

miniscientist24@gmail.com

author
AhmedA664 (author)2017-01-01

did anyone send u the mpu 6050 code?

author
miniscientist (author)AhmedA6642017-01-01

i need a code for 6050 too

author
miniscientist (author)2016-12-31

could you please help me with the code for mpu6050

author
Rudarth (author)2016-12-28

Can you send me the code.
Ssuraj938@gmail.com

author
Micky Flanagan (author)2016-12-16

MCM electronics is a really good website too-

http://www.mcmelectronics.com/

author
ChrisR108 (author)2016-12-09

Can you send me the code: daddycdr@yahoo.com

author
hlias7 (author)2016-12-07

Hi first of all great job.
Please can someone send the code for MPU6050 ? Thanks !!!

My emai is footballplayerel7@gmail.com

author
EBOCK (author)2016-12-02

Hi pinuct, I have a commercial application for a self -balancing robotic function. I would like to discuss with you for potential collaboration. Please email me a emailbock@gmail.com Thanks. Edward

author
hikam (author)2016-11-26

Can you send me the code,please to mbm.hikam@gmail.com

author
vaxus (author)2016-11-12

you better buy all that on EBAY.... it will make 1/4 of the total price, believe me, I do so (example, Arduino board - <= 4 dollars)

author
AsheeshM (author)2016-10-19

please someone send the code for MPU-6050.

mail me at asheesh.malviya@gmail.com

thank you

author
SamirA27 (author)2016-10-17

Thank you for this great job ..Can you send me the code (SKETCH ) for the PMU6050 ..to sam.dr.ph@gmail.com . thank you again

author
slmozdgn3 (author)2016-10-17

Can you send me the code? : slmozdgn@hotmail.com

author
OnikT (author)2016-10-13

can you please send me the code to this email: onilink1991@gmail.com

author
ayushmishra1 (author)2016-10-11

your chassis robot italy is outdated kindly send a new one

author
gabriel.lim_2015 made it! (author)2016-10-05

Hello, i am doing your instructables and i got this error in the end, what should i do now? thanks;;, AWESOME instructable btw

help.jpg
author
bartstrik (author)2016-10-04

Hi', I'm making a self balancing robot just like yours. Could you send me your code for MPU6050?

146105@csgwesselgansfort.nl

Thank you

author
gabriel.lim_2015 (author)2016-10-03

HI can u help with your project, i am having some problems ty

author
DarkOverride (author)2016-09-22

Hi,
thank you for this project. Im also using the MPU6050. But my robot falls over after a few seconds. Can you send me your code please?

ferrari-spider@e.mail.de

Thanks

author
RonaldoC7 (author)DarkOverride2016-10-03

can u send me your code for for MPU6050?

jronaldoac@hotmail.com

author
barshan23 (author)DarkOverride2016-09-25

try changing your gain settings of the pid controller. Specially 'I' and 'D' part.

author
LoicA1 (author)2016-09-25

Hi,

Thank you so much for sharing your job.

I also would be interested in getting your code for MPU6050 imu

Thank you by advance

legrosloak@outlook.fr

author
RonaldoC7 (author)LoicA12016-10-03

can u to get the code for mpu6050? if yes, please send me :)

jronaldoac@hotmail.com

author
RonaldoC7 (author)2016-10-03

Hi,

Thank you so much for sharing your job.

I also would be interested in getting your code for MPU6050 imu

Thank you by advance (2)

jronaldoac@hotmail.com

author
ВагеС (author)2016-09-20

Nice project dude.

Im using the MPU6050. is it possible to send the code for this MPU6050?

vauger_sogomom@mail.ru

author
LucasR97 (author)2016-09-10

Nice project dude.

Im using the MPU6050. is it possible to send the code for this MPU6050?

lucas.resende.eng@gmail.com

author
Jake1811 (author)2016-08-05

Hello, great project! where can i find the code for the MPU6050 as this is the sensor i have? cheers

author
EkamS3 (author)2016-06-23

Using a motor shild and imu sensor with arduino uno alone isnt possible.
Use an arduino mega.

author
theograha (author)2016-06-22

nice tutorial..

can u help me ? mr pinuct..if start my robot,the motor continues to move..

there is no response from the sensor GY 80.

but, Written in the serial monitor (initial roll = 130.04)

please help me.. theoraha25@gmail.com

author
stormbr (author)2016-06-19

Thank you by your incredible work.


Not have (i not found) many codes explain PID in the internet.

author
SantoshS64 (author)2016-06-18

Brilliant! Job done well! Please share your code for your bot with me!
satapathyboy@gmail.com

author
eddythebreaker (author)2016-06-09

Excellent tutorial! what I was looking for to learn about this kind of robots :) Thank you very much my friend!