kramann.info
© Guido Kramann

Login: Passwort:










kramann.info
© Guido Kramann

Login: Passwort:




Ideen zu einer Implementierung einer Skriptsprache für das COACH-Vehikel

  • Nach den ganzen Vorüberlegungen, sollen nun einige ganz konkrete Ansätze zur Umsetzung einer Skriptsprache und des zugehörigen Interpreters dargestellt werden.

Konfiguration eines Fuzzy-Systems

  • Ein Fuzzy-System wird durch die Lage der Maxima der Zugehörigkeitsfunktionen und eine Liste an Regeln beschrieben.
  • Beides ließe sich auch in Array bzw. Matrix-Form über Funk als eine Art Skript auf ein Vehikel übertragen.
  • Erinnern Sie sich an Kapitel 10.3 Regelungssysteme, dass die Regeln als eine einfache Matrix von Indices für den Einachser umgesetzt werden konnten:
...
int indices[25]  = {
                                    0,0,1,2,2,
                                    0,1,2,2,3,
                                    0,1,2,3,4,
                                    1,2,2,3,4,
                                    2,2,3,4,4
                                };
...

Code 0-1: Ausschnitt aus der Klasse Fuzzysystem für den Einachser.

  • Natürlich können die übertragenen Arrays und Matrizen nicht direkt als "Skript" bezeichnet werden.
  • Bei entsprechender Anlage mehrerer Fuzzy-Systeme zur Gestaltung des Verhaltens des Vehikels, entspricht der resultierende Effekt jedoch durchaus dem, bei dem das Verhaltensmuster über ein gewöhnliche(re)s Skript beschrieben wird.

Interpretation einer Liste von Befehlen

  • In unserem Fall kommt es nicht sehr darauf an, dass die Skriptbefehle von einem Menschen direkt gelesen und verstanden werden.
  • Der Verzicht hierauf erübrigt jedenfalls die Notwendigkeit eines komplizierteren Befehlsinterpreters, der die Wörter im Skript mit einer Liste mit den erlaubten Befehlen vergleicht.
  • Statt dessen wäre eine Nummer für eine aufzurufende Funktion auch ausreichend.
  • Angenommen, die verfügbaren Funktionen benötigten keine Übergabeparameter und lieferten auch keine Rückgabewerte, dann könnte ein sehr simpler Interpreter in folgender Weise mit einer switch-Anweisung realisiert werden:
for(int i=0;i<ANZAHL_BEFEHLE;i++)
{
     switch(befehls_liste[i])
     {
         case 0:
             antriebs_regelung.setzteSollwert(20);
         break;
         case 1:
             servo.links();
         break;
         case 2:
             wert[k++] = sensor.hole_wert();
             k%=10;
         break;
             ...
     }
}

Code 0-2: Denkbarer Programmabschnitt des Skript-Interpreters mittels switch-Anweisung

  • An dem Beispiel wird ersichtlich:
  • Auch wenn die Befehlsliste keine Parameter enthält, kann dies realisiert werden, indem unterschiedliche Befehlsnummern, die gleiche Funktion, jedoch mit unterschiedlichen Parametern aufrufen.
  • Ebenso können Rückgabewerte von Funktionen gespeichert werden, wenn die entsprechende Zuweisung direkt in einer der auswählbaren Anweisungen steht.
  • Ähnlich der Trennung zwischen Regeln und Zugehörigkeitspositionen bei Fuzzy-Systemen, können Parameter auch unabhängig zum Skript auf das Vehikel übertragen werden.

Verzicht auf "switch" und vergleichbare Kontrollstrukturen durch Einsatz von Funktionszeigern

  • C/C++ bietet die Möglichkeit neben Variablen auch Funktionen in Zeigern zu speichern.
  • Indem man die Zeiger aller verfügbaren Methoden in einem Array speichert und das "Skript" aus der Angabe der Indices dieses Arrays, kann auf die switsch-Anweisung verzichtet werden.
  • In C++ können Funktionszeiger aber nur folgendermaßen (testweise auf einem PC) umgesetzt werden:
#include<iostream>
using namespace std;
class Befehle
{
  public:      
     void tudies()
     {
         cout<<"dies"<<endl;          
     }
     void tudas()
     {
         cout<<"das"<<endl;          
     }
     void tujenes()
     {
         cout<<"jenes"<<endl;          
     }
};
int main()
{
    Befehle befehle;
    void (Befehle::*zeiger[3])(void) = {
                                         &Befehle::tudies,  
                                         &Befehle::tudas,
                                         &Befehle::tujenes,
                                     };    
    int skript[4] = {0,1,0,2};
    for(int i=0;i<4;i++)
        (befehle.*(zeiger[skript[i]]))();
}

Code 0-3: Verwendung von Funktionszeigern, um auf einen Teil der Kontrollstrukturen bei der Skriptinterpretation verzichten zu können

  • Erläuterungen:
  • void (Befehle::*zeiger[3])(void) ist ein Array von 3 Funktionszeigern mit dem Namen "zeiger".
  • Es hat als Übergabeparameter und Rückgabewert "void".
  • &Befehle::tudies wählt den Zeiger auf die Methode "tudies" der Klasse "Befehle" aus.
  • Da Funktionen in C++ an Objekte gebunden sind und nur über eine Syntax "OBJEKTNAME.FUNKTION()" aufgerufen werden können, wäre ein Aufruf, um die nullte Funktion in zeiger anzusprechen der Art *(zeiger[0]))(); in C++ unzulässig.
  • Mit (befehle.*(zeiger[skript[i]]))(); wird die im Zeiger gespeicherte Funktion an ein Objekt gebunden.
  • Diskussion:
  • Die Verwendung von Funktionszeigern führ sicher zu einem performanteren Programm.
  • Sie setzt aber voraus, dass alle möglichen Methoden in einer Klasse gesammelt werden.
  • Dies zu bewerkstelligen kann wiederum einen recht hohen Programmieraufwand bedeuten.