Toolbox Interactiondesign


Hardware & Software Sketching 2012

Pixelschubse

Pixelschubse | Entwurf

Janine Perkuhn, 01.10.2012 | Hardware & Software Sketching bei Prof. Christine Goutrié

Bei dem Projekt „Software & Hardware Sketching“ verschwimmen die Grenzen zwischen Analog und Digital, denn eine 8×8 LED-Matrix ist ein physisches Objekt, auf dem nur in Kombination aus Elektronik und Software leuchtende Pixel entstehen. Das Konzept der „Pixelschubse“ vermittelt den Brückenschlag zwischen Atomen und Bits. Denn was ist ein Pixel? Ist es ein Bit oder ein Atom? Welche Eigenschaften hat es und wie wird es wahrgenommen? Auf einem Display oder einem Blatt Papier ist es ein kaum wahrzunehmendes Bildelement. Auf einer 8×8-LED-Matrix ist es jedoch ein offensichtlicher Teil eines Rasters und steht exemplarisch für einen Hybrid mit virtuellem Hintergrund, der physisch erfahrbar wird. Nehmen wir dieses abstrakte Etwas also mit in unsere reale, dreidimensionale Welt und verleihen ihm physische Eigenschaften.

Die Pixelschubse besteht aus zwei 8×8 LED-Matritzen. Sie sind als Behältnis zu verstehen, in denen sich der physische Pixel befindet. Dieser einzelne leuchtende Pixel besitzt ein Eigengewicht und reagiert auf die simulierte Gravitationskraft der Erde. Mit Hilfe von Lagesensoren und einem entsprechenden Arduino-Skript kann das rote Quadrat von einer Matrix in die andere „geschubst“ werden und kommt am jeweiligen Boden wieder zur Ruhe.

Pixelschubse | Präsentation

Das Ergebnis der “Pixelschubse” und alle weiteren Hard- und Softwaresketching-Projekte wurde intern im Rahmen der Endsemesterausstellung SINNflut im Institut für Industrial Design präsentiert und ausprobiert. Im Oktober waren die Matritzen auf der Designers Open in Leipzig zu sehen und sind auf reges Interesse der Besucher gestoßen.

Pixelschubse | Prozess

Die Entwicklung der Pixelschubse stellt einen Prozess ausgehend von rudimentären Experimenten hin zu einem komplexen Gebilde dar. Sowohl auf Hardware- als auch auf Softwareebene wurde zu Beginn einfachste Versuche gestartet, um sich an die Metrie heranzutasten. Erste Programme befassten sich mit der Steuerung einer, bald mehret, in einer Reihe geschalteten Leuchtdioden. Nachvollzogen wurden die Steckverbindungen, insbesondere aber der Arduino-Code. Mit voranschreitender Erfahrung entstanden zunehmend komplexere Prototypen.

Eine Möglichkeit den Pixeln Physis zu verleihen ist, sich ein Element auszusuchen, das besonders prägnante Eigenschaften besitzt, beispielsweise Wasser. Bewegt man die Matrix, könnten die Pixel hin und her schwappen und wie eine Wasserwaage stets die Neigung ausgleichen. Um den Wiedererkennungswert des Elements zu erhöhen, könnte der Nutzer den Aggregatzustand (respektive Temperatur) der Pixel mit Hilfe von Drehpotis verändern: So wird das Wasser fest oder gasförmig und verdampft. Hier: Erst in Bewegung, dann in gekipptem Zustand eingefroren.

Begreift man den Pixel als einzelnes Objekt und verleiht ihm ein Gewicht, so könnten die Elemente mit dem Finger von einer Seite zur andere geschubst werden oder durch Drehung der Matrix die Zentrifugalkraft simuliert werden. Die Pixel würden dann aus der Matrix „rausfliegen“ oder sich am Rand sammeln.

 

Begreift man die Matrix als geschlossenes Gefäß, indem sich einzelne Partikel befinden, so wirkt sie wie eine Schneekugel. Durch Schütteln bewegen sich die Pixel und setzten sich wieder am Boden ab, sobald die Matrix wieder in ruhigem Zustand ist. Interessant wäre es, wenn die Gravitation verändert werden könnten um z.B. die des Mondes zu simulieren. Die Pixel würden sich dann viel langsamer wieder absetzen.

Um die Brücke zwischen den beiden Welten der Hard- und Software noch offensichtlicher zu schlagen, wurde letztendlich das Konzept verfolgt, indem die einzelnen Pixel aus der Matrix „ausgekippt“ bzw. von einer in eine andere Matrix „gefüllt“ werden können. Dadurch wird besonders in dem Moment, indem die Pixel für die Überbrückung der Distanz kurzzeitig verschwinden, deutlich, dass es diese Objekte, die so physisch wirken, gar nicht gibt.

Mit dem rohen Gerüst der LED-Matrix wurden erste konkrete Experimente durchlaufen. Unter anderem wurde ein „Pixelregen“ simuliert: Viele einzelne Pixel fallen in die Matrix hinein, prallen auf dem Boden auf, prallen ab und hüpfen einige male bevor sie verschwinden und neue Pixel erscheinen. In diesem Rahmen ist das folgende Skript entstanden:

/*
Hochschule Magdeburg Stendal
Master Interaciton Design

Hardware and Software Sketching 
Sommersemester 2012
Betreuung durch Prof. Dr. Christine Goutrié
                Dipl. Ing. Jörg Schröder
Tutor           Stephan Fink

Pixelschubse
Janine Perkuhn

*/

const int an[] = {2,3,4,5,6,7,8,9};          //   Ports für Zeilen 
const int kat[] = {10,11,12,13,14,15,16,17}; //   Ports für Spalten

const int xPin = A4; //   Ports für x-Wert des Beschleunigungssensors
//const int yPin = A5; //   Ports für y-Wert des Beschleunigungssensors

//   Koordinatensystem/bzw. Bühnengröße (Vielfaches der Matrix, damit Beschleunigung möglich ist/Berechnung einfacher ist-> keine Krummen Werte)
int koord[] = {800,800}; //   Array
//   Benennung für Koord.Array:
int breite = 0, hoehe = 1; //   Positionierung der x- und y-Werte (B und H)im Array, 0ter und 1ster Platz im Array

int raster = 8;            //   Raster der Matrix
int wolke[8][2];           //   Wolke = alle fallende Bildpunkte zusammen [Spalten 0 bis 7 bzw. Tropfen] [jeder Tropfen besitzt zwei Werte (y & Bouncer-Wert ->Beschleunigung)], Höhenwerte pro Spalte (jeweils nur ein Tropfen)
//   Benennung für die Zweite Dimension des Arrays Wolke (Tabelle: 0 bis 7 Spalten, Zeilen: yPos und Bouncer):
int yPos = 0, bouncer = 1; //

float beschleunigung = 3;   //   Beschleunigung während des "Falls"
float elast = 0.7;          //   Prallt mit 70% der Aufprallgeschwindigkeit wieder zurück -> bei 1 Entlosflummi
int framesPerSecond = 25;   //   "Bildrate" pro Sekunde (Geschwindigkeit) -> Processingüberrest, Relativiert die Werte

void setup(){

  Serial.begin(115200);          //   Baud Rate (Übertragungsgeschwindigkeit der Bits pro Sekunde) 

  for(int i = 0; i < 8; i++){    //   Initialisierung aller Ports für die Matrix
    pinMode(an[i], OUTPUT);      //   Anoden (Zeilen) als Ausgang definieren
    digitalWrite(an[i], LOW);    //   Anoden in Sperrrichtung schalten
    pinMode(kat[i], OUTPUT);     //   Kathoden (Spalten) als Ausgang definieren
    digitalWrite(kat[i], HIGH);  //   Kathoden in Sperrrichtung schalten

    // Bedeutung/Inhalt der beiden Arraylevels (ertser und zweter Ordnung)
    wolke[i][yPos] = koord[hoehe] + random(1, koord[hoehe]) /2; //   bestimmen der y-Position pro Spalte i (0 - 7) -> 800 + (Wert zw. (1-800) geteilt durch 2) oder: 800 + (Wert zw. 0 und 400) 
    wolke[i][bouncer] = 0;       //   Bestimmung des Bouncer-Werts pro Spalte am Anfang beginnt immer bei 0 Anfangsbeschleunigung
  }
}

void loop(){
  setGravity();  //  Beeinflussen der Gravitation durch den Beschleunigungssensor  
  playRain();   //   Mit jedem durchgang wird Bouncewert
}

void setGravity(){

      beschleunigung = (analogRead(xPin)-512)/170; //   Sensorwert auslesen, mittlen ihn auf 0 (eigentlich 0 - 1023 jetzt aber: -512 bis 511), durch 170 bis Wertebereich bei -3 bis 3 liegt (Beschleunigung in beide Richtungen)

}

void playRain(){

  //   Berechnet die Y-Position der Tropfen für jede Spalte 
  for(int i = 0; i < 8; i++){  
    //   Bed. für durchfallende Tropfen, fallen wieder oben rein bzw. werdne resettet -> IF-BED. UNWICHTIG   NEUER TROPFEN
    /*
    if(wolke[i][yPos] < -10){
      wolke[i][yPos] = koord[hoehe] + random(1, koord[hoehe]) /2;
      wolke[i][bouncer] = 0;
    }
    */
    wolke[i][yPos] = getY(i);   //   Funktion getY gibt ywert durch, neue ywert für jeden tropfen   FALLENDER TROPFEN
    //Serial.println(wolke[0][yPos]);
  }

  //   Zählt von oben nach unten die Zeilen durch (k = kathoden)
  for(int k = 0; k < 8; k++){

  //   Zählt Spalten durch (a = Anoden)  
    for(int a = 0; a < 8; a++){
      if(wolke[a][yPos] *raster /koord[hoehe] - k == 0){ //   BERECHNUNG: yPos Pixel wird einem wert von 0 - 7 zugewiesen   -K: in welcher zeile befinden wir uns
        switchLED(1, a, 7 - k);
      }
    }

    //   ???
    delayMicroseconds(100);
    //delay(100);

    for(int a = 0; a < 8; a++){
      switchLED(0, a, 7 - k);
    }
  }

}

//   Funktion zum An- und Ausschalten der LEDs
void switchLED(int LEDstat, int anode, int kathode){
  switch(LEDstat){
    case 0:    //  Diode aus
      digitalWrite (an[anode], LOW);
      digitalWrite (kat[kathode], HIGH);
    break;
    case 1:    //  Diode an
      digitalWrite (an[anode], HIGH);
      digitalWrite (kat[kathode], LOW);
    break;
  }
}

int getY(int i){

  wolke[i][bouncer]++;             // Mit jedem Durchlauf wird der Bouncer u 1 erhöht -> Wird mit Beschl. mulltipliziert
  int tempY = wolke[i][yPos];      // Auslesen des y-Wertes der Kreise in eine verwertbare Variable

  if(tempY <= 0 && wolke[i][bouncer] > 25){
    wolke[i][bouncer] = wolke[i][bouncer] * -1 * elast;
  }

  tempY = constrain(tempY - beschleunigung * wolke[i][bouncer] /framesPerSecond,0,koord[hoehe]-1) ;   //   constrain
  Serial.println(wolke[i][yPos] - tempY);
  return int(tempY);
}

Neben zwei Ausführungen der grundlegenden Hardware (Erläuterung und Bau siehe Artikel „Hardware & Software Sketching | Was ist eine LED-Matrix ) benötigt die Pixelschubse jeweils einen Beschleunigungssensor pro Gehäuse, der die Bewegungen übersetzt. Also wurde nach dem Bau zunächst der Beschleunigungssensor mit Hilfe des Arduinos usgelesen und versucht, den Wert zu Glätten, um dann mit ihm einen Pixel exemplarisch auf der Matrix zu steuern. Verwendet wurden zwei Beschleunigungssensor des Typen MMA7341L 3-Achsen. Diese wurden so verlötet, dass die Stromversorgung sowie der Selftest mit dem 3,3 V Pin des Arduinos verbunden werden können. Beide GND-Anschlüsse wurden mit dem GND-Pin des Mikrocontrolers verbunden. Da wir für das spätere Hin- und Herkippen der Pixel nur die Werte von zwei Achsen benötigen, gehen der X- und der Y-Achsenwert jeweils in einen analogen Eingang, die Z-Achse wird außer Acht gelassen.

Im folgenden ein Programmschnipsel der ersten Smoothing-Versuche. Hier ist es möglich mit Hilfe des Integers „numReadings“ den geglätteten Wert zu beeinflussen. Je größer die Zahl, desto mehr ausgelesene Werte werden zusammengezählt und zu einem arithmetischen Mittelwert verrechnet.

const int numReadings = 5;        //Anzahl an Werten, die zusammengezählt werden
int readingsX[numReadings];      // Werte vom analogen Input X
int readingsY[numReadings];      // Werte vom analogen Input Y

  //SMOOTHING
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
    readingsX[thisReading] = 0; 

  for (int thisReading = 0; thisReading < numReadings; thisReading++)
    readingsY[thisReading] = 0; 
}

Im nächste Schritt ging es darum, mit Hilfe des ausgelesenen Beschleunigungssensors die Matrix zu manipulieren. Dazu wurde die angedachten vielen Pixel zunächst auf einen Pixel reduziert. Dieser Pixel sollte mit Hilfe des Sensors über die Matrix bewegt werden, bzw. mit ihm sollte die Position der LED bestimmt werden, die leuchten. Die physische Eigenschaften wurden im Anschluss Programmiert. Somit konnte der Pixel nicht nur bewegt, sondern auch „geschüttelt“ werden, denn durch das Schütteln der Matrix hat der leuchtende Pixel die Geschwindigkeit und Richtung der Bewegung aufgenommen und springt dadurch in der Matrix hin und her.

Größte Herausforderung war dann die beiden Matrizen miteinander zu verbinden, und den Pixel von einer in die andere zu übertragen. Eine Zwischenzeitliche Überlegung, wie es gelingen könnte, den Pixel haargenau an der gleichen Position von der einen in die andere Matrix hineinfallen zu lassen, war mit Magneten und Magnetschaltern zu arbeiten: Pro Doppelzeile LEDs wäre ein Magnetschalter angebracht worden, sowie jeweils zwei Magnete an den oberen beide Ecken der Matrizen. Wäre dann die eine Matrix über die andere gehalten worden und in einem bestimmten Abstand zu ihr der Pixel übertragen worden wäre, wäre er genau an der Stelle in die zweite Matrix gefallen, an der sich die Ecke der ersten Matrix befunden hätte.

Von dieser Lösung wurde abgesehen, da der Effekt nur dann eintreten würde, wenn beide Matrizen nah genug aneinander gehalten würden. Um die Interaktion für den Nutzer zu vereinfachen, kann er im Endmodell den Pixel beliebig von Matrix zu Matrix kippen, er fällt stets am Rand hinein. Die beiden fertigen Programme sehen folgendermaßen aus:

/*
Hochschule Magdeburg Stendal
Master Interaciton Design

Hardware and Software Sketching 
Sommersemester 2012
Betreuung durch Prof. Dr. Christine Goutrié
                Dipl. Ing. Jörg Schröder
Tutor           Stephan Fink

Pixelschubse
MATRIX 1 
Janine Perkuhn

*/
#define  NUM_TLCS  1                             // Anzahl der kaskadierten TLC5940 ; in unserem Fall 1
#define  NUM_ROWS  4                             // Anzahl der Zeilen, die durch die Treibertransistoren auf dem Shield bestimmt wird ( 8 Zeilen --> 8  , 9 Zeilen --> 9 )

#include "Tlc5940Mux.h"                          // Library einbinden
#include <Wire.h>

unsigned long time;
int xSvalue;
int xVal;
int ySvalue;
int yVal;
int tempValue;
int halfRage;
int eingang;
boolean aktiv = true;

///////////////  Konfiguration  ///////////////////

const int zeile[]={4,6,5,2};                // Zuordnungsmatrix der Arduinopins zu den Zeilen  (Zeile 1 = 8, Zeile 2 = 7 , usw) 

#define xSensor A0
#define ySensor A1

#define rageMin 220
#define rageMax 420

/////////////////  TLC  //////////////////////////////////

volatile uint8_t isShifting;
uint8_t shiftRow;                                // aktuelle zu übertragende Zeile 

ISR(TIMER1_OVF_vect)                             // Inerruptroutine zur übertragung der Daten aus der logischen Matrix auf die physische LED-Matrix
{
  if (!isShifting) {                             // wenn Variable isShifting = LOW
    disable_XLAT_pulses();                       // Datenübernahmeimpuls für TLC -> ausschalten   // TCCR1A = _BV(COM1B1)
    isShifting = 1;                              // Variable isShifting = HIGH
    sei();                                       // globalen Interupt wieder einschalten
    if(shiftRow == 0) {                          // wenn die erste Zeile die altuelle Zeile ist
      digitalWrite(zeile[NUM_ROWS-1], HIGH);     // letzten Zeilentreiber ausschalten
    }
    else digitalWrite(zeile[shiftRow -1], HIGH); // vorherige LED-Zeile ausschalten      
    TlcMux_shiftRow(shiftRow);                   // Daten der aktuellen Zeile aus dem Array an den TLC5940 übertragen (Variable shiftRow wird nicht verändert
    digitalWrite(zeile[shiftRow], LOW);          // aktuzelle LED-Zeile einschalten und Zeilenzähler erhöhen
    shiftRow++;
    if (shiftRow == NUM_ROWS) {                  // Wenn die letzte Zeile erreicht wurde
      shiftRow = 0;                              // dann Zeilenzähler rücksetzen
    }
    enable_XLAT_pulses();                        // Datenübernahmeimpuls für TLC wieder zulassen   // TCCR1A = _BV(COM1B1)
    isShifting = 0;
  }
}

void setup(){

  //Serial.begin(115200);

  Wire.begin(0); // Start I2C Bus
  Wire.onReceive(receiveEvent); // register event

  TlcMux_init();                                           // Initialisierung des TLC5940
  for (int i=0; i < NUM_ROWS; i++){                        // alle Zeilentreiber ... 
   pinMode(zeile[i], OUTPUT);                              // ... als Ausgang definieren und ...
   digitalWrite(zeile[i] , HIGH);                          // ... inaktiv schalten  
  }
  TlcMux_clear();                                          // ganze Matrix löschen  

  xSvalue = 400;
  ySvalue = 400;

  halfRage = (rageMax - rageMin) * 0.5;
}

void loop(){
  if(aktiv){
    readSensor();
    playBall();
  }
}

void playBall(){

  if(aktiv){

  switchLED(0, int(ySvalue*0.008), 7 - int(xSvalue*0.007));
  switchLED(4095, int(yVal*0.008), 7 - int(xVal*0.007));

    //switchLED(0, ySvalue*0.008 + 1, 7 - xSvalue*0.006);
    /*switchLED(0, ySvalue*0.008, 7 - xSvalue*0.006);
    switchLED(0, ySvalue*0.008 + 1, 7 - xSvalue*0.006 - 1);
    switchLED(0, ySvalue*0.008, 7 - xSvalue*0.006 - 1);*/
    //switchLED(4095, yVal*0.008 + 1, 7 - xVal*0.006);
    /*switchLED(4095, yVal*0.008, 7 - xVal*0.006);
    switchLED(4095, yVal*0.008 + 1, 7 - xVal*0.006 - 1);
    switchLED(4095, yVal*0.008, 7 - xVal*0.006 - 1);*/
    xSvalue = xVal;
    ySvalue = yVal;
    xVal = 7 - int(xVal*0.007);
    yVal = int(yVal*0.008);

    if(yVal > 7){
      //Serial.println("hups");
      Wire.beginTransmission(1); // transmit to device #9
      Wire.write(xVal);              // sends x 
      Wire.endTransmission();    // stop transmitting
      aktiv = false;
    }
  }
}

void readSensor(){

  tempValue = analogRead(xSensor);
  tempValue = constrain(tempValue, rageMin, rageMax) - rageMin;
  tempValue = xSvalue + (tempValue - halfRage)*0.02;
  xVal = constrain(tempValue, 0, halfRage*10);

  tempValue = analogRead(ySensor);
  tempValue = constrain(tempValue, rageMin, rageMax) - rageMin;
  tempValue = ySvalue + (tempValue - halfRage)*0.02;
  yVal = constrain(tempValue, 0, halfRage*10);
  Serial.println(7 - int(xVal*0.007));
}

void switchLED(int LEDstat, int zeile, int spalte){

  if(zeile >= 4){
    zeile = zeile -4;
    spalte = spalte + 8;
  }
  TlcMux_set(zeile, spalte, LEDstat);
}

void receiveEvent(int howMany) {
  eingang = Wire.read();    // receive byte as an integer
  xSvalue = (7 - eingang) * 1000;
  aktiv = true;
}
/*
Hochschule Magdeburg Stendal
Master Interaciton Design

Hardware and Software Sketching 
Sommersemester 2012
Betreuung durch Prof. Dr. Christine Goutrié
                Dipl. Ing. Jörg Schröder
Tutor           Stephan Fink

Pixelschubse
MATRIX 2 
Janine Perkuhn

*/

#define  NUM_TLCS  1                             // Anzahl der kaskadierten TLC5940 ; in unserem Fall 1
#define  NUM_ROWS  4                             // Anzahl der Zeilen, die durch die Treibertransistoren auf dem Shield bestimmt wird ( 8 Zeilen --> 8  , 9 Zeilen --> 9 )

#include "Tlc5940Mux.h"                          // Library einbinden
#include <Wire.h>

unsigned long time;
int xSvalue;
int xVal;
int ySvalue;
int yVal;
int tempValue;
int halfRage;
int eingang;
boolean aktiv = true;

///////////////  Konfiguration  ///////////////////

const int zeile[]={4,6,5,2};                // Zuordnungsmatrix der Arduinopins zu den Zeilen  (Zeile 1 = 8, Zeile 2 = 7 , usw) 

#define xSensor A0
#define ySensor A1

#define rageMin 220
#define rageMax 420

/////////////////  TLC  //////////////////////////////////

volatile uint8_t isShifting;
uint8_t shiftRow;                                // aktuelle zu übertragende Zeile 

ISR(TIMER1_OVF_vect)                             // Inerruptroutine zur übertragung der Daten aus der logischen Matrix auf die physische LED-Matrix
{
  if (!isShifting) {                             // wenn Variable isShifting = LOW
    disable_XLAT_pulses();                       // Datenübernahmeimpuls für TLC -> ausschalten   // TCCR1A = _BV(COM1B1)
    isShifting = 1;                              // Variable isShifting = HIGH
    sei();                                       // globalen Interupt wieder einschalten
    if(shiftRow == 0) {                          // wenn die erste Zeile die altuelle Zeile ist
      digitalWrite(zeile[NUM_ROWS-1], HIGH);     // letzten Zeilentreiber ausschalten
    }
    else digitalWrite(zeile[shiftRow -1], HIGH); // vorherige LED-Zeile ausschalten      
    TlcMux_shiftRow(shiftRow);                   // Daten der aktuellen Zeile aus dem Array an den TLC5940 übertragen (Variable shiftRow wird nicht verändert
    digitalWrite(zeile[shiftRow], LOW);          // aktuzelle LED-Zeile einschalten und Zeilenzähler erhöhen
    shiftRow++;
    if (shiftRow == NUM_ROWS) {                  // Wenn die letzte Zeile erreicht wurde
      shiftRow = 0;                              // dann Zeilenzähler rücksetzen
    }
    enable_XLAT_pulses();                        // Datenübernahmeimpuls für TLC wieder zulassen   // TCCR1A = _BV(COM1B1)
    isShifting = 0;
  }
}

void setup(){

  //Serial.begin(115200);

  Wire.begin(0); // Start I2C Bus
  Wire.onReceive(receiveEvent); // register event

  TlcMux_init();                                           // Initialisierung des TLC5940
  for (int i=0; i < NUM_ROWS; i++){                        // alle Zeilentreiber ... 
   pinMode(zeile[i], OUTPUT);                              // ... als Ausgang definieren und ...
   digitalWrite(zeile[i] , HIGH);                          // ... inaktiv schalten  
  }
  TlcMux_clear();                                          // ganze Matrix löschen  

  xSvalue = 400;
  ySvalue = 400;

  halfRage = (rageMax - rageMin) * 0.5;
}

void loop(){
  if(aktiv){
    readSensor();
    playBall();
  }
}

void playBall(){

  if(aktiv){

  switchLED(0, int(ySvalue*0.008), 7 - int(xSvalue*0.007));
  switchLED(4095, int(yVal*0.008), 7 - int(xVal*0.007));

    //switchLED(0, ySvalue*0.008 + 1, 7 - xSvalue*0.006);
    /*switchLED(0, ySvalue*0.008, 7 - xSvalue*0.006);
    switchLED(0, ySvalue*0.008 + 1, 7 - xSvalue*0.006 - 1);
    switchLED(0, ySvalue*0.008, 7 - xSvalue*0.006 - 1);*/
    //switchLED(4095, yVal*0.008 + 1, 7 - xVal*0.006);
    /*switchLED(4095, yVal*0.008, 7 - xVal*0.006);
    switchLED(4095, yVal*0.008 + 1, 7 - xVal*0.006 - 1);
    switchLED(4095, yVal*0.008, 7 - xVal*0.006 - 1);*/
    xSvalue = xVal;
    ySvalue = yVal;
    xVal = 7 - int(xVal*0.007);
    yVal = int(yVal*0.008);

    if(yVal > 7){
      //Serial.println("hups");
      Wire.beginTransmission(1); // transmit to device #9
      Wire.write(xVal);              // sends x 
      Wire.endTransmission();    // stop transmitting
      aktiv = false;
    }
  }
}

void readSensor(){

  tempValue = analogRead(xSensor);
  tempValue = constrain(tempValue, rageMin, rageMax) - rageMin;
  tempValue = xSvalue + (tempValue - halfRage)*0.02;
  xVal = constrain(tempValue, 0, halfRage*10);

  tempValue = analogRead(ySensor);
  tempValue = constrain(tempValue, rageMin, rageMax) - rageMin;
  tempValue = ySvalue + (tempValue - halfRage)*0.02;
  yVal = constrain(tempValue, 0, halfRage*10);
  Serial.println(7 - int(xVal*0.007));
}

void switchLED(int LEDstat, int zeile, int spalte){

  if(zeile >= 4){
    zeile = zeile -4;
    spalte = spalte + 8;
  }
  TlcMux_set(zeile, spalte, LEDstat);
}

void receiveEvent(int howMany) {
  eingang = Wire.read();    // receive byte as an integer
  xSvalue = (7 - eingang) * 1000;
  aktiv = true;
}

Pixelschubse | Konzeptvarianten

Auf der Grundlage der 8×8-LED-Matrix wurden neben der realisierten Pixelschubse unterschiedlichste Konzepte entwickelt, die darauf abzielen, das Potential der Verbindung von Bits und Atomen aufzuzeigen. Die entstandenen Hard- und Software-Sketches führten teils durch grafischer Ausarbeitung, oftmals aber besonders durch schnell entstandene Prototypen zu Erkenntnissen in Bezug auf das Potential und die Umsetzbarkeit der Ideen.

„Light Sketching“ basiert auf der Idee spielerisch durch einen Laserpointer oder den eigenen Finger mit der Matrix zu interagieren. Technische Grundlage dafür ist die Idee, einfache LEDs als Photodioden zu verwenden. So dient sie nicht nur Aktor, sondern auch als Sensor, denn zum einen ist die LED Lichtquelle, zum anderen der Empfänger, der die einfallende Lichtintensität misst und darauf reagiert. Somit wäre es denkbar, den Zustand der einzelnen LEDs der Matrix entweder durch verdecken mit dem Finger oder durch Anstrahlen mit dem Lichtpunkt des Lasers zu verändern.

„Weatherman“ ist ein Konzept, dass die 8×8-LED-Matrix als Wetteranzeige nutzt. Mit Hilfe von unterschiedlichen Sensoren aber auch Ventilatoren oder Mikrophonen soll der Interagierende verschiedene Werte abrufen können: Trendangaben über Windgeschwindigkeit, Niederschlagswahrscheinlichkeit und Temperaturangaben sollen dargestellt werden. Die Informationen könnten via Processing von einer Onlinedatenplattform eingelesen werden. Die Herausforderung liegt zudem in der grafischen Darstellung der Information: Wie lassen sich Wind und Wetter auf 8×8 Pixel darstellen?

„Time Code“ ist ein Konzept, bei dem auf 8×8 LEDs die aktuelle Uhrzeit alternativ dargestellt wird. Nicht als Digitalanzeige soll das grobe Display dienen, sondern eine abstrakte, grafische Darstellung visualisieren. Es ist angedacht, dass Stunden, Minuten und zumindest ein Sekundentakt wiedergegeben werden. Der Nutzer soll die Time-Code-Matrix aber auch als Wecker nutzen können. Daher gilt es sich ein Interaktionskonzept auszudenken, dass du der reduzierten Erscheinung passt.

Das Konzept „Installation“ überträgt das Thema der generativen Gestaltung auf die 8×8-LED-Matrix. Durch diverse Sensoren kann eine zufällig generierte Form oder ein Rhythmus manipuliert werden. Dabei tritt der „Nutzer“ vielleicht nur durch Zufall mit der Matrix in Interaktion. Die entstehenden Muster oder Animationen sollten so spannend sein, dass der Interagierende gefesselt wird. Es handelt sich hierbei um ein Konzept, dass in diesen Dimensionen nur als exemplarisch anzusehen ist und bei einer Umsetzung als größer dimensionierte Installation im öffentlichen Raum gedacht ist.

Pixelschubse | Essay: “Atoms+Bits=the neue Craft”

„Atoms + Bits = The neue Craft“ ist die Formel, die der Interactiondesigner und Informatiker John Maeda im Rahmen des Adobe Museum of Digital Media aufstellt und erläutert. Laut ihm gibt es zwei Welten, die der Atome und die der Bits. Wir leben in und gestalten diese beiden Welten. Mit Hilfe von Wissenschaft, Technologie und Design können wir eine Brücke zwischen Atomen und Bits schlagen und Innovationen schaffen. Die daraus resultierende Summe, das Potential, nennt Maeda „The neue Craft“.

Für uns ist das Ergebnis dieser Formel teil unseres alltäglichen Lebens. Bits sind genauso präsent wie Atome und verschmelzen unbemerkt in Arbeitsprozessen miteinander: Ein digitales Foto bestehend aus zig Pixeln wird gedruckt und durch seine physische Form zu greifbaren Atomen. Andersherum sehen wir die Natur, einen Menschen, ein Objekt, fangen dieses mit Hilfe einer Kamera ein und übertragen das gerade noch Physische in die digitale Welt. Doch schon das digitale Foto ist genaugenommen ein Hybrid und kein einzelnes Formelelement. Es schlägt bereits die Brücke zwischen Virtuellem und Physischem, denn letztlich sorgt erst die Dekodierung durch ein Rechnersystem dafür, dass die einzelnen Pixel, die wiederum nur aus vielen Einsen und Nullen bestehen, für das menschliche Auge auf einem Monitor sichtbar und somit zur sinnvollen Summe werden.

Die Anwendung der Formel ist also ein Dekodierungsprozess dessen Hauptakteure Informatiker und Interactiondesigner sind. Sie jonglieren mit Bits und Atomen und versuchen mit Hilfe spezieller Werkzeuge – Computerprogrammen, Sensoren und Aktoren – sinnige Rückverbindungen zu schaffen. Dieser Prozess ist in unterschiedlichsten Formen in ständigem Gange: Täglich werden physische Objekte zu Code, zu Rohmaterial, neu geformt und tauchen in virtueller Form auf einem Bildschirm im Taschenformat wieder auf. Oftmals können die entstehenden mobilen Anwendungen tatsächlich unseren Alltag bereichern, teilweise gehen bei der Dematerialisierung, der Übertragung ins Virtuelle, jedoch Eigenschaften verloren, die nicht nachgeahmt werden können. Doch selbst bei gelungenen Beispielen stellt sich die Frage, wie innovativ die Summe dieser Zitationen realer Objekten ist? Und steckt in ihnen tatsächlich die von Maeda beschriebene „Neue Craft“?

Damit Maedas Rechnung aufgeht sind Entwickler und Gestalter angehalten mehr zu tun, als zu zitieren. Denn auch wenn das Ergebnis solcher digitaler Reproduktionen oftmals zu Überraschungen führt, steckt noch viel unausgeschöpftes Potential im experimentieren mit den rohen Formelelementen. Durch kreative Prozesse und Arbeitsmethoden können gewollte aber auch zufällige Ergebnisse geschaffen werden, die inspirieren und zu neuen, innovativen Lösungen führen. Eine Idee baut auf der anderen auf und eröffnet gerade in solch unbeschrittenen Gebieten neue Wege. Doch gilt es gerade in einem solchen quantitativen Prozess Ergebnisse zu hinterfragen und gute Ideen von Möglichkeiten zu differenzieren, denn auch hier ist nicht alles, was machbar ist auch sinnvoll. Es gilt also weiter zu addieren, Produkte in experiemntiellen Prozessen zu erzeugen und mit gesunder Kritik bewusste Entscheidungen zu treffen und somit verantwortlicher zu gestalten und die „neue Craft“ in Maedas Sinne auszuschöpfen und zu vermitteln.

Quelle: http://tv.adobe.com/watch/adobe-museum-of-digital-media/john-maeda, Februar 2011, [21.06.2012]

Pixelschubse | Analoge Pixelbilder 2D

Die folgenden analog produzierten Pixelbilder werden oft nicht wirklich als solche wahrgenommen. Die verwendeten Formen, Objekte und Materialien setzen es in einen ungewohnten Kontext, in dem man nicht mit ihm rechnet. Zudem wirken die einzelnen Bildelemente durch die menschliche Ungenauigkeit nicht wie ein akkurat gerastertes Bild.

 

Fineliner: Feinste schwarze Punkte auf einem Blatt Papier simulieren durch Variation in ihrer Dichte Graustufen. Fingerabdrucke: Ein Fingerabdruck wird zum Pixel, wobei jeder Bildpunkt individuell ist und in seiner Größe und Form variiert. Ringe: Ist der Pixel eines Bildes größer als das zugrunde liegende Raster, so überschneiden sich die einzelnen Bildelemente.

Pixelschubse | Analoge Pixelbilder 3D

Lorem ipsum…

Sandkorn: Auch ein Sandkorn kann ein Pixel darstellen. Die Körner sind so fein und dicht beieinander, dass sie nicht mehr als einzelnes Element wahrgenommen werden. Sticken: Der Prozess des Stickens basiert auf dem sehr feinen Raster des Textils, dessen einzelne Rasterpunkte mit der Farbe des Garns gefüllt werden. Nägel: Der Kopf eines Nagels ist ein runder Pixel. Unterschiedliche Nägelköpfe in unterschiedlichen Höhen lassen dreidimensionale Strukturen entstehen.

Pixelschubse | Digitale Pixelbilder

Digitale Rastergrafiken werden selbst in geringer Auflösung durch ihre Darstellungsform als Pixelbild wahrgenommen. Sie unterscheiden sich besonders darin, dass sie dynamisch verändert werden können: Farbe, Pixelform und -dimension können mit Hilfe von Processing bestimmt und stetig angepasst werden. Die Ergebnisse zeigen teilweise überraschende Darstellungen.

Copic: Ein Copic-Deckel stellt einen Pixel dar. Die Farbwerte der Rastergrafik hängen dann von der Variation der Copics ab. Hier: Schwarz-Weiß, Graustufen, Farbe. Diese digitale Darstellung ist noch nicht dynamisch.

Dynamische Pixelkreise: Via Processing können Bilder gerastert und alternativ dargestellt werden. Hier ist als Pixel ein Kreis verwendet worden, der durch eine unterschiedliche Rasterauflösung in Verbindung mit Transparenz interessante Überschneidungen ergibt und dadurch neue Formen entstehen lässt.

Pixelschubse | Ausblick

Der Spielraum 8×8 Pixel bietet mehr spannende Interaktionsmöglichkeiten als zunächst angenommen. Das zeigt die Konzeptvielfalt, als auch die Variationsmöglichkeiten des umgesetzten Entwurfs. Das Potential der Pixelschubse liegt sowohl in der Weiterentwicklung des Details, als auch in der Übertragung in unterschiedliche Szenarien.

Interessant ist die Wirkung des Pixelschubsen, wenn es sich um mehr als nur ein Element handelt aber auch, wenn sich die Eigenschaften der Elemente ändern: Wie verhält sich eine Masse von simulierten physischen Pixeln, die aufeinander Einfluss nehmen? Wie wirkt die Masse, wenn sich die Gravitationskraft verändert? Wie unterscheiden sich die Eigenschaften von elastischen Pixeln, leichten und schweren Pixeln? Was passiert mit zerbrechlichen Pixelformationen? Durch die Darstellung unterschiedlichster physikalischer Regeln bekommt die Matrix musealen Charakter.

 

14.05.2013 | Janine Perkuhn |