Introduction: The Breadboarded Self Balancing Robot

About: Hi!! I am Aditya Patil, robotics enthusiast and a hardware designer developer, skilled with stuffing anything into small space and loves to make tiny robots.

Being a Robotics enthusiast I always wanted to build a Self Balancing Robot but never build untill now.

Self Balancing Robots are not a new thing to the world, what makes this build different from other Self Balancing Robots is the compact design and modularity of the build. The robot can be build by just plugging in various modules and can be assembled in a matter of minutes.

So let's build one.

Step 1: The Idea!

The Breadboard

A PCB is generally used to connect electronic components together but as we want our build to be modular and easy to assemble, the best way to do so is to use a breadboard. We will use 2 mini breadboards to connect everything electrically.

Micro-controller

Micro-controller board which we will use to control the motors, sense the angle of tilt and to implement PID algorithm will be Arduino Nano. The processing power of atemga328 (the micro-controller around which Arduino Nano is developed) is just enough and its all pins are breadboard compatible.

Motion tracking Device

To measure the tilt angle we will use MPU6050 a motion tracking device which has 3 axis accelerometer and 3 axis gyroscope and will use a complimentary filter to combine measurements from accelerometer and gyroscope to get noise free and stable angle values.

Motors

Motors used for this build will be 12V 300RPM N20 micro gear motors with compatible wheels and mounting brackets.

Motor Driver

To drive the motors we will be using L293d motor driver. This driver has two full H-bridge driver in a single DIP-package perfect for our application.

Miscellaneous

A 3D printed support will be used to hold things all together and jumper wires will used to connect everything electrically.

Step 2: Supplies

Electronics Components:

  • Mini breadboard ____________________ x 2 Link
  • Arduino Nano ______________________ x 1 Link
  • MPU6050 _________________________ x 1 Link
  • L293D motor driver - DIP package ______ x 1 Link
  • N20 micro gear motor - 12V 300 RPM ___ x 2 Link
  • N20 motor brackets__________________ x 2 Link
  • Compatible N20 motor wheels _________ x 2 Link
  • 9V batteries________________________ x 2

Supplies

  • Single strand wires - multi colors
  • 3D printer/ printing service
  • Male pin headers
  • Battery snap connector
  • Zip ties
  • Jumper wires
  • 12V power supply
  • dc jack to screw terminal
  • Rubber band

Tools

  • Solder iron
  • Solder wire
  • Plier

Step 3: A Bit of Theory

Working of the Robot

A self Balancing Robot tries to balance itself by some how counter acting the force of gravity acting on it's center of mass. To generate the counter acting force it uses motors.

You can imagine as when we try to balance a stick on our palm we move the base of stick which is resting on our palm to balance it. Same does the Robot, it moves its base using motors wheels.

What is PID?

PID stands for Proportional Integral Derivative. It is a control loop mechanism. What it basically does is continuously monitor the robot tilt angle and controls the motor speed to balance.

What is Complementary Filter?

There two ways we can measure the tilt angle using MPU6050, either by using its accelerometer or by using its gyroscope. The issue with these two is, accelerometer is susceptible to noise and measurements from gyroscope drift from actual values with time. So to avoid these, we combine both the values and filter out the errors using a complementary filter.

Step 4: Preparing Arduino Nano - the Drivers

If you get the original Arduino Nano it wont be any problem but if you get the clone version of Arduino Nano the computer may not detect the board which uses CH340G chip, a USB to serial converter if in case the driver are not installed or updated.

Having a clone version of Arduino Nano will be fine, it work the same as original.

  • Install the executable file. Download from Here.
  • Run it.
  • Click uninstall then install, to remove any older version residing.
  • To check if everything worked fine go to device manager and plug-in Arduino Nano.
  • The chip and hence the board should be detected in PORTS sub-menu.

Step 5: Preparing Arduino Nano - Pin Headers

Arduino Nano has a lot of GPIOs to be used and we wont be using all of them either. Instead of soldering all pin headers we will solder only those pin which are being utilized. This way we get enough room for the jumper wire to route around the breadboard.

The pin which we are going to solder and hence we will use for the build are:

  • VIN
  • GND _____ (both)
  • 5V
  • A4 _______ (SDA)
  • A5 _______ (SCL)
  • D5 _______ (M1power)
  • D6 _______ (M2power)
  • D8 _______ (M1enable)
  • D9 _______ (M2enable)
  • D10 ______ (M2direction)
  • D11 ______ (M1direction)
  • D2, D3, D7 _ (for future use)

Step 6: Preparing MPU6050

MPU6050 uses I2C communication to transfer the measured data to Arduino Nano.

Solder pin headers to pins VCC, GND, SCL, SDA. We wont we using the remaining pins.

Place the MPU on the second breadboard.

Connect:

___MPU6050__-__Arduino Nano___

  • __VCC ___-______ 5V________
  • __GND___-_____ GND _______
  • __SCL ___-______ A5 ________
  • __SDA ___-______ A4 ________

Step 7: Library for MPU6050

As MPU6050 uses I2C communication we could use the Wire library and read each data byte by byte and interpret later, this will make the code more longer and hard to debug.

So instead we will use a library developed by Jeff Rowberg.

  • Head on to this link.
  • Download the ZIP file.
  • Extract the contents of ZIP file.
  • Open the folder and navigate to Arduino folder inside i2cdevlib-master folder
  • Copy MPU6050 and i2cdev folder
  • And paste in libraries folder where all external libraries are stored, for windows it is documents folder
  • Restart Arduino IDE and the libraries should be visible.

Step 8: Preparing Batteries

As the power source for the robot we will be using two 9V non-rechargeable batteries. Having non-rechargeable makes the build more simple or in other case the rechargeable batteries require extra charging circuitry.

The reason to use two batteries one for motors and other for logic devices (Arduino Nano, MPU6050) is that sometimes the motor induce power surges which may lead to resetting of Arduino Nano.

  • Cut the snap connector's wire to 40mm length.
  • Trim the insulation to expose the wire and bend it.
  • Separate a 1x2 male pin header.
  • Place them on breadboard and solder the battery snap connector to pin header.
  • Ensure the wire bend before soldering because the way they go to battery from pin headers.

We used 1x2 pin header for 1st battery because the pins VIN and GND on Nano are adjacent to each other, but in case of L293d the motor power and GND pins are not adjacent but instead have two pins in between them. We can use two 1x1 pin headers but we will instead use 1x4 and will remove the middle two pins from the spacer.

If we use 2 separate 1x1 pin header, they begin not attached to each other can lead to shorts.

  • Cut and trim snap connector with 35mm length.
  • Separate 1x4 pin header.
  • Now using a plier remove the middle pin from pin header.
  • Solder the wires from snap connector to pin header keeping the wires bend.

Step 9: Electric Connections

After preparing Arduino Nano and MPU6050 by soldering necessary pin headers, now is the time to connect every module and ICs to each other electrically.

  • First connect the two mini breadboard vertically using the male female part provided.
  • Then cut out single strand wire of different colors.
  • I used RED for VCC
  • BLACK for GND
  • YELLOW for I2C
  • WHITE for enable pins.
  • BLUE for right motors inputs and outputs.
  • and GREEN for left motor input and outputs.

Using color coded wires helps in debugging and also makes the build look more attractive.

  • Remove insulation from every wire piece from both the end so that wires can be inserted in breadboard.
  • Now bend the wires and connect to the breadboard as in above pictures.

By doing so we connect the following pins to each other.

