– af Rasmus Jensen (rasje17) og Patrick Christoffersen (pachr16)

Systemets Opbygning

Grundet de ekstraordinære omstændigheder i forbindelse med dette projekt er systemet fremstillet i TinkerCad, da vi ikke har alle de elektriske komponenter der skal bruges til robotten. Dette har medvirket til at visse beslutninger og valg i projektet ikke falder helt sammen med sådan som systemet ville være i virkeligheden, idet TinkerCad ikke er så fleksibelt som en virkelig løsning, og at projektet derfor har været underlagt TinkerCad’s begrænsninger. Det vil være nævnt i hvert afsnit hvor det er relevant hvorledes TinkerCad løsningen adskiller sig fra sådan som systemet ville have været bygget i virkeligheden.

Spændingsregulator

For at forsyne arduinoen med 5 volt med et system som er baseret på en 9 volts spændingskilde vil det være nødvendigt at inkludere en spændingsregulator.

Grundet problemer med at TinkerCad ikke vil simulere at spændingsregulatoren bruges som en del af et større kredsløb (se billede herunder), samt at TinkerCad-Arduinoen under simuleringer forsynes med strøm via USB-stikket, har vi valgt ikke at inkludere spændingsregulatoren i det endelige system, som der testes på.

For stadig at vise hvordan spændingsregulatoren skulle bruges hvis systemet skulle bygges fysisk, er den lavet i et separat TinkerCad-kredsløb.

I dette system er spændingsregulatoren omgivet af 2 kondensatorer som hjælper med at udligne i tilfælde hvor der er pludselige udfald i spænding.
Kredsløbet er sat op efter anvisningerne for en LM7805 spændingsregulator fra: https://www.sparkfun.com/datasheets/Components/LM7805.pdf.

Som vist på billedet herunder (og demonstreret med to multimetre), er spændingsregulatoren blevet brugt til at nedregulere til en spænding på 5V, hvilket er det Arduinoen skal forsynes med, mens batteriet samtidigt kan forsyne et andet kredsløb med de sædvanlige 9V.

H-bro

For at motoren skal kunne dreje i begge retninger, er der blevet bygget en H-bro, som kan vende den retning som strømmen løber igennem motoren.

H-broen er blevet konstrueret med inspiration i nedenstående diagram fra Practical Electronics for Inventors (af Paul Scherz og Simon Monk, s. 468) og består af 2 n-channel MOSFETs (Q1, Q2) og 2 p-channel MOSFETs (Q3, Q4). Hvilken vej strømmen løber gennem motoren afhænger af hvilken af de to kontakter (SW1 og SW2) som er tilsluttet. Når SW1 er tilsluttet bliver spændingen på gate af Q1 og Q3 til nul, hvilket slukker Q1 og tænder Q3, og tillader at strømmen løber gennem Q3 til motoren og Q2, hvilket får motoren til at køre. Omvendt hvis vi slår SW2 til i stedet for, så slukker Q2, mens Q4 tænder. Dette får strømmen til at løbe fra Q4 den anden vej gennem motoren til Q1, hvilket får motoren til at køre den modsatte vej rundt.

(Practical Electronics for Inventors af Paul Scherz og Simon Monk, s. 468)

For at kunne styre motoren med en arduino, er de to switches erstattet med to BJT npn transistorer som det ses i opsætningen vist herunder.
At benytte npn transistorer tillader at vi kan kontrollere strømmen til motoren ved at forbinde arduinoens output til base på transistoren. Hermed kan vi, ved at regulere strømstyrken, regulere hvor meget strøm der løber igennem transistoren, og derved regulere motorhastigheden.

Gearing

Motoren, der skal dreje solcellen, drejer meget hurtigere end det vil være praktisk at vende solcellen. Derfor skal der findes en gearing, der gør det nemmere at styre hvor meget solcellen egentlig vendes når motoren kører.

Til at starte med, er det nødvendigt at vide hvor hurtigt motoren kører – derudfra kan der findes et gearingsforhold. Derfor er det blevet testet, hvor hurtigt motoren kører ved fuld kraft i det byggede kredsløb – og det er fundet, at den kører med 17415 omdrejninger i minuttet (Dette er en DC motor i TinkerCad – den udleverede lego-motor til projektet drejer langsommere). Desuden er det blevet tjekket, at motorens omdrejninger skalerer lineært – dvs. hvis vi fra arduinoen fortæller, at vi kun vil sende et signal på henholdsvis 191, 127, og 63 (75%, 50%, og 25% af 256, som er det maksimale signal), så kører motoren med det der svarer til 75%, 50%, og 25% af dens maksimale RPM, 17415.
Det vil være en fordel at regne med, hvor mange grader solcellen vendes, når motoren kører.  Med udgangspunkt i maksimalhastigheden findes det ved at gange de 17415 RPM med 360 – antallet af grader på en fuld omdrejning. 

17415 * 360 = 6.269.400‬ grader pr. minut.

Det er en alt for hurtig rotation til, at solcellens vendinger kan blive fintfølende nok til at fange solen. Hvis der derimod benyttes en nedgearing på 500.000 til 1, fås der en meget mere kontrollabel rotationshastighed:

6.269.400 / 500.000 = 12,5388 grader pr. minut.
12,5388 / 60 = 0,20898 grader pr. sekund.

Gearforholdet på 500.000 til 1 betyder, at for hver gang motoren har gennemført 500.000 omdrejninger, fuldfører solcellen kun 1 enkelt omdrejning. Dette er meget mere praktisk, og gør at solcellen kan være mere fintfølende. Nu kan den mængde tid, motoren skal køre, for at vende solcellen 1 grad findes:

1 / 0,20898 = 4,785 sekunder pr. grad.

Dette vil sige, at arduinoen skal kodes til at give motoren besked på at køre ved fuld hastighed i 4785 millisekunder per grad solcellen skal vendes, når der benyttes et gearingsforhold på 500.000 til 1.

Da det tidligere blev testet og bekræftet, at motorens omdrejninger skalerer lineært med den mængde strøm, der sendes til BJT-transistorerne i H-broen, kan det desuden beregnes hvor lang tid motoren skal køre, for at dreje solcellen 1 grad ved disse lavere motorhastigheder – og stadig med det samme gearforhold som tidligere beregnet. Disse hastigheder skal dog kun bruges under de langsommere start og stop-faser. Det ønskes, at både start og stop-faserne tilsammen drejer solcellen 1 grad, da dette er den mindste vending, solcellen skal kunne lave – dvs. den er fintfølende ned til 1 grad. Da der desuden køres tre forskellige hastigheder under både start og stop-faserne, skal der derfor kun drejes 1/6 grad ved hver hastighed.
Først beregnes motorens omdrejninger ved de tre ønskede hastigheder:

17415 * 0,25 = 4353,75 RPM
17415 * 0,5 = 8707,5 RPM
17415 * 0,75 = 13061,25 RPM

De omregnes ligesom tidligere til grader per minut, og deles med gearforholdet:

(4353,75 * 360) / 500.000 = 3,1347
(8707,5 * 360) / 500.000 = 6,2694
(13061,25 * 360) / 500.000 = 9,4041

Omregning til grader per sekund:

3,1347 / 60 = 0,052245
6,2694 / 60 = 0,10449
9,4041 / 60 = 0,156735

Herfra findes det antal sekunder motoren skal køre, for at dreje en sjettedel af en grad ved hver hastighed:

1 / 0,052245 / 6 = 3,190
1 / 0,10449 / 6 = 1,595
1 / 0,156735 / 6 = 1,063

Disse udregninger har vist, at hver fase skal vare følgende mængde af tid – angivet i millisekunder, da det er den tidsenhed, arduinoen arbejder med:

FaseTid
Start – 25%3190 ms
Start – 50%1595 ms
Start – 75%1063 ms
Fuld hastighed4785 ms pr. grad
Stop – 75%1063 ms
Stop – 50%1595 ms
Stop – 25%3190 ms

Da et gearforhold på 500.000:1 er ekstremt højt, grundet den meget hurtige motor der bruges i TinkerCad, vil det formentlig ikke være realistisk at bygge det fysisk. Det ville svare til, at et tandhjul med 6 tænder skulle drive et med 3 millioner tænder. Tankegangen bag opbygningen demonstreres derfor med de gear, som vi nåede at hente inden nedlukningen af SDU – men eftersom vi selvfølgelig ikke har nok gear til at lave et forhold på 500.000 til 1, bliver det med nogle andre tal.
Der er brugt følgende typer af gear:

  • Sort med 36 tænder
  • Mellemstor grå med 16 tænder
  • Lille grå med 8 tænder

Som set på billederne herunder bruges et lille gear til at drive et større, for at nedskalere mængden af omdrejninger. Disse gear drejer desuden en stang, som er forbundet med endnu et gear, således at flere gearsamlinger kan bruges til at nedskalere mængden af omdrejninger.
Det første gear, der drejes, er det lille grå med 8 tænder. Dette drejer et sort gear med 36 tænder, og gearforholdet er dermed 36/8, eller 4,5. Det sorte gear drejer en stang, hvorpå et mellemstort gråt gear driver et andet sort gear – her er gearforholdet 36/16, eller 2,25. Det samlede gearforhold igennem denne række af interaktioner er derfor 4,5 + 2,25 = 6,75. Dette betyder at 6,75 omdrejninger af det første, lille gear resulterer i 1 omdrejning af det sidste gear i rækken. Det sidste gear drejer i dette tilfælde en platform, hvorpå det var tiltænkt at solcellen skulle sidde, før begrænsningerne grundet COVID-19 trådte i kraft.

Sensorer og deres placering

Som robottens sensorer er der brugt 3 lys-sensitive resistorer (LDR). To af disse er placeret på hver sin side af solcellen, og bruges til at bedømme om der falder mest sollys på venstre eller højre side af cellen – og dermed i hvilken retning der skal drejes for at få solcellen rettet direkte mod sollyset, i hvilket tilfælde der vil være en lige stor mængde sollys på begge sider.
Den sidste LDR er placeret bag ved solcellen, og skal bruges til at bedømme om den rigtige side af solcellen er rettet mod solen. Hvis den står i skygge, ved vi at solcellen er rettet nogenlunde mod solen – hvis der derimod er meget lys på denne sensor, skal solcellen drejes hele vejen rundt, så den rigtige side bliver vendt mod solen.
LDR-opsætningen ser således ud:

Færdigt system

Det færdige system som det er afbilledet herunder består af en arduino, som på breadboardet til højre for har de 3 LDR som måler lyset. På breadboardet over arduinoen er der opsat 3 dioder som repræsentere de tre faser der er i bevægelsen af solcellen – slowStart (gul), FullSpeed (blå), og slowStop (rød). Over dette er h-broen og motoren afbilledet.

Diagram

Der er blevet lavet følgende diagram over systemets opstilling:

Robottens udseende

Følgende 3D-opstilling af robotten er blevet udarbejdet i TinkerCad:

Pilene på billedet viser placeringen af følgende dele:

  1. LDR
  2. Solcellepanel
  3. Spændingsregulator
  4. H-bro
  5. Arduino
  6. Dioder til at vise hvor i programmet systemet er

Problemer undervejs

Der har været en del forskellige problemer undervejs i udarbejdelsen af opgaven udover den helt åbenlyse problematik med at universitetet lukkede ned og opgaven overgik til at være i TinkerCad.

Før vi overgik til en digital løsning sad vi hovedsageligt med to problematikker, først og fremmest at den udleverede h-bro var tegnet forkert, og derudover havde vi problemer med det lego som var stillet til rådighed.
I forhold til h-broen så brugte vi meget lang tid både af vores egen og af instruktørernes til at kigge på hvorfor vores h-bro ikke virkede, og vi endte med at genopbygge den over 5 gange på forskellige breadboards og i tinkercad idet vi blev vejledt til at problemet højst sandsynligt skyldes at ledningerne rørte hinanden under boardet. Det viste sig dog efter at have fået den rigtige tegning, at det var den forkert vendte transistor som var problemet.
I forhold til det udleverede lego indeholdt beholderne med lego ikke nok brugbare dele og alt for mange ubrugelige elementer som hverken kan benyttes til gearing eller strukturel opbygning af solcelle platformen. Dette skyldtes blandt andet en overvægt af ubrugelige dele (dekorative dele), og derudover kan det skyldes at den ekstraordinære situation kan have medført at tidligere grupper kan have haft en tendens til at hamstre rigeligt.

Efter at vi overgik til en digital løsning af opgavebeskrivelsen har vi erfaret nogle problemstillinger i forhold til at benytte TinkerCad. Heriblandt at simulationer i værste fald slet ikke virker, og hvis de gør kan de have en tendens til at simulationen kører så langsomt at programmet bliver ubrugeligt, og ikke reagerer på input. Disse udfordringer er især set ved simulationer som benytter flere kondensatorer.

Systemets Opførsel

Robottens adfærd er programmeret i den arduino, der kontrollerer motorens retning og hastighed igennem de to NPN-transistorer. Tankerne bag både adfærden generelt, samt specifikt omkring arduinoens kode er beskrevet herunder.

Flowdiagram

Det ønskes at robotten først, ved hjælp af de lys-sensitive resistorer (systemets sensorer), bedømmer i hvilken retning den skal dreje, for at komme tættere på at være rettet direkte mod solen. Da systemet benytter tre lys-sensitive resistorer, findes der seks tilfælde:

  1. Der er en lige stor mængde lys på højre og venstre side, og mindre lys på bagsiden.
    • Dette betyder at solcellen er rettet direkte mod solen, og der er derfor ikke behov for at dreje – vi går derfor direkte til re-evaluering.
  2. Der er en lige stor mængde lys på højre og venstre side, men mere lys på bagsiden.
    • Dette betyder at solcellen står med ryggen direkte mod solen, og derfor skal den drejes 180 grader.
  3. Der er en større mængde lys på venstre side end i højre, og mindre lys på bagsiden.
    • Hermed er solcellen rettet nogenlunde i retning af solen, men da der er mere lys på venstre side, end på højre, skal den drejes lidt mod venstre.
  4. Der er en større mængde lys på venstre side end i højre, og endnu mere lys på bagsiden.
    • Dette vil sige at solcellen er vendt mindst 90 grader væk fra solen, og der skal derfor drejes 90 grader mod venstre.
  5. Der er en større mængde lys på højre side end i venstre, og mindre lys på bagsiden.
    • Hermed er solcellen rettet nogenlunde i retning af solen, men da der er mere lys på højre side end på venstre, skal den drejes lidt mod højre.
  6. Der er en større mængde lys på højre side end i venstre, og endnu mere lys på bagsiden.
    • Dette vil sige at solcellen er vendt mindst 90 grader væk fra solen, og der skal derfor drejes 90 grader mod højre.

Når det er blevet besluttet hvilken af de seks cases der er sand på nuværende tidspunkt, skal det tjekkes om den ønskede rotation er mulig – det er vigtigt, at robotten ikke altid kun drejer til højre, for eksempel, da det ville resultere i, at ledningerne ville blive snoet rundt. Derfor er robotten blevet begrænset til kun at måtte dreje 360 grader. Hvis det ikke er muligt at udføre den ønskede rotation uden at overskride denne grænse, bliver rotationen inverteret, således at robotten drejer den anden vej rundt til den ønskede position.
Alt dette er blevet opstillet i følgende flowchart:

Metodebeskrivelser

Arduino-koden er inddelt i fem hoved-metoder:

  • move(int movement)
  • turn(int degrees)
  • slowStart(int degrees)
  • fullSpeed(int degrees)
  • slowStop(int degrees)

Move-metoden står for at tjekke, om det er muligt at dreje den mængde grader i den retning, som den er blevet givet. Hvis det ikke er, så inverterer den bevægelsen. Herefter opdaterer den robottens orientation-variabel, og sender bevægelsen videre til turn-metoden.

Turn-metoden står udelukkende for at sende bevægelsen videre til de rigtige del-bevægelser – slowStart, fullSpeed, og slowStop. Den tjekker for, om det er brug for fullSpeed, men det er kun i de tilfælde, hvor der skal drejes mere end 1 grad. Dette er fordi slowStart og slowStop tilsammen drejer solcellen 1 grad.

