<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fr">
	<id>https://wiki-se.plil.fr/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Bblack</id>
	<title>wiki-se.plil.fr - Contributions [fr]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki-se.plil.fr/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Bblack"/>
	<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php/Sp%C3%A9cial:Contributions/Bblack"/>
	<updated>2026-05-13T23:29:44Z</updated>
	<subtitle>Contributions</subtitle>
	<generator>MediaWiki 1.39.1</generator>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4991</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4991"/>
		<updated>2024-01-29T14:54:42Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* Vidéo */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=SignSpeak 2023/2024 =&lt;br /&gt;
== '''Présentation du projet''' ==&lt;br /&gt;
&lt;br /&gt;
=== 1. Introduction ===&lt;br /&gt;
----Le projet SignSpeak a pour ambition de créer une solution innovante pour la traduction du langage des signes en texte. L'objectif principal est de développer un système capable de capturer les mouvements des mains et de les interpréter en langage des signes, permettant une communication fluide entre les personnes sourdes ou malentendantes et celles qui ne connaissent pas le langage des signes. Ce projet intègre des technologies avancées telles que l'edge computing, l'intelligence artificielle embarquée, et les communications MQTT, offrant une approche novatrice dans le domaine de l'accessibilité et de la communication.&lt;br /&gt;
&lt;br /&gt;
=== 2. Architecture du Système ===&lt;br /&gt;
----Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :&lt;br /&gt;
&lt;br /&gt;
* '''Capteurs et STM32''' : Des capteurs sont connectés à un microcontrôleur STM32, responsables de la capture des mouvements de main. Ces données sont ensuite transmises pour traitement.&lt;br /&gt;
* '''Raspberry Pi''' : Agissant comme un intermédiaire, la Raspberry Pi reçoit les données des capteurs via UART, exécute un traitement préliminaire et communique avec le serveur.&lt;br /&gt;
* '''Serveur et Machine Learning''' : Un serveur, hébergé sur une VM Xen, traite les données à l'aide d'un modèle SVM pour la traduction en langage des signes et fournit une interface web pour l'interaction utilisateur.&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== 3. Collecte et Préparation des Données ===&lt;br /&gt;
----Le processus de collecte des données est géré par le script &amp;lt;code&amp;gt;enregistrementData.py&amp;lt;/code&amp;gt;. Ce script lit les données transmises par le STM32 via UART et les enregistre dans un fichier CSV. Chaque entrée du fichier représente les valeurs de capteurs à un moment donné, accompagnées d'une étiquette correspondant au signe effectué. Cette approche assure une collecte de données structurée, essentielle pour l'entraînement précis du modèle d'apprentissage automatique.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
import csv&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
# Vérification de l'argument d'entrée&lt;br /&gt;
if len(sys.argv) &amp;lt; 2:&lt;br /&gt;
    print(&amp;quot;Usage: python script.py &amp;lt;etiquette&amp;gt;&amp;quot;)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
etiquette = sys.argv[1]&lt;br /&gt;
&lt;br /&gt;
# Paramètres de l'UART&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
&lt;br /&gt;
# Créer une connexion UART&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
&lt;br /&gt;
# Nom du fichier CSV&lt;br /&gt;
filename = f&amp;quot;data_complete.csv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Vérifier si le fichier existe déjà&lt;br /&gt;
file_exists = False&lt;br /&gt;
try:&lt;br /&gt;
    with open(filename, 'r') as f:&lt;br /&gt;
        file_exists = True&lt;br /&gt;
except FileNotFoundError:&lt;br /&gt;
    file_exists = False&lt;br /&gt;
&lt;br /&gt;
# Ouvrir le fichier CSV en mode append&lt;br /&gt;
with open(filename, 'a', newline='') as file:&lt;br /&gt;
    writer = csv.writer(file)&lt;br /&gt;
&lt;br /&gt;
    # Écrire l'en-tête si le fichier n'existait pas&lt;br /&gt;
    if not file_exists:&lt;br /&gt;
        writer.writerow([&amp;quot;Capteur1&amp;quot;, &amp;quot;Capteur2&amp;quot;, &amp;quot;Capteur3&amp;quot;, &amp;quot;Capteur4&amp;quot;, &amp;quot;Capteur5&amp;quot;, &amp;quot;Capteur6&amp;quot;, &amp;quot;Capteur7&amp;quot;, &amp;quot;Capteur8&amp;quot;, &amp;quot;Capteur9&amp;quot;, &amp;quot;Capteur10&amp;quot;, &amp;quot;Capteur11&amp;quot;, &amp;quot;Capteur12&amp;quot;, &amp;quot;Capteur13&amp;quot;, &amp;quot;Capteur14&amp;quot;, &lt;br /&gt;
&amp;quot;Capteur15&amp;quot;, &amp;quot;Capteur16&amp;quot;, &amp;quot;Etiquette&amp;quot;])&lt;br /&gt;
    elif file_exists:&lt;br /&gt;
        writer.writerow([])&lt;br /&gt;
    while True:&lt;br /&gt;
        # Lire une ligne de données depuis l'UART&lt;br /&gt;
        data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
        print(f&amp;quot;Données reçues : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Vérifier si des données ont été reçues&lt;br /&gt;
        if data:&lt;br /&gt;
            # Diviser les données en valeurs individuelles&lt;br /&gt;
            sensor_values = data.split(',')&lt;br /&gt;
&lt;br /&gt;
            # Filtrer les chaînes vides ou non numériques et convertir en flottants&lt;br /&gt;
            try:&lt;br /&gt;
                sensor_values = [float(value) for value in sensor_values if value.strip().isdigit()]&lt;br /&gt;
&lt;br /&gt;
                # Vérifier qu'il y a 16 valeurs de capteur&lt;br /&gt;
                if len(sensor_values) == 16:&lt;br /&gt;
                    sensor_values.append(etiquette)&lt;br /&gt;
                    writer.writerow(sensor_values)&lt;br /&gt;
                else:&lt;br /&gt;
                    print(&amp;quot;Données incomplètes reçues&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            except ValueError as e:&lt;br /&gt;
                print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
                print(f&amp;quot;Données problématiques : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Le script commence par établir une communication série avec le STM32.&lt;br /&gt;
* Il lit ensuite les données en série, les décode et les stocke dans un fichier CSV pour une utilisation ultérieure.&lt;br /&gt;
&lt;br /&gt;
* Une fois les données collectées et stockées dans le fichier CSV, elles sont préparées pour l'entraînement du modèle.&lt;br /&gt;
* Cette préparation implique la normalisation des données, la gestion des valeurs manquantes ou aberrantes, et leur formatage dans un bon format.[[Fichier:Rpi entrainement.png|vignette|1000x1000px|néant]]&lt;br /&gt;
=== 4. Entraînement du Modèle d'Apprentissage Automatique ===&lt;br /&gt;
----L'entraînement du modèle est réalisé par un script Python utilisant la bibliothèque scikit-learn. Le modèle SVM, choisi pour sa capacité à gérer des espaces de grande dimension, est entraîné sur l'ensemble des données collectées. Ce processus comprend la division des données en ensembles d'entraînement et de test, l'entraînement du modèle, et sa validation par le calcul de la précision. Nous avions testé plusieurs modèle, comme par exemple un modèle Knn ou randomForest, des 3 algorithmes, c'est celui qui nous à apporté les meilleurs résultats pour un meme nombre de data d'entrainement. (RandomForest en deuxième position)&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import pandas as pd&lt;br /&gt;
from sklearn.model_selection import train_test_split&lt;br /&gt;
from sklearn.svm import SVC&lt;br /&gt;
from sklearn.metrics import accuracy_score&lt;br /&gt;
import pickle&lt;br /&gt;
&lt;br /&gt;
# Charger vos données&lt;br /&gt;
data = pd.read_csv('data_complete.csv')&lt;br /&gt;
&lt;br /&gt;
# Séparer les caractéristiques et les étiquettes&lt;br /&gt;
X = data.drop('Etiquette', axis=1)&lt;br /&gt;
y = data['Etiquette']&lt;br /&gt;
&lt;br /&gt;
# Diviser les données en ensembles d'entraînement et de test&lt;br /&gt;
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)&lt;br /&gt;
&lt;br /&gt;
# Créer et entraîner le modèle SVM&lt;br /&gt;
model = SVC(kernel='rbf')&lt;br /&gt;
model.fit(X_train, y_train)&lt;br /&gt;
&lt;br /&gt;
# Sauvegarder le modèle entraîné&lt;br /&gt;
with open('modele_svm.pkl', 'wb') as file:&lt;br /&gt;
    pickle.dump(model, file)&lt;br /&gt;
&lt;br /&gt;
# Charger le modèle et faire des prédictions&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    loaded_model = pickle.load(file)&lt;br /&gt;
    predictions = loaded_model.predict(X_test)&lt;br /&gt;
    print(&amp;quot;Précision :&amp;quot;, accuracy_score(y_test, predictions))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# '''Séparation des Données''':&lt;br /&gt;
#* Les données sont divisées en deux ensembles : un ensemble d'entraînement et un ensemble de test. Cette séparation est cruciale pour évaluer objectivement la performance du modèle.&lt;br /&gt;
#* Généralement, on adopte une répartition de 80% pour l'entraînement et 20% pour les tests.&lt;br /&gt;
# '''Entraînement du Modèle SVM''':&lt;br /&gt;
#* Le modèle SVM avec un noyau RBF (Radial Basis Function) est entraîné sur l'ensemble d'entraînement.&lt;br /&gt;
#* L'entraînement implique l'ajustement du modèle aux données d'entraînement, en apprenant à distinguer les différents signes.&lt;br /&gt;
# '''Sauvegarde et Réutilisation du Modèle'''&lt;br /&gt;
#* Une fois entraîné et validé, le modèle est sauvegardé à l'aide de la bibliothèque &amp;lt;code&amp;gt;pickle&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Validation et Évaluation du Modèle''':&lt;br /&gt;
#* Après l'entraînement, le modèle est testé sur l'ensemble de test pour évaluer sa performance.&lt;br /&gt;
#* La métrique principale utilisée est la précision, qui mesure la proportion de prédictions correctes par rapport au total des prédictions.&lt;br /&gt;
&lt;br /&gt;
Ensuite on peut générer le modèle comme ceci:&lt;br /&gt;
[[Fichier:Generate model.png|vignette|399x399px|néant]]&lt;br /&gt;
&lt;br /&gt;
Avec cette prédiction lorsque notre modèle prédit le résultat, il est correct environ 71.81% du temps.&lt;br /&gt;
&lt;br /&gt;
=== 5. Intégration MQTT et Communication ===&lt;br /&gt;
----Protocole de communication  :&lt;br /&gt;
&lt;br /&gt;
Dans le cadre de notre projet, la communication entre les dispositifs Raspberry Pi et le serveur  est établie via le protocole MQTT.&lt;br /&gt;
&lt;br /&gt;
Justification du Choix de MQTT :&lt;br /&gt;
&lt;br /&gt;
Au début du projet, une approche basée sur des sockets IPv6 avait été envisagée pour tirer parti de l'adressage direct et de la simplification de la configuration réseau qu'offre IPv6. Cependant, dans le but de respecter les impératifs de sobriété énergétique et d'assurer une scalabilité optimale du système, permettant ainsi de gérer aisément un nombre croissant de dispositifs Raspberry Pi, la décision a été prise d'adopter MQTT comme protocole de communication. Le protocole MQTT, reconnu pour sa légèreté et sa fiabilité, s'adapte parfaitement aux contraintes des applications IoT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Installation du broker mosquitto sur le serveur:'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
apt install -y mosquitto mosquitto-clients&lt;br /&gt;
service mosquitto start&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Activation de l'accès à distance au Broker Mosquitto:&lt;br /&gt;
&lt;br /&gt;
ajouter l'authentification par username et mot de passe&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
sudo mosquitto_passwd -c /etc/mosquitto/passwd username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
après on nous demande d'entrer le mot de passe &lt;br /&gt;
&lt;br /&gt;
Modifier le fichier /etc/mosquitto/mosquitto.conf:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
listener 1883 10.42.0.5&lt;br /&gt;
#listener 1883 2001:660:4401:6050:216:3eff:fe86:cd63&lt;br /&gt;
allow_anonymous false&lt;br /&gt;
password_file /etc/mosquitto/passwd&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Mosquitto:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
service mosquitto restart&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vérification ds logs:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
cat /var/log/mosquitto/mosquitto.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Création d'un client MQTT sur la Raspberry Pi:'''&lt;br /&gt;
&lt;br /&gt;
Le script mqtt_client_rpi.py joue un rôle clé dans cette architecture en facilitant la communication bidirectionnelle : il permet non seulement l'envoi des prédictions réalisées par le modèle SVM depuis la Raspberry Pi vers le serveur, mais autorise également la réception des commandes de contrôle, telles que les instructions de démarrage ou d'arrêt de la collecte de données.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import serial&lt;br /&gt;
import pandas as pd&lt;br /&gt;
import pickle&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
#MQTT_BROKER_ADDRESS = &amp;quot;2001:660:4401:6050:216:3eff:fe86:cd63&amp;quot; VmHblgrimBblack&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
pi_id = &amp;quot;rpi1234&amp;quot;&lt;br /&gt;
&lt;br /&gt;
collecting_data = False &lt;br /&gt;
&lt;br /&gt;
client = mqtt.Client()&lt;br /&gt;
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)&lt;br /&gt;
client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
client.loop_start()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(f&amp;quot;config/{pi_id}&amp;quot;)&lt;br /&gt;
    client.publish(&amp;quot;raspberry_available&amp;quot;, pi_id)&lt;br /&gt;
&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global collecting_data&lt;br /&gt;
    if msg.topic == f&amp;quot;config/{pi_id}&amp;quot;:&lt;br /&gt;
        command = msg.payload.decode()&lt;br /&gt;
        if command == &amp;quot;start&amp;quot;:&lt;br /&gt;
            collecting_data = True&lt;br /&gt;
        elif command == &amp;quot;stop&amp;quot;:&lt;br /&gt;
            collecting_data = False&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.on_connect = on_connect&lt;br /&gt;
client.on_message = on_message&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Configurez le port série et chargez le modèle ici&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    rf = pickle.load(file)&lt;br /&gt;
try:&lt;br /&gt;
&lt;br /&gt;
    while True:&lt;br /&gt;
        if collecting_data:&lt;br /&gt;
            data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
            if data:&lt;br /&gt;
                try:&lt;br /&gt;
                    sensor_values = [value for value in data.split(',') if value.strip().replace('.', '', 1).isdigit()]&lt;br /&gt;
                    if len(sensor_values) == 16:&lt;br /&gt;
                        sensor_values = list(map(float, sensor_values))&lt;br /&gt;
                        sensor_values_df = pd.DataFrame([sensor_values])&lt;br /&gt;
                        prediction = rf.predict(sensor_values_df)&lt;br /&gt;
                        client.publish(f&amp;quot;telemetry/{pi_id}&amp;quot;, str(prediction[0]).encode())&lt;br /&gt;
                        print(&amp;quot;Prédiction :&amp;quot;, prediction[0])&lt;br /&gt;
                except ValueError as e:&lt;br /&gt;
                    print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:&lt;br /&gt;
    print(&amp;quot;Script interrompu&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.loop_stop()&lt;br /&gt;
client.disconnect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Ici il y a 3 topics différents. lorsqu'une raspberry se connecte au réseau elle publie son ID (qui est unique, on peut prendre par exemple l'adresse MAC) sur le topic raspberry_available. Cela nous servira a savoir quelle raspberry est connecté et de se fait pouvoir afficher celles-ci sur notre interface web.&lt;br /&gt;
&lt;br /&gt;
le deuxième topic et le topic config/ID (avec id l'identifiant unique de la raspberry), il nous sert a envoyer les commandes &amp;quot;start&amp;quot; et &amp;quot;stop&amp;quot; a la raspberry afin qu'elle démarre ou arrête la lecture des datas.&lt;br /&gt;
&lt;br /&gt;
Le troisième topic est le topic telemetry/ID, ou la raspberry vient publier ses données.&lt;br /&gt;
&lt;br /&gt;
Un quatrième topic pourrait être implémenter comme par exemple le topic common_config, toutes les raspberrys serait abonnées a ce topic. S'il est nécessaire, cela nous permettrais d'envoyer la même commande a toutes les raspberry  plutôt que de faire une publication sur chaque config/ID&lt;br /&gt;
&lt;br /&gt;
=== 6. Interface Serveur et Gestion des Données ===&lt;br /&gt;
----Le serveur central, au cœur de notre système, est orchestré par le script &amp;lt;code&amp;gt;app.py&amp;lt;/code&amp;gt; qui exploite le framework Flask pour mettre en place une interface serveur. Cette interface est conçue pour traiter efficacement les requêtes HTTP et les messages MQTT, offrant ainsi une API réactive pour l'interface utilisateur web. Elle permet également de visualiser en temps réel l'état des dispositifs Raspberry Pi connectés et les dernières données traitées.&lt;br /&gt;
[[Fichier:Signspeakweb.png|centré|vignette|1000x1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from flask import Flask, render_template, request, jsonify&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import queue&lt;br /&gt;
&lt;br /&gt;
app = Flask(__name__)&lt;br /&gt;
messages = []&lt;br /&gt;
received_messages = queue.Queue()&lt;br /&gt;
latest_message = None&lt;br /&gt;
subscribed_topics = set()&lt;br /&gt;
raspberry_ids = set()&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
#MQTT_BROKER_ADDRESS = &amp;quot;2001:660:4401:6050:216:3eff:fe86:cd63&amp;quot; VmHblgrimBblack&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client = mqtt.Client()&lt;br /&gt;
mqtt_client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD) &lt;br /&gt;
mqtt_client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
mqtt_client.loop_start()&lt;br /&gt;
&lt;br /&gt;
def send_command_to_pi(pi_id, command):&lt;br /&gt;
    try:&lt;br /&gt;
        topic = f&amp;quot;config/{pi_id}&amp;quot;&lt;br /&gt;
        mqtt_client.publish(topic, command)&lt;br /&gt;
        subscribe_to_pi_telemetry(pi_id)&lt;br /&gt;
        return True, &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
    except Exception as e:&lt;br /&gt;
        return False, f&amp;quot;Commande pas envoyée: Erreur MQTT : {e}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
def subscribe_to_pi_telemetry(pi_id):&lt;br /&gt;
    global subscribed_topics&lt;br /&gt;
    topic = f&amp;quot;telemetry/{pi_id}&amp;quot;&lt;br /&gt;
    if topic not in subscribed_topics:&lt;br /&gt;
        mqtt_client.subscribe(topic)&lt;br /&gt;
        subscribed_topics.add(topic)&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(&amp;quot;raspberry_available&amp;quot;)&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    print(f&amp;quot;Received message on topic {msg.topic}: {msg.payload.decode()}&amp;quot;)  # Ajouter pour le débogage&lt;br /&gt;
    if msg.topic == &amp;quot;raspberry_available&amp;quot;:&lt;br /&gt;
        raspberry_ids.add(msg.payload.decode())&lt;br /&gt;
    else:&lt;br /&gt;
        received_messages.put(msg.payload.decode())&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client.on_connect = on_connect&lt;br /&gt;
mqtt_client.on_message = on_message&lt;br /&gt;
@app.route('/get-raspberry-ids')&lt;br /&gt;
def get_raspberry_ids():&lt;br /&gt;
    return jsonify(list(raspberry_ids))&lt;br /&gt;
@app.route('/get-latest-message')&lt;br /&gt;
def get_latest_message():&lt;br /&gt;
    global latest_message&lt;br /&gt;
    while not received_messages.empty():&lt;br /&gt;
        messages.append(received_messages.get())&lt;br /&gt;
&lt;br /&gt;
    latest_message = messages[-1] if messages else None&lt;br /&gt;
    &lt;br /&gt;
    print(f&amp;quot;Contenu de la réponse pour /get-latest-message : {latest_message}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    if latest_message is not None:&lt;br /&gt;
         response = jsonify({&amp;quot;message&amp;quot;: latest_message})&lt;br /&gt;
         return response&lt;br /&gt;
    else:&lt;br /&gt;
        message = &amp;quot;Aucun signe a traduire pour le moment&amp;quot;&lt;br /&gt;
        return jsonify(message)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@app.route('/', methods=['GET', 'POST'])&lt;br /&gt;
&lt;br /&gt;
def index():&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    error_message_rpi = None&lt;br /&gt;
    success_message = None&lt;br /&gt;
&lt;br /&gt;
    if request.method == 'POST':&lt;br /&gt;
        pi_id = request.form.get('pi_id')&lt;br /&gt;
        command = request.form.get('command')&lt;br /&gt;
        if pi_id and command in [&amp;quot;start&amp;quot;, &amp;quot;stop&amp;quot;]:&lt;br /&gt;
            success, er_message = send_command_to_pi(pi_id, command)&lt;br /&gt;
            if success:&lt;br /&gt;
                success_message = &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                error_message_rpi = er_message&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    return render_template('index.html', raspberry_ids=list(raspberry_ids), error_message_rpi=error_message_rpi, success_message=success_message, message=latest_message)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    app.run(debug=False, port=8066)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7. Conception de l'Interface Utilisateur ===&lt;br /&gt;
----L'interface utilisateur, développée à l'aide des technologies web standard HTML, CSS, et JavaScript, offre une expérience interactive. Le fichier index.html constitue le point d'entrée de cette interface, proposant des fonctionnalités telles que l'envoi de commandes aux dispositifs Raspberry Pi et la visualisation des données traitées. L'utilisation de JavaScript pour interroger dynamiquement le serveur Flask permet de rafraîchir les informations affichées en temps réel, garantissant ainsi une interface réactive et à jour.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
index.html:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
        body {&lt;br /&gt;
            background-color: #343a40; &lt;br /&gt;
            color: #ced4da; &lt;br /&gt;
        }&lt;br /&gt;
        .card {&lt;br /&gt;
            background-color: #495057; &lt;br /&gt;
        }&lt;br /&gt;
        .card-title, .card-text, .alert {&lt;br /&gt;
            color: #adb5bd; &lt;br /&gt;
        }&lt;br /&gt;
        .btn-primary {&lt;br /&gt;
            background-color: #007bff; &lt;br /&gt;
            border-color: #007bff;&lt;br /&gt;
        }&lt;br /&gt;
        .btn-danger {&lt;br /&gt;
            background-color: #dc3545; &lt;br /&gt;
            border-color: #dc3545;&lt;br /&gt;
        }&lt;br /&gt;
        .form-control {&lt;br /&gt;
            background-color: #495057; &lt;br /&gt;
            border: 1px solid #6c757d;&lt;br /&gt;
            color: #ced4da; &lt;br /&gt;
        }&lt;br /&gt;
        a, .btn-secondary {&lt;br /&gt;
            color: #17a2b8; &lt;br /&gt;
        }&lt;br /&gt;
        a:hover {&lt;br /&gt;
            color: #138496; &lt;br /&gt;
        }&lt;br /&gt;
        #latest-message {&lt;br /&gt;
            background-color: #596069; &lt;br /&gt;
            border: 1px solid #6c757d; &lt;br /&gt;
            color: #E9ECEF; &lt;br /&gt;
            padding: 10px; &lt;br /&gt;
            border-radius: 5px; &lt;br /&gt;
        }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;container mt-5&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;h1 class=&amp;quot;text-center mb-4&amp;quot;&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/h1&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour les Raspberry Pi Disponibles --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-md-12&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Raspberry Pi Disponibles&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;ul id=&amp;quot;raspberry-list&amp;quot; class=&amp;quot;list-group list-group-flush&amp;quot;&amp;gt;&lt;br /&gt;
                    &lt;br /&gt;
                        &amp;lt;/ul&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour la Collecte des données --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Collecte de données&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;form method=&amp;quot;post&amp;quot; class=&amp;quot;form-inline&amp;quot;&amp;gt;&lt;br /&gt;
                            &amp;lt;input type=&amp;quot;text&amp;quot; class=&amp;quot;form-control mb-2 mr-sm-2&amp;quot; name=&amp;quot;pi_id&amp;quot; placeholder=&amp;quot;Entrez l'ID de la Raspberry Pi&amp;quot; required&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-primary mb-2 mr-sm-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;start&amp;quot;&amp;gt;Démarrer la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-danger mb-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;stop&amp;quot;&amp;gt;Arrêter la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                        &amp;lt;/form&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;!-- Encadré pour le Dernier Message Reçu --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Dernier Message Reçu&amp;lt;/h2&amp;gt;&lt;br /&gt;
                    &amp;lt;div id=&amp;quot;latest-message&amp;quot; class=&amp;quot;alert alert-dark&amp;quot;&amp;gt;&lt;br /&gt;
                        Aucun message reçu pour le moment. &lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;mb-3 text-center&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;a href=&amp;quot;/logs&amp;quot; class=&amp;quot;btn btn-secondary&amp;quot;&amp;gt;Voir les Logs&amp;lt;/a&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        function fetchRaspberryIds() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        var ids = JSON.parse(xhr.responseText);&lt;br /&gt;
                        var list = document.getElementById('raspberry-list');&lt;br /&gt;
                        list.innerHTML = '';&lt;br /&gt;
                        ids.forEach(function(id) {&lt;br /&gt;
                            var li = document.createElement('li');&lt;br /&gt;
                            li.textContent = id;&lt;br /&gt;
                            list.appendChild(li);&lt;br /&gt;
                        });&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-raspberry-ids', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function fetchLatestMessage() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        console.log(xhr.responseText)&lt;br /&gt;
                        document.getElementById('latest-message').textContent = xhr.responseText;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-latest-message', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setInterval(fetchRaspberryIds, 5000); // Met à jour les IDs toutes les 5 secondes&lt;br /&gt;
        setInterval(fetchLatestMessage, 500); // Met à jour le dernier message toutes les secondes&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    {% if error_message_rpi %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ error_message_rpi }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&lt;br /&gt;
    {% if success_message %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ success_message }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On a aussi ajouté une page de logs, qui permet de voir l'historique de tous les données traitées.&lt;br /&gt;
&lt;br /&gt;
=== 9. Conclusion et Perspectives ===&lt;br /&gt;
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont&lt;br /&gt;
&lt;br /&gt;
En conclusion, notre projet a vu la mise en place d'une infrastructure qui permet de facilité interaction  entre les serveurs et les Raspberry Pi, notamment pour le démarrage et l'arrêt de la collecte de données, ainsi que pour l'envoi d'instructions d'entraînement spécifiques. Bien que nous ayons entamé le développement des fonctionnalités d'entraînement, permettant à l'utilisateur de spécifier depuis l'interface web l'identifiant de la Raspberry Pi et la lettre à entraîner, cette partie n'a pas pu être totalement finalisée dans le temps imparti.&lt;br /&gt;
&lt;br /&gt;
Pour le processus d'entraînement, l'idée était que la Raspberry Pi reçoit la lettre depuis le serveur,après il initie la collecte des données à partir du module STM32, stocke ces données dans un fichier CSV et génère le fichier .pkl correspondant au modèle d'intelligence artificielle. Parallèlement, pour la gestion des données brutes, la Raspberry Pi recçoit la lettre et devait transmettre les informations collectées au serveur, qui aurait alors pour tâche de les stocker également sous forme de fichier CSV et de générer le fichier .pkl nécessaire à l'application de l'intelligence artificielle.&lt;br /&gt;
&lt;br /&gt;
Les perspectives d'évolution de ce projet sont multiples. Elles incluent la finalisation de la fonctionnalité d'entraînement pour permettre une interaction complète et efficace dans la préparation des modèles d'intelligence artificielle directement depuis l'interface web. De plus, l'amélioration de la gestion des données brutes pour optimiser le stockage et le traitement sur le serveur ouvrirait la voie à des analyses plus poussées et à une meilleure performance des modèles générés. Enfin, l'extension de cette infrastructure à un plus grand nombre de Raspberry Pi et l'intégration de fonctionnalités supplémentaires pourraient transformer ce projet en une solution robuste et scalable pour diverses applications nécessitant la collecte et l'analyse de données en temps réel.[[Fichier:SignEntrainement.png|centré|vignette|1000x1000px]]&lt;br /&gt;
&lt;br /&gt;
== Vidéo ==&lt;br /&gt;
Lorsqu'une raspberry se connecte au réseau, son ID apparait dans le cadre &amp;quot;Raspberry disponible&amp;quot;. Ensuite il suffit de choisir la raspberry, rentrer son ID dans l'emplacement prévu à cet effet, puis on clique sur &amp;quot;démarrer la collecte&amp;quot;, on peut voir en temps réel (mise jour du message toutes les secondes) le résultat dans le cadre Dernier Message Recu. Dans la vidéo on a choisi de prendre comme exemple la lettre &amp;quot;A&amp;quot;, &amp;quot;B&amp;quot;, les chiffres 1 et 2 et la phrase &amp;quot;I Love You&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:RPReplay_Final1706462779.mov|sans_cadre]]&lt;br /&gt;
[[Fichier:Capture d’écran 2024-01-29 à 15.43.56.png|néant|vignette]]&lt;br /&gt;
[[Fichier:Capture d’écran 2024-01-29 à 15.45.25.png|néant|vignette|133x133px]]&lt;br /&gt;
&lt;br /&gt;
== Déroulement des séances ==&lt;br /&gt;
&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:IfconfigVM.png|sans_cadre]]&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
[[Fichier:Capture d’écran 2024-01-28 à 19.07.42.png|néant|vignette]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4990</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4990"/>
		<updated>2024-01-29T14:50:29Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* Vidéo */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=SignSpeak 2023/2024 =&lt;br /&gt;
== '''Présentation du projet''' ==&lt;br /&gt;
&lt;br /&gt;
=== 1. Introduction ===&lt;br /&gt;
----Le projet SignSpeak a pour ambition de créer une solution innovante pour la traduction du langage des signes en texte. L'objectif principal est de développer un système capable de capturer les mouvements des mains et de les interpréter en langage des signes, permettant une communication fluide entre les personnes sourdes ou malentendantes et celles qui ne connaissent pas le langage des signes. Ce projet intègre des technologies avancées telles que l'edge computing, l'intelligence artificielle embarquée, et les communications MQTT, offrant une approche novatrice dans le domaine de l'accessibilité et de la communication.&lt;br /&gt;
&lt;br /&gt;
=== 2. Architecture du Système ===&lt;br /&gt;
----Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :&lt;br /&gt;
&lt;br /&gt;
* '''Capteurs et STM32''' : Des capteurs sont connectés à un microcontrôleur STM32, responsables de la capture des mouvements de main. Ces données sont ensuite transmises pour traitement.&lt;br /&gt;
* '''Raspberry Pi''' : Agissant comme un intermédiaire, la Raspberry Pi reçoit les données des capteurs via UART, exécute un traitement préliminaire et communique avec le serveur.&lt;br /&gt;
* '''Serveur et Machine Learning''' : Un serveur, hébergé sur une VM Xen, traite les données à l'aide d'un modèle SVM pour la traduction en langage des signes et fournit une interface web pour l'interaction utilisateur.&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== 3. Collecte et Préparation des Données ===&lt;br /&gt;
----Le processus de collecte des données est géré par le script &amp;lt;code&amp;gt;enregistrementData.py&amp;lt;/code&amp;gt;. Ce script lit les données transmises par le STM32 via UART et les enregistre dans un fichier CSV. Chaque entrée du fichier représente les valeurs de capteurs à un moment donné, accompagnées d'une étiquette correspondant au signe effectué. Cette approche assure une collecte de données structurée, essentielle pour l'entraînement précis du modèle d'apprentissage automatique.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
import csv&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
# Vérification de l'argument d'entrée&lt;br /&gt;
if len(sys.argv) &amp;lt; 2:&lt;br /&gt;
    print(&amp;quot;Usage: python script.py &amp;lt;etiquette&amp;gt;&amp;quot;)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
etiquette = sys.argv[1]&lt;br /&gt;
&lt;br /&gt;
# Paramètres de l'UART&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
&lt;br /&gt;
# Créer une connexion UART&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
&lt;br /&gt;
# Nom du fichier CSV&lt;br /&gt;
filename = f&amp;quot;data_complete.csv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Vérifier si le fichier existe déjà&lt;br /&gt;
file_exists = False&lt;br /&gt;
try:&lt;br /&gt;
    with open(filename, 'r') as f:&lt;br /&gt;
        file_exists = True&lt;br /&gt;
except FileNotFoundError:&lt;br /&gt;
    file_exists = False&lt;br /&gt;
&lt;br /&gt;
# Ouvrir le fichier CSV en mode append&lt;br /&gt;
with open(filename, 'a', newline='') as file:&lt;br /&gt;
    writer = csv.writer(file)&lt;br /&gt;
&lt;br /&gt;
    # Écrire l'en-tête si le fichier n'existait pas&lt;br /&gt;
    if not file_exists:&lt;br /&gt;
        writer.writerow([&amp;quot;Capteur1&amp;quot;, &amp;quot;Capteur2&amp;quot;, &amp;quot;Capteur3&amp;quot;, &amp;quot;Capteur4&amp;quot;, &amp;quot;Capteur5&amp;quot;, &amp;quot;Capteur6&amp;quot;, &amp;quot;Capteur7&amp;quot;, &amp;quot;Capteur8&amp;quot;, &amp;quot;Capteur9&amp;quot;, &amp;quot;Capteur10&amp;quot;, &amp;quot;Capteur11&amp;quot;, &amp;quot;Capteur12&amp;quot;, &amp;quot;Capteur13&amp;quot;, &amp;quot;Capteur14&amp;quot;, &lt;br /&gt;
&amp;quot;Capteur15&amp;quot;, &amp;quot;Capteur16&amp;quot;, &amp;quot;Etiquette&amp;quot;])&lt;br /&gt;
    elif file_exists:&lt;br /&gt;
        writer.writerow([])&lt;br /&gt;
    while True:&lt;br /&gt;
        # Lire une ligne de données depuis l'UART&lt;br /&gt;
        data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
        print(f&amp;quot;Données reçues : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Vérifier si des données ont été reçues&lt;br /&gt;
        if data:&lt;br /&gt;
            # Diviser les données en valeurs individuelles&lt;br /&gt;
            sensor_values = data.split(',')&lt;br /&gt;
&lt;br /&gt;
            # Filtrer les chaînes vides ou non numériques et convertir en flottants&lt;br /&gt;
            try:&lt;br /&gt;
                sensor_values = [float(value) for value in sensor_values if value.strip().isdigit()]&lt;br /&gt;
&lt;br /&gt;
                # Vérifier qu'il y a 16 valeurs de capteur&lt;br /&gt;
                if len(sensor_values) == 16:&lt;br /&gt;
                    sensor_values.append(etiquette)&lt;br /&gt;
                    writer.writerow(sensor_values)&lt;br /&gt;
                else:&lt;br /&gt;
                    print(&amp;quot;Données incomplètes reçues&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            except ValueError as e:&lt;br /&gt;
                print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
                print(f&amp;quot;Données problématiques : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Le script commence par établir une communication série avec le STM32.&lt;br /&gt;
* Il lit ensuite les données en série, les décode et les stocke dans un fichier CSV pour une utilisation ultérieure.&lt;br /&gt;
&lt;br /&gt;
* Une fois les données collectées et stockées dans le fichier CSV, elles sont préparées pour l'entraînement du modèle.&lt;br /&gt;
* Cette préparation implique la normalisation des données, la gestion des valeurs manquantes ou aberrantes, et leur formatage dans un bon format.[[Fichier:Rpi entrainement.png|vignette|1000x1000px|néant]]&lt;br /&gt;
=== 4. Entraînement du Modèle d'Apprentissage Automatique ===&lt;br /&gt;
----L'entraînement du modèle est réalisé par un script Python utilisant la bibliothèque scikit-learn. Le modèle SVM, choisi pour sa capacité à gérer des espaces de grande dimension, est entraîné sur l'ensemble des données collectées. Ce processus comprend la division des données en ensembles d'entraînement et de test, l'entraînement du modèle, et sa validation par le calcul de la précision. Nous avions testé plusieurs modèle, comme par exemple un modèle Knn ou randomForest, des 3 algorithmes, c'est celui qui nous à apporté les meilleurs résultats pour un meme nombre de data d'entrainement. (RandomForest en deuxième position)&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import pandas as pd&lt;br /&gt;
from sklearn.model_selection import train_test_split&lt;br /&gt;
from sklearn.svm import SVC&lt;br /&gt;
from sklearn.metrics import accuracy_score&lt;br /&gt;
import pickle&lt;br /&gt;
&lt;br /&gt;
# Charger vos données&lt;br /&gt;
data = pd.read_csv('data_complete.csv')&lt;br /&gt;
&lt;br /&gt;
# Séparer les caractéristiques et les étiquettes&lt;br /&gt;
X = data.drop('Etiquette', axis=1)&lt;br /&gt;
y = data['Etiquette']&lt;br /&gt;
&lt;br /&gt;
# Diviser les données en ensembles d'entraînement et de test&lt;br /&gt;
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)&lt;br /&gt;
&lt;br /&gt;
# Créer et entraîner le modèle SVM&lt;br /&gt;
model = SVC(kernel='rbf')&lt;br /&gt;
model.fit(X_train, y_train)&lt;br /&gt;
&lt;br /&gt;
# Sauvegarder le modèle entraîné&lt;br /&gt;
with open('modele_svm.pkl', 'wb') as file:&lt;br /&gt;
    pickle.dump(model, file)&lt;br /&gt;
&lt;br /&gt;
# Charger le modèle et faire des prédictions&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    loaded_model = pickle.load(file)&lt;br /&gt;
    predictions = loaded_model.predict(X_test)&lt;br /&gt;
    print(&amp;quot;Précision :&amp;quot;, accuracy_score(y_test, predictions))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# '''Séparation des Données''':&lt;br /&gt;
#* Les données sont divisées en deux ensembles : un ensemble d'entraînement et un ensemble de test. Cette séparation est cruciale pour évaluer objectivement la performance du modèle.&lt;br /&gt;
#* Généralement, on adopte une répartition de 80% pour l'entraînement et 20% pour les tests.&lt;br /&gt;
# '''Entraînement du Modèle SVM''':&lt;br /&gt;
#* Le modèle SVM avec un noyau RBF (Radial Basis Function) est entraîné sur l'ensemble d'entraînement.&lt;br /&gt;
#* L'entraînement implique l'ajustement du modèle aux données d'entraînement, en apprenant à distinguer les différents signes.&lt;br /&gt;
# '''Sauvegarde et Réutilisation du Modèle'''&lt;br /&gt;
#* Une fois entraîné et validé, le modèle est sauvegardé à l'aide de la bibliothèque &amp;lt;code&amp;gt;pickle&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Validation et Évaluation du Modèle''':&lt;br /&gt;
#* Après l'entraînement, le modèle est testé sur l'ensemble de test pour évaluer sa performance.&lt;br /&gt;
#* La métrique principale utilisée est la précision, qui mesure la proportion de prédictions correctes par rapport au total des prédictions.&lt;br /&gt;
&lt;br /&gt;
Ensuite on peut générer le modèle comme ceci:&lt;br /&gt;
[[Fichier:Generate model.png|vignette|399x399px|néant]]&lt;br /&gt;
&lt;br /&gt;
Avec cette prédiction lorsque notre modèle prédit le résultat, il est correct environ 71.81% du temps.&lt;br /&gt;
&lt;br /&gt;
=== 5. Intégration MQTT et Communication ===&lt;br /&gt;
----Protocole de communication  :&lt;br /&gt;
&lt;br /&gt;
Dans le cadre de notre projet, la communication entre les dispositifs Raspberry Pi et le serveur  est établie via le protocole MQTT.&lt;br /&gt;
&lt;br /&gt;
Justification du Choix de MQTT :&lt;br /&gt;
&lt;br /&gt;
Au début du projet, une approche basée sur des sockets IPv6 avait été envisagée pour tirer parti de l'adressage direct et de la simplification de la configuration réseau qu'offre IPv6. Cependant, dans le but de respecter les impératifs de sobriété énergétique et d'assurer une scalabilité optimale du système, permettant ainsi de gérer aisément un nombre croissant de dispositifs Raspberry Pi, la décision a été prise d'adopter MQTT comme protocole de communication. Le protocole MQTT, reconnu pour sa légèreté et sa fiabilité, s'adapte parfaitement aux contraintes des applications IoT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Installation du broker mosquitto sur le serveur:'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
apt install -y mosquitto mosquitto-clients&lt;br /&gt;
service mosquitto start&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Activation de l'accès à distance au Broker Mosquitto:&lt;br /&gt;
&lt;br /&gt;
ajouter l'authentification par username et mot de passe&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
sudo mosquitto_passwd -c /etc/mosquitto/passwd username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
après on nous demande d'entrer le mot de passe &lt;br /&gt;
&lt;br /&gt;
Modifier le fichier /etc/mosquitto/mosquitto.conf:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
listener 1883 10.42.0.5&lt;br /&gt;
#listener 1883 2001:660:4401:6050:216:3eff:fe86:cd63&lt;br /&gt;
allow_anonymous false&lt;br /&gt;
password_file /etc/mosquitto/passwd&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Mosquitto:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
service mosquitto restart&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vérification ds logs:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
cat /var/log/mosquitto/mosquitto.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Création d'un client MQTT sur la Raspberry Pi:'''&lt;br /&gt;
&lt;br /&gt;
Le script mqtt_client_rpi.py joue un rôle clé dans cette architecture en facilitant la communication bidirectionnelle : il permet non seulement l'envoi des prédictions réalisées par le modèle SVM depuis la Raspberry Pi vers le serveur, mais autorise également la réception des commandes de contrôle, telles que les instructions de démarrage ou d'arrêt de la collecte de données.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import serial&lt;br /&gt;
import pandas as pd&lt;br /&gt;
import pickle&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
#MQTT_BROKER_ADDRESS = &amp;quot;2001:660:4401:6050:216:3eff:fe86:cd63&amp;quot; VmHblgrimBblack&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
pi_id = &amp;quot;rpi1234&amp;quot;&lt;br /&gt;
&lt;br /&gt;
collecting_data = False &lt;br /&gt;
&lt;br /&gt;
client = mqtt.Client()&lt;br /&gt;
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)&lt;br /&gt;
client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
client.loop_start()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(f&amp;quot;config/{pi_id}&amp;quot;)&lt;br /&gt;
    client.publish(&amp;quot;raspberry_available&amp;quot;, pi_id)&lt;br /&gt;
&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global collecting_data&lt;br /&gt;
    if msg.topic == f&amp;quot;config/{pi_id}&amp;quot;:&lt;br /&gt;
        command = msg.payload.decode()&lt;br /&gt;
        if command == &amp;quot;start&amp;quot;:&lt;br /&gt;
            collecting_data = True&lt;br /&gt;
        elif command == &amp;quot;stop&amp;quot;:&lt;br /&gt;
            collecting_data = False&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.on_connect = on_connect&lt;br /&gt;
client.on_message = on_message&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Configurez le port série et chargez le modèle ici&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    rf = pickle.load(file)&lt;br /&gt;
try:&lt;br /&gt;
&lt;br /&gt;
    while True:&lt;br /&gt;
        if collecting_data:&lt;br /&gt;
            data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
            if data:&lt;br /&gt;
                try:&lt;br /&gt;
                    sensor_values = [value for value in data.split(',') if value.strip().replace('.', '', 1).isdigit()]&lt;br /&gt;
                    if len(sensor_values) == 16:&lt;br /&gt;
                        sensor_values = list(map(float, sensor_values))&lt;br /&gt;
                        sensor_values_df = pd.DataFrame([sensor_values])&lt;br /&gt;
                        prediction = rf.predict(sensor_values_df)&lt;br /&gt;
                        client.publish(f&amp;quot;telemetry/{pi_id}&amp;quot;, str(prediction[0]).encode())&lt;br /&gt;
                        print(&amp;quot;Prédiction :&amp;quot;, prediction[0])&lt;br /&gt;
                except ValueError as e:&lt;br /&gt;
                    print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:&lt;br /&gt;
    print(&amp;quot;Script interrompu&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.loop_stop()&lt;br /&gt;
client.disconnect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Ici il y a 3 topics différents. lorsqu'une raspberry se connecte au réseau elle publie son ID (qui est unique, on peut prendre par exemple l'adresse MAC) sur le topic raspberry_available. Cela nous servira a savoir quelle raspberry est connecté et de se fait pouvoir afficher celles-ci sur notre interface web.&lt;br /&gt;
&lt;br /&gt;
le deuxième topic et le topic config/ID (avec id l'identifiant unique de la raspberry), il nous sert a envoyer les commandes &amp;quot;start&amp;quot; et &amp;quot;stop&amp;quot; a la raspberry afin qu'elle démarre ou arrête la lecture des datas.&lt;br /&gt;
&lt;br /&gt;
Le troisième topic est le topic telemetry/ID, ou la raspberry vient publier ses données.&lt;br /&gt;
&lt;br /&gt;
Un quatrième topic pourrait être implémenter comme par exemple le topic common_config, toutes les raspberrys serait abonnées a ce topic. S'il est nécessaire, cela nous permettrais d'envoyer la même commande a toutes les raspberry  plutôt que de faire une publication sur chaque config/ID&lt;br /&gt;
&lt;br /&gt;
=== 6. Interface Serveur et Gestion des Données ===&lt;br /&gt;
----Le serveur central, au cœur de notre système, est orchestré par le script &amp;lt;code&amp;gt;app.py&amp;lt;/code&amp;gt; qui exploite le framework Flask pour mettre en place une interface serveur. Cette interface est conçue pour traiter efficacement les requêtes HTTP et les messages MQTT, offrant ainsi une API réactive pour l'interface utilisateur web. Elle permet également de visualiser en temps réel l'état des dispositifs Raspberry Pi connectés et les dernières données traitées.&lt;br /&gt;
[[Fichier:Signspeakweb.png|centré|vignette|1000x1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from flask import Flask, render_template, request, jsonify&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import queue&lt;br /&gt;
&lt;br /&gt;
app = Flask(__name__)&lt;br /&gt;
messages = []&lt;br /&gt;
received_messages = queue.Queue()&lt;br /&gt;
latest_message = None&lt;br /&gt;
subscribed_topics = set()&lt;br /&gt;
raspberry_ids = set()&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
#MQTT_BROKER_ADDRESS = &amp;quot;2001:660:4401:6050:216:3eff:fe86:cd63&amp;quot; VmHblgrimBblack&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client = mqtt.Client()&lt;br /&gt;
mqtt_client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD) &lt;br /&gt;
mqtt_client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
mqtt_client.loop_start()&lt;br /&gt;
&lt;br /&gt;
def send_command_to_pi(pi_id, command):&lt;br /&gt;
    try:&lt;br /&gt;
        topic = f&amp;quot;config/{pi_id}&amp;quot;&lt;br /&gt;
        mqtt_client.publish(topic, command)&lt;br /&gt;
        subscribe_to_pi_telemetry(pi_id)&lt;br /&gt;
        return True, &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
    except Exception as e:&lt;br /&gt;
        return False, f&amp;quot;Commande pas envoyée: Erreur MQTT : {e}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
def subscribe_to_pi_telemetry(pi_id):&lt;br /&gt;
    global subscribed_topics&lt;br /&gt;
    topic = f&amp;quot;telemetry/{pi_id}&amp;quot;&lt;br /&gt;
    if topic not in subscribed_topics:&lt;br /&gt;
        mqtt_client.subscribe(topic)&lt;br /&gt;
        subscribed_topics.add(topic)&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(&amp;quot;raspberry_available&amp;quot;)&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    print(f&amp;quot;Received message on topic {msg.topic}: {msg.payload.decode()}&amp;quot;)  # Ajouter pour le débogage&lt;br /&gt;
    if msg.topic == &amp;quot;raspberry_available&amp;quot;:&lt;br /&gt;
        raspberry_ids.add(msg.payload.decode())&lt;br /&gt;
    else:&lt;br /&gt;
        received_messages.put(msg.payload.decode())&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client.on_connect = on_connect&lt;br /&gt;
mqtt_client.on_message = on_message&lt;br /&gt;
@app.route('/get-raspberry-ids')&lt;br /&gt;
def get_raspberry_ids():&lt;br /&gt;
    return jsonify(list(raspberry_ids))&lt;br /&gt;
@app.route('/get-latest-message')&lt;br /&gt;
def get_latest_message():&lt;br /&gt;
    global latest_message&lt;br /&gt;
    while not received_messages.empty():&lt;br /&gt;
        messages.append(received_messages.get())&lt;br /&gt;
&lt;br /&gt;
    latest_message = messages[-1] if messages else None&lt;br /&gt;
    &lt;br /&gt;
    print(f&amp;quot;Contenu de la réponse pour /get-latest-message : {latest_message}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    if latest_message is not None:&lt;br /&gt;
         response = jsonify({&amp;quot;message&amp;quot;: latest_message})&lt;br /&gt;
         return response&lt;br /&gt;
    else:&lt;br /&gt;
        message = &amp;quot;Aucun signe a traduire pour le moment&amp;quot;&lt;br /&gt;
        return jsonify(message)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@app.route('/', methods=['GET', 'POST'])&lt;br /&gt;
&lt;br /&gt;
def index():&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    error_message_rpi = None&lt;br /&gt;
    success_message = None&lt;br /&gt;
&lt;br /&gt;
    if request.method == 'POST':&lt;br /&gt;
        pi_id = request.form.get('pi_id')&lt;br /&gt;
        command = request.form.get('command')&lt;br /&gt;
        if pi_id and command in [&amp;quot;start&amp;quot;, &amp;quot;stop&amp;quot;]:&lt;br /&gt;
            success, er_message = send_command_to_pi(pi_id, command)&lt;br /&gt;
            if success:&lt;br /&gt;
                success_message = &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                error_message_rpi = er_message&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    return render_template('index.html', raspberry_ids=list(raspberry_ids), error_message_rpi=error_message_rpi, success_message=success_message, message=latest_message)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    app.run(debug=False, port=8066)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7. Conception de l'Interface Utilisateur ===&lt;br /&gt;
----L'interface utilisateur, développée à l'aide des technologies web standard HTML, CSS, et JavaScript, offre une expérience interactive. Le fichier index.html constitue le point d'entrée de cette interface, proposant des fonctionnalités telles que l'envoi de commandes aux dispositifs Raspberry Pi et la visualisation des données traitées. L'utilisation de JavaScript pour interroger dynamiquement le serveur Flask permet de rafraîchir les informations affichées en temps réel, garantissant ainsi une interface réactive et à jour.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
index.html:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
        body {&lt;br /&gt;
            background-color: #343a40; &lt;br /&gt;
            color: #ced4da; &lt;br /&gt;
        }&lt;br /&gt;
        .card {&lt;br /&gt;
            background-color: #495057; &lt;br /&gt;
        }&lt;br /&gt;
        .card-title, .card-text, .alert {&lt;br /&gt;
            color: #adb5bd; &lt;br /&gt;
        }&lt;br /&gt;
        .btn-primary {&lt;br /&gt;
            background-color: #007bff; &lt;br /&gt;
            border-color: #007bff;&lt;br /&gt;
        }&lt;br /&gt;
        .btn-danger {&lt;br /&gt;
            background-color: #dc3545; &lt;br /&gt;
            border-color: #dc3545;&lt;br /&gt;
        }&lt;br /&gt;
        .form-control {&lt;br /&gt;
            background-color: #495057; &lt;br /&gt;
            border: 1px solid #6c757d;&lt;br /&gt;
            color: #ced4da; &lt;br /&gt;
        }&lt;br /&gt;
        a, .btn-secondary {&lt;br /&gt;
            color: #17a2b8; &lt;br /&gt;
        }&lt;br /&gt;
        a:hover {&lt;br /&gt;
            color: #138496; &lt;br /&gt;
        }&lt;br /&gt;
        #latest-message {&lt;br /&gt;
            background-color: #596069; &lt;br /&gt;
            border: 1px solid #6c757d; &lt;br /&gt;
            color: #E9ECEF; &lt;br /&gt;
            padding: 10px; &lt;br /&gt;
            border-radius: 5px; &lt;br /&gt;
        }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;container mt-5&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;h1 class=&amp;quot;text-center mb-4&amp;quot;&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/h1&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour les Raspberry Pi Disponibles --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-md-12&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Raspberry Pi Disponibles&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;ul id=&amp;quot;raspberry-list&amp;quot; class=&amp;quot;list-group list-group-flush&amp;quot;&amp;gt;&lt;br /&gt;
                    &lt;br /&gt;
                        &amp;lt;/ul&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour la Collecte des données --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Collecte de données&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;form method=&amp;quot;post&amp;quot; class=&amp;quot;form-inline&amp;quot;&amp;gt;&lt;br /&gt;
                            &amp;lt;input type=&amp;quot;text&amp;quot; class=&amp;quot;form-control mb-2 mr-sm-2&amp;quot; name=&amp;quot;pi_id&amp;quot; placeholder=&amp;quot;Entrez l'ID de la Raspberry Pi&amp;quot; required&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-primary mb-2 mr-sm-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;start&amp;quot;&amp;gt;Démarrer la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-danger mb-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;stop&amp;quot;&amp;gt;Arrêter la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                        &amp;lt;/form&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;!-- Encadré pour le Dernier Message Reçu --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Dernier Message Reçu&amp;lt;/h2&amp;gt;&lt;br /&gt;
                    &amp;lt;div id=&amp;quot;latest-message&amp;quot; class=&amp;quot;alert alert-dark&amp;quot;&amp;gt;&lt;br /&gt;
                        Aucun message reçu pour le moment. &lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;mb-3 text-center&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;a href=&amp;quot;/logs&amp;quot; class=&amp;quot;btn btn-secondary&amp;quot;&amp;gt;Voir les Logs&amp;lt;/a&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        function fetchRaspberryIds() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        var ids = JSON.parse(xhr.responseText);&lt;br /&gt;
                        var list = document.getElementById('raspberry-list');&lt;br /&gt;
                        list.innerHTML = '';&lt;br /&gt;
                        ids.forEach(function(id) {&lt;br /&gt;
                            var li = document.createElement('li');&lt;br /&gt;
                            li.textContent = id;&lt;br /&gt;
                            list.appendChild(li);&lt;br /&gt;
                        });&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-raspberry-ids', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function fetchLatestMessage() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        console.log(xhr.responseText)&lt;br /&gt;
                        document.getElementById('latest-message').textContent = xhr.responseText;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-latest-message', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setInterval(fetchRaspberryIds, 5000); // Met à jour les IDs toutes les 5 secondes&lt;br /&gt;
        setInterval(fetchLatestMessage, 500); // Met à jour le dernier message toutes les secondes&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    {% if error_message_rpi %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ error_message_rpi }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&lt;br /&gt;
    {% if success_message %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ success_message }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On a aussi ajouté une page de logs, qui permet de voir l'historique de tous les données traitées.&lt;br /&gt;
&lt;br /&gt;
=== 9. Conclusion et Perspectives ===&lt;br /&gt;
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont&lt;br /&gt;
&lt;br /&gt;
En conclusion, notre projet a vu la mise en place d'une infrastructure qui permet de facilité interaction  entre les serveurs et les Raspberry Pi, notamment pour le démarrage et l'arrêt de la collecte de données, ainsi que pour l'envoi d'instructions d'entraînement spécifiques. Bien que nous ayons entamé le développement des fonctionnalités d'entraînement, permettant à l'utilisateur de spécifier depuis l'interface web l'identifiant de la Raspberry Pi et la lettre à entraîner, cette partie n'a pas pu être totalement finalisée dans le temps imparti.&lt;br /&gt;
&lt;br /&gt;
Pour le processus d'entraînement, l'idée était que la Raspberry Pi reçoit la lettre depuis le serveur,après il initie la collecte des données à partir du module STM32, stocke ces données dans un fichier CSV et génère le fichier .pkl correspondant au modèle d'intelligence artificielle. Parallèlement, pour la gestion des données brutes, la Raspberry Pi recçoit la lettre et devait transmettre les informations collectées au serveur, qui aurait alors pour tâche de les stocker également sous forme de fichier CSV et de générer le fichier .pkl nécessaire à l'application de l'intelligence artificielle.&lt;br /&gt;
&lt;br /&gt;
Les perspectives d'évolution de ce projet sont multiples. Elles incluent la finalisation de la fonctionnalité d'entraînement pour permettre une interaction complète et efficace dans la préparation des modèles d'intelligence artificielle directement depuis l'interface web. De plus, l'amélioration de la gestion des données brutes pour optimiser le stockage et le traitement sur le serveur ouvrirait la voie à des analyses plus poussées et à une meilleure performance des modèles générés. Enfin, l'extension de cette infrastructure à un plus grand nombre de Raspberry Pi et l'intégration de fonctionnalités supplémentaires pourraient transformer ce projet en une solution robuste et scalable pour diverses applications nécessitant la collecte et l'analyse de données en temps réel.[[Fichier:SignEntrainement.png|centré|vignette|1000x1000px]]&lt;br /&gt;
&lt;br /&gt;
== Vidéo ==&lt;br /&gt;
Lorsque l'on clique sur &amp;quot;démarrer la collecte&amp;quot; en ayant spécifié un ID, on peut voir en temps réel le résultat dans le cadre Dernier Message Recu. Dans la vidéo on a choisi de prendre comme exemple la lettre &amp;quot;A&amp;quot;, &amp;quot;B&amp;quot;, les chiffres 1 et 2 et la phrase &amp;quot;I Love You&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:RPReplay_Final1706462779.mov|sans_cadre]]&lt;br /&gt;
[[Fichier:Capture d’écran 2024-01-29 à 15.43.56.png|néant|vignette]]&lt;br /&gt;
[[Fichier:Capture d’écran 2024-01-29 à 15.45.25.png|néant|vignette|133x133px]]&lt;br /&gt;
&lt;br /&gt;
== Déroulement des séances ==&lt;br /&gt;
&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:IfconfigVM.png|sans_cadre]]&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
[[Fichier:Capture d’écran 2024-01-28 à 19.07.42.png|néant|vignette]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4989</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4989"/>
		<updated>2024-01-29T14:50:12Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* Vidéo */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=SignSpeak 2023/2024 =&lt;br /&gt;
== '''Présentation du projet''' ==&lt;br /&gt;
&lt;br /&gt;
=== 1. Introduction ===&lt;br /&gt;
----Le projet SignSpeak a pour ambition de créer une solution innovante pour la traduction du langage des signes en texte. L'objectif principal est de développer un système capable de capturer les mouvements des mains et de les interpréter en langage des signes, permettant une communication fluide entre les personnes sourdes ou malentendantes et celles qui ne connaissent pas le langage des signes. Ce projet intègre des technologies avancées telles que l'edge computing, l'intelligence artificielle embarquée, et les communications MQTT, offrant une approche novatrice dans le domaine de l'accessibilité et de la communication.&lt;br /&gt;
&lt;br /&gt;
=== 2. Architecture du Système ===&lt;br /&gt;
----Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :&lt;br /&gt;
&lt;br /&gt;
* '''Capteurs et STM32''' : Des capteurs sont connectés à un microcontrôleur STM32, responsables de la capture des mouvements de main. Ces données sont ensuite transmises pour traitement.&lt;br /&gt;
* '''Raspberry Pi''' : Agissant comme un intermédiaire, la Raspberry Pi reçoit les données des capteurs via UART, exécute un traitement préliminaire et communique avec le serveur.&lt;br /&gt;
* '''Serveur et Machine Learning''' : Un serveur, hébergé sur une VM Xen, traite les données à l'aide d'un modèle SVM pour la traduction en langage des signes et fournit une interface web pour l'interaction utilisateur.&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== 3. Collecte et Préparation des Données ===&lt;br /&gt;
----Le processus de collecte des données est géré par le script &amp;lt;code&amp;gt;enregistrementData.py&amp;lt;/code&amp;gt;. Ce script lit les données transmises par le STM32 via UART et les enregistre dans un fichier CSV. Chaque entrée du fichier représente les valeurs de capteurs à un moment donné, accompagnées d'une étiquette correspondant au signe effectué. Cette approche assure une collecte de données structurée, essentielle pour l'entraînement précis du modèle d'apprentissage automatique.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
import csv&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
# Vérification de l'argument d'entrée&lt;br /&gt;
if len(sys.argv) &amp;lt; 2:&lt;br /&gt;
    print(&amp;quot;Usage: python script.py &amp;lt;etiquette&amp;gt;&amp;quot;)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
etiquette = sys.argv[1]&lt;br /&gt;
&lt;br /&gt;
# Paramètres de l'UART&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
&lt;br /&gt;
# Créer une connexion UART&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
&lt;br /&gt;
# Nom du fichier CSV&lt;br /&gt;
filename = f&amp;quot;data_complete.csv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Vérifier si le fichier existe déjà&lt;br /&gt;
file_exists = False&lt;br /&gt;
try:&lt;br /&gt;
    with open(filename, 'r') as f:&lt;br /&gt;
        file_exists = True&lt;br /&gt;
except FileNotFoundError:&lt;br /&gt;
    file_exists = False&lt;br /&gt;
&lt;br /&gt;
# Ouvrir le fichier CSV en mode append&lt;br /&gt;
with open(filename, 'a', newline='') as file:&lt;br /&gt;
    writer = csv.writer(file)&lt;br /&gt;
&lt;br /&gt;
    # Écrire l'en-tête si le fichier n'existait pas&lt;br /&gt;
    if not file_exists:&lt;br /&gt;
        writer.writerow([&amp;quot;Capteur1&amp;quot;, &amp;quot;Capteur2&amp;quot;, &amp;quot;Capteur3&amp;quot;, &amp;quot;Capteur4&amp;quot;, &amp;quot;Capteur5&amp;quot;, &amp;quot;Capteur6&amp;quot;, &amp;quot;Capteur7&amp;quot;, &amp;quot;Capteur8&amp;quot;, &amp;quot;Capteur9&amp;quot;, &amp;quot;Capteur10&amp;quot;, &amp;quot;Capteur11&amp;quot;, &amp;quot;Capteur12&amp;quot;, &amp;quot;Capteur13&amp;quot;, &amp;quot;Capteur14&amp;quot;, &lt;br /&gt;
&amp;quot;Capteur15&amp;quot;, &amp;quot;Capteur16&amp;quot;, &amp;quot;Etiquette&amp;quot;])&lt;br /&gt;
    elif file_exists:&lt;br /&gt;
        writer.writerow([])&lt;br /&gt;
    while True:&lt;br /&gt;
        # Lire une ligne de données depuis l'UART&lt;br /&gt;
        data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
        print(f&amp;quot;Données reçues : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Vérifier si des données ont été reçues&lt;br /&gt;
        if data:&lt;br /&gt;
            # Diviser les données en valeurs individuelles&lt;br /&gt;
            sensor_values = data.split(',')&lt;br /&gt;
&lt;br /&gt;
            # Filtrer les chaînes vides ou non numériques et convertir en flottants&lt;br /&gt;
            try:&lt;br /&gt;
                sensor_values = [float(value) for value in sensor_values if value.strip().isdigit()]&lt;br /&gt;
&lt;br /&gt;
                # Vérifier qu'il y a 16 valeurs de capteur&lt;br /&gt;
                if len(sensor_values) == 16:&lt;br /&gt;
                    sensor_values.append(etiquette)&lt;br /&gt;
                    writer.writerow(sensor_values)&lt;br /&gt;
                else:&lt;br /&gt;
                    print(&amp;quot;Données incomplètes reçues&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            except ValueError as e:&lt;br /&gt;
                print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
                print(f&amp;quot;Données problématiques : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Le script commence par établir une communication série avec le STM32.&lt;br /&gt;
* Il lit ensuite les données en série, les décode et les stocke dans un fichier CSV pour une utilisation ultérieure.&lt;br /&gt;
&lt;br /&gt;
* Une fois les données collectées et stockées dans le fichier CSV, elles sont préparées pour l'entraînement du modèle.&lt;br /&gt;
* Cette préparation implique la normalisation des données, la gestion des valeurs manquantes ou aberrantes, et leur formatage dans un bon format.[[Fichier:Rpi entrainement.png|vignette|1000x1000px|néant]]&lt;br /&gt;
=== 4. Entraînement du Modèle d'Apprentissage Automatique ===&lt;br /&gt;
----L'entraînement du modèle est réalisé par un script Python utilisant la bibliothèque scikit-learn. Le modèle SVM, choisi pour sa capacité à gérer des espaces de grande dimension, est entraîné sur l'ensemble des données collectées. Ce processus comprend la division des données en ensembles d'entraînement et de test, l'entraînement du modèle, et sa validation par le calcul de la précision. Nous avions testé plusieurs modèle, comme par exemple un modèle Knn ou randomForest, des 3 algorithmes, c'est celui qui nous à apporté les meilleurs résultats pour un meme nombre de data d'entrainement. (RandomForest en deuxième position)&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import pandas as pd&lt;br /&gt;
from sklearn.model_selection import train_test_split&lt;br /&gt;
from sklearn.svm import SVC&lt;br /&gt;
from sklearn.metrics import accuracy_score&lt;br /&gt;
import pickle&lt;br /&gt;
&lt;br /&gt;
# Charger vos données&lt;br /&gt;
data = pd.read_csv('data_complete.csv')&lt;br /&gt;
&lt;br /&gt;
# Séparer les caractéristiques et les étiquettes&lt;br /&gt;
X = data.drop('Etiquette', axis=1)&lt;br /&gt;
y = data['Etiquette']&lt;br /&gt;
&lt;br /&gt;
# Diviser les données en ensembles d'entraînement et de test&lt;br /&gt;
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)&lt;br /&gt;
&lt;br /&gt;
# Créer et entraîner le modèle SVM&lt;br /&gt;
model = SVC(kernel='rbf')&lt;br /&gt;
model.fit(X_train, y_train)&lt;br /&gt;
&lt;br /&gt;
# Sauvegarder le modèle entraîné&lt;br /&gt;
with open('modele_svm.pkl', 'wb') as file:&lt;br /&gt;
    pickle.dump(model, file)&lt;br /&gt;
&lt;br /&gt;
# Charger le modèle et faire des prédictions&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    loaded_model = pickle.load(file)&lt;br /&gt;
    predictions = loaded_model.predict(X_test)&lt;br /&gt;
    print(&amp;quot;Précision :&amp;quot;, accuracy_score(y_test, predictions))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# '''Séparation des Données''':&lt;br /&gt;
#* Les données sont divisées en deux ensembles : un ensemble d'entraînement et un ensemble de test. Cette séparation est cruciale pour évaluer objectivement la performance du modèle.&lt;br /&gt;
#* Généralement, on adopte une répartition de 80% pour l'entraînement et 20% pour les tests.&lt;br /&gt;
# '''Entraînement du Modèle SVM''':&lt;br /&gt;
#* Le modèle SVM avec un noyau RBF (Radial Basis Function) est entraîné sur l'ensemble d'entraînement.&lt;br /&gt;
#* L'entraînement implique l'ajustement du modèle aux données d'entraînement, en apprenant à distinguer les différents signes.&lt;br /&gt;
# '''Sauvegarde et Réutilisation du Modèle'''&lt;br /&gt;
#* Une fois entraîné et validé, le modèle est sauvegardé à l'aide de la bibliothèque &amp;lt;code&amp;gt;pickle&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Validation et Évaluation du Modèle''':&lt;br /&gt;
#* Après l'entraînement, le modèle est testé sur l'ensemble de test pour évaluer sa performance.&lt;br /&gt;
#* La métrique principale utilisée est la précision, qui mesure la proportion de prédictions correctes par rapport au total des prédictions.&lt;br /&gt;
&lt;br /&gt;
Ensuite on peut générer le modèle comme ceci:&lt;br /&gt;
[[Fichier:Generate model.png|vignette|399x399px|néant]]&lt;br /&gt;
&lt;br /&gt;
Avec cette prédiction lorsque notre modèle prédit le résultat, il est correct environ 71.81% du temps.&lt;br /&gt;
&lt;br /&gt;
=== 5. Intégration MQTT et Communication ===&lt;br /&gt;
----Protocole de communication  :&lt;br /&gt;
&lt;br /&gt;
Dans le cadre de notre projet, la communication entre les dispositifs Raspberry Pi et le serveur  est établie via le protocole MQTT.&lt;br /&gt;
&lt;br /&gt;
Justification du Choix de MQTT :&lt;br /&gt;
&lt;br /&gt;
Au début du projet, une approche basée sur des sockets IPv6 avait été envisagée pour tirer parti de l'adressage direct et de la simplification de la configuration réseau qu'offre IPv6. Cependant, dans le but de respecter les impératifs de sobriété énergétique et d'assurer une scalabilité optimale du système, permettant ainsi de gérer aisément un nombre croissant de dispositifs Raspberry Pi, la décision a été prise d'adopter MQTT comme protocole de communication. Le protocole MQTT, reconnu pour sa légèreté et sa fiabilité, s'adapte parfaitement aux contraintes des applications IoT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Installation du broker mosquitto sur le serveur:'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
apt install -y mosquitto mosquitto-clients&lt;br /&gt;
service mosquitto start&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Activation de l'accès à distance au Broker Mosquitto:&lt;br /&gt;
&lt;br /&gt;
ajouter l'authentification par username et mot de passe&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
sudo mosquitto_passwd -c /etc/mosquitto/passwd username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
après on nous demande d'entrer le mot de passe &lt;br /&gt;
&lt;br /&gt;
Modifier le fichier /etc/mosquitto/mosquitto.conf:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
listener 1883 10.42.0.5&lt;br /&gt;
#listener 1883 2001:660:4401:6050:216:3eff:fe86:cd63&lt;br /&gt;
allow_anonymous false&lt;br /&gt;
password_file /etc/mosquitto/passwd&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Mosquitto:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
service mosquitto restart&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vérification ds logs:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
cat /var/log/mosquitto/mosquitto.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Création d'un client MQTT sur la Raspberry Pi:'''&lt;br /&gt;
&lt;br /&gt;
Le script mqtt_client_rpi.py joue un rôle clé dans cette architecture en facilitant la communication bidirectionnelle : il permet non seulement l'envoi des prédictions réalisées par le modèle SVM depuis la Raspberry Pi vers le serveur, mais autorise également la réception des commandes de contrôle, telles que les instructions de démarrage ou d'arrêt de la collecte de données.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import serial&lt;br /&gt;
import pandas as pd&lt;br /&gt;
import pickle&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
#MQTT_BROKER_ADDRESS = &amp;quot;2001:660:4401:6050:216:3eff:fe86:cd63&amp;quot; VmHblgrimBblack&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
pi_id = &amp;quot;rpi1234&amp;quot;&lt;br /&gt;
&lt;br /&gt;
collecting_data = False &lt;br /&gt;
&lt;br /&gt;
client = mqtt.Client()&lt;br /&gt;
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)&lt;br /&gt;
client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
client.loop_start()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(f&amp;quot;config/{pi_id}&amp;quot;)&lt;br /&gt;
    client.publish(&amp;quot;raspberry_available&amp;quot;, pi_id)&lt;br /&gt;
&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global collecting_data&lt;br /&gt;
    if msg.topic == f&amp;quot;config/{pi_id}&amp;quot;:&lt;br /&gt;
        command = msg.payload.decode()&lt;br /&gt;
        if command == &amp;quot;start&amp;quot;:&lt;br /&gt;
            collecting_data = True&lt;br /&gt;
        elif command == &amp;quot;stop&amp;quot;:&lt;br /&gt;
            collecting_data = False&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.on_connect = on_connect&lt;br /&gt;
client.on_message = on_message&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Configurez le port série et chargez le modèle ici&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    rf = pickle.load(file)&lt;br /&gt;
try:&lt;br /&gt;
&lt;br /&gt;
    while True:&lt;br /&gt;
        if collecting_data:&lt;br /&gt;
            data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
            if data:&lt;br /&gt;
                try:&lt;br /&gt;
                    sensor_values = [value for value in data.split(',') if value.strip().replace('.', '', 1).isdigit()]&lt;br /&gt;
                    if len(sensor_values) == 16:&lt;br /&gt;
                        sensor_values = list(map(float, sensor_values))&lt;br /&gt;
                        sensor_values_df = pd.DataFrame([sensor_values])&lt;br /&gt;
                        prediction = rf.predict(sensor_values_df)&lt;br /&gt;
                        client.publish(f&amp;quot;telemetry/{pi_id}&amp;quot;, str(prediction[0]).encode())&lt;br /&gt;
                        print(&amp;quot;Prédiction :&amp;quot;, prediction[0])&lt;br /&gt;
                except ValueError as e:&lt;br /&gt;
                    print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:&lt;br /&gt;
    print(&amp;quot;Script interrompu&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.loop_stop()&lt;br /&gt;
client.disconnect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Ici il y a 3 topics différents. lorsqu'une raspberry se connecte au réseau elle publie son ID (qui est unique, on peut prendre par exemple l'adresse MAC) sur le topic raspberry_available. Cela nous servira a savoir quelle raspberry est connecté et de se fait pouvoir afficher celles-ci sur notre interface web.&lt;br /&gt;
&lt;br /&gt;
le deuxième topic et le topic config/ID (avec id l'identifiant unique de la raspberry), il nous sert a envoyer les commandes &amp;quot;start&amp;quot; et &amp;quot;stop&amp;quot; a la raspberry afin qu'elle démarre ou arrête la lecture des datas.&lt;br /&gt;
&lt;br /&gt;
Le troisième topic est le topic telemetry/ID, ou la raspberry vient publier ses données.&lt;br /&gt;
&lt;br /&gt;
Un quatrième topic pourrait être implémenter comme par exemple le topic common_config, toutes les raspberrys serait abonnées a ce topic. S'il est nécessaire, cela nous permettrais d'envoyer la même commande a toutes les raspberry  plutôt que de faire une publication sur chaque config/ID&lt;br /&gt;
&lt;br /&gt;
=== 6. Interface Serveur et Gestion des Données ===&lt;br /&gt;
----Le serveur central, au cœur de notre système, est orchestré par le script &amp;lt;code&amp;gt;app.py&amp;lt;/code&amp;gt; qui exploite le framework Flask pour mettre en place une interface serveur. Cette interface est conçue pour traiter efficacement les requêtes HTTP et les messages MQTT, offrant ainsi une API réactive pour l'interface utilisateur web. Elle permet également de visualiser en temps réel l'état des dispositifs Raspberry Pi connectés et les dernières données traitées.&lt;br /&gt;
[[Fichier:Signspeakweb.png|centré|vignette|1000x1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from flask import Flask, render_template, request, jsonify&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import queue&lt;br /&gt;
&lt;br /&gt;
app = Flask(__name__)&lt;br /&gt;
messages = []&lt;br /&gt;
received_messages = queue.Queue()&lt;br /&gt;
latest_message = None&lt;br /&gt;
subscribed_topics = set()&lt;br /&gt;
raspberry_ids = set()&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
#MQTT_BROKER_ADDRESS = &amp;quot;2001:660:4401:6050:216:3eff:fe86:cd63&amp;quot; VmHblgrimBblack&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client = mqtt.Client()&lt;br /&gt;
mqtt_client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD) &lt;br /&gt;
mqtt_client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
mqtt_client.loop_start()&lt;br /&gt;
&lt;br /&gt;
def send_command_to_pi(pi_id, command):&lt;br /&gt;
    try:&lt;br /&gt;
        topic = f&amp;quot;config/{pi_id}&amp;quot;&lt;br /&gt;
        mqtt_client.publish(topic, command)&lt;br /&gt;
        subscribe_to_pi_telemetry(pi_id)&lt;br /&gt;
        return True, &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
    except Exception as e:&lt;br /&gt;
        return False, f&amp;quot;Commande pas envoyée: Erreur MQTT : {e}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
def subscribe_to_pi_telemetry(pi_id):&lt;br /&gt;
    global subscribed_topics&lt;br /&gt;
    topic = f&amp;quot;telemetry/{pi_id}&amp;quot;&lt;br /&gt;
    if topic not in subscribed_topics:&lt;br /&gt;
        mqtt_client.subscribe(topic)&lt;br /&gt;
        subscribed_topics.add(topic)&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(&amp;quot;raspberry_available&amp;quot;)&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    print(f&amp;quot;Received message on topic {msg.topic}: {msg.payload.decode()}&amp;quot;)  # Ajouter pour le débogage&lt;br /&gt;
    if msg.topic == &amp;quot;raspberry_available&amp;quot;:&lt;br /&gt;
        raspberry_ids.add(msg.payload.decode())&lt;br /&gt;
    else:&lt;br /&gt;
        received_messages.put(msg.payload.decode())&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client.on_connect = on_connect&lt;br /&gt;
mqtt_client.on_message = on_message&lt;br /&gt;
@app.route('/get-raspberry-ids')&lt;br /&gt;
def get_raspberry_ids():&lt;br /&gt;
    return jsonify(list(raspberry_ids))&lt;br /&gt;
@app.route('/get-latest-message')&lt;br /&gt;
def get_latest_message():&lt;br /&gt;
    global latest_message&lt;br /&gt;
    while not received_messages.empty():&lt;br /&gt;
        messages.append(received_messages.get())&lt;br /&gt;
&lt;br /&gt;
    latest_message = messages[-1] if messages else None&lt;br /&gt;
    &lt;br /&gt;
    print(f&amp;quot;Contenu de la réponse pour /get-latest-message : {latest_message}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    if latest_message is not None:&lt;br /&gt;
         response = jsonify({&amp;quot;message&amp;quot;: latest_message})&lt;br /&gt;
         return response&lt;br /&gt;
    else:&lt;br /&gt;
        message = &amp;quot;Aucun signe a traduire pour le moment&amp;quot;&lt;br /&gt;
        return jsonify(message)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@app.route('/', methods=['GET', 'POST'])&lt;br /&gt;
&lt;br /&gt;
def index():&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    error_message_rpi = None&lt;br /&gt;
    success_message = None&lt;br /&gt;
&lt;br /&gt;
    if request.method == 'POST':&lt;br /&gt;
        pi_id = request.form.get('pi_id')&lt;br /&gt;
        command = request.form.get('command')&lt;br /&gt;
        if pi_id and command in [&amp;quot;start&amp;quot;, &amp;quot;stop&amp;quot;]:&lt;br /&gt;
            success, er_message = send_command_to_pi(pi_id, command)&lt;br /&gt;
            if success:&lt;br /&gt;
                success_message = &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                error_message_rpi = er_message&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    return render_template('index.html', raspberry_ids=list(raspberry_ids), error_message_rpi=error_message_rpi, success_message=success_message, message=latest_message)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    app.run(debug=False, port=8066)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7. Conception de l'Interface Utilisateur ===&lt;br /&gt;
----L'interface utilisateur, développée à l'aide des technologies web standard HTML, CSS, et JavaScript, offre une expérience interactive. Le fichier index.html constitue le point d'entrée de cette interface, proposant des fonctionnalités telles que l'envoi de commandes aux dispositifs Raspberry Pi et la visualisation des données traitées. L'utilisation de JavaScript pour interroger dynamiquement le serveur Flask permet de rafraîchir les informations affichées en temps réel, garantissant ainsi une interface réactive et à jour.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
index.html:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
        body {&lt;br /&gt;
            background-color: #343a40; &lt;br /&gt;
            color: #ced4da; &lt;br /&gt;
        }&lt;br /&gt;
        .card {&lt;br /&gt;
            background-color: #495057; &lt;br /&gt;
        }&lt;br /&gt;
        .card-title, .card-text, .alert {&lt;br /&gt;
            color: #adb5bd; &lt;br /&gt;
        }&lt;br /&gt;
        .btn-primary {&lt;br /&gt;
            background-color: #007bff; &lt;br /&gt;
            border-color: #007bff;&lt;br /&gt;
        }&lt;br /&gt;
        .btn-danger {&lt;br /&gt;
            background-color: #dc3545; &lt;br /&gt;
            border-color: #dc3545;&lt;br /&gt;
        }&lt;br /&gt;
        .form-control {&lt;br /&gt;
            background-color: #495057; &lt;br /&gt;
            border: 1px solid #6c757d;&lt;br /&gt;
            color: #ced4da; &lt;br /&gt;
        }&lt;br /&gt;
        a, .btn-secondary {&lt;br /&gt;
            color: #17a2b8; &lt;br /&gt;
        }&lt;br /&gt;
        a:hover {&lt;br /&gt;
            color: #138496; &lt;br /&gt;
        }&lt;br /&gt;
        #latest-message {&lt;br /&gt;
            background-color: #596069; &lt;br /&gt;
            border: 1px solid #6c757d; &lt;br /&gt;
            color: #E9ECEF; &lt;br /&gt;
            padding: 10px; &lt;br /&gt;
            border-radius: 5px; &lt;br /&gt;
        }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;container mt-5&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;h1 class=&amp;quot;text-center mb-4&amp;quot;&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/h1&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour les Raspberry Pi Disponibles --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-md-12&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Raspberry Pi Disponibles&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;ul id=&amp;quot;raspberry-list&amp;quot; class=&amp;quot;list-group list-group-flush&amp;quot;&amp;gt;&lt;br /&gt;
                    &lt;br /&gt;
                        &amp;lt;/ul&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour la Collecte des données --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Collecte de données&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;form method=&amp;quot;post&amp;quot; class=&amp;quot;form-inline&amp;quot;&amp;gt;&lt;br /&gt;
                            &amp;lt;input type=&amp;quot;text&amp;quot; class=&amp;quot;form-control mb-2 mr-sm-2&amp;quot; name=&amp;quot;pi_id&amp;quot; placeholder=&amp;quot;Entrez l'ID de la Raspberry Pi&amp;quot; required&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-primary mb-2 mr-sm-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;start&amp;quot;&amp;gt;Démarrer la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-danger mb-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;stop&amp;quot;&amp;gt;Arrêter la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                        &amp;lt;/form&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;!-- Encadré pour le Dernier Message Reçu --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Dernier Message Reçu&amp;lt;/h2&amp;gt;&lt;br /&gt;
                    &amp;lt;div id=&amp;quot;latest-message&amp;quot; class=&amp;quot;alert alert-dark&amp;quot;&amp;gt;&lt;br /&gt;
                        Aucun message reçu pour le moment. &lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;mb-3 text-center&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;a href=&amp;quot;/logs&amp;quot; class=&amp;quot;btn btn-secondary&amp;quot;&amp;gt;Voir les Logs&amp;lt;/a&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        function fetchRaspberryIds() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        var ids = JSON.parse(xhr.responseText);&lt;br /&gt;
                        var list = document.getElementById('raspberry-list');&lt;br /&gt;
                        list.innerHTML = '';&lt;br /&gt;
                        ids.forEach(function(id) {&lt;br /&gt;
                            var li = document.createElement('li');&lt;br /&gt;
                            li.textContent = id;&lt;br /&gt;
                            list.appendChild(li);&lt;br /&gt;
                        });&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-raspberry-ids', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function fetchLatestMessage() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        console.log(xhr.responseText)&lt;br /&gt;
                        document.getElementById('latest-message').textContent = xhr.responseText;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-latest-message', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setInterval(fetchRaspberryIds, 5000); // Met à jour les IDs toutes les 5 secondes&lt;br /&gt;
        setInterval(fetchLatestMessage, 500); // Met à jour le dernier message toutes les secondes&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    {% if error_message_rpi %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ error_message_rpi }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&lt;br /&gt;
    {% if success_message %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ success_message }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On a aussi ajouté une page de logs, qui permet de voir l'historique de tous les données traitées.&lt;br /&gt;
&lt;br /&gt;
=== 9. Conclusion et Perspectives ===&lt;br /&gt;
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont&lt;br /&gt;
&lt;br /&gt;
En conclusion, notre projet a vu la mise en place d'une infrastructure qui permet de facilité interaction  entre les serveurs et les Raspberry Pi, notamment pour le démarrage et l'arrêt de la collecte de données, ainsi que pour l'envoi d'instructions d'entraînement spécifiques. Bien que nous ayons entamé le développement des fonctionnalités d'entraînement, permettant à l'utilisateur de spécifier depuis l'interface web l'identifiant de la Raspberry Pi et la lettre à entraîner, cette partie n'a pas pu être totalement finalisée dans le temps imparti.&lt;br /&gt;
&lt;br /&gt;
Pour le processus d'entraînement, l'idée était que la Raspberry Pi reçoit la lettre depuis le serveur,après il initie la collecte des données à partir du module STM32, stocke ces données dans un fichier CSV et génère le fichier .pkl correspondant au modèle d'intelligence artificielle. Parallèlement, pour la gestion des données brutes, la Raspberry Pi recçoit la lettre et devait transmettre les informations collectées au serveur, qui aurait alors pour tâche de les stocker également sous forme de fichier CSV et de générer le fichier .pkl nécessaire à l'application de l'intelligence artificielle.&lt;br /&gt;
&lt;br /&gt;
Les perspectives d'évolution de ce projet sont multiples. Elles incluent la finalisation de la fonctionnalité d'entraînement pour permettre une interaction complète et efficace dans la préparation des modèles d'intelligence artificielle directement depuis l'interface web. De plus, l'amélioration de la gestion des données brutes pour optimiser le stockage et le traitement sur le serveur ouvrirait la voie à des analyses plus poussées et à une meilleure performance des modèles générés. Enfin, l'extension de cette infrastructure à un plus grand nombre de Raspberry Pi et l'intégration de fonctionnalités supplémentaires pourraient transformer ce projet en une solution robuste et scalable pour diverses applications nécessitant la collecte et l'analyse de données en temps réel.[[Fichier:SignEntrainement.png|centré|vignette|1000x1000px]]&lt;br /&gt;
&lt;br /&gt;
== Vidéo ==&lt;br /&gt;
Lorsque l'on clique sur &amp;quot;démarrer la collecte&amp;quot; en ayant spécifié un ID, on peut voir en temps réel le résultat dans le cadre Dernier Message Recu. Dans la vidéo on a choisi de prendre comme exemple la lettre &amp;quot;A&amp;quot;, &amp;quot;B&amp;quot;, les chiffres 1 et 2 et la phrase &amp;quot;I Love You&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:RPReplay_Final1706462779.mov|sans_cadre]]&lt;br /&gt;
[[Fichier:Capture d’écran 2024-01-29 à 15.43.56.png|néant|vignette]]&lt;br /&gt;
[[Fichier:Capture d’écran 2024-01-29 à 15.45.25.png|néant|vignette]]&lt;br /&gt;
&lt;br /&gt;
== Déroulement des séances ==&lt;br /&gt;
&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:IfconfigVM.png|sans_cadre]]&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
[[Fichier:Capture d’écran 2024-01-28 à 19.07.42.png|néant|vignette]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4988</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4988"/>
		<updated>2024-01-29T14:49:02Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* Vidéo */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=SignSpeak 2023/2024 =&lt;br /&gt;
== '''Présentation du projet''' ==&lt;br /&gt;
&lt;br /&gt;
=== 1. Introduction ===&lt;br /&gt;
----Le projet SignSpeak a pour ambition de créer une solution innovante pour la traduction du langage des signes en texte. L'objectif principal est de développer un système capable de capturer les mouvements des mains et de les interpréter en langage des signes, permettant une communication fluide entre les personnes sourdes ou malentendantes et celles qui ne connaissent pas le langage des signes. Ce projet intègre des technologies avancées telles que l'edge computing, l'intelligence artificielle embarquée, et les communications MQTT, offrant une approche novatrice dans le domaine de l'accessibilité et de la communication.&lt;br /&gt;
&lt;br /&gt;
=== 2. Architecture du Système ===&lt;br /&gt;
----Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :&lt;br /&gt;
&lt;br /&gt;
* '''Capteurs et STM32''' : Des capteurs sont connectés à un microcontrôleur STM32, responsables de la capture des mouvements de main. Ces données sont ensuite transmises pour traitement.&lt;br /&gt;
* '''Raspberry Pi''' : Agissant comme un intermédiaire, la Raspberry Pi reçoit les données des capteurs via UART, exécute un traitement préliminaire et communique avec le serveur.&lt;br /&gt;
* '''Serveur et Machine Learning''' : Un serveur, hébergé sur une VM Xen, traite les données à l'aide d'un modèle SVM pour la traduction en langage des signes et fournit une interface web pour l'interaction utilisateur.&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== 3. Collecte et Préparation des Données ===&lt;br /&gt;
----Le processus de collecte des données est géré par le script &amp;lt;code&amp;gt;enregistrementData.py&amp;lt;/code&amp;gt;. Ce script lit les données transmises par le STM32 via UART et les enregistre dans un fichier CSV. Chaque entrée du fichier représente les valeurs de capteurs à un moment donné, accompagnées d'une étiquette correspondant au signe effectué. Cette approche assure une collecte de données structurée, essentielle pour l'entraînement précis du modèle d'apprentissage automatique.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
import csv&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
# Vérification de l'argument d'entrée&lt;br /&gt;
if len(sys.argv) &amp;lt; 2:&lt;br /&gt;
    print(&amp;quot;Usage: python script.py &amp;lt;etiquette&amp;gt;&amp;quot;)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
etiquette = sys.argv[1]&lt;br /&gt;
&lt;br /&gt;
# Paramètres de l'UART&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
&lt;br /&gt;
# Créer une connexion UART&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
&lt;br /&gt;
# Nom du fichier CSV&lt;br /&gt;
filename = f&amp;quot;data_complete.csv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Vérifier si le fichier existe déjà&lt;br /&gt;
file_exists = False&lt;br /&gt;
try:&lt;br /&gt;
    with open(filename, 'r') as f:&lt;br /&gt;
        file_exists = True&lt;br /&gt;
except FileNotFoundError:&lt;br /&gt;
    file_exists = False&lt;br /&gt;
&lt;br /&gt;
# Ouvrir le fichier CSV en mode append&lt;br /&gt;
with open(filename, 'a', newline='') as file:&lt;br /&gt;
    writer = csv.writer(file)&lt;br /&gt;
&lt;br /&gt;
    # Écrire l'en-tête si le fichier n'existait pas&lt;br /&gt;
    if not file_exists:&lt;br /&gt;
        writer.writerow([&amp;quot;Capteur1&amp;quot;, &amp;quot;Capteur2&amp;quot;, &amp;quot;Capteur3&amp;quot;, &amp;quot;Capteur4&amp;quot;, &amp;quot;Capteur5&amp;quot;, &amp;quot;Capteur6&amp;quot;, &amp;quot;Capteur7&amp;quot;, &amp;quot;Capteur8&amp;quot;, &amp;quot;Capteur9&amp;quot;, &amp;quot;Capteur10&amp;quot;, &amp;quot;Capteur11&amp;quot;, &amp;quot;Capteur12&amp;quot;, &amp;quot;Capteur13&amp;quot;, &amp;quot;Capteur14&amp;quot;, &lt;br /&gt;
&amp;quot;Capteur15&amp;quot;, &amp;quot;Capteur16&amp;quot;, &amp;quot;Etiquette&amp;quot;])&lt;br /&gt;
    elif file_exists:&lt;br /&gt;
        writer.writerow([])&lt;br /&gt;
    while True:&lt;br /&gt;
        # Lire une ligne de données depuis l'UART&lt;br /&gt;
        data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
        print(f&amp;quot;Données reçues : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Vérifier si des données ont été reçues&lt;br /&gt;
        if data:&lt;br /&gt;
            # Diviser les données en valeurs individuelles&lt;br /&gt;
            sensor_values = data.split(',')&lt;br /&gt;
&lt;br /&gt;
            # Filtrer les chaînes vides ou non numériques et convertir en flottants&lt;br /&gt;
            try:&lt;br /&gt;
                sensor_values = [float(value) for value in sensor_values if value.strip().isdigit()]&lt;br /&gt;
&lt;br /&gt;
                # Vérifier qu'il y a 16 valeurs de capteur&lt;br /&gt;
                if len(sensor_values) == 16:&lt;br /&gt;
                    sensor_values.append(etiquette)&lt;br /&gt;
                    writer.writerow(sensor_values)&lt;br /&gt;
                else:&lt;br /&gt;
                    print(&amp;quot;Données incomplètes reçues&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            except ValueError as e:&lt;br /&gt;
                print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
                print(f&amp;quot;Données problématiques : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Le script commence par établir une communication série avec le STM32.&lt;br /&gt;
* Il lit ensuite les données en série, les décode et les stocke dans un fichier CSV pour une utilisation ultérieure.&lt;br /&gt;
&lt;br /&gt;
* Une fois les données collectées et stockées dans le fichier CSV, elles sont préparées pour l'entraînement du modèle.&lt;br /&gt;
* Cette préparation implique la normalisation des données, la gestion des valeurs manquantes ou aberrantes, et leur formatage dans un bon format.[[Fichier:Rpi entrainement.png|vignette|1000x1000px|néant]]&lt;br /&gt;
=== 4. Entraînement du Modèle d'Apprentissage Automatique ===&lt;br /&gt;
----L'entraînement du modèle est réalisé par un script Python utilisant la bibliothèque scikit-learn. Le modèle SVM, choisi pour sa capacité à gérer des espaces de grande dimension, est entraîné sur l'ensemble des données collectées. Ce processus comprend la division des données en ensembles d'entraînement et de test, l'entraînement du modèle, et sa validation par le calcul de la précision. Nous avions testé plusieurs modèle, comme par exemple un modèle Knn ou randomForest, des 3 algorithmes, c'est celui qui nous à apporté les meilleurs résultats pour un meme nombre de data d'entrainement. (RandomForest en deuxième position)&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import pandas as pd&lt;br /&gt;
from sklearn.model_selection import train_test_split&lt;br /&gt;
from sklearn.svm import SVC&lt;br /&gt;
from sklearn.metrics import accuracy_score&lt;br /&gt;
import pickle&lt;br /&gt;
&lt;br /&gt;
# Charger vos données&lt;br /&gt;
data = pd.read_csv('data_complete.csv')&lt;br /&gt;
&lt;br /&gt;
# Séparer les caractéristiques et les étiquettes&lt;br /&gt;
X = data.drop('Etiquette', axis=1)&lt;br /&gt;
y = data['Etiquette']&lt;br /&gt;
&lt;br /&gt;
# Diviser les données en ensembles d'entraînement et de test&lt;br /&gt;
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)&lt;br /&gt;
&lt;br /&gt;
# Créer et entraîner le modèle SVM&lt;br /&gt;
model = SVC(kernel='rbf')&lt;br /&gt;
model.fit(X_train, y_train)&lt;br /&gt;
&lt;br /&gt;
# Sauvegarder le modèle entraîné&lt;br /&gt;
with open('modele_svm.pkl', 'wb') as file:&lt;br /&gt;
    pickle.dump(model, file)&lt;br /&gt;
&lt;br /&gt;
# Charger le modèle et faire des prédictions&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    loaded_model = pickle.load(file)&lt;br /&gt;
    predictions = loaded_model.predict(X_test)&lt;br /&gt;
    print(&amp;quot;Précision :&amp;quot;, accuracy_score(y_test, predictions))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# '''Séparation des Données''':&lt;br /&gt;
#* Les données sont divisées en deux ensembles : un ensemble d'entraînement et un ensemble de test. Cette séparation est cruciale pour évaluer objectivement la performance du modèle.&lt;br /&gt;
#* Généralement, on adopte une répartition de 80% pour l'entraînement et 20% pour les tests.&lt;br /&gt;
# '''Entraînement du Modèle SVM''':&lt;br /&gt;
#* Le modèle SVM avec un noyau RBF (Radial Basis Function) est entraîné sur l'ensemble d'entraînement.&lt;br /&gt;
#* L'entraînement implique l'ajustement du modèle aux données d'entraînement, en apprenant à distinguer les différents signes.&lt;br /&gt;
# '''Sauvegarde et Réutilisation du Modèle'''&lt;br /&gt;
#* Une fois entraîné et validé, le modèle est sauvegardé à l'aide de la bibliothèque &amp;lt;code&amp;gt;pickle&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Validation et Évaluation du Modèle''':&lt;br /&gt;
#* Après l'entraînement, le modèle est testé sur l'ensemble de test pour évaluer sa performance.&lt;br /&gt;
#* La métrique principale utilisée est la précision, qui mesure la proportion de prédictions correctes par rapport au total des prédictions.&lt;br /&gt;
&lt;br /&gt;
Ensuite on peut générer le modèle comme ceci:&lt;br /&gt;
[[Fichier:Generate model.png|vignette|399x399px|néant]]&lt;br /&gt;
&lt;br /&gt;
Avec cette prédiction lorsque notre modèle prédit le résultat, il est correct environ 71.81% du temps.&lt;br /&gt;
&lt;br /&gt;
=== 5. Intégration MQTT et Communication ===&lt;br /&gt;
----Protocole de communication  :&lt;br /&gt;
&lt;br /&gt;
Dans le cadre de notre projet, la communication entre les dispositifs Raspberry Pi et le serveur  est établie via le protocole MQTT.&lt;br /&gt;
&lt;br /&gt;
Justification du Choix de MQTT :&lt;br /&gt;
&lt;br /&gt;
Au début du projet, une approche basée sur des sockets IPv6 avait été envisagée pour tirer parti de l'adressage direct et de la simplification de la configuration réseau qu'offre IPv6. Cependant, dans le but de respecter les impératifs de sobriété énergétique et d'assurer une scalabilité optimale du système, permettant ainsi de gérer aisément un nombre croissant de dispositifs Raspberry Pi, la décision a été prise d'adopter MQTT comme protocole de communication. Le protocole MQTT, reconnu pour sa légèreté et sa fiabilité, s'adapte parfaitement aux contraintes des applications IoT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Installation du broker mosquitto sur le serveur:'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
apt install -y mosquitto mosquitto-clients&lt;br /&gt;
service mosquitto start&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Activation de l'accès à distance au Broker Mosquitto:&lt;br /&gt;
&lt;br /&gt;
ajouter l'authentification par username et mot de passe&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
sudo mosquitto_passwd -c /etc/mosquitto/passwd username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
après on nous demande d'entrer le mot de passe &lt;br /&gt;
&lt;br /&gt;
Modifier le fichier /etc/mosquitto/mosquitto.conf:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
listener 1883 10.42.0.5&lt;br /&gt;
#listener 1883 2001:660:4401:6050:216:3eff:fe86:cd63&lt;br /&gt;
allow_anonymous false&lt;br /&gt;
password_file /etc/mosquitto/passwd&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Mosquitto:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
service mosquitto restart&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vérification ds logs:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
cat /var/log/mosquitto/mosquitto.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Création d'un client MQTT sur la Raspberry Pi:'''&lt;br /&gt;
&lt;br /&gt;
Le script mqtt_client_rpi.py joue un rôle clé dans cette architecture en facilitant la communication bidirectionnelle : il permet non seulement l'envoi des prédictions réalisées par le modèle SVM depuis la Raspberry Pi vers le serveur, mais autorise également la réception des commandes de contrôle, telles que les instructions de démarrage ou d'arrêt de la collecte de données.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import serial&lt;br /&gt;
import pandas as pd&lt;br /&gt;
import pickle&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
#MQTT_BROKER_ADDRESS = &amp;quot;2001:660:4401:6050:216:3eff:fe86:cd63&amp;quot; VmHblgrimBblack&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
pi_id = &amp;quot;rpi1234&amp;quot;&lt;br /&gt;
&lt;br /&gt;
collecting_data = False &lt;br /&gt;
&lt;br /&gt;
client = mqtt.Client()&lt;br /&gt;
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)&lt;br /&gt;
client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
client.loop_start()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(f&amp;quot;config/{pi_id}&amp;quot;)&lt;br /&gt;
    client.publish(&amp;quot;raspberry_available&amp;quot;, pi_id)&lt;br /&gt;
&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global collecting_data&lt;br /&gt;
    if msg.topic == f&amp;quot;config/{pi_id}&amp;quot;:&lt;br /&gt;
        command = msg.payload.decode()&lt;br /&gt;
        if command == &amp;quot;start&amp;quot;:&lt;br /&gt;
            collecting_data = True&lt;br /&gt;
        elif command == &amp;quot;stop&amp;quot;:&lt;br /&gt;
            collecting_data = False&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.on_connect = on_connect&lt;br /&gt;
client.on_message = on_message&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Configurez le port série et chargez le modèle ici&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    rf = pickle.load(file)&lt;br /&gt;
try:&lt;br /&gt;
&lt;br /&gt;
    while True:&lt;br /&gt;
        if collecting_data:&lt;br /&gt;
            data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
            if data:&lt;br /&gt;
                try:&lt;br /&gt;
                    sensor_values = [value for value in data.split(',') if value.strip().replace('.', '', 1).isdigit()]&lt;br /&gt;
                    if len(sensor_values) == 16:&lt;br /&gt;
                        sensor_values = list(map(float, sensor_values))&lt;br /&gt;
                        sensor_values_df = pd.DataFrame([sensor_values])&lt;br /&gt;
                        prediction = rf.predict(sensor_values_df)&lt;br /&gt;
                        client.publish(f&amp;quot;telemetry/{pi_id}&amp;quot;, str(prediction[0]).encode())&lt;br /&gt;
                        print(&amp;quot;Prédiction :&amp;quot;, prediction[0])&lt;br /&gt;
                except ValueError as e:&lt;br /&gt;
                    print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:&lt;br /&gt;
    print(&amp;quot;Script interrompu&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.loop_stop()&lt;br /&gt;
client.disconnect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Ici il y a 3 topics différents. lorsqu'une raspberry se connecte au réseau elle publie son ID (qui est unique, on peut prendre par exemple l'adresse MAC) sur le topic raspberry_available. Cela nous servira a savoir quelle raspberry est connecté et de se fait pouvoir afficher celles-ci sur notre interface web.&lt;br /&gt;
&lt;br /&gt;
le deuxième topic et le topic config/ID (avec id l'identifiant unique de la raspberry), il nous sert a envoyer les commandes &amp;quot;start&amp;quot; et &amp;quot;stop&amp;quot; a la raspberry afin qu'elle démarre ou arrête la lecture des datas.&lt;br /&gt;
&lt;br /&gt;
Le troisième topic est le topic telemetry/ID, ou la raspberry vient publier ses données.&lt;br /&gt;
&lt;br /&gt;
Un quatrième topic pourrait être implémenter comme par exemple le topic common_config, toutes les raspberrys serait abonnées a ce topic. S'il est nécessaire, cela nous permettrais d'envoyer la même commande a toutes les raspberry  plutôt que de faire une publication sur chaque config/ID&lt;br /&gt;
&lt;br /&gt;
=== 6. Interface Serveur et Gestion des Données ===&lt;br /&gt;
----Le serveur central, au cœur de notre système, est orchestré par le script &amp;lt;code&amp;gt;app.py&amp;lt;/code&amp;gt; qui exploite le framework Flask pour mettre en place une interface serveur. Cette interface est conçue pour traiter efficacement les requêtes HTTP et les messages MQTT, offrant ainsi une API réactive pour l'interface utilisateur web. Elle permet également de visualiser en temps réel l'état des dispositifs Raspberry Pi connectés et les dernières données traitées.&lt;br /&gt;
[[Fichier:Signspeakweb.png|centré|vignette|1000x1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from flask import Flask, render_template, request, jsonify&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import queue&lt;br /&gt;
&lt;br /&gt;
app = Flask(__name__)&lt;br /&gt;
messages = []&lt;br /&gt;
received_messages = queue.Queue()&lt;br /&gt;
latest_message = None&lt;br /&gt;
subscribed_topics = set()&lt;br /&gt;
raspberry_ids = set()&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
#MQTT_BROKER_ADDRESS = &amp;quot;2001:660:4401:6050:216:3eff:fe86:cd63&amp;quot; VmHblgrimBblack&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client = mqtt.Client()&lt;br /&gt;
mqtt_client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD) &lt;br /&gt;
mqtt_client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
mqtt_client.loop_start()&lt;br /&gt;
&lt;br /&gt;
def send_command_to_pi(pi_id, command):&lt;br /&gt;
    try:&lt;br /&gt;
        topic = f&amp;quot;config/{pi_id}&amp;quot;&lt;br /&gt;
        mqtt_client.publish(topic, command)&lt;br /&gt;
        subscribe_to_pi_telemetry(pi_id)&lt;br /&gt;
        return True, &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
    except Exception as e:&lt;br /&gt;
        return False, f&amp;quot;Commande pas envoyée: Erreur MQTT : {e}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
def subscribe_to_pi_telemetry(pi_id):&lt;br /&gt;
    global subscribed_topics&lt;br /&gt;
    topic = f&amp;quot;telemetry/{pi_id}&amp;quot;&lt;br /&gt;
    if topic not in subscribed_topics:&lt;br /&gt;
        mqtt_client.subscribe(topic)&lt;br /&gt;
        subscribed_topics.add(topic)&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(&amp;quot;raspberry_available&amp;quot;)&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    print(f&amp;quot;Received message on topic {msg.topic}: {msg.payload.decode()}&amp;quot;)  # Ajouter pour le débogage&lt;br /&gt;
    if msg.topic == &amp;quot;raspberry_available&amp;quot;:&lt;br /&gt;
        raspberry_ids.add(msg.payload.decode())&lt;br /&gt;
    else:&lt;br /&gt;
        received_messages.put(msg.payload.decode())&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client.on_connect = on_connect&lt;br /&gt;
mqtt_client.on_message = on_message&lt;br /&gt;
@app.route('/get-raspberry-ids')&lt;br /&gt;
def get_raspberry_ids():&lt;br /&gt;
    return jsonify(list(raspberry_ids))&lt;br /&gt;
@app.route('/get-latest-message')&lt;br /&gt;
def get_latest_message():&lt;br /&gt;
    global latest_message&lt;br /&gt;
    while not received_messages.empty():&lt;br /&gt;
        messages.append(received_messages.get())&lt;br /&gt;
&lt;br /&gt;
    latest_message = messages[-1] if messages else None&lt;br /&gt;
    &lt;br /&gt;
    print(f&amp;quot;Contenu de la réponse pour /get-latest-message : {latest_message}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    if latest_message is not None:&lt;br /&gt;
         response = jsonify({&amp;quot;message&amp;quot;: latest_message})&lt;br /&gt;
         return response&lt;br /&gt;
    else:&lt;br /&gt;
        message = &amp;quot;Aucun signe a traduire pour le moment&amp;quot;&lt;br /&gt;
        return jsonify(message)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@app.route('/', methods=['GET', 'POST'])&lt;br /&gt;
&lt;br /&gt;
def index():&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    error_message_rpi = None&lt;br /&gt;
    success_message = None&lt;br /&gt;
&lt;br /&gt;
    if request.method == 'POST':&lt;br /&gt;
        pi_id = request.form.get('pi_id')&lt;br /&gt;
        command = request.form.get('command')&lt;br /&gt;
        if pi_id and command in [&amp;quot;start&amp;quot;, &amp;quot;stop&amp;quot;]:&lt;br /&gt;
            success, er_message = send_command_to_pi(pi_id, command)&lt;br /&gt;
            if success:&lt;br /&gt;
                success_message = &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                error_message_rpi = er_message&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    return render_template('index.html', raspberry_ids=list(raspberry_ids), error_message_rpi=error_message_rpi, success_message=success_message, message=latest_message)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    app.run(debug=False, port=8066)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7. Conception de l'Interface Utilisateur ===&lt;br /&gt;
----L'interface utilisateur, développée à l'aide des technologies web standard HTML, CSS, et JavaScript, offre une expérience interactive. Le fichier index.html constitue le point d'entrée de cette interface, proposant des fonctionnalités telles que l'envoi de commandes aux dispositifs Raspberry Pi et la visualisation des données traitées. L'utilisation de JavaScript pour interroger dynamiquement le serveur Flask permet de rafraîchir les informations affichées en temps réel, garantissant ainsi une interface réactive et à jour.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
index.html:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
        body {&lt;br /&gt;
            background-color: #343a40; &lt;br /&gt;
            color: #ced4da; &lt;br /&gt;
        }&lt;br /&gt;
        .card {&lt;br /&gt;
            background-color: #495057; &lt;br /&gt;
        }&lt;br /&gt;
        .card-title, .card-text, .alert {&lt;br /&gt;
            color: #adb5bd; &lt;br /&gt;
        }&lt;br /&gt;
        .btn-primary {&lt;br /&gt;
            background-color: #007bff; &lt;br /&gt;
            border-color: #007bff;&lt;br /&gt;
        }&lt;br /&gt;
        .btn-danger {&lt;br /&gt;
            background-color: #dc3545; &lt;br /&gt;
            border-color: #dc3545;&lt;br /&gt;
        }&lt;br /&gt;
        .form-control {&lt;br /&gt;
            background-color: #495057; &lt;br /&gt;
            border: 1px solid #6c757d;&lt;br /&gt;
            color: #ced4da; &lt;br /&gt;
        }&lt;br /&gt;
        a, .btn-secondary {&lt;br /&gt;
            color: #17a2b8; &lt;br /&gt;
        }&lt;br /&gt;
        a:hover {&lt;br /&gt;
            color: #138496; &lt;br /&gt;
        }&lt;br /&gt;
        #latest-message {&lt;br /&gt;
            background-color: #596069; &lt;br /&gt;
            border: 1px solid #6c757d; &lt;br /&gt;
            color: #E9ECEF; &lt;br /&gt;
            padding: 10px; &lt;br /&gt;
            border-radius: 5px; &lt;br /&gt;
        }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;container mt-5&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;h1 class=&amp;quot;text-center mb-4&amp;quot;&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/h1&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour les Raspberry Pi Disponibles --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-md-12&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Raspberry Pi Disponibles&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;ul id=&amp;quot;raspberry-list&amp;quot; class=&amp;quot;list-group list-group-flush&amp;quot;&amp;gt;&lt;br /&gt;
                    &lt;br /&gt;
                        &amp;lt;/ul&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour la Collecte des données --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Collecte de données&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;form method=&amp;quot;post&amp;quot; class=&amp;quot;form-inline&amp;quot;&amp;gt;&lt;br /&gt;
                            &amp;lt;input type=&amp;quot;text&amp;quot; class=&amp;quot;form-control mb-2 mr-sm-2&amp;quot; name=&amp;quot;pi_id&amp;quot; placeholder=&amp;quot;Entrez l'ID de la Raspberry Pi&amp;quot; required&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-primary mb-2 mr-sm-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;start&amp;quot;&amp;gt;Démarrer la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-danger mb-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;stop&amp;quot;&amp;gt;Arrêter la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                        &amp;lt;/form&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;!-- Encadré pour le Dernier Message Reçu --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Dernier Message Reçu&amp;lt;/h2&amp;gt;&lt;br /&gt;
                    &amp;lt;div id=&amp;quot;latest-message&amp;quot; class=&amp;quot;alert alert-dark&amp;quot;&amp;gt;&lt;br /&gt;
                        Aucun message reçu pour le moment. &lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;mb-3 text-center&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;a href=&amp;quot;/logs&amp;quot; class=&amp;quot;btn btn-secondary&amp;quot;&amp;gt;Voir les Logs&amp;lt;/a&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        function fetchRaspberryIds() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        var ids = JSON.parse(xhr.responseText);&lt;br /&gt;
                        var list = document.getElementById('raspberry-list');&lt;br /&gt;
                        list.innerHTML = '';&lt;br /&gt;
                        ids.forEach(function(id) {&lt;br /&gt;
                            var li = document.createElement('li');&lt;br /&gt;
                            li.textContent = id;&lt;br /&gt;
                            list.appendChild(li);&lt;br /&gt;
                        });&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-raspberry-ids', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function fetchLatestMessage() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        console.log(xhr.responseText)&lt;br /&gt;
                        document.getElementById('latest-message').textContent = xhr.responseText;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-latest-message', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setInterval(fetchRaspberryIds, 5000); // Met à jour les IDs toutes les 5 secondes&lt;br /&gt;
        setInterval(fetchLatestMessage, 500); // Met à jour le dernier message toutes les secondes&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    {% if error_message_rpi %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ error_message_rpi }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&lt;br /&gt;
    {% if success_message %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ success_message }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On a aussi ajouté une page de logs, qui permet de voir l'historique de tous les données traitées.&lt;br /&gt;
&lt;br /&gt;
=== 9. Conclusion et Perspectives ===&lt;br /&gt;
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont&lt;br /&gt;
&lt;br /&gt;
En conclusion, notre projet a vu la mise en place d'une infrastructure qui permet de facilité interaction  entre les serveurs et les Raspberry Pi, notamment pour le démarrage et l'arrêt de la collecte de données, ainsi que pour l'envoi d'instructions d'entraînement spécifiques. Bien que nous ayons entamé le développement des fonctionnalités d'entraînement, permettant à l'utilisateur de spécifier depuis l'interface web l'identifiant de la Raspberry Pi et la lettre à entraîner, cette partie n'a pas pu être totalement finalisée dans le temps imparti.&lt;br /&gt;
&lt;br /&gt;
Pour le processus d'entraînement, l'idée était que la Raspberry Pi reçoit la lettre depuis le serveur,après il initie la collecte des données à partir du module STM32, stocke ces données dans un fichier CSV et génère le fichier .pkl correspondant au modèle d'intelligence artificielle. Parallèlement, pour la gestion des données brutes, la Raspberry Pi recçoit la lettre et devait transmettre les informations collectées au serveur, qui aurait alors pour tâche de les stocker également sous forme de fichier CSV et de générer le fichier .pkl nécessaire à l'application de l'intelligence artificielle.&lt;br /&gt;
&lt;br /&gt;
Les perspectives d'évolution de ce projet sont multiples. Elles incluent la finalisation de la fonctionnalité d'entraînement pour permettre une interaction complète et efficace dans la préparation des modèles d'intelligence artificielle directement depuis l'interface web. De plus, l'amélioration de la gestion des données brutes pour optimiser le stockage et le traitement sur le serveur ouvrirait la voie à des analyses plus poussées et à une meilleure performance des modèles générés. Enfin, l'extension de cette infrastructure à un plus grand nombre de Raspberry Pi et l'intégration de fonctionnalités supplémentaires pourraient transformer ce projet en une solution robuste et scalable pour diverses applications nécessitant la collecte et l'analyse de données en temps réel.[[Fichier:SignEntrainement.png|centré|vignette|1000x1000px]]&lt;br /&gt;
&lt;br /&gt;
== Vidéo ==&lt;br /&gt;
Lorsque l'on clique sur &amp;quot;démarrer la collecte&amp;quot; en ayant spécifié un ID, on peut voir en temps réel le résultat dans le cadre Dernier Message Recu.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:RPReplay_Final1706462779.mov|sans_cadre]]&lt;br /&gt;
[[Fichier:Capture d’écran 2024-01-29 à 15.43.56.png|néant|vignette]]&lt;br /&gt;
[[Fichier:Capture d’écran 2024-01-29 à 15.45.25.png|néant|vignette]]&lt;br /&gt;
&lt;br /&gt;
== Déroulement des séances ==&lt;br /&gt;
&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:IfconfigVM.png|sans_cadre]]&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
[[Fichier:Capture d’écran 2024-01-28 à 19.07.42.png|néant|vignette]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Capture_d%E2%80%99%C3%A9cran_2024-01-29_%C3%A0_15.45.25.png&amp;diff=4987</id>
		<title>Fichier:Capture d’écran 2024-01-29 à 15.45.25.png</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Capture_d%E2%80%99%C3%A9cran_2024-01-29_%C3%A0_15.45.25.png&amp;diff=4987"/>
		<updated>2024-01-29T14:48:51Z</updated>

		<summary type="html">&lt;p&gt;Bblack : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Capture d’écran 2024-01-29 à 15.45.25&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Capture_d%E2%80%99%C3%A9cran_2024-01-29_%C3%A0_15.43.56.png&amp;diff=4986</id>
		<title>Fichier:Capture d’écran 2024-01-29 à 15.43.56.png</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Capture_d%E2%80%99%C3%A9cran_2024-01-29_%C3%A0_15.43.56.png&amp;diff=4986"/>
		<updated>2024-01-29T14:47:34Z</updated>

		<summary type="html">&lt;p&gt;Bblack : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Capture d’écran 2024-01-29 à 15.43.56&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4908</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4908"/>
		<updated>2024-01-28T18:19:22Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* 7. Conception de l'Interface Utilisateur */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Compte rendu des séances=&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:IfconfigVM.png|sans_cadre]]&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
[[Fichier:Capture d’écran 2024-01-28 à 19.07.42.png|néant|vignette]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== '''Présentation du projet''' ==&lt;br /&gt;
&lt;br /&gt;
=== 1. Introduction ===&lt;br /&gt;
----Le projet SignSpeak a pour ambition de créer une solution innovante pour la traduction du langage des signes en texte. L'objectif principal est de développer un système capable de capturer les mouvements des mains et de les interpréter en langage des signes, permettant une communication fluide entre les personnes sourdes ou malentendantes et celles qui ne connaissent pas le langage des signes. Ce projet intègre des technologies avancées telles que l'edge computing, l'intelligence artificielle embarquée, et les communications MQTT, offrant une approche novatrice dans le domaine de l'accessibilité et de la communication.&lt;br /&gt;
&lt;br /&gt;
=== 2. Architecture du Système ===&lt;br /&gt;
----Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :&lt;br /&gt;
&lt;br /&gt;
* '''Capteurs et STM32''' : Des capteurs sont connectés à un microcontrôleur STM32, responsables de la capture des mouvements de main. Ces données sont ensuite transmises pour traitement.&lt;br /&gt;
* '''Raspberry Pi''' : Agissant comme un intermédiaire, la Raspberry Pi reçoit les données des capteurs via UART, exécute un traitement préliminaire et communique avec le serveur.&lt;br /&gt;
* '''Serveur et Machine Learning''' : Un serveur, hébergé sur une VM Xen, traite les données à l'aide d'un modèle SVM pour la traduction en langage des signes et fournit une interface web pour l'interaction utilisateur.&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== 3. Collecte et Préparation des Données ===&lt;br /&gt;
----Le processus de collecte des données est géré par le script &amp;lt;code&amp;gt;enregistrementData.py&amp;lt;/code&amp;gt;. Ce script lit les données transmises par le STM32 via UART et les enregistre dans un fichier CSV. Chaque entrée du fichier représente les valeurs de capteurs à un moment donné, accompagnées d'une étiquette correspondant au signe effectué. Cette approche assure une collecte de données structurée, essentielle pour l'entraînement précis du modèle d'apprentissage automatique.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
import csv&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
# Vérification de l'argument d'entrée&lt;br /&gt;
if len(sys.argv) &amp;lt; 2:&lt;br /&gt;
    print(&amp;quot;Usage: python script.py &amp;lt;etiquette&amp;gt;&amp;quot;)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
etiquette = sys.argv[1]&lt;br /&gt;
&lt;br /&gt;
# Paramètres de l'UART&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
&lt;br /&gt;
# Créer une connexion UART&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
&lt;br /&gt;
# Nom du fichier CSV&lt;br /&gt;
filename = f&amp;quot;data_complete.csv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Vérifier si le fichier existe déjà&lt;br /&gt;
file_exists = False&lt;br /&gt;
try:&lt;br /&gt;
    with open(filename, 'r') as f:&lt;br /&gt;
        file_exists = True&lt;br /&gt;
except FileNotFoundError:&lt;br /&gt;
    file_exists = False&lt;br /&gt;
&lt;br /&gt;
# Ouvrir le fichier CSV en mode append&lt;br /&gt;
with open(filename, 'a', newline='') as file:&lt;br /&gt;
    writer = csv.writer(file)&lt;br /&gt;
&lt;br /&gt;
    # Écrire l'en-tête si le fichier n'existait pas&lt;br /&gt;
    if not file_exists:&lt;br /&gt;
        writer.writerow([&amp;quot;Capteur1&amp;quot;, &amp;quot;Capteur2&amp;quot;, &amp;quot;Capteur3&amp;quot;, &amp;quot;Capteur4&amp;quot;, &amp;quot;Capteur5&amp;quot;, &amp;quot;Capteur6&amp;quot;, &amp;quot;Capteur7&amp;quot;, &amp;quot;Capteur8&amp;quot;, &amp;quot;Capteur9&amp;quot;, &amp;quot;Capteur10&amp;quot;, &amp;quot;Capteur11&amp;quot;, &amp;quot;Capteur12&amp;quot;, &amp;quot;Capteur13&amp;quot;, &amp;quot;Capteur14&amp;quot;, &lt;br /&gt;
&amp;quot;Capteur15&amp;quot;, &amp;quot;Capteur16&amp;quot;, &amp;quot;Etiquette&amp;quot;])&lt;br /&gt;
    elif file_exists:&lt;br /&gt;
        writer.writerow([])&lt;br /&gt;
    while True:&lt;br /&gt;
        # Lire une ligne de données depuis l'UART&lt;br /&gt;
        data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
        print(f&amp;quot;Données reçues : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Vérifier si des données ont été reçues&lt;br /&gt;
        if data:&lt;br /&gt;
            # Diviser les données en valeurs individuelles&lt;br /&gt;
            sensor_values = data.split(',')&lt;br /&gt;
&lt;br /&gt;
            # Filtrer les chaînes vides ou non numériques et convertir en flottants&lt;br /&gt;
            try:&lt;br /&gt;
                sensor_values = [float(value) for value in sensor_values if value.strip().isdigit()]&lt;br /&gt;
&lt;br /&gt;
                # Vérifier qu'il y a 16 valeurs de capteur&lt;br /&gt;
                if len(sensor_values) == 16:&lt;br /&gt;
                    sensor_values.append(etiquette)&lt;br /&gt;
                    writer.writerow(sensor_values)&lt;br /&gt;
                else:&lt;br /&gt;
                    print(&amp;quot;Données incomplètes reçues&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            except ValueError as e:&lt;br /&gt;
                print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
                print(f&amp;quot;Données problématiques : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Le script commence par établir une communication série avec le STM32.&lt;br /&gt;
* Il lit ensuite les données en série, les décode et les stocke dans un fichier CSV pour une utilisation ultérieure.&lt;br /&gt;
&lt;br /&gt;
* Une fois les données collectées et stockées dans le fichier CSV, elles sont préparées pour l'entraînement du modèle.&lt;br /&gt;
* Cette préparation implique la normalisation des données, la gestion des valeurs manquantes ou aberrantes, et leur formatage dans un bon format.[[Fichier:Rpi entrainement.png|vignette|1000x1000px|néant]]&lt;br /&gt;
=== 4. Entraînement du Modèle d'Apprentissage Automatique ===&lt;br /&gt;
----L'entraînement du modèle est réalisé par un script Python utilisant la bibliothèque scikit-learn. Le modèle SVM, choisi pour sa capacité à gérer des espaces de grande dimension, est entraîné sur l'ensemble des données collectées. Ce processus comprend la division des données en ensembles d'entraînement et de test, l'entraînement du modèle, et sa validation par le calcul de la précision. Nous avions testé plusieurs modèle, comme par exemple un modèle Knn ou randomForest, des 3 algorithmes, c'est celui qui nous à apporté les meilleurs résultats pour un meme nombre de data d'entrainement. (RandomForest en deuxième position)&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import pandas as pd&lt;br /&gt;
from sklearn.model_selection import train_test_split&lt;br /&gt;
from sklearn.svm import SVC&lt;br /&gt;
from sklearn.metrics import accuracy_score&lt;br /&gt;
import pickle&lt;br /&gt;
&lt;br /&gt;
# Charger vos données&lt;br /&gt;
data = pd.read_csv('data_complete.csv')&lt;br /&gt;
&lt;br /&gt;
# Séparer les caractéristiques et les étiquettes&lt;br /&gt;
X = data.drop('Etiquette', axis=1)&lt;br /&gt;
y = data['Etiquette']&lt;br /&gt;
&lt;br /&gt;
# Diviser les données en ensembles d'entraînement et de test&lt;br /&gt;
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)&lt;br /&gt;
&lt;br /&gt;
# Créer et entraîner le modèle SVM&lt;br /&gt;
model = SVC(kernel='rbf')&lt;br /&gt;
model.fit(X_train, y_train)&lt;br /&gt;
&lt;br /&gt;
# Sauvegarder le modèle entraîné&lt;br /&gt;
with open('modele_svm.pkl', 'wb') as file:&lt;br /&gt;
    pickle.dump(model, file)&lt;br /&gt;
&lt;br /&gt;
# Charger le modèle et faire des prédictions&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    loaded_model = pickle.load(file)&lt;br /&gt;
    predictions = loaded_model.predict(X_test)&lt;br /&gt;
    print(&amp;quot;Précision :&amp;quot;, accuracy_score(y_test, predictions))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# '''Séparation des Données''':&lt;br /&gt;
#* Les données sont divisées en deux ensembles : un ensemble d'entraînement et un ensemble de test. Cette séparation est cruciale pour évaluer objectivement la performance du modèle.&lt;br /&gt;
#* Généralement, on adopte une répartition de 80% pour l'entraînement et 20% pour les tests.&lt;br /&gt;
# '''Entraînement du Modèle SVM''':&lt;br /&gt;
#* Le modèle SVM avec un noyau RBF (Radial Basis Function) est entraîné sur l'ensemble d'entraînement.&lt;br /&gt;
#* L'entraînement implique l'ajustement du modèle aux données d'entraînement, en apprenant à distinguer les différents signes.&lt;br /&gt;
# '''Sauvegarde et Réutilisation du Modèle'''&lt;br /&gt;
#* Une fois entraîné et validé, le modèle est sauvegardé à l'aide de la bibliothèque &amp;lt;code&amp;gt;pickle&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Validation et Évaluation du Modèle''':&lt;br /&gt;
#* Après l'entraînement, le modèle est testé sur l'ensemble de test pour évaluer sa performance.&lt;br /&gt;
#* La métrique principale utilisée est la précision, qui mesure la proportion de prédictions correctes par rapport au total des prédictions.&lt;br /&gt;
&lt;br /&gt;
Ensuite on peut générer le modèle comme ceci:&lt;br /&gt;
[[Fichier:Generate model.png|vignette|399x399px|néant]]&lt;br /&gt;
&lt;br /&gt;
Avec cette prédiction lorsque notre modèle prédit le résultat, il est correct environ 71.81% du temps.&lt;br /&gt;
&lt;br /&gt;
=== 5. Intégration MQTT et Communication ===&lt;br /&gt;
----Protocole de communication  :&lt;br /&gt;
&lt;br /&gt;
Dans le cadre de notre projet, la communication entre les dispositifs Raspberry Pi et le serveur  est établie via le protocole MQTT.&lt;br /&gt;
&lt;br /&gt;
Justification du Choix de MQTT :&lt;br /&gt;
&lt;br /&gt;
Au début du projet, une approche basée sur des sockets IPv6 avait été envisagée pour tirer parti de l'adressage direct et de la simplification de la configuration réseau qu'offre IPv6. Cependant, dans le but de respecter les impératifs de sobriété énergétique et d'assurer une scalabilité optimale du système, permettant ainsi de gérer aisément un nombre croissant de dispositifs Raspberry Pi, la décision a été prise d'adopter MQTT comme protocole de communication. Le protocole MQTT, reconnu pour sa légèreté et sa fiabilité, s'adapte parfaitement aux contraintes des applications IoT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Installation du broker mosquitto sur le serveur:'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
apt install -y mosquitto mosquitto-clients&lt;br /&gt;
service mosquitto start&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Activation de l'accès à distance au Broker Mosquitto:&lt;br /&gt;
&lt;br /&gt;
ajouter l'authentification par username et mot de passe&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
sudo mosquitto_passwd -c /etc/mosquitto/passwd username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
après on nous demande d'entrer le mot de passe &lt;br /&gt;
&lt;br /&gt;
Modifier le fichier /etc/mosquitto/mosquitto.conf:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
listener 1883 10.42.0.5&lt;br /&gt;
allow_anonymous false&lt;br /&gt;
password_file /etc/mosquitto/passwd&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Mosquitto:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
service mosquitto restart&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vérification ds logs:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
cat /var/log/mosquitto/mosquitto.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Création d'un client MQTT sur la Raspberry Pi:'''&lt;br /&gt;
&lt;br /&gt;
Le script mqtt_client_rpi.py joue un rôle clé dans cette architecture en facilitant la communication bidirectionnelle : il permet non seulement l'envoi des prédictions réalisées par le modèle SVM depuis la Raspberry Pi vers le serveur, mais autorise également la réception des commandes de contrôle, telles que les instructions de démarrage ou d'arrêt de la collecte de données.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import serial&lt;br /&gt;
import pandas as pd&lt;br /&gt;
import pickle&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
pi_id = &amp;quot;rpi1234&amp;quot;&lt;br /&gt;
&lt;br /&gt;
collecting_data = False &lt;br /&gt;
&lt;br /&gt;
client = mqtt.Client()&lt;br /&gt;
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)&lt;br /&gt;
client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
client.loop_start()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(f&amp;quot;config/{pi_id}&amp;quot;)&lt;br /&gt;
    client.publish(&amp;quot;raspberry_available&amp;quot;, pi_id)&lt;br /&gt;
&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global collecting_data&lt;br /&gt;
    if msg.topic == f&amp;quot;config/{pi_id}&amp;quot;:&lt;br /&gt;
        command = msg.payload.decode()&lt;br /&gt;
        if command == &amp;quot;start&amp;quot;:&lt;br /&gt;
            collecting_data = True&lt;br /&gt;
        elif command == &amp;quot;stop&amp;quot;:&lt;br /&gt;
            collecting_data = False&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.on_connect = on_connect&lt;br /&gt;
client.on_message = on_message&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Configurez le port série et chargez le modèle ici&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    rf = pickle.load(file)&lt;br /&gt;
try:&lt;br /&gt;
&lt;br /&gt;
    while True:&lt;br /&gt;
        if collecting_data:&lt;br /&gt;
            data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
            if data:&lt;br /&gt;
                try:&lt;br /&gt;
                    sensor_values = [value for value in data.split(',') if value.strip().replace('.', '', 1).isdigit()]&lt;br /&gt;
                    if len(sensor_values) == 16:&lt;br /&gt;
                        sensor_values = list(map(float, sensor_values))&lt;br /&gt;
                        sensor_values_df = pd.DataFrame([sensor_values])&lt;br /&gt;
                        prediction = rf.predict(sensor_values_df)&lt;br /&gt;
                        client.publish(f&amp;quot;telemetry/{pi_id}&amp;quot;, str(prediction[0]).encode())&lt;br /&gt;
                        print(&amp;quot;Prédiction :&amp;quot;, prediction[0])&lt;br /&gt;
                except ValueError as e:&lt;br /&gt;
                    print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:&lt;br /&gt;
    print(&amp;quot;Script interrompu&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.loop_stop()&lt;br /&gt;
client.disconnect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Ici il y a 3 topics différents. lorsqu'une raspberry se connecte au réseau elle publie son ID (qui est unique, on peut prendre par exemple l'adresse MAC) sur le topic raspberry_available. Cela nous servira a savoir quelle raspberry est connecté et de se fait pouvoir afficher celles-ci sur notre interface web.&lt;br /&gt;
&lt;br /&gt;
le deuxième topic et le topic config/ID (avec id l'identifiant unique de la raspberry), il nous sert a envoyer les commandes &amp;quot;start&amp;quot; et &amp;quot;stop&amp;quot; a la raspberry afin qu'elle démarre ou arrête la lecture des datas.&lt;br /&gt;
&lt;br /&gt;
Le troisième topic est le topic telemetry/ID, ou la raspberry vient publier ses données.&lt;br /&gt;
&lt;br /&gt;
Un quatrième topic pourrait être implémenter comme par exemple le topic common_config, toutes les raspberrys serait abonnées a ce topic. S'il est nécessaire, cela nous permettrais d'envoyer la même commande a toutes les raspberry  plutôt que de faire une publication sur chaque config/ID &lt;br /&gt;
&lt;br /&gt;
=== 6. Interface Serveur et Gestion des Données ===&lt;br /&gt;
----Le serveur central, au cœur de notre système, est orchestré par le script &amp;lt;code&amp;gt;app.py&amp;lt;/code&amp;gt; qui exploite le framework Flask pour mettre en place une interface serveur. Cette interface est conçue pour traiter efficacement les requêtes HTTP et les messages MQTT, offrant ainsi une API réactive pour l'interface utilisateur web. Elle permet également de visualiser en temps réel l'état des dispositifs Raspberry Pi connectés et les dernières données traitées.&lt;br /&gt;
[[Fichier:Signspeakweb.png|centré|vignette|1000x1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from flask import Flask, render_template, request, jsonify&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import queue&lt;br /&gt;
&lt;br /&gt;
app = Flask(__name__)&lt;br /&gt;
messages = []&lt;br /&gt;
received_messages = queue.Queue()&lt;br /&gt;
latest_message = None&lt;br /&gt;
subscribed_topics = set()&lt;br /&gt;
raspberry_ids = set()&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client = mqtt.Client()&lt;br /&gt;
mqtt_client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD) &lt;br /&gt;
mqtt_client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
mqtt_client.loop_start()&lt;br /&gt;
&lt;br /&gt;
def send_command_to_pi(pi_id, command):&lt;br /&gt;
    try:&lt;br /&gt;
        topic = f&amp;quot;config/{pi_id}&amp;quot;&lt;br /&gt;
        mqtt_client.publish(topic, command)&lt;br /&gt;
        subscribe_to_pi_telemetry(pi_id)&lt;br /&gt;
        return True, &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
    except Exception as e:&lt;br /&gt;
        return False, f&amp;quot;Commande pas envoyée: Erreur MQTT : {e}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
def subscribe_to_pi_telemetry(pi_id):&lt;br /&gt;
    global subscribed_topics&lt;br /&gt;
    topic = f&amp;quot;telemetry/{pi_id}&amp;quot;&lt;br /&gt;
    if topic not in subscribed_topics:&lt;br /&gt;
        mqtt_client.subscribe(topic)&lt;br /&gt;
        subscribed_topics.add(topic)&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(&amp;quot;raspberry_available&amp;quot;)&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    print(f&amp;quot;Received message on topic {msg.topic}: {msg.payload.decode()}&amp;quot;)  # Ajouter pour le débogage&lt;br /&gt;
    if msg.topic == &amp;quot;raspberry_available&amp;quot;:&lt;br /&gt;
        raspberry_ids.add(msg.payload.decode())&lt;br /&gt;
    else:&lt;br /&gt;
        received_messages.put(msg.payload.decode())&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client.on_connect = on_connect&lt;br /&gt;
mqtt_client.on_message = on_message&lt;br /&gt;
@app.route('/get-raspberry-ids')&lt;br /&gt;
def get_raspberry_ids():&lt;br /&gt;
    return jsonify(list(raspberry_ids))&lt;br /&gt;
@app.route('/get-latest-message')&lt;br /&gt;
def get_latest_message():&lt;br /&gt;
    global latest_message&lt;br /&gt;
    while not received_messages.empty():&lt;br /&gt;
        messages.append(received_messages.get())&lt;br /&gt;
&lt;br /&gt;
    latest_message = messages[-1] if messages else None&lt;br /&gt;
    &lt;br /&gt;
    print(f&amp;quot;Contenu de la réponse pour /get-latest-message : {latest_message}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    if latest_message is not None:&lt;br /&gt;
         response = jsonify({&amp;quot;message&amp;quot;: latest_message})&lt;br /&gt;
         return response&lt;br /&gt;
    else:&lt;br /&gt;
        message = &amp;quot;Aucun signe a traduire pour le moment&amp;quot;&lt;br /&gt;
        return jsonify(message)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@app.route('/', methods=['GET', 'POST'])&lt;br /&gt;
&lt;br /&gt;
def index():&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    error_message_rpi = None&lt;br /&gt;
    success_message = None&lt;br /&gt;
&lt;br /&gt;
    if request.method == 'POST':&lt;br /&gt;
        pi_id = request.form.get('pi_id')&lt;br /&gt;
        command = request.form.get('command')&lt;br /&gt;
        if pi_id and command in [&amp;quot;start&amp;quot;, &amp;quot;stop&amp;quot;]:&lt;br /&gt;
            success, er_message = send_command_to_pi(pi_id, command)&lt;br /&gt;
            if success:&lt;br /&gt;
                success_message = &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                error_message_rpi = er_message&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    return render_template('index.html', raspberry_ids=list(raspberry_ids), error_message_rpi=error_message_rpi, success_message=success_message, message=latest_message)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    app.run(debug=False, port=8066)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7. Conception de l'Interface Utilisateur ===&lt;br /&gt;
----L'interface utilisateur, développée à l'aide des technologies web standard HTML, CSS, et JavaScript, offre une expérience interactive. Le fichier index.html constitue le point d'entrée de cette interface, proposant des fonctionnalités telles que l'envoi de commandes aux dispositifs Raspberry Pi et la visualisation des données traitées. L'utilisation de JavaScript pour interroger dynamiquement le serveur Flask permet de rafraîchir les informations affichées en temps réel, garantissant ainsi une interface réactive et à jour.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
index.html:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
        body {&lt;br /&gt;
            background-color: #343a40; &lt;br /&gt;
            color: #ced4da; &lt;br /&gt;
        }&lt;br /&gt;
        .card {&lt;br /&gt;
            background-color: #495057; &lt;br /&gt;
        }&lt;br /&gt;
        .card-title, .card-text, .alert {&lt;br /&gt;
            color: #adb5bd; &lt;br /&gt;
        }&lt;br /&gt;
        .btn-primary {&lt;br /&gt;
            background-color: #007bff; &lt;br /&gt;
            border-color: #007bff;&lt;br /&gt;
        }&lt;br /&gt;
        .btn-danger {&lt;br /&gt;
            background-color: #dc3545; &lt;br /&gt;
            border-color: #dc3545;&lt;br /&gt;
        }&lt;br /&gt;
        .form-control {&lt;br /&gt;
            background-color: #495057; &lt;br /&gt;
            border: 1px solid #6c757d;&lt;br /&gt;
            color: #ced4da; &lt;br /&gt;
        }&lt;br /&gt;
        a, .btn-secondary {&lt;br /&gt;
            color: #17a2b8; &lt;br /&gt;
        }&lt;br /&gt;
        a:hover {&lt;br /&gt;
            color: #138496; &lt;br /&gt;
        }&lt;br /&gt;
        #latest-message {&lt;br /&gt;
            background-color: #596069; &lt;br /&gt;
            border: 1px solid #6c757d; &lt;br /&gt;
            color: #E9ECEF; &lt;br /&gt;
            padding: 10px; &lt;br /&gt;
            border-radius: 5px; &lt;br /&gt;
        }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;container mt-5&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;h1 class=&amp;quot;text-center mb-4&amp;quot;&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/h1&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour les Raspberry Pi Disponibles --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-md-12&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Raspberry Pi Disponibles&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;ul id=&amp;quot;raspberry-list&amp;quot; class=&amp;quot;list-group list-group-flush&amp;quot;&amp;gt;&lt;br /&gt;
                    &lt;br /&gt;
                        &amp;lt;/ul&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour la Collecte des données --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Collecte de données&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;form method=&amp;quot;post&amp;quot; class=&amp;quot;form-inline&amp;quot;&amp;gt;&lt;br /&gt;
                            &amp;lt;input type=&amp;quot;text&amp;quot; class=&amp;quot;form-control mb-2 mr-sm-2&amp;quot; name=&amp;quot;pi_id&amp;quot; placeholder=&amp;quot;Entrez l'ID de la Raspberry Pi&amp;quot; required&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-primary mb-2 mr-sm-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;start&amp;quot;&amp;gt;Démarrer la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-danger mb-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;stop&amp;quot;&amp;gt;Arrêter la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                        &amp;lt;/form&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;!-- Encadré pour le Dernier Message Reçu --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Dernier Message Reçu&amp;lt;/h2&amp;gt;&lt;br /&gt;
                    &amp;lt;div id=&amp;quot;latest-message&amp;quot; class=&amp;quot;alert alert-dark&amp;quot;&amp;gt;&lt;br /&gt;
                        Aucun message reçu pour le moment. &lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;mb-3 text-center&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;a href=&amp;quot;/logs&amp;quot; class=&amp;quot;btn btn-secondary&amp;quot;&amp;gt;Voir les Logs&amp;lt;/a&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        function fetchRaspberryIds() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        var ids = JSON.parse(xhr.responseText);&lt;br /&gt;
                        var list = document.getElementById('raspberry-list');&lt;br /&gt;
                        list.innerHTML = '';&lt;br /&gt;
                        ids.forEach(function(id) {&lt;br /&gt;
                            var li = document.createElement('li');&lt;br /&gt;
                            li.textContent = id;&lt;br /&gt;
                            list.appendChild(li);&lt;br /&gt;
                        });&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-raspberry-ids', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function fetchLatestMessage() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        console.log(xhr.responseText)&lt;br /&gt;
                        document.getElementById('latest-message').textContent = xhr.responseText;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-latest-message', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setInterval(fetchRaspberryIds, 5000); // Met à jour les IDs toutes les 5 secondes&lt;br /&gt;
        setInterval(fetchLatestMessage, 500); // Met à jour le dernier message toutes les secondes&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    {% if error_message_rpi %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ error_message_rpi }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&lt;br /&gt;
    {% if success_message %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ success_message }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On a aussi ajouté une page de logs, qui permet de voir l'historique de tous les données traitées.&lt;br /&gt;
&lt;br /&gt;
=== 9. Conclusion et Perspectives ===&lt;br /&gt;
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont&lt;br /&gt;
&lt;br /&gt;
== Vidéo ==&lt;br /&gt;
Lorsque l'on clique sur &amp;quot;démarrer la collecte&amp;quot; en ayant spécifié un ID, on peut voir en temps réel le résultat dans le cadre Dernier Message Recu.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:RPReplay_Final1706462779.mov|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Déroulement des séances ==&lt;br /&gt;
&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:IfconfigVM.png|sans_cadre]]&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
[[Fichier:Capture d’écran 2024-01-28 à 19.07.42.png|néant|vignette]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4903</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4903"/>
		<updated>2024-01-28T18:15:47Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* 7. Conception de l'Interface Utilisateur */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Compte rendu des séances=&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:IfconfigVM.png|sans_cadre]]&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
[[Fichier:Capture d’écran 2024-01-28 à 19.07.42.png|néant|vignette]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== '''Présentation du projet''' ==&lt;br /&gt;
&lt;br /&gt;
=== 1. Introduction ===&lt;br /&gt;
----Le projet SignSpeak a pour ambition de créer une solution innovante pour la traduction du langage des signes en texte. L'objectif principal est de développer un système capable de capturer les mouvements des mains et de les interpréter en langage des signes, permettant une communication fluide entre les personnes sourdes ou malentendantes et celles qui ne connaissent pas le langage des signes. Ce projet intègre des technologies avancées telles que l'edge computing, l'intelligence artificielle embarquée, et les communications MQTT, offrant une approche novatrice dans le domaine de l'accessibilité et de la communication.&lt;br /&gt;
&lt;br /&gt;
=== 2. Architecture du Système ===&lt;br /&gt;
----Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :&lt;br /&gt;
&lt;br /&gt;
* '''Capteurs et STM32''' : Des capteurs sont connectés à un microcontrôleur STM32, responsables de la capture des mouvements de main. Ces données sont ensuite transmises pour traitement.&lt;br /&gt;
* '''Raspberry Pi''' : Agissant comme un intermédiaire, la Raspberry Pi reçoit les données des capteurs via UART, exécute un traitement préliminaire et communique avec le serveur.&lt;br /&gt;
* '''Serveur et Machine Learning''' : Un serveur, hébergé sur une VM Xen, traite les données à l'aide d'un modèle SVM pour la traduction en langage des signes et fournit une interface web pour l'interaction utilisateur.&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== 3. Collecte et Préparation des Données ===&lt;br /&gt;
----Le processus de collecte des données est géré par le script &amp;lt;code&amp;gt;enregistrementData.py&amp;lt;/code&amp;gt;. Ce script lit les données transmises par le STM32 via UART et les enregistre dans un fichier CSV. Chaque entrée du fichier représente les valeurs de capteurs à un moment donné, accompagnées d'une étiquette correspondant au signe effectué. Cette approche assure une collecte de données structurée, essentielle pour l'entraînement précis du modèle d'apprentissage automatique.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
import csv&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
# Vérification de l'argument d'entrée&lt;br /&gt;
if len(sys.argv) &amp;lt; 2:&lt;br /&gt;
    print(&amp;quot;Usage: python script.py &amp;lt;etiquette&amp;gt;&amp;quot;)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
etiquette = sys.argv[1]&lt;br /&gt;
&lt;br /&gt;
# Paramètres de l'UART&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
&lt;br /&gt;
# Créer une connexion UART&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
&lt;br /&gt;
# Nom du fichier CSV&lt;br /&gt;
filename = f&amp;quot;data_complete.csv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Vérifier si le fichier existe déjà&lt;br /&gt;
file_exists = False&lt;br /&gt;
try:&lt;br /&gt;
    with open(filename, 'r') as f:&lt;br /&gt;
        file_exists = True&lt;br /&gt;
except FileNotFoundError:&lt;br /&gt;
    file_exists = False&lt;br /&gt;
&lt;br /&gt;
# Ouvrir le fichier CSV en mode append&lt;br /&gt;
with open(filename, 'a', newline='') as file:&lt;br /&gt;
    writer = csv.writer(file)&lt;br /&gt;
&lt;br /&gt;
    # Écrire l'en-tête si le fichier n'existait pas&lt;br /&gt;
    if not file_exists:&lt;br /&gt;
        writer.writerow([&amp;quot;Capteur1&amp;quot;, &amp;quot;Capteur2&amp;quot;, &amp;quot;Capteur3&amp;quot;, &amp;quot;Capteur4&amp;quot;, &amp;quot;Capteur5&amp;quot;, &amp;quot;Capteur6&amp;quot;, &amp;quot;Capteur7&amp;quot;, &amp;quot;Capteur8&amp;quot;, &amp;quot;Capteur9&amp;quot;, &amp;quot;Capteur10&amp;quot;, &amp;quot;Capteur11&amp;quot;, &amp;quot;Capteur12&amp;quot;, &amp;quot;Capteur13&amp;quot;, &amp;quot;Capteur14&amp;quot;, &lt;br /&gt;
&amp;quot;Capteur15&amp;quot;, &amp;quot;Capteur16&amp;quot;, &amp;quot;Etiquette&amp;quot;])&lt;br /&gt;
    elif file_exists:&lt;br /&gt;
        writer.writerow([])&lt;br /&gt;
    while True:&lt;br /&gt;
        # Lire une ligne de données depuis l'UART&lt;br /&gt;
        data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
        print(f&amp;quot;Données reçues : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Vérifier si des données ont été reçues&lt;br /&gt;
        if data:&lt;br /&gt;
            # Diviser les données en valeurs individuelles&lt;br /&gt;
            sensor_values = data.split(',')&lt;br /&gt;
&lt;br /&gt;
            # Filtrer les chaînes vides ou non numériques et convertir en flottants&lt;br /&gt;
            try:&lt;br /&gt;
                sensor_values = [float(value) for value in sensor_values if value.strip().isdigit()]&lt;br /&gt;
&lt;br /&gt;
                # Vérifier qu'il y a 16 valeurs de capteur&lt;br /&gt;
                if len(sensor_values) == 16:&lt;br /&gt;
                    sensor_values.append(etiquette)&lt;br /&gt;
                    writer.writerow(sensor_values)&lt;br /&gt;
                else:&lt;br /&gt;
                    print(&amp;quot;Données incomplètes reçues&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            except ValueError as e:&lt;br /&gt;
                print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
                print(f&amp;quot;Données problématiques : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Le script commence par établir une communication série avec le STM32.&lt;br /&gt;
* Il lit ensuite les données en série, les décode et les stocke dans un fichier CSV pour une utilisation ultérieure.&lt;br /&gt;
&lt;br /&gt;
* Une fois les données collectées et stockées dans le fichier CSV, elles sont préparées pour l'entraînement du modèle.&lt;br /&gt;
* Cette préparation implique la normalisation des données, la gestion des valeurs manquantes ou aberrantes, et leur formatage dans un bon format.[[Fichier:Rpi entrainement.png|vignette|1000x1000px|néant]]&lt;br /&gt;
=== 4. Entraînement du Modèle d'Apprentissage Automatique ===&lt;br /&gt;
----L'entraînement du modèle est réalisé par un script Python utilisant la bibliothèque scikit-learn. Le modèle SVM, choisi pour sa capacité à gérer des espaces de grande dimension, est entraîné sur l'ensemble des données collectées. Ce processus comprend la division des données en ensembles d'entraînement et de test, l'entraînement du modèle, et sa validation par le calcul de la précision. Nous avions testé plusieurs modèle, comme par exemple un modèle Knn ou randomForest, des 3 algorithmes, c'est celui qui nous à apporté les meilleurs résultats pour un meme nombre de data d'entrainement. (RandomForest en deuxième position)&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import pandas as pd&lt;br /&gt;
from sklearn.model_selection import train_test_split&lt;br /&gt;
from sklearn.svm import SVC&lt;br /&gt;
from sklearn.metrics import accuracy_score&lt;br /&gt;
import pickle&lt;br /&gt;
&lt;br /&gt;
# Charger vos données&lt;br /&gt;
data = pd.read_csv('data_complete.csv')&lt;br /&gt;
&lt;br /&gt;
# Séparer les caractéristiques et les étiquettes&lt;br /&gt;
X = data.drop('Etiquette', axis=1)&lt;br /&gt;
y = data['Etiquette']&lt;br /&gt;
&lt;br /&gt;
# Diviser les données en ensembles d'entraînement et de test&lt;br /&gt;
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)&lt;br /&gt;
&lt;br /&gt;
# Créer et entraîner le modèle SVM&lt;br /&gt;
model = SVC(kernel='rbf')&lt;br /&gt;
model.fit(X_train, y_train)&lt;br /&gt;
&lt;br /&gt;
# Sauvegarder le modèle entraîné&lt;br /&gt;
with open('modele_svm.pkl', 'wb') as file:&lt;br /&gt;
    pickle.dump(model, file)&lt;br /&gt;
&lt;br /&gt;
# Charger le modèle et faire des prédictions&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    loaded_model = pickle.load(file)&lt;br /&gt;
    predictions = loaded_model.predict(X_test)&lt;br /&gt;
    print(&amp;quot;Précision :&amp;quot;, accuracy_score(y_test, predictions))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# '''Séparation des Données''':&lt;br /&gt;
#* Les données sont divisées en deux ensembles : un ensemble d'entraînement et un ensemble de test. Cette séparation est cruciale pour évaluer objectivement la performance du modèle.&lt;br /&gt;
#* Généralement, on adopte une répartition de 80% pour l'entraînement et 20% pour les tests.&lt;br /&gt;
# '''Entraînement du Modèle SVM''':&lt;br /&gt;
#* Le modèle SVM avec un noyau RBF (Radial Basis Function) est entraîné sur l'ensemble d'entraînement.&lt;br /&gt;
#* L'entraînement implique l'ajustement du modèle aux données d'entraînement, en apprenant à distinguer les différents signes.&lt;br /&gt;
# '''Sauvegarde et Réutilisation du Modèle'''&lt;br /&gt;
#* Une fois entraîné et validé, le modèle est sauvegardé à l'aide de la bibliothèque &amp;lt;code&amp;gt;pickle&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Validation et Évaluation du Modèle''':&lt;br /&gt;
#* Après l'entraînement, le modèle est testé sur l'ensemble de test pour évaluer sa performance.&lt;br /&gt;
#* La métrique principale utilisée est la précision, qui mesure la proportion de prédictions correctes par rapport au total des prédictions.&lt;br /&gt;
&lt;br /&gt;
Ensuite on peut générer le modèle comme ceci:&lt;br /&gt;
[[Fichier:Generate model.png|vignette|399x399px|néant]]&lt;br /&gt;
&lt;br /&gt;
Avec cette prédiction lorsque notre modèle prédit le résultat, il est correct environ 71.81% du temps.&lt;br /&gt;
&lt;br /&gt;
=== 5. Intégration MQTT et Communication ===&lt;br /&gt;
----Protocole de communication  :&lt;br /&gt;
&lt;br /&gt;
Dans le cadre de notre projet, la communication entre les dispositifs Raspberry Pi et le serveur  est établie via le protocole MQTT.&lt;br /&gt;
&lt;br /&gt;
Justification du Choix de MQTT :&lt;br /&gt;
&lt;br /&gt;
Au début du projet, une approche basée sur des sockets IPv6 avait été envisagée pour tirer parti de l'adressage direct et de la simplification de la configuration réseau qu'offre IPv6. Cependant, dans le but de respecter les impératifs de sobriété énergétique et d'assurer une scalabilité optimale du système, permettant ainsi de gérer aisément un nombre croissant de dispositifs Raspberry Pi, la décision a été prise d'adopter MQTT comme protocole de communication. Le protocole MQTT, reconnu pour sa légèreté et sa fiabilité, s'adapte parfaitement aux contraintes des applications IoT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Installation du broker mosquitto sur le serveur:'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
apt install -y mosquitto mosquitto-clients&lt;br /&gt;
service mosquitto start&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Activation de l'accès à distance au Broker Mosquitto:&lt;br /&gt;
&lt;br /&gt;
ajouter l'authentification par username et mot de passe&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
sudo mosquitto_passwd -c /etc/mosquitto/passwd username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
après on nous demande d'entrer le mot de passe &lt;br /&gt;
&lt;br /&gt;
Modifier le fichier /etc/mosquitto/mosquitto.conf:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
listener 1883 10.42.0.5&lt;br /&gt;
allow_anonymous false&lt;br /&gt;
password_file /etc/mosquitto/passwd&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Mosquitto:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
service mosquitto restart&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vérification ds logs:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
cat /var/log/mosquitto/mosquitto.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Création d'un client MQTT sur la Raspberry Pi:'''&lt;br /&gt;
&lt;br /&gt;
Le script mqtt_client_rpi.py joue un rôle clé dans cette architecture en facilitant la communication bidirectionnelle : il permet non seulement l'envoi des prédictions réalisées par le modèle SVM depuis la Raspberry Pi vers le serveur, mais autorise également la réception des commandes de contrôle, telles que les instructions de démarrage ou d'arrêt de la collecte de données.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import serial&lt;br /&gt;
import pandas as pd&lt;br /&gt;
import pickle&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
pi_id = &amp;quot;rpi1234&amp;quot;&lt;br /&gt;
&lt;br /&gt;
collecting_data = False &lt;br /&gt;
&lt;br /&gt;
client = mqtt.Client()&lt;br /&gt;
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)&lt;br /&gt;
client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
client.loop_start()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(f&amp;quot;config/{pi_id}&amp;quot;)&lt;br /&gt;
    client.publish(&amp;quot;raspberry_available&amp;quot;, pi_id)&lt;br /&gt;
&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global collecting_data&lt;br /&gt;
    if msg.topic == f&amp;quot;config/{pi_id}&amp;quot;:&lt;br /&gt;
        command = msg.payload.decode()&lt;br /&gt;
        if command == &amp;quot;start&amp;quot;:&lt;br /&gt;
            collecting_data = True&lt;br /&gt;
        elif command == &amp;quot;stop&amp;quot;:&lt;br /&gt;
            collecting_data = False&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.on_connect = on_connect&lt;br /&gt;
client.on_message = on_message&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Configurez le port série et chargez le modèle ici&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    rf = pickle.load(file)&lt;br /&gt;
try:&lt;br /&gt;
&lt;br /&gt;
    while True:&lt;br /&gt;
        if collecting_data:&lt;br /&gt;
            data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
            if data:&lt;br /&gt;
                try:&lt;br /&gt;
                    sensor_values = [value for value in data.split(',') if value.strip().replace('.', '', 1).isdigit()]&lt;br /&gt;
                    if len(sensor_values) == 16:&lt;br /&gt;
                        sensor_values = list(map(float, sensor_values))&lt;br /&gt;
                        sensor_values_df = pd.DataFrame([sensor_values])&lt;br /&gt;
                        prediction = rf.predict(sensor_values_df)&lt;br /&gt;
                        client.publish(f&amp;quot;telemetry/{pi_id}&amp;quot;, str(prediction[0]).encode())&lt;br /&gt;
                        print(&amp;quot;Prédiction :&amp;quot;, prediction[0])&lt;br /&gt;
                except ValueError as e:&lt;br /&gt;
                    print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:&lt;br /&gt;
    print(&amp;quot;Script interrompu&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.loop_stop()&lt;br /&gt;
client.disconnect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Ici il y a 3 topics différents. lorsqu'une raspberry se connecte au réseau elle publie son ID (qui est unique, on peut prendre par exemple l'adresse MAC) sur le topic raspberry_available. Cela nous servira a savoir quelle raspberry est connecté et de se fait pouvoir afficher celles-ci sur notre interface web.&lt;br /&gt;
&lt;br /&gt;
le deuxième topic et le topic config/ID (avec id l'identifiant unique de la raspberry), il nous sert a envoyer les commandes &amp;quot;start&amp;quot; et &amp;quot;stop&amp;quot; a la raspberry afin qu'elle démarre ou arrête la lecture des datas.&lt;br /&gt;
&lt;br /&gt;
Le troisième topic est le topic telemetry/ID, ou la raspberry vient publier ses données.&lt;br /&gt;
&lt;br /&gt;
Un quatrième topic pourrait être implémenter comme par exemple le topic common_config, toutes les raspberrys serait abonnées a ce topic. S'il est nécessaire, cela nous permettrais d'envoyer la même commande a toutes les raspberry  plutôt que de faire une publication sur chaque config/ID &lt;br /&gt;
&lt;br /&gt;
=== 6. Interface Serveur et Gestion des Données ===&lt;br /&gt;
----Le serveur central, au cœur de notre système, est orchestré par le script &amp;lt;code&amp;gt;app.py&amp;lt;/code&amp;gt; qui exploite le framework Flask pour mettre en place une interface serveur. Cette interface est conçue pour traiter efficacement les requêtes HTTP et les messages MQTT, offrant ainsi une API réactive pour l'interface utilisateur web. Elle permet également de visualiser en temps réel l'état des dispositifs Raspberry Pi connectés et les dernières données traitées.&lt;br /&gt;
[[Fichier:Signspeakweb.png|centré|vignette|1000x1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from flask import Flask, render_template, request, jsonify&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import queue&lt;br /&gt;
&lt;br /&gt;
app = Flask(__name__)&lt;br /&gt;
messages = []&lt;br /&gt;
received_messages = queue.Queue()&lt;br /&gt;
latest_message = None&lt;br /&gt;
subscribed_topics = set()&lt;br /&gt;
raspberry_ids = set()&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client = mqtt.Client()&lt;br /&gt;
mqtt_client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD) &lt;br /&gt;
mqtt_client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
mqtt_client.loop_start()&lt;br /&gt;
&lt;br /&gt;
def send_command_to_pi(pi_id, command):&lt;br /&gt;
    try:&lt;br /&gt;
        topic = f&amp;quot;config/{pi_id}&amp;quot;&lt;br /&gt;
        mqtt_client.publish(topic, command)&lt;br /&gt;
        subscribe_to_pi_telemetry(pi_id)&lt;br /&gt;
        return True, &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
    except Exception as e:&lt;br /&gt;
        return False, f&amp;quot;Commande pas envoyée: Erreur MQTT : {e}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
def subscribe_to_pi_telemetry(pi_id):&lt;br /&gt;
    global subscribed_topics&lt;br /&gt;
    topic = f&amp;quot;telemetry/{pi_id}&amp;quot;&lt;br /&gt;
    if topic not in subscribed_topics:&lt;br /&gt;
        mqtt_client.subscribe(topic)&lt;br /&gt;
        subscribed_topics.add(topic)&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(&amp;quot;raspberry_available&amp;quot;)&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    print(f&amp;quot;Received message on topic {msg.topic}: {msg.payload.decode()}&amp;quot;)  # Ajouter pour le débogage&lt;br /&gt;
    if msg.topic == &amp;quot;raspberry_available&amp;quot;:&lt;br /&gt;
        raspberry_ids.add(msg.payload.decode())&lt;br /&gt;
    else:&lt;br /&gt;
        received_messages.put(msg.payload.decode())&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client.on_connect = on_connect&lt;br /&gt;
mqtt_client.on_message = on_message&lt;br /&gt;
@app.route('/get-raspberry-ids')&lt;br /&gt;
def get_raspberry_ids():&lt;br /&gt;
    return jsonify(list(raspberry_ids))&lt;br /&gt;
@app.route('/get-latest-message')&lt;br /&gt;
def get_latest_message():&lt;br /&gt;
    global latest_message&lt;br /&gt;
    while not received_messages.empty():&lt;br /&gt;
        messages.append(received_messages.get())&lt;br /&gt;
&lt;br /&gt;
    latest_message = messages[-1] if messages else None&lt;br /&gt;
    &lt;br /&gt;
    print(f&amp;quot;Contenu de la réponse pour /get-latest-message : {latest_message}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    if latest_message is not None:&lt;br /&gt;
         response = jsonify({&amp;quot;message&amp;quot;: latest_message})&lt;br /&gt;
         return response&lt;br /&gt;
    else:&lt;br /&gt;
        message = &amp;quot;Aucun signe a traduire pour le moment&amp;quot;&lt;br /&gt;
        return jsonify(message)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@app.route('/', methods=['GET', 'POST'])&lt;br /&gt;
&lt;br /&gt;
def index():&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    error_message_rpi = None&lt;br /&gt;
    success_message = None&lt;br /&gt;
&lt;br /&gt;
    if request.method == 'POST':&lt;br /&gt;
        pi_id = request.form.get('pi_id')&lt;br /&gt;
        command = request.form.get('command')&lt;br /&gt;
        if pi_id and command in [&amp;quot;start&amp;quot;, &amp;quot;stop&amp;quot;]:&lt;br /&gt;
            success, er_message = send_command_to_pi(pi_id, command)&lt;br /&gt;
            if success:&lt;br /&gt;
                success_message = &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                error_message_rpi = er_message&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    return render_template('index.html', raspberry_ids=list(raspberry_ids), error_message_rpi=error_message_rpi, success_message=success_message, message=latest_message)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    app.run(debug=False, port=8066)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7. Conception de l'Interface Utilisateur ===&lt;br /&gt;
----L'interface utilisateur, développée à l'aide des technologies web standard HTML, CSS, et JavaScript, offre une expérience interactive. Le fichier index.html constitue le point d'entrée de cette interface, proposant des fonctionnalités telles que l'envoi de commandes aux dispositifs Raspberry Pi et la visualisation des données traitées. L'utilisation de JavaScript pour interroger dynamiquement le serveur Flask permet de rafraîchir les informations affichées en temps réel, garantissant ainsi une interface réactive et à jour.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
index.html:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
        body {&lt;br /&gt;
            background-color: #343a40; &lt;br /&gt;
            color: #ced4da; &lt;br /&gt;
        }&lt;br /&gt;
        .card {&lt;br /&gt;
            background-color: #495057; /* Fond des encadrés plus sombre */&lt;br /&gt;
        }&lt;br /&gt;
        .card-title, .card-text, .alert {&lt;br /&gt;
            color: #adb5bd; /* Gris plus doux pour les titres, le texte et les alertes */&lt;br /&gt;
        }&lt;br /&gt;
        .btn-primary {&lt;br /&gt;
            background-color: #007bff; /* Bleu Bootstrap par défaut pour les boutons */&lt;br /&gt;
            border-color: #007bff;&lt;br /&gt;
        }&lt;br /&gt;
        .btn-danger {&lt;br /&gt;
            background-color: #dc3545; /* Rouge Bootstrap par défaut pour les boutons d'arrêt */&lt;br /&gt;
            border-color: #dc3545;&lt;br /&gt;
        }&lt;br /&gt;
        .form-control {&lt;br /&gt;
            background-color: #495057; /* Fond des champs de saisie plus sombre */&lt;br /&gt;
            border: 1px solid #6c757d;&lt;br /&gt;
            color: #ced4da; /* Couleur du texte dans les champs de saisie */&lt;br /&gt;
        }&lt;br /&gt;
        a, .btn-secondary {&lt;br /&gt;
            color: #17a2b8; /* Bleu clair pour les liens et les boutons secondaires */&lt;br /&gt;
        }&lt;br /&gt;
        a:hover {&lt;br /&gt;
            color: #138496; &lt;br /&gt;
        }&lt;br /&gt;
        #latest-message {&lt;br /&gt;
            background-color: #596069; &lt;br /&gt;
            border: 1px solid #6c757d; &lt;br /&gt;
            color: #E9ECEF; &lt;br /&gt;
            padding: 10px; &lt;br /&gt;
            border-radius: 5px; &lt;br /&gt;
        }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;container mt-5&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;h1 class=&amp;quot;text-center mb-4&amp;quot;&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/h1&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour les Raspberry Pi Disponibles --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-md-12&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Raspberry Pi Disponibles&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;ul id=&amp;quot;raspberry-list&amp;quot; class=&amp;quot;list-group list-group-flush&amp;quot;&amp;gt;&lt;br /&gt;
                    &lt;br /&gt;
                        &amp;lt;/ul&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour la Collecte des données --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Collecte de données&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;form method=&amp;quot;post&amp;quot; class=&amp;quot;form-inline&amp;quot;&amp;gt;&lt;br /&gt;
                            &amp;lt;input type=&amp;quot;text&amp;quot; class=&amp;quot;form-control mb-2 mr-sm-2&amp;quot; name=&amp;quot;pi_id&amp;quot; placeholder=&amp;quot;Entrez l'ID de la Raspberry Pi&amp;quot; required&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-primary mb-2 mr-sm-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;start&amp;quot;&amp;gt;Démarrer la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-danger mb-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;stop&amp;quot;&amp;gt;Arrêter la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                        &amp;lt;/form&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;!-- Encadré pour le Dernier Message Reçu --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Dernier Message Reçu&amp;lt;/h2&amp;gt;&lt;br /&gt;
                    &amp;lt;div id=&amp;quot;latest-message&amp;quot; class=&amp;quot;alert alert-dark&amp;quot;&amp;gt;&lt;br /&gt;
                        Aucun message reçu pour le moment. &lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;mb-3 text-center&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;a href=&amp;quot;/logs&amp;quot; class=&amp;quot;btn btn-secondary&amp;quot;&amp;gt;Voir les Logs&amp;lt;/a&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        function fetchRaspberryIds() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        var ids = JSON.parse(xhr.responseText);&lt;br /&gt;
                        var list = document.getElementById('raspberry-list');&lt;br /&gt;
                        list.innerHTML = '';&lt;br /&gt;
                        ids.forEach(function(id) {&lt;br /&gt;
                            var li = document.createElement('li');&lt;br /&gt;
                            li.textContent = id;&lt;br /&gt;
                            list.appendChild(li);&lt;br /&gt;
                        });&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-raspberry-ids', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function fetchLatestMessage() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        console.log(xhr.responseText)&lt;br /&gt;
                        document.getElementById('latest-message').textContent = xhr.responseText;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-latest-message', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setInterval(fetchRaspberryIds, 5000); // Met à jour les IDs toutes les 5 secondes&lt;br /&gt;
        setInterval(fetchLatestMessage, 500); // Met à jour le dernier message toutes les secondes&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    {% if error_message_rpi %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ error_message_rpi }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&lt;br /&gt;
    {% if success_message %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ success_message }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On a aussi ajouté une page de logs, qui permet de voir l'historique de tous les données traitées.&lt;br /&gt;
&lt;br /&gt;
=== 9. Conclusion et Perspectives ===&lt;br /&gt;
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont&lt;br /&gt;
&lt;br /&gt;
== Vidéo ==&lt;br /&gt;
Lorsque l'on clique sur &amp;quot;démarrer la collecte&amp;quot; en ayant spécifié un ID, on peut voir en temps réel le résultat dans le cadre Dernier Message Recu.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:RPReplay_Final1706462779.mov|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Déroulement des séances ==&lt;br /&gt;
&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:IfconfigVM.png|sans_cadre]]&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
[[Fichier:Capture d’écran 2024-01-28 à 19.07.42.png|néant|vignette]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4902</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4902"/>
		<updated>2024-01-28T18:14:19Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* Séance du 04/12/2023 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Compte rendu des séances=&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:IfconfigVM.png|sans_cadre]]&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
[[Fichier:Capture d’écran 2024-01-28 à 19.07.42.png|néant|vignette]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== '''Présentation du projet''' ==&lt;br /&gt;
&lt;br /&gt;
=== 1. Introduction ===&lt;br /&gt;
----Le projet SignSpeak a pour ambition de créer une solution innovante pour la traduction du langage des signes en texte. L'objectif principal est de développer un système capable de capturer les mouvements des mains et de les interpréter en langage des signes, permettant une communication fluide entre les personnes sourdes ou malentendantes et celles qui ne connaissent pas le langage des signes. Ce projet intègre des technologies avancées telles que l'edge computing, l'intelligence artificielle embarquée, et les communications MQTT, offrant une approche novatrice dans le domaine de l'accessibilité et de la communication.&lt;br /&gt;
&lt;br /&gt;
=== 2. Architecture du Système ===&lt;br /&gt;
----Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :&lt;br /&gt;
&lt;br /&gt;
* '''Capteurs et STM32''' : Des capteurs sont connectés à un microcontrôleur STM32, responsables de la capture des mouvements de main. Ces données sont ensuite transmises pour traitement.&lt;br /&gt;
* '''Raspberry Pi''' : Agissant comme un intermédiaire, la Raspberry Pi reçoit les données des capteurs via UART, exécute un traitement préliminaire et communique avec le serveur.&lt;br /&gt;
* '''Serveur et Machine Learning''' : Un serveur, hébergé sur une VM Xen, traite les données à l'aide d'un modèle SVM pour la traduction en langage des signes et fournit une interface web pour l'interaction utilisateur.&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== 3. Collecte et Préparation des Données ===&lt;br /&gt;
----Le processus de collecte des données est géré par le script &amp;lt;code&amp;gt;enregistrementData.py&amp;lt;/code&amp;gt;. Ce script lit les données transmises par le STM32 via UART et les enregistre dans un fichier CSV. Chaque entrée du fichier représente les valeurs de capteurs à un moment donné, accompagnées d'une étiquette correspondant au signe effectué. Cette approche assure une collecte de données structurée, essentielle pour l'entraînement précis du modèle d'apprentissage automatique.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
import csv&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
# Vérification de l'argument d'entrée&lt;br /&gt;
if len(sys.argv) &amp;lt; 2:&lt;br /&gt;
    print(&amp;quot;Usage: python script.py &amp;lt;etiquette&amp;gt;&amp;quot;)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
etiquette = sys.argv[1]&lt;br /&gt;
&lt;br /&gt;
# Paramètres de l'UART&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
&lt;br /&gt;
# Créer une connexion UART&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
&lt;br /&gt;
# Nom du fichier CSV&lt;br /&gt;
filename = f&amp;quot;data_complete.csv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Vérifier si le fichier existe déjà&lt;br /&gt;
file_exists = False&lt;br /&gt;
try:&lt;br /&gt;
    with open(filename, 'r') as f:&lt;br /&gt;
        file_exists = True&lt;br /&gt;
except FileNotFoundError:&lt;br /&gt;
    file_exists = False&lt;br /&gt;
&lt;br /&gt;
# Ouvrir le fichier CSV en mode append&lt;br /&gt;
with open(filename, 'a', newline='') as file:&lt;br /&gt;
    writer = csv.writer(file)&lt;br /&gt;
&lt;br /&gt;
    # Écrire l'en-tête si le fichier n'existait pas&lt;br /&gt;
    if not file_exists:&lt;br /&gt;
        writer.writerow([&amp;quot;Capteur1&amp;quot;, &amp;quot;Capteur2&amp;quot;, &amp;quot;Capteur3&amp;quot;, &amp;quot;Capteur4&amp;quot;, &amp;quot;Capteur5&amp;quot;, &amp;quot;Capteur6&amp;quot;, &amp;quot;Capteur7&amp;quot;, &amp;quot;Capteur8&amp;quot;, &amp;quot;Capteur9&amp;quot;, &amp;quot;Capteur10&amp;quot;, &amp;quot;Capteur11&amp;quot;, &amp;quot;Capteur12&amp;quot;, &amp;quot;Capteur13&amp;quot;, &amp;quot;Capteur14&amp;quot;, &lt;br /&gt;
&amp;quot;Capteur15&amp;quot;, &amp;quot;Capteur16&amp;quot;, &amp;quot;Etiquette&amp;quot;])&lt;br /&gt;
    elif file_exists:&lt;br /&gt;
        writer.writerow([])&lt;br /&gt;
    while True:&lt;br /&gt;
        # Lire une ligne de données depuis l'UART&lt;br /&gt;
        data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
        print(f&amp;quot;Données reçues : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Vérifier si des données ont été reçues&lt;br /&gt;
        if data:&lt;br /&gt;
            # Diviser les données en valeurs individuelles&lt;br /&gt;
            sensor_values = data.split(',')&lt;br /&gt;
&lt;br /&gt;
            # Filtrer les chaînes vides ou non numériques et convertir en flottants&lt;br /&gt;
            try:&lt;br /&gt;
                sensor_values = [float(value) for value in sensor_values if value.strip().isdigit()]&lt;br /&gt;
&lt;br /&gt;
                # Vérifier qu'il y a 16 valeurs de capteur&lt;br /&gt;
                if len(sensor_values) == 16:&lt;br /&gt;
                    sensor_values.append(etiquette)&lt;br /&gt;
                    writer.writerow(sensor_values)&lt;br /&gt;
                else:&lt;br /&gt;
                    print(&amp;quot;Données incomplètes reçues&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            except ValueError as e:&lt;br /&gt;
                print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
                print(f&amp;quot;Données problématiques : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Le script commence par établir une communication série avec le STM32.&lt;br /&gt;
* Il lit ensuite les données en série, les décode et les stocke dans un fichier CSV pour une utilisation ultérieure.&lt;br /&gt;
&lt;br /&gt;
* Une fois les données collectées et stockées dans le fichier CSV, elles sont préparées pour l'entraînement du modèle.&lt;br /&gt;
* Cette préparation implique la normalisation des données, la gestion des valeurs manquantes ou aberrantes, et leur formatage dans un bon format.[[Fichier:Rpi entrainement.png|vignette|1000x1000px|néant]]&lt;br /&gt;
=== 4. Entraînement du Modèle d'Apprentissage Automatique ===&lt;br /&gt;
----L'entraînement du modèle est réalisé par un script Python utilisant la bibliothèque scikit-learn. Le modèle SVM, choisi pour sa capacité à gérer des espaces de grande dimension, est entraîné sur l'ensemble des données collectées. Ce processus comprend la division des données en ensembles d'entraînement et de test, l'entraînement du modèle, et sa validation par le calcul de la précision. Nous avions testé plusieurs modèle, comme par exemple un modèle Knn ou randomForest, des 3 algorithmes, c'est celui qui nous à apporté les meilleurs résultats pour un meme nombre de data d'entrainement. (RandomForest en deuxième position)&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import pandas as pd&lt;br /&gt;
from sklearn.model_selection import train_test_split&lt;br /&gt;
from sklearn.svm import SVC&lt;br /&gt;
from sklearn.metrics import accuracy_score&lt;br /&gt;
import pickle&lt;br /&gt;
&lt;br /&gt;
# Charger vos données&lt;br /&gt;
data = pd.read_csv('data_complete.csv')&lt;br /&gt;
&lt;br /&gt;
# Séparer les caractéristiques et les étiquettes&lt;br /&gt;
X = data.drop('Etiquette', axis=1)&lt;br /&gt;
y = data['Etiquette']&lt;br /&gt;
&lt;br /&gt;
# Diviser les données en ensembles d'entraînement et de test&lt;br /&gt;
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)&lt;br /&gt;
&lt;br /&gt;
# Créer et entraîner le modèle SVM&lt;br /&gt;
model = SVC(kernel='rbf')&lt;br /&gt;
model.fit(X_train, y_train)&lt;br /&gt;
&lt;br /&gt;
# Sauvegarder le modèle entraîné&lt;br /&gt;
with open('modele_svm.pkl', 'wb') as file:&lt;br /&gt;
    pickle.dump(model, file)&lt;br /&gt;
&lt;br /&gt;
# Charger le modèle et faire des prédictions&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    loaded_model = pickle.load(file)&lt;br /&gt;
    predictions = loaded_model.predict(X_test)&lt;br /&gt;
    print(&amp;quot;Précision :&amp;quot;, accuracy_score(y_test, predictions))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# '''Séparation des Données''':&lt;br /&gt;
#* Les données sont divisées en deux ensembles : un ensemble d'entraînement et un ensemble de test. Cette séparation est cruciale pour évaluer objectivement la performance du modèle.&lt;br /&gt;
#* Généralement, on adopte une répartition de 80% pour l'entraînement et 20% pour les tests.&lt;br /&gt;
# '''Entraînement du Modèle SVM''':&lt;br /&gt;
#* Le modèle SVM avec un noyau RBF (Radial Basis Function) est entraîné sur l'ensemble d'entraînement.&lt;br /&gt;
#* L'entraînement implique l'ajustement du modèle aux données d'entraînement, en apprenant à distinguer les différents signes.&lt;br /&gt;
# '''Sauvegarde et Réutilisation du Modèle'''&lt;br /&gt;
#* Une fois entraîné et validé, le modèle est sauvegardé à l'aide de la bibliothèque &amp;lt;code&amp;gt;pickle&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Validation et Évaluation du Modèle''':&lt;br /&gt;
#* Après l'entraînement, le modèle est testé sur l'ensemble de test pour évaluer sa performance.&lt;br /&gt;
#* La métrique principale utilisée est la précision, qui mesure la proportion de prédictions correctes par rapport au total des prédictions.&lt;br /&gt;
&lt;br /&gt;
Ensuite on peut générer le modèle comme ceci:&lt;br /&gt;
[[Fichier:Generate model.png|vignette|399x399px|néant]]&lt;br /&gt;
&lt;br /&gt;
Avec cette prédiction lorsque notre modèle prédit le résultat, il est correct environ 71.81% du temps.&lt;br /&gt;
&lt;br /&gt;
=== 5. Intégration MQTT et Communication ===&lt;br /&gt;
----Protocole de communication  :&lt;br /&gt;
&lt;br /&gt;
Dans le cadre de notre projet, la communication entre les dispositifs Raspberry Pi et le serveur  est établie via le protocole MQTT.&lt;br /&gt;
&lt;br /&gt;
Justification du Choix de MQTT :&lt;br /&gt;
&lt;br /&gt;
Au début du projet, une approche basée sur des sockets IPv6 avait été envisagée pour tirer parti de l'adressage direct et de la simplification de la configuration réseau qu'offre IPv6. Cependant, dans le but de respecter les impératifs de sobriété énergétique et d'assurer une scalabilité optimale du système, permettant ainsi de gérer aisément un nombre croissant de dispositifs Raspberry Pi, la décision a été prise d'adopter MQTT comme protocole de communication. Le protocole MQTT, reconnu pour sa légèreté et sa fiabilité, s'adapte parfaitement aux contraintes des applications IoT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Installation du broker mosquitto sur le serveur:'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
apt install -y mosquitto mosquitto-clients&lt;br /&gt;
service mosquitto start&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Activation de l'accès à distance au Broker Mosquitto:&lt;br /&gt;
&lt;br /&gt;
ajouter l'authentification par username et mot de passe&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
sudo mosquitto_passwd -c /etc/mosquitto/passwd username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
après on nous demande d'entrer le mot de passe &lt;br /&gt;
&lt;br /&gt;
Modifier le fichier /etc/mosquitto/mosquitto.conf:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
listener 1883 10.42.0.5&lt;br /&gt;
allow_anonymous false&lt;br /&gt;
password_file /etc/mosquitto/passwd&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Mosquitto:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
service mosquitto restart&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vérification ds logs:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
cat /var/log/mosquitto/mosquitto.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Création d'un client MQTT sur la Raspberry Pi:'''&lt;br /&gt;
&lt;br /&gt;
Le script mqtt_client_rpi.py joue un rôle clé dans cette architecture en facilitant la communication bidirectionnelle : il permet non seulement l'envoi des prédictions réalisées par le modèle SVM depuis la Raspberry Pi vers le serveur, mais autorise également la réception des commandes de contrôle, telles que les instructions de démarrage ou d'arrêt de la collecte de données.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import serial&lt;br /&gt;
import pandas as pd&lt;br /&gt;
import pickle&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
pi_id = &amp;quot;rpi1234&amp;quot;&lt;br /&gt;
&lt;br /&gt;
collecting_data = False &lt;br /&gt;
&lt;br /&gt;
client = mqtt.Client()&lt;br /&gt;
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)&lt;br /&gt;
client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
client.loop_start()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(f&amp;quot;config/{pi_id}&amp;quot;)&lt;br /&gt;
    client.publish(&amp;quot;raspberry_available&amp;quot;, pi_id)&lt;br /&gt;
&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global collecting_data&lt;br /&gt;
    if msg.topic == f&amp;quot;config/{pi_id}&amp;quot;:&lt;br /&gt;
        command = msg.payload.decode()&lt;br /&gt;
        if command == &amp;quot;start&amp;quot;:&lt;br /&gt;
            collecting_data = True&lt;br /&gt;
        elif command == &amp;quot;stop&amp;quot;:&lt;br /&gt;
            collecting_data = False&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.on_connect = on_connect&lt;br /&gt;
client.on_message = on_message&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Configurez le port série et chargez le modèle ici&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    rf = pickle.load(file)&lt;br /&gt;
try:&lt;br /&gt;
&lt;br /&gt;
    while True:&lt;br /&gt;
        if collecting_data:&lt;br /&gt;
            data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
            if data:&lt;br /&gt;
                try:&lt;br /&gt;
                    sensor_values = [value for value in data.split(',') if value.strip().replace('.', '', 1).isdigit()]&lt;br /&gt;
                    if len(sensor_values) == 16:&lt;br /&gt;
                        sensor_values = list(map(float, sensor_values))&lt;br /&gt;
                        sensor_values_df = pd.DataFrame([sensor_values])&lt;br /&gt;
                        prediction = rf.predict(sensor_values_df)&lt;br /&gt;
                        client.publish(f&amp;quot;telemetry/{pi_id}&amp;quot;, str(prediction[0]).encode())&lt;br /&gt;
                        print(&amp;quot;Prédiction :&amp;quot;, prediction[0])&lt;br /&gt;
                except ValueError as e:&lt;br /&gt;
                    print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:&lt;br /&gt;
    print(&amp;quot;Script interrompu&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.loop_stop()&lt;br /&gt;
client.disconnect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Ici il y a 3 topics différents. lorsqu'une raspberry se connecte au réseau elle publie son ID (qui est unique, on peut prendre par exemple l'adresse MAC) sur le topic raspberry_available. Cela nous servira a savoir quelle raspberry est connecté et de se fait pouvoir afficher celles-ci sur notre interface web.&lt;br /&gt;
&lt;br /&gt;
le deuxième topic et le topic config/ID (avec id l'identifiant unique de la raspberry), il nous sert a envoyer les commandes &amp;quot;start&amp;quot; et &amp;quot;stop&amp;quot; a la raspberry afin qu'elle démarre ou arrête la lecture des datas.&lt;br /&gt;
&lt;br /&gt;
Le troisième topic est le topic telemetry/ID, ou la raspberry vient publier ses données.&lt;br /&gt;
&lt;br /&gt;
Un quatrième topic pourrait être implémenter comme par exemple le topic common_config, toutes les raspberrys serait abonnées a ce topic. S'il est nécessaire, cela nous permettrais d'envoyer la même commande a toutes les raspberry  plutôt que de faire une publication sur chaque config/ID &lt;br /&gt;
&lt;br /&gt;
=== 6. Interface Serveur et Gestion des Données ===&lt;br /&gt;
----Le serveur central, au cœur de notre système, est orchestré par le script &amp;lt;code&amp;gt;app.py&amp;lt;/code&amp;gt; qui exploite le framework Flask pour mettre en place une interface serveur. Cette interface est conçue pour traiter efficacement les requêtes HTTP et les messages MQTT, offrant ainsi une API réactive pour l'interface utilisateur web. Elle permet également de visualiser en temps réel l'état des dispositifs Raspberry Pi connectés et les dernières données traitées.&lt;br /&gt;
[[Fichier:Signspeakweb.png|centré|vignette|1000x1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from flask import Flask, render_template, request, jsonify&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import queue&lt;br /&gt;
&lt;br /&gt;
app = Flask(__name__)&lt;br /&gt;
messages = []&lt;br /&gt;
received_messages = queue.Queue()&lt;br /&gt;
latest_message = None&lt;br /&gt;
subscribed_topics = set()&lt;br /&gt;
raspberry_ids = set()&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client = mqtt.Client()&lt;br /&gt;
mqtt_client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD) &lt;br /&gt;
mqtt_client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
mqtt_client.loop_start()&lt;br /&gt;
&lt;br /&gt;
def send_command_to_pi(pi_id, command):&lt;br /&gt;
    try:&lt;br /&gt;
        topic = f&amp;quot;config/{pi_id}&amp;quot;&lt;br /&gt;
        mqtt_client.publish(topic, command)&lt;br /&gt;
        subscribe_to_pi_telemetry(pi_id)&lt;br /&gt;
        return True, &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
    except Exception as e:&lt;br /&gt;
        return False, f&amp;quot;Commande pas envoyée: Erreur MQTT : {e}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
def subscribe_to_pi_telemetry(pi_id):&lt;br /&gt;
    global subscribed_topics&lt;br /&gt;
    topic = f&amp;quot;telemetry/{pi_id}&amp;quot;&lt;br /&gt;
    if topic not in subscribed_topics:&lt;br /&gt;
        mqtt_client.subscribe(topic)&lt;br /&gt;
        subscribed_topics.add(topic)&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(&amp;quot;raspberry_available&amp;quot;)&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    print(f&amp;quot;Received message on topic {msg.topic}: {msg.payload.decode()}&amp;quot;)  # Ajouter pour le débogage&lt;br /&gt;
    if msg.topic == &amp;quot;raspberry_available&amp;quot;:&lt;br /&gt;
        raspberry_ids.add(msg.payload.decode())&lt;br /&gt;
    else:&lt;br /&gt;
        received_messages.put(msg.payload.decode())&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client.on_connect = on_connect&lt;br /&gt;
mqtt_client.on_message = on_message&lt;br /&gt;
@app.route('/get-raspberry-ids')&lt;br /&gt;
def get_raspberry_ids():&lt;br /&gt;
    return jsonify(list(raspberry_ids))&lt;br /&gt;
@app.route('/get-latest-message')&lt;br /&gt;
def get_latest_message():&lt;br /&gt;
    global latest_message&lt;br /&gt;
    while not received_messages.empty():&lt;br /&gt;
        messages.append(received_messages.get())&lt;br /&gt;
&lt;br /&gt;
    latest_message = messages[-1] if messages else None&lt;br /&gt;
    &lt;br /&gt;
    # Ajoutez cet enregistrement de débogage&lt;br /&gt;
    print(f&amp;quot;Contenu de la réponse pour /get-latest-message : {latest_message}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    if latest_message is not None:&lt;br /&gt;
         response = jsonify({&amp;quot;message&amp;quot;: latest_message})&lt;br /&gt;
         return response&lt;br /&gt;
    else:&lt;br /&gt;
        message = &amp;quot;Aucun signe a traduire pour le moment&amp;quot;&lt;br /&gt;
        return jsonify(message)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@app.route('/', methods=['GET', 'POST'])&lt;br /&gt;
&lt;br /&gt;
def index():&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    error_message_rpi = None&lt;br /&gt;
    success_message = None&lt;br /&gt;
&lt;br /&gt;
    if request.method == 'POST':&lt;br /&gt;
        pi_id = request.form.get('pi_id')&lt;br /&gt;
        command = request.form.get('command')&lt;br /&gt;
        if pi_id and command in [&amp;quot;start&amp;quot;, &amp;quot;stop&amp;quot;]:&lt;br /&gt;
            success, er_message = send_command_to_pi(pi_id, command)&lt;br /&gt;
            if success:&lt;br /&gt;
                success_message = &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                error_message_rpi = er_message&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    return render_template('index.html', raspberry_ids=list(raspberry_ids), error_message_rpi=error_message_rpi, success_message=success_message, message=latest_message)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    app.run(debug=False, port=8066)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7. Conception de l'Interface Utilisateur ===&lt;br /&gt;
----L'interface utilisateur, développée à l'aide des technologies web standard HTML, CSS, et JavaScript, offre une expérience interactive. Le fichier index.html constitue le point d'entrée de cette interface, proposant des fonctionnalités telles que l'envoi de commandes aux dispositifs Raspberry Pi et la visualisation des données traitées. L'utilisation de JavaScript pour interroger dynamiquement le serveur Flask permet de rafraîchir les informations affichées en temps réel, garantissant ainsi une interface réactive et à jour.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
index.html:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
        body {&lt;br /&gt;
            background-color: #343a40; /* Couleur d'arrière-plan foncé */&lt;br /&gt;
            color: #ced4da; /* Gris clair pour le texte pour un meilleur contraste */&lt;br /&gt;
        }&lt;br /&gt;
        .card {&lt;br /&gt;
            background-color: #495057; /* Fond des encadrés plus sombre */&lt;br /&gt;
        }&lt;br /&gt;
        .card-title, .card-text, .alert {&lt;br /&gt;
            color: #adb5bd; /* Gris plus doux pour les titres, le texte et les alertes */&lt;br /&gt;
        }&lt;br /&gt;
        .btn-primary {&lt;br /&gt;
            background-color: #007bff; /* Bleu Bootstrap par défaut pour les boutons */&lt;br /&gt;
            border-color: #007bff;&lt;br /&gt;
        }&lt;br /&gt;
        .btn-danger {&lt;br /&gt;
            background-color: #dc3545; /* Rouge Bootstrap par défaut pour les boutons d'arrêt */&lt;br /&gt;
            border-color: #dc3545;&lt;br /&gt;
        }&lt;br /&gt;
        .form-control {&lt;br /&gt;
            background-color: #495057; /* Fond des champs de saisie plus sombre */&lt;br /&gt;
            border: 1px solid #6c757d;&lt;br /&gt;
            color: #ced4da; /* Couleur du texte dans les champs de saisie */&lt;br /&gt;
        }&lt;br /&gt;
        a, .btn-secondary {&lt;br /&gt;
            color: #17a2b8; /* Bleu clair pour les liens et les boutons secondaires */&lt;br /&gt;
        }&lt;br /&gt;
        a:hover {&lt;br /&gt;
            color: #138496; &lt;br /&gt;
        }&lt;br /&gt;
        #latest-message {&lt;br /&gt;
            background-color: #596069; &lt;br /&gt;
            border: 1px solid #6c757d; &lt;br /&gt;
            color: #E9ECEF; &lt;br /&gt;
            padding: 10px; &lt;br /&gt;
            border-radius: 5px; &lt;br /&gt;
        }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;container mt-5&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;h1 class=&amp;quot;text-center mb-4&amp;quot;&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/h1&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour les Raspberry Pi Disponibles --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-md-12&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Raspberry Pi Disponibles&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;ul id=&amp;quot;raspberry-list&amp;quot; class=&amp;quot;list-group list-group-flush&amp;quot;&amp;gt;&lt;br /&gt;
                    &lt;br /&gt;
                        &amp;lt;/ul&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour la Collecte des données --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Collecte de données&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;form method=&amp;quot;post&amp;quot; class=&amp;quot;form-inline&amp;quot;&amp;gt;&lt;br /&gt;
                            &amp;lt;input type=&amp;quot;text&amp;quot; class=&amp;quot;form-control mb-2 mr-sm-2&amp;quot; name=&amp;quot;pi_id&amp;quot; placeholder=&amp;quot;Entrez l'ID de la Raspberry Pi&amp;quot; required&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-primary mb-2 mr-sm-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;start&amp;quot;&amp;gt;Démarrer la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-danger mb-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;stop&amp;quot;&amp;gt;Arrêter la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                        &amp;lt;/form&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;!-- Encadré pour le Dernier Message Reçu --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Dernier Message Reçu&amp;lt;/h2&amp;gt;&lt;br /&gt;
                    &amp;lt;div id=&amp;quot;latest-message&amp;quot; class=&amp;quot;alert alert-dark&amp;quot;&amp;gt;&lt;br /&gt;
                        Aucun message reçu pour le moment. &lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;mb-3 text-center&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;a href=&amp;quot;/logs&amp;quot; class=&amp;quot;btn btn-secondary&amp;quot;&amp;gt;Voir les Logs&amp;lt;/a&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        function fetchRaspberryIds() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        var ids = JSON.parse(xhr.responseText);&lt;br /&gt;
                        var list = document.getElementById('raspberry-list');&lt;br /&gt;
                        list.innerHTML = '';&lt;br /&gt;
                        ids.forEach(function(id) {&lt;br /&gt;
                            var li = document.createElement('li');&lt;br /&gt;
                            li.textContent = id;&lt;br /&gt;
                            list.appendChild(li);&lt;br /&gt;
                        });&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-raspberry-ids', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function fetchLatestMessage() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        console.log(xhr.responseText)&lt;br /&gt;
                        document.getElementById('latest-message').textContent = xhr.responseText;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-latest-message', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setInterval(fetchRaspberryIds, 5000); // Met à jour les IDs toutes les 5 secondes&lt;br /&gt;
        setInterval(fetchLatestMessage, 500); // Met à jour le dernier message toutes les secondes&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    {% if error_message_rpi %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ error_message_rpi }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&lt;br /&gt;
    {% if success_message %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ success_message }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On a aussi ajouté une page de logs, qui permet de voir l'historique de tous les données traitées.&lt;br /&gt;
&lt;br /&gt;
=== 9. Conclusion et Perspectives ===&lt;br /&gt;
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont&lt;br /&gt;
&lt;br /&gt;
== Vidéo ==&lt;br /&gt;
Lorsque l'on clique sur &amp;quot;démarrer la collecte&amp;quot; en ayant spécifié un ID, on peut voir en temps réel le résultat dans le cadre Dernier Message Recu.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:RPReplay_Final1706462779.mov|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Déroulement des séances ==&lt;br /&gt;
&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:IfconfigVM.png|sans_cadre]]&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
[[Fichier:Capture d’écran 2024-01-28 à 19.07.42.png|néant|vignette]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4901</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4901"/>
		<updated>2024-01-28T18:13:07Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* Séance du 04/12/2023 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Compte rendu des séances=&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:IfconfigVM.png|sans_cadre]]&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
[[Fichier:Capture d’écran 2024-01-28 à 19.07.42.png|néant|vignette]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== '''Présentation du projet''' ==&lt;br /&gt;
&lt;br /&gt;
=== 1. Introduction ===&lt;br /&gt;
----Le projet SignSpeak a pour ambition de créer une solution innovante pour la traduction du langage des signes en texte. L'objectif principal est de développer un système capable de capturer les mouvements des mains et de les interpréter en langage des signes, permettant une communication fluide entre les personnes sourdes ou malentendantes et celles qui ne connaissent pas le langage des signes. Ce projet intègre des technologies avancées telles que l'edge computing, l'intelligence artificielle embarquée, et les communications MQTT, offrant une approche novatrice dans le domaine de l'accessibilité et de la communication.&lt;br /&gt;
&lt;br /&gt;
=== 2. Architecture du Système ===&lt;br /&gt;
----Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :&lt;br /&gt;
&lt;br /&gt;
* '''Capteurs et STM32''' : Des capteurs sont connectés à un microcontrôleur STM32, responsables de la capture des mouvements de main. Ces données sont ensuite transmises pour traitement.&lt;br /&gt;
* '''Raspberry Pi''' : Agissant comme un intermédiaire, la Raspberry Pi reçoit les données des capteurs via UART, exécute un traitement préliminaire et communique avec le serveur.&lt;br /&gt;
* '''Serveur et Machine Learning''' : Un serveur, hébergé sur une VM Xen, traite les données à l'aide d'un modèle SVM pour la traduction en langage des signes et fournit une interface web pour l'interaction utilisateur.&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== 3. Collecte et Préparation des Données ===&lt;br /&gt;
----Le processus de collecte des données est géré par le script &amp;lt;code&amp;gt;enregistrementData.py&amp;lt;/code&amp;gt;. Ce script lit les données transmises par le STM32 via UART et les enregistre dans un fichier CSV. Chaque entrée du fichier représente les valeurs de capteurs à un moment donné, accompagnées d'une étiquette correspondant au signe effectué. Cette approche assure une collecte de données structurée, essentielle pour l'entraînement précis du modèle d'apprentissage automatique.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
import csv&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
# Vérification de l'argument d'entrée&lt;br /&gt;
if len(sys.argv) &amp;lt; 2:&lt;br /&gt;
    print(&amp;quot;Usage: python script.py &amp;lt;etiquette&amp;gt;&amp;quot;)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
etiquette = sys.argv[1]&lt;br /&gt;
&lt;br /&gt;
# Paramètres de l'UART&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
&lt;br /&gt;
# Créer une connexion UART&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
&lt;br /&gt;
# Nom du fichier CSV&lt;br /&gt;
filename = f&amp;quot;data_complete.csv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Vérifier si le fichier existe déjà&lt;br /&gt;
file_exists = False&lt;br /&gt;
try:&lt;br /&gt;
    with open(filename, 'r') as f:&lt;br /&gt;
        file_exists = True&lt;br /&gt;
except FileNotFoundError:&lt;br /&gt;
    file_exists = False&lt;br /&gt;
&lt;br /&gt;
# Ouvrir le fichier CSV en mode append&lt;br /&gt;
with open(filename, 'a', newline='') as file:&lt;br /&gt;
    writer = csv.writer(file)&lt;br /&gt;
&lt;br /&gt;
    # Écrire l'en-tête si le fichier n'existait pas&lt;br /&gt;
    if not file_exists:&lt;br /&gt;
        writer.writerow([&amp;quot;Capteur1&amp;quot;, &amp;quot;Capteur2&amp;quot;, &amp;quot;Capteur3&amp;quot;, &amp;quot;Capteur4&amp;quot;, &amp;quot;Capteur5&amp;quot;, &amp;quot;Capteur6&amp;quot;, &amp;quot;Capteur7&amp;quot;, &amp;quot;Capteur8&amp;quot;, &amp;quot;Capteur9&amp;quot;, &amp;quot;Capteur10&amp;quot;, &amp;quot;Capteur11&amp;quot;, &amp;quot;Capteur12&amp;quot;, &amp;quot;Capteur13&amp;quot;, &amp;quot;Capteur14&amp;quot;, &lt;br /&gt;
&amp;quot;Capteur15&amp;quot;, &amp;quot;Capteur16&amp;quot;, &amp;quot;Etiquette&amp;quot;])&lt;br /&gt;
    elif file_exists:&lt;br /&gt;
        writer.writerow([])&lt;br /&gt;
    while True:&lt;br /&gt;
        # Lire une ligne de données depuis l'UART&lt;br /&gt;
        data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
        print(f&amp;quot;Données reçues : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Vérifier si des données ont été reçues&lt;br /&gt;
        if data:&lt;br /&gt;
            # Diviser les données en valeurs individuelles&lt;br /&gt;
            sensor_values = data.split(',')&lt;br /&gt;
&lt;br /&gt;
            # Filtrer les chaînes vides ou non numériques et convertir en flottants&lt;br /&gt;
            try:&lt;br /&gt;
                sensor_values = [float(value) for value in sensor_values if value.strip().isdigit()]&lt;br /&gt;
&lt;br /&gt;
                # Vérifier qu'il y a 16 valeurs de capteur&lt;br /&gt;
                if len(sensor_values) == 16:&lt;br /&gt;
                    sensor_values.append(etiquette)&lt;br /&gt;
                    writer.writerow(sensor_values)&lt;br /&gt;
                else:&lt;br /&gt;
                    print(&amp;quot;Données incomplètes reçues&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            except ValueError as e:&lt;br /&gt;
                print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
                print(f&amp;quot;Données problématiques : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Le script commence par établir une communication série avec le STM32.&lt;br /&gt;
* Il lit ensuite les données en série, les décode et les stocke dans un fichier CSV pour une utilisation ultérieure.&lt;br /&gt;
&lt;br /&gt;
* Une fois les données collectées et stockées dans le fichier CSV, elles sont préparées pour l'entraînement du modèle.&lt;br /&gt;
* Cette préparation implique la normalisation des données, la gestion des valeurs manquantes ou aberrantes, et leur formatage dans un bon format.[[Fichier:Rpi entrainement.png|vignette|1000x1000px|néant]]&lt;br /&gt;
=== 4. Entraînement du Modèle d'Apprentissage Automatique ===&lt;br /&gt;
----L'entraînement du modèle est réalisé par un script Python utilisant la bibliothèque scikit-learn. Le modèle SVM, choisi pour sa capacité à gérer des espaces de grande dimension, est entraîné sur l'ensemble des données collectées. Ce processus comprend la division des données en ensembles d'entraînement et de test, l'entraînement du modèle, et sa validation par le calcul de la précision. Nous avions testé plusieurs modèle, comme par exemple un modèle Knn ou randomForest, des 3 algorithmes, c'est celui qui nous à apporté les meilleurs résultats pour un meme nombre de data d'entrainement. (RandomForest en deuxième position)&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import pandas as pd&lt;br /&gt;
from sklearn.model_selection import train_test_split&lt;br /&gt;
from sklearn.svm import SVC&lt;br /&gt;
from sklearn.metrics import accuracy_score&lt;br /&gt;
import pickle&lt;br /&gt;
&lt;br /&gt;
# Charger vos données&lt;br /&gt;
data = pd.read_csv('data_complete.csv')&lt;br /&gt;
&lt;br /&gt;
# Séparer les caractéristiques et les étiquettes&lt;br /&gt;
X = data.drop('Etiquette', axis=1)&lt;br /&gt;
y = data['Etiquette']&lt;br /&gt;
&lt;br /&gt;
# Diviser les données en ensembles d'entraînement et de test&lt;br /&gt;
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)&lt;br /&gt;
&lt;br /&gt;
# Créer et entraîner le modèle SVM&lt;br /&gt;
model = SVC(kernel='rbf')&lt;br /&gt;
model.fit(X_train, y_train)&lt;br /&gt;
&lt;br /&gt;
# Sauvegarder le modèle entraîné&lt;br /&gt;
with open('modele_svm.pkl', 'wb') as file:&lt;br /&gt;
    pickle.dump(model, file)&lt;br /&gt;
&lt;br /&gt;
# Charger le modèle et faire des prédictions&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    loaded_model = pickle.load(file)&lt;br /&gt;
    predictions = loaded_model.predict(X_test)&lt;br /&gt;
    print(&amp;quot;Précision :&amp;quot;, accuracy_score(y_test, predictions))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# '''Séparation des Données''':&lt;br /&gt;
#* Les données sont divisées en deux ensembles : un ensemble d'entraînement et un ensemble de test. Cette séparation est cruciale pour évaluer objectivement la performance du modèle.&lt;br /&gt;
#* Généralement, on adopte une répartition de 80% pour l'entraînement et 20% pour les tests.&lt;br /&gt;
# '''Entraînement du Modèle SVM''':&lt;br /&gt;
#* Le modèle SVM avec un noyau RBF (Radial Basis Function) est entraîné sur l'ensemble d'entraînement.&lt;br /&gt;
#* L'entraînement implique l'ajustement du modèle aux données d'entraînement, en apprenant à distinguer les différents signes.&lt;br /&gt;
# '''Sauvegarde et Réutilisation du Modèle'''&lt;br /&gt;
#* Une fois entraîné et validé, le modèle est sauvegardé à l'aide de la bibliothèque &amp;lt;code&amp;gt;pickle&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Validation et Évaluation du Modèle''':&lt;br /&gt;
#* Après l'entraînement, le modèle est testé sur l'ensemble de test pour évaluer sa performance.&lt;br /&gt;
#* La métrique principale utilisée est la précision, qui mesure la proportion de prédictions correctes par rapport au total des prédictions.&lt;br /&gt;
&lt;br /&gt;
Ensuite on peut générer le modèle comme ceci:&lt;br /&gt;
[[Fichier:Generate model.png|vignette|399x399px|néant]]&lt;br /&gt;
&lt;br /&gt;
Avec cette prédiction lorsque notre modèle prédit le résultat, il est correct environ 71.81% du temps.&lt;br /&gt;
&lt;br /&gt;
=== 5. Intégration MQTT et Communication ===&lt;br /&gt;
----Protocole de communication  :&lt;br /&gt;
&lt;br /&gt;
Dans le cadre de notre projet, la communication entre les dispositifs Raspberry Pi et le serveur  est établie via le protocole MQTT.&lt;br /&gt;
&lt;br /&gt;
Justification du Choix de MQTT :&lt;br /&gt;
&lt;br /&gt;
Au début du projet, une approche basée sur des sockets IPv6 avait été envisagée pour tirer parti de l'adressage direct et de la simplification de la configuration réseau qu'offre IPv6. Cependant, dans le but de respecter les impératifs de sobriété énergétique et d'assurer une scalabilité optimale du système, permettant ainsi de gérer aisément un nombre croissant de dispositifs Raspberry Pi, la décision a été prise d'adopter MQTT comme protocole de communication. Le protocole MQTT, reconnu pour sa légèreté et sa fiabilité, s'adapte parfaitement aux contraintes des applications IoT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Installation du broker mosquitto sur le serveur:'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
apt install -y mosquitto mosquitto-clients&lt;br /&gt;
service mosquitto start&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Activation de l'accès à distance au Broker Mosquitto:&lt;br /&gt;
&lt;br /&gt;
ajouter l'authentification par username et mot de passe&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
sudo mosquitto_passwd -c /etc/mosquitto/passwd username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
après on nous demande d'entrer le mot de passe &lt;br /&gt;
&lt;br /&gt;
Modifier le fichier /etc/mosquitto/mosquitto.conf:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
listener 1883 10.42.0.5&lt;br /&gt;
allow_anonymous false&lt;br /&gt;
password_file /etc/mosquitto/passwd&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Mosquitto:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
service mosquitto restart&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vérification ds logs:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
cat /var/log/mosquitto/mosquitto.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Création d'un client MQTT sur la Raspberry Pi:'''&lt;br /&gt;
&lt;br /&gt;
Le script mqtt_client_rpi.py joue un rôle clé dans cette architecture en facilitant la communication bidirectionnelle : il permet non seulement l'envoi des prédictions réalisées par le modèle SVM depuis la Raspberry Pi vers le serveur, mais autorise également la réception des commandes de contrôle, telles que les instructions de démarrage ou d'arrêt de la collecte de données.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import serial&lt;br /&gt;
import pandas as pd&lt;br /&gt;
import pickle&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
pi_id = &amp;quot;rpi1234&amp;quot;&lt;br /&gt;
&lt;br /&gt;
collecting_data = False &lt;br /&gt;
&lt;br /&gt;
client = mqtt.Client()&lt;br /&gt;
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)&lt;br /&gt;
client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
client.loop_start()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(f&amp;quot;config/{pi_id}&amp;quot;)&lt;br /&gt;
    client.publish(&amp;quot;raspberry_available&amp;quot;, pi_id)&lt;br /&gt;
&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global collecting_data&lt;br /&gt;
    if msg.topic == f&amp;quot;config/{pi_id}&amp;quot;:&lt;br /&gt;
        command = msg.payload.decode()&lt;br /&gt;
        if command == &amp;quot;start&amp;quot;:&lt;br /&gt;
            collecting_data = True&lt;br /&gt;
        elif command == &amp;quot;stop&amp;quot;:&lt;br /&gt;
            collecting_data = False&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.on_connect = on_connect&lt;br /&gt;
client.on_message = on_message&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Configurez le port série et chargez le modèle ici&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    rf = pickle.load(file)&lt;br /&gt;
try:&lt;br /&gt;
&lt;br /&gt;
    while True:&lt;br /&gt;
        if collecting_data:&lt;br /&gt;
            data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
            if data:&lt;br /&gt;
                try:&lt;br /&gt;
                    sensor_values = [value for value in data.split(',') if value.strip().replace('.', '', 1).isdigit()]&lt;br /&gt;
                    if len(sensor_values) == 16:&lt;br /&gt;
                        sensor_values = list(map(float, sensor_values))&lt;br /&gt;
                        sensor_values_df = pd.DataFrame([sensor_values])&lt;br /&gt;
                        prediction = rf.predict(sensor_values_df)&lt;br /&gt;
                        client.publish(f&amp;quot;telemetry/{pi_id}&amp;quot;, str(prediction[0]).encode())&lt;br /&gt;
                        print(&amp;quot;Prédiction :&amp;quot;, prediction[0])&lt;br /&gt;
                except ValueError as e:&lt;br /&gt;
                    print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:&lt;br /&gt;
    print(&amp;quot;Script interrompu&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.loop_stop()&lt;br /&gt;
client.disconnect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Ici il y a 3 topics différents. lorsqu'une raspberry se connecte au réseau elle publie son ID (qui est unique, on peut prendre par exemple l'adresse MAC) sur le topic raspberry_available. Cela nous servira a savoir quelle raspberry est connecté et de se fait pouvoir afficher celles-ci sur notre interface web.&lt;br /&gt;
&lt;br /&gt;
le deuxième topic et le topic config/ID (avec id l'identifiant unique de la raspberry), il nous sert a envoyer les commandes &amp;quot;start&amp;quot; et &amp;quot;stop&amp;quot; a la raspberry afin qu'elle démarre ou arrête la lecture des datas.&lt;br /&gt;
&lt;br /&gt;
Le troisième topic est le topic telemetry/ID, ou la raspberry vient publier ses données.&lt;br /&gt;
&lt;br /&gt;
Un quatrième topic pourrait être implémenter comme par exemple le topic common_config, toutes les raspberrys serait abonnées a ce topic. S'il est nécessaire, cela nous permettrais d'envoyer la même commande a toutes les raspberry  plutôt que de faire une publication sur chaque config/ID &lt;br /&gt;
&lt;br /&gt;
=== 6. Interface Serveur et Gestion des Données ===&lt;br /&gt;
----Le serveur central, au cœur de notre système, est orchestré par le script &amp;lt;code&amp;gt;app.py&amp;lt;/code&amp;gt; qui exploite le framework Flask pour mettre en place une interface serveur. Cette interface est conçue pour traiter efficacement les requêtes HTTP et les messages MQTT, offrant ainsi une API réactive pour l'interface utilisateur web. Elle permet également de visualiser en temps réel l'état des dispositifs Raspberry Pi connectés et les dernières données traitées.&lt;br /&gt;
[[Fichier:Signspeakweb.png|centré|vignette|1000x1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from flask import Flask, render_template, request, jsonify&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import queue&lt;br /&gt;
&lt;br /&gt;
app = Flask(__name__)&lt;br /&gt;
messages = []&lt;br /&gt;
received_messages = queue.Queue()&lt;br /&gt;
latest_message = None&lt;br /&gt;
subscribed_topics = set()&lt;br /&gt;
raspberry_ids = set()&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client = mqtt.Client()&lt;br /&gt;
mqtt_client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD) &lt;br /&gt;
mqtt_client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
mqtt_client.loop_start()&lt;br /&gt;
&lt;br /&gt;
def send_command_to_pi(pi_id, command):&lt;br /&gt;
    try:&lt;br /&gt;
        topic = f&amp;quot;config/{pi_id}&amp;quot;&lt;br /&gt;
        mqtt_client.publish(topic, command)&lt;br /&gt;
        subscribe_to_pi_telemetry(pi_id)&lt;br /&gt;
        return True, &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
    except Exception as e:&lt;br /&gt;
        return False, f&amp;quot;Commande pas envoyée: Erreur MQTT : {e}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
def subscribe_to_pi_telemetry(pi_id):&lt;br /&gt;
    global subscribed_topics&lt;br /&gt;
    topic = f&amp;quot;telemetry/{pi_id}&amp;quot;&lt;br /&gt;
    if topic not in subscribed_topics:&lt;br /&gt;
        mqtt_client.subscribe(topic)&lt;br /&gt;
        subscribed_topics.add(topic)&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(&amp;quot;raspberry_available&amp;quot;)&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    print(f&amp;quot;Received message on topic {msg.topic}: {msg.payload.decode()}&amp;quot;)  # Ajouter pour le débogage&lt;br /&gt;
    if msg.topic == &amp;quot;raspberry_available&amp;quot;:&lt;br /&gt;
        raspberry_ids.add(msg.payload.decode())&lt;br /&gt;
    else:&lt;br /&gt;
        received_messages.put(msg.payload.decode())&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client.on_connect = on_connect&lt;br /&gt;
mqtt_client.on_message = on_message&lt;br /&gt;
@app.route('/get-raspberry-ids')&lt;br /&gt;
def get_raspberry_ids():&lt;br /&gt;
    return jsonify(list(raspberry_ids))&lt;br /&gt;
@app.route('/get-latest-message')&lt;br /&gt;
def get_latest_message():&lt;br /&gt;
    global latest_message&lt;br /&gt;
    while not received_messages.empty():&lt;br /&gt;
        messages.append(received_messages.get())&lt;br /&gt;
&lt;br /&gt;
    latest_message = messages[-1] if messages else None&lt;br /&gt;
    &lt;br /&gt;
    # Ajoutez cet enregistrement de débogage&lt;br /&gt;
    print(f&amp;quot;Contenu de la réponse pour /get-latest-message : {latest_message}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    if latest_message is not None:&lt;br /&gt;
         response = jsonify({&amp;quot;message&amp;quot;: latest_message})&lt;br /&gt;
         return response&lt;br /&gt;
    else:&lt;br /&gt;
        message = &amp;quot;Aucun signe a traduire pour le moment&amp;quot;&lt;br /&gt;
        return jsonify(message)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@app.route('/', methods=['GET', 'POST'])&lt;br /&gt;
&lt;br /&gt;
def index():&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    error_message_rpi = None&lt;br /&gt;
    success_message = None&lt;br /&gt;
&lt;br /&gt;
    if request.method == 'POST':&lt;br /&gt;
        pi_id = request.form.get('pi_id')&lt;br /&gt;
        command = request.form.get('command')&lt;br /&gt;
        if pi_id and command in [&amp;quot;start&amp;quot;, &amp;quot;stop&amp;quot;]:&lt;br /&gt;
            success, er_message = send_command_to_pi(pi_id, command)&lt;br /&gt;
            if success:&lt;br /&gt;
                success_message = &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                error_message_rpi = er_message&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    return render_template('index.html', raspberry_ids=list(raspberry_ids), error_message_rpi=error_message_rpi, success_message=success_message, message=latest_message)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    app.run(debug=False, port=8066)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7. Conception de l'Interface Utilisateur ===&lt;br /&gt;
----L'interface utilisateur, développée à l'aide des technologies web standard HTML, CSS, et JavaScript, offre une expérience interactive. Le fichier index.html constitue le point d'entrée de cette interface, proposant des fonctionnalités telles que l'envoi de commandes aux dispositifs Raspberry Pi et la visualisation des données traitées. L'utilisation de JavaScript pour interroger dynamiquement le serveur Flask permet de rafraîchir les informations affichées en temps réel, garantissant ainsi une interface réactive et à jour.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
index.html:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
        body {&lt;br /&gt;
            background-color: #343a40; /* Couleur d'arrière-plan foncé */&lt;br /&gt;
            color: #ced4da; /* Gris clair pour le texte pour un meilleur contraste */&lt;br /&gt;
        }&lt;br /&gt;
        .card {&lt;br /&gt;
            background-color: #495057; /* Fond des encadrés plus sombre */&lt;br /&gt;
        }&lt;br /&gt;
        .card-title, .card-text, .alert {&lt;br /&gt;
            color: #adb5bd; /* Gris plus doux pour les titres, le texte et les alertes */&lt;br /&gt;
        }&lt;br /&gt;
        .btn-primary {&lt;br /&gt;
            background-color: #007bff; /* Bleu Bootstrap par défaut pour les boutons */&lt;br /&gt;
            border-color: #007bff;&lt;br /&gt;
        }&lt;br /&gt;
        .btn-danger {&lt;br /&gt;
            background-color: #dc3545; /* Rouge Bootstrap par défaut pour les boutons d'arrêt */&lt;br /&gt;
            border-color: #dc3545;&lt;br /&gt;
        }&lt;br /&gt;
        .form-control {&lt;br /&gt;
            background-color: #495057; /* Fond des champs de saisie plus sombre */&lt;br /&gt;
            border: 1px solid #6c757d;&lt;br /&gt;
            color: #ced4da; /* Couleur du texte dans les champs de saisie */&lt;br /&gt;
        }&lt;br /&gt;
        a, .btn-secondary {&lt;br /&gt;
            color: #17a2b8; /* Bleu clair pour les liens et les boutons secondaires */&lt;br /&gt;
        }&lt;br /&gt;
        a:hover {&lt;br /&gt;
            color: #138496; &lt;br /&gt;
        }&lt;br /&gt;
        #latest-message {&lt;br /&gt;
            background-color: #596069; &lt;br /&gt;
            border: 1px solid #6c757d; &lt;br /&gt;
            color: #E9ECEF; &lt;br /&gt;
            padding: 10px; &lt;br /&gt;
            border-radius: 5px; &lt;br /&gt;
        }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;container mt-5&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;h1 class=&amp;quot;text-center mb-4&amp;quot;&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/h1&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour les Raspberry Pi Disponibles --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-md-12&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Raspberry Pi Disponibles&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;ul id=&amp;quot;raspberry-list&amp;quot; class=&amp;quot;list-group list-group-flush&amp;quot;&amp;gt;&lt;br /&gt;
                    &lt;br /&gt;
                        &amp;lt;/ul&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour la Collecte des données --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Collecte de données&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;form method=&amp;quot;post&amp;quot; class=&amp;quot;form-inline&amp;quot;&amp;gt;&lt;br /&gt;
                            &amp;lt;input type=&amp;quot;text&amp;quot; class=&amp;quot;form-control mb-2 mr-sm-2&amp;quot; name=&amp;quot;pi_id&amp;quot; placeholder=&amp;quot;Entrez l'ID de la Raspberry Pi&amp;quot; required&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-primary mb-2 mr-sm-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;start&amp;quot;&amp;gt;Démarrer la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-danger mb-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;stop&amp;quot;&amp;gt;Arrêter la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                        &amp;lt;/form&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;!-- Encadré pour le Dernier Message Reçu --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Dernier Message Reçu&amp;lt;/h2&amp;gt;&lt;br /&gt;
                    &amp;lt;div id=&amp;quot;latest-message&amp;quot; class=&amp;quot;alert alert-dark&amp;quot;&amp;gt;&lt;br /&gt;
                        Aucun message reçu pour le moment. &lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;mb-3 text-center&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;a href=&amp;quot;/logs&amp;quot; class=&amp;quot;btn btn-secondary&amp;quot;&amp;gt;Voir les Logs&amp;lt;/a&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        function fetchRaspberryIds() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        var ids = JSON.parse(xhr.responseText);&lt;br /&gt;
                        var list = document.getElementById('raspberry-list');&lt;br /&gt;
                        list.innerHTML = '';&lt;br /&gt;
                        ids.forEach(function(id) {&lt;br /&gt;
                            var li = document.createElement('li');&lt;br /&gt;
                            li.textContent = id;&lt;br /&gt;
                            list.appendChild(li);&lt;br /&gt;
                        });&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-raspberry-ids', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function fetchLatestMessage() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        console.log(xhr.responseText)&lt;br /&gt;
                        document.getElementById('latest-message').textContent = xhr.responseText;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-latest-message', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setInterval(fetchRaspberryIds, 5000); // Met à jour les IDs toutes les 5 secondes&lt;br /&gt;
        setInterval(fetchLatestMessage, 500); // Met à jour le dernier message toutes les secondes&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    {% if error_message_rpi %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ error_message_rpi }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&lt;br /&gt;
    {% if success_message %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ success_message }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On a aussi ajouté une page de logs, qui permet de voir l'historique de tous les données traitées.&lt;br /&gt;
&lt;br /&gt;
=== 9. Conclusion et Perspectives ===&lt;br /&gt;
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont&lt;br /&gt;
&lt;br /&gt;
== Vidéo ==&lt;br /&gt;
Lorsque l'on clique sur &amp;quot;démarrer la collecte&amp;quot; en ayant spécifié un ID, on peut voir en temps réel le résultat dans le cadre Dernier Message Recu.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:RPReplay_Final1706462779.mov|sans_cadre]]&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Capture_d%E2%80%99%C3%A9cran_2024-01-28_%C3%A0_19.07.42.png&amp;diff=4900</id>
		<title>Fichier:Capture d’écran 2024-01-28 à 19.07.42.png</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Capture_d%E2%80%99%C3%A9cran_2024-01-28_%C3%A0_19.07.42.png&amp;diff=4900"/>
		<updated>2024-01-28T18:12:47Z</updated>

		<summary type="html">&lt;p&gt;Bblack : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Capture d’écran 2024-01-28 à 19.07.42&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4897</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4897"/>
		<updated>2024-01-28T17:57:36Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* 7. Conception de l'Interface Utilisateur */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Compte rendu des séances=&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:IfconfigVM.png|sans_cadre]]&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
mettre la config de la raspberry&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== '''Présentation du projet''' ==&lt;br /&gt;
&lt;br /&gt;
=== 1. Introduction ===&lt;br /&gt;
----Le projet SignSpeak a pour ambition de créer une solution innovante pour la traduction du langage des signes en texte. L'objectif principal est de développer un système capable de capturer les mouvements des mains et de les interpréter en langage des signes, permettant une communication fluide entre les personnes sourdes ou malentendantes et celles qui ne connaissent pas le langage des signes. Ce projet intègre des technologies avancées telles que l'edge computing, l'intelligence artificielle embarquée, et les communications MQTT, offrant une approche novatrice dans le domaine de l'accessibilité et de la communication.&lt;br /&gt;
&lt;br /&gt;
=== 2. Architecture du Système ===&lt;br /&gt;
----Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :&lt;br /&gt;
&lt;br /&gt;
* '''Capteurs et STM32''' : Des capteurs sont connectés à un microcontrôleur STM32, responsables de la capture des mouvements de main. Ces données sont ensuite transmises pour traitement.&lt;br /&gt;
* '''Raspberry Pi''' : Agissant comme un intermédiaire, la Raspberry Pi reçoit les données des capteurs via UART, exécute un traitement préliminaire et communique avec le serveur.&lt;br /&gt;
* '''Serveur et Machine Learning''' : Un serveur, hébergé sur une VM Xen, traite les données à l'aide d'un modèle SVM pour la traduction en langage des signes et fournit une interface web pour l'interaction utilisateur.&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== 3. Collecte et Préparation des Données ===&lt;br /&gt;
----Le processus de collecte des données est géré par le script &amp;lt;code&amp;gt;enregistrementData.py&amp;lt;/code&amp;gt;. Ce script lit les données transmises par le STM32 via UART et les enregistre dans un fichier CSV. Chaque entrée du fichier représente les valeurs de capteurs à un moment donné, accompagnées d'une étiquette correspondant au signe effectué. Cette approche assure une collecte de données structurée, essentielle pour l'entraînement précis du modèle d'apprentissage automatique.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
import csv&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
# Vérification de l'argument d'entrée&lt;br /&gt;
if len(sys.argv) &amp;lt; 2:&lt;br /&gt;
    print(&amp;quot;Usage: python script.py &amp;lt;etiquette&amp;gt;&amp;quot;)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
etiquette = sys.argv[1]&lt;br /&gt;
&lt;br /&gt;
# Paramètres de l'UART&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
&lt;br /&gt;
# Créer une connexion UART&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
&lt;br /&gt;
# Nom du fichier CSV&lt;br /&gt;
filename = f&amp;quot;data_complete.csv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Vérifier si le fichier existe déjà&lt;br /&gt;
file_exists = False&lt;br /&gt;
try:&lt;br /&gt;
    with open(filename, 'r') as f:&lt;br /&gt;
        file_exists = True&lt;br /&gt;
except FileNotFoundError:&lt;br /&gt;
    file_exists = False&lt;br /&gt;
&lt;br /&gt;
# Ouvrir le fichier CSV en mode append&lt;br /&gt;
with open(filename, 'a', newline='') as file:&lt;br /&gt;
    writer = csv.writer(file)&lt;br /&gt;
&lt;br /&gt;
    # Écrire l'en-tête si le fichier n'existait pas&lt;br /&gt;
    if not file_exists:&lt;br /&gt;
        writer.writerow([&amp;quot;Capteur1&amp;quot;, &amp;quot;Capteur2&amp;quot;, &amp;quot;Capteur3&amp;quot;, &amp;quot;Capteur4&amp;quot;, &amp;quot;Capteur5&amp;quot;, &amp;quot;Capteur6&amp;quot;, &amp;quot;Capteur7&amp;quot;, &amp;quot;Capteur8&amp;quot;, &amp;quot;Capteur9&amp;quot;, &amp;quot;Capteur10&amp;quot;, &amp;quot;Capteur11&amp;quot;, &amp;quot;Capteur12&amp;quot;, &amp;quot;Capteur13&amp;quot;, &amp;quot;Capteur14&amp;quot;, &lt;br /&gt;
&amp;quot;Capteur15&amp;quot;, &amp;quot;Capteur16&amp;quot;, &amp;quot;Etiquette&amp;quot;])&lt;br /&gt;
    elif file_exists:&lt;br /&gt;
        writer.writerow([])&lt;br /&gt;
    while True:&lt;br /&gt;
        # Lire une ligne de données depuis l'UART&lt;br /&gt;
        data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
        print(f&amp;quot;Données reçues : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Vérifier si des données ont été reçues&lt;br /&gt;
        if data:&lt;br /&gt;
            # Diviser les données en valeurs individuelles&lt;br /&gt;
            sensor_values = data.split(',')&lt;br /&gt;
&lt;br /&gt;
            # Filtrer les chaînes vides ou non numériques et convertir en flottants&lt;br /&gt;
            try:&lt;br /&gt;
                sensor_values = [float(value) for value in sensor_values if value.strip().isdigit()]&lt;br /&gt;
&lt;br /&gt;
                # Vérifier qu'il y a 16 valeurs de capteur&lt;br /&gt;
                if len(sensor_values) == 16:&lt;br /&gt;
                    sensor_values.append(etiquette)&lt;br /&gt;
                    writer.writerow(sensor_values)&lt;br /&gt;
                else:&lt;br /&gt;
                    print(&amp;quot;Données incomplètes reçues&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            except ValueError as e:&lt;br /&gt;
                print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
                print(f&amp;quot;Données problématiques : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Le script commence par établir une communication série avec le STM32.&lt;br /&gt;
* Il lit ensuite les données en série, les décode et les stocke dans un fichier CSV pour une utilisation ultérieure.&lt;br /&gt;
&lt;br /&gt;
* Une fois les données collectées et stockées dans le fichier CSV, elles sont préparées pour l'entraînement du modèle.&lt;br /&gt;
* Cette préparation implique la normalisation des données, la gestion des valeurs manquantes ou aberrantes, et leur formatage dans un bon format.[[Fichier:Rpi entrainement.png|vignette|1000x1000px|néant]]&lt;br /&gt;
=== 4. Entraînement du Modèle d'Apprentissage Automatique ===&lt;br /&gt;
----L'entraînement du modèle est réalisé par un script Python utilisant la bibliothèque scikit-learn. Le modèle SVM, choisi pour sa capacité à gérer des espaces de grande dimension, est entraîné sur l'ensemble des données collectées. Ce processus comprend la division des données en ensembles d'entraînement et de test, l'entraînement du modèle, et sa validation par le calcul de la précision. Nous avions testé plusieurs modèle, comme par exemple un modèle Knn ou randomForest, des 3 algorithmes, c'est celui qui nous à apporté les meilleurs résultats pour un meme nombre de data d'entrainement. (RandomForest en deuxième position)&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import pandas as pd&lt;br /&gt;
from sklearn.model_selection import train_test_split&lt;br /&gt;
from sklearn.svm import SVC&lt;br /&gt;
from sklearn.metrics import accuracy_score&lt;br /&gt;
import pickle&lt;br /&gt;
&lt;br /&gt;
# Charger vos données&lt;br /&gt;
data = pd.read_csv('data_complete.csv')&lt;br /&gt;
&lt;br /&gt;
# Séparer les caractéristiques et les étiquettes&lt;br /&gt;
X = data.drop('Etiquette', axis=1)&lt;br /&gt;
y = data['Etiquette']&lt;br /&gt;
&lt;br /&gt;
# Diviser les données en ensembles d'entraînement et de test&lt;br /&gt;
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)&lt;br /&gt;
&lt;br /&gt;
# Créer et entraîner le modèle SVM&lt;br /&gt;
model = SVC(kernel='rbf')&lt;br /&gt;
model.fit(X_train, y_train)&lt;br /&gt;
&lt;br /&gt;
# Sauvegarder le modèle entraîné&lt;br /&gt;
with open('modele_svm.pkl', 'wb') as file:&lt;br /&gt;
    pickle.dump(model, file)&lt;br /&gt;
&lt;br /&gt;
# Charger le modèle et faire des prédictions&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    loaded_model = pickle.load(file)&lt;br /&gt;
    predictions = loaded_model.predict(X_test)&lt;br /&gt;
    print(&amp;quot;Précision :&amp;quot;, accuracy_score(y_test, predictions))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# '''Séparation des Données''':&lt;br /&gt;
#* Les données sont divisées en deux ensembles : un ensemble d'entraînement et un ensemble de test. Cette séparation est cruciale pour évaluer objectivement la performance du modèle.&lt;br /&gt;
#* Généralement, on adopte une répartition de 80% pour l'entraînement et 20% pour les tests.&lt;br /&gt;
# '''Entraînement du Modèle SVM''':&lt;br /&gt;
#* Le modèle SVM avec un noyau RBF (Radial Basis Function) est entraîné sur l'ensemble d'entraînement.&lt;br /&gt;
#* L'entraînement implique l'ajustement du modèle aux données d'entraînement, en apprenant à distinguer les différents signes.&lt;br /&gt;
# '''Sauvegarde et Réutilisation du Modèle'''&lt;br /&gt;
#* Une fois entraîné et validé, le modèle est sauvegardé à l'aide de la bibliothèque &amp;lt;code&amp;gt;pickle&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Validation et Évaluation du Modèle''':&lt;br /&gt;
#* Après l'entraînement, le modèle est testé sur l'ensemble de test pour évaluer sa performance.&lt;br /&gt;
#* La métrique principale utilisée est la précision, qui mesure la proportion de prédictions correctes par rapport au total des prédictions.&lt;br /&gt;
&lt;br /&gt;
Ensuite on peut générer le modèle comme ceci:&lt;br /&gt;
[[Fichier:Generate model.png|vignette|399x399px|néant]]&lt;br /&gt;
&lt;br /&gt;
Avec cette prédiction lorsque notre modèle prédit le résultat, il est correct environ 71.81% du temps.&lt;br /&gt;
&lt;br /&gt;
=== 5. Intégration MQTT et Communication ===&lt;br /&gt;
----Protocole de communication  :&lt;br /&gt;
&lt;br /&gt;
Dans le cadre de notre projet, la communication entre les dispositifs Raspberry Pi et le serveur  est établie via le protocole MQTT.&lt;br /&gt;
&lt;br /&gt;
Justification du Choix de MQTT :&lt;br /&gt;
&lt;br /&gt;
Au début du projet, une approche basée sur des sockets IPv6 avait été envisagée pour tirer parti de l'adressage direct et de la simplification de la configuration réseau qu'offre IPv6. Cependant, dans le but de respecter les impératifs de sobriété énergétique et d'assurer une scalabilité optimale du système, permettant ainsi de gérer aisément un nombre croissant de dispositifs Raspberry Pi, la décision a été prise d'adopter MQTT comme protocole de communication. Le protocole MQTT, reconnu pour sa légèreté et sa fiabilité, s'adapte parfaitement aux contraintes des applications IoT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Installation du broker mosquitto sur le serveur:'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
apt install -y mosquitto mosquitto-clients&lt;br /&gt;
service mosquitto start&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Activation de l'accès à distance au Broker Mosquitto:&lt;br /&gt;
&lt;br /&gt;
ajouter l'authentification par username et mot de passe&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
sudo mosquitto_passwd -c /etc/mosquitto/passwd username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
après on nous demande d'entrer le mot de passe &lt;br /&gt;
&lt;br /&gt;
Modifier le fichier /etc/mosquitto/mosquitto.conf:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
listener 1883 10.42.0.5&lt;br /&gt;
allow_anonymous false&lt;br /&gt;
password_file /etc/mosquitto/passwd&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Mosquitto:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
service mosquitto restart&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vérification ds logs:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
cat /var/log/mosquitto/mosquitto.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Création d'un client MQTT sur la Raspberry Pi:'''&lt;br /&gt;
&lt;br /&gt;
Le script mqtt_client_rpi.py joue un rôle clé dans cette architecture en facilitant la communication bidirectionnelle : il permet non seulement l'envoi des prédictions réalisées par le modèle SVM depuis la Raspberry Pi vers le serveur, mais autorise également la réception des commandes de contrôle, telles que les instructions de démarrage ou d'arrêt de la collecte de données.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import serial&lt;br /&gt;
import pandas as pd&lt;br /&gt;
import pickle&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
pi_id = &amp;quot;rpi1234&amp;quot;&lt;br /&gt;
&lt;br /&gt;
collecting_data = False &lt;br /&gt;
&lt;br /&gt;
client = mqtt.Client()&lt;br /&gt;
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)&lt;br /&gt;
client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
client.loop_start()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(f&amp;quot;config/{pi_id}&amp;quot;)&lt;br /&gt;
    client.publish(&amp;quot;raspberry_available&amp;quot;, pi_id)&lt;br /&gt;
&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global collecting_data&lt;br /&gt;
    if msg.topic == f&amp;quot;config/{pi_id}&amp;quot;:&lt;br /&gt;
        command = msg.payload.decode()&lt;br /&gt;
        if command == &amp;quot;start&amp;quot;:&lt;br /&gt;
            collecting_data = True&lt;br /&gt;
        elif command == &amp;quot;stop&amp;quot;:&lt;br /&gt;
            collecting_data = False&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.on_connect = on_connect&lt;br /&gt;
client.on_message = on_message&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Configurez le port série et chargez le modèle ici&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    rf = pickle.load(file)&lt;br /&gt;
try:&lt;br /&gt;
&lt;br /&gt;
    while True:&lt;br /&gt;
        if collecting_data:&lt;br /&gt;
            data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
            if data:&lt;br /&gt;
                try:&lt;br /&gt;
                    sensor_values = [value for value in data.split(',') if value.strip().replace('.', '', 1).isdigit()]&lt;br /&gt;
                    if len(sensor_values) == 16:&lt;br /&gt;
                        sensor_values = list(map(float, sensor_values))&lt;br /&gt;
                        sensor_values_df = pd.DataFrame([sensor_values])&lt;br /&gt;
                        prediction = rf.predict(sensor_values_df)&lt;br /&gt;
                        client.publish(f&amp;quot;telemetry/{pi_id}&amp;quot;, str(prediction[0]).encode())&lt;br /&gt;
                        print(&amp;quot;Prédiction :&amp;quot;, prediction[0])&lt;br /&gt;
                except ValueError as e:&lt;br /&gt;
                    print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:&lt;br /&gt;
    print(&amp;quot;Script interrompu&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.loop_stop()&lt;br /&gt;
client.disconnect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Ici il y a 3 topics différents. lorsqu'une raspberry se connecte au réseau elle publie son ID (qui est unique, on peut prendre par exemple l'adresse MAC) sur le topic raspberry_available. Cela nous servira a savoir quelle raspberry est connecté et de se fait pouvoir afficher celles-ci sur notre interface web.&lt;br /&gt;
&lt;br /&gt;
le deuxième topic et le topic config/ID (avec id l'identifiant unique de la raspberry), il nous sert a envoyer les commandes &amp;quot;start&amp;quot; et &amp;quot;stop&amp;quot; a la raspberry afin qu'elle démarre ou arrête la lecture des datas.&lt;br /&gt;
&lt;br /&gt;
Le troisième topic est le topic telemetry/ID, ou la raspberry vient publier ses données.&lt;br /&gt;
&lt;br /&gt;
Un quatrième topic pourrait être implémenter comme par exemple le topic common_config, toutes les raspberrys serait abonnées a ce topic. S'il est nécessaire, cela nous permettrais d'envoyer la même commande a toutes les raspberry  plutôt que de faire une publication sur chaque config/ID &lt;br /&gt;
&lt;br /&gt;
=== 6. Interface Serveur et Gestion des Données ===&lt;br /&gt;
----Le serveur central, au cœur de notre système, est orchestré par le script &amp;lt;code&amp;gt;app.py&amp;lt;/code&amp;gt; qui exploite le framework Flask pour mettre en place une interface serveur. Cette interface est conçue pour traiter efficacement les requêtes HTTP et les messages MQTT, offrant ainsi une API réactive pour l'interface utilisateur web. Elle permet également de visualiser en temps réel l'état des dispositifs Raspberry Pi connectés et les dernières données traitées.&lt;br /&gt;
[[Fichier:Signspeakweb.png|centré|vignette|1000x1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from flask import Flask, render_template, request, jsonify&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import queue&lt;br /&gt;
&lt;br /&gt;
app = Flask(__name__)&lt;br /&gt;
messages = []&lt;br /&gt;
received_messages = queue.Queue()&lt;br /&gt;
latest_message = None&lt;br /&gt;
subscribed_topics = set()&lt;br /&gt;
raspberry_ids = set()&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client = mqtt.Client()&lt;br /&gt;
mqtt_client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD) &lt;br /&gt;
mqtt_client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
mqtt_client.loop_start()&lt;br /&gt;
&lt;br /&gt;
def send_command_to_pi(pi_id, command):&lt;br /&gt;
    try:&lt;br /&gt;
        topic = f&amp;quot;config/{pi_id}&amp;quot;&lt;br /&gt;
        mqtt_client.publish(topic, command)&lt;br /&gt;
        subscribe_to_pi_telemetry(pi_id)&lt;br /&gt;
        return True, &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
    except Exception as e:&lt;br /&gt;
        return False, f&amp;quot;Commande pas envoyée: Erreur MQTT : {e}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
def subscribe_to_pi_telemetry(pi_id):&lt;br /&gt;
    global subscribed_topics&lt;br /&gt;
    topic = f&amp;quot;telemetry/{pi_id}&amp;quot;&lt;br /&gt;
    if topic not in subscribed_topics:&lt;br /&gt;
        mqtt_client.subscribe(topic)&lt;br /&gt;
        subscribed_topics.add(topic)&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(&amp;quot;raspberry_available&amp;quot;)&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    print(f&amp;quot;Received message on topic {msg.topic}: {msg.payload.decode()}&amp;quot;)  # Ajouter pour le débogage&lt;br /&gt;
    if msg.topic == &amp;quot;raspberry_available&amp;quot;:&lt;br /&gt;
        raspberry_ids.add(msg.payload.decode())&lt;br /&gt;
    else:&lt;br /&gt;
        received_messages.put(msg.payload.decode())&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client.on_connect = on_connect&lt;br /&gt;
mqtt_client.on_message = on_message&lt;br /&gt;
@app.route('/get-raspberry-ids')&lt;br /&gt;
def get_raspberry_ids():&lt;br /&gt;
    return jsonify(list(raspberry_ids))&lt;br /&gt;
@app.route('/get-latest-message')&lt;br /&gt;
def get_latest_message():&lt;br /&gt;
    global latest_message&lt;br /&gt;
    while not received_messages.empty():&lt;br /&gt;
        messages.append(received_messages.get())&lt;br /&gt;
&lt;br /&gt;
    latest_message = messages[-1] if messages else None&lt;br /&gt;
    &lt;br /&gt;
    # Ajoutez cet enregistrement de débogage&lt;br /&gt;
    print(f&amp;quot;Contenu de la réponse pour /get-latest-message : {latest_message}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    if latest_message is not None:&lt;br /&gt;
         response = jsonify({&amp;quot;message&amp;quot;: latest_message})&lt;br /&gt;
         return response&lt;br /&gt;
    else:&lt;br /&gt;
        message = &amp;quot;Aucun signe a traduire pour le moment&amp;quot;&lt;br /&gt;
        return jsonify(message)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@app.route('/', methods=['GET', 'POST'])&lt;br /&gt;
&lt;br /&gt;
def index():&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    error_message_rpi = None&lt;br /&gt;
    success_message = None&lt;br /&gt;
&lt;br /&gt;
    if request.method == 'POST':&lt;br /&gt;
        pi_id = request.form.get('pi_id')&lt;br /&gt;
        command = request.form.get('command')&lt;br /&gt;
        if pi_id and command in [&amp;quot;start&amp;quot;, &amp;quot;stop&amp;quot;]:&lt;br /&gt;
            success, er_message = send_command_to_pi(pi_id, command)&lt;br /&gt;
            if success:&lt;br /&gt;
                success_message = &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                error_message_rpi = er_message&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    return render_template('index.html', raspberry_ids=list(raspberry_ids), error_message_rpi=error_message_rpi, success_message=success_message, message=latest_message)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    app.run(debug=False, port=8066)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7. Conception de l'Interface Utilisateur ===&lt;br /&gt;
----L'interface utilisateur, développée à l'aide des technologies web standard HTML, CSS, et JavaScript, offre une expérience interactive. Le fichier index.html constitue le point d'entrée de cette interface, proposant des fonctionnalités telles que l'envoi de commandes aux dispositifs Raspberry Pi et la visualisation des données traitées. L'utilisation de JavaScript pour interroger dynamiquement le serveur Flask permet de rafraîchir les informations affichées en temps réel, garantissant ainsi une interface réactive et à jour.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
index.html:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
        body {&lt;br /&gt;
            background-color: #343a40; /* Couleur d'arrière-plan foncé */&lt;br /&gt;
            color: #ced4da; /* Gris clair pour le texte pour un meilleur contraste */&lt;br /&gt;
        }&lt;br /&gt;
        .card {&lt;br /&gt;
            background-color: #495057; /* Fond des encadrés plus sombre */&lt;br /&gt;
        }&lt;br /&gt;
        .card-title, .card-text, .alert {&lt;br /&gt;
            color: #adb5bd; /* Gris plus doux pour les titres, le texte et les alertes */&lt;br /&gt;
        }&lt;br /&gt;
        .btn-primary {&lt;br /&gt;
            background-color: #007bff; /* Bleu Bootstrap par défaut pour les boutons */&lt;br /&gt;
            border-color: #007bff;&lt;br /&gt;
        }&lt;br /&gt;
        .btn-danger {&lt;br /&gt;
            background-color: #dc3545; /* Rouge Bootstrap par défaut pour les boutons d'arrêt */&lt;br /&gt;
            border-color: #dc3545;&lt;br /&gt;
        }&lt;br /&gt;
        .form-control {&lt;br /&gt;
            background-color: #495057; /* Fond des champs de saisie plus sombre */&lt;br /&gt;
            border: 1px solid #6c757d;&lt;br /&gt;
            color: #ced4da; /* Couleur du texte dans les champs de saisie */&lt;br /&gt;
        }&lt;br /&gt;
        a, .btn-secondary {&lt;br /&gt;
            color: #17a2b8; /* Bleu clair pour les liens et les boutons secondaires */&lt;br /&gt;
        }&lt;br /&gt;
        a:hover {&lt;br /&gt;
            color: #138496; &lt;br /&gt;
        }&lt;br /&gt;
        #latest-message {&lt;br /&gt;
            background-color: #596069; &lt;br /&gt;
            border: 1px solid #6c757d; &lt;br /&gt;
            color: #E9ECEF; &lt;br /&gt;
            padding: 10px; &lt;br /&gt;
            border-radius: 5px; &lt;br /&gt;
        }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;container mt-5&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;h1 class=&amp;quot;text-center mb-4&amp;quot;&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/h1&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour les Raspberry Pi Disponibles --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-md-12&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Raspberry Pi Disponibles&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;ul id=&amp;quot;raspberry-list&amp;quot; class=&amp;quot;list-group list-group-flush&amp;quot;&amp;gt;&lt;br /&gt;
                    &lt;br /&gt;
                        &amp;lt;/ul&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour la Collecte des données --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Collecte de données&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;form method=&amp;quot;post&amp;quot; class=&amp;quot;form-inline&amp;quot;&amp;gt;&lt;br /&gt;
                            &amp;lt;input type=&amp;quot;text&amp;quot; class=&amp;quot;form-control mb-2 mr-sm-2&amp;quot; name=&amp;quot;pi_id&amp;quot; placeholder=&amp;quot;Entrez l'ID de la Raspberry Pi&amp;quot; required&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-primary mb-2 mr-sm-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;start&amp;quot;&amp;gt;Démarrer la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-danger mb-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;stop&amp;quot;&amp;gt;Arrêter la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                        &amp;lt;/form&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;!-- Encadré pour le Dernier Message Reçu --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Dernier Message Reçu&amp;lt;/h2&amp;gt;&lt;br /&gt;
                    &amp;lt;div id=&amp;quot;latest-message&amp;quot; class=&amp;quot;alert alert-dark&amp;quot;&amp;gt;&lt;br /&gt;
                        Aucun message reçu pour le moment. &lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;mb-3 text-center&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;a href=&amp;quot;/logs&amp;quot; class=&amp;quot;btn btn-secondary&amp;quot;&amp;gt;Voir les Logs&amp;lt;/a&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        function fetchRaspberryIds() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        var ids = JSON.parse(xhr.responseText);&lt;br /&gt;
                        var list = document.getElementById('raspberry-list');&lt;br /&gt;
                        list.innerHTML = '';&lt;br /&gt;
                        ids.forEach(function(id) {&lt;br /&gt;
                            var li = document.createElement('li');&lt;br /&gt;
                            li.textContent = id;&lt;br /&gt;
                            list.appendChild(li);&lt;br /&gt;
                        });&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-raspberry-ids', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function fetchLatestMessage() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        console.log(xhr.responseText)&lt;br /&gt;
                        document.getElementById('latest-message').textContent = xhr.responseText;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-latest-message', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setInterval(fetchRaspberryIds, 5000); // Met à jour les IDs toutes les 5 secondes&lt;br /&gt;
        setInterval(fetchLatestMessage, 500); // Met à jour le dernier message toutes les secondes&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    {% if error_message_rpi %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ error_message_rpi }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&lt;br /&gt;
    {% if success_message %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ success_message }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On a aussi ajouté une page de logs, qui permet de voir l'historique de tous les données traitées.&lt;br /&gt;
&lt;br /&gt;
=== 9. Conclusion et Perspectives ===&lt;br /&gt;
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont&lt;br /&gt;
&lt;br /&gt;
== Vidéo ==&lt;br /&gt;
Lorsque l'on clique sur &amp;quot;démarrer la collecte&amp;quot; en ayant spécifié un ID, on peut voir en temps réel le résultat dans le cadre Dernier Message Recu.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:RPReplay_Final1706462779.mov|sans_cadre]]&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4890</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4890"/>
		<updated>2024-01-28T17:42:56Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* Vidéo */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Compte rendu des séances=&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:IfconfigVM.png|sans_cadre]]&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
mettre la config de la raspberry&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== '''Présentation du projet''' ==&lt;br /&gt;
&lt;br /&gt;
=== 1. Introduction ===&lt;br /&gt;
----Le projet SignSpeak a pour ambition de créer une solution innovante pour la traduction du langage des signes en texte. L'objectif principal est de développer un système capable de capturer les mouvements des mains et de les interpréter en langage des signes, permettant une communication fluide entre les personnes sourdes ou malentendantes et celles qui ne connaissent pas le langage des signes. Ce projet intègre des technologies avancées telles que l'edge computing, l'intelligence artificielle embarquée, et les communications MQTT, offrant une approche novatrice dans le domaine de l'accessibilité et de la communication.&lt;br /&gt;
&lt;br /&gt;
=== 2. Architecture du Système ===&lt;br /&gt;
----Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :&lt;br /&gt;
&lt;br /&gt;
* '''Capteurs et STM32''' : Des capteurs sont connectés à un microcontrôleur STM32, responsables de la capture des mouvements de main. Ces données sont ensuite transmises pour traitement.&lt;br /&gt;
* '''Raspberry Pi''' : Agissant comme un intermédiaire, la Raspberry Pi reçoit les données des capteurs via UART, exécute un traitement préliminaire et communique avec le serveur.&lt;br /&gt;
* '''Serveur et Machine Learning''' : Un serveur, hébergé sur une VM Xen, traite les données à l'aide d'un modèle SVM pour la traduction en langage des signes et fournit une interface web pour l'interaction utilisateur.&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== 3. Collecte et Préparation des Données ===&lt;br /&gt;
----Le processus de collecte des données est géré par le script &amp;lt;code&amp;gt;enregistrementData.py&amp;lt;/code&amp;gt;. Ce script lit les données transmises par le STM32 via UART et les enregistre dans un fichier CSV. Chaque entrée du fichier représente les valeurs de capteurs à un moment donné, accompagnées d'une étiquette correspondant au signe effectué. Cette approche assure une collecte de données structurée, essentielle pour l'entraînement précis du modèle d'apprentissage automatique.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
import csv&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
# Vérification de l'argument d'entrée&lt;br /&gt;
if len(sys.argv) &amp;lt; 2:&lt;br /&gt;
    print(&amp;quot;Usage: python script.py &amp;lt;etiquette&amp;gt;&amp;quot;)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
etiquette = sys.argv[1]&lt;br /&gt;
&lt;br /&gt;
# Paramètres de l'UART&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
&lt;br /&gt;
# Créer une connexion UART&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
&lt;br /&gt;
# Nom du fichier CSV&lt;br /&gt;
filename = f&amp;quot;data_complete.csv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Vérifier si le fichier existe déjà&lt;br /&gt;
file_exists = False&lt;br /&gt;
try:&lt;br /&gt;
    with open(filename, 'r') as f:&lt;br /&gt;
        file_exists = True&lt;br /&gt;
except FileNotFoundError:&lt;br /&gt;
    file_exists = False&lt;br /&gt;
&lt;br /&gt;
# Ouvrir le fichier CSV en mode append&lt;br /&gt;
with open(filename, 'a', newline='') as file:&lt;br /&gt;
    writer = csv.writer(file)&lt;br /&gt;
&lt;br /&gt;
    # Écrire l'en-tête si le fichier n'existait pas&lt;br /&gt;
    if not file_exists:&lt;br /&gt;
        writer.writerow([&amp;quot;Capteur1&amp;quot;, &amp;quot;Capteur2&amp;quot;, &amp;quot;Capteur3&amp;quot;, &amp;quot;Capteur4&amp;quot;, &amp;quot;Capteur5&amp;quot;, &amp;quot;Capteur6&amp;quot;, &amp;quot;Capteur7&amp;quot;, &amp;quot;Capteur8&amp;quot;, &amp;quot;Capteur9&amp;quot;, &amp;quot;Capteur10&amp;quot;, &amp;quot;Capteur11&amp;quot;, &amp;quot;Capteur12&amp;quot;, &amp;quot;Capteur13&amp;quot;, &amp;quot;Capteur14&amp;quot;, &lt;br /&gt;
&amp;quot;Capteur15&amp;quot;, &amp;quot;Capteur16&amp;quot;, &amp;quot;Etiquette&amp;quot;])&lt;br /&gt;
    elif file_exists:&lt;br /&gt;
        writer.writerow([])&lt;br /&gt;
    while True:&lt;br /&gt;
        # Lire une ligne de données depuis l'UART&lt;br /&gt;
        data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
        print(f&amp;quot;Données reçues : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Vérifier si des données ont été reçues&lt;br /&gt;
        if data:&lt;br /&gt;
            # Diviser les données en valeurs individuelles&lt;br /&gt;
            sensor_values = data.split(',')&lt;br /&gt;
&lt;br /&gt;
            # Filtrer les chaînes vides ou non numériques et convertir en flottants&lt;br /&gt;
            try:&lt;br /&gt;
                sensor_values = [float(value) for value in sensor_values if value.strip().isdigit()]&lt;br /&gt;
&lt;br /&gt;
                # Vérifier qu'il y a 16 valeurs de capteur&lt;br /&gt;
                if len(sensor_values) == 16:&lt;br /&gt;
                    sensor_values.append(etiquette)&lt;br /&gt;
                    writer.writerow(sensor_values)&lt;br /&gt;
                else:&lt;br /&gt;
                    print(&amp;quot;Données incomplètes reçues&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            except ValueError as e:&lt;br /&gt;
                print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
                print(f&amp;quot;Données problématiques : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Le script commence par établir une communication série avec le STM32.&lt;br /&gt;
* Il lit ensuite les données en série, les décode et les stocke dans un fichier CSV pour une utilisation ultérieure.&lt;br /&gt;
&lt;br /&gt;
* Une fois les données collectées et stockées dans le fichier CSV, elles sont préparées pour l'entraînement du modèle.&lt;br /&gt;
* Cette préparation implique la normalisation des données, la gestion des valeurs manquantes ou aberrantes, et leur formatage dans un bon format.[[Fichier:Rpi entrainement.png|vignette|1000x1000px|néant]]&lt;br /&gt;
=== 4. Entraînement du Modèle d'Apprentissage Automatique ===&lt;br /&gt;
----L'entraînement du modèle est réalisé par un script Python utilisant la bibliothèque scikit-learn. Le modèle SVM, choisi pour sa capacité à gérer des espaces de grande dimension, est entraîné sur l'ensemble des données collectées. Ce processus comprend la division des données en ensembles d'entraînement et de test, l'entraînement du modèle, et sa validation par le calcul de la précision. Nous avions testé plusieurs modèle, comme par exemple un modèle Knn ou randomForest, des 3 algorithmes, c'est celui qui nous à apporté les meilleurs résultats pour un meme nombre de data d'entrainement. (RandomForest en deuxième position)&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import pandas as pd&lt;br /&gt;
from sklearn.model_selection import train_test_split&lt;br /&gt;
from sklearn.svm import SVC&lt;br /&gt;
from sklearn.metrics import accuracy_score&lt;br /&gt;
import pickle&lt;br /&gt;
&lt;br /&gt;
# Charger vos données&lt;br /&gt;
data = pd.read_csv('data_complete.csv')&lt;br /&gt;
&lt;br /&gt;
# Séparer les caractéristiques et les étiquettes&lt;br /&gt;
X = data.drop('Etiquette', axis=1)&lt;br /&gt;
y = data['Etiquette']&lt;br /&gt;
&lt;br /&gt;
# Diviser les données en ensembles d'entraînement et de test&lt;br /&gt;
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)&lt;br /&gt;
&lt;br /&gt;
# Créer et entraîner le modèle SVM&lt;br /&gt;
model = SVC(kernel='rbf')&lt;br /&gt;
model.fit(X_train, y_train)&lt;br /&gt;
&lt;br /&gt;
# Sauvegarder le modèle entraîné&lt;br /&gt;
with open('modele_svm.pkl', 'wb') as file:&lt;br /&gt;
    pickle.dump(model, file)&lt;br /&gt;
&lt;br /&gt;
# Charger le modèle et faire des prédictions&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    loaded_model = pickle.load(file)&lt;br /&gt;
    predictions = loaded_model.predict(X_test)&lt;br /&gt;
    print(&amp;quot;Précision :&amp;quot;, accuracy_score(y_test, predictions))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# '''Séparation des Données''':&lt;br /&gt;
#* Les données sont divisées en deux ensembles : un ensemble d'entraînement et un ensemble de test. Cette séparation est cruciale pour évaluer objectivement la performance du modèle.&lt;br /&gt;
#* Généralement, on adopte une répartition de 80% pour l'entraînement et 20% pour les tests.&lt;br /&gt;
# '''Entraînement du Modèle SVM''':&lt;br /&gt;
#* Le modèle SVM avec un noyau RBF (Radial Basis Function) est entraîné sur l'ensemble d'entraînement.&lt;br /&gt;
#* L'entraînement implique l'ajustement du modèle aux données d'entraînement, en apprenant à distinguer les différents signes.&lt;br /&gt;
# '''Sauvegarde et Réutilisation du Modèle'''&lt;br /&gt;
#* Une fois entraîné et validé, le modèle est sauvegardé à l'aide de la bibliothèque &amp;lt;code&amp;gt;pickle&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Validation et Évaluation du Modèle''':&lt;br /&gt;
#* Après l'entraînement, le modèle est testé sur l'ensemble de test pour évaluer sa performance.&lt;br /&gt;
#* La métrique principale utilisée est la précision, qui mesure la proportion de prédictions correctes par rapport au total des prédictions.&lt;br /&gt;
&lt;br /&gt;
Ensuite on peut générer le modèle comme ceci:&lt;br /&gt;
[[Fichier:Generate model.png|vignette|399x399px|néant]]&lt;br /&gt;
&lt;br /&gt;
Avec cette prédiction lorsque notre modèle prédit le résultat, il est correct environ 71.81% du temps.&lt;br /&gt;
&lt;br /&gt;
=== 5. Intégration MQTT et Communication ===&lt;br /&gt;
----Protocole de communication  :&lt;br /&gt;
&lt;br /&gt;
Dans le cadre de notre projet, la communication entre les dispositifs Raspberry Pi et le serveur  est établie via le protocole MQTT.&lt;br /&gt;
&lt;br /&gt;
Justification du Choix de MQTT :&lt;br /&gt;
&lt;br /&gt;
Au début du projet, une approche basée sur des sockets IPv6 avait été envisagée pour tirer parti de l'adressage direct et de la simplification de la configuration réseau qu'offre IPv6. Cependant, dans le but de respecter les impératifs de sobriété énergétique et d'assurer une scalabilité optimale du système, permettant ainsi de gérer aisément un nombre croissant de dispositifs Raspberry Pi, la décision a été prise d'adopter MQTT comme protocole de communication. Le protocole MQTT, reconnu pour sa légèreté et sa fiabilité, s'adapte parfaitement aux contraintes des applications IoT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Installation du broker mosquitto sur le serveur:'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
apt install -y mosquitto mosquitto-clients&lt;br /&gt;
service mosquitto start&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Activation de l'accès à distance au Broker Mosquitto:&lt;br /&gt;
&lt;br /&gt;
ajouter l'authentification par username et mot de passe&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
sudo mosquitto_passwd -c /etc/mosquitto/passwd username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
après on nous demande d'entrer le mot de passe &lt;br /&gt;
&lt;br /&gt;
Modifier le fichier /etc/mosquitto/mosquitto.conf:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
listener 1883 10.42.0.5&lt;br /&gt;
allow_anonymous false&lt;br /&gt;
password_file /etc/mosquitto/passwd&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Mosquitto:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
service mosquitto restart&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vérification ds logs:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
cat /var/log/mosquitto/mosquitto.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Création d'un client MQTT sur la Raspberry Pi:'''&lt;br /&gt;
&lt;br /&gt;
Le script mqtt_client_rpi.py joue un rôle clé dans cette architecture en facilitant la communication bidirectionnelle : il permet non seulement l'envoi des prédictions réalisées par le modèle SVM depuis la Raspberry Pi vers le serveur, mais autorise également la réception des commandes de contrôle, telles que les instructions de démarrage ou d'arrêt de la collecte de données.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import serial&lt;br /&gt;
import pandas as pd&lt;br /&gt;
import pickle&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
pi_id = &amp;quot;rpi1234&amp;quot;&lt;br /&gt;
&lt;br /&gt;
collecting_data = False &lt;br /&gt;
&lt;br /&gt;
client = mqtt.Client()&lt;br /&gt;
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)&lt;br /&gt;
client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
client.loop_start()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(f&amp;quot;config/{pi_id}&amp;quot;)&lt;br /&gt;
    client.publish(&amp;quot;raspberry_available&amp;quot;, pi_id)&lt;br /&gt;
&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global collecting_data&lt;br /&gt;
    if msg.topic == f&amp;quot;config/{pi_id}&amp;quot;:&lt;br /&gt;
        command = msg.payload.decode()&lt;br /&gt;
        if command == &amp;quot;start&amp;quot;:&lt;br /&gt;
            collecting_data = True&lt;br /&gt;
        elif command == &amp;quot;stop&amp;quot;:&lt;br /&gt;
            collecting_data = False&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.on_connect = on_connect&lt;br /&gt;
client.on_message = on_message&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Configurez le port série et chargez le modèle ici&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    rf = pickle.load(file)&lt;br /&gt;
try:&lt;br /&gt;
&lt;br /&gt;
    while True:&lt;br /&gt;
        if collecting_data:&lt;br /&gt;
            data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
            if data:&lt;br /&gt;
                try:&lt;br /&gt;
                    sensor_values = [value for value in data.split(',') if value.strip().replace('.', '', 1).isdigit()]&lt;br /&gt;
                    if len(sensor_values) == 16:&lt;br /&gt;
                        sensor_values = list(map(float, sensor_values))&lt;br /&gt;
                        sensor_values_df = pd.DataFrame([sensor_values])&lt;br /&gt;
                        prediction = rf.predict(sensor_values_df)&lt;br /&gt;
                        client.publish(f&amp;quot;telemetry/{pi_id}&amp;quot;, str(prediction[0]).encode())&lt;br /&gt;
                        print(&amp;quot;Prédiction :&amp;quot;, prediction[0])&lt;br /&gt;
                except ValueError as e:&lt;br /&gt;
                    print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:&lt;br /&gt;
    print(&amp;quot;Script interrompu&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.loop_stop()&lt;br /&gt;
client.disconnect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Ici il y a 3 topics différents. lorsqu'une raspberry se connecte au réseau elle publie son ID (qui est unique, on peut prendre par exemple l'adresse MAC) sur le topic raspberry_available. Cela nous servira a savoir quelle raspberry est connecté et de se fait pouvoir afficher celles-ci sur notre interface web.&lt;br /&gt;
&lt;br /&gt;
le deuxième topic et le topic config/ID (avec id l'identifiant unique de la raspberry), il nous sert a envoyer les commandes &amp;quot;start&amp;quot; et &amp;quot;stop&amp;quot; a la raspberry afin qu'elle démarre ou arrête la lecture des datas.&lt;br /&gt;
&lt;br /&gt;
Le troisième topic est le topic telemetry/ID, ou la raspberry vient publier ses données.&lt;br /&gt;
&lt;br /&gt;
Un quatrième topic pourrait être implémenter comme par exemple le topic common_config, toutes les raspberrys serait abonnées a ce topic. S'il est nécessaire, cela nous permettrais d'envoyer la même commande a toutes les raspberry  plutôt que de faire une publication sur chaque config/ID &lt;br /&gt;
&lt;br /&gt;
=== 6. Interface Serveur et Gestion des Données ===&lt;br /&gt;
----Le serveur central, au cœur de notre système, est orchestré par le script &amp;lt;code&amp;gt;app.py&amp;lt;/code&amp;gt; qui exploite le framework Flask pour mettre en place une interface serveur. Cette interface est conçue pour traiter efficacement les requêtes HTTP et les messages MQTT, offrant ainsi une API réactive pour l'interface utilisateur web. Elle permet également de visualiser en temps réel l'état des dispositifs Raspberry Pi connectés et les dernières données traitées.&lt;br /&gt;
[[Fichier:Signspeakweb.png|centré|vignette|1000x1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from flask import Flask, render_template, request, jsonify&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import queue&lt;br /&gt;
&lt;br /&gt;
app = Flask(__name__)&lt;br /&gt;
messages = []&lt;br /&gt;
received_messages = queue.Queue()&lt;br /&gt;
latest_message = None&lt;br /&gt;
subscribed_topics = set()&lt;br /&gt;
raspberry_ids = set()&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client = mqtt.Client()&lt;br /&gt;
mqtt_client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD) &lt;br /&gt;
mqtt_client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
mqtt_client.loop_start()&lt;br /&gt;
&lt;br /&gt;
def send_command_to_pi(pi_id, command):&lt;br /&gt;
    try:&lt;br /&gt;
        topic = f&amp;quot;config/{pi_id}&amp;quot;&lt;br /&gt;
        mqtt_client.publish(topic, command)&lt;br /&gt;
        subscribe_to_pi_telemetry(pi_id)&lt;br /&gt;
        return True, &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
    except Exception as e:&lt;br /&gt;
        return False, f&amp;quot;Commande pas envoyée: Erreur MQTT : {e}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
def subscribe_to_pi_telemetry(pi_id):&lt;br /&gt;
    global subscribed_topics&lt;br /&gt;
    topic = f&amp;quot;telemetry/{pi_id}&amp;quot;&lt;br /&gt;
    if topic not in subscribed_topics:&lt;br /&gt;
        mqtt_client.subscribe(topic)&lt;br /&gt;
        subscribed_topics.add(topic)&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(&amp;quot;raspberry_available&amp;quot;)&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    print(f&amp;quot;Received message on topic {msg.topic}: {msg.payload.decode()}&amp;quot;)  # Ajouter pour le débogage&lt;br /&gt;
    if msg.topic == &amp;quot;raspberry_available&amp;quot;:&lt;br /&gt;
        raspberry_ids.add(msg.payload.decode())&lt;br /&gt;
    else:&lt;br /&gt;
        received_messages.put(msg.payload.decode())&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client.on_connect = on_connect&lt;br /&gt;
mqtt_client.on_message = on_message&lt;br /&gt;
@app.route('/get-raspberry-ids')&lt;br /&gt;
def get_raspberry_ids():&lt;br /&gt;
    return jsonify(list(raspberry_ids))&lt;br /&gt;
@app.route('/get-latest-message')&lt;br /&gt;
def get_latest_message():&lt;br /&gt;
    global latest_message&lt;br /&gt;
    while not received_messages.empty():&lt;br /&gt;
        messages.append(received_messages.get())&lt;br /&gt;
&lt;br /&gt;
    latest_message = messages[-1] if messages else None&lt;br /&gt;
    &lt;br /&gt;
    # Ajoutez cet enregistrement de débogage&lt;br /&gt;
    print(f&amp;quot;Contenu de la réponse pour /get-latest-message : {latest_message}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    if latest_message is not None:&lt;br /&gt;
         response = jsonify({&amp;quot;message&amp;quot;: latest_message})&lt;br /&gt;
         return response&lt;br /&gt;
    else:&lt;br /&gt;
        message = &amp;quot;Aucun signe a traduire pour le moment&amp;quot;&lt;br /&gt;
        return jsonify(message)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@app.route('/', methods=['GET', 'POST'])&lt;br /&gt;
&lt;br /&gt;
def index():&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    error_message_rpi = None&lt;br /&gt;
    success_message = None&lt;br /&gt;
&lt;br /&gt;
    if request.method == 'POST':&lt;br /&gt;
        pi_id = request.form.get('pi_id')&lt;br /&gt;
        command = request.form.get('command')&lt;br /&gt;
        if pi_id and command in [&amp;quot;start&amp;quot;, &amp;quot;stop&amp;quot;]:&lt;br /&gt;
            success, er_message = send_command_to_pi(pi_id, command)&lt;br /&gt;
            if success:&lt;br /&gt;
                success_message = &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                error_message_rpi = er_message&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    return render_template('index.html', raspberry_ids=list(raspberry_ids), error_message_rpi=error_message_rpi, success_message=success_message, message=latest_message)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    app.run(debug=False, port=8066)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7. Conception de l'Interface Utilisateur ===&lt;br /&gt;
----L'interface utilisateur, développée à l'aide des technologies web standard HTML, CSS, et JavaScript, offre une expérience interactive. Le fichier index.html constitue le point d'entrée de cette interface, proposant des fonctionnalités telles que l'envoi de commandes aux dispositifs Raspberry Pi et la visualisation des données traitées. L'utilisation de JavaScript pour interroger dynamiquement le serveur Flask permet de rafraîchir les informations affichées en temps réel, garantissant ainsi une interface réactive et à jour.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
index.html:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
        body {&lt;br /&gt;
            background-color: #343a40; /* Couleur d'arrière-plan foncé */&lt;br /&gt;
            color: #ced4da; /* Gris clair pour le texte pour un meilleur contraste */&lt;br /&gt;
        }&lt;br /&gt;
        .card {&lt;br /&gt;
            background-color: #495057; /* Fond des encadrés plus sombre */&lt;br /&gt;
        }&lt;br /&gt;
        .card-title, .card-text, .alert {&lt;br /&gt;
            color: #adb5bd; /* Gris plus doux pour les titres, le texte et les alertes */&lt;br /&gt;
        }&lt;br /&gt;
        .btn-primary {&lt;br /&gt;
            background-color: #007bff; /* Bleu Bootstrap par défaut pour les boutons */&lt;br /&gt;
            border-color: #007bff;&lt;br /&gt;
        }&lt;br /&gt;
        .btn-danger {&lt;br /&gt;
            background-color: #dc3545; /* Rouge Bootstrap par défaut pour les boutons d'arrêt */&lt;br /&gt;
            border-color: #dc3545;&lt;br /&gt;
        }&lt;br /&gt;
        .form-control {&lt;br /&gt;
            background-color: #495057; /* Fond des champs de saisie plus sombre */&lt;br /&gt;
            border: 1px solid #6c757d;&lt;br /&gt;
            color: #ced4da; /* Couleur du texte dans les champs de saisie */&lt;br /&gt;
        }&lt;br /&gt;
        a, .btn-secondary {&lt;br /&gt;
            color: #17a2b8; /* Bleu clair pour les liens et les boutons secondaires */&lt;br /&gt;
        }&lt;br /&gt;
        a:hover {&lt;br /&gt;
            color: #138496; /* Bleu plus foncé au survol des liens */&lt;br /&gt;
        }&lt;br /&gt;
        /* Autres styles personnalisés ici */&lt;br /&gt;
        #latest-message {&lt;br /&gt;
            background-color: #596069; /* Couleur de fond plus claire pour l'encadré */&lt;br /&gt;
            border: 1px solid #6c757d; /* Bordure pour distinguer l'encadré */&lt;br /&gt;
            color: #E9ECEF; /* Couleur du texte plus claire pour un meilleur contraste */&lt;br /&gt;
            padding: 10px; /* Espace intérieur pour que le texte ne touche pas les bords */&lt;br /&gt;
            border-radius: 5px; /* Bords arrondis pour l'encadré */&lt;br /&gt;
        }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;container mt-5&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;h1 class=&amp;quot;text-center mb-4&amp;quot;&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/h1&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour les Raspberry Pi Disponibles --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-md-12&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Raspberry Pi Disponibles&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;ul id=&amp;quot;raspberry-list&amp;quot; class=&amp;quot;list-group list-group-flush&amp;quot;&amp;gt;&lt;br /&gt;
                            &amp;lt;!-- Les IDs seront ajoutés ici par JavaScript --&amp;gt;&lt;br /&gt;
                        &amp;lt;/ul&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour la Collecte des données --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Collecte de données&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;form method=&amp;quot;post&amp;quot; class=&amp;quot;form-inline&amp;quot;&amp;gt;&lt;br /&gt;
                            &amp;lt;input type=&amp;quot;text&amp;quot; class=&amp;quot;form-control mb-2 mr-sm-2&amp;quot; name=&amp;quot;pi_id&amp;quot; placeholder=&amp;quot;Entrez l'ID de la Raspberry Pi&amp;quot; required&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-primary mb-2 mr-sm-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;start&amp;quot;&amp;gt;Démarrer la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-danger mb-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;stop&amp;quot;&amp;gt;Arrêter la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                        &amp;lt;/form&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;!-- Encadré pour le Dernier Message Reçu --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Dernier Message Reçu&amp;lt;/h2&amp;gt;&lt;br /&gt;
                    &amp;lt;div id=&amp;quot;latest-message&amp;quot; class=&amp;quot;alert alert-dark&amp;quot;&amp;gt;&lt;br /&gt;
                        Aucun message reçu pour le moment. &lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;mb-3 text-center&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;a href=&amp;quot;/logs&amp;quot; class=&amp;quot;btn btn-secondary&amp;quot;&amp;gt;Voir les Logs&amp;lt;/a&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        function fetchRaspberryIds() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        var ids = JSON.parse(xhr.responseText);&lt;br /&gt;
                        var list = document.getElementById('raspberry-list');&lt;br /&gt;
                        list.innerHTML = '';&lt;br /&gt;
                        ids.forEach(function(id) {&lt;br /&gt;
                            var li = document.createElement('li');&lt;br /&gt;
                            li.textContent = id;&lt;br /&gt;
                            list.appendChild(li);&lt;br /&gt;
                        });&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-raspberry-ids', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function fetchLatestMessage() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        console.log(xhr.responseText)&lt;br /&gt;
                        document.getElementById('latest-message').textContent = xhr.responseText;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-latest-message', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setInterval(fetchRaspberryIds, 5000); // Met à jour les IDs toutes les 5 secondes&lt;br /&gt;
        setInterval(fetchLatestMessage, 500); // Met à jour le dernier message toutes les secondes&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;!-- Les messages d'alerte dynamiques ici --&amp;gt;&lt;br /&gt;
    {% if error_message_rpi %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ error_message_rpi }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&lt;br /&gt;
    {% if success_message %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ success_message }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On a aussi ajouté une page de logs, qui permet de voir l'historique de tous les données traitées.&lt;br /&gt;
&lt;br /&gt;
=== 9. Conclusion et Perspectives ===&lt;br /&gt;
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont&lt;br /&gt;
&lt;br /&gt;
== Vidéo ==&lt;br /&gt;
Lorsque l'on clique sur &amp;quot;démarrer la collecte&amp;quot; en ayant spécifié un ID, on peut voir en temps réel le résultat dans le cadre Dernier Message Recu.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:RPReplay_Final1706462779.mov|sans_cadre]]&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4888</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4888"/>
		<updated>2024-01-28T17:39:21Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* Vidéo */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Compte rendu des séances=&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:IfconfigVM.png|sans_cadre]]&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
mettre la config de la raspberry&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== '''Présentation du projet''' ==&lt;br /&gt;
&lt;br /&gt;
=== 1. Introduction ===&lt;br /&gt;
----Le projet SignSpeak a pour ambition de créer une solution innovante pour la traduction du langage des signes en texte. L'objectif principal est de développer un système capable de capturer les mouvements des mains et de les interpréter en langage des signes, permettant une communication fluide entre les personnes sourdes ou malentendantes et celles qui ne connaissent pas le langage des signes. Ce projet intègre des technologies avancées telles que l'edge computing, l'intelligence artificielle embarquée, et les communications MQTT, offrant une approche novatrice dans le domaine de l'accessibilité et de la communication.&lt;br /&gt;
&lt;br /&gt;
=== 2. Architecture du Système ===&lt;br /&gt;
----Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :&lt;br /&gt;
&lt;br /&gt;
* '''Capteurs et STM32''' : Des capteurs sont connectés à un microcontrôleur STM32, responsables de la capture des mouvements de main. Ces données sont ensuite transmises pour traitement.&lt;br /&gt;
* '''Raspberry Pi''' : Agissant comme un intermédiaire, la Raspberry Pi reçoit les données des capteurs via UART, exécute un traitement préliminaire et communique avec le serveur.&lt;br /&gt;
* '''Serveur et Machine Learning''' : Un serveur, hébergé sur une VM Xen, traite les données à l'aide d'un modèle SVM pour la traduction en langage des signes et fournit une interface web pour l'interaction utilisateur.&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== 3. Collecte et Préparation des Données ===&lt;br /&gt;
----Le processus de collecte des données est géré par le script &amp;lt;code&amp;gt;enregistrementData.py&amp;lt;/code&amp;gt;. Ce script lit les données transmises par le STM32 via UART et les enregistre dans un fichier CSV. Chaque entrée du fichier représente les valeurs de capteurs à un moment donné, accompagnées d'une étiquette correspondant au signe effectué. Cette approche assure une collecte de données structurée, essentielle pour l'entraînement précis du modèle d'apprentissage automatique.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
import csv&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
# Vérification de l'argument d'entrée&lt;br /&gt;
if len(sys.argv) &amp;lt; 2:&lt;br /&gt;
    print(&amp;quot;Usage: python script.py &amp;lt;etiquette&amp;gt;&amp;quot;)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
etiquette = sys.argv[1]&lt;br /&gt;
&lt;br /&gt;
# Paramètres de l'UART&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
&lt;br /&gt;
# Créer une connexion UART&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
&lt;br /&gt;
# Nom du fichier CSV&lt;br /&gt;
filename = f&amp;quot;data_complete.csv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Vérifier si le fichier existe déjà&lt;br /&gt;
file_exists = False&lt;br /&gt;
try:&lt;br /&gt;
    with open(filename, 'r') as f:&lt;br /&gt;
        file_exists = True&lt;br /&gt;
except FileNotFoundError:&lt;br /&gt;
    file_exists = False&lt;br /&gt;
&lt;br /&gt;
# Ouvrir le fichier CSV en mode append&lt;br /&gt;
with open(filename, 'a', newline='') as file:&lt;br /&gt;
    writer = csv.writer(file)&lt;br /&gt;
&lt;br /&gt;
    # Écrire l'en-tête si le fichier n'existait pas&lt;br /&gt;
    if not file_exists:&lt;br /&gt;
        writer.writerow([&amp;quot;Capteur1&amp;quot;, &amp;quot;Capteur2&amp;quot;, &amp;quot;Capteur3&amp;quot;, &amp;quot;Capteur4&amp;quot;, &amp;quot;Capteur5&amp;quot;, &amp;quot;Capteur6&amp;quot;, &amp;quot;Capteur7&amp;quot;, &amp;quot;Capteur8&amp;quot;, &amp;quot;Capteur9&amp;quot;, &amp;quot;Capteur10&amp;quot;, &amp;quot;Capteur11&amp;quot;, &amp;quot;Capteur12&amp;quot;, &amp;quot;Capteur13&amp;quot;, &amp;quot;Capteur14&amp;quot;, &lt;br /&gt;
&amp;quot;Capteur15&amp;quot;, &amp;quot;Capteur16&amp;quot;, &amp;quot;Etiquette&amp;quot;])&lt;br /&gt;
    elif file_exists:&lt;br /&gt;
        writer.writerow([])&lt;br /&gt;
    while True:&lt;br /&gt;
        # Lire une ligne de données depuis l'UART&lt;br /&gt;
        data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
        print(f&amp;quot;Données reçues : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Vérifier si des données ont été reçues&lt;br /&gt;
        if data:&lt;br /&gt;
            # Diviser les données en valeurs individuelles&lt;br /&gt;
            sensor_values = data.split(',')&lt;br /&gt;
&lt;br /&gt;
            # Filtrer les chaînes vides ou non numériques et convertir en flottants&lt;br /&gt;
            try:&lt;br /&gt;
                sensor_values = [float(value) for value in sensor_values if value.strip().isdigit()]&lt;br /&gt;
&lt;br /&gt;
                # Vérifier qu'il y a 16 valeurs de capteur&lt;br /&gt;
                if len(sensor_values) == 16:&lt;br /&gt;
                    sensor_values.append(etiquette)&lt;br /&gt;
                    writer.writerow(sensor_values)&lt;br /&gt;
                else:&lt;br /&gt;
                    print(&amp;quot;Données incomplètes reçues&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            except ValueError as e:&lt;br /&gt;
                print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
                print(f&amp;quot;Données problématiques : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Le script commence par établir une communication série avec le STM32.&lt;br /&gt;
* Il lit ensuite les données en série, les décode et les stocke dans un fichier CSV pour une utilisation ultérieure.&lt;br /&gt;
&lt;br /&gt;
* Une fois les données collectées et stockées dans le fichier CSV, elles sont préparées pour l'entraînement du modèle.&lt;br /&gt;
* Cette préparation implique la normalisation des données, la gestion des valeurs manquantes ou aberrantes, et leur formatage dans un bon format.[[Fichier:Rpi entrainement.png|vignette|1000x1000px|néant]]&lt;br /&gt;
=== 4. Entraînement du Modèle d'Apprentissage Automatique ===&lt;br /&gt;
----L'entraînement du modèle est réalisé par un script Python utilisant la bibliothèque scikit-learn. Le modèle SVM, choisi pour sa capacité à gérer des espaces de grande dimension, est entraîné sur l'ensemble des données collectées. Ce processus comprend la division des données en ensembles d'entraînement et de test, l'entraînement du modèle, et sa validation par le calcul de la précision. Nous avions testé plusieurs modèle, comme par exemple un modèle Knn ou randomForest, des 3 algorithmes, c'est celui qui nous à apporté les meilleurs résultats pour un meme nombre de data d'entrainement. (RandomForest en deuxième position)&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import pandas as pd&lt;br /&gt;
from sklearn.model_selection import train_test_split&lt;br /&gt;
from sklearn.svm import SVC&lt;br /&gt;
from sklearn.metrics import accuracy_score&lt;br /&gt;
import pickle&lt;br /&gt;
&lt;br /&gt;
# Charger vos données&lt;br /&gt;
data = pd.read_csv('data_complete.csv')&lt;br /&gt;
&lt;br /&gt;
# Séparer les caractéristiques et les étiquettes&lt;br /&gt;
X = data.drop('Etiquette', axis=1)&lt;br /&gt;
y = data['Etiquette']&lt;br /&gt;
&lt;br /&gt;
# Diviser les données en ensembles d'entraînement et de test&lt;br /&gt;
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)&lt;br /&gt;
&lt;br /&gt;
# Créer et entraîner le modèle SVM&lt;br /&gt;
model = SVC(kernel='rbf')&lt;br /&gt;
model.fit(X_train, y_train)&lt;br /&gt;
&lt;br /&gt;
# Sauvegarder le modèle entraîné&lt;br /&gt;
with open('modele_svm.pkl', 'wb') as file:&lt;br /&gt;
    pickle.dump(model, file)&lt;br /&gt;
&lt;br /&gt;
# Charger le modèle et faire des prédictions&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    loaded_model = pickle.load(file)&lt;br /&gt;
    predictions = loaded_model.predict(X_test)&lt;br /&gt;
    print(&amp;quot;Précision :&amp;quot;, accuracy_score(y_test, predictions))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# '''Séparation des Données''':&lt;br /&gt;
#* Les données sont divisées en deux ensembles : un ensemble d'entraînement et un ensemble de test. Cette séparation est cruciale pour évaluer objectivement la performance du modèle.&lt;br /&gt;
#* Généralement, on adopte une répartition de 80% pour l'entraînement et 20% pour les tests.&lt;br /&gt;
# '''Entraînement du Modèle SVM''':&lt;br /&gt;
#* Le modèle SVM avec un noyau RBF (Radial Basis Function) est entraîné sur l'ensemble d'entraînement.&lt;br /&gt;
#* L'entraînement implique l'ajustement du modèle aux données d'entraînement, en apprenant à distinguer les différents signes.&lt;br /&gt;
# '''Sauvegarde et Réutilisation du Modèle'''&lt;br /&gt;
#* Une fois entraîné et validé, le modèle est sauvegardé à l'aide de la bibliothèque &amp;lt;code&amp;gt;pickle&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Validation et Évaluation du Modèle''':&lt;br /&gt;
#* Après l'entraînement, le modèle est testé sur l'ensemble de test pour évaluer sa performance.&lt;br /&gt;
#* La métrique principale utilisée est la précision, qui mesure la proportion de prédictions correctes par rapport au total des prédictions.&lt;br /&gt;
&lt;br /&gt;
Ensuite on peut générer le modèle comme ceci:&lt;br /&gt;
[[Fichier:Generate model.png|vignette|399x399px|néant]]&lt;br /&gt;
&lt;br /&gt;
Avec cette prédiction lorsque notre modèle prédit le résultat, il est correct environ 71.81% du temps.&lt;br /&gt;
&lt;br /&gt;
=== 5. Intégration MQTT et Communication ===&lt;br /&gt;
----Protocole de communication  :&lt;br /&gt;
&lt;br /&gt;
Dans le cadre de notre projet, la communication entre les dispositifs Raspberry Pi et le serveur  est établie via le protocole MQTT.&lt;br /&gt;
&lt;br /&gt;
Justification du Choix de MQTT :&lt;br /&gt;
&lt;br /&gt;
Au début du projet, une approche basée sur des sockets IPv6 avait été envisagée pour tirer parti de l'adressage direct et de la simplification de la configuration réseau qu'offre IPv6. Cependant, dans le but de respecter les impératifs de sobriété énergétique et d'assurer une scalabilité optimale du système, permettant ainsi de gérer aisément un nombre croissant de dispositifs Raspberry Pi, la décision a été prise d'adopter MQTT comme protocole de communication. Le protocole MQTT, reconnu pour sa légèreté et sa fiabilité, s'adapte parfaitement aux contraintes des applications IoT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Installation du broker mosquitto sur le serveur:'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
apt install -y mosquitto mosquitto-clients&lt;br /&gt;
service mosquitto start&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Activation de l'accès à distance au Broker Mosquitto:&lt;br /&gt;
&lt;br /&gt;
ajouter l'authentification par username et mot de passe&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
sudo mosquitto_passwd -c /etc/mosquitto/passwd username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
après on nous demande d'entrer le mot de passe &lt;br /&gt;
&lt;br /&gt;
Modifier le fichier /etc/mosquitto/mosquitto.conf:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
listener 1883 10.42.0.5&lt;br /&gt;
allow_anonymous false&lt;br /&gt;
password_file /etc/mosquitto/passwd&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Mosquitto:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
service mosquitto restart&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vérification ds logs:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
cat /var/log/mosquitto/mosquitto.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Création d'un client MQTT sur la Raspberry Pi:'''&lt;br /&gt;
&lt;br /&gt;
Le script mqtt_client_rpi.py joue un rôle clé dans cette architecture en facilitant la communication bidirectionnelle : il permet non seulement l'envoi des prédictions réalisées par le modèle SVM depuis la Raspberry Pi vers le serveur, mais autorise également la réception des commandes de contrôle, telles que les instructions de démarrage ou d'arrêt de la collecte de données.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import serial&lt;br /&gt;
import pandas as pd&lt;br /&gt;
import pickle&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
pi_id = &amp;quot;rpi1234&amp;quot;&lt;br /&gt;
&lt;br /&gt;
collecting_data = False &lt;br /&gt;
&lt;br /&gt;
client = mqtt.Client()&lt;br /&gt;
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)&lt;br /&gt;
client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
client.loop_start()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(f&amp;quot;config/{pi_id}&amp;quot;)&lt;br /&gt;
    client.publish(&amp;quot;raspberry_available&amp;quot;, pi_id)&lt;br /&gt;
&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global collecting_data&lt;br /&gt;
    if msg.topic == f&amp;quot;config/{pi_id}&amp;quot;:&lt;br /&gt;
        command = msg.payload.decode()&lt;br /&gt;
        if command == &amp;quot;start&amp;quot;:&lt;br /&gt;
            collecting_data = True&lt;br /&gt;
        elif command == &amp;quot;stop&amp;quot;:&lt;br /&gt;
            collecting_data = False&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.on_connect = on_connect&lt;br /&gt;
client.on_message = on_message&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Configurez le port série et chargez le modèle ici&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    rf = pickle.load(file)&lt;br /&gt;
try:&lt;br /&gt;
&lt;br /&gt;
    while True:&lt;br /&gt;
        if collecting_data:&lt;br /&gt;
            data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
            if data:&lt;br /&gt;
                try:&lt;br /&gt;
                    sensor_values = [value for value in data.split(',') if value.strip().replace('.', '', 1).isdigit()]&lt;br /&gt;
                    if len(sensor_values) == 16:&lt;br /&gt;
                        sensor_values = list(map(float, sensor_values))&lt;br /&gt;
                        sensor_values_df = pd.DataFrame([sensor_values])&lt;br /&gt;
                        prediction = rf.predict(sensor_values_df)&lt;br /&gt;
                        client.publish(f&amp;quot;telemetry/{pi_id}&amp;quot;, str(prediction[0]).encode())&lt;br /&gt;
                        print(&amp;quot;Prédiction :&amp;quot;, prediction[0])&lt;br /&gt;
                except ValueError as e:&lt;br /&gt;
                    print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:&lt;br /&gt;
    print(&amp;quot;Script interrompu&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.loop_stop()&lt;br /&gt;
client.disconnect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Ici il y a 3 topics différents. lorsqu'une raspberry se connecte au réseau elle publie son ID (qui est unique, on peut prendre par exemple l'adresse MAC) sur le topic raspberry_available. Cela nous servira a savoir quelle raspberry est connecté et de se fait pouvoir afficher celles-ci sur notre interface web.&lt;br /&gt;
&lt;br /&gt;
le deuxième topic et le topic config/ID (avec id l'identifiant unique de la raspberry), il nous sert a envoyer les commandes &amp;quot;start&amp;quot; et &amp;quot;stop&amp;quot; a la raspberry afin qu'elle démarre ou arrête la lecture des datas.&lt;br /&gt;
&lt;br /&gt;
Le troisième topic est le topic telemetry/ID, ou la raspberry vient publier ses données.&lt;br /&gt;
&lt;br /&gt;
Un quatrième topic pourrait être implémenter comme par exemple le topic common_config, toutes les raspberrys serait abonnées a ce topic. S'il est nécessaire, cela nous permettrais d'envoyer la même commande a toutes les raspberry  plutôt que de faire une publication sur chaque config/ID &lt;br /&gt;
&lt;br /&gt;
=== 6. Interface Serveur et Gestion des Données ===&lt;br /&gt;
----Le serveur central, au cœur de notre système, est orchestré par le script &amp;lt;code&amp;gt;app.py&amp;lt;/code&amp;gt; qui exploite le framework Flask pour mettre en place une interface serveur. Cette interface est conçue pour traiter efficacement les requêtes HTTP et les messages MQTT, offrant ainsi une API réactive pour l'interface utilisateur web. Elle permet également de visualiser en temps réel l'état des dispositifs Raspberry Pi connectés et les dernières données traitées.&lt;br /&gt;
[[Fichier:Signspeakweb.png|centré|vignette|1000x1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from flask import Flask, render_template, request, jsonify&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import queue&lt;br /&gt;
&lt;br /&gt;
app = Flask(__name__)&lt;br /&gt;
messages = []&lt;br /&gt;
received_messages = queue.Queue()&lt;br /&gt;
latest_message = None&lt;br /&gt;
subscribed_topics = set()&lt;br /&gt;
raspberry_ids = set()&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client = mqtt.Client()&lt;br /&gt;
mqtt_client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD) &lt;br /&gt;
mqtt_client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
mqtt_client.loop_start()&lt;br /&gt;
&lt;br /&gt;
def send_command_to_pi(pi_id, command):&lt;br /&gt;
    try:&lt;br /&gt;
        topic = f&amp;quot;config/{pi_id}&amp;quot;&lt;br /&gt;
        mqtt_client.publish(topic, command)&lt;br /&gt;
        subscribe_to_pi_telemetry(pi_id)&lt;br /&gt;
        return True, &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
    except Exception as e:&lt;br /&gt;
        return False, f&amp;quot;Commande pas envoyée: Erreur MQTT : {e}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
def subscribe_to_pi_telemetry(pi_id):&lt;br /&gt;
    global subscribed_topics&lt;br /&gt;
    topic = f&amp;quot;telemetry/{pi_id}&amp;quot;&lt;br /&gt;
    if topic not in subscribed_topics:&lt;br /&gt;
        mqtt_client.subscribe(topic)&lt;br /&gt;
        subscribed_topics.add(topic)&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(&amp;quot;raspberry_available&amp;quot;)&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    print(f&amp;quot;Received message on topic {msg.topic}: {msg.payload.decode()}&amp;quot;)  # Ajouter pour le débogage&lt;br /&gt;
    if msg.topic == &amp;quot;raspberry_available&amp;quot;:&lt;br /&gt;
        raspberry_ids.add(msg.payload.decode())&lt;br /&gt;
    else:&lt;br /&gt;
        received_messages.put(msg.payload.decode())&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client.on_connect = on_connect&lt;br /&gt;
mqtt_client.on_message = on_message&lt;br /&gt;
@app.route('/get-raspberry-ids')&lt;br /&gt;
def get_raspberry_ids():&lt;br /&gt;
    return jsonify(list(raspberry_ids))&lt;br /&gt;
@app.route('/get-latest-message')&lt;br /&gt;
def get_latest_message():&lt;br /&gt;
    global latest_message&lt;br /&gt;
    while not received_messages.empty():&lt;br /&gt;
        messages.append(received_messages.get())&lt;br /&gt;
&lt;br /&gt;
    latest_message = messages[-1] if messages else None&lt;br /&gt;
    &lt;br /&gt;
    # Ajoutez cet enregistrement de débogage&lt;br /&gt;
    print(f&amp;quot;Contenu de la réponse pour /get-latest-message : {latest_message}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    if latest_message is not None:&lt;br /&gt;
         response = jsonify({&amp;quot;message&amp;quot;: latest_message})&lt;br /&gt;
         return response&lt;br /&gt;
    else:&lt;br /&gt;
        message = &amp;quot;Aucun signe a traduire pour le moment&amp;quot;&lt;br /&gt;
        return jsonify(message)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@app.route('/', methods=['GET', 'POST'])&lt;br /&gt;
&lt;br /&gt;
def index():&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    error_message_rpi = None&lt;br /&gt;
    success_message = None&lt;br /&gt;
&lt;br /&gt;
    if request.method == 'POST':&lt;br /&gt;
        pi_id = request.form.get('pi_id')&lt;br /&gt;
        command = request.form.get('command')&lt;br /&gt;
        if pi_id and command in [&amp;quot;start&amp;quot;, &amp;quot;stop&amp;quot;]:&lt;br /&gt;
            success, er_message = send_command_to_pi(pi_id, command)&lt;br /&gt;
            if success:&lt;br /&gt;
                success_message = &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                error_message_rpi = er_message&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    return render_template('index.html', raspberry_ids=list(raspberry_ids), error_message_rpi=error_message_rpi, success_message=success_message, message=latest_message)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    app.run(debug=False, port=8066)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7. Conception de l'Interface Utilisateur ===&lt;br /&gt;
----L'interface utilisateur, développée à l'aide des technologies web standard HTML, CSS, et JavaScript, offre une expérience interactive. Le fichier index.html constitue le point d'entrée de cette interface, proposant des fonctionnalités telles que l'envoi de commandes aux dispositifs Raspberry Pi et la visualisation des données traitées. L'utilisation de JavaScript pour interroger dynamiquement le serveur Flask permet de rafraîchir les informations affichées en temps réel, garantissant ainsi une interface réactive et à jour.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
index.html:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
        body {&lt;br /&gt;
            background-color: #343a40; /* Couleur d'arrière-plan foncé */&lt;br /&gt;
            color: #ced4da; /* Gris clair pour le texte pour un meilleur contraste */&lt;br /&gt;
        }&lt;br /&gt;
        .card {&lt;br /&gt;
            background-color: #495057; /* Fond des encadrés plus sombre */&lt;br /&gt;
        }&lt;br /&gt;
        .card-title, .card-text, .alert {&lt;br /&gt;
            color: #adb5bd; /* Gris plus doux pour les titres, le texte et les alertes */&lt;br /&gt;
        }&lt;br /&gt;
        .btn-primary {&lt;br /&gt;
            background-color: #007bff; /* Bleu Bootstrap par défaut pour les boutons */&lt;br /&gt;
            border-color: #007bff;&lt;br /&gt;
        }&lt;br /&gt;
        .btn-danger {&lt;br /&gt;
            background-color: #dc3545; /* Rouge Bootstrap par défaut pour les boutons d'arrêt */&lt;br /&gt;
            border-color: #dc3545;&lt;br /&gt;
        }&lt;br /&gt;
        .form-control {&lt;br /&gt;
            background-color: #495057; /* Fond des champs de saisie plus sombre */&lt;br /&gt;
            border: 1px solid #6c757d;&lt;br /&gt;
            color: #ced4da; /* Couleur du texte dans les champs de saisie */&lt;br /&gt;
        }&lt;br /&gt;
        a, .btn-secondary {&lt;br /&gt;
            color: #17a2b8; /* Bleu clair pour les liens et les boutons secondaires */&lt;br /&gt;
        }&lt;br /&gt;
        a:hover {&lt;br /&gt;
            color: #138496; /* Bleu plus foncé au survol des liens */&lt;br /&gt;
        }&lt;br /&gt;
        /* Autres styles personnalisés ici */&lt;br /&gt;
        #latest-message {&lt;br /&gt;
            background-color: #596069; /* Couleur de fond plus claire pour l'encadré */&lt;br /&gt;
            border: 1px solid #6c757d; /* Bordure pour distinguer l'encadré */&lt;br /&gt;
            color: #E9ECEF; /* Couleur du texte plus claire pour un meilleur contraste */&lt;br /&gt;
            padding: 10px; /* Espace intérieur pour que le texte ne touche pas les bords */&lt;br /&gt;
            border-radius: 5px; /* Bords arrondis pour l'encadré */&lt;br /&gt;
        }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;container mt-5&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;h1 class=&amp;quot;text-center mb-4&amp;quot;&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/h1&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour les Raspberry Pi Disponibles --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-md-12&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Raspberry Pi Disponibles&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;ul id=&amp;quot;raspberry-list&amp;quot; class=&amp;quot;list-group list-group-flush&amp;quot;&amp;gt;&lt;br /&gt;
                            &amp;lt;!-- Les IDs seront ajoutés ici par JavaScript --&amp;gt;&lt;br /&gt;
                        &amp;lt;/ul&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour la Collecte des données --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Collecte de données&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;form method=&amp;quot;post&amp;quot; class=&amp;quot;form-inline&amp;quot;&amp;gt;&lt;br /&gt;
                            &amp;lt;input type=&amp;quot;text&amp;quot; class=&amp;quot;form-control mb-2 mr-sm-2&amp;quot; name=&amp;quot;pi_id&amp;quot; placeholder=&amp;quot;Entrez l'ID de la Raspberry Pi&amp;quot; required&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-primary mb-2 mr-sm-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;start&amp;quot;&amp;gt;Démarrer la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-danger mb-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;stop&amp;quot;&amp;gt;Arrêter la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                        &amp;lt;/form&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;!-- Encadré pour le Dernier Message Reçu --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Dernier Message Reçu&amp;lt;/h2&amp;gt;&lt;br /&gt;
                    &amp;lt;div id=&amp;quot;latest-message&amp;quot; class=&amp;quot;alert alert-dark&amp;quot;&amp;gt;&lt;br /&gt;
                        Aucun message reçu pour le moment. &lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;mb-3 text-center&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;a href=&amp;quot;/logs&amp;quot; class=&amp;quot;btn btn-secondary&amp;quot;&amp;gt;Voir les Logs&amp;lt;/a&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        function fetchRaspberryIds() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        var ids = JSON.parse(xhr.responseText);&lt;br /&gt;
                        var list = document.getElementById('raspberry-list');&lt;br /&gt;
                        list.innerHTML = '';&lt;br /&gt;
                        ids.forEach(function(id) {&lt;br /&gt;
                            var li = document.createElement('li');&lt;br /&gt;
                            li.textContent = id;&lt;br /&gt;
                            list.appendChild(li);&lt;br /&gt;
                        });&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-raspberry-ids', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function fetchLatestMessage() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        console.log(xhr.responseText)&lt;br /&gt;
                        document.getElementById('latest-message').textContent = xhr.responseText;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-latest-message', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setInterval(fetchRaspberryIds, 5000); // Met à jour les IDs toutes les 5 secondes&lt;br /&gt;
        setInterval(fetchLatestMessage, 500); // Met à jour le dernier message toutes les secondes&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;!-- Les messages d'alerte dynamiques ici --&amp;gt;&lt;br /&gt;
    {% if error_message_rpi %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ error_message_rpi }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&lt;br /&gt;
    {% if success_message %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ success_message }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On a aussi ajouté une page de logs, qui permet de voir l'historique de tous les données traitées.&lt;br /&gt;
&lt;br /&gt;
=== 9. Conclusion et Perspectives ===&lt;br /&gt;
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont&lt;br /&gt;
&lt;br /&gt;
== Vidéo ==&lt;br /&gt;
[[Fichier:RPReplay_Final1706462779.mov|sans_cadre]]&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4886</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4886"/>
		<updated>2024-01-28T17:38:27Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* Vidéo */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Compte rendu des séances=&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:IfconfigVM.png|sans_cadre]]&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
mettre la config de la raspberry&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== '''Présentation du projet''' ==&lt;br /&gt;
&lt;br /&gt;
=== 1. Introduction ===&lt;br /&gt;
----Le projet SignSpeak a pour ambition de créer une solution innovante pour la traduction du langage des signes en texte. L'objectif principal est de développer un système capable de capturer les mouvements des mains et de les interpréter en langage des signes, permettant une communication fluide entre les personnes sourdes ou malentendantes et celles qui ne connaissent pas le langage des signes. Ce projet intègre des technologies avancées telles que l'edge computing, l'intelligence artificielle embarquée, et les communications MQTT, offrant une approche novatrice dans le domaine de l'accessibilité et de la communication.&lt;br /&gt;
&lt;br /&gt;
=== 2. Architecture du Système ===&lt;br /&gt;
----Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :&lt;br /&gt;
&lt;br /&gt;
* '''Capteurs et STM32''' : Des capteurs sont connectés à un microcontrôleur STM32, responsables de la capture des mouvements de main. Ces données sont ensuite transmises pour traitement.&lt;br /&gt;
* '''Raspberry Pi''' : Agissant comme un intermédiaire, la Raspberry Pi reçoit les données des capteurs via UART, exécute un traitement préliminaire et communique avec le serveur.&lt;br /&gt;
* '''Serveur et Machine Learning''' : Un serveur, hébergé sur une VM Xen, traite les données à l'aide d'un modèle SVM pour la traduction en langage des signes et fournit une interface web pour l'interaction utilisateur.&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== 3. Collecte et Préparation des Données ===&lt;br /&gt;
----Le processus de collecte des données est géré par le script &amp;lt;code&amp;gt;enregistrementData.py&amp;lt;/code&amp;gt;. Ce script lit les données transmises par le STM32 via UART et les enregistre dans un fichier CSV. Chaque entrée du fichier représente les valeurs de capteurs à un moment donné, accompagnées d'une étiquette correspondant au signe effectué. Cette approche assure une collecte de données structurée, essentielle pour l'entraînement précis du modèle d'apprentissage automatique.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
import csv&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
# Vérification de l'argument d'entrée&lt;br /&gt;
if len(sys.argv) &amp;lt; 2:&lt;br /&gt;
    print(&amp;quot;Usage: python script.py &amp;lt;etiquette&amp;gt;&amp;quot;)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
etiquette = sys.argv[1]&lt;br /&gt;
&lt;br /&gt;
# Paramètres de l'UART&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
&lt;br /&gt;
# Créer une connexion UART&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
&lt;br /&gt;
# Nom du fichier CSV&lt;br /&gt;
filename = f&amp;quot;data_complete.csv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Vérifier si le fichier existe déjà&lt;br /&gt;
file_exists = False&lt;br /&gt;
try:&lt;br /&gt;
    with open(filename, 'r') as f:&lt;br /&gt;
        file_exists = True&lt;br /&gt;
except FileNotFoundError:&lt;br /&gt;
    file_exists = False&lt;br /&gt;
&lt;br /&gt;
# Ouvrir le fichier CSV en mode append&lt;br /&gt;
with open(filename, 'a', newline='') as file:&lt;br /&gt;
    writer = csv.writer(file)&lt;br /&gt;
&lt;br /&gt;
    # Écrire l'en-tête si le fichier n'existait pas&lt;br /&gt;
    if not file_exists:&lt;br /&gt;
        writer.writerow([&amp;quot;Capteur1&amp;quot;, &amp;quot;Capteur2&amp;quot;, &amp;quot;Capteur3&amp;quot;, &amp;quot;Capteur4&amp;quot;, &amp;quot;Capteur5&amp;quot;, &amp;quot;Capteur6&amp;quot;, &amp;quot;Capteur7&amp;quot;, &amp;quot;Capteur8&amp;quot;, &amp;quot;Capteur9&amp;quot;, &amp;quot;Capteur10&amp;quot;, &amp;quot;Capteur11&amp;quot;, &amp;quot;Capteur12&amp;quot;, &amp;quot;Capteur13&amp;quot;, &amp;quot;Capteur14&amp;quot;, &lt;br /&gt;
&amp;quot;Capteur15&amp;quot;, &amp;quot;Capteur16&amp;quot;, &amp;quot;Etiquette&amp;quot;])&lt;br /&gt;
    elif file_exists:&lt;br /&gt;
        writer.writerow([])&lt;br /&gt;
    while True:&lt;br /&gt;
        # Lire une ligne de données depuis l'UART&lt;br /&gt;
        data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
        print(f&amp;quot;Données reçues : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Vérifier si des données ont été reçues&lt;br /&gt;
        if data:&lt;br /&gt;
            # Diviser les données en valeurs individuelles&lt;br /&gt;
            sensor_values = data.split(',')&lt;br /&gt;
&lt;br /&gt;
            # Filtrer les chaînes vides ou non numériques et convertir en flottants&lt;br /&gt;
            try:&lt;br /&gt;
                sensor_values = [float(value) for value in sensor_values if value.strip().isdigit()]&lt;br /&gt;
&lt;br /&gt;
                # Vérifier qu'il y a 16 valeurs de capteur&lt;br /&gt;
                if len(sensor_values) == 16:&lt;br /&gt;
                    sensor_values.append(etiquette)&lt;br /&gt;
                    writer.writerow(sensor_values)&lt;br /&gt;
                else:&lt;br /&gt;
                    print(&amp;quot;Données incomplètes reçues&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            except ValueError as e:&lt;br /&gt;
                print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
                print(f&amp;quot;Données problématiques : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Le script commence par établir une communication série avec le STM32.&lt;br /&gt;
* Il lit ensuite les données en série, les décode et les stocke dans un fichier CSV pour une utilisation ultérieure.&lt;br /&gt;
&lt;br /&gt;
* Une fois les données collectées et stockées dans le fichier CSV, elles sont préparées pour l'entraînement du modèle.&lt;br /&gt;
* Cette préparation implique la normalisation des données, la gestion des valeurs manquantes ou aberrantes, et leur formatage dans un bon format.[[Fichier:Rpi entrainement.png|vignette|1000x1000px|néant]]&lt;br /&gt;
=== 4. Entraînement du Modèle d'Apprentissage Automatique ===&lt;br /&gt;
----L'entraînement du modèle est réalisé par un script Python utilisant la bibliothèque scikit-learn. Le modèle SVM, choisi pour sa capacité à gérer des espaces de grande dimension, est entraîné sur l'ensemble des données collectées. Ce processus comprend la division des données en ensembles d'entraînement et de test, l'entraînement du modèle, et sa validation par le calcul de la précision. Nous avions testé plusieurs modèle, comme par exemple un modèle Knn ou randomForest, des 3 algorithmes, c'est celui qui nous à apporté les meilleurs résultats pour un meme nombre de data d'entrainement. (RandomForest en deuxième position)&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import pandas as pd&lt;br /&gt;
from sklearn.model_selection import train_test_split&lt;br /&gt;
from sklearn.svm import SVC&lt;br /&gt;
from sklearn.metrics import accuracy_score&lt;br /&gt;
import pickle&lt;br /&gt;
&lt;br /&gt;
# Charger vos données&lt;br /&gt;
data = pd.read_csv('data_complete.csv')&lt;br /&gt;
&lt;br /&gt;
# Séparer les caractéristiques et les étiquettes&lt;br /&gt;
X = data.drop('Etiquette', axis=1)&lt;br /&gt;
y = data['Etiquette']&lt;br /&gt;
&lt;br /&gt;
# Diviser les données en ensembles d'entraînement et de test&lt;br /&gt;
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)&lt;br /&gt;
&lt;br /&gt;
# Créer et entraîner le modèle SVM&lt;br /&gt;
model = SVC(kernel='rbf')&lt;br /&gt;
model.fit(X_train, y_train)&lt;br /&gt;
&lt;br /&gt;
# Sauvegarder le modèle entraîné&lt;br /&gt;
with open('modele_svm.pkl', 'wb') as file:&lt;br /&gt;
    pickle.dump(model, file)&lt;br /&gt;
&lt;br /&gt;
# Charger le modèle et faire des prédictions&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    loaded_model = pickle.load(file)&lt;br /&gt;
    predictions = loaded_model.predict(X_test)&lt;br /&gt;
    print(&amp;quot;Précision :&amp;quot;, accuracy_score(y_test, predictions))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# '''Séparation des Données''':&lt;br /&gt;
#* Les données sont divisées en deux ensembles : un ensemble d'entraînement et un ensemble de test. Cette séparation est cruciale pour évaluer objectivement la performance du modèle.&lt;br /&gt;
#* Généralement, on adopte une répartition de 80% pour l'entraînement et 20% pour les tests.&lt;br /&gt;
# '''Entraînement du Modèle SVM''':&lt;br /&gt;
#* Le modèle SVM avec un noyau RBF (Radial Basis Function) est entraîné sur l'ensemble d'entraînement.&lt;br /&gt;
#* L'entraînement implique l'ajustement du modèle aux données d'entraînement, en apprenant à distinguer les différents signes.&lt;br /&gt;
# '''Sauvegarde et Réutilisation du Modèle'''&lt;br /&gt;
#* Une fois entraîné et validé, le modèle est sauvegardé à l'aide de la bibliothèque &amp;lt;code&amp;gt;pickle&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Validation et Évaluation du Modèle''':&lt;br /&gt;
#* Après l'entraînement, le modèle est testé sur l'ensemble de test pour évaluer sa performance.&lt;br /&gt;
#* La métrique principale utilisée est la précision, qui mesure la proportion de prédictions correctes par rapport au total des prédictions.&lt;br /&gt;
&lt;br /&gt;
Ensuite on peut générer le modèle comme ceci:&lt;br /&gt;
[[Fichier:Generate model.png|vignette|399x399px|néant]]&lt;br /&gt;
&lt;br /&gt;
Avec cette prédiction lorsque notre modèle prédit le résultat, il est correct environ 71.81% du temps.&lt;br /&gt;
&lt;br /&gt;
=== 5. Intégration MQTT et Communication ===&lt;br /&gt;
----Protocole de communication  :&lt;br /&gt;
&lt;br /&gt;
Dans le cadre de notre projet, la communication entre les dispositifs Raspberry Pi et le serveur  est établie via le protocole MQTT.&lt;br /&gt;
&lt;br /&gt;
Justification du Choix de MQTT :&lt;br /&gt;
&lt;br /&gt;
Au début du projet, une approche basée sur des sockets IPv6 avait été envisagée pour tirer parti de l'adressage direct et de la simplification de la configuration réseau qu'offre IPv6. Cependant, dans le but de respecter les impératifs de sobriété énergétique et d'assurer une scalabilité optimale du système, permettant ainsi de gérer aisément un nombre croissant de dispositifs Raspberry Pi, la décision a été prise d'adopter MQTT comme protocole de communication. Le protocole MQTT, reconnu pour sa légèreté et sa fiabilité, s'adapte parfaitement aux contraintes des applications IoT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Installation du broker mosquitto sur le serveur:'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
apt install -y mosquitto mosquitto-clients&lt;br /&gt;
service mosquitto start&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Activation de l'accès à distance au Broker Mosquitto:&lt;br /&gt;
&lt;br /&gt;
ajouter l'authentification par username et mot de passe&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
sudo mosquitto_passwd -c /etc/mosquitto/passwd username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
après on nous demande d'entrer le mot de passe &lt;br /&gt;
&lt;br /&gt;
Modifier le fichier /etc/mosquitto/mosquitto.conf:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
listener 1883 10.42.0.5&lt;br /&gt;
allow_anonymous false&lt;br /&gt;
password_file /etc/mosquitto/passwd&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Mosquitto:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
service mosquitto restart&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vérification ds logs:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
cat /var/log/mosquitto/mosquitto.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Création d'un client MQTT sur la Raspberry Pi:'''&lt;br /&gt;
&lt;br /&gt;
Le script mqtt_client_rpi.py joue un rôle clé dans cette architecture en facilitant la communication bidirectionnelle : il permet non seulement l'envoi des prédictions réalisées par le modèle SVM depuis la Raspberry Pi vers le serveur, mais autorise également la réception des commandes de contrôle, telles que les instructions de démarrage ou d'arrêt de la collecte de données.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import serial&lt;br /&gt;
import pandas as pd&lt;br /&gt;
import pickle&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
pi_id = &amp;quot;rpi1234&amp;quot;&lt;br /&gt;
&lt;br /&gt;
collecting_data = False &lt;br /&gt;
&lt;br /&gt;
client = mqtt.Client()&lt;br /&gt;
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)&lt;br /&gt;
client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
client.loop_start()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(f&amp;quot;config/{pi_id}&amp;quot;)&lt;br /&gt;
    client.publish(&amp;quot;raspberry_available&amp;quot;, pi_id)&lt;br /&gt;
&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global collecting_data&lt;br /&gt;
    if msg.topic == f&amp;quot;config/{pi_id}&amp;quot;:&lt;br /&gt;
        command = msg.payload.decode()&lt;br /&gt;
        if command == &amp;quot;start&amp;quot;:&lt;br /&gt;
            collecting_data = True&lt;br /&gt;
        elif command == &amp;quot;stop&amp;quot;:&lt;br /&gt;
            collecting_data = False&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.on_connect = on_connect&lt;br /&gt;
client.on_message = on_message&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Configurez le port série et chargez le modèle ici&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    rf = pickle.load(file)&lt;br /&gt;
try:&lt;br /&gt;
&lt;br /&gt;
    while True:&lt;br /&gt;
        if collecting_data:&lt;br /&gt;
            data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
            if data:&lt;br /&gt;
                try:&lt;br /&gt;
                    sensor_values = [value for value in data.split(',') if value.strip().replace('.', '', 1).isdigit()]&lt;br /&gt;
                    if len(sensor_values) == 16:&lt;br /&gt;
                        sensor_values = list(map(float, sensor_values))&lt;br /&gt;
                        sensor_values_df = pd.DataFrame([sensor_values])&lt;br /&gt;
                        prediction = rf.predict(sensor_values_df)&lt;br /&gt;
                        client.publish(f&amp;quot;telemetry/{pi_id}&amp;quot;, str(prediction[0]).encode())&lt;br /&gt;
                        print(&amp;quot;Prédiction :&amp;quot;, prediction[0])&lt;br /&gt;
                except ValueError as e:&lt;br /&gt;
                    print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:&lt;br /&gt;
    print(&amp;quot;Script interrompu&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.loop_stop()&lt;br /&gt;
client.disconnect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Ici il y a 3 topics différents. lorsqu'une raspberry se connecte au réseau elle publie son ID (qui est unique, on peut prendre par exemple l'adresse MAC) sur le topic raspberry_available. Cela nous servira a savoir quelle raspberry est connecté et de se fait pouvoir afficher celles-ci sur notre interface web.&lt;br /&gt;
&lt;br /&gt;
le deuxième topic et le topic config/ID (avec id l'identifiant unique de la raspberry), il nous sert a envoyer les commandes &amp;quot;start&amp;quot; et &amp;quot;stop&amp;quot; a la raspberry afin qu'elle démarre ou arrête la lecture des datas.&lt;br /&gt;
&lt;br /&gt;
Le troisième topic est le topic telemetry/ID, ou la raspberry vient publier ses données.&lt;br /&gt;
&lt;br /&gt;
Un quatrième topic pourrait être implémenter comme par exemple le topic common_config, toutes les raspberrys serait abonnées a ce topic. S'il est nécessaire, cela nous permettrais d'envoyer la même commande a toutes les raspberry  plutôt que de faire une publication sur chaque config/ID &lt;br /&gt;
&lt;br /&gt;
=== 6. Interface Serveur et Gestion des Données ===&lt;br /&gt;
----Le serveur central, au cœur de notre système, est orchestré par le script &amp;lt;code&amp;gt;app.py&amp;lt;/code&amp;gt; qui exploite le framework Flask pour mettre en place une interface serveur. Cette interface est conçue pour traiter efficacement les requêtes HTTP et les messages MQTT, offrant ainsi une API réactive pour l'interface utilisateur web. Elle permet également de visualiser en temps réel l'état des dispositifs Raspberry Pi connectés et les dernières données traitées.&lt;br /&gt;
[[Fichier:Signspeakweb.png|centré|vignette|1000x1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from flask import Flask, render_template, request, jsonify&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import queue&lt;br /&gt;
&lt;br /&gt;
app = Flask(__name__)&lt;br /&gt;
messages = []&lt;br /&gt;
received_messages = queue.Queue()&lt;br /&gt;
latest_message = None&lt;br /&gt;
subscribed_topics = set()&lt;br /&gt;
raspberry_ids = set()&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client = mqtt.Client()&lt;br /&gt;
mqtt_client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD) &lt;br /&gt;
mqtt_client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
mqtt_client.loop_start()&lt;br /&gt;
&lt;br /&gt;
def send_command_to_pi(pi_id, command):&lt;br /&gt;
    try:&lt;br /&gt;
        topic = f&amp;quot;config/{pi_id}&amp;quot;&lt;br /&gt;
        mqtt_client.publish(topic, command)&lt;br /&gt;
        subscribe_to_pi_telemetry(pi_id)&lt;br /&gt;
        return True, &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
    except Exception as e:&lt;br /&gt;
        return False, f&amp;quot;Commande pas envoyée: Erreur MQTT : {e}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
def subscribe_to_pi_telemetry(pi_id):&lt;br /&gt;
    global subscribed_topics&lt;br /&gt;
    topic = f&amp;quot;telemetry/{pi_id}&amp;quot;&lt;br /&gt;
    if topic not in subscribed_topics:&lt;br /&gt;
        mqtt_client.subscribe(topic)&lt;br /&gt;
        subscribed_topics.add(topic)&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(&amp;quot;raspberry_available&amp;quot;)&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    print(f&amp;quot;Received message on topic {msg.topic}: {msg.payload.decode()}&amp;quot;)  # Ajouter pour le débogage&lt;br /&gt;
    if msg.topic == &amp;quot;raspberry_available&amp;quot;:&lt;br /&gt;
        raspberry_ids.add(msg.payload.decode())&lt;br /&gt;
    else:&lt;br /&gt;
        received_messages.put(msg.payload.decode())&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client.on_connect = on_connect&lt;br /&gt;
mqtt_client.on_message = on_message&lt;br /&gt;
@app.route('/get-raspberry-ids')&lt;br /&gt;
def get_raspberry_ids():&lt;br /&gt;
    return jsonify(list(raspberry_ids))&lt;br /&gt;
@app.route('/get-latest-message')&lt;br /&gt;
def get_latest_message():&lt;br /&gt;
    global latest_message&lt;br /&gt;
    while not received_messages.empty():&lt;br /&gt;
        messages.append(received_messages.get())&lt;br /&gt;
&lt;br /&gt;
    latest_message = messages[-1] if messages else None&lt;br /&gt;
    &lt;br /&gt;
    # Ajoutez cet enregistrement de débogage&lt;br /&gt;
    print(f&amp;quot;Contenu de la réponse pour /get-latest-message : {latest_message}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    if latest_message is not None:&lt;br /&gt;
         response = jsonify({&amp;quot;message&amp;quot;: latest_message})&lt;br /&gt;
         return response&lt;br /&gt;
    else:&lt;br /&gt;
        message = &amp;quot;Aucun signe a traduire pour le moment&amp;quot;&lt;br /&gt;
        return jsonify(message)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@app.route('/', methods=['GET', 'POST'])&lt;br /&gt;
&lt;br /&gt;
def index():&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    error_message_rpi = None&lt;br /&gt;
    success_message = None&lt;br /&gt;
&lt;br /&gt;
    if request.method == 'POST':&lt;br /&gt;
        pi_id = request.form.get('pi_id')&lt;br /&gt;
        command = request.form.get('command')&lt;br /&gt;
        if pi_id and command in [&amp;quot;start&amp;quot;, &amp;quot;stop&amp;quot;]:&lt;br /&gt;
            success, er_message = send_command_to_pi(pi_id, command)&lt;br /&gt;
            if success:&lt;br /&gt;
                success_message = &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                error_message_rpi = er_message&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    return render_template('index.html', raspberry_ids=list(raspberry_ids), error_message_rpi=error_message_rpi, success_message=success_message, message=latest_message)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    app.run(debug=False, port=8066)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7. Conception de l'Interface Utilisateur ===&lt;br /&gt;
----L'interface utilisateur, développée à l'aide des technologies web standard HTML, CSS, et JavaScript, offre une expérience interactive. Le fichier index.html constitue le point d'entrée de cette interface, proposant des fonctionnalités telles que l'envoi de commandes aux dispositifs Raspberry Pi et la visualisation des données traitées. L'utilisation de JavaScript pour interroger dynamiquement le serveur Flask permet de rafraîchir les informations affichées en temps réel, garantissant ainsi une interface réactive et à jour.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
index.html:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
        body {&lt;br /&gt;
            background-color: #343a40; /* Couleur d'arrière-plan foncé */&lt;br /&gt;
            color: #ced4da; /* Gris clair pour le texte pour un meilleur contraste */&lt;br /&gt;
        }&lt;br /&gt;
        .card {&lt;br /&gt;
            background-color: #495057; /* Fond des encadrés plus sombre */&lt;br /&gt;
        }&lt;br /&gt;
        .card-title, .card-text, .alert {&lt;br /&gt;
            color: #adb5bd; /* Gris plus doux pour les titres, le texte et les alertes */&lt;br /&gt;
        }&lt;br /&gt;
        .btn-primary {&lt;br /&gt;
            background-color: #007bff; /* Bleu Bootstrap par défaut pour les boutons */&lt;br /&gt;
            border-color: #007bff;&lt;br /&gt;
        }&lt;br /&gt;
        .btn-danger {&lt;br /&gt;
            background-color: #dc3545; /* Rouge Bootstrap par défaut pour les boutons d'arrêt */&lt;br /&gt;
            border-color: #dc3545;&lt;br /&gt;
        }&lt;br /&gt;
        .form-control {&lt;br /&gt;
            background-color: #495057; /* Fond des champs de saisie plus sombre */&lt;br /&gt;
            border: 1px solid #6c757d;&lt;br /&gt;
            color: #ced4da; /* Couleur du texte dans les champs de saisie */&lt;br /&gt;
        }&lt;br /&gt;
        a, .btn-secondary {&lt;br /&gt;
            color: #17a2b8; /* Bleu clair pour les liens et les boutons secondaires */&lt;br /&gt;
        }&lt;br /&gt;
        a:hover {&lt;br /&gt;
            color: #138496; /* Bleu plus foncé au survol des liens */&lt;br /&gt;
        }&lt;br /&gt;
        /* Autres styles personnalisés ici */&lt;br /&gt;
        #latest-message {&lt;br /&gt;
            background-color: #596069; /* Couleur de fond plus claire pour l'encadré */&lt;br /&gt;
            border: 1px solid #6c757d; /* Bordure pour distinguer l'encadré */&lt;br /&gt;
            color: #E9ECEF; /* Couleur du texte plus claire pour un meilleur contraste */&lt;br /&gt;
            padding: 10px; /* Espace intérieur pour que le texte ne touche pas les bords */&lt;br /&gt;
            border-radius: 5px; /* Bords arrondis pour l'encadré */&lt;br /&gt;
        }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;container mt-5&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;h1 class=&amp;quot;text-center mb-4&amp;quot;&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/h1&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour les Raspberry Pi Disponibles --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-md-12&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Raspberry Pi Disponibles&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;ul id=&amp;quot;raspberry-list&amp;quot; class=&amp;quot;list-group list-group-flush&amp;quot;&amp;gt;&lt;br /&gt;
                            &amp;lt;!-- Les IDs seront ajoutés ici par JavaScript --&amp;gt;&lt;br /&gt;
                        &amp;lt;/ul&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour la Collecte des données --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Collecte de données&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;form method=&amp;quot;post&amp;quot; class=&amp;quot;form-inline&amp;quot;&amp;gt;&lt;br /&gt;
                            &amp;lt;input type=&amp;quot;text&amp;quot; class=&amp;quot;form-control mb-2 mr-sm-2&amp;quot; name=&amp;quot;pi_id&amp;quot; placeholder=&amp;quot;Entrez l'ID de la Raspberry Pi&amp;quot; required&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-primary mb-2 mr-sm-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;start&amp;quot;&amp;gt;Démarrer la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-danger mb-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;stop&amp;quot;&amp;gt;Arrêter la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                        &amp;lt;/form&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;!-- Encadré pour le Dernier Message Reçu --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Dernier Message Reçu&amp;lt;/h2&amp;gt;&lt;br /&gt;
                    &amp;lt;div id=&amp;quot;latest-message&amp;quot; class=&amp;quot;alert alert-dark&amp;quot;&amp;gt;&lt;br /&gt;
                        Aucun message reçu pour le moment. &lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;mb-3 text-center&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;a href=&amp;quot;/logs&amp;quot; class=&amp;quot;btn btn-secondary&amp;quot;&amp;gt;Voir les Logs&amp;lt;/a&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        function fetchRaspberryIds() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        var ids = JSON.parse(xhr.responseText);&lt;br /&gt;
                        var list = document.getElementById('raspberry-list');&lt;br /&gt;
                        list.innerHTML = '';&lt;br /&gt;
                        ids.forEach(function(id) {&lt;br /&gt;
                            var li = document.createElement('li');&lt;br /&gt;
                            li.textContent = id;&lt;br /&gt;
                            list.appendChild(li);&lt;br /&gt;
                        });&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-raspberry-ids', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function fetchLatestMessage() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        console.log(xhr.responseText)&lt;br /&gt;
                        document.getElementById('latest-message').textContent = xhr.responseText;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-latest-message', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setInterval(fetchRaspberryIds, 5000); // Met à jour les IDs toutes les 5 secondes&lt;br /&gt;
        setInterval(fetchLatestMessage, 500); // Met à jour le dernier message toutes les secondes&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;!-- Les messages d'alerte dynamiques ici --&amp;gt;&lt;br /&gt;
    {% if error_message_rpi %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ error_message_rpi }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&lt;br /&gt;
    {% if success_message %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ success_message }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On a aussi ajouté une page de logs, qui permet de voir l'historique de tous les données traitées.&lt;br /&gt;
&lt;br /&gt;
=== 9. Conclusion et Perspectives ===&lt;br /&gt;
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont&lt;br /&gt;
&lt;br /&gt;
== Vidéo ==&lt;br /&gt;
[[Fichier:RPReplay Final1706462779.mov|centré|vignette]]&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:RPReplay_Final1706462779.mov&amp;diff=4885</id>
		<title>Fichier:RPReplay Final1706462779.mov</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:RPReplay_Final1706462779.mov&amp;diff=4885"/>
		<updated>2024-01-28T17:37:05Z</updated>

		<summary type="html">&lt;p&gt;Bblack : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;RPReplay Final1706462779&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4877</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4877"/>
		<updated>2024-01-28T17:10:12Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* 9. Conclusion et Perspectives */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Compte rendu des séances=&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:IfconfigVM.png|sans_cadre]]&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
mettre la config de la raspberry&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== '''Présentation du projet''' ==&lt;br /&gt;
&lt;br /&gt;
=== 1. Introduction ===&lt;br /&gt;
----Le projet SignSpeak a pour ambition de créer une solution innovante pour la traduction du langage des signes en texte. L'objectif principal est de développer un système capable de capturer les mouvements des mains et de les interpréter en langage des signes, permettant une communication fluide entre les personnes sourdes ou malentendantes et celles qui ne connaissent pas le langage des signes. Ce projet intègre des technologies avancées telles que l'edge computing, l'intelligence artificielle embarquée, et les communications MQTT, offrant une approche novatrice dans le domaine de l'accessibilité et de la communication.&lt;br /&gt;
&lt;br /&gt;
=== 2. Architecture du Système ===&lt;br /&gt;
----Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :&lt;br /&gt;
&lt;br /&gt;
* '''Capteurs et STM32''' : Des capteurs sont connectés à un microcontrôleur STM32, responsables de la capture des mouvements de main. Ces données sont ensuite transmises pour traitement.&lt;br /&gt;
* '''Raspberry Pi''' : Agissant comme un intermédiaire, la Raspberry Pi reçoit les données des capteurs via UART, exécute un traitement préliminaire et communique avec le serveur.&lt;br /&gt;
* '''Serveur et Machine Learning''' : Un serveur, hébergé sur une VM Xen, traite les données à l'aide d'un modèle SVM pour la traduction en langage des signes et fournit une interface web pour l'interaction utilisateur.&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== 3. Collecte et Préparation des Données ===&lt;br /&gt;
----Le processus de collecte des données est géré par le script &amp;lt;code&amp;gt;enregistrementData.py&amp;lt;/code&amp;gt;. Ce script lit les données transmises par le STM32 via UART et les enregistre dans un fichier CSV. Chaque entrée du fichier représente les valeurs de capteurs à un moment donné, accompagnées d'une étiquette correspondant au signe effectué. Cette approche assure une collecte de données structurée, essentielle pour l'entraînement précis du modèle d'apprentissage automatique.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
import csv&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
# Vérification de l'argument d'entrée&lt;br /&gt;
if len(sys.argv) &amp;lt; 2:&lt;br /&gt;
    print(&amp;quot;Usage: python script.py &amp;lt;etiquette&amp;gt;&amp;quot;)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
etiquette = sys.argv[1]&lt;br /&gt;
&lt;br /&gt;
# Paramètres de l'UART&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
&lt;br /&gt;
# Créer une connexion UART&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
&lt;br /&gt;
# Nom du fichier CSV&lt;br /&gt;
filename = f&amp;quot;data_complete.csv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Vérifier si le fichier existe déjà&lt;br /&gt;
file_exists = False&lt;br /&gt;
try:&lt;br /&gt;
    with open(filename, 'r') as f:&lt;br /&gt;
        file_exists = True&lt;br /&gt;
except FileNotFoundError:&lt;br /&gt;
    file_exists = False&lt;br /&gt;
&lt;br /&gt;
# Ouvrir le fichier CSV en mode append&lt;br /&gt;
with open(filename, 'a', newline='') as file:&lt;br /&gt;
    writer = csv.writer(file)&lt;br /&gt;
&lt;br /&gt;
    # Écrire l'en-tête si le fichier n'existait pas&lt;br /&gt;
    if not file_exists:&lt;br /&gt;
        writer.writerow([&amp;quot;Capteur1&amp;quot;, &amp;quot;Capteur2&amp;quot;, &amp;quot;Capteur3&amp;quot;, &amp;quot;Capteur4&amp;quot;, &amp;quot;Capteur5&amp;quot;, &amp;quot;Capteur6&amp;quot;, &amp;quot;Capteur7&amp;quot;, &amp;quot;Capteur8&amp;quot;, &amp;quot;Capteur9&amp;quot;, &amp;quot;Capteur10&amp;quot;, &amp;quot;Capteur11&amp;quot;, &amp;quot;Capteur12&amp;quot;, &amp;quot;Capteur13&amp;quot;, &amp;quot;Capteur14&amp;quot;, &lt;br /&gt;
&amp;quot;Capteur15&amp;quot;, &amp;quot;Capteur16&amp;quot;, &amp;quot;Etiquette&amp;quot;])&lt;br /&gt;
    elif file_exists:&lt;br /&gt;
        writer.writerow([])&lt;br /&gt;
    while True:&lt;br /&gt;
        # Lire une ligne de données depuis l'UART&lt;br /&gt;
        data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
        print(f&amp;quot;Données reçues : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Vérifier si des données ont été reçues&lt;br /&gt;
        if data:&lt;br /&gt;
            # Diviser les données en valeurs individuelles&lt;br /&gt;
            sensor_values = data.split(',')&lt;br /&gt;
&lt;br /&gt;
            # Filtrer les chaînes vides ou non numériques et convertir en flottants&lt;br /&gt;
            try:&lt;br /&gt;
                sensor_values = [float(value) for value in sensor_values if value.strip().isdigit()]&lt;br /&gt;
&lt;br /&gt;
                # Vérifier qu'il y a 16 valeurs de capteur&lt;br /&gt;
                if len(sensor_values) == 16:&lt;br /&gt;
                    sensor_values.append(etiquette)&lt;br /&gt;
                    writer.writerow(sensor_values)&lt;br /&gt;
                else:&lt;br /&gt;
                    print(&amp;quot;Données incomplètes reçues&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            except ValueError as e:&lt;br /&gt;
                print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
                print(f&amp;quot;Données problématiques : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Le script commence par établir une communication série avec le STM32.&lt;br /&gt;
* Il lit ensuite les données en série, les décode et les stocke dans un fichier CSV pour une utilisation ultérieure.&lt;br /&gt;
&lt;br /&gt;
* Une fois les données collectées et stockées dans le fichier CSV, elles sont préparées pour l'entraînement du modèle.&lt;br /&gt;
* Cette préparation implique la normalisation des données, la gestion des valeurs manquantes ou aberrantes, et leur formatage dans un bon format.[[Fichier:Rpi entrainement.png|vignette|1000x1000px|néant]]&lt;br /&gt;
=== 4. Entraînement du Modèle d'Apprentissage Automatique ===&lt;br /&gt;
----L'entraînement du modèle est réalisé par un script Python utilisant la bibliothèque scikit-learn. Le modèle SVM, choisi pour sa capacité à gérer des espaces de grande dimension, est entraîné sur l'ensemble des données collectées. Ce processus comprend la division des données en ensembles d'entraînement et de test, l'entraînement du modèle, et sa validation par le calcul de la précision. Nous avions testé plusieurs modèle, comme par exemple un modèle Knn ou randomForest, des 3 algorithmes, c'est celui qui nous à apporté les meilleurs résultats pour un meme nombre de data d'entrainement. (RandomForest en deuxième position)&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import pandas as pd&lt;br /&gt;
from sklearn.model_selection import train_test_split&lt;br /&gt;
from sklearn.svm import SVC&lt;br /&gt;
from sklearn.metrics import accuracy_score&lt;br /&gt;
import pickle&lt;br /&gt;
&lt;br /&gt;
# Charger vos données&lt;br /&gt;
data = pd.read_csv('data_complete.csv')&lt;br /&gt;
&lt;br /&gt;
# Séparer les caractéristiques et les étiquettes&lt;br /&gt;
X = data.drop('Etiquette', axis=1)&lt;br /&gt;
y = data['Etiquette']&lt;br /&gt;
&lt;br /&gt;
# Diviser les données en ensembles d'entraînement et de test&lt;br /&gt;
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)&lt;br /&gt;
&lt;br /&gt;
# Créer et entraîner le modèle SVM&lt;br /&gt;
model = SVC(kernel='rbf')&lt;br /&gt;
model.fit(X_train, y_train)&lt;br /&gt;
&lt;br /&gt;
# Sauvegarder le modèle entraîné&lt;br /&gt;
with open('modele_svm.pkl', 'wb') as file:&lt;br /&gt;
    pickle.dump(model, file)&lt;br /&gt;
&lt;br /&gt;
# Charger le modèle et faire des prédictions&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    loaded_model = pickle.load(file)&lt;br /&gt;
    predictions = loaded_model.predict(X_test)&lt;br /&gt;
    print(&amp;quot;Précision :&amp;quot;, accuracy_score(y_test, predictions))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# '''Séparation des Données''':&lt;br /&gt;
#* Les données sont divisées en deux ensembles : un ensemble d'entraînement et un ensemble de test. Cette séparation est cruciale pour évaluer objectivement la performance du modèle.&lt;br /&gt;
#* Généralement, on adopte une répartition de 80% pour l'entraînement et 20% pour les tests.&lt;br /&gt;
# '''Entraînement du Modèle SVM''':&lt;br /&gt;
#* Le modèle SVM avec un noyau RBF (Radial Basis Function) est entraîné sur l'ensemble d'entraînement.&lt;br /&gt;
#* L'entraînement implique l'ajustement du modèle aux données d'entraînement, en apprenant à distinguer les différents signes.&lt;br /&gt;
# '''Sauvegarde et Réutilisation du Modèle'''&lt;br /&gt;
#* Une fois entraîné et validé, le modèle est sauvegardé à l'aide de la bibliothèque &amp;lt;code&amp;gt;pickle&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Validation et Évaluation du Modèle''':&lt;br /&gt;
#* Après l'entraînement, le modèle est testé sur l'ensemble de test pour évaluer sa performance.&lt;br /&gt;
#* La métrique principale utilisée est la précision, qui mesure la proportion de prédictions correctes par rapport au total des prédictions.&lt;br /&gt;
&lt;br /&gt;
Ensuite on peut générer le modèle comme ceci:&lt;br /&gt;
[[Fichier:Generate model.png|vignette|399x399px|néant]]&lt;br /&gt;
&lt;br /&gt;
Avec cette prédiction lorsque notre modèle prédit le résultat, il est correct environ 71.81% du temps.&lt;br /&gt;
&lt;br /&gt;
=== 5. Intégration MQTT et Communication ===&lt;br /&gt;
----Protocole de communication  :&lt;br /&gt;
&lt;br /&gt;
Dans le cadre de notre projet, la communication entre les dispositifs Raspberry Pi et le serveur  est établie via le protocole MQTT.&lt;br /&gt;
&lt;br /&gt;
Justification du Choix de MQTT :&lt;br /&gt;
&lt;br /&gt;
Au début du projet, une approche basée sur des sockets IPv6 avait été envisagée pour tirer parti de l'adressage direct et de la simplification de la configuration réseau qu'offre IPv6. Cependant, dans le but de respecter les impératifs de sobriété énergétique et d'assurer une scalabilité optimale du système, permettant ainsi de gérer aisément un nombre croissant de dispositifs Raspberry Pi, la décision a été prise d'adopter MQTT comme protocole de communication. Le protocole MQTT, reconnu pour sa légèreté et sa fiabilité, s'adapte parfaitement aux contraintes des applications IoT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Installation du broker mosquitto sur le serveur:'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
apt install -y mosquitto mosquitto-clients&lt;br /&gt;
service mosquitto start&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Activation de l'accès à distance au Broker Mosquitto:&lt;br /&gt;
&lt;br /&gt;
ajouter l'authentification par username et mot de passe&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
sudo mosquitto_passwd -c /etc/mosquitto/passwd username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
après on nous demande d'entrer le mot de passe &lt;br /&gt;
&lt;br /&gt;
Modifier le fichier /etc/mosquitto/mosquitto.conf:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
listener 1883 10.42.0.5&lt;br /&gt;
allow_anonymous false&lt;br /&gt;
password_file /etc/mosquitto/passwd&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Mosquitto:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
service mosquitto restart&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vérification ds logs:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
cat /var/log/mosquitto/mosquitto.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Création d'un client MQTT sur la Raspberry Pi:'''&lt;br /&gt;
&lt;br /&gt;
Le script mqtt_client_rpi.py joue un rôle clé dans cette architecture en facilitant la communication bidirectionnelle : il permet non seulement l'envoi des prédictions réalisées par le modèle SVM depuis la Raspberry Pi vers le serveur, mais autorise également la réception des commandes de contrôle, telles que les instructions de démarrage ou d'arrêt de la collecte de données.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import serial&lt;br /&gt;
import pandas as pd&lt;br /&gt;
import pickle&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
pi_id = &amp;quot;rpi1234&amp;quot;&lt;br /&gt;
&lt;br /&gt;
collecting_data = False &lt;br /&gt;
&lt;br /&gt;
client = mqtt.Client()&lt;br /&gt;
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)&lt;br /&gt;
client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
client.loop_start()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(f&amp;quot;config/{pi_id}&amp;quot;)&lt;br /&gt;
    client.publish(&amp;quot;raspberry_available&amp;quot;, pi_id)&lt;br /&gt;
&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global collecting_data&lt;br /&gt;
    if msg.topic == f&amp;quot;config/{pi_id}&amp;quot;:&lt;br /&gt;
        command = msg.payload.decode()&lt;br /&gt;
        if command == &amp;quot;start&amp;quot;:&lt;br /&gt;
            collecting_data = True&lt;br /&gt;
        elif command == &amp;quot;stop&amp;quot;:&lt;br /&gt;
            collecting_data = False&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.on_connect = on_connect&lt;br /&gt;
client.on_message = on_message&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Configurez le port série et chargez le modèle ici&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    rf = pickle.load(file)&lt;br /&gt;
try:&lt;br /&gt;
&lt;br /&gt;
    while True:&lt;br /&gt;
        if collecting_data:&lt;br /&gt;
            data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
            if data:&lt;br /&gt;
                try:&lt;br /&gt;
                    sensor_values = [value for value in data.split(',') if value.strip().replace('.', '', 1).isdigit()]&lt;br /&gt;
                    if len(sensor_values) == 16:&lt;br /&gt;
                        sensor_values = list(map(float, sensor_values))&lt;br /&gt;
                        sensor_values_df = pd.DataFrame([sensor_values])&lt;br /&gt;
                        prediction = rf.predict(sensor_values_df)&lt;br /&gt;
                        client.publish(f&amp;quot;telemetry/{pi_id}&amp;quot;, str(prediction[0]).encode())&lt;br /&gt;
                        print(&amp;quot;Prédiction :&amp;quot;, prediction[0])&lt;br /&gt;
                except ValueError as e:&lt;br /&gt;
                    print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:&lt;br /&gt;
    print(&amp;quot;Script interrompu&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.loop_stop()&lt;br /&gt;
client.disconnect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Ici il y a 3 topics différents. lorsqu'une raspberry se connecte au réseau elle publie son ID (qui est unique, on peut prendre par exemple l'adresse MAC) sur le topic raspberry_available. Cela nous servira a savoir quelle raspberry est connecté et de se fait pouvoir afficher celles-ci sur notre interface web.&lt;br /&gt;
&lt;br /&gt;
le deuxième topic et le topic config/ID (avec id l'identifiant unique de la raspberry), il nous sert a envoyer les commandes &amp;quot;start&amp;quot; et &amp;quot;stop&amp;quot; a la raspberry afin qu'elle démarre ou arrête la lecture des datas.&lt;br /&gt;
&lt;br /&gt;
Le troisième topic est le topic telemetry/ID, ou la raspberry vient publier ses données.&lt;br /&gt;
&lt;br /&gt;
Un quatrième topic pourrait être implémenter comme par exemple le topic common_config, toutes les raspberrys serait abonnées a ce topic. S'il est nécessaire, cela nous permettrais d'envoyer la même commande a toutes les raspberry  plutôt que de faire une publication sur chaque config/ID &lt;br /&gt;
&lt;br /&gt;
=== 6. Interface Serveur et Gestion des Données ===&lt;br /&gt;
----Le serveur central, au cœur de notre système, est orchestré par le script &amp;lt;code&amp;gt;app.py&amp;lt;/code&amp;gt; qui exploite le framework Flask pour mettre en place une interface serveur. Cette interface est conçue pour traiter efficacement les requêtes HTTP et les messages MQTT, offrant ainsi une API réactive pour l'interface utilisateur web. Elle permet également de visualiser en temps réel l'état des dispositifs Raspberry Pi connectés et les dernières données traitées.&lt;br /&gt;
[[Fichier:Signspeakweb.png|centré|vignette|1000x1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from flask import Flask, render_template, request, jsonify&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import queue&lt;br /&gt;
&lt;br /&gt;
app = Flask(__name__)&lt;br /&gt;
messages = []&lt;br /&gt;
received_messages = queue.Queue()&lt;br /&gt;
latest_message = None&lt;br /&gt;
subscribed_topics = set()&lt;br /&gt;
raspberry_ids = set()&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client = mqtt.Client()&lt;br /&gt;
mqtt_client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD) &lt;br /&gt;
mqtt_client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
mqtt_client.loop_start()&lt;br /&gt;
&lt;br /&gt;
def send_command_to_pi(pi_id, command):&lt;br /&gt;
    try:&lt;br /&gt;
        topic = f&amp;quot;config/{pi_id}&amp;quot;&lt;br /&gt;
        mqtt_client.publish(topic, command)&lt;br /&gt;
        subscribe_to_pi_telemetry(pi_id)&lt;br /&gt;
        return True, &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
    except Exception as e:&lt;br /&gt;
        return False, f&amp;quot;Commande pas envoyée: Erreur MQTT : {e}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
def subscribe_to_pi_telemetry(pi_id):&lt;br /&gt;
    global subscribed_topics&lt;br /&gt;
    topic = f&amp;quot;telemetry/{pi_id}&amp;quot;&lt;br /&gt;
    if topic not in subscribed_topics:&lt;br /&gt;
        mqtt_client.subscribe(topic)&lt;br /&gt;
        subscribed_topics.add(topic)&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(&amp;quot;raspberry_available&amp;quot;)&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    print(f&amp;quot;Received message on topic {msg.topic}: {msg.payload.decode()}&amp;quot;)  # Ajouter pour le débogage&lt;br /&gt;
    if msg.topic == &amp;quot;raspberry_available&amp;quot;:&lt;br /&gt;
        raspberry_ids.add(msg.payload.decode())&lt;br /&gt;
    else:&lt;br /&gt;
        received_messages.put(msg.payload.decode())&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mqtt_client.on_connect = on_connect&lt;br /&gt;
mqtt_client.on_message = on_message&lt;br /&gt;
@app.route('/get-raspberry-ids')&lt;br /&gt;
def get_raspberry_ids():&lt;br /&gt;
    return jsonify(list(raspberry_ids))&lt;br /&gt;
@app.route('/get-latest-message')&lt;br /&gt;
def get_latest_message():&lt;br /&gt;
    global latest_message&lt;br /&gt;
    while not received_messages.empty():&lt;br /&gt;
        messages.append(received_messages.get())&lt;br /&gt;
&lt;br /&gt;
    latest_message = messages[-1] if messages else None&lt;br /&gt;
    &lt;br /&gt;
    # Ajoutez cet enregistrement de débogage&lt;br /&gt;
    print(f&amp;quot;Contenu de la réponse pour /get-latest-message : {latest_message}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    if latest_message is not None:&lt;br /&gt;
         response = jsonify({&amp;quot;message&amp;quot;: latest_message})&lt;br /&gt;
         return response&lt;br /&gt;
    else:&lt;br /&gt;
        message = &amp;quot;Aucun signe a traduire pour le moment&amp;quot;&lt;br /&gt;
        return jsonify(message)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@app.route('/', methods=['GET', 'POST'])&lt;br /&gt;
&lt;br /&gt;
def index():&lt;br /&gt;
    global raspberry_ids&lt;br /&gt;
    error_message_rpi = None&lt;br /&gt;
    success_message = None&lt;br /&gt;
&lt;br /&gt;
    if request.method == 'POST':&lt;br /&gt;
        pi_id = request.form.get('pi_id')&lt;br /&gt;
        command = request.form.get('command')&lt;br /&gt;
        if pi_id and command in [&amp;quot;start&amp;quot;, &amp;quot;stop&amp;quot;]:&lt;br /&gt;
            success, er_message = send_command_to_pi(pi_id, command)&lt;br /&gt;
            if success:&lt;br /&gt;
                success_message = &amp;quot;Commande envoyée avec succès&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                error_message_rpi = er_message&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    return render_template('index.html', raspberry_ids=list(raspberry_ids), error_message_rpi=error_message_rpi, success_message=success_message, message=latest_message)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    app.run(debug=False, port=8066)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7. Conception de l'Interface Utilisateur ===&lt;br /&gt;
----L'interface utilisateur, développée à l'aide des technologies web standard HTML, CSS, et JavaScript, offre une expérience interactive. Le fichier index.html constitue le point d'entrée de cette interface, proposant des fonctionnalités telles que l'envoi de commandes aux dispositifs Raspberry Pi et la visualisation des données traitées. L'utilisation de JavaScript pour interroger dynamiquement le serveur Flask permet de rafraîchir les informations affichées en temps réel, garantissant ainsi une interface réactive et à jour.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
index.html:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
        body {&lt;br /&gt;
            background-color: #343a40; /* Couleur d'arrière-plan foncé */&lt;br /&gt;
            color: #ced4da; /* Gris clair pour le texte pour un meilleur contraste */&lt;br /&gt;
        }&lt;br /&gt;
        .card {&lt;br /&gt;
            background-color: #495057; /* Fond des encadrés plus sombre */&lt;br /&gt;
        }&lt;br /&gt;
        .card-title, .card-text, .alert {&lt;br /&gt;
            color: #adb5bd; /* Gris plus doux pour les titres, le texte et les alertes */&lt;br /&gt;
        }&lt;br /&gt;
        .btn-primary {&lt;br /&gt;
            background-color: #007bff; /* Bleu Bootstrap par défaut pour les boutons */&lt;br /&gt;
            border-color: #007bff;&lt;br /&gt;
        }&lt;br /&gt;
        .btn-danger {&lt;br /&gt;
            background-color: #dc3545; /* Rouge Bootstrap par défaut pour les boutons d'arrêt */&lt;br /&gt;
            border-color: #dc3545;&lt;br /&gt;
        }&lt;br /&gt;
        .form-control {&lt;br /&gt;
            background-color: #495057; /* Fond des champs de saisie plus sombre */&lt;br /&gt;
            border: 1px solid #6c757d;&lt;br /&gt;
            color: #ced4da; /* Couleur du texte dans les champs de saisie */&lt;br /&gt;
        }&lt;br /&gt;
        a, .btn-secondary {&lt;br /&gt;
            color: #17a2b8; /* Bleu clair pour les liens et les boutons secondaires */&lt;br /&gt;
        }&lt;br /&gt;
        a:hover {&lt;br /&gt;
            color: #138496; /* Bleu plus foncé au survol des liens */&lt;br /&gt;
        }&lt;br /&gt;
        /* Autres styles personnalisés ici */&lt;br /&gt;
        #latest-message {&lt;br /&gt;
            background-color: #596069; /* Couleur de fond plus claire pour l'encadré */&lt;br /&gt;
            border: 1px solid #6c757d; /* Bordure pour distinguer l'encadré */&lt;br /&gt;
            color: #E9ECEF; /* Couleur du texte plus claire pour un meilleur contraste */&lt;br /&gt;
            padding: 10px; /* Espace intérieur pour que le texte ne touche pas les bords */&lt;br /&gt;
            border-radius: 5px; /* Bords arrondis pour l'encadré */&lt;br /&gt;
        }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;container mt-5&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;h1 class=&amp;quot;text-center mb-4&amp;quot;&amp;gt;SignSpeak - Traducteur de Langage des Signes&amp;lt;/h1&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour les Raspberry Pi Disponibles --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-md-12&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Raspberry Pi Disponibles&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;ul id=&amp;quot;raspberry-list&amp;quot; class=&amp;quot;list-group list-group-flush&amp;quot;&amp;gt;&lt;br /&gt;
                            &amp;lt;!-- Les IDs seront ajoutés ici par JavaScript --&amp;gt;&lt;br /&gt;
                        &amp;lt;/ul&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- Encadré pour la Collecte des données --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Collecte de données&amp;lt;/h2&amp;gt;&lt;br /&gt;
                        &amp;lt;form method=&amp;quot;post&amp;quot; class=&amp;quot;form-inline&amp;quot;&amp;gt;&lt;br /&gt;
                            &amp;lt;input type=&amp;quot;text&amp;quot; class=&amp;quot;form-control mb-2 mr-sm-2&amp;quot; name=&amp;quot;pi_id&amp;quot; placeholder=&amp;quot;Entrez l'ID de la Raspberry Pi&amp;quot; required&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-primary mb-2 mr-sm-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;start&amp;quot;&amp;gt;Démarrer la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                            &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;btn btn-danger mb-2&amp;quot; name=&amp;quot;command&amp;quot; value=&amp;quot;stop&amp;quot;&amp;gt;Arrêter la Collecte&amp;lt;/button&amp;gt;&lt;br /&gt;
                        &amp;lt;/form&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;!-- Encadré pour le Dernier Message Reçu --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card-body&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;h2 class=&amp;quot;card-title&amp;quot;&amp;gt;Dernier Message Reçu&amp;lt;/h2&amp;gt;&lt;br /&gt;
                    &amp;lt;div id=&amp;quot;latest-message&amp;quot; class=&amp;quot;alert alert-dark&amp;quot;&amp;gt;&lt;br /&gt;
                        Aucun message reçu pour le moment. &lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;mb-3 text-center&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;a href=&amp;quot;/logs&amp;quot; class=&amp;quot;btn btn-secondary&amp;quot;&amp;gt;Voir les Logs&amp;lt;/a&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        function fetchRaspberryIds() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        var ids = JSON.parse(xhr.responseText);&lt;br /&gt;
                        var list = document.getElementById('raspberry-list');&lt;br /&gt;
                        list.innerHTML = '';&lt;br /&gt;
                        ids.forEach(function(id) {&lt;br /&gt;
                            var li = document.createElement('li');&lt;br /&gt;
                            li.textContent = id;&lt;br /&gt;
                            list.appendChild(li);&lt;br /&gt;
                        });&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-raspberry-ids', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function fetchLatestMessage() {&lt;br /&gt;
            var xhr = new XMLHttpRequest();&lt;br /&gt;
            xhr.onreadystatechange = function() {&lt;br /&gt;
                if (xhr.readyState == XMLHttpRequest.DONE) {&lt;br /&gt;
                    if (xhr.status == 200) {&lt;br /&gt;
                        console.log(xhr.responseText)&lt;br /&gt;
                        document.getElementById('latest-message').textContent = xhr.responseText;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            xhr.open('GET', '/get-latest-message', true);&lt;br /&gt;
            xhr.send();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        setInterval(fetchRaspberryIds, 5000); // Met à jour les IDs toutes les 5 secondes&lt;br /&gt;
        setInterval(fetchLatestMessage, 500); // Met à jour le dernier message toutes les secondes&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;!-- Les messages d'alerte dynamiques ici --&amp;gt;&lt;br /&gt;
    {% if error_message_rpi %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ error_message_rpi }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&lt;br /&gt;
    {% if success_message %}&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        alert(&amp;quot;{{ success_message }}&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 9. Conclusion et Perspectives ===&lt;br /&gt;
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont&lt;br /&gt;
&lt;br /&gt;
== Vidéo ==&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Interfaces_sign.png&amp;diff=4876</id>
		<title>Fichier:Interfaces sign.png</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Interfaces_sign.png&amp;diff=4876"/>
		<updated>2024-01-28T17:08:23Z</updated>

		<summary type="html">&lt;p&gt;Bblack : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;interfaces sign&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4853</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4853"/>
		<updated>2024-01-28T16:47:24Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* 6. Interface Serveur et Gestion des Données */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Compte rendu des séances=&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:IfconfigVM.png|sans_cadre]]&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
mettre la config de la raspberry&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== '''Présentation du projet''' ==&lt;br /&gt;
&lt;br /&gt;
=== 1. Introduction ===&lt;br /&gt;
----Le projet SignSpeak a pour ambition de créer une solution innovante pour la traduction du langage des signes en texte. L'objectif principal est de développer un système capable de capturer les mouvements des mains et de les interpréter en langage des signes, permettant une communication fluide entre les personnes sourdes ou malentendantes et celles qui ne connaissent pas le langage des signes. Ce projet intègre des technologies avancées telles que l'edge computing, l'intelligence artificielle embarquée, et les communications MQTT, offrant une approche novatrice dans le domaine de l'accessibilité et de la communication.&lt;br /&gt;
&lt;br /&gt;
=== 2. Architecture du Système ===&lt;br /&gt;
----Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :&lt;br /&gt;
&lt;br /&gt;
* '''Capteurs et STM32''' : Des capteurs sont connectés à un microcontrôleur STM32, responsables de la capture des mouvements de main. Ces données sont ensuite transmises pour traitement.&lt;br /&gt;
* '''Raspberry Pi''' : Agissant comme un intermédiaire, la Raspberry Pi reçoit les données des capteurs via UART, exécute un traitement préliminaire et communique avec le serveur.&lt;br /&gt;
* '''Serveur et Machine Learning''' : Un serveur, hébergé sur une VM Xen, traite les données à l'aide d'un modèle SVM pour la traduction en langage des signes et fournit une interface web pour l'interaction utilisateur.&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== 3. Collecte et Préparation des Données ===&lt;br /&gt;
----Le processus de collecte des données est géré par le script &amp;lt;code&amp;gt;enregistrementData.py&amp;lt;/code&amp;gt;. Ce script lit les données transmises par le STM32 via UART et les enregistre dans un fichier CSV. Chaque entrée du fichier représente les valeurs de capteurs à un moment donné, accompagnées d'une étiquette correspondant au signe effectué. Cette approche assure une collecte de données structurée, essentielle pour l'entraînement précis du modèle d'apprentissage automatique.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
import csv&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
# Vérification de l'argument d'entrée&lt;br /&gt;
if len(sys.argv) &amp;lt; 2:&lt;br /&gt;
    print(&amp;quot;Usage: python script.py &amp;lt;etiquette&amp;gt;&amp;quot;)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
etiquette = sys.argv[1]&lt;br /&gt;
&lt;br /&gt;
# Paramètres de l'UART&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
&lt;br /&gt;
# Créer une connexion UART&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
&lt;br /&gt;
# Nom du fichier CSV&lt;br /&gt;
filename = f&amp;quot;data_complete.csv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Vérifier si le fichier existe déjà&lt;br /&gt;
file_exists = False&lt;br /&gt;
try:&lt;br /&gt;
    with open(filename, 'r') as f:&lt;br /&gt;
        file_exists = True&lt;br /&gt;
except FileNotFoundError:&lt;br /&gt;
    file_exists = False&lt;br /&gt;
&lt;br /&gt;
# Ouvrir le fichier CSV en mode append&lt;br /&gt;
with open(filename, 'a', newline='') as file:&lt;br /&gt;
    writer = csv.writer(file)&lt;br /&gt;
&lt;br /&gt;
    # Écrire l'en-tête si le fichier n'existait pas&lt;br /&gt;
    if not file_exists:&lt;br /&gt;
        writer.writerow([&amp;quot;Capteur1&amp;quot;, &amp;quot;Capteur2&amp;quot;, &amp;quot;Capteur3&amp;quot;, &amp;quot;Capteur4&amp;quot;, &amp;quot;Capteur5&amp;quot;, &amp;quot;Capteur6&amp;quot;, &amp;quot;Capteur7&amp;quot;, &amp;quot;Capteur8&amp;quot;, &amp;quot;Capteur9&amp;quot;, &amp;quot;Capteur10&amp;quot;, &amp;quot;Capteur11&amp;quot;, &amp;quot;Capteur12&amp;quot;, &amp;quot;Capteur13&amp;quot;, &amp;quot;Capteur14&amp;quot;, &lt;br /&gt;
&amp;quot;Capteur15&amp;quot;, &amp;quot;Capteur16&amp;quot;, &amp;quot;Etiquette&amp;quot;])&lt;br /&gt;
    elif file_exists:&lt;br /&gt;
        writer.writerow([])&lt;br /&gt;
    while True:&lt;br /&gt;
        # Lire une ligne de données depuis l'UART&lt;br /&gt;
        data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
        print(f&amp;quot;Données reçues : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Vérifier si des données ont été reçues&lt;br /&gt;
        if data:&lt;br /&gt;
            # Diviser les données en valeurs individuelles&lt;br /&gt;
            sensor_values = data.split(',')&lt;br /&gt;
&lt;br /&gt;
            # Filtrer les chaînes vides ou non numériques et convertir en flottants&lt;br /&gt;
            try:&lt;br /&gt;
                sensor_values = [float(value) for value in sensor_values if value.strip().isdigit()]&lt;br /&gt;
&lt;br /&gt;
                # Vérifier qu'il y a 16 valeurs de capteur&lt;br /&gt;
                if len(sensor_values) == 16:&lt;br /&gt;
                    sensor_values.append(etiquette)&lt;br /&gt;
                    writer.writerow(sensor_values)&lt;br /&gt;
                else:&lt;br /&gt;
                    print(&amp;quot;Données incomplètes reçues&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            except ValueError as e:&lt;br /&gt;
                print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
                print(f&amp;quot;Données problématiques : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Le script commence par établir une communication série avec le STM32.&lt;br /&gt;
* Il lit ensuite les données en série, les décode et les stocke dans un fichier CSV pour une utilisation ultérieure.&lt;br /&gt;
&lt;br /&gt;
* Une fois les données collectées et stockées dans le fichier CSV, elles sont préparées pour l'entraînement du modèle.&lt;br /&gt;
* Cette préparation implique la normalisation des données, la gestion des valeurs manquantes ou aberrantes, et leur formatage dans un bon format.[[Fichier:Rpi entrainement.png|vignette|1000x1000px|néant]]&lt;br /&gt;
=== 4. Entraînement du Modèle d'Apprentissage Automatique ===&lt;br /&gt;
----L'entraînement du modèle est réalisé par un script Python utilisant la bibliothèque scikit-learn. Le modèle SVM, choisi pour sa capacité à gérer des espaces de grande dimension, est entraîné sur l'ensemble des données collectées. Ce processus comprend la division des données en ensembles d'entraînement et de test, l'entraînement du modèle, et sa validation par le calcul de la précision. Nous avions testé plusieurs modèle, comme par exemple un modèle Knn ou randomForest, des 3 algorithmes, c'est celui qui nous à apporté les meilleurs résultats pour un meme nombre de data d'entrainement. (RandomForest en deuxième position)&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import pandas as pd&lt;br /&gt;
from sklearn.model_selection import train_test_split&lt;br /&gt;
from sklearn.svm import SVC&lt;br /&gt;
from sklearn.metrics import accuracy_score&lt;br /&gt;
import pickle&lt;br /&gt;
&lt;br /&gt;
# Charger vos données&lt;br /&gt;
data = pd.read_csv('data_complete.csv')&lt;br /&gt;
&lt;br /&gt;
# Séparer les caractéristiques et les étiquettes&lt;br /&gt;
X = data.drop('Etiquette', axis=1)&lt;br /&gt;
y = data['Etiquette']&lt;br /&gt;
&lt;br /&gt;
# Diviser les données en ensembles d'entraînement et de test&lt;br /&gt;
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)&lt;br /&gt;
&lt;br /&gt;
# Créer et entraîner le modèle SVM&lt;br /&gt;
model = SVC(kernel='rbf')&lt;br /&gt;
model.fit(X_train, y_train)&lt;br /&gt;
&lt;br /&gt;
# Sauvegarder le modèle entraîné&lt;br /&gt;
with open('modele_svm.pkl', 'wb') as file:&lt;br /&gt;
    pickle.dump(model, file)&lt;br /&gt;
&lt;br /&gt;
# Charger le modèle et faire des prédictions&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    loaded_model = pickle.load(file)&lt;br /&gt;
    predictions = loaded_model.predict(X_test)&lt;br /&gt;
    print(&amp;quot;Précision :&amp;quot;, accuracy_score(y_test, predictions))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# '''Séparation des Données''':&lt;br /&gt;
#* Les données sont divisées en deux ensembles : un ensemble d'entraînement et un ensemble de test. Cette séparation est cruciale pour évaluer objectivement la performance du modèle.&lt;br /&gt;
#* Généralement, on adopte une répartition de 80% pour l'entraînement et 20% pour les tests.&lt;br /&gt;
# '''Entraînement du Modèle SVM''':&lt;br /&gt;
#* Le modèle SVM avec un noyau RBF (Radial Basis Function) est entraîné sur l'ensemble d'entraînement.&lt;br /&gt;
#* L'entraînement implique l'ajustement du modèle aux données d'entraînement, en apprenant à distinguer les différents signes.&lt;br /&gt;
# '''Sauvegarde et Réutilisation du Modèle'''&lt;br /&gt;
#* Une fois entraîné et validé, le modèle est sauvegardé à l'aide de la bibliothèque &amp;lt;code&amp;gt;pickle&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Validation et Évaluation du Modèle''':&lt;br /&gt;
#* Après l'entraînement, le modèle est testé sur l'ensemble de test pour évaluer sa performance.&lt;br /&gt;
#* La métrique principale utilisée est la précision, qui mesure la proportion de prédictions correctes par rapport au total des prédictions.&lt;br /&gt;
&lt;br /&gt;
Ensuite on peut générer le modèle comme ceci:&lt;br /&gt;
[[Fichier:Generate model.png|vignette|399x399px|néant]]&lt;br /&gt;
&lt;br /&gt;
Avec cette prédiction lorsque notre modèle prédit le résultat, il est correct environ 71.81% du temps.&lt;br /&gt;
&lt;br /&gt;
=== 5. Intégration MQTT et Communication ===&lt;br /&gt;
----Protocole de communication  :&lt;br /&gt;
&lt;br /&gt;
Dans le cadre de notre projet, la communication entre les dispositifs Raspberry Pi et le serveur  est établie via le protocole MQTT.&lt;br /&gt;
&lt;br /&gt;
Justification du Choix de MQTT :&lt;br /&gt;
&lt;br /&gt;
Au début du projet, une approche basée sur des sockets IPv6 avait été envisagée pour tirer parti de l'adressage direct et de la simplification de la configuration réseau qu'offre IPv6. Cependant, dans le but de respecter les impératifs de sobriété énergétique et d'assurer une scalabilité optimale du système, permettant ainsi de gérer aisément un nombre croissant de dispositifs Raspberry Pi, la décision a été prise d'adopter MQTT comme protocole de communication. Le protocole MQTT, reconnu pour sa légèreté et sa fiabilité, s'adapte parfaitement aux contraintes des applications IoT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Installation du broker mosquitto sur le serveur:'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
apt install -y mosquitto mosquitto-clients&lt;br /&gt;
service mosquitto start&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Activation de l'accès à distance au Broker Mosquitto:&lt;br /&gt;
&lt;br /&gt;
ajouter l'authentification par username et mot de passe&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
sudo mosquitto_passwd -c /etc/mosquitto/passwd username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
après on nous demande d'entrer le mot de passe &lt;br /&gt;
&lt;br /&gt;
Modifier le fichier /etc/mosquitto/mosquitto.conf:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
listener 1883 10.42.0.5&lt;br /&gt;
allow_anonymous false&lt;br /&gt;
password_file /etc/mosquitto/passwd&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Mosquitto:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
service mosquitto restart&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vérification ds logs:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
cat /var/log/mosquitto/mosquitto.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Création d'un client MQTT sur la Raspberry Pi:'''&lt;br /&gt;
&lt;br /&gt;
Le script mqtt_client_rpi.py joue un rôle clé dans cette architecture en facilitant la communication bidirectionnelle : il permet non seulement l'envoi des prédictions réalisées par le modèle SVM depuis la Raspberry Pi vers le serveur, mais autorise également la réception des commandes de contrôle, telles que les instructions de démarrage ou d'arrêt de la collecte de données.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import serial&lt;br /&gt;
import pandas as pd&lt;br /&gt;
import pickle&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
pi_id = &amp;quot;rpi1234&amp;quot;&lt;br /&gt;
&lt;br /&gt;
collecting_data = False &lt;br /&gt;
&lt;br /&gt;
client = mqtt.Client()&lt;br /&gt;
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)&lt;br /&gt;
client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
client.loop_start()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(f&amp;quot;config/{pi_id}&amp;quot;)&lt;br /&gt;
    client.publish(&amp;quot;raspberry_available&amp;quot;, pi_id)&lt;br /&gt;
&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global collecting_data&lt;br /&gt;
    if msg.topic == f&amp;quot;config/{pi_id}&amp;quot;:&lt;br /&gt;
        command = msg.payload.decode()&lt;br /&gt;
        if command == &amp;quot;start&amp;quot;:&lt;br /&gt;
            collecting_data = True&lt;br /&gt;
        elif command == &amp;quot;stop&amp;quot;:&lt;br /&gt;
            collecting_data = False&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.on_connect = on_connect&lt;br /&gt;
client.on_message = on_message&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Configurez le port série et chargez le modèle ici&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    rf = pickle.load(file)&lt;br /&gt;
try:&lt;br /&gt;
&lt;br /&gt;
    while True:&lt;br /&gt;
        if collecting_data:&lt;br /&gt;
            data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
            if data:&lt;br /&gt;
                try:&lt;br /&gt;
                    sensor_values = [value for value in data.split(',') if value.strip().replace('.', '', 1).isdigit()]&lt;br /&gt;
                    if len(sensor_values) == 16:&lt;br /&gt;
                        sensor_values = list(map(float, sensor_values))&lt;br /&gt;
                        sensor_values_df = pd.DataFrame([sensor_values])&lt;br /&gt;
                        prediction = rf.predict(sensor_values_df)&lt;br /&gt;
                        client.publish(f&amp;quot;telemetry/{pi_id}&amp;quot;, str(prediction[0]).encode())&lt;br /&gt;
                        print(&amp;quot;Prédiction :&amp;quot;, prediction[0])&lt;br /&gt;
                except ValueError as e:&lt;br /&gt;
                    print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:&lt;br /&gt;
    print(&amp;quot;Script interrompu&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.loop_stop()&lt;br /&gt;
client.disconnect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Ici il y a 3 topics différents. lorsqu'une raspberry se connecte au réseau elle publie son ID (qui est unique, on peut prendre par exemple l'adresse MAC) sur le topic raspberry_available. Cela nous servira a savoir quelle raspberry est connecté et de se fait pouvoir afficher celles-ci sur notre interface web.&lt;br /&gt;
&lt;br /&gt;
le deuxième topic et le topic config/ID (avec id l'identifiant unique de la raspberry), il nous sert a envoyer les commandes &amp;quot;start&amp;quot; et &amp;quot;stop&amp;quot; a la raspberry afin qu'elle démarre ou arrête la lecture des datas.&lt;br /&gt;
&lt;br /&gt;
Le troisième topic est le topic telemetry/ID, ou la raspberry vient publier ses données.&lt;br /&gt;
&lt;br /&gt;
Un quatrième topic pourrait être implémenter comme par exemple le topic common_config, toutes les raspberrys serait abonnées a ce topic. S'il est nécessaire, cela nous permettrais d'envoyer la même commande a toutes les raspberry  plutôt que de faire une publication sur chaque config/ID &lt;br /&gt;
&lt;br /&gt;
=== 6. Interface Serveur et Gestion des Données ===&lt;br /&gt;
----Le script &amp;lt;code&amp;gt;app.py&amp;lt;/code&amp;gt; crée une interface serveur utilisant Flask. Cette interface gère les requêtes entrantes, les messages MQTT, et fournit une API pour l'interface utilisateur web. Elle permet également de visualiser les Raspberry Pi disponibles et les derniers messages traduits.&lt;br /&gt;
&lt;br /&gt;
=== 7. Conception de l'Interface Utilisateur ===&lt;br /&gt;
----L'interface utilisateur est développée en HTML, CSS et JavaScript. Le fichier &amp;lt;code&amp;gt;index.html&amp;lt;/code&amp;gt; fournit une interface claire et intuitive pour l'envoi de commandes et la visualisation des traductions. L'utilisation de JavaScript pour interroger dynamiquement le serveur Flask permet une mise à jour en temps réel des informations affichées.&lt;br /&gt;
&lt;br /&gt;
=== 9. Conclusion et Perspectives ===&lt;br /&gt;
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4840</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4840"/>
		<updated>2024-01-28T16:34:19Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* Raspberry-Pi */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Compte rendu des séances=&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:IfconfigVM.png|sans_cadre]]&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
mettre la config de la raspberry&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== '''Présentation du projet''' ==&lt;br /&gt;
&lt;br /&gt;
=== 1. Introduction ===&lt;br /&gt;
----Le projet SignSpeak a pour ambition de créer une solution innovante pour la traduction du langage des signes en texte. L'objectif principal est de développer un système capable de capturer les mouvements des mains et de les interpréter en langage des signes, permettant une communication fluide entre les personnes sourdes ou malentendantes et celles qui ne connaissent pas le langage des signes. Ce projet intègre des technologies avancées telles que l'edge computing, l'intelligence artificielle embarquée, et les communications MQTT, offrant une approche novatrice dans le domaine de l'accessibilité et de la communication.&lt;br /&gt;
&lt;br /&gt;
=== 2. Architecture du Système ===&lt;br /&gt;
----Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :&lt;br /&gt;
&lt;br /&gt;
* '''Capteurs et STM32''' : Des capteurs sont connectés à un microcontrôleur STM32, responsables de la capture des mouvements de main. Ces données sont ensuite transmises pour traitement.&lt;br /&gt;
* '''Raspberry Pi''' : Agissant comme un intermédiaire, la Raspberry Pi reçoit les données des capteurs via UART, exécute un traitement préliminaire et communique avec le serveur.&lt;br /&gt;
* '''Serveur et Machine Learning''' : Un serveur, hébergé sur une VM Xen, traite les données à l'aide d'un modèle SVM pour la traduction en langage des signes et fournit une interface web pour l'interaction utilisateur.&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== 3. Collecte et Préparation des Données ===&lt;br /&gt;
----Le processus de collecte des données est géré par le script &amp;lt;code&amp;gt;enregistrementData.py&amp;lt;/code&amp;gt;. Ce script lit les données transmises par le STM32 via UART et les enregistre dans un fichier CSV. Chaque entrée du fichier représente les valeurs de capteurs à un moment donné, accompagnées d'une étiquette correspondant au signe effectué. Cette approche assure une collecte de données structurée, essentielle pour l'entraînement précis du modèle d'apprentissage automatique.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
import csv&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
# Vérification de l'argument d'entrée&lt;br /&gt;
if len(sys.argv) &amp;lt; 2:&lt;br /&gt;
    print(&amp;quot;Usage: python script.py &amp;lt;etiquette&amp;gt;&amp;quot;)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
etiquette = sys.argv[1]&lt;br /&gt;
&lt;br /&gt;
# Paramètres de l'UART&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
&lt;br /&gt;
# Créer une connexion UART&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
&lt;br /&gt;
# Nom du fichier CSV&lt;br /&gt;
filename = f&amp;quot;data_complete.csv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Vérifier si le fichier existe déjà&lt;br /&gt;
file_exists = False&lt;br /&gt;
try:&lt;br /&gt;
    with open(filename, 'r') as f:&lt;br /&gt;
        file_exists = True&lt;br /&gt;
except FileNotFoundError:&lt;br /&gt;
    file_exists = False&lt;br /&gt;
&lt;br /&gt;
# Ouvrir le fichier CSV en mode append&lt;br /&gt;
with open(filename, 'a', newline='') as file:&lt;br /&gt;
    writer = csv.writer(file)&lt;br /&gt;
&lt;br /&gt;
    # Écrire l'en-tête si le fichier n'existait pas&lt;br /&gt;
    if not file_exists:&lt;br /&gt;
        writer.writerow([&amp;quot;Capteur1&amp;quot;, &amp;quot;Capteur2&amp;quot;, &amp;quot;Capteur3&amp;quot;, &amp;quot;Capteur4&amp;quot;, &amp;quot;Capteur5&amp;quot;, &amp;quot;Capteur6&amp;quot;, &amp;quot;Capteur7&amp;quot;, &amp;quot;Capteur8&amp;quot;, &amp;quot;Capteur9&amp;quot;, &amp;quot;Capteur10&amp;quot;, &amp;quot;Capteur11&amp;quot;, &amp;quot;Capteur12&amp;quot;, &amp;quot;Capteur13&amp;quot;, &amp;quot;Capteur14&amp;quot;, &lt;br /&gt;
&amp;quot;Capteur15&amp;quot;, &amp;quot;Capteur16&amp;quot;, &amp;quot;Etiquette&amp;quot;])&lt;br /&gt;
    elif file_exists:&lt;br /&gt;
        writer.writerow([])&lt;br /&gt;
    while True:&lt;br /&gt;
        # Lire une ligne de données depuis l'UART&lt;br /&gt;
        data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
        print(f&amp;quot;Données reçues : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Vérifier si des données ont été reçues&lt;br /&gt;
        if data:&lt;br /&gt;
            # Diviser les données en valeurs individuelles&lt;br /&gt;
            sensor_values = data.split(',')&lt;br /&gt;
&lt;br /&gt;
            # Filtrer les chaînes vides ou non numériques et convertir en flottants&lt;br /&gt;
            try:&lt;br /&gt;
                sensor_values = [float(value) for value in sensor_values if value.strip().isdigit()]&lt;br /&gt;
&lt;br /&gt;
                # Vérifier qu'il y a 16 valeurs de capteur&lt;br /&gt;
                if len(sensor_values) == 16:&lt;br /&gt;
                    sensor_values.append(etiquette)&lt;br /&gt;
                    writer.writerow(sensor_values)&lt;br /&gt;
                else:&lt;br /&gt;
                    print(&amp;quot;Données incomplètes reçues&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            except ValueError as e:&lt;br /&gt;
                print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
                print(f&amp;quot;Données problématiques : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Le script commence par établir une communication série avec le STM32.&lt;br /&gt;
* Il lit ensuite les données en série, les décode et les stocke dans un fichier CSV pour une utilisation ultérieure.&lt;br /&gt;
&lt;br /&gt;
* Une fois les données collectées et stockées dans le fichier CSV, elles sont préparées pour l'entraînement du modèle.&lt;br /&gt;
* Cette préparation implique la normalisation des données, la gestion des valeurs manquantes ou aberrantes, et leur formatage dans un bon format.[[Fichier:Rpi entrainement.png|vignette|1000x1000px|néant]]&lt;br /&gt;
=== 4. Entraînement du Modèle d'Apprentissage Automatique ===&lt;br /&gt;
----L'entraînement du modèle est réalisé par un script Python utilisant la bibliothèque scikit-learn. Le modèle SVM, choisi pour sa capacité à gérer des espaces de grande dimension, est entraîné sur l'ensemble des données collectées. Ce processus comprend la division des données en ensembles d'entraînement et de test, l'entraînement du modèle, et sa validation par le calcul de la précision. Nous avions testé plusieurs modèle, comme par exemple un modèle Knn ou randomForest, des 3 algorithmes, c'est celui qui nous à apporté les meilleurs résultats pour un meme nombre de data d'entrainement. (RandomForest en deuxième position)&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import pandas as pd&lt;br /&gt;
from sklearn.model_selection import train_test_split&lt;br /&gt;
from sklearn.svm import SVC&lt;br /&gt;
from sklearn.metrics import accuracy_score&lt;br /&gt;
import pickle&lt;br /&gt;
&lt;br /&gt;
# Charger vos données&lt;br /&gt;
data = pd.read_csv('data_complete.csv')&lt;br /&gt;
&lt;br /&gt;
# Séparer les caractéristiques et les étiquettes&lt;br /&gt;
X = data.drop('Etiquette', axis=1)&lt;br /&gt;
y = data['Etiquette']&lt;br /&gt;
&lt;br /&gt;
# Diviser les données en ensembles d'entraînement et de test&lt;br /&gt;
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)&lt;br /&gt;
&lt;br /&gt;
# Créer et entraîner le modèle SVM&lt;br /&gt;
model = SVC(kernel='rbf')&lt;br /&gt;
model.fit(X_train, y_train)&lt;br /&gt;
&lt;br /&gt;
# Sauvegarder le modèle entraîné&lt;br /&gt;
with open('modele_svm.pkl', 'wb') as file:&lt;br /&gt;
    pickle.dump(model, file)&lt;br /&gt;
&lt;br /&gt;
# Charger le modèle et faire des prédictions&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    loaded_model = pickle.load(file)&lt;br /&gt;
    predictions = loaded_model.predict(X_test)&lt;br /&gt;
    print(&amp;quot;Précision :&amp;quot;, accuracy_score(y_test, predictions))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# '''Séparation des Données''':&lt;br /&gt;
#* Les données sont divisées en deux ensembles : un ensemble d'entraînement et un ensemble de test. Cette séparation est cruciale pour évaluer objectivement la performance du modèle.&lt;br /&gt;
#* Généralement, on adopte une répartition de 80% pour l'entraînement et 20% pour les tests.&lt;br /&gt;
# '''Entraînement du Modèle SVM''':&lt;br /&gt;
#* Le modèle SVM avec un noyau RBF (Radial Basis Function) est entraîné sur l'ensemble d'entraînement.&lt;br /&gt;
#* L'entraînement implique l'ajustement du modèle aux données d'entraînement, en apprenant à distinguer les différents signes.&lt;br /&gt;
# '''Sauvegarde et Réutilisation du Modèle'''&lt;br /&gt;
#* Une fois entraîné et validé, le modèle est sauvegardé à l'aide de la bibliothèque &amp;lt;code&amp;gt;pickle&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Validation et Évaluation du Modèle''':&lt;br /&gt;
#* Après l'entraînement, le modèle est testé sur l'ensemble de test pour évaluer sa performance.&lt;br /&gt;
#* La métrique principale utilisée est la précision, qui mesure la proportion de prédictions correctes par rapport au total des prédictions.&lt;br /&gt;
&lt;br /&gt;
Ensuite on peut générer le modèle comme ceci:&lt;br /&gt;
[[Fichier:Generate model.png|vignette|399x399px|néant]]&lt;br /&gt;
&lt;br /&gt;
Avec cette prédiction lorsque notre modèle prédit le résultat, il est correct environ 71.81% du temps.&lt;br /&gt;
&lt;br /&gt;
=== 5. Intégration MQTT et Communication ===&lt;br /&gt;
----Protocole de communication  :&lt;br /&gt;
&lt;br /&gt;
Dans le cadre de notre projet, la communication entre les dispositifs Raspberry Pi et le serveur  est établie via le protocole MQTT.&lt;br /&gt;
&lt;br /&gt;
Justification du Choix de MQTT :&lt;br /&gt;
&lt;br /&gt;
Au début du projet, une approche basée sur des sockets IPv6 avait été envisagée pour tirer parti de l'adressage direct et de la simplification de la configuration réseau qu'offre IPv6. Cependant, dans le but de respecter les impératifs de sobriété énergétique et d'assurer une scalabilité optimale du système, permettant ainsi de gérer aisément un nombre croissant de dispositifs Raspberry Pi, la décision a été prise d'adopter MQTT comme protocole de communication. Le protocole MQTT, reconnu pour sa légèreté et sa fiabilité, s'adapte parfaitement aux contraintes des applications IoT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Installation du broker mosquitto sur le serveur:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
apt install -y mosquitto mosquitto-clients&lt;br /&gt;
service mosquitto start&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Activation de l'accès à distance au Broker Mosquitto:&lt;br /&gt;
&lt;br /&gt;
ajouter l'authentification par username et mot de passe&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
sudo mosquitto_passwd -c /etc/mosquitto/passwd username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
après on nous demande d'entrer le mot de passe &lt;br /&gt;
&lt;br /&gt;
Modifier le fichier /etc/mosquitto/mosquitto.conf:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
listener 1883 10.42.0.5&lt;br /&gt;
allow_anonymous false&lt;br /&gt;
password_file /etc/mosquitto/passwd&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Mosquitto:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
service mosquitto restart&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vérification ds logs:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
cat /var/log/mosquitto/mosquitto.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import paho.mqtt.client as mqtt&lt;br /&gt;
import serial&lt;br /&gt;
import pandas as pd&lt;br /&gt;
import pickle&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MQTT_BROKER_ADDRESS = &amp;quot;10.42.0.5&amp;quot;&lt;br /&gt;
MQTT_USERNAME = &amp;quot;username&amp;quot;&lt;br /&gt;
MQTT_PASSWORD = &amp;quot;confidentiel&amp;quot;&lt;br /&gt;
pi_id = &amp;quot;rpi1234&amp;quot;&lt;br /&gt;
&lt;br /&gt;
collecting_data = False &lt;br /&gt;
&lt;br /&gt;
client = mqtt.Client()&lt;br /&gt;
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)&lt;br /&gt;
client.connect(MQTT_BROKER_ADDRESS, 1883, 60)&lt;br /&gt;
client.loop_start()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def on_connect(client, userdata, flags, rc):&lt;br /&gt;
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))&lt;br /&gt;
    client.subscribe(f&amp;quot;config/{pi_id}&amp;quot;)&lt;br /&gt;
    client.publish(&amp;quot;raspberry_available&amp;quot;, pi_id)&lt;br /&gt;
&lt;br /&gt;
def on_message(client, userdata, msg):&lt;br /&gt;
    global collecting_data&lt;br /&gt;
    if msg.topic == f&amp;quot;config/{pi_id}&amp;quot;:&lt;br /&gt;
        command = msg.payload.decode()&lt;br /&gt;
        if command == &amp;quot;start&amp;quot;:&lt;br /&gt;
            collecting_data = True&lt;br /&gt;
        elif command == &amp;quot;stop&amp;quot;:&lt;br /&gt;
            collecting_data = False&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.on_connect = on_connect&lt;br /&gt;
client.on_message = on_message&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Configurez le port série et chargez le modèle ici&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    rf = pickle.load(file)&lt;br /&gt;
try:&lt;br /&gt;
&lt;br /&gt;
    while True:&lt;br /&gt;
        if collecting_data:&lt;br /&gt;
            data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
            if data:&lt;br /&gt;
                try:&lt;br /&gt;
                    sensor_values = [value for value in data.split(',') if value.strip().replace('.', '', 1).isdigit()]&lt;br /&gt;
                    if len(sensor_values) == 16:&lt;br /&gt;
                        sensor_values = list(map(float, sensor_values))&lt;br /&gt;
                        sensor_values_df = pd.DataFrame([sensor_values])&lt;br /&gt;
                        prediction = rf.predict(sensor_values_df)&lt;br /&gt;
                        client.publish(f&amp;quot;telemetry/{pi_id}&amp;quot;, str(prediction[0]).encode())&lt;br /&gt;
                        print(&amp;quot;Prédiction :&amp;quot;, prediction[0])&lt;br /&gt;
                except ValueError as e:&lt;br /&gt;
                    print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
except KeyboardInterrupt:&lt;br /&gt;
    print(&amp;quot;Script interrompu&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
client.loop_stop()&lt;br /&gt;
client.disconnect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6. Interface Serveur et Gestion des Données ===&lt;br /&gt;
----Le script &amp;lt;code&amp;gt;app.py&amp;lt;/code&amp;gt; crée une interface serveur utilisant Flask. Cette interface gère les requêtes entrantes, les messages MQTT, et fournit une API pour l'interface utilisateur web. Elle permet également de visualiser les Raspberry Pi disponibles et les derniers messages traduits.&lt;br /&gt;
&lt;br /&gt;
=== 7. Conception de l'Interface Utilisateur ===&lt;br /&gt;
----L'interface utilisateur est développée en HTML, CSS et JavaScript. Le fichier &amp;lt;code&amp;gt;index.html&amp;lt;/code&amp;gt; fournit une interface claire et intuitive pour l'envoi de commandes et la visualisation des traductions. L'utilisation de JavaScript pour interroger dynamiquement le serveur Flask permet une mise à jour en temps réel des informations affichées.&lt;br /&gt;
&lt;br /&gt;
=== 9. Conclusion et Perspectives ===&lt;br /&gt;
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4837</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4837"/>
		<updated>2024-01-28T16:30:19Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* Raspberry-Pi */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Compte rendu des séances=&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:IfconfigVM.png|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
mettre la config de la raspberry&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1. Introduction ===&lt;br /&gt;
----Le projet SignSpeak a pour ambition de créer une solution innovante pour la traduction du langage des signes en texte. L'objectif principal est de développer un système capable de capturer les mouvements des mains et de les interpréter en langage des signes, permettant une communication fluide entre les personnes sourdes ou malentendantes et celles qui ne connaissent pas le langage des signes. Ce projet intègre des technologies avancées telles que l'edge computing, l'intelligence artificielle embarquée, et les communications MQTT, offrant une approche novatrice dans le domaine de l'accessibilité et de la communication.&lt;br /&gt;
&lt;br /&gt;
=== 2. Architecture du Système ===&lt;br /&gt;
----Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :&lt;br /&gt;
&lt;br /&gt;
* '''Capteurs et STM32''' : Des capteurs sont connectés à un microcontrôleur STM32, responsables de la capture des mouvements de main. Ces données sont ensuite transmises pour traitement.&lt;br /&gt;
* '''Raspberry Pi''' : Agissant comme un intermédiaire, la Raspberry Pi reçoit les données des capteurs via UART, exécute un traitement préliminaire et communique avec le serveur.&lt;br /&gt;
* '''Serveur et Machine Learning''' : Un serveur, hébergé sur une VM Xen, traite les données à l'aide d'un modèle SVM pour la traduction en langage des signes et fournit une interface web pour l'interaction utilisateur.&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== 3. Collecte et Préparation des Données ===&lt;br /&gt;
----Le processus de collecte des données est géré par le script &amp;lt;code&amp;gt;enregistrementData.py&amp;lt;/code&amp;gt;. Ce script lit les données transmises par le STM32 via UART et les enregistre dans un fichier CSV. Chaque entrée du fichier représente les valeurs de capteurs à un moment donné, accompagnées d'une étiquette correspondant au signe effectué. Cette approche assure une collecte de données structurée, essentielle pour l'entraînement précis du modèle d'apprentissage automatique.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
import csv&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
# Vérification de l'argument d'entrée&lt;br /&gt;
if len(sys.argv) &amp;lt; 2:&lt;br /&gt;
    print(&amp;quot;Usage: python script.py &amp;lt;etiquette&amp;gt;&amp;quot;)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
etiquette = sys.argv[1]&lt;br /&gt;
&lt;br /&gt;
# Paramètres de l'UART&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
&lt;br /&gt;
# Créer une connexion UART&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
&lt;br /&gt;
# Nom du fichier CSV&lt;br /&gt;
filename = f&amp;quot;data_complete.csv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Vérifier si le fichier existe déjà&lt;br /&gt;
file_exists = False&lt;br /&gt;
try:&lt;br /&gt;
    with open(filename, 'r') as f:&lt;br /&gt;
        file_exists = True&lt;br /&gt;
except FileNotFoundError:&lt;br /&gt;
    file_exists = False&lt;br /&gt;
&lt;br /&gt;
# Ouvrir le fichier CSV en mode append&lt;br /&gt;
with open(filename, 'a', newline='') as file:&lt;br /&gt;
    writer = csv.writer(file)&lt;br /&gt;
&lt;br /&gt;
    # Écrire l'en-tête si le fichier n'existait pas&lt;br /&gt;
    if not file_exists:&lt;br /&gt;
        writer.writerow([&amp;quot;Capteur1&amp;quot;, &amp;quot;Capteur2&amp;quot;, &amp;quot;Capteur3&amp;quot;, &amp;quot;Capteur4&amp;quot;, &amp;quot;Capteur5&amp;quot;, &amp;quot;Capteur6&amp;quot;, &amp;quot;Capteur7&amp;quot;, &amp;quot;Capteur8&amp;quot;, &amp;quot;Capteur9&amp;quot;, &amp;quot;Capteur10&amp;quot;, &amp;quot;Capteur11&amp;quot;, &amp;quot;Capteur12&amp;quot;, &amp;quot;Capteur13&amp;quot;, &amp;quot;Capteur14&amp;quot;, &lt;br /&gt;
&amp;quot;Capteur15&amp;quot;, &amp;quot;Capteur16&amp;quot;, &amp;quot;Etiquette&amp;quot;])&lt;br /&gt;
    elif file_exists:&lt;br /&gt;
        writer.writerow([])&lt;br /&gt;
    while True:&lt;br /&gt;
        # Lire une ligne de données depuis l'UART&lt;br /&gt;
        data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
        print(f&amp;quot;Données reçues : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Vérifier si des données ont été reçues&lt;br /&gt;
        if data:&lt;br /&gt;
            # Diviser les données en valeurs individuelles&lt;br /&gt;
            sensor_values = data.split(',')&lt;br /&gt;
&lt;br /&gt;
            # Filtrer les chaînes vides ou non numériques et convertir en flottants&lt;br /&gt;
            try:&lt;br /&gt;
                sensor_values = [float(value) for value in sensor_values if value.strip().isdigit()]&lt;br /&gt;
&lt;br /&gt;
                # Vérifier qu'il y a 16 valeurs de capteur&lt;br /&gt;
                if len(sensor_values) == 16:&lt;br /&gt;
                    sensor_values.append(etiquette)&lt;br /&gt;
                    writer.writerow(sensor_values)&lt;br /&gt;
                else:&lt;br /&gt;
                    print(&amp;quot;Données incomplètes reçues&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            except ValueError as e:&lt;br /&gt;
                print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
                print(f&amp;quot;Données problématiques : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Le script commence par établir une communication série avec le STM32.&lt;br /&gt;
* Il lit ensuite les données en série, les décode et les stocke dans un fichier CSV pour une utilisation ultérieure.&lt;br /&gt;
&lt;br /&gt;
* Une fois les données collectées et stockées dans le fichier CSV, elles sont préparées pour l'entraînement du modèle.&lt;br /&gt;
* Cette préparation implique la normalisation des données, la gestion des valeurs manquantes ou aberrantes, et leur formatage dans un bon format.[[Fichier:Rpi entrainement.png|vignette|1000x1000px|néant]]&lt;br /&gt;
=== 4. Entraînement du Modèle d'Apprentissage Automatique ===&lt;br /&gt;
----L'entraînement du modèle est réalisé par un script Python utilisant la bibliothèque scikit-learn. Le modèle SVM, choisi pour sa capacité à gérer des espaces de grande dimension, est entraîné sur l'ensemble des données collectées. Ce processus comprend la division des données en ensembles d'entraînement et de test, l'entraînement du modèle, et sa validation par le calcul de la précision.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import pandas as pd&lt;br /&gt;
from sklearn.model_selection import train_test_split&lt;br /&gt;
from sklearn.svm import SVC&lt;br /&gt;
from sklearn.metrics import accuracy_score&lt;br /&gt;
import pickle&lt;br /&gt;
&lt;br /&gt;
# Charger vos données&lt;br /&gt;
data = pd.read_csv('data_complete.csv')&lt;br /&gt;
&lt;br /&gt;
# Séparer les caractéristiques et les étiquettes&lt;br /&gt;
X = data.drop('Etiquette', axis=1)&lt;br /&gt;
y = data['Etiquette']&lt;br /&gt;
&lt;br /&gt;
# Diviser les données en ensembles d'entraînement et de test&lt;br /&gt;
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)&lt;br /&gt;
&lt;br /&gt;
# Créer et entraîner le modèle SVM&lt;br /&gt;
model = SVC(kernel='rbf')&lt;br /&gt;
model.fit(X_train, y_train)&lt;br /&gt;
&lt;br /&gt;
# Sauvegarder le modèle entraîné&lt;br /&gt;
with open('modele_svm.pkl', 'wb') as file:&lt;br /&gt;
    pickle.dump(model, file)&lt;br /&gt;
&lt;br /&gt;
# Charger le modèle et faire des prédictions&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    loaded_model = pickle.load(file)&lt;br /&gt;
    predictions = loaded_model.predict(X_test)&lt;br /&gt;
    print(&amp;quot;Précision :&amp;quot;, accuracy_score(y_test, predictions))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# '''Séparation des Données''':&lt;br /&gt;
#* Les données sont divisées en deux ensembles : un ensemble d'entraînement et un ensemble de test. Cette séparation est cruciale pour évaluer objectivement la performance du modèle.&lt;br /&gt;
#* Généralement, on adopte une répartition de 80% pour l'entraînement et 20% pour les tests.&lt;br /&gt;
# '''Entraînement du Modèle SVM''':&lt;br /&gt;
#* Le modèle SVM avec un noyau RBF (Radial Basis Function) est entraîné sur l'ensemble d'entraînement.&lt;br /&gt;
#* L'entraînement implique l'ajustement du modèle aux données d'entraînement, en apprenant à distinguer les différents signes.&lt;br /&gt;
# '''Sauvegarde et Réutilisation du Modèle'''&lt;br /&gt;
#* Une fois entraîné et validé, le modèle est sauvegardé à l'aide de la bibliothèque &amp;lt;code&amp;gt;pickle&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Validation et Évaluation du Modèle''':&lt;br /&gt;
#* Après l'entraînement, le modèle est testé sur l'ensemble de test pour évaluer sa performance.&lt;br /&gt;
#* La métrique principale utilisée est la précision, qui mesure la proportion de prédictions correctes par rapport au total des prédictions.&lt;br /&gt;
&lt;br /&gt;
Ensuite on peut générer le modèle comme ceci:&lt;br /&gt;
[[Fichier:Generate model.png|vignette|399x399px|néant]]&lt;br /&gt;
&lt;br /&gt;
Avec cette prédiction lorsque notre modèle prédit le résultat, il est correct environ 71.81% du temps.&lt;br /&gt;
&lt;br /&gt;
=== 5. Intégration MQTT et Communication ===&lt;br /&gt;
----Protocole de communication  :&lt;br /&gt;
&lt;br /&gt;
Dans le cadre de notre projet, la communication entre les dispositifs Raspberry Pi et le serveur  est établie via le protocole MQTT.&lt;br /&gt;
&lt;br /&gt;
Justification du Choix de MQTT :&lt;br /&gt;
&lt;br /&gt;
Au début du projet, une approche basée sur des sockets IPv6 avait été envisagée pour tirer parti de l'adressage direct et de la simplification de la configuration réseau qu'offre IPv6. Cependant, dans le but de respecter les impératifs de sobriété énergétique et d'assurer une scalabilité optimale du système, permettant ainsi de gérer aisément un nombre croissant de dispositifs Raspberry Pi, la décision a été prise d'adopter MQTT comme protocole de communication. Le protocole MQTT, reconnu pour sa légèreté et sa fiabilité, s'adapte parfaitement aux contraintes des applications IoT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Installation du broker mosquitto sur le serveur:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
apt install -y mosquitto mosquitto-clients&lt;br /&gt;
service mosquitto start&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Activation de l'accès à distance au Broker Mosquitto:&lt;br /&gt;
&lt;br /&gt;
ajouter l'authentification par username et mot de passe&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
sudo mosquitto_passwd -c /etc/mosquitto/passwd username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
après on nous demande d'entrer le mot de passe &lt;br /&gt;
&lt;br /&gt;
Modifier le fichier /etc/mosquitto/mosquitto.conf:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
listener 1883 10.42.0.5&lt;br /&gt;
allow_anonymous false&lt;br /&gt;
password_file /etc/mosquitto/passwd&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Mosquitto:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
service mosquitto restart&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vérification ds logs:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
cat /var/log/mosquitto/mosquitto.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6. Interface Serveur et Gestion des Données ===&lt;br /&gt;
----Le script &amp;lt;code&amp;gt;app.py&amp;lt;/code&amp;gt; crée une interface serveur utilisant Flask. Cette interface gère les requêtes entrantes, les messages MQTT, et fournit une API pour l'interface utilisateur web. Elle permet également de visualiser les Raspberry Pi disponibles et les derniers messages traduits.&lt;br /&gt;
&lt;br /&gt;
=== 7. Conception de l'Interface Utilisateur ===&lt;br /&gt;
----L'interface utilisateur est développée en HTML, CSS et JavaScript. Le fichier &amp;lt;code&amp;gt;index.html&amp;lt;/code&amp;gt; fournit une interface claire et intuitive pour l'envoi de commandes et la visualisation des traductions. L'utilisation de JavaScript pour interroger dynamiquement le serveur Flask permet une mise à jour en temps réel des informations affichées.&lt;br /&gt;
&lt;br /&gt;
=== 9. Conclusion et Perspectives ===&lt;br /&gt;
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4835</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4835"/>
		<updated>2024-01-28T16:28:47Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* 4. Entraînement du Modèle d'Apprentissage Automatique */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Compte rendu des séances=&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
[[Fichier:IfconfigVM.png|gauche|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
mettre la config de la raspberry&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1. Introduction ===&lt;br /&gt;
----Le projet SignSpeak a pour ambition de créer une solution innovante pour la traduction du langage des signes en texte. L'objectif principal est de développer un système capable de capturer les mouvements des mains et de les interpréter en langage des signes, permettant une communication fluide entre les personnes sourdes ou malentendantes et celles qui ne connaissent pas le langage des signes. Ce projet intègre des technologies avancées telles que l'edge computing, l'intelligence artificielle embarquée, et les communications MQTT, offrant une approche novatrice dans le domaine de l'accessibilité et de la communication.&lt;br /&gt;
&lt;br /&gt;
=== 2. Architecture du Système ===&lt;br /&gt;
----Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :&lt;br /&gt;
&lt;br /&gt;
* '''Capteurs et STM32''' : Des capteurs sont connectés à un microcontrôleur STM32, responsables de la capture des mouvements de main. Ces données sont ensuite transmises pour traitement.&lt;br /&gt;
* '''Raspberry Pi''' : Agissant comme un intermédiaire, la Raspberry Pi reçoit les données des capteurs via UART, exécute un traitement préliminaire et communique avec le serveur.&lt;br /&gt;
* '''Serveur et Machine Learning''' : Un serveur, hébergé sur une VM Xen, traite les données à l'aide d'un modèle SVM pour la traduction en langage des signes et fournit une interface web pour l'interaction utilisateur.&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== 3. Collecte et Préparation des Données ===&lt;br /&gt;
----Le processus de collecte des données est géré par le script &amp;lt;code&amp;gt;enregistrementData.py&amp;lt;/code&amp;gt;. Ce script lit les données transmises par le STM32 via UART et les enregistre dans un fichier CSV. Chaque entrée du fichier représente les valeurs de capteurs à un moment donné, accompagnées d'une étiquette correspondant au signe effectué. Cette approche assure une collecte de données structurée, essentielle pour l'entraînement précis du modèle d'apprentissage automatique.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
import csv&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
# Vérification de l'argument d'entrée&lt;br /&gt;
if len(sys.argv) &amp;lt; 2:&lt;br /&gt;
    print(&amp;quot;Usage: python script.py &amp;lt;etiquette&amp;gt;&amp;quot;)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
etiquette = sys.argv[1]&lt;br /&gt;
&lt;br /&gt;
# Paramètres de l'UART&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
&lt;br /&gt;
# Créer une connexion UART&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
&lt;br /&gt;
# Nom du fichier CSV&lt;br /&gt;
filename = f&amp;quot;data_complete.csv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Vérifier si le fichier existe déjà&lt;br /&gt;
file_exists = False&lt;br /&gt;
try:&lt;br /&gt;
    with open(filename, 'r') as f:&lt;br /&gt;
        file_exists = True&lt;br /&gt;
except FileNotFoundError:&lt;br /&gt;
    file_exists = False&lt;br /&gt;
&lt;br /&gt;
# Ouvrir le fichier CSV en mode append&lt;br /&gt;
with open(filename, 'a', newline='') as file:&lt;br /&gt;
    writer = csv.writer(file)&lt;br /&gt;
&lt;br /&gt;
    # Écrire l'en-tête si le fichier n'existait pas&lt;br /&gt;
    if not file_exists:&lt;br /&gt;
        writer.writerow([&amp;quot;Capteur1&amp;quot;, &amp;quot;Capteur2&amp;quot;, &amp;quot;Capteur3&amp;quot;, &amp;quot;Capteur4&amp;quot;, &amp;quot;Capteur5&amp;quot;, &amp;quot;Capteur6&amp;quot;, &amp;quot;Capteur7&amp;quot;, &amp;quot;Capteur8&amp;quot;, &amp;quot;Capteur9&amp;quot;, &amp;quot;Capteur10&amp;quot;, &amp;quot;Capteur11&amp;quot;, &amp;quot;Capteur12&amp;quot;, &amp;quot;Capteur13&amp;quot;, &amp;quot;Capteur14&amp;quot;, &lt;br /&gt;
&amp;quot;Capteur15&amp;quot;, &amp;quot;Capteur16&amp;quot;, &amp;quot;Etiquette&amp;quot;])&lt;br /&gt;
    elif file_exists:&lt;br /&gt;
        writer.writerow([])&lt;br /&gt;
    while True:&lt;br /&gt;
        # Lire une ligne de données depuis l'UART&lt;br /&gt;
        data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
        print(f&amp;quot;Données reçues : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Vérifier si des données ont été reçues&lt;br /&gt;
        if data:&lt;br /&gt;
            # Diviser les données en valeurs individuelles&lt;br /&gt;
            sensor_values = data.split(',')&lt;br /&gt;
&lt;br /&gt;
            # Filtrer les chaînes vides ou non numériques et convertir en flottants&lt;br /&gt;
            try:&lt;br /&gt;
                sensor_values = [float(value) for value in sensor_values if value.strip().isdigit()]&lt;br /&gt;
&lt;br /&gt;
                # Vérifier qu'il y a 16 valeurs de capteur&lt;br /&gt;
                if len(sensor_values) == 16:&lt;br /&gt;
                    sensor_values.append(etiquette)&lt;br /&gt;
                    writer.writerow(sensor_values)&lt;br /&gt;
                else:&lt;br /&gt;
                    print(&amp;quot;Données incomplètes reçues&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            except ValueError as e:&lt;br /&gt;
                print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
                print(f&amp;quot;Données problématiques : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Le script commence par établir une communication série avec le STM32.&lt;br /&gt;
* Il lit ensuite les données en série, les décode et les stocke dans un fichier CSV pour une utilisation ultérieure.&lt;br /&gt;
&lt;br /&gt;
* Une fois les données collectées et stockées dans le fichier CSV, elles sont préparées pour l'entraînement du modèle.&lt;br /&gt;
* Cette préparation implique la normalisation des données, la gestion des valeurs manquantes ou aberrantes, et leur formatage dans un bon format.[[Fichier:Rpi entrainement.png|gauche|vignette|1000x1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 4. Entraînement du Modèle d'Apprentissage Automatique ===&lt;br /&gt;
----L'entraînement du modèle est réalisé par un script Python utilisant la bibliothèque scikit-learn. Le modèle SVM, choisi pour sa capacité à gérer des espaces de grande dimension, est entraîné sur l'ensemble des données collectées. Ce processus comprend la division des données en ensembles d'entraînement et de test, l'entraînement du modèle, et sa validation par le calcul de la précision.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import pandas as pd&lt;br /&gt;
from sklearn.model_selection import train_test_split&lt;br /&gt;
from sklearn.svm import SVC&lt;br /&gt;
from sklearn.metrics import accuracy_score&lt;br /&gt;
import pickle&lt;br /&gt;
&lt;br /&gt;
# Charger vos données&lt;br /&gt;
data = pd.read_csv('data_complete.csv')&lt;br /&gt;
&lt;br /&gt;
# Séparer les caractéristiques et les étiquettes&lt;br /&gt;
X = data.drop('Etiquette', axis=1)&lt;br /&gt;
y = data['Etiquette']&lt;br /&gt;
&lt;br /&gt;
# Diviser les données en ensembles d'entraînement et de test&lt;br /&gt;
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)&lt;br /&gt;
&lt;br /&gt;
# Créer et entraîner le modèle SVM&lt;br /&gt;
model = SVC(kernel='rbf')&lt;br /&gt;
model.fit(X_train, y_train)&lt;br /&gt;
&lt;br /&gt;
# Sauvegarder le modèle entraîné&lt;br /&gt;
with open('modele_svm.pkl', 'wb') as file:&lt;br /&gt;
    pickle.dump(model, file)&lt;br /&gt;
&lt;br /&gt;
# Charger le modèle et faire des prédictions&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    loaded_model = pickle.load(file)&lt;br /&gt;
    predictions = loaded_model.predict(X_test)&lt;br /&gt;
    print(&amp;quot;Précision :&amp;quot;, accuracy_score(y_test, predictions))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# '''Séparation des Données''':&lt;br /&gt;
#* Les données sont divisées en deux ensembles : un ensemble d'entraînement et un ensemble de test. Cette séparation est cruciale pour évaluer objectivement la performance du modèle.&lt;br /&gt;
#* Généralement, on adopte une répartition de 80% pour l'entraînement et 20% pour les tests.&lt;br /&gt;
# '''Entraînement du Modèle SVM''':&lt;br /&gt;
#* Le modèle SVM avec un noyau RBF (Radial Basis Function) est entraîné sur l'ensemble d'entraînement.&lt;br /&gt;
#* L'entraînement implique l'ajustement du modèle aux données d'entraînement, en apprenant à distinguer les différents signes.&lt;br /&gt;
# '''Sauvegarde et Réutilisation du Modèle'''&lt;br /&gt;
#* Une fois entraîné et validé, le modèle est sauvegardé à l'aide de la bibliothèque &amp;lt;code&amp;gt;pickle&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Validation et Évaluation du Modèle''':&lt;br /&gt;
#* Après l'entraînement, le modèle est testé sur l'ensemble de test pour évaluer sa performance.&lt;br /&gt;
#* La métrique principale utilisée est la précision, qui mesure la proportion de prédictions correctes par rapport au total des prédictions.&lt;br /&gt;
&lt;br /&gt;
Ensuite on peut générer le modèle comme ceci:&lt;br /&gt;
[[Fichier:Generate model.png|gauche|vignette|399x399px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Avec cette prédiction lorsque notre modèle prédit le résultat, il est correct environ 71.81% du temps.&lt;br /&gt;
&lt;br /&gt;
=== 5. Intégration MQTT et Communication ===&lt;br /&gt;
----Protocole de communication  :&lt;br /&gt;
&lt;br /&gt;
Dans le cadre de notre projet, la communication entre les dispositifs Raspberry Pi et le serveur  est établie via le protocole MQTT.&lt;br /&gt;
&lt;br /&gt;
Justification du Choix de MQTT :&lt;br /&gt;
&lt;br /&gt;
Au début du projet, une approche basée sur des sockets IPv6 avait été envisagée pour tirer parti de l'adressage direct et de la simplification de la configuration réseau qu'offre IPv6. Cependant, dans le but de respecter les impératifs de sobriété énergétique et d'assurer une scalabilité optimale du système, permettant ainsi de gérer aisément un nombre croissant de dispositifs Raspberry Pi, la décision a été prise d'adopter MQTT comme protocole de communication. Le protocole MQTT, reconnu pour sa légèreté et sa fiabilité, s'adapte parfaitement aux contraintes des applications IoT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Installation du broker mosquitto sur le serveur:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
apt install -y mosquitto mosquitto-clients&lt;br /&gt;
service mosquitto start&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Activation de l'accès à distance au Broker Mosquitto:&lt;br /&gt;
&lt;br /&gt;
ajouter l'authentification par username et mot de passe&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
sudo mosquitto_passwd -c /etc/mosquitto/passwd username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
après on nous demande d'entrer le mot de passe &lt;br /&gt;
&lt;br /&gt;
Modifier le fichier /etc/mosquitto/mosquitto.conf:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
listener 1883 10.42.0.5&lt;br /&gt;
allow_anonymous false&lt;br /&gt;
password_file /etc/mosquitto/passwd&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6. Interface Serveur et Gestion des Données ===&lt;br /&gt;
----Le script &amp;lt;code&amp;gt;app.py&amp;lt;/code&amp;gt; crée une interface serveur utilisant Flask. Cette interface gère les requêtes entrantes, les messages MQTT, et fournit une API pour l'interface utilisateur web. Elle permet également de visualiser les Raspberry Pi disponibles et les derniers messages traduits.&lt;br /&gt;
&lt;br /&gt;
=== 7. Conception de l'Interface Utilisateur ===&lt;br /&gt;
----L'interface utilisateur est développée en HTML, CSS et JavaScript. Le fichier &amp;lt;code&amp;gt;index.html&amp;lt;/code&amp;gt; fournit une interface claire et intuitive pour l'envoi de commandes et la visualisation des traductions. L'utilisation de JavaScript pour interroger dynamiquement le serveur Flask permet une mise à jour en temps réel des informations affichées.&lt;br /&gt;
&lt;br /&gt;
=== 9. Conclusion et Perspectives ===&lt;br /&gt;
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4834</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4834"/>
		<updated>2024-01-28T16:27:20Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* 3. Collecte et Préparation des Données */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Compte rendu des séances=&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
[[Fichier:IfconfigVM.png|gauche|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
mettre la config de la raspberry&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1. Introduction ===&lt;br /&gt;
----Le projet SignSpeak a pour ambition de créer une solution innovante pour la traduction du langage des signes en texte. L'objectif principal est de développer un système capable de capturer les mouvements des mains et de les interpréter en langage des signes, permettant une communication fluide entre les personnes sourdes ou malentendantes et celles qui ne connaissent pas le langage des signes. Ce projet intègre des technologies avancées telles que l'edge computing, l'intelligence artificielle embarquée, et les communications MQTT, offrant une approche novatrice dans le domaine de l'accessibilité et de la communication.&lt;br /&gt;
&lt;br /&gt;
=== 2. Architecture du Système ===&lt;br /&gt;
----Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :&lt;br /&gt;
&lt;br /&gt;
* '''Capteurs et STM32''' : Des capteurs sont connectés à un microcontrôleur STM32, responsables de la capture des mouvements de main. Ces données sont ensuite transmises pour traitement.&lt;br /&gt;
* '''Raspberry Pi''' : Agissant comme un intermédiaire, la Raspberry Pi reçoit les données des capteurs via UART, exécute un traitement préliminaire et communique avec le serveur.&lt;br /&gt;
* '''Serveur et Machine Learning''' : Un serveur, hébergé sur une VM Xen, traite les données à l'aide d'un modèle SVM pour la traduction en langage des signes et fournit une interface web pour l'interaction utilisateur.&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== 3. Collecte et Préparation des Données ===&lt;br /&gt;
----Le processus de collecte des données est géré par le script &amp;lt;code&amp;gt;enregistrementData.py&amp;lt;/code&amp;gt;. Ce script lit les données transmises par le STM32 via UART et les enregistre dans un fichier CSV. Chaque entrée du fichier représente les valeurs de capteurs à un moment donné, accompagnées d'une étiquette correspondant au signe effectué. Cette approche assure une collecte de données structurée, essentielle pour l'entraînement précis du modèle d'apprentissage automatique.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
import csv&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
# Vérification de l'argument d'entrée&lt;br /&gt;
if len(sys.argv) &amp;lt; 2:&lt;br /&gt;
    print(&amp;quot;Usage: python script.py &amp;lt;etiquette&amp;gt;&amp;quot;)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
etiquette = sys.argv[1]&lt;br /&gt;
&lt;br /&gt;
# Paramètres de l'UART&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
&lt;br /&gt;
# Créer une connexion UART&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
&lt;br /&gt;
# Nom du fichier CSV&lt;br /&gt;
filename = f&amp;quot;data_complete.csv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Vérifier si le fichier existe déjà&lt;br /&gt;
file_exists = False&lt;br /&gt;
try:&lt;br /&gt;
    with open(filename, 'r') as f:&lt;br /&gt;
        file_exists = True&lt;br /&gt;
except FileNotFoundError:&lt;br /&gt;
    file_exists = False&lt;br /&gt;
&lt;br /&gt;
# Ouvrir le fichier CSV en mode append&lt;br /&gt;
with open(filename, 'a', newline='') as file:&lt;br /&gt;
    writer = csv.writer(file)&lt;br /&gt;
&lt;br /&gt;
    # Écrire l'en-tête si le fichier n'existait pas&lt;br /&gt;
    if not file_exists:&lt;br /&gt;
        writer.writerow([&amp;quot;Capteur1&amp;quot;, &amp;quot;Capteur2&amp;quot;, &amp;quot;Capteur3&amp;quot;, &amp;quot;Capteur4&amp;quot;, &amp;quot;Capteur5&amp;quot;, &amp;quot;Capteur6&amp;quot;, &amp;quot;Capteur7&amp;quot;, &amp;quot;Capteur8&amp;quot;, &amp;quot;Capteur9&amp;quot;, &amp;quot;Capteur10&amp;quot;, &amp;quot;Capteur11&amp;quot;, &amp;quot;Capteur12&amp;quot;, &amp;quot;Capteur13&amp;quot;, &amp;quot;Capteur14&amp;quot;, &lt;br /&gt;
&amp;quot;Capteur15&amp;quot;, &amp;quot;Capteur16&amp;quot;, &amp;quot;Etiquette&amp;quot;])&lt;br /&gt;
    elif file_exists:&lt;br /&gt;
        writer.writerow([])&lt;br /&gt;
    while True:&lt;br /&gt;
        # Lire une ligne de données depuis l'UART&lt;br /&gt;
        data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
        print(f&amp;quot;Données reçues : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Vérifier si des données ont été reçues&lt;br /&gt;
        if data:&lt;br /&gt;
            # Diviser les données en valeurs individuelles&lt;br /&gt;
            sensor_values = data.split(',')&lt;br /&gt;
&lt;br /&gt;
            # Filtrer les chaînes vides ou non numériques et convertir en flottants&lt;br /&gt;
            try:&lt;br /&gt;
                sensor_values = [float(value) for value in sensor_values if value.strip().isdigit()]&lt;br /&gt;
&lt;br /&gt;
                # Vérifier qu'il y a 16 valeurs de capteur&lt;br /&gt;
                if len(sensor_values) == 16:&lt;br /&gt;
                    sensor_values.append(etiquette)&lt;br /&gt;
                    writer.writerow(sensor_values)&lt;br /&gt;
                else:&lt;br /&gt;
                    print(&amp;quot;Données incomplètes reçues&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            except ValueError as e:&lt;br /&gt;
                print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
                print(f&amp;quot;Données problématiques : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Le script commence par établir une communication série avec le STM32.&lt;br /&gt;
* Il lit ensuite les données en série, les décode et les stocke dans un fichier CSV pour une utilisation ultérieure.&lt;br /&gt;
&lt;br /&gt;
* Une fois les données collectées et stockées dans le fichier CSV, elles sont préparées pour l'entraînement du modèle.&lt;br /&gt;
* Cette préparation implique la normalisation des données, la gestion des valeurs manquantes ou aberrantes, et leur formatage dans un bon format.[[Fichier:Rpi entrainement.png|gauche|vignette|1000x1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 4. Entraînement du Modèle d'Apprentissage Automatique ===&lt;br /&gt;
----L'entraînement du modèle est réalisé par un script Python utilisant la bibliothèque scikit-learn. Le modèle SVM, choisi pour sa capacité à gérer des espaces de grande dimension, est entraîné sur l'ensemble des données collectées. Ce processus comprend la division des données en ensembles d'entraînement et de test, l'entraînement du modèle, et sa validation par le calcul de la précision.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import pandas as pd&lt;br /&gt;
from sklearn.model_selection import train_test_split&lt;br /&gt;
from sklearn.svm import SVC&lt;br /&gt;
from sklearn.metrics import accuracy_score&lt;br /&gt;
import pickle&lt;br /&gt;
&lt;br /&gt;
# Charger vos données&lt;br /&gt;
data = pd.read_csv('data_complete.csv')&lt;br /&gt;
&lt;br /&gt;
# Séparer les caractéristiques et les étiquettes&lt;br /&gt;
X = data.drop('Etiquette', axis=1)&lt;br /&gt;
y = data['Etiquette']&lt;br /&gt;
&lt;br /&gt;
# Diviser les données en ensembles d'entraînement et de test&lt;br /&gt;
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)&lt;br /&gt;
&lt;br /&gt;
# Créer et entraîner le modèle SVM&lt;br /&gt;
model = SVC(kernel='rbf')&lt;br /&gt;
model.fit(X_train, y_train)&lt;br /&gt;
&lt;br /&gt;
# Sauvegarder le modèle entraîné&lt;br /&gt;
with open('modele_svm.pkl', 'wb') as file:&lt;br /&gt;
    pickle.dump(model, file)&lt;br /&gt;
&lt;br /&gt;
# Charger le modèle et faire des prédictions&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    loaded_model = pickle.load(file)&lt;br /&gt;
    predictions = loaded_model.predict(X_test)&lt;br /&gt;
    print(&amp;quot;Précision :&amp;quot;, accuracy_score(y_test, predictions))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# '''Séparation des Données''':&lt;br /&gt;
#* Les données sont divisées en deux ensembles : un ensemble d'entraînement et un ensemble de test. Cette séparation est cruciale pour évaluer objectivement la performance du modèle.&lt;br /&gt;
#* Généralement, on adopte une répartition de 80% pour l'entraînement et 20% pour les tests.&lt;br /&gt;
# '''Entraînement du Modèle SVM''':&lt;br /&gt;
#* Le modèle SVM avec un noyau RBF (Radial Basis Function) est entraîné sur l'ensemble d'entraînement.&lt;br /&gt;
#* L'entraînement implique l'ajustement du modèle aux données d'entraînement, en apprenant à distinguer les différents signes.&lt;br /&gt;
# '''Sauvegarde et Réutilisation du Modèle'''&lt;br /&gt;
#* Une fois entraîné et validé, le modèle est sauvegardé à l'aide de la bibliothèque &amp;lt;code&amp;gt;pickle&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Validation et Évaluation du Modèle''':&lt;br /&gt;
#* Après l'entraînement, le modèle est testé sur l'ensemble de test pour évaluer sa performance.&lt;br /&gt;
#* La métrique principale utilisée est la précision, qui mesure la proportion de prédictions correctes par rapport au total des prédictions.&lt;br /&gt;
&lt;br /&gt;
Ensuite on peut générer le modèle comme ceci:&lt;br /&gt;
[[Fichier:Generate model.png|gauche|vignette|399x399px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Avec cette prédiction lorsque notre modèle prédit le résultat, il est correct environ 71.81% du temps.&lt;br /&gt;
&lt;br /&gt;
=== 5. Intégration MQTT et Communication ===&lt;br /&gt;
----Protocole de communication  :&lt;br /&gt;
&lt;br /&gt;
Dans le cadre de notre projet, la communication entre les dispositifs Raspberry Pi et le serveur  est établie via le protocole MQTT.&lt;br /&gt;
&lt;br /&gt;
Justification du Choix de MQTT :&lt;br /&gt;
&lt;br /&gt;
Au début du projet, une approche basée sur des sockets IPv6 avait été envisagée pour tirer parti de l'adressage direct et de la simplification de la configuration réseau qu'offre IPv6. Cependant, dans le but de respecter les impératifs de sobriété énergétique et d'assurer une scalabilité optimale du système, permettant ainsi de gérer aisément un nombre croissant de dispositifs Raspberry Pi, la décision a été prise d'adopter MQTT comme protocole de communication. Le protocole MQTT, reconnu pour sa légèreté et sa fiabilité, s'adapte parfaitement aux contraintes des applications IoT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Installation du broker mosquitto sur le serveur:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
apt install -y mosquitto mosquitto-clients&lt;br /&gt;
service mosquitto start&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Activation de l'accès à distance au Broker Mosquitto:&lt;br /&gt;
&lt;br /&gt;
ajouter l'authentification par username et mot de passe&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
sudo mosquitto_passwd -c /etc/mosquitto/passwd username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
après on nous demande d'entrer le mot de passe &lt;br /&gt;
&lt;br /&gt;
Modifier le fichier /etc/mosquitto/mosquitto.conf:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
listener 1883 10.42.0.5&lt;br /&gt;
allow_anonymous false&lt;br /&gt;
password_file /etc/mosquitto/passwd&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6. Interface Serveur et Gestion des Données ===&lt;br /&gt;
----Le script &amp;lt;code&amp;gt;app.py&amp;lt;/code&amp;gt; crée une interface serveur utilisant Flask. Cette interface gère les requêtes entrantes, les messages MQTT, et fournit une API pour l'interface utilisateur web. Elle permet également de visualiser les Raspberry Pi disponibles et les derniers messages traduits.&lt;br /&gt;
&lt;br /&gt;
=== 7. Conception de l'Interface Utilisateur ===&lt;br /&gt;
----L'interface utilisateur est développée en HTML, CSS et JavaScript. Le fichier &amp;lt;code&amp;gt;index.html&amp;lt;/code&amp;gt; fournit une interface claire et intuitive pour l'envoi de commandes et la visualisation des traductions. L'utilisation de JavaScript pour interroger dynamiquement le serveur Flask permet une mise à jour en temps réel des informations affichées.&lt;br /&gt;
&lt;br /&gt;
=== 9. Conclusion et Perspectives ===&lt;br /&gt;
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4832</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4832"/>
		<updated>2024-01-28T16:25:26Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* 5. Intégration MQTT et Communication */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Compte rendu des séances=&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
[[Fichier:IfconfigVM.png|gauche|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
mettre la config de la raspberry&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1. Introduction ===&lt;br /&gt;
----Le projet SignSpeak a pour ambition de créer une solution innovante pour la traduction du langage des signes en texte. L'objectif principal est de développer un système capable de capturer les mouvements des mains et de les interpréter en langage des signes, permettant une communication fluide entre les personnes sourdes ou malentendantes et celles qui ne connaissent pas le langage des signes. Ce projet intègre des technologies avancées telles que l'edge computing, l'intelligence artificielle embarquée, et les communications MQTT, offrant une approche novatrice dans le domaine de l'accessibilité et de la communication.&lt;br /&gt;
&lt;br /&gt;
=== 2. Architecture du Système ===&lt;br /&gt;
----Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :&lt;br /&gt;
&lt;br /&gt;
* '''Capteurs et STM32''' : Des capteurs sont connectés à un microcontrôleur STM32, responsables de la capture des mouvements de main. Ces données sont ensuite transmises pour traitement.&lt;br /&gt;
* '''Raspberry Pi''' : Agissant comme un intermédiaire, la Raspberry Pi reçoit les données des capteurs via UART, exécute un traitement préliminaire et communique avec le serveur.&lt;br /&gt;
* '''Serveur et Machine Learning''' : Un serveur, hébergé sur une VM Xen, traite les données à l'aide d'un modèle SVM pour la traduction en langage des signes et fournit une interface web pour l'interaction utilisateur.&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== 3. Collecte et Préparation des Données ===&lt;br /&gt;
----Le processus de collecte des données est géré par le script &amp;lt;code&amp;gt;enregistrementData.py&amp;lt;/code&amp;gt;. Ce script lit les données transmises par le STM32 via UART et les enregistre dans un fichier CSV. Chaque entrée du fichier représente les valeurs de capteurs à un moment donné, accompagnées d'une étiquette correspondant au signe effectué. Cette approche assure une collecte de données structurée, essentielle pour l'entraînement précis du modèle d'apprentissage automatique.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
import csv&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
# Vérification de l'argument d'entrée&lt;br /&gt;
if len(sys.argv) &amp;lt; 2:&lt;br /&gt;
    print(&amp;quot;Usage: python script.py &amp;lt;etiquette&amp;gt;&amp;quot;)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
etiquette = sys.argv[1]&lt;br /&gt;
&lt;br /&gt;
# Paramètres de l'UART&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
&lt;br /&gt;
# Créer une connexion UART&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
&lt;br /&gt;
# Nom du fichier CSV&lt;br /&gt;
filename = f&amp;quot;data_complete.csv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Vérifier si le fichier existe déjà&lt;br /&gt;
file_exists = False&lt;br /&gt;
try:&lt;br /&gt;
    with open(filename, 'r') as f:&lt;br /&gt;
        file_exists = True&lt;br /&gt;
except FileNotFoundError:&lt;br /&gt;
    file_exists = False&lt;br /&gt;
&lt;br /&gt;
# Ouvrir le fichier CSV en mode append&lt;br /&gt;
with open(filename, 'a', newline='') as file:&lt;br /&gt;
    writer = csv.writer(file)&lt;br /&gt;
&lt;br /&gt;
    # Écrire l'en-tête si le fichier n'existait pas&lt;br /&gt;
    if not file_exists:&lt;br /&gt;
        writer.writerow([&amp;quot;Capteur1&amp;quot;, &amp;quot;Capteur2&amp;quot;, &amp;quot;Capteur3&amp;quot;, &amp;quot;Capteur4&amp;quot;, &amp;quot;Capteur5&amp;quot;, &amp;quot;Capteur6&amp;quot;, &amp;quot;Capteur7&amp;quot;, &amp;quot;Capteur8&amp;quot;, &amp;quot;Capteur9&amp;quot;, &amp;quot;Capteur10&amp;quot;, &amp;quot;Capteur11&amp;quot;, &amp;quot;Capteur12&amp;quot;, &amp;quot;Capteur13&amp;quot;, &amp;quot;Capteur14&amp;quot;, &lt;br /&gt;
&amp;quot;Capteur15&amp;quot;, &amp;quot;Capteur16&amp;quot;, &amp;quot;Etiquette&amp;quot;])&lt;br /&gt;
    elif file_exists:&lt;br /&gt;
        writer.writerow([])&lt;br /&gt;
    while True:&lt;br /&gt;
        # Lire une ligne de données depuis l'UART&lt;br /&gt;
        data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
        print(f&amp;quot;Données reçues : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Vérifier si des données ont été reçues&lt;br /&gt;
        if data:&lt;br /&gt;
            # Diviser les données en valeurs individuelles&lt;br /&gt;
            sensor_values = data.split(',')&lt;br /&gt;
&lt;br /&gt;
            # Filtrer les chaînes vides ou non numériques et convertir en flottants&lt;br /&gt;
            try:&lt;br /&gt;
                sensor_values = [float(value) for value in sensor_values if value.strip().isdigit()]&lt;br /&gt;
&lt;br /&gt;
                # Vérifier qu'il y a 16 valeurs de capteur&lt;br /&gt;
                if len(sensor_values) == 16:&lt;br /&gt;
                    sensor_values.append(etiquette)&lt;br /&gt;
                    writer.writerow(sensor_values)&lt;br /&gt;
                else:&lt;br /&gt;
                    print(&amp;quot;Données incomplètes reçues&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            except ValueError as e:&lt;br /&gt;
                print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
                print(f&amp;quot;Données problématiques : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Le script commence par établir une communication série avec le STM32.&lt;br /&gt;
* Il lit ensuite les données en série, les décode et les stocke dans un fichier CSV pour une utilisation ultérieure.&lt;br /&gt;
&lt;br /&gt;
* Une fois les données collectées et stockées dans le fichier CSV, elles sont préparées pour l'entraînement du modèle.&lt;br /&gt;
* Cette préparation implique la normalisation des données, la gestion des valeurs manquantes ou aberrantes, et leur formatage dans un bon format.[[Fichier:Rpi entrainement.png|gauche|vignette|1000x1000px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 4. Entraînement du Modèle d'Apprentissage Automatique ===&lt;br /&gt;
----L'entraînement du modèle est réalisé par un script Python utilisant la bibliothèque scikit-learn. Le modèle SVM, choisi pour sa capacité à gérer des espaces de grande dimension, est entraîné sur l'ensemble des données collectées. Ce processus comprend la division des données en ensembles d'entraînement et de test, l'entraînement du modèle, et sa validation par le calcul de la précision.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import pandas as pd&lt;br /&gt;
from sklearn.model_selection import train_test_split&lt;br /&gt;
from sklearn.svm import SVC&lt;br /&gt;
from sklearn.metrics import accuracy_score&lt;br /&gt;
import pickle&lt;br /&gt;
&lt;br /&gt;
# Charger vos données&lt;br /&gt;
data = pd.read_csv('data_complete.csv')&lt;br /&gt;
&lt;br /&gt;
# Séparer les caractéristiques et les étiquettes&lt;br /&gt;
X = data.drop('Etiquette', axis=1)&lt;br /&gt;
y = data['Etiquette']&lt;br /&gt;
&lt;br /&gt;
# Diviser les données en ensembles d'entraînement et de test&lt;br /&gt;
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)&lt;br /&gt;
&lt;br /&gt;
# Créer et entraîner le modèle SVM&lt;br /&gt;
model = SVC(kernel='rbf')&lt;br /&gt;
model.fit(X_train, y_train)&lt;br /&gt;
&lt;br /&gt;
# Sauvegarder le modèle entraîné&lt;br /&gt;
with open('modele_svm.pkl', 'wb') as file:&lt;br /&gt;
    pickle.dump(model, file)&lt;br /&gt;
&lt;br /&gt;
# Charger le modèle et faire des prédictions&lt;br /&gt;
with open('modele_svm.pkl', 'rb') as file:&lt;br /&gt;
    loaded_model = pickle.load(file)&lt;br /&gt;
    predictions = loaded_model.predict(X_test)&lt;br /&gt;
    print(&amp;quot;Précision :&amp;quot;, accuracy_score(y_test, predictions))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# '''Séparation des Données''':&lt;br /&gt;
#* Les données sont divisées en deux ensembles : un ensemble d'entraînement et un ensemble de test. Cette séparation est cruciale pour évaluer objectivement la performance du modèle.&lt;br /&gt;
#* Généralement, on adopte une répartition de 80% pour l'entraînement et 20% pour les tests.&lt;br /&gt;
# '''Entraînement du Modèle SVM''':&lt;br /&gt;
#* Le modèle SVM avec un noyau RBF (Radial Basis Function) est entraîné sur l'ensemble d'entraînement.&lt;br /&gt;
#* L'entraînement implique l'ajustement du modèle aux données d'entraînement, en apprenant à distinguer les différents signes.&lt;br /&gt;
# '''Sauvegarde et Réutilisation du Modèle'''&lt;br /&gt;
#* Une fois entraîné et validé, le modèle est sauvegardé à l'aide de la bibliothèque &amp;lt;code&amp;gt;pickle&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Validation et Évaluation du Modèle''':&lt;br /&gt;
#* Après l'entraînement, le modèle est testé sur l'ensemble de test pour évaluer sa performance.&lt;br /&gt;
#* La métrique principale utilisée est la précision, qui mesure la proportion de prédictions correctes par rapport au total des prédictions.&lt;br /&gt;
&lt;br /&gt;
Ensuite on peut générer le modèle comme ceci:&lt;br /&gt;
[[Fichier:Generate model.png|gauche|vignette|399x399px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 5. Intégration MQTT et Communication ===&lt;br /&gt;
----Protocole de communication  :&lt;br /&gt;
&lt;br /&gt;
Dans le cadre de notre projet, la communication entre les dispositifs Raspberry Pi et le serveur  est établie via le protocole MQTT.&lt;br /&gt;
&lt;br /&gt;
Justification du Choix de MQTT :&lt;br /&gt;
&lt;br /&gt;
Au début du projet, une approche basée sur des sockets IPv6 avait été envisagée pour tirer parti de l'adressage direct et de la simplification de la configuration réseau qu'offre IPv6. Cependant, dans le but de respecter les impératifs de sobriété énergétique et d'assurer une scalabilité optimale du système, permettant ainsi de gérer aisément un nombre croissant de dispositifs Raspberry Pi, la décision a été prise d'adopter MQTT comme protocole de communication. Le protocole MQTT, reconnu pour sa légèreté et sa fiabilité, s'adapte parfaitement aux contraintes des applications IoT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Installation du broker mosquitto sur le serveur:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
apt install -y mosquitto mosquitto-clients&lt;br /&gt;
service mosquitto start&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6. Interface Serveur et Gestion des Données ===&lt;br /&gt;
----Le script &amp;lt;code&amp;gt;app.py&amp;lt;/code&amp;gt; crée une interface serveur utilisant Flask. Cette interface gère les requêtes entrantes, les messages MQTT, et fournit une API pour l'interface utilisateur web. Elle permet également de visualiser les Raspberry Pi disponibles et les derniers messages traduits.&lt;br /&gt;
&lt;br /&gt;
=== 7. Conception de l'Interface Utilisateur ===&lt;br /&gt;
----L'interface utilisateur est développée en HTML, CSS et JavaScript. Le fichier &amp;lt;code&amp;gt;index.html&amp;lt;/code&amp;gt; fournit une interface claire et intuitive pour l'envoi de commandes et la visualisation des traductions. L'utilisation de JavaScript pour interroger dynamiquement le serveur Flask permet une mise à jour en temps réel des informations affichées.&lt;br /&gt;
&lt;br /&gt;
=== 9. Conclusion et Perspectives ===&lt;br /&gt;
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Generate_model.png&amp;diff=4825</id>
		<title>Fichier:Generate model.png</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Generate_model.png&amp;diff=4825"/>
		<updated>2024-01-28T16:17:40Z</updated>

		<summary type="html">&lt;p&gt;Bblack : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;generate model&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Rpi_entrainement.png&amp;diff=4814</id>
		<title>Fichier:Rpi entrainement.png</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Rpi_entrainement.png&amp;diff=4814"/>
		<updated>2024-01-28T16:07:09Z</updated>

		<summary type="html">&lt;p&gt;Bblack : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;rpi_entrainement&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4810</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4810"/>
		<updated>2024-01-28T16:04:32Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* 3. Collecte et Préparation des Données */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Compte rendu des séances=&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
[[Fichier:IfconfigVM.png|gauche|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
mettre la config de la raspberry&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1. Introduction ===&lt;br /&gt;
----Le projet SignSpeak a pour ambition de créer une solution innovante pour la traduction du langage des signes en texte. L'objectif principal est de développer un système capable de capturer les mouvements des mains et de les interpréter en langage des signes, permettant une communication fluide entre les personnes sourdes ou malentendantes et celles qui ne connaissent pas le langage des signes. Ce projet intègre des technologies avancées telles que l'edge computing, l'intelligence artificielle embarquée, et les communications MQTT, offrant une approche novatrice dans le domaine de l'accessibilité et de la communication.&lt;br /&gt;
&lt;br /&gt;
=== 2. Architecture du Système ===&lt;br /&gt;
----Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :&lt;br /&gt;
&lt;br /&gt;
* '''Capteurs et STM32''' : Des capteurs sont connectés à un microcontrôleur STM32, responsables de la capture des mouvements de main. Ces données sont ensuite transmises pour traitement.&lt;br /&gt;
* '''Raspberry Pi''' : Agissant comme un intermédiaire, la Raspberry Pi reçoit les données des capteurs via UART, exécute un traitement préliminaire et communique avec le serveur.&lt;br /&gt;
* '''Serveur et Machine Learning''' : Un serveur, hébergé sur une VM Xen, traite les données à l'aide d'un modèle SVM pour la traduction en langage des signes et fournit une interface web pour l'interaction utilisateur.&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== 3. Collecte et Préparation des Données ===&lt;br /&gt;
----Le processus de collecte des données est géré par le script &amp;lt;code&amp;gt;enregistrementData.py&amp;lt;/code&amp;gt;. Ce script lit les données transmises par le STM32 via UART et les enregistre dans un fichier CSV. Chaque entrée du fichier représente les valeurs de capteurs à un moment donné, accompagnées d'une étiquette correspondant au signe effectué. Cette approche assure une collecte de données structurée, essentielle pour l'entraînement précis du modèle d'apprentissage automatique.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
import csv&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
# Vérification de l'argument d'entrée&lt;br /&gt;
if len(sys.argv) &amp;lt; 2:&lt;br /&gt;
    print(&amp;quot;Usage: python script.py &amp;lt;etiquette&amp;gt;&amp;quot;)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
etiquette = sys.argv[1]&lt;br /&gt;
&lt;br /&gt;
# Paramètres de l'UART&lt;br /&gt;
port = &amp;quot;/dev/ttyACM0&amp;quot;&lt;br /&gt;
baudrate = 460800&lt;br /&gt;
&lt;br /&gt;
# Créer une connexion UART&lt;br /&gt;
ser = serial.Serial(port, baudrate, timeout=1)&lt;br /&gt;
&lt;br /&gt;
# Nom du fichier CSV&lt;br /&gt;
filename = f&amp;quot;data_complete.csv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Vérifier si le fichier existe déjà&lt;br /&gt;
file_exists = False&lt;br /&gt;
try:&lt;br /&gt;
    with open(filename, 'r') as f:&lt;br /&gt;
        file_exists = True&lt;br /&gt;
except FileNotFoundError:&lt;br /&gt;
    file_exists = False&lt;br /&gt;
&lt;br /&gt;
# Ouvrir le fichier CSV en mode append&lt;br /&gt;
with open(filename, 'a', newline='') as file:&lt;br /&gt;
    writer = csv.writer(file)&lt;br /&gt;
&lt;br /&gt;
    # Écrire l'en-tête si le fichier n'existait pas&lt;br /&gt;
    if not file_exists:&lt;br /&gt;
        writer.writerow([&amp;quot;Capteur1&amp;quot;, &amp;quot;Capteur2&amp;quot;, &amp;quot;Capteur3&amp;quot;, &amp;quot;Capteur4&amp;quot;, &amp;quot;Capteur5&amp;quot;, &amp;quot;Capteur6&amp;quot;, &amp;quot;Capteur7&amp;quot;, &amp;quot;Capteur8&amp;quot;, &amp;quot;Capteur9&amp;quot;, &amp;quot;Capteur10&amp;quot;, &amp;quot;Capteur11&amp;quot;, &amp;quot;Capteur12&amp;quot;, &amp;quot;Capteur13&amp;quot;, &amp;quot;Capteur14&amp;quot;, &lt;br /&gt;
&amp;quot;Capteur15&amp;quot;, &amp;quot;Capteur16&amp;quot;, &amp;quot;Etiquette&amp;quot;])&lt;br /&gt;
    elif file_exists:&lt;br /&gt;
        writer.writerow([])&lt;br /&gt;
    while True:&lt;br /&gt;
        # Lire une ligne de données depuis l'UART&lt;br /&gt;
        data = ser.readline().decode('utf-8').rstrip()&lt;br /&gt;
        print(f&amp;quot;Données reçues : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Vérifier si des données ont été reçues&lt;br /&gt;
        if data:&lt;br /&gt;
            # Diviser les données en valeurs individuelles&lt;br /&gt;
            sensor_values = data.split(',')&lt;br /&gt;
&lt;br /&gt;
            # Filtrer les chaînes vides ou non numériques et convertir en flottants&lt;br /&gt;
            try:&lt;br /&gt;
                sensor_values = [float(value) for value in sensor_values if value.strip().isdigit()]&lt;br /&gt;
&lt;br /&gt;
                # Vérifier qu'il y a 16 valeurs de capteur&lt;br /&gt;
                if len(sensor_values) == 16:&lt;br /&gt;
                    sensor_values.append(etiquette)&lt;br /&gt;
                    writer.writerow(sensor_values)&lt;br /&gt;
                else:&lt;br /&gt;
                    print(&amp;quot;Données incomplètes reçues&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            except ValueError as e:&lt;br /&gt;
                print(f&amp;quot;Erreur de conversion : {e}&amp;quot;)&lt;br /&gt;
                print(f&amp;quot;Données problématiques : '{data}'&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        time.sleep(0.1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 4. Entraînement du Modèle d'Apprentissage Automatique ===&lt;br /&gt;
----L'entraînement du modèle est réalisé par un script Python utilisant la bibliothèque scikit-learn. Le modèle SVM, choisi pour sa capacité à gérer des espaces de grande dimension, est entraîné sur l'ensemble des données collectées. Ce processus comprend la division des données en ensembles d'entraînement et de test, l'entraînement du modèle, et sa validation par le calcul de la précision.&lt;br /&gt;
&lt;br /&gt;
=== 5. Intégration MQTT et Communication ===&lt;br /&gt;
----La communication entre la Raspberry Pi et le serveur utilise le protocole MQTT, un choix idéal pour les applications IoT en raison de sa légèreté et de sa fiabilité. Le script &amp;lt;code&amp;gt;mqtt_client2.py&amp;lt;/code&amp;gt; gère cette communication, permettant à la Raspberry Pi d'envoyer les prédictions du modèle SVM au serveur et de recevoir des commandes pour démarrer ou arrêter la collecte de données.&lt;br /&gt;
&lt;br /&gt;
=== 6. Interface Serveur et Gestion des Données ===&lt;br /&gt;
----Le script &amp;lt;code&amp;gt;app.py&amp;lt;/code&amp;gt; crée une interface serveur utilisant Flask. Cette interface gère les requêtes entrantes, les messages MQTT, et fournit une API pour l'interface utilisateur web. Elle permet également de visualiser les Raspberry Pi disponibles et les derniers messages traduits.&lt;br /&gt;
&lt;br /&gt;
=== 7. Conception de l'Interface Utilisateur ===&lt;br /&gt;
----L'interface utilisateur est développée en HTML, CSS et JavaScript. Le fichier &amp;lt;code&amp;gt;index.html&amp;lt;/code&amp;gt; fournit une interface claire et intuitive pour l'envoi de commandes et la visualisation des traductions. L'utilisation de JavaScript pour interroger dynamiquement le serveur Flask permet une mise à jour en temps réel des informations affichées.&lt;br /&gt;
&lt;br /&gt;
=== 9. Conclusion et Perspectives ===&lt;br /&gt;
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4790</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=4790"/>
		<updated>2024-01-28T15:36:51Z</updated>

		<summary type="html">&lt;p&gt;Bblack : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Compte rendu des séances=&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
[[Fichier:IfconfigVM.png|gauche|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
mettre la config de la raspberry&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1. Introduction ===&lt;br /&gt;
----Le projet SignSpeak a pour ambition de créer une solution innovante pour la traduction du langage des signes en texte. L'objectif principal est de développer un système capable de capturer les mouvements des mains et de les interpréter en langage des signes, permettant une communication fluide entre les personnes sourdes ou malentendantes et celles qui ne connaissent pas le langage des signes. Ce projet intègre des technologies avancées telles que l'edge computing, l'intelligence artificielle embarquée, et les communications MQTT, offrant une approche novatrice dans le domaine de l'accessibilité et de la communication.&lt;br /&gt;
&lt;br /&gt;
=== 2. Architecture du Système ===&lt;br /&gt;
----Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :&lt;br /&gt;
&lt;br /&gt;
* '''Capteurs et STM32''' : Des capteurs sont connectés à un microcontrôleur STM32, responsables de la capture des mouvements de main. Ces données sont ensuite transmises pour traitement.&lt;br /&gt;
* '''Raspberry Pi''' : Agissant comme un intermédiaire, la Raspberry Pi reçoit les données des capteurs via UART, exécute un traitement préliminaire et communique avec le serveur.&lt;br /&gt;
* '''Serveur et Machine Learning''' : Un serveur, hébergé sur une VM Xen, traite les données à l'aide d'un modèle SVM pour la traduction en langage des signes et fournit une interface web pour l'interaction utilisateur.&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== 3. Collecte et Préparation des Données ===&lt;br /&gt;
----Le processus de collecte des données est géré par le script &amp;lt;code&amp;gt;enregistrementData.py&amp;lt;/code&amp;gt;. Ce script lit les données transmises par le STM32 via UART et les enregistre dans un fichier CSV. Chaque entrée du fichier représente les valeurs de capteurs à un moment donné, accompagnées d'une étiquette correspondant au signe effectué. Cette approche assure une collecte de données structurée, essentielle pour l'entraînement précis du modèle d'apprentissage automatique.&lt;br /&gt;
&lt;br /&gt;
=== 4. Entraînement du Modèle d'Apprentissage Automatique ===&lt;br /&gt;
----L'entraînement du modèle est réalisé par un script Python utilisant la bibliothèque scikit-learn. Le modèle SVM, choisi pour sa capacité à gérer des espaces de grande dimension, est entraîné sur l'ensemble des données collectées. Ce processus comprend la division des données en ensembles d'entraînement et de test, l'entraînement du modèle, et sa validation par le calcul de la précision.&lt;br /&gt;
&lt;br /&gt;
=== 5. Intégration MQTT et Communication ===&lt;br /&gt;
----La communication entre la Raspberry Pi et le serveur utilise le protocole MQTT, un choix idéal pour les applications IoT en raison de sa légèreté et de sa fiabilité. Le script &amp;lt;code&amp;gt;mqtt_client2.py&amp;lt;/code&amp;gt; gère cette communication, permettant à la Raspberry Pi d'envoyer les prédictions du modèle SVM au serveur et de recevoir des commandes pour démarrer ou arrêter la collecte de données.&lt;br /&gt;
&lt;br /&gt;
=== 6. Interface Serveur et Gestion des Données ===&lt;br /&gt;
----Le script &amp;lt;code&amp;gt;app.py&amp;lt;/code&amp;gt; crée une interface serveur utilisant Flask. Cette interface gère les requêtes entrantes, les messages MQTT, et fournit une API pour l'interface utilisateur web. Elle permet également de visualiser les Raspberry Pi disponibles et les derniers messages traduits.&lt;br /&gt;
&lt;br /&gt;
=== 7. Conception de l'Interface Utilisateur ===&lt;br /&gt;
----L'interface utilisateur est développée en HTML, CSS et JavaScript. Le fichier &amp;lt;code&amp;gt;index.html&amp;lt;/code&amp;gt; fournit une interface claire et intuitive pour l'envoi de commandes et la visualisation des traductions. L'utilisation de JavaScript pour interroger dynamiquement le serveur Flask permet une mise à jour en temps réel des informations affichées.&lt;br /&gt;
&lt;br /&gt;
=== 9. Conclusion et Perspectives ===&lt;br /&gt;
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E13&amp;diff=3924</id>
		<title>Atelier SysRes SE5 2023/2024 E13</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E13&amp;diff=3924"/>
		<updated>2024-01-16T17:10:08Z</updated>

		<summary type="html">&lt;p&gt;Bblack : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Cassage de clef WEP:[[Fichier:wep-pw.png|neant|511x511px]]Clé WEP: &lt;br /&gt;
&lt;br /&gt;
Cassage de clef WPA2:&lt;br /&gt;
&lt;br /&gt;
récupération Handshake:[[Fichier:wpa2.png|neant|511x511px]]craquage le mot passe par dictionnaire :[[Fichier:pw-wpa2.png|neant|511x511px]]Clé WPA&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E13&amp;diff=3918</id>
		<title>Atelier SysRes SE5 2023/2024 E13</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E13&amp;diff=3918"/>
		<updated>2024-01-16T17:06:20Z</updated>

		<summary type="html">&lt;p&gt;Bblack : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:wep-pw.png|neant|511x511px]]&lt;br /&gt;
[[Fichier:pw-wpa2.png|neant|511x511px]]&lt;br /&gt;
[[Fichier:wpa2.png|neant|511x511px]]&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E13&amp;diff=3914</id>
		<title>Atelier SysRes SE5 2023/2024 E13</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E13&amp;diff=3914"/>
		<updated>2024-01-16T17:04:53Z</updated>

		<summary type="html">&lt;p&gt;Bblack : Contenu remplacé par «   »&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Wpa2.png&amp;diff=3913</id>
		<title>Fichier:Wpa2.png</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Wpa2.png&amp;diff=3913"/>
		<updated>2024-01-16T17:04:01Z</updated>

		<summary type="html">&lt;p&gt;Bblack : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Wpa2&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Pw-wpa2.png&amp;diff=3909</id>
		<title>Fichier:Pw-wpa2.png</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Pw-wpa2.png&amp;diff=3909"/>
		<updated>2024-01-16T17:02:52Z</updated>

		<summary type="html">&lt;p&gt;Bblack : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Pw-wpa2&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E13&amp;diff=3907</id>
		<title>Atelier SysRes SE5 2023/2024 E13</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E13&amp;diff=3907"/>
		<updated>2024-01-16T17:01:52Z</updated>

		<summary type="html">&lt;p&gt;Bblack : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:wep-pw.png|neant|511x511px]]&lt;br /&gt;
[[Fichier:PRA.png|vignette]]&lt;br /&gt;
Pour les wifis cracotte12 et krakotte12    &lt;br /&gt;
&lt;br /&gt;
'''Clé WEP'''  &amp;quot;    FF:FF:FF:FF:FA:BC:13:CB:AE:EE:EE:EE:EE     &amp;quot;  &lt;br /&gt;
&lt;br /&gt;
'''Clé WPA2'''    &amp;quot;   66678666    &amp;quot;&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E13&amp;diff=3906</id>
		<title>Atelier SysRes SE5 2023/2024 E13</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E13&amp;diff=3906"/>
		<updated>2024-01-16T17:01:32Z</updated>

		<summary type="html">&lt;p&gt;Bblack : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:wep-pw.png|vignette|511x511px]]&lt;br /&gt;
[[Fichier:PRA.png|vignette]]&lt;br /&gt;
Pour les wifis cracotte12 et krakotte12    &lt;br /&gt;
&lt;br /&gt;
'''Clé WEP'''  &amp;quot;    FF:FF:FF:FF:FA:BC:13:CB:AE:EE:EE:EE:EE     &amp;quot;  &lt;br /&gt;
&lt;br /&gt;
'''Clé WPA2'''    &amp;quot;   66678666    &amp;quot;&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E13&amp;diff=3905</id>
		<title>Atelier SysRes SE5 2023/2024 E13</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E13&amp;diff=3905"/>
		<updated>2024-01-16T16:59:42Z</updated>

		<summary type="html">&lt;p&gt;Bblack : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:WEP-PW.png|vignette|511x511px]]&lt;br /&gt;
[[Fichier:PRA.png|vignette]]&lt;br /&gt;
Pour les wifis cracotte12 et krakotte12    &lt;br /&gt;
&lt;br /&gt;
'''Clé WEP'''  &amp;quot;    FF:FF:FF:FF:FA:BC:13:CB:AE:EE:EE:EE:EE     &amp;quot;  &lt;br /&gt;
&lt;br /&gt;
'''Clé WPA2'''    &amp;quot;   66678666    &amp;quot;&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E13&amp;diff=3904</id>
		<title>Atelier SysRes SE5 2023/2024 E13</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E13&amp;diff=3904"/>
		<updated>2024-01-16T16:59:19Z</updated>

		<summary type="html">&lt;p&gt;Bblack : Page créée avec « 511x511px vignette Pour les wifis cracotte12 et krakotte12      '''Clé WEP'''  &amp;quot;    FF:FF:FF:FF:FA:BC:13:CB:AE:EE:EE:EE:EE     &amp;quot;    '''Clé WPA2'''    &amp;quot;   66678666    &amp;quot; »&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:CaptureWPE.png|vignette|511x511px]]&lt;br /&gt;
[[Fichier:PRA.png|vignette]]&lt;br /&gt;
Pour les wifis cracotte12 et krakotte12    &lt;br /&gt;
&lt;br /&gt;
'''Clé WEP'''  &amp;quot;    FF:FF:FF:FF:FA:BC:13:CB:AE:EE:EE:EE:EE     &amp;quot;  &lt;br /&gt;
&lt;br /&gt;
'''Clé WPA2'''    &amp;quot;   66678666    &amp;quot;&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Wep-pw.png&amp;diff=3900</id>
		<title>Fichier:Wep-pw.png</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Wep-pw.png&amp;diff=3900"/>
		<updated>2024-01-16T16:56:09Z</updated>

		<summary type="html">&lt;p&gt;Bblack : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Wep-pw&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_syst%C3%A8me/r%C3%A9seau_2023/2024&amp;diff=3766</id>
		<title>SE5 système/réseau 2023/2024</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_syst%C3%A8me/r%C3%A9seau_2023/2024&amp;diff=3766"/>
		<updated>2024-01-15T07:04:04Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* Répartition des binômes en PRA */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= PRA SE5 =&lt;br /&gt;
&lt;br /&gt;
== Menu de la première séance ==&lt;br /&gt;
&lt;br /&gt;
Pour la  première séance du 06/10/2023 il vous est demandé d'effectuer individuellement les opérations listées ci-dessous.&lt;br /&gt;
* création d'une machine virtuelle sur le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* création d'un conteneur &amp;quot;à la main&amp;quot; sur votre station de travail &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt; :&lt;br /&gt;
** créez un conteneur isolé au maximum (sauf pour les utilisateur) avec la méthode décrite en cours,&lt;br /&gt;
** création d'un commutateur virtuel privé sur la &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt; dans le réseau IPv4 &amp;lt;code&amp;gt;192.168.68.0/24&amp;lt;/code&amp;gt;, l'adresse &amp;lt;code&amp;gt;192.168.68.1&amp;lt;/code&amp;gt; est affectée au commutateur lui-même,&lt;br /&gt;
** création d'une interface Ethernet virtuelle, une extrémité doit être envoyée dans le conteneur, l'autre dans le commutateur virtuel privé,&lt;br /&gt;
** mise en place d'une mascarade sur la &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt;, vérifiez que le conteneur a accès aux mêmes machines que la  &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Par binôme vous devez créer une machine virtuelle mandataire connectée sur le commutateur virtuel SE5 et sur le commutateur virtuel privé des machines virtuelles de services concernées (voir deuxième section du sujet).&lt;br /&gt;
&lt;br /&gt;
Globalement vous devez configurer le routeur principal de la promotion (voir la troisième section du sujet). Pour votre promotion il s'agit du Catalyst 9200 situé en E304. Il faut le connecter en fibre vers le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; de la E306 dans le commutateur virtuel SE5 et aussi en fibre vers le local technique SR52 sur un port dans le VLAN 531. Vous pouvez configurer le commutateur via l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt; à partir de la machine &amp;lt;code&amp;gt;zabeth09&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Répartition des élèves pour la première séance :&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Station de travail !! Elève&lt;br /&gt;
|-&lt;br /&gt;
| zabeth02 || Elias SIMON&lt;br /&gt;
|-&lt;br /&gt;
| zabeth03 || Mathis RIFFAUT&lt;br /&gt;
|-&lt;br /&gt;
| zabeth04 || Dann RODENBURG&lt;br /&gt;
|-&lt;br /&gt;
| zabeth05 || Benjamin NGUYEN&lt;br /&gt;
|-&lt;br /&gt;
| zabeth06 || Halaoui Mohammed&lt;br /&gt;
|-&lt;br /&gt;
| zabeth07 || Blgrim Haitam&lt;br /&gt;
|-&lt;br /&gt;
| zabeth08 || Florian Vallée&lt;br /&gt;
|-&lt;br /&gt;
| zabeth09 (routeur) || Julien Charleux&lt;br /&gt;
|-&lt;br /&gt;
| zabeth10 || Amine SELLALI&lt;br /&gt;
|-&lt;br /&gt;
| zabeth11 || Paul Amoros&lt;br /&gt;
|-&lt;br /&gt;
| zabeth12 || Maël Delaby&lt;br /&gt;
|-&lt;br /&gt;
| zabeth13 || Black Baptiste&lt;br /&gt;
|-&lt;br /&gt;
| zabeth14 || Timothé Brenier&lt;br /&gt;
|-&lt;br /&gt;
| zabeth15 || Jeanne Delcourt&lt;br /&gt;
|-&lt;br /&gt;
| zabeth16 || Estelle Godard&lt;br /&gt;
|-&lt;br /&gt;
| zabeth17 || Jason DELANNOY&lt;br /&gt;
|-&lt;br /&gt;
| zabeth18 || Chloé Lemaire&lt;br /&gt;
|-&lt;br /&gt;
| zabeth19 || Gabriel THOMAS&lt;br /&gt;
|-&lt;br /&gt;
| zabeth20 || Albin MOUTON&lt;br /&gt;
|-&lt;br /&gt;
| zabeth21 || Konstantin PATRIKEEV&lt;br /&gt;
|-&lt;br /&gt;
| zabeth22 || Maxime Balbastre&lt;br /&gt;
|-&lt;br /&gt;
| zabeth26 || François NAUDOT&lt;br /&gt;
|-&lt;br /&gt;
| zabeth27 || Karl HABRE&lt;br /&gt;
|-&lt;br /&gt;
| zabeth28 || Rémi FARAULT&lt;br /&gt;
|-&lt;br /&gt;
| zabeth30 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Répartition des binômes en PRA ==&lt;br /&gt;
&lt;br /&gt;
Concertez-vous pour trouver des noms de machines de services et de machines mandataires dans deux thèmes.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Cahier !! Nom machine services &lt;br /&gt;
!IP machine services !! Nom de domaine !! Nom machine mandataire &lt;br /&gt;
!IP machine mandataires!! Elève &lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E1 | Cahier n°1]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E2 | Cahier n°2]]&lt;br /&gt;
| Elom|| || || Baloo|| || Elias SIMON&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E3 | Cahier n°3]]&lt;br /&gt;
| Mustafar (Mustafare)|| || mustafare.lol|| Baloo|| 193.48.57.189|| Mathis RIFFAUT&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E4 | Cahier n°4]]&lt;br /&gt;
| Dagobah|| || dagobah.lol|| Aladin|| || Dann RODENBURG&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E5 | Cahier n°5]]&lt;br /&gt;
| Motis|| || || Dingo|| || Mohammed Halaoui&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E6 | Cahier n°6]]&lt;br /&gt;
| bogano|| || || Timon|| || Benjamin Nguyen&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E7 | Cahier n°7]]&lt;br /&gt;
| Takobo|| || &amp;lt;code&amp;gt;takobo.lol&amp;lt;/code&amp;gt;|| Timon|| 193.48.57.184|| Timothé Brenier&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E8 | Cahier n°8]]&lt;br /&gt;
| Fondor|| || || mushu|| 193.48.57.190|| Florian Vallée&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E9 | Cahier n°9]]&lt;br /&gt;
| hoth|| || hoth.lol|| BlancheNeige|| 193.48.57.187|| Haitam Blgrim&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E10 | Cahier n°10]]&lt;br /&gt;
| Abafar|| || abafar.lol|| Aladin|| 193.48.57.179|| Amine SELLALI&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E11 | Cahier n°11]]&lt;br /&gt;
| Rotia|| || || DIngo|| 193.48.57.181|| Rémi Farault&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E12 | Cahier n°12]]&lt;br /&gt;
| jedha|| || || judy|| 193.48.57.182|| Julien Charleux&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E13 | Cahier n°13]]&lt;br /&gt;
| Bogden|| || bodgen.lol|| BlancheNeige|| || Black Baptiste&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E14 | Cahier n°14]]&lt;br /&gt;
| endor|| 10.10.10.10|| || mickey|| 193.48.57.188 / 10.10.10.1|| Maël Delaby&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E15 | Cahier n°15]]&lt;br /&gt;
| jiruus|| 192.168.19.3|| jiruus.lol|| cruella|| || Jeanne Delcourt&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E16 | Cahier n°16]]&lt;br /&gt;
| exegol|| 192.168.19.2|| exegol.lol|| cruella|| 193.48.57.186 /&lt;br /&gt;
192.168.19.1&lt;br /&gt;
| Estelle Godard&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E17 | Cahier n°17]]&lt;br /&gt;
| Jakku|| || || Jafar|| || Jason DELANNOY&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E18 | Cahier n°18]]&lt;br /&gt;
| naboo|| 192.168.18.2|| naboo.lol|| bouh|| 193.48.57.180 / 192.168.18.1|| Chloé Lemaire&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E19 | Cahier n°19]]&lt;br /&gt;
| geonosis|| 192.168.18.3|| geonosis.lol|| bouh|| || Gabriel THOMAS&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E20 | Cahier n°20]]&lt;br /&gt;
| alderaan|| || || Jafar|| 193.48.57.183|| Albin MOUTON&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E21 | Cahier n°21]]&lt;br /&gt;
| kesh|| || || Judy|| || Konstantin Patrikeev&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E22 | Cahier n°22]]&lt;br /&gt;
| kashyyyk|| || || mushu|| || Maxime BALBASTRE&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E23 | Cahier n°23]]&lt;br /&gt;
| Felucia|| 192.168.26.2|| || Ursula|| 193.48.57.185 / 192.168.26.1|| François NAUDOT&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E24 | Cahier n°24]]&lt;br /&gt;
| Pelagon|| 10.10.10.11|| || mickey|| 193.48.57.188 / 10.10.10.1|| Paul Amoros&lt;br /&gt;
|-&lt;br /&gt;
|[[Atelier SysRes SE5 2023/2024 E24 | Cahier n°25]]&lt;br /&gt;
|Kalee&lt;br /&gt;
|192.168.26.3&lt;br /&gt;
|kalee.lol&lt;br /&gt;
|Ursula&lt;br /&gt;
|&lt;br /&gt;
|Karl Habre&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Contrôle continu ==&lt;br /&gt;
&lt;br /&gt;
=== Contrôle du 20/11/2023 ===&lt;br /&gt;
&lt;br /&gt;
A noter qu'aucune machine, quelle soit de service ou mandataire, ne peut avoir accès à Internet vu qu'aucun effort n'a été fait pour relier le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; au réseau SE5.&lt;br /&gt;
&lt;br /&gt;
Machines de service.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Elève !! Nom machine !! Configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Elom || Elias SIMON || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Mustafar|| Mathis RIFFAUT || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Dagobah|| Dann RODENBURG || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Motis || Mohammed Halaoui || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| bogano || Benjamin Nguyen || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Takobo || Timothé Brenier || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Fondor || Florian Vallée || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| hoth || Haitam Blgrim || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Abafar || Amine SELLALI || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Rotia || Rémi Farault || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| jedha || Julien Charleux || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Bogden || Black Baptiste || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| jiruus || Jeanne Delcourt || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| exegol || Estelle Godard || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Jakku || Jason DELANNOY || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| naboo || Chloé Lemaire || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| geonosis || Gabriel THOMAS || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| alderaan || Albin MOUTON || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| kesh || Konstantin Patrikeev || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| kashyyyk || Maxime BALBASTRE || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Felucia || François NAUDOT || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Machines mandataires.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Elèves !! Nom machine !! Configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Elias SIMON &amp;amp; Mathis RIFFAUT || Baloo || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Dann RODENBURG &amp;amp; Amine SELLALI || Aladin || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Mohammed Halaoui &amp;amp; Rémi Farault || Dingo || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Benjamin Nguyen &amp;amp; Timothé Brenier || Timon || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Florian Vallée &amp;amp; Maxime BALBASTRE || mushu || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Haitam Blgrim &amp;amp; Black Baptiste || BlancheNeige || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Jeanne Delcourt &amp;amp; Estelle Godard || cruella || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Jason DELANNOY &amp;amp; Albin MOUTON || Jafar || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Chloé Lemaire &amp;amp; Gabriel THOMAS || bouh || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Konstantin Patrikeev &amp;amp; Julien Charleux || judy || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| François NAUDOT &amp;amp; Karl HABRE || Ursula|| rien&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Liste des machines&lt;br /&gt;
&lt;br /&gt;
 Elom Mustafar dagobah Motis bogano Takobo Fondor hoth abafar Rotia jedha Bogden jiruus exegol Jakku naboo geonosis alderaan kesh kashyyyk Felucia&lt;br /&gt;
&lt;br /&gt;
 Baloo aladin Dingo Timon mushu BlancheNeige cruella Jafar bouh judy&lt;br /&gt;
&lt;br /&gt;
=== Contrôle du 03/12/2023 ===&lt;br /&gt;
&lt;br /&gt;
Le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; a été relié au réseau SE5 par &amp;lt;code&amp;gt;naboo&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Il est normal de ne pas avoir d'adresse IPv4 sur la machine de services pour l'interface sur le commutateur virtuel. Par contre, avec mise en place de la mascarade sur la machine mandataire, il doit être possible, pour la machine de services, de se connecter à Internet en IPv4.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Elève !! Nom machine !! Configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Elom || Elias SIMON&lt;br /&gt;
| IPv4 sur CV : 10.0.69.220, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe0f:b26d, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Mustafar|| Mathis RIFFAUT&lt;br /&gt;
| IPv4 sur CV : 10.0.69.165, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fea9:f79, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle &lt;br /&gt;
|-&lt;br /&gt;
| Dagobah|| Dann RODENBURG&lt;br /&gt;
| IPv4 sur CV : 10.0.69.205, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe53:7d33, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle &lt;br /&gt;
|-&lt;br /&gt;
| Motis || Mohammed Halaoui&lt;br /&gt;
| IPv4 sur CV : 10.0.69.195, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe7c:2d6a, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle &lt;br /&gt;
|-&lt;br /&gt;
| bogano || Benjamin Nguyen&lt;br /&gt;
| IPv4 sur CV : 10.0.69.245, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe62:6960, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Takobo || Timothé Brenier&lt;br /&gt;
| IPv4 sur CV : 10.0.69.181, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe93:8c48, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Fondor || Florian Vallée&lt;br /&gt;
| IPv4 sur CV : 10.0.69.200, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe2d:82bf, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| hoth || Haitam Blgrim&lt;br /&gt;
| IPv4 sur CV : 10.0.69.157, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fee8:4736, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle &lt;br /&gt;
|-&lt;br /&gt;
| Abafar || Amine SELLALI&lt;br /&gt;
| IPv4 sur CV : 10.0.69.233, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:feae:bcbb, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Rotia || Rémi Farault&lt;br /&gt;
| IPv4 sur CV : 10.0.69.130, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe2e:ec48, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| jedha || Julien Charleux&lt;br /&gt;
| IPv4 sur CV : 10.0.69.221, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fef6:364f, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Bogden || Black Baptiste&lt;br /&gt;
| IPv4 sur CV : 10.0.69.246, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe67:89fd, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| jiruus || Jeanne Delcourt&lt;br /&gt;
| IPv4 sur CV : 10.0.69.247, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe9c:6f0e, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| exegol || Estelle Godard&lt;br /&gt;
| IPv4 sur CV : 10.0.69.147, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe17:bc38, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Jakku || Jason DELANNOY&lt;br /&gt;
| IPv4 sur CV : 10.0.69.136, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fee1:1e4d, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| naboo || Chloé Lemaire&lt;br /&gt;
| IPv4 sur CV : 192.168.18.2, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fef2:7e2, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| geonosis || Gabriel THOMAS&lt;br /&gt;
| IPv4 sur CV : 10.0.69.231, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:feb0:b140, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| alderaan || Albin MOUTON&lt;br /&gt;
| IPv4 sur CV : 10.0.69.106, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe97:2114, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| kesh || Konstantin Patrikeev&lt;br /&gt;
| IPv4 sur CV : 10.0.69.222, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe10:e2cb, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| kashyyyk || Maxime BALBASTRE&lt;br /&gt;
| IPv4 sur CV : 10.0.69.240, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:feca:73e7, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Felucia || François NAUDOT&lt;br /&gt;
| IPv4 sur CV : 10.0.69.139, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe89:460a, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Machines mandataires.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Elèves !! Nom machine !! Configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Elias SIMON &amp;amp; Mathis RIFFAUT || Baloo &lt;br /&gt;
| IPv4 sur CV : 10.0.69.152, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fec8:5379, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Dann RODENBURG &amp;amp; Amine SELLALI || Aladin&lt;br /&gt;
| IPv4 sur CV : 10.0.69.107, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe6b:c000, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Mohammed Halaoui &amp;amp; Rémi Farault || Dingo&lt;br /&gt;
| IPv4 sur CV : 10.0.69.156, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe0d:4f9c, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Benjamin Nguyen &amp;amp; Timothé Brenier || Timon&lt;br /&gt;
| IPv4 sur CV : 10.0.69.104, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fedc:7539, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Florian Vallée &amp;amp; Maxime BALBASTRE || mushu&lt;br /&gt;
| IPv4 sur CV : 10.0.69.160, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe20:8816, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Haitam Blgrim &amp;amp; Black Baptiste || BlancheNeige&lt;br /&gt;
| IPv4 sur CV : 10.0.69.182, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:feba:38f4, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Jeanne Delcourt &amp;amp; Estelle Godard || cruella&lt;br /&gt;
| IPv4 sur CV : 10.0.69.108, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fee5:ff99, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Jason DELANNOY &amp;amp; Albin MOUTON || Jafar&lt;br /&gt;
| IPv4 sur CV : 10.0.69.171, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe3e:f0bb, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Chloé Lemaire &amp;amp; Gabriel THOMAS || bouh&lt;br /&gt;
| IPv4 sur CV : 192.168.18.1, IPv4 sur SE5 : 193.48.57.180, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe4f:dde2, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Konstantin Patrikeev &amp;amp; Julien Charleux || judy&lt;br /&gt;
| IPv4 sur CV : 10.0.69.216, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe7d:4762, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| François NAUDOT &amp;amp; Karl HABRE ||&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Contrôle du 11/01/2024 ===&lt;br /&gt;
&lt;br /&gt;
Il est normal de ne pas avoir d'adresse IPv4 sur la machine de services pour l'interface sur le commutateur virtuel. Par contre, avec mise en place de la mascarade sur la machine mandataire, il doit être possible, pour la machine de services, de se connecter à Internet en IPv4.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Elève !! Nom machine !! Interfaces dans SE5 et CV !! Domaine Internet !! Accès &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt; root !! DNS installé&lt;br /&gt;
|-&lt;br /&gt;
| Elom || Elias SIMON&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;elom.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Mustafar|| Mathis RIFFAUT&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;mustafare.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Dagobah|| Dann RODENBURG&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;dagobah.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Motis || Mohammed Halaoui&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;motis.hair&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| bogano || Benjamin Nguyen&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;bogano.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Takobo || Timothé Brenier&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;takobo.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Fondor || Florian Vallée&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;fondor.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| hoth || Haitam Blgrim&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;hoth.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Abafar || Amine SELLALI&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;abafar.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Rotia || Rémi Farault&lt;br /&gt;
| SE5 uniquement || Aucun&lt;br /&gt;
| Ajouté || Non&lt;br /&gt;
|-&lt;br /&gt;
| jedha || Julien Charleux&lt;br /&gt;
| SE5 uniquement || Aucun&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Bogden || Black Baptiste&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;bodgen.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| jiruus || Jeanne Delcourt&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;jiruus.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ajouté || Non&lt;br /&gt;
|-&lt;br /&gt;
| exegol || Estelle Godard&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;exegol.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ajouté || Non&lt;br /&gt;
|-&lt;br /&gt;
| Jakku || Jason DELANNOY&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;jakku.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ajouté || Non&lt;br /&gt;
|-&lt;br /&gt;
| naboo || Chloé Lemaire&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;naboo.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ajouté || Non&lt;br /&gt;
|-&lt;br /&gt;
| geonosis || Gabriel THOMAS&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;geonosis.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ajouté || Non&lt;br /&gt;
|-&lt;br /&gt;
| alderaan || Albin MOUTON&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;alderaan.website&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ajouté || Non&lt;br /&gt;
|-&lt;br /&gt;
| kesh || Konstantin Patrikeev&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;kesh.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| kashyyyk || Maxime BALBASTRE&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;kashyyyk.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Felucia || François NAUDOT&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;felucia.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| pelagon || Paul AMOROS&lt;br /&gt;
| activée le 11/01/2024 (IPv6 &amp;lt;code&amp;gt;2001:660:4401:60b0:216:3eff:fe03:2af3&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;pelagon.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Kalee || Karl HABRE&lt;br /&gt;
| pas de machine virtuelle || &amp;lt;code&amp;gt;kalee.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Machines mandataires.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Elèves !! Nom machine !! Commutateur virtuel !! Interfaces dans SE5 et CV !! Accès &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt; root !! DNS installé&lt;br /&gt;
|-&lt;br /&gt;
| Elias SIMON &amp;amp; Mathis RIFFAUT || Baloo &lt;br /&gt;
| Non || Non&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Dann RODENBURG &amp;amp; Amine SELLALI || Aladin&lt;br /&gt;
| Non || Non&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Mohammed Halaoui &amp;amp; Rémi Farault || Dingo&lt;br /&gt;
| Non || Non&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Benjamin Nguyen &amp;amp; Timothé Brenier || Timon&lt;br /&gt;
| Non || Non&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Florian Vallée &amp;amp; Maxime BALBASTRE || mushu&lt;br /&gt;
| Non || Non&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Haitam Blgrim &amp;amp; Black Baptiste || BlancheNeige&lt;br /&gt;
| Non || Non&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Jeanne Delcourt &amp;amp; Estelle Godard || cruella&lt;br /&gt;
| Non || Non&lt;br /&gt;
| Ajouté || Non&lt;br /&gt;
|-&lt;br /&gt;
| Jason DELANNOY &amp;amp; Albin MOUTON || Jafar&lt;br /&gt;
| Non || Non&lt;br /&gt;
| Ajouté || Non&lt;br /&gt;
|-&lt;br /&gt;
| Chloé Lemaire &amp;amp; Gabriel THOMAS || bouh&lt;br /&gt;
| Oui || Oui&lt;br /&gt;
| Ajouté || Non&lt;br /&gt;
|-&lt;br /&gt;
| Konstantin Patrikeev &amp;amp; Julien Charleux || judy&lt;br /&gt;
| Non || Non&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| François NAUDOT &amp;amp; Karl HABRE || Ursula&lt;br /&gt;
| || &lt;br /&gt;
| || &lt;br /&gt;
|-&lt;br /&gt;
| Paul AMOROS || mandataire inconnu&lt;br /&gt;
| || &lt;br /&gt;
| || &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Contrôle du 14/01/2024 ===&lt;br /&gt;
&lt;br /&gt;
Il est normal, pour les machines de services, de ne pas avoir d'@IPv4 sur le commutateur virtuel.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Elève !! Nom machine !! Configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Elom || Elias SIMON&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe0f:b26d, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Mustafar|| Mathis RIFFAUT&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fea9:f79, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Dagobah|| Dann RODENBURG&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe53:7d33, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Motis || Mohammed Halaoui&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe7c:2d6a, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| bogano || Benjamin Nguyen&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe62:6960, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Takobo || Timothé Brenier&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe93:8c48, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Fondor || Florian Vallée&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe2d:82bf, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| hoth || Haitam Blgrim&lt;br /&gt;
| IPv4 sur CV : 10.0.69.157, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fee8:4736, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, &amp;lt;code&amp;gt;bind9&amp;lt;/code&amp;gt; installé pas plus.&lt;br /&gt;
|-&lt;br /&gt;
| Abafar || Amine SELLALI&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:feae:bcbb, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Rotia || Rémi Farault&lt;br /&gt;
| IPv4 sur CV : 10.0.69.130, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe2e:ec48, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| jedha || Julien Charleux&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fef6:364f, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Bogden || Black Baptiste&lt;br /&gt;
| IPv4 sur CV : 10.0.69.246, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe67:89fd, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| jiruus || Jeanne Delcourt&lt;br /&gt;
| IPv4 sur CV : 192.168.19.3, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe9c:6f0e, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, serveur DNS fonctionnel.&lt;br /&gt;
|-&lt;br /&gt;
| exegol || Estelle Godard&lt;br /&gt;
| IPv4 sur CV : 192.168.19.2, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe17:bc38, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, serveur DNS fonctionnel.&lt;br /&gt;
|-&lt;br /&gt;
| Jakku || Jason DELANNOY&lt;br /&gt;
| IPv4 sur CV : 10.0.69.136, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fee1:1e4d, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, serveur DNS fonctionnel.&lt;br /&gt;
|-&lt;br /&gt;
| naboo || Chloé Lemaire&lt;br /&gt;
| IPv4 sur CV : 192.168.18.2, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fef2:7e2, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, serveur DNS fonctionnel.&lt;br /&gt;
|-&lt;br /&gt;
| geonosis || Gabriel THOMAS&lt;br /&gt;
| IPv4 sur CV : 192.168.18.3, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:feb0:b140, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, serveur DNS fonctionnel (aide massive).&lt;br /&gt;
|-&lt;br /&gt;
| alderaan || Albin MOUTON&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe97:2114, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| kesh || Konstantin Patrikeev&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe10:e2cb, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| kashyyyk || Maxime BALBASTRE&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:feca:73e7, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Felucia || François NAUDOT&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe89:460a, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| pelagon || Paul Amoros&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe03:2af3, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| endor || Maël Delaby&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe5f:ebac, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, serveur DNS fonctionnel (mauvais domaine).&lt;br /&gt;
|-&lt;br /&gt;
| Kalee || Karl Harbre&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe45:42ed, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Machines mandataires.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Elèves !! Nom machine !! Configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Elias SIMON &amp;amp; Mathis RIFFAUT || Baloo &lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fec8:5379, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Dann RODENBURG &amp;amp; Amine SELLALI || Aladin&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe6b:c000, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Mohammed Halaoui &amp;amp; Rémi Farault || Dingo&lt;br /&gt;
| IPv4 sur CV : 193.48.57.181 10.0.69.156, IPv4 sur SE5 : 193.48.57.181, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe0d:4f9c, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Benjamin Nguyen &amp;amp; Timothé Brenier || Timon&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fedc:7539, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Florian Vallée &amp;amp; Maxime BALBASTRE || mushu&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe20:8816, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.pas de serveur DNS.z&lt;br /&gt;
|-&lt;br /&gt;
| Haitam Blgrim &amp;amp; Black Baptiste || BlancheNeige&lt;br /&gt;
| IPv4 sur CV : 193.48.57.187 10.0.69.182, IPv4 sur SE5 : 193.48.57.187, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:feba:38f4, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, &amp;lt;code&amp;gt;bind9&amp;lt;/code&amp;gt; installé sans plus.&lt;br /&gt;
|-&lt;br /&gt;
| Jeanne Delcourt &amp;amp; Estelle Godard || cruella&lt;br /&gt;
| IPv4 sur CV : 193.48.57.186 192.168.19.1, IPv4 sur SE5 : 193.48.57.186, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fee5:ff99, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, serveur DNS secondaire configuré.&lt;br /&gt;
|-&lt;br /&gt;
| Jason DELANNOY &amp;amp; Albin MOUTON || Jafar&lt;br /&gt;
| IPv4 sur CV : 193.48.57.183 10.0.69.1, IPv4 sur SE5 : 193.48.57.183, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe3e:f0bb, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, &amp;lt;code&amp;gt;bind9&amp;lt;/code&amp;gt; installé sans plus.&lt;br /&gt;
|-&lt;br /&gt;
| Chloé Lemaire &amp;amp; Gabriel THOMAS || bouh&lt;br /&gt;
| IPv4 sur CV : 193.48.57.180 192.168.18.1, IPv4 sur SE5 : 193.48.57.180, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe4f:dde2, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, serveur DNS secondaire configuré.&lt;br /&gt;
|-&lt;br /&gt;
| Konstantin Patrikeev &amp;amp; Julien Charleux || judy&lt;br /&gt;
| IPv4 sur CV : 193.48.57.182, IPv4 sur SE5 : 193.48.57.182, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe7d:4762, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Paul Amoros &amp;amp; Maël Delaby || mickey&lt;br /&gt;
| IPv4 sur CV : 193.48.57.188 10.10.10.2 10.10.10.1, IPv4 sur SE5 : 193.48.57.188, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe34:13d5, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, serveur DNS secondaire configuré mais le répertoire pour les zones secondaires n'existe pas, l'écriture échoue.&lt;br /&gt;
|-&lt;br /&gt;
| François NAUDOT &amp;amp; Karl HABRE || Ursula&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe33:7f89, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Répartition des binômes en ASR ==&lt;br /&gt;
&lt;br /&gt;
Donnez les élèves dans chaque groupe.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Groupe !! Elèves &lt;br /&gt;
|-&lt;br /&gt;
| g1 || Konstantin Patrikeev &amp;amp; Julien Charleux &lt;br /&gt;
|-&lt;br /&gt;
| g2 || Chloé Lemaire &amp;amp; Gabriel Thomas&lt;br /&gt;
|-&lt;br /&gt;
| g3 || Timothé Brenier &amp;amp; Benjamin Nguyen&lt;br /&gt;
|-&lt;br /&gt;
| g4 || François Naudot &amp;amp; Dann Rodenburg &lt;br /&gt;
|-&lt;br /&gt;
| g5 || Maël Delaby &amp;amp; Paul Amoros &lt;br /&gt;
|-&lt;br /&gt;
| g6 || Haitam Blgrim &amp;amp; Baptiste Black &lt;br /&gt;
|-&lt;br /&gt;
| g7 || Jason Delannoy &amp;amp; Albin Mouton &lt;br /&gt;
|-&lt;br /&gt;
| g8 || Elias Simon &amp;amp; Mathis Riffaut &lt;br /&gt;
|-&lt;br /&gt;
| g10 || Estelle Godard &amp;amp; Jeanne Delcourt&lt;br /&gt;
|-&lt;br /&gt;
| g11 || Karl Habre &amp;amp; Amine Sellali &lt;br /&gt;
|-&lt;br /&gt;
| g12 || Mohammed Halaoui &amp;amp; Rémi Farault &lt;br /&gt;
|-&lt;br /&gt;
|g13&lt;br /&gt;
|Maxime Balbastre &amp;amp; Florian Vallée&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Le 05/11/2023, aucun commutateur virtuel correctement configuré, soit une adresse IPv4 sur le commutateur pour aucune raison, soit une configuration &amp;lt;code&amp;gt;static&amp;lt;/code&amp;gt; non adaptée, pas de &amp;lt;code&amp;gt;up&amp;lt;/code&amp;gt; sur le commutateur virtuel.&lt;br /&gt;
&lt;br /&gt;
== Contrôle continu ==&lt;br /&gt;
&lt;br /&gt;
=== Contrôle au 05/11/2023 ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Groupe !! Elèves !! Migration !! Archi. penfret !! Archi. antifer&lt;br /&gt;
|-&lt;br /&gt;
| g1 || Konstantin Patrikeev &amp;amp; Julien Charleux || || jcharleu, CV conf. erronée, MV interf. vlan50, pas de config. IPv4 || kpatrikee, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, routeur mauvais disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g2 || Chloé Lemaire &amp;amp; Gabriel Thomas || || gthomas, CV conf. erronée, MV mdp erroné, interf. vlan50 || clemair1, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, routeur lancé, une seule interface réseau, pas de config. réseau&lt;br /&gt;
|-&lt;br /&gt;
| g3 || Timothé Brenier &amp;amp; Benjamin Nguyen || || bnguyen1, CV conf. erronée, MV interf. vlan50, pas de config. IPv4 || tbrenier, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, routeur mauvais disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g4 || François Naudot &amp;amp; Dann Rodenburg || || drodenbu, CV conf. erronée, MV interf. vlan50, pas de config. IPv4 || fnaudot, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, routeur mauvais disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g5 || Maël Delaby &amp;amp; Paul Amoros || || pas de CV, pas de MV || mdelaby, CV conf. erronée, pygrub dans la MV ? pas de routeur, faut lui créer son propre &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g6 || Haitam Blgrim &amp;amp; Baptiste Black || || hblgrim, CV conf. erronée, MV avec 2 interfaces, pas de MAC sur la 1ère, config. IPv4 OK || bblack, CV commenté, pas de MV (plus exactement une machine visible via &amp;lt;code&amp;gt;xen list&amp;lt;/code&amp;gt; mais pas de &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;/etc/xen&amp;lt;/code&amp;gt;), pas de routeur OpenWRT&lt;br /&gt;
|-&lt;br /&gt;
| g7 || Jason Delannoy &amp;amp; Albin Mouton || || jdelanno, CV conf. erronée, MV interf. vlan50, pas de config. IPv4 || amouton, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, routeur lancé, une seule interface réseau&lt;br /&gt;
|-&lt;br /&gt;
| g8 || Elias Simon &amp;amp; Mathis Riffaut || || mriffaut, CV conf. erronée, MV interf. vlan50, pas de config. IPv4 || esimon, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, pas de routeur&lt;br /&gt;
|-&lt;br /&gt;
| g10 || Estelle Godard &amp;amp; Jeanne Delcourt || || jdelcour, CV conf. erronée, MV interf. vlan50, pas de config. IPv4 || egodard, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, routeur lancé, deux interfaces réseau, changez l'ordre des interfaces dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g11 || Karl Habre &amp;amp; Amine Sellali || || khabre, CV conf. erronée, MV non créée, MV interf. vlan50, pas de config. IPv4 || asellali, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, routeur avec une définition de disque aberrante dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g12 || Mohammed Halaoui &amp;amp; Rémi Farault || || rfarault, CV conf. erronée, MV interf. vlan50, pas de config. IPv4 || pas de CV, MV interf. vlan50, pas de config. IPv4, pas de routeur&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Contrôle au 20/11/2023 ===&lt;br /&gt;
&lt;br /&gt;
A noter qu'un sacré coup de pouce aura été nécessaire pour configurer le routeur de promotion, avec un seul élève en appui.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Groupe !! Elèves !! Migration !! Archi. penfret !! Archi. antifer&lt;br /&gt;
|-&lt;br /&gt;
| g1 || Konstantin Patrikeev &amp;amp; Julien Charleux || || jcharleu, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte || kpatrikee, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, pour le routeur toujours une mauvaise définition de disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g2 || Chloé Lemaire &amp;amp; Gabriel Thomas || || gthomas, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), pas de configuration IPv4 correcte || clemair1, CV configuré, VLAN configuré, MV lancée et totalement configurée en IPv4, routeur lancé et correctement configuré&lt;br /&gt;
|-&lt;br /&gt;
| g3 || Timothé Brenier &amp;amp; Benjamin Nguyen || || bnguyen1, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte || tbrenier, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, pour le routeur toujours une mauvaise définition de disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;, deux interfaces cependant&lt;br /&gt;
|-&lt;br /&gt;
| g4 || François Naudot &amp;amp; Dann Rodenburg || || drodenbu, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte || fnaudot, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, pour le routeur toujours une mauvaise définition de disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;, deux interfaces cependant&lt;br /&gt;
|-&lt;br /&gt;
| g5 || Maël Delaby &amp;amp; Paul Amoros || || toujours pas de CV, pas de VLAN, toujours pas de MV || mdelaby, CV configuration toujours erronée, pas de VLAN, toujours le bootloader &amp;lt;code&amp;gt;pygrub&amp;lt;/code&amp;gt; dans la MV (commenté), MV avec une seule interface réseau (dans le CV), configuration DHCP OK pour l'interface (dans le CV), toujours pas de routeur : il faut lui créer son propre &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g6 || Haitam Blgrim &amp;amp; Baptiste Black || || hblgrim, CV conf. toujours erronée, pas de VLAN, MV ne démarre pas à cause de l'erreur sur le CV (correction ReX sur le CV), MV avec 2 interfaces, pas de MAC sur la première interface dans le .cfg, configuration IPv4 OK dans la MV || bblack, CV configuration toujours erronée, pas de VLAN, toujours pas e &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; pour la MV, un routeur OpenWRT avec la bonne définition de disque, deux interface mais sans @MAC, aucune configuration du routeur&lt;br /&gt;
|-&lt;br /&gt;
| g7 || Jason Delannoy &amp;amp; Albin Mouton || || jdelanno, CV conf. toujours, erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte || amouton, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, routeur lancé, une seule interface réseau, pas de configuration du routeur&lt;br /&gt;
|-&lt;br /&gt;
| g8 || Elias Simon &amp;amp; Mathis Riffaut || || mriffaut, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), pas de configuration IPv4 correcte || esimon, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, toujours pas de routeur&lt;br /&gt;
|-&lt;br /&gt;
| g10 || Estelle Godard &amp;amp; Jeanne Delcourt || || jdelcour, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), pas de configuration IPv4 correcte || egodard, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, routeur lancé, deux interfaces réseau, pas de configuration du routeur&lt;br /&gt;
|-&lt;br /&gt;
| g11 || Karl Habre &amp;amp; Amine Sellali || || khabre, CV conf. toujours erronée, pas de VLAN, MV enfin créée avec une seule interface, pas de configuration IPv4 correcte || asellali, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, routeur avec une définition de disque aberrante dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;, une seule interface, pas de configuration du routeur&lt;br /&gt;
|-&lt;br /&gt;
| g12 || Mohammed Halaoui &amp;amp; Rémi Farault || || rfarault, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), pas de configuration IPv4 correcte || pas de CV, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, toujours pas de routeur&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Contrôle au 30/11/2023 ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Groupe !! Elèves !! Archi. penfret !! Archi. antifer&lt;br /&gt;
|-&lt;br /&gt;
| g1 || Konstantin Patrikeev &amp;amp; Julien Charleux || jcharleu, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte. || kpatrikee, CV et VLAN configurés mais dites moi comment vous trouvez 1 avec la formule &amp;lt;code&amp;gt;6+N%4&amp;lt;/code&amp;gt;, MV avec les bonnes interfaces, inversion dans la configuration IPv4 entre &amp;lt;code&amp;gt;enX0&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;enX1&amp;lt;/code&amp;gt;, pour le routeur toujours une mauvaise définition de disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; par contre les deux interfaces demandées sont présentes.&lt;br /&gt;
|-&lt;br /&gt;
| g2 || Chloé Lemaire &amp;amp; Gabriel Thomas || gthomas, CV configuré, VLAN configuré, MV lancée et totalement configurée en IPv4. || clemair1, CV configuré, VLAN configuré, MV lancée et totalement configurée en IPv4, routeur lancé et correctement configuré.&lt;br /&gt;
|-&lt;br /&gt;
| g3 || Timothé Brenier &amp;amp; Benjamin Nguyen || bnguyen1, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte. || tbrenier, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, pour le routeur toujours une mauvaise définition de disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;, deux interfaces cependant.&lt;br /&gt;
|-&lt;br /&gt;
| g4 || François Naudot &amp;amp; Dann Rodenburg || drodenbu, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte. || fnaudot, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, pour le routeur toujours une mauvaise définition de disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;, deux interfaces cependant.&lt;br /&gt;
|-&lt;br /&gt;
| g5 || Maël Delaby &amp;amp; Paul Amoros || toujours pas de CV, pas de VLAN, toujours pas de MV. || mdelaby, CV configuration toujours erronée, pas de VLAN, toujours le bootloader &amp;lt;code&amp;gt;pygrub&amp;lt;/code&amp;gt; dans la MV (commenté), MV avec un chemin des disques étranges, MV avec une seule interface réseau (dans le CV), configuration DHCP OK pour l'interface (dans le CV), toujours pas de routeur : il faut lui créer son propre &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| g6 || Haitam Blgrim &amp;amp; Baptiste Black || hblgrim, il manque les directives pour démarrer et arrêter les interfaces mais sinon CV et VLAN configurés, MV lancé et configurée, il ne faut pas de &amp;lt;code&amp;gt;gateway&amp;lt;/code&amp;gt; sur &amp;lt;code&amp;gt;enX1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;enX0&amp;lt;/code&amp;gt; ne trouve pas son adresse par DHCP à cause du commutateur virtuel non activé. || bblack, CV et VLAN configurés mais pas toutes les directives de démarrage et d'arrêt, toujours pas de &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; pour la MV, un routeur OpenWRT avec la bonne définition de disque, deux interface mais sans @MAC, aucune configuration du routeur.&lt;br /&gt;
|-&lt;br /&gt;
| g7 || Jason Delannoy &amp;amp; Albin Mouton || jdelanno, CV conf. toujours, erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte; || amouton, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, routeur lancé, une seule interface réseau, pas de configuration du routeur.&lt;br /&gt;
|-&lt;br /&gt;
| g8 || Elias Simon &amp;amp; Mathis Riffaut || mriffaut, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), pas de configuration IPv4 correcte. || esimon, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, toujours pas de routeur.&lt;br /&gt;
|-&lt;br /&gt;
| g10 || Estelle Godard &amp;amp; Jeanne Delcourt || jdelcour, CV configuré, VLAN configuré (par contre l'utilisation de &amp;lt;code&amp;gt;ether4&amp;lt;/code&amp;gt; est impossible), MV lancée et correctement configurée en IPv4, &amp;lt;code&amp;gt;enX0&amp;lt;/code&amp;gt; ne trouve pas son @IPv4 à cause de l'erreur sur le VLAN. || egodard, CV configuré, VLAN configuré (par contre l'utilisation de &amp;lt;code&amp;gt;ether4&amp;lt;/code&amp;gt; est impossible), MV avec deux interfaces, correctement configurée en IPv4, pas d'adresse obtenue par DHCP, problème de l'OpenWRT, routeur OpenWRT avec les bonnes interfaces, l'adresse IPv4 sur SE5 est donnée avec un mauvais masque, linterface &amp;lt;code&amp;gt;enX0&amp;lt;/code&amp;gt; reçoit bien son adresse IPv4 par DHCP.&lt;br /&gt;
|-&lt;br /&gt;
| g11 || Karl Habre &amp;amp; Amine Sellali || khabre, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface, pas de configuration IPv4 correcte || asellali, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, routeur avec une définition de disque aberrante dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;, une seule interface, pas de configuration du routeur&lt;br /&gt;
|-&lt;br /&gt;
| g12 || Mohammed Halaoui &amp;amp; Rémi Farault || rfarault, CV configuré, VLAN configuré mais configuration commentée (pourquoi donc ?!), MV lancée et correctement configurée en IPv4, &amp;lt;code&amp;gt;enX0&amp;lt;/code&amp;gt; ne trouve pas son @IPv4 à cause de l'absence d'interface VLAN. || CV configuré, VLAN configuré, MV avec deux interfaces, correctement configurée en IPv4, un routeur avec les deux interfaces demandées, pas d'adresse IPv4 sur SE5, serveur DHCP fonctionnel.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Contrôle au 02/12/2023 ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Groupe !! Elèves !! MV &amp;lt;code&amp;gt;penfret&amp;lt;/code&amp;gt; !! MV &amp;lt;code&amp;gt;antifer&amp;lt;/code&amp;gt; !! Routeur OpenWRT&lt;br /&gt;
|-&lt;br /&gt;
| g1 || Konstantin Patrikeev &amp;amp; Julien Charleux&lt;br /&gt;
| IPv4 sur CV : 10.0.69.185, IPv4 sur VLAN50 : 172.126.145.103, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe00:a98d, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.218, IPv4 sur VLAN50 : 172.26.145.102, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe7d:bc44, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| pas d'IPv4 routée sur Internet, une IPv6 routée sur Internet, pas de connexion à Internet en IPv4&lt;br /&gt;
|-&lt;br /&gt;
| g2 || Chloé Lemaire &amp;amp; Gabriel Thomas&lt;br /&gt;
| IPv4 sur CV : 10.0.69.212, IPv4 sur VLAN50 : 172.26.145.105, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fedb:2ac4, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.145, IPv4 sur VLAN50 : 172.26.145.104, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe31:b916, connexion à Internet en IPv4 possible, resolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.180, une IPv6 routée sur Internet, connexion à Internet en IPv4 possible&lt;br /&gt;
|-&lt;br /&gt;
| g3 || Timothé Brenier &amp;amp; Benjamin Nguyen &lt;br /&gt;
| MV non contactable sur le VLAN 50 en IPv6&lt;br /&gt;
| pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.106, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feaa:f292, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| routeur openWRT non fonctionnel&lt;br /&gt;
|-&lt;br /&gt;
| g4 || François Naudot &amp;amp; Dann Rodenburg &lt;br /&gt;
| MV non contactable sur le VLAN 50 en IPv6&lt;br /&gt;
| pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.108, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fec6:168, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| routeur openWRT non fonctionnel (si ? non, inversion des &amp;lt;code&amp;gt;vif&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| g5 || Maël Delaby &amp;amp; Paul Amoros&lt;br /&gt;
| MV non contactable sur le VLAN 50 en IPv6&lt;br /&gt;
| image disque du fichier de configuration non présente sur &amp;lt;code&amp;gt;antifer&amp;lt;/code&amp;gt;&lt;br /&gt;
| routeur openWRT non fonctionnel&lt;br /&gt;
|-&lt;br /&gt;
| g6 || Haitam Blgrim &amp;amp; Baptiste Black &lt;br /&gt;
| MV non contactable sur le VLAN 50 en IPv6&lt;br /&gt;
| pas de fichier de configuration&lt;br /&gt;
| routeur openWRT non fonctionnel&lt;br /&gt;
|-&lt;br /&gt;
| g7 || Jason Delannoy &amp;amp; Albin Mouton&lt;br /&gt;
| MV non contactable sur le VLAN 50 en IPv6&lt;br /&gt;
| machine non contactable en IPv6 sur le bridgeStudents&lt;br /&gt;
| pas d'adresse MAC dans le fichier de configuration&lt;br /&gt;
|-&lt;br /&gt;
| g8 || Elias Simon &amp;amp; Mathis Riffaut&lt;br /&gt;
| MV non contactable sur le VLAN 50 en IPv6&lt;br /&gt;
| pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.116, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe01:754c, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| routeur openWRT non fonctionnel&lt;br /&gt;
|-&lt;br /&gt;
| g10 || Estelle Godard &amp;amp; Jeanne Delcourt&lt;br /&gt;
| IPv4 sur CV : 10.0.69.165, IPv4 sur VLAN50 : 172.26.145.121, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe7e:35e1, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.132, IPv4 sur VLAN50 : 172.26.145.120, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feb4:5ea3, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.191, une IPv6 routée sur Internet, pas de connexion à Internet en IPv4&lt;br /&gt;
|-&lt;br /&gt;
| g11 || Karl Habre &amp;amp; Amine Sellali&lt;br /&gt;
| MV non contactable sur le VLAN 50 en IPv6&lt;br /&gt;
| machine non contactable en IPv6 sur le bridgeStudents&lt;br /&gt;
| pas d'adresse MAC dans le fichier de configuration, création du routeur impossible&lt;br /&gt;
|-&lt;br /&gt;
| g12 || Mohammed Halaoui &amp;amp; Rémi Farault&lt;br /&gt;
| pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.125, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe54:5aee, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.124, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe9a:5186, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| pas d'IPv4 routée sur Internet, pas d'IPv6 routée sur Internet, pas de connexion à Internet en IPv4&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Contrôle au 05/12/2023 ===&lt;br /&gt;
&lt;br /&gt;
Pour utiliser l'interface Web LuCi des openWRT à partir d'une zabeth :&lt;br /&gt;
* vérifiez que vous avez bien une IPv6 routée sur IPv6 (avec &amp;lt;code&amp;gt;ip address show dev eth0&amp;lt;/code&amp;gt;, l'adresse commence par &amp;lt;code&amp;gt;2001:660:4401:60b0:&amp;lt;/code&amp;gt;) ;&lt;br /&gt;
* si vous n'en avez pas, prenez le suffixe (les derniers 8 octets de l'adresse locale, celle qui commence par &amp;lt;code&amp;gt;fe80::&amp;lt;/code&amp;gt;) et créez votre adresse IPv6 routée par la commande :&lt;br /&gt;
  ip address add dev eth0 2001:660:4401:60b0:&amp;lt;suffixe&amp;gt;/64&lt;br /&gt;
bien entendu vous n'aurez oublié de rajouter la route IPv6 par défaut vers le routeur de la promotion :&lt;br /&gt;
  ip -6 route add default via 2001:660:4401:60b0:6a9e:bff:fe46:5a76&lt;br /&gt;
* établissez un tunnel &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt; avec la commande :&lt;br /&gt;
 zabethXX# ssh -L 6443:localhost:6443 root@IPv6&lt;br /&gt;
* connectez vous sur LuCi avec le navigateur de la zabeth pointant sur &amp;lt;code&amp;gt;https://localhost:6443&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attention l'ordre des interfaces &amp;lt;code&amp;gt;vif&amp;lt;/code&amp;gt; dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; a une importance.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Groupe !! Elèves !! MV &amp;lt;code&amp;gt;penfret&amp;lt;/code&amp;gt; !! MV &amp;lt;code&amp;gt;antifer&amp;lt;/code&amp;gt; !! Routeur OpenWRT&lt;br /&gt;
|-&lt;br /&gt;
| g1 || Konstantin Patrikeev &amp;amp; Julien Charleux&lt;br /&gt;
| IPv4 sur CV : 10.0.69.185, IPv4 sur VLAN50 : 172.126.145.103, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe00:a98d, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.218, IPv4 sur VLAN50 : 172.26.145.102, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe7d:bc44, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| pas d'IPv4 routée sur Internet (puis &amp;lt;code&amp;gt;193.48.57.191&amp;lt;/code&amp;gt; donc une erreur), pas d'IPv6 routée sur Internet, pas de connexion à Internet en IPv4&lt;br /&gt;
|-&lt;br /&gt;
| g2 || Chloé Lemaire &amp;amp; Gabriel Thomas&lt;br /&gt;
| IPv4 sur CV : 10.0.69.212, IPv4 sur VLAN50 : 172.26.145.105, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fedb:2ac4, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.145, IPv4 sur VLAN50 : 172.26.145.104, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe31:b916, connexion à Internet en IPv4 possible, resolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.180, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fe31:b916, connexion à Internet en IPv4 possible&lt;br /&gt;
|-&lt;br /&gt;
| g3 || Timothé Brenier &amp;amp; Benjamin Nguyen &lt;br /&gt;
| IPv4 sur CV : 10.0.69.130, IPv4 sur VLAN50 : 172.26.145.107, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feff:4c44, connexion à Internet en IPv4 possible, résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.167, IPv4 sur VLAN50 : 172.26.145.106, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feaa:f292, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.184, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:feaa:f293, connexion à Internet en IPv4 possible&lt;br /&gt;
|-&lt;br /&gt;
| g4 || François Naudot &amp;amp; Dann Rodenburg &lt;br /&gt;
| IPv4 sur CV : 10.0.69.156, IPv4 sur VLAN50 : 172.26.145.109, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe46:70cd, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.106, IPv4 sur VLAN50 : 172.26.145.108, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fec6:168, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.185, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fec6:169, connexion à Internet en IPv4 possible&lt;br /&gt;
|-&lt;br /&gt;
| g5 || Maël Delaby &amp;amp; Paul Amoros&lt;br /&gt;
| IPv4 sur CV : 10.0.69.189, IPv4 sur VLAN50 : 172.26.145.111, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe14:cdb5, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.171, IPv4 sur VLAN50 : 172.26.145.110, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe5b:b2b5, connexion à Internet en IPv4 possible, resolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.188, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fe5b:b2b6, connexion à Internet en IPv4 possible&lt;br /&gt;
|-&lt;br /&gt;
| g6 || Haitam Blgrim &amp;amp; Baptiste Black &lt;br /&gt;
| IPv4 sur CV : 10.0.69.100, IPv4 sur VLAN50 : 172.26.145.113, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fef9:2bb9, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| pas de machine virtuelle&lt;br /&gt;
| bloquage du serveur &amp;lt;code&amp;gt;antifer&amp;lt;/code&amp;gt; par installation du routeur openWRT sous la racine, machine non contactable en IPv6 sur le SE5&lt;br /&gt;
|-&lt;br /&gt;
| g7 || Jason Delannoy &amp;amp; Albin Mouton&lt;br /&gt;
| CV non configuré, machine non contactable en IPv6 sur le VLAN50&lt;br /&gt;
| machine non contactable en IPv6 sur le bridgeStudent&lt;br /&gt;
| pas d'adresse MAC dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g8 || Elias Simon &amp;amp; Mathis Riffaut&lt;br /&gt;
| CV non configuré, machine non contactable en IPv6 sur le VLAN50&lt;br /&gt;
| machine non contactable en IPv6 sur le bridgeStudents&lt;br /&gt;
| machine non contactable en IPv6 sur le SE5&lt;br /&gt;
|-&lt;br /&gt;
| g10 || Estelle Godard &amp;amp; Jeanne Delcourt&lt;br /&gt;
| IPv4 sur CV : 10.0.69.165, IPv4 sur VLAN50 : 172.26.145.121, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe7e:35e1, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.132, IPv4 sur VLAN50 : 172.26.145.120, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feb4:5ea3, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.191 (erreur !!), IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:feb4:5ea4, pas de connexion à Internet en IPv4&lt;br /&gt;
|-&lt;br /&gt;
| g11 || Karl Habre &amp;amp; Amine Sellali&lt;br /&gt;
| machine non contactable en IPv6 sur le VLAN50&lt;br /&gt;
| machine non contactable en IPv6 sur le bridgeStudents&lt;br /&gt;
| pas d'adresse MAC dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g12 || Mohammed Halaoui &amp;amp; Rémi Farault&lt;br /&gt;
| IPv4 sur CV : 10.0.69.131, IPv4 sur VLAN50 : 172.26.145.125, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe54:5aee, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.124, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe9a:5186, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.181, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fe9a:5186, pas de connexion à Internet en IPv4&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Pas de changement sur les routeurs OpenWRT à 17h30.&lt;br /&gt;
&lt;br /&gt;
Pas de changement sur les MV d'&amp;lt;code&amp;gt;antifer&amp;lt;/code&amp;gt; à 18h00.&lt;br /&gt;
&lt;br /&gt;
Une seule modification sur les MV de &amp;lt;code&amp;gt;penfret&amp;lt;/code&amp;gt; à 18h15 : la G7 (&amp;lt;code&amp;gt;g7jdelannoVM&amp;lt;/code&amp;gt;) est maintenant contactable (@IPv4 et @IPv6 sur le VLAN50) mais sans rien de plus.&lt;br /&gt;
&lt;br /&gt;
=== Contrôle au 06/12/2023 ===&lt;br /&gt;
&lt;br /&gt;
Données brutes pour les routeurs openWRT (pas de relancement) :&lt;br /&gt;
&lt;br /&gt;
 G1 | IPv4 sur Internet : 193.48.57.191, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fe7d:bc44, pas de connexion à Internet en IPv4&lt;br /&gt;
 G2 | IPv4 sur Internet : 193.48.57.180, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fe31:b916, connexion à Internet en IPv4 possible&lt;br /&gt;
 G3 | IPv4 sur Internet : 193.48.57.184, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:feaa:f293, connexion à Internet en IPv4 possible&lt;br /&gt;
 G4 | IPv4 sur Internet : 193.48.57.185, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fec6:169, connexion à Internet en IPv4 possible&lt;br /&gt;
 G5 | IPv4 sur Internet : 193.48.57.188, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fe5b:b2b6, connexion à Internet en IPv4 possible&lt;br /&gt;
 G6 | IPv4 sur Internet : 193.48.57.187, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fef9:2bba, connexion à Internet en IPv4 possible&lt;br /&gt;
 G7 | Bad MAC address &lt;br /&gt;
 G8 | machine non contactable en IPv6 sur le SE5&lt;br /&gt;
 G9 | Rien&lt;br /&gt;
 G10 | IPv4 sur Internet : 193.48.57.186, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:feb4:5ea4, pas de connexion à Internet en IPv4&lt;br /&gt;
 G11 | machine non contactable en IPv6 sur le SE5&lt;br /&gt;
 G12 | IPv4 sur Internet : 193.48.57.181, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fe9a:5186, pas de connexion à Internet en IPv4&lt;br /&gt;
&lt;br /&gt;
Données brutes pour les MV sur &amp;lt;code&amp;gt;antifer&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
 ==== g1kpatrikeevVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.218, IPv4 sur VLAN50 : 172.26.145.102, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe7d:bc44, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g2clemair1VM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.145, IPv4 sur VLAN50 : 172.26.145.104, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe31:b916, connexion à Internet en IPv4 possible, resolution DNS fonctionnelle&lt;br /&gt;
 ==== g3tbrenierVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.167, IPv4 sur VLAN50 : 172.26.145.106, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feaa:f292, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g4fnaudotVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.106, IPv4 sur VLAN50 : 172.26.145.108, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fec6:168, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g5mdelabyVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.171, IPv4 sur VLAN50 : 172.26.145.110, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe5b:b2b5, connexion à Internet en IPv4 possible, resolution DNS fonctionnelle&lt;br /&gt;
 ==== g6bblackVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.113, IPv4 sur VLAN50 : 172.26.145.112, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe4a:d2be, connexion à Internet en IPv4 possible, resolution DNS fonctionnelle&lt;br /&gt;
 ==== g7amoutonVM&lt;br /&gt;
 | pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.114, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe59:7616, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g8esimonVM&lt;br /&gt;
 | machine non contactable en IPv6 sur le bridgeStudents&lt;br /&gt;
 ==== g10egodardVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.132, IPv4 sur VLAN50 : 172.26.145.120, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feb4:5ea3, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g11asellaliVM&lt;br /&gt;
 | machine non contactable en IPv6 sur le bridgeStudents&lt;br /&gt;
 ==== g12mhalaouiVM&lt;br /&gt;
 | pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.124, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe9a:5186, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
&lt;br /&gt;
Données brutes pour les MV sur &amp;lt;code&amp;gt;penfret&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
 ==== g1jcharleuxVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.185, IPv4 sur VLAN50 : 172.126.145.103, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe00:a98d, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g2gthomasVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.212, IPv4 sur VLAN50 : 172.26.145.105, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fedb:2ac4, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g3bnguyen1VM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.130, IPv4 sur VLAN50 : 172.26.145.107, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feff:4c44, connexion à Internet en IPv4 possible, résolution DNS fonctionnelle&lt;br /&gt;
 ==== g4drodenbuVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.156, IPv4 sur VLAN50 : 172.26.145.109, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe46:70cd, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g5pamorosVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.189, IPv4 sur VLAN50 : 172.26.145.111, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe14:cdb5, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g6hblgrimVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.100, IPv4 sur VLAN50 : 172.26.145.113, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fef9:2bb9, connexion à Internet en IPv4 possible, résolution DNS fonctionnelle&lt;br /&gt;
 ==== g7jdelannoVM&lt;br /&gt;
 | pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.115, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe0f:aba1, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g8mriffautVM&lt;br /&gt;
 | machine non contactable en IPv6 sur le VLAN50&lt;br /&gt;
 ==== g10jdelcourVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.165, IPv4 sur VLAN50 : 172.26.145.121, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe7e:35e1, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g11khabreVM&lt;br /&gt;
 | machine non contactable en IPv6 sur le VLAN50&lt;br /&gt;
 ==== g12rfaraultVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.131, IPv4 sur VLAN50 : 172.26.145.125, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe54:5aee, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
&lt;br /&gt;
Trois groupes finissent à 17h : G2, G5 et G7.&lt;br /&gt;
&lt;br /&gt;
Un groupe à 17h20 : G6.&lt;br /&gt;
&lt;br /&gt;
Un groupe à 17h40 : G10.&lt;br /&gt;
&lt;br /&gt;
Le reste :&lt;br /&gt;
&lt;br /&gt;
  G8 -&amp;gt; installation du conteneur synapse&lt;br /&gt;
  G3 -&amp;gt; erreur à la connexion de la base de données, encodage ASCII&lt;br /&gt;
  G4 -&amp;gt; création de la base de données&lt;br /&gt;
  G12 -&amp;gt; problème à l'exécution du conteneur&lt;br /&gt;
  G11 -&amp;gt; essayent d'installer le conteneur synapse sur la zabeth&lt;br /&gt;
  G13 -&amp;gt; installation du mandataire inverse (reverse proxy nginx)&lt;br /&gt;
  G1 -&amp;gt; installation du conteneur synapse, se lance mais en échec&lt;br /&gt;
&lt;br /&gt;
G13 n'a pas mis à jour le tableau de répartition.&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=3625</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=3625"/>
		<updated>2023-12-20T15:54:24Z</updated>

		<summary type="html">&lt;p&gt;Bblack : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Compte rendu des séances=&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
[[Fichier:IfconfigVM.png|gauche|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
mettre la config de la raspberry&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
Coté serveur:&lt;br /&gt;
&lt;br /&gt;
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Mise en Place de l'algorithme d'apprentissage&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
nous avons tester plusieurs méthode d'apprentissage comme la '''Méthode des k plus proches voisins''' (K-Neighbour) ou encore '''forêt aléatoire''' Random forest.&lt;br /&gt;
&lt;br /&gt;
'''Random Forest'''&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=3539</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=3539"/>
		<updated>2023-12-20T07:28:14Z</updated>

		<summary type="html">&lt;p&gt;Bblack : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Compte rendu des séances=&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
[[Fichier:IfconfigVM.png|gauche|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
mettre la config de la raspberry&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;br /&gt;
&lt;br /&gt;
== Séance du 19/12/2023 et du 20/12/2023 ==&lt;br /&gt;
utilisation de la bibliothèque sciait-learn pour l'apprentissage automatique. Nous avons décidé que le but de notre application serait de traduire le langage des signes.&lt;br /&gt;
&lt;br /&gt;
Pour cela nous avons entrainé notre modèle avec quelques signes, comme la lettre A, B ou C et des chiffres 1, 2 et 3 pour commencer.&lt;br /&gt;
&lt;br /&gt;
//mettre screen des résultats entrainement.py et test.py&lt;br /&gt;
&lt;br /&gt;
Les résultats sont satisfaisants mais avec quelques erreurs, la prochaine étape est donc d'améliorer notre algorithme d'apprentissage (pour l'instant on utilise l'algorithme des k plus proches voisins), pour cela nous allons rajouter par exemple du filtrage et tester d'autres algo d'apprentissage automatique&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Coté serveur&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=3518</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=3518"/>
		<updated>2023-12-18T18:19:56Z</updated>

		<summary type="html">&lt;p&gt;Bblack : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Compte rendu des séances=&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
[[Fichier:IfconfigVM.png|gauche|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
mettre la config de la raspberry&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
pas de capteurs lors de la première séance&lt;br /&gt;
&lt;br /&gt;
== Séance du 18/12/2023 ==&lt;br /&gt;
&lt;br /&gt;
=== Sur la VM ===&lt;br /&gt;
script serveur.py&lt;br /&gt;
&lt;br /&gt;
=== sur la raspberry ===&lt;br /&gt;
script client.py&lt;br /&gt;
&lt;br /&gt;
lecture sur l'uart des données envoyés par le stm32&lt;br /&gt;
&lt;br /&gt;
envoie au serveur (tcp)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sur le capteur ===&lt;br /&gt;
pris ene main du capteur, mettre le code,&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=3517</id>
		<title>SE5 ECEAI/eceai 2023/2024/black-blgrim</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/black-blgrim&amp;diff=3517"/>
		<updated>2023-12-18T18:13:10Z</updated>

		<summary type="html">&lt;p&gt;Bblack : Page créée avec « =Compte rendu des séances= ==Séance du 04/12/2023== ===Création de la machine virtuelle=== Création d'une machine virtuelle  sur le serveur chassiron :  &amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt; sans_cadre        ===Raspberry-Pi===   '''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;''' »&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Compte rendu des séances=&lt;br /&gt;
==Séance du 04/12/2023==&lt;br /&gt;
===Création de la machine virtuelle===&lt;br /&gt;
Création d'une machine virtuelle  sur le serveur chassiron :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents&amp;lt;/code&amp;gt;&lt;br /&gt;
[[Fichier:IfconfigVM.png|gauche|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Raspberry-Pi===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;Capteurs&amp;lt;/big&amp;gt;'''&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:IfconfigVM.png&amp;diff=3516</id>
		<title>Fichier:IfconfigVM.png</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:IfconfigVM.png&amp;diff=3516"/>
		<updated>2023-12-18T18:12:08Z</updated>

		<summary type="html">&lt;p&gt;Bblack : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ifconfigVM&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI_2023/2024&amp;diff=3515</id>
		<title>SE5 ECEAI 2023/2024</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI_2023/2024&amp;diff=3515"/>
		<updated>2023-12-18T18:02:28Z</updated>

		<summary type="html">&lt;p&gt;Bblack : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SE5 ECEAI 2023/2024&lt;br /&gt;
&lt;br /&gt;
Groupe Delannoy - Lemaire : [[SE5 ECEAI/eceai 2023/2024/jcie]]&lt;br /&gt;
&lt;br /&gt;
Groupe Rodenburg - Thomas → [[Gabidann|SE5 ECEAI/eceai 2023/2024/gabidann]]&lt;br /&gt;
&lt;br /&gt;
Groupe Halaoui - Farault : [[SE5 ECEAI/eceai 2023/2024/FaraultHalaoui]]&lt;br /&gt;
&lt;br /&gt;
Groupe Godard - Delcourt : [[SE5 ECEAI/eceai 2023/2024/GodardDelcourt]]&lt;br /&gt;
&lt;br /&gt;
Groupe Naudot - Riffaut : [[SE5 ECEAI/eceai_2023/2024/NaudotRiffaut]]&lt;br /&gt;
&lt;br /&gt;
Groupe Amoros - Delaby : [[SE5 ECEAI/eceai 2023/2024/AmorosDelaby]]&lt;br /&gt;
&lt;br /&gt;
Groupe Charleux - Habre : [[SE5 ECEAI/eceai 2023/2024/CharleuxHabre]]&lt;br /&gt;
&lt;br /&gt;
Groupe Balbastre - Simon : [[SE5 ECEAI/eceai 2023/2024/BalbastreSimon]]&lt;br /&gt;
&lt;br /&gt;
Groupe Patrikeev - Mouton : [[SE5 ECEAI/eceai 2023/2024/Patrikeev-Mouton]]&lt;br /&gt;
&lt;br /&gt;
Groupe Brenier - Nguyen : [[SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen]]&lt;br /&gt;
&lt;br /&gt;
Groupe Vallée - Sellali : [[SE5 ECEAI/eceai 2023/2024/ValleeSellali]]&lt;br /&gt;
&lt;br /&gt;
Groupe Black - Blgrim: [[SE5 ECEAI/eceai 2023/2024/black-blgrim]]&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_syst%C3%A8me/r%C3%A9seau_2023/2024&amp;diff=1934</id>
		<title>SE5 système/réseau 2023/2024</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_syst%C3%A8me/r%C3%A9seau_2023/2024&amp;diff=1934"/>
		<updated>2023-10-06T14:55:09Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* Répartition des binômes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= PRA SE5 =&lt;br /&gt;
&lt;br /&gt;
== Menu de la première séance ==&lt;br /&gt;
&lt;br /&gt;
Pour la  première séance du 06/10/2023 il vous est demandé d'effectuer individuellement les opérations listées ci-dessous.&lt;br /&gt;
* création d'une machine virtuelle sur le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* création d'un conteneur &amp;quot;à la main&amp;quot; sur votre station de travail &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt; :&lt;br /&gt;
** créez un conteneur isolé au maximum (sauf pour les utilisateur) avec la méthode décrite en cours,&lt;br /&gt;
** création d'un commutateur virtuel privé sur la &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt; dans le réseau IPv4 &amp;lt;code&amp;gt;192.168.68.0/24&amp;lt;/code&amp;gt;, l'adresse &amp;lt;code&amp;gt;192.168.68.1&amp;lt;/code&amp;gt; est affectée au commutateur lui-même,&lt;br /&gt;
** création d'une interface Ethernet virtuelle, une extrémité doit être envoyée dans le conteneur, l'autre dans le commutateur virtuel privé,&lt;br /&gt;
** mise en place d'une mascarade sur la &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt;, vérifiez que le conteneur a accès aux mêmes machines que la  &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Par binôme vous devez créer une machine virtuelle mandataire connectée sur le commutateur virtuel SE5 et sur le commutateur virtuel privé des machines virtuelles de services concernées (voir deuxième section du sujet).&lt;br /&gt;
&lt;br /&gt;
Globalement vous devez configurer le routeur principal de la promotion (voir la troisième section du sujet). Pour votre promotion il s'agit du Catalyst 9200 situé en E304. Il faut le connecter en fibre vers le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; de la E306 dans le commutateur virtuel SE5 et aussi en fibre vers le local technique SR52 sur un port dans le VLAN 531. Vous pouvez configurer le commutateur via l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt; à partir de la machine &amp;lt;code&amp;gt;zabeth09&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Répartition des élèves pour la première séance :&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Station de travail !! Elève&lt;br /&gt;
|-&lt;br /&gt;
| zabeth02 || Elias SIMON&lt;br /&gt;
|-&lt;br /&gt;
| zabeth03 || Mathis RIFFAUT&lt;br /&gt;
|-&lt;br /&gt;
| zabeth04 || Dann RODENBURG&lt;br /&gt;
|-&lt;br /&gt;
| zabeth05 || Benjamin NGUYEN&lt;br /&gt;
|-&lt;br /&gt;
| zabeth06 || Halaoui mohammed&lt;br /&gt;
|-&lt;br /&gt;
| zabeth07 || Blgrim Haitam&lt;br /&gt;
|-&lt;br /&gt;
| zabeth08 || Florian Vallée&lt;br /&gt;
|-&lt;br /&gt;
| zabeth09 (routeur) || Julien Charleux&lt;br /&gt;
|-&lt;br /&gt;
| zabeth10 || Amine SELLALI&lt;br /&gt;
|-&lt;br /&gt;
| zabeth11 || Paul Amoros&lt;br /&gt;
|-&lt;br /&gt;
| zabeth12 || Maël Delaby&lt;br /&gt;
|-&lt;br /&gt;
| zabeth13 || Black Baptiste&lt;br /&gt;
|-&lt;br /&gt;
| zabeth14 || Timothé Brenier&lt;br /&gt;
|-&lt;br /&gt;
| zabeth15 || Jeanne Delcourt&lt;br /&gt;
|-&lt;br /&gt;
| zabeth16 || Estelle Godard&lt;br /&gt;
|-&lt;br /&gt;
| zabeth17 || Jason DELANNOY&lt;br /&gt;
|-&lt;br /&gt;
| zabeth18 || Chloé Lemaire&lt;br /&gt;
|-&lt;br /&gt;
| zabeth19 || Gabriel THOMAS&lt;br /&gt;
|-&lt;br /&gt;
| zabeth20 || Albin MOUTON&lt;br /&gt;
|-&lt;br /&gt;
| zabeth21 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth22 || Maxime Balbastre&lt;br /&gt;
|-&lt;br /&gt;
| zabeth26 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth27 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth28 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth30 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Répartition des binômes ==&lt;br /&gt;
&lt;br /&gt;
Concertez-vous pour trouver des noms de machines de services et de machines mandataires dans deux thèmes.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Cahier !! Nom machine services &lt;br /&gt;
!IP machine services !! Nom de domaine !! Nom machine mandataire &lt;br /&gt;
!IP machine mandataires!! Elève &lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E1 | Cahier n°1]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E2 | Cahier n°2]]&lt;br /&gt;
| Elom|| || || || || Elias SIMON&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E3 | Cahier n°3]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E4 | Cahier n°4]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E5 | Cahier n°5]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E6 | Cahier n°6]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E7 | Cahier n°7]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E8 | Cahier n°8]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E9 | Cahier n°9]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E10 | Cahier n°10]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E11 | Cahier n°11]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E12 | Cahier n°12]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E13 | Cahier n°13]]&lt;br /&gt;
| Bogden|| || || BlancheNeige|| || Black Baptiste&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E14 | Cahier n°14]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E15 | Cahier n°15]]&lt;br /&gt;
| jiruus|| || || cruella|| || Jeanne Delcourt&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E16 | Cahier n°16]]&lt;br /&gt;
| exegol|| || || cruella|| || Estelle Godard&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E17 | Cahier n°17]]&lt;br /&gt;
| Jakku|| || || Jafar|| || Jason DELANNOY&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E18 | Cahier n°18]]&lt;br /&gt;
| naboo|| || || bouh|| || Chloé Lemaire&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E19 | Cahier n°19]]&lt;br /&gt;
| geonosis|| || || bouh|| || Gabriel THOMAS&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E20 | Cahier n°20]]&lt;br /&gt;
| alderaan|| || || Jafar|| || Albin MOUTON&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E21 | Cahier n°21]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E22 | Cahier n°22]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E23 | Cahier n°23]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E24 | Cahier n°24]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Contrôle continu ==&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_syst%C3%A8me/r%C3%A9seau_2023/2024&amp;diff=1933</id>
		<title>SE5 système/réseau 2023/2024</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_syst%C3%A8me/r%C3%A9seau_2023/2024&amp;diff=1933"/>
		<updated>2023-10-06T14:54:19Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* Répartition des binômes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= PRA SE5 =&lt;br /&gt;
&lt;br /&gt;
== Menu de la première séance ==&lt;br /&gt;
&lt;br /&gt;
Pour la  première séance du 06/10/2023 il vous est demandé d'effectuer individuellement les opérations listées ci-dessous.&lt;br /&gt;
* création d'une machine virtuelle sur le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* création d'un conteneur &amp;quot;à la main&amp;quot; sur votre station de travail &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt; :&lt;br /&gt;
** créez un conteneur isolé au maximum (sauf pour les utilisateur) avec la méthode décrite en cours,&lt;br /&gt;
** création d'un commutateur virtuel privé sur la &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt; dans le réseau IPv4 &amp;lt;code&amp;gt;192.168.68.0/24&amp;lt;/code&amp;gt;, l'adresse &amp;lt;code&amp;gt;192.168.68.1&amp;lt;/code&amp;gt; est affectée au commutateur lui-même,&lt;br /&gt;
** création d'une interface Ethernet virtuelle, une extrémité doit être envoyée dans le conteneur, l'autre dans le commutateur virtuel privé,&lt;br /&gt;
** mise en place d'une mascarade sur la &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt;, vérifiez que le conteneur a accès aux mêmes machines que la  &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Par binôme vous devez créer une machine virtuelle mandataire connectée sur le commutateur virtuel SE5 et sur le commutateur virtuel privé des machines virtuelles de services concernées (voir deuxième section du sujet).&lt;br /&gt;
&lt;br /&gt;
Globalement vous devez configurer le routeur principal de la promotion (voir la troisième section du sujet). Pour votre promotion il s'agit du Catalyst 9200 situé en E304. Il faut le connecter en fibre vers le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; de la E306 dans le commutateur virtuel SE5 et aussi en fibre vers le local technique SR52 sur un port dans le VLAN 531. Vous pouvez configurer le commutateur via l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt; à partir de la machine &amp;lt;code&amp;gt;zabeth09&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Répartition des élèves pour la première séance :&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Station de travail !! Elève&lt;br /&gt;
|-&lt;br /&gt;
| zabeth02 || Elias SIMON&lt;br /&gt;
|-&lt;br /&gt;
| zabeth03 || Mathis RIFFAUT&lt;br /&gt;
|-&lt;br /&gt;
| zabeth04 || Dann RODENBURG&lt;br /&gt;
|-&lt;br /&gt;
| zabeth05 || Benjamin NGUYEN&lt;br /&gt;
|-&lt;br /&gt;
| zabeth06 || Halaoui mohammed&lt;br /&gt;
|-&lt;br /&gt;
| zabeth07 || Blgrim Haitam&lt;br /&gt;
|-&lt;br /&gt;
| zabeth08 || Florian Vallée&lt;br /&gt;
|-&lt;br /&gt;
| zabeth09 (routeur) || Julien Charleux&lt;br /&gt;
|-&lt;br /&gt;
| zabeth10 || Amine SELLALI&lt;br /&gt;
|-&lt;br /&gt;
| zabeth11 || Paul Amoros&lt;br /&gt;
|-&lt;br /&gt;
| zabeth12 || Maël Delaby&lt;br /&gt;
|-&lt;br /&gt;
| zabeth13 || Black Baptiste&lt;br /&gt;
|-&lt;br /&gt;
| zabeth14 || Timothé Brenier&lt;br /&gt;
|-&lt;br /&gt;
| zabeth15 || Jeanne Delcourt&lt;br /&gt;
|-&lt;br /&gt;
| zabeth16 || Estelle Godard&lt;br /&gt;
|-&lt;br /&gt;
| zabeth17 || Jason DELANNOY&lt;br /&gt;
|-&lt;br /&gt;
| zabeth18 || Chloé Lemaire&lt;br /&gt;
|-&lt;br /&gt;
| zabeth19 || Gabriel THOMAS&lt;br /&gt;
|-&lt;br /&gt;
| zabeth20 || Albin MOUTON&lt;br /&gt;
|-&lt;br /&gt;
| zabeth21 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth22 || Maxime Balbastre&lt;br /&gt;
|-&lt;br /&gt;
| zabeth26 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth27 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth28 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth30 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Répartition des binômes ==&lt;br /&gt;
&lt;br /&gt;
Concertez-vous pour trouver des noms de machines de services et de machines mandataires dans deux thèmes.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Cahier !! Nom machine services &lt;br /&gt;
!IP machine services !! Nom de domaine !! Nom machine mandataire &lt;br /&gt;
!IP machine mandataires!! Elève &lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E1 | Cahier n°1]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E2 | Cahier n°2]]&lt;br /&gt;
| Elom|| || || || || Elias SIMON&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E3 | Cahier n°3]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E4 | Cahier n°4]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E5 | Cahier n°5]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E6 | Cahier n°6]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E7 | Cahier n°7]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E8 | Cahier n°8]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E9 | Cahier n°9]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E10 | Cahier n°10]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E11 | Cahier n°11]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E12 | Cahier n°12]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E13 | Cahier n°13]]&lt;br /&gt;
| Bogden|| || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E14 | Cahier n°14]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E15 | Cahier n°15]]&lt;br /&gt;
| jiruus|| || || cruella|| || Jeanne Delcourt&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E16 | Cahier n°16]]&lt;br /&gt;
| exegol|| || || cruella|| || Estelle Godard&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E17 | Cahier n°17]]&lt;br /&gt;
| Jakku|| || || Jafar|| || Jason DELANNOY&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E18 | Cahier n°18]]&lt;br /&gt;
| naboo|| || || bouh|| || Chloé Lemaire&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E19 | Cahier n°19]]&lt;br /&gt;
| geonosis|| || || bouh|| || Gabriel THOMAS&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E20 | Cahier n°20]]&lt;br /&gt;
| alderaan|| || || Jafar|| || Albin MOUTON&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E21 | Cahier n°21]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E22 | Cahier n°22]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E23 | Cahier n°23]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E24 | Cahier n°24]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Contrôle continu ==&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_syst%C3%A8me/r%C3%A9seau_2023/2024&amp;diff=1919</id>
		<title>SE5 système/réseau 2023/2024</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_syst%C3%A8me/r%C3%A9seau_2023/2024&amp;diff=1919"/>
		<updated>2023-10-06T14:13:59Z</updated>

		<summary type="html">&lt;p&gt;Bblack : /* Menu de la première séance */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= PRA SE5 =&lt;br /&gt;
&lt;br /&gt;
== Menu de la première séance ==&lt;br /&gt;
&lt;br /&gt;
Pour la  première séance du 06/10/2023 il vous est demandé d'effectuer individuellement les opérations listées ci-dessous.&lt;br /&gt;
* création d'une machine virtuelle sur le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* création d'un conteneur &amp;quot;à la main&amp;quot; sur votre station de travail &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt; :&lt;br /&gt;
** créez un conteneur isolé au maximum (sauf pour les utilisateur) avec la méthode décrite en cours,&lt;br /&gt;
** création d'un commutateur virtuel privé sur la &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt; dans le réseau IPv4 &amp;lt;code&amp;gt;192.168.68.0/24&amp;lt;/code&amp;gt;, l'adresse &amp;lt;code&amp;gt;192.168.68.1&amp;lt;/code&amp;gt; est affectée au commutateur lui-même,&lt;br /&gt;
** création d'une interface Ethernet virtuelle, une extrémité doit être envoyée dans le conteneur, l'autre dans le commutateur virtuel privé,&lt;br /&gt;
** mise en place d'une mascarade sur la &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt;, vérifiez que le conteneur a accès aux mêmes machines que la  &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Par binôme vous devez créer une machine virtuelle mandataire connectée sur le commutateur virtuel SE5 et sur le commutateur virtuel privé des machines virtuelles de services concernées (voir deuxième section du sujet).&lt;br /&gt;
&lt;br /&gt;
Globalement vous devez configurer le routeur principal de la promotion (voir la troisième section du sujet). Pour votre promotion il s'agit du Catalyst 9200 situé en E304. Il faut le connecter en fibre vers le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; de la E306 dans le commutateur virtuel SE5 et aussi en fibre vers le local technique SR52 sur un port dans le VLAN 531. Vous pouvez configurer le commutateur via l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt; à partir de la machine &amp;lt;code&amp;gt;zabeth09&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Répartition des élèves pour la première séance :&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Station de travail !! Elève&lt;br /&gt;
|-&lt;br /&gt;
| zabeth02 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth03 || Mathis RIFFAUT&lt;br /&gt;
|-&lt;br /&gt;
| zabeth04 || Dann RODENBURG&lt;br /&gt;
|-&lt;br /&gt;
| zabeth05 || Benjamin NGUYEN&lt;br /&gt;
|-&lt;br /&gt;
| zabeth06 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth07 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth08 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth09 (routeur) || Julien Charleux&lt;br /&gt;
|-&lt;br /&gt;
| zabeth10 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth11 || Paul Amoros&lt;br /&gt;
|-&lt;br /&gt;
| zabeth12 || Maël Delaby&lt;br /&gt;
|-&lt;br /&gt;
| zabeth13 || Black Baptiste&lt;br /&gt;
|-&lt;br /&gt;
| zabeth14 || Timothé Brenier&lt;br /&gt;
|-&lt;br /&gt;
| zabeth15 || Jeanne Delcourt&lt;br /&gt;
|-&lt;br /&gt;
| zabeth16 || Estelle Godard&lt;br /&gt;
|-&lt;br /&gt;
| zabeth17 || Jason DELANNOY&lt;br /&gt;
|-&lt;br /&gt;
| zabeth18 || Chloé Lemaire&lt;br /&gt;
|-&lt;br /&gt;
| zabeth19 || Gabriel THOMAS&lt;br /&gt;
|-&lt;br /&gt;
| zabeth20 || Albin MOUTON&lt;br /&gt;
|-&lt;br /&gt;
| zabeth21 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth22 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth26 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth27 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth28 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth30 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Répartition des binômes ==&lt;br /&gt;
&lt;br /&gt;
Concertez-vous pour trouver des noms de machines de services et de machines mandataires dans deux thèmes.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Cahier !! Nom machine services &lt;br /&gt;
!IP machine services !! Nom de domaine !! Nom machine mandataire &lt;br /&gt;
!IP machine mandataires!! Elève &lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E1 | Cahier n°1]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E2 | Cahier n°2]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E3 | Cahier n°3]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E4 | Cahier n°4]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E5 | Cahier n°5]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E6 | Cahier n°6]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E7 | Cahier n°7]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E8 | Cahier n°8]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E9 | Cahier n°9]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E10 | Cahier n°10]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E11 | Cahier n°11]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E12 | Cahier n°12]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E13 | Cahier n°13]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E14 | Cahier n°14]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E15 | Cahier n°15]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E16 | Cahier n°16]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E17 | Cahier n°17]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E18 | Cahier n°18]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E19 | Cahier n°19]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E20 | Cahier n°20]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E21 | Cahier n°21]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E22 | Cahier n°22]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E23 | Cahier n°23]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E24 | Cahier n°24]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Contrôle continu ==&lt;/div&gt;</summary>
		<author><name>Bblack</name></author>
	</entry>
</feed>