Arduino two wheel self Balancing Robot

Arduino two wheel self Balancing Robot

Skip to product information
1 of 1
Regular price $0.00 USD
Regular price Sale price $0.00 USD
Sale Sold out
  • 1.4k views
  • 27 likes
  • 12 downloads

Table of contents

View full details

Components and supplies

Project Description

Self Balancing Robot is device that can balance itself from falling to the ground. Its function is to maintain balance using the motor’s axis movement of the wheels and body. There are several types of self-balancing robots, and in this particular case I will present you a way to make a Two-Wheeled Balancing Robot. Actually, I made this robot together with one of my students and it is a high school graduation project. This is the simplest type of balancing robot and only requires a few components to build. e.

Step 1

3D printed part image

First, let's explain the components used and their functions. - Processed data from the Arduino is sent to the motor driver board, which in our case is the L298N 5AD type. A motor driver circuit controls the direction and speed of the motors. - This robot uses two DC motors, each connected to a wheel. These motors adjust the speed of the wheels to correct the robot’s tilt. - and power source, specifically two Lithium batteries connected in series wich provides energy to the motors and electronics. All components are mounted on a suitable supporting structure made of 5mm thick PVC board.

- MPU6050 Accelerometer and Gyroscope sensor with Micro Electro Mechanical System(MEMS) technology, which is used to detect angle of tilt or inclination along the X, Y and Z axes.

- The information from this sensor is transmitted to a microcontroller, and in our case it is an Arduino Uno board. This board is the brain of the robot, processes the sensor data and determines the actions needed to keep the robot upright.

Step 2

3D printed part image

Now that we have the 3D printed parts, it’s time to assemble the animatronic eyes. For this, we’ll use five MG90S servo motors to control both the eyelids and the eyes' movement. Here’s what you’ll need:

Components:

  • 5x MG90S Servo Motors
  • Metal wire (we used a few paperclips to form the connecting rods)
  • Pliers and wire cutters (for shaping and cutting the paperclips)

Assembly Process:

  • Center the Servos: Make sure all servos are positioned at 90 degrees to start. This is critical to ensure the movements are calibrated properly.
  • Mount the Servos: Place each servo into the 3D printed servo holder. Two servos will control the left-right movement of the eyes two for the up-down movement and one for the eyelid.
  • Attach the Eyes: Connect the servos to the eyes using the paperclip wires shaped into linkage rods. This will transmit the servo’s rotation to the eye movement. Universal joints are added to ensure the eye movements are smooth.
  • Attach the Eyelids: The final servo will control the eyelids giving your mask the ability to blink or close its eyes. The same wire and paperclip method is used to attach the eyelids to the servo.

Animatronic eyes move thanks to the servos manipulating them in two axes (up-down and left-right). Each eye's movement is controlled by two servos, while the eyelids are controlled by a single servo for opening and closing.

Step 3: Printed Circuit Board

3D printed part image

A printed circuit board (PCB) was designed to integrate all components, including the DFPlayer, PIR sensor, servo motors, speaker, and Arduino Nano. The goal is to create a more stable circuit and prototype.

  • Arduino Nano (main controller)
  • DFPlayer MP3 module (for sound)
  • PIR sensor (motion detection)
  • 5x servo motor inputs
  • Speaker for audio output

PCBWay was chosen for the PCB fabrication. You can find the Gerber file and circuit diagram for PCB fabrication at this link:  https://www.pcbway.com/project/shareproject/The_Face_maker101_c4124445.html $ Also, if you have no soldering experience, you can use PCBWay's assembled PCB service.

I also participated in PCBWay's 7th design contest, if you want to support the project, you can vote for the project from the same link. Thank you.

The component list includes capacitors for power requirements, resistors for servo motor digital inputs, terminal blocks for the sensor and speaker, and female and male headers for the DFPlayer and Arduino Nano.

  • Resistors and capacitors (for power regulation)
  • Terminal blocks (for the sensor and speaker connections)
  • Male/female headers (for the DFPlayer - Nano - and servos)

I soldered all the components in place using a soldering iron and solder wire. This setup ensures that the entire project runs smoothly and that the wiring doesn’t get messy.

Step 4: Main Code for the Face

3D printed part image

Now that everything is assembled, it’s time to upload the main code into the Arduino Nano. This code integrates the PIR sensor, servo motors, and the DFPlayer MP3 module. The idea is simple: when the PIR sensor detects motion, the servos will move to open the eyelids and make the eyes move while the DFPlayer plays a sound.

Key Components of the Code:

  • The PIR sensor triggers when it detects motion.
  • The DFPlayer plays a sound file stored on an SD card.
  • The servos control the eye and eyelid movement.

The DFPlayer Mini is a simple, low-cost MP3 player that can play audio files stored on a microSD card. In this project, it will play a sound file when motion is detected by the PIR sensor.

  • Connect the RX pin of the DFPlayer to Digital 11 and the TX pin to Digital 10 on the Arduino Nano.
  • Attach a speaker to the SPK+ and SPK- pins of the DFPlayer for sound output.

PIR Motion Sensor Connection

  • The PIR sensor will detect motion and trigger the servo movements and audio playback.
  • Connect the PIR sensor’s output pin to Digital 7 of the Arduino Nano.

Use a 9V external power supply for the circuit to ensure stable performance. Once the wiring and coding are complete, it’s time to test your project.

  • Upload the code to your Arduino Nano.
  • Ensure the PIR sensor is placed in a location where it can easily detect motion.
  • When the PIR sensor detects movement the servos controlling the eyelids should open and the DFPlayer should play the pre-loaded sound file.
  • The servos will then make the eyes move in a coordinated sequence.

