Optimized high speed nRF24L01+ driver class documentation v1.4.8
TMRh20 2020 - Optimized fork of the nRF24L01+ driver
Loading...
Searching...
No Matches
examples_linux/multiceiver_demo.py

Written by 2bndy5 in 2020

This is a simple example of using the RF24 class on a Raspberry Pi for using 1 nRF24L01 to receive data from up to 6 other transceivers. This technique is called "multiceiver" in the datasheet.

Remember to install the Python wrapper, then navigate to the "RF24/examples_linux" folder.
To run this example, enter

python3 multiceiver_demo.py

and follow the prompts.

Note
this example requires python v3.7 or newer because it measures transmission time with time.monotonic_ns().
1"""
2A simple example of sending data from as many as 6 nRF24L01 transceivers to
31 receiving transceiver. This technique is trademarked by
4Nordic Semiconductors as "MultiCeiver".
5
6This example was written to be used on up to 6 devices acting as TX nodes &
7only 1 device acting as the RX node (that's a maximum of 7 devices).
8
9See documentation at https://nRF24.github.io/RF24
10"""
11
12import time
13import struct
14from RF24 import RF24, RF24_PA_LOW, RF24_DRIVER
15
16print(__file__)
17
18
25CSN_PIN = 0 # GPIO8 aka CE0 on SPI bus 0: /dev/spidev0.0
26if RF24_DRIVER == "MRAA":
27 CE_PIN = 15 # for GPIO22
28elif RF24_DRIVER == "wiringPi":
29 CE_PIN = 3 # for GPIO22
30else:
31 CE_PIN = 22
32radio = RF24(CE_PIN, CSN_PIN)
33
34# initialize the nRF24L01 on the spi bus
35if not radio.begin():
36 raise RuntimeError("radio hardware is not responding")
37
38# set the Power Amplifier level to -12 dBm since this test example is
39# usually run with nRF24L01 transceivers in close proximity of each other
40radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default
41
42# To save time during transmission, we'll set the payload size to be only what
43# we need.
44# 2 int occupy 8 bytes in memory using struct.pack()
45# "ii" means 2 unsigned integers
46radio.payloadSize = struct.calcsize("ii")
47
48# for debugging, we have 2 options that print a large block of details
49# radio.printDetails(); # (smaller) function that prints raw register values
50# radio.printPrettyDetails(); # (larger) function that prints human readable data
51
52# setup the addresses for all transmitting radio nodes
53addresses = [
54 b"\x78" * 5,
55 b"\xf1\xb6\xb5\xb4\xb3",
56 b"\xcd\xb6\xb5\xb4\xb3",
57 b"\xa3\xb6\xb5\xb4\xb3",
58 b"\x0f\xb6\xb5\xb4\xb3",
59 b"\x05\xb6\xb5\xb4\xb3",
60]
61# It is very helpful to think of an address as a path instead of as
62# an identifying device destination
63
64
65def master(node_number):
66 """start transmitting to the base station.
67
68 :param int node_number: the node's identifying index (from the
69 the `addresses` list). This is a required parameter
70 """
71 # According to the datasheet, the auto-retry features's delay value should
72 # be "skewed" to allow the RX node to receive 1 transmission at a time.
73 # So, use varying delay between retry attempts and 15 (at most) retry attempts
74 radio.setRetries(
75 ((node_number * 3) % 12) + 3, 15
76 ) # maximum value is 15 for both args
77
78 radio.stopListening() # put radio in TX mode
79 # set the TX address to the address of the base station.
80 radio.openWritingPipe(addresses[node_number])
81 counter = 0
82 failures = 0
83 while failures < 6:
84 counter += 1
85 # payloads will include the node_number and a payload ID character
86 payload = struct.pack("<ii", node_number, counter)
87 start_timer = time.monotonic_ns()
88 report = radio.write(payload)
89 end_timer = time.monotonic_ns()
90 # show something to see it isn't frozen
91 print(
92 f"Transmission of payloadID {counter} as node {node_number}",
93 end=" ",
94 )
95 if report:
96 print(
97 f"successful! Time to transmit = {(end_timer - start_timer) / 1000} us"
98 )
99 else:
100 failures += 1
101 print("failed or timed out")
102 time.sleep(1) # slow down the test for readability
103 print(failures, "failures detected. Leaving TX role.")
104
105
106def slave(timeout: int = 10):
107 """Use the radio as a base station for listening to all nodes
108
109 :param int timeout: The number of seconds to wait (with no transmission)
110 until exiting function.
111 """
112 # write the addresses to all pipes.
113 for pipe_n, addr in enumerate(addresses):
114 radio.openReadingPipe(pipe_n, addr)
115 radio.startListening() # put radio in RX mode
116 start_timer = time.monotonic() # start timer
117 while time.monotonic() - start_timer < timeout:
118 has_payload, pipe_number = radio.available_pipe()
119 if has_payload:
120 # unpack payload
121 node_id, payload_id = struct.unpack("<ii", radio.read(radio.payloadSize))
122 # show the pipe number that received the payload
123 print(
124 f"Received {radio.payloadSize} bytes",
125 f"on pipe {pipe_number} from node {node_id}.",
126 f"PayloadID: {payload_id}",
127 )
128 start_timer = time.monotonic() # reset timer with every payload
129
130 print("Nothing received in", timeout, "seconds. Leaving RX role")
131 radio.stopListening()
132
133
134def set_role() -> bool:
135 """Set the role using stdin stream. Timeout arg for slave() can be
136 specified using a space delimiter (e.g. 'R 10' calls `slave(10)`)
137
138 :return:
139 - True when role is complete & app should continue running.
140 - False when app should exit
141 """
142 user_input = (
143 input(
144 "*** Enter 'R' for receiver role.\n"
145 "*** Enter a number in range [0, 5] to use a specific node ID for "
146 "transmitter role.\n"
147 "*** Enter 'Q' to quit example.\n"
148 )
149 or "?"
150 )
151 user_input = user_input.split()
152 if user_input[0].upper().startswith("R"):
153 if len(user_input) > 1:
154 slave(int(user_input[1]))
155 else:
156 slave()
157 return True
158 if user_input[0].isdigit() and 0 <= int(user_input[0]) <= 5:
159 master(int(user_input[0]))
160 return True
161 if user_input[0].upper().startswith("Q"):
162 radio.powerDown()
163 return False
164 print(user_input[0], "is an unrecognized input. Please try again.")
165 return set_role()
166
167
168if __name__ == "__main__":
169 try:
170 while set_role():
171 pass # continue example until 'Q' is entered
172 except KeyboardInterrupt:
173 print(" Keyboard Interrupt detected. Powering down radio.")
174 radio.powerDown()
175else:
176 print(" Run slave() on the receiver")
177 print(" Run master(node_number) on a transmitter")
178 print(" master()'s parameter, `node_number`, must be in range [0, 5]")
Driver class for nRF24L01(+) 2.4GHz Wireless Transceiver.
Definition RF24.h:116