Système de tracking avec Arduino

Bonsoir,

voilà je me suis lancé dans la réalisation d'un tracker solaire avec Arduino et pour la circonstance j'utilise deux moteurs pas à pas de niveau de tension tout à fait différent (5V ? et 12 V (TEAC 14769070)). Je ne connais pas non plus le nombre de pas pour une révolution de ces derniers. Et pour cela j'ai utilisé le code ci-dessous pour pouvoir faire mes tests :

int motorPin1 = 8;
int motorPin2 = 9;
int motorPin3 = 10;
int motorPin4 = 11;
int delayTime = 500;

void setup () {
  pinMode (motorPin1, OUTPUT);
  pinMode (motorPin2, OUTPUT);
  pinMode (motorPin3, OUTPUT);
  pinMode (motorPin4, OUTPUT);
}

void loop () 
{
  //backward.
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);
  digitalWrite(11, HIGH);
  delay(500);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  digitalWrite(10, HIGH);
  digitalWrite(11, LOW);
  delay(500);
  digitalWrite(8, LOW);
  digitalWrite(9, HIGH);
  digitalWrite(10, LOW);
  digitalWrite(11, LOW);
  delay(500);
  digitalWrite(8, HIGH);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);
  digitalWrite(11, LOW);
  delay(500);
}

Je trouve que ce code est avantageux pour moi dans la mesure où je ne connais pas le nombre de pas du moteur.

Alors comme dit au début, j'aimerais avec ces deux moteurs monté un système de tracker solaire. J'ai donc écrit le code ci-dessous juste pour un seul moteur en attendant de faire le reste après :

int ldr1 = A0;
int ldr2 = A1;
int ldr3 = A2;
int ldr4 = A3;

int left = 0;
int right = 0;
int top = 0;
int bottom = 0;

void setup ()
{
   pinMode(ldr1, INPUT);
   pinMode(ldr2, INPUT);
   pinMode(ldr3, INPUT);
   pinMode(ldr4, INPUT);
}

void loop ()
{
  left = analogRead(ldr1);
  Serial.println(left);
  right = analogRead(ldr2);
  Serial.println(right);
  top = analogRead(ldr3);
  Serial.println(top);
  bottom = analogRead(ldr4);
  Serial.println(ldr4);
  
  // FORWARD
  
  while (left > right)
  {
  digitalWrite(4, HIGH);
  digitalWrite(5, LOW);
  digitalWrite(6, LOW);
  digitalWrite(7, LOW);
  
  left = analogRead(ldr1);
  right = analogRead(ldr2);
  
  if (left > right){
  digitalWrite(4, LOW);
  digitalWrite(5, HIGH);
  digitalWrite(6, LOW);
  digitalWrite(7, LOW);
  }
  else {
    if (left == right)
  {
    stopMoteur1 ();
  }
  }
  
  left = analogRead(ldr1);
  right = analogRead(ldr2);
  
  if (left > right){
  digitalWrite(4, LOW);
  digitalWrite(5, LOW);
  digitalWrite(6, HIGH);
  digitalWrite(7, LOW); 
  }
  else {
    if (left == right)
  {
    stopMoteur1 ();
  }
  }
  
  left = analogRead(ldr1);
  right = analogRead(ldr2);
  
  if (left > right){
  digitalWrite(4, LOW);
  digitalWrite(5, LOW);
  digitalWrite(6, LOW);
  digitalWrite(7, HIGH);
  }
  
  else {
    if (left == right)
  {
    stopMoteur1 ();
  }
  }
}
  
  // BACKWARD
  
  while (left < right)
  {
  digitalWrite(4, LOW);
  digitalWrite(5, LOW);
  digitalWrite(6, LOW);
  digitalWrite(7, HIGH);
  
  left = analogRead(ldr1);
  right = analogRead(ldr2);
  
  if (left < right){
  digitalWrite(4, LOW);
  digitalWrite(5, LOW);
  digitalWrite(6, HIGH);
  digitalWrite(7, LOW);
  }
  else {
    if (left == right)
  {
    stopMoteur1 ();
  }
  }
  
  left = analogRead(ldr1);
  right = analogRead(ldr2);
  
  if (left < right){
  digitalWrite(4, LOW);
  digitalWrite(5, HIGH);
  digitalWrite(6, LOW);
  digitalWrite(7, LOW); 
  }
  else {
    if (left == right)
  {
    stopMoteur1 ();
  }
  }
  
  left = analogRead(ldr1);
  right = analogRead(ldr2);
  
  if (left < right){
  digitalWrite(4, HIGH);
  digitalWrite(5, LOW);
  digitalWrite(6, LOW);
  digitalWrite(7, LOW);
  }
  
  else {
    if (left == right);
  {
    stopMoteur1 ();
  }
  }
}

  while (left == right)
  {
    stopMoteur1 (); 
  }
}

