Forum: Mikrocontroller und Digitale Elektronik Geschwindigkeitsmessung für Projektile mit/ohne Arduino


von Christoph E. (stoppi)



Lesenswert?

Hallo!

Vor einiger Zeit habe ich ja schon einen Geschwindigkeitsmesser auf 
Basis zweier Lichtschranken, einer bi- und a-stabilen Kippschaltung und 
einem CD4026 digital counter gebastelt. Funktioniert(e) eigentlich sehr 
gut. Das besondere war der aufwändige Strahlengang beider Laser zur 
Detektion des Projektils. Durch den zickzack-Verlauf konnten auch 
kleinere Projektile verlässlich und ohne genauere Ausrichtung detektiert 
werden. Habe dann noch eine einfachere Variante ohne Mehrfachreflexionen 
gebaut. Nun bin ich gerade dabei, einen Geschwindigkeitsmesser mit 
Arduino umzusetzen.

Als Lichtschranken kommen zwei Photodioden (wohl SFR203) in 
Sperrrichtung zum Einsatz, die von je einem 3V-Laser (2 in Serie an 5V) 
bestrahlt werden. Im Setup werden die Werte ohne Projektil eingelesen 
und dann für die Auslöseschwellen mit 0.95 oder weniger multipliziert.

Ein Analogread dauert normal rund 112 µs, kann aber durch andere Taktung 
deutlich beschleunigt werden, sodass ein Einlesevorgang nur noch 4 µs 
dauert.

Die Halterungen für die Lichtschranken bzw. den Arduino bastel ich aus 
Matador-Bausteinen, die habe ich noch von meinen "Kindern" übrig.


1
#include <LiquidCrystal_I2C.h>
2
#include <Wire.h>
3
4
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 !!!
5
6
// Anschlüsse:
7
// GND - GND
8
// VCC - 5V
9
// SDA - ANALOG Pin 4
10
// SCL - ANALOG pin 5
11
12
unsigned long time_start;
13
unsigned long time_end;
14
unsigned long time;
15
16
int PD_start;      // value of the start-PD
17
int PD_end;        // value of the end-PD
18
int Werte[100];
19
long start;
20
int i;
21
22
float velocity;     // velocity of the projectile
23
float multiplier;   // multiplier of the PD-value to start or finish the measurement
24
float distance;     // distance between the two PDs
25
26
// settings for faster analogread:
27
28
//  ADPS2     ADPS1    ADPS0     Division factor
29
//    0         0        0              1          nicht schneller als 2
30
//    0         0        1              2
31
//    0         1        0              4
32
//    0         1        1              8
33
//    1         0        0             16
34
//    1         0        1             32
35
//    1         1        0             64
36
//    1         1        1            128   (Standard)
37
38
39
40
#define FASTADC 1
41
42
// defines for setting and clearing register bits
43
#ifndef cbi
44
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
45
#endif
46
#ifndef sbi
47
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
48
#endif
49
50
51
52
// ===========================
53
// =======   SETUP   =========
54
// ===========================
55
56
void setup()
57
   {
58
    Serial.begin(9600);
59
60
     #if FASTADC
61
62
    /*
63
    // set prescale to 128
64
    
65
    sbi(ADCSRA,ADPS2) ;      // ADPS2  auf  1  gesetzt
66
    sbi(ADCSRA,ADPS1) ;      // ADPS1  auf  1  gesetzt
67
    sbi(ADCSRA,ADPS0) ;      // ADPS0  auf  1  gesetzt
68
    */
69
    
70
    // set prescale to 2
71
    
72
    cbi(ADCSRA,ADPS2) ;      // ADPS2  auf  0  gesetzt
73
    cbi(ADCSRA,ADPS1) ;      // ADPS1  auf  0  gesetzt
74
    sbi(ADCSRA,ADPS0) ;      // ADPS0  auf  1  gesetzt
75
    
76
    
77
    #endif
78
79
    lcd.begin();        // initialize the lcd
80
    lcd.backlight();
81
    lcd.setCursor(0,0);
82
    lcd.print("Geschwindigkeits");
83
    lcd.setCursor(0,1);
84
    lcd.print("messer");
85
    
86
    delay(3000);
87
    
88
    lcd.setCursor(0,0);
89
    lcd.print("                ");
90
    lcd.setCursor(0,1);
91
    lcd.print("                ");
92
93
    
94
    multiplier = 0.95;            // the LDR-values have to be 5% lower than the values without projectile to start and finish the measurement
95
96
    distance = 0.20;              // distance in meters between the two LDRs
97
    
98
    PD_start = analogRead(A0);   // measuring the brightness of the starting-PD without projectile
99
    delay(20);
100
    PD_end = analogRead(A1);     // measuring the brightness of the ending-PD without projectile
101
    delay(20);
102
103
    Serial.print("PD-start: ");
104
    Serial.print(PD_start);
105
    Serial.print("  ,  PD-end: ");
106
    Serial.println(PD_end);
107
108
    lcd.setCursor(0,0);
109
    lcd.print("PD1: ");
110
    lcd.print(PD_start);
111
    lcd.setCursor(0,1);
112
    lcd.print("PD2: ");
113
    lcd.print(PD_end);
114
    
115
    delay(6000);
116
117
    lcd.setCursor(0,0);
118
    lcd.print("ready for shoot");
119
    lcd.setCursor(0,1);
120
    lcd.print("...             ");
121
122
    delay(4000);    
123
124
    lcd.setCursor(0,0);
125
    lcd.print("                ");
126
    lcd.setCursor(0,1);
127
    lcd.print("                ");    
128
   }
129
130
131
132
// ===========================
133
// =======    LOOP   =========
134
// ===========================
135
   
136
void loop()
137
   {
138
    
139
    while(analogRead(A0) > PD_start * multiplier)
140
       {
141
        // waiting for the projectile
142
       }
143
144
    time_start = micros();      // start-time in µs
145
146
    while(analogRead(A1) > PD_end * multiplier)
147
       {
148
        // waiting for the projectile
149
       }
150
    
151
    time_end = micros();        // end-time in µs
152
    
153
    time = time_end - time_start;   // flight-time in µs
154
    
155
156
    //time = 123456;
157
    
158
    Serial.print("Time: ");
159
    Serial.println(time);
160
161
    velocity = distance * 1000000 / time;  // velocity of the projectile in m/s
162
163
    lcd.setCursor(0,0);
164
    lcd.print("                ");
165
    lcd.setCursor(0,1);
166
    lcd.print("                ");
167
        
168
    lcd.setCursor(0,0);
169
    lcd.print("t = ");
170
    lcd.setCursor(4,0);
171
    lcd.print(time);
172
    lcd.print(" us");
173
     
174
    lcd.setCursor(0,1);
175
    lcd.print("v = ");
176
    lcd.setCursor(4,1);
177
    lcd.print(velocity, 2);
178
    lcd.print(" m/s");
179
180
    //delay(1000);
181
182
    /*
183
    // test for fast-analogread
184
    
185
    Serial.print("ADCTEST: ") ;
186
    
187
    start = micros();
188
       
189
    for (i = 0 ; i < 100 ; i++)
190
       Werte[i] = analogRead(A0);
191
    
192
    //delay(16);
193
    Serial.print(micros() - start);
194
    Serial.println(" microsec (100 calls)") ;
195
    */
196
    
197
   }

: Bearbeitet durch User
von Wolfgang (Gast)


Lesenswert?

Christoph E. schrieb:
> Ein Analogread dauert normal rund 112 µs, kann aber durch andere Taktung
> deutlich beschleunigt werden, sodass ein Einlesevorgang nur noch 4 µs
> dauert.

Ein digitalReadFast() ist wesentlich schneller und immer noch langsamer 
als ein direktes Capture per Timer. Dazu brauchst du nur einen 
Komparator, dessen Schwelle du per TP-gefiltertem PWM anhand der 
initialen Messung vorgeben kannst.

von Blubb (Gast)


Lesenswert?

Wie ist die maximale Geschwindigkeit, die erfasst werden kann?

von Christoph E. (stoppi)


