"Train Balanced" station with several unloading/loading platforms
Posted: Fri May 22, 2020 11:16 pm
For my sub-factories which need a lot of a specific material, I use a trainstation with several unloading "platforms" which are all named equally. So my delivery trains will be distributed between those and supply all production lines. Additionally, I have a specific waiting area for each platform, and behind that another stacker. My largest station of that kind is the ore delivery for my steel works, which has five unloading platforms. You can see the whole layout zommed out here
Similarily I have also loading stations with multiple loading platforms to be able to several trains in parallel.
Of course you can just let the trains decide themself which platform they take. But that has a disadvantage - they always prefer the closes one, so platforms which are further away will get visited last and might even "starve". So I decided to use some circuit dark magic to steer the trains to the platform where they are needed the most. I followed the following priorisation rules:
- as long as unloading areas are free and reachable, drive to those.
- if all unloading areas are occupied, drive into the waiting areas.
- If both unloading area and waiting area are occupied, no train should enter (obviously)
- if more than one unloading areas or waiting areas are free, drive to the one with least (unloading stations) resp. most (loading stations) resources in its buffer chests.
For that I installed an additional signal on each rail leading to the different platforms. In the end each platform looks like this:
Three signals are relevant - signal A shows if the unloading area is occupied and signal B indicates if the waiting area is occupied. Signal C which is placed directly before signal B is the signal which will be set to red in case trains should not enter this platform due to the conditions mentioned above.
After a lot of trial and error I managed to create some circuit networks which did achieve this - they ended to be pretty messy, and you couldn't just take over one for e.g. four platforms and use it easily for five or three platforms - I had to rework a lot of those circuit networks for each variant.
While doing this I also run into occasional deadlocks - it could happen that a train was heading to a specific platform, but while it was on its way another platform became the intended target of my circuit, and the signal in the train's path switched to red. After that the train decided to stop just in the crossing to all platforms blocking it completely. So I added a chainsignal in a central position below - if it is red for more than three seconds, the circuits will ignore the priorisation rules above to let the train pass again.
While my solution did finally work, I was not really content with it as it was very hard to understand and maintain, and not really scalable. So I decided today to fix it and develop a solution which could be applied to different number of platforms easily and is also far easier to understand. First I split the whole problem in three - I could define three layers which makes it easier to create a managable design, limited to up to 10 different platforms (note - I don't think using 10 platforms is in any way feasible):
The first layer will provide the values of the signals and the content of the buffer crates. These signals will be laid on the red data bus (not to mixed up with the other meaning of "bus" often used in factorio ):
0:9 - the content of the buffer crates for platforms 0 to 9.
A:J - bus signals indicating if train signal A (OK, now these different meanings get really confusing... ) is green or not for platforms 0 to 9(1: signal is green, 0: signal is not green)
K:T - bus signals indicating if train signal B is green or not for platforms 0 to 9 (1: signal is green, 0: signal is not green)
Fish: Indicating a blockade suspicion (fish = 0: blockade suspicion, fish = 1: no blockade suspicion)
The next layer is the preprocessing layer which will do most of the work. Here's a screenshot of my full blueprint version in my "test bench". The preprocessing part is the big part on the left side.
In row 1 it checks if a train can drive directly to a station (by checking if both signal A and B are green) for each platform. Local boolean signals 0 to 9 are created to indicate the result.
In row 2 it determines if all platforms are occupied. If that's the case, it sets the signal V to 1. It also provides the constant "crate" with a value of 10 Mio.
In row 3 a local signal Y is set to one for all platforms if V is one and the platform's waiting area is free.
In row 4 the results from rows one and 3 are added up. The result Z indicates if this platform should be a target at all.
In row 5 the signal "crate" will change to 0 for all platforms which are accesible. For the rest it remains at 10 Mio.
In row 6 the actual content of the each platform's buffer is added (for the unloading variant)/substracted (for the loading variant) to the local "crates" value. That means that the adjusted value for blocked platforms is far higher resp. lower than those for reachable platforms. These adjusted values are also sent to a green data bus.
The rows 7 to 9 calculate the mimumun (unloading) resp. maximum (loading) of all the adjusted buffer contents. As the values of blocked platforms are way higher resp. lower than those for free platforms, these values won't "win". The final result is stored in the signal M which is also sent on the green data bus.
So now we have a second data bus which has adjusted buffer contents and the minimum resp. maximum value. With this information, it's easy to determine which signals should be closed and which should be open. For that purpose we add another small part for each platform, the signal setter instance. The screenshot shows it on the right top section.
It has two pylons directly to each other. The top pylon needs to be connected to the green bus, the bottom to the red bus. Two of the three combinators contain placeholders: the wooden crate needs to replaced with the value of the appropriate buffer chests (e.g. 0), and the train signal with the (bus) signal for the platform's (train) signal B (e.g. K). If either the waiting area is blocked, or the minimum value is lower than its own buffer chest count (for the unloader), no train should be allowed to enter this platform. In case we have a fishy situation and a deadlock is detected it will ignore the buffer chest content, though. The final result is stored in the red square value and sent to the lower pylon via a green wire. The lower pylon needs to be connected with the appropriate signal C by a green wire, and signal C needs to close in case "Red square > 0".
With that it's actually pretty easy to set up a station like that. Once the initial signals are set up, the preprocessing part can be placed via blueprint and the colums for the non-used platforms can be simply deleted. Both green and red bus need to be connected to one of the substations. The only other adjustment is to connect the output of rows 7 and 9 via green wire to the lower substation, so that the minimum is available on your green bus, too.
After that place for each platform a seperate signal setter instance, and connect its power poles to the correct data buses, and connect the signal to be controlled with a green cable to the lower pylon. Replace the wooden crate and the train signal with the appropriate values for that platform.
Here's the blueprint book with the designs for both the preprocessor layer and signal setter instance for both loading and unloading, plus a small blueprint for the deadlock detection:
Similarily I have also loading stations with multiple loading platforms to be able to several trains in parallel.
Of course you can just let the trains decide themself which platform they take. But that has a disadvantage - they always prefer the closes one, so platforms which are further away will get visited last and might even "starve". So I decided to use some circuit dark magic to steer the trains to the platform where they are needed the most. I followed the following priorisation rules:
- as long as unloading areas are free and reachable, drive to those.
- if all unloading areas are occupied, drive into the waiting areas.
- If both unloading area and waiting area are occupied, no train should enter (obviously)
- if more than one unloading areas or waiting areas are free, drive to the one with least (unloading stations) resp. most (loading stations) resources in its buffer chests.
For that I installed an additional signal on each rail leading to the different platforms. In the end each platform looks like this:
Three signals are relevant - signal A shows if the unloading area is occupied and signal B indicates if the waiting area is occupied. Signal C which is placed directly before signal B is the signal which will be set to red in case trains should not enter this platform due to the conditions mentioned above.
After a lot of trial and error I managed to create some circuit networks which did achieve this - they ended to be pretty messy, and you couldn't just take over one for e.g. four platforms and use it easily for five or three platforms - I had to rework a lot of those circuit networks for each variant.
While doing this I also run into occasional deadlocks - it could happen that a train was heading to a specific platform, but while it was on its way another platform became the intended target of my circuit, and the signal in the train's path switched to red. After that the train decided to stop just in the crossing to all platforms blocking it completely. So I added a chainsignal in a central position below - if it is red for more than three seconds, the circuits will ignore the priorisation rules above to let the train pass again.
While my solution did finally work, I was not really content with it as it was very hard to understand and maintain, and not really scalable. So I decided today to fix it and develop a solution which could be applied to different number of platforms easily and is also far easier to understand. First I split the whole problem in three - I could define three layers which makes it easier to create a managable design, limited to up to 10 different platforms (note - I don't think using 10 platforms is in any way feasible):
The first layer will provide the values of the signals and the content of the buffer crates. These signals will be laid on the red data bus (not to mixed up with the other meaning of "bus" often used in factorio ):
0:9 - the content of the buffer crates for platforms 0 to 9.
A:J - bus signals indicating if train signal A (OK, now these different meanings get really confusing... ) is green or not for platforms 0 to 9(1: signal is green, 0: signal is not green)
K:T - bus signals indicating if train signal B is green or not for platforms 0 to 9 (1: signal is green, 0: signal is not green)
Fish: Indicating a blockade suspicion (fish = 0: blockade suspicion, fish = 1: no blockade suspicion)
The next layer is the preprocessing layer which will do most of the work. Here's a screenshot of my full blueprint version in my "test bench". The preprocessing part is the big part on the left side.
In row 1 it checks if a train can drive directly to a station (by checking if both signal A and B are green) for each platform. Local boolean signals 0 to 9 are created to indicate the result.
In row 2 it determines if all platforms are occupied. If that's the case, it sets the signal V to 1. It also provides the constant "crate" with a value of 10 Mio.
In row 3 a local signal Y is set to one for all platforms if V is one and the platform's waiting area is free.
In row 4 the results from rows one and 3 are added up. The result Z indicates if this platform should be a target at all.
In row 5 the signal "crate" will change to 0 for all platforms which are accesible. For the rest it remains at 10 Mio.
In row 6 the actual content of the each platform's buffer is added (for the unloading variant)/substracted (for the loading variant) to the local "crates" value. That means that the adjusted value for blocked platforms is far higher resp. lower than those for reachable platforms. These adjusted values are also sent to a green data bus.
The rows 7 to 9 calculate the mimumun (unloading) resp. maximum (loading) of all the adjusted buffer contents. As the values of blocked platforms are way higher resp. lower than those for free platforms, these values won't "win". The final result is stored in the signal M which is also sent on the green data bus.
So now we have a second data bus which has adjusted buffer contents and the minimum resp. maximum value. With this information, it's easy to determine which signals should be closed and which should be open. For that purpose we add another small part for each platform, the signal setter instance. The screenshot shows it on the right top section.
It has two pylons directly to each other. The top pylon needs to be connected to the green bus, the bottom to the red bus. Two of the three combinators contain placeholders: the wooden crate needs to replaced with the value of the appropriate buffer chests (e.g. 0), and the train signal with the (bus) signal for the platform's (train) signal B (e.g. K). If either the waiting area is blocked, or the minimum value is lower than its own buffer chest count (for the unloader), no train should be allowed to enter this platform. In case we have a fishy situation and a deadlock is detected it will ignore the buffer chest content, though. The final result is stored in the red square value and sent to the lower pylon via a green wire. The lower pylon needs to be connected with the appropriate signal C by a green wire, and signal C needs to close in case "Red square > 0".
With that it's actually pretty easy to set up a station like that. Once the initial signals are set up, the preprocessing part can be placed via blueprint and the colums for the non-used platforms can be simply deleted. Both green and red bus need to be connected to one of the substations. The only other adjustment is to connect the output of rows 7 and 9 via green wire to the lower substation, so that the minimum is available on your green bus, too.
After that place for each platform a seperate signal setter instance, and connect its power poles to the correct data buses, and connect the signal to be controlled with a green cable to the lower pylon. Replace the wooden crate and the train signal with the appropriate values for that platform.
Here's the blueprint book with the designs for both the preprocessor layer and signal setter instance for both loading and unloading, plus a small blueprint for the deadlock detection: