Dual Axis Solar System Windgeschwindigkeit

Gut das die Forensoftware warnt.

Ich habs jetzt nach zwei Kaffee verstanden

Dieser Beitrag ist dann obsolet - aber vielleicht für spätere Leser noch hilfreich (und ich habe ihn nun mal fertig).

Zum Verständnisvon Funktionsdeklaration, -implementierung und -aufruf:

Man nutzt wie selbstverständliche eine Funktion namens pinMode - das ist der Funktionsaufruf:

pinMode(motorPin, OUTPUT);

Die Funktionsdefinition und -implementierung siehst man nicht, das stellt die Mimik hinter der Arduino IDE bereit.
Diese IDE erwartet von uns z.B. die Implementierung von setup() und loop() - die stellst man in einem Sketch bereit (Implementierung). Den Aufruf davon sehen wir normalerweise wieder nicht.

Bei eigenen Funktionen a la windGeschwindigkeit ist das anders - da hat man alles selbst in der Hand:

// Deklaration - muss vor dem ersten Aufruf erfolgen.
void windGeschwindigkeit();
...
void setup() {
}

void loop() {
...
  // Aufruf - hier wird in die Funktion abgebogen
  windGeschwindigkeit(); 
  // und danach geht es hier weiter
}
// loop ENDE!

// Implementierung
void windGeschwindigkeit() {
  // hier steht der Code, der beim Aufruf - auch gerne mehrfach - ausgeführt wird
}

Gruß Walter

wno158:
Bei eigenen Funktionen a la windGeschwindigkeit ist das anders - da hat man alles selbst in der Hand:

// Deklaration - muss vor dem ersten Aufruf erfolgen.

void windGeschwindigkeit();

Meist wird die Deklaration nicht benötigt, das macht die IDE für uns. Das gilt auch für diesen Fall, habe es gerade mal probiert.

Hallo zusammen,

ich hatte eben bei #39 viel mehr geschrieben. Über die Hälfte des Textes ist verschwunden 

Also jedenfalls werden die Funktionen jetzt aufgerufen. Danke nochmal für die Geduld mit mir an HotSystems!

Nun habe ich noch ein Problem. Die Wind- Funktion funktioniert noch nicht richtig.
Ich vermute es liegt daran, dass ich den Sketch, den mir agmue zur Verfügung gestellt hat, abgeändert hatte.

Ich hatte folgende Zeilen aus dem Sketch genommen, da ich damit nichts anfangen konnte, und meine Relais im Hz-Takt angezogen haben.

}

if (jetzt - herz >= 111) { // zum Testen blockadearmer Programmierung
herz = jetzt;
digitalWrite(herzschlagPin, !digitalRead(herzschlagPin));
}
}

Nun ist es so, dass sobald das Anemometer angepustet wird, die Serielle Schnittstelle anfängt schnell durchzulaufen. Sonst passiert nichts.

Dann solltest du noch mal auf agmue warten.
Der hat sicher noch eine Idee.

hackbartho:
Ich vermute es liegt daran, dass ich den Sketch, den mir agmue zur Verfügung gestellt hat, abgeändert hatte.

Nö, das ist nur der Herzschlag zur Überprüfung der blockadearmen Programmierung. Ein Relais soll da nicht an den Ausgang, eher eine LED.

hackbartho:
Nun ist es so, dass sobald das Anemometer angepustet wird, die Serielle Schnittstelle anfängt schnell durchzulaufen. Sonst passiert nichts.

Welcher Text?

HotSystems:
Dann solltest du noch mal auf agmue warten.
Der hat sicher noch eine Idee.

Möglicherweise ja, aber momentan heiße ich Godot und warte auf das aktuelle Programm!

EDIT: Für Literaturkundige: Ich heiße natürlich Estragon und warte auf Godot, also das Programm. Aber ich bin auch etwas vergeßlich :slight_smile:

Guten Morgen zusammen, guten Morgen Godot,

dann hatte ich das mit dem Herzschlag richtig verstanden.

Ich habe nochmal über die Funktion Windgeschwindigkeit () nachgedacht.
Momentan wäre es in dem Sketch ja so, dass wenn die Sonne scheint das Solarpanel ausgefahren ist. Sollte es jetzt windig werden und die Windgeschwindigkeit überschritten werden, würde das Solarpanel einfahren wollen. Das würde jetzt ja zu einem undefinierten Zustand führen. Müsste man da bei der Funktion Windgeschwindigkeit() ein break setzten, damit das Panel nicht wieder ausfährt?

Hier der aktuelle Sketch

#define rxPin =2
#define txPin =3
#define Motor1 4 // Motor 1: pin 4 goes to DIR // Motor 1: pin 5 goes to STEP

int linearPin = A5;
int linearPos = 0;
const byte motorPin = 9;
const byte reverserPin = 10;
const int northLDRPin = A4;
const int southLDRPin = A1;
int WestLDRPin = A3; // West photoresistor sensor pin
int EastLDRPin = A2; // East photoresistor sensor pin
int WestLDRValue; // West photoresistor circuit Vout reading
int EastLDRValue; // East photoresistor circuit Vout reading
int solarPin = A0;
int solarValue;
float angLR = 0.0; // Initial E-W tracking angle
int angMin = -110; // Minimum angle for the motors to approach
int angleMax = 110; // Maximum angle for the motors to approach
float stepsize = 1.8; // Degrees rotated through per step
const float thresholdLR = 0.03; //volts-Natural Difference between L and R sensors in full sun
int enablePin = 6;
int northLDR[10];                                     // 10 sample readings from sensor on the north side
int southLDR[10];                                     // 10 sample readings from sensor on the south side
const int sample_time_interval = 500;                // Change this value to set the interval between each sample is taken (1000 ms)
const long solar_panel_adjustment_interval = 1000;    // Change this value to set the interval between each adjustment from the solar panel (6000ms)
float wind = 0.0;
const unsigned long MESSINTERVALL = 1000; // in ms
unsigned long jetzt = 0, vorhin = 0, herz = 0;
volatile unsigned int zaehler = 0;
const byte anemoPin=3;
void countWind();
void windGeschwindigkeit();

void setup()
{
   
  attachInterrupt(digitalPinToInterrupt(anemoPin), countWind, RISING);  
  pinMode(motorPin, OUTPUT);
  pinMode(reverserPin, OUTPUT);
  digitalWrite(motorPin, LOW);
  digitalWrite(reverserPin, LOW);
  pinMode(northLDRPin, INPUT);
  pinMode(southLDRPin, INPUT);
  pinMode(linearPin, INPUT);
  pinMode(enablePin, OUTPUT);
  digitalWrite(enablePin, LOW);
  Serial.begin(9600);
  delay(5000);
}

void loop() {
    
    
  
  linearPos = analogRead(linearPin);
  int solar_input_north = 0;                                     // Sun light intensity readings from sensor north
  int solar_input_south = 0;                                     // Sun light intensity readings from sensor south

  for ( int i = 0; i < 10; i++)
  {
    northLDR[i] = analogRead(northLDRPin);                    // Taking the analog readings from sensor west
    southLDR[i] = analogRead(southLDRPin);
    // Taking the analog readings from sensor east
    solar_input_north  = northLDR[i] + solar_input_north;       // Sum all the inputs from sensor north
    solar_input_south = southLDR[i] + solar_input_south;       // Sum all the inputs from sensor south

    delay(sample_time_interval);
  }

  solar_input_north = (solar_input_north) / 10;                   // The the average of input signals from sensor west
  solar_input_south = (solar_input_south) / 10;                   // The the average of input signals from sensor east


  if ( solar_input_north - solar_input_south > 20)               // If the sunlight intensity is higher on the west side of the panel
  {
    digitalWrite(reverserPin, HIGH);
    digitalWrite(motorPin, HIGH);

    if (linearPos > 740)
    {
      digitalWrite(reverserPin, LOW);
      digitalWrite(motorPin, LOW);
    }
  }
  else if ( solar_input_south - solar_input_north > 20)          // Geändert solar_input_south - solar_input_south > 20
  {
    digitalWrite(reverserPin, LOW);
    digitalWrite(motorPin, HIGH);
  }
  else                                                   // If ther sunlight intensity is similar from both side of the panel
  {
    digitalWrite(reverserPin, LOW);
    digitalWrite(motorPin, LOW);                       // Stationary (1520) signal stop the solar panel from moving

  }

  delay(solar_panel_adjustment_interval);                      // Delay before another adjustment will be made

  Serial.print("North: ");
  Serial.println( solar_input_north);
  Serial.print("South: ");
  Serial.println(solar_input_south);
  Serial.print("Linear: ");
  Serial.println(linearPos);

  if (solar_input_south && solar_input_north > 950)       //Geändert   solar_input_south && solar_input_south >950
  {
    digitalWrite(reverserPin, LOW);
    digitalWrite(motorPin, HIGH);
  }

  if (linearPos < 25)
  {
    digitalWrite(reverserPin, LOW);
    digitalWrite(motorPin, LOW);
  }
    
    windGeschwindigkeit();
    schrittMotor();
}
void windGeschwindigkeit()
{

  jetzt = millis();
  if (jetzt - vorhin >= MESSINTERVALL) {
    vorhin = jetzt;
    unsigned int z = zaehler;
    zaehler = 0;
    wind = z / 2.4; // ob diese Rechnung stimmt, hängt vom Sensor ab!
    Serial.print("zaehler: ");
    Serial.print(z);
    Serial.print("\tWindgeschwindigkeit: ");
    Serial.print(wind);       //Speed in Km/h
    Serial.println(" km/h - ");

    if (wind > 14 && linearPos > 700) {
      Serial.println("Merker setzen für Einfahren!");
       digitalWrite(motorPin, HIGH);
       digitalWrite(reverserPin, LOW);
    }
      if (wind < 10) {
      Serial.println("Merker setzen für Ausfahren!");
  
    }  
  }

  

}

void countWind() {
  zaehler ++;
}

void schrittMotor() {

  WestLDRValue = analogRead(WestLDRPin); // West photoresistor circuit Vout reading
  float newWestLDRValue = map_to_float(WestLDRValue, 0, 1023, 0, 5);
  EastLDRValue = analogRead(EastLDRPin); // East photoresistor circuit Vout reading
  float newEastLDRValue = map_to_float(EastLDRValue, 0, 1023, 0, 5);

  solarValue = analogRead(solarPin); // Solar Panel circuit Vout reading
  float newSolarValue = map_to_float(solarValue, 0, 1023, 0, 5);
  delay(1000);

  if ((newWestLDRValue - newEastLDRValue) >= thresholdLR && (newWestLDRValue - newEastLDRValue) > 0 && angLR >=
      (angMin - 0.01) && angLR < angleMax) {
    turnCW(Motor1);
    angLR += stepsize;
  }
  else if (newEastLDRValue - newWestLDRValue >= thresholdLR && (newEastLDRValue - newWestLDRValue) > 0 && angLR >
           angMin && angLR < angleMax) {
    turnCCW(Motor1);
    angLR -= stepsize;
  }
  else {
    shutdown(Motor1);
    angLR = angLR;
  }
  Serial.print("Millis: ");
  Serial.println(millis()); //prints all information to be copied and pasted into a csv for later plotting
  Serial.print("AngleWestEast: ");
  Serial.println(angLR);
  Serial.print("NewSolarValue:");
  Serial.println(newSolarValue);
  Serial.print("SolarValue:");
  Serial.println(solarPin);
  Serial.print("\n");
}

void turnCW(int Digital0) {
  pinMode(Digital0, OUTPUT); // Set motor pins to output
  pinMode(Digital0 + 1, OUTPUT);
  digitalWrite(Digital0, LOW); // CW Direction
  digitalWrite(Digital0 + 1, HIGH); // Send pulse for motor to trigger on
  delay(10);
  digitalWrite(Digital0 + 1, LOW);
  delay(100);
}

void turnCCW(int Digital0) {
  pinMode(Digital0, OUTPUT); // Set motor 1pins to output
  pinMode(Digital0 + 1, OUTPUT);
  digitalWrite(Digital0, HIGH); // CCW Direction
  digitalWrite(Digital0 + 1, HIGH); // Send pulse for motor to trigger on
  delay(10);
  digitalWrite(Digital0 + 1, LOW);
  delay(100);
}

void idle(int Digital0) {
  pinMode(Digital0, OUTPUT);
  pinMode(Digital0 + 1, OUTPUT);
  digitalWrite(Digital0, LOW);
  digitalWrite(Digital0 + 1, LOW);
}

void shutdown(int Digital0) {
  pinMode(Digital0, INPUT);
  pinMode(Digital0 + 1, INPUT);
}

float map_to_float(float x, float a, float b, float c, float d)
{
  float f = (x - a) / (b - a) * (d - c) + c;
  return f;
}

hackbartho:
guten Morgen Godot,

Bei genauerer Überlegung Estragon, denn der wartet auf Godot, also das Programm, in diesem Fall aber nicht vergeblich. Das nur am Rande.

hackbartho:
Das würde jetzt ja zu einem undefinierten Zustand führen. Müsste man da bei der Funktion Windgeschwindigkeit() ein break setzten, damit das Panel nicht wieder ausfährt?

Hier wird eine Priorisierung benötigt, damit bei viel Wind das Panel geschützt ist, auch wenn die Sonne bruzelt. Wind hat eine höhere Priorität als Sonnenenstrahlung, wenn es um das Einfahren geht.

Hallo Estragon, oder Gadot, oder agmue?

Hauptsache kein Basilikum.

Danke für deine Hilfe! Das hatte ich mir auch schon gedacht, dass man die Wind-Funktion priorisieren muss.

Ist nur die Frage wie!

Gruss Silizium

Damit Du meinen Bezug kennst: Warten auf Godot

Du sitzt nun schon monatelang vor diesem Programm, kennst jede Ecke der Hardware auswendig. Mir geht das nicht so. Deine Frage zur Windgeschwindigkeit war so formuliert, daß ich ihr folgen konnte. Dein Schwenk zur Integration in Dein bestehnedes Programm erfolgte dann aber recht ansatzlos, weshalb ich dann leider nicht mehr folgen konnte. Welcher Motortyp, welche Ansteuerung?

Als Camper ohne Radio, Fernsehen und Wassertank beobachte ich gerne andere Camper, wie sie ihren Platz "erobern". Ich lernte, ein freier "Blick" zum Satelliten kann wichtig sein. Bei WoMos klappt dann irgendwann die Schüssel nach oben, wobei die Ausrichtung zum Satelliten entweder mit lautem Rufen oder auch vollautomatisch erfolgt. Ich weiß dann, wo Süden ist und wie ich mein Sonnensegel plaziere.

So ungefähr stelle ich mir auch Dein Vorhaben vor. Ist das richtig?

Die Schüsseln dürfen aber nur in einer speziellen Parkposition eingefahren werden. Ausrichtung zum Heck, erst dann runter. Ist das bei Dir auch so?

Hallo agmue,

ok jetzt kenne ich den Bezug zu Godot: Zuerst hatte ich an Gal Gadot gedacht :slight_smile:

Stimmt, du hast recht. Ich hätte mein Projekt von Anfang an besser beschreiben müssen.
Dann mache ich das mal jetzt. Besser zu spät als nie 

Mit dem Projekt habe ich ca. vor 8 Monaten angefangen. Ich habe zuerst die Mechanik konstruiert und danach die Elektronik entwickelt und gebaut/gelötet.

Die horizontale Achse wird mit einem Nema 34 Schrittmotor über einen DM860T Schrittmotortreiber angetrieben. Die vertikale Achse wird über ein Linearantrieb (400mm) gesteuert. Der Linearantrieb wird über zwei Relais angesteuert. Einmal um die Spannung an/auszuschalten und um den Pol zu wechseln fürs rein und rausfahren.

Das SolarPanel hat 100 Watt und ist von Phaesun. Angeschlossen ist das Solarpanel an einem Laderegler von Steca Tamron 4545. Der Akku hat eine Kapazität von 100 AH.

Als Lichtsensoren habe ich vier LDR 100KOhm eingesetzt.

Ich hoffe, ich habe jetzt nicht vergessen.

Sobald der Dual Axis Solar Tracker fertig ist, soll darüber ein Roboterstaubsauger geladen werden und noch ein paar andere Dinge, die ich mir noch ausdenken muss.

Ich würde hier ja gerne Bilder hochladen, aber das scheint nicht zu funktionieren?

Achso, fast vergessen. Mit dem Programmieren habe ich erst vor knapp zwei Monaten angefangen.

hackbartho:
Ich würde hier ja gerne Bilder hochladen, aber das scheint nicht zu funktionieren?

Doch, über die Vorschau.

hackbartho:
Ich hoffe, ich habe jetzt nicht vergessen.

Leider nicht, aber es wird :slight_smile:

Der Schrittmotor hat Endlagentaster? Was passiert bei Dunkelheit oder schlechtem Wetter?

Der Linearantrieb hat ein Poti für die Positionsrückmeldung?

Kann der Linearantrieb das Panel in jeder horizontalen Lage einfahren?

Ist die Anlage stationär?

Funktionen müssen miteinander Daten austauschen. Die Funktion windGeschwindigkeit() könnte als Ergebnis zurüchgeben, ob das Panel wegen zu viel Wind eingefahren werden soll oder nicht. Das kannst Du dann mit if(windGeschwindigkeit()) {} auswerten. Die Bewegung selbst gehört nicht in die Funktion, weil es dann eben zu Konflikten kommen kann.

Hallo zusammen,

hier erstmal ein paar Bilder. Dann kann man sich es besser vorstellen.

Noch ein Bild

Der Schrittmotor hat Endlagentaster?

Leider nein. Das werde ich wohl ändern müssen. Ich hatte überlegt, ob ich einen Endschalter so positioniere,
dass das Panel bei 0° steht. Das würde bedeuten, dass bei jedem Neustart der Schrittmotor sich neu ausrichten müsste.

Was passiert bei Dunkelheit oder schlechtem Wetter?

Nun ja, normalerweise würde ich die gesamte Anlage ausschalten, so lange die Bedingungen schlecht sind, bzw. die Energieausbeute gering ist. Die gesamte Schaltung verbraucht zudem auch 1,6A. Das ist sehr viel und wird hauptsächlich durch den Schrittmotor verursacht.

Der Linearantrieb hat ein Poti für die Positionsrückmeldung?

Ja, hat er.

Kann der Linearantrieb das Panel in jeder horizontalen Lage einfahren?

Ja

Ist die Anlage stationär?

Nicht unbedingt. Könnte auch mobile verwendet werden.

Und hier nochmal von der Seite

(deleted)

hackbartho:
Dann kann man sich es besser vorstellen.

Du hast einen guten Geschmack bei der Schreibtischauswahl bewiesen, den habe ich auch :grin:

Wäre es nicht sinnvoll, die Rotationsachse des Schrittmotors mit einem absoluten Positionsgeber auszustatten? Grundsätzlich ginge ein Poti, weil der Drehwinkel begrenzt ist.

hackbartho:
Die gesamte Schaltung verbraucht zudem auch 1,6A. Das ist sehr viel und wird hauptsächlich durch den Schrittmotor verursacht.

Wenn Du ein selbsthemmendes Getriebe verwendest, kannst Du den Motor bei Nichtnutzung ausschalten. Möglicherweise macht das der ENABLE-Eingang des Treibers.

Auch wenn Du die Anlage transportieren würdest, richtest Du sie aber doch nach Süden aus, oder?

Hallo agmue, hallo Peter,

vielen dank schonmal für eure tollen Vorschläge!

@Peter: WindAlarmPosition das ist eigentlich die richtige Bezeichnung für die Funktion. Du hast du schon recht, dass der Wind aus allen möglichen Richtungen kommt. Aber ich glaube, wenn ich das jetzt auch noch beachten würde, würde es das Projekt sprengen?

p.s. zur Nachführung des Seiten- und Höhenwinkels der Solarzelle habe ich noch eine Idee.

Wie würde deine Idee denn aussehen?
@agmue:

Ja, der Schreibtisch ist klasse!. Schon einige Jahre alt aber noch gut.

Wäre es nicht sinnvoll, die Rotationsachse des Schrittmotors mit einem absoluten Positionsgeber auszustatten? Grundsätzlich ginge ein Poti, weil der Drehwinkel begrenzt ist.

Ja, das wäre wirklich sinnvoll. Das mit einem Poti zu machen ist wirklich eine gute Idee. Das Problem ist nur, dass ich keinen analogen Port mehr frei habe. Evtl. wäre es auch besser gewesen einen Schrittmotor mit Closed Loop zu nehmen. Es gäbe allerdings noch die Möglichkeit eine digitale Schaltung zu bauen.

Wenn Du ein selbsthemmendes Getriebe verwendest, kannst Du den Motor bei Nichtnutzung ausschalten. Möglicherweise macht das der ENABLE-Eingang des Treibers.

Wenn du mir sagst, wo ich so ein selbsthemmendes Getriebe herbekomme, würde ich mir das mal anschauen. Aber dann müsste ich wahrscheinlich die gesamte Mechanik wieder umbauen. Alleine das kürzen der Kette hat mich schon Stunden gekostet,, da ich nicht das richtige Werkzeug hatte und ich auch keins kaufen wollte um es einmal zu benutzen.
Es ist auch ganz gut, dass der Motor unter Saft steht, sonst würde das Panel "rumflattern".

Auch wenn Du die Anlage transportieren würdest, richtest Du sie aber doch nach Süden aus, oder?

Ja, die Anlage müsste immer nach Süden ausgerichtet werden.

hackbartho:
Wenn du mir sagst, wo ich so ein selbsthemmendes Getriebe herbekomme, würde ich mir das mal anschauen.

Jedes Schneckengetriebe ist selbsthemmend. Dann flattert das Panel auch bei Wind nicht. Bei Schrittmotoren mit Planetengetriebe bin ich mir da nicht so sicher.

Um Dein Konzept grundsätzlich in Frage zu stellen: Warum eigentlich ein Schrittmotor? Ein DC-Motor mit Schneckengetriebe täte es zusammen mit einem Absolutpositionsgeber doch auch, oder?