Inhalt
Bei der Antriebsplattform habe ich mich für einen Raupenantrieb entschieden. Diesen habe ich mit Zahnriemenscheiben und Doppeltverzahnten Zahnriemen(T10) realisiert. Die Antriebs- und Umlenkwellen sind schlicht Kugelgelagert. Den Rahmen habe ich aus Aluminiumprofilen zusammengebaut.
Die mobile Roboterplattform im Aufbau
Als Antriebsmotoren für die Roboterplattform werden zwei 24V- Getriebemotoren mit eingebautem Impulsgeber zur Drehzahlmessung-/ -Regelung verwendet. Die Motoren vom Typ EMG49 von Devantech sind mittels Klauenkupplungen mit den Antriebswellen verbunden und mittels zweier Aluminiumwinkel am Grundrahmen befestigt.
Technische Daten der Antriebsmotoren EMG49
Betriebsspannung | 24V DC |
Nenndrehmoment | 16kg/cm |
Nenngeschwindigkeit | 122rpm |
Nennstrom | 2100mA |
Leerlaufdrehzahl | 143rpm |
Leerlaufstrom | 500mA |
Blockierstrom | 13A |
Nennleistung | 37,4W |
Encoderimpulse pro Motorumdrehung | 588 |
Getriebeuntersetzung | 49:1 |
Auf dem Grundgestell wurde dann eine Einhausung aus Aluminiumprofilen und -Blechen aufgebaut, die die bisherige Elektronik und Spannungsversorgung des Roboters beinhaltet.
Die mobile Roboterplattform im Aufbau
Im Bild oben ist der bisherige Aufbau der mobilen Roboterplattform schematisch skizziert
Statt des Raspberry Pi verwende ich inzwischen den leistungsfähigeren Einplatinencomputer pcDuino3 als Rechner auf dem Roboter.
Wir können die serielle Schnittstelle des MD49 nicht ohne weiteres mit der des pcDuino verbinden, da der pcDuino 3,3V und das MD49-Board 5V als Betriebsspannung am jeweiligen UART führt. Deswegen setzten wir hier beidseitig einen Pegelwandler ein. Für das MD49 den MAX232-5V-Pegelwandler und für den pcDuino den MAX3232-3,3V-Pegelwandler. Die Schaltung und Platine habe ich mit der E-CAD Software Target3001 entworfen.
Das Layout und PCB ist hier dasselbe, wie beimMAX232-5V-Pegelwandler. Auch von der Bestückung ist es annähern baugleich, nur ist bei der 3,3V-Version statt dem MAX232 der MAX3232 verbaut und statt den 10µF Elkos werden 1µF Elkos verwendet.
Als Motortreiber wird die Steuerplatine MD49 verwendet, es wird wie die Motoren von der Firma Devantech vertrieben. Die Ansteuerung erfolgt per serieller Schnittstelle und es ist geeignet für den Betrieb zweier EMG49-Motoren.
Die Eckdaten für diesen 24V 5A Dual H-Bridge Motortreiber:
Link zur technischen Dokumentation MD49
Als Spannungsversorgung für die Antriebe und die Antriebsregelung verwende ich zwei 12V-Bleigel-Akkus, die in Reihe geschalten die nötigen 24V für Antriebe und Antriebsregelung bereitstellen.
Als Spannungsversorgung für den Einplatinencomputer und alle anderen 5V- Komponenten verwende ich eine 5V Powerbank mit 19,6 Ah
Die Elektronik der mobilen Roboterplattform im Aufbau
Für weitere Mess- und Regelaufgaben, z.B. die Auswertung der Akkuspannung und den Anschluss weiterer Sensorik und Aktorik für den Roboter sollen Mikrokontrollerboards auf Basis des Arduinos zum Einsatz kommen. Diese können einfach per USB mit dem pcDuino verbunden und programmiert werden. Messwerte und Kommandos könnten ebenfalls einfach per USB zwischen Arduino und pcDuino seriell übertragen werden. Um die Programmierung der Arduinos auch per Kommandozeile zu ermöglichen kann man Inotool verwenden, damit kann man Arduino-Projekte ohne die Arduino IDE unter Linux per Kommandozeile erstellen, kompilieren und übertragen. Mehr zur Installation der Arduino IDE, Inotool und Integration von Arduinos in ROS ist im Kapitel Betriebssystems (robotOS) für pcDuino installieren und im Kapitel Grundlagen unter ROS: Arduino als ROS-Nodes beschrieben.
Ich habe lange überlegt, mit welcher Sensorik der Roboter zur Objekt- bzw. Hinderniserkennung ausgestattet werden soll. Ein Ziel des Projekts ist ja, dass der Roboter später autonom navigieren und seine Umgebung Kartografieren soll (Mapping). ROS bietet dazu den Navigation Stack, den wir nach und nach implementieren wollen. Dazu sind natürlich Sensordaten notwendig.
Prinzipiell gibt es mehrere Möglichkeiten diese Sensordaten zu liefern. Da wären zum einen Laserscanner, wie sie oft in anderen Projekten verwendet werden, wie der Hokuyo URG-04LX (~1.100€) oder der etwas günstigere RPLIDAR (~400€). Ein anderer inzwischen von ROS unterstützter Laserscanner ist der XV-11, der aus einem Neato Staubsaugerroboter stammt und teilweise gebraucht (~150€) erstanden werden kann. Ein wesentlicher Nachteil ist hier, zumindest bei den professionellen Ansätzen, der hohe Preis für den Sensor.
Eine weitere, günstigere Möglichkeit wäre, einen eigenen Sensor auf Ultraschall- oder Infrarotbasis aufzubauen. Vorstellbar wäre z.B. ein Aufbau aus einem SR04- oder SR08 Ultraschallsensor auf einem Servo, der dann zum Beispiel einen Bereich von 180° scannt und die Daten als ROS Laserscan Message bereit stellt. Ein Nachteil bei dieser Lösung ist zum einen die beschränkte Reichweite der Sensoren und die durch den Aufbau bedingte langsame Verarbeitungsgeschwindigkeit der Daten.
Bei meiner Recherche bin ich dann über den Microsoft Kinect, den man ja von der XBOX kennt, gestolpert. Der Sensor ist inzwischen gebraucht relativ günstig zu erhalten (~60€) und wird von ROS unterstützt. Deshalb viel meine Wahl zunächst auf diesen Sensor. Einzelheiten zur Inbetriebnahme, Programmierung und Integration in ROS findet man unten im ROS Package robot_kinect
Ich verwende derzeit als Workstation sowohl ein Notebook, arbeite aber parallel auch in einer VM mit der Oracle VM VirtualBox auf meinem Desktop-PC unter Windows 10. Aufgebaut wird auf einer Basisinstallation von Ubuntu 16.04 Xenial. Das Betriebssystem workstationOS mit ROS Kinetic wurde eingerichtet, wie im folgenden beschrieben:
Zuerst habe ich Ubuntu 16.04 a) unter Windows10 in einer VM und b) auf dem ebenfalls als Workstation verwendeten Laptop direkt installiert.
Benutzerdaten
User: user
Hostname: workstationOS
Static IP
In Ubuntu am einfachsten über die grafische Netzwerkeinstellung ändern.
192.168.178.201
Passwort für User root ändern
sudo passwd root
System aktualisieren
sudo apt-get update
sudo apt-get upgrade
Hostname ändern, falls nicht bereits bei der Installation festgelegt, in workstationOS
sudo nano /etc/hosts
sudo nano /etc/hostname
sudo reboot
Ein paar Softwarepakete installieren
sudo apt-get install libnss-mdns sshpass chrony sqlite3 git lxterminal
ROS-Kinetic installieren
Auf anderen auf Ubuntu basierenden Distributionen (z.B. Elementary OS oder Linux Mint) kann statt dem Befehl oben folgender Befehl verwendet werden:
Auf anderen auf Ubuntu basierenden Distributionen (z.B. Elementary OS) diese Zeile in die .bashrc einfügen bevor rosdep update ausgeführt wird:
ROS-Package robot-pose-ekf
ROS-Package joy installieren
Dieses Package enthält die Node joy_node, welche für uns die Auswertung eines angeschlossenen Joysticks/Gamepads übernimmt und uns die ermittelten Daten mittels ROS-Topic /joy zur weiteren Verwendung bereitstellt. Das Package mit folgendem Befehl installieren:
ROS-Package rosbridge-suite
Dieses Package wird später verwendet um Web-Konnektivität mittels ROS herzustellen
ROS-Package liburdfdom-tools
ROS-Package map-server
ROS-Package amcl
Kinect-Treiber und ROS-Package freenect_stack
ROS-Package depthimage_to_laserscan
ROSserial mit Arduino
Arduino Toolchain
Es wurde auf dem workstationOS die komplette Arduino Toolchain installiert, wie weiter unten, unter Betriebssystem (robotOS) für pcDuino installieren, beschrieben. Also die Arduino IDE, Ino für die Programmierung der Arduinos in der Kommandozeile und die Integration in ROS per rosserial.
Um mit den Arduinos zu arbeiten muss der angemeldete User Mitglied der Gruppe dialout sein:
ROS-Workspace von Git klonen und kompilieren
Elementary OS oder andere auf Ubuntu basierende Distributionen, statt dem Befehl oben folgenden Befehl verwenden:
ROS für SSH- Betrieb einrichten
export ROSLAUNCH_SSH_UNKNOWN=1 in ~/.bashrc einfügen
ROS für das lokale Netzwerk einrichten
dort folgende Zeilen anhängen
export ROS_IP="workstationOS.local" export ROS_HOSTNAME="workstationOS.local" export ROS_MASTER_URI=http://workstationOS.local:11311 |
Skript ssh2robot.sh und Desktopverknüpfung
Zuerst das Skript zum starten der SSH-Verbindung zum robotOS erstellen:
#!/bin/bash PASSWD="yourpassword" echo Connecting robot@robotOS... sshpass -p "$PASSWD" ssh -X robot@robotOS.local |
und mit
ausführbar machen.
Auf dem Desktop dann folgenden Desktopeintrag ssh2robot.desktop einrichten:
[Desktop Entry] Type=Application Hidden=false NoDisplay=false Exec=lxterminal -e /home/user/ssh2robot.sh Name=SSH to robot@robotOS X-Forwarded Icon=utilities-terminal Terminal=false Name[de_DE]=SSH to Robot |
Bei Elementary OS das File in /usr/share/applications erstellen, es kann dann im Dock verankert werden.
IDEs für die Programmierung (C++)
Inzwischen habe ich mich für einfachere Arbeiten am Quellcode des Projekts für den Editor Atom IDE entschieden.
Atom IDE
Um in der IDE ein Terminal (z.B. zum kompilieren einer Änderung) zur Verfügung zu haben habe ich mich für das Atom Package Termination entscheiden, das wie folgt installiert werden kann:
Once a new release is out, install updates via command:
Webserver Nginx, Sqlite und PHP installieren
Zuerst klonen des webserver_root Directorys von Github:
Installieren von nginx, php5 und sqlite
nginx Konfiguration:
bei folgender Zeile den Kommentar entfernen:
darunter “index.php” hinzufügen:
nun das document-root- Verzeichnis von nginx anpassen in:
dann folgende Zeilen auskommentieren:
User user zur Gruppe www-data hinzufügen:
Ändern des Users für nginx von www-data zu user
hier ändern:
Damit sowohl aus den einzelnen Programmen (erstellt in C++) und auch aus dem Browser, z.B. mit phpliteadmin auf die Datenbanken zugegriffen werden kann muss man noch folgende Anpassungen vornehmen:
Ändern des Users für php von www-data zu user:
hier ändern:
Nginx und PHP5-fpm neustarten:
Nginx Monitoring Tool
Ein gutes Kommandozeilen Tool um den Traffic auf dem Webserver anzuzeigen ist ngxtop.
Zuerst falls noch nicht geschehen pip, einen Python Package-Installer installieren:
Dann ngxtop installieren mit:
und mit ngxtop starten.
Eine andere Ausgabe kann z.B. mit folgendem Befehl erzeugt werden:
ngxtop print request http_user_agent remote_addr
Damit der Server auch unter seiner WAN, nicht nur unter seiner lokalen IP, auch von außerhalb des lokalen Netzwerks erreichbar ist, muss am Router eine Portweiterleitung für den Webserver eingerichtet werden, hier exemplarisch für einen Speedport-Router der Telekom oder die Fritzbox 7490:
Dyndns einrichten
Damit der Server bzw. das Webinterface des Roboters auch unter einer festen IP erreichbar ist, wurde unter no-ip.com ein DynDNS- Dienst eingerichtet. Der Server ist somit,wenn online unter der Adresse robotik.ddns.net erreichbar.
Router ohne NAT-Loopback
Unterstützt der Router ,z.B. der Telekom Speedport 723V, kein NAT-Loopback muss man, damit der Webserver auch im lokalen Netzwerk unter robotik.ddns.net erreichbar ist, auf allen Rechnern im lokalen Netzwerk die hosts-Dateien anpassen.
Unter Linux:
In Datei ‘/etc/hosts’ den Eintrag ‘IP_der_Workstation robotik.ddns.net’ anhängen, z.B.:
192.168.178.201 robotik.ddns.net
Unter Windows findet man die Datei hosts unter C:\Windows\System32\drivers\etc
Sublime Text installieren
Ein praktischer Editor für Sourcecodes
VNC-Viewer installieren
Am besten Reminna dazu verwenden, es ist bereits in der Standardinstallation von Ubuntu 14.04 enthalten
Doxygen und epydoc installieren
In das Verzeichnis des zu dokumentierenden Packages wechseln:
cd ~/ROS-Workspace/src/base_controller
sudo nano rosdoc.yaml (neu anlegen)
- builder: epydoc |
sudo nano package.xml (folgendes im export tag einfügen)
<export> |
rosdoc_lite .
Die Dokumentation wird in ~/ROS-Workspace/src/base_controller/doc erstellt
( Ich verwende rosdoc-lite, der Vollständigkeit halber sei hier folgende Möglichkeit erwähnt:
Doxygen im QTCreator verwenden:
Package in den Editor laden wie oben unter QT installieren beschrieben, hier z.B. das base_controller Package.
<Projekte> -> Build-Schritt hinzufügen: Kommando: doxygen; als Argumente den Pfad zum Doxyfile (/home/user/ROS-Workspace/src/base_controller/src/base_controller/Doxyfile)
)
Bloom
Release Tool. Wird von mir verwendet, um ROS Packages zu veröffentlichen
ZSH als Shell
Will man ZSH als Linux Shell benutzen:
ZSH als Standardshell für den user ‘user’
Oh-My-ZSH bietet viele Themes und nützliche Addons für ZSH
TMUX
VIM
Zuerst alles an VIM vom System entfernen, was vielleicht schon vorhanden ist
VIM-Nox installieren:
VIM Plugins
myDotFiles clonen:
Symlinks anlegen:
dann ausführen:
Dann alle colorschemes von flazz/colorschemes nach .vim/colors kopieren/verschieben
Damit das Vim Plugin vim-airline Symbole in der Statusbar richtig anzeigt, brauchen wir die Powerlinefonts:
Im Gnome Terminal muss dann bei den Profileinstellungen auch ein Powerlinefont, z.B. ‘Ubuntu Mono derivative Powerline’ eingestellt werden.
FreeCAD
PyCharm
IDE für Python
Docker
Videocapture
Bildbearbeitung
Entweder die eierlegende Wollmilchsau:
Eine einfachere, MS Paint entsprechende Variante
Ich verwende zur Zeit für meinen pcDuino3 die Ubuntu Xenial Distribution von Armbian. Derzeit die Legacy Variante mit Kernel 3.4.113 für den pcDuino3.
Das Betriebssystem robotOS mit ROS Kinetic wurde, wie im folgenden beschrieben, eingerichtet:
Basisinstallation Ubuntu Xenial
Das Image (RAW-Datei) Armbian_5.31_Pcduino3_Ubuntu_xenial_default_3.4.113_desktop.img z.B. unter Windows mit Win32DiskImager auf eine MicroSD brennen und den pcDuino damit booten. Man kann sich das erste mal mit Username: root und Passwort: 1234 anmelden. Dabei wird man direkt aufgefordert ein neues root- Passwort einzugeben und kann dann einen neuen User anlegen. Bei mir heißt der neu angelegte User ‘robot’.
Nun richten wir das WLAN ein, dazu zuerst mit:
den Onboard-WLAN-Adapter einrichten.
Von nun an kann man auch headless per SSH auf dem pcDuino, als User root oder User robot, einloggen:
Nun fügen wir dem neuen User der Gruppe sudo und einigen anderen Gruppen hinzu
AVAHI Daemon und Chrony
Betriebssystem auf SATA-Festplatte transferieren
Jetzt die SATA Platte anschließen und das folgende Script starten:
Nach einem Neustart, sollte der pcduino nun von der Festplatte booten, was mit df -h überprüft werden kann.
System aktualisieren
Hostname ändern, dazu in /etc/hosts und /etc/hostname von pcduino3 in robotOS ändern
ROS Kinetic installieren und einrichten
ROS für lokales Netzwerk einrichten
export ROS_IP="robotOS.local" export ROS_HOSTNAME="robotOS.local" export ROS_MASTER_URI=http://workstationOS.local:11311 |
Environment File erstellen, damit ROS Nodes remote auf dem pcDuino ausgeführt werden können:
#!/bin/sh |
speichern und ausführbar machen mit:
ROS-Workspace installieren
Die mobile Roboterplattform im Aufbau
Serielle Schnittstelle UART2 einrichten
zeigt zwar , dass ttyS1 richtig konfiguriert ist:
serinfo:1.0 driver revision: 0: uart:U6_16550A mmio:0x01C28000 irq:40 tx:53 rx:0 RTS|DTR 1: uart:unknown port:00000000 irq:0 2: ... |
RX und TX von ttyS1 (UART2) am GPIO sind aber standardmässig noch als I/O konfiguriert (siehe Forenpost). Abhilfe schafft das Skript setuart2, welches z.B. manuell heruntergeladen und gestartet werden kann:
wget --no-check-certificate http://www.the-starbearer.de/Files/setuart2
sudo chmod +x setuart2
Jetzt kann der UART2 (ttyS1) manuell mit ‘sudo ./setuart2 on’ aktiviert, und mit ‘sudo ./setuart2 off’ wieder deaktiviert werden.
Sowohl der Quellcode als die ausführbare Datei setuart2 sind auch auf https://github.com/Scheik/pcDuino_UART2.git hinterlegt.
Um den Befehl ‘setuart2 on’ aber nicht nach jedem Neustart des pcDuino manuell neu eingeben zu müssen, nehmen wir folgende Änderungen am System vor.
Zuerst erstellen wir ein neues Script in /etc/init.d:
und speichern es mit folgen Inhalt ab:
#!/bin/sh ### BEGIN INIT INFO # Provides: setuart2on.sh # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start script at boot time # Description: Enable service provided by script. ### END INIT INFO sudo /home/robot/ROS-Workspace/scripts/setuart2 on |
nun machen wir dieses Skript und die Datei setuart2 ausführbar mit:
und fügen wir es den Sytemservices hinzu:
Jetzt wird der Befehl ‘setuart2 on’ bei jedem Systemstart automatisch ausgeführt und man muss ihn nicht nach jedem Neustart erneut eingeben. Die Konfiguration kann mit folgendem Befehl erneut überprüft werden:
serinfo:1.0 driver revision: 0: uart:U6_16550A mmio:0x01C28000 irq:33 tx:11574 rx:0 RTS|DTR 1: uart:U6_16550A mmio:0x01C28800 irq:35 tx:16300 rx:14021 RTS|DTR 2: uart:unknown port:00000000 irq:0 ... |
VNC Server installieren
VNC starten um config file zu erzeugen:
VNC wieder stoppen:
Bei XFCE waren keine Änderungen notwendig in ~/.vnc/xstartup
VNC neu starten:
Arduino Toolchain installieren
Arduino IDE installieren
Arduino IDE starten damit das Verzeichnis /sketchbook angelegt wird
Inotool, dazu installieren wir pip, einen Python Package-Installer:
dann Inotool selbst
und ein Terminalprogramm für die Konsole
ROSserial mit Arduino
Nach dem Neustart der Arduino-IDE sollte ros_lib unter File -> Examples zu finden sein.
Im Kapitel Grundlagen unter 4. Arduino (Linux) zeige ich anhand einfacher Beispiele, wie man Arduinos mit Inotool auch per Kommandozeile programmieren oder direkt im ROS-Workspace per CMake mithilfe von rosserial_arduino kompilieren kann. Arduinos können so, auf dem hier gezeigten Weg, auch als Nodes für ROS programmiert werden. Beispielcodes dazu sind im ROS-Workspace im Package arduino_examples zu finden.
Kinect-Treiber und ROS-Package freenect_stack
Der angemeldete User muss, falls nicht schon geschehen, zur Gruppe video hinzugefügt werden und Mitglied der Gruppe plugdev sein.
Package depthimage_to_laserscan installieren
WLAN ändern
Muss man mit einem neuen WLAN verbinden, kann man dazu einfach die Einstellungen in /etc/network/interfaces ändern.
Bisher haben wir das robotOS immer per WLAN direkt mit unserem Router verbunden, um eine Internetverbindung herzustellen und im lokalen Netzwerk eine Verbindung zur Workstation zu haben. Das ist für den Betrieb des Roboters im lokalen Heimnetz in Ordnung, bringt aber das Problem mit sich, dass wir den Roboter im Verbund mit der Workstation außerhalb unseres Heimnetzes so nicht betreiben können.
Dieses Problem kann man folgendermaßen umgehen:
Auf dem Smartphone z.B. die Android App ‘Wi-Fi hotspot’ oder jede andere funktionierende WLAN Hotspot App installieren und beide Geräte (Workstation und Roboter) mit dem hier erstellten WLAN verbinden.
Autologin als User robot
Wie man sieht, habe ich mich für die Software ROS als Betriebssystem/Middleware für den Roboter entschieden; und ich habe wie oben beschrieben ROS Indigo auf dem pcDuino und der Ubuntu-Workstation installiert. Das unten verlinkte Git- Repository enthält den aktuellen ROS Workspace für den Betrieb des Roboters als Catkin Workspace.
Der komplette Sourcecode befindet sich als Repository auf GitHub unter:
Das Repository wird für den Betrieb des Roboters, wie folgt, sowohl auf den pcDuino als auch die Ubuntu-Workstation geklont und kompiliert.
Im folgenden beschreibe ich die Funktion aller ROS-Packages, Nodes und Funktionsbibliotheken in diesem Workspace, die ich für den Betrieb des Roboters entwickelt habe. Dabei kommen im Verlauf des Projekts viele eigens programmierte Codes dazu, es werden dazu aber auch 3rd-Party Packages verwendet oder kommen modifiziert zur Anwendung.
Die erste Aufgabe bestand darin eine Möglichkeit zur Fernsteuerung der Roboterantriebe mittels ROS zu implementieren (Also ein Teleoperation, kurz TeleOP- Modus). Der ROS Workflow dazu sieht so aus:
Einfaches Beispiel zur Veranschaulichung der Funktionsweise von ROS, hier zur Fernsteuerung mittels Gamepad
Dieses Basissetup stellt auch schon ganz gut die prinzipielle Funktion der mobilen Roboterplattform mit ROS dar. Dieses einfache Setup ermöglicht so erst mal die einfache Fernsteuerung der Roboterplattform per Joystick oder Gamepad von der Workstation aus.
Ein Vorteil von ROS ist, das es die meisten der oben gezeigten Funktionen schon von Haus aus mitbringt. Es musste dazu zuerst nur der base_controller und der joystick_driver selbst programmiert werden.
Im folgenden werden alle Packages/ Nodes des ROS-Workspace und deren Funktion und Aufgaben vorgestellt.
ROS Nodes kommunizieren miteinander, indem Messages an Topics gepublished oder von Topics subscribed werden. ROS bietet dazu von Haus aus viele Standardtypen dieser Messages an. Das im folgenden beschriebene Package base_controller soll z.B. die Encoderwerte der Antriebsmotoren an das Topic /md49_encoders publishen. Dieses Topic enthält dann mehrere Werte, die durch ein so genanntes msg-File definiert werden. Dieses msg-File ist im Grunde ein einfaches Text-File, welches die Daten und Struktur der jeweiligen Message definiert.
Deshalb wurde das Package md49_messages erstellt, also ein separates Package für unsere eigenen, benutzerdefinierten ROS-Messages/Topics.
Zum erstellen des Packages wurden zuerst die nötigen Verzeichnisse im ROS-Workspace erstellt:
Es enthält bislang folgende Custom Messages/ Topics:
Dazu wurden im Ordner /msg des Packages folgende .msg Files erstellt:
~/ROS-Workspace/src/md49_messages/msg/md49_data.msg
Header header int16 speed_l int16 speed_r int16 volts int16 current_l int16 current_r int16 error int16 acceleration int16 mode int16 regulator int16 timeout |
~/ROS-Workspace/src/custom_messages/msg/md49_encoders.msg
Header header int32 encoder_l int32 encoder_r int16 encoderbyte1l int16 encoderbyte2l int16 encoderbyte3l int16 encoderbyte4l int16 encoderbyte1r int16 encoderbyte2r int16 encoderbyte3r int16 encoderbyte4r |
Nun wurden die Dateien CMakeLists.txt und package.xml erstellt:
~/ROS-Workspace/src/md49_messages/CMakeLists.txt
cmake_minimum_required(VERSION 2.4.6) project(md49_messages) find_package(catkin REQUIRED COMPONENTS std_msgs message_generation) #generate messages in the msg folder add_message_files( FILES md49_encoders.msg md49_data.msg ) #generate added messages with any dependencies listed here generate_messages(DEPENDENCIES std_msgs) catkin_package(CATKIN_DEPENDS std_msgs message_runtime) |
~/ROS-Workspace/src/custom_messages/package.xml
<?xml version="1.0"?> <package> <name>md49_messages</name> <version>0.1.0</version> <description>The md49_messages package</description> <author email="scheik.todeswache@googlemail.com">Fabian Prinzing</author> <maintainer email="scheik.todeswache@googlemail.com">Fabian Prinzing</maintainer> <license>BSD</license> <url type="website">http://www.the-starbearer.de</url> <url type="bugtracker">https://github.com/scheik/ROS-Workspace/issues</url> <url type="repository">https://github.com/scheik/ROS-Workspace</url> <buildtool_depend>catkin</buildtool_depend> <build_depend>message_generation</build_depend> <build_depend>std_msgs</build_depend> <run_depend>message_runtime</run_depend> <run_depend>std_msgs</run_depend> </package> |
Kompiliert man nun den Workspace mit
werden die md49_messages als eigenes Package kompiliert und können in anderen Packages/ Nodes des Workspace verwendet werden.
Ich zeige nun exemplarisch, anhand des Package base_controller, wie die oben beschriebenen benutzerdefinierten Messages verwendet werden können. Dazu müssen im Package base_controller in den Dateien package.xml und CMakeLists.txt folgende Änderungen vorgenommen werden:
~/ROS-Workspace/src/base_controller/package.xml
. . . <build_depend>message_generation</build_depend> <build_depend>md49_messages</build_depend> <run_depend>md49_messages</run_depend> . . . |
~/ROS-Workspace/src/base_controller/CMakeLists.txt
. . . find_package(catkin REQUIRED COMPONENTS … … md49_messages ) . . . catkin_package( CATKIN_DEPENDS … … … message_runtime … ) . . . add_executable(base_controller src/base_controller/base_controller_node.cpp) target_link_libraries(base_controller ${catkin_LIBRARIES}) add_dependencies(base_controller custom_messages_generate_messages_cpp) add_dependencies(base_controller base_controller_EXPORTED_TARGETS) |
Im Laufe des Projekts bin ich dazu gekommen, für die Ansteuerung der seriellen Schnittstelle des pcDuino, eine bereits bestehende C++ Funktionsbibliothek in Form eines offiziellen ROS Packages zu verwenden und dieses für meine Zwecke anzupassen.
Basis war dafür ein offizielles ROS Package:
Das Package serialport in unserem ROS-Workspace enthält folgende Bibliotheken/ Programme
Das Package serialport ist also eine C++-Funktionsbibliothek für die serielle Schnittstelle und kann somit leicht auch in andere Packages, wie bei mir z.B. in das Package base_controller, eingebunden werden.
Dazu muss folgendes erfüllt sein:
Kommen wir nun zur base_controller_node selbst. Sie dient als direkte Schnittstelle zur Roboterhardware, genauer zum MD49, und muss deswegen auf dem pcDuino selbst gestartet werden. Die eigentliche Funktion ist leicht beschrieben: Derzeit empfängt diese Node Twist-Messages über das ROS-Topic /cmd_vel und übersetzt diese in entsprechende serielle Befehle um damit die Antriebe des Roboters anzusteuern. Gleichzeitig liest sie laufend die Encoderwerte und alle anderen Parameter der beiden Motoren seriell vom MD49 aus und veröffentlicht die so empfangenen Daten an die ROS Topics /md49_encoders und /md49_data.
Das Package enthält folgende Nodes:
Dient als direkte Schnittstelle zum MD49
Node base_controller
Topics
Parameter
Die Node base_controller lädt bei ihrem Start per Launchfile mehrere ROS Parameter aus den Konfigurationsdateien serialport_defaults.yaml und md49_defaults.yaml. So können vor dem Start die zu verwendende serielle Schnittstelle zum MD49 und die Parameter des MD49 angepasst werden.
Name | Type | Default |
serialport/name | std:string | “/dev/ttyS1” |
serialport/bps | Int | 38400 |
md49/mode | Int | 0 |
md49/acceleration | Int | 5 |
md49/regulator | Bool | True (On) |
md49/timeout | Bool | True (On) |
md49/speed_l | Int | 128 |
md49/speed_r | Int | 128 |
Die eingestellten Parameter für die serielle Schnittstelle und die MD49-Defaults für Mode, Acceleration, Timeout, etc. wurden mittels des Befehls rosparam dump im Ordner config des ROS Workspace als YAML-Files gesichert:
Die Parameter, wie die verwendete serielle Schnittstelle oder z.B. der gewünschte MD49-Mode können so vor dem Start der base_controller Node entweder per rosparam set in der Konsole, oder indem man das entsprechende YAML-File per rosparam load einliest, angepasst werden.
Die Default-Werte für das MD49 kann man der obigen Tabelle entnehmen. Ihre Funktion sind in der Dokumentation des Motortreiberboards MD49 beschrieben.
Beispiele zum Ändern von Parametern per Kommandozeile:
Mit folgenden Befehlen in der Konsole können die Parameter aus den jeweiligen YAML-Files manuell eingelesen werden:
Mit dem folgenden Befehl kann die Node base_controller, lokal auf dem pcDuino, gestartet werden. Werden die Parameter vorher nicht manuell wie oben gezeigt eingelesen, werden dann aber die im Sourcecode angegebenen Defaults als Parameter verwendet:
Launchfile base_controller_local.launch
Um den Start der base_controller Node zu vereinfachen wurde ein ROS Launchfile für die Node erstellt. Mittels base_controller_local.launch lässt sich die Node dann einfach mittels eines einzelnen Befehls starten und nimmt uns viel Arbeit ab. So legt es in diesem Fall das robotOS als Rechner fest, auf dem die Node lokal gestartet wird, da das MD49 ja mit dessen serieller Schnittstelle verbunden ist. Dannach lädt es alle zum Betrieb nötigen Parameter aus den beiden Config-Dateien md49_defaults.yaml, serialport_defaults.yaml und startet dann die Node.
Starten der Node base_controller auf der Ubuntu Workstation (Remote)
Da im Launchfile als Rechner auf dem die Node base_controller gestartet werden soll das robotOS, also der pcDuino angegeben wurde, kann sie einfach über das Netzwerk, also “remote” von der Ubuntu-Workstation, mittels des Launchfiles base_controller_remote.launch gestartet werden. Zuvor müssen aber ein paar Dinge auf dem pcDuino und der Workstation eingerichtet sein (Quelle: Node remote starten):
Auf der Workstation:
Auf dem pcDuino:
Diese Vorraussetzungen sind alle erfüllt, wenn die Betriebssysteme robotOS und workstationOS wie oben beschrieben eingerichtet wurden.
Auf der Workstation wird die Node base_controller dann per Launchfile mit folgendem Befehl gestartet:
Mittels der base_controller Node können nun also die Antriebe des Roboters einfach mittels des Topics /cmd_vel angesteuert werden. Zusätzlich stehen durch diese Node laufend die aktuellen Daten des MD49 über die Topics /md49_encoders und /md49_data zur weiteren Verwendung zur Verfügung.
Diese beiden Topics können z.B. über die Befehle
und
in der Konsole angezeigt werden.
Es könnten nun auch schon die Antriebe mittels
aus der Kommandozeile angesteuert werden, das wäre aber dauerhaft zum fernsteuern der Antriebe des Roboters wohl zu umständlich.
Um den Roboter fernsteuern zu können entstand das zweite Package robot_teleop, mit der joystick_teleop und der keyboard_teleop Node. Mit ihnen ist es möglich, den Roboter einfach mittels eines USB-Gamepads oder -Joysticks oder per Tastatur, angeschlossen an der ROS-Workstation, fernzusteuern.
Node joystick_teleop
Topics
P U B L I S H |
| ||||||
S U |
|
Parameter
Name | Type | Default |
/joystick/name | std:string | “/dev/input/js1” |
Wie man sieht, hört die joystick_driver Node auf das Topic /joy. Hier kommt die erste 3rd-Party Node zum Einsatz, die wir benutzen. Denn wir wollen den Vorteil von ROS ja auch nutzen und das Rad nicht neu erfinden. Für die Auswertung eines USB-Gamepads oder -Joysticks gibt es nämlich schon ein ROS-Package http://wiki.ros.org/joy
Dieses Package enthält die Node joy_node, welche für uns die Auswertung des angeschlossenen Joysticks übernimmt und uns die ermittelten Daten mittels ROS-Topic /joy zur weiteren Verwendung bereitstellt. Das Package wurde einfach mittels sudo apt-get install ros-indigo-joystick-drivers auf der Ubuntu-Workstation installiert.
Nun kann mit folgendem Befehl der angeschlossene Joystick mit ROS bekannt gemacht werden:
Wobei hier ‘jsx’ für den jeweils verwendeten Joystick, z.B: js2, js1 oder js0 steht (mittels lsusb oder ls /dev/input ermitteln)
Nun kann auch schon die joy_node gestartet werden:
Das Setup lässt sich einfach testen, indem man in der Kommandozeile rostopic echo /joy eingibt
Startet man nun unsere eigene Node joystick_teleop aus dem Package robot_teleop, übersetzt diese jede neue /joy Message in eine entsprechende /cmd_vel Message. Voila, zusammen mit unserer Node base_controller lässt sich unser Roboter nun schon per Joystick an der Workstation fernsteuern.
Um den verwendeten Port für die joy_node nicht mit “rosparam set” angeben zu müssen wurde im Package robot_teleop das Config-file joystick_defaults.yaml angelegt.
Dieses kann mit folgendem Befehl eingelesen werden:
Nun kann man die joy_node starten:
Und schließlich kann man die Node joystick_teleop in einem neuen Terminalfenster starten:
Node keyboard_teleop
Topics
P U B L I S H |
|
Die Node keyboard_teleop kann einfach mit folgendem Befehl gestartet werden:
Launchfile joystick_driver.launch
Um den hier beschriebenen Ablauf zum Starten der Joystick-Ansteuerung zu automatisieren bietet sich wieder ein ROS Launchfile an. Dieses führt folgende Schritte aus:
Das Launch-File joystick_driver.launch:
<launch> <rosparam command="load" ns="/joy_node" file="$(find robot_teleop)/config/joystick_defaults.yaml" /> <node name="joy_node" pkg="joy" type="joy_node" required="true" output="screen" /> <node name="joystick_teleop" pkg="robot_teleop" type="joystick_teleop" required="true" output="screen" /> </launch> |
Im folgenden will ich zeigen wie der Ablauf aussieht, den Roboter per Gamepad an der Workstation fernzusteuern.
Vorraussetzung dafür ist, dass das Betriebssystem robotOS auf dem pcDuino eingerichtet ist, wie hier beschrieben und das Betriebssystem der Workstation, das workstationOS wie hier beschrieben eingerichtet wurde. Damit sollte auch der komplette ROS-Workspace sowohl auf dem robotOS als auch auf dem workstationOS geklont und kompiliert sein.
Wir haben also inzwischen alle Komponenten beieinander, um den Roboter manuell fernsteuern zu können. Im wesentlichen ist das die Node base_controller, welche das Topic /cmd_vel subscribed und die entsprechenden Steuerbefehle über die serielle Schnittstelle an das MD49 sendet.
Zweiter Bestandteil sind die Nodes, welche das Gamepad auswerten. Das ist zum einen die Node joy_node aus dem ROS Package joystick_drivers und unsere eigene Node joystick_teleop, die dann das Topic /joy in entsprechende /cmd_vel -Befehle übersetzt.
Workflow auf der Workstation:
Launchfile joystick_teleop.launch
Um den obigen Ablauf zu vereinfachen habe ich inzwischen das Launchfile joystick_teleop.launch in ~/ROS-Workspace/launch erstellt. Dieses startet alle zum fernsteuern per Joystick nötigen Nodes/Launchfiles mit einem Befehl. Dazu auf der Workstation folgendes ausführen:
Ausgabe von rqt_graph vom Ablauf gestartet durch joystick_teleop.launch
Die Idee hinter diesem Package ist, dass eine ROS Node Daten aus ROS Topics, hier /md49_data und /md49_encoders in eine Datenbank schreiben kann, um später, z.B. über ein Webinterface/ -tool darauf zugreifen zu können.
Es muss dazu der Nginx Webserver, PHP und SQLite auf der Workstation installiert sein, wie in diesem Kapitel beschrieben.
Bisher loggt die Node sqlite_connector also die Daten der Topics /md49_encoders und /md49_data in eine SQLite Datenbank. So sind alle Daten der Motoren in der SQLite Datenbank md49data.db für die weitere Verarbeitung, z.B. in einem Webinterface per PHP, verfügbar. Die dafür verwendete Datenbank md49data.db liegt im Root-Verzeichnis unseres Webservers unter :
~/webserver_root/sqlite_connector/md49data.db.
Starten der Node sqlite_connector:
Topics
S U S |
|
Das Package sqlite_connector wird derzeit nicht weiterentwickelt, weil die Anbindung an ein mögliches Webtool/ Webinterface derzeit eher über den Ansatz rosbridge_suite bzw. roslibjs verfolgt wird. Siehe im Kapitel Grundlagen unter ROS: Web-Konnektivität mit ROSBridge und hier hier im Kapitel Aufbau unter ROS Webtools. |
Nun, da die Ansteuerung der Motoren per Twist- Messages möglich ist und die Encoderdaten zur Verarbeitung bereitstehen, möchte ich in Anlehnung an den ROS-Navigation-Stack Odometriedaten daraus errechnen. Dazu ist die Node base_odometry im dazugehörigen Package base_odometry des ROS-Workspace entstanden. Um die Theorie dahinter zu verstehen, kann folgende Antwort aus den ROS Answers helfen:
Your velocities at the left and right wheel are denoted as v_l and v_r respectively. Velocities in the robot frame (which are located in the center of rotation, e.g. base_link frame) v_rx = ( v_right + v_left ) /2; Subscript r indicates the robot frame. Note, after converting your encoder values to rotational velocities at each wheel (omega_left,omega_right), you can transform them to the translational velocity at each wheel using the radius of the wheel: v_left = omega_left * radius. Velocities in the odom frame The velocities expressed in the robot base frame can be transformed into another coordinate system (e.g. odom). For transforming velocities (in this simple setting with scalar values), we only need to rotate them according to the current robot orientation. Here we apply the 2D rotation matrix ((we are operating in the x-y plane). We assume that we already know the current orientation (theta). v_wx = v_rx * cos(theta) - v_ry * sin(theta); For your robot kinematics it is v_ry=0. Subscript w indicates the world frame. Computing the current robot pose In order to obtain the current robot position, numerical integration can be applied. The velocities are integrated in order to achieve the current pose (x, y, theta). We define the pose in the odom frame, and start with x=y=theta=0 (origin of the odom frame). Applying Explicit/Forward Euler Integration leads to x_kp1 = x_k + v_wx * dt; // kp1 := k+1 In your implementation, you can simply share the same variables for x_kp1 and x_k etc. dt denotes the step width and should be choosen according to the time elapsed since the last integration step (here you might see, that your rate significantly influences your integration accuracy. But the integration rate is limited by the rate of your sensors (wheel encoders). Composing your odometry message The odometry message contains the pose and the twist information. Now you should have everything to compute the values. The pose represents your current robot pose w.r.t the odom frame (x_k, y_k, theta_k). You must convert theta_k to a Quaternion, e.g. by calling the related functions of the tf package. The twist part usually contains the velocities expressed in your robot frame (there is an extra parameter where you can insert the frame name (child_frame_id), but not all drivers are filling it with a value. Here you just need the linear velocity (linear.x = v_rx and the angular velocity (around the z-axis, angular.z = omega_r). All other values are zero. |
Topics
P U B L I S H |
| |||||||||
S U |
|
Parameter
Name | Type | Default |
base_odometry_parameters/ticks_per_meter | int32_t | 4900 |
base_odometry_parameters/encoder_min | int32_t | -2147483647 |
base_odometry_parameters/encoder_max | int32_t | 2147483647 |
base_odometry_parameters/base_width | double | 0.5 |
base_odometry_parameters/transform_tf | bool | true |
Die Parameter können über das File base_odometry_parameters.yaml aus dem Ordner /config des Packages base_odometry gesetzt werden.
Startet man die Node per
muss das Config-File dazu zuvor mit
eingelesen werden.
Die Node wird deswegen am besten über das Launchfile base_odometry.launch gestartet, so wird das Config-File beim Start automatisch mit eingelesen:
Enthält u.a. urdf-Files und launch-Files, und dient dazu mit RViz Roboter-Modell, -Bewegungen, Sensordaten und Umgebung zu visualisieren.
Dieses kurze Video demonstriert die Funktionsweise von RViz.
Erstellung des Package robot_urdf und erste Schritte
Im Verzeichnis src des ROS-Groovy-Workspace wurde das Package robot_urdf erstellt:
Dann wurde ein Verzeichnis urdf im Stammverzeichnis des eben angelegten Package erstellt und darin das urdf-File robot.urdf angelegt:
Testen/Parsen des urdf-Files
jetzt kann man mit
eine Visualisierung des URDF Files (robot.pdf und robot.gf) erstellen und mit
testen, ob das angelegte File korrekt geparsed wird.
Ein mit urdf_to_graphiz visualisiertes urdf- File robot.pdf, hier im Bild ein früher Stand des Files robot.urdf
Darstellen des Modells in RViz
Dazu muss man die RViz- Konfigurationsdatei urdf.rviz in ~/ROS-Workspace/src/robot_urdf erstmalig erstellen:
https://github.com/Scheik/ROS-Groovy-Workspace/blob/master/src/robot_urdf/urdf.rviz |
Das Verzeichnis ~/ROS-Workspace/src/robot_urdf/launch erstellen. Darin das Launch-File display.launch erstellt
<launch> <arg name="model" /> <arg name="gui" default="False" /> <param name="robot_description" textfile="$(arg model)" /> <param name="use_gui" value="$(arg gui)"/> <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" ></node> <node name="robot_state_publisher" pkg="robot_state_publisher" type="state_publisher" /> <node name="rviz" pkg="rviz" type="rviz" args="-d $(find robot_urdf)/urdf.rviz" /> </launch> |
Das so angelegte launch-File starten:
Ein einfacheres Launchfile robot_rviz.launch, ohne Argumente im Aufruf:
<launch> <!-- urdf xml robot description loaded on the Parameter Server--> <param name="robot_description" textfile="$(find robot_urdf)/urdf/robot.urdf" />
<!-- source that publishes the joint positions as a sensor_msgs/JointState --> <param name="use_gui" value="true"/> <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" />
<!-- robot visualization --> <node name="rviz" pkg="rviz" type="rviz" required="true" args="-d $(find robot_urdf)/urdf.rviz"/>
<!-- publish all the frames to TF --> <node name="robot_state_publisher" pkg="robot_state_publisher" type="state_publisher"> <param name="publish_frequency" value="50"/> <!-- Hz --> </node> </launch> |
Das Launch-File robot_rviz.launch starten:
Ein frühes urdf- Modell des Roboters im ‘3D Visualization Tool’ rviz
Das statische Roboter-Modell aber einfach nur so in RViz darzustellen ist aber natürlich nicht Zweck des ganzen. Später sollen alle Bewegungen des Roboters und seine Sensordaten in RViz dargestellt werden. Kommen wir nun also zuerst dazu, wie wir die Bewegungen des Roboters visualisieren können.
Die einzigen Sensordaten die uns bisher zur Orientierung des Roboters dienen erhalten wir bisher aus dem Package base_odometry, welches die Encoderdaten der der Antriebe in Odometriedaten verarbeitet. Dies reicht vorerst schon aus, die Bewegungen des Roboters in RViz darzustellen.
Kommen wir also nun zum Test unseres Robotermodells in RViz mit diesen Odometrie-Daten. Wir starten dazu folgenden Workflow:
Sind alle Nodes gestartet müsste man den Roboter per Gamepad steuern können und es sollten die Bewegungen simultan in RViz abgebildet werden. In RViz muss dazu unter ‘Global Options’ als ‘Fixed Frame’ der Link ‘encoder/odom’ angegeben werden.
Video?
tf-Debugging Tools
http://wiki.ros.org/tf/Debugging%20tools
Ausgabe frames.pdf von ‘rosrun tf view_frames’
Macht eigentlich dasselbe wie view_frames aus dem Package tf nur direkt in einem rqt- Fenster anstatt der Ausgabe in einem PDF.
Mit diesem Package kann der Roboter über RViz mittels ROS Interactive Markers ferngesteuert werden:
Workflow auf der Workstation:
Das Package basiert auf dem Sourcecode von http://wiki.ros.org/interactive_marker_twist_server, der in meinem Package etwas modifiziert zum Einsatz kommt.
Enthält u.a. xacro-Files und launch-Files, und dient dazu mit Gazebo Roboter-Modell, -Bewegungen, Sensordaten und Umgebung zu visualisieren.
http://www.romin.upm.es/wiki/index.php?title=ROS%3ATutorials/Simulate_Your_Robot_in_Gazebo
Package robot_gazebo erstellen
Folgende Dateien in ~/ROS-Gazebo/src/robot_gazebo/urdf/ erstellen:
In ~/ROS-Gazebo/src/robot_gazebo/launch/ das folgende Launchfile erstellen:
Launchfile starten:
Das Package ist in einem eigenen Repository https://github.com/Scheik/ROS-Gazebo.git zu finden. Es wird derzeit nicht weiterentwickelt, weil ich mich derzeit auf die Visualisierung mit RViz konzentrieren will. |
Um später den ROS Navigation Stack für den Roboter zu implementiert benötigt man Karten. Dieses Package beinhaltet Map- und YAML-Files für den ROS map_server. Das map_server package beinhaltet die map_server -Node, welche Map-Daten als ROS Service bereitstellt.
Für die ersten Versuche habe ich im Package eine leere Karte empty_map.pgm erstellt. Eine PGM-Datei ist Mitglied des PNM-Formats, was eine Familie von einfachen Dateiformaten zur Speicherung von Rastergrafiken ist.
Für ROS sind dabei weiße Pixel freies, schwarze Pixel belegtes und Graustufen dazwischen unbekanntes Terrain. In einem dazugehörigen YAML-File, hier empty_map.yaml werden Parameter für die jeweilige Karte festgelegt werden, z.B. die Auflösung/Resolution und Threshold der Graustufen.
Man kann den map_server manuell starten mit:
Die ROS Node map_server hat die bisher leere Karte geladen.
Wie man sieht wird die gewünschte Map hier mit einem yaml-File empty_map.yaml gestartet. In diesem yaml- File sind z.B. der Pfad zur gewünschten Map und weitere Parameter der Map hinterlegt:
image: empty_map.pgm resolution: 0.1 origin: [0.0, 0.0, 0.0] occupied_thresh: 0.65 free_thresh: 0.196 negate: 0 width: 20 height: 20 |
Das YAML Format (Aus der Dokumentation des ROS Packages map_Server):
Alleine macht diese map_server Node noch nicht viel, man wird sie normalerweise nicht manuell starten. Wir kommen aber später im Package robot_2dnav noch zur Anwendung.
Beginnen wir mit der Inbetriebnahme des Kinect Sensors unter Ubuntu 16.04 LTS. Derzeit gibt es dafür zwei relevante Open-Source Treiberpakete, da wäre zum einen OpenNi und zum anderen libfreenect von OpenKinect. Der Unterschied wird in einem Thread auf Stackoverflow ziemlich gut zusammengefasst:
“Libfreenect is mainly a driver which exposes the Kinect device's features: - depth stream - IR stream - color(RGB) stream - motor control - LED control - accelerometer. If does not provide any advanced processing features like scene segmentation, skeleton tracking, etc.
On the other hand, OpenNI allows generic access to Kinect's feature (mainly the image streams), but also provides rich processing features such as: - scene segmentation - skeleton tracking - hand detection and tracking - gesture recognition - user interface elements etc. but no low level controls to device features like motor/LED/accelerometer.”
Da uns zunächst die Grundfunktionalität der Kinect für unsere Pläne ausreicht, habe ich mich für das Treiberpaket libreenect von OpenKinect entschieden und werde im folgenden zeigen, wie ich dieses installiert habe.
Treiber für Kinect installieren
Der angemeldete User muss, falls nicht schon geschehen, zur Gruppe video hinzugefügt werden und Mitglied der Gruppe plugdev sein.
Nach dem anstecken des Kinect sollten 3 neue Einträge durch den Befehl lsusb angezeigt werden:
$ lsusb ... Bus 002 Device 006: ID 045e:02ae Microsoft Corp. Xbox NUI Camera Bus 002 Device 004: ID 045e:02b0 Microsoft Corp. Xbox NUI Motor Bus 002 Device 005: ID 045e:02ad Microsoft Corp. Xbox NUI Audio ... |
Installieren wir nun die Treiber für Kinect, wie gesagt habe ich mich für die freenect-Treiber des OpenKinect Projektes entschieden:
Nun können wir einen ersten Test mit einem der libfreenect-demos durchführen:
Mit diesem Demo kann auch der Tiltmotor mit den Tasten ‘w’ nach oben, mit ‘x’ nach unten und mit ‘s” in die neutrale Position gefahren werden. Daneben kann mit den Tasten ‘1’-’6’ und ‘0’ die LED-Anzeige am Kinect verändert werden. Alle möglichen Kommandos kann man dem Sourcecode des Programms entnehmen.
Die Ausgabe des libfreenect-Demos freenect-glview
Bei Problemen bis hier hin bitte folgende Fehlerquellen prüfen (Quelle):
ROS und Kinect
Installieren wir nun den zum gewählten Treiberpaket passenden ROS Stack für die Kinect:
(Im Falle man das Treiberpaket von OpenNi statt libfreenect verwendet hätte, wäre das Pendant hierzu die Packages ros-indigo-openni-camera und ros-indigo-openni-launch.)
Erste Tests analog zu http://wiki.ros.org/openni_launch:
In RViz den Global Frame (links oben) zu /camera_depth_optical_frame ändern. Dann ein neues Display Pointcloud2 hinzufügen, und das Topic auf /camera/depth/points setzen.
Man sollte nun eine weiße Punktewolke sehen.
Nun wollen wir die Punktewolke mit der RGB Kamera synchronisieren. Dazu in einem neuen Terminal das Tool rqt_reconfigure starten:
Hier dann /camera/driver im Dropdownmenu wählen und die Checkbox depth_registration anwählen.
Dann zurück in RViz das Topic /camera/depth_registered/points für die Pointcloud2 wählen und den ColorTransformer Wert auf RGB8 setzten.
Das Package freenect_launch bietet weitere Launchfiles, mit denen man weiter experimentieren kann:
Zur Funktion zitiere ich hierzu die Dokumentation des Packages:
“The first launch files only produces a pointcloud from depth data. The second launch file produces a registered pointcloud using hardware registration on the device.”
2D-Laserscan Daten für den Navigation-Stack
Um mit dem Kinect später im Navigation Stack eine 2D- Karte aufzubauen benötigen wir einen Laserscan in einer Ebene, also in 2D, deswegen muss die, durch den obigen Treiber gelieferte Pointcloud in eine Laserscan- Message umgewandelt werden.
Dazu kann z.B. das ROS Package depthimage_to_laserscan, das Package pointcloud_to_laserscan oder das Package kinect_2d_scanner verwendet werden. Ich werde später nur noch das Package depthimage_to_laserscan verwenden, zeige aber auch kurz die Funktionsweise der anderen beiden Packages auf.
Package kinect_2d_scanner:
In RViz den Global Frame auf KINECT_2D setzten, ein Display LaserScan hinzufügen un das Topic auf /scan setzen.
Package pointcloud_to_laserscan:
Package depthimage_to_laserscan
In RViz den Global Frame auf /camera_link setzen und ein Display LaserScan hinzufügen und das Topic auf /scan setzten:
Integration der Kinect in das Projekt/ ROS-Workspace
Das nächste Ziel ist es nun, diese 2D-LaserScan-Daten in RViz anzuzeigen und in Verbindung mit dem Roboter URDF- Modell zu bringen.
<link name="camera_link"> <visual> <geometry> <box size="0.064 0.280 0.03" /> </geometry> <material name="black" /> </visual> </link> <joint name="camera_link_to_torso" type="fixed"> <origin xyz="0.148 0 0.075" rpy="0 0 0" /> <parent link="torso" /> <child link="camera_link" /> </joint> <joint name="kinect_depth_joint" type="fixed"> <origin xyz="0 0.028 0" rpy="0 0 0" /> <parent link="camera_link" /> <child link="camera_depth_frame" /> </joint> <link name="camera_depth_frame"> </link> <joint name="depth_optical_joint" type="fixed"> <origin xyz="0 0 0" rpy="1.57075 0 -1.57075" /> <parent link="camera_depth_frame" /> <child link="kinect_depth_optical_frame" /> </joint> <link name="kinect_depth_optical_frame"> </link> |
Die Kinect im robot.urdf in stark vereinfachter Version.
Die letztlich verwendete Version basiert auf einem Mesh aus dem Package turtlebot_description
<launch> <include file="$(find freenect_launch)/launch/freenect.launch"> <arg name="rgb_processing" value="false" /> <arg name="ir_processing" value="false" /> <arg name="depth_processing" value="true" /> <arg name="depth_registered_processing" value="false" /> <arg name="disparity_processing" value="false" /> <arg name="disparity_registered_processing" value="false" /> </include> <node name="depthimage_to_laserscan" pkg="depthimage_to_laserscan" type="depthimage_to_laserscan" args="image:=/camera/depth/image_raw" required="true" output="screen" /> </launch> |
Eine Version depthimage_to_laserscan.launch
Die 2D-Laserscan-Daten des Kinect, visualisiert in RViz
Zuerst wurde dazu ein Package robot_mapping im ROS-Workspace erstellt:
Da nun mit der Kinect Laserscan- Daten zur Verfügung stehen, ist das nächste Ziel, basierend auf diesen Daten eine Karte der Umgebung des Roboters zu erstellen und ihn später darin zu lokalisieren. Dazu gibt es in der ROS- Umgebung mehrere mögliche Ansätze. Eine Gegenüberstellung gängiger Mapping-/Slam- Techniken mit ROS bietet diese Ausarbeitung. Sie stellt die folgenden fünf Ansätze gegenüber:
Hector_Mapping
Launchfile erstellen aus Vorlage hector_slam/hector_mapping/launch/mapping_default.launch
Erster Versuch:
WorkstationOS
RobotOS
Erster Test eine Karte zu erstellen mit Hector_Mapping
Mit diesem Package soll der ROS Navigation Stack implementiert werden. Ich bin dazu nach dem Tutorial Setup and Configuration of the Navigation Stack on a Robot vorgegangen.
Zuerst wurde dazu ein Package robot_2dnav im ROS-Workspace erstellt:
Dann die jeweiligen Ordner für die Config- und Launchfiles erstellt:
Folgende Launchfiles wurden erstellt:
Folgende Config-Files wurden erstellt
Um den Navigation-Stack zu starten können die beiden dazu nötigen Launchfiles separat gestartet werden:
Oder man kann die beiden Launchfiles gemeinsam starten mit:
Workflow (alles auf der Workstation):
VIDEO!
Die nötigen Odometriedaten liefert weiterhin die base_odometry Node. Sie wird hier aber nicht separat, sondern durch das Launchfile robot_configuration.launch gestartet.
Damit die 2D-LaserScan-Daten der Kinect für den Navigation-Stack zur Verfügung stehen, wird das Launchfile depthimage_to_laserscan.launch der Packages robot_kinect ebenfalls durch robot_configuration.launch gestartet.
Alle nötigen Grundlagen und Erklärungen dazu findet man im Kapitel Grundlagen unter ROS: Arduino als ROS-Nodes.
Dieses Package zeigt anhand einfacher Beispiele, wie ein Arduino als ROS-Nodes programmiert und verwendet werden kann. Welche Schritte also notwendig sind ein Arduino Programm in unserem Catkin ROS-Workspace zu erstellen, zu kompilieren, es auf den Arduino hochzuladen und letztlich mittels rosserial_node mit ROS zu verbinden.
Man findet in diesem Package Beispielprogramme, z. B. einen einfachen ROS-Subscriber und einen -Publisher, um die Funktion eines Arduino als ROS-Node zu demonstrieren.
Auf der Workstation wurde wie im Kapitel Betriebssystem (workstationOS) für Workstation installieren beschrieben, Nginx als Webserver installiert. Dieser ist, wenn aktiv, unter http://robotik.ddns.net erreichbar. Neben Newspage, Source- und Projektdokumentation sollen dort nach und nach auch Webtools zu finden sein um interaktiv mit der mobilen Roboterplattform zu arbeiten. Die Web-Konnektivität zur mobilen Roboterplattform wird dazu mittels rosbridge_suite und roslibjs hergestellt.
Im Kapitel Grundlagen unter ROS: Web-Konnektivität mit ROSBridge findet man alles Grundlegende zum Thema ROS Web-Konnektivität mittels rosbridge_suite und roslibjs.
Erstes Ziel ist es derzeit, ein Webtool base_controller zu erstellen. Dieses Tool soll zuerst die von der ROS-Node base_controller gepublishten Topics /md49_data und /md49_encoders live im Browser darstellen und später die Fernsteuerung des Roboters ermöglichen, also auch an das ROS-Topic /cmd_vel publishen.
Bisher werden folgende Techniken zum Erstellen der Seite eingesetzt:
Um die Webtools zu nutzen, muss natürlich wie im Kapitel Betriebssystem (workstationOS) für Workstation installieren beschrieben Nginx als Webserver installiert sein.
Damit dann die betreffenden ROS-Topics auch bereit stehen, muss natürlich zuerst die Node base_controller gestartet werden:
Rosbridge starten:
Laden wir nun die Webtools im Browser unter http://robotik.ddns.net/Webtools und wechseln zum Tab base_controller, sollten wir die folgende Seite sehen, welche die aktuellen Daten der laufenden Node base_controller visualisiert:
Screenshot des Webtools base_controller