Projekt: Autonomer Roboter

  • Beim Code für den HC-SR04 lässt sich natürlich auch noch was machen, denn aktuell verwenden wir die sog. "Polling"-Methode, dh wir rufen selbstständig den aktuellen GPIO-Status ab und handeln entsprechend. Das ist nicht wirklich effektiv und kostet auch weitaus mehr Rechenleistung, weil die while ungebremst extrem schnell rotiert.

    Effektiver und auch präziser wäre die Flankendetektierung via Interrupt... Dafür definiert man eine sog. Interrupt-Service-Routine (ISR), die für jede steigende und fallende Flanke (GPIO.BOTH) automatisch aufgerufen und der ausgelöste GPIO übergeben wird. Innerhalb der Routine wird dann der ECHO-Pin abgefragt. Hat er den Wert 1 (was mit GPIO.HIGH gleichzusetzen ist) war eine steigende Flanke Auslöser und eine Variable speichert die aktuelle Zeit. Im anderen Fall war die fallende Flanke der Auslöser und es werden die Zeitdifferenz und die Entfernung berechnet - also genau so wie bisher auch, nur dass diese ISR automatisch im Hintergrund in einem separaten Thread läuft und die Handhabung komplett vom RPi.GPIO Module übernommen wird. Einziges Manko: Um eine IPC muss man sich trotzdem selber kümmern. Hier würde ich auch wieder die Verwendung eines Queue zum speichern des Distanz-Werts empfehlen, da dann tatsächlich nur der aktuelle Wert ausgegeben wird und nicht evtl. noch ein alter Wert.

    Zu beachten ist auch dass durch GPIO.add_event_detect() auch wieder ein separater Thread ausgeführt wird... Allerdings nur ein einziger Thread, nicht für jede Callback ein extra Thread... Details sind aber erst mal egal, das sprengt das Thema hier. Siehe dazu auch https://sourceforge.net/p/raspberry-gpio-python/wiki/Inputs/


    Auch hier gäbe es erneut mehrere Möglichkeiten - wie immer. Am besten wäre eine eigene Klasse zu schreiben die dann mehrere Methoden hätte und innerhalb dieser Methoden kann man dann nämlich auf "self." definierte Variablen anderer Methoden problemlos zugreifen, was das ganze vereinfacht.

    Hierdurch ergibt sich dann auch die Gelegenheit auf das threading Module verzichten zu können und stattdessen multiprocessing zu verwenden ;)

    Und im gleichen Zuge würde ich auch für die Motor-Steuerung eine eigene Klasse erstellen - was den Umgang ebenfalls erleichtert.

    Ein weiterer Nebeneffekt dieses Umbaus: Falls ein Echo 'out of range' sein sollte, läuft das Script normal weiter.

    Würde beim alten Vorgehen niemals nie eine Antwort vom HC-SR04-Ping zurück kommen, würde das alte Script stecken bleiben weil es eben so lange wartet bis ECHO einen Flankenwechsel erfährt...

    ...ich weiß nicht ob die GPIO-Zuweisung so korrekt ist... das ist das Problem wenns weder Kommentare noch vernünftige Benennung von Variablen/Konstanten gibt, wie soll das "jemand anderes" nachvollziehen.

    Das wäre die nächste Stufe das Programm zu verbessern... Als nächstes könnte man die Klassen in einzelne Dateien auslagern.


    Was dann noch wichtig werden könnte ist einen Mittelwert für jeden Messvorgang zu ermitteln, da der HC-SR04 nicht 100% fehlerfrei arbeitet und es fatal/nervig werden könnte wenn eine Messung etwas falsches ergibt.


    Siehe dazu auch:

    http://www.netzmafia.de/skripten/hardw…hall/index.html

    http://blog404de.github.io/RasPiUltraschallEntfernungsmesser/

  • Hier seht Ihr mal, dass es anscheinend sehr gut möglich ist, den Roboter ohne Begrenzungskabel zu betreiben. Der Aufwand der dahinter steckt ist wahrscheinlich imens.

    Klickt mal auf das "i" bei den einzelnen Punkten das klingt schon interessant. Sowas hatte ich mir für später auch gedacht, aber ich glaube der Aufwand ist einfach zu groß.

    Link

    LG

    Bastelstube

  • Ja schau dir mal den Xiaomi Roborock: Hackable Saugroboter an, auf dessen Basis könnte man sowas probieren

    Müsste man später einmal ausprobieren, wie sich das ganze verhält. Eventuell kann man ja auch eine Schnittstelle zu Google Maps einbinden, anhand der Roboter/Gefährt erkennt wo er schon war. Andererseits ist das aus meinem vorherigen Post auch interessant. Dort kartiert man die Fläche und der Roboter berechnet anhand dessen den optimalen Fahrweg. Das ganze basiert anscheined auf einem DGPS Sensor + Kompass Sensor. Habe mal nach einem DGPS Sensor geschaut für den Raspberry, dabei aber nichts gescheites gefunden. Lediglich die normalen GPS und GPRS Module. Diese DGPS Sensoren kommen wohl aus der Landwirtschaft.

    Hier ist mal so ein Sensor. Dieser ist glaube ich aber nur für Lego Mindstorms.

    Sensor

    Beispiel

    Edit: Habe hier einen Sensor gefunden der eventuell passen könnte für die Zenitmeter genaue Fahrweise ohne Leitkabel. Was haltet Ihr davon? Link


    P.S Zu #81 werde ich heute abend Antworten.

    LG

    Bastelstube

    4 Mal editiert, zuletzt von Shaq (22. Januar 2018 um 15:03)

  • Habe den Code nun ausprobiert. Hierbei bekomme ich folgende Fehlermeldung. Kannst Du weiterhelfen?

    Bin momentan dabei, den bisherigen Code zu analysieren und zu verstehen mithilfe von Google :)

    Code
    pi@raspberrypi:~ $ sudo python MotorTest2.py
    Traceback (most recent call last):
      File "MotorTest2.py", line 167, in <module>
        main()
      File "MotorTest2.py", line 148, in main
        radar = sonar_ranger(GPIO, sonar_trigger, sonar_echo, telemetry, status, settings)
      File "MotorTest2.py", line 27, in __init__
        gpio.setup(trig, gpio.OUT)
    NameError: global name 'trig' is not defined
    pi@raspberrypi:~ $

    LG

    Bastelstube

  • Steht doch da. Das ist n Typo, in trigger oder self.trig abändern.

    Habe ich ja schon ausprobiert.

    Python
    gpio.setup(self.trig, gpio.OUT)

    Bekomme dann folgende Meldung.

    Das heißt ja das sonar_ranger das Attribut start_timefehlt wenn ich das richtig interpretiere. Das time Modul ist aber ja importiert.

    LG

    Bastelstube

  • Musste noch ein paar Einrückungen machen (siehe Code)

    Nach der Ausführung bekomme ich folgende Fehlermeldung

    Es ist aber ja die Klasse deklariert, somit dürfte es doch keinen NameError geben oder? Wo liegt der Fehler? Kann es jemand erklären?

    LG

    Bastelstube

  • Falsch Eingerückt... Du kannst nicht mal 8, mal vier Leerzeichen nehmen. Ab def main(): muss alles eine/zwei Ebenen (du mischst 4 und 8 Spaces) ausgerückt werden.

    Danke funktioniert jetzt soweit.


    Folgendes passiert aktuell:

    - Beide reifen drehen sich vorwärts

    - Halte ich die Hand davor, macht er anstatt eines turn_left einen pivot_left(ein rad dreht sich vorwärts, eins rückwärts), was aber nicht schlimm sondern eher besser ist.

    - Nehme ich die Hand weg, fährt das Gefährt wieder vorwärts. Halte ich sie dann wieder davor, geschieht wieder der turn_left

    - Das einzige was mir bis jetzt auffällt, was nicht funktioniert, ist die Ausgabe der Funktion def print_distance(self):

    Hier nochmal die besagte Funktion

    Python
    def print_distance(self):
                if self.distance:
                    if (int(time.time()) - self.status["announce_time"]) >= self.settings["distance_announce_time"]:
                        if self.distance > self.range_max or self.distance < self.range_min:
                            print("Distance: out of range")
                        else:
                            print("Distance: %.2f cm" % self.telemetry["distance"])
                        self.status["announce_time"] = int(time.time())

    LG

    Bastelstube

  • pivot_left() habe ich im Code gar nicht drin - also hast du daran was verändert und somit kann ich wieder nur mit den Schultern zucken wieso bei Dir die print_distance() Methode nicht funktioniert....


    PS: Die Einrückungen wie ich sie in Beitrag#88 habe sind 100% korrekt.

  • #!/usr/bin/python3

    class sonar_ranger(object):

    class motor_control(object)

    Darf ich euch beiden mal virtuell auf die Finger hauen?

    1. Das tolle an so Sachen wie PEP-8 ist, dass (wenn man sich dran hält) man auch ohne die Definition einer Funktion/Klasse sofort sieht, womit man es zu tun hat. Wenn man aber Klassen wie Funktionen benennt tritt einem diese Konvention in den Ar***.

    2. Das Script ist laut Shebang für Python 3 geschrieben, da muss man nicht mehr von object erben, da alle Klassen per default new-style classes sind.

  • Das fällt dir aber früh auf :lol:


  • pivot_left() habe ich im Code gar nicht drin - also hast du daran was verändert und somit kann ich wieder nur mit den Schultern zucken wieso bei Dir die print_distance() Methode nicht funktioniert....

    Geändert habe ich nichts. Lediglich ein Komma was gefehlt hat.

    PS: Die Einrückungen wie ich sie in Beitrag#88 habe sind 100% korrekt.

    Habe aber die Fehlermedldung bekommen, dass ein paar Zeilen nicht richtig Eingerückt waren.

    Werde es heute abend erneut testen. Sind aber auf dem richtigen weg.

    1. Das tolle an so Sachen wie PEP-8 ist, dass (wenn man sich dran hält) man auch ohne die Definition einer Funktion/Klasse sofort sieht, womit man es zu tun hat. Wenn man aber Klassen wie Funktionen benennt tritt einem diese Konvention in den Ar***.


    2. Das Script ist laut Shebang für Python 3 geschrieben, da muss man nicht mehr von object erben, da alle Klassen per default new-style classes sind.

    Werde mir ich mir mal durchlesen und versuchen zu verstehen, was PEP-8 und default new-style classes sind. Melde mich ggf. nochmal bzgl. dessen wenn ich Fragen dazu habe.

    LG

    Bastelstube

  • Und wieso fehlte es dann bei dir? :-/

    Wie gesagt gibt es in meinem Code kein pivot_left ... Also wie kommt es dann das in Deinem Code pivot_left ausgeführt werden kann wenn du denn aber nichts am Code verändert hast?

    Also sorry aber das widerspricht sich doch irgendwie?

    ...dieses Katz und Maus Spiel fängt langsam an zu nerven - entweder wir arbeiten zusammen oder eben nicht... Zusammenarbeit sieht aber anders aus.


    PS:

    Bitte nicht Beiträge vollständig quoten/zitieren, vor allem wenn diese genau da drüber stehen.

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!