Erfahrungsbericht aus der studentischen Praxis Embedded Multithreading meistern

Von Yannik Süssmuth, KITcar Hardware Team 5 min Lesedauer

Anbieter zum Thema

Wie sich mit FreeRTOS, micro-ROS und Tracealyzer eine robuste, echtzeitfähige Firmware für autonome Modellfahrzeuge erfolgreich umsetzen lässt.

Miss Magic: Für das aktuelle vom KITCar-Team für die Cognitive Autonomous Driving Challenge entwickelte selbstfahrende Modellfahrzeug musste das zugrunde liegende Embedded-System komplett umgestellt werden. Zum Einsatz kamen die Open-Source-Systeme FreeRTOS und micro-ROS. Dabei musste das mit Multithreading unerfahrene Team umfassende Analysem am System durchführen.(Bild:  KIT)
Miss Magic: Für das aktuelle vom KITCar-Team für die Cognitive Autonomous Driving Challenge entwickelte selbstfahrende Modellfahrzeug musste das zugrunde liegende Embedded-System komplett umgestellt werden. Zum Einsatz kamen die Open-Source-Systeme FreeRTOS und micro-ROS. Dabei musste das mit Multithreading unerfahrene Team umfassende Analysem am System durchführen.
(Bild: KIT)

Moderne Mobilität erfordert schnelle Entscheidungen – sei es ein Kind, das auf die Straße läuft, ein plötzlich bremsendes Fahrzeug oder ein unerwartetes Hindernis, das aus dem Nichts auftaucht. Für autonome Fahrzeuge ist es genauso entscheidend wie für menschliche Fahrer, in solchen Momenten schnell und korrekt reagieren zu können. Umso wichtiger wird diese Herausforderung in Rennszenarien mit autonomen Modellfahrzeugen, deren Fähigkeiten die eines menschlichen Fahrers bei Weitem übertreffen. Schnelle und zuverlässige Entscheidungsfindung ist hier der Schlüssel – genau dieser Herausforderung stellen wir uns jeden Tag bei KITcar.

KITcar ist ein studentisches Team am Karlsruher Institut für Technologie (KIT). Seit über zehn Jahren entwickelt die Gruppe autonome Modellfahrzeuge im Maßstab 1:10. Mit ihnen tritt das Team bei Wettbewerben wie der Cognitive Autonomous Driving Challenge an – und arbeitet kontinuierlich daran, die Fahrzeuge in allen Bereichen weiterzuentwickeln: vom mechanischen Design bis hin zur Softwarearchitektur.

Das aktuellste Fahrzeug – Miss Magic – markiert einen neuen Höhepunkt in ihrer Entwicklung: Direktantrieb über Radnabenmotoren, moderne Sensorik und deutlich gesteigerte Rechenleistung bilden die Grundlage für komplexere und schnellere Entscheidungen.

Eine überfällige Erneuerung

Während sich viele Komponenten unserer Fahrzeuge über die Jahre weiterentwickelt haben, blieb das zugrunde liegende Embedded-System – das sogenannte „Bus-System“ zur Anbindung von Sensoren und Aktoren – lange Zeit nahezu unverändert. Die bisherige Architektur, basierend auf mehreren Mikrocontrollern, einem Superloop und einem proprietären seriellen Protokoll, war auf Dauer kaum noch wartbar. Mit dem Umstieg auf ROS 2 bot sich die ideale Gelegenheit, das Embedded-System grundlegend zu überdenken.

Neue Firmware-Architektur mit FreeRTOS und micro-ROS

Es sollte dabei eine moderne Firmware-Architektur auf Basis von FreeRTOS und micro-ROS geschaffen werden – einer leichtgewichtigen ROS-2-Implementierung für Embedded-Systeme. Damit lassen sich ROS-2-Nodes direkt auf einem Mikrocontroller ausführen, was sowohl die Systemkomplexität als auch die Hardwareanforderungen reduziert. Zudem ermöglicht der Einsatz dedizierter Threads für jede Node eine modulare Erweiterung des Systems und die gezielte Nutzung der Echtzeitfähigkeiten von FreeRTOS.

Aufbau des vom KITCar-Team entwickelten Bus Systems auf Basis eines STM32F439 von ST Microelectronics.(Bild:  KIT)
Aufbau des vom KITCar-Team entwickelten Bus Systems auf Basis eines STM32F439 von ST Microelectronics.
(Bild: KIT)

Geplant war ein System mit 6 bis 8 micro-ROS-Nodes und etwa 10 bis 15 parallelen Threads, jeweils mit eigenen Echtzeitanforderungen und Prioritäten. Ziel war es, rund 15 Sensoren und Aktoren mit idealerweise 120 Hz oder mehr anzusteuern. Auch wenn keine. Auch wenn keine rechenintensiven Algorithmen nötig waren, mussten kontinuierlich große Datenmengen verarbeitet und übertragen werden. Die Wahl fiel auf den STM32F439, einen Mikrocontroller, der bei sorgfältiger Optimierung all diese Anforderungen erfüllen konnte.

Multithreading: Theorie vs. Praxis

So vielversprechend das Konzept auf dem Papier auch war – in der Praxis stand das Team vor einem Problem: Niemand aus der Mannschaft hatte zuvor mit Echtzeitbetriebssystemen oder Multithreading auf Bare-Metal-Systemen gearbeitet.

Natürlich traten schon bald die ersten Probleme auf: Threads verhielten sich unerwartet, Logmeldungen verschwanden und Nodes hörten plötzlich auf, Daten zu publizieren. Ohne viel Vorerfahrung waren viele dieser Fehler schwer zu durchschauen.

Zwar war Debugging mit klassischen Mitteln wie GDB und printf grundsätzlich möglich, wurde bei einem Multithreading-System jedoch schnell frustrierend. Ein einziger blockierender Funktionsaufruf in einem scheinbar „unbeteiligten“ Thread konnte stundenlange Fehlersuche bedeuten.

Neben den reinen Debugging-Problemen stellten sich bald auch grundlegende Fragen:

  • Wie lässt sich sicherstellen, dass alle kritischen Komponenten zuverlässig laufen?
  • Wie kann man garantieren, dass alle Echtzeitanforderungen eingehalten werden?
  • Fällt es auf, wenn es zu Race Conditions oder Timing-Problemen kommt?
  • Reicht der Arbeitsspeicher für alle Anforderungen?

Beispielhaftes Trace Log aus dem Tracealyzer von Percepio.(Bild:  KIT / Percepio)
Beispielhaftes Trace Log aus dem Tracealyzer von Percepio.
(Bild: KIT / Percepio)

Auf der Suche nach geeigneten Debugging-Tools für Echtzeitsysteme stieß das Team von KITCar auf die Tracing-Funktionalitäten von FreeRTOS und auf Percepio Tracealyzer. Mit Features wie Echtzeit-Task-Visualisierung, detaillierten Speicherstatistiken und intuitiven Ablaufdiagrammen bot Tracealyzer genau das, was wir suchten. Nach kurzer Kontaktaufnahme stellte Percepio eine Team-Lizenz zur Verfügung, bereits 30 Minuten später liefen die ersten Trace-Aufzeichnungen

Die gewonnenen Einblicke waren sofort überzeugend: Im Streaming-Modus ließen sich wie erhooft die Thread-Ausführung in Echtzeit beobachten. Erstmals hatte das Team somit ein klares Bild davon, wie das System tatsächlich arbeitet. Ausführungszeiten pro Task, Reaktionszeiten auf externe Ereignisse, CPU-Auslastung im Zeitverlauf sowie Heap- und Stack-Nutzung pro Thread konnten eingesehen werden. So ließen sich beispielsweise Speicherlecks oder Stacküberläufe frühzeitig erkennen – lange bevor sie kritisch wurden.

Jetzt Newsletter abonnieren

Verpassen Sie nicht unsere besten Inhalte

Mit Klick auf „Newsletter abonnieren“ erkläre ich mich mit der Verarbeitung und Nutzung meiner Daten gemäß Einwilligungserklärung (bitte aufklappen für Details) einverstanden und akzeptiere die Nutzungsbedingungen. Weitere Informationen finde ich in unserer Datenschutzerklärung. Die Einwilligungserklärung bezieht sich u. a. auf die Zusendung von redaktionellen Newslettern per E-Mail und auf den Datenabgleich zu Marketingzwecken mit ausgewählten Werbepartnern (z. B. LinkedIn, Google, Meta).

Aufklappen für Details zu Ihrer Einwilligung

Nutzer-Events und Zustandsvisualisierung

Beobachtung von Timings und Zustandswechseln im Tracealyzer.(Bild:  KIT / Percepio)
Beobachtung von Timings und Zustandswechseln im Tracealyzer.
(Bild: KIT / Percepio)

Jede der micro-ROS-Nodes sowie jeder Hardwaretreiber in "Miss Magic" verwaltet eine eigene Zustandsmaschine. Mithilfe benutzerdefinierter Events ließen sich Zustandswechsel in Tracealyzer sichtbar machen und deren Timing präzise analysieren.

Tracealyzer wurde direkt in die Logging-Schnittstelle integriert, wodurch sich Nachrichten mit einer Genauigkeit von wenigen Mikrosekunden und minimalem Overhead aufzeichnen lassen. Im vorliegenden System dauert das Protokollieren einer formatierten Nachricht weniger als drei Mikrosekunden – und kann damit sogar in Interrupt-Routinen oder anderen kritischen Bereichen erfolgen, ohne die Performance spürbar zu beeinträchtigen

Ausprüren verborgener Bugs

Event Log im Tracealyzer.(Bild:  KIT / Percepio)
Event Log im Tracealyzer.
(Bild: KIT / Percepio)

Das Team schildert auch, wie Tracealyzer diente, einen verborgen gebliebenen Bug aufzuspüren: Einer der eigesetzten hochfrequenten IMU-Sensoren (Inertial Measurement Unit) hörte gelegentlich auf, Daten zu senden. Nach einigen Sekunden wechselte der Treiber in einen Fail-Safe-Modus und stellte den Betrieb ein. Das Problem trat nur sporadisch auf, war nicht reproduzierbar und ließ sich mit GDB oder klassischem Logging nicht eingrenzen.

Dank des minimalen Overheads lief Tracealyzer dauerhaft im Hintergrund mit und konnte das Verhalten schließlich lückenlos aufzeichnen. Die Ursache: Ein fehlerhafter Crimp-Anschluss an einem Time-of-Flight-Sensor führte dazu, dass dieser gelegentlich das I2C-Taktsignal verpasste. Der Sensor teilte sich den I2C-Bus mit der IMU, wobei der Zugriff durch einen Mutex geschützt war. Trat der Verbindungsfehler während einer Datenübertragung auf, konnte der Sensor den Bus vollständig blockieren – bis er sich nach einem Timeout automatisch zurücksetzte.

Zwar erkannte der Mikrocontroller das Problem und die HAL gab korrekt einen Fehlercode zurück – dieser wurde jedoch nicht richtig verarbeitet. Infolgedessen wurde der Mutex freigegeben, obwohl der Bus weiterhin blockiert war. Alle nachfolgenden I2C-Operationen schlugen daher fehl.

Dank Tracealyzer ließ sich genau feststellen, welcher Task den Mutex hielt und wie lange Übertragungen dauerten – und somit die eigentliche Fehlerquelle finden. Ohne diese Einblicke wäre der Bug vermutlich ungelöst geblieben.

Das an der Systementwicklung beteiligte KITCar-Team.(Bild:  KIT)
Das an der Systementwicklung beteiligte KITCar-Team.
(Bild: KIT)

Tracealyzer ist inzwischen ein fester Bestandteil des Toolsets im KITCar-Entwicklungsprozess. Das Tool hat das nötige Vertrauen gegeben, die Embedded-Multithreading-Architektur systematisch zu implementieren und seinen Mehrwert im Verlauf des gesamten Projekts immer wieder unter Beweis gestellt. Die aktuelle Firmware läuft stabil mit rund 15 separaten Threads, deren Interaktionen das Entwicklerteam weiterhin in Echtzeit beobachten und analysieren kann.  (sg)

(ID:50549084)