11부는 118 × 125 mm 판이었습니다. 이번엔 같은 프로젝트의 작은 쪽입니다. 88 × 90 mm 2층, 부품 39개. 220 V를 반파 정류해서 모터 브레이크 전자석에 넣고, 코일에 전류가 실제로 흐르는지 감시해서 상위 제어기에 신호 한 점을 돌려주는 판입니다.
게이트는 다 초록불이었습니다.
DRC 위반 0 · 미연결 0 · 회로도 패리티 0
절연 장벽 위반 0
연면·공간거리 3,514쌍 · 미달 0 · 예외 4(패키지 내부 핀)
라우팅 178구간 813.0 mm · 비아 26
그래서 저는 **“보드는 끝났고 이제 발주만 하면 된다”**고 생각했습니다. 그 말을 한 뒤에 여섯 가지가 나왔고, 그중 셋은 “끝났다”고 말하게 만든 검사 자체의 구멍이었습니다.

완성한 판의 3D 렌더입니다. 위쪽 계통 구역에 정류 소자와 큰 부품이, 아래쪽 저전압 구역에 감시 회로가 모여 있습니다.
절연 장벽 — 굵기 차이가 그대로 전압 차이입니다
본론에 들어가기 전에 한 장만 보겠습니다. 아래가 2D 아트웍인데, 가운데 가로로 지나가는 노란 선이 계통(위)과 SELV(아래)의 경계입니다. 위쪽 굵은 배선이 1.0 mm, 아래쪽 얇은 게 0.25 mm입니다.

