Kalman-Filter zur Bestimmung der Geschwindigkeit aus den LIDAR-Daten

Aus HSHL Mechatronik
Zur Navigation springen Zur Suche springen

Autor: Daniel Block

Bearbeiten Sie nachfolgende Aufgaben bis zum Abgabetermin und stellen Sie Ihre Lösung bis zum Abgabetermin Prof. Göbel vor. Gehen Sie systematisch in den in SDE vermittelten Schritten

  • Theorie
  • Konzept
  • Modellierung
  • Umsetzung
  • Testing

vor.


Die erstellten Dateien wurden, wenn nicht anders angegeben, im Ordner MTR_SDE_Praktikum/trunk/Daten/Kalman-Filter zur Bestimmung der Geschwindigkeit aus den LIDAR-Daten gespeichert.
LIDAR steht im gesamten Artikel für den auf dem AMR des SDE-Praktikums verbauten Laser-Scanner mit einem Rundumlaser.

Konzept

Als Aufgabenstellung ist anhand der LIDAR-Messwerte die Egogeschwindigkeit des Fahrzeugs in Längsrichtung mittels Kalman-Filter zu schätzen.

Aufzeichnung

Zeichnen Sie im Praktikum mit Hilfe des Teams Deitel/Groß eine Geradeausfahrt auf ein stehendes Ziel (z.B. Karton) auf. Diese Aufzeichnung sollte auch die aus den Hallsensoren ermittelte Geschwindigkeit und Position enthalten.


Die Aufzeichnung geschieht mit dem AMR des SDE-Praktikums gesteuert über dSPACE ControlDesk®. Das genaue Vorgehen bei einer Messung mit ControlDesk® mit Hilfe eines selbst konfigurierten Recorders wird in dem Artikel Messungen mit dSPACE ControlDesk beschrieben.
Es wird eine einfache Geradeausfahrt mit relativ langsamer Geschwindigkeit auf ein stehendes Hindernis aufgezeichnet. Als Hindernis werden nacheinander ein Rollcontainer und ein Papierkarton verwendet. Jede Art von Messunge wird mehrmals wiederholt, um die Messdaten dadurch zu validieren. Da die Kommunikation zwischen dem LIDAR und der dSPACE-Autobox zwischendurch abbricht, sind ebenfalls mehrere Messungen erforderlich. Aus den Aufzeichungsdaten kann dann für die Auswertung ein geeigneter Datensatz ausgewählt werden.
Folgende Daten werden aufgenommen:

  • Streckenmessung Hallsensoren SenVx_sx_K_f64
  • Geschwindigkeit Hallsensoren SenVx_vx_K_f64
  • Winkel der Objekte Signal_Object_angle als Array [5x1]
  • Tiefe der Objekte Signal_Object_depth als Array [5x1]
  • Wahrscheinlichkeit der Objekte Signal_Object_plausibility als Array [5x1]
  • Geschwindigkeit der Objekte Signal_Object_speed als Array [5x1]
  • Breite der Objekte Signal_Object_width als Array [5x1]
  • X-Koordinate der Objekte Signal_Object_x als Array [5x1]
  • Y-Koordinate der Objekte Signal_Object_y als Array [5x1]
  • Parameter der Objekte Signal_Object_params als Array [5x1]
  • Zähler der Objekte Signal_Object_count

Die Messdaten werden als mat-File exportiert und können in Matlab eingelesen werden.
Die Mess-Dateien als exportierte mat-Files liegen in im SVN-Archiv des SDE-Pratkikums unter MTR_SDE_Praktikum/trunk/Software/CaroloCupFahrzeug/dSPACE/Carolo Cup Fahrzeug/Inbetriebnahme/Measurement Data/. Es sind die Dateien lid001.mat bis lid015.mat.

Schnittstelle zu Matlab

Lesen Sie die Messwerte in Matlab (nicht Simulink) ein.


Da die Qualität und Verwendbarkeit der Messdaten untersucht werden muss, werden zunächst alle Messungen geladen. Dies geschieht mit dem load-Befehl in Matlab. Hier ein Beispiel:

% Datei mit Pfad und Dateinamen festlegen
Datei=([Pfad,Name]);
messung = load(Datei);

Signalnamen

Um eine schnelle Übersicht der getriggerten Signale zu bekommen, können die Signale in eine separate char-Variable gespeichert werden. Dabei muss berücksichtigt werden, dass die Messdaten in einer struct-Variabel gespeichert sind.

%% Namen der Signale extrahieren
% enthaltene Namen aus einer Messung (hier lid001) auslesen
for k=1:45
    namen_Signale.cell(k) = cellstr(lid001.Y(1,k).Name);
end

