Architecture et distribution

Dans le document The DART-Europe E-theses Portal (Page 151-159)

L'architecture logicielle de CoreBot M se prête parfaitement à une implémentation sous NJN. Chaque unité logicielle est implémentée sous la forme d'un composant.

Les composants sont répartis dans sept processus systèmes afin, d'une part, de profiter des deux cœurs de la cible matérielle et, d'autre part, d'isoler certains composants.

Figure 59. Répartition des composants de CoreBot M sur plusieurs processus systèmes.

Chaque composant de pilotage de capteur/actionneur est isolé dans son propre processus, à l'exception des composants liés au laser (URG et CoreSLAM).

L'objectif est d'éviter la perte de données en provenance des capteurs. En donnant à ces processus une priorité maximale, on évite que des trames de données soient ignorées.

L'exécution de CoreSLAM est intimement liée aux données laser. Il ne peut donc fonctionner sans source en provenance du pilote du laser. Il est donc inutile de les séparer. Ils sont placés dans le même processus.

Selon cette même idée, les processus de traitement des données Kinect sont, à priori, à placer dans le même processus. Cependant, le pilote est séparé pour les questions de fiabilité évoqués dans la section 2.2. De même, le composant Core3DAnalyzer n'étant pas fiable, il est placé dans un processus qui lui est propre.

Le projet CoreBots - 139 Les deux derniers composants, CoreControl et CoreCarotte, sont deux éléments de traitement algorithmique. Ils ne sont pas critiques et leur fiabilité a été éprouvée. Nous les avons donc placés dans un processus unique.

Les composants les plus gourmands en ressources sont Core3DAnalyser et CoreSLAM. Ils consomment à eux deux 70% des ressources CPU. On pourrait donc envisager de les déporter sur une ferme de processeurs. Avec NJN, ce type de manipulation est en effet très aisé et ne remet pas en cause le comportement temporel de l'application, du moment que la latence donnée au système est suffisante. L'intérêt majeur de déporter les composants gourmands est de pouvoir réduire la puissance de calcul embarquée et donc la consommation électrique.

3.2 Fiabilité

Les processus qui hébergent des composants critiques doivent être surveillés. C'est le cas par exemple du processus 3 qui héberge le composant Core3DAnalyzer.

Une tâche supplémentaire se charge de ce travail. Elle fonctionne à la manière d'un chien de garde [88]. L'extrait de code ci-dessous en montre le principe.

Deux tâches sont instanciées dans cet exemple : la tâche task et la tâche monitor.

Cette dernière a pour fonction de surveiller la première.

NJN_DEF_ALWAYS(monitor){

njn_ref_t task = njn_new(self, "rt_task", "task", /*...*/);

njn_ref_t beat = njn_new(self, "var", "beat", NJN_BIND_TO_BEAT(task));

njn_new(self, "vt_task", "monitor", NJN_ALWAYS(monitor),

NJN_WHEN(beat), NJN_TIMEOUT(1 SEC));

return NJN_SUCCESS;

}

Lorsque le signal beat est à l'origine du réveil de la tâche monitor, aucune action n'est entreprise. En revanche un réveil par timeout permet d'identifier l’arrêt du processus et de le redémarrer.

Pour surveiller un processus, il suffit de lui confier l'exécution d'une tâche périodique et de placer le moniteur dans un autre processus. Lorsque le moniteur identifie un arrêt de l'exécution, il peut entreprendre de créer un nouveau processus pour y reconstituer les composants détruits. Le fonctionnement du système redevient alors normal.

140 - Chapitre 6

Dans notre application, il suffit de surveiller la tâche hébergée par le composant Core3DAnalyzer. En outre, en cas de défaillance du processus hébergeur, il est possible d'extraire des données du composant Kinect Voxel pour assurer la continuité du service en attendant le rétablissement du Core3DAnalyzer. Les données extraites sont moins riches mais parfaitement suffisantes pour les opérations courantes du robot. Elles ne permettent cependant pas de différencier les rampes des simples obstacles.

3.3 Synchronisation

Le problème de la synchronisation des données est réglé de façon totalement transparente par le framework NJN. Il suffit d'associer à chaque tâche la liste des signaux sur lesquels elle doit être synchronisée (figure 60).

Figure 60. Synchronisation des différents composants de CoreBot M.

Les données lues sur les autres flux correspondent systématiquement aux dernières informations disponibles à l'instant de synchronisation. Par exemple, la tâche associée au composant CoreSLAM est synchronisée sur les données du laser.

Elle consomme également les données en provenance de la centrale inertielle à travers un appel à la méthode njn_read(). La donnée récupérée correspond naturellement à la dernière trame de la centrale inertielle précédant la donnée laser à l'origine du traitement.

Un problème subsiste cependant : les données récupérées depuis les différents capteurs sont datées lorsque la trame correspondante est reçue par le driver logiciel correspondant et non à la date physique de la mesure. Or, à chaque capteur correspond une latence de mise en forme et de transmission des données

Le projet CoreBots - 141 très différente. Il faut donc, au moment de leur introduction dans NJN tenir compte de ce délai. Deux solutions existent.

La première consiste à synchroniser les données sur celles du capteur le plus lent en ajoutant un délai différentiel aux autres données. Il suffit de réaliser les écritures avec un paramètre NJN_AFTER() de valeur adéquate. Par exemple, pour retarder les données laser, il suffit d'écrire :

data = njn_read(laser_in);

njn_write(laser_out, data, NJN_AFTER(25 MSEC));

Toutes les données se trouvent datées avec retard, ce qui peut être inconfortable.

La seconde solution consiste à utiliser des boites de découplage pour redater les données issues des capteurs. La méthode njn_write_at() permet, dans le cadre d'une DecouplingBox uniquement, d'attribuer une date arbitraire aux évènements.

Dans le cas du laser qui introduit un retard d'environ 30 ms, il suffit alors d'écrire :

data = njn_read(laser_in);

njn_write_at(laser_out, data, njn_time_sub(njn_now(), 30 MSEC));

pour redater les données à leur instant réel de mesure.

Ne reste plus qu'à fixer la latence globale du système en attribuant à la tâche chargée du contrôle moteur une valeur suffisante pour effectuer l'ensemble des traitements et des échanges de données. Les performances de vitesse du robot sont directement liées à ce paramètre de latence. Typiquement, le contrôle est effectué à 20Hz (cadence de traitement des données laser) avec une latence de 100 ms, NJN se chargeant naturellement de pipeliner les traitements. Avec cette latence, le fonctionnement du robot est assuré pour une vitesse linéaire de 1 m/s environ et une vitesse de rotation de l'ordre de 180°/s.

Notons enfin que si l'on souhaite déporter l'algorithme de SLAM sur une ferme de calcul, la conception de l'application n'est pas affectée mais la latence globale doit être augmentée. Cela oblige à ralentir le robot pour préserver sa stabilité.

*

* *

Même si elle est empruntée au domaine de la robotique, cette étude de cas d'un système réel pose les problèmes de complexité des systèmes actuels de façon très réaliste. Les algorithmes mis en œuvre sont nombreux, très différents, complexes, de temps d'exécution fortement variable et pas toujours d'une fiabilité totale. Le nombre de capteurs est important et ils délivrent leurs données à des fréquences très différentes. La puissance de calcul nécessaire est très élevée et les contraintes temps-réel sont relativement sévères sans être critiques.

La solution proposée est générique : seul le composant CoreCarotte est spécifique au défi. Les autres composants sont réutilisables dans d'autres applications. Les aspects synchronisation et distribution sont totalement gérés par NJN. Seules la latence globale du système et la vitesse du robot sont à régler.

142 - Chapitre 6

Lors du développement du projet CoreBots, NJN n'était pas totalement fiabilisé.

L'implémentation réelle sur le robot CoreBot M s'appuie donc uniquement sur les primitives de bas niveau du projet AROS : DOHC, CHASSIS et CABLES.

Cependant, la conception des différents modules du système intègrent, en dur, les mécanismes du moteur d'NJN pour assurer la synchronisation notamment. Les principes de synchronisation, de monitoring et de distribution exposés ci-dessus ont été appliqués à tous les niveaux de la conception. Ils ont largement contribué à la réussite du projet et ont permis au robot de gagner le défi CAROTTE deux années consécutives.

T ROISIÈME PARTIE

L' IMPLÉMENTATION

C HAPITRE 7

A BSTRACTION DE LA MÉMOIRE , DE LA

PLATEFORME ET DE LA COMMUNICATION

– L ES BIBLIOTHÈQUES SUPPORTS

L'implémentation d'NJN repose sur trois bibliothèques : DOHC, qui assure la gestion de la mémoire et qui procure un ensemble de structures de données génériques ; CHASSIS, qui encapsule les services du système d'exploitation de manière à assurer la portabilité des applications ; et enfin CABLES, qui se charge de gérer les communications sous la forme d'appel de services distants asynchrone. Ce chapitre décrit brièvement les points essentiels de ces trois bibliothèques.

1 Le double arbre à cames en tête

La librairie DOHC procure à NJN des capacités de typage dynamique des données proches de celles des langages de scripts tels que Ruby ou Pyton. Le type des objets DOHC n'est pas fixé à la compilation et peut changer au cours de l'exécution. Il peut s'agir de données scalaires entières ou flottantes, mais aussi d'objets plus complexes tels que des tableaux dynamiques, des tables de hachages, etc. En associant DOHC à la librairie CLUTCH, on peut même manipuler des classes et des objets au sens de la POO.

Par ailleurs, la mémoire occupée par les objets DOHC est gérée par un ramasse-miette. Ce dernier peut travailler à espace mémoire limité et fixé, si bien que l'on peut contrôler efficacement les besoins mémoire des applications NJN, en

146 - Chapitre 7

particulier sur les cibles matérielles disposant de peu de mémoire. Ce ramasse-miette comporte cependant quelques inconvénients. Le compromis adopté, celui de la rapidité, conduit dans certaines configurations à confier à l'utilisateur la libération mémoire de certains objets. Nous aborderons ce point plus en détail.

L'objet de cette partie est de donner un aperçu des différents types d'objets DOHC et de montrer les possibilités offertes par la bibliothèque dans son ensemble. La première section est assez générale. Elle traite de l'organisation et des principes généraux de DOHC. Dans la section suivante nous verrons comment DOHC permet de construire des structures et des objets avec la librairie CLUTCH. Nous verrons ensuite les mécanismes de sérialisation qui facilitent les échanges de données à travers fichiers et réseaux. Enfin nous aborderons la gestion mémoire proprement dite.

Dans le document The DART-Europe E-theses Portal (Page 151-159)