1 | /***************************************************************************
|
2 | * Solar light tracker project with Mega 2560 R3 Board microcontroller, *
|
3 | * Solar panel, LDR resistors, 0.96 inch OLED 128X64 pixels display, *
|
4 | * 2 TB6600 modules and 2 NEMA17 step by step motors. *
|
5 | * *
|
6 | * Armin Rolfes / Wilfried Meyer *
|
7 | * Last revisión 04.10.2024 *
|
8 | ***************************************************************************/
|
9 | #include <AccelStepper.h>
|
10 | /************** OLED display library and configuration *************/
|
11 | #include <Wire.h> // I2C communication library.
|
12 | #include <Adafruit_GFX.h> // Core graphics library for screen.
|
13 | #include <Adafruit_SSD1306.h> // SSD1306 oled driver library for monochrome 128x64 display.
|
14 |
|
15 | #define SCREEN_WIDTH 128 // 128 pixels width screen.
|
16 | #define SCREEN_HEIGHT 64 // 64 pixels height screen.
|
17 | Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); // Screen object declaration.
|
18 |
|
19 | /******************* LDR config *********************/
|
20 | int LDR_UpR = A0; // Upper right LDR connected to the analog pin 0 of the microcontroller.
|
21 | int LDR_UpL = A1; // Upper left LDR connected to the analog pin 1 of the microcontroller.
|
22 | int LDR_LoL = A2; // Lower left LDR connected to the analog pin 2 of the microcontroller.
|
23 | int LDR_LoR = A3; // Lower right LDR connected to the analog pin 3 of the microcontroller.
|
24 |
|
25 | int upperRightLdrVal = 0; // Upper right LDR resistor voltage (AD)
|
26 | int upperLeftLdrVal = 0; // Upper left LDR resistor voltage (AD)
|
27 | int lowerLeftLdrVal = 0; // Lower left LDR resistor voltage (AD)
|
28 | int lowerRightLdrVal = 0; // Lower right LDR resistor voltage (AD)
|
29 |
|
30 | int upperAverageLdr = 0; // Arithmetic mean of the upper LDR sensors
|
31 | int lowerAverageLdr = 0; // Arithmetic mean of the lower LDR sensors
|
32 | int rightAverageLdr = 0; // Arithmetic mean of the right LDR sensors
|
33 | int leftAverageLdr = 0; // Arithmetic mean of the left LDR sensors
|
34 |
|
35 | int toleranceAverageLdr = 10; // tolerance for the LDR average values
|
36 |
|
37 | /******************* Solar panel ********************/
|
38 | int SPV = A4; // Solar Panel connected to the analog pin 4 of the microcontroller.
|
39 | int solarPanelAdVal = 0; // value of the direct voltage of the solar panel (AD).
|
40 | float solarPanelVoltage = 0; // Analog-to-Digital converted voltage value
|
41 |
|
42 | /****************** Motors config ******************/
|
43 | int MOTOR_ENABLE = HIGH; // value to enable the motor (LOW or HIGH depending on hardware configuration)
|
44 | int MOTOR_DISABLE = LOW; // value to disable the motor (LOW or HIGH depending on hardware configuration)
|
45 |
|
46 | // config for horizontal movement
|
47 | int MOTOR_LEFT_RIGHT_ENABLE = 41; // enable Pin for Motor for left / right Motor movement / todo//
|
48 | int MOTOR_LEFT_RIGHT_PULS = 37; // Puls Pin for Motor left / right Motor movement / todo//
|
49 | int MOTOR_LEFT_RIGHT_DIRECTION = 39; // direction PIN for Motor left / right Motor movement / todo//
|
50 |
|
51 | int MOTOR_DIRECTION_LEFT = 39 HIGH; // value for which motor moves to the left (LOW or HIGH depending on hardware configuration) / todo//
|
52 | int MOTOR_DIRECTION_RIGHT = 39 LOW; // value for which motor moves to the right (LOW or HIGH depending on hardware configuration) / todo//
|
53 |
|
54 | // config for vertical movement
|
55 | int MOTOR_UP_DOWN_ENABLE = 35; // enable Pin for Motor up / down Motor movement / todo//
|
56 | int MOTOR_UP_DOWN_PULS = 31; // Puls Pin for Motor up / down Motor movement / todo//
|
57 | int MOTOR_UP_DOWN_DIRECTION = 33; // direction PIN for Motor up / down Motor movement / todo//
|
58 |
|
59 | int MOTOR_DIRECTION_UP = 33 HIGH; // value for which motor moves to the up (LOW or HIGH depending on hardware configuration) / todo//
|
60 | int MOTOR_DIRECTION_DOWN = 33 LOW; // value for which motor moves to the down (LOW or HIGH depending on hardware configuration) / todo//
|
61 |
|
62 | /****************** Motors speed ******************/
|
63 | int motorMoveDelay = 500; // Delay between movement steps of the stepper motor [us] / todo//
|
64 | int motorStepsToMoveLeftRight = 5; // Number of steps to move in left or right direction / todo//
|
65 | int motorStepsToMoveUpDown = 2; // Number of steps to move in up or down direction / todo //
|
66 |
|
67 |
|
68 | /****************** limit switches *********************************
|
69 | * Normally closed Sunrise limit switch *
|
70 | * Normally opened Sunset limit switch *
|
71 | ***********************************************************************/
|
72 | int LIMIT_SWITCH_LEFT = 1; // Pin Limit switch left // todo Pin Endschalter links West
|
73 | int LIMIT_SWITCH_LEFT_PRESSED = HIGH; // value for which the LEFT limit switch is pressed (LOW or HIGH depending on hardware configuration) / todo//
|
74 |
|
75 | int LIMIT_SWITCH_RIGHT = 0; // Pin Limit switch right // todo Pin Endschalter rechts Ost
|
76 | int LIMIT_SWITCH_RIGHT_PRESSED = LOW; // value for which the RIGHT limit switch is pressed (LOW or HIGH depending on hardware configuration) / todo//
|
77 |
|
78 | int LIMIT_SWITCH_UP = 2; // Pin Limit switch up // todo Pin Endschalter Oben Nord
|
79 | int LIMIT_SWITCH_UP_PRESSED = HIGH; // value for which the UP limit switch is pressed (LOW or HIGH depending on hardware configuration) // todo//
|
80 |
|
81 | int LIMIT_SWITCH_DOWN = 3; // Pin Limit switch down // todo Pin Endschalter unten Süd
|
82 | int LIMIT_SWITCH_DOWN_PRESSED = HIGH; // value for which the DOWN limit switch is pressed (LOW or HIGH depending on hardware configuration) / todo//
|
83 |
|
84 | int limitSwitchLeftStatus; // current value for left limit switch
|
85 | int limitSwitchRightStatus; // current value for right limit switch
|
86 | int limitSwitchUpStatus; // current value for up limit switch
|
87 | int limitSwitchDownStatus; // current value for down limit switch
|
88 |
|
89 | void setup()
|
90 | {
|
91 |
|
92 | Serial.begin(9600); // Serial monitor initialisation.
|
93 |
|
94 | if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C))
|
95 | { // OLED screen initialisation.
|
96 | Serial.println(F("SSD1306 allocation failed")); // Message if display initialization fails.
|
97 | for(;;);
|
98 | }
|
99 |
|
100 | display.clearDisplay(); // Clear display.
|
101 | display.setTextColor(WHITE); // Set text to white color.
|
102 |
|
103 | // Config LDR Pins
|
104 | pinMode (LDR_UpR, INPUT);
|
105 | pinMode (LDR_UpL, INPUT);
|
106 | pinMode (LDR_LoL, INPUT);
|
107 | pinMode (LDR_LoR, INPUT);
|
108 |
|
109 | pinMode (SPV, INPUT);
|
110 |
|
111 | // Config Motor Pins
|
112 | pinMode(MOTOR_LEFT_RIGHT_ENABLE, OUTPUT); // Enable
|
113 | pinMode(MOTOR_LEFT_RIGHT_PULS, OUTPUT); // Puls
|
114 | pinMode(MOTOR_LEFT_RIGHT_DIRECTION, OUTPUT); // Direction
|
115 | digitalWrite(MOTOR_LEFT_RIGHT_ENABLE, MOTOR_DISABLE); // disable Motor left right
|
116 |
|
117 | pinMode(MOTOR_UP_DOWN_ENABLE, OUTPUT); // Enable
|
118 | pinMode(MOTOR_UP_DOWN_PULS, OUTPUT); // Puls
|
119 | pinMode(MOTOR_UP_DOWN_DIRECTION, OUTPUT); // Direction
|
120 | digitalWrite(MOTOR_UP_DOWN_ENABLE, MOTOR_DISABLE); // disable Motor up down
|
121 |
|
122 | // Config limit switches
|
123 | pinMode (LIMIT_SWITCH_LEFT, INPUT);
|
124 | pinMode (LIMIT_SWITCH_RIGHT, INPUT);
|
125 | pinMode (LIMIT_SWITCH_UP, INPUT);
|
126 | pinMode (LIMIT_SWITCH_DOWN, INPUT);
|
127 |
|
128 | // set back to start position
|
129 | limitSwitchRightStatus = digitalRead(LIMIT_SWITCH_RIGHT);
|
130 | while (limitSwitchRightStatus != LIMIT_SWITCH_RIGHT_PRESSED)
|
131 | { // Check of the sunrise limit switch
|
132 | Serial.println("move Panel to Start position"); // Message on OLED display.
|
133 | movePanelRight(); // Call to the initialize horizontal motor method.
|
134 | limitSwitchRightStatus = digitalRead(LIMIT_SWITCH_RIGHT); // Sunrise limit switch check, initial status must be LOW to exit the loop.
|
135 | }
|
136 |
|
137 | }
|
138 |
|
139 | void loop()
|
140 | {
|
141 | limitSwitchLeftStatus = digitalRead(LIMIT_SWITCH_LEFT); // read limit switches
|
142 | limitSwitchRightStatus = digitalRead(LIMIT_SWITCH_RIGHT);
|
143 | limitSwitchUpStatus = digitalRead(LIMIT_SWITCH_UP);
|
144 | limitSwitchDownStatus = digitalRead(LIMIT_SWITCH_DOWN);
|
145 |
|
146 | upperRightLdrVal = analogRead(LDR_UpR); // Config LDR microcontroller pins
|
147 | upperLeftLdrVal = analogRead(LDR_UpL);
|
148 | lowerLeftLdrVal = analogRead(LDR_LoL);
|
149 | lowerRightLdrVal = analogRead(LDR_LoR);
|
150 |
|
151 | solarPanelAdVal = analogRead(SPV); // Config the microcontroller solar panel pin how analogic
|
152 | solarPanelVoltage = (solarPanelAdVal*5.0)/1023.0; // Analog-to-digital conversion of the voltage obtained by the solar panel.
|
153 |
|
154 | upperAverageLdr = (upperRightLdrVal + upperLeftLdrVal) /2; // Calculation of the average voltage value of the LDRs on each side.
|
155 | lowerAverageLdr = (lowerRightLdrVal + lowerLeftLdrVal) /2;
|
156 | rightAverageLdr = (upperRightLdrVal + lowerRightLdrVal)/2;
|
157 | leftAverageLdr = (upperLeftLdrVal + lowerLeftLdrVal) /2;
|
158 |
|
159 | Serial.print("upperRightLdrVal: "); // Messages on the serial monitor of the LDR value.
|
160 | Serial.println(upperRightLdrVal);
|
161 | Serial.print("upperLeftLdrVal: ");
|
162 | Serial.println(upperLeftLdrVal);
|
163 | Serial.print("lowerLeftLdrVal: ");
|
164 | Serial.println(lowerLeftLdrVal);
|
165 | Serial.print("lowerRightLdrVal: ");
|
166 | Serial.println(lowerRightLdrVal);
|
167 | Serial.println();
|
168 |
|
169 | Serial.print("Upper LDR Average : "); // Messages on the serial monitor of the averages value.
|
170 | Serial.println(upperAverageLdr);
|
171 | Serial.print("Lower LDR Average : ");
|
172 | Serial.println(lowerAverageLdr);
|
173 | Serial.print("Right LDR Average : ");
|
174 | Serial.println(rightAverageLdr);
|
175 | Serial.print("Left LDR Average : ");
|
176 | Serial.println(leftAverageLdr);
|
177 | Serial.println();
|
178 |
|
179 | Serial.print("Solar Panel Voltage: "); // Message on the serial monitor of the Analog-to-digital conversion voltage value.
|
180 | Serial.print(solarPanelVoltage, 2);
|
181 | Serial.println(" volts");
|
182 | Serial.println();
|
183 |
|
184 | Serial.print("limit switch left state: "); // Message on the serial monitor of the limit switch states.
|
185 | Serial.println(limitSwitchLeftStatus);
|
186 | Serial.print("limit switch right state: ");
|
187 | Serial.println(limitSwitchRightStatus);
|
188 | Serial.print("limit switch up state: ");
|
189 | Serial.println(limitSwitchUpStatus);
|
190 | Serial.print("limit switch down state: ");
|
191 | Serial.println(limitSwitchDownStatus);
|
192 |
|
193 | /***************** Horizontal motor movements **************************/
|
194 | if (rightAverageLdr == leftAverageLdr) // With similar measure, the motor is off.
|
195 | {
|
196 | stopMoveLeftOrRight(); // Calling the motor stop method.
|
197 | }
|
198 |
|
199 | if (rightAverageLdr > leftAverageLdr && (rightAverageLdr-leftAverageLdr) > toleranceAverageLdr)
|
200 | { // When a measurement is higher and the difference is greater than the toleranceAverageLdr,
|
201 | movePanelLeft(); // moves the horizontal motor in the corresponding direction by method call.
|
202 | }
|
203 |
|
204 | if (leftAverageLdr > rightAverageLdr && (leftAverageLdr-rightAverageLdr) > toleranceAverageLdr)
|
205 | {
|
206 | movePanelRight();
|
207 | }
|
208 |
|
209 | stopMoveLeftOrRight(); // Calling the motor stop method.
|
210 | delay(500);
|
211 |
|
212 | /**************** Vertical motor movements ****************************/
|
213 | if (upperAverageLdr == lowerAverageLdr)
|
214 | { // With similar measure, the motor is off.
|
215 | stopMoveUpOrDown(); // Calling the motor stop method.
|
216 | }
|
217 |
|
218 | if (upperAverageLdr > lowerAverageLdr && (upperAverageLdr-lowerAverageLdr) > toleranceAverageLdr)
|
219 | { // When a measurement is higher and the difference is greater than the toleranceAverageLdr,
|
220 | movePanelUp(); // moves the horizontal motor in the corresponding direction by method call.
|
221 | }
|
222 |
|
223 | if (lowerAverageLdr > upperAverageLdr && (lowerAverageLdr-upperAverageLdr) > toleranceAverageLdr)
|
224 | {
|
225 | movePanelDown();
|
226 | }
|
227 |
|
228 | stopMoveUpOrDown(); // Calling the motor stop method.
|
229 | delay(500);
|
230 |
|
231 | /*************** End of motors movement methods **********************/
|
232 |
|
233 | oled_message(); // Method call to display the voltage of the solar panel on the OLED screen.
|
234 |
|
235 | }
|
236 |
|
237 | // Method for moving the motor horizontally to the right.
|
238 | void movePanelRight()
|
239 | {
|
240 | for (int i = 0; i < motorStepsToMoveLeftRight; i++)
|
241 | {
|
242 | limitSwitchRightStatus = digitalRead(LIMIT_SWITCH_RIGHT); // limit switch check.
|
243 | if (limitSwitchRightStatus != LIMIT_SWITCH_RIGHT_PRESSED)
|
244 | {
|
245 | digitalWrite(MOTOR_LEFT_RIGHT_ENABLE, MOTOR_ENABLE); // Enable movement
|
246 | digitalWrite(MOTOR_LEFT_RIGHT_DIRECTION, MOTOR_DIRECTION_RIGHT); // set direction for movement
|
247 |
|
248 | digitalWrite(MOTOR_LEFT_RIGHT_PULS, HIGH);
|
249 | delayMicroseconds(motorMoveDelay);
|
250 | digitalWrite(MOTOR_LEFT_RIGHT_PULS, LOW);
|
251 | delayMicroseconds(motorMoveDelay);
|
252 |
|
253 | digitalWrite(MOTOR_LEFT_RIGHT_ENABLE,MOTOR_DISABLE); // Disable movement
|
254 | }
|
255 | else
|
256 | {
|
257 | Serial.println("Limit switch RIGHT pressed! Can't move further!");
|
258 | break;
|
259 | }
|
260 | }
|
261 | }
|
262 |
|
263 | // Method for moving the motor horizontally to the left.
|
264 | void movePanelLeft()
|
265 | {
|
266 | for (int i = 0; i < motorStepsToMoveLeftRight; i++)
|
267 | {
|
268 | limitSwitchLeftStatus = digitalRead(LIMIT_SWITCH_LEFT); // limit switch check.
|
269 | if (limitSwitchLeftStatus != LIMIT_SWITCH_LEFT_PRESSED)
|
270 | {
|
271 | digitalWrite(MOTOR_LEFT_RIGHT_ENABLE, MOTOR_ENABLE); // Enable movement
|
272 | digitalWrite(MOTOR_LEFT_RIGHT_DIRECTION, MOTOR_DIRECTION_RIGHT); // set direction for movement
|
273 |
|
274 | digitalWrite(MOTOR_LEFT_RIGHT_PULS, HIGH);
|
275 | delayMicroseconds(motorMoveDelay);
|
276 | digitalWrite(MOTOR_LEFT_RIGHT_PULS, LOW);
|
277 | delayMicroseconds(motorMoveDelay);
|
278 |
|
279 | digitalWrite(MOTOR_LEFT_RIGHT_ENABLE,MOTOR_DISABLE); // Disable movement
|
280 | }
|
281 | else
|
282 | {
|
283 | Serial.println("Limit switch LEFT pressed! Can't move further!");
|
284 | break;
|
285 | }
|
286 | }
|
287 | }
|
288 |
|
289 | // Horizontal motor off method.
|
290 | void stopMoveLeftOrRight()
|
291 | {
|
292 | digitalWrite(MOTOR_LEFT_RIGHT_ENABLE,MOTOR_DISABLE); // disable Motor left right
|
293 | }
|
294 |
|
295 | // Method for moving the motor vertically upward.
|
296 | void movePanelUp()
|
297 | {
|
298 | for (int i = 0; i < motorStepsToMoveUpDown; i++)
|
299 | {
|
300 | limitSwitchUpStatus = digitalRead(LIMIT_SWITCH_UP); // limit switch check
|
301 | if (limitSwitchUpStatus != LIMIT_SWITCH_UP_PRESSED)
|
302 | {
|
303 | digitalWrite(MOTOR_UP_DOWN_ENABLE, MOTOR_ENABLE); // Enable movement
|
304 | digitalWrite(MOTOR_UP_DOWN_DIRECTION, MOTOR_DIRECTION_UP); // set direction for movement
|
305 |
|
306 | digitalWrite(MOTOR_UP_DOWN_PULS, HIGH);
|
307 | delayMicroseconds(motorMoveDelay);
|
308 | digitalWrite(MOTOR_UP_DOWN_PULS, LOW);
|
309 | delayMicroseconds(motorMoveDelay);
|
310 |
|
311 | digitalWrite(MOTOR_UP_DOWN_ENABLE,MOTOR_DISABLE); // Disable movement
|
312 | }
|
313 | else
|
314 | {
|
315 | Serial.println("Limit switch UP pressed! Can't move further!");
|
316 | break;
|
317 | }
|
318 | }
|
319 | }
|
320 |
|
321 | // Method for moving the motor vertically downward.
|
322 | void movePanelDown()
|
323 | {
|
324 | for (int i = 0; i < motorStepsToMoveUpDown; i++)
|
325 | {
|
326 | limitSwitchUpStatus = digitalRead(LIMIT_SWITCH_DOWN); // limit switch check
|
327 | if (limitSwitchUpStatus != LIMIT_SWITCH_DOWN_PRESSED)
|
328 | {
|
329 | digitalWrite(MOTOR_UP_DOWN_ENABLE, MOTOR_ENABLE); // Enable movement
|
330 | digitalWrite(MOTOR_UP_DOWN_DIRECTION, MOTOR_DIRECTION_DOWN); // set direction for movement
|
331 |
|
332 | digitalWrite(MOTOR_UP_DOWN_PULS, HIGH);
|
333 | delayMicroseconds(motorMoveDelay);
|
334 | digitalWrite(MOTOR_UP_DOWN_PULS, LOW);
|
335 | delayMicroseconds(motorMoveDelay);
|
336 |
|
337 | digitalWrite(MOTOR_UP_DOWN_ENABLE,MOTOR_DISABLE); // Disable movement
|
338 | }
|
339 | else
|
340 | {
|
341 | Serial.println("Limit switch UP pressed! Can't move further!");
|
342 | break;
|
343 | }
|
344 | }
|
345 | }
|
346 |
|
347 | // Vertical motor off method.
|
348 | void stopMoveUpOrDown()
|
349 | {
|
350 | digitalWrite(MOTOR_UP_DOWN_ENABLE,MOTOR_DISABLE);
|
351 | }
|
352 |
|
353 | void oled_message() { // Solar panel voltage message on the OLED screen.
|
354 | display.clearDisplay();
|
355 | display.setTextSize(2);
|
356 | display.setCursor(7,0);
|
357 | display.print("Solar Vols");
|
358 | display.setTextSize(3);
|
359 | display.setCursor(20, 30);
|
360 | display.print(solarPanelVoltage, 2);
|
361 | display.display();
|
362 | }
|