sábado, 24 de enero de 2015

Calibración de sensores (I). Uso de While

Calibración de sensores (I). Uso de While

En la entrada anterior vimos como ajustar un sensor para que actuase en un rango de funcionamiento determinado. El método era muy sencillo y sobretodo visual, lo que nos enseñaba a entender el procedimiento.
Por otro lado, tenía el inconveniente de que necesitas del portátil para calibrarlo, con lo que pierde practicidad e impide que la calibración la pueda realizar cualquiera, y en cualquier caso la complica un poco.
Veamos en esta entrada otro método más autónomo para calibrar sensores, pero primero explicaremos la instrucción que nos ayudará a realizarlo.

While 

La instrucción while, ejecuta una serie de instrucciones, hasta que la condición a testear sea cierta. Este bucle se repetiría indefinidamente hasta que se cumpla, por lo que hay que incluir una condición que pueda variar para que en algún momento se cumpla, de no ser así, entraríamos en bucle infinito, y sería un error de programación.
Esta condición, que debe estar dentro del bucle, puede ser el incremento de una variable o el chequeo de un sensor o entrada del Arduino.
La sintaxis de la instrucción es:

While (expresión){
Acciones en el bucle
}

Un ejemplo , sacado de la web arduino.cc, sería el siguiente:

var = 0;
while(var < 200){
  
// do something repetitive 200 times
  var++;
}

En este ejemplo, se usa la variable while para realizar un bucle que repetirá una acción 200 veces antes de salir del bucle.

Ejemplo calibración


Para nuestro caso concreto, lo que queremos realizar es la calibración de un sensor LDR durante los primeros segundos de puesta en marcha, para luego modular la luminosidad de un LED en función de la luz incidente.
El algoritmo para nuestro montaje sería algo parecido a esto:

  • Crear un bucle de un tiempo definido desde la puerta en marcha
  • Comprobar en este tiempo los valores ofrecidos por el sensor almacenando los valores máximos y mínimos
  • Fuera del bucle, escalar nuestros valores de salida (mapear)en función de los resultados obtenidos y generar la señal de salida correspondiente.

El montaje será idéntico a la entrada anterior, pero refresquémoslo:



El sketch propuesto para resolverlo es el siguiente:


/* Ejercicio Calibracion I. Procedemos a establecer los valores maximos
y mínimos durante los primeros segundos de ejecución del programa
 */

const int ldrPin = A0;    // pin conectado al LDR
const int ledPin = 9;     // pin conectado al LED
const int settime= 5000;  // Tiempo dedicado al ajuste desde
                          // el inicio del programa 
int ValorLDR = 0;         // Valor lectura LDR
int MinLDR = 1023;        // Valor mínimo de la LDR
int MaxLDR = 0;           // Valor máximo de la LDR

void setup() {
  // Encendemos ell LED del Arduino durante la calibración
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);

  //Iniciamos la calibración
  while (millis() < settime) {//Definido en principio para 10 segundos
    ValorLDR = analogRead(ldrPin); // Leemos el valor del sensor

    // Grabamos el valor máximo si es mayor que el guardado
    if (ValorLDR > MaxLDR) {
      MaxLDR = ValorLDR;
    }

    // Grabamos el valor mínimo si es menor que el guardado
    if (ValorLDR < MinLDR) {
      MinLDR = ValorLDR;
    }
  }

  // Apagamos el led 13 pasados los 5 segundos para indicar que 
  // la calibracion ha finalizado
  digitalWrite(13, LOW);
}

void loop() {
  // read the sensor:
  ValorLDR = analogRead(ldrPin);
  
  //Restringimos los valores a los obtenidos durante el calibrado
  ValorLDR = constrain(ValorLDR, MinLDR,MaxLDR);
  
  // Escalamos los valores en la horquilla obtenida en calibracion
  ValorLDR = map(ValorLDR, MinLDR, MaxLDR, 0, 255);

  // Encendemos el LED al valor obtenido con la salida PWM
  analogWrite(ledPin, ValorLDR);
}

El sketch o podeis descargar de aquí.

Esta vez para calibrar el sensor, a diferencia de la entrada anterior bastará con cargar el sketch y durante los primeros segundos ( hemos definido 5s), iluminar y oscurecer el sensor con los valores de trabajo. Transcurrido este tiempo los valores máximo y mínimo quedarán grabados.

Os dejo un video con el procedimiento.



Ya trabajamos con la función milis, en una entrada anterior, pero para refrescar, esta función cuenta el tiempo transcurrido desde la puerta en marcha.