// Stop function for motor 1
void stopMoteur1 ()
{
  digitalWrite(4, LOW);
  digitalWrite(5, LOW);
  digitalWrite(6, LOW);
  digitalWrite(7, LOW);
}

Ma logique est la suivante :

  • Au départ qu'on lis la valeur des quatre photorésistances
  • Ensuite on stock la valeur de chaque photorésistance dans des variables.
  • On a ensuite trois cas :
  • Tant que left > right,
  • on avance d'un pas,
  • on lis a nouveau les valeurs
  • si c'est encore supérieur alors on avance d'un pas et on lit à nouveau les valeurs
  • (cela va se faire tout en alimentant les bobines une à une) ensuite on repart testé la condition "tant que"
  • Tant que left < right
  • là on recule d'un pas à chaque test (!=)
  • tant que left == right
  • stopMoteur1

Comme vous l'aurez remarquer je veux juste qu'à chaque pas, on lis les valeurs, on test la condition et on fait une action correspondante.

J'aimerais donc que vous me dites si j'ai bon dans le code que j'ai écrit où s'il y a des inconvénients assez visibles. Restez dans la logique du code précédent !!!

Merci !

Déjà ce qu'on peut dire : c'est lourd ! Ca peut être simplifié et bien plus lisible. Il faudrait que tu crées une fonction FaireUnPas() par exemple, avec en argument le nombre de pas. Ca évite de se retaper toute la série des digitalWrite() etc ...

De plus je te conseille vivement de mettre en place deux chose : un seuil pour la différence, sinon tes moteur vont osciller car i lest difficile d'avoir un état stable. Donc plutot faire : si left-droite>10 alors je me déplace. Ensuite prévoit une mesure minimale : et oui sinon la nuit ça risque d'être funky :wink:

Autre remarque : la ton moteur ne tournera jamais. Entre chaque pas il faut faire une pose sinon ton rotor n'a pas le temps de se déplacer.

Un meilleur algorithme au final serait :

Loop
Lecture des sinaux analogique droite et gauche
Si les signaux sont valides (est-ce la nuit ?) et la différence left-right est >seuil ou <-seuil
Alors déplacement suivant que la différence left-right est positive ou négative
fin loop

Après tu peux étoffer en utilisant la librairie PID

Il faut être conscient que les systèmes de tracking à base de cellules ont été abandonnés, au profit de systèmes à base de GPS, à base de calculs astronomiques (trigonométriques) ou à base de calculs: "temps/mouvement" (genre horlogerie.)
Mais si c'est pour le challenge, bon courage pour la discrimination (temps couvert) et les contre-réactions à mettre en jeu.

Carolyne:
Mais si c'est pour le challenge, bon courage pour la discrimination (temps couvert) et les contre-réactions à mettre en jeu.

bonjour,
il suffit d'utiliser un capteur UV, même avec des nuages ca passe, heureusement pour les panneaux solaires.

"

Carolyne:
Il faut être conscient que les systèmes de tracking à base de cellules ont été abandonnés, au profit de systèmes à base de GPS, à base de calculs astronomiques (trigonométriques) ou à base de calculs: "temps/mouvement" (genre horlogerie.)
Mais si c'est pour le challenge, bon courage pour la discrimination (temps couvert) et les contre-réactions à mettre en jeu.

Merci pour ton intervention. J'aimerais préciser ceci : Je suis tout à fait conscient que les systèmes de poursuite avec photorésistances sont tout à fait autonome mais ne sont pas fiable à 100% pour autant. Le mieux comme tu l'as dit, serait d'utiliser un système de tracking à base de calculs, ce qui nous permet d'espérer une autonomie presque "parfaite" du système.
Mais j'ai opté pour un système avec photorésistances juste par manque de temps et surtout de moyens. J'aimerais aussi par là prouver que les systèmes de tracking offrent un rendement assez élevé par rapport aux panneaux solaires fixes à longueur de journée.

B@tto:
Déjà ce qu'on peut dire : c'est lourd ! Ca peut être simplifié et bien plus lisible. Il faudrait que tu crées une fonction FaireUnPas() par exemple, avec en argument le nombre de pas. Ca évite de se retaper toute la série des digitalWrite() etc ...

De plus je te conseille vivement de mettre en place deux chose : un seuil pour la différence, sinon tes moteur vont osciller car i lest difficile d'avoir un état stable. Donc plutot faire : si left-droite>10 alors je me déplace. Ensuite prévoit une mesure minimale : et oui sinon la nuit ça risque d'être funky :wink:

Autre remarque : la ton moteur ne tournera jamais. Entre chaque pas il faut faire une pose sinon ton rotor n'a pas le temps de se déplacer.

Un meilleur algorithme au final serait :

Loop
Lecture des sinaux analogique droite et gauche
Si les signaux sont valides (est-ce la nuit ?) et la différence left-right est >seuil ou <-seuil
Alors déplacement suivant que la différence left-right est positive ou négative
fin loop

Après tu peux étoffer en utilisant la librairie PID

Merci à toi aussi pour tes remarques et suggestions. j'ai prit tout ça en compte et j'ai écrit à nouveau le code que voici :

int motorPin1 = 4;
int motorPin2 = 5;
int motorPin3 = 6;
int motorPin4 = 7;

int ldr1 = A0;
int ldr2 = A1;
int ldr3 = A2;
int ldr4 = A3;
int ldr5 = A4;

int left = 0;
int right = 0;
int top = 0;
int bottom = 0;
int center = 0;

int seuil_1 = 10; // seuil pour faire tourner le moteur
int seuil_2 = 150; // seuil pour différencier le jour de la nuit

void setup ()
{
   pinMode(motorPin1, OUTPUT);
   pinMode(motorPin2, OUTPUT);
   pinMode(motorPin3, OUTPUT);
   pinMode(motorPin4, OUTPUT);
   
   pinMode(ldr1, INPUT);
   pinMode(ldr2, INPUT);
   pinMode(ldr3, INPUT);
   pinMode(ldr4, INPUT);
   pinMode(ldr5, INPUT);
}

void loop ()
{
  left = analogRead(ldr1);
  Serial.println(left);
  right = analogRead(ldr2);
  Serial.println(right);
  top = analogRead(ldr3);
  Serial.println(top);
  bottom = analogRead(ldr4);
  Serial.println(ldr4);
  center = analogRead(ldr5);
  
  // FORWARD
  if (center > seuil_2){ 
  while ((left > right) && (left - right) > seuil_1)
  {
  pas1 ();
  delay(500);
  
  left = analogRead(ldr1);
  right = analogRead(ldr2);
  
  if ((left > right) && (left - right) > seuil_1){
  pas2 ();
  }
  else {
    if ((left - right) < 10)
  {
    stopMoteur1 ();
  }
  }
  delay(500);
  
  left = analogRead(ldr1);
  right = analogRead(ldr2);
  
  if ((left > right) && (left - right) > seuil_1){
  pas3 () ;
  }
  else {
    if ((left - right) < 10)
  {
    stopMoteur1 ();
  }
  }
  delay(500);
  
  left = analogRead(ldr1);
  right = analogRead(ldr2);
  
  if ((left > right) && (left - right) > seuil_1){
   pas4 () ;
  }
  
  else {
    if ((left - right) < 10)
  {
    stopMoteur1 ();
  }
  }
}
}

else {
 stopMoteur1 () ; 
}
}


// Stop function for motor 1
void stopMoteur1 ()
{
  digitalWrite(4, LOW);
  digitalWrite(5, LOW);
  digitalWrite(6, LOW);
  digitalWrite(7, LOW);
}

void pas1 () {
   digitalWrite(4, HIGH);
  digitalWrite(5, LOW);
  digitalWrite(6, LOW);
  digitalWrite(7, LOW); 
}

void pas2 () {
   digitalWrite(4, LOW);
  digitalWrite(5, HIGH);
  digitalWrite(6, LOW);
  digitalWrite(7, LOW); 
}

void pas3 () {
   digitalWrite(4, LOW);
  digitalWrite(5, LOW);
  digitalWrite(6, HIGH);
  digitalWrite(7, LOW); 
}

void pas4 () {
   digitalWrite(4, LOW);
  digitalWrite(5, LOW);
  digitalWrite(6, LOW);
  digitalWrite(7, HIGH); 
}

Au départ :

  • Je vérifie ma valeur seuil pour voir s'il fait jour ou s'il fait nuit.

  • s'il fait jour alors la condition est vraie et on exécute les instructions

  • Tant que (left > right) et que leur différence est supérieure au seuil du déclenchement alors on bouge d'un pas.

  • on attend 0,5 seconde

  • on lit à nouveau les valeurs

  • on test si (left > right) et si leur différence est supérieure au seuil du déclenchement alors on bouge d'un pas.

  • sinon si leur différence est inférieure au seuil de déclenchement alors on ne fait rien (left et right ne peuvent pas
    être tout à fait égale)

  • .........................

  • ainsi de suite jusqu'à faire le tour des quatre bobines et on repart testé la condition avec le "tant que"

  • s'il fait nuit alors rien ne se passe.

C'est juste le code pour la marche avant du moteur. La marche arrière c'est à peu près l'inverse de celle-ci. On aura donc la marche : AVANT - ARRIÈRE - HAUT - BAS

Dites moi si j'ai bon cette fois où s'il faut encore retoucher le code.

Je me demandais aussi comment je peux faire pour qu'à la nuit tombée mon système retourne à une position correspondant au jour suivant.

Merci !

Je me demandais aussi comment je peux faire pour qu'à la nuit tombée mon système retourne à une position correspondant au jour suivant.

il suffit de donner un seuil mini pour cela ou comme je l'ai dit juste au dessus, tu utilise un capteur UV en complément.
si UV<1
OU
si luminosité<300 (au pif)
retour point zero

Merci pour l'idée, je vais y songer pour la suite.
Pour mon code, j'aimerais savoir s'il est acceptable ou s'il faut apporter encore quelques modifications pour parfaire le tout ?
Je suis ouvert à toute autres suggestions !

Oula toujours bien trop lourd ! En plus je ne pense pas que ça va marcher.Voici des fonctions que j'utilise couramment avec mes pas à pas :

void Bouge(long Pas){

  if(Pas>0){
    for(int y=0;y<Pas;y++){
      FaireUnPas();
      Etape++;
      if(Etape>8) Etape=1; 
    }
  }

  if(Pas<0){
    for(int x=0;x<(-Pas);x++){
      FaireUnPas();
      Etape--;
      if(Etape<1) Etape=8; 
    }
  }

  digitalWrite(M1,LOW);
  digitalWrite(M2,LOW);
  digitalWrite(M3,LOW);   
  digitalWrite(M4,LOW);

}

