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

viernes, 14 de noviembre de 2014

Python para comunicación con Arduino.

Python para comunicación con Arduino.


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

Introducción.

Los microcontroladores son dispositivos electrónicos que permiten interactuar elementos electrónicos como sensores, interruptores, entradas y salidas analógicas y digitales y comunicarlos con un PC o con redes de datos como internet, bluetooth WiFi, entre otras. Esto los convierte en equipos muy versátiles para controlar equipos en respuesta a cambios registrados por sensores (retroalimentación o control de lazo cerrado) o bien para operar equipos a distancia.

Una aplicación de bastante utilidad es el censado de variables ambientales en sistemas naturales o en sistemas controlados para registrar el estado real del sistema durante todo el tiempo de operación. No importa si es de día o de noche, el censado se realiza conforme a la frecuencia programada. El resultado puede ser un registro de datos que se puede analizar en tiempo real, o bien, utilizarse para un análisis posterior, o ambas cosas. El sistema permite además controlar equipos en respuesta a cambios ambientales. Desde encender una lámpara cuando la intensidad lumínica baja de un valor establecido o encender un sistema de enfriamiento cuando la temperatura se eleva por encima del límite máximo, hasta controlar el vuelo de un dron equipado con GPS siguiendo un itinerario previamente establecido y registrando variables ambientales de interés o registrando imágenes en archivos electrónicos.

En este blog he publicado otras entradas sobre proyectos con la tarjeta electrónica Arduino. Accede AQUÍ.

Desarrollo del proyecto.

En este ejercicio se utiliza un programa en Python para abrir un puerto de comunicación serial. A través de este puerto se recibe una linea de datos generada por una tarjeta electrónica Arduino, que tiene un sensor de temperatura LM35. El dato se guarda en un archivo de texto, junto con la fecha y la hora en que fue realizada la lectura. 

# Abre un puerto de comunicacion con Arduino. Continuo.
from time import sleep
from time import strftime
import serial
serialPort=3
baudRate=115200
storeFile='E:/ArduinoDataFile.txt'
arduino=serial.Serial(serialPort,baudRate)
if (arduino.isOpen()):
        print "Arduino is available ..."
  arduino.close()
if (~arduino.isOpen()):
  arduino.open()
  print "Arduino is open ..."
  while (arduino.isOpen()):
                hora=strftime("%H:%M:%S")
  fecha=strftime("%Y-%m-%d")
  arduino.flush()
  print fecha,"\t",hora,"\t",arduino.readline()
  f=open(storeFile,'a')
  f.write(str(fecha)+"\t"+str(hora)+"\t"+str(arduino.readline()))
  f.close()
  sleep(2.0)
raw_input()  # Esta linea de codigo para archivo.py.


El programa se hizo para Python 2.7 y se instaló la librería PySerial para poder establecer la comunicación a través del puerto serie. También se utiliza la librería time para obtener la fecha y la hora del sistema.

En la consola de salida se despliega el valore de la temperatura junto con la fecha y la hora en que se realizó la lectura (Figura 1). La lectura se repite cada 2.0 segundos, dejando un tiempo de espera con la instrucción sleep().

El sensor de temperatura se instaló en una tarjeta electrónica ArduinoUNO, en la entrada digital A1. El código que se cargó en el microcontrolador es el siguiente:

void setup()
{
  Serial.begin(115200);
}
void loop()
{
  Serial.print(tempSensor());
  Serial.print("\t");
  Serial.println(analogRead(A0));
  delay(1000);
}

float tempSensor()
{
    analogReference(INTERNAL);
    int sens;
    for (int k=0; k<10;k++)  /* Lecturas mientras estabiliza despues de analogReference. */
    {
        sens=analogRead(A1);
        delay(5);
    }
    float temp=sens/9.31;
    analogReference(DEFAULT);
    return temp;
}

Para tomar la lectura del sensor analógico de temperatura se utilizó un ciclo for con 10 iteraciones. Esto con el fin de estabilizar la lectura y obtener un dato preciso. Normalmente las primeras dos o tres lecturas del LM35 después de cambiar la referencia de voltaje analógico con la instrucción analogReference(), se obtienen lecturas bastante alejadas del valor real.

