User Tools

Site Tools


digispark:tutorials:nrfmesh

This is an old revision of the document!


nRF Mesh Network Example

Requirements:

3x or more Digispark Pros 3x or more Pro nRF Shields (may also work with original Digisparks wired to nRF modules)

Theory:

This example implements a simple, easy to understand and change, Mesh network layer over the RF24 library. The goal of this is to be lightweight for relatively small meshes, and relatively easy to set up. While a more complex mesh layer might allow for ad hoc additions to the network - for simplicity this requires the total number of nodes (or max number at least - they don't all have to be on) to be known. That is all - addressing is automatic as long as you change the NODE_ADDRESS to be unique for each node.

Note: NODE_ADDRESS is 0 indexed so your first node is 0 NOT 1

Data Structure

For simplicity this implements a data structure in the RF24 payload. That structure is defined in the example as:

struct 
{
 char toAddress;
 char fromAddress;
 char fromSequence;
 long data;
} msg;

So each message contains the address of its final destination, the address of who sent it, the sequence number of the sender (more on this later), and the data itself (set to be a long).

You can change the type or length of the data - just make sure you do so on all nodes.

Repeating without looping forever

This mesh layer expects any node the receives a message (they all listen for any message by listening all on the same channel) to re-transmit the message if that node was not the node in the toAddress. In order to ensure that a node doesn't keep re-transmitting a message endlessly we could use some sort of ACK system (complex) or more simply (but less robust) we can record the last message we repeated based on the from address and not repeat it again - which is what we do here.

Each node stores an array of sequence numbers - one for each node - when it repeats a number it sets the sequence for that node to the sequence of that message and does not repeat again any message from the same node with a sequence number lower than that. This ensures that it only repeats a message once and also doesn't repeat a message older than the last one it repeated from a given node.

This results in as many duplicates of the message as there are nodes if the nodes are all close to each other (each message would be duplicated once by each node) - but if they are say in a line where each node is just in range of the one in front and behind it then we end up with no more than are necessary to get to the destination.

This mesh layer also implements a broadcast address at 255 so if you do sendToMesh(255, analogRead(A5)); all nodes that receive the message will repeat it and read it! (This of a mesh of motion detectors with alarms - if one detects motion it sends a message on broadcast to all nodes to turn on their alarms).

The Mesh Functions:

These two main functions are well commented and cover most of how this works on the code level:

void sendToMesh(uint8_t toAddress, long data){
  if(sequence[NODE_ADDRESS]<255)
    sequence[NODE_ADDRESS]++; //increment sequence count for this device
  else
    sequence[NODE_ADDRESS] = 0; //set to zero if last was 255 so we don't overflow - logic for read is built to handle this too
    
  msg.toAddress = toAddress; //set the address of the destination node
  msg.fromAddress = NODE_ADDRESS; //set the from as this node - of course
  msg.fromSequence = sequence[NODE_ADDRESS]; //set it to the sequence number we just implemented which should be greater than any the nodes have received 
  radio.stopListening(); //turn of recv so we can transmit
  radio.write(&msg, sizeof(msg));
  radio.startListening(); //turn recv back on
}
bool readAndRepeat(){
  if(radio.read(&msg, sizeof(msg))){ //if we have incoming data
    if(msg.fromAddress!=NODE_ADDRESS){ //make sure this node didn't send it
      if(sequence[msg.fromAddress] < msg.fromSequence || (sequence[msg.fromAddress] == 255 && msg.fromSequence == 0)){ //make sure we haven't already repeated it or received it
          //increment sequence for that address so we don't repeat it twice from this node or receive it twice
          sequence[msg.fromAddress] = msg.fromSequence;
          if(msg.toAddress==NODE_ADDRESS){ //is it for this node? if so return true so we can use it!
            return true;
          }
          //otherwise repeat it - send it back out
          radio.write(&msg, sizeof(msg));
          if(msg.toAddress == 255){ //it was a broadcast so return true so we do something with it
            return true;
          }
      }
    }
  }
  return false;
}

Topography:

This mesh layer


digispark/tutorials/nrfmesh.1421128812.txt.gz · Last modified: 2015/01/12 22:00 by digistump