As a tinkerer it is always very satisfying to see the numerical results of your tinkering. Many of us have modified Nerf guns before and who doesn't love flinging pieces of foam across the house at over 100fps?
After modifying many Nerf guns throughout my life, starting when I was ~10 with my Dad until now when me and my roommates continue to fling foam across the apartment at each other, I've always wanted to know exactly how fast the darts are flying, and how many darts per second my roommates Rapid-Strike shoots. There are commercial chronographs available for Nerf and Airsoft, but the high precision ones are expensive, and it fun to build one on our own. If you do want to buy one, Nerf released a barrel nearly identical to the one featured in this project (with some better industrial design) and it can be found here:
The Nerf version is also battery powered, and displays a counter for darts fired. The Instructable here also includes a screen and a reset button, however relies on dart length for speed calculation, and doesn't appear to use interrupts. The main focus of this project will be on the serial communication (as a simple example such as this was not the easiest to find online), and the use of interrupts for accurate timing. This can likely be easily converted into an airsoft chronograph for the same reasons with a tighter enclosure and a better mounting system for airsoft guns. Without using interrupts the code can be slower and less efficient, it is also much more difficult to time in regard of microseconds accurately as milliseconds will not produce accurate values for dart speed.
I will not focus too much on the enclosure design although STL files are available in the GitHub, because anybody can just buy the Nerf version which is definitely better for actual game play, but a future version of this may mitigate the results.
Basic Principles (Learning Outcomes):
- Has the form of a standard Nerf Barrel
- Use of phototransistors as timing gates for the dart.
- Shows the use of Adruino interrupts for timing
- Use of Processing with Arduino for Serial Communication
I plan to go over mostly specifics to this project with some brief overviews and recommend reading the references for Arduino and Processsing for more specific info. This will not teach you how to solder, but more of a how to integrate Arduino and Processing and use interrupts. Much of this learning will be through reading the actual commented code so please ensure that you read through all of the code before blindly uploading and attempting to get it to work.
Benefits over Similar Projects:
- Use of Interrupts for accurate measuring of high speed
- Extensive debugging section for phototransistors
- Rate of Fire (ROF) Calculation outputting Rounds per Second (RPS)
- Fullscreen computer interface - not useful during battle, but great if you want to show others the results on stream or Youtube with a screen recorder.
- Potential to be adapted for Airsoft or Paintball by modification of just the enclosure
- No need for custom PCBs (Would be nice in a future update but anybody can make this for relatively low cost
- Total cost of under $10 when parts are parted out and if a 3D printer is available - On par with the commercial cost, with ROF addition
Step 1: Required Parts and Tools
If you have a 3D printer this will be a great project for you as I will be providing the files for the enclosure. Feel free to update the enclosure. I didn't have any LCDs on hand, but a second version will hopefully have an LCD and utilize a WEMOS D1 or similar WiFi/BT enabled board, and a battery. This will allow for data logging on mobile and real time feedback - for example, how many darts are left in the gun. Some soldering experience is recommended, if you don't feel comfortable I recommend following an Instructable for soldering and probably buying extra electronic components just in case.
- Soldering Iron
- Hot air blower/ Heat Gun/ Lighter (If using heat shrink)
- Wire Strippers
- Mini - B USB Cable (or whichever cable is required for your micro controller)
- Hot Glue Gun or Similar (I used a 3D printing pen to attach all components to the 3D printed enclosure)
- 22AWG Solid-core wire ex: Solid Core Wire Set 22AWG
- Arduino Nano (or similar, I used a clone) ex: 3 x Arduino Nano (Clone)
- Resistor Kit (2 x 220 ohm, 2 x 220k ohm) You may be able to use lower value pulldown resistors such as 47k with success, I just happened to find that I needed this value for it to work. The troubleshooting guide outlines how to determine if the pulldown resistor is the correct value for your specific phototransistor and LED set. Because of this I reccomend getting a set: ex: Resistor Set
- 2 x IR LED ex: IR LED and PhotoTransistor Set
- 2 x PhotoTransistor
- 1 x 3D printed Enclosure - In an IR Opaque Filament (Hatchbox Silver Worked and was the only color I tested)
- Full Project Files are available here on GitHub as well as in the attached Zip File. The STLs are also availabe on Thingiverse here.
Step 2: Breadboard Testing
Once the electronics have arrived, solder leads to the phototransistors and IR Leds ~20-30cm for debugging, I recommend heat shrinking these. I didn't have the correct size heat shrink and had to utilize electrical tape for this prototype. This will allow for you to use them for testing in the enclosure. If you have printed the enclosure and have LEDs and photo transistors in the correct positions you can begin testing.
The zip file at the beginning has all the code as well as the STL files for printing the enclosure.
Use Arduino to debug at first and only use processing for final testing (you can see everything in serial monitor from Arduino).
You can try simply firing a Nerf dart through the chronograph with Chronogrpah_Updated.ino installed on the Arduino. If this works then you are all set. If this doesn't work then you will likely have to adjust the resistor values. This is discussed in the next step.
A little bit on how the code works:
- Interrupst stop the code whenever a dart goes through a gate and determines the time in microseconds
- The speed is calculated with this and the time is stored
- The time between shots is calculated and converted to rounds per second
- The time between gates is calcultated and converted to feet per second based on gate distance.
- Use of two gates allows for better results with identical timing (how much of the sensor must be covered) and reduces hysteresis
- The speed and rate of fire are sent via serial seperated by a comma to either the serial monitor in arduino or the processing sketch allowing for a nice UI (focus on processing when everything else works!).
Step 3: Testing and Debugging
If you did not have success with the initial test, then we need to figure out what went wrong.
Open the Arduino example AnalogReadSerial found in File-> Examples->0.1 Basics -> AnalogReadSerial
We want to ensure that the phototransistors are working as we expect them to. We want them to read HIGH when the dart is not blocking them, and LOW when the dart is not. This is because the code is using Interrupts to record the time when the dart is passing the sensor, and the type of interrupt being used is FALLING, which means it will trigger when going from HIGH to LOW. To ensure the pin is HIGH we can use use the analog pins to determine the value of these pins.
Upload the Arduino Example AnalogReadSerial and jump from the digital pin D2 or D3 to A0.
D2 should be the first sensor and D3 should be the second sensor. Choose 1 to read and begin there. Follow the guide below to determine the correct solution based on the readings:
Value is 0 or very low:
The value should be around 1000 initially, if it is reading a very low value or zero then ensure your LEDs are wired correctly and not burnt out, as well as aligned well. I burnt out my LEDs in testing when using a 100 ohm resistor instead of the 220 ohm. It is best to refer to the datasheet for the LEDs to determine the correct resistor value, but most LEDs will probably work with the 220 ohm resistor.
LEDs Work, and Value is still 0 or very low:
The issue is likely in the pull down resistor being too low in resistance. If you are having an issue with the 220k resistor, you could maybe increase it higher than this, but may get noise. You should ensure your photo transistor is not burnt out.
Value is a middle range:
This will cause a great deal of problems, mostly false triggers, or never causing a high. We need to ensure that a HIGH is received, in order to do this we need a value ~600 but lets aim for 900+ to be safe. Being too close to this threshold can cause false triggers, so we want to avoid any false positives. To adjust this value, we want to increase the pulldown resistor (220K). I already did this a few times in my design and you likely won't have to do this as this is a very large value for a pull-down resistor.
Value is very noisy (jumping around a lot with no external stimuli):
Ensure your wiring is correct with the pull-down resistor. If this is correct, you may need to increase the value of the resistor.
Value is stuck at 1000+, even when blocking the sensor:
Ensure your pull-down resistor is wired correctly, this is likely to occur if there is no pull-down. If this is still an issue, try reducing pull-down resistor value.
Value is high and goes to zero when blocking the light:
This should be sufficient for the sensor to work, however we may not be a fast enough response as the dart crosses the path. There is some capacitance in the circuit, and with the 220K resistor it may take some time for the voltage to fall below the required threshold. If this is the case, reduce this resistor to 100K and see how the tests work.
ENSURE ANY RESISTOR CHANGES ARE CONSISTENT BETWEEN BOTH SENSORS
Ensuring identical circuits for both sensors maintains the same latency between the resistors which will allow for the best accuracy in measurements.
If you have any additional issues, drop a comment below and I'll do my best to help you.
Step 4: Hardware Assembly
Solder the components to the small PCB as seen here:
The leads for the LEDs and the PhotoTransistors should cut to length, approximately ___.
Solder the Arduino onto the board, and wire the resistors from the ground to accessible pins. Additionally ensure that the 4 Positive wires can be easily attached together. If you are having issues with this, you can strip a piece of the wire and solder it across all the leads at the end.
I wired the sensors to the opposite side of the enclosure, however feel free to wire either as long as you keep the sides consistent. I cut the wires to lengh and soldered the wires to each of the diodes last. I updated the wire routing slightly to provide more room and less worry for having some wires under the PCB and others over it for easy of use. The STLs are in the full project zip file at the beginning of the project.
Step 5: Final Assembly
If your PCB Holes don't match-up with the holes on the main chronograph body, you can likely secure the electronics in the enclosure with some tape or hot glue, I found it didn't need to be secured after the wire and USB were in place, however your results may vary. It is designed to allow for the pressing of 1.75mm filament into the screw holes for heat staking, however the PCB can also be screwed in or glued. The most important part here is ensuring the USB port is accessible.
Cover the electronics with the electronics cover, The updated Files should fit better than mine did and will hopefully press into place, however I utilized a 3D printing pen to weld the covers in place. You are now ready to fire some darts!
A future update may use internal routing for the wires, but the covers in this case yield slightly to the Nerf aesthetic.
Step 6: Chronograph in Action
Opening the Processing File: Chronograph_Intitial_Release will allow for a really nice user interface for the chronograph displaying both FPS and RPS (Rounds per Second). If you are having trouble connecting ensure you closed your Arduino serial monitor, you may also have to change the serial port in the code, but this is commented and should be simple. To reset the max values simply press the space-bar on your computer.
A little bit on how the code works (Photo of UI can be seen above):
- Receives input from the Arduino
- Compares this to past input to find the max value
- Displays the current and max values in full screen for easy visual feedback
- Resets max value when space is pressed
Step 7: Future Plans
A future update for this will include the following improvements. If you have additional features that you would like, let me know and I'll try to implement them.
- Include LCD Screen
- Include Batteries
- Nerf Compatible Attachment points
- Updated Enclosure
- Iron Sights