|
|
| (7 révisions intermédiaires par le même utilisateur non affichées) |
| Ligne 1 : |
Ligne 1 : |
| | {{Tuto Details | | {{Tuto Details |
| − | |Main_Picture=Syst_me_de_traduction_et_d_apprentissage_du_Braille_20250526_144220_1_.jpg | + | |Main_Picture=Boitier.png |
| − | |Main_Picture_annotation={"version":"3.5.0","objects":[{"type":"image","version":"3.5.0","originX":"left","originY":"top","left":601.2,"top":-33,"width":3468,"height":4624,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":0.15,"scaleY":0.15,"angle":90,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"crossOrigin":"","cropX":0,"cropY":0,"src":"https://wikifab.org/images/f/f9/Syst_me_de_traduction_et_d_apprentissage_du_Braille_20250526_144220_1_.jpg","filters":[]}],"height":449.2718446601942,"width":600} | + | |Main_Picture_annotation={"version":"3.5.0","objects":[{"type":"image","version":"3.5.0","originX":"left","originY":"top","left":108,"top":54,"width":1920,"height":1659,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":0.2,"scaleY":0.2,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"crossOrigin":"","cropX":0,"cropY":0,"src":"https://wikifab.org/images/1/15/Boitier.png","filters":[]}],"height":450.2664298401421,"width":600} |
| | |Licences=Attribution (CC BY) | | |Licences=Attribution (CC BY) |
| − | |Description=<translate>Objet qui permet de traduire et d'apprendre le braille.</translate> | + | |Description=<translate>Présentation d'un tutoriel notre projet de classe de terminale STI2D afin de le reproduire chez soi</translate> |
| | |Area=Electronics, Health and Wellbeing | | |Area=Electronics, Health and Wellbeing |
| | |Type=Creation | | |Type=Creation |
| Ligne 14 : |
Ligne 14 : |
| | }} | | }} |
| | {{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></translate> |
| | }} | | }} |
| | {{Materials | | {{Materials |
| Ligne 23 : |
Ligne 23 : |
| | |Step_Picture_04=Syst_me_de_traduction_et_d_apprentissage_du_Braille_61L4aoIqYOL._AC_SX679_.jpg | | |Step_Picture_04=Syst_me_de_traduction_et_d_apprentissage_du_Braille_61L4aoIqYOL._AC_SX679_.jpg |
| | |Step_Picture_05=Syst_me_de_traduction_et_d_apprentissage_du_Braille_Capture_d_cran_2025-05-26_153426.png | | |Step_Picture_05=Syst_me_de_traduction_et_d_apprentissage_du_Braille_Capture_d_cran_2025-05-26_153426.png |
| − | |Material=<translate>-Bois 3mm | + | |Material=<translate><u>'''Matériaux pour le boitier'''</u> |
| | | | |
| − | -Plastique pour découpeuse laser ( ici du PLA) | + | -Planche en bois 3mm d'épaisseur / 30cm de large / 60 cm de long |
| | | | |
| − | -1 raspberry pi 3 | + | -Plastique pour découpeuse laser ( ici du PLA) environ (100g) |
| | | | |
| − | -6 servo moteurs linéaires
| |
| | | | |
| − | -1 haut parleur (Module haut-parleur SKU00101)
| + | '''<u>Composants électroniques</u>''' |
| | | | |
| − | -1 Cordon Jack CA35M | + | -1x Raspberry pi 3 |
| | | | |
| − | - Une carte arduino | + | -6x Servo moteurs linéaires |
| | | | |
| − | - 6 boutons poussoirs | + | -1x Mini Haut parleur (Module haut-parleur SKU00101) |
| | | | |
| − | - Un capteur Ultrason | + | -1x Cordon Jack CA35M |
| | | | |
| − | - Une caméra de chez kubii</translate> | + | - 1x Carte Arduino Uno |
| | + | |
| | + | - 5x boutons poussoirs |
| | + | |
| | + | - 1x Capteur Ultrason |
| | + | |
| | + | - 1x Caméra compatible Raspberry pi disponible chez Kubii |
| | + | |
| | + | -40x Fils de connexion électronique</translate> |
| | |Tools=<translate>-Découpeuse laser | | |Tools=<translate>-Découpeuse laser |
| | | | |
| − | -Imprimante 3D (ici la Ultimaker 2+)</translate> | + | -Imprimante 3D (ici la Ultimaker 2+) |
| | + | |
| | + | -Ordinateur</translate> |
| | |Tuto_Attachments={{Tuto Attachments | | |Tuto_Attachments={{Tuto Attachments |
| | |Attachment=support servomoteur .stl | | |Attachment=support servomoteur .stl |
| Ligne 69 : |
Ligne 78 : |
| | }}{{Tuto Attachments | | }}{{Tuto Attachments |
| | |Attachment=Arduino_code.ino | | |Attachment=Arduino_code.ino |
| | + | }}{{Tuto Attachments |
| | + | |Attachment=Raspberry_code.docx |
| | }} | | }} |
| | }} | | }} |
| | {{Tuto Step | | {{Tuto Step |
| | |Step_Title=<translate>Découpe des pièces en bois du boitier</translate> | | |Step_Title=<translate>Découpe des pièces en bois du boitier</translate> |
| − | |Step_Content=<translate>-Connecter l'ordinateur à la découpeuse laser | + | |Step_Content=<translate>-Connecter l'ordinateur à la découpeuse laser. |
| | | | |
| − | -Ouvrir le logiciel Trotek ( Nécessaire à la découpe) | + | -Ouvrir le logiciel Trotek ( Nécessaire à la découpe). |
| | | | |
| − | -Ouvrir les pièces à découper en format dxf dans le logiciel | + | -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 | + | -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 | + | -Lancer la découpe. |
| | | | |
| | -Nettoyer les pièces afin d'éviter des tâches dues au bois brûlé.</translate> | | -Nettoyer les pièces afin d'éviter des tâches dues au bois brûlé.</translate> |
| | + | |Step_Picture_00=Découpe.jpg |
| | }} | | }} |
| | {{Tuto Step | | {{Tuto Step |
| Ligne 89 : |
Ligne 101 : |
| | |Step_Content=<translate>-Assembler les pièces découpées grâce aux images ci-contre. | | |Step_Content=<translate>-Assembler les pièces découpées grâce aux images ci-contre. |
| | | | |
| − | -Les coller via de la colle à bois</translate> | + | -Les coller via de la colle à bois.</translate> |
| | + | |Step_Picture_00=Assemblage.jpg |
| | }} | | }} |
| | {{Tuto Step | | {{Tuto Step |
| − | |Step_Title=<translate></translate>
| + | |Step_Title=<translate>Configuration de la carte électronique Raspberry pi v3</translate> |
| − | |Step_Content=<translate></translate>
| + | |Step_Content=<translate>-Configurer votre carte Raspberry pi. |
| − | }}
| |
| − | {{Tuto Step
| |
| − | |Step_Title=<translate>Configuration de la carte électronique Arduino Uno</translate> | |
| − | |Step_Content=<translate>-Alimenter la carte Arduino Uno via son câble d'alimentation à ordinateur | |
| − | | |
| − | -Ouvrir Le logiciel Arduino IDE
| |
| − | | |
| − | -Ouvrir le fichier "Arduino_code.ino"
| |
| | | | |
| − | -Uploader le code.</translate> | + | -Alimenter la carte Raspberry pi via son câble d'alimentation à l'ordinateur et en hdmi à l'écran. |
| − | |Step_Picture_00=Syst_me_de_traduction_et_d_apprentissage_du_Braille_61AvdQOxFzL.jpg
| |
| − | }}
| |
| − | {{Tuto Step
| |
| − | |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 si cela n'est pas déja fait je vous invite à regarder ce [https://alain-michel.canoprof.fr/eleve/tutoriels/raspberry/premiers-pas-raspberrypi.pdf tuto] avant de poursuivre
| |
| | | | |
| − | - Brancher les servo moteur sur la carte arduino avec les broches indiquées dans le code | + | -Copier le code "Raspberry_code" dans un fichier python au même nom. |
| | | | |
| − | - inséré le code Arduino | + | -Avant de lancer ce fichier, vous devez d’abord créer et démarrer un environnement virtuel à l’aide du terminal. Cela permet de préparer un espace propre pour faire fonctionner votre programme. |
| | | | |
| − | - Se munir de la carte raspery Pi | + | -Dans le terminal, tapper "python3 Raspberry_code.py". |
| | | | |
| − | - Brancher relier les broches Gpio raspery Pi avec celle de arduino(gnd,vcc) Vous pouvez taper sur internet (Broche Raspberry Pi pour trouvé l'illustration) | + | -Le code devrait se lancer. |
| | | | |
| − | - inséré ce code <syntaxhighlight lang="python"> | + | -Si c'est le cas, débrancher la carte raspberry pi, sinon regarder un tutoriel sur internet.</translate> |
| − | import smbus
| + | |Step_Picture_00=raspberry.jpg |
| − | import time
| + | }} |
| − | import RPi.GPIO as GPIO
| + | {{Tuto Step |
| − | import random
| + | |Step_Title=<translate>Configuration de la carte électronique Arduino Uno</translate> |
| − | import os
| + | |Step_Content=<translate>-Alimenter la carte Arduino Uno via son câble d'alimentation à ordinateur. |
| − | import threading
| |
| − | import cv2
| |
| − | import pytesseract
| |
| − | import numpy as np
| |
| | | | |
| − | I2C_ADDR = 8
| + | -Ouvrir Le logiciel Arduino IDE. |
| − | bus = smbus.SMBus(1)
| |
| | | | |
| − | # GPIO des boutons
| + | -Ouvrir le fichier "Arduino_code.ino". |
| − | 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
| + | -Uploader le code. |
| − | TRIG = 5 # GPIO pour le trigger du capteur
| |
| − | ECHO = 6 # GPIO pour l'echo du capteur
| |
| | | | |
| − | # Configuration des GPIO
| + | -Si le code parvient à s'uploader, débrancher la carte Arduino, sinon regarder un tutoriel sur internet.</translate> |
| − | try:
| + | |Step_Picture_00=Syst_me_de_traduction_et_d_apprentissage_du_Braille_61AvdQOxFzL.jpg |
| − | GPIO.cleanup()
| + | |Step_Picture_01=arduino ide image.jpg |
| − | except:
| + | |Step_Picture_02=code.png |
| − | pass
| + | }} |
| | + | {{Tuto Step |
| | + | |Step_Title=<translate>Branchement des composants</translate> |
| | + | |Step_Content=<translate>-Une fois les 2 cartes débranchées, les connecter en I2C via 3 fils de connexion M>F.(SDA; SCL; GND) |
| | | | |
| − | GPIO.setmode(GPIO.BCM)
| + | -Bancher la caméra à la carte raspberry pi. |
| − | 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
| + | -Connecter le capteur de distance via 4 fils de connexion F>F à la carte Raspberry pi(VCC; GND; TRIG; ECHO) |
| − | 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
| + | -Connecter les boutons sur les GPIO {17; 22; 23; 24; 27} de la Raspberry pi et les alimenter via la carte Arduino |
| − | 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
| + | -Connecter le haut-parleur via 2 fils de connexion F>F.(VCC; GND) et le câble jack |
| − | 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
| + | <br /></translate> |
| − | IMAGE_PATH = "capture.jpg"
| + | |Step_Picture_00=Caméra.jpg |
| − | CROPPED_PATH = "cropped.jpg"
| + | |Step_Picture_01=capteur distance.jpg |
| − | DISTANCE_OPTIMALE = 15 # Distance optimale en cm
| + | |Step_Picture_02=Syst_me_de_traduction_et_d_apprentissage_du_Braille_5-mini-bouton-poussoir.jpg |
| − | MARGE_DISTANCE = 2.5 # Marge de tolérance en cm (+/-)
| + | |Step_Picture_03=Syst_me_de_traduction_et_d_apprentissage_du_Braille_thumbnail_Afficher_les_photos_re_centes.jpg |
| − | | + | }} |
| − | def mesurer_distance():
| + | {{Tuto Step |
| − | """Mesure la distance avec le capteur ultrason HCSR04."""
| + | |Step_Title=<translate>Branchement des servo-moteurs</translate> |
| − | # Envoyer une impulsion de 10µs au trigger
| + | |Step_Content=<translate>-Connecter en PWM les 6 servo-moteurs linéaires à la carte Arduino en utilisant son alimentation et via les ports {3; 5; 6; 9; 10; 11}.</translate> |
| − | GPIO.output(TRIG, True)
| + | |Step_Picture_00=servomoteur.jpg |
| − | 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()
| |
| − | </syntaxhighlight>-Regardez un tutoriel en ligne pour apprendre à créer un fichier dans lequel vous pourrez insérer le code destiné au Raspberry Pi.
| |
| − | | |
| − | Avant de lancer ce fichier, vous devez d’abord créer un environnement virtuel à l’aide du terminal (appelé "cmd") du Raspberry Pi. Cela permet de préparer un espace propre pour faire fonctionner votre programme.
| |
| − | | |
| − | Vous pouvez facilement trouver des explications simples sur Internet en cherchant "comment créer un environnement virtuel sur Raspberry Pi".</translate>
| |
| − | |Step_Picture_00=Syst_me_de_traduction_et_d_apprentissage_du_Braille_nm_arduino-front.jpg | |
| − | |Step_Picture_01=Syst_me_de_traduction_et_d_apprentissage_du_Braille_91zSu44_34L._AC_UF1000_1000_QL80_.jpg
| |
| − | |Step_Picture_02=Syst_me_de_traduction_et_d_apprentissage_du_Braille_images_1_.jpeg
| |
| − | |Step_Picture_02_annotation={"version":"3.5.0","objects":[{"type":"image","version":"3.5.0","originX":"left","originY":"top","left":-41,"top":7,"width":251,"height":200,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":2.7,"scaleY":2.7,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"crossOrigin":"","cropX":0,"cropY":0,"src":"https://wikifab.org/images/7/7e/Syst_me_de_traduction_et_d_apprentissage_du_Braille_images_1_.jpeg","filters":[]}],"height":478.15384615384613,"width":600}
| |
| | }} | | }} |
| | {{Tuto Step | | {{Tuto Step |
| − | |Step_Title=<translate>Système d'interface homme-machine</translate> | + | |Step_Title=<translate>Test des codes</translate> |
| − | |Step_Content=<translate>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. | + | |Step_Content=<translate>-Alimenter les 2 carte électroniques. |
| | | | |
| − | -Brancher les bouton aux broches gpio correspondantes grâce au code inséré précédement | + | -Attendre quelques instants que la raspberry se lance. |
| | | | |
| − | -Lancer le code</translate> | + | -Tester les boutons: |
| − | |Step_Picture_00=Syst_me_de_traduction_et_d_apprentissage_du_Braille_raspberry-pi-camera-module-3-12mp-objectif-standard-haute-resolution-sc0872.jpg | + | |
| − | |Step_Picture_01=Syst_me_de_traduction_et_d_apprentissage_du_Braille_images.jpeg
| + | *Bouton 1: Début du mode leçon ( Lettre dans l'ordre alphabétique) |
| | + | *Bouton 2: Début du mode exercice ( Lettre dans le désordre) |
| | + | *Bouton 3: Lancement de la caméra: |
| | + | *#Positionner le capteur de distance à environ 15cm, +/- 1cm d'un texte |
| | + | *#Ne plus bouger |
| | + | *#Attendre quelques secondes que la raspberry pi reconnaisse des lettres |
| | + | *Bouton 4: Lettre suivante( Du texte détecté via la caméra) |
| | + | *Bouton 5: Lettre précédente (Du texte détecté via la caméra)</translate> |
| | + | |Step_Picture_00=Syst_me_de_traduction_et_d_apprentissage_du_Braille_thumbnail_Sujet_6_.png |
| | }} | | }} |
| | {{Tuto Step | | {{Tuto Step |
| − | |Step_Title=<translate>Système de détection de texte</translate> | + | |Step_Title=<translate>Assemblage</translate> |
| − | |Step_Content=<translate>'''Le système utilise une caméra et un capteur à ultrasons pour détecter du texte .''' | + | |Step_Content=<translate>-Assembler les composants dans le boitier afin de les protéger. |
| − | | |
| − | -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 [https://www.gotronic.fr/pj2-tutopicam-1585.pdf?srsltid=AfmBOorFOpsASuNtAhuMkrhdSImstiAlyNY9y20oJxfODo4Vyu3Cx9X6 ici]
| |
| | | | |
| − | -Lancer le code</translate> | + | -Utiliser des vis pour un meilleur maintien des composants si possible.</translate> |
| − | |Step_Picture_00=Syst_me_de_traduction_et_d_apprentissage_du_Braille_capteur-de-distance-ultrason-hc-sr04.jpg | + | |Step_Picture_00=Syst_me_de_traduction_et_d_apprentissage_du_Braille_thumbnail_Sujet_4_.png |
| − | |Step_Picture_01=Syst_me_de_traduction_et_d_apprentissage_du_Braille_raspberry-pi-camera-module-3-12mp-objectif-standard-haute-resolution-sc0872.jpg | + | |Step_Picture_01=Assemblage 2 Braille.png |
| | }} | | }} |
| | {{Tuto Step | | {{Tuto Step |
| − | |Step_Title=<translate></translate> | + | |Step_Title=<translate>Test final</translate> |
| − | |Step_Content=<translate></translate> | + | |Step_Content=<translate>-Tester les boutons et valider les actions engendrées.</translate> |
| | + | |Step_Picture_00=Syst_me_de_traduction_et_d_apprentissage_du_Braille_thumbnail_Sujet_5_.png |
| | }} | | }} |
| | {{Notes | | {{Notes |