15.08.2013

Wärmebildkamera mit dem RasPi (3): Ansteuerung der Servos / Auswertung mit Python

1. Thermographie-Kamera mit dem Raspberry Pi
2. Ansteuerung des Sensors mit Perl
3. Ansteuerung der Servos / Auswertung (dieser Teil)
4. Zusammenfassung, WLAN und  Batteriebetrieb


Code: 




Montage des Sensors

Der MLX90614-Sensor muß in zwei Achsen bewegt werden, um ein Bild abzuscannen. Für jede Achse wird ein RC-Servo verwendet, die beiden Servos wurden mit Sekundenkleber aufeinander geklebt. Der Sensor wurde per Kabelbinder an einem Servo befestigt. Die Servos sind für etwa 5-10€ erhältlich, es genügt die "Micro"-Ausführung, da sie wenig Platz und Strom braucht.



Ansteuerung eines RC-Servos

RC-Servos (Modellbauservos) werden über Pulsweitenmodulation (PWM) angesteuert. Die Breite des Impulses bestimmt die Stellung des Servos. Üblicherweise entspricht die eine Endstellung einer Impulsbreite von 1ms, die andere einer Breite von 2ms. In Mittelstellung ist das Servo bei einem Impuls von 1,5ms.

Genauer ist das hier erklärt:
Die PWM-Eingänge der Servos sind direkt an GPIO 24 und 25 (Pins 18 und 22 der GPIO-Kontaktleiste) angeschlossen. Zusätzlich brauchen die Servos noch Masse und +5V, das sind Pin 25 bzw Pin 2 der Kontaktleiste. Obwohl die GPIO-Pins nur 3,3V liefern, klappt bei mir die Servoansteuerung ohne weitere Zusatzschaltung. Wichtig ist, daß das Netzteil genügend Leistung hat, sonst hängt sich der Raspberry Pi auch schon mal auf.

RC-PWM und der Raspberry Pi

Der Raspberry Pi hat zwar Hardware-Unterstützung für PWM, aber leider nur für einen GPIO-Pin. Wir brauchen aber zwei Servos..

Wenn man per Software und Pythons sleep() versucht, PWM-Signale zu erzeugen, stellt man fest, daß die Pulsweite variiert und die Servos ziemlich zittern. Das passiert, weil unter Linux viele Prozesse laufen und damit die Zeitzuteilung für den Python-Prozess variiert und ungenau ist.

RPIO.PWM als Abhilfe

Chris Hager (chris@linuxuser.at) hat ein Python-Modul geschrieben, das DMA zum Erzeugen von PWM-Impulsen benutzt und so die Einschränkungen von Hardware- oder Software-PWM umgeht. Damit kann man ohne CPU-Belastung stabile PWM-Impulse erzeugen. Als Bonus gibt es noch High-Level-Funktionen zum direkten Ansteuern von Servos. Was will man mehr..

Installation von RPIO.PWM

Um das Modul zu installieren, führt man auf der Kommandozeile (eingeloggt als root  per ssh) folgende Befehle aus:

apt-get install python-dev
apt-get install python-setuptools
git clone https://github.com/metachris/RPIO.git
cd RPIO
python setup.py install


und weil wir schon dabei sind, wird gleich auch noch matplotlib für Python installiert:

apt-get install python-matplotlib

Dann noch das bottle-Framework (für den Webserver, siehe unten)

easy_install -U bottle

Damit ist unsere Python-Umgebung auf dem Raspberry Pi fertig.

Start des python-Scripts

als Benutzer root

python web.py

Aufgaben des Python-Scripts

Das Python-Script ist die zentrale Software der Thermographie-Kamera, es erledigt folgende Aufgaben:
  • Webserver mit Bedienoberfläche
  • Setup der Hardware
  • Steuerung der Servos
  • Abholen der Sensordaten
  • Erzeugen des Thermographiebildes

Webserver mit Bedienoberfläche

Die Bedienung der Thermographie-Kamera erfolgt über eine Weboberfläche. Das bedeutet, daß auf dem Raspberry Pi ein Webserver laufen muß. Dazu gibt es für Python das Bottle-Web-Framework, das einen minimalen Webserver bereitstellt.

Für die Thermographie-Kamera besteht die Oberfläche aus einer einzigen index.html-Datei, die das neueste Image anzeigt. Drei Links werden vom Python-Script erkannt und erzeugen Wärmebilder mit verschiedener Auflösung, indem Parameter für den Scan-Vorgang gesetzt werden.



 

Setup der Hardware

Je nach Auflösung (small, standard und big) wird die Schrittweite der Servos berechnet und damit der Scanvorgang gestartet.

Steuerung der Servos / Erfassung der Daten

Die Datenerfassung erfolgt in einer verschachtelten Schleife für X- und Y-Koordinaten. Dazu muß vorher das Perl-Script für den Sensor gestartet sein, damit die Temperaturwerte geholt werden können.
  • Jede Position wird angefahren (servo.set_servo)
  • kurz gewartet (time.sleep(), der Sensor ist etwas träge). 
  • Dann wird der aktuelle Temperaturwert vom Sensor-Daemon per http gelesen (mit urlopen(), response.read()) 
  • und in ein Array geschrieben.

# Sweep thru one frame
  for x in range(step_count):
    servo.set_servo(servo_x, start_pos + x * step_size)
    servo.set_servo(servo_y, start_pos)
    time.sleep(pause_line)
    for y in range(step_count):
      servo.set_servo(servo_y, start_pos + y * step_size)
      time.sleep(pause)
      response=urllib2.urlopen(mlx_url)
      temperature=response.read()
      data[x,y]=temperature

Erzeugung des heatmap-Bildes

Die gemessenen Temperaturwerte befinden sich nun in einem Array. Das Array wird über die matplotlib-Library in ein .png-Image verwandelt und beschriftet. Hier das Codeschnipsel dazu:

# Generate heatmap from data array
  cmap = cm.get_cmap('jet')
  plt.clf()
  plt.imshow(data, interpolation="nearest", cmap=cmap)
  plt.axis('off')
# add temp colorbar
  cb = plt.colorbar()
  date_disp = datetime.now().strftime("%Y-%m-%d  %H:%M")
  cb.set_label('Temp (in C)  ' + date_disp)
  plt.savefig('/root/thermo/scripts/images/heatmap.png')

# save again with datecoded filename
  date_string = datetime.now().strftime("%Y-%m-%d--%H-%M")
  plt.savefig('/root/thermo/scripts/images/heatmap' + date_string + '.png')

  redirect("/html/index.html")


matplotlib ist sehr mächtig - es reichen10 Zeilen Code aus, um aus den Rohdaten ein Bild zu erzeugen!

Der Dateiname wird um das Datum ergänzt und in einem extra Verzeichnis abgespeichert. Anschließend erhält der Browser einen redirect auf die Startseite, das gerade generierte Image wird angezeigt.

Was wurde erreicht?


Nach Start von zwei Skripten mit

perl mlx.pl
python web.py

haben wir
  • Eine Weboberfläche, die das neueste Wärmebild anzeigt
  • Die Möglichkeit, neue Wärmebilder mit drei Auflösungen (10x10, 32x32 und 48x48 Pixel) zu erzeugen
  • Bedienung über Browser via PC und Handy möglich



Links




1. Thermographie-Kamera mit dem Raspberry Pi
2. Ansteuerung des Sensors mit Perl
3. Ansteuerung der Servos / Auswertung (dieser Teil)
4. Zusammenfassung, WLAN und  Batteriebetrieb

12.08.2013

Wärmebildkamera mit dem RasPi (2): Ansteuerung des Sensors mit Perl

1. Thermographie-Kamera mit dem Raspberry Pi
2. Ansteuerung des Sensors mit Perl (dieser Teil)
3. Ansteuerung der Servos / Auswertung
4. Zusammenfassung, WLAN und  Batteriebetrieb

Schwierigkeiten..

I2C-Bus am Raspberry Pi und repeated start


Der MLX90614 hat eine I2C-Schittstelle, der Raspberry Pi ebenso und außerdem ist I2C in den Linux-Kernel der verwendeten Raspbian-Distribution integriert.

So weit, so gut! Eigentlich sollte also eine Integration ohne Klimmzüge funktionieren. Leider steckt der Teufel im Detail: der MLX90614 benutzt zum Auslesen der Temperatur die Repeated-Start-Condition, die im I2C-Standard definiert ist. Dummerweise kennt der I2C-Kernel-Treiber für den Raspberry Pi genau diesen Befehl nicht! Damit kann man den Sensor nicht per I2C-Kernel-Modul auslesen - eine andere Lösung muss her!

 

Lösung mit Perl-Modul


Glücklicherweise hat Mark Dootson ein Perl-Modul geschrieben, das die repeated-start-Funktion für den I2C-Bus nachrüstet. Auslesen des MLX90614 ist damit  mit einem Perl-Script möglich.

