Den Stream einer Webcam via RasPi ins Internet stellen? Eine der leichtesten Übungen, könnte man meinen. Weit gefehlt, denn die Hürden sind tückisch.
Es ist kein großes Geheimnis, dass es rund um den Raspberry Pi immer wieder neue, tolle Projekte gibt und dafür andere in der Versenkung verschwinden. So verwundert es nicht, dass auch die Anleitungen im Internet oft veraltet sind. Für ein Azubi-Projekt sollte der Raspberry Pi einen Kamera-Stream an einen zentralen Server senden, von wo aus er sich über einen Webbrowser abrufen lässt.
Das klingt erst einmal recht simpel. Eine Suche im Netz förderte viele Treffer zu diesem Thema zutage. Ohne zu sehr ins Detail zu gehen, kann man sagen, dass sich kaum eine der Anleitungen zum Nachbau eignet. Die Ursache liegt häufig in nicht mehr vorhandenen Bibliotheken oder Programmen. Nicht selten wurden diese schon seit Jahren nicht mehr aktualisiert und funktionieren nicht mehr. Daher hat sich der Autor des Artikels des Themas angenommen und eine brauchbare Anleitung verfasst.
Das Setup
Die Basis für das Projekt bildet ein RasPi 4 unter der 64-Bit-Version des aktuellen Raspberry Pi OS. An den CAMERA-Port des RasPi schließen wir eine preiswerte RasPi-Kamera [1] an. Beim Verbinden des Flachbandkabels mit der Platine ist etwas Fingerspitzengefühl gefragt. Zuerst gilt es, den Kabelverbinder auf dem RasPi zu entriegeln, danach schieben Sie die Leitung ein und schließen die Verriegelung wieder.
Achten Sie bei der Montage darauf, dass sich die Kontakte der Leitung auf der richtigen Seite befinden. Die Verrieglung ist recht filigran, daher sollten Sie hier sehr vorsichtig zu Werke gehen. Ein Blick von oben in den Verbinder verschafft Klarheit, wie herum Sie die Leitung legen müssen. Die Kamera selbst ist über einen Steckverbinder mit der kleinen Platine verbunden (Abbildung 1). Nach der Montage des Moduls booten Sie den RasPi und starten einen ersten Hardwaretest.
Kameratest
Raspberry Pi OS bringt bereits die gesamte nötige Software zum Verwenden der Kamera mit, die Namen aller einschlägigen Programme beginnen mit rpicam-. Um ein Bild aufzunehmen, verwenden Sie das Kommando rpicam-jpeg -o test.jpg. Der Parameter -o gibt dabei an, in welcher Datei Sie das Bild speichern möchten. Das Programm Rpicam-jpeg verfügt über weitere, nützliche Parameter. Eine Übersicht dazu erhalten Sie mit rpicam-jpeg -h. Das Testbild betrachten Sie mit dem Kommando xdg-open test.jpg.
Zur Aufnahme von Videos verwenden Sie das Programm Rpicam-vid. Es hat eine Vielzahl von Einstellungsmöglichkeiten, die Sie sich am besten in der Online-Hilfe (-h) ansehen. In der Grundeinstellung speichert die Software die Videos im Format H.264. Um einen anderen Codec zu verwenden, nutzen Sie die Option --codec. Für einen ersten Test der Videoaufnahme tippen Sie rpicam-vid -t 10s -o test.h264. Damit speichert das Programm ein zehn Sekunden langes Video in der Datei test.h264. Das Abspielen des Clips starten Sie mit dem Aufruf ffplay test.h264. Da Ffplay eigentlich dazu dient, Streams abzuspielen, beendet es sich nicht automatisch; das erledigen Sie mit [Strg]+[C]. Eine vollständige Beschreibung aller Möglichkeiten der Kamera finden Sie in der offiziellen Dokumentation [2].
Mediaserver
Die von Rpicam-vid erzeugten Video-Streams lassen sich nicht direkt auf einer Webseite verwenden und sind zudem sehr unflexibel – oft kommt es zu Timing-Problemen. Für Abhilfe sorgt eine zusätzliche Komponente, die wir zwischen den Stream-Erzeuger und den Konsumenten schalten. Dafür gibt es eine Vielzahl von möglichen Lösungen.
Wir entscheiden uns für den Server MediaMTX [3], der sich auch als Docker-Container verwenden lässt. Er funktioniert ohne viel Bastelei und läuft vollständig unabhängig von anderen Komponenten. Die Installation auf dem Raspberry Pi gestaltet sich denkbar einfach: Laden Sie das Paket in ein beliebiges Verzeichnis herunter, entpacken Sie es und starten Sie die enthaltene Software mit dem Kommando ./mediamtx (Listing 1). Verwenden Sie immer die aktuellste Version von der Webseite des Projekts [4].
Listing 1
MediaMTX starten
$ mkdir mediaMTX $ cd mediaMTX $ wget https://github.com/bluenviron/mediamtx/releases/download/v1.12.0/mediamtx_v1.12.0_linux_arm64v8.tar.gz $ tar -xvzf mediamtx_v1.12.0_linux_arm64v8.tar.gz $ ./mediamtx
Die Funktionsweise des Mediaservers ist schnell erklärt. Ein Stream-Lieferant publiziert unter einer bestimmten URL auf dem Server einen Stream, der sich von beliebigen Clients unter dieser Adresse abrufen lässt. Zur Datenübertragung dient das Real Time Streaming Protocol RTSP. MediaMTX unterstützt aber auch andere Protokolle.
Projekt
Wie eingangs erwähnt, möchten wir einen Video-Stream auf einer Webseite darstellen. Dazu installieren wir zunächst einen Webserver auf dem Raspberry Pi. Für einen ersten Test eignet sich Apache, den Sie mit dem Kommando sudo apt install apache2 auf dem System einrichten. Um ihn zu testen, geben Sie im Webbrowser die IP-Adresse des RasPi ein. Hat alles geklappt, erscheint die Startseite des Webservers (Abbildung 2).

Abbildung 2: Nach erfolgter Installation und dem Start von Apache sehen Sie im Browser die Startseite des Webservers.
Falls nicht, starten Sie Apache mit dem Befehl sudo /etc/init.d/apache2 restart neu. Jetzt können Sie damit beginnen, den von der Kamera erzeugten Stream via Rpicam-vid zum Mediaserver zu senden. Das erfordert jedoch ein Umformatieren der Daten. Das umfangreiche Kommando dazu zeigt Listing 2. Den Stream aus der Kamera passen Sie mithilfe von Rpicam-vid so an, wie es für die aktuellen Umgebungsgegebenheiten passt. Die meisten Parameter erklären sich selbst, Sie können sie entsprechend Ihrem Projekt anpassen.
Der Stream wandert als Nächstes via Pipe in das Tool Ffmpeg weiter. In diesem Fall kümmert es sich darum, den Stream in RTSP umzuwandeln und an den Mediaserver zu senden. Falls Sie den Server nicht zusammen mit der Kamera auf demselben System betreiben, geben Sie hier die URL des Mediaservers an.
Um zu überprüfen, ob Sie den Stream vom Mediaserver abrufen können, verwenden Sie das Ffplay-Kommando aus den letzten beiden Zeilen von Listing 2. Hier müssen Sie gegebenenfalls die URL an Ihre Gegebenheiten anpassen.
Listing 2
Kamera-Stream an den Mediaserver senden
$ rpicam-vid \ --inline 1 --brightness 0.2 --contrast 1.1 \ --sharpness 1.0 --level 4.1 --framerate 60 \ --width 640 --height 360 -t 0 -n \ --codec libav --libav-format mpegts \ --libav-video-codec h264_v4l2m2m -o - | \ ffmpeg -fflags +nobuffer+igndts+discardcorrupt \ -flags low_delay -hwaccel drm \ -hwaccel_output_format drm_prime -hide_banner \ -r 60 -i - -c:v h264_v4l2m2m -b:v 2000k -r 30 \ -threads 0 -f rtsp -rtsp_transport udp \ rtsp://localhost:8554/stream/1 &> /dev/null $ ffplay rtsp://localhost:8554/stream/1 \ -fflags nobuffer -flags low_delay -framedrop
Ziel dieses Projekts ist es aber, den Stream an eine Webseite zu senden. Hier gilt es, einige Dinge zu beachten, damit die Datenübertragung wie gewünscht klappt. Zuerst einmal sollten Web- und Mediaserver auf demselben Rechner laufen. Wenn Sie den Stream auf einer Webseite verwenden möchten, eignet sich RTSP nicht als Protokoll; verwenden Sie stattdessen WebRTC über HTTP.
Um keinen zusätzlichen Javascript-Player einbauen zu müssen, arbeiten Sie mit einem IFrame, in den Sie den Stream einbinden (Listing 3). Auf diese Weise lassen sich bei Bedarf mehrere Streams auf einer HTML-Seite unterbringen. Für einen ersten Test legen Sie mit Root-Rechten im Verzeichnis /var/www/html/ die Datei stream.html mit dem IFrame an und rufen sie dann im Webbrowser auf.
Listing 3
stream.html
<iframe src="http://RasPi-IP/URL:8889/stream/1" width="800px" height="600px"/>
Wenn Sie für Ihre Zwecke eine fest montierte Kamera benötigen, ist das Projekt an dieser Stelle für Sie abgeschlossen. Das Steuern der Kamera über den Browser erfordert jedoch einige zusätzliche Schritte.
Bewegung!
Um die Kamera zu bewegen, verwenden wir einige 3D-gedruckte Teile und zwei handelsübliche Servomotoren [5]. Die für den Druck benötigten STL-Dateien finden Sie auf Thingiverse [6]. Als Gehäuse für den Raspberry Pi eignet sich die U-Maker Box von Weidmüller [7] besonders gut, da sie sich flexibel anpassen lässt.
Zum Ansteuern der Servos dient die Bibliothek Pigpio [8], die bereits Bestandteil der Distribution ist. Sie umfasst einen Daemon und unterschiedliche Clients. Es genügt, den Daemon zu starten. Die Tabelle “Kommandos für den Pigpio-Daemon” zeigt alle Befehle, die Sie dafür benötigen. Da es hier um dynamischen Content geht, ist das Web-Framework Flask [9] das Mittel der Wahl. Für das Projekt erstellen Sie ein eigenes, virtuelles Python-Environment. In Listing 4 finden Sie alle notwendigen Kommandos, um die entsprechende Software zu installieren.
|
Kommando |
Beschreibung |
|---|---|
|
|
Autostart aktivieren |
|
|
Autostart deaktivieren |
|
|
Start |
|
|
Stopp |
|
|
Statusanzeige |
Listing 4
Virtuelles Environment vorbereiten
$ python -m venv httpserver $ cd httpserver/ $ source ./bin/activate $ pip install Flask $ pip install pigpio $ sudo systemctl start pigpiod
Die zwei Servomotoren schließen Sie mit ihrer Betriebsspannung an die GPIO-Pins 5V und GND an, die Signaleingänge der Motoren gehören an GPIO17 und GPIO18 (Abbildung 3). Die Wago-Klemmen passen exakt in die Aussparungen im Gehäuse, die orangefarbenen Halterungen gewährleisten eine saubere Leitungsführung. Sorgen Sie beim Einbau der Servos dafür, dass sie sich in Mittelstellung befinden.
Wie erwähnt, besteht die Bibliothek Pigpio aus einem Daemon und einem Client, die über den Port 8888 miteinander kommunizieren. Den belegt allerdings bereits MediaMTX für das HLS-Protokoll. Um diesen Konflikt aufzulösen, editieren Sie die Datei mediamtx.yml im Stammverzeichnis des Servers. Suchen Sie darin nach dem Eintrag hls: und setzen Sie ihn auf no. Der Server verwendet diesen Port nach einem Neustart nicht mehr. Gegebenenfalls müssen Sie zusätzlich den Pigpio-Daemon via sudo systemctl start pigpiodneu starten.
Nach dem Einrichten der virtuellen Umgebung geht es ans Programmieren des Servers. Flask ist ein sehr mächtiges Framework, das Ihnen dabei eine Menge Arbeit abnimmt. Es genügt, die Pfade für die Endpunkte zu definieren und den dazugehörigen Code zu schreiben. Listing 5 zeigt, wie Sie einen Servomotor ansteuern. Um die Bewegung auszulösen, versendet das Skript einfache Ajax-Requests. Das Programm dient lediglich als Einstieg in eine eigene Implementierung.
Hier gibt es definitiv noch viel Verbesserungspotenzial. Das Ansteuern des zweiten Servos ist noch nicht implementiert, eine Fehlerbehandlung fehlt komplett, und das Layout der HTML-Seite fällt rudimentär aus. Es bleiben viele kleine Funktionen, die Sie selbst schrittweise implementieren und verbessern können. Um den Server zu starten, müssen Sie sich im virtuellen Environment befinden und das Kommando python server.py auf der Konsole absetzen.
Listing 5
server.py
from flask import Flask
import pigpio
import time
pwm = pigpio.pi()
pwm.set_mode(17, pigpio.OUTPUT)
pwm.set_PWM_frequency(17, 50)
pos=1500
app = Flask(__name__)
@app.route('/')
def hello_world():
page = '<HTML><BODY>'
page = page + '<iframe src="http://<RASPI-IP/URL>:8889/stream/1" width="800px" height="600px"></iframe><BR>'
page = page + '<TABLE width="800px"><TR><TD><BUTTON type="button" onclick="servo(1)">Links</TD>'
page = page + ' <TD><BUTTON type="button" onclick="servo(2)">Rechts</TD></TABLE>'
page = page + '<SCRIPT>'
page = page + 'function servo(url) { console.log(url);'
page = page + 'const xhttp = new XMLHttpRequest();xhttp.open("GET", url, true);xhttp.send();'
page = page + '}</SCRIPT>'
page = page + '</BODY></HTML>'
return page
@app.route('/1')
def l():
global pos
pos=pos+50
pwm.set_servo_pulsewidth(17, pos)
return ''
@app.route('/2')
def r():
global pos
pos=pos-50
pwm.set_servo_pulsewidth(17, pos)
return ''
if __name__ == '__main__':
app.run(debug=True,host="0.0.0.0")
Es brummt
Servomotoren fahren abhängig von der Signallänge eine bestimmte Position an. Im Inneren stecken ein Poti für die Positionsermittlung sowie eine Regelelektronik, die den Motor steuert.
Bei den meisten Servos kommt hier traditionelle Analogtechnik zum Einsatz. Gelegentlich ist die Regelung oder Mechanik nicht in der Lage, die Position zu erreichen, die der Signallänge entspricht. In einem solchen Fall fängt die Regelung an zu schwingen. Dadurch wechselt der Motor ständig die Richtung und fängt an zu brummen. Um das zu verhindern, ermitteln Sie empirisch, bei welchen Signallängen der Motor (noch) nicht brummt.
Mitunter rufen aber auch mechanische Widerstände das Brummen hervor. Alles in allem ist das keine schlimme Sache, allerdings reagiert die Kamera mit massiver Fehlfokussierung darauf.
Fazit
Mit einer aktuellen Anleitung und ein wenig Aufwand ist es gar nicht so schwer, den Kamera-Stream des Raspberry Pi auf einer Webseite darzustellen (Abbildung 4).
Eine wichtige Komponente in einem solchen Setup stellt allerdings ein gut funktionierender Mediaserver dar. Wir haben uns für MediaMTX entschieden, weil der Server sehr viele Möglichkeiten bietet und ohne zusätzliche Software funktioniert. Zugegebenermaßen haben wir nur einen Bruchteil der von MediaMTX gebotenen Funktionen verwendet. Wenn Sie tiefer in das Thema einsteigen möchten, lesen Sie sich die Anleitung bei Github genau durch. (tle)
Der Autor
Martin Mohr erlebte die komplette Entwicklung der modernen Computertechnik live mit. Nach dem Studium entwickelte er überwiegend Java-Applikationen. Mit dem Raspberry Pi erwachte seine alte Liebe zur Elektronik wieder.
Glossar
-
RTSP
-
Das Real Time Streaming Protocol (RTSP) wurde zum Übertragen von kontinuierlichen Datenströmen entwickelt. Dabei kann es sich um Audio- oder Videodaten, Messwerte von Sensoren oder ähnliche Daten handeln.
Infos
-
Raspberry Cam: https://www.amazon.de/dp/B076F83JW5
-
Dokumentation Raspberry Pi Kamera:https://www.raspberrypi.com/documentation/computers/camera_software.html
-
MediaMTX: https://github.com/bluenviron/mediamtx
-
MediaMTX herunterladen: https://github.com/bluenviron/mediamtx/releases/latest
-
Servomotoren kaufen: https://www.amazon.de/AZDelivery-Roboter-Hubchrauber-Flugzeug/dp/B07CYZSVKW/
-
STL-Dateien: https://www.thingiverse.com/thing:7051628
-
U-Maker Box: https://www.weidmueller.de/de/produkte/elektronik/elektronikgehaeuse/raspberry_pi_gehaeuse.jsp
-
Bibliothek Pigpio: https://abyz.me.uk/rpi/pigpio/
-
Flask Python Server: https://flask.palletsprojects.com/en/stable/








