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

ok, bon avec la mesure de période en µs avec micros(), ça fonctionne très bien jusqu'a 1kHz, soit le double de la vitesse maxi du moteur, j'ai donc de la marge :slight_smile:

reste à modifier le câblage de mon entrée, et là par contre c'est merdique, car la tension batterie peut varier de 14,5V (en fonctionnement, alternateur en charge) à moins de 7V (démarreur en fonction par temps froid). Et la tension ne doit pas descendre en sortie de pont en dessous de 3,1V... ce qui n'est pas possible pour ne pas non plus dépasser 5,5V !
Donc j'hésite entre laisser le pont, calibré pour arriver à 3,5V avec 7V en entrée, et utiliser les diodes internes à l'atmega pour limiter le voltage lorsque la Ubat remonte, ou remplacer R37 par une zener à 5V.
La zener est-elle préférable ? j'ai lu un peu tout et son contraire dans les topics parlant de limiter une tension d'entrée par une zener...

bricofoy:
ok, bon avec la mesure de période en µs avec micros(), ça fonctionne très bien jusqu'a 1kHz, soit le double de la vitesse maxi du moteur, j'ai donc de la marge :slight_smile:

reste à modifier le câblage de mon entrée, et là par contre c'est merdique, car la tension batterie peut varier de 14,5V (en fonctionnement, alternateur en charge) à moins de 7V (démarreur en fonction par temps froid). Et la tension ne doit pas descendre en sortie de pont en dessous de 3,1V... ce qui n'est pas possible pour ne pas non plus dépasser 5,5V !
Donc j'hésite entre laisser le pont, calibré pour arriver à 3,5V avec 7V en entrée, et utiliser les diodes internes à l'atmega pour limiter le voltage lorsque la Ubat remonte, ou remplacer R37 par une zener à 5V.
La zener est-elle préférable ? j'ai lu un peu tout et son contraire dans les topics parlant de limiter une tension d'entrée par une zener...

tu n'a pas un 78L05 (ou meme un 7805) pour tester l'entrée comme je l'ai proposé plus haut ?
http://forum.arduino.cc/index.php?topic=125887.msg1302300#msg1302300
ça procure une large fourchette de tension en entrée, ça coute 20cts et en TO92 ce n'est pas compliqué à implanter

La zener ou la diode interne devrait parfaitement faire l'affaire

Artouste:
tu n'a pas un 78L05 (ou meme un 7805) pour tester l'entrée comme je l'ai proposé plus haut ?
Commande automatique de groupe électrogène - machine à états et autres questions - #115 by Artouste - Réalisations et Projets Finis - Arduino Forum
ça procure une large fourchette de tension en entrée, ça coute 20cts et en TO92 ce n'est pas compliqué à implanter

à 500Hz ? je doute fort que ça fonctionne... mais ça mériterait de le tester :slight_smile: mais pour le greffer sur le carte, c'est pas des plus simple. Je vais déja tester avec une zener car ça c'est facile j'ai juste à la mettre à la place de la R37 du pont

Hmmm pour moi les erreurs de calcul de RPM que tu observes (valeurs erronees et valeurs a zero) sont probablement dues a un probleme d'exclusion mutuelle.

Le code qui execute en interruption et le code qui execute dans la boucle principale operent sur des variables communes. Ceci n'est pas un probleme jusqu'au moment ou les variables sont assignees, par chaque morceau de code. Les 2 codes executent concouramment, creant une condition de course.
Ces conditions peuvent etre intermittentes ou tres frequentes, et ce qui est interessant est qu'elles apparaissent et disparaissent en function de la charge du microcontroller.

En bref, si chaque partie du code doit assigner des variables partagees, il doit y avoir un moyen d'assurer que les variables ne sont pas assignees concouramment. La solution la plus facile est d'inhiber les interruptions depuis le code principal (loop) lorsque les variables partagees sont assignees. Ceci cree une section de code critique.

Dans tous les comptes tours a base d'interruptions sur lesquels j'ai travaille il fallait creer une section de code critique.

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.

le nouveau scema de la carte V3.0 est le suivant :
http://sourceforge.net/p/groupe/code/ci/capteur_rota/tree/kicad/groupe2/groupe2.pdf?format=raw

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 1601000/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...

