Torque | 25.0 oz-in (1.80 kg.cm) at 4.8V | |
Speed | 0.1sec/60° (4.8V) | |
Voltage | 4.0V to 7.2V, 4.6V - 5.2V nominal | |
Running current with 5V supply (no mechanical load) | 220 ±50mA | |
Stall current with 5V supply (horn locked) | 650 ±80mA | |
Idle current with 5V supply | 6 ±10mA | |
Dimensions | 0.91in x 0.48in x 1.14in (23mm x 12.2mm x 29mm) | |
Weight | 0.32oz (9g) | |
Dead band width | 10µs | |
Operating Temperature range | -22°F to 140°F (-30°C to 60°C) | |
Universal "S" type connector fits most receivers |
Contrôler un servo-moteur à l'aide d'un microcontrôleur est simple, aucun pilote externe. Le principe de base est assez simple. Il suffit d'envoyer une impulsion et c'est le temps que durera cette impulsion qui déterminera l'angle du servo-moteur. ce temps d'impulsion est de quelques de quelques millisecondes et doit être répété à intervalle régulier ( 50Hz soit toutes les 20 ms ). Si le temps d'impulsion varie d'un fabricant à l'autre, les valeurs sur ce schéma sont assez standard. |
//Réglage du Servo moteur par position angulaire //(c) sammy76.free.fr #include "Servo.h>" Servo myservo; // Créer l'objet Servo pour contrôler servomoteur // 9 servomoteurs maximum int pos = 0; // variable de sauvegarde de positon servo static void videbuffer_att() { while (Serial.available() > 0) { char t = Serial.read(); } do {} while (!Serial.available()); } static int readnumber() { //lit une chaine de caractère et la converti en entier videbuffer_att(); while (Serial.available() == 0); int newpos = Serial.parseInt(); //lit int return newpos; } void setup() { myservo.attach(9); // Attache le servo à la broche 9 de l'arduino Nano Serial.begin(9600); Serial.print("Configuration du Servo 9g\nSaisir la position initiale\n"); } void loop() { pos = readnumber(); /*if (pos<10){ pos=10; }*/ myservo.write(pos); Serial.print("Position : ");Serial.println(pos); delay(1000); // wait for one seconds }
Retirer du couvercle et de la boîte de vitesses | Dessouder, puis Retirer le moteur à courant continu et le potentiomètre |
Remplacement du potentiomètre par deux résistances, soit la moitié de la valeur du potentiomètre Ici 2,7kΩ | Couper la patte qui dépasse de l'engrenage |
DD | Dimensions du moteur, son diamètre ou longueur côté du carré de la face avant, hors tout, exprimé en dixièmes de pouce ,arrondi. Exemple pour un NEMA17 : $1,7\times25,4=43,18mm$ |
MM | type de montage (pouce x 10)+diamètre, "C" trous taraudés en façade "D" tôle arriere |
LLL | LLL : longueur (pouce x 10) |
- | séparation |
CCC | courant par phase (A x 10) |
I | classe d'isolation, définit la temp max de travail en °F
|
VVV | Tension par phase (V x 10) |
SSS | Nombre de pas/tour |
W | code bobinage
|
Angle par pas deg | Courant A | Résistance/phase Ω | couple de maintien Nmm | Nombre de fils |
---|---|---|---|---|
1.8 | 0.6 | 8 | 120 | 4 |
A4988 | DRV8825 | LV8729 | TMC2208 | TMC2100 | TMC2130 | |
---|---|---|---|---|---|---|
Courant par default | 2A | 1.3A | 0.8A | 0.7A | 0.5A | 0.76 |
Vref par default | 0.8V | 0.65V | 0.4V | 1V | 0.65V | 1V |
Courant Maxi | 2A | 2.5A | 1.5A | 1.41A | 1.2A | 2A |
Formule | $i=\dfrac{V_REF}{0.8}$ | $i=V_REF\times 2$ | $i=\dfrac{V_REF}{\sqrt 2}$ | $i=\dfrac{V_REF\times 1.9}{2.5}$ | ||
Ajustement du courant | Horaire Augmente Anti-horaire Diminue | Horaire Diminue Anti-horaire Augmente | Horaire Augmente Anti-horaire Diminue | |||
Micropas | 1, 1/2, 1/4, 1/8, 1/16 | 1, 1/2, 1/4, 1/8, 1/16, 1/32 | 1, 1/2, 1/4, 1/8, 1/16, 1/32, 1/64, 1/128 | 1, 1/2, 1/4, 1/8, 1/16 | 1/16 | 1, 1/2, 1/4, 1/8, 1/16, 1/256 |
Moteur | 8V-35V | 8.2V-45V | 6V-36V | 4V-35V | <1.2A | 4.75V-46V |
Spécifications | Pas cher | Courant fort | Silencieux | Silencieux, lissage |
$R_{CS}$ est la résistance de détection de courant; Les versions originales de cette carte utilisaient des résistances de détection de courant de 0,050 Ω, mais le fabricant est passés à des résistances de détection de courant de 0,068 Ω en janvier 2017, ce qui rend plus utile la plage du potentiomètre de réglage.
Ainsi, par exemple, si vous souhaitez régler la limite de courant à 1 A et que vous avez une carte avec des résistances de détection de 68 mΩ, vous définirez VREF sur 540 mV. Cela garantit que même si le courant à travers chaque bobine change d'un pas à l'autre, l'amplitude du vecteur de courant dans le moteur pas à pas reste constante à 1 A:
$\sqrt{I_{COIL1}^2 + I_{COIL2}^2}= I_{MAX}= 1 A$
Si vous souhaitez au contraire que le courant traversant chaque bobine soit de 1 A en mode pas à pas complet, vous devez définir la limite de courant à 40% plus élevée, ou 1,4 A, car les bobines sont limitées à environ 70% du courant défini limite en mode pas à pas (l'équation ci-dessus montre pourquoi c'est le cas). Pour ce faire avec une carte avec des résistances de détection de 68 mΩ, vous devez régler VREF à 770 mV.
Moteur | A4988 (Imax=2A) | A8825 (Imax=2,5A) | |||||
---|---|---|---|---|---|---|---|
Imoteur | Inom (71%) | R050 | R100 | R200 | R050 | R100 | R200 |
Vref (mV) | Vref (mV) | ||||||
0,1 | 0,07 | 28 | 56 | 112 | 17 | 35 | 70 |
0,2 | 0,14 | 56 | 112 | 224 | 35 | 70 | 140 |
0,3 | 0,21 | 84 | 168 | 336 | 52 | 105 | 210 |
0,4 | 0,28 | 112 | 224 | 448 | 70 | 140 | 280 |
0,5 | 0,36 | 144 | 288 | 576 | 90 | 180 | 360 |
0,6 | 0,43 | 172 | 344 | 688 | 107 | 215 | 430 |
0,7 | 0,50 | 200 | 400 | 800 | 125 | 250 | 500 |
0,8 | 0,57 | 228 | 456 | 912 | 142 | 285 | 570 |
0,9 | 0,64 | 256 | 512 | 1 024 | 160 | 320 | 640 |
1,0 | 0,71 | 284 | 568 | 1 136 | 177 | 355 | 710 |
1,1 | 0,78 | 312 | 624 | 1 248 | 195 | 390 | 780 |
1,2 | 0,85 | 340 | 680 | 1 360 | 212 | 425 | 850 |
1,3 | 0,92 | 368 | 736 | 1 472 | 230 | 460 | 920 |
1,4 | 0,99 | 396 | 792 | 1 584 | 247 | 495 | 990 |
1,5 | 1,07 | 428 | 856 | 1 712 | 267 | 535 | 1070 |
1,6 | 1,14 | 456 | 912 | 1 824 | 285 | 570 | 1 140 |
1,7 | 1,21 | 484 | 968 | 1 936 | 302 | 605 | 1 210 |
1,8 | 1,28 | 512 | 1 024 | 2 048 | 320 | 640 | 1 280 |
1,9 | 1,35 | 540 | 1 080 | 2 160 | 337 | 675 | 1 350 |
2,0 | 1,42 | 568 | 1 136 | 2 272 | 355 | 710 | 1 420 |
2,1 | 1,49 | 372 | 745 | 1 490 | |||
2,2 | 1,56 | 390 | 780 | 1 560 | |||
2,3 | 1,63 | 407 | 815 | 1 630 | |||
2,4 | 1,70 | 425 | 850 | 1 700 | |||
2,5 | 1,78 | 445 | 890 | 1 780 |
MS2 | MS1 | Pas | Interpolation | Mode |
0 | 0 | 1/8 | oui jusqu'à 256 | Stealthchop2 |
0 | 1 | 1/2 | oui jusqu'à 256 | Stealthchop2 |
1 | 0 | 1/4 | oui jusqu'à 256 | Stealthchop2 |
1 | 1 | 1/16 | oui jusqu'à 256 | Stealthchop2 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
Sync + Reservé | Adresse Esclave | R/W Registre 7bits | 32 bits données | CRC | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 | 0 | 1 | 0 | Réservé (sans souci mais inclus dans le CRC) | SLAVEADDR=0 | Adresse du registre 7bits | 1 | octets de données 3, 2, 1, 0 (octet haut à bas | CRC |
Equation 1 | $\delta t=\dfrac{c}{f}$ | $f$ = fréquence de la minuterie (Hz). |
Equation 2 | $\omega=\dfrac{\alpha\cdot f}{c}$ | $\omega$ angle de pas du moteur (radian) $1~rad = 180 /\pi = 57,3 \deg$ $1~rad\cdot s^{-1} = 30 /\pi = 9,55~tr\cdot min^{-1}$. |
Equation 3 | $\omega \prime =\dfrac{2\dot \alpha\cdot f^2\cdot (c_1-c_2)}{c_1\cdot c_2 \cdot (c_1+c_2)}$ | $\omega$ angle de pas du moteur (radian) $1~rad = 180 /\pi = 57,3 \deg$ $1~rad\cdot s^{-1} = 30 /\pi = 9,55~tr\cdot min^{-1}$. |
Equation 4 | $\theta(t)=\int_{0}^{t}\omega(\tau)d\tau=\dfrac{\omega'\cdot t^2}{2}=n\cdot\alpha$ | $n≥ 0$ numéro de pas (réel). Lorsque l'arbre est à $\theta = n\cdot\alpha$, (entier n ) est la n ième impulsion de pas. |
Equation 5 | $t_n=\sqrt{\dfrac{2\cdot n\cdot \alpha}{\omega'}}$ | Le décompte exact de la minuterie pour programmer le délai entre les n ième et (n + 1) ième impulsions ($n≥0). |
Equation 6 | $C_n=f\cdot (t_{n+1}-t_n)$ | Le compte initial $c_0$ se factorise pour donner les équations 7 et 8 :. |
Equation 7 | $C_0=f\sqrt{\dfrac{2\alpha}{\omega'}}$ | |
Equation 8 | $C_n=C_0(\sqrt{n+1}-\sqrt{n})$ |
G0 G90 X100 Y0 G1 Y100 F200 G2 X150 Y150 I50 J0 G2 X200 Y100 I0 J-50 G1 Y0 X100
Couple | en kg.cm | Nombre de KV | en kV à vide |
---|---|---|---|
Vitesse | en tr.min-1 | Tension | en V |
Diamètre de roue | en mm | ||
Commençons par le moteur parfait, sans pertes, η=1
Un rotor est constitué d’un cylindre en fer doux (perméable au champ magnétique) de longueur l dans lequel on a fait des encoches, ici trois (mais il peut y en avoir un nombre quelconque, trois et douze étant très courants en modélisme). On place des bobines en fil de cuivre autour des parties saillantes appelées pôles. On ne considère que la longueur des conducteurs éctiligne, le long des pôles. | ||
---|---|---|
Ici, un rotor à P = 4 pôles et des bobines à n = 3 spires, ce qui est équivalent à utiliser 4x3x2 = 24 conducteurs rectilignes de longueur L. |
$P$ le nombre de pôles | Nombre d'encoches | ||
---|---|---|---|
Diamètre | Masse liéïque | Section mm² | 2 fils parallèles |
3 fils parallèles | |
Centième | mm | gr/m | |||
10 | 0,10 | 0,070 | 0,008 | 0,016 | 0,024 |
12 | 0,12 | 0,101 | 0,011 | 0,023 | 0,034 |
14 | 0,14 | 0,137 | 0,015 | 0,031 | 0,046 |
16 | 0,16 | 0,179 | 0,020 | 0,040 | 0,060 |
18 | 0,18 | 0,226 | 0,025 | 0,051 | 0,076 |
20 | 0,20 | 0,279 | 0,031 | 0,063 | 0,094 |
22.4 | 0,22 | 0,350 | 0,039 | 0,079 | 0,118 |
25 | 0,25 | 0,436 | 0,049 | 0,098 | 0,147 |
28 | 0,28 | 0,547 | 0,062 | 0,123 | 0,185 |
30 | 0,30 | 0,628 | 0,071 | 0,141 | 0,212 |
35.5 | 0,36 | 0,880 | 0,099 | 0,198 | 0,297 |
40 | 0,40 | 1,117 | 0,126 | 0,251 | 0,377 |
45 | 0,45 | 1,414 | 0,159 | 0,318 | 0,477 |
50 | 0,50 | 1,746 | 0,196 | 0,393 | 0,589 |
56 | 0,56 | 2,190 | 0,246 | 0,493 | 0,739 |
63 | 0,63 | 2,771 | 0,312 | 0,623 | 0,935 |
65 | 0,65 | 2,950 | 0,332 | 0,664 | 0,995 |
67 | 0,67 | 3,134 | 0,353 | 0,705 | 1,058 |
71 | 0,71 | 3,520 | 0,396 | 0,792 | 1,188 |
75 | 0,75 | 3,927 | 0,442 | 0,884 | 1,325 |
80 | 0,80 | 4,469 | 0,503 | 1,005 | 1,508 |
85 | 0,85 | 5,045 | 0,567 | 1,135 | 1,702 |
90 | 0,90 | 5,656 | 0,636 | 1,272 | 1,909 |
95 | 0,95 | 6,301 | 0,709 | 1,418 | 2,126 |
100 | 1,00 | 6,982 | 0,785 | 1,571 | 2,356 |
106 | 1,06 | 7,845 | 0,882 | 1,765 | 2,647 |
112 | 1,12 | 8,758 | 0,985 | 1,970 | 2,956 |
118 | 1,18 | 9,722 | 1,094 | 2,187 | 3,281 |
120 | 1,20 | 10,054 | 1,131 | 2,262 | 3,393 |
125 | 1,25 | 10,910 | 1,227 | 2,454 | 3,682 |
130 | 1,30 | 11,800 | 1,327 | 2,655 | 3,982 |
140 | 1,40 | 13,685 | 1,539 | 3,079 | 4,618 |
150 | 1,50 | 15,710 | 1,767 | 3,534 | 5,301 |
160 | 1,60 | 17,874 | 2,011 | 4,021 | 6,032 |
170 | 1,70 | 20,179 | 2,270 | 4,540 | 6,809 |
180 | 1,80 | 22,622 | 2,545 | 5,089 | 7,634 |
Matériau | Résistivité ρ x 10-8 Ωm | Matériau | Résistivité ρ x 10-8 Ωm | |
---|---|---|---|---|
argent | 1,6 | platine | 10 | |
cuivre | 1,7 | fer | 10 | |
or | 2,4 | silicium | 10 | |
aluminium | 2,7 | étain | 18 | |
magnésium | 4,6 | plomb | 21 | |
tungstène | 5,6 | germanium | 46 | |
zinc | 6 | constantan | 49 | |
nickel | 7 | mercure | 96 | |
laiton | 7 | nichrome | 100 | |
cadmium | 7,6 | carbone | 3500 |
Choisir la matière : | 1.7 x 10-8 Ωm | ||
Choisir le diamètre en Centième: | 0.1 mm soit 0.008 mm2 | ||
Longueur : | m | ||
Résistivité 43.290 Ω, Masse 1.396 gr |
Nombre d'encoches | Nombre d'encoches par phase | Nombre de pôle P |
---|---|---|
6 | 1 | 2 |
12 | 1 | 4 |
12 | 2 | 2 |
18 | 1 | 6 |
18 | 2 | 3 |
18 | 3 | 2 |
24 | 1 | 8 |
24 | 2 | 4 |
24 | 4 | 2 |
36 | 1 | 12 |
36 | 2 | 6 |
36 | 3 | 4 |
36 | 4 | 3 |
36 | 6 | 2 |
48 | 1 | 16 |
48 | 2 | 8 |
48 | 4 | 4 |
48 | 8 | 2 |
72 | 1 | 24 |
72 | 2 | 12 |
72 | 3 | 8 |
72 | 4 | 6 |
72 | 6 | 4 |
72 | 8 | 3 |
72 | 12 | 2 |
Accéder au paramètres
Mode | defaut | Autre choix | |
Valeur | Réglage | Valeur/Réglage | Valeur→Réglage |
Initialisation | 0 | ||
248 | |||
248 | |||
120 | |||
248 | |||
120 | |||
248 | |||
RPM | 248 | ||
Type de batterie | 120 | Lipo | 0→NiMH |
128 | |||
Type de batterie 2 | 128 | Lipo | vide→NiMH |
Low Voltage Limiter | 120 | réduite | 0→Stop |
248 | |||
Protection de batterie | 248 | 3.0V | 120→2.8V 120→3.2V |
Protection de batterie 2 | 248 | 3.0V | 248→2.8V Vide→3.2V |
128 | |||
Motor Direction | 128 | Normal | 120→Inversé |
Motor Timing | 0 | Auto | 0→7-22 120→22-30 |
0 | Auto | Vide→7-22 Vide→22-30 | |
248 | |||
Start | 120 | Soft | 128→ACC 0→Very Soft |
Start 2 | Vide | Soft | 128→ACC Vide |
120 | |||
Frein | 0 | Off | 120→on |
Fin de configuration | 248 | ||
128 | |||
248 | |||
0 |
GRADE | T° max °C | Rémanence Br | Intensité du Champ coercitif | Produit énergétique | |||||
---|---|---|---|---|---|---|---|---|---|
bHc | iHc (intrasèque) | (BxH)max | |||||||
Gauss (kg) | Tesla (mT) | kOe | kA/m | kOe | kA/m | MGOe | kJ/m³ | ||
N30 | ≤80 | 10,800-11,200 | 1008-1012 | 9.8-10.5 | 780-836 | ≥12 | ≥955 | 28-30 | 223-239 |
N33 | ≤80 | 11,400-11,700 | 1014-1017 | 10.3-11 | 820-876 | ≥12 | ≥955 | 31-33 | 247-263 |
N35 | ≤80 | 11,700-12,100 | 1017-1021 | 10.8-11.5 | 860-915 | ≥12 | ≥955 | 33-35 | 263-279 |
N38 | ≤80 | 12,200-12,600 | 1022-1026 | 10.8-11.5 | 860-915 | ≥12 | ≥955 | 36-38 | 287-303 |
N40 | ≤80 | 12,600-12,900 | 1026-1029 | 10.5-12.0 | 860-955 | ≥12 | ≥955 | 38-40 | 303-318 |
N42 | ≤80 | 12,900-13,200 | 1029-1032 | 10.8-12.0 | 860-955 | ≥12 | ≥955 | 40-42 | 318-334 |
N45 | ≤80 | 13,200-13,700 | 1032-1037 | 10.8-12.5 | 860-995 | ≥12 | ≥955 | 43-45 | 342-358 |
N48 | ≤80 | 13,700-14,200 | 1037-1042 | 10.8-12.5 | 860-995 | ≥12 | ≥955 | 45-48 | 358-382 |
N50 | ≤80 | 14,000-14,600 | 1040-1046 | 10.8-12.5 | 860-995 | ≥12 | ≥955 | 47-51 | 374-406 |
N52 | ≤65 | 14,200-14,700 | 1042-1007 | 10.8-12.5 | 860-995 | ≥12 | ≥955 | 48-53 | 380-422 |
Moteur courant continu (Direct Current)
Conversion d'énergie électrique continue, en énergie mécanique.
// connectez les broches du contrôleur de moteur aux broches numériques Arduino // moteur 1 int enA = 10; int in1 = 9; int in2 = 8; // moteur 2 int enB = 5; int in3 = 7; int in4 = 6; void setup() { // définit toutes les broches de commande du moteur sur les sorties pinMode (enA, OUTPUT); pinMode (enB, OUTPUT); pinMode (in1, OUTPUT); pinMode (in2, OUTPUT); pinMode (in3, OUTPUT); pinMode (in4, OUTPUT); } void demoOne () { // cette fonction fera tourner les moteurs dans les deux sens à une vitesse fixe // allumer le moteur A digitalWrite (in1, HIGH); digitalWrite (in2, LOW); // régler la vitesse à 200 hors de la plage possible 0 ~ 255 analogWrite (enA, 200); // allumer le moteur B digitalWrite (in3, HIGH); digitalWrite (in4, LOW); // régler la vitesse à 200 hors de la plage possible 0 ~ 255 analogWrite (enB, 200); delay (2000); // change maintenant les directions du moteur digitalWrite (in1, LOW); digitalWrite (in2, HIGH); digitalWrite (in3, LOW); digitalWrite (in4, HIGH); delay (2000); // éteignez maintenant les moteurs digitalWrite (in1, LOW); digitalWrite (in2, LOW); digitalWrite (in3, LOW); digitalWrite (in4, LOW); } void demoTwo () { // cette fonction fera fonctionner les moteurs sur la plage de vitesses possibles // notez que la vitesse maximale est déterminée par le moteur lui-même et la tension de service // les valeurs PWM envoyées par analogWrite () sont des fractions de la vitesse maximale possible // par votre matériel // allumer les moteurs digitalWrite (in1, LOW); digitalWrite (in2, HIGH); digitalWrite (in3, LOW); digitalWrite (in4, HIGH); // accélère de zéro à la vitesse maximale for (int i = 0; i <256; i ++) { analogWrite (enA, i); analogWrite (enB, i); delay (20); } // décélère de la vitesse maximale à zéro for (int i = 255; i> = 0; --i) { analogWrite (enA, i); analogWrite (enB, i); delay (20); } // éteignez maintenant les moteurs digitalWrite (in1, LOW); digitalWrite (in2, LOW); digitalWrite (in3, LOW); digitalWrite (in4, LOW); } void loop() { demoOne (); delay (1000); demoTwo (); delay (1000); }
Equipé d'un MOS L298N, module d'entraînement de moteur à courant continu, double pont en H.
Tension d'alimentation du Module 2 V-10 V
Tension d'entrée du Signal 1.8-7 V
Courant de fonctionnement monocanal de 1,5A, le courant de crête jusqu'à 2,5A, faible courant de veille (moins de 0,1μA)
Et enfin ça mini taille : 24,7x21x5mm.
L'inconvénients de ce petit composant c'est qu'il necéssite deux sorties PWM par moteur, pour réguler la vitesse.
La bibliothèque arduino est bien documentée, mais elle n'existe pas en micropython sur RP2040-ZERO
# Librairie MX1508 # Auteur : Samuel Dupré # (c) sammy76.free.fr # Date: April 4th, 2022 # Version: 1.0 #Pour deux moteurs uniquement #Utilisation : #from mx1508a import MX1508A #from time import sleep #CarteMX=MX1508A(9,10,11,12) #CarteMX.speed(250,-127) #sleep(5) #CarteMX.stop() from machine import Pin,PWM class MX1508A: def __init__(self, in1,in2,in3,in4): self.IN1=in1 self.IN2=in2 self.IN3=in3 self.IN4=in4 self.pwm1=PWM(Pin(self.IN1)) self.pwm2=PWM(Pin(self.IN2)) self.pwm3=PWM(Pin(self.IN3)) self.pwm4=PWM(Pin(self.IN4)) self.pwm1.freq(2000) self.pwm2.freq(2000) self.pwm3.freq(2000) self.pwm4.freq(2000) def stop(self): self.pwm1.duty_u16(0) #stop self.pwm2.duty_u16(0) #stop self.pwm3.duty_u16(0) #stop self.pwm4.duty_u16(0) #stop def speed(self,M1,M2): """Vitesse Moteur 1 et 2""" def map(x, in_min, in_max, out_min, out_max): return int((x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min) #print(Npwm1,Npwm2) pwmV1 = map(abs(M1), 0, 255, 5000, 50000) if M1>0: self.pwm1.duty_u16(pwmV1) self.pwm2.duty_u16(0) else: self.pwm2.duty_u16(pwmV1) self.pwm1.duty_u16(0) pwmV2 = map(abs(M2), 0, 255, 5000, 50000) if M2>0: self.pwm3.duty_u16(pwmV2) self.pwm4.duty_u16(0) else: self.pwm4.duty_u16(pwmV2) self.pwm3.duty_u16(0) #print(pwmV1,pwmV2) def display(self): print("IN1\tIN2\tIN3\tIN4") print("%d\t%d\t%d\t%d" % (self.IN1,self.IN2,self.IN3,self.IN4)) print("PWM1\tPWM2\tPWM3\tPWM4") print("%d\t%d\t%d\t%d" % (self.pwm1.duty_u16(),self.pwm2.duty_u16(),self.pwm3.duty_u16(),self.pwm4.duty_u16()))Maintenant elle existe....
// object avoidance robot, two DC motors driven by a A4988 module // speed is set with value of 0-255 but 255 is the slowest speed and 0 the fastest int dirPin = 2; //Broche Dir du A4988 int stepperPin = 3; //Broche Step du A4988 int en = 5; //Broche EN du A4988 int state = 0; int oldSpeed = 0; int rst = 4; const int trigPin = 7; const int echoPin = 8; void setup() { Serial.begin(9600); pinMode(dirPin, OUTPUT); pinMode(stepperPin, OUTPUT); pinMode(en, OUTPUT); //enable, active low pinMode(rst, OUTPUT); //rst, active low digitalWrite(rst, HIGH); pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); digitalWrite(en, LOW); digitalWrite(dirPin, HIGH); delay(1000); randomSeed(analogRead(A0)); } void loop(){ // some simple object avoidance int view = ultra(); view = min(view,100); //Valeur la plus petit entre view et 100 if (view < 30) //si view<30 { if (view <15) //si view<15 { state = motors(1, 100); //backwards recul durant 800ms delay(800); } int way = random(4,6); //hasard gauche droite while (ultra() < 30) state = motors(way, 70); //tand que la distance est <30 alors avance delay(110); } view = map(view, 0, 100, 5, 150); view = 255-view; state = motors(2, view); //go forward, speed depends on distance ahead delay(10); } int motors(int robot_direction, int robot_speed) // this determines how many steps to what direction ; determine le nombre d'étapes vers quelle direction { switch(robot_direction){ case 0: if(state != robot_direction){ digitalWrite(en, HIGH); //Desative les moteurs robot_direction = state; } break; case 1: if(state != robot_direction || oldSpeed != robot_speed){ digitalWrite(rst, LOW); delayMicroseconds(5); digitalWrite(rst, HIGH); analogWrite(en, robot_speed); // oldSpeed = robot_speed; step(2); } break; case 2: if(state != robot_direction || oldSpeed != robot_speed){ digitalWrite(rst, LOW); delayMicroseconds(5); digitalWrite(rst, HIGH); analogWrite(en, robot_speed); oldSpeed = robot_speed; //step(false, 2); } break; case 4: if(state != robot_direction || oldSpeed != robot_speed){ digitalWrite(rst, LOW); delayMicroseconds(5); digitalWrite(rst, HIGH); digitalWrite(en, LOW); analogWrite(en, robot_speed); oldSpeed = robot_speed; step(1); } break; case 5: if(state != robot_direction || oldSpeed != robot_speed){ digitalWrite(rst, LOW); delayMicroseconds(5); digitalWrite(rst, HIGH); digitalWrite(en, LOW); analogWrite(en, robot_speed); oldSpeed = robot_speed; step(3); } break; } return(robot_direction); } //make some steps void step(int stepsit){ //digitalWrite(dirPin,dir); //delay(50); for(int i=0;i<stepsit;i++){ digitalWrite(stepperPin, HIGH); delayMicroseconds(800); digitalWrite(stepperPin, LOW); delayMicroseconds(800); } } //Capteur ultra-son int ultra() { // just get distance: int result = 0; unsigned long duree = 0; unsigned long dist = 0; for (int i = 0; i<3; i++) { digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); delayMicroseconds(1); duree = pulseIn(echoPin, HIGH); dist = dist +(duree/58.2); delay(10); } dist /= 3; delay(10); Serial.println(dist); result = dist; return(result); }
La position relative.
Le codeur de position incrémental signal un changement de position angulaire.
Lorsqu’un codeur incrémental est mis sous tension, il ne rapportera sa position angulaire qu’une fois qu’il disposera d’un point de référence à partir duquel il pourra effectuer des mesures.
Addition | Soustraction |
---|---|
Lors d'un changement d'état de A on vérifie l'état de B, si c'est identique, on ajoute 1 | Si c'est différent, on enlève 1. |
Rien de plus simple |
volatile int compteur = 0; volatile int old_compteur=0; void setup(){ pinMode(2, INPUT); //A pinMode(3, INPUT); //B attachInterrupt(0, Int_Calc, CHANGE); //int0 sur P2 Serial.begin(115200); Serial.println("Start"); } void loop(){ if (compteur!=old_compteur){ Serial.println(compteur); } } void Int_Calc(){ old_compteur=compteur; if(digitalRead(2) == digitalRead(3)){ compteur++; }else{ compteur--; } }
from machine import Pin # declare les broches SA = Pin(13, Pin.IN) SB= Pin(12, Pin.IN) # variable pour l'indication de la position compteur_position = 0 old_position=0 def fonction_interruptionSA(irq1): global compteur_position print(SA.value(),SB.value()) if SB.value() == SA.value(): compteur_position += 1 else: compteur_position -= 1 # declaration de l'interruption SA (sur front tous le front, sans PULL_UP interne): SA.irq(trigger=3, handler=fonction_interruptionSA) #Si demi période uniquement sur front montant #SA.irq(trigger=Pin.IRQ_RISING, handler=fonction_interruptionSA) while "true": if compteur_position!=old_position: print(compteur_position) old_position=compteur_position
; ATtiny85 - 20MHz interne ; +-\/-+ ; PB5 1|- -|8 Vcc ; PB3 2|- -|7 PB2 T0/Int0 entrée signal A ; entrée signal B PB4 3|- -|6 PB1 ; GND 4|- -|5 PB0 ; +----+ .equ SGA = PB2 ;Signal A .equ SGB = PB4 ;Signal B .def countLL =r2 .def countLH =r3 .def countHL =r4 .def countHH =r5 .def regA =r16 .def zero =r15 .def savereg =r11 .def justone =r12 .cseg .org 0000 ;************************************************ ;* Interrupt Vectors * ;************************************************ rjmp main ; Reset Handler rjmp VECT_INT0; External Interrupt 0 main: ldi regA,high(RAMEND) ; set up stack pointer out SPH,regA ldi regA,low(RAMEND) out SPL,regA ldi regA,(1<<CLKPCE) ; enable the clock prescaler sts CLKPR,regA ; for 4 cycles clr regA sts CLKPR,regA ; and div factor to 1 clr zero ldi regA,1 mov justone,regA cbi DDRB,SGA cbi DDRB,SGB rcall start_count ;init compteur loop: BRTC loop clt ;Traitement du compteur après modification de la valeur rjmp loop ;**************************************************** ;start_count: configure int0 ;**************************************************** start_count: cli ldi regA,(0<<ISC01) | (1<<ISC00) ;Any logical change on INT0 generates an interrupt request. out MCUCR,regA ldi regA,(1<<INTF0) | (0<<PCIE) ; INT0: External Interrupt Request 0 Enable out GIMSK,regA clt ;Flag T=0 clr countLL clr countLH clr countHL clr countHH sei ret ;**************************************************** ; Interruption 0 ;**************************************************** VECT_INT0: set ;Spécifie le changement du flag T=1 in savereg,SREG ;Avant sauvegarde push regA clr regA sbic PINB,SGB ;skip B=0 inc regA sbic PINB,SGA ;skip A=0 inc regA SBRC regA,0 ; rjmp subLL addLL: add countLL,justone adc countLH,zero adc countHL,zero adc countHH,zero rjmp end_int0 subLL: sub countLL,justone sbc countLH,zero sbc countHL,zero sbc countHH,zero end_int0: pop regA out SREG,savereg reti
volatile int compteur = 0; //Position (en nombre de pas) du codeur volatile bool flagT=False; //Booléen en cas de changement de position volatile float vit = 0; // Vitesse (en nombre de pas par seconde) du codeur volatile unsigned long t = 0; // temps "courant" (en microsecondes) void setup(){ pinMode(2, INPUT); //A pinMode(3, INPUT); //B attachInterrupt(0, Int_Calc, CHANGE); //int0 sur P2 Serial.begin(115200); Serial.println("Start"); t = micros(); // Initialisation du temps "courant" } void loop(){ if (flagT){ //traitement en cas de déplacement ici Serial.print(compteur); Serial.print(" "); Serial.println(vit); flagT=False; } } void Int_Calc(){ unsigned long dt = micros() - t; // Temps écoulé depuis le dernier front t += dt; flagT=True; if(digitalRead(2) == digitalRead(3)){ compteur++; }else{ compteur--; } if (dt > 0) { vit = 1e6/dt; // Calcul de la vitesse (ici en pas par seconde) } }
Tous les x millisecondes, faire : erreur = consigne - mesure; somme_erreurs += erreur; variation_erreur = erreur - erreur_précédente; commande = Kp * erreur + Ki * somme_erreurs + Kd * variation_erreur; erreur_précédente = erreur
Kp=4. Ki=0. Kd=0. encoderval=0 consigne=384*4 commande_max=1000. commande=1. erreur_precedente = 0 somme_erreurs=0 while encoderval<>consigne: encoderval-=(commande/abs(commande))*1 #commande pour la variation erreur=encoderval-consigne somme_erreurs += erreur variation_erreur = erreur - erreur_precedente commande = (Kp * erreur) + (Ki * somme_erreurs) + (Kd * variation_erreur) if abs(commande)>1000: commande=(commande/abs(commande))*1000 print (("commande "+str(commande)+" encoderval "+str(encoderval))) erreur_precedente = erreur
Performances rapides (1/4 du rapport d'amortissement) | |||||
---|---|---|---|---|---|
Type de contrôle | $K_P$ | $T_I$ | $T_D$ | $K_I$ | $K_D$ |
P | $0,5\cdot K_U$ | - | - | - | - |
PI | $0,45\cdot K_U$ | $0,83\cdot T_U$ | - | $0,54\dfrac{K_U}{T_U}$ | - |
PD | $0,8\cdot K_U$ | - | $0,125\cdot T_U$ | - | $0,1\cdot K_U\cdot T_U$ |
PID | $0,6\cdot K_U$ | $0,5\cdot T_U$ | $0,125\cdot T_U$ | $1,2\dfrac{K_U}{T_U}$ | $0,075\cdot K_U\cdot T_U$ |
Performances normales (du dépassement) | |||||
P | $0,2\cdot K_U$ | - | - | - | - |
PI | $0,18\cdot K_U$ | $0,83\cdot T_U$ | - | - | - |
PID | $0,25\cdot K_U$ | $0,5\cdot T_U$ | $0,125\cdot T_U$ | - | - |
lentes (peu de dépassement) | |||||
P | $0,13\cdot K_U$ | - | - | - | - |
PI | $0,13\cdot K_U$ | $0,83\cdot T_U$ | - | - | - |
PID | $0,15\cdot K_U$ | $0,5\cdot T_U$ | $0,125\cdot T_U$ | - | - |
lentes (aucun de dépassement) | |||||
PID | $0,2\cdot K_U$ | $0,5\cdot T_U$ | $0,33\cdot T_U$ | $0,4\dfrac{K_U}{T_U}$ | $0,066\cdot K_U\cdot T_U$ |