domingo, 22 de marzo de 2015

Desarrollo de algunas aplicaciones del ACELERÓMETRO ADXL345 en la tarjeta de Desarrollo ChipKit ®

Desarrollo de algunas aplicaciones del ACELERÓMETRO ADXL345 en la tarjeta de Desarrollo ChipKit ® 
(PARTE 1)

Hola, en esta ocasión te presentaremos 3 aplicaciones muy útiles que el ACELERÓMETRO ADXL345 de Analog Devices ® puede implementar:
ª       Control de actuadores (en este caso SERVOMOTORES de acuerdo a la inclinación del sensor)
ª       Detección de TAP (movimiento de pulso corto)
ª       Detección de Caída Libre.

Vayamos!!!


  • ·         El acelerómetro ADXL345.

El ADXL345 es un acelerómetro delgado y de baja potencia, con tres ejes de medición de alta resolución (13 bits) hasta ± 16 g. La salida digital de Datos tiene el formato de complemento a  dos de 16 bits y es accesible a través de las interfaces SPI (3- o 4 conexiones) o interfaz digital I2C.

El ADXL345 es muy adecuado para aplicaciones de dispositivos móviles. Este mide la aceleración estática de la gravedad en la inclinación, así como la aceleración dinámica resultante de movimiento o choque. Su alta resolución (4mg / LSB) permite resolución de los cambios de inclinación de tan poco como 0,25 °.




ª       Control de actuadores (SERVOMOTORES)

Como leímos el ADXL345 tiene la capacidad de detectar su inclinación y mandar por medio de una interfaz I2C o SPI las coordenadas de su posición.
Para esto primeramente te invitamos  a que corrobores el funcionamiento de tu acelerómetro mediante una aplicación que implementaras en tu ChipKit, necesitas tener simplemente las librería Wire.h la cual ya viene en la paquetería básica del ChipKit o que puedes descargar aquí, asegúrate que las palabras clave CORRESPONDAN con las funciones de la librería ya que algunas que están heredadas de la plataforma Arduino sufren modificaciones como:


Wire.write → Wire.send
Wire.read →Wire.receive

 Abre tu IDE y teclea el siguiente código:



#include <Wire.h>
#define accel_module (0x53)

byte values[6] ;
char output[512];
void setup(){
Wire.begin();
Serial.begin(9600);

Wire.beginTransmission(accel_module);
Wire.send(0x2D);
Wire.send(0);
Wire.endTransmission();
Wire.beginTransmission(accel_module);
Wire.send(0x2D);
Wire.send(16);
Wire.endTransmission();
Wire.beginTransmission(accel_module);
Wire.send(0x2D);
Wire.send(8);
Wire.endTransmission();
}
void loop(){
int xyzregister = 0x32;
int x, y, z;
Wire.beginTransmission(accel_module);
Wire.send(xyzregister);
Wire.endTransmission();
Wire.beginTransmission(accel_module);
Wire.requestFrom(accel_module, 6);

int i = 0;
while(Wire.available()){
values[i] = Wire.receive();
i++;
}
Wire.endTransmission();
x = (((int)values[1]) << 8) | values[0];
y = (((int)values[3])<< 8) | values[2];
z = (((int)values[5]) << 8) | values[4];
sprintf(output, "%d %d %d", x, y, z);
Serial.print(output);
Serial.write(10);

delay(1000);
}


Corre el programa, deberás de ver el despliegue de las coordenadas en el monitor serial.


El monitor serial arroja las coordenadas del acelerómetro de acuerdo a su gravedad estática, con estos valores implementaremos nuestra aplicación!!!

Implementamos entonces el siguiente circuito:

Para el primer inciso:


ChipKit ofrece ya una librería heredada de Arduino la cual nos ayuda a manipular un servomotor, con el siguiente código podrás enlazar la información recibida por nuestro ADXL345 para manipular en:

EJE X  -> SERVO 1
EJE Y -> SERVO 2.

CÓDIGO:

#include <Wire.h>
#include <Servo.h>


Servo myservox; // servo for x axis
Servo myservoy; // servo for y axis
#define DEVICE (0x53) //ADXL345 device address
#define TO_READ (6)   //num of bytes we are going to read each time (two bytes for each axis)
#define TRIGGER 16    // pin analog2 (16) connect to CS Adxl345, active high
byte buff[TO_READ] ;  //6 bytes buffer for saving data read from the device
int i;

void setup()
{
  pinMode(TRIGGER,OUTPUT);
  digitalWrite(TRIGGER,HIGH);
  Wire.begin();        // join i2c bus (address optional for master)
  myservox.attach(9);  // attaches the servo on pin 9 to the servo object
  myservoy.attach(10); // attaches the servo on pin 10 to the servo object
  myservox.write(90);  // tell servo x to go to position 90 deg
  delay(25);           // makesure servo move
  myservoy.write(90);  // tell servo y to go to position 90 deg
  delay(25);          // makesure servo move
  //Turning on the ADXL345
  writeTo(DEVICE, 0x2D, 0);     
  writeTo(DEVICE, 0x2D, 16);
  writeTo(DEVICE, 0x2D, 8);
}

void loop()
{
  int regAddress = 0x32;    //first axis-acceleration-data register on the ADXL345
  int x, y, z;
  digitalWrite(TRIGGER,LOW);
  delay(10);
  digitalWrite(TRIGGER,HIGH);
  readFrom(DEVICE, regAddress, TO_READ, buff); //read the acceleration data from the ADXL345

  //each axis reading comes in 10 bit resolution, ie 2 bytes.  Least Significat Byte first!!
  //thus we are converting both bytes in to one int
  //read 5 times and average them
  x=0;
  y=0;
  z=0;
  for(i=1;i<=5;i++){
    x += (((int)buff[1]) << 8) | buff[0];  
    y += (((int)buff[3])<< 8) | buff[2];
    z += (((int)buff[5]) << 8) | buff[4];
    delay(10);
  }
  x/=5;
  y/=5;
  z/=5;
  if(x<-255)x= -255; else if (x>255)x=255;
  if(y<-255)y= -255; else if (y>255)y=255;
  x=map(x, -255, 255, 0, 180);  // map range y
  y=map(y, -255, 255, 0, 180);  // map range y
  myservox.write(x);            // tell servo to go to position in variable x
  delay(25);
  myservoy.write(180-y);            // tell servo to go to position in variable y
  delay(25);
   //It appears that delay is needed in order not to clog the port
  delay(200);
}

//---------------- Functions
//Writes val to address register on device
void writeTo(int device, byte address, byte val) {
  Wire.beginTransmission(device); //start transmission to device
  Wire.send(address);        // send register address
  Wire.send(val);        // send value to write
  Wire.endTransmission(); //end transmission
}

//reads num bytes starting from address register on device in to buff array
void readFrom(int device, byte address, int num, byte buff[]) {
  Wire.beginTransmission(device); //start transmission to device
  Wire.send(address);        //sends address to read from
  Wire.endTransmission(); //end transmission

    Wire.beginTransmission(device); //start transmission to device
  Wire.requestFrom(device, num);    // request 6 bytes from device

  int i = 0;
  while(Wire.available())    //device may send less than requested (abnormal)
  {
    buff[i] = Wire.receive(); // receive a byte
    i++;
  }
  Wire.endTransmission(); //end transmission
}

TAP y Caída Libre

La librería heredada para tap y caida libre tambien son de amplia apertura a través de la RED, donde al igual que este código no es necesario hacer ligeras modificaciones:


Wire.write → Wire.send
Wire.read →Wire.receive

Archivo PDE:

#include <Wire.h>
#include <ADXL345.h>
#include <Servo.h> 
Servo myservox; // servo for x axis
Servo myservoy; // servo for y axis
#define DEVICE (0x53) //ADXL345 device address
#define TO_READ (6)   //num of bytes we are going to read each time (two bytes for each axis)
#define TRIGGER 16    // pin analog2 (16) connect to CS Adxl345, active high
byte buff[TO_READ] ;  //6 bytes buffer for saving data read from the device
int i;

ADXL345 accelerometer;

void setup(void) 
{
  Serial.begin(9600);
  
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(30, OUTPUT);

  // Initialize ADXL345
  Serial.println("Initialize ADXL345");

  if (!accelerometer.begin())
  {
    Serial.println("Could not find a valid ADXL345 sensor, check wiring!");
    delay(500);
  }

  // Set tap detection on Z-Axis
  accelerometer.setTapDetectionX(0);       // Don't check tap on X-Axis
  accelerometer.setTapDetectionY(0);       // Don't check tap on Y-Axis
  accelerometer.setTapDetectionZ(1);       // Check tap on Z-Axis
  // or
  // accelerometer.setTapDetectionXYZ(1);  // Check tap on X,Y,Z-Axis

  accelerometer.setTapThreshold(2.5);      // Recommended 2.5 g
  accelerometer.setTapDuration(0.02);      // Recommended 0.02 s
  accelerometer.setDoubleTapLatency(0.10); // Recommended 0.10 s
  accelerometer.setDoubleTapWindow(0.30);  // Recommended 0.30 s
  
  //Values for Free Fall detection
  accelerometer.setFreeFallThreshold(0.35); // Recommended 0.3 -0.6 g
  accelerometer.setFreeFallDuration(0.1);  // Recommended 0.1 s

  // Select INT 1 for get activities
  accelerometer.useInterrupt(ADXL345_INT1);

  // Check settings
  checkSetup();
  
  pinMode(TRIGGER,OUTPUT);
  digitalWrite(TRIGGER,HIGH);
  Wire.begin();        // join i2c bus (address optional for master)
  myservox.attach(9);  // attaches the servo on pin 9 to the servo object 
  myservoy.attach(10); // attaches the servo on pin 10 to the servo object 
  myservox.write(90);  // tell servo x to go to position 90 deg
  delay(25);           // makesure servo move
  myservoy.write(90);  // tell servo y to go to position 90 deg
  delay(25);          // makesure servo move
  //Turning on the ADXL345
  writeTo(DEVICE, 0x2D, 0);      
  writeTo(DEVICE, 0x2D, 16);
  writeTo(DEVICE, 0x2D, 8);
}

void checkSetup()
{
  Serial.print("Look tap on axis = "); 
  if (accelerometer.getTapDetectionX()) { Serial.print(" X "); }
  if (accelerometer.getTapDetectionY()) { Serial.print(" Y "); }
  if (accelerometer.getTapDetectionZ()) { Serial.print(" Z "); }
  Serial.println();

  Serial.print("Tap Threshold = "); Serial.println(accelerometer.getTapThreshold());
  Serial.print("Tap Duration = "); Serial.println(accelerometer.getTapDuration());
  Serial.print("Double Tap Latency = "); Serial.println(accelerometer.getDoubleTapLatency());
  Serial.print("Double Tap Window = "); Serial.println(accelerometer.getDoubleTapWindow());
  
  Serial.print("Free Fall Threshold = "); Serial.println(accelerometer.getFreeFallThreshold());
  Serial.print("Free Fall Duration = "); Serial.println(accelerometer.getFreeFallDuration());
}

void loop(void) 
{
  // Read values for activities
  delay(50);
  Vector norm = accelerometer.readNormalize();

  // Read activities
  Activites activ = accelerometer.readActivites();

if (activ.isFreeFall)
  {
    Serial.println("Free Fall Detected! led");
    digitalWrite(30, HIGH);
    delay(500);
    digitalWrite(30, LOW);
  }else
  if (activ.isDoubleTap)
  {
    Serial.println("Double Tap Detected led");
    digitalWrite(4, HIGH);
    delay(500);
    digitalWrite(4, LOW);
    
  } else
  
  
  if (activ.isTap)
  {
    Serial.println("Tap Detected led");
    digitalWrite(5, HIGH);
    delay(500);
    digitalWrite(5, LOW);
  }
  
  int regAddress = 0x32;    //first axis-acceleration-data register on the ADXL345
  int x, y, z;
  digitalWrite(TRIGGER,LOW);
  delay(10);
  digitalWrite(TRIGGER,HIGH); 
  readFrom(DEVICE, regAddress, TO_READ, buff); //read the acceleration data from the ADXL345

  //each axis reading comes in 10 bit resolution, ie 2 bytes.  Least Significat Byte first!!
  //thus we are converting both bytes in to one int
  //read 5 times and average them
  x=0;
  y=0;
  z=0;
  for(i=1;i<=5;i++){
    x += (((int)buff[1]) << 8) | buff[0];   
    y += (((int)buff[3])<< 8) | buff[2];
    z += (((int)buff[5]) << 8) | buff[4];
    delay(10);
  }
  x/=5;
  y/=5;
  z/=5;
  if(x<-255)x= -255; else if (x>255)x=255;
  if(y<-255)y= -255; else if (y>255)y=255;
  x=map(x, -255, 255, 0, 180);  // map range y
  y=map(y, -255, 255, 0, 180);  // map range y
  myservox.write(x);            // tell servo to go to position in variable x
  delay(25); 
  myservoy.write(180-y);            // tell servo to go to position in variable y 
  delay(25); 
   //It appears that delay is needed in order not to clog the port
  delay(200);
}

//---------------- Functions
//Writes val to address register on device
void writeTo(int device, byte address, byte val) {
  Wire.beginTransmission(device); //start transmission to device 
  Wire.send(address);        // send register address
  Wire.send(val);        // send value to write
  Wire.endTransmission(); //end transmission
}

//reads num bytes starting from address register on device in to buff array
void readFrom(int device, byte address, int num, byte buff[]) {
  Wire.beginTransmission(device); //start transmission to device 
  Wire.send(address);        //sends address to read from
  Wire.endTransmission(); //end transmission

    Wire.beginTransmission(device); //start transmission to device
  Wire.requestFrom(device, num);    // request 6 bytes from device

  int i = 0;
  while(Wire.available())    //device may send less than requested (abnormal)
  { 
    buff[i] = Wire.receive(); // receive a byte
    i++;
  }
  Wire.endTransmission(); //end transmission
}



TE COMPARTIMOS EL VIDEO!!!!



4 comentarios:

  1. Hola equipo, me agrado mucho los diagramas que están poniendo de conexión es agradable y se entiende a simple vista las conexiones, en ves de la foto.
    Igual un gran detalle en explicar la practica de forma para que nosotros lo repitamos sobre todo la parte de corroborar el funcionamiento del acelerómetro mediante la aplicación que comparten, lastima que no estemos manejando el mismo micro ChipKi.
    Se ayudaron bastante con la biblioteca de arduino, lo que hizo que el codigo este bastante claro, y gracias por compartirlo.

    Y claro que esperamos la siguiente aplicación con el TAP y caída libre, espero haya vídeo.

    Saludos, equipo 1

    ResponderEliminar
  2. Igual concuerdo con ale, las imágenes que utilizan para representar la practica están excelentes. Eso ayuda mucho a que el lector tenga interés para seguir paso a paso las instrucciones. Y compartir los códigos que muchas veces no están completos en Internet. Gracias por el aporte.

    ResponderEliminar
  3. Igual concuerdo con ale, las imágenes que utilizan para representar la practica están excelentes. Eso ayuda mucho a que el lector tenga interés para seguir paso a paso las instrucciones. Y compartir los códigos que muchas veces no están completos en Internet. Gracias por el aporte.

    ResponderEliminar
  4. Excelente post. No son nada egoístas el código, que muchas veces solo te explican pero al final no tienes idea como funciona. Cualquier usuario puede implementar esta práctica y adaptarla a sus necesidades. Excelentes diagramas y aportes. Gracias!
    Saludos.

    ResponderEliminar