Anveshan diaries #2: NRF24L01 communication tutorial

  • What we plan to do as a part of Anveshan is render all sensors wireless and send data via tiny microcontrollers (like Arduino Nano) to the main computer (Raspberry Pi 3) without wires. I feel that using nRF24 modules would work well. What I did not expect is that running 2 way communication would be such a hassle.

    nrf24-fig1

    I first stumbled upon RF24 library by maniacbug. Call it my naïve approach or the insufficient documentation, I just wasn’t able to set it up via C++ on Pi, while 2 way communication between two Arduinos was working just fine. We tried and tried, and the error codes kept piling up. I gave up on that particular library this morning and started afresh. The new approach worked pretty well and here I am going to share how to use it.

    On Arduino

    Clone the MIRF library from GitHub. Copy the folder to where you install libraries for Arduino. There’s nothing else left to do. The library works out of the box.

    On Raspberry Pi 2

    We need three libraries. In fact, 2 of them are dependencies for the first. You first need to enable SPI using:

    sudo raspi-config
    

    and going to advanced options and enabling both SPI and device tree. Once that’s done you can move on to installing the libraries.

    Clone the py-spidev library from Github. Go to root and type (one after the other).

    sudo python build
    
    sudo python install

    For  the WiringPi library, simply type:

    sudo pip install wiringpi

    Now we’re all set to download the example code. Download the code from my repository which in turn has been sourced from r3ek0’s repository.

    Connections

    Now we can test communication between the two. The connections are as follows (credits to r3ek0):

    for Pi 2

       nRF24L01              RaspberryPi
    +-+-+                    (header)      wiringpi-pins
    |8|7|   1: GND      ->   6              -
    +-+-+   2: 3.3V     ->   1              -
    |6|5|   3: CE       ->   13             2
    +-+-+   4: CSN      ->   15             3
    |4|3|   5: SCKL     ->   23            14
    +-+-+   6: MOSI     ->   19            12
    |2|1|   7: MISO     ->   21            13
    +-+-+   8: IRQ      ->   not used      not used
    
    

    for Arduino

       nRF24L01              Arduino Mega
    +-+-+                    (header)     
    |8|7|   1: GND      ->   GND          
    +-+-+   2: 3.3V     ->   3.3V             
    |6|5|   3: CE       ->   8         
    +-+-+   4: CSN      ->   7           
    |4|3|   5: SCKL     ->   52           
    +-+-+   6: MOSI     ->   51           
    |2|1|   7: MISO     ->   50           
    +-+-+   8: IRQ      ->   not used      

    Once the connections are done, we simply have to upload the codes. We have to change the RADDR and TADDR in receiving and sending codes in order for it to work. The TADDR on Pi should be the RADDR for Arduino and vice versa.

    A short note on the format in which data is sent

    The data is received in modulo-256 format. If you send a data of 65538, it would be received as 102 (1*256^2+0*256^1+2*256^0) which would be separate bits in a python list. You’d get the idea when you run the code.

    While receiving on Arduino, the ASCII code is formatted into the same format but it is received in the form of a number in the reverse format. So “aaaa” is sent in the form of “97*256^3+97*256^2+97*256+97” or “1633771873”. I hope you get the idea.

     

    So I hope this tutorial helps you out and saves you time. A video of this working would be posted soon.

    Here’s the video of this working:

    Here I am listing down a sample code pair for an Arduino Mega and a Raspberry Pi 2.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    
    /**
     * A Mirf example to test the latency between two Ardunio.
     *
     * Pins:
     * Hardware SPI:
     * MISO -> 12
     * MOSI -> 11
     * SCK -> 13
     *
     * Configurable:
     * CE -> 8
     * CSN -> 7
     *
     * Note: To see best case latency comment out all Serial.println
     * statements not displaying the result and load 
     * 'ping_server_interupt' on the server.
     */
     
    #include 
    #include 
    #include 
    #include 
     
    void setup(){
      Serial.begin(9600);
     
      /*
       * Setup pins / SPI.
       */
     
      /* To change CE / CSN Pins:
       * 
       * Mirf.csnPin = 9;
       * Mirf.cePin = 7;
       */
      /*
     
      */
      Mirf.cePin = 8;
      Mirf.csnPin = 7;
      Mirf.spi = &MirfHardwareSpi;
      Mirf.init();
      byte payload[8];
      /*
       * Configure reciving address.
       */
     
     
      /*
       * Set the payload length to sizeof(unsigned long) the
       * return type of millis().
       *
       * NB: payload on client and server must be the same.
       */
     
      Mirf.payload = sizeof(payload);
     
      /*
       * Write channel and payload config then power up reciver.
       */
     
      /*
       * To change channel:
       * 
     
       *
       * NB: Make sure channel is legal in your area.
       */
     
      Mirf.channel = 10;
      Mirf.config();
     
      Serial.println("Beginning ... "); 
    }
     
    void loop(){
      unsigned long time = 255;
     
      Mirf.setTADDR((byte *)"host2");
     
      Mirf.send((byte *)&time);
     
      while(Mirf.isSending()){
      }
      Serial.println("Finished sending");
      delay(10);
      while(!Mirf.dataReady()){
        //Serial.println("Waiting");
        if ( ( millis() - time ) > 1000 ) {
          Serial.println("Timeout on response from server!");
          return;
        }
      }
     
    }
    1
    2
    3
    4
    5
    6
    7
    8
    
    from nrf24 import Nrf24
    nrf = Nrf24(cePin=2,csnPin=3,channel=10,payload=8)
    nrf.config()
    nrf.setRADDR("host2")
     
    while True:
        if nrf.dataReady():
            print nrf.getData()
  • Leave a Reply

    Your email address will not be published. Required fields are marked *