domingo, 9 de junio de 2019

NORBA LANDERS - 2º ESO

Una vez probado el circuito de motores nos faltaba dar el siguiente paso que consistía en programar el vehículo y añadirle los sensores.
Fase 1: programación de motores para realizar un circuito o recorrido concreto.
Fase 2: instalación de sensor de ultrasonidos para que el vehículo redirija su trayectoria en caso de encontrarse con obstáculos.

Fase 1: Para conectar los motores hemos utilizado un módulo L298N. Este módulo nos permite conectar ambos motores a la alimentación y desde él a la placa programable arduino. Las conexiones son bastante sencillas.
Hemos buscado información sobre él en varias páginas y blogs. Nos gustaría remitiros a este canal de youtube por si necesitáis más detalles:

Bitwise Ar https://www.youtube.com/channel/UC4unPLtykzwO7MB3IvaQZaA


Conexiones de módulo L298N

.
Cuando tenemos las conexiones programamos el movimiento de nuestros motores y probamos varios recorridos para practicar con el lenguaje de programación de Arduino:
int IN1= 7;
int IN2= 6;
int ENA= 5; //conectado a un pin con posibilidad de modulación pwn;
int IN3= 8;
int IN4= 9;
int ENB= 10; //conectado a un pin con posibilidad de modulación pwn;
int VELOCIDAD;

void setup() {
pinMode (IN1, OUTPUT);
pinMode (IN2, OUTPUT);
pinMode (ENA, OUTPUT);
pinMode (IN3, OUTPUT);
pinMode (IN4, OUTPUT);
pinMode (ENB, OUTPUT);
}

void loop() {
 VELOCIDAD =200; //PUEDE VALER ENTRE 0 Y 255
 Aavance (VELOCIDAD);
 Bavance (VELOCIDAD);
 delay (3000);
 detieneAmbos ();
 delay (2000);
 Aavance (VELOCIDAD);
 delay (1000);
 detieneAmbos ();
 delay (2000);
 Aavance (VELOCIDAD);
 Bavance (VELOCIDAD);
 delay (3000);
 detieneAmbos ();
 delay (2000);
 Aavance (VELOCIDAD);
 delay (1000);
 detieneAmbos ();
 delay (2000);
}
void Aavance (int veloc) { //función para que avance el motor A
 analogWrite (ENA, veloc);
 digitalWrite (IN1, LOW);
 digitalWrite (IN2, HIGH);
}
void Bavance (int veloc) { //función para que avance el motor B
 analogWrite (ENB, veloc);
 digitalWrite (IN3, LOW);
 digitalWrite (IN4, HIGH);
}
void detieneAmbos () { //función para detener ambos motores
 analogWrite (ENA, 0);
 analogWrite (ENB, 0);
}

En este programa conseguimos el giro del vehículo parando uno de los motores durante un tiempo determinado.






domingo, 2 de junio de 2019

NORBA LANDERS - 2º ESO


Durante el tercer trimestre hemos seguido trabajando en nuestros vehículos
Una vez realizado el montaje de la estructura base, los alumnos han trabajado varios aspectos relacionados con las unidades que están planificadas para este trimestre final del curso:




- Electricidad: Se han realizado las conexiones eléctricas de ambos motores y los alumnos han dibujado los circuitos correspondientes con la simbología eléctrica estudiada en clase de Tecnología. Una vez realizadas las conexiones los alumnos han puesto en marcha los vehículos de manera básica a modo de iniciación a la electricidad.


-TICs: En este apartado del currículo de Tecnología los alumnos han utilizado los equipos informáticos, en concreto software específico (libreoffice calc) para elaborar un presupuesto (ficticio) de su vehículo, buscando información en Internet relativa a precios de los componentes y realizando los cálculos básicos utilizando las fórmulas en su hoja de cálculo (suma, multiplicación, %IVA, descuento...).

Al mismo tiempo hemos realizado el montaje completo de un vehículo en el que se instaló la placa programable Arduino y se han programado los movimientos básicos. Lo veremos en la siguiente entrada Norba Lander - 2º ESO.
En esta parte de vehículo programado hemos trabajado la soldadura de estaño con alumnos de Tecnología de 4º ESO. A pesar de que el apartado Norba Lander estaba previsto para 2º y 3º, hemos considerado que era una práctica sencilla y necesaria para aprender en 4º ESO, al mismo tiempo que estábamos trabajando con los brazos robots (Norba Joints).


domingo, 26 de mayo de 2019

Programando Arduino con Scracth.

Seguimos avanzando en las prácticas con 4º ESO. Esta vez nos hemos atrevido con Scratch for Arduino (S4A), que no es más que una versión modificada del lenguaje de bloques Scratch, que permite la interacción con el hardware libre Arduino. Creado por el equipo de Smalltalk del Citilab en 2010 e implementa bloques específicos para manejar los sensores y actuadores de Arduino, este entorno nos pareció muy útil y conveniente para introducir a nuestros alumnos en esta programación y trabajar durante unos días, previos a programar Arduino, para que nuestro brazo robot realice sus movimientos con sus cuatro servomotores.
Para usar este software, debemos instalar el entorno S4A en los equipos portátiles del aula-taller y también un firmware específico de S4A en la memoria de la placa de Arduino, que será el que realice la comunicación con el software del PC, informando a este de la situación de cada entrada y salida en todo momento. Estos pasos están muy bien explicados e la página de descargas de S4A.
La interfaz de S4A es muy parecida a la de Scratch 1.4, aunque con algunas diferencias que los alumnos ha ido descubriendo con el desarrollo de  pequeños proyectos que tenían que resolver.
Programa de bloques de S4A que permite controlar a Arduino
El primer bloque permite inicializar las variables asociadas a las posiciones de los servos, así como los ángulos iniciales de los mismos. Hay que cambiar las posiciones (aquí 10, 10, 10) según en qué punto queramos que el brazo robot se posicione inicialmente. Las variables "hombro", "horizontal" y "pinza" contendrán en todo momento los ángulos de las articulaciones del brazo (servos) y se podrán modificar con los distintos eventos asociados a distintas pulsaciones de teclas. Estas variables actualizarán constantemente los ángulos reales de los servos en el bucle "por siempre" inicial. 
En los bloques siguientes (en el centro de la imagen), asociados a distintos eventos del teclado, vamos situando los servos manualmente mediante la modificación de los ángulos contenidos en las variables antes citadas, para colocarlos en las posiciones que necesitemos. Además, fijándonos en los valores que aparecen en la ventana de ejecución, arriba a la derecha de la pantalla, tomaremos los ángulos extremo hasta donde puede llegar la articulación correspondiente, para luego poder calibrar el movimiento de forma exacta.
Ventana de ejecución a la derecha de la imagen
Y por último con el bloque de la derecha, permitimos realizar movimientos fijos de prueba cada vez que pulsemos la tecla espaciadora.

Brazo robot controlado mediante código de bloques S4A

sábado, 25 de mayo de 2019

NORBA-STATION: Potenciómetro

Para aprender a utilizar las salidas analógicas, hemos aprendido a programar un potenciómetro con arduino. Normalmente un potenciómetro tiene 3 patillas, una irá conectada a tierra (GND), otra a 5V y la otra a un pin analógico de la tarjeta Arduino. Descubrimos también que existen 2 tipos de potenciómetros, unos lineales y otros rotativos. En esta práctica usaremos uno rotativo. Por otra parte, también aprendimos que en Arduino hay 6 entradas analógicas (A0-A5). Internamente, Arduino tiene un conversor analógico-digital que cambia la tensión recibida a un número entero. Los valores van desde 0V =0 a 5V=1023 . Los valores intermedios se calculan de manera proporcional. Lo primero que hicimos fue conectar el potenciómetro según lo visto y abrir un programa de ejemplo que trae el propio IDE de Arduino, llamado AnalogReadSerial, que es el siguiente:


Como podemos ver en el programa, hay que configurar la comunicación serie entre nuestro arduino y el ordenador a 9600 bits de información por segundo, eso se hace con la instrucción Serial.begin (9600) En el loop, se crea una variable llamada sensorValue donde se recogerá el valor de la entrada analógica donde está conectado el potenciómetro (la A0) Con la otra instrucción Serial.println(sensorValue) lo que se hace es imprimir en pantalla el valor que va recogiendo la variable. Para verlo, tenemos que sacar el monitor serie en el IDE. Aquí podemos observar cómo al mover el potenciómetro, van variando los valores de 0 a 1023 La práctica siguiente consistía en hacer variar la velocidad de parpadeo en función de cómo usemos el potenciómetro. El esquema es:






Y por último, con el mismo montaje, hicimos un cambio en el código para que la intensidad de brillo de nuestro led esté en función de los valores del potenciómetro. El programa sería el siguiente:




NORBA-STATIONS. Sensor DTH11 y pantalla LCD

Como habíamos indicado en la entrada anterior, ahora se va a conectar el sensor a una pantalla LCD para que se puedan visualizar los datos que lee.

#include <LiquidCrystal.h>
#include <DHT.h>


int SENSOR = 2;

int VO = 3;
int RS = 4;
int E = 5;
int D4 = 6;
int D5 = 7;
int D6 = 8;
int D7 = 9;

int temp;
int humedad;

DHT dht (SENSOR, DHT11);
LiquidCrystal lcd (RS, E, D4, D5 ,D6, D7);

void setup(){
  dht.begin();

  lcd.begin(16, 2);
  analogWrite(VO, 50); //contraste
}

void loop(){
    humedad = dht.readHumidity();
    temp = dht.readTemperature();

    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Temperatura: ");
    lcd.print(temp);
    lcd.print("C");
    lcd.setCursor(0,1);
    lcd.print("Humedad: ");
    lcd.print(humedad);
    lcd.print("%");

    delay(15000);
}

Y el resultado es:

IMG-20180604-WA0010

IMG-20180604-WA0020



NORBA-STATIONS. Sensor de temperatura y humedad DTH11

Con el sensor DTH11, vamos a medir la temperatura y la humedad del ambiente usando la placa arduino. El sensor DTH11 tiene las siguientes conexiones:




Como se puede ver en la imagen, son muy sencillas, una patilla irá a tierra (GND), otra a 5 V (VCC) y la del medio a un pin digital (en nuestro caso al pin 2). El código desarrollado para hacerlo funcionar ha sido :

miércoles, 22 de mayo de 2019

NORBA LANDER 2: vehículo lunar controlado por control remoto IR / Bluetooth

Durante las últimas semanas el grupo de 3ºB del IES Norba Caesarina está realizando el diseño y construcción de un vehículo lunar. Tras un estudio de cómo debería ser un vehículo lunar, sus características técnicas, movimientos, sensores que deben instalarse en el mismo,  nos hemos marcado una serie de objetivos para definir nuestro prototipo definitivo.

 

     Después de realizar los diferentes diseños o bocetos de los vehículos, teniendo en cuenta las premisas establecidas al principio del proyecto, los alumnos de cada uno de los grupos se ha distribuido el trabajo. Dentro de cada uno de los grupos (seis alumnos por grupo) se diferencian los siguientes trabajos:
  • Construcción del vehículo: se diseña y construye la estructura del vehículo (una vez definido el diseño definitivo).
  • Memoria: particularidades en la estructura del vehículo como la amortiguación, la transmisión del movimiento entre motor y eje principal, y la localización de las placa protoboard y arduino.
  • Programación con Arduino: código del programa para controlar el vehículo por IR (Infrarrojos). 
      Para la construcción del vehículo se han utilizado diversos materiales del taller como madera, metal (sujeción de motores, ejes) o plástico (caucho), siempre teniendo en perspectiva posibles materiales reciclados o reutilizados.
     En el equipo de diseño específico de cada uno de los grupos se evalúa las consideraciones sobre amortiguación, compartimentación dentro del vehículo (situación de los controles, fuente de alimentación, paracaídas...), situación de cada uno de los elementos fundamentales como motores o ruedas.
      Por último, dos miembros de cada grupo está realizando un estudio sobre el código para la placa de Arduino. En primer lugar, se realizará una simulación con el programa Tinkercad (primero se controlarán diodos led por IR y más adelante se controlarán el o los motores). Finalmente, se implementará en una placa real, para posteriormente situarla en el propio vehículo.

      La situación de las placas, sensores y fuente de alimentación se preverá en el diseño y construcción del prototipo de vehículo lunar.








PRIMERA PARTE:

Tras el estudio de las conexiones de los motores (análisis del funcionamiento de un puente H para controlar dos motores) y la colocación de un Bluetooth con sus conexiones correspondientes, se procede a probar, en una práctica más sencilla, y en paralelo el funcionamiento de un Bluetooth para encender los dispositivos más sencillos (diodos leds).

CONTROLAR EL BLUETOOTH (ENCENDIDO DE DOS DIODOS LEDS CON BLUETOOTH -ARDUINO-)

Ficha de códigos (pdf) para controlar dos diodos led.

martes, 9 de abril de 2019

IX Edición de los Premios “Investigar en Ciencias”

La Universidad de Extremadura acogió en la tarde de ayer la gala de entrega de la IX Edición de los Premios “Investigar en Ciencias”, que organiza la facultad de Ciencias con el patrocinio de Caja Rural de Extremadura, para el fomento del espíritu investigador de los jóvenes estudiantes de educación secundaria y ciclos formativos en diferentes campos de la ciencia.
En el acto de ayer se han reconocido los mejores trabajos en las áreas de Tecnología, Biología, Química, Física y Matemáticas, siendo premiados en total once proyectos de alumnos de la ESO y Bachillerato que provenían de distintos centros educativos de toda la región.


Participantes de la IX Edición de los Premios "Investigar en Ciencias"
C:\Users\Usuario\Pictures\2019-04-03 Premios investigar en ciencias\Premios investigar en ciencias 136.JPG
Acto de entrega de premios.
En concreto, en la categoría de Tecnología el ganador ha sido el IES Campos de San Roque, de Valverde de Leganés, por el proyecto “Apostando por el medio ambiente con Agro-Concrete”. En el área de Biología también ha resultado ganador el IES Campos de San Roque, en este caso por el proyecto “Daphnia magna como recursos de la investigación en secundaria”. El segundo premio ha sido para el IES Virgen del Soterraño por el trabajo “Lo que tu piel esconde…” y el tercero ha sido para el IES Cella Vinaria, de Ceclavín, por el “Análisis de la composición de ciertos estiércoles”.
En la categoría de Química el proyecto “Determinación de parámetros de calidad de aceites de oliva virgen extra” del IESO Cella Vinaria, de Ceclavín, ha obtenido el primer premio. El segundo puesto ha sido para el IES Miguel Durán, de Azuaga, por la “Aplicación robótica a la determinación de la concentración de disolución” mientras que el tercer puesto ha sido para el IESO Cella Vinaria por la “Determinación de parámetros fisicoquímicos en la leche de oveja, cabra y vaca”.
En cuanto a la categoría de Física, el mejor proyecto ha sido para el IES Miguel Durán, de Azuaga, por la “Determinación de los coeficientes de rozamiento estático y cinético de diferentes parejas de materias”. El segundo puesto ha sido para el IES NorbaCaesarina por el trabajo “Descubriendo la doble naturaleza de la luz en la vida cotidiana”.
Exposición de nuestros alumnos del Norba Caesarina:
"Descubriendo la doble naturaleza de la luz en la vida cotidiana"
Recogida de premios de nuestros alumnos
Por último, el primer premio en Matemáticas ha sido para el IES Virgen del Soterraño, de Barcarrota, por el trabajo “Elementos matemáticos en la obra escultórica de Ángel Duarte”. En segunda posición se ha situado el Colegio Sopeña de Badajoz por “Estudio estadístico de la antropometría de los alumnos del colegio Sopeña de Badajoz”.
Durante la jornada de esta novena edición de premios, se realizaron numerosas actividades y visitaron varios talleres y laboratorios dedicados a la ciencia y la tecnología:
Espacio dedicado a la Realidad Virtual
Espacio dedicado a la Impresión 3D
Espacio dedicado a la aerodinámica (Tunel de viento)
Fue una fantástica jornada en la que nos lo pasamos muy bien, nos divertimos y aprendimos sobre ciencia. Además nos llevamos un premio a casa. ¿Qué más podemos pedir?

martes, 2 de abril de 2019

Localizando fuentes de luz mediante el uso de fotorresistencias (LDR)

Se denomina fotorresistencia a un componente electrónico cuya resistencia disminuye con el aumento de intensidad de luz que incide sobre el mismo.​ A veces se lo denomina fotoconductor, célula fotoeléctrica o resistencia dependiente de la luz (LDR en inglés). Este tipo de componentes se utilizan mucho en electrónica para detectar situaciones de más o menos luz (por ejemplo, para detectar cuando es de día y de noche...), pero no permiten por si mismos determinar la dirección desde donde procede la luz, lo cual es algo que nos interesará mucho en otros tipo de proyectos.
Desde principio de curso, algunos alumnos de 4º de ESO están trabajando en un proyecto de construcción de un sistema de captación solar de energía fotovoltaica auto-orientable, para posteriormente realizar un estudio de rendimiento del mismo. Para construir este sistema, dividimos el problema en dos partes perfectamente diferenciadas:
  • La primera consistía en la parte mecánica, con la que tuvimos mínimos problemas, y que consideramos más o menos funcional, con algunos pequeños detalles mejorables, los cuales consideramos de poca importancia para nuestras pretensiones. 
  • La segunda parte consistía en un sistema que permitiera localizar la ubicación de una fuente de luz, algo que conceptualmente era bastante simple, y que incluso con un software relativamente sencillo funcionaba a la perfección en el simulador. Sin embargo, en la práctica han surgido numerosos problemas que hemos tenido que ir solucionando poco a poco.

Diseño preliminar del sistema (pirámide)

Para llevar a cabo el sistema de detección de luz, nuestra idea inicial consistía en colocar 4 fotorresistencias distintas orientadas en dos pares Norte-Sur y Este-Oeste, con inclinaciones perpendiculares en cada par. Básicamente colocar una LDR en cada una de los cuatro laterales de una pirámide de base cuadrada cuya inclinación fuera de 45 grados con respecto a su base. De esta forma podrían darse las siguientes situaciones:
  • Que 4 LDR tuvieran la misma resistencia, lo que supondría que todas estarían recibiendo la misma cantidad de luz, y por tanto la pirámide apuntaría a la luz.
  • Que 1 LDR de uno de los pares (N-S o E-O) tuviera menos resistencia la otra. Entonces la luz estaría indiciendo más sobre la misma, y por tanto, habría que mover un poco la pirámide hacia esa fotorresistencia para que recibiera menos a favor de la LDR opuesta.
Sistema de orientación basado en pirámide con inclinación de 45º respecto a horizontal.

Segundo diseño del sistema (paredes perpendiculares)

Después de realizar distintas pruebas, nos dimos cuenta que la inclinación de la LDR respecto al rayo de luz no tenía tanto efecto como el esperado. Si un mismo rayo se proyectaba sobre la LDR, independientemente de su ángulo (salvo inclinaciones muy exageradas), la resistencia que adquiría era similar. Así que tuvimos que modificar el diseño creando una estructura de paredes perpendiculares que proyectaran sombra sobre las LDR cuando un rayo de luz incidiera desde el otro lado de la misma.
Sistema de orientación con "pared perpendicular aislante de luz".
En principio este nuevo diseño no debería dar problemas. Todo indicaba que esta vez si que obtendríamos resultados satisfactorios. Basándonos en el nuevo diseño y en un circuito relativamente simple, pasamos a construir un sistema físico funcional.
Diseño de sistema de orientación con botón de calibración en entorno simulado.
Alumnos de 4º de ESO creando el sistema de orientación fisicamente.
Soldando conexiones del sistema de orientación físico.
Creación sistema orientación (paso 1).
Creando la estructura y colocando las LDR.
Creación sistema orientación (paso 2).
Uniendo las patillas comunes que conectan a 5V.
Creación sistema orientación (paso 3).
Conectando patillaje central con linea de 5V.
Creación sistema orientación (paso 4).
Conectando resto de patillas a línea de datos y res. pulldown.
Creación sistema orientación (paso 5).
Aislando conexiones para crear nueva capa de contactos.
Creación sistema orientación (paso 6).
Conectando resistencias pulldown a línea de tierra.

Creación de circuito de leds para pruebas y sistema de calibración básico

Antes de probar el diseño real, diseñamos un circuito adicional con 5 leds para probar el sistema. Si se recibía más luz por la derecha, se encendería el led derecho (analogamente debería ocurrir lo mismo con el izquierdo, superior e inferior). El led central se encendería en el punto óptimo. Añadimos al circuito un sistema de calibrado semiautomático que determinara la luz máxima y mínima de un determinado entorno (añadiendo un pequeño pulsador para indicar el fin del proceso de calibrado) y procedimos a realizar pruebas en un entorno simulado. Todo funcionaba perfectamente.

Esquema de conexionado del sistema de orientación con cuadro de leds de prueba.
Sin embargo, cuando pasamos a probar el sistema de orientación físico, los resultados no fueron los esperados. En ocasiones el tablero de leds respondía medianamente, pero nunca de forma precisa. Cuando exagerábamos la situación de luz y forzabamos una luz directa hacia las LDR, el circuito tenía un comportamiento más o menos adecuado. Pero usando condiciones de luz medioambiental reales, parecía que algunas fotorresistencias eran más sensibles que otras. Montamos los circuitos una y otra vez, usando distintos componentes para evitar que alguno estuviera defectuoso. Pero siempre ocurría lo mismo: el sistema "no iba fino".

Montaje del cuadro le leds de prueba.
Cuadro de leds montado en protoboard independiente.
Versión del sistema de orientación con cuadro de leds de prueba sobre la misma protoboard.
Pruebas iniciales sobre el sistema de orientación y cuadro de leds con resultados poco satisfactorios.

Rediseñando el sistema de calibrado: tratamiendo independiente de LDR's

Así que nos pusimos a realizar pruebas y mediciones, para posteriormente estudiar los resultados. Nos dimos cuenta que cada fotorresistencia devolvía valores distintos ante condiciones de luz similares.
Por tanto tuvimos que replantear como tratar los datos y optamos por calibrar cada una de las 4 LDR de forma independiente para posteriormente mapearlas a valores discretos conocidos. Para ello usamos un código de calibrado un tanto más complejo que el original.
/*
 * En esta fragmento de código se lee información de las 4 LDR conectadas a HMin, HMax, VMin y VMax
 * buscando para cada una de ellas un valor máximo y otro mínimo, en un proceso continuo que acaba
 * cuando el usuario pulsa el botón de calibrado. Estos valores se almacenan en MinLuz[] y MaxLuz[].
 *
 * La información de todo el proceso se va mostrando por el terminal serie.
 *
 * En la función loop no se ejecuta nada, ya que se está probando el proceso de calibrado unicamente.
 */


#define HMin A2
#define HMax A1
#define VMin A0
#define VMax A3

#define LedCentro 3


#define BotonCalibrado 7


#define NivelesCalibrado 2            //Las lecturas de las LDR se mapearán de 0 a NivelesCalibrado

int MinLuz[4]={1024,1024,1024,1024};  //Valor inicial a corregir en calibrado

int MaxLuz[4]={0,0,0,0};              //Valor inicial a corregir en calibrado

int foto_res[4]={HMin,HMax,VMin,VMax};


void setup() {

  int luz;
  
  char cadena[200]; //Para uso exclusivo en función de conversión dtostrf()
  
  Serial.begin(9600);
  for (int x=0;x<4;x++){ 
      pinMode(foto_res[x], INPUT); 
      };
  pinMode(BotonCalibrado, INPUT);

  
  //Proceso de calibrado, buscando luz máxima y mínima
  while (digitalRead(BotonCalibrado)==0) {
    Serial.println("");
    Serial.print(dtostrf((float)millis()/1000, 6, 1, cadena));
    for (int x=0;x<4;x++) {  
        luz=analogRead(foto_res[x]); 
        MinLuz[x]=(luz<MinLuz[x]?luz:MinLuz[x]); 
        MaxLuz[x]=(luz>MaxLuz[x]?luz:MaxLuz[x]);

        //Impresión en formato:  ----(LDRX: val(map) m:min M:max)
        //                       ----(LDR1: 230(  9) m:  6 M:231)    
        Serial.print("----(LDR"+String(x)+":"+String(luz)+"("+
                     String(map(luz,MinLuz[x],MaxLuz[x],0,NivelesCalibrado))+
                     ")  m:"+String(MinLuz[x])+" M:"+String(MaxLuz[x])+")");
        }
    }
  }

void loop() {

//Aquí iría el código del loop. Aún no programado hasta calibrar correctamente
}
Código de calibrado con salida serie: amarillo (código de control por salida serie), azul (código de calibrado)
Con este código, en la mayoría de las ocasiones todo funcionaba correctamente y el sistema detectaba correctamente el origen de la luz. Pero aún existía algún tipo de problema en determinadas situaciones y no localizabamos ningún error en el código.

Nuevo diseño de calibrado: eliminando lecturas ruidosas

Después de estudiar los datos de control obtenidos por el sistema, nos dimos cuenta que en ocasiones se producían picos máximos (o mínimos) en los mismos. Es como si los LDR repentinamente y durante periodos muy pequeños de tiempo condujeran mejor (o peor) la electricidad (como si les diera mucha luz). ¿Quizá es un defecto de este tipo de dispositivos?¿Quizá sea debido a la histéresis de los mismos?. No lo sabemos. En cualquier caso, estos picos estropeaban el calibrado, forzando al sistema a determinar un máximo que no era real, o al menos no era práctico para la mayor parte de las situaciones. Así que volvimos a pensar en nuevas soluciones. Había que eliminar los picos, pero desconocíamos qué datos eran picos y no sabíamos como identificarlos. Después de pensar mucho optamos provisonalmente por dar un peso de un 20% a los nuevos máximos que encontrasemos. En el caso de que se tratase de picos aleatorios, no afectarían demasiado al calibrado realizado. De esta forma, adaptamos el código de calibrado según el nuevo parámetro.

/*
 * En esta fragmento de código se lee información de las 4 LDR conectadas a HMin, HMax, VMin y VMax
 * buscando para cada una de ellas un valor máximo y otro mínimo, en un proceso continuo que acaba
 * cuando el usuario pulsa el botón de calibrado. Estos valores se almacenan en MinLuz[] y MaxLuz[].
 * 
 * Cada vez que se encuentra un candidato a un nuevo máximo o mínimo, este no sustituye al antiguo
 * máximo o mínimo, sino que afecta al mismo en un portentaje dado por PesoN. De esta forma se evita
 * que lecturas ruidosas afecten al proceso de calibrado de forma significativa. 
 *
 * La información de todo el proceso se va mostrando por el terminal serie.
 *
 * En la función loop no se ejecuta nada, ya que se está probando el proceso de calibrado unicamente.
 */


#define HMin A2
#define HMax A1
#define VMin A0
#define VMax A3

#define LedCentro 3


#define BotonCalibrado 7


#define PesoN 20         //Porcentaje de peso que se asigna a un nuevo máximo o mínimo encontrado

#define PesoV 80         //Porcentaje de peso que se asigna al antiguo máximo o mínimo almacenado

#define NivelesCalibrado 2            //Las lecturas de las LDR se mapearán de 0 a NivelesCalibrado

int MinLuz[4]={1024,1024,1024,1024};  //Valor inicial a corregir en calibrado

int MaxLuz[4]={0,0,0,0};              //Valor inicial a corregir en calibrado

int foto_res[4]={HMin,HMax,VMin,VMax};

void setup() {

  long int luz;
  
  char cadena[20];  //Para uso exclusivo en función de conversión dtostrf()
  
  Serial.begin(9600);
  for (int x=0;x<4;x++){ 
      pinMode(foto_res[x], INPUT); 
      };
  pinMode(BotonCalibrado, INPUT);

  
  //Proceso de calibrado, buscando luz máxima y mínima
  while (digitalRead(BotonCalibrado)==0) {
    Serial.println("");
    Serial.print(dtostrf((float)millis()/1000, 6, 1, cadena));
    for (int x=0;x<4;x++) {  
        luz=analogRead(foto_res[x]); 
        MinLuz[x]=(luz<MinLuz[x]?(luz*PesoN+MinLuz[x]*PesoV)/100:MinLuz[x]); 
        MaxLuz[x]=(luz>MaxLuz[x]?(luz*PesoN+MaxLuz[x]*PesoV)/100:MaxLuz[x]);
        Serial.print("----(LDR"+String(x)+":"+String(luz)+"("+
                     String(map(luz,MinLuz[x],MaxLuz[x],0,NivelesCalibrado))+
                     ")  m:"+String(MinLuz[x])+" M:"+String(MaxLuz[x])+")");
        }
    }
}

void loop() {


}
Codigo de calibrado robusto a ruidos con salida serie: amarillo (control por salida serie), azul (código de calibrado)
Con esta nueva situación, el calibrado parecía funcionar correctamente. El principal problema era que ahora el proceso se hacía mucho más largo, ya que había que esperar a encontrar numerosos máximos para que entre todos se almacenase un máximo bastante cercano a los mismos en la estructura MaxLuz[]. Lo mismo ocurría con los mínimos. Aumentando el peso de los nuevos máximos (PesoN), este tiempo disminuía, pero los picos extraños afectaban más al sistema de calibrado. Es algo que tendríamos que estudiar más (y estudiar su origen), pero queda fuera de este proyecto principalmente por falta de tiempo.

Realizando pruebas con circuito de leds

Finalmente procedimos a realizar pruebas sobre el circuito de leds. Reconstruimos nuevamente el citado circuito ya que lo habíamos desarmado previamente para usar sus piezas en otros proyectos. Por simplificar, eliminamos el led central (si todos los leds restantes se apagaban, el sistema estaría correctamente orientado).
Sistema de orientación en funcionamiento: la salida por serie, y los leds iluminados
informan hacia donde hay que moverlo para obtener la iluminación óptima.
Diseño hardware del sistema de orientación, así como sistema de leds que informan hacia donde hay que girar.
Con ello, comenzamos a probar el nuevo código, y hasta el momento, a falta de tests más exhaustivos, todo parece funcionar correctamente.
/*
 * En esta fragmento de código se lee información de las 4 LDR conectadas a HMin, HMax, VMin y VMax
 * buscando para cada una de ellas un valor máximo y otro mínimo, en un proceso continuo que acaba
 * a los 15 segundos (hemos eliminado el botón provisionalmente). Estos valores se almacenan en
 * MinLuz[] y MaxLuz[].
 * 
 * CALIBRACIÓN ROBUSTA
 * Cada vez que se encuentra un candidato a un nuevo máximo o mínimo, este no sustituye al antiguo
 * máximo o mínimo, sino que afecta al mismo en un portentaje dado por PesoN. De esta forma se evita
 * que lecturas ruidosas afecten al proceso de calibrado de forma significativa. 
 *
 * La información de todo el proceso se va mostrando por el terminal serie.
 *
 * FUNCINAMIENTO
 * La información procedente de las LDR se lee 20 veces y se hace un promedio, eliminado ruido del
 * proceso. El resultado se mapea en tres valores posibles (0, 1 y 2). Comparando estos valores se
 * puede determinar de donde procede la luz y que actuación hay que realizar.
 */


#define VArr A2 //Lila
#define HIzq A0 //Blanco
#define VAba A1 //Gris
#define HDer A3 //Azul

#define HLedIzq 13 //Blanco
#define HLedDer 10 //Azul
#define VLedArr 11 //Lila
#define VLedAba 12 //Gris


#define NivelesCalibrado 2

#define PesoNuevoMinMax 90
#define PesoViejoMinMax 10

#define BotonCalibrado 7
long int MinLuz[4]={1024,1024,1024,1024};  //Valor inicial a corregir en calibrado
long int MaxLuz[4]={0,0,0,0};              //Valor inicial a corregir en calibrado


int foto_res[4]={HIzq,VAba,VArr,HDer};

void setup() {
  long int luz;
  char cadena[20];  //Para uso exclusivo en función de conversión dtostrf()
  
  Serial.begin(9600);
  for (int x=0;x<4;x++){ 
    pinMode(foto_res[x], INPUT); 
    };
  pinMode(BontonCalibrado,INPUT);
p
  
  //Proceso de calibrado, buscando luz máxima y mínima
  
  while (digitalRead(BotonCalibrado)==LOW) { Calibrar hasta pulsar botón
    Serial.println("");
    Serial.print(dtostrf((float)millis()/1000, 6, 1, cadena));
    for (int x=0;x<4;x++) {  
        luz=analogRead(foto_res[x]); 
        MinLuz[x]=(luz<MinLuz[x]?(luz*PesoNuevoMinMax+MinLuz[x]*PesoViejoMinMax)/100:MinLuz[x]); 
        MaxLuz[x]=(luz>MaxLuz[x]?(luz*PesoNuevoMinMax+MaxLuz[x]*PesoViejoMinMax)/100:MaxLuz[x]);
        Serial.print("----(LDR"+String(x)+":"+String(luz)+"("+
                     String(map(luz,(int)MinLuz[x],(int)MaxLuz[x],0,NivelesCalibrado))+
                     ")  m:"+String(MinLuz[x])+" M:"+String(MaxLuz[x])+")");
        delay(10);
        }
    }
}


void loop() {
  int v[4];
  
  //Se hacen 20 lecturas distintas para cada LDR y posteriormente se hace la media 
  //de las mismas, mapeando los resultados a valores entre 0 y NivelesCalibrado.
  for (int x=0;x<4;x++) { v[x]=0; }
  for (int cont=0;cont<20;cont++){
      for (int x=0;x<4;x++) { 
          v[x]=v[x]+analogRead(foto_res[x]);
          }
      delay(20);
      } 

   
  for (int x=0;x<4;x++) { 
      v[x]=map(v[x]/20,MinLuz[x],MaxLuz[x],0,NivelesCalibrado); 
      }
      
  Serial.print( " Izq:"+String(v[0])+" Der:"+String(v[3])+
                " Arr:"+String(v[2])+" Aba:"+String(v[1]));

  //Actuación en función de los valores obtenidos en el vector v[]
  digitalWrite(HLedIzq, (v[0]>v[3]));  
  if (v[0]>v[3]) {Serial.print(" Torcer a izquierda.");} //VIzq>VDer

  digitalWrite(HLedDer, (v[3]>v[0]));  
  if (v[3]>v[0]) {Serial.print(" Torcer a derecha.");}   //VDer>Vizq

  digitalWrite(VLedArr, (v[1]>v[2]));  
  if (v[1]>v[2]) {Serial.print(" Torcer a abajo.");}     //HAba>HArr

  digitalWrite(VLedAba, (v[2]>v[1]));  
  if (v[2]>v[1]) {Serial.print(" Torcer a arriba.");}    //HArr>HAba

  Serial.println("");

  delay(100); 
}
Codigo de orientación funcional: calibrado (azul), lectura robusta de LDRs (verde), actuación (rojo), información (amarillo)
Y con el sistema acabado y funcionando de forma totalmente satisfactoria para nuestras pretensiones, ya solo queda integrar éste en el sistema motor para realizar un control automático. Hemos dedicado para conseguir un funcionamiento óptimo, hemos tenido momentos de desesperación, de querer tirar la toalla porque parecía que todo se volvía en contra y ninguno de los resultados era el esperado. Pero al final, después de mucho trabajar, investigar, rediseñar y aprender sobre la marcha, parece que la espera ha merecido la pena.