Solar Tracker mit Schrittmotoren und OLED-Display

Jeden Tag wird mehr und mehr bewiesen, dass wir uns in einem Klimawandel befinden, der auf die Umweltverschmutzung zurückzuführen ist. Es gibt keinen Zweifel daran, die extremen Wetterphänomene in Europa werden immer häufiger. Das war die Frage, die ich mir gestellt habe. Es gibt auf der Welt eine saubere und gleichzeitig billige Energiequelle, nämlich die Sonne. Hier in Spanien haben wir viele Stunden Licht, die wir mit Hilfe von Solarmodulen nutzen können. Um die beste Leistung zu erzielen, müssen sie idealerweise immer senkrecht zu den Sonnenstrahlen ausgerichtet sein. Eine Möglichkeit, dies zu erreichen, ist der Bau eines Solarlicht-Trackers.

Bei dem hier entwickelten Projekt handelt es sich um zwei Bewegungsachsen, sowohl horizontal als auch vertikal. So werden die Solarmodule immer senkrecht zu den Sonnenstrahlen ausgerichtet und ihre Effizienz maximiert. Als Referenz für die Lichtmenge, die das Solarpanel erreicht, werden 4 LDR-Widerstände verwendet (Light Dependent Resistor; lichtabhängiger Widerstand). Wir verwenden zwei Endschalter, um zu erkennen, wann die Sonnenuntergangs- und Sonnenaufgangsposition erreicht ist. Da es sich so zu sagen um ein "grünes" Projekt handelt, habe ich für das Chassis, die Motorhalterung, die LDR-Widerstände und das Solarpanel einige Obstkisten aus Sperrholz und ein Paar Endschalter von einer alten Maus wiederverwendet.

Benötigte Hardware und Materialien

1

Mega 2560 Board mit ATmega2560 mit USB Kabel

1

0,96 Zoll OLED SSD1306 Display I2C 128 x 64 Pixel

4

Fotowiderstand Photo Resistor Dioden Set 150V 5mm LDR5528 GL5528

4

Widerstand 10 KOhm

1

Widerstand 220 Ohm

2

ULN2003 Schrittmotor mit Antrieb Modulplatine

1

Solarpanel 5V 1,5W Wasserdichtes Polysilizium Mini Solar Modul

2

Mikro Endschalter mit Roller

1

PCB Board Set Lochrasterplatine

 

Kabel

 

Holz

 

Benötigte Software

  • Arduino DIE
  • solar_light_tracker Sketch
  • Wire Library (integriert)
  • Adafruit_GFX library (über Bibliotheksverwalter)
  • Adafruit_SSD1306 library (über Bibliotheksverwalter)

Schaltplan

Download des Schaltplans

Beschreibung der Funktionsweise und des Quellcodes

Wie auf dem folgenden Foto zu sehen ist, befinden sich sowohl das Solarpanel als auch die LDR-Widerstände in derselben Ebene. Dies ist notwendig, da die Lichtmenge, die das Solarpanel empfängt, dieselbe sein muss, die auch auf die vier LDRs trifft. Diese sind in einer 2 x 2-Matrix angeordnet.

Die folgende Zeichnung zeigt die Anordnung der LDR-Widerstände von vorne gesehen. Diese Referenzen werden bei den Berechnungen berücksichtigt, um die beste Lichtmessung zu erhalten.

Das Herzstück des Aufbaus ist der Mega 2560 R3, der die Messwerte der 4 LDR-Widerstände empfängt, die notwendigen Berechnungen durchführt, die beiden Schrittmotoren bewegt und die Spannungsdaten an das OLED-Display sendet.

Als erstes müssen die notwendigen Bibliotheken für die I2C-Kommunikation und das OLED-Display in den Sketch eingebunden werden.

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

Anschließend müssen wir die Anzahl der Pixel für Breite und Höhe des OLED-Bildschirms definieren und ein Bildschirm-Objekt implementieren. Als Konstruktor-Parameter übergeben wir die Variablen der Anzahl der Pixel für Breite und Höhe des Bildschirms, die Referenz auf das Wire-Objekt. Außerdem hier noch die -1 für den Anschluss des Reset-Pins, wenn er vorhanden ist.

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

Wir deklarieren vier Variablen, um anzugeben, welcher LDR-Widerstand mit welchem Port des Mikrocontrollers verbunden ist. Außerdem deklarieren wir auch vier weitere Variablen für den Wert des Widerstandes, wenn das Licht auftrifft.

int LDR_SD = A0;
int LDR_SI = A1;
int LDR_II = A2;
int LDR_ID = A3;

int SD, SI, II, ID; 

Um Durchschnittswerte in den jeweils gleichen Spalten und Zeilen der gemessenen vier Werte der LDR-Widerstände zu berechnen, deklarieren wir weitere vier Variablen. Dadurch erhalten wir eine Referenz, um die Ausrichtung des Solarpanels zu verändern. In der obigen Zeichnung sehen Sie, welche Widerstände auf jeder Seite beteiligt sind. Wir deklarieren auch eine Toleranzvariable, um ständige Bewegungen zu vermeiden.

int sup_aver, inf_aver, right_aver, left_aver;     
int tolerance = 10;

Für die Spannungsmessung am Solarpanel deklarieren wir die Variable SPV. Sie enthält den Pin, an den wir das Panel anschließen (in unserem Projekt ist es Pin 4). Die Variable solar_panel_read für den Eingangswert der Messung der Spannung (Es handelt sich um analoge Werte) und die Variable solar_panel_voltage, um die Analog-Digital-Umwandlung durchzuführen. Mit dem Wert können wir arbeiten und ihn auf dem OLED-Bildschirm anzeigen.

int SPV = A4;
int solar_panel_read;
float solar_panel_voltaje;

Für die Geschwindigkeit der Schrittmotoren werden wir zwei Variablen deklarieren. Die Variable retardo (sp. delay) ist für die Bewegung der Motoren im normalen Betrieb gedacht. Die Variable retardo_inicializacion (sp. delay_initialisation) verwenden wir für die Bewegung des horizontalen Motors, wenn er sich in die Ausgangsposition bewegt.

int retardo = 5;
int retardo_inicializacion = 15;

Es wurden zwei Endschalter für Sonnenauf- und untergang in die Anlage eingebaut. Wenn der Sonnenaufgang stattfindet, befindet sich die Anlage in der Sonnenaufgangsposition. Der Sonnenaufgangsendschalter (switch_sunrise) ist normal closed (NC) und mit Pullup-Widerstand angeschlossen. Er ist immer geschlossen, wodurch dauerhaft 5V am Pin anliegen und sein Zustand somit HIGH ist. Er wird gedrückt und damit geöffnet, wenn sich das Panel in einer fast vertikalen Position befindet. Es zeigt in östlicher Richtung, da dort die Sonne aufgeht. Wenn das Panel während des Tages der Bewegung der Sonne am Himmel folgt, wird es bei Erreichen der Sonnenuntergangsposition wieder fast senkrecht stehen und Richtung Westen ausgerichtet sein.

Dann wird der normal open (NO) Sonnenuntergangs-Endschalter (switch_sunset) aktiviert. Er ist mit Masse und dem RESET-Pin des Mikrocontrollers verbunden. So wird er zurückgesetzt, wenn der Pin auf Masse gelegt wird. Dadurch kehrt das Solarpanel in die Sonnenaufgangsposition zurück. Dieser Code wird im setup()-Teil des Sketches ausgeführt. In den nächsten beiden Zeilen konfigurieren wir also den Anschluss des Endschalters an Port 10 des Mikrocontrollers und definieren ihn standardmäßig mit HIGH.

int sunrise_pin = 10;
int switch_sunrise = HIGH;

Nachdem wir die Bibliotheken eingebunden, die Variablen deklariert und die Komponentenobjekte instanziiert haben, müssen wir sie in der Methode setup() initialisieren. Als erstes initialisieren wir den seriellen Monitor und den OLED-Bildschirm an Adresse 0x3C, wir löschen den Bildschirm und stellen die Textfarbe Weiß ein.

Serial.begin(9600);

if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
  Serial.println(F("SSD1306 allocation failed"));
  for(;;);
}

display.clearDisplay();
display.setTextColor(WHITE);

Als Nächstes konfigurieren wir die Mikrocontroller-Pins, die von den LDR-Widerständen, dem Solarpanel, den Motoren und dem Endschalter für den Sonnenaufgang verwendet werden, als Eingang oder Ausgang.

pinMode (LDR_SD, INPUT);      // LDR resistors
pinMode (LDR_SI, INPUT);
pinMode (LDR_II, INPUT);
pinMode (LDR_ID, INPUT); 

