Acelerómetro

Acelerómetro

Un acelerómetro es un dispositivo capaz de detectar dos tipos de aceleración, estática (la gravedad) y la dinámica (movimientos o vibraciones).

Suelen contener placas capacitivas internas, así como otros están unidos a diminutos resortes que se mueven según la aceleración que actúe sobre él. Es gracias a estos cambios en la capacitancia, por lo que puede determinarse la aceleración producida en cada momento.

Calculando ángulos de inclinación

Cuando se encuentra en reposo, y de manera horizontal al suelo, lo único que detectará será la fuerza de la gravedad sobre el eje Z, refiriéndose a los ejes cada uno en esta dirección:

ejes

Conociendo el valor de la fuerza gravitatoria de los 3 ejes, y aplicando trigonometría podemos obtener, el ángulo de inclinación de los ejes, y por tanto la pendiente del entorno. acc_examples

En el caso 1 tenemos el acelerómetro totalmente paralelo al suelo, por lo que la única componente donde existe fuerza gravitatoria es la del eje Z, y por tanto las inclinación es para el Eje X e Y son nulas. Sin embargo en el caso 2, el acelerómetro está inclinado un cierto ángulo Theta, por lo que la resultante de la fuerza gravitatoria ahora se reparte sobre el eje Y y sobre el Z, de tal manera que la fuerza gravitatoria sobre el Y es igual a la fuerza gravitatoria total sobre el acelerómetro por el seno del ángulo Theta:

Formula-GY

Mientras que la del eje Z será la fuerza total multiplicada por el coseno del ángulo:

Formula-GZ

Si dividimos una entre la otra, obtenemos la tangente del ángulo

Tg

Y por tanto aplicando la arcotangente de la fuerza gravitatoria del eje Y entre la del Z, obtenemos el ángulo de inclinación del acelerómetro respecto al eje Y.

Arctg

Ejes

Lo mismo pasaría respecto al eje X.

ADLX345

En este caso se utiliza el ADLX345, que se trata de un acelerómetro digital de 3 ejes de la marca Analog Devices. Dispone de sensibilidad ajustable y una resolución de 13 bits. Se puede conectar mediante SPI o I2C. Posee una resolución de 3,9mg / LSB permitiendo detectar cambios de inclinación menores a 1º.

Otras características

  • Rango de medición seleccionable +/- 2, 4, 8 y 16 g
  • El módulo o tarjeta de interconexión incluye un circuito regulador de voltaje
  • Pines configurables para generar interrupciones
  • Voltaje de operación de a 3.6 V

Para calibrar correctamente el transductor, hay que tener en cuenta el offset que hay que corregir a cada eje, y escribirlo en los registros: 0x1E, 0x1F, 0x20 para el eje x, y, z respectivamente.

Para saber que offset aplicar en cada uno de los ejes, se coloca el transductor horizontal al suelo, de tal manera que la gravedad se encuentre en el eje Z. Se toman varias medidas y se hace una media de las correspondientes a cada eje. Se obtiene así el offset real correspondiente a cada uno.

Además hay que indicar el rango de medición y la resolución deseados en el registro 0x31. Y el ancho de banda y la velocidad de salida de datos en el registro 0x2C.

Un ejemplo de un programa basado en la librería de python del ADXL345 sería el siguiente:

#!/usr/bin/python
# -*- coding: utf-8 -*-
#################################################
#						#
# Accelerometer control module			#
# Authors: Ismael Tobar and Raquel Muñoz        #
#						#
#################################################

import smbus
import threading
import math #function atan
from time import sleep

#constants
TIME_THREAD = 0.3
EARTH_GRAVITY_MS2   = 9.80665
DATA_FORMAT         = 0x31
BW_RATE             = 0x2C
POWER_CTL           = 0x2D
BW_RATE_100HZ       = 0x0B
RANGE_2G            = 0x00
MEASURE             = 0x08
AXES_DATA           = 0x32
X_OFFSET            = 0x1E
Y_OFFSET            = 0x1F
Z_OFFSET            = 0x20
ACCELEROMETER_ADDRESS = 0x53

#status variables
DISCONNECTED = 0
CONNECTED_OK = 1
CONNECTED_ERROR = 2

#variables
i2c = 0 #i2c bus
ac_x = 0  #Measure of the X axe taken by the accelerometer
ac_y = 0  #Measure of the Y axe taken by the accelerometer
ac_z = 0  #Measure of the Z axe taken by the accelerometer
angleXZ = 0 	#angle measured by the accelerometer between X and Z axes
angleYZ = 0 	#angle measured by the accelerometer between Y and Z axes
calibrate_x = 32 #value to calibrate X axe
calibrate_y = 15 #value to calibrate Y axe  
stop_thread_a = True #It's the variable than stop the thread of the accelerometer
status = DISCONNECTED

def setup():
  global i2c
  global status
  try:
    i2c = smbus.SMBus(1) #The i2c bus is declared
    i2c.write_byte_data(ACCELEROMETER_ADDRESS, BW_RATE, BW_RATE_100HZ ) # set Band width Rate to 100 Hz
    value = i2c.read_byte_data(ACCELEROMETER_ADDRESS, DATA_FORMAT)
    value &= ~0x0F;
    value '= RANGE_2G
    value '= 0x08;
    i2c.write_byte_data(ACCELEROMETER_ADDRESS, DATA_FORMAT, value) #Set the range to 2G
    i2c.write_byte_data(ACCELEROMETER_ADDRESS, POWER_CTL, MEASURE) #Enable de measure
    print("AC: Setup")
    status = CONNECTED_OK
  except Exception as e:
    print("AC: Error creating connection to i2c")
    print(e)
    status = CONNECTED_ERROR

def read_axes(gforce = False):
  bytes = i2c.read_i2c_block_data(ACCELEROMETER_ADDRESS, AXES_DATA, 6)
  x = bytes[0] ' (bytes[1] << 8)
  if(x & (1 << 16 - 1)):
    x = x - (1<<16)
  y = bytes[2] ' (bytes[3] << 8)
  if(y & (1 << 16 - 1)):
    y = y - (1<<16)
  z = bytes[4] ' (bytes[5] << 8)
  if(z & (1 << 16 - 1)):
    z = z - (1<<16)
  if gforce == False:
    x = x * EARTH_GRAVITY_MS2
    y = y * EARTH_GRAVITY_MS2
    z = z * EARTH_GRAVITY_MS2
  x = round(x, 4)
  y = round(y, 4)
  z = round(z, 4)
  return {"x": x, "y": y, "z": z}

def read_ac():
  global ac_x
  global ac_y
  global ac_z
  global angleXZ
  global angleYZ
  axes = read_axes(True)
  ac_x = abs(axes['x'])*2-512        #the range is adapted to +-512
  ac_y = abs(axes['y'])*2-512
  ac_z = axes['z']
  angleYZ = math.atan(ac_y / ac_z)       #The angle is obtained
  angleYZ = int(round(angleYZ*(114.5916),0) - calibrate_y)  #The angle is transformed into degrees
  angleXZ = math.atan(ac_x/ ac_z)
  angleXZ = int(round(angleXZ*(114.5916),0) - calibrate_x)  #The angle is transformed into degrees

def thread_ac():
  global status
  while stop_thread_a == False:
    try:
      read_ac()
      sleep(TIME_THREAD)
    except Exception as e:
      print("AC: Error in accelerometer thread")
      print(e)
      status = CONNECTED_ERROR
  print("AC: Accelerometer thread stopped")

def start_thread_ac():
  global status
  global stop_thread_a
  try:
    thread_sensors_ac = threading.Thread(target=thread_ac)
    stop_thread_a = False
    thread_sensors_ac.start()
    print('AC started')
  except Exception as e:
    print("AC: Error starting accelerometer thread")
    print(e)
    status = CONNECTED_ERROR

def stop_thread_ac():
  global stop_thread_a
  stop_thread_a = True
  #print("\n AC: Stop thread")

def get_accelerometer():
  return(angleXZ,angleYZ)

def get_accelerometer_axes():
  return(ac_x,ac_y,ac_z)

def calibrate():
  #It's supouse that the robot is in the correct position before start the calibration
  global calibrate_x
  global calibrate_y
  read_ac()
  calibrate_x += angleXZ
  calibrate_y += angleYZ

if __name__ == "__main__":
  setup()
  terminate = False
  calibrated = input('Do you want to calibrate the accelerometer first? (0 no, 1 yes) : ')
  if calibrated == 1:
    calibrate()
  while terminate == False:
    sleep(0.1)
    seconds = input('Enter how many seconds you want be taking measures? (0 to exit) : ')
    if seconds != 0:
      start_thread_ac()
      for i in range (0,seconds):
        sleep(1)
        print("x: ",angleXZ)
        print("y: ",angleYZ)
      stop_thread_ac()
    else:
      stop_thread_ac()
      terminate = True
  print('AC: Exit accelerometer')

En nuestro caso este acelerómetro forma parte del vehículo robotizado que hemos desarrollado.