Porteføljeopgave 1: Solcellestyring

Navn: EZLight

 

Gruppemedlemmer: Anders Bossel Holst Christensen og Jonas Steen Lysemose

Udseende

Systemet er opbygget af en platform, hvorpå motor, Arduino og batteri er påsat. Motoren er placeret yderligt og kører gearingen, som sidder i midten af konstruktionen. Gearingen kører en aksel, som går direkte op til platformen, hvorpå breadboardet er påsat, hvorpå modstande og LDR sidder. På platformen er der også en skillevæg, som sørger for at lyset er forskelligt på de to LDR.

Systemet

I dette afsnit vil systemets hardware og software blive beskrevet.

Hardware

Systemet blev bygget til at være så kompakt som muligt. Dette var grunden til den relativt lille platform og lave konstruktion. Konstruktionen er bygget i Lego og bliver kørt af en Lego motor. Denne motor er placeret i bunden, helt henne i hjørnet for at give plads til den gearing som skal køre platformens akse som er placeret inde i midten af konstruktionen. Lego motoren starter med at drive et snekkedrev, som består af en gevindstang, som kører et 24-tandstandhjul. Dette tandhjul sidder på en akse hvorpå der også sidder et 8-tandstandhjul. Det lille tandhjul kører så en 40-tandstandhjul, som driver den akse hvor platformen sidder. Dette giver en gearing mellem de to sidste gear en ratio på 0,2 hvilket giver platformen en passende hastighed, som ikke ryster det hele fra hinanden. Gearingen af snekkedrevet mellem gevindstangen og det første tandhjul foregår således at for hver omdrejning aksen med gevindstangen foretager sig, så rykker tandhjulet sig én tand. Dette må betyde at gearingen er 1/24, hvilket udgør størstedelen af gearingen af systemet.

Oppe på platformen sidder et breadboard, hvorpå der er placeret to LDR sensorer, som sidder i en spændingsdeler med en 10K ohms modstand hver, hvilket giver en nem måde at tilgå og udskifte de elektriske komponenter der bruges, da breadboardet er let tilgængeligt og da LDR og modstandene sidder direkte på breadboardet. LDR’erne sidder i en spændingsdeler med modstandene for at der er en reference til den varierende LDR. Det er altså spændingsdelerformlen, som er basis for at det er muligt at få en værdi for lysintensiteten. Formlen er

U1=U∙R1/R1+R2

hvor U er den samlede spænding, U1 er spændingen over modstanden R1 og R1 og R2 er de to modstande i spændingsdeleren.

Breadboardet og motoren er forbundet til Arduinoen og dets Motor Shield, som ligger nede i bunden ved siden af motoren.

Nedenfor ses et billede at opsætningen af hardwaren. Fra Arduinoen går der 4 ledninger, en fra ground til minus, en fra 5v til plus og en fra en analog pin og hen foran modstanden. På breadboardet går der to 10K ohms modstande fra minus og hen på boardet. Der fra føres der videre til LDR’en. LDR’en går så over på en anden række og hen til plus.

Selve konstruktionen af robotten har ikke ændret sig betydeligt hen over projektet. Kun små ændringer med bedre fastgørelse af Arduino og breadboard og mere stabil akse er blevet lavet, for at være sikker på at intet gik i stykker når den kørte. Der har været lidt problemer med at få den ene LDR til at virke. Efter en fejlfinding blev problemet sporet ned til at være en dårlig analog pin i Motor Shieldet, så problemet blev løst ved at bruge en anden analog pin i Shieldet.

 

Software

Robottens opførsler

  1. Robotten følger lyset, så den optimerer lysindfaldet på begge LDR’er
  2. Robotten går på “sleep-mode”, når det er nat

Robottens overordnede opførsel kan aflæses i flowdiagrammet nedenfor. Robotten opretter ved opstart nogle interne variabler, som den skal bruge til at holde styr på data. Alt i flowdiagrammet kører i programmets loop-metode, bortset fra System Setup.

I softwaren på robotten tjekkes først, om der har været en forandring i lysintensiteten på de to LDR’er i de sidste 30 minutter. Dette kan holdes styr på i programmet ved blot at tælle en variabel “darkCounter” op hver gang LDR_Dif <= 50, og sætte den til 0 hver gang LDR_Dif > 50. Hvis der ikke har været nogen forandring i lysintensiteten de sidste 30 minutter, går robotten i “sleep-mode”, hvilket betyder, at den stopper med at foretage målinger de næste 60 minutter, hvorefter den vågner op igen. Hvis det er nat, vil robotten gå i sleep mode flere gange i løbet af natten.

Hvis robotten er aktiv, vil den hver gang loopet køres, lave en måling af modstanden gennem hver af de to LDR’er. På grund af forskelligheder i modstande samt LDR’er, var det nødvendigt at korrigere målingerne fra den ene LDR, så de to målte nogenlunde samme værdi ved samme lysintensitet. For at kunne teste sensor-outputs, transformeres dataene fra værdier mellem 0 og 1023 til værdier mellem 0 og 100. Dataene skrives ud i Serial Monitoren så de løbende kan monitoreres.

Hvis forskellen mellem målingerne fra de to LDR’er er over 50, og motoren er inden for dens grænseværdier, køres motoren ved 255 PWM i 500 ms. Omdrejningsretningen bestemmes af hvorvidt den venstre- eller den højre LDR har den mindste modstand (modtager mest lys).

Problematikker ifm. implementering

Et af problemerne ifm. at få koden til at virke, har været at sørge for en rimelig dataprocessering, således at de to LDR’er måler nogenlunde det samme, ved samme lysintensitet.

En anden udfordring har været at implementere den opførsel, som får robotten til at gå i “sleep-mode” når det er nat, men stadig være aktiv, hvis den skygges for af skyer. Ifm. dette har det været nødvendigt at lave nogle antagelser:

  • Om dagen vil der kontinuerligt være forandrende lysintensiteter med intervaller på mindre end 30 minutter.
  • Skyer skaber ikke skygger, som vil skabe uforandrende lysintensiteter i op til 30 minutter.

Endnu en udfordring ift. at få den rigtige opførsel, har været at kunne styre motoren, således at den ikke overskrider sine grænseværdier (den kan rotere 90 grader i begge retninger ift. udgangspunktet), samt for at kunne få robotten til at returnere til sit udgangspunkt når “sleep-mode” aktiveres. For at kunne gøre dette, har det været nødvendigt at vide nogenlunde hvilken orientering solcellen har på et givet tidspunkt. For at kunne gøre dette med en DC-motor, valgte vi at måle DC-motorens rotationshastighed ved 255 PWM. Ved samtidig at vide, hvor lang tid motoren er aktiv ad gangen, har det kunnet lade sig gøre at kontrollere motoren i en grad, som har vist sig at være præcis nok til formålet. En anden løsning kunne have været at bruge et potentiometer i forbindelse med DC-motoren, så orienteringen kunne måles.

 

const int brakePin = 9;
const int pwmPin = 3;
const int dirPin = 12;
const int ldrPin1 = 2;
const int ldrPin2 = 5;
int darkCounter=0;
int dirCounter = 0;
int dirMin = -54;
int dirMax = 54;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(dirPin, OUTPUT);
  pinMode(brakePin, OUTPUT); 
}

