This commit is contained in:
Никита Круглицкий
2025-05-10 19:21:51 +06:00
parent a81aa450dc
commit 9f19c7d618
23 changed files with 310 additions and 334 deletions

View File

@@ -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