Proyecto

Cámara de solarigrafía

El objetivo es automatizar la captura del Analema solar, que es la curva que describe la posición del Sol en el cielo si todos los días del año se lo observa a la misma hora del día (uso horario) y desde el mismo lugar de observación.

Grupo Katxarraroak

Cámara de solarigrafía

La Solarigrafía es un concepto y una práctica fotográfica basadas en la observación del recorrido del sol en el cielo (diferente en los distintos lugares de la tierra) y su efecto en el paisaje, captados mediante un procedimiento específico que combina fotografía estenopeica, tratamiento digital y difusión por internet. Se suele utilizar papel fotográfico sin revelado, una cámara estenopeica y un escáner para crear imágenes que recogen el recorrido diario del sol por el cielo mediante tiempos de exposición muy largos, entre varias horas y muchos meses. Tiene desde su inicio vocación de difusión, colaboración y compartición entre aficionados en todo el mundo gracias principalmente a los cauces de Internet.

Para este proyecto, el objetivo es automatizar la captura del Analema solar, que es la curva que describe la posición del Sol en el cielo si todos los días del año se lo observa a la misma hora del día (huso horario) y desde el mismo lugar de observación. El analema forma una curva que suele ser, aproximadamente, una forma de ocho (8) o lemniscata.

La captura del analema de forma manual requiere tomar una fotografía todos los días del año a la misma hora, lo que muchas veces es inviable porque no siempre se puede estar presente para hacerlo, por tanto una cámara automatizada que tome las imágenes siempre a la misma hora es una herramienta muy útil para este tipo de práctica.

Durante el proyecto se ha realizado una cámara controlada por arduino, usando un RTC (real time clock) para mantener la sincronización horaria, y con un sistema de batería y panel solar para que el sistema sea totalmente autónomo sin depender de fuentes de alimentación externas, lo que posibilita instalarlo en lugares de difícil acceso pero adecuados para capturar el sol sin obstrucciones. El obturador de la cámara (de tipo pinhole) es controlado por un servo de 9gr que mueve una pieza que tapa el orificio del pinhole.

Paso a paso

  • Arduino Nano
  • Módulo RTC DS3231
  • SparkFun SunnyBuddy
  • Panel solar
  • Batería Lipo 1S 2000 mAh
  • Servo 9gr
  • LED 5mm
  • Resistencia 220 Ohm
  • Cable de conexión.

/*
   Control de cámara de solarigrafía
   David Pello 2019

   Controla la apertura del obturador de una cámara
   solarigráfica usando un servo y un RTC DS3231.

   Pensado para un Arduino Nano.

*/

#include 
#include 
#include 
#include 
#include 

// Soft reset
#define RESTART asm("jmp 0x0000")

// secuencias
#define TOMA_SOL2
#define TOMA_SOL3

// tiempos
#define HORA_APERTURA_SOL1         16
#define MIN_APERTURA_SOL1          0
#define HORA_CIERRE_SOL1           16
#define MIN_CIERRE_SOL1            1

#define HORA_APERTURA_SOL2         17
#define MIN_APERTURA_SOL2          0
#define HORA_CIERRE_SOL2           17
#define MIN_CIERRE_SOL2            1

#define HORA_APERTURA_SOL3         18
#define MIN_APERTURA_SOL3          0
#define HORA_CIERRE_SOL3           18
#define MIN_CIERRE_SOL3            1

#define HORA_APERTURA_PAISAJE     9
#define MIN_APERTURA_PAISAJE      0
#define HORA_CIERRE_PAISAJE       10
#define MIN_CIERRE_PAISAJE        55

#define ANGULO_APERTURA           30
#define ANGULO_CIERRE             0

#define PIN_ACT_OBTURADOR         3  // Arduino D3
#define PIN_CONFIGURACION_I       6 // D6
#define PIN_CONFIGURACION_O       7 // D7

#define SLEEPTIME                 30


// ESTADOS
#define ESPERA_SOL1               0
#define ABRE_SOL1                 1
#define ESPERA_SOL2               2
#define ABRE_SOL2                 3
#define ESPERA_SOL3               4
#define ABRE_SOL3                 5
#define ESPERA_PAISAJE            6
#define ABRE_PAISAJE              7

// variables

DS3231 Clock;
Servo obturador;
byte anyo;
byte mes;
byte dia;
byte dia_semana;
byte hora;
byte minuto;
bool h12, pm, siglo;
byte estado;
struct rst_info* reset_info;
int init_mode;
byte ADay, AHour, AMinute, ASecond, ABits;
bool ADy, A12h, Apm;


void setup() {
  delay(1);

  // Iniciamos el I2C
  Wire.begin();
  // Aseguramos que estamos en modo de 24h
  Clock.setClockMode(false);

  // Empezar de cero
  siglo = false;

  // LED
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  // IO
  pinMode(PIN_CONFIGURACION_I, INPUT_PULLUP);
  pinMode(PIN_CONFIGURACION_O, OUTPUT);
  // set to LOW
  digitalWrite(PIN_CONFIGURACION_O, LOW);

  // Y el puerto serie
  Serial.begin(115200);
  Serial.println();
  Serial.println("Iniciando...");

  // Vemos si tenemos que reiniciar o no.
  init_mode = digitalRead(PIN_CONFIGURACION_I);
  Serial.print("Configuración Leida: ");
  Serial.println(init_mode);
  if (init_mode) {
    // parpadeo
    digitalWrite(LED_BUILTIN, HIGH);
    delay(100);
    digitalWrite(LED_BUILTIN, LOW);
    
    Serial.println("Continuando...");
    // Cargamos el modo actual desde la eeprom
    estado = EEPROM.read(0);
    Serial.print("Estado leido: "); Serial.println(estado);
    // Leemos el RTC
    mes = Clock.getMonth(siglo);
    dia_semana = Clock.getDoW();
    dia = Clock.getDate();
    hora = Clock.getHour(h12, pm);
    minuto = Clock.getMinute();

    Serial.println(); Serial.print("---- ");
    Serial.print(mes); Serial.print("/"); Serial.print(dia); Serial.print(" ");
    Serial.print(hora); Serial.print(":"); Serial.println(minuto);

    if (Clock.checkAlarmEnabled(1)) {
      Serial.println("nAlarm 1 enabled");
    }

    Serial.print("Alarm 1: ");
    Clock.getA1Time(ADay, AHour, AMinute, ASecond, ABits, ADy, A12h, Apm);
    Serial.print(ADay, DEC);
    if (ADy) {
      Serial.print(" DoW");
    } else {
      Serial.print(" Date");
    }
    Serial.print(' ');
    Serial.print(AHour, DEC);
    Serial.print(' ');
    Serial.print(AMinute, DEC);
    Serial.print(' ');
    Serial.print(ASecond, DEC);
    Serial.print(' ');
    if (A12h) {
      if (Apm) {
        Serial.print('pm ');
      } else {
        Serial.print('am ');
      }
    }
    Serial.print(' ');
    Serial.println(ABits, BIN);


  } else {
    Serial.println("Iniciando desde cero...");

    // parpadeo largo
    for (int i = 0; i < 20; i++) { digitalWrite(LED_BUILTIN, HIGH); delay(100); digitalWrite(LED_BUILTIN, LOW); delay(100); } // iniciamos estado = ESPERA_SOL1; EEPROM.write(0, estado); // obturador cerrado obturador.attach(PIN_ACT_OBTURADOR); obturador.write(ANGULO_CIERRE); delay(250); obturador.detach(); // Leemos el RTC mes = Clock.getMonth(siglo); dia_semana = Clock.getDoW(); hora = Clock.getHour(h12, pm); minuto = Clock.getMinute(); Serial.println(); Serial.print("---- "); Serial.print(hora); Serial.print(":"); Serial.println(minuto); // Ponemos la alarma (0x8 = 1000b = A4 A3 A2 A1 = horas,minutos,segundos da igual el día) Clock.setA1Time(0, HORA_APERTURA_SOL1, MIN_APERTURA_SOL1, 0, 0x8, false, false, false); // Y la activamos Clock.turnOnAlarm(1); } } void loop() { // reiniciamos el i2c // Wire.begin(); // Comprobamos alarma if (Clock.checkIfAlarm(1)) { Serial.println("Evento de alarma RTC!"); // Dependiendo del estado actual... switch (estado) { case ESPERA_SOL1: // Abrimos obturador estado = ABRE_SOL1; EEPROM.write(0, estado); obturador.attach(PIN_ACT_OBTURADOR); obturador.write(ANGULO_APERTURA); delay(250); obturador.detach(); Serial.println("Abriendo SOL1"); // ponemos la nueva alarma dia_semana = Clock.getDoW(); Clock.setA1Time(0, HORA_CIERRE_SOL1, MIN_CIERRE_SOL1, 0, 0x8, false, false, false); Clock.turnOnAlarm(1); break; case ABRE_SOL1: // Cerramos obturador // cambiamos el estado dependiendo de si hay más aperturas de sol #ifndef TOMA_SOL2 estado = ESPERA_PAISAJE; EEPROM.write(0, estado); EEPROM.commit(); obturador.attach(PIN_ACT_OBTURADOR); obturador.write(ANGULO_CIERRE); delay(250); obturador.detach(); Serial.println("Cerrando SOL1 -> Espera Paisaje");

        // ponemos la nueva alarma
        dia_semana = Clock.getDoW();
        Clock.setA1Time(0, HORA_APERTURA_PAISAJE,
                        MIN_APERTURA_PAISAJE, 0, 0x8, false, false, false);
        Clock.turnOnAlarm(1);
#else
        estado = ESPERA_SOL2;
        EEPROM.write(0, estado);
        obturador.attach(PIN_ACT_OBTURADOR);
        obturador.write(ANGULO_CIERRE);
        delay(250);
        obturador.detach();
        Serial.println("Cerrando SOL1 -> Espera SOL2");

        // ponemos la nueva alarma
        dia_semana = Clock.getDoW();
        Clock.setA1Time(0, HORA_APERTURA_SOL2, MIN_APERTURA_SOL2,
                        0, 0x8, false, false, false);
        Clock.turnOnAlarm(1);
#endif
        break;
      case ESPERA_SOL2:
        // Abrimos obturador
        estado = ABRE_SOL2;
        EEPROM.write(0, estado);
        obturador.attach(PIN_ACT_OBTURADOR);
        obturador.write(ANGULO_APERTURA);
        delay(250);
        obturador.detach();
        Serial.println("Abriendo SOL2");

        // ponemos la nueva alarma
        dia_semana = Clock.getDoW();
        Clock.setA1Time(0, HORA_CIERRE_SOL2, MIN_CIERRE_SOL2,
                        0, 0x8, false, false, false);
        Clock.turnOnAlarm(1);
        break;

      case ABRE_SOL2:
        // Cerramos obturador
        // cambiamos el estado dependiendo de si hay más aperturas de sol
#ifndef TOMA_SOL3
        estado = ESPERA_PAISAJE;
        EEPROM.write(0, estado);
        obturador.attach(PIN_ACT_OBTURADOR);
        obturador.write(ANGULO_CIERRE);
        delay(250);
        obturador.detach();
        Serial.println("Cerrando SOL2... -> Espera paisaje");

        // ponemos la nueva alarma
        dia_semana = Clock.getDoW();
        Clock.setA1Time(0, HORA_APERTURA_PAISAJE,
                        MIN_APERTURA_PAISAJE, 0, 0x0, false, false, false);
        Clock.turnOnAlarm(1);
#else
        estado = ESPERA_SOL3;
        EEPROM.write(0, estado);
        obturador.attach(PIN_ACT_OBTURADOR);
        obturador.write(ANGULO_CIERRE);
        delay(250);
        obturador.detach();
        Serial.println("Cerrando SOL2... -> Espera SOL3");

        // ponemos la nueva alarma
        dia_semana = Clock.getDoW();
        Clock.setA1Time(0, HORA_APERTURA_SOL3, MIN_APERTURA_SOL3,
                        0, 0x8, false, false, false);
        Clock.turnOnAlarm(1);
#endif
        break;

      case ESPERA_SOL3:
        // Abrimos obturador
        estado = ABRE_SOL3;
        EEPROM.write(0, estado);
        obturador.attach(PIN_ACT_OBTURADOR);
        obturador.write(ANGULO_APERTURA);
        delay(250);
        obturador.detach();
        Serial.println("Abriendo SOL3");

        // ponemos la nueva alarma
        dia_semana = Clock.getDoW();
        Clock.setA1Time(0, HORA_CIERRE_SOL3, MIN_CIERRE_SOL3,
                        0, 0x8, false, false, false);
        Clock.turnOnAlarm(1);
        break;

      case ABRE_SOL3:
        // Cerramos obturador
        estado = ESPERA_PAISAJE;
        EEPROM.write(0, estado);
        obturador.attach(PIN_ACT_OBTURADOR);
        obturador.write(ANGULO_CIERRE);
        delay(250);
        obturador.detach();
        Serial.println("Cerrando SOL3... -> Espera Paisaje");

        // ponemos la nueva alarma
        dia_semana = Clock.getDoW();
        Clock.setA1Time(0, HORA_APERTURA_PAISAJE, MIN_APERTURA_PAISAJE,
                        0, 0x8, false, false, false);
        Clock.turnOnAlarm(1);
        break;

      case ESPERA_PAISAJE:
        // Abrimos obturador
        estado = ABRE_PAISAJE;
        EEPROM.write(0, estado);
        obturador.attach(PIN_ACT_OBTURADOR);
        obturador.write(ANGULO_APERTURA);
        delay(250);
        obturador.detach();
        Serial.println("Abriendo Paisaje");

        // ponemos la nueva alarma
        dia_semana = Clock.getDoW();
        Clock.setA1Time(0, HORA_CIERRE_PAISAJE, MIN_CIERRE_PAISAJE,
                        0, 0x8, false, false, false);
        Clock.turnOnAlarm(1);
        break;

      case ABRE_PAISAJE:
        // Cerramos obturador
        estado = ESPERA_SOL1;
        EEPROM.write(0, estado);
        obturador.attach(PIN_ACT_OBTURADOR);
        obturador.write(ANGULO_CIERRE);
        delay(250);
        obturador.detach();
        Serial.println("Cerrando Paisaje -> Espera SOL1");

        // ponemos la nueva alarma
        dia_semana = Clock.getDoW();
        Clock.setA1Time(0, HORA_APERTURA_SOL1, MIN_APERTURA_SOL1,
                        0, 0x8, false, false, false);
        Clock.turnOnAlarm(1);
        break;
    }

    // Apagamos el i2c
    //Wire.end();

  }

  // a dormir (bajo consumo)
  Serial.flush(); // wait for serial
  for (int i = 0 ;  i  <  15 ; i++)
    LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF);

  RESTART;
}

Después de ensamblar el circuito descrito en el diagrama, y ​​asegurarse de que el RTC ya tenga la hora correcta (usando el ejemplo de la biblioteca RTC DS3231 para configurarlo el tiempo), será necesario programarlo con el código Arduino listado, y para ello primero tendremos que configurar en el código las horas deseadas para los disparos en su primer apartado.

Para ello modificaremos las horas, minutos y segundos de cada disparo en el apartado de tiempos, y comentaremos o descomentaremos las secuencias TOMA_SOL2 y TOMA_SOL3 en función de si queremos uno, dos o tres disparos (y por tanto anomalías como las que ocurren con la imagen del ejemplo de la galería).

Luego programaremos el arduino con este código y montaremos el sistema dentro de la cámara que vamos a utilizar. Recomendamos utilizar una caja totalmente estanca, posiblemente una caja de conexión de PVC adecuada al tamaño de la toma que queramos hacer (dependiendo de nuestro pinhole, distancia focal, etc.), y pegaremos el servo con una pieza que cuando el servo está en posición 0º tapar la persiana. Podemos hacer alguna prueba primero con el ejemplo de servocontrol incluido en el entorno arduino para ver las posiciones correspondientes y la dirección del movimiento.

Colocaremos el panel solar orientado hacia el sur y con un ángulo aproximado con respecto al horizonte en la latitud donde nos encontremos para maximizar su exposición solar.

Antes de cerrar la cámara, debemos reiniciar el código. Para ello conectaremos los pines marcados en el diagrama como E / S entre sí y alimentaremos la placa, para que el programa entienda que tiene que empezar de cero. Ahora desconectaremos todo, incluidos los pines de E / S y volveremos a encender el sistema, que ahora estará listo para realizar las tomas de forma automática. Podemos comprobar si el sistema está vivo mirando el LED esquemático, que debería parpadear aproximadamente cada 30 segundos.