Adaptive kinetic roof for solar tracking

concept

SOLCYCLE is an adaptive solar energy system that captures sunlight during the day and converts it into usable electricity for night-time illumination. 

By tracking the Sun’s movement, the system optimises solar energy collection through its panels, stores the harvested energy in a battery, and uses it to power bulbs after sunset. Integrating solar tracking, energy harvesting, storage, and illumination into a unified system, the project explores a continuous day-to-night energy cycle, demonstrating how responsive technology can harness renewable energy efficiently to create a more sustainable future.

system Overview

Interactive Simulation : https://lively-hummingbird-929bf7.netlify.app

Schematic

Bill of Materials

Prototype

STAGE 01

STAGE 02

STAGE 03

Development of Light

Final Model

Modular Configurations

DAY / NIGHT

video

System Animation
Physical Prototype – System in Motion
Presentation Video

Arduino Control Code

#include <Servo.h>

Servo x;

Servo y;

int angleX = 90;

int angleY = 90;

int targetX = 90;

int targetY = 90;

unsigned long moveTime = 0;

unsigned long lightTime = 0;

const int northPin = A0;

const int southPin = A2;

const int eastPin = A3;

const int westPin = A6;

const int buttonPin = 7;

const int pirPin = 2;

const int leds[] = {8, 9, 10, 11, 12, 13};

bool nightMode = false;

int buttonState = HIGH;

int lastButtonReading = HIGH;

unsigned long lastDebounceTime = 0;

const unsigned long debounceDelay = 50;

const unsigned long pirFilterTime = 500;

int lastPirReading = LOW;

int stablePirState = LOW;

unsigned long lastPirChangeTime = 0;

const unsigned long lightHoldTime = 3000;

unsigned long lastMotionTime = 0;

bool motionDetected = false;

int previousPir = -1;

bool previousLedState = false;

unsigned long pirPrintTime = 0;

void setup() {

  Serial.begin(9600);

  x.attach(5);

  y.attach(3);

  x.write(90);

  y.write(90);

  pinMode(buttonPin, INPUT_PULLUP);

  pinMode(pirPin, INPUT);

  for (int i = 0; i < 6; i++) {

    pinMode(leds[i], OUTPUT);

    digitalWrite(leds[i], LOW);

  }

  Serial.println(“SYSTEM READY”);

  Serial.println(“MODE: DAY”);

}

void loop() {

  int reading = digitalRead(buttonPin);

  if (reading != lastButtonReading) {

    lastDebounceTime = millis();

  }

  if (millis() – lastDebounceTime > debounceDelay) {

    if (reading != buttonState) {

      buttonState = reading;

      if (buttonState == LOW) {

        nightMode = !nightMode;

        if (nightMode) {

          targetX = angleX;

          targetY = angleY;

          motionDetected = false;

          lastMotionTime = 0;

          lastPirReading = LOW;

          stablePirState = LOW;

          lastPirChangeTime = millis();

          previousPir = -1;

          previousLedState = false;

          Serial.println(“MODE: NIGHT”);

        } else {

          for (int i = 0; i < 6; i++) {

            digitalWrite(leds[i], LOW);

          }

          previousLedState = false;

          Serial.println(“MODE: DAY”);

        }

      }

    }

  }

  lastButtonReading = reading;

  if (!nightMode) {

    if (millis() – lightTime >= 200) {

      lightTime = millis();

      int north = analogRead(northPin);

      int south = analogRead(southPin);

      int east = analogRead(eastPin);

      int west = analogRead(westPin);

      targetX = 90;

      targetY = 90;

      if (east > 750) {

        targetX = 135;

      }

      else if (south > 750) {

        targetX = 45;

      }

      if (north > 750 && north > west + 150) {

        targetY = 135;

      }

      else if (west > 750 && west > north + 150) {

        targetY = 45;

      }

    }

    if (millis() – moveTime >= 40) {

      moveTime = millis();

      if (angleX < targetX) angleX++;

      else if (angleX > targetX) angleX–;

      if (angleY < targetY) angleY++;

      else if (angleY > targetY) angleY–;

      x.write(angleX);

      y.write(angleY);

    }

    for (int i = 0; i < 6; i++) {

      digitalWrite(leds[i], LOW);

    }

  } else {

    int pirReading = digitalRead(pirPin);

    if (pirReading != lastPirReading) {

      lastPirChangeTime = millis();

    }

    if (millis() – lastPirChangeTime >= pirFilterTime) {

      stablePirState = pirReading;

    }

    lastPirReading = pirReading;

    bool motion = (stablePirState == HIGH);

    if (motion) {

      lastMotionTime = millis();

      motionDetected = true;

    }

    bool lightsOn =

      motion ||

      (motionDetected &&

       millis() – lastMotionTime < lightHoldTime);

    for (int i = 0; i < 6; i++) {

      digitalWrite(leds[i], lightsOn ? HIGH : LOW);

    }

    if (stablePirState != previousPir) {

      Serial.print(“PIR CHANGED: “);

      Serial.println(stablePirState);

      previousPir = stablePirState;

    }

    if (millis() – pirPrintTime >= 1000) {

      pirPrintTime = millis();

      Serial.print(“PIR RAW = “);

      Serial.print(pirReading);

      Serial.print(” | FILTERED = “);

      Serial.println(stablePirState);

    }

    if (lightsOn != previousLedState) {

      Serial.println(lightsOn ? “LEDS: ON” : “LEDS: OFF”);

      previousLedState = lightsOn;

    }

  }

}