Suiveur solaire auto/manuel avec fin de course et retour a l'Est la nuit

Bonjour a tous, je suis André 55 ans et sans activités pour le moment, je ne connais pas du tout les codes Arduino. J'ai un projet de construire un suiveur solaire, après beaucoup de recherche sur le net j'ai trouvé un code qui fonctionne très bien, il possède 2 fin de course pour l’extrémité Ouest et Est, et un retour vers l'Est pour la nuit. Le problème c'est qu'il n'y a qu'un seul moteur, âpres plusieurs semaine a étudier le code je me suis dit qu'il suffit de doubler le code en changeant les noms et broches , mais après plusieurs essai je n'ai toujours qu'un seul moteur qui fonctionne et je ne comprend pas pourquoi.
Mon matériel : Carte Arduino UNO , Module 4 relais
Le code originale :

2 capteurs photorésistance sur broches A0 et A1
2 capteurs de bout de course sur broches 13 pour l'ouest et 12 pour l'est
1 moteur piloté par 2 relais sur broche 2 pour aller vers l'ouest
et broche 3 pour aller vers l'est

Montage du moteur :

+ 12V ------------|
borne 1 moteur----| Relais 1
Gnd --------------|

+12V -------------|
borne 2 moteur ---| Relais 2
Gnd --------------|
*/

// Constantes 
const int moteurOuest = 2; // broche du relais ouest
const int moteurEst = 3;   // broche du relais est

const int buteeOuest = 13; // broche de la butee ouest. 1 = relache, 0 = enfonce
const int buteeEst = 12;   // broche de la butee est

const int pvOuest = A0; // broche analogique pour cellule pv ouest
const int pvEst = A1;   // broche analogique pour cellule pv est

const int nuit = 100; // Valeur en-dessous de laquelle on considère qu'il fait nuit
const int ecart = 50; // Écart d'éclairement qui déclenche le mouvement

// Variables
boolean atteintEst = true ;  // Butées atteintes. Si rebond sur la butée, évite les actions répétitives
boolean atteintOuest = true ;

int lumiereEst = 0 ; // Lecture lumière capteur est
int lumiereOuest = 0; // Lecture lumière capteur ouest

//initialisation
void setup() {
    // broche de commande moteur
    pinMode (moteurOuest, OUTPUT);
    pinMode (moteurEst, OUTPUT);

    // broche de détection butée
    pinMode (buteeOuest, INPUT);
    digitalWrite (buteeOuest, HIGH); //activer résistance pull-up
    pinMode (buteeEst, INPUT);
    digitalWrite (buteeEst, HIGH); //activer pull-up

}

void loop() {
    lumiereEst = analogRead(pvEst);
    lumiereOuest = analogRead(pvOuest);

    //Si il ne fait pas nuit
    if (lumiereEst > nuit){
        //======================================================================
        // Si Ouest plus éclairé, boucle pour tourner vers l'ouest jusqu'à butee
        while ((lumiereOuest - lumiereEst > ecart) && (atteintOuest)) { 
            digitalWrite(moteurOuest, HIGH); // mettre un coup de moteur vers l'ouest
            atteintEst = true; // relacher butée est

            lumiereEst = analogRead(pvEst); // Relire les éclairements
            lumiereOuest = analogRead(pvOuest);

            atteintOuest = digitalRead(buteeOuest); // Tester la butee et sortir de la boucle
            if (!atteintOuest) {
                 break;
            }
        } 
        digitalWrite(moteurOuest, LOW); // Eteindre le moteur

        //==================================================================
        // Si Est plus éclairé, boucle pour tourner vers l'est jusqu'a butee
        while ((lumiereEst - lumiereOuest > ecart) && (atteintEst)) { 
            digitalWrite(moteurEst, HIGH); //Mettre un coup de moteur à l'est
            atteintOuest = true; // Libérer butee ouest

            lumiereEst = analogRead(pvEst); // Relire les éclairements
            lumiereOuest = analogRead(pvOuest);

            atteintEst = digitalRead(buteeEst); // Lire si la butee est atteinte pour arret
            if (!atteintEst){
                break;
            }
        }
        digitalWrite(moteurEst, LOW); // Eteindre le moteur

    }
    //===============================================
    // S'il fait nuit, retour à l'est
    else{ 
        while (atteintEst){
            digitalWrite(moteurEst, HIGH);
            atteintOuest = true ; //Libérer butee ouest
            atteintEst = digitalRead(buteeEst);
        }
        digitalWrite(moteurEst, LOW);

    }

}

bonjour, bienvenue sur ce forum. Félicitations, tu as bien présenté ton 1er message.

Sur ton projet, je ne comprends pas. Pourquoi faut-il deux moteurs ?
Un moteur qui suit le soleil est-ouest le jour et revient à l'est la nuit, ok, je vois.
Chaque moteur ne va que dans un seul sens ?
Comme tout ça est cyclique, que tu aies 1, 2, ou N moteurs, ils doivent tous régulièrement revenir à leur point de départ, c'est fatal.

Mon code bidouillé:

  Montage du moteur :

  + 12V ------------|
  borne 1 moteur----| Relais 1
  Gnd --------------|

  +12V -------------|
  borne 2 moteur ---| Relais 2
  Gnd --------------|
*/

// Constantes
const int moteurOuest = 2; // broche du relais ouest
const int moteurEst = 3;   // broche du relais est

const int moteurHaut = 4; // broche du relais haut
const int moteurBas = 5;   // broche du relais bas

const int buteeOuest = 13; // broche de la butee ouest. 1 = relache, 0 = enfonce
const int buteeEst = 12;   // broche de la butee est

const int buteeHaut = 11; // broche de la butee haut. 1 = relache, 0 = enfonce
const int buteeBas = 10;   // broche de la butee bas

const int pvOuest = A0; // broche analogique pour cellule pv ouest
const int pvEst = A1;   // broche analogique pour cellule pv est

const int pvHaut = A3; // broche analogique pour cellule pv haut
const int pvBas = A4;   // broche analogique pour cellule pv bas

const int nuit = 100; // Valeur en-dessous de laquelle on considère qu'il fait nuit
const int ecart = 50; // Écart d'éclairement qui déclenche le mouvement

// Variables
boolean atteintEst = true ;  // Butées atteintes. Si rebond sur la butée, évite les actions répétitives
boolean atteintOuest = true ;

boolean atteintBas = true ;  // Butées atteintes. Si rebond sur la butée, évite les actions répétitives
boolean atteintHaut = true ;

int lumiereEst = 0 ; // Lecture lumière capteur est
int lumiereOuest = 0; // Lecture lumière capteur ouest

int lumiereBas = 0 ; // Lecture lumière capteur bas
int lumiereHaut = 0; // Lecture lumière capteur haut

//initialisation
void setup() {
  // broche de commande moteur
  pinMode (moteurOuest, OUTPUT);
  pinMode (moteurEst, OUTPUT);
  pinMode (moteurHaut, OUTPUT);
  pinMode (moteurBas, OUTPUT);

  // broche de détection butée
  pinMode (buteeOuest, INPUT);
  digitalWrite (buteeOuest, HIGH); //activer résistance pull-up
  pinMode (buteeEst, INPUT);
  digitalWrite (buteeEst, HIGH); //activer pull-up
  pinMode (buteeHaut, INPUT);
  digitalWrite (buteeHaut, HIGH); //activer résistance pull-up
  pinMode (buteeBas, INPUT);
  digitalWrite (buteeBas, HIGH); //activer pull-up

}

void loop() {
  lumiereEst = analogRead(pvEst);
  lumiereOuest = analogRead(pvOuest);

  //Si il ne fait pas nuit
  if (lumiereEst > nuit) {
    //======================================================================
    // Si Ouest plus éclairé, boucle pour tourner vers l'ouest jusqu'à butee
    while ((lumiereOuest - lumiereEst > ecart) && (atteintOuest)) {
      digitalWrite(moteurOuest, HIGH); // mettre un coup de moteur vers l'ouest
      atteintEst = true; // relacher butée est

      lumiereEst = analogRead(pvEst); // Relire les éclairements
      lumiereOuest = analogRead(pvOuest);

      atteintOuest = digitalRead(buteeOuest); // Tester la butee et sortir de la boucle
      if (!atteintOuest) {
        break;
      }
    }
    digitalWrite(moteurOuest, LOW); // Eteindre le moteur

    //==================================================================
    // Si Est plus éclairé, boucle pour tourner vers l'est jusqu'a butee
    while ((lumiereEst - lumiereOuest > ecart) && (atteintEst)) {
      digitalWrite(moteurEst, HIGH); //Mettre un coup de moteur à l'est
      atteintOuest = true; // Libérer butee ouest

      lumiereEst = analogRead(pvEst); // Relire les éclairements
      lumiereOuest = analogRead(pvOuest);

      atteintEst = digitalRead(buteeEst); // Lire si la butee est atteinte pour arret
      if (!atteintEst) {
        break;
      }
    }
    digitalWrite(moteurEst, LOW); // Eteindre le moteur

  }
  //===============================================
  // S'il fait nuit, retour à l'est
  else {
    while (atteintEst) {
      digitalWrite(moteurEst, HIGH);
      atteintOuest = true ; //Libérer butee ouest
      atteintEst = digitalRead(buteeEst);
    }
    digitalWrite(moteurEst, LOW);

  }

  lumiereEst = analogRead(pvEst);
  lumiereOuest = analogRead(pvOuest);

  //Si il ne fait pas nuit moteur haut bas
  if (lumiereBas > nuit) {
    //======================================================================
    // Si Haut plus éclairé, boucle pour tourner vers le haut jusqu'à butee
    while ((lumiereHaut - lumiereBas > ecart) && (atteintHaut)) {
      digitalWrite(moteurHaut, HIGH); // mettre un coup de moteur vers le haut
      atteintBas = true; // relacher butée bas

      lumiereBas = analogRead(pvBas); // Relire les éclairements
      lumiereHaut = analogRead(pvHaut);

      atteintHaut = digitalRead(buteeHaut); // Tester la butee et sortir de la boucle
      if (!atteintHaut) {
        break;
      }
    }
    digitalWrite(moteurHaut, LOW); // Eteindre le moteur

    //==================================================================
    // Si Bas plus éclairé, boucle pour tourner vers le bas jusqu'a butee
    while ((lumiereBas - lumiereHaut > ecart) && (atteintBas)) {
      digitalWrite(moteurBas, HIGH); //Mettre un coup de moteur à le bas
      atteintHaut = true; // Libérer butee haut

      lumiereBas = analogRead(pvBas); // Relire les éclairements
      lumiereHaut = analogRead(pvHaut);

      atteintBas = digitalRead(buteeBas); // Lire si la butee est atteinte pour arret
      if (!atteintBas) {
        break;
      }
    }
    digitalWrite(moteurBas, LOW); // Eteindre le moteur

  }
  //===============================================
  // S'il fait nuit, retour le haut
  else {
    while (atteintHaut) {
      digitalWrite(moteurHaut, HIGH);
      atteintBas = true ; //Libérer butee bas
      atteintHaut = digitalRead(buteeHaut);
    }
    digitalWrite(moteurHaut, LOW);

  }

}

Merci pour votre aide

bonjour Biggil, en fait le deuxième moteur c'est pour orienter le panneau du haut vers le bas

J'espère que tu as pris en compte que :

  • pour l'azimut la course c'est 270° au solstice de Juin et à peine une centaine de degrès au solstice de décembre.
  • pour la hauteur idem hauteur max d'un peu plus de 60° en juin et un peu moins de 25 ° en décembre.

Cela serait plus profitable si tu décrivais comment tu positionne le panneau solaire : calcul sur éphéméride ou capteur de luminosité. Et comment tu le déplace : vis sans fin, couroie, servo, engrenage, ...?

Un pdf qui pourrait t'interesser (si tu ne l'as pas déjà) : https://perso.limsi.fr/bourdin/master/Calculs_astronomiques_simples.pdf

Le moteur de l'axe verticale met 6 minutes pour faire un tour dans un mat cylindrique sur roulements a bille, pour régler en verticale un moteur linéaire de 3 mm/seconde , le montage utilise des capteur de luminosité , les butées seront au delà des 270° réglable mécaniquement , les moteur sont en 12v continu commandé par 2 relais chacun, même si les butées sont mal réglé les capteur vont aligner le panneau automatiquement. pour les jours nuageux une commande manuel est prévue a l'aide d'une télécommande.

je n'arrive pas a poster une photo du schémas de branchement :o

hello
un peu de lecture ICI

J'ai déjà lu ce post tres intéressant mais qui ne correspond pas vraiment a mon projet , il n'a pas de retour a l'Est . Le premier code que j'ai posté fonctionne exactement comme je le souhaite, mon problème est que ce code fonctionne que pour un axe de rotation, je veux faire tourner aussi sur l'axe vertical, si quelqu'un pouvait contrôler mon code "bidouille'" pour voir pourquoi il ne fonctionne pas.

@68tjs : la méthode de suivi est un asservissement ( asservir la position pour que l'intensité lumineuse à l'est soit égale à celle à l'ouest). Pas besoin d'éphémerides.

@papy_andre : dans ton code tu te mélanges les pinceaux entre les deux moteurs :

digitalWrite(moteurOuest, HIGH); // mettre un coup de moteur vers l'ouest
.../...
digitalWrite(moteurEst, HIGH); //Mettre un coup de moteur à l'est

Ce que tu fais là, c'est que dans un cas tu actives le moteur 1, et dans l'autre le moteur 2. Si effectivement le second moteur fait une rotation haut-bas, c'est ballot de les avoir nommés moteurEst et moteurOuest ! Sais-tu comment faire aller le moteur dans l'autre sens ?

Par ailleurs, tu voudrais donc asservir le panneau en haut-bas (en plus de est-ouest), mais tu n'as rien pour cela ! Comment calculer la postion haut-bas ? il te faudrait, si tu veux utiliser la même méthode que pour est-ouest, il te faudrait un capteur de lumière en haut et un autre en bas.
Ou alors une autre méthode, mais il faut y réfléchir avant de vouloir coder (comment coder ce qu'on ne sait pas faire ?))

Enfin, relis bien ton code. Par exemple :

while (atteintEst) {
      digitalWrite(moteurEst, HIGH);
      atteintOuest = true ; //Libérer butee ouest
      atteintEst = digitalRead(buteeEst);
    }

Quand tu arrives ici la variable atteintEst peut être non initilisée.Si la variable atteintEst est vrai lorsque qu'on est en butée est, le bon test est :

atteintEst = digitalRead(buteeEst);  // initialiser
while ( ! atteintEst) {              // test NOT atteintEst
      .../...
      atteintEst = digitalRead(buteeEst);
    }

Tu parle du code original, ce n’est pas moi qui l’ai écrit, il fonctionne très bien, celui que j’ai écrit c’est celui que j’ai nommé " bidouille"

J'ai fait les essais avec 4 photos résistance, 4 fin de course, 4 relais et deux moteur le tout branché suivant le code que j'ai nommé bidouille , mais ça ne fonctionne pas

papi_andre:
J'ai fait les essais avec 4 photos résistance, 4 fin de course, 4 relais et deux moteur le tout branché suivant le code que j'ai nommé bidouille , mais ça ne fonctionne pas

Bonsoir,
Dans ton code

//initialisation
void setup() {
  // broche de commande moteur
  

  // broche de détection butée
  pinMode (buteeOuest, INPUT);
  digitalWrite (buteeOuest, HIGH); //activer résistance pull-up
  pinMode (buteeEst, INPUT);
  digitalWrite (buteeEst, HIGH); //activer pull-up
  pinMode (buteeHaut, INPUT);
  digitalWrite (buteeHaut, HIGH); //activer résistance pull-up
  pinMode (buteeBas, INPUT);
  digitalWrite (buteeBas, HIGH); //activer pull-up

}

Dans ton setup tu declare des pin en entrées,
Par exemple
pinMode (buteeOuest, INPUT);
puis tu vas ecrire dessus
"digitalWrite (buteeOuest, HIGH); //activer résistance pull-up" .... pas logique

Et pour déclarer une pin en entrée avec le pull upp activé c'est pinMode (buteeOuest,INPUT_PULLUP); ..

J'ai pas regardé plus loin.

biggil:
@68tjs : la méthode de suivi est un asservissement ( asservir la position pour que l'intensité lumineuse à l'est soit égale à celle à l'ouest). Pas besoin d'éphémeride

Ce n'est pas mon avis.
Que ce passe t-il au démarage de l'installation au lever du jour ?

Sous très faible luminosité comment la recherche par capteur d'intensité lumineuse va fonctionner ?
Je ne parle même pas d'un ciel couvert où la lumière diffuse est plus importante que la lumière directe et provient de tous les cotés avec les réflexions entre le sol et les nuages.
Un asservissement c'est bien mais cela peut aussi "pomper".
@papi_andré a bien prévu ce cas puisqu'il prévois un positionnement manuel.

Qu'elle sera la précision du pointage ?
Une erreur de pointage de 10 ° introduit une perte de 1,5% (cos(10°) = 0,985)
20° -> - 6,5%

@papi_andré veut faire un retour à l'est dans la nuit.
Sans calculs ce retour se fera jusqu'aux fins de course soit un azimut de ~ -135° Est, et une hauteur de 0°.

Au démarrage de l'installation le matin, sous faible luminosité, comment va se faire la recherche du soleil ?
Si on fait un suiveur solaire c'est bien pour récupérer le maximum d'énergie pendant le maximum d'heures, ce n'est pas pour fonctionner 2h de part et d'autre de midi au soleil.
En partant de la position fin de course l'algorithme sera assez complexe et va consommer de l'énergie alors que celle récupérée par le panneau sera minimale.

Je veux bien que la solution tout calcul soit assez compliqué puisqu'en fonction du jour de l'année il peut y avoir jusqu'à ± 20 mn entre l'heure officielle "TU" et l'heure sidérale vraie du soleil. Mais bon une fois que les formules sont dans le code c'est le microcontrôleur qui travaille.

Je pense qu'une horloge DS3231 plus quelques calculs relativement simples (sans correction de l'heure) permettront d'améliorer le rendement de la phase "accrochage du soleil" en prépositionnant le panneau et peut avantageusement remplacer le pointage manuel par conditions défavorable.

je n'ai toujours qu'un seul moteur qui fonctionne

Plus tu est précis, moins on a de travail pour répondre, d'autant plus que l'on ne peut pas facilement le tester. Un seul moteur à la fois? Un seul moteur qui tourne et jamais l'autre? Mais lequel tourne?

Et pour déclarer une pin en entrée avec le pull upp activé c'est pinMode (buteeOuest,INPUT_PULLUP); ..

L'autre méthode fonctionne aussi. C'était quand PULL_UP n'existait pas.

C'est celui de Est Ouest qui fonctionne

Donc celui de l'azimut.

A priori, je ne vois pas, Mais il se peut qu'il y ait une erreur de branchements.

Pour débugger un programme de ce type, c'est pratique de placer un Serial.println("coucou"); en un endroit et de voir si on a ou pas le message. Dans ton cas avant ou après la mise en route du moteur nord-sud. Si on a un message c'est que l'on demande au moteur de tourner et qu'il ne le fait pas (câblage sans doute) et un voltmètre peut confirmer. Si on n'a pas de message c'est que le problème est avant.

Il y a trop de capteurs pour que l'on puisse tester le programme

Je note:

    while ((lumiereOuest - lumiereEst > ecart) && (atteintOuest))
    {
      digitalWrite(moteurOuest, HIGH); // mettre un coup de moteur vers l'ouest
      atteintEst = true; // relacher butée est

      lumiereEst = analogRead(pvEst); // Relire les éclairements
      lumiereOuest = analogRead(pvOuest);

      atteintOuest = digitalRead(buteeOuest); // Tester la butee et sortir de la boucle
      if (!atteintOuest)
      {
        break;
      }
    }
    digitalWrite(moteurOuest, LOW); // Eteindre le moteur

Quand atteintOuest devient faux, on sort de laboucle par le break. Mais si on supprime cette "sortie" et le if qui va avec, cela ne change rien car la condition atteintOuest est aussi dans le while

Bonjours, je viens de tester les branchements et tout est bon, j'ai interverti les cellules PV et fin de course Est/Ouest avec Haut/Bas et maintenant Haut/bas fonctionne et Est/ Ouest ne fonctionne plus. C'est bien le code Haut / Bas qui ne fonctionne pas.

Je vous post le dessin des branchements, pour être plus lisible les branchements du moteur Est/ Ouest sur un dessin et Haut/Bas sur un autre, il vas de soit que la carte Uno et le module relais est commun au deux dessins.Pour les test les diodes et boutons poussoir manuel (relais télécommande) ne sont pas branché.