User Tools

Site Tools


Sidebar



Minetest Forum
Content Database
Git Repository
Bug Tracker
Website

usage:atlatc:examples:level_crossing

Level Crossing Warning System

Introduction

A level crossing is very dangerous as trains travel at a high speed and are often very quiet. They kill instantly whilst leaving no trace.

As such, a level crossing warning system is a very good idea.

Explanation

To use this system, one needs a luacontroller, digilines, and an Andrew's Cross. When a train approaches, it causes a digiline signal and then this is interpreted by the luacontroller and sent to the Andrew's Cross.

This code is also compatible with traffic lights from the streets mod.

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:

-- Andrew's cross activation code. Compatible with traffic signals. Use channel "a" using digilines connected to tracks.
 
__approach_callback_mode = 2
 
 
if event.type == "approach" then
    digiline_send("a", "RED")
end
 
if event.type == "train" then
    digiline_send("a", "GREEN")
end

Luacontroller:

-- Connect to rail with digilines. Turns ports on if there is a train.
 
if event.type == "digiline" and event.msg == "RED" then
    port.a = true
    port.b = true
    port.c = true
    port.d = true
end
 
if event.type == "digiline" and event.msg == "GREEN" then
    port.a = false
    port.b = false
    port.c = false
    port.d = false
end

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:

  1. Prefix: Crossing location
  2. 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

if not event.train then return end
F.acwd_occupy(atc_id, "garply", "west", "garply west approach")

Example code for trains leaving crossing

if not event.train then return end
F.acwd_free(atc_id, "garply", "west", "garply west exit")

LuaATC environment code

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

Implementation 3

-- 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")

More information:

Network Rail PDF

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.txt · Last modified: 2022-07-04 13:31 by 56independent