Tracker solaire basique

Bonjour,
Je suis toujours vivant :slight_smile: Je reviens sur du vrai apprentissage après avoir stagné trop longtemps dans la facilité de python pour un projet communautaire, en commençant par terminer ceci (commencé à mes débuts ici, il traînait sur le bureau depuis maintenant 3 ans)

Le concept n'est ni nouveau ni compliqué, c'est un projet simple (on en trouve pléthore sur internet) qui peut servir d'inspiration pour des débutants par exemple. J'étais parti à l'époque sur un système biaxial (simplement deux servomoteurs SG90 180°), commandé par 4 photorésistances (dans mon cas des GL5516).

Dans ma grande flemmardise, je n'ai pas cherché à faire quelque chose d'optimal dans le choix des valeurs des résistances fixes, utilisé pour former le pont diviseur avec chaque LDR (ma maîtrise et ma compréhension des formules d'électricité, même basiques, laissent à désirer :woozy_face:), j'ai mis 10kΩ et ça fonctionne bien (je ne doute pas que certains ici sauront expliquer quoi chercher dans la datasheet et comment calculer la résistance adaptée pour avoir la plage de valeurs la plus large possible)

Je précise, même si cette "démo" est fonctionnelle, si vous envisagez de réaliser un tracker solaire de ce type à plus grande échelle (par ex. dans un vrai but de production électrique rentable) en extérieur, les photorésistances ne sont pas idéales.

Je n'ai pas cherché à savoir si une telle installation vaut le coup, ça dépend de plein de paramètres (taille de l'installation, ensoleillement/durée d'exposition, type et consommation des moteurs, surface de panneau, et que sais-je encore). Sachez juste qu'un asservissement en fonction du temps est souvent cité comme solution plus fiable (ex. Tracker Solaire 2 axes sans Photo résistance, est ce possible)


La logique est basée sur une bête comparaison de deux moyennes, pour chaque axe; j'ai trouvé un pdf intéressant qui résume assez bien le tout avec un beau diagramme page 9. Le code:

#include <Arduino.h>
#include <Servo.h>

Servo servoAxeVertical;
Servo servoAxeHorizontal;

#define PIN_LUM_HAUT_GAUCHE A0
#define PIN_LUM_HAUT_DROITE A1
#define PIN_LUM_BAS_DROITE A2
#define PIN_LUM_BAS_GAUCHE A3

/*
délai de màj de la position en millisecondes (valeur faible pour que le mouvement soit visible).
Avec le soleil, il faudrait faire le calcul mais 5/10 min sont sûrement plus adaptées.
Je rappelle, les LDR sont peu adaptées à un tracker solaire grande échelle,
car elles sont sensibles à la température, au vieillissement, sont peu précises sur des variations faibles,
et sont sujettes à erreur au moindre oiseau ou nuage au mauvais moment...
*/
constexpr uint16_t TEMPS_MAJ_POSITION = 100;

void orienterAxeVertical()
{
    const uint16_t moyenneHaut = (analogRead(PIN_LUM_HAUT_DROITE) + analogRead(PIN_LUM_HAUT_GAUCHE))/2;
    const uint16_t moyenneBas = (analogRead(PIN_LUM_BAS_DROITE) + analogRead(PIN_LUM_BAS_GAUCHE))/2;

    const uint8_t angleActuel = servoAxeVertical.read();
    if(moyenneHaut > moyenneBas)
    {
        servoAxeVertical.write(angleActuel - 1);
    }
    else if(moyenneHaut < moyenneBas)
    {
        servoAxeVertical.write(angleActuel + 1);
    }
}

void orienterAxeHorizontal()
{
    const uint16_t moyenneDroite = (analogRead(PIN_LUM_HAUT_DROITE) + analogRead(PIN_LUM_BAS_DROITE))/2;
    const uint16_t moyenneGauche = (analogRead(PIN_LUM_HAUT_GAUCHE) + analogRead(PIN_LUM_BAS_GAUCHE))/2;

    const uint8_t angleActuel = servoAxeHorizontal.read();
    if(moyenneDroite > moyenneGauche)
    {
        servoAxeHorizontal.write(angleActuel + 1);
    }
    else if(moyenneDroite < moyenneGauche)
    {
        servoAxeHorizontal.write(angleActuel - 1);
    }
}

void setup()
{
    servoAxeHorizontal.attach(5);
    servoAxeVertical.attach(6);
    Serial.begin(115200);
    Serial.println("Starting!");
}

void loop()
{
    uint32_t tempsActuel = millis();
    static uint32_t tempsPrecedent = millis();
    if((tempsActuel - tempsPrecedent) >= TEMPS_MAJ_POSITION)
    {
        tempsPrecedent = tempsActuel;
        orienterAxeVertical();
        orienterAxeHorizontal();
    }
}

Quelques photos (je l'ai fait quand j'avais 12 ans, probablement pas un de mes plus beaux montages lol :pray:)


Voila, juste histoire d'avoir un projet de moins sur le bureau ;)
La suite va être bien plus intéressante, j'ai pas mal d'idées sur le feu à base d'ESP32, d'écran TFT et de protocole custom à travers toute la maison notamment :slight_smile:
Cdlt,
Pandaroux007

2 Likes

bravo pour un projet bien fini :)

quelques remarques :

je ne sais pas si servoAxeVertical peut aller à zéro mais dans ce code

si vous rentrez dans le if angleActuel - 1 provoque un underflow qui donne 255 car c'est un uin8_t

en pratique il serait bon de vous assurer que vous restez dans des valeurs cohérentes pour les servos avec un type plutôt int16_t et utiliser un truc constrain(nouvelAngle, 0, 180)

(et attention read() retourne la dernière valeur écrite, pas forcement la vraie valeur donc au départ si vous n'avez pas forcé une valeur, ça peut lire n'importe quoi).

sinon attention aussi aux analogRead() les uns à la suite des autres, il n'y a qu'un seul ADC et si on lit trop vite plusieurs broches différentes et qu'elle présentent une valeur très différentes sous forte impédance, la petite capacité de l'ADC qui permet de faire l'échantillonnage n'a pas le temps de bien se charger et on obtient une fausse lecture. C'est pour cela qu'on trouve souvent deux analogRead() de la même broche l'un à la suite de l'autre, le premier sert à configurer cette broche pour qu'elle alimente le condensateur (et fait une lecture que l'on jette), le second analogRead ne modifie pas la route et donc la lecture sera OK.

C'est toujours bien de finir un projet, mes félicitations :slight_smile:

Si c'est fonctionnel, c'est déjà bien, l'optimisation est souvent du au constat que dans les cas limites, le choix fait influence, la limites des cas limites, il arrive plus vite que l'on croyait.

Comme par exemple, tu n'a pas de contrainte de rentabilité, si c'est fonctionnel, c'est déjà bien suffisant.

Je crois que si quelqu'un veut passer a une sorte d'industrialisons, en plus des photorésistances, passer sur un servo avec le même rapport puissance/effort doit être aussi un défit. Sans parler des contraintes purement mécanique :slight_smile:

Je te trouve bien dure, même si je n'aime pas trop le Python, à partir du moment ou tu as développé, je ne sais pas si on peut parler de stagnation, ou alors en embarqué et encore :slight_smile:

Bonjour

2 commentaires concernant ce genre de projet:

  • Il est fort avantageux d'intégrer un capteur de vent, pour positionner le panneau à plat.
  • des fin de courses pour le panneau, pour éviter la casse en cas de "glissement" de la mécanique.
  • pour éviter de moyenner les LDR, on peut les placer en série, juste 2 lectures analogiques pour lire la position du panneau par rapport au soleil, lecture= 1/2 Vcc, quelle que soit la luminosité.
  • une dernière LDR pour stopper tout ça la nuit.

le capteur de vent peut être construit avec une boule légère pendue au bout d'une tige souple qui vient faire contact sur un anneau conducteur en cas de fort vent, une cloche au dessus pour mettre à l'abri de la pluie.