TPE - Voitures autonomes
La voiture adapte sa vitesse en fonction de la couleur de la ligne.
​
Nous avons créé un programme et un circuit pour mêler les capteurs suiveurs de ligne, le capteur de couleur et les moteurs. Ainsi, nous souhaitons que la voiture adapte sa vitesse en fonction de la couleur de la ligne qu'elle suit.
​
sudo nano circuit_couleur.py
# Importation des librairies pour controle du port GPIO
import RPi.GPIO as GPIO
import time
import threading
import pigpio
import sys
# Definition de la classe du capteur de couleur
class sensor(threading.Thread):
"""
This class reads RGB values from a TCS3200 colour sensor.
GND Ground.
VDD Supply Voltage (2.7-5.5V)
/OE Output enable, active low. When OE is high OUT is disabled
allowing multiple sensors to share the same OUT line.
OUT Output frequency square wave.
S0/S1 Output frequency scale selection.
S2/S3 Colour filter selection.
OUT is a square wave whose frequency is proprtional to the
intensity of the selected filter colour.
S2/S3 selects between red, green, blue, and no filter.
S0/S1 scales the frequency at 100%, 20%, 2% or off.
To take a reading the colour filters are selected in turn for a
fraction of a second and the frequency is read and converted to
Hz.
"""
def __init__(self, pi, OUT, S2, S3, S0=None, S1=None, OE=None):
"""
The gpios connected to the sensor OUT, S2, and S3 pins must
be specified. The S2, S3 (frequency) and OE (output enable)
gpios are optional.
"""
threading.Thread.__init__(self)
self._pi = pi
self._OUT = OUT
self._S2 = S2
self._S3 = S3
self._mode_OUT = pi.get_mode(OUT)
self._mode_S2 = pi.get_mode(S2)
self._mode_S3 = pi.get_mode(S3)
pi.write(OUT, 0) # disable output gpio
pi.set_mode(S2, pigpio.OUTPUT)
pi.set_mode(S3, pigpio.OUTPUT)
self._S0 = S0
self._S1 = S1
self._OE = OE
if (S0 is not None) and (S1 is not None):
self._mode_S0 = pi.get_mode(S0)
self._mode_S1 = pi.get_mode(S1)
pi.set_mode(S0, pigpio.OUTPUT)
pi.set_mode(S1, pigpio.OUTPUT)
if OE is not None:
self._mode_OE = pi.get_mode(OE)
pi.set_mode(OE, pigpio.OUTPUT)
pi.write(OE, 0) # enable device
self.set_sample_size(50)
self._period = 0.25 # 4 readings per second
self.set_frequency(1) # 2%
self._rgb_black = [0]*3
self._rgb_white = [10000]*3
self._set_filter(3) # Clear
self.Hertz=[0]*3 # latest triplet
self._Hertz=[0]*3 # current values
self.tally=[1]*3 # latest triplet
self._tally=[1]*3 # current values
self._delay=[0.1]*3 # tune delay to get TALLY readings
self._edge = 0
self._start_tick = 0
self._last_tick = 0
self._cb_OUT = pi.callback(OUT, pigpio.RISING_EDGE, self._cbf)
self._cb_S2 = pi.callback(S2, pigpio.EITHER_EDGE, self._cbf)
self._cb_S3 = pi.callback(S3, pigpio.EITHER_EDGE, self._cbf)
self._read = True
self.daemon = True
self.start()
def _cbf(self, g, l, t):
if g == self._OUT:
if self._edge == 0:
self._start_tick = t
else:
self._last_tick = t
self._edge += 1
else: # Must be transition between colour samples
if g == self._S2:
if l == 0: # Clear -> Red
self._edge = 0
return
else: # Blue -> Green
colour = 2
else:
if l == 0: # Green -> Clear
colour = 1
else: # Red -> Blue
colour = 0
if self._edge > 1:
self._edge -= 1
td = pigpio.tickDiff(self._start_tick, self._last_tick)
self._Hertz[colour] = (1000000 * self._edge) / td
self._tally[colour] = self._edge
else:
self._Hertz[colour] = 0
self._tally[colour] = 0
self._edge = 0
# Have we a new set of RGB?
if colour == 1:
for i in range(3):
self.Hertz[i] = self._Hertz[i]
self.tally[i] = self._tally[i]
def run(self):
while True:
if self._read:
next_time = time.time() + self._period
self._pi.set_mode(self._OUT, pigpio.INPUT) # enable output gpio
# The order Red -> Blue -> Green -> Clear is needed by the
# callback function so that each S2/S3 transition triggers
# a state change. The order was chosen so that a single
# gpio changes state between the change in colour to be
# sampled.
self._set_filter(0) # Red
time.sleep(self._delay[0])
self._set_filter(2) # Blue
time.sleep(self._delay[2])
self._set_filter(1) # Green
time.sleep(self._delay[1])
self._pi.write(self._OUT, 0) # disable output gpio
self._set_filter(3) # Clear
delay = next_time - time.time()
if delay > 0.0:
time.sleep(delay)
# Tune the next set of delays to get reasonable results
# as quickly as possible.
for c in range(3):
# Calculate dly needed to get a decent number of samples
if self.Hertz[c]:
dly = self._samples / float(self.Hertz[c])
# Constrain dly to reasonable values
if dly < 0.001:
dly = 0.001
elif dly > 0.5:
dly = 0.5
self._delay[c] = dly
else:
time.sleep(0.1)
def pause(self):
"""
No more readings will be made until resume is called.
"""
self._read = False
def resume(self):
"""
Resumes readings (after a call to pause).
"""
self._read = True
def get_Hertz(self):
"""
Returns the latest Hertz reading.
"""
return self.Hertz
def get_rgb(self, top=255):
"""
Returns the latest RGB reading.
The raw colour Hertz readings are converted to RGB values.
By default the RGB values are constrained to be between
0 and 255. A different upper limit can be set by using
the top parameter.
"""
rgb = [0]*3
for c in range(3):
v = self.Hertz[c] - self._rgb_black[c]
s = self._rgb_white[c] - self._rgb_black[c]
p = top * v / s
if p < 0:
p = 0
elif p > top:
p = top
rgb[c] = p
return rgb
def cancel(self):
"""
Cancels the sensor and release all used resources.
"""
self._cb_S3.cancel()
self._cb_S2.cancel()
self._cb_OUT.cancel()
self.set_frequency(0) # off
self._set_filter(3) # Clear
self._pi.set_mode(self._OUT, self._mode_OUT)
self._pi.set_mode(self._S2, self._mode_S2)
self._pi.set_mode(self._S3, self._mode_S3)
if (self._S0 is not None) and (self._S1 is not None):
self._pi.set_mode(self._S0, self._mode_S0)
self._pi.set_mode(self._S1, self._mode_S1)
if self._OE is not None:
self._pi.write(self._OE, 1) # disable device
self._pi.set_mode(self._OE, self._mode_OE)
def set_black_level(self, rgb):
"""
Sets the black level calibration.
"""
for i in range(3):
self._rgb_black[i] = rgb[i]
def set_white_level(self, rgb):
"""
Sets the white level calibration.
"""
for i in range(3):
self._rgb_white[i] = rgb[i]
def _set_filter(self, f):
"""
Set the colour to be sampled.
f S2 S3 Photodiode
0 L L Red
1 H H Green
2 L H Blue
3 H L Clear (no filter)
"""
if f == 0: # Red
S2 = 0; S3 = 0
elif f == 1: # Green
S2 = 1; S3 = 1
elif f == 2: # Blue
S2 = 0; S3 = 1
else: # Clear
S2 = 1; S3 = 0
self._pi.write(self._S2, S2); self._pi.write(self._S3, S3)
def get_frequency(self):
"""
Returns the current frequency scaling.
"""
return self._frequency
def set_frequency(self, f):
"""
Sets the frequency scaling.
f S0 S1 Frequency scaling
0 L L Off
1 L H 2%
2 H L 20%
3 H H 100%
"""
if f == 0: # off
S0 = 0; S1 = 0
elif f == 1: # 2%
S0 = 0; S1 = 1
elif f == 2: # 20%
S0 = 1; S1 = 0
else: # 100%
S0 = 1; S1 = 1
if (self._S0 is not None) and (self._S1 is not None):
self._frequency = f
self._pi.write(self._S0, S0)
self._pi.write(self._S1, S1)
else:
self._frequency = None
def set_update_period(self, t):
"""
Sets the period between RGB updates.
"""
if (t >= 0.1) and (t < 2.0):
self._period = t
def set_sample_size(self, samples):
if (samples < 10) or (samples > 1000):
samples = 50
self._samples = samples
# Acces au port GPIO avec la numerotation Broadcom
mode = GPIO.BCM
​
# Declaration des emplacements
#capteurC = 3
capteurG = 14
capteurD = 15
motor1A=16
motor1B=20
motor1E=21
motor2A=9
motor2B=10
motor2E=11
GPIO.setmode(mode)
GPIO.setwarnings(False)
GPIO.setup(motor1E,GPIO.OUT)
GPIO.setup(motor2E,GPIO.OUT)
motor1 = GPIO.PWM(motor1E,50)
motor2 = GPIO.PWM(motor2E,50)
vitesse = 50
RED=12
GREEN=13
BLUE=19
pi = pigpio.pi()
p = 0.333
# Bottom view
#
# GND VCC
# OE OUT
# S1 S2
# S0 S3
s = sensor(pi, 24, 22, 23, 4, 17, 18)
s.set_update_period(p)
s.set_frequency(2) # 20%
s.set_sample_size(20)
# Parametrage
def Parametrage():
GPIO.setup(capteurG, GPIO.IN, pull_up_down = GPIO.PUD_UP) #initialisation
GPIO.setup(capteurD, GPIO.IN, pull_up_down = GPIO.PUD_UP)
# GPIO.setup(capteurC, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(motor1A,GPIO.OUT)
GPIO.setup(motor1B,GPIO.OUT)
GPIO.setup(motor2A,GPIO.OUT)
GPIO.setup(motor2B,GPIO.OUT)
motor1.start(0)
motor2.start(0)
# Calibrage
def Calibrage():
wait_for_return("Calibrage du noir, appuyer sur Entree pour demarrer")
for i in range(5):
time.sleep(p)
rgb = s.get_Hertz()
print(rgb)
s.set_black_level(rgb)
wait_for_return("Calibrage du blanc, appuyer sur Entree pour demarrer")
for i in range(5):
time.sleep(p)
rgb = s.get_Hertz()
print(rgb)
s.set_white_level(rgb)
wait_for_return("Position sur la ligne de depart, appuyer sur Entree pour demarrer")
def avant(speed):
print "Avant"
GPIO.output(motor1A,GPIO.HIGH)
GPIO.output(motor1B,GPIO.LOW)
motor1.ChangeDutyCycle(speed)
GPIO.output(motor2A,GPIO.HIGH)
GPIO.output(motor2B,GPIO.LOW)
motor2.ChangeDutyCycle(speed)
def arriere(speed):
print "Arriere"
GPIO.output(motor1A,GPIO.LOW)
GPIO.output(motor1B,GPIO.HIGH)
motor1.ChangeDutyCycle(speed)
GPIO.output(motor2A,GPIO.LOW)
GPIO.output(motor2B,GPIO.HIGH)
motor2.ChangeDutyCycle(speed)
def avant_droite(speed):
print "Pivot Droite"
GPIO.output(motor1A,GPIO.HIGH)
GPIO.output(motor1B,GPIO.LOW)
motor1.ChangeDutyCycle(speed)
def pivot_droite(speed):
print "Pivot Droite"
GPIO.output(motor1A,GPIO.HIGH)
GPIO.output(motor1B,GPIO.LOW)
GPIO.output(motor2A,GPIO.LOW)
GPIO.output(motor2B,GPIO.HIGH)
motor1.ChangeDutyCycle(speed)
motor2.ChangeDutyCycle(speed)
def avant_gauche(speed):
print "Pivot Gauche"
GPIO.output(motor2A,GPIO.HIGH)
GPIO.output(motor2B,GPIO.LOW)
motor2.ChangeDutyCycle(speed)
def pivot_gauche(speed):
print "Pivot Gauche"
GPIO.output(motor1A,GPIO.LOW)
GPIO.output(motor1B,GPIO.HIGH)
GPIO.output(motor2A,GPIO.HIGH)
GPIO.output(motor2B,GPIO.LOW)
motor1.ChangeDutyCycle(speed)
motor2.ChangeDutyCycle(speed)
def stop():
motor1.ChangeDutyCycle(0)
motor2.ChangeDutyCycle(0)
# Boucle du programme pour lire le capteur de couleur et les capteurs suiveurs de ligne
def Boucle():
vitesse=70
while True:
# time.sleep(p)
rgb = s.get_rgb()
r = rgb[0]
g = rgb[1]
b = rgb[2]
print(rgb, s.get_Hertz(), s.tally)
pi.set_PWM_dutycycle(RED, r)
pi.set_PWM_dutycycle(GREEN, g)
pi.set_PWM_dutycycle(BLUE, b)
if (r>=g+10) and (r>=b+10):
print "rouge"
vitesse=100
if (g>=r+10) and (g>=b+10):
print "vert"
vitesse=50
if (b>=r+10) and (b>=g+10):
print "bleu"
vitesse=75
if (r>=240) and (g>=240) and (b>=240): print "blanc"
if (r<=15) and (g<=15) and (b<=15): print "noir"
# capteurCentre=GPIO.input(capteurC)
capteurGauche=GPIO.input(capteurG)
capteurDroite=GPIO.input(capteurD)
print "---------------------------------------"
# if (capteurGauche==GPIO.HIGH) and (capteurDroite==GPIO.HIGH) and (capteurCentre==GPIO.LOW):
if (capteurGauche==GPIO.HIGH) and (capteurDroite==GPIO.HIGH):
# print "blanc a gauche // blanc a droite // noir au centre"
print "blanc a gauche // blanc a droite"
avant(vitesse)
if (capteurGauche==GPIO.LOW):
print "noir a gauche"
stop()
pivot_gauche(30)
if (capteurDroite==GPIO.LOW):
print "noir a droite"
stop()
pivot_droite(30)
# if (capteurGauche==GPIO.HIGH) and (capteurDroite==GPIO.HIGH) and (capteurCentre==GPIO.HIGH):
# print "blanc a gauche // blanc a droite // blanc au centre"
# stop()
time.sleep(0.05)
def Reinitialisation(): # Reinitialiser le circuit GPIO
#GPIO.setup(capteurG, GPIO.LOW)
#GPIO.setup(capteurD, GPIO.LOW)
GPIO.cleanup() # Relacher les ressources
def wait_for_return(str):
if sys.hexversion < 0x03000000:
raw_input(str)
else:
input(str)
# Le programme demarre ici
if __name__ == '__main__':
Parametrage()
Calibrage()
try:
Boucle()
except KeyboardInterrupt: # Si on interrompt le programme, on passe d'abord par la fonction Reinitialisation
Reinitialisation()
​
Sur notre vidéo, nous pouvons voir qu'après avoir calibrer le capteur de couleur, la voiture roule de plus en plus vite sur la ligne droite.