Code semble erroné pour commander un servomoteur

Bonjour à tous,
Tout d'abord un grand merci pour ce forum avec tous ces tutos et cours ainsi que toutes ces réalisations.

J'ai découvert depuis quelques semaines le monde de l'arduino et c'est véritablement passionnant !

J'ai suivi un tuto pour automatisé ma porte de poulailler (je sais que ce sujet n'est pas original au nombre de posts sur ce sujet).

Ma porte guillotine est terminée.
J'ai branché ma carte Elegoo Uno R3 sur un servo moteur 995 (fonctionne sur piles pour le moment).

Quand je fais des tests la porte s'ouvre et se ferme. Les réglages d'angle sont bons.
Cependant quand je paramètre les réglages horaires, c'est là que cela se gâte... La porte ne s'ouvre et ne se ferme pas... :face_with_raised_eyebrow:

Je vous mets ci-joint le code utilisé.
J'avoue ne pas vraiment le comprendre dans son intégralité

 #include <Servo.h>

 Servo leServo1;

  unsigned int heurereinitialisation;

  unsigned int fermeturesoir;

  unsigned int ouverturematin;

  unsigned int t;

  unsigned int t1;

  unsigned int t2;

  int pinServo1= 9;

void setup() {

 

fermeturesoir=22;                    //fermeturesoir correspond à l'heure ou la porte se fermera(heure en heure)

ouverturematin=6;                    //ouverturematin correspond à l'heure ou la porte se fermera(heure en heure)

heurereinitialisation=22;             //heurereinitialisation correpond à l'heure à laquelle vous téléverser le programme sur la carte, Vous devez changez ce paramètre à chaque fois que téléverser le programme(heure en heure)

 

leServo1.attach(pinServo1);

ouverturematin=24-heurereinitialisation+ouverturematin;

fermeturesoir=fermeturesoir-heurereinitialisation;

fermeturesoir=fermeturesoir+1;

ouverturematin=ouverturematin+1;

 

}

 

void loop(){

t2=0;

while (t2 < 24){

  t2=t2+1;

  t1=0;

  if (t2==ouverturematin){

    leServo1.write(0);

    delay(2000);  }

  if (t2==fermeturesoir) {

    leServo1.write(120);

    delay(2000); }

while (t1 < 3600 ){

   t1=t1+1;

   t=0;

while (t < 2 ){

   t=t+1;

   delay(500);

  }}}}

Si je renseigne l'heure d'initialisation identique à l'heure d'ouverture ou de fermeture, la porte s'ouvre ou se ferme. Mais une fois dans la réalité (avec la bonne heure initialisation) plus rien ne marche.

J'avoue que ce passage est très mystérieux pour moi :

ouverturematin=24-heurereinitialisation+ouverturematin;

fermeturesoir=fermeturesoir-heurereinitialisation;

fermeturesoir=fermeturesoir+1;

ouverturematin=ouverturematin+1;

Ce qui est dans le boucle n'est pas très clair non plus...

Seriez-vous ce qui pêche ?
Merci d'avance pour la lecture de ce post.

Bonjour jypi

J'ai contrôlé ton programme en l'accélérant et il fonctionne.

#include <Servo.h>
Servo leServo1;
unsigned int heurereinitialisation;
unsigned int fermeturesoir;
unsigned int ouverturematin;
unsigned int t;
unsigned int t1;
unsigned int t2;
int pinServo1= 9;
const String t2Label = "T2\t";

void setup() {
Serial.begin(115200);	
	fermeturesoir=22;                    //fermeturesoir correspond à l'heure ou la porte se fermera(heure en heure)
	ouverturematin=6;                    //ouverturematin correspond à l'heure ou la porte se fermera(heure en heure)
	heurereinitialisation=22;             //heurereinitialisation correpond à l'heure à laquelle vous téléverser le programme sur la carte, Vous devez changez ce paramètre à chaque fois que téléverser le programme(heure en heure)
	
	leServo1.attach(pinServo1);
	ouverturematin=24-heurereinitialisation+ouverturematin;
	fermeturesoir=fermeturesoir-heurereinitialisation;
	fermeturesoir=fermeturesoir+1;
	ouverturematin=ouverturematin+1;
	
}

void loop(){
	t2=0;
	while (t2 < 24){
		t2=t2+1;
		Serial.println(t2Label + t2);
		t1=0;
		if (t2==ouverturematin){
			Serial.println("Servo 0");
			leServo1.write(0);
		delay(2000);  }
		if (t2==fermeturesoir) {
			Serial.println("Servo 120");
			leServo1.write(120);
		delay(2000); }
		while (t1 < 12 ){
			t1=t1+1;
			t=0;
			while (t < 2 ){
				t=t+1;
				delay(50);
			}}}}

Si tu mets ton moniteur à 115200 tu en verras le déroulement.

