Finished grip steering

This commit is contained in:
Иван Грачёв 2021-09-19 23:38:05 +05:00
parent d5bbad6f1d
commit f5192ebfff
3 changed files with 115 additions and 14 deletions

View File

@ -6,11 +6,40 @@ Steering = class('Steering')
require('./slave.txt') require('./slave.txt')
function inrange(val, min, max)
return val >= min and val <= max
end
function isNaN(val)
return val ~= val
end
function vectorIsNaN(vec)
return isNaN(vec[1]) or isNaN(vec[2]) or isNaN(vec[3])
end
function getLocalVelocity(ent)
return ent:worldToLocal((ent:getVelocity() + ent:getPos()))
end
local options = { local options = {
Camber = 0, Camber = -2,
Caster = 85, Caster = 5,
Ackermann = 10, Ackermann = 15,
Lock = 50 Lock = 45,
ZeroThreshold = 2,
StartSpeedThreshold = 40,
EndSpeedThreshold = 150,
SpeedCoeff = 0.2,
StartCorrectionThreshold = 5,
EndCorrectionThreshold = 40,
CorrectionOnCoeff = 0.6,
CorrectionOffCoeff = 1,
CorrectionOnLerp = 0.3,
CorrectionOffLerp = 0.6
} }
function Steering:_adjustPorts() function Steering:_adjustPorts()
@ -23,7 +52,8 @@ function Steering:_adjustPorts()
local outputs = { local outputs = {
SteerAngle = 'number', SteerAngle = 'number',
TargetAngle = 'number' TargetAngle = 'number',
CorrectionAngle = 'number'
} }
wire.adjustPorts(inputs, outputs) wire.adjustPorts(inputs, outputs)
@ -37,6 +67,7 @@ function Steering:_createSlaves()
local slave = Slave:new({ local slave = Slave:new({
Entity = v, Entity = v,
IsLeft = k % 2 == 1, IsLeft = k % 2 == 1,
Offset = 180,
Base = wire.ports.Base, Base = wire.ports.Base,
Camber = self.slavesConfig.Camber, Camber = self.slavesConfig.Camber,
Caster = self.slavesConfig.Caster, Caster = self.slavesConfig.Caster,
@ -49,33 +80,99 @@ end
function Steering:_updateOutputs() function Steering:_updateOutputs()
wire.ports.TargetAngle = self.targetAngle wire.ports.TargetAngle = self.targetAngle
wire.ports.SteerAngle = self.angle
wire.ports.CorrectionAngle = self.correction
end
function Steering:_getCorrectionGradient(speed)
return math.clamp(math.remap(speed, self.startCorrectionThreshold, self.endCorrectionThreshold, 0, 1), 0, 1)
end
function Steering:getBaseSpeed()
local MPH = self.base:getVelocity():getLength() * 3600 / 63360
local KPH = MPH * 1.609
return KPH
end
function Steering:_getSpeedCorrectionGradient(speed)
return math.clamp(math.remap(speed, self.startSpeedThreshold, self.endSpeedThreshold, 0, 1), 0, 1)
end
function Steering:_getCorrectionAngle()
local localVel = getLocalVelocity(self.base)
local forwardVel = (localVel * Vector(1, 0, 0)):getNormalized()
local planarVec = (localVel * Vector(1, 1, 0)):getNormalized()
forwardVel = vectorIsNaN(forwardVel) and Vector(0, 0, 0) or forwardVel
planarVec = vectorIsNaN(planarVec) and Vector(0, 0, 0) or planarVec
local cross = forwardVel:cross(planarVec)
return math.deg(math.acos(forwardVel:dot(planarVec))) * math.sign(localVel[2])
end end
function Steering:initialize(options) function Steering:initialize(options)
self:_adjustPorts()
options = options or {} options = options or {}
self.base = wire.ports.Base
self.slavesConfig = { self.slavesConfig = {
Camber = options.Camber, Camber = options.Camber,
Caster = options.Caster, Caster = options.Caster,
Ackermann = options.Ackermann Ackermann = options.Ackermann
} }
self.lock = 50 self.lock = options.Lock
self.targetAngle = 0 self.targetAngle = 0
self.angle = 0 self.angle = 0
self.zeroThreshold = options.ZeroThreshold
self.speedCoeff = options.SpeedCoeff
self.startSpeedThreshold = options.StartSpeedThreshold
self.endSpeedThreshold = options.EndSpeedThreshold
self.startCorrectionThreshold = options.StartCorrectionThreshold
self.endCorrectionThreshold = options.EndCorrectionThreshold
self.correctionOnCoeff = options.CorrectionOnCoeff
self.correctionOffCoeff = options.CorrectionOffCoeff
self.correctionOnLerp = options.CorrectionOnLerp
self.correctionOffLerp = options.CorrectionOffLerp
self.correction = 0
self.slaves = {} self.slaves = {}
self:_adjustPorts()
self:_createSlaves() self:_createSlaves()
end end
function Steering:update() function Steering:update()
local horizontal = wire.ports.Axles.Horizontal.Value local horizontal = wire.ports.Axles.Horizontal.Value
local horizontalTarget = wire.ports.Axles.Horizontal.Target
local baseSpeedKMH = self:getBaseSpeed()
local angleCorrection = self:_getCorrectionGradient(baseSpeedKMH)
local speedCorrection = self.angle * self:_getSpeedCorrectionGradient(baseSpeedKMH) * self.speedCoeff
self.targetAngle = horizontal * self.lock self.targetAngle = horizontal * self.lock
self.angle = -horizontal * self.lock
local correctionCoeff = horizontalTarget ~= 0 and self.correctionOnCoeff or self.correctionOffCoeff
local correctionLerpCoeff = horizontalTarget ~= 0 and self.correctionOnLerp or self.correctionOffLerp
local correction = self:_getCorrectionAngle() * angleCorrection * correctionCoeff
self.correction = math.lerp(correctionLerpCoeff, self.correction, isNaN(correction) and 0 or correction)
local possibleAngle = math.clamp(horizontal * self.lock + speedCorrection + self.correction, -self.lock, self.lock)
if inrange(possibleAngle, -self.zeroThreshold, self.zeroThreshold) then
self.angle = 0
else
self.angle = possibleAngle
end
for k, v in pairs(self.slaves) do for k, v in pairs(self.slaves) do
v:rotate(self.angle) v:rotate(self.angle)

View File

@ -10,6 +10,7 @@ function Slave:initialize(options)
self.caster = options.Caster self.caster = options.Caster
self.ackermann = options.Ackermann self.ackermann = options.Ackermann
self.isLeft = options.IsLeft self.isLeft = options.IsLeft
self.offset = options.Offset
end end
function Slave:rotate(ang) function Slave:rotate(ang)
@ -17,9 +18,12 @@ function Slave:rotate(ang)
self.entity:setFrozen(1) self.entity:setFrozen(1)
end end
local angle = Angle(0, ang, 0) local ackermann = math.sin(math.rad(ang)) ^ 2 * self.ackermann * (self.isLeft and -1 or 1)
local yaw = self.offset + ang + ackermann
local roll = (self.isLeft and 1 or -1) * self.camber - ang / 270 * self.caster
local angle = Angle(0, yaw, roll)
local transformedAngle = self.base:localToWorldAngles(angle) local transformedAngle = self.base:localToWorldAngles(angle)
self.entity:setAngles(transformedAngle) self.entity:setAngles(transformedAngle)
-- rotate slave here
end end

View File

@ -5,10 +5,10 @@
-- @include ./sv_input.txt -- @include ./sv_input.txt
local Axles = { local Axles = {
Horizontal = { Horizontal = {
Negative = KEY.A, Negative = KEY.D,
Positive = KEY.D, Positive = KEY.A,
Gravity = 0.05, Gravity = 0.1,
Sensitivity = 0.1 Sensitivity = 0.2
} }
} }