13. May 2012: Arduino-Senso

Als ich im letzten Jahr endlich den Open Camera Controller fertiggestellt hatte, stellte sich die Frage: Was mache ich jetzt mit meinem Arduino Eine Antwort war schnell gefunden: Einen Senso-Klon) bauen! Leider sich das Projekt dann doch wesentlich lÀnger hingezogen als gedacht. Einen nicht unwesentlichen Teil haben meine eher rostigen Elektronik-Kenntnisse dazu beigetragen. Aber nichts desto trotz ist es nun endlich vollbracht! Auch wenn es sicherlich nicht schönsten Lösung ist, hier eine simplifizierte Version meines Schaltplans.

Zum 1:1 Nachbau möchte ich so allerdings nicht raten – Pin 13 des Arduino eignet sich nicht sonderlich gut als Input (wegen der Standard Notification-LED). Und auch sollte man fĂŒr blaue LEDs einen höheren Widerstand als fĂŒr die anderen LEDs (rot, gelb und grĂŒn in meinem Fall) benutzen – sie sind schlichtweg viel zu hell!

Die Software zur Hardware war wiederum erstaunlich schnell geschrieben – lediglich wenige Stunden (intensives Testen inklusive) hat es gedauert. Ganz in Anlehnung an das Hardware-Layout ist auch der Code nicht sonderlich ansehnlich. Dennoch sei er hier vorgestellt:

/* Arduino-Senso; v1.1
   (c)2012 by Kai Boenke
   Published under CC BY-NC-SA 3.0
 */

// Define Pins
#define ledGrn 6
#define ledRed 7
#define ledBlu 8
#define ledYel 9
#define btnGrn 10
#define btnRed 11
#define btnBlu 12
#define btnYel 13

// Customizations
#define maxWait 100000
#define maxMoves 30
#define inputDelay 500

// Declare Program-internal Vars
boolean waiting; //Defines Status for loop()
int waitCounter; //Used to determine Timeouts in loop()
int moveCounter; //Defines current Move in Sequence (Sequence-Replay)
int nextCounter; //Defines curent move to be made (next move to be made)
int rndSequence[maxMoves]; //Holds complete Sequence
int ledPinMin; //Define lowest Pin
int ledPinMax; //Define highest Pin


// Intial Setup
void setup() {
  // Pinmodes
  pinMode(ledGrn, OUTPUT);
  pinMode(ledRed, OUTPUT);
  pinMode(ledBlu, INPUT); //Exploits reduced voltage to dim LED
  pinMode(ledYel, OUTPUT);
  pinMode(btnGrn, INPUT);
  pinMode(btnRed, INPUT);
  pinMode(btnBlu, INPUT);
  pinMode(btnYel, INPUT);
  
  // Determine lowest/highest LED-Pins
  ledPinMin = min(min(min(ledGrn, ledRed), ledYel), ledBlu);
  ledPinMax = max(max(max(ledGrn, ledRed), ledYel), ledBlu);
  
  // Randomness
  Serial.begin(9600);
  randomSeed(analogRead(0));
  
  // Start first Game
  initGame();
}

// Main Loop
void loop() {
  // Check for Timeout
  if(waitCounter > maxWait){
    initGame();
  }else{
    waitCounter++;
  }
  
  // Show Sequence for new Move?
  if((!waiting) && (moveCounter == 0)){
    showSequence();
  }
  
  // Read Input
  int valGrn = digitalRead(btnGrn);
  int valRed = digitalRead(btnRed);
  int valBlu = digitalRead(btnBlu);
  int valYel = digitalRead(btnYel);
  
  // Evaluate Input
  if((valGrn == HIGH) || (valRed == HIGH) || (valBlu == HIGH) || (valYel == HIGH)){
    switch(rndSequence[moveCounter]){
      case ledGrn:
        if(valGrn == HIGH){
          blink(ledGrn);
          nextTry();
        }else{
          youLoose();
        }
        break;
      case ledRed:
        if(valRed == HIGH){
          blink(ledRed);
          nextTry();
        }else{
          youLoose();
        }
        break;
      case ledBlu:
        if(valBlu == HIGH){
          blink(ledBlu);
          nextTry();
        }else{
          youLoose();
        }
        break;
      case ledYel:
        if(digitalRead(btnYel) == HIGH){
          blink(ledYel);
          nextTry();
        }else{
          youLoose();
        }
        break;
    }
  }
}


/*
   Game-Logic
 */

// Setup a new Game
void initGame(){
  // Re-Initialize
  nextCounter = 0;
  moveCounter = 0;
  waiting = false;
  waitCounter = 0;
  
  // Visualize beginning of new Game
  roundBlink(5);
  
  // Generate new Sequence
  for(int i = 0; i < maxMoves; i++){
    rndSequence[i] = random(ledPinMin, ledPinMax+1);
    delay(20); //Try to increase Randomness even more
  }
}

// Visualize Sequence
void showSequence() {
  // Customize
  int blinkDelay = 500;
  int waitDelay = 100;
  
  // Show Sequence
  resetLeds();
  for(int i=0; i<=nextCounter; i++){
    blink(rndSequence[i], blinkDelay);
    delay(waitDelay);
  }
  
  // Reset Status
  waiting = true;
}

// Advance Try after successful Move
void nextTry(){
  // Next Move in Sequence or Replay?
  if(moveCounter >= nextCounter){
    delay(inputDelay);
    blinkAll(1, 10);
    nextCounter++;
    moveCounter = 0;
  }else{
    moveCounter++;
  }
  
  // Base-Case
  if(nextCounter >= maxMoves){
    // We have a Winner!
    blinkAll(10, 10);
    initGame();
  }else{
    // Move on!
    delay(inputDelay);
    waiting = false;
  }
}

// Wrong Move
void youLoose(){
  // Visualize
  blinkAll(1, 500);
  
  // New Game
  initGame();
}


/*
   LED-Controls
 */

// Single Blink
void blink(int led){
  blink(led, 100);
}
void blink(int led, int blinkDelay){
  resetLeds();
  digitalWrite(led, HIGH);
  delay(blinkDelay);
  digitalWrite(led, LOW);
}

// Random Blink
void blinkRandom(){
  blinkRandom(1, 100, 0);
}
void blinkRandom(int loops){
  blinkRandom(loops, 100, 0);
}
void blinkRandom(int loops, int blinkDelay){
  blinkRandom(loops, blinkDelay, 0);
}
void blinkRandom(int loops, int blinkDelay, int wait) {
  resetLeds();
  for(int i = 0; i

Insgesamt hat mich dieses Projekt wesentlich mehr Nerven als Geld gekostet. Wenn man bereits ein Arduino zur Hand hat, benötigt man lediglich eine Platine, ein paar LEDs, WiderstĂ€nde sowie vier Schalter – den Rest kann man wiederverwenden. Stellt sich nur die Frage was ich jetzt mit dem Arduino anfange…