Skip to content

Instantly share code, notes, and snippets.

@Majiir
Last active February 11, 2023 22:06
Show Gist options
  • Save Majiir/81fc491b6f2e0228c98b3e3d8bcdc0e7 to your computer and use it in GitHub Desktop.
Save Majiir/81fc491b6f2e0228c98b3e3d8bcdc0e7 to your computer and use it in GitHub Desktop.
A Factorio train management system with configurable station priority.
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

Ethertrains v3.1 (by Majiir)

A Factorio train management system with configurable station priority. (Blueprint book string)

Index

Overview

Features

  • Configurable station priority
  • First-in-first-out queueing (at equal priority)
  • Full stacker utilization
  • Vanilla Factorio
  • No depots or central stackers
  • No central computer
  • No pathing penalties or extra pathing stations

Requirements

  • A combinator module at each train stop
  • A global green circuit wire (this isn't as bad as it sounds - see Communication section)
  • Non-pathable "decoy" stations hidden away somewhere

Some setups may require adjustments to:

  • Train schedules
  • Intersection signalling
  • Stacker signalling
  • Rail network layout

Principles of Operation

Many-to-Many Schedules

For each train schedule, there are pickups and dropoffs. For example, you might name all of your iron mines Iron Ore Pickup and all of your iron smelters Iron Ore Dropoff.

Priority Levels

Every station in the system has a configured priority level. Stations with a higher priority (a lower priority level number) have precedence over stations with a lower priority (higher number).

For example, setting a low priority number at the coal dropoff for your power plant will prioritize coal for power generation, and coal would only route to your plastic plant if the power plant has enough.

Train Stop Limits

Ethertrains provides functionality similar to train stop limits, but it doesn't use the built-in train stop limit feature. Instead, it uses train swapping and full stackers together to replicate the effect of train stop limits.

Full Stackers

Every station has a fixed number of slots for waiting trains. Each station can be configured independently. The total number of trains using a schedule equals the total number of slots across all stations in that schedule. In other words, if every train is waiting at a station, then every slot will be occupied.

Train Swapping

Trains are routed through train swapping. A full train can only depart from a pickup if a corresponding empty train simultaneously departs from a dropoff.

Swapping full and empty trains allows us to maintain the full-stackers invariant. If every train is sitting in a stacker slot, then there are no free stacker slots. If both a full train and an empty train depart simultaneously, then they can take each other's place.

Communication

Each train stop is controlled by a combinator module. Modules communicate with each other using a global green circuit wire that connects all of the modules in the factory.

Ordinarily, I might find a base-spanning wire to be an onerous requirement for a train system. In this case, the wire may be shared with other applications because modules communicate using the Combinator Ethernet system. Combinator Ethernet takes care of addressing, collision detection, congestion control, and more. Any circuits communicating around the factory can use this wire through the Combinator Ethernet protocol. See the Combinator Ethernet section for blueprints and reference information.

Blueprints

Pickup/Dropoff Module

Each train station is controlled by a combinator module. There's a Pickup Module and a Dropoff Module. The two are similar and configured as opposites.

image

  • The substation green wire connects to the global network wire.
  • The substation red wire connects to stacker monitors, if any.
  • The configuration constant combinator specifies:
    • Schedule ID (I value)
    • Priority level (P value)
    • Network channel (gray value)
  • The train present indicator turns on when there is a train at the station controlled by the module.
  • The train ready indicator:
    • Blinks yellow on a failed signal transmission
    • Holds green when the train is in queue
  • The hold-back signal and train stop are wired to control train routing.

Reset Tool

Each station keeps track of the state of the network. When a new station is added, the network must be reset in order for the new station to learn the network state. The Reset Tool transmits the command to reset the network.

image

To use the tool:

  • Paste the Reset Tool blueprint
  • Connect the power pole to the global green network wire
  • Configure the schedule ID (I value) that you want to reset
  • Toggle on the send trigger
  • When the light turns solid green, the reset is complete

Stacker Monitor

Modules support multiple trains waiting at a station, but the module needs to observe when waiting spaces are empty. Use a Stacker Monitor before each waiting space (excluding the train stop area itself) and connect them all to the red wire on the module substation.

image

User's Guide

Station Setup

Repeat these steps (in order) for each new station in the system:

  • Place a pickup or dropoff module
  • Set the schedule ID (I value) on the module
  • Set a priority number (P value) on the module
  • Connect the module substation to a base-wide green wire
  • Run the Reset Tool for the station's schedule ID (I value)
  • (Optional) Add a Stacker Monitor for each train waiting space
  • Set the train station name
  • Create a train and send it to the new station

If this is the first train stop with its name (e.g. the first Iron Ore Dropoff station) then place a Decoy Train Stop.

The ordering of these steps ensures that the network will remain in a working state. In particular, it's important that no train stops at the station before the module has been configured, connected to the network, and initialized through a reset. Delaying naming the train station until after those steps ensures that other trains in your network won't path to it too early. If you copy-paste an existing station, take care to prevent trains from pathing to it before it's fully set up (e.g. by temporarily removing a rail segment before the train stop).

Train Schedules

Train schedules should meet these requirements:

  • Schedules consist of one pickup and one dropoff.
  • Departure conditions take some non-zero amount of time.

The second requirement ensures that a train stop can detect a stopped train. When a train stops at a station where its conditions have already been met, the train stop will never emit a signal value for the train ID. The train would be invisible to the station, which would throw the network out of balance because the train will depart without a corresponding departure from an opposite station. An easy way to satisfy this requirement is to include an AND 1s passed condition.

Example train schedule:

image

Train Network Design

The train network (rails, signals, intersections) should satisfy some requirements to keep trains from getting stuck.

Every train in the system must have at least one of the following at all times:

  • Available paths to every station matching the train's current destination, without pathing through a different station's stacker
  • A reserved signal block in a stacker for the train's current destination

What are these rules for?

The system enables and disables train stops to control train routing. When a train stop is disabled while a train is heading toward it, the train must re-path and find a new train stop. If the train cannot find a path to a train stop matching its current destination, the train will stop dead in the tracks.

The rules above ensure that a train will always find its way to a destination without getting stuck. If a train has reserved a signal block in a stacker, then it is guaranteed a spot. (A train stop will not disable until every stacker slot is full.) On the other hand, if a train has not yet reserved a stacker slot, then it must cope with the possibility that another train will beat it to its current destination, disabling the train stop. As long as the train can reach every other train stop with the same name, it will be able to find a home.

In practice, this means you want to:

  • Be careful about intersection signalling near stations
  • Include turnarounds or other loops

This example shows a typical problem with standard intersection designs:

image

Both trains pathed toward the same train stop and arrived at roughly the same time. The upper train reserved the signal block first, so the lower train started waiting at the signal for it to open. When the first train arrived at the train stop, the train stop disabled. That caused the second train to find a path to a different train stop, but it had already taken the turn into the station. This network violates the first requirement listed above because the train's only path to one of its destinations is through another destination's stacker.

The fix is to add a chain signal before any fork at an intersection leading to a station. In this example, the lower train waits at the chain signal briefly, but as soon as the upper train reaches the train stop, the lower train re-paths and continues ahead.

image

As this train re-paths, the system has guaranteed that there will be at least one destination station enabled. That station could be anywhere, including behind the train. There must be some way for that train to reach every train stop matching its destination because there is no way to predict which train stops will be enabled.

You can add simple turnaround loops at each station, or you can build larger loops and rings into your network design. If you find a train with a no-path error when there is clearly an open destination, you may be missing a turnaround somewhere.

Decoy Train Stops

Due to a quirk in Factorio train routing, you will need to place decoy train stops. These are train stops which are non-pathable from your main rail network but share the same name as your normal stops.

Why are decoy train stops necessary?

The system learns that a train is ready to leave by observing that the train is no longer waiting at the train stop (the train ID signal has changed to zero).

At some point, your network will get into a state where every train stop in a schedule is disabled. In this state, a departing train will try to path to a destination, but none are available - so it doesn't leave the train stop.

The decoy stations ensure that there is always at least one enabled train stop for every schedule. That station is non-pathable, but it's enough to cause a train to technically depart from its current stop. Once the modules coordinate a swap, the real destination station becomes enabled, and the trains drive away.

You can hide them away somewhere on the map. Make sure they are not connected to your rail network. Every pickup and dropoff must have a decoy.

image

References

Combinator Ethernet

Alternative Designs

Many Factorio engineers have built train management systems. These are some alternative designs which address various train routing problems in different ways. They are ordered oldest to newest. If I missed one, let me know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment