
Von Piotr Rybicki
Bei Nomagic bringen wir Robotern bei, die reale Welt zu verstehen. Es ist kein Geheimnis, dass die reale Welt unglaublich komplex ist, und für manche Aufgaben wünscht man sich ein zusätzliches Paar Augen. Einige unserer Roboter empfanden das genauso, deshalb haben wir beschlossen, ihnen zu helfen.
In diesem Beitrag teilen wir unsere Erfahrungen beim Aufbau eines Systems, mit dem sich mithilfe des Robot Operating System (ROS1) schnell Farb- und Tiefenbilder von bis zu 16 Intel RealSense-Kameras bei minimaler CPU-Auslastung aufnehmen lassen. Der Quellcode ist enthalten!
Auf den ersten Blick mag es scheinen, als könne man einfach ein paar USB-3-Hubs kaufen, alle Kameras anschließen und fertig. Doch die Beschaffung einer ausreichenden Anzahl von USB-3-Anschlüssen ist nur die Spitze des Eisbergs.
Die eigentliche Herausforderung liegt in der begrenzten Bandbreite von USB 3. Intel hat einen hervorragenden Artikel veröffentlicht, der die verschiedenen Details zum Anschluss mehrerer Kameras erläutert. Die wichtigste Erkenntnis ist, dass man die Anzahl und Qualität der USB-3-Controller, die die Kameras verwalten, maximieren sollte. Da unsere PCs nur über einen einzigen USB-Controller verfügen, haben wir uns für den Kauf dieser PCIe-USB-Karte entschieden, die für jeden Port einen separaten USB-Controller besitzt. https://www.delock.com/produkte/2072_Type-A/89365/merkmale.html.

Um die gewünschte Anzahl an Anschlüssen (16) zu erreichen und sicherzustellen, dass jede Kamera ausreichend mit Strom versorgt wird, haben wir außerdem vier zusätzliche externe USB-Hubs mit eigener Stromversorgung angeschafft: https://www.delock.de/produkte/G_64053/merkmale.html.

Das Anschließen aller Kameras hat großen Spaß gemacht:

Vor vielen Robotern kann man sich verstecken, aber nicht vor diesem 🙂
In den meisten Fällen benötigt ein Roboter nur eine einzige Kamera, und selbst wenn mehrere verwendet werden, sind es typischerweise zwei bis vier. 16 Kameras an einen einzigen PC anzuschließen, klingt definitiv ambitioniert. Also dachten wir: Los geht's!
Wir haben die Kameras nacheinander angebracht und aktiviert und dabei das Tiefenvideo auf einem Bildschirm beobachtet. ros-realsense und RViz. Nach einiger Zeit bemerkten wir, dass die Bildrate (FPS) sank. Eine kurze Untersuchung ergab die Ursache:

Eines der Anzeichen dafür, dass die Kameras funktionieren 🙂
Der obige Screenshot dürfte Linux-Nutzern bekannt vorkommen – volle CPU-Auslastung, was unerwünscht ist, insbesondere wenn man noch andere Programme auf dem Rechner ausführen möchte. Auf unserem PC beanspruchte eine einzelne Kamera etwa 1,2 CPU-Kerne. Im nächsten Schritt galt es, die Ursache der hohen CPU-Last zu ermitteln.

Wir führten eine Profilanalyse durch und stellten fest, dass der größte Teil der CPU-Last durch die Nachbearbeitung verursacht wurde. ros-realsense. Jedes von der Kamera empfangene Bild wird gefiltert, um Rauschen zu entfernen und fehlende Daten mithilfe räumlicher und/oder zeitlicher Interpolation zu ergänzen. Die Filterung eines einzelnen Bildes dauert einige Millisekunden, sodass bereits etwa 10 Kameras ausreichen, um selbst eine Hochleistungs-CPU auszulasten. Während der Filterung in ros-realsense ist optional, verbessert aber die Qualität der Tiefenbilder erheblich, deshalb wollten wir es beibehalten.
Wir stellten fest, dass wir gar nicht alle Frames filtern mussten, da wir letztendlich nur alle paar Sekunden einen Frame verwenden. Um dem entgegenzuwirken, haben wir den Code geforkt und modifiziert. ros-realsense Um diesen Anwendungsfall zu berücksichtigen, haben wir anstatt jedes einzelne Bild zu filtern, die aktuellsten Bilder in einem Ringpuffer gespeichert und die Filter nur auf Anfrage über einen ROS-Serviceaufruf angewendet. Das Speichern und Filtern mehrerer Bilder (anstatt nur eines) war notwendig, da einige Filterprozesse auf früheren Bildern basieren.
Diese Optimierung reduzierte die CPU-Auslastung deutlich auf etwa 201 TP3T pro Kamera. Der Kampf war jedoch noch nicht gewonnen. Niedrige Bildraten bestanden weiterhin, allerdings änderte sich das Muster: Anstatt alle Kameras zu betreffen, trat das Problem nun lokal begrenzter auf und führte dazu, dass einzelne Kameras ihre Leistung zeitweise reduzierten. Der (vorhersehbare) Übeltäter wurde identifiziert in ros-realsense Protokolle, die mit Meldungen wie diesen gefüllt waren:
13.05. 10:16:06,190 WARNUNG [140247325210368] (backend-v4l2.cpp:1057) Unvollständiger Frame empfangen: Unvollständiger Videoframe erkannt! Größe 541696 von 1843455 Bytes (29%)
Obwohl wir unter dem theoretischen USB-Durchsatz lagen, hatten die Kameras Schwierigkeiten, vollständige Bilder zu übertragen. Wir reduzierten die Bildrate auf 6 Bilder pro Sekunde und deaktivierten die Infrarotübertragung. Glücklicherweise reichte dies aus, um Stabilität zu erreichen.
Nachdem wir den Kampf gewonnen hatten, testeten wir unsere Lösung, um die erreichbaren Latenzzeiten zu ermitteln.

Farbbilder (blau) benötigen keine Verarbeitung und können daher schnell empfangen werden – üblicherweise in unter 10 Millisekunden. Die Anforderung eines Tiefenbildes (grün) löst eine Filterung aus, die je nach Thread-Planung etwa 150 ms dauert. Ausgerichtete Tiefenbilder (rot) erfordern etwas mehr Verarbeitungsaufwand, daher die geringfügig höhere Latenz.
Der Betrieb der Kameras mit niedriger Bildrate und längeren Verarbeitungszeiten führt dazu, dass die von unserem Service gelieferten Bilder leicht gealtert sind. Wenn Ihre Szene jedoch, wie unsere, größtenteils statisch ist, ist eine Verzögerung von 0,5 Sekunden akzeptabel.

Das obige Histogramm zeigt das Alter der empfangenen Frames, gemessen anhand von Zeitstempeln, die zu Beginn der Belichtung erstellt wurden (daher entspricht das Mindestalter dem Intervall zwischen den Frames – 166 Millisekunden).
Zusammenfassend lässt sich sagen, dass unsere Modifikation die CPU-Auslastung von Intel RealSense-Kameras deutlich reduziert, wenn nur gelegentlich ein einzelnes Bild abgerufen werden muss. Mit dieser Modifikation und zusätzlicher Hardware können über ein Dutzend Kameras angeschlossen und genutzt werden.
Der Quellcode für diese Modifikation ist hier zu finden: https://github.com/NoMagicAi/realsense-ros.