Système de traduction et d'apprentissage du Braille : Différence entre versions

 
(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

Version actuelle datée du 26 mai 2025 à 22:29

Auteur avatarGOACOLO | Dernière modification 26/05/2025 par Yawen

Présentation d'un tutoriel notre projet de classe de terminale STI2D afin de le reproduire chez soi

Matériaux

Matériaux pour le boitier

-Planche en bois 3mm d'épaisseur / 30cm de large / 60 cm de long

-Plastique pour découpeuse laser ( ici du PLA) environ (100g)


Composants électroniques

-1x Raspberry pi 3

-6x Servo moteurs linéaires

-1x Mini Haut parleur (Module haut-parleur SKU00101)

-1x Cordon Jack CA35M

- 1x Carte Arduino Uno

- 5x boutons poussoirs

- 1x Capteur Ultrason

- 1x Caméra compatible Raspberry pi disponible chez Kubii

-40x Fils de connexion électronique

Outils

-Découpeuse laser

-Imprimante 3D (ici la Ultimaker 2+)

-Ordinateur

Étape 1 - Découpe des pièces en bois du boitier

-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é.




Étape 2 - Assemblage des pièces en bois

-Assembler les pièces découpées grâce aux images ci-contre.

-Les coller via de la colle à bois.




Étape 3 - Configuration de la carte électronique Raspberry pi v3

-Configurer votre carte Raspberry pi.

-Alimenter la carte Raspberry pi via son câble d'alimentation à l'ordinateur et en hdmi à l'écran.

-Copier le code "Raspberry_code" dans un fichier python au même nom.

-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.

-Dans le terminal, tapper "python3 Raspberry_code.py".

-Le code devrait se lancer.

-Si c'est le cas, débrancher la carte raspberry pi, sinon regarder un tutoriel sur internet.




Étape 4 - Configuration de la carte électronique Arduino Uno

-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.

-Si le code parvient à s'uploader, débrancher la carte Arduino, sinon regarder un tutoriel sur internet.


Étape 5 - Branchement des composants

-Une fois les 2 cartes débranchées, les connecter en I2C via 3 fils de connexion M>F.(SDA; SCL; GND)

-Bancher la caméra à la carte raspberry pi.

-Connecter le capteur de distance via 4 fils de connexion F>F à la carte Raspberry pi(VCC; GND; TRIG; ECHO)

-Connecter les boutons sur les GPIO {17; 22; 23; 24; 27} de la Raspberry pi et les alimenter via la carte Arduino

-Connecter le haut-parleur via 2 fils de connexion F>F.(VCC; GND) et le câble jack



Étape 6 - Branchement des servo-moteurs

-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}.




Étape 7 - Test des codes

-Alimenter les 2 carte électroniques.

-Attendre quelques instants que la raspberry se lance.

-Tester les boutons:

  • 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:
    1. Positionner le capteur de distance à environ 15cm, +/- 1cm d'un texte
    2. Ne plus bouger
    3. 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)




Étape 8 - Assemblage

-Assembler les composants dans le boitier afin de les protéger.

-Utiliser des vis pour un meilleur maintien des composants si possible.



Étape 9 - Test final

-Tester les boutons et valider les actions engendrées.




Commentaires

Published