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.