RaspberryとArduinoの無線通信

nRF24L01(その4)

前回、Payload付きAck(PayloadAck)の機能を紹介しました。
そこで、1対nの環境でPayloadAckが動くかどうか試してみます。

【Raspberry側】

Raspberry側のコード(RecvMultiPayloadAck.cpp)は以下の通りです。
前回から赤字の部だけ変えています。
#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 7 nodes to communicate.
const uint8_t pipes[][6] =
        {"1Node", "2Node", "3Node", "4Node", "5Node", "6Node"};

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

  // Setup and configure rf radio
  radio.begin();

  // Enable Payload with Ack function
  radio.enableAckPayload(); // Enable dynamic payload on pipes 0 & 1
  radio.enableDynamicPayloads(); // Enable dynamic payload on all pipes

  radio.openReadingPipe(0,pipes[0]);
  radio.openReadingPipe(1,pipes[1]);
  radio.openReadingPipe(2,pipes[2]);
  radio.openReadingPipe(3,pipes[3]);
  radio.openReadingPipe(4,pipes[4]);
  radio.openReadingPipe(5,pipes[5]);
  radio.startListening();
  radio.printDetails();

  // forever loop
  unsigned long got_time;
  uint8_t pipe;
  static uint32_t message_count = 0;
  while (1) {
    if(radio.available(&pipe)){
      radio.writeAckPayload( pipe, &message_count, sizeof(message_count) );
      message_count++;

      radio.read(&got_time, sizeof(unsigned long));
      printf("pipe=%d payload=%lu\n",pipe, got_time);
    }
  } // end while
}

examples_linuxディレクトリにあるMakefileを修正してmakeします。
PROGRAMS = ...... RecvMultiPayloadAck

【Arduino側】

1台目のArduinoのスケッチは前回と同じです。
2台目のArduinoのスケッチは赤字の部分だけ変更します。


{前略}


// Radio pipe addresses for the 2 nodes to communicate.
byte addresses[][6] = {"SNode", "2Node"};

{後略}


1台目のArduinoではRaspberryから偶数のAckデータを受信します。


2台目のArduinoではRaspberryから奇数のAckデータを受信します。


Raspberry側はArduino1とArduino2からのデータを交互に受信するので、このような動作になります。
Arduinoを1台止めると、連続したAckデータとなります。




writeAckPayload()を使うと、1対nの場合でも、Arduino(データ送信)→Raspberry(データ受信+Ack応 答)→Arduino(Ack受信)の通信ができますが、
writeAckPayload()では不便なことが有ります。
それは、writeAckPayload()では受信する前にPayloadAckのデータを決めてしまうので、
Arduinoから受信したデータに応じて、PayloadAckのデータを変えることができません。
Arduino
Raspberry

radio.write()



radio.writeAckPayload() 受信する前にPayloadAckが決まってしま う                           

radio.read()
あらかじめ決まっているPayloadAckを応答する
radio.read()



PayloadAckは最大3つまで、事前にTX FIFOに積んでおくことができます。
TX FIFOに複数のPayloadAckが有るときは、FirstIn-FirstOutでPayloadが使われます。
無理やりやるとすればこんな感じになります。
Arduino
Raspberry

radio.write()



radio.writeAckPayload() とりあえずダミーのPayloadAckをTX FIFOに格納する

radio.read()
ダミーのPayloadAckを応答する
radio.read()

ダミーのPayloadAckを受信する

radio.writeAckPayload()
受信データに応じた本物のPayloadAckをTX FIFOに格納しておく



radio.write()



radio.read()
TX FIFOに格納されているPayloadAckを応答する
radio.read()

本物のPayloadAckを受信する

Raspberryは複数の相手からデータを受信することになるので、非常に面倒になります。
また、TX FIFOには最大3つまでしかPayloadを積めないので現実的ではありません。
Arduino UNO
Arduino NANO
Raspberry

radio.write()





radio.writeAckPayload() とりあえずダミーのPayloadAckをTX FIFOに格納する


radio.read()
ダミーのPayloadAckを応答する
radio.read()


ダミーのPayloadAckを受信する


radio.writeAckPayload() UNO用の本物のPayloadAckをTX FIFOに格納しておく





radio.write()




radio.writeAckPayload() とりあえずダミーのPayloadAckをTX FIFOに格納する


radio.read()
ダミーのPayloadAckを応答する

radio.read()

ダミーのPayloadAckを受信する


radio.writeAckPayload() NANO用の本物のPayloadAckをTX FIFOに格納しておく




radio.write()





radio.read()
TX FIFOに格納されているPayloadAckを応答する
radio.read()


本物のPayloadAckを受信する





radio.write()




radio.read()
TX FIFOに格納されているPayloadAckを応答する

radio.read()

本物のPayloadAckを受信する

現在時刻など、どの相手にも同じデータを戻すのであればPayloadAckの機能は有効です。
Arduino UNO
Arduino NANO
Raspberry

radio.write()





radio.writeAckPayload() 現在日時をPayloadAckに設定する


radio.read()
現在日時をPayloadAckとして応答する
radio.read()


現在日時を受けとる





radio.write()




radio.writeAckPayload() 現在日時をPayloadAckに設定する


radio.read()
現在日時をPayloadAckとして応答する

radio.read()

現在日時を受けとる



1台のReceiverは最大6台のTransmitterと同時に通信することができます。
このように1台のReceiverで、同時に複数のTransmitterと通信できるのもこのモジュールの特徴です。
但し、受信アドレス(受信用パイプの値)には、以下の制限が有ります。
・受信用パイプ0とパイプ1はユニークな5バイトの値を設定することができます。
・受信用パイプ2〜5はパイプ1のByte4〜1を共有し、Byte0の1バイトのみユニークな値を設定することができます。
Product SpecificationのFigure 11. Addressing data pipes 0-5にこの説明が有ります。

以下に例を示します。

Byte4
Byte3
Byte2
Byte1
Byte0
パイプ0
0x31
0x4E
0x6F
0x64
0x65
パイプ1
0x32
0x4E
0x6F
0x64
0x65
パイプ2
↑(0x32)
↑(0x4E) ↑(0x6F) ↑(0x64) 0x33
パイプ3
↑(0x32) ↑(0x4E) ↑(0x6F) ↑(0x64) 0xC4
パイプ4
↑(0x32) ↑(0x4E) ↑(0x6F) ↑(0x64) 0xC5
パイプ5
↑(0x32) ↑(0x4E) ↑(0x6F) ↑(0x64) 0xC6

以下の表示で、RX_ADDR_P0-1は5バイト表示されていますが、
RX_ADDR_P2-5はByte0の1バイトだけが表示されます。
このあたりのこともnRF24L01のドキュメントを読まないと分かりません。


続く....