Figura 1. Salida en Python de la función que abre el puerto serial, obtiene la lectura de temperatura y lo guarda en un archivo de texto.


Figura 2. Salida de Python a un archivo de texto donde se guarda el valor de temperatura (°C) junto con la fecha y la hora en que se realizó la lectura.


Para obtener lecturas de manera ininterrumpida, debe sustituirse la linea de código - while (k<25) - por la linea - while (arduino.isOpen()) -. Para detener la lectura simplemente se cierra la ventana de salida de Python.



Bibliografía

Arduino: www.arduino.cc/

Python 2.7: https://www.python.org/download/releases/2.7/



viernes, 10 de octubre de 2014

Datalogger y dado electrónico con Arduino.

Data-logger y dado electrónico con Arduino.


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

Las placas electrónicas de desarrollo están entrando al mercado ofreciendo cada vez más aplicaciones, para varios sectores de interés, desde los hobbystas, los aficionados a las transformaciones automotrices, los desarrolladores de robots en aplicaciones a pequeña y mediana escala, hasta los trabajos más formales de ingeniería, o en el diseño de experimentos. Aplicaciones interesantes se desarrollan para controlar sistemas a escala en laboratorio así como en el censado automático de algunas variables dentro de esos mismos sistemas. En las aplicaciones más formales es posible diseñar el hardware, escribir el código necesario e integrarlo en un sistema embebido que contiene por así decirlo, trabajo previamente hecho de manera que el proyecto final involucra menos esfuerzo de desarrollo en cuestiones básicas. Esto se cumple tanto en el hardware como en el software.

En esta ocasión se describen dos proyectos: 1) un sistema de censado de datos basado en una tarjeta de desarrollo Arduino UNO, un Shield MicroSD Sparkfun y un sensor de temperatura LM35; 2) un dado electrónico basado en una tarjeta de desarrollo Arduino UNO y un display de 7 segmentos.

En una entrada anterior había explicado un dado electrónico que hacía exactamente lo mismo que este nuevo proyecto. La diferencia notable está en el software, que esta vez está mejor presentado.

El código de los dos proyectos así como la descripción de los circuitos electrónicos periféricos la puedes ver en Programa 1 y Programa 2 abajo, en esta misma página.

Para ilustrar el uso de la función Random() en la generación de números aleatorios se escribió el código siguiente:

/************************************************
Random
************************************************/
void setup()
{
  Serial.begin(115200);
  pinMode(3,OUTPUT);
  randomSeed(analogRead(0));
}
void loop()
{
  float num = random(0,11.5);  // Para obtener un máximo de 0.6*11.5=6.9
  num *= 0.6;
  int dado = num;
  Serial.print("num = ");
  Serial.println(num);
  Serial.print("dado = ");
  Serial.println(dado);
  Serial.println("");
  digitalWrite(3,HIGH);
  delay(15);
  digitalWrite(3,LOW);
  delay(50);
  digitalWrite(3,HIGH);
  delay(15);
  digitalWrite(3,LOW);
  delay(5000);
}

En el código para el dado electrónico (Programa 1) se excluye la posibilidad de generar un cero, ya que los dados no tienen ese número, mediante una condición do { ... } while (num == 0);

Como ejercicio se propone escribir un código para generar números aleatorios del 1 al 6 y guardarlos en un archivo en la microSD. Después de un número infinito de eventos, digamos 1000, generando un número aleatorio cada 2 sec, se puede calcular la frecuencia de ocurrencia para cada resultado. Para este ejercicio se propone formatear la salida al archivo de texto de la siguiente manera:
  String dataString = "";
  dataString += "\n";
  dataString += String(dado);

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

Este código se coloca dentro de un ciclo for con 1000 iteraciones dentro de la función setup(), para que se ejecute una sola vez. La función loop() { ... } se deja vacía.

El archivo de texto se abre con Excel y aparecerán todos los valores en la primera columna, separados por [enter]. Así se pueden agrupar de menor a mayor y calcular las frecuencias correspondientes.


Conclusiones:

- El proyecto data-logger utiliza una entrada analógica de la placa Arduino UNO. Como este modelo tiene capacidad para 6 entradas analógicas, es posible colocar ese mismo número de sensores.

- El código de programa de data-logger genera un archivo de 19,598 bytes de un total de 32,256 bytes máximo de capacidad de memoria del AT_Mega_328 de Arduino UNO. De esta manera es posible utilizar más funciones. Si se utiliza la Shield Ethernet de Arduino es posible desplegar los resultados en una página web visible dentro de la misma red donde sea conectado el dispositivo.

- El proyecto dado electrónico ilustra la utilización de la función random(min,max); en el IDE de Arduino. Esta misma idea puede aplicarse cuando se quiere simular un proceso en el que una o más variables pueden tener fluctuaciones irregulares fuera del control del operador. Por ejemplo en la carga contaminante de un caudal de agua residual que entra en una planta de tratamiento para su depuración.

- El código de este programa genera un archivo de 2890 bytes de un total de 32,256 bytes máximo de capacidad de memoria del AT_Mega_328 de Arduino UNO.

1
 2
 3
En la imagen 1 se muestra a la izquierda el sensor TMP102 (PCB roja) y el micrófono (forma circular, junto al TL082), al centro el sensor de temperatura LM35 y a la derecha el Shield MicroSD Sparkfun acoplado a Arduino UNO (PCB azul - Arduino original -, debajo); en la imagen 2 el sensor TMP102; y en la imagen 3 una fuente de alimentación de 12V con la que se puede alimentar la placa Arduino UNO mediante un Jack macho de 2.1mm con el positivo al centro.


Fuentes de información:


http://www.onemansanthology.com/blog/sparkfun-tmp102-temperature-sensor-and-arduino-code/

Sitio oficial Arduino: http://www.arduino.cc/


Nota:
En este mismo blog he dedicado otras entradas a describir proyectos utilizando las tarjetas de desarrollo Arduino. Te facilito enlaces a ellas:

- Proyectos de electrónica con Arduino.
- Registro de datos a una micro SD.
- Sensor analógico y señal luminosa con Arduino UNO.
- Manejo de la micro SD del Shield Ethernet.
- Dado electrónico.

***********************************                  *****************************

Programa 1. Datalogger.

/***************************************************
TMP102

Este sensor de temperatura utiliza comunicación I2C (Inter Integrated Circuit) para enviar el dato al microcontrolador maestro.

http://www.onemansanthology.com/blog/sparkfun-tmp102-temperature-sensor-and-arduino-code/

Circuito TMP102:
- ADD0 -> GND
- ALT  -> unused
- SCL  -> A5
- SDA  -> A4
- GND  -> GND
- VCC  -> 3.3V

Circuito LM35:
- +Vcc -> +5V
- Vout -> A0
- GND  -> GND

Circuito Mic (TL082):
- Pin1   OUT   2
- Pin2   -IN   Mic (-)
- Pin3   +IN   Mic (+)
- Pin4   GND   GND
- Pin5   +IN2  N/C
- Pin6   -IN2  N/C
- Pin7   OUT2  N/C
- Pin8   Vdd   +5V

Nota: La tarjeta microSd utiliza los pines de comunicacion
SPI, por lo que no deben conectarse periféricos en esos
puntos.
Pin_11  RB3  MOSI
Pin_12  RB4  MISO
Pin_13  RB5  SCK
Ademas utiliza los pines:
Pin_4   RD4  CS  Ethernet Shield
Pin_10  RB2  CS  Se inicializa como OUTPUT.
Pin_8   RB0  CS  Sparkfun MicroSd
Nota: El microfono genera un conflicto cuando se conecta su
senal en una entrada analogica. Por eso se utilizo un pin I/O
digital.

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

#include <Wire.h>
#include <SD.h>

int tmp102Address = 0x48;
#define TERMBAUD  115200
#define led 3
#define ruido 2
unsigned long T;
unsigned long T_ant=0;
unsigned long lap=3000;  // 3 sec
int estado = 0;
float minute = 0.0;
const int chipSelect = 8;

void setup()
{
  Wire.begin();
  Serial.begin(TERMBAUD);
  T= millis();
  Serial.print(" **** INICIO **** t= ");
  Serial.print(T);
  Serial.print(" **** TMP102 **** LM35 ****\n");
  pinMode(led,OUTPUT);
  pinMode(10,OUTPUT);
  
  Serial.println("Inicializando SD card ...");
  if (!SD.begin(chipSelect))
  {
    Serial.println("Falla en tarjeta. Inserta tarjeta ...");
    return;
  }
  Serial.println("Se inicilizo tarjeta SD ...");
}

void loop()
{
  T=millis();
  analogReference(DEFAULT);
  minute = ((T*0.001)/60);
  micEstado();  
  if (T - T_ant > lap)
  {
    digitalWrite(led,HIGH);
    T_ant=millis();
    Serial.print("T_TMP102= ");
    Serial.print(getTemperature_TMP102());
    Serial.print(" T_LM35= ");
    Serial.print(getTemperature_LM35());
    Serial.print(" Time= ");
    Serial.print(minute);
    Serial.print(" MicState= ");
    Serial.println(estado);
    escribeArchivo();
    if (estado != 0)
    {
      estado=0;
    }
    
    delay(15);
    digitalWrite(led,LOW);
    delay(50);
    digitalWrite(led,HIGH);
    delay(15);
    digitalWrite(led,LOW);
  }
}

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

float getTemperature_TMP102()
{
  Wire.requestFrom(tmp102Address,2); 
  byte MSB = Wire.read();
  byte LSB = Wire.read();
  int TemperatureSum = ((MSB << 8) | LSB) >> 4; 
  float celsius = TemperatureSum*0.0625;
  return celsius;
}

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

float getTemperature_LM35()
{
  analogReference(INTERNAL);
  int sens=analogRead(A0);
  float temp=sens/9.31;  // conversion a grados celsius.
  analogReference(DEFAULT);
  return temp;
}

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

void micEstado()
{
  int mic = digitalRead(ruido);
  if (mic)
  {
    estado = 1;
  }
  else
  {
    estado = 0;
  }
}

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

void escribeArchivo()
{
  String dataString = "";
  int tiempo = T/60000;
  int TMP102 = getTemperature_TMP102();
  int LM35 = getTemperature_LM35();
  dataString += "\n";
  dataString += String(tiempo);
  dataString += "\t";
  dataString += String(TMP102);
  dataString += "\t";
  dataString += String(LM35);
  dataString += "\t";
  dataString += String(estado);

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


El código de este programa genera un archivo de 19,598 bytes de un total de 32,256 bytes máximo de capacidad de memoria del AT_Mega_328 de Arduino UNO.


******************************             ***********************************


Programa 2. Dado electrónico.

/*************************************************
DadoElectronico

Circuito:
- Display de 7 segmentos. Catodo comun. DC05.
- Pin7 pulsador. Colocar resistencia de 10k_Ohm a +Vcc.

Pin0  a
Pin1  b
Pin2  c
Pin3  d
Pin4  e
Pin5  f
Pin6  g

g  f  gnd  a b
**************
*            *
*            *
*            *
*            *
**************
e  d  gnd  c dp

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

#define push 7
int uno = 0x06;
int dos = 0x5B;
int tres = 0x4F;
int cuatro = 0x66;
int cinco = 0x6D;
int seis = 0x7D;
int disp_num[]={uno,dos,tres,cuatro,cinco,seis};

void setup()
{
  Serial.begin(9600);
  DDRB=0x00;  // PuertoB saliida.
  PORTB = 0x00;
  pinMode (7,INPUT);  // Pin7 entrada digital.
  randomSeed(analogRead(0));
}
void loop()
{
  int num;
  
  do
  {
    float dado = random(0,11.5);  // Para obtener un máximo de 0.6*11.5=6.9.
    num = dado * 6;
  }
  while (num == 0);
  
  if (!push)
  {
    for (int s=0; s<1000; s++)
    {
      PORTB = num;
      delay(8);
      PORTB = 0x00;
      delay(12);
    }
  }
  
  for (int v=0; v<6; v++)
  {
    PORTB = disp_num[v];
    delay(200);
    PORTB = 0x00;
    delay(50);
  }
}
  
El código de este programa genera un archivo de 2890 bytes de un total de 32,256 bytes máximo de capacidad de memoria del AT_Mega_328 de Arduino UNO.








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.