/*************************************************************************** * Solar light tracker project with Mega 2560 R3 Board microcontroller, * * Solar panel, LDR resistors, 0.96 inch OLED 128X64 pixels display, * * 2 TB6600 modules and 2 NEMA17 step by step motors. * * * * Armin Rolfes / Wilfried Meyer * * Last revisión 04.10.2024 * ***************************************************************************/ #include /************** OLED display library and configuration *************/ #include // I2C communication library. #include // Core graphics library for screen. #include // SSD1306 oled driver library for monochrome 128x64 display. #define SCREEN_WIDTH 128 // 128 pixels width screen. #define SCREEN_HEIGHT 64 // 64 pixels height screen. Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); // Screen object declaration. /******************* LDR config *********************/ int LDR_UpR = A0; // Upper right LDR connected to the analog pin 0 of the microcontroller. int LDR_UpL = A1; // Upper left LDR connected to the analog pin 1 of the microcontroller. int LDR_LoL = A2; // Lower left LDR connected to the analog pin 2 of the microcontroller. int LDR_LoR = A3; // Lower right LDR connected to the analog pin 3 of the microcontroller. int upperRightLdrVal = 0; // Upper right LDR resistor voltage (AD) int upperLeftLdrVal = 0; // Upper left LDR resistor voltage (AD) int lowerLeftLdrVal = 0; // Lower left LDR resistor voltage (AD) int lowerRightLdrVal = 0; // Lower right LDR resistor voltage (AD) int upperAverageLdr = 0; // Arithmetic mean of the upper LDR sensors int lowerAverageLdr = 0; // Arithmetic mean of the lower LDR sensors int rightAverageLdr = 0; // Arithmetic mean of the right LDR sensors int leftAverageLdr = 0; // Arithmetic mean of the left LDR sensors int toleranceAverageLdr = 10; // tolerance for the LDR average values /******************* Solar panel ********************/ int SPV = A4; // Solar Panel connected to the analog pin 4 of the microcontroller. int solarPanelAdVal = 0; // value of the direct voltage of the solar panel (AD). float solarPanelVoltage = 0; // Analog-to-Digital converted voltage value /****************** Motors config ******************/ int MOTOR_ENABLE = HIGH; // value to enable the motor (LOW or HIGH depending on hardware configuration) int MOTOR_DISABLE = LOW; // value to disable the motor (LOW or HIGH depending on hardware configuration) // config for horizontal movement int MOTOR_LEFT_RIGHT_ENABLE = 41; // enable Pin for Motor for left / right Motor movement / todo// int MOTOR_LEFT_RIGHT_PULS = 37; // Puls Pin for Motor left / right Motor movement / todo// int MOTOR_LEFT_RIGHT_DIRECTION = 39; // direction PIN for Motor left / right Motor movement / todo// int MOTOR_DIRECTION_LEFT = 39 HIGH; // value for which motor moves to the left (LOW or HIGH depending on hardware configuration) / todo// int MOTOR_DIRECTION_RIGHT = 39 LOW; // value for which motor moves to the right (LOW or HIGH depending on hardware configuration) / todo// // config for vertical movement int MOTOR_UP_DOWN_ENABLE = 35; // enable Pin for Motor up / down Motor movement / todo// int MOTOR_UP_DOWN_PULS = 31; // Puls Pin for Motor up / down Motor movement / todo// int MOTOR_UP_DOWN_DIRECTION = 33; // direction PIN for Motor up / down Motor movement / todo// int MOTOR_DIRECTION_UP = 33 HIGH; // value for which motor moves to the up (LOW or HIGH depending on hardware configuration) / todo// int MOTOR_DIRECTION_DOWN = 33 LOW; // value for which motor moves to the down (LOW or HIGH depending on hardware configuration) / todo// /****************** Motors speed ******************/ int motorMoveDelay = 500; // Delay between movement steps of the stepper motor [us] / todo// int motorStepsToMoveLeftRight = 5; // Number of steps to move in left or right direction / todo// int motorStepsToMoveUpDown = 2; // Number of steps to move in up or down direction / todo // /****************** limit switches ********************************* * Normally closed Sunrise limit switch * * Normally opened Sunset limit switch * ***********************************************************************/ int LIMIT_SWITCH_LEFT = 1; // Pin Limit switch left // todo Pin Endschalter links West int LIMIT_SWITCH_LEFT_PRESSED = HIGH; // value for which the LEFT limit switch is pressed (LOW or HIGH depending on hardware configuration) / todo// int LIMIT_SWITCH_RIGHT = 0; // Pin Limit switch right // todo Pin Endschalter rechts Ost int LIMIT_SWITCH_RIGHT_PRESSED = LOW; // value for which the RIGHT limit switch is pressed (LOW or HIGH depending on hardware configuration) / todo// int LIMIT_SWITCH_UP = 2; // Pin Limit switch up // todo Pin Endschalter Oben Nord int LIMIT_SWITCH_UP_PRESSED = HIGH; // value for which the UP limit switch is pressed (LOW or HIGH depending on hardware configuration) // todo// int LIMIT_SWITCH_DOWN = 3; // Pin Limit switch down // todo Pin Endschalter unten Süd int LIMIT_SWITCH_DOWN_PRESSED = HIGH; // value for which the DOWN limit switch is pressed (LOW or HIGH depending on hardware configuration) / todo// int limitSwitchLeftStatus; // current value for left limit switch int limitSwitchRightStatus; // current value for right limit switch int limitSwitchUpStatus; // current value for up limit switch int limitSwitchDownStatus; // current value for down limit switch void setup() { Serial.begin(9600); // Serial monitor initialisation. if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // OLED screen initialisation. Serial.println(F("SSD1306 allocation failed")); // Message if display initialization fails. for(;;); } display.clearDisplay(); // Clear display. display.setTextColor(WHITE); // Set text to white color. // Config LDR Pins pinMode (LDR_UpR, INPUT); pinMode (LDR_UpL, INPUT); pinMode (LDR_LoL, INPUT); pinMode (LDR_LoR, INPUT); pinMode (SPV, INPUT); // Config Motor Pins pinMode(MOTOR_LEFT_RIGHT_ENABLE, OUTPUT); // Enable pinMode(MOTOR_LEFT_RIGHT_PULS, OUTPUT); // Puls pinMode(MOTOR_LEFT_RIGHT_DIRECTION, OUTPUT); // Direction digitalWrite(MOTOR_LEFT_RIGHT_ENABLE, MOTOR_DISABLE); // disable Motor left right pinMode(MOTOR_UP_DOWN_ENABLE, OUTPUT); // Enable pinMode(MOTOR_UP_DOWN_PULS, OUTPUT); // Puls pinMode(MOTOR_UP_DOWN_DIRECTION, OUTPUT); // Direction digitalWrite(MOTOR_UP_DOWN_ENABLE, MOTOR_DISABLE); // disable Motor up down // Config limit switches pinMode (LIMIT_SWITCH_LEFT, INPUT); pinMode (LIMIT_SWITCH_RIGHT, INPUT); pinMode (LIMIT_SWITCH_UP, INPUT); pinMode (LIMIT_SWITCH_DOWN, INPUT); // set back to start position limitSwitchRightStatus = digitalRead(LIMIT_SWITCH_RIGHT); while (limitSwitchRightStatus != LIMIT_SWITCH_RIGHT_PRESSED) { // Check of the sunrise limit switch Serial.println("move Panel to Start position"); // Message on OLED display. movePanelRight(); // Call to the initialize horizontal motor method. limitSwitchRightStatus = digitalRead(LIMIT_SWITCH_RIGHT); // Sunrise limit switch check, initial status must be LOW to exit the loop. } } void loop() { limitSwitchLeftStatus = digitalRead(LIMIT_SWITCH_LEFT); // read limit switches limitSwitchRightStatus = digitalRead(LIMIT_SWITCH_RIGHT); limitSwitchUpStatus = digitalRead(LIMIT_SWITCH_UP); limitSwitchDownStatus = digitalRead(LIMIT_SWITCH_DOWN); upperRightLdrVal = analogRead(LDR_UpR); // Config LDR microcontroller pins upperLeftLdrVal = analogRead(LDR_UpL); lowerLeftLdrVal = analogRead(LDR_LoL); lowerRightLdrVal = analogRead(LDR_LoR); solarPanelAdVal = analogRead(SPV); // Config the microcontroller solar panel pin how analogic solarPanelVoltage = (solarPanelAdVal*5.0)/1023.0; // Analog-to-digital conversion of the voltage obtained by the solar panel. upperAverageLdr = (upperRightLdrVal + upperLeftLdrVal) /2; // Calculation of the average voltage value of the LDRs on each side. lowerAverageLdr = (lowerRightLdrVal + lowerLeftLdrVal) /2; rightAverageLdr = (upperRightLdrVal + lowerRightLdrVal)/2; leftAverageLdr = (upperLeftLdrVal + lowerLeftLdrVal) /2; Serial.print("upperRightLdrVal: "); // Messages on the serial monitor of the LDR value. Serial.println(upperRightLdrVal); Serial.print("upperLeftLdrVal: "); Serial.println(upperLeftLdrVal); Serial.print("lowerLeftLdrVal: "); Serial.println(lowerLeftLdrVal); Serial.print("lowerRightLdrVal: "); Serial.println(lowerRightLdrVal); Serial.println(); Serial.print("Upper LDR Average : "); // Messages on the serial monitor of the averages value. Serial.println(upperAverageLdr); Serial.print("Lower LDR Average : "); Serial.println(lowerAverageLdr); Serial.print("Right LDR Average : "); Serial.println(rightAverageLdr); Serial.print("Left LDR Average : "); Serial.println(leftAverageLdr); Serial.println(); Serial.print("Solar Panel Voltage: "); // Message on the serial monitor of the Analog-to-digital conversion voltage value. Serial.print(solarPanelVoltage, 2); Serial.println(" volts"); Serial.println(); Serial.print("limit switch left state: "); // Message on the serial monitor of the limit switch states. Serial.println(limitSwitchLeftStatus); Serial.print("limit switch right state: "); Serial.println(limitSwitchRightStatus); Serial.print("limit switch up state: "); Serial.println(limitSwitchUpStatus); Serial.print("limit switch down state: "); Serial.println(limitSwitchDownStatus); /***************** Horizontal motor movements **************************/ if (rightAverageLdr == leftAverageLdr) // With similar measure, the motor is off. { stopMoveLeftOrRight(); // Calling the motor stop method. } if (rightAverageLdr > leftAverageLdr && (rightAverageLdr-leftAverageLdr) > toleranceAverageLdr) { // When a measurement is higher and the difference is greater than the toleranceAverageLdr, movePanelLeft(); // moves the horizontal motor in the corresponding direction by method call. } if (leftAverageLdr > rightAverageLdr && (leftAverageLdr-rightAverageLdr) > toleranceAverageLdr) { movePanelRight(); } stopMoveLeftOrRight(); // Calling the motor stop method. delay(500); /**************** Vertical motor movements ****************************/ if (upperAverageLdr == lowerAverageLdr) { // With similar measure, the motor is off. stopMoveUpOrDown(); // Calling the motor stop method. } if (upperAverageLdr > lowerAverageLdr && (upperAverageLdr-lowerAverageLdr) > toleranceAverageLdr) { // When a measurement is higher and the difference is greater than the toleranceAverageLdr, movePanelUp(); // moves the horizontal motor in the corresponding direction by method call. } if (lowerAverageLdr > upperAverageLdr && (lowerAverageLdr-upperAverageLdr) > toleranceAverageLdr) { movePanelDown(); } stopMoveUpOrDown(); // Calling the motor stop method. delay(500); /*************** End of motors movement methods **********************/ oled_message(); // Method call to display the voltage of the solar panel on the OLED screen. } // Method for moving the motor horizontally to the right. void movePanelRight() { for (int i = 0; i < motorStepsToMoveLeftRight; i++) { limitSwitchRightStatus = digitalRead(LIMIT_SWITCH_RIGHT); // limit switch check. if (limitSwitchRightStatus != LIMIT_SWITCH_RIGHT_PRESSED) { digitalWrite(MOTOR_LEFT_RIGHT_ENABLE, MOTOR_ENABLE); // Enable movement digitalWrite(MOTOR_LEFT_RIGHT_DIRECTION, MOTOR_DIRECTION_RIGHT); // set direction for movement digitalWrite(MOTOR_LEFT_RIGHT_PULS, HIGH); delayMicroseconds(motorMoveDelay); digitalWrite(MOTOR_LEFT_RIGHT_PULS, LOW); delayMicroseconds(motorMoveDelay); digitalWrite(MOTOR_LEFT_RIGHT_ENABLE,MOTOR_DISABLE); // Disable movement } else { Serial.println("Limit switch RIGHT pressed! Can't move further!"); break; } } } // Method for moving the motor horizontally to the left. void movePanelLeft() { for (int i = 0; i < motorStepsToMoveLeftRight; i++) { limitSwitchLeftStatus = digitalRead(LIMIT_SWITCH_LEFT); // limit switch check. if (limitSwitchLeftStatus != LIMIT_SWITCH_LEFT_PRESSED) { digitalWrite(MOTOR_LEFT_RIGHT_ENABLE, MOTOR_ENABLE); // Enable movement digitalWrite(MOTOR_LEFT_RIGHT_DIRECTION, MOTOR_DIRECTION_RIGHT); // set direction for movement digitalWrite(MOTOR_LEFT_RIGHT_PULS, HIGH); delayMicroseconds(motorMoveDelay); digitalWrite(MOTOR_LEFT_RIGHT_PULS, LOW); delayMicroseconds(motorMoveDelay); digitalWrite(MOTOR_LEFT_RIGHT_ENABLE,MOTOR_DISABLE); // Disable movement } else { Serial.println("Limit switch LEFT pressed! Can't move further!"); break; } } } // Horizontal motor off method. void stopMoveLeftOrRight() { digitalWrite(MOTOR_LEFT_RIGHT_ENABLE,MOTOR_DISABLE); // disable Motor left right } // Method for moving the motor vertically upward. void movePanelUp() { for (int i = 0; i < motorStepsToMoveUpDown; i++) { limitSwitchUpStatus = digitalRead(LIMIT_SWITCH_UP); // limit switch check if (limitSwitchUpStatus != LIMIT_SWITCH_UP_PRESSED) { digitalWrite(MOTOR_UP_DOWN_ENABLE, MOTOR_ENABLE); // Enable movement digitalWrite(MOTOR_UP_DOWN_DIRECTION, MOTOR_DIRECTION_UP); // set direction for movement digitalWrite(MOTOR_UP_DOWN_PULS, HIGH); delayMicroseconds(motorMoveDelay); digitalWrite(MOTOR_UP_DOWN_PULS, LOW); delayMicroseconds(motorMoveDelay); digitalWrite(MOTOR_UP_DOWN_ENABLE,MOTOR_DISABLE); // Disable movement } else { Serial.println("Limit switch UP pressed! Can't move further!"); break; } } } // Method for moving the motor vertically downward. void movePanelDown() { for (int i = 0; i < motorStepsToMoveUpDown; i++) { limitSwitchUpStatus = digitalRead(LIMIT_SWITCH_DOWN); // limit switch check if (limitSwitchUpStatus != LIMIT_SWITCH_DOWN_PRESSED) { digitalWrite(MOTOR_UP_DOWN_ENABLE, MOTOR_ENABLE); // Enable movement digitalWrite(MOTOR_UP_DOWN_DIRECTION, MOTOR_DIRECTION_DOWN); // set direction for movement digitalWrite(MOTOR_UP_DOWN_PULS, HIGH); delayMicroseconds(motorMoveDelay); digitalWrite(MOTOR_UP_DOWN_PULS, LOW); delayMicroseconds(motorMoveDelay); digitalWrite(MOTOR_UP_DOWN_ENABLE,MOTOR_DISABLE); // Disable movement } else { Serial.println("Limit switch UP pressed! Can't move further!"); break; } } } // Vertical motor off method. void stopMoveUpOrDown() { digitalWrite(MOTOR_UP_DOWN_ENABLE,MOTOR_DISABLE); } void oled_message() { // Solar panel voltage message on the OLED screen. display.clearDisplay(); display.setTextSize(2); display.setCursor(7,0); display.print("Solar Vols"); display.setTextSize(3); display.setCursor(20, 30); display.print(solarPanelVoltage, 2); display.display(); }