// PiFace CAD: Erste Versuche mit MPD

Wie bereits berichtet habe ich vor mit dem PiFace Control and Display (CAD) und MPD einen kleinen Musikplayer aus einem Raspberry Pi Model B zu basteln. Zum PiFace CAD existiert eine offizielle Python Library, die über die Raspbian Paketquellen nachinstalliert werden kann. Mit dieser kann man auf recht einfache Weise alle Funktionen der Erweiterungsplatine nutzen. Da sich meine Python Kenntnisse aber eher gering waren, habe ich mich in letzter Zeit ein bisschen in Python eingearbeitet. Sollte mein Programmierstil also noch etwas suboptimal sein, schrecke bitte nicht vor einem Kommentar zurück!

Vorbereitung

Zunächst habe ich das Board mit dem Raspberry Pi (Model B) in das passende Gehäuse eingebaut, welches es beispielsweise beim Distributor Farnell element14 gibt. Dies geht am besten, wenn zuerst der Pi und anschließend die Erweiterungsplatine in das Case gesteckt wird.

Auf das Model B+ passt das CAD zwar, allerdings liegt es aufgrund der neuen USB-Buchsen wie in den Bildern erkennbar etwas schief auf. Wenn die Kontaktstellen mit etwas Isolierband abgeklebt werden und sichergestellt wird, dass die GPIOs gut verbunden sind, dürfte dies aber kein Problem darstellen. Da ich aber ein „altes“ Model B verwende, bleiben mir diese Probleme erspart.

MPD installieren & konfigurieren

Auf die Installation und Konfiguration von MPD will ich hier nicht weiter eingehen, dazu gibt es zahlreiche Ressourcen. Statt dessen will ich kurz erläutern, welche Änderungen für den Pi notwendig sind und einen groben Einstiegspunkt liefern.
Nachdem die Pakete mpd und mpc installiert sind und die gröbsten Anpassungen in /etc/default/mpd und /etc/mpd.conf gemacht sind, kann mit raspi-config festgelegt werden welche Audioausgang verwendet werden soll. Diese Option findet sich unter Punkt 8 Advanced Options → Punkt A6 Audio. Ebenfalls unter Punkt 8 Advanced Options kann bei A5 SPI noch SPI, was später für das CAD benötigt wird, aktiviert werden.

Ich verwende für meinen Versuch die 3.5'er Klinke. Reicht die oft krtitisierte Qualität der Klinkenbuchse nicht aus kann ein HDMI Audio Extractor oder eine externe USB-Soundkarte verwendet werden. Im folgenden eine für den Pi gut funktioniernde MPD Audioconfig. Soll statt der internen Soundkarte eine externe USB-Soundkarte verwendet werden, muss noch Alsa konfiguriert werden.

audio_output {
        type            "alsa"
        name            "My ALSA Device"
        mixer_control   "Master"
        mixer_type      "software"
}

Nun kann die MPD Konfiguration überprüft werden, dazu aktualisiere ich zunächste mit mpc update die Datenbank, füge alle Titel der Wiedergabewarteschlange hinzu und starte die Wiedergabe. MPD sollte nun beginnen die Playlist, also alle verfügbaren Titel abzuspielen.

$ mpc update
# warten bis MPD die Datenbank aktualisiert hat (mit mpc status checken)
$ mpc add /
$ mpc play

MPC ist ein kleiner CLI Client für MPD. Eine Übersicht über die zur Verfügung stehenden Optionen liefert mpc help.

PiFace CAD einrichten

Auf mein.homelinux.com habe ich bereits eine Kurzanleitung zum PiFace CAD erstellt. Dort findet sich auch ein Abschnitt zur Einrichtung. Die Eckpunkte meines Vorgehens zu Einrichtung des CADs, die im Übrigen sehr gut auf der offziellen Seite dokumentiert sind:

  • SPI aktivieren (siehe weiter oben)
  • python{,3}-pifacecad (die offizielle Python 2 bzw. 3 Library) installieren und anschließend den Pi neustarten
  • sysinfo.py (eine Systemstatusanzeige) ausprobieren
  • den IR-Receiver bzw. LIRC einrichten

Die ersten Versuche

Zum PiFace CAD existiert eine offizielle Python Library, über die alle Funktionen des Boards in Python genutzten werden können. In der Dokumentation zur Library finden sich einige gut erklärte Beispiele, sodass auch ein Python Neuling wie ich etwas damit anfangen kann. Hin und wieder lohnt sich auch ein Blick in die Referenz.
Die wichtigsten Funktionen der Lirbrary habe ich hier kurz zusammengefasst. Dort finden sich auch einige kleine Beispiele, die im Endeffekt meine ersten Versuche waren.
Dieser Code nutzt zum Beispiel „Interrupts“ und gibt den gerade gedrückten Button auf das Display aus, dies ist besonders praktisch, wenn einem die Buttonbelegung noch nicht bekannt ist.

import pifacecad
 
# Init the CAD    
def initCad():
	cad.lcd.blink_off()
	cad.lcd.cursor_off()
	cad.lcd.clear()
	cad.lcd.backlight_on()
 
# Handle pushed pins
def handlePin(event):
	event.chip.lcd.clear()
	event.chip.lcd.write("Pressed button:")
	event.chip.lcd.set_cursor(0, 1)
	event.chip.lcd.write(str(event.pin_num))
 
cad = pifacecad.PiFaceCAD()
initCad()
listener = pifacecad.SwitchEventListener(chip=cad)
 
for i in range(8):
	listener.register(i, pifacecad.IODIR_FALLING_EDGE, handlePin)
 
listener.activate()

Für den Anfang habe ich mich entschieden vorerst kein LIRC zu verwenden. Ich will zuerst eine funktionierende Steuerung nur mit den Buttons realisieren.

MPD ansteuern

MPD lässt sich ganz einfach aus der Shell mit dem CLI Client mpc steuern. In Verbindung mit der Fähigkeit von Python Shell Befehle zum Beispiel mit os.system() auszuführen, ergibt sich hieraus eine sehr einfache Möglichkeit MPD zu kontrollieren:

$ python3
>>> import os
>>> os.system("mpc next")      # nächster Titel

Um nun auch die Ausgaben von mpc parsen zu können, kann subprocess.check_output() verwendet werden:

$ python3
>>> import subprocess
>>> status = subprocess.check_output("mpc status", shell=True, stderr=subprocess.STDOUT)      # Achtung: Python3 => binary string
>>> status = status.decode()
>>> status.find("%")

Mit diesen Hilfsmitteln habe ich nun versucht eine einfach Steuerung zu realisieren:

  • Eine erste naive Umsetzung: Mein erster Versuch, in dem das Display nicht wirklich verwendet wird, ist hier ersichtlich. Der Code nutzt den Status (Play/Pause) von MPC nur bedingt.
  • Erweiterte Realisierung: In diesem Code berücksichtige ich die Ausgaben von mpc zur Titelanzeige, Volumenanzeige und zur Ermittlung des Statuses (Play/Pause). Außerdem habe ich die Steuerung von MPD in eine eigene Klasse ausgelagert.

Wie gehts es weiter?

Der Code kann bis jetzt nur die Basisaufgaben, so aktualisiert sich die Anzeige noch nicht. Pin/Taster 0 ist eigentlich noch unbelegt und soll später dazu verwendet werden zwischen den einzelnen Funktionen des erweiterten Mediaplayersumzuschalten.
Bis jetzt habe ich neben der MPD Steuerung noch eine Uhr- und Wetteranzeige, eine Netzwerk bzw. Statusfunktion und die Möglichkeit den Raspberry Pi herunterzufahren oder zu rebooten in Planung. Diese zusätzlichen Funktionen werde ich nach und nach implementieren und hier über meinen Fortschritt berichten.

// Raspberry Pi: Basteln mit dem PiFace Control and Display

Neulich bin ich auf das PiFace Control and Display aufmerksam geworden. Die Erweiterungsplatine für den Raspberry Pi verfügt neben einem bequem mit Python programmierbaren Display über einen IR-Receiver, 5 Taster und einen Navigationsschalter. Die Dokumentation des Boards ist sehr ausführlich und enthält zahlreiche Beispiele.
Ich habe vor mit dem Board (und natürlich einem Pi) ein auf dem Musik Player Demon (MPD) basierenden Musikplayer zu basteln. Da ich die Hardware erst bestellt habe und noch nicht in den Händen halte, kann ich in diesem Post leider nur die beiden Komponenten – den Musikserver und das Erweiterungsboard – vorstellen und ein wenig auf die Möglichkeiten eingehen.

Hardware – PiFace Control and Display

Der IR-Receiver kann von LIRC verwendet werden, was die Hardware äußerst interessant macht. So kann der Pi prinzipiell von jeder IR-Fernbedienung aus gesteuert werden. Damit ist z.B. ein Musikplayer sehr gut realisierbar – von überall im Raum kann die Playlist gewechselt, die Musik pausiert oder die Lautstärke verändert werden.
Auch Timer (etwa nach 10min Pause) oder gar Weckzeiten könnte man damit einstellen. Mit den zusätzlich auf dem Board angebrachten Schaltern und Tastern lässt sich dies natürlich auch direkt am Pi erledigen.
Auf dem Displays des Boards können zusätzlich zahlreiche Informationen wie Musiktitel, Künstler, Lautstärke und Dauer dargestellt werden.

Musikserver – Musik Player Demon (MPD)

Musik höre ich in den eigenen 4 Wänden mit dem Musikserver Musik Player Demon (MPD). Die Software ist als Client/Server aufgebaut, wobei MPD eigentlich nur den Server bereitstellt.

  • Der Server (MPD) gibt die Musik wieder und verfügt über die Musiksammlung. Da der Server wenn möglich immer verfügbar sein sollte, macht es Sinn hier einen kleinen sparsamen Rechner zu verwenden, der außerdem passiv gekühlt/leise ist. Der Raspberry Pi erfüllt genau diese Eigenschaften und verfügt auch gleich über ein Audiointerface.
  • Der Client, der nun z.B. die Playlists erstellt und auswählt, die Lautsärke regelt, die Musik pausiert und fortsetzt, kann dann ein anderer Rechner mit entsprechender Software oder ein Smartphone mit passender App sein.

Aber auch eine Steuerung direkt auf dem Pi ist möglich und genau hier kommt nun das PiFace Control and Display zum Einsatz. Durch die zahlreichen Mensch-Maschine-Schnittstellen (IR-Fernbedienung, Taster/Schalter, Display) bietet es sich sehr gut zur Steuerung von MPD und zur Präsentation der relevanten Daten an.

Vorausblick – Wie gehts weiter?

Genug geschrieben, in der nächsten Zeit werde ich mich (sobald ich die Hardware habe) mit der Steuerung von MPD mit dem PiFace Control and Display beschäftigen …und mich in Python einarbeiten :-)
Zunächst habe ich vor einzelne Aktionen wie Pausieren der Musik oder Anpassung der Lautstärke über die Taster und später dann natürlich auch per IR-Fernbedienung zum Laufen zu bekommen. Das Display werde ich dann nach und nach einbinden. Wobei ich hier noch gespannt bin, wie das alles läuft.
Interessant ist auch die Anzeige des Wetters (siehe Beispiel) oder die Integration einer Weckerfunktion. Doch dazu in den nächsten Wochen mehr!

// Kurztipp: BIND – Cache leeren

Nachdem diese NoIP Geschichte nun doch noch ein gutes Ende genommen hatte, musste ich ein paar Backup MX-Einträge wieder zurückbiegen, die ich nach dem Domainklau durch Microsoft verbiegen durfte. In diesem Zusammenhang nochmal vielen Dank an die Redmonder ;-)
Wenn man Änderungen an DNS Records kontrollieren will, muss man wegen den Verzögerungen/Caching/TTL im Domainsystem meistens etwas warten (teilweise bis zu 24h). Ein eigener Resolver wie z.B. BIND verkürzt diese Wartezeit extrem, wenn man dessen Cache leert. Dies geht bei BIND mit dem Tool rndc:

$ sudo rndc flush       # mit Root-Rechten ausführen!

Die Änderungen kamen ca. 15min. später an! MX-Einträge lassen sich übrigens sehr gut mit nslookup oder host überprüfen:

$ nslookup -q=mx domain.tld
$ host -t mx domain.tld

// Matlab: Datenauswertung mit corrcoef() und der Statistics Toolbox

Vor Kurzem stand ich vor der Aufgabe eine große Anzahl an in CSV enthaltenen Daten auszuwerten. Neben der Berechnung der Korrelationsmatrix, der Varianz, des Mittelwerts, des Medians und der Standardabweichung, galt es auch diese Größen als Tabelle in LaTeX zu exportieren. Dazu habe ich eine kleine Matlab Funktion erstellt, die genau diese Aufgabe erfüllt.

Vorarbeit mit LibreOffice und dem CLI

Zunächst habe ich das Rohformat mit LibreOffice Calc grob vorbereitet. Dabei habe ich unter anderem nicht vorhandene Messwerte durch NaN (Not a Number) ersetzt und nachträglich durch Automatisierung nicht behebbare Probleme „von Hand“ gelöst. Die erste Zeile und Spalte (mit den Titeln/Inhalten) habe ich mit cut und sed automatisch entfernt um nachher die Daten in Matlab einfacher einlesen zu können (wäre natürlich auch mit diesen Zeilen/Spalten möglich gewesen). Dazu habe ich folgendes einfache Skript verwendet (hier wurden auch noch die Semikolons durch Kommas ersetzt).

#!/bin/bash
 
READY="../Fertig"
 
for i in *.csv
do
   cat $i | cut -d";" -f2- | sed 1d | sed 's/;/,/g' > ${READY}/${i}
done

Auswahl der passenden Funktionen in Matlab

Als nächstes suchte ich mir passende Matlab Funktionen und informierte mich über deren Parameter. Hilfreich ist in diesem Zusammenhang immer die Hilfefunktion (help function_name).

Import der Daten: csvread()

Die Daten konnte ich in Matlab nun einfach mit csvread() einlesen. An csvread() muss nur der Dateiname als String übergeben werden.

>> csvread('test.csv')
 
ans =
 
     1     2
     3     4
     1   NaN

Berechnung der Korrelationsmatrix: corrcoef()

Sehr wichtig bei der Berechnung der Korrelationsmatrix war es die zuvor eingetragenen NaNs zu berücksichtigen. Matlab meinte dazu folgendes:

>> help corrcoef
 corrcoef Correlation coefficients.
    [...]=corrcoef(...,'PARAM1',VAL1,'PARAM2',VAL2,...) specifies additional
    parameters and their values.  Valid parameters are the following:
 
        Parameter  Value
        'rows'     Either 'all' (default) to use all rows, 'complete' to
                   use rows with no NaN values, or 'pairwise' to compute
                   R(i,j) using rows with no NaN values in column i or j.
                   The 'pairwise' option potentially uses different sets
                   of rows to compute different elements of R, and can
                   produce a matrix that is indefinite.

Folglich stand die Funktion corrcoef() mit den Werten 'complete' oder 'pairwise' für den Parameter 'rows' zur Auswahl. Hier ein kleines Beispiel mit 'complete'.

>> M=[1:4,NaN;2:2:10;3:3:15]
 
M =
 
     1     2     3     4   NaN
     2     4     6     8    10
     3     6     9    12    15
 
>> corrcoef(M)                        % normal
 
ans =
 
     1     1     1     1   NaN
     1     1     1     1   NaN
     1     1     1     1   NaN
     1     1     1     1   NaN
   NaN   NaN   NaN   NaN   NaN
 
>> corrcoef(M,'rows','complete')      % hier dann mit 'rows','complete'
 
ans =
 
    1.0000    1.0000    1.0000    1.0000    1.0000
    1.0000    1.0000    1.0000    1.0000    1.0000
    1.0000    1.0000    1.0000    1.0000    1.0000
    1.0000    1.0000    1.0000    1.0000    1.0000
    1.0000    1.0000    1.0000    1.0000    1.0000

Berechnung weitere statistischen Werte: Statistics Toolbox

Für die anderen Größen habe ich jew. die passenden Funktionen der Statistics Toolbox (nanvar, nanmean(), nanmedian() und nanstd()) verwendet. Diese Funktionen berücksichtigen ebenfalls die NaNs bei der Berechnung.

>> mean([2;3;NaN])      % "normales" mean
 
ans =
 
   NaN                  % ...kann nicht mit NaNs umgehen
 
>> nanmean([2;3;NaN])   % nanmean
 
ans =
 
    2.5000              % ...hingegen schon 

Export der Daten: matrix2latex

Um diese Daten nun in LaTeX Files zu exportieren, habe ich die Funktion matrix2latex von Moritz Koehler verwendet. Eine ausführliche Beschreibung der Parameter findet sich in den Kommentaren der Funktion.

Fertige Matlab Funktion

Im folgenden die fertige Matlab Funktion. Statt fprintf() kann übrigens auch disp() verwendet werden.

function [  ] = auswerten( file )
%Funktion zum Auswerten der Daten
%   Berechnet KorrelationsM, Mittelwert, Median, Standardabweichung und Varianz
%   und exportiert diese Groessen in 2 LaTeX Tabellen
 
    % Daten einlesen
    fprintf('Daten:\n')
    M=csvread(file)
 
    % Korrelationen berechnen
    fprintf('Normal:\n')
    normalC=corrcoef(M)
    fprintf('Complete:\n')
    completeC=corrcoef(M,'rows','complete')
    fprintf('Pairwise:\n')
    pairwiseC=corrcoef(M,'rows','pairwise')
 
    % weitere stat. Werte
    fprintf('Mean (Mittelwert):\n')
    meanM=nanmean(M)
    fprintf('Median:\n')
    medianM=nanmedian(M)
    fprintf('Std (Standardabweichung):\n')
    stdM=nanstd(M)
    fprintf('Var (Varianz):\n')
    varM=nanvar(M)
 
    % stat. Werte in eine Matrix
    statM=[meanM; medianM; stdM; varM]
 
    % In LaTeX exportieren
    valDesc={'val1', 'val2', 'val3', 'val4', 'val5'};
    statDesc={'Mittelwert', 'Median', 'Standardabweichung', 'Varianz'};
    exportC=['../Export/' file '.tex'];
    exportS=['../Export/' file 'stat.tex'];
 
    matrix2latex(completeC, exportC, 'rowLabels', valDesc, 'columnLabels', valDesc, 'alignment', 'c', 'format', '%-6.2f', 'size', 'tiny');
    matrix2latex(statM, exportS, 'rowLabels', statDesc, 'columnLabels', valDesc, 'alignment', 'c', 'format', '%-6.2f', 'size', 'tiny');
 
end

An diese Funktion muss der Dateipfad eines bereits „zurecht geschnittenes“ CSV File als String übergeben werden:

>> auswerten('datei.csv')

Anschließend wird die Datei eingelesen, die Werte berechnet und in zwei LaTeX Tabellen, wovon eine die Korrelationsmatrix und die andere die statistischen Werte enthält, exportiert. Diese Dateien können dann in einem LaTeX Dokument mit \input{} oder \include{} eingebunden werden. Falls mehrere Datensätze ausgewertet werden, kann eine weitere Funktion (oder Aufruf) diese Funktion z.B. über eine For-Schleife ausführen.

Hello World!

This is the personal website of Christoph Winkler aka chrisge.
Here you will find a sort of blog and some information about me and my projectshave fun!

Recent Comments
Latest Tweets

Follow me on Twitter...

QR-Code: aktuelle Seiten-URL
Falls nicht anders bezeichnet, ist der Inhalt dieses Wikis unter der folgenden Lizenz veröffentlicht: CC Attribution-Noncommercial-Share Alike 3.0 Unported