Introduction: Air Rifle Chronograph, Chronoscope. 3D Printed

About: Hi, i'm electronic technician but it's my hobby too. I like to do and try many projects just for fun :)

Hi everyone, today we will revisit a projet i have done in 2010. An Air Rifle Chronograph. This device will telling you the speed of a projectile. Pellet, BB or even air soft BB plastic ball.

In 2010 i bought an air rifle for fun. Was hitting cans, bottles, aim. I know that the speed of this gun was maximum 500 feet/s. Because it's the canada's law. Some stronger air rifle are available but you need to have a licence for and you can't buy those thing at Walmart.

Now i had this licence, i could buy another one. But short story, the same gun was available to the U.S. at 1000 feet/s. WHAT!? The same gun ? yes... In canada, the stroke have a hole in it and the spring is softer.

First thing to do is fill up the hole. That's what i done with solder. Next thing to do was to order a replacement spring. But wait... what is the current speed of my new toy ? Is the spring really necessary ? I dont know and i want to know. I want to know now but how ?

That's why i did this project. All i needed was 2 sensors, a uC and a display and we are in business.

Last week, i saw my old blue chronograph on a shelf and i talk to myself:"Why dont share this and do an instructable with it ?" And by the way, we could rise the accuracy and add a battery indicator. Put 1 button instead of 2 for on/off. All surface mount. We are now in 2020!

So there it is... let's begin!

Step 1: Feature

-Pellet speed


-20 mhz running, huge accuracy

-Auto off

-Battery voltage displayed

-schematic available

-pcb available

-parts list available

-STL available

-C code available

Step 2: Theory of Operation and Accuracy

-We have a uC running at 20Mhz. The oscillator used is a TCX0 +-2.5 ppm

-We have 2 sensors at 3 inches far from each other.

-The projectile hit the first sensor. uC start counting (timer1)

-The projectile hit the second sensor. uC stop counting.

-uC check timer1 value, do the math and display speed and velocity.

I'm using 16 bit timer1 + the overflow flag tov1. 17 bit total for 131071 "tic" for a full count.

1/20 mhz = 50 ns. Each tic is 50ns

131071 x 50 ns = 6.55355 ms to do 3 inches.

6.55355 ms x 4 = 26.21 ms to do 12 inches.

1/26.21 ms = 38.1472637 feet/s

This is the slowest speed the device can mesure.

Why 20 mhz ? Why dont using the internal 8 mhz or even a cristal ?

My first device was using the internal oscillator. Was working but this one wasn't accurate enough. The variation is too huge. A cristal is better but temperature is varying frequency. We can't do an accurate measurement device with that. Also, more the frequency is high, more tic will be count for the same speed. The sampling will be better to have a very good accuracy. Because a tic isn't dividable, the loss is little if the duty cycle is quick.

At 20 MHz we have steps of 50 ns. Do we know how much accurate it is 50 ns for a projectile at 38 ft/s.

38.1472637 ft/s divide by 131071 = 0,000291042 feet

0,0003880569939956207 feet x 12 = 0,003492512 inches

1/0,003492512 = 286.37 ". In other word. At 50 ft/s we have a accuracy of +- 1/286 " or +- 0,003492512 inches

But if my oscillator is the worst and running at 20 mhz +2.5 ppm is it ok ? Let's find out...

2.5 ppm of 20 000 000 is: (20000000/1000000) x 2.5 = 20000050 Hz

So worst case scenario we have 50 more clock on 20 mhz. It's 50 clock on 1 seconde. How many tic more on timer1 if pellet is doing same speed ( 38.1472637 feet/s or 6.55ms) ?

1/20000050 = 49.999875 ns

49.999875 ns x 131071 = 6,553533616 ms

6,553533616 ms x 4 = 26.21413446 ms

1/26.21413446 ms = 38.14735907 feet/s

So we have 38.14735907 feet/s instead of 38.1472637 feet/s

Now we know that 2.5 ppm doesn't affect the result.