11부에서 이 선을 재는 이야기를 길게 했으니, 여기서는 선을 다 지킨 다음에 무슨 일이 남았는지만 씁니다.
낡은 그림이 릴리스에 세 번 들어갔습니다
산출물을 폴더로 묶으면서 세 번 잡았습니다.
| 무엇 | 어떻게 걸렸나 |
|---|---|
| 거버가 보드보다 9분 오래됨 | 3D 모델을 고치고 거버를 다시 안 뽑았습니다 |
| BOM·2D 아트웍이 소스보다 오래됨 | 릴리스 묶다가 우연히 |
case_top.png가 옛 케이스(109 × 111) | 누가 “그림 안 보여준 것 같은데?” 하고 물어서 |
세 번 다 눈으로 훑다가 걸렸거나 못 걸렸습니다. 셋 다 파일 수정시각 하나만 봐도 잡히는 것들이었고요. 그래서 규칙을 코드로 옮겼습니다.
검사는 두 종류가 필요했습니다.
| 묻는 것 | 범위 | |
|---|---|---|
| 시각 순서 | 산출물이 그 소스보다 새것인가 | 쌉니다. 전부에 겁니다 |
| 재생성 대조 | 정말 그 소스에서 나왔는가 | 비쌉니다. 재생성 경로가 있는 것에만 |
두 번째가 통과하면 첫 번째는 사실 필요 없습니다. 그런데 첫 번째는 모든 산출물에 걸 수 있고, 두 번째는 다시 만들 방법이 있는 것에만 걸립니다. 그 차이가 뒤에서 문제가 됩니다.
첫 실행은 6항목 실패로 나왔습니다. 그리고 그 여섯 중 다섯이 제 검사기 잘못이었습니다.
거짓 경보를 따라갔더니 진짜가 있었습니다
“거버 재생성 대조 — 다름 9”. 아홉 장이 전부 다르다고 나왔습니다. 한 장을 열어서 줄 단위로 비교했더니 차이가 세 줄뿐이었습니다.
%TF.CreationDate,2026-09-07T14:55:27+09:00*% vs ...T16:15:39+09:00*%
%TF.ProjectId,fab_snapshot,6661625f-...*% vs %TF.ProjectId,brake_mon_220,...*%
G04 Created by KiCad (PCBNEW 10.0.5) date ... vs ... 16:15:39*
첫째와 셋째는 날짜입니다. 제 정규화에서 G04 ... Created by ... date 줄을
빼먹어서 생긴 거짓 경보였습니다. 구리는 같았습니다.
문제는 둘째 줄입니다. %TF.ProjectId가 **fab_snapshot**이었습니다.
제조소가 받는 거버의 프로젝트 이름이 제 임시 파일 이름이었던 겁니다.
왜 그런 파일이 있었냐면, kicad-cli는 보드를 건드리면 존(구리 채움)을 다시 채웁니다. 이 보드에는 GND 포어가 앞뒤로 둘 있어서, 그 재채움이 “아무도 재지 않은 보드”를 내보내는 길이 됩니다. 그래서 스냅샷을 떠서 거기서 뽑고 있었습니다. 그 판단 자체는 맞았는데, 파일 이름이 산출물에 박힌다는 걸 몰랐습니다. 게다가 출력 파일명에도 그 이름이 붙어서 나중에 이름을 되돌리는 루프를 따로 돌리고 있었습니다.
고치는 건 한 줄이었습니다. 스냅샷을 하위 폴더에 보드 이름 그대로 두면 됩니다.
SNAPDIR=out/fab_snap
SNAP=$SNAPDIR/$N.kicad_pcb # 파일명 = 보드 이름
리네이밍 루프도 같이 없어졌습니다.
거짓 경보를 그냥 끄지 않은 게 이번엔 이득이었습니다. “왜 저렇게 나왔지”를 한 번 더 따라갔더니 그 옆에 진짜가 붙어 있었습니다.
검사가 검사 대상을 건드렸습니다
두 번째와 세 번째 실패는 더 민망합니다.
재생성 대조는 생성기를 다시 돌립니다. 그런데 그 생성기가 out/의 정해진
자리에 씁니다. 그러니까 대조를 하는 순간 작업본이 덮이고 수정시각이 지금으로
밀립니다. 그러면 시각 순서 검사가 검사 때문에 깨집니다. 실측으로 세 항목이
그렇게 빨간불이 됐고, 내용은 멀쩡했습니다.
원본 바이트와 수정시각을 들고 있다가 대조가 끝나면 되돌리게 했습니다.
세 번째는 이겁니다. 시각 순서를 릴리스 폴더 안에서 보고 있었습니다.
cp는 복사본의 수정시각을 복사한 시각으로 새로 찍습니다. 그래서 릴리스
안에서 산출물과 소스를 비교하면 둘 다 “묶은 시각”이라 순서 정보가 통째로
사라집니다. 실제로 여섯 항목이 전부 -0 분으로 나왔습니다.
시각 순서는 작업 폴더에서 보고, 릴리스가 소스와 맞는지는 재생성 대조가 답하게 했습니다. 두 검사를 나눠 둔 이유가 여기서 살아났습니다.
함체 그림에는 다시 만들 방법이 없었습니다
case_top.png가 옛 케이스로 남아 있던 진짜 이유를 이때 찾았습니다.
함체 렌더에는 생성기가 없었습니다. KiCad에 붙일 WRL 모델을 그때그때 인라인 스크립트로 만들고, kicad-cli를 손으로 두드려서 그림을 뽑고 있었습니다. 그러니 기하가 바뀌어도 그림은 조용히 옛것으로 남습니다. 그리고 재생성 경로가 없으니 검사기가 걸 수 있는 건 수정시각 비교 하나뿐이었습니다.
고친 방향은 STL과 WRL을 같은 박스 목록에서 내는 것입니다. 슬라이서로 가는 STL과 렌더로 가는 WRL이 같은 기하에서 나오면, 이제 한쪽만 낡을 수가 없습니다. 그리고 렌더까지 한 줄로 가는 스크립트를 만들었습니다.

함체는 109 × 97 × 40.3 mm입니다. 직접 출력해서 쓰는 물건이라 뚜껑까지 제가 만들어야 했습니다.
만들면서 지적을 세 번 받았는데, 세 번 다 치수 하나만 보고 정한 것이 원인이었습니다. 처음엔 정사각형에 가깝게 만들어서 단자대가 벽에서 9.2 mm 떨어졌고 — 그 상태면 케이블을 꽂을 수가 없습니다. Y축을 낮춰 직사각형으로 바꾸고 단자대를 위아래 벽에 붙였습니다.

위에서 보면 좌우 벽의 배선구가 단자대 극마다 하나씩 뚫려 있는 게 보입니다. 벽 안쪽면에서 단자 인입면까지 2.23 mm — 벽이 곧 인입구입니다.

