Recalculate when the tnc_call_approach_callback is called; remove dtime limit

TODO: Fix incorrect behavior with non-zero speed limits
h137
ywang 2020-04-30 16:55:06 +02:00
parent d824198b94
commit 75a948792e
3 changed files with 113 additions and 78 deletions

View File

@ -477,23 +477,8 @@ minetest.register_globalstep(function(dtime_mt)
advtrains.load()
end
local dtime = GENERATE_ATRICIFIAL_LAG and 0.2 or math.min(dtime_mt, 0.2)
--[[if GENERATE_ATRICIFIAL_LAG then
dtime = 0.2
if os.clock()<t then
return
end
t = os.clock()+0.2
else
--limit dtime: if trains move too far in one step, automation may cause stuck and wrongly braking trains
dtime=dtime_mt
if dtime>0.2 then
atprint("Limiting dtime to 0.2!")
dtime=0.2
end
end ]]
--local dtime = GENERATE_ATRICIFIAL_LAG and 0.2 or math.min(dtime_mt, 0.2)
local dtime = GENERATE_ATRICIFIAL_LAG and 0.2 or dtime_mt
advtrains.mainloop_trainlogic(dtime)
if advtrains_itm_mainloop then
advtrains_itm_mainloop(dtime)

View File

@ -113,9 +113,9 @@ function advtrains.lzb_get_limit_by_entry(train, lzb, dtime)
if train.index + v0*t + getacc(train,4)*t*t/2 <= i then return 4 end
i = advtrains.lzb_get_limit_zone(train, lzb, 3, v0)
if train.index + v0*t <= i then return 3 end
i = advtrains.path_get_index_by_offset(train, i, params.ZONE_HOLD)
i = advtrains.path_get_index_by_offset(train, i, -params.ZONE_HOLD)
if train.index + v0*t + getacc(train,2)*t*t/2 <= i then return 2 end
i = advtrains.path_get_index_by_offset(train, i, params.ZONE_ROLL)
i = advtrains.path_get_index_by_offset(train, i, -params.ZONE_ROLL)
if train.index + v0*t + getacc(train,1)*t*t/2 <= i then return 1 end
return 0
end
@ -123,39 +123,44 @@ end
-- Get next LZB restriction with the lowest speed restriction
-- The return values include the LZB entry and the speed limit
function advtrains.lzb_get_next(train,dtime)
if lever == 4 then return nil end
-- if lever == 4 then return nil end
local lzb = train.lzb
local i = 1
local ret
local a = advtrains.get_acceleration(train, 3) -- Acceleration
local ret, retlimit
--local a = advtrains.get_acceleration(train, 3) -- Acceleration
local v0 = train.velocity
-- Remove LZB entries that are no longer valid
while i <= #lzb.oncoming do
if lzb.oncoming[i].idx < train.index then
-- The entry is no longer valid and should be removed
local ent = lzb.oncoming[i]
if ent.fun then
ent.fun(ent.pos, id, train, ent.idx, ent.spd, lzb.data)
end
table.remove(lzb.oncoming, i)
-- This should (hopefully) be faster than table.remove(lzb.oncoming, i)
if i == #lzb.oncoming then
lzb.oncoming[i] = nil
else
lzb.oncoming[i] = lzb.oncoming[#lzb.oncoming]
lzb.oncoming[#lzb.oncoming] = nil
end
else
-- Check for the speed requirement from this LZB entry instead of putting it into another loop
local it = lzb.oncoming[i]
local v1 = it.spd
if v1 and v1 <= 0 then
if not ret then ret = it
else
local curlimit = advtrains.lzb_get_limit_by_entry(train, it, dtime)
if retlimit and retlimit > curlimit then ret = it
elseif retlimit == curlimit and it.idx < ret.idx then ret = it
end
end
retlimit = advtrains.lzb_get_limit_by_entry(train, ret, dtime)
end
i = i + 1
end
end
-- Now run through all the LZB entries and find the one with the lowest speed requirement
for _, it in ipairs(lzb.oncoming) do
local v1 = it.spd
if v1 and v1 <= v0 then
if not ret then ret = it
else
local retlimit = advtrains.lzb_get_limit_by_entry(train,ret,dtime)
local curlimit = advtrains.lzb_get_limit_by_entry(train,ret,dtime)
if retlimit and retlimit > curlimit then ret=it
elseif retlimit == curlimit and it.idx < ret.idx then ret=it
end
end
end
end
return ret,advtrains.lzb_get_limit_by_entry(train, ret,dtime)
return ret, retlimit
end
local function invalidate(train)

View File

@ -191,8 +191,9 @@ local function assertdef(tbl, var, def)
end
function advtrains.get_acceleration(train, lever)
local acc_all = t_accel_all[lever]
local acc_eng = t_accel_eng[lever]
local lvr = lever or train.lever
local acc_all = t_accel_all[lvr] or -3 -- assume braking to avoid problems
local acc_eng = t_accel_eng[lvr] or 0
local nwagons = #train.trainparts
if nwagons == 0 then
-- empty train! avoid division through zero
@ -364,24 +365,8 @@ function advtrains.train_step_b(id, train, dtime)
if train.ctrl.user then
advtrains.atc.train_reset_command(train)
else
local braketar = train.atc_brake_target
local emerg = false -- atc_brake_target==-1 means emergency brake (BB command)
if braketar == -1 then
braketar = 0
emerg = true
end
--[[
if braketar and braketar>=trainvelocity then
train.atc_brake_target=nil
braketar = nil
end
]]
--if train.tarvelocity and train.velocity==train.tarvelocity then
-- train.tarvelocity = nil
--end
--[[
if train.atc_wait_finish then
if not train.atc_brake_target and (not train.tarvelocity or train.velocity==train.tarvelocity) then
if (not train.ctrl.atc) or (train.ctrl.atc<3 and train.tarvelocity>=train.velocity) or (train.ctrl.atc==3) or (train.ctrl.atc>3 and train.velocity>=train.tarvelocity) then
train.atc_wait_finish=nil
end
end
@ -394,8 +379,12 @@ function advtrains.train_step_b(id, train, dtime)
elseif train.atc_delay then
train.atc_delay = nil
end
]]
local braketar = train.atc_brake_target
local emerg = false -- atc_brake_target==-1 means emergency brake (BB command)
if braketar == -1 then
braketar = 0
emerg = true
end
train.ctrl.atc = nil
if train.tarvelocity then train.ctrl.atc = 3 end
if train.tarvelocity and train.tarvelocity>trainvelocity then
@ -412,20 +401,6 @@ function advtrains.train_step_b(id, train, dtime)
train.ctrl.atc=2
end
end
if train.atc_wait_finish then
if (not train.ctrl.atc) or (train.ctrl.atc<3 and train.tarvelocity>=train.velocity) or (train.ctrl.atc==3) or (train.ctrl.atc>3 and train.velocity>=train.tarvelocity) then
train.atc_wait_finish=nil
end
end
if train.atc_command then
if (not train.atc_delay or train.atc_delay<=0) and not train.atc_wait_finish then
advtrains.atc.execute_atc_command(id, train)
else
train.atc_delay=train.atc_delay-dtime
end
elseif train.atc_delay then
train.atc_delay = nil
end
end
--if tarvel_cap and train.tarvelocity and tarvel_cap<train.tarvelocity then
@ -452,8 +427,9 @@ function advtrains.train_step_b(id, train, dtime)
local a = advtrains.get_acceleration(train, tmp_lever)
local v0 = train.velocity
local v1 = a*dtime+v0
v1 = math.min(v1, (tarvel_cap or train.max_speed or 10))
v1 = math.min(v1, train.max_speed or 10)
v1 = math.max(v1, 0)
if tarvel_cap then v1 = math.min(v1, tarvel_cap) end
if tmp_lever == 4 and train.tarvelocity then v1=math.min(train.tarvelocity,v1) end
local s
if a == 0 then s = v1*dtime
@ -464,16 +440,35 @@ function advtrains.train_step_b(id, train, dtime)
end
s = math.max(s,0)
--- 4b. Move train and update train properties ---
local idx_floor = math.floor(train.index)
local pdist = train.path_dist[idx_floor+1] - train.path_dist[idx_floor]
local distance = pdist == 0 and s or s / pdist
train.lever = tmp_lever
train.velocity = v1
train.acceleration = a==0 and 0 or (v1-v0)/dtime
local idx_floor = math.floor(train.index)
local pdist
if train.path_dist[idx_floor+1] and train.path_dist[idx_floor] then
pdist = train.path_dist[idx_floor+1] - train.path_dist[idx_floor]
else
local lifloor
if train.lastcalc then lifloor = math.floor(train.lastcalc.index) end
if lifloor and train.path_dist[lifloor+1] and train.path_dist[lifloor] then
pdist = train.path_dist[lifloor+1] - train.path_dist[lifloor]
else
pdist = 1
end
end
local distance = pdist > 0 and s/pdist or s
--debugging code
--train.debug = atdump(train.ctrl).."step_dist: "..math.floor(distance*1000)
train.lastcalc = {
["index"] = train.index,
["v0"] = v0,
["v1"] = v1,
["lever"] = tmp_lever,
["t"] = dtime,
["trainparts"] = trainparts,
}
train.index=train.index+distance
recalc_end_index(train)
@ -579,6 +574,56 @@ function advtrains.train_step_c(id, train, dtime)
end
end
local function recalc_train_index(id, train, index)
-- check for necessary data
if not train.lastcalc then return end
local trainparts = train.lastcalc.trainparts
local last_index = train.lastcalc.index
local last_v0 = train.lastcalc.v0
local last_v1 = train.lastcalc.v1
local last_lever = train.lastcalc.lever
local last_t = train.lastcalc.t
local last_acc = advtrains.get_acceleration(train, last_lever)
local v0 -- Since we are recalculating, the speed when the train reached here would become v0
local idiff = index - last_index
local time_to_here, t
if train.trainparts~=trainparts then return end
local sa
if last_acc==0 then
sa = 0
else
sa = (last_v1*last_v1 - last_v0*last_v0)/2/last_acc
end
if idiff <= 0 then return end
if sa < 0 then return end
if idiff < sa then
-- v = sqrt(v0^2+2*s*a)
local v0sq = last_v0*last_v0+2*idiff*last_acc
if v0sq<0 then return end
v0 = math.sqrt(v0sq)
time_to_here = (last_v1-last_v0)/last_acc
else
v0 = last_v1
if last_acc == 0 then
time_to_here = 0
else
time_to_here = (last_v1-last_v0)/last_acc
end
if v0~=0 then time_to_here = time_to_here + (idiff-sa)/last_v1 end
end
t = last_t - time_to_here
if t<0 then return end
train.index = index
train.velocity = v0
train.acceleration = advtrains.get_acceleration(train)
advtrains.train_step_b(id, train, t)
end
-- Default occupation callbacks for node callbacks
-- (remember, train.end_index is set separately because callbacks are
-- asserted to rely on this)