/
nerfTurret2.ino
295 lines (251 loc) · 6.76 KB
/
nerfTurret2.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
//nerfTurret2
//Matthew Miller
//KK4NDE
//23-January-2013
/*
This was the second more elaborate Nerf Turret sketch
used in the YouTube video. It controls 2 guns as well
as a laptop running VLC, and my LED lights; all
activated by PIR motion detection. It also monitors
the break-beam sensors on both guns to sync them
firing alternately (to increase rate of fire) and
identify when each gun has misfired or run out of darts
and stop firing after 3 failures. The timing delays are
dynamically calculated to keep the program in sync such
that the amount of time the code took to execute is
accounted for in the delay. This required a more complex
delay by recording the "millis" time and then comparing
it with a desired value at various intervals instead of
calling a conventional sleep delay. This was especially
complex because it was interleaving 2 guns which were
running simaltaniously kept about 1/2 cycle out of sync.
It interfaced thru the Ethernet shield to turn my
bedroom LED lights (which are controlled by a simple
webserver) on and off.
It interfaced thru the Ethernet shield to control the
VLC playlist by sending telnet commands to VLC running
on a nearby laptop.
*/
#include <SPI.h>
#include <Ethernet.h>
// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0x54, 0xF6, 0x9D, 0x38 };
IPAddress lights(192,168,1,221);
IPAddress vlc(192,168,1,104);
#define vlcPort 1234 //TCP port for VLC rc interface control
#define pirPin 7 //PIR sensor logic pin
#define vccPin 8 //PIR sensor power pin
#define gun1Pin 2 //fire control pin
#define gun1Sense 3 //dart sensor pin
#define fireHold 200 //hold for one trigger press
#define fireTimeout 180 //max time to wait (after fireHold ends) for dart to fire before calling misfire
#define cycleTimeout 400 //time for full gun fire cycle
#define misfireLimit 3 //max number of misfires in a row before critical error
#define gun2Pin 4 //fire control pin
#define gun2Sense 5 //dart sensor pin
bool last=LOW; //set last state of PIR detector (so we can act only on start/end)
bool network=true;
int misfireCount=0;
bool gunGood=true;
int misfire2Count=0;
bool gun2Good=true;
// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client;
void setup() {
//Serial.begin(9600);
pinMode(vccPin,OUTPUT);
pinMode(pirPin,INPUT);
pinMode(gun1Pin,OUTPUT);
pinMode(gun1Sense,INPUT);
digitalWrite(gun1Pin,LOW);
pinMode(gun2Pin,OUTPUT);
pinMode(gun2Sense,INPUT);
digitalWrite(gun2Pin,LOW);
//Wait for device to settle
digitalWrite(vccPin,LOW);
delay(5000);
//Power on sensor
digitalWrite(vccPin,HIGH);
//Wait for learning
delay(25000); //25 second warmup
//start the Ethernet connection:
if (Ethernet.begin(mac) == 0) {
// if DHCP fails, drop network stuff.
network=false;
}
//ready
if(network)
{
turnOnGreen();
delay(500);
turnOff();
}
else
{
pinMode(13,OUTPUT);
digitalWrite(13,HIGH);
delay(500);
digitalWrite(13,LOW);
}
}
//fire control loop
void loop()
{
//lots of free time here, just makes fire rate slower
if(digitalRead(pirPin) == HIGH) //if motion sensed
{
//lots of free time here, just makes fire rate slower
if(last == LOW && network)
{
last=HIGH;
int toPlay=random(5,9);
play(toPlay);
delay(2000); //covers playtime of 5,6,7
if(toPlay == 8)
delay(2000); //additional playtime of 8
}
long time=0;
long time2=0;
long timeoutTime=0;
//begin:fire1 start
if(gunGood)
{
time=millis();
digitalWrite(gun1Pin,HIGH);
}
//end: fire1 start
//about 140ms free here while gun1 is firing
if(network && gun2Good)
turnOnRed(); //flash corrisponding to gun 2
//begin:Monitor 2 for misfire
//must run without interruption
if(gun2Good)
{
timeoutTime=millis()+fireTimeout;
while(true)
{
if(digitalRead(gun2Sense) == LOW)
{
misfire2Count=0;
break;
}
else if(millis() > timeoutTime)
{
misfire2Count++;
if(misfire2Count > misfireLimit)
gun2Good=false;
break;
}
}
}
//must run without interruption
//end: Monitor 2 for misfire
//about 20ms free here
if(network)
turnOff();
//begin:fire1 stop
while(millis()-time < fireHold); //delay (dynamic so code can insert above)
digitalWrite(gun1Pin,LOW);
//end: fire1 stop
//begin:fire2 start
if(gun2Good)
{
time2=millis();
digitalWrite(gun2Pin,HIGH);
}
//end: fire2 start
//about 140ms free here
if(network && gunGood)
turnOnRed(); //flash corrisponding to gun1
//begin:Monitor for misfire
//must run without interruption
if(gunGood)
{
timeoutTime=millis()+fireTimeout;
while(true)
{
if(digitalRead(gun1Sense) == LOW)
{
misfireCount=0;
break;
}
else if(millis() > timeoutTime)
{
misfireCount++;
if(misfireCount > misfireLimit)
gunGood=false;
break;
}
}
}
//must run without interruption
//end: Monitor for misfire
//about 20ms free here
if(network)
turnOff();
//begin:fire2 stop
while(millis()-time2 < fireHold);
digitalWrite(gun2Pin,LOW);
//end: fire2 stop
//end of cycle
while((millis()-time) < cycleTimeout);
}
else
{
if(last == HIGH && network)
{
last=LOW;
if(gunGood && gun2Good)
play(9);
else
play(10);
delay(1000); //to cover play time of clips
}
}
}
//in case of critical error, flash PIR quickly
void criticalError()
{
while(true)
{
digitalWrite(vccPin,HIGH);
delay(100);
digitalWrite(vccPin,LOW);
delay(100);
}
}
void turnOnRed()
{
client.connect(lights, 80);
// Make a HTTP request:
client.println("GET /?r=255&g=0&b=0&noform HTTP/1.0");
client.println();
client.stop();
}
void turnOnGreen()
{
client.connect(lights, 80);
// Make a HTTP request:
client.println("GET /?r=0&g=255&b=0&noform HTTP/1.0");
client.println();
client.stop();
}
void turnOff()
{
client.connect(lights, 80);
// Make a HTTP request:
client.println("GET /?r=0&g=0&b=0&noform HTTP/1.0");
client.println();
client.stop();
}
void play(int item)
{
client.connect(vlc, vlcPort);
// Send a telnet command:
client.print("goto ");
client.println(item);
client.stop();
}