Un problema asociado con distintos sensores es que cada uno tiene una sensibilidad, un modo de medición, retrasos. Y de forma complementaria Arduino es una placa limitada que no admite concurrencia; es decir; no se pueden medir dos sensores y ejecutar otras acciones simultáneamente. Ésta razón entre otras provocan que las lecturas de un sensor o la manipulación de los datos obtenidos de ellos desemboquen en errores, a veces muy difíciles de detectar.
Expongo algunos ejemplos en los que los errores pueden ser comunes y que merecen una atención para evitar en desarrollos posteriores.
Ruido (Noise)
En muchos campos de la ingeniería se trata este término, que suele provocar tantos quebraderos, pero simplificaremos un poco la atención de este efecto. En un ejemplo práctico disponemos de un robot que se mueve sobre un tablero de ajedrez y éste debe reconocer su situación sobre una casilla blanca o negra y el cambio de una a otra.
Estos estados se detectan mediante un sensor infrarrojo que proporciona un valor booleano true si está sobre una casilla negra y false si está sobre una casilla blanca.
Este es un ejemplo de un ejercicio en el que varios robots se mueven sobre el tablero y algunas de las situaciones que pueden producir colisión entre ellos.
Centrándonos en el problema, si hacemos que se mueva nuestro robot sobre el terreno para ir de una casilla a otra puede ocurrirnos que detecta un cambio de casilla cuando no debe.
Este hecho puede deberse a la mala calibración del sensor que suele encontrarse muy cerca del suelo para medir, y que en este caso se puede ajustar con un potenciómetro incorporado para determinar bien el cambio de una casilla a otra. Así que primero deberemos verificar que está bien calibrado.
Otra opción se debe muchas veces a que el terreno está mal impreso o que se encuentre con pequeños objetos por el camino. Estos cambios repentinos pueden producirse en otros sensores cuando de forma puntual aparece un valor que no es el que se ajusta con el modelo de juego real, ya sean fallos de conexión o pequeñas alteraciones.
Así pues, debemos proporcionar robustez mediante código. Y para ello nos basaremos en el hecho de que un valor de ruido aparece de forma puntual y no se mantiene en un pequeño periodo de tiempo, mientras que un cambio real sí que se mantendrá. Para ello creamos una función iterativa de la siguiente forma.
#include <Servo.h> bool IRactual=false; Servo motor; void setup(){ Serial.begin(9600); motor.attach(9); IRactual=digitalRead(2); avanzar(); IRDetector(IRactual); } void loop(){ } void IRDetector (bool IRantes) { bool IRdespues=IRantes; bool IRaux=false; int contador=0; while (IRantes == IRdespues) { IRdespues=digitalRead(2); if (IRantes != IRdespues) { IRaux=IRdespues; for (contador = 0; contador <= 100; contador++) { IRaux=digitalRead(2); if ((IRaux != IRdespues) || (contador >= 100)) { break; } } if (contador >= 100) { detener (); break; }else { IRdespues=!IRdespues; } } } } void avanzar(){ motor.write(180); } void detener(){ motor.write(90); }
Para explicarlo se puede ver que se utilizan bucles dentro de la función IRDetector cuyo parámetro de entrada es la situación actual. Y hacemos uso de variables auxiliares para determinar que el cambio se produce por un cambio de casilla o solo es un factor de ruido. Para ello se vuelve a realizar otro bucle con un contador; en este caso de 100. Esto quiere decir que si el ruido se mantiene durante las 100 iteraciones, es que podemos descartar la suposición de que sea ruido y detener el coche. Mientras que si antes de las 100 iteraciones se vuelve al estado anterior, se rompe el bucle con break y sigue avanzando.
*Aunque esté mal usar las instrucciones break en los tiempos que corren, creedme que me he visto obligado para la reutilización de este código en otras plataformas más adaptadas para otros alumnos.
Error de velocidad
Para este ejemplo usamos el cambio producido por un LDR o fotoresistencia, para que se comporte de la misma manera que el sensor infrarrojo. En este modelo el transmisor será un LED y el receptor una fotoresistencia, de manera que el rebote de la luz sobre una superficie oscura proporcionará un valor diferente que el que rebotaría sobre una superficie más clara.
En lugar de medir la cantidad de luz en el ambiente, lo que queremos es obtener la velocidad de cambio cuando nuestro coche avanza. De esta manera cuando se produzca un cambio grande, indicará que se ha cruzado una barrera de blanco a negro o viceversa; mientras que si el cambio es pequeño o progresivo significará que se mantiene sobre el mismo color.
int pinLDR = 0; int LDR_before,LDR_after; float ms=147; float v_LDR; void setup() { Serial.begin(9600); } void loop() { LDR_before=analogRead(pinLDR); delay(ms); LDR_after=analogRead(pinLDR); Serial.print("Sensor before: "); Serial.println(LDR_before); Serial.print("Sensor after: "); Serial.println(LDR_after); v_LDR = (LDR_after-LDR_before)*1000/ms; Serial.println(v_LDR); }
El primer error observable e inevitable, es que los valores proporcionados por el LDR son enteros en un rango de 0 1023. Esto implica que la sensibilidad es de una unidad, y no podríamos saber que valores existen entre una unidad y otra.
Este aspecto es muy importante, sobre todo si hacemos la escala de tiempo para medir la velocidad más pequeña. En este ejemplo he usado la función delay cuyo parámetro de entrada son milisegundos, pero si hubiera utilizado delayMicroseconds(), siempre obtendría el valor 0, ya que no da tiempo en ese periodo tan pequeño a detectarse un cambio ni tan siquiera de una unidad. Y la diferencia siempre daría un valor nulo.
Aún así, este método está expuesto al error mencionado anteriormente. En caso de encontrarse con ruido, que es una alteración puntual, esto puede provocar un alto grado de cambio, pudiendo ser confundido con la transición de nuestro terreno.
Y además de este error, si hacemos avanzar el coche, el propio movimiento genera un caos caótico de cambios muy rápidos y cuyo efecto no solo está en el avance si no en los choques del vehículo con algún obstáculo del camino.