亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

什么是微机电系统?带有 Arduino 的加速度计、陀螺仪和磁力计

在本教程中,我们将了解 MEMS 加速度计、陀螺仪和磁力计的工作原理以及如何将它们与 Arduino 板一起使用。此外,借助 Processing IDE,我们将使用传感器进行一些实际应用。您可以观看以下视频或阅读下面的书面教程。

什么是MEMS?

MEMS 是非常小的系统或设备,由尺寸从 0.001 毫米到 0.1 毫米不等的微型元件组成。这些组件由硅、聚合物、金属和/或陶瓷制成,通常与 CPU(微控制器)结合以完成系统。

现在我们将简要解释这些微机电系统 (MEMS) 传感器的工作原理。

MEMS加速度计

它通过测量电容的变化来测量加速度。它的微观结构看起来像这样。它有一个附在弹簧上的质量块,该弹簧被限制为沿一个方向移动并固定外板。因此,当施加特定方向的加速度时,质量会移动,并且板和质量之间的电容会发生变化。这种电容变化会被测量、处理,并对应一个特定的加速度值。

MEMS陀螺仪

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

陀螺仪的微观结构看起来像这样。一个不断移动或振荡的质量块,当施加外部角速率时,质量块的柔性部分会移动并产生垂直位移。

MEMS磁力计

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

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


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

Arduino 和 MEMs 传感器


好的,现在让我们将这些传感器连接到 Arduino 板并使用它们。例如,我将使用具有以下传感器的 GY-80 分线板:ADXL345 3 轴加速度计、L3G4200D 3 轴陀螺仪、MC5883L 3 轴磁力计以及气压计和温度计,我们不会在本教程中使用。

您可以从以下任何网站获取这些组件:

  • ADXL345 三轴加速器………………………………………………………………
  • 二合一:MPU6050 6轴陀螺仪和加速度计……………………
  • 三合一:GY-80 9 轴磁场加速陀螺仪…………亚马逊
  • 三合一:GY-86 10DOF MS5611 HMC5883L MPU6050 模块…………Banggood  / 速卖通

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

  • ADXL345 加速度计数据表
  • L3G4200D 陀螺仪数据表
  • MC5883L 磁力计数据表

有关 I2C 通信如何工作的更多详细信息,您可以查看我的其他 I2C 通信协议教程。

源代码

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

Arduino 加速度计代码

首先,我们需要包含 Arduino Wire 库并定义传感器的寄存器地址。在设置部分,我们需要启动 Wire Library 并启动串行通信,因为我们将使用串行监视器来显示结果。同样在这里,我们需要激活传感器,或者通过向 Power_CTL 寄存器发送适当的字节来启用测量,这就是我们如何做到的。使用 Wire.beginTransmission() 函数,我们选择要与哪个传感器通话,在本例中为 3 轴加速度计。然后使用 Wire.write() 函数我们告诉我们将与哪个内部寄存器交谈。在此之后,我们将发送适当的字节以启用测量。使用 Wire.endTransmission() 函数,我们将结束传输并将数据传输到寄存器。

在循环部分,我们需要读取每个轴的数据。我们将从 X 轴开始。所以首先我们将选择我们要讨论的寄存器,在这种情况下是两个 X – Axis 内部寄存器。然后使用 Wire.requestFrom() 函数,我们将从两个寄存器请求传输的数据或两个字节。 Wire.available() 函数将返回可用于检索的字节数,如果该数字与我们请求的字节匹配,在我们的例子中为 2 个字节,使用 Wire.read() 函数我们将从X轴的两个寄存器中读取字节。

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

#include <Wire.h>

//--- Accelerometer Register Addresses
#define Power_Register 0x2D
#define X_Axis_Register_DATAX0 0x32 // Hexadecima address for the DATAX0 internal register.
#define X_Axis_Register_DATAX1 0x33 // Hexadecima address for the DATAX1 internal register.
#define Y_Axis_Register_DATAY0 0x34 
#define Y_Axis_Register_DATAY1 0x35
#define Z_Axis_Register_DATAZ0 0x36
#define Z_Axis_Register_DATAZ1 0x37

int ADXAddress = 0x53;  //Device address in which is also included the 8th bit for selecting the mode, read in this case.

int X0,X1,X_out;
int Y0,Y1,Y_out;
int Z1,Z0,Z_out;
float Xa,Ya,Za;

void setup() {
  Wire.begin(); // Initiate the Wire library    
  Serial.begin(9600);    
  delay(100);
  
  Wire.beginTransmission(ADXAddress);
  Wire.write(Power_Register); // Power_CTL Register
  // Enable measurement
  Wire.write(8); // Bit D3 High for measuring enable (0000 1000)
  Wire.endTransmission();
}

void loop() {
  // X-axis
  Wire.beginTransmission(ADXAddress); // Begin transmission to the Sensor 
  //Ask the particular registers for data
  Wire.write(X_Axis_Register_DATAX0);
  Wire.write(X_Axis_Register_DATAX1);  
  Wire.endTransmission(); // Ends the transmission and transmits the data from the two registers
  Wire.requestFrom(ADXAddress,2); // Request the transmitted two bytes from the two registers
  if(Wire.available()<=2) {  // 
    X0 = Wire.read(); // Reads the data from the register
    X1 = Wire.read();
    /* Converting the raw data of the X-Axis into X-Axis Acceleration
     - The output data is Two's complement 
     - X0 as the least significant byte
     - X1 as the most significant byte */ 
    X1=X1<<8;
    X_out =X0+X1;
    Xa=X_out/256.0; // Xa = output value from -1 to +1, Gravity acceleration acting on the X-Axis
  }
  // Y-Axis
  Wire.beginTransmission(ADXAddress); 
  Wire.write(Y_Axis_Register_DATAY0);
  Wire.write(Y_Axis_Register_DATAY1);  
  Wire.endTransmission(); 
  Wire.requestFrom(ADXAddress,2);
  if(Wire.available()<=2) { 
    Y0 = Wire.read();
    Y1 = Wire.read();
    Y1=Y1<<8;
    Y_out =Y0+Y1;
    Ya=Y_out/256.0;
  }
  // Z-Axis
  Wire.beginTransmission(ADXAddress); 
  Wire.write(Z_Axis_Register_DATAZ0);
  Wire.write(Z_Axis_Register_DATAZ1);  
  Wire.endTransmission(); 
  Wire.requestFrom(ADXAddress,2);
  if(Wire.available()<=2) { 
    Z0 = Wire.read();
    Z1 = Wire.read();
    Z1=Z1<<8;
    Z_out =Z0+Z1;
    Za=Z_out/256.0;
  }
  // Prints the data on the Serial Monitor
  Serial.print("Xa= ");
  Serial.print(Xa);
  Serial.print("   Ya= ");
  Serial.print(Ya);
  Serial.print("   Za= ");
  Serial.println(Za);
}
Code language: Arduino (arduino)

Arduino 陀螺仪代码

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

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

#include <Wire.h>

//--- Gyro Register Addresses
#define Gyro_gX0 0x28  
#define Gyro_gX1 0x29
#define Gyro_gY0 0x2A
#define Gyro_gY1 0x2B
#define Gyro_gZ0 0x2C  
#define Gyro_gZ1 0x2D

int Gyro = 0x69; //Device address in which is also included the 8th bit for selecting the mode, read in this case.

int gX0, gX1, gX_out;
int gY0, gY1, gY_out;
int gZ0, gZ1, gZ_out;
float Xg,Yg,Zg;
float angleX,angleY,angleZ,angleXc,angleYc,angleZc;


unsigned long start, finished, elapsed;
float dt=0.015;

void setup()
{
  Wire.begin();                
  Serial.begin(9600);    
  delay(100);
  
  Wire.beginTransmission(Gyro);
  Wire.write(0x20); // CTRL_REG1 - Power Mode
  Wire.write(15);   // Normal mode: 15d - 00001111b   
  Wire.endTransmission();
  
  Wire.beginTransmission(Gyro);
  Wire.write(0x23); // CTRL_REG4 - Sensitivity, Scale Selection
  Wire.write(48);   // 2000dps: 48d - 00110000b
  Wire.endTransmission();
}

void loop()
{
  start=millis();
  //---- X-Axis
  Wire.beginTransmission(Gyro); // transmit to device
  Wire.write(Gyro_gX0);
  Wire.endTransmission();
  Wire.requestFrom(Gyro,1); 
  if(Wire.available()<=1)   
  {
    gX0 = Wire.read();
  }
  Wire.beginTransmission(Gyro); // transmit to device
  Wire.write(Gyro_gX1);
  Wire.endTransmission();
  Wire.requestFrom(Gyro,1); 
  if(Wire.available()<=1)   
  {
    gX1 = Wire.read();
  }

  //---- Y-Axis
  Wire.beginTransmission(Gyro); // transmit to device
  Wire.write(Gyro_gY0);
  Wire.endTransmission();
  Wire.requestFrom(Gyro,1); 
  if(Wire.available()<=1)   
  {
    gY0 = Wire.read();
  }
  Wire.beginTransmission(Gyro); // transmit to device
  Wire.write(Gyro_gY1);
  Wire.endTransmission();
  Wire.requestFrom(Gyro,1); 
  if(Wire.available()<=1)   
  {
    gY1 = Wire.read();
  }
  
  //---- Z-Axis
  Wire.beginTransmission(Gyro); // transmit to device
  Wire.write(Gyro_gZ0);
  Wire.endTransmission();
  Wire.requestFrom(Gyro,1); 
  if(Wire.available()<=1)   
  {
    gZ0 = Wire.read();
  }
  Wire.beginTransmission(Gyro); // transmit to device
  Wire.write(Gyro_gZ1);
  Wire.endTransmission();
  Wire.requestFrom(Gyro,1); 
  if(Wire.available()<=1)   
  {
    gZ1 = Wire.read();
  }
  
  //---------- X - Axis
  
  // Raw Data
  gX1=gX1<<8;
  gX_out =gX0+gX1;
  
  // From the datasheet: 70 mdps/digit
  Xg=gX_out*0.07; // Angular rate
  // Angular_rate * dt = angle
  angleXc = Xg*dt;
  angleX = angleX + angleXc;

  //---------- Y - Axis
  gY1=gY1<<8;
  gY_out =gY0+gY1;
  Yg=gY_out*0.07;
  angleYc = Yg*dt;
  angleY = angleY + angleYc;
  
  //---------- Z - Axis
  gZ1=gZ1<<8;
  gZ_out =gZ0+gZ1;
  Zg=gZ_out*0.07;
  angleZc = Zg*dt;
  angleZ = angleZ + angleZc;

  
  // Prints the data on the Serial Monitor
  Serial.print("angleX= ");
  Serial.print(angleX);
  Serial.print("   angleY= ");
  Serial.print(angleY);
  Serial.print("   angleZ= ");
  Serial.println(angleZ);
  
  delay(10);
  // Calculating dt
  finished=millis();
  elapsed=finished-start;
  dt=elapsed/1000.0;
  start = elapsed = 0;
  
}Code language: Arduino (arduino)

Arduino 磁力计代码

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

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

#include <Wire.h> //I2C Arduino Library

#define Magnetometer_mX0 0x03  
#define Magnetometer_mX1 0x04  
#define Magnetometer_mZ0 0x05  
#define Magnetometer_mZ1 0x06  
#define Magnetometer_mY0 0x07  
#define Magnetometer_mY1 0x08  


int mX0, mX1, mX_out;
int mY0, mY1, mY_out;
int mZ0, mZ1, mZ_out;

float Xm,Ym,Zm;


#define Magnetometer 0x1E //I2C 7bit address of HMC5883

void setup(){
  //Initialize Serial and I2C communications
  Serial.begin(9600);
  Wire.begin();
  delay(100);
  
  Wire.beginTransmission(Magnetometer); 
  Wire.write(0x02); // Select mode register
  Wire.write(0x00); // Continuous measurement mode
  Wire.endTransmission();
}

void loop(){
 
  //---- X-Axis
  Wire.beginTransmission(Magnetometer); // transmit to device
  Wire.write(Magnetometer_mX1);
  Wire.endTransmission();
  Wire.requestFrom(Magnetometer,1); 
  if(Wire.available()<=1)   
  {
    mX0 = Wire.read();
  }
  Wire.beginTransmission(Magnetometer); // transmit to device
  Wire.write(Magnetometer_mX0);
  Wire.endTransmission();
  Wire.requestFrom(Magnetometer,1); 
  if(Wire.available()<=1)   
  {
    mX1 = Wire.read();
  }

  //---- Y-Axis
  Wire.beginTransmission(Magnetometer); // transmit to device
  Wire.write(Magnetometer_mY1);
  Wire.endTransmission();
  Wire.requestFrom(Magnetometer,1); 
  if(Wire.available()<=1)   
  {
    mY0 = Wire.read();
  }
  Wire.beginTransmission(Magnetometer); // transmit to device
  Wire.write(Magnetometer_mY0);
  Wire.endTransmission();
  Wire.requestFrom(Magnetometer,1); 
  if(Wire.available()<=1)   
  {
    mY1 = Wire.read();
  }
  
  //---- Z-Axis
  Wire.beginTransmission(Magnetometer); // transmit to device
  Wire.write(Magnetometer_mZ1);
  Wire.endTransmission();
  Wire.requestFrom(Magnetometer,1); 
  if(Wire.available()<=1)   
  {
    mZ0 = Wire.read();
  }
  Wire.beginTransmission(Magnetometer); // transmit to device
  Wire.write(Magnetometer_mZ0);
  Wire.endTransmission();
  Wire.requestFrom(Magnetometer,1); 
  if(Wire.available()<=1)   
  {
    mZ1 = Wire.read();
  }
  
  //---- X-Axis
  mX1=mX1<<8;
  mX_out =mX0+mX1; // Raw data
  // From the datasheet: 0.92 mG/digit
  Xm = mX_out*0.00092; // Gauss unit
  //* Earth magnetic field ranges from 0.25 to 0.65 Gauss, so these are the values that we need to get approximately.

  //---- Y-Axis
  mY1=mY1<<8;
  mY_out =mY0+mY1;
  Ym = mY_out*0.00092;

  //---- Z-Axis
  mZ1=mZ1<<8;
  mZ_out =mZ0+mZ1;
  Zm = mZ_out*0.00092;
 
  //Print out values of each axis
  Serial.print("x: ");
  Serial.print(Xm);
  Serial.print("  y: ");
  Serial.print(Ym);
  Serial.print("  z: ");
  Serial.println(Zm);
  
  delay(50);
}Code language: Arduino (arduino)

这是使用 Processing IDE 制作的传感器的一个很酷的应用程序,一个 MEMS 数字罗盘。您可以在以下链接中找到更多详细信息和此示例的源代码:


制造工艺

  1. 什么是磁力计?
  2. 如何处理数据?!
  3. Arduino Gyroscope Game with MPU-6050
  4. NeoPixel Ring 的陀螺仪乐趣
  5. 使用 K30 传感器监测二氧化碳
  6. 聋盲通信与 1Sheeld/Arduino
  7. 使用 Arduino 控制硬币接收器
  8. Arduino 带蓝牙控制 LED!
  9. 带有 Arduino 或 ESP8266 的电容式指纹传感器
  10. 玩 Nextion Display
  11. Nunchuk 控制机械臂(使用 Arduino)
  12. 使用 Arduino 测量太阳辐射