pinMode (SPV, INPUT);         // Solar panel

pinMode (5, OUTPUT);          // Horizontal motor
pinMode (4, OUTPUT);
pinMode (3, OUTPUT);
pinMode (2, OUTPUT);

pinMode (9, OUTPUT);          // Vertical motor
pinMode (8, OUTPUT);
pinMode (7, OUTPUT);
pinMode (6, OUTPUT);

pinMode (sunrise_pin, INPUT); // Sunrise limit switch

Die letzten Punkte, die wir konfigurieren werden, sind die Zustände des LDR-Widerstands und des Solarpanels, wenn der Mikrocontroller initialisiert wird. Als Erstes müssen wir den Zustand des Endschalters switch_sunrise kennen. Wenn er sich im HIGH-Zustand befindet, d.h. nicht gedrückt ist, zeigen wir eine Meldung über den seriellen Monitor an und führen die Methode inicializacion_motor_horizontal()  (initialization_horizontal_motor) aus. Solange er nicht gedrückt ist, bewegt sich der Motor der horizontalen Achse, bis dieser Endschalter gedrückt wird und die Initialisierung abgeschlossen ist.

switch_sunrise = digitalRead(sunrise_pin);
        
while (switch_sunrise == HIGH) { 
  Serial.println("Inicializando motor horizontal, espere ......");
  inicializacion_motor_horizontal();
  switch_sunrise = digitalRead(sunrise_pin);
}

Wir sind mit der setup()-Methode fertig, jetzt werden wir die loop()-Methode analysieren, die kontinuierlich ausgeführt wird. In dieser Methode werden das empfangene Licht gemessen und die Motoren bewegt.

Ein LDR (Light Dependent Resistor - lichtabhängiger Widerstand) ändert seinen Widerstand mit der Lichtmenge, die auf ihn fällt. Die beste Leistung wird erzielt, wenn das Licht senkrecht einfällt. Wie Sie im Schaltbild sehen können, wurde eine Spannungsteilerschaltung mit jedem LDR und einem 10K-Widerstand hergestellt. Wenn wir sie an eine Spannung von 5V anschließen und jeder LDR mit einem analogen Port des Mikrocontrollers verbunden ist, können wir die jeweils variierende Spannung messen. Wir werden die Spannungswerte jedes LDRs in den Variablen speichern, die wir zu diesem Zweck deklariert haben.

SD = analogRead(LDR_SD);
SI = analogRead(LDR_SI);
II = analogRead(LDR_II);
ID = analogRead(LDR_ID);

Die Berechnungen, die der Mikrocontroller für die Bewegung der Motoren durchführen muss, lauten wie folgt:

Es werden jeweils die Werte der horizontal gelegenen LDRs addiert und dann halbiert. Dann werden die jeweils vertikal liegenden LDRs ebenfalls addiert und halbiert. So erhalten wir die Mittelwerte. Die Ergebnisse speichern wir in den zuvor deklarierten Variablen. Die Anordnung der LDRs sehen Sie oben in der Abbildung.

sup_aver = (SD + SI)/2;
inf_aver = (ID + II)/2;
right_aver = (SD + ID)/2;
left_aver = (SI + II)/2;

Nun, da wir die Durchschnittswerte haben, müssen wir die beiden Motoren in Bewegung setzen. Dazu vergleichen wir die Werte der gegenüberliegenden Seiten mit der Toleranz. Immer wenn die berechnete Differenz der Werte der verglichenen Seiten größer ist, als die Toleranz (int tolerance = 10;), müssen wir mit Hilfe der Methoden paso_izq(), paso_der(), paso_up() y paso_down() (step left, right, up und down) dem entsprechenden Motor den Befehl geben. Er ändert die Richtung der Seite, deren Wert höher ist, bis der Wert der Differenz kleiner als die Toleranz ist.

/***************** Horizontal Motor **************************/
if (right_aver == left_aver) {
   apagado_hor();
}
  
if (right_aver > left_aver && (right_aver-left_aver) > tolerance) {
  paso_izq();
}
 
if (left_aver > right_aver && (left_aver-right_aver) > tolerance) {
  paso_der();
}
apagado_hor();
delay(500);

/**************** Vertical Motor ****************************/

if (sup_aver == inf_aver) {
   apagado_ver();
}
  
if (sup_aver > inf_aver && (sup_aver-inf_aver) > tolerance) {
    paso_up();
}
 
