Geschwindigkeitsmesser-Arduino

Um die Geschwindigkeit von Pfeilen oder Projektilen bestimmen zu können, habe ich mir auf Arduino-Basis einen Geschwindigkeitsmesser gebaut. Dieser basiert auf 2 Laserlichtschranken. Fällt die Intensität an der Eingangs-Photodiode (Typ SFH-203) unter einen bestimmten Wert (konkret 95% des Ausgangswerts), so wird die Zeitmessung gestartet. Gestoppt wird diese, wenn die Intensität an der Ausgangs-Photodiode wieder unter diese 95%-Schwelle fällt. Die Flugzeit t zwischen den beiden Lichtschranken wird dann am 16 x 2 Display in µs angegeben. Aus dem Abstand s der beiden Laserlichtschranken und der Zeit t ergibt sich für die Geschwindigkeit des Projektils v = s/t.

Um den Aufbau flexibler zu gestalten verwendete ich Matador-Holzbausteine. So lassen sich etwa beide Lichtschranken einfach von der Basis trennen, wenn man diese etwa an besonderer Position anbringen möchte/muss. Die beiden Lasermodule sind für 3V ausgelegt. Dadurch kann man sie direkt in Serie an den 5V-Pin des Arduino anschließen. Damit die Lichtschranken auch auf kleine Projektile reagiert, habe ich die Eingänge zu den beiden Photodioden mittels Lochblenden verkleinert. Betrieben wird der Geschwindigkeitsmesser mittels zweier 18650 Liion-Zellen.

 


Arduino-Code:

#include <LiquidCrystal_I2C.h>
#include <Wire.h>

LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display. ACHTUNG: Adresse kann auch 0x3F sein !!!

// Anschlüsse:
// GND - GND
// VCC - 5V
// SDA - ANALOG Pin 4
// SCL - ANALOG pin 5

unsigned long time_start;
unsigned long time_end;
unsigned long time;

int PD_start;      // value of the start-Photodiode
int PD_end;        // value of the end-Photodiode
int Werte[100];
long start;
int i;

float velocity;     // velocity of the projectile
float multiplier;   // multiplier of the PD-value to start or finish the measurement
float distance;     // distance between the two PDs

// settings for faster analogread:

//  ADPS2     ADPS1    ADPS0     Division factor
//    0         0        0              1          nicht schneller als 2
//    0         0        1              2
//    0         1        0              4
//    0         1        1              8
//    1         0        0             16
//    1         0        1             32
//    1         1        0             64
//    1         1        1            128   (Standard)



#define FASTADC 1

// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif



// ===========================
// =======   SETUP   =========
// ===========================

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

     #if FASTADC

    /*
    // set prescale to 32
    
    sbi(ADCSRA,ADPS2) ;      // ADPS2  auf  1  gesetzt
    cbi(ADCSRA,ADPS1) ;      // ADPS1  auf  0  gesetzt
    sbi(ADCSRA,ADPS0) ;      // ADPS0  auf  1  gesetzt
    */
    
    // set prescale to 8
    
    cbi(ADCSRA,ADPS2) ;      // ADPS2  auf  0  gesetzt
    sbi(ADCSRA,ADPS1) ;      // ADPS1  auf  1  gesetzt
    sbi(ADCSRA,ADPS0) ;      // ADPS0  auf  1  gesetzt
    
    
    #endif

    lcd.begin();        // initialize the lcd
    lcd.backlight();
    lcd.setCursor(0,0);
    lcd.print("Geschwindigkeits");
    lcd.setCursor(0,1);
    lcd.print("messer");
    
    delay(3000);
    
    lcd.setCursor(0,0);
    lcd.print("                ");
    lcd.setCursor(0,1);
    lcd.print("                ");

    
    multiplier = 0.95;            // the PD-values have to be 5% lower than the values without projectile to start and finish the measurement

    distance = 0.258;             // distance in meters between the two PDs

    Serial.print(analogRead(A0));
    Serial.print("   ");
    Serial.println(analogRead(A1));
    delay(100);
    
    PD_start = analogRead(A0);   // measuring the brightness of the starting-PD without projectile
    delay(20);
    PD_end = analogRead(A1);     // measuring the brightness of the ending-PD without projectile
    delay(20);

    Serial.print("PD-start: ");
    Serial.print(PD_start);
    Serial.print("  ,  PD-end: ");
    Serial.println(PD_end);

    lcd.setCursor(0,0);
    lcd.print("PD1: ");
    lcd.print(PD_start);
    lcd.setCursor(0,1);
    lcd.print("PD2: ");
    lcd.print(PD_end);
    
    delay(5000);

    lcd.setCursor(0,0);
    lcd.print("ready for shoot");
    lcd.setCursor(0,1);
    lcd.print("...             ");

    delay(40);    
   }



// ===========================
// =======    LOOP   =========
// ===========================
   
void loop()
   {
    while(analogRead(A0) > PD_start * multiplier)
       {
        // waiting for the projectile
       }

    time_start = micros();      // start-time in µs

    while(analogRead(A1) > PD_end * multiplier)
       {
        // waiting for the projectile
       }
    
    time_end = micros();        // end-time in µs
    
    time = time_end - time_start;   // flight-time in µs
    
    //time = 123456;
    
    /*
    Serial.print("Time: ");
    Serial.println(time);
    */
    
    velocity = distance * 1000000 / time;  // velocity of the projectile in m/s

    lcd.setCursor(0,0);
    lcd.print("                ");
    lcd.setCursor(0,1);
    lcd.print("                ");
        
    lcd.setCursor(0,0);
    lcd.print("t = ");
    lcd.setCursor(4,0);
    lcd.print(time);
    lcd.print(" us");
     
    lcd.setCursor(0,1);
    lcd.print("v = ");
    lcd.setCursor(4,1);
    lcd.print(velocity, 2);
    lcd.print(" m/s");

    delay(10);

    
    // test for fast-analogread
    /*
    Serial.print("ADCTEST: ") ;
    
    start = micros();
       
    for (i = 0 ; i < 100 ; i++)
       Werte[i] = analogRead(A0);
    
    //delay(16);
    Serial.print(micros() - start);
    Serial.println(" microsec (100 calls)") ;
    */
    
   }