RaspberryとArduinoの無線通信(nRF24L01 その1)

nRF24L01モジュールを使ってRaspberryとArduinoの無線通信に成功しましたので紹介します。
nRF24L01モジュールを使ったRaspberryとArduinoの無線通信は、こ ちらのページに紹介されていますが
少し記事が古いようです。
そこで、もっとも頻度が高いであろう、Raspberry側をサーバ、Arduino側をクライアントにしたサンプルを作ってみました。
RaspberryのFirmwareのリビジョンは3.18.7を使用しています。

nRF24L01モジュールは技術基準適合証明等のマーク(通称技適マーク)が交付されていませんので
これ以降の記事は、あくまでも実験レベルと考えてください。

【Raspberry側】

最初にこ ちらなどを参考にしてSPIを有効にします。
次に、必要なライブラリをダウンロード、インストールします。
$ git clone https://github.com/stanleyseow/RF24.git
$ cd RF24/RPi/RF24
$ make
$ sudo make install

次にexamplesディレクトリに移動します。
$ cd examples

ここにいくつかサンプルソースがあるのですが、適当なサーバのソースがなかったので以下のコード(RecvSimple.cpp)を書きました。
なおpipes変数はArrayになっていますが、今回pipes[0]の変数は使いません。

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include <RF24/RF24.h>


using namespace std;
//
// Hardware configuration
//

// CE Pin, CSN Pin, SPI Speed

// Setup for GPIO 22 CE and CE1 CSN with SPI Speed @ 4Mhz
//RF24 radio(RPI_V2_GPIO_P1_22, BCM2835_SPI_CS1, BCM2835_SPI_SPEED_4MHZ);

// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 4Mhz
RF24 radio(RPI_V2_GPIO_P1_22, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_4MHZ);

// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 8Mhz
//RF24 radio(RPI_V2_GPIO_P1_22, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_8MHZ);

// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };

int main(int argc, char** argv){

  uint8_t len;
  uint8_t data[32];

  radio.begin();                           // Setup and configure rf radio
  radio.openReadingPipe(0,pipes[1]);
  radio.startListening();
  radio.printDetails();


  // forever loop
  while (1) {
    if(radio.available()){
      len = radio.getDynamicPayloadSize();
      radio.read(&data,len);
      printf("data=%d\n",data[0]);
    }
  } // end while
}

次にexamplesディレクトリにあるMakefileを修正します。
PROGRAMS = gettingstarted gettingstarted_call_response transfer pingpair_dyn
の行をコメントアウトし
PROGRAMS = RecvSimple
を追加します。

# define all programs
#PROGRAMS = scanner pingtest gettingstarted
#PROGRAMS = gettingstarted gettingstarted_call_response transfer pingpair_dyn
PROGRAMS = RecvSimple

nRF24L01とRaspberryの結線はこ のページのままです。

<補足>
CEピン(黄色のライン)だけは自由なピンを使うことができます。
以下の行のXXに物理ピン番号を指定します。
RF24 radio(RPI_V2_GPIO_P1_XX, BCM2835_SPI_CS0,BCM2835_SPI_SPEED_4MHZ);
例えば8番をCEピンに使う場合
RF24 radio(RPI_V2_GPIO_P1_08, BCM2835_SPI_CS0,BCM2835_SPI_SPEED_4MHZ);
となります。
</補足>

モジュールを接続して実行すると以下の表示となります。

$ make
$ sudo ./ResvSimple



【Arduino側】

以下のページからRF24-master.zipをダウンロードし、解凍したらフォルダーごとlibrariesフォルダーに移動します。
https://github.com/TMrh20/RF24

なお、ArduinoのRF24ライブラリには以下のバージョンもありますが、こちらは少し古くバグが残っているようです。
最初にこちらをダウンロードしたので、めちゃくちゃはまりました。
https://github.com/maniacbug/RF24

Arduino側のスケッチは以下の通りです。
ポイントは相手側(今回はRaspberry)とパイプ変数の値を合わせておくことです。
Raspberry側:0xF0F0F0F0D2LLで受信(openReadingPipe)
Arduino側:<0xF0F0F0F0D2LLで送信(openWritingPipe)
ここが合っていないと正しく通信できません。
/*
 * nRF24L01 Send Sample Program
 *
 * VCC  3.3V
 * MISO 12
 * MOSI 11
 * SCK  13
 * CE   8
 * CSN  7
 */
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"

// Set up nRF24L01 radio on SPI bus plus pins 9 & 10
//RF24 radio(9,10);
RF24 radio(8,7);// CE,CSN

// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };


void setup(void)
{
  Serial.begin(9600);
  Serial.println("nTF24L01 Send Demo");
  printf_begin();
 
  //
  // Setup and configure rf radio
  //
  radio.begin();
  radio.openWritingPipe(pipes[1]);
  radio.openReadingPipe(1,pipes[0]);
  radio.printDetails();
}

void loop(void)
{
  static int value = 0;
  uint8_t data[32];

  // Take the time, and send it.  This will block until complete
  data[0]=value;
  value++;
  Serial.print("Now sending ...");

  bool ok = false;
  while(!ok) {
    ok = radio.write( data, sizeof(data) );
    if (ok) {
      Serial.println("ok...");
    } else {
      Serial.print("failed.");
      delay(1000);
    }
  }

  delay(1000);

}

nRF24L01とArduinoの接続は以下の通りです。
nRF24L01 Arduino
VCC 3.3V(注意)
GND GND
MISO
D12
MOSI
D11
SCK
D13
CE
D8
CSN
D7

nRF24L01のCEピンをD8に、CSNピンをD7に接続していますが、ここはスケッチ内で好きなピンに変更できます。
nRF24L01のMISO MOSI SCKはD12,D11,D13に固定です。→変 更できることが分かりました

(注意)
Arduinoの互換機では3.3V出力の電流容量が正規品よりも小さいみたいで、
3.3Vを直接ボードから供給すると正しく動かないことがあります。
Arduinoの3.3V出力の電流容量についてはこ ちらに詳しく紹介されていますが
メーカやバージョンによってボードに実装されているレギュレータが違うみたいです。
ボードに実装されているレギュレータはとても小さな部品で、マーキングを読み取ることが困難なので、
外部レギュレータを使って5V→3.3Vに変換し、nRF24L01に供給したほうがいいです。
レギュレータはAMS1117(最 大1000mA)の様に、できるだけ電流容量の大きなもののほうが安心ですが、
RF24L01はそれほど電気を食わないので、LP-2950(最大 100mA) でも動いています。

このようなnRF24L01専用のソケットがあります。
基板上に3.3Vへのレギュレータが実装されているので、5V給電で動かすことができます。





Arduinoのスケッチを実行するとRaspberry側の表示が以下のようになります。



一度に32バイトまでのデータを送ることができます。
Arduino側は以下の様に表示されます。



Raspberry側のプログラムを止めると、きちんと送信失敗を検出します。
Raspberry側のプログラムを再起動すると再び送信を始めます。



なお、Raspberry側で複数のセッションを立ち上げて、同じプログラムを起動すると、正常に受信できませんでした。

続く...