Arduino Balistic Chronograph?

Hi I am in the process of starting my annual winter Arduino project, something for the coming dark nights.

I have designed and 3d printed the hardware mk1, which is basically a 15cm tube with a 15mm opening at one end to slot the rifle barrel in, with O rings for a snug fit, further down the tube there are four housings to hold two sets of IR emitters and detectors.

My plan is a sketch in which the timer starts when the first beam is broken, and stops when the second beam is broken.

The maximum resolution at this time is around 250mps, I have googled Arduino Balistic, there are a few around, what I am looking to do is start with a basic stopwatch and improve from there.

The problem I am encountering, is all the stopwatch sketches use the same button for Stop/Start and I can not get my head round how to modify them to use two.

Can anyone suggest a basic two button stopwatch sketch I can use as my foundation?

If anyone would like the stl file of the hardware to make one themselves, please ask and I will upload it.

Thanks in advance.

Have you considered that with 'O' rings and a snug fit on the barrel, that your 3d printed tube will be subjected to the barrel pressure?

Take a look at the input capture capabilities of Timer 2

The maximum resolution at this time is around 250mps

What does that mean, please?

AWOL:
Take a look at the input capture capabilities of Timer 2What does that mean, please?

Sorry mps = meters per second

"resolution of 250 m/s" means you can measure 0, 250, 500, 750, etc. Not too bad a resolution if you're nearing light speed, pretty poor for measuring the speed of a bullet.

I guess the best approach to do this measurement is through interrupts (scanning ports is far too slow, you may even miss events that way). Two pins, two separate interrupts. Timer set to no prescaler (i.e. counting clock ticks). When the first is triggered, set the timer to zero. When the second is triggered, read the current timer value. This way you get a resolution of 62.5 ns on a 16 MHz Arduino, and it's a matter of simple maths to get to the speed.

Of course it takes time for the interrupt to actually kick in, a few clock cycles, but the timer starts late by as many cycles as it stops late (+/- 1-2 cycles) so no problem there.

Again I apologise, I should have said around the 250 mark
So far I have come up with the following, which will also report back muzzle energy, based on a 8 grain pellet, this at the moment is hard coded but as I progress I hope to be able to select weight once a lcd is added.
I decided to go down the line of one button start/stop detectors in series, to keep tasks down to a minimum.

/*


// INCLUDE CHRONO LIBRARY : http://github.com/thomasfredericks/Chrono
#include <Chrono.h>

#define BUTTON_PIN 3

Chrono myChrono;
int previousButtonState;

void setup() {
  Serial.begin(57600);


  pinMode(BUTTON_PIN, INPUT);

  previousButtonState = digitalRead(BUTTON_PIN);
}

void loop() {

  int newButtonState = digitalRead(BUTTON_PIN);

  if ( previousButtonState != newButtonState ) {
    previousButtonState = newButtonState;

    if ( newButtonState == LOW && myChrono.hasPassed(1) ) {
      unsigned long FPS =  myChrono.elapsed() * 13.33333 / 3.37;
      unsigned long FtLbs = FPS * FPS * 8 / 450240; //450240 magic number ?????
      Serial.print("ms ");
      Serial.print( myChrono.elapsed() );
      Serial.println();
      Serial.print("MPS ");
      Serial.print( myChrono.elapsed() * 13.33333  );// multiply time same ratio as length travels to == 1m
      Serial.print("FPS ");
      Serial.print( myChrono.elapsed() * 13.33333 / 3.37  );// convert mps to fps
      Serial.print("Muzzle Energy Based on 8 Grain " (FtLbs ());




    }

    myChrono.restart();
  }
}

Is there a question?

Have you looked at the input capture capabilities of Timer 2?

Yes, I have looked at Timer 2 and will post my trial sketch shortly.
I was looking for suggestions how to improve current sketch.

JohnLincoln:
Have you considered that with 'O' rings and a snug fit on the barrel, that your 3d printed tube will be subjected to the barrel pressure?

The O rings simply stop it falling off :slight_smile: The barrel is 16mm in diameter and fires 5.5mm (.22) pellets the housing is 16mm id down its length, leaving 5.25mm gap all round the projectile, thankfully no back pressure of the escaping C02.

Now having a play with Timer 2

Having read keywords file I see there is

MsTimer2::set
MsTimer2::start
MsTimer2::stop

How do I pull the value of elapsed ?

andi968:
Now having a play with Timer 2

Having read keywords file I see there is

MsTimer2::set
MsTimer2::start
MsTimer2::stop

How do I pull the value of elapsed ?

No idea - I've never used MsTimer2 - where did you find it? What does it do?

I hope "Ms" doesn't stand for "Microsoft"

I found it within the Arduino library, not the one you meant was it :frowning:

MsTimer2 because it "hardcodes" a resolution of 1 millisecond on timer2

Not a lot of use at 250ms-1

Would you be so kind as to point me to the library you refer.

I haven't referred to any libraries.
Timer 2 is a hardware resource, documented in the processor datasheet.
Have a look at Nick Gammon's tutorial on using timers.

After a week of fine tuning, I have come up with the following.
It gives
Number of shots
FPS
FtLb
MPS
Joules

The sketch saves previous results, rearms and waits for next shot.

If anyone has any constructive ideas how to add to it, I would love to hear suggestions.

//AndiChrono copyright 2017 AGMSTANCLIFFE@GMAIL.COM

#define firstsensor_1 10
#define secoundsensor_2 11
unsigned long time1;
unsigned long time2;
float fps, elap, ms, joule, ftlb;

int counter_shots = 0; //After each shot 1++

void setup() {

  Serial.begin(9600);
  pinMode (firstsensor_1, INPUT);
  pinMode (secoundsensor_2, INPUT);
  digitalWrite(firstsensor_1, HIGH);
  digitalWrite(secoundsensor_2, HIGH);
  reset_variables();
}


void loop() {
  Serial.println("I am waiting for a shot - YOU can shoot!");
  while (digitalRead(firstsensor_1) == 0);
  while (digitalRead(firstsensor_1));
  time1 = micros();
  while (digitalRead(secoundsensor_2));
  time2 = micros();
  printserial();

}


void printserial() {
  Serial.print("Shot number:\t");
  Serial.println(counter_shots++ );
  elap = time2 - time1;
  fps = elap * 13.33333 * 3.28084;
  Serial.print("FPS\t");
  Serial.println(fps );
  
  ftlb = (8 * fps * fps / 450240    );// 8 Grain ammo 450240 magic number
  joule = ftlb * 1.356;
  ms = fps * 3.28084;
  Serial.print("Ft lb   ");
  Serial.println(ftlb );
  Serial.print("MPS   ");
  Serial.println(ms );
  Serial.print("Joules   ");
  Serial.println(joule );
}

void reset_variables() {
  time1 = 0;
  time2 = 0;
}

I'm sorry - I did of course mean Timer1.

Blame the brain-fart.

I can't really see the point of the functions printserial and reset_variables or all the globals.

For greater accuracy, read the ports directly instead of using digitalRead().

aarg:
For greater accuracy, read the ports directly instead of using digitalRead().

I dont have a clue how to do that :frowning:
I was thinking that any lag in digitalRead would equal out on each pin?

Do a search for "arduino port registers". You'll be able to find lots of tutorials.

It's quite easy, super fast, and if you can rid your sketch of all digitalRead() calls you can save a good number of bytes in total size.