Master/5-slave star net

Has anyone successfully created a star network of one master and multiple slave nodes using TMRh20 RF24.h? A network with 2-way communication?

I would really appreciate sample code showing how to establish the communication. I have no idea where to start.

Thanks

I suggest using the ackPayload technique as in the second example in this Simple nRF24L01+ Tutorial. The ackPayload system removes all the complexities out of 2-way communication. Extending the example so that the master communicates in turn with multiple slaves will be straightforward.

I am using this system for 2-way communication with model trains.

...R

Robin2:
Extending the example so that the master communicates in turn with multiple slaves will be straightforward.

My attempt has the same structures and functions as your code, but I have found getting it to work with more than one slave (or, in this case, respondent) at a time anything but straightforward. I have not been able to devise an addressing system in which each address is both unique and discrete. That is, (assume I have two or three slaves active) I cannot get the master to talk to one respondent, then later to another, without the transmissions going all over the place.

Robin2:
I am using this system for 2-way communication with model trains.

Does the (station) master control more than one train? If so, may I have a look at the code? I'd love to check out your addresses.

Thanks

rickduley:
My attempt has the same structures and functions as your code, but I have found getting it to work with more than one slave (or, in this case, respondent) at a time anything but straightforward. I have not been able to devise an addressing system in which each address is both unique and discrete. That is, (assume I have two or three slaves active) I cannot get the master to talk to one respondent, then later to another, without the transmissions going all over the place.

How can I comment when you have not posted your programs?

Does the (station) master control more than one train?

Yes. I don’t have that many but I’m pretty sure it could communicate with 15 or so with messages 5 times per second.

The addressing system is the same as in my tutorial. I don’t understand why addressing would be causing you a problem. Just give each slave a different address and in the master have an array containing all the slave addresses.

This is the function in my program that talks to the individual locos

void talkToLocos() {
    // this sends whatever is in locoData
    //   it does not depend on valid data in the most recent input

    //~ static int sendVal[2] = {0,27}; // for testing - matches NewHandControl.ino
    for (byte n  = 0; n < numLocos; n++) {
        slaveAddress[4] = locoData[n].locoID;
        Serial.print("{SlaveADDR ");
        Serial.print((char*)slaveAddress);
        Serial.print('}');
        radio.openWritingPipe(slaveAddress);
        bool rslt;
        rslt = radio.write( &locoData[n], lDlen );
        //~ rslt = radio.write( sendVal, sizeof(sendVal) ); // for testing
        if (rslt) {
            if ( radio.isAckPayloadAvailable() ) {
                radio.read(&locoReply[n], sizeof(locoReply[n]));
                newData = true;
            }
            else {
                locoReply[n][0] = -2; // signifies no data
            }
        }
        else {
            locoReply[n][0] = -1; // signifies failed TX
        }
        Serial.print("{LocoREPLY ");
        Serial.print(locoReply[n][0]);
        Serial.print(' ');
        Serial.print(locoReply[n][1]);
        Serial.print(' ');
        Serial.print(locoReply[n][2]);
        Serial.print('}');

    }
    //~ sendVal[0] ++; // for testing

}

…R

Thanks robin2

I see the line

        slaveAddress[4] = locoData[n].locoID;

and I am guessing that locoData is an array of struct which contains a field locoID.

If that is so, would you please show me that, else please show me what the line does refer to.

Thanks

rickduley:
I see the line

        slaveAddress[4] = locoData[n].locoID;

and I am guessing that locoData is an array of struct which contains a field locoID.

The array slaveAddress has 5 values as in my Tutorial. This line just changes one byte in that array to give a unique address for each loco. It means the addresses can be something like ABCD1, ABCD2, ABCD3 etc.

...R

Robin2:
It means the addresses can be something like ABCD1, ABCD2, ABCD3 etc.

I have tried a range of different address styles

//const uint8_t SLAVE_0[] = { 0x00, 0x00, 0x00, 0x00, 0xAA };
//const uint8_t SLAVE_1[] = { 0x00, 0x00, 0x00, 0x00, 0xBB };
//const uint8_t SLAVE_2[] = { 0x00, 0x00, 0x00, 0x00, 0xCC };
//const uint8_t SLAVE_3[] = { 0x00, 0x00, 0x00, 0x00, 0xDD };
//const uint8_t SLAVE_4[] = { 0x00, 0x00, 0x00, 0x00, 0xEE };
//const uint8_t SLAVE_5[] = { 0x00, 0x00, 0x00, 0x00, 0xFF };

//const uint8_t SLAVE_0[] = { 0xAA, 0x00, 0x00, 0x00, 0x00 };
//const uint8_t SLAVE_1[] = { 0xBB, 0x00, 0x00, 0x00, 0x00 };
//const uint8_t SLAVE_2[] = { 0xCC, 0x00, 0x00, 0x00, 0x00 };
//const uint8_t SLAVE_3[] = { 0xDD, 0x00, 0x00, 0x00, 0x00 };
//const uint8_t SLAVE_4[] = { 0xEE, 0x00, 0x00, 0x00, 0x00 };
//const uint8_t SLAVE_5[] = { 0xFF, 0x00, 0x00, 0x00, 0x00 };

//const uint8_t SLAVE_0[] = { 0xAA, 0x00, 0x00, 0x00, 0xAA };
//const uint8_t SLAVE_1[] = { 0xBB, 0x00, 0x00, 0x00, 0xBB };
//const uint8_t SLAVE_2[] = { 0xCC, 0x00, 0x00, 0x00, 0xCC };
//const uint8_t SLAVE_3[] = { 0xDD, 0x00, 0x00, 0x00, 0xDD };
//const uint8_t SLAVE_4[] = { 0xEE, 0x00, 0x00, 0x00, 0xEE };
//const uint8_t SLAVE_5[] = { 0xFF, 0x00, 0x00, 0x00, 0xFF };

//const uint8_t SLAVE_0[] = { 0x00, 0x00, 0x00, 0x00, 0xAA };
//const uint8_t SLAVE_1[] = { 0xF0, 0xF0, 0xF0, 0xF0, 0xBB };
//const uint8_t SLAVE_2[] = { 0xF0, 0xF0, 0xF0, 0xF0, 0xCC };
//const uint8_t SLAVE_3[] = { 0xF0, 0xF0, 0xF0, 0xF0, 0xDD };
//const uint8_t SLAVE_4[] = { 0xF0, 0xF0, 0xF0, 0xF0, 0xEE };
//const uint8_t SLAVE_5[] = { 0xF0, 0xF0, 0xF0, 0xF0, 0xFF };

//const uint8_t SLAVE_0[] = { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA };
//const uint8_t SLAVE_1[] = { 0xBB, 0xBB, 0xBB, 0xBB, 0xBB };
//const uint8_t SLAVE_2[] = { 0xCC, 0xCC, 0xCC, 0xCC, 0xCC };
//const uint8_t SLAVE_3[] = { 0xDD, 0xDD, 0xDD, 0xDD, 0xDD };
//const uint8_t SLAVE_4[] = { 0xEE, 0xEE, 0xEE, 0xEE, 0xEE };
//const uint8_t SLAVE_5[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

// ==========================================================
// direct lift from page 41 pf the nRF24L01+ datasheet
// http://infocenter.nordicsemi.com/pdf/nRF24L01P_PS_v1.0.pdf
// ==========================================================
//const uint8_t SLAVE_0[] = { 0x78, 0x78, 0x78, 0x78, 0x78 };
//const uint8_t SLAVE_1[] = { 0xB3, 0xB4, 0xB5, 0xB6, 0xF1 };
//const uint8_t SLAVE_2[] = { 0xB3, 0xB4, 0xB5, 0xB6, 0xCD };
//const uint8_t SLAVE_3[] = { 0xB3, 0xB4, 0xB5, 0xB6, 0xA3 };
//const uint8_t SLAVE_4[] = { 0xB3, 0xB4, 0xB5, 0xB6, 0x0F };
//const uint8_t SLAVE_5[] = { 0xB3, 0xB4, 0xB5, 0xB6, 0x05 };
// ==========================================================

//const uint8_t SLAVE_0[] = { "0Node"};
//const uint8_t SLAVE_1[] = { "1Node" };
//const uint8_t SLAVE_2[] = { "2Node" };
//const uint8_t SLAVE_3[] = { "3Node" };
//const uint8_t SLAVE_4[] = { "4Node" };
//const uint8_t SLAVE_5[] = { "5Node" };

uint8_t SLAVE_0[] = { "0Node" };
uint8_t SLAVE_1[] = { "1Node" };
uint8_t SLAVE_2[] = { "2Node" };
uint8_t SLAVE_3[] = { "3Node" };
uint8_t SLAVE_4[] = { "4Node" };
uint8_t SLAVE_5[] = { "5Node" };


//uint8_t addr[][6] = { "0Node", "1Node", "2Node", "3Node", "4Node", "5Node" };
//uint8_t addr[] = { "0Node" "1Node" "2Node" "3Node" "4Node" "5Node" };
//const uint8_t slave_0[] = { "0Node" };
//const byte wAddress[] = { "0Node" "1Node" "2Node" "3Node" "4Node" "5Node" };
//const byte addr[] = { "0Node", "1Node", "2Node", "3Node", "4Node", "5Node" };
//const byte addr[] = { "0Node" "1Node" "2Node" "3Node" "4Node" "5Node" };
//uint8_t addr[][6] = { "0Node", "1Node", "2Node", "3Node", "4Node", "5Node" };
//uint8_t addr[][6] = { "0Node", "1Node", "2Node", "3Node", "4Node", "5Node" };

Some of these have permitted me to have my master address ONE slave at a time. The set above that are not commented out are as reliable as any. However, NONE of them work when I have two slaves (say SLAVE_1 and SLAVE_2) running at the same time. The result of trying to have one master and two slaves is ALWAYS chaos.

That is why I asked you if you have had more than one slave unit running with your master at the same time. Something happens that makes the addresses no longer unique. Something which is, as far as I know, beyond my control.

Now CaptainJack said he had found a solution in another thread you have visited. Unfortunately the solution went down with the Black Pearl. Leastways, CaptainJack did not tell anyone what his solution was.

I, for one, would dearly love to know the answer. What addresses will work when multiple slave programs are running in parallel with the master program?

rickduley:
The result of trying to have one master and two slaves is ALWAYS chaos.

Post the master and slave programs that represent your best attempt and still demonstrate the chaos.

...R

You have to move the different byte in the address to the LSB position,
making it the first value of the initializer list, not the last.

Datasheet

Addr Data Pipe 0 (RX_ADDR_P0): 0x7878787878
Addr Data Pipe 1 (RX_ADDR_P1): 0xB3B4B5B6F1
Addr Data Pipe 2 (RX_ADDR_P2): 0xB3B4B5B6CD
Addr Data Pipe 3 (RX_ADDR_P3): 0xB3B4B5B6A3
Addr Data Pipe 4 (RX_ADDR_P4): 0xB3B4B5B60F
Addr Data Pipe 5 (RX_ADDR_P5): 0xB3B4B5B605

Your misinterpretation

// ==========================================================
// direct lift from page 41 pf the nRF24L01+ datasheet
// http://infocenter.nordicsemi.com/pdf/nRF24L01P_PS_v1.0.pdf
// ==========================================================
//const uint8_t SLAVE_0[] = { 0x78, 0x78, 0x78, 0x78, 0x78 };
//const uint8_t SLAVE_1[] = { 0xB3, 0xB4, 0xB5, 0xB6, 0xF1 };
//const uint8_t SLAVE_2[] = { 0xB3, 0xB4, 0xB5, 0xB6, 0xCD };
//const uint8_t SLAVE_3[] = { 0xB3, 0xB4, 0xB5, 0xB6, 0xA3 };
//const uint8_t SLAVE_4[] = { 0xB3, 0xB4, 0xB5, 0xB6, 0x0F };
//const uint8_t SLAVE_5[] = { 0xB3, 0xB4, 0xB5, 0xB6, 0x05 };
// ==========================================================

This should work

uint8_t SLAVE_0[] = { "0Node" };
uint8_t SLAVE_1[] = { "1Node" };
uint8_t SLAVE_2[] = { "2Node" };
uint8_t SLAVE_3[] = { "3Node" };
uint8_t SLAVE_4[] = { "4Node" };
uint8_t SLAVE_5[] = { "5Node" };

Pipes.png

Addresses for pipes 1 to 5 have to share the 4 high bytes of the address.
Remember that pipe 1 hast to be set to one of the common prefix addresses, before using pipes 2 to 5.

Whandall:
This should work

uint8_t SLAVE_0[] = { "0Node" };

uint8_t SLAVE_1 = { “1Node” };
uint8_t SLAVE_2 = { “2Node” };
uint8_t SLAVE_3 = { “3Node” };
uint8_t SLAVE_4 = { “4Node” };
uint8_t SLAVE_5 = { “5Node” };

This addressing system is current in my code and it gives the best results yet. It allows communication between Master and any ONE slave. It does not work if I have two or more slaves running.

robin2 here is the code.
Notes:

  1. You change the slave(s) the Master talks to at lines masterBackChat::462 ff. Just comment/uncomment. Slaves 3, 4, and 5 do not have code to assign tasks, but they should handshake as individuals.
  2. You change the SLAVE_NUMBER of the individual slaceBackChat instantiation at line slaveBackChat::31

masterBackChat.ino (36.4 KB)

slaveBackChat.ino (21.1 KB)

Then you have some errors in your program.

[SOLVED] pipes supprting auto ack NRF24L01

the last post contains a working 5 pipe arrangement with 3 pipes doing ack-payload.

 switch (SLAVE_NUMBER)
 {
 case '1':
 radio.openReadingPipe(1, SLAVE_1);
 radio.openWritingPipe(SLAVE_1);
 break;
 case '2':
 radio.openReadingPipe(2, SLAVE_2);
 radio.openWritingPipe(SLAVE_2);
 break;
 case '3':
 radio.openReadingPipe(3, SLAVE_3);
 radio.openWritingPipe(SLAVE_3);
 break;
 case '4':
 radio.openReadingPipe(4, SLAVE_4);
 radio.openWritingPipe(SLAVE_4);
 break;
 case '5':
 radio.openReadingPipe(5, SLAVE_5);
 radio.openWritingPipe(SLAVE_5);
 break;
 default:
 if (debug) Serial.println("*****No slave of that number*****");
 }

This can not work for pipes 2 to 5.

But I already told you:

Whandall:
Addresses for pipes 1 to 5 have to share the 4 high bytes of the address.
Remember that pipe 1 hast to be set to one of the common prefix addresses, before using pipes 2 to 5.

If you want to use less than three pipes at a time, use pipe 0 and/or 1.

Whandall:
the last post contains a working 5 pipe arrangement with 3 pipes doing ack-payload.

I followed that code as you and mestek123 were developing it. Congratulations, you have one slave that can answer 5 phones (so to speak). It doesn't do anything else except demonstrate that it is possible for one slave to answer 5 phones.

I am working on a machine control system where 5 individual slaves each answer one phone, do what they are told to their part of the machine, then tell the master node the job is done. When appropriate, the master node can then ring up an individual slave and tell it to do something else. In another metaphor, the master is the conductor, the 5 slaves the chamber orchestra each playing a different instrument.

My research leads me to believe that the cause of the problems in running more than one slave unit with the master is in the addressing. You will not understand the problem unless you try to run two instantiations of a slave unit with a master calling each individually. That means setting up three sets of hardware. When I got my system to run with one slave I made the mistake of assuming that it would, therefore, run with two or three slaves. It doesn't! It is that solution I am seeking here.

Incidentally, I seem to remember mestek123 wanting to know the solution CaptainJack said he had. I am not alone.

Whandall:
This can not work for pipes 2 to 5.
If you want to use less than three pipes at a time, use pipe 0 and/or 1.

I want to use more than one slave unit at a time. That means a master unit and two or more slaves. None of the address systems I have tried (including yours) permits this.

rickduley:
I want to use more than one slave unit at a time. That means a master unit and two or more slaves. None of the address systems I have tried (including yours) permits this.

Let's go back to basics.

Is there any reason why your master cannot poll the slaves in turn? If that is possible then there is no need for complex addressing. Everything can be done with a single pipe.

...R

You still do not understand how the pipes/addresses work.

You are using pipes 2 to 5 without previous initalization of pipe 1, again: this can not work*.

You are using only one pipe in the quoted code, so use pipe 1 or pipe 0 for the address.

You don't have to put the fourth address in the fourth pipe.

Edit: *receiving on that channel.

I think you do not really understand the ack-payload process.
(Symptoms: no preloading of ack-payload data, function names.)

That data has to be loaded before a packet is received,
you seem to use it like an extra send, but the data that the transmitting node gets,
is the data that was loaded before that packet.

On a node that listens, your delay(500) (25x, 40x, 30x) are an invitation to loose packets, get out of synch, etc.

I think a NRF24 program should not have any delays.

Whandall:
I think a NRF24 program should not have any delays.

If he is using the ackPayload process it will be OK to limit how often the master calls the slave. But the slave must be listening all the time.

...R

There is only one ackpayload that can be sent, three packets in the input fifo after those you start to loose packets.

If it is guaranteed that nobody send while delaying, why bother listening?

The whole mechanism of the programs is flawed, ackpayload is used as an answer/handshake,
but the first request is guaranteed to get no ackpayload like any first packet after a send of this node.

Whandall:
If it is guaranteed that nobody send while delaying, why bother listening?

I think we are at cross purposes. I meant that the sender can have an interval between transmissions. I agree that the listener should listen all the time.

I am also assuming that the OP organizes his system as 1 sender and 5 listeners.

...R