Contrôle moteur pas à pas

Ce tutoriel explique comment faire tourner un moteur pas à pas sous MicroPython.

Description

Un moteur pas à pas est un composant capable de convertir un signal électrique en un déplacement angulaire. Ce type de moteur peut effectuer des mouvements très précis. Pour cette raison il est utilisé en robotique, dans les imprimantes (3D ou pas), les disques durs, etc. Il est en contrepartie plus difficile à commander et moins rapide que d’autres types de moteurs. Sa vitesse angulaire est déterminée par la fréquence et le nombre des impulsions de commande.

Le rotor du moteur est à aimants permanents tandis que son stator dispose de 4 bobines réparties par paires. Le schéma qui suit illustre cette architecture et son principe de fonctionnement :

Principe moteur pas à pas

Chaque axe A, B, C, D fait tourner le moteur en fonction de son niveau d’alimentation. A noter que l’on alimente seulement un axe en même temps sous peine de bloquer le moteur.

Fonctionnement moteur pas à pas

Ainsi si on veut faire tourner le moteur dans le sens horaire on l’alimente dans cet ordre : A –> B –> C –> D –> A et ainsi de suite.

A l’inverse si on veut faire tourner le moteur dans le sens anti-horaire on l’alimente dans cet ordre : D –> C –> B –> A –> D et ainsi de suite.

Afin d’améliorer la stabilité du moteur mais aussi pour avoir une position intermédiaire entre deux axes, on peut se permettre d’alimenter deux axes en même temps dans l’ordre suivant : A –> AB –> B –> BC –> C –> CD –> D –> DA –> A et ainsi de suite. On peut inverser cette séquence pour faire tourner le moteur dans le sens opposé.

Le moteur que nous utilisons dans cet exercice dispose de 32 pôles magnétiques donc un seul cercle nécessite 32 pas. La sortie du moteur est connectée à plusieurs engrenages réducteurs avec un ratio de 1/64. En prenant en compte les engrenages on a donc 32*64 = 2048 pas pour faire un cercle d’où la grande précision du moteur.

En plus du moteur pas à pas nous utilisons un driver pour moteur pas à pas. Il a pour but de convertir un signal de faible puissance en signal de forte puissance pour contrôler le moteur. Nous reviendrons en détail sur ce composant dans la partie dédiée au montage.

Montage

Prérequis :

  1. La carte NUCLEO-WB55
  2. Un moteur pas à pas (de référence 28BYJ-48)
  3. Un driver pour moteur pas à pas (de référence ULN2003)
  4. Une alimentation externe (batterie ou pile)
Schéma de montage moteur pas à pas

La correspondance entre les composants est la suivante :

Driver moteur NUCLEO-WB55 Alim externe
IN1 D3  
IN2 D2  
IN3 D1  
IN4 D0  
GND   GND
+   +

Le code MicroPython

Vous pouvez télécharger les scripts MicroPython de ce tutoriel (entre autres) en cliquant ici.

Le but de ce programme est de contrôler le moteur en le faisant tourner dans les deux sens. On souhaite :

  • mettre en marche/arrêt le moteur en fonction de l’appui sur le bouton SW1. On allumera la LED rouge pour prévenir l’utilisateur que le moteur est éteint.
  • faire tourner le moteur dans le sens horaire/anti-horaire en fonction de l’appui sur le bouton SW2. On allumera la LED verte ou bleue en selon le sens de rotation.

Les boutons poussoirs seront gérés avec des interruptions.

Editez maintenant le script main.py :

Etape 1 : On importe les bibliothèques dans notre code.

from pyb import Pin, Timer
from time import sleep_ms
import gc # Ramasse miettes, pour éviter de saturer la mémoire

Etape 2 : On définit des variables globales qui nous serviront à récupérer l’état des boutons poussoirs. SW1 modifiera la variable etat_moteur tandis que SW2 modifiera la variable sens_moteur.

# Variables globales
motor_state = 0
motor_rotation = 0

Etape 3 : On fait l’initialisation des composants. Pour le moteur on définit les 4 pattes puis on les enregistre dans un tableau moteur qui nous permettra de simplifier le code.

# BP (en entrée + pull up)
sw1 = pyb.Pin('SW1')
sw1.init(pyb.Pin.IN, pyb.Pin.PULL_UP, af=-1)
sw2 = pyb.Pin('SW2')
sw2.init(pyb.Pin.IN, pyb.Pin.PULL_UP, af=-1)

# Initialisation des LED de la carte NUCLEO
blue_led = pyb.LED(3)
green_led = pyb.LED(2)
red_led = pyb.LED(1)

# GPIO qui controle le relais/transistor
A = pyb.Pin('D0', Pin.OUT_PP)
B = pyb.Pin('D1', Pin.OUT_PP)
C = pyb.Pin('D2', Pin.OUT_PP)
D = pyb.Pin('D3', Pin.OUT_PP)

motor_pin = (A, B, C, D)

Etape 4 : Afin de contrôler le moteur à n’importe quel instant on gère les boutons poussoirs avec des interruptions qui mettront à jour les variables globales définies précédemment.

# Interruption de SW1
def ITbutton1(line):
	# Variables globales
	global motor_state
	# Etat moteur à 0 ou 1
	if(motor_state == 1):
		motor_state = 0
	else:
		motor_state = 1

# Interruption de SW2
def ITbutton2(line):
	# Variables globales
	global motor_rotation
	# Sens moteur à 0 (sens horaire) ou 1 (sens anti-horaire)
	if(motor_rotation == 1):
		motor_rotation = 0
	else:
		motor_rotation = 1
	# Faire un reset du moteur
	motor_stop()

# Initialisation des vecteurs d'interruption
irq_1 = pyb.ExtInt(sw1, pyb.ExtInt.IRQ_FALLING, pyb.Pin.PULL_UP, ITbutton1)
irq_2 = pyb.ExtInt(sw2, pyb.ExtInt.IRQ_FALLING, pyb.Pin.PULL_UP, ITbutton2)

Etape 5 : On crée une fonction pour stopper le moteur. Celle-ci met tout simplement à l’état “bas” les alimentations des axes du moteur.

def motor_stopped():
	# Gestion des LED
	blue_led.off()
	green_led.off()
	red_led.on()
	# Eteind toutes les sorties
	for i in range(0, 4, 1):
		motor_pin[i].low()

Etape 6 : On crée une deuxième fonction pour faire tourner le moteur. Elle reçoit en paramètre le sens de rotation (0 ou 1) et la temporisation de la vitesse, qui fixe la vitesse de rotation (plus TempoVitesse est petite, plus la rotation est rapide). On fait tourner le moteur selon la séquence suivante : A –> AB –> B –> etc. Ce traitement est assuré par la boucle for qui contrôle chaque axe.

def motor_running(direction, TempoSpeed):

	i = 0

	#Tourner dans le sens horaire
	if(direction == 0):
		# Gestion des LED
		blue_led.off()
		green_led.on()
		red_led.off()
		# Dans le sens horaire
		for i in range(0, 4, 1):
			# Allume le segment 1
			motor_pin[i].on()
			sleep_ms(TempoSpeed)
			# Allume le segment 2
			if(i == 3):
				motor_pin[0].on()
			else:
				motor_pin[i+1].on()
			sleep_ms(TempoSpeed)
			# Eteind le segment 1
			motor_pin[i].off()
			sleep_ms(TempoSpeed)
	
	#Tourner dans le sens anti-horaire
	if(direction == 1):
		# Gestion des LED
		blue_led.on()
		green_led.off()
		red_led.off()
		# Dans le sens anti-horaire
		for i in range(3, -1, -1):
			# Allume le segment 2
			motor_pin[i].on()
			sleep_ms(TempoSpeed)
			# Allume le segment 1
			if(i == 0):
				motor_pin[3].on()
			else:
				motor_pin[i-1].on()
			sleep_ms(TempoSpeed)
			# Eteind le segment 2
			motor_pin[i].off()
			sleep_ms(TempoSpeed)

Etape 7 : Finalement on assigne à la variable TempoVitesse une valeur de 3 millisecondes. Cette variable permet de faire varier le délai de rotation du moteur. Si on augmente sa valeur le moteur va mettre (encore) plus de temps pour tourner.

# Temporisation de la vitesse de rotation du moteur. /!\ ne peut être inférieure à 3ms /!\
TempoSpeed = 3

# Boucle infinie
while True:

	if(motor_state == 0):
		motor_stopped()
		
	if(motor_state == 1):
		motor_running(motor_rotation, TempoSpeed)

	# Appel du ramasse-miettes
	gc.collect()

Résultat

Il ne vous reste plus qu’à enregistrer le code et redémarrer la carte NUCLEO-WB55. La LED rouge de la carte s’allume indiquant que le moteur est à l’arrêt. Appuyez sur un des boutons poussoirs SW1 ou SW2 pour faire tourner le moteur. Vous pouvez également vous amuser à changer la valeur de la variable tempo_vitesse et observer le comportement du moteur.