lunes, 30 de diciembre de 2013

Nivelando superficies con un acelerómetro

Cómo funciona un acelerómetro

Un acelerómetro, como su nombre indica, mide la aceleración a la que está sometido. Si lo movemos, nos medirá no sólo la aceleración, sino hacia dónde acelera. Para ello nuestro acelerómetro tiene una entrada para cada dimensión del espacio y nos devolverá los tres componentes del vector aceleración. Pero no solo es capaz de medir la aceleración, sino que en reposo mide la componente de la gravedad que soporta cada uno de sus ejes. Si lo conectamos y lo ponemos sobre una mesa en su posición normal veremos cómo las entradas de los ejes x e y tienen más o menos el mismo valor, pero la del eje z no. Esto es porque está perpendicular al centro de la tierra y por lo tanto la atracción gravitatoria recae enteramente sobre el eje z.



Si lo inclinamos un poco z disminuirá al repartirse la gravedad entre los tres ejes.



Así pues, la superficie sobre la que se apoye el acelerómetro estará nivelada cuando el eje perpendicular a ella soporte toda la fuerza de la gravedad si estamos nivelando en horizontal y ninguna fuerza si estamos nivelando en vertical. Un detalle importante es que el acelerómetro puede detectar la gravedad pero no la orientación, es decir, que si lo rotamos alrededor de uno de los ejes no se enterará. Para detectar el giro necesitaríamos un giróscopo . Este detalle es importante a la hora de mostrar en la pantalla LCD la inclinación que tiene el acelerómetro, ya que nos obliga a orientar correctamente los ejes para realizar el nivelado de superficies verticales.

El acelerómetro

Para el circuito vamos a usar un acelerómetro GY-61. Como podemos ver en la imagen tiene dibujados los ejes para que podamos orientarlo. Para que el sketch funcione correctamente lo tenemos que orientar de forma que el eje Z quede perpendicular a la placa de prototipo. El acelerómetro funciona a 3.3V, por lo que tenemos que ir con cuidado de no conectarlo al pin de 5V de Arduino sino al 3.3V ya que lo podemos quemar.



La pantalla LCD

Para mostrar la orientación del acelerómetro vamos a usar una pantalla Nokia LCD 5110. Supuestamente es la que llevan varios modelos de móviles Nokia, así que, al menos en teoría, los podríamos desmontar y reutilizar la pantalla. En mi caso la he comprado, ya que tampoco tienen un precio excesivo. Para programarla usaremos la biblioteca de arduino desarrollada por Adafruit. La podemos descargar aquí. También tenemos que descargar la biblioteca GFX también desarrollada por Adafruit.
La pantalla LCD también funciona a 3.3V y por lo tanto también tendremos que conectarla al pin 3.3V de arduino. Además tendremos que usar resistencias para bajar el voltaje que le llega desde los pines digitales, ya que su voltaje de salida es 5V. En la conexión del acelerómtro no las necesitamos porque únicamente vamos a leer, pero en los pines del LCD vamos a escribir y por lo tanto les tenemos que enviar 3.3V en lugar de 5V, que es lo que sale de los pines del arduino. El esquema de conexión es el siguiente:

  
El pin LED del LCD es el que se encarga de iluminar la pantalla. Lo hemos conectado a corriente para que esté siempre iluminada. Si quisiéramos encenderla mediante programación tendríamos que conectarla a uno de los pines digitales de arduino y encenderla o apagarla con la función analogWrite poniendo el pin a HIGH o LOW. El resto de pines digitales son los estándares del protocolo SPI que es el que usa la biblioteca de Adafruit. Un detalle importante es que conectamos el pin VCC y LED directamente a corrienta porque todo el circuito está funcionando a 3.3V. Si conectamos el LCD a un circuito cuyos componentes funcionen a 5V deberemos ponerles una resistencia de 10kΏ o correremos el riesgo de quemar el LCD. Aquí lo tenemos montado en la placa de prototipo



El sketch

El sketch va a dibujar en el LCD dos círculos, uno señalará el punto en el que la superficie está nivelada y el otro se moverá conforme vayamos inclinando el acelerómetro. La superficie estará nivelada cuando el segundo círculo esté dentro del primero.
Antes de poder usar el acelerómetro tenemos que calibrarlo para averiguar los valores para 1g, 0g y -1g. Para ello lo colocaremos sobre una superficie horizontal y anotaremos los valores para el eje Z, que será 1g, y el valor para X o Y que serán 0g. Para averiguar el -1g pondremos el acelerómetro al revés y lo rotamos hacia ambos lados. El menor valor que tome será -1g. Las constantes que guardan estos valores son:

const int negativegValue=270;
const int zerogValue=350;
const int onegValue=424;

El código fuente completo:

#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>

const int xPin = 0;
const int yPin = 1;
const int zPin = 2;

const byte SCLKpin = 13;
const byte DNpin = 11;
const byte DCpin = 12; 
const byte RESETpin = 10;

const byte ballRadius=5;
const byte errorMargin=1;
int xReadOld=0;
int yReadOld=0;
int zReadOld=0;

const int negativegValue=270;
const int zerogValue=350;
const int onegValue=424;
char contrast=57;
char buffer[10];

Adafruit_PCD8544 lcd(SCLKpin,DNpin,DCpin,RESETpin);

void setup(){
  Serial.begin(115200); 
  lcd.begin();
  lcd.setContrast(contrast);
}


void loop(){

  int xRead = analogRead(xPin);
  int yRead = analogRead(yPin);
  int zRead = analogRead(zPin);
  int currentX;
  int currentY;
  /* Elegimos la orientacion que estamos nivelando por el valor del eje z que siempre sera perpendicular a la superficie
  Cambiaremos segun su valor este mas cerca de cero o de 1g*/
  if(zRead<(zerogValue+((onegValue-zerogValue)/2))){
    //Orientacion vertical
    //currentX=lcd.width()/2;
    currentX=map(zerogValue,negativegValue,onegValue,0,lcd.width());
    currentY=map(zRead,negativegValue,onegValue,0,lcd.height());
  }
  else{
    currentX=map(xRead,negativegValue,onegValue,0,lcd.width());
    currentY=map(yRead,negativegValue,onegValue,0,lcd.height());
  }
  
  if(abs(zRead-zReadOld)>=errorMargin){
  
    lcd.clearDisplay();
    
    drawBall(currentX,currentY,5);
    
    xReadOld=xRead;
    yReadOld=yRead;
    zReadOld=zRead;
  }
  
  
  Serial.print("xRead: ");
  Serial.print(xRead);
  Serial.print(" | yRead: ");
  Serial.print(yRead);
  Serial.print(" | zRead: ");
  Serial.println(zRead);

  

  delay(100);
}

void drawBall(int x,int y,int radius){
  
  for(int i=0;i<radius;i++){
    lcd.drawCircle(x,y,i,BLACK);
  }
lcd.drawCircle((int)map(zerogValue,negativegValue,onegValue,0,lcd.width()),(int)map(zerogValue,negativegValue,onegValue,0,lcd.height()),radius+2,BLACK);
  lcd.display();
}

Básicamente lo que hace el sketch es leer los valores de los tres ejes del acelerómetro y redibujar la pantalla cuando el eje Z se ha movido más de un margen de error indicado en la variable errorMargin. La orientación de la superficie a nivelar lo decidimos en función del valor del eje Z, si está más cerca de 1g asumiremos que estamos nivelando una superficie horizontal y si está más cerca de 0g asumiremos que nivelamos una superficie vertical. Para las superficies horizontales la bola se moverá en cualquier dirección del plano XY y para las verticales sólo se moverá arriba y abajo. Para que funcione correctamente con las superficies verticales tenemos que situar el acelerómetro con la flecha del eje Y apuntando hacia el centro de la Tierra. Aquí tenemos un vídeo mostrando su funcionamiento


No hay comentarios:

Publicar un comentario