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