如何在家制作手势控制机器人
组件和用品
| × | 1 | ||||
| × | 1 | ||||
| × | 2 | ||||
| × | 1 | ||||
| × | 2 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 2 |
必要的工具和机器
| ||||
| ||||
| ||||
|
应用和在线服务
|
关于这个项目
这是关于如何自己制作手势控制的汽车。基本上这是 MPU-6050 3 轴陀螺仪、加速度计的简单应用。你可以做更多的事情。通过了解如何使用它、如何将其与 Arduino 连接以及如何通过蓝牙模块传输数据。在这篇文章中,我将重点介绍两个 HC-05 蓝牙模块之间的蓝牙到蓝牙通信。
按照视频为该项目构建机器人主体和连接。
图> 图> 图> 图> 图> 图> 图>下面给出了机器人和发射器单元的连接图,您可以参考。
图> 图> 图> 图>从PCBway直接订购本项目使用的PCB:https://www.pcbway.com/project/shareproject/How_to_Make_Arduino_Based_Edge_Avoiding_Robot.html
图> 图> 图> 图> 图> 图> 图> 图> 图>现在来说说蓝牙模块配置。基本上,HC-05 蓝牙模块带有从属模块出厂设置。这意味着我们可以通过插入模块将数据发送到 jus。无需进行任何其他设置即可从移动设备向 HC-05 模块发送数据。只需输入其默认密码 (1234/0000) 即可连接。但是如果我们想使用这个模块将数据发送到其他相同的模块或移动设备怎么办。
图>在这个项目中,我们做同样的事情,通过蓝牙模块发送数据。 mpu-6050陀螺仪传感器采集到另一个蓝牙模块。
所以要做到这一点首先我们需要配置这两个蓝牙模块。使它们在通电后可以自动相互绑定。在这里,第一个模块充当从设备,它将接收来自远程单元的信号并安装在汽车上。并将第二个配置为主设备,它将充当发送器单元并向从设备发送数据,所以首先将第一个蓝牙模块配置为从设备。为此,请按照此接线图将其与 Arduino 连接。
并按名称上传代码配置。
#include
SoftwareSerial BTSerial(10, 11); // 接收 | TX
void setup()
{
Serial.begin(9600);
Serial.println("输入 AT 命令:");
BTSerial.begin(38400) ); // HC-05 AT 命令中的默认速度 more
}
void loop()
{
// 继续从 HC-05 读取并发送到 Arduino 串行监视器
if (BTSerial.available())
Serial.write(BTSerial.read());
// 继续从 Arduino 串行监视器读取并发送到 HC-05
if (Serial.可用())
BTSerial.write(Serial.read());
}
断开模块。按住模块上的 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+UART?
AT+UART=38400, 0, 0
AT+角色?
将此模块的角色设置为主设备。 AT+ROLE=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_”上传程序。上传程序时,请确保电池和蓝牙模块未与汽车连接。
//由 Shubham Shinganapure 于 3-10-2019 编写的程序
//
//用于手势控制的机器人车
int lm1=8; //左电机输出1
int lm2=9; //左电机输出2
int rm1=10; //右马达输出1
int rm2=11; //右电机输出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);
}
对远程单元执行相同操作。按名称远程打开程序。并将其上传到远程单元。
//由 Shubham Shinganapure 于 3/10/19 修改的程序。
//
//用于手势控制的机器人汽车(远程)
#include " I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
//#include "MPU6050.h" // 如果使用 MotionApps 包含文件则不需要
// 如果 I2Cdev 需要 Arduino Wire 库I2CDEV_ARDUINO_WIRE实现
//用于I2Cdev.h
#if I2CDEV_IMPLEMENTATION ==I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
//类默认I2C地址是 0x68
// 特定的 I2C 地址可以作为参数在这里传递
// AD0 低 =0x68(SparkFun 突破和 InvenSense 评估板的默认值)
// AD0 高 =0x69
MPU6050 mpu;
#define OUTPUT_READABLE_YAWPITCHROLL
// MPU 控制/状态变量
bool dmpReady =false; // 如果 DMP 初始化成功则设置为真
uint8_t mpuIntStatus; // 保存来自 MPU 的实际中断状态字节
uint8_t devStatus; // 每次设备操作后返回状态(0 =成功,!0 =错误)
uint16_t packetSize; // 预期的 DMP 数据包大小(默认为 42 字节)
uint16_t fifoCount; // 当前 FIFO 中所有字节的计数
uint8_t fifoBuffer[64]; // FIFO存储缓冲区
VectorFloat weight;
四元数q;
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll 容器和重力矢量
uint8_t teapotPacket[14] ={ '$', 0x02, 0,0, 0,0, 0,0, 0,0 , 0x00, 0x00, '\r', '\n' };
volatile bool mpuInterrupt =false; // 指示 MPU 中断引脚是否变高
void dmpDataReady() {
mpuInterrupt =true;
}
#include
SoftwareSerial BTSerial( 10, 11); // 接收 | TX
int bt=8;
int x =1;
void setup() {
#if I2CDEV_IMPLEMENTATION ==I2CDEV_ARDUINO_WIRE
Wire.begin();
TWBR =24; // 400kHz I2C 时钟(如果 CPU 为 8MHz,则为 200kHz)
#elif I2CDEV_IMPLEMENTATION ==I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
// 初始化串行通信
//(选择 115200 是因为茶壶演示输出需要它,但它
// 取决于您的项目)
Serial.begin(115200);
BTSerial.begin(38400);
// while (!Serial); // 等待 Leonardo 枚举,其他人立即继续
Serial.println(F("Initializing I2C devices..."));
mpu.initialize();
// 验证连接
Serial.println(F("测试设备连接..."));
Serial.println(mpu.testConnection() ? F("MPU6050 连接成功") :F("MPU6050 连接失败" ));
// 等待就绪
// 加载并配置 DMP
Serial.println(F("Initializing DMP..."));
devStatus =mpu .dmpInitialize();
// 在这里提供您自己的陀螺偏移量,按最小灵敏度缩放
mpu.setXGyroOffset(220);
mpu.setYGyroOffset(76);
mpu. setZGyroOffset(-85);
mpu.setZAccelOffset(1788);
// 确保它有效(如果是,则返回 0)
if (devStatus ==0) {
/ / 打开 DMP,现在它已经准备好了
Serial.println(F("Enabling DMP..."));
mpu.setDMPEnabled(true);
// 启用 Arduino 中断检测
Serial.println(F("启用中断检测(Arduino外部中断0)..."));
a ttachInterrupt(0, dmpDataReady, RISING);
mpuIntStatus =mpu.getIntStatus();
// 设置我们的 DMP Ready 标志,以便主 loop() 函数知道可以使用它
Serial .println(F("DMP 准备好了!等待第一个中断..."));
dmpReady =true;
// 获取预期的 DMP 数据包大小以供以后比较
packetSize =mpu.dmpGetFIFOPacketSize();
} else {
// 错误!
// 1 =初始内存加载失败
// 2 =DMP 配置更新失败
//(如果它要崩溃,通常是代码将是 1)
Serial.print(F("DMP Initialization failed (code "));
Serial.print(devStatus);
Serial.println(F(")"));
}
// 为输出配置 LED
pinMode(bt,INPUT);
}
// ================================================================
// ===主程序循环 ===
// ================================================================
void loop() {
if(digitalRead(bt)==HIGH)
{
x++;
delay(150);
}
if((x%2)==0) {
// 如果编程失败,不要尝试做任何事情
if (!dmpReady) return;
// 等待 MPU 中断或额外的数据包可用
while (!mpuInterrupt &&fifoCount // 这里的其他程序行为内容
// .
// .
// .
// 如果你真的很偏执,你可以经常测试在其他
// 之间查看mpuInterrupt 是否为真,如果是,则从
// while() 循环中“中断”以立即处理MPU 数据
//。
// .
// .
}
// 重置中断标志并获取 INT_STATUS 字节
mpuInterrupt =false;
mpuIntStatus =mpu.getIntStatus( );
// 获取当前 FIFO 计数
fifoCount =mpu.getFIFOCount();
// 检查溢出(除非我们的代码效率太低,否则永远不会发生)
if ((mpuIntStatus &0x10) || fifoCount ==1024) {
// 重置以便我们可以干净地继续
mpu.resetFIFO();
Serial.println(F("FIFO 溢出!"));
// 否则,检查 DMP 数据就绪中断(这应该经常发生)
} else if (mpuIntStatus &0x02) {
// 等待正确的可用数据长度,应该是一个非常短的等待
while (fifoCount // 从 FIFO 中读取一个数据包
mpu.getFIFOBytes(fifoBuffer, packetSize);
// 在这里跟踪 FIFO 计数如果有> 1 个数据包可用
//(这让我们可以立即读取更多数据而无需等待中断)
fifoCount -=packetSize;
#ifdef OUTPUT_READABLE_YAWPITCHROLL
// 显示以度为单位的欧拉角
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);
串行.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');
}
}
在车载单元上插入从属蓝牙模块,在远程单元上主控蓝牙模块。大功告成。
图> 图> 图>让我们打开它,它就可以开始播放了.......
图> 图> 图> 图>
希望您觉得这个有帮助。如果是,喜欢它,分享它,评论你的疑问。更多此类项目,关注我!在 YouTube 上支持我的工作并订阅我的频道。
谢谢!
代码
- 手势控制机器人(远程单元)
手势控制机器人(远程单元)Arduino
//19 年 3 月 10 日由 Shubham Shinganapure 修改的程序。 ////对于手势控制的机器人车(远程)#include "I2Cdev.h"#include "MPU6050_6Axis_MotionApps20.h"//#include "MPU6050.h" // 如果使用 MotionApps 则不需要包含文件 // Arduino Wire 库是如果 I2Cdev I2CDEV_ARDUINO_WIRE 实现需要 // 在 I2Cdev.h 中使用#if I2CDEV_IMPLEMENTATION ==I2CDEV_ARDUINO_WIRE #include "Wire.h"#endif// 类默认 I2C 地址是 0x68 // 特定的 I2C 地址可以作为参数在这里传递// AD0 低 =0x68(SparkFun 突破和 InvenSense 评估板的默认值)// AD0 高 =0x69MPU6050 mpu;#define OUTPUT_READABLE_YAWPITCHROLL// MPU 控制/状态 varsbool dmpReady =false; // 如果 DMP 初始化成功则设置为真uint8_t mpuIntStatus; // 保存来自 MPUuint8_t devStatus 的实际中断状态字节; // 每次设备操作后返回状态(0 =成功,!0 =错误)uint16_t packetSize; // 预期的 DMP 数据包大小(默认为 42 字节)uint16_t fifoCount; // 当前 FIFOuint8_t fifoBuffer[64] 中所有字节的计数; // FIFO 存储 bufferVectorFloat 重力;四元数 q;浮动 ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll 容器和重力 vectoruint8_t teapotPacket[14] ={ '$', 0x02, 0,0, 0,0, 0,0, 0,0, 0x00, 0x00, '\r', '\n' }; volatile bool mpuInterrupt =false; // 指示 MPU 中断引脚是否变为 highvoid dmpDataReady() { mpuInterrupt =true;}#includeSoftwareSerial BTSerial(10, 11); // 接收 | TXint bt=8;int x =1;void setup() { #if I2CDEV_IMPLEMENTATION ==I2CDEV_ARDUINO_WIRE Wire.begin(); TWBR =24; // 400kHz I2C 时钟(如果 CPU 为 8MHz,则为 200kHz)#elif I2CDEV_IMPLEMENTATION ==I2CDEV_BUILTIN_FASTWIRE Fastwire::setup(400, true); #endif // 初始化串行通信 //(选择 115200 是因为茶壶演示输出需要它,但它 // 真的取决于你的项目) Serial.begin(115200); BTSerial.begin(38400); // 同时 (!Serial); // 等待 Leonardo 枚举,其他人立即继续Serial.println(F("Initializing I2C devices...")); mpu.initialize(); // 验证连接 Serial.println(F("Testing device connections...")); Serial.println(mpu.testConnection() ? F("MPU6050 连接成功") :F("MPU6050 连接失败")); // 等待就绪 // 加载并配置 DMP Serial.println(F("Initializing DMP...")); devStatus =mpu.dmpInitialize(); // 在这里提供您自己的陀螺仪偏移量,按最小灵敏度进行缩放 mpu.setXGyroOffset(220); mpu.setYGyroOffset(76); mpu.setZGyroOffset(-85); mpu.setZAccelOffset(1788); // 确保它工作(如果是,则返回 0) if (devStatus ==0) { // 打开 DMP,现在它已准备就绪 Serial.println(F("Enabling DMP...")); mpu.setDMPEnabled(true); // 启用 Arduino 中断检测 Serial.println(F("启用中断检测 (Arduino 外部中断 0)...")); attachInterrupt(0, dmpDataReady, RISING); mpuIntStatus =mpu.getIntStatus(); // 设置我们的 DMP Ready 标志,以便主 loop() 函数知道可以使用它 Serial.println(F("DMP ready! Waiting for first interrupt...")); dmpReady =真; // 获取预期的 DMP 数据包大小以供稍后比较 packetSize =mpu.dmpGetFIFOPacketSize(); } else { // 错误! // 1 =初始内存加载失败 // 2 =DMP 配置更新失败 //(如果它会中断,通常代码将为 1) Serial.print(F("DMP Initialization failed (code ")); Serial.print(F("DMP Initialization failed (code ")); Serial.打印(devStatus);Serial.println(F(“)”)); } // 配置 LED 输出 pinMode(bt,INPUT); }// ================================================================// ===主程序循环 ===// ==============================================================void loop() { if (digitalRead(bt)==HIGH) { x++;延迟(150); } if((x%2)==0){ // 如果编程失败,不要尝试做任何事情 if (!dmpReady) return; // 等待 MPU 中断或额外的数据包可用,而 (!mpuInterrupt &&fifoCount 1 个可用数据包 //(这让我们可以立即读取更多数据而无需等待中断) fifoCount -=packetSize; #ifdef OUTPUT_READABLE_YAWPITCHROLL // 以度为单位显示欧拉角 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'); }}
示意图
制造工艺