NES Zapper target
- 1 What is this then?
- 2 Hardware
- 3 Software
- 4 Now what?!
What is this then?
In short: this thing is a battery-fed 'target' for shooting at with a Nintendo Zapper(tm) light-gun. Targets can each have their own ID, sending out an unique pulse pattern, which can be distinguished by the Zapper.
NOTE: this is just a lame page describing how to build such a target, not how to mod a Zapper into ... something else. Interpreting a target's pulse-pattern is not discussed here, and neither is (wireless?) host/gun communication.
The most obvious difference between the Duck Hunt game and the Zapper-target described here, is that the zapper-target is just a dumb emitter, and doesn't know if/when the Zapper shot it.
Q: if that is so, isn't this whole thing a bit lame? A: yes, quite right. Q: then why would I invest ANY time AT ALL into reading this..? A: because you have nothing better to do anyway, my friend.
Background: the NES Zapper(tm) and Duck Hunt
After a recent friendly chat with a mate about how the NES Zapper would work, it seemed like a good idea to pick up a 2nd hand one to toy with.
Duck Hunt ( Wikipedia page) is/was a game where you could 'shoot' ducks on your TV-set, using a light-gun (the Nintendo 'Zapper'). The Nintendo Entertainment System (NES) would detect which, if any, duck was shot, and adjust the gameplay accordingly.
The Zapper and Duck Hunt game interaction is nicely described here, and roughly works as follows:
- 2 ducks appear on the screen
- player shoots at the screen/duck
- NES detects gun's trigger pulse, and blackens the screen for 1 frame
- in the next frame, a white rectangle is painted where duck #1 was
- in the next frame, an additional white rectangle is painted where duck #2 was
- if the gun's sensor receives black-white-white, duck #1 was shot
- if the gun's sensor receives black-black-white, duck #2 was shot
- gameplay resumes according to hit-result, etc
Most of the f*cking about was spent on the hardware, or rather, aiming the gun towards the LED, trying more LEDs, trying to diffuse the light, and less with the software itself.
My idea was to put targets here and there, give them their ID, and just let them sit there. (The result of shooting (at) a target would be interpreted either in the gun itself, or in the gun-receiver in the PC - both outside the scope of this page.)
Therefore, power consumption would have to be minimal. Furthermore, light-pulse patterns emitted by a target shouldn't be irritating, e.g. no bright 4Hz flashes.
Size was also an issue; the idea was to place targets somewhere out of sight, with only the lightsource visible to take aim at. It would be nice if the whole target could be covered by a 'front' (e.g. a picture of a cow, sheep or Teletubby to take aim at) made by simple cardboard + sticker, for instance.
A PAL TV connected to a NES displays frames at 50 Hz vertical refresh rate, and draws rasterlines at 15.625 kHz (Wikipedia to the rescue). Not taking into account the fade-out effect of a TV's phosphor layer (is it indeed phosphor?), the Zapper will thus likely see a burst of 15 kHz pulses (the circle on the screen it is pointed at) 50 times every second, assuming it is pointed towards something non-black on the TV-set.
On this excellent page, it is suggested the Zapper's amplifier/filter circuitry only passes signals around 15 kHz; I tried a bit, and this was indeed so - of course I forgot the exact cutoff-frequencies I measured :-)
During testing and experimenting with different-length 15 kHz bursts, I found a burst of as few as 3 pulses was enough for the gun to detect it, as can be seen here. Upon detecting a valid 15 kHz burst, the zapper releases its open-collector sensor output for some time, resulting in a nice pulse, in this case of about 900 us.
As an extra feature, I wanted to include a periodic battery-check in the target, to inform the user when it's about time to change the battery.
Looking at the childishly simple schematics, the ATtiny's pin PB0 can be pulled low to sink the LED-current, and when doing so, the voltage drop over the LED's series-resistor can be measured at PB2's ADC-input. Since voltage over the LED (when conducting) is quite constant, a drop in supply voltage will be directly visible as decreased voltage drop over the resistor.
As a battery, a 3.6 V one (e.g. a lithium cell, such as this one) would do nicely; the MCU has a minimal supply voltage of 2.7V, so a visible alarm at 3.0 or lower sounds sane. To minimise power-consumption in the LED and ADC during a check, a check every 15 minutes would be enough.
To test the battery-check, avrdude's STK500 interface offers a nice 'terminal' interface:
echo vtarg 3.6 | avrdude -F -P /dev/ttyS1 -c stk500v2 -p t13 -t
... would set target-voltage to 3.6 V. Lovely.
ATTiny13 has 1 kb of codespace, and 63 bytes RAM. This is really not a problem, since our needs are modest :-) Software can be found here, BTW.
Modes of operation
Typical use would (probably) be to take the target, turn it on, select its ID, and then let it sit somewhere, ready to be Zapped. ID-selection would basically be a one-time operation, so storing it in an NVRAM would not be necessary.
I was planning on physically soldering a battery onto the circuit-board, so the device would always be powered on. 'Turning it off' would mean entering a sleep mode.
When powered on (i.e. battery soldered into the circuit), the device would go through following modes:
- enter power-down (deep sleep) mode, waiting to be turned on using button-press
- choose ID by means of LED-indicator and button-press
- resume normal operation (i.e. emit pulses) with periodic battery check; button-press would power-down and start from the beginning
From a user-interface point of view, perhaps the only interesting bit is choosing the ID: 8 LED-flashes are given, with approx. 750 ms delay after each flash. If the button is pressed during the delay after the Nth flash, the ID will be N. If no button-press was seen, 8 flashes will be emitted again after a 2 second delay, etc. Now who said I suck at user-interface design?!?!?!
Looking at the ATtiny13 datasheet, it has different sleep-modes to cut down on current: (assuming 25 deg C, 3.5 V supply, watchdog and brownout-detect disabled)
- active mode: about 70 uA (all clocks operational)
- idle mode: about 17 uA (no CPU and flash clocks)
- power-down mode: about 3 uA (all clocks halted, only wake on pin change / external interrupt)
This is nice.
We will use active mode only when choosing the ID, emitting a 15 kHz pulse burst, or when performing a battery-check. These situations are rare, timeline-wise.
Idle mode is used between 15 kHz bursts. Another option could be to use power-down mode and watchdog-timer to save another uA, but unfortunately the watchdog's timeout-resolution is too coarse to make a nice 50 Hz clock. Oh well. :-)
Power-down mode is used when the device is turned off; a pin-change interrupt on the ATtiny's PB3 (PCINT3) is used to wake it up again.
Furthermore, we will use the internal 128 kHz watchdog RC-oscillator with a 1:2 prescaler to make the device run at 64 kHz.
Note to self: I control the LED using DDRB, switching between placing the LED-pin in hi-Z, or driving it low. A transition seems to take 2 cycles. Why? I thought 1.
Unique per-ID pulse-patterns
Each target would continuously send its unique ID (where ID is in the range 1..8, so it's not really that unique ;-) for the Zapper or host to interpret.
First attempt: encode 6-bit word using 15 kHz bursts
For this, the delay between 2 15 kHz bursts is always a multiple of a constant delay (let's say 20 ms), i.o.w. only once every 20ms, a burst is output, or not.
If each ID is thus encoded to a fixed-size word (of e.g. 6 bits, with 'no burst' for '0', and 'burst' for '1'), each target can then send the word corresponding to its ID, continuously.
For 6-bit words, when allowing at most 3 0's in a word, and disallowing 'all ones' (to filter out lightsources that simply happen to be pulsing at that frequency), the following words are possible: (showing each word 3 times, to indicate they are being sent continuously, head-to-tail)
As an example, this picture shows word #1 being sent continuously.
The maximum frequency of 15 kHz bursts, together with the alternation of 0's and 1's in a word, must be so that...
- powerconsumption is not becoming an issue (i.e. burst-frequency not too high)
- the flash-pattern is not irritating
- the receiver/interpreter must be able to interpret a word reasonably fast (say, max 100 ms); this affects the time the gun has to be held fixed at the target when the trigger is pulled
The level of irritation varies a lot; e.g. word #1 and #4 appear quite steady/calm, while other words are more irritating to watch at, at lower burst- (or bit-)frequencies.
The irritation-factor, that would only go away with quite high burst-frequencies (about 150 Hz), together with the needed complexity of the receiver/interpreter, made me decide to ditch this method. Oh well.
Much nicer: 15 kHz bursts with toggling periods
Much less irritating, even at lower burst-frequencies, is to toggle the interval of 15 kHz bursts. In other words: send a burst, wait T1, send another burst, wait T2, send burst, wait T1, etc. Sum of periods of 2 consecutive bursts is always a constant (2T, or 40 ms). Therefore, T1 = T - Delta, and T2 = T + Delta.
In this picture, you can see a shift of every odd pulse. The green area is the allowed margin for Delta; note that Delta must be nonzero, to filter out devices that just happen to emitting a constant-frequency pulse.
The uncalibrated internal RC-oscillator of the MCU deviates quite a bit between devices, and under influence of temperature. However, if the receiver interprets factor T1/T2 to determine the target's ID, this is not a problem.
I am assuming the time between a 15 kHz burst and the corresponding Zapper's sensor-output pulse varies a bit, but I have never seen this vary more than 100 us. To find a nice balance between irritation-level of the pulse pattern and robustness of the receiver/interpreter, Delta varies from approximately 1 to 5 ms, in steps of about 500 us. This should be enough to interpret target ID's reliably.
Yes, this thing by itself is pretty useless. Next up, the Zapper(tm) needs to be modified a bit to identify targets. A special 'game mode' where targets would turn on for a short moment at random moments, ready to be shot, would perhaps also be nice. Someone suggested a 'bad guy'/'civilian' indicator to make it a bit more interesting. :-)
Have fun -- Michai