Author Topic: LoRa low-power CAD  (Read 844 times)

powernode

  • Newbie
  • *
  • Posts: 4
LoRa low-power CAD
« on: October 09, 2017, 11:03:12 AM »
Spent the past few weeks hacking on this and finally got it working!  A stock Motieno with LoRa radio running from a 1F, 12V capacitor bank and checking for commands every 2 seconds.  By the looks of things it should last ~5 days on the capacitors alone.

The first step was to get CAD working.  Fortunately the latest RadioHead library supports it out of the box.

Next, I needed a way to reliably detect channel activity.  My first attempt looked like this:

Code: [Select]
void loop() {
  // use the CAD function to check for an incoming message
  if (driver.isChannelActive()) {
    // attempt to recieve the incoming packet
    uint8_t len = sizeof(buf);
    if (manager.recvfromAckTimeout(buf, &len, 1000)) {
      // handle the command
      Serial.write(buf, len);
    }
  }

  // sleep for 8 seconds before checking again
  driver.sleep();
  LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}

The problem I discovered with this approach was that the transmitter divides it's time between transmitting and listening for ACKs.  This means that there's only a 50% chance of detecting channel activity, assuming you push the timeout as low as possible.  (25ms according to my testing.)

My next attempt was to modify the RadioHead library to use a very long (500ms) preamble for standard packets and a much shorter preamble (5ms) for ACKs.  I set my sleep cycle to do CAD checks in pairs spaced 60ms apart, and then sleep 8 seconds before trying again.  That way at least one of the two checks would be guaranteed to run during a preamble.

Code: [Select]
void loop() {
  // use the CAD function to check for an incoming message
  if (driver.isChannelActive()) {
    for (uint8_t i=0; i < 2; i++) {
      // attempt to recieve the incoming packet
      uint8_t len = sizeof(buf);
      if (manager.recvfromAckTimeout(buf, &len, 1000)) {
        // handle the command
        Serial.write(buf, len);
        // don't check again
        break;
      }

    driver.sleep();
    LowPower.powerDown(SLEEP_60MS, ADC_OFF, BOD_OFF);
    }
  }

  // sleep for 8 seconds before checking again
  driver.sleep();
  LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}

This worked, but battery life was much less than expected.  Measuring the current consumption on my scope showed that a full wakeup and CAD check only consumed 0.00027 Joules, so that's definitely not the problem.

It turns out that the CAD check is not 100% reliable and sometimes gives false positives.  When this happened, RadioHead was keeping the Moteino + RF module awake for a full 1000ms waiting for a packet that would never come.  I calculated that I couldn't afford to spend more than 20ms waiting for an incoming packet before sleeping.

For reasons I still don't understand, I couldn't get the timeout below 250ms without causing RX errors.   I reduced the preamble time, TX timeout, and tweaked every other parameter I could think of but never got it working reliably.

Since I was still an order of magnitude beyond my target I decided to try working with a thinner abstraction.  My next attempt used RHDatagram, which is really just a thin wrapper over the RH_RF95.  When I want to reach a sleeping node, I send a barage of packets for 10 seconds without waiting for ACKs, greatly simplifying the node's RX logic.  I've also reduced my sleep cycle to 2 seconds now that I have a better idea of what's drawing most of the power.

Code: [Select]
void loop() {
  // use the CAD function to check for an incoming message
  if (driver.isChannelActive()) {
    // switch the radio to RX mode
    driver.setModeRx();

    // wait for the packet to come in.
    LowPower.powerDown(SLEEP_15MS, ADC_OFF, BOD_OFF);
   
    // check if anything has arrived
    uint8_t len = sizeof(buf);
    if (manager.recvfrom(buf, &len)) {
      // immediately sleep the radio
      driver.sleep();

      // handle the command
      Serial.write(buf, len);
    }
  }

  // sleep for 8 seconds before checking again
  driver.sleep();
  LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF);
}

And what do you know, it works wonderfully!  This is my first Moteino project and I'm glad I finally got it working.
« Last Edit: October 09, 2017, 11:15:24 AM by powernode »

mielleriealphonse

  • Newbie
  • *
  • Posts: 9
  • Country: fr
Re: LoRa low-power CAD
« Reply #1 on: January 27, 2018, 08:25:35 AM »
Quote
Since I was still an order of magnitude beyond my target I decided to try working with a thinner abstraction.  My next attempt used RHDatagram, which is really just a thin wrapper over the RH_RF95.  When I want to reach a sleeping node, I send a barage of packets for 10 seconds without waiting for ACKs, greatly simplifying the node's RX logic.  I've also reduced my sleep cycle to 2 seconds now that I have a better idea of what's drawing most of the power.

Thank powernode for sharing your experience in Lora Low Power Land !

Would you mind if I ask to developp a bit the code of your sender ?

I am familiar with RFM69 module and library. I am successfully using the Low Power Listen mode in my product for 2 years now. It work great. I manage to run on a single battery a reciever for at least one year in RX mode. RFM69HCW has a good range (around 1.2km if line insight) but I would like to go a bit further. I looking for Lora based low power solution (low cost RFM95)

As far as I have understood, you manage to run at really low power a Lora reciever. Your code is straight to understand and sounds clear to me. however I am tried to figure out your sender code. I am new to RadioHead Lib, and it is not so simple to translate you sentence "send a barage of packets for 10 seconds" into code. If you don't mind I would be please to have the corresponding piece of code.

Thank you again for sharing !

Jérôme

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 5308
  • Country: us
    • LowPowerLab
Re: LoRa low-power CAD
« Reply #2 on: January 27, 2018, 08:23:30 PM »
Very interesting, thanks to powernode for sharing!
Jérôme - I hope this puts you in the right direction with low power 'listen mode' for LoRa.