Go Down

Topic: Probleme de RTC (DS1307) avec Arduino Micro sans le moniteur serie (Read 290 times) previous topic - next topic

dubarn2

Bonjour à tous,

Je commence à tourner en rond, je vous explique :

Je suis en train de fabriquer une "horloge robotique", sur base de Arduino micro avec un RTC DS1307, un microservo indique les heures et un "mini bras robotique" composé de deux microservos indique les minutes.

Une alimentation de 12v 1.5A alimente la Micro qui elle régule du 5V pour les 3 servos et le RTC, je sais que c'est un peu limite toute cette consommation sur la Micro. Il y a un condensateur 200 uF entre le +5 et la masse

Mon problème, tous fonctionne parfaitement mais uniquement si j ai ouvert le moniteur série de IDE sinon les servos se figent toujours à la même position.

Une fois le moniteur série ouvert je peux le refermer, allumer l'alimentation externe et débrancher l'USB, cela fonctionne.
Par contre juste en allument l 'alim et/ou par cable USB, les servos restent actif mais immobiles!

Code: [Select]


// Date and time functions using a DS1307 RTC connected via I2C and Wire lib
#include <Wire.h>
#include "RTClib.h"
#include <Servo.h>

Servo servomin1;
Servo servomin2;
Servo servoheure;

RTC_DS1307 rtc;


void setup () {

 servomin1.attach(12);
 servomin2.attach(11);
 servoheure.attach(10);
  
  while (!Serial); // for Leonardo/Micro/Zero

  Serial.begin(9600);
  Wire.begin();
  rtc.begin();
  
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
     //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }
   servomin1.write(50);
   delay(600)  
   servomin2.write(100);
   delay(700);
}

void loop () {
    DateTime now = rtc.now();
    
    //Serial.print(now.year(), DEC);
    //Serial.print('/');
    //Serial.print(now.month(), DEC);
    //Serial.print('/');
   // Serial.print(now.day(), DEC);
   // Serial.print(" (");
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();

   if (now.minute()== 1){
      servomin1.write(26);    
      servomin2.write(111);  
    }
    if (now.minute()== 2){
      servomin1.write(55);  
      servomin2.write(110);  
    }
    if (now.minute()== 3){
      servomin1.write(18);    
      servomin2.write(70);  
    }
    if (now.minute()== 4){
      servomin1.write(60);    
      servomin2.write(82);  
    }
    if (now.minute()== 5){
      servomin1.write(60);    
      servomin2.write(146);  
    }
                                        // ECT ... jusqu'a 60
  
     if (now.hour()== 1){                
      servoheure.write(1);          
    }
     if (now.hour()== 2){
      servoheure.write(13);          
    }
     if (now.hour()== 3){
      servoheure.write(23);          
    }
     if (now.hour()== 4){
      servoheure.write(40);          
    }
     if (now.hour()== 5){
      servoheure.write(54);          
    }
     if (now.hour()== 6){
      servoheure.write(71);          
    }
     if (now.hour()== 7){
      servoheure.write(84);          
    }
     if (now.hour()== 8){
      servoheure.write(100);          
    }
     if (now.hour()== 9){
      servoheure.write(115);          
    }
     if (now.hour()== 10){
      servoheure.write(138);          
    }
     if (now.hour()== 11){
      servoheure.write(135);          
    }    
    if (now.hour()== 12){
      servoheure.write(8);          
    }

delay (2000);
    
}

    




Quelqu'un à t'il une idée de mon problème ?

Merci à vous!

J-M-L

Essayez en virant cette ligne du setup()

while (!Serial); // for Leonardo/Micro/Zero et tous les print...et Le Serial.begin(9600)

Pas d'USB = pas de Serial = bloqué dans le while sur unarduino Micro

Autre option tester si Serial s'initialise en attendant quelques secondes dans le setup() et sinon affecter un drapeau (une variable globale boolean portSerieOK;) à faux qui dit que la communication série ne fonctionne pas et dans le code qui suit lier l'exécution de tous les print et le begin à un test sur ce flag
if (portSerieOK) Serial.println(F("Bonjour"));

Code: [Select]

boolean portSerieOK = false;
...
void setup()
{
   ...
   for (int i = 0;  i < 50; i++) { // essaye pendant 5 secondes
       if (!Serial) {
          delay(100);   
       } else {
          portSerieOK = true;
          Serial.begin(115200);
          Serial.println(F("USB de l'Arduino Micro actif"));
          break;
       }
   }
   ...
}

void loop()
{
   ...
   if (portSerieOK) Serial.println(F("xxx"));
   ...
}



Sinon vous devriez pouvoir trouver une formule mathématique qui vous donne l'angle à utiliser pour vos servos sans écrire 60+12 (ou 24) tests (et les else...!!!)... ou au moins utiliser un tableau avec tous les angles et accéder le bon angle à l'indice correspondant à la minute courante et l'heure.

