Guten Tag, liebe Leser von Habr! Dies ist der zweite Artikel in einer Reihe von Artikeln über die praktische Verwendung von ROS auf dem Raspberry Pi. Im ersten Artikel der Serie habe ich die Installation der erforderlichen ROS-Komponenten und die Einrichtung der Arbeitsumgebung für die Arbeit beschrieben.Im zweiten Teil der Serie werden wir beginnen, die ROS-Funktionen auf der Raspberry Pi-Plattform praktisch zu nutzen. In diesem Artikel werde ich speziell auf die Verwendung der Raspberry Pi-Kamerakarte auf dem Raspberry Pi in Verbindung mit ROS zur Lösung von Computer-Vision-Problemen eingehen. Wer interessiert sich bitte unter Katze.Kamera-RPi-Kamerakarte
Für die Arbeit benötigen wir eine solche Raspberry Pi Camera Board-
Kamera : Diese Kamera wird über einen CSi-Anschluss auf der Platine direkt mit der GPU verbunden, sodass Sie das Bild von der Kamera ohne Prozessorzeit aufnehmen und codieren können. Ein ZIF-Kabel wird zum Anschließen der Kamera verwendet. Der Kabelanschluss auf der Karte befindet sich zwischen den Ethernet- und HDMI-Anschlüssen:
Bibliotheksinstallation
Fahren wir also mit der Installation der erforderlichen Bibliotheken fort. Installieren Sie zuerst OpenCV:$ sudo apt-get install libopencv-dev
Um die Raspberry Pi-Kamera verwenden zu können, benötigen wir die Raspicam-Bibliothek. Laden Sie das Archiv hier herunter .Installieren Sie als Nächstes die Bibliothek:$ tar xvzf raspicamxx.tgz
$ cd raspicamxx
$ mkdir build
$ cd build
$ cmake ..
$ make
$ sudo make install
$ sudo ldconfig
Sie müssen die Kameraunterstützung in Raspbian über das Programm raspi-config aktivieren:$ sudo raspi-config
Wählen Sie Option 5 - Kamera aktivieren, speichern Sie die Auswahl und starten Sie das System neu.Erste Schritte mit ROS
Erstellen Sie zur Vereinfachung einen neuen Kätzchen-Workshop für unsere Pakete:$ mkdir -p ~/driverobot_ws/src
$ cd ~/driverobot_ws/src
$ catkin_init_workspace
$ cd ~/driverobot_ws
$ catkin_make
Erstellen Sie ein neues ROS-Paket:$ cd src/
$ catkin_create_pkg raspi_cam_ros image_transport cv_bridge roscpp std_msgs sensor_msgs compressed_image_transport opencv2
Die Spezifikation des Befehls catkin_create_pkg lautet wie folgt: catkin_create_pkg <Paketname> [abhängig1] [abhängig2],wobei Sie alle Abhängigkeiten unter der Bibliothek angeben können - die Bibliotheken, die das Paket verwenden wird.Dieser Befehl erstellt das Framework des ROS-Projekts: ein leeres src-Verzeichnis für Knotenskripte und Konfigurationsdateien für CMakeLists.txt und package.xml.Ich habe ein einfaches Skript gefunden, das Bilder von der Kamera empfängt und sie mit dem „Herausgeber“ (Herausgeber) veröffentlicht und für ROS Indigo angepasst. Sie können es hier herunterladen .Um es zu verwenden, müssen Sie den Raspberry Pi UV4L-Kameratreiber installieren:$ curl http://www.linux-projects.org/listing/uv4l_repo/lrkey.asc | sudo apt-key add -
Fügen Sie der Datei /etc/apt/sources.list die folgende Zeile hinzudeb http://www.linux-projects.org/listing/uv4l_repo/raspbian/ wheezy main
Aktualisieren Sie die Pakete und installieren Sie:$ sudo apt-get update
$ sudo apt-get install uv4l uv4l-raspicam
Um den Treiber herunterzuladen, installieren wir bei jedem Systemstart auch ein optionales Paket:$ sudo apt-get install uv4l-raspicam-extras
Fahren wir mit der Bearbeitung des Pakets fort. Fügen Sie die Zeilen von hier in Ihre CMakeLists.txt-Datei ein .Die wichtigsten Zeilen in der Datei CMakeLists.txt:link_directories(/usr/lib/uv4l/uv4lext/armv6l/)
…
target_link_libraries(capture ${catkin_LIBRARIES} uv4lext)
Daher fügen wir einen Link zum uv4l-Treiber hinzu, der zum Kompilieren des Pakets erforderlich ist.Am Ende der Datei setzen wir spezielle Zeilen für unseren Knoten:add_executable(capture src/capturer.cpp)
target_link_libraries(capture ${catkin_LIBRARIES} uv4lext)
Die Zeile add_executable erstellt eine Binärdatei für den Start und target_link_lbraries verknüpft zusätzliche Bibliotheken für die Capture-Binärdatei.Fügen Sie die fehlenden Zeilen von hier aus so in die Datei package.xml ein, dass sie folgendermaßen aussehen:<?xml version="1.0"?>
<package>
<name>raspi_cam_ros</name>
<version>0.0.0</version>
<description>The raspi_cam_ros package</description>
<maintainer email="pi@todo.todo">pi</maintainer>
<license>TODO</license>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>cv_bridge</build_depend>
<build_depend>image_transport</build_depend>
<build_depend>roscpp</build_depend>
<build_depend>std_msgs</build_depend>
<build_depend>sensor_msgs</build_depend>
<build_depend>opencv2</build_depend>
<build_depend>compressed_image_transport</build_depend>
<run_depend>cv_bridge</run_depend>
<run_depend>image_transport</run_depend>
<run_depend>roscpp</run_depend>
<run_depend>std_msgs</run_depend>
<run_depend>sensor_msgs</run_depend>
<run_depend>opencv2</run_depend>
<run_depend>compressed_image_transport</run_depend>
</package>
In den ersten Zeilen werden die grundlegenden Parameter des Knotens festgelegt - Name, Version, Beschreibung, Informationen zum Autor. Die build_depend-Zeilen bestimmen die Bibliotheksabhängigkeiten, die zum Kompilieren des Pakets erforderlich sind, und die run_depend-Zeilen bestimmen die Abhängigkeiten, die zum Ausführen des Codes im Paket erforderlich sind.Erstellen Sie eine capturer.cpp-Datei im Ordner src und fügen Sie die Zeilen von hier aus ein . Hier in der main () -Methode wird der Knoten initialisiert und in einer Schleife gestartet:ros::init(argc, argv,"raspi_cam_ros");
ros::NodeHandle n;
UsbCamNode a(n);
a.spin();
Die gesamte Logik des Skripts besteht darin, dass wir das Bild mit OpenCV von der Kamera abrufen, es in eine Nachricht für ROS in der fillImage-Methode einbinden und im Thema veröffentlichen. Hier wird das image_transport-Paket verwendet, um ein "Publisher" -Bild zu erstellen.Starten Sie den uv4l-Treiber, indem Sie den folgenden Befehl ausführen:$ uv4l --driver raspicam --auto-video_nr --width 640 --height 480 --nopreview
Was wird MJPEG-Streaming erstellen.Kompilieren Sie unseren ROS-Knoten:$ roscore
$ cd ~/driverobot_ws
$ catkin_make
Überprüfen Sie den Wert der Variablen ROS_PACKAGE_PATH:echo $ROS_PACKAGE_PATH
/opt/ros/indigo/share:/opt/ros/indigo/stacks
Der Wert der Variablen ROS_PACKAGE_PATH sollte den Pfad zu unserem Arbeitsbereich enthalten. Fügen Sie dem Pfad unseren Werkstattraum hinzu:$ source devel/setup.bash
Wenn Sie nun den Befehl echo $ ROS_PACKAGE_PATH erneut ausführen, sollte eine ähnliche Ausgabe angezeigt werden:/home/youruser/catkin_ws/src:/opt/ros/indigo/share:/opt/ros/indigo/stacks
, wobei / home / <Benutzername> / catkin_ws / src der Pfad zu unserem Arbeitsbereich ist. Dies bedeutet, dass ROS unsere in catkin_ws erstellten Knoten „sehen“ und sie durch rosrun ausführen kann.Führen Sie unseren ROS-Knoten aus:$ rosrun raspi_cam_ros capture
Führen Sie das Grafikprogramm rqt_image_view aus, um den Videostream aus dem Thema anzuzeigen:$ rosrun rqt_image_view rqt_image_view
Wählen Sie das Thema image_raw im Fenster rqt_image_view aus.
Beim Starten des Knotens kann der Fehler "Gtk-WARNING **: Anzeige kann nicht geöffnet werden: -1" auftreten, wenn Sie über ssh arbeiten, oder "GdkGLExt-WARNING **: Fenstersystem unterstützt OpenGL nicht." bei Ausführung im VNC-Remotedesktopmodus. Die Lösung besteht darin, über XH mit X11-Weiterleitung eine Verbindung zum Raspberry Pi herzustellen:$ ssh -X pi@<host_pi>
Mit dem Befehl rostopic können Sie herausfinden, wie oft Beiträge zum Thema gepostet werden:rostopic hz image_raw
Dieser Befehl berechnet die Häufigkeit des Empfangs von Nachrichten pro Thema pro Sekunde und zeigt sie in der Konsole an.Für Modell B + hatte ich eine Schlussfolgerung wie folgt:average rate: 7.905
min: 0.075s max: 0.249s std dev: 0.02756s
Wie Sie sehen können, beträgt die Häufigkeit der Veröffentlichung 8 Hz.Ich habe auch die Häufigkeit der Veröffentlichung von Bildern von der Kamera auf dem RPi 2-Modell überprüft. Hier waren die Ergebnisse um ein Vielfaches besser:average rate: 30.005
min: 0.024s max: 0.043s std dev: 0.00272s
Nachrichten werden bereits mit einer Frequenz von 30 Hz veröffentlicht, was im Vergleich zum B + -Modell eine ziemlich gute Geschwindigkeitssteigerung darstellt.Visuelle Robotersteuerung mit OpenCV und ROS
Jetzt schreiben wir ein kleines ROS-Paket für die Verwendung von Computer Vision auf einem Roboter mit dem Raspberry Pi, das den Erkennungsalgorithmus (in unserem Fall die visuelle Ausrichtung mithilfe der Linienfolgemethode) ausführt und den Wert des erforderlichen Roboterversatzes zum Thema veröffentlicht. Andererseits abonniert der Roboter-Bewegungssteuerungsknoten dieses Thema und sendet Bewegungssteuerungsbefehle an das Arduino.Fügen wir nun dem Skript capturer.cpp einen "Herausgeber" hinzu, der den Verschiebungswert veröffentlicht. Aktivieren Sie zunächst die Definition des Nachrichtentyps für den Verschiebungswert - std_msgs / Int16.#include <std_msgs/Int16.h>
rosserial nimmt spezielle Nachrichtendateien und generiert Quellcode für diese. Die folgende Vorlage wird verwendet: Der Quellcode für Standard-Rosserialnachrichten wird im Ordner package_name im Verzeichnis ros_lib gespeichert. Als nächstes initialisieren wir die Nachricht für diesen Typ:package_name/msg/Foo.msg → package_name::Foo
std_msgs::Int16 shift_msg;
Erstellen Sie einen "Publisher":ros::Publisher shift_pub;
und innerhalb des UsbCamNode-Konstruktors geben wir ihm eine Definition:shift_pub = nh.advertise<std_msgs/Int16>(“line_shift”, 1);
Hier legen wir die Art der Nachrichten und den Namen des Themas für die Veröffentlichung fest.Als Nächstes fügen wir die Logik zum Berechnen des Zeilenverschiebungswerts mit OpenCV und zum Veröffentlichen im line_shift-Thema in der Methode take_and_send_image () vor der Zeile #ifdef OUTPUT_ENABLED hinzu:
shift_msg.data = offset;
shift_pub.publish(shift_msg);
Ich habe keinen vorgefertigten Zeilenverfolgungsalgorithmus, daher kann der Leser hier seine eigene Logik schreiben.Tatsächlich werden die Daten in der Nachricht im Datenfeld gespeichert. Die Nachrichtenstruktur kann mit dem folgenden Befehl angezeigt werden:$ rosmsg show std_msgs/Int16
Führen Sie nun den Knoten aus:$ rosrun raspi_cam_ros capturer
Wir verwenden den Befehl rostopic echo, um Daten auszugeben, die im Thema line_shift veröffentlicht wurden:$ rostopic echo line_shift
Fügen Sie nun dem Robotersteuerungsknoten einen „Teilnehmer“ hinzu. Aktivieren Sie die Definition des Nachrichtentyps:#include <std_msgs/UInt16.h>
Dann fügen wir eine Rückruffunktion hinzu, die ausgeführt wird, wenn eine Nachricht vom Thema empfangen wird.void messageCb(const std_msgs::UInt16& message)
{
int shift_val = int(message.data);
char* log_msg;
if(shift_val < 0) log_msg = "Left";
else if(shift_val > 0 ) log_msg = "Right";
else log_msg = "Forward";
nh.loginfo(log_msg);
}
Die Rückruffunktion muss vom Typ void sein und eine konstante Referenz des Nachrichtentyps als Argument verwenden.Der Einfachheit halber protokolliere ich eine Nachricht über die Richtung des Linienversatzes. Hier können Sie Ihre eigene Roboterbewegungslogik für Ihr Szenario hinzufügen.Erstellen Sie einen Abonnenten für Nachrichten aus dem Thema line_shift.ros::Subscriber<std_msgs::UInt16> sub("line_shift", &messageCb);
Hier setzen wir den Namen des Themas und einen Link zur Rückruffunktion.Als nächstes folgen die Standardskizzenmethoden für rosserial_arduino:void setup()
{
nh.initNode();
nh.subscribe(sub);
Serial.begin(57600);
}
void loop()
{
nh.spinOnce();
delay(100);
}
Der einzige Unterschied besteht darin, dass wir nh.subscribe (sub) hinzufügen, um das tatsächliche "Abonnement" des Knotens für das Thema zu erstellen.Eine Skizze zur Steuerung eines Roboters kann hier heruntergeladen werden .Kleiner Trick! In ROS gibt es spezielle Startdateien, mit denen Sie Knoten als separate Prozesse mit bestimmten Parametern automatisch starten können. Startdateien werden im XML-Format erstellt und mit ihrer Syntax können Sie viele Knoten gleichzeitig ausführen. Die Startdatei garantiert jedoch nicht, dass die Knoten in der angegebenen genauen Reihenfolge gestartet werden.Sie können eine Startdatei erstellen, um den Start des rosserial_python-Servers zu vereinfachen.$ cd <catkin_ws>/src
$ catkin_create_pkg rosserial_controller
$ cd src/rosserial_controller
$ vim rosserial_controller.launch
Wir schreiben eine Startdatei mit folgendem Inhalt:<launch>
<node pkg="rosserial_python" type="serial_node.py" name="arduino_serial">
<param name="port" value="/dev/ttyACM0"/>
</node>
</launch>
Kompilieren und ausführen:$ cd ~/<catkin_ws>
$ catkin_make
$ source devel/setup.bash
$ roslaunch rosserial_controller rosserial_controller.launch
Wir können die im line_shift-Theme veröffentlichten Werte mit dem Dienstprogramm rqt_plot visualisieren, wie im Artikel beschrieben :$ rqt_plot line_shift
Jetzt können Sie die Raspberry Pi-Kamera und die OpenCV-Bibliothek in Ihren Skripten voll ausnutzen, um den Roboter visuell zu orientieren, Objekte zu erkennen, zu verfolgen und viele andere. Lassen Sie Ihrer Fantasie freien Lauf!Das nächste Mal werden wir über die Steuerung des Roboters im Teleoperationsmodus durch Drücken der Tasten auf der Tastatur sprechen.PS. Das Netzwerk verfügt über nützliche Spickzettel - ROS-Spickzettel. Für die ROS Indigo-Version kann diese hier heruntergeladen werden .