Willkommen auf unserem Seminar-Blog

Immer auf dem aktuellen Stand bleiben

Dieser Seminar-Blog befindet sich noch im Aufbau und wird in den kommenden Tagen entsprechend verfeinert.

Member Login

Lost your password?

Registration is closed

Sorry, you are not allowed to register by yourself on this site!

You must either be invited by one of our team member or request an invitation by email at viad.info {at} zhdk {dot} ch.

chameleon scales

Konzept

Die Chamäleon Scales ist eine Abstraktion einer Chamäleon Hautschuppe. Sie verfügt über die Fähigkeit Farben aufzunehmen und diese zu imitieren. Die Abstraktion besteht aus einem Holzquader mit einem matten Glasdeckel. Unter dem Deckel befindet sich eine RGB-LED, die die gemessene Farbe von der Unterseite anzeigt. Die Messung findet ebenfalls mit Hilfe einer RGB-LED und einem Helligkeitssensor statt. Es wird jeder Farbton (rot, grün, blau) einzeln vom Helligkeitssensor gemessen. Die einzelnen Werte lassen sich anschliessend auf den RGB Farbraum überragen und an die LED an der Oberseite weitergeben. Der Änderungsprozess der Farbe verläuft langsam und träge, ähnlich wie beim Tier, das die Farbe nicht innert Sekunden ändert. Dies bietet interessante Interaktionen mit mehreren Schuppen. Jede Schuppe kann eine andere Farbe repräsentieren zusammengetragen auf einer Unterlage wechseln die verschieden Farbtöne langsam zu einem Homogenen Farbton.

Prozess

Um die ganze Sache übersichtlicher zu gestalten, habe ich das Projekt in zwei Projektteile unterteilt: Farbe bestimmen und Farbe ausgeben.

Farbleser

Die Farbmessung soll mit Hilfe drei LEDs (rot, grün, blau) und einem Fotowiderstand realisiert werden. Der Fotowiderstand misst das remittierte Licht und ermittelt so den Farbton. Damit diese Messung genau und konstant ist, muss es in einem Geschützten Lichtumfeld statt finden. Für diesen Zweck habe ich einen Holzquader konstruiert, die LEDs und den Fotowiderstand integriert.

Der erste Prototyp lieferte bereits brauchbare Daten. Mittels einer Kalibration mir weissem und schwarzem Untergrund können die gelesenen Werte von 0 bis 255 gemapt werden und diese via serielle Schnittstelle über Processing am Bildschirm dargestellt werden. Die Messungen stellten sich sogar als erstaunlich genau heraus.

Das Programm änderte in diesem Zustand die Farbe ohne Verzögerung. Das Konzept sieht aber einen Langsamen Farbwechsel vor. An dieser Stelle habe ich das Skript bereits vorbereitet für den späteren Gebrauch und einen langsamen, fliessenden Farbwechsel programmiert.

Farbe ausgeben

In den Teil der Farbausgabe gehört auch die Konstruktion des zweiten Prototyps. Diesem habe ich bereits ein schöneres, eleganteres Gehäuse spendiert. Die Grösse des Gehäuses wurde so berechnet, dass die Elektronik exakt hineinpasste. Im Nachhinein stellte sich das als einen Fehlentscheid heraus, da dadurch das Debugging und optimieren des Skript sehr kompliziert wurde.

Die Ausgabe über eine RGB-LED stellte sich als knifflig heraus, da die Farben nicht so genau abgebildet wurde wie auf dem Bildschirm. Es benötigte also auch noch eine Farbkorrektur auf der "Anzeige-LED". diese Korrektur liess sich jedoch nur per Auge vornehmen. Man musste also, z.B. weiss ausgeben und schauen, ob dieses zu rot, zu blau oder zu grün ausfällt. Die Korrektur im Programm vornehmen, das Skript wieder auf den Chip laden und die Anpassung kontrollieren. Da die Farbmessung nur im geschlossenen Gehäuse funktioniert, musste die ganze Schuppe schon früh zusammengebaut werden und so weiter entwickelt werden. Das heisst, dass für jede Änderung am Skript die Schuppe komplett geöffnet werden musste, der Arduino Chip angeschlossen, das Skript hochgeladen und die Schuppe wieder zusammengebaut werden.

Zusammenspiel mehrerer Schuppen

Interessant werden die Chamäleon Skales auch, wenn sie in Kombinationen mit mehreren verwendet werden. Verschieden farbige Schuppen können zusammen auf einen homogenen Hintergrund gestellt werden und sie gleichen sich langsam aneinander an. Dies ermöglicht auch eine soziale Interaktion: Mehret Personen können z.B. verschiedene Farben "einfangen", diese zusammenbringen und langsam die Scales sich langsam aneinander anpassen lassen (siehe Video).

Fazit

Das Konstruieren der Scales war sehr interessant und vor allem lehrreich. Rückblickend würde ich möglichst spät das Produkt im definitiven Gehäuse zusammenbauen. Das vereinfacht das Testen und Optimieren des Skripts und der Komponenten erheblich! Das Zusammenbauen und Löten der Schaltung darf auf keinen Fall zu wenig Zeit beigemessen werden. Ich habe diesen Teil des Projekts stark unterschätzt. Es ist zudem wichtig von Beginn an eine sauberer Arbeitsweise anzustreben um spätere Fehler zu vermeiden.

Ausblick

Die Chameleon Scales können in desem Stadion als funktionierenden Prototypen betrachtet werden. Es bedarf aber noch einiger Optimierungen und Verbesserungen: Die Farbausgabe muss genauer werden. Es benötigt eine genauere und separate Korrektur der Farbausgabe. Die LED unter der Plexiabdeckung muss weiter nach unten verlegt werden um einen besser gestreuten Lichtkegel zu erreichen. Ich kann mir gut vorstellen diese Optimierungen noch auszuführen. Interessant dabei wäre auch die Erstellung einer gesamt Platine, auf der sich die ganze Schaltung, Akku-Ladeeinheit, LEDs und Sensoren befinden. Das würde zusätzlich Platz sparen und der Optimierung der Lichtverteilung entgegen wirken.

Chameleon Scales from Patrick Müller on Vimeo.

// Settings
int debug = 1; // 0 = kein debugging, 1 = Kalibration Messwerte, 2 = Korrigierte Messwerte, 3 = Korrigierte Ausgabewerte.

int lichtSensor = 0;
int ledReadR = 10;
int ledReadG = 9;
int ledReadB = 11;
int ledR = 5;
int ledG = 6;
int ledB = 3;

float valueR;
float valueG;
float valueB;
int readingR = 255;
int readingG = 255;
int readingB = 255;

long currentMillis = 0;
long previousMillis = 0;
long previousMillisColor = 0;
int intervalMesure = 1000;
int intervalColor = 100;
int count = 0;
boolean mesureGo = false;


void setup() {
  
  Serial.begin(9600);
  
  pinMode(ledReadR, OUTPUT);
  pinMode(ledReadG, OUTPUT);
  pinMode(ledReadB, OUTPUT);
  
  pinMode(ledR, OUTPUT);
  pinMode(ledG, OUTPUT);
  pinMode(ledB, OUTPUT);
  
  ledOff();
  
}


void loop() {
  
  currentMillis = millis();
  
  // Messung alle x Millisekunden Starten
  if (currentMillis - previousMillis > intervalMesure && analogRead(lichtSensor) < 1) {
    
    previousMillis = currentMillis;
    if(!mesureGo)
      count = 1;
    mesureGo = true;
    previousMillisColor = currentMillis;
    
  }
  
  // Farbe messen
  if (mesureGo) {
    
    switch (count) {
      case 1:
        digitalWrite(ledReadR, LOW);
        readingR = analogRead(lichtSensor);
        break;
      
      case 2:
        digitalWrite(ledReadG, LOW);
        readingG = analogRead(lichtSensor);
        break;
      
      case 3:
        digitalWrite(ledReadB, LOW);
        readingB = analogRead(lichtSensor);
    
    }
    
    // Farbinterval
    if (currentMillis - previousMillisColor > intervalColor) {
        
      previousMillisColor = currentMillis;
      ledOff();
      count++;
      
      if (count == 4) {
        count = 1;
        mesureGo = false;
        ledOff();
      }
      
    }
    
  }
  
  // Wert anpassen
  valueR = valueR * 0.992 + calibrateReadRed(readingR) * 0.008;
  valueG = valueG * 0.992 + calibrateReadGreen(readingG) * 0.008;
  valueB = valueB * 0.992 + calibrateReadBlue(readingB) * 0.008;
  
  // Neue Farbe ausgeben
  analogWrite(ledR, 255 - calibrateSendRed(valueR));
  analogWrite(ledG, 255 - calibrateSendGreen(valueG));
  analogWrite(ledB, 255 - calibrateSendBlue(valueB));
  
  // Debuggung
  switch(debug) {
    case 1:
      Serial.print("raw reading: ");
      Serial.print(readingR);
      Serial.print(",");
      Serial.print(readingG);
      Serial.print(",");
      Serial.print(readingB);
      Serial.println();
      break;
      
    case 2:
      Serial.print("corr measure: ");
      Serial.print(valueR);
      Serial.print(",");
      Serial.print(valueG);
      Serial.print(",");
      Serial.print(valueB);
      Serial.println();
      break;
      
    case 3:
      Serial.print("cor write: ");
      Serial.print(calibrateSendRed(valueR));
      Serial.print(",");
      Serial.print(calibrateSendRed(valueG));
      Serial.print(",");
      Serial.print(calibrateSendRed(valueB));
      Serial.println();
      break;
  }
  
}


int calibrateReadRed(int _read) {
  
  int _return = map(_read, 15, 73, 0, 255);
  if (_return < 0)
    _return = 1;
  if (_return > 255)
    _return = 255;
  return _return;
  
}

int calibrateReadGreen(int _read) {
  
  int _return = map(_read, 6, 49, 0, 255);
  if (_return < 0)
    _return = 1;
  if (_return > 255)
    _return = 255;
  return _return;
  
}

int calibrateReadBlue(int _read) {
  
  int _return = map(_read, 6, 49, 0, 255);
  if (_return < 0)
    _return = 1;
  if (_return > 255)
    _return = 255;
  return _return;
  
}


int calibrateSendRed(int _send) {
  
  int _return = map(_send, 0, 255, 0, 170);
  if (_return < 0)
    _return = 1;
  if (_return > 170)
    _return = 170;
  return _return;
  
}

int calibrateSendGreen(int _send) {
  
  int _return = map(_send, 0, 255, 0, 255);
  if (_return < 0)
    _return = 1;
  if (_return > 255)
    _return = 255;
  return _return;
  
}

int calibrateSendBlue(int _send) {
  
  int _return = map(_send, 0, 255, 0, 220);
  if (_return < 0)
    _return = 1;
  if (_return > 220)
    _return = 220;
  return _return;
  
}


void ledOff() {
  digitalWrite(ledReadR, HIGH);
  digitalWrite(ledReadG, HIGH);
  digitalWrite(ledReadB, HIGH);
}