Intro: Paintball/Ballistic Chronograph
A ballistic chronograph is a device that records the velocity of a projectile. This particular chronograph I have made has only been tested with a paintball gun and it is relatively simple to make. I have also implemented a function that can record the rate of fire at which a device is firing.
Seeing as you will be using a device that shoots projectiles at high speeds to test this chronograph, use your head and be smart. Follow all safety procedures and guidelines that pertain to the use of the paintball marker or other device that you are using to shoot projectiles.
Step 1: Electronic Requirements
Although this chronograph is pretty easy to build, a basic understanding of electronics and soldering skills is essential. The most trouble I had with this project was making the PCB. I use the toner transfer method, but that doesn't produce very nice boards when your laser-jet printer needs a new cartridge. The board itself has some spots that are pitted and doesn't look too neat, but it gets the job done. If you aren't able to make your own PCB's, one can just use some perfboard and point to point wire everything together.
Here is a list of the following electronic components required:
- 2x 47µf Electrolytic Capacitors
- 2x 0.1µf 0805 SMD Capacitors
- 1x 0.01µf 0805 SMD Capacitor
- 1x 0.01µf Ceramic Capacitor
- 2x 27pf 0805 SMD Capacitors
- 2x 10kΩ 0805 SMD Resistors
- 2x 2.4kΩ 0805 SMD Resistors
- 2x 470Ω 0805 SMD Resistors
- 1x 150Ω 0805 SMD Resistor
- 2x 100Ω 0805 SMD Resistors
- 1x 4.7kΩ Trim Potentiometer
- 1x 1N4148 Diode
- 1x LM7805 5v Regulator
- 2x TSOP4838 IR Detectors
- 2x IR Transmitters
- 2x Female 2-pin Molex Connectors
- 2x Male 2-pin Molex Connectors
- 1x 5-pin Header
- 1x MMMBT2222A General Purpose Transistor
- 1x 12MHz Crystal
- 1x Tactile Switch
- 1x Rocker Switch
- 1x PIC18F13K50 SOIC Microcontroller
- 1x 16x2 LCD Display
- 1x 9v Battery Clip
Most of these components I had already had on hand, but I would estimate the cost of this project to be around $30-$40. I have not shown any of the SMD components (except for the PIC) in the photo below.
I have gone and posted print screens of some places where you can buy the components. Some components couldn't be bought as 1 or were cheaper in higher quantities, that's why you may see some extra parts in the pictures. Many of the parts can be bought at a good price at www.dipmicro.com. I will tag the cost of each product in the photos below. With all of these parts, not including the board, it came to $38.11 to purchase all the components for this chronograph with all shipping included except for the PIC18F13K50 bought at Digikey. Then it would be a couple more bucks for the PVC pipe. Also, if you want to save $3.39, you can buy 16x2 LCD Displays on eBay for $2.99 including shipping.
Step 2: Tools Required
Here is a list of tools and supplies that were used to build this project:
- Soldering Iron
- Flux Pen
- Super Glue
- Digital Calipers
- Needle Nose Pliers/Side Cutters
- Heatshrink Tubing/Electrical Tape
- Scalpel/Utility Knife (Used for PCB touch-ups)
- PIC Programmer (I used a MPLAB ICD2 Clone)
- Anti-Static Tweezers for small SMD components
- Perfboard/Breadboard or Materials required to make a PCB
- Toothbrush and Rubbing Alcohol to clean the flux off the PCB
- 6" long, 1" Diameter PVC Pipe (May need a hacksaw to cut down a larger PVC piece)
A hacksaw/jigsaw or something of the sort is required to cut the PVC pipe down to 6". I bought a 5ft piece of PVC, cut a piece of pipe off that was 6" long and used digital calipers to measure out 4" between the IR transmitter/detector pairs and drill holes for them in the PVC pipe.
Step 3: How It Works
Now that we got all of the requirements and setup out of the way, we can move on and finally get to the exciting stuff. The operation of this chronograph is rather simple, there are two IR transmitters and two IR Detectors, each transmitter/detector pair is placed exactly four inches apart.
When an object breaks the first beam the microcontroller starts a timer (Timer1). This timer will keep running until the object breaks the second beam or the timer causes an interrupt (on the 65,536th instruction cycle). If the object breaks the second beam before the timer causes an interrupt, it will stop the timer and read the 16-Bit value in the registers TMR1H and TMR1L. We can then calculate the amount of time that it took the projectile to travel the length in between the IR beams, which are 4 inches apart, and find the speed of the projectile.
If the object is too slow, or if the projectile breaks beam #1 but does not break beam #2, the chronograph will display an Error message on the LCD Display. Seeing as this is a 1" diameter pipe, and a paintball is 0.68", I have never had a paintball that failed to break beam #2. However, if a paintball chops in the barrel you might get some inaccurate data and you will more than likely have to clean out the paint that would have splattered in the chronograph to ensure a good "connection" from the transmitter to the detector.
Step 4: Calculations
Now we'll take a look at what calculations are needed to get the actual velocity of the projectile.
The PIC18F13K50 is setup to run at 48MHz. It takes 4 cycles to perform one instruction cycle, so the MCU is running at 12 MIPS (Million Instructions per Second). So the time it takes for the PIC to perform one instruction cycle is equal to (1 / 12MIPS), which is 83.3333 nanoseconds/instruction.
We know that the distance between the IR "beams" is exactly 4 inches. So all we need now is to know how long it took the projectile to travel from beam #1 to beam #2. This is what Timer1 is used for. Every instruction cycle (83.3333 ns) the value of TMR1H:TMR1L will increment.
Say we fired a paintball through the chronograph. Once the paintball has traveled through the chronograph and broke beam #2, we go and read the value of TMR1H:TMR1L (it's a 16-Bit value). For examples sake, we'll say the value we read was 15,930. Here is how we calculate the velocity of the paintball:
MCU Speed = 12 MIPS
= 83.3333 ns/ins
Distance = 4 in.
= 1/3 ft
Time = MCU Speed * TMR1H:TMR1L
= 83.3333 ns/ins * 15,930 instructions
= 1.3275 milliseconds
Velocity = Distance / Time
= (1/3 ft) / 1.3275 ms
= 251 feet per second
The paintball was traveling at a speed of 251 fps. While this way of calculating is perfectly fine, in my code I just rearranged the equation so the MCU could calculate it a little bit quicker. The equation I use in my code is:
Velocity = ((FOSC / 4) / TMR1H:TMR1L) / 3
= ((12 MIPS) / 15,930) / 3
Step 5: Rate of Fire Mode
As mentioned in the intro, this chronograph also has a Rate of Fire (RoF) mode. This allows the user to determine how many shots per second their paintball marker is capable of. It is pretty straightforward, when switch #2 (S2) is pressed, the chronograph switches from velocity mode to RoF mode and vice versa.
In RoF mode, Timer0 is setup to interrupt after 1.00s as soon as it is enabled. The chronograph waits for a projectile to break beam #1, once it does it enables Timer0 and increments the variable 'rate' which keeps track of the shots fired in the 1.00s time period. The program will then poll beam #1 to see if another projectile has been fired. If another shot has been fired within the 1.00s time period, it will break beam #1 and increment the variable 'rate', yet again, by one. It will then loop until beam #1 is restored back to its default state (not obstructed) before continuing on and checking for another shot. This is to make sure that we do not count the same projectile several times as it passes through beam #1.
Once the 1.00s time period has elapsed, the MCU will display the RoF for 2.00s on the LCD regardless of how many more shots go through the chronograph in the 2.00s time period. This is to ensure that the chronograph does not start recording any shots right after the 1.00s time period which would then result in a new RoF value. Without this delay, the user would have to stop shooting before the 1.00s interrupt occurs, otherwise if the user didn't stop shooting right before the interrupt and an extra ball or two traveled through the chronograph, it would record the RoF of the extra balls that went through because the function would just start over again.
Step 6: Chronograph - Pseudo Code
Below is the attached schematic of the chronograph, here is a pseudo code representation of how the chronograph operates:
========== Chronograph Operation ==========
- Power Up
- Initialize Ports
- Initialize LCD
- Initialize PWM
- Initialize Timer0 but keep it disabled
- Initialize Timer1 but keep it disabled
- Initialize External INT2 (S2)
- Enable Interrupts
- Loop Forever
- Check if its set for "velocity" mode or "RoF" mode
- If its set for "velocity" mode, debounce S2 and enable INT2, then enter "velocity" mode
- Else if its set for "RoF" mode, debounce S2 and enable INT2, then enter "RoF" mode
- Prepare Timer1 to record the speed of the projectile (set TMR1H:TMR1L to 0x0000)
- Loop until a flag is set (pressing S2 would cause this) or an object breaks beam #1
- Start Timer1
- Loop until a flag is set (S2 is pressed or Timer1 overflows) or an object breaks beam #2
- Stop Timer1
- Make sure that a flag hasn't been set (Make sure the operation completed successfully)
- If no flag has been set, increment the shot count and calculate the projectiles speed
- Display the projectiles speed on the LCD display
- Else if a flag has been set and it has not been changed to "RoF" mode, display an error
(This error is due to the projectile moving too slow for the chronograph to capture its speed)
- Return to main loop and check which mode the chronograph is in
- Prepare Timer0 to interrupt at exactly 1.00s (It is still disabled at this point)
- Loop until a flag is set (pressing S2 would cause this) or an object breaks beam #1
- Check to make sure that a flag has not been set (S2 wasn't pressed)
- If no flag has been set, start Timer0
- Loop until a flag is set (until Timer0 has interrupted after 1.00s)
- If beam #1 is broken, increment variables 'rate' and 'shots'
- Loop until beam #1 is restored (wait for the projectile to finish passing through beam #1)
- It has been 1.00s and Timer0 has interrupted, display the RoF on the LCD
- Return to main loop and check which mode the chronograph is in
========== Interrupts ==========
- Shut off Timer0
- Set a flag
- Clear the Timer0 interrupt flag
- Set a flag
- Clear the Timer1 interrupt flag
- Make sure both Timers are shut off; Shut off Timer0 and Timer1
- Change the mode from "velocity" to "RoF" or vice versa
- Set a flag
- Disable INT2 (So we can debounce the button press of S2)
- Clear the INT2 interrupt flag
P.S.> I apologize for how the schematic looks a little scattered.
Step 7: Making the Chronograph "Barrel"
Take your 1" diameter PVC pipe and measure 6" in from one of the outer ends. Make a mark here with a pencil or a marker. Use a hacksaw or similar tool to cut the PVC pipe at the mark you made. You should now have a 6" piece of PVC pipe. From there, measure 1.5" in from one end of the piece. Make a mark on the pipe. This is where you will drill the hole for the first IR transmitter. Drill the hole with a 3/16" drill bit, then from the exact center of that hole, measure 4" to the other side of the pipe and make another mark. You will then drill the hole here for the second IR transmitter.
After you have drilled the two holes for the IR transmitters, put the drill in the second hole you drilled and make sure it is completely perpendicular to the PVC pipe (there is pictures for most of these steps). Drill through the other side of the PVC pipe. You have just drilled out the hole for the second IR detector. Next, flip the pipe over and measure 4" across the pipe from the exact center of the second IR detectors hole. Make a mark and drill another hole, this one is for the first IR detector.
The reason I don't drill through both IR transmitter holes and instead I measure 4" from the second IR detector hole is for accuracy. It is to ensure that both IR transmitters and both IR detectors are spaced exactly 4" apart from each other. This minimizes the error in the calculations and allows for greater accuracy.
After all the holes are drilled, the two IR transmitters are placed in their respective holes. Seeing as we used a 3/16" drill bit, the holes diameter is only ~4.8mm. This means that the 5mm LED will not completely fit in the hole, this is what we want though. We just want the IR LED's to slightly poke into the barrel, for two reasons. First, it helps direct the IR beam in a straighter path to the IR detector. Second, it reduces the chance of a projectile striking the IR LED itself and damaging it.
Once the IR LED's are placed in their holes, a small dab of super glue is used to tack them in place. Don't fully glue the IR LED in the hole, just in case you need to replace it later. Once tacked into place, take your soldering iron and solder some wires to the IR LED's. Ensure that the wires can reach the other side of the PVC pipe where we will later be installing the PCB. I would recommend putting connectors on the wires so that it is easier to disassemble the chronograph in the event that you need to clean it.
Step 8: Putting It All Together
Below I have uploaded the photos of the saved PCB at 300DPI. This is the circuit board that I have designed for the chronograph. The crucial part to this board is that the IR Detector holes are exactly 4" apart. This will allow us to align them with the holes on the PVC pipe. I have also uploaded a PDF file which contains all the board faces required to create a PCB using the Toner Transfer Method.
Once you get the PCB made and solder all of the components to it, you are ready to put everything together. I have gone through the steps for putting it together in the pictures. Its is much easier to follow when you can visually see it, so I will not write them up in two paragraphs as they are in the pictures tags.
Step 9: Testing
I do not use the C18's driver files in my code for this chronograph. Instead I wrote my own driver files for the timers, external interrupts, pwm, etc. These files are all located at the bottom of this step, enclosed in a downloadable zip file.
I have included the schematic in this step so you don't have to go back to step #6 to view it. You will notice that IR1 and IR2 Detectors are connected up to INT0 and INT1 respectively. Although I did not need to use INT0 or INT1 because my device has nothing else to do anyways when its polling their inputs, I placed them at these locations so that they could be used as interrupts in case someone wants to have the code doing other things and not being tied up in a loop. INT2 has to be used if the user wants to use both modes ("velocity" and "RoF") in their chronograph.
The IR transmitters produce a 38KHz frequency, which is then picked up by the IR Detectors. This is how the device knows when an object is passing through its "beam". The IR Detector will not see a 38KHz IR pulse because it has been blocked by the projectile. I originally wanted to use a comparator and phototransistors to do the job of the TSOP4838's, because I then wouldn't have to worry about pulsing the IR Transmitters at a rate of 38KHz and I could just apply the specified voltage to the IR transmitters. However, I did not have any high-speed comparators here so I went ahead and decided to use IR detectors, of which I did have on hand. As for pulsing the IR transmitters at a rate of 38KHz, I simply used the hardware PWM module on the PIC18F13K50.
In order to program the PIC18F13K50, one must use a programming adapter to avoid damaging the USB pins which are also PGC and PGD. I have included a PDF file which contains the schematic and board layout of a cheap programming header for this device. I did not make the schematic itself, I simply ported it into Cadsoft Eagle and made a board for it. The link is below this paragraph. I have added a 470Ω resistor on the PGC and PGD lines to the microcontroller and it will program this way, but it may damage your USB D+/D- lines without the programming header.
Step 10: Accuracy and Error
Now that we have the chronograph up and working, we will find the worst case scenarios and error tolerances of this device. I will calculate the accuracy according to a 300fps velocity (I assume that the IR Transmitters/Detectors are placed exactly 4" apart, I won't account for manufacturing error).
If a paintball is traveling at 300fps, it takes 3.3333ms to travel 1ft (1 / 300fps = 3.3333ms). Seeing as our IR Transmitter/Detector pairs are spaced 4" apart, we have to divide 3.3333ms by 3 (1ft / 4in. = 3). So the time it will take the paintball to travel 4" at 300fps is 1.1111ms.
300fps = 3.3333ms/ft
time to travel 4in. = 3.3333ms / (1ft / 4 in.)
CPU Speed = 12 MIPS
Accuracy = 100 - (100 * (83.3333ns / 1.1111ms))
= 99.9925% accuracy @ 300fps
Now that is not the actual accuracy of this chronograph. If this microcontroller could detect an object at any instruction cycle, it would have an accuracy of 99.9925% at 300fps because its worst case scenario of not detecting an object when it has broken the beam could only be 83.3333ns before it would actually detect it.
Seeing as I am polling the IR Detectors and waiting to see when an object has broken beam #1, it takes 8 instruction cycles per loop when I am trying to detect if there is an object breaking the beam. Then once it has detected an object, it has one more instruction cycle to perform because it has to start Timer1. After it has done all of this, it has begun recording the time period that it takes the projectile to travel from beam #1 to beam #2. The same goes for beam #2. It takes 8 instruction cycles per "detection" loop and one more instruction to turn Timer1 off. Therefore the worst case scenario is:
Ins/Loop = 8 ins * 2 Loops
= 16 instructions before a detection
Ins/Enabling of Timer1 = 1 ins * 2 (enabling and disabling of Timer1)
= 2 instructions
Longest amount of time possible before a detection = (16 ins + 2 ins) * 83.3333ns/ins
= 1.5 µs
Accuracy = 100 - (100 * (1.5µs / 1.1111ms))
= 99.865% accuracy @ 300fps
So assuming that there are no other sources of error (distance is exactly 4", beams are broken identically on each side, etc) we would have an accuracy of 99.865% at 300fps for this chronograph. This is very good, however, there are many other small sources of error that I have not accounted for. Therefore it is highly unlikely that the chronograph that I build or you build will be 99.865% accurate. Nonetheless, it works quite well and I am very pleased with it.
I forgot to add the minimum velocity of the projectile. Seeing as the highest count that Timer1 can count up to is 65,535, plus it uses one more instruction to make it overflow back to 0 and its running at 12MIPS, we can calculate the speed of a projectile as low as 62fps. The calculations are as follows:
MCU Speed = 12 MIPS
Max Count Timer1 = 65,535 instructions + 1 more instruction to make it interrupt
= 65,536 instructions
Min Velocity = ((12MIPS / 65,536 ins) * 1/3ft)
= 61.03516fps (To be safe, we'll say 62fps)
Step 11: Conclusion
All in all, I am quite pleased with how the chronograph works. It wasn't very difficult to build and the code itself is pretty easy to follow. Eventually I plan to update the code and use INT0 and INT1 to detect when a projectile is being shot through the chronograph. This will increase the accuracy and allow for much more efficient code. I would like to make a smaller version of this chronograph, but it is pretty tough to make a lot smaller due to the 16x2 LCD Display. Perhaps I will look into using 7-Segment Displays as a means of relaying the data to the user.
If you have any questions or concerns about this project, send me a message or post a comment and I will get back to you as soon as I can. I may have missed some parts in the Instructable (some parts may be unclear or worded funny) so don't be afraid to ask for help or guidance. The more feedback I get, the better this Instructable will become.
Well, this concludes my first Instructable. As I said before, I am open to any constructive criticism, as I know there will be many spots in the Instructable that I can "touch up". Thanks for having a look!