TP F2R101D Sensors Network

De Le wiki des TPs RSM

L'objectif de ce TP est d'expérimenter les interfaces d'accès aux capteurs comme le bouton et le capteur de luminosité, ainsi que la librairie réseau uIP permettant des communications en IPv6 entre les motes.


Accès à l'interface Bouton

Objectif et structure du programme

L'objectif de ce programme est de contrôler la LED du mote à partir de son bouton. L'interface Bouton de Contiki génère à chaque appui un événement pouvant réveiller un processus, de la même façon qu'un timer.

Le programme reprendra la structure du dernier programme du précédent TP :

  • Un processus se réveillant sur l'événement Bouton.
  • Un processus changeant l'état de la LED sur le signal PROCESS_EVENT_CONTINUE envoyé par le premier processus.
Question.jpg
Quel est l'avantage de séparer le contrôle de la LED en 2 processus ?




Références utiles

Le bouton est considéré par Contiki comme un capteur (sensor). Le processus souhaitant réagir aux événements Bouton doit d'abord initialiser ce capteur :

 SENSORS_ACTIVATE(button_sensor)

Le processus recevra alors des événements de type sensors_event. Les données associées à l'événements permettent de déterminer de quel capteur il s'agit. Le code ci-dessous montre une utilisation minimal de l'interface Bouton.

#include "dev/button-sensor.h"

PROCESS_THREAD (p, ev, data) {

   PROCESS_BEGIN();
   SENSORS_ACTIVATE(button_sensor);

   while(1) {
     PROCESS_YIELD();
     if (ev == sensors_event && data == &button_sensor) {
       printf("Button pressed!\n");
     }
  }
  PROCESS_END();
}
Question.jpg
Quel est le sens de la fonction PROCESS_YIELD() ?




L'interface LED a été décrite lors du premier TP.

Red arrow.png Ecrivez le programme selon les indications données à partir du code du précédent TP et des fonctions données en référence

Tests

Red arrow.png Exécutez ce programme dans le simulateur Cooja. Le bouton du mote est accessible depuis le menu Tools/Mote Interface Viewer puis Button dans la liste déroulante.

Utilisation du réseau

Objectif et structure du programme

L'objectif de ce programme est identique au programme précédent : contrôler une LED depuis le bouton d'un mote. Or il s'agit ici de contrôler la LED d'un mote depuis le bouton d'un autre mote. Le réseau sera utilisé pour transmettre le signal permettant le basculement de la LED.

Chaque mote exécutera un processus similaire à chacun des processus du programme précédent. La signalisation entre les deux processus s'effectuera cette fois-ci par le réseau. Les communications se feront via la pile uIP en utilisant le protocole IPv6.

Références utiles

L'utilisation de la librairie uIP impose l'inclusion des fichiers suivants :

#include "net/uip.h"
#include "net/uip-ds6.h"
#include "simple-udp.h"

Le Makefile devra être modifié lui aussi pour inclure les lignes suivantes au début du fichier :

WITH_UIP6=1
UIP_CONF_IPV6=1

Chaque fois que vous modifiez le fichier Makefile, une recompilation complète est nécessaire (Clean).

Gestion des adresses

Dans la librairie uIP, les adresses se manipulent grâce au type uip_ipaddr_t. L'appel à la fonction uip_ip6addr permet de spécifier une adresse IPv6 à partir d'une écriture sous forme de nombre :

static uip_ipaddr_t server_addr;

uip_ip6addr(&server_addr, 0xfe80, 0, 0, 0, 0, 0, 0, 1);

Dans ce cas précis, la variable server_addr est fixée à l'adresse IPv6 fe80::1.


Une variable de ce type peut servir à désigner le destinataire d'une connexion, ainsi que pour spécifier l'adresse pour une interface. Cette dernière opération s'effectue par l'appel suivant :

 uip_ds6_addr_add(&server_addr, 0, ADDR_MANUAL);

La constante ADDR_MANUAL sert à spécifier que cette adresse a été définie manuellement, pour la différencier des adresses auto-configurée.

Question.jpg
Dans quel cas aurez-vous besoin de spécifier une adresse manuellement pour écrire votre programme ?




Gestion des connexions

La librairie réseau uIP est assez complexe à mettre en oeuvre. Heureusement, il existe une interface simplifiée Simple UDP que vous allez mettre ici en oeuvre. La documentation de cette interface est disponible sur cette page.

Les appels à cette librairie spécifie la connexion à travers une variable de type simple_udp_connection

static struct simple_udp_connection current_connection;

L'initialisation de la connexion s'effectue par l'appel à la fonction simple_udp_register :

simple_udp_register(&current_connection,   // Connection to be initialized
                    1234, // Source Port
                    NULL, // Dest. Address
                    1234, // Dest. Port
                    handler); // Handler for receive packets

En fixant la valeur de l'adresse du destinataire à NULL, cette connexion nécessite de spécifier l'adresse à chaque envoi de paquet.

handler est une fonction qui sera appelée à chaque fois qu'un paquet sera reçu sur cette connexion. La fonction doit suivre le prototype suivant :

static void
handler(struct simple_udp_connection *c,
         const uip_ipaddr_t *sender_addr,
         uint16_t sender_port,
         const uip_ipaddr_t *receiver_addr,
         uint16_t receiver_port,
         const uint8_t *data,
         uint16_t datalen)

Au sein de cette fonction doit être écrit le traitement individuel d'un paquet reçu.

L'envoi de donnée sur le réseau s'effectue par les appels :

simple_udp_send(&current_connection, "Test", 4);  

ou

simple_udp_sendto(&current_connection, "Test", 4, &server_addr);

selon que l'adresse du destinataire a été fixée lors de l'appel simple_udp_register

Red arrow.png écrivez les 2 programmes pour chacun des motes selon les objectifs donnés et les exemples donnés en référence.

Tests

Red arrow.png compilez le programme et exécutez le dans l'environnement Cooja.

Attention.png Un nettoyage des fichiers de compilation du système Contiki (par le bouton clean) est nécessaire pour qu'il soit recompilé en prenant en compte la librairie uIP.

Red arrow.png Créer 2 motes avec chacun des programmes, et demandez à afficher le trafic réseau dans l'interface de visualisation des motes. Observez le résultat de la simulation

Vous allez maintenant tester ce programme sur des motes physiques. Vous avez sur votre table 2 types de motes. Voici le schéma des composants d'un mote.

Moteiv.jpg

L'une des motes à votre disposition possède des capteurs. Ce sera le mote qui va générer le signal pour contrôler la LED. L'autre mote ne contient pas de capteur. Celui-ci exécutera le programme pour recevoir le signal et contrôler la LED.

Red arrow.png Repérez chaque mote selon sa fonction

Pour compiler et télécharger le programme sur la mote, il faut d'abord la connecter en USB au poste, puis ensuite d'activer ce nouveau périphérique dans la machine virtuelle.

La compilation demande d'être placé en ligne de commande dans le répertoire contenant le code du programme et d'exécuter la commande suivante :

make TARGET=sky <programme>
make TARGET=sky <programme>.upload

Red arrow.png Connecter et activer tour à tour chaque mote sur la machine virtuelle, puis télécharger le code correspondant.

Red arrow.png Brancher le mote sans capteur sur le côté de l'écran, l'autre mote sur la façade du PC, et valider le bon fonctionnement du programme.

Note: le bouton d'action est celui le plus proche de la prise USB. L'autre bouton sert à la ré-initialisation du mote. Un reset est peut être nécessaire pour que les motes communiquent.

Accès au capteur de luminosité

Objectif et structure du programme

L'objectif de ce programme est toujours de contrôler une LED, mais cette fois ci à travers le capteur de luminosité plutôt qu'à travers le bouton. Ce capteur va permettre de reconnaitre si une main est placée au dessus ou non du capteur. Le code du mote récepteur reste donc inchangé. Par contre celui du mote générant le signal sera modifié pour ajouter la prise en compte du capteur de luminosité, tout en gardant l'action à partir du bouton.

La lecture de la valeur du capteur de luminosité se fera dans un processus séparé de celui qui effectue pour l'instant l'envoi d'un message sur appui d'un bouton. Dans le cas où le capteur détecte un changement de luminosité, il donnera la main à ce premier processus. La lecture de la valeur du capteur se fera de manière régulière (tous les 250ms).

Question.jpg
Quels mécanismes de Contiki déjà rencontrés allez-vous mettre en oeuvre dans ce processus ?




La détection du changement de luminosité se basera sur la détermination d'un seuil. Celui ci indiquera si la valeur mesurée est inférieure ou supérieure au seuil que le capteur est recouvert ou non.

Références utiles

Le capteur de luminosité ne génère pas d'événement de lui même. Une fois initialisé dans un processus, le capteur permet de lire dans une variable la valeur courante mesurée.

#include "dev/light-sensor.h"
...
SENSORS_ACTIVATE(light_sensor) // Activation du capteur
...
value = light_sensor.value(0); // Lecture de la valeur
...

Tests

Red arrow.png Ecrivez tout d'abord un programme simple, permettant d'afficher sur la sortie standard (printf) les valeurs mesurées par le capteur de luminosité.

Sur un mote physique connecté en USB, vous pouvez afficher les messages générés sur la sortie standard grâce à la commande suivante, exécutez depuis le répertoire contenant le code :

make TARGET=sky login

Red arrow.png déterminez à partir de ce programme le seuil à utiliser dans vos conditions.

Red arrow.png Modifiez le code du programme précédent afin de contrôler la LED grâce au capteur de luminosité.

Outils personnels