-
Notifications
You must be signed in to change notification settings - Fork 0
/
car.go
242 lines (205 loc) · 6.63 KB
/
car.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
package car
import (
// "fmt"
"math"
glm "github.com/Jragonmiris/mathgl"
)
const (
Gravity = 9.8
)
type Profile struct {
Mass float64 //Kg
Engine EngineProfile
Drag float64
RollingResistance float64
BreakingPower float64 //N
CenterOfGravityHeight float64 //m
RearAxelDisplacement float64 //m
FrontAxelDisplacement float64 //m
TyreFrictionMu float64
TyreTractionConstant float64
GearRatio float64
DifferentialRatio float64
TransmissionEfficiency float64
WheelRadius float64
WheelMass float64
MaxStreeringAngle float64
}
type Car struct {
Profile Profile
Center glm.Vec4d
Velocity glm.Vec4d
Direction glm.Vec4d
RearWheelAngularVelocity float64
RearWheelAngularDeviation float64
FrontWheelAngularDeviation float64
FrontWheelO float64
//Transient properties for numerical integration
TransientAcceleration glm.Vec4d
}
type Controls struct {
FuelPedal float64
BreakPedal float64
WheelAngularVelocity float64
}
type EngineProfile interface {
Torque(rpm float64) float64
StallingRPM() float64
}
type SimpleEngine struct {
torque float64
stallingRPM float64
}
func (engine *SimpleEngine) Torque(rpm float64) float64 {
return engine.torque
}
func (engine *SimpleEngine) StallingRPM() float64 {
return engine.stallingRPM
}
func NewCar() Car {
return Car {
Profile {
1500, //Mass Kg
&SimpleEngine{448, 1000}, //Engine N, rpm
0.4257, //Drag
12.8, //rolling friction
10000, //breaking power N
1, //center of gravity height m
3, //rear axel
3, //front axel
10000, //type friction mu
1, //tyre traction constant
2.66, //gear ratio
3.42, //diff ratio
0.7, //efficiency
1,//0.34, //wheel radius
150, //whell mass
45 * math.Pi / 180, //max turning angle
// Mass float64 //Kg
// Engine EngineProfile
// Drag float64
// RollingResistance float64
// BreakingPower float64 //N
//
// CenterOfGravityHeight float64 //m
// RearAxelDisplacement float64 //m
// FrontAxelDisplacement float64 //m
// TyreFrictionMu float64
// TyreTractionConstant float64
//
// GearRatio float64
// DifferentialRatio float64
// TransmissionEfficiency float64
// WheelRadius float64
// WheelMass float64
},
glm.Vec4d{0,0,1,1},
glm.Vec4d{0,0,0,0},
glm.Vec4d{0,1,0,0},
0,
0,
0,
0,
glm.Vec4d{0,0,0,0},
}
}
func IsZero(v glm.Vec4d) bool {
return v.ApproxEqual(glm.Vec4d{})
}
func (car *Car) Simulate(controls Controls, timestep float64) {
p := car.Center
v := car.Velocity
u := car.Direction
at := car.TransientAcceleration
rwav := car.RearWheelAngularVelocity
m := car.Profile.Mass
d := car.Profile.Drag
rr := car.Profile.RollingResistance
h := car.Profile.CenterOfGravityHeight
fl := car.Profile.FrontAxelDisplacement
rl := car.Profile.RearAxelDisplacement
xg := car.Profile.GearRatio
xd := car.Profile.DifferentialRatio
te := car.Profile.TransmissionEfficiency
wr := car.Profile.WheelRadius
wm := car.Profile.WheelMass
bmax := car.Profile.BreakingPower
bmaxToruqe := bmax / wr
mu := car.Profile.TyreFrictionMu
tc := car.Profile.TyreTractionConstant
g := Gravity
dt := timestep
vmag := v.Len()
staticWeight := g * m
axelDisplacement := fl + rl
// maxFrontTyreTraction := rl / axelDisplacement * weight - (h-wr)/axelLength * m * at.Dot(u)
dynamicWeight := (h-wr) / axelDisplacement * m * at.Dot(u)
weight := fl / axelDisplacement * staticWeight + dynamicWeight
maxRearTyreTraction := mu * weight
freeRollingAV := v.Dot(u) / wr
rwav = freeRollingAV
slipRatio := 0.0
if !IsZero(v) {
slipRatio = (rwav * wr - v.Dot(u)) / vmag
}
// else {
// // slipRatio = rwav * wr //-rwav * wr
// }
tractionForce := math.Min(tc * slipRatio, maxRearTyreTraction)
tractionTorque := tractionForce * wr
// fmt.Println("tyre traction force", tractionForce)
vn := glm.Vec4d{}
if !IsZero(v) {
vn = v.Normalize()
}
brakeTorque := bmaxToruqe * vn.Dot(u) * controls.BreakPedal
rpm := freeRollingAV * xg * xd * 60 / (2 * math.Pi)
engineTorque := car.Profile.Engine.Torque(rpm)
appliedTorque := engineTorque * controls.FuelPedal
driveTorque := appliedTorque * xg * xd * te
driveForce := driveTorque / wr
totalTorque := driveTorque - 2 * tractionTorque - brakeTorque
// fmt.Println("wrav", rwav)
// fmt.Println("driveTorque", driveTorque)
// fmt.Println("tractionTorque", tractionTorque)
// fmt.Println("brakeTorque", brakeTorque)
// fmt.Println("totalTorque", totalTorque)
b := bmax * controls.BreakPedal
rearForceTraction := math.Copysign(math.Min(math.Abs(driveForce), maxRearTyreTraction), driveForce)
forceTraction := u.Mul(rearForceTraction)
forceBreaking := u.Mul(-b * vn.Dot(u))
forceDrag := v.Mul(-d * vmag)
forceRollingResistance := v.Mul(-rr)
force := forceTraction.Add(forceDrag).Add(forceRollingResistance).Add(forceBreaking)
rearWheelInertia := wm * wr * wr / 2
wheelAcceleration := totalTorque / rearWheelInertia
drwav := wheelAcceleration * dt
a := force.Mul(1.0/m)
dv := a.Mul(dt)
dp := v.Mul(dt).Add(a.Mul(dt*dt*0.5))
if v.Len() < forceBreaking.Len()*dt/m {
dv = v.Mul(-1)
}
// fmt.Println(rwav, dv)
p = p.Add(dp)
v = v.Add(dv)
rwav = rwav + drwav
rwav = v.Dot(u) / wr
car.FrontWheelO = car.FrontWheelO + controls.WheelAngularVelocity * dt
car.FrontWheelO = math.Copysign(math.Min(math.Abs(car.FrontWheelO), car.Profile.MaxStreeringAngle), car.FrontWheelO)
if math.Abs(car.FrontWheelO) > 0.0001 {
turningRadius := axelDisplacement / math.Sin(car.FrontWheelO)
angularVelocity := v.Dot(u) / turningRadius
rotation := dt * angularVelocity
m := glm.HomogRotate3DZd(-rotation * 180 / math.Pi)
u = m.Mul4x1(u)
v = m.Mul4x1(v)
}
car.Center = p
car.Velocity = v
car.TransientAcceleration = a
car.RearWheelAngularVelocity = rwav
car.Direction = u
car.FrontWheelAngularDeviation += freeRollingAV * dt
car.RearWheelAngularDeviation += car.RearWheelAngularVelocity * dt
}