Autonome Navigation eines mobilen Roboters

Es gibt eine Vielzahl von Möglichkeiten, wie ein Roboter Informationen von der Außenwelt empfangen kann, um mit ihm zu interagieren. Abhängig von den ihm zugewiesenen Aufgaben unterscheiden sich auch die Methoden zur Verarbeitung dieser Informationen. In diesem Artikel werde ich die Hauptphasen der im Rahmen des Schulprojekts durchgeführten Arbeiten beschreiben, deren Ziel es ist, Informationen zu verschiedenen Methoden der autonomen Roboternavigation zu systematisieren und das bei der Erstellung des Roboters für die Wettbewerbe „RTK Cup“ gewonnene Wissen anzuwenden.



Einführung


Bei den Wettbewerben „RTK Cup“ gibt es einen Aufgabenblock, der ohne Eingreifen des Bedieners erledigt werden muss. Ich glaube, dass viele Teilnehmer diese Aufgaben zu Unrecht vermeiden, weil die scheinbar Komplexität der Erstellung eines Roboterdesigns und des Schreibens eines Programms weitgehend vereinfachte Aufgaben aus anderen Wettbewerbsdisziplinen verbirgt, die auf einem Trainingsgelände zusammengefasst sind. Mit meinem Projekt möchte ich mögliche Lösungen für solche Probleme aufzeigen, wobei ich als Beispiel das Folgende entlang der Linie betrachte.

Um das Projektziel zu erreichen, wurden folgende Zwischenaufgaben formuliert:

  • Analyse der Wettbewerbsregeln „RTK Cup“
  • Analyse bestehender Algorithmen zur autonomen Orientierung eines mobilen Roboters
  • Softwareerstellung

Analyse der Wettbewerbsregeln „RTK Cup“


Bei den „RTK Cup“ -Wettbewerben wird den Teilnehmern ein Trainingsgelände präsentiert, auf dem Abschnitte unterschiedlicher Komplexität modelliert werden. Der Wettbewerb soll die junge Robotik dazu anregen, Geräte zu entwickeln, die unter extremen Bedingungen arbeiten, Hindernisse überwinden, unter menschlicher Kontrolle oder autonom arbeiten können.



kurz über die Elemente, aus denen das Polygon besteht
«» , . , , (), , (), ..

:



:



– , «» ( ) , . , , , , .

. , , , , , , .

Die Wettbewerbe sind in zwei grundlegend unterschiedliche Nominierungen unterteilt: "Seeker" und "Extreme". Damit soll sichergestellt werden, dass der Wettbewerb zwischen Teilnehmern mit einem Mindestunterschied in Bezug auf Alter und Erfahrung bei der Entwicklung von Robotersystemen durchgeführt wurde: Sucher für jüngere und Extreme für Teilnehmer ab 14 Jahren. Bei der Seeker-Nominierung kann sich der Bediener frei in der Reichweite bewegen und direkten Blickkontakt mit der Maschine haben, während bei der Extreme-Nominierung davon ausgegangen wird, dass der Roboter über Videokommunikationssysteme und / oder Computer Vision verfügt, da der Bediener im Labyrinth navigieren muss und sich nur auf das Labyrinth verlassen muss Die Kamera und die Sensoren sind in den Roboter eingebaut, während sie sich hinter einem speziellen Bildschirm befinden.

Um sich für Wettbewerbe zu qualifizieren, muss der Roboter entweder die Aufgabe zur Fernsteuerung des Manipulators bestehen oder eines der Elemente der Autonomie ausführen. Im Rahmen des Projekts wurde die Aufgabe festgelegt, Autonomieaufgaben zu erfüllen, da sie die meisten Punkte zu den niedrigsten Kosten des Betreibers liefern. Die Elemente der Autonomie umfassen:

  • Fahren entlang einer Linie mit einem Umgebungslichtsensor oder einem Sichtliniensystem
  • Standalone-Beacon-Erfassung mit Entfernungssensor oder Bildverarbeitungssystemen
  • Bewegung entlang einer komplexen Flugbahn (z. B. Auf- / Abstieg von Treppen) entlang einer Linie mit einem Kompass, Gyroskop, Beschleunigungsmesser, Sichtsystem oder kombinierten Methoden

Außerdem werden Punkte zur Überwindung von Hindernissen verdoppelt, wenn der Roboter sie autonom passiert.

