8 Years of Voice Journey

So this is a short article about my journey with voice control over the past 8 years. It’s just a summary of how voice improved over the last few years in general. Maybe some people might find it an interesting read.

I started relatively early with voice around 2017. My goal was to turn off light switches via voice, since my bed was far away from the light switch. I am often driven by laziness. Sometimes you have to get up from the couch to stay on the couch…

CMU Sphinx

The first setup was CMU sphinx on a pi with a cheap Logitech webcam as a mic combined with some cpp magic to send 433Mhz signals. There were wall switches with 433Mhz signals that you could control from these cheap remotes.

It did not work well and I had to scream a bit but sometimes it was switching the lights.

SNIPS.ai

A bit later, around 2018, Snips.ai came along and worked surprisingly well – the mqtt hermes protocol was easy enough to hook in a bunch of intents that I wrote in python to tell jokes and switch my 433 Mhz controller for the lights.

“Hey Snips, tell a joke…”. The joke was that Snips was bought by Sonos and I experienced the cloud lock-in for the first time. While you could run Snips fully offline, the training had to run in their cloud. Sonos did not take long to take down the Snips Cloud Training – so my setup became unchangeable and I could not add new intents. I kept it alive and hoped to find a replacement.

In 2019 I found a project called Rhasspy 2.4 that essentially was a drop-in replacement for Snips as it followed its Hermes mqtt protocol. It’s also the first time I learned about @synesthesiam . He is the mastermind behind Rhasspy.
I think it took not long until I got it running and all my intents and light control was working again. I could finally add new intents again as well. So far I still implemented everything that was controllable via direct listening on mqtt for parsed intents. On the hardware side, I was still limited to switching lights and outlets via 433Mhz from the Pi.

Homeassistant and Node-RED

In 2020 I found the homeassistant project that allowed to build a kind of hardware abstraction layer. With all these integrations, I started buying more appliances, threw out the 433Mhz devices to replace it with Shellys and essentially got my hands on a lot of other fun things.
Homeassistant did not have voice support yet though. Rhasspy somehow was available as an addon but I was running homeassistant via docker, so that was painful to get working together while not running directly on Home Assistant OS (HAOS).

I managed to write a lot of glue code in Node-RED to bridge Rhasspy into Homeassistant. Node-RED was collecting all entities, filtered them and used Rhasspy’s api endpoints for training to make Rhasspy aware of them. I even built some magic to be area aware. If the satellite was in the “living room” and there was a “living room light” entity, it was enough to say “turn on the light” to only turn on the living room light. As Rhasspy also provided a lot of other api endpoints I also added Signal Messenger. I could write intents directly via chat or send a voice message that would be handled via Rhasspy for intent handling. My glue code Node-RED-Signal-Rhasspy-Homeassistant bridge would then handle it and call the right services in Homeassistant.

My Rhasspy Glue Code Magic:

Handling Messages from and to Signal Messenger:

Integration of Signal with Rhasspy/Hermes

Year of the Voice

In 2023 Homeassistant announced the year of the voice. That’s also when I learned that @synesthesiam — the same person behind Rhasspy, which I had been using for 4 years — was involved. I had an Atom echo to try – but this thing was just useless to get anything going properly. Also wyoming satellite together with whisper was very far from usable and my Rhasspy setup was still way better in understanding the commands and executing them. However, I read every blog post about new voice features and got my hands on an esp32 box 3 – which was really challenging back then. It was definitely better than the atom echo and integrated better than my messy wyoming satellite setup but still – not on par with my Rhasspy setup.

Speech-to-Phrase

Fast forward to early 2025. @synesthesiam released speech-to-phrase. It was a bit hard to set up as docs were a bit confusing for running it in docker but I managed. This finally had detection rates similar to my rhasspy setup. Then I also got my hands on a few Voice PE which had some issues in the beginning but now are working reliably. Over the past few months, I migrated most of my intents from Node-RED to Homeassistant directly.

Getting Signal Messenger running again

I still wanted to use Signal Messenger to send voice commands to open the door while waiting outside. As I wanted to get away from my Node Red glue code magic, I rewrote my Signal bot which now directly talks to the Homeassistant assist web api endpoints.

So now, a bit less than two years after the “Year of the Voice” announcement, it finally feels like the Year of the Voice for me…

I want to thank the whole Homeassistant team, especially @synesthesiam for working on this and bringing local control, so I never have to care about another cloud going down…

Next step is fully local LLMs that do what we want.

So the last thing to do for now…

pete@homeassistant:~/Programming/docker/rhasspy$ docker compose down
[+] Running 2/2
 ✔ Container rhasspy        Removed                                                                                                                                                                                                                                                                                                                                                                                                                                                    0.2s 
 ✔ Network rhasspy_default  Removed                                                                                                                                                                                                                                                                                                                                                                                                                                                    0.2s 

Minisforum UM790 Pro 120mm Fan Case

Introduction

This is a fan case for Minisforum UM790 pro with ports for external antennas. As the internal fan for SSD and Memory seems to often fail and has a pretty bad temperature curve without a proper hysteresis I decided to replace it with a 120mm fan as it kinda fits with the size of the mini PC.

It consists of two parts. One to house the fan and another one to mount to the top and hold the two antennas.

The fan itself connects via a USB cable to one usb port on the back of the mini PC. You can use pretty much any 120mm fan that connects via usb. I additionally added a filter to not suck dust into the PC.

Continue reading “Minisforum UM790 Pro 120mm Fan Case”

SLAM Lecture – Simultaneous Localization and Mapping

I found a nice online video lecture for the simultaneous location and mapping problem. The lecture features small programming exercises in Python to directly apply the newly acquired knowledge. It starts easy with developing a motion model for a simple robot and extracting landmark information from LIDAR scanner data.

Youtube playlist | Author’s website

FAZ to Kindle in Python

Nachdem ich durch eine Werbeaktion an ein einjaehriges E-Paper Abo von der Frankfurter Allgmeinen Zeitung gekommen bin, wollte ich das ganze nun gemuetlich auf meinem Kindle geniessen. Allerdings ist das wohl gar nicht so einfach. Zwar gibt es ueber Amazon direkt ein FAZ Abo, dieses ist aber nicht kompatibel mit der E-Paper-Variante. Letztere besteht eigentlich nur aus der Printversion als PDF. Diese bekommt man aber nicht automatisch auf sein Geraet, sondern muss sich erst online einloggen, das ganze herunterladen und auf den Kindle kopieren.

faz2kindle

Viel bequemer waere es doch, die aktuellste Ausgabe immer direkt auf den Kindle geschickt zu bekommen. Morgens kurz das W-LAN anschalten und schon erscheint die aktuellste Ausgabe wie durch Zauberhand auf dem Geraet.

Im Prinzip muessen also drei Schritte automatisiert werden.

  1. Einloggen auf der FAZ-Aboseite
  2. Herunterladen der neusten Ausgabe(n)
  3. Senden an den Kindle

Da python fuer hack-n-slay bekannt ist und viele Bibliotheken fuer diese Art von Problemen bereits mitbringt, wird es im folgenden die Programmiersprache der Wahl. Continue reading “FAZ to Kindle in Python”

Programming a Robotic Car

Nachdem die Onlinevorlesungen von Stanford sehr gut von Menschen auf dem ganzen Globus angenommen wurden, haben sich die Professoren der Artificial Intelligence Class dazu entschieden eine Art Onlineuni zu eröffnen. Auf www.udacity.com werden ab sofort eine Einführung in die Informatik und eine Vorlesung über autonomes Fahren angeboten.

Während die Einführung in die Informatik (CS 101) noch relativ einfach beginnt, sollte man für den zweiten Kurs schon etwas Erfahrung mitbringen. Jede Woche gibt es einen neuen Block mit Vorlesungsvideos und kleinen Zwischenfragen, sowie eine Hausaufgabe. Im ersten Block geht es um Selbstlokalisierung eines mobilen Roboters mithilfe von Bayes. Sebastian Thrun erklärt dabei sehr bildhaft und gut verständlich an mehreren Beispielen die Theorie, die dann in der Hausaufgabe programmatisch ausprobiert werden darf. Die Abgabe erfolgt dabei in einem Online-Python-Interpreter.

Ich persönlich finde, dass diese Onlinevorlesungen, die auch durch ein Forum Kontakt zum Dozenten bereitstellen, eine sehr interessante Möglichkeit sind, sich vielleicht auch später im Beruf noch weiterzubilden.

Kinect im Robocup

Unser Kinectprojekt wurde nun in das Repository vom Autonomous Lab gemerged. Das lief trotz der Umstellung von Orocos 1.x auf 2.0 relativ problemlos.

Ziel des Projektes ist es einen konkurrenzfähigen Roboter für den Robocup@home zu bauen und mit Software für die einzelnen Aufgaben zu versorgen. Der Grundaufbau dieses  Robotors ist ein Otto Bock Xeno Rollstuhl, auf den die Kinect sowie ein Greifarm montiert werden soll. Die Kinect habe ich heute zusammen mit David montiert.

Kinectaufbau Front

Etwas problematisch war, dass wir keine Bohrungen oder sonstige Veränderungen am Rollstuhl selbst vornehmen konnten, da dieser vorerst nur eine Leigabe der Firma ist.

Kinectbefestigung am Sitz

Der Rollstuhl besitzt zusätzlich zur Kinect je einen Sick-Laserscanner vorn und hinten, die für Selbstlokalisierung und Kartographie benutzt werden können.

Gesamtaufbau

Die Aufgaben im Robocup@Home sind sehr vielseitig und reichen von einfacher Sprachausgabe über Wegfindung und Spracherkennung  bis zur komplexen Gestenerkennung. Zu Beginn muss sich der Roboter beim Technical Commitee vorstellen und seine Registrierungsunterlagen abgeben. Schwieriger wird es schon, wenn einer bestimmten Person durch einen Hindernisparkour gefolgt werden soll. Ein weiteres Beispiel ist das Finden eines bestimmten Objekts, sowie das Herbeibringen des selbigen. Im auf der Homepage downloadbaren Regelbuch sind alle weiteren Aufgaben mit Bepunktungskriterien wie Zeit oder Genauigkeit genau aufgelistet.

Vorerst ergibt sich jedoch als kurzfristiges Ziel die Steuerungsschnittstelle des Rollstuhls sauber ansprechen zu können.

Kinect-Projekt

Im Bachelor-Mastersystem ist es üblich jedes Modul mit einer Prüfungsleistung abzuschließen. Da Klausuren meist weder dem Studenten noch dem Dozenten viel bringen, hat Prof. Dr Rojas für das Computer Vision-Modul in diesem Semester Projekte vergeben. Da diese meinem Gruppenpartner Rene Meusel und mir nicht hundertprozentig zusagten und wir eigentlich gern mit einer Kinect (Eine Erweiterung von Microsoft zur Xbox, die unter anderem eine Kamera enthält, die Entfernungen messen kann) rumspielen wollten, haben wir einfach nachgefragt und vom Autonomous Lab eine Kinect, zusammen mit einer Aufgabe von Prof. Dr. Rojas bekommen. Das Framework, das unter anderem auch das autonome Auto der FU steuert, soll um eine Kinectschnittstelle erweitert werden. Dieses Framework soll dann einen wesentlich kleineren fahrenden Roboter steuern. Der Einfachheit halber soll vorerst nur in die Richtung gefahren werden, die am meisten freien Raum offeriert. Hindernisse sollen dabei umfahren und bei nicht umfahrbaren Hindernissen gebremst werden.

Zum Testen haben wir die Kinect einfach in der Höhe, in der sie später wahrscheinlich auch am Roboter montiert wird, an der Wand befestigt – zugegeben etwas russisch.

Xbox Kinect Testaufbau (russische Version)

Um ein Gefühl für das Framework und die Kinect zu bekommen, versuchen wir unsere Algorithmen vorerst sehr einfach zu halten. Wir lassen uns vom Kinectframework Punkte im 3-dimensionalen Raum generieren, die den Koordinaten in Millimetern ausgehend vom Punkt auf dem Boden direkt unter der Kamera entsprechen. Das bedeutet, dass ein Punkt P mit \((x=2000, y=0, z=1000)\) 2m vor der Kamera auf einer Höhe von 1m liegt. An dieser Stelle befindet sich also irgendein Gegenstand.

Die Grundidee besteht darin diese Punktwolke, die wir von der Kinect bekommen, in eine Obstacle Map (Hinderniskarte) umzuwandeln, also eine Karte in der 2-dimensional Bereiche beschrieben sind, in denen der Robotor sich ungehindert bewegen könnte und Bereiche, in denen sich Hindernisse befinden.

Kinect Obstacle Map

Soweit sind wir dann auch beim ersten Treffen schon gekommen. Der Boden wird durch simples Thresholding klassifiziert. Das bedeutet alle Punkte, die niedriger als 5cm in unserem Koordinatensystem sind, werden als Boden angenommen – zugegebenermaßen könnte das allerdings bei schrägen Ebenen problematisch werden. Wir legen danach ein Raster mit einer Auflösung von 10x10cm über den ganzen Boden und bilden in den Rastern Histogramme der Boden- und Nicht-bodenpunkte, d.h. wir speichern die Anzahl der Bodenpunkte und der Nichtbodenpunkte separat für dieses Rasterstück ab. So können wir für jedes Raster sagen, ob es befahrbar oder mit einem Hindernis besetzt ist, indem wir die Anzahl der entsprechenden Bodenpunkte und Nichtbodenpunkte betrachten. Grüne Bereiche im Bild geben hindernisfreie Raster an, in dunkelgrünen Bereichen würde der Roboter an sich auch in seiner Gänze hineinpassen. Rote Raster geben Hindernisse an, wohingegen in schwarzen Rastern keine Aussage möglich ist, da zu wenig oder keine Sensordaten vorliegen.

Soweit zum aktuellen Stand. Bisher läuft das System auf eher betagter Hardware unter Ubuntu 10.10 ohne die grafische Ausgabe mit etwa 80 Bildern pro Sekunde – also weit mehr als wahrscheinlich benötigt werden wird.

Unsere Idee ist nun für das weitere Vorgehen, dass wir aus der Obstacle Map einen Graphen generieren, der alle möglichen Wege vorwärts und nach links oder rechts beinhaltet. Lenkaktionen sollen dabei bestraft werden, da wir mit dem Roboter möglichst wenig lenken und dennoch in den größtmöglichen freien Raum navigieren wollen. Als Ziel gilt dann der am weitesten entfernte Punkt, der noch auf einem Weg erreichbar ist. Der Lenkwinkel, der dann pro Berechnungsschritt ausgegeben werden soll, ist derjenige, welcher zu Beginn auf dem Weg mit den geringsten Kosten liegt, also der, auf dem am wenigsten gelenkt wird um den Punkt zu erreichen. Das ist zumindest der Plan für die nächste Programmiersession, gefolgt von der eigentlichen Integration ins Autonomous Framework.

Kinect Infrarotprojektion

Ankunft in Moskau

Während bei uns langsam der Frühling einkehrt, liegt in Moskau noch recht viel Schnee herum.

Aeroflot hat entgegen vieler Vorurteile gegen russische Fluglinien doch eher geglänzt und ich konnte mich sogar recht weitläufiger Beinfreiheit erfreuen. Die Dame an der Information am Flughafen konnte mir sogar eine exakte Beschreibung des Weges zu meinem Hostel für die erste Nacht geben, da sie dort schon einmal gearbeitet hat. Aufgrund des Preises von 28Rubel (etwa 75C) habe ich mich für den Bus entschieden, selbiger erinnerte allerdings an die bereits alten Busse der 90er Jahre in den neuen Bundesländern.

Das Hostel an sich ist auch eines der besseren und wurde 2009 komplett renoviert. Das Personal ist sehr nett und hilfsbereit und der Preis von etwa 20€ für eine Nacht ist auch in Ordnung.

Den Rest des Tages habe ich damit verbracht die Stadt zu Fuß zu erkunden. Zum Abschluss folgen nun noch ein paar kleine Impressionen.

 

 

Russlandreise – Schritt 2 Planung und Unterkunft

Nachdem nun alle Reisemitglieder ihr fertiges Visum erhalten haben, wenden wir uns der Detailplanung der Reise zu. Bei der Beantragung des Visums über ein russisches Reisebüro kann ich nur jedem empfehlen das Kleingedruckte zu lesen – im Detail geht es z.B. darum ob die Einladung und die Konsulargebühren bereits im Preis enthalten sind oder nicht. Während bei russland-visum.eu  etwa 61€ inklusive Versand für alles anfallen, bezahlt man für die gleiche Leistung bei längerer Bearbeitungsdauer auf russland-visum.de etwa 120€ (36€ Einladung, 45€ Visumsantrag, 35€ Konsulargebühren und Versand).

Heute habe ich zudem die Nachricht erhalten, dass mein Flug von Berlin nach Moskau gestrichen wurde und ich auf einen früheren Flug am gleichen Tag umgebucht wurde. Das wäre prinzipiell nicht schlimm, wenn der Rest der Reisetruppe aus Stuttgart nicht erst 12h später eintreffen würde. Aber so bin ich dann wahrscheinlich wenigstens animiert dazu meine Restrussischkenntnisse wieder etwas zu vertiefen.

Die Planung an sich sieht bisher so aus, dass wir wohl fünf bis sechs Tage in Moskau verbringen und dann Richtung Ulianosk mit Flugzeug oder Zug aufbrechen werden. Eventuell schieben wir in Moskau noch einen Abstecher nach St. Petersburg ein.

Android und Ad-Hoc Netzwerke

Da ich auf meinem Android heute einige größere Apps aktualisieren wollte, aber keinen WLAN Router vor Ort habe, wollte ich mit meinem Laptop ein Ad-Hoc Netzwerk aufbauen um die Daten herunterzuladen. Wie es aussieht kann Android allerdings bisher nicht zu Ad-Hoc-WLANs verbinden. Dies ist meines Wissens ein Manko aller großen Smartphoneplattformen. Da Android entgegen der Konkurrenten jedoch OpenSource ist, hat sich jemand die Mühe gemacht das WLAN-Modul entsprechend zu patchen. Die Patchfiles gibt es hier: http://szym.net/2010/12/adhoc-wifi-in-android/

Wer allerdings gleich Updatedateien zum Einspielen über die Updatekonsole des Rom Managers haben möchte, ist hier besser aufgehoben. Zum Einspielen wird jedoch ein gerootetes Android benötigt. Je nach Version des WLAN-Modules (Shell: wpa_supplicant -v) muss ein anderes Update geladen werden – Informationen dazu finden sich jedoch auf der Downloadseite. Nach dem Herunterladen des richtigen Zips muss dieses auf die Speicherkarte kopiert und im Rom Manger als Update ausgewählt werden. Nach einem Neustart sollten Ad-Hoc Netze funktionieren. Die Verschlüsselung ist jedoch auf WEP beschränkt.Für ein kurzes Update der Apps sollte dies aber ausreichend sein.

Ich habe das ganze mit Windows 7 Ad-Hoc und Internet Sharing zusammen mit einem HTC Desire mit Leedroid 2.3d ROM erfolgreich getestet.