Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

Präzise Solar-Nachführung mit Servo-Plattform für maximalen Energieertrag

Komponenten und Zubehör

Fotowiderstände (LDR, 10–20 kΩ dunkel) × 4
RGB-Neopixel-LEDs (4er-Pack, z. B. Adafruit Flora) × 1
Taster 12 mm (Normalerweise offen) × 2
Temperatursensor (z. B. TMP36 oder LM35) × 1
Arduino UNO × 1
180°-Servos (z. B. Futaba S3003 oder RobotGeek) × 2
Widerstände 10 kΩ × 6
Widerstand 220 Ω (für NeoPixel/LED) × 1
Kondensator 100 µF (Entstörung Servos) × 2
Solarmodul (ca. 80×80 mm) × 1

Benötigtes Werkzeug & Material

Apps & Entwicklungsumgebung

Projektbeschreibung

Eine weitere Implementierung einer zweiachsigen Solarnachführung mit zwei 180°-Servos und vier Fotowiderständen (LDRs). Die Plattform richtet das kleine Solarmodul kontinuierlich auf die hellste Lichtquelle aus.

Die Motoren führen kleine, stetige Bewegungen aus, um dem Lichtmaximum zu folgen. Eine RGB-LED signalisiert den Betriebszustand (aktiv/inaktiv). Zwei Taster ermöglichen manuelles Ein-/Ausschalten der Nachführung.

Zusätzlich gibt es eine serielle Kommando-Schnittstelle (Numeric Codes), um Servopositionen gezielt anzufahren. Die Bewegungsroutinen sind mit Sanftanlauf/-stopp implementiert, um mechanische Erschütterungen zu vermeiden.

Arduino-Code (Q2 Version 2.0, C/C++)

Der Sketch ist modular aufgebaut: Initialisierung, Hauptschleife, Serielle Kommandos, Glättungsroutinen, Sensor-Mittelwertbildung.

// Scott Mangiacotti, Tucson AZ, May 2018 – Q2 v2.0
#include <Servo.h>

const int GIVE_BACK_TIME = 125; // Loop-Pause ms

// Pins
const int PIN_BTN_RED   = 4;   // Aus-Schalter
const int PIN_BTN_GREEN = 2;   // Ein-Schalter
const int PIN_LDR_TL    = A3;  // Links oben
const int PIN_LDR_TR    = A2;  // Rechts oben
const int PIN_LDR_BL    = A1;  // Links unten
const int PIN_LDR_BR    = A0;  // Rechts unten
const int PIN_LED_R     = 9;   // NeoPixel R (PWM)
const int PIN_LED_G     = 11;  // NeoPixel G (PWM)
const int PIN_LED_B     = 10;  // NeoPixel B (PWM)
const int PIN_SERVO_TWIST = 5; // Basis-Drehung
const int PIN_SERVO_TILT  = 6; // Neigung

// Globale Zustände
bool running = false;
bool trackEnabled = false;
bool verbose = false;
Servo servoTwist, servoTilt;
int cmdTwistPos, cmdTiltPos;
bool movingTwist = false, movingTilt = false;
int ldrTL, ldrTR, ldrBL, ldrBR;

void setup() {
  Serial.begin(9600);
  pinMode(PIN_BTN_RED, INPUT); pinMode(PIN_BTN_GREEN, INPUT);
  pinMode(PIN_LED_R, OUTPUT); pinMode(PIN_LED_G, OUTPUT); pinMode(PIN_LED_B, OUTPUT);
  startup(); // Selbsttest & Initialposition
}

void loop() {
  // Serielle Kommandos verarbeiten
  if (Serial.available() > 0) {
    int code = Serial.parseInt();
    processSerial(code);
  }

  // Grüner Taster: Tracking starten
  if (digitalRead(PIN_BTN_GREEN) == HIGH && !running) {
    enableTracking(); trackEnabled = true;
  }
  // Roter Taster: Tracking stoppen
  if (digitalRead(PIN_BTN_RED) == HIGH && running) {
    disableTracking();
  }

  // Sensoren lesen
  readLDRs();
  float topAvg = avgTop(), botAvg = avgBottom();
  float leftAvg = avgLeft(), rightAvg = avgRight();

  if (running) {
    if (trackEnabled) trackToLight(topAvg, botAvg, leftAvg, rightAvg);
    else { smoothMoveTwist(); smoothMoveTilt(); }
  }
  delay(GIVE_BACK_TIME);
}

