Auteur Sujet: pilotage moteur via utilisation du TIMER A0 (AVR & MEGATINY séries 0/1/2)  (Lu 8469 fois)

laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
Bonjour

Je profite des ponts de moi de mai ( hélas le dernier sic!) pour avancer sur une problématique "simple" et construire une solution facilement déclinable pour pouvoir piloter un moteur via pont en H à une fréquence "qui va bien "idéalement pour un décodeur embarqué.

De quoi parlons nous plus précisément:

Coté CPU:
les candidats sont les AVR séries 0/1/2 ( ATmegax08,x09, AVR DA DB DD EA ( et futurs EB) et la famille des MEGATINY Attinyx6 x7 des séries 0/1/2.
Tous sont dotés du TIMER A ( ( certains ont en même deux A0 et A1).
Ces derniers sont tout particulièrement indiqués pour la génération du PWM.

Néanmoins par "hardware design" toutes les broches ne sont pas nécessairement éligibles ou disponibles selon les modèles (ref et/ou nombres de pins) , il va donc convenir de bien avoir en tète les datasheets! associées au hardware

Par "défaut" sur ARDUINO NANO EVERY équipé d'l'ATMEGA4809 pour des raisons de compatibilité les fréquences des broches supportant le PWM HARDWARE ( = sans BIT BANGING) ont une fréquence "limitée" à ~1Khz pour les plus rapides.

Ce ~1Khz qui convient fort bien pour des usages tel que le pilotage d'une led est en revanche "insuffisant" (comprendre trop lent) pour le pilotage d'un moteur. On peut mieux plutôt simplement.

Par chance on peut modifier les "paramètres qui vont bien" pour passer à des fréquences plus élevées de plusieurs dizaines de Khz.

Les décodeurs ESU par exemple proposent 40khz et jusqu'à ~50Khz sur leur dernière génération de produits. C est donc une plage bien adaptée.
Je me souviens du 15(k) 2/3Hz cher à certains pour piloter leur modèles miniature! ...

Pour s'en approcher il y a deux approches:
fixer une fréquence donnée ici par exemple 40Khz et construire autour la solution quelque soit la vitesse du CPU.
laisser le fréquence proportionnelle à la vitesse de CPU.

Par défaut les librairies MEGACOREX, DX CORE et MEGATINY CORE vont configurer pour rester 100% "Arduino" compatible le TIMERA en mode "SPLIT"  (2x 8 Bits mode ) avec un prescaler de /64.
(voir doc MICROCHIP TB3217)
On a ainsi 16Mhz (160000000/64/256 valeurs en 8bits) 976Hz ~1Khz

Et bien si on joue sur ce prescaler on joue alors sur la fréquence de sortie ( Attention ce n'est pas sans impact!)

Ainsi on peut obtenir toujours en 8bits @16Mhz 40Khz via le calcul suivant 16000000/2/200 = 40000hz = 40Khz Magique non?
Si on laisse par défaut on aura @16Mhz  16000000/1/256 = 62.5Khz et 16000000/2/256 = 31Khz250

Si on a une vitesse de CPU plus élevée disons à 20Mhz on a alors 20000000/2/256 = 39062.5hz ~39Khz et 20000000/1/256 = 78125Hz = 78Khz125

On voit donc le coté "facile" de la chose a l aide de quelques parametres judicieusement choisis.

Cependant il faut aller encore un peu plus loin et les notes détaillées de la librairie DXCORE explique le bien fondé de travailler avec 255 valeurs et non 256.
Interet un analogWrite (x,0) se traduira comme un DigirtalWrite (x,LOW)  et réciproquement pour un analoguWrtite(x,255) comme un digitalWrite(x,HIGH)

entre les deux on aura un PWM proportionnel.

L'idée va donc etre de permettre de sélectionner en entrée le mode qui "convient" le mieux ( et surtout selon les conséquences associées) avec frequence fixe ou proportionnelle à la vitesse CPU.

Pilotage du pont en H
2 cas de figure existent ici
Les ponts en H pilotés via 2 PINS gérant nativement du PWM (canaux A et B ou IN1 et IN2)
Les ponts en H pilotés via 3PINS: 1PWM 1 pour le sens AVANT ( FORWARD= FWD) l autre pour le sens INVERSE ( REVERSE= REV)

La aussi on poura sélectionner dans l initialisation de l'objet la combinaison souhaitée (magique!)

Il faudrait aller encore un petit peu plus loin pour être complet et gérer l'inversion d'état de sortie car il arrive que des pont en H requièrent 2 entrées hautes pour une sortie basse! ( ex voir la table de vérité du MP6513 bien adapté pour les petites échelles selon DCC NMRA qui invite à tenir 22V VIN MAX NOMINAL et 24V en PIC VIN ( que l on écrêtera au besoin avec une diode TVS de 24V)

Ma préférence pour un peu plus de puissance va vers le TB67H450 mais plus délicat à caser pour de petits volumes au bénéfice d une puissance dispo en sortie très supérieure( jusqu'à 3.5A!)

.

Nous voila déjà bien lancé :)

A suivre

Laurent









« Modifié: mai 29, 2023, 12:59:25 am par laurentr »

laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
Pour le pilotage du moteur:
Nous avons besoin de fournir 2 informations:
1/la vitesse
2/la direction

Avec ces éléments la rotation du moteur doit s'opérer simplement quelques soit le nombre de PIN de pilotage, la fréquence, la vitesse du CPU.
Gérer l inversion du sens de marche avec décélération avant inversion puis reprise du niveau initial de vitesse en sens inverse si requis.

Initialisation:
Le choix de PINS sera lui à faire TRES précieusementt afin de respecter les contraintes du hardware. ( WISELY selon nos amis anglophones!)
Quelques règles de "sanity check" seront toutefois faite mais impossible d être exhaustif donc comprendre la philosophie et se l'approprier avant toute utilisation malheureuse... Je n ai pas integrer de sortie en mode #if zzz #ERROR...

Le must serait d asservir le pilotage du moteur à la mesure de la BEMF ( Back Electro Motrice Force) (FCEM :Force Contre Electro Motrice ) mais c est un niveau supérieur de réalisation (en projet!)

On a alors un "hard" et un "soft" clé en main prêts à être utilisés simplement.

Pour initier notre objet de base on fournira la sélection des broches selon un mode de pilotage et l'appel à un mode avec une fréquence fixe soit à une fréquence proportionnelle à la vitesse du CPU.

Notre objet pourra retourner quelques info utiles dont le niveau de PWM, la direction actuelle de rotation du moteur, et si la PWM est active ou non...

N'étant pas équipé pour le moment d un oscillo je ne pourrai contrôler la cohérence des résultats obtenus via les paramètres mis en place mais peut être que certains d entre vous pourront confirmer les hypothèses posées à l'aide de mesures.

Etat de la réalisation actuelle:
J ai crée une première classe initialement pour le pilotage à 3 broches fixes et avec un PWM à 40Khz.
Puis chemin faisant j'ai augmenté la "complexité" progressivement pour ouvrir au multiplexage des broches sur les ports puis, intégrer le mode de pilotage à 2 pins en fréquence proportionnelle à la vitesse CPU.

Avec près de 2000 lignes de code plus tard... cela compile sans erreur! C'est déjà un bon point :)

Le traitement de l'inversion de sens de marche avec une vitesse non nulle m'a pris quelques lignes! ( et il sera peut-être à revoir aussi!)


Les prochaines étapes prévues sont:
intégrer le mode 40Khz fixe pour le mode 2 PINS
actualiser le mode de pilotage en mode 3 PINS pour les deux types de fréquence.
en mode 3 PINS proposer le 40Khz et le mode à fréquence proportionnelle à la vitesse CPU.

Plus loin:
intégrer la gestion du BEMF (débrayable)
...

YAKA :)

Laurent



« Modifié: mai 30, 2023, 12:39:50 pm par laurentr »

laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
Bonjour

actualisation faite:
Le mode de pilotage est généré à l'initialisation soit en créant:
 un objet pour un pilotage sur 2 broches
 un objet pour un pilotage sur 3 broches

Il n'est pas possible de gérer en même temps des fréquences différentes, la même fréquence est appliquée pour tout le port sur toutes les broches.
Si plusieurs objets sont crées choisir IMPERATIVEMENT le même type de FERQUENCE (FREQ =0 => proportionnelle à la vitesse du CPU, FREQ =1 => mode 40Khz fixe)

Aucun Sanity check n'est effectué en pareil cas.

Les MEGATINY ATtinyx06 ATtinyx07 en sont pas supportés car le mapping de leurs ports est différemment construit ( syntaxe plus mapping individuel)
La librairie MEGATINYCORE devrait permettre une harmonisation des appellations / syntaxes  mais je n'ai pas réussie à y parvenir avec succès. (j ai du louper un truc? ???)

Je les ai donc écarté mais si on trouve la syntaxe qui va bien pour eux... il seraient ajoutables à la liste des CPU supportés.
A noter que ceux présentant 2 TIMER B sont les plus intéressant à exploiter (séries 1 & 2)
On leur préférera cependant l'AVR32DD20 par exemple pleinement supporté ici mais dont attention le brochage est différent des ATtinyx06 à 20 pins!!

A TESTER:
Il est alors possible de piloter plusieurs canaux PWM pour piloter des moteurs par des ponts en H.
Une fois encore bien choisir les broches dédiées à ces usages. 
Il serait possible de:
 piloter jusqu'à 3 ponts en H par 3 couples de 2 PINS sur les 6 PINS PWM du même port ( si 6 broches PWM présentes).
 piloter jusqu'à 6 ponts en H par 6 PINS PWM individuelles sur le même port et 12 pins sur d'autres ports pour la gestion des directions.

 ATTENTION Aucun Sanity check inter objet n'est effectué en pareil cas. (serait ce même possible? Peut être via une classe parent en public contenant un lock sur les ressources? puis des classes dérivées pour les objets? Un peu usine à gaz non?) ( je prends les avis! mais je ne m'y collerai pas pour la réalisation!)

La fréquence est fixée à l'initialisation (proportionnelle à la vitesse du CPU ou fixe à 40Khz)

La PWM générée étant HARDWARE on ne doit pas trop être inquiet de la conso des ressources. Sa régularité doit être exemplaire et précise  8)

J'ai commenté les étapes dans le code.( in English of course!)  ;)

Par contre même comprimé je suis a 13Ko pour le .h et le .cpp ( resp:  8Ko et 57 Ko) donc impossible à uplaoder en fichier joint ici.

Une solution à proposer pour les partager? :-\

Laurent




« Modifié: mai 30, 2023, 12:40:50 pm par laurentr »

laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
Voici le programme qui permet de tester.

On a ainsi un pilotage de 2 ponts H à la même fréquence ici à la même vitesse et dans la même direction (FWD)
 L un avec 2 pins
 L autre via 3 pins

On peut alors faire varier les paramètres très facilement en modifiant les vitesses et/ou les directions de chacun

#include <Arduino.h>

#include "classmotorpropfreqv2.h"

//OBJECT DEFINITIONS:
motorpropfreqv2 mymotor3pins;
motorpropfreqv2 mymotor2pins;

//VARIABLES:
uint8_t speedMotor1 = 0;
uint8_t directionMotor1 = 0;

uint8_t speedMotor2 = 0;
uint8_t directionMotor2 = 0;

uint8_t REVPIN;
uint8_t FWDPIN;
uint8_t PWMPIN;
uint8_t FREQ;

uint8_t PWMPINA;
uint8_t PWMPINB;


void setup() {
  // put your setup code here, to run once:

  REVPIN = PIN_PA1;
  FWDPIN = PIN_PA2;
  PWMPIN = PIN_PA5;
  PWMPINA = PIN_PA3;
  PWMPINB = PIN_PA4;
  FREQ = 0;

  //INIT OBJECTS:
  mymotor3pins.initmotorpropfreq3pinsmode(PWMPIN,REVPIN,FWDPIN,FREQ);

  mymotor2pins.initmotorpropfreq2pinsmode(PWMPINA,PWMPINB,FREQ);

  speedMotor1 = 70;
  directionMotor1 = 1;

  speedMotor2 = 70;
  directionMotor2 = 1;

}

void loop() {

mymotor3pins.drivemotor3pinsmode(speedMotor1,directionMotor1);

mymotor2pins.drivemotor2pinsmode(speedMotor2,directionMotor2);


}

laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
actualisation:
Sur le mode pilotage en MODE 2PINS: mise en place du mode de pilotage en mode "logique inverse" pour les ponts en H avec une table de vérité telle que celle du MP6513 (IN1 = HIGH IN2 =HIGH  OUT1 = LOW OUT2 =LOW)
Adaptation des conversions de vitesse en conséquence.

Par défaut il n'est pas nécessaire de devoir préciser le mode de fonctionnement en mode normal
//mymotor2pins.initmotorpropfreq2pinsmode(PWMPINA,PWMPINB,FREQ,false);
ceci fonctionne nativement:
//mymotor2pins.initmotorpropfreq2pinsmode(PWMPINA,PWMPINB,FREQ);

Si il y besoin du mode de logique inverse pour le pilotage on définira alors comme ceci l'objet
//mymotor2pins.initmotorpropfreq2pinsmode(PWMPINA,PWMPINB,FREQ,true);

Cette option n'est pas disponible sur le mode pilotage à 3 PINS

Laurent

laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
Illustration de la compilation pour les 21 modèles de CPU différents (hors type de brochage TQFP, VQFN, DIP....!)



Rm: la classe a ete "pensée" pour être utilisée avec une plage de vitesse comprise entre 0 et 127 ce qui correspond aux 128 pas du DCC.

Si cette plage doit être différente un petit mapping avant d'y entrer les valeurs pour "speed" remettra les choses dans l'ordre. (via fonction map() par exemple ou calcul)

Néanmoins cela impose plusieurs niveaux de mapping différents successifs ce qui introduit un biais.

Selon les conversions la linéarité n'est pas garantie comme absolument linéaire et des sauts pourraient être constatés.

On pourrait envisager de borner la plage nativement avec les seuils hauts et bas... A voir!

Pour l'utilisation je pense que une fois récupérée la vitesse demandée en nombre de crans avant injection vers le moteur à l'aide de celle classe celle ci doit être "mise à l'échelle" de la plage des caractéristiques du moteur/modèle en respectant Vmin ( CV2)  Vmax (CV5)  et ou la plage des 28 crans possibles si utilisation des CV adhoc (CV67-CV94 et les coefficients de réglages CV3 CV4 et CV65 CV66

Laurent

« Modifié: mai 30, 2023, 05:40:28 pm par laurentr »

laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
Voici le lien qui permet d'accéder aux fichiers de la classe: (via wetransfert)

https://we.tl/t-WnNlMOcce6

Bons tests!


Laurent

laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
Bonjour

Vérifié à l'oscilo c est une affaire qui tourne bien à 40khz!

Je métrai prochainement la capture d'écran ad hoc pour illustrer.

Dans la liste des "TO DO" une mise à jour sera faite pour

introduire une fonction qui pilote les actions lorsque la fonction ACK DCC est requise aussi bien en mode 2 pins que 3 pins
corrections typographiques diverses.
je dois "reflechir" à une implémentation "simple" de la gestion des Vmin( Vstart), Vmid, Vmax et des coefficients d accélération et décélération

A noter que j ai bien avancé sur une autre version pour la co gestion du BEMF avec cette classe :)

Apres avoir parcouru  plusieurs articles source sur la gestion du PID ( en gros ce qui va mesurer la BEMF et agir sur la "compensation de charge") un rapide état de l art ma fait appréhender différentes bibliothèques existantes.

C est à l occasion de la vision d une video youtube ( sur les explications mathématiques du PID) que j ai mieux compris la méthode utilisée par les décodeurs NAGODEN qui réalisent une correction PI avec un coef de lissage qui est pour le CPU plus "léger" à traiter
Je me suis donc très fortement inspiré de la trame des décodeurs NAGODEN pour fusionner la classe initiale avec la trame de gestion du BEMF implémentée sur les décodeurs NAGODEN.

Rm: il y aura plus de paramètres à initialiser lors de la création des objets en plus des valeurs usuelles on trouvera les valeurs spécifiques à la gestion BEMF ( coefficients P, I, timeout, Vmin Vmax, coef accélération, décélération)

Pour le moment cela compile bien mai je dois aligner les tests avec le pilotage effectif d un moteur et déceler l'apport

Je ne prévois pas d intégrer la gestion du mode par traitement des 28 steps ( CV64 à 97) de la courbe de vitesse.

Je n'y vois pas de plus value directe mais ceux qui utilisent ce mode pourront peut être nous apporter l apport de son usage en comparaison à un réglage "3 points" avec compensation de charge...

Laurent
« Modifié: juin 15, 2023, 04:49:33 pm par laurentr »