void loop() {
  if(darkCounter >= 360) { //Change this back to 360
    Serial.println("Going to sleep mode...");
    if (dirCounter >0) {
      while (dirCounter != 0) {
        Serial.println("Driving motor LEFT...");
        digitalWrite(dirPin,LOW);
        digitalWrite(brakePin,LOW);
        analogWrite(pwmPin, 255);
        delay(500);
        dirCounter--;
        Serial.print("dirCounter is now: ");Serial.println(dirCounter);
      }
    }
    else if (dirCounter < 0) {
      while (dirCounter != 0) {
        Serial.println("Driving motor RIGHT...");
        digitalWrite(dirPin,HIGH);
        digitalWrite(brakePin,LOW);
        analogWrite(pwmPin, 255);
        delay(500);
        dirCounter++;
        Serial.print("dirCounter is now: ");Serial.println(dirCounter);
      }
    }
    analogWrite(pwmPin,0);
    digitalWrite(brakePin, HIGH);
    delay(3600000); //Sleep for one hour
    darkCounter=0;
  }
  else {
    // put your main code here, to run repeatedly:
  int ldrVal1 = analogRead(ldrPin1)-90;
  int ldrVal2 = analogRead(ldrPin2);
  int dif = abs(ldrVal1-ldrVal2);
  int ldrPerc1 = map(ldrVal1, 0, 1023, 0, 100);
  int ldrPerc2 = map(ldrVal2, 0, 1023, 0, 100);
  int percDif = abs(ldrPerc1-ldrPerc2);
  
  Serial.print("ldr 1 reads: ");Serial.println(ldrVal1);
  Serial.print("ldr 2 reads: ");Serial.println(ldrVal2);
  Serial.print("Difference = ");Serial.println(dif);
  Serial.print("Difference in %: ");Serial.println(percDif);
  //Serial.println("---------------- DELAY 1 SEC -----------------");
  
  if(ldrVal1 > ldrVal2 && dif > 50 && dirCounter>dirMin && dirCounter<=dirMax) {
    Serial.println("Driving motor LEFT...");
    digitalWrite(dirPin,LOW);
    digitalWrite(brakePin,LOW);
    
    int runningDif = dif;
    int priorDif = dif;

    while(runningDif <= priorDif && dirCounter>dirMin && dirCounter<=dirMax) {
      int ldrRunningVal1 = analogRead(ldrPin1)-90;
      int ldrRunningVal2 = analogRead(ldrPin2);
      int dif1 = abs(ldrRunningVal1-ldrRunningVal2);

      digitalWrite(brakePin, LOW);
      analogWrite(pwmPin, 255);
      delay(500);
      analogWrite(pwmPin, 0);
      digitalWrite(brakePin, HIGH);

      dirCounter--; //going in the east direction
      Serial.print("dirCounter is: "); Serial.println(dirCounter);
      
      int ldrRunningVal1_2 = analogRead(ldrPin1)-90;
      int ldrRunningVal2_2 = analogRead(ldrPin2);
      int dif2 = abs(ldrRunningVal1_2-ldrRunningVal2_2);
      
      priorDif=runningDif;
      runningDif = abs(dif1-dif2);
      
      Serial.print("runningDif = ");Serial.println(runningDif);
      Serial.print("priorDif = ");Serial.println(priorDif);
    }
    darkCounter = 0;
  }
  else if(ldrVal2 > ldrVal1 && dif > 50 && dirCounter>=dirMin && dirCounter<dirMax) {
    Serial.println("Driving motor RIGHT...");
    digitalWrite(dirPin,HIGH);
    digitalWrite(brakePin,LOW);
    
    int runningDif = dif;
    int priorDif = dif;

    while(runningDif <= priorDif && dirCounter>=dirMin && dirCounter<dirMax) {
      int ldrRunningVal1 = analogRead(ldrPin1)-90;
      int ldrRunningVal2 = analogRead(ldrPin2);
      int dif1 = abs(ldrRunningVal1-ldrRunningVal2);
      
      digitalWrite(brakePin, LOW);
      analogWrite(pwmPin, 255);
      delay(500);
      analogWrite(pwmPin, 0);
      digitalWrite(brakePin, HIGH);

      dirCounter++; //going in the west direction
      Serial.print("dirCounter is: ");Serial.println(dirCounter);

      int ldrRunningVal1_2 = analogRead(ldrPin1)-90;
      int ldrRunningVal2_2 = analogRead(ldrPin2);
      int dif2 = abs(ldrRunningVal1_2-ldrRunningVal2_2);
      
      priorDif=runningDif;
      runningDif = abs(dif1-dif2);
      
      Serial.print("runningDif = ");Serial.println(runningDif);
      Serial.print("priorDif = ");Serial.println(priorDif);
    }
    darkCounter = 0;
  }

  else {
    Serial.println("Threshold not exceeded - not driving motor");
    darkCounter++;
    Serial.print("Dark counter is: ");Serial.println(darkCounter);
    delay(4000);
    }

  delay(1000);
  digitalWrite(brakePin,HIGH);
  }
  
}

Leave a Reply