_____Arduino Nano__-__MPU6050__-__L293d______

  • ______5V_____ to____Vcc____to____pin 16____
  • _____GND_____-____GND____-____pin 4_____
  • ____A4(SDA)___-____SDA ____-_____________
  • ____A5(SCL)___-____SCL_____-_____________
  • ______D5 _____- ____________-____pin 2_____
  • ______D6 _____-____________ -____pin 15____
  • ______D8 _____-____________ -____pin 1_____
  • ______D9 _____-____________ -____pin 9_____
  • ______D10 ____-____________ -____pin 10____
  • ______D11 ____-____________ -____pin7______

We haven't connected the battery and motors to the build we will do so in the next steps.

Step 10: 3D Prints

I 3D designed the chassis/support in fusion 360.

The wall thickness has been purposefully set to1.6mm so that when printed with standard printer of 0.4mm nozzle everything fuses perfectly.

Parameters:

  • 0.4mm nozzle
  • 0.2mm layer height
  • 20% infill
  • Black PLA
  • Total time - 2hrs

Step 11: Assembly - Installing Brackets

Lets first mount the brackets for N20 motors.

  • First insert m2 nut in the section provided in the brackets.
  • Insert the bolt in 3d print from above and screw the bracket to the support.
  • Don't tighten up the nut bolts completely as we have to insert N20 motors in them.

Step 12: Installing Motors

The purpose to first install brackets is, it becomes a bit difficult to handle the motor, bracket, and to bolt them down at one go.

  • As we haven't bolted the brackets tightly, the motors just slide into the bracket.
  • Make sure to insert the motors from outside and the back of motor should go first.
  • If it becomes a bit hard to slide the motor try loosening the bolt a little more.

Step 13: Installing the Breadboard

Installing breadboard and batteries is fairly easy as they both slide into support from above.

Make sure USB of arduino nano faces down, to match the orentation

Step 14: Preparing Motors

The reason why we are connecting motors after the assembly is, if we had to solder the wires to motors before assembly then we would need a 3rd hand or any kind of rig to hold the motors and wires so if the motors are first fixed to build it would be easy to solder them as one end will be attached to breadboard and other to the motor terminal.

We will use single strand wire as well to connect motors as they remain sturdy as compared to multi stranded ones.

  • First cut single strand wire of green and blue color to color code the motors.
  • Remove the insulation from both the ends of wire.
  • Now take a green wire piece and insert in breadboard where it will connect to pin 3 of L293d
  • And solder the other end to the nearest terminal of motor.
  • Similarly connect the remaining 3 motor terminals to the breadboard using single strand wires.

Connections:

  • Left_Motor_terminal_1 ----> L293d pin 3
  • Left_Motor_terminal_2 ----> L293d pin 6
  • Right_Motor_terminal_1 --> L293d pin 11
  • Right_Motor_terminal_2 --> L293d pin 14

Step 15: Done With Assembly

Once we install the wheels on motor shafts we are complete with the assembly.

The battery might fall off when the robot is tilted, so to secure it firmly we can zip tie or we can use a rubber band.

Step 16: The Code

To implement PID controller we will use library by Brett Beauregard. It can be installed from library manger of Arduino IDE itself.

The logic of code is fairly simple.

  • We first receive data from MPU6050.
  • Interpret it to get the tilt angle from each accelerometer and gyroscope.
  • Then implement the complementary filter to combine values from both.
  • Then we call the PID.compute function to calculate the output
  • And we power the motor based on output sign and its value.

The complete code is here.

//Include necessary libraries
#include <Wire.h>
#include <I2Cdev.h>
#include <MPU6050.h>
#include <PID_v1.h>

//define macros
#define LeftMotorDir 11
#define LeftMotorPower 5
#define RightMotorDir 10
#define RightMotorPower 6

#define LeftMotorEnable 8
#define RightMotorEnable 9

//the angle where the robot is stable
double Setpoint = -0.75;

double Input, Output;

//PID controllers
double Kp = 4.6;
double Kd = 0.04;
double Ki = 1;

//required variables
int accY, accZ, gyroX;
float accAngle = 0, gyroAngle = 0, previousAngle = 0;
float gyroRate = 0;
int val = 0;

