USB-Serial C++ Timing Probleme

Welches Modul/Treiber für welche Hardware, Kernel compilieren...
Antworten
Benutzeravatar
fabske
Beiträge: 2023
Registriert: 14.06.2003 15:07:51

USB-Serial C++ Timing Probleme

Beitrag von fabske » 13.07.2012 16:38:10

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:
Paste1
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 lesen

Das Ergebnis ist leider nicht zufriedenstellend. Anstatt alle 5,5ms
einen Wert auszulesen, ergibt sich dieses komische Muster:
Paste2

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):
Paste3


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!
Zuletzt geändert von fabske am 17.07.2012 09:04:34, insgesamt 1-mal geändert.
Bevor Du einen Beitrag postest:
- Kennst Du unsere Verhaltensregeln?
- Hast Du die Suchfunktion benutzt? Deine Frage wurde vielleicht schon in einem anderen Beitrag beantwortet.
- Ist schon ein Artikel in unserem Wiki vorhanden, der Deine Frage beantwortet?

Cae
Beiträge: 6349
Registriert: 17.07.2011 23:36:39
Wohnort: 2130706433

Re: USB-Serial C++ Timing Probleme

Beitrag von Cae » 13.07.2012 17:16:31

Hey, deine Links sind kaputt, das hashtag ist nicht komplett. Aber auch sonst finde ich das interessant.

Gruß Cae
If universal surveillance were the answer, lots of us would have moved to the former East Germany. If surveillance cameras were the answer, camera-happy London, with something like 500,000 of them at a cost of $700 million, would be the safest city on the planet.

—Bruce Schneier

Benutzeravatar
schorsch_76
Beiträge: 2609
Registriert: 06.11.2007 16:00:42
Lizenz eigener Beiträge: MIT Lizenz

Re: USB-Serial C++ Timing Probleme

Beitrag von schorsch_76 » 13.07.2012 17:39:02

Das ist das selbe Phänomen wie es bei Socket Programmierung ist. Es kommen immer nur Rohdaten welche noch von dir interpretiert werden müssen. Das du einen Puffer von 39 Byte angibst, ist dem Kernel egal. Er sagt: "HEy hier hab ich wieder was für dich". Der Puffer dem du dem BEtriebssystem gibts, ist dafür da, falls dein Programm mal etwas schläft (aus was für Gründen auch immer) die Daten aufzunehmen, so dass du trotzdem noch alle Daten bekommen kannst und keine verloren gehen.

Persönlich mache ich immer eine deque<char> und packe alles was kommt ans hintere Ende. Wenn meine geforderten Bytes da sind, hole ich diese "vorne" ab.

Code: Alles auswählen

std::deque<char> buffer;

while (buffer,size() >= 39)
{
   char tmp[39];
   for (int i = 0; i < 39; ++i)
   {
      tmp[i] = buffer.front();
      buffer.pop_front();
   }
}
Das kann man auch mit Threads parallelisieren. einer schiebt in die queue rein, der andere liest aus und verarbeitet. Mutexe sind hier wichtig ;) Aber auch seqentiell kann das gemacht werden.

Damit kann der Kernel, das Netzwerk, was auch immer ein beliebiges Timingverhalten an den Tag legen und ich bekomme trotzdem immer meine geforderten Packete.

Gruß
schorsch

cosmac
Beiträge: 4576
Registriert: 28.03.2005 22:24:30

Re: USB-Serial C++ Timing Probleme

Beitrag von cosmac » 13.07.2012 18:30:02

hi,

schau dir mal termios an, besonders VMIN und VTIME. Solange wirklich alle Datensätze genau 39 Byte lang sind, könnte VMIN=39 funktionieren. Der Time-Out ist nur für grobe Notfälle gut, wenn länger als 100ms keine Daten mehr kommen.
Beware of programmers who carry screwdrivers.

Benutzeravatar
GoKi
Beiträge: 2068
Registriert: 04.07.2003 23:08:56
Lizenz eigener Beiträge: MIT Lizenz

Re: USB-Serial C++ Timing Probleme

Beitrag von GoKi » 13.07.2012 18:55:02

fabske hat geschrieben: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?
Weil du die Datei mit O_NONBLOCK und O_NDELAY öffnest?
read returned dann sofort mit den paar bytes die halt gerade verfügbar sind, evtl auch 0.
Schau Dir doch mal den Rückgabewert von read an.
MfG GoKi
:wq

Benutzeravatar
fabske
Beiträge: 2023
Registriert: 14.06.2003 15:07:51

Re: USB-Serial C++ Timing Probleme

Beitrag von fabske » 17.07.2012 09:12:59

Hallo und danke für die Rückmeldungen!!! :)

Sorry für die kaputten Links (Danke Cae), ich habe sie nun im ORIGINAL POST REPARIERT! Könnt sie anklicken! :)

Mein Code läuft bereits als Modul eines Frameworks in einem eigenen Thread. Er soll nichts anderes machen als alle 4ms die von der Platine gesendeten 39 Byte bereitsstellen.
Ich hab nun O_NDELAY und O_NONBLOCK rausgeworfen. Ich hatte es nur alles reingemacht um damit zu experimentieren. Es ergibt sich nun das Bild vom Anfang, das Lesen dauert einfach immer unterschiedlich lange: Paste4

Wie du cosmac nun in meinen funktionierenden Links sehen kannst, verwende ich bereits VMIN und VTIME. Allerdings ist VTIME uninteressant, weil man dort nur Zehntelsekunden angeben kann. Ich bräuchte aber 3-5ms! Auch 39 Byte habe ich bereits konfiguriert.
Genau schorsch_76 und cosmac, jemand sagte mir USB sei eben nicht echtzeitfähig "Da sind zuviele Puffer und FIFOs und Treiber, Caches, Betriebsystemeigenarten usw. dazwischen. Du kannst das Verhalten jedoch optimieren". Ich soll diese Puffer des Betriebssystems umstellen. Kann man das unter Linux?
Bevor Du einen Beitrag postest:
- Kennst Du unsere Verhaltensregeln?
- Hast Du die Suchfunktion benutzt? Deine Frage wurde vielleicht schon in einem anderen Beitrag beantwortet.
- Ist schon ein Artikel in unserem Wiki vorhanden, der Deine Frage beantwortet?

cosmac
Beiträge: 4576
Registriert: 28.03.2005 22:24:30

Re: USB-Serial C++ Timing Probleme

Beitrag von cosmac » 17.07.2012 15:29:19

was den Puffer angeht, kann ich nur hoffen, dass der count von read() berücksichtigt wird. Aber es gibt einen Timer:
'modinfo ftdi_sio' hat geschrieben:(...)
vermagic: 3.1.0-ag1 SMP mod_unload ATOM
(...)
parm: ndi_latency_timer:NDI device latency timer override (int)
und
http://www.ftdichip.com/Support/Knowled ... atency.htm
http://www.ftdichip.com/Support/Knowled ... ataend.htm

über die Suchfunktion findest du dort evt. noch mehr zum Thema.
Beware of programmers who carry screwdrivers.

Antworten