Skip to content

Instantly share code, notes, and snippets.

@samsch
Created December 11, 2017 15:58
Show Gist options
  • Save samsch/1174d95057e0ee701ebe1a534c929fd6 to your computer and use it in GitHub Desktop.
Save samsch/1174d95057e0ee701ebe1a534c929fd6 to your computer and use it in GitHub Desktop.
Laser Gun Module V1 (file is actually .ino, but... github)
#include <Wire.h>
#include <LSM303.h>
#include <L3G.h>
L3G gyro;
LSM303 acc;
void setup() {
pinMode(3, OUTPUT);
pinMode(4, INPUT);
pinMode(5, INPUT);
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
pinMode(12, OUTPUT);
// Serial.begin(9600);
Wire.begin();
if (!gyro.init())
{
// Serial.println("Failed to autodetect gyro type!");
while (1);
}
gyro.enableDefault();
acc.init();
acc.enableDefault();
acc.writeMagReg(0x02, 0b00000011);
acc.writeAccReg(0x23, 0b00010000);
startUpSound();
}
#define S_READY 0
#define S_FIRING 1
#define S_NEED_RELOAD 2
#define S_RELOADING 3
#define MAX_AMMO 24
#define NR_START 0
#define NR_STEP1 1
#define NR_STEP2 2
#define NR_STEP3 3
#define FM_FAST 0
#define FM_SINGLE 1
#define FM_CHARGE 3
#define MOSTLY_DOWN 25
#define SPIN_THRESH 50
bool soundOn = false;
char gx = 0;
char gy = 0;
char gz = 0;
char ax = 0;
char ay = 0;
char az = 0;
byte state = S_READY;
byte ammo = MAX_AMMO;
byte reloadState = NR_START;
byte fireMode = FM_FAST;
unsigned long nextSample = 0;
unsigned long waitUntilTime = 0;
void loop() {
if (isModePressed()) {
switch (fireMode) {
case FM_FAST:
fireMode = FM_SINGLE;
tone(3, 1000, 100);
delay(100);
break;
case FM_SINGLE:
fireMode = FM_FAST;
tone(3, 1000, 100);
delay(200);
tone(3, 1000, 100);
delay(100);
break;
case FM_CHARGE: // Not yet used
fireMode = FM_FAST;
break;
}
}
unsigned long now = millis();
if (now < nextSample) {
return;
}
nextSample = now + 50;
if (isWaiting()) {
return;
}
gyro.read();
acc.read();
gx = gyro.g.x / 255;
gy = gyro.g.y / 255;
gz = gyro.g.z / 255;
ax = acc.a.x / 255;
ay = acc.a.y / 255;
az = -acc.a.z / 255;
// Serial.print("State: ");
// Serial.print(state);
// Serial.print(" RLS: ");
// Serial.print(reloadState);
// Serial.print(" Ammo: ");
// Serial.print(ammo);
// Serial.print(" ");
// debugMotionData();
digitalWrite(10, LOW);
switch (state) {
case S_READY:
digitalWrite(11, LOW);
digitalWrite(10, HIGH);
if (ammo < 1) {
state = S_NEED_RELOAD;
digitalWrite(11, HIGH);
break;
}
if (isTriggerOn()) {
fire();
}
break;
case S_FIRING:
case S_NEED_RELOAD:
if (gy > SPIN_THRESH) {
state = S_RELOADING;
reloadState = NR_STEP1;
waitFor(100);
}
dryFireCheck(isTriggerOn());
break;
case S_RELOADING:
needReload();
break;
}
}
void needReload() {
switch (reloadState) {
case NR_STEP1:
if (gy < SPIN_THRESH) {
if (ax > MOSTLY_DOWN) {
reloadState = NR_STEP2;
} else {
state = S_NEED_RELOAD;
}
}
break;
case NR_STEP2:
waitFor(500);
startReloadSound();
reloadState = NR_STEP3;
break;
case NR_STEP3:
if (ammo < MAX_AMMO && ax > MOSTLY_DOWN && abs(gx) < SPIN_THRESH && abs(gy) < SPIN_THRESH && abs(gz) < SPIN_THRESH) {
addAmmo();
waitFor(100);
} else {
noTone(3);
if (ammo > 1) {
state = S_READY;
} else {
state = S_NEED_RELOAD;
}
}
break;
}
}
void fire() {
ammo--;
switch (fireMode) {
case FM_FAST:
laserEffect();
break;
case FM_SINGLE:
singleFireEffect();
delay(10);
while (isTriggerOn()) {}
delay(10);
break;
}
}
bool hasFired = false;
void dryFireCheck(bool triggerOn) {
if (!hasFired && triggerOn) {
dryFireSound();
hasFired = true;
} else if (hasFired && !triggerOn) {
hasFired = false;
}
}
bool modeToggle = true;
bool isModePressed() {
bool pressed = digitalRead(5) == false;
if (modeToggle && pressed) {
modeToggle = false;
return true;
}
if (!modeToggle && !pressed) {
modeToggle = true;
}
return false;
}
bool isTriggerOn() {
return digitalRead(4) == false;
}
void addAmmo() {
addAmmoSound();
ammo++;
}
void startReloadSound() {
tone(3, 1000, 80);
delay(180);
tone(3, 500, 150);
delay(300);
noTone(3);
}
void addAmmoSound() {
// tone(3, 800, 50);
int min = map(ammo, 0, 24, 500, 700);
int max = map(ammo, 0, 24, 800, 900);
for (int t = min; t < max; t += 36) {
tone(3, t);
delay(2);
}
noTone(3);
}
void singleFireEffect() {
digitalWrite(12, HIGH);
for (int t = 4000; t < 5000; t += 100) {
tone(3, t);
delay(2);
}
int soundStep = 1000;
for (int t = 5000; t > 500; t -= 50) {
tone(3, t);
delayMicroseconds(soundStep);
soundStep += 22;
}
digitalWrite(12, LOW);
noTone(3);
}
void laserEffect() {
digitalWrite(12, HIGH);
for (int t = 5000; t > 500; t -= 125) {
tone(3, t);
delay(2);
}
digitalWrite(12, LOW);
noTone(3);
}
void dryFireSound() {
for (int t = 1000; t > 500; t -= 100) {
tone(3, t);
delay(10);
}
noTone(3);
}
void outSound() {
tone(3, 500, 100);
tone(3, 1000, 100);
tone(3, 500, 100);
tone(3, 1000, 100);
noTone(3);
}
void startUpSound() {
// Serial.println("Startup!");
for (int t = 100; t < 800; t += 10) {
tone(3, t);
delay(5);
}
noTone(3);
delay(100);
tone(3, 500, 50);
delay(100);
tone(3, 1000, 50);
delay(1000);
}
void waitFor(int timeMs) {
waitUntilTime = millis() + timeMs;
}
bool isWaiting() {
return millis() < waitUntilTime;
}
void debugMotionData() {
Serial.print("X: g: ");
Serial.print((int)gx);
Serial.print(" a: ");
Serial.print((int)ax);
Serial.print(" Y: ");
Serial.print((int)gy);
Serial.print(" a: ");
Serial.print((int)ay);
Serial.print(" Z: ");
Serial.print((int)gz);
Serial.print(" a: ");
Serial.println((int)az);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment