{"id":2145,"date":"2026-03-14T08:53:48","date_gmt":"2026-03-14T07:53:48","guid":{"rendered":"https:\/\/g7itchme.wordpress.com\/?p=2145"},"modified":"2026-03-14T08:53:48","modified_gmt":"2026-03-14T07:53:48","slug":"reihe-embedded-world-die-unsichtbaren-gehirne-verstehen-teil-9","status":"publish","type":"post","link":"https:\/\/technodidact.de\/en\/reihe-embedded-world-die-unsichtbaren-gehirne-verstehen-teil-9\/","title":{"rendered":"Reihe: Embedded World \u2013 Die unsichtbaren Gehirne verstehen (Teil 9)"},"content":{"rendered":"<h3 class=\"wp-block-heading\">Wenn es komplex wird \u2013 Echtzeitbetriebssysteme (RTOS) f\u00fcr Embedded Systems<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Von DerSchneider<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Einleitung: Der Dirigent im Chaos<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Im letzten Artikel haben wir die Welt der Bare-Metal-Programmierung erkundet \u2013 die Kunst, mit einer einfachen Super-Loop und geschickt platzierten Interrupts auch komplexe Abl\u00e4ufe zu bew\u00e4ltigen. Doch diese Kunst hat ihre Grenzen. Sobald ein System mehr als ein halbes Dutzend Aufgaben koordinieren muss, sobald Priorit\u00e4ten eine Rolle spielen und Aufgaben miteinander kommunizieren m\u00fcssen, wird der Code schnell un\u00fcbersichtlich, fehleranf\u00e4llig und schwer wartbar.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Hier kommen Echtzeitbetriebssysteme ins Spiel \u2013 Real-Time Operating Systems, kurz RTOS. Sie sind die Dirigenten im Chaos der vielen Aufgaben. Sie \u00fcbernehmen das Scheduling, die Synchronisation und die Kommunikation und erlauben dem Entwickler, sich auf die eigentliche Anwendungslogik zu konzentrieren.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dieser Artikel f\u00fchrt in die Welt der RTOS ein. Wir lernen die grundlegenden Konzepte kennen, verstehen, wie sich ein RTOS von Desktop-Betriebssystemen unterscheidet, und sehen an Beispielen, wie Tasks, Queues und Semaphoren die Entwicklung komplexer Embedded Systems erleichtern.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Hauptteil<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>1. Was ist ein RTOS \u2013 und was nicht?<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ein Echtzeitbetriebssystem ist ein Betriebssystem, das f\u00fcr Anwendungen mit Zeitbedingungen entwickelt wurde. Es garantiert, dass bestimmte Aufgaben innerhalb vorgegebener Fristen ausgef\u00fchrt werden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Wichtig: Ein RTOS ist&nbsp;<strong>nicht<\/strong>&nbsp;einfach eine abgespeckte Version von Windows oder Linux. Die Unterschiede sind fundamental:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th class=\"has-text-align-left\" data-align=\"left\">Merkmal<\/th><th class=\"has-text-align-left\" data-align=\"left\">Desktop-OS (Windows, Linux)<\/th><th class=\"has-text-align-left\" data-align=\"left\">RTOS (FreeRTOS, Zephyr)<\/th><\/tr><\/thead><tbody><tr><td>Ziel<\/td><td>Durchschnittlicher Durchsatz<\/td><td>Garantierte Reaktionszeiten<\/td><\/tr><tr><td>Scheduling<\/td><td>Fairness, alle kommen dran<\/td><td>Priorit\u00e4ten, wichtige Tasks zuerst<\/td><\/tr><tr><td>Speicherschutz<\/td><td>Gesch\u00fctzte Adressr\u00e4ume<\/td><td>Meist ein gemeinsamer Adressraum<\/td><\/tr><tr><td>Vorhersagbarkeit<\/td><td>Nicht garantiert<\/td><td>Deterministisch<\/td><\/tr><tr><td>Gr\u00f6\u00dfe<\/td><td>Gigabyte<\/td><td>Kilobyte<\/td><\/tr><tr><td>Echtzeit<\/td><td>&#8222;Weich&#8220; (meist)<\/td><td>&#8222;Hart&#8220; (garantiert)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Ein RTOS ist kein Monolith, sondern eine Sammlung von Diensten, die der Entwickler nach Bedarf zuschalten kann. Es passt in wenige Kilobyte Speicher und l\u00e4uft auf Mikrocontrollern, die zu schwach f\u00fcr auch nur einen Linux-Thread w\u00e4ren.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>2. Die Grundbausteine: Tasks<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Das zentrale Konzept jedes RTOS ist der Task (auch Thread oder Prozess genannt). Ein Task ist eine eigenst\u00e4ndige Ausf\u00fchrungseinheit mit eigenem Stack und eigener Priorit\u00e4t.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Im Gegensatz zur Super-Loop, wo alles in einer einzigen Schleife l\u00e4uft, werden bei einem RTOS die verschiedenen Aufgaben auf mehrere Tasks verteilt:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">c<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><em>\/\/ Task f\u00fcr Tasterabfrage<\/em>\nvoid task_taster(void *params) {\n    while(1) {\n        int taster = gpio_lesen(TASTER_PIN);\n        if (taster) {\n            xQueueSend(tasterQueue, &amp;taster, 0);\n        }\n        vTaskDelay(pdMS_TO_TICKS(10)); <em>\/\/ 10 ms warten<\/em>\n    }\n}\n\n<em>\/\/ Task f\u00fcr Display-Aktualisierung<\/em>\nvoid task_display(void *params) {\n    while(1) {\n        display_aktualisieren();\n        vTaskDelay(pdMS_TO_TICKS(50)); <em>\/\/ 50 ms warten<\/em>\n    }\n}\n\n<em>\/\/ Task f\u00fcr Sensorauslesung<\/em>\nvoid task_sensor(void *params) {\n    while(1) {\n        int wert = sensor_lesen();\n        daten_speichern(wert);\n        vTaskDelay(pdMS_TO_TICKS(1000)); <em>\/\/ 1 Sekunde warten<\/em>\n    }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Jeder Task lebt sein eigenes Leben. Der Scheduler entscheidet, welcher Task wann l\u00e4uft \u2013 basierend auf Priorit\u00e4ten und Ereignissen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>3. Das Herzst\u00fcck: Der Scheduler<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Der Scheduler ist die wichtigste Komponente eines RTOS. Er entscheidet, welcher Task als n\u00e4chstes die CPU bekommt.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die g\u00e4ngigsten Scheduling-Verfahren:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Priorit\u00e4tsbasiertes Scheduling:<\/strong>&nbsp;Jeder Task hat eine Priorit\u00e4t. Immer der Task mit der h\u00f6chsten Priorit\u00e4t, der lauff\u00e4hig ist, bekommt die CPU. Das ist einfach und effizient, kann aber dazu f\u00fchren, dass niederpriore Tasks verhungern, wenn hochpriore immer etwas zu tun haben.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Round-Robin:<\/strong>&nbsp;Tasks gleicher Priorit\u00e4t teilen sich die CPU fair, indem sie abwechselnd f\u00fcr eine feste Zeitscheibe laufen. Verhindert das Verhungern, aber weniger deterministisch.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Rate-Monotonic-Scheduling:<\/strong>&nbsp;Eine mathematisch fundierte Methode, bei der Tasks mit k\u00fcrzeren Perioden h\u00f6here Priorit\u00e4ten bekommen. F\u00fcr bestimmte Aufgabenklassen l\u00e4sst sich damit mathematisch beweisen, dass alle Fristen eingehalten werden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die meisten RTOS verwenden eine Mischung: priorit\u00e4tsbasiertes Scheduling mit optionalem Round-Robin f\u00fcr gleiche Priorit\u00e4ten.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>4. Kommunikation: Queues und Mailboxen<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In einem Multitasking-System m\u00fcssen Tasks miteinander kommunizieren. Ein Task produziert Daten, ein anderer konsumiert sie. Daf\u00fcr gibt es Queues (Warteschlangen):<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">c<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><em>\/\/ Queue erstellen<\/em>\nQueueHandle_t sensorQueue = xQueueCreate(10, sizeof(int));\n\n<em>\/\/ Task 1: Sensor auslesen und Wert in Queue senden<\/em>\nvoid task_sensor(void *params) {\n    int wert;\n    while(1) {\n        wert = sensor_lesen();\n        xQueueSend(sensorQueue, &amp;wert, portMAX_DELAY);\n        vTaskDelay(100);\n    }\n}\n\n<em>\/\/ Task 2: Werte aus Queue empfangen und verarbeiten<\/em>\nvoid task_logger(void *params) {\n    int wert;\n    while(1) {\n        xQueueReceive(sensorQueue, &amp;wert, portMAX_DELAY);\n        sd_karte_schreiben(wert);\n    }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Die Queue entkoppelt die Tasks. Der Sensor-Task kann Werte produzieren, auch wenn der Logger-Task gerade besch\u00e4ftigt ist. Die Werte werden zwischengespeichert. Und wenn die Queue voll ist, kann der Sender warten oder einen Fehler melden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>5. Synchronisation: Semaphoren und Mutexe<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Wenn Tasks gemeinsame Ressourcen nutzen (z.B. eine serielle Schnittstelle oder einen Speicherbereich), m\u00fcssen sie sich synchronisieren, damit nicht beide gleichzeitig zugreifen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Bin\u00e4re Semaphore:<\/strong>&nbsp;Ein einfaches Flag, das anzeigt, ob ein Ereignis eingetreten ist. Ein Task wartet darauf, ein anderer signalisiert es.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">c<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><em>\/\/ Taster-ISR<\/em>\nvoid ISR_taster(void) {\n    xSemaphoreGiveFromISR(tasterSem, NULL); <em>\/\/ Semaphor geben<\/em>\n}\n\n<em>\/\/ Task wartet auf Taster<\/em>\nvoid task_taster_aktion(void *params) {\n    while(1) {\n        xSemaphoreTake(tasterSem, portMAX_DELAY); <em>\/\/ Warten<\/em>\n        aktion_ausfuehren(); <em>\/\/ Wird bei Tastendruck ausgef\u00fchrt<\/em>\n    }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Mutex (Mutual Exclusion):<\/strong>&nbsp;Ein spezieller Semaphor f\u00fcr den Zugriff auf gemeinsame Ressourcen. Er verhindert, dass zwei Tasks gleichzeitig auf dieselbe Ressource zugreifen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">c<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><em>\/\/ Gemeinsame Ressource: Serielle Schnittstelle<\/em>\nvoid task_send1(void *params) {\n    while(1) {\n        xSemaphoreTake(serialMutex, portMAX_DELAY);\n        printf(\"Task 1: Hallo Welt\\n\");\n        xSemaphoreGive(serialMutex);\n        vTaskDelay(100);\n    }\n}\n\nvoid task_send2(void *params) {\n    while(1) {\n        xSemaphoreTake(serialMutex, portMAX_DELAY);\n        printf(\"Task 2: Guten Tag\\n\");\n        xSemaphoreGive(serialMutex);\n        vTaskDelay(100);\n    }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Ohne Mutex w\u00fcrden sich die Ausgaben der beiden Tasks wild vermischen. Mit Mutex ist sichergestellt, dass jeder Task die Ausgabe ungest\u00f6rt zu Ende bringen kann.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>6. Zeitdienste: Timer und Delays<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">RTOS bieten auch komfortable Zeitdienste:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Task-Delay:<\/strong>&nbsp;<code>vTaskDelay(100)<\/code>&nbsp;l\u00e4sst den Task f\u00fcr 100 Ticks schlafen. Der Scheduler l\u00e4uft inzwischen andere Tasks.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Software-Timer:<\/strong>&nbsp;Timer, die nach Ablauf eine Funktion aufrufen oder einen Task benachrichtigen. N\u00fctzlich f\u00fcr periodische Aktionen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Timestamp-Dienste:<\/strong>&nbsp;Funktionen, um die vergangene Zeit hochpr\u00e4zise zu messen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>7. Ein RTOS im Vergleich: FreeRTOS<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Das mit Abstand am weitesten verbreitete RTOS ist FreeRTOS. Es ist Open Source, extrem portabel, l\u00e4uft auf Dutzenden von Plattformen und ist klein genug f\u00fcr winzige Mikrocontroller.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">FreeRTOS bietet:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Priorit\u00e4tsbasiertes Scheduling<\/li>\n\n\n\n<li>Tasks, Queues, Semaphoren, Mutexe<\/li>\n\n\n\n<li>Software-Timer<\/li>\n\n\n\n<li>Speicherverwaltung (mehrere Optionen)<\/li>\n\n\n\n<li>Hunderte von Portierungen<\/li>\n\n\n\n<li>Eine riesige Community<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Ein komplettes FreeRTOS-System passt oft in 5-10 KB Flash und 1 KB RAM \u2013 Platz genug f\u00fcr erstaunlich komplexe Anwendungen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>8. Die Kosten eines RTOS<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ein RTOS ist kein Geschenk. Es hat seinen Preis \u2013 nicht in Geld, aber in anderen Ressourcen:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Speicher:<\/strong>&nbsp;Jeder Task braucht eigenen Stack. Bei vielen Tasks kann das den RAM schnell f\u00fcllen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>CPU-Zeit:<\/strong>&nbsp;Der Scheduler verbraucht Rechenzeit. Bei jedem Taskwechsel, bei jedem Interrupt l\u00e4uft RTOS-Code.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Komplexit\u00e4t:<\/strong>&nbsp;Ein RTOS-System ist schwerer zu debuggen als eine Super-Loop. Task-Wechsel, Priorit\u00e4ten und Synchronisation k\u00f6nnen zu schwer reproduzierbaren Fehlern f\u00fchren.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Determinismus:<\/strong>&nbsp;Obwohl RTOS f\u00fcr Echtzeit gemacht sind, k\u00f6nnen sie durch Priorit\u00e4tsinversion und andere Effekte unvorhersehbares Verhalten zeigen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>9. Priorit\u00e4tsinversion \u2013 Die RTOS-Falle<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ein klassisches Problem in RTOS ist die Priorit\u00e4tsinversion. Stellen Sie sich vor:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Task H (hohe Priorit\u00e4t) braucht eine Ressource.<\/li>\n\n\n\n<li>Task L (niedrige Priorit\u00e4t) h\u00e4lt die Ressource, kann aber nicht laufen, weil Task M (mittlere Priorit\u00e4t) gerade rechnet.<\/li>\n\n\n\n<li>Task H wartet auf L, L wartet auf M, M rechnet fr\u00f6hlich vor sich hin.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Der hochpriore Task H muss warten, bis der mittelpriore Task M fertig ist \u2013 eine Umkehrung der Priorit\u00e4ten.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">L\u00f6sung: Priority Inheritance. Wenn ein niederpriorer Task eine Ressource h\u00e4lt, die ein hochpriorer braucht, bekommt der niederpriore kurzzeitig die Priorit\u00e4t des hochprioren. So kann er schnell fertig werden und die Ressource freigeben.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>10. Wann RTOS, wann Bare-Metal?<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die Entscheidung ist nicht immer einfach. Hier eine Faustregel:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Bare-Metal<\/strong>&nbsp;ist besser, wenn:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Das System sehr klein ist (wenige Aufgaben, wenig RAM)<\/li>\n\n\n\n<li>Die Anforderungen extrem deterministisch sind<\/li>\n\n\n\n<li>Sie maximale Kontrolle brauchen<\/li>\n\n\n\n<li>Der Stromverbrauch minimiert werden muss (Schlafmodi)<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>RTOS<\/strong>&nbsp;ist besser, wenn:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Mehr als 5-10 Aufgaben koordiniert werden m\u00fcssen<\/li>\n\n\n\n<li>Aufgaben unterschiedliche Priorit\u00e4ten haben<\/li>\n\n\n\n<li>Komplexe Kommunikation zwischen Tasks n\u00f6tig ist<\/li>\n\n\n\n<li>Sie Code zwischen Plattformen portieren wollen<\/li>\n\n\n\n<li>Sie vorhandene RTOS-Komponenten nutzen k\u00f6nnen<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Viele Embedded-Entwickler haben beide Ans\u00e4tze im Werkzeugkasten und entscheiden von Projekt zu Projekt.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fazit und Ausblick<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Echtzeitbetriebssysteme sind m\u00e4chtige Werkzeuge f\u00fcr komplexe Embedded-Anwendungen. Sie entlasten den Entwickler von der Koordination der vielen Aufgaben und bieten bew\u00e4hrte Mechanismen f\u00fcr Kommunikation und Synchronisation. Tasks, Queues und Semaphoren sind die Grundbausteine, aus denen sich auch anspruchsvolle Systeme bauen lassen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Doch mit der Macht kommt die Verantwortung. Ein RTOS ist kein Allheilmittel. Es erfordert ein tiefes Verst\u00e4ndnis der Konzepte und der m\u00f6glichen Fallstricke. Priorit\u00e4tsinversion, Deadlocks und Race Conditions sind die Schreckgespenster, die im RTOS-Schrank lauern.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Aber selbst das beste Betriebssystem n\u00fctzt nichts, wenn das Programm Fehler enth\u00e4lt. Wie findet man Fehler in einem System, das keine Tastatur und keinen Bildschirm hat? Wie debuggt man Code, der in Echtzeit auf unsichtbare Hardware zugreift?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Mit dieser Kunst des Debuggens besch\u00e4ftigen wir uns im n\u00e4chsten Artikel.<\/p>","protected":false},"excerpt":{"rendered":"<p>Wenn es komplex wird \u2013 Echtzeitbetriebssysteme (RTOS) f\u00fcr Embedded Systems Von DerSchneider Einleitung: Der Dirigent im Chaos Im letzten Artikel haben wir die Welt der Bare-Metal-Programmierung erkundet \u2013 die Kunst, mit einer einfachen Super-Loop und geschickt platzierten Interrupts auch komplexe Abl\u00e4ufe zu bew\u00e4ltigen. Doch diese Kunst hat ihre Grenzen. Sobald ein System mehr als ein [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[46,26],"tags":[2069],"class_list":["post-2145","post","type-post","status-publish","format-standard","hentry","category-industrie-4-0","category-mit-den-handen","tag-embedded-world"],"_links":{"self":[{"href":"https:\/\/technodidact.de\/en\/wp-json\/wp\/v2\/posts\/2145","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/technodidact.de\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/technodidact.de\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/technodidact.de\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/technodidact.de\/en\/wp-json\/wp\/v2\/comments?post=2145"}],"version-history":[{"count":0,"href":"https:\/\/technodidact.de\/en\/wp-json\/wp\/v2\/posts\/2145\/revisions"}],"wp:attachment":[{"href":"https:\/\/technodidact.de\/en\/wp-json\/wp\/v2\/media?parent=2145"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/technodidact.de\/en\/wp-json\/wp\/v2\/categories?post=2145"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/technodidact.de\/en\/wp-json\/wp\/v2\/tags?post=2145"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}