En nuestro bucle While, vamos comprobando los sensores  hasta que transcurra el tiempo previsto.

Otro punto interesante del sketch, es que esta calibración no la realizamos en el cuerpo del programa , void loop, sino en el void setup, por lo que tan solo se realizará en una ocasión durante el arranque del Arduino. Para volver a calibrar el sensor habría que reiniciar el Arduino, con lo que bastaría con pulsar el reset de la placa.

Esta solución, si bien es sencilla, pierde practicidad si se han de calibrar varios sensores, y además implica interrumpir el programa en caso de querer recalibrarlo.

En la siguiente entrada desarrollaremos una versión mejorada, y que serviría para la mayor parte de los montajes.

Nos vemos! 

domingo, 18 de enero de 2015

Ajuste luminosidad de un LED con LDR

Hola a todos. En esta entrada vamos a seguir  trabajando con las LDR.

Hay un tipo de montaje muy común con fotorresistencias que  varía la luminosidad de un LED en función de la  luz que incide en el LDR. Es fácil encontrarlo pero vamos a desarrollarlo para introducir nuevos conceptos y como base para otras entradas posteriores.

El enunciado por tanto, de lo que queremos conseguir, es el siguiente. Queremos un circuito que varíe la luminosidad de un LED en función de la cantidad de luz incidente en el LDR.

A primera vista el planteamiento debería ser prácticamente un “copy-paste” de la entrada sobre PWM, (puedes consultarla aquí), pero cambiando el potenciómetro por el LDR. El esquema es el mismo expuesto en la entrada anterior:


Por lo tanto no variará el montaje, es éste:


La diferencia la tendremos en el rango dinámico que encontraremos en la entrada analógica. Con el potenciómetro, conectado como divisor de tensión, la entrada podía oscilar entre los 0 y los 5V, o en digital entre valores comprendidos entre 0 y 1023.

Con el circuito propuesto, la entrada nunca podrá alcanzar los 5V, pues con la mayor de las fuentes de luz incidiendo en el LDR, tendría una resistencia de más de 100Ω, por tanto la entrada del Arduino vería una tensión de:

I=V/(R+LDR)=5/10.100=0.495mA

VARD=R*I=10.000*0.000495=4,95V

Insisto en que este valor con una fuente de luz muy intensa y muy próxima al LDR.

Para calcular elvalor mínimo de tensión, a oscuras, debemos contemplar una resistencia del LDR de 0.5MΩ. Calculando ota vez la corriente que fluye por la malla:

I=V/(R+LDR)=5/510000=0.0098mA

VARD=R*I=10.000*0.0000098=0.098V

Estos serían valores comprendidos entre máximos y mínimos, que están muy lejos de condiciones reales de funcionamiento.

En condiciones normales yo he obtenido diferencias de unos 3 Voltios, lo que traducido al conversor AD del Arduino (entrega valores entre 0 y 1023), nos da una resolución de tan solo 600 puntos de los 1024 posibles.

Veamos primero como funcionaría una adaptación simple del sketch empleado en el ejemplo del potenciómetro.

int lightPin = 0;  //define el pin de la foto-resistencia
int ledPin=9;     //define el pin para el  LED
int valor;     //define una variable en la que haremos los cálculos

void setup()
{
    Serial.begin(9600);  //Inicializa la comunicación serie
    pinMode( ledPin, OUTPUT );
}

void loop()
{
    valor = analogRead(lightPin);
    analogWrite(ledPin, valor); 
    Serial.println(valor); 
    delay(1000); //pequeño retardo para darle
               // tiempo al LED a responder.
}


¿Qué sucede cuando lo cargamos en el Arduino? 
Antes de nada abrir el serial monitor, y probad a tapad y destapar el LDR y observar los valores obtenidos.  Os muestro los obtenidos en mi caso:





Si vemos los valores obtenidos en la entrada,podemos observar que están entre los 238 y los 774. Eso es debido a que como he comentado anteriormente, en condiciones normales nunca se alcanzan los valores extremos, 0 y 1023. Veamos como solucionar este apartado, para que trabaje solamente entre los valores “ de campo” y el LED pase por todos los estados posibles, incluido el apagado o máximo brillo.

Nota: estos valores son para mis componentes y en las condiciones de casa. Aunque para cada caso variará, no alcanzará los valores extremos.

Map y constrain


