Cargo Landing Pad: Throughput-optimal 3.600 items/s without bots

Post pictures and videos of your factories.
If possible, please post also the blueprints/maps of your creations!
For art/design etc. you can go to Fan Art.

DemRat
Burner Inserter
Burner Inserter
Posts: 13
Joined: Tue Jan 06, 2015 2:41 pm
Contact:

Cargo Landing Pad: Throughput-optimal 3.600 items/s without bots

Post by DemRat »

Hello! Today I will showcase my most dearest project over the last two weeks month or two (writing this took a while) - the best possible cargo landing pad throughput that doesn't use bots. For a different (not necessarily better) reading experience you can visit my work in progress blog.
Have a clip of it in action:



Isn't it beautiful? 106 legendary stack inserters moving 3.600 items every second onto 30 turbo transport belts.

Additional benefits:
  • backup resilience
  • no bots
  • seamlessly works with lower quality
  • no bots
  • neigh incomprehensible
  • cursed
  • no bots
This post is structured in multiple parts:
  • Blueprint String
  • Constraints
  • Operating Principle
  • Entity Layout
  • Circuitry
  • Usage Guide
  • Prior Work
  • Q&A
I will do my best to make each of these as straightforward and easy to follow as possible - I do take suggestions!
A lot of the decision making in this project is interdependent, so I recommend at least skimming every section, though I do try to make them somewhat independent.
Now, without further ado, let me guide you through this beauty monstrosity thing.
Chapter 0: Here ya go
Chapter 1: Constraints
This build is born from a very specific need I had in my main save file: Move arbitrary items as quickly as possible from the cargo landing pad onto trains. With a proper setup for the train network, I could request whatever I want and be sure that it gets transported to where I need it.

I also, for no adequately explainable reason, don't want to use bots. Because I can.

From this a few design constraints emerge piece by piece:
  1. As many tiles as possible around the CLP need to be filled with inserters. (Duh.)
  2. Yet still, Cargo Bays must be attached to the CLP, to allow for sufficient throughput from space.
  3. The primary inserters must be inventory to inventory, as they would slow down otherwise. (It takes 4 ticks for a belt to move all items out of a stack inserters hand)
  4. These inventories must be emptied immediately, as to never overflow, or stop the primary inserters by lack of space.
  5. There must be more inserters taking out of the inventories than there are primary inserters, as they necessarily must be slower at moving items.
  6. To ensure throughput on the train terminal, the items must be (mostly) ordered.
  7. A minimized footprint is preferred - because it allows to also use bots (possibly), because it makes it easier to put on planets with limited space, and because there are few things more enjoyable to me than to find entirely pointless space saves on my builds.
Chapter 2: Operating Principle
The output of the CLP is divided into 15 pairs of inserters. Each pair outputs into a cargo wagon, which provide the necessary surface area to fulfill constraint 5. Each of these pairs is adressed as one, providing 32 items per second of throughput for a selected item type.

Four additional inserters per cargo wagon provide the necessary inventory-to-belt-throughput. They output onto two belts. While one belt would be sufficient for the pair of inserters, two belts give leeway for blockage on the output belts, which otherwise would immediately lead to a drop in throughput.

A selection mechanism is employed to chose what item to output from the CLP. This mechanism selects both an item of which there is some configurable sufficient quantity, and an inserter pair that is currently without a job.
This amount and type is assigned as a job to that pair. The amount is also remembered as a negative bias, to prevent over-assigning.

The pair then counts the items it moved, and once the final items are picked up, signal themselves as ready for the next job. The selection mechanism is then quick enough to assign the next job before they finish their swing, leading to a seemless pickup of the next sufficient item.
Chapter 3: Entity Layout
To achieve sufficient throughput, two inserters insert into one cargo wagon (or two chests, where two inserters *then* insert into one cargo wagon). Four inserters then empty the cargo wagon onto a total of two output belts. The output onto these belts must be split between the sides of the belt for at least one of them, as otherwise it's just one belt full but with twice the belt count. This lead to a lot of micro-decisions about belt and inserter placement that I will not get into. Most likely, a lot of this can be improved.

To power the inserters, I originally wanted to use substations. They require too much space, so instead eight uncommon medium electric poles are used, to reach the middle primary inserters on each side. All other power poles are of common quality.

To minimize the footprint, all belts converge to one solid block of belts at the top. This makes the routing unnecessarily complicated. I will not apologize.

The necessary width of the construction is 8 (CLP) + 2 * (6 (wagon) + 3 (inserters) + 1 (chest) + 1 (belt)) = 30 tiles.
Three inserter pairs at the bottom plus two on each side need to be routed so that they reach the top. This makes fourteen belts that somehow get routed to the top. A few of these are trivial, as there is enough place on the outside side wagons for underground belts to be routed.
sensible-underground-belts.png
sensible-underground-belts.png (502.48 KiB) Viewed 1159 times
With a bit of weaving, a few more can be routed:
side-weaving-one.png
side-weaving-one.png (293.62 KiB) Viewed 1159 times
side-weaving-two.png
side-weaving-two.png (243.63 KiB) Viewed 1159 times
Finally, for the remaining few belts, we do the single most cursed thing I have done so far. You might have noticed at some point that you only need two rails to place a cargo wagon, which spans six tiles. So, technically 4 tiles are covered by the wagon, but the floor underneath it is free.
This allows you to place inserters where they really, *really* shouldn't be.
inserter-under-wagon.png
inserter-under-wagon.png (365.93 KiB) Viewed 1159 times
I have made liberal use of this.

Most of the rest of the routing is relatively straightforward. A lot of it is mandated by the goal of not widening the footprint - without it, it would be very easy to just go outwards more. Instead, I had to find space to move belts inwards, where the top wagons would create natural gaps if you were to route more liberally.

The heavy use of underground belts also buy space for the necessary wiring, which made it relatively easy to find space for all logic units.
logic-units-one.png
logic-units-one.png (476.25 KiB) Viewed 1159 times
Finally, the selection mechanism is spread out at the bottom of the construction, for a total footprint of 34x36 tiles, leading to thirty belts at the top, where each pair of adjecent belts transports the output of one primary inserter pair.
Chapter 4: Circuitry
To achieve arbitrary item throughput, the output of every pair of inserters must be selected dynamically. The logic here consists of three parts:
  • The local command circuitry (lcc), of which there is one per inserter pair
  • The item decision circuitry (idc)
  • The pair selection circuitry (psc)
To achieve perfect item throughput, the whole selection process must run within the span of one swing of an inserter arm, which is eight frames at legendary quality. Achieving this was the hardest part of the build (directly followed by assembling the logic at all).

All three components are joined together by a common green wire. The idc and psc closely work together.

I will go through these in order. The local command circuitry depends on the pair selection circuitry and vice versa, so I recommend reading both fully for comprehension.

Local command circuitry (lcc)
lcc.png
lcc.png (959.75 KiB) Viewed 1159 times
The lcc has the task to manage the current task of any given inserter pair. A task consists of an item type and an amount to move, given as a negative number.

The first part of the lcc is the ID generator. The ID generators of all lccs are wired in sequence to generate a unique id for each lcc. The id is simply a bit field which gets shifted in sequence, i.e. the first lcc has the id 1, the second the id 2, third is 4 etc. up to 16384 (2 to the power of 15). These ids enable the identification of each lcc to the pair selection circuitry.

While no task is given, the lcc outputs the id on a unique letter signal. Originally, the ids formed a bit mask of available inserter pairs, but the decoding was a frame too slow to allow this. When the psc selects this lcc, it transmits the up arrow with the id, as well as an item amount, for two ticks. The lcc stores these with the job counter decider combinator which discards all non negative values and feeds the rest into itself. Whenever the inserters pick up items, the amount is immediately deducted from the stored job on the wire. This leads to the job being done the very tick that the inserters *pick up* the last items, leaving seven more ticks to receive the next task.

From the point of view of the lcc, a task transmission looks like this:
  • Frame 1: The stored job amount reaches zero
  • Frame 2: The lcc letter goes on the common wire
  • Frame 3: Waiting...
  • Frame 4: Waiting...
  • Frame 5: The arrow signal is set to the lcc's ID for this and the next frame
  • Frame 6: The negative item amount goes into the job counter
  • Frame 7: The amount is multiplied by minus two and put on the inserter wire. Another combinator puts one more on the wire. Additionally, the amount goes into the counter a second time. This leads to the sum of the wires being exactly one, which sets the filter of the inserters.
  • Frame 8: The inserters parse the filter.
  • Frame 9: Beginning on this frame, the filter is active. The inserters pick up the next items without losing a single frame.


This new task is then executed until all items have been moved, which leads back to outputting the letter signal. If no task is assigned, the inserters idle until a task arrives.

Item decision circuitry (idc)
idc.png
idc.png (209.47 KiB) Viewed 1159 times
The item decision circuitry selects an item, of which there is a sufficient amount stored, to be extracted from the CLP. The first part is easy: A combinator system filters the available items according to a threshold. This is freely replaceable. In my case, a constant combinator selects a number of stacks, and a selector + decider + arithmetic combinator combo filter the signals for those that exceed that amount. These signals then get fed into a selector combinator that selects a random input, to ensure that all items get moved eventually. (It should be possible to build a system that prioritizes certain items, like perishables.)

The randomly decided signal then gets put into a holding cell, which is a R/S Latch that stores one set of signals until it gets reset, and as a bonus outputs the stored signal for exactly one frame on a separate wire. In this case, the selected signal gets put on the common wire and just remains there until reset.
holding-cell.png
holding-cell.png (97.21 KiB) Viewed 1159 times


Pair selection circuitry (psc)
psc.png
psc.png (427.47 KiB) Viewed 1159 times
This is the heart of the circuit, as it is the part I optimized the most to make this construction work. It has the goal of selecting which pair of inserters gets the next job. For this, an inserter id must be put on the up-arrow channel of the common wire. Additionally, both the psc and the idc need to be reset.

The overall process has five steps:

1. The signals on the common wire get filtered, so that only the letters which identify the lccs are made available to the rest of the circuit
2. A random letter is selected.
3. The letter gets translated into an arrow by a holding cell.
4. If an item amount is present, a reset signal is sent to both the psc and the idc holding cell.
5. A two frame lockout is initated, to give time for the letter signal to disappear from the common wire. The holding cell is reset, taking the next signal after the lockout.



This leads us to the overall sequence of events that leads to assigning a job.

The full selection sequence
  • Independently: A negative item amount goes on the common wire
  • Frame 1 (lcc): The stored job amount of an lcc reaches zero
  • Frame 2 (lcc): The lcc letter goes on the common wire
  • Frame 3 (psc): Non-letters are filtered from the common wire
  • Frame 4 (psc): A random letter is selected
  • Frame 5 (psc): The letters id is put on the bus as the arrow signal for this and the next frame
  • Frame 6 (lcc): The negative item amount goes into the job counter
  • Frame 7 (lcc): The filter of the inserters is set.
  • Frame 8 (lcc): The inserters parse the filter.
  • Frame 9: The filter is active and the inserters pick up the next items without losing a single frame.
Chapter 5: Usage Guide
With the mechanisms explained, here is a quick guide on how to use this in your own world.
For the most part, you can just plop down the blueprint and go. Make sure that all combinators are placed before setting the requests on the CLP.

In the blueprint as is, the selection of items happens by filtering for an amount of stacks set in the Stack Constant Combinator. For whatever you want to move, the total amount should be a multiple of 32 (or the amount a stack inserter can move, in the case of artillery shells for example), to ensure that the primary inserters can move the full amount.
stack-constant-combinator.png
stack-constant-combinator.png (99.82 KiB) Viewed 1159 times
The operation can also be modified:

Custom Selection

Selection happens every 5 ticks.
This means that there is a delay of 75 ticks (5 per pair) until all inserters are running after full depletion and a new shipment.
It takes 8 ticks to move 32 items. That means at least 160 items need to be moved per batch so that all inserters run permanently.

From this follows that the selection mechanism needs to, for maximum throughput, select 160 items at a time. Additionally, selections should happen in multiples of 32, as otherwise the stack inserters might stall due to missing input.

This selection has 5 ticks to take place, reading from the bias selector.

I would put a picture here but I ran out of available attachment slots. It's the idc selector with two "each".

Slowing down the selection means losing maximum throughput. Specifically, two items are lost per additional tick, spread out over the duration of moving the selected amount of items.
Or said differently, the throughput lost is negligable as long as the quantities moved are sufficiently large.

Reserving items

The bias selector can be used to remove items from the calculation. By inputting a negative amount for a single tick, that amount becomes reserved and will not be moved by further selections. This bias has to be cleared manually by inputting corresponding positive amounts for a single tick. This could, for example, be used for interacting with the logistics network in a way that does not interfere with normal operation.

I would put a picture here but I ran out of available attachment slots. It's the idc selector with two "each".

Operation with lower quality entities

The uncommon medium power poles are _required_ for operation. The primary inserters can be downgraded arbitrarily. The belts can be downgraded, the underground belts cannot.
Chapter 6: Prior Work
I actually only had two external inspirations.
First is Dosh Doshingtons video on not using belts, as inspiration for using train cars.
The second is Nilaus' video on a high throughput cargo landing pad, from where I stole the idea to put chests to get the train cars closer to the CLP.
Chapter 7: Q&A
Question 1: Why.

Because I can.

Question 2: No but why though.

I sometimes get those moments where I think, "this should be doable", and then I got to work on it until I have either proven or disproven it. This one started with the simple problem of moving items from the dock onto rails, and how to make it scale. And since there is a physical upper limit for the throughput without bots, I got stuck on thinking about what the best possible solution would even look like. About like, over a month later, here we are.

Question 3: What do you have against bots?


They are boring. It's easy to just throw bots at the problem, and it's also seldomly truly optimal. It also doesn't use trains, which are clearly better than bots, objectively. And before you suggest combining both, I already did that on Fulgora, so it would be boring to do it again.

Question 4: What else did you try?

My first approach was to make all inserter pairs independent. This failed due to the simultaneous selection problem: How can two independent logic units know what the other will do this frame? They might try to move the same item type. They cannot know, hence there needs to be a central decision unit.
Not having logic is out of the question, as it would make it impossible to ensure that all items get moved, or have any influence on which items get moved when, and it would lead to very, very mixed belts.

In the first design with a central control unit, I just iterated all ids because selecting ids seemed too painful. This is when the idea for bit masks came up, which also made the selection way easier. At that point, I was still working with common rarity inserters, so iterating for up to 15 frames was acceptable. I made an image post on that version, where a commenter pointed out that legendary inserters are faster. So I had to accelerate. It took a while to grind down from up to 23 frames to consistent 8 frames - but it worked. And that's where it's at.
adam_bise
Filter Inserter
Filter Inserter
Posts: 580
Joined: Fri Jun 08, 2018 10:42 pm
Contact:

Re: Cargo Landing Pad: Throughput-optimal 3.600 items/s without bots

Post by adam_bise »

DemRat wrote: Thu Feb 20, 2025 9:22 am Isn't it beautiful?
It is!
DemRat wrote: Thu Feb 20, 2025 9:22 am Additional benefits:
  • no bots
  • no bots
  • neigh incomprehensible
  • cursed
  • no bots
That does check all of the boxes.

DemRat wrote: Thu Feb 20, 2025 9:22 am I also, for no adequately explainable reason, don't want to use bots. Because I can.
See? To me this is adequate.
DemRat wrote: Thu Feb 20, 2025 9:22 am and because there are few things more enjoyable to me than to find entirely pointless space saves on my builds.
Starting to like this guy.
DemRat wrote: Thu Feb 20, 2025 9:22 am This makes the routing unnecessarily complicated. I will not apologize.
Love it!
DemRat wrote: Thu Feb 20, 2025 9:22 am sensible-underground-belts.png
I reject any and all sense of sarcasm here.
DemRat wrote: Thu Feb 20, 2025 9:22 am This allows you to place inserters where they really, *really* shouldn't be.
The crowning achievement. See? To me this is the focal point of the entire build. Beautiful.
DemRat wrote: Thu Feb 20, 2025 9:22 am I have made liberal use of this.
Absolutely!
DemRat wrote: Thu Feb 20, 2025 9:22 am Question 3: What do you have against bots?[/u]

They are boring.
QFT

Thank you, that was a pleasure to read and looks very interesting. The circuit parts went a bit over my head, but I do love overly-complicated monstrosities projects like these.
Post Reply

Return to “Show your Creations”