Intelligence embarque IMA5 2022/2023 G2
Sommaire
Choix du projet
Nous avons décidé, d'utiliser dans la détection de problème dans le calibrage d'une machine
Contexte
De nos jours, la fabrication des engins de transports dans de nombreux domaines (e.g l'aéronautique, ferroviaire) sont réalisées par des machines. Et le calibrage de ces machines doit être précis pour fixer les éléments. Cependant, lorsque les moteurs commencent à être usés, le calibrage de ce dernier peut être imprécis. Une fluctuation de calibrage peut générer une longue erreur de production (ceci est grave pour l'entreprise de production en chaîne), il est alors nécéssaire de détecter ces erreurs de calibrage pour adopter une solution.
Idée
Le capteur sera monté sur un bras. On veut détecter la présence de trous sur des pièces afin d'y fixer des rivets. Ainsi, on peut mesurer la taille et profondeur des trous. Il y aura d'autres forme de détection : pronfondeur des trous, nombre de trous, etc
STMCubeIDE
Premier programme : Blink
Pour se familiariser avec STMCubeIDE, on essaye de faire fonctioner la carte Nucleo-F401RE, la LED utilisateur LD2 est situé sur le pin PA5 (GPIOA, GPIO_PIN_5) Pour se faire :
- On crée un nouveau projet STM
- On vérifie la configuration des GPIO et Clock
- On clique sur Device Generation Tool Code Generation
- On ouvre main.c et on ajoute ce code dans la boucle loop:
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, 1); HAL_Delay(1000); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, 0); HAL_Delay(1000);
- On build et on run le debug
Pour plus de détail, suivre sur ce lien
Premier pas avec le capteur NUCLEO-53L5A1
On récupère le projet sur ce fichier : Fichier:Ai4industry-master.zip
On ouvre ce projet sur l'IDE, puis on configure un utilitaire port série (par exemple minicom) :
- Baud rate : 460800
- 8N-1
- Par défaut l'écoute sur /dev/ttyACM0
Le programme initial du projet nous affiche les valeurs sur un tableau 4*4, nous pouvons modifier cette variable pour avoir toute les valeurs dans un tableau 8*8 :
Profile.RangingProfile = RS_PROFILE_8x8_CONTINUOUS;
Maintenant on essaye de récupèrer les valeurs vers un fichier csv, on modifie la fonction print_result
pour afficher les valeurs séparées d'une virgule :
static void print_result(RANGING_SENSOR_Result_t *Result) { int8_t j, k, l; uint8_t zones_per_line; zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) || (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4; 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((l!=0) || (k!=(zones_per_line - 1)) || (j!=0)){ printf(","); } if (Result->ZoneResult[j+k].NumberOfTargets > 0) printf("%ld",(long)Result->ZoneResult[j+k].Distance[l]); else printf("0"); } } } printf("\r\n"); }
Puis on récupère les donénes dans un fichier csv : cat /dev/ttyACM0 >> data.csv
On récupère toutes nos datasets dans le répertoire /dataset
Liste des problèmes et résolutions
- Impossible de télécharger le firmware de la carte
- Résolution : Configurer le proxy (mettre en manuel et non native et configurer HTTP et HTTPS et tout cocher)
- Erreur lors du débug : Could not determine GDB version using command: arm-none-eabi-gdb --version
- Résolution : Lancer sur un terminal :
sudo apt-get install libncurses5:amd64
source
- Résolution : Lancer sur un terminal :
Récupération de données
1er jet
On réalise la récupération avec ces paramètres de maquette
- maquette en bois avec petits trous de 1cm de diamètre
- distance entre le capteur et la plaque : 30 cm
- Pas de planche de background (mur ou autre)
Résultats : il ne détecte que des plaques avec 0 trous
2ème jet
On réalise la récupération avec ces paramètres de maquette
- maquette en bois avec petits trous de 1cm de diamètre
- distance entre le capteur et la plaque : 20-15 cm
- Pas de planche de background (mur ou autre)
Résultats : il détecte plus facilement les trous mais très instable, on essaye de changer de maquette
3ème jet
On réalise la récupération avec ces paramètres de maquette
- maquette en carton calculée l'aide des formules trigo et de l'angle de calcul du capteur avec petits trous de 3.14cm de diamètre
- distance entre le capteur et la plaque : 24 cm
- Pas de planche de background (mur ou autre)
Résultats : il détecte plus facilement les trous mais reste très instable, nous avons remarquer que le capteur est plus stable si il y un élément derrière les trous, on ajoute un background
4ème jet
On réalise la récupération avec ces paramètres de maquette
- maquette en carton calculée l'aide des formules trigo et de l'angle de calcul du capteur avec petits trous de 3.14cm de diamètre
- distance entre le capteur et la plaque : 24 cm
- Background distance de 10cm de la maquette
Résultats : beaucoup plus stable
Résultats finaux
NanoEdgeAIStudio
On upload nos datasets et on fait un benchmark :
Nous avons un résultat de 96%. Lorsque nous essayons de simuler, il détecte :
- Si il y a une pièces ou non
- les erreurs de position
Cependant il ne détecte pas le type de pièce (1,2 ou 3 trous) et l'erreur de profondeur
Nous calculons la taille des pixels, pour une distance de 24cm entre le capteur et la pièce, nous avons une taille de 3.12cm, or nos trous font 1.2cm de diamètre. Nous essayons alors avec notre maquette actuel, de diminuer la distance entre le capteur et la pièce, pour que le capteur détecte plus précisément les trous espacées.
Autres possibilités :
- Agrandir l'espacement entre les trous (puisque il est possible qu'un seul pixel de calcul détecte plusieurs trous) au moins 3.12cm d'espacement pour une distance de 24cm
- Agrandir la taille des trous, plus la taille est élevée, plus le calcul des pixels sera précis
Maquette
1ème maquette
On réalise 4 pièces en bois pour simuler une pièce à fixer avec différents trous :
Nous avons fait aussi bricoler quelque chose pour simuler si la pièce est correctement percer :
Puis on réalise notre maquette, on fixe le capteur de distance sur un support vertical, on place les pièces sur un autre support à même hauteur du capteur pour simuler le fait que la pièce arrive devant le bras fixeur (ou le capteur de distance)
2ème maquette
On réalise une maquette plus grand selon les paramètres du capteur et la distance en utilisant les formules de trigonométrie :
Implémentation en embarqué
On récupère le .zip de notre AI, on l'a met dans un dossier créé pour l'occasion (e.g /home/pifou/STM32CubeIDE/derlique_meynier/53L5A1_ThresholdDetection/neai),
Dans STM32IDE, on importe la librarie : voila comment faire
On ajoute au le flag -u _printf_float dans les paramètres de build pour pouvoir afficher les flottants dans la liaison série
On crée deux fonction et on change la boule loop du fichier, et on inclut les headers files</code>app_x-cude-tof1.c</code>
... while (1) { /* interrupt mode */ if (ToF_EventDetected != 0) { ToF_EventDetected = 0; status = VL53L5A1_RANGING_SENSOR_GetDistance(VL53L5A1_DEV_CENTER, &Result); if (status == BSP_ERROR_NONE) { fill_buffer(input_user_buffer,&Result); neai_classification(input_user_buffer, output_class_buffer, &id_class); my_print_result(&Result,input_user_buffer,output_class_buffer,id_class); } } } ...
void my_print_result(RANGING_SENSOR_Result_t *Result, float input[], float output_class_buffer[], uint16_t id_class) { int8_t j; for(int i=0;i<DATA_INPUT_USER * AXIS_NUMBER;i++){ printf("%lf,",(double)input[i]); } printf("\r\n"); int8_t plus_grd=0; float plus_grd_f=-1; for(j=0;j<CLASS_NUMBER;j++){ if(plus_grd_f < output_class_buffer[j]){ plus_grd_f = output_class_buffer[j]; plus_grd = j; } printf("probability of %d holes : ",j); printf("%ld%%\r\n",(long)(output_class_buffer[j]*100)); } printf("probably %d holes !\r\n",plus_grd); }
void fill_buffer(float sample_buffer[], RANGING_SENSOR_Result_t *Result) { int8_t j, k, l; uint8_t zones_per_line; int8_t count=0; zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) || (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4; for (j = 0; j < Result->NumberOfZones; j += zones_per_line) { for (l = 0; l < RANGING_SENSOR_NB_TARGET_PER_ZONE; l++) { for (k = (zones_per_line - 1); k >= 0; k--){ if((l!=0) || (k!=(zones_per_line - 1)) || (j!=0)){ } if (Result->ZoneResult[j+k].NumberOfTargets > 0){ sample_buffer[count] = (float)Result->ZoneResult[j+k].Distance[l]; count++; } else{ sample_buffer[count] = (float)0; count++; } } } } }
Présentation / Questions / Réponses
[Fichier : IMA5sc 2022 23 G2 IE_presentation.pdf]
Réponses au questions pour les prochaines générations de IMA5SC :
- Question sur la taille des données : il est mieux de faire des bases de données grande et égales, ce que nous savions mais nous pas fait de grande databases pour savoir un meilleur temps de calcul de benchmark.
- Question sur la luminosité : la luminosité peut avoir un impact sur les données du capteur de distance, vérifier à faire des mesures et tests avec une maquette exposé dans le même niveau de luminosité.
- Question sur la matrice de confusion : Pour voir quel paramètre influe sur un autre, on peut regarder la matrice de confusion dans les résultats du benchmark en regardant dans la partie "Result" à droite dans la page des résultats (voir image), la matrice de confusion permet de savoir la proportion de données bien entraîner (voir image)