433MHz RF “Hello World” on the Raspberry Pi
When most people hear the term wireless, they think of Wifi or Bluetooth. Of course our daily lives would be much different without Wifi…
When most people hear the term wireless, they think of WiFi or Bluetooth. Of course, our daily lives would be much different without WiFi and Bluetooth, but radio communication is another large powerhouse that makers should have in their back pockets. There are a ton of great options for getting started in radio communication. One of my favorite sources for electronic supplies, Adafruit, recently restocked their Radio Bonnets with OLED displays. So I decided to pick up a couple and get an RF equivalent of “Hello World” up and running on it using my overflowing stock of Raspberry Pis.
Adafruit’s Radio Bonnets come in a few different flavors. I chose the RFM69 at 433MHz version (note: you have to choose the same frequency for radios you want to communicate with each other). The radio chip itself, the RFM69, is available on several different breakout/dev boards, but I found the Radio Bonnet to be the most getting started friendly because of it’s OLED display that can be utilized for status messages (I’m talking to you, printf debuggers) and the three push buttons on the front that can be used to trigger events such as packet transmissions.
First things first, the Raspberry Pi needs a bit of setup. The RFM69 chip talks to a microcontroller via an SPI interface and with the later versions of Raspbian, the SPI interface on the Raspberry Pi is disabled by default. Assuming you haven’t already enabled the SPI interface for another project, run the configuration application as super user to enable it, then navigate to the SPI option under Interfacing Options to select ‘Yes’ to enable.
Now that the Raspberry Pi is pretty much ready to go, the Radio Bonnet needed some hardware and software setup.
For the antenna, there are several options but for beginners I strongly recommend going the “hard-wired” route. This means you don’t have to worry about any sort of FCC restrictions (433MHz is in a band designated for amateur use, but there are still ways you can get yourself in trouble if you don’t know what you’re doing). The antenna port on the Radio Bonnets is an extremely small RF connector know as a U.FL connector. Adafruit also stocks a U.FL to female SMA cable that I bought two of. I then picked up a male-to-male SMA adapter from Fairview Microwave (one of my preferred source for RF components).
Along with my nifty stacking case for my Raspberry Pis, my “hard-wired” antenna setup looked like this:
The RFM69 is operated by a microcontroller using an object-oriented library that packetizes messages for transmission and reception known as RadioHead. The RadioHead library is open-source and supports a variety of radios and transceivers that many have written driver libraries for. Since the RFM69 is a pretty popular transceiver, there are quite a few libraries that have popped up for it. Adafruit has done it’s own version using their CircuitPython framework. While it’s a very basic implementation of the RadioHead library in that it only handles “raw” packets and doesn’t perform any of the more complex RadioHead functionalities of guaranteed delivery via retransmission, variable message length acknowledgements, multi-hop delivery, etc., it is very well checked out and has good documentation.
To install the CircuitPython library, both the SPI and the I2C peripheral interfaces need to be enabled on the Raspberry Pi, which we already enabled the SPI interface using the configuration application earlier and you can run it again if you haven’t already enabled the I2C interface. CircuitPython uses Python 3 and the Raspberry Pi GPIO library. If you don’t have either installed yet, simply run the following:
sudo apt-get install python3-pip
pip3 install RPI.GPIO
In order to work with the OLED display on the Radio Bonnets, you’ll also need to install the library for that particular display along with the framebuf module (which is the library that is used to create the bitmap images to be sent to the display):
pip3 install adafruit-circuitpython-ssd1306
pip3 install adafruit-circuitpython-framebuf
To support the font to print messages out to the OLED of the Radio Bonnet, download the bin file Adafruit provides nd place it in the same directory as your scripts for the Radio Bonnet.
And finally, install the CircuitPython library for the RFM69 module itself:
pip3 install adafruit-circuitpython-rfm69
For the scripts to be run on each of the radios, it made sense to designate one radio as the ‘transmitter’ and the other radio as the ‘receiver’. The transmitter radio sends a packet that is a utf-8 string saying “Hello World” while the receiver radio is set in a perpetual listening state until it receives the “Hello World” packet. Upon receiving the “Hello World” packet, the receiver radio then transmits back a packet of utf-8 string type saying “ACK” as an acknowledgement back to the transmitter that has been waiting to receive that ack packet before it sends the “Hello World” packet again. It is important to note that timing is a huge thing to keep in mind when sending and receiving RF signals, especially when working with a more bare bones/simplistic library such as this one.
Since the Adafruit version of the RFM69 RadioHead library is done completely in Python, there isn’t a interrupt system. This means that if packets are sent back to back too quickly while the receiver radio is still processing the previous packet, the incoming packet(s) will be lost. Additionally, if the receiver radio isn’t quite ready for the incoming packet and detects it part of the way through the transmission, this will result in that incoming packet being dropped.
For these reasons, take note of the way I’ve structured my scripts between the transmitter and receiver radios, which you can download from my GitHub here.
Right after I send the “Hello World” packet out in the transmitter script I enter a loop waiting for the ACK packet, but that loop also has a counter timeout on it. This is to prevent the transmitter for being stuck waiting indefinitely for that ACK packet in the event that the receiver dropped the last “Hello World” packet that was sent. If the counter times out before the ACK packet is received, then the transmitter knows to go ahead and try resending the “Hello World” packet.
In contrast, on the receiver script, I have it wait indefinitely while the incoming packet variable is null. This prevents the receiver from getting into a state where it is trying to send an acknowledgment packet at the same time as the transmitter is sending a “Hello World” packet.
I mentioned earlier that for two radio modules to be able to talk to each other, they need to be the same frequency, but RadioHead also necessitates that they also need to have the same encryption key specified, even if it’s None. If you are using my scripts and want to change the encryption key from None, just be sure to change it on both the receiver and transmitter.
Because of the way I structured the receiver and transmitter scripts, I didn’t have to worry about which script on which Raspberry Pi I started first or how soon I needed to start the second script on the other Raspberry Pi after I ran the first one. Here are a few photos of the setup in action:
As always, these getting started blogs are meant for you to expand on. Download my scripts and add on to them! You can start playing around with the different modulation schemes the RFM69 supports, experiment with packet structures, etc. (just to give you a couple of ideas).
All thoughts/opinions are my own and do not reflect those of any company/entity I currently/previously associate with.