In mid 2015 I decided to start dabbling with Arduino, and programming in C++. After doing a few introductory exercises (flashing an LED, using a button etc), I decided to tackle making a remote control, using a radio transmitter module called nRF24.

I was naive and didn’t expect it to be so hard! But after a few months I finally worked it out and achieved a working prototype. This was eventually used by one of my students, to animate a sculptural design they’d created for an exhibition.

Here’s two videos of the prototype in action. There’s a bit of a delay in the signal, as well as perhaps the starting-torque for the motors that means you have to turn the dial at least ~half way before the motor starts turning. But, it works!

Some Technical Details

Why Radio Control, RF?

Initially I tried using infrared (IR) remote control. I used an infrared sensor and an Apple remote. This was fine to start the motor running (from 0 rpm). But once the motor was spinning it generated so much interference that the IR signal from the remote couldn’t get through anymore (this was with a high rpm DC hobby motor that did have a capacitor connected across the motor terminals). Interference doesn’t seem to be an issue with radio control via the nRF24L01 module. The radio signal also has much better range — works through walls and upstairs/downstairs.

Radio transmitter/receiver module

Wiring Connections
The connections are different for Arduino Uno and Mega boards because SPI pins are in different positions on these boards.

nRF24L01 module pin — UNO — MEGA — my wire colour
GND — GND — GND — brown (ground)
VCC — 3.3v — 3.3v — red (module doesn’t like 5v)
MOSI — 11–51 — blue (Master Out Slave In)
MISO — 12–50 — purple (Master In Slave Out)
SCK — 13–52 — green (Clock)
CSN — 10–53 — yellow (Slave Select)
CE — 9–40 — orange (Chip Enable)
IRQ not used

(Thanks to Matthew for this info)

 

A Metaphor for how nRF24L01+ wireless communication works

‘Pipes’ and ‘Addresses’ and radio syntax was pretty confusing. Understanding this could save a lot of time and frustration in coding.

Open a window (a ‘pipe’)

Imagine you and your friend live in high-rise buildings and your apartments face each other. You want to yell out to your friend without going over to their apartment. You want to transmit information for him to receive.

 

You have 6 windows in your apartment — you have to choose one window to use, to call out to them. Similarly the nRF24L01 has 6 windows (or ‘pipes’, numbered 0,1,2,3,4 and 5) through which it can communicate. For the nRF24L01 radio to send or receive information it needs to be told which ‘pipe’ it will use to send/receive.

Once you’ve chosen which window to use, you have to open the window before you can yell out to your friend. The transmitting radio needs to open a pipe in order to send (‘write’) information. The transmitting pipe is pipe 0, so pipe number doesn’t need to be specified. It just needs to be opened. Use openWritingPipe()

On the other side your friend has to choose one of their own windows and open it, in order to hear you. Also your friend has to be ready, ‘listening’, for you. Use openReadingPipe() and startListening(). The receiving radio waits (‘listens’) and collects (‘reads’) the information.

Identify what to notice, what to ignore (using ‘addresses’)

Lastly, there’s a lot of noise around in the city and your friend needs some way of knowing what to listen to and what to ignore. You help them by calling his name “John!” before you say what you want to say. For this to work both you and your friend need to know his name is John. Similarly we need to tell both the transmitter and receiver what name (‘address’) to use. Create the address by declaring a const uint64_t type variable.

const uint64_t pipeAddressA = 0xE8E8F0F0E1LL

Note about the address variable definition:

  • the ‘uint64_t’ tells the processor the pipeAddressA variable is a 64bit integer
  • ‘pipeAddressA’ is the name of the address variable (can name it anything and it doesn’t have to be the same in transmitter and receiver code).
  • The hexadecimal number E8E8F0F0E1 is the address value.
  • the prefix ‘0x’ (zero x) indicates the number is hexademical
  • the suffix ‘LL’ tells the processor how to handle the hexadecimal number of this length (it’s quite long for Arduino apparently).
  • The address can be any value whatsoever, as long as only one radio is writing to it and only one other radio is listening to it. Coordinate these pipe addresses amongst nodes on the network. (http://maniacbug.github.io/RF24/classRF24.html)
  • Note: Pipe 0 is the same as the transmitting pipe, and pipes 1 to 5 should have addresses with the same first 32 bits. Only the last 8 bits can be different (eg ‘E1’ in the above address). So if we wanted to use multiple pipes we’d need multiple addresses. Another address we use in the sketch below is and E8E8F0F0D2 (same as first one except ‘E1’ is replaced by ‘D2’).
  • Some addresses: 0xF0F0F0F0D2LL and 0xF0F0F0F0E1LL. 0xE8E8F0F0E1LL and 0xE8E8F0F0D2LL

So, the complete syntax for opening pipes is:

  • for Transmitter: radio.openWritingPipe(address to use)
  • for Receiver: radio.openReadingPipe(pipe number, address to use)

 

Code

Download here for Arduino.

 

Other links I found useful

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s