Monday, May 27, 2013

Raspberry pi: nRF24L01 and TCP

This time I will describe how I got a Raspberry pi (Wheezy) to work as a Python server that controls a RF-transmitter (nRF24L01). The server takes commands either from a TCP connection (internet) or via the keyboard, and broadcasts the data through the RF-transmitter to the receivers i have set up in my home automation system. See my other posts covering how to use the nRF with an AVR, and the construction of a multi-functional remote control.

Why use a Raspberry pi when i already have a working TCP-server on my PC?

Easy answered:

I do not like to have my PC up and running 24-7 due to the facts that it's noisy (stationed in my bedroom)

The RPi takes much less energy (runs on a 1000mA cellphone charger)

I don't need any other parts other than a RPi, a nRF24L01(+) and cables, since the RPi has a 3,3V power supply!

Setting up SPI on RPi

First of all, you must have a working copy of raspbian, I use Wheezy (made a small tutorial in how to set it up). The RPi has a built in hardware SPI, which we first has to get up and running according to this guide, and here is how i did it:

Start a terminal like the LXTerminal and follow these commands:

To check if the SPI is working (optional) you can connect the mosi-pin to the miso-pin (GPIO10 and 9, see picture), and run the commands in a terminal:

Quick2Wire

Quick2Wire is a tool that makes it possible to control the GPIO and the SPI via python. We need to install quick2wire, download the quick2wire python plugin (API) and gain root access to the spi.
Start by downloading the plugin from there website. Extract the zip-file by right clicking and unzip. Now open a terminal window and change directory so that you are in the extracted folder called "quick2wire-gpio-admin-master" then enter the following commands:

Now log out from the RPi and back in again. The power button at the bottom right quorner has the option to log out. Log back in by typing your username "pi"/enter, then your code "raspberry"/enter...

To gain root access for the SPI so that you dont have to use the "sudo" command in front of every bit of code, I followed this guide, which tells you to do this:

Finnish by remove and reattach the power cable to restart.

Python 3

Now it's time to install python3 which is needed to run the code. Open a terminal and run these commands:

Now to use quick2wire with python, you need the python API which can be downloaded from this site. Download it, and unpack it to a location on you SD-card (no installation required!)

I think the CE-pin should work on a different pin (it would be convenient to put it on GPIO25) since it doesn't have anything to do with the SPI, but I haven't tried that yet...

The python programs

I got the basic nrf python code from this program (plus a lot of help with the steps above) from Jussi Kinnunen, all creds to him!
Download my version of the program, as well as my TCP-server program. which is well commented to make it easy to understand. You see the codes below:

nRF24L01p.py

TCP_Server.py

To run the program, create a third file, and name it to something like "a.sh", the ending "sh" means shell file, which is runnable. Fill the file with these commands:
(change the path "/home/pi/" to where you have the quick2wire-folder!)

This will make sure the path is imported every time the script is run! If anyone knows how to permanently add the path, please tell me in the comment field!

To run the program, all you have to do now is to set the working path in the terminal to where you store the a.sh-file with the cd-command and type

This is a screenshot from the code running in the terminal:

As you can see, the program starts by asking if you want to run it as "rx" (Receiver) or "tx" (transmitter). I chose transmitter by typing "tx"/enter.
Then it prints out all the registers that the code changes (or sets) and then starts a server loop in a background thread (TCP).
When this is done the program waits for either the user to type in data to send (3 bytes in my example), or for a command from the TCP-server.
In the picture above, you can see that i started by typing "123" on the keyboard, which was sent to the nRF and broadcasted to any nRF-receiver with address 0x12. As you can see the STATUS register after the broadcast tells me that the transmission failed (0x1E), since i don't have a receiver running at the moment... a working transmission would give the result "0x2E" (when the EN_AA is turned on)!

The second thing I did was to send the command "300" to the TCP-server from my home-made android application (can be sent form any TCP-client with the right port number). The TCP-server then calls the nRF24L01p.py and transmits the data like it was inputted with the keyboard.

If a (large) error shows up when you try to run the code, which tells you something about "cannot export the pin number 18 because it is already exported", run the following command in the terminal:

If an error shoes up that tells you that the address is occupied, the TCP-server has not closed yet, and you have to sit down and wait for up to 1min before you try again (I know you can change this timing, but haven't come so far)

If you have any questions or just want to tell me what you think of the blog, just give me a comment in the comment field underneath...
/Kalle

Hi!Thanks for the note about the names, I have now updated the codes to working names... (my original file names are in Swedish...)

I have a working setup at the moment, where a couple of AVRs (Atmega88 and Attiny26) are connected to nRFs that are in receiving mode, and it is working without problem! You can see the basics of the code in my previous blog post(http://gizmosnack.blogspot.se/2013/04/tutorial-nrf24l01-and-avr.html), and a code-example (for a AVR-nrf-transmitter) is found on this link: https://gist.github.com/klalle/5652658

Do you have a working SPI-setup between the RPi and the nRF with my python script?

So, SPI is working when I use your test. One thing I noticed is that your screenshot says "STATUS.........[0x0E]" when you start the program and also says "STATUS before..[0x0E]" while mine says "STATUS before..[0x1E]" in both cases. Maybe this is a hint to the problem? Thanks in advance from Hamburg, Jens

The "1" indicates that the "MAX_RT" is set, which is the flag that tells you that maximum number of transmitting retries has occurred. Could it be a problem with the CE-pin? is it connected to the right GPIO (which is set to 0V)? try connecting the CE-pin to GND instead, run the program, and see if it still returns 0x1E!

It must be the same thing, since the code is working on my rpi!I have a program that changes the address on the fly, and it certainly works =)Did you try to ground the CE-pin on the nRF and run the code?

Hi, I see that both of us shared similar interests of nRF24L01, raspberry pi and AVR (Arduino) ... On my blog at almost similar period, I have written on how to get Raspberry Pi, Arduino & attiny85 working on the nRF24L01+ wireless module... and a few more articles on the nRF24L01...

We should exchange knowledge/email and do further improvements to these radios...

Hi Stanley!Nice to see you have found my blog!I actually started out with you code, but fell in love with the simplicity of the pyton program that Jussi Kinnunen had written... I will link your blog! /Kalle

Hi!I don't really understand what you are doing there.. I cannot see how your raspberry (or arduino) can detect if you are using the + version or not? And why should that be a problem? You are clearly not using my bit of python code, and I have seen other codes using other pin configurations, like this for example: http://arduino-for-beginners.blogspot.se/2013/02/setup-nordic-nrf24l01-rf-modules-to.htmlgood luck with

Thanks for the notice! I havent actually used the code as a receiver, I just wrote some code that would probably work...

I still think it is supposed to be "4E"!The code first checks if ANY flag is set in the status registry (if not "0E"), then it checks if it is the "RX_DR" (sets high when data arrives) flag, which is bit number 6 in the status registry. We are looking if the status looks like "4E" which equals 0b01001110.

Hi, i'm trying to get it work my Arduino project with your code, but i can't!

Here's my Arduino code: http://pastebin.com/c102ENFR

Can you please tell me how to set the settings variables in the .py script to get it work?I have a C program that works with CE in the pin 24, but i moved my CE pin to 12 but i guess it's not working. I Always receive wrong data conf when i launch the script, and it always print STATUS[0x00] or [0xFF], even though i'm sending nothing.

im very new to the entire scene of electronics and im a bit confused about the communication between the different nRFs, how do you define the address of each node? SET_RX_ADDR_P0 & SET_TX_ADDR ? and if i have more nodes ?

Well, there are many different ways to do this! In the example above (see colored code: https://gist.github.com/klalle/5658484) i am just using the P0-channel, and to communicate with different nodes (which I have programmed to the same P0-channel but with different addresses), I could simply call the "changeAddress()" function with the corresponding address to the node i want to communicate with, before I send the data!

The above code is just an example for you to see how you can use the functions i programmed...

It runs fine until my transmitting node actually sends content, then it blows up with that message. I think I did all the steps that would allow for the automated permissions setting, but I could have messed something up. Can you offer me any advice at all?