Alles klar, ich werde es mit Pin_IRQs (muss erstmal gucken was das meinst) probieren. Oszillator ist nicht vorhanden.
Ich habe, wie gesagt, mehrere Beispiele im Netz gesehen, wo das Messen recht präzise mit dem im Ausgangspost genannten Code funktioniert. Mit Pico + HC-SR04. Hatte es ebenfalls mit nem Pi3B+ probiert.
Da das nicht gefruchtet hat vermute ich, dass irgendwas am Setup nicht stimmt. Also falsche Pins oder so... benutze GPIO 6 und 7 (Pin 9 und 10).
Gibt es GPIO's die eher verwendet werden sollten als andere?
[RPi3] Entfernung über Ultraschallsensor messen
Oszilloskop. Nicht Oszillator. Meines Wissens Nacht gibt es keine Pins, die bevorzugt sind. Du kannst aber erstmal die prinzipielle Funktionsfähigkeit testen, indem du mit einem Kabel oder gar Schalter prüfst, ob eine LOW/HIGH/LOW Sequenz erkannt wird. Auch wenn die händisch natürlich unpräzise und langsam ist, erkennst du daran, ob die Programmierung überhaupt tut.
So, hier nun meine aktuelle Version, die vom Prinzip her funktioniert.
Und zwar:
Ich habe als Trigger eine LED genommen und diese 2 Sekunden lang leuchten lassen, die geht schonmal an.
Um das Echo zu testen hab ich einfach am Steckbrett auf den GPIO 7 (Echo) mit nem Kabel 3,3V vom Pin 36 angelegt.
Ich konnte damit die Zeit in Sekunden messen, die die Reihe im Steckbrett dann mit 3,3V versorgt war (durchs Kabel einstecken).
2. Variante: Um den Spannungswandler zu testen, wollte ich das ganze wiederholen, nur dass ich das Kabel, welches mein Schalter simulieren soll, mit 5V (Pin40) verbunden ist. Da das ja so nicht an die GPIO's darf, hab ich dass durch den Y-Anschluss vom Wandler gejagt (und die A-Seite liegt am GPIO an). Also eigentlich das gleiche, nur dass mein 'Schalter' (in Form des Kabels) 5V hat und erst durch den Wandler geht, so wie beim Sensor halt auch.
Und das klappt nicht.
Entweder passiert gar nichts, als wäre nichts gesteckt, oder es wird dauerhaft die irq_callback() aufgerufen. Klingt mir mich als Laie danach, dass die Spannung entweder gar nicht anliegt oder zu gering ist. Also sprich, das Wandeln von 5V -> 3V klappt anscheinend nicht.
Nun muss ich sehen wie ich das Problem gelöst kriege...
Code: Alles auswählen
from machine import Pin
import utime
import micropython
micropython.alloc_emergency_exception_buf(100)
# Pin 9 / 10
TRIGGER_GPIO = 6
ECHO_GPIO = 7
SOUND_VELOCITY_M_S = 343
class Measurement:
def __init__(self):
self.trigger = Pin(TRIGGER_GPIO, Pin.OUT)
self.echo = Pin(ECHO_GPIO, Pin.IN, Pin.PULL_DOWN)
self.echo_start = utime.ticks_us()
self.echo_end = utime.ticks_us()
self.finished_measurement = False
def loop(self):
print("=== loop()")
self.measure()
while self.finished_measurement == False:
print("... waiting for finish...")
utime.sleep(1)
diff = utime.ticks_diff(self.echo_end, self.echo_start)
delay_s = diff / 1e6
print("Signal was high for ", delay_s, " seconds.")
self.finished_measurement = False
def measure(self):
print("=== measure()", self.echo.value(), " is current echo status")
self.trigger.high()
utime.sleep(2)
self.trigger.low()
while self.echo.value() == 0:
print("low...")
utime.sleep_us(1)
print("WE ARE HIGH")
self.echo_start = utime.ticks_us()
self.echo.irq(self.irq_callback, self.echo.IRQ_FALLING, hard=True)
def irq_callback(self, _):
print("--- irq_callback()")
self.echo_end = utime.ticks_us()
self.finished_measurement = True
if __name__ == "__main__":
print("starting up ...")
m = Measurement()
m.loop()
Ich habe als Trigger eine LED genommen und diese 2 Sekunden lang leuchten lassen, die geht schonmal an.
Um das Echo zu testen hab ich einfach am Steckbrett auf den GPIO 7 (Echo) mit nem Kabel 3,3V vom Pin 36 angelegt.
Ich konnte damit die Zeit in Sekunden messen, die die Reihe im Steckbrett dann mit 3,3V versorgt war (durchs Kabel einstecken).
2. Variante: Um den Spannungswandler zu testen, wollte ich das ganze wiederholen, nur dass ich das Kabel, welches mein Schalter simulieren soll, mit 5V (Pin40) verbunden ist. Da das ja so nicht an die GPIO's darf, hab ich dass durch den Y-Anschluss vom Wandler gejagt (und die A-Seite liegt am GPIO an). Also eigentlich das gleiche, nur dass mein 'Schalter' (in Form des Kabels) 5V hat und erst durch den Wandler geht, so wie beim Sensor halt auch.
Und das klappt nicht.
Entweder passiert gar nichts, als wäre nichts gesteckt, oder es wird dauerhaft die irq_callback() aufgerufen. Klingt mir mich als Laie danach, dass die Spannung entweder gar nicht anliegt oder zu gering ist. Also sprich, das Wandeln von 5V -> 3V klappt anscheinend nicht.
Nun muss ich sehen wie ich das Problem gelöst kriege...
Da sind ein paar Fehler drin. IRQs nur einmal registrieren, und die sollten so wenig wie möglich machen - vor allem nix ausgeben. Und das warten auf das Echo sollte auch keine print Ausgabe noch Wartezeit beinhalten. Auf einem Micro ist ein tighter poll loop schon ok, alternativ sollte der IRQ beide Richtungen beherrschen. Aber dann muss man ja auch Pollen, bis der Abbruch kommt.
Was die Elektronik angeht - ja, das sieht nach einem elektronischen Problem aus. Die Komponente kann kaputt sein. Wenn du öfter sowas machen willst, lohnt sich wirklich ein Oszi. . Billige analoge bekommt man zum Preis von 2 Kästen Bier. Und spart sich Stunden an Probiererei. Vielleicht habt ihr auch ein repair Café oder Ähnliches, wo man sowas mal benutzen oder sich helfen lassen kann.
Was die Elektronik angeht - ja, das sieht nach einem elektronischen Problem aus. Die Komponente kann kaputt sein. Wenn du öfter sowas machen willst, lohnt sich wirklich ein Oszi. . Billige analoge bekommt man zum Preis von 2 Kästen Bier. Und spart sich Stunden an Probiererei. Vielleicht habt ihr auch ein repair Café oder Ähnliches, wo man sowas mal benutzen oder sich helfen lassen kann.
Ja stimmt, dass hatte ich vergessen, im ersten Draft hatte ich im Callback die IRQ auf IRQ_FALLING gesetzt, also quasi ein callback für HIGH und dann einen für LOW. Das war aber nicht so stabil, zumindest mit meiner "Ich steck das Kabel ins Steckbrett" - Variante.
Das mit dem Prints weiß ich, musste nur irgendwie debuggen.
Genau, das mit dem IRQ in beide Richtungen funktioniert vielleicht mit dem Sensor, aber nicht mit meiner Ausprobiererei. Beim Reinstecken ins Board gabs anscheinend paar mal Kontakt - Kein Kontakt wodurch das ja dann direkt ausgelöst wurde.Auf einem Micro ist ein tighter poll loop schon ok, alternativ sollte der IRQ beide Richtungen beherrschen. Aber dann muss man ja auch Pollen, bis der Abbruch kommt.
Mit "Tighter poll loop" meinst du das hier dann?
Code: Alles auswählen
while self.echo.value() == 0:
pass
Danke für den Tipp, ich schau mal in der Uni + EbayWenn du öfter sowas machen willst, lohnt sich wirklich ein Oszi. . Billige analoge bekommt man zum Preis von 2 Kästen Bier. Und spart sich Stunden an Probiererei. Vielleicht habt ihr auch ein repair Café oder Ähnliches, wo man sowas mal benutzen oder sich helfen lassen kann.