Une fois le bon angle positionné pas la peine d'appeler en permanence la fonction sur le servo - une fois à chaque nouvelle heure et minute ça suffit.


Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums
Pas de messages privés SVP

dubarn2

Merci de ta reponse,

Effectivement sans le "while (!Serial);" cela fonctionne !

Pour la position des servos, un calcule ne permet pas d'accéder à la position suivante car les minutes sont ranger aléatoirement dans une liste.
Je n'est pas mis les ELSE , seulement les IF mais cela revient quasiment au même ?

Il faut que je me renseigne un peu plus sur les listes et leurs utilisations

Pour ne pas appeler tous le temps la fonction Servo, je mets du Delay? ou je créer une variable afin de vérifier si les minutes ont changées et n'appeler la fonction Servo que dans ce cas?

En tous cas merci de tes conseils!

_pepe_

Je n'est pas mis les ELSE , seulement les IF mais cela revient quasiment au même ?
Sans les « else », tous les tests sont systématiquement effectués, ce qui prend plus de temps.

Avec les « else », la suite de tests s'interrompt au premier test vrai, ce qui prend un temps variable.

Il faut que je me renseigne un peu plus sur les listes et leurs utilisations
Des tableaux de constantes serait plus indiqués.

Tu pourrais déclarer :

Code: [Select]

const byte positions_servoheure[12] = { // de 0 à 11
   8,   1,  13,  23,  40,  54,
   71,  84, 100, 115, 138, 135
};

const byte positions_servomin1[60] = { // de 0 à 59
   26,  55,  18,  60,  60,
... jusqu'à la 60ème valeur
};

const byte positions_servomin2[60] = { // de 0 à 59
  111, 110,  70,  82, 146,
... jusqu'à la 60ème valeur
};


puis dans loop() :

Code: [Select]

  byte index_heure = now.hour();
  byte index_min = now.minute();
  if ( index_heure<24 && index_min<60 ) { // test en cas d'erreur de lecture de la RTC
    servomin1.write( positions_servomin1[index_min] );
    servomin2.write( positions_servomin2[index_min] );

    index_heure %= 12;
    servoheure.write( positions_servoheure[index_heure] );
  }



(Dans cet exemple, j'ai corrigé le fait que les minutes ne vont pas de 1 à 60 mais de 0 à 59, et que les heures ne vont pas forcément de 1 à 12 mais pourraient éventuellement aller de 0 à 23.)

Pour ne pas appeler tous le temps la fonction Servo, je mets du Delay? ou je créer une variable afin de vérifier si les minutes ont changées et n'appeler la fonction Servo que dans ce cas?
Il est préférable d'utiliser une variable pour vérifier si les minutes ont changé, mais en espaçant les lectures successives de la RTC avec un petit un délai.

J-M-L

Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums
Pas de messages privés SVP

_pepe_

Une alimentation de 12v 1.5A alimente la Micro qui elle régule du 5V pour les 3 servos et le RTC
Le régulateur 5V de la carte risque de ne pas pouvoir dissiper suffisamment de puissance, et de se mettre en sécurité.

En effet, son pouvoir de dissipation est limité à environ 0,6 W dans des conditions normales d'utilisation (TA<50°C), ce qui pour une tension d'entrée de 12V, représente un courant continu moyen de 0,6W/(12V-5V) = 85,7 mA.

La carte seule consomme plus de 20 mA, ce qui laisse moins de 65 mA pour alimenter les 3 servos et la RTC.

Si le régulateur de la carte devient trop chaud, ou si l'on constate qu'il disjoncte (notamment quand la température ambiante est élevée), alors il faudrait se résoudre à alimenter les servos à l'aide d'un régulateur séparé.

dubarn2

Merci _pepe_ pour ton aide, tes explications et cerise sur le cadeau des propositions écrites d'amélioration du code !

J'ai donc modifié mon code avec ton exemple pour utiliser les tableaux (Code beaucoup plus court et facile a lire) et aussi une variable pour attendre un changement de minute avant d'appeler la fonction Servo.

Je n'ai pas eu le temps de l'uploader pour le vérifier mais je me permets de le poster si quelqu'un découvre une erreur ou un axe d'amélioration :)



Code: [Select]


#include <Wire.h>
#include "RTClib.h"
#include <Servo.h>

Servo servomin1;
Servo servomin2;
Servo servoheure;

RTC_DS1307 rtc;

const byte positions_servomin1[24] = {8, 1, 13, 23, 40, 54, 71, 84, 100, 115, 138, 135, 8, 1, 13, 23, 40, 54, 71, 84, 100, 115, 138, 135};
const byte positions_servomin1[60] = {26, 55, 18, 60, 60, 85 ,63, 123, 105, 51, 24, 24, 35, 37, 59, 67, 83, 119, 39, 57, 77, 116, 96, 25, 46, 61, 21, 125, 42, 54, 77, 22, 71, 104, 38, 108, 79, 57, 99, 13, 47, 108, 66, 42, 26, 114, 76, 60, 60, 26, 31, 93, 53, 60, 79, 79, 62, 85, 66, 97};
const byte positions_servomin2[60] = {111, 110, 70, 82, 146, 146, 50, 102, 145, , 102, 126, 129, 88, 71, 68, 113, 120, 138, 134, 118, 82, 110, 106, 90, 73, 33, 123, 115, 113, 72, 110, 80, 102, 114, 96, 93, 63, 93, 123, 58, 92, 104, 93, 82, 98, 121, 130, 143, 143, 105, 77, 78, 84, 134, 99, 73, 61, 107, 78, 137};

int ancien_temps = 61  // 61 valeur initiale differente des 60 posibilitées de minute


void setup () {

 servomin1.attach(12);
 servomin2.attach(11);
 servoheure.attach(10);
 
  Serial.begin(57600);
 
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
     //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }
}

void loop () {
 
    DateTime now = rtc.now();
   
    byte index_heure = now.hour();
    byte index_min = now.minute();

    Serial.print(now.hour(), DEC);      // pour debug
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();
   
    if (index_min != ancien_temps) {
   
         if ( index_heure<24 && index_min<60 )                          { // test en cas d'erreur de lecture de la RTC
         
               servomin1.write( positions_servomin1[index_min] );
               delay(500);
               servomin2.write( positions_servomin2[index_min] );
               delay(500);

               index_heure %= 12;
               servoheure.write( positions_servoheure[index_heure] );
               delay(500);
               
               ancien_temps = index_min;
                                                                        }
                                   } 
   
}





Quelle est la signification exact de %=  (dans mon cas: index_heure %= 12;  ) ?


Pour mes servos, mème si tous fonctionnais bien 99% du temps, j'ai modifié pour les alimenter à travers un régulateur linéaire 6v dédié.
Je pensais ainsi réduire ou supprimer les vibrations de mon bras des minutes, composé de deux servos 9g, qui peux dans certaines positions faire des vibration frénétique.
Mais cela n'a rien changé !
Une simple pression de quelques grammes sur le bras permet d'annuler cette vibration.
La cause peut elle etre du à une bras trop léger (quelques grammes de PLA)?

Si le problème persiste je vais mettre un transistor pour activer l'alim des servos uniquement quand besoin. La force de maintient des servos non alimenté est suffisante.

Arnaud

J-M-L

Quote
Quelle est la signification exact de %=  (dans mon cas: index_heure %= 12;  ) ?
% c'est la fonction mathématique "modulo", c'est à dire le reste de la division entière

23 % 12 c'est 11 parce que 23 / 12 = 1 et reste 11  --> pratique pour ramener l'heure qui peut être de 0 à 23 dans la game 0 à 11.

Quote
Je pensais ainsi réduire ou supprimer les vibrations de mon bras des minutes, composé de deux servos 9g, qui peux dans certaines positions faire des vibration frénétique.
Mais cela n'a rien changé !
Sans doute ce sont des servos de moyenne qualité... et donc certains angles ne sont pas atteignables souvent dans le petites et grandes valeurs... il faut les tester un par un, en essayant l'angle 0 voir si ça vibre, passer à 1, 2, 3, etc jusqu'à ce que ça ne vibre plus (il se peut aussi que ça vibre en fin de course) ==> malheureusement ça fait que vous n'aurez pas l'ensemble de la palette des angles dispos
Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums
Pas de messages privés SVP

_pepe_

Quelle est la signification exact de %=  (dans mon cas: index_heure %= 12;  ) ?
index_heure %= 12; est juste une autre façon d'écrire index_heure = index_heure % 12;

« % » est l'opérateur mathématique « modulo », correspondant au reste de la division entière. On a notamment :

0 % 12 = 0
1 % 12 = 1
...
11 % 12 = 11
12 % 12 = 0
13 % 12 = 1
...
23 % 12 = 11

Ainsi, on a la garantie que l'heure sera restreinte à une valeur comprise entre 0 et 11, qui sont les valeurs d'index admissible du tableau de positions.


Concernant les vibrations des servos, il peut s'agir d'une instabilité de l'asservissement qu'on pourrait corriger en changeant les caractéristiques mécaniques de la charge, ou bien d'un défaut du produit (jeu mécanique trop important, discontinuité dans la réponse du capteur de position, ...).

Un arrêt de l'alimentation ou de l'envoi des impulsions de commande pourraient être envisagés, sous réserve de la réaction des servos, qui peut être très différente d'un modèle à l'autre.

Par exemple, j'ai déjà obtenu de bons résultat en privant d'alimentation 5V un servo SM-S2309S grâce à la coupure de son GND tout en maintenant son signal de commande au niveau haut. (Attention : ne pas tenter avec une alimentation de 6V !) La coupure de son +5V (avec le maintien de son signal de commande au niveau bas) entraînait des mouvements aléatoires de grande amplitude à la remise sous tension.

Go Up