Make a Gesture Control Robot at Low Cost

by psp50 in Circuits > Robots

311 Views, 3 Favorites, 0 Comments

Make a Gesture Control Robot at Low Cost

image-removebg-preview (11).png

This tutorial will help you build a car with gesture control by yourself. This is an easy application using MPU-6050's three-axis Gyroscope and Accelerometer. You can perform a myriad of things. By understanding how to use it and how to interface it with Arduino, and how to transfer data using Bluetooth modules. In this article, I will concentrate upon Bluetooth connecting to Bluetooth communication in the case of two HC-05 Bluetooth modules.

Supplies

Screenshot 2021-11-12 12352244.png
Screenshot 2021-11-20 123801.png
Screenshot 2021-11-20 123811.png
Screenshot 2021-11-20 123821.png
Screenshot 2021-11-20 123832.png
Screenshot 2021-11-20 123842.png

Connection Diagram

circuit-page-001.jpg
Screenshot 2021-11-20 124157.png

A Diagram of the connection between robot and transmitter unit is provided below. You can refer to them.

one is for the car unit and another one is for the hand unit.

Assambling

Screenshot_2021-11-20_124429-removebg-preview.png
image-removebg-preview.png
image-removebg-preview (1).png
image-removebg-preview (2).png
image-removebg-preview (3).png
image-removebg-preview (4).png
image-removebg-preview (9).png

Assemble both units according to the circuit diagram.

assemble according to the photos and diagram.



Hardware Configuration

image-removebg-preview (5).png
image-removebg-preview (6).png
image-removebg-preview (7).png
image-removebg-preview (8).png
image-removebg-preview (9).png
Screenshot 2021-11-20 130012.png
image-removebg-preview (10).png

We will now discuss Bluetooth modules configuration. In essence, the HC-05 Bluetooth module has an option to set the slave module's factory settings. this means that we can transmit data to the module as soon as we connecting it. there is no need to change any other settings to transfer messages from devices on mobile to HC05 module. Simply enter its default password (1234/0000)to connect to it. But what happens if we want to transfer data via this module to another similar module, or even to a mobile device.

In this project, we're using the same method this project, sending data through this Bluetooth module. Data is collected by the MPU-6050 gyro sensor to other Bluetooth modules.

So, to accomplish this, we have to set up the two Bluetooth modules. So that they will automatically be paired with one another when they are powered on. The first module acts as a slave unit, which receives messages from remote units and is mounted on the vehicle. Also, configure the second as a master device that can act as transmitter units and transmit information directly to the slave devices.

First, you must configure the initial Bluetooth module to be a slave device. To do this, connect it to Arduino according to the wiring diagram.


And upload the code by name configure.

#include <SoftwareSerial.h>
SoftwareSerial BTSerial(10, 11); // RX | TX
void setup()
{
Serial.begin(9600);
Serial.println("Enter AT commands:");
BTSerial.begin(38400); // HC-05 default speed in AT command more
}
void loop()
{
// Keep reading from HC-05 and send to Arduino Serial Monitor
if (BTSerial.available())
Serial.write(BTSerial.read());
// Keep reading from Arduino Serial Monitor and send to HC-05
if (Serial.available())
BTSerial.write(Serial.read());
}

Remove the module. Hold and press the Ky on the module until you reconnect it. You'll notice that the led on the module blinked at a slower rate. Each time it happens, it takes 2 seconds. This means that HC-05 has entered its AT commands mode. When you open the serial monitor, adjust the baud speed to 9600 and the output type to the combination of NL & CR. Then type AT in the your send box and then transmit it. If it responds with OK this means that everything is well. If it doesn't, and responds with an error, send AT again. until it replies with OK or chek connections. Then send AT once more .



After you have received a good response from module, enter the following commands, one by one.

AT+ORGL and then send the command. This command will put the module to the factory setting.

AT+RMAAD command will free the the module from any previous pairing

AT+UART? examine the current baud speed of the module

AT+UART=38400, 0, 0. set the baudrate to 38400.

AT+ROLE? Find out if the role is master or slave. It will reply with either the number 1 or 0. If the module is a slave device, it will reply with to 0 and if it's a master device, it will reply with 1.

assign role as slave device. Enter AT+ROLE=0

AT+ADDR? look up the address of the module.

Note this address down. The module responded. Once the module has received this address, the configuration of the slave module is completed.



Now it's time to set your second Bluetooth module to act as the master device. Connect it to an Arduino board and then switch it into AT mode. Similar to what we did with our previous one.



