SE5 ECEAI/eceai 2023/2024/AmorosDelaby

De wiki-se.plil.fr
Révision datée du 28 janvier 2024 à 20:39 par Mdelaby (discussion | contributions) (intro)
Aller à la navigation Aller à la recherche


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.

Architecture matérielle déployée

L'architecture matérielle est composé d'un capteur TOF (time of flight), d'une carte équipée d'un microcontrôleur STM32, d'une raspberry pi, point d'accès Wifi, d'un serveur de virtualisation et finalement d'un PC de l'utilisateur.

Notre objectif est d'implémenter le modèle d'intelligence artificielle le plus proche de l'utilisateur afin d'éviter de transmettre à travers internet un flux de donnée continu provenant du capteur. Le modèle sera exécuté par le STM32 (ou éventuellement la Rapsbery Pi) pour ne transférer que des requêtes simple et légères.

Ainsi, la partie serveur ne sers qu'on stockage des données et à l'interface web.

D'un point de vu énergétique, le mème modèle exécuté sur un micro contrôleur ou une Raspberry pi sera surement moins efficace qu'un modèle exécuté sur un véritable serveur, principalement a cause de la différence de finesse de gravure entre les puces.

En effet la réduction de bande passante est massive :

  • 8x8 valeurs de 8 bit à 60hz + 20 octets de header/ paquets = 40 kbit/s / clients. Une connexion ADSL serait saturé en une cinquantaine de clients, sans compter l'interface web.
  • 5 requete de 50 octets par minutes = 0.033 kbit/s / clients. L'impacte sur la bande passante est minime.


Chaque kbit supplémentaire impliquera une consommation supplémentaire pour leur cryptage ainsi que pour leur transfert a travers chaque serveurs, routeurs, point d'accès et interface jusqu'au modèle. A l'opposée, en implémentant le modèle sur le STM32, l'impact énergétique transférée au dispositif, et pris en charge par l'utilisateur.

Notre dispositif client Raspbery PI + SMT32 consomme environ 8W connecté à un réseau WiFi.

On pourrait encore réduire en remplaçant la Raspberry par un ESP32 pour la connectivité.

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 :

  1. Légèreté et efficacité : Utilise peu de bande passante et de ressources, idéal pour des appareils avec des capacités limitées.
  2. Facilité de mise en œuvre : Protocole simple à comprendre et à implémenter.
  3. Basse consommation d'énergie : Convient pour les appareils fonctionnant sur batterie.
  4. Supporte les communications bi-directionnelles : Permet des interactions bidirectionnelles entre le serveur et les appareils.
  5. Scalabilité : un broker peut facilement servir des centaines de clients, exécutant chacun le même code.

Inconvénients :

  1. Sécurité : Bien que MQTT supporte le cryptage SSL/TLS, la gestion de la sécurité peut être complexe.
  2. Dépendance au broker : Nécessite un broker central, ce qui peut être un point de défaillance unique.
  3. 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:

Capture d'ecran du site final. L'image change à chaque message MQTT de type "Right" sur le topic "history"

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.

- Exposer les services à Internet et les sécuriser.

Voici une proposition d'architecture améliorer pour exposer l'application et rendre le site plus fonctionnelle :

Web IE MD.png

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")