RoboCar3 mit Coral

Nachdem RoboCar3 mit den Ultraschall-Sensoren einfach viel zu unverlässig lief (den verchromten Kühlschrank hat das Ding auch nach diversen Rammversuchen nicht erkannt und Stuhlbeine haben die Sensoren generell sehr gerne übersehen), habe ich es via Kamera versucht.

Die Kamera anzubauen ging sogar mit meinen arg eingeschränkten handwerklichen Fähigkeiten auffallend einfach und schnell. Der Anleitung bei github folgend, war auch die Software schnell installiert.

Eigentlich wollte ich mich jetzt an das Model machen und Tensorflow die Wohnung erklären. Im Gegensatz zum echten Leben (also richtigen Autos in freier Wildbahn) habe ich den Vorteil einer sehr übersichtlichen Umgebung mit vielen Konstanten – so oft räume ich nun nicht um. Dabei ergab sich schnell ein kleines Problem mit der doch recht eingeschränkten Rechenleistung des Raspberry: schon das kleine Beispiel-Model braucht ab 600ms aufwärts, um sich für ein Objekt zu entscheiden. Das erschien mir für die geplanten Fahrten zu wenig zu sein.

Als Abhilfe habe mich entschieden den TPU-Beschleuniger von Google zu testen. Es gibt da mittlerweile einige Alternativen, aber der USB-Stick erschien mir am einfachsten zu nutzen und ist auch relativ erschwinglich. Das Ergebnis:

Die Kamera habe ich vorne über den Ultraschall-Sensoren befestigt (der kleine rote Punkt im Bild), die TPU ist der große weiße Block, welcher per USB am Pi hängt. Nach links aus dem Bild läuft ein HDMI-Kabel zum Display. Diese Kabel war etwas tricky, da direkt vor dem HDMI-Port des PI der Servo für die Lenkung des Autos sitzt. Für einen normalen HDMI-Stecker zu wenig Platz. Unter dem Stichwort FPU findet man flexible HDMI-Kabel mit relativ kurzen Steckern zum selber montieren. Damit ging es problemlos.

Die Installation der Software war nicht ganz reibungslos, wenngleich eine an sich gute Anleitung geliefert wird. Es fehlten ein paar Details, was dann doch einige Zeit gekostet hat. Am Ende mussten nur einige Pakete nachinstalliert werden:

apt-get install libopenjp2-7-dev
 apt install libtiff5
 apt install libtiff5-dev
 apt-get install libatlas-base-dev

Und damit man auch als normaler User arbeiten kann:

usermod -aG plugdev mathias

Das Ergebnis ist schon beeindruckend:

13ms pro Bild – damit kann ich erstmal gut leben.

Jetzt geht es also wirklich an das Model, ich bin schon gespannt.

Ubuntu automatisiert installieren

Ein Ubuntu ist ja schnell installiert, ein paar Fragen beantworten, ein paar Mausklicks und fertig. Wer das einige Male am Tag machen darf, ist davon schnell genervt und wünscht sich eine Automatisierung.

Erste Wahl wäre hier wohl kickstart, es gibt dafür Dokumentation und ein grafisches Frontend. Leider kann kickstart nicht mit verschlüsselten Festplatten umgehen.

Bei debian gibt es preseed, sehr gut dokumentiert und sehr stabil. Leider lässt sich das bei Ubuntu, trotz der Debian-Wurzeln, nicht direkt anwenden. Für seine Desktop-Systeme hat sich Ubuntu etwas neues überlegt: ubiquity. Unglücklicherweise ist dieses wirklich sehr karg dokumentiert und man braucht schon einige Zeit des Probierens, um eine stabile Lösung zu finden.

Das generelle Vorgehen ist bei beiden (preseed und ubiquity) gleich: man lädt sich das iso runter und packt es aus, bindet sein Customizing ein und baut wieder ein iso.

iso auspacken

Das sind Linux basics:

  • iso runterladen
  • iso mounten: mount -o loop ubuntu-18.04.2-desktop-amd64.iso /mnt
  • Dateien kopieren: cp -rT /mnt preseed/
  • Schreibbar machen: chmod -R u+rw preseed

