MEMS加速度计陀螺磁力计&Arduino

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

概述


MEMS是非常小的系统或设备,由0.001mm至0.1mm的微量分量组成。这些部件由硅,聚合物,金属和/或陶瓷制成,并且通常与CPU(微控制器)组合以完成系统。现在,我们将简要解释这些微机电系统(MEMS)传感器的各种工作。

MEMS加速度计


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

MEMS-Accelerometer-Wher-Works

MEMS陀螺仪


陀螺仪使用科里奥利效应测量角度率。当质量在具有特定速度的特定方向上移动并且当外部角速率将被施加为与绿色箭头的显示时,将发生与蓝色红色箭头的示出,这将导致质量垂直位移。如此类似于加速度计,该位移将导致电容的变化,该电容将被测量,处理,并且它将对应于特定的角速率。

陀螺仪 - 如何 - 工作

陀螺仪的微结构看起来像这样。一种恒定移动或振荡的质量,并且当外部角速率将施加肌肉的柔性部分将移动并制造垂直的位移。

陀螺微观结构

MEMS磁力计


它通过使用霍尔效应或磁电阻效应来测量地球磁场。实际上,市场上的近90%的传感器使用了霍尔效应,这是它的工作原理。betway

霍尔效应-01

如果我们在照片中示出了类似的导电板,并且我们将电流设置为流过它,则电子将直接从板的另一侧流动。现在,如果我们在板附近带来一些磁场,我们会扰乱直流,并且电子将使板的一侧偏转到板的另一侧。这意味着如果我们现在在这两面之间放置仪表,我们将获得一些电压,这取决于磁场强度及其方向。

磁力计磁仪 - 工作 - 工作室效果 -
其他10%的传感器在市场上使用磁阻效应。这些传感器使用对磁场敏感的材料,通常由铁(Fe)和镍(NE)组成。因此,当这些材料暴露于磁场时,它们会改变它们的阻力。

Arduino和MEMS传感器


好的,现在让我们将这些传感器连接到Arduino Board并进行一些使用它们。作为一个例子,我将使用具有以下传感器的GY-80分支板:ADXL345 3轴加速度计,L3G4200D 3轴陀螺仪,MC5883L 3轴磁力计以及晴雨表和温度计,我们不会在本教程中使用。

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

必威外围提钱披露:这些是联盟链接。作为亚马逊助理,我从合格购买中获得。

GY-80-LOAD-AND-ARDUINO

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

有关详细信息,I2C通信如何检查我的其他方式I2C通信协议教程

源代码


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

Arduino加速度计代码

首先,我们需要包括Arduino Wire库并定义传感器的寄存器地址。在设置部分中,我们需要启动线路库并开始串行通信,因为我们将使用串行监视器来显示结果。此外,我们还需要激活传感器,或通过向Power_ctl寄存器发送适当的字节来启用测量,这就是我们的方式。使用Wire.BegintRansmission()函数,我们选择我们将在这种情况下进行谈话的传感器,在这种情况下为3轴加速度计。然后使用Wire.Write()函数,我们告诉我们将谈论哪个内部寄存器。在此之后,我们将发送适当的字节来实现测量。使用Wire.endTransmission()函数我们将结束传输,并将数据传输到寄存器。

在循环部分中,我们需要读取每个轴的数据。我们将从X轴开始。所以首先,我们将选择我们将交谈的寄存器,两个X轴内部寄存器在这种情况下。然后使用Wire.Requestfrom()函数,我们将从两个寄存器中请求传输的数据或两个字节。这Wire.Available()函数将返回可用于检索的字节数,如果该数字与我们所请求的字节相匹配,请在我们的情况下使用2个字节,使用wire.read()功能我们将从X轴的两个寄存器中读取字节。

这output data from the registers is two’s complement, with X0 as the least significant byte and X1 as the most significant byte so we need to convert these bytes into float values from -1 to +1 depending on the direction of the X – Axis relative to the Earth acceleration or the gravity. We will repeat this procedure for the two other axis and at the end we will print these values on the serial monitor.

#include  // ---加速度计寄存器地址#define power_register 0x2d #define x_axis_register_datax0 0x32 // datax0内部寄存器的hexadecima地址。#define x_axis_register_datax1 0x33 // Datax1内部寄存器的HexadeCima地址。#define y_axis_register_datay0 0x34 #define y_axis_register_datay1 0x35 #define z_axis_register_dataz0 0x36 #dataz0 0x36 #define z_axis_register_dataz1 0x37 int adxaddress = 0x53;//设备地址,其中还包括用于选择模式的第8位,在这种情况下读取。int x0,x1,x_out;int y0,y1,y_out;int z1,z0,z_out;浮子Xa,ya,za;void setup(){wire.begin();//发起线条库序列号.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); }

Arduino陀螺仪代码

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

在类似于加速度计的循环部分中,我们将读取x,y和z轴的数据。然后,必须将原始数据转换为角度值。从传感器的数据表中,我们可以看到,对于2000DPS灵敏度模式,对应于70 MDPS /数字单元。这意味着我们必须将原始输出数据乘以0.07,以便在每秒度数的角度下获得角度。然后,如果乘以角速率,它将给我们一个角度值。因此,我们需要计算每个循环部分的时间间隔,我们可以通过使用循环部分的顶部和底部的毫米()函数来执行此操作,我们将其值存储在此“dt”变量中。因此,对于每个执行的循环,我们将计算该角度并将其添加到最终角度值。我们将为另外两个轴线为此做同样的事情,最后我们将在串行监视器中打印结果。

#include  // ---陀螺仪寄存器地址#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;//设备地址,其中还包括用于选择模式的第8位,在这种情况下读取。int gx0,gx1,gx_out;int gy0,gy1,gy_out;int gz0,gz1,gz_out;Float XG,YG,ZG;浮动角度,角度尖锐,角度Z,Anglexc,Anstyc,Anstzc;毫无符号长开始,完成,经过;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; }

Arduino磁力计代码

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

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

#include  // i2c arduino library #define magnetometer_mx0 0x03 #define magnetometer_mx1 0x04 #define magnetometer_mz0 0x05 #define magnetomet_mz1 0x06 #define magnetomet_my0 0x07 #define magnetomet_my1 0x08 int mx0,mx1,mx_out;int my0,my1,my_out;int mz0,mz1,mz_out;Float XM,YM,ZM;#define磁力计0x1e // i2c 7bit hmc5883 void setup(){//初始化串口和i2c通信串行.begin(9600);Wire.begin();延迟(100);Wire.Begintroansmission(磁力计);Wire.write(0x02);//选择模式寄存器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); }

以下是使用处理IDE制造的MEMS数字罗盘的传感器的酷炫应用。您可以在以下链接上找到更多详细信息和此示例的源代码:

arduino-compass.

33回应

  1. 汉斯

    你好,
    解释非常好,工作良好。
    在移动MEMS加速度计陀螺仪磁仪时,我是否有一个关于处理草图的处理草图的链接?
    (@ 0:20在视频中,左图像,我找到了指南针的页面,但不是左侧的示例)
    汉斯

    回复
  2. dmitrii.

    嗨Dejan,
    非常感谢您的工作。这对我帮助很大。
    我使用GY 273突破,只有磁力计MC5883L。并有2个问题/问题才能理解:
    1)即使我在所有方向上旋转传感器,关于Z轴的测量值约为零。原始数据较少。因此,当我将其乘以0.00092串行端口时,请显示ME值0.00或-0.00。
    但关于x和y轴的测量似乎可以。当这两个轴铺设在水平面上时,我计算标题角度时,它的值看起来非常可靠。如果我旋转90度,它会显示大约90个退化等。
    你有什么想法为什么我的传感器不想要测量关于z轴的数据?
    2)在第2页的磁力计的数据表中有信息:
    8位读取地址0x3D
    8位写入地址0x3C
    我试过它,但它不起作用。I2C扫描仪显示地址0x1e,所有示例都使用此地址。
    难道我不对关于设备地址的数据表编写的内容吗?
    非常感谢!

    回复
    • Dejan Nedelkovski.

      嗯,0x1e是传感器地址,然后在第11页的每个轴上有单独的内部寄存器地址。你用它们吗?
      你说这是一个奇怪的行为,因为x和y工作和z没有。最后有一个机会z轴根本不起作用(制造错误)。例如,我使用的传感器对于3轴具有比特不同的值(它们应该是相同的,我认为它是制造错误)。

      回复
      • dmitrii.

        感谢您的回复!
        我认为这是它的制造错误和有序的新磁力计。
        至于0x1E,我发现了什么意思0x1c和0x1d在这种情况下,这是我的注意力:
        “这些指针位置从主母部发送到此
        从设备并成功7位地址(0x1e)加1位读/写标识符,即读取和0x3c for write ...“

  3. 穆拉特

    你好 ,
    你能解释一下,为什么我将最重要的位移动到左侧8位?你能用Numbers.Can举例说明你解释MSB更详细吗?

    回复
  4. Zoltan.

    嗨Dejan!
    非常感谢它真的有帮助。我正在研究一个项目,我使用陀螺仪和加速度计的组合。在您的视频中,有一个带蓝色框的很酷的处理示例。你能告诉我它的源代码吗?这会帮助我很多!
    非常感谢你!

    回复
  5. 嗨,我看到你是IMU或运动传感器领域的专家。如果可能的话,您可以向我发送可以测量体育体系的IMU的框图。框图应包括滤波器(如果需要),微控制器和通信等连接和组件的详细信息。帮助我如何根据运动的采样率选择传感器。我是这个主题的新手,想知道它看起来非常有趣。
    谢谢你。

    回复
      • 嗨Dejan,谢谢你的快速回复。您可以为我提供基本想法,以如何为高性能运动设计原型IMU。据我所知,我们需要IMU传感器(加速度计,陀螺仪,磁力计或GPS)微控制器和通信系统。只是不知道如何连接它以及如何定义采样率(可能是我们需要一些公式来查找采样率),以便选择传感器。只是通过你的主席先生引导我。谢谢

    • Dejan Nedelkovski.

      //计算DT.
      完成= millis();
      经过=完成 - 开始;
      dt =经过/ 1000.0;
      开始=经过= 0;

      //

      DT = 0.015只是起始值,可以但除了0之外,还可以计算DT变量,但是计算每个迭代,它的值为0.015(需要执行每个迭代的时间)

      回复
  6. 缺口

    你好,
    你能解释如何将陀螺和加权组合起来以获得准确的价值观?
    我太愚蠢了,无法弄明白; _;

    回复
  7. ogar.

    嗨,谢谢你对我的教程对我来说非常有用。请帮助我使用MATLAB代码来读取这些加速度计值。您给出了很好的示例,我能够在串行监视器上查看结果。我需要将数据导出到MATLAB。谢谢

    回复
  8. 亚历山大·佩雷马丁

    你好德州,

    我的名字是Alexandre,我正在为我的航空飞行工程毕业项目开发一个Quadcopter。我刚刚看到了你的教程,并希望在陀螺仪模块L3G4200D随时询问您是否越来越多。

    一世am asking it because I have the same module (GY 80) , with the same gyro and accelerometer here, I have already implemented the complementary filter to get the correct attitude measurements, even thought I’m still having problems with the gyro drift over time, I don’t know if I still have to implement another kind of adjustment or if it could be a hardware problem.

    如果你可以用这个陀螺模块与我分享你的经验,我会非常高兴,也许如果你可以和我谈谈一段时间。

    这是我的skpe号码,供您参考:ALE_Martins88

    最好的祝福,

    亚历山大

    回复
    • Dejan Nedelkovski.

      你好呀,
      嗯,这不是硬件问题,陀螺仪趋于漂移。所以是的,您必须找到与加速度计或/和磁力计结合它的方法,以纠正漂移。

      回复
    • 萨尼亚

      嗨,我正在研究MPU6050模块,以通过双重集成来检测Z轴上的振动并从加速度计数据中找到位置。您告诉您已实现互补过滤器以获得准确的值。所以请您协助我或为我提供源代码。我会非常感谢你。

      回复
  9. Goos.

    你好,
    感谢您对模块和代码的清晰描述。
    我完全复制了加速器代码的代码,但它给了我x和y之间的值0到-2,而不是1和-1。z几乎没有。
    我还打印了x0和x1。X0介于0到2xx之间,X1为-512或-256。
    对于Y是相同的。这是正确的还是我的gy-80破碎,因为z不像你的演示一样工作。
    提前致谢,关于GOOS
    一世

    回复
    • Dejan Nedelkovski.

      你好呀,
      尝试在单独的“if(wire.available()<= 1)”中读取x0和x1值,如在陀螺仪的代码中。陀螺仪和磁力计你得到正确的值吗?

      回复
  10. 亚马尔

    你好德詹!
    你真的帮了我很多。但是有一个问题我做不到
    您使用ITG3200为Gyro.i的编写了0.07。我在哪里可以找到ITG3200的0.07值。

    回复
  11. 肖恩

    我非常感谢您的帮助,了解这个模块如何工作,但我认为当您靠近北方时,您的低通滤波器存在问题。让我们说它在一个大约2度的过程中,下一个读数是355度,低通滤波器将占据最新方向的85%,并增加最新标题的15%(355 * 15/200)约53并声明平滑标题现在为54.7。这与真正的标题非常不同,可能导致一些严重的导航问题。

    回复
  12. 安德烈

    很棒的文章谢谢你分享这个!我打算做一个项目来捕捉手机位置并读出数据。问题是我需要在运动中需要,所以我以为我在手上固定了传感器。在这种情况下,我需要一个带电池的Arduino,因为我将在不同的位置和高度上移动。您是否认为这可能使用您在本文中介绍的这样的设备?最好!

    回复
  13. 你好!
    找到您的视频,因为我正在研究如何实施加速度计和陀螺仪,以获得详细的阅读并用它制作AWD控制器。
    但是,有一个问题困扰着我:
    如果将该模块设置为扁平(例如WaterLevel)表面,请关闭传感器,将传感器移动到A,例如45°表面,然后重新打开。
    如果我理解正确的“工作原理”解释,则使用过的传感器应该能够识别此更改(由于内部结构始终“移动”)并显示重新为其供电后显示正确的值。
    我的假设是否正确?
    如上所述,提出的原因,我将在汽车中实施该传感器,因为它需要“智能”,通常您不能总是将其停在完全平坦的表面上,因此如果传感器将被使用为了控制某些东西,它始终需要知道汽车的绝对位置,并且每次电源打开时,必须不会将自身重置为“0”。

    我希望这个问题是以某种方式可以理解的。

    谢谢!

    布尔

    回复
    • Dejan Nedelkovski.

      嘿,好的,加速度计感应引力,所以随时你为设备供电,它会给你正确的结果。
      在另一边,陀螺仪感测角度运动/速率,这在内部发生并仅取决于传感器本身。这意味着在位于45°时,电源不会给出正确的结果。但他们仍然可以合并并为您提供正确编程的正确结果。

      回复

发表评论

您的电子邮件地址不会被公开。

受到推崇的

2019年初学者和爱好者的最佳进入级示波器

为初学者和爱好者最好的示波器

受到推崇的

2019年初学者的8个最佳Arduino Starter Kits

初学者的8个最佳Arduino Starter Kits

受到推崇的

用于初学者和爱好者的最佳3D打印机 -  3D打印

初学者和爱好者的最佳3D打印机