RF24Network for Wireless Sensor Networking

17-Node Party

RF24Network is a network layer for Nordic nRF24L01+ radios running on Arduino-compatible hardware. It’s goal is to have an alternative to Xbee radios for communication between Arduino units. It provides a host address space and message routing for up to 6,000 nodes. The layer forms the background of a capable and scalable Wireless Sensor Network system. At the same time, it makes communication between even two nodes very simple.

Today, I managed to get 17 nodes running on a single network. Now I need to build some more nodes, because the system worked great with 17, and could likely handle thousands of nodes.

Hardware

The fastest way to get RF24Network-compatible hardware is to build the Getting Started board, or the ProtoShield board as explained in other posts, attached to commercially-available Arduino. These are used for nodes 03 and 043 in the picture above.

Ultimately, I wanted something smaller, cheaper and more power-efficient, so I built a Low Power Wireless Sensor Node. That blog post covers the V3 version of that unit, which is used by nodes 04, 011, and 021. Nodes 01 and 02 use an earlier revision, and the rest use a later version. Building them, I was surprised how almost all of them were built slightly differently. It took a ton of experimentation to figure out physically how best to package these. In the end, Node 031 is the winner, so for the upcoming V5 iteration, I’ll build 10 nodes using the PCB-mounted 2AA battery holder.

Simple Transmit/Receive

The Hello World examples illustrate how simple it is to communicate between two nodes. The receive example goes on one node, and the transmit example on the other.

There are three simple sections:

Static Initialization

First, the static setup to prepare the radio, and set the addresses. In this case, we consider ourself “Node #1”, and will communicate with “Node #0”. Of course, it’s important to get the pins right. To use the boards from the Getting Started example, you’d use pins 9 & 10.

// nRF24L01(+) radio attached using Getting Started board
RF24 radio(9,10);
 
// Network uses that radio
RF24Network network(radio);
 
// Address of our node
const uint16_t this_node = 1;
 
// Address of the other node
const uint16_t other_node = 0;
 
// How often to send 'hello world to the other unit
const unsigned long interval = 2000; //ms
 
// When did we last send?
unsigned long last_sent;
 
// How many have we sent already
unsigned long packets_sent;
 
// Structure of our payload
struct payload_t
{
  unsigned long ms;
  unsigned long counter;
};

setup()

Second, the ‘setup()’ simply prints out a quick salutation, and initializes the radio layers.

void setup(void)
{
  Serial.begin(57600);
  Serial.println("RF24Network/examples/helloworld_tx/");
 
  SPI.begin();
  radio.begin();
  network.begin(/*channel*/ 90, /*node address*/ this_node);
}

Transmitter loop()

Finally, the ‘loop()’ regularly sends a message to the other unit. Note that RF24Network requires a regular call to “update()” to process packets from the radio. It’s best to avoid calling delay() anywhere in a sketch that uses this system.

void loop(void)
{
  // Pump the network regularly
  network.update();
 
  // If it's time to send a message, send it!
  unsigned long now = millis();
  if ( now - last_sent >= interval  )
  {
    last_sent = now;
 
    Serial.print("Sending...");
    payload_t payload = { millis(), packets_sent++ };
    RF24NetworkHeader header(/*to node*/ other_node);
    bool ok = network.write(header,&payload,sizeof(payload));
    if (ok)
      Serial.println("ok.");
    else
      Serial.println("failed.");
  }
}

Receiver loop()

Also, we can look at the receiver example, which is equivalent to the transmitter sketch, with the difference of the loop(). It keeps a look out for packets, pulls them off the radio, and prints them to the console.

void loop(void)
{
  // Pump the network regularly
  network.update();
 
  // Is there anything ready for us?
  while ( network.available() )
  {
    // If so, grab it and print it out
    RF24NetworkHeader header;
    payload_t payload;
    network.read(header,&payload,sizeof(payload));
    Serial.print("Received packet #");
    Serial.print(payload.counter);
    Serial.print(" at ");
    Serial.println(payload.ms);
  }
}

Addressing in Detail

RF24Network Addressing

RF24Network works great with a few nodes, but it was designed for a house-full of nodes. Nodes are automatically configured in a tree topology, according to their node address. Nodes can only directly communicate with their parent and their children. The network will automatically send messages to the right place.

Node 00 is the ‘base’ node. Nodes 01-05 directly communicate with Node 00, but not with each other. So for Node 01 to send a message to Node 02, it will travel through Node 00. Nodes 011, 021, 031 and so on are children of Node 01. So for Node 011 to send to 02, it will send to 01, then to 00, then to 02. Therefore, if you put a Node 011 on your network, be sure that there is a Node 01 on the network, and it’s powered up, and it’s in range!

Wireless Sensor Node With Power

In practice, I’ve gotten in the habit of designating a ‘router’ node numbered 01-05 on each floor, using a high-power antenna, and connected to wall power. Then all the nodes on that floor communicate with the ‘floor parent’. The picture above is a standard V3 node with a special ‘power pack’ added on to let it plug into the wall, and a radio unit with an amplified antenna.

Building a Wireless Sensor Network

The ‘sensornet’ example is the place to start from when building out a network of sensors. This example demonstrates how to send a pair of sensor readings back to the base from any number of nodes. The readings are a temperature sensor connected to Analog input 2, and a voltage sensor connected to Analog input 3. Every node will send a ping to the base every 4 seconds, which is a good interval for testing, while in practice you’ll want a much longer interval. Leaf nodes will sleep in between transmissions to conserve battery life.

The base simply dumps the ping to the console, and tracks the packet loss. This way we can monitor the health of the network while testing it. In a real application, you’d want to store or transmit those values somewhere, for example up to Pachube.

Payload Details

RF24Network sends two pieces of information out on the wire in each frame, a header and a message. The header is defined by the library, and used to route frames to the correct place, and provide standard information. This is defined in RF24Network.h.

/**
* Header which is sent with each message
*
* The frame put over the air consists of this header and a message
*/
struct RF24NetworkHeader
{
  uint16_t from_node; /**< Logical address where the message was generated */
  uint16_t to_node; /**< Logical address where the message is going */
  uint16_t id; /**< Sequential message ID, incremented every message */
  unsigned char type; /**< Type of the packet.  0-127 are user-defined types, 128-255 are reserved for system */
  unsigned char reserved; /**< Reserved for future use */
 
...

The message is application-defined, and the header keeps track of the TYPE of message using a single character. So your application can have different types of messages to transmit different kinds of information. For the sensornet example, we’ll use only a type ‘S’ message, meaning “Sensor Data”.

This message is defined in the example, in S_message.h:

/**
* Sensor message (type 'S')
*/
 
struct S_message
{
  uint16_t temp_reading;
  uint16_t voltage_reading;
  S_message(void): temp_reading(0), voltage_reading(0), counter(next_counter++) {}
  char* toString(void);
};

This simply contains a temperature and voltage reading. These values are 8.8-bit “fixed point” values, which is to say that the high byte is the decimal part and the low byte is the fractional part. For example, 3.5V is represented as 0x380. Also included is a method to convert it to a string for easy printing.

Voltage Sensor

I like to monitor the battery level of each node, so I can see when it’s time to track one down and replace its batteries. To do so, I connect the VIN from my power source, to the ‘voltage sensor’ input, via a voltage divider:

Battery Voltage Measurement.sch

I use a 1M/470k divider circuit, which will reduce 3.44V down to 1.1V, and then use the 1.1V internal voltage reference. This is perfect for my uses because I don’t use voltages over 3.44V. Of course, if you do, you’ll want a larger divider. In my case, when analogRead(A3) returns 1024, I have 3.44V. In the sensornet example it works like this:

// What voltage is a reading of 1023?
const unsigned voltage_reference = 5 * 256; // 5.0V
// How many measurements to take.  64*1024 = 65536, so 64 is the max we can fit in a uint16_t.
const int num_measurements = 64;
...
    // Take the voltage reading
    i = num_measurements;
    reading = 0;
    while(i--)
      reading += analogRead(voltage_pin);
 
    // Convert the voltage reading to volts*256
    message.voltage_reading = ( reading * voltage_reference ) >> 16;

First, I take 64 readings, to get a good sample size. The other advantage to 64 readings is that it uses the full 16-bits of a uint16_t, so a value of 0x8000 is half of the max 1.1V. Next, I multiply it by the voltage reference. That reference considers the voltage divider I have in place, telling me what voltage I ‘really‘ have on the battery if I get an 0xFFFF reading. In the case of the example, it’s 0x500, or 5V. Finally, I shift it down so the decimal point is in the correct place for an 8.8 fixed point value.

Temperature Sensor

The sensornet example uses the MCP9700 temperature sensor, which is my sensor of choice. You could change it to anything you like, just be sure to modify the calculations accordingly. The way the MCP9700 works is it emits 0.5V at 0 Celsius and increases 0.01V every 1 Celsius above that. Perfect for the 1.1V internal analog reference. Here’s how its used in the example:

    // Take the temp reading
    i = num_measurements;
    uint32_t reading = 0;
    while(i--)
      reading += analogRead(temp_pin);
 
    // Convert the voltage reading to celsius*256
    // This is the formula for MCP9700.
    // V = reading * 1.1
    // C = ( V - 1/2 ) * 100
     message.temp_reading = ( ( ( reading * 0x120 ) - 0x800000 ) * 0x64 ) >> 16;

Same as above, I first take 64 samples to get a reading in the range of 0x0000-0xFFFF. Then convert it using these steps:

  • Multiply by 0x120, which is 1.1 in 8.8-fixed point. This converts the reading into volts, and increases the decimal place by 8 bits.
  • Subtract 0x800000, which is 0.5, because the decimal point is way out at 24 bits.
  • Multiply by 0x64 which is 100
  • Shift right 16, which reduces the decimal point from 24 bits to 8 bits which is where we need it.

All of this is done in a 32-bit integer so there are plenty of bits to do this calculation.

Deploying

Put the sketch on every node. Start it first while connected to the serial port, so you can give it an address:

RF24network/examples/sensornet/
PLATFORM: Getting Started Board
VERSION: 013b4d3
*** No valid address found. Send node address via serial of the form 011<cr>

Once you get a bunch of them going, you’ll see the whole spew:

1733003: APP Received #16 24.23C / 3.21V from 053
1733709: APP Received #37 23.82C / 2.70V from 043
1734297: APP Received #109 24.46C / 3.06V from 013
1735108: APP Received #55 25.16C / 3.06V from 033
1735224: APP Received #134 22.66C / 2.71V from 031
1735286: APP Received #287 25.10C / 3.24V from 01
1735565: APP Received #299 24.79C / 3.36V from 03
1736871: APP Received #71 25.78C / 3.07V from 023
1737094: APP Received #137 22.89C / 3.01V from 041
1737119: APP Received #120 23.69C / 2.98V from 011
1737247: APP Received #17 24.23C / 3.21V from 053
1738025: APP Received #38 23.82C / 2.70V from 043
1738361: APP Received #110 24.45C / 3.06V from 013
1739286: APP Received #288 25.11C / 3.24V from 01
1739404: APP Received #56 25.16C / 3.06V from 033
1739565: APP Received #300 24.78C / 3.36V from 03
1739574: APP Received #135 22.68C / 2.71V from 031
1741043: APP Received #72 25.77C / 3.07V from 023
1741213: APP Received #138 22.87C / 3.01V from 041
1741490: APP Received #121 23.68C / 2.98V from 011
1741492: APP Received #18 24.21C / 3.21V from 053

Setting the sleep interval

Once it’s up and running, you can change the sleep interval to something more rational. For production networks, I shoot for one reading from each node every minute, which is probably overkill but it gives me some flexibility because sometimes nodes have trouble reaching the base for several minutes at a time. These are the values to adjust:

// Sleep constants.  In this example, the watchdog timer wakes up
// every 4s, and every single wakeup we power up the radio and send
// a reading.  In real use, these numbers which be much higher.
// Try wdt_8s and 7 cycles for one reading per minute.> 1
const wdt_prescalar_e wdt_prescalar = wdt_4s;
const int sleep_cycles_per_transmission = 1;

Next Steps

The sensornet example can get a large number of sensor nodes up and running. But then what do you do with the data? Probably, you want to transmit or store them somewhere. That will be the topic of a future post.

