« SE5 ECEAI/eceai 2023/2024/BalbastreSimon » : différence entre les versions

De wiki-se.plil.fr
Aller à la navigation Aller à la recherche
 
(3 versions intermédiaires par le même utilisateur non affichées)
Ligne 46 : Ligne 46 :


==== Acquisition du dataset. ====
==== Acquisition du dataset. ====
<syntaxhighlight lang="python3">
Le code ci-dessous nous a permis d'acquérir 30 rotation complètes par sens de rotation.<syntaxhighlight lang="python3">
import serial
import serial
import numpy as np
import numpy as np
Ligne 116 : Ligne 116 :
==== Augmentation ====
==== Augmentation ====
Nous avons découpé les échantillons de façon aléatoire pour détecter des parties de la rotation plus courtes.
Nous avons découpé les échantillons de façon aléatoire pour détecter des parties de la rotation plus courtes.
==== Inférence ====
Pour faire tourner l'inférence, nous avons utilisé l'émulateur généré par nanoedge. Nous l'avons placé sur la VM où il lisait les données reçues dans un fichier tampon.


=== Communication ===
=== Communication ===
Ligne 122 : Ligne 125 :
Grâce à cube IDE, nous avons flashé la carte avec un des code d'exemples adapté au capteur et à la carte: 53L5A1_SimpleRanging.
Grâce à cube IDE, nous avons flashé la carte avec un des code d'exemples adapté au capteur et à la carte: 53L5A1_SimpleRanging.


Nous avons modifié le code afin de rendre le formatage de communication série moins lourd.
Nous avons modifié le code afin de rendre le formatage de communication série moins lourd:<syntaxhighlight lang="c++">
static void print_result(RANGING_SENSOR_Result_t *Result)
{
  int8_t j;
  int8_t k;
  int8_t l;
  uint8_t zones_per_line;
 
  zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) ||
        (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4;
 
  printf("\n\n");
 
  for (j = 0; j < Result->NumberOfZones; j += zones_per_line)
  {
    for (l = 0; l < RANGING_SENSOR_NB_TARGET_PER_ZONE; l++)
    {
      /* Print distance and status */
      for (k = (zones_per_line - 1); k >= 0; k--)
      {
        if (Result->ZoneResult[j+k].NumberOfTargets > 0)
          printf("%5ld : %5ld ",
              (long)Result->ZoneResult[j+k].Distance[l],
              (long)Result->ZoneResult[j+k].Status[l]);
        else
          printf("%5s : %5s ", "X", "X");
      }
      printf("|\n");
 
      if ((Profile.EnableAmbient != 0) || (Profile.EnableSignal != 0))
      {
        /* Print Signal and Ambient */
        for (k = (zones_per_line - 1); k >= 0; k--)
        {
          if (Result->ZoneResult[j+k].NumberOfTargets > 0)
          {
            if (Profile.EnableSignal != 0)
              printf("%5ld : ", (long)Result->ZoneResult[j+k].Signal[l]);
            else
              printf("%5s : ", "X");
 
            if (Profile.EnableAmbient != 0)
              printf("%5ld ", (long)Result->ZoneResult[j+k].Ambient[l]);
            else
              printf("%5s ", "X");
          }
          else
            printf("%5s : %5s ", "X", "X");
        }
        printf("|\n");
      }
    }
  }
}
</syntaxhighlight>


==== Réception des données sur la raspberry ====
==== Réception des données sur la raspberry ====
Ligne 166 : Ligne 223 :
==== Communication entre la Raspberry et la VM. ====
==== Communication entre la Raspberry et la VM. ====
Nous avons utilisé mosquitto pour communiquer. La Raspberry était le client et la VM le serveur.
Nous avons utilisé mosquitto pour communiquer. La Raspberry était le client et la VM le serveur.
== A detailler un peu mieux ==
-Formatage des messages envoyés par la Nucleo avec STM32CubeIDE
-installation de mosquitto sur la VM
-installation de mosquitto sur la raspberry (client)
-en fait le client marche mieux en python sans mosquitto
-en fait le broker marche mieux en python sans mosquitto non plus

Version actuelle datée du 28 janvier 2024 à 22:22

Le Sujet

L'objectif de ce TP est de créer un système capable de reconnaître certains mouvements à l'aide d'une caméra, notre système doit faire la différence entre une rotation de la main dans le sens horaire et une rotation dans le sens trigonométrique.


L'architecture utilisée est la suivante:

Un capteur X-NUCLEO-53L5A1 récupère les données, il est consitué d'une matrice 8x8 de capteurs de distance, nous utiliserons ici une matrice 4x4 faisant partie du composant NUCLEO.

Ce composant NUCLEO est envoie les données brutes à une stm32 chargée de les formater avant de les transmettre à une raspberry pi4.

La raspberry pi utilise un script python pour récupérer les données et les envoyer par MQTT (un protocole basé sur TCP) à une machine virtuelle hébergée sur chassiron.

Ce travail a été réalisé par Maxime Balbastre et Élias Simon

Raspberry Pi4

Nous avons d'abord cherché à mettre l'OS Raspbian sur la carte à l'aide de l'installeur "Raspberry PI Imager"

L'objectif était de configurer la raspberry via une liaison série vers la zabeth. Devant les difficultés éprouvées, nous avons décider de nous tourner vers une autre connexion et nous avons re-flashé la carte en la connectant directement au routeur WiFi_IE_1 en autorisant les connexions ssh.

De cette manière nous pouvions nous connecter à la raspberry par ssh en partant de n'importe quelle machine connectée à WiFi_IE_1.


Machine virtuelle

Nous avons d'abord créé une machine virtuelle tournant sur debian à l'aide de la commande suivante:

xen-create-image --hostname BalbastreSimon --force --dist bookworm --size 10G --memory 1G --dir /usr/local/xen --password glopglop --dhcp --bridge bridgeStudents

Il fallait ensuite faire les configurations réseau, nous avons ajouté ceci dans le fichier /etc/network/interfaces afin de permettre les connexions en ipv6:

auto enX0
iface enX0 inet6 auto

Nous avons ensuite ajouté ces lignes dans le fichier /etc/resolv.conf afin de stocker les adresses des serveurs DNS:

domain plil.info
search plil.info plil.fr
nameserver 2a01:c916:2047:c800:216:3eff:fe82:8a5c

Enfin, nous avons ajouté de nouvelles sources dans le fichier /etc/apt/sources.list pour pouvoir ajouter certains paquets jusqu'alors inaccessibles

deb     http://deb.debian.org/debian     bookworm main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian     bookworm main contrib non-free non-free-firmware

IA

Nous avons utilisé nanoedge pour les entraînements. Nous avons choisi de détecter les mouvements de rotation de la main. Le format du dataset était le suivant:

1 fichier par classe, 1 ligne par mouvement.

Cela nous a permit de détecter les rotation dans un intervalle de temps prédéfini d'environ 7 secondes.

Acquisition du dataset.

Le code ci-dessous nous a permis d'acquérir 30 rotation complètes par sens de rotation.

import serial
import numpy as np
import keyboard

import sys

#py -m serial.tools.list_ports
n, m = 4, 4
res = (n,m)

nb_sample_per_recording = 20

try:
	file = sys.argv[1]
except:
	print("Give file name as input.")
	exit()


print("Writing to", file)

with serial.Serial('COM7', 460800, timeout=1) as ser:
	for i_sample in range(10):
		f = open(file, mode="a")
		print("Press q to start recording")
		while 1:
			if keyboard.is_pressed('q'):  # if key 'q' is pressed 
				break  # finishing the loop

		#synchronisation
		line = ser.readline().decode()   # read a '\n' terminated line
		while line != "\n":
			line = ser.readline().decode()   # read a '\n' terminated line

		print("Sample number: {}".format(i_sample))
		print("Recording...")

		lines = []
		for t in range(nb_sample_per_recording):
			#converts to matrix
			mat = np.zeros(res)
			for i in range(n):
				line = ser.readline().decode()   # read a '\n' terminated line
				line = str(line)
				cells = line.split('|')
				for j in range(m): 
					intensity, state = cells[j].split(':')
					try:
						intensity = int(intensity)
					except:
						intensity = 0
					mat[i][j] = intensity

			line = ser.readline()   # read a '\n' terminated line
			mat = mat.flatten()
			str_list = map(str,mat)
			line = ",".join(str_list)
			lines.append(line)
			#np.savetxt("main bouge.csv", matrix, delimiter=",")
		lines = ",".join(lines)
		f.write(lines)
		f.write("\n")
		print("Finished")

		f.close()

L'IA fonctionnant très bien après validation (87,40% de précision avec le modèle random forest), nous avons décidé de détecter les mouvement en continu en faisant de l'augmentation de données.

Augmentation

Nous avons découpé les échantillons de façon aléatoire pour détecter des parties de la rotation plus courtes.

Inférence

Pour faire tourner l'inférence, nous avons utilisé l'émulateur généré par nanoedge. Nous l'avons placé sur la VM où il lisait les données reçues dans un fichier tampon.

Communication

Carte NUCLEO

Grâce à cube IDE, nous avons flashé la carte avec un des code d'exemples adapté au capteur et à la carte: 53L5A1_SimpleRanging.

Nous avons modifié le code afin de rendre le formatage de communication série moins lourd:

static void print_result(RANGING_SENSOR_Result_t *Result)
{
  int8_t j;
  int8_t k;
  int8_t l;
  uint8_t zones_per_line;

  zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) ||
         (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4;

  printf("\n\n");

  for (j = 0; j < Result->NumberOfZones; j += zones_per_line)
  {
    for (l = 0; l < RANGING_SENSOR_NB_TARGET_PER_ZONE; l++)
    {
      /* Print distance and status */
      for (k = (zones_per_line - 1); k >= 0; k--)
      {
        if (Result->ZoneResult[j+k].NumberOfTargets > 0)
          printf("%5ld : %5ld ",
              (long)Result->ZoneResult[j+k].Distance[l],
              (long)Result->ZoneResult[j+k].Status[l]);
        else
          printf("%5s : %5s ", "X", "X");
      }
      printf("|\n");

      if ((Profile.EnableAmbient != 0) || (Profile.EnableSignal != 0))
      {
        /* Print Signal and Ambient */
        for (k = (zones_per_line - 1); k >= 0; k--)
        {
          if (Result->ZoneResult[j+k].NumberOfTargets > 0)
          {
            if (Profile.EnableSignal != 0)
              printf("%5ld : ", (long)Result->ZoneResult[j+k].Signal[l]);
            else
              printf("%5s : ", "X");

            if (Profile.EnableAmbient != 0)
              printf("%5ld ", (long)Result->ZoneResult[j+k].Ambient[l]);
            else
              printf("%5s ", "X");
          }
          else
            printf("%5s : %5s ", "X", "X");
        }
        printf("|\n");
      }
    }
  }
}

Réception des données sur la raspberry

import serial
import numpy as np
import keyboard

import sys

#py -m serial.tools.list_ports
n, m = 4, 4
res = (n,m)

with serial.Serial('COM7', 460800, timeout=1) as ser:
	#synchronisation
	line = ser.readline().decode()   # read a '\n' terminated line
	while line != "\n":
		line = ser.readline().decode()   # read a '\n' terminated line

	while 1:
		print("New sample")
		#converts to matrix
		mat = np.zeros(res)
		for i in range(n):
			line = ser.readline().decode()   # read a '\n' terminated line
			line = str(line)
			cells = line.split('|')
			for j in range(m): 
				intensity, state = cells[j].split(':')
				try:
					intensity = int(intensity)
				except:
					intensity = 0
				mat[i][j] = intensity
		line = ser.readline()
		mat = mat.flatten()
		str_list = map(str,mat)
		line = ",".join(str_list)

Communication entre la Raspberry et la VM.

Nous avons utilisé mosquitto pour communiquer. La Raspberry était le client et la VM le serveur.