Input these AT commands with the given sequence.

AT+ORGL

AT+RMAAD

AT+UART?

AT+UART=38400, 0, 0

AT+ROLE?

assign the function of this module to be the device that is master. AT+ROLE=1

AT+CMODE=0 means that the module connects to a single device. the default setting is 0

Now you can connect this module to the slave device. To do this, and then press enter.

AT+BIND =" The address for the module slave" and that's it!

Now, you can install the MPU-6050 library sensor. It also supports I2C communication. Because MPU-6050's gyro sensor is equipped with an I2C interface. download libraries and Source code from here: http://www.mediafire.com/file/l8mru5emulb8x93/gesture_control_robot.rar/file

If you've installed these libraries, you can skip this.

The car unit should be connected to the PC via an USB cable. Choose the right connection port and type of board. And upload theprogram by name "Gesture_controled_Robot__car_unit_". Be sure that the battery as well as Bluetooth module are not connected to the vehicle while you upload the application.

//program by Shubham Shinganapure on 3-10-2019
//
//for Gesture controled Robotic Car
int lm1=8; //left motor output 1
int lm2=9; //left motor output 2
int rm1=10;  //right motor output 1
int rm2=11;  //right motor output 2
char d=0;
void setup()
{
pinMode(lm1,OUTPUT);
pinMode(lm2,OUTPUT);
pinMode(rm1,OUTPUT);
pinMode(rm2,OUTPUT);
Serial.begin(38400);
sTOP();
}
void loop()
{
if(Serial.available()>0)
{
d=Serial.read();
if(d=='F')
{
ForWard();
}
if(d=='B')
{
BackWard();
}
if(d=='L')
{
Left();
}
if(d=='R')
{
Right();
}
if(d=='S')
{
sTOP();
}
}
}
void ForWard()
{
digitalWrite(lm1,HIGH);
digitalWrite(lm2,LOW);
digitalWrite(rm1,HIGH);
digitalWrite(rm2,LOW);
}
void BackWard()
{
digitalWrite(lm1,LOW);
digitalWrite(lm2,HIGH);
digitalWrite(rm1,LOW);
digitalWrite(rm2,HIGH);
}
void Left()
{
digitalWrite(lm1,LOW);
digitalWrite(lm2,HIGH);
digitalWrite(rm1,HIGH);
digitalWrite(rm2,LOW);
}
void Right()
{
digitalWrite(lm1,HIGH);
digitalWrite(lm2,LOW);
digitalWrite(rm1,LOW);
digitalWrite(rm2,HIGH);
}
void sTOP()
{
digitalWrite(lm1,LOW);
digitalWrite(lm2,LOW);
digitalWrite(rm1,LOW);
digitalWrite(rm2,LOW);
}

Similar to your remote device. Start the program with the name remote. Upload this program to your remote unit.



//program modified on 3/10/19 by // by Shubham Shinganapure.
//
//for Gesture controled Robotic Car (remote  )
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
//#include "MPU6050.h" // not necessary if using MotionApps include file
// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for SparkFun breakout and InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 mpu;
#define OUTPUT_READABLE_YAWPITCHROLL
// 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
VectorFloat gravity;
Quaternion q;
float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector
uint8_t teapotPacket[14] = { '$', 0x02, 0,0, 0,0, 0,0, 0,0, 0x00, 0x00, '\r', '\n' };
volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
mpuInterrupt = true;
}
#include <SoftwareSerial.h>
SoftwareSerial BTSerial(10, 11); // RX | TX
int bt=8;
int x =1;
void setup() {
#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
// initialize serial communication
// (115200 chosen because it is required for Teapot Demo output, but it's
// really up to you depending on your project)
Serial.begin(115200);
BTSerial.begin(38400);
// while (!Serial); // wait for Leonardo enumeration, others continue immediately
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"));
// wait for ready
// load and configure the DMP
Serial.println(F("Initializing DMP..."));
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);
// 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();
} 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(")"));
}
// configure LED for output
pinMode(bt,INPUT);
}
// ================================================================
// ===                    MAIN PROGRAM LOOP                     ===
// ================================================================
void loop() {
if(digitalRead(bt)==HIGH)
{
x++;
delay(150);
}
if((x%2)==0){
// 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) {
// other program behavior stuff here
// .
// .
// .
// if you are really paranoid you can frequently test in between other
// stuff to see if mpuInterrupt is true, and if so, "break;" from the
// while() loop to immediately process the MPU data
// .
// .
// .
}
// 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;
#ifdef OUTPUT_READABLE_YAWPITCHROLL
// display Euler angles in degrees
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
Serial.print("ypr\t");
Serial.print(ypr[0] * 180/M_PI);
Serial.print("\t");
Serial.print(ypr[1] * 180/M_PI);
Serial.print("\t");
Serial.println(ypr[2] * 180/M_PI);
if((ypr[1] * 180/M_PI)<= -25)
{BTSerial.write('F');
}
else if((ypr[1] * 180/M_PI)>= 25)
{BTSerial.write('B');
}
else if((ypr[2] * 180/M_PI)<= -25)
{BTSerial.write('L');
}
else if((ypr[2] * 180/M_PI)>= 20)
{BTSerial.write('R');
}
else{
BTSerial.write('S');
}
#endif
}
}
else{
BTSerial.write('S');

}
}


Install master Bluetooth module in the car unit. Then, connect control the Bluetooth module in the unit remote. Then you're done.



We'll turn it on and then it's all set to go .......

Arduino Code

Here is the Arduino control gesture control robot code. made by the Shubham Shinganapure.

https://www.youtube.com/watch?v=ifcIrTVrGHw


//program modified on 3/10/19 by // by Shubham Shinganapure. 

//

//for Gesture controled Robotic Car (remote  )



#include "I2Cdev.h"



#include "MPU6050_6Axis_MotionApps20.h"

//#include "MPU6050.h" // not necessary if using MotionApps include file



// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation

// is used in I2Cdev.h

#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE

    #include "Wire.h"

#endif



// class default I2C address is 0x68

// specific I2C addresses may be passed as a parameter here

// AD0 low = 0x68 (default for SparkFun breakout and InvenSense evaluation board)

// AD0 high = 0x69

MPU6050 mpu;

#define OUTPUT_READABLE_YAWPITCHROLL



// 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



VectorFloat gravity;  

Quaternion q;      

float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector



uint8_t teapotPacket[14] = { '$', 0x02, 0,0, 0,0, 0,0, 0,0, 0x00, 0x00, '\r', '\n' };



volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high

void dmpDataReady() {

    mpuInterrupt = true;

}

#include <SoftwareSerial.h> 

SoftwareSerial BTSerial(10, 11); // RX | TX



int bt=8;

int x =1;

void setup() {

   

 #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



    // initialize serial communication

    // (115200 chosen because it is required for Teapot Demo output, but it's

    // really up to you depending on your project)

    Serial.begin(115200);

    BTSerial.begin(38400);

   // while (!Serial); // wait for Leonardo enumeration, others continue immediately



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"));



    // wait for ready

   

    // load and configure the DMP

    Serial.println(F("Initializing DMP..."));

    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);



    // 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();

    } 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(")"));

    }



    // configure LED for output

   

  pinMode(bt,INPUT);

  

}







// ================================================================

// ===                    MAIN PROGRAM LOOP                     ===

// ================================================================



void loop() {

 if(digitalRead(bt)==HIGH)

 {

  x++;

  delay(150);

  }

  if((x%2)==0){

    // 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) {

        // other program behavior stuff here

        // .

        // .

        // .

        // if you are really paranoid you can frequently test in between other

        // stuff to see if mpuInterrupt is true, and if so, "break;" from the

        // while() loop to immediately process the MPU data

        // .

        // .

        // .

    }

    // 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;



 #ifdef OUTPUT_READABLE_YAWPITCHROLL
            // display Euler angles in degrees
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
            Serial.print("ypr\t");
            Serial.print(ypr[0] * 180/M_PI);
            Serial.print("\t");
            Serial.print(ypr[1] * 180/M_PI);
            Serial.print("\t");
            Serial.println(ypr[2] * 180/M_PI);
            if((ypr[1] * 180/M_PI)<= -25)
            {BTSerial.write('F');
            }
            else if((ypr[1] * 180/M_PI)>= 25)
            {BTSerial.write('B');
            }
            else if((ypr[2] * 180/M_PI)<= -25)
            {BTSerial.write('L');
            }
            else if((ypr[2] * 180/M_PI)>= 20)
            {BTSerial.write('R');
            }
            else{
              BTSerial.write('S');
              }

        #endif
}

  }

  else{
              BTSerial.write('S');
              }

}

Ending

I hope You will like this tutorial after making it.

If you like this helpful please follow me and if you have any doubt please feel free to comment.