【雕爷学编程】Arduino动手做(108)---GY-521三轴模块

37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里准备逐一动手尝试系列实验,不管成功(程序走通)与否,都会记录下来---小小的进步或是搞不掂的问题,希望能够抛砖引玉。

 

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)

实验一百零八:MPU-6050模块 三轴加速度 电子陀螺仪6DOF GY-521传感器(三轴陀螺仪 + 三轴加速度)

 

 

 陀螺仪传感器
是一个简单易用的基于自由空间移动和手势的定位和控制系统,它原本是运用到直升机模型上,现已被广泛运用于手机等移动便携设备。对于不熟悉这类产品的人来说,陀螺仪传感器是一个简单易用的基于自由空间移动和手势的定位和控制系统。在假想的平面上挥动鼠标,屏幕上的光标就会跟着移动,并可以绕着链接画圈和点击按键。当你正在演讲或离开桌子时,这些操作都能够很方便地实现。 陀螺仪传感器原本是运用到直升机模型上的,已经被广泛运用于手机这类移动便携设备上(IPHONE的三轴陀螺仪技术)。陀螺仪的原理就是,一个旋转物体的旋转轴所指的方向在不受外力影响时,是不会改变的。人们根据这个道理,用它来保持方向。然后用多种方法读取轴所指示的方向,并自动将数据信号传给控制系统。我们骑自行车其实也是利用了这个原理。轮子转得越快越不容易倒,因为车轴有一股保持水平的力量。现代陀螺仪可以精确地确定运动物体的方位的仪器,它在现代航空,航海,航天和国防工业中广泛使用的一种惯性导航仪器。传统的惯性陀螺仪主要部分有机械式的陀螺仪,而机械式的陀螺仪对工艺结构的要求很高。70年代提出了现代光纤陀螺仪的基本设想,到八十年代以后,光纤陀螺仪就得到了非常迅速的发展,激光谐振陀螺仪也有了很大的发展。光纤陀螺仪具有结构紧凑,灵敏度高,工作可靠。光纤陀螺仪在很多的领域已经完全取代了机械式的传统的陀螺仪,成为现代导航仪器中的关键部件。光纤陀螺仪同时发展的除了环式激光陀螺仪外。

 

MPU-6050(6000)
为全球首例整合性6轴运动处理组件,相较于多组件方案,免除了组合陀螺仪与加速器时间轴之差的问题,减少了大量的封装空间。当连接到三轴磁强计时,MPU-60X0提供完整的9轴运动融合输出到其主I2C或SPI端口(SPI仅在MPU-6000上可用)。MPU-6050(6000)的角速度全格感测范围为±250、±500、±1000与±2000°/sec (dps),可准确追踪快速与慢速动作,并且,用户可程式控制的加速器全格感测范围为±2g、±4g±8g与±16g。产品传输可透过最高至400kHz的IIC或最高达20MHz的SPI(MPU-6050没有SPI)。MPU-6000可在不同电压下工作,VDD供电电压介为2.5V±5%、3.0V±5%或3.3V±5%,逻辑接口VDDIO供电为1.8V± 5%(MPU6000仅用VDD)。MPU-6000的包装尺寸4x4x0.9mm(QFN),在业界是革命性的尺寸。其他的特征包含内建的温度感测器、包含在运作环境中仅有±1%变动的振荡器。

 

 

技术特征
以数字输出6轴或9轴的旋转矩阵、四元数(quaternion)、欧拉角格式(Euler Angle forma)的融合演算数据。 具有131 LSBs/°/sec 敏感度与全格感测范围为±250、±500、±1000与±2000°/sec 的3轴角速度感测器(陀螺仪)。 可程式控制,且程式控制范围为±2g、±4g、±8g和±16g的3轴加速器。 移除加速器与陀螺仪轴间敏感度,降低设定给予的影响与感测器的飘移。 数字运动处理(DMP: Digital Motion Processing)引擎可减少复杂的融合演算数据、感测器同步化、姿势感应等的负荷。 运动处理数据库支持Android、Linux与Windows 内建之运作时间偏差与磁力感测器校正演算技术,免除了客户须另外进行校正的需求。 以数位输出的温度传感器 以数位输入的同步引脚(Sync pin)支援视频电子影相稳定技术与GPS 可程式控制的中断(interrupt)支援姿势识别、摇摄、画面放大缩小、滚动、快速下降中断、high-G中断、零动作感应、触击感应、摇动感应功能。 VDD供电电压为2.5V±5%、3.0V±5%、3.3V±5%;VDDIO为1.8V± 5% 陀螺仪运作电流:5mA,陀螺仪待命电流:5µA;加速器运作电流:350µA,加速器省电模式电流: 20µA@10Hz 高达400kHz快速模式的I2C,或最高至20MHz的SPI串行主机接口(serial host interface) 内建频率产生器在所有温度范围(full temperature range)仅有±1%频率变化。 使用者亲自测试 10,000 g 碰撞容忍度 为可携式产品量身订作的最小最薄包装 (4x4x0.9mm QFN) 符合RoHS及环境标准。

陀螺仪
是用高速回转体的动量矩敏感壳体相对惯性空间绕正交于自转轴的一个或二个轴的角运动检测装置。利用其他原理制成的角运动检测装置起同样功能的也称陀螺仪。绕一个支点高速转动的刚体称为陀螺(top)。通常所说的陀螺是特指对称陀螺,它是一个质量均匀分布的、具有轴对称形状的刚体,其几何对称轴就是它的自转轴。 与苍蝇退化的后翅(平衡棒)原理类似。在一定的初始条件和一定的外在力矩作用下,陀螺会在不停自转的同时,环绕着另一个固定的转轴不停地旋转,这就是陀螺的旋进(precession),又称为回转效应(gyroscopic effect)。陀螺旋进是日常生活中常见的现象,许多人小时候都玩过的陀螺就是一例。人们利用陀螺的力学性质所制成的各种功能的陀螺装置称为陀螺仪(gyroscope),它在科学、技术、军事等各个领域有着广泛的应用。比如:回转罗盘、定向指示仪、炮弹的翻转、陀螺的章动等。陀螺仪的种类很多,按用途来分,它可以分为传感陀螺仪和指示陀螺仪。传感陀螺仪用于飞行体运动的自动控制系统中,作为水平、垂直、俯仰、航向和角速度传感器。指示陀螺仪主要用于飞行状态的指示,作为驾驶和领航仪表使用。陀螺仪分为,压电陀螺仪,微机械陀螺仪,光纤陀螺仪和激光陀螺仪,它们都是电子式的,并且它们可以和加速度计,磁阻芯片,GPS,做成惯性导航控制系统。

 

 

 

陀螺仪原理
是指陀螺仪工作的原理,螺旋仪是一种用来传感与维持方向的装置,基于角动量守恒的理论设计出来的。陀螺仪主要是由一个位于轴心且可旋转的转子构成。 陀螺仪一旦开始旋转,由于转子的角动量,陀螺仪有抗拒方向改变的趋向。陀螺仪多用于导航、定位等系统常用实例如手机GPS定位导航、卫星三轴陀螺仪定位。陀螺仪基本上就是运用物体高速旋转时,角动量很大,旋转轴会一直稳定指向一个方向的性质,所制造出来的定向仪器。不过它必需转得够快,或者惯量够大(也可以说是角动量要够大)。不然,只要一个很小的力矩,就会严重影响到它的稳定性。高速旋转的物体的旋转轴,对于改变其方向的外力作用有趋向于垂直方向的倾向。而且,旋转物体在横向倾斜时,重力会向增加倾斜的方向作用,而轴则向垂直方向运动,就产生了摇头的运动(岁差运动)。当陀螺经纬仪的陀螺旋转轴以水平轴旋转时,由于地球的旋转而受到铅直方向旋转力,陀螺的旋转体向水平面内的子午线方向产生岁差运动。当轴平行于子午线而静止时可加以应用。陀螺仪基本上就是运用物体高速旋转时,角动量很大,旋转轴会一直稳定指向一个方向的性质,所制造出来的定向仪器。不过它必需转得够快,或者惯量够大(也可以说是角动量要够大)。不然,只要一个很小的力矩,就会严重影响到它的稳定性。

 

 

加速度(Acceleration)
是速度变化量与发生这一变化所用时间的比值Δv/Δt,是描述物体速度变化快慢的物理量,通常用a表示,单位是m/s2。加速度是矢量,它的方向是物体速度变化(量)的方向,与合外力的方向相同。表示质点速度变化的快慢的物理量。举例:假如两辆汽车开始静止,均匀地加速后,达到10m/s的速度,A车花了10s,而B车只用了5s。它们的速度都从0变为10m/s,速度改变了10m/s。所以它们的速度变化量是一样的。但是很明显,B车变化得更快一些。我们用加速度来描述这个现象:B车的加速度(a=Δv/Δt,其中的Δv是速度变化量)>A车的加速度。显然,当速度变化量一样的时候,花时间较少的B车,加速度更大。也就是说B车的启动性能相对A车好一些。因此,加速度是表示物体速度变化快慢的物理量。加速度 (acceleration) 表征单位时间内速度改变程度的矢量。一般情况下,加速度是个瞬时概念,它的常用单位是米/秒²、m/s2等。

 

加速度传感器(acceleration transducer)

是一种能够测量加速度的传感器。通常由质量块、阻尼器、弹性元件、敏感元件和适调电路等部分组成。传感器在加速过程中,通过对质量块所受惯性力的测量,利用牛顿第二定律获得加速度值。根据传感器敏感元件的不同,常见的加速度传感器包括电容式、电感式、应变式、压阻式、压电式等。线加速度计的原理是惯性原理,也就是力的平衡,A(加速度)=F(惯性力)/M(质量) 我们只需要测量F就可以了。怎么测量F?用电磁力去平衡这个力就可以了。就可以得到 F对应于电流的关系。只需要用实验去标定这个比例系数就行了。当然中间的信号传输、放大、滤波就是电路的事了。多数加速度传感器是根据压电效应的原理来工作的。所谓的压电效应就是 "对于不存在对称中心的异极晶体加在晶体上的外力除了使晶体发生形变以外,还将改变晶体的极化状态,在晶体内部建立电场,这种由于机械力作用使介质发生极化的现象称为正压电效应 "。一般加速度传感器就是利用了其内部的由于加速度造成的晶体变形这个特性。由于这个变形会产生电压,只要计算出产生电压和所施加的加速度之间的关系,就可以将加速度转化成电压输出。当然,还有很多其它方法来制作加速度传感器,比如压阻技术,电容效应,热气泡效应,光效应,但是其最基本的原理都是由于加速度产生某个介质产生变形,通过测量其变形量并用相关电路转化成电压输出。每种技术都有各自的机会和问题。使用加速度传感器有时会碰到低频场合测量时输出信号出现失真的情况,用多种测量判断方法一时找不出故障出现的原因,经过分析总结,导致测量结果失真的因素主要是:系统低频响应差,系统低频信噪比差,外界环境对测量信号的影响。 所以,只要出现加速度传感器低频测量信号失真情况,对比以上三点看看是哪个因素造成的,有针对性的进行解决。

 

MPU 6050属于IMU传感器系列,通常被用于自平衡机器人、无人机、智能手机等领域。IMU传感器可以帮助我们在三维空间中获取物体当前三维位置的值,这些值可以用来帮助我们确定物体的精确位置,通过MPU6050可以检测智能手机的水平或倾斜状态或是使用IMU传感器来追踪运动状态等。MU传感器通常包含两个或多个功能,按优先级分别是加速计、陀螺仪、磁力计和测高仪。MPU 6050是6自由度或6轴的IMU传感器,这意味着它提供了6个值作为输出:包含加速度计的3个值和陀螺仪的3个值。MPU 6050是一种基于MEMS(微机电系统)技术的传感器,它将加速度计和陀螺仪嵌入到一块芯片中,芯片使用的I2C通信协议。

 

 

 

名称:电子陀螺仪6DOF GY-521传感器
使用芯片:MPU-6050
供电电源:3-5v(内部低压差稳压)
通信方式:标准IIC通信协议
芯片内置16bit AD转换器,16位数据输出
陀螺仪范围:±250 500 1000 2000  °/s
加速度范围:±2±4±8±16g   
采用沉金PCB,机器焊接工艺保证质量
引脚间距2.54mm

应用
运动感测游戏
现实增强
电子稳像 (EIS: Electronic Image Stabilization)
光学稳像(OIS: Optical Image Stabilization)
行人导航器
“零触控”手势用户接口
姿势快捷方式
认证

 


模块电原理图

 

 

实验接线示意图

 

 

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验一百零八:MPU-6050模块 三轴加速度 电子陀螺仪6DOF GY-521传感器(三轴陀螺仪 + 三轴加速度)
项目之一:测试MPU6050示例
实验接线:
Arduino------MPU 6050
5V-------------VCC
GND-----------GND
A4-----------SDA IIC 数据线
A5-----------SCL IIC 时钟线
D2-----------INT 中断脚

 

/*

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)

实验一百零八:MPU-6050模块 三轴加速度 电子陀螺仪6DOF GY-521传感器(三轴陀螺仪 + 三轴加速度)

项目之一:测试MPU6050示例

实验接线:

Arduino------MPU 6050

5V-------------VCC

GND-----------GND

A4-----------SDA IIC 数据线

A5-----------SCL IIC 时钟线

D2-----------INT 中断脚

*/



#include "I2Cdev.h"

#include "MPU6050_6Axis_MotionApps20.h"

//#include "MPU6050.h" 

#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE

  #include "Wire.h"

  #endif

MPU6050 mpu;

#define OUTPUT_READABLE_YAWPITCHROLL

#define LED_PIN 13 

bool blinkState = false;

// MPU control/status vars

bool dmpReady = false;  

uint8_t mpuIntStatus;  

uint8_t devStatus;    

uint16_t packetSize;   

uint16_t fifoCount;   

uint8_t fifoBuffer[64]; 

Quaternion q;      

VectorInt16 aa;     

VectorInt16 aaReal;   

VectorInt16 aaWorld;   

VectorFloat gravity;  

float euler[3];     

float ypr[3];      

uint8_t teapotPacket[14] = { '

, 0x02, 0,0, 0,0, 0,0, 0,0, 0x00, 0x00, '\r', '\n' };

volatile bool mpuInterrupt = false;   

void dmpDataReady() {

  mpuInterrupt = true;

}

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

  Serial.begin(115200);

  while (!Serial); 

  Serial.println(F("Initializing I2C devices..."));

  mpu.initialize();

  Serial.println(F("Testing device connections..."));

  Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));

  Serial.println(F("\nSend any character to begin DMP programming and demo: "));

  while (Serial.available() && Serial.read()); 

  while (!Serial.available());         

  while (Serial.available() && Serial.read()); 

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

  devStatus = mpu.dmpInitialize();

  mpu.setXGyroOffset(220);

  mpu.setYGyroOffset(76);

  mpu.setZGyroOffset(-85);

  mpu.setZAccelOffset(1788); 

  if (devStatus == 0) {

  

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

    mpu.setDMPEnabled(true);

    Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));

    attachInterrupt(0, dmpDataReady, RISING);

    mpuIntStatus = mpu.getIntStatus();

    Serial.println(F("DMP ready! Waiting for first interrupt..."));

    dmpReady = true;

    packetSize = mpu.dmpGetFIFOPacketSize();

  } 

  else {

     

    Serial.print(F("DMP Initialization failed (code "));

    Serial.print(devStatus);

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

  }

  // configure LED for output

  pinMode(LED_PIN, OUTPUT);

}

void loop() {

  if (!dmpReady) return;

  while (!mpuInterrupt && fifoCount < packetSize) {

  }

  mpuInterrupt = false;

  mpuIntStatus = mpu.getIntStatus();

  fifoCount = mpu.getFIFOCount();

  if ((mpuIntStatus & 0x10) || fifoCount == 1024) {

     

    mpu.resetFIFO();

    Serial.println(F("FIFO overflow!"));

  } else if (mpuIntStatus & 0x02) {

    while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();

    mpu.getFIFOBytes(fifoBuffer, packetSize);

     

    fifoCount -= packetSize;

    #ifdef OUTPUT_READABLE_QUATERNION

      

      mpu.dmpGetQuaternion(&q, fifoBuffer);

      Serial.print("quat\t");

      Serial.print(q.w);

      Serial.print("\t");

      Serial.print(q.x);

      Serial.print("\t");

      Serial.print(q.y);

      Serial.print("\t");

      Serial.println(q.z);

    #endif

    #ifdef OUTPUT_READABLE_EULER

      

      mpu.dmpGetQuaternion(&q, fifoBuffer);

      mpu.dmpGetEuler(euler, &q);

      Serial.print("euler\t");

      Serial.print(euler[0] * 180/M_PI);

      Serial.print("\t");

      Serial.print(euler[1] * 180/M_PI);

      Serial.print("\t");

      Serial.println(euler[2] * 180/M_PI);

    #endif

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

    #endif

    #ifdef OUTPUT_READABLE_REALACCEL

       

      mpu.dmpGetQuaternion(&q, fifoBuffer);

      mpu.dmpGetAccel(&aa, fifoBuffer);

      mpu.dmpGetGravity(&gravity, &q);

      mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);

      Serial.print("areal\t");

      Serial.print(aaReal.x);

      Serial.print("\t");

      Serial.print(aaReal.y);

      Serial.print("\t");

      Serial.println(aaReal.z);

    #endif

    #ifdef OUTPUT_READABLE_WORLDACCEL

      

      mpu.dmpGetQuaternion(&q, fifoBuffer);

      mpu.dmpGetAccel(&aa, fifoBuffer);

      mpu.dmpGetGravity(&gravity, &q);

      mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);

      mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);

      Serial.print("aworld\t");

      Serial.print(aaWorld.x);

      Serial.print("\t");

      Serial.print(aaWorld.y);

      Serial.print("\t");

      Serial.println(aaWorld.z);

    #endif

   

    #ifdef OUTPUT_TEAPOT

       

      teapotPacket[2] = fifoBuffer[0];

      teapotPacket[3] = fifoBuffer[1];

      teapotPacket[4] = fifoBuffer[4];

      teapotPacket[5] = fifoBuffer[5];

      teapotPacket[6] = fifoBuffer[8];

      teapotPacket[7] = fifoBuffer[9];

      teapotPacket[8] = fifoBuffer[12];

      teapotPacket[9] = fifoBuffer[13];

      Serial.write(teapotPacket, 14);

      teapotPacket[11]++; 

    #endif

    blinkState = !blinkState;

    digitalWrite(LED_PIN, blinkState);

    delay(1000);

  }

}

  