  • Posting to Pachube‘. Combined with NanodeUIP, we can post sensor readings to Pachube from all thousand-some nodes connected. (Or at least 17 for starters :))
  • PC application to monitor the network‘. The serial port is quite a cacophony of node information. I am also working on a C# WPF application to give an overall view of how the network is doing. It’s quite nice, so when it’s done I’ll put that up too.
  • My Personal Pachube Lite‘. Pachube is awesome, but there are times I may want to just capture the readings on my own database. It will do less than Pachube, but I can do whatever I want with the data. I’ve written my own solution using PHP and MySQL, but it’s not exactly easy for someone else to replicate. My latest idea is to build a server using Ruby on Rails which looks ideally suited for the purpose.

125 Comments

Filed under Arduino, RF Radio

125 responses to “RF24Network for Wireless Sensor Networking

  1. Gary

    Hi

    Excellent article, just wondered if you had considered using SQLite, for your database as its easy to setup, does not need a server, is fast and compact and easily transportable. I am currently using it to back up my data when using RF24. http://www.sqlite.org/

    Also I use this database freeware viewer to set up and monitor the database http://www.sqliteexpert.com/

    Regards

    Gary

    • Thanks! Yeah, sqlite is interesting if you’re storing data from an app running on a PC and the base node is connected by serial. My personal preferred approach is to connect the base node directly to Ethernet, and then store them on a server using MySQL. But sqlite would work just as well for personal use, especially as Rails comes with it by default.

  2. kurtnelle

    Awesome dude. When farmers have large fields and they want to monitor it I can use this system can’t they. I’m sure if we use motion sensors it will make a very nice farm alarm system (against raiders and stray animals)

  3. kurtnelle

    This would make an awesome field alarm system so that farmers can monitor their crops and produce. Awesome work dude.

    • Thanks! Yes, this should work great for farmers. They would need to have an enclosed node, though 🙂 By my calculations, 2 AA batteries can last for well over a year.

  4. Fcaeiro

    Great maniacbug …
    My network is now with 11 devices 6 in beta stage working perfect still some boxes missing…
    The others are in alpha mode still testing some stuff I’m using the dth11 humidity and temp sensor .. For the battery voltage I’m using the internal atmega trick not so accurate but enough to understand when mine 18650 batts are running down.
    Still have a issue with the main sensor 00 being directly connected to internet by the ether shield. When I got some time out updating the pachube I miss some readings …
    Solution create a pc app that gets all the data locally and update pachube ( almost done)
    Once again thanks a million for your work with rf24 lib.
    I have to check your enhancements and reflash all my noses, still using arduino IDE 22
    Regards

  5. Grag38

    Nice job ManiacBug, I follow all of your works from the Arduino forum and I love these nrf24 modules. So from can you give us the schema of the V3 ‘power pack’.

    I plan to use 10 of these modules to drive a tally wireless camera system. I need to send informations up to 80 meters in ‘real time’ (from few ms up to 500ms, not more).

    I plan to use high power antenna modules with battery pack with arduino nano v3 board.

    Thanks if you can give us some advices and power schema

    Best Regards Grag38

  6. First off, thank you for these great tutorials, ManiacBug! It truly gives novices like myself a jump start with Arduino and the nRF24L01 modules. Are there plans on porting this library over to IDE 1.0.1 in the future?

    • Thanks! Does it not work with the IDE 1.0.1??

      • It does for me just fine, I used the lib this morning in IDE 1.0.1.

      • Oeloe

        RX, TX example works under 1.0.1, Sensornet does not. (or I am missing something) Can it have something to do with the jamfiles? What is their purpose? I only have the bare Arduino IDE, do I need something else. (errors seem to be abouth the EEPROM part)

        Thank you for all the great work you have done on this library. Now posting on COSM from 3 nodes, more to come….

      • Yes, the sensornet doesn’t compile under all versions of the avr tools. I do need to fix that. The jamfiles can be safely ignored.

  7. Wes

    I am only just starting off in the land of Adruino, but it is exactly for this type of project I have got involved. I am disabled and have been installing an irrigation system in garden and greenhouse that I want to be able to control via RF when I am too poorly to go out to look after the plants myself, fingers crossed I don’t struggle too much following what you have explained !

    Hope it does work with 1.0.1 !
    Thanks a lot for a massive help with what I need to do !!!

  8. mdellen

    Great work on this, I am loving it !
    Hello world works right away, but I am not getting the sensornet example to work.

    The sensornet example gives a lot of compile errors in IDE1.0.1, am I missing something ?

    eeprom_update_block whas not declared in this scope (in nodeconfig.cpp)
    S_message has not been declared (in S_message.cpp)
    temp_reading was not declared in this scope (in S_message.cpp)
    voltage_reading was not declared in this scope (in S_message.cpp)
    ………..

    Hope I will figure it out soon, or that someone can point me in the right direction.
    Parts for 10 dedicated nodes are starting to get in, build 3 testnodes using Aruino Nano V3. (no soldering) 🙂

    Keep up the great work !

  9. smitjjohan

    Hi there,

    How did you manage to get the ENC28J60 module and the NRF24L01+ module to work together? Did you have do do any SPI specifics? It also seems that the MOSI and MISO pins required in the specific libaries are different and not consistant. For example. the NRF24L01

    • No, MISO and MOSI are the same. You just need a different chip select line for each chip on the bus. NRF24L01 and ENC28J60 work together great.

      • wazolas

        I’ve been struggling with this (enc28j60 + nrf24l01+) and i’m unable to get it to work. They work alone with no problems. When I get them together, once I do a network.read or network.write from RF24Network lib the ENC28J60 stops responding… How did you manage to put them together in the loop() function? You make it sound like it’s just managing the 2 SS signals, dividing your code in two (eth part and rf24 part) and before each of this parts the respective SS changes from high to low (activate slave) and the other one to high (disable). I’ve tried this and a ton of other options and nothing… do you use any delay? or other ‘trick’? does the order by which the libs are loaded/initialized matter?
        thanks in advance! 🙂

      • No special tricks, sorry I wish there was something I could add. It works very simple for me, no issues.

  10. Hi!
    I have a question about sending strings with your RF24 (network) library. I managed to successfully transmit integers, but I have some problems with strings. At the moment, my structure looks like this:

    struct Sensor_message
    {
    char* sensor;
    int temp_reading;
    };

    I can read the integer value on the receiving side, but “sensor” field is blank.

    Thank you for all of your work and great articles.

  11. This is great inspiration – I’m looking very much forward to getting the time on my hands to do a set-up myself! Internet of things is really only feasible for us lower-income house-holds if it doesn’t involve xbee or wi-fi 🙂 Great stuff, well done!

  12. Johann

    Hi Maniac

    Im trying to load the sensornet code but get eeprom block not declared error any idea?

  13. saleve

    This is excellent stuff – congratulations! Any chance that you’d be prepared to share schematics and Gerbers for your V3 node boards? Thanks.

  14. Hi – right – ignore previous message about meshping – all working – I wonder if you could clarify a few points.. am I right in saying the largest single message the chip can handle is 32 bytes…. and if so how many are left once your header is used? ie what is the maximum length the message could be? Also may I suggest making a public override for the data rate – 250KB increases the range and it would save people poking your source code as I’ve done to slow it down. Finally – at a guess… things like the Dallas chips have delays in them, do you know the maximum time (at 250k for example) that you could leave in between calls to pump the radio network without losing anything?

  15. Nick H

    I’m excited to have found your site. You have provided a wealth of knowledge and I’m very grateful for it. Also, I am really interested in starting a project that will utilize these sensor nodes. I was curious if you had the parts list and PCB schematics for your v5 node put together yet?

    • Hi, I haven’t posted V5 yet. (I’m up to V6, and it’s pretty sweet). But really it’s just incremental refinements. I recommend to start with what I have already posted, and then you can tweak it to meet your own unique requirements as you go along. Good luck!

      • Nick H

        Thanks for the reply. I’ve been busy the last few weeks learning how to build my own boards in Eagle. I’ve actually submitted my first design to Iteadstudio. Hopefully I will get them in here in the next week or so. I’ve been working controlling an electromagnetic strike plate to open my front door. I’ll put together a write up once I’ve got it completed and send it your way.

        Thanks again for all your hard work on these libraries.

        Nick

  16. Simon

    Hi,
    I’ve another question: How send a string with your class. Using this “network.write(header,&message,sizeof(unsigned long));” I can send only numbers, right? Taken from meshping example.

    Simon

    • You wouldn’t send a string, per se, you’d send an array of characters. So instead of a ‘float’, you’d send a char[18], for example. Then you’d need to copy the string into that, and extract it on the other end. This would be a good time to move over to char arrays instead of strings in your designs. Using the string class on such a memory-constrained environment as Arduino is the path to running out of memory (and getting random crashes).

      • Simon

        Hello!
        As you suggested I’ve moved to a char array. Until here ok, I can send and receive messaged between nodes. A char array is used to create a sequence of numbers, separated by semicolons that contains sensor values. The same variable is then sent out with network.write and populated by network.read in case a node receives these informations from other nodes. It happens often the char-array is overwritten or cutted-off. Without posting the code, I only would like to know how these 5 PIPES are working. It’s possible in case two nodes sends simultaniuosly to node00 a message they would be overwritten? Or how network.read reads these pipes? Do I need different headers? Thank’s for the help!

        Simon

  17. Sergey

    Compilation errors:

    nodeconfig.cpp: In function ‘void nodeconfig_listen()’:
    nodeconfig.cpp:73: error: ‘eeprom_update_block’ was not declared in this scope
    nodeconfig.cpp:82: error: ‘eeprom_update_block’ was not declared in this scope
    nodeconfig.cpp:100: error: ‘eeprom_update_block’ was not declared in this scope

  18. Zim

    First up thanks++

    Some advice please. I am developing a project that requires about 200 temperature sensors. Each sensor will be a self contained aduino + nrf24l01 + sensor. All fine so far but this is where my problem comes. This project requires 1 control node and all 200 boards to talk directly* to it. The best way I can describe the situation is a bag full of marbles being scattered in a room. This will rule out using the sensornet example as nodes could be anywhere in the room.

    Things to work with:
    Arduino pro mini 3.3v
    The sensor I have chosen to use is a ds18b22**
    Nrf24l01 module
    A very basic understanding of arduino and c/c++ so any advice would be great.

    *or have a dynamic mesh.
    ** each one wire device has its own unique id that could be used as an address.

    • Hi. I don’t see an obvious solution for your problem. You have a complex problem, with no obvious off-the-shelf solutions, and limited c/c++ expertise. Perhaps the thing to do is start small and build up your expertise one step at a time until you’re at the point where you can undertake something of this scope?

  19. patricio

    How many nodes can the base have? By simply seeing the notation of the names i can only have 9? I wish i could have a very large amount of children from the base node, actually that is the only connection i want.

    Another question, what happens when a node is out of range? Is there a way for the base to detect when their children is in range?

    • The base can have 5 children.

      As to range detection, the library will not do this for you. However, it’s not so hard to design an application that builds in range checking. For example, leaf nodes can send an “I’m alive” message on a regular interval. The base can for example post that message to a server. Then from a web page, you could see how long its been since the system heard from a particular leaf node. This could tell you it’s out of range (or out of batteries!).

      • patricio

        Why is it that 5 is the limit? Is it because of the Enhanced Shockburst? is there a way i could get this number higher? i just need 1 nrf recevier being the “server” and many sensors reporting to it.

      • patricio

        I’ve been thinking, what i really need is a star network, but i need a big network. i need to have maybe 100 leaf nodes, which if i am getting my calculations correct i could create this by using 3 layers as my “base” node, meaning having 31 modules being my “base” 1 base, 5 relays, and 5 relays beneath each relay.

        This would give me a total of 125 possible leaf nodes. but if i have that config that would be pretty expensive because every module would need an arduino attached to it would it?

        Is this aproach to achieve my solution not being good? maybe zigbee would be a better option?

        Thanks!

  20. Hello maniacbug,

    I didn’t understand one thing. If you have the receiver/transmitter code separated, how can my node 01 send message to 02? All the not leaf stations should be listening (waiting for their children and his father) to communicate. Does the RF24Network network(radio); takes the pipes automatically based on station ID?

    And multiceiver is able to use 6 pipes, so the base station can have 6 childs, all his childs can have just 5 (one to talk with him and 5 childs)… and this keep going right? So the limitation are the “addressing” size?

    Best Regards,
    Matheus

    • Good question, which can hopefully clarify things for some people. For node 02 to send to 01, the message goes through 00. This is transparent to the application code. The library sets up a (potentially large) tree network, where nodes can only communicate directly with their parents or their children.

      The base can only have 5 children, so yes a pipe is wasted on the base unit. This was a conscious choice to keep the design as simple as possible.

      • Larz

        Hi Maniacbug,

        On the 5 vs 6 pipes question…can a non-base node have 6 child nodes? I.e. Can relay node 01 have children 011 through 061?

        Thanks,
        Larz

      • Nope, because each non-base node uses one of its pipes to communicate with its parent.

  21. One other little question, If I’m using interruptions, my board will just get interrupt when one of the pipes that the station is waiting for ? Or any network message? For example, if a leaf (022) want to talk with his father(02), and send a message but the base station is in the range. Does the base station (00) will wake up to?

    • So, I don’t typically use interrupts with RF24Network. Base and relay nodes are expected to be on wall power, so I don’t sleep those nodes, ergo no big need for interrupts.

      If you do have interrupts hooked up, you’ll get an interrupt any time there is a message that the node needs to process. For example, consider node 01. If node 021 wants to send a message to the base (00), it will send it first to 01, which will relay it to the base. So in this case, node 01 will get an interrupt when 021’s message arrives which needs to be relayed.

      • So for example, in the case that you said, when 021 sends the message to 01 just 01 will wake up then, 01 will send to the base 00, and then just it will wake up. So, the interrupts just work when you’re actively participating on transmission, if you’re not for example node 031 it will not wake up. 😀 Thanks!

      • I really would appreciate if you’d give an example how how to run this under interrupts. In an application where the data rate is relatively high, you just can’t do anything else but sit in that loop for fear of missing anything.

      • Yes, this is a good point. I should point out that my use of RF networking is biased toward nodes that sleep a lot and transmit in small bursts. Not high-bandwidth operations.

  22. Grag38

    “Why is it that 5 is the limit? Is it because of the Enhanced Shockburst? is there a way i could get this number higher? i just need 1 nrf recevier being the “server” and many sensors reporting to it.”

    Look at the specs of nRF24 (http://www.nordicsemi.com/eng/nordic/download_resource/8041/1/12853037) , you will discover that there is 6 pipes actives at the same time. If considering that a master takes one pipe, there is 5 free. If you just want one master that send packet without ‘return’ as UDP protocol do, it will works without trouble.

    I already use 1 master that sends datas to 12 receivers. But there is no protocol about to know if a receiver had received the datas.

    You can read in the specs (ref done above, around the 7.7 part of the document).

    Best regards.

  23. Simon

    Hi maniacbug,

    As written before, thank’s for your library, it’s great. I’m trying a bidirectional comunication, as descrived here on Arduino forum:

    http://arduino.cc/forum/index.php/topic,136588.0.html

    If you could help me would be nice. In case you can answer me here or on forum directly.

    Thank’s! Simon

  24. Hei Maniacbug, i’m just curious, how far nrf24 can transmit to another node?peer to peer, without bridge.
    thanks

  25. Frank

    Someone posting on the arduino forum lead me to your blog. This has some info I can use in my project, thanks for sharing !

  26. ronsegalnz

    Hi maniacbug

    About 18 months ago now I developed something similar, based on the nRF24L01+ transceiver, though the network was not as developed as yours. Mine provides a link for sensing water level (ultrasonic range sensor) of remote tanks (around 1 Kilometer distant using a PA version nRF24L01+ module), temperature, and voltage of the sensor node battery. The sensor node board that I designed, with Microchip processor, also includes a solar charge controller for a Lion battery and a real-time clock, which controls putting the entire board to sleep to minimise power consumption. A slightly different design host node with an ethernet connection enables sensor data to be made available to a simple web application, which can also be used to configure the host and sensor nodes from anywhere. However, I stopped development of this using the nRF24L01+, as it became clear that for outdoor reliability in difficult (hilly) terrain in New Zealand, a self-healing mesh would be needed, providing multiple redundant routes as necessary. As this particular transceiver chip doesn’t have a broadcast capability a self-healing mesh isn’t practical. However the ‘successor’ nRF24AP2-8CH ANT transceiver does support broadcast, so I had been planning to migrate the design to use these and develop a simple mesh protocol, but suitable power amplified modules don’t seem to be readily available, at least not to New Zealand, darnit!

    Since then I’ve been experimenting with ARM based transceivers and Contiki 6LoWPAN, which is standards compliant but also much more complex being based on 802.15.4 MAC, and so frankly, bloated. I miss the elegantly simple design of the nRF24 series MAC (MAC plus really). I’d be interested in any views that you might have on this?

    • Yes, you’re exactly right on both counts.

      The nRF24 modules are too simple to (easily) do the self-healing mesh. The 802.15.4 MAC is super powerful and standards compliant. But for getting something up and running, especially for a hobbyist, the nRF24’s can’t be beat. So, you’ve pretty well nailed the trade-off between simple vs. powerful.

  27. Alex

    Hello Maniacbug,
    Thank you for producing such a fantastic library (and well document too!). Great to read and learn from real programmers code.

    Cheers,

    alex

  28. Hello Maniacbug,

    thanks for all your information and work!

    You share the schematic of V3 on another side. Here you tell us that you did some improvements and will do a V5. Did you just arranged the components different or did you also chanced the schematic itself?

    Best regards

    Sebastian

  29. Greg

    I like your house monitoring solution. Is there any progress on V5 and V6 nodes that you mentioned above. If yes, I would appreciate to get some more information on them. If there is nothing new about V5 or V6, I would at least like to get any updates on V3 (Low-Power Wireless Sensor Node https://maniacbug.wordpress.com/2011/10/19/sensor-node/).

  30. Werner Kraus

    Hi,
    Your work is great, exactly what I was dreaming of, thanks. I’ve done the first tests and it is working very well. Now, I am thinking to make the sensors even smaller. Have You ever tried to use an ATtiny for a node?

  31. Raph

    Hi ManiacBug,

    Thanks a lot for this blog. Do you thing that the RF24 library is easy to use/translate to the teensy 3.0 board ? (considering spi and miso particulary)
    This 32b microcontroller has a lot of digital I/0 and serial ports for a such so small .

    Thanks for an answer from you.

    Best Regards.

    Raph

  32. Hi, Maniac. Did you ever get to building/publicizing the V5 version of your low-power node? Are there headers for extra sensors on it?

    • No not yet. I need to do that! And no, I’m not adding more sensors on this unit. My goal is to get SMALLER not LARGER 🙂 That said, it wouldn’t be hard to rework it and add other sensors. The 328 has lots of spare unused pins.

      • autonomy

        Cool, will be on the lookout if you ever do. From my research, your build appears to be the lowest-cost and lowest-power solution per sensor allowing for remote/outdoor installations, though it does require a gateway for internet monitoring. Then again, WI-FI enabled nodes would not be able to do mesh networking without extra configuration.

  33. Cool project, I’m started with something similar by myself (hardware: http://www.open-homeautomation.com/projects/sparrow/). I need some functions that are not available today in your network stack. In my application nodes have to join the network ad-hoc and get an address from the network (similar to ARP). I’m thinking of using the your RF24 as a base. Did you do further work on the module or should I use the version on GitHub?

  34. maniacbug,
    1st off great work!
    Would you have a problem with me converting/rewritting your code for use with the Atmel Studio IDE?
    I will provide a ReadMe file with references to you, your site and licensing.
    It is not an exact convert I am merging in code that I have written with code from you that has been rewritten, I used your code as a template.

    Thanks

    • Hi, sorry for the delay in replying. If you are still interested in this, then yes of course. All the code is GPL2, so as long as you respect the terms of that license, you can do with it anything you like!

  35. Outstanding work! I’m working with an ARM-Cortex M0+ with Arduino headers (FRDM-KL25Z board from Freescale) which provides a lot of processing power with low power. So far I’m using Bluetooth (http://mcuoneclipse.com/2013/06/19/using-the-hc-06-bluetooth-module/) and IEEE802.15.4/Zigbee (http://mcuoneclipse.com/2013/05/12/freedom-track-robot-with-ieee802-15-4/) for communincation between devices and the host PC. This RF24 seems like a really good alternative. I noticed that your GitHub and files are GPL2, and not LGPL or BSD license style. Any reasons to use the more restrictive GPL2 license, and not using a BSD one?

    • Zigbee has a lot going for it. I just think it’s too expensive and complex for what most folks in the Arduino community use it for.

      GPL2 is a conscious choice. I’ve put a lot of work into the libraries, and happy to share them. But only with people who also want to share their code. I don’t see the value in making the code available for others to use in a closed-source product and distribute it.

      • Yes, that’s a fair comment about GPL2. I have received a handful of the RF24 modules, so I will spend some time during the summer break to get them up and running with my processor board. Thanks for sharing your work, outstanding stuff!

  36. martin lutteral

    Got this question:
    I connected my arduino uno with the RF24 module. I power the module from the 3.3V from the arduino, and I was thinking about the logical signal. The logical 1, is 5V for the arduino, and 3.3V for the RF24. I was wondering if that difference can do some harm.
    However, my setup worked as a charm, first try. I got two arduinos talking to each other.
    Do I have to worry about the transceiver failing because of the higher voltage logical signal?
    Do I need a bidirectional databus translator? (something like this: http://e2e.ti.com/support/logic/f/151/t/180222.aspx)
    thanks a lot for your help!!
    M

  37. Garrett B.

    I’m playing some late catch-up here, but had an idea that I’d like to run by someone with more experience than myself.

    I grasp the pipes concept on a single radio just fine. However, I can’t figure out how it all comes into play when you start creating larger networks of radios. Is it possible for two radios to share the same pipe address? What I’m trying to figure out is if a simpler, non-relay network can be set up with more than 5 sensor nodes. The base node would be listening on a single address. All the child nodes would transmit only to that base address. However, prior to transmitting, could a child node send a broadcast-type “ping” on a special pipe address assigned to all child nodes to check if any other child nodes might be transmitting?

    As an example, the base node has an RX of 00. All the child nodes have TX of 01. The child nodes also have an extra RX of 10. Could any given child node “broadcast” to 10 to see if other child nodes are active?

    Considering the ACK and auto-retransmit, it probably wouldn’t work. Maybe we can hope for broadcast addressing in the nRF24L01++, relaying in the +++, and multi-casting in the ++++?

    I have referenced your posts over and over again to get me here. The relay network code you have programmed is the next logical step for my project. Thank you for all your hard work and sharing it with everyone!

    • Once you start sharing a pipe, it just becomes a more complicated problem. There are lots of strategies for sharing a single frequency. For one, there is a ‘carrier detect’ function, where you can listen to see if anyone else is talking before you transmit. You can also give each unit a slice of time. I just chose the one-device/one-pipe method for simplicity.

  38. Neeraj

    Can i use any of the following trancievers instead of nRF24L01 based radios to create RF24 Networks using your library?? When shipping nRF24L01 based trancievers to india, it is still costly. (About 30US$ or 1500INR).

    Kindly please visit the product page.
    1) http://www.rhydolabz.com/index.php?main_page=product_info&products_id=1201
    2) http://www.rhydolabz.com/index.php?main_page=product_info&products_id=410

    These two cost 3US$ or 150INR and use SPI and 2.4GHz.
    Also, if i can use, what should be the modification in your schematics and code??
    I am eagerly waiting for your answer. Thanks in advance.

  39. Hi maniacbug

    With higher powered transceivers for longer distances, the node at the base of each branch (the routers)would need to sleep for the batteries to last a reasonable period. Have you considered time slotting?

    In any case you’ve clearly done a fantastic job with this network, able to take advantage of the huge number of cheap Chinese sources. I notice that there are even shielded versions now of some of the high powered (PA+LNA) modules.

    Cheers

    Ron

  40. Hi!

    Thanks for this article. I appreciate your work.

    May be this is not the best place to ask, but what do you think about creating an nRF24 based bootloader for Atmega 328? It would be very confortable to upgrade microcontroller code in remote devices without the need to attache them to a computer.

    Did you try it or do you know about somebody who already did?

    Regards

    Gábor

    • It’s an interesting idea. Not sure if all the needed code would fit within the bootloader space, but it’d be worth a try.

      • Brokhin

        Do you think that is possible? I already thought about that, but as my search didn’t have any results, I thought it would be impossible. The only thing similar that I found was in the arduino fio page (http://arduino.cc/en/Main/ArduinoBoardFio), they say “…Additionally, by using a modified USB-to-XBee adaptor such as XBee Explorer USB, the user can upload sketches wirelessly..” So I assume that it’s only possible to do it by usb, or not?

        Cheers

      • I do think it’s possible, if the code would fit in the bootloader space.

  41. Håkan Hallberg

    Hi!
    Awesome work!! I’m kind of newbie to C++ programming but learning from libraries like Yours. I got the meshping example to work perfect between one Arduino Mega and one Uno but I’m stucked on how to kind of ‘reverse’ the way it works. The aim is to get the Mega work as a central unit sending out commands (like ‘DU1111100001111000’ etc) to every node on network and then the relevant node takes action and pings back to central unit. I’ve created a third handle for sending the command when a CR is seen on serial port on Mega (from Raspberry Pi). This works as expected and the message is sent out but only to unit 00 and receieved by unit 00 despite that the other node is active. I’ve spend hours and hours ,mostly try and terror since I can’t figure out exactly how the network is sending between nodes without success. I’m not lazy,expecting someone else do my coding but I’m ego to get this working,the idea is to control different areas in my garden,pool area,pond area etc. Is there someone done similar and willing to share a code snippet or explaining how to do this I would be very happy. In conclusion I need to do a reverse sensornet examle.Btw when setting address on my second node sending a ‘1’ it get’s address 02,shouldn’t it get address 01 ??
    Cheers Hucke

  42. JJ

    Congratulations on your excellent work.
    I look forward to new releases that allow treating large amount of data generated by the nodes (Pc application to monitor the network, Pachube, etc.).
    My idea is to connect the node 00 through SPI with a Raspberry Pi converted into data warehouse (MySQL) and web server to display in a graphical environment of each room temperatures and battery status of each node.
    The possibilities are endless: send alarms by email, etc, etc ….
    (sorry for the English using google translator)

    Greetings.

  43. Ramón

    Hi maniacbug,

    I send messages from node 0 to node 11 through the node 1 of my network. If node 11 is not available, however the network.write() function returns Ok=true. Is it possible to know whether the message has reached the destination node?

    Thanks,

    Ramón

    • With the library works today, that information is not propagated up to the application. So you’d need to have node 11 send an explicit ack back to 0. In general, RF24Network is designed for a system where we don’t really need to know whether a specific packet made it or not, because we’ll be sending another one before too long.

  44. Hi ManiacBug
    I’ve been working with your libraries for arduino to interact with the nRF24 wireless modules. First, I have to thank you for all the work you have put in the development of this library and for making it available for us.
    I have one question regarding the libraries that you developed. Is it possible to implement an auto generated mesh or tree topology with this library, or something like that?
    For what I can see in the code, each node uses its own address as a way to know if it is a leaf or a relay, but could it be possible for the relays to discover its leaves or for the leaves to turn into relays if they detect a leaf without parent?
    I have been trying to make a pseudo-mesh by making all nodes relay all packages to all the other nodes, but I haven’t been able to. I guess it’s because of the pipes they are using. Could you point me in the right direction?
    Thanks for your help in advance.
    Best regards.

    • It’s definitely possible. Anything is possible 🙂 That is a much more complex system, and I’m sure would be valuable to many. RF24Network is designed to be really simple, so RF24Network wouldn’t do this.

    • RonSegal

      Maniacbug is right, what you are asking for is an order of magnitude more complex. For example the Contiki project (www.contiki-os.org) uses RPL (the ripple protocol) where control messages propagate from node to node building a map of nodes in the network. It might be possible to port the nRF24+ as a front end radio to Contiki together with a suitable processor, but it would be a lot of work and Contiki is relatively poorly documented.

  45. I just wanto to say thanks! Thanks for your amazing and ispirational work on rf24network library. Keep going.

  46. Brokhin

    Hi maniacbug, I was trying this library but it gives me an error: ‘class RF24’ has no member named ‘isValid’
    and it’s true, it has no member named like that, can you please help me with that? 🙂

    Cheers

  47. pablo saldivia

    Hi
    Really Great work!
    I have a problem with the sensornet example, compile ok, but when try with serial monitor, i see the next alert
    *** No valid address found. Send node address via serial of the form 011
    Send the addreess but nothing , no storing, nothing. i dont understand what is the problem , no bug no message in the terminal, the meshping example work really fine.
    Please help me

    • I did just recently change it to expect “011N”, you might try again and see if it works now.

      • pablo saldivia

        Thanks work fine, also change RF24 library to resolve a problem ” no member named ‘isValid’”.
        Please 2 question
        1) what is the way to change again the address node for example 11 to 12 . When send a new address not change.
        2) What is the way to address node 00, probe with 000N or 00N or 0N the system show ERROR: This sketch cannot run on node 00 , i need make a change to node 00

        Thanks for all and again very good work

      • Yes, I committed on Thursday a fix for RF24 containing ‘isValid’. Sorry, I can not make out how to answer the other questions.

  48. Hello meniacbug, you have done a fantastic job.
    When I was using nrf24 with your libraries I’ve found,
    when;
    00 01 11
    low power low power low power – working fine
    high power low power high power – not in proper way (in 00 receiving duplicates)
    high power high power low power – working fine

    Can any user explain this situation. Anyone has a similar experience ?

  49. Hi, I was able to receive package from node 1 to node 0 (base) but now I want to make a new node 21 (leaf) to send data to base (node 0 ) but thru node 1 , can you give me an example of code ? Thank you

  50. Hello,
    How can this network expands up to 6000 nodes ?
    in one channel – > can connect max 30. >>>>>>>> 00 -> 01,…05 -> 011,…015 /,…………………/, 051,…055 so on..
    and 125 channels possible

    • 1,2,3,4,5 + (5*5) +(5*5*5) + (5*5*5) etc. Simple…

      ie

      Base level only there are 5 units
      One level out there are (5*5)+5=30
      Two levels out there are (5*5*5)+(5*5)+5=155
      There levels out there are (5*5*5*5)+(5*5*5)+(5*5)+5=LOTS

      etc
      To get the distance through my stone wall house I’ve had units 2111 running…. though obviously not populated all.

      In practice, you could never get that many running unless they were either (a) controlled by a master and unable to speak unless spoken to or (b) talking only very occasionally – because the radios cannot talk and listen at the same time.

      • Hello Peter,

        Thank you for your attention.

        But still I can’t figure out how to address nodes beyond One level out….

        example : 00 (root) -> 01 (first level node) -> 011 (second level node) -> HOW …? (third level node)

      • 01 – 011 – 0111 – 01111 where the original unit is on the RIGHT… so if you wanted the second slave of 011 it would be 0211

      • Exactly. I try to space out the transmissions so the base gets one every 3 seconds. With 20 radios, they can each send once every 60 seconds. So with 6000 radios, you’d want them sending every 2000 seconds each, 33 minutes. Still, if you’re masuring something that doesn’t change SO often, even 30 minute intervals is OK.

  51. I’m seriously wondering about these radios and the various usb power supplies… the software works a treat but I am getting ATTROCIOUS range – like less than a room range.

  52. Hi.
    To send to one node we use “const uint16_t other_node = 0;”
    But if I have a light that should be set on, and send from adress “00”, and thru “01”.
    How do we do this?

  53. JJ

    Hello Maniacbug.
    I can not configure the node 00 in SensorNet. I always responded “This sketch can not run on node 00”. If it is the same sketch for all nodes, how to configure the 00?. I tried with 00, 00N, etc. and no way.
    thanks

    • pablo saldivia

      I have the same problem 😦 but not understand the problem . I need create a new sketch for these??
      Again a very good work

  54. gary

    RF24network and how do i send text instead of a float number ?

    Hi,

    Hope you can help me, I have been tryng all day to work out how to accomplish the following:

    I have been using this code for a year and it works well, I obtain a float temparature reading, then its converted to decimal places and then sent out via nRF24L01 transmitter.

    My needs have changed and I know need to send text, such as: TurnOnLed

    I cannot work out how to convert the text to be sent using this part of the code:
    RF24NetworkHeader header(other_node);
    bool ok = network.write(header,&payload,sizeof(payload));

    I think it may involve using a char is some way, but not really sure ?

    Thanks in anticipation

    Gary

    struct payload_t
    {
    float Anything; // This is just a name, usually descriptive, could be anything at all, as its a ‘member’ of struct.
    float Sensor; //
    };

    void RF_send_temperature (void)
    {
    network.update(); // Pump the network regularly.

    Temparature_float_2_decimals(); // Convert the float to 2 decimals places after decimal point.

    payload_t payload = {packets_sent++, Float_to_Decimal};

    Print_temperature();

    RF24NetworkHeader header(other_node);
    bool ok = network.write(header,&payload,sizeof(payload));

    if (ok)
    Serial.println(F(“sent ok.”));
    else
    Serial.println(F(“failed.”));
    }
    }

Leave a reply to maniacbug Cancel reply