Here is some exemple of different speed

For 1000 ft/s

1000 ft/s x 12 is 12000 inches/s

1 second for 12000" how many time to do 3" ? 3x1/12000 = 250 us seconds

250 us / 50 ns = 5000 tic.

Timer1 will be at 5000

uC do the math and 1000 ft/s is displayed. So far so good

For 900 ft/s

900 ft/s is 10800 "/s

3x1/10800 = 277.77 us

277,77 ns / 50 ns = 5555,5555 tic

Timer 1 will be at 5555

uC do the math and 900,09 will be displayed instead of 900

Why ? because timer 1 is at 5555 and 0,5555 is lost. Tic on timer aren't dividable.

We have an error fo 0,09 on 900 ft/s

0,09/900x100 = 0,01% error only

For 1500 ft/s
1500 ft/s is 18000 "/s 3x1/10800 =166.66 us

166.66 us / 50 ns = 3333.333 tic Timer 1 will be at 3333

uC do the math and 1500.15 will be displayed instead of 1500 it's .15/1500x100= 0,01%

For 9000 ft/s

9000 x 12 = 180000 inches / s

3x1/180000 = 27.7777 us

27.77 us / 50 ns = 555,555

Timer1 will be at 555 and 4/(1/555x50ns) will be displayed 9009,00 will be displayed

Here error is of 9 feet/s on 9000 = 0,1%

As you can see % error is rising when speed is higher. But stay < 0.1%

Those results are very good.

But accuracy isn't linear. At 10000 ft/s it'is 0,1 %. Good new is we never test a 10,000 ft/s pellet.

Another thing to keep in mind. When an interrupt happen, uC always finish last instruction before enter in interrupt. This is normal and all uC do this. If you code arduino, in C or even assembler. Most of the time you will wait in a forever loop... to wait. Problem is, in a loop we spend 2 cycles. Normally this isn't important. But in our case. YES, each tic is important. Let's look a infinite loop:



rjmp loop

In C:

while (1){}

In fact C compiler use rjmp instruction. RJMP is 2 cycles.

That means if the interrupt happen to the first cycle, we loose one cycle(tic)(50ns).

My way to fix that is to add many nop instruction in the loop. NOP is 1 cycle.







rjmp loop

If the interrupt happen on a nop instruction. We are ok. If it happen on the second cycle of rjmp instruction we are ok. But if it happen on the first cycle of rjmp instruction, we will lost one tic.Yes it's just 50 ns but like you can see above, 50 ns on 3 inches isn't nothing. We can't correct this by software because we dont know when exactly the interrupt happen. It's why in the code you will see a lot of nop instruction. Now i'm pretty sure that the interrupt will fall on a nop instruction. If i adding 2000 nop i have 0,05% to fall on the rjmp instruction.

Another thing to keep in mind. When interrupt happen. Compiler do many push and pull. But it's always the same number. So now we can do a software correction.

To conclude on this:

Accuracy for an average pellet of 1000 ft/s is 0,01%

100x more accurate than other 1% on the market. Frequency is higher and with TCXO, more accurate.

For exemple, 1% of 1000 ft/s is more or less 10 ft/s. It's a huge difference.

Step 3: Schematic and Parts List.

Here i implemented my one push button on/off circuit. (see my last instructable) This circuit is very handy and works very well.

I'm using an atmega328p. This one is programmed in C.

Display is a standard 2 lines lcd HD44780 compatible. 4 bit mode is used.

An 3.3v regulator is used to provide voltage to the TCXO 20mhz.

D1 is for lcd backlight. Optional. Battery will last longer if you doesn't install D1.

All resistors and caps are 0805 package

C1 .1uf 25v

C2 1uf 16v

C3 2.2uf 10v

C4 .1uf

C5 .1uf

C6 .1uf

C7 1uf

C8 .1uf

C9 .1uf

C10 .1uf

D1 1n4148 SM SOT123

D2 5.1v SOT123


