Inhalt

Mobile Roboterplattform: Mechanik

Basisplattform und Antrieb

Mobile Roboterplattform: Elektronik

Einplatinencomputer pcDuino

MAX232-5V-Pegelwandler (für MD49)

MAX3232-3,3V-Pegelwandler (für pcDuino)

Motoransteuerung MD49

Spannungsversorgung Antriebe und Antriebsregelung

Spannungsversorgung pcDuino3 und Steuerelektronik

Arduino am pcDuino

Kinect als Sensor

Mobile Roboterplattform: Programmierung

Betriebssystem (workstationOS) für Workstation installieren

Betriebssystems (robotOS) für pcDuino installieren

ROS-Workspace

ROS Package: md49_messages

ROS Package: serialport

ROS Package: base_controller

ROS Package: robot_teleop

Meilenstein: Fernsteuerung des Roboters mittels eines Gamepad

ROS Package: sqlite_connector

ROS Package: base_odometry

ROS Package: robot_urdf

Meilenstein: Roboter fernsteuern und Bewegungen in RViz darstellen

ROS Package: interactive_markers_twist_server

ROS Package: robot_gazebo

ROS Package robot_maps

ROS Package robot_kinect

ROS Package robot_mapping

ROS Package robot_2dnav

Meilenstein: Navigieren des Roboters mittels RViz Navigationgoals

ROS Package: arduino_examples

ROS Webtools

Mobile Roboterplattform: Mechanik

Basisplattform und Antrieb

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.

Basisplattform.png

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.

2015-07-17 08.49.33.jpg2015-07-17 08.50.22.jpg

Die mobile Roboterplattform im Aufbau

Mobile Roboterplattform: Elektronik

Schema_Roboter_Hardware.png

Im Bild oben ist der bisherige Aufbau der mobilen Roboterplattform schematisch skizziert

Einplatinencomputer pcDuino

Statt des Raspberry Pi verwende ich inzwischen den leistungsfähigeren Einplatinencomputer pcDuino3 als Rechner auf dem Roboter.

pcduino_header.jpg

MAX232-5V-Pegelwandler (für MD49)

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.

MAX232_Modul_Bestückungsplan.png

MAX3232-3,3V-Pegelwandler (für pcDuino)

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.

Motoransteuerung MD49

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.

md49-connections.png

Die Eckdaten für diesen 24V 5A Dual H-Bridge Motortreiber:

Link zur technischen Dokumentation MD49

Spannungsversorgung Antriebe und Antriebsregelung

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.

Spannungsversorgung pcDuino3 und Steuerelektronik

LOGILINK_PA0086_01.jpg

Als Spannungsversorgung für den Einplatinencomputer und alle anderen 5V- Komponenten verwende ich eine 5V Powerbank mit 19,6 Ah

2015-07-17 08.50.22.jpg2015-07-17 08.49.14.jpg

Die Elektronik der mobilen Roboterplattform im Aufbau

Arduino am pcDuino

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.

Kinect als Sensor

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.

hokuyo-urg-04lx-ug01-scanning-laser-rangefinder.jpgHC-SR04.jpgXbox-360-Kinect-Standalone.png

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

Mobile Roboterplattform: Programmierung

Betriebssystem (workstationOS) für Workstation installieren

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

http://wiki.ros.org/joy 

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:

Portforwarding_webserver.pngPortweiterleitung_Fritzbox.jpg

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
  output_dir: python
- builder: doxygen
  name: C++ API
  output_dir: c++
  file_patterns: '*.c *.cpp *.h *.cc *.hh *.dox'

sudo nano package.xml (folgendes im export tag einfügen)

<export>
 <rosdoc config="rosdoc.yaml" />
</ex
port>

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

Betriebssystems (robotOS) für pcDuino installieren

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

  1. sudo apt-get install avahi-daemon libnss-mdns 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
export ROS_IP=robotOS.local
export ROS_HOSTNAME=robotOS.local
. /home/robot/ROS-Workspace/devel/setup.sh
exec "$@"

speichern und ausführbar machen mit:

ROS-Workspace installieren

2015-07-17 08.49.33.jpg2015-07-17 08.49.59.jpg

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

ROS-Workspace

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.

  1. cd ~
  2. git clone https://github.com/Scheik/ROS-Workspace.git
  3. cd ~/ROS-Workspace
  4. rosdep install --from-paths . --ignore-src --rosdistro indigo
  5. catkin_make
  6. echo source /home/robot/ROS-Workspace/devel/setup.bash >> ~/.bashrc
  7. source ~/.bashrc

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:

ROS_Master_Joypad_workflow.png

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 Package: md49_messages

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)

ROS Package: serialport

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:

  1. #include <serialport/serialport.h> im Sourcecode des Programms,
  2. find_package(catkin REQUIRED COMPONENTS serialport) im CMakeLists.txt des jeweiligen Packages,
  3. <build_depend>serialport</build_depend> und <run_depend>serialport</run_depend> im jeweiligen package.xml des Packages.

ROS Package: base_controller

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

P

U

B

L

I

S

H

Topic

Message type

Description

/md49_encoders

int16 encoderbyte1l

int16 encoderbyte2l

int16 encoderbyte3l

int16 encoderbyte4l

int16 encoderbyte1r

int16 encoderbyte2r

int16 encoderbyte3r

int16 encoderbyte4r

int32 encoder_l

int32 encoder_r

md49_encoders.msg

aus Package md49_messages

Topic

Message type

Description

/md49_data

int16 speed_l

int16 speed_r

int16 volts

int16 current_l

int16 current_r

int16 error

int16 acceleration

int16 mode

int16 regulator

int16 timeout

md49_data.msg

aus Package md49_messages

S

U
B
S
C
R
I
B

E

Topic

Message type

Description

/cmd_vel

geometry_msgs::Twist

Standardmessage

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:

  1. Der pcDuino muss unter robotOS.local anpingbar sein und anders herum (Siehe Kapitel Die Toolchain: ROS im Netzwerk)
  2. Standardmässig arbeitet ROS nur mit ssh Hosts die auch im known_hosts file definiert wurden, um das zu ändern:
    export ROSLAUNCH_SSH_UNKNOWN=1
    Möglich aber nicht optimal: Die Zeile in die ~/.bashrc packen, wie hier beschrieben.
    oder die sicherere Variante wählen und den Host ordentlich in known-hosts definieren.

Auf dem pcDuino:

  1. Es muss ein Environment- File angelegt sein, bei mir /opt/ros/indigo/myenv.sh,wie hier beschrieben.

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.  

ROS Package: robot_teleop

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

Topic

Message type

Description

/cmd_vel

geometry_msgs::Twist

S

U
B
S
C
R
I
B
E

Topic

Message type

Description

/joy

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

Topic

Message type

Description

/cmd_vel

geometry_msgs::Twist

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:

  1. Setzten des Parameters für den Port an dem der Joystick angeschlossen ist, z.B. /dev/input/js2. Dazu wird der Parameter aus der Datei joystick_defaults.yaml ausgelesen
  2. Starten der Node joy_node aus dem 3rd Party Package Joy
  3. Starten der selbst programmierten Node joystick_driver

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>

Meilenstein: Fernsteuerung des Roboters mittels eines Gamepad

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:

Youtube_teleop1.jpg

Joystick Teleop Youtube

Youtube_teleop2.jpg

Joystick Teleop Youtube

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:

2015-09-02-201625_1366x768_scrot.png

Ausgabe von rqt_graph vom Ablauf gestartet durch joystick_teleop.launch

ROS Package: sqlite_connector

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
B
S
C
R
I
B
E

S

Topic

Message type

Description

/md49_encoders

int16 encoderbyte1l

int16 encoderbyte2l

int16 encoderbyte3l

int16 encoderbyte4l

int16 encoderbyte1r

int16 encoderbyte2r

int16 encoderbyte3r

int16 encoderbyte4r

int32 encoder_l

int32 encoder_r

md49_encoders.msg

aus dem Package

custom_messages

/md49_data

int16 speed_l

int16 speed_r

int16 volts

int16 current_l

int16 current_r

int16 error

int16 acceleration

int16 mode

int16 regulator

int16 timeout

md49_data.msg

aus dem Package

custom_messages

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.

ROS Package: base_odometry

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;
v_ry
= 0; // we have a non-holonomic constraint (for a non-holonomic robot, this is non-zero)
omega_r
= ( v_right - v_left ) / d; // d denotes the distance between both wheels (track)

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);
v_wy
= v_rx * sin(theta) + v_ry * cos(theta);
thetadot
= omega_r;

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
y_kp1
= y_k + v_wy * dt; // by the way, the last term is delta_y from the equations in your comment
theta_kp1
= theta_k + thetadot * dt;

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

Topic

Message type

Description

/encoder/odom

nav_msgs/odometry

Odometry Daten

/tf

/tf/transform_broadcaster

transformation

S

U
B
S
C
R
I
B
E

Topic

Message type

Description

/md49_encoders

int16 encoderbyte1l

int16 encoderbyte2l

int16 encoderbyte3l

int16 encoderbyte4l

int16 encoderbyte1r

int16 encoderbyte2r

int16 encoderbyte3r

int16 encoderbyte4r

int32 encoder_l

int32 encoder_r

md49_encoders.msg

aus dem Package

md49_messages

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:

ROS Package: robot_urdf

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.

robot_urdf.jpg

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.

Meilenstein: Roboter fernsteuern und Bewegungen in RViz darstellen

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

tf_view_frames.jpg

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.

roswtf.jpg

ROS Package: interactive_markers_twist_server

Mit diesem Package kann der Roboter über RViz mittels ROS Interactive Markers ferngesteuert werden:

Interactive_Marker.png

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.

ROS Package: robot_gazebo

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.

ROS Package robot_maps

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:

map_server.png

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.

ROS Package robot_kinect

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.

Bildschirmfoto vom 2016-01-09 21:28:09.png

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.

Bildschirmfoto vom 2016-01-09 22:05:28.png

Dann zurück in RViz das Topic /camera/depth_registered/points für die Pointcloud2 wählen und den ColorTransformer Wert auf RGB8 setzten.

Bildschirmfoto vom 2016-01-09 22:14:56.png

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:

Bildschirmfoto vom 2016-01-10 18:25:17.png

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.

  1. Dazu wurde zuerst die Kinect mit ins URDF-Modell des Roboters eingepflegt:

<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.

Bildschirmfoto vom 2016-01-12 21-25-46.png

Die letztlich verwendete Version basiert auf einem Mesh aus dem Package turtlebot_description

  1. Nun wurde das Package robot_kinect im ROS-Workspace erstellt, welches die im folgenden erstellten Launchfiles für die Kinect enthält.
  2. Zur Wandlung der Kinect- Daten in einen 2D-Laserscan wird, wie oben genannt, das ROS Package depthimage_to_laserscan benutzt. Deshalb wurde im Package robot_kinect das Launchfile depthimage_to_laserscan.launch erstellt:

<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

  1. Wir können nun die Laserscan-Daten zusammen mit unserem Robotermodell in RViz visualisieren:

Bildschirmfoto vom 2016-01-11 20_37_24.png

Die 2D-Laserscan-Daten des Kinect, visualisiert in RViz 

ROS Package robot_mapping

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

hector_map_first_try.png

Erster Test eine Karte zu erstellen mit Hector_Mapping

ROS Package robot_2dnav

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:

Meilenstein: Navigieren des Roboters mittels RViz Navigationgoals

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.

ROS Package: arduino_examples

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.

ROS Webtools

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