MEMSとは何ですか? Arduinoを搭載した加速度計、ジャイロスコープ、磁力計
このチュートリアルでは、MEMS加速度計、ジャイロスコープ、磁力計がどのように機能し、Arduinoボードでそれらを使用する方法を学びます。また、Processing IDEを使用して、センサーを使用していくつかの実用的なアプリケーションを作成します。次のビデオを見るか、以下のチュートリアルを読むことができます。
MEMSは非常に小さなシステムまたはデバイスであり、サイズが0.001mmから0.1mmの範囲のマイクロコンポーネントで構成されています。これらのコンポーネントは、シリコン、ポリマー、金属、セラミックでできており、通常、システムを完成させるためにCPU(マイクロコントローラー)と組み合わされます。
次に、これらの微小電気機械システム(MEMS)センサーのそれぞれがどのように機能するかを簡単に説明します。
静電容量の変化を測定することで加速度を測定します。その微細構造はこんな感じ。それは一方向に沿って動くように制限されたばねに取り付けられた質量と固定された外板を持っています。したがって、特定の方向の加速度が適用されると、質量が移動し、プレートと質量の間の静電容量が変化します。この静電容量の変化は測定、処理され、特定の加速度値に対応します。
ジャイロスコープは、コリオリ効果を使用して角速度を測定します。質量が特定の速度で特定の方向に移動しているとき、および緑の矢印で示されているように外部角速度が適用されると、青赤の矢印で示されているように力が発生し、質量の垂直変位が発生します。加速度計と同様に、この変位により静電容量が変化し、測定、処理され、特定の角速度に対応します。
ジャイロスコープの微細構造はこんな感じ。絶えず移動または振動している質量で、外部角速度が適用されると、質量の柔軟な部分が移動して垂直に変位します。
ホール効果または磁気抵抗効果を使用して地磁気を測定します。実際、市場に出回っているセンサーのほぼ90%がホール効果を使用しており、その仕組みは次のとおりです。
写真のような導電性プレートがあり、それに電流を流すように設定すると、電子はプレートの一方の側からもう一方の側にまっすぐ流れます。ここで、プレートの近くに磁場を持ってくると、まっすぐな流れが妨げられ、電子がプレートの片側に偏向し、正極がプレートの反対側に偏向します。つまり、これらの2つの側面の間にメーターを置くと、磁場の強さとその方向に依存する電圧が得られます。
では、これらのセンサーをArduinoボードに接続して、それらを利用してみましょう。例として、次のセンサーを備えたGY-80ブレークアウトボードを使用します:ADXL345 3軸加速度計、L3G4200D 3軸ジャイロスコープ、MC5883L 3軸磁力計、およびこのチュートリアルでは使用しない気圧計と温度計。
これらのコンポーネントは、以下のいずれかのサイトから入手できます。
このボードはI2C通信プロトコルを使用しているため、2本のワイヤーですべてのセンサーを使用できます。したがって、Arduinoとセンサー間の通信を行うには、それらの固有のデバイスアドレスと、それらからデータを取得するための内部レジスタアドレスを知る必要があります。これらのアドレスは、センサーのデータシートから見つけることができます:
I2C通信の仕組みの詳細については、他のI2C通信プロトコルチュートリアルを確認してください。
次に、センサーからデータを取得するためのコードを見てみましょう。加速度計から始めて、各コードの前にいくつかの説明と、コードのコメントにいくつかの追加の説明があります。
まず、Arduinoワイヤーライブラリを含め、センサーのレジスタアドレスを定義する必要があります。セットアップセクションでは、結果を表示するためにシリアルモニターを使用するため、ワイヤーライブラリを開始してシリアル通信を開始する必要があります。また、ここでセンサーをアクティブにするか、適切なバイトをPower_CTLレジスタに送信して測定を有効にする必要があります。その方法は次のとおりです。 Wire.beginTransmission()関数を使用して、話すセンサー(この場合は3軸加速度計)を選択します。次に、Wire.write()関数を使用して、どの内部レジスタと通信するかを指示します。この後、測定を有効にするための適切なバイトを送信します。 Wire.endTransmission()関数を使用して、送信を終了し、データをレジスタに送信します。
ループセクションでは、各軸のデータを読み取る必要があります。 X軸から始めます。したがって、最初に、どのレジスタと通信するかを選択します。この場合は、2つのX軸内部レジスタです。次に、Wire.requestFrom()関数を使用して、送信されたデータまたは2つのレジスタからの2バイトを要求します。 Wire.available() 関数は、取得可能なバイト数を返し、その数が要求されたバイト(この場合は2バイト)と一致する場合は、 Wire.read()を使用します。 関数は、X軸の2つのレジスタからバイトを読み取ります。
レジスタからの出力データは2の補数であり、X0が最下位バイト、X1が最上位バイトであるため、これらのバイトをX軸の相対方向に応じて-1から+1までの浮動小数点値に変換する必要があります。地球の加速度または重力に。他の2つの軸についてもこの手順を繰り返し、最後にこれらの値をシリアルモニターに出力します。
ジャイロスコープからデータを取得するために、前のコードと同様のコードがあります。したがって、最初に、データのレジスタアドレスといくつかの変数を定義する必要があります。セットアップセクションでは、CTRL_REG1を使用してウェイクアップし、センサーを通常モードにする必要があります。また、センサーの感度を選択する必要があります。この例では、2000dpsの感度モードを選択します。
加速度計と同様のループセクションで、X、Y、Z軸のデータを読み取ります。次に、生データを角度値に変換する必要があります。センサーのデータシートから、2000dpsの感度モードは70mdps/ディジット単位に対応することがわかります。これは、毎秒の角速度を取得するために、生の出力データに0.07を掛ける必要があることを意味します。次に、角速度に時間を掛けると、角度の値が得られます。したがって、各ループセクションの時間間隔を計算する必要があります。これは、ループセクションの上部と下部にあるmillis()関数を使用して計算でき、その値をこの「dt」変数に格納します。したがって、実行されたループごとに、角度を計算し、それを最終的な角度値に追加します。他の2つの軸についても同じことを行い、最後に結果をシリアルモニターに出力します。
ここでも、前の手法と同様の手法を使用します。まず、レジスタアドレスを定義する必要があります。セットアップセクションでは、センサーを連続測定モードに設定します。ループセクションでは、前のセンサーと同じ方法で各軸の生データを取得します。
次に、生データを磁場値またはガウス単位に変換する必要があります。センサーのデータシートから、デフォルトの感度モードは0.92mG/桁であることがわかります。つまり、ガウス単位で地磁気を取得するには、生データに0.00092を掛ける必要があります。最後に、シリアルモニターに値を出力します。
これは、ProcessingIDEを使用して作成されたセンサーの見栄えの良いアプリケーションであるMEMSデジタルコンパスです。この例の詳細とソースコードは、次のリンクにあります:MEMS加速度計
MEMSジャイロスコープ
MEMS磁力計
市場に出回っている他の10%のセンサーは、磁気抵抗効果を使用しています。これらのセンサーは、磁場に敏感な材料を使用しており、通常は鉄(Fe)とニッケル(Ne)で構成されています。したがって、これらの材料が磁場にさらされると、抵抗が変化します。ArduinoおよびMEMsセンサー
Arduino加速度計コード
#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ジャイロスコープコード
#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磁力計コード
#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)
製造プロセス