实验串口返回情况

 

串口提示的翻译(未接D2时)
正在初始化I2C设备…
正在测试设备连接…
MPU6050连接成功

发送任意字符开始DMP编程和演示:
正在初始化DMP…
正在启用DMP…
启用中断检测(Arduino外部中断0…)
DMP准备好了!正在等待第一个中断…

 

 

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)

实验一百零八:MPU-6050模块 三轴加速度 电子陀螺仪6DOF GY-521传感器(三轴陀螺仪 + 三轴加速度)

项目之二:显示六轴曲线

实验接线:

Arduino------MPU 6050

5V-------------VCC

GND-----------GND

A4-----------SDA IIC 数据线

A5-----------SCL  IIC 时钟线

D2-----------INT 中断脚

 

 

/*

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)

实验一百零八:MPU-6050模块 三轴加速度 电子陀螺仪6DOF GY-521传感器(三轴陀螺仪 + 三轴加速度)

项目之二:显示六轴曲线

实验接线:

Arduino------MPU 6050

5V-------------VCC

GND-----------GND

A4-----------SDA IIC 数据线

A5-----------SCL  IIC 时钟线

D2-----------INT 中断脚

*/



#include "I2Cdev.h"

#include "MPU6050.h"

#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE

  #include "Wire.h"

#endif

MPU6050 accelgyro;

int16_t ax, ay, az;

int16_t gx, gy, gz;

#define OUTPUT_READABLE_ACCELGYRO

#define LED_PIN 13

bool blinkState = false;

void setup() {

   

  #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE

    Wire.begin();

  #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE

    Fastwire::setup(400, true);

  #endif

  Serial.begin(38400);

  Serial.println("Initializing I2C devices...");

  accelgyro.initialize();

  Serial.println("Testing device connections...");

  Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");

   

  pinMode(LED_PIN, OUTPUT);

}

void loop() {

  accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

  #ifdef OUTPUT_READABLE_ACCELGYRO

    Serial.print("a/g:\t");

    Serial.print(ax); Serial.print("\t");

    Serial.print(ay); Serial.print("\t");

    Serial.print(az); Serial.print("\t");

    Serial.print(gx); Serial.print("\t");

    Serial.print(gy); Serial.print("\t");

    Serial.println(gz);

  #endif

  #ifdef OUTPUT_BINARY_ACCELGYRO

    Serial.write((uint8_t)(ax >> 8)); Serial.write((uint8_t)(ax & 0xFF));

    Serial.write((uint8_t)(ay >> 8)); Serial.write((uint8_t)(ay & 0xFF));

    Serial.write((uint8_t)(az >> 8)); Serial.write((uint8_t)(az & 0xFF));

    Serial.write((uint8_t)(gx >> 8)); Serial.write((uint8_t)(gx & 0xFF));

    Serial.write((uint8_t)(gy >> 8)); Serial.write((uint8_t)(gy & 0xFF));

    Serial.write((uint8_t)(gz >> 8)); Serial.write((uint8_t)(gz & 0xFF));

  #endif

  blinkState = !blinkState;

  digitalWrite(LED_PIN, blinkState);

  delay(50);

}

  

实验串口返回情况

 

 

打开Arduino IDE——工具——串口绘图器,查看实验波形
实验串口绘图器返回情况

 

 

实验场景图

 

实验开源图形编程(Mind+、编玩边学)

 

 

 

实验串口返回情况

 

 

实验开源仿真编程(Linkboy V4.63)

 

 

 

实验串口返回情况

 

橙色、紫色和黑色线为X\Y\Z轴的加速度值,非常敏感,轻轻动下就会大幅变动,数值在-32000到32000之间

 

 

posted @ 2022-10-10 15:11  行者花雕  阅读(910)  评论(0编辑  收藏  举报