void FaireUnPas(){

  switch(Etape) {

  case 1:
    digitalWrite(M1,HIGH);
    digitalWrite(M2,LOW);
    digitalWrite(M3,LOW);   
    digitalWrite(M4,LOW);
    break;

  case 2:
    digitalWrite(M1,HIGH);
    digitalWrite(M2,HIGH);
    digitalWrite(M3,LOW);   
    digitalWrite(M4,LOW);
    break;

  case 3:
    digitalWrite(M1,LOW);
    digitalWrite(M2,HIGH);
    digitalWrite(M3,LOW);   
    digitalWrite(M4,LOW);
    break;

  case 4:
    digitalWrite(M1,LOW);
    digitalWrite(M2,HIGH);
    digitalWrite(M3,HIGH);   
    digitalWrite(M4,LOW);
    break;

  case 5:
    digitalWrite(M1,LOW);
    digitalWrite(M2,LOW);
    digitalWrite(M3,HIGH);   
    digitalWrite(M4,LOW);
    break;

  case 6:
    digitalWrite(M1,LOW);
    digitalWrite(M2,LOW);
    digitalWrite(M3,HIGH);   
    digitalWrite(M4,HIGH);
    break;

  case 7:
    digitalWrite(M1,LOW);
    digitalWrite(M2,LOW);
    digitalWrite(M3,LOW);   
    digitalWrite(M4,HIGH);
    break;

  case 8:
    digitalWrite(M1,HIGH);
    digitalWrite(M2,LOW);
    digitalWrite(M3,LOW);   
    digitalWrite(M4,HIGH);
    break;
  }

  delayMicroseconds(PAUSE);

}

Alors la attention c'est de la gestion en demi-pas, je te laisse mettre à ta sauce si tu ne veux que du plein pas :wink:

Ma vitesse est simplement gérer par PAUSE défini en début de programme (ou tu peux utiliser une variable si tu veux faire des test). La variable Etape permet de gérer à quelle moment dans la séquence du moteur on se situe.

Après ton code simplifié ressemblerait plus à :

void loop(){

left=analogRead(ldr1);
right=analogRead(ldr2);

if(left>LimiteNuit && right > LimiteNuit) {

if(left>(right + seuil)) Bouge(1);
if(right>(left + seuil)) Bouge(-1);

}

}

Plus simple nan ? :slight_smile:

tu as un code dont tu peux t'inspirer
http://arduino4projects.com/arduino-solar-tracker/

bonjour
Et venant d'un temps :

  • où l'arduino n'existait pas :grin:
  • où certains lecteurs ici , n'etaient même pas nés :grin:
  • où certains lectaurs ici ignoraient encore ce qu'etait une diode, alors un AOP :grin:

pour simple illustration (déjà evoquée , il me semble 8) )

Un temps où visiblement le soleil avait un regard pervers aussi

comme celui d'Artouste, héhéhéhé

Merci à @Batto et à @infobarquee pour votre aide.

@Batto : J'ai lu le code que tu as soumis et je crois que c'est plus simple comme ça.

Pour résumer ton code :

  • Dans void loop () on test si il fait nuit par rapport à une valeur prédéfini plus haut (on suppose qu'il ne fait pas nuit)
  • ensuite on test si left> right + seuil si oui alors le "Pas" vaut 1 et pour cela, on fait appel à la fonction "Bouge ()". A ce niveau on fait
    appel à une autre fonction qui nous permettra de faire avancer le moteur d'un demi pas en incrémentant la valeur de "Etape" .
  • ensuite on test si "Etape" est > à 8 pour reprendre le cycle de pas à pas.
  • Enfin on test les autres conditions si elles sont vraie ou non.
  • On remet le tout à zéro.
  • Et le cycle recommence à nouveau

Ai-je bien compris ton code ? Si oui alors je ne crois plus que j'ai une condition à poser encore puisque si on a une valeur en dessous du seuil fixé alors rien ne se passera. Mais dans le cas contraire on bouge le moteur jusqu'à ce que cela arrive.

J'aimerais savoir si (left >( right + seuil)) équivaut aussi à dire ((left > right) && (left-right) > seuil)

Uzuma:
J'aimerais savoir si (left >( right + seuil)) équivaut aussi à dire ((left > right) && (left-right) > seuil)

Si le test "(left-right) > seuil" est vrai alors de toute façon (left > right) est vrai (si seuil est positif). Donc la première condition est superflue.

Uzuma:
Ai-je bien compris ton code ? Si oui alors je ne crois plus que j'ai une condition à poser encore puisque si on a une valeur en dessous du seuil fixé alors rien ne se passera. Mais dans le cas contraire on bouge le moteur jusqu'à ce que cela arrive.

Oui je pense que tu as tout saisi :wink:

Bon la j'ai fait un programme comme ça, il faut bien sûr affiner. Car en vrai il y aura d'autre car que jour plein soleil et nuit noire à gérer. Donc idéalement installer des capteurs de butée pour être sur que ton panneau ne se retrouve pas dans une position impossible (par exemple un phare de voiture ou un jour gris couvert de nuage où on se sait pas où est le soleil mais que c'est bien lumineux quand même). Un autre perfectionnement pourrait être d'installer une RTC et de fixer des bornes limites suivant l'heure de la journée, ce qui nécessite également de connaitre la position exacte de ton panneau

@fdufnews Tout à fait et je pense même que c'était évident. Ma question n'avait pas lieu d'être ! :stuck_out_tongue:

@Batto : Un grand merci pour ton code ! Je vais finaliser le tout et je soumettrai le code final à ton appréciation.
C'est juste un système de poursuite à base de photorésistances (ce qui je crois est très simple à réaliser). Mais je vise plus les systèmes à base de calculs astronomique et pour cela je me tournerai vers ce site : Welcome cerebralmeltdown.com - BlueHost.com très complet même s'il est en anglais :frowning:
Comme je l'ai dit, c'est un peu difficile dans ma position actuelle de me procurer le RTC (ce qui aurais grandement arranger les choses) et aussi y a les moyens financier à mettre en jeu et le temps qui m'est imparti.
Mais bon en guise de démonstration, des Ldrs et de 2 Steppers motors suffisent. :smiley:
Juste pour le code on peut dire que la première partie est terminée, je vais finaliser la réalisation du système maintenant.

Bonsoir,

Uzuma:
Mais je vise plus les systèmes à base de calculs astronomique et pour cela je me tournerai vers ce site : http://cerebralmeltdown.com/Sun_Tracking_and_Heliostats/ très complet même s'il est en anglais :frowning:

Si tu parts sur le calcul astronomique, tu oublies les cartes Arduino ou alors tu te contentes de formules très simplistes (ça existe mais il faut les trouver).
De mémoire, il doit traîner chez les moins jeunes un soft basic tournant sur un 8052 pour un héliographe.
@+

Bonsoir Uzuma, il y a là: PANNEAU SOLAIRE THERMIQUE piloté aux équations solaires par PIC 16F - BRICOLSEC
Un gars qui a fait le job; ça a l'air "coton".

icare:
Bonsoir,

Uzuma:
Mais je vise plus les systèmes à base de calculs astronomique et pour cela je me tournerai vers ce site : http://cerebralmeltdown.com/Sun_Tracking_and_Heliostats/ très complet même s'il est en anglais :frowning:

Si tu parts sur le calcul astronomique, tu oublies les cartes Arduino ou alors tu te contentes de formules très simplistes (ça existe mais il faut les trouver).
De mémoire, il doit traîner chez les moins jeunes un soft basic tournant sur un 8052 pour un héliographe.
@+

Il faut fouiller sur le forum. Il y a eu des choses de faites il y a longtemps déjà.
Il y a pas mal de calculs mais le temps de réponse sur ce genre d'installation n'a pas besoin d'être à la milliseconde (ni même à la seconde d'ailleurs)

calcul de la position du soleil en C :wink: