Publié le 15 avril 2022 - par

Piloter un moteur Pas à Pas avec le Raspberry Pi et un driver A4988

J’ai une idée qui me trotte dans la tête depuis un moment, c’est de réaliser une « poursuite » de satellite pilotée par un Raspberry Pi. L’idée c’est de faire tourner le programme Gpredict sur le Pi, de récupérer les coordonnées et de piloter un duo de moteurs pas à pas pour diriger une (petite) antenne vers un satellite. La première étape est de piloter un moteur pas à pas à partir du Raspberry Pi.

Article présenté aux JMRAF 2022

En direct le 16 avril. Je présente cette application du Raspberry Pi vers 18h30 (H de Paris). Vous pouvez gagner mon livre « Raspberry Pi 4 » offert par les Editions ENI.

Commander un moteur pas à pas avec le Raspberry Pi

Le synoptique du montage est le suivant :

Le Raspberry Pi envoie au driver A4988 une direction (sens horaire CW, ou anti horaire CCW) et sur un autre GPIO on sort des impulsions qui provoqueront chacune une avance d’un pas.

Le nombre de pas par tour est déterminé par les entrées MS1 à MS3. Par d&f&ut le moteur PaP fait un tour en 200 pas (de 1,8°) mais on peut modifier le nombre de micro-pas fournis par le driver pour affiner le déplacement.

Le montage tel qu’il sera réalisé est présenté ici avec Fritzing. Le module supporte une alimentation de puissance pour le moteur comprise entre 8 et 35 volts. Ici j’ai opté pour une alimentation 12 volts, suffisante pour fournir le courant souhaité au moteur.

La câblage une fois réalisé donne ceci. J’ai muni le moteur PaP d’une flèche en impression 3D pour vérifier que ses déplacements sont conformes à ce qui est attendu

Ici le module A4988 avant la pose du radiateur sur le circuit de commande. La potentiomètre sert à régler le courant qui circule dans les bobines du moteur car le moteur est alimenté en courant, pas en tension. C’est le module qui va limiter le courant envoyé dans les bobines du moteur. Ne pas oublier que tant que le montage est alimenté le moteur est maintenu en position par le courant qui circule dans les bobines… Donc… il chauffe. Vous pouvez consulter la notice du A4988 en cliquant sur ce lien.

Détecteur de zéro

Le moteur pas à pas n’a pas de repère lors de sa mise sous tension. Sur les imprimantes 3D par exemple, on utilise

Un switch optique

« Fourchette » optique utilisée comme détecteur. D’un côté une LED envoie un faisceau lumineux, de l’autre un phototransistor le reçoit. Quand le faisceau est interrompu, la sortie change d’état.

Dans le monde des makers, on retrouve ce genre de détecteur sur les imprimantes 3D, par exemple. Ici une Anycubic Viper.

Le détecteur optique utilisé ici, lors des tests. Une LED s’éteint quand le faisceau est interrompu.

Premiers essais sur la barre fixée au moteur PaP.

Un switch mécanique

Switch mécanique, ici un swicth équipé d’un rouleau.

Exemple d’utilisation du switch mécanique (sur mon imprimante 3D). Lorsque le chariot appuie sur le switch, la carte mère considère que c’est la position Zero. Il y a un switch sur chacun des 3 axes.

Les programmes

Programme de démo

#!/usr/bin/python3             
# Pour exécuter le prog. en ligne de commande
from time import sleep         # Importer la bibliothèque de gestion du temps 
import RPi.GPIO as GPIO        # Importer la bibliothèque de gestion des GPIO

STEP = 14                      # La commande de pas est reliée au GPIO 14
DIR = 15                       # La commande de direction est reliée au GPIO 15
vitesse = 0.0005

GPIO.setmode(GPIO.BCM)         # Paramétrage de la numérotation des GPIO en mode BCM
GPIO.setwarnings(False)        # Ne pas tenir comte des alertes
GPIO.setup(STEP, GPIO.OUT)     # GPIO STEP configuré en sortie
GPIO.setup(DIR, GPIO.OUT)      # GPIO DIR configuré en sortie

# Tourner d'un nombre de pas en CW ou CCW
def tourne(pas, sens, vitesse):
    # Sens de rotation
    if (sens == "CW"):
        GPIO.output(DIR, GPIO.HIGH)
    else:
        GPIO.output(DIR, GPIO.LOW)
    # Avancer du nombre de pas
    for x in range(pas):
        GPIO.output(STEP, GPIO.HIGH)
        sleep(vitesse)
        GPIO.output(STEP, GPIO.LOW)
        sleep(vitesse)



while True:
    # On travaille en 1/16 de pas soit 3200 micropas par tour
    for x in range(3200):
        GPIO.output(STEP, GPIO.HIGH)
        sleep(vitesse)
        GPIO.output(STEP, GPIO.LOW)
        sleep(vitesse)

    sleep(1)

    GPIO.output(DIR, GPIO.LOW)
    for x in range(3200):
        GPIO.output(STEP, GPIO.HIGH)
        sleep(vitesse)
        GPIO.output(STEP, GPIO.LOW)
        sleep(vitesse)
        
    sleep(1)	
    tourne(1600, "CW", vitesse)
    sleep(0.5)
    tourne(1600, "CCW", vitesse)
    sleep(1)	
    tourne(800, "CW", vitesse)
    sleep(0.5)
    tourne(800, "CW", vitesse)
    sleep(0.5)
    tourne(800, "CW", vitesse)
    sleep(0.5)
    tourne(800, "CW", vitesse)
    
    sleep(1)

Commande du moteur au clavier

#!/usr/bin/python3             
# Pour exécuter le prog. en ligne de commande  
from pynput import keyboard    # Bibliothèque de gestion clavier
from time import sleep         # Bibliothèque de gestion du temps
import RPi.GPIO as GPIO        # Bibliothèque de gestion des GPIO   

STEP = 14                      # La commande d'avance d'un pas est connectée à GPIO14  
DIR = 15                       # La commande du sens de rotation est connectée à GPIO15
vitesse = 0.0005               # Temps d'attente entre les pas : règle la vitesse

GPIO.setmode(GPIO.BCM)         # Utiliser la numérotation BCM pour les GPIO
GPIO.setwarnings(False)        # Ne pas afficher les alertes
GPIO.setup(STEP, GPIO.OUT)     # Paramétrer GPIO14 en sortie
GPIO.setup(DIR, GPIO.OUT)      # Paramétrer GPIO15 en sortie

# Tourner d'un nombre de pas en CW ou CCW à une vitesse donnée
def tourne(pas, sens, vitesse):
    # Sens de rotation
    if (sens == "CW"):
        GPIO.output(DIR, GPIO.HIGH)
    else:
        GPIO.output(DIR, GPIO.LOW)
    # Avancer du nombre de pas
    for x in range(pas):
        GPIO.output(14, GPIO.HIGH)
        sleep(vitesse)
        GPIO.output(14, GPIO.LOW)
        sleep(vitesse)
        
# Fonction appelée quand une touche est appuyée
def appui(key):
    try:
        print('Touche alphanumérique : {0} '.format(
            key.char))
    except AttributeError:
        print('Touche spéciale : {0}'.format(
            key))
        # Touche flèche gauche - Sens inverse des aiguilles d'une montre - 10 pas
        if (key == keyboard.Key.left):
            sens = "CCW"
            tourne(10,sens,vitesse) 
        # Touche flèche droite - Sens des aiguilles d'une montre - 10 pas
        elif (key == keyboard.Key.right):
            sens = "CW"
            tourne(10,sens,vitesse) 
        # Touche flèche haute - Sens inverse des aiguilles d'une montre - 100 pas
        elif (key == keyboard.Key.up):
            sens = "CCW"
            tourne(100,sens,vitesse) 
        # Touche flèche basse - Sens des aiguilles d'une montre - 100 pas
        elif (key == keyboard.Key.down):
            sens = "CW"
            tourne(100,sens,vitesse) 
        # Touche page haute - Sens inverse des aiguilles d'une montre - 800 pas = 1/4 de tour
        elif (key == keyboard.Key.page_up):
            sens = "CCW"
            tourne(800,sens,vitesse/10) 
        # Touche page basse - Sens des aiguilles d'une montre - 800 pas = 1/4 de tour
        elif (key == keyboard.Key.page_down):
            sens = "CW"
            tourne(800,sens,vitesse/10) 
           
# Fonction exécutée quand une touche est relachée
def relache(key):
    print('Key released: {0}'.format(
        key))
    # Si c'est la touche ESC on sort du programme
    if key == keyboard.Key.esc:
        # Stop listener
        print("Sortie du programme")
        GPIO.cleanup()
        return False

# Le listener collecte les événements et appelle les fonctions en callback
with keyboard.Listener(
        on_press = appui,
        on_release = relache) as listener:
    listener.join()
    

Et après ?

L’étape suivante sera de récupérer l’azimut d’un satellite dans Gpredict pour piloter le moteurs d’azimut. Actuellement j’ai testé plusieurs serveurs TCP (puisqu’on passe par un socket IP) dont celui de F6BVP. Mais après un moment Gpredict affiche une erreur de lecture de ca que renvoie le serveur et coupe la communication. Je n’ai pas trouvé comment maintenir la liaison… SI vous avez une solution, je suis preneur.

Vidéo

Programmes sur Github

https://github.com/framboise314/RasPi_PaP

Un coup de main SVP [RESOLU]

Merci à Frédéric qui a déverminé le dialogue entre Gpredict et le serveur TCP. Ça fonctionne maintenant. Le serveur est sur Github en version Py2 et Py3.
Le souci était que la fonction de Gpredict qui reçoit la réponse de rotctl (en fait ici le serveur TCP maison) zappe les 4 premiers caractères de la chaîne. Il faut donc renvoyer « xxxx0 » pour que ça fonctionne sans planter au bout de quelques erreurs…
BESOIN D’AIDE GPREDICT sur RASPI :Suite à la présentation de la commande d’un moteur pas à pas avec le Raspberry Pi lors des #jmraf2022, j’essaye vainement de récupérer les infos d’azimut depuis #Gpredict sur #RaspberryPi. J’utilise un serveur tcp minimum sur le raspberry pi. J’en ai trouvé plusieurs, très semblables mais aucun ne fonctionne correctement. Je ne vois pas ce que je fais comme conn… bêtise.Je lance Gpredict, choix d’un satellite visible, mise en route du contrôleur de rotor d’antenne.Dans une fenêtre de terminal, lancement du mini serveur TCPJ’engage le suivi sur Gpredict => connexion ok au serveur tcpJe lance le tracking sur le contrôleur de rotor de Gpredict. Les infos azimut+elevation arrivent bien au serveur mini tcp, qui renvoie les mêmes valeurs en réponse. Mais au bout d’un (court) moment Gpredict signale une erreur de reception des données, et le serveur annonce avoir reçu S\n et met fin à la liaison.J’ai essayé en python 2 et python 3, en fr_fr et en GB pour les locales (à cause du problème possible de . ou de , dans les nombres flottants mais c’est pareilJ’ai testé avec les serveurs tcp trouvés ici (très proches les uns des autres).Exemple serveur TCP : https://adventurist.me/posts/0136Programme de F6BVP :http://radiotelescope.over-blog.com/2020/09/mise-en-place-de-la-poursuite-en-azimut-et-elevation-avec-gpredict.htmlhttps://radiotelescopelavillette.wordpress.com/interface-rotor/Après c’est possible qu’ils aient testé avec une autre version de Gpredict, sur un PC Windows… il y a peu d’infos là dessus.Si quelqu’un a fait fonctionner cette liaison en interne sur RasPi, je suis preneur de toute info.

j’ai ouvert une page github ou toutes les infos seront publiées (avec le nom de tous les participants bien entendu) https://github.com/framboise314/RasPi_PaP

Sources

Lire touches clavier

:
https://www.delftstack.com/fr/howto/python/python-detect-keypress/

Detect keypress in Python

Communication socket Python : https://info.blaisepascal.fr/nsi-sockets-python

Exemple serveur TCP : https://adventurist.me/posts/0136

Programme de F6BVP : https://radiotelescopelavillette.wordpress.com/interface-rotor/

http://radiotelescope.over-blog.com/2020/09/mise-en-place-de-la-poursuite-en-azimut-et-elevation-avec-gpredict.html

Protocole rotctld : http://manpages.ubuntu.com/manpages/trusty/man8/rotctld.8.html

Gérer les threads : http://www.xavierdupre.fr/app/teachpyx/helpsphinx/c_parallelisation/thread.html

 

 

 

À propos François MOCQ

Électronicien d'origine, devenu informaticien, et passionné de nouvelles technologies, formateur en maintenance informatique puis en Réseau et Télécommunications. Dès son arrivée sur le marché, le potentiel offert par Raspberry Pi m’a enthousiasmé j'ai rapidement créé un blog dédié à ce nano-ordinateur (www.framboise314.fr) pour partager cette passion. Auteur de plusieurs livres sur le Raspberry Pi publiés aux Editions ENI.

2 réflexions au sujet de « Piloter un moteur Pas à Pas avec le Raspberry Pi et un driver A4988 »

  1. Ping : Piloter un moteur pas à pas avec un Raspberry Pi et un driver A4988 - TUTO3D

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur la façon dont les données de vos commentaires sont traitées.