Monday, January 23, 2017

RFM69HCW/LowPowerLab SendWithRetry function

Hardware: Adafruit Feather 32u4 Radio (RFM69HCW)

Software:  Windows 10, Arduino Sketch App 1.6.11, LowPowerLab

One minor issue I ran into when testing with the ~900mhz RF radio chips the first time was getting the units to retry failed transmissions.  I had chosen to download/utilize the LowPowerLab RFM69 functions to enhance and simplify many of the radio communications methods.  

I initially made the assumption (as most would) that the examples which used sendWithRetry were essentially correct.  And while that is true-ish (in that they work) it is not true that they are showing you the full power of that function.

Here's something closer to what you might use in a real application:

void loop()
  //sendWithRetry(target Id, message, message length, retries, time between retries)
  if (radio.sendWithRetry(RECEIVER, radiopacket, strlen(radiopacket), 10, 100)) { 
    Serial.println("ACK received");
  } else {
    Serial.println("No ACK received");

Most examples leave off the last two bolded optional components for that function (retries and time between retries).  Without that information, one is left wondering how many times it actually retries and how often.  Well, the answer to how it functions without those two items added can be found by looking at the source code the guys over at LowPowerLab provide with their toolset.  If you pull open their source on your PC (by default in Windows 10 C:\Users\yourusername\Documents\Arduino\libraries\RFM69\RFM69.h), and search for sendWithRetry you'll find the following chunk of code: 

    virtual bool sendWithRetry(uint8_t toAddress, const void* buffer, uint8_t bufferSize, uint8_t retries=2, uint8_t retryWaitTime=40); // 40ms roundtrip req for 61byte packets

That's a handy-dandy bit of info there that includes defaults for the extra values.  So if you don't include the last two variables then it defaults to 2 retries with a 40ms pause between them.  

That may very well serve most people in basic scenarios.  In my case, I actually cared that events were received (go figure), so I instead used code similar to what I included in the first example above which sent the packet up to 10 times and paused 100ms between them.  In truth, I then switch over and do some error handling to reflect an un-received communication, change the data packet to notify the receiver that something's "wonky" and try 60 times every 1000ms so it can log a poorly communicating node.  If I were really serious I'd probably put two radio units up with different frequencies (this board can do 868 and 915mhz) and have the endpoints switch in a pinch.

Radio transmission on these open frequencies can be pretty sporadic and lots of interference can occur.  It means that while the default of a couple of retries with a minimal pause between them is OK on a desk in the lab, it is not the way to do this in the field.

In my own design I not only increased the retries and the pause duration, but I also put multiple receivers out and programmed the clients to cycle through each of them to attempt to get an ACK.  If it gets a successful reply from one then it always starts with that one going fwd (until a reboot).  That makes it easy to move things around and never have to sweat about what device is supposed to talk with what receiver.

No comments:

Post a Comment