So,
Ich hab den Sensor jetzt zufriedenstellend ans laufen bekommen - vielen Dank!
Lösung war, wie schon im letzten Post vermutet, dass das Echo Signal nicht durch kam.
Ich habe das jetzt mit 2 in Reihe geschalteten Wiederständen gemacht, 10kOhm und 22kOhm: Das Echo Signal geht durch beide in GND, nach dem ersten (10kOhm) greife ich mir das ab und das ist dann die Verbindung zum Pico GPIO.
Sollte dann so bei 3.4V liegen, also im Rahmen.
Hier nun die zwischenfertige Lösung:
Ich werde das zukünftig erweitern und vmtl. mittels MQTT die Daten an nen Server schicken.
Vermutlich ist die Variante mit den Widerständen nicht so schön, eig. wäre dafür ja der Spannungswandler gewesen... vielleicht krieg ich das zukünftig dann mal hin.
Danke:)
Ich hab den Sensor jetzt zufriedenstellend ans laufen bekommen - vielen Dank!
Lösung war, wie schon im letzten Post vermutet, dass das Echo Signal nicht durch kam.
Ich habe das jetzt mit 2 in Reihe geschalteten Wiederständen gemacht, 10kOhm und 22kOhm: Das Echo Signal geht durch beide in GND, nach dem ersten (10kOhm) greife ich mir das ab und das ist dann die Verbindung zum Pico GPIO.
Sollte dann so bei 3.4V liegen, also im Rahmen.
Hier nun die zwischenfertige Lösung:
Code: Alles auswählen
from machine import Pin
import utime
import micropython
micropython.alloc_emergency_exception_buf(100)
TOGGLE_GREEN_LT = 0.1
TOGGLE_RED_GT = 0.2
THRESHOLD = 0.02
# Pin 1,2,4
RED_GPIO = 0
YELLOW_GPIO = 1
GREEN_GPIO = 2
# Pin 9 / 10
TRIGGER_GPIO = 6
ECHO_GPIO = 7
SOUND_VELOCITY_M_S = 343
class Measurement:
def __init__(self, freq_hz = 5):
self.freq_hz = freq_hz
self.trigger = Pin(TRIGGER_GPIO, Pin.OUT)
self.echo = Pin(ECHO_GPIO, Pin.IN, Pin.PULL_DOWN)
self.echo.irq(self.irq_callback, self.echo.IRQ_FALLING, hard=True)
self.echo_start = utime.ticks_us()
self.echo_end = utime.ticks_us()
self.finished_measurement = False
self.red = Pin(RED_GPIO, Pin.OUT)
self.yellow = Pin(YELLOW_GPIO, Pin.OUT)
self.green = Pin(GREEN_GPIO, Pin.OUT)
self.current_light = None
self.lights_off = {RED_GPIO: [self.yellow, self.green], YELLOW_GPIO: [self.green, self.red], GREEN_GPIO: [self.yellow, self.red]}
self.lights = {RED_GPIO: self.red, YELLOW_GPIO: self.yellow, GREEN_GPIO: self.green}
def off(self):
for p in self.lights.values():
p.low()
def signal_length_to_distance_m(self, diff_us):
diff_s = diff_us / 1e6
distance_m = SOUND_VELOCITY_M_S * diff_s / 2
return distance_m
def toggle(self, gpio):
self.lights[gpio].high()
for p in self.lights_off[gpio]:
p.low()
def control_lights(self, distance_m):
TOGGLE_GREEN_COND = distance_m < TOGGLE_GREEN_LT
TOGGLE_YELLOW_COND = TOGGLE_GREEN_LT + THRESHOLD < distance_m < TOGGLE_RED_GT - THRESHOLD
TOGGLE_RED_COND = distance_m > TOGGLE_RED_GT
if TOGGLE_GREEN_COND and self.current_light != GREEN_GPIO:
self.toggle(GREEN_GPIO)
elif TOGGLE_YELLOW_COND and self.current_light != YELLOW_GPIO:
self.toggle(YELLOW_GPIO)
elif TOGGLE_RED_COND and self.current_light != RED_GPIO:
self.toggle(RED_GPIO)
def loop(self):
while True:
self.measure()
while self.finished_measurement == False:
utime.sleep(1 / self.freq_hz)
diff = utime.ticks_diff(self.echo_end, self.echo_start)
self.finished_measurement = False
distance_m = self.signal_length_to_distance_m(diff)
self.control_lights(distance_m)
def measure(self):
self.trigger.high()
utime.sleep_us(10)
self.trigger.low()
while self.echo.value() == 0:
pass
self.echo_start = utime.ticks_us()
def irq_callback(self, _):
self.echo_end = utime.ticks_us()
self.finished_measurement = True
if __name__ == "__main__":
m = Measurement()
try:
m.loop()
except KeyboardInterrupt:
m.off()
Vermutlich ist die Variante mit den Widerständen nicht so schön, eig. wäre dafür ja der Spannungswandler gewesen... vielleicht krieg ich das zukünftig dann mal hin.
Danke:)
- __blackjack__
- User
- Beiträge: 12490
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
Anmerkungen zum Quelltext: Das Hauptprogramm sollte in einer Funktion stehen. Momentan ist `m` (kein guter Name!) eine globale Variable.
`Measurement` ist auch kein guter Name für die Klasse. Die enthält auch zu viel. Letztlich ist das eine Gott-Klasse die *alles* macht.
Der `off()`-Aufruf sollte nicht nur passieren wenn der Benutzer das mit Strg+C abbricht, sondern *immer*, nehme ich mal an. Dann gehört das in einen ``finally``-Zweig.
Das `current_light`-Attribut wird nicht benutzt.
`lights_off` ist überflüssig und fehleranfällig wenn man so etwas manuell mit den ”invertierten” Werten füllt. Und bei `lights` ist die Abbildung überflüssig und das der Code über die Pin-Nummern-Konstanten geht, statt direkt die `Pin`-Objekte zu verwenden.
`high()` und `low()` sind nicht auf allen Portierungen vorhanden, `on()` und `off()` dagegen schon.
`freq_hz` macht eigentlich nicht wirklich Sinn. Man verzögert damit letztlich nur die Erkennung des Ereignisses.
In `control_lights()` sind lokale Namen wie Konstanten benannt. Und warum werden die ganzen Bedingungen überhaupt vor dem ``if``/``elif`` ausgewertet? Da ist doch noch gar nicht klar ob überhaupt alle Ergebnisse benötigt werden.
`toggle()` ist ein extrem irreführender Name. Eine Methode die so heisst und den Wert für eine LED übergeben bekommt, schaltet diese eine LED in den Zustand in dem sie gerade nicht ist. Wenn die was anderes macht, ist das total überraschend, denn alle anderen Methoden die so heissen machen genau das.
Ungetestet:
`Measurement` ist auch kein guter Name für die Klasse. Die enthält auch zu viel. Letztlich ist das eine Gott-Klasse die *alles* macht.
Der `off()`-Aufruf sollte nicht nur passieren wenn der Benutzer das mit Strg+C abbricht, sondern *immer*, nehme ich mal an. Dann gehört das in einen ``finally``-Zweig.
Das `current_light`-Attribut wird nicht benutzt.
`lights_off` ist überflüssig und fehleranfällig wenn man so etwas manuell mit den ”invertierten” Werten füllt. Und bei `lights` ist die Abbildung überflüssig und das der Code über die Pin-Nummern-Konstanten geht, statt direkt die `Pin`-Objekte zu verwenden.
`high()` und `low()` sind nicht auf allen Portierungen vorhanden, `on()` und `off()` dagegen schon.
`freq_hz` macht eigentlich nicht wirklich Sinn. Man verzögert damit letztlich nur die Erkennung des Ereignisses.
In `control_lights()` sind lokale Namen wie Konstanten benannt. Und warum werden die ganzen Bedingungen überhaupt vor dem ``if``/``elif`` ausgewertet? Da ist doch noch gar nicht klar ob überhaupt alle Ergebnisse benötigt werden.
`toggle()` ist ein extrem irreführender Name. Eine Methode die so heisst und den Wert für eine LED übergeben bekommt, schaltet diese eine LED in den Zustand in dem sie gerade nicht ist. Wenn die was anderes macht, ist das total überraschend, denn alle anderen Methoden die so heissen machen genau das.
Ungetestet:
Code: Alles auswählen
import micropython
import utime
from machine import Pin
micropython.alloc_emergency_exception_buf(100)
TOGGLE_GREEN_LT = 0.1
TOGGLE_RED_GT = 0.2
THRESHOLD = 0.02
# Pin 1,2,4
RED_GPIO = 0
YELLOW_GPIO = 1
GREEN_GPIO = 2
# Pin 9 / 10
TRIGGER_GPIO = 6
ECHO_GPIO = 7
SOUND_VELOCITY_M_S = 343
class Instrument:
def __init__(self):
self.process_echo = self._process_echo
self.trigger = Pin(TRIGGER_GPIO, Pin.OUT)
self.echo = Pin(ECHO_GPIO, Pin.IN, Pin.PULL_DOWN)
self.echo_start = None
self.distance_m = None
self.echo.irq(
self.irq_callback, Pin.IRQ_RAISING | Pin.IRQ_FALLING, hard=True
)
self.red = Pin(RED_GPIO, Pin.OUT)
self.yellow = Pin(YELLOW_GPIO, Pin.OUT)
self.green = Pin(GREEN_GPIO, Pin.OUT)
self.lights = [self.red, self.yellow, self.green]
def _process_echo(self, echo_end):
diff = utime.ticks_diff(echo_end, self.echo_start)
self.distance_m = SOUND_VELOCITY_M_S * (diff / 1e6) / 2
def irq_callback(self, pin):
if pin.value():
self.echo_start = utime.ticks_us()
else:
micropython.shedule(self.process_echo, utime.ticks_us())
def switch_to(self, target_light):
for light in self.lights:
light.value(light == target_light)
def update_lights(self):
if self.distance_m < TOGGLE_GREEN_LT:
self.switch_to(self.green)
elif (
TOGGLE_GREEN_LT + THRESHOLD
< self.distance_m
< TOGGLE_RED_GT - THRESHOLD
):
self.switch_to(self.yellow)
elif self.distance_m > TOGGLE_RED_GT:
self.switch_to(self.red)
def start_measurement(self):
self.distance_m = None
self.trigger.on()
utime.sleep_us(10)
self.trigger.off()
def off(self):
self.switch_to(None)
def main():
instrument = Instrument()
try:
while True:
instrument.start_measurement()
while instrument.distance_m is None:
pass
instrument.update_lights()
except KeyboardInterrupt:
pass
finally:
instrument.off()
if __name__ == "__main__":
main()
“Weltsprache No. 1 dürfte weder amerikanisches noch britisches, sondern schlechtes Englisch sein.”
— Ralf Callenberg in de.etc.sprache.deutsch
— Ralf Callenberg in de.etc.sprache.deutsch
Könnte evtl. *jemand* mal der Titel anpassen? Es geht ja schon länger nicht mehr um einen RPi3 oder/und "normales" Python. 
//Edit: Sorry, ich hatte ein "Bitte!" vergessen
//Edit: Sorry, ich hatte ein "Bitte!" vergessen
Alles was wir sind ist Sand im Wind Hoschi.
Solche Muehe gebt ihr euch vielleicht im Raspberry Pi Forum - dafuer streicht ihr da ja auch die dicke Werbekohle ein! Hier, im bescheidenen Python-Forum, das grau und frei von "dieser eine komische Trick, dein Bauchfett zu verlieren" ist, obwohl ich den wirklich dringend braeuchte, ist mir das zu aufwendig 
So, ich habe das ganze mal in Rust durchimplementiert. Die PIO Statemachine zaehlt munter die verflossenen Ticks, und die Ergebnisse sind meistens plausibel - ich vermute bei Abweichungen eher den Sensor als Problemquelle. Und im Oszilloskop sieht auch alles tippi toppi aus, es wackelt halt gerade bei kleinen Abstaenden.
https://github.com/deets/pico-experiments
https://github.com/deets/pico-experiments