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.






lunes, 1 de abril de 2019

NORBA STATION 1: captación de energía solar fotovoltaica

Un grupo de alumnos de 4º de ESO están desarrollando un sistema para captar energía solar, almacenarla y posteriormente usarla, el cual debe disponer de un mecanismo que permita orientarse automáticamente para maximizar la obtención de energía. Para la realización del mismo se utilizarán una placa solar policristalina, cuatro fotorresistencias, dos servomotores y una placa arduino de control, así como otros componentes básicos tales como resistencias, cableado, protoboard, pegamento, y materiales reciclados en general. Además, con vistas a probar el rendimiento del sistema, se utilizarán también voltímetros, amperímetros y baterías, entre otros elementos.

Placa solar fotovoltaica
Fotorresistencia
Servomotor
Previa a la creación del sistema, el cual aún no está finalizado, se ha realizado un estudio preliminar de los distintos componentes a utilizar. Para ello se ha empleado, como en otros proyectos, el simulador proporcionado por Tinkercad. Posteriormente se ha dividido el proyecto en tres partes bien diferenciadas:
  1. Sub-sistema motor para el movimiento de la placa solar, el cual consta de dos servomotores que permiten dotar al mismo de dos grados de libertad (giro de 360 grados sobre una superficie horizontal, y giro de unos 170 grados en el plano vertical), y de distintas estructuras conectadas a los mismos capaces de sujetar la placa y moverla de forma eficiente.
    Un primer esbozo de la estructura de este subsistema se ha realizado mediante el software de diseño CAD de Tinkercad.
    Diseño CAD del sistema motor.
    Basándose en ese diseño, posteriormente se ha realizado un primer prototipo del mismo usando materiales reciclados, el cual aún está en fase de revisión y mejora.
    Alumnos 4º ESO con su primer prototipo del sub-sistema motor.
    Sub-sistema motor del captador de energía solar en detalle.
    Para probar este sub-sistema se ha utilizado una placa Arduino y una serie de interruptores para la realización del movimiento de forma manual, mediante un diseño y un software de control muy parecido al utilizado para la construcción del primer NORBA JOINT o "Brazo Robot" del proyecto NorbaSky.
    Circuito creado para probar manualmente el movimiento de los dos servomotores.
    Completando el circuito de control manual mediante interruptores y Arduino.

    Sistema motor, aún sin placa solar, moviéndose mediante interruptores y Arduino.
    (Actualización febrero 2019). Los alumnos han creado un segundo prototipo para el sub-sistema motor, mucho más refinado, usando también materiales reciclados. Esta nueva mejora soluciona algunos problemas del primer prototipo tales como la "rotación invertida de la base" cuando la placa rotaba, añadiendo una base de granito reciclado procedente de escombros de una obra. También se ha añadido un "segundo eje de sujección" para la placa, la cual se desprendía frecuentemente del motor debido a su peso. No obstante, esta solución es provisional y puede ser mejorada.
    Segundo prototipo del sistema motor con mejoras importantes.
    Alumnos de 4º de ESO mostrando las mejoras del segundo prototipo.
    Segundo prototipo del sistema motor montado, pero no conectado a la circuitería de control.
    Probando funcionamiento del nuevo subsistema motor conectado a la circuitería de control.
    Además de las nuevas mejoras del prototipo físico de este nuevo sistema, se han realizado también importantes mejoras en el software de control, inicialmente casi idéntico al del primer NorbaJoint, destinadas a la optimización energética. Hasta el momento, el sistema estaba constantemente actualizando la posición de los motores, aunque los cambios de orientación fueran mínimos o incluso nulos. Esto suponía una vibración constante de los servos y un consumo eléctrico constante. Ahora se han introducido unas modificaciones tales que hacen que solamente se activen los servomotores cuando se detecta un cambio significativo de los ángulos de inclinación de los mismos, ahora mismo debidos únicamente a la pulsación de los botones de control y más adelante debidos a la información recibida del sistema de localización de luz.
    #include <Servo.h> 
    
    //Patillas control servos
    #define PinSERVO1 6
    #define PinSERVO2 5
    
    //Interruptores de control 
    #define BotonSube1 13
    #define BotonBaja1 7
    #define BotonSube2 12
    #define BotonBaja2 8
    
    //Angulos máximos y minimos de cada servo
    #define MAX1 180
    #define MIN1 0
    #define MAX2 125
    #define MIN2 55
    
    Servo Servo1, Servo2; //2 objetos servo, uno por motor
    int angulo1=(MIN1+MAX1)/2, angulo2=(MIN2+MAX2)/2, mover=0;
    
    void setup() {
      Servo1.attach(PinSERVO1);  // Asocia patilla PinSERVO1 a motor Servo1
      Servo2.attach(PinSERVO2);  // Asocia patilla PinSERVO2 a motor Servo2
      pinMode(BotonSube1,INPUT);
      pinMode(BotonBaja1,INPUT);
      pinMode(BotonSube2,INPUT);
      pinMode(BotonBaja2,INPUT);
      Servo1.write(angulo1); //Le dice a Servo1 (base) que gire a angulo1
      Servo2.write(angulo2); //Le dice a Servo2 (placa) que se incline a angulo2
      delay(500);
      }
    
    void loop() {
      if (digitalRead(BotonSube1)&&(angulo1<MAX1)){angulo1++; mover=1;}
      if (digitalRead(BotonSube2)&&(angulo2<MAX2)){angulo2++; mover=1;}
      if (digitalRead(BotonBaja1)&&(angulo1>MIN1)){angulo1--; mover=1;}
      if (digitalRead(BotonBaja2)&&(angulo2>MIN2)){angulo2--; mover=1;} 
      if (mover==1){ //Solo se manda mover al servo cuando se modifican angulos
          Servo1.write(angulo1);
          Servo2.write(angulo2); 
          delay(20);
          mover=0;
          }
      }
    
Código de control del Sistema de Motor .







  • (Actualización abril 2019) Sub-sistema de localización de luz, el cual consta de dos pares de fotorresistencias colocadas perpendicularmente una de la otra, formando todas ellas un ángulo de 45º con la placa solar. Estos componentes informarán acerca de la luz recibida. Con esta configuración, las cuatro fotorresistencias deberían recibir la misma cantidad de luz cuando la placa solar fotovoltaica se posicionase perpendicularmente a la fuente de luz (situación óptima).
    Para probar este sistema, se han creadon varios circuitos a partir de las citadas fotoresistencias además de varios leds como indicadores del punto de origen de la luz. Hemos tenido muchos problemas para conseguir que este sistema funcionase correctamente, ya que las LDR no se comportaban igual ante la misma luz, se producían numerosos ruidos esporádicos en las lecturas, los ángulos de incidencia de la luz sobre las mismas no afectaban a su comportamiento tanto como hubiéramos deseado, retardos en las lecturas, histiéresis,... Para más detalle, hemos creado una entrada en el blog en la que hemos explicado todos los problemas encontrados y cómo los hemos ido solucionando.
    Sistema de información de inclinación óptima de las cuatro fotorresistencias.
    #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 BotonCalibrado 7
    
    
    #define NivelesCalibrado 2
    
    #define PesoNuevoMinMax 90
    #define PesoViejoMinMax 10
    
    
    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];
      
      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)==LOW) { //Calibrado 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];
      
      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]));
      
      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); 
    }
    
    
    Código de control del Sistema de Información de Orientación Optima.
  • Sistema completo incluyendo el "sub-sistema de localización de luz", el "sub-sistema motor" y el software de procesamiento que transforma la información procedente del primero en actuaciones sobre el segundo. En nuestro diseño definitivo hemos utilizado unos servos de 9V alimentados por pilas de 9V, pero cuyo rendimiento caía en cuanto el voltaje bajaba minimamente. Para evitar el arruinarnos en pilas, finalmente nos decantamos por usar como alimentación un transformador de 12V de un router viejo. Por lo pronto, no hemos quemado los motores que están demostrando funcionar bastante bien. Pero por si acaso, incluimos una pequeña resistencia en el circuito para evitar problemas. 

  • Esquema hardware del sistema de completo de la placa solar autoorientable de forma autónoma.
    Construcción del sistema completo de captación de energía solar incluyendo los subsistemas de localización de fuente de luz y motor (vista 1).
    Construcción del sistema completo de captación de energía solar incluyendo los subsistemas de localización de fuente de luz y motor (vista 2).
     
    Sistema de captación de luz auto-orientable en funcionamiento, probándose con una linterna.
     
    #include <Servo.h>
    #define VArr A2 //Lila      ver
    #define HIzq A0 //Amarillo  ama
    #define VAba A1 //Gris      nar
    #define HDer A3 //Azul      azu
    
    #define NivelesCalibrado 2
    
    #define PesoNuevoMinMax 90 //Porcentaje aplicado a nuevo máximo o mínimo
    #define PesoViejoMinMax 10 //Porcentaje aplicado a viejo máximo o mínimo
    #define BotonCalibrado 7
    
    //Patillas control servos 
    #define PinSERVO1 6     //Servo Izquierda-derecha
    #define PinSERVO2 5     //Servo Arriba-Abajo
     
     
    //Angulos máximos y minimos de cada servo 
    #define MAX1 180
    #define MIN1 0
    #define MAX2 170
    #define MIN2 10
    
    
    Servo Servo1, Servo2; //2 objetos servo, uno por motor
    int angulo1=(MIN1+MAX1)/2, angulo2=(MIN2+MAX2)/2, mover=0;
    
    
    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];
      
      Serial.begin(9600); 
     
      for (int x=0;x<4;x++){ 
        pinMode(foto_res[x], INPUT); 
        };
      pinMode(BotonCalibrado,INPUT);
     
      Servo1.attach(PinSERVO1);  // Asocia patilla PinSERVO1 a motor Servo1 Izq-Der
      Servo2.attach(PinSERVO2);  // Asocia patilla PinSERVO2 a motor Servo2 Arr-Aba
      Servo1.write(angulo1);     //Le dice a Servo1 (base) que gire a angulo1
      delay(500);
      Servo2.write(angulo2);     //Le dice a Servo2 (placa) que se incline a angulo2
      delay(500);  
     
      //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])+")");        }
            } 
      }
    
    
    void loop() {
      int v[4];  
      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]);
              }
          }  
      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]));                  
     
      // Moviendo a la izquierda (a la derecha si la placa está por el otro lado (angulo2>90)
      if (v[0]>v[3]  && (abs(v[3]-v[0])<=5) && angulo1<MAX1) { 
           //La parte de "abs" evita que por error de calibrado o hardware se mueva bruscamente el sistema
           Serial.print(" Torcer a izquierda. de "+String(angulo1)+" hasta "); 
           angulo1=angulo1+((angulo2<90)?1:-1); //90º es horizontal. Por debajo de 90, girar al oeste es a la izq. Pero por encima de 90, girar al oeste es la der
           Serial.print(String(angulo1)+". "); 
           mover=1;
           } //VIzq>VDer 
     
       // Moviendo a la derecha (a la izquierda si la placa está por el otro lado (angulo2>90) 
      if (v[3]>v[0] && (abs(v[3]-v[0])<=5) && angulo1>MIN1) { 
           //La parte de "abs" evita que por error de calibrado o hardware se mueva bruscamente el sistema 
           Serial.print(" Torcer a derecha de "+String(angulo1)+" hasta "); 
           angulo1=angulo1-((angulo2<90)?1:-1); //90º es horizontal. Por debajo de 90, girar al este es a la der. Pero por encima de 90, girar al este es la izq
           mover=1;
           Serial.print(String(angulo1)+". "); 
           }  //VDer>Vizq 
     
      // Moviendo hacia arriba 
      if (v[1]>v[2]  && (abs(v[1]-v[2])<=5) && angulo2<MAX2) {  
           //La parte de "abs" evita que por error de calibrado o hardware se mueva bruscamente el sistema
           Serial.print(" Torcer a abajo. de "+String(angulo2)+" hasta "); 
           mover=1;
           angulo2+=1;
           Serial.print(String(angulo2)+". ");
           }    //HAba>HArr 
     
      // Moviendo hacia abajo
      if (v[2]>v[1]  && (abs(v[1]-v[2])<=5) && angulo2>MIN2) {  
           //La parte de "abs" evita que por error de calibrado o hardware se mueva bruscamente el sistema
           Serial.print(" Torcer a arroba. de "+String(angulo2)+" hasta "); 
           mover=1;
           angulo2-=1;
           Serial.print(String(angulo2)+". "); 
           }   //HArr>HAba
     
      if (mover==1){ //Solo se manda mover al servo cuando se modifican angulos
          Servo1.write(angulo1);
          Servo2.write(angulo2); 
          mover=0;
          } 
     
      Serial.println(""); 
    }
    Código de control del sistema de captación de luz auto-orientable: azul (motor), naranja (orientación), amarillo (salida información por serie).