Er beschreibt das in seinem Blog:
I2C-Zugriff und andere Befehle hat er in seinem HiPi-Perl-Modul zusammengefasst. Damit ist der Sensor direkt mit einer Scriptprache auslesbar.

 

HiPi-Modul für Perl installieren


Zunächst muß das Perl-Modul installiert werden. Die nachfolgende Anleitung setzt voraus, daß der Raspberry Pi unter Raspbian läuft. Andere Distributionen sind sicherlich auch geeignet, ich habe das aber nicht getestet.
Dazu muß man in einer Shell auf dem Raspberry Pi eingeloggt sein (per ssh oder direkt) und folgende Befehle auf der Kommandozeile ausführen:
wget http://raspberry.znix.com/hipifiles/hipi-install
perl hipi-install (dauert ca 15 Minuten)
Zusätzlich habe ich noch das HTTP::Server::Simple-Modul per Kommandozeile installiert:
sudo perl -MCPAN -e 'install HTTP::Server::Simple' (Fragen mit yes beantworten)
Nun ist das HiPi-Modul und das HTTP-Server-Modul installiert und man kann direkt aus Perl auf den I2C-Bus und damit auf den Thermo-Sensor zugreifen.

Die vom Sensor gemessenene Temperatur  wird über den I2C-Bus aus zwei Registern abgeholt. Dort befindet sich der Rohwert, der noch nach Grad Celsius (bzw Fahrenheit) umgerechnet werden muß.

Das Codeschnipsel zum Lesen des Rohwertes sieht folgendermassen aus:


do {
         eval {
             @reg_val = $dev->i2c_read_register_rs($register, 0x02);
         };
# an error occured, set reg_val to an invalid value
         if ($@) {
             @reg_val = (255, 255);
         }
         $raw = @reg_val[1] * 256 + @reg_val[0];
         $diff = abs($raw - $last_raw);
         $last_raw = $raw;
    } while(($diff > $max_diff) or ($raw > 32000));

In der Praxis hat sich gezeigt, daß das Auslesen nicht immer zuverlässig funktioniert, deshalb ist eine Fehlererkennung eingebaut, die bei zu großer Abweichung vom vorhergehenden Messwert (oder einem Hardware-Fehler) die Messung wiederholt (do/while-Schleife).

Das ist schonmal sehr schön, aber ich finde Python besser geeignet, um die gelesenen Daten auszuwerten und darzustellen.

Dazu müssen die gelesenen Temperaturwerte irgendwie vom Perl-Script an ein Python-Script übergeben werden. Die einfachste Methode dazu ist, das per HTTP zu tun.

 

Temperatur per HTTP auslesen


Damit man per HTTP auf die gemessenen Temperaturwerte zugreifen kann, ist ein Web-Server in das Perl-Script integriert. Das geht ganz einfach mit dem Perl-Modul HTTP::Server::Simple::CGI. Es hört auf verschiedene URLs, die den gelesenen Wert in Celsius, Fahrenheit und als Rohwert ausgeben. Das ermöglicht auch das Auslesen der Temperatur per Browser! Sehr schön zum Testen. Eine weitere URL liefert die Werte als JSON, ideal falls man den Sensor per Javascript befragen will.


Das Script liegt auf GitHub:

https://github.com/hermann-kurz/thermography-raspberrypi/blob/master/perl-sensor/mlx.pl

Gestartet wird es (als root) mit

perl mlx.pl

und läuft dann als Dämon auf Port 8080.

Wenn das Script läuft, kann man direkt im Browser den Sensor per URL aufrufen

http://ADRESSE-DES-RASPBERRY-PI:8080/c



Als JSON sieht das so aus:




und hat die Temperatur im Browser, die der Sensor gerade vor sich sieht!


Was wurde bis jetzt erreicht: Zusammenfassung

  • Zugriff auf den MLX90614-Sensor via Perl
  • Ein in Perl geschriebener HTTP-Server, der die gemessene Temperatur liefert
  • Der Messwert kann in Celsius, Fahrenheit oder als Rohwert angezeigt werden
  • Alle Werte zusammen gibt es als JSON

Nächste Schritte: Servoansteuerung, Auswertung der Messwerte in Python


Links:




1. Thermographie-Kamera mit dem Raspberry Pi
2. Ansteuerung des Sensors mit Perl (dieser Teil)
3. Ansteuerung der Servos / Auswertung
4. Zusammenfassung, WLAN und  Batteriebetrieb