Guten Abend zusammen,
ich habe derzeit ein, mehr oder weniger, kleines Problem bei meinem
Projekt bzw. stehe auf dem Schlauch und hoffe auf Hilfe ^^
In meinem Projekt benutze ich einen Ultraschallsensor (200lm450), einen
US-Treiber (PW0268) und einen Arduino. Das Ziel ist es eine
Distanzmessung unter Wasser durchzuführen. Das ganze funktioniert auch
ganz gut für Distanzen 20cm bis ~560cm. Ab ca. 6m funktioniert der
interne Komparator des US-Treibers nicht mehr, allerdings ist das
gefilterte Echo-Signal vor dem Komparator noch sehr "schön" zu sehen.
Ich möchte nun dieses gefilterte Echosignal, als analoges Signal, auf
den Arduino führen und auf die "Flanke" triggern. Daher habe ich mich
für den internen Komparator des Arduino UNO entschieden. Als
Referenzspanung führe ich ein PWM Signal über einen 10kOhm Widerstand
auf Pin D6 [AIN0] und von Pin D6 mit einem Kondensator auf GND für eine
DC Spannung. Als [AIN1] habe ich dann das analoge Signal (CH3).
Mit einem Interrupt möchte ich die Schwelle/Flanke erkennen und die Zeit
aufnehmen. Dabei ist noch das Problem, dass ich beim Programmstart auch
eine hohe Flanke habe (durch das "Ringing" des US-Sensors). Ich möchte
also die Flanke erkennen, sobald der Sensor im "horchen"-Modus ist. Als
einfache Lösung hatte ich mir gedacht, ich packe "einfach" ein
delayMicroseconds(400) rein, nachdem der Rechteck-Puls gesendet wurde.
Nur bekomme ich hier dann Zeitwerte von 408 µs zurück. Das dürfte ja
eigentlich nicht passieren, da die Referenzspannung zu dem Zeitpunkt
noch deutlich über dem Analogsignal hängt(?). Ebenfalls ändert sich an
den 408µs nahezu nichts wenn ich die Distanz mal auf 30cm verkürze bzw.
auf 80cm erhöhe. Ich denke mein Code ist dann fehlerhaft.
Vielleicht gibt es aber auch eine viel einfachere bzw. besssere Lösung?
Ansonsten könnte ich mir auch vorstellen, dass der Interrupt nicht ganz
so funktioniert wie ich mir das denke..
Angehängte Bilder
- Messungen für 70cm, 9m, 50m von links nach rechts [gemessen im Becken
2m x 60m]
- Testmessung mit Komparator Signal [gemessen in Behälter 1m x 1m]
CH1: Rechteck-Signal -> Impuls zum anregen des Sensors
CH2: Echo-Signal nach Treiber-internem Komparator.
CH3: Gefiltertes Echo-Signal, nach internem Bandpass und vor dem
Komparator
CH4: Referenzspannung für Arduino UNO Komparator (Gilt nur
Komparator-Bild, in den anderen Bildern stellt CH4 den Strom am Sensor
dar [Stromzange])
Datenblätterhttp://www.prowave.com.tw/pdf/undertx.pdf -> US-Sensor
http://www.farnell.com/datasheets/1714673.pdf -> Sensor-Treiber
Arduino Code für Komparator und Interrupt
1
#include"analogComp.h"
2
3
4
#define OutputPIN 13// Gibt Rechtecksignal auf Schaltung
5
#define echoPin 12 //Nimmt Echosignal auf
6
7
#define referenceVoltagePin 3 //reference signal for comparator [AIN0]
8
9
#define thresholdvalue 180 // 0=0V, 255 = 5V
10
//Referenzspannung in der Schaltung sind ~2V => Pegel von 102
11
12
volatilebooleanobstacle=false;
13
14
15
16
voidsetup(){
17
18
analogComparator.setOn(AIN0,AIN1);
19
analogWrite(referenceVoltagePin,thresholdvalue);
20
21
Serial.begin(9600);
22
23
pinMode(referenceVoltagePin,OUTPUT);
24
pinMode(OutputPIN,OUTPUT);
25
pinMode(echoPin,INPUT);
26
}//end-setup
27
28
29
voidloop(){
30
31
unsignedlongstart,ende,dauer=0;
32
33
34
35
analogComparator.disableInterrupt();//Interrupt soll nicht IMMER aktiv sein
36
Pulse();//Rechteck-Impuls, US-Sensor anregen
37
delayMicroseconds(400);//"Ringing" beim Start des Sensors auslassen
38
39
40
start=micros();
41
analogComparator.enableInterrupt(ownTest);//Interrupt starten, sobald Sensor im "horchen" Modus
Ergänzend zum obigen Kommentar würde ich den Ende-Zeitstempel direkt in
der ISR "ownTest" ausführen lassen - damit bist Du präziser.
Hinweis zur Terminologie: "Ringing" verwendet man eher bei
Resonanzeffekten; bei Dir liegt aber ein Nebensprechen vor - also
"Crosstalk".
Vielen Dank für die Antworten.
Die Änderung von der if() - Anweisung zur while(!obstacle) hat super
funktioniert :-)
Nach einigem rumprobieren habe ich noch gesehen, dass ich die Flag aus
dem Interrupt am Anfang der loop() nochmal zurücksetzen muss, da diese
sonst für immer auf "true" bleibt.
Nun bin ich auch schon fast zufrieden. Lediglich zeigt mir der
Zeitstempel aus dem Interrupt ca. 100µs zuviel an. Warum das passiert
kann ich nicht ganz nachvollziehen.
Als Referenzspannung speise ich nun direkt 3,3V vom Arduino ein. Ich
hatte hier kurz die Befürchtung, dass die PWM-Anweisung etwas Zeit
kostet und ich daher die 100µs zuviel hatte.. aber hier hat sich nichts
geändert.
Am Montag kann ich dann wahrscheinlich nochmal im 50m Becken messen und
schauen ob die ~100µs auch bei längeren Distanzen auftreten oder ob die
Abweichung doch größer wird.
1
#include"analogComp.h"
2
#define OutputPIN 13// Gibt Rechtecksignal auf Schaltung
3
4
5
volatilebooleanobstacle=false;
6
7
voidsetup(){
8
9
analogComparator.setOn(AIN0,AIN1);
10
pinMode(OutputPIN,OUTPUT);
11
12
Serial.begin(9600);
13
14
}//end-setup
15
16
17
voidloop(){
18
unsignedlongstart,dauer,ende=0;
19
20
analogComparator.disableInterrupt();//Interrupt soll nicht IMMER aktiv sein
21
obstacle=false;//obstacle bei erneutem loop() durchlauf zurücksetzen
22
23
start=micros();
24
Pulse();//Rechteck-Impuls, US-Sensor anregen
25
delayMicroseconds(300);//"Spitzen" des analogen Signals beim Start überspringen
26
analogComparator.enableInterrupt(ownTest);//Interrupt starten, sobald Sensor im "horchen" Modus
27
//bzw. Interrupt starten sobald analoges Signal unter
28
//Referenzspannung liegt
29
30
while(!obstacle){
31
obstacle=false;//solange kein Hindernis erkannt wird, obstacle = false
Tobias P. schrieb:> Als Referenzspannung speise ich nun direkt 3,3V vom Arduino ein.
Läuft der Arduino selbstauch mit 3,3 V? Und ist das rote Signal direkt
am Analogen Input gemessen?
Der Atmega clampt intern eigentlich mit Schottky-Dioden gegen die
Versorgungsspannung. Und eine Wechselspannung solltest du da sowieso
nicht anschließen. Wenn das rote Signal nicht direkt am AIN Pin gemessen
ist, könntest du sein, dass du durch die Dioden Richtung 3,3V
Nichtlinearitäten bekommst und das den Komparator verfälscht.
Und das hier:
1
while(!obstacle){
2
obstacle = false; //solange kein Hindernis erkannt wird, obstacle = false
3
}
Ergibt auch keinen Sinn. Damit baust du dir eine klassische Race
Condition.
Richtig wäre
Du hast da was mit den Interrupts wohl nicht ganz verstanden.
Ich habe gemeint, daß Du "Start" und "Ende" als globale Variablen
definierst. Dann wird beim Aufruf des Interrupts sofort Ende ermittelt
(das am besten gleich als erste Aktion).
Hier mal der Code, wie ich ihn verwenden würde. Dazu ein paar Hinweise:
1. Konstanten einsetzen, wo sinnvoll - macht die Nachbearbeitung
einfacher
2. Konstanten immer in Großbuchstaben.
3. Funktionen tun etwas, man hat also idR. ein Verb im Funktionsnamen
drin: Anstatt Pulse() also "GeneratePulse()", "ReceivePing()",
"Wait4Ping()" o.ä.
4. Wenn Du mal jobmäßig etwas internationaler wirst, wäre es gut die
Kommentare und auch sämtliche Funktionsnamen, Variablen, etc. auf
englisch zu machen - es liest sich auch leichter, wenn davor if, for,
o.ä. steht.
5. Am besten 4 Einrückungen (als Leerzeichen), nicht nur zwei, das ist
etwas wenig.
6. Jetzt wird's kleinlich: Der Terminus "obstacle" ist zwar nicht
falsch, aber ich würde da etwas Generischeres nehmen, eben wie u.a.
"pingFound". Ob die Antwort wirklich durch einen Gegenstand enstanden
ist oder die Hardware für das Signal verantwortlich ist, weißt Du nicht
und Du kannst auf diesem Weg das Codefragment auch einfacher für andere
Anwendungen portieren.
7. Die while()-Schleife hat keine Notfall-Abbruchmöglichkeit, ich habe
das ergänzt.
1
#include"analogComp.h"
2
3
#define US_PULSEPIN 13 // Rectangular signal output
4
#define US_PULSEWIDTH 100 // Pulse width in us
5
#define US_DELAY 300 // Delay in us before receiver is armed
6
#define US_TIMEOUT 1000 // Timeout in us to leave loop if no ping is received.
7
8
volatileunsignedlongtsStt,tsEnd;// global timestamps for start and end
9
volatileunsignedlongpingFound;// set to one, when ping was detected
10
11
12
voidsetup()
13
{
14
analogComparator.setOn(AIN0,AIN1);
15
pinMode(OutputPIN,OUTPUT);
16
Serial.begin(9600);
17
}
18
19
20
21
voidloop()
22
{
23
unsignedlongi;// internal variable
24
25
analogComparator.disableInterrupt();// Interrupt only active after pulse generation!
26
27
pingFound=false;// Reset
28
tsStt=micros();
29
GeneratePulse();// Rect. pulse, excite US-sensor
30
delayMicroseconds(US_DELAY);// Delay to avoid erratic detection of sent signal.
31
analogComparator.enableInterrupt(ownTest);// Arm Interrupt after crosstalk from sent pulse has vanished.
32
33
i=0;// 'Emergency' exit if no ping is received.
34
while(!pingFound&&(i<US_TIMEOUT))// Remain here until ISR or timeout detected.