TP1

Communication entre deux nœuds DW1001 avec le code Ranger

I. Introduction

Ce TP se focalise sur la communication entre deux nœuds DW1001 grâce à la bibliothèque Ranger.

Objectifs du TP

Le but de ce TP est de vous familiariser avec l’utilisation de la bibliothèque Ranger pour rĂ©aliser des communications Ă  courte portĂ©e en utilisant la technologie UWB (Ultra-Wideband). Vous serez amenĂ© Ă  utiliser les modules DecaDuino pour Ă©tablir des communications entre diffĂ©rents nĹ“uds et mesurer les distances entre eux.

Matériel Utilisé

  • Un ordinateur avec une connexion internet
  • Des nĹ“uds DWM1001 disponibles sur la plateforme LOCURA4IoT

II. Présentation du Matériel et des Bibliothèques

Les Cartes DW1001

Les cartes DW1001 sont des cartes sans fil basées sur la technologie UWB (Ultra Wideband), qui permet de mesurer avec précision les distances entre les différents nœuds.

dwm1001

La Technologie UWB (Ultra-Wideband)

a. Concepts de base de l’UWB

Dans cette section, nous explorerons les concepts fondamentaux de la technologie UWB, qui joue un rôle clé dans les communications sans fil et la localisation précise.

  • Principes de fonctionnement : L’UWB utilise des impulsions brèves et Ă©nergĂ©tiques pour transmettre des donnĂ©es sur une large gamme de frĂ©quences.
  • Avantages en communication : L’UWB offre une haute rĂ©solution en distance, une faible consommation d’Ă©nergie et une immunitĂ© aux interfĂ©rences.
b. Protocoles UWB

Dans cette partie, nous aborderons les protocoles UWB qui déterminent comment les nœuds communiquent et mesurent les distances. Notre focus sera sur le protocole Two-Way Ranging (TWR).

  • PrĂ©sentation du Two-Way Ranging (TWR) : Le TWR permet des mesures prĂ©cises de distance en utilisant des Ă©changes bidirectionnels et des mesures de temps de vol.
  • Utilisation du TWR avec les nĹ“uds DW1001 : Les nĹ“uds DWM1001 exploitent la puissance du TWR pour la localisation prĂ©cise et la communication fiable Ă  courte portĂ©e.

Bibliothèque Ranger

La bibliothèque Ranger est une bibliothèque logicielle spécialement conçue pour simplifier la communication UWB en utilisant les modules DecaDuino. Elle est conçue pour configurer les modules, établir des communications et effectuer des mesures de distances.

III. Configuration de l’Environnement de DĂ©veloppement

PrĂ©paration de l’Environnement Arduino IDE

Pour commencer, nous devons configurer l’environnement de dĂ©veloppement Arduino IDE pour travailler avec les nĹ“uds DW1001. Suivez ces Ă©tapes :

  • TĂ©lĂ©charger et installer l’IDE Arduino sur votre ordinateur, si ce n’est pas dĂ©jĂ  fait. L’IDE Arduino est disponible gratuitement sur le site officiel d’Arduino.

Installez la chaîne de compilation en suivant les instructions sur cette page.

Installation des Bibliothèques Requises

Pour pouvoir flacher le code Ranger sur les nœuds DW1001, nous devons installer les bibliothèques nécessaires. Suivez ces étapes :

  • TĂ©lĂ©chargez le fichier ranger_dependencies.zip.
  • Extrayez son contenu dans le dossiez “libraries” de votre installation Arduino
    • Astuce : vous trouverez le chemin oĂą se situe de ce dossier dans l’IDE Arduino : PrĂ©fĂ©rences > Emplacement du carnet de croquis
    • Note : il faut que les dossiers suivants se retrouvent directement dans le dossier “libraries”
      • base64
      • DecaDuino
      • Ranger
      • DWM100x_id/
      • printfserial

Ces bibliothèques fournissent les fonctionnalités nécessaires pour la communication UWB avec les nœuds DW1001.

Configuration de la Carte DW1001

Maintenant que les bibliothèques sont installées, nous devons configurer Arduino IDE pour reconnaître la carte DW1001. Suivez ces étapes :

  • Allez dans le menu “Outils” (Tools).
  • SĂ©lectionnez “Type de carte” (Board) et choisissez “DecaWave DWM1001 Module Development Board”.

IV. Téléversement du Code sur les Nœuds DW1001

Maintenant que l’environnement de dĂ©veloppement est configurĂ©, vous pouvez tĂ©lĂ©verser le code Ranger sur les nĹ“uds DW1001. Voici comment procĂ©der :

  1. Ouvrez le fichier > Exemples > ranger > minimalRangerExample dans Arduino IDE.
Cliquez pour afficher le code complet
// minimalRangerExample
// This sketch shows the bare minimum required to use the Ranger library to perform distance measurements using
// the TWR ranging protocol over the UWB radio on a DWM1001-DEV board.
// by Cassandre Vey <cassandre.vey@irit.fr>
// This sketch is a part of the Ranger Project - please refer to the Ranger LICENCE file for licensing details

// Use the following parameters to set ranging cycle (period), client address and server address.
#define CLIENT_RANGING_PERIOD 1000 //ms. Client performs a ranging cycle every x ms
#define CLIENT_ADDRESS 0x8C30 // client/mobile/initiator address
#define SERVER_ADDRESS 0xA55E // server/anchor/target address

#include <DecaDuino.h>
#include <Ranger.h>
#include <DWM100x_id.h>
#include <printfToSerial.h>

DecaDuino decaduino(SS1, DW_IRQ);

uint8_t txData[1024];
uint8_t rxData[1024];
uint8_t sqn = 0;
uint16_t rxLen;
uint16_t nodeAddress = 0;
uint32_t prevSoftwareInterrupt = 0;
uint32_t rangingPeriod;

Ranger ranger;
Ranger::RangingRequestStatus_e rangingStatus;
Ranger::ranging_t ranging;
Ranger::message_t txMsg, rxMsg;

// Performs the actual message sending
void prepareAndSendMessage(Ranger::message_t *txmsg) {
    int i, l = 0;

    // create a simple L2 header :
    //    sender address,
    //    destination address,
    //    sequence number,
    //    protocol
    decaduino.plmeRxDisableRequest();
    decaduino.encodeUint16(nodeAddress, &txData[l]);
    l += 2;
    decaduino.encodeUint16(txMsg.destination, &txData[l]);
    l += 2;
    txData[l++] = ++sqn;
    txData[l++] = txMsg.protocol;
    // adds the ranging payload
    for ( i = 0 ; i < txMsg.payloadLen ; i++ ) {
        txData[l + i] = txMsg.payload[i];
    }
    // actual sending
    decaduino.pdDataRequest(txData, l + i);
    // wait until the transmission is successful
    while ( !decaduino.hasTxSucceeded() ) {
        decaduino.engine();
    };
    // record transmission timestamp
    txMsg.tsTx = decaduino.getLastTxTimestamp();
}

// This function is the glue-code between Decaduino and Ranger.
// It translates the requests from ranger in actions by Decaduino and notifies the
// ranger state machine when appropriate
void processHal()
{
    // Is there a message to send?
    if ( ranger.getTxBufferStatus() ) {
        // A new message has to be sent.
        // Warning : RX is not re-enabled after message is sent.
        prepareAndSendMessage( &txMsg);
        // notify ranger that the transmission is done
        ranger.setTxBufferStatus(Ranger::TX_STATUS_DONE);
    }

    // Enable RX?
    if ( ranger.getRxRequestStatus() ) {
        rxMsg.trxTemperatureBegin = decaduino.getTemperature();
        decaduino.plmeRxEnableRequest();
        // clears the RX enable request
        ranger.rxEnableRequest(false);
    }

    // Has a message been received?
    if ( decaduino.rxFrameAvailable() ) {
        // A new message has been received: analyse-it
        // simple L2 header decoding
        uint16_t sourceAddress = decaduino.decodeUint16( &rxData[0]);
        uint16_t destinationAddress = decaduino.decodeUint16( &rxData[2]);
        uint8_t sqn = rxData[4];
        uint8_t msgType = rxData[5];

        // destination address filtering
        if ( (destinationAddress == nodeAddress) || (destinationAddress == 0xffff) ) {
            // record the metadata of the packet
            rxMsg.source = sourceAddress;
            rxMsg.destination = destinationAddress;
            rxMsg.tsRx = decaduino.getLastRxTimestamp();
            rxMsg.skew = decaduino.getLastRxSkew();
            rxMsg.protocol = (Ranger::protocols_e)msgType;
            // record the ranging payload
            for ( int i = 0 ; i < rxLen ; i++ ) {
                rxMsg.payload[i] = rxData[6 + i];
            }

            // if protocol is TWR, notify ranger
            if ( rxMsg.protocol == Ranger::PROTOCOL_TWR ) {
                ranger.newRxMessage();
            }
            // otherwise re-enable reception
            else {
                decaduino.plmeRxEnableRequest();
            }
        }
        else {
            // This message is not for this node. Re-enable RX
            decaduino.plmeRxEnableRequest();
        }
    }
}

