Mostrando entradas con la etiqueta Ethernet. Mostrar todas las entradas
Mostrando entradas con la etiqueta Ethernet. Mostrar todas las entradas

martes, 29 de julio de 2014

Censado de datos. Monitorea un ambiente.

Censado de datos. Monitorea un ambiente.

Categoría: 1. Programación y electrónica.

Este ejercicio es de utilidad para realizar un registro puntual o permanente de las condiciones de temperatura y luminosidad de un ambiente que se maneja automáticamente. De esta manera verificar que las condiciones que se programaron o se ajustaron en los equipos acondicionadores funcionan correctamente. Los datos se registran en un archivo de texto cada 10 minutos. También se despliegan en una pagina web muy simple que se refresca cada cinco segundos.

Una de las ventajas de este programa es que mientras estás visualizando la página web, los datos se refrescan cada 5 segundos (esto puede modificarse en el código) pero si cierras la página, el registro de datos continúa, refrescándose cada 60 segundos por default (también lo puedes programar con otra frecuencia).

El hardware para este ejercicio consiste en lo siguiente:
- Placa de desarrollo Arduino UNO R3.
- Shield Ethernet Arduino.
- Placa para prototipos.
- Tres termorresistencias (termistor) conectadas a GND con una resistencia de 10k_Ohm y calibradas.
- Una fotorresistencia de 2M_Ohm, conectada a GND con una resistencia de 10k_Ohm.
- Un led con resistencia de 1k_Ohm conectada a GND.
- Un buzzer.
- Fuente de alimentación 9Vcc.

En esta aplicación se combina el uso de las funciones de Ethernet y de la micro SD de Arduino Ethernet Shield. Se utilizaron como base los ejemplos DataLogger y WebServer que acompañan al IDE de Arduino. Además se trata de poner este equipo a trabajar de manera indepenciente. Es decir, no necesita estar conectado al puerto USB de la computadora, pero se pueden visualizar los datos en tiempo real en una computadora conectada a la misma red donde se conecta el servidor (Ethernet Shield).

De esta manera, no se depende del monitor serial para el despliegue de los datos censados ni se dedica una conexión USB para alimentar el circuito. 

Como aplicaciones para este sistema se sugiere el monitoreo de temperatura e iluminación durante un periodo de tiempo determinado, 24 a 48 h por ejemplo, y así detectar si la temperatura se mantiene dentro del rango deseado, o si se está fuera de las condiciones durante ciertas horas del día o la noche. También podemos calcular con cierta precisión la hora en que se encienden y apagan las luces. Esto puede ser útil si tenemos un sistema controlado automáticamente, pero queremos tener un registro de que esto está ocurriendo realmente. Podemos poner por ejemplo el caso en que una luminaria quede fuera de servicio. El equipo funciona correctamente, pero la iluminación no se encendió a la hora requerida. 

Esta aplicación se puede llevar a un invernadero donde las plantas necesitan un fotoperiodo mínimo para crecer o para no florear. Un laboratorio de cultivo de tejidos vegetales in vitro, donde se necesita exponer los cultivos a un fotoperiodo mínimo, normalmente 16 horas de iluminación por 8 horas de oscuridad. Una instalación donde se crían peces o aves y que requieren que la temperatura ambiente (aire o agua) estén siempre dentro de rango óptimo. 

En ambos casos, iluminación y temperatura, podemos agregar una alerta sonora cuando una de las condiciones salga de rango.

El sistema se puede manejar de manera permanente, teniendo cuidado de vaciar el archivo de destino cada semana o cada mes. Para no saturar la capacidad de la tarjeta de la memoria micro SD del Shield Arduino.

Este ejemplo se puede ampliar a otro tipo de mediciones, como pH, potencial redox, humedad relativa, presión atmosférica, concentración de CO (monóxido de carbono), entre otros. Contando con los sensores necesarios.

Así mismo es posible aumentar el número de sensores hasta 6 en el caso de ArduinoUNO. Si se trata de censar mayor número e variables se puede usar el Arduino Mega (16 entradas analógicas), que también es compatible con Ethernet Shield.


Gráfico 1. 

Los datos almacenados durante las 24h del día en un archivo de texto pueden procesarse con una hoja de cálculo (Microsoft Excel en este caso) para hacer un análisis visual de un gráfico. En él se puede distinguir claramente las horas de insolación y las horas de oscuridad. Para eso es necesario colocar la hora de inicio del censado, esto debe hacerse manualmente abriendo el archivo de texto y agregando la hora y fecha en el encabezado. En el editor de textos, menú [Editar] [Hora y fecha]. Es recomendable colocar en el encabezado del archivo de texto las ecuaciones de los sensores y la entrada analógica a la que se conectaron A0-A5 (para Arduino UNO).

