User Tools

Site Tools


usage:atlatc:examples:level_crossing

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
usage:atlatc:examples:level_crossing [2022-07-03 14:07]
56independent created
usage:atlatc:examples:level_crossing [2022-07-04 13:31] (current)
56independent [Implementation 3] Add resources
Line 10: Line 10:
 This code is also compatible with traffic lights from the streets mod. This code is also compatible with traffic lights from the streets mod.
  
-===== Code =====+ 
 +===== Alternatives ===== 
 +When using TSS interlocking, you can lock Andrew's crosses to a flashing state for as long as a route is held by punching them like any other passive component. This may not be suitable for 100% of cases, since you may only want the crossing activated for part of the route. 
 + 
 +In the future, it is hoped Andrew's crosses will be linkable directly to section occupation, meaning any train will activate the cross without further setup, making the whole system safer 
 + 
 +===== Implementation 1 =====
 Track: Track:
  
Line 48: Line 54:
 </code> </code>
  
 +
 +===== Implementation 2 =====
 +Hereafter the generic term "Automatic Crossing Warning Device" (ACWD, or just warning device) will be used generically. This usually means Andrew's crosses but there may be others in future or in your special use case. In this implementation, name each warning device with the passive component naming tool according to this scheme:
 +  - Prefix: Crossing location
 +  - Suffix: Warning device number
 +
 +and add entries to the ''S.acwd_crossings'' table to let the environment know how many warning devices that crossing has. For instance the passive component names at one crossing location might be: ''Foo1'', ''Foo2'' and ''Foo3'', and they will be registered with ''S.acwd_crossings.Foo = 3''
 +
 +Trains that approach a crossing will occupy it, and after they leave will free it. They occupy a specific approach to the crossing as well, so that, for instance, double track sections can be kept safe. They do this with calls to the environment code on LuaATC tracks on the approach and exit to the crossing.
 +
 +The implementation can be unreliable in case a train misses the approach and/or exit tracks, so make sure all ways in and out of a crossing have tracks with appropriate LuaATC. It is also up to you to ensure the crossing does not go off too early or stay on too late; factor in the speed of the train, track speed limits and so on. Also, this implementation assumes that approaches are directly linked to exits, and that a train will clear the approach it used correctly. If you have a weird crossing like this, you may be able to bodge it by calling ''F.acwd_free'' for both entrances that an exit has, but this code is untested so no guarantees :) I would add I don't usually recommend shunting over a level crossing :)
 +
 +The code assumes your warning devices use the passive component states "on" and "off". If they do not, it is left as an exercise to the reader to extend the code to be able to handle other states.
 +
 +Example code for trains approaching crossing
 +<code lua>
 +if not event.train then return end
 +F.acwd_occupy(atc_id, "garply", "west", "garply west approach")
 +</code>
 +
 +Example code for trains leaving crossing
 +<code lua>
 +if not event.train then return end
 +F.acwd_free(atc_id, "garply", "west", "garply west exit")
 +</code>
 +
 +LuaATC environment code
 +<code lua>
 +-- ACWD automatic crossing warning devices
 +-- (C) 2022 Blockhead licensed under the MIT license
 +-- Based largely on code on LinuxForks server, but made without reading it 
 +-- recently and not fully tested.
 +S.acwd_crossings = {
 +  -- Put the number of ACWDs at this crossing as an integer key e.g.
 +  foobaz = 1,
 +  garply = 2,
 +  schnitzel = 3,
 +}
 +
 +-- locals for speed
 +local acwd_occupation = S.acwd_occupation or {} --safe to re-run init code
 +if next(acwd_occupation) == nil then
 +  for location, numcrossings in pairs(acwd_occupation) do
 +    -- Every occupation entry is a table of train IDs occupying it.
 +    acwd_occupation[location] = {}
 +  end
 +end
 +
 +S.acwd_occupation = acwd_occupation
 +
 +-- Set occupation of a train with its train_id, at a crossing location, with
 +-- an approach key to distinguish locations where trains can approach the
 +-- crossing more than one way (e.g. a double track section will have 2
 +-- approaches). Give an optional debug_pos so bad calls can be debugged.
 +function F.acwd_occupy(train, crossing, approach, debug_pos)
 +  if type(crossing) ~= "string" then
 +    error("ACWD: Crossing name is not a string! " .. "@"(debug_pos or ""))
 +  end
 +
 +  n = acwd_crossings[crossing] or 0
 +  if not n > 0 then
 +    error("ACWD: Crossing name not valid: '" .. tostring(crossing) 
 +            .. "' @" .. (debug_pos or ""))
 +  end
 +  
 +  for wd=1,n do
 +    setstate(crossing .. tostring(wd), "on")
 +  end
 +  
 +  acwd_occupation[crossing][approach] = train
 +  
 +  end
 +end
 +
 +-- Clear occupation of a train with its train_id, at a crossing location, with
 +-- an approach key to distinguish locations where trains can approach the
 +-- crossing more than one way (e.g. a double track section will have 2
 +-- approaches). Give an optional debug_pos so bad calls can be debugged.
 +-- This will only set the warning devices back to off if there are no
 +-- occupation entries left at all for the crossing!
 +function F.acwd_free(train, crossing, approach, debug_pos)
 +  if type(crossing) ~= "string" then
 +    error("ACWD: Crossing name is not a string! " .. "@"(debug_pos or ""))
 +  end
 +
 +  n = acwd_crossings[crossing] or 0
 +  if not n > 0 then
 +    error("ACWD: Crossing name not valid: '" .. tostring(crossing) .. 
 +            "' @" .. (debug_pos or ""))
 +  end
 +  
 +  -- Clear this approach
 +  acwd_occupation[crossing][approach] = nil
 +  
 +  -- There must be no trains on any approach to the crossing to
 +  -- be able to clear it and disable the warning devices.
 +  if next(acwd_occupation[crossing]) == nil then
 +    for wd=1,n do
 +      setstate(crossing .. tostring(wd), "off")
 +    end
 +  end
 +end
 +
 +</code>
 +
 +===== Implementation 3 =====
 +<code lua>
 +-- The safest level crossing is no crossing. The path passes above or below the track and does not force people to cross the track. This track just keeps a train at mainline programming.
 +
 +atc_send("OCA1SM")
 +</code>
 +
 +More information:
 +
 +[[https://www.networkrail.co.uk/wp-content/uploads/2020/03/Enhancing-Level-Crossing-Safety-2019-2029.pdf|Network Rail PDF]]
 +
 +[[https://www.networkrail.co.uk/communities/living-by-the-railway/level-crossing-closures/|Network Rail Post]] (It basically says trains are going faster and there is more risk so they should close more rail crossings)
usage/atlatc/examples/level_crossing.1656850074.txt.gz · Last modified: 2022-07-03 14:07 by 56independent