SlowStart-metoden er den der først bliver kaldt. Denne står for at starte motoren stille og roligt – det gør den i tre faser. Først får den motoren til at køre 25%, hvorefter den venter længe nok til at dette har drejet solcellen en sjettedel af en grad (da der kommer til at være seks af disse faser ved hver bevægelse, og den ønskede mindst mulige bevægelse er 1 grad). Herefter sætter den motoren op på 50%, og venter igen til den har drejet solcellen en sjettedel af en grad. Processen gentages for 75%. Dette er meget lig det der sker i slowStop-metoden, bortset fra at det går i den anden retning (dvs. starter på 75%, og går nedad), og slutter med at motoren bliver sat til at stoppe helt.

FullSpeed-metoden kaldes kun, hvis der skal drejes mere end 1 grad. Den kaldes efter slowStart, men før slowStop, og sætter motoren til at køre med fuld hastighed i den mængde tid, som det kræver for solcellen at dreje den mængde grader minus 1, som den har fået givet. Den ene grad der trækkes fra er på grund af, at slowStart og slowStop stadig står for 1 grads bevægelse.

Arduino-kode

Den kode, der er blevet programmeret til arduinoen, kan ses herunder – inklusive kommentarer. De vigtigste dele af koden er yderligere beskrevet i Metodebeskrivelser-afsnittet, mens flowdiagrammet beskriver de cases, som der tjekkes for i Loop-metoden, hvor det bestemmes hvilken bevægelse der skal udføres. Hvis der for eksempel er en lige stor mængde lys på begge sider af solcellen, men der er mest lys på back-sensoren, vil solcellen blive drejet 180 grader, så den bliver vendt mod solen igen. Dermed tager koden også højde for hvad der skal ske når det eksempelvis bliver morgen, og der derfor kan være behov for at dreje en stor mængde.

#define left A0
#define back A1
#define right A2

int leftVal = 0;
int backVal = 0;
int rightVal = 0;

// initializing orientation to be in the middle of the 0 to 360 allowed interval
// must never go below 0 or above 360 to avoid tangling wires etc.
int orientation = 180;

// delay needed for turning 1 degree at full speed
long ONE_DEGREE_FULL_MS = 4785;

// precalculated delays for turning 1/6th of a degree at different motor speeds
int DELAY25 = 3190;
int DELAY50 = 1595;
int DELAY75 = 1063;

void setup()
{
  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  Serial.begin(9600);
}

void loop()
{
  Serial.println("Current orientation: ");
  Serial.println(orientation);

  leftVal = analogRead(left);
  backVal = analogRead(back);
  rightVal = analogRead(right);

  if (leftVal == rightVal && backVal > leftVal)
  {
    // turn 180 degrees - it seems like the sun is directly behind us
    move(180);
  }
  else if (leftVal < rightVal)
  {
    if (backVal > rightVal)
    {
      // 90 degrees - back is getting more sun than front, so we should turn a large amount before rechecking.
      move(90);
    }
    else
    {
      // 1 degree - already facing the sun, just not directly, so should only make small adjustments until we find the perfect spot.
      move(1);
    }
  }
  else if (leftVal > rightVal)
  {
    if (backVal > leftVal)
    {
      // turn 90 degrees left
      move(-90); 
    }
    else
    {
      // turn 1 degree left
      move(-1);
    }
  }
}

// check if movement is possible (due to wires - never go above 360 orientation, or below 0)
// and update orientation
void move(int movement)
{
  // check if orientation would go out of bounds by performing this movement
  if ((orientation + movement > 360) || (orientation + movement < 0))
  {
    // invert movement
    if (movement > 0)
    {
      turn(-360 + movement);
      orientation = (orientation + (-360 + movement)) % 360;
    }
    else
    {
      turn(360 + movement);
      orientation = (orientation + (360 + movement)) % 360;
    }
  }
  else
  {
    turn(movement);
    orientation += movement;
  }
}

// turn the specified amount of degrees.
// Negative = left, positive = right.
void turn(int degrees)
{

  slowStart(degrees);

  // slowStart and slowStop turns 1 degree.
  // therefore full speed is only reached w/ more than 1 degree movement.
  if (abs(degrees) > 1)
  {
    fullSpeed(degrees);
  }

  slowStop(degrees);
}

void slowStart(int degrees)
{
  digitalWrite(8, HIGH);

  if (degrees < 0)
  { // turn left
    // 25% power
    analogWrite(5, 63);
    delay(DELAY25);

    // 50% power
    analogWrite(5, 127);
    delay(DELAY50);

    // 75% power
    analogWrite(5, 191);
    delay(DELAY75);
  }
  else
  { // turn right
    // 25% power
    analogWrite(3, 63);
    delay(DELAY25);

    // 50% power
    analogWrite(3, 127);
    delay(DELAY50);

    // 75% power
    analogWrite(3, 191);
    delay(DELAY75);
  }

  digitalWrite(8, LOW);
}

void fullSpeed(int degrees)
{
  digitalWrite(9, HIGH);

  // the time needed to turn this amount of degrees
  // 1 degree of movement has already been handled by start/stop
  long delaytimer = (abs(degrees) - 1) * ONE_DEGREE_FULL_MS;
  Serial.println("Will be turning at full speed for: ");
  Serial.print(delaytimer);
  Serial.println(" ms.");

  if (degrees < 0)
  {
    // turn left
    Serial.println("Turning left at full speed");
    analogWrite(5, 255);
    delay(delaytimer);
    analogWrite(5, 0);
  }
  else
  {
    // turn right
    Serial.println("Turning right at full speed");
    analogWrite(3, 255);
    delay(delaytimer);
    analogWrite(3, 0);
  }

  digitalWrite(9, LOW);
}

void slowStop(int degrees)
{
  digitalWrite(10, HIGH);

  if (degrees < 0)
  { // turn left
    // 75% power
    analogWrite(5, 191);
    delay(DELAY75);

    // 50% power
    analogWrite(5, 127);
    delay(DELAY50);

    // 25% power
    analogWrite(5, 63);
    delay(DELAY25);

    // stop turning
    analogWrite(5, 0);
  }
  else
  { // turn right
    // 75% power
    analogWrite(3, 191);
    delay(DELAY75);

    // 50% power
    analogWrite(3, 127);
    delay(DELAY50);

    // 25% power
    analogWrite(3, 63);
    delay(DELAY25);

    // stop turning
    analogWrite(3, 0);
  }

  digitalWrite(10, LOW);
}

Konklusion

Som udgangspunkt har det ikke været muligt at fuldføre den fysiske opbygning af en robot som opfylder de krav som er stillet, men gennem denne blog er der blevet beskrevet og simuleret alle delene til opbygningen af en sådan robot. Dermed er vi nået i mål med et digitalt proof of concept, som det burde være ligetil at overføre til virkeligheden.
Denne mere eller mindre simulerede robot er i stand til at dreje en solcelle med en motor, og ved hjælp af 3 lys-sensitive resistorer som sensorer kan den bedømme hvilken vej den bør dreje for at vende solcellen bedst muligt mod solen.

Hvis der skulle laves eventuelle forbedringer til systemet, så kunne en idé være at implementere en form for aften / solnedgangs-detektering som vender solcellen 180 grader ved solnedgang, for at forbedre den effektive tid solcellen får belysning. Det nuværende system vender først solcellen når solen står op igen, og er derfor ikke fuldt effektiv i den tid, som det tager at dreje om til den rigtige position hver morgen.
Et andet punkt der kan forbedres på, især hvis systemet videreudvikles til en større skala, kunne være den bløde start/stop fase af bevægelsen. Disse kan udglattes yderligere, da den nuværende løsning stadig springer i 25% effektivitets intervaller – ideelt set ville motoren starte og stoppe i en helt blød kurve, der gik op og ned med den mindst mulige forskel ad gangen.

Video-test

Der er udført en test af løsningen, der viser flere forskellige typer rotationer og positioner – heriblandt drejninger på en enkelt grad, og en vending på 180 grader, der bliver inverteret til -180 grader. Disse kan ses i videoen herunder.

Leave a Reply