1896 Tage zuvor: 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…