nRF24 / CircuitPython_nRF24L01

CircuitPython driver library for the nRF24L01 transceiver.
http://circuitpython-nrf24l01.rtfd.io/
MIT License
45 stars 11 forks source link

Mesh #45

Closed conaito closed 6 months ago

conaito commented 1 year ago

hi, i try the network / mesh example between 2 pico boards but not get the mesh working... i try 1 node with Y > 0 and 2nd with Y > 1.. it will not connect to the mesh master. With 1 node as arduino and c++ code it connect to the mesh mast well. If i try just Network it works well togehter. ANy idea here? May i try it in wrong way using your example?

conaito commented 1 year ago

I try the mesh with 2 pico (circuitpython mesh example) and 1x arduino with c++. As soon the arduino is connect to the master then also the 2nd pico can connect. Thats strange. Can you help me to get the example working with just the 2 circuitpython?

2bndy5 commented 1 year ago

The quick answer is that the circuitpython firmware runs slower than the C++ examples.

I documented the connection process in the topology page of the docs. What you're experiencing is a common point of failure (point 2 in the list).

I'm not sure what the best solution is here. Essentially the master node needs to have a slight delay so the child nodes on network level 1 have enough time to switch back to RX mode and complete the pairing process.


Are these nodes not stationary? Is that why RF24Network is insufficient for your application?

conaito commented 1 year ago

It means its not possible to connect 2 picos with circuitpython by Mesh? (1 is master and 2nd is a child)

I want use mesh because i not want setup octal node id´s. it should hold it simple by simple set on a child nodes 1,2,3,4 etc

conaito commented 1 year ago

btw if i not use Mesh (in exmaple 'N' > 0 and 2nd 'N' >1) it works great

2bndy5 commented 1 year ago

RF24Network is much more reliable for nodes that don't physically move around. RF24Mesh is designed for nodes that do physically move around, but the connecting process is flawed because the process doesn't use auto-ack. Transmissions in RF24Mesh will also be slower because the octal address has to be fetched from the master node before any the message can be sent to the actual destination.

2bndy5 commented 1 year ago

The actual line of code that is failing in the master is here: https://github.com/nRF24/CircuitPython_nRF24L01/blob/c73978c954d074cebd1337227dbc7ae08fbda51c/circuitpython_nrf24l01/rf24_mesh.py#L373

You could try doubling that call so it transmits twice:

                    self._write(self.frame_buf.header.to_node, TX_PHYSICAL)
                    self._write(self.frame_buf.header.to_node, TX_PHYSICAL)

Hopefully that will give the child enough time to receive the the response from master and complete the process.

conaito commented 1 year ago

ok i will try that tomorrow.

If i use network instead, is there a way to automatically give the child nodes id on connect to master or a similar workaround to not need to set node id on each child into the code?

also, how is the best way to send a message to all childs? just by a loop only possible or exist a function already for? Am 7. Nov. 2022, 17:05 +0100 schrieb Brendan @.***>:

The actual line of code that is failing in the master is here: https://github.com/nRF24/CircuitPython_nRF24L01/blob/c73978c954d074cebd1337227dbc7ae08fbda51c/circuitpython_nrf24l01/rf24_mesh.py#L373 You could try doubling that call so it transmits twice: self._write(self.frame_buf.header.to_node, TX_PHYSICAL) self._write(self.frame_buf.header.to_node, TX_PHYSICAL) Hopefully that will give the child enough time to receive the the response from master and complete the process). — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.Message ID: @.***>

2bndy5 commented 1 year ago

is there a way to automatically give the child nodes id on connect to master or a similar workaround to not need to set node id on each child into the code?

No, you need to assign a unique id to each node in the network. There is no way around that.

how is the best way to send a message to all childs?

This is called "multicasting". You can enable multicast_relay and use multicast(). Beware that auto-ack is disabled for multicasting, so there is no guarantee that the message is received by all nodes.

conaito commented 1 year ago

on multicast how can i send to all nodes without worry to set the correct level of the child nodes? basically to all childs not depend on level they are Am 7. Nov. 2022, 17:24 +0100 schrieb Brendan @.***>:

is there a way to automatically give the child nodes id on connect to master or a similar workaround to not need to set node id on each child into the code? No, you need to assign a unique id to each node in the network. There is no way around that. how is the best way to send a message to all childs? This is called "multicasting". You can enable multicast_relay and use multicast(). Beware that auto-ack is disabled for multicasting, so there is no guarantee that the message is received by all nodes. — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.Message ID: @.***>

2bndy5 commented 1 year ago

I suppose there should be an example code snippet in the docs for this...

From master node, you just need to

mesh_node.multicast(payload, 0, level=1)

this broadcasts the payload to all child nodes on level 1. If multicast_relay is set to True (on all child nodes in level 1), then the payload is re-broadcasted to all child nodes on level 2. I think you get the idea from there.

TMRh20 commented 1 year ago

Typically you don’t want to enable multicast relay with RF24Mesh it will interfere with mesh functionality. You would need to manually relay multicast packets

On Nov 7, 2022, at 10:55 AM, Brendan @.***> wrote:

 I suppose there should be an example code snippet in the docs for this...

From master node, you just need to

mesh_node.multicast(payload, 0, level=1) this broadcasts the payload to all child nodes on level 1. If multicast_relay is set to True (on all child nodes in level 1), then the payload is re-broadcasted to all child nodes on level 2. I think you get the idea from there.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you are subscribed to this thread.

conaito commented 1 year ago

it means if i require multicast (what i need) then its better to go with Network instead Mesh?

Is in Network a function available to get a list of all registered childs at master? Am 7. Nov. 2022, 18:55 +0100 schrieb TMRh20 @.***>:

Typically you don’t want to enable multicast relay with RF24Mesh it will interfere with mesh functionality. You would need to manually relay multicast packets

On Nov 7, 2022, at 10:55 AM, Brendan @.***> wrote:

I suppose there should be an example code snippet in the docs for this...

From master node, you just need to

mesh_node.multicast(payload, 0, level=1) this broadcasts the payload to all child nodes on level 1. If multicast_relay is set to True (on all child nodes in level 1), then the payload is re-broadcasted to all child nodes on level 2. I think you get the idea from there.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you are subscribed to this thread. — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.Message ID: @.***>

TMRh20 commented 1 year ago

Yup

On Nov 7, 2022, at 12:07 PM, conaito @.***> wrote:

 it means if i require multicast (what i need) then its better to go with Network instead Mesh?

Is in Network a function available to get a list of all registered childs at master? Am 7. Nov. 2022, 18:55 +0100 schrieb TMRh20 @.***>:

Typically you don’t want to enable multicast relay with RF24Mesh it will interfere with mesh functionality. You would need to manually relay multicast packets

On Nov 7, 2022, at 10:55 AM, Brendan @.***> wrote:

I suppose there should be an example code snippet in the docs for this...

From master node, you just need to

mesh_node.multicast(payload, 0, level=1) this broadcasts the payload to all child nodes on level 1. If multicast_relay is set to True (on all child nodes in level 1), then the payload is re-broadcasted to all child nodes on level 2. I think you get the idea from there.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you are subscribed to this thread. — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.Message ID: @.***> — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.

2bndy5 commented 1 year ago

Is in Network a function available to get a list of all registered childs at master?

No. RF24Network doesn't need to keep track of node addresses that correspond to node IDs (the RF24Mesh master node's DHCP list). All logical addresses (octal numbers) are static in RF24Network.

conaito commented 1 year ago

Double the line 373 not help :( any other idea? Am 7. Nov. 2022, 23:21 +0100 schrieb Brendan @.***>:

Is in Network a function available to get a list of all registered childs at master? No. RF24Network doesn't need to keep track of node addresses that correspond to node IDs (the RF24Mesh master node's DHCP list). All logical addresses (octal numbers) are static in RF24Network. — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.Message ID: @.***>

2bndy5 commented 1 year ago

Nope, use C++ for nodes on level 1 or switch to RF24Network. There's nothing I can do to speed up CircuitPython's slow execution which is the problem with nodes connecting to master from level 1. Trust me, I invested a lot of time trying to optimize this lib around that limitation.

2bndy5 commented 1 year ago

Just in case I get the time to reproduce this,

  1. What version of CircuitPython are you using?
  2. I assume you're using the latest version of this lib (v2.1.2)?
conaito commented 1 year ago
  1. i use on 1 pico CircuitPython 7.3.3 on the other 8.0.0 beta4
  2. the latest from GIT
  3. at moment i play with the network example (non mesh) and hang on send a string (from emit function).. lets say "b24z" and print it on idle function on other pico. i really not get it working. can you give me small example code for both pico´s? (i know it not really lib depending but it help me a lot)
2bndy5 commented 1 year ago

Honestly, your English is hard to read and understand. I will not write code for you - that is what the documentation is supposed to help with.

If by string you mean "some value", then that is an invalid data type for a payload. Payloads in this lib should only use bytes or bytearray objects.

Please also read the python docs about using struct.pack() or struct.unpack(). I will not teach you on this.

conaito commented 1 year ago

i understand to need follow on sender message = struct.pack("4s", b"cool") but no chance to get it correct unpack on receiver :(

2bndy5 commented 1 year ago

for actual strings, you could use str.encode()

msg = "cool"
nrf.send(msg.encode(encoding="utf-8"))

and then use bytearray.decode() on the receiver.

rcv = nrf.read()
msg = rcv.decode(encoding="utf-8")

raw bytes objects are easy enough to construct, but the functions exist to deal with data that isn't a simple ASCII character.

>>> b"cool" == "cool".encode(encoding="utf-8")
True
2bndy5 commented 1 year ago

Have you tried using the more basic RF24 examples? This should've been your first step in understanding how to use the library. Once you can get the RF24 examples working, then you know its not a radio hardware problem, and you can graduate to networking usage.

conaito commented 1 year ago
  1. thx a lot about the string message sending - works very well and i can work with it.
  2. about Mesh: hopefully you can find the time to figure out why it not working. yes i also tried other samples and it work too except the Mesh example
2bndy5 commented 1 year ago

I already know why it isn't working. I documented the problem as a known point of failure. As stated in the docs:

If a master node is able to respond faster than the connecting node can prepare itself to receive, then the process will fail entirely. This failure about faster master nodes often results in some slower RF24Mesh nodes only being able to connect to the network through another non-master node.

2bndy5 commented 1 year ago

The problem isn't so much about the library's code, rather the real problem is with CircuitPython's slow execution. Its not something I can fix until CircuitPython becomes significantly faster which entirely depends on the MCU board.

The RP2040 is dual core, but that doesn't mean it is the fastest processor (actually about 125-133 MHz). The ESP32 can run at about 240 MHz.

2bndy5 commented 1 year ago

This is a complete hack, but I'm curious if using the auto-ack would help resolve this...

Instead of https://github.com/nRF24/CircuitPython_nRF24L01/blob/c73978c954d074cebd1337227dbc7ae08fbda51c/circuitpython_nrf24l01/rf24_mesh.py#L373 try

                    self._write_to_pipe(self.frame_buf.header.to_node, 1, False)
2bndy5 commented 1 year ago

To be clear, the hack I just posted is meant for the master node, not the child node.

conaito commented 1 year ago

i test it out tomorrow and let you know. thank you Am 8. Nov. 2022, 14:36 +0100 schrieb Brendan @.***>:

To be clear, the hack I just posted is meant for the master node, not the child node. — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.Message ID: @.***>

2bndy5 commented 1 year ago

EDIT: It is a dirty hack. If we bypass _write(), then we need to also put the radio back in RX mode for continued operation. So, I change my suggestion to:

                    self._write_to_pipe(self.frame_buf.header.to_node, 1, False)
                    self.listen = True
                    self._rf24.auto_ack = 0x3E
conaito commented 1 year ago

I tested your latest code. Same.. not connected to Mesh :/

2bndy5 commented 1 year ago

It seems there is no way to reliably fix this within the confines of circuitpython. If we make any changes to this lib, then they should also be added to the RF24Mesh C++ lib because the code for this lib's RF24Mesh and RF24Network is directly ported from the C++ libs.