Commande automatique de groupe électrogène - machine à états et autres questions

Il faut quand même que je revoie le système d'erreurs et de reset, c'est assez merdique et la cliente ne s'en sort pas. Et comme quand le moteur cale par panne sèche, ça passe en erreur, et que régulièrement elle se fait avoir vu qu'elle n'a pas voulu de l'option réservoir externe grande capacité...

nouvelle version 1.0.0 avec l'ajout de temporisations de montée en température et de refroidissement avant et après activation de la sortie puissance de la génératrice. Cette coupure de la sortie puissance se fait par un relais commandé par la sortie décompresseur de la carte, puisqu'elle ne va finalement pas servir.

https://sourceforge.net/p/groupe/code/ci/0cbda993f452e1612fbcbb8a91f8b451ff6bba47/tarball

par contre ma machine à états est de plus en plus un fouillis inimaginable, c'est in-maintenable. il faut vraiment que je reprenne le code à partir de zéro pour remettre ça propre.

En fait ce topic pourrait être déplacé dans "réalisations et projets finis" je suppose, même si il y aura sans doute des évolutions, vu que c'est déja un projet fonctionnel.

C'est fait :wink:

Nouvelle version de la carte !

Si vous avez des commentaires...

groupe2-schema-v3.0.pdf (91.5 KB)

groupe2.svg|0x0

bricofoy:
Nouvelle version de la carte !

Si vous avez des commentaires...

je suppose que tu es content d'avoir bien mené ton projet au bout ?
c'est une belle démonstration des difficultés qui apparaissent entre l'idée posée sur la page blanche et la réalisation fonctionnelle ET validée :grin:

ben pour l'instant, je sais pas si on peut considérer que c'est "mené au bout" :stuck_out_tongue: j'ai certes un groupe qui tourne, mais je suis encore en train de redessiner la carte, pour palier aux insuffisances des deux premières versions (dont la deuxième n'a d'ailleurs jamais été montée ! ).
En particulier avec la découverte sur ebay de capteurs de proximité à 4€, je remplace la détection du démarrage moteur par une mesure de vitesse de rotation, ce qui va éviter de limer le pignon du démarreur contre la couronne pendant toute la phase d'accélération du moteur.
J'ai aussi rajouté une sortie pour contrôler un relais qui coupe la sortie de la génératrice, afin de laisser au moteur le temps de refroidir avant de le couper (ça m'a coûté une culasse, quand même, la coupure moteur en charge)

Avis aux amateurs ! j'ai donc à dispositions deux cartes à base d'ATMEGA328, une qui est littéralement un shield pour une nano (celle qui est en usage actuellement), et une à base de 328P (boitier DIL). Ces deux cartes comportent chacune 5 relais dont 4 utilisables directement, et deux sorties collecteur ouvert (2N2222) (3 pour la seconde), ainsi que 4 entrées analogiques.

Ces deux cartes ne me servirons plus dès que la V3 sera opérationnelle, si ça intéresse qqn, je les fais à prix coûtant :wink:

Nouvelle version de la carte (V3.0) en cours de finalisation :

je dois dire que je suis assez content de ma sérigraphie maison :slight_smile:

Ça progresse : y'a des composants et des trucs qui s'allument ! :slight_smile:

Bon alors voila, pour détecter la rotation du moteur, j'ai rajouté un capteur de proximité qui compte les dents du ventilateur du moteur.

le nouveau scema de la carte V3.0 est le suivant :

J'ai connecté ce capteur sur l'entrée INT1 (pin D03), ma fonction associée à l'interruption mesure la période entre plusieurs tops et compte ces tops. Ensuite j'ai une fonction qui est appelée dans la boucle principale, qui calcule la vitesse de rotation du moteur à partir de cette période et du nombre de tops comptés.

unsigned int rpm_moteur; 	//vitesse de rotation moteur.

//variables utilisees en interruption (volatile = stockees en RAM)
volatile unsigned int rpm_cpt;                     //compteur de passage en interruption. Pour savoir cb de périodes sont utilisées pour le calcul de F
volatile unsigned long rpm_periode;                //periode des implulsion du capteur de rotation
volatile unsigned long rpm_tprecedent,rpm_tcourant;//temps utilisés pour calculer la période

void setup()
{
(...)
attachInterrupt(1, comptetour, RISING);	//entree rotation moteur sur INT1
(...)
}