// --- Tracking-Logik ---
void trackToLight(float top, float bot, float left, float right) {
  const int STEP = 5; // Grad pro Zyklus
  int twist = servoTwist.read();
  int tilt  = servoTilt.read();

  if (left > right) twist += STEP; else if (right > left) twist -= STEP;
  if (top > bot)    tilt  += STEP; else if (bot > top)    tilt  -= STEP;

  twist = constrain(twist, 0, 179);
  tilt  = constrain(tilt, 45, 135); // Mechanischer Begrenzung

  servoTwist.write(twist);
  servoTilt.write(tilt);

  if (verbose) {
    Serial.print("LDRs: "); Serial.print(ldrTL); Serial.print(","); Serial.print(ldrTR);
    Serial.print(","); Serial.print(ldrBL); Serial.print(","); Serial.println(ldrBR);
    Serial.print("Avgs: T="); Serial.print(top); Serial.print(" B="); Serial.print(bot);
    Serial.print(" L="); Serial.print(left); Serial.print(" R="); Serial.println(right);
    Serial.print("Move: Twist="); Serial.print(twist); Serial.print(" Tilt="); Serial.println(tilt);
  }
}

// --- Sanfte Servobewegung (Ramp) ---
void smoothMoveTwist() {
  const int STEP = 1;
  int cur = servoTwist.read();
  if (cur == cmdTwistPos) { movingTwist = false; return; }
  movingTwist = true;
  int next = (cur < cmdTwistPos) ? cur + STEP : cur - STEP;
  next = constrain(next, 0, 179);
  servoTwist.write(next);
  if (verbose) { Serial.print("Twist step: "); Serial.print(next); Serial.print("/"); Serial.println(cmdTwistPos); }
}

void smoothMoveTilt() {
  const int STEP = 1;
  int cur = servoTilt.read();
  if (cur == cmdTiltPos) { movingTilt = false; return; }
  movingTilt = true;
  int next = (cur < cmdTiltPos) ? cur + STEP : cur - STEP;
  next = constrain(next, 0, 179);
  servoTilt.write(next);
  if (verbose) { Serial.print("Tilt step: "); Serial.print(next); Serial.print("/"); Serial.println(cmdTiltPos); }
}

// --- Sensor-Hilfsfunktionen ---
void readLDRs() {
  ldrTL = analogRead(PIN_LDR_TL); ldrTR = analogRead(PIN_LDR_TR);
  ldrBL = analogRead(PIN_LDR_BL); ldrBR = analogRead(PIN_LDR_BR);
}
float avgTop()    { return (ldrTL + ldrTR) / 2.0; }
float avgBottom() { return (ldrBL + ldrBR) / 2.0; }
float avgLeft()   { return (ldrTL + ldrBL) / 2.0; }
float avgRight()  { return (ldrTR + ldrBR) / 2.0; }

// --- Serielle Kommando-Verarbeitung ---
// Format: CCVVV  (CC=Kommando-Kategorie 10/11/12, VVV=Wert 0-179)
void processSerial(int code) {
  int cat = code / 1000;
  int val = code % 1000;
  Serial.print("Cmd: "); Serial.print(code); Serial.print(" Cat: "); Serial.print(cat); Serial.print(" Val: "); Serial.println(val);

  if (cat == 10) { // System
    switch (val) {
      case 0: verbose = true; digitalWrite(PIN_LED_B, HIGH); Serial.println("Diag ON"); break;
      case 1: verbose = false; digitalWrite(PIN_LED_B, LOW); Serial.println("Diag OFF"); break;
      case 2: reportInfo(); break;
      case 3: digitalWrite(PIN_LED_R, HIGH); break; // Rot an
      case 4: digitalWrite(PIN_LED_R, LOW); break;  // Rot aus
      case 5: digitalWrite(PIN_LED_G, HIGH); break; // Grün an
      case 6: digitalWrite(PIN_LED_G, LOW); break;  // Grün aus
      case 7: digitalWrite(PIN_LED_B, HIGH); break; // Blau an
      case 8: digitalWrite(PIN_LED_B, LOW); break;  // Blau aus
      case 9: Serial.print("LDR TL: "); Serial.println(ldrTL); break;
      case 10: Serial.print("LDR TR: "); Serial.println(ldrTR); break;
      case 11: Serial.print("LDR BL: "); Serial.println(ldrBL); break;
      case 12: Serial.print("LDR BR: "); Serial.println(ldrBR); break;
      case 13: enableTracking(); break;
      case 14: disableTracking(); break;
      case 19: if (running && !movingTwist && !movingTilt) { cmdTwistPos=90; cmdTiltPos=90; Serial.println("Home 90°"); } break;
      case 21: if (running) { trackEnabled = true; Serial.println("Tracking ON"); } break;
      case 22: trackEnabled = false; Serial.println("Tracking OFF"); break;
      default: Serial.print("Invalid val: "); Serial.println(val);
    }
  } else if (cat == 11) { // Twist-Servo direkt
    if (val >= 0 && val <= 179 && running && !movingTwist) {
      cmdTwistPos = val; movingTwist = true;
      Serial.print("Twist cmd: "); Serial.println(val);
    } else Serial.println("Invalid twist val");
  } else if (cat == 12) { // Tilt-Servo direkt
    if (val >= 0 && val <= 179 && running && !movingTilt) {
      cmdTiltPos = val; movingTilt = true;
      Serial.print("Tilt cmd: "); Serial.println(val);
    } else Serial.println("Invalid tilt val");
  }
  Serial.println("-----");
}

// --- Tracking Ein/Aus ---
void enableTracking() {
  running = true;
  servoTwist.attach(PIN_SERVO_TWIST);
  servoTilt.attach(PIN_SERVO_TILT);
  digitalWrite(PIN_LED_G, HIGH); digitalWrite(PIN_LED_R, LOW);
  Serial.println("Servos enabled");
}

void disableTracking() {
  running = false; trackEnabled = false;
  servoTwist.detach(); servoTilt.detach();
  cmdTwistPos = servoTwist.read(); movingTwist = false;
  cmdTiltPos = servoTilt.read(); movingTilt = false;
  digitalWrite(PIN_LED_R, HIGH); digitalWrite(PIN_LED_G, LOW);
  Serial.println("Servos disabled");
}

// --- Startup-Sequenz (Selbsttest) ---
void startup() {
  int d = 500;
  reportInfo(); delay(d);
  processSerial(10003); delay(d); // Rot an
  processSerial(10004); processSerial(10005); delay(d); // Rot aus, Grün an
  processSerial(10006); processSerial(10007); delay(d); // Grün aus, Blau an
  processSerial(10008); processSerial(10009); processSerial(10010); processSerial(10011); processSerial(10012); delay(d); // LDRs anzeigen
  enableTracking(); delay(d);
  processSerial(10019); delay(d); // Home 90°
  disableTracking();
  Serial.println("Startup done");
}

void reportInfo() {
  Serial.println("Q2 Solar Tracker v2"); Serial.println("Tucson, AZ USA"); Serial.println("May 2018");
  Serial.println("Checksum 58BA-D969-2F82-08FD-2078-2777-396D-E1AA");
}

3D-Druck / Mechanik

Montage-Details & Halterungszeichnungen als ZIP: q2_assembly_details_RCbi893qzA.zip

Schaltplan

Fritzing-Datei: q2_schematic_TVp7kakwNa.fzz

Herstellungsprozess

  1. Solarheizsysteme: Von passiven zu aktiven Lösungen für nachhaltiges Heizen
  2. Solarzellen: Von frühen Experimenten zur modernen Photovoltaik – Technologie, Produktion und Ausblick
  3. Echtzeit-Solarmonitoring mit Arduino: Low-Cost Datenerfassungssystem
  4. Intelligente Jalousien: Automatische Lichtsteuerung mit Arduino & Solarenergie
  5. IoT-Solartracker: Intelligentes Energiemanagement mit Arduino Mega
  6. SmartPostBox: IoT-fähiges intelligentes Briefkasten-System
  7. Dual-Achsen-Solartracker mit Auto- & Manual-Modus – Effizientes Sonnen-Tracking
  8. Solarenergie nutzen: Ihr vollständiger Leitfaden zu sauberer, zuverlässiger Energie
  9. Solarmodul-Qualität: Kritische Kontrollpunkte für maximale Leistung
  10. Solarmodul-Fertigung: Materialien, Maschinen und Prozessschritte