Las temperaturas interior y en el sistema monitoreado (agua) se mantienen dentro de un rango estrecho, mientras que la temperatura exterior muestra una amplia variación, que durante el día se comporta de manera semejante a la intensidad luminosa (Ampliar el gráfico para ver detalles).

Los sensores de temperatura se encapsularon en un tubo de ensayo (vidrio) con bolitas de plomo unidas con silicón en el fondo (para evitar flotación). El tapón del tubo se selló con silicón para mantener siempre seco el termistor (Imagen 1).

Imagen 1.

La calibración de los termistores se hizo contra un termómetro de mercurio (Ver: calibración de un termistor). Colocando agua con hielo y tomando lecturas analógicas (0 - 1023) y de temperatura simultáneamente, hasta que el agua alcanza la temperatura ambiente. Otra serie de datos se toma en un vaso con agua caliente, hasta que se temperatura es la misma que el ambiente.

A continuación se muestra el código del programa (IDE Arduino).

/**********************************************
DataLogger_&_WebServer

Basado en:
DataLogger
 created  24 Nov 2010
 modified 9 Apr 2012
 by Tom Igoe

WebServer
 created 18 Dec 2009
 by David A. Mellis
 modified 9 Apr 2012
 by Tom Igoe

**********************************************/

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>

int buzzer = 6;
int redLed = 9;
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,1,177);  // 192.168.1.177
EthernetServer server(80);
const int chipSelect = 4;
float sensor[5];
long double tiempoActual,tiempoPrevio,tiempoPrevio2;
long double intervalo = 600000;  // 10 minutos
long double intervalo2 = 60000;  // 1 minuto

void setup() {
  Serial.begin(9600);
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());

  Serial.print("Inicializando SD card ...");
  pinMode(10,OUTPUT);
  if (!SD.begin(chipSelect))
  {
    Serial.println("Falla en tarjeta. Inserte tarjeta ...");
    return;
  }
  Serial.println("Se inicalizo tarjeta SD ...");

  pinMode(buzzer,OUTPUT);
  pinMode(redLed,OUTPUT);
}


void loop() {
  tiempoActual=millis();
  EthernetClient client = server.available();

  if (client)
  {
    digitalWrite(redLed,HIGH);
    refreshWebServer();
    digitalWrite(redLed,LOW);
  }

  else
  {
    if (tiempoActual - tiempoPrevio2 > intervalo2)
    {
      digitalWrite(redLed,HIGH);
      refreshOutWeb();
      tiempoPrevio2 = millis();
      digitalWrite(redLed,LOW);
    }
  }

  if (tiempoActual - tiempoPrevio > intervalo)
  {
    digitalWrite(buzzer,HIGH);
    digitalWrite(redLed,HIGH);
    escribeArchivo();
    tiempoPrevio=millis();
    digitalWrite(buzzer,LOW);
    digitalWrite(redLed,LOW);
  }
}

/*********************        *********************/

void escribeArchivo()
{
  String dataString = "";
  int dato;  // Solo acepta int en la funcion String(dato);
  int tiempo = tiempoActual/60000;

  dataString += "\n";
  dataString += String(tiempo);
  dataString += "\t";

  for (int analogPin = 0; analogPin < 4; analogPin++)
  {
    dato = sensor[analogPin];
    dataString += String(dato);
    dataString += "\t";
  }

  File dataFile = SD.open("datalog.txt", FILE_WRITE);
  if (dataFile)
  {
    dataFile.println(dataString);
    dataFile.close();
    Serial.println(dataString);
  }
  else {
    Serial.println("error opening datalog.txt");
  }
}


/*******************         **********************/

void refreshWebServer()
{
  EthernetClient client = server.available();

    digitalWrite(redLed,HIGH);
 
    Serial.println("new client");
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        if (c == '\n' && currentLineIsBlank) {
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");
 client.println("Refresh: 5");
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          for (int analogChannel = 0; analogChannel < 4; analogChannel++) {
            float sensorReading = analogRead(analogChannel);
            client.print("analog input ");
            client.print(analogChannel);
            client.print(" is \t");
            if (analogChannel == 0)
            {
              client.print("Interior ");
              sensorReading = 0.1591*sensorReading - 56.113;
              sensor[analogChannel]=sensorReading;
              client.print(sensorReading);
              client.print(" Celsius degree.");
            }
            if (analogChannel == 1)
            {
              client.print("Exterior ");
              sensorReading = 0.1116*sensorReading - 35.358;
              sensor[analogChannel]=sensorReading;
              client.print(sensorReading);
              client.print(" Celsius degree.");
            }
            if (analogChannel == 2)
            {
              client.print("Sistema ");
              sensorReading = 0.13318*sensorReading - 43.9853;
              sensor[analogChannel]=sensorReading;
              client.print(sensorReading);
              client.print(" Celsius degree.");
            }
            if (analogChannel == 3)
            {
              client.print("Iluminacion ");
              sensor[analogChannel]=sensorReading;
              client.print(sensorReading);
              client.print(" Digital value (0-1023).");
            }
            else
            {
              client.println(" ");
            }
            client.println("<br />");    
          }
          client.println("</html>");
          break;
        }
        if (c == '\n') {
         currentLineIsBlank = true;
        }
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    delay(1);
    client.stop();
    Serial.println("client disonnected");
 
    digitalWrite(redLed,LOW);
}


/*******************        ***********************/

void refreshOutWeb()
{
          for (int analogChannel = 0; analogChannel < 4; analogChannel++)
          {
            float sensorReading = analogRead(analogChannel);
            if (analogChannel == 0)
            {
              sensorReading = 0.1591*sensorReading - 56.113;
              sensor[analogChannel]=sensorReading;
            }
            if (analogChannel == 1)
            {
              sensorReading = 0.1116*sensorReading - 35.358;
              sensor[analogChannel]=sensorReading;
            }
            if (analogChannel == 2)
            {
              sensorReading = 0.13318*sensorReading - 43.9853;
              sensor[analogChannel]=sensorReading;
            }
            if (analogChannel == 3)
            {
              sensor[analogChannel]=sensorReading;
            }
            else
            {
            }
          }
}

Los datos de calibración de los termómetros se graficaron en Excel y se ajustaron a una recta por el método de regresión por mínimos cuadrados. Las ecuaciones obtenidas son las siguientes:

Termometro1. Temperatura interior:              y=0.1591*x-56.113               Pin: A0
Termometro2. Temperatura exterior:             y=0.1116*x-35.358               Pin: A1
Termometro3. Temperatura del sistema:        y=0.13318*x-43.9853           Pin: A2

La fotorresistencia no se calibró. Para este dispositivo se registran los valores digitales leídos por el convertidor analógico digital (valores de 0 a 1023).

Figura 2.

Para poder visualizar los datos censados, se abre una ventana en el explorador y en la barra de direcciones se escribe la dirección IP que se utiliizó en el código del programa. Los valores se refrescan cada 5 segundos, lo cual es adecuado, ya que por ser una página web tan sencilla casi no consume recursos de la computadora en que se despliegan.

El valor de tiempo registrado en el archivo de texto está en minutos. Para poderlo manejar en Excel se recomienda convertir los datos de esa columna a valores de hora (00:00 a 23:59). Esto se hace fácilmente con la función TIEMPO(hora,minuto,segundo). Como el dato está en minutos, se colocan ceros en hora y segundo, en el atributo minuto se escribe la dirección de la celda que se va a convertir). En la primer celda de la siguiente columna se coloca la hora de inicio y a partir de la segunda se coloca una fórmula que suma esa primera celda (fija, como en $C$7+B8).

En el siguiente enlace puedes encontrar un proyecto para la construcción de un medidor de pulso utilizando optoelectrónica.

Dispositivos electrónicos programables como el que se utilizó en este ejemplo, pueden servir para la automatización de otras aplicaciones. En este enlace puedes ver unas notas sobre automatización de un invernadero. O en forma de presentación (automatización de un invernadero).






jueves, 6 de septiembre de 2012

Manejo de la micro SD del Shield Ethernet

Manejo de la micro SD del Shield Ethernet.

Categoría: 1. Programación y electrónica.

Se desarrolló un programa (C/C++) para tener juntas algunas instrucciones útiles en el manejo de los archivos contenidos en la tarjeta micro SD del Shield Ethernet de Arduino. Con base en algunos programas de ejemplo como dumpFile, cardInfo y readWrite se desarrolló un menú y las acciones leerArchivo, leerMicroSD y borrarArchivo se programaron como funciones. El monitor serial despliega el menú de opciones y el usuario introduce a través del mismo monitor serial la opción que desea que el programa ejecute. Se verificó cada una de las tres opciones del menú por separado, una vez que crrieron correctamente al cargarlas en la tarjeta Arduino se procedió a colocarlas en un programa único una a una, y teniendo cuidado de no sobrepasar el límite de almacenamiento de la tarjeta (32256 bytes). Para terminar, se verificó el programa completo (16598 bytes) y se cargó en la tarjeta electrónica.

El código es el siguiente:

#include <SD.h>
Sd2Card card;
SdVolume volume;
SdFile root;
const int chipSelect = 4;
void setup ()  {
  Serial.begin(9600);
  pinMode(10, OUTPUT);
  Serial.println("enter:\n 1. cardInfo\n 2. leerArchivo\n 3. borrarArchivo\n 0. Salir ");  }
 
void loop()  {
  if (Serial.available() > 0)  {
    char ch = Serial.read();
    if (ch == '1')  {
       cardInfo(); }
    else if (ch == '2')  {
       leerArchivo(); }
    else if (ch == '3')  {
       borrarArchivo();  }
    else if (ch == '4')  {  }
    else if (ch == '0')  {  }  }  }

void cardInfo ()  {
  Serial.print("\ninitializing SD card... ");
  if (!card.init(SPI_HALF_SPEED, chipSelect)) {
    Serial.println("initialization failed. Things to check:");
    Serial.println("* is a card is inserted?");
    Serial.println("* Is your wiring correct?");
    Serial.println("* did you change the chipSelect pin to match your shield or module?");
    return;  }
    else {
   Serial.println("Wiring is correct and a card is present.");  }
  Serial.print("\nCard type: ");
  switch(card.type()) {
    case SD_CARD_TYPE_SD1:
      Serial.println("SD1");
      break;
    case SD_CARD_TYPE_SD2:
      Serial.println("SD2");
      break;
    case SD_CARD_TYPE_SDHC:
      Serial.println("SDHC");
      break;
    default:
      Serial.println("Unknown");  }
  if (!volume.init(card)) {
    Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
    return;  }
  uint32_t volumesize;
  Serial.print("\nVolume type is FAT");
  Serial.println(volume.fatType(), DEC);
  Serial.println();
 
  volumesize = volume.blocksPerCluster();   
  volumesize *= volume.clusterCount();      
  volumesize *= 512;                        
  Serial.print("Volume size (bytes): ");
  Serial.println(volumesize);
  Serial.print("Volume size (Kbytes): ");
  volumesize /= 1024;
  Serial.println(volumesize);
  Serial.print("Volume size (Mbytes): ");
  volumesize /= 1024;
  Serial.println(volumesize);
 
  Serial.println("\nFiles found on the card (name, date and size in bytes): ");
  root.openRoot(volume);
 
  root.ls(LS_R | LS_DATE | LS_SIZE);  }


void borrarArchivo ()  {
  Serial.print("Initializing SD card...");
  if (!SD.begin(chipSelect))  {
    Serial.println("initialization failed!...");
    return;  }
  Serial.println("initialization done!...");
 
  if (SD.exists("pulsedat.txt"))  {
    Serial.println("pulsedat.txt exists...");  }
  else  {
    Serial.println("pulsedat.txt doesn't exist...");  }
  Serial.println("removing pulsedat.txt...");
  SD.remove("pulsedat.txt");
 
  if (SD.exists("pulsedat.txt"))  {
    Serial.println("pulsedat.txt exists...");  }
  else  {
    Serial.println("pulsedat.txt doesn't exist..");  }  }


void leerArchivo ()  {
  Serial.print("Initializing SD card...");
    if (!SD.begin(chipSelect))  {
      Serial.println("initialization failed!...");
      return;  }
  Serial.println("initialization done!...");
 
  File dataFile = SD.open("pulsedat.txt", FILE_READ);
  if (dataFile)  {
    Serial.println("pulsedat.txt exists...");
    while (dataFile.available())  {
      Serial.write(dataFile.read());  }
      dataFile.close();  }
  else  {
    Serial.println("error opening pulsedat.txt...");  }  }
     
De esta manera, se puede trabajar de manera más amigable con el programa presentado anteriormente como EjercicioPulseDat04 para el registro de pulsaciones generadas por un multivibrador astable construido con un circuito integrado NE555 (o NE556).

Es todo por ahora. Saludos.

La bibliografía contenida en la entrada 'registro de datos a una micro SD' también aplica para esta entrada, y es la siguiente:
Bibliografía.

Stengel, Lester. 2006. El ABC de la electrónica. Steren Electrónica SA de CV. México.
Arduino. Sitio web: http://www.arduino.cc/. Consulta el 31 de julio de 2012.







sábado, 1 de septiembre de 2012

Registro de datos a una micro SD

Registro de un generador de pulsos a un archivo de texto (pulsedat.txt).

Categoría: 1. Programación y electrónica.

El programa generador de pulsos funciona registrando los momentos en que un generador de pulsos, un botón pulsador conectado a una resistencia de 10K o, como en este ejercicio, un circuito electrónico generador de pulsos. Este circuito está basado en un circuito integrado NE555 o NE556.

El circuito astable es como sigue:



El programa EjercicioPulseDat04 lee la salida digital del vibrador astable (pin 3 en el NE555 o pines 5 o 9 del NE556), registra en el monitor serial los tiempos de encendido (HIGH) y de apagado (LOW) utilizando la instrucción millis(); y también registra el número de pulsos acumulado. De esta manera es posible medir el tiempo de duración en HIGH y el tiempo de duración en LOW.
Estos mismos datos se registran en un archivo llamado pulsedat.txt, almacenado en la tarjeta de datos micro SD contenida en el Shield Ethernet de Arduino. Como se sabe, esta tarjeta va acoplada con la tarjeta electrónica Arduino UNO.

Las siguientes imágenes muestran la salida en el monitor serial y la ventana del ambiente Arduino con parte del programa a la vista.





El programa se desarrolló tomando como base el ejemplo 'state change detection' (edge detection) que proorciona el ambiente Arduino para la tarjeta electrónica Arduino UNO. También se utilizó parte del código del ejemplo 'datalogger' para la tarjeta Ethernet Shield.

/*
EjercicioPulseDat04
*/
/*
  State change detection (edge detection)

 Often, you don't need to know the state of a digital input all the time,
 but you just need to know when the input changes from one state to another.
 For example, you want to know when a button goes from OFF to ON.  This is called
 state change detection, or edge detection.

 This example shows how to detect when a button or button changes from off to on
 and on to off.

 The circuit:
 * pushbutton attached to pin 2 from +5V
 * 10K resistor attached to pin 2 from ground
 * LED attached from pin 13 to ground (or use the built-in LED on
   most Arduino boards)

 created  27 Sep 2005
 modified 30 Aug 2011
 by Tom Igoe
This example code is in the public domain.

 http://arduino.cc/en/Tutorial/ButtonStateChange

 */
#include <SD.h>
const int  buttonPin = 2;   
const int ledPin = 13;      
int buttonPushCounter = 0; 
int buttonState = 0;       
int lastButtonState = 0; 
File dataFile;
void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
  pinMode(10, OUTPUT);
 
    if (!SD.begin(4))  {
    Serial.println("card failed, or not present...");
    return;  }
  Serial.println("card initialized...");
 
  Serial.println("removing pulsedat.txt...");
  SD.remove("pulsedat.txt");
  if (SD.exists("pulsedat.txt"))  {
    Serial.println("pulsedat.txt exists...");  }
  else  {
    Serial.println("pulsedat.txt doesn't exist...");  }  }

void loop()
{
  buttonState = digitalRead(buttonPin);
  if (buttonState != lastButtonState)
  {
    if (buttonState == HIGH)
    {
      buttonPushCounter++;
      Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter);
      Serial.print("time on= ");
      Serial.println(millis());
 
  dataFile = SD.open("pulsedat.txt", FILE_WRITE);
  if (dataFile) 
      {
    Serial.println("writing to pulsedat.txt...");
    dataFile.print("number of button pushes:  ");
    dataFile.println(buttonPushCounter);
    dataFile.print("time on= ");
    dataFile.println(millis());   
    dataFile.close();
    Serial.println("action done..."); 
      }
  else 
      {
    Serial.println("error opening pulsedat.txt"); 
      }   
    }
 
   
    else
      {
      Serial.print("time off= ");
      Serial.println(millis());
     
  dataFile = SD.open("pulsedat.txt", FILE_WRITE);
  if (dataFile) 
        {
    Serial.println("writing to pulsedat.txt...");
    dataFile.print("time off= ");
    dataFile.println(millis());
   
    dataFile.close();
    Serial.println("action done..."); 
        }
  else 
        {
    Serial.println("error opening pulsedat.txt"); 
        }
      }
 
  lastButtonState = buttonState;
  if (buttonPushCounter % 4 == 0)
      {
    digitalWrite(ledPin, HIGH);
      }
  else
      {
   digitalWrite(ledPin, LOW);
      }
  }
}
Este programa con algunas modificaciones puede adaptarse para medir variables de uno o más sensores (temperatura, humedad, presión atmosférica, intensidad lumínica, voltaje, etc) conectados a las entradas analógicas de la tarjeta electrónica.

Por lo pronto es todo. Saludos.

Bibliografía.

Stengel, Lester. 2006. El ABC de la electrónica. Steren Electrónica SA de CV. México.
Arduino. Sitio web: http://www.arduino.cc/. Consulta el 31 de julio de 2012.