ciel ! bonjour JS, tu t'es perdu sur ce forum dédié aux "microcontrolleurs d'en bas" ? :slight_smile: je serai ravi de profiter de ton expérience en la matière en tout cas :slight_smile: :slight_smile:

merci pour ta réponse. en effet, j'avais pensé à désactiver l'interruption le temps de calculer la vitesse. Et à vrai dire, je ne sais plus pourquoi je ne l'ai pas fait.
Quoi qu'il en soit, les soucis d'erreurs de mesure énormes du début étaient liés à un bête soucis de tension d'entrée trop basse, à cause d'un pont diviseur foireux. Là ça fonctionne, j'ai toujours des erreurs de temps en temps, mais minimes (de l'ordre de 50à100tr/min) et qui ne gênent en rien le fonctionnement normal, vu que ce n'est pas l'atmega qui fait la régulation de vitesse.

D'ailleurs je viens tout juste de rentrer de l'installation du premier groupe avec cette version du matériel, et quelques correction du soft sur place (parceque forcément, si on part installer un matériel testé, c'est beaucoup moins drôle :blush: ) avec un nuit blanche à la clef, mais ça fonctionne.
En plus, aller travailler à 1850m d'altitude dans la montagne, c'est la classe 8) dommage que je n'ai pas eu le temps d'aller aux champignons =(

La dernière version (qui marche) de la carte et du soft son disponible ici :
http://sourceforge.net/p/groupe/code/ci/capteur_rota/tarball

Attention toutefois pour la carte, il faut remplacer deux résistances dans les ponts diviseurs des entrées d'interruption par des zeners à 4,6V, je n'ai pas eu le temps de modifier les fichiers kicad.

la carte V3 en place sur le groupe :

un peu de déboggage sur place après une nuit blanche, parceque sinon c'est pas sport :

pas mal la vue depuis la fenetre du bureau quand même !

et finalement la bête à sa place :

Ahah, j'ai achete une Arduino Uno il y a 2 jours (ma premiere :blush:). Je mettrai des photos du projet sur Facebook la semaine prochaine. Je me suis apercu un peu tard que j'avais besoin d'une carte microcontrolleur pour les vacances, pas le temps d'en construire une. Arduino c'est bien parce qu'il y a beaucoup de code et de shields disponibles. Par contre, quelle perte de temps sans debugguer et programmeur!
Je serais ravis d'aider, envois moi du code a developer ou une carte a construire. En ce moment je suis un peu a cours d'idees pour des projets personnels. Mon nouveau constructeur de cartes les livres en violet ::love::, ca rajoutera de la gaiete dans cette boite grise!

Quel est le but de ce controleur de ce groupe electrogene? Demarrer quand le systeme solaire a epuise toutes ses reserves?
C'est marrant parce qu'au travail on a achete un petit generateur diesel de chez Caterpillar (18kW) pour un des projets de recherche. On le controle par Modbus. On l'a un peu modifie pour verifier l'efficacite, on a rajoute des capteurs de debit d'essence etc. Avant de travailler sur ce projet, je ne savais pas que la plupart des reserves indiennes au nord de Winnipeg utilisent des generateurs diesel. La plupart de ce generateurs marchent en paires, un supporte la charge du reseau, l'autre tourne au ralenti, en standby au cas ou le generateur principal tombe en panne. Aussi, la plupart de ces generateurs tournent a regime constant, ce qui fait que tu peux te retrouver avec trop d'energie si la demande du reseau est trop basse. Donc a present ces generateurs peuvent mieux faire.
Donc on a monte un projet de recherche et on s'amuse avec ce generateur, on fait tourner different scenario, estime lequel conserve le plus de diesel, compare avec des simulation etc.

Meme si le compte tour semble marcher maintenant je pense que c'est dans ton interet d'ajouter une section de code critique quand les variables partagees sont assignees dans le code principal.

Est ce que tu as un port de debuggage ou de telemetrie sur cette carte? Type OBD? Bluetooth ou WIFI ::love::. Il manque un LCD d'une vielle imprimante dans ton design!

Combien de place est ce qu'il te reste sur ce microcontrolleur? Une chose qui me frustre un peu avec l'Arduino que j'ai eu, c'est le manque de flash. C'est facile de s'habituer a des micros avec 512k de flash et 64k de RAM.

bricofoy:
ciel ! bonjour JS, tu t'es perdu sur ce forum dédié aux "microcontrolleurs d'en bas" ? :slight_smile: je serai ravi de profiter de ton expérience en la matière en tout cas :slight_smile: :slight_smile:

merci pour ta réponse. en effet, j'avais pensé à désactiver l'interruption le temps de calculer la vitesse. Et à vrai dire, je ne sais plus pourquoi je ne l'ai pas fait.
Quoi qu'il en soit, les soucis d'erreurs de mesure énormes du début étaient liés à un bête soucis de tension d'entrée trop basse, à cause d'un pont diviseur foireux. Là ça fonctionne, j'ai toujours des erreurs de temps en temps, mais minimes (de l'ordre de 50à100tr/min) et qui ne gênent en rien le fonctionnement normal, vu que ce n'est pas l'atmega qui fait la régulation de vitesse.

D'ailleurs je viens tout juste de rentrer de l'installation du premier groupe avec cette version du matériel, et quelques correction du soft sur place (parceque forcément, si on part installer un matériel testé, c'est beaucoup moins drôle :blush: ) avec un nuit blanche à la clef, mais ça fonctionne.
En plus, aller travailler à 1850m d'altitude dans la montagne, c'est la classe 8) dommage que je n'ai pas eu le temps d'aller aux champignons =(

La dernière version (qui marche) de la carte et du soft son disponible ici :
groupe / Git / Commit [c2ef5b]

Attention toutefois pour la carte, il faut remplacer deux résistances dans les ponts diviseurs des entrées d'interruption par des zeners à 4,6V, je n'ai pas eu le temps de modifier les fichiers kicad.

la carte V3 en place sur le groupe :

un peu de déboggage sur place après une nuit blanche, parceque sinon c'est pas sport :

pas mal la vue depuis la fenetre du bureau quand même !

et finalement la bête à sa place :

Alors ici, j'ai de disponible sur la carte V3 un port I2C et un port 1-Wire, avec pour but de rajouter des capteurs de températures (1-Wire) pour déterminer si il y a besoin ou pas de préchauffage, et pour adapter les temps de chauffage/refroidissement du moteur.
Et via i2c pour rajouter un afficheur, une horloge pour permettre de programmer des horaires, un datalogger sur carte SD (par exemple un openlog trafiqué pour logger en i2c), etc etc

J'ai aussi une autre entrée interruption inutilisée pour le moment prévue pour mettre une jauge capacitive dans le réservoir.

mais avec 32k de dispo, et un environnement de devel pas spécialement optimisé, c'est un peu tendu. Pour le moment mon code qui ne fait pas grand chose utilise déjà 19k.

pas de port SPI sur ma carte qui permettrait de faire du vrai debug, car l'ai eu besoin des bits pour commander les relais.

pour résumer, la carte V3 a donc :
-port série
-port I2C
-port 1-Wire
-2entrées interruption (une pour le compte-tours, une pour la jauge)
-3entrées logiques (contact de démarrage local, externe, et pression d'huile)
-1entrées analogique (mesure de la tension batterie)
-3sorties relais 25A (contact, préchauffage, démarreur)
-1sortie relais ou PWM avec un PMOS (pour piloter un solénoide de controle du régime)
-3sorties collecteur ouvert NPN (2 pour les leds d'état, 1 pour le relais qui coupe la sortie de la génératrice)
-1relais interne qui assure l'auto-maintien de l'alim de la carte

L'objectif ici est pour le moment d'assurer uniquement la gestion du moteur de la manière la plus automatique possible pour que l'utilisateur n'ait rien à faire. C'est l'onduleur du système solaire qui lui détermine si il y a besoin de recharger les batteries avec le groupe ou non et demande le démarrage (contact sec).
Il peut également demander le soutien du groupe en cas de surcharge ou de surchauffe.
Mais je songe à faire une seconde carte qui s'occupera de la gestion de la charge des batteries, car les possibilités de paramétrage offertes par l'onduleur sont assez limitées.

voila voila

bricofoy:
... et un port 1-Wire, avec pour but de rajouter des capteurs de températures (1-Wire) pour déterminer si il y a besoin ou pas de préchauffage, et pour adapter les temps de chauffage/refroidissement du moteur.
...

bonjour bricofoy
comme tu semble etre en environnement certes bucolique :grin: mais de moyenne montagne, je te conseillerais d'utiliser comme capteur de T° 1W un DS1920 (DS1820 en boitier microcan inox )
si tu en veux un pour test, ----> MP

en fait j'ai des 1820 montés dans des petits tubes inox étanches, avec un fil de 2m. c'est je trouve bien plus pratique à utiliser que le boitier des 1920. Mais je te remercie pour ta proposition :slight_smile:

Mais en fait je suis en train de me dire que le capteur maxim, ça va pas le faire, car il est limité à 100°, et si je colle le machin sur le moteur, il va cramer assez rapidement... je vais plutot voir pour utiliser une PT100 ou un thermocouple avec un circuit I2C qui va bien, peut-être.
Au pire le port 1-Wire, si il ne me sert pas ça me fera toujours une I/O pour faire autrechose.

bricofoy:
Mais en fait je suis en train de me dire que le capteur maxim, ça va pas le faire, car il est limité à 100°, et si je colle le machin sur le moteur, il va cramer assez rapidement... je vais plutot voir pour utiliser une PT100 ou un thermocouple avec un circuit I2C qui va bien, peut-être.
Au pire le port 1-Wire, si il ne me sert pas ça me fera toujours une I/O pour faire autrechose.

bonjour bricofoy
c'est sur que si la T° à verifier flirte au dessus des 120° C , les 1820 ou autres capteurs "actifs" sont hors concours
les thermocouples ou PT100(0) deviennent alors un choix quasi obligés.
ceci etant une CTN "haute temperature" si la T° ne dépasse pas 300° C peut être une bonne alternative si il te reste un port ana (cout, facilité d’intégration)

non, je n'ai plus de dispo que la pin digitale prévue pour le bus 1-Wire, et les deux analogiques pour l'I2C, mais comme je veux garder l'i2C pour pouvoir rajouter un LCD et un module RTC... ben voila.

Bonjour à tous

Ce projet n'est pas mort, contrairement à ce qu'on aurait pu croire :smiley:

Je suis en train de créer une nouvelle librairie de création de machines à états simple, basée sur les pointeurs de fonction.
Celles existantes que j'ai trouvé étant inutilement complexes à mon sens. Et une fois ça fini, je vais recoder tout le projet avec cette nouvelle lib. histoire de nettoyer un peu mon bazard car là c'est immonde.

Pour le moment il me manque encore quelques fonctions utiles, je devrais avoir tout ça qui fonctionne demain...

Mais cette version est déjà tout à fait fonctionnelle. Il me manque juste des timers en fait.
Si des gourous de la MAE veulent bien y jeter un oeil pour mettre le doigt là où ça ne devrait pas manquer de faire mal...

YASM.zip (1.22 KB)

Bonjour,

Je viens de regarder le code de ta classe YASM.
C'est simple et clair.
J'utilise très souvent les MAE (FSM en Anglais) de manière artisanale avec des "switch case" pour les états et "millis()" pour gérer le temps.
Je ne sais pas si utiliser les timers apportera de la clarté au code.
Par contre un tableau de pointeurs sur des propriétés, permettrait de diminuer, voire éliminer les variables globales que l'on utilise pour gérer les transitions d'état.
Je ne sais pas si je me fais bien comprendre; les variables "i" et "j" de ton exemple.

Bon, après 36h de codage non-stop (et un rendez-vous raté pour installer le résultat ce matin...), je crois que même l'atmega devient philosophe :

bon finalement la machin est installé, et tout a marche du premier coup ! Incroyable, c'est la première fois que je ne suis pas obligé de sortir l'ordi pour régler les bugs de dernière minute chez le client... Comme quoi une bonne MAE bien cadrée dans une classe propre, ça marche mieux qu'un bricolage de switch/case pleines de sous-états dans les états :stuck_out_tongue: et en plus finalement ça prends moins de place en mémoire de l'arduino !

Du coup dans la foulée on en a installé un second, mais avec une vielle carte remise au goût du jour avec l'ajout de l'afficheur un peu à l'arrache avec le bus I2C soudé direct sur les pins de l'atmega avec du fil à wrapper. Bon c'est sûr si le client ouvre la boite, c'est pas idéal, mais ça fonctionne en un temps record :slight_smile: