sudomesh / LoRaLayer2

Layer 2 routing protocol for LoRa connected devices

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Using this protocol in similar projects?

geeksville opened this issue · comments

Hi,

So I had googled this project but somehow never found ya'lls github. A kind commenter on my similar (but more focused on hikers, etc...) project pointed me this way. I had initially used the (not ideal) RadioHead mesh routing but I'm looking into other options for when I add mesh back in. Are you interested in collaborating? I would happily use this lib and help with development, send PRs etc...

I just sent an email to sign up on your mailing list, so when I get blessed for that we can talk over there if that is easier.

OOH those links were super helpful.

Most of the packets in my project are actually broadcasts, do you have any plans/ideas wrt handling broadcast for nodes that are more than one hop distant?

One way I might be able to help your project if I used your layer1/2/3 in my project is: provide a transport at the bottom based on my modified version of the RadioHead RF95 driver. You might like this more than arduino-LoRa because:

  • It is fully interrupt based (all sent messages start in freertos queues and received messages get delivered to queues). Messages get allocated from a pool storage allocator (which is ISR safe and no fragmentation problems)
  • Because of this there is no polling for radio state, so the main CPU can be asleep almost all of the time (cuts ESP32 power draw from 150mA to about 60mA). No polling in loop().
  • But even better, the CPU can be left in light-sleep (lowers down to a total of only 1mA current draw for the CPU) until an interrupt arrives indicating that the Semtech has a packet incoming.
  • Same thing for sending, once the packet is inside the radio the main CPU is asleep. So for almost all the time the current draw of the board is 12mA for the sematech + 1mA for the CPU.
  • Someday this could even work for a deep-sleep CPU, though IMO not a priority because it only saves 1mA.
  • The scheduled reception option of the sematech can allow that 12mA to drop down to 1mA with a bit more software work. ie. all nodes on the mesh know they have a timeslot when nearby neighbors are listening for the start of packet framing, and other times the rx side of the sematech is in sleep. This is almost trivial if all nodes has a clock set from GPS (which is why I chose the T-BEAM board for my project).
  • Address filtering can be handled by the sematech, so no need to wake the main cpu for packets that are not destined for it

I needed to do this mostly because I wanted my device to be able to run on battery for a long time (and I didn't have the option of changing the hw design to use a lower power main CPU - though this approach is not ESP32 specific). Currently the run time is about 3 days between recharging, but with a small amount more more it should be 8 days.

https://docs.google.com/spreadsheets/d/1ft1bS3iXqFKU8SApU8ZLTq9r7QQEGESYnVgdtvdT67k/edit#gid=1182643433

btw - my thoughts on how to solve the mesh problem are not nearly as mature as yours, but here's what they were: https://github.com/geeksville/Meshtastic-esp32/blob/master/docs/sw-design.md#mesh-broadcast-algoritm (in particular: approach 4 - because of my 'broadcasts are a large percentage of the packets' problem)

I initially used the RadioHead mesh router, but I have that turned off right now because I mostly onyl care about the broadcast case.

One other idea: Have you considered using T-BEAMs for your project? I have no connection to the company but it seems like it checks almost all of your boxes and possibly easier to get wide adoption if users don't don't need to build hardware? https://disaster.radio/build/

commented

Those power savings certainly sound appealing! I'm unqualified to answer but @paidforby or possibly @beegee-tokyo may have a view on it.

Is your 60mA with clock speed at 240MHz? If so you may see further savings by dropping to 80MHz

In terms of tbeam there is some experimental support https://github.com/sudomesh/disaster-radio/wiki/Devices--&-Hardware

oh yes - I think the power draw for most of the boards you list is dominated by the CPU and if you jiggle things around so that the CPU is mostly clock-stopped (in ESP32 land they call that light-sleep) you can achieve much lower power draws than what is in that table.

I'm assuming a mesh that is mostly not talking - of course if packets are being sent/received 100% of the time (unlikely for my use case) the CPU is almost always stopped unless the user just pressed a button or a packet just arrived or we just sent something. But even in the 100% case the savings from clock-stopping are substantial, because the sematech chip is so slow you can have the CPU clock-stopped 90% of the time while sending/receiving packets) [ I haven't yet added this optimization though ]

Is your 60mA with clock speed at 240MHz? If so you may see further savings by dropping to 80MHz

That was when I was still running at 240MHz. I'm now at 80MHz most of the time, but I haven't remeasured because 80 vs 240 doesn't make much difference in my case because the CPU clocks aren't running at all (except briefly because of press or packet activity). So 1mA.

In two LoRa (no Mesh) customer projects I was able to learn some things about power savings. But this is mainly based on the newer Semtech SX126x LoRa transceivers, which are better in power consumption than the SX127x chips used in the RFM95/96 modules.

I really prefer the SX1262 LoRa chips over the RFM95 modules because they are much better in power consumption and offer higher TX power. The problem is that the Arduino support is limited. So far there is only RadioLib from Jan Gromes and my own library SX126x-Arduino. And from HW side there is only one breakout board (Adafruit Feather compatible), but that is only available here in the Philippines.

Some info about my paid customer projects:

Project 1

Sensor nodes using LoRa to send every 15 minutes sensor data to a loRa/GSM gateway.
Both nodes and gateway based on ESP32 and using Semtech SX1262 LoRa transceivers.
Sensor nodes ESP32 is in deep sleep most of the time and LoRa is switched off. ESP32 wakes up from deep sleep by internal RTC, does its measurement and sends the sensor data over LoRa to the gateway. Up to 10 sensor nodes can be used. (Limited by customer request, he wants to sell more gateways 😆 )
The gateway ESP32 is as well in deep sleep, woken up by the SX1262 interrupt in case of a received package. The SX1262 is using its RX Duty Cycle mode to check for incoming packets. In RX Duty Cycle mode the LoRa transceiver sleeps most of the time and checks only in defined intervals for symbols on the LoRa channel. The calculation of ON/OFF times is a little bit complicated, but it works when following the Semtech application note.
Both sensor and gateway are running from big LiPo (2Ah) batteries. I got the sensors running for 3 weeks (sending every minutes) without recharging. The gateway lasted only 1 week with listening to 3 sensor nodes. Main problem here is the GSM module which is very power hungry.

Project 2

Insight ISP4520 based boards running permanently measuring sensor data and sending data every 30 seconds to a WiFi gateway based on ESP32.
The ISP4520 used in the sensor boards is basically a SOC with an Nordic nRF52832 BLE chip and a Semtech SX1262 LoRa transceiver inside. The sensor node is collecting sensor data permanently and sending a data processing result every 30 seconds over LoRa. In a "training" mode, the sensor node is sending the sensor data with 200 SPS over BLE to an Android app for recording and visualization. The gateway is outlet powered and has no batteries.
In LoRa mode the sensor node is running from a 500mAh LiPo for 7 days. IN BLE mode it lasted 2 days.

@samuk have ya'll given any thoughts on how to handle broadcast in the general mesh network case?

@geeksville
Some thoughts about the device ID.

I agree with the 6 bytes address being too expensive.

But, just my experience regarding skipping the OUI and using only the 3 byte NIC, Espressif uses different OUI for the ESP32 (I saw at least 2 different ones).
Also ESP32 is a 32bit machine and works best with 32bit variables. A 3 byte array will either slow it down or the the compiler aligns it to 4 byte address, wasting memory.

So maybe a 4 byte ID with the lower 3 byte being the NIC and the high byte being the lowest byte of the OUI will go around both above restrictions.

Hi ya'll,

So I've poked around a bit more and I think this library/protocol could work well for my application with some tweaks (I would be switching from my RadioHead RH_Mesh proof of concept).

Proposed tweaks (I'd happily do these and send in PRs and adjust based on our discussion/feedback):

  • Change the bottom layer out to instead of arduino-LoRa to my (initially RadioHead but now diverged) RF95 class (so I can get the ability to leave the main CPU off most of the time). Is it acceptable for your use-case to assume you'll always be on a platform that has FreeRTOS (or similar) primitives? Are all of your current platforms ESP32 based?
  • Add an implementation of naive flooding (because I need it for my user's chats and GPS messages)
  • Whatever work is needed so these changes could be tested and run in your environment. What do you use? Is it always a custom board?

Related things from my project that might be useful for you and I'd be totally up for mergifying efforts:

  • A reasonably nice GUI on the device (probably not relevant for you?)
  • A nice channel abstraction to communicate radio settings (center freq, SF, encryption etc...) between humans as a 'url' or QR code (which was useful for my case of having a simple way for non techy users to say "here's the channel to set your radio to")
  • A software BLE update mechanism for the ESP32 over bluetooth (and sister android code)

Work I'm willing to sign up for in the near but not immediate term (< 3 mos):

  • Adding payload level encryption (probably AES256 OFB but somewhat TBD ;-)). The ESP32 has very nice hw support for this cypher.
  • Extending the flooding protocol with something a bit more optimized (Multipoint relay? either with rssi or gps position as the heuristic in selecting the relay set)

Thoughts? Would that fit with what ya'll want to achieve?

Also - in the next couple of days I'll be updating my duty cycle spreadsheet based on some guesses on the cost of routing and I'll add a link here.

@samuk, @beegee-tokyo, @Juul - any thoughts on this idea?

commented

@paidforby is the maintainer and author of this code. It certainly sounds good to me, but it would be up to him to feedback.

Sorry I didn't jump into to this discussion sooner, I was distracted and had a large backlog to catch up on. To repsond to your prosposals

  • Change the bottom layer out to instead of arduino-LoRa to my (initially RadioHead but now diverged) RF95 class (so I can get the ability to leave the main CPU off most of the time). Is it acceptable for your use-case to assume you'll always be on a platform that has FreeRTOS (or similar) primitives? Are all of your current platforms ESP32 based?

Sure, you just need to write another Layer1 cpp file, something like Layer1_RF95.cpp and then add the necessary public functions and class definitions to the Layer1.h. Note, this modular aspect could be written a lot better, I'm open to any suggestions as long as they maintain the support for arduino-LoRa as an option.

*Add an implementation of naive flooding (because I need it for my user's chats and GPS messages.

By "naive flooding" do you mean that nodes forward every broadcast packet they receive? I added something like support for this recently, if you look at the routePacket() function here, it has a broadcast variable that can tell the protocol to forward a packet no matter what, as long as it's TTL is not expired. All you need to change the 0 is this line to a 1 and all broadcast packets will automatically flood. This may put you in a seriously bad situation where nodes keep looping the same packet, I'm not sure the best way to avoid this scenario.

  • Whatever work is needed so these changes could be tested and run in your environment. What do you use? Is it always a custom board?

I typically test on the LILY TTGO V2 dev board, though I've also be expanding support to the T-Beam and the Pycom LoPy4. I know other people have used the Sparkfun 1 channel and the Heltec V2 boards. Our custom, open source board is still in development, AFAIK. If your RF95 code works on any of the aforementioned boards, I'm happy to review and test once you have some code to merge.

  • A reasonably nice GUI on the device (probably not relevant for you?)

GUIs are cool. Currently we have a web-based chat app that is very spartan and a nicely designed BLE android app . I'm not sure what all you intend for your device, so I doubt these will be the kind of GUIs you are looking for, but they are worth glancing at.

  • A software BLE update mechanism for the ESP32 over bluetooth (and sister android code)

Cool idea, @beegee-tokyo wrote that android app, maybe you could integrate it into that, that'd be a great feature for disaster-radio to utilize also.

  • Adding payload level encryption (probably AES256 OFB but somewhat TBD ;-)). The ESP32 has very nice hw support for this cypher.

Great! Encryption is awesome! I haven't put too much thought into any sort of encryption. Mostly I'm worried about the limited packet size and over-utilization of airtime, but if you think there's a type of encryption that is small enough for LoRa packets then go for it.

  • Extending the flooding protocol with something a bit more optimized (Multipoint relay? either with rssi or gps position as the heuristic in selecting the relay set)

Sure, I like the idea of having intelligent flooding. I'm curious to see what you would come up with.

Finally, I agree with the comments about the 6 byte address being to long, I mostly used it out of convenience. I like @beegee-tokyo idea for a 4 byte node address. I may implement this soon since it will break backwards compatibility and I already have one recent change that broke backwards compatibility, so I might as well make them both at the same time.

btw: here's my general (not an expert) thinking on mesh routing (and the various approaches listed are more just notes than real ideas): https://github.com/meshtastic/Meshtastic-esp32/blob/master/docs/software/mesh-alg.md

I initially used the RadioHead mesh implementation (which seems to be a clone of data source routing). MPR seems to be similar to naive flooding, except with heuristics to preselect a limited set of relay nodes. I'd probably start with rssi as a quick proxy for link quality.

I made a ESP OTA update from Android app in another project, but it used WiFi, not BLE. But I can look into the possibility to add it to the current Android app.

For the usage of another LoRa library, I had a problem when testing DisasterRadio, because I have only 1 RFM95 module, but plenty of devices with a Semtech SX1262 LoRa transceiver. What I did was to write a wrapper around my SX126x-Arduino library that geve the same function calls as the DisasterRadio's LoRa lib. Worked perfectly and was not much effort. Maybe a simple way to use @geeksville LoRa lib.

Not as perfect as your mesh routers, but I am working on my own LoRa Mesh utilizing the SX126x LoRa chips and it works ok so far (testing with 6 to 12 nodes only). The mesh allows both addressed and broadcast messages and detects disconnected nodes. But it is very specific for the SX126x chips and FreeRTOS. It runs on Nordic nRF52 and Espressif ESP32.

@beegee-tokyo cool beans. I took at look at your new project: https://github.com/beegee-tokyo/Emy-Chat

Any interest in joining up and we share effort? It seems like we have almost identical desires in our recreational futzing. It is a fun/friendly/chill project. ;-)

(alternatively, @beegee-tokyo, could I have your email address? mine is kevinh@geeksville.com)

@geeksville
Interesting project, but I have right now no time to seriously jump into another challenge. Even DisasterRadio is not on my priority list right now. I just jumped in for the Android app.

@beegee-tokyo we also have an android app that could be yours to do with as you wish ;-) https://github.com/meshtastic/Meshtastic-Android/

But do whatever you enjoy!

I think next week I'll finally have time to work on this (my meshtastic time got sucked into user report based bugfixing and being out six days with mystery disease). I'll port it to have an adapter so it can work with my RF95 class and change our app to use it rather than our current solution.

Ya'll okay with me changing the addressing to be 4 byte node addrs?

@paidforby do you have a test app I should use to make sure I didn't break anything?

I think next week I'll finally have time to work on this (my meshtastic time got sucked into user report based bugfixing and being out six days with mystery disease). I'll port it to have an adapter so it can work with my RF95 class and change our app to use it rather than our current solution.

Awesome! Good luck, let me know if you need any help adapting it you your platform.

Ya'll okay with me changing the addressing to be 4 byte node addrs?

Go for it. I was gonna attack this myself sometime soon, but if you get to it first then great.

@paidforby do you have a test app I should use to make sure I didn't break anything?

When you change to 4-byte addresses, it will break lots of functionality until I update the Layer 3 code to work with 4-byte addresses also.

Once you have it working for yourself, then make a pull request and I will review it, test existing disaster.radio functionality, and resolve any conflicts with minimal changes.

@geeksville see d533eea
I've updated LoRaLayer2 to use 4 byte addresses. I have tested this with the full disaster radio firmware and it appears to be working.

@geeksville fyi, I just created a very simple example. When you start working on your merge you can test that LoRaLayer2 is still working by flashing the router_beacon example to a device and confirming that the fake node address (which defaults to c0d3f00d) appears the routing tables of your other devices.

@paidforby cool beans! I'm (finally) working on this now. I should have something for you to review in a few days.

/me leaves a note to follow a discussion amongst LoRa mesh implementors.
(the HeyMac protocol I'm working on)

@paidforby

A few questions questions (I'm working on this now):

  • Is it okay if I change the Layer1 API to be asynchronous and with no polling? (I'm assuming yes) I need to do this to keep low battery draw (i.e. no polling from loop() to check for rx packets, and allowing sends/receives to complete asynchronously.
  • What targets does this lib run on, i.e. do all of the real (not sim) targets have FreeRTOS at the bottom?
  • I'll expose an asyncronous/poll-free layer2 API. And make a syncronous wrapper that looks like the current layer2 API. Fine?
  • Is it okay if I change the Layer1 API to be asynchronous and with no polling? (I'm assuming yes) I need to do this to keep low battery draw (i.e. no polling from loop() to check for rx packets, and allowing sends/receives to complete asynchronously.

Sure, I wasn't familiar with how to make it Layer1 fully async, but that would be great if it was.

  • What targets does this lib run on, i.e. do all of the real (not sim) targets have FreeRTOS at the bottom?

The only target it must run on is the ESP32. So believe the answer to your question is yes.

  • I'll expose an asyncronous/poll-free layer2 API. And make a syncronous wrapper that looks like the current layer2 API. Fine?

That's fine with me, I would probably just switch to using the async API once you create it. But this sounds like a good way to start.

Note, that I just pushed some changes today, mostly just replaced the push/pop buffers with fifo buffers and cleaned up and reorganized the code. Hopefully it helps.

sounds good. btw - this is the plan/branch I'm going from. I hope to have a PR for you by Friday.

https://github.com/geeksville/Meshtastic-esp32/blob/removeradiohead/src/rf95/kh-todo.txt

Alas. I have some bad news. As I got into the process of mergifying our code I realized I underestimated the size of the task. I don't think I'll be able to sign up for this after all. Sorry for wasting your time in this discussion :-(.

As it turns out my fork of RadioHead gets a lot of benefit from depending on Protocol Buffers (also they are great for things like node addresses because PBs nicely compress uint32s down to a smaller number of bits when possible. The process of taking those concepts out and changing to your layer2 was beginning to look like a lot more work to instead just doing a simple implementation of DSR (cribbing from the existing radiohead version and RFC 4728). So I'm just going to implement a subset of DSR (+ naive flooding). DSR also seems nicer for my usecase (a generally quiet network very concerned about battery life) vs your algorithm (which periodically shares updated routing tables). I will make this available as a library in case it is useful for any other project.

So I don't think I'll be able to merge after all.

I totally understand. I'm going to look into implementing something like DSR in LL2 based on comments in other issues. I'm guessing it will take me some time, so don't hold your breath.