USB-Serial C++ Timing Probleme
-
Hallo Zusammen

Ich habe ein C++ Programm geschrieben um einen Sensor unter Linux
auszulesen. Es handelt sich um den CHR-6dm, der per USB angeschlossen
wird, aber per serieller Schnittstelle (/dev/ttyUSB0) ausgelesen.
Es handelt sich um einen USB Serial Converter: Future Technology Devices
International, Ltd FT232 USB-Serial (UART) IC
Ich kann über diese Schnittstelle mit dem CHR-6dm kommunizieren, was
auch schon sehr gut klappt. Im Prinzip geht es mir nur darum, möglichst
schnell Daten auszulesen. Dies ist von 20-300Hz möglich:
"The CHR-6dm is factory-configured to broadcast angles and angular rates
at 200 Hz over a TTL UART at 115200 baud. The serial protocol uses 8
data bits, 1 stop bit, and no parity."
Der Sensor schickt mir genau 39 Byte die ich lesen möchte.Ich öffne also eine serielle Verbindung:
// Seriell Schnittstelle öffnen und konfigurieren
int fd_seriell = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY |
O_NONBLOCK);
int flags = fcntl(fd_seriell, F_GETFL);
flags = ( O_DIRECT | O_FSYNC | O_RSYNC | O_DSYNC);
if (fd_seriell == -1) perror("open_port: Unable to open serial port
");
else fcntl(fd_seriell, F_SETFL, 0);
leselaenge = 39;
setzeOptionen(&fd_seriell);und konfiguriere sie:
http://nopaste.immersight.de/?3ad970837b6016ae#JIN...
Die Zeit zwischen dem Lesen von der Schnittstelle messe ich dabei. Das
Gerät ist auf 300 Hz eingestellt uns sendet mir damit alle 5,5ms 39
Byte.
read((*p_fd_seriell),&stream,leselaenge);//Stream lesenDas Ergebnis ist leider nicht zufriedenstellend. Anstatt alle 5,5ms
einen Wert auszulesen, ergibt sich dieses komische Muster:
http://nopaste.immersight.de/?d00eb0eb88bf16d7#Z5e...Als hässliche Lösung habe ich das nun so gemacht. Vor dem Read setze ich
den Thread einfach 3ms schlafen:
boost::this_thread::sleep(boost::posix_time::microseconds(3000));
Dann ergibt sich ein regelmäßiges Muster wie ich es gerne hätte (der
Beweis dass es geht):
http://nopaste.immersight.de/?95e44e07fbf177f3#BmX...Ich frage mich warum der read-Aufruf nicht einfach wartet bis wieder 39
Byte vorhanden sind. Wie kann denn in 3 mal nacheinander in 0.05ms etwas
ausgelesen werden?Vielen Dank schonmal im Voraus!

-
Ich mache sowas anders:
1.) Warten auf Daten
2.) Alle verfuegbaren Daten auslesen
3.) Parsen der Daten, falls vollstaendig Paket in Messagequeue schreiben
4.) Goto 1.)Ich frage mich warum der read-Aufruf nicht einfach wartet bis wieder 39
Byte vorhanden sindman read schrieb:
read() attempts to read up to count bytes from file descriptor fd into the buffer starting at buf.
Also ganz einfach: weil das Verhalten der Funktion nicht so spezifiziert ist.
-
Hab nun die Ausgabe um eine Angabe der gelesenen Byte erweitert:
http://nopaste.immersight.de/?5a40863665485dd0#1z84uxEzXxHnjDgX6ImBSpSaCAOLHF/BwCyH4vg5v5Q=Man sieht deutlich dass er immer nur 39 Byte liest! Ich will eigentlich einen blockierenden Aufruf haben der 4 MilliSekunden blockiert (sollte) und mir dadurch einen super Takt liefert. (Diese Kode läuft in einem eigenen Thread!).
Also die Aussage das read hier mehr oder weniger als 39 Byte liest lässt sich nicht bestätigen knivil.Ich mache sowas anders:
1.) Warten auf Daten
2.) Alle verfuegbaren Daten auslesen
3.) Parsen der Daten, falls vollstaendig Paket in Messagequeue schreiben
4.) Goto 1.)Wie machst du denn das? Mit einem Signal? Ich warte ja auch auf Daten, nämlich bis 39 Byte angekommen sind, das macht doch read? Oder wie soll man das sonst machen?
-
@fabske
Poste mal den gesamten Code deiner Empfangsschleife.
-
und mir dadurch einen super Takt liefert.
Etwa 1000 Lines of Code brauche ich dafuer (geschaetzt). Habe gerade mein Projekt nicht zur Hand, um nachzuzaehlen.
-
Wie gesagt, es handelt sich um ein Modul innerhalb eines Frameworks das in einem eigenen Thread (arbeiten()) läuft: http://nopaste.immersight.de/?0051b943683dc619#wdtCo8wtxDqlUCQcTu6YsoLjNFYYjvkOJwjQtIgsoAI=
Mich würde echt interessieren knivil wie du USB halbwegs echtzeitfähig machst?
-
1.) Also ein Thread liesst Daten und packt das Paket* in eine Msg-Queue ( http://www.youtube.com/watch?v=309Y-QlIvew&list=PL1835A90FC78FF8BE&index=9&feature=plpp_video )
2.) Ein anderer Thread wartet solande, bis ein Paket in der Msg-Queue verfuegbar ist.Producer & Consumer halt. Die meiste Arbeit ist in die Ansteuerung des Com-Ports geflossen. Unter Windows mit AsyncIO. Echtzeitfaehig ... naja, manchmal liegen 2 Pakete in der Msg-Queue (bei 1000 Hz Sendefrequenz). Aber Windows ist kein Echtzeitsystem.
*Dazu musst du natuerlich wissen, wie du aus deinem Datenstrom ein Paket machst. Die Anzahl von 39 Byte reicht da nicht bzgl. Uebertragunsfehler oder Synchronisation nicht.
-
@fabske
Das sieht soweit auf den ersten Blick OK aus ...Vielleicht funkt dir der Linux-Treiber des USB/RS232 Adapters dazwischen.
Ein USB 2.0 Gerät kann man jede Millisekunde pollen (vielleicht auch schneller, hab den genauen Wert vergessen), d.h. für deine Anwendung sollte das reichen. Ein Jitter von 1-2 ms wäre ja vermutlich kein Beinbruch.Unter Windows hatte ich mit USB/RS232 Adaptern auf jeden Fall noch kein solches Problem, da waren die Daten immer quasi "sofort" verfügbar (also mit einer Verzögerung < 2ms, was für mich immer vollkommen ausreichend war).
Ich würde die Frage vielleicht eher im Linux Forum stellen.
C++ Problem ist es auf jeden Fall keines, und vermutlich auch kein grundsätzliches Problem mit deinem Code.Nochwas: mach dir ein kleines Test-Projekt, wo du den ganzen Auswertungs-Code etc. rauswirfst. Nur Lesen von der Schnittstelle + Checksum & Sync prüfen, Erfassung wann was passiert ist (wann wie viel Daten gelesen, war Checksum OK, war Sync OK etc.), und verzögerte Ausgabe. Einerseits um sicherzustellen dass du nicht durch irgendwas anderes Verzögerungen verursachst (z.B. durch die Ausgabe der Debug-Infos, weitere Verarbeitung der Daten - was auch immer). Und andrerseits weil es in so einem Test-Projekt einfacher sein sollte diverse Dinge auszuprobieren.