domingo, 6 de febrero de 2011

Calculando la inclinación en grados de nuestro acelerómetro MMA7260

Una vez que disponemos de las aceleraciones estáticas de nuestro dispositivo tan sólo queda aplicar un poco de trigonometría para disponer para cada eje el ángulo.
Las formulas que he usado son las siguientes:

 x=analogRead(xaxis);
 y=analogRead(yaxis);
 z=analogRead(zaxis);

 unsigned long tt = micros();
 
 float aax = (((x*5000.0)/1023.0)-XError)/RESOLUTION;
 float aay = (((y*5000.0)/1023.0)-YError)/RESOLUTION;
 float aaz = (((z*5000.0)/1023.0)-ZError)/RESOLUTION;

 float rho = atan(aax/sqrt(pow(aay,2)+pow(aaz,2)))*(360/2*PI);
 float phi = atan(aay/sqrt(pow(aax,2)+pow(aaz,2)))*(360/2*PI);
 float theta = atan(sqrt(pow(aay,2)+pow(aax,2))/aaz)*(360/2*PI);
 
 tt = micros() - tt;

el último término es para pasar de radianes a grados.
Como puede verse, el cálculo es bastante costoso debido a la gran cantidad de cálculos que hay que realizar por lo que intentaremos acelerar y simplificar dichas operaciones. Utilizando la función micros() podemos ver los microsegundos que se tardan en resolver todos los cálculos lo que nos será muy útil para ver si vamos mejorando el algoritmo.

El valor de "tt" es aproximadamente de 980 microsegundos por lo que disponemos ahora de un indicador de lo que tarda en calcularse los grados a partir del voltaje de entrada del acelerómetro.

Aplicando algunas optimizaciones podemos disponer ya de los valores en grados de los tres ejes de nuestro acelerómetro

#define DEBUGMODE

#define _360div2xPI     57.29577951
#define _5000div1023    4.887585533 

#define MMA7260_RESOLUTION      800     //0.8 v/g -> resolucion de 1.5g -> 800mV/g
#define MMA7260_VOLTAGE         3300.0; //mv voltage al que está conectado el acelerómetro

const float ZOUT1G = 2450;   // mv Voltage en Zout a 1G
const float ZOUT0G = 1650;   // mv Voltage en Zout a 1G
#define MMA7260_ZOUT_1G 850   // mv Voltage en Zout a 1G

const float XOUT1G = 2450;   // mv Voltage en Zout a 1G
const float XOUT0G = 1650;   // mv Voltage en Zout a 1G

const float YOUT1G = 2450;   // mv Voltage en Zout a 1G
const float YOUT0G = 1650;   // mv Voltage en Zout a 1G

#define NADJ  50        // Número de lecturas para calcular el error

// Entradas analógicas donde van los sensores
#define XAXIS_PORT  0
#define YAXIS_PORT  1
#define ZAXIS_PORT  2

// Salida digital del led de la placa
#define LEDPIN_PORT  13

float XError,YError,ZError;
float z,x,y;

float AccelAdjust(int axis)
{
  float acc = 0;

  for (int j=0;j < NADJ;j++)
  {
    float lectura=analogRead(axis);
    acc = acc + (lectura*_5000div1023);
    delay(11); //número primo para evitar ciclos de lectura proporcionales
  }

  return acc/NADJ;
}

void setup()
{  
  Serial.begin(9600); // 9600 bps
  pinMode(XAXIS_PORT,INPUT);
  pinMode(YAXIS_PORT,INPUT);
  pinMode(ZAXIS_PORT,INPUT);
  pinMode(LEDPIN_PORT, OUTPUT);

  digitalWrite(LEDPIN_PORT, HIGH);
  XError =  AccelAdjust(XAXIS_PORT);
  YError =  AccelAdjust(YAXIS_PORT);
  ZError =  AccelAdjust(ZAXIS_PORT);
  ZError = ZError - MMA7260_ZOUT_1G;
  digitalWrite(LEDPIN_PORT, LOW);

#ifdef DEBUGMODE
  Serial.println("Ajustado acelerometro eje X");
  Serial.print("Error de X= ");
  Serial.println(XError);

  Serial.println("Ajustado acelerometro eje Y");
  Serial.print("Error de Y= ");
  Serial.println(YError);

  Serial.println("Ajustado acelerometro eje Z");
  Serial.print("Error de Z= ");
  Serial.println(ZError);
#endif   
}

void loop()
{
  x=analogRead(XAXIS_PORT);
  y=analogRead(YAXIS_PORT);
  z=analogRead(ZAXIS_PORT);

  unsigned long tt = micros();

  float aax = ((x*_5000div1023)-XError)/MMA7260_RESOLUTION;
  float aay = ((y*_5000div1023)-YError)/MMA7260_RESOLUTION;
  float aaz = ((z*_5000div1023)-ZError)/MMA7260_RESOLUTION;

  float rho = atan(aax/sqrt((aay*aay)+(aaz*aaz)))*_360div2xPI;
  float phi = atan(aay/sqrt((aax*aax)+(aaz*aaz)))*_360div2xPI;
  float theta = atan(sqrt((aay*aay)+(aax*aax))/aaz)*_360div2xPI;

  tt = micros()-tt;

#ifdef DEBUGMODE
  Serial.print(aax);
  Serial.print(" ");
  Serial.print(aay);
  Serial.print(" ");          
  Serial.print(aaz);
  Serial.println();

  Serial.print(rho);
  Serial.print(" ");
  Serial.print(phi);
  Serial.print(" ");
  Serial.print(theta);

  Serial.println();

  Serial.print(tt);
  Serial.println();

#endif

  delay(1000);
}


En esta imagen puede verse, con el acelerómetro inclinado hacia arriba, el eje Y y Z cerca de 90º.

Con este código modificado dispondremos de las inclinaciones en reposo así como un tiempo de alrededor de 930 microsegundos (50 microsegundos más rápido). Se han cambiado algunas variables por #defines así como algunos cálculos se han convertido en constantes. Sin embargo el mayor tiempo se consume en el cálculo de las funciones trigonométricas que espero poder mejorar usando por ejemplo lookup-tables.

sábado, 5 de febrero de 2011

Midiendo las inclinaciones con el MMA7260

Siguiendo con nuestro trabajo con el acelerómetro MMA7260 toca recoger la información que nos suministra. Inicialmente lo utilizaremos para medir la aceleración estática y como en reposo está sometido a la fuerza de la gravedad podremos medir las inclinaciones en los tres ejes.

Existe un documento muy bueno y muy detallado desarrollado por el fabricante con los detalles técnicos que utilizaremos para esta aplicación.

Lo primero será conectar al Arduino las señales provenientes de cada eje de aceleración del acelerómetro. Para ello utilizaremos las entradas analógicas A0, A1 y A2 como vimos en el post anterior.


Una vez conectadas, programaremos el Arduino para que recoja los valores de esas entradas, las transformaremos y las mostraremos por pantalla.

Para programar con Arduino necesitaremos descargarnos el entorno de desarrollo desde la página web oficial (mejor en inglés ya que dispondrá de la versión más actualizada), podeis seguir las instrucciones para los que nos hayais programado nunca en este entorno.

A continuación os coloco el programa para medir la lectura de la aceleración en Gs:

#define DEBUGMODE

const float RESOLUTION=800; //0.8 v/g -> resolucion de 1.5g -> 800mV/g
const float VOLTAGE=3.3;  //voltage al que está conectado el acelerómetro

const float ZOUT1G = 2450;   // mv Voltage en Zout a 1G
const float ZOUT0G = 1650;   // mv Voltage en Zout a 1G
const float ZOUT_1G = 850;   // mv Voltage en Zout a 1G

const float XOUT1G = 2450;   // mv Voltage en Zout a 1G
const float XOUT0G = 1650;   // mv Voltage en Zout a 1G

const float YOUT1G = 2450;   // mv Voltage en Zout a 1G
const float YOUT0G = 1650;   // mv Voltage en Zout a 1G

const int NADJ  = 50;        // Número de lecturas para calcular el error

// Entradas analógicas donde van los sensores
const int xaxis = 0;
const int yaxis = 1;
const int zaxis = 2;

// Salida digital del led de la placa
const int LEDPIN = 13;

float XError,YError,ZError;
float xd,yd,zd,z,x,y;

float AccelAdjust(int axis)
{
 float acc = 0;

 for (int j=0;j
 {
   float lectura=analogRead(axis);
   acc = acc + ((lectura*5000)/1023.0);
   delay(11); //número primo para evitar ciclos de lectura proporcionales
 }

 return acc/NADJ;
}

void setup()
{  
 Serial.begin(9600); // 9600 bps
 pinMode(xaxis,INPUT);
 pinMode(yaxis,INPUT);
 pinMode(zaxis,INPUT);
 pinMode(LEDPIN, OUTPUT);

 digitalWrite(LEDPIN, HIGH);
 XError =  AccelAdjust(xaxis);
 YError =  AccelAdjust(yaxis);
 ZError =  AccelAdjust(zaxis);
 ZError = ZError - ZOUT_1G;
 digitalWrite(LEDPIN, LOW);

#ifdef DEBUGMODE
 Serial.println("Ajustado acelerometro eje X");
 Serial.print("Error de X= ");
 Serial.println(XError);

 Serial.println("Ajustado acelerometro eje Y");
 Serial.print("Error de Y= ");
 Serial.println(YError);

 Serial.println("Ajustado acelerometro eje Z");
 Serial.print("Error de Z= ");
 Serial.println(ZError);
#endif  
}

void loop()
{
 x=analogRead(xaxis);
 y=analogRead(yaxis);
 z=analogRead(zaxis);

 float aax = (((x*5000.0)/1023.0)-XError)/RESOLUTION;
 float aay = (((y*5000.0)/1023.0)-YError)/RESOLUTION;
 float aaz = (((z*5000.0)/1023.0)-ZError)/RESOLUTION;

#ifdef DEBUGMODE
 Serial.print(aax);
 Serial.print(" ");
 Serial.print(aay);
 Serial.print(" ");          
 Serial.print(aaz);
 Serial.println();
#endif

 delay(500);
} 

Una vez ejecutado el programa podemos ver como se realiza un ajuste del error estando en reposo y se recogen valores del mismo.

Los ejes X e Y (los dos primeros valores) están próximos a cero y el eje Z debido a la gravedad está en torno a 1. En realidad la oscilación de valores es mucho mayor pero gracias al ajuste del principio podemos disponer de valores mucho más estables y fiables. Si movemos el acelerómetro veremos como la fuerza G se ve aplicada a cada uno de los ejes. A partir de estos valores podremos calcular por ejemplo los grados de inclinación y utilizar el acelerómetro como un inclinómetro pero eso en el siguiente post.

Utilidad de identificación de CPU de Intel

Los que trabajamos con muchos ordenadores solemos encontrarnos con la duda de que tipo de CPU tenemos en cada máquina y, por que hemos perdido el libro de instrucciones de la placa o no tenemos ganas de quitar el sistema de refrigeración del micro o nuestra bios no nos dá información detallada, nos quedamos con la duda que la mayoría de las veces se soluciona por medio de prueba y error y reinstalación del software.

En la mayoría de los casos y debido a que cada vez se está extendiendo más las solucionas de virtulización sobre escritorio nos gustaría por ejemplo saber si nuestro micro soporta VT o cuanta memoria caché dispone.

Para ello Intel dispone de una herramienta que en nuestro caso nos puede solucionar muchos problemas y además nos permite informarnos sobre detalles de nuestro micro.

La herramienta se llama "Intel® Processor Identification Utility" y se puede descargar desde aquí.

Una vez instalada podemos ver información sobre nuestra la frecuencia de funcionamiento actual de tu CPU y la memoria caché que dispone
Si dispones de tecnología VT, Hyper-Threading o si es de 64 bits, así como otras tecnologías  asociadas

 y el tipo, familia, modelo, versión, etc.... de tu microprocesador.

me acabo de dar cuenta que no dispongo de VT y ahora comprendo porque por más que lo intento no puedo virtualizar un MAC en mi pc con Virtualbox :-(

viernes, 4 de febrero de 2011

El acelerómetro MMA7260

¿Qué es un acelerómetro y para que sirve?, pues es un dispositivo electrónico que sirve para medir las aceleraciones en uno o varios ejes. Para mis primeras pruebas decidí adquirir el modelo MMA 7260 de Freescale Semiconductor que es ligero, barato (15€) y robusto y permite medir las aceleraciones en los tres ejes.

Las principales caracteristicas son:
  • Dispone de sensivilidad ajustable de 1,5G/2G/4G y 6G
  • Bajo consumo. En torno a 500µA
  • Modo de reposo con un consumo de 3µA
  • Alta sensibilidad (800 mV/g para 1,5G) 
  • Incluye filtros paso bajo ideal para no tener que añadir más hardware
Atención: su voltaje de operación es entre 2.2V y 3.6V, esto es importante si lo vamos a conectar al Arduino ya que podemos estar acostumbrados a conectar dispositivos y sensores que funcionan a 5V y podríamos freirlo.

El acelerómetro viene con una serie de cables para alimentarlo y para recoger las señales que serán un valor analógico en milivoltios para representar el valor de la aceleración.

En esta imagen se puede ver con detalle el significado de cada conector, el selector de la sensibilidad del acelerómetro y los tres ejes de medición X,Y y Z.

Para los más intrépidos os pongo aquí el datasheet

Para conectarlo al Arduino y así poder capturar la aceleración del dispositivo tenemos que primero, alimentarlo correctamente y luego conectar las señales procedentes del acelerómetro a entradas analógicas del Arduino.

Os recuerdo que la alimentación es de 3.3V y para ello conectamos cualquiera de los cables rojos y negro a la alimentación y masa respectivamente.

En la fotografía anterior puede verse el conexionado del cable de masa y tensión a los conectores correspondientes del Arduino. No me hartaré de repertirlo: 3.3V!!! lo digo por experiencia... :-(
La conexión de alimentación se puede conectar a cualquiera de los 3 mazos de cable que trae siempre respetando conectarlo al sitio adecuado.

A continuación, para conectar las señales de acelaración suministradas por el acelerómetro tendremos que usar las entradas analógicas que trae el Arduino. Para ello usamos el cable azul que viene del acelerómetro

en este caso usando un cable verde y lo conectamos a la entrada analógica A2
comprobamos que todo está correctamente conectado, conectamos el arduino al puerto usb para encenderlo y veremos que además de encenderse el Arduino se enciende un pequeño led rojo del acelerómetro
si queremos podemos conectar las otras dos señales de los dos ejes de aceleración que faltan (no es necesario conectar más cables de alimentación, sólo el cable azul del resto de mazo de cables)

y ya podemos proceder a realizar la lectura de las aceleraciones desde el Arduino... pero esto lo dejaré para más adelante.

jueves, 3 de febrero de 2011

Problemas con tablas marcadas como corruptas en MySQL

Una de las razones por las que migré en todos mis desarrollos a PostgreSQL ha sido la capacidad de soportar los cortes de corriente que hacen estragos en bases de datos MySQL. En alguno que otro sistema todavia conservo estas bases de datos y es muy común encontrar errores como:

Table 'xxx' is marked as crashed and should be repaired .....
 
para solucionarlo tan sólo debe realizarse la siguiente acción con un usuario con privilegios para gestionar la base de datos correspondiente

mysqlcheck -u root -p --auto-repair base_de_datos;

donde el usuario puede ser cualquier otro y el -p fuerza a la petición de la clave. En realidad este comando chequea y repara la base de datos y existen más opciones pero ya os dejo aquí el enlace a la documentación oficial.

Por desgracia he tenido que realizar este arreglo varias veces pero por suerte siempre me ha sacado del apuro.

Ante todo espero que no tengais que recurir a él ;-)

miércoles, 2 de febrero de 2011

Arduino - Primer contacto

Durante mucho tiempo llevo usando y aplicando el paradigma de fuentes abiertas (que no es lo mismo que software libre pero ya lo contaré en otra entrada) y cuando escuché que se estaba extendiendo hacia el mundo del hardware causó en mí una expectación y curiosidad de como podría ser esto posible.
Indagando un poco descubrí que existe una plataforma de desarrollo abierta denominada Arduino que pretende compartir desarrollos electrónicos entre todos y además es sencilla de usar y bastante efectiva. Lo primero que me llamó la atención fue pensar si su precio sería muy superior a lo que cuestan los puñados de bytes (sin entrar en el valor de su calidad, por supuesto) de un desarrollo software abierto y realmente me sorprendió. Con un precio de alrededor 20€ se puede disponer de un kit completo para pasar del mundo del soft al mundo del hard, o al menos, tender un puente entre ambos.

Aprovechando que en fechas señaladas cuando la gente se regala cosas yo puedo permitirme el lujo de orientar "mi regalo sorpresa" decidí que me regalasen uno de ellos. Debido a que la plataforma es abierta encontré multitud de sitios en Internet donde disponían de ellos y me decanté por una tienda simplemente por que me hicieron gracia sus ositos de colores de caramelo en su página web (alguien que se publicita con tan tierno reclamo no puede darte productos hardware que te amarguen demasiado, sobre todo si estas empezando).

Después de seleccionar el modelo básico y realizar el correspondiente desembolso forzoso tenía el paquete en casa en 24 horas. Lo primero que me sorprendió fue su diseño respecto la presentación que no hizo más que recordarme cierta empresa de Cupertino dedicada a la fruticultura pomácea mordisqueada.

Lo siguiente fue su tamaño. Yo me imaginaba una placa con multitud de microchips pero era todo lo contrario. 

El conector para el usb, el de la alimentación, las entradas/salidas analógicas y digitales y el procesador programable es lo que abarca la mayor parte del espacio de la placa que tiene una superficie total de tan sólo 6,9x5,3 cms.

Ahora toca conectarlo al ordenador por medio del cable usb, descargar el software y empezar a probarlo.