Intelligence embarque IMA5 2022/2023 G2 : Différence entre versions

De Wiki d'activités IMA
(Premier pas avec le capteur NUCLEO-53L5A1)
(Présentation / Questions / Réponses)
 
(52 révisions intermédiaires par 2 utilisateurs non affichées)
Ligne 1 : Ligne 1 :
 
= Choix du projet =
 
= Choix du projet =
  
Nous avons décidé, d'utiliser dans la détection de problème dans le calibrage d'une machine
+
L'intelligence embarquée sera utilisée pour détecter les erreurs de perçage.
  
 
===Contexte===
 
===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.
+
De nos jours, la fabrication des engins de transports dans de nombreux domaines (e.g l'aéronautique, ferroviaire) est réalisée par des machines. Et le calibrage de ces machines doit être précis pour percer, riveter, fixer les éléments. Cependant, lorsque les moteurs commencent à être usés, ils deviennent moins précis. Une fluctuation de la précision peut générer une longue erreur de production (ce qui peut être très grave dans une chaîne de production), il est alors nécessaire de détecter ces erreurs de précision pour adopter une solution.
  
 
===Idée===
 
===Idée===
  
Le capteur sera monté sur un bras.
+
On suppose que 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.
+
Le concept est de 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.
+
Le capteur est utilisé pour détecter le nombre de trous effectivement percés sur une plaque (peu importe le matériau).
Il y aura d'autres forme de détection : pronfondeur des trous, nombre de trous, etc
+
Une classification sera effectuée pour savoir si aucun, un, deux ou trois trous ont été effectivement percés.
  
 
= STMCubeIDE =
 
= STMCubeIDE =
Ligne 40 : Ligne 40 :
 
* Baud rate : 460800
 
* Baud rate : 460800
 
* 8N-1
 
* 8N-1
* Par défaut l'écoute sur /dev/ttyACM0
+
* Par défaut l'écoute sur /dev/ttyACM0 sur linux
  
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 :  
+
Le programme initial du projet nous affiche les valeurs sur un tableau 4*4, nous pouvons modifier le code pour avoir toutes les valeurs dans un tableau 8*8 :  
 
<code> Profile.RangingProfile = RS_PROFILE_8x8_CONTINUOUS;</code>
 
<code> Profile.RangingProfile = RS_PROFILE_8x8_CONTINUOUS;</code>
  
Ligne 74 : Ligne 74 :
 
   }
 
   }
  
Puis on récupère les donénes dans un fichier csv : <code>cat /dev/ttyACM0 >> data.csv</code>
+
Puis on récupère les données dans un fichier csv : <code>cat /dev/ttyACM0 >> data.csv</code>
  
=Maquette=
+
On récupère tous nos datasets dans le répertoire /dataset
  
 
==Liste des problèmes et résolutions==
 
==Liste des problèmes et résolutions==
Ligne 86 : Ligne 86 :
 
* Erreur lors du débug : Could not determine GDB version using command: arm-none-eabi-gdb --version  
 
* Erreur lors du débug : Could not determine GDB version using command: arm-none-eabi-gdb --version  
 
**Résolution : Lancer sur un terminal : <code>sudo apt-get install libncurses5:amd64</code> [https://stackoverflow.com/questions/39831575/could-not-determine-gdb-version-after-sending-arm-none-eabi-gdb-version-resp source]
 
**Résolution : Lancer sur un terminal : <code>sudo apt-get install libncurses5:amd64</code> [https://stackoverflow.com/questions/39831575/could-not-determine-gdb-version-after-sending-arm-none-eabi-gdb-version-resp source]
 +
 +
=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 : Les trous ne sont pas détectés par le capteur
 +
 +
==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 : détection des tous mais très instable, on peut mieux faire
 +
 +
==3ème jet==
 +
 +
On réalise la récupération avec ces paramètres de maquette
 +
* maquette en carton dimensionnée à l'aide des formules de trigonométrie 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 : Les trous sont bien détectés mais la détection reste un peu instable, nous avons remarqué que la mesure est plus consistante s'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 : Classification efficace, mesures stables
 +
 +
==Problèmes==
 +
 +
* Maquette qui change de position, instable
 +
* Difficile de retrouver la bonne position de la maquette ou capteur après déplacement
 +
 +
==Résultats finaux==
 +
[[Fichier:IMA5sc 2022 23 G2 db0.png|thumb|center|300px|dataset 0 trou (moyenne)]]
 +
[[Fichier:IMA5sc 2022 23 G2 db1.png|thumb|center|300px|dataset 1 trou (moyenne)]]
 +
[[Fichier:IMA5sc 2022 23 G2 db2.png|thumb|center|300px|dataset 2 trous (moyenne)]]
 +
[[Fichier:IMA5sc 2022 23 G2 db3.png|thumb|center|300px|dataset 3 trous (moyenne)]]
 +
 +
=NanoEdgeAIStudio=
 +
 +
On upload nos datasets et on fait un benchmark :
 +
 +
[[Fichier:IMA5sc 2022 23 G2 benckmark.png|thumb|center|700px|maquette]]
 +
 +
Nous avons une précision de 96%.
 +
Le type de pièce est bien détecté ainsi que l'erreur de profondeur
 +
 +
=Maquette=
 +
 +
==1ème maquette==
 +
 +
On réalise 4 pièces en bois pour simuler une pièce à fixer avec différents trous :
 +
 +
[[Fichier:IMA5sc 2022 23 G2 piece en bois.jpg|thumb|center|400px|Pièces en bois pour maquette]]
 +
 +
Nous avons aussi bricolé quelque chose pour simuler si la pièce est correctement percée :
 +
 +
[[Fichier:IMA5sc 2022 23 G2 bricolage.jpg|thumb|center|200px|bricolage]]
 +
 +
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.
 +
 +
 +
[[Fichier:IMA5sc 2022 23 G2 maquette1.jpg|thumb|center|200px|maquette]]
 +
[[Fichier:IMA5sc 2022 23 G2 maquette2.jpg|thumb|center|200px|maquette]]
 +
 +
==2ème maquette==
 +
 +
On réalise une maquette plus grande selon les paramètres du capteur et la distance en utilisant les formules de trigonométrie :
 +
 +
[[Fichier:IMA5sc 2022 23 G2 maquette3.jpg|thumb|center|200px|maquette2]]
 +
[[Fichier:IMA5sc 2022 23 G2 maquette4.jpg|thumb|center|600px|maquette2]]
 +
 +
=Implémentation en embarqué=
 +
 +
On récupère le .zip de notre IA, on la met dans un dossier créé pour l'occasion (e.g /home/pifou/STM32CubeIDE/derlique_meynier/53L5A1_ThresholdDetection/neai),
 +
 +
Dans STM32IDE, on importe la librairie : [https://community.st.com/s/question/0D50X0000BJ2gL4SQJ/how-to-add-external-libraries-in-stm32cubeide voila comment faire]
 +
 +
On ajoute 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 fonctions et on change la boucle principale 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++;
 +
          }
 +
        }
 +
      }
 +
    }
 +
  }
 +
 +
Résultat sur la liaison série :
 +
 +
[[Fichier:IMA5sc 2022 23 G2 resultat implementation.png|thumb|center|700px|Page de benchmark]]
 +
 +
=Présentation / Questions / Réponses=
 +
 +
[[Fichier : IMA5sc 2022 23 G2 IE_presentation.pdf]]
 +
 +
[[Fichier:IMA5sc 2022 23 G2 IE_video.pdf]]
 +
 +
Réponses aux questions pour les prochaines générations de IMA5SC :
 +
 +
* Question sur la taille des données : il est mieux de faire des datasets grands et de tailles égales pour chaque classe de données, il est important de noter que cela influe sur temps de calcul de benchmark attention à prendre cela en compte pour ne pas manquer de temps sur l'implémentation du code sur STM32IDE avant la fin de la séance.
 +
 +
* 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înée (voir image)
 +
 +
[[Fichier:IMA5sc 2022 23 G2 benchmark page.png|thumb|center|700px|Page de benchmark]]
 +
[[Fichier:IMA5sc 2022 23 G2 matrice de confusion.png|thumb|center|700px|Exemple matrice de confusion]]

Version actuelle datée du 27 décembre 2022 à 17:58

Choix du projet

L'intelligence embarquée sera utilisée pour détecter les erreurs de perçage.

Contexte

De nos jours, la fabrication des engins de transports dans de nombreux domaines (e.g l'aéronautique, ferroviaire) est réalisée par des machines. Et le calibrage de ces machines doit être précis pour percer, riveter, fixer les éléments. Cependant, lorsque les moteurs commencent à être usés, ils deviennent moins précis. Une fluctuation de la précision peut générer une longue erreur de production (ce qui peut être très grave dans une chaîne de production), il est alors nécessaire de détecter ces erreurs de précision pour adopter une solution.

Idée

On suppose que le capteur sera monté sur un bras. Le concept est de détecter la présence de trous sur des pièces afin d'y fixer des rivets. Le capteur est utilisé pour détecter le nombre de trous effectivement percés sur une plaque (peu importe le matériau). Une classification sera effectuée pour savoir si aucun, un, deux ou trois trous ont été effectivement percés.

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 sur linux

Le programme initial du projet nous affiche les valeurs sur un tableau 4*4, nous pouvons modifier le code pour avoir toutes 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 données dans un fichier csv : cat /dev/ttyACM0 >> data.csv

On récupère tous 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é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 : Les trous ne sont pas détectés par le capteur

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 : détection des tous mais très instable, on peut mieux faire

3ème jet

On réalise la récupération avec ces paramètres de maquette

  • maquette en carton dimensionnée à l'aide des formules de trigonométrie 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 : Les trous sont bien détectés mais la détection reste un peu instable, nous avons remarqué que la mesure est plus consistante s'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 : Classification efficace, mesures stables

Problèmes

  • Maquette qui change de position, instable
  • Difficile de retrouver la bonne position de la maquette ou capteur après déplacement

Résultats finaux

dataset 0 trou (moyenne)
dataset 1 trou (moyenne)
dataset 2 trous (moyenne)
dataset 3 trous (moyenne)

NanoEdgeAIStudio

On upload nos datasets et on fait un benchmark :

maquette

Nous avons une précision de 96%. Le type de pièce est bien détecté ainsi que l'erreur de profondeur

Maquette

1ème maquette

On réalise 4 pièces en bois pour simuler une pièce à fixer avec différents trous :

Pièces en bois pour maquette

Nous avons aussi bricolé quelque chose pour simuler si la pièce est correctement percée :

bricolage

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.


maquette
maquette

2ème maquette

On réalise une maquette plus grande selon les paramètres du capteur et la distance en utilisant les formules de trigonométrie :

maquette2
maquette2

Implémentation en embarqué

On récupère le .zip de notre IA, on la met dans un dossier créé pour l'occasion (e.g /home/pifou/STM32CubeIDE/derlique_meynier/53L5A1_ThresholdDetection/neai),

Dans STM32IDE, on importe la librairie : voila comment faire

On ajoute 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 fonctions et on change la boucle principale 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++;
          }
        }
      }
    }
  }

Résultat sur la liaison série :

Page de benchmark

Présentation / Questions / Réponses

Fichier:IMA5sc 2022 23 G2 IE presentation.pdf

Fichier:IMA5sc 2022 23 G2 IE video.pdf

Réponses aux questions pour les prochaines générations de IMA5SC :

  • Question sur la taille des données : il est mieux de faire des datasets grands et de tailles égales pour chaque classe de données, il est important de noter que cela influe sur temps de calcul de benchmark attention à prendre cela en compte pour ne pas manquer de temps sur l'implémentation du code sur STM32IDE avant la fin de la séance.
  • 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înée (voir image)
Page de benchmark
Exemple matrice de confusion