Jump to content


Photo

OpenChrony - open source, DIY chronograph


8 replies to this topic

#1 TantumBull

TantumBull

    Member

  • Moderators
  • 1,929 posts

Posted 25 January 2018 - 07:49 PM

*
POPULAR

firstcomp.jpg

 

I’m calling it OpenChrony. It’s an open source chronograph, compatible with nerf and paintball. It is Arduino-based, and the code is publicly available, as are the part files (.stl, .step and .sldpart coming soon). I’m hoping that others will improve the design, this is only the first functional version.

 

Write-Up:

 

Attached File  OpenChrony V1.5 Writeup.pdf   1.46MB   2511 downloads

 

 

V1.0:

 

Thingiverse

 

Attached File  OpenChrony.zip   751.42KB   1151 downloads

 

V1.0 Video

 

 

V1.5:

 

Attached File  OpenChrony1.5f.zip   753.69KB   1048 downloads

 

 

Updated part files coming soon


Edited by TantumBull, 20 February 2018 - 12:47 AM.

  • 2

#2 Frost999 flinging foam

Frost999 flinging foam

    Member

  • Members
  • 8 posts

Posted 29 January 2018 - 05:14 PM

Wow, now I need a 3d printer.



Frost999
  • 0

#3 Daniel Beaver

Daniel Beaver

    HQRSE CQCK

  • Moderators
  • 2,096 posts

Posted 30 January 2018 - 01:46 PM

Im reading through this, itll take me a bit.
  • 0

#4 TantumBull

TantumBull

    Member

  • Moderators
  • 1,929 posts

Posted 20 February 2018 - 12:48 AM

V1.5 Firmware is up. Accompanying file set will be up in the next week or so but existing files are fully compatible. Check first post for video. I've also formalized the write-up and uploaded a PDF.


  • 0

#5 meow121325

meow121325

    Member

  • Members
  • 125 posts

Posted 26 March 2018 - 01:21 PM

will a gamer kit from tech will save us all work for this


  • 0

#6 TantumBull

TantumBull

    Member

  • Moderators
  • 1,929 posts

Posted 26 March 2018 - 11:10 PM

will a gamer kit from tech will save us all work for this

 

I'm not familiar with that board or the chipset it uses. Whatever chip you use needs to have an I2C pin and 2 external interrupts, and the board needs the corresponding pinouts. Off-brand Arduino uno's are inexpensive, I recommend just picking one up if you're unsure about compatibility.


  • 0

#7 meow121325

meow121325

    Member

  • Members
  • 125 posts

Posted 27 March 2018 - 10:43 AM

 

I'm not familiar with that board or the chipset it uses. Whatever chip you use needs to have an I2C pin and 2 external interrupts, and the board needs the corresponding pinouts. Off-brand Arduino uno's are inexpensive, I recommend just picking one up if you're unsure about compatibility.

it is an arduino uno with an IR sensor chips and a LED board


  • 0

#8 Justin Andrews

Justin Andrews

    Member

  • Members
  • 21 posts

Posted 08 April 2018 - 12:40 PM

Hi. I noted that in your source code you are using a while loop with a digitalRead.

While this will work, you can optimise your code, as the while and especially the digitalRead are quite slow.
For a faster more accurate reading I recommend setting up Pin Interrupts, known as an ISR (Interrupt Service Requests) these interrupts can be raised internally in the Atmel AVR processor independent of code execution. On the arduino you can access these using the attachInterrupt() function.
( https://www.arduino....ttachinterrupt/ )

I have written my own chrony code in the past.
My Chrono code is below. I've bolded the interrupt parts/

 

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// If using software SPI (the default case):
#define OLED_MOSI   9
#define OLED_CLK   10
#define OLED_DC    11
#define OLED_CS    12
#define OLED_RESET 13
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);


// -------------------------------------------------------------------
// Interrupt Service Variables

const byte interruptPin1 = 3;
const byte interruptPin2 = 2;

volatile bool m_pin1_active = false;
volatile bool m_pin2_active = false;
volatile float m_time1 = 0;
volatile float m_time2 = 0;


// -------------------------------------------------------------------
// Variables

