Wireless Pi to Pi Communication with NRF24L01+

The NRF24L01+ is a popular transceiver among hobbyists known for its ease of use, very long distance range for communication and inexpensive nature. The NRF24L01+ boasts a communication range of over a kilometer when using the power amplified version and having a clear line of sight. Even low end units can achieve 30m ranges. In this tutorial I show you how to establish communication between two Raspberry Pis using the NRF24L01+ transceiver.

This tutorial is a little older (published in 2016!). The main principles are still relevant, so I haven't needed to update this lesson.


DIFFICULTY
DIFFICULT
CIRCUITRY KNOWLEDGE
LITTLE
PYTHON PROGRAMMING
SOME
ABOUT
0
MINUTES
  • How to connect a NRF24L01+ transceiver to a Raspberry Pi
  • How to send a message from a nRF24L01+
  • How to receive a message from a nRF24L01+ on a Raspberry Pi
You can copy / paste the code below if you’re having issues with typos or want a shortcut. However I recommend that you follow along in the tutorial to understand what is going on!

recv.py


import RPi.GPIO as GPIO
from lib_nrf24 import NRF24
import time
import spidev

GPIO.setmode(GPIO.BCM)

pipes = [[0xe7, 0xe7, 0xe7, 0xe7, 0xe7], [0xc2, 0xc2, 0xc2, 0xc2, 0xc2]]

radio = NRF24(GPIO, spidev.SpiDev())
radio.begin(0, 17)
radio.setPayloadSize(32)
radio.setChannel(0x60)

radio.setDataRate(NRF24.BR_2MBPS)
radio.setPALevel(NRF24.PA_MIN)
radio.setAutoAck(True)
radio.enableDynamicPayloads()
radio.enableAckPayload()

radio.openReadingPipe(1, pipes[1])
radio.printDetails()

radio.startListening()

while True:
    ackPL = [1]
    while not radio.available(0):
        time.sleep(1/100)

    receivedMessage = []
    radio.read(receivedMessage, radio.getDynamicPayloadSize())
    print("Received: {}".format(receivedMessage))

    print("Translating the receivedMessage into unicode characters...")
    string = ""
    for n in receivedMessage:
        # Decode into standard unicode set
        if (n >=32 and n <= 126):
            string += chr(n)
    print(string)

    radio.writeAckPayload(1, ackPL, len(ackPL))
    print("Loaded payload reply of {}".format(ackPL))    

#>

slave.py


import RPi.GPIO as GPIO
from lib_nrf24 import NRF24
import time
import spidev

GPIO.setmode(GPIO.BCM)

pipes = [[0xe7, 0xe7, 0xe7, 0xe7, 0xe7], [0xc2, 0xc2, 0xc2, 0xc2, 0xc2]]

radio = NRF24(GPIO, spidev.SpiDev())
radio.begin(0, 17)
radio.setPayloadSize(32)
radio.setChannel(0x60)

radio.setDataRate(NRF24.BR_2MBPS)
radio.setPALevel(NRF24.PA_MIN)
radio.setAutoAck(True)
radio.enableDynamicPayloads()
radio.enableAckPayload()

radio.openWritingPipe(pipes[0])
radio.openReadingPipe(1, pipes[1])
radio.printDetails()

radio.startListening()

def getTemp():
    temp = 25
    return str(temp)

def sendData(ID, value):
    radio.stopListening()
    time.sleep(0.25)
    message = list(ID) + list(value)
    print("About to send the message.")
    radio.write(message)
    print("Sent the data.")
    radio.startListening()

while True:
    ackPL = [1]
    radio.writeAckPayload(1, ackPL, len(ackPL))
    while not radio.available(0):
        time.sleep(1/100)

    receivedMessage = []
    radio.read(receivedMessage, radio.getDynamicPayloadSize())
    print("Received: {}".format(receivedMessage))

    print("Translating the receivedMessage into unicode characters...")
    string = ""
    for n in receivedMessage:
        # Decode into standard unicode set
        if (n >=32 and n <= 126):
            string += chr(n)
    print(string)

    # We want to react to the command from the master.
    command = string
    if command == "GET_TEMP":
        print("We should get the temperature!")
        tempID = "temp_"
        temp = getTemp()
        sendData(tempID, temp)
    command = ""

    radio.writeAckPayload(1, ackPL, len(ackPL))
    print("Loaded payload reply of {}".format(ackPL))

#>

master.py


import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
from lib_nrf24 import NRF24
import time
import spidev

pipes = [[0xe7, 0xe7, 0xe7, 0xe7, 0xe7], [0xc2, 0xc2, 0xc2, 0xc2, 0xc2]]

radio = NRF24(GPIO, spidev.SpiDev())
radio.begin(0, 17)

radio.setRetries(15,15)
radio.setPayloadSize(32)
radio.setChannel(0x60)
radio.setDataRate(NRF24.BR_2MBPS)
radio.setPALevel(NRF24.PA_MIN)
radio.setAutoAck(True)
radio.enableDynamicPayloads()
radio.enableAckPayload()

radio.openWritingPipe(pipes[1])
radio.openReadingPipe(1, pipes[0])
radio.printDetails()

ackPL = [1]

def receiveData():
    print("Ready to receive data.")
    radio.startListening()
    pipe = [0]
    while not radio.available(pipe):
        time.sleep(1/100)
    receivedMessage = []
    radio.read(receivedMessage, radio.getDynamicPayloadSize())

    print("Translating the receivedMessage to unicode characters...")
    string = ""
    for n in receivedMessage:
        # We want to only decode standard symbols/alphabet/numerals
        # Based off unicode standards, our encoding method
        if (n >= 32 and n <= 126):
            string += chr(n)
    print("Our sensor sent us: {}".format(string))
    radio.stopListening()

while True:
    command = "GET_TEMP"
    message = &#91;&#93;
    message = list(command)

    # send a packet to receiver
    radio.write(message)
    print("Sent: {}".format(message))

    # did it return with a payload?
    if radio.isAckPayloadAvailable():
        pl_buffer=&#91;&#93;
        radio.read(pl_buffer, radio.getDynamicPayloadSize())
        print(pl_buffer)
        print("Translating the acknowledgement to unicode characters...")
        string = ""
        for n in pl_buffer:
            # We want to only decode standard symbols/alphabet/numerals
            # Based off unicode standards, our encoding method
            if (n >= 32 and n <= 126):
                string += chr(n)
        print(string)
        # So our command was received and acknowledged. We should
        # setup ourselves to receive what that temperature was.
        receiveData()
    else:
        print("No received acknowledgement.")
    time.sleep(0.5)
#>

Tutorial 32

Tutorial 33