Réseau de capteurs sans fil : Différence entre versions
Ligne 1 : | Ligne 1 : | ||
+ | [[Catégorie:Projets]] | ||
+ | [[Catégorie:Projets Réseaux Mobiles et Avancés]] | ||
+ | |||
{{ | {{ | ||
Projet Étudiant | Projet Étudiant | ||
− | | titre = Réseau de capteurs sans fil | + | |titre = Réseau de capteurs sans fil |
− | | image = [[Fichier:RF2500.png|200px]] | + | |cadre= Projets Réseaux Mobiles et Avancés |
+ | |image = [[Fichier:RF2500.png|200px]] | ||
|equipe=[mailto:vincent.bonnecuelle@ensimag.grenoble-inp.org Vincent Bonnecuelle], [mailto:sofiene.jouini@grenoble-inp.org Sofiene Jouini] | |equipe=[mailto:vincent.bonnecuelle@ensimag.grenoble-inp.org Vincent Bonnecuelle], [mailto:sofiene.jouini@grenoble-inp.org Sofiene Jouini] | ||
|encadrants=[mailto:Franck.Rousseau@imag.fr Franck Rousseau] | |encadrants=[mailto:Franck.Rousseau@imag.fr Franck Rousseau] | ||
}} | }} | ||
− | |||
− | |||
− | |||
== Introduction == | == Introduction == |
Version actuelle en date du 9 avril 2018 à 11:02
![]() | |
---|---|
Titre du projet | Réseau de capteurs sans fil |
Cadre | Projets Réseaux Mobiles et Avancés
|
Équipe | Vincent Bonnecuelle, Sofiene Jouini |
Encadrants | Franck Rousseau |
Sommaire
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
- Capteurs basse consommation TI MSP430
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
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).
simple_beacon_txrx.c |
#include <mrfi.h>
#include <radios/family1/mrfi_spi.h>
#include <bsp_leds.h>
#include <stdlib.h>
#include <stdio.h>
#include "protocol.h"
void TXString(char* string, int length)
{
int pointer;
for( pointer = 0; pointer < length; pointer++)
{
UCA0TXBUF = string[pointer];
while (!(IFG2&UCA0TXIFG));
}
UCA0TXBUF = '\r';
while (!(IFG2&UCA0TXIFG));
UCA0TXBUF = '\n';
}
void print_beacon(mBeacon beacon)
{
char buffer[30];
sprintf(buffer, "Received beacon {%u, %u, %u} %c",
beacon.network_num,
beacon.slot_num,
beacon.slot_total, '\0');
TXString(buffer, sizeof(buffer) - 1);
}
void receive_beacon()
{
mrfiPacket_t packet;
MRFI_Receive(&packet);
if (packet.frame[9] == FBEACON) {
mBeacon incoming_beacon = {
.network_num = packet.frame[10],
.slot_num = packet.frame[11],
.slot_total = N_SLOT
};
print_beacon(incoming_beacon);
}
}
void send_beacon(mBeacon beacon)
{
mrfiPacket_t packet;
packet.frame[0]=8+20;
packet.frame[9] = FBEACON;
packet.frame[10] = beacon.network_num;
packet.frame[11] = beacon.slot_num;
MRFI_Transmit(&packet, MRFI_TX_TYPE_FORCED);
}
int main(void)
{
BSP_Init();
P1DIR &= ~0x04;
P1REN |= 0x04;
P1OUT |= 0x04;
P1IE |= 0x04;
MRFI_Init();
P3SEL |= 0x30; // P3.4,5 = USCI_A0 TXD/RXD
UCA0CTL1 = UCSSEL_2; // SMCLK
UCA0BR0 = 0x41; // 9600 from 8Mhz
UCA0BR1 = 0x3;
UCA0MCTL = UCBRS_2;
UCA0CTL1 &= ~UCSWRST; // Initialize USCI state machine
IE2 |= UCA0RXIE; // Enable USCI_A0 RX interrupt
MRFI_SetLogicalChannel(2);
mrfiSpiWriteReg(CHANNR,0x12);
MRFI_WakeUp();
MRFI_RxOn();
__bis_SR_register(GIE+LPM4_bits);
return 0;
}
void MRFI_RxCompleteISR()
{
BSP_TOGGLE_LED1();
receive_beacon();
}
__attribute__ ((interrupt (PORT1_VECTOR)))
void interrupt_button(void)
{
P1IFG &= ~0x04;
mBeacon own_beacon = {
.network_num = (rand() % 255) + 1, // number between 1 and 244
.slot_num = 0,
.slot_total = N_SLOT
};
send_beacon(own_beacon);
BSP_TOGGLE_LED2();
}
|
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.
simple_timer.c |
#include <mrfi.h>
#include <bsp_leds.h>
int milliseconds;
int seconds;
void start_timer_A()
{
TACTL|=TACLR; TACCTL0=CCIE; TACTL=TASSEL_1+MC_1;
}
void stop_timer_A()
{
TACTL=MC_0; TACCTL0=0;
}
int main(void)
{
BSP_Init();
P1DIR &= ~0x04;
P1REN |= 0x04;
P1OUT |= 0x04;
P1IE |= 0x04;
MRFI_Init();
P3SEL |= 0x30; // P3.4,5 = USCI_A0 TXD/RXD
UCA0CTL1 = UCSSEL_2; // SMCLK
UCA0BR0 = 0x41; // 9600 from 8Mhz
UCA0BR1 = 0x3;
UCA0MCTL = UCBRS_2;
UCA0CTL1 &= ~UCSWRST; // Initialize USCI state machine
IE2 |= UCA0RXIE; // Enable USCI_A0 RX interrupt
BCSCTL3 |= LFXT1S_2; TACTL=MC_0; TACCTL0=0; TACCR0=11;
return 0;
}
__attribute__ ((interrupt (PORT1_VECTOR)))
void interrupt_button(void)
{
P1IFG &= ~0x04;
milliseconds = 0;
seconds = 0;
start_timer_A();
}
__attribute__ ((interrupt (TIMERA0_VECTOR)))
void interrupt_timer_A(void)
{
milliseconds++;
if (milliseconds >= 1000) {
BSP_TOGGLE_LED1();
milliseconds = 0;
seconds++;
}
if (seconds >= 5) {
BSP_TOGGLE_LED2();
seconds = 0;
}
}
void MRFI_RxCompleteISR() {} // Unused
|
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.
simple_synchronisation.c |
#include <mrfi.h>
#include <radios/family1/mrfi_spi.h>
#include <bsp_leds.h>
#include "protocol.h"
#include <stdlib.h>
#include <stdio.h>
int milliseconds;
int counter;
void start_timer_A()
{
TACTL|=TACLR; TACCTL0=CCIE; TACTL=TASSEL_1+MC_1;
}
void stop_timer_A()
{
TACTL=MC_0; TACCTL0=0;
}
void TXString(char* string, int length)
{
int pointer;
for( pointer = 0; pointer < length; pointer++)
{
UCA0TXBUF = string[pointer];
while (!(IFG2&UCA0TXIFG));
}
UCA0TXBUF = '\r';
while (!(IFG2&UCA0TXIFG));
UCA0TXBUF = '\n';
}
void print_counter(int counter)
{
char buffer[5];
sprintf(buffer, "%d %c", counter, '\0');
TXString(buffer, sizeof(buffer) - 1);
}
void send_beacon_flag() {
mrfiPacket_t packet;
packet.frame[0]=8+20;
packet.frame[9] = FBEACON;
MRFI_Transmit(&packet, MRFI_TX_TYPE_FORCED);
milliseconds = 0;
counter = 0;
}
void receive_beacon_flag() {
mrfiPacket_t packet;
MRFI_Receive(&packet);
if (packet.frame[9] == FBEACON) {
milliseconds = 0;
counter = 0;
}
}
int main(void)
{
BSP_Init();
P1DIR &= ~0x04;
P1REN |= 0x04;
P1OUT |= 0x04;
P1IE |= 0x04;
MRFI_Init();
MRFI_SetLogicalChannel(2);
mrfiSpiWriteReg(CHANNR,0x12);
P3SEL |= 0x30; // P3.4,5 = USCI_A0 TXD/RXD
UCA0CTL1 = UCSSEL_2; // SMCLK
UCA0BR0 = 0x41; // 9600 from 8Mhz
UCA0BR1 = 0x3;
UCA0MCTL = UCBRS_2;
UCA0CTL1 &= ~UCSWRST; // Initialize USCI state machine
IE2 |= UCA0RXIE; // Enable USCI_A0 RX interrupt
BCSCTL3 |= LFXT1S_2; TACTL=MC_0; TACCTL0=0; TACCR0=11;
MRFI_WakeUp();
MRFI_RxOn();
milliseconds = 0;
counter = 0;
start_timer_A();
return 0;
}
void MRFI_RxCompleteISR()
{
BSP_TOGGLE_LED1();
stop_timer_A();
receive_beacon_flag();
start_timer_A();
}
__attribute__ ((interrupt (PORT1_VECTOR)))
void interrupt_button(void)
{
P1IFG &= ~0x04;
stop_timer_A();
send_beacon_flag();
BSP_TOGGLE_LED2();
start_timer_A();
}
__attribute__ ((interrupt (TIMERA0_VECTOR)))
void interrupt_timer_A(void)
{
milliseconds++;
if (milliseconds >= 1000) {
// one second has passed
counter++;
milliseconds = 0;
print_counter(counter);
}
}
|
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.
double_timer_synchronisation.c |
#include <mrfi.h>
#include <radios/family1/mrfi_spi.h>
#include <bsp_leds.h>
#include "protocol.h"
#include <stdlib.h>
#include <stdio.h>
int delay_a;
int delay_b;
int counter;
void start_timer_A()
{
TACTL|=TACLR; TACCTL0=CCIE; TACTL=TASSEL_1+MC_1;
}
void stop_timer_A()
{
TACTL=MC_0; TACCTL0=0;
}
void start_timer_B()
{
TBCTL|=TBCLR; TBCCTL0=CCIE; TBCTL=TBSSEL_2+MC_1;
}
void stop_timer_B()
{
TBCTL=MC_0; TBCCTL0=0;
}
void TXString(char* string, int length)
{
int pointer;
for( pointer = 0; pointer < length; pointer++)
{
UCA0TXBUF = string[pointer];
while (!(IFG2&UCA0TXIFG));
}
UCA0TXBUF = '\r';
while (!(IFG2&UCA0TXIFG));
UCA0TXBUF = '\n';
}
void print_counter(int counter)
{
char buffer[5];
sprintf(buffer, "%d %c", counter, '\0');
TXString(buffer, sizeof(buffer) - 1);
}
void send_counter_value(int value) {
mrfiPacket_t packet;
packet.frame[0]=8+20;
packet.frame[9] = counter;
MRFI_Transmit(&packet, MRFI_TX_TYPE_FORCED);
}
int receive_counter_value() {
mrfiPacket_t packet;
MRFI_Receive(&packet);
return packet.frame[9];
}
int main(void)
{
BSP_Init();
P1DIR &= ~0x04;
P1REN |= 0x04;
P1OUT |= 0x04;
P1IE |= 0x04;
MRFI_Init();
MRFI_SetLogicalChannel(2);
mrfiSpiWriteReg(CHANNR,0x12);
P3SEL |= 0x30; // P3.4,5 = USCI_A0 TXD/RXD
UCA0CTL1 = UCSSEL_2; // SMCLK
UCA0BR0 = 0x41; // 9600 from 8Mhz
UCA0BR1 = 0x3;
UCA0MCTL = UCBRS_2;
UCA0CTL1 &= ~UCSWRST; // Initialize USCI state machine
IE2 |= UCA0RXIE; // Enable USCI_A0 RX interrupt
BCSCTL3 |= LFXT1S_2; TACTL=MC_0; TACCTL0=0; TACCR0=11;
TBCTL=MC_0; TBCCTL0=0; TBCCR0=7999;
MRFI_WakeUp();
MRFI_RxOn();
delay_a = 0;
delay_b = 0;
counter = 0;
start_timer_A();
__bis_SR_register(GIE+LPM3_bits); // Active interruptions
return 0;
}
void MRFI_RxCompleteISR()
{
BSP_TOGGLE_LED1();
counter = receive_counter_value();
delay_a = 0;
}
__attribute__ ((interrupt (PORT1_VECTOR)))
void interrupt_button(void)
{
P1IFG &= ~0x04;
send_counter_value(counter);
BSP_TOGGLE_LED2();
start_timer_B();
}
__attribute__ ((interrupt (TIMERA0_VECTOR)))
void interrupt_timer_A(void)
{
delay_a++;
if (delay_a >= 1000) {
// one second has passed
counter++;
delay_a = 0;
print_counter(counter);
}
// Enter in LPM0 mode for leaving timer A running
__bic_SR_register_on_exit(SCG1+SCG0);
}
__attribute__ ((interrupt (TIMERB0_VECTOR)))
void interrupt_timer_B(void)
{
delay_b++;
if (delay_b >= 5000) {
// five seconds passed
delay_b = 0;
send_counter_value(counter);
delay_a = 0;
BSP_TOGGLE_LED2();
}
// Enter in LPM3 mode for leaving timer B running
__bis_SR_register_on_exit(LPM3_bits);
}
|
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 :
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.
beacons.h |
#ifndef __BEACONS_H__
#define __BEACONS_H__
#include "protocol.h"
#define BEACON_ARRAY_MAX_SIZE 8
mBeacon received_beacons[BEACON_ARRAY_MAX_SIZE];
// Empty received_beacons
void empty_received_beacons();
// Return number of non-empty beacons stored in received_beacons
int number_of_beacons();
// Return 1 (true) if b1 == b2, 0 (false) otherwise
int compare_beacon(mBeacon b1, mBeacon b2);
// Return 1 (true) if beacon is empty, 0 (false) otherwise
int is_empty_beacon(mBeacon b);
// Print a given beacon
void print_beacon(mBeacon b);
// Return 1 (true) if beacon successfully stored, 0 (false) otherwise
int save_beacon(mBeacon b);
// Return an incoming beacon, empty beacon otherwise
mBeacon receive_beacon();
// Send a given beacon
void send_beacon(mBeacon b);
#endif
|
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 (flagFBEACON
) 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
- La page commune du projet capteurs 2011
- La documentation utilisateur du MSP430
- Le TP de Thomas Watteyne