// distance between sensors = 170mm or 6.69291 inches
// distance between sensors 557742.5

unsigned long m_distance = 557742; // distance between sensors in inches

int m_numTimings = 0;

float m_fps[10];
float m_currentFPS = 0;
float m_avgFPS = 0;
float m_lowFPS = 99999.0;
float m_highFPS = 0;
float m_totalFPS = 0;

static String m_stringCurrent = "Current: ";
static String m_stringFPS = " FPS";
static String m_stringHi = "Hi:";
static String m_stringLow = ": Low:";
static String m_stringAvg = "Average: ";

// -------------------------------------------------------------------
// Interrupt Service Functions

void Pin1_ISR()
{
  m_pin1_active = true;
  m_time1 = micros();
}


void Pin2_ISR()
{
  m_pin2_active = true;
  m_time2 = micros();
}


// -------------------------------------------------------------------


void displayText( String string, int x, int y, int textSize = 1, int stride = 6)
{
  int textCursor = x;

  for ( int i = 0; i < string.length(); ++i)
  {
    display.drawChar(textCursor, y, string[i], WHITE, BLACK, textSize);
    textCursor += stride;
  }
}

void setup()
{

  // put your setup code here, to run once:
  Serial.begin(9600);
  // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
  display.begin(SSD1306_SWITCHCAPVCC);
 

  pinMode(interruptPin1, INPUT_PULLUP);
  pinMode(interruptPin2, INPUT_PULLUP);
  attachInterrupt( digitalPinToInterrupt(interruptPin1), Pin1_ISR, RISING );
  attachInterrupt( digitalPinToInterrupt(interruptPin2), Pin2_ISR, RISING );


  display.clearDisplay();

  pinMode(A0, INPUT);
}

void checkISRPins()
{
   if( m_pin1_active && m_pin2_active )
  {
    
    if( m_time2 > m_time1)
    {
      float timeDiff;
      timeDiff = m_time2 - m_time1;

      float fps = m_distance / timeDiff;

      m_currentFPS = fps;
      
      m_numTimings++;

      if( m_currentFPS < m_lowFPS )
      {
        m_lowFPS = m_currentFPS;
      }
      if( m_currentFPS > m_highFPS )
      {
        m_highFPS = m_currentFPS;
      }

      m_totalFPS += m_currentFPS;
 
      m_avgFPS = m_totalFPS / m_numTimings;

    }
    // reset ISR variables
    m_pin1_active = false;
    m_pin2_active = false;
    m_time1 = 0.0f;
    m_time2 = 0.0f;
  }
}

void displayResults()
{
     display.clearDisplay();
    
    String outString = "";

    outString = m_stringCurrent + m_currentFPS + m_stringFPS;   
    displayText(outString, 1, 1 );

    outString = m_stringAvg +  m_avgFPS + m_stringFPS;
    displayText(outString, 1, 11);

    outString = m_stringHi +  m_highFPS + m_stringLow + m_lowFPS;
    displayText(outString, 1, 21);
 
    display.display();  
}

void loop()
{
  checkISRPins();
  displayResults();
  delay(100);
}
 


Edited by Justin Andrews, 08 April 2018 - 12:48 PM.

  • 0

#9 TantumBull

TantumBull

    Member

  • Moderators
  • 1,929 posts

Posted 08 April 2018 - 11:32 PM

If you take a look at V1.5 you will find ISR's implemented. However, I still have a while loop that holds things up before the first gate is tripped. Which is unnecessary because the ISRs are present. While having that while loop in 1.5 doesn't affect accuracy, it does unnecessarily hold things up.

I'll look into how you got around the while loop. I got informed of another way to get around it on the Arduino forums but I haven't gotten around to implementing it. Either way the only end effect on the user is that the first gate needs to be tripped before pot test mode works properly, but you need to block the gates to get feedback in the first place, so I'm not worried about it.

 

One final thing I'd add is that you can totally get rid of the flag variables inside your ISR's, they are needless operations during a time-critical routine. You can have a function return various output depending on the result of math on your micros() readings, as in v1.5.


Edited by TantumBull, 09 April 2018 - 07:47 PM.

  • 0


0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users