Bien, ahora conectemos estos sensores a la placa Arduino y hagamos algún uso de ellos. Como ejemplo, usaré la placa de conexión GY-80 que tiene los siguientes sensores:acelerómetro de 3 ejes ADXL345, giroscopio de 3 ejes L3G4200D, magnetómetro de 3 ejes MC5883L y también un barómetro y un termómetro que no usaremos en este tutorial.
Esta placa usa el protocolo de comunicación I2C, lo que significa que podemos usar todos los sensores con solo dos cables. Entonces, para establecer la comunicación entre Arduino y los sensores, necesitamos conocer las direcciones únicas de sus dispositivos y sus direcciones de registro interno para obtener los datos de ellos. Estas direcciones se pueden encontrar en las hojas de datos de los sensores:
Hoja de datos del acelerómetro ADXL345
L3G4200D Giroscopio Hoja de datos
Hoja de datos del magnetómetro MC5883L
Para obtener más detalles sobre cómo funciona la comunicación I2C, puede consultar mi otro tutorial sobre el protocolo de comunicación I2C.
Código fuente
Ahora veamos los códigos para obtener los datos de los sensores. Comenzaremos con el acelerómetro y habrá alguna explicación antes de cada código, así como alguna descripción adicional en los comentarios del código.
Código del acelerómetro de Arduino
Primero debemos incluir la biblioteca de cables de Arduino y definir las direcciones de registro del sensor. En la sección de configuración, debemos iniciar la biblioteca de cables e iniciar la comunicación en serie, ya que usaremos el monitor en serie para mostrar los resultados. También aquí necesitamos activar el sensor o habilitar la medición enviando el byte apropiado al registro Power_CTL y así es como lo hacemos. Usando la función Wire.beginTransmission() seleccionamos con qué sensor hablaremos, el Acelerómetro de 3 ejes en este caso. Luego, usando la función Wire.write(), le decimos a qué registro interno hablaremos. Luego de esto enviaremos el byte apropiado para habilitar la medición. Usando la función Wire.endTransmission() terminaremos la transmisión y eso transmitirá los datos a los registros.
En la sección de bucle necesitamos leer los datos de cada eje. Comenzaremos con el eje X. Entonces, primero seleccionaremos a qué registros hablaremos, los dos registros internos del eje X en este caso. Luego usando la función Wire.requestFrom() solicitaremos los datos transmitidos o los dos bytes de los dos registros. El Cable.disponible() la función devolverá el número de bytes disponibles para la recuperación y si ese número coincide con nuestros bytes solicitados, en nuestro caso 2 bytes, usando Wire.read() función vamos a leer los bytes de los dos registros del eje X.
Los datos de salida de los registros son complemento a dos, con X0 como el byte menos significativo y X1 como el byte más significativo, por lo que debemos convertir estos bytes en valores flotantes de -1 a +1 según la dirección del eje X relativo. a la aceleración de la Tierra oa la gravedad. Repetiremos este procedimiento para los otros dos ejes y al final imprimiremos estos valores en el monitor serie.
#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 de giroscopio de Arduino
Para obtener los datos del giroscopio tendremos un código similar al anterior. Entonces, primero tenemos que definir las direcciones de registro y algunas variables para los datos. En la sección de configuración tenemos que despertar y poner el sensor en modo normal usando el CTRL_REG1 y también seleccionar la sensibilidad del sensor. Para este ejemplo, seleccionaré el modo de sensibilidad de 2000 dps.
En la sección de bucle similar al acelerómetro, leeremos los datos para los ejes X, Y y Z. Luego, los datos sin procesar deben convertirse en valores de ángulo. De la hoja de datos del sensor podemos ver que para el modo de sensibilidad de 2000 dps corresponde una unidad de 70 mdps/dígito. Esto significa que tenemos que multiplicar los datos de salida sin procesar por 0,07 para obtener la velocidad angular en grados por segundo. Luego, si multiplicamos la velocidad angular por el tiempo, nos dará el valor del ángulo. Entonces, necesitamos calcular el intervalo de tiempo de cada sección del ciclo y podemos hacerlo usando la función millis() en la parte superior e inferior de la sección del ciclo, y almacenaremos su valor en esta variable "dt". Entonces, para cada bucle ejecutado, calcularemos el ángulo y lo agregaremos al valor del ángulo final. Haremos lo mismo con los otros dos ejes y al final imprimiremos los resultados en el monitor serie.
#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 de Magnetómetro Arduino
Nuevamente utilizaremos una técnica similar a la anterior. Primero necesitamos definir las direcciones de los registros y en la sección de configuración configurar el sensor en modo de medición continua. En la sección de bucle obtendremos los datos sin procesar para cada eje con el mismo método que para los sensores anteriores.
Luego necesitamos convertir los datos sin procesar en valor de campo magnético o unidades de Gauss. En la hoja de datos del sensor podemos ver que el modo de sensibilidad predeterminado es 0,92 mG/dígito. Eso significa que necesitamos multiplicar los datos sin procesar por 0,00092 para obtener el campo magnético terrestre en unidades Gauss. Al finalizar imprimiremos los valores en el 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)
Aquí hay una aplicación atractiva del sensor, una brújula digital MEMS, creada con Processing IDE. Puede encontrar más detalles y el código fuente de este ejemplo en el siguiente enlace: