Proiektua

Solarigrafia kamera

Proiektu honen helburua modu automatizatuan eguzki-analema jasotzea da. Eguzkiak zeruaren esferan duen batez besteko posiziotik (egun berean ordu berean eta leku beretik) aldentzen denean osatzen duen kurba da analema.

Taldea Katxarraroak

Solarigrafia kamera

Solarigrafia eguzkiak zeruan (Lur planetako leku bakoitzean modu ezberdinean) daukan ibilbidea behatzen duen efektua argazkigintzako praktika eta kontzeptua da. Paisaian horrek duen efektua argazkigintza estenopeikoa, tratamentu digitala eta Internet bidezko hedapena konbinatzen duen prozedimentu espezifikoa da. Rebelatu gabeko argazkigintzako papera erabiltzen da , kamara estenopeikoa eta eskanerra erabiltzen da eguzkiak egunero zeruan (orduak eta hilabeteen arteko esposizio luzeak) egiten duen ibilbidea jasotzen duen irudiak sortzeko. Bere sorreratik dauka mundu osoko afizionatuen artean Internet bidez hedatzeko, kolaboratzeko eta partekatzeko zaletasuna eta nahia.

Proiektu honen helburua modu automatizatuan eguzki-analema jasotzea da. Eguzkiak zeruaren esferan duen batez besteko posiziotik (egun berean ordu berean eta leku beretik) aldentzen denean osatzen duen kurba da analema. Gehienetan, terminoa Eguzkiak urtean zehar betetzen dituen posizioek zeruan marrazten duten irudia izendatzeko erabiltzen da. Analemak zortzi (8) formako kurba osatzen du.

Analema eskuz jasotzeak urte batez jarraian ordu berean eta leku berean argazki bat ateratzea esan nahi du. Batzuetan zaila gertatzen denez hori egitea argazki kamara bat edukitzea egunero ordu berean argazki bat aterako duena ariketa hau egiteko oso baliagarria izan daiteke.

Proiektu honetan Arduino bidez kontrolatzen den kamara bat sortu da; ordu sinkronizaziorako RTC-a (real time clock) erabili da eta kanpoko elikatze-iturrien beharrik ez izateko bateria sistema bat eta eguzki-panel bat. Sistema horrek eguzkiaren irudia jasotzeko eragozpenik gabeko leku zailetan kokatzea ahalbidetzen du. Kamararen obturadorea (pinhole motakoa) servo de 9gr kontrolatzen du, zeinek pinhole-aren zuloa ezkutatzen duen pieza bat mugitzen duen.

Pausuz pausu

  • Arduino Nano
  • RTC DS3231 moduloa
  • SparkFun SunnyBuddy
  • Eguzki panela
  • Lipo 1S 2000 mAh bateria
  • Servo 9gr
  • LED 5mm
  • 220 Ohm ERresistentzia
  • Konexio kablea
/*
   Solarigrafia kamararen kontrola
   David Pello 2019

   Solarigrafia kamarako obtuladorearen irekiera kontrolatzen du servo eta RTC DS3231 erabiliz.

   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;
}

Eskeman azaldutako zirkuitua muntatu ondoren eta RTC -ak ordua ondo jarrita duela baieztatu ondoren (ordua jartzeko RTC DS3231 ematen duen adibidea erabiliz ) arduinoa goian azaldutako kodearekin programatu behar da. Horretarako nahi diren ordu kodeak konfiguratu beharko dira.

Denbora sekzioan hartualdi bakoitzaren  orduak, minutuak eta segundoak aldatuko dira, eta TOMA_SOL2 eta TOMA_SOL3 komentatu edo deskomentatuko dugu, baldin eta bat, bi edo hiru hartualdi nahi ditugun (eta beraz galeriako irudiko adibideko analemen kasua bezalaxe).

Ondoren arduinoa kodearekin programatuko dugu eta sistema guztia erabiliko dugun kameraren barruan montatua utzi. Hermetikoa den kaxa bat erabiltzea gomendatzen da, hartualdien neurrien araberako PVC konexioen kaxa bat (gure pinholearen araberakoa, foku-distantzia, etab.). Serboa pieza batekin itsatsiko dugu, modu horretan serboa 0º posizioan dagoenean obtuladorea estaliko du. Frogaren bat egin genezake aurretik, arduinoaren inguruko serboaren kontrolarekin, posizioaren eta mugimenduaren zentzuaren jarraipena egiteko.

Eguzki-panela, hegoalderantz begira jarriko dugu eta ikuspegia zeruertzera begira, eguzki-esposizioa maximizatzeko helburuarekin.

Kamera itxi aurretik, kodea berabiarazi behar da. Horretarako eskeman I/O moduan markatuak dauden pinak konektatuko dira eta plakari elikatze-iturria jarriko diogu, horrekin programak ulertuko du zerotik hasi behar duela. Ondoren guztia deskonektatuko dugu, I/O pinak barne eta sistema berriz ere elikatzen jarriko dugu. Hemendik aurrera hartualdiak automatikoki egiteko prest geratuko da. Sistema bizirik ote dagoen ikusteko modua eskemako LED-era begiratzea izango da, 30 segundoero kliskatu beharko luke-eta.