Réseau de capteurs sans fil

De Ensiwiki
Aller à : navigation, rechercher
RF2500.png
Titre du projet Réseau de capteurs sans fil
Cadre Ensimag

Équipe Vincent Bonnecuelle, Sofiene Jouini
Encadrants Franck Rousseau

Introduction

Ce projet a pour objet la création d'un réseau à l'aide de microcontrôleurs très basse consommation. Lesdits microcontrôleurs (modèle Texas Instruments MSP430) seront par la suite nommés « capteurs » par souci de simplification.

Afin d'assurer la communication entre les capteurs, ceux-ci doivent suivre un protocole de communication préalablement défini ici.

Cette page présente donc les étapes que nous avons suivies afin d'implémenter le protocole, ou du moins une partie de celui-ci.

Matériels et logiciels requis

Matériels

Ces capteurs ont ici plusieurs avantages à être utilisés en tant que nœuds d'un réseau. Premièrement, la programmation de ceux-ci est faite en langage C, qui en soi n'est pas nécessairement un langage de bas niveau, mais qui aborde tout de même plusieurs aspects propres à la programmation bas niveau (possibilités d'accès à la mémoire en utilisant des adresses explicites, "bitfields" dans les structures, etc.). Cet aspect bas niveau est justement nécessaire pour aborder les couches inférieures du modèle OSI, car ces couches imposent une certaine proximité avec le matériel sur lequel elles sont implémentées. De plus, ces capteurs sont très économes en énergie, et peuvent à ce titre être individuellement alimentés par une simple pile AA. Enfin, la famille MSP430 est grande et particulièrement populaire parmi les microcontrôleurs disponibles sur le marché, la documentation à ce sujet est donc tout aussi grande.

Logiciels

  • Compilateur MSPGCC
  • Débogueur MSPDEBUG
  • Émulateur de terminal Minicom
  • Bibliothèques logicielles MRFI (Minimal RF Interface) et BSP (Board Support Package), fournies par Texas Instrument.

La page commune du projet fournie une aide précieuse pour installer et configurer ces programmes, celle-ci est accessible ici.

Présentation du protocole

Protocol eZ430-RF2500.png

Le protocole schématisé ci-dessus suit quatre étapes principales :

La période de scan (SCANNING)

Durant cette période, le capteur recherche des balises (beacons) provenant d'autres capteurs voisins. Lorsque la recherche se termine deux cas de figure s'imposent alors :

  • Soit il en trouve aucune, et initie alors un nouveau réseau, devenant ainsi capteur initiateur, c'est-à-dire le capteur sur lequel les autres capteurs voisins se synchronisent.
  • Soit il en trouve au moins une, auquel cas il s'associe à ce réseau avoisinant.

La période de balisage (BEACONING)

Durant cette période, le capteur adopte deux comportements distincts :

  • Soit il se situe dans son slot temporel, auquel cas il émet ses balises aux capteurs voisins ;
  • Soit il se situe hors de son slot temporel, auquel cas il reçoit les balises des capteurs voisins, notamment celles du capteur initiateur qui lui seront nécessaires pour synchroniser son duty cycle sur celui de ce dernier.

Comme spécifié dans la page commune du projet, l'envoi des balises se fera directement à l'instant prévu (MRFI_TX_TYPE_FORCED).

La période active (ACTIVE)

Durant cette période, l'échange des paquets a lieu entre les capteurs appartenant au même réseau.

L'envoi des paquets se fait cette fois-ci selon la méthode définie par CSMA/CA (MRFI_TX_TYPE_CCA).

De plus, afin de se laisser du temps pour observer les envois et réceptions, un paquet reçu génèrera l'envoi d'un autre paquet lors du duty cycle suivant et non immédiatement.

La période de sommeil (SLEEPING)

Durant cette période, le capteur interrompt toutes ses communications afin d'économiser son énergie et attend patiemment que le duty cycle arrive à terme.

Une fois cette période écoulée, le capteur rentre à nouveau en période de balisage et son duty cycle est remis à zéro.

Prise en main des capteurs

Avant d'implémenter le protocole, il convenait de prendre en main les capteurs. En effet, programmer un microcontrôleur n'est pas aussi aisé que programmer un ordinateur « classique », où nombre d'aspects bas niveau sont automatiquement gérés par le système d'exploitation. Fort heureusement, nous disposions de plusieurs codes sources d'exemples dont notamment ceux présents dans le TP de Thomas Watteyne, qui fut notre principale source d'inspiration pour la mise en place des tests qui vont suivre. Malgré cela, nos « premiers pas » furent hésitants tant la moindre ligne modifiée, ne serait-ce que déplacée, peut changer radicalement le comportement du capteur. Pour donner une image, c'était comme programmer avec des gants de boxe, exercice périlleux s'il en est !

Simple échange de balises

Le but de ce test est d'illustrer les mécanismes de communication permettant à au moins deux capteurs d'échanger des balises. Le format des balises utilisé ici est le même que celui défini ici. Aussi, il est nécessaire d'inclure le fichier protocol.h disponible ici. Le code source est le même pour tous les capteurs qui souhaitent communiquer leurs balises. Pour envoyer une balise, il suffit d'appuyer sur le bouton du capteur. Les balises sont échangées en broadcast, c'est-à-dire qu'une fois qu'une balise est émise, celle-ci est susceptible d'être reçue par l'ensemble des capteurs en zone de portée. Lorsqu'une balise est reçue, celle-ci est affichée via le lien série (accessible avec minicom par exemple).

Utilisation basique d'un timer

Le but de ce test est d'illustrer l'utilisation basique d'un timer (une horloge). Les capteurs disposent de deux timers : le timer A et le timer B. Le timer A est contrôlé par un DCO (Digitally Controlled Oscillator) tandis que le timer B est contrôlé par un VLO (Very-low-power, Low-frequency Oscillator). À ce titre, le timer A est bien plus rapide et plus précis que le timer B, mais consomme cependant bien plus d'énergie. Dans cet exemple, seul le timer A sera utilisé. Une fois le code flashé sur un capteur, il suffit de presser le bouton de celui-ci pour que la LED verte clignote toutes les secondes tandis que la LED rouge s'allume et s'éteint successivement toutes les 5 secondes. Plus concrètement, lors de l'appui sur le bouton, le timer A est lancé et chaque milliseconde, il incrémente une variable milliseconds. Lorsque la valeur de cette variable dépasse 1000, la LED verte s'allume, la variable milliseconds est remise à zéro, et la variable seconds est incrémentée. Lorsque la valeur de cette dernière variable dépasse 5, la LED rouge s'allume, et la variable seconds est remise à zéro.

Première tentative de synchronisation avec un timer

Le but de ce test est de mettre en place un mécanisme de synchronisation basique entre au moins deux capteurs. Le code source est le même pour tous les capteurs. Dès le branchement du capteur, le timer A se déclenche toutes les millisecondes et toutes les secondes, un compteur est incrémenté afin que sa valeur soit affichée via le lien série. Lors de l'appui sur le bouton de l'un des capteurs, un paquet portant le flag FBEACON est émis, puis le timer et le compteur de ce même capteur sont remis à zéro. Lors de la réception de ce paquet par les capteurs en zone de portée, le timer et le compteur de ces mêmes capteurs sont remis à zéro. Ainsi, le timer et le compteur de chacun des capteurs devraient être synchronisés sur ceux des autres. Cependant, nous constatons une dérivation qui se creuse davantage avec le temps, d'où la nécessité pour la suite de synchroniser les capteurs à chaque duty cycle.

Seconde tentative de synchronisation avec deux timers

Le but de ce test est de corriger le problème de dérivation temporelle constaté dans le test précédent (simple_synchronisation.c). Pour ce faire nous utiliserons deux timers : le timer A et le timer B. Le code source est le même pour tous les capteurs. Dès le branchement du capteur, le timer A se déclenche toutes les millisecondes et toutes les secondes, un compteur est incrémenté afin que sa valeur soit affichée via le lien série. Lors d'un appui sur le bouton de l'un des capteurs, ce capteur envoie un paquet contenant la valeur courante de son compteur et dès lors le timer B se déclenche afin d'envoyer ce même paquet toutes les cinq secondes. Ce capteur devient alors le capteur initiateur, autrement dit celui qui synchronise ses voisins avec lui-même. En effet, à la réception de ce paquet, les capteurs voisins actualisent leurs propres compteurs qui devraient alors être identiques à celui du capteur initiateur. Un phénomène de dérivation similaire est constaté, mais il est cette fois-ci corrigé toutes les cinq secondes, la synchronisation est donc plus stable.

Implémentation du protocole

Machine à état

Chaque capteur implémente le cycle de vie suggéré par le protocole grâce à une machine à état comme schématisée ci-dessous :

Protocol implementation.png

Pour passer d'un état à un autre, nous avons utilisé les timers A et B. Le timer A déclenche une interruption toutes les millisecondes et incrémente la variable delay_a tandis que le timer B déclenche également une interruption toutes les millisecondes mais incrémente cette fois-ci la variable delay_b. La variable delay_a assure ainsi la transition entre l'état SCANNING et l'état BEACONING, puis une fois le duty cycle enclenché, la transition entre l'état SLEEPING et l'état BEACONING. Quant à la variable delay_b, elle assure la transition entre l'état BECONING et l'état ACTIVE ainsi que celle entre l'état ACTIVE et l'état SLEEPING. C'est le timer A qui démarre le timer B dès que l'état BEACONING est atteint, aussi, le timer B tourne systématiquement en parallèle du timer A.

Gestion des balises

Lors de l'état SCANNING, le capteur doit être en mesure de recevoir et sauvegarder plusieurs balises pour ensuite s'associer au réseau de l'une d'entre elles. Pour cela, nous avions tout d'abord songé à utiliser des listes chainées pour stocker et parcourir les balises reçues, mais hélas, le microcontrôleur MSP430F2274 possède seulement 1Ko de RAM, et avec cette méthode, la pile du capteur se retrouvait rapidement pleine. Afin de pallier à ce problème, nous avons donc utilisé des tableaux de taille fixe et avons défini des méthodes pour en simplifier l'usage. Lesdites méthodes sont définies dans le fichier beacons.h et implémentées dans le fichier beacons.c. Ainsi, lors de l'état SCANNING, les balises reçues sont stockées dans le tableau adéquat. Lorsque l'état SCANNING arrive à terme, ce même tableau est parcouru afin de sélectionner la balise qui possède le plus petit identifiant de réseau (telle que défini dans la spécification) et le plus grand slot, afin de ne pas occuper un slot déjà prit.

Synchronisation des capteurs

Afin d'assurer que les timers de chaque capteur soient bien synchronisés avec ceux des autres, nous avons choisi de définir un capteur initiateur, occupant le slot 0. Ainsi, au tout début de l'état BEACONING, chaque capteur reçoit une balise du capteur initiateur et ajuste leurs timers en fonction, et ce à chaque duty_cycle afin d'assurer une synchronisation stable. Bien que ce choix simplifie grandement la synchronisation des capteurs, il présente un inconvénient majeur : si le capteur initiateur se retrouve hors de portée ou qu'il est simplement débranché, alors la synchronisation est perdue.

Ce qu'il reste à faire

Dans l'état actuel des choses, le protocole implémenté permet simplement de créer un réseau auprès duquel d'autres capteurs peuvent s'associer. Les capteurs d'un même réseau sont bel et bien synchronisés et chaque capteur émet ses balises dans le slot temporel qui lui a été attribué.

Cependant, comme nous n'avons pas pu implémenter le protocole en entier, les fonctionnalités suivantes restent à écrire :

  • Gérer l'envoi de paquet d'informations (flag FDATA) en broadcast : actuellement, seules les balises (flag FBEACON) sont transmises en broadcast ;
  • Gérer l'envoi de paquets unicast entre voisins à un saut : malheureusement, nous ne sommes pas parvenus à lire l'adresse physique d'un capteur ;
  • Mettre en place le routage multi-sauts de niveau 2 : impossible à mettre en place sans avoir au préalable implémenté l'envoi de paquets unicast.

Conclusion

Bien que nous n'ayons pas pu implémenter le protocole en entier, nous tirons un bilan positif de ce projet, car il fut riche en apprentissage. En effet, nous étions auparavant inexpérimentés avec la programmation sur microcontrôleur, et désormais nous en connaissons les grands principes. Ensuite, à travers ce protocole quoique minimal, nous comprenons bien mieux le socle applicatif sur lequel reposent la majorité des objets connectés qui nous entourent. Dorénavant, face à un projet similaire, nos connaissances et notre savoir-faire acquis lors de ce projet nous permettons d’aborder le problème avec méthode, calme et sérénité.

Références