글을 쓴 계기 : https://gall.dcinside.com/mgallery/board/view/?id=factorio&no=28439

저 질문글을 보고 능동형공급상자 같은걸 LTN으로 구현하려면 어떻게 할지 고민하다가 저 댓글에 네트워크 분리하라는 팁을 보고 한번 체계적으로 정리를 해보고 싶었음



로봇 물류 시스템


일반적인 로봇 물류시스템은 6종류로 구성이 되어있음

능동형공급상자, 수동형공급상자, 보급상자, 완충상자, 요청상자 그리고 플레이어


이중에서 보급상자, 완충상자, 플레이어는 요청도 하고 공급도 한다는 특징을 가지고있음

각 요소의 요청 우선 순위는 다음표와 같음



공급

요청

플레이어 공급


5

플레이어 폐기

5


능동형 공급 상자

4


요청 상자


4

완충 상자

3

3

보관 상자

2

2

수동형 공급상자

1


숫자가 클수록 더 우선적으로 처리가 되게 되어있음

그것과는 별개로 표의 색을 칠했는데 색의 의미하는것 다음과 같다


보라색 : 능동공급

빨간색 : 수동공급

파란색 : 능동요청

노란색 : 수동요청


즉 완충상자는 수동공급상자와 능동요청상자를 합쳐놓은 형태

보관상자는 수동공급상자와 수동요청상자를 합쳐놓은 형태라고 볼 수있음


수동요청이라는 말은 좀 임의로 붙인 말이긴 한데 의미상으로 틀리진 않은것 같아서 사용했음


물류 상자를 능동공급, 수동공급, 능동요청, 수동요청이 있다고 보면 물류의 이동은 다음과 같이 이루어짐


능동공급 -> 능동요청 (O)

능동공급 -> 수동요청 (O)

수동공급 -> 능동요청 (O)

수동요청 -> 수동요청 (X)


수동에서 수동으로의 이동은 이루어 지지 않음

수동요청상자(보관상자)로 물건이 이동하는 경우는 오로지 능동공급하는 무언가가 있는데 그것을 능동적으로 요청하는 것이 없을 때 최후로 선택되는 상자의 역할이 됨




LTN 물류 시스템


로봇시스템에는 능동공급, 수동공급, 능동요청, 수동요청들을 할 수 있지만

LTN역은 그런거 없고 기본적으로 단 두 종류만 있음

수동공급역 그리고 능동요청역

즉 일반적으로 생각했을 때는 로봇물류에서 보관상자(수동공급+수동요청), 완충상자(수동공급+능동요청)에 해당하는 기차역을 구현 할 수 없다는 뜻이 됨


그럼 정녕 LTN에서는 보관역을 구현할 수 없는걸까?

여기서 LTN Network ID가 등장한다.




LTN Network ID



보통은 네트워크 ID의 개념을 몰라도 LTN을 사용하는데는 큰 지장이 없다.

역 설정시에 해당 신호를 넣어주지 않으면 기본값으로 ID는 -1을 사용하도록 되어있다.(기본값은 모드 설정에서 변경 할 수도 있다)

네트워크 ID가 하는일이 무엇이냐면, 공급역과 요청역의 네트워크를 참고해서 서로 같은 네트워크에 속해있을 때만 경로를 생성하기 위해 사용된다.


예를 들자면

네트워크 ID가 1인 공급역과 네크워크 ID가 1인 요청역이 있다면 경로가 생성되지만

네트워크 ID가 1인 공급역과 네크워크 ID가 2인 요청역이 있다면 경로가 생성되지 않는다.


그렇다면

네트워크 ID가 5인 공급역과 네크워크 ID가 12인 요청역이 있다면 경로가 생성이 될까 안될까?





답은 생성이 된다.

애초에 생성이 안된다면 이런 질문을 하지도 않았을 것이다.


네트워크 ID가 의미하는 것은 숫자 그자체가 네트워크를 의미하는 것이 아니라 숫자의 각 비트가 네트워크를 나타내도록 되어있다.

그래서 신호이름도 그냥 네트워크 ID가 아니라 인코딩된 네트워크 ID 인 것.


5을 2진법으로 쓰면 101이다.

12를 2진법으로 1100이다.

덤으로 -1을 2진법으로 쓰면 111111111111111111111111111111 이다.


이걸 한번 아래와 같은 표로 나타내보자

Net

32

31

30

29

28

27

26

25

24

23

22

21

20

19

18

17

16

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

5

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

1

0

1

12

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

1

1

0

0

-1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1


좀 보이는가?

네트워크 ID를 5로 한다면 그 역은 LTN 네트워크 1, 3번에 속하게 되는 것이다.

마찬가지로 네트워크 ID를 12로 한다면 그 역은 LTN 네트워크 3, 4번에 속하게 된다.

즉 ID 5와 ID 12는 둘다 네트워크 3번에 속하기 때문에 열차 경로가 생성이 된다.


참고로 ID를 -1로 한다면 1~32 모든 네트워크에 속하게 되므로 어떤 역하고도 소통을 할 수 있게 된다.


만약 LTN외에 추가로 LTN Combinator 모드를 사용한다면 아래와 같은 인터페이스를 볼 수 있다

21=16+4+1이므로 2진법으로 나타내면 0000...00010101 이므로 1,3,5 네트워크에 속하게 되는것




LTN Network ID를 이용한 능동공급역, 수동요청역 구현


위에서도 말했듯이 LTN에는 수동공급역과 능동요청역만이 존재한다.

즉 능동공급역도 수동공급역을 이용해 만들어야하고

수동요청역도 능동요청역을 이용해 만들어야한다.


만약 Network ID를 하나로 통일해서 쓴다면 이런것은 불가능하다.

(아래 사진에 보관상자를 깐 역은 수동요청역을 의미한다)

ID가 통일되어 있기 때문에 수동공급역으로부터 수동요청역으로의 물류이동이 발생해 버리는 것.


하지만 ID를 이용하여 능동공급역과 수동공급역에 사이에만 전용네트워크를 따로 할당하면 대책이 보이게 된다.


다음 예시에서는 1번 네트워크를 이러한 용도로 사용할 것이고, 일반적인 물류이동에는 2번 네트워크를 할당할 것이다.


이렇게 설정하면 수동공급역에서 수동요청역으로의 경로는 생성되지 않는다.

근데 뭔가 이상하다. 이상태로라면 능동공급역에서 능동요청역으로의 경로도 생성되지 않게 된다.


올바르게 동작하기 위해서는 능동요청역은 네트워크1과 네트워크2에 동시 접속이 되어야 한다.

즉 ID를 3으로 주면 된다.


이렇게 능동공급역과 수동요청역을 구현하는 것까지 달성되었다.



보관역의 구현



보관역(의 상상도)


로봇물류에서의 보관상자가 수동공급+수동요청의 기능을 하듯이

보관역은 수동요청역과 수동공급역의 두개의 역을 이용해 구성하게 된다.

역을 두개 세워 놓고 그사이에 거대한 버퍼를 두면 된다.

위의 예시는 그냥 간단하게만 만든것일 뿐이고 실제로 보관역을 운용할 것이라면 매우매우 거대한 버퍼를 만들게 될것이다.

그걸 설계하는 것도 꽤 머리를 써야할 것같지만 이 글에서는 생략하도록 하겠다.


보관역을 진정한 쓰레기통을 만들고 싶은것이라면 수동요청역은 게임에 존재하는 모든아이템들...에 대하여 요청을 걸어두면 된다...

요청수량은 마이너스 무한으로 잡아둔다면 온갖 쓰레기들을 끌어들일 것이다.


로봇물류에서 보관상자가 수동형공급상자보다 공급 우선순위를 가지는 것처럼

보관역에 있는 수동공급역도 실제 물품 생산지의 수동공급역보다 공급 우선순위를 높게 설정하는 것이 좋을 것이다.




능동공급역의 구현


위의 내용을 잘 이해해왔다면 의문을 가질수 있다.

능동공급역은 그냥 네트워크만 1번으로 설정하면 끝 아니야?

유감스럽지만 그렇게 쉽게 해결되지 않는다


다음과 같은 상황을 생각해보자



LTN Combinator로 캡쳐하긴 했는데 LTN combinator 없이 LTN만 사용해본 사람도 이해에는 지장 없을거임


1번 구역 - 능동공급역

A 생산품을 초당 100개 생산함

부산물로 B 생산품(위의 사진에서는 돌)이 초당 50개 나옴

B가 소비되지 않아 A가 같이 막히는 일이 발생해서는 안되므로 B를 능동공급하고자 함

공급우선순위는 2로 설정


2번 구역 - 보관역(수동공급+수동요청역)

쓰레기 보관소

위에서 설명한 보관역 방식을 사용함, 능동공급역으로부터 물건을 받을 수 있음

공급우선순위는 1로 설정(1번 구역에 비해 우선순위가 낮기 때문에 1,2번 구역에서 동시에 공급을 하면 1번 구역부터 처리됨)

요청우선순위는 1로 설정

쓰레기를 무제한으로 요청해야 하므로 Output에 돌을 -1,000,000,000 으로 설정해뒀음


3번 구역 - 능동요청역

B 물품을 최대 초당 70개 소모하여 다른 물건 C를 만듬

단 이곳의 생산량은 일정하지 않아서 제작이 이루어 지지 않을 수도 있음(다이소 등)

요청우선순위는 2로 설정(2번 구역에 비해 우선순위가 높기 때문에 쓰레기장보다 우선적으로 요청됨)

돌을 적절하게 요청하도록 Output에 돌을 -30,000으로 설정함



상황을 가정해봄
1번 구역은 쉬지않고 돌아가고 있음 B 아이템이 초당 50개가 나온다
3번 구역에서는 B아이템을 초당 70개까지 처리가 가능하지만 현재 3번 구역에서 생산한 아이템C의 수요가 없어서 B 아이템 수요도 없는 상태임
결국 1->3 으로의 요청도 없어지고 이 물건은 1->2의 요청으로 인해 보관역에 B아이템이 쌓이게 된다
이상태로 시간이 좀 지나서 보관역에 B아이템이 10만개 쌓여있는 상태라고 생각하자
이상태에서 3번 구역이 풀가동하기 시작할때 어떻게 돌아가는지 알아보자

- 이상적인 동작

3번 구역은 초당 70개를 처리할수 있는데 1번 구역에서는 초당 50개를 공급해줄 수 있음

2번보단 1번의 공급우선순위가 높으므로 1->3경로로 초당50개꼴의 운반을 하면 되고

초당 20개 분량이 모자라므로 2->3의 경로로 초당20개꼴의 운반을 하기를 기대하고 있음


- 실제 동작

1번 구역에선 공급 임계치를 1000으로 설정한 상태임

즉 B아이템이 1000개가 쌓일때마다 경로 생성을 시도하는데 문제는 2번 구역의 요청량을 마이너스 무한으로 설정한 상태기 때문에 2번 구역은 언제나 요청을 발생시킬수 있다는 것임

1번 구역에서 공급을 발생시키는 순간과 동시에 3번 구역이 요청을 하지 않는 이상 2번 구역은 3번 구역보다 우선 순위가 낮음에도 불구하고 1번 구역에서 발생한 공급 물량을 가져가게 된다


3번 구역에서는 목표 요구치를 3만개로 설정하고 요청임계치를 1000으로 설정한 상태임

즉 보유수량이 29000개 이하로 떨어질때마다 요청을 발생시킴

하지만 1번 구역은 위에서 말한대로 1000개가 쌓이는 즉시즉시 방출 시키고 있으므로 1번 구역으로 요청을 못날림

그래서 2번 구역으로만 요청을 날리게 된다.


1->3 요청이 발생하기 위해서는 1번의 공급과 3번의 요청의 아다리가 맞아 떨어져야 하는데 1번이든 3번이든 요청이 발생하는 순간 2번 보관역은 항상 그 요청을 받아들일 수 있기 때문에 결국 1->3 요청이 발생할 수 없게 된다.


그래서 실제 동작은


1->2 초당50개 꼴

2->3 초당70개 꼴


의 꼴로 돌아가게 된다.


이상적인 케이스는 초당 70개정도만 운송하면 됐는데 실제로는 괜히 초당120개를 운반을 하게 되어서 효율이 떨어진다.

1,3번 구역이 인접해있고 2번 구역이 혼자 멀리 떨어진 상태라면 낭비는 더더욱 심해질 것이다




제대로 된 능동공급역의 구현


위의 문제를 해결하기 위해선 어떻게 하느냐

결국 근본적인 문제는 1번 구역-> 2번 구역의 경로가 계속 생성이 된다는게 문제임

따라서 이를 해결하기 위해선 1번 구역의 공급역을 2개로 쪼갤 필요가 있다.

수동공급역과 능동공급역을 각각 만들고 분배기 우선출력기능을 쓰든 뭘하든 해서 수동공급역의 버퍼상자에 물건이 먼저 차게 하는것이다

수동공급상자의 버퍼가 가득차면 그때서야 능동공급역의 버퍼상자에 물건이 차기 시작할꺼고 여기에 쌓인 물건은 쌓이는 족족 보관역으로 배출 될 것이다.


이런식으로 구성한다면 하단의 역에 먼저 물건이 찰 것이고 하단의 역은 1번네트워크가 아닌 2번 네트워크에 연결되어 있으므로 보관역으로의 이동이 발생하지 않는다

따라서 정상적으로 1->3의 요청이 생길 것이다

하단 역에 물품이 가득차고 상단 역에 쌓이기 시작한다면 그 물품은 족족 보관역으로 배출될 것이다.


다 좋은데 문제가 하나 있다. 역을 두개나 만들어야 한다는 것이다




진짜 제대로 된 능동공급역의 구현


위와 같이 하나의 역을 설치한다

단 수량비교 조합기가 추가로 필요하다

수량비교조합기에는 능동공급하고자 하는 아이템을 설정하고 능동공급 하고 싶은 시점의 임계치를 설정해준다

결국 수동공급에대한 임계값과 능동공급에대한 임계값을 각각 설정하는 것이다.

수량비교조합기의 출력으로는 '인코딩된 네트워크 ID' 신호를 1로 선택한다.


이렇게 구성을 하게 된다면 B물품이 창고에 쌓이게 되고 1000개 이상이 된 순간 공급을 발생시키게 된다.

하지만 이시점에서의 인코딩된 네트워크 ID는 2이므로 보관역으로 가는 경로는 발생하지 않는다.

따라서 이 시간이 유지되고 있는사이에 3번 구역에서 요청을 발생시킨다면 정상적으로 1->3의 경로가 생기게 된다.


만약 3번 구역에서 요청을 발생시키지 않는다면 1번 구역의 창고에 B물품이 계속해서 쌓이게 될 것이다.

이러다가 10,000개 이상이 쌓이게 되면 수량비교조합기가 '인코딩된 네트워크 ID' 신호 1을 내보내게 된다.

즉 해당 LTN역의 '인코딩된 네트워크 ID' 신호 값은 2+1=3 이 되고 이는 1번네트워크와 2번네트워크에 동시에 연결됨을 의미한다.

이렇게 되면 2번 구역 보관역으로의 경로가 생성될 수 있어서 1번 구역의 버퍼가 가득차는 것을 막을 수 있다.


이러한 방식으로 구현하기 위해서는 능동폐기라인의 LTN 네트워크는 1번을 사용하는 것이 권장된다.

수량비교조합기에서 1이라는 상수값을 뱉는건 쉬워도 다른 값으로는 설정하기 힘들기 때문이다.

2~32 네트워크는 사용자의 의도에 따라서 적절히 네트워크를 배치하고 1번만 폐기전용라인으로 사용하면 된다.




완충역?


LTN에서 보관역은 좀 의미가 있다해도 완충역에 큰 의미가 있을까 싶어서 자세한 설명은 생략한다.

굳이 구현하려면 보관역을 수동요청+수동공급역으로 구성한 것처럼 능동요청+수동공급역 식으로 구성하면 되지 않을까 싶다.

단, 로봇물류 요청상자를 보면 '완충상자에서 요청' 이라는 옵션이 있는데 이것까지 구현하려면 머리는 좀 더 굴려야할 듯




참고용 데모 영상



이 영상에서는 다음과 같은 공정이 있음



빨간구역 1번

사피라이트 광석분쇄

출력 : 120 분쇄된 사피라이트 광석/s , 60 분쇄된 돌(부산물)/s


빨간구역 2번

물 전기분해->분쇄된 돌

출력 : (최대) 60 분쇄된 돌/s


파란구역 1번

사피라이트사용

입력 : (최대) 180 분쇄된사피라이트광석/s


파란구역 2번

분쇄된 돌->돌->매립

입력 : (최대) 80 분쇄된 돌/s


노란구역-보관역

초록구역-대기역


영상에서 사피라이트는 크게 중요하지않음

항상 풀로 사용한다고 가정하고 영상에서는 그냥 무한상자에 넣어서 버리고 있음


실제로 중요한건 분쇄된 돌인데 빨간1구역에서는 분쇄된돌이 부산물로 나오고 있고 2구역에서는 주 생산품으로 나오고있음

분쇄된 돌을 처리하는곳은 파란2구역인데 여기선 초당 80개까지 처리가 가능하므로

부산물로 나오는 분쇄된 돌을 우선적으로 처리(초당 60), 그러고 남는 부분을 분쇄된 돌 주생산 라인에서 가져와서 처리하는 방식임(초당20)


2번 구역에서는 최종생산품으로 매립을 만들고 있는데 매립은 지속적으로 소모가 되는 아이템이 아니므로 어느순간 버퍼가 막힐 수가 있음

이러면 분쇄된 돌이 더이상 사용되지 않기 때문에 빨간1구역에서 만드는 분쇄된 돌 또한 갈곳이 없어짐

하지만 이 영상에서는 보관역을 만들었기 때문에 남는 분쇄된 돌은 전부 보관역에 가져가다 버리게 된다

하지만 빨간2구역에서 만드는 분쇄된돌은 폐기 네트워크가 아니기 때문에 쓸때 없이 과생산해서 보관역에 가져다 버리는 일은 발생하지 않음

따라서 사피라이트는 끊임 없이 공급이 가능해진다.


만약 매립을 소모해서 매립 공장이 다시 가동되기 시작한다면

부산물로 나오는 분쇄된 돌을 우선적으로 처리(초당 60), 그러고 남는 부분을 보관역에 쌓인 돌을 가져와서 가져와서 처리함(초당20)

빨간2구역은 보관역에 분쇄된 돌이 남아 있는한 여전히 추가 과생산을 하지 않음

이러다가 보관역의 돌이 거덜나면 다시 빨간2구역이 가동을 시작할 것임



마무리


이 글에서 등장하는 역의 종류는

능동공급역(부산물), 수동공급역(주생산), 수동요청역(보관역), 수동공급역(보관역), 능동요청역(사용처)

들이 있음


대충 이 글에서 추천하고자 하는 설정의 테이블은 아래와 같음


역 종류

인코딩된 네트워크ID

요청/공급 우선순위

기타

능동요청역(사용처)

3

2

필요한 수량만큼 요청

수동요청역(보관역)

1

1

마이너스 무한(실제로는 최대 약 -21억)만큼 요청





능동공급역(부산물)

2(+1)

3

(+1)은 수량비교조합기의 출력을 연결

수동공급역(보관역)

2

2


수동공급역(주생산)

2

1



기본 틀을 이렇게 하고 추가적으로 자신에게 맞게 변경할것 있으면 조율하는 식으로하면 무리 없이 잘 돌지 않을까 싶음