Rotation moteur pap contrôlé par un RTC

Bonjour,

Je découvre le monde de la programmation Arduino et trouve cela très passionnant et captivant. Je me documente sur différents forums et site français ou anglais (j’avoue que ça aide de parler couramment anglais ! :D).

J’ai fabriqué une horloge à engrenage en bois avec une gestion électronique pour faire mouvoir le mécanisme. j’utilise pour cela un moteur 28BYJ-48 et son driver ULN2003. J’ai réussi en quelques jours à faire un programme pour faire tourner un moteur à la vitesse de 12 tours par minute. C’est la vitesse qui correspond au ration de la démultiplication utilisée.

Je souhaiterai utiliser un RTC pour contrôler avec précision la rotation du moteur pour qu’il fasse précisément 12 tours/minute ou 1 tour en 5 seconde. Je voudrai intégrer au code une fonction qui interrogerait le RTC toutes les secondes pour qu’il contrôle si le moteur à fait le bon nombre de pas et puisse le corriger s’il en fait plus ou pas assez.

Si pour 1 tour de 2048 pas en 5 seconde, il faut que le moteur fasse précisément 409.6 pas/seconde. Hors je doute que l’on puisse diviser les pas en 1/10 de pas! Donc si je fais faire 410 pas/seconde le moteur va faire 0.4 pas de plus en une seconde soit 24 pas de trop par minute (0.4x60=24 ) et 1440 pas de trop par heure (24x60=1440). Soit 3.5s de plus par heure (1440/409.6=3.5 (en arrondissant au 1/10 de seconde ) et donc 1.4 minute d’avance par jour.

Pour utiliser le RTC DS3132 il faut la librairie rtclib.h. Je vais brancher le port SCL sur la sortie analogique 5 et le port SDA sur la sortie analogique 4.

J’en appelle à votre aide pour m’aiguiller sur les fonctions à utiliser pour synthétiser ce que j’ai décrit et comment insérer la gestion du RTC à mon code.

Merci à tous pour vos conseilles, idées, compétences et aide.

Guillaume

#include "RTClib.h"
RTC_DS3231 rtc;
#include <Stepper.h> 
double stepsPerRevolution = 2048;
Stepper myStepper(stepsPerRevolution, 8, 10, 9, 11); 
void setup() { 
 myStepper.setSpeed(12); //1= 1tour/min ; 60s/5= 12 =1tour en 5s 
 Serial.begin(9600); 
 } 
 
 void loop() {  
    
   Serial.println("clockwise");    
   myStepper.step(stepsPerRevolution);    
}

Bonjour

Vous pouvez configurer votre RTC_DS3231 pour qu’elle vous envoie un signal toutes les secondes avec writeSqwPinMode(DS3231_SquareWave1Hz). dans cette interruption vous mettez un drapeau à vrai que vous traitez dans la boucle. ça vous permet de faire un truc toutes les secondes.

le truc en question serait un certain nombre de pas. Vous avez raison, ce sera assez difficile de trouver la virgule dans le nombre de pas (à moins de regarder en micro-stepping mais y’a des ratés. Je suis sûr que @vileroi pourra donner des conseils). Le nombre de pas à faire à chaque fois ne sera donc pas constant, c’est un arrondi mais ce qui compte c’est qu’au bout de vos 5 secondes vous ayez réalisé 2048 pas (en gros ça veut dire répéter ces séquences de 5 déplacements: +409, +410, +409, +410, +410 - car 3410+2409 = 2048)

ces chiffres en sortent pas du chapeau, c’est simplement le reste entier lorsque vous devez atteindre 2048 en 5 étapes. donc ça se code assez facilement. Voici un exemple:

#include <RTClib.h>
RTC_DS3231 rtc;

const byte sqWavePin = 2;
volatile bool topSeconde;
uint32_t compteurSeconde = 0;
uint32_t compteurDePas = 0;

const double stepsPerRevolution = 2048; // 2048 pas par tour pour le stepper
const uint16_t revolutionDuration = 5;    // on veut un tour en 5 secondes

void tictac()
{
  topSeconde = true;
}

void setup() {
  pinMode(sqWavePin, INPUT_PULLUP);
  Serial.begin(115200);

  if (!rtc.begin()) {
    Serial.println(F("pas de RTC!"));
    Serial.flush();
    while (true); // on arrête ici.
  }
  rtc.disable32K(); // on n'utilise pas cette sortie
  rtc.writeSqwPinMode(DS3231_OFF);

  attachInterrupt(digitalPinToInterrupt(sqWavePin), tictac, FALLING);
  topSeconde = false;
  rtc.writeSqwPinMode(DS3231_SquareWave1Hz); // on active la sortie à 1Hz
}

void loop() {
  if (topSeconde) {
    topSeconde = false;
    static uint16_t previousAbsolutePosition = 0;
    uint16_t stepStage = compteurSeconde % revolutionDuration + 1;
    if (stepStage == 1) previousAbsolutePosition = 0;
    uint16_t absolutePosition = stepsPerRevolution * stepStage / revolutionDuration;
    uint16_t deltaStep = absolutePosition - previousAbsolutePosition;

    // AVANCER DE deltaStep

    compteurSeconde++;
    compteurDePas += deltaStep;
    previousAbsolutePosition = absolutePosition;

    Serial.print(F("t = "));
    Serial.print(compteurSeconde);
    Serial.print(F("\tJe fais "));
    Serial.print(deltaStep);
    Serial.print(F(" pas.\tTotal Parcouru: "));
    Serial.println(compteurDePas);

  }
}

pour l’utiliser vous câblez ainsi
DS3231 — ARDUINO
VCC— 5V
GND ---- GND
SDA — A4
SCL ---- A5
SQW ---- 2

Si tout va bien le moniteur série (à 115200 bauds) affichera

[color=purple]
t = 1	Je fais 409 pas.	Total Parcouru: 409
t = 2	Je fais 410 pas.	Total Parcouru: 819
t = 3	Je fais 409 pas.	Total Parcouru: 1228
t = 4	Je fais 410 pas.	Total Parcouru: 1638
[b][color=red]t = 5	Je fais 410 pas.	Total Parcouru: 2048[/color][/b]
t = 6	Je fais 409 pas.	Total Parcouru: 2457
t = 7	Je fais 410 pas.	Total Parcouru: 2867
t = 8	Je fais 409 pas.	Total Parcouru: 3276
t = 9	Je fais 410 pas.	Total Parcouru: 3686
[b][color=red]t = 10	Je fais 410 pas.	Total Parcouru: 4096[/color][/b]
t = 11	Je fais 409 pas.	Total Parcouru: 4505
t = 12	Je fais 410 pas.	Total Parcouru: 4915
t = 13	Je fais 409 pas.	Total Parcouru: 5324
t = 14	Je fais 410 pas.	Total Parcouru: 5734
[b][color=red]t = 15	Je fais 410 pas.	Total Parcouru: 6144[/color][/b]
t = 16	Je fais 409 pas.	Total Parcouru: 6553
t = 17	Je fais 410 pas.	Total Parcouru: 6963
t = 18	Je fais 409 pas.	Total Parcouru: 7372
t = 19	Je fais 410 pas.	Total Parcouru: 7782
[b][color=red]t = 20	Je fais 410 pas.	Total Parcouru: 8192[/color][/b]
t = 21	Je fais 409 pas.	Total Parcouru: 8601
...
[/color]

On voit bien que toutes les 5 secondes on a fait 2048 pas de plus - donc un tour (si le moteur ne rate pas de pas).

Et bien ! ça c'est ce que j'appelle de la réponse précise !!! Merci beaucoup pour tout ses détails, je vais pouvoir étudier le fonctionnement et l'élaboration du code que vous m'avez fourni, j'en attendais pas tant ! Je vais tester cela. J'avais pensé à faire faire un pas de plus et un pas de moins dans une boucle mais je suis trop limité par mes connaissances... ça viendra avec la pratique !?

Merci beaucoup !

à moins de regarder en micro-stepping mais y'a des ratés. Je suis sûr que @vileroi pourra donner des conseils

Le micro-stepping n'est pas accessible pour les moteurs unipolaires. On peut seulement utiliser les demi-pas.

répéter ces séquences de 5 déplacements: +409, +410, +409, +410, +410 - car 3*410+2*409 = 2048

Dans ce cas précis on peut aussi faire un "moteur virtuel" qui tournerait 10 fois plus vite soit exactement 4096 pas par seconde. Quand on donne un ordre au moteur virtuel d'avancer d'un pas, il fait avancer le moteur réel de un seul pas, une fois sur 10.

ok, j'ai compris le principe en effet c'est très logique et malin de multiplier le nombre de tours en virtuel pour que le moteur réel sois dans le bon timming. Plein de chose à découvrir et apprendre car en langage humain pas de soucis de compréhension mais en Langage Arduino j'ai pas le bon code pour retranscrire !! :D

Merci à vous pour votre implication !

Bonjour !

J'ai intégré le stepper.h au code avec les paramètre adéquats et bien fait attention qu'il n'y ait pas d'erreur d'accolade ni de parenthèse et autres mais au moment de téléverser il me sort un message d'erreur de compilation pour la carte arduino uno, j'ai déjà eu ce soucis mais je ne sais plus comment je m'y suis pris pour le résoudre...

Merci pour votre aide précieuse et si efficace !

Guillaume ;)

#include "Stepper.h" 
Stepper motor(2048,8,10,9,11)
#include "RTClib.h"
RTC_DS3231 rtc;
const byte sqWavePin = 2;
volatile bool topSeconde;
uint32_t compteurSeconde = 0;
uint32_t compteurDePas = 0;
const double stepsPerRevolution = 2048; // 2048 pas par tour pour le stepper
const uint16_t revolutionDuration = 5;    // on veut un tour en 5 secondes
void tictac()
{
  topSeconde = true;
}

void setup() 
{  
  Serial.println("clockwise");    
   motor.step(2048);   

 pinMode(sqWavePin, INPUT_PULLUP);
  Serial.begin(115200);

  if (!rtc.begin()) {
    Serial.println(F("pas de RTC!"));
    Serial.flush();
    while (true); // on arrête ici.
  }
  rtc.disable32K(); // on n'utilise pas cette sortie
  rtc.writeSqwPinMode(DS3231_OFF);

{
    attachInterrupt(digitalPinToInterrupt(sqWavePin), tictac, FALLING);
  topSeconde = false;
  rtc.writeSqwPinMode(DS3231_SquareWave1Hz); // on active la sortie à 1Hz
}
}

void loop() {
  if (topSeconde) {
    topSeconde = false;
    static uint16_t previousAbsolutePosition = 0;
    uint16_t stepStage = compteurSeconde % revolutionDuration + 1;
    if (stepStage == 1) previousAbsolutePosition = 0;
    uint16_t absolutePosition = stepsPerRevolution * stepStage / revolutionDuration;
    uint16_t deltaStep = absolutePosition - previousAbsolutePosition;

    // AVANCER DE deltaStep

    compteurSeconde++;
    compteurDePas += deltaStep;
    previousAbsolutePosition = absolutePosition;

    Serial.print(F("t = "));
    Serial.print(compteurSeconde);
    Serial.print(F("\tJe fais "));
    Serial.print(deltaStep);
    Serial.print(F(" pas.\tTotal Parcouru: "));
    Serial.println(compteurDePas);
  }
}

il me sort un message d'erreur de compilation

Pour faciliter notre tâche, joint le message d'erreur par un couper coller (il y a un bouton "recopier les messages d'erreur" qui fait le copier). A mettre plutôt dans une balise code pour éviter les smiles.

Appuyez sur ctrl-T dans l’IDE pour indenter correctement aussi avant de poster le code

Ce n’est pas le pb de compilation mais il faut mettre le Serial.begin(115200); avant le premier appel à print si vous voulez voir quelque chose

Je viens de contacter Jacques Fabre via my mini factory et il m’a communiqué le code qui correspondait parfaitement à mon usage. Je le mets ci joint si ça peux être utile à quelqu’un. j’ai juste mis “const long interval = 0” car je ne veux pas d’intervalle.

//FOR RTC
//Date and time functions using a DS3231 RTC connected via I2C and Wire lib
#include <Wire.h>
#include “RTClib.h”
RTC_DS3231 rtc;
//FOR stepper
#include <Stepper.h>
// constants won’t change. Used here to set a pin number:
const int ledPin = LED_BUILTIN;// the number of the LED pin
int ledState = LOW; // ledState used to set the LED

unsigned long previousSECOND = 0; // will store last time LED was updated
// constants won’t change:
const long interval = 0; // interval at which to blink (1 seconds)
//and for stepper
int in1Pin = 8;
int in2Pin = 9;
int in3Pin = 10;
int in4Pin = 11;

// 96 step motor salvaged from a paper printer
Stepper motor(2048, in1Pin, in2Pin, in3Pin, in4Pin);

// to print time to console
unsigned long time;

void setup () {

#ifndef ESP8266
while (!Serial); // for Leonardo/Micro/Zero
#endif

// set stepper output
pinMode(in1Pin, OUTPUT);
pinMode(in2Pin, OUTPUT);
pinMode(in3Pin, OUTPUT);
pinMode(in4Pin, OUTPUT);

//set motor speed
motor.setSpeed(12);
//set up monitor to print out infos
Serial.begin(9600);

if (! rtc.begin()) {
Serial.println(“Couldn’t find RTC”);
while (1);
}

if (rtc.lostPower()) {
Serial.println(“RTC lost power, lets set the time!”);
// 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));
}
pinMode(ledPin, OUTPUT);// set the digital pin as output:

}

void loop () {
// here is where you’d put code that needs to be running all the time.
//Creat RTC object
DateTime now = rtc.now();
//load currant second
unsigned long currentSECOND = now.unixtime();

// check to see if it’s time to blink the LED; that is, if the difference
// between the current time and last time you blinked the LED is bigger than
// the interval at which you want to blink the LED.
if (currentSECOND - previousSECOND >= interval) {
//print time to console
Serial.print("Time: ");
time = now.unixtime();
Serial.println(time); //prints time since program started

previousSECOND = currentSECOND;
//And do something
// if the LED is off turn it on and vice-versa:
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}

// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);

//And activate the stepper motor

//move 8 steps
motor.step(-32);

}

}

Un grand merci à lui ! :wink: