Making an Arduino sleep (to conserve power). Looks useful: http://code.google.com/p/narcoleptic/
Tag: arduino
Airsoft M-COM station: the prototype
So, I decided to make an M-COM station for airsoft games.
The first challenge was to get the electronics working. I thought this would be a perfect opportunity to get to grips with Arduino. I’ve had a go at using PIC processors for this kind of thing but it’s hard work: no libraries and coding everything in (arcane, mind-bending, RISC) assembly makes life pretty slow.
I wanted the following behaviour:
- A button which, when pressed, would arm or disarm the box
- When entering the armed state, the box should start an internal countdown timer, flash a light, and activate a siren
- When entering the disarmed state, the box should stop the light and siren, and pause the timer at its current value
- When the timer is close to expiring, the sound emitted by the siren should change
- When the timer expires, the light and siren should stop, and one or more electric pyrotechnics should be detonated
- A potentiometer which could be used to adjust the length of the countdown timer
- A push-to-close switch which could be used to reset the box for the next game
In order to simplify debugging and to avoid having to make a load of noise, I also added LED status indicators to show when the power is on, when the timer is running, and when the timer has expired.
After working out that list of things, I was a bit concerned that this was too big to be a good starting project to learn how to use Arduino, but it ended up being fine. Arduinos are really lovely to use!
I ended up part-designing and part-hacking-together the following circuit:
I used a chunk of stripboard for the non-arduino components. I now hate stripboard. I’m planning to investigate kits for etching PCBs — or if I don’t get around to that, I’ll try my next project with tripad board. Though really, that looks just as fiddly and irritating.
I got the circuit up & running and coded up chunks of the software as I went along. It took a while to get it all working correctly. I got quite confused about some odd behaviour until I realised that my (signed) ints were overflowing. Obviously been too long since I’ve done any C. The full program & comments is below:
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 | // Configs const int warn_pin = 5; const int siren_pin = 3; const int bang_pin = 2; const int pwr_pin = 13; const int switch_pin = 4; const int timer_pin = A0; const unsigned long min_time_needed = 1000L * 60L * 5L; const unsigned long max_time_needed = 1000L * 60L * 20L; const unsigned long warn_time = 1000L * 30L; const int debounce_timeout = 400; // Globals unsigned long time_start = 0; unsigned long time_needed = max_time_needed; void setup() { // Set the modes of pins pinMode(warn_pin, OUTPUT); pinMode(siren_pin, OUTPUT); pinMode(bang_pin, OUTPUT); pinMode(pwr_pin, OUTPUT); pinMode(switch_pin, INPUT); // Read the state of the timer adjust pot time_needed = map(analogRead(timer_pin), 0, 1024, min_time_needed, max_time_needed); // Illuminate the power LED digitalWrite(pwr_pin, HIGH); } void start_countdown() { time_start = millis(); digitalWrite(warn_pin, HIGH); digitalWrite(siren_pin, HIGH); } void stop_countdown() { time_needed = time_needed - (millis() - time_start); digitalWrite(warn_pin, LOW); digitalWrite(siren_pin, LOW); } void check_countdown() { // If the elapsed time has exceeded the time set by the adjust pot, // Turn off the light and siren and set off the pyro if(millis() - time_start > time_needed) { digitalWrite(warn_pin, LOW); digitalWrite(siren_pin, LOW); digitalWrite(bang_pin, HIGH); // Delay until the end of time (or reset) while(true) { } } } void check_finalwarning() { // If the timer is nearly finished, flash the warning light // If the timer is not nearly finished, make the siren intermittent static unsigned long last_flash = 0; static unsigned long last_bleep = 0; if((signed long)(millis() - time_start) > (signed long)time_needed - (signed long)warn_time) { digitalWrite(siren_pin, HIGH); if(millis() - last_flash > 100) { digitalWrite(warn_pin, !bitRead(PORTD, warn_pin)); last_flash = millis(); } } else { if(millis() - last_bleep > 300) { digitalWrite(siren_pin, !bitRead(PORTD, siren_pin)); last_bleep = millis(); } } } void loop() { static int prev_reading = LOW; static unsigned long debounce_time = 0; static boolean waiting = true; // Read the switch state int reading = digitalRead(switch_pin); // Debounce and switch state if(reading == HIGH && prev_reading == LOW && millis() - debounce_time > debounce_timeout) { debounce_time = millis(); if(waiting) { waiting = false; start_countdown(); } else { waiting = true; stop_countdown(); } } prev_reading = reading; if(!waiting) { // This will make exciting flashy things happen when the countdown is nearly up check_finalwarning(); // If the countdown has expired, this will not return check_countdown(); } } |
After I got it all working, I raided the kitchen and mounted the whole thing in a lunchbox. I sanded it down, sprayed it with green acrylic, masked off the lid (poorly) and did some yellow stripes, and gave the whole thing a coat of varnish.
It’s a bit top-heavy but it leans against a tree well enough. I took it out for a test game and it performed pretty well. We put a thermobaric pyro in a tent. It is now an ex-tent.
I’ve started work on its big brother, which will be a more solid and durable prop, and will hopefully look better. More to come on that soon!