앞에서 자른 단면입니다. 보드 밑 4 mm가 스탠드오프, 위쪽이 부품 공간 30.2 mm (최고 부품 25.2 + 여유 5.0). 가운데 검은 덩어리가 AC-DC 컨버터입니다.
그리고 같은 실수를 한 번 더 했습니다. 나사 길이를 확인하려고 함체 생성기를 실행했는데, 그게 STL과 WRL을 다시 써서 수정시각이 밀렸고 검증이 또 깨졌습니다. 리포트를 보는 것과 파일을 만드는 것을 갈랐습니다.
py case88.py --report # 치수만 출력, 파일을 안 씁니다
품번 21개를 채웠습니다 — 지어내지 않고
여기까지가 검증이고, 여기서부터가 진짜 발주 준비입니다.
이 프로젝트에는 **“범용 수동소자는 품번을 지어내지 않는다”**는 정책이 있었습니다. 0805 저항이나 X7R 25 V에 벤더 코드를 박으면 구매처가 바뀔 때마다 BOM을 고쳐야 하고, 값이 확정되기 전에 박으면 낡은 코드가 남으니까요. 실제로 이 프로젝트에서 근거 없는 품번이 BOM에 실린 적이 있었습니다.
그런데 그 정책의 진짜 이유는 “근거 없는 품번을 박지 말라”는 것이지 “품번을 비워 두라”가 아니었습니다. 발주 게이트는 계속 빨간불이었고요.
[FAIL] BOM: components with MPNs (13/34)
유통사 API 자격증명이 없어서, 제조사 데이터시트를 직접 열어서 주문코드 규칙과 치수를 읽고 채웠습니다. 21줄, 한 줄도 기억으로 적지 않았습니다.
재미있었던 세 자리만 적습니다.
랜드가 부품을 골랐습니다
CS1은 10 µF / 50 V 전해입니다. 값만 보면 UPW1H100MDD가 맞습니다.
그런데 그 부품은 지름 5 mm에 리드 피치 2.0 mm입니다. 우리 랜드는
CP_Radial_D6.3mm_P2.50mm — 피치 2.5 mm입니다. 안 들어갑니다.
같은 계열에서 지름 6.3 / 피치 2.5로 올라가는 10 µF는 100 V 판이었습니다.
그래서 UPW2A100MED를 썼습니다. 전압을 올린 게 아니라 케이스를 맞춘 겁니다.
CS1의 실제 작동 전압은 옆의 제너가 잡는 15 V라 50이든 100이든 여유는 넘칩니다.
설계가 가정한 Vf를 부품이 지켜야 합니다
표시등 두 개는 설계가 Vf 2.0 V를 가정하고 저항을 정해 놨습니다. D8은 12 V에서 3.3 kΩ으로 3.0 mA, D10은 5 V 로직에서 1.5 kΩ으로 2.0 mA.
요즘 흔한 InGaN 순녹색은 Vf가 3.2 V입니다. 그걸 꽂으면 D10 전류가 2.0 → 1.2 mA로 떨어집니다. 그래서 AlGaInP 계열로 골랐습니다.
| 품번 | Vf typ | 실제 전류 | |
|---|---|---|---|
| D8 (PWR) | APT2012MGC | 2.1 V | (12 − 2.1)/3.3 k = 3.0 mA |
| D10 (CURRENT) | APT2012SURCK | 1.95 V | (5 − 1.95)/1.5 k = 2.0 mA |
설계 주석에 적혀 있던 숫자와 그대로 맞았습니다.
이름이 비슷한 게 제일 위험합니다
퓨즈 사양은 “세라믹 HBC 차단용량 1500 A 이상 @ 250 VAC, IEC 60127-2 sheet 5”
였습니다. 홀더가 Schurter라 같은 회사 퓨즈를 찾았는데, 검색에 제일 먼저 걸린
FST 5x20은 유리관에 저차단이었습니다. 5 × 20이라는 치수가 같아서
그대로 쓸 뻔했습니다.
맞는 건 SPT 5x20입니다. 데이터시트에 이렇게 적혀 있습니다.
Time-Lag T, H = High Breaking Capacity (Ceramic Tube)
IEC 60127-2/5 · 250 VAC
각주 1) IEC: H = 1500 A @ 250 VAC, p.f. 0.7 - 0.8
1 A는 0001.2504. 주문표에서 1.6 A가 0001.2506인 걸로 자릿수를 교차확인했습니다.
이 프로젝트에는 손으로 적은 품번이 값과 10배 어긋나 있던 전례가 있습니다.
랜드가 없으면 세어지지 않습니다
품번을 채우다가 이게 나왔습니다. BOM에 퓨즈가 없었습니다.
BOM은 보드에 놓인 풋프린트를 세서 만듭니다. 그런데 F1 자리의 풋프린트는 클립 홀더입니다. 퓨즈 자체는 그 클립에 끼우는 소모품이라 랜드가 없고, 그래서 세는 기준에 아예 안 잡혔습니다. 함체 뚜껑 나사 4개도 같은 이유로 없었습니다.
랜드가 없다고 사지 않아도 되는 게 아닙니다. 퓨즈가 없으면 보드가 동작하지 않고, 뚜껑 나사가 없으면 함체가 안 닫힙니다.
같은 장에서 두 개가 더 나왔습니다.
D8과 D10이 한 줄로 뭉쳐 있었습니다. 둘 다 값이 LED라서요. 품번이 다른데
값으로만 조회하면 둘 중 하나가 사라집니다. 위의 표에서 녹색과 적색을 나눈 게
이걸 고친 다음입니다.
회로도의 품번 필드가 39개 부품 중 14개뿐이었습니다. 품번 표만 고치고 회로도를 다시 안 만들면, BOM은 새 값을 쓰고 회로도는 옛 값을 들고 있습니다. 둘 다 산출물이라 받는 사람에 따라 다른 부품을 사게 됩니다. 회로도를 다시 만들어서 39/39로 맞췄습니다.
결과 — 품번 34/34, 릴리스 17항목 통과
최종 수치입니다. 시작과 끝만 놓고 보면 이렇게 됐습니다.
| 항목 | 시작 | 끝 |
|---|---|---|
| 품번이 있는 부품 | 13 / 34 | 34 / 34 |
| BOM 줄 수 | 29줄 | 32줄 · 전 줄 확정 품번 |
| 회로도 품번 필드 | 14 / 39 | 39 / 39 |
| 릴리스 검증 | 6항목 실패 | 17항목 전부 통과 · 174 파일 22.5 MB |
| DRC | 위반 0 · 미연결 0 | 변화 없음 |
남는 생각 — 검사가 안 보는 곳
11부에서는 자가 두 개인데 그걸 모를 때가 제일 위험하다고 썼습니다. 이번에는 조금 다른 게 나왔습니다.
“다 됐다”고 말하게 만든 검사들이, 실은 자기가 못 보는 자리를 갖고 있었습니다.
- 풋프린트를 기준으로 세면 → 랜드 없는 부품이 조용히 빠집니다
- 값을 기준으로 조회하면 → 값이 같고 품번이 다른 부품이 뭉칩니다
- 릴리스 폴더 안에서 수정시각을 보면 →
cp가 순서를 지웁니다 - 재생성 경로가 없는 산출물은 → 낡아도 물어볼 방법이 없습니다
넷 다 “검사가 틀렸다”가 아니라 **“검사가 안 보는 곳이 있다”**는 종류입니다. 그래서 결과가 늘 초록불이었고요.
이번에 진짜 얻은 건 품번 21개가 아니라 릴리스를 한 줄로 다시 물어볼 수 있게 된 것 같습니다. 산출물마다 다시 만드는 명령이 하나씩 생겼고, 그게 있으니 “낡았나?”를 눈으로 훑지 않아도 됩니다.
그리고 하나 더. 이 판에서 남은 진짜 열린 항목은 단자대 정격이 사내 기록에 없다는 것입니다. 사내 부품이라 제조사 품번이 존재하지 않고, 라이브러리 주석에 “공급처에 확인할 것”이라고 적혀 있습니다. 지어내지 않고 그대로 남겨 뒀습니다.
품번을 채우는 일에서 제일 중요한 건 채우지 말아야 할 자리를 아는 것입니다.
🔧 시리즈 전체: 1부 · 2부 · 3부 · 4부 · 5부 · 6부 · 7부 · 8부 — 완성 · 9부 — 리뷰 · 10부 — 배치 루프 · 11부 — 절연 장벽
문의
- Email : [email protected]
- Insta : https://www.instagram.com/going.sen/
- Website : https://intosen.com/kr/consult/
댓글
닉네임만 입력하면 바로 댓글을 남길 수 있어요. Google/GitHub 로그인도 가능합니다.