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