Lesenswert?

Danke einmal... Die Geschwindigkeiten liegen im Bereich 0-100 m/s 
(kartoffelkanone, coilgun etc.). Dies ist auch der Bereich der erfasst 
werden soll. Mit dem arduino lese ich die verstrichene Zeit in 
microsekunden ein. Die Auflösung ist da glaube ich 4 microsekunden. Von 
daher müsste der oben genannte Bereich aufzulösen sein, da die Flugzeit 
zwischen den beiden Lichtschranken minimal 2 Millisekunden beträgt.

: Bearbeitet durch User
von Volker S. (vloki)


Lesenswert?

Christoph E. schrieb:
> Durch den zickzack-Verlauf konnten auch
> kleinere Projektile verlässlich und ohne genauere Ausrichtung detektiert
> werden.

Interessant - Wie klein waren denn die kleineren Projektile?
bzw. hältst du es grundsätzlich für möglich den zickzack Vorhang so fein 
zu gestalten, dass man Diabolos (4,5mm) oder Pfeilspitzen (7mm) 
detektieren kann?

von Thomas (kosmos)


Lesenswert?

ich würde den IR-Sender (mit großen Strahlwinkel) und Empfänger auf 
einer Seite positionieren und die Gegenseite eher nicht reflektierend 
auslegen, das Projektil selber reflektiert dann die IR Strahlung. Das 
ganze 2 mal hintereinander. Der erste Punkt startet den Timer und der 
2te Punkt Captured den Wert im Timer, danach hast du zeit bis zum 
nächsten Schuss das Captureregister auszulesen und in eine 
Geschwindigkeit umzurechnen und anzuzeigen.

von Christoph E. (stoppi)



Lesenswert?

>Wie klein waren denn die kleineren Projektile?
>bzw. hältst du es grundsätzlich für möglich den zickzack Vorhang so fein
>zu gestalten, dass man Diabolos (4,5mm) oder Pfeilspitzen (7mm)
>detektieren kann?

Also die 7mm dürften kein Problem sein. Schau dir oben mein Bild 
"Geschwindigkeitsmesser_08" an. Die Steigung eines einzelnen Strahls 
entspricht genau der Hälfte des Abstands zweier benachbarter 
Reflexionen...

Danke für den Vorschlag mit der Reflexion. Ich probiere einmal den 
Aufbau mit Laserlichtschranken. Falls ich damit scheitern sollte, kann 
ich es noch immer ausprobieren. Ich möchte sie Sache halt so simpel wie 
möglich halten.

von OssiFant (Gast)


Lesenswert?

Volker S. schrieb:
> Interessant - Wie klein waren denn die kleineren Projektile?
> bzw. hältst du es grundsätzlich für möglich den zickzack Vorhang so fein
> zu gestalten, dass man Diabolos (4,5mm) oder Pfeilspitzen (7mm)
> detektieren kann?

Das ist für mich eine Frage des Winkels und der Aufweitung des 
Laserstrahls auf die sich ergebende Strecke.

von GEKU (Gast)


Lesenswert?

Ist die Anordnung mit dem Laserstrahl nicht sehr 
erschütterungsempfindlich?
Winkeländerungen summieren sich mit jeder Reflexion auf, oder?

Wie groß muss der Erfassungsbereich sein?

Könne man nicht einen Lichtstrahl mit einer Linse aufweiten und am 
anderen Ende mit einer Linse wieder konzentrieren.

Wenn der Lichtstrahl moduliert ist, ähnlich wie bei den 
IR-Fernbedienungen, dann könnte man das Umgebungslicht sehr leicht 
unterdrücken und das Nutzsignal sehr gut verstärken, digitalisieren und 
dem MC Eingang zur Verfügung stellen. Mit der Flanke einen Interrupt 
auslösen, die Zeit in der Interruptroutine speichern. Mit der zweiten 
Lichtschranke in der gleichen Art und Weise verfahren und die Werte 
subtrahieren.

von OssiFant (Gast)


Lesenswert?

