基于Arduino Leonardo和MPU6050模块的手势控制
本文将向你展示如何使用Arduino Leonardo和MPU6050加速计/陀螺仪模块来制作一个类似于任天堂Wii控制器的手势控制装置。手势控制装置主要用于游戏、互动活动和一些基础娱乐。几年前,任天堂创造了一种全新的人机交互模式,手势控制,它允许用户在Wii控制器的帮助下,通过游戏手柄与游戏内容进行交互。Wii控制器使用一个加速度计来识别你当前的手势,然后将手势映射到游戏控制器上。下面,我们也将使用Arduino Leonardo和MPU6050模块来制作一个有线的手势控制器。

工作原理
该装置依赖于两个关键组件:MPU6050和Arduino Leonardo。MPU6050可以帮助我们收集控制装置沿x轴和y轴移动的三维姿态数据。然后,根据传感器的值,我们可以控制光标位置。要实现单击鼠标的效果,需要停止移动光标并将其锁定在一个点上两秒钟(或者将它设置成一个按钮)。

MPU6050是一个IMU传感器,它基于MEMS技术,包含有6个自由度,可以提供6个值作为输出。这六个值中,三个来自加速度计,其余三个来自陀螺仪。
Arduino Leonardo与Arduino Uno外形相同。Arduino Uno配备的是ATmega385芯片,而Leonardo配备了atmega32u4芯片。它有20个数字输入/输出引脚,20个引脚中,7个引脚可作为PWM输出,12个引脚可作为模拟输入,同时它板载了一个微型USB接口,一个电源插口,一个ICSP端口和一个复位按钮。详见Arduino开发板知多少?
连接Arduino Leonardo和MPU6050
需要说明:因为该装置代码中需要引入mouse.h库文件,而该库文件只支持ATmega32U4芯片,所以只有在基于ATmega32U4芯片的Arduino开发板才能支持这个项目。因此,除了选择Arduino Leonardo外你还可以使用 Arduino Pro Mini开发板。


上传代码
根据上面的图连接好硬件后,就可以将你的Arduino Leonardo连接到电脑上,并将代码上传到你的Arduino上。代码分为两部分,第一部分是校准代码,第二部分是包点击功能的代码。首先上传校准代码:
//calibrate_air_mouse #include <Wire.h> #include <I2Cdev.h> #include <MPU6050.h> #include <Mouse.h> MPU6050 mpu; int16_t ax, ay, az, gx, gy, gz; int vx, vy; void setup() { Serial.begin(9600); Wire.begin(); mpu.initialize(); if (!mpu.testConnection()) { while (1); } } void loop() { mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); vx = (gx+300)/150; // change 300 from 0 to 355 vy = -(gz-100)/150; // same here about "-100" from -355 to 0 Serial.print("gx = "); Serial.print(gx); Serial.print(" | gz = "); Serial.print(gz); Serial.print(" | X = "); Serial.print(vx); Serial.print(" | Y = "); Serial.println(vy); Mouse.move(vx, vy); delay(20); }
上传代码后,鼠标指针就会映射到传感器上。尝试摇动MPU传感器模块。如果正常,请可以接着上传第二部分代码。如果光标不能与MPU6050的移动而移动,那么需要更改源代码中的一些值。可以打开串口监视器,确保可以x和y值可以归零,也就是静止状态。如果不能归零,请根据校准情况修改源代码中的 vx 或 vy 的值。位置如下:
vx = (gx+300)/150; // change 300 from 0 to 355 vy = -(gz-100)/150; // same here about "-100" from -355 to 0
校准完成后,就可以上传第二部分的代码,这段代码还添加了单击功能。单击时,是将光标停留在计算机屏幕上的某个点上约两秒钟。代码将检查光标是否在屏幕的10×10像素区域内停留了x秒的延迟,来执行点击效果的。
//air_mouse_with_click #include <Wire.h> #include <I2Cdev.h> #include <MPU6050.h> #include <Mouse.h> MPU6050 mpu; int16_t ax, ay, az, gx, gy, gz; int vx, vy, vx_prec, vy_prec; int count=0; void setup() { Serial.begin(9600); Wire.begin(); mpu.initialize(); if (!mpu.testConnection()) { while (1); } } void loop() { mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); vx = (gx+300)/200; vy = -(gz-100)/200; Mouse.move(vx, vy); if ( (vx_prec-5)<=vx && vx<=vx_prec+5 && (vy_prec-5)<=vy && vy<=vy_prec+5) { // for checking the cursor doesn't move too much from its actual position: (in this case a 10 pixel square) count++; if(count == 100){ // the click will happen after 2 seconds the pointer has stopped in the 10px square if (!Mouse.isPressed(MOUSE_LEFT)) { Mouse.press(MOUSE_LEFT); count = 0; } } else { if (Mouse.isPressed(MOUSE_LEFT)) { Mouse.release(MOUSE_LEFT); } } } else { vx_prec = vx; // updating values to check the position of the pointer and allow the click vy_prec = vy; count = 0; } delay(20); }