(RF24) Problem using ack payload

I am using the RF24 library (gcopeland fork) for a radio controlled vehicle, and everything is working great. Now I want to try sending some information back from the vehicle to the controller, and it seems that the ack payload is a good way to do that. But unfortunately I can't get it to work at all.

I cut my code down to the simplest possible, and before I try the ack payload it goes like this:

//sender
radio.begin();
radio.openWritingPipe( pipe );

... and:

//receiver
radio.begin();
radio.openReadingPipe( 1, pipe );
radio.startListening();

Then I use radio.write and radio.read to perform a one-way transmission, and it works great.

Now, if I add radio.enableAckPayload() after the radio.begin() to both sides, the receiver never receives any packets. Has anyone else experienced this? Is there something else I need to change as well?

I have tried using writeAckPayload to set the contents of any ack packets that might get sent, but this seems to be irrelevant at this point because the receiver is not even receiving anything to ack in the first place. In any case, acks would still be sent even if I don't use writeAckPayload to fill their content right?

Now I want to try sending some information back from the vehicle to the controller, and it seems that the ack payload is a good way to do that.

No it's not.where did you get the idea that you can insert data in the ack packet? ack is to the sender make sure the receiver gets the payload without any error or if there are error the repeat the transmission.You can have this feature one or off, that because the function enableAckPayload() exist since you can turn it on or off.

I got that idea from the documentation, which says "Ack payloads are a handy way to return data back to senders without manually changing the radio modes on both units".
http://maniacbug.github.io/RF24/classRF24.html#abf8efced2ee9edbcc6510878b20edc1b

Please note also these functions, in the same documentation:
writeAckPayload - "The next time a message is received on pipe, the data in buf (up to 32 bytes max) will be sent back in the acknowledgement"
isAckPayloadAvailable - "Determine if an ack payload was received in the most recent call to write(). Call read() to retrieve the ack payload."

The library also includes an example demonstrating the use of this feature, inserting data in the ack packet:
http://maniacbug.github.io/RF24/pingpair_pl_8pde-example.html

There are plenty of people using the ack payload feature successfully. In particular these guys are using it for exactly the same thing as I'm trying to:
http://wiki.bitcraze.se/projects:crazyradio:protocol

If you think about it, the ack packet must contain some kind of content data, otherwise there would be no point sending it. The ack payload feature simply adds a little more to outgoing packets that were going to be sent anyway.

1 Like

Ok, after many hours I have it working. I narrowed the problem down to this line in the enableAckPayload function:

write_register(FEATURE,read_register(FEATURE) | _BV(EN_DYN_ACK) | _BV(EN_ACK_PAY) | _BV(EN_DPL) );

When I excluded the EN_DYN_ACK flag everything started working correctly (note that there are two such lines in that function if you make this change).

I should have mentioned that I am using Arduino pro minis and nRF24L01+ chips. I don't know if that would have anything to do with the problem though.

Here are a couple of other things I discovered while investigating:

writeAckPayload can only buffer three packets, and if you do it four times in a row, the program will block. The only way to get packets out of the buffer is by successfully reading a packet from the transmitter (which causes one of the buffered ack packets to be used), or by flushing the transmit buffer manually. So ideally you should only do writeAckPayload once for each successful read. I think the following arrangement is a good way to keep this under control (ack payload buffer will never hold more than one packet):

if ( radio.available() ) { // make sure the read will succeed
    radio.writeAckPayload( 1, buf, len ); // prep the ack payload
    radio.read( &got_time, sizeof(unsigned long) ); // also shunts out ack payload
}

I also found another small issue in the library, in that the features register was not being cleared in the begin function. This means that even when the Arduino is reset, any bits that were set previously, will remain set because the radio chip still has power. I discovered this problem because I was powering each of my pro minis with a battery, and switching my FTDI connector between them to upload different programs. Of course that is not the typical use, but I wasted a lot of time before I realized what was happening, so I thought I would mention it. You can make sure the features register is reset by adding this to the begin function:

write_register(FEATURE,0);

Anyway now that these issues have been sorted out, this little radio chip suddenly becomes much more useful! Using the 2Mbps setting I can get about 600 packets per second (18kb/s) in both directions. :slight_smile:

1 Like

Hello iforce2d

I am also using the RF24 library (gcopeland fork), with PRO MINI and UNO, for a vr input device,
and things are working well so far, but I am stuck at getting the ACK to be received.

On the transmitter I have - (snippets of relevant parts.)

String ACK_MSG;
byte Ack_Package[3];

    radio.setAutoAck(1);                    // Ensure autoACK is enabled
    radio.enableAckPayload();


byte NRF_SEND_ACK(String NRFPack = ""){

  NRFPack.getBytes(Send_Package, 32);


bool ok = radio.write(Send_Package,sizeof(Send_Package));

  if (!ok) {
    Serial.println("radio.write NOT OK");
  }else{
    Serial.println("radio.write OK.");
  }

    if ( radio.isAckPayloadAvailable() ) {
        radio.read(&Ack_Package,sizeof(Ack_Package));

        ACK_MSG = ((char *)Ack_Package);
        Serial.println(ACK_MSG);
    }else{
        Serial.println("NO ACK received");
    }

}

On the receiver I have - (snippets of relevant parts.)

String ACK_MSG;
byte Ack_Package[3];

    radio.setAutoAck(1);                    // Ensure autoACK is enabled
    radio.enableAckPayload();


void NRF_RECEIVE_ACK(){

 uint8_t pipe_num;
  if ( radio.available(&pipe_num) )  {

    //ACK
        radio.writeAckPayload( 1, &Ack_Package, sizeof(Ack_Package) );
        radio.writeAckPayload( 2, &Ack_Package, sizeof(Ack_Package) );

    bool done = false;
    while (!done)    {
        done = radio.read( &Received_Package, sizeof(Received_Package) );
//      delay(1);
    }

}

I have removed the EN_DYN_ACK flag from the .cpp, as seen below, as you suggest but I get a compile error after doing so...

void RF24::enableAckPayload(void)
{

  write_register(FEATURE,read_register(FEATURE) | _BV(EN_ACK_PAY) | _BV(EN_DPL) );

  // If it didn't work, the features are not enabled
  if ( ! read_register(FEATURE) )
  {
    // So enable them and try again
    toggle_features();
    write_register(FEATURE,read_register(FEATURE) | _BV(EN_ACK_PAY) | _BV(EN_DPL) );
  }

So any advice on how to get those packets moving would be much appreciated ;D

The gcopeland fork has an example "pingpair_pl" which uses ack payloads. That would probably be the first thing to try and get running.
What is the compile error you get from removing the EN_DYN_ACK flag? It looks ok to me.

Hi,

Right, pingpair_pl is the code I am using as the starting point, so I believe we are on the same page...

The compile error is really long, and I dont know which part is relevant so,
excuse me I will have to paste the whole thing..
I can compile without error, if I use the un-modified .cpp

RF24\RF24 - MOD.cpp.o:C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24 - MOD.cpp:661: first defined here
RF24\RF24.cpp.o: In function `RF24::openReadingPipe(unsigned char, unsigned long long)':
C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24.cpp:634: multiple definition of `RF24::openReadingPipe(unsigned char, unsigned long long)'
RF24\RF24 - MOD.cpp.o:C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24 - MOD.cpp:634: first defined here
RF24\RF24.cpp.o: In function `RF24::read(void*, unsigned char)':
C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24.cpp:582: multiple definition of `RF24::read(void*, unsigned char)'
RF24\RF24 - MOD.cpp.o:C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24 - MOD.cpp:582: first defined here
RF24\RF24.cpp.o: In function `RF24::startWrite(void const*, unsigned char, bool)':
C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24.cpp:510: multiple definition of `RF24::startWrite(void const*, unsigned char, bool)'
RF24\RF24 - MOD.cpp.o:C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24 - MOD.cpp:510: first defined here
RF24\RF24.cpp.o: In function `RF24::powerUp()':
C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24.cpp:443: multiple definition of `RF24::powerUp()'
RF24\RF24 - MOD.cpp.o:C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24 - MOD.cpp:443: first defined here
RF24\RF24.cpp.o: In function `RF24::powerDown()':
C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24.cpp:436: multiple definition of `RF24::powerDown()'
RF24\RF24 - MOD.cpp.o:C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24 - MOD.cpp:436: first defined here
RF24\RF24.cpp.o: In function `RF24::startListening()':
C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24.cpp:403: multiple definition of `RF24::startListening()'
RF24\RF24 - MOD.cpp.o:C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24 - MOD.cpp:403: first defined here
RF24\RF24.cpp.o: In function `RF24::getChannel()':
C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24.cpp:261: multiple definition of `RF24::getChannel()'
RF24\RF24 - MOD.cpp.o:C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24 - MOD.cpp:261: first defined here
RF24\RF24.cpp.o: In function `RF24::print_byte_register(char const*, unsigned char, unsigned char)':
C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24.cpp:209: multiple definition of `RF24::print_byte_register(char const*, unsigned char, unsigned char)'
RF24\RF24 - MOD.cpp.o:C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24 - MOD.cpp:209: first defined here
RF24\RF24.cpp.o: In function `RF24::begin()':
C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24.cpp:340: multiple definition of `RF24::begin()'
RF24\RF24 - MOD.cpp.o:C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24 - MOD.cpp:340: first defined here
RF24\RF24.cpp.o: In function `RF24::read_register(unsigned char, unsigned char*, unsigned char)':
C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24.cpp:38: multiple definition of `RF24::read_register(unsigned char, unsigned char*, unsigned char)'
RF24\RF24 - MOD.cpp.o:C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24 - MOD.cpp:38: first defined here
RF24\RF24.cpp.o: In function `RF24::write(void const*, unsigned char, bool)':
C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24.cpp:451: multiple definition of `RF24::write(void const*, unsigned char, bool)'
RF24\RF24 - MOD.cpp.o:C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24 - MOD.cpp:451: first defined here
RF24\RF24.cpp.o: In function `RF24::print_address_register(char const*, unsigned char, unsigned char)':
C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24.cpp:220: multiple definition of `RF24::print_address_register(char const*, unsigned char, unsigned char)'
RF24\RF24 - MOD.cpp.o:C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24 - MOD.cpp:220: first defined here
RF24\RF24.cpp.o: In function `RF24::printDetails()':
C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24.cpp:316: multiple definition of `RF24::printDetails()'
RF24\RF24 - MOD.cpp.o:C:\Users\NORIHIRO-01\Documents\Arduino\libraries\RF24/RF24 - MOD.cpp:316: first defined here

Ok,
thanks to being able to ask the right question, I realized that the compile error is caused by having backups of the original and modified .cpp file in the same directory :wink:
It has compiled successfully.

So did this make the difference between the ACK working and not working for you?

NT_N:
So did this make the difference between the ACK working and not working for you?

hmm.... not sure what you mean by "this". If you're talking about the compile error, I did not have that error to begin with.
If you're talking about the changes I mention above, yes, the ack payload was not working for me without making those changes.
Note that 'ack' and 'ack payload' are not quite the same. The ack itself was working for me right from the start - it's just that I could not get any data to be attached to the ack.

iforce2d:
If you're talking about the changes I mention above, yes, the ack payload was not working for me without making those changes.
Note that 'ack' and 'ack payload' are not quite the same. The ack itself was working for me right from the start - it's just that I could not get any data to be attached to the ack.

Right, that is what I meant. thanks.

To confirm, there is not need to do a stopListening after the write, and before the read, is that correct?

bool ok = radio.write(Send_Package,sizeof(Send_Package));

    if ( radio.isAckPayloadAvailable() ) {
        radio.read(&Ack_Package,sizeof(Ack_Package));

That's correct. You don't need to do stopListening anywhere.

I've encountered the same problem. Seems to occur when both the RX and TX units have the EN_DYN_ACK bit set in the FEATURE register. Clearing that bit in either unit seems to clear up the failed ack problem. Don't know if it's a silicon thing or if I'm missing something obscure in the data sheet. Weird.

is this where i want to ask how to tx imu data/values using the NRF to other MCU's/nodes/Slaves?

Hi,

We have a similar R/C project, but I am controling a sailing boat. It works fine, but I now I would like the solution a bit clever.

The issue that I have is that the ackpayload function seems to only work with up to 4 bytes..
I understand you have been able to use this function to send back a bigger payload.
I am a newbie and don't really understand your post. Do you mean that you actually send data one by one ?

Ideally, I would need to send back 5 int (current speed, current direction, ideal direction to next buoy, distance to next boy, wind angle).

Thanks for any help.

mrick:
Thanks for any help.

First you need to post your code - both programs.

And please use the code button </>so your code looks like thisand is easy to copy to a text editor

...R

There are timeout settings that can disturb acknowledge data, especially for lower transmission rates.

Look into the datasheet (ARD).