IC2 MIC5225-5.0YM5-TR TPS70950DBVT SOT23-DBV


R1 1M

R2 1M

R4 2.2k

R5 160

R6 160

R7 1M

R8 1M

U1 MIC5317-3.3 MIC5317 SOT23-5

U2 DMG6601LVT DMG6601LVT SOT23-6

Display lcd 2 line HD44780. No need to buy the i2c module.


2x Emitter OP140A

2x Reciever OPL530

Encoder: PEC11R-4215K-S0024 *Not forget to add 4x 10k resistors and 2x .01uf to do the encoder filter. see picture below

Step 4: PCB Gerber File

Step 5: Solder Your Pcb

With schematic help, solder all your component on the pcb. Each part or writen on pcb, r1, r2... and so on.

I do not have installed D1. This is for the lcd back-light. It's beautiful but battery life is affected. So i choose to keep the lcd back-light off.

Step 6: Programming the Atmega328p

Check here at step 12 to program the atmega328p. I provide here the .hex file for this.

Here is the avrdude program ready to program batch file. Only click on program usbasp.bat and the your usbasp is install correctly. All will be do automatically including fuse bit.

In this project i'm sharing also the C source code. Be aware that some note in it can be in french.

All needed files are available here

Step 7: Lcd Display

Install some tape and connect pcb and lcd together

Step 8: STL File

stl file here

Support is needed for enclosure, sensor pipe and rifle holder.

I have all printed at .2 mm high.


This rotary encoder is connected to the isp connector. it's used to change pellet weight and to turn on and off the device.

vcc isp pin 2 (pull up resistor)

Terminal A (yellow) go to the ISP pin 1

Terminal B (green) go to ISP pin 3

Terminal C (gnd) isp pin 6

I'm adding 2 pictures to see the difference between to have a filter vs no filter. You can see easily the difference between both.

The push button go to the pcb SW connector.

Step 10: Sensor Pipe


Sensor pipe must be Black and sensor receiver must be hide.

My first attempts was to have a beautiful red pipe. But this is tricky! It wasn't working at all. I figured out that outside light was incoming throw the plastic and receiver sensor was always on.

To have good result i had no choice to change the color to black.

Install receiver on top. And hide the clear plastic with black paint, tape or gum, black silicone.

Install emitter on bottom.. Check with a pen if sensors are well responding. Maybe the hole of the emitter will need to be enlarge a little bit. it will be depend of your printer calibration.

I have also better result in the shade. Avoid direct sunlight.

Step 11: Sensor Pipe Alternative

If you dont have a 3d printer, you can do the same with a copper pipe. It will be working very well to. Hard thing to do is the hole at exactly 3 inches and receiver and emitter must be aligned.

Step 12: A Pellet on Oscilloscope and Calibration.

This is a real pellet passing throw the pipe. Probe 1 yellow is sensor 1. Probe 2 purple is sensor 2.

Time/div is 50 us.

We can count 6 divisions of 50us. 50 us x 6 = 300 us (for 3 inches). 300 us x 4 = 1.2 ms for 1 feet

1/1.2ms= 833.33 ft/s

We can also see that sensor is normally at 5v. And can we block the emitter light, sensor fall to 0.

It's the way th uC start and stop his conter (timer1)

But to know exactly if the speed was accurate, i needed a way to mesure this.

To do software calibration and test the accuracy of this device, i used a 10 mhz reference oscillator. See my GPSDO on other instructable.

I feed another atmega328 with this 10 mhz. And program this one in assembler to send me 2 pulses each time i push a button to simulate a pellet. Exactly like we saw in picture but instead to have a real pellet it was another uC sending me 2 pulses.

Each time push button was pressed 1 pulse was sent and exactly 4 ms after another pulse was sent.

This way, i'm be able to balance the software compiler to have always 1000 ft/s displayed.

Step 13: More...

This is my first prototype of 2010.

To any questions or error report you can email me. English or french. I'll do my best to help.