void setup() {
    Serial.begin(115200);
    delay(500);

    nodeAddress = getIotlabID();
    printf("My nodeAddress is %x\n", nodeAddress);

    // check configuration
    while ( (nodeAddress != CLIENT_ADDRESS && nodeAddress != SERVER_ADDRESS) || !CLIENT_ADDRESS || !SERVER_ADDRESS ) {
        printf("My nodeAddress is %x and is neither client nor server, or these are not properly defined (must be non-zero)\n", nodeAddress);
        delay(1000);
    }

    while ( !decaduino.init() ) {
        Serial.println("DecaDuino init failed... retry...");
        delay(100);
    }

    while ( !ranger.init() ) {
        Serial.println("Ranger init failed... retry...");
        delay(100);
    }

    // Configure DecaDuino
    decaduino.setRxBuffer(rxData, &rxLen);

    // Configure Ranger
    ranger.setTxBuffer( &txMsg);
    ranger.setRxBuffer( &rxMsg);
    ranger.setNodeAddress(nodeAddress);
    ranger.enableTwrServer(true);

    // Various
    if ( (nodeAddress == CLIENT_ADDRESS) ) {
        rangingPeriod = CLIENT_RANGING_PERIOD;
    }
    prevSoftwareInterrupt = millis();
}

void loop() {
    // Process incoming/outgoing messages
    processHal();

    // Call the Decaduino Engine (must be called regularly)
    decaduino.engine();

    // Call the Ranger Engine (must be called regularly)
    ranger.engine();

    // Periodic action
    if ( rangingPeriod && (millis() - prevSoftwareInterrupt) > rangingPeriod ) {
        prevSoftwareInterrupt = millis();
        ranger.rangingRequest(SERVER_ADDRESS, Ranger::PROTOCOL_TWR, RANGING_UNIT, &ranging);
    }

    // Handle result at the end of the ranging
    if ( ranger.rangingIndication( &rangingStatus) ) {
        switch ( rangingStatus ) {
            case Ranger::RANGING_STATUS_ERROR :
                printf("Error while ranging with %d\n", ranging.other);
                break;

            case Ranger::RANGING_STATUS_DONE :
                printf("Result for this ranging with %04x:\n", ranging.other);
                ranger.printRangingMinimumAsJson( &ranging);
                printf("\r\n");
                Serial.flush();
                break;

            default :
                break;
        }
    }
}

Ce code est conçu pour utiliser la bibliothèque Ranger et permettre la communication entre nœuds DW1001 en utilisant le protocole Two-Way Ranging (TWR) sur la radio UWB.

Voici un résumé des points clés de ce code :

  • Le code est conçu pour ĂŞtre exĂ©cutĂ© sur un nĹ“ud DW1001 configurĂ© en tant que serveur TWR (ranger.enableTwrServer(true);).

  • Il est destinĂ© Ă  ĂŞtre utilisĂ© avec un client dont l’adresse est dĂ©finie par CLIENT_ADDRESS.

  • L’ancre (serveur) est dĂ©finie par SERVER_ADDRESS.

Assurez-vous que toutes les configurations spĂ©cifiques Ă  votre environnement telle que l’adresse du client, les adresses des nĹ“uds, les dĂ©lais, etc.

#define CLIENT_ADDRESS 0x0D81 // adresse du noeud dwm1001-1.toulouse.iot-lab.info (mobile/client)
#define SERVER_ADDRESS        // adresse du noeud dwm1001-2.toulouse.iot-lab.info (ancre/serveur)

Flasher le code sur la carte DWM1001

  1. Connectez vous sur IoT-Lab Fit.
  2. Créer une nouvelle expérience sur IoT-Lab Fit et sélectionner les nœuds sur lesquels vous souhaitez flasher le code.

Remarque : Vous pouvez choisir les nœuds en fonction de leur emplacement, de leur disponibilité et des besoins de votre projet.

  1. SĂ©lectionnez l’icĂ´ne de tĂ©lĂ©versement et spĂ©cifiez le chemin d’accès vers le fichier elf gĂ©nĂ©rĂ© lors de la compilation du code Blink avec l’IDE Arduino, Ă  partir de l’emplacement suivant : \Users\username\AppData\Local\Temp\arduino_build\ . Vous devrez modifier le nom du fichier en supprimant “.ino” pour qu’il soit acceptĂ©.

  2. Les nœuds DW1001 devraient maintenant exécuter le code.

  3. Une fois que vous avez rĂ©ussi Ă  tĂ©lĂ©verser et Ă  exĂ©cuter le code sur la plateforme Fit Lab et Ă  observer la communication entre les nĹ“uds DW1001, On peut visualiser ces messages il suffit de vous connecter sur le serveur toulouse.iot-lab.info avec votre nom d’utilisateur et votre mot de passe, en entrant la commande suivante iotlab-auth -u username. Ensuite, vous pouvez taper la commande serial_aggregator pour afficher les messages.

image
Le résultat affiché dans le Serial Aggregator représente les données de communication entre les nœuds DW1001 lors de l'exécution du code Ranger. Voici une explication des informations fournies dans ces données :
  • Les lignes, comme dwm1001-5;My nodeAddress is 52332, indiquent le nĹ“ud Ă©metteur et son adresse. Par exemple, “dwm1001-5” est le nĹ“ud Ă©metteur avec l’adresse “52332”, et “dwm1001-6” est le nĹ“ud destinataire avec l’adresse “3457”.

  • Les donnĂ©es suivantes sont au format JSON et contiennent des informations sur la communication entre les nĹ“uds. Ces informations sont divisĂ©es en plusieurs catĂ©gories :
    “initiator” et “target” indiquent respectivement le nĹ“ud Ă©metteur et le nĹ“ud destinataire.

  • “protocol” spĂ©cifie le protocole utilisĂ©, ici “TWR” pour Two-Way Ranging.

  • Les valeurs comme “t1”, “t2”, “t3” et “t4” reprĂ©sentent les temps de vol mesurĂ©s entre les nĹ“uds.

  • “skew”, “skewRequest”, “skewAck” et “skewData” sont des valeurs de synchronisation entre les nĹ“uds.

  • “nlosIndicator” donne un indicateur sur la visibilitĂ© directe entre les nĹ“uds.

  • “tof” reprĂ©sente le temps de vol total.

  • “range” est la distance mesurĂ©e entre les nĹ“uds.

  • “rssiRequest”, “rssiData” et “rssiAck” sont les niveaux de puissance du signal dans diffĂ©rentes phases de la communication.

  • Les autres valeurs telles que “fp_powerRequest”, “fp_powerAck”, “fp_powerData”, “pa_powerRequest”, “pa_powerAck”, “pa_powerData”, “voltage”, “temperature”, et “distantTemperature” sont des donnĂ©es supplĂ©mentaires liĂ©es Ă  la communication.

Ces informations permettent de suivre la communication entre les nĹ“uds DW1001, de mesurer les distances et d’Ă©valuer la qualitĂ© de la communication en termes de synchronisation, de force de signal, etc.