Le hic, c'est le programme, c'est du minimum voire du minimaliste!
As-tu vu que l'heure de démarrage du timing est défini par la variable heurereinitialisation, ce qui veut dire que si tu coupée l'alimentatoion de ton Arduino à 15:00 et que tu le remets en route, il redémarre comme s'il était heurereinitialisation c'est à dire 22h.!
Pour travailler "proprement", il faudrait travailler avec une horloge (RTC) genre DS3231 ou l'alternative basé sur la lumière ambiante avec une cellule photo-électrique.

Cordialement
jpbbricole

Si tu élèves des poules, tu dois probablement savoir qu'elles se lèvent et se couchent en même temps que le soleil.
Si tu fermes à 22H en été tout va bien, mais l'hiver c'est la porte ouverte aux prédateurs.

#include <time.h>
#include "RTClib.h"

RTC_DS3231 rtc;
    
void setup() {
  Serial.begin(115200);
  if (!rtc.begin()) {
    Serial.println(F("Couldn't find RTC"));
    while(1);
  }
  if (rtc.lostPower()) {
    Serial.println(F("RTC lost power"));
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
}

void loop() {
  Serial.print("day : "); Serial.println(isDay() ? "YES" : "NO");
  delay(2000);
}

bool isDay(void)
{
  time_t now;

  DateTime utc = rtc.now();
  now = utc.unixtime();
  time_t sunRise = sun_rise(&now);
  time_t sunSet = sun_set(&now);
  return now >= sunRise && now <= sunSet ? true : false;
}

sun_rise() et sun_set() sont deux fonctions standard de la librairie C.
Il te faut un module RTC DS3231. Librairie : voir RTClib dans gestionnaire de biblios.
Eviter DS1307, pas assez précis sur la durée.

1 Like

Bonjour jpbbricole,
merci pour votre réponse rapide.
Je vais donc rajouter une horloge RTC DS3231.
Je n'ai pas compris l'histoire du moniteur par contre. Pouvez-vous m'expliquer ?
Et dans le but d'apprendre, comment faites-vous concrètement pour tester rapidement un programme et savoir s'il fonctionne ?
Pourquoi, s'il fonctionne en accéléré dans votre test, il ne fonctionne pas en réel ?Y aurait-il des micro-coupures d'alimentation qui redémarre la carte régulièrement avec comme heure d’initialisation 22h ? (j'utilise pour le moment des piles rechargeables assez anciennes)

Bonjour hbachatti,
effectivement, j'avais initialement prévu de modifier deux à trois fois dans l'année les horaires d'ouverture et de fermeture...
J'attends le module RTC pour ajouter ce code au précédent et je reviens vers vous.

Merci à vous deux !

Bonjour jypi

Le moniteur permet de voire "vivre" ton programme par des instructions comme
Serial.println("Servo 0");
ou
Serial.println("Servo120");
Je prends cet exemple, parce que je n'avais pas connecté de servo sur mon Arduino. Je te rassure, j'ai aussi testé avec un servo et ça fonctionne aussi.
Le mieux, tu recherches arduino le moniteur sur le Net et le premier lien PlaisirArduino me semble pas mal.

Comme c'est un programme qui tourne sur 24H. et que je suis un impatient, j'ai accéléré le tout ainsi, avant:

		while (t1 < 3600 ){
			t1=t1+1;
			t=0;
			while (t < 2 ){
				t=t+1;
				delay(500);
			}
		}

Après

		while (t1 < 12 ){
			t1=t1+1;
			t=0;
			while (t < 2 ){
				t=t+1;
				delay(50);
			}
		}

Ce qui fait que les heures passent de 3600 secondes à 12 secondes, ça décoiffe!
Comme, sur le moment, je n'avais pas connevté de sero à mon Arduino, j'ai ajouté à l'endroit où ils étaient actionnés:

			Serial.println("Servo 0");
			leServo1.write(0);
// et
			Serial.println("Servo 120");
			leServo1.write(120);

Le mieux est que tu testes la version accélérée avec ton servo,

A+
Cordialement
jpbbricole

Bonjour,

Est-il possible d'afficher les heures du coucher et du lever sur le moniteur série sans brancher le RTC ?

Je suppose que le résultat soit à peu près le même qu'avec la mesure de luminosité sur une LDR ou un PV.
J'ai remarqué qu'en programmant le seuil de fermeture de la trappe l'hiver,1/2 heure après que les poules soient effectivement rentrée, en ce moment c'est plus d'une heure de décalage.

Je dis ça parce que mes poules jouent les filles de l'air depuis 2 mois. Elles ont du avoir peur de quelque chose, ma jeune chatte qui commence à chasser peut-être, parce qu'elles deviennent folle quand elles la voient ?
Ce n'était jamais arrivé depuis 5 ans que mon système était installé.

En ce moment, il y a beaucoup de pluies nocturnes, je ne peut pas les laisser à leur sort.
Tous les soirs, vers 21 h; 21 h 30, je vais les récupérer perchées sur une branche basse, à l'autre extrémité du terrain, mais elles n'y reviennent plus d'elle-même. Elles se couchent un peu plus tôt par temps couvert.

  time_t now;

  DateTime utc = rtc.now();
  now = utc.unixtime();

L'heure provient forcément de la RTC, sauf si tu as mis à l'heure l'horloge système de l'ARDUINO. Cela va dériver, forcément.

L'horloge système se met à l'heure comme ceci :
set_system_time(time_t timestamp) ou timestamp est le nombre de secondes écoulées depuis le 1/1/1970 : ce que l'on appelle Epoch.

Si tu veux tester sun_rise() et sun_set() rien ne t'empêche de travailler à partir de l'horloge système.
Il faut inclure time.h

  time_t now;
  time(&now);

now est le nombre de secondes écoulées depuis le 1/1/1970, valeur qui devra être passée à sun_rise() et sun_set().

Mais attention : toutes ces fonctions travaillent en temps UTC (Greenwich).
Pour afficher l'heure locale France il faudra ajouter le décalage (2H pour nous en été).

Par exemple (sous Ubuntu) :
riton@alpha:/mnt/sdc1/riton/kicad$ date +%s && date &&date -u
1625645644 // heure Epoch
mercredi 7 juillet 2021, 10:14:04 (UTC+0200) // heure locale
mercredi 7 juillet 2021, 08:14:04 (UTC+0000) // heure UTC

Teste ceci :

#include <time.h>
#include "RTClib.h"

void setup() {
  Serial.begin(115200);
  set_system_time(1625645644);      // à modifier (Epoch)
}

void loop() {
  time_t now;
  time(&now);
  Serial.print(now); Serial.print(" : day : "); Serial.println(isDay(now) ? "YES" : "NO");
  delay(1000);
  system_tick();
}

bool isDay(time_t now)
{
  time_t sunRise = sun_rise(&now);
  time_t sunSet = sun_set(&now);
  return now >= sunRise && now <= sunSet ? true : false;
}

Sous Windows, il est possible de récupérer l'heure Epoch en ligne : https://timestamp-tool.fr/

J'ai oublié qu'il fallait donner la latitude et la longitude :upside_down_face:
Ce code donne l'heure de lever et coucher à partir de l'heure de la compilation.

#include <time.h>

#define LATITUDE          47.25
#define LONGITUDE         6.033

void setup() {
  Serial.begin(115200);
  set_system_time(getCompileTime());
  set_position(LATITUDE * ONE_DEGREE, LONGITUDE * ONE_DEGREE);
  char s[30];
  time_t now;
  time(&now);
  struct tm *dt = localtime(&now);
  sprintf(s, "%02d/%02d/%d %02d:%02d:%02d", dt->tm_mday, dt->tm_mon+1, dt->tm_year+1900, dt->tm_hour, dt->tm_min, dt->tm_sec);
  Serial.println(s);
  time_t sunRise = sun_rise(&now);
  struct tm *sr = localtime(&sunRise);
  sprintf(s, "sun rise : %02d/%02d/%d %02d:%02d:%02d", sr->tm_mday, sr->tm_mon+1, sr->tm_year+1900, sr->tm_hour+2, sr->tm_min, sr->tm_sec);
  Serial.println(s);
  time_t sunSet = sun_set(&now);
  struct tm *ss = localtime(&sunSet);
  sprintf(s, "sun set : %02d/%02d/%d %02d:%02d:%02d", ss->tm_mday, ss->tm_mon+1, ss->tm_year+1900, ss->tm_hour+2, ss->tm_min, ss->tm_sec);
  Serial.println(s);
}

void loop() {
}

time_t getCompileTime(void)
{
  char s_month[5];
  struct tm t;
  int s, m, h, d, y;
  static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";

  memset(&t, 0, sizeof(struct tm));
  sscanf(__DATE__, "%s %d %d", s_month, &d, &y);
  sscanf(__TIME__, "%d:%d:%d", &h, &m, &s);
  t.tm_sec = s;
  t.tm_min = m;
  t.tm_hour = h;
  t.tm_mday = d;
  t.tm_mon = (strstr(month_names, s_month) - month_names) / 3;
  t.tm_year = y - 1900;
  t.tm_isdst = -1;
  return mktime(&t);
}

Après il reste à jouer avec la timezone pour l'heure été hiver.

Bonjour jpbbricole,
Merci pour la découverte du moniteur, du site plaisirArduino et tes explications claires.
Effectivement, tout fonctionne.

La "panne" vient de mon alimentation.
J'ai mis 4 anciennes piles rechargeables 1.5 V pour alimenter la carte et le servomoteur.
Dans le tuto, il mettait 6 piles 1.5V.
Par conséquent, soit ces piles sont trop faibles soit il n y en a pas assez...

En tout cas, grâce à toi, j'ai appris de nouvelles choses qui vont me permettent d'être plus autonome à l'avenir, je l'espère et qui sait un jour en aider d'autres...

J'attends mon module RTC DS3132 et avec les explications d' hbachetti, je vais configurer cela pour plus de précision et de simplicité par la suite.

Je ne sais pas comment ce système va être alimenté, mais il vaudrait mieux lire ceci :

Comme il s'agit d'une UNO il faut oublier l'alimentation par batterie ou piles. Ce sera forcément secteur.

Bonjour hbachetti

Pas forcément, il y a les powerbank,
image
qui peuvent se connecter par un câble USB sur le port USB de l'Arduino, ou s'il faut alimenter d'autres périphériques en 5V. via un plug USB comme ceci

image
et reprendre le 5V. du plug USB et alimenter l'Arduino sur la broche 5V.

Ily a quantité de capacité de powerbank et pas trop chères. Le petit problème, est que, si votre montage ne consomme pas beaucoup, le powerbank se déclenche. Ceci peut être éviter en mettant une résistance pour consommer un peu plus de courant afin de dépasser la limite basse.

Si votre montage nécessite aussi du 9V. ou du 12V. il y a des DC-DC Step Up Converter pour produire ces tensions.
image

Cordialement
jpbbricole

Une UNO alimentée par USB consomme 20mA en mode veille (qui n'est pas utilisé dans le code de jypi actuellement) , et 38mA en mode éveillé.

Par mois, la consommation sera de 20 * 24 * 30 = 14400mAH en mode veille, et 27360mAH en mode éveillé.
A cela il faut ajouter la consommation du reste : servo, RTC, etc.

Une PRO MINI 5V modifiée (sans LED, sans régulateur) consomme 3µA en mode veille, et 3.2mA en mode éveillé.

Je te laisse refaire les calculs.

D'autre part une UNO, avec ses fils DUPONT, en extérieur, par +35° ou -10°, sécheresse, humidité, n'est pas une solution fiable.

Rien ne vaut une NANO (sur secteur) ou une PRO MINI (sur batterie) soudée sur une plaquette à pastilles ou un PCB, avec les composants annexes : RTC, connecteur servomoteur, etc.

On ne travaille pas de la même façon sur un coin de table et en situation réelle.

Bonjour hbachetti

Pourquoi pas un UNO avec un PCB à pastilles sur le dos
image
il y a déjà le jack d'alimentation, ce qui simplifie les choses?
Quelle est la différence, étant donné que le Nano est un Uno moins encombrant.

Cordialement
jpbbricole

Laissons à jypi le temps de faire ses choix. Pour l'instant on ne sait même pas s'il a accès au secteur ou pas.

Ton code horaire fonctionne bien.
Chez moi, avec les bonnes coordonnées, j'obtiens

sun rise : 07/07/2021 05:53:00
sun set : 07/07/2021 21:56:38

C'est l'heure ou le soleil a passé l'horizon et il fait encore bien jour.

Ces derniers temps elles se couchaient vers 21 h par temps couvert et 21 h 30 par temps clair.
Fermer la trappe à 21 H 56 est une bonne heure avec une bonne marge de sécurité.
L'hiver, comme les jours sont plus court, elles on tendance à rentrer à plus basse luminosité, à surveiller.

Reste plus qu'à combiner les 2 codes que tu as donné pour commander le servo moteur ?
J'avais déjà téléchargé ce que tu avais fais, mais beaucoup trop d'instructions que je ne comprends pas pour ressortir un programme uniquement basé éphéméride.

Moi, avec alimentation 5.3 V j'ai au mieux : 6.8 µA

Le dernier seulement.
Mais il faut savoir qu'il bosse en temps UTC.
Pour l'exemple, j'ajoute manuellement 2H pour afficher l'heure de lever et de coucher, mais c'est OK en été seulement.
De toutes façons je te conseille de stocker l'heure UTC dans le DS3231, pas l'heure locale (France). C'est le meilleur moyen de travailler.

Si tu as mon code, tout est dans timedate.h, timedate.cpp, options.h.

Je fonctionne avec un serveur DOMOTICZ, qui envoie l'heure à ma porte motorisée, mais en heure locale (France). Je recalcule systématiquement l'heure UTC avant d'envoyer à la RTC. Si tu saisis l'heure manuellement, tu auras le même problème. Ou alors il faut saisir l'heure UTC directement.

Tu as peut-être une carte pas très propre. La passer à l'acétone pourrait améliorer.
Mais il ne sert à rien de chatouiller le µA, le courant d’auto-décharge de la batterie est plus important.