산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

정밀 서보 구동 태양 추적 플랫폼 - 최적 에너지 수확을 위한 이축 트래커

부품 및 소모품

부품수량비고
포토레지스터 (CdS 셀)4태양광 강도 감지용
Adafruit Flora RGB 네오픽셀 LED (4개 팩)1또는 동등한 RGB 멀티컬러 LED
스파크펀 12mm 푸시버튼2일반적인 상시개방 푸시버튼
온도 센서1
아두이노 우노1
180도 로봇 서보 (Futaba S3003 등)2트위스트(방위각), 틸트(고도각)용
10kΩ 저항6포토레지스터 풀다운용
220Ω 저항1LED 전류 제한용
100μF 커패시터2서보 전원 안정화용
태양광 패널 (80mm x 80mm)1아마존 등에서 구매 가능

필요한 도구 및 재료

앱 및 온라인 서비스

프로젝트 개요

두 개의 180도 서보와 네 개의 포토레지스터를 사용하여 소형 태양광 패널이 가장 강한 빛을 향하도록 추적하는 또 다른 구현입니다.

모터는 태양광 패널을 가장 밝은 빛 방향으로 향하게 하기 위해 작은 움직임을 반복합니다.

시스템 활성화 여부를 나타내는 멀티컬러 LED와, 모터를 활성화/비활성화하는 두 개의 푸시버튼이 있습니다.

시리얼 포트 인터페이스를 통해 숫자 코드/명령어를 보내 모터를 지정된 위치로 이동시키는 몇 가지 루틴이 프로그래밍되어 있습니다. 독립 이동 명령은 기계적 구조가 격렬하게 움직이지 않도록 즉각적인 위치 명령 대신 (어느 정도) 부드러운 움직임을 제공하도록 설계되었습니다.

코드 (Q2 버전 2.0)

// Scott Mangiacotti, Tucson, Arizona, May 2018
// Q2 Version 2.0
#include <Servo.h>

// 상수
const int GIVE_BACK_TIME = 125;

// 입력 핀
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;
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() {
  // 시리얼 명령 처리
  if (Serial.available() > 0) {
    int iControlCode = Serial.parseInt();
    processSerialMessage(iControlCode);
  }

  // 그린 버튼: 추적 시작
  int iGreenButton = digitalRead(I_GREEN_BUTTON_PIN);
  if (iGreenButton == HIGH && gRunning == false) {
    enableTracking();
    gTrackToLightEnabled = true;
  }

  // 레드 버튼: 추적 정지
  int iRedButton = digitalRead(I_RED_BUTTON_PIN);
  if (iRedButton == HIGH && gRunning == true) {
    disableTracking();
  }

  // 센서 읽기
  readPhotoResistors();
  averageTopTwoSensors();
  averageBottomTwoSensors();

  // 서보 위치 조정
  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;  // 스캔당 이동 각도 (GIVE_BACK_TIME과 조합으로 속도 결정)

  iTwistMoveCommand = gServoTwist.read();
  iTiltMoveCommand = gServoTilt.read();

  fTop = averageTopTwoSensors();
  fBottom = averageBottomTwoSensors();
  fLeft = averageLeftTwoSensors();
  fRight = averageRightTwoSensors();

  // 트위스트(방위각) 이동 계산
  if (fLeft > fRight) iTwistMoveCommand += iMoveAmount;
  else if (fRight > fLeft) iTwistMoveCommand -= iMoveAmount;

  // 틸트(고도각) 이동 계산
  if (fTop > fBottom) iTiltMoveCommand += iMoveAmount;
  else if (fBottom > fTop) iTiltMoveCommand -= iMoveAmount;

  // 범위 제한
  if (iTwistMoveCommand < 0) iTwistMoveCommand = 0;
  if (iTwistMoveCommand > 179) iTwistMoveCommand = 179;
  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,bottom,left,right,twist,tilt: ");
    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;  // 스캔당 1도씩 이동
  if (iCurrentPos == gServoTwistPositionCommand) { gServoTwistMoveIP = false; return; }
  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(iNewMoveCommand); Serial.print(", "); Serial.println(gServoTwistPositionCommand); }
}

// 부드러운 이동: 틸트 서보
void smoothMoveTilt() {
  int iCurrentPos = gServoTilt.read();
  int iMoveAmountPerScan = 1;
  if (iCurrentPos == gServoTiltPositionCommand) { gServoTiltMoveIP = false; return; }
  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(iNewMoveCommand); Serial.print(", "); 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; }

// 시리얼 명령 처리 (명령코드 2자리 + 값 3자리)
void processSerialMessage(int iControlCode) {
  int iControlCommand = iControlCode / 1000;
  int iControlValue = iControlCode % 1000;
  Serial.print("control code: "); Serial.println(iControlCode);
  Serial.print("command: "); Serial.println(iControlCommand);
  Serial.print("value: "); Serial.println(iControlValue);

  if (iControlCommand == 10) {  // 기타 명령
    if (iControlValue == 0) { gVerboseDiagMode = true; digitalWrite(O_BLUE_LED_PIN, HIGH); Serial.println("diag mode on"); }
    else if (iControlValue == 1) { gVerboseDiagMode = false; digitalWrite(O_BLUE_LED_PIN, LOW); Serial.println("diag mode off"); }
    else if (iControlValue == 2) { reportProductInfo(); }
    else if (iControlValue == 3) { digitalWrite(O_RED_LED_PIN, HIGH); Serial.println("red led on"); }
    else if (iControlValue == 4) { digitalWrite(O_RED_LED_PIN, LOW); Serial.println("red led off"); }
    else if (iControlValue == 5) { digitalWrite(O_GREEN_LED_PIN, HIGH); Serial.println("green led on"); }
    else if (iControlValue == 6) { digitalWrite(O_GREEN_LED_PIN, LOW); Serial.println("green led off"); }
    else if (iControlValue == 7) { digitalWrite(O_BLUE_LED_PIN, HIGH); Serial.println("blue led on"); }
    else if (iControlValue == 8) { digitalWrite(O_BLUE_LED_PIN, LOW); Serial.println("blue led off"); }
    else if (iControlValue >= 9 && iControlValue <= 12) { 
      int ldrVals[4] = {gLDR1, gLDR2, gLDR3, gLDR4};
      Serial.print("LDR"); Serial.print(iControlValue-8); Serial.print(" value: "); Serial.println(ldrVals[iControlValue-9]);
    }
    else if (iControlValue == 13) { enableTracking(); }
    else if (iControlValue == 14) { disableTracking(); }
    else if (iControlValue == 19) { 
      if (gRunning && !gServoTwistMoveIP && !gServoTiltMoveIP) {
        gServoTwistPositionCommand = 90; gServoTiltPositionCommand = 90;
        Serial.println("twist and tilt servos commanded to 90 degrees");
      }
    }
    else if (iControlValue == 21) { if (gRunning) { gTrackToLightEnabled = true; Serial.println("Track to light enabled"); } }
    else if (iControlValue == 22) { gTrackToLightEnabled = false; Serial.println("Track to light disabled"); }
    else { Serial.print("invalid value: "); Serial.println(iControlValue); }
  }
  else if (iControlCommand == 11) {  // 트위스트 서보 명령
    if (iControlValue >= 0 && iControlValue <= 179) {
      if (gRunning && !gServoTwistMoveIP) { gServoTwistPositionCommand = iControlValue; gServoTwistMoveIP = true; 
        Serial.print("Move twist servo: "); Serial.println(gServoTwistPositionCommand); }
    } else { Serial.print("invalid value: "); Serial.println(iControlValue); }
  }
  else if (iControlCommand == 12) {  // 틸트 서보 명령
    if (iControlValue >= 0 && iControlValue <= 179) {
      if (gRunning && !gServoTiltMoveIP) { gServoTiltPositionCommand = iControlValue; gServoTiltMoveIP = true;
        Serial.print("Move tilt servo: "); Serial.println(gServoTiltPositionCommand); }
      else { Serial.print("tilt not ready: "); Serial.print(gRunning); Serial.print(", "); Serial.println(gServoTiltMoveIP); }
    } else { Serial.print("invalid value: "); Serial.println(iControlValue); }
  }
  Serial.println("-----");
}

// 시작 시퀀스: 자가 테스트, 서보 활성화, 광추적 모드 진입
void startup() {
  int iDelay = 500;
  reportProductInfo(); delay(iDelay);
  processSerialMessage(10003); delay(iDelay);  // 빨강 ON
  processSerialMessage(10004); processSerialMessage(10005); delay(iDelay);  // 빨강 OFF, 초록 ON
  processSerialMessage(10006); processSerialMessage(10007); delay(iDelay);  // 초록 OFF, 파랑 ON
  processSerialMessage(10008); processSerialMessage(10009); processSerialMessage(10010); processSerialMessage(10011); processSerialMessage(10012); delay(iDelay);  // LDR 값 출력
  enableTracking(); delay(iDelay);
  processSerialMessage(10019); delay(iDelay);  // 홈 포지션(90,90)
  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 모델 및 인클로저

조립 상세 도면 (ZIP)

회로도

프릿징 회로도 파일

제조공정

  1. 태양열 난방 시스템: 패시브에서 액티브까지 지속 가능한 가정 난방 솔루션
  2. 태양전지: 초기 실험부터 현대 광전지까지 - 기술, 생산, 미래 전망
  3. 아두이노로 태양광 패널 실시간 모니터링 - 저비용 데이터 수집 시스템
  4. 스마트 블라인드: 아두이노와 태양광으로 자동 조명 제어
  5. IoT 기반 듀얼 축 태양광 추적기: 아두이노로 구현하는 스마트 에너지 관리
  6. 스마트포스트박스: IoT 기반 지능형 우편함 알림 시스템
  7. 이중축 태양광 추적기: 자동/수동 모드 전환 가능한 고효율 선트래킹 시스템
  8. 태양광 에너지 완전 가이드: 깨끗하고 신뢰할 수 있는 친환경 전력의 모든 것
  9. 태양광 패널 품질: 최적 성능을 위한 필수 관리 포인트
  10. 태양광 패널 제조 공정: 고품질 태양에너지 생산을 위한 단계별 가이드