GEKU schrieb:
> Könne man nicht einen Lichtstrahl mit einer Linse aufweiten und am
> anderen Ende mit einer Linse wieder konzentrieren

Entsprechend minimal wird auch die Reduktion der Strahlenergie durch das 
relativ kleine Geschoss sein - und entsprechend "feinfühliger" muss 
gemessen werden.

von GEKU (Gast)


Lesenswert?

OssiFant schrieb:
> "feinfühliger"

Man kann heute schon durch kleine Helligkeitsschwankungen Exo-Planeten 
entdecken und sogar ihre Größe bestimmen. Es ist nur eine Frage des 
Aufwandes.

von Raph (Gast)


Lesenswert?

Die Idee mit dem Lichtvorhang ist zwar gut, aber falsch umgesetzt!

Du musst normalerweise nur ein Lichtsensor nehmen und einen 
Differenzierer. Sobald die Kugel durchfliegt deckt sie mit ihrer Fläche 
einen Teil des ankommenden Lichtes aus der Umgebung ab (genau so wie man 
es mit dem Kepplerteleskop macht um extrasolare Planeten zu finden). Der 
Differenzierer gibt dir dabei einen Impuls aus.

von GEKU (Gast)


Lesenswert?

Raph schrieb:
> Der
> Differenzierer gibt dir dabei einen Impuls aus.

Dieser Impuls verstärkt auf Logikpegel könnte dann einen Interrupt 
auslösen und in der Interruptroutine die Zeit stoppen.

von Christoph E. (stoppi)



Lesenswert?

Der Aufbau ist soweit fertig und die Laser ausgerichtet. Jetzt warte ich 
nur noch auf die schnellen SFH203 Photodioden von reichelt. Müssten aber 
diese Woche noch ankommen.

Die beiden Lichtschranken kann ich vom Sockel abnehmen um sie dann ggf. 
variabel zu positionieren...

: Bearbeitet durch User
von Christoph E. (stoppi)



Lesenswert?

So, habe den Geschwindigkeitsmesser einmal mit bereits vorhandenen 
Photodioden unbekannten Typs ausprobiert. Er machte einige Probleme. 
Zuerst einmal konnte ich analogread() nicht bis aufs Maximum 
beschleunigen. Jetzt habe ich eine Einlesezeit pro analogread() von 9 
µs, was eigentlich auch mehr als reichen sollte. Dann gab es 
eigenartigerweise beim ersten Einlesen des Analogwerts auch Probleme, 
indem er einen zu niedrigen Wert einlas. Jetzt lese ich davor einfach 
einmal zusätzlich ein ohne den Wert dann zu verwenden.

Mit einer Gewindestange komme ich schon einmal auf Geschwindigkeiten um 
die 11 m/s. Seine Feuertaufe wird das Messgerät aber erst bei Verwendung 
der Kartoffelkanone oder des Druckluftgewehrs bestehen müssen...

: Bearbeitet durch User
von Christoph E. (stoppi)



Lesenswert?

Nachdem die Lichtschranke nur auf größere Projektile (d > 5mm) 
angesprochen hat, habe ich nun die Eintrittslöcher zu den Photodioden 
mit einer Abdeckplatte und einem 1.5mm Bohrer deutlich verkleinert. 
Jetzt spricht der Geschwindigkeitsmesser auch auf einen Zahnstocher an, 
wenn ich ihn durch die beiden Lichtschranken ziehe. Gedacht ist sie aber 
ohnehin für deutlich größere Armbrustpfeile, Nerfpatronen, Eisenkugeln 
oder eben Kartoffeln bzw. Bälle ...

: Bearbeitet durch User
von Christoph E. (stoppi)



Lesenswert?

Heute sind die SFH203 Photodioden von reichelt angekommen und ich konnte 
diese gleich einbauen. Trotz des relativ kleinen Eintrittlochs fallen an 
den beiden 47k Widerständen ohne Projektil die vollen 5V (analogread = 
1023) ab. Bei Abschattung liegen die Werte nur noch bei 2V (analogread = 
ca. 400). Als Schwelle zur Detektion sind 95% des Ausgangswerts 
eingestellt.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.