| Ligne 15 : | Ligne 15 : | ||
{{Introduction | {{Introduction | ||
|Introduction=<translate>Présentation d'un tutoriel notre projet de classe de terminale STI2D afin de le reproduire chez soi</translate> | |Introduction=<translate>Présentation d'un tutoriel notre projet de classe de terminale STI2D afin de le reproduire chez soi</translate> | ||
| + | }} | ||
| + | {{TutoVideo | ||
| + | |VideoType=Youtube | ||
| + | |VideoURLYoutube=https://youtu.be/lhH82QnR_hY?si=ZPldD7446yzoAs-8 | ||
}} | }} | ||
{{Materials | {{Materials | ||
| Ligne 54 : | Ligne 58 : | ||
}} | }} | ||
{{Tuto Step | {{Tuto Step | ||
| − | |Step_Title=<translate></translate> | + | |Step_Title=<translate>Configuration Arduino</translate> |
| − | |Step_Content=<translate></translate> | + | |Step_Content=<translate>- Brancher les servo moteur sur la carte arduino |
| + | |||
| + | - inséré le code Arduino | ||
| + | |||
| + | Servo servos[6]; // Tableau de 6 servos | ||
| + | |||
| + | const int pinsServos[6] = {3, 5, 6, 9, 10, 11}; // Broches des servos | ||
| + | |||
| + | unsigned long tempsServo = 0; | ||
| + | |||
| + | bool servosActifs = false; | ||
| + | |||
| + | void setup() { | ||
| + | |||
| + | Serial.begin(9600); // Initialisation du moniteur série | ||
| + | |||
| + | Serial.println("✅ Arduino prêt, en attente des commandes I2C..."); | ||
| + | |||
| + | Wire.begin(8); // Arduino en esclave I2C (adresse 8) | ||
| + | |||
| + | Wire.onReceive(recevoirCommande); | ||
| + | |||
| + | // Initialiser les servos à la position souhaitée (par exemple, 45°) | ||
| + | |||
| + | for (int i = 0; i < 6; i++) { | ||
| + | |||
| + | servos[i].attach(pinsServos[i]); | ||
| + | |||
| + | servos[i].write(45); // Position initiale (en bas) | ||
| + | |||
| + | } | ||
| + | |||
| + | } | ||
| + | |||
| + | void loop() { | ||
| + | |||
| + | if (servosActifs && millis() - tempsServo >= 3000) { | ||
| + | |||
| + | Serial.println("🔄 Retour des servos à la position initiale."); | ||
| + | |||
| + | for (int i = 0; i < 6; i++) { | ||
| + | |||
| + | servos[i].write(45); // Retour à la position initiale (en bas) | ||
| + | |||
| + | } | ||
| + | |||
| + | servosActifs = false; | ||
| + | |||
| + | } | ||
| + | |||
| + | } | ||
| + | |||
| + | void recevoirCommande(int nombreOctets) { | ||
| + | |||
| + | if (Wire.available()) { | ||
| + | |||
| + | int valeur = Wire.read(); // Lire le nombre envoyé par le Raspberry Pi | ||
| + | |||
| + | Serial.print("📩 Commande reçue: "); | ||
| + | |||
| + | Serial.println(valeur, BIN); // Afficher la valeur en binaire (code Braille) | ||
| + | |||
| + | // Déplacer chaque servo un par un avec un petit délai | ||
| + | |||
| + | for (int i = 0; i < 6; i++) { | ||
| + | |||
| + | if (valeur & (1 << (5 - i))) { // Vérifier si le bit i est actif | ||
| + | |||
| + | Serial.print("🔼 Servo "); | ||
| + | |||
| + | Serial.print(i); | ||
| + | |||
| + | Serial.println(" activé."); | ||
| + | |||
| + | servos[i].write(135); // Position haute (en haut) | ||
| + | |||
| + | } else { | ||
| + | |||
| + | Serial.print("🔽 Servo "); | ||
| + | |||
| + | Serial.print(i); | ||
| + | |||
| + | Serial.println(" désactivé."); | ||
| + | |||
| + | servos[i].write(45); // Position initiale (en bas) | ||
| + | |||
| + | } | ||
| + | |||
| + | delay(100); // Petite pause entre les déplacements des servos | ||
| + | |||
| + | } | ||
| + | |||
| + | tempsServo = millis(); // Démarrer le timer pour retour automatique | ||
| + | |||
| + | servosActifs = true; | ||
| + | |||
| + | } | ||
| + | |||
| + | }</translate> | ||
| + | |Step_Picture_00=Syst_me_de_traduction_et_d_apprentissage_du_Braille_Carte_Arduino_Uno_Rev._3.jpg | ||
}} | }} | ||
{{Tuto Step | {{Tuto Step | ||
|Step_Title=<translate>Branchement entre les carte électroniques et les servo-moteurs</translate> | |Step_Title=<translate>Branchement entre les carte électroniques et les servo-moteurs</translate> | ||
|Step_Content=<translate>-Assurez vous d'avoir une Raspberry Pi configurer avant de commencer | |Step_Content=<translate>-Assurez vous d'avoir une Raspberry Pi configurer avant de commencer | ||
| − | |||
| − | |||
| − | |||
| − | |||
- Se munir de la carte raspery Pi | - Se munir de la carte raspery Pi | ||
| − | - Brancher relier les broches Gpio raspery Pi avec celle de arduino(gnd,vcc) taper sur internet broche raspery pi | + | - Brancher relier les broches Gpio raspery Pi avec celle de arduino(gnd,vcc etc...) taper sur internet broche raspery pi |
- inséré ce code <syntaxhighlight lang="python"> | - inséré ce code <syntaxhighlight lang="python"> | ||
Auteur
GOACOLO | Dernière modification 26/05/2025 par Yawen
aveugles, Braille, Traduction, Apprentissage Syst_me_de_traduction_et_d_apprentissage_du_Braille_20250526_144220_1_.jpg Creation
Youtube
-Connecter l'ordinateur à la découpeuse laser
-Ouvrir le logiciel Trotek ( Nécessaire à la découpe)
-Ouvrir les pièces à découper en format dxf dans le logiciel
-Optimiser l'espace sur la planche afin d'avoir les moins de perte de matière et déplaçant les pièces
-Lancer la découpe
-Nettoyer les pièces afin d'éviter des tâches dues au bois brûlé.
- Brancher les servo moteur sur la carte arduino
- inséré le code Arduino
Servo servos[6]; // Tableau de 6 servos
const int pinsServos[6] = {3, 5, 6, 9, 10, 11}; // Broches des servos
unsigned long tempsServo = 0;
bool servosActifs = false;
void setup() {
Serial.begin(9600); // Initialisation du moniteur série
Serial.println("✅ Arduino prêt, en attente des commandes I2C...");
Wire.begin(8); // Arduino en esclave I2C (adresse 8)
Wire.onReceive(recevoirCommande);
// Initialiser les servos à la position souhaitée (par exemple, 45°)
for (int i = 0; i < 6; i++) {
servos[i].attach(pinsServos[i]);
servos[i].write(45); // Position initiale (en bas)
}
}
void loop() {
if (servosActifs && millis() - tempsServo >= 3000) {
Serial.println("🔄 Retour des servos à la position initiale.");
for (int i = 0; i < 6; i++) {
servos[i].write(45); // Retour à la position initiale (en bas)
}
servosActifs = false;
}
}
void recevoirCommande(int nombreOctets) {
if (Wire.available()) {
int valeur = Wire.read(); // Lire le nombre envoyé par le Raspberry Pi
Serial.print("📩 Commande reçue: ");
Serial.println(valeur, BIN); // Afficher la valeur en binaire (code Braille)
// Déplacer chaque servo un par un avec un petit délai
for (int i = 0; i < 6; i++) {
if (valeur & (1 << (5 - i))) { // Vérifier si le bit i est actif
Serial.print("🔼 Servo ");
Serial.print(i);
Serial.println(" activé.");
servos[i].write(135); // Position haute (en haut)
} else {
Serial.print("🔽 Servo ");
Serial.print(i);
Serial.println(" désactivé.");
servos[i].write(45); // Position initiale (en bas)
}
delay(100); // Petite pause entre les déplacements des servos
}
tempsServo = millis(); // Démarrer le timer pour retour automatique
servosActifs = true;
}
}
-Assurez vous d'avoir une Raspberry Pi configurer avant de commencer
- Se munir de la carte raspery Pi
- Brancher relier les broches Gpio raspery Pi avec celle de arduino(gnd,vcc etc...) taper sur internet broche raspery pi
- inséré ce codeimport smbus
import time
import RPi.GPIO as GPIO
import random
import os
import threading
import cv2
import pytesseract
import numpy as np
I2C_ADDR = 8
bus = smbus.SMBus(1)
# GPIO des boutons
BOUTON_PRECEDENT = 17
BOUTON_SUIVANT = 27
BOUTON_LECON = 23
BOUTON_EXERCICE = 24
BOUTON_CAMERA = 22 # Bouton pour la caméra
# GPIO du capteur ultrason HCSR04
TRIG = 5 # GPIO pour le trigger du capteur
ECHO = 6 # GPIO pour l'echo du capteur
# Configuration des GPIO
try:
GPIO.cleanup()
except:
pass
GPIO.setmode(GPIO.BCM)
GPIO.setup(BOUTON_PRECEDENT, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(BOUTON_SUIVANT, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(BOUTON_LECON, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(BOUTON_EXERCICE, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(BOUTON_CAMERA, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# Configuration du capteur ultrason
GPIO.setup(TRIG, GPIO.OUT)
GPIO.setup(ECHO, GPIO.IN)
GPIO.output(TRIG, False) # S'assurer que le trigger est bas au démarrage
# Dictionnaire Braille
braille_dict = {
"a": 0b100000, "b": 0b110000, "c": 0b101000, "d": 0b101100,
"e": 0b100100, "f": 0b111000, "g": 0b111100, "h": 0b110100,
"i": 0b011000, "j": 0b011100, "k": 0b100010, "l": 0b110010,
"m": 0b101010, "n": 0b101110, "o": 0b100110, "p": 0b111010,
"q": 0b111110, "r": 0b110110, "s": 0b011010, "t": 0b011110,
"u": 0b100011, "v": 0b110011, "w": 0b011101, "x": 0b101011,
"y": 0b101111, "z": 0b100111, " ": 0b000000
}
texte = "bonjour" # Texte par défaut
index = 0
lecon_en_cours = False
exercice_en_cours = False
attente_texte = False # Pour savoir si on attend une saisie de texte
camera_en_cours = False # Pour indiquer si une capture par caméra est en cours
# Paramètres de capture d'image
IMAGE_PATH = "capture.jpg"
CROPPED_PATH = "cropped.jpg"
DISTANCE_OPTIMALE = 15 # Distance optimale en cm
MARGE_DISTANCE = 2.5 # Marge de tolérance en cm (+/-)
def mesurer_distance():
"""Mesure la distance avec le capteur ultrason HCSR04."""
# Envoyer une impulsion de 10µs au trigger
GPIO.output(TRIG, True)
time.sleep(0.00001) # 10µs
GPIO.output(TRIG, False)
# Attendre que l'écho commence
start_time = time.time()
timeout = start_time + 1.0 # Timeout de 1 seconde
while GPIO.input(ECHO) == 0:
if time.time() > timeout:
return -1 # Erreur: pas de signal
pulse_start = time.time()
# Attendre que l'écho se termine
while GPIO.input(ECHO) == 1:
if time.time() > timeout:
return -1 # Erreur: signal trop long
pulse_end = time.time()
# Calculer la durée de l'impulsion
pulse_duration = pulse_end - pulse_start
# Calculer la distance (vitesse du son = 34300 cm/s)
# Diviser par 2 car le signal fait l'aller-retour
distance = (pulse_duration * 34300) / 2
return round(distance, 1) # Arrondir à 1 décimale
def guide_position():
"""Guide l'utilisateur pour positionner correctement le texte."""
global camera_en_cours
print("📏 Positionnement du texte...")
os.system('espeak -v fr "Positionnez le texte" --stdout | aplay')
# Attendre que la distance soit stable dans la plage optimale
position_stable = False
nb_mesures_stables = 0
while camera_en_cours and not position_stable:
distance = mesurer_distance()
if distance < 0:
print("⚠️ Erreur de mesure de distance")
time.sleep(0.5)
continue
print(f"📏 Distance mesurée : {distance} cm")
if distance < DISTANCE_OPTIMALE - MARGE_DISTANCE:
# Trop proche
os.system('espeak -v fr "Reculez" --stdout | aplay')
nb_mesures_stables = 0
elif distance > DISTANCE_OPTIMALE + MARGE_DISTANCE:
# Trop loin
os.system('espeak -v fr "Avancez" --stdout | aplay')
nb_mesures_stables = 0
else:
# Distance correcte
print(f"✅ Distance correcte : {distance} cm")
nb_mesures_stables += 1
# Si 3 mesures consécutives sont dans la plage, on considère la position comme stable
if nb_mesures_stables >= 3:
position_stable = True
os.system('espeak -v fr "Position correcte" --stdout | aplay')
time.sleep(0.5) # Attendre avant la prochaine mesure
return position_stable
def envoyer_nombre(nombre, mode=None):
"""Envoie une lettre en Braille et annonce (avec délai optionnel en mode exercice)."""
try:
lettre = [key for key, val in braille_dict.items() if val == nombre][0]
bus.write_byte(I2C_ADDR, nombre)
print(f"✅ Lettre envoyée: {lettre.upper()} ({bin(nombre)})")
# Si c'est le mode exercice, attendre 2 secondes avant d'énoncer la lettre
if mode == "exercice":
# Vérifier périodiquement si l'exercice a été arrêté pendant l'attente
debut = time.time()
while time.time() - debut < 2 and exercice_en_cours:
time.sleep(0.1)
# Ne prononcer la lettre que si l'exercice est toujours en cours
if exercice_en_cours:
os.system(f'espeak -v fr "{lettre}" --stdout | aplay')
else:
# Pour les autres modes, énoncer la lettre immédiatement
os.system(f'espeak -v fr "{lettre}" --stdout | aplay')
except IOError:
print("❌ Erreur de communication avec l'Arduino")
except IndexError:
print("❌ Erreur: code braille non trouvé dans le dictionnaire")
except Exception as e:
print(f"❌ Erreur inattendue: {str(e)}")
def demander_nouveau_texte():
"""Demande un nouveau texte et réinitialise l'index."""
global texte, index, attente_texte
# Annonce vocale
os.system('espeak -v fr "Entrez un nouveau texte" --stdout | aplay')
# Lancer un thread pour attendre la saisie sans bloquer le reste du programme
def attendre_saisie():
global texte, index, attente_texte
nouveau_texte = input("\n🆕 Entrez un texte (ou appuyez sur Entrée pour garder 'bonjour') : ").lower()
if nouveau_texte: # Si l'utilisateur a entré quelque chose
texte = nouveau_texte
index = 0
print(f"🔠 Texte actuel : {texte}")
print("📌 Appuyez sur le bouton 'Suivant' pour parcourir le texte, ou sur 'Leçon'/'Exercice' pour ces modes.")
attente_texte = False # Fin de l'attente
attente_texte = True # Début de l'attente
t = threading.Thread(target=attendre_saisie)
t.daemon = True
t.start()
def bouton_precedent(channel):
"""Affiche la lettre précédente pendant la lecture du texte."""
global index
# Ne pas exécuter si un mode est en cours ou si on attend une saisie
if lecon_en_cours or exercice_en_cours or attente_texte or camera_en_cours:
return
time.sleep(0.2) # Anti-rebond
if GPIO.input(BOUTON_PRECEDENT) == GPIO.LOW:
if index > 0:
index -= 1
envoyer_nombre(braille_dict.get(texte[index], 0))
print(f"🔙 Lettre précédente: {texte[index]}")
else:
print("🚫 Déjà à la première lettre.")
os.system('espeak -v fr "Première lettre" --stdout | aplay')
def bouton_suivant(channel):
"""Affiche la lettre suivante et lit le mot en entier à la fin."""
global index
# Ne pas exécuter si un mode est en cours ou si on attend une saisie
if lecon_en_cours or exercice_en_cours or attente_texte or camera_en_cours:
return
time.sleep(0.2) # Anti-rebond
if GPIO.input(BOUTON_SUIVANT) == GPIO.LOW:
if texte and index < len(texte):
envoyer_nombre(braille_dict.get(texte[index], 0))
index += 1
print(f"🔜 Lettre suivante: {texte[index-1]}")
if index == len(texte):
print("🔁 Fin du texte, lecture complète...")
os.system(f'espeak -v fr "{texte}" --stdout | aplay')
demander_nouveau_texte()
def lancer_lecon():
"""Fonction pour lancer la leçon dans un thread séparé."""
global lecon_en_cours
# Si on attend une saisie de texte, annuler cette attente
global attente_texte
attente_texte = False
# Marquer le début de la leçon
lecon_en_cours = True
print("📖 Début de la leçon...")
os.system('espeak -v fr "Début de la leçon" --stdout | aplay')
# Parcourir l'alphabet
for lettre in "abcdefghijklmnopqrstuvwxyz":
# Vérifier si la leçon a été arrêtée
if not lecon_en_cours:
return
# Afficher et annoncer la lettre
print(f"📝 Leçon : Lettre {lettre.upper()}")
envoyer_nombre(braille_dict[lettre])
# Attendre 8 secondes, en vérifiant si la leçon a été arrêtée
debut = time.time()
while time.time() - debut < 8:
if not lecon_en_cours:
return # Sortir immédiatement si la leçon a été arrêtée
time.sleep(0.1)
# Fin normale de la leçon
print("✅ Leçon terminée !")
os.system('espeak -v fr "Leçon terminée" --stdout | aplay')
lecon_en_cours = False
# Proposer d'entrer un nouveau texte sans bloquer
demander_nouveau_texte()
def lancer_exercice():
"""Fonction pour lancer l'exercice dans un thread séparé."""
global exercice_en_cours
# Si on attend une saisie de texte, annuler cette attente
global attente_texte
attente_texte = False
# Marquer le début de l'exercice
exercice_en_cours = True
print("🎲 Début de l'exercice...")
os.system('espeak -v fr "Début de l\'exercice" --stdout | aplay')
# Préparer les lettres dans un ordre aléatoire
lettres = list("abcdefghijklmnopqrstuvwxyz")
random.shuffle(lettres)
# Parcourir les lettres aléatoires
for lettre in lettres:
# Vérifier si l'exercice a été arrêté
if not exercice_en_cours:
return
# Afficher et annoncer la lettre avec délai de 2 secondes
print(f"📝 Exercice : Lettre {lettre.upper()}")
envoyer_nombre(braille_dict[lettre], mode="exercice")
# Attendre le reste des 8 secondes (moins les 2 secondes d'attente déjà écoulées),
# en vérifiant si l'exercice a été arrêté
debut = time.time()
while time.time() - debut < 6: # 8 - 2 = 6 secondes restantes
if not exercice_en_cours:
return # Sortir immédiatement si l'exercice a été arrêté
time.sleep(0.1)
# Fin normale de l'exercice
print("🏆 Exercice terminé !")
os.system('espeak -v fr "Exercice terminé" --stdout | aplay')
exercice_en_cours = False
# Proposer d'entrer un nouveau texte sans bloquer
demander_nouveau_texte()
def capturer_et_lire_texte():
"""Fonction pour capturer une image avec la caméra et en extraire le texte."""
global camera_en_cours, texte, index, attente_texte
# Si on attend une saisie de texte, annuler cette attente
attente_texte = False
# Marquer le début de la capture
camera_en_cours = True
print("📸 Préparation de la capture...")
os.system('espeak -v fr "Préparation de la capture" --stdout | aplay')
# Guide de positionnement avec le capteur ultrason
if guide_position():
# Capture de l'image (réduction du temps à 3s car on a déjà guidé l'utilisateur)
print("📸 Capture en cours...")
os.system('espeak -v fr "Capture en cours" --stdout | aplay')
os.system(f"libcamera-jpeg -o {IMAGE_PATH} -t 3000 --width 1920 --height 1080 --quality 100")
# Vérifier si l'image existe
if not os.path.exists(IMAGE_PATH):
print("❌ Erreur : L'image n'a pas été capturée.")
os.system('espeak -v fr "Erreur de capture" --stdout | aplay')
camera_en_cours = False
return
print("⚡ Optimisation de l'image...")
try:
# Chargement et conversion en niveaux de gris
image = cv2.imread(IMAGE_PATH)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Correction de l'orientation
try:
osd = pytesseract.image_to_osd(gray)
angle = int(osd.split("\n")[1].split(":")[1].strip())
if angle != 0:
(h, w) = gray.shape[:2]
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, -angle, 1.0)
gray = cv2.warpAffine(gray, M, (w, h))
except:
print("⚠ Impossible de détecter l'orientation, passage à l'étape suivante.")
# Prétraitement (amélioration du contraste et du bruit)
gray = cv2.GaussianBlur(gray, (3, 3), 0)
gray = cv2.equalizeHist(gray) # Augmentation du contraste
gray = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 10)
# Détection des contours pour recadrer uniquement le texte
print("📐 Détection du texte...")
edges = cv2.Canny(gray, 50, 150)
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
filtered_contours = [c for c in contours if cv2.contourArea(c) > 1000]
if filtered_contours:
x, y, w, h = cv2.boundingRect(cv2.convexHull(np.vstack(filtered_contours)))
cropped = image[y:y+h, x:x+w]
cropped = cv2.resize(cropped, None, fx=1.5, fy=1.5, interpolation=cv2.INTER_LINEAR)
cv2.imwrite(CROPPED_PATH, cropped)
else:
print("⚠ Aucun texte clairement détecté, extraction sur l'image entière.")
cropped = image
# OCR optimisé
print("🔍 Extraction du texte...")
detected_text = pytesseract.image_to_string(cropped, lang="eng+fra", config="--psm 6 --oem 3").strip()
# Nettoyer le texte détecté (supprimer les caractères spéciaux et garder lettres, chiffres et espaces)
cleaned_text = ''.join(c.lower() for c in detected_text if c.isalnum() or c.isspace())
# Si le texte est vide après nettoyage, afficher un message
if not cleaned_text:
print("⚠ Aucun texte détecté après nettoyage.")
os.system('espeak -v fr "Aucun texte détecté" --stdout | aplay')
camera_en_cours = False
return
# Afficher le texte détecté
print(f"\n📄 Texte détecté : {cleaned_text}")
os.system(f'espeak -v fr "Texte détecté" --stdout | aplay')
# Mettre à jour le texte global et réinitialiser l'index
texte = cleaned_text
index = 0
print(f"🔠 Nouveau texte : {texte}")
print("📌 Appuyez sur le bouton 'Suivant' pour parcourir le texte.")
except Exception as e:
print(f"❌ Erreur lors du traitement de l'image : {str(e)}")
os.system('espeak -v fr "Erreur de traitement" --stdout | aplay')
else:
print("❌ Positionnement annulé.")
os.system('espeak -v fr "Positionnement annulé" --stdout | aplay')
# Marquer la fin de la capture
camera_en_cours = False
def bouton_lecon_presse(channel):
"""Fonction appelée lorsque le bouton leçon est pressé."""
global lecon_en_cours
# Ne pas réagir si un autre mode est en cours
if exercice_en_cours or camera_en_cours:
return
time.sleep(0.2) # Anti-rebond
if GPIO.input(BOUTON_LECON) == GPIO.LOW:
# Basculer l'état de la leçon
if lecon_en_cours:
lecon_en_cours = False
print("📖 Leçon arrêtée par l'utilisateur.")
os.system('espeak -v fr "Leçon arrêtée" --stdout | aplay')
# La leçon est arrêtée, sera nettoyée dans le thread
else:
# Lancer la leçon dans un thread séparé
t = threading.Thread(target=lancer_lecon)
t.daemon = True # Le thread s'arrêtera quand le programme principal s'arrête
t.start()
def bouton_exercice_presse(channel):
"""Fonction appelée lorsque le bouton exercice est pressé."""
global exercice_en_cours
# Ne pas réagir si un autre mode est en cours
if lecon_en_cours or camera_en_cours:
return
time.sleep(0.2) # Anti-rebond
if GPIO.input(BOUTON_EXERCICE) == GPIO.LOW:
# Basculer l'état de l'exercice
if exercice_en_cours:
exercice_en_cours = False
print("🎲 Exercice arrêté par l'utilisateur.")
os.system('espeak -v fr "Exercice arrêté" --stdout | aplay')
# L'exercice est arrêté, sera nettoyé dans le thread
else:
# Lancer l'exercice dans un thread séparé
t = threading.Thread(target=lancer_exercice)
t.daemon = True # Le thread s'arrêtera quand le programme principal s'arrête
t.start()
def bouton_camera_presse(channel):
"""Fonction appelée lorsque le bouton caméra est pressé."""
global camera_en_cours
# Ne pas réagir si un autre mode est en cours
if lecon_en_cours or exercice_en_cours or camera_en_cours:
return
time.sleep(0.2) # Anti-rebond
if GPIO.input(BOUTON_CAMERA) == GPIO.LOW:
# Lancer la capture dans un thread séparé
t = threading.Thread(target=capturer_et_lire_texte)
t.daemon = True # Le thread s'arrêtera quand le programme principal s'arrête
t.start()
# Supprimer les détecteurs d'événements existants s'il y en a
try:
GPIO.remove_event_detect(BOUTON_SUIVANT)
GPIO.remove_event_detect(BOUTON_PRECEDENT)
GPIO.remove_event_detect(BOUTON_LECON)
GPIO.remove_event_detect(BOUTON_EXERCICE)
GPIO.remove_event_detect(BOUTON_CAMERA)
except:
pass
# Configuration des détecteurs d'événements
GPIO.add_event_detect(BOUTON_SUIVANT, GPIO.FALLING, callback=bouton_suivant, bouncetime=500)
GPIO.add_event_detect(BOUTON_PRECEDENT, GPIO.FALLING, callback=bouton_precedent, bouncetime=500)
GPIO.add_event_detect(BOUTON_LECON, GPIO.FALLING, callback=bouton_lecon_presse, bouncetime=500)
GPIO.add_event_detect(BOUTON_EXERCICE, GPIO.FALLING, callback=bouton_exercice_presse, bouncetime=500)
GPIO.add_event_detect(BOUTON_CAMERA, GPIO.FALLING, callback=bouton_camera_presse, bouncetime=500)
# Initialisation du capteur ultrason (attendre qu'il se stabilise)
print("⚙️ Initialisation du capteur ultrason...")
time.sleep(0.5)
GPIO.output(TRIG, False)
time.sleep(0.5)
# Afficher les instructions au démarrage
print("👋 Bienvenue dans l'application d'apprentissage du Braille")
print("📋 Instructions:")
print(" - Bouton LEÇON: Apprendre l'alphabet (8s par lettre)")
print(" - Bouton EXERCICE: Pratiquer avec des lettres aléatoires (2s de réflexion, puis annonce)")
print(" - Bouton SUIVANT: Afficher la lettre suivante du texte")
print(" - Bouton PRÉCÉDENT: Afficher la lettre précédente du texte")
print(" - Bouton CAMÉRA: Guide le positionnement, puis capture une image et extrait le texte")
print("⚠️ Appuyez à nouveau sur LEÇON/EXERCICE pour arrêter à tout moment")
print(f"🔠 Texte par défaut : {texte}")
print("📌 Appuyez sur le bouton 'Suivant' pour parcourir le texte, ou choisissez un mode.")
# Boucle principale pour maintenir le programme actif
try:
while True:
time.sleep(0.1)
except KeyboardInterrupt:
print("\n🛑 Arrêt du programme.")
GPIO.cleanup()
Le système est équipé de 5 boutons physiques qui permettent de contrôler les différents modes d'apprentissage et la détection du texte.
-Brancher les bouton aux broches gpio correspondantes grâce au code inséré précédement
-Lancer le code
-Se munir du Capteur ultrason et le brancher sur la broche gpio (regardez le code rasperypi pour savoir )
- Brancher la camera à la Raspberry Pi, il y a un tuto ici
-Lancer le code
fr none 0 Published
Vous avez entré un nom de page invalide, avec un ou plusieurs caractères suivants :
< > @ ~ : * € £ ` + = / \ | [ ] { } ; ? #