In seiner Funktionalität auf die Lehre in gestalterischen Studiengängen zugeschnitten... Schnittstelle für die moderne Lehre
In seiner Funktionalität auf die Lehre in gestalterischen Studiengängen zugeschnitten... Schnittstelle für die moderne Lehre
Dieses Projekt entstand im Rahmen folgenden Kurses:
Copper Turtle (Interface Werkstatt Blockseminar) 14W4D-IL Interface-Labor Sommersemester 2016 Dozent: Fabian Morón Zirfas
In diesem Seminar setzten wir uns mit unterschiedlichen Technologien und den Grundlagen der Softwareentwicklung auseinander. Es wird das Programmieren von Arduino Mikrocontroller in C++ und JavaScript für Generative Gestaltung im Webbrowser vermittelt. Das Seminar erstreckt sich über 6 ganztägige Termine und ist in 3 Tage Workshop und 3 Tage Mash-Up-Projekt gegliedert.
(offizielle Kursbeschreibung)
Im sechstägigen Blockseminar, geleitet von Fabian Morón Zirfas, lernten wir an den ersten drei Tagen die Grundkonzepte generativer Gestaltung mit P5.js sowie Grundlagen der Arduino-Plattform kennen. In den darauffolgenden Tagen sollte ein kleines, freies Projekt realisiert werden. Es war uns hierbei freigestellt, ob wir uns mit P5.js oder Arduino beschäftigen möchten.
Ich entschied mich, ein mit Solarzelle betriebenes Kinderspielzeug (Modell eines Dinosauriers) umzubauen und eine kabellose Steuerung mit Hilfe eines Smartphones zu ermöglichen.
Als Projektgrundlage diente ein kleines Plastikmodell eines grünen Dinosauriers, welches ich als Bausatz für knapp 8 Euro kaufte. In der Verkaufsedition wird der Dino über eine Solarzelle auf dem Kopf, im Falle von (starker) Sonneneinstrahlung, mit Strom versorgt und beginnt zu laufen.
Es ist kein An-/Aus-Schalter vorhanden. Die Möglichkeiten mit dem Modell zu interagieren sind also begrenzt. Entweder der Dino läuft, oder er läuft nicht. Diesen Umstand galt es zu ändern.
Ich habe mir von Anfang an vorgenommen, den Dino mit Hilfe des Gyroskops eines Smartphones zu steuern. Wird das Smartphone nach vorne gekippt, läuft der Dino. Je stärker die vom Gyroskop gemessene Neigung, desto schneller wird er. Wird das Smartphone aufrecht gehalten, stoppt das grüne Plastikreptil.
Ich habe mich zur Steuerung für eine Webseite statt für eine App entschieden. Die Werte des Smartphone-Gyroskops lassen sich leicht via JavaScript auslesen. Eine Webseite hat zudem den Vorteil, dass wirklich jeder Smartphonebesitzer den Dino steuern könnte, solange er die Adresse der Webseite kennt. Ein, wie ich finde, sehr spannender Ansatz, den ich in Zukunft gerne auch bei anderen Projekten zum Einsatz bringen möchte.
Hardwareseitig habe ich ein [Particle Photon](https://store.particle.io/collections/photon „Particle Photon“) verwendet. Das Arduino-Board verfügt über ein eingebautes WLAN-Modul, serverseitige IoT-Kommunikationsfähigkeiten mittels der kostenlosen Particle-Plattform und hat zudem eine sehr geringe Größe (36,58mm × 20,32mm × 6,86mm). Ideal für den Plastikdino geeignet.
Mittels Webseite wird also das Gyroskop des Smartphones ausgelesen. Der gemessene Wert wird per HTTP-POST-Request an die Particle-Plattform gesendet, welche ihn daraufhin an das Photon-Board weiterleitet, welches schlussendlich den Motor des Dinos ansteuert.
Die aktuellen Neigungswinkel des Smartphones lassen sich per JavaScript relativ einfach auslesen. Lediglich ein EventListener für das „deviceorientation“-Event wird benötigt. Danach sollten die ausgegebenen Daten in Variablen gespeichert werden.
window.addEventListener(„deviceorientation“, handleOrientation, true);
function handleOrientation(event) {
var absolute = event.absolute;
var alpha = event.alpha;
var beta = event.beta;
var gamma = event.gamma;
// Do stuff with the new orientation data
}
Codebeispiel aus dem [Mozilla Developer Network](https://developer.mozilla.org/en-US/docs/Web/API/Detecting_device_orientation „Mozilla Developer Network“)
Um ältere Browserversionen zu unterstützen und um Unterschiede in den Gyroskop-Werten zwischen verschiedenen Plattformen auszugleichen (Apple-Geräte geben leicht anders berechnete Daten zurück) ist es jedoch ratsam, die [gyronorm.js-Bibliothek](https://github.com/dorukeker/gyronorm.js „gyronorm.js-Bibliothek“) von Github-Nutzer [dorukeker](https://github.com/dorukeker „dorukeker“) zu verwenden.
/* this code uses gyronorm.js */
var gyroBeta = 0;
var gn = new GyroNorm();
gn.init().then(function(){
gn.start(function(data){
gyroBeta = data.do.beta;
});
}).catch(function(e){
// Catch if the DeviceOrientation or DeviceMotion is not supported by the browser or device
});
Mit diesem Code werden die aktuellen Beta-Werte des Smartphone-Gyroskops in einer Variable gyroBeta gespeichert und bei jeder Neuorientierung überschrieben. Der Beta-Wert beschreibt - bei einem aufrecht gehaltenen Smartphone im Portrait-Modus - den Neigungswinkel nach vorne (vom Nutzer weg) oder hinten (zum Nutzer hin).
Die erhaltenen Werte werden schließlich mit Hilfe von [P5.JS](http://p5js.org/ „P5.JS“) in einem simplen Interface verarbeitet und ausgegeben.
Der folgende Code zeichnet mit Hilfe eines frei definierbaren Gridsystems horizontale Linien in ein Canvas-Element, versieht diese mit Prozentangaben (ganz unten: 0%, ganz oben: 100%) und platziert - je nach Wert des Gyroskops - einen Indikator auf dieser Skala. Der verarbeitete Gyroskop-Wert wird zudem, zu Testzwecken, in einer Zeile am Kopf der Seite ausgegeben.
/* this code uses P5.JS */
var lastInputData;
var inputData = 0;
function setup(){
// executed once
createCanvas(windowWidth, windowHeight);
setTimeout(sendToPhoton, 150); // start timeout loop
}
function draw(){
// executed all the time
var vGrid = 14; // define vertical gridsystem
var hGrid = 8; // define horizontal gridsystem
// map gyroscope value to display height
// and define a tilt scope
var minTilt = 20; // in degree
var maxTilt = 70;
if(gyroBeta >= minTilt && gyroBeta <= maxTilt) {
var mappedBeta = map(gyroBeta, minTilt, maxTilt, height/vGrid*2, height - height/vGrid*2);
console.log(mappedBeta);
} else if(gyroBeta < minTilt) {
mappedBeta = height/vGrid*2;
} else if(gyroBeta > maxTilt) {
mappedBeta = height - height/vGrid*2;
}
// draw grid-system and numerics
background(10);
textFont(„Roboto Mono“);
textSize(14);
for(i = 2; i <= vGrid; i++){
if(i != 2 && i != vGrid/2 && i != vGrid-1 && i != vGrid-2) {
if (i != vGrid) {
strokeWeight(1);
stroke(200);
line((width/hGrid)*3.3, i*height/vGrid, (width/hGrid)*4.7, i*height/vGrid);
}
} else if(i != vGrid-1) {
strokeWeight(2);
stroke(150);
line((width/hGrid)*3.1, i*height/vGrid, (width/hGrid)*4.9, i*height/vGrid);
fill(150);
strokeWeight(0);
if (i == 2) {
text("100%", (width/hGrid)*4.9+13, i*height/vGrid+5);
} else if (i == vGrid/2) {
text("50%", (width/hGrid)*4.9+13, i*height/vGrid+5);
} else {
text("0%", (width/hGrid)*4.9+13, i*height/vGrid+5);
}
}
}
// draw moving indicator
strokeWeight(20);
stroke(170, 220, 20);
point(width/2, mappedBeta);
// send data to Particle Photon
inputData = map(mappedBeta, height/vGrid*2, height - height/vGrid*2, 255, 0).toFixed();
}
function windowResized(){
resizeCanvas(windowWidth, windowHeight);
}
Alle 150ms (via Timeout-Function, siehe Codeblock oben) wird zudem die Funktion sendToPhoton aufgerufen. Diese übermittelt einen, von Arduino zur Motorsteuerung verarbeitbaren, Wert (zwischen 0 und 255 - zur Konvertierung der Werte via P5.JS-map-Function siehe Codeblock oben) mittels HTTP-Post-Request an die Particle-Plattform.
Um den Post-Request einfacher zu gestalten habe ich hierfür die [jQuery-Bibliothek](https://jquery.com/ „jQuery-Bibliothek“) verwendet.
function sendToPhoton(){
var photonID = „Photon-Gerätename“;
var accessToken = „privater Photon-Access-Token“;
var webHook = „motor“;
var url = „https://api.particle.io/v1/devices/“ + photonID + „/“ + webHook + „?access_token=“ + accessToken;
// compare current input value to last input value
if(lastInputData !== inputData) {
$.post(url, {value: inputData}, function(data, status) {
console.log("Status: " + status);
});
document.getElementById('log').innerHTML = inputData;
} else {
document.getElementById('log').innerHTML = "No new input. Last input: " + lastInputData;
}
// start new Timeout
setTimeout(sendToPhoton, 150);
lastInputData = inputData;
}
Die Variable PhotonID muss den jeweiligen Gerätenamen des Particle-Photon-Boards enthalten und accessToken muss einen privaten Hashwert enthalten, welcher vor unberechtigten Zugriffen schützt und im Backend der Particle-Plattform vergeben wird.
Ich habe die so entstandene Smartphone-Steuerung zunächst über einen lokalen [NodeJS](https://nodejs.org/en/ „NodeJS“)-Server getestet. Somit war die Webseite nur aus meinem privaten Netzwerk zu erreichen. Natürlich könnte man das Projekt auch auf einem externen Server hosten und somit die Steuerung von überall ermöglichen.
![arduino dino](http://i.giphy.com/4XrNnhQSImic0.gif „Arduino Dino“)
Nach dem Zusammenbau des Dinosaurier-Bausatzes habe ich zunächst die Solarzelle vom integrierten Mini-Motor abgelötet. Nach einem kurzen Messvorgang, zur Ermittlung der Stromstärken und Spannungen der Solarzelle, konnte ich den Motor mit meinem Particle-Photon-Board verbinden. Zunächst in einem Testsetting mittels Breadboard.
Sehr hilfreich hierbei war der Learn-Arduino-Workshop von adafruit.com - insbesondere das [Beispiellayout für DC-Motoren](https://learn.adafruit.com/adafruit-arduino-lesson-13-dc-motors/breadboard-layout „Beispiellayout für DC-Motoren“).
Der Motor wird über einen der PWM-Pins (pulse width modulation) des Particle-Photon-Boards angesteuert. PWM-Pins akzeptieren Eingabewerte zwischen 0 (Aus) und 255 (volle Leistung). Die Smartphonesteuerung liefert uns bereits Werte innerhalb dieser Bandbreite, diese müssen also lediglich verarbeitet werden.
Der notwendige Arduino-Code gestaltet sich daher relativ übersichtlich:
int motor1 = D0;
void setup()
{
pinMode(motor1, OUTPUT);
Particle.function(„motor“,motorToggle);
// This is saying that when we ask the cloud for the function „motor“, it will employ the function motorToggle().
// For good measure, let's also make sure the motor is off when we start:
analogWrite(motor1, 0);
}
void loop()
{
// Nothing to do here
}
int motorToggle(String command) {
int cmd = command.toInt();
if (cmd >= 0 && cmd <= 255) {
analogWrite(motor1, cmd);
return cmd;
}
else {
return -1;
}
}
Nach einigen anfänglichen Schwierigkeiten mit den Widerstandswerten der Diode und des Transistors lief der Motor zum ersten Mal über den vom Board gelieferten Strom. Noch am Breadboard und damit nicht kabellos, aber immerhin.
Kleiner Schock: der Dino läuft rückwärts. Habe ich ausversehen einen Moonwalk-Dino erschaffen? Doch die Lösung gestaltete sich einfach: Plus- und Minus-Speisung des Motors tauschen, fertig. Das Plastikreptil läuft brav geradeaus.
Zu diesem Zeitpunkt wurde das Photon-Board und somit auch der Dinomotor noch via USB mit Strom versorgt. Um einen wirklich kabellosen Dinosaurier zu erschaffen, musste dieser natürlich noch auf Akkubetrieb umgestellt werden.
Ich habe einen 1000mAh 3.7V Lithium-Polymer-Akkumulator verwendet. Der neue Schaltplan gestaltete sich daher wie folgt:
All dies galt es nun vom Breadboard zu lösen und auf dem Dino selbst zu befestigen. Zu diesem Zweck habe ich Transistor, Diode und Widerstand auf eine kleine Platine gelötet.
Für die Platine und den Akku habe ich einen Rucksack genäht, welcher auf dem Rücken des Dinosauriers Platz findet. Das Particle-Photon-Board wurde zunächst notdürftig mit Gummbändern auf dem Kopf befestigt.
Funktionierte bereits kabellos, sah aber noch nicht ideal aus. Fabian äußerte den Wunsch, die noch sichtbare Technik besser zu verstecken und die Gummibänder verschwinden zu lassen.
Kein Problem. Ich habe daraufhin den Rucksack mit angenähten Druckknöpfen statt mit Gummibändern am Dino befestigt - dafür hat er extra ein paar zusätzliche, maßgeschneiderte Schulterriemen bekommen. Das Board auf dem Kopf wurde mit einer kleinen Strickmütze versteckt.
Mit Rucksack und Mütze ausgestattet war der Dino somit also endlich bereit für seine Ausflüge in die große, weite Welt.
Folgende Probleme bestehen noch bei diesem Projekt:
Zumindest die langsamen, schwerfälligen Bewegungen ließen sich mit einem stärkeren Motor lösen.
Nichtsdestotrotz war das Projekt für mich ein voller Erfolg. Ich konnte in drei Tagen alles umsetzen was ich mir vorgenommen hatte, ohne Vorerfahrung mit Arduino oder Physical Computing zu haben. Fabians Ratschläge und Lösungsansätze haben dabei geholfen, manches Problem deutlich schneller zu beheben als es ansonsten der Fall gewesen wäre. Vielen Dank dafür!