update
This commit is contained in:
@@ -8,13 +8,12 @@ local Vehicle, POWERTRAIN_COMPONENT = unpack(require('/koptilnya/engine_remaster
|
||||
local Differential = require('/koptilnya/engine_remastered/powertrain/differential.txt')
|
||||
|
||||
local WheelConfig = {
|
||||
BrakePower = 800,
|
||||
CustomWheel = {},
|
||||
Model = 'models/sprops/trans/wheel_d/t_wheel25.mdl',
|
||||
RotationAxle = Angle(1, 0, 0)
|
||||
BrakePower = 1200,
|
||||
CustomWheel = { Mass = 80 },
|
||||
Model = 'models/sprops/trans/wheel_d/t_wheel25.mdl'
|
||||
}
|
||||
local FrontWheelsConfig = table.merge(table.copy(WheelConfig), { SteerLock = 35 })
|
||||
local RearWheelsConfig = table.merge(table.copy(WheelConfig), { HandbrakePower = 2000 })
|
||||
local FrontWheelsConfig = table.merge(table.copy(WheelConfig), { SteerLock = 33, CustomWheel = { Mass = 80, CasterAngle = 7 } })
|
||||
local RearWheelsConfig = table.merge(table.copy(WheelConfig), { HandbrakePower = 2200 })
|
||||
|
||||
Vehicle:new({
|
||||
{
|
||||
@@ -58,12 +57,31 @@ Vehicle:new({
|
||||
Reverse = 3.437
|
||||
}
|
||||
},
|
||||
{
|
||||
Name = 'AxleFront',
|
||||
Type = POWERTRAIN_COMPONENT.Differential,
|
||||
Config = {
|
||||
SteerLock = 50
|
||||
}
|
||||
},
|
||||
{
|
||||
Name = 'WheelFL',
|
||||
Type = POWERTRAIN_COMPONENT.Wheel,
|
||||
Input = 'AxleFront',
|
||||
Config = table.merge(table.copy(FrontWheelsConfig), { Offset = 0 })
|
||||
},
|
||||
{
|
||||
Name = 'WheelFR',
|
||||
Type = POWERTRAIN_COMPONENT.Wheel,
|
||||
Input = 'AxleFront',
|
||||
Config = table.merge(table.copy(FrontWheelsConfig), { Offset = 180 })
|
||||
},
|
||||
{
|
||||
Name = 'Axle1',
|
||||
Input = 'Gearbox',
|
||||
Type = POWERTRAIN_COMPONENT.Differential,
|
||||
Config = {
|
||||
Type = Differential.TYPES.HLSD,
|
||||
Type = Differential.TYPES.Open,
|
||||
FinalDrive = 3.392,
|
||||
Inertia = 0.01,
|
||||
BiasAB = 0.5,
|
||||
@@ -73,25 +91,15 @@ Vehicle:new({
|
||||
SlipTorque = 1000
|
||||
}
|
||||
},
|
||||
{
|
||||
Name = 'WheelFL',
|
||||
Input = 'Axle1',
|
||||
Type = POWERTRAIN_COMPONENT.Wheel,
|
||||
Config = table.merge(table.copy(FrontWheelsConfig), { Offset = 0 })
|
||||
},
|
||||
{
|
||||
Name = 'WheelFR',
|
||||
Input = 'Axle1',
|
||||
Type = POWERTRAIN_COMPONENT.Wheel,
|
||||
Config = table.merge(table.copy(FrontWheelsConfig), { Offset = 180 })
|
||||
},
|
||||
{
|
||||
Name = 'WheelRL',
|
||||
Input = 'Axle1',
|
||||
Type = POWERTRAIN_COMPONENT.Wheel,
|
||||
Config = table.merge(table.copy(RearWheelsConfig), { Offset = 0 })
|
||||
},
|
||||
{
|
||||
Name = 'WheelRR',
|
||||
Input = 'Axle1',
|
||||
Type = POWERTRAIN_COMPONENT.Wheel,
|
||||
Config = table.merge(table.copy(RearWheelsConfig), { Offset = 180 })
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
-- @name SX 240
|
||||
-- @author Koptilnya1337
|
||||
-- @server
|
||||
-- @include /koptilnya/engine_remastered/vehicle.txt
|
||||
--@name SX 240
|
||||
--@author Koptilnya1337
|
||||
--@server
|
||||
--@include /koptilnya/engine_remastered/vehicle.txt
|
||||
require('/koptilnya/engine_remastered/vehicle.txt')
|
||||
|
||||
Vehicle:new({
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
--@include /koptilnya/libs/constants.txt
|
||||
--@include ./powertrain_component.txt
|
||||
|
||||
|
||||
local PowertrainComponent = require('./powertrain_component.txt')
|
||||
local WheelComponent = require('./wheel.txt')
|
||||
|
||||
@@ -29,6 +28,9 @@ function Differential:initialize(vehicle, name, config)
|
||||
self.stiffness = config.Stiffness or 0.1
|
||||
self.slipTorque = config.SlipTorque or 1000
|
||||
self.splitStrategy = Differential.getSplitStrategy(config.Type or Differential.TYPES.Open)
|
||||
|
||||
self.steerLock = config.SteerLock or 0
|
||||
self.steerAngle = 0
|
||||
end
|
||||
|
||||
function Differential:linkComponent(component)
|
||||
@@ -107,6 +109,40 @@ function Differential:forwardStep(torque, inertia)
|
||||
tqA = self.outputA:forwardStep(tqA, inertia * 0.5 * math.pow(self.finalDrive, 2) + aI) / self.finalDrive
|
||||
tqB = self.outputB:forwardStep(tqB, inertia * 0.5 * math.pow(self.finalDrive, 2) + bI) / self.finalDrive
|
||||
|
||||
-- // REFACTOR
|
||||
if self.steerLock ~= 0 then
|
||||
local steerInertia = (aI + bI) / 2
|
||||
local inputForce = 228.0
|
||||
local maxSteerSpeed = math.rad(1337)
|
||||
|
||||
local inputTorque = self.vehicle.steer * inputForce
|
||||
|
||||
local avgSteerAngle = (self.outputA.customWheel.steerAngle + self.outputB.customWheel.steerAngle) / 2
|
||||
local mz = self.outputA.customWheel.mz + self.outputB.customWheel.mz
|
||||
local avgMz = (self.outputA.customWheel.mz + self.outputB.customWheel.mz) / 2
|
||||
local maxMz = math.max(self.outputA.customWheel.mz + self.outputB.customWheel.mz)
|
||||
local steerTorque = mz * -1 + inputTorque
|
||||
|
||||
local steerAngularAccel = steerTorque / steerInertia
|
||||
|
||||
self.steerAngle = math.clamp(
|
||||
self.steerAngle + steerAngularAccel * TICK_INTERVAL,
|
||||
-self.steerLock,
|
||||
self.steerLock
|
||||
)
|
||||
|
||||
-- Аккерман
|
||||
local wheelbase = 2.05
|
||||
local trackWidth = 1.124
|
||||
local radius = wheelbase / math.tan(math.rad(self.steerAngle))
|
||||
|
||||
local innerAngle = math.deg(math.atan(wheelbase / (radius - (trackWidth / 2))))
|
||||
local outerAngle = math.deg(math.atan(wheelbase / (radius + (trackWidth / 2))))
|
||||
|
||||
self.outputA.customWheel.steerAngle = outerAngle
|
||||
self.outputB.customWheel.steerAngle = innerAngle
|
||||
end
|
||||
|
||||
return (tqA + tqB) / self.finalDrive
|
||||
end
|
||||
|
||||
|
||||
@@ -55,10 +55,24 @@ function Wheel:initialize(vehicle, name, config)
|
||||
end
|
||||
end)
|
||||
|
||||
local right = self.entity:getRight()
|
||||
local right = self.entity:getRight():getRotated(Angle(0, 90, 0))
|
||||
local offsetRight = self.entity:getRight():rotateAroundAxis(self.entity:getUp(), self.offset)
|
||||
|
||||
self.dir = right:dot(offsetRight)
|
||||
|
||||
self.debugHolo1 = holograms.create(
|
||||
Vector(),
|
||||
Angle(),
|
||||
'models/sprops/geometry/sphere_3.mdl'
|
||||
)
|
||||
|
||||
self.debugHolo2 = holograms.create(
|
||||
Vector(),
|
||||
Angle(),
|
||||
'models/sprops/geometry/sphere_3.mdl'
|
||||
)
|
||||
|
||||
self.steerVelocity = 0
|
||||
end
|
||||
|
||||
function Wheel:getEntityRadius()
|
||||
@@ -79,8 +93,10 @@ function Wheel:createHolo(entity)
|
||||
entity:getAngles() + Angle(0, self.offset, 0),
|
||||
self.CONFIG.Model or ''
|
||||
)
|
||||
|
||||
holo:setParent(entity)
|
||||
|
||||
-- holo:setColor(Color(255,255,255,110))
|
||||
entity:setColor(Color(0,0,0,0))
|
||||
|
||||
return holo
|
||||
@@ -105,7 +121,7 @@ function Wheel:forwardStep(torque, inertia)
|
||||
return 0
|
||||
end
|
||||
|
||||
self.customWheel.steerAngle = self.vehicle.steer * self.steerLock
|
||||
-- self.customWheel.steerAngle = self.vehicle.steer * self.steerLock
|
||||
--self.customWheel.inertia = inertia
|
||||
--self.customWheel:setInertia(inertia)
|
||||
self.customWheel.motorTorque = torque
|
||||
@@ -115,19 +131,39 @@ function Wheel:forwardStep(torque, inertia)
|
||||
|
||||
self.angularVelocity = self.customWheel.angularVelocity
|
||||
|
||||
self.debugHolo1:setPos(self.entity:localToWorld(Vector(0, 0, -self.entity:getModelRadius())))
|
||||
|
||||
if self.customWheel.hasHit and isValid(self.vehicle.basePhysObject) then
|
||||
local surfaceForceVector = self.customWheel.right * self.customWheel.sideFriction.force + self.customWheel.forward * self.customWheel.forwardFriction.force
|
||||
|
||||
self.vehicle.basePhysObject:applyForceOffset(surfaceForceVector, self.entity:getPos() - Vector(0, 0, self.customWheel.radius))
|
||||
self.vehicle.basePhysObject:applyForceOffset(surfaceForceVector, self.entity:localToWorld(Vector(0, 0, -self.entity:getModelRadius())))
|
||||
end
|
||||
|
||||
if isValid(self.holo) then
|
||||
self.rot = self.rot + math.deg(self.angularVelocity) * TICK_INTERVAL * self.dir
|
||||
|
||||
local steerAngle = self.entity:localToWorldAngles(Angle(0, self.offset - self.customWheel.steerAngle, 0) + self.rotationAxle * self.rot)
|
||||
local angle = steerAngle
|
||||
local spinAxis = self.customWheel.up:cross(self.customWheel.forward):getNormalized()
|
||||
|
||||
self.holo:setAngles(angle)
|
||||
self.debugHolo2:setPos(self.entity:localToWorld(self.customWheel.up * math.sin(timer.curtime()) * 20))
|
||||
|
||||
local rotatedForwardAngle = self.customWheel.forward:getAngle() + Angle(0, 90, 0)
|
||||
|
||||
|
||||
-- self.holo:setAngles(rotatedForwardAngle)
|
||||
|
||||
|
||||
-- local ang = up:getAngle()
|
||||
-- self.holo:setAngles(self.customWheel.forward:getAngle())
|
||||
|
||||
-- self.holo:setAngles(self.holo:getAngles():rotateAroundAxis(self.customWheel.right, 0))
|
||||
-- self.holo:setAngles(self.holo:getAngles():rotateAroundAxis(self.customWheel.right, nil, self.angularVelocity * TICK_INTERVAL))
|
||||
|
||||
|
||||
self.holo:setAngles(self.holo:getAngles():rotateAroundAxis(self.customWheel.right, nil, self.angularVelocity * TICK_INTERVAL))
|
||||
|
||||
-- local steerAngle = self.entity:localToWorldAngles(Angle(0, self.offset - self.customWheel.steerAngle, 0) + self.rotationAxle * self.rot)
|
||||
-- local angle = steerAngle
|
||||
|
||||
-- self.holo:setAngles(angle)
|
||||
end
|
||||
|
||||
return self.customWheel.counterTorque
|
||||
|
||||
@@ -63,7 +63,7 @@ function Vehicle:linkComponents()
|
||||
for _, componentConfig in pairs(self.config) do
|
||||
local component = self:getComponentByName(componentConfig.Name)
|
||||
|
||||
if componentConfig.Type == POWERTRAIN_COMPONENT.Wheel and componentConfig.Input == nil then
|
||||
if componentConfig.Input == nil && component ~= self:getRootComponent() then
|
||||
table.insert(self.independentComponents, component)
|
||||
else
|
||||
local inputComponent = self:getComponentByName(componentConfig.Input)
|
||||
|
||||
@@ -14,9 +14,10 @@ function Wheel:initialize(config)
|
||||
|
||||
self.mass = config.Mass or 20
|
||||
self.radius = config.Radius or 0.27
|
||||
self.rollingResistance = config.RollingResistance or 40
|
||||
self.rollingResistance = config.RollingResistance or 20
|
||||
self.squat = config.Squat or 0.1
|
||||
self.slipCircleShape = config.SlipCircleShape or 1.05
|
||||
self.casterAngle = math.rad(config.CasterAngle or 0)
|
||||
|
||||
self.forwardFriction = Friction:new(config.ForwardFriction)
|
||||
self.sideFriction = Friction:new(config.SideFriction)
|
||||
@@ -35,6 +36,7 @@ function Wheel:initialize(config)
|
||||
|
||||
self.forward = Vector(0)
|
||||
self.right = Vector(0)
|
||||
self.up = Vector(0)
|
||||
self.entity = NULL_ENTITY
|
||||
self.physObj = nil
|
||||
self.baseInertia = 0.5 * self.mass * math.pow(self.radius, 2)
|
||||
@@ -168,73 +170,26 @@ function Wheel:slipCircle(Sx, Sy, Fx, Fy, slipCircleShape)
|
||||
return Sx, Sy, Fx, Fy
|
||||
end
|
||||
|
||||
function Wheel:selfAligningTorque(Vx, Vy, Lc)
|
||||
local VxAbs = math.abs(Vx)
|
||||
local Sy = 0
|
||||
|
||||
if VxAbs > 0.3 then
|
||||
Sy = math.deg(math.atan(Vy / VxAbs))
|
||||
else
|
||||
Sy = Vy * (0.003 / TICK_INTERVAL)
|
||||
end
|
||||
|
||||
Sy = math.clamp(Sy, -90, 90)
|
||||
--local phi = (1 - self.E) * Sy + (self.E / self.B) * math.atan(self.B * Sy)
|
||||
--local Mz = -slipSign * self.satFrictionPreset:evaluate(math.abs(phi), self.B, C, self.D, 0) * Lc
|
||||
|
||||
return self.satFrictionPreset:evaluate(math.abs(Sy)) * -math.sign(Sy)
|
||||
end
|
||||
|
||||
function Wheel:selfAligningTorque2(Vx, Vy, Fz)
|
||||
|
||||
if Fz == 0 then
|
||||
function Wheel:selfAligningTorque(Sy, load)
|
||||
if math.abs(Sy) < 0.001 or load < 0.001 then
|
||||
return 0
|
||||
end
|
||||
|
||||
local VxAbs = math.abs(Vx)
|
||||
local Sy = 0
|
||||
local B = self.satFrictionPreset.B
|
||||
local C = self.satFrictionPreset.C
|
||||
local D = self.satFrictionPreset.D
|
||||
local E = self.satFrictionPreset.E
|
||||
|
||||
if VxAbs > 0.3 then
|
||||
Sy = math.deg(math.atan(Vy / VxAbs))
|
||||
else
|
||||
Sy = Vy * (0.003 / TICK_INTERVAL)
|
||||
end
|
||||
local loadScale = load * 1000
|
||||
local mechanicalTrail = 0.15
|
||||
local casterEffect = math.tan(self.casterAngle)
|
||||
local effectiveTrail = mechanicalTrail + casterEffect * self.radius
|
||||
local D_scaled = D * loadScale * effectiveTrail
|
||||
|
||||
Sy = math.clamp(Sy, -1, 1)
|
||||
local term = B * Sy - E * (B * Sy - math.atan(B * Sy))
|
||||
local Mz = D_scaled * math.sin(C * math.atan(term))
|
||||
|
||||
local a = {
|
||||
-2.72,
|
||||
-2.28,
|
||||
-1.86,
|
||||
-2.73,
|
||||
0.110,
|
||||
-0.070,
|
||||
0.643,
|
||||
-4.04,
|
||||
0.015,
|
||||
-0.066,
|
||||
0.945,
|
||||
0.030,
|
||||
0.070
|
||||
}
|
||||
local FzSqr = math.pow(Fz, 2)
|
||||
|
||||
local C = 2.4
|
||||
local D = a[1] * FzSqr + a[2] * Fz
|
||||
local BCD = (a[3] * FzSqr + a[4] * Fz) / math.pow(math.exp(1), a[5] * Fz)
|
||||
local B = BCD / (C * D)
|
||||
local E = a[6] * FzSqr + a[7] * Fz + a[8]
|
||||
|
||||
local phi = (1 - E) * Sy + (E / B) * math.atan(B * Sy)
|
||||
self.phi = phi
|
||||
|
||||
return D * math.sin(C * math.atan(B * phi))
|
||||
end
|
||||
|
||||
function Wheel:selfAligningTorque3(Mx, My, Sx, Sy)
|
||||
local M = Mx * math.cos(Sy) + My * math.cos(Sx)
|
||||
|
||||
return self.radius * M
|
||||
return Mz
|
||||
end
|
||||
|
||||
function Wheel:update()
|
||||
@@ -251,10 +206,27 @@ function Wheel:update()
|
||||
self.longitudinalLoadCoefficient = self:getLongitudinalLoadCoefficient(self.load * 1000)
|
||||
self.lateralLoadCoefficient = self:getLateralLoadCoefficient(self.load * 1000)
|
||||
|
||||
--self.steerAngle = self.steerAngle + self.mz / self.inertia
|
||||
local baseForward = self.entity:getForward()
|
||||
local baseUp = self.entity:getUp()
|
||||
local baseRight = self.entity:getRight()
|
||||
|
||||
self.forward = self.entity:getForward():rotateAroundAxis(self.entity:getUp(), -self.steerAngle)
|
||||
self.right = self.entity:getRight():rotateAroundAxis(self.entity:getUp(), -self.steerAngle)
|
||||
local steerRotatedForward = baseForward:rotateAroundAxis(baseUp, -self.steerAngle)
|
||||
local finalForward = steerRotatedForward:rotateAroundAxis(baseRight, nil, self.casterAngle)
|
||||
|
||||
self.forward = finalForward:getNormalized()
|
||||
self.right = baseUp:cross(self.forward):getNormalized()
|
||||
self.up = self.forward:cross(self.right):getNormalized()
|
||||
|
||||
|
||||
-- local steerRotated = self.entity:getForward():rotateAroundAxis(self.entity:getUp(), -self.steerAngle)
|
||||
-- self.forward = steerRotated:rotateAroundAxis(self.entity:getRight(), self.casterAngle)
|
||||
|
||||
|
||||
-- local steerRotatedRight = self.entity:getRight():rotateAroundAxis(self.entity:getUp(), -self.steerAngle)
|
||||
-- self.right = steerRotatedRight:rotateAroundAxis(self.entity:getRight(), self.casterAngle)
|
||||
|
||||
-- self.forward = self.entity:getForward():rotateAroundAxis(self.entity:getUp(), -self.steerAngle)
|
||||
-- self.right = self.entity:getRight():rotateAroundAxis(self.entity:getUp(), -self.steerAngle)
|
||||
|
||||
local forwardSpeed = 0
|
||||
local sideSpeed = 0
|
||||
@@ -272,16 +244,16 @@ function Wheel:update()
|
||||
self.longitudinalLoadCoefficient,
|
||||
self.radius,
|
||||
self.inertia,
|
||||
0.95, -- Force coeff
|
||||
0.9 -- Slip coeff
|
||||
0.95,
|
||||
0.9
|
||||
)
|
||||
|
||||
local Sy, Fy = self:stepLateral(
|
||||
forwardSpeed,
|
||||
sideSpeed,
|
||||
self.lateralLoadCoefficient,
|
||||
0.95, -- Force coeff
|
||||
0.9 -- Slip coeff
|
||||
0.95,
|
||||
0.9
|
||||
|
||||
)
|
||||
|
||||
@@ -290,15 +262,10 @@ function Wheel:update()
|
||||
Sy,
|
||||
Fx,
|
||||
Fy,
|
||||
1.05 -- Shape of the slip circle / ellipse.
|
||||
1.05
|
||||
)
|
||||
|
||||
--local Mx = Fy * (math.cos(Sx) - 1) + Fx * math.sin(Sx)
|
||||
--local My = Fx * (math.cos(Sy) - 1) + Fy * math.sin(Sy)
|
||||
--local Mz = self:selfAligningTorque3(Mx, My, Sx, Sy)
|
||||
local Mz = self:selfAligningTorque2(forwardSpeed, sideSpeed, self.load)
|
||||
|
||||
self.mz = Mz
|
||||
self.mz = self:selfAligningTorque(Sy, self.load)
|
||||
|
||||
self.angularVelocity = W
|
||||
self.counterTorque = CounterTq
|
||||
|
||||
Reference in New Issue
Block a user