Networking & Communications

By Dan Chen, September 12, 2014

For my final project, I need wireless communication between 4 different boards. I decided to go with NRF24L01 with the RF24 Arduino Library.

There are other ways to talk to the NRF24L01 that you will find here http://playground.arduino.cc/InterfacingWithHardware/Nrf24L01 

Here is how to wire the NRF24L01 to your FabDurino, in my case I made my own with ATmega328p, which is the same as the Arduino UNO below.

https://github.com/TMRh20/RF24

PIN NRF24L01 Arduino UNO ATtiny25/45/85 [0] ATtiny44/84 [1]
1 GND GND pin 4 pin 14
2 VCC 3.3V pin 8 pin 1
3 CE digIO 7 pin 2 pin 12
4 CSN digIO 8 pin 3 pin 11
5 SCK digIO 13 pin 7 pin 9
6 MOSI digIO 11 pin 6 pin 7
7 MISO digIO 12 pin 5 pin 8
8 IRQ

I used this site as my guide to program NRF24L01 with RF24

Getting Started with nRF24L01+ on Arduino

Note: The Chip can take 5V, there is no need to regulate the voltage.

IMG_0597

Testing on Arduino

I want to test it on Arduino first, just to make sure that I understand how to run the software and modify it correctly without the hardware issue. I could not get it to work on Arduino YUN, but it works on Arduino UNO.

IMG_0565

Running the example Code:

libraries/RF24-master/examples/GettingStarted_CallResponse/GettingStarted_CallResponse.ino
or Arduino file menu: File > Example > RF24-master …

Once I upload the sketch I get the following serial data on both of my Arduinos. You need a pair of Arduino with NRF24L01 to test this, but you should get the message below with just one.

Note: Serial. bud rate is 57600

RF24/examples/GettingStarted/
ROLE: Pong back
STATUS	= 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1	= 0xf0f0f0f0d2 0xf0f0f0f0e1
RX_ADDR_P2-5	= 0xc3 0xc4 0xc5 0xc6
TX_ADDR	= 0xf0f0f0f0d2
RX_PW_P0-6	= 0x08 0x08 0x00 0x00 0x00 0x00
EN_AA	= 0x3f
EN_RXADDR	= 0x03
RF_CH	= 0x4c
RF_SETUP	= 0x07
CONFIG	= 0x0f
DYNPD/FEATURE	= 0x00 0x00
Data Rate	= 1MBPS
Model	= nRF24L01
CRC Length	= 16 bits
PA Power	= PA_HIGH

The serial data will then display whether or not it gets the message back.

 

Modifing the RF24 example

Creating a sending only Nrf24L01 by taking out the receiver part of the code

#include 
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"

// Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 
RF24 radio(7,8);

int sensorPin = A1;    // select the input pin for the potentiometer
     
byte sensorValue;
byte seninbyte;
                                                                           // Topology
byte addresses[][6] = {"8Node","8Node"};              // Radio pipe addresses for the 2 nodes to communicate.

// Role management: Set up role.  This sketch uses the same software for all the nodes
// in this system.  Doing so greatly simplifies testing.  
typedef enum { role_ping_out = 1, role_pong_back } role_e;                 // The various roles supported by this sketch
const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"};  // The debug-friendly names of those roles
role_e role = role_pong_back;                                              // The role of the current running sketch

byte counter = 1;                                                          // A single byte to keep track of the data being sent back and forth


void setup(){

  Serial.begin(57600);
  printf_begin();
  printf("\n\rRF24/examples/GettingStarted/\n\r");
  printf("ROLE: %s\n\r",role_friendly_name[role]);
  printf("*** PRESS 'T' to begin transmitting to the other node\n\r");

  // Setup and configure radio

  radio.begin();
  radio.setAutoAck(1);                    // Ensure autoACK is enabled
  radio.enableAckPayload();               // Allow optional ack payloads
  radio.setRetries(0,15);                 // Smallest time between retries, max no. of retries
  radio.setPayloadSize(1);                // Here we are sending 1-byte payloads to test the call-response speed
  radio.openWritingPipe(addresses[1]);        // Both radios listen on the same pipes by default, and switch when writing
  radio.openReadingPipe(1,addresses[0]);      // Open a reading pipe on address 0, pipe 1
  radio.startListening();                 // Start listening
  radio.powerUp();
  radio.printDetails();                   // Dump the configuration of the rf unit for debugging
  
  
  
  role=role_ping_out;

}

void loop(void) {

  sensorValue =    map (analogRead(sensorPin), 500, 988, 0, 180); // wind sensor
  if (sensorValue>-1 && sensorValue < 181){
    seninbyte=sensorValue;
  }



/****************** Ping Out Role ***************************/


  if (role == role_ping_out){                               // Radio is in ping mode

    byte gotByte;                                           // Initialize a variable for the incoming response
    
    radio.stopListening();                                  // First, stop listening so we can talk.      
    printf("Now sending %d as payload\n\r",seninbyte);          // Use a simple byte counter as payload
    unsigned long time = micros();                          // Record the current microsecond count   
                                                            
    if ( radio.write(&seninbyte,1  ) ){                         // Send the counter variable to the other radio 
    //if ( radio.write(&counter,sizeof(counter)) ){                         // Send the counter variable to the other radio 
        if(!radio.available()){                             // If nothing in the buffer, we got an ack but it is blank
            //printf("Got blank response. round-trip delay: %lu microseconds\n\r",micros()-time);     
        }else{      
            while(radio.available() ){                      // If an ack with payload was received
                radio.read( &gotByte, 1 );                  // Read it, and display the response time
                printf("Got response %d, round-trip delay: %lu microseconds\n\r",gotByte,micros()-time);

                //counter++;                                  // Increment the counter variable
            }
        }
    
    }else{        printf("Sending failed.\n\r"); }          // If no ack response, sending failed
    
    delay(100);  // Try again later
  }


}

Creating a receiving only Nrf24L01

#include 
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
#include  


Servo myservo; 
int pos = 0;

// Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 
RF24 radio(7,8);
                                                                           // Topology
byte addresses[][6] = {"8Node","8Node"};              // Radio pipe addresses for the 2 nodes to communicate.

// Role management: Set up role.  This sketch uses the same software for all the nodes
// in this system.  Doing so greatly simplifies testing.  
typedef enum { role_ping_out = 1, role_pong_back } role_e;                 // The various roles supported by this sketch
const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"};  // The debug-friendly names of those roles
role_e role = role_pong_back;                                              // The role of the current running sketch

byte counter = 1;                                                          // A single byte to keep track of the data being sent back and forth


void setup(){

  Serial.begin(57600);
  myservo.attach(A1);  // attaches the servo on pin 9 to the servo object 

  printf_begin();
  printf("\n\rRF24/examples/GettingStarted/\n\r");
  printf("ROLE: %s\n\r",role_friendly_name[role]);
  printf("*** PRESS 'T' to begin transmitting to the other node\n\r");

  // Setup and configure radio

  radio.begin();
  radio.setAutoAck(1);                    // Ensure autoACK is enabled
  radio.enableAckPayload();               // Allow optional ack payloads
  radio.setRetries(0,15);                 // Smallest time between retries, max no. of retries
  radio.setPayloadSize(1);                // Here we are sending 1-byte payloads to test the call-response speed
  radio.openWritingPipe(addresses[1]);        // Both radios listen on the same pipes by default, and switch when writing
  radio.openReadingPipe(1,addresses[0]);      // Open a reading pipe on address 0, pipe 1
  radio.startListening();                 // Start listening
  radio.powerUp();
  radio.printDetails();                   // Dump the configuration of the rf unit for debugging



  role=role_pong_back;


}

void loop(void) {


/****************** Pong Back Role ***************************/

  if ( role == role_pong_back ) {
    byte pipeNo, gotByte;                          // Declare variables for the pipe and the byte received
    while( radio.available(&pipeNo)){              // Read all available payloads
      radio.read( &gotByte, 1 );                   
                                                   // Since this is a call-response. Respond directly with an ack payload.
                                                   // Ack payloads are much more efficient than switching to transmit mode to respond to a call
      // turing this off, no feedback
      //radio.writeAckPayload(pipeNo,&gotByte, 1 );  // This can be commented out to send empty payloads.
      //printf("Sent response %d \n\r", gotByte);  
      printf("I am getting %d \n\r", gotByte); 
      
      if (gotByte>0){
        myservo.write(gotByte);
      }
              delay(100);

   }
 }


}

Download my version of RF-24

 

Trying to get serial data

Tip: Use 2 Arduino IDEs to get 2 serial data with FTDI, so you don’t need a 2nd computer. All you need to do is duplicate the Arduino program in your application folder on your mac.

Screen Shot 2014-11-22 at 2.35.54 PM

Here I have the code running with the wind sensor. Wind sensor just measures the current drop between the 2 wires, so whenever I touch the tip of the wire, the voltage drops.

Adding some output devices

Testing the wiring and software with a servo and a wind sensor.

Moving everything to FabDuino

This process is really simple and fast, once I know the code is good and my “DanDurino” is good, I used the same colors wires to hook up the Nrf24L01, and uploaded the sketch. They work exactly the same as the Arduino UNO.

IMG_0588

 

Sender

The sender contains an analog wind sensor, that I purchased from here. http://moderndevice.com/product/wind-sensor/

IMG_0603

Receiver

The receiver end has a servo, getting the position data from the sender.

IMG_0608

 

Putting it all together

I imaging you could place the “sender” outdoor to sense the wind and reproduce the environment with the servo indoor.

 

Integrate with DanDurino / Making a direct plug

To save space and wiring, I decided to make a new board without ISP header and pins for Nrf24L01.

Screen Shot 2014-11-25 at 11.38.46 AM Screen Shot 2014-11-25 at 11.38.36 AM

I hope this works …

IMG_0633

I removed the IPS pins so I had to make my own custom IPS pins that will fit with the Nrf24L01. I included the reset pin on first column.

IMG_0645

The special pins works as ISP or Nrf24L01

IMG_0642

IMG_0640

After burning the boot loader successfully, I was able to run exactly the same sending and receiving sketches. These will be the perfect boards for my final project.