//instance of class PID
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

//instance of class MPU6050
MPU6050 mpu;

/*.............................SETUP.................................*/
/*...................................................................*/

void setup()
{
  //initializing MPU6050
  mpu.initialize();

  //setting the pinmodes
  pinMode(LeftMotorEnable, OUTPUT);
  pinMode(LeftMotorDir, OUTPUT);
  pinMode(LeftMotorPower, OUTPUT);

  pinMode(RightMotorEnable, OUTPUT);
  pinMode(RightMotorDir, OUTPUT);
  pinMode(RightMotorPower, OUTPUT);

  //making enable pin high
  digitalWrite(LeftMotorEnable, HIGH);
  digitalWrite(RightMotorEnable, HIGH);

  //setting PID parameters
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(-255, 255); // may change (50,255);
  myPID.SetSampleTime(5); //how often pid is evaluated in millisec
  myPID.SetControllerDirection(REVERSE);

  //initialize the timer
  initTimer2();

}

/*..............................LOOP.................................*/
/*...................................................................*/

void loop() {

  accZ = mpu.getAccelerationZ();
  accY = mpu.getAccelerationY();

  gyroX = mpu.getRotationX();

  accAngle = atan2(accZ, -accY) * RAD_TO_DEG;

  gyroRate = gyroX / 131;

  Input = 0.97 * (previousAngle + gyroAngle) + 0.03 * (accAngle);
  previousAngle = Input;

  myPID.Compute();

  if (Output > Setpoint)
  {
    digitalWrite(LeftMotorDir, LOW);
    digitalWrite(RightMotorDir, LOW);
    val = map(Output, 0, 255, 18, 255);
    analogWrite(LeftMotorPower, val);
    analogWrite(RightMotorPower, val);
  }

  if (Output < Setpoint)
  {
    digitalWrite(LeftMotorDir, HIGH);
    digitalWrite(RightMotorDir, HIGH);
    val = map(Output, -255, 0, 0, 237);
    analogWrite(LeftMotorPower, val);
    analogWrite(RightMotorPower, val);
  }
}


/*................... ........ISR_TIMER2.............................*/
/*...................................................................*/

ISR(TIMER2_COMPA_vect)
{
  gyroAngle = (float)gyroRate * 0.001;
}

/*...........................iniTimer2...............................*/
/*...................................................................*/

void initTimer2()
{
  //reset timer2 control register A
  TCCR2A = 0;

  //set CTC mode
  TCCR2A |= (1 << WGM21);
  TCCR2A &= ~(1 << WGM20);
  TCCR2B &= ~(1 << WGM22);

  //prescaler of 128
  TCCR2B &= ~(1 << CS21);
  TCCR2B |= ((1 << CS22) | (1 << CS20));

  //reset counter
  TCNT2 = 0;

  //set compare register
  OCR2A = 125;

  //enable timer1 compare match interrupt
  TIMSK2 |= (1 << OCIE2A);

  //enable global interrupt
  sei();
}

Step 17: Are We Done?

A mistake I made and so you should avoid in your future builds.

While choosing the power source for build I did not consider if the battery is capable of suppling the utmost current possible for the motor to work properly. Though a dc motor can run on voltage level significant below from rated ones, the 9V battery was not able to provide enough current to motors to work up to mark.

I realised this mistake when assembly was complete and I headed for testing.

So we need to shift to external power source. A 12V lab bench power supply or a wall mount adapter works best as they can provide enough current to work.

If not using the 2nd 9V battery then why keep in the build?

We need to do this because if we remove the 2nd battery it will lead to lowering of the center of mass of the bot and hence will also be difficult to balance. So the 2nd battery just acts as a dead weight.

Step 18: Final Thoughts!!

It was not a straight forward process to design and build this self balancing robot. Apart from power source everything wad just perfect. In the upcoming version we will fix the power supply and will try to increase the recovery angle of the robot which in this case was very low.

Do follow me on Instagram