Im Rahmen dieses Projekts wird die Lösung der ersten Aufgabe in Betracht gezogen - Bewegung entlang der Linie. Die gebräuchlichsten Methoden, um sich entlang der Linie zu bewegen, sind Lichtsensoren und eine Kamera. Zu den Pluspunkten der Sensoren gehört die einfache Erstellung eines Programms - viele von ihnen sind mit einem Abstimmwiderstand ausgestattet, sodass beim Einstellen des Sensors für die Hintergrundbeleuchtung 0 oder 1 ausgegeben wird, je nachdem, ob er in der Leitung ist oder nicht. Aus dem gleichen Grund stellen Lichtsensoren keine Anforderungen an die Verarbeitungsleistung der verwendeten Steuerung. Aus diesem Grund ist die Lösung des Problems mit Hilfe von Lichtsensoren am kostengünstigsten - die Kosten für den einfachsten Sensor betragen 35 Rubel, und für eine relativ stabile Fahrt entlang der Linie reichen drei Sensoren aus (einer ist an der Linie und zwei an den Seiten installiert). Jedoch,Einer der Hauptnachteile solcher Sensoren sind Installationsbeschränkungen. Idealerweise sollte der Sensor genau in der Mitte in geringem Abstand vom Boden installiert werden, da sonst falsche Werte angezeigt werden. Dies ist kein Problem bei speziellen Wettbewerben, bei denen der Roboter so schnell wie möglich auf der Strecke fahren muss. Unter den Bedingungen des „RTK Cup“ -Wettbewerbs können jedoch alle oben genannten Sensorfehler kritisch sein - ihre Installation erfordert in erster Linie das Vorhandensein zusätzlicher mechanischer Teile am Roboter, die anheben und Das Absenken der Sensoren erfordert zusätzlichen Platz auf dem Roboter, einen separaten Motor, der die Sensoren bewegt, und ist auch ein Ort für potenzielle Schäden und erhöht die Masse des Roboters.Andernfalls werden falsche Werte angezeigt. Dies ist kein Problem bei speziellen Wettbewerben, bei denen der Roboter so schnell wie möglich auf der Strecke fahren muss. Unter den Bedingungen des „RTK Cup“ -Wettbewerbs können jedoch alle oben genannten Sensorfehler kritisch sein - ihre Installation erfordert in erster Linie das Vorhandensein zusätzlicher mechanischer Teile am Roboter, die anheben und Das Absenken der Sensoren erfordert zusätzlichen Platz auf dem Roboter, einen separaten Motor, der die Sensoren bewegt, und ist auch ein Ort für potenzielle Schäden und erhöht die Masse des Roboters.Andernfalls werden falsche Werte angezeigt. Dies ist kein Problem bei speziellen Wettbewerben, bei denen der Roboter so schnell wie möglich auf der Strecke fahren muss. Unter den Bedingungen des „RTK Cup“ -Wettbewerbs können jedoch alle oben genannten Sensorfehler kritisch sein - ihre Installation erfordert in erster Linie das Vorhandensein zusätzlicher mechanischer Teile am Roboter, die anheben und Das Absenken der Sensoren erfordert zusätzlichen Platz auf dem Roboter, einen separaten Motor, der die Sensoren bewegt, und ist auch ein Ort für potenzielle Schäden und erhöht die Masse des Roboters.Alle oben genannten Sensorfehler können kritisch sein - ihre Installation erfordert in erster Linie das Vorhandensein zusätzlicher mechanischer Teile am Roboter, die die Sensoren anheben und absenken. Dies erfordert zusätzlichen Platz auf dem Roboter, einen separaten Motor, der die Sensoren bewegt, und ist auch ein Ort für potenzielle Schäden und erhöht die Masse des Roboters .Alle oben genannten Sensorfehler können kritisch sein - ihre Installation erfordert in erster Linie das Vorhandensein zusätzlicher mechanischer Teile am Roboter, die die Sensoren anheben und absenken. Dies erfordert zusätzlichen Platz auf dem Roboter, einen separaten Motor, der die Sensoren bewegt, und ist auch ein Ort für potenzielle Schäden und erhöht die Masse des Roboters .



Die Kamera hat wiederum die folgenden Vorteile: Sie hat einen praktisch unbegrenzten (im Vergleich zu Sensoren) Messradius, d.h. Nur ein Kameramodul kann gleichzeitig die Linie sehen, sowohl direkt unter dem Roboter als auch in ausreichendem Abstand davon, wodurch beispielsweise seine Krümmung ausgewertet und eine proportionale Steueraktion ausgewählt werden kann. Gleichzeitig stört das Kameramodul nicht die Weiterentwicklung des Roboters in anderen Teilen der Deponie, die keine Autonomie erfordern, da die Kamera in einem Abstand vom Boden befestigt ist. Der Hauptnachteil der Kamera besteht darin, dass die Videoverarbeitung einen leistungsstarken Rechenkomplex an Bord des Roboters erfordert und die zu entwickelnde Software eine genauere Abstimmung erfordert, da die Kamera eine Größenordnung mehr Informationen von der Außenwelt empfängt als drei Lichtsensoren, während Kamera und ComputerIn der Lage sind, die empfangenen Informationen zu verarbeiten, sind um ein Vielfaches mehr als drei Sensoren und "Arduine".

Für mich persönlich liegt die Antwort auf der Hand - in der Nominierung „extremal“ muss der Roboter über eine Richtkamera verfügen, mit der der Bediener navigieren kann. Wenn Sie vorgefertigte FPV-Lösungen verwenden, können die Gesamtkosten für „Sensoren“ sogar noch höher sein, während zusätzliche Geräte installiert werden müssen. Darüber hinaus hat ein Roboter mit Himbeer-Pi und einer Kamera ein größeres Potenzial für die Entwicklung einer autonomen Bewegung, da die Kamera eine Vielzahl von Problemen lösen kann und nicht nur bei Linienbewegungen verwendet werden kann, ohne das Design wesentlich zu komplizieren.

Analyse bestehender Computer-Vision-Algorithmen


Computer Vision ist die Theorie der Erstellung von Geräten, die Bilder von Objekten der realen Welt empfangen, die erhaltenen Daten verarbeiten und verwenden können, um verschiedene Arten von angewandten Problemen ohne menschliches Eingreifen zu lösen.

Computer Vision Systeme bestehen aus:

  • eine oder mehrere Kameras
  • Computerkomplex
  • Software, die Bildverarbeitungswerkzeuge bereitstellt
  • Kommunikationskanäle zur Übertragung von Ziel- und Telemetrieinformationen.

Wie bereits geschrieben, gibt es viele Möglichkeiten, Objekte zu identifizieren, die für uns von Interesse sind. Wenn Sie entlang einer Linie fahren, müssen Sie die Linie selbst vom kontrastierenden Hintergrund trennen (eine schwarze Linie auf weißem Hintergrund oder eine weiße Linie auf schwarzem Hintergrund für eine umgekehrte Linie). Algorithmen, die ein Computer-Vision-System verwenden, können in mehrere „Schritte“ zur Verarbeitung des Originalbilds unterteilt werden:

Bildaufnahme : Digitale Bilder werden direkt von der Kamera, von einem an das Gerät übertragenen Videostream oder als separate Bilder erhalten. Pixelwerte entsprechen normalerweise der Lichtintensität (Farb- oder Graustufenbilder), können jedoch mit verschiedenen physikalischen Messungen in Verbindung gebracht werden, beispielsweise mit der Temperatur einer Wärmebildkamera.

Vorbearbeitung: Bevor Computer-Vision-Methoden auf Videodaten angewendet werden können, ist abhängig von der verwendeten Methode eine Vorverarbeitung erforderlich, um bestimmte Bedingungen einzuführen. Beispiele sind:

  • Entfernen von Rauschen oder Verzerrungen durch den verwendeten Sensor
  • Bildunschärfe wird verwendet, um kleine Artefakte zu entfernen, die während des Kamerabetriebs, von Dekomprimierungselementen, Rauschen usw. auftreten.
  • Verbesserung des Kontrasts, damit die richtigen Informationen wahrscheinlicher erkannt werden können
  • Ändern Sie die Belichtung von Schatten oder Lichtern
  • Skalieren oder Zuschneiden, um die Strukturen im Bild besser unterscheiden zu können.
  • Konvertieren eines Bilds in Schwarzweiß oder Ändern der Auflösung für eine schnellere Systemleistung

Hervorheben von Details : Bilddetails verschiedener Schwierigkeitsgrade werden aus den Videodaten extrahiert. Typische Beispiele für solche Details sind Linien, Ränder, Kanten, einzelne Punkte und Bereiche, die für jedes Merkmal charakteristisch sind.
Erkennung : In einem bestimmten Stadium der Programmarbeit werden programmrelevante Informationen vom Rest des Bildes getrennt. Beispiele sind:

  • Die Auswahl eines bestimmten Satzes von Punkten von Interesse für die Farbe, die Anzahl der isolierten Pixel, die in irgendeiner Weise ähnlich sind (Krümmung der Figur, Farbe, Helligkeit usw.)
  • Segmentierung eines oder mehrerer Bildabschnitte, die ein charakteristisches Objekt enthalten.

Verarbeitung auf hoher Ebene : In diesem Schritt wird die Informationsfülle aus dem Bild auf eine Größe reduziert, die leicht verarbeitet werden kann, z. B. ein Satz bestimmter Pixel oder die Koordinaten des Teils des Bildes, in dem sich das interessierende Objekt angeblich befindet. Beispiele sind:

  • Filtern von Werten nach einem beliebigen Kriterium
  • Bewertung von Parametern wie den physischen Abmessungen des Objekts, der Form, seiner Position im Rahmen oder relativ zu anderen charakteristischen Objekten
  • Einstufung

Als nächstes musste die Bibliothek ausgewählt werden, auf deren Grundlage das Programm erstellt wird. Die Schlüsselfaktoren bei meiner Wahl waren:

  • Die Unterstützung der Bibliothek für die Python-Oberfläche aufgrund der relativ einfachen Lernfähigkeit dieser Sprache durch Anfänger ist eine einfache Syntax, die sich positiv auf die Lesbarkeit des Programms auswirkt.
  • Portabilität, d.h. die Möglichkeit, ein Programm mit dieser Bibliothek auf Himbeer-Pi3 auszuführen.
  • Die Verbreitung der Bibliothek, die eine gut entwickelte Community von Programmierern garantiert, die möglicherweise bereits auf Probleme gestoßen sind, die während Ihrer Arbeit auftreten können.

Unter den Optionen, die ich untersucht habe, habe ich die OpenCV Open Computer Vision-Bibliothek hervorgehoben, da sie Python unterstützt und über eine umfangreiche Online-Dokumentation verfügt. Es gibt viele Artikel und Anweisungen im Internet, die alle Feinheiten der Arbeit mit dieser Bibliothek beschreiben. Es gibt ein offizielles Forum von Entwicklern, in dem jeder eine Frage dazu stellen kann. Außerdem ist diese Bibliothek in C / C ++ - Sprachen implementiert, was die Systemleistung garantiert, und ihre Struktur unterstützt verschiedene Module, die deaktiviert werden können, um die Leistung zu steigern.

Software-Entwicklung


Nach der Installation des Betriebssystems und der Erstkonfiguration von Raspberry pi müssen Sie jedoch alle dafür erforderlichen Pakete installieren, bevor Sie mit der Erstellung des Programms beginnen. Die meisten dieser Pakete werden wiederum mit dem Pip-Paketmanager installiert (im Fall von Python 3, pip3).

$ sudo apt install python3-pip

Die folgenden Bibliotheken sind installiert, z.

  • picamera - Bibliothek für die Arbeit mit Himbeer-Pi-Kamera
  • numpy - eine Bibliothek zum Arbeiten mit mehrdimensionalen Datenarrays als Bilder

$ sudo pip3 install picamera
$ sudo pip3 install numpy

cmake - Dienstprogramm zum automatischen Erstellen eines Programms aus dem Quellcode
cmake-curses-gui - GUI-Paket (grafische Oberfläche) für cmake

$ sudo apt-get install cmake cmake-curses-gui libgtk2.0-dev
$ sudo apt-get install cmake cmake-curses-gui libgtk2.0-dev

Bibliotheken für die Arbeit mit verschiedenen Bild- und Videoformaten und mehr

$ sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev libx264-dev libxvidcore-dev
$ sudo apt-get install libjpeg-dev libpng12-dev libtiff5-dev libjasper-dev
$ sudo apt-get install gfortran libatlas-base-dev

Zum Übertragen von Videodaten vom Roboter zum Computer wird GStreamer verwendet - ein Framework zum Empfangen, Verarbeiten und Übertragen von Multimediadaten:

$ sudo apt install libgstreamer1.0-0 gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc gstreamer1.0-tools gstreamer1.0-x gstreamer1.0-alsa gstreamer1.0-gl gstreamer1.0-gtk3 gstreamer1.0-qt5 gstreamer1.0-pulseaudio

Der nächste Schritt besteht darin, die openCV-Bibliothek selbst aus Quellen zu installieren, zu konfigurieren und zu erstellen. Dazu wird ein opencv-Arbeitsordner erstellt.

$ mkdir opencv
$ cd opencv

Zum Herunterladen der neuesten Versionen der Bibliothek wird wget verwendet - ein Konsolenprogramm zum Herunterladen von Dateien aus dem Netzwerk. Zum Zeitpunkt der Erstellung des Programms ist die neueste stabile Version von openCV 4.1.0. Laden Sie also die Quellen herunter und entpacken Sie sie:

$ wget https://github.com/opencv/opencv/archive/4.1.0.zip -O opencv_source.zip
$ unzip opencv_source.zip
$ wget https://github.com/opencv/opencv_contrib/archive/4.1.0.zip -O opencv_contrib.zip
$ unzip opencv_contrib.zip

Nach Abschluss des Entpackvorgangs können die Quellarchive gelöscht werden.

$ rm opencv_source.zip
$ rm opencv_contrib.zip

Für die Montage und Konfiguration wird ein Verzeichnis erstellt.

$ cd /home/pi/opencv/opencv-4.1.0
$ mkdir build
$ cd build

Build-Parameter werden mit dem Dienstprogramm cmake konfiguriert. Zu diesem Zweck werden alle wichtigen Parameter zusammen mit den zugewiesenen Werten als Dienstprogrammvariablen übergeben:

cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D INSTALL_PYTHON_EXAMPLES=ON -D INSTALL_C_EXAMPLES=OFF -D BUILD_opencv_python2=OFF -D WITH_GSTREAMER=ON -D BUILD_EXAMPLES=ON -DENABLE_VFPV3=ON -DENABLE_NEON=ON -DCPU_BASELINE=NEON ..

Nach dem Einrichten der Konfiguration zeigt das Dienstprogramm alle Parameter an. Als nächstes müssen Sie die Bibliothek kompilieren. Verwenden Sie dazu den Konsolenbefehl make –jN, wobei N die Anzahl der Kerne ist, die am Kompilierungsprozess beteiligt sind. Für Himbeer-Pi 3 beträgt die Anzahl der Kerne 4, aber Sie können diese Anzahl definitiv herausfinden, indem Sie den Befehl nproc in die Konsole schreiben.

$ make –j4

Aufgrund der begrenzten Ressourcen von Himbeeren kann die Kompilierung eine Weile dauern. In einigen Fällen können Himbeeren sogar einfrieren, aber wenn Sie später in den Build-Ordner gehen und make neu registrieren, wird die Arbeit fortgesetzt. In diesem Fall lohnt es sich, die Anzahl der beteiligten Kerne zu reduzieren. Meine Kompilierung verlief jedoch ohne Probleme. In diesem Stadium lohnt es sich auch, über die aktive Abkühlung von Himbeeren nachzudenken, da selbst damit die Prozessortemperatur etwa 75 Grad erreichte.

Wenn die Kompilierung erfolgreich war, muss die Bibliothek installiert werden. Dies erfolgt auch mit dem Dienstprogramm make. Dann werden wir alle notwendigen Verbindungen mit dem Dienstprogramm ldconfig herstellen:

$ sudo make install
$ sudo ldconfig

Wir überprüfen die Installation, indem wir die folgenden Befehle im interaktiven Python-Modus schreiben:

import cv2
print(cv2.getBuildInformation())

Die folgende Schlussfolgerung des Programms ist ein Beweis für die korrekte Installation.



Es ist zu beachten, dass das obige Verfahren zum Kompilieren der Bibliothek sowohl auf dem Roboter als auch auf dem PC ausgeführt werden muss, von dem aus die Steuerung des Roboters geplant ist und auf dem die Sendung vom Roboter empfangen wird.

Erstellen eines Videoverteilungsschemas

Bevor Sie mit dem Schreiben von Code beginnen, müssen Sie ein Schema entwickeln, nach dem der Algorithmus funktioniert. Im betrachteten Fall der Softwareentwicklung für einen Roboter, der für die Teilnahme an den RTK Cup-Wettbewerben in der Extreme-Nominierung erstellt wurde, wird das gesamte Programm in zwei Teile unterteilt: einen Roboter und eine Fernbedienung, die von einem Computer mit installiertem Linux gespielt werden. Eine der wichtigsten Aufgaben hierbei ist die Erstellung eines ungefähren Schemas für die Übertragung von Videodaten zwischen verschiedenen Teilen des Algorithmus. Wi-Fi wird als Kommunikationskanal zwischen den beiden Geräten verwendet. Datenpakete, die die Steuerung des Roboters und Rückmeldedaten bereitstellen, werden unter Verwendung des in der Socket-Bibliothek implementierten UDP-Protokolls von einem Gerät zu einem anderen übertragen. VideodatenAufgrund von Einschränkungen in der Größe des UDP-Pakets wird mit GStreamer übertragen. Zum bequemen Debuggen werden zwei Videostreams implementiert:

  • Hauptvideostream - Überträgt Videodaten direkt von der Kamera des Roboters auf einen Computer, um eine minimale Steuerverzögerung zu gewährleisten.
  • Hilfsvideostream - überträgt die vom Roboter verarbeiteten Videodaten, die zum Einrichten und Debuggen eines Programms erforderlich sind, das Computer Vision implementiert.

Auf dem Roboter sind gleichzeitig zwei Videostreams aktiv, und der Computer zeigt je nach aktiviertem Antriebsmodus das gewünschte Bild an. Der Roboter verwendet wiederum abhängig davon, ob der Autonomiemodus ein- oder ausgeschaltet ist, entweder Steuerdaten, die von einem Computer empfangen oder von einem Bildprozessor generiert wurden.



Die Fernsteuerung des Roboters erfolgt aufgrund der Arbeit von zwei parallelen Flüssen am Roboter und am Computer:

  • Die „Konsole“ in einem Zyklus fragt alle verfügbaren Eingabegeräte ab und bildet ein Steuerdatenpaket, das aus den Daten selbst und der Prüfsumme besteht (zum Zeitpunkt der endgültigen Änderungen am Artikel habe ich mich geweigert, Prüfsummen zu erstellen, um die Verzögerung zu verringern, aber in der Quelle, die ich Am Ende wird dieser Code verlassen) - von einem bestimmten Wert, der aus einem Datensatz berechnet wird, indem ein Algorithmus verwendet wird, der zur Bestimmung der Integrität von Daten während der Übertragung verwendet wird
  • Roboter - Wartet auf den Datenzugriff vom Computer. Entpackt die Daten, berechnet die Prüfsumme neu und vergleicht sie mit der auf der Computerseite gesendeten und berechneten. Wenn die Prüfsummen übereinstimmen, werden die Daten an das Hauptprogramm übertragen.

Bevor Sie den Linienerkennungsalgorithmus analysieren, sollten Sie sich mit den Konstruktionsmerkmalen des Roboters vertraut machen:

über den Roboter
.

— . (3 ) . , . 6 , . . . . , - . «» rasberry pi 3 b — .

, , , , Solidworks petg . , raspberry .

ubiquiti bullet M5 hp. ( ) , . , «» .


: «» thingiverse. , , , , .


, , . , . , , , , . , , , .





- ( - 200 ) , , 90 70 ( ), , « ». , VL53L0X , .


«» , , (rds3115). — , , , , .


, , , :


- , , , . . raspberry, , . , .

, USB. , , .




Erstellung eines Zeilenerkennungsalgorithmus mit OpenCV-Bibliotheksmethoden


I. Empfangen von Daten

Aufgrund der Tatsache, dass der Bildprozessor keine Videodaten direkt von der Kamera, sondern vom Hauptstrom empfängt, ist es notwendig, sie von dem für die Übersetzung verwendeten Format in das für die Bildverarbeitung verwendete Format zu übertragen, nämlich ein aus roten Werten bestehendes Numpy-Array , grün und blau für jedes der Pixel. Dazu benötigen Sie die Anfangsdaten - einen Frame, der vom Himbeer-Pi-Kameramodul empfangen wird.

Der einfachste Weg, Bilder von Kamera c zur weiteren Verarbeitung abzurufen, ist die Verwendung der Picamera-Bibliothek. Bevor Sie beginnen, müssen Sie den Zugriff auf die Kamera über raspi-config -> Schnittstellenoptionen Kamera -> Ja auswählen zulassen.

sudo raspi-config

Der nächste Codeabschnitt ist mit der Himbeerkamera verbunden und empfängt in einem Zyklus mit einer bestimmten Frequenz Frames in Form eines Arrays, das von der opencv-Bibliothek verwendet werden kann.

from picamera.array import PiRGBArray
from picamera import PiCamera
import cv2
#   
camera = PiCamera()
camera.resolution = (640, 480) 
camera.framerate = 30
cap = PiRGBArray(camera, size=(640, 480))

for frame in camera.capture_continuous(cap , format="bgr", use_video_port=True):
	new_frame = frame.array
	cap.truncate(0)
	if False: #   -   
		break

Es ist auch erwähnenswert, dass diese Methode zum Erfassen von Frames zwar die einfachste ist, jedoch einen schwerwiegenden Nachteil aufweist: Sie ist nicht sehr effektiv, wenn Sie Frames über GStreamer senden müssen, da dies mehrere Male erfordert, um das Video neu zu codieren, was die Geschwindigkeit des Programms verringert. Ein viel schnellerer Weg, um Bilder zu erhalten, besteht darin, auf Anfrage des Bildprozessors Bilder aus dem Videostream auszugeben. Die weiteren Stufen der Bildverarbeitung hängen jedoch nicht von der verwendeten Methode ab.

Ein Beispiel für ein Bild von einer Roboterkamera ohne Verarbeitung:


II. Vorverarbeitung

Wenn Sie auf einer Linie fahren, ist es am einfachsten, den Bereich der Punkte zu trennen, die am stärksten von der Hintergrundfarbe abweichen. Diese Methode ist ideal für den RTK Cup-Wettbewerb geeignet, da sie eine schwarze Linie auf weißem Hintergrund (oder eine weiße Linie auf schwarzem Hintergrund für umgekehrte Abschnitte) verwendet. Um die Menge an Informationen zu reduzieren, die verarbeitet werden müssen, können Sie einen Binärisierungsalgorithmus anwenden, dh das Bild in ein Schwarzweißformat konvertieren, in dem es nur zwei Arten von Pixeln gibt - Dunkel und Hell. Zuvor sollte das Bild in Graustufen übersetzt und verwischt werden, um kleine Fehler und Rauschen zu vermeiden, die während des Betriebs der Kamera unvermeidlich sind. Um das Bild zu verwischen, wird ein Gauß-Filter verwendet.

gray = cv2.cvtColor(self._frame, cv2.COLOR_RGB2GRAY)
blur = cv2.GaussianBlur(gray, (ksize, ksize), 0)

Dabei ist ksize die Größe des Gaußschen Kerns. Wenn Sie diese Größe erhöhen, können Sie den Grad der Unschärfe erhöhen.

Beispielbild nach Übersetzung in Graustufen und Unschärfe:


III. Auswählen von Details

Nachdem das Bild in Graustufen übersetzt wurde, muss es bei einem bestimmten Schwellenwert binärisiert werden. Mit dieser Aktion können Sie die Datenmenge weiter reduzieren. Dieser Schwellenwert wird vor jedem Abflug des Roboters an einem neuen Ort oder wenn sich die Lichtverhältnisse ändern, angepasst. Im Idealfall besteht die Aufgabe der Kalibrierung darin, sicherzustellen, dass der Umriss der Linie auf dem Bild definiert ist. Gleichzeitig sollten jedoch keine weiteren Details auf dem Bild vorhanden sein, die keine Linie sind:

thresh = cv2.threshold(blur, self._limit, 255, cv2.THRESH_BINARY_INV)[1]

Hier werden alle Pixel, die dunkler als der Schwellenwert (self._limit) sind, durch 0 (schwarz), heller - durch 255 (weiß) ersetzt.

Nach der Verarbeitung sieht das Bild wie folgt aus:


Wie Sie sehen können, hat das Programm mehrere der dunkelsten Teile des Bildes identifiziert. Nachdem Sie den Schwellenwert so kalibriert haben, dass die Kopfhörer vollständig „erfasst“ werden, werden neben ihnen andere weiße Elemente auf dem Bildschirm angezeigt. Natürlich können Sie die Schwelle fein einstellen, und auf dem Trainingsgelände schaut die Kamera nach unten, sodass keine unnötigen Elemente in den Rahmen gelangen. Ich halte es jedoch für erforderlich, die Linie von allem anderen zu trennen.

IV. Erkennung

Im binärisierten Bild habe ich einen Rahmensuchalgorithmus angewendet. Es wird benötigt, um freistehende Punkte zu bestimmen und sie in eine bequeme Anordnung von Koordinatenwerten von Punkten umzuwandeln, aus denen der Rand besteht. Im Fall von opencv, wie in der Dokumentation beschrieben, verwendet der Standardalgorithmus zum Auffinden von Schleifen den Suzuki85-Algorithmus (ich konnte mit Ausnahme der opencv-Dokumentation nirgendwo Verweise auf den Algorithmus mit diesem Namen finden, aber ich gehe davon aus, dass dies der Suzuki-Abe- Algorithmus ist ).

contours = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[0]

Und hier ist der Rahmen, der zu diesem Zeitpunkt erhalten wurde:


V. Verarbeitung auf hoher Ebene

Nachdem alle Konturen im Rahmen gefunden wurden, wird die Kontur mit der größten Fläche ausgewählt und als Kontur der Linie verwendet. Wenn man die Koordinaten aller Punkte dieser Kontur kennt, wird die Koordinate ihres Mittelpunkts gefunden. Hierzu werden die sogenannten "Bildmomente" verwendet. Der Moment ist die Gesamtcharakteristik der Kontur, berechnet durch Summieren der Koordinaten aller Pixel der Kontur. Es gibt verschiedene Arten von Momenten - bis zur dritten Ordnung. Für dieses Problem wird nur das Moment nullter Ordnung (m00) benötigt - die Anzahl aller Punkte, aus denen die Kontur besteht (Konturumfang), das Moment erster Ordnung (m10), das die Summe der X-Koordinaten aller Punkte ist, und m01 ist die Summe der Y-Koordinaten aller Punkte. Durch Teilen der Summe der Koordinaten der Punkte entlang einer der Achsen durch ihre Anzahl wird das arithmetische Mittel erhalten - die ungefähre Koordinate des Mittelpunkts der Kontur. Als nächstes wird die Abweichung des Roboters vom Kurs berechnet:Der Kurs „direkt“ entspricht der Koordinate des Mittelpunkts entlang X nahe der durch zwei geteilten Rahmenbreite. Wenn die Koordinate des Linienmittelpunkts nahe an der Mitte des Rahmens liegt, ist die Steueraktion minimal, und dementsprechend behält der Roboter seinen aktuellen Kurs bei. Wenn der Roboter von einer der Seiten abweicht, wird eine der Abweichung proportionale Steueraktion eingeleitet, bis er zurückkehrt.

mainContour = max(contours, key = cv2.contourArea)
M = cv2.moments(mainContour)
if M['m00'] != 0:#     (..   -  )
    cx = int(M['m10']/M['m00'])
    cy = int(M['m01']/M['m00'])

Unten sehen Sie eine schematische Zeichnung der Position des Roboters relativ zur Linie und den Rahmen, wobei die Ergebnisse des Programms überlagert sind: die „Hauptkontur“, die Linien, die durch die Mitte der Kontur verlaufen, sowie der Punkt in der Mitte, um die Abweichung abzuschätzen. Diese Elemente werden mit dem folgenden Code hinzugefügt:

cv2.line(frame, (cx, 0), (cx, self.height), (255, 0, 0), 1)    #    
cv2.line(frame, (0, cy), (self.width, cy), (255, 0, 0), 1)                  
cv2.circle(frame, (self.width//2, self.height//2), 3, (0, 0, 255), -1) #  
cv2.drawContours(frame, mainContour, -1, (0, 255, 0), 2, cv2.FILLED) #   

Zur Vereinfachung des Debuggens werden alle zuvor beschriebenen Elemente zum Roh-Frame hinzugefügt:





Nachdem wir den Frame durch den Verarbeitungsalgorithmus gefahren haben, erhalten wir die X- und Y-Koordinaten des Zentrums des für uns interessanten Objekts sowie das Debug-Bild. Als nächstes wird die Position des Roboters relativ zur Linie schematisch gezeigt, sowie das Bild, das den Verarbeitungsalgorithmus bestanden hat.


Der nächste Schritt im Programm besteht darin, die im vorherigen Schritt erhaltenen Informationen in die Leistungswerte von zwei Motoren umzuwandeln.

Der einfachste Weg, um die Differenz zwischen der Verschiebung der Mitte des Farbflecks relativ zur Mitte des Rahmens umzurechnen, ist der Proportionalregler (es gibt auch einen Relaisregler, der jedoch aufgrund seiner Funktionsweise nicht sehr gut zum Fahren entlang der Linie geeignet ist). Das Funktionsprinzip eines solchen Algorithmus besteht darin, dass die Steuerung eine Steueraktion auf das Objekt proportional zur Größe des Fehlers erzeugt. Neben dem Proportionalregler gibt es auch einen Integralregler, bei dem die Integralkomponente im Laufe der Zeit den Fehler und das Differential „akkumuliert“, dessen Prinzip auf der Anwendung der Regelungsmaßnahme nur bei ausreichender Änderung der Regelgröße beruht. In der Praxis werden diese einfachsten P, I, D-Regler zu Reglern vom Typ PI, PD, PID kombiniert.

Es ist erwähnenswert, dass ich bei meinem Roboter versucht habe, den PID-Regler zu „starten“, aber seine Verwendung brachte keine ernsthaften Vorteile gegenüber dem üblichen Proportionalregler. Ich gebe zu, dass ich den Regler nicht richtig einstellen konnte, aber es ist auch möglich, dass seine Vorteile bei einem schweren Roboter, der keine hohen Geschwindigkeiten entwickeln kann, nicht so deutlich sichtbar sind. In der neuesten Version des Programms zum Zeitpunkt des Schreibens wird ein einfacher Proportionalregler verwendet, jedoch mit einer kleinen Funktion, mit der Sie mehr Informationen von der Kamera verwenden können: Bei der Generierung des Fehlerwerts wurde nicht nur die horizontale Position der Mitte des Spots berücksichtigt, sondern auch die vertikale, was verschiedene Möglichkeiten ermöglichte auf Linienelemente reagierenBefindet sich „in der Ferne“ und unmittelbar vor oder unter dem Roboter (die Steuerkamera des Roboters hat einen großen Betrachtungswinkel, sodass Sie bereits einen signifikanten Teil des Feldes unter dem Roboter sehen können, wenn Sie ihn nur um 45 Grad nach unten drehen).

error= cx / (self.width/2) - 1  
#  ( 0   )  [-1; 1]
error*= cy / self.height + self.gain #

Unter den Bedingungen des "RTK Cup" -Wettbewerbs verwenden die Teilnehmer meistens den sogenannten "Tankkreis" - ein oder mehrere Motoren steuern eine Seite des Roboters und funktionieren sowohl mit Ketten als auch mit Rädern. Mit diesem Schema können Sie komplexe Getriebeelemente entfernen, die die Bruchgefahr erhöhen (Differentiale oder Kardanwellen), und den kleinstmöglichen Wenderadius erzielen, was bei einem begrenzten Polygon von Vorteil ist. Dieses Schema beinhaltet die parallele Steuerung von zwei "Seiten" für die Bewegung entlang eines komplexen Pfades. Zu diesem Zweck verwendet das Programm zwei Variablen - die Leistung des rechten und des linken Motors. Diese Leistung hängt von der Grundgeschwindigkeit (BASE_SPEED) ab und variiert im Bereich von 0 bis 100.Fehler (Fehler) - die Differenz zwischen der Mitte des Rahmens und der Koordinate der Linienmitte und dem vom Bediener kalibrierten Proportional-Effekt-Koeffizienten (self._koof). Sein absoluter Wert beeinflusst, wie schnell der Roboter versucht, sich an der Linie auszurichten. Aufgrund der Tatsache, dass bei einem Motor die Regelwirkung von der Grundgeschwindigkeit abgezogen wird und bei dem anderen - es wird hinzugefügt, wird eine Abweichung ausgeführt, wenn von der Strecke abgewichen wird. Die Richtung, in der die Umkehrung durchgeführt wird, kann durch Ändern des Vorzeichens der Variablen self._koof angepasst werden. Möglicherweise stellen Sie auch fest, dass im nächsten Codeabschnitt möglicherweise ein Leistungswert von mehr als 100 angezeigt wird. In meinem Programm werden solche Fälle jedoch später zusätzlich verarbeitet.Sein absoluter Wert beeinflusst, wie schnell der Roboter versucht, sich an der Linie auszurichten. Aufgrund der Tatsache, dass bei einem Motor die Regelwirkung von der Grundgeschwindigkeit abgezogen wird und bei dem anderen - es wird hinzugefügt, wird eine Abweichung ausgeführt, wenn von der Strecke abgewichen wird. Die Richtung, in der die Umkehrung durchgeführt wird, kann durch Ändern des Vorzeichens der Variablen self._koof angepasst werden. Möglicherweise stellen Sie auch fest, dass im nächsten Codeabschnitt möglicherweise ein Leistungswert von mehr als 100 angezeigt wird. In meinem Programm werden solche Fälle jedoch später weiter verarbeitet.Sein absoluter Wert beeinflusst, wie schnell der Roboter versucht, sich an der Linie auszurichten. Aufgrund der Tatsache, dass bei einem Motor die Regelwirkung von der Grundgeschwindigkeit abgezogen wird und bei dem anderen - es wird hinzugefügt, wird eine Abweichung ausgeführt, wenn von der Strecke abgewichen wird. Die Richtung, in der die Umkehrung durchgeführt wird, kann durch Ändern des Vorzeichens der Variablen self._koof angepasst werden. Möglicherweise stellen Sie auch fest, dass im nächsten Codeabschnitt möglicherweise ein Leistungswert von mehr als 100 angezeigt wird. In meinem Programm werden solche Fälle jedoch später zusätzlich verarbeitet.Bei der Umkehrung können Sie die Einstellung vornehmen, indem Sie das Vorzeichen der Variablen self._koof ändern. Möglicherweise stellen Sie auch fest, dass im nächsten Codeabschnitt möglicherweise ein Leistungswert von mehr als 100 angezeigt wird. In meinem Programm werden solche Fälle jedoch später weiter verarbeitet.Bei der Umkehrung können Sie die Einstellung vornehmen, indem Sie das Vorzeichen der Variablen self._koof ändern. Möglicherweise stellen Sie auch fest, dass im nächsten Codeabschnitt möglicherweise ein Leistungswert von mehr als 100 angezeigt wird. In meinem Programm werden solche Fälle jedoch später weiter verarbeitet.

#if lineFound:
leftSpeed = round(self.base_speed + error*self.koof)
rightSpeed = round(self.base_speed - error*self.koof)

Fazit


Nachdem ich das resultierende Programm getestet habe, kann ich sagen, dass der wichtigste schwierige Moment beim Einrichten des Programms die Kalibrierung des Algorithmus auf die Beleuchtungsmerkmale ist. Da die Phase der Erstellung des Artikels mit der erklärten Selbstisolierung zusammenfiel, musste ich ein Video mit einer Demonstration der Arbeit in einem kleinen Raum erstellen. Dies bereitete mir folgende Schwierigkeiten:

  • -, , ( , ), . , , , . , , , ,
  • -, — , ,

Trotz der Tatsache, dass diese beiden Probleme unter den Bedingungen realer Wettbewerbe nicht vorhanden sind, werde ich Maßnahmen ergreifen, um sicherzustellen, dass die Arbeit des Programms nur minimal von externen Faktoren abhängt.
Außerdem ist geplant, in Zukunft die Arbeit an der Implementierung von Algorithmen mithilfe von Computer-Vision-Methoden fortzusetzen und Software zu erstellen, die die verbleibenden im ersten Teil des Artikels beschriebenen Elemente der Autonomie (autonome Beacon-Erfassung, Bewegung auf einem komplexen Pfad) durchlaufen kann. Es ist geplant, die Funktionalität des Roboters um zusätzliche Sensoren zu erweitern: Entfernungsmesser, Gyroskop-Beschleunigungsmesser, Kompass. Trotz der Tatsache, dass die Veröffentlichung dieses Artikels meine Arbeit an dem Projekt als Pflichtschulfach beenden wird, plane ich, hier die weiteren Entwicklungsstadien weiter zu beschreiben. Daher möchte ich Kommentare zu dieser Arbeit erhalten.

Nach der Implementierung aller Schritte zur Lösung der Probleme des Projekts kann man mit Sicherheit sagen, dass die Verwendung von Computer-Vision-Algorithmen mit all ihrer relativen Komplexität beim Programmieren und Debuggen in der Phase der Wettbewerbe selbst den größten Gewinn bringt. Aufgrund der geringen Abmessungen der Kamera bietet sie ein enormes Potenzial für die Softwareentwicklung, da Sie mit der Kamera mehrere "herkömmliche" Sensoren gleichzeitig austauschen und dabei unglaublich mehr Informationen von der Außenwelt erhalten können. Es war möglich, das Ziel des Projekts zu verwirklichen - ein Programm zu erstellen, das mithilfe von Computer Vision das Problem der autonomen Navigation des Roboters unter den Bedingungen des Wettbewerbs „RTK Cup“ löst und den Prozess der Programmerstellung und die wichtigsten Phasen der Bildverarbeitung beschreibt.

Wie ich bereits sagte, war es jedoch nicht möglich, die komplexe Trajektorie der Hauslinie nachzubilden, und dieses Beispiel zeigt, wie der Algorithmus Kurven erfüllt. Die Dicke der Linie entspricht hier der gemäß der Vorschrift, und die Kurve selbst aus den Windungen spiegelt ungefähr die Rotationskrümmung um 90 Grad am Polygon wider:


Sie können den Programmcode sehen und weitere Arbeiten am Projekt, auf meinem Github oder hier überwachen , wenn ich fortfahre.

All Articles