if (inf_aver > sup_aver && (inf_aver-sup_aver) > tolerance) {
    paso_down();
}
apagado_ver();
delay(500);

Für die Bewegung des Solarpanels und der LDR-Widerstände wurden zwei 28BYJ-Motoren und die dazugehörigen ULN2003-Controllermodule gewählt. Wobei ein Motor auf die Bewegung der X-Achse und der andere Motor auf die Y-Achse wirkt.

Hinweis: Es sollte eine externe Spannungsquelle für die Versorgung der Motoren angeschlossen werden.

In den folgenden Zeilen des Sketches sehen Sie, dass immer zwei Spulen, also zwei Pins für einen Schritt des Motos aktiviert werden. Die Geschwindigkeit der Motordrehung regulieren wir mit delay(retardo).

void paso_XXX() {
  digitalWrite(5, LOW); 
  digitalWrite(4, LOW);  
  digitalWrite(3, HIGH);  
  digitalWrite(2, HIGH);  
     delay(retardo); 
  digitalWrite(5, LOW); 
  digitalWrite(4, HIGH);  
  digitalWrite(3, HIGH);  
  digitalWrite(2, LOW);  
     delay(retardo); 
  digitalWrite(5, HIGH); 
  digitalWrite(4, HIGH);  
  digitalWrite(3, LOW);  
  digitalWrite(2, LOW);  
     delay(retardo); 
  digitalWrite(5, HIGH); 
  digitalWrite(4, LOW);  
  digitalWrite(3, LOW);  
  digitalWrite(2, HIGH);  
     delay(retardo);  
}

Um die Spannungswerte zu visualisieren, die das Solarmodul zu einem bestimmten Zeitpunkt erhält, haben wir einen 0,96-Zoll-OLED-Bildschirm installiert. Die Spannung des Solarpanels ermitteln wir an Pin 4. Vor der Ausgabe auf dem Display müssen wir den analogen in einen digitalen Wert umwandeln.

Das Solarpanel liefert eine maximale Spannung von 5V, die dem am analogen Eingang eingelesenen Wert 1023 entspricht. Mit einer einfachen Operation können wir diesen Wert umwandeln und auf dem Bildschirm ausgeben.

solar_panel_read = analogRead(SPV);
solar_panel_voltaje = (solar_panel_read*5.0) / 1023.0;
oled_message();

Die Methode zur Anzeige von Daten auf dem OLED-Bildschirm (oled_message()) ist sehr einfach. Sie führt folgende Schritte aus:

Löschen des Bildschirms, Einstellen der Textgröße auf 2, Platzieren des Cursors auf den X- und Y-Koordinaten in Pixeln und Vorbereiten des Textes, um ihn in die erste Zeile des Textes zu schreiben. Textgröße auf 3 einstellen, Cursor erneut auf die neuen X- und Y-Koordinaten bringen, den neuen anzuzeigenden Text vorbereiten (Spannungswert mit 2 Dezimalstellen des Solarpanels) und die letzte Zeile ist die Ausgabe des gesamten zuvor eingestellten Textes.

void oled_message() {
  display.clearDisplay();
  display.setTextSize(2);
  display.setCursor(7,0);
  display.print("Solar Vols");
  display.setTextSize(3);
  display.setCursor(20, 30);
  display.print(solar_panel_voltaje, 2);
  display.display();
}

Skizzen der Bauteile mit Maßangaben als PDF Download

Der Leser Thorsten Hartwig hat aus der Vorlage ein Modell für den 3D-Drucker erstellt und Ihn freundlicherweise mit uns geteilt. Vielen Dank noch einmal an dieser Stelle. Zur Projektseite auf Thingiverse geht es hier entlang.

Jetzt, wo es Sommer ist und die Sonne scheint, könnte man daraus zum Beispiel ein Handyladegerät bauen. Ein passendes Projekt dazu folgt demnächst.

DisplaysFür arduinoProjekte für anfänger

11 commentaires

Andreas Wolter

Andreas Wolter

@Thorsten Hartwig: Ich habe mir die Bilder kurz angesehen. Sieht sehr gut aus. Ich verlinke das im Projekt. Vielen Dank!

Grüße,
Andreas Wolter
AZ-Delivery Blog

Thorsten Hartwig

Thorsten Hartwig

Wie versprochen, hier die STL Dateien. Es ist so wesentlich einfacher als mit Holz. Habe natürlich einiges geändert, 3D-Druck ist halt ein völlig anderes Konstruieren. Eine finale Version des Solarpanel-Rahmens wird gelegentlich upgedated. Aber ohne die Skizzen wäre ich völlig hilflos gewesen, nochmals vielen Dank an den Autor.

https://www.thingiverse.com/thing:5437654

Freue mich über jeden Make. Haut rein.

Pontifex42

Pontifex42

Vielen vielen Dank für die Zeichnungen. Ich habe das soweit in Fusion360 abgezeichnet. Das ist aber alles für Holzschnitt gedacht. Für 3D Druck muss ich noch einiges ändern. Z.B. kann man alle Löcher gleichmit drucken anstatt später zu bohren. Ausserdem kann man einige Sachen gleich am Stück machen anstatt aus flachen Einzelteilen zusammenzustecken. Zudem sind einige Stellen auf “Maß” gemacht, d.h. man steckt ein 30mm Stück in einen 30mm Slot. Bei Druckteilen sollte man da ein oder zwei Zehntel mm Spiel vorsehen, spart das Feilen. Die Materialstärke von 3mm ist eh nicht so optimal für 3D-Druck, da werden es eher 1,5-2mm.
Ich schicke die Dateien zum Veröffentlichen, wenn ich das erfolgreich zusammengebaut habe. Vermutlich in den nächsten 5 Tagen.

Andreas Wolter

Andreas Wolter

Wir haben am Ende des Beitrags einen Link zu einer PDF-Datei ergänzt. Sie enhält Skizzen mit Maßangaben der einzelnen Bauteile.

Wenn Sie Parts für den 3D-Drucker erstellen und diese bei uns veröffentlichen möchten, dann geben Sie Bescheid. Wir können Sie dann hier ebenfalls veröffentlichen.

Grüße,
Andreas Wolter
AZ-Delivery Blog

Andreas Wolter

Andreas Wolter

Was die Maße angeht, ist der Autor des Beitrags dabei, eine Übersicht anzufertigen. Die werden wir nachreichen.

Grüße,
Andreas Wolter
AZ-Delivery Blog

Jack

Jack

Gibt es abmessungen von die drehscheibe und so weiter?
Danke.
Jack.

Peter

Peter

@Pontifex42
Bitte ich hätte Interesse an den..STL files
Danke!

Andreas Wolter

Andreas Wolter

@Alex: das ist korrekt. Nach Aussage des Autors hatte er zur Zeit der Erstellung des Projektes nur dieses andere Display zur Hand. Es hat jedoch den gleichen Chip und wird genauso verwendet, wie das verlinkte Display.

@Marco: theoretisch wäre es möglich. Es müssen jedoch Anpassunge an den Verbindungen und im Code vorgenommen werden. Der analoge Pin zum Auslesen der Spannung des Solarpanels muss dort für die Verbindung des OLEDs verwendet werden.
(Info des Autors)

Grüße,
Andreas Wolter
AZ-Delivery Blog

Pontifex42

Pontifex42

@Marco: Ja, Nano geht auch. Hab jetzt die Pins nicht durchgezählt, aber sollte reichen. Und wenn es knapp mit den Pins wird: einfach die Endschalter parallel zu zwei der LDRs schalten, das lässt sich dann per Software erkennen.
@Alex: Es gibt diese Displays tatsächlich in einer Variante, die oben fix einen gelben Bereich haben und darunter blau oder weiss sind. Findet man bei Suche nach “OLED Display blue yellow”, dauert halt einen Augenblick.
@AZDelivery: Wollte das schon lange mal nachbauen, aber da ist keine Skizze für die Holzteile. Gibt es da was? Bin etwas unbegabt beim mechanischen konstruieren. Würde ich sowieso nicht aus Holz machen sondern 3D-Drucken. Falls jemand dann interesse an den STL-Dateien hat, kann ich die gern publishen.

Marco

Marco

Hallo,
Ein interessantes Projekt. Ich habe noch einen Nano V3.0 mit Atmega328 CH340 herumliegen. Funktioniert das auch mit dem Arduino?
Danke Maro

Alex

Alex

Hallo,

das angegebene Display ist doch eigentlich weiss bzw. monochrom, wie ist es möglich, dass der angezeigte Text gelb und blau ist ?

Grüße

Laisser un commentaire

Tous les commentaires sont modérés avant d'être publiés