[BlitzMax] Lenkachsensteuerung

Übersicht Sonstiges Projekte

Neue Antwort erstellen

 

CO2

ehemals "SirMO"

Betreff: [BlitzMax] Lenkachsensteuerung

BeitragFr, Jul 04, 2014 23:54
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo,

ich möchte ein kleineres Projekt von mir vorstellen, was aus Interesse und zum vertiefen der Kenntnisse im Bereich Trigonometrie entstanden ist.
Es handelt sich um eine Lenkachsensteuerung bei Fahrzeugen. Sie berechnet die optimalen Winkel aller lenkbaren Räder aller Achsen eines Fahrzeugs um den Gummiabrieb verschwindent gering zu halten.
Um ein Fahrzeug zu definieren stehen dem Benutzer zwei Arten von Achsen zur Verfügung: Zum einen können starre Achsen und zum anderen lenkbare Achsen definiert werden. Die lenkbaren Achsen teilen sich auf in eine "Steuerachse" und beliebig viele "normale" lenkbare Achsen. Mit der Steuerachse kann der Winkel der Kurve eingestellt werden, die anderen Achsen passen sich an diesen Winkel an.

Wie funktioniert's?
- Voraussetzung ist, dass das Fahrzeug mit einer Achsschenkellenkung ausgestattet ist (Also bspw. keine Drehschemel-Lenkung besitzt, bei der die Achse im Gesamten gedreht wird)
- Nachdem der Benutzer ein beliebig vielachsiges Fahrzeug definiert hat, wird im ersten Schritt die "Kurvenlinie" berechnet (Diese muss aus Performancegründen nur einmal berechnet werden, vorausgesetzt, die Anzahl der Achsen ändert sich danach nicht mehr). Die Kurvenlinie ist die Drehachse des Fahrzeugs und muss in drei Fällen anders berechnet werden:
1.) Das Fahrzeug besitzt eine starre Achse und beliebig viele lenkbare Achsen: Hier liegt die Kurvenlinie auf Höhe der starren Achse und verläuft in Achsrichtung.
2.) Das Fahrzeug besitzt beliebig viele starre Achsen und beliebig viele lenkbare Achsen: Hier muss zunächst die vorderste starre Achse und die hinterste Starre Achse ermittelt werden. Die Kurvenlinie liegt nun genau in der Mitte dieser beiden Achsen.
3.) Das Fahrzeug besitzt keine starre Achse und beliebig viele lenkbare Achsen: Hier muss zunächst die vorderste lenkbare Achse und die hinterste lenkbare Achse ermittelt werden. Die Kurvenlinie liegt nun genau in der Mitte dieser beiden Achsen.
- Nachdem die Kurvenachse berechnet wurde, kann nun ein bestimmter Kurvenwinkel angegeben werden. Von der Steuerachse ausgehend wird dann der Schnittpunkt mit der Kurvenlinie ermittelt. Alle lenkbaren Räder des Fahrzeugs werden dann auf diesen Schnittpunkt ausgerichtet.

Screenshots?
Legende:
- horizontale weiße Linien: Achsen
- vertikale / gedrehte weiße Linien: Räder (und deren Stellung)
- grünes Quadrat auf Achse: lenkbare Achse
- blauer Kreis auf Achse: starre Achse
- roter Kreis auf grünem Quadrat auf Achse: Steuerachse (lenkbare Achse)
- violette horizontale Linie: Kurvenlinie
- gelber Punkt auf Kurvenlinie: Schnittpunkt mit dieser
- türkise Linie: Hypotenuse des zur Berechnung des Schnittpunkts mit der Kurvenlinie erstellten Dreiecks
- gelbe Linie: Hypotenuse des Dreiecks, das vom Radmittelpunkt mit dem ausgerechneten Winkel des betroffenen Rades aufgespannt werden kann.

- Fall 1:
user posted image
user posted image
- Fall 2:
user posted image
user posted image
- Fall 3:
user posted image
user posted image

- Nachwort?
Vielleicht kann es einer verwenden (ich kann mir nichts wichtigeres in einem Spiel vorstellen, als die korrekten Winkel der Räder zum Kurvenmittelpunkt zu berechnen Wink). Spaß beiseite: Falls es jemand benötigt, um physikalische Dinge zu simulieren, oder einfach mal zum rumprobieren, der kann es gerne verwenden.

