本网页已闲置超过3分钟,按键盘任意键或点击空白处,即可回到网页

在家就能做:双 HC-05 蓝牙模块手势控制机器人

发布时间:2021-12-30
分享到:

在家就能做:双 HC-05 蓝牙模块手势控制机器人

发布时间:2021-12-30
分享到:

本篇是关于如何自己制作手势控制汽车的文章。基本上是 MPU-6050 3 轴陀螺仪、加速度计的简单应用。在此基础上,还可以做一些其他模块的添加。

在这篇文章中,我将重点介绍两个 HC-05 蓝牙模块之间的蓝牙到蓝牙通信,通过了解如何使用它、如何将其与 Arduino 连接以及如何通过蓝牙模块传输数据。

下面给出了机器人和发射器单元的连接图,可以用于参考。

现在来说说蓝牙模块配置。基本上,HC-05 蓝牙模块带有从属模块出厂设置。这意味着我们可以通过插入它来向模块发送数据。不需要做任何其他设置来从移动设备发送数据到HC-05模块。只需输入其默认密码 (1234/0000) 即可连接。但是如果我们想使用这个模块将数据发送到其他相同的模块或移动设备呢?

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

所以要做到这一点首先我们需要配置这两个蓝牙模块。使它们在通电后可以自动相互绑定。在这里,第一个模块充当从设备,它将接收来自远程单元的信号并安装在汽车上。并将第二个配置为主设备,它将充当发送器单元并向从设备发送数据,

所以首先将第一个蓝牙模块配置为从设备。为此,请按照此接线图将其与 Arduino 连接。

并按名称上传代码配置。

断开模块。按住模块上的 ky 并将其连接回去。您将看到模块上的 LED 闪烁较慢。每 2 秒一次。这意味着 HC-05 处于 AT 命令模式。现在打开串行监视器,将波特率更改为 9600,输出类型为 NL 和 CR。现在在发送框中键入 AT 并发送。如果它回复 ok,则表示一切都很好。但如果不是,并且回复有错误,请再次发送 AT。直到它回复 ok 或 chek 连接并再次发送 AT

得到模块的OK响应后,一一输入以下命令,

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

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

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

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

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

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

AT+地址?检查模块地址。

记下这个地址,得到这个地址后,就完成了对从模块的配置。

现在是时候将第二个蓝牙模块配置为主设备了。将此模块与Arduino板连接并进入AT模式。正如我们对上一个所做的那样。

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

AT+ORGL

AT+RMAAD

AT+串口?

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 电缆将汽车单元与电脑连接。选择正确的 com 端口和板卡类型。并按名称“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');
}
}

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

直接打开它,就可以开始播放了。

如果您对此项目有任何想法、意见或问题,请在下方留言。

原文链接丨以上内容来源网络,如涉及侵权可联系删除。

加入微信技术交流群

技术交流,职业进阶

关注与非网服务号

获取电子工程师福利

加入电路城 QQ 交流群

与技术大牛交朋友

讨论