Forum: Mikrocontroller und Digitale Elektronik Datenstream über nRF24L01+ wie übertragen?


von Karl K. (karl2go)


Lesenswert?

Ich möchte Messdaten eines oder mehrerer Datenlogger per nRF24L01+ 
Module übertragen. Kommunikation funktioniert soweit.

Nun hat der nRF24 ja nur 32 Bytes Payload. In den Tutorials mit nur 
einem Sensor am Arduino ist das kein Problem, das passt immer in die 
Payload. Ich habe aber mehrere Sensoren (Temp, RH, Licht, ADC1..6), die 
verschiedene Werte (Ganzzahl, Festkommazahl) in unterschiedlicher 
Skalierung (16bit, 32bit) erzeugen. Wenn ich die in einem Rutsch 
übertrage, werden die 32 Bytes der Payload überschritten.

Jetzt überlege ich, wie ich die Daten möglichst einfach und dennoch 
zuverlässig übertrage.

1. Binär hintereinander, etwa wie RTC-MODBUS
Vorteil: Es spart enorm Bytes
Nachteil: Ich übertrage keine Information über das Datenformat, 
Kommastelle, Anzahl der Bytes pro Wert. Das muss alles in Sender und 
Empfänger exakt übereinstimmen.
Der nRF24 scheint Probleme mit langen Payloads ohne Pegelwechsel zu 
haben, eine Übertragung von mehreren Werten mit Nullen könnte also 
fehlerhaft empfangen werden.

2. Hex-Codiert hintereinander, etwa wie ASCII-MODBUS
Vorteil: immer noch kürzer als ASCII-Strings, keine reinen Nullbytes in 
der Payload
Nachteil: wie 1., keine Info über Datenformat

3. ASCII, je ein Wert pro Payload
Beispiel: Dtemp1[-15.55°C]
Vorteil: Ich kann beliebige Werte senden, inklusive Kennung, Einheit und 
würde die 32Bytes doch nicht ausreizen. Geht ein Paket verloren (max. 
Retransmits überschritten), sind die anderen Werte dennoch gültig.
Nachteil: Es müssten sehr viele Datenpakete gesendet werden, um einen 
Datensatz zu übertragen.

4. ASCII, mehrere Werte pro Payload
Beispiel: Data1[-15.55,33.3,1023.0]
Vorteil: wie 3., und es würden weniger Pakete benötigt
Nachteil: Die Pakete wären nicht "schön" aufgebaut. Z.B. gehen 3 Werte 
eines Sensors (Temp, RH, Druck) in ein Paket, 6 Werte vom ADC müssten 
aber auf 2 Pakete aufgeteilt werden.

5. ASCII, alle Werte als Stream
Alle Werte hintereinander in einen Sendebuffer, dieser wird dann 
paketweise gesendet.
Vorteil: keine Probleme mit Payload-Länge
Nachteil: geht ein Paket verloren, ist der gesamte Datensatz 
unbrauchbar. Und ich muss irgendwie (zusätzliche Prüfsumme) feststellen 
können, ob alle Pakete angekommen sind.

6. ASCII, alle Werte als JSON Stream
Die Werte als JSON Stream ausgeben, sonst wie 5.
Vorteil: wie 5., aber willkürliche Anordnung der Daten möglich, 
Einheiten werden mit übertragen
Nachteil: wie 5., und erheblicher Overhead durch die JSON Formatierung

Welche Art der Datenübertragung hat sich in dem Bereich bewährt? Der 
nRF24 nimmt einem ja schon Vieles ab (AutoRetransmit, Enhanced 
ShockBurst Mode, CRC Validation (eines Paketes).

von Wolfgang (Gast)


Lesenswert?

Karl K. schrieb:
> Nun hat der nRF24 ja nur 32 Bytes Payload.

Dann definierst du verschiedene Datenpakettypen und überträgst in einem 
Byte den Typ.

> Der nRF24 scheint Probleme mit langen Payloads ohne Pegelwechsel zu
> haben, eine Übertragung von mehreren Werten mit Nullen könnte also
> fehlerhaft empfangen werden.

Dann sorge in deinen Payloads dafür, dass das nicht passiert.

Stichwort "Bit Stuffing". Bei längeren Sequenzen von 1en oder 0en fügst 
du nach einer bestimmten Anzahl ein gegenpoliges Bit zusätzlich ein. Der 
Empfänger weiß das und sortiert es wieder aus.

von Karl K. (karl2go)


Lesenswert?

Naja, andererseits haben wir 2019 und der nRF24 bringt ja schon einige 
Eigenintelligenz mit. Muss man sich da wirklich noch mit so Kram wie 
Bitstuffing beschäftigen?

Der nRF selbst arbeitet ja mit GFSK und entsprechenden Filtern zur 
Fehlerreduzierung, plus zuschaltbarem CRC.

von Wolfgang (Gast)


Lesenswert?

Karl K. schrieb:
> Der nRF selbst arbeitet ja mit GFSK und entsprechenden Filtern zur
> Fehlerreduzierung, plus zuschaltbarem CRC.

GFSK ist eine Modulationsart. Mit der Kodierung deines Datenstromes hat 
das nun wirklich nichts zu tun.
Du willst nicht wirklich bei der Datenkodierung/-dekodierung schlampen, 
um deine Fehleralgorithmen herauszufordern. Sonst geht hinterher die 
Jammerei wegen der geringen Reichweite los und/oder dir bricht die 
Datenrate ein, weil du auf Grund von deiner CRC immer feststellst, dass 
die Daten nicht heil ankommen.

von Karl K. (karl2go)


Lesenswert?

Wolfgang schrieb:
> GFSK ist eine Modulationsart. Mit der Kodierung deines Datenstromes hat
> das nun wirklich nichts zu tun.

Insofern schon, da FSK wahrscheinlich doch anfällig bei Daten ohne 
längeren Bitwechsel ist, weil dann keine Flanke zur Synchronisation da 
ist.

Wolfgang schrieb:
> Du willst nicht wirklich bei der Datenkodierung/-dekodierung schlampen,
> um deine Fehleralgorithmen herauszufordern.

Deswegen würde mich halt mal interessieren, wie andere sowas umsetzen 
und was sie für Erfahrungen damit haben.

Wie gesagt, es gibt unzählige Tuts wo mit dem nRF24 und nem Arduino oder 
Raspberry ein einzelner Sensorwert übertragen wird. Und wie das mit Tuts 
so ist: Wenn es spannend wird, hören sie auf. Also wie übertrage ich 
damit größere Datenmengen? (Wobei größere hier immer noch im Bereich 
wenige hundert Byte sind.)

Meine Überlegungen: Wenn ich mit ASCII arbeite, habe ich in einem Byte 
immer wechselnde Bits drin, auch wenn ich 000.0 übertrage. Wenn ich mit 
ASCII-Hex arbeite auch.

Wenn ich mit Packed-BCD oder Binärdaten arbeite, können längere Folgen 
nur Null auftreten, die müsste ich dann mit Bitstuffing oder 
Manchestercodierung auflockern, allerdings würde meine Payload dadurch 
um 20% bei Bitstuffing oder 100% bei Manchestercodierung länger - aber 
immer noch kürzer als die Zeichen als ASCII-String zu übertragen.

Was immer noch nicht das Problem löst: Was mache ich wenn die Bytefolge 
nicht mehr in meine Payload passt?

von Rico W. (bitkipper)


Lesenswert?

Karl K. schrieb:
> Wenn ich mit Packed-BCD oder Binärdaten arbeite, können längere Folgen
> nur Null auftreten, die müsste ich dann mit Bitstuffing oder
> Manchestercodierung auflockern, allerdings würde meine Payload dadurch
> um 20% bei Bitstuffing oder 100% bei Manchestercodierung länger - aber
> immer noch kürzer als die Zeichen als ASCII-String zu übertragen.
Ich bin da auch noch nicht drauf gekommen, daß der nRF24 keine interne 
Codierungseinheit bzw. Modem besitzt. Will demnächst was mit dem machen, 
insofern erstmal danke für den Tip und die Überlegung.
Normalerweise hat selbst ein älterer Transceiver wie der CC1101 sowas 
wie eine Manchester-Engine mit drin, die man nur benutzen muß. Der NRF 
ist eben viel billiger und hat deshalb andere Einsatzbereiche.

Ich würde hier erstmal zu einem Leitungscode, naheliegend Manchester 
Code, greifen. Halbiert zwar die Datenrate, macht aber Sinn bei längeren 
Folgen. Gibts auch schon Libs dazu, z.B.:
https://github.com/silentbicycle/spooky

Oder eben was anderes implementierbares:
https://de.wikipedia.org/wiki/Leitungscode

Oder im einfachsten Fall einen Scrambler implementieren, um die 
Gleichanteile zu eliminieren, mit dem schönen Nebeneffekt, daß die 
Datenrate nicht halbiert wird.
https://de.wikipedia.org/wiki/Scrambler_(Telekommunikation)

> Was immer noch nicht das Problem löst: Was mache ich wenn die Bytefolge
> nicht mehr in meine Payload passt?
Im einfachsten Fall mit lookup table bekannte und häufige Bytefolgen 
codieren. Besser würde ich aber zu Quellcodierung wie Shannon-Fano oder 
Huffman greifen.
https://de.wikipedia.org/wiki/Datenkompression#W%C3%B6rterbuchmethode
https://de.wikipedia.org/wiki/Datenkompression#Entropiekodierung
https://en.wikipedia.org/wiki/Shannon%E2%80%93Fano_coding

Habe nur das als beispielhafte Implementierung auf die Schnelle 
gefunden:
https://github.com/GENiEBEN/fanohuff

Das ist doch mal eine schöne nachrichtentechnische Aufgabe. Da werde ich 
gleich richtig sentimental, wenn mir meine Studienzeit wieder in 
Erinnerung kommt :-)

: Bearbeitet durch User
von Rico W. (bitkipper)


Lesenswert?

Karl K. schrieb:
> Naja, andererseits haben wir 2019 und der nRF24 bringt ja schon einige
> Eigenintelligenz mit. Muss man sich da wirklich noch mit so Kram wie
> Bitstuffing beschäftigen?
Das Manual vom Chip, das man so findet, ist übrigens von 2008. Und wie 
gesagt, war der Chip wohl für irgendwas Billiges vorgesehen.

von Wolfgang (Gast)


Lesenswert?

Karl K. schrieb:
> Deswegen würde mich halt mal interessieren, wie andere sowas umsetzen
> und was sie für Erfahrungen damit haben.

Die verwenden Bit Stuffing (z.B. max. 5 gleiche Bits hintereinander) und 
übertragen ihre Daten nicht per ASCII, sondern verwenden z.B. einen Code 
mit einem Hamming-Abstand von drei, so dass sich einzelne Bitfehler im 
Datenwort korrigieren lassen. Besser noch ist ein Blockcode.

von Karl K. (karl2go)


Lesenswert?

Rico W. schrieb:
> Ich würde hier erstmal zu einem Leitungscode, naheliegend Manchester
> Code, greifen.

Andererseits bietet mir der nRF24 ja schon OSI-Layer 1 und 2 an. Da will 
ich eigentlich nicht mehr mit Manchester oder Scrambling rummachen 
müssen.

Und zumindest mit ASCII läuft die Übertragung erstaunlich zuverlässig. 
Wenn Bytes falsch angekommen sind, dann lags an der Software. (Tipp: Man 
kann zwar eine Payload mit 34 Byte senden, es kommen trotzdem nur 32 an, 
nur wird halt die Länge falsch übermittelt.)

Allerdings ist meine Überlegung zu 5. unzureichend: Wenn eine Payload 
nicht übermittelt wird, gibts kein Ackn und die Übertragung wird 
abgebrochen. Damit ist der Datensatz eh unvollständig und wird vom 
Empfänger komplett verworfen.

Dann hab ich zwar keine falschen Daten, aber das ändert leider nichts 
dran, dass ich für den Datensatz gar keine Daten habe. Und im Sinne von 
"der Datalogger soll mit Akku laufen" will ich dann auch nicht ständig 
versuchen den Datensatz erneut zu senden.

von Rico W. (bitkipper)


Lesenswert?

Karl K. schrieb:
> Rico W. schrieb:
>> Ich würde hier erstmal zu einem Leitungscode, naheliegend Manchester
>> Code, greifen.
>
> Andererseits bietet mir der nRF24 ja schon OSI-Layer 1 und 2 an. Da will
> ich eigentlich nicht mehr mit Manchester oder Scrambling rummachen
> müssen.
Layer 1 (Sicherung) ist im Chip eben nur unzureichend für deine 
Anwendung umgesetzt. Dann mußt du dich entweder mit der Implementierung 
auseinandersetzen oder mit den Gegebenheiten abfinden.
Übrigens alles schonmal dagewesen:
Beitrag "Scrambler für Funkstrecke"

Guck dir mal das Packet Modem und den Scrambler nach G3RUH an. Hat sich 
lange Zeit bewährt, bis heute. Code gibt es auch:
https://gist.github.com/andresv/4589178
Oder ein App Note:
https://www.silabs.com/documents/public/application-notes/AN592.pdf

von Karl K. (karl2go)


Lesenswert?

Rico W. schrieb:
> Layer 1 (Sicherung) ist im Chip eben nur unzureichend für deine
> Anwendung umgesetzt.

Nun, offenbar nicht. Hab gerade mal ein paar Bitpattern ausprobiert: Es 
ist völlig egal, ob da Nullen oder ASCII oder 1010 Wechsel oder $FF 
durchgeschoben wird, auch mit 32 Bytes an Nullen ergeben sich weder 
Fehler im Datenstream noch eine merklich erhöhte Retransmit-Rate wegen 
fehlerhafter Pakete. Insofern würde ich durch irgendwelches Bitstuffing 
oder Scrambling nichts gewinnen.

Dass man lange Folgen von Nullen / Einsen vermeiden soll bezieht sich 
offenbar wirklich nur auf die Adresse. Es kommt dann zu erhöhten 
Empfangsfehlern, weil der nRF glaubt was zu empfangen was zur Adresse 
passt. Das wird dann zwar sowieso spätestens bei der Checksumme 
verworfen, aber erhöht halt den Fehlercounter.

Und 1010 Bitwechsel in der Adresse ($55 und $AA) soll man vermeiden, 
weil das die Preampel zur Synchro fortsetzt und auch zu falschen 
Adresserkennungen führen kann.

Für die Übertragung ist also offenbar egal ob Binärdaten oder 
ASCII-Strings. Jetzt muss ich nur sehen, ob die Einsparung mit Binär 
wirklich so viel mehr bringt, um die Nachteile gegenüber ASCII 
auszugleichen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.