- Download?
Da es zu wenig ist, um dafür extra ein RAR-Archiv zu erstellen, etc. hier einfach der Quellcode: BlitzMax: [AUSKLAPPEN]
Rem
Autor: Marius Otto
Datum: 03.07.2014
Beschr.: Eine Lenkachsensteuerung, die die optimalen Winkel der Räder eines Fahrzeugs wärend der Kurvenfahrt errechnet.
End Rem


' ### EINSTELLUNGEN ###
Const WHEEL_SIZE:Float = 50 ' Die Größe eines Reifens in Pixeln
Const DRAWING_BENCHMARK:Float = 50 ' Maßstab: Wie viele Pixel entsprechen 100cm?
Const DRAWING_COLORINTENSITY:Int = 255 ' Die Farbstärke der Markierungen für die Zeichnung
Const DRAWING_DRAWCURVELINE:Byte = True ' Die "Kurvenlinie" auch mit zeichnen?
Const DRAWING_DRAWANGLELINES:Byte = True ' Die Winkellinien aller Räder mit zeichen?

' ### KONSTANTEN (NICHT VERÄNDERN!) ###
Const SYS_LEFTWHEEL:Int = 0
Const SYS_RIGHTWHEEL:Int = 1

' ### HAUPTCODE ###
Type TWheel
Field PosX:Float
Field PosY:Float
Field Size:Float
Field Angle:Float

Function CreateWheel:TWheel(PosX:Float, PosY:Float, Size:Float, Angle:Float)
Local ReturnMe:TWheel = New TWheel
ReturnMe.PosX = PosX
ReturnMe.PosY = PosY
ReturnMe.Size = Size
ReturnMe.Angle = Angle
Return ReturnMe
End Function

Method SetRot(NewRot:Float)
Self.Angle = NewRot
End Method

Method Draw()
Local PrevRot:Float = GetRotation()
SetRotation(Self.Angle)
DrawLine(Self.PosX, Self.PosY, Self.PosX, (Self.PosY - (Self.Size / 2)))
DrawLine(Self.PosX, Self.PosY, Self.PosX, (Self.PosY + (Self.Size / 2)))
SetRotation(PrevRot)
End Method
End Type

Type TAxle
Field PosX:Float
Field PosY:Float
Field TrackWidth:Float
Field Wheels:TWheel[2]
Field IsCtrl:Byte

Method CreateAxle(PosX:Float, PosY:Float, TrackWidth:Float)
Self.PosX = PosX
Self.PosY = PosY
Self.TrackWidth = TrackWidth
End Method

Method Draw() Abstract
Method SetWheelRot(WheelIndex:Int, Rot:Float) Abstract
Method IsSteeringAxle:Byte() Abstract
Method GetMaxWheelRot:Int() Abstract
Method GetMinWheelRot:Int() Abstract
Method DebugOnScreen(PosX:Int, PosY:Int) Abstract
End Type

Type TSteeringAxle Extends TAxle
Field SteerMax:Float

Function CreateSteeringAxle:TSteeringAxle(PosX:Float, PosY:Float, TrackWidth:Float, SteerMax:Float, IsCtrl:Byte = False)
Local ReturnMe:TSteeringAxle = New TSteeringAxle
ReturnMe.CreateAxle(PosX / (100 / DRAWING_BENCHMARK), PosY / (100 / DRAWING_BENCHMARK), TrackWidth / (100 / DRAWING_BENCHMARK))
ReturnMe.SteerMax = SteerMax
ReturnMe.IsCtrl = IsCtrl

ReturnMe.Wheels[SYS_LEFTWHEEL] = TWheel.CreateWheel((ReturnMe.PosX - (ReturnMe.TrackWidth / 2)), ReturnMe.PosY, WHEEL_SIZE / (100 / DRAWING_BENCHMARK), 0)
ReturnMe.Wheels[SYS_RIGHTWHEEL] = TWheel.CreateWheel((ReturnMe.PosX + (ReturnMe.TrackWidth / 2)), ReturnMe.PosY, WHEEL_SIZE / (100 / DRAWING_BENCHMARK), 0)

Return ReturnMe
End Function

Method Draw()
DrawLine(Self.PosX, Self.PosY, (Self.PosX - (Self.TrackWidth / 2)), Self.PosY)
DrawLine(Self.PosX, Self.PosY, (Self.PosX + (Self.TrackWidth / 2)), Self.PosY)
SetColor(0, DRAWING_COLORINTENSITY, 0)
DrawRect((Self.PosX - 5), (Self.PosY - 5), 10, 10)
If(Self.IsCtrl = True)
SetColor(DRAWING_COLORINTENSITY, 0, 0)
DrawOval((Self.PosX - 5), (Self.PosY - 5), 10, 10)
EndIf
SetColor(255, 255, 255)
If(Self.Wheels[SYS_LEFTWHEEL] <> Null) Then Self.Wheels[SYS_LEFTWHEEL].Draw()
If(Self.Wheels[SYS_RIGHTWHEEL] <> Null) Then Self.Wheels[SYS_RIGHTWHEEL].Draw()
End Method

Method SetWheelRot(WheelIndex:Int, Rot:Float)
If(WheelIndex <> 0 And WheelIndex <> 1) Then Return
Self.Wheels[WheelIndex].SetRot(Rot)
End Method

Method DebugOnScreen(PosX:Int, PosY:Int)
DrawText("Steering Axle: PosY: " + Self.PosY + "; LeftWheelRot: " + Self.Wheels[SYS_LEFTWHEEL].Angle + " Deg; RightWheelRot: " + Self.Wheels[SYS_RIGHTWHEEL].Angle + " Deg", PosX, PosY)
End Method

Method GetMaxWheelRot:Int()
Return Self.SteerMax
End Method

Method GetMinWheelRot:Int()
Return -Self.SteerMax
End Method

Method IsSteeringAxle:Byte()
Return True
End Method
End Type

Type TBeamAxle Extends TAxle
Function CreateBeamAxle:TBeamAxle(PosX:Float, PosY:Float, TrackWidth:Float)
Local ReturnMe:TBeamAxle = New TBeamAxle
ReturnMe.CreateAxle(PosX / (100 / DRAWING_BENCHMARK), PosY / (100 / DRAWING_BENCHMARK), TrackWidth / (100 / DRAWING_BENCHMARK))

ReturnMe.Wheels[SYS_LEFTWHEEL] = TWheel.CreateWheel((ReturnMe.PosX - (ReturnMe.TrackWidth / 2)), ReturnMe.PosY, WHEEL_SIZE / (100 / DRAWING_BENCHMARK), 0)
ReturnMe.Wheels[SYS_RIGHTWHEEL] = TWheel.CreateWheel((ReturnMe.PosX + (ReturnMe.TrackWidth / 2)), ReturnMe.PosY, WHEEL_SIZE / (100 / DRAWING_BENCHMARK), 0)

ReturnMe.IsCtrl = False

Return ReturnMe
End Function

Method Draw()
DrawLine(Self.PosX, Self.PosY, (Self.PosX - (Self.TrackWidth / 2)), Self.PosY)
DrawLine(Self.PosX, Self.PosY, (Self.PosX + (Self.TrackWidth / 2)), Self.PosY)
SetColor(0, 0, DRAWING_COLORINTENSITY)
DrawOval((Self.PosX - 5), (Self.PosY - 5), 10, 10)
SetColor(255, 255, 255)
If(Self.Wheels[SYS_LEFTWHEEL] <> Null) Then Self.Wheels[SYS_LEFTWHEEL].Draw()
If(Self.Wheels[SYS_RIGHTWHEEL] <> Null) Then Self.Wheels[SYS_RIGHTWHEEL].Draw()
End Method

Method SetWheelRot(WheelIndex:Int, Rot:Float)
End Method

Method GetMaxWheelRot:Int()
Return 0
End Method

Method GetMinWheelRot:Int()
Return 0
End Method

Method IsSteeringAxle:Byte()
Return False
End Method

Method DebugOnScreen(PosX:Int, PosY:Int)
DrawText("Beam Axle: PosY: " + Self.PosY, PosX, PosY)
End Method
End Type

Type TLASModel
Field Axles:TList
Field CurveLine:Float = 0

Function CreateTLASM:TLASModel()
Local ReturnMe:TLASModel = New TLASModel
ReturnMe.Axles = CreateList()
Return ReturnMe
End Function

Method AddAxle(Axle:TAxle)
If(Axle <> Null)
ListAddLast(Self.Axles, Axle)
EndIf
End Method

Method Draw()
If(DRAWING_DRAWCURVELINE = True)
SetColor(DRAWING_COLORINTENSITY, 0, DRAWING_COLORINTENSITY)
DrawLine(-GraphicsWidth(), Self.CurveLine, GraphicsWidth(), Self.CurveLine)
SetColor(255, 255, 255)
EndIf
For Local x:TAxle = EachIn Self.Axles
x.Draw()
Next
End Method

Method CalculateCurveLine()
Local BeamAxleFound:Byte = False
For Local BeamAxleSearch:TAxle = EachIn Self.Axles
If(BeamAxleSearch.IsSteeringAxle() = False)
BeamAxleFound = True
EndIf
Next
Local MinAxle:TAxle = Null
For Local TempAxle:TAxle = EachIn Self.Axles
If(BeamAxleFound = True)
If(TempAxle.IsSteeringAxle() = False)
If(MinAxle = Null)
MinAxle = TempAxle
Continue
EndIf
If(TempAxle.PosY <= MinAxle.PosY)
MinAxle = TempAxle
EndIf
EndIf
Else
If(MinAxle = Null)
MinAxle = TempAxle
Continue
EndIf
If(TempAxle.PosY <= MinAxle.PosY)
MinAxle = TempAxle
EndIf
EndIf
Next
Local MaxAxle:TAxle = Null
For TempAxle = EachIn Self.Axles
If(BeamAxleFound = True)
If(TempAxle.IsSteeringAxle() = False)
If(MaxAxle = Null)
MaxAxle = TempAxle
Continue
EndIf
If(TempAxle.PosY >= MaxAxle.PosY)
MaxAxle = TempAxle
EndIf
EndIf
Else
If(MaxAxle = Null)
MaxAxle = TempAxle
Continue
EndIf
If(TempAxle.PosY >= MaxAxle.PosY)
MaxAxle = TempAxle
EndIf
EndIf
Next
If(MinAxle <> Null And MaxAxle <> Null)
Self.CurveLine = (MaxAxle.PosY + MinAxle.PosY) / 2
EndIf
End Method

Method SetSteeringRot(Angle:Float)
For Local CtrlAxle:TAxle = EachIn Self.Axles
If(CtrlAxle.IsSteeringAxle() = True)
If(CtrlAxle.IsCtrl = True)
Exit
EndIf
Else
CtrlAxle = Null
EndIf
Next
If(CtrlAxle <> Null)
Local Length:Float = Abs(Self.CurveLine) + Abs(CtrlAxle.PosY)
Local intercept:Float = (Length / Tan(Angle)) - CtrlAxle.PosX
If(DRAWING_DRAWANGLELINES = True)
SetColor(0, DRAWING_COLORINTENSITY, DRAWING_COLORINTENSITY)
DrawLine(CtrlAxle.PosX, CtrlAxle.PosY, intercept, Self.CurveLine)
SetColor(255, 255, 255)

SetColor(DRAWING_COLORINTENSITY, DRAWING_COLORINTENSITY, 0)
DrawOval((intercept - 5), (Self.CurveLine - 5), 10, 10)
SetColor(255, 255, 255)
EndIf
For Local TempAxle:TAxle = EachIn Self.Axles
If(TempAxle.IsSteeringAxle() = True)
Local WheelAngle:Float
Local Distance:Float
Local TempLength:Float
If(TempAxle.PosY > Self.CurveLine)
TempLength = TempAxle.PosY - Self.CurveLine
Else
TempLength = Self.CurveLine - TempAxle.PosY
EndIf
Distance = (intercept - (TempAxle.TrackWidth / 2)) - TempAxle.PosX
WheelAngle = ATan(TempLength / Distance)
If(TempAxle.PosY < Self.CurveLine)
TempAxle.Wheels[SYS_RIGHTWHEEL].SetRot(WheelAngle)
Else
TempAxle.Wheels[SYS_RIGHTWHEEL].SetRot(-WheelAngle)
EndIf
If(DRAWING_DRAWANGLELINES = True)
SetColor(DRAWING_COLORINTENSITY, DRAWING_COLORINTENSITY, 0)
DrawLine(TempAxle.PosX + (TempAxle.TrackWidth / 2), TempAxle.PosY, intercept, Self.CurveLine)
EndIf
Distance = (intercept + (TempAxle.TrackWidth / 2)) - TempAxle.PosX
WheelAngle = ATan(TempLength / Distance)
If(TempAxle.PosY < Self.CurveLine)
TempAxle.Wheels[SYS_LEFTWHEEL].SetRot(WheelAngle)
Else
TempAxle.Wheels[SYS_LEFTWHEEL].SetRot(-WheelAngle)
EndIf
If(DRAWING_DRAWANGLELINES = True)
SetColor(DRAWING_COLORINTENSITY, DRAWING_COLORINTENSITY, 0)
DrawLine((TempAxle.PosX - TempAxle.TrackWidth / 2), TempAxle.PosY, intercept, Self.CurveLine)
EndIf
EndIf
Next
EndIf
End Method

Method DebugOnScreen(PosX:Int, PosY:Int)
Local MomPosY:Int = PosY
For Local TempAxle:TAxle = EachIn Self.Axles
TempAxle.DebugOnScreen(PosX, MomPosY)
MomPosY = MomPosY + 20
Next
End Method
End Type


- Codebeispiele?
Hier mal der Code, mit dem die oben gezeigten Screenshots erstellt wurden:
BlitzMax: [AUSKLAPPEN]
Graphics(1600, 900, 32, 60)

Global FPS:TTimer = CreateTimer(60)

Global TestModel:TLASModel = TLASModel.CreateTLASM()
' Passendes auskommentieren:
' Modell 1: Eine starre Achse, mehrere lenkbare Achsen:
Rem
TestModel.AddAxle(TSteeringAxle.CreateSteeringAxle(-200, 150, 45, True))
TestModel.AddAxle(TSteeringAxle.CreateSteeringAxle(-100, 150, 45, False))
TestModel.AddAxle(TBeamAxle.CreateBeamAxle(100, 150))
End Rem


' Modell 2: Mehrere starre Achsen, mehrere lenkbare Achsen:
Rem
TestModel.AddAxle(TSteeringAxle.CreateSteeringAxle(-200, 150, 45, True))
TestModel.AddAxle(TSteeringAxle.CreateSteeringAxle(-100, 150, 45, False))
TestModel.AddAxle(TBeamAxle.CreateBeamAxle(0, 150))
TestModel.AddAxle(TBeamAxle.CreateBeamAxle(100, 150))
End Rem


' Modell 3: keine starre Achse, mehrere lenkbare Achsen:
Rem
TestModel.AddAxle(TSteeringAxle.CreateSteeringAxle(-200, 150, 45, True))
TestModel.AddAxle(TSteeringAxle.CreateSteeringAxle(-100, 150, 45, False))
TestModel.AddAxle(TSteeringAxle.CreateSteeringAxle(100, 150, 45, True))
TestModel.AddAxle(TSteeringAxle.CreateSteeringAxle(200, 150, 45, False))
End Rem


TestModel.CalculateCurveLine() ' Einmalige Berechnung der Kurvenlinie

SetOrigin((GraphicsWidth() / 2), (GraphicsHeight() / 2)) ' Ursprung auf die Mitte des Bildschirms setzen

Global MomDeg:Float = -45
Global DirectionRight:Byte = False

Repeat
WaitTimer(FPS)
Cls

TestModel.SetSteeringRot(MomDeg)

If(DirectionRight = False)
MomDeg = MomDeg + 0.25
Else
MomDeg = MomDeg - 0.25
EndIf

If(MomDeg > 45 Or MomDeg < -45)
DirectionRight = Not DirectionRight
EndIf

TestModel.Draw()

TestModel.DebugOnScreen(-800, -430)

DrawText("Deg: " + MomDeg, -800, -450)

Flip 0
Until KeyHit(KEY_ESCAPE)
End


Joa, ich glaube das wär's...

EDIT:
-> Kleinen Bug im Code behoben, der u.U. den Winkel einiger Räder falsch berechnete
-> Möglichkeit geschaffen, die Achsen auch auf horizontaler Ebene zu verschieben.
mfG, CO²

Sprachen: BlitzMax, C, C++, C#, Java
Hardware: Windows 7 Ultimate 64-Bit, AMX FX-6350 (6x3,9 GHz), 32 GB RAM, Nvidia GeForce GTX 750 Ti

Tornado11

BeitragSa, Jul 05, 2014 18:01
Antworten mit Zitat
Benutzer-Profile anzeigen
Was passiert denn wenn man geradeaus fährt?
 

CO2

ehemals "SirMO"

BeitragSa, Jul 05, 2014 18:28
Antworten mit Zitat
Benutzer-Profile anzeigen
Dann werden alle lenkbaren Achsen in Fahrtrichtung gelenkt.

user posted image
mfG, CO²

Sprachen: BlitzMax, C, C++, C#, Java
Hardware: Windows 7 Ultimate 64-Bit, AMX FX-6350 (6x3,9 GHz), 32 GB RAM, Nvidia GeForce GTX 750 Ti

Neue Antwort erstellen


Übersicht Sonstiges Projekte

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group