void calcule_rpm() {
  //calcul de la vitesse de rotation du moteur.
  
  //on calcule la fréquence avec 1*60*1000/période car la période est en ms (*1000), et que l'on veut la fréquence en tr/min et non en Hz ou tr/s (*60)
  //on divise ensuite le total par le nombre de dents comptées par le capteur sur 1 tour moteur
  //la periode est une moyenne des rpm_cpt periodes mesurees en interruption avant passage par ici
  
  //Serial.print(rpm_cpt);
  //Serial.println(" ");  
  if (rpm_cpt) {
    rpm_moteur = (unsigned int)(60000/(rpm_periode/rpm_cpt))/nbr_dents_capteur_rota;
    rpm_cpt = 0; 			//remise à zero du compteur pour les prochaines mesures
    rpm_periode = 0;			//idem pour la periode
  }
  else if (rpm_tcourant<(temps_courant-300))
	rpm_moteur = 0;			//si pas de nouvelle mesure pdt plus de 300ms, alors le moteur est à l'arret ou le capteur est HS
					//300ms de période correspond à 22trs minutes si nbr_dents_capteur_rota=9
  //Serial.print(rpm_moteur);
  //Serial.print(" ");
  
}	

void comptetour(void) {
  //passage ici en interruption à chaque top capteur de vitesse. 
  //On stocke juste la somme des période des impulsions, et un compteur du nombre de périodes additionnées  
  rpm_tprecedent = rpm_tcourant;
  rpm_tcourant = millis();
  rpm_cpt++;
  rpm_periode += (rpm_tcourant-rpm_tprecedent);  
}

le code complet est ici : http://sourceforge.net/p/groupe/code/ci/31e71b1ae87b4828ae862ed18880018b4c217bed/tree/groupe.ino

Tout ça fonctionne très bien, du moins tant que le système est en veille (machine à état en état et_attente).

En revanche, dès que je demande un démarrage du moteur, on dirais que le passage en interruption ne se fait plus. Je passe bien dans la fonction de calcul de vitesse à chaque boucle, comme en attestent les serial.print que j'ai collé dedans, mais le nombre de tops comptés est toujours 0, quelle que soit la fréquence des impulsions en entrée, ce qui semble vouloir dire que je ne passe pas dans l'interruption.

Le pire, c'est que une fois la séquence de démarrage (ratée !) finie, quand la machine à état repasse en attente, ben ça remarche.... arghhhh !

Qu'est-ce qui peut me bloquer l'interruption ? J'avoue que je m'arrache les cheveux, je sent bien que ça doit être une connerie énorme, mais j'y suis depuis 3h et je trouve pas...

bricofoy:
Bon alors voila, pour détecter la rotation du moteur, j'ai rajouté un capteur de proximité qui compte les dents du ventilateur du moteur.

...
Qu'est-ce qui peut me bloquer l'interruption ? J'avoue que je m'arrache les cheveux, je sent bien que ça doit être une connerie énorme, mais j'y suis depuis 3h et je trouve pas...

Bonjour bricofoy
je ne suis pas un specialiste des interruptions, mais j'ai joué avec il n'y a pas longtemps
voir ici
http://forum.arduino.cc/index.php?topic=165087.msg1236504#msg1236504

suggestion : une fois en marche ton code ne voit plus jamais de rising ? (trop rapide ?)
juste pour test ça donne quoi avec change au lieu de rising , "une dent et un creux" c'est 3 "change"

alors en fait, c'est plus merdique que ça ! là j'attaque l'entrée avec un signal carré à 100Hz, ce qui devrait me donner une valeur de rpm à environ 667 trs/min, et en fait j'ai une valeur qui oscille entre zéro et 416 avec de temps en temps des pics à 7000, enfin bref c'est totalement n'importe-quoi.

donc en fait la fonction de calcul ou ma fonction de mesure ne marchent pas.

trop rapide, non, certainement pas, grand maximum mon entrée sera à 500Hz ça ne devrait pas poser trop de soucis...

bricofoy:
alors en fait, c'est plus merdique que ça ! là j'attaque l'entrée avec un signal carré à 100Hz, ce qui devrait me donner une valeur de rpm à environ 667 trs/min, et en fait j'ai une valeur qui oscille entre zéro et 416 avec de temps en temps des pics à 7000, enfin bref c'est totalement n'importe-quoi.

donc en fait la fonction de calcul ou ma fonction de mesure ne marchent pas.

trop rapide, non, certainement pas, grand maximum mon entrée sera à 500Hz ça ne devrait pas poser trop de soucis...

ça depend du temps que tu consomme en phase d'interruption
pour ne rien louper j'ai du deriver le calcul et me contenter de renseigner simplement un tableau (voir code commenté)
mais ceci n'est peut etre pas exploitable dans tons cas

Est-ce que tu es sûr que c'est software ? Est-ce que le code que tu post ici est juste un résumé du code qui est réellement exécuté ou bien ce code ci te pose réellement problème ?

ben justement, j'ai essayé d'en faire le moins possible en interruption, regarde la fonction void comptetour() elle est réduite à sa plus simple expression..

bon en fait, le calcul marche, c'est mon entrée qui merdait (tension de sortie du gbf intégré au DSO Quad trop basse ! j'ai bricolé un ampli et ça marche, j'ai bien mes 666 trs/min (avec de temps en temps un pic à 740, donc il reste un bug que je n'ai absolument aucune espèce d'idée de la manière de la trouver ! )

par contre je retrouve mon comportement du début : dès que l'état de la machine change, je mesure 0 !! donc c'est que ça ne passe plus en interruption...

B@tto:
Est-ce que tu es sûr que c'est software ? Est-ce que le code que tu post ici est juste un résumé du code qui est réellement exécuté ou bien ce code ci te pose réellement problème ?

je croyais être sûr que c'était un soucis soft (en tout cas il y en a un : les pics à 740tr/min) mais à vrai dire je ne suis plus sûr de rien, là :confused:

le code est bien un résumé du code actuellement executé par l'atmega

ARGHHH en fait quand j'ai les relais qui s'activent, l'alim baisse avec la conso des bobines, et les créneaux en sortie du pont diviseur R37/R32 sont trop bas (3,08V crète) et l'atmega ne les détecte plus !! en remontant l'alim, ça fonctionne... Pourtant d'après la donc de l'atméga, il me semblait qu'un niveau haut était pris en compte à partir d'une tension bien plus faible que ça ??

le schéma est là : http://sourceforge.net/p/groupe/code/ci/capteur_rota/tree/kicad/groupe2/groupe2.pdf?format=raw

Je vais modifier mon entrée, le pont diviseur foire, manifestement. Si d'ailleurs vous avez une idée à me suggérer ? par exemple ne pas faire un pont diviseur mais limiter la tension d'entrée avec une zéner ?

Le capteur que j'utilise fonctionne en 12V, avec une sortie collecteur ouvert PNP, d'où ce pont diviseur pour ne pas cramer l'entrée de l'atmega avec des pulse en 12V

bricofoy:
Je vais modifier mon entrée, le pont diviseur foire, manifestement. Si d'ailleurs vous avez une idée à me suggérer ? par exemple ne pas faire un pont diviseur mais limiter la tension d'entrée avec une zéner ?

Le capteur que j'utilise fonctionne en 12V, avec une sortie collecteur ouvert PNP, d'où ce pont diviseur pour ne pas cramer l'entrée de l'atmega avec des pulse en 12V

J'avais demerdé un probleme du genre capricieux comme le tiens Vin 12 ---> Vcommut 5V
si les temps de recouvrement sont acceptable , essaye un petit 78L05 comme regulateur du signal d'entrée , (ne pas oublier de tirer un peu dessus )
ce n'est pas à priori fait pour, mais si F° est faible ça peut etre une bonne solution "à pas cher" 8)

Artouste:
Bonjour bricofoy
je ne suis pas un specialiste des interruptions, mais j'ai joué avec il n'y a pas longtemps
voir ici
projet inutile donc absolument necessaire - #16 by Artouste - Français - Arduino Forum

suggestion : une fois en marche ton code ne voit plus jamais de rising ? (trop rapide ?)
juste pour test ça donne quoi avec change au lieu de rising , "une dent et un creux" c'est 3 "change"

je vois que tu stockes les valeurs dans un tableau, au lieu de les additionner comme moi. C'est plus rapide ainsi ?

Dans mon cas, en faisant des print avec la valeur du compteur, je constate qu'elle est majoritairement à 1 et n'a jamais dépassé 3, donc finlement le reste du code (machine à état, entrées/sorties, liaison série) que je pensais assez lent s'execute en fait assez rapidement.

Je n'ai aucun idée en revanche de la manière de débugger mon erreur occasionelle avec le pic à 740 au lieu des 666 theoriques...
En fait la seule explication que je vois à cette erreur c'est un passage en interruption avant la fin du traitement de la fonction calcule_rpm(), auquel cas j'ai alors un calcul fait avec une valeur de compteur erronée car elle n'a pas eu le temps d'être remise à zéro.
Peut-être que je devrait faire un detachInterrupt() a l'entrée dans la fonction, et à nouveau attachInterrup() à sa sortie ? ainsi je risque de rater un ou deux pulse, mais au moins e calcul restera juste avec les suivants ?

bricofoy:
...

  • je vois que tu stockes les valeurs dans un tableau, au lieu de les additionner comme moi. C'est plus rapide ainsi ?
    ...

  • Peut-être que je devrait faire un detachInterrupt() a l'entrée dans la fonction, et à nouveau attachInterrup() à sa sortie ? ainsi je risque de rater un ou deux pulse, mais au moins e calcul restera juste avec les suivants ?

  • Dans mon cas : je sais +/- quel est le temps d'amortissement (nombre de secteurs parcourus) pour tendre à Vitesse=0
    c'etait dans le but d'une collecte statistique
    c'est la methode d'acquisition la plus efficace que j'avais trouvé (tout ce qui est traité dans l'interrupt consomme du temps)

  • comme je l'ai expliqué , je ne suis pas assez pointu sur ce domaine , mais ça semble une bonne voie pour "calibrer une fenetre de tir" 8)