Letzteres dient der Bequemlichkeit, sonst nerven die Texteditoren beim Speichern.

preseed aktivieren

Unter preseed/isolinux findet sich nun eine Datei txt.cfg, diese definiert die verfügbaren Bootoptionen. Dort kommentieren wir alle Einträge bis auf live-install aus. Letzteren ergänzen wir zu:

label live-install
   menu label ^Install Ubuntu
   kernel /casper/vmlinuz
   append  file=/cdrom/auto.seed  auto=true priority=critical debian-installer/locale=de_DE keyboard-configuration/layoutcode=de ubiquity/reboot=true languagechooser/language-name=German countrychooser/shortlist=DE localechooser/supported-locales=de_DE.UTF-8 boot=casper automatic-ubiquity initrd=/casper/initrd quiet splash noprompt noshell ---

Der Eintrag auto.seed verweist auf eine gleichnamige Datei, in der wir später den Ablauf der Installation definieren werden. Der Eintrag auto=true weist auf die automatische Installation hin, der Rest, insbesondere die locale-Einstellungen, sind Geschmackssache.

Die auto.seed füllen wir später, erstmal erzeugen wir eine leere Datei: touch preseed/auto.seed.

iso bauen

Das ist wieder einfach:

mkisofs -D -r -V "UNATTENDED_UBUNTU" -cache-inodes -J -l -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -o /tmp/ubuntu16-desktop-unattended-install.iso preseed/

Im Ergebnis liegt in /tmp ein .iso welches man nun testen kann. Am einfachsten in einer virtuellen Maschine, einfach das iso als cdrom einbinden und starten.

Customizing

Der eigentlich spannende Teil ist ja das Steuern der Installation. Meine auto.seed enthält da einige Sektion, die wir uns der Reihe nach anschauen.

Zuerst die Partition der Platten:

ubiquity partman-auto/disk string /dev/sda
ubiquity partman-auto/method string regular
ubiquity partman-lvm/device_remove_lvm boolean true
ubiquity partman-md/device_remove_md boolean true
ubiquity partman-auto/choose_recipe select atomic

Damit weisen wir ubiquity an, auf /dev/sda zu installieren. Da ist noch keine Encryption dabei, dafür müssen wir auf die alte Debian-Methode zurückfallen:

d-i partman-crypto/passphrase password geheim
d-i partman-crypto/passphrase-again password geheim
d-i partman-lvm/device_remove_lvm boolean true
d-i partman-md/device_remove_md boolean true
d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
d-i partman-auto-lvm/guided_size string max
d-i partman-auto-lvm/new_vg_name string sup
d-i partman-auto/choose_recipe select atomic
d-i partman-partitioning/confirm_write_new_label boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true

Das Passwort für die Festplattenverschlüsselung wird hier im Klartext angegeben, man darf “geheim” gern durch etwas Eigenes ersetzen.

Die Zielgruppe für die Installation sind “normale” Anwender, also stellen wir alles auf deutsch:

d-i debian-installer/locale string de_DE.UTF-8
d-i debian-installer/keymap select de-latin1
d-i console-keymaps-at/keymap select de
d-i languagechooser/language-name-fb select German
d-i countrychooser/country-name select Germany
d-i console-setup/layoutcode string de_DE

Nun noch einige Einstellungen für die Uhrzeit:

d-i clock-setup/utc boolean true
d-i clock-setup/utc-auto boolean true
d-i time/zone string Europe/Berlin
d-i clock-setup/ntp boolean true

Nun noch einige Angaben zu den gewünschten Packageservern:

d-i mirror/country string DE
d-i apt-setup/multiverse boolean true
d-i apt-setup/restricted boolean true
d-i apt-setup/universe boolean true

Jetzt legen wir noch einen Admin-User an. In guter Ubuntu-Tradition gibt es keinen root-Login, sondern der erste User kann per sudo root-Rechte bekommen. Daher erstellen wir diesen User direkt bei der Installation, später kommen die normalen User dazu – dann ohne root-Rechte.

d-i passwd/user-fullname string Admin
d-i passwd/username string admin
d-i passwd/user-password-crypted password Grzbml4711
d-i passwd/user-default-groups string adm audio cdrom dip lpadmin sudo plugdev sambashare video
d-i passwd/root-login boolean false

Das Password für den Admin-User wird diesmal verschlüsselt übergeben. Man kann sich dieses sehr einfach mit Hilfe das Programmes mkpasswd erzeugen.

Jetzt wird es nochmal tricky: nach der Installation wollen wir dann doch noch ein paar Aktionen durchführen, dazu installieren wir einfach ein Skript, welches im Anschluss ausgeführt wird:

ubiquity ubiquity/success_command string \
  mkdir -p /target/root/bin; \
  cp /cdrom/custom.sh /target/root/bin; \
  chmod a+x /target/root/bin/custom.sh; \
  /target/root/bin/custom.sh stage0;

Das Skript custom.sh findet sich im root-Folder unseres iso, auf gleicher Ebene wie das auto.seed. Es wird im Anschluß an die Installation ausgeführt, aber noch vor dem ersten Booten des Systems. Zu diesem Zeitpunkt ist das Installations-ISO unter /cdrom gemountet, das neu installierte System unter /target. Das muss man beachten, ansonsten stehen uns an dieser Stelle alle üblichen Linux-Features zur Verfügung.

Ganz zuletzt installieren wir dann noch den Bootloader und starten das neue System:

d-i grub-installer/grub2_instead_of_grub_legacy boolean true
d-i grub-installer/only_debian boolean true
ubiquity ubiquity/reboot boolean true

Es ist also doch so einiges an Vorarbeit nötig. Am Ende hat man aber ein System, welches sich weitgehend von alleine installiert und konfiguriert. Wenn man mal einige Dutzend Rechner ausliefern muss, macht sich das doch schnell bezahlt.

Am Ende haben wir also in unserem in das Verzeichnis preseed ausgepackten iso folgende Dateien angepasst bzw. angelegt:

  • isolinux/txt.cfg: Kernel Parameter fürs Booten
  • auto.seed: Konfiguration der automatischen Installation
  • custom.sh: Skript zur Ausführung am Ende der Installation
Das Ganze funktioniert bei mir stabil. Dennoch erhebe ich keinen Anspruch auf Perfektion, die karge Dokumentation und das wilde Mischen von ubiquity (Ubuntu) und d-i (Debian) lassen sicher viel Raum für Verbesserungen.

Wetterstation III

Ein kleines Update: nachdem ich den ersten esp32 verbrannt habe (und das meine ich fast wörtlich: es gab ordentlich Funken), musste ich auf die Neulieferung warten. Die Zeit habe ich genutzt, um tatsächlich ein ordentliches Gehäuse zu bauen. Man muss dazu wissen, dass ich wirklich gerne bastele, allerdings nicht wirklich talentiert bin. Ich folge hier der Tradition von Tim Taylor (die älteren unter uns können mit den Namen vielleicht noch etwas anfangen). Am Ende ist es nicht so ganz exakt gerade geworden, aber doch ganz ordentlich:

Letzte Woche kam dann auch der neue esp32, auch den konnte ich in Betrieb nehmen (wohlgemerkt: man muss dabei löten – und es funktioniert trotzdem). Unglücklicherweise habe ich bei der Gelegenheit auch mal die libraries aktualisiert: Merlin war auch fleissig und es hat eine ganze Weile gedauert, die Konflikte aus dem merge aufzulösen. Leider hat der Code zwar an Umfang, aber nicht an Qualität zugelegt. Ich lästere an dieser Stelle mit viel Begeisterung, alldieweil ich vor geraumer Zeit mal als Programmierer in den embedded Bereich wechseln wollte. Leider hat sich da nichts ergeben, die meisten Absagen kamen mit der Begründung, ich hätte ja keine Erfahrung auf diesem Gebiet. Nun verstehe ich, warum die Leute keine echten Softwareentwickler haben wollen 😉 Nur um Beschwerden vorzubeugen: alle embedded developer die ich persönlich kenne, halte ich durchaus für kompetent.

Und es gibt auch schon ein neues Projekt: unerwarteterweise hat meine Frau Gefallen gefunden an dem Gerät und wünscht sich mehrere davon, nach Möglichkeit auch mit mehr bunt…