Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

Точная солнеследующая платформа на сервоприводах для максимальной генерации энергии

Компоненты и материалы

Фоторезисторы (LDR)4 шт.
RGB NeoPixel LED (4 шт. в наборе Adafruit Flora или аналогичные)1 набор
Тактильные кнопки 12 мм (нормально открытые)2 шт.
Датчик температуры (например, TMP36 или LM35)1 шт.
Arduino UNO1 шт.
Сервоприводы 180° (Futaba S3003 или RobotGeek)2 шт.
Резисторы 10 кОм6 шт.
Резистор 220 Ом (для LED)1 шт.
Конденсаторы 100 мкФ2 шт.
Солнечная панель ~80×80 мм1 шт.

Инструменты и механика

Программное обеспечение

О проекте

Ещё одна реализация двухосевого солнеслежения на двух сервоприводах 180° и четырёх фоторезисторах. Платформа с панелью и датчиками поворачивается к зоне максимальной освещённости.

Есть RGB-индикатор состояния (включено/выключено) и две кнопки: включение/выключение слежения. Команды также можно посылать через Serial-порт (числовые коды). Реализовано плавное движение сервоприводов (пошаговые приращения) вместо рывков.

Код (Arduino, версия Q2 v2.0)

// Scott Mangiacotti, Tucson, Arizona, May 2018
#include 

const int GIVE_BACK_TIME = 125; // мс между итерациями loop()

// Входы
const int I_RED_BUTTON_PIN   = 4;  // Выкл
const int I_GREEN_BUTTON_PIN = 2;  // Вкл
const int I_LDR1_PIN = A3; // Верхний левый
const int I_LDR2_PIN = A2; // Верхний правый
const int I_LDR3_PIN = A1; // Нижний левый
const int I_LDR4_PIN = A0; // Нижний правый

// Выходы
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; // Угол места

// Глобальные переменные
bool gRunning = false;
bool gTrackToLightEnabled = false;
bool gVerboseDiagMode = false;

Servo gServoTwist;
int gServoTwistPositionCommand;
bool gServoTwistMoveIP;

Servo gServoTilt;
int gServoTiltPositionCommand;
bool gServoTiltMoveIP;

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() {
  // Serial-команды
  if (Serial.available() > 0) {
    int iControlCode = Serial.parseInt();
    processSerialMessage(iControlCode);
  }

  // Зелёная кнопка — включить слежение
  if (digitalRead(I_GREEN_BUTTON_PIN) == HIGH && !gRunning) {
    enableTracking(); gTrackToLightEnabled = true;
  }
  // Красная кнопка — выключить
  if (digitalRead(I_RED_BUTTON_PIN) == HIGH && gRunning) {
    disableTracking();
  }

  readPhotoResistors();

  if (gRunning) {
    if (gTrackToLightEnabled) {
      trackToLightSensors(); // Автоматическое слежение
    } else {
      smoothMoveTwist();     // Ручное управление через Serial
      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 = averageTopTwoSensors();
  float fBottom = averageBottomTwoSensors();
  float fLeft = averageLeftTwoSensors();
  float fRight = averageRightTwoSensors();

  int iTwistMoveCommand = gServoTwist.read();
  int iTiltMoveCommand = gServoTilt.read();
  int iMoveAmount = 5; // градусов за шаг (в сочетании с GIVE_BACK_TIME задаёт скорость)

  if (fLeft > fRight) iTwistMoveCommand += iMoveAmount;
  else if (fRight > fLeft) iTwistMoveCommand -= iMoveAmount;

  if (fTop > fBottom) iTiltMoveCommand += iMoveAmount;
  else if (fBottom > fTop) iTiltMoveCommand -= iMoveAmount;

  // Ограничители
  iTwistMoveCommand = constrain(iTwistMoveCommand, 0, 179);
  iTiltMoveCommand = constrain(iTiltMoveCommand, 45, 135);

  gServoTwist.write(iTwistMoveCommand);
  gServoTilt.write(iTiltMoveCommand);

  if (gVerboseDiagMode) {
    Serial.print("LDRs: "); Serial.print(gLDR1); Serial.print(","); Serial.print(gLDR2);
    Serial.print(","); Serial.print(gLDR3); Serial.print(","); Serial.println(gLDR4);
    Serial.print("Avgs: T="); Serial.print(fTop); Serial.print(" B="); Serial.print(fBottom);
    Serial.print(" L="); Serial.print(fLeft); Serial.print(" R="); Serial.println(fRight);
    Serial.print("Cmd: Twist="); Serial.print(iTwistMoveCommand); Serial.print(" Tilt="); 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);
}

// Плавное движение сервопривода "twist" (азимут)
void smoothMoveTwist() {
  const int iMoveAmountPerScan = 1;
  int iCurrentPos = gServoTwist.read();
  if (iCurrentPos == gServoTwistPositionCommand) { gServoTwistMoveIP = false; return; }
  gServoTwistMoveIP = true;
  int iNewMoveCommand = iCurrentPos;
  if (iCurrentPos < gServoTwistPositionCommand) iNewMoveCommand += iMoveAmountPerScan;
  else iNewMoveCommand -= iMoveAmountPerScan;
  iNewMoveCommand = constrain(iNewMoveCommand, 0, 179);
  gServoTwist.write(iNewMoveCommand);
  if (gVerboseDiagMode) { Serial.print("Twist move: "); Serial.print(iNewMoveCommand); Serial.print(" target: "); Serial.println(gServoTwistPositionCommand); }
}

// Плавное движение сервопривода "tilt" (угол места)
void smoothMoveTilt() {
  const int iMoveAmountPerScan = 1;
  int iCurrentPos = gServoTilt.read();
  if (iCurrentPos == gServoTiltPositionCommand) { gServoTiltMoveIP = false; return; }
  gServoTiltMoveIP = true;
  int iNewMoveCommand = iCurrentPos;
  if (iCurrentPos < gServoTiltPositionCommand) iNewMoveCommand += iMoveAmountPerScan;
  else iNewMoveCommand -= iMoveAmountPerScan;
  iNewMoveCommand = constrain(iNewMoveCommand, 0, 179);
  gServoTilt.write(iNewMoveCommand);
  if (gVerboseDiagMode) { Serial.print("Tilt 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; }

// Обработка Serial-команд: код = команда*1000 + значение
void processSerialMessage(int iControlCode) {
  int iControlCommand = iControlCode / 1000;
  int iControlValue   = iControlCode % 1000;
  Serial.print("code: "); Serial.println(iControlCode);
  Serial.print("cmd: "); Serial.println(iControlCommand);
  Serial.print("val: "); Serial.println(iControlValue);

  if (iControlCommand == 10) { // Разное
    switch (iControlValue) {
      case 0: gVerboseDiagMode = true;  digitalWrite(O_BLUE_LED_PIN, HIGH); Serial.println("diag ON"); break;
      case 1: gVerboseDiagMode = false; digitalWrite(O_BLUE_LED_PIN, LOW);  Serial.println("diag OFF"); break;
      case 2: reportProductInfo(); break;
      case 3: digitalWrite(O_RED_LED_PIN, HIGH);   Serial.println("red ON"); break;
      case 4: digitalWrite(O_RED_LED_PIN, LOW);    Serial.println("red OFF"); break;
      case 5: digitalWrite(O_GREEN_LED_PIN, HIGH); Serial.println("green ON"); break;
      case 6: digitalWrite(O_GREEN_LED_PIN, LOW);  Serial.println("green OFF"); break;
      case 7: digitalWrite(O_BLUE_LED_PIN, HIGH);  Serial.println("blue ON"); break;
      case 8: digitalWrite(O_BLUE_LED_PIN, LOW);   Serial.println("blue OFF"); break;
      case 9:  Serial.print("LDR1: "); Serial.println(gLDR1); break;
      case 10: Serial.print("LDR2: "); Serial.println(gLDR2); break;
      case 11: Serial.print("LDR3: "); Serial.println(gLDR3); break;
      case 12: Serial.print("LDR4: "); Serial.println(gLDR4); break;
      case 13: enableTracking(); break;
      case 14: disableTracking(); break;
      case 19: if (gRunning && !gServoTwistMoveIP && !gServoTiltMoveIP) { gServoTwistPositionCommand = 90; gServoTiltPositionCommand = 90; Serial.println("home 90/90"); } break;
      case 21: if (gRunning) { gTrackToLightEnabled = true; Serial.println("track ON"); } break;
      case 22: gTrackToLightEnabled = false; Serial.println("track OFF"); break;
      default: Serial.print("bad val: "); Serial.println(iControlValue);
    }
  } else if (iControlCommand == 11) { // Servo Twist
    if (iControlValue >= 0 && iControlValue <= 179 && gRunning && !gServoTwistMoveIP) {
      gServoTwistPositionCommand = iControlValue; gServoTwistMoveIP = true;
      Serial.print("Twist cmd: "); Serial.println(gServoTwistPositionCommand);
    } else Serial.print("bad val: "); Serial.println(iControlValue);
  } else if (iControlCommand == 12) { // Servo Tilt
    if (iControlValue >= 0 && iControlValue <= 179 && gRunning && !gServoTiltMoveIP) {
      gServoTiltPositionCommand = iControlValue; gServoTiltMoveIP = true;
      Serial.print("Tilt cmd: "); Serial.println(gServoTiltPositionCommand);
    } else Serial.print("bad val: "); Serial.println(iControlValue);
  }
  Serial.println("-----");
}

void startup() {
  int d = 500;
  reportProductInfo(); delay(d);
  processSerialMessage(10003); delay(d); // red ON
  processSerialMessage(10004); processSerialMessage(10005); delay(d); // red OFF, green ON
  processSerialMessage(10006); processSerialMessage(10007); delay(d); // green OFF, blue ON
  processSerialMessage(10008); processSerialMessage(10009); processSerialMessage(10010); processSerialMessage(10011); processSerialMessage(10012); delay(d); // LDR values
  enableTracking(); delay(d);
  processSerialMessage(10019); delay(d); // home
  disableTracking();
  Serial.println("startup done");
}

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

3D-модели и чертежи

Архив с деталями сборки: q2_assembly_details_RCbi893qzA.zip

Схемы

Fritzing-файл: q2_schematic_TVp7kakwNa.fzz

Производственный процесс

  1. Солнечные отопительные системы: от пассивных к активным решениям для устойчивого отопления домов
  2. Солнечные ячейки: от ранних экспериментов к современной фотовольтаике — технологии, производство и перспекти…
  3. Мониторинг солнечной панели в реальном времени: дешёвая система сбора данных на Arduino и Excel
  4. Умные шторы: автоматическое управление светом на Arduino с солнечной энергией
  5. IoT-солнечный трекер на Arduino: умное управление энергией с мониторингом через Cayenne
  6. SmartPostBox: умный почтовый ящик на Arduino MKR Fox 1200 и Sigfox
  7. Двухосевой солнечный трекер с авто/ручным управлением
  8. Солнечная энергия: полное руководство по чистой и надежной энергии
  9. Качество солнечных панелей: ключевые контрольные точки для оптимальной производительности
  10. Как производятся солнечные панели: пошаговое руководство к высококачественному солнечному производству