Code source
La librairie RpiMotorLib pour Python 3 permet de piloter très simplement les moteurs pas à pas (pilote ULN2003, L298N, A4988, DRV8825, A3967 ou TB6612FNG) et les moteurs à courant continu via le GPIO du Raspberry Pi. Les moteurs pas à pas sont très largement utilisés pour réaliser les mouvements des axes des imprimantes 3D, des graveurs laser et commandes numériques (CNC).
Pour ce tutoriel, nous allons utiliser un moteur pas à pas Nema 17 (précisément 17HS4401) piloté par un micro-contrôleur A4988, deux composants très largement employés dans les imprimantes 3D et CNC à assembler soi-même.
Sommaire
- 0.1 Installer les librairies RpiMotorLib et Flask
- 0.2 Que peut-on piloter avec la librairie RpiMotorLib ?
- 0.3 Liste des fonctions proposées par la librairie
- 0.4 Remarque concernant l’arrêt des mouvements des moteurs pas à pas
- 0.5 Circuit
- 0.6 Exemple de projet Python permettant de déplacer un Moteur Nema 17
- 0.7 Explication du code
- 1 Hello World
Installer les librairies RpiMotorLib et Flask
Pour pouvoir fonctionner, la librairie RpiMotorLib nécessite Python 3.5 ou supérieur. La version Desktop de Raspberry Pi OS est installée avec les versions 2.7 et 3.7 ou ultérieures. Pour vérifier que la version 3 est bien installée, exécutez la commande suivante dans un Terminal.
Si Python3 est correctement installé, vous devez obtenir le numéro de version en réponse.
python3 --version
Python 3.7.3
Pour installer les librairies Python, on aura besoin du script pip3. Pour vérifier qu’il est bien installé, exécuter cette commande qui doit vous renvoyer le chemin vers le script
pip3 --version
Si pip3 n’est pas installé, exécuter
sudo apt install python3-pip
Maintenant, on peut installer les librairies
sudo pip3 install rpimotorlib
python3 -m pip install Flask
Que peut-on piloter avec la librairie RpiMotorLib ?
La librairie développée par Gavin Lyons permet de piloter des moteurs pas à pas (stepper motors), des servo-moteurs et moteurs à courant continu. Pour chaque type de mouvement, plusieurs contrôleurs sont pris en charge. Voici la liste avec le renvoi vers la documentation en ligne pour le câblage et un petit exemple de code.
Moteurs pas à pas (Stepper motors)
Moteurs à courant continu (DC Motor)
Contrôleurs supportés par la librairie pour piloter les moteurs à courant continu
Liste des fonctions proposées par la librairie
Les fonctions proposées par la librairie varient en fonction de contrôleur utilisé et du type de moteur.
Classe | Fonction | Paramètres |
Code source du fichier RpiMotorLib.py | ||
BYJMotor | print_cursor_spin | Fonction dépréciée |
motor_run(gpiopins, wait=.001, steps=512, ccwise=False, verbose=False, steptype=”half”, initdelay=.001 ) |
GPIOPins type liste de 4 entiers longs. Broches du GPIO sur lesquels sont connectées le contrôleur.
wait type float, temps d’attente (en secondes) entre chaque pas (steps) steps. type int. Nombre de séquences d’étapes exécuter. La valeur par défaut est une révolution, 512 pour le 28BYJ-48. ccwise sens antihoraire par défaut. True pour inverser le sens verbose True pour activer la mise au point steptype type string. half par défaut. Type de pilote. 3 options : full (fullstep), half (half step), wave (wave drive) initdelay type float, 1ms par défaut. Délai d’attente après l’initialisation avant de lancer le mouvement. |
|
A4988
Contrôleurs supportés A4988 DRV8825 |
motor_go(clockwise=False, steptype=“Full”,steps=200, stepdelay=.005, verbose=False, initdelay=.05) | clockwise sens de rotation dans le sens des aiguilles d’une montre par défaut. True pour inverser
steptype chaîne, par défaut Full. Type de moteur pas à pas. 5 options Full, Half, 1/4, 1/8, 1/16, 1/32 steps entier. Nombre de pas à exécuter, 200 par défaut stepdelay type float, par défault 0.05 seconde. Temps d’attente entre chaque pas. verbose True pour activer les messages de mise au point initdelay type float, 0.05 s par défaut. Délai d’attente après l’initialisation avant de lancer le mouvement. |
Code source du fichier rpi_dc_lib.py | ||
L298NMDc
DRV8833NmDc |
initialisation(pin_one, pin_two, freq=50, verbose=False, name=”DCMotorY”) | pin_one type int, broche de direction connectée à IN1 ou IN3
pin_two type int, broche PWM du GPIO pour la vitesse connectée à IN2 ou IN4 Freq fréquence en Hz par défaut 50 verbose True pour activer les messages de mise au point Name aucune utilité |
forward(duty_cycle=50) | Marche avant | |
backward(duty_cycle=50) | Marche arrière | |
stop(duty_cycle=0) | Arrête le moteur | |
brake(duty_cycle=100) | Freine le moteur | |
cleanup(clean_up=False) | Libère le GPIO. A utiliser en cas de problème de communication | |
TranDc | initialisation(pin, freq=50, verbose=False) | Classe pour contrôler un moteur à courant continu via un transistor
pin type int, broche PWM du GPIO pour la vitesse connectée à IN2 ou IN4 Freq fréquence en Hz par défaut 50 verbose True pour activer les messages de mise au point |
TB6612FNGDc | initialisation(pin_one, pin_two, pwm_pin, freq=50, verbose=False, name=”DCMotorY”) | pin_one Broche GPIO connectée à AI1 ou BI1
pin_two Broche GPIO connectée à AI2 ou BI2 pwm_pin Broche GPIO connectée à PWA ou PWB Freq fréquence en Hz par défaut 50 verbose True pour activer les messages de mise au point Name aucune utilité |
standby(standby_pin, standby_on=True) | standby_pin Broche GPIO connectée à la broche standby du TB661FNG
Active / désactive le mode veille du contrôleur TB661FNG |
|
forward(duty_cycle=50) | Marche avant | |
backward(duty_cycle=50) | Marche arrière | |
stop(duty_cycle=0) | Arrête le moteur | |
brake(duty_cycle=100) | Freine le moteur | |
cleanup(clean_up=False) | Libère le GPIO. A utiliser en cas de problème de communication |
Remarque concernant l’arrêt des mouvements des moteurs pas à pas
Le librairie RpiMotorLib n’offre aucune méthode pour stopper le mouvement en cours un pour les moteurs pas à pas.
On ne pourra pas arrêter en cas d’urgence ou manuellement les mouvements gérés par les micro-contrôleurs BYJMotor, A4988 et DRV8825.
Attention également à ne pas débrancher les broches durant un mouvement. Cela peut endommager le GPIO du Raspberry Pi ou du micro-contrôleur.
Circuit
Le GPIO du Raspberry Pi (quelque soit le modèle et la génération) ne délivre pas suffisamment de puissance pour alimenter directement un moteur Nema (ou n’importe quel autre moteur d’ailleurs).
La contrôleur A4988 dispose d’une entrée 12V qu’il suffira d’alimenter à l’aide d’une batterie ou sur le secteur. L’A4988 doit également être alimenté en 5V. Si vous n’avez qu’un seul accessoire connecté au GPIO, le Raspberry Pi peut délivrer suffisamment de puissance.
Il existe des cartes d’alimentation multi-tension permettant de délivrer suffisamment de puissance pour ce type de montage.
N’oubliez pas de connecter les broches Reset et Sleep à l’aide d’un jumper sinon le micro-contrôleur reste en veille. La librairie RpiMotorLib ne permet pas de gérer la sortie de veille uniquement lorsqu’un mouvement est demandé. Cela signifie que le moteur reste sous tension en permanence.
Voici le repérage des broches en détail
Alimentation 12V | Broche A4988 |
+12V de la batterie ou de l’alimentation secteur | VMOT |
GND de la batterie ou de l’alimentation secteur | GND |
GPIO du Raspberry Pi (toute version) | |
5V du Raspberry Pi | VDD |
GND du Raspberry Pi | GND |
GPIO 21 | STP |
GPIO 20 | DIR |
Vers le moteur pas à pas
Généralement le moteur est livré avec un câble 4 broches muni d’un connecteur au pas de 2,54mm. Si le déplacement est inversé, inverser le connecteur ou modifiez le code Python |
1A, 1B, 2A, 2B |
GPIO 14 | MS1 |
GPIO 15 | MS2 |
GPIO 18 | MS3 |
Connecter les broches RESET et SLEEP ensembles |
Schéma de câblage du circuit
Exemple de projet Python permettant de déplacer un Moteur Nema 17
Ouvrez l’éditeur de code Thonny Python IDE accessible depuis le menu Programmation.
Coller le code Python ci-dessous
#! /usr/bin/python # -*- coding:utf-8 -*- from RpiMotorLib import RpiMotorLib from flask import Flask, render_template_string, redirect, request #define GPIO pins GPIO_pins = (14, 15, 18) # Microstep Resolution MS1-MS3 -> GPIO Pin direction= 20 # Direction Pin, step = 21 # Step Pin distance = 80 # Default move 1mm => 80 steps per mm # Declare an named instance of class pass GPIO pins numbers mymotortest = RpiMotorLib.A4988Nema(direction, step, GPIO_pins, "A4988") app = Flask(__name__) #HTML Code TPL = ''' Stepper Motor Controller Up Down 0.1 mm 1 mm 10 mm ''' @app.route("/") def home(): return render_template_string(TPL) @app.route("/setdistance", methods=["POST"]) def setdistance(): global distance global distance distance = int(request.form["distance"]) print("set distance to", distance) return redirect(request.referrer) @app.route("/up", methods=["POST"]) def up(): global distance print("Move up,", distance, "steps") mymotortest.motor_go(False, "Full" , distance, 0.01 , False, .05) return redirect(request.referrer) @app.route("/down", methods=["POST"]) def down(): global distance print("Move down,", distance, "steps") mymotortest.motor_go(True, "Full" , distance, 0.01 , False, .05) return redirect(request.referrer) # Run the app on the local development server if __name__ == "__main__": app.run()
Cliquer sur la flèche verte pour lancer le script
Ouvrir Chromium et saisir l’adresse http://127.0.0.1:5000 dans la barre d’adresse.
Utiliser le sélecteur pour choisir le déplacement à effectuer : 0.1mm, 1mm ou 10mm
Puis la direction du mouvement :
- UP pour monter
- DOWN pour descendre
Voici une petite vidéo de démonstration
https://projetsdiy.fr/data/uploads/2020/10/piloter-stepper-motor-nema-a4988-raspberry-pi.mp4?_=1
Comme nous l’avons vu au paragraphe précédent, on doit attribuer 5 broches au micro-contrôleur A4988. MS1, MS2, MS3, step et inversion de direction.
On créé ensuite un objet RpiMotorLib.A4988Nema que l’on pourra ensuite utiliser dans le code du projet
GPIO_pins = (14, 15, 18) # Microstep Resolution MS1-MS3 -> GPIO Pin
direction= 20 # Direction Pin,
step = 21 # Step Pin
mymotortest = RpiMotorLib.A4988Nema(direction, step, GPIO_pins, "A4988")
Explication du code
Nous allons créer une interface Web pour piloter le moteur Nema à l’aide de la librairie Flask.
from flask import Flask, render_template_string, redirect, request
Ici la page HTML est stocké directement dans la chaîne TPL. On importe la feuille de style Bootstrap 4.0 directement depuis internet. Pour changer de version, rendez-vous ici.
Avec Flask, il suffit de quelques lignes de code pour créer un serveur Web
app = Flask(__name__)
if __name__ == "__main__":
app.run()
Comme la plupart des framework HTML, Flask gère des points de sortie (endpoint), l’adresse de la page Web. Par défaut lorsqu’on arrive sur un site internet (la racine), la page se par /
On créé donc une route pour chaque page et chaque action soumise submit par un formulaire.
Le décorateur @ permet de spécifier un endpoint et la fonction (immédiatement après) à exécuter dès que la page est appelée par l’utilisateur. La méthode home renvoie la page principale dont le code source est stocké dans la chaine TPL au début du projet.
@app.route("/")
def home():
return render_template_string(TPL)
Le rendu des pages Web peut être fait de 3 manières
- Renvoyer directement le code HTML sous la forme d’une chaîne.
return "
Hello World
"
- Le code HTML est stocké dans une chaîne de caractères. Dans ce cas, on utilise la méthode render_template_string pour réaliser le rendu. C’est la solution utilisée dans le projet.
- A partir d’un fichier HTML stocké dans un fichier séparé à l’aide de la méthode render_template
On envoi les commandes au code Python à l’aide de requêtes HTTP de type POST. Pour cela, il suffit de placer les commandes (les boutons en l’occurence) dans un Formulaire.
Ici, le code du bouton UP qui permet de lancer le déplacement du moteur vers le haut.
Up
Lorsqu’on souhaite envoyer des paramètres au serveur, on peut par exemple utiliser l’argument value.
La méthode request.form([“name”]) permet de récupérer la valeur de l’argument coté serveur
distance = int(request.form["distance"])
On créé une nouvelle route /up qui accepte la méthode HTTP Post.
La distance à parcourir est stockée dans un variable globale distance. Pour récupérer la valeur de celle-ci dans la méthode up(), il faut faire précédé le nom de la variable par l’argument global afin d’indiquer à l’interpréteur Python qu’on souhaite accéder à la variable globale.
On utilise la méthode motor_go de la librairie RpiMotorLib pour exécuter le déplacement. Voici les paramètres nécessaires
- False indique le sens de rotation
- “Full” type de moteur
- Distance nombre de pas (step) à faire
- 0.01 délai d’attente entre chaque pas
- False exécution silencieuse de la fonction
- 0.05 secondes délai d’attente avant de lancer le mouvement
Inutile ici de redessiner la page HTML, on renvoi simplement l’utilisateur sur la page d’origine à l’aide de la méthode redirect(request.referrer).
@app.route("/up", methods=["POST"])
def up():
global distance
print("Move up,", distance, "steps")
mymotortest.motor_go(False, "Full" , distance, 0.01 , False, .05)
return redirect(request.referrer)
Comment calculer le nombre de pas par millimètre parcouru ?
C’est un problème récurrent en impression 3D et CNC. Heureusement, on trouve de nombreux outils pour nous aider. Tout d’abord ce résumé posté par J-Max sur le forum du site lesimprimantes3d.fr nous donne quelques bons conseils
- Transmission directe à courroie : steps_per_mm = (pas_moteur_par_tour * nb_de_micropas_driver) / (pas_courroie * nombre_de_dents_de_la_poulie)
- Transmission directe à vis : steps_per_mm = (pas_moteur_par_tour * nb_de_micropas_driver) / pas_du_filetage
- Extrudeur à entrainement direct (direct drive) : steps_per_mm = (pas_moteur_par_tour * nb_de_micropas_driver) / (diamètre_effectif_galet * pi)
- Extrudeur à réduction (geared) : steps_per_mm = (pas_moteur_par_tour * nb_de_micropas_driver) * (Nb_dents_plateau / nb_dents_pignon) / (diamètre_effectif_galet * pi)
Vous pouvez également utiliser ces calculateurs en ligne proposés par Prusa, le fabricant d’imprimantes 3D Espagnol bien connu
Mises à jour
20/10/2020 Publication de l’article
- ESP32, broches GPIO et fonctions associées. I/O, PWM, RTC, I2C, SPI, ADC, DAC
- ESP32-CAM. Broches et équipements ESP-EYE, AI Thinker, TTGO T-Camera, M5Stack Timer Camera…
- ESP32-CAM. Quel modèle choisir ? ESP-EYE, AI Thinker, TTGO T-Camera, M5Stack Timer Camera…
- M5Stack Atomic GPS. Tracker ESP32 TinyGPS++, export GPX sur carte SD, visualisation sur Google Maps ou VSCode
- Home Assistant. Installer le snap sur NAS Synology sur une machine virtuelle Ubuntu
Avez-vous aimé cet article ?
[Total: 0 Moyenne: 0]