0°

手势控制机器人

简介

步骤一 材料准备

硬件准备:

arduino uno

arduino nano R3

HC-05 蓝牙模块

MPU6050

DC motor 12V

轮子

L239D H桥电机驱动

9v 电池

软件准备:

arduino IDE

步骤二 原理说明

这是关于如何自己制作手势控制的车子。基本上,这是MPU-6050 3轴陀螺仪,加速度计的简单应用。您可以做更多的事情。通过了解如何使用它,如何将其与Arduino接口以及如何通过蓝牙模块传输其数据。在本文中,我将重点介绍两个HC-05蓝牙模块之间的蓝牙到蓝牙通信。

步骤三 电路搭建

手势控制机器人
手势控制机器人

现在让我们谈谈蓝牙模块的配置。基本上,HC-05蓝牙模块带有从属模块出厂设置。这意味着我们可以通过插入数据将数据发送到jus模块。无需进行任何其他设置即可将数据从移动设备发送到HC-05模块。只需输入其默认密码(1234/0000)即可进行连接。但是,如果我们想使用此模块将数据发送到其他相同模块或移动设备,该怎么办?

手势控制机器人

在这个项目中,我们做同样的事情,通过蓝牙模块发送数据。由mpu-6050陀螺仪传感器收集到另一个蓝牙模块。

手势控制机器人

为此,首先我们需要配置这两个蓝牙模块。以便它们在开机后可以自动相互绑定。在这里,第一个模块充当从设备,它将接收来自远程单元的信号并将其安装在汽车上。并将第二个设备配置为主设备,该主设备将充当发送器单元并将数据发送到从设备,因此,首先将第一个蓝牙模块配置为从设备。为此,请按照此接线图将其与Arduino连接。

手势控制机器人
#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());
}

断开模块。按住模块上的ky,然后将其重新连接。您会看到led on模块的闪烁速度变慢。每2秒一次。这意味着HC-05处于AT命令模式。现在打开串行监视器,将波特率更改为9600,并将输出类型分别设置为NL和CR。现在在发送框中键入AT并将其发送。如果回答确定,则表示一切正常。但是,如果没有,并且出现一些错误,请再次发送AT。直到它回复正常或检查连接并再次发送AT…

从模块获得OK响应后,依次输入以下命令,

AT + ORGL并将其发送。此命令将模块设置为出厂设置。

AT + RMAAD此命令将从先前的任何配对中释放模块

AT + UART?检查模块的当前波特率

AT + UART = 38400,0,0设置波特率为38400

AT +角色?检查角色是从属角色还是主角色。它回答0或1。如果模块是从设备,则回答0,如果它是主设备,则它将回答1。

将角色设置为从设备。输入AT + ROLE = 0

AT + ADDR?检查模块地址。

记下该地址。按模块回答。获取此地址后,将完成从站模块的配置

手势控制机器人

现在该配置第二个蓝牙模块作为主设备了。将此模块与Arduino开发板连接,并使其进入AT模式。就像上一个一样。

按给定顺序输入这些AT命令。

AT + ORGL

AT + RMAAD

AT + UART?

AT + UART = 38400,0,0

AT +角色?

将此模块设置为主设备。AT +角色= 1

AT + CMODE = 0,因此模块将仅连接单个设备。默认设置为0

现在将此模块与从属设备绑定以执行此输入,

AT + BIND =“从站模块的地址”并全部完成

现在安装用于MPU-6050传感器I2C通讯的库。由于MPU-6050陀螺仪传感器具有I2C接口。从此处下载库和源代码:http //www.mediafire.com/file/l8mru5emulb8x93/gesture_control_robot.rar/file

如果您已预先安装了这些库,请跳过此步骤。

现在,使用USB电缆将汽车单元与PC连接。选择正确的串口和单板类型。并以名称“ Gesture_controled_Robot__car_unit_”上传程序。上载程序时,请确保电池和蓝牙模块未与汽车连接。

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

对远程单元执行相同的操作。通过远程名称打开程序。并将其上传到远程单元。

手势控制机器人
//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');
}
}

将从属蓝牙模块插入汽车单元,并在远程单元上主控蓝牙模块。一切都完成了。

让我们打开电源,即可开始……。

步骤四 编写程序

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

              }

}

步骤五 验证结果

接下来我们就可以看到小车可以跟随手势进行移动了。

「点点赞赏,手留余香」

    还没有人赞赏,快来当第一个赞赏的人吧!
0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论