SE5 ECEAI/eceai 2023/2024/AmorosDelaby
Nous essayons d'implémenter une application qui permet de détecter un mouvement de type "Swipe" vers la gauche, la droite, le haut ou le bas, dans l'objectif de développer une application type Tinder.
L'architecture matérielle est composé d'un capteur TOF (time of flight), d'une carte équipée d'un micro-controleur STM32, d'une raspberry pi, point d'accès Wifi, d'un serveur de virtualisation et finalement d'un PC de l'utilisateur.
L'objectif de
Machine virtuelle (serveur) et services
Machine virtuelle
Afin de réaliser la partie de gestion des données, nous avons créé une VM sur le serveur Chassiron, qui sera chargée de recevoir les données, les traitées et.
Cette machine virtuelle est créée et configurée avec Xen. Elle n’a qu'une seule interface virtuelle qui est placée dans le réseau de promotion.
Paramètre | Valeur |
---|---|
hostname | g5amodelVM |
ipv6 | 2001:660:4401:6050:216:3eff:fe40:73d8/64 |
MQTT
Pour remonter les requêtes vers notre serveur, nous avons fait le choix d'utiliser le protocole MQTT (Message Queuing Telemetry Transport).
C'est un protocole de messagerie léger et largement utilisé dans les applications de l'Internet des Objets (IoT).
Le protocole MQTT repose sur une architecture de type "client-broker".
- Le broker est un serveur central qui gère la transmission des messages entre les clients MQTT.
- Il reçoit les messages publiés par les clients, les trie et les transmet ensuite aux clients abonnés.
- Les clients peuvent être des dispositifs ou des applications logicielles qui publient (envoient) ou s'abonnent (reçoivent) des messages via le broker.
- Un client qui publie envoie des messages à un topic, et un client qui s'abonne reçoit des messages de ce topic.
Avantages :
- Légèreté et efficacité : Utilise peu de bande passante et de ressources, idéal pour des appareils avec des capacités limitées.
- Facilité de mise en œuvre : Protocole simple à comprendre et à implémenter.
- Basse consommation d'énergie : Convient pour les appareils fonctionnant sur batterie.
- Supporte les communications bi-directionnelles : Permet des interactions bidirectionnelles entre le serveur et les appareils.
- Scalabilité : un broker peut facilement servir des centaines de clients, exécutant chacun le même code.
Inconvénients :
- Sécurité : Bien que MQTT supporte le cryptage SSL/TLS, la gestion de la sécurité peut être complexe.
- Dépendance au broker : Nécessite un broker central, ce qui peut être un point de défaillance unique.
- Latence : Peut avoir une latence plus élevée en comparaison avec d'autres protocoles plus directs, surtout dans les niveaux élevés de QoS.
Pour l'implémentation du broker, nous avons choisi d'utiliser le programme "Mosquito", avec une configuration basique sans SSL et en réseau local.
Nous avons ensuite créer un topic "history" servant a logger la date de tout les messages ainsi que la machine d'origine. Un deuxième topic "action" reçoit les commandes servant à interagir avec le site Web.
Serveur web
Le serveur web sers la page web accessible pour l'interface utilisateur.
Il est hébergé sur la même VM que le broker MQTT. Le site est basée sur le framework "flask" en python, permettant un développement simple.
L'utilisation de python permet aussi d’implémenter un client MQTT très simplement dans le même programme que le serveur web. Nous utilisons la bibliothéque PAHO
Comme pour le broker, la configuration est réalisée sans SSL dans un réseau local.
Raspberry Pi
Pour commencer, nous devons installer un OS sur notre Raspberry. A l'aide du Raspberry Pi Imager, nous installons un système d'exploitation Raspbian, conçu pour les Raspberry.
Cette Raspberry est ensuite branchée en port série à notre machine Zabeth, et nous utilisons l'utilitaire Minicom pour accéder aux fichiers de la RPi sans interface.
Capteur X-NUCLEO-53L5A1
Ce capteur de STD Microelectronics est un capteur de distance laser, composé de plusieurs capteurs formant une matrice de 8 capteur de longueur et 8 capteurs en largeur.
Modèle de machine learning
Les jeux de données d'entraînement pour le modèle créés sont les suivants:
- un jeu de données pour lequel rien de se passe pour le capteur (ni mouvement de swipe à gauche, ni à droite)
- un jeu de données pour le swipe à gauche,
- un jeu de données pour le swipe à droite.
Le formatage des données pour que Nanoedgestudio puisse les utiliser pour générer un modèle est un mélange du code implémenté dans le capteur et d'un script Python modifiant les fichiers de logs générés par nanoedgestudio pour créer des lignes contenant les données des 16 axes sur une durée de 10 à 16 samples.
Le test du benchmark sur Nanoaistudio avec les jeux de données de swipe gauche ou swipe droite n'ont pas donné de résultats concluants lors de l'émulation avec un nouveau jeu de données de test. En revanche, les jeux de données avec aucun mouvement et un mouvement de swipe droit on donné un modèle assez efficace dans la reconnaissance du mouvement.
Le manque d'efficacité d'un modèle peut-être dû notamment aux jeu de données d’entraînement qui n'est pas assez conséquent. Pour obtenir un modèle fiable dans tous les cas, il serait nécessaire d'utiliser des certaines voire des milliers de samples.
Application développée
Le site web développé possède l'interface suivante:
Ce site web reçoit correctement les requêtes MQTT, et change bien la photo lorsque cette requête indique "Right". En revanche, un modèle de données utilisable n'étant pas implémenté sur le capteur pour traiter les informations de distance et reconnaitre si le swipe est droit ou gauche, le système prévu utilisant le capteur n'est pas fonctionnel.
Travail restant
- Implémentation du modèle de machine learning sur le capteur NUCLEO-53L5A1 avec STM32CubeIDE
- Récupération de la réponse du modèle de machine learning via la Raspberry
Codes Sources
webserver.py :
from flask import Flask, request, render_template, jsonify
import paho.mqtt.client as mqtt
import random
import os
client_id = f'python-mqtt-{random.randint(0, 1000)}'
IMAGE_DIR = os.path.join('static', 'images')
image_files = [f for f in os.listdir(IMAGE_DIR) if os.path.isfile(os.path.join(IMAGE_DIR, f))]
current_image_index = 0
mqtt_client = mqtt.Client(client_id, userdata=None)#,protocol=mqtt.MQTTv5)
app = Flask(__name__)
broker = '127.0.0.140'
#broker = '2001:660:4401:6050:216:3eff:fe40:73d8'
port = 1883
username = "paul"
password = "pasglop"
messages = []
def on_connect(client,userdata,flags, rc):
print("Connected with result code " +str(rc))
client.subscribe("history")
def on_message(client, userdata, msg):
global current_image_index
print(msg.topic+" "+str(msg.payload))
messages.append(str(msg.payload))
if msg.payload.decode() == "Right":
current_image_index = (current_image_index + 1) % len(image_files)
mqtt_client.on_connect = on_connect
mqtt_client.on_message = on_message
mqtt_client.username_pw_set(username,password)
mqtt_client.connect(broker,port)
print("MQTT client connected successfuly !")
@app.route("/home") # this sets the route to this page
def home():
return "Hello! this is the main page <h1>HELLO</h1>"
@app.route("/")
def index():
return render_template('index.html')
@app.route("/get_messages")
def get_messages():
return jsonify(messages)
@app.route('/current_index')
def current_index():
global current_image_index
return jsonify(current_image_index)
@app.route('/current_image')
def current_image():
global current_image_index
image_path = os.path.join('static', 'images', image_files[current_image_index])
return jsonify({'image_url': image_path})
if __name__ == "__main__":
mqtt_client.loop_start()
app.run(host="0.0.0.0",debug=True)
index.html :
<!DOCTYPE html>
<html>
<head>
<title>MQTT Messages</title>
<script>
function fetchMessages(){
fetch('/get_messages')
.then(response => response.json())
.then(data => {document.getElementById('messages').innerHTML = data.join('<br>');
if (data.includes("Right")) {
updateCarouselImage();
}
})
.catch(error => {
console.error('Error fetching messages:', error);
});
}
function updateCarouselImage() {
fetch('/current_image')
.then(response => response.json())
.then(data => {
document.getElementById('carousel-image').src = data.image_url;
console.log('Updated Carousel');
})
.catch(error => {
console.error('Error fetching current image:', error);
});
}
setInterval(fetchMessages, 1000);
setInterval(updateCarouselImage, 1000);
</script>
</head>
<body>
<h1>TINDER</h1>
<div id="carousel-images">
<img id="carousel-image" src="static/images/img1.jpg" alt="Carousel Image">
</div>
<h1>MQTT Messages</h1>
<div id="messages"></div>
</body>
</html>
File Structure :
`-- website
|-- static
| |-- images
| | |-- img1.jpg
| | |-- img2.jpg
| | `-- img3.jpg
| `-- index.css
|-- templates
| `-- index.html
`-- webserver.py
raspberry script :
import paho.mqtt.client as paho
from datetime import datetime
username = "pifou"
password = "pasglop"
server_address = "2001:660:4401:6050:216:3eff:fe40:73d8"
mqtt_hostname = "G5_RPI4"
print("Connecting to MQTT server")
client = paho.Client(client_id="", userdata=None, protocol=paho.MQTTv5)
#client.tls_set(tls_version=mqtt.client.ssl.PROTOCOL_TLS)
client.username_pw_set(username,password)
client.connect(server_address, 1883)
print("Connection to MQTT server successfully established !")
now = datetime.now()
dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
client.publish("history", payload= mqtt_hostname+" "+dt_string, qos=1)
print("Mqtt message sent, exiting")