/*
Wokwi | projects
Help error compilation
stephaneV - Monday, April 6, 2026 6:55 AM
Hello, I created the solar tracker project, and it worked perfectly
in the simulation. I'm reworking the code, adding the height, and
renaming the project to Solar 2. When I run the simulation again,
I get an error:
In file included from /libraries/ESP32Servo/src/ESP32Servo.h:84,
=====================================================
TRAQUEUR SOLAIRE 2 AXES — ESP32
LDR : 33 (TL), 35 (TR), 32 (BL), 34 (BR)
Servo: 19 (horizontal), 18 (vertical)
OLED : SDA=21, SCL=22 (I2C 0x3C, SSD1306 128x64)
LED : 25 (mode nuit)
Autheur : Stephane VANGOUT
=====================================================
*/
#include <ESP32Servo.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// ── OLED ──────────────────────────────────────────────
#define OLED_W 128
#define OLED_H 64
#define OLED_ADDR 0x3C
Adafruit_SSD1306 display(OLED_W, OLED_H, &Wire, -1);
// ── Pins ──────────────────────────────────────────────
constexpr uint8_t PIN_LDR_TL = 33;
constexpr uint8_t PIN_LDR_TR = 35;
constexpr uint8_t PIN_LDR_BL = 32;
constexpr uint8_t PIN_LDR_BR = 34;
constexpr uint8_t PIN_SERVO_H = 19;
constexpr uint8_t PIN_SERVO_V = 18;
constexpr uint8_t PIN_LED_NIGHT = 25;
// ── Paramètres ────────────────────────────────────────
constexpr int DEADBAND = 80; // seuil déséquilibre ADC
constexpr int NIGHT_THRESHOLD = 200; // en dessous = nuit (valeur ADC)
constexpr int SERVO_STEP = 1; // pas en degrés
constexpr int SERVO_H_MIN = 0;
constexpr int SERVO_H_MAX = 180;
constexpr int SERVO_V_MIN = 30;
constexpr int SERVO_V_MAX = 150;
constexpr int LOOP_DELAY_MS = 20;
constexpr uint8_t ADC_SAMPLES = 4;
// Position "est" au lever du soleil
constexpr int NIGHT_POS_H = 0;
constexpr int NIGHT_POS_V = 90;
Servo servoH, servoV;
int posH = 90, posV = 90;
bool nightMode = false;
// ── Lecture ADC moyennée ──────────────────────────────
int readLDR(uint8_t pin) {
long sum = 0;
for (uint8_t i = 0; i < ADC_SAMPLES; i++) {
sum += analogRead(pin);
delayMicroseconds(200);
}
return 4096 - ((int)(sum / ADC_SAMPLES)); // inverts Wokwi sensor
}
// ── Déplacement servo clampé ──────────────────────────
int moveServo(Servo& s, int pos, int delta, int lo, int hi) {
pos = constrain(pos + delta, lo, hi);
s.write(pos);
return pos;
}
// ── Affichage OLED ────────────────────────────────────
void updateDisplay(int tl, int tr, int bl, int br,
int dH, int dV, bool night) {
display.clearDisplay();
// Titre
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print(night ? F("** MODE NUIT **") : F("Solar Tracker 2X"));
// Ligne de séparation
display.drawLine(0, 10, 127, 10, SSD1306_WHITE);
// Valeurs LDR en croix (disposition visuelle)
display.setCursor(0, 14); display.printf("TL:%4d", tl);
display.setCursor(68, 14); display.printf("TR:%4d", tr);
display.setCursor(0, 24); display.printf("BL:%4d", bl);
display.setCursor(68, 24); display.printf("BR:%4d", br);
// Ligne de séparation
display.drawLine(0, 34, 127, 34, SSD1306_WHITE);
// Positions servos
display.setCursor(0, 37);
display.printf("H:%3d deg V:%3d deg", posH, posV);
// Déséquilibres
display.setCursor(0, 47);
display.printf("dH:%5d dV:%5d", dH, dV);
// Barre de lumière totale
int total = tl + tr + bl + br;
int barW = map(total, 0, 4 * 4095, 0, 127);
display.setCursor(0, 57);
display.print(F("Lum:"));
display.drawRect(24, 57, 100, 7, SSD1306_WHITE);
display.fillRect(24, 57, barW, 7, SSD1306_WHITE);
display.display();
}
// ── Setup ─────────────────────────────────────────────
void setup() {
Serial.begin(115200);
pinMode(PIN_LED_NIGHT, OUTPUT);
// OLED
display.setRotation(2);
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
Serial.println(F("OLED non détecté !"));
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(20, 24);
display.print(F("Solar Tracker 2X"));
display.setCursor(30, 38);
display.print(F("Initialisation..."));
display.display();
// Servos
ESP32PWM::allocateTimer(0);
ESP32PWM::allocateTimer(1);
servoH.setPeriodHertz(50);
servoV.setPeriodHertz(50);
servoH.attach(PIN_SERVO_H, 500, 2400);
servoV.attach(PIN_SERVO_V, 500, 2400);
servoH.write(posH);
servoV.write(posV);
delay(1000);
Serial.println(F("Traqueur solaire 2 axes démarré."));
}
// ── Loop ──────────────────────────────────────────────
void loop() {
int tl = readLDR(PIN_LDR_TL);
int tr = readLDR(PIN_LDR_TR);
int bl = readLDR(PIN_LDR_BL);
int br = readLDR(PIN_LDR_BR);
int avg = (tl + tr + bl + br) / 4;
// ── Mode nuit ──
if (avg < NIGHT_THRESHOLD) {
if (!nightMode) {
nightMode = true;
digitalWrite(PIN_LED_NIGHT, HIGH);
// Retour à l'est pour attendre le lever
posH = moveServo(servoH, posH,
(NIGHT_POS_H > posH ? 1 : -1) *
min(abs(NIGHT_POS_H - posH), SERVO_STEP),
SERVO_H_MIN, SERVO_H_MAX);
posV = moveServo(servoV, posV,
(NIGHT_POS_V > posV ? 1 : -1) *
min(abs(NIGHT_POS_V - posV), SERVO_STEP),
SERVO_V_MIN, SERVO_V_MAX);
}
updateDisplay(tl, tr, bl, br, 0, 0, true);
Serial.printf("[NUIT] avg:%4d | H:%3d V:%3d\n", avg, posH, posV);
delay(LOOP_DELAY_MS);
return;
}
// ── Mode jour ──
if (nightMode) {
nightMode = false;
digitalWrite(PIN_LED_NIGHT, LOW);
}
int diffH = (tl + bl) - (tr + br);
int diffV = (tl + tr) - (bl + br);
if (abs(diffH) > DEADBAND) {
posH = moveServo(servoH, posH,
(diffH > 0) ? -SERVO_STEP : SERVO_STEP,
SERVO_H_MIN, SERVO_H_MAX);
}
if (abs(diffV) > DEADBAND) {
posV = moveServo(servoV, posV,
(diffV > 0) ? SERVO_STEP : -SERVO_STEP,
SERVO_V_MIN, SERVO_V_MAX);
}
updateDisplay(tl, tr, bl, br, diffH, diffV, false);
Serial.printf("TL:%4d TR:%4d BL:%4d BR:%4d | dH:%5d dV:%5d | H:%3d V:%3d\n",
tl, tr, bl, br, diffH, diffV, posH, posV);
delay(LOOP_DELAY_MS);
}