% Signalnamen an Matlab-Konvention anpassen, entfernen eckiger Klammern
for ii=1:45
    namen_Signale.cell(ii)=strrep(namen_Signale.cell(ii), '[',);
    namen_Signale.cell(ii)=strrep(namen_Signale.cell(ii), ']',);
end

% in char konvertieren
namen_Signale=char(namen_Signale.cell);

Diese beiden Befehle sind in dem Script NamenAuslesen.m zusammengefasst.

Visualisierung

Von den aufgenommenen Messungen können, wie oben angedeutet, evt. nicht alle verwendet werden. Deswegen werden die einzelnen Signale der Messungen in separaten Plots visualisiert. Hier ist das beispielhaft für die Messung lid008.mat gezeigt.

for ii=1:length(lid008.Y)
    figure
    plot(lid008.X.Data,lid008.Y(1,ii).Data)
    xlabel('t [s]')
    ylabel(strrep(lid008.Y(1,ii).Name,'_','\_'))
    grid on, box on
end

Diese Befehlsfolge befindet sich im Script PlotData.m.
Dadurch können die nicht verwendbaren Messungen schnell identifiziert werden, da ohne genaue Betrachtung der Daten ein erster Eindruck möglich ist. Desweiteren kann für die jeweilige Messung der ungefähre zeitliche Rahmen bestimmt werden. Dies kann mit dem Cursor z. Bsp. im Plot der Streckenmessung herausgefunden werden, vgl. Abbildung Cursor im Matlab-Plot.

Cursor im Matlab-Plot (Originaldatei)

Es stellte sich heraus, dass nur folgende Messungen von Null verschiedene Daten enthalten

Messung Messzeitraum in s
lid004.mat 23.5
lid005.mat 14.8
lid007.mat 27.75
lid008.mat 16.7

Messungen laden

Für das Laden der Messdaten wurde eine separate Funktion MessungLaden.m geschrieben. Nachdem die Variable für die Daten als leere struct-Variable angelegt wurde, wird der Benutzer in einem Dialogfenster nach der einzulesenden Datei gefragt.

%% Messung extrahieren aus Mat-Datei
% Mat-Datei laden
% Benutzer bekommt Pfad-, Dateinamen- und Dateiformat-Vorschlag
[Name,Pfad]=uigetfile({'*.m;*.fig;*.mat;*.slx;*.mdl','MATLAB Files (*.m,*.fig,*.mat,*.slx,*.mdl)';
   '*.m',  'Code files (*.m)';'*.fig','Figures (*.fig)';'*.mat','MAT-files (*.mat)'; ...
   '*.mdl;*.slx','Models (*.slx, *.mdl)';'*.*',  'All Files (*.*)'},'Dateiauswahl',...
          '..\..\Software\CaroloCupFahrzeug\dSPACE\Carolo Cup Fahrzeug\Inbetriebnahme\Measurement Data\lid004.mat');
Datei=([Pfad,Name]);
messung = load(Datei);

Mit der Funktion fieldnames lassen sich in struct-Variablen die Namen der Ebenen auslesen. In der ersten Ebene lässt sich hier somit der ursprüngliche Name des mat-Files abspeichern.

% Messungsnamen auslesen
name_messung = fieldnames(messung);

Im Weiteren wird die Struktur der Messung in die erste Ebene der Variable verschoben. Sollte das nicht möglich sein, wird eine Fehlermeldung ausgegeben.

% in erste Ebene der Struktur verschieben
if length(name_messung) == 1
    messung = messung.(name_messung{1});
else % Fehlermeldung, falls nicht möglich
    fprintf('Messstruktur nicht lesbar, bitte Aufbau der Struktur überprüfen. In der ersten Ebene muss die Messdatei mit seinem Namen stehen');
end

Die Signale werden nun in die zuvor erstellte Variable geschrieben.

% Ergebnisstruktur nur mit den Signalen füllen
Messdaten.(messung.Y(ii).Name) = messung.Y(ii).Data';

Rohdatenverarbeitung

Extrahieren Sie aus LIDAR-Messwerten das stehende Objekt. Sie dürfen gern den Algorithmus aus der Vorlesung verwenden.


Übersichts-Plot

Für die Auswahl aus den vier oben genannten Messungen wurde ein Übersichts-Plot für die relevanten Signale realisiert. Beispielhaft für die Messung Lid007 ist dieser in der Abbildung Übersichts-Plot der Messung Lid007 zu sehen. Der Plot wird mit der Funktion PlotMessung.m aufgerufen.

Übersichts-Plot der Messung Lid007 (Originaldatei)

In dem Fensternamen wurde zur besseren Übersicht der Name der Messung integriert. Dieses lässt sich mit dem Attribut Name in der figure-Anweisung erreichen. Hier ein Beispiel:

figure('Name',['Plot der Messung ' char(name_messung)])

Der Plot besteht aus mehreren Subplots mit jeweils einem Signal über der Zeit. Die Achsen sind beschriftet mit einem Schlagwort und der Einheit des Signals. Die Gitternetzlinien werden angezeigt. Der Code dafür sieht zum Beispiel so aus:

subplot(2,4,1)
hold on
plot(Messdaten.t,Messdaten.SenVx_vx_K_f64, 'b', 'LineWidth', 2)
xlabel('t [s]')
ylabel('Geschwindigkeit v [m/s]')
grid on

Es ist festzustellen, dass die y-Koordinate der Objektdaten in Fahrtrichtung des Fahrzeuges zeigt. Die x-Koordinate zeigt dementsprechend in Fahrtrichtung nach rechts. Die Längenangaben in den Objektdaten sind in Millimeter mm, die Winkel in Radiand rad. Die Werte für die Wahrscheinlichkeit sind in Prozent % angegeben.

Plot der Fahrt

Im weiteren Schritt soll ein erster Eindruck der Bewegung des Fahrzeugs auf das Objekt zu geschaffen werden. Dafür wird in einem Plot das Objekt als Rechteck statisch dargestellt. Im Plot ist der Nullpunkte der Ordinate die fahrzeugzugewandte Seite des Objektes. Die Dimension des Hindernisses ist beispielhaft gewählt mit einer Breite von 0,6 m und eine Tiefe von 0,4 m.

% Objekt alles statisches Rechteck
rectangle('Position',[-0.30,0,0.6,0.4])

Damit das Bild im Plot nicht verzehrt wird, sind die Skalierungen der beiden Koordinaten-Achsen gleich zu wählen.

% Skalierung der Achsen gleichmäßig --> keine Verzerrung
axis equal

Bei der Betrachtung der Signale fällt auf, das die Objektwerte aus der LIDAR-Messung nicht für jeden Zeitstempel aktualisiert werden. Dies ist auch in der sprungförmigen Darstellung der Signale in dem Plot zu sehen, vgl. Abbildung Übersichts-Plot der Messung Lid007. Möglicherweise liegt hier ein Performance-Problem der Datenübertragung zwischen LIDAR und CPU auf dem AMR vor, da anzunehmen ist, dass die Abtastrate des LIDARs deutlich höher ist. Aus diesem Grund werden die Wertepaare, die als Wegpunkte des Fahrzeugs angesehen werden können, in einer zuvor angelegten Matrix position geschrieben. Diese werden dabei von Millimeter in Meter umgerechenet. Die y-Koordinaten werden mit -1 multipliziert, sodass der abnehmende Abstand zum Objekt, das bei 0 steht, visualisiert werden kann.

% Matrix für Wegpunkte vorbereiten, da sich nicht zu jedem Zeitstempel Koordinaten ändern
position=zeros(2,2);
n=1;

% Durchlauf über alle Zeitstempel
for ii=1:length(Messdaten.Signal_Object_x0)
    
    [...]

        position(n,1)=Messdaten.Signal_Object_x0(ii)/1000;
        position(n,2)=-Messdaten.Signal_Object_y0(ii)/1000;
        n=n+1;
end

Sind zwei zeitlich folgende Wertepaare identisch, werden diese nicht gespeichert. Leere Signalwerte werden im Schleifendurchlauf über die Messwerte übersprungen. Mit dem Befehl contiune wird der aktuelle Schleifendurchlauf beendet und der nächste begonnen.

% leere Signale überspringen
if (Messdaten.Signal_Object_x0(ii)==0) || (Messdaten.Signal_Object_x0(ii)==-inf)
   continue
end

Durch diese Maßnahmen kann die Durchlaufzeit des gesamten Scriptes deutlich reduziert werden, da nicht alle Werte für den Plot verwendet werden.
Der Plot der Wegpunkte erfolgt mit roten Kreisen, die Wegstrecke wird durch eine rote Linie dargestellt. Es werden einfach alle Wertpaare der zuvor erstellten Matrix durchlaufen. Dabei muss darauf geachtet werden, dass Index nicht größer als die Matrix-Dimension wird.

% Durchlauf über alle Wegpunkte
for m=1:length(position)
    
    % Plot der Wegpunkte als rote Kreise
    plot(position(m,1),position(m,2),'ro')

    % Plot der Strecke zwischen zwei Wegpunkten als blaue Linie
    if m<length(position)
       line([position(m,1) position(m+1,1)],[position(m,2) position(m+1,2)])
    end
end

Die Funktion PlotFahrt.m erzeugt diesen Plot, vgl. Abbildung Plot der Fahrt auf das Objekt zu.

Plot der Fahrt auf das Objekt zu (Originaldatei)

Die Aufgabe lautet, das Objekt aus den Messdaten zu extrahieren, da sich aber das Fahrzeug auf das Objekt zubewegt, wurde hier diese Darstellung gewählt. In der Weiterverarbeitung soll es ja auch um die Geschwindigkeit des Fahrzeugs und nicht des Objektes gehen.

Modellierung

Erstellen Sie ein System- und ein Messmodell.

Als Systemmodell ist ein Ruck-Null-Modell zu wählen.

Der Zustandsvektor lautet


Nutzen Sie ein Kalman-Filter-Tracking, um die Geschwindigkeit und Position des Egofahrzeugs kontinuierlich aus den stehenden Objekten zu bestimmen. Hierzu dürfen keine Toolboxen verwendet werden.


Für das Kalman-Filter sind folgende Schritte notwendig:

  • Initialisierung
  • Prädektion
  • Schätzung

In diesen wird auch hier vorgegangen.

Initialisierung

Es werden ein System- und ein Messmodell benötigt.

Systemmodell

Als Systemmodell soll ein Ruck-Null-Modell zum Einsatz kommen. Dieses meint ein Bewegungsmodell, bei dem sich die Beschleunigung nicht ändert. Hier wird die Geschwindigkeit ebenfalls als statisch angenommen, Rauschen wird dabei vernachlässigt (vgl. Abbildung Übersichts-Plot der Messung Lid007). Richtungsänderungen kommen nur durch äußere Einwirkungen zustande, es wurde nicht aktiv gelenkt. Somit liegt hier für das System eine gleichförmige Bewegung vor.
Das allgemeine Systemmodell lautet xk+1=Axk+wk . Da das Systemrauschen wk als Null angenommen wird, lässt sich das Systemmodell hier vereinfachen zu xk+1=Axk mit A={1 t;0 1} .

Messmodell

Das Messmodell beschreibt den Zusammenhang zweier aufeinanderfolgender Messwerte. Das allgemeine Messmodell lautet zk+1=Cxk+vk. Das Messmodell lässt sich hier vereinfachen zu zk+1=Cxk+R mit C={1 0} und R als Skalar.

Rauschen

Das Systemrauschen wird als sehr gering angenommen. Die Rauschmatrix Q wird festgelegt mit Q={0,001 0;0 00,1} . Die Werte auf der Hauptdiagonalen sind die Kovarianzquadrate von x und v. Die Werte der Nebendiagonalen beschreiben die Kovarianz zwischen Strecke und Geschwindigkeit, diese ist hier nicht vorhanden.
Das Messrauschen ist relativ groß, wird als Kovarianzquadrat mit 10 festgelegt.

Startwerte

Die initialen Werte werden wie folgt festgelegt:

  • Geschwindigkeit v0=0,11 m/s
  • Entfernung vom Fahrzeug zum Objekt x0=1 m
  • initiale Fehlerkovarianzmatrix P={1 0;0 1}

Diese Fehlerkovarianzmatrix beschreibt, wie genau die Schätzug war. Da sich diese an dem Plot orientiert, wird sie mit relativ hoher Sicherheit angenommen.

Prädektion

Ergebnisdarstellung

Stellen Sie die Schätzung in je einem Diagramm und der Messung gegenüber und diskutieren Sie diese.

Plausibilisieren Sie die Strecke und die Geschwindigkeit über die mit dem Hallsensor gemessenen Referenzdaten.

Code Review

Machen Sie für Ihren Quelltext ein Code Review und dokumentieren Sie dieses in der Vorlage (\Anforderungsmanagement\Testverfahren).

Modultest

Führen Sie für Ihre Quellen einen Komponententest durch und dokumentieren Sie diesen entsprechend der Vorlesung Reliability Engineering. Simulieren Sie hierzu die Eingangsdaten, stellen Sie die Ergebnisse dar und diskutieren Sie diese.

Systemtest

Prüfen Sie, ob Ihr Modell negative Auswirkungen auf das Gesamtsystem (EPA, BSF) hat. Führen Sie Ihre Ergebnisse Herrn Prof. Göbel vor und übernehmen Sie nach der Abnahme das Modell in den Hauptzweig (trunk).

Dokumentation

Dokumentieren Sie alle Daten in SVN und die Ergebnisse in diesem Artikel. Berücksichtigen Sie dabei die Kriterien für wissenschaftliches Arbeiten sowie die Anforderungsunterlagen von SDE (z.B. Schnittstellendokumentation.docx, Namenskonventionen.pdf, Lastenheft_AutonomesFahrzeug.docx).



→ zurück zum Hauptartikel: Geschwindigkeitsermittlung