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

前回まではArduino→Raspberryの一方向だけの通信でした。
Examplesフォルダーにある他のサンプルを見るとArduino→(受信)Raspberry(応答)→Arduinoの通信もできそうで すが
ようやく成功しました。
Raspberry→Arduinoに応答するにはwriteAckPayload()という関数(メソッド)を使うのですが、
今までずっと radio.read()の後に実行していました。(パッケージ付属のサンプルもそのようになっていました)
RF24のクラスリファ レンスをよく読むと、writeAckPayload()の説明に

Write an ack payload for the specified pipe.
The next time a message is received on pipe, the data in buf will be sent back in the acknowledgement.

と書かれています。
要するに「次回メッセージを受信したときにデータが返信される」ということで、radio.read()の前に
呼び出しておく必要がありました。
こ このページが大いに参考になりました)

【Raspberry側】

Raspberry側のコード(RecvSimpleAck.cpp)は以下の通りです。
赤字の部分だけ、その1と 変えています。
#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];

  static uint32_t message_count = 0;

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

  radio.setAutoAck(true);
  radio.enableAckPayload();

  radio.openReadingPipe(0,pipes[1]);
  radio.startListening();
  radio.printDetails();


  // forever loop
  while (1) {
    if(radio.available()){
      radio.writeAckPayload( 0, &message_count, sizeof(message_count) );
      printf("writeAckPayload=%d ",message_count);
      ++message_count;

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


次にexamplesディレクトリにあるMakefileを修正します。
PROGRAMS = RecvSimple RecvMulti
の行を以下の様に変更します。
PROGRAMS = RecvSimple RecvMulti RecvSimpleAck

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

nRF24L01とRaspberryの結線は前回と同じです。

【Arduino側】

Arduino側のスケッチは以下の通りです。
赤字の部分だけ、その 1と変え ています。
/*
 * nRF24L01 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);

// 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 and AckPayload Demo");
  printf_begin();
 
  //
  // Setup and configure rf radio
  //
  radio.begin();
  radio.enableAckPayload();
  radio.openWritingPipe(pipes[1]);
  radio.openReadingPipe(1,pipes[0]);
  radio.printDetails();
}

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

  // 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.");
  }

  if ( radio.isAckPayloadAvailable() )  {
    radio.read(&message_count,sizeof(message_count));
    Serial.print("Ack message_count=");
    Serial.println(message_count);
  }

  //https://github.com/maniacbug/RF24で は、この2行を入れないと次のradio.writeが正常に動かない
  //radio.startListening();
  //radio.stopListening();

  delay(1000);

}

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



RaspberryからのAckデータが受け取れていて、Arduino→(受信)Raspberry(応答)→Arduinoとなっています。
今回Ackデータとして32ビット(4バイト)を応答していますが、Ackデータとして応答できるのは最大32バイトです。

さてArduinoが複数の場合は....

続く....