Зарядная станция с автоматической ориентацией солнечных панелей

Источник:

Зарядная станция с автоматической ориентацией солнечных панелей

Прошлым летом я приобрел небольшой солнечный модуль. В инструкции по эксплуатации указано, что его следует ориентировать на юг с углом наклона 35°, чтобы заряжать аккумулятор на 3,7 В через модуль Solar Power Manager.
Однако, чтобы днем он всегда был направлен в сторону солнца, я решил попробовать построить полностью автоматический следящий механизм с помощью датчика освещенности и двух сервоприводов.

Как всегда, я действовал постепенно. Сначала протестировал датчик освещенности, затем сервоприводы. Затем было интересно наблюдать за взаимодействием компонентов при поиске самой яркой точки.
Самое важное было задокументировано здесь, и я надеюсь, что это вдохновит кого-нибудь на создание собственной версии.
Когда версия 1 с Arduino была готова и работала, я сразу же создал вторую версию с платой ESP32, с тем чтобы при переходе в спящий режим устройство потребляло меньше энергии и, таким образом, более эффективно заряжало аккумулятор.

Но как же измерить интенсивность света?
Наиболее эффективная длина волны для наиболее распространенных солнечных батарей лежит в видимом диапазоне спектра света. Световой поток в 1 люмен, падающий на площадь 1 м², освещает ее (в среднем) с интенсивностью 1 люкс.
Интенсивность освещенности – Википедия

Итак, сначала поиск подходящего датчика освещенности.

Оборудование 1: Измерение освещенности с помощью GY-30

Изображение

Плата расширения датчика освещенности GY-30 / BH1750FVI оснащена фотодиодом, способным улавливать большую часть видимого света в диапазоне примерно от 400 до 700 нм. Чем ярче свет, тем выше значение освещенности в люксах, выдаваемое 16-разрядным аналого-цифровым преобразователем. Плата может выполнять как непрерывные, так и единичные измерения. Управление осуществляется через интерфейс I2C, питание — от 3,3 до 5 В.
Технические характеристики датчика освещенности GY-30

Подключение, часть 1:

Изображение

Исходный код для теста датчика освещенности:

Первое измерение освещенности в люксах.

  1. #include "BH1750FVI.h"
  2.  
  3. BH1750FVI myLux(0x23);
  4. uint32_t lastUpdate = 0;
  5.  
  6. void setup()
  7. {
  8. Serial.begin(115200);
  9. Serial.println();
  10. Serial.print(__FILE__);// liefert den Pfad zur aktuellen Datei
  11. Serial.println();
  12.  
  13. Wire.begin(); // für arduino uno
  14. // Wire.begin(23,19); // für lolin32 lite an SDA (Serial Data): Pin 23 und SCL (Serial Clock): Pin 19
  15.  
  16. myLux.powerOn();
  17. myLux.setContHighRes(); // Für kontinuierliche Messung
  18. // myLux.setOnceHighRes();// Für einmalige Messung - Stromsparmodus
  19. }
  20.  
  21. void loop()
  22. {
  23. uint16_t interval = 100;
  24. if (millis() - lastUpdate >= interval)
  25. {
  26. lastUpdate += interval;
  27. float val = myLux.getLux();
  28. Serial.println(val, 1);
  29. }
  30. delay(1000);
  31. // myLux.setOnceHighRes();// Für einmalige Messung - Stromsparmodus
  32. }

Еще одним открытием стало то, что библиотека для датчика освещенности позволяет выполнять однократное измерение, чтобы впоследствии сэкономить энергию. Однако в таком случае при каждом новом измерении необходимо вводить myLux.setOnceHighRes();. Измерение с помощью USB-тестера напряжения не показало никаких изменений. Поэтому я пока оставил это без внимания.

Оборудование 2: Сервопривод MG996R
MG996R — это цифровой микросервопривод, известный своим применением в дистанционно управляемых роботах, вертолетах и самолетах.
Он оснащен металлической передачей для повышенной прочности и может поворачиваться в диапазоне около 180 градусов. Его положение можно регулировать с высокой точностью.
Благодаря своей низкой стоимости и простоте в обращении он пользуется популярностью у любителей-конструкторов, и, следовательно, у меня.
Технические характеристики сервопривода

Подключение, часть 2:

Изображение

Исходный код
Для начала — тест с одним сервоприводом:

  1. #include <Servo.h> //f&uuml;r Arduino Uno
  2.  
  3.  
  4. Servo servo; // Servo-Objekt erstellen f&uuml;r Arduino
  5.  
  6. const int servoPin = 9; // servo1 gelb unten horizontal an Pin 9
  7.  
  8. void setup() {
  9. servo.attach(servoPin); //
  10. }
  11.  
  12. void loop() {
  13. servo.write(0); // move MG996R's shaft to angle 0&deg;
  14. delay(1000); // wait for one second
  15. servo.write(45); // move MG996R's shaft to angle 45&deg;
  16. delay(1000); // wait for one second
  17. servo.write(90); // move MG996R's shaft to angle 90&deg;
  18. delay(1000); // wait for one second
  19. servo.write(135); // move MG996R's shaft to angle 135&deg;
  20. delay(1000); // wait for one second
  21. servo.write(180); // move MG996R's shaft to angle 180&deg;
  22. delay(1000); // wait for one second
  23. }

Теперь тест с двумя сервоприводами:

  1. #include <Servo.h>
  2.  
  3. Servo servo1; // der MG 996R servo1
  4. Servo servo2; // der MG 996R servo2
  5.  
  6. void setup() {
  7. servo1.attach(9); // servo1 gelb unten horizontal an Pin 9
  8. servo2.attach(10); // orange servo2 oben vertikal an Pin 10
  9. }
  10.  
  11. void loop() {
  12. servo2.write(45); // move MG996R's shaft to angle 0&deg;
  13. delay(1000); // wait for one second
  14. servo1.write(45); // move MG996R's shaft to angle 45&deg;
  15. delay(1000); // wait for one second
  16. servo2.write(90); // move MG996R's shaft to angle 90&deg;
  17. delay(1000); // wait for one second
  18. servo1.write(90); // move MG996R's shaft to angle 135&deg;
  19. delay(1000); // wait for one second
  20. servo2.write(135); // move MG996R's shaft to angle 180&deg;
  21. delay(1000); // wait for one second
  22. servo1.write(135); // move MG996R's shaft to angle 180&deg;
  23. delay(1000); // wait for one second
  24. }

Третье испытание:
Датчик освещенности управляет сервоприводом, GY-30 и MG996r одновременно

Теперь датчик освещенности и оба сервопривода работают вместе для первоначального горизонтального сканирования с целью нахождения самой яркой точки.

Подключение, часть 3: 

Изображение

Исходный код для сканирования:

Тестовое сканирование самой яркой точки по горизонтали

  1. #include "BH1750FVI.h"
  2. #include <Servo.h>
  3.  
  4. BH1750FVI myLux(0x23);
  5. uint32_t lastUpdate = 0;
  6.  
  7. Servo servo1; // der MG996R servo1
  8. Servo servo2; // der MG996R servo2
  9.  
  10. void setup(){
  11. Wire.begin();
  12. myLux.powerOn();
  13. myLux.setContHighRes();
  14. servo1.attach(9); // servo1 gelb unten horizontal an Pin 9
  15. servo2.attach(10); // orange servo2 oben vertikal an Pin 10
  16. }
  17.  
  18. void loop() {
  19. int maxLightIntensity = 0; // Maximal gemessene Lichtintensit&auml;t
  20. int maxAngle = 0; // Winkel mit der h&ouml;chsten Lichtintensit&auml;t
  21.  
  22. // Durchlaufe alle Winkel von 0 bis 180 Grad
  23. for(int angle = 0; angle <= 180; angle += 10){
  24. servo1.write(angle); // Drehe den Servo auf den aktuellen Winkel
  25. delay(200); // Warte einen Moment, damit sich der Servo drehen kann
  26.  
  27. uint16_t lux = myLux.getLux(); // Lese die Lichtintensit&auml;t
  28. if(lux > maxLightIntensity){
  29. maxLightIntensity = lux;
  30. maxAngle = angle;
  31. }
  32. }
  33.  
  34. // Drehe den Servo auf den Winkel mit der h&ouml;chsten Lichtintensit&auml;t
  35. servo1.write(maxAngle);
  36. delay(10000); // Warte einen Moment, bevor der n&auml;chste Durchlauf beginnt
  37. }

Тест сканирования самой яркой точки по горизонтали и вертикали

  1. #include "BH1750FVI.h"
  2. #include <Servo.h>
  3.  
  4. BH1750FVI myLux(0x23);
  5.  
  6. Servo servo1; // der MG 996R servo1
  7. Servo servo2; // der MG 996R servo2
  8.  
  9. void setup(){
  10. Serial.begin(115200);
  11. Serial.println();
  12. Serial.print(__FILE__);// liefert den Pfad zur aktuellen Datei
  13. Serial.println();
  14.  
  15. Wire.begin();
  16. myLux.powerOn();
  17. myLux.setContHighRes();
  18. servo1.attach(9); // servo1 gelb unten horizontal an Pin 9
  19. servo2.attach(10); // orange servo2 oben vertikal an Pin 10
  20. servo1.write(90);
  21. servo2.write(90);
  22. }
  23.  
  24. void loop() {
  25. int maxLightIntensity1 = 0; // Maximal gemessene Lichtintensit&auml;t horizontal
  26. int maxAngle1 = 0; // Winkel mit der h&ouml;chsten Lichtintensit&auml;t horizontal
  27. int maxLightIntensity2 = 0; // Maximal gemessene Lichtintensit&auml;t vertikal
  28. int maxAngle2 = 0; // Winkel mit der h&ouml;chsten Lichtintensit&auml;t vertikal
  29.  
  30. // Durchlaufe alle Winkel von 0 bis 180 Grad horizontal
  31. for(int angle1 = 0; angle1 <= 180; angle1 += 10){
  32. servo1.write(angle1); // Drehe den Servo auf den aktuellen Winkel
  33. delay(500); // Warte einen Moment, damit sich der Servo drehen kann
  34.  
  35. uint16_t lux = myLux.getLux(); // Lese die Lichtintensit&auml;t
  36. if(lux > maxLightIntensity1){
  37. maxLightIntensity1 = lux;
  38. maxAngle1 = angle1;
  39. Serial.print("MaxLux1: ");
  40. Serial.println(maxLightIntensity1, 1);
  41. Serial.print("Bester Winkel horizontal: ");
  42. Serial.println(maxAngle1, 1);
  43. }
  44. }
  45.  
  46. // Durchlaufe alle Winkel von 0 bis 180 Grad vertikal
  47. for(int angle2 = 20; angle2 <= 160; angle2 += 10){
  48. servo2.write(angle2); // Drehe den Servo auf den aktuellen Winkel
  49. delay(500); // Warte einen Moment, damit sich der Servo drehen kann
  50.  
  51. uint16_t lux = myLux.getLux(); // Lese die Lichtintensit&auml;t
  52. if(lux > maxLightIntensity2){
  53. maxLightIntensity2 = lux;
  54. maxAngle2 = angle2;
  55. Serial.print("MaxLux2: ");
  56. Serial.println(maxLightIntensity2, 1);
  57. Serial.print("Bester Winkel horizontal: ");
  58. Serial.println(maxAngle2, 1);
  59. }
  60. }
  61.  
  62. // Drehe den Servo auf den Winkel mit der h&ouml;chsten Lichtintensit&auml;t
  63. servo1.write(maxAngle1);
  64. servo2.write(maxAngle2);
  65. Serial.print("Bester Winkel 1 und 2 : ");
  66. Serial.print(maxAngle1, 1);
  67. Serial.print(" und ");
  68. Serial.println(maxAngle2, 1);
  69. delay(10000); // Warte einen Moment, bevor der n&auml;chste Durchlauf beginnt
  70. }

Чтобы обеспечить полное сканирование на 360 градусов с помощью 180-градусных сервоприводов, необходимо выполнить 3 цикла.

1-й проход: все углы от 0 до 180 градусов по горизонтали при 35 градусах по вертикали.
2-й проход: все углы от 0 до 180 градусов по горизонтали при 145 градусах по вертикали.
3-й проход: все углы от 0 до 180 градусов по вертикали с оптимальным значением по горизонтали.

  1. #include "BH1750FVI.h"
  2. #include <Servo.h>
  3.  
  4. BH1750FVI myLux(0x23);
  5.  
  6. Servo servo1; // der MG 996R servo1
  7. Servo servo2; // der MG 996R servo2
  8.  
  9. void setup(){
  10. Serial.begin(115200);
  11. Serial.println();
  12. Serial.print(__FILE__); // liefert den Pfad zur aktuellen Datei
  13. Serial.println();
  14.  
  15. Wire.begin();
  16. myLux.powerOn();
  17. myLux.setContHighRes(); // F&uuml;r kontinuierliche Messung
  18. servo1.attach(9); // servo1 gelb unten horizontal an Pin 9
  19. servo2.attach(10); // orange servo2 oben vertikal an Pin 10
  20. servo1.write(90);
  21. servo2.write(90);
  22. }
  23.  
  24. void loop() {
  25. int maxLightIntensity1 = 0; // Maximal gemessene Lichtintensit&auml;t horizontal
  26. int maxAngle1 = 0; // Winkel mit der h&ouml;chsten Lichtintensit&auml;t horizontal
  27. int maxLightIntensity2 = 0; // Maximal gemessene Lichtintensit&auml;t vertikal
  28. int maxAngle2 = 0; // Winkel mit der h&ouml;chsten Lichtintensit&auml;t vertikal
  29.  
  30. // Durchlauf alle Winkel von 0 bis 180 Grad horizontal bei 35 Grad
  31. servo2.write(35);
  32. for(int angle1 = 0; angle1 <= 180; angle1 += 10){
  33. servo1.write(angle1); // Drehe den Servo auf den aktuellen Winkel
  34. delay(500); // Warte einen Moment, damit sich der Servo drehen kann
  35.  
  36. uint16_t lux = myLux.getLux(); // Lese die Lichtintensit&auml;t
  37. if(lux > maxLightIntensity1){
  38. maxLightIntensity1 = lux;
  39. maxAngle1 = angle1;
  40. Serial.print("MaxLux1: ");
  41. Serial.println(maxLightIntensity1, 1);
  42. Serial.print("Bester Winkel horizontal: ");
  43. Serial.println(maxAngle1, 1);
  44. }
  45. }
  46.  
  47. // Durchlauf alle Winkel von 0 bis 180 Grad horizontal bei 145 Grad
  48. servo2.write(145);
  49. for(int angle1 = 180; angle1 >= 0; angle1 -= 10){
  50. servo1.write(angle1); // Drehe den Servo auf den aktuellen Winkel
  51. delay(500); // Warte einen Moment, damit sich der Servo drehen kann
  52.  
  53. uint16_t lux = myLux.getLux(); // Lese die Lichtintensit&auml;t
  54. if(lux > maxLightIntensity1){
  55. maxLightIntensity1 = lux;
  56. maxAngle1 = angle1;
  57. Serial.print("MaxLux1: ");
  58. Serial.println(maxLightIntensity1, 1);
  59. Serial.print("Bester Winkel horizontal: ");
  60. Serial.println(maxAngle1, 1);
  61. }
  62. }
  63. // Durchlauf alle Winkel von 0 bis 180 Grad vertikal mit bester Wert bei horizontal
  64. servo1.write(maxAngle1);
  65. for(int angle2 = 30; angle2 <= 150; angle2 += 10){
  66. servo2.write(angle2); // Drehe den Servo auf den aktuellen Winkel
  67. delay(500); // Warte einen Moment, damit sich der Servo drehen kann
  68.  
  69. uint16_t lux = myLux.getLux(); // Lese die Lichtintensit&auml;t
  70. if(lux > maxLightIntensity2){
  71. maxLightIntensity2 = lux;
  72. maxAngle2 = angle2;
  73. Serial.print("MaxLux2: ");
  74. Serial.println(maxLightIntensity2, 1);
  75. Serial.print("Bester Winkel horizontal: ");
  76. Serial.println(maxAngle2, 1);
  77. }
  78. }
  79.  
  80. // Drehe den Servo auf den Winkel mit der h&ouml;chsten Lichtintensit&auml;t
  81.  
  82. servo1.write(maxAngle1);
  83. servo2.write(maxAngle2);
  84. Serial.print("Bester Winkel 1 und 2 : ");
  85. Serial.print(maxAngle1, 1);
  86. Serial.print(" und ");
  87. Serial.println(maxAngle2, 1);
  88. delay(300000); // Warte 5 Minuten, bevor der n&auml;chste Durchlauf beginnt
  89. }

Попробуй ускорить процесс:
Сократи время измерения после обнаружения максимального значения. (В ходе длительного тестирования этот метод не всегда эффективен в зависимости от облачности)

  1. #include "BH1750FVI.h"
  2. #include <Servo.h>
  3.  
  4. BH1750FVI myLux(0x23);
  5.  
  6. Servo servo1; // der MG 996R servo1
  7. Servo servo2; // der MG 996R servo2
  8.  
  9. void setup(){
  10. Serial.begin(115200);
  11. Serial.println();
  12. Serial.print(__FILE__); // liefert den Pfad zur aktuellen Datei
  13. Serial.println();
  14.  
  15. Wire.begin();
  16. myLux.powerOn();
  17. myLux.setContHighRes();
  18. servo1.attach(9); // servo1 ist am Arduino an Pin 9
  19. servo2.attach(10); // orange servo2 oben vertikal an Pin 10
  20.  
  21. }
  22.  
  23. void loop() {
  24. int maxLightIntensity1 = 0; // Maximal gemessene Lichtintensit&auml;t horizontal
  25. int maxAngle1 = 0; // Winkel mit der h&ouml;chsten Lichtintensit&auml;t horizontal
  26. int maxLightIntensity2 = 0; // Maximal gemessene Lichtintensit&auml;t vertikal
  27. int maxAngle2 = 0; // Winkel mit der h&ouml;chsten Lichtintensit&auml;t vertikal
  28.  
  29. // Durchlaufe alle Winkel von 0 bis 180 Grad horizontal bei 35 Grad
  30. servo2.write(35);
  31. for(int angle1 = 0; angle1 <= 180; angle1 += 10){
  32. servo1.write(angle1); // Drehe den Servo auf den aktuellen Winkel
  33. delay(500); // Warte einen Moment, damit sich der Servo drehen kann
  34.  
  35. uint16_t lux = myLux.getLux(); // Lese die Lichtintensit&auml;t
  36. if(lux > maxLightIntensity1){
  37. maxLightIntensity1 = lux;
  38. maxAngle1 = angle1;
  39. Serial.print("MaxLux1: ");
  40. Serial.println(maxLightIntensity1, 1);
  41. Serial.print("Bester Winkel horizontal: ");
  42. Serial.println(maxAngle1, 1);
  43. }
  44. else if(lux < maxLightIntensity1){ // Bei abnehmender Helligkeit, breche die Schleife ab
  45. break;
  46. }
  47. }
  48.  
  49. // Durchlaufe alle Winkel von 0 bis 180 Grad horizontal bei 120 Grad
  50. servo2.write(120);
  51. for(int angle1 = 180; angle1 >= 0; angle1 -= 10){
  52. servo1.write(angle1); // Drehe den Servo auf den aktuellen Winkel
  53. delay(500); // Warte einen Moment, damit sich der Servo drehen kann
  54.  
  55. uint16_t lux = myLux.getLux(); // Lese die Lichtintensit&auml;t
  56. if(lux > maxLightIntensity1){
  57. maxLightIntensity1 = lux;
  58. maxAngle1 = angle1;
  59. Serial.print("MaxLux1: ");
  60. Serial.println(maxLightIntensity1, 1);
  61. Serial.print("Bester Winkel horizontal: ");
  62. Serial.println(maxAngle1, 1);
  63. }
  64. else if(lux < maxLightIntensity1){ // Bei abnehmender Helligkeit, breche die Schleife ab
  65. break;
  66. }
  67. }
  68. // Durchlaufe alle Winkel von 0 bis 180 Grad vertikal
  69. servo1.write(maxAngle1);
  70. for(int angle2 = 30; angle2 <= 150; angle2 += 10){
  71. servo2.write(angle2); // Drehe den Servo auf den aktuellen Winkel
  72. delay(500); // Warte einen Moment, damit sich der Servo drehen kann
  73.  
  74. uint16_t lux = myLux.getLux(); // Lese die Lichtintensit&auml;t
  75. if(lux > maxLightIntensity2){
  76. maxLightIntensity2 = lux;
  77. maxAngle2 = angle2;
  78. Serial.print("MaxLux2: ");
  79. Serial.println(maxLightIntensity2, 1);
  80. Serial.print("Bester Winkel horizontal: ");
  81. Serial.println(maxAngle2, 1);
  82. }
  83. else if(lux < maxLightIntensity2){ // Bei abnehmender Helligkeit, breche die Schleife ab
  84. break;
  85. }
  86. }
  87.  
  88. // Drehe den Servo auf den Winkel mit der h&ouml;chsten Lichtintensit&auml;t
  89.  
  90. servo1.write(maxAngle1);
  91. servo2.write(maxAngle2);
  92. Serial.print("Bester Winkel 1 und 2 : ");
  93. Serial.print(maxAngle1, 1);
  94. Serial.print(" und ");
  95. Serial.println(maxAngle2, 1);
  96. delay(300000); // Warte 5 Minuten, bevor der n&auml;chste Durchlauf beginnt
  97. }

Пока что почти всё работает. В качестве текущей финальной версии я использую поиск оптимального угла в 3 прогонах.
Теперь осталось подключить Servo Power Manager и аккумулятор (схема подключения показана на Lolin32) — и можно приступать к измерению потребляемого тока. Потребление Arduino составляет 0,058 А·ч.

Версия на Arduino готова.

Вторая версия с платой ESP32 Lolin32 Lite

В этой второй версии я заменил плату Arduino на Lolin32 Lite. Я хочу провести более длительное тестирование, чтобы проверить, будет ли плата без проблем работать с сервомоторами, когда она переходит в спящий режим. Первые измерения показывают, что во время «сна» потребление снижается с 0,052 Ач до 0,008 Ач.

Подключение с Lolin32 Lite:

Изображение

Тест датчика освещенности:
Скетч для тестирования измерения освещенности идентичен версии для Arduino; необходимо лишь добавить в функцию setup строку wire.begin() с указанием номера вывода: SDA (последовательные данные) — на вывод 23, а SCL (последовательный такт) — на вывод 19.

Изображение

Исходный код теста сервопривода на Lolin32:

Вот скетч для второго теста сервопривода с использованием библиотеки esp32servo (версия 1.1.2) и для проверки, не затянут ли где-нибудь кабели или не мешают ли они.

  1. #include <Arduino.h>
  2. #include <ESP32Servo.h> // Die ESP32Servo-Bibliothek einbinden
  3.  
  4. const int servoPin1 = 5; // gelb servo 1 unten horizontal an Pin 5
  5. const int servoPin2 = 18; // orange servo 2 oben vertikal an Pin 18
  6.  
  7. Servo myServo1; // Servo1-Objekt erstellen
  8. Servo myServo2; // Servo2-Objekt erstellen
  9.  
  10. void setup() {
  11.  
  12. myServo1.attach(servoPin1);
  13. myServo2.attach(servoPin2);
  14. }
  15.  
  16. void loop() {
  17. myServo2.write(90); // Servo 2 auf 90 Grad (Mittelstellung) drehen
  18. delay(5000);
  19. myServo1.write(90); // Servo1 auf 90 Grad (Mittelstellung) drehen
  20. delay(5000); // 5 Sekunde warten
  21. myServo1.write(0);
  22. delay(5000);
  23. myServo1.write(180);
  24. delay(5000);
  25.  
  26. myServo2.write(30); // Servo 2 auf 30 Grad drehen
  27. delay(5000);
  28. myServo1.write(0);
  29. delay(5000);
  30. myServo1.write(90);
  31. delay(5000);
  32. myServo1.write(180);
  33. delay(5000);
  34.  
  35. myServo2.write(150); // Servo 2 auf 150 Grad drehen
  36. delay(5000);
  37. myServo1.write(0);
  38. delay(5000);
  39. myServo1.write(90);
  40. delay(5000);
  41. myServo1.write(180);
  42. delay(5000);
  43. }

Исходный код финальной версии от Lolin32:
Вот мой текущий финальный скетч с отключенной возможностью сокращения времени сканирования:

  1. #include "BH1750FVI.h"
  2. #include <Arduino.h>
  3. #include <ESP32Servo.h> // Die ESP32Servo-Bibliothek einbinden
  4.  
  5. const int servoPin1 = 5; // gelb servo1 unten horizental an Pin 5
  6. const int servoPin2 = 18; // orange servo2 oben vertikal an Pin 18
  7. BH1750FVI myLux(0x23);
  8.  
  9. Servo Servohorizontal; // Servo 1 Objekt erstellen
  10. Servo Servovertikal; // Servo 2 Objekt erstellen
  11.  
  12. void setup() {
  13. Serial.begin(115200);
  14. Serial.println();
  15. Serial.print(__FILE__); // liefert den Pfad zur aktuellen Datei
  16. Serial.println();
  17. Wire.begin(23, 19); // f&uuml;r lolin32 lite an SDA (Serial Data): Pin 23 und SCL (Serial Clock): Pin 19
  18. Servohorizontal.attach(servoPin1);
  19. Servovertikal.attach(servoPin2);
  20. myLux.powerOn();
  21. myLux.setContHighRes(); // F&uuml;r kontinuierliche Messung
  22. }
  23.  
  24. void loop() {
  25. int maxLichtstaerkehoriz = 0; // Maximal gemessene Lichtintensit&auml;t horizontal
  26. int maxWinkelHorizont = 0; // Winkel mit der h&ouml;chsten Lichtintensit&auml;t horizontal
  27. int maxLichtstaerkevert = 0; // Maximal gemessene Lichtintensit&auml;t vertikal
  28. int maxWinkelvertikal = 0; // Winkel mit der h&ouml;chsten Lichtintensit&auml;t vertikal
  29.  
  30. // Durchlaufe alle Winkel von 0 bis 180 Grad horizontal bei 35 Grad vertikal
  31. Servovertikal.write(25);
  32. for (int winkelhorizontal = 0; winkelhorizontal <= 180; winkelhorizontal += 10) {
  33. Servohorizontal.write(winkelhorizontal); // Drehe den Servo auf den aktuellen Winkel
  34. delay(100); // Warte einen Moment, damit sich der Servo drehen kann
  35.  
  36. uint16_t lux = myLux.getLux(); // Lese die Lichtintensit&auml;t
  37. if (lux > maxLichtstaerkehoriz) {
  38. maxLichtstaerkehoriz = lux;
  39. maxWinkelHorizont = winkelhorizontal;
  40. Serial.print("Schleife 1: ");
  41. Serial.print("MaxLux1: ");
  42. Serial.println(maxLichtstaerkehoriz, 1);
  43. Serial.print("Bester Winkel horizontal: ");
  44. Serial.println(maxWinkelHorizont, 1);
  45. delay(1000);
  46. }
  47. // else if (lux < maxLichtstaerkehoriz) { // Bei abnehmender Helligkeit, breche die Schleife ab
  48. // Serial.println("breche die Schleife 1 ab");
  49. // delay(1000);
  50. // break;
  51. // }
  52. }
  53.  
  54. // Durchlaufe alle Winkel von 0 bis 180 Grad horizontal bei 120 Grad
  55. Servovertikal.write(140);
  56. for (int winkelhorizontal = 180; winkelhorizontal >= 0; winkelhorizontal -= 10) {
  57. Servohorizontal.write(winkelhorizontal); // Drehe den Servo auf den aktuellen Winkel
  58. delay(100); // Warte einen Moment, damit sich der Servo drehen kann
  59.  
  60. uint16_t lux = myLux.getLux(); // Lese die Lichtintensit&auml;t
  61. if (lux > maxLichtstaerkehoriz) {
  62. maxLichtstaerkehoriz = lux;
  63. maxWinkelHorizont = winkelhorizontal;
  64. Serial.print("Schleife 2: ");
  65. Serial.print("MaxLux1: ");
  66. Serial.println(maxLichtstaerkehoriz, 1);
  67. Serial.print("Bester Winkel horizontal: ");
  68. Serial.println(maxWinkelHorizont, 1);
  69. delay(1000);
  70. }
  71. // else if (lux < maxLichtstaerkehoriz) {
  72. // Serial.println("breche die Schleife 2 ab");
  73. // delay(1000); // Bei abnehmender Helligkeit, breche die Schleife ab
  74. // break;
  75. // }
  76. }
  77. // Durchlaufe alle Winkel von 0 bis 180 Grad vertikal
  78. Servohorizontal.write(maxWinkelHorizont);
  79. for (int angle2 = 30; angle2 <= 150; angle2 += 10) {
  80. Servovertikal.write(angle2); // Drehe den Servo auf den aktuellen Winkel
  81. delay(100); // Warte einen Moment, damit sich der Servo drehen kann
  82.  
  83. uint16_t lux = myLux.getLux(); // Lese die Lichtintensit&auml;t
  84. if (lux > maxLichtstaerkevert) {
  85. maxLichtstaerkevert = lux;
  86. maxWinkelvertikal = angle2;
  87. Serial.print("Schleife 3: ");
  88. Serial.print("MaxLux2: ");
  89. Serial.println(maxLichtstaerkevert, 1);
  90. Serial.print("Bester Winkel horizontal: ");
  91. Serial.println(maxWinkelvertikal, 1);
  92. delay(1000);
  93. }
  94. // else if (lux < maxLichtstaerkevert) {
  95. // Serial.println("breche die Schleife 3 ab");
  96. // delay(1000); // Bei abnehmender Helligkeit, breche die Schleife ab // Bei abnehmender Helligkeit, breche die Schleife ab
  97. // break;
  98. // }
  99. }
  100.  
  101. // Drehe den Servo auf den Winkel mit der h&ouml;chsten Lichtintensit&auml;t
  102.  
  103. Servohorizontal.write(maxWinkelHorizont);
  104. Servovertikal.write(maxWinkelvertikal);
  105. Serial.print("Bester Winkel 1 und 2 : ");
  106. Serial.print(maxWinkelHorizont, 1);
  107. Serial.print(" und ");
  108. Serial.println(maxWinkelvertikal, 1);
  109. // Warte 5 Minuten, bevor der n&auml;chste Durchlauf beginnt
  110. // delay(300000);
  111. esp_sleep_enable_timer_wakeup(300 * 1000000); // Setze die Schlafdauer (5 Minuten = 300.000.000 Mikrosekunden)
  112. esp_deep_sleep_start(); // Betrete den Deep-Sleep-Modus. Manuell aufwecken mit Reset-Taste.
  113. }

Финальная зарядная станция:
Поскольку в прошлые выходные было два солнечных дня без дождя, в конце дня я смог зарядить с её помощью два смартфона через разъем USB-A (5 В / 1 А).

Что мне пока не понравилось, так это то, что аккумуляторный блок находится под воздействием солнца, и эта версия подходит только для использования в хорошую погоду.
На фотографии уже видна вторая тестовая версия опорной пластины с крышкой, к которой, вероятно, еще будут добавлены боковые стенки.

Изображение

Используемые библиотеки:
Для датчика освещенности с обеими платами микроконтроллера:
GitHub – RobTillaart/BH1750FVI_RT: библиотека Arduino для датчика освещенности BH1750FVI (GY-30)
Для сервопривода MG996r:
На Arduino Uno: Servo (установлена по умолчанию)
На Lolin32 Lite: esp32servo

Дополнительное оборудование:
Солнечная панель 3,5 Вт
Модуль управления солнечной энергией без аккумулятора 14500, так как емкость составляет всего 800 мАч
Аккумулятор LiPo 10000 мАч, 3,7 В с разъемом PH2.0A

Технические характеристики производителя:
Датчик освещенности GY-30
Сервопривод MG996R
Управление солнечной энергией: http://www.waveshare.com/wiki/Solar_Power_Manager

Расположение выводов Arduino:
Схема расположения выводов Arduino Uno Rev3 – Prilchen tüftelt
Расположение выводов Lolin32:
Схема расположения выводов ESP32 LOLIN32 (Lite) – Prilchen tüftelt

3D-печать:
Всего для печати требуется 5 деталей, базовая плата доступна для Arduino Uno и Lolin32 Lite.
Базовая платформа размером 20 x 20 см предоставляет дополнительное место для Solar Panel Manager и аккумулятора на 3,7 В.
Крепление для солнечной панели рассчитано на размер 13,5 x 16,5 см.
Печать выполнялась с использованием нити PETG.
Солнечная панель и MG996R_servo1 были склеены с помощью клея для ПВХ-U от Tangit. На PETG держится надежно!
Сервоприводы были закреплены прилагающимися винтами. Остальные детали — саморезами M2x4 и M2x10.

17:57
163
Нет комментариев. Ваш будет первым!

Ссылка появится после регистрации

Похожие модели

Настраиваемый кейс для батареек (магнитный)
Настраиваемый кейс для переноскиПодробнее
Кейс для аккумуляторов и MicroSD GoPro
Полностью закрытый кейс для переноскиПодробнее
держатель для LiFePo4 аккумуляторов
📁 держатель для 2-4 LiFePo4Подробнее
Powerbank из батарей 21700
📁 3D модель корпуса для пауэрбанка наПодробнее
Кейс для хранения батарей ( 21700, 18650, AA, AAA)
📁 Кейс для хранения батарей ( 21700Подробнее
Зарядник на 1х 18650 и TP4056
Недавно мне досталось несколькоПодробнее
Кейс для двух аккумуляторов 18650
Простой корпус для 18650 без лишнихПодробнее
Кейс для 8х 18650 батарей
Контейнер для аккумуляторов 18650 безПодробнее
Каркас для сборки батарей Lifepo4 32700 / 32650
Держатель для аккумуляторов типоразмераПодробнее
Корпус для адаптера питания
📁 Корпус для преобразователя питания сПодробнее
Корпус для DC регулируемого источника
📁 Корпус для DC регулируемого источникаПодробнее
Портативный настольный источник питания
📁 Портативный настольный источникПодробнее
Зарядное устройство для часов Casio Tough Solar
С помощью этой конструкции я хотелПодробнее
Батарейный отсек для Baofeng под 18650
Обновление за сентябрь 2025 года: ПослеПодробнее
Источник питания на 40 000 мАч
Корпус для сборки источника питания наПодробнее
Корпус на магнитах с солн. батареей Meshtastic
# Магнитный автомобильный крепление LoRaПодробнее
Корпус для стационарной уличной ноды Meshtastic
Это стационарный узел, а не портативноеПодробнее
Герметичная коробка для размещения на мачте Meshtastic
Это закрытый корпус, предназначенный дляПодробнее
Meshtastic Солнечная нода с 10W панелью
Корпус для уличной ноды с солнечнойПодробнее
3D солнечный Meshtastic корпус
Материал: PETG, PC, ASA. КрепежныеПодробнее
Корпус для Meshtastic в виде скворечника
Вот солнечная панель, которую яПодробнее
Meshtastic солнечная нода, корпус/крепление
📁 Meshtastic солнечная нода, корпусПодробнее
Уличный узел Meshtastic с солнечной батареей
📁 Уличный узел Meshtastic с солнечнойПодробнее
Корпус для устройства Meshtastic с солнечной батареей
📁 Корпус для устройства Meshtastic сПодробнее
Уличный узел Promicro DIY с солнечной батареей
📁 3D модель корпуса для внешнего роутераПодробнее
Мештастик корпус для точки с солнечной батареей
📁 Meshtastic Мештастик кейс с солнечнойПодробнее
Бокс для репитера Meshtastic, Meshcore, Faketec
📁 Бокс для репитера Meshtastic, MeshcoreПодробнее
Корпус для Heltec T114 под батарею 21700
Этот корпус разработан для Heltec T114Подробнее
Meshtastic & MeshCore Солнечная нода
MESH-S — это солнечный узел MeshtasticПодробнее
Посещая этот сайт, вы соглашаетесь с тем, что мы используем файлы cookie.