Softwarekonzepte der Robotik am Beispiel des Rug Warrior


Inhalt:

1. Allgemeines zu Robotern und Programmiersprachen

2. Bottom Up vs. Top Down

3. Die Praxis

4. Autonomie, Sensorik, Theoretisches und Arbeitsfelder


1. Allgemeines zu Robotern und Programmiersprachen

Im üblichen Sprachgebrauch versteht man unter einem Roboter, eine mehr oder minder komplexe Maschine, die in gewissem Maße ohne direkte Einwirkung des Menschen funktionieren kann. Roboter haben dabei im Gegensatz zu Computern physikalisch mechanische Komponenten über die sie mit ihrer Umwelt interagieren. Mit dem Wunsch Werkzeuge für immer komplexere Aufgaben zu entwickeln, entstand die Notwendigkeit Maschinen mit Sensoren auszustatten, um eine entsprechende Problemstellung zu lösen. Diese Sensorik ermöglichte es im Gegenzug, die Behandlung eines gewissen Aufgabenspektrums ohne zusätzliche Steuerung des Menschen, zu automatisieren. Eine genaue Unterscheidung zwischen einer komplexen Maschine und einem Roboter wird in der Regel nach einem sehr subjektiven Kriterium gefällt, der Analogie zu biologischem Leben. Industrieroboter ähneln Lebewesen insofern, als sie Extremitäten besitzen, wohingegen kaum jemand von einem Kopiergerät als Roboter sprechen wird, obwohl es sowohl sensorische als auch mechanische Komponenten enthält. Man unterscheidet verschiedene Klassen von Robotern hinsichtlich ihres Zwecks und herausragender Fähigkeiten, ersteres geschieht bei den schon erwähnten sog. Industrierobotern, letzteres beispielsweise, wenn man vom Rug Warrior als einem mobilen Roboter spricht.


Schematischer Aufbau eines Roboters:


Im folgenden soll nun hauptsächlich auf die Steuerungskomponente von Robotern eingegangen werden. Obwohl die Steuerung der sonstigen Komponenten im Prinzip durch eine feste Verdrahtung realisiert werden könnte, ist dieser Ansatz nur in sehr einfachen Fällen praktikabel. Wesentlich flexibler ist eine Steuerung die auf Computerprogrammen basiert. Als Grundlage für eine solche Steuerung kann dann, je nach Komplexität und Größe des Roboters, ein integrierter Chip dienen oder auch ein über Funk verbundener Workstation-Cluster. Die eigentliche Steuerung erfolgt durch Programme in entsprechenden Programmiersprachen, die im besten Fall von der zugrundegelegten Hardware unabhängig sind. Durch den Einsatz von Programmiersprachen stehen der Robotik damit alle Methoden der Softwaretechnik zur Verfügung, insbesondere solcher, die eine Bewältigung komplexer Problemstellungen unterstützen.

In der Robotik finden sich zwei Ebenen auf denen Programmiersprachen zum Einsatz kommen. Die erste, auf die im Folgenden nicht weiter eingegangen werden soll, obwohl sie die Grundlage für alles weitere bildet, ist die Hardwareschnittstelle. Hier müssen auf dem Maschinennivau die jeweils sehr speziellen Komponenten eines Roboters verfügbar gemacht werden. Alle Sensoren und Aktuatoren müssen in die Software abgebildet werden, damit sie zur Steuerung des Roboters herangezogen werden können. Dies geschieht unter Zuhilfenahme eines für die verwendete Computerplattform (Microcontroller, Laptop, ...) spezifischen Assemblerprogrammes. Ist die Hardwareschnittstelle realisiert worden, so kann die weitere Programmierung in einer höheren Programmiersprache erfolgen. Abhängig vom gewünschten Steuerungsprogramm können verschiedene Programmiersprachen herangezogen werden, mit denen die jeweiligen Aufgaben gelöst werden. (LISP, IC, ...)


2. Top Down vs. Bottom Up

Betrachtet man Steuerungsprogramme für Roboter, so findet man zwei Herangehensweisen, die sich grundlegend unterscheiden. Der erste, klassische Ansatz deckt sich im wesentlichen mit der Herangehensweise in der Forschung über Künstliche Intelligenz und könnte auch Weltmodell-Ansatz genannt werden. Der zweite Ansatz ist wesentlich jünger und geht auf eine Arbeit von Professor Rodney Brooks und der Arbeitsgruppe Mobile Roboter am MIT Artificial Intelligence Laboratory zurück.


2.1. Modellierung, Planung

Bei diesem Ansatz erfolgt zunächst das Sammeln von Sensordaten, diese werden dann klassifiziert und auf Widersprüchlichkeiten untersucht, bis schließlich intern ein stimmiges Weltmodell aufgebaut wird. Anhand dieses Modells wird eine Abfolge von Aktionen geplant, die schließlich zur Ausführung gebracht werden.


Beispiel: pick-and-place Problem

Ein Roboter soll ein Werkstück innerhalb eines gewissen Bereiches aufnehmen und an einer festgesetzten Position wieder absetzen. Zunächst wird durch einen Laserscanner die Position und Ausrichtung des Werkstücks bestimmt. Die gewonnenen Daten werden in das übrige Weltmodell eingefügt, das vom Programmierer aufgebaut wurde, und auch die festgelegte Zielposition enthält. Nun errechnet das Programm aufgrund des Weltmodells eine Bewegungsabfolge mit der das Problem gelöst werden kann. Schließlich wird diese Bewegungsabfolge umgesetzt in eine Reihe von Steuerbefehlen, die eine Greifarm veranlassen das Werkstück aufzunehmen, entsprechend zu drehen und zu positionieren und es wie gewünscht abzusetzen.


2.2. Subsumtion

Hier verzichtet man auf das Anlegen eines Weltmodells und konstruiert hingegen mehrere Verhaltensmuster, die von den Sensordaten beeinflußt werden. Alle diese Verhalten sind gleichzeitig aktiv, welches von ihnen tatsächlich zur Ausführung kommt, wird durch Prioritäten geregelt.


Beispiel: search-light

Ein Roboter soll in einem Gebiet herumfahren ohne zu kollidieren, bis er ein leuchtendes Objekt entdeckt, und diese dann rammen. Der Roboter verfügt hierzu über einen Ring von Ultraschall-Sensoren sowie über zwei Photo-Sensoren, die nach vorne-links und vorne-rechts ausgerichtet sind. Die Ultraschall-Sensoren ermöglichen es dem Roboter ein Verhalten zu geben, das Kollisionen vermeidet. Dieses Verhalten (Avoid) ist aktiv, solange die Photo-Sensoren nicht ausreichend aktiv sind. Sobald dies eintritt, tritt ein zweites Verhalten mit höherer Priorität in Kraft, das den Roboter veranlaßt auf das entsprechende Objekt zuzufahren.


2.3. Vor- und Nachteile

Der Weltmodell-Ansatz ermöglicht Optimierungen in der Planungsphase, auf Grund der Daten des Weltmodells kann ein optimaler Weg ermittelt werden, um die Aufgabe zu lösen. Oft sind auch Garantien möglich, die besagen, daß eine Aufgabe binnen einer vorgegebenen Zeit gelöst werden kann. Das Verfahren steht und fällt allerdings mit der Güte des Weltmodells und damit der Sensordaten und ihrer Verarbeitung. Dieser Umstand führt zu erheblichen Kosten, sowohl finanzieller (genaue Sensoren, Kallibrierung, ...) als auch zeitlicher (großer rechnerischer Aufwand) Art. Insbesondere darf sich die Umgebung des Roboters nicht allzu schnell verändern, da sonst das einer Bewegung zugrundeliegende Weltmodell zum Zeitpunkt ihrer Durchführung überhaupt nicht mehr aktuell ist.

Die Subsumtion hingegen ermöglicht sehr schnelle Reaktionen des Roboters auf seine Umwelt. Zudem führt ein komplexeres Steuerungsprogramm nicht zu einer Verlangsamung, da sich die Verhalten beliebig parallelisieren lassen. Der Verbesserung eines Subsumtionsprogramms sind damit keine Grenzen gesetzt und es kann nach und nach weiter Verfeinert werden, indem man die Steuerung durch zusätzliche Verhalten auf höheren Ebenen ergänzt (Bottom Up). Allerdings lassen sich kaum genaue Vorhersagen über die Bewältigung einzelner Aufgaben treffen und die vorab Optimierung eines Vorganges ist ebenso unmöglich.


Top Down

Bottom Up


Weltmodell


Sensor-Aktuator-feed-through

Sensordatenfusion

Verhaltensfusion


3. Die Praxis

Mit dem am MIT entwickelten Bausatz des Rug Warrior wird ein Beispielprogramm geliefert, das die verfügbare Sensorik ausnutzt um eine Lichtquelle zu suchen. Realisiert wurde das Programm in IC einem Interpreter der sich stark an der Syntax von C orientiert. Es soll als Beispiel für eine Subsumtionsarchitektur analysiert werden.


3.1. Verwendete Sensoren und Aktuatoren

Um Licht orten zu können verfügt der Rug Warrior über zwei Photowiderstände, die vorne links und rechts angebracht sind. Mit Hilfe eines Infrarotsenders und zweier Empfänger können Hindernisse erkannt werden, hierbei erfolgt jedoch keine Entfernungsbestimmung. Kommt es zu einer Kollision, so registrieren dies Microschalter, die je nach Ort der Kollision einzeln oder in Kombination geschlossen werden.

Die Bewegung erfolgt über das Anlegen von Spannung an zwei Motoren, die Shaft-Encoder zur Messung der Umdrehungen des jeweils verbundenen Rads werden nicht verwendet.


3.2. Verhaltensmuster

Die Einzelnen Verhaltensmuster sind als Funktionen implementiert, für das Verhalten maßgebend sind dabei folgende:


int cruise() /* Default activity */

{

while(1)

{

cruise_command = FORWARD; /* Robot forward */

cruise_active = 1;

wait(1000); /* Cruise once a second */

}

}


int photo() /* Follow a light */

{

int lpc, rpc, delta; /* Left and Right Photo Cells */

while (1)

{

lpc = analog(1) + photo_cal;

rpc = analog(0);

delta = rpc - lpc; /* + => left sees bright, - => right */

/* New for demo */

if (switch() == 0)

delta = rpc - lpc; /* Seek Light */

else

delta = lpc - rpc; /* Seek Darkness */

del_out = delta; /* DEBUGGING */

if ( abs(delta) > photo_dead_zone )

{

if (delta > 0)

photo_command = LEFT_ARC; /* Left bright => turn left */

else

photo_command = RIGHT_ARC; /* Otherwise turn right */

photo_active = 1; /* Activate when detected */

}

else

photo_active = 0; /* Deactivate when not detected */

defer(); /* Once per scheduler tick */

}

}


void ir()

{

int val;

while (1)

{

/* New for demo */

if (switch() == 2) /* Sound mode */

{

leds(0); /* Do it for sound mode */

val = 0;

}

else /* Otherwise do it the normal way */

val = ir_detect();

sleep(0.25); /* Don't change too often */

ir_out = val; /* DEBUG */

if (val == 0b11) /* Left and right */

{

ir_active = T;

ir_command = LEFT_ARC;

}

else if (val == 0b01) /* Left IR */

{

ir_active = T;

ir_command = RIGHT_ARC;

}

else if (val == 0b10) /* Right IR */

{

ir_active = T;

ir_command = LEFT_ARC;

}

else

{

ir_active = NIL;

}

defer();

}

}


void bump()

{

while (1)

{


bump_check();

if ((bump_left | bump_right) != 0) /* Any collisions? */

recent_hits++; /* Add to count of recent hits */

else

recent_hits--; /* Let hits drain away */

recent_hits = limit(recent_hits, 0, 4); /* Limit the range or rh */


if (bump_left && bump_right)

{

bump_active = 1;

bump_command = BACKWARD;

wait(msec_per_rad / 2); /* Move back a bit */

bump_command = LEFT_TURN;

wait(rev_4);

}

else if (bump_left)

{

bump_active = 1;

bump_command = RIGHT_TURN;

wait(recent_hits * rev_8);

}

else if (bump_right)

{

bump_active = 1;

bump_command = LEFT_TURN;

wait(recent_hits * rev_8);

}

else if (bump_back)

{

bump_active = 1;

bump_command = LEFT_TURN;

wait(recent_hits * rev_4);

}

else

bump_active = 0;

defer();

}

}


Diese Verhaltensmuster sollen nun alle zur gleichen Zeit aktiv sein, dazu muß die Prozessorzeit auf alle Funktionen Aufgeteilt werden. Dies geschieht in so kurzen Zeitintervallen, daß der Eindruck der Gleichzeitigkeit entsteht (Multitasking). Ein Programm, das die Verwaltung dieses Vorganges übernimmt, wird als Scheduler bezeichnet und muß im Allgemeinen vom Programmierer selbst implementiert werden. IC bietet jedoch bereits alle Funktionen die dazu notwendig sind und erlaubt, das starten von Funktionen als sog. Prozesse. Eine als Prozess aufgerufene Funktion wird solange wiederholt, bis der entsprechende Prozess abgebrochen wird. Das Starten der notwendigen Prozesse sieht im Quelltext folgendermaßen aus:


void main()

{ sleep(0.75);

test_number++; /* Update test number */

alert_tune(); /* Show that processes are starting */

start_process(printer()); /* For debugging */

start_process(motor_control());

start_process(cruise());

start_process(photo());

start_process(ir());

start_process(bump());

start_process(check_sound()); /* Sometimes we listen for a sound */

start_process(check_bump());

}


Einige der gestarteten Prozesse wurden bisher nicht erwähnt, weil sie für die eigentliche Aufgabe keine wesentliche Bedeutung haben, einer der Prozesse ist allerdings für das funktionieren des Programms unerläßlich. Es handelt sich um die Steuerung der Prioritäten der Prozesse, dort wird festgelegt welches der Verhaltensmuster momentan für die Aktionen des Rug Warrior ausschlaggebend ist:


void motor_control()

{

while (1)

{

if (switch() == 2) /* Stop while listening... */

move(STOP);

else if (bump_active)

move(bump_command);

else if (ir_active)

move(ir_command);

else if (photo_active)

drive(50.0, (float) del_out * p_gain);

else if (cruise_active)

move(cruise_command);

else

move(STOP); /* No commands => STOP */

defer(); /* Update once per scheduler iteration */

}

}


4. Autonomie, Sensorik, Theoretisches und Arbeitsfelder

Im Zusammenhang mit mobilen Robotern spricht man ab und an auch von autonomen Robotern. Autonomie bezieht sich dabei auf die Fähigkeit selbständig zu agieren und kann in sehr verschiedenen Abstufungen auftreten:

- Selbständiges Manövrieren in beliebiger Umgebung ohne Selbstgefährdung

- Selbständige Energieaufnahme

- Selbständige Reproduktion

Strebt man für einen Roboter Autonomie in Bezug auf ein bestimmtes Problem an, so hat dies Konsequenzen in allen wesentlichen Bereichen. Zunächst ist Autonomie auf eine Bestimmte Klasse von Umgebungen beschränkt, da beispielsweise bei zu rauhem Gelände das Fahrwerk modifiziert werden muß. Ebenso verhält es sich mit der verwendeten Sensorik, die ebenfalls nur unter bestimmten Bedingungen zu gebrauchen ist. Häufig ist für die Nutzung von Sensoren abhängig von Parametern, um Rauschen und Meßfehler zu unterdrücken. Deren optimale Werte sind von der Umgebung abhängig. Besitzt der Roboter die Möglichkeit diese Parameter eigenständig anzupassen, so wird er autonomer. Theoretisch ist dies von Belang, da es für bestimmte Fragestellungen unerläßlich scheint, die Umgebung in die Definition eines Roboters einzubeziehen (offene Systeme).

Am Rug Warrior sind vor diesem Hintergrund folgende Aufgaben von Interesse:

- Selbständiges Anpassen von Steuerparametern (z.B.: photo_dead_zone)

- Bau einer Dockingstation zum selbständigen Wiederaufladen der Batterien

- Flexibles Steuerungssystem, das den Ausfall einzelner Sensoren erkennen und kompensieren kann

Als Grundlage für solche Arbeiten scheint es außerdem angebracht eine verbesserte und sauber spezifizierte Hardwareschnittstelle zu realisieren, sowie den Aufbau einer Subsumtions-Architektur mit IC zu standardisieren, so daß einzelne Verhaltensmodule problemlos zwischen den am Projekt beteiligten ausgetauscht werden können.

- saubere Hardwareschnittstelle für den Rug Warrior (evtl. erweiterbar zu einer allgemeinen HW-Schnittstelle)

- modulare Subsumtionsarchitektur mit IC

Ein Konzept, das die Subsumtionsarchitektur mathematisch zugängig macht ist das „Dual Dynamics Design Scheme“ von Herbert Jaeger, es enthält einige interessante Ansätze und könnte als Grundlage für eine praxisorientierte Implementation dienen.



Literatur/Quellen:


Herbert Jaeger: The Dual Dynamics Design Scheme for Behavior-based Robots, Arbeitspapiere der GMD 966, 1996

Joseph L. Jones, Anita M. Flynn: Mobile Roboter, 1. Aufl. Addison Wesley 1996

Joseph L. Jones, The Mobile Robot Assembly Guide With Interactive C Manual, A K Peters 1996


demo-one.c, Beilage des Rug Warrior Bausatzes „The Brains and the Brawns“

AUTOR_Bernd