Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Manufacturing Technology >> Productieproces

Precisie servo-aangedreven zonnevolgsysteem voor optimale energieopbrengst

Onderdelen en benodigdheden

Fotoweerstand (LDR) 4
Adafruit Flora RGB NeoPixel LEDs - pak van 4 (of equivalente RGB multi-kleur LED) 1
SparkFun Drukknop 12mm (of equivalente normally-open drukknop) 2
Temperatuursensor 1
Arduino UNO 1
RobotGeek 180-graden Robot Servo (of equivalente, ik gebruikte Futaba S3003 servos) 2
Weerstand 10k ohm 6
Weerstand 221 ohm (ik gebruikte 220 ohm) 1
Condensator 100 µF 2
Zonnepaneel (80mm x 80mm) (verkrijgbaar op Amazon.com of equivalent) 1

Benodigde tools en machines

  • Handgereedschap en een paar kleine bouten en moeren voor de beugel
  • Stevige basis voor het monteren van de "draai"-servomotor (ik gebruikte een klein houtblok)
  • Buigbaar metaal of kleine platen star aluminium die in een "L"-vormige beugel gevormd kunnen worden (ik gebruikte ~3mm dik aluminium, net onder 2cm breed)
  • Dun, buigbaar metaal voor een beugel om het zonnepaneel-platform te houden en te monteren op de "draai"-servo (ik gebruikte dunne staalstrippen uit de bouwmarkt, typisch voor HVAC-luchtkanalen, met voorgeboorde montagegaten)

Apps en online diensten

  • Arduino IDE
  • Microsoft Excel - voor documentatie en notities

Over dit project

Dit is een andere implementatie van het gebruik van twee 180-graden servos en vier fotoweerstanden om een klein zonnepaneel te laten volgen en uit te lijnen met het gebied van de hoogste lichtintensiteit.

De motoren maken kleine bewegingen om het zonnepaneel naar het helderste licht te richten.

Er is ook een multi-kleur LED om aan te geven of het systeem ingeschakeld is of niet. En twee drukknoppen om de motoren in/uit te schakelen.

Er zijn een paar routines die gebruikt kunnen worden om de gemotoriseerde platform naar aangewezen posities te bewegen. De commando's worden via de seriële poortinterface gegeven en een serie numerieke codes/commando's die naar de Arduino Uno gestuurd kunnen worden.

De onafhankelijke beweegcommando's zijn zo geprogrammeerd dat ze (redelijk) vloeiende bewegingen geven in plaats van directe positiecommando's die het mechanische mechanisme heftig laten bewegen.

Code

Q2 Code (Versie 2.0)

Volledige Arduino-code voor het zonnevolgsysteem met seriële commando-interface, vloeiende servo-bewegingen en licht-volging.

// Scott Mangiacotti
// Tucson, Arizona USA
// Mei 2018
// Q2 - Version 2.0

#include <Servo.h>

// Constanten
const int GIVE_BACK_TIME = 125;

// Input pinnen
const int I_RED_BUTTON_PIN = 4;
const int I_GREEN_BUTTON_PIN = 2;
const int I_LDR1_PIN = A3; // linksboven
const int I_LDR2_PIN = A2; // rechtsboven
const int I_LDR3_PIN = A1; // linksonder
const int I_LDR4_PIN = A0; // rechtsonder

// Output pinnen
const int O_RED_LED_PIN = 9;
const int O_GREEN_LED_PIN = 11;
const int O_BLUE_LED_PIN = 10;
const int O_TWIST_SERVO_PIN = 5;
const int O_TILT_SERVO_PIN = 6;

// Globale variabelen
bool gRunning = false;
bool gTrackToLightEnabled = false;
bool gVerboseDiagMode = false;

Servo gServoTwist;
int gServoTwistPositionCommand;
bool gServoTwistMoveIP;

Servo gServoTilt;
bool gServoTiltMoveIP;
int gServoTiltPositionCommand;

int gLDR1, gLDR2, gLDR3, gLDR4;

void setup() {
  Serial.begin(9600);
  pinMode(I_RED_BUTTON_PIN, INPUT);
  pinMode(I_GREEN_BUTTON_PIN, INPUT);
  pinMode(O_RED_LED_PIN, OUTPUT);
  pinMode(O_GREEN_LED_PIN, OUTPUT);
  pinMode(O_BLUE_LED_PIN, OUTPUT);
  startup();
}

void loop() {
  // Seriële poort commando verwerking
  if (Serial.available() > 0) {
    int iControlCode = Serial.parseInt();
    processSerialMessage(iControlCode);
  }
  
  // Groene knop: inschakelen tracking
  int iGreenButton = digitalRead(I_GREEN_BUTTON_PIN);
  if (iGreenButton == HIGH && gRunning == false) {
    enableTracking();
    gTrackToLightEnabled = true;
  }
  
  // Rode knop: uitschakelen tracking
  int iRedButton = digitalRead(I_RED_BUTTON_PIN);
  if (iRedButton == HIGH && gRunning == true) {
    disableTracking();
  }
  
  // Sensoren uitlezen
  readPhotoResistors();
  averageTopTwoSensors();
  averageBottomTwoSensors();
  
  // Servo posities aanpassen op basis van licht
  if (gRunning == true) {
    if (gTrackToLightEnabled == true) {
      trackToLightSensors();
    } else {
      smoothMoveTwist();
      smoothMoveTilt();
    }
  }
  
  delay(GIVE_BACK_TIME);
}

void enableTracking() {
  gRunning = true;
  gServoTwist.attach(O_TWIST_SERVO_PIN);
  gServoTilt.attach(O_TILT_SERVO_PIN);
  digitalWrite(O_GREEN_LED_PIN, HIGH);
  digitalWrite(O_RED_LED_PIN, LOW);
  Serial.println("servos enabled");
}

void disableTracking() {
  gRunning = false;
  gTrackToLightEnabled = false;
  gServoTwist.detach();
  gServoTilt.detach();
  gServoTwistPositionCommand = gServoTwist.read();
  gServoTwistMoveIP = false;
  gServoTiltPositionCommand = gServoTilt.read();
  gServoTiltMoveIP = false;
  digitalWrite(O_RED_LED_PIN, HIGH);
  digitalWrite(O_GREEN_LED_PIN, LOW);
  Serial.println("servos disabled");
}

void trackToLightSensors() {
  float fTop, fBottom, fLeft, fRight;
  int iTwistMoveCommand, iTiltMoveCommand;
  int iMoveAmount = 5; // graden per scan
  
  iTwistMoveCommand = gServoTwist.read();
  iTiltMoveCommand = gServoTilt.read();
  
  fTop = averageTopTwoSensors();
  fBottom = averageBottomTwoSensors();
  fLeft = averageLeftTwoSensors();
  fRight = averageRightTwoSensors();
  
  // Draai (twist) berekening
  if (fLeft > fRight) iTwistMoveCommand += iMoveAmount;
  else if (fRight > fLeft) iTwistMoveCommand -= iMoveAmount;
  
  // Kantel (tilt) berekening
  if (fTop > fBottom) iTiltMoveCommand += iMoveAmount;
  else if (fBottom > fTop) iTiltMoveCommand -= iMoveAmount;
  
  // Grenscontrole twist (0-179)
  if (iTwistMoveCommand < 0) iTwistMoveCommand = 0;
  if (iTwistMoveCommand > 179) iTwistMoveCommand = 179;
  
  // Grenscontrole tilt (45-135 voor zonnepaneel)
  if (iTiltMoveCommand < 45) iTiltMoveCommand = 45;
  if (iTiltMoveCommand > 135) iTiltMoveCommand = 135;
  
  gServoTwist.write(iTwistMoveCommand);
  gServoTilt.write(iTiltMoveCommand);
  
  if (gVerboseDiagMode) {
    Serial.print("tl, tr, bl, br, top avg, bottom avg, left avg, right avg, twist move, tilt move: ");
    Serial.print(gLDR1); Serial.print(", ");
    Serial.print(gLDR2); Serial.print(", ");
    Serial.print(gLDR3); Serial.print(", ");
    Serial.print(gLDR4); Serial.print(", ");
    Serial.print(fTop); Serial.print(", ");
    Serial.print(fBottom); Serial.print(", ");
    Serial.print(fLeft); Serial.print(", ");
    Serial.print(fRight); Serial.print(", ");
    Serial.print(iTwistMoveCommand); Serial.print(", ");
    Serial.println(iTiltMoveCommand);
  }
}

void readPhotoResistors() {
  gLDR1 = analogRead(I_LDR1_PIN);
  gLDR2 = analogRead(I_LDR2_PIN);
  gLDR3 = analogRead(I_LDR3_PIN);
  gLDR4 = analogRead(I_LDR4_PIN);
}

void smoothMoveTwist() {
  int iCurrentPos = gServoTwist.read();
  int iMoveAmountPerScan = 1;
  
  if (iCurrentPos == gServoTwistPositionCommand) {
    gServoTwistMoveIP = false;
    return;
  } else {
    gServoTwistMoveIP = true;
  }
  
  int iNewMoveCommand = iCurrentPos;
  if (iCurrentPos < gServoTwistPositionCommand)
    iNewMoveCommand += iMoveAmountPerScan;
  else
    iNewMoveCommand -= iMoveAmountPerScan;
  
  if (iNewMoveCommand < 0) iNewMoveCommand = 0;
  if (iNewMoveCommand > 179) iNewMoveCommand = 179;
  
  gServoTwist.write(iNewMoveCommand);
  
  if (gVerboseDiagMode) {
    Serial.print("Twist servo move: "); Serial.print(iNewMoveCommand);
    Serial.print(", target: "); Serial.println(gServoTwistPositionCommand);
  }
}

void smoothMoveTilt() {
  int iCurrentPos = gServoTilt.read();
  int iMoveAmountPerScan = 1;
  
  if (iCurrentPos == gServoTiltPositionCommand) {
    gServoTiltMoveIP = false;
    return;
  } else {
    gServoTiltMoveIP = true;
  }
  
  int iNewMoveCommand = iCurrentPos;
  if (iCurrentPos < gServoTiltPositionCommand)
    iNewMoveCommand += iMoveAmountPerScan;
  else
    iNewMoveCommand -= iMoveAmountPerScan;
  
  if (iNewMoveCommand < 0) iNewMoveCommand = 0;
  if (iNewMoveCommand > 179) iNewMoveCommand = 179;
  
  gServoTilt.write(iNewMoveCommand);
  
  if (gVerboseDiagMode) {
    Serial.print("Tilt servo move: "); Serial.print(iNewMoveCommand);
    Serial.print(", target: "); Serial.println(gServoTiltPositionCommand);
  }
}

float averageTopTwoSensors() {
  return (gLDR1 + gLDR2) / 2.0;
}

float averageBottomTwoSensors() {
  return (gLDR3 + gLDR4) / 2.0;
}

float averageLeftTwoSensors() {
  return (gLDR1 + gLDR3) / 2.0;
}

float averageRightTwoSensors() {
  return (gLDR2 + gLDR4) / 2.0;
}

void processSerialMessage(int iControlCode) {
  int iControlCommand = iControlCode / 1000;
  int iControlValue = iControlCode % 1000;
  
  Serial.print("control code: "); Serial.println(iControlCode);
  Serial.print("control command: "); Serial.println(iControlCommand);
  Serial.print("control value: "); Serial.println(iControlValue);
  
  // Misc commando's (10xxx)
  if (iControlCommand == 10) {
    switch(iControlValue) {
      case 0: gVerboseDiagMode = true; digitalWrite(O_BLUE_LED_PIN, HIGH); Serial.println("diagnostics mode started"); break;
      case 1: gVerboseDiagMode = false; digitalWrite(O_BLUE_LED_PIN, LOW); Serial.println("diagnostics mode stopped"); break;
      case 2: reportProductInfo(); break;
      case 3: digitalWrite(O_RED_LED_PIN, HIGH); Serial.println("red led on"); break;
      case 4: digitalWrite(O_RED_LED_PIN, LOW); Serial.println("red led off"); break;
      case 5: digitalWrite(O_GREEN_LED_PIN, HIGH); Serial.println("green led on"); break;
      case 6: digitalWrite(O_GREEN_LED_PIN, LOW); Serial.println("green led off"); break;
      case 7: digitalWrite(O_BLUE_LED_PIN, HIGH); Serial.println("blue led on"); break;
      case 8: digitalWrite(O_BLUE_LED_PIN, LOW); Serial.println("blue led off"); break;
      case 9: Serial.print("LDR1 value: "); Serial.println(gLDR1); break;
      case 10: Serial.print("LDR2 value: "); Serial.println(gLDR2); break;
      case 11: Serial.print("LDR3 value: "); Serial.println(gLDR3); break;
      case 12: Serial.print("LDR4 value: "); Serial.println(gLDR4); break;
      case 13: enableTracking(); break;
      case 14: disableTracking(); break;
      case 19: if (gRunning && !gServoTwistMoveIP && !gServoTiltMoveIP) { gServoTwistPositionCommand = 90; gServoTiltPositionCommand = 90; Serial.println("twist and tilt servos commanded to 90 degrees"); } break;
      case 21: if (gRunning) { gTrackToLightEnabled = true; Serial.println("Track to light source enabled"); } break;
      case 22: gTrackToLightEnabled = false; Serial.println("Track to light source disabled"); break;
      default: Serial.print("invalid control value: "); Serial.println(iControlValue);
    }
  }
  
  // Twist servo commando (11xxx)
  if (iControlCommand == 11) {
    if (iControlValue >= 0 && iControlValue <= 179) {
      if (gRunning && !gServoTwistMoveIP) {
        gServoTwistPositionCommand = iControlValue;
        gServoTwistMoveIP = true;
        Serial.print("Move twist servo command: "); Serial.println(gServoTwistPositionCommand);
      }
    } else {
      Serial.print("invalid control value: "); Serial.println(iControlValue);
    }
  }
  
  // Tilt servo commando (12xxx)
  if (iControlCommand == 12) {
    if (iControlValue >= 0 && iControlValue <= 179) {
      if (gRunning && !gServoTiltMoveIP) {
        gServoTiltPositionCommand = iControlValue;
        gServoTiltMoveIP = true;
        Serial.print("Move tilt servo command: "); Serial.println(gServoTiltPositionCommand);
      } else {
        Serial.print("tilt servo not enabled or move in progress, "); Serial.print(gRunning); Serial.print(", "); Serial.println(gServoTiltMoveIP);
      }
    } else {
      Serial.print("invalid control value: "); Serial.println(iControlValue);
    }
  }
  
  Serial.println("-----");
}

void startup() {
  int iDelay = 500;
  reportProductInfo(); delay(iDelay);
  processSerialMessage(10003); delay(iDelay); // Rode LED aan
  processSerialMessage(10004); processSerialMessage(10005); delay(iDelay); // Rode uit, groen aan
  processSerialMessage(10006); processSerialMessage(10007); delay(iDelay); // Groen uit, blauw aan
  processSerialMessage(10008); processSerialMessage(10009); processSerialMessage(10010); processSerialMessage(10011); processSerialMessage(10012); delay(iDelay); // LDR waarden
  enableTracking(); delay(iDelay);
  processSerialMessage(10019); delay(iDelay); // Home positie
  disableTracking();
  Serial.println("startup sequence completed");
}

void reportProductInfo() {
  Serial.println("q version 2");
  Serial.println("tucson, arizona usa");
  Serial.println("may 2018");
  Serial.print("checksum "); Serial.println("58BA-D969-2F82-08FD-2078-2777-396D-E1AA");
}

3D-modellen / CAD-bestanden

Montagedetails en 3D-printbestanden: q2_assembly_details_RCbi893qzA.zip

Schema

Fritzing-schema: q2_schematic_TVp7kakwNa.fzz

Productieproces

  1. Zonneverwarmingssystemen: Van Passief tot Actieve Oplossingen voor Duurzame Huisverwarming
  2. Zonnecellen: van vroege experimenten tot moderne fotovoltaïsche technieken – Technologie, productie en toekomstperspectieven
  3. Real-time zonnepaneelmonitoring met Arduino: Goedkope data-acquisitie
  4. Slimme Jaloezieën: Geautomatiseerd Lichtbeheer met Arduino & Zonne-energie
  5. IoT-zonnesturing: Slimme energiemanagement met Arduino
  6. SmartPostBox: IoT-geïntegreerde intelligente brievenbus met Sigfox
  7. Dubbele-as zonnepaneel-volgsysteem met auto & handmatige controle – Efficiënte zonvolging
  8. Draagbare Zonnetracker Telefoonlader met Arduino en Servo-besturing
  9. Zonenergie Benutten: Complete Gids voor Schone, Betrouwbare Energie
  10. Zonnepaneelkwaliteit: essentiële controlepunten voor optimale prestaties
  11. Hoe zonnepanelen gemaakt worden: stap-voor-stap gids voor hoogwaardige zonne-energieproductie