Arduino Sketch

Nachfolgend wird der verwendete Arduino sketch beschrieben

Der Sketch

/***********************/
/*        PINS         */
/***********************/
// Ultraschall
const int echoPin = 8;
const int trigPin = 9;
// Piezo
const int piezoPin[2] = { A0, A1 };
// Button
const int buttonPin = 2;
const int buttonLedPin = 3;

// Matrix
// Output Pins
const int PO_[4] = { 22, 24, 49, 47 };
// Input Pins
const int PI_[16] = { 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 53, 51 };

/***********************/
/*        VARIABLEN    */
/***********************/
// Matrix Werte
// 120 = single 20, 220 = double 20, 320 = triple 20
// 125 = single Bull, 225 = doppel bull
// 4x16 = 64, aber nur 62 Zahlenwerte, deshalb kommt zweimal 000 vor
// usw..
const int FAKTOR_WERTE[4][16]={
	{212, 112, 209, 109, 214, 114, 211, 111, 208, 108, 000, 312, 309, 314, 311, 308},
	{216, 116, 207, 107, 219, 119, 203, 103, 217, 117, 225, 316, 307, 319, 303, 317},
	{202, 102, 215, 115, 210, 110, 206, 106, 213, 113, 125, 302, 315, 310, 306, 313},
	{204, 104, 218, 118, 201, 101, 220, 120, 205, 105, 000, 304, 318, 301, 320, 305}
};

bool bI[4][16];
bool bHitDetected = false;
const int iHitPause = 300;
unsigned int iLastThrow = 0;

// Piezo
int wert[2] = { 0, 0 };
int schwelle = 20;
bool bFehlwurf = false;
// Button
int buttonState = 0;
// Ultraschall
long duration;
int distance;
int ultraschwelle = 0;
bool bUsAn = false;
bool bBewegungErkannt = false;
bool bSchwelleDefiniert = false;
// Input String von PI zu Arduino
String inputString = "";
boolean stringComplete = false;
//
int wurfanzahl = 0;

/***********************/
/*       FUNKTIONEN    */
/***********************/
void Ultraschall() {
	/* Ultraschall */
	// trigPin frei machen
	digitalWrite(trigPin, LOW);
	delayMicroseconds(2);
	// trigPin an für 10 micro secs
	digitalWrite(trigPin, HIGH);
	delayMicroseconds(10);
	digitalWrite(trigPin, LOW);
	// Lesen des Echo Pins
	duration = pulseIn(echoPin, HIGH);
	// Berechnung der Entfernung
	distance = duration*0.034/2;
	// Prüfen ob sich jemand genähert hat
	if (distance > ultraschwelle) {
		// Bislang ausgabe Seriell
		Serial.println("PFEILE");
	}
}

int UltraschallMessen() {
	/* Ultraschall */
	// trigPin frei machen
	digitalWrite(trigPin, LOW);
	delayMicroseconds(2);
	// trigPin an für 10 micro secs
	digitalWrite(trigPin, HIGH);
	delayMicroseconds(10);
	digitalWrite(trigPin, LOW);
	// Lesen des Echo Pins
	duration = pulseIn(echoPin, HIGH);
	// Berechnung der Entfernung
	distance = duration*0.034/2;
	// Delay
	delay(100);
	// Entfernung zurückgeben
	return distance;
}

void checkButton() {
	/* Button */
	// Button einlesen
	buttonState = digitalRead(buttonPin);
	// Wenn gedrückt Ausgabe
	if (buttonState == LOW) {
		Serial.println("KNOPF");
		delay(500);
	}
}


void WurfSchicken(int x, int y) {
	Serial.println(FAKTOR_WERTE[x][y]);
	delay(iHitPause);
	bHitDetected = true;
	// Zur Sicherheit - Bulls auf NULL
	bI[1][10] = 1;
	bI[2][10] = 1;
}

void WurfAuswerten() {
	/* Matrix */
	bHitDetected = false;

	// Reihe 0-3 auslesen in Bool Array
	for (int x=0; x<4; x++) {
		digitalWrite(PO_[0], HIGH);
		digitalWrite(PO_[1], HIGH);
		digitalWrite(PO_[2], HIGH);
		digitalWrite(PO_[3], HIGH);
		digitalWrite(PO_[x], LOW);

		for (int y=0; y<16; y++) {
			bI[x][y]  = digitalRead(PI_[y]);
			// Wenn getroffen dann
			if (bI[x][y] == 0) {
				WurfSchicken(x, y);
			}
		}
	}
}

void FehlwurfErkennen() {
	/* Piezo */
	// Fehlwurf auf false setzen
	bFehlwurf = false;

	// Piezos in Schleife auslesen
	for (int i = 0; i < 2; i++) {
		// Zweifach auslesen um Störungen zu minimieren
		wert[i] = analogRead(piezoPin[i]);
		wert[i] = analogRead(piezoPin[i]);

		if (wert[i] >= schwelle) {
			bFehlwurf = true;
		}
	}

	// Wenn kein Wurf erkannt wurde ist es ein Fehlwurf
	if (!bHitDetected) {
		if (bFehlwurf) {
			// Bislang nur Ausgabe
			Serial.println("FEHLWURF");
			delay(200);
		}
	}
}

void Blinken(int Anzahl) {
	for (int i=0; i<Anzahl; i++) {
		digitalWrite(buttonLedPin, HIGH);
		delay(250);
		digitalWrite(buttonLedPin, LOW);
		delay(250);
	}
}

void SchwelleDefinieren() {
	int abstand = UltraschallMessen();
	ultraschwelle = abstand + 3;
	bSchwelleDefiniert = true;
}

void ReagiereAufSerialString() {
	if ( inputString.indexOf("BAN") != -1) {
		digitalWrite(buttonLedPin, HIGH);
		bUsAn = true;
		SchwelleDefinieren();
	} else if (inputString.indexOf("BAUS") != -1) {
		digitalWrite(buttonLedPin, LOW);
		bUsAn = false;
		bBewegungErkannt = false;
		bSchwelleDefiniert = false;
	} else if (inputString.indexOf("PERK") != -1) {
		bBewegungErkannt = true;
	} else if (inputString.indexOf("NEXT") != -1) {
		bSchwelleDefiniert = false;
	}
	inputString = "";
	stringComplete = false;
}

/***********************/
/* Die einzelnen Loops */
/***********************/

/* Setup loop */
void setup() {
	// Pins für Ultraschall
	pinMode(trigPin, OUTPUT);
	pinMode(echoPin, INPUT);
	// Pin für Button
	pinMode(buttonPin, INPUT_PULLUP);
	// Pin für Button LED
	pinMode(buttonLedPin, OUTPUT);
	digitalWrite(buttonLedPin, LOW);
	// Matrix
	for (int i=0; i<4; i++) {
		pinMode(PO_[i], OUTPUT);
	}

	for (int i=0; i<16; i++) {
		pinMode(PI_[i], INPUT_PULLUP);
	}

	// Button blinken lassen
	Blinken(3);
	// Beginne serielle Übertragung an PC
	Serial.begin(9600);
}

/* Main loop */
void loop() {
	if (!bUsAn) {
		WurfAuswerten();
		FehlwurfErkennen();
		checkButton();
	} else if (bUsAn) {
		if (bSchwelleDefiniert) {
			checkButton();
			if (!bBewegungErkannt) {
				Ultraschall();
			} else {
				Blinken(1);
			}
		} else {
			SchwelleDefinieren();
		}
	} else {
		Serial.println("Error in Main Loop");
	}

	if(stringComplete)
		ReagiereAufSerialString();
}

/* Für die Kommunikation von PI zu Arduino */
void serialEvent() {
  while (Serial.available()) {
    char inChar = (char)Serial.read();
    inputString += inChar;
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
}

PINS

In diesem Abschnitt des Sketches werden die Pin Definitionen gemacht. Wie unter Pinbelegung zu erkennen ist definiere ich hier Die Ultraschall Pins (echo = 8, trigger = 9), die PiezoPins A0 und A1 als array, den Button Pin 2 und den Button LED Pin 3, sowie die Output und Input Pins der Matrix.

VARIABLEN

In diesem Abschnitt des Sketches werden unterschiedliche Variablen definiert. Sicherlich am interessantesten ist die Definition der Wertematrix für das Auslesen des Matrix als zweidimensionales Array.

FUNKTIONEN

Nachfolgend werden die Funktionen des Sketches beschrieben.

Ultraschall()

In dieser Funktion wird der Ultraschall Sensor ausgelesen. Zuerst wird der Sensor durch aus- und anschalten frei gemacht, dann wird eine Dauer des Echos ermittelt und so verrechnet, dass sich eine Abstandseinheit in cm ergibt. Unterschreitet dieser Abstand eine Schwelle, so hat der Spieler seine Pfeile geholt und auf der seriellen Konsole wird das Wort “PFEILE” geschrieben. Danach erfolgt eine Wartezeit.

checkButton()

In dieser Funktion wird der Knopf ausgelesen. Wird er gedrückt wird das Wort “KNOPF” auf der seriellen Konsole geschrieben. Es erfolgt eine Wartezeit.

WurfSchicken(int x, int y)

In dieser Funktion wird der ermittelte Wurf auf die serielle Konsole geschrieben. Der Funktion wird ein Wert des zweidimensionalen Matrixarrays übergeben. Dieser wird dann im Array nachgeschaut und auf die Konsole geschrieben. Außerdem wird die Variable bHitDetected (also Wurf erkannt) auf true gesetzt. Im Falle, dass ein Piezo ausgelöst wurde wird so verhindert, dass ein Fehlwurf anstatt des erkannten Wurfwertes gebucht wird.

WurfAuswerten()

In dieser Funktion wird die Matrix des Automaten ausgelesen. Hierbei wird nacheinander auf den Output Pins der Matrix ein Signal gegeben und dann auf jedem Input Pin der Matrix geprüft ob der Kontakt geschlossen ist. Ist dies der Fall wird genau dieser Wert des zweidimensionalen Matrixarrays an die Funktion WurfSchicken(int x, int y) übergeben.

FehlwurfErkennen()

In dieser Funktion werden die Piezos ausgelesen und evaluiert, ob es sich um einen Fehlwurf handelt. Dafür wird nacheinander jeder Piezo zweimal in Folge ausgelesen und wenn der ausgelesene Wert den Schwellwert übersteigt, so wird die Variable bFehlwurf auf true gesetzt. Anschließend wird geprüft, ob ein Wurf erkannt wurde anhand des Status der Variablen bHitDetected. Ist dieser false, also es wurde kein Wurf erkannt, aber bFehlwurf ist true, also ein Fehlwurf wurde erkannt so wird das Wort “FEHLWURF” auf die serielle Konsole geschrieben.

Blinken(int Anzahl)

In dieser Funktion kann der Knopf zum blinken gebracht werden. Der Funktion wird eine Anzahl für das Blinken übergeben. Dann blinkt der Knopf, indem er an- und wieder ausgeschaltet wird.

ReagiereAufSerialString()

In dieser Funktion können Befehle verarbeitet werden, die dem Arduino auf die serielle Konsole geschrieben werden. Aktuell wird geprüft, ob jemand “BAN”, “BAUS” oder “BB” schreibt. Die Abkürzungen stehen für “Button AN”, also Knopf anschalten, “Button AUS”, also Knopf ausschalten oder “Button BLINKEN”, also einmal blinken lassen mithilfe der Funktion Blinken(int Anzahl).

LOOPS

Nachfolgend werden die Loops des Programms beschrieben

Setup

Der Setup Loop wird immer beim Boot des Arduino ausgeführt, einmalig. Hier werden die einzelnen Pins als Input oder Output Pin definiert. Außerdem blinkt der Knopf dreimal mithilfe der Funktion Blinken(int Anzahl) und eine serielle Übertragung wird gestartet. Diese Übertragung wird vom Python Koppler ausgelesen und behandelt.

Main

Der Main Loop bildet praktisch einen cycle des Prozessors ab. Dieser Loop läuft unendlich lange und wird immer wieder wiederholt. Es werden hier nacheinander die Funktionen Ultraschall(), checkButton(), WurfAuswerten()und FehlwurfErkennen() ausgeführt. Anschließend wird noch geprüft, ob durch den Loop serialEvent() ein fertige String empfangen wurde. Wenn ja wird er mithilfe der Funktion ReagiereAufSerialString() ausgewertet und behandelt. Danach startet der cycle von vorne. Ein cycle benötigt ohne Wartezeiten der Funktionen etwa 20 Millisekunden.

serialEvent

In diesem Loop wird überprüft, ob auf der seriellen Konsole ein String empfangen wurde und ob dieser schon zuende geschrieben wurde (erkennbar an einem Zeilenumbruch). Dieser string wird dann in der Funktion ReagiereAufSerialString() behandelt.