Sprache Deutsch Language English

Script Dokumentation LS 2015 - VehicleMotor (Patch 1.3)

Script Dokumentation Übersicht

scripts/vehicles/VehicleMotor.lua

Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de
1--
2-- VehicleMotor
3--
4-- @author Stefan Geiger
5-- @date 08/03/08
6--
7-- Copyright (C) GIANTS Software GmbH, Confidential, All Rights Reserved.
8
9VehicleMotor = {};
10
11VehicleMotor_mt = Class(VehicleMotor);
12
13function VehicleMotor:new(vehicle, minRpm, maxRpm, maxForwardSpeed, maxBackwardSpeed, torqueCurve, brakeForce, forwardGearRatio, backwardGearRatio, minForwardGearRatio, maxForwardGearRatio, minBackwardGearRatio, maxBackwardGearRatio, ptoMotorRpmRatio, rpmFadeOutRange, maxTorque)
14
15 local self = {};
16 setmetatable(self, VehicleMotor_mt);
17
18 self.vehicle = vehicle;
19 self.minRpm = minRpm;
20 self.maxRpm = maxRpm;
21 self.maxForwardSpeed = maxForwardSpeed; -- speed in m/s
22 self.maxBackwardSpeed = maxBackwardSpeed;
23
24 self.maxClutchTorque = 5; -- amount of torque that can be transferred from motor to clutch/wheels [t m s^-2]
25
26 self.torqueCurve = torqueCurve;
27 self.brakeForce = brakeForce;
28
29 self.gear = 0;
30 self.gearRatio = 0;
31
32 self.forwardGearRatios = {forwardGearRatio};
33 self.backwardGearRatios = {backwardGearRatio};
34 self.minForwardGearRatio = minForwardGearRatio;
35 self.maxForwardGearRatio = maxForwardGearRatio;
36 self.minBackwardGearRatio = minBackwardGearRatio;
37 self.maxBackwardGearRatio = maxBackwardGearRatio;
38
39 self.lastMotorRpm = 0;
40
41 self.rpmFadeOutRange = rpmFadeOutRange;
42 self.rpmLimit = math.huge;
43 self.speedLimit = math.huge; -- Speed limit in km/h
44 self.speedLimitAcc = math.huge;
45
46 -- this is not clamped by minRpm
47 self.nonClampedMotorRpm = 0;
48 self.clutchRpm = 0;
49 self.motorLoad = 0;
50 self.requiredWheelTorque = 0;
51
52 if self.maxForwardSpeed == nil then
53 self.maxForwardSpeed = self:calculatePhysicalMaximumForwardSpeed();
54 end
55 if self.maxBackwardSpeed == nil then
56 self.maxBackwardSpeed = self:calculatePhysicalMaximumBackwardSpeed();
57 end
58
59 self.maxMotorTorque = self.torqueCurve:getMaximum();
60
61 self.ptoMotorRpmRatio = ptoMotorRpmRatio;
62
63 self.maxTorque = maxTorque;
64
65 return self;
66end;
67
68function VehicleMotor:setLowBrakeForce(lowBrakeForceScale, lowBrakeForceSpeedLimit)
69 self.lowBrakeForceScale = lowBrakeForceScale;
70 self.lowBrakeForceSpeedLimit = lowBrakeForceSpeedLimit;
71end;
72
73function VehicleMotor:getTorque(acceleration, limitRpm)
74 -- Note: the torque curve is undefined outside the min/max rpm range. Clamping makes the curve flat at the outside range
75 local torque = self.torqueCurve:get(Utils.clamp(self.nonClampedMotorRpm, self.minRpm, self.maxRpm));
76 local brakePedal = 0;
77
78 if limitRpm then
79 local maxRpm = self:getCurMaxRpm();
80
81 local rpmFadeOutRange = self.rpmFadeOutRange*self:getGearRatio();
82
83 local fadeStartRpm = maxRpm - rpmFadeOutRange;
84 if self.nonClampedMotorRpm > fadeStartRpm then
85 if self.nonClampedMotorRpm > maxRpm then
86 brakePedal = math.min((self.nonClampedMotorRpm-maxRpm)/rpmFadeOutRange, 1);
87 torque = 0;
88 else
89 torque = torque * math.max((fadeStartRpm-self.nonClampedMotorRpm)/rpmFadeOutRange, 0);
90 end;
91 end;
92 end
93 torque = torque * math.abs(acceleration);
94
95 local neededPtoTorque = PowerConsumer.getTotalConsumedPtoTorque(self.vehicle);
96 if neededPtoTorque > 0 then
97 torque = math.max(torque - neededPtoTorque/self.ptoMotorRpmRatio, torque*0.1);
98 end
99
100 return torque, brakePedal;
101end;
102
103function VehicleMotor:getMaximumForwardSpeed()
104 return self.maxForwardSpeed;
105end
106
107function VehicleMotor:getMaximumBackwardSpeed()
108 return self.maxBackwardSpeed;
109end
110
111
112function VehicleMotor:calculatePhysicalMaximumForwardSpeed()
113 local minRatio;
114 if self.minForwardGearRatio ~= nil then
115 minRatio = self.minForwardGearRatio
116 else
117 minRatio = math.huge;
118 for _, ratio in pairs(self.forwardGearRatios) do
119 minRatio = math.min(minRatio, ratio);
120 end
121 end
122 return self.maxRpm * math.pi / (30 * minRatio);
123end
124
125function VehicleMotor:calculatePhysicalMaximumBackwardSpeed()
126 local minRatio;
127 if self.minBackwardGearRatio ~= nil then
128 minRatio = self.minBackwardGearRatio
129 else
130 minRatio = math.huge;
131 for _, ratio in pairs(self.backwardGearRatios) do
132 minRatio = math.min(minRatio, ratio);
133 end
134 end
135 return self.maxRpm * math.pi / (30 * minRatio);
136end
137
138function VehicleMotor:updateMotorRpm(dt)
139 local vehicle = self.vehicle;
140 if next(vehicle.differentials) ~= nil and vehicle.motorizedNode ~= nil then
141 self.nonClampedMotorRpm, self.clutchRpm, self.motorLoad = getMotorRotationSpeed(vehicle.motorizedNode)
142 self.nonClampedMotorRpm = self.nonClampedMotorRpm * 30 / math.pi;
143 self.clutchRpm = self.clutchRpm * 30 / math.pi;
144
145 --[[
146 local motorLoad = math.max(self.motorLoad, 0);
147 -- We always require 30% of max torque extra
148
149 local requiredWheelTorque = (motorLoad + 0.3*self.maxMotorTorque) * math.abs(self.gearRatio);
150
151 local requiredWheelTorqueSmoothing = 0.3;
152 if requiredWheelTorque > self.requiredWheelTorque then
153 requiredWheelTorqueSmoothing = 0.05;
154 end
155 requiredWheelTorqueSmoothing = math.pow(requiredWheelTorqueSmoothing, dt*0.001);
156
157 self.requiredWheelTorque = requiredWheelTorque + (self.requiredWheelTorque-requiredWheelTorque)*requiredWheelTorqueSmoothing;
158 ]]--
159
160 self.requiredWheelTorque = self.maxMotorTorque*math.abs(self.gearRatio);
161
162 else
163 local gearRatio = self:getGearRatio();
164 if vehicle.isServer then
165 self.nonClampedMotorRpm = math.max(WheelsUtil.computeRpmFromWheels(vehicle) * gearRatio, 0);
166 else
167 self.nonClampedMotorRpm = math.max(WheelsUtil.computeRpmFromSpeed(vehicle) * gearRatio, 0);
168 end
169 end
170 self.lastMotorRpm = math.max(self.nonClampedMotorRpm, self.minRpm);
171 -- the clamped motor rpm always is higher-equal than the required rpm by the pto
172 --local ptoRpm = math.min(PowerConsumer.getMaxPtoRpm(self.vehicle)*self.ptoMotorRpmRatio, self.maxRpm);
173 -- smoothing for raise/fall of ptoRpm
174 if self.lastPtoRpm == nil then
175 self.lastPtoRpm = self.minRpm;
176 end;
177 local ptoRpm = PowerConsumer.getMaxPtoRpm(self.vehicle)*self.ptoMotorRpmRatio;
178 if ptoRpm > self.lastPtoRpm then
179 self.lastPtoRpm = math.min(ptoRpm, self.lastPtoRpm + self.maxRpm*dt/2000);
180 elseif ptoRpm < self.lastPtoRpm then
181 self.lastPtoRpm = math.max(self.minRpm, self.lastPtoRpm - self.maxRpm*dt/1000);
182 end;
183 local ptoRpm = math.min(self.lastPtoRpm, self.maxRpm);
184 self.lastMotorRpm = math.max(self.lastMotorRpm, ptoRpm);
185end;
186
187-- accSafeMotorRpm: Select gear ratio so that motor RPM will at least accSafeMotorRpm lower than max rpm, so that we are able to accelerate
188function VehicleMotor:getBestGearRatio(wheelSpeedRpm, minRatio, maxRatio, accSafeMotorRpm, requiredWheelTorque, requiredMotorRpm)
189
190 if requiredMotorRpm ~= 0 then
191 local gearRatio = math.max(requiredMotorRpm-accSafeMotorRpm, requiredMotorRpm*0.8) / math.max(wheelSpeedRpm, 0.001);
192 gearRatio = Utils.clamp(gearRatio, minRatio, maxRatio);
193 return gearRatio;
194 end
195
196 local bestWheelTorque = 0;
197 local bestGearRatio = minRatio;
198 -- TODO make this more efficient
199 for gearRatio = minRatio, maxRatio, 0.5 do
200 local rpm = wheelSpeedRpm * gearRatio; -- * (30/math.pi);
201 if rpm > self.maxRpm - accSafeMotorRpm then
202 break;
203 end
204 -- Note: optimizing the wheel torque is the same as optimizing the motor power
205 local wheelTorque = self.torqueCurve:get(rpm) * gearRatio;
206 if wheelTorque > bestWheelTorque then
207 bestWheelTorque = wheelTorque;
208 bestGearRatio = gearRatio;
209 end
210
211 if wheelTorque >= requiredWheelTorque then
212 break;
213 end
214 end
215
216 return bestGearRatio;
217end
218
219function VehicleMotor:getBestGear(acceleration, wheelSpeedRpm, accSafeMotorRpm, requiredWheelTorque, requiredMotorRpm)
220 if acceleration > 0.001 then
221 if self.minForwardGearRatio ~= nil then
222 local wheelSpeedRpm = math.max(wheelSpeedRpm, 0);
223 local bestGearRatio = self:getBestGearRatio(wheelSpeedRpm, self.minForwardGearRatio, self.maxForwardGearRatio, accSafeMotorRpm, requiredWheelTorque/acceleration, requiredMotorRpm);
224 return 1, bestGearRatio;
225 else
226 return 1, self.forwardGearRatios[1];
227 end
228 elseif acceleration < -0.001 then
229 if self.minBackwardGearRatio ~= nil then
230 local wheelSpeedRpm = math.max(-wheelSpeedRpm, 0)
231 local bestGearRatio = self:getBestGearRatio(wheelSpeedRpm, self.minBackwardGearRatio, self.maxBackwardGearRatio, accSafeMotorRpm, requiredWheelTorque/(-acceleration), requiredMotorRpm);
232 return -1, -bestGearRatio;
233 else
234 return -1, -self.backwardGearRatios[1];
235 end
236 else
237 -- unchanged
238 return self.gear, self.gearRatio;
239 end
240end
241
242function VehicleMotor:updateGear(acceleration)
243 local requiredWheelTorque = math.huge;
244 if (acceleration > 0) == (self.gearRatio > 0) then
245 requiredWheelTorque = self.requiredWheelTorque;
246 self.speedLimitAcc = self.maxForwardSpeed * 3.6 * math.abs(acceleration);
247 end
248 local requiredMotorRpm = PowerConsumer.getMaxPtoRpm(self.vehicle)*self.ptoMotorRpmRatio;
249 -- 1) safe rpm for acceleration is 10% of the motor max rpm, so it will take at least 10 frames (=0.16s) until a vehicle has fully accelerated
250 -- 2) replaced lastSpeedReal with clutchRPM/gearRatio => better acceleration when using high values for differentials and steeringAngle is at max/min
251 local wheelSpeedRpm;
252 if math.abs(self.gearRatio) < 0.001 then
253 wheelSpeedRpm = self.vehicle.lastSpeedReal*self.vehicle.movingDirection * 30000/ math.pi;
254 else
255 wheelSpeedRpm = (self.clutchRpm/self.gearRatio); -- * math.pi/30;
256 end
257 self.gear, self.gearRatio = self:getBestGear(acceleration, wheelSpeedRpm, self.maxRpm*0.1, requiredWheelTorque, requiredMotorRpm);
258end
259
260function VehicleMotor:getGearRatio()
261 return self.gearRatio;
262end;
263
264function VehicleMotor:getCurMaxRpm()
265 local maxRpm = self.maxRpm;
266
267 local gearRatio = self:getGearRatio();
268 if gearRatio ~= 0 then
269 --local speedLimit = self.speedLimit * 0.277778;
270 local speedLimit = math.min(self.speedLimit, math.max(self.speedLimitAcc, self.vehicle.lastSpeedReal*3600)) * 0.277778;
271 if gearRatio > 0 then
272 speedLimit = math.min(speedLimit, self.maxForwardSpeed);
273 else
274 speedLimit = math.min(speedLimit, self.maxBackwardSpeed);
275 end
276
277 maxRpm = math.min(maxRpm, speedLimit * 30 / math.pi * math.abs(gearRatio));
278 end
279
280 maxRpm = math.min(maxRpm, self.rpmLimit);
281 return maxRpm;
282end;
283
284function VehicleMotor:setSpeedLimit(limit)
285 self.speedLimit = math.max(limit, 1);
286end
Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de
Script Dokumentation Übersicht