Affichage des articles dont le libellé est xbee. Afficher tous les articles
Affichage des articles dont le libellé est xbee. Afficher tous les articles


Arduino : XBee Ethernet data logger

Après plusieurs semaines de galère, j'ai décidé de rassembler ici tous les éléments qui m'ont permis, tant bien que mal, de mettre en place l'installation suivante :

D'un côté, un module XBee transmettant les informations d'un capteur de température (LM35). De l'autre, un second XBee relié à un Seeduino ATMega 2560 (similaire à un Arduino) qui enregistre toutes les mesures reçues sur une carte SD et expose le fichier créé via une connexion Ethernet. Voici le schéma du montage :

Avant d'aller plus loin, il est indispensable de faire un point sur la notion de SPI afin de comprendre le fonctionnement de notre montage.

SPI est un bus de communication basé sur les principes de Maitre et Esclave. Il est composé de 4 canaux. Pour ne pas plagier un très bon cours existant sur le site rocketnumbernine, voici en quelques mots son fonctionnement :

Each end of a SPI connection is acting in one of two roles - Master or Slave. The master is responsible for initiating and controlling the communication.

SPI Master/Slave Connections

The basic mode of operation is very simple: When the master wishes to initiate transfer of data:
  1. It sets the SS (Slave Select - often called CS - chip select) pin low to tell the slave that communication is about to start
  2. The master writes a bit of information onto the MOSI (Master Out Slave In) wire (sets it to 0 or 1) and the slave does the same on the MISO wire (either of these can be omitted if the data transfer is one way)
  3. As the master ticks the clock line SCLK it will read the value of MISO (Master In Slave Out) wire (which the Slave has written) and the slave will read the value of the MOSI wire (whether the data is sampled as the clock rises or falls depends on which mode is in operation)
  4. The process is repeated from (b), transferring a bit of data on each pulse of the clock until all data is transferred

Ce bus SPI est accessible via les broches ICSP (Arduino UNO et Mega 2560) ET les broches 11,12,13 (pour le UNO) ou 50,51,52 (pour le Mega 2560).

Un élément important est le Chip Select : il s'agit de la broche qui permet de choisir le périphérique cible de l'échange. Pour désactiver un périphérique, il faut passer la broche en niveau haut et pour l'activer, en niveau bas. Un seul périphérique ne peut être activé à la fois car les trois broches de communication MOSI, MISO et SCK sont partagées.

Sur l'Arduino UNO (Revision 3), le Mega 2560 (Rev 3) et sur le shield Ethernet (Rev 3), on trouve le CS :

  • sur la broche A4 pour la carte SD
  • sur la broche A10 pour l'Ethernet

C'est grâce à cette correspondance des broches qu'il est possible de simplement empiler les cartes sans avoir à faire de connexions supplémentaires. Il est tout de même possible, si vous ne souhaitez pas empiler les cartes, de relier les broches comme indiqué sur le schéma. Attention cependant, ceci est impossible sur le shield Ethernet car seules les broches CS sont utilisées et reliées directement à l'ICSP. Toutes les autres broches ne servent qu'à transférer les connexions à une éventuelle autre carte supperposée.

Revenons donc à notre projet. La carte Ethernet est apposée sur l'ATMega 2560, le module XBee principal (coordinateur) relié directement au Serial1 : broches RX1 et TX1 (croisées avec les RX/TX du XBee).

Côté logiciel maintenant : l'application doit, au démarrage, aller lire un fichier de configuration sur la carte SD et initialiser une connexion Ethernet. Pour bien démarrer, voici le code de la fonction setup() :


void setup() {
 pinMode(10, OUTPUT);
 pinMode(4, OUTPUT);
 // 
 pinMode(53, OUTPUT);
 digitalWrite(53, HIGH);
 /* disable all slaves */
 // disable Ethernet
 digitalWrite(10, HIGH);
 delay(5);
 // disable SD
 digitalWrite(4, HIGH);
 delay(5);

 /* read config file */
 // init SD
 boolean sd = SD.begin(4);
 delay(5);
 // ... read file ...
 // disable SD
 digitalWrite(4, HIGH);
 delay(5);
}

A noter qu'il est très important de désactiver à la main l'Ethernet après son initialisation car la librairie ne le fait pas! Sur un ATMega 2560, il faut également obligatoirement définir la broche de Hardware SS (53) en sortie.

Ensuite, afin que le programme puisse à la fois recevoir en continu des paquets de données XBee à écrire sur la carte SD et assurer son rôle de serveur web, voici, sous forme algorithmique, le déroulement du code à mettre en place :

void loop() {
 - Vérifier la présence d'un packet XBee
  - si un paquet a été reçu :
   - traiter les informations du paquet 
   - désactiver l'Ethernet : digitalWrite(10, HIGH)
   - activer la carte SD : digitalWrite(4, LOW)
   - écrire sur la carte SD
   - désactiver la carte SD : digitalWrite(4, HIGH)
 - Vérifier la réception d'une requete Ethernet :
  - si une requete a été reçue :
   - désactiver la carte SD : digitalWrite(4, HIGH)
   - activer l'Ethernet : digitalWrite(10, LOW)
   - générer la réponse HTTP
   - fermer la connexion client
   - désactiver l'Ethernet : digitalWrite(10, HIGH)
}

Normalement, la gestion de l'activation/désactivation de chaque périphérique SD ou Ethernet est gérée en interne par les librairies correspondantes, mais je vous conseille de ne pas hésiter à le faire également manuellement afin de renforcer votre programme (on n'est jamais mieux servi que par soi-même!).

Un conseil supplémentaire : il est préférable d'ajouter quelques délais après chaque dés/activation de périphérique (via la méthode delay()), au moins pendant la phase de développement, afin d'éviter tout conflit de communication sur le bus SPI (par les broches partagées) qui pourrait engendrer, par exemple, la destruction de la carte SD (qui arrive plus vite qu'on ne le croit!).

Ci-dessous sont décrites les erreurs les plus communes qui peuvent être rencontrées :

  • Impossible de démarrer la carte SD :
    Si SD.begin() renvoie false, il faut dans un premier temps vérifier les connexions SPI (MOSI, MISO) dans le cas où elles auraient été réalisées autrement que par les broches ICSP et dans un second temps s'assurer que seule sa broche CS est active.
  • Impossible de PING la carte Ethernet :
    Les requêtes ping répondent "Impossible de joindre l'hôte" ("Host unreachable") et la LED TX de la carte ne s'allume jamais : vérifier également que seule la broche CS de la carte Ethernet est active et qu'aucun autre périphérique ne tente d'accéder au bus SPI.

Vous voilà prêts! J'ai essayé de regrouper ici les connaissances de base dont j'ai eu besoin et pour lesquelles j'ai du écumer nombre de blogs et forums. J'espère que tout cela vous sera utile!


Fichier(s) joint(s) :



Xbee sans Arduino

Comme vous l'aurez remarqué dans mon article précédent, je me lance dans les montages électroniques, basés sur la platine Arduino et tout son écosystème.

Aujourd'hui je vous propose d'aller plus loin : nous allons voir comment établir une communication sans fil grâce aux modules radio Xbee. Le projet ici est de recevoir sur PC les mesures d'un capteur de température distant.

Matériel nécessaire


Module Xbee
Série 2 (x2)
Carte interface Adaptateur USB-miniUSB

Mon petit conseil pour l'achat de tout ceci est de commander sur le site Matlog : un revendeur français très bien équipé garantissant une livraison rapide.

Vous aurez également besoin du logiciel de configuration X-CTU fourni par Digi, fabricant des modules Xbee et d'un petit capteur de température (LM35 ici).

Principes

Les modules XBee permettent de créer des réseaux, du plus simple au plus complexe, Peer-to-peer ou maillé. Pour ce faire, ils peuvent être configurés pour jouer différents rôles : endpoint, routeur ou coordinateur (voici une bonne explication des différents rôles). Dans notre montage, nous allons avoir besoin d'un routeur (qui fera office d'endpoint) et d'un coordinateur.

Le montage

Avant de continuer, voici un aperçu du résultat :

Comme vous le voyez sur la première image, aucun micro-contrôleur n'est nécessaire. Nos deux modules radio communiquent directement et le routeur sera programmé pour envoyer à intervalles régulier la valeur du capteur de température. Le coordinateur est relié au PC directement via un câble USB et identifié par une petite pastille (par commodité). La seconde image montre en détail le montage : le fil blanc permet d'indiquer au module la valeur de référence du courant utilisé, afin qu'il puisse nous donner une valeur relative cohérente du signal reçu sur la broche 20 (première broche analogique du Xbee, fil rouge à droite). Le reste du câblage n'est que de l'alimentation par la pile 9V.

Configuration

L'étape la plus complexe. Nous allons voir comment attribuer chaque rôle aux modules et leur permettre de communiquer entre eux. Les XBee étant des modems radio, ils répondent à des commandes normalisées commençant par "AT". Je ne vais cependant pas m'étendre sur ce point dans cet article, mais plutôt utiliser un logiciel permettant de "masquer" ce niveau.

Commençons par le coordinateur. Une fois le premier module relié au PC, il faudra installer le driver, comme indiqué sur le site de Digi et lancer X-CTU :

Dans le permier onglet "PC Settings", il suffit de sélectionner la ligne correspondant au port COM sur lequel est branché notre XBee. Ensuite, dans l'onglet "Modem Configuration", choisir la configuration présentée : Modem XB24-ZB (pour les modules 2.4GHz Zigbee serie 2) et la dernière version du firmware. Cliquer ensuite sur Write pour envoyer cette première configuration au module.

Cliquer ensuite sur Read pour récupérer les valeurs par défaut définies par le module afin de pouvoir les ajuster à notre besoin. Pour faire simple, nous n'allons ici modifier que l'adresse du réseau (PAN ID ou ID) : n'importe quelle valeur aléatoire suffit. Cliquer de nouveau sur Write après modification pour mémoriser les changements.

Et voilà! Le point principal de notre réseau est configuré! Passons maintenant au routeur, qui va nous transmettre les informations du thermomètre. Même manipulation donc pour ce qui est du raccordement au PC et à la connexion dans X-CTU. Mais cette fois-ci, il faut indiquer la configuration suivante :

On affecte le même identifiant de réseau (ID) que le coordinateur (456) et les adresses de destination (DH et DL) correspondant à celles du coordinateur (0). La section "I/O settings" permet d'indiquer la gestion des entrées/sorties : ici nous choisissons de configurer le broche 20 (DI0) en entrée analogique (mode 2) ce qui donne DI02. Enfin, dans la sous-section "I/O sampling", nous définissons les intervalles de temps auxquels le routeur nous enverra des données : 12C en hexadécimal = 300 millisecondes.

Ensuite... Il ne reste plus qu'à rebrancher le tout! Tout devrait fonctionner. J'avoue tout de même qu'il m'a fallu pas mal d'heures de recherche pour réunir tous ces éléments. Si vous avez des soucis, n'hésitez pas à m'en parler en commentaire j'essaierai de vous aider.

Vous pouvez observer les données reçue via le Terminal de XCTU :

Je passe un peu sur l'analyse de la trame hexadécimale reçue (il y a des documents très complets sur le site de Digi à ce sujet) mais vous pouvez voir que la valeur entourée correspond à ce que nous envoie le capteur de température : D9 = 217. Selon la spécification de notre capteur LM35, pour trouver la valeur réelle de la température, il faut effectuer un calcul tout simple : 10mV par °C donc pour nous 217 / 10 = 21.7°C :D

Pour aller plus loin...

Ne nous arrêtons pas en si bon chemin! Comme vous l'avez vu, notre module capteur de température est autonome et alimenté par une pile. Même si les XBee sont assez peu énergivores, il faut tout de même rapidement penser à la gestion de l'énergie et à la réduction de leur consommation. Pour ce faire, ils disposent d'un mode veille qui augmente considérablement la durée d'utilisation des batteries.

Voici une brève description des différents modes :

  • ATSM 0 : Pas de veille
  • ATSM 1 : "pin wake mode" : la mise en veille ou le réveil sont gérées par l'alimentation ou l'extinction de la broche 9
  • ATSM 2 et 3 : réservés, non utilisables
  • ATSM 4 : Entrée et sortie de veille par intervalle de temps
  • ATSM 5 : combinaison des 1 et 4

A ceci nous allons ajouter un temps défini pendant lequel le module restera allumé avant de retourner en veille (afin de garantir la transmission des paquets).

Dans notre exemple, nous allons paramétrer une veille de 10 secondes et un temps d'attente de 1,5 seconde. Ce qui nous donne dans XCTU :

  • SM 4
  • SP 3E8 (= 1000 multiplié par 10 = 10 secondes)
  • ST 96 (= 150 multiplié par 10 = 1.5 seconde)

Et là... Il se peut que cela ne fonctionne pas! ;) En effet, à chaque sortie de veille, le routeur doit s'identifier de nouveau auprès du coordinateur (qui a considéré qu'au bout de quelques secondes de non réponse il ne faisait plus partie du réseau), ce qui prend normalement quelques secondes, impossible au vu de notre temps d'activité de 1.5 secondes. Pour y remédier, comme indiqué dans cet article, il faut modifier la configuration du coordinateur et augmenter les valeurs de SP et SN afin de couvrir les cycles de veille du routeur.

Cette fois notre matériel est prêt : nous recevons toutes les 10 secondes la température du module distant.

Et la cerise sur le gateau

Tout ceci est bien, mais il serait plus intéressant de recevoir ces informations dans un programme Java, afin de pouvoir s'en servir dans n'importe quel contexte. Pour cela, rien de plus simple : XBEE API. Quelques lignes de code plus tard :


import com.rapplogic.xbee.api.XBee;
import com.rapplogic.xbee.api.XBeeException;
import com.rapplogic.xbee.api.zigbee.ZNetRxIoSampleResponse;

public class TempRead {
 
 public static void main(String[] args) throws XBeeException {
  XBee xbee = new XBee();         
  xbee.open("COM6", 9600);
                          
  while (true) {
   ZNetRxIoSampleResponse ioSample = (ZNetRxIoSampleResponse) xbee.getResponse();
//      System.out.println("We received a sample from " + ioSample.getRemoteAddress16());     
      if (ioSample.containsAnalog()) {
          System.out.println("Temperature : " + ioSample.getAnalog0()/10.0);
      }
  }
 }

}

Ouf, enfin terminé! Avec cette API, nous sommes capables de savoir quel module nous a envoyé des données et de récupérer directement la valeur reçue sur la broche 20.

J'espère vous avoir donné assez d'éléments pour vous lancer de votre côté, bon courage!

Sources


Fichier(s) joint(s) :