NRF24L01+ AckPayload Erste Nachricht

Moin,

Was muss ich in meinen Code noch einbauen, das ich die erste AckPayload Nachricht erhalte? Mit meinem jetzigen Code, geht immer die erste AckPayload verloren :frowning:

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

RF24 radio(7,8);

byte addresses[][6] = {"1Node","2Node"}; 
int counter = 1; 

void setup(){

  Serial.begin(115200);

  radio.begin();

  radio.enableAckPayload();                     // Allow optional ack payloads
  radio.enableDynamicPayloads();                // Ack payloads are dynamic payloads
  
   radio.openWritingPipe(addresses[0]);
   radio.openReadingPipe(1,addresses[1]);

  radio.startListening();                       // Start listening  

}

void loop(void) {
  
/****************** Ping Out Role ***************************/

    char a1[] = "hello ";
    char a2[18];
    
    radio.stopListening();  
    
    a1[6] = (counter+'0');
    a1[7] = '\0';
                                                            
    if ( radio.write(&a1, 8 )){                         // Send the counter variable to the other radio 
      Serial.print("Sent: ");
      Serial.print(a1);
      if(!radio.available()){                             // If nothing in the buffer, we got an ack but it is blank
          Serial.println("no radio is available");
        }
        else{      
            while(radio.available() ){                      // If an ack with payload was received
                radio.read( &a2, 18 );                  // Read it, and display the response time
                Serial.print("    Got: ");
                Serial.println(a2);
                }
        }
    if (counter <9 ) counter++;
    else (counter  = 0);
    }
    
    else    {        
      Serial.println(F("Sending failed.")); 
      }          // If no ack response, sending failed
    
    delay(1000);  // Try again later

}
#include <SPI.h>
#include "RF24.h"

RF24 radio(7,8);

byte addresses[][6] = {"1Node","2Node"};              // Radio pipe addresses for the 2 nodes to communicate.

void setup(){

  Serial.begin(115200);

  radio.begin();

  radio.enableAckPayload();                     // Allow optional ack payloads
  radio.enableDynamicPayloads();                // Ack payloads are dynamic payloads

    radio.openWritingPipe(addresses[1]);        // Both radios listen on the same pipes by default, but opposite addresses
    radio.openReadingPipe(1,addresses[0]);      // Open a reading pipe on address 0, pipe 1

  radio.startListening();                       // Start listening  
  
  radio.writeAckPayload(1,1,1);          // Pre-load an ack-paylod into the FIFO buffer for pipe 1

}

void loop(void) {

/****************** Pong Back Role ***************************/
    byte pipeNo;                          // Declare variables for the pipe and the byte received
    char a1[8];
 
    while( radio.available(&pipeNo)){              // Read all available payloads

      radio.read( &a1, 8 );                   

      Serial.print("Got: ");
      Serial.print(a1);
      Serial.print("   Sent: ");
      Serial.println(a1);
      
      radio.writeAckPayload(pipeNo,&a1, 8 );  // This can be commented out to send empty payloads.

   }
}

was ich so bekomme:

Sent: hello 1`    Got: 
Sent: hello 2`    Got: hello 1
Sent: hello 3`    Got: hello 2

Wie kriege ich beim Sender, das erste Payload?

Das eine Byte an der Adresse 1 könnte einfach eine Null sein, oder etwas das nicht printable ist.

Benutz doch das gleiche Statement für das Preload wie für das Reload.

      radio.writeAckPayload(pipeNo,&a1, 8 ); payloads.

a1 sollte dann aber global sein und einen Inhalt wie "hello 0" haben.

Schon klar, aber das behebt ja nicht mein Problem, das mein Sender das erste Payload nicht empfängt, sondern immer um 1 Payload hinterher hängt...

Dir ist schon klar, dass das genau so sein muss?
Vorher mit einem Paket laden, beim nächsten Empfang wird diese Nachricht gesendet,
nicht die, die danach wieder vorgeladen wird.

Das ist mir klar, aber es ändert schlicht nichts, das ich am Sender die erste Payload NICHT empfange, auch wenn ich beim Receiver:

radio.enableAckPayload();                     // Allow optional ack payloads
  radio.enableDynamicPayloads();                // Ack payloads are dynamic payloads

    radio.openWritingPipe(addresses[1]);        // Both radios listen on the same pipes by default, but opposite addresses
radio.openReadingPipe(1,addresses[0]);      // Open a reading pipe on address 0, pipe 1

radio.startListening(); 
radio.writeAckPayload(1,"hello 0", 8 ); payloads.

Wenn du es sagst, es ist zumindest ungewöhnlich,
ich habe schon das erste in setup geladene Paket als Ack-Payload erhalten.

Du könntest das preload vor das startListening verschieben.

Ansonsten, wenn das bei dir so ist, wo ist das Problem?
Schick am Sender das erste Paket zweimal, das erste hat halt dann kein Ack-payload.

Hm... vielleicht bin ich auch einfach zu doof, oder denke zu kompliziert...?

Leider kein erfolg, der Sender blieb immer 1 Paket dahinter....

Das Problem ist, ich schicke den Befehl "BATTERY" an eine Adresse, diese gibt mir per "ACK" dann die Batterie-Spannung zurück, schicke danach den Befehl "LUX" dann erhalte ich per ACK die LUX als Analogwert zurück.

Aktuell ist es so, ich sende Battery kriege nichts, sende dann LUX und kriege dafür die Batteriespannung zurück, beim nächsten "Battery" Befehl, dann die LUX Zahl.... So wiederholt sich das für alle Anfragen (Bleibt Asynchron 1 Paket dahinter)

Klar könnte ich erstmal ein Fake Paket los schicken, bis das "läuft" aber ist ja eigentlich nicht sinn und zweck der Sache.

Beim Sender muss ich aber nicht ein writeAckPayload losschicken?

Das funktioniert nicht so wie du glaubst.
Du bekommst keine Antwort per Ack, die Info im Ack muss älter als die Nachricht sein.

Schick einfach Batteriewert und Lux als ein Ack-Payload.

Da hast du wohl leider Recht, ich dachte das es dennoch funktioniert?
Dachte eigentlich das dass Funktionieren sollte, wozu gibts denn die Funktion dann um eine Payload zurück zugeben, wenn diese nicht Synchron ist?

Das sind ja leider nicht die einzigen Infos die ich schicke, die Payload Länge ist ja ohne Mesh auf 32 Begrenzt. Soviel Informationen kriege ich leider nicht in eine einzelne Payload, deshalb hänge ich genau an diesem Problem fest :frowning:

Nö, du hängst nur in deiner Denke fest.

Sende jeden Request direkt aufeinanderfolgend zweimal,
und betrachte nur den Ack-Payload des zweiten (das ist deine "Antwort" auf den ersten).
Dazu musst du nur entsprechend schnell preloaden.

Alternativ könntest du erst nach der Analyse des empfangenen Pakets etwas preloaden,
das dann mit dem zweiten Request abgegriffen wird.
(Hier sehe ich eine weitere Möglichkeit einfach viele Daten zu übertragen,
indem man in der Frage spezifiziert, welchen Teil der Daten man möchte.)
Ack-Payload ist keine Pflicht, nur eine Möglichkeit.

Dein Beispiel ist nicht tauglich zu sehen, was du wirklich wo machst,
also kannst du nur generelle Tipps bekommen.

Haben deine Knoten wirklich mehr als 32 Byte Daten zu berichten?
Erscheint mir sehr viel, ich bin bisher selten an diese Grenze gestoßen.

Aber wenn du mehr Daten zu berichten hast, kannst du ja zusätzliche Requests benutzen,
zwei benutzt du ja eh schon, um top-aktuell zu sein (bzw. um eine "Antwort" zu bekommen).

Die physikalische Payload Länge ist immer auf 32 Bytes begrenzt,
Mesh ist 'lediglich' ein Protokoll das multi-Packet Nachrichten unterstützt,
was natürlich die nutzbare Paketgröße weiter verkleinert.

request1 -> Keine Antwort
request2 < ack auf 1
request3 -> Kommt jetzt keine Antwort oder ack auf 2?
request4 < ack auf 3?

Ich find mich da nicht wirklich rein, halte das Verfahren aber für völlig kontraproduktiv.
Ich hab ja mit denen nu ne Menge gemacht :wink: aber irgendwie will mir nicht in den Sinn, warum ich zwei Payloads schicken muss um ein payload.ACK zu bekommen.

Dann stimmt IMHO etwas an dem Konzept nicht.
Kannst Du mir das bitte auflösen?

Es sind einfach zwei unabhängige Streams von Paketen.
Nur das Ack gehört zum aktuellen Paket,
die Daten mussten aber vor Empfang des Pakets generiert und übertragen werden.

Du kannst keine Antwort erwarten, die vorliegen muss, ehe die Frage gestellt wird.
Die Kommunikation soll so schnell als möglich erfolgen,
da bleibt keine Zeit vor einem Ack den Prozessor zu bemühen.
Insofern ist deine Anwendung nicht wirklich darauf abgestimmt,
kann aber über einen zweiten Request erfüllt werden.

Willst du lieber jedes Mal den Mode beider Stationen ändern,
um die Antwort zu übertragen?
Das dauert länger als ein zweiter Request.

Es funktioniert halt nicht so wie du (und viele andere) sich das vorstellen,
bevor sie sich wirklich damit auseinandersetzen.
Ist ein prima Rückkanal, aber halt ein Paket versetzt, was in der Natur der Sache liegt.

Aber es ist wie mit der maximalen Paketlänge,
mehr wäre schöner, aber man kann und muss damit leben.

request 1 -> Keine Antwort
request 2 -> Antwort auf Request 1
request 3 -> Antwort auf Request 2
request 4 -> Antwort auf Request 3
request 5 -> Antwort auf Request 4

u.s.w

Ich halte das ACK Verfahren auch für kontraproduktiv wenn das wirklich so funktionieren soll.
Doch leider kann ich im Netz nichts finden, das es genau SO sein SOLL, wie ich es habe.

Okay, wie würde denn deine Empfohlene Methode sein wenn ich folgendes machen möchte:

Abfrage erfolgt alle 15 Sekunden...

(Master wechselt in Sendemodus)
Master sendet Request an Node 1

(Master wechselt von Sende und Empfangsmodus)
Master wartet auf Node 1 seine Antwort.

(Master wechselt in Sendemodus)
Master Sendet Request an Node 1

(Master wechselt in Empfangsmodus)
Master wartet auf Node 1 seine Antwort.

Es kann ja nicht Sache des Erfinders gewesen sein, das die NRF24 Module als "only Sender" und "only Receiver" gedacht sind? oder irre ich mich?

Nein. :wink:

Und genau hier würde ich eingreifen:
Abfrage erfolgt alle 15 Sekunden...
Antwortzeit auf xxx(!?)ms begrenzt.

(Master wechselt in Sendemodus)
Master sendet Request an Node 1

(Master wechselt von Sende in Empfangsmodus)
Master wartet auf Node 1 seine Antwort oder ob die Anwortzeit abgelaufen ist.

Die Antwort besteht aus tatsächlichen zwei Teilen.
Im ersten Teil wird bestätigt, das Anfrage empfangen und auf diese reagiert wird; aufgefüllt mit einer ID

Die zweite enthält die ID und die Antwort, was abgefragt wurde.

Wird Antwort Teil1 empfangen und Teil2 nicht, geht das im nächsten Umlauf wieder von vorn los.

Das könnte Deine Lösung sein. Dann bist Du mit dem ACK bei und sendest die ID, die schon vorher angelegt wurde.
Und im nächsten Durchgang die ID mit payload.

Bekommst Du kein ACK.ID, gehst Du gleich weiter und fragst den nächsten Node ab ohne auf den Abbruch durch TiemOut zu warten...

1 Like

Da sehe ich keine Anwendung für Ack-Payload.
Mach doch einfach was du da beschreibst, ohne den "Warten" Teil.

Ich würde alle 15 Sekunden eine Abfrage machen und nur dafür in den Sendemodus gehen.
Nicht auf irgendetwas warten, sondern einfach Nachrichten der anderen verarbeiten,
auch, wenn ich diese vorher mit einer Nachricht auslöse.

Wenn viele Daten übertragen werden sollen ist ein häufiger Modewechsel ungünstig.

1 Like

woki toki oder walkie-talkie so is es
:wink: