O que é MEMS? Acelerômetro, Giroscópio e Magnetômetro com Arduino
Neste tutorial, aprenderemos como o acelerômetro, giroscópio e magnetômetro MEMS funcionam e como usá-los com a placa Arduino. Também com o Processing IDE faremos algumas aplicações práticas usando os sensores. Você pode assistir ao vídeo a seguir ou ler o tutorial escrito abaixo.
O que é MEMS?
Os MEMS são sistemas ou dispositivos muito pequenos, compostos por microcomponentes que variam de 0,001 mm a 0,1 mm de tamanho. Esses componentes são feitos de silício, polímeros, metais e/ou cerâmicas, e geralmente são combinados com uma CPU (Microcontrolador) para completar o sistema.
Agora vamos explicar brevemente como funciona cada um desses sensores Micro-Eletro-Mecânicos (MEMS).
Acelerômetro MEMS
Ele mede a aceleração medindo a mudança na capacitância. Sua micro estrutura se parece com isso. Tem uma massa presa a uma mola que se limita a se mover ao longo de uma direção e placas externas fixas. Portanto, quando uma aceleração na direção específica for aplicada, a massa se moverá e a capacitância entre as placas e a massa mudará. Esta mudança na capacitância será medida, processada e corresponderá a um determinado valor de aceleração.
Giroscópio MEMS
O giroscópio mede a taxa angular usando o Efeito Coriolis. Quando uma massa está se movendo em uma determinada direção com uma determinada velocidade e quando uma taxa angular externa for aplicada, como mostra a seta verde, ocorrerá uma força, como mostra a seta vermelha azul, que causará um deslocamento perpendicular da massa. Assim semelhante ao acelerômetro, esse deslocamento causará mudança na capacitância que será medida, processada e corresponderá a uma determinada taxa angular.
A microestrutura do giroscópio se parece com isso. Uma massa que está em constante movimento, ou oscilando, e quando a taxa angular externa for aplicada uma parte flexível da massa se moveria e faria o deslocamento perpendicular.
Magnetômetro MEMS
Ele mede o campo magnético da terra usando o efeito Hall ou o efeito magneto-resistivo. Na verdade, quase 90% dos sensores do mercado usam o efeito Hall e aqui está como funciona.
Se tivermos uma placa condutora como a mostrada na foto e definirmos a corrente para fluir através dela, os elétrons fluirão direto de um para o outro lado da placa. Agora, se trouxermos algum campo magnético para perto da placa, perturbaríamos o fluxo reto e os elétrons desviariam para um lado da placa e os pólos positivos para o outro lado da placa. Isso significa que se colocarmos um medidor agora entre esses dois lados, obteremos alguma voltagem que depende da força do campo magnético e de sua direção.
Os outros 10% dos sensores do mercado utilizam o Efeito Magneto-resistivo. Esses sensores utilizam materiais sensíveis ao campo magnético, geralmente compostos de Ferro (Fe) e Níquel (Ne). Então, quando esses materiais são expostos ao campo magnético, eles mudam sua resistência.
Sensores Arduino e MEMs
Ok, agora vamos conectar esses sensores à placa Arduino e fazer algum uso deles. Como exemplo vou usar a placa breakout GY-80 que possui os seguintes sensores:Acelerômetro de 3 Eixos ADXL345, Giroscópio de 3 Eixos L3G4200D, Magnetômetro de 3 Eixos MC5883L e também um Barômetro e um Termômetro que não usaremos neste tutorial.
Você pode obter esses componentes em qualquer um dos sites abaixo:
- Acelerador de 3 eixos ADXL345………………………………………………………
- 2 em 1:giroscópio e acelerômetro de 6 eixos MPU6050 …………………
- 3 em 1:Giroscópio de aceleração de campo magnético de 9 eixos GY-80……… Amazon
- 3 em 1: GY-86 10DOF MS5611 HMC5883L MPU6050 Módulo……… Banggood / AliExpress
Esta placa usa o protocolo de comunicação I2C, o que significa que podemos usar todos os sensores com apenas dois fios. Portanto, para fazer a comunicação entre o Arduino e os sensores, precisamos conhecer seus endereços exclusivos de dispositivos e seus endereços de registros internos para obter os dados deles. Esses endereços podem ser encontrados nas fichas técnicas dos sensores:
- ADXL345 Acelerômetro Folha de dados
- L3G4200D Giroscópio Folha de dados
- MC5883L Magnetômetro Folha de dados
Para mais detalhes sobre como a comunicação I2C funciona, você pode conferir meu outro Tutorial do Protocolo de Comunicação I2C.
Código-fonte
Agora vamos ver os códigos para obter os dados dos sensores. Começaremos com o acelerômetro e haverá algumas explicações antes de cada código, bem como algumas descrições adicionais nos comentários do código .
Código do Acelerômetro do Arduino
Primeiro precisamos incluir a Biblioteca de Fios do Arduino e definir os endereços dos registradores do sensor. Na seção de configuração, precisamos iniciar a Wire Library e iniciar a comunicação serial, pois usaremos o monitor serial para mostrar os resultados. Também aqui precisamos ativar o sensor ou habilitar a medição enviando o byte apropriado para o registrador Power_CTL e aqui está como fazemos isso. Usando a função Wire.beginTransmission() selecionamos para qual sensor vamos falar, o Acelerômetro de 3 Eixos neste caso. Então usando a função Wire.write() informamos para qual registrador interno falaremos. Após isso enviaremos o byte apropriado para habilitar a medição. Usando a função Wire.endTransmission() terminaremos a transmissão e isso transmitirá os dados para os registradores.
Na seção de loop, precisamos ler os dados para cada eixo. Começaremos com o Eixo X. Então primeiro vamos selecionar para quais registradores falaremos, os dois registradores internos do Eixo X neste caso. Em seguida, usando a função Wire.requestFrom(), solicitaremos os dados transmitidos ou os dois bytes dos dois registradores. O Wire.available() A função retornará o número de bytes disponíveis para recuperação e se esse número corresponder aos bytes solicitados, no nosso caso 2 bytes, usando o comando Wire.read() vamos ler os bytes dos dois registradores do eixo X.
Os dados de saída dos registros são o complemento de dois, com X0 como o byte menos significativo e X1 como o byte mais significativo, portanto, precisamos converter esses bytes em valores flutuantes de -1 a +1, dependendo da direção do eixo X - relativo à aceleração da Terra ou à gravidade. Repetiremos este procedimento para os outros dois eixos e ao final imprimiremos esses valores no monitor serial.
#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)
Código do giroscópio do Arduino
Para obter os dados do giroscópio, teremos um código semelhante ao anterior. Então primeiro temos que definir os endereços dos registradores e algumas variáveis para os dados. Na seção de configuração temos que acordar e colocar o sensor no modo normal usando o CTRL_REG1 e também selecionar a sensibilidade do sensor. Para este exemplo, selecionarei o modo de sensibilidade de 2000dps.
Na seção de loop semelhante ao acelerômetro, leremos os dados para os eixos X, Y e Z. Em seguida, os dados brutos devem ser convertidos em valores de ângulo. Da folha de dados do sensor podemos ver que para o modo de sensibilidade de 2000dps corresponde uma unidade de 70 mdps/dígito. Isso significa que temos que multiplicar os dados brutos de saída por 0,07 para obter a taxa angular em graus por segundo. Então, se multiplicar a taxa angular pelo tempo, isso nos dará o valor do ângulo. Portanto, precisamos calcular o intervalo de tempo de cada seção do loop e podemos fazer isso usando a função millis() na parte superior e inferior da seção do loop, e armazenaremos seu valor nessa variável “dt”. Portanto, para cada loop executado, calcularemos o ângulo e o adicionaremos ao valor final do ângulo. Faremos o mesmo para os outros dois eixos e ao final imprimiremos os resultados no monitor serial.
#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)
Código do magnetômetro do Arduino
Novamente, usaremos uma técnica semelhante à anterior. Primeiro precisamos definir os endereços dos registradores e na seção de configuração colocar o sensor no modo de medição contínua. Na seção de loop, obteremos os dados brutos para cada eixo com o mesmo método dos sensores anteriores.
Em seguida, precisamos converter os dados brutos em valor de campo magnético ou unidades de Gauss. A partir da folha de dados do sensor podemos ver que o modo de sensibilidade padrão é 0,92mG/dígito. Isso significa que precisamos multiplicar os dados brutos por 0,00092 para obter o campo magnético da Terra em unidades de Gauss. Ao final imprimiremos os valores no monitor serial.
#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)
Aqui está uma aplicação legal do sensor, uma bússola digital MEMS, feita usando o Processing IDE. Você pode encontrar mais detalhes e o código-fonte deste exemplo no seguinte link:
Processo de manufatura
- O que é um magnetômetro?
- O que eu faço com os dados ?!
- Jogo Arduino Gyroscope com MPU-6050
- Diversão do giroscópio com anel NeoPixel
- Monitoramento de CO2 com Sensor K30
- Comunicação para surdos-cegos com 1Sheeld / Arduino
- Aceitar moeda de controle com Arduino
- Arduino com Bluetooth para controlar um LED!
- Sensor capacitivo de impressão digital com um Arduino ou ESP8266
- Brincando com Nextion Display