风筝
发表于: 2018-11-24 13:58:23 | 显示全部楼层

在本篇文章中,我们将学习MEMS加速度计、陀螺仪和磁力计的工作原理以及如何将它们与Arduino开发部一起使用。通过使用Processing IDE,我们将使用传感器进行一些实际应用。


MEMS概述

MEMS是非常小的系统或器件,由尺寸范围为0.001mm至0.1mm的微小元件组成。这些组件由硅、聚合物、金属和/或陶瓷制成,并且它们通常与CPU(微控制器)组合以完成系统。现在我们将简要解释每个微电子机械系统(MEMS)传感器的工作原理。


MEMS加速度计

它通过测量电容的变化来测量加速度。它的微观结构看起来像下图所示。它具有附着在弹簧上的质量块,弹簧被限制为沿一个方向移动并固定在外板。因此,当施加特定方向上的加速度时,质量块将移动,然后外板和质量块之间的电容将改变。这种电容变化将被测量,处理,并且它将对应于特定的加速度值。

MEMS-Accelerometer-How-It-Works.jpg


MEMS陀螺仪

陀螺仪使用科里奥利效应Coriolis Effect测量角速率。当质量以特定的速度在特定方向上移动时,并且施加外部角速率时,如绿色箭头所示,将产生力,如蓝色红色箭头所示,这将导致质量的垂直位移。与加速度计类似,这种位移将引起电容的变化,该电容将被测量和处理,这些变化对应于特定的角速率。

Gyroscope-How-It-Works.png


陀螺仪的微观结构类似于下图。质量块不断移动或振荡,当外部角速率施加时,质量的柔性部分将移动并产生垂直位移。

Gyroscope-Microstructure.jpg


MEMS磁力计

它通过使用霍尔效应或磁阻效应来测量地球磁场。实际上,市场上几乎90%的传感器都使用霍尔效应,以下是它的工作原理。

Hall-Effect-01.png


如果我们有一个像照片中所示的导电板,我们设置电流流过它,电子将直接从板的一侧流到另一侧。现在,如果我们在板附近带来一些磁场,我们就会扰乱直流,电子会偏转到板的一侧,而正极则偏向板的另一侧。这意味着如果我们现在在这两侧之间放置一个电表,我们将获得一些电压,该电压取决于磁场强度及其方向。

Magnetometer-How-It-Works-Hall-Effect-.png


市场上另外10%的传感器使用磁阻效应。这些传感器使用对磁场敏感的材料,通常由铁(Fe)和镍(Ne)组成。因此,当这些材料暴露在磁场中时,它们会改变它们的电阻。


Arduino示例

好了,现在让我们将这些传感器连接到Arduino开发板并使用它们。作为一个例子,我将使用GY-80扩展板,该电路板带有以下传感器:3轴加速度计ADXL345 、3轴陀螺仪L3G4200D、3轴磁力计MC5883L以及气压计和温度计。

本示例所需的组件如下所示:

●    3轴加速器ADXL345

●    2合1:MPU6050 6轴陀螺仪和加速度计.

●    3合1:GY-80 9轴磁场加速陀螺仪

●    3合1:GY-86 10DOF MS5611 HMC5883L MPU6050模块.


GY-80-Board-and-Arduino.png

该扩展板使用I2C通信协议,这意味着我们可以使用只有两根线的所有传感器。因此,为了在Arduino和传感器之间进行通信,我们需要知道它们唯一的设备地址和它们的内部寄存器地址,以便从中获取数据。这些地址可以从传感器的数据手册中找到:

●    ADXL345加速度计数据手册

●    L3G4200D陀螺仪数据手册

●    MC5883L磁力计数据手册


源代码

现在让我们看一下从传感器获取数据的代码。我们将从加速度计开始,每个代码前都会有一些解释,以及代码注释中的一些其他描述。


Arduino加速度计代码

首先,我们需要包含Arduino Wire Library并定义传感器的寄存器地址。在setu函数部分,我们需要初始化Wire Library并启动串行通信,因为我们将使用串行监视器来显示结果。此外,我们需要激活传感器,或者通过向Power_CTL寄存器发送适当的字节来启用测量,以下是具体过程。使用Wire.beginTransmission()函数,我们选择将要讨论的传感器,本例中是3轴加速度计。然后使用Wire.write()函数告诉我们将与哪个内部寄存器通信。在此之后,我们将发送适当的字节以启用测量。使用Wire.endTransmission()函数,我们将结束传输,并将数据传输到寄存器。


在loop函数中,我们需要读取每个轴的数据。我们将从X轴开始。首先,我们将选择我们将要通信的寄存器,也就是两个X轴内部寄存器。然后使用Wire.requestFrom()函数,我们将从两个寄存器请求传输的数据或两个字节。 Wire.available()函数将返回可用于检索的字节数,如果该数字与我们请求的字节匹配,本例中是2个字节,使用Wire.read()函数,我们将从两个X轴寄存器中读取字节。


寄存器的输出数据是二进制补码,X0作为最低有效字节,X1作为最高有效字节,因此我们需要将这些字节转换为从-1到+1的浮点值,具体取决于X轴的相对方向地球加速度或重力。我们将为另外两个轴重复此过程,最后我们将在串行监视器上打印这些值。

  1. #include <Wire.h>
  2. //--- Accelerometer Register Addresses
  3. #define Power_Register 0x2D
  4. #define X_Axis_Register_DATAX0 0x32 // Hexadecima address for the DATAX0 internal register.
  5. #define X_Axis_Register_DATAX1 0x33 // Hexadecima address for the DATAX1 internal register.
  6. #define Y_Axis_Register_DATAY0 0x34
  7. #define Y_Axis_Register_DATAY1 0x35
  8. #define Z_Axis_Register_DATAZ0 0x36
  9. #define Z_Axis_Register_DATAZ1 0x37
  10. int ADXAddress = 0x53;  //Device address in which is also included the 8th bit for selecting the mode, read in this case.
  11. int X0,X1,X_out;
  12. int Y0,Y1,Y_out;
  13. int Z1,Z0,Z_out;
  14. float Xa,Ya,Za;
  15. void setup() {
  16.   Wire.begin(); // Initiate the Wire library   
  17.   Serial.begin(9600);   
  18.   delay(100);
  19.   
  20.   Wire.beginTransmission(ADXAddress);
  21.   Wire.write(Power_Register); // Power_CTL Register
  22.   // Enable measurement
  23.   Wire.write(8); // Bit D3 High for measuring enable (0000 1000)
  24.   Wire.endTransmission();
  25. }
  26. void loop() {
  27.   // X-axis
  28.   Wire.beginTransmission(ADXAddress); // Begin transmission to the Sensor
  29.   //Ask the particular registers for data
  30.   Wire.write(X_Axis_Register_DATAX0);
  31.   Wire.write(X_Axis_Register_DATAX1);  
  32.   Wire.endTransmission(); // Ends the transmission and transmits the data from the two registers
  33.   Wire.requestFrom(ADXAddress,2); // Request the transmitted two bytes from the two registers
  34.   if(Wire.available()<=2) {  //
  35.     X0 = Wire.read(); // Reads the data from the register
  36.     X1 = Wire.read();
  37.     /* Converting the raw data of the X-Axis into X-Axis Acceleration
  38.      - The output data is Two's complement
  39.      - X0 as the least significant byte
  40.      - X1 as the most significant byte */
  41.     X1=X1<<8;
  42.     X_out =X0+X1;
  43.     Xa=X_out/256.0; // Xa = output value from -1 to +1, Gravity acceleration acting on the X-Axis
  44.   }
  45.   // Y-Axis
  46.   Wire.beginTransmission(ADXAddress);
  47.   Wire.write(Y_Axis_Register_DATAY0);
  48.   Wire.write(Y_Axis_Register_DATAY1);  
  49.   Wire.endTransmission();
  50.   Wire.requestFrom(ADXAddress,2);
  51.   if(Wire.available()<=2) {
  52.     Y0 = Wire.read();
  53.     Y1 = Wire.read();
  54.     Y1=Y1<<8;
  55.     Y_out =Y0+Y1;
  56.     Ya=Y_out/256.0;
  57.   }
  58.   // Z-Axis
  59.   Wire.beginTransmission(ADXAddress);
  60.   Wire.write(Z_Axis_Register_DATAZ0);
  61.   Wire.write(Z_Axis_Register_DATAZ1);  
  62.   Wire.endTransmission();
  63.   Wire.requestFrom(ADXAddress,2);
  64.   if(Wire.available()<=2) {
  65.     Z0 = Wire.read();
  66.     Z1 = Wire.read();
  67.     Z1=Z1<<8;
  68.     Z_out =Z0+Z1;
  69.     Za=Z_out/256.0;
  70.   }
  71.   // Prints the data on the Serial Monitor
  72.   Serial.print("Xa= ");
  73.   Serial.print(Xa);
  74.   Serial.print("   Ya= ");
  75.   Serial.print(Ya);
  76.   Serial.print("   Za= ");
  77.   Serial.println(Za);
  78. }
复制代码
跳转到指定楼层
风筝
发表于: 2018-11-24 14:05:35 | 显示全部楼层

Arduino陀螺仪代码

为了从陀螺仪获取数据,我们将使用与前一个类似的代码。首先,我们必须为数据定义寄存器地址和一些变量。在setup部分,我们必须使用CTRL_REG1唤醒并将传感器置于正常模式,并选择传感器的灵敏度。在本例中,我将选择2000dps灵敏度模式。


在类似于加速度计的loop部分中,我们将读取X、Y和Z轴的数据。然后必须将原始数据转换为角度值。从传感器的数据手册中我们可以看出,对于2000dps,灵敏度模式对应一个70 mdps /位的单位。这意味着我们必须将原始输出数据乘以0.07,以获得每秒度数的角速率。然后,如果将角速率乘以时间,它将给出角度值。所以我们需要计算每个loop部分的时间间隔,我们可以通过在循环部分的顶部和底部使用millis()函数来实现,我们将其值存储到这个“dt”变量中。因此,对于每个执行的循环,我们将计算角度并将其添加到最终角度值。我们将对另外两个轴执行相同的操作,最后我们将在串口监视器中打印结果。

  1. #include <Wire.h>
  2. //--- Gyro Register Addresses
  3. #define Gyro_gX0 0x28  
  4. #define Gyro_gX1 0x29
  5. #define Gyro_gY0 0x2A
  6. #define Gyro_gY1 0x2B
  7. #define Gyro_gZ0 0x2C  
  8. #define Gyro_gZ1 0x2D
  9. int Gyro = 0x69; //Device address in which is also included the 8th bit for selecting the mode, read in this case.
  10. int gX0, gX1, gX_out;
  11. int gY0, gY1, gY_out;
  12. int gZ0, gZ1, gZ_out;
  13. float Xg,Yg,Zg;
  14. float angleX,angleY,angleZ,angleXc,angleYc,angleZc;
  15. unsigned long start, finished, elapsed;
  16. float dt=0.015;
  17. void setup()
  18. {
  19.   Wire.begin();               
  20.   Serial.begin(9600);   
  21.   delay(100);
  22.   
  23.   Wire.beginTransmission(Gyro);
  24.   Wire.write(0x20); // CTRL_REG1 - Power Mode
  25.   Wire.write(15);   // Normal mode: 15d - 00001111b   
  26.   Wire.endTransmission();
  27.   
  28.   Wire.beginTransmission(Gyro);
  29.   Wire.write(0x23); // CTRL_REG4 - Sensitivity, Scale Selection
  30.   Wire.write(48);   // 2000dps: 48d - 00110000b
  31.   Wire.endTransmission();
  32. }
  33. void loop()
  34. {
  35.   start=millis();
  36.   //---- X-Axis
  37.   Wire.beginTransmission(Gyro); // transmit to device
  38.   Wire.write(Gyro_gX0);
  39.   Wire.endTransmission();
  40.   Wire.requestFrom(Gyro,1);
  41.   if(Wire.available()<=1)   
  42.   {
  43.     gX0 = Wire.read();
  44.   }
  45.   Wire.beginTransmission(Gyro); // transmit to device
  46.   Wire.write(Gyro_gX1);
  47.   Wire.endTransmission();
  48.   Wire.requestFrom(Gyro,1);
  49.   if(Wire.available()<=1)   
  50.   {
  51.     gX1 = Wire.read();
  52.   }
  53.   //---- Y-Axis
  54.   Wire.beginTransmission(Gyro); // transmit to device
  55.   Wire.write(Gyro_gY0);
  56.   Wire.endTransmission();
  57.   Wire.requestFrom(Gyro,1);
  58.   if(Wire.available()<=1)   
  59.   {
  60.     gY0 = Wire.read();
  61.   }
  62.   Wire.beginTransmission(Gyro); // transmit to device
  63.   Wire.write(Gyro_gY1);
  64.   Wire.endTransmission();
  65.   Wire.requestFrom(Gyro,1);
  66.   if(Wire.available()<=1)   
  67.   {
  68.     gY1 = Wire.read();
  69.   }
  70.   
  71.   //---- Z-Axis
  72.   Wire.beginTransmission(Gyro); // transmit to device
  73.   Wire.write(Gyro_gZ0);
  74.   Wire.endTransmission();
  75.   Wire.requestFrom(Gyro,1);
  76.   if(Wire.available()<=1)   
  77.   {
  78.     gZ0 = Wire.read();
  79.   }
  80.   Wire.beginTransmission(Gyro); // transmit to device
  81.   Wire.write(Gyro_gZ1);
  82.   Wire.endTransmission();
  83.   Wire.requestFrom(Gyro,1);
  84.   if(Wire.available()<=1)   
  85.   {
  86.     gZ1 = Wire.read();
  87.   }
  88.   
  89.   //---------- X - Axis
  90.   
  91.   // Raw Data
  92.   gX1=gX1<<8;
  93.   gX_out =gX0+gX1;
  94.   
  95.   // From the datasheet: 70 mdps/digit
  96.   Xg=gX_out*0.07; // Angular rate
  97.   // Angular_rate * dt = angle
  98.   angleXc = Xg*dt;
  99.   angleX = angleX + angleXc;
  100.   //---------- Y - Axis
  101.   gY1=gY1<<8;
  102.   gY_out =gY0+gY1;
  103.   Yg=gY_out*0.07;
  104.   angleYc = Yg*dt;
  105.   angleY = angleY + angleYc;
  106.   
  107.   //---------- Z - Axis
  108.   gZ1=gZ1<<8;
  109.   gZ_out =gZ0+gZ1;
  110.   Zg=gZ_out*0.07;
  111.   angleZc = Zg*dt;
  112.   angleZ = angleZ + angleZc;
  113.   
  114.   // Prints the data on the Serial Monitor
  115.   Serial.print("angleX= ");
  116.   Serial.print(angleX);
  117.   Serial.print("   angleY= ");
  118.   Serial.print(angleY);
  119.   Serial.print("   angleZ= ");
  120.   Serial.println(angleZ);
  121.   
  122.   delay(10);
  123.   // Calculating dt
  124.   finished=millis();
  125.   elapsed=finished-start;
  126.   dt=elapsed/1000.0;
  127.   start = elapsed = 0;
  128.   
  129. }
复制代码

Arduino磁力计代码

我们将再次使用与前一个类似的技术。 首先,我们需要定义寄存器地址,setup部分将传感器设置为连续测量模式。 在loop部分中,我们将使用与先前传感器相同的方法获取每个轴的原始数据。


然后我们需要将原始数据转换为磁场值或高斯单位。从传感器的数据表中我们可以看到默认的灵敏度模式是0.92mG / digit。 这意味着我们需要将原始数据乘以0.00092,以便以高斯单位获得地球磁场。 最后,我们将在串口监视器上打印该值。

  1. #include <Wire.h> //I2C Arduino Library
  2. #define Magnetometer_mX0 0x03  
  3. #define Magnetometer_mX1 0x04  
  4. #define Magnetometer_mZ0 0x05  
  5. #define Magnetometer_mZ1 0x06  
  6. #define Magnetometer_mY0 0x07  
  7. #define Magnetometer_mY1 0x08  
  8. int mX0, mX1, mX_out;
  9. int mY0, mY1, mY_out;
  10. int mZ0, mZ1, mZ_out;
  11. float Xm,Ym,Zm;
  12. #define Magnetometer 0x1E //I2C 7bit address of HMC5883
  13. void setup(){
  14.   //Initialize Serial and I2C communications
  15.   Serial.begin(9600);
  16.   Wire.begin();
  17.   delay(100);
  18.   
  19.   Wire.beginTransmission(Magnetometer);
  20.   Wire.write(0x02); // Select mode register
  21.   Wire.write(0x00); // Continuous measurement mode
  22.   Wire.endTransmission();
  23. }
  24. void loop(){

  25.   //---- X-Axis
  26.   Wire.beginTransmission(Magnetometer); // transmit to device
  27.   Wire.write(Magnetometer_mX1);
  28.   Wire.endTransmission();
  29.   Wire.requestFrom(Magnetometer,1);
  30.   if(Wire.available()<=1)   
  31.   {
  32.     mX0 = Wire.read();
  33.   }
  34.   Wire.beginTransmission(Magnetometer); // transmit to device
  35.   Wire.write(Magnetometer_mX0);
  36.   Wire.endTransmission();
  37.   Wire.requestFrom(Magnetometer,1);
  38.   if(Wire.available()<=1)   
  39.   {
  40.     mX1 = Wire.read();
  41.   }
  42.   //---- Y-Axis
  43.   Wire.beginTransmission(Magnetometer); // transmit to device
  44.   Wire.write(Magnetometer_mY1);
  45.   Wire.endTransmission();
  46.   Wire.requestFrom(Magnetometer,1);
  47.   if(Wire.available()<=1)   
  48.   {
  49.     mY0 = Wire.read();
  50.   }
  51.   Wire.beginTransmission(Magnetometer); // transmit to device
  52.   Wire.write(Magnetometer_mY0);
  53.   Wire.endTransmission();
  54.   Wire.requestFrom(Magnetometer,1);
  55.   if(Wire.available()<=1)   
  56.   {
  57.     mY1 = Wire.read();
  58.   }
  59.   
  60.   //---- Z-Axis
  61.   Wire.beginTransmission(Magnetometer); // transmit to device
  62.   Wire.write(Magnetometer_mZ1);
  63.   Wire.endTransmission();
  64.   Wire.requestFrom(Magnetometer,1);
  65.   if(Wire.available()<=1)   
  66.   {
  67.     mZ0 = Wire.read();
  68.   }
  69.   Wire.beginTransmission(Magnetometer); // transmit to device
  70.   Wire.write(Magnetometer_mZ0);
  71.   Wire.endTransmission();
  72.   Wire.requestFrom(Magnetometer,1);
  73.   if(Wire.available()<=1)   
  74.   {
  75.     mZ1 = Wire.read();
  76.   }
  77.   
  78.   //---- X-Axis
  79.   mX1=mX1<<8;
  80.   mX_out =mX0+mX1; // Raw data
  81.   // From the datasheet: 0.92 mG/digit
  82.   Xm = mX_out*0.00092; // Gauss unit
  83.   //* Earth magnetic field ranges from 0.25 to 0.65 Gauss, so these are the values that we need to get approximately.
  84.   //---- Y-Axis
  85.   mY1=mY1<<8;
  86.   mY_out =mY0+mY1;
  87.   Ym = mY_out*0.00092;
  88.   //---- Z-Axis
  89.   mZ1=mZ1<<8;
  90.   mZ_out =mZ0+mZ1;
  91.   Zm = mZ_out*0.00092;

  92.   //Print out values of each axis
  93.   Serial.print("x: ");
  94.   Serial.print(Xm);
  95.   Serial.print("  y: ");
  96.   Serial.print(Ym);
  97.   Serial.print("  z: ");
  98.   Serial.println(Zm);
  99.   
  100.   delay(50);
  101. }
复制代码

以上就是本篇文章的全部内容。如果遇到任何问题,请随时在本帖下面进行回复。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题 705 | 回复: 1492



手机版|

GMT+8, 2024-11-23 02:48 , Processed in 0.057016 second(s), 6 queries , Gzip On, MemCache On. Powered by Discuz! X3.5

YiBoard一板网 © 2015-2022 地址:河北省石家庄市长安区高营大街 ( 冀ICP备18020117号 )

快速回复 返回顶部 返回列表