Ich habe einen 2-Rad-Differentialantriebsroboter, den ich mit pid für die Steuerung des niedrigen Füllstands verwende, um der Linie zu folgen. Ich habe q learning implementiert , das Samples für 16 Iterationen verwendet und diese dann verwendet, um die beste Position für die Linie zu bestimmen, damit das Auto von dort aus abbiegt. Dadurch kann die PID eingerichtet und schnell verfolgt werden. Meine Frage ist, wie ich eine Belohnungsfunktion einrichten kann, die die Leistung verbessert, dh dem q-Lernen ermöglicht, das Beste zu finden
Bearbeiten
Was es zu lernen versucht, ist Folgendes: Es hat 16 Eingaben, die die Zeilenpositionen für die letzten 15 Iterationen und diese Iteration enthalten. Linienposition zwischen -1
und 1
welche -1
Mittel nur links meisten Sensor sieht die Zeile und 0 ist die Linie in der Mitte. Ich möchte, dass es eine Linienposition lernt, die, wenn es wieder dieser Eingabe zugewandt ist, diese Linienposition wie die Mitte einstellt und die Kurve entsprechend dieser Linienposition nimmt. Zum Beispiel ist ein Fehler erforderlich. Position - Linienposition. Nehmen wir also an, ich hätte 16 0
als Eingabe, dann habe ich die erforderliche als berechnet 0.4
. Danach wird sich das Auto zentrieren. 0.4
Ich hoffe, das hilft :)
Du hast nach meinem Quellcode gefragt, den ich unten poste
void MainController::Control(void){
float linePosition = sensors->ReadSensors();
if(linePosition == -2.0f){
lost_line->FindLine(lastPos[1] - lastPos[0]);
}
else{
line_follower->Follow(linePosition);
lastPos.push_back(linePosition);
lastPos.erase(lastPos.begin());
}
}
Mein Sensorwert gibt einen Wert zwischen -1.0f
und zurück 1.0f
. 1.0f
bedeutet, dass der äußere Sensor rechts nur die Linie ist. Ich habe 8 Sensoren.
void LineFollower::Follow(float LinePosition){
float requiredPos = Qpredictor.Process(LinePosition,CurrentSpeed);
float error = requiredPos - LinePosition;
float ErrorDer = error -LastError;
float diffSpeed = (KpTerm * error + (KdTerm * ErrorDer));
float RightMotorSpeed = CurrentSpeed - diffSpeed;
float LeftMotorSpeed = CurrentSpeed + diffSpeed;
LastError = error;
driver->Drive(LeftMotorSpeed,RightMotorSpeed);
}
Hier ist die Logik für den Wert für QPredictor (ich nenne den Lernteil so). Und schließlich QPredictor
float Memory[MemorySize][DataVectorLength] =
{
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3},
{0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6},
{0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8},
{0.000, 0.012, 0.050, 0.113, 0.200, 0.312, 0.450, 0.613, 0.800, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000},
{0.000, 0.000, 0.012, 0.050, 0.113, 0.200, 0.312, 0.450, 0.613, 0.800, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000},
{0.000, 0.000, 0.000, 0.012, 0.050, 0.113, 0.200, 0.312, 0.450, 0.613, 0.800, 1.000, 1.000, 1.000, 1.000, 1.000},
{0.000, 0.000, 0.000, 0.000, 0.012, 0.050, 0.113, 0.200, 0.312, 0.450, 0.613, 0.800, 1.000, 1.000, 1.000, 1.000},
{0.000, 0.000, 0.000, 0.000, 0.000, 0.012, 0.050, 0.113, 0.200, 0.312, 0.450, 0.613, 0.800, 1.000, 1.000, 1.000},
{0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.012, 0.050, 0.113, 0.200, 0.312, 0.450, 0.613, 0.800, 1.000, 1.000},
{0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.012, 0.050, 0.113, 0.200, 0.312, 0.450, 0.613, 0.800, 1.000},
{0.000, 0.025, 0.100, 0.225, 0.400, 0.625, 0.900, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000},
{0.000, 0.050, 0.200, 0.450, 0.800, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000},
{0.000, 0.100, 0.400, 0.900, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000},
{0.000, 0.000, 0.100, 0.400, 0.900, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000},
{0.000, 0.000, 0.000, 0.100, 0.400, 0.900, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000},
{0.000, 0.000, 0.000, 0.000, 0.100, 0.400, 0.900, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000},
{0.000, 0.000, 0.000, 0.000, 0.000, 0.100, 0.400, 0.900, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000},
{0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.100, 0.400, 0.900, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000},
{0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.100, 0.400, 0.900, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000},
{0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.100, 0.400, 0.900, 1.000, 1.000, 1.000, 1.000, 1.000},
{0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.100, 0.400, 0.900, 1.000, 1.000, 1.000, 1.000},
{0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.100, 0.400, 0.900, 1.000, 1.000, 1.000},
{0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.100, 0.400, 0.900, 1.000, 1.000},
{0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.100, 0.400, 0.900, 1.000}
};
QPredictor::QPredictor(){
for(int i=0;i<MemorySize;i++){
output[i]=0.0f;
input[i]=0.0f;
}
state = 0;
PrevState = 0;
}
float QPredictor::Process(float linePosition,float currentBaseSpeed){
for(int i=1;i<DataVectorLength;i++){
input[i] = input[i-1];
}
input[0] = m_abs(linePosition);
int MinIndex = 0;
float Distance = 10000.0f;
float sum = 0.0f;
for(int i=0;i<MemorySize;i++){
sum = 0.0f;
for(int j=0;j<DataVectorLength;j++){
sum +=m_abs(input[j] - Memory[i][j]);
}
if(sum <= Distance){
MinIndex = i;
Distance = sum;
}
}
sum = 0.0f;
for(int i=0;i<DataVectorLength;i++){
sum += input[i];
}
float eta = 0.95f;
output[MinIndex] = eta * output[MinIndex] + (1 - eta) * sum;
return -m_sgn(linePosition) * output[MinIndex];
}
float QPredictor::rewardFunction(float *inputData,float currentBaseSpeed){
float sum = 0.0f;
for(int i=0;i<DataVectorLength;i++){
sum += inputData[i];
}
sum /= DataVectorLength;
return sum;
}
Ich habe jetzt nur einen durchschnittlichen Fehler und verwende derzeit kein Lernen, da es ohne Belohnungsfunktion nicht vollständig ist. Wie kann ich es an die Abmessungen meines Roboters anpassen?
quelle
Antworten:
Die adaptive PID-Regelung basiert auf einem manuell codierten Algorithmus für die Zeilenverfolgung, der durch Verstärkungslernen modifiziert wird. Die Idee ist, dass in der PID-Funktion ein Parameter unbekannt ist (z. B. der Abstand von der Linie, der als Abweichung toleriert werden kann) und dieser Parameter während der Fahrt des Roboters im laufenden Betrieb berechnet wird. Die Belohnungen werden manuell von einem Bediener- Clicker-Training vergeben oder können in einer Schleife ermittelt werden. Der Roboter fährt einen Parcurs, die Zeit wird gemessen. Der Roboter fährt die Parcurs erneut und das Ziel ist es, die Zeit zu verkürzen.
quelle
Ich denke, Q-Learning ist ein Overkill für ein so einfaches Tracking-Problem. Ich empfehle Ihnen dringend, eine einfachere Methode zu verwenden, nämlich einen reinen Verfolgungs-Tracking-Controller. Hier sind einige Links, die Sie über die Methode lesen können. Matlabs Seite zu diesem Thema ist ziemlich ordentlich.
Matlabs Pure Pursuit Controller
Implementierung des Pure Pursuit Path Tracking-Algorithmus
quelle