Les codeurs

Description des codeurs

Chaque roue étant équipée d’un codeur incrémental, il est donc possible de commander le mouvement en distance plutôt qu’en durée.

Attention : les contrôleurs des moteurs n’autorisent pas le freinage ! Il y a donc un fort risque de dépassement des positions visées !

 

Les disques des codeurs sont sur le même axe que les roues, et comportent 20 fentes :

Les deux barrières infrarouge des codeurs sont reliées aux ports numériques (mode entrée) suivants :

  • codeur Droit : GPIO7 (ou CE1 )
  • codeur Gauche : GPIO8 (ou CE0 )

 

Programmation en Python

Pour connaitre à chaque instant la position d’un codeur, il faut, pour chacun d’entre eux :

  1. initialiser une position angulaire (dans une variable),
  2. déterminer le sens de rotation (les codeurs de l’AlphaBot n’ont qu’une seule voie !),
  3. compter les impulsions (fronts montants et descendants du signal) en modifiant la valeur de la position angulaire.
Question
Les codeurs incrémentaux « double sens » sont dotés d’un double détecteur de front, déphasé d’un quart de période, afin de permettre le décodage du sens de rotation. Dans le cas d’un robot comme l’AlphaBot, comment peut-on connaitre le sens de rotation alors que les codeurs n’ont qu’un seul détecteur ?
CORRECTION :

Dans le cas d’un robot, le mouvement des roues est provoqué par le mouvement des moteurs. Et on connait le sens de rotation du moteur puisqu’ils sont pilotés par le programme Python ! Par conséquent, on sait s’il faut incrémenter (augmenter de 1) le compteur de position ou bien le décrémenter (diminuer de 1) !

[/su_private]

 

Gestion des interruptions

Une interruption est un arrêt temporaire de l’exécution normale d’un programme par le microprocesseur afin d’exécuter un autre programme (appelé service d’interruption). Les interruptions sont gérées par le gestionnaire d’événement.

Le service d’interruption est exécuté de manière asynchrone (on parle de thread séparé). Pour qu’il puisse être exécutée le plus fréquemment possible, il doit être très court, peu couteux en temps de calcul.

 

 

 

Initialisation

# Trois valeurs sont possibles : 
#   front montant : GPIO.RISING
#   front descendant : GPIO.FALLING
#   les deux : GPIO.BOTH
GPIO.add_event_detect(CH, GPIO.BOTH, callback = fct_interrupt, bouncetime = 75)

fct_interrupt(channel) est une fonction qui sera appelée à chaque fois que le port CH connaitra un front. L’argument channel est automatiquement passé à la fonction par le gestionnaire d’événement, il prend la valeur du numéro du port qui a déclenché l’événement.

Voici par exemple comment elle peut être définie :

def fct_interrupt(ch):
   print(ch) # affiche le numéro du port sur lequel s'est produit l'événement

Attention : elle doit être définie avant l’ajout de l’événement avec .add_event_detect() !

bouncetime est un paramètre de temporisation destiné à éviter l’effet de rebond, un phénomène fréquent lorsqu’il s’agit d’un bouton poussoir qui provoque le front du signal. La valeur de la temporisation nécessaire dépend de la technologie de ce qui fait commuter la tension (contact électrique, transistorTransistor Le transistor est le composant de base des ordinateurs, les microprocesseurs d'aujourd'hui en comportent plusieurs milliards, et leur progression dans le temps suit plus ou moins la loi de Moore. Inventé en 1947 par les Américains John Bardeen, William Shockley et Walter Brattain, le transistor fut alors un immense progrès car les premiers ordinateurs (antérieurs à cette date), étaient conçus à base de tubes électroniques (on parle aussi de tubes à vide), des composant beaucoup plus gros que les transistors. Dans un ordinateur, les transistors sont regroupés au sein de circuits intégrés : un très grand nombre de transistors, ainsi que leurs connexions, sont gravés sur des plaques de silicium. Dans un ordinateur les transistors se comportent comme des interrupteurs (ou des contacts) : voir article sur les booléens., …). Il faut la spécifier en millisecondes.

 

Suppression

On peut à tout moment annuler (ou simplement interrompre) la détection d’événements :

GPIO.remove_event_detect(CH)

Exercice : codeurs

On décide, au sein d’un module nommé alphabot , de créer des variables globales posD et posG permettant de mémoriser les positions angulaires absolues des deux roues :

# Positions angulaires des roues (en "pas"), initialisées à 0 
posD, posG = 0, 0

En utilisant, comme un module, le programme écrit pour les moteurs (à modifier selon les besoins), écrire en Python (puis tester !) la fonction front_codeur() , qui doit permettre de modifier les variables mémorisant les positions angulaires des deux roues.
CORRECTION

# -*- coding:utf-8 -*-

import RPi.GPIO as GPIO
import time

from moteurs import *

GPIO.setmode(GPIO.BCM)

# Ports des codeurs
CDG = 7  # gauche
CDD = 8  # droite

GPIO.setup(CDG, GPIO.IN)
GPIO.setup(CDD, GPIO.IN)

# Positions angulaires des roues (en "pas"), initialisées à 0
posD, posG = 0, 0


########################################################################
# 
########################################################################
def front_codeur(port):
	global posD, posG
	if port == CDD:
		if get_vitesse('D') > 0:
			posD += 1
		elif get_vitesse('D') < 0:
			posD -= 1
	elif port == CDG:
		if get_vitesse('G') > 0:
			posG += 1
		elif get_vitesse('G') < 0:
			posG -= 1

	
GPIO.add_event_detect(CDG, GPIO.BOTH, callback = front_codeur, 
						bouncetime = 5)
GPIO.add_event_detect(CDD, GPIO.BOTH, callback = front_codeur, 
						bouncetime = 5)



########################################################################
# Procédures de test du module
########################################################################
if __name__ == "__main__":
	rot_moteur('G', 20)
	time.sleep(1)
	rot_moteur('G', -20)
	time.sleep(1)
	rot_moteur('G', 0)
	
	rot_moteur('D', 100)
	time.sleep(1)
	rot_moteur('D', -50)
	time.sleep(1)
	
	rot_moteur('D', 0)

	GPIO.cleanup()

Exercice : codeurs (suite)

Comme pour les positions, on crée au sein du module alphabot , deux variables globales vitD et vitG permettant de mémoriser les vitesses angulaires des deux roues :

# Vitesses angulaires des roues (en "pas/seconde"), initialisées à 0 
vitD, vitG = 0, 0

Modifier la fonction front_codeur() de sorte qu’elle calcule en plus la vitesse angulaire, en pas/seconde, de la roue droite (roue == ‘D’ ) ou gauche (roue == ‘G’ )
On aura besoin de la fonction time.clock() (voir article sur le temps).
CORRECTION

# -*- coding:utf-8 -*-

import RPi.GPIO as GPIO
import time

from moteurs import *

GPIO.setmode(GPIO.BCM)

# Ports des codeurs
CDG = 7  # gauche
CDD = 8  # droite

GPIO.setup(CDG, GPIO.IN)
GPIO.setup(CDD, GPIO.IN)

# Positions angulaires des roues (en "pas"), initialisées à 0
posD, posG = 0, 0

# Vitesses angulaires des roues (en "pas/seconde"), initialisées à 0 
vitD, vitG = 0, 0

# Une variable pour mesurer le temps écoulé entre deux fronts
t = time.clock()

########################################################################
# 
########################################################################
def front_codeur(port):
	global posD, posG, vitD, vitG, t

	t1 = time.clock()
	dt = t1 - t
	t = t1

	if port == CDD:
		if get_vitesse('D') > 0:
			posD += 1
			vitD = 1/dt
		elif get_vitesse('D') < 0:
			posD -= 1
			vitD = -1/dt
	
	elif port == CDG:
		if get_vitesse('G') > 0:
			posG += 1
			vitG = 1/dt
		elif get_vitesse('G') < 0:
			posG -= 1
			vitG = -1/dt

	
GPIO.add_event_detect(CDG, GPIO.BOTH, callback = front_codeur, 
						bouncetime = 5)
GPIO.add_event_detect(CDD, GPIO.BOTH, callback = front_codeur, 
						bouncetime = 5)



########################################################################
# Procédures de test du module
########################################################################
if __name__ == "__main__":
	rot_moteur('G', 20)
	time.sleep(1)
	rot_moteur('G', -20)
	time.sleep(1)
	rot_moteur('G', 0)
	
	rot_moteur('D', 100)
	time.sleep(1)
	rot_moteur('D', -50)
	time.sleep(1)
	
	rot_moteur('D', 0)

	GPIO.cleanup()

 

Asservissement en position

On a vu que la commande de rotation des roues basée sur le temps n’était pas fiable, car pour un consigne de vitesse donnée, les vitesses effectives des roues varient.

De plus, les moteurs sont incapables de freiner.

On se propose de réaliser un asservissement en position des roues.

Exercice : asservissement en position
Écrire une fonction position_P(roue, pos, P) permettant de contrôler le mouvement d'une roue ('D' ou 'G' ), et lui faisant parcourir un déplacement pos (pas de codeur - nombre entier relatif) en utilisant un correcteur proportionnel de gain P (valeur à ajuster).
CORRECTION
def position_P(roue, pos, P = 10):
	""" 
	    
	"""
	try:
		while True:
			if roue == 'D':
				ecart = pos - posD
			else:
				ecart = pos - posG
			vit = P*ecart
			if vit > 100:
				vit = 100
			elif vit < -100:
				vit == -100
			rot_moteur(roue, vit)
	except KeyboardInterrupt:
		pass

[/_su_spoiler]
Exercice : asservissement en position (suite)
Écrire une fonction permettant de faire avancer le robot, chacune des deux roues étant commandée individuellement, en programmation parallèle.
Correction
[/su_private]
Écrire une fonction permettant d’asservir le mouvement des roues en vitesse. Ainsi, le robot devrait aller en ligne droite quant les deux consigne de vitesse sont égales (contrairement au fonctionnement en boucle ouverte).
Correction
[/su_private]
Après avoir observé le comportement du robot et identifié les problèmes, améliorer la fonction position_P() en réalisant un correcteur plus performant.
Correction
[/su_private]

 

Vous aimerez aussi...

Laisser un commentaire

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