Autres Realisation d'un system de filetage par µC

  • Auteur de la discussion simon74
  • Date de début
S

simon74

Compagnon
J'avait commencé cela en MP avec @vibram, mais je pense que ça peut être intéressant pour un public plus large, donc je le publie directement en fil séparé.

Je m'excuse d'avance pour des fautes d'orthographe et surtout de grammaire, ainsi que des éventuels anglicismes. Je suis ce que je suis.

On va parler du programmation d'un système de filetage pour tours pas équipées de vis mère, utilisant les uC STM32, particulièrement les STM32F103 trouvable sous le nom de "Blue Pill", "Maple Mini" ect. Je ne parlerai pas de Arduino, même si, d'un façon non-officiel, y a du
support pour ces cartes sur Arduino (gogol pour STM32Duino). Les exemples en C sera centre atour le HAL de ST Microsystems et non pas
autour de Arduino - par contre, ça sera probablement possible de les convertir en libraire Arduino. On risque même d'avoir des exemple en Forth ou Scheme.

Ceci ne sera pas un truc "clefs en main", ce n'est pas mon truc. Ca resterai plus un explication de façon d'approcher un problème. "Cut and paste" n'est pas mon truc non plus, je déconseille fortement de le faire. Franchement, même le code ne sera pas un but, (ce qui fait que le "réalisation" dans le titre de ce fil soit peut-être exagéré) c'est plus un explication des décisions que je prendrai en développant un système de ce type.

En "conceptuel" de l'informatique, y en a pas une seule façon de faire les choses correctement, mais plein de façons de faire incorrectement. Ceci sera un explication de ce que je considère être un des façons de faire, en espérant que ça sera aussi "correcte".

Pour suivre, il en faut quelques trucs. Déjà, il en faut RM0008 de chez ST, la manuel de référence de ces processeurs. Mon copie est version 13, de 2011, autres versions peut être different en nombre de page, ect. A cote de ça, il sera probablement bien d'en avoir le code du HAL, comme référence (par exemple, ici https://github.com/rpavlik/xpacks-stm32f1-hal)

Si le manque d'Arduino gêne (et j'espère que ça ne sera pas le cas), je laisse des modos trancher. Je ne veut surtout pas créer de polémique, et je demanderai même d'avoir des messages de ce type consigné a la bac a copeaux.
 
Dernière édition:
G

Guy69

Compagnon
Ca roule Simon, très bonne introduction, on t'écoute :)
Perso je n'ai pas de µC STM mais ça ne fait rien, c'est toujours instructif.
Au plaisir de te lire
Cordialement
Guy
 
S

simon74

Compagnon
Descriptif Generale

On va parler d'une système avec un codeur sur un broche tournant, un moteur pas a pas qui tournerai une vis mère (qui pourrait être une vis mère séparé, le vis d'un chariot, ou autre), quelques boutons ou autre inputs, et éventuellement un écran LCD.

Le but sera de faire tourner la vis mère a la bonne vitesse par rapport a vitesse de la broche pour que un outil pousse par ce vis dessine un pas de vis sur la pièce tenu sur / dans la broche. On doit avoir la possibilité de définir le pas de ce vis, ainsi que sa longueur.

En termes de matériel, mon ami @vibram est équipé de:
  • Carte embarque stm32f103 "blue pill"
  • Un codeur qui génère du quadrature.
  • Moteur PaP avec driver avec deux entrées - "direction" et "step"
  • Quelques boutons
  • Un écran LCD, qui sera géré par un libraire existant.
Pour ma réalisation perso, j'ai plus ou moins la même, mais mes drivers PaP sont a 4 entrées (les H-bridge de base), et nécessite la génération des signaux de commande "low level" des moteurs, mais la problème est plus ou moins la même. On discutera des deux.
 
G

Guy69

Compagnon
yes!
C'est le même cahier des charges que celui de ma petite bobineuse (codeur sur broche, entrainement du guide-fil en fonction de paramètres saisis par bouton rotatif et affichage LCD).
Je pense qu'on sera plusieurs à suivre ton fil
Cordialement
Guy
 
M

metalux

Compagnon
Bonjour
Je m'excuse d'avance pour des fautes d'orthographe et surtout de grammaire, ainsi que des éventuels anglicismes. Je suis ce que je suis.

ne t'excuses pas il y a bien pire que toi ! :roll:

clair net et précis :smt023 on attend la suite avec impatience
 
S

simon74

Compagnon
Quelques Concepts de Base

(ou, «la ou ça risque de froisser quelques uns»)

Il ne faut pas oublier qu'on vas créer une système de contrôle "real time"; une fois attelée sur un tour de type schaublin les erreurs peut entrainer les dégâts très lourds, dangereux pour l'opérateur, et très cher a réparer. Ce n'est pas notre bon vieux Microsoft Windows, "turn it off and turn it on
again". On n'as pas le droit de louper des signaux de commande, ni de se tromper dans les signaux de commande. Notre programme doit être
solide, correct. Parfait n'existe pas, mais faut s'y approcher.

En programmation, peu importe la langue utilise ou la plate-forme ciblée, on produit en moyen 1 erreur tous les 10 lignes de code. Nous,
les programmeurs, va te dire que non, mais on sur-estime quotidiennement nos capacités - en réalité on est tous touche par ce "règle". Donc 10x moins de code écrit, c'est 10x moins d'erreurs a corriger.

Réduire les lignes de code, réduit aussi (en général) le temps d'exécution de ce code. Surtout dans les parties de code critique a l'interception et action sur les signaux de commande, la vitesse d'exécution c'est d'un importance capital.

Moins de code, c'est aussi un program moins "lourd" en taille, important sur un microcontroleur avec des capacités assez restreints.

Ca a été dit ailleurs, que il ne faut pas tripoter avec des valeurs de type "float". Mais la raison cité était, pour moi, complètement fausse. On n'est plus a l'épopée des processeurs 8-bit tel que les 8051 (perso, j'ai commence sur les 4040 et 6502 dans les années '80) ou les floats étaient énormément difficile et impensable, voir impossible, a utiliser. Maintenant ils existants, "bonne marche", des uCs avec unité FP, séparé du processeur proprement dit, pour lesquels les floats sont plus vite calcule que les integers. Ce n'est pas le cas pour les STM32F1xx, mais les STM32F4xx... La problème avec les floats en ça cas particulier est l'exactitude. Y a beaucoup de matière traitent ce sujet, mais suffit de dire que les valeurs float ne sont rarement exactes, et les comparaisons directes de style produise souvent les résultats peu attendus, c'est a dire false.

Pour éviter tout cela, les mathématiques on va utiliser tournent autour des rapports - vitesse broche vs vitesse vis mère, ect, et peut (pour ne pas dire
"doit") être représenté d'un façon exacte comme le rapport entre deux nombres intégrales. Faut comprendre que cela est dictée par les nécessités et spécificités de l'application et pas par raison de performance. Y en a des applications, même en embarqué, ou l'utilisation des floats sera tout a fait justifié.
 
V

vibram

Compagnon
Bien sur que je vais suivre :wink:

Je pense avoir trouvé un moyen avec mon code existant de retomber dans le pas donc je vais continuer ma manière mais quoi qu'il arrive j'ai hâte de voir une manière plus propre qui est la tienne :)
 
S

simon74

Compagnon
La continuation va attendre un peu, j'ai les parents qui sont a la maison.
 
S

simon74

Compagnon
Quelques Contraintes Physiques

Ce système as, quand même, une partie physique, et les contraintes de ce partie "hardware" ont des implications pour la partie "software".

Ca sera facile a considérer que les longueurs de filetage a faire peut être traite uniquement par le program. Ca sera, selon moi, un erreur assez grave. Tout erreur de code, tout signal manque, tout impulsion loupé par le moteur PaP, peut entrainer un filetage "bourré", ce qui peut entrainer un "crash" de l'outil, et des dégâts matériels. Pour moi, les butées doit être physique, ce qui va dire butées de début et fin de filetages, ainsi que (éventuellement) fin de course de vis mère.

J'ai mentionné les "pas manquées". Les moteurs PaP ne sont pas, malgré leurs apparences, garanti de faire un pas chaque fois ils recevants l'impulsion correct. Ils ont des vitesses maximales qui ne peut être dépassé, et bien sur ils ont de l'inertie, ce qui implique des courbes d'accélération et décélération - on doit suivre ces courbes pour éviter les "pas manquées". Ils ont aussi un couple limité, qui peut occasionner le manque d'un, plusieurs, ou même tous les commandes envoyées. Si on veut traiter les PaP comme des accessoires "fire and forget", sans avoir besoin d'un codeur supplémentaire sur la vis mère, il faut bien gérer notre tir, et bien choisir notre matériel. On en parlera plus quand on traite la génération des signaux de pas.

Le course des chariots Schaublin (ou autres de ce type) étant assez limite, il sera bien de pouvoir faire un repérage de pas "manuel" en cas de filetage longue nécessitant le déplacement de chariot. Mais cela implique une autre problème, celle du commander la sorti d'outil de la pièce en milieu de filetage, donc je vais, pour l'instant, consigner cette idée a la poubelle.
 
S

simon74

Compagnon
C'est le même cahier des charges que celui de ma petite bobineuse
Tout a fait - ce style de conception n'est pas limité aux filetages, et les contraintes sont les memes; j'espere rester assez generale pour que ca soit interessant pour tout le monde.
Je pense avoir trouvé un moyen avec mon code existant de retomber dans le pas
C'est tres bien, cette probleme n'est pas anodyne.
j'ai hâte de voir une manière plus propre qui est la tienne
Comme j'ai dit, y en a pas une seule facon "correcte" de faire :)
 
V

vres

Compagnon
Il ne faut jamais utiliser == pour comparer des flottants c,est une évidence, perso j'ai une fonction quasiegal avec une tolerance.
Pourquoi faire plusieurs plusieurs projets individuels et pas un seul projet collaboratif?
 
S

simon74

Compagnon
Un dessin de système plus concret.

Arrivé a ce point, on peut définir plus concretement le structure du logiciel, au moins sa partie "controle".

On as, comme entrees :

  • Une commande «Go!» qui va demarrer l'application
  • Plusiers commandes «Stop!» (bouton d'arrêt, butées fin de courses) qui vont entrainer l'arret anticipé de l'application
  • Un (ou des) butée(s) de fin de filetage
  • Un codeur de broche
  • Eventuellement un codeur de vis mère
Les parametres de filetage, on considerera comme fixe, predefini. Je ne traiterai pas le "user interface".

Comme sorties :
  • Les signaux de moteur PaP
  • Eventuellement un ou des signal marche / arret / direction de la broche.
Et des parametres :
  • Nombre de pas par tour donné par le (ou les) codeur(s)
  • Pas de vis mère
  • Nombre de pas par tour de moteur PaP
  • Pas de vis ciblé

<Petit deviation vers la monde des matheux>

Les pas de vis mère et vis ciblé seront des rapports en termes de mm. Cela pour pouvoir rester generale, et pour eviter l'utilisation des floats qui sont inexactes. Quelques exemples:

4mm -> 4 : 1
Pas Schaublin -> 5 : 3
20 TPI -> 127 : 100

Donc, en C on peut utiliser un struct de ce type

On as aussi quelques operations a definir sur les rapports, qu'on s'on souviens de nos jours ecoliers. Addition, soustraction, multiplication, division sont simples, et ne necessite pas que les valeurs soit canonique. Avant comparaison, par contre, faut le faire, en utilisant la methode de greatest common divisor. Code pour tous cela peut etre trouvé, par exemple, sur rosetta code. En termes de performance, ces fonctionnalités peut etre mises "inline" - franchement on va pas utiliser beaucoup.

<fin de deviation>

Ignorant le fonction de retomber dans les pas, l'application est assez, voir "tres" simple. On suit le vitesse de la broche instant par instant et on changes la vitesse de la vis mere en fonction de cela. En pseudocode, ca donne quelque chose comme ca:

 
S

simon74

Compagnon
Les codeurs en STM32

Bon, assez d'amuse-gueules, on arrive vers le plat. Le codeur est un truc important. Si on loupe le codeur, on loupe le tout, on ne sais pas ou on est. Ya deux types de codeur - les codeurs relatif, qui génère deux signaux en quadrature donnant les pas et leurs directions, et les codeurs absolus qui donne la position exacte du codeur. On parlera des codeurs relatif ici.

Comment gérer un codeur, donc?

  1. Lire ses signaux directement, en "user code". Cela ne laisse pas trop de temps pour faire autre choses, car on peut louper des pas.
  2. Avec un timer qui génère un interrupt assez rapide, on peut scruter les deux entrées et réagir aux changements. Comme option 1, mais avec moins de chance de louper des changements (au moins si ils ne sont pas plus rapides que les interrupts, mais on peut scheduler celles-ci pour éviter). Par contre, on est sujet aux artefacts du "Nyquist sampling frequency".
  3. On peut mettre des interrupts sur les changements des deux entrées, et avec un peu de logique, on suit les impulsions du codeur. Ceci est la méthode la plus utilisé sur les µCs en générale.
  4. Sur les STM32 (et, de mémoire, sur les STM8) y a un mode "codeur" sur quelques uns des timers. Ceci est vraiment intéressant, car la totalité du logique se passe en dehors de, et indépendant de, la code qui se passe sur le processeur. Y a presque rien a faire, et c'est ça qu'on va faire. Moins de code, fainéantise comme philosophie.
En se repérant a section 15.3.12 de RM0008, on se découvrira comment ça marche. On definira un niveau de filtrage pour eviter les fausses lectures (debouncing), et le timer va compter, sous la controle de codeur, de 0 a n, par repetition (ou n est le nombre de pulsations/tour generé par le codeur, et que on va donner au timer comme "auto reload value").

On peut utiliser le mode DMA du timer pour copier ses valeurs internes vers nos variables chaque fois que ca change, et / ou utiliser des interrupts capture/compare pour faire des choses au passage de zero. On peut utiliser notre compteur comme "gachette" pour demarrer un autre timer, et encore d'autres choses. Le tout avec un minimum absolu de code executant sur le processeur meme.

Toujours ignorant le "retomber dans les pas", on s'en fout bien assez du positionnement exacte de la broche. Ce qu'on veut, c'est sa vitesse, combien de µS entre chaque changement de position, et ca, on n'as pas directement. Pour l'avoir, en mode "naïf", on pourrait utiliser le mode codeur, avec un interrupt sur chaque changement. Dans l'interrupt, on prends le temps exacte, et on calcul notre vitesse. Admettons un vitesse maximale de broche en filetage de 240 t/m, ca fait 4 t/s, ce qui fait (avec le codeur de vibram) 2000 interrupts/sec si on interrupt sur chaque pulsation, ou 1000 interrupts/sec si on interrupt sur une seule signal. En effet, on a utilisé le mode codeur pour eviter de faire un interrupt sur chaque changement des signaux, mais on va faire un interrupt a chaque changement des signaux quand meme.

Dans RM0008, meme, il est dit

The timer, when configured in Encoder Interface mode provides information on the sensor’s current position. You can obtain dynamic information (speed, acceleration, deceleration) by measuring the period between two encoder events using a second timer configured in capture mode. The output of the encoder which indicates the mechanical zero can be used for this purpose. Depending on the time between two events, the counter can also be read at regular times. You can do this by latching the counter value into a third input capture register if available (then the capture signal must be periodic and can be generated by another timer). when available, it is also possible to read its value through a DMA request generated by a Real-Time clock.

Admettons qu'on va utiliser TIM2 (timer 2) en mode codeur. Pour avoir le valeur de codeur en temps reel pour notre application, on va le configurer pour faire un transfert DMA de sa compteur vers nos variables (voila le pourquoi du volatile dans le pseudocode dessus). A ce point la, on a le valeur de codeur, sans aucun code mise apart sa configuration.

On va aussi configurer sa compteur comme signal de reset pour un autre compteur, par exemple TIM3, qui fera un DMA de son compteur sur le trigger, encore, vers nos variables. On peut jouer sur le prescaler de ce compteur pour compter le temps pour un ou plusiers "ticks" de codeur. Encore, on fini avec les valeurs qu'on veut, sans faire executer du code sur le processeur.

Il exist une autre probleme. Qu'est-ce-que va passer quand le codeur s'arrete subitement? On n'aura plus de updates, donc notre PaP va continuer a avancer a sa vitesse actuel, broche a l'arret, jusqu'au butee, ruinant notre piece. Mince alors. Il faut un watchdog, quelque chose qui arret le PaP en cas d'arret de broche. Et encore, on as des outils pour ca. Sur notre timer "esclave", on configurera un interrupt sur un canal capture/compare; si le compteur arrive vers un valeur predefini, on aura un interrupt qui peut arreter le tout.

Donc, on aura les valeurs qui nous interesse, automatiquement et sans avoir besoin d'executer du code, et un petit bout de code qui sera execute en cas d'arret, ce qui doit arriver assez peu souvent.

Prochaine etape, du code pour faire en sort que ca se passe comme ca.
 
G

gaston48

Compagnon
Toujours ignorant le "retomber dans les pas", on s'en fout bien assez du positionnement exacte de la broche.
Bonjour,
Et comment tu gères les passes multiples pour usiner complètement un filetage
retours en début de filetage, retombé exacte dans le pas précédent ?
 
G

Guy69

Compagnon
bonjour
Qu'est-ce-que va passer quand le codeur s'arrete subitement? On n'aura plus de updates, donc notre PaP va continuer a avancer a sa vitesse actuel, broche a l'arret, jusqu'au butee, ruinant notre piece.
pourquoi? le Pap n'avance que quand on lui dit, et si tu ne le fais avancer QUE lorsqu'il y a changement d'état sur le codeur, il ne va pas avancer tout seul. Y a un truc que je pige pas là.
A+
Guy
 
S

simon74

Compagnon
C'est car, comme pour le codeur, y a plusiers facons de faire avec les PaP, entre "faire le tout manuellement" et "laisse faire (d'un facon ou un autre) un timer". Moi, je propose de faire un maximum par timer, en dehors de processeur, et ca va dire que, encore comme avec le codeur, on ne va pas gerer chaque impulsion manuellement.
 
S

simon74

Compagnon
Pour coder tout ca, on vas en avoir besoin d'un peu plus (ou meme moins) que le HAL nous donne, il va falloir plonger un peu dans les fichiers stm32f1xx_ll_* au lieu de stm32f1xx_hal_*. Les driveurs "low level", quoi.

Avant d'y plonger la tete en avant, par contre, on verra pour la fonctionnalité de base - un timer pour lire le codeur, et qui nous envoi le positionnement de ce codeur, sans qu'on as besoin d'agir. On regardant dans stm32f1xx_hal_tim.h, on trouve les fonctions necessaires:

Au lieu d'utiliser HAL_TIM_Base_Init(), on va utiliser HAL_TIM_Encoder_Init(), en passant l'addresse d'un structure de TIM_Encoder_InitTypeDef, et ca nous fera le necessaire. Par exemple, pour notre codeur de 1000 pas / tour, on pourrait avoir ca:
A noter que IC1Filter et IC2Filter nous permets de faire du "debouncing" des signaux, c'est a dire qu'il va falloir 4 samples du meme niveau pour que ca soit pris en compte.

Il faut qu'on connect les sorties du codeur sur lee entrees du timer, bien sur. Par default, TIM2 Canal 1 et 2 sont sur PA0 et PA1.
Puis, au lieu de HAL_TIM_Base_Start_xx(), on utilisera HAL_TIM_Encoder_Start_xx(). Pour le mode "polling" ou "interrupt", un peu de lecture du RM0008 et le code du HAL, on s'on sortira tres bien.

Le mode DMA est un peu plus complex, car il faut aussi initialiser l'accessoire DMA, qui permets le timer de faire un transfert direct vers un endroit en memoire. Sur les stm32f1, y a 2 controleurs DMA avec 12 canaux total de DMA. Si on est sur TIM2, et on veut faire un DMA sur chaque update (TIM2_UP), il nous faut DMA1, canal 2 (voir RM0008, 13.3.7, table 78).


Par contre, demarrer le timer est plus delicat. HAL_TIM_Encoder_Start_DMA() n'est pas si bon que ca, car il transfert par DMA a partir du registre (ou registres) CCR1 / CCR2, sur les changements CCR, et ne transfert pas le direction (bit 4 en registre CR1). Nous, on veut transferer CR1 et CNT sur update; on as besoin de creer notre propre fonction de demarrage. Bof, mais en gros c'est du copier-coller su code de HAL.
et similaire pour l'arret. Puis on defini un bloc de memoire de 0x28 bytes pour recevoir ces donnees (n'oublient pas les declarations volatile), et on appel notre fonction de demarrage.
 
V

vibram

Compagnon
Salut Simon,

Est ce que tu tests ton sketch en même temps ?
Juste pour demander car je n'ai pas le temps de le faire mais je suis avec intérêt
 
S

simon74

Compagnon
Celles la ne sont pas testé pour l'instant. Y a des parties tirés des autres de mes projets, et un partie qui suit les techniques que j'ai utilisé ailleurs. Faut que je setup un projet :)

Mais, comme j'ai dit, ce n'est pas "clefs en main".
 
S

simon74

Compagnon
Bon, ca a pris du temps de remettre en route un environnement C/C++ pour ARM qui peut faire avec ce qui genere STM32CubeMX. J'ai maintenant 2 installations de llvm/clang (qui marche tres bien, mais pas avec CubeMX); finalement j'ai cedé et installé un toolchain arm-none-eabi. Enfin bref, j'ai un projet qui compile maintenant, mais j'ai du me tromper sur le clock, c'est enormement lent.

[edit]
Probleme entre clavier et chaise. J'ai oublié de preciser un source pour le HSE.

Donc, le code sera ici : https://github.com/tufty/stm32-noodling

Je m'excuse, mais les commentaires et messages de commit sera en Anglais, car - ummm - c'est difficile de faire les accents avec emacs. Oui, c'est ca.

Et puis, bien sur, j'avait du code qui marchait parfaitement deja hier matin, mais j'ai fait un connerie avec STM32CubeMX et il m'a tout zappé, y compris le repo git locale. Et non, je n'avait pas mon disque de sauvegarde branché.

If it's not backed up, it's not important.
 
Dernière édition:

Sujets similaires

J
Réponses
6
Affichages
559
Julien
J
D
Réponses
9
Affichages
428
Doctor_itchy
D
wika58
Général Arduino Uno R4
Réponses
17
Affichages
39 944
furynick
furynick
J
Réponses
17
Affichages
6 532
Jean marc 11
J
J
Réponses
7
Affichages
4 642
jeanou56
J
wika58
Réponses
283
Affichages
46 234
furynick
furynick
thierry74
Réponses
40
Affichages
3 087
thierry74
thierry74
F
Réponses
13
Affichages
5 317
freddy007
F
C
Réponses
25
Affichages
5 599
Squal112
Squal112
S
Réponses
10
Affichages
905
stefan531
S
Haut