Si aún no eres usuario, puedes crear una cuenta o entrar
Sistema de medición inercial con Arduino y Processing

Os dejo por aqui una interesante implementación de un acelerómetro y un giroscopio utilizados como sistema de medición inercial con Arduino. El sistema es muy sencillo y no necesita de ningún componente extra más que un acelerómetro ADXL y un giroscopio IDG300. Para visualizar los datos, se utiliza un pequeño programa realizado en Processing, el cual muestra las curvas de los 3 ejes del acelerómetro y los valores de cada eje del giroscopio unas 100 veces por segundo.

Os dejo a continuación una pequeña explicación del montaje, el código fuente y un video que muestra el conjunto funcionando.





Sistema de medición inercial

Wikipedia:

En mecánica, un sistema de referencia inercial es un sistema de referencia en el que las leyes del movimiento cumplen la conservación del momento lineal. El término aparece principalmente en mecánica newtoniana donde los sistemas inerciales son precisamente aquellos en los que se cumplen las leyes de Newton.

El sistema es realmente muy sencillo y salvo una placa Arduino y un conjunto de acelerómetro y giroscopio, no se necesita nada más. aunque se podrían haber usado los componentes por separado, el autor ha preferido utilizar un módulo IMU fabricado por Sparkfun dado que incorpora los dos componentes en una sola placa, la cual podemos ver en la imagen.

Aunque existen sistemas más complejos (y completos), éste es una buena forma de realizar las primeras pruebas de forma rápida y sencilla dado que ofrece una sensibilidad no despreciable y además podemos visualizar los datos directamente desde nuestro ordenador.

El código fuente

Tanto el acelerómetro como el girocópio devuelve valores analógicos para cada uno de sus ejes. Ésto hace que conectarlo con nuestra placa Arduino sea muy fácil ya que disponemos de varias entradas ADC para medir valores analógicos. Tras iniciar una comunicación série a 115kbps, se leen los valores y se envian por el puerto série 100 veces por segundo. El código fuente para Arduino sería éste:

// Maurice Ribble 
// 6-28-2009
// http://www.glacialwanderer.com/hobbyrobotics

// This app just probes two external sensors (ADXL330 and IDG300) and 
// then sends that data over a serial connection.  I used a sparkfun
// breakout board to make using these chips easier.
// http://www.sparkfun.com/commerce/product_info.php?products_id=741

// I wrote a processing.org app that reads in this data and graphs it
// on a pc.

#define X_ACCEL_APIN 0
#define Y_ACCEL_APIN 1
#define Z_ACCEL_APIN 2
#define V_REF_APIN   3
#define Y_RATE_APIN  4
#define X_RATE_APIN  5

void setup()
{
  Serial.begin(115200);
}

// If this is defined it prints out the FPS that we can send a
// complete set of data over the serial port.
//#define CHECK_FPS

void loop()
{
  int xAccel=0, yAccel=0, zAccel=0, vRef=0, xRate=0, yRate=0;
  unsigned int startTag = 0xDEAD;  // Analog port maxes at 1023 so this is a safe termination value
  int loopCount;

#ifdef CHECK_FPS  
  unsigned long startTime, endTime;
  startTime = millis();
#endif
  
  // Can't do more than 64 loops or could overflow the 16 bit ints
  // This just averages together as many sensor reads as we can in
  // order to reduce sensor noise.  Might want to introduce add
  // a smarter filter her in the future.
  loopCount = 12;  // 12 gives a little over 100 FPS
  for(int i = 0; i< loopCount; ++i)
  {
    // It takes 100 us (0.0001 s) to read an analog input
    xAccel += analogRead(X_ACCEL_APIN);
    yAccel += analogRead(Y_ACCEL_APIN);
    zAccel += analogRead(Z_ACCEL_APIN);
    vRef   += analogRead(V_REF_APIN);
    xRate  += analogRead(X_RATE_APIN);
    yRate  += analogRead(Y_RATE_APIN);
  }
  xAccel /= loopCount;
  yAccel /= loopCount;
  zAccel /= loopCount;
  vRef   /= loopCount;
  xRate  /= loopCount;
  yRate  /= loopCount;

  Serial.write( (unsigned byte*)&startTag, 2);
  Serial.write((unsigned byte*)&xAccel, 2);
  Serial.write((unsigned byte*)&yAccel, 2);
  Serial.write((unsigned byte*)&zAccel, 2);
  Serial.write((unsigned byte*)&vRef, 2);
  Serial.write((unsigned byte*)&xRate, 2);
  Serial.write((unsigned byte*)&yRate, 2);
  
#ifdef CHECK_FPS  
  endTime = millis();
  Serial.print(" - FPS: ");
  Serial.println(1.f / (endTime-startTime) * 1000);
#endif
}

Visualizando los datos con Processing

Una vez que tenemos todos los datos listo para ser evaluados, tenemos una pequeña ventana creada utilizando Processing para visualizar los datos en tiempo real.

Es una aplicación muy sencilla que recoge los datos enviados por arduino con diferentes colores y los muestra haciendo un scroll lateral. El código de processing es el siguiente:

// Maurice Ribble 
// 6-28-2009
// http://www.glacialwanderer.com/hobbyrobotics

// This takes data off the serial port and graphs it.
// There is an option to log this data to a file.

// I wrote an arduino app that sends data in the format expected by this app.
// The arduino app sends accelerometer and gyroscope data.

import processing.serial.*;

// Globals
int g_winW             = 820;   // Window Width
int g_winH             = 600;   // Window Height
boolean g_dumpToFile   = true;  // Dumps data to c:output.txt in a comma seperated format (easy to import into Excel)
boolean g_enableFilter = true;  // Enables simple filter to help smooth out data.

cDataArray g_xAccel    = new cDataArray(200);
cDataArray g_yAccel    = new cDataArray(200);
cDataArray g_zAccel    = new cDataArray(200);
cDataArray g_vRef      = new cDataArray(200);
cDataArray g_xRate     = new cDataArray(200);
cDataArray g_yRate     = new cDataArray(200);
cGraph g_graph         = new cGraph(10, 190, 800, 400);
Serial g_serial;
PFont  g_font;

void setup()
{
  size(g_winW, g_winH, P2D);

  println(Serial.list());
  g_serial = new Serial(this, Serial.list()[1], 115200, 'N', 8, 1.0);
  g_font = loadFont("ArialMT-20.vlw");
  textFont(g_font, 20);
  
  // This draws the graph key info
  strokeWeight(1.5);
  stroke(255, 0, 0);     line(20, 420, 35, 420);
  stroke(0, 255, 0);     line(20, 440, 35, 440);
  stroke(0, 0, 255);     line(20, 460, 35, 460);
  stroke(255, 255, 0);   line(20, 480, 35, 480);
  stroke(255, 0, 255);   line(20, 500, 35, 500);
  stroke(0, 255, 255);   line(20, 520, 35, 520);
  fill(0, 0, 0);
  text("xAccel", 40, 430);
  text("yAccel", 40, 450);
  text("zAccel", 40, 470);
  text("vRef", 40, 490);
  text("xRate", 40, 510);
  text("yRate", 40, 530);
  
  if (g_dumpToFile)
  {
    // This clears deletes the old file each time the app restarts
    byte[] tmpChars = {'r', 'n'};
    saveBytes("c:output.txt", tmpChars);
  }
}

void draw()
{
  // We need to read in all the avilable data so graphing doesn't lag behind
  while (g_serial.available() >= 2*6+2)
  {
    processSerialData();
  }

  strokeWeight(1);
  fill(255, 255, 255);
  g_graph.drawGraphBox();
  
  strokeWeight(1.5);
  stroke(255, 0, 0);
  g_graph.drawLine(g_xAccel, 0, 1024);
  stroke(0, 255, 0);
  g_graph.drawLine(g_yAccel, 0, 1024);
  stroke(0, 0, 255);
  g_graph.drawLine(g_zAccel, 0, 1024);
  stroke(255, 255, 0);
  g_graph.drawLine(g_vRef, 0, 1024);
  stroke(255, 0, 255);
  g_graph.drawLine(g_xRate, 0, 1024);
  stroke(0, 255, 255);
  g_graph.drawLine(g_yRate, 0, 1024);
}

// This reads in one set of the data from the serial port
void processSerialData()
{
  int inByte = 0;
  int curMatchPos = 0;
  int[] intBuf = new int[2];

  intBuf[0] = 0xAD;
  intBuf[1] = 0xDE;
  
  while (g_serial.available() < 2); // Loop until we have enough bytes
  inByte = g_serial.read();
  
  // This while look looks for two bytes sent by the client 0xDEAD
  // This allows us to resync the server and client if they ever
  // loose sync.  In my testing I haven't seen them loose sync so
  // this could be removed if you need to, but it is a good way to
  // prevent catastrophic failure.
  while(curMatchPos < 2)
  {
    if (inByte == intBuf[curMatchPos])
    {
      ++curMatchPos;
      
      if (curMatchPos == 2)
        break;
    
      while (g_serial.available() < 2); // Loop until we have enough bytes
      inByte = g_serial.read();
    }
    else
    {
      if (curMatchPos == 0)
      {
        while (g_serial.available() < 2); // Loop until we have enough bytes
        inByte = g_serial.read();
      }
      else
      {
        curMatchPos = 0;
      }
    }
  }
  
  while (g_serial.available() < 2*6);  // Loop until we have a full set of data

  // This reads in one set of data
  {
    byte[] inBuf = new byte[2];
    int xAccel, yAccel, zAccel, vRef, xRate, yRate;
  
    g_serial.readBytes(inBuf);
    // Had to do some type conversion since Java doesn't support unsigned bytes
    xAccel = ((int)(inBuf[1]&0xFF) << 8) + ((int)(inBuf[0]&0xFF) << 0);
    g_serial.readBytes(inBuf);
    yAccel = ((int)(inBuf[1]&0xFF) << 8) + ((int)(inBuf[0]&0xFF) << 0);
    g_serial.readBytes(inBuf);
    zAccel = ((int)(inBuf[1]&0xFF) << 8) + ((int)(inBuf[0]&0xFF) << 0);
    g_serial.readBytes(inBuf);
    vRef   = ((int)(inBuf[1]&0xFF) << 8) + ((int)(inBuf[0]&0xFF) << 0);
    g_serial.readBytes(inBuf);
    xRate  = ((int)(inBuf[1]&0xFF) << 8) + ((int)(inBuf[0]&0xFF) << 0);
    g_serial.readBytes(inBuf);
    yRate  = ((int)(inBuf[1]&0xFF) << 8) + ((int)(inBuf[0]&0xFF) << 0);
    
    g_xAccel.addVal(xAccel);
    g_yAccel.addVal(yAccel);
    g_zAccel.addVal(zAccel);
    g_vRef.addVal(vRef);
    g_xRate.addVal(xRate);
    g_yRate.addVal(yRate);

    if (g_dumpToFile)  // Dump data to a file if needed
    {
      String tempStr;
      tempStr = xAccel + "," + yAccel + "," + zAccel + "," + vRef + "," + xRate + "," + yRate + "rn";
      FileWriter file;

      try  
      {  
        file = new FileWriter("c:output.txt", true); //bool tells to append
        file.write(tempStr, 0, tempStr.length()); //(string, start char, end char)
        file.close();
      }  
      catch(Exception e)  
      {  
        println("Error: Can't open file!");
      }
    }

    /*
    print(xAccel);  print(" ");   print(yAccel);   print(" ");    print(zAccel);     print(" ");
    print(vRef);    print(" ");   print(xRate);    print(" ");    println(yRate);
    */
  }
}

// This class helps mangage the arrays of data I need to keep around for graphing.
class cDataArray
{
  float[] m_data;
  int m_maxSize;
  int m_startIndex = 0;
  int m_endIndex = 0;
  int m_curSize;
  
  cDataArray(int maxSize)
  {
    m_maxSize = maxSize;
    m_data = new float[maxSize];
  }
  
  void addVal(float val)
  {
    
    if (g_enableFilter && (m_curSize != 0))
    {
      int indx;
      
      if (m_endIndex == 0)
        indx = m_maxSize-1;
      else
        indx = m_endIndex - 1;
      
      m_data[m_endIndex] = getVal(indx)*.5 + val*.5;
    }
    else
    {
      m_data[m_endIndex] = val;
    }
    
    m_endIndex = (m_endIndex+1)%m_maxSize;
    if (m_curSize == m_maxSize)
    {
      m_startIndex = (m_startIndex+1)%m_maxSize;
    }
    else
    {
      m_curSize++;
    }
  }
  
  float getVal(int index)
  {
    return m_data[(m_startIndex+index)%m_maxSize];
  }
  
  int getCurSize()
  {
    return m_curSize;
  }
  
  int getMaxSize()
  {
    return m_maxSize;
  }
}

// This class takes the data and helps graph it
class cGraph
{
  float m_gWidth, m_gHeight;
  float m_gLeft, m_gBottom, m_gRight, m_gTop;
  
  cGraph(float x, float y, float w, float h)
  {
    m_gWidth     = w;
    m_gHeight    = h;
    m_gLeft      = x;
    m_gBottom    = g_winH - y;
    m_gRight     = x + w;
    m_gTop       = g_winH - y - h;
  }
  
  void drawGraphBox()
  {
    stroke(0, 0, 0);
    rectMode(CORNERS);
    rect(m_gLeft, m_gBottom, m_gRight, m_gTop);
  }
  
  void drawLine(cDataArray data, float minRange, float maxRange)
  {
    float graphMultX = m_gWidth/data.getMaxSize();
    float graphMultY = m_gHeight/(maxRange-minRange);
    
    for(int i=0; i

El código fuente también se puede descargar en formato zip aqui. Y como no podía ser de otra forma, aqui teneis un video del montage funcionando:

Artículo original escrito por Maurice Ribble. Enlace aqui.


Comparte esto con tus amigos!

Si te ha gustado, quizás también te interese...
Horno de Reflow casero con Arduino
Publicado el 17/01/2014

Comentarios:


fabian wallingre
Enviado el 03/10/2011 (17:11)
Hola! conecte todo pero no puedo hacer funcionar el programita en processing, me dice (The size of this applet could not automatically be determinated from your code. Use only numeric values (Not Variables)). Necesito ayuda. GRACIAS


Enviar comentario

Debes disponer de una cuenta de usuario para publicar un comentario.

Si aún no dispones de una cuenta, únete a la comunidad de BricoGeek.com y registrate ahora, te llevará tan solo un minuto y es gratis. También puedes identificate si ya dispones de una cuenta de usuario.
rss

Conecta con BricoGeek.com

Canales sociales

Nos gusta mucho estar en contacto con nuestros lectores y saber más acerca de sus proyecto e inventos.


También puedes sugerir una noticia en el blog
Tienda de Electrónica DIY y Arduino

Lo que se cuece...

Comentarios recientes Más comentado Top noticias
Feed de novedades

Tienda BricoGeek.com

Electrónica para tus proyectos!

Estás preparando un proyecto o quieres iniciarte en la electrónica? Encuentra todo lo que necesitas en la tienda.

Visita la tienda BricoGeek!

La familia de BricoGeek.com

Conoce toda la gente que hace que BricoGeek.com sea posible cada día:

Alejandro Mallo
Colaborador
Puedes hacer click sobre un autor para ver todas sus noticias


Etiquetas más populares:

Descubre todo el contenido de bricogeek.com con las etiquetas más populares:

Páginas amigas:

Aqui tienes una selección de las páginas que más nos gusta visitar


© BricoGeek.com 2005-2014

Demuestra lo que sabes hacer!