« SE5 ECEAI/eceai 2023/2024/black-blgrim » : différence entre les versions
(→Vidéo) |
|||
(14 versions intermédiaires par 2 utilisateurs non affichées) | |||
Ligne 1 : | Ligne 1 : | ||
= | =SignSpeak 2023/2024 = | ||
== '''Présentation du projet''' == | == '''Présentation du projet''' == | ||
Ligne 221 : | Ligne 168 : | ||
<syntaxhighlight lang="shell"> | <syntaxhighlight lang="shell"> | ||
listener 1883 10.42.0.5 | listener 1883 10.42.0.5 | ||
#listener 1883 2001:660:4401:6050:216:3eff:fe86:cd63 | |||
allow_anonymous false | allow_anonymous false | ||
password_file /etc/mosquitto/passwd | password_file /etc/mosquitto/passwd | ||
Ligne 249 : | Ligne 197 : | ||
MQTT_BROKER_ADDRESS = "10.42.0.5" | MQTT_BROKER_ADDRESS = "10.42.0.5" | ||
#MQTT_BROKER_ADDRESS = "2001:660:4401:6050:216:3eff:fe86:cd63" VmHblgrimBblack | |||
MQTT_USERNAME = "username" | MQTT_USERNAME = "username" | ||
MQTT_PASSWORD = "confidentiel" | MQTT_PASSWORD = "confidentiel" | ||
Ligne 318 : | Ligne 267 : | ||
Le troisième topic est le topic telemetry/ID, ou la raspberry vient publier ses données. | Le troisième topic est le topic telemetry/ID, ou la raspberry vient publier ses données. | ||
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 | 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 | ||
=== 6. Interface Serveur et Gestion des Données === | === 6. Interface Serveur et Gestion des Données === | ||
Ligne 338 : | Ligne 287 : | ||
raspberry_ids = set() | raspberry_ids = set() | ||
MQTT_BROKER_ADDRESS = "10.42.0.5" | MQTT_BROKER_ADDRESS = "10.42.0.5" | ||
#MQTT_BROKER_ADDRESS = "2001:660:4401:6050:216:3eff:fe86:cd63" VmHblgrimBblack | |||
MQTT_USERNAME = "username" | MQTT_USERNAME = "username" | ||
MQTT_PASSWORD = "confidentiel" | MQTT_PASSWORD = "confidentiel" | ||
Ligne 388 : | Ligne 338 : | ||
latest_message = messages[-1] if messages else None | latest_message = messages[-1] if messages else None | ||
print(f"Contenu de la réponse pour /get-latest-message : {latest_message}") | print(f"Contenu de la réponse pour /get-latest-message : {latest_message}") | ||
Ligne 439 : | Ligne 388 : | ||
<style> | <style> | ||
body { | body { | ||
background-color: #343a40; | background-color: #343a40; | ||
color: #ced4da; | color: #ced4da; | ||
} | } | ||
.card { | .card { | ||
background-color: #495057; | background-color: #495057; | ||
} | } | ||
.card-title, .card-text, .alert { | .card-title, .card-text, .alert { | ||
color: #adb5bd; | color: #adb5bd; | ||
} | } | ||
.btn-primary { | .btn-primary { | ||
background-color: #007bff; | background-color: #007bff; | ||
border-color: #007bff; | border-color: #007bff; | ||
} | } | ||
.btn-danger { | .btn-danger { | ||
background-color: #dc3545; | background-color: #dc3545; | ||
border-color: #dc3545; | border-color: #dc3545; | ||
} | } | ||
.form-control { | .form-control { | ||
background-color: #495057; | background-color: #495057; | ||
border: 1px solid #6c757d; | border: 1px solid #6c757d; | ||
color: #ced4da; | color: #ced4da; | ||
} | } | ||
a, .btn-secondary { | a, .btn-secondary { | ||
color: #17a2b8; | color: #17a2b8; | ||
} | } | ||
a:hover { | a:hover { | ||
Ligne 585 : | Ligne 534 : | ||
=== 9. Conclusion et Perspectives === | === 9. Conclusion et Perspectives === | ||
----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont | ----SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont | ||
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. | |||
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. | |||
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]] | |||
== Vidéo == | == Vidéo == | ||
Lorsqu'une raspberry se connecte au réseau, son ID apparait dans le cadre "Raspberry disponible". Ensuite il suffit de choisir la raspberry, rentrer son ID dans l'emplacement prévu à cet effet, puis on clique sur "démarrer la collecte", 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 "A", "B", les chiffres 1 et 2 et la phrase "I Love You". | |||
[[Fichier:RPReplay_Final1706462779.mov|sans_cadre]] | [[Fichier:RPReplay_Final1706462779.mov|sans_cadre]] | ||
[[Fichier:Capture d’écran 2024-01-29 à 15.43.56.png|néant|vignette]] | |||
[[Fichier:Capture d’écran 2024-01-29 à 15.45.25.png|néant|vignette|133x133px]] | |||
== Déroulement 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 : | |||
<code>xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents</code> | |||
[[Fichier:IfconfigVM.png|sans_cadre]] | |||
===Raspberry-Pi=== | |||
[[Fichier:Capture d’écran 2024-01-28 à 19.07.42.png|néant|vignette]] | |||
'''<big>Capteurs</big>''' | |||
pas de capteurs lors de la première séance | |||
== Séance du 18/12/2023 == | |||
=== Sur la VM === | |||
script serveur.py | |||
=== sur la raspberry === | |||
script client.py | |||
lecture sur l'uart des données envoyés par le stm32 | |||
envoie au serveur (tcp) | |||
=== sur le capteur === | |||
pris ene main du capteur, mettre le code, | |||
== Séance du 19/12/2023 et du 20/12/2023 == | |||
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. | |||
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. | |||
//mettre screen des résultats entrainement.py et test.py | |||
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 | |||
Coté serveur: | |||
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher. | |||
'''<big>Mise en Place de l'algorithme d'apprentissage</big>''' | |||
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. | |||
'''Random Forest''' |
Version actuelle datée du 29 janvier 2024 à 14:54
SignSpeak 2023/2024
Présentation du projet
1. Introduction
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.
2. Architecture du Système
Notre solution repose sur une architecture intégrée impliquant plusieurs composants clés :
- 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.
- 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.
- 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.
3. Collecte et Préparation des Données
Le processus de collecte des données est géré par le script enregistrementData.py
. 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.
import serial
import csv
import sys
import time
# Vérification de l'argument d'entrée
if len(sys.argv) < 2:
print("Usage: python script.py <etiquette>")
sys.exit(1)
etiquette = sys.argv[1]
# Paramètres de l'UART
port = "/dev/ttyACM0"
baudrate = 460800
# Créer une connexion UART
ser = serial.Serial(port, baudrate, timeout=1)
# Nom du fichier CSV
filename = f"data_complete.csv"
# Vérifier si le fichier existe déjà
file_exists = False
try:
with open(filename, 'r') as f:
file_exists = True
except FileNotFoundError:
file_exists = False
# Ouvrir le fichier CSV en mode append
with open(filename, 'a', newline='') as file:
writer = csv.writer(file)
# Écrire l'en-tête si le fichier n'existait pas
if not file_exists:
writer.writerow(["Capteur1", "Capteur2", "Capteur3", "Capteur4", "Capteur5", "Capteur6", "Capteur7", "Capteur8", "Capteur9", "Capteur10", "Capteur11", "Capteur12", "Capteur13", "Capteur14",
"Capteur15", "Capteur16", "Etiquette"])
elif file_exists:
writer.writerow([])
while True:
# Lire une ligne de données depuis l'UART
data = ser.readline().decode('utf-8').rstrip()
print(f"Données reçues : '{data}'")
# Vérifier si des données ont été reçues
if data:
# Diviser les données en valeurs individuelles
sensor_values = data.split(',')
# Filtrer les chaînes vides ou non numériques et convertir en flottants
try:
sensor_values = [float(value) for value in sensor_values if value.strip().isdigit()]
# Vérifier qu'il y a 16 valeurs de capteur
if len(sensor_values) == 16:
sensor_values.append(etiquette)
writer.writerow(sensor_values)
else:
print("Données incomplètes reçues")
except ValueError as e:
print(f"Erreur de conversion : {e}")
print(f"Données problématiques : '{data}'")
time.sleep(0.1)
- Le script commence par établir une communication série avec le STM32.
- Il lit ensuite les données en série, les décode et les stocke dans un fichier CSV pour une utilisation ultérieure.
- 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.
- Cette préparation implique la normalisation des données, la gestion des valeurs manquantes ou aberrantes, et leur formatage dans un bon format.
4. Entraînement du Modèle d'Apprentissage Automatique
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)
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
import pickle
# Charger vos données
data = pd.read_csv('data_complete.csv')
# Séparer les caractéristiques et les étiquettes
X = data.drop('Etiquette', axis=1)
y = data['Etiquette']
# Diviser les données en ensembles d'entraînement et de test
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Créer et entraîner le modèle SVM
model = SVC(kernel='rbf')
model.fit(X_train, y_train)
# Sauvegarder le modèle entraîné
with open('modele_svm.pkl', 'wb') as file:
pickle.dump(model, file)
# Charger le modèle et faire des prédictions
with open('modele_svm.pkl', 'rb') as file:
loaded_model = pickle.load(file)
predictions = loaded_model.predict(X_test)
print("Précision :", accuracy_score(y_test, predictions))
- Séparation des Données:
- 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.
- Généralement, on adopte une répartition de 80% pour l'entraînement et 20% pour les tests.
- Entraînement du Modèle SVM:
- Le modèle SVM avec un noyau RBF (Radial Basis Function) est entraîné sur l'ensemble d'entraînement.
- L'entraînement implique l'ajustement du modèle aux données d'entraînement, en apprenant à distinguer les différents signes.
- Sauvegarde et Réutilisation du Modèle
- Une fois entraîné et validé, le modèle est sauvegardé à l'aide de la bibliothèque
pickle
- Une fois entraîné et validé, le modèle est sauvegardé à l'aide de la bibliothèque
- Validation et Évaluation du Modèle:
- Après l'entraînement, le modèle est testé sur l'ensemble de test pour évaluer sa performance.
- 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.
Ensuite on peut générer le modèle comme ceci:
Avec cette prédiction lorsque notre modèle prédit le résultat, il est correct environ 71.81% du temps.
5. Intégration MQTT et Communication
Protocole de communication :
Dans le cadre de notre projet, la communication entre les dispositifs Raspberry Pi et le serveur est établie via le protocole MQTT.
Justification du Choix de MQTT :
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.
Installation du broker mosquitto sur le serveur:
apt install -y mosquitto mosquitto-clients
service mosquitto start
Activation de l'accès à distance au Broker Mosquitto:
ajouter l'authentification par username et mot de passe
sudo mosquitto_passwd -c /etc/mosquitto/passwd username
après on nous demande d'entrer le mot de passe
Modifier le fichier /etc/mosquitto/mosquitto.conf:
listener 1883 10.42.0.5
#listener 1883 2001:660:4401:6050:216:3eff:fe86:cd63
allow_anonymous false
password_file /etc/mosquitto/passwd
Restart Mosquitto:
service mosquitto restart
Vérification ds logs:
cat /var/log/mosquitto/mosquitto.log
Création d'un client MQTT sur la Raspberry Pi:
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.
import paho.mqtt.client as mqtt
import serial
import pandas as pd
import pickle
import time
MQTT_BROKER_ADDRESS = "10.42.0.5"
#MQTT_BROKER_ADDRESS = "2001:660:4401:6050:216:3eff:fe86:cd63" VmHblgrimBblack
MQTT_USERNAME = "username"
MQTT_PASSWORD = "confidentiel"
pi_id = "rpi1234"
collecting_data = False
client = mqtt.Client()
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)
client.connect(MQTT_BROKER_ADDRESS, 1883, 60)
client.loop_start()
def on_connect(client, userdata, flags, rc):
print("Connected with result code " + str(rc))
client.subscribe(f"config/{pi_id}")
client.publish("raspberry_available", pi_id)
def on_message(client, userdata, msg):
global collecting_data
if msg.topic == f"config/{pi_id}":
command = msg.payload.decode()
if command == "start":
collecting_data = True
elif command == "stop":
collecting_data = False
client.on_connect = on_connect
client.on_message = on_message
# Configurez le port série et chargez le modèle ici
port = "/dev/ttyACM0"
baudrate = 460800
ser = serial.Serial(port, baudrate, timeout=1)
with open('modele_svm.pkl', 'rb') as file:
rf = pickle.load(file)
try:
while True:
if collecting_data:
data = ser.readline().decode('utf-8').rstrip()
if data:
try:
sensor_values = [value for value in data.split(',') if value.strip().replace('.', '', 1).isdigit()]
if len(sensor_values) == 16:
sensor_values = list(map(float, sensor_values))
sensor_values_df = pd.DataFrame([sensor_values])
prediction = rf.predict(sensor_values_df)
client.publish(f"telemetry/{pi_id}", str(prediction[0]).encode())
print("Prédiction :", prediction[0])
except ValueError as e:
print(f"Erreur de conversion : {e}")
else:
time.sleep(0.1)
except KeyboardInterrupt:
print("Script interrompu")
client.loop_stop()
client.disconnect()
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.
le deuxième topic et le topic config/ID (avec id l'identifiant unique de la raspberry), il nous sert a envoyer les commandes "start" et "stop" a la raspberry afin qu'elle démarre ou arrête la lecture des datas.
Le troisième topic est le topic telemetry/ID, ou la raspberry vient publier ses données.
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
6. Interface Serveur et Gestion des Données
Le serveur central, au cœur de notre système, est orchestré par le script app.py
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.
from flask import Flask, render_template, request, jsonify
import paho.mqtt.client as mqtt
import queue
app = Flask(__name__)
messages = []
received_messages = queue.Queue()
latest_message = None
subscribed_topics = set()
raspberry_ids = set()
MQTT_BROKER_ADDRESS = "10.42.0.5"
#MQTT_BROKER_ADDRESS = "2001:660:4401:6050:216:3eff:fe86:cd63" VmHblgrimBblack
MQTT_USERNAME = "username"
MQTT_PASSWORD = "confidentiel"
mqtt_client = mqtt.Client()
mqtt_client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)
mqtt_client.connect(MQTT_BROKER_ADDRESS, 1883, 60)
mqtt_client.loop_start()
def send_command_to_pi(pi_id, command):
try:
topic = f"config/{pi_id}"
mqtt_client.publish(topic, command)
subscribe_to_pi_telemetry(pi_id)
return True, "Commande envoyée avec succès"
except Exception as e:
return False, f"Commande pas envoyée: Erreur MQTT : {e}"
def subscribe_to_pi_telemetry(pi_id):
global subscribed_topics
topic = f"telemetry/{pi_id}"
if topic not in subscribed_topics:
mqtt_client.subscribe(topic)
subscribed_topics.add(topic)
def on_connect(client, userdata, flags, rc):
print("Connected with result code " + str(rc))
client.subscribe("raspberry_available")
def on_message(client, userdata, msg):
global raspberry_ids
print(f"Received message on topic {msg.topic}: {msg.payload.decode()}") # Ajouter pour le débogage
if msg.topic == "raspberry_available":
raspberry_ids.add(msg.payload.decode())
else:
received_messages.put(msg.payload.decode())
mqtt_client.on_connect = on_connect
mqtt_client.on_message = on_message
@app.route('/get-raspberry-ids')
def get_raspberry_ids():
return jsonify(list(raspberry_ids))
@app.route('/get-latest-message')
def get_latest_message():
global latest_message
while not received_messages.empty():
messages.append(received_messages.get())
latest_message = messages[-1] if messages else None
print(f"Contenu de la réponse pour /get-latest-message : {latest_message}")
if latest_message is not None:
response = jsonify({"message": latest_message})
return response
else:
message = "Aucun signe a traduire pour le moment"
return jsonify(message)
@app.route('/', methods=['GET', 'POST'])
def index():
global raspberry_ids
error_message_rpi = None
success_message = None
if request.method == 'POST':
pi_id = request.form.get('pi_id')
command = request.form.get('command')
if pi_id and command in ["start", "stop"]:
success, er_message = send_command_to_pi(pi_id, command)
if success:
success_message = "Commande envoyée avec succès"
else:
error_message_rpi = er_message
return render_template('index.html', raspberry_ids=list(raspberry_ids), error_message_rpi=error_message_rpi, success_message=success_message, message=latest_message)
if __name__ == '__main__':
app.run(debug=False, port=8066)
7. Conception de l'Interface Utilisateur
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.
index.html:
<!DOCTYPE html>
<html>
<head>
<title>SignSpeak - Traducteur de Langage des Signes</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
body {
background-color: #343a40;
color: #ced4da;
}
.card {
background-color: #495057;
}
.card-title, .card-text, .alert {
color: #adb5bd;
}
.btn-primary {
background-color: #007bff;
border-color: #007bff;
}
.btn-danger {
background-color: #dc3545;
border-color: #dc3545;
}
.form-control {
background-color: #495057;
border: 1px solid #6c757d;
color: #ced4da;
}
a, .btn-secondary {
color: #17a2b8;
}
a:hover {
color: #138496;
}
#latest-message {
background-color: #596069;
border: 1px solid #6c757d;
color: #E9ECEF;
padding: 10px;
border-radius: 5px;
}
</style>
</head>
<body>
<div class="container mt-5">
<h1 class="text-center mb-4">SignSpeak - Traducteur de Langage des Signes</h1>
<div class="row">
<!-- Encadré pour les Raspberry Pi Disponibles -->
<div class="col-md-12">
<div class="card">
<div class="card-body">
<h2 class="card-title">Raspberry Pi Disponibles</h2>
<ul id="raspberry-list" class="list-group list-group-flush">
</ul>
</div>
</div>
</div>
</div>
<div class="row">
<!-- Encadré pour la Collecte des données -->
<div class="col-lg-6">
<div class="card">
<div class="card-body">
<h2 class="card-title">Collecte de données</h2>
<form method="post" class="form-inline">
<input type="text" class="form-control mb-2 mr-sm-2" name="pi_id" placeholder="Entrez l'ID de la Raspberry Pi" required>
<button type="submit" class="btn btn-primary mb-2 mr-sm-2" name="command" value="start">Démarrer la Collecte</button>
<button type="submit" class="btn btn-danger mb-2" name="command" value="stop">Arrêter la Collecte</button>
</form>
</div>
</div>
</div>
<!-- Encadré pour le Dernier Message Reçu -->
<div class="col-lg-6">
<div class="card">
<div class="card-body">
<h2 class="card-title">Dernier Message Reçu</h2>
<div id="latest-message" class="alert alert-dark">
Aucun message reçu pour le moment.
</div>
</div>
</div>
</div>
</div>
<div class="mb-3 text-center">
<a href="/logs" class="btn btn-secondary">Voir les Logs</a>
</div>
</div>
<script>
function fetchRaspberryIds() {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
if (xhr.status == 200) {
var ids = JSON.parse(xhr.responseText);
var list = document.getElementById('raspberry-list');
list.innerHTML = '';
ids.forEach(function(id) {
var li = document.createElement('li');
li.textContent = id;
list.appendChild(li);
});
}
}
}
xhr.open('GET', '/get-raspberry-ids', true);
xhr.send();
}
function fetchLatestMessage() {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
if (xhr.status == 200) {
console.log(xhr.responseText)
document.getElementById('latest-message').textContent = xhr.responseText;
}
}
}
xhr.open('GET', '/get-latest-message', true);
xhr.send();
}
setInterval(fetchRaspberryIds, 5000); // Met à jour les IDs toutes les 5 secondes
setInterval(fetchLatestMessage, 500); // Met à jour le dernier message toutes les secondes
</script>
{% if error_message_rpi %}
<script>
alert("{{ error_message_rpi }}");
</script>
{% endif %}
{% if success_message %}
<script>
alert("{{ success_message }}");
</script>
{% endif %}
</body>
</html>
On a aussi ajouté une page de logs, qui permet de voir l'historique de tous les données traitées.
9. Conclusion et Perspectives
SignSpeak représente une avancée significative dans le domaine de la traduction du langage des signes. Ce projet non seulement démont
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.
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.
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.
Vidéo
Lorsqu'une raspberry se connecte au réseau, son ID apparait dans le cadre "Raspberry disponible". Ensuite il suffit de choisir la raspberry, rentrer son ID dans l'emplacement prévu à cet effet, puis on clique sur "démarrer la collecte", 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 "A", "B", les chiffres 1 et 2 et la phrase "I Love You".
Déroulement 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 :
xen-create-image --hostname= --force --dist=bookworm --size=10G --memory=10G --dir=/usr/local/xen --password=glopglop --dhcp --bridge=bridgeStudents
Raspberry-Pi
Capteurs
pas de capteurs lors de la première séance
Séance du 18/12/2023
Sur la VM
script serveur.py
sur la raspberry
script client.py
lecture sur l'uart des données envoyés par le stm32
envoie au serveur (tcp)
sur le capteur
pris ene main du capteur, mettre le code,
Séance du 19/12/2023 et du 20/12/2023
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.
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.
//mettre screen des résultats entrainement.py et test.py
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
Coté serveur:
Création d'un serveur web, afin de lire les données qui proviennet depuis la raspberrypi et les afficher.
Mise en Place de l'algorithme d'apprentissage
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.
Random Forest