Shooting Chrony second screen and micro SD card data logger

So I have a shooting chrony beta model chronograph, for those who don't know its a device that measured the speed of a projectile, this model has a few functions the others don't like 60 shot memory and the ability to display speeds in feet per second (fps) and meters per second (fps)

Now this thing was designed 30 years ago and for its time it was awesome, for its time...
Today in the world of bluetooth, memory card storage, apps and what not this chronograph is showing its age. Don't get me wrong it works flawlessly but I would like a few modern features such as a memory card to store the days shot at the range and a screen I can put on my bench.

so the project is this: build an Arduino powered second screen to connect to the serial port on the chronograph to display the shot speed and save that info to a memory card. At this point I want to keep it simple but once I have a working script there are a few other things I would like to add but for now just the basics.

Ive played about with it for a while now and I'm making some progress, Using the info on

http://noplabs.com/index.html

and

I was able to make a cheap interface cable and using a serial terminal program (GoSerial, I'm a Mac user) I am able to see each shot displayed on my MacBook.

So this got me thinking, an Arduino can natively read serial data so I connected the cable to the Arduino with using the D0-RX and D1-TX pins and opened GoSerial and each shot is displayed (see pic) so the hardware part of this seems to be straight forward.

I have this LCD shield Arduino_LCD_KeyPad_Shield__SKU__DFR0009_-DFRobot
and was able to upload the test sketch and it works so this is the lcd I plan to use. I have the TF card shield which seems easy to wire up.

My problem is I have no idea where to start on the script. I have the one for the lcd test script and thinking I should be able to modify it and use a gps to lcd script? I just have no idea where to start or even an example to use to get me started. Can any one help me please?

shooting crony website: http://www.shootingchrony.com

Screen Shot 2017-07-08 at 6.04.15 pm.png

Break the project into smaller parts. Lets see a sketch that reads one line from the Crony serial into a string. I don't remember if I linked this before but, serial input basics.

groundFungus:
Break the project into smaller parts. Lets see a sketch that reads one line from the Crony serial into a string. I don't remember if I linked this before but, serial input basics.

Thanks for the link, that advice dose make sense, 1, get it to read the serial data, 2, get it to send serial data, 3 print that data to an lcd, 4, send that data to a TF card

Ok this is what I have so far, I've modified a sketch I found for displaying data sent via serial to an LCD with changes to work with the pin out of my LCD and the correct rate of 4800 set to match the chronograph.

I can open the serial monitor in the Arduino software and type a what ever I like and have it appear on the second line. So next I connect it to the chronograph to see if I get an output on the screen and I have had some success! the shot data is displayed, if you check the first photo I put up the shot data in the serial monitor for example looks like -01-, 21311V, 56.80Vf

However there is a catch, there isn't enough room on the screen to display the whole string of data. It cuts off the last portion which is the part I want to keep, its the speed. not sure what the "V" means but the "f" is fps.
I need to work out how to keep the -01- as this is the shot number and loose the next 5 digits which I have no idea what it is and display the last 6 digits and add "fps" to the end of the string (i.e. 1234.56 fps) so the data on the screen looks like -01-, 1234.56 fps.

Anyone got any ideas on how I should modify the script to do what I want?

/*

 http://arduino-er.blogspot.com/
 
Example of using 16x2 LCD display
 Read from Arduino Serial port, and write to 2x16 LCD

*/

#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

void setup() {
 // set up the LCD's number of columns and rows:
 lcd.begin(16, 2);
 // Print a message to the LCD.
 lcd.print("shot data");
 
 Serial.begin(4800);
}

void loop() {
 if(Serial.available()){
   lcd.setCursor(0, 1);
   lcd.print("               ");
   delay(100);
   lcd.setCursor(0, 1);
   while(Serial.available() > 0){
     lcd.write(Serial.read());
   }
 }
}

Hi,

Please read the first post in any forum entitled how to use this forum.
http://forum.arduino.cc/index.php/topic,148850.0.html then look down to item #7 about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

Thanks.. Tom.. :slight_smile:

TomGeorge:
Hi,

Please read the first post in any forum entitled how to use this forum.
http://forum.arduino.cc/index.php/topic,148850.0.html then look down to item #7 about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

Thanks.. Tom.. :slight_smile:

done :slight_smile:

You need to read in the entire string* and parse the data that you want from it. The third example in the Robin2's serial input basics shows how. The start marker would be the '-' that starts every data string and the end marker would be The carriage return ('\r') or line feed ('\n') that ends each line. Once you have the data in a string you can use the technique in example 5 to parse the data into chunks. You can then pull out the numbers that you want and format the data for displaying on the LCD (or saving to SD) or if an error, ignore it or display an error message on the LCD.

*note the small s string, not String. The small s string is a "c string" or null terminated character array and, when working with Arduino, is the preferred way to handle character data. Capital s String objects are, maybe, easier to use but can cause memory fragmentation if not used with care.

Thanks ground fungus, ill do some reading and see if I cant tweak the code

I've been staring at the code in example 3 and for the life of me I don't get it, how dose the code know what to keep and what to ditch if it docent have <> around it when sent to the Arduino? if the data coming in from the serial had < and > around it then it might work? I want to keep the first 4 characters, ditch the next 6 charactersthen keep the last 7, if I read it right the solution is in this bit of code?

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;

else if (rc == startMarker) {
            recvInProgress = true;

You can change the start and end markers to suit your situation. From the screenshot that you posted, each line (except the boot message) begins with '-' (a minus sign).
Change

char startMarker = '<';

To.

char startMarker = '-';

Every line ends with a carriage return ('\r') and line feed ('\n'). So change the end marker to '\r'.

char endMarker = '\r';

Now read in the whole line. The data from the line will be in the null terminated character array (string) receivedChars. Now using the technique in example 5 split the line into its parts using the comma (',') as the delimiter. You will end up with an array of strings. You can then use atoi() or atof() to pull the numbers out.

Since you seem to be really trying to learn I modified Robin2's serial input basics, example 5, code to read and parse your data. I wouldn't usually do this but strtok() is hard to learn (for me anyway) so I thought that this would help. I based the code on the data in your screenshot in an earlier post. Sketch reports shot number and velocity to serial monitor and will trap the -Err- error and print a message.

You will need to set the right serial port up, too. If testing with serial monitor, make sure that line endings are set to carriage return or carriage return and line feed.

// modified serial input basics code (http://forum.arduino.cc/index.php?topic=396450).  
//Thanks to Robin2
// Example 5 - Receive with start- and end-markers combined with parsing
// modified to read Chrony shot velocity unit by groundfungus

const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing

// variables to hold the parsed data
int shotNumber = 0;
char notUsed[12];
float shotVelocity = 0.0;
boolean error = false;
boolean newData = false;

//============

void setup() 
{
  Serial.begin(9600);
  Serial.println("This sketch will read shot number and velocity form Chrony");
  Serial.println("Will print ERROR for a read error");
  Serial.println();
}

//============

void loop() 
{
  recvWithStartEndMarkers();
  if (newData == true)
 {
    strcpy(tempChars, receivedChars);
    // this temporary copy is necessary to protect the original data
    // because strtok() used in parseData() replaces the commas with \0
    parseData();
    if(error == true)  // if there was an error print message 
    {
      Serial.println("ERROR");
    }
    else // no error, print data
    {
    showParsedData();
    }
    newData = false;
  }
}

//============

void recvWithStartEndMarkers() 
{
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '-';  //*************  changed start marker to -
  char endMarker = '\r';   //*************  changed end marker to \r
  char rc;

  while (Serial.available() > 0 && newData == false) 
  {
    rc = Serial.read();

    if (recvInProgress == true) 
    {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) 
        {
          ndx = numChars - 1;
        }
      }
      else
      {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

    else if (rc == startMarker) 
    {
      recvInProgress = true;
    }
  }
}

//============

void parseData() 
{      // split the data into its parts

  error = false; // reset error flag
  char * strtokIndx; // this is used by strtok() as an index

  strtokIndx = strtok(tempChars, ",");     // get the first part - the shot number or error
  if(strchr(tempChars, 'E'))  // if there is an E then error
  {    
    error = true;
    return;
  }
  
  shotNumber = atoi(strtokIndx); // get numeric part

  // get and ignore middle part to keep place in the string
  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off   
  
  strtokIndx = strtok(NULL, ",");
  shotVelocity = atof(strtokIndx);     // convert this part to a float
}

//============

void showParsedData()  
{
  Serial.print("Shot Number ");
  Serial.print(shotNumber);
  Serial.print("   Shot Velocity  ");
  Serial.println(shotVelocity);
}

Thanks ground fungus, that code works perfectly in the serial monitor :slight_smile: I am now going to try and get it to print it onto a lcd screen and hopefully with all the footnotes in the example I should be able to get it working.
thanks heaps for your help

Hi Kayjay,
I too have a Shooting Chrony and would like to know how you are going with this project?
I have found that under certain lighting conditions the readout display is difficult to read and would also like to make a remote display.

KayJay:
Thanks ground fungus, that code works perfectly in the serial monitor :slight_smile: I am now going to try and get it to print it onto a lcd screen and hopefully with all the footnotes in the example I should be able to get it working.
thanks heaps for your help

Hi mate, Due to family commitments I had to put the project down but was thinking about it just the other day and thought I would look over the code I wrote and uploaded. Basically I could get the Arduino to read the info via the ttl output only it was too long to display properly on the 16x2 screen I was using. I now have a 3D printer and have been getting into the whole diy thing with it so I'm keen to finish the project. My biggest problem is simply my lack of skills and full understanding of the Arduino language.

What do you need help with?

Hi KayJay,
Two minds think alike, I too have purchased a 3D printer to do among other projects, make a case for this project once finished. I'm using the display and keyboard and so far have got it printing to the screen and to the serial monitor. I plan to use the keys to operate the ST and FU keys on the Shooting Chrony Beta.

Hi groundFungus,
I'm building a very similar project to KayJay using the code that was available here. I have modified some of the code but come across some problems due to my lack of under standing of coding.

(Please Note. I have note been firing a firearm in the house, I have been blowing 6mm wooden dowel pieces in a brass tube across the Chroney, it is far too dangerous and wasteful)

Some background to the Shooting Chrony:
The Chrony has two optical gates that the projectile must pass across to calculate the velocity.
If the Chrony detects the projectile at gate 2 but, not at gate 1 it displays Err-1
If the Chrony detects the projectile at gate 1 but, not at gate 2 it displays Err-2
If the projectile passes over both, the velocity is displayed.

I would like my Arduino Nano project to display either Error 1, Error 2 or Shot number and Velocity.

I'm having two problems:

  1. The program is unable to determine the difference between Err-1 and Err-2
    Code from the Chrony via serial is eg: -02-Err-1 or -02-Err-2
    -02- is for the shot number and is irrelevant here.
    The LCD and Serial monitor is displaying: ERROR 1

  2. Once the system is powered up and shot across it I get from the Serial monitor:

Data available
Data available
Data available
10-, 140570V, 86.11Vf
found char E
ERROR 1
Data available
Data available

Error 1 is displayed, take the next shot

Data available
Data available
Data available
10-, 140570V, 86.11Vf10-,
found char E
ERROR 1
Data available

Error 1 is displayed, take the next shot

Data available
Data available
Data available
10-, 140570V, 86.11Vf10-,
found char E
ERROR 1
Data available

There is a problem with the if statements and the fact the data (10-, 140570V, 86.11Vf) is not being updated, even thou the Chrony is working correctly.

Code:

// modified serial input basic code (http://forum.aruino.cc/index.php?topic=396450).
// Example 5 - Receive with start- and end - markers combined with parsing
// modifies to read Chrony shot velocity unit

// include the library code:
#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

const byte numChars = 32;
char recievedChars[numChars];
char tempChars[numChars];   //temporary array for use when parsing

// variables to hold the parsed data
int shotNumber = 0;
char notUsed[12];
//float shotVelocity = 0.0;
int shotVelocity = 0;

boolean newData =false;   //set at start of program

//===========================================================

void setup() {
  Serial.begin(4800);  // put your setup code here, to run once:
  lcd.begin(16, 2);   // set up the LCD's number of columns and rows:
  Serial.println("This sketch will read shot number and velocity from Chrony"); //Write text to serial console
  Serial.println("Will print ERROR for a read error");  //Write text to serial console
  Serial.println();
  lcd.print("Ready");
  }

void loop() 
{
  // put your main code here, to run repeatedly:
  recvWithStartEndMarkers(); 
  if (newData == true) //Boolean test
  {
    strcpy(tempChars, recievedChars);  //this tempoary copy is necessary to protect the original data because strtok() 
    // used in parseData() replaces the commas with \0
    // copy data in recievedChars to tempChars
    parseData();
//     Serial.println("Data available");

        showParsedData();

   newData = false;  // re-set newData Flag
//   Serial.println("No Data available");
  }
}

//============================================================

void recvWithStartEndMarkers()
{
  static boolean recvInProgress = false;
  static byte ndx =0;
  char startMarker = '-';  //**** changed start marker to -
  char endMarker = '\r';   //**** changed end marker to \r
  char rc;

   while (Serial.available() > 0 && newData == false)   // read all through and we have New data then exit
   {
    Serial.println("Data available");
    rc = Serial.read();   // this is our data, re4ad serial data and stick it in rc
    if (recvInProgress == true)
    {
      if (rc != endMarker)    // is the rc character Not Equal to \r our end marker?
      {
        recievedChars[ndx] = rc;
        ndx++;    // increment a counter ndx
        if (ndx >= numChars)
        {
          ndx = numChars - 1;
        }
      }
      else
      {
       recievedChars[ndx] = '\0'; //terminate the string
       recvInProgress = false;
       newData = true;
       Serial.println(recievedChars);   // shows what was Rx __--[]-10-,  152116V,    79.57V
     }
   }
    else if (rc == startMarker)
    {
      recvInProgress = true;
    }
  }
}

//===============================================

void parseData()
{ 
 
   char * strtokIndx; // this is used by strtok90 as an index
  
   strtokIndx = strtok(tempChars, "-");   // get the first part - the shot number or error
   
      if (strchr (tempChars,"E"));   // does it have the 'Err' word in it? check    
      {
        Serial.println("found char E");
         if(strchr (tempChars,"1"));   // if it has a 1 it is Err-1 print this
         {
          Serial.println("ERROR 1");
          lcd.clear();
          lcd.setCursor(6,0);
          lcd.print("ERROR 1");
          delay(2500);
 //         lcd.clear();
          return;
         }

         if(strchr (tempChars,"2"));   // if it has a 2 it is Err-2 print this
         {
          Serial.println("ERROR 2");
          lcd.clear();
          lcd.setCursor(6,0);
          lcd.print("ERROR 2");
          delay(2500);
          lcd.clear();
          return;
         }
      }
  Serial.println("found No char E, 1, or 2");       
  shotNumber = atoi(strtokIndx);  // get numeric part
  
  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off to get and ignor middle part to keep place in the string

  strtokIndx = strtok(NULL, ",");   // get last part of string
  shotVelocity = atof(strtokIndx);  // convert this part to a float
//  shotVelocity = atoi(strtokIndx);  // convert this part to a int
}

//==============================================

void showParsedData()
{
  if(shotNumber == 0)
  return;
  Serial.print("Shot Number ");
  Serial.print(shotNumber);
  
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Shot ");  
  lcd.print(shotNumber);

  
  Serial.print("   Shot Velocity  ");
  Serial.println(shotVelocity);
  
  lcd.setCursor(0,1);
  lcd.print("Vel. ");  
  lcd.print(shotVelocity);  
}

Could you please help?

groundFungus:
What do you need help with?

I need to pull all my gear out and give it another go, You helped heaps with the code and when i ran the code on my computer i was able to display exactly what i wanted, i just could never get it to work on the 16x2 screen i was using. Im good with the hardware side just the software side of things had me lost.

Glad to hear I was able to help someone. I'm waiting for groundFungus to help me with the problem I'm having currently. Is there a way I could get him to help with my code? I was hoping the post above was what I had to do.
Regards,
countpv

I don't see anything wrong with the code on first look, but I have had a long day and my brain is a bit fried. I will look again later and try to help.