Background
I am trying to build a basic project involving 3 nRF24L01+ modules. One will act as a transmitter, the other two receivers. The transmitter will send identical payloads to both receivers at all times, and as such all devices share the same address and pipe.
However, one of the receivers is far for important than the other, and I want to be absolutely sure that this receiver has gotten every message (or at least as many as possible). The other receiver is best-effort, it would be nice if it got most of them but I don't care if it misses any.
The Problem
In normal operations with autoAcks, it seems to be whichever receiver gets the message first will send an auto ack and the transmitter will cease any additional retries or write attempts. This gets me in a scenario where the important receiver is missing many messages because the 2nd answered first. I would like to make it so that the transmitter will only listen to acks from the first receiver, and once its good, will stop writing. If the other receiver has gotten the message as this point, great. If not, I don't care.
My Idea
To accomplish this, my thought was to disable autoAcks (radio.setAutoAck(false)) on all devices and have the important receivers manually write its own ackPayload. The transmitter would then read this ack payload to know when to move on. The 2nd, less important receiver sends no ack payload at all and gets whatever it can.
However, as soon as I disable autoAcks, the receivers stops getting any messages of any kind. Even with a manual retry scheme of sending the writing the same message up to 10 times, there is never an ack payload present and no data is ever received on the receiver. As soon as I re-enable autoAcks, everything works again and I can see the ackPayloads on the transmitter.
Transmitter
#include <Arduino.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
RF24 radio(9, 10); // CE, CSN
const byte address[5] = {'0', '1', '2', '3', '4'};
const float LOOP_INTERVAL = 16.666; //60Hz in ms
const char text[] = "Hello World";
long previousMillis = 0;
int16_t ackData = 0;
void setup() {
Serial.begin(9600);
radio.begin();
radio.setChannel(115);
radio.setPALevel(RF24_PA_MAX);
radio.setDataRate(RF24_250KBPS);
radio.openWritingPipe(address);
radio.enableDynamicPayloads();
radio.enableAckPayload();
radio.setRetries(3, 15);
// radio.setAutoAck(false); //This breaks it
radio.stopListening();
Serial.println("starting up...");
}
void loop() {
if((millis() - previousMillis) < LOOP_INTERVAL) {
return;
}
previousMillis = millis();
ackData = 0;
radio.write(&text, sizeof(text));
if(radio.isAckPayloadAvailable()) {
radio.read(&ackData, sizeof(ackData));
Serial.println("ack");
} else {
Serial.println("no ack");
}
}
Important Receiver code (other receiver would be identical with the ack payload stuff removed).
#include <Arduino.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
RF24 radio(35, 34); // CE, CSN
const byte address[5] = {'0', '1', '2', '3', '4'};
const int16_t ACK_DATA = 1;
void setup() {
Serial.begin(9600);
radio.begin();
radio.setChannel(115);
radio.setPALevel(RF24_PA_MAX);
radio.setDataRate(RF24_250KBPS);
radio.openReadingPipe(0, address);
radio.enableDynamicPayloads();
radio.enableAckPayload();
radio.writeAckPayload(0, &ACK_DATA, sizeof(ACK_DATA));
// radio.setAutoAck(false); //This breaks it
radio.startListening();
}
void loop() {
if (!radio.available()) {
return;
}
char text[32] = "";
radio.read(&text, sizeof(text));
radio.writeAckPayload(0, &ACK_DATA, sizeof(ACK_DATA));
Serial.println(text);
}
I'm using the RF24 library: http://tmrh20.github.io/RF24/index.html
My transmitter is an Arduino Nano
My receivers are Teensy 4.1s (These devices work fine under normal circumstances so it is likely not a compatibility issue, rather a misunderstanding of the library or these radios on my part).
Questions
My questions are:
-
Why does disabling autoAck seem to affect manual ackPayloads?
-
Is there a better way than this to accomplish my original goal (ensure one particular receiver out of two gets the message). I thought about putting the two receivers on different addresses, but in the interest of speed I want to minimize the number of write calls.