[nrf24l01+] one base station broadcast to multiple receiver and wait for reply

hi, I use 3 sets of nrf24l01+ and arduino uno.
One as base station and the others are nodes.
First, the base station send a broadcast (multicast) to pipe1, and then listen on pipe2 to wait for reply.
The others act as nodes listen on pipe 1 and if radio available, send a reply to pipe2.

My problem is, if I use only two, one as base station and one as node, it works charming.
When I add a node into (become 1 base and 2 nodes), just one of nodes acts.
The other node listening nothing and no reply.
If I reset the idle node, it act as what I want and base station received 2 reply as charming.
But just that round is normal, next round receive only one node reply.

I use RF24 (maniacbug and tmrh20) library and arduino uno, code is as below, please help me, Thanks.

/*
 Copyright (C) 2011 James Coliz, Jr. <maniacbug@ymail.com>

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 version 2 as published by the Free Software Foundation.
 */

/**
 * Example RF Radio Ping Pair
 *
 * This is an example of how to use the RF24 class.  Write this sketch to two different nodes,
 * connect the role_pin to ground on one.  The ping node sends the current time to the pong node,
 * which responds by sending the value back.  The ping node can then see how long the whole cycle
 * took.
 */

#include <SPI.h>
#include "nRF24L01.h"
#include <RF24.h>
#include "printf.h"

//
// Hardware configuration
//

// Set up nRF24L01 radio on SPI bus plus pins 8 & 9

RF24 radio(9, 10);

// sets the role of this unit in hardware.  Connect to GND to be the 'pong' receiver
// Leave open to be the 'ping' transmitter
const int role_pin = 7;

//
// Topology
//

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

//
// Role management
//
// Set up role.  This sketch uses the same software for all the nodes
// in this system.  Doing so greatly simplifies testing.  The hardware itself specifies
// which node it is.
//
// This is done through the role_pin
//

// The various roles supported by this sketch
typedef enum { role_ping_out = 1, role_pong_back } role_e;

// The debug-friendly names of those roles
const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"};

// The role of the current running sketch
role_e role;

void setup(void)
{
  //
  // Role
  //

  // set up the role pin
  pinMode(role_pin, INPUT);
  digitalWrite(role_pin,HIGH);
  delay(20); // Just to get a solid reading on the role pin

  // read the address pin, establish our role
  if ( ! digitalRead(role_pin) )
    role = role_ping_out;
  else
    role = role_pong_back;

  //
  // Print preamble
  //

  Serial.begin(57600);
  printf_begin();
  printf("\n\rRF24/examples/pingpair/\n\r");
  printf("ROLE: %s\n\r",role_friendly_name[role]);

  //
  // Setup and configure rf radio
  //

  radio.begin();

  // optionally, increase the delay between retries & # of retries
  // radio.setRetries(15,15);

  // optionally, reduce the payload size.  seems to
  // improve reliability
  // radio.setPayloadSize(8);

  //
  // Open pipes to other nodes for communication
  //

  // This simple sketch opens two pipes for these two nodes to communicate
  // back and forth.
  // Open 'our' pipe for writing
  // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading)

  if ( role == role_ping_out )
  {
    radio.openWritingPipe(pipes[0]);
    radio.openReadingPipe(1,pipes[1]);
  }
  else
  {
    radio.openWritingPipe(pipes[1]);
    radio.openReadingPipe(1,pipes[0]);
  }

  //
  // Start listening
  //
  // if( radio.setDataRate( RF24_250KBPS ) ) {
  //   printf( "Data rate 250KBPS set!\n\r" ) ;
  // } else {
  //   printf( "Data rate 250KBPS set FAILED!!\n\r" ) ;
  // }
  // radio.setDataRate( RF24_2MBPS ) ;
  // radio.setPALevel( RF24_PA_MAX ) ;
  radio.enableDynamicPayloads() ;
  //radio.setAutoAck( false ) ;
  //radio.powerUp() ;
  radio.startListening();

  //
  // Dump the configuration of the rf unit for debugging
  //

  radio.printDetails();
}

char sendBuffer[33];
uint8_t counter = 1;

void loop(void)
{
  //
  // Ping out role.  Repeatedly send the current time
  //

  if (role == role_ping_out)
  {
    
    // send it.  This will block until complete
    sprintf(sendBuffer, "%d|root", counter);
    
    // First, stop listening so we can talk.
    radio.stopListening();

    printf("Now sending %s...", sendBuffer);
    bool ok = radio.write( sendBuffer, strlen(sendBuffer), true );

    if (ok) printf("ok...\r\n");
    else printf("no ack, failed...\r\n");
    
    counter++;
    
    // wait for reply
    radio.startListening();
    
    unsigned long time_started_waiting = millis();
    uint8_t pipe_num;
    bool timeout = false;
    while( !timeout ) {
      
      if (radio.available(&pipe_num)) {
        
        uint8_t len = radio.getDynamicPayloadSize();
        char backPayload[33];
        
        radio.read( backPayload, len );
        backPayload[len] = 0;
        
        printf("Got reply \"%s\" from pipe \"%d\".\r\n", backPayload, pipe_num);
        
      }
      
      if ( (millis() - time_started_waiting) > 3000 ) {
          timeout = true;
          printf("This round is over.\r\n\r\n");
      }
      
    }

    // Try again 1s later
    delay(1000);
  }

  //
  // Pong back role.  Receive each packet, dump it out, and send it back
  //

  if ( role == role_pong_back )
  {
    uint8_t pipe_num;
    //printf("counter = %d\r\n", counter);
    
    // if there is data ready
    if ( radio.available(&pipe_num) && pipe_num == 1)
    {
      // Dump the payloads until we've gotten everything
      char receivePayload[33];
      bool done = false;
      uint8_t len = radio.getDynamicPayloadSize();
      
      while (radio.available())
      {
        // Fetch the payload, and see if this was the last one.
        radio.read( receivePayload, len );
      }
      
      receivePayload[len] = 0;

      printf("received pipe: %d, \"%s\".\n\r", pipe_num, receivePayload);

      strcat(receivePayload, "|node2");
      
      radio.stopListening();
      radio.openWritingPipe(pipes[1]);
      
      delay(random(10, 20)*3);
      radio.write(receivePayload, strlen(receivePayload), true);
      
      radio.startListening();
    }
    
  }
}

It looks like there are 3 things keeping it from working properly. One of them is a bug that I've been noticing, and this post helped me to identify it fully:

  1. There is (was) a problem with the libraries that would only really cause issues when using multicast writes, with two or more nodes, when pipe0 was not assigned a reading address - This has just been fixed in my fork, see https://github.com/TMRh20/RF24/archive/master.zip
  2. You need to enableDynamicAck(); per the code below, or disable auto-ack altogether when using multicast.
  3. The while(available()) is not needed, and can throw things off a bit

Re-installing the library from the above link and using the minor changes in the code below should fix the issue.

/*
 Copyright (C) 2011 James Coliz, Jr. <maniacbug@ymail.com>

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 version 2 as published by the Free Software Foundation.
 */

/**
 * Example RF Radio Ping Pair
 *
 * This is an example of how to use the RF24 class.  Write this sketch to two different nodes,
 * connect the role_pin to ground on one.  The ping node sends the current time to the pong node,
 * which responds by sending the value back.  The ping node can then see how long the whole cycle
 * took.
 */

#include <SPI.h>
#include "nRF24L01.h"
#include <RF24.h>
#include "printf.h"

//
// Hardware configuration
//

// Set up nRF24L01 radio on SPI bus plus pins 8 & 9

RF24 radio(9,10);

// sets the role of this unit in hardware.  Connect to GND to be the 'pong' receiver
// Leave open to be the 'ping' transmitter
const int role_pin = 7;

//
// Topology
//

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

//
// Role management
//
// Set up role.  This sketch uses the same software for all the nodes
// in this system.  Doing so greatly simplifies testing.  The hardware itself specifies
// which node it is.
//
// This is done through the role_pin
//

// The various roles supported by this sketch
typedef enum { role_ping_out = 1, role_pong_back } role_e;

// The debug-friendly names of those roles
const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"};

// The role of the current running sketch
role_e role;

void setup(void)
{
  //
  // Role
  //

  // set up the role pin
  pinMode(role_pin, INPUT);
  digitalWrite(role_pin,HIGH);
  delay(20); // Just to get a solid reading on the role pin

  // read the address pin, establish our role
  if ( ! digitalRead(role_pin) )
    role = role_ping_out;
  else
    role = role_pong_back;

  //
  // Print preamble
  //

  Serial.begin(57600);
  printf_begin();
  printf("\n\rRF24/examples/pingpair/\n\r");
  printf("ROLE: %s\n\r",role_friendly_name[role]);

  //
  // Setup and configure rf radio
  //

  radio.begin();

  // optionally, increase the delay between retries & # of retries
  // radio.setRetries(15,15);

  // optionally, reduce the payload size.  seems to
  // improve reliability
  // radio.setPayloadSize(8);

  //
  // Open pipes to other nodes for communication
  //

  // This simple sketch opens two pipes for these two nodes to communicate
  // back and forth.
  // Open 'our' pipe for writing
  // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading)

  if ( role == role_ping_out )
  {
    radio.openWritingPipe(pipes[0]);
    radio.openReadingPipe(1,pipes[1]);
  }
  else
  {
    radio.openWritingPipe(pipes[1]);
    radio.openReadingPipe(1,pipes[0]);
  }

  //
  // Start listening
  //
  // if( radio.setDataRate( RF24_250KBPS ) ) {
  //   printf( "Data rate 250KBPS set!\n\r" ) ;
  // } else {
  //   printf( "Data rate 250KBPS set FAILED!!\n\r" ) ;
  // }
  // radio.setDataRate( RF24_2MBPS ) ;
  // radio.setPALevel( RF24_PA_MAX ) ;
  radio.enableDynamicPayloads() ;
  radio.enableDynamicAck();
  //radio.setAutoAck( false ) ;
  //radio.powerUp() ;
  radio.startListening();

  //
  // Dump the configuration of the rf unit for debugging
  //

  radio.printDetails();
}

char sendBuffer[33];
uint8_t counter = 1;

void loop(void)
{
  //
  // Ping out role.  Repeatedly send the current time
  //

  if (role == role_ping_out)
  {
    
    // send it.  This will block until complete
    sprintf(sendBuffer, "%d|root", counter);
    
    // First, stop listening so we can talk.
    radio.stopListening();

    printf("Now sending %s...", sendBuffer);
    bool ok = radio.write( sendBuffer, strlen(sendBuffer), true );

    if (ok) printf("ok...\r\n");
    else printf("no ack, failed...\r\n");
    
    counter++;
    
    // wait for reply
    radio.startListening();
    
    unsigned long time_started_waiting = millis();
    uint8_t pipe_num;
    bool timeout = false;
    while( !timeout ) {
      
      if (radio.available(&pipe_num)) {
        
        uint8_t len = radio.getDynamicPayloadSize();
        char backPayload[33];
        
        radio.read( backPayload, len );
        backPayload[len] = 0;
        
        printf("Got reply \"%s\" from pipe \"%d\".\r\n", backPayload, pipe_num);
        
      }
      
      if ( (millis() - time_started_waiting) > 3000 ) {
          timeout = true;
          printf("This round is over.\r\n\r\n");
      }
      
    }

    // Try again 1s later
    delay(1000);
  }

  //
  // Pong back role.  Receive each packet, dump it out, and send it back
  //

  if ( role == role_pong_back )
  {
    uint8_t pipe_num;
    //printf("counter = %d\r\n", counter);
    
    // if there is data ready
    if ( radio.available(&pipe_num) && pipe_num == 1)
    {
      // Dump the payloads until we've gotten everything
      char receivePayload[33];
      bool done = false;
      uint8_t len = radio.getDynamicPayloadSize();
      
      //while (radio.available())
      //{
        // Fetch the payload, and see if this was the last one.
        radio.read( receivePayload, len );
      //}
      
      receivePayload[len] = 0;

      printf("received pipe: %d, \"%s\".\n\r", pipe_num, receivePayload);

      strcat(receivePayload, "|node2");
      
      radio.stopListening();
      radio.openWritingPipe(pipes[1]);
      
      delay(random(10, 20)*3);
      radio.write(receivePayload, strlen(receivePayload), true);
      
      radio.startListening();
    }
    
  }
}

tmrh20, you're rock!
I reinstall your library and fix my code, it works!
It has confused me 1 week.
Thank you very much.

Hey Did you run the identical program on all three Arduinos? Did you need to change the pipe address ?