Code Overview: The main code utilizes the DFPlayer library to control audio playback while coordinating with the PIR sensor's output. When motion is detected, the code triggers the servos to move the eyes and simultaneously starts the audio file. This synchronization enhances the effect, making the animatronic eyes appear more lifelike and engaging. The code efficiently handles various scenarios, ensuring seamless transitions between eye movements and sound playback.

Note: The attached file “1.mp3” contains the sound “I see you” used in the project. Simply upload the audio file to the SD card (SD card format must be FAT32)

Step 5: Final Assembly

3D printed part image

Now it’s time to put everything together in the mask. Follow these steps:

  • Insert the Bars: Attach the two support bars to the back of the mask.
  • Mount the Servo Holder: Secure the servo holder (with the servos and eyes attached) to the bars using hot glue.
  • Install the PIR Sensor: Drill a small 6mm hole in the front of the mask to place the PIR sensor. It’s a mini PIR sensor so it fits perfectly into the hole.
  • Place the Speaker: Position the speaker inside the mask ensuring it’s hidden from view. Attach the PCB: Secure the PCB inside the mask and make all the necessary connections.
  • Seal the Mask: Once everything is connected and in place use the back cover to enclose the electronics.

Finally, mount the mask on the wall using double-sided tape or other methods. Power the mask using a 9V power supply, and you’re all set!

3D printed part image

This project combines creativity, technology, and a bit of spookiness, making it perfect for the Halloween season. With a few tweaks, you can customize this mask to your liking, adding different sounds or even more complex eye movements. Happy making!

An extra idea, add LED lighting: If you want to make your project even more engaging, you can add LED lights that turn on when motion is detected, enhancing the visual effect.

Code

cpp Servo Motor Code
#include "I2Cdev.h"
#include  //From https://github.com/br3ttb/Arduino-PID-Library/blob/master/PID_v1.h
#include "MPU6050_6Axis_MotionApps20.h" //https://github.com/jrowberg/i2cdevlib/tree/master/Arduino/MPU6050
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
/*********Tune these 4 values for your BOT*********/
double setpoint= 182; //set the value when the bot is perpendicular to ground using serial monitor. 
//Read the project documentation on circuitdigest.com to learn how to set these values
double Kp = 15; //21 Set this first
double Kd = 0.9; //0.8 Set this secound
double Ki = 140; //140 Finally set this 
/******End of values setting*********/
double input, output;
PID pid(&input, &output, &setpoint, Kp, Ki, Kd, DIRECT);
volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high
void dmpDataReady()
{
    mpuInterrupt = true;
}
void setup() {
  Serial.begin(115200);
  // initialize device
    Serial.println(F("Initializing I2C devices..."));
    mpu.initialize();
     // verify connection
    Serial.println(F("Testing device connections..."));
    Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
    // load and configure the DMP
    devStatus = mpu.dmpInitialize();
    // supply your own gyro offsets here, scaled for min sensitivity
    mpu.setXGyroOffset(-479);
    mpu.setYGyroOffset(84);
    mpu.setZGyroOffset(15);
    mpu.setZAccelOffset(1638); 
      // make sure it worked (returns 0 if so)
    if (devStatus == 0)
    {
        // turn on the DMP, now that it's ready
        Serial.println(F("Enabling DMP..."));
        mpu.setDMPEnabled(true);
        // enable Arduino interrupt detection
        Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
        attachInterrupt(0, dmpDataReady, RISING);
        mpuIntStatus = mpu.getIntStatus();
        // set our DMP Ready flag so the main loop() function knows it's okay to use it
        Serial.println(F("DMP ready! Waiting for first interrupt..."));
        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(")"));
    }
//Initialise the Motor outpu pins
    pinMode (6, OUTPUT);
    pinMode (9, OUTPUT);
    pinMode (10, OUTPUT);
    pinMode (11, OUTPUT);
//By default turn off both the motors
    analogWrite(6,LOW);
    analogWrite(9,LOW);
    analogWrite(10,LOW);
    analogWrite(11,LOW);
}
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();
        //Print the value of Input and Output on serial monitor to check how it is working.
        Serial.print(input); Serial.print(" =>"); Serial.println(output);
        if (input>150 && input<200){//If the Bot is falling 
        if (output>0) //Falling towards front 
        Forward(); //Rotate the wheels forward 
        else if (output<0) //Falling towards back
        Reverse(); //Rotate the wheels backward 
        }
        else //If Bot not falling
        Stop(); //Hold the wheels still
    }
    // 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); //get value for q
        mpu.dmpGetGravity(&gravity, &q); //get value for gravity
        mpu.dmpGetYawPitchRoll(ypr, &q, &gravity); //get value for ypr
        input = ypr[1] * 180/M_PI + 180;
   }
}
void Forward() //Code to rotate the wheel forward 
{
    analogWrite(6,output);
    analogWrite(9,0);
    analogWrite(10,output);
    analogWrite(11,0);
    Serial.print("F"); //Debugging information 
}
void Reverse() //Code to rotate the wheel Backward  
{
    analogWrite(6,0);
    analogWrite(9,output*-1);
    analogWrite(10,0);
    analogWrite(11,output*-1);
    Serial.print("R");
}
void Stop() //Code to stop both the wheels
{
    analogWrite(6,0);
    analogWrite(9,0);
    analogWrite(10,0);
    analogWrite(11,0);
    Serial.print("S");
}

Customer Reviews

Be the first to write a review
0%
(0)
0%
(0)
0%
(0)
0%
(0)
0%
(0)