Necesitamos hacer proporcional la salida a los valores de entrada, convirtiendo el valor mínimo en la entrada del Arduino, en el "0" de la salida, y el valor máximo obtenido en la entrada en el "255", valor máximo en la salida.

Ya existe una función que rescala estos valores, es la función map. Esta función usa los siguientes argumentos:

map ( valor, fromLow, fromHigh, toLow, toHigh )

Una breve descripción de los parámetros sería:

valor:        número que queremos reescalar,
fromLow: límite inferior de la horquilla que queremos usar como valores de entrada,
fromHigh: este es el límite superior a usar en los valores de entrada,
toLow:      valor mínimo a obtener en la salida,
toHigh:     valor máximo  a obtener en la salida.


Los valores toLow y toHigh, serán los valores mínimo y máximo de la salida PWM, 0 y 255.

Los valores de entrada fromLow y fromHigh, en esta entrada los hallaremos de forma empírica.

Los pasos a seguir, serían los siguiente:

- Cargar el sketch,
- Lanzar el monitor serial,
- Someter el LDR a la fuente de luz mínima y máxima y anotar lo valores obtenidos,
- Modificar el sketch con los valores máximo y mínimos y volverlos a cargar

El sketch est aquí:


/* Ejemplo para reescalr los valores obtenidos en la entrada 
analogica del Arduino. En este caso usamos un LDR conectado a A0,
a traves de un divisor de tension con un a resistencia de 10.000ohmios*/

int lightPin = 0; // Pin LDR.
int ledPin = 9; // Pin LED.
int valor; // Variable para cálculos.
int ajuste;
int min = 0; // Valor minimo obtenido por A0.
int max = 1024; // Valor maximo obtenido por A0.

void setup(){

Serial.begin(9600); // Inicializa el puerto serie.
pinMode( ledPin, OUTPUT ); // ledPin como salida.
}

void loop()
{

valor = analogRead(lightPin); // Leemos el valor de A0.
Serial.print ("Valor de entrada: ");
Serial.println(valor); // Valor de entrada de A0.
valor = constrain(valor, min, max); // Normalizamos el valor.
valor = map(valor, min, max, 0, 255); // Re-mapeamos.
analogWrite(ledPin, valor); // Escribimos el valor.


delay(1000); 

}


Vale, casi se me olvidaba. Nos faltaba explicar la función constrain. Esta función restringe los valores de salida a los que queden dentro de la horquilla de valores que hayamos definido. La sintaxis es la siguiente:

constrain (x, a, b)

Siendo :

x: el dato que hemos obtenido,
a: el límite inferior,
b: límite superior,

¿ Cómo funciona?, esta función devuelve:
  • El mismo valor x a la entrada si a < x < b.
  • Si el valor x es menor que o igual a  a, devolverá a,
  • Si es mayor o igual que b, devolverá b.
Esto nos sirve para que el Arduino no tenga en cuenta los valores de fuera del rango que hemos definido en la función map. Los valores por encima o por debajo de los límites se ajustarán a los valores establecidos.

Un video explicativo del procedimiento a seguir.




Bibliografía:

En esta entrada se han usado ejemplos adaptados de la web http://arduino.cc, para explicar las funciones map y constrain.




sábado, 10 de enero de 2015

Interruptor crepuscular con LDR y Arduino

Hola a todos. Espero que hayáis tenido una buena entrada de año. Una vez pasadas las fiestas retomamos el hilo de este blog.

Esta vez nuestra propuesta es construir un interruptor que active nuestro led en función de la luz ambiental. Un proyecto sencillo pero que nos sirve para empezar a trabajar con sensores.
Hasta ahora hemos dado siempre a nuestro Arduino las órdenes de forma manual, ya sea a través de pulsadores, interruptores o potenciómetros.

Ahora nuestro circuito será capaz de decidir "solito" en función de una variable ambiental. Así que paso a describir del componente que nos hará posible realizar el proyecto.

Fotorresistor o LDR ("ligth-dependent resistor")


El fotorresistor es un componente electrónico, del tipo semiconductor, cuya resistencia varía en función de la luz que recibe.
Los valores resistivos que alcanza van de los 100Ω a los 10kΩ bajo una luz brillante, hasta valores en la oscuridad que típicamente están entre los 500kΩ y los 10MΩ .
Para nuestro ejemplo usaremos el  VT90N2. Aquí lo tenéis junto a una tarjeta SD para comparar el tamaño.



Este modelo en concreto se encuentra en muchos kits de Arduino, tiene una resistencia en la oscuridad de 0,5MΩ y unos 100Ω, bajo luz intensa.
Para usarla en este montaje necesita una resistencia convencional para montar un divisor de tensión a modo de resistencia pull-down. El esquema del circuito que utilizaremos es el siguiente:



Mi propuesta para el montaje en la protoboard es esta:



Es totalmente necesario el uso de la resistencia pull para poder tener variación de tensión en la entrada analógica del Arduino, pues si conectaremos la resistencia directamente a la entrada analógica, entre VCC y masa, tendríamos variación en la intensidad que fluye a través de la resistencia, pero no variaciones de tensión que es lo que podemos analizar con el conversor AD.

El algoritmo del sketch sería muy sencillo, pues tan solo queremos que lea el valor de la resistencia, lo compare con un valor de consigna, y decida si debe apagar o encender el led.

Os invito a intentar encontrar la solución antes de continuar leyendo... tic tac tic tac.

De acuerdo pues aquí os dejo el sketch. Y podéis descargarlo desde aquí.

/* Ejemplo !_), recreamos un interruptor
crepuscular que actua en funcion del valor leido
por una LDR. Ver el video para ver como ajustar
en http://arduinopractico.blogspot.com.es */

int LDR_Pin = 0;  //pin conectado al fotoresistor LDR
int ledPin=9;     //pin conectado al led
int luminosidad;  // variable para registrar la lectura del LDR
int umbral=330;   // valor umbral de luminosidad
void setup()
{
    Serial.begin(9600);  //Begin serial communcation
    pinMode( ledPin, OUTPUT );//  Lo usaremos para ver la lectura real
    digitalWrite(ledPin,LOW);// y ajustar si necesario
}

void loop()
{
   
    luminosidad= analogRead(LDR_Pin); 
    Serial.println(analogRead(luminosidad)); //Escribimos el valor en monitor serie
    //monitorizando este valor podemos  ajustar el umbral para encender el led
    //en funci´n de la luminosidad
    if (luminosidad > umbral)// valor experimental
    {
      digitalWrite(ledPin,LOW);// si la luminosidad es mayor apagamos el led
    }    
    else
    {
      digitalWrite(ledPin,HIGH);// en caso contrario encendemos el led
    }
      
   delay(10); // A mayor valor mas lenta sera la respuesta a los cambios de luminosidad
}





Si os fijais, he incluido una línea para poder monitorizar el valor que obtenemos, ( entre 0 y 1023) de la resistencia LDR en el pin A0 del micro. Para activarlo debereis ir al monitor serial desde el IDE de Arduino.

Serial.println(analogRead(luminosidad));


La explicación del funcionamiento es muy sencilla, primero declaramos las cuatro variables que intervienen en el ejemplo:

int LDR_Pin = 0;  //pin conectado al fotoresistor LDR
int ledPin=9;     //pin conectado al led
int luminosidad;  // variable para registrar la lectura del LDR
int umbral=330;   // valor umbral de luminosidad

Una vez comienza el ejemplo, realizamos la lectura analógica en el pin 0, y lo almacenamos en la la variable luminosidad.

luminosidad= analogRead(LDR_Pin); 

En el siguiente bloque usamos una forma condicional, IT THEN, ( lo podéis repasar aquí), para comparar el valor leído con lo que queremos que sea nuestro umbral de luminosidad.

if (luminosidad > umbral)

Si es mayor, apagaremos el led ( entendemos que hay suficiente luz ambiental).
Por otro lado cuando cae por debajo de nuestra consigna encendemos nuestro led.

if (luminosidad > umbral)// valor experimental
    {
      digitalWrite(ledPin,LOW);// si la luminosidad es mayor apagamos el led
    }    
    else
    {
      digitalWrite(ledPin,HIGH);// en caso contrario encendemos el led
    }
      

El valor que que he usado es experimental. Dependerá del valor que uséis en la resistencia para hacer el PULL, del LDR, de la temperatura, etc.

Por eso es interesante el uso del monitor serial para monitorizar los valores obtenidos y ajustar de forma empírica.

Como procederíamos?

Cargamos el sketch,




y activamos el monitor serial (Heramientas > Monitor serie):


Simulando la luminosidad que queremos obtener y observando el monitor serial tendremos una idea de que valor aproximado podemos usar para nuestro circuito.

Un último consejo, para un ajuste de "campo" más sencillo, en el caso que quisiéramos cambiar este valor de forma más sencilla sin necesidad de conectarnos, sería sustituir la resistencia de 10kΩ por un potenciómetro.

Un video de ejemplo: