• Aucun résultat trouvé

Avant de s’intéresser, dans le chapitre suivant, à la projection de notre Composition sur un Middleware, nous devons mentionner brièvement l’implémentation des différentes étapes de la phase d’étude des Contraintes. Celle-ci demeure pour le moment limitée et mise en œuvre dans une librairie logicielle indépendante de celle présentée à l’Annexe D.

Même si, en l’état actuel, elle demeure limitée dans les fonctionnalités implémentées, elle propose une bonne base pour de futurs développements. Notre librairie propose une structure

6.5. Implémentation de cette approche

de données permettant de représenter notre graphe comme une liste de nœuds et d’arcs. Il est à noter que les Contraintes temporelles portant sur les Besoins de nos entités sont ici reportées sur les Liens pour un souci de simplicité et de représentation. Partant de cette structure de données, nous avons implémenté l’étape de vérification de compatibilité des Contraintes tem- porelles ainsi que certaines étapes de la structuration du graphe, à savoir la simplification de celui-ci (suppression des entités non périodiques, fusion des liens) et la séparation en différents graphes sur la base des Contraintes. A chaque étape du processus, un ou plusieurs fichiers en langage DOT [GKN15] sont générés afin de pouvoir automatiquement produire une repré- sentation visuelle de notre graphe en utilisant l’outil dot permettant de dessiner des graphes orientés.

Néanmoins, cette librairie présente encore un grand nombre de limitations. Premièrement, nous n’avons pas encore défini de description générique des Compositions. Dès lors, le Graphe d’Association de Connaissances associé à celle-ci doit être défini manuellement. En outre, l’absence actuelle d’interface entre cette librairie et celle chargée de gérer la description des Entités Composables ne nous permet pas à la fois de vérifier la validité du graphe (notamment si les Besoins et Produits utilisés pour décrire les Liens appartiennent effectivement aux entités liées) et de mettre en place la phase chargée de transformer le graphe pour qu’il ne soit plus constitué que d’Atomes. De fait, même s’il est possible de décrire un Graphe d’Association de Connaissances qui ne soit pas constitué entièrement d’Instances d’Atomes, il est nécessaire d’effectuer manuellement la conversion vers un Graphe d’Association de Connaissances ne contenant que des Instances d’Atomes afin de pouvoir appliquer les étapes déjà implémentées. Enfin, la structuration des graphes sous forme de Blocs n’est pas non plus implémentée. La détection des parallélismes et sérialisations dans un graphe orienté est en plus une probléma- tique complexe. Néanmoins, les travaux sur l’ordonnancement multi-cœurs tels que [SACG11, Section VI et Figure 3 notamment] peuvent offrir des pistes intéressantes d’algorithmes pour effectuer la structuration en Blocs de nos Graphes d’Association de Connaissances. Néanmoins, ces travaux se limitent souvent au cas où les graphes sont acycliques ce qui est rarement le cas d’une Composition utilisée pour décrire le contrôleur d’un robot.

6.6

Points clés du chapitre

 La phase d’étude des Contraintes a pour but de vérifier l’implémentabilité du contrôle décrit sur une cible technologique et logicielle donnée et de pouvoir déterminer les va- leurs des différents paramètres de l’implémentation et notamment la période d’exécution des entités ayant une exécution périodique.

 Cette phase commence par une restructuration du Graphe d’Association de Connais- sances associé à la Composition afin d’obtenir un ensemble de graphes temporellement indépendants et constitués uniquement des Instances d’Atomes ayant des Contraintes de nature P ´eriodique qui doivent toutes s’exécuter à la même période.

 Il faut ensuite, pour chaque graphe, exprimer les sérialisations et les parallélismes dans l’ordre des calculs à effectuer.

 Nous pouvons dès lors appliquer les formules de diffusion des Contraintes qui vont nous permettre de déterminer l’expression littérale de l’ensemble des périodes d’exécution possibles de chaque graphe en fonction des périodes d’exécution possibles des entités qu’il contient.

 Cet ensemble de périodes d’exécution possibles correspond à l’ensemble des périodes pour lesquelles la stabilité du contrôle est garantie tout en respectant les contraintes inhérentes à la cible d’implémentation.

 Il faut ensuite valuer les propri´et´es des Contraintes portant sur les différentes entités et appliquer les formules de calcul des périodes d’exécution précédemment établies pour vérifier l’implémentabilité de la Composition.

 Si la Composition n’est pas implémentable, l’étude des Contraintes va fournir aux concepteurs des architectures matérielles, logicielles et de contrôle des informations essentielles pour les aider à déterminer les modifications à mettre en œuvre pour rendre la Composition implémentable.

 Si elle est implémentable, alors nous pouvons choisir, parmi l’ensemble des périodes d’exécution possibles, celle que nous souhaitons affecter à chaque partie de la Compo- sition.

Chapitre 7

Projection sur un Middleware, l’exemple

de ContrACT

Au chapitre précédent, nous avons vu comment déterminer les périodes d’exécution de nos Atomes qui ont des Contraintes périodiques. A partir des Contraintes, nous devons désormais déterminer comment utiliser les différentes connaissances dans notre logiciel de contrôle. Il nous faut donc définir un ensemble de règles qui, pour une architecture logicielle et un Middleware donnés, vont nous permettre de savoir comment tel ou tel Atome sera utilisé.

Notre description étant indépendante des différentes cibles d’implémentation logicielles avec lesquelles elle est susceptible d’être implémentée, il nous faut établir un ensemble de règles pratiques pour chacune d’entre elles en fonction de ses spécificités. Ces règles, qui sont construites grâce à l’expérience du concepteur de l’architecture logicielle, vont nous permettre de déterminer les mécanismes à utiliser suivant les différentes natures de Contraintes et surtout ce qu’il ne faut pas faire car les mécanismes fournis ne le permettent pas.

Comme les règles sont spécifiques à un Middleware cible donné, nous allons donc illustrer notre approche avec l’exemple du Middleware ContrACT. Nous allons commencer par présen- ter les spécificités du Middleware ContrACT puis nous détaillerons les règles qui découlent de celles-ci.

7.1

ContrACT

Développée au LIRMM, l’approche ContrACT est une méthodologie de développement d’architectures de contrôle associée à un Middleware permettant leur mise en œuvre suivant les concepts établis par la méthodologie. Elle vise à permettre de respecter des considérations clés du génie logiciel [Pas10] :

Figure 7.1 – Aspects de la méthodologie abordés dans le chapitre 7

sabilité des composants logiciels.

– Une composition flexible de ces entités logicielles favorisant l’évolutivité du système.

Les briques logicielles utilisées dans ContrACT sont appelées modules. A l’instar d’objets ou de nos Atomes, les modules comprennent un comportement interne, non accessible direc- tement depuis l’extérieur et une interface qui leur permet d’échanger des informations entre modules ou de paramétrer leur comportement. Le comportement interne d’un module peut être divisé en deux parties, d’un côté un code commun générique (sous forme d’un squelette de code) chargé de la gestion du module (réception des messages, appel au code utilisateur, initialisation, fermeture) et de l’autre le code spécifique à l’utilisateur dont la structure dépend

7.1. ContrACT

du rôle joué ou de la fonctionnalité assurée par le module. L’interface de tous les modules, basée sur des ports typés, est organisée de manière identique, comme montré à la Figure 7.2.

Figure7.2 – Structure d’un module

Cette interface permet l’assemblage des modules par interconnexion de ports. Les échanges de données entre modules relèvent du modèle producteur/consommateur (publisher/subscriber).

Des ports de paramètres permettent à un autre module de valuer certaines données internes aux modules. Les ports d’évènements permettent aux modules d’émettre ou de recevoir des évènements, c’est-à-dire des données envoyées de manière sporadique. La connexion entre deux ports d’évènements peut soit se faire de manière unique (le receveur se désabonne de l’émetteur après réception de l’évènement) soit de manière "continue" (i.e. le receveur récupèrera tout les évènements émis), on parlera alors de flux d’évènements. Des ports de données permettent d’échanger des informations de manière périodique entre les modules. La connexion entre un port d’entrée d’un module et un port de sortie d’un autre module est appelée flux de données. En outre, les modules possèdent un port de requête qui permet de gérer leur activité (démarrage/arrêt) et leurs connexions (abonnement/désabonnement). Du point de vue logiciel, chacun de ces ports est une boîte aux lettres qui possède son propre buffer et peut donc stocker quelques données. Enfin, il est à noter que, quel que soit le type de flux (données ou évènements), c’est toujours le module consommateur de l’information qui doit réaliser les actions d’abonnement (connexion au flux) ou de désabonnement (déconnexion du flux).

De fait, la gestion des flux entre les modules peut être dynamique, c’est-à-dire qu’à tout moment un flux peut être mis en place ou interrompu. Cela offre une grande flexibilité dans la construction de l’application mais nécessite également une grande précaution dans la manipu- lation de ces flux. En effet, leur gestion étant totalement découplée, par exemple, du démarrage

ou de l’arrêt d’un module, il faut toujours s’assurer de la bonne interruption des flux dirigés vers un module avant de désactiver celui-ci. Sinon il ne relèvera plus les messages arrivant dans ses boîtes aux lettres ce qui entraînera le débordement de celles-ci et l’apparition de nombreuses erreurs dans l’application.

Les modules sont organisés en deux couches, décisionnelle et exécutive, qui traduisent leur rôle dans l’architecture logicielle ainsi que leurs modalités de fonctionnement (i.e. priorité, mécanismes de mises en œuvre, éléments d’interface utilisables). Ces différentes couches et les relations entre modules sont présentées à la Figure 7.3.

Figure7.3 – Structuration des différentes couches du Middleware ContrACT

Dans la couche décisionnelle, les modules sont appelés superviseurs et sont organisés, par le concepteur, de manière hiérarchique suivant le caractère plus ou moins global des déci- sions qu’ils doivent prendre. Les superviseurs peuvent interagir soit avec les superviseurs de niveau hiérarchique directement supérieur en leur transmettant des notifications sous forme d’évènements soit avec les superviseurs de niveau inférieur ou avec les modules de la couche exécutive en leur transmettant des requêtes et/ou des informations via des paramètres. Ces derniers traduisent la demande émanant d’un superviseur de mise en œuvre d’une décision par

7.1. ContrACT

d’autres superviseurs ou par des modules de la couche exécutive. Les superviseurs sont par définition asynchrones car ils ne s’exécutent que lorsqu’un évènement significatif (notification, timer, paramétrage) se produit. De fait, ils n’utilisent pas de port de données.

Leur code utilisateur est structuré en fonctions de supervision qui regroupent un ensemble de règles. Ces fonctions peuvent être activées soit par l’utilisateur (typiquement pour démarrer l’application ou activer un mode de fonctionnement spécifique), soit par des superviseurs de niveau hiérarchique plus élevé. L’activation ou non des fonctions de supervision permet ainsi de sélectionner les ensembles de règles activables, c’est-à-dire qui peuvent s’exécuter et dont les conditions d’activation et d’arrêt sont monitorées. Les règles, pouvant s’exécuter de manière concurrente au sein d’une fonction, sont construites en trois parties :

– Une précondition qui définit les conditions à remplir pour qu’une règle activable soit activée.

– Des actions à effectuer lorsque la règle devient active, il peut s’agir de calculs (courts), de paramétrages, d’envois d’évènements ou d’actions structurantes (activation d’un schéma, i.e. d’un assemblage de modules, et des modules associés, établissement d’un flux entre deux modules).

– Une postcondition qui définit les conditions à remplir pour qu’une règle active soit désac- tivée. Lorsque la règle devient inactive, les actions structurantes sont annulées (arrêt du schéma, interruption des flux).

La couche exécutive contient les modules qui sont chargés de mettre en œuvre la (ou les) commande(s) du robot choisie(s) par l’étage décisionnel. Ces modules doivent gérer à la fois, l’interaction avec le monde extérieur au contrôleur (capteurs, communications, actionneurs) et la (ou les) commande(s) elle(s)-même(s). Cette couche est divisée en deux domaines : le domaine synchrone qui comprend tous les modules s’exécutant de manière périodique et le domaine asynchrone comprenant tous les modules s’exécutant de manière évènementielle.

Les modules asynchrones ne sont pas ordonnancés et vont s’exécuter sur demande des superviseurs. En outre, ils ne possèdent pas de ports de données. Ils sont divisés en deux catégories. Les modules d’interaction sont utilisés pour implémenter des calculs courts ou des échanges avec des périphériques non périodiques. Ils peuvent être reliés ensemble par des flux d’évènements. Il s’agit des modules les plus prioritaires de la couche exécutive. D’un autre côté, les modules "temps-restant" sont utilisés pour effectuer des calculs longs souvent liés à la gestion de la mission et que ne peuvent réaliser les superviseurs pour des questions de réactivité, ou même des actions dont la durée exacte n’est pas prévisible. Il s’agit des modules

les moins prioritaires au sein du Middleware.

Le domaine synchrone comprend tous les modules s’exécutant de manière périodique ainsi que le module ordonnanceur chargé de gérer leur exécution. En effet, la gestion des modules synchrones est assurée par un module ordonnanceur qui pilote l’ordonnanceur du système d’exploitation. Il permet ainsi un contrôle plus précis de leur exécution.

A l’intérieur des modules synchrones, le code utilisateur est organisé autour de trois fonc- tions :

– Initialisation : les actions à réaliser à la création du module.

– Comportement : les actions à exécuter à chaque exécution du module. – Terminaison : les actions à réaliser quand le module est détruit.

De plus, lors de la description du module, sa durée critique doit être renseignée. Celle-ci correspond à la durée d’exécution laissée au module par l’ordonnanceur. Si le module dépasse cette durée, l’ordonnanceur commence par lui laisser une durée supplémentaire (ce qui décale d’autant l’ordonnancement des autres modules) et si le module n’a toujours pas terminé son exécution, l’ordonnanceur va réduire sa priorité afin de permettre aux modules suivants de s’exécuter pour respecter leurs échéances, puis le module pourra reprendre son exécution afin de la terminer une fois que tous les autres modules se seront exécutés. Nous pouvons donc constater l’importance d’un réglage précis de cette durée critique. De plus, différentes stratégies de gestion des dépassements peuvent être mises en œuvre dans l’ordonnancement en fonction du nombre et de la récurrence de ceux-ci (par exemple le nombre de dépassements sur une fenêtre glissante de n exécutions).

Les modules sont ensuite regroupés en schémas comme illustré Figure 7.4. On définit un schéma comme un ensemble de modules fonctionnant à une même période. Au sein d’un schéma, les modules sont reliés ensemble par des flux de données. Nous pouvons ainsi définir des contraintes de précédence entre les modules d’un même schéma qui vont permettre à l’ordonnanceur de déterminer dans quel ordre doivent s’exécuter les différents modules du schéma. Il est bien entendu possible d’utiliser plusieurs schémas simultanément, fonctionnant à des fréquences différentes ou non, et de connecter des modules appartenant à différents schémas. Néanmoins, deux points clés sont à noter. Premièrement, il est impossible d’imposer des contraintes de précédence entre des modules appartenant à différents schémas. De fait, les modules connectés ensemble par des flux interschémas doivent être "calculatoirement" indépendants pour éviter les problèmes liés au non-respect des contraintes de précédence. Deuxièmement, il faut s’assurer de correctement paramétrer la fréquence des émissions sur les flux de données. En effet, ContrACT permet d’indiquer le nombre de cycles séparant chaque envoi. Ainsi, si par exemple on connecte la sortie d’un module faisant partie d’un schéma