13년차의 서버실

서버, 인프라, 홈랩 기술 블로그

[태그:] 3D프린터 펌웨어

  • [3D Printer] Klipper 오류: MCU ‘Unable to Connect’ 문제 진단 및 해결 가이드

    [3D Printer] Klipper 오류: MCU ‘Unable to Connect’ 문제 진단 및 해결 가이드

    Klipper 오류: MCU ‘Unable to Connect’ 문제 진단 및 해결 가이드

    Klipper 오류 중에서 제일 오래 붙잡히는 유형이 대개 MCU 연결 실패입니다. 화면에는 Unable to Connect 한 줄만 뜨는데, 실제 원인은 한 가지가 아니거든요. 저는 이 문제를 볼 때 장치가 안 보이는 문제, 장치는 보이는데 설정이 틀린 문제, 설정까지 맞는데 프로토콜 단계에서 붙지 않는 문제를 먼저 분리해서 봅니다.

    이번 글은 그 세 층을 나눠서 정리합니다. 그냥 재부팅만 반복하는 방식보다, 장치 열거(enumeration) – 경로 고정 – 로그 확인 – 포트 점유/권한 – 펌웨어 정합성 순서로 좁혀가면 훨씬 덜 헤매더라고요. 실제로 제가 먼저 보는 명령어와 로그 포인트, 그리고 이럴 땐 A, 저럴 땐 B라고 판단하는 기준까지 같이 정리해보겠습니다.

    Klipper 오류와 MCU 연결 문제 구조를 설명하는 전체 아키텍처 이미지

    Klipper 호스트와 프린터 보드가 어떤 경로로 연결되는지 한눈에 보여주는 개요 이미지입니다.

    1. Klipper 오류, MCU 연결이 어디서 끊기는지부터 나눠 봐야 합니다

    Klipper 연결 실패는 보통 세 단계로 나눠 보면 정리가 빨라집니다.

    • 1단계: 호스트가 보드를 발견했는가 – /dev/serial/by-id/ 또는 /dev/serial/by-path/에 장치가 생기는지
    • 2단계: Klipper가 올바른 장치를 열고 있는가 – printer.cfg의 [mcu] 아래 serial: 값이 실제 장치와 일치하는지
    • 3단계: 장치를 열었는데도 통신이 실패하는가 – 잘못된 펌웨어 대상, 플래시 실패, 포트 점유, 호스트/MCU 소프트웨어 불일치 같은 문제

    이 분류가 중요한 이유가 있습니다. 장치 자체가 안 보이는데 printer.cfg만 계속 수정하면 시간이 버려지고, 반대로 장치는 보이는데 케이블만 계속 바꾸고 있으면 해결이 안 되죠. 증상은 비슷해도 원인 계층이 다르기 때문입니다.

    실제로 Unable to Connect가 뜨는 흔한 원인은 대체로 아래 범주에 들어갑니다.

    • 장치 경로가 틀렸습니다. /dev/ttyUSB0, /dev/ttyACM0 같은 가변 이름을 고정값처럼 쓴 경우가 대표적입니다.
    • printer.cfg의 serial: 값이 현재 보드와 다릅니다. 플래시 후 USB 식별명이 바뀌었는데 예전 경로를 그대로 쓴 경우가 많습니다.
    • 펌웨어가 보드와 맞지 않거나 플래시가 제대로 완료되지 않았습니다.
    • Klipper 호스트와 MCU 펌웨어가 서로 맞지 않습니다. 호스트만 업데이트하고 MCU는 예전 빌드인 상황이 여기 걸립니다.
    • 포트 권한 또는 포트 점유 문제가 있습니다. Klipper 외 프로세스가 장치를 잡고 있거나, 서비스 계정이 장치에 접근하지 못하는 경우죠.

    핵심만 먼저 말씀드리면, 장치가 보이는지 확인하기 전에는 설정을 고치지 말고, 설정이 맞는지 확인하기 전에는 재플래시부터 가지 않는 것이 가장 덜 돌아가는 루트입니다.

    2. Klipper 트러블슈팅은 증상별로 첫 확인 지점이 다릅니다

    제가 현장에서 자주 쓰는 판단표는 아래 형태입니다. 중요한 건 원인을 외우는 게 아니라, 다음 한 번의 확인으로 어떤 가설을 버릴 수 있느냐입니다.

    관찰된 증상 먼저 확인할 것 유력한 원인 추천 조치
    웹 UI에 Unable to Connect만 표시 ~/printer_data/logs/klippy.log 또는 /tmp/klippy.log 경로 오기입, 장치 미인식, 포트 열기 실패 로그 문구를 기준으로 장치 존재 여부부터 분리
    재부팅 뒤 갑자기 연결 불가 [mcu]의 serial: /dev/ttyUSB0, /dev/ttyACM0 같은 가변 경로 사용 /dev/serial/by-id/로 교체
    플래시 직후부터 접속 불가 플래시 후 새 장치명 재확인 USB 식별명 변경, 부트로더 상태, 잘못된 보드 대상 ls /dev/serial/by-id/*를 다시 실행하고 경로 갱신
    Permission denied 류 문구 장치 파일 소유 그룹과 서비스 실행 사용자 시리얼 장치 접근 권한 문제 실제 그룹명 확인 후 해당 사용자에 권한 추가
    make flash만 실패 Klipper 서비스 정지 여부, 보드별 플래시 방식 포트 점유, 수동 플래시 필요, 부트로더 진입 실패 서비스 중지 후 재시도, 안 되면 보드별 수동 절차 확인
    업데이트 후 연결 이상 호스트 업데이트 여부와 MCU 재플래시 여부 호스트와 MCU 소프트웨어 불일치 필요 시 make clean 후 재빌드 및 MCU 재플래시

    실전에서는 여기서 한 단계 더 들어가면 좋습니다. 장치가 안 보이면 물리/USB 계층, 장치는 보이는데 경로가 안 맞으면 설정 계층, 경로까지 맞는데 안 붙으면 펌웨어/점유/권한 계층으로 끊어서 보시면 됩니다. 이렇게 나누면 범위를 절반씩 줄여갈 수 있어서 진짜 편합니다.

    3. 실전 진단 1단계: MCU 장치가 실제로 열거되는지 확인

    여기서는 느낌으로 보면 안 됩니다. 호스트 OS가 보드를 장치로 만들었는지를 먼저 확인해야 합니다. Klipper 공식 문서도 /dev/serial/by-id/* 사용을 권장하고, 저도 이 경로를 기본으로 봅니다. 이유는 단순합니다. ttyUSB0, ttyACM0는 순서가 바뀌면 이름이 달라지지만, by-id는 장치 식별자를 기준으로 잡히기 때문입니다.

    1. SSH로 Klipper 호스트에 접속합니다.
    2. 장치가 고유 ID로 보이는지 확인합니다.
    3. 아무것도 안 보이면 커널이 장치를 감지했는지까지 확인합니다.
    ls /dev/serial/by-id/*
    ls /dev/serial/by-path/*
    dmesg | tail -n 50
    # dmesg 접근이 막히면
    sudo dmesg | tail -n 50

    여기서 판단 기준은 꽤 명확합니다.

    • by-id가 보이면: USB 열거는 성공한 겁니다. 이제 설정과 포트 점유 쪽으로 넘어가면 됩니다.
    • by-id는 없고 by-path만 보이면: CH340 계열처럼 고유 ID가 애매한 경우를 의심해볼 수 있습니다. 이런 환경에선 by-path를 차선책으로 씁니다.
    • 둘 다 안 보이면: 이 시점에는 printer.cfg를 만질 이유가 거의 없습니다. 케이블, 전원, USB 포트, 보드 부트 상태를 먼저 봐야 합니다.

    제가 특히 강조드리고 싶은 포인트가 하나 있습니다. 플래시 전의 장치명과 플래시 후의 장치명이 같을 거라고 가정하지 마세요. 공식 설치 문서도 플래시 후 장치명이 바뀔 수 있으니 다시 확인하라고 안내합니다. 이거 한 번 놓치면 펌웨어는 정상인데 경로만 예전 값을 보고 있어서, 재플래시 실패로 오해하기 쉽더라고요.

    보드가 여러 개인 환경이라면 더 엄격하게 보셔야 합니다. 메인보드와 USB 가속도계, 별도 MCU가 같이 꽂혀 있으면 장치 목록이 여러 줄 나옵니다. 이럴 때는 케이블을 하나씩 빼고 다시 같은 명령을 실행해서 어떤 항목이 사라지는지 확인하는 방식이 제일 정확합니다.

    SSH 터미널에서 MCU 장치 경로를 식별하는 실제 작업 흐름을 보여주는 이미지입니다.

    4. 실전 진단 2단계: printer.cfg의 serial 설정을 고정 경로로 맞추기

    장치가 보이기 시작했다면 이제는 Klipper가 그 장치를 정확히 열 수 있는지를 봐야 합니다. 대부분은 printer.cfg의 [mcu] 아래 serial: 한 줄에서 갈립니다. 이 값이 실제 장치와 한 글자라도 다르면 연결은 실패합니다.

    [mcu]
    serial: /dev/serial/by-id/usb-1a86_USB2.0-Serial-if00-port0

    여기서 제 권장 방식은 단순합니다. 직접 타이핑하지 말고, 방금 확인한 경로를 그대로 복사해서 붙여넣는 것입니다. 문자열이 은근히 비슷해서 사람 손으로 넣다가 오타 나는 경우가 꽤 많습니다.

    그리고 보드 특성에 따라 선택 기준이 조금 갈립니다.

    경로 선택 방식 언제 추천하나 장점 주의점
    /dev/serial/by-id/... 대부분의 USB MCU 보드 재부팅 후에도 안정적, 사람이 식별하기 쉽습니다 일부 보드/칩셋은 고유 ID를 노출하지 않을 수 있습니다
    /dev/serial/by-path/... CH340 계열처럼 by-id가 모호하거나 없는 경우 물리 포트 기준이라 식별 자체는 가능합니다 USB 허브 위치나 포트 변경에 민감합니다
    /dev/ttyUSB0, /dev/ttyACM0 임시 테스트 외에는 비추천 짧고 빠르게 확인하기 쉽습니다 재부팅, 재연결, 장치 추가 시 이름이 바뀔 수 있습니다

    설정을 수정한 뒤에는 UI만 보지 말고 콘솔과 로그를 같이 보시는 게 좋습니다. 연결 문제와 설정 문법 문제는 겉보기엔 비슷하게 보일 때가 있는데, 실제론 전혀 다른 장애거든요.

    tail -n 100 ~/printer_data/logs/klippy.log

    로그를 볼 때 무엇을 읽어야 하는가도 중요합니다. 저는 아래처럼 해석합니다.

    • 장치 파일을 못 찾는 메시지: 경로 문제일 가능성이 큽니다.
    • 권한 거부 메시지: 포트 권한 또는 서비스 계정 문제입니다.
    • 장치는 열었는데 MCU 식별/초기화 단계에서 실패: 펌웨어 불일치, 잘못된 빌드 타깃, 플래시 문제 쪽으로 넘어갑니다.
    • 설정 문법 오류: 이건 연결 문제가 아니라 printer.cfg 파싱 단계에서 막힌 겁니다.

    여기서 한 가지 더. RESTART가 만능은 아닙니다. 설정을 다시 읽는 데는 유효하지만, 호스트 소프트웨어를 업데이트했거나 MCU 펌웨어를 바꾼 뒤라면 서비스 재시작이나 재플래시가 따로 필요할 수 있습니다. 이 구분을 해두면 같은 작업을 몇 번씩 반복하는 일을 줄일 수 있습니다.

    5. 실전 진단 3단계: 포트 점유, 권한, 펌웨어 정합성까지 확인

    장치도 보이고 serial:도 맞는데 여전히 Unable to Connect가 뜬다면, 그때부터는 장치를 여는 데 실패하는지, 열고도 통신이 안 되는지를 더 깊게 봐야 합니다. 이 구간에서 흔한 함정이 세 가지 있습니다. 포트 점유, 권한, 호스트/MCU 빌드 불일치입니다.

    먼저 포트 점유부터 보는 이유가 있습니다. 펌웨어나 케이블보다 더 흔한데, UI만 봐서는 티가 잘 안 납니다. 특히 예전에 OctoPrint, 시리얼 모니터, 다른 자동화 스크립트를 같이 쓴 환경이면 이 가능성을 먼저 의심하셔야 합니다.

    sudo service klipper stop
    lsof /dev/serial/by-id/*
    fuser -v /dev/ttyUSB0 /dev/ttyACM0 2>/dev/null
    sudo service klipper start

    위 명령에서 포인트는 이겁니다.

    • lsof나 fuser 결과가 나오면: 누군가 그 포트를 잡고 있는 겁니다. Klipper만의 문제로 보면 안 됩니다.
    • Klipper를 멈춘 뒤 플래시가 성공한다면: 플래시 실패의 본질은 포트 점유였을 가능성이 큽니다.

    그다음은 권한입니다. 여기서는 무조건 tty 그룹부터 추가하는 식으로 가지 않는 게 좋습니다. 실제 장치 파일의 그룹은 배포판과 설정에 따라 dialout, uucp, tty처럼 다를 수 있거든요. 그래서 먼저 어떤 사용자로 서비스가 돌고 있는지, 장치 파일의 소유 그룹이 무엇인지를 확인해야 합니다.

    ps -ef | grep -E 'klippy|klipper'
    ls -l /dev/serial/by-id/*
    id
    groups
    # 예시: 실제 그룹명과 사용자명 확인 후
    sudo usermod -a -G <device_group> <service_user>

    마지막 줄의 <device_group>과 <service_user>는 예시입니다. 실제 환경에 맞게 바꿔야 하고, 그룹 추가 뒤에는 보통 새 로그인 세션이나 서비스 재시작이 필요합니다. 이 부분을 건너뛰면 적용이 안 됐는데 명령만 반복하는 상황이 생기기 쉽습니다.

    마지막으로 남는 게 펌웨어 쪽입니다. 특히 아래 상황이라면 재빌드/재플래시 우선순위가 올라갑니다.

    • 보드를 새로 교체했습니다.
    • make menuconfig에서 MCU 아키텍처나 통신 인터페이스를 바꿨습니다.
    • 호스트 소프트웨어는 업데이트했는데 MCU는 오래된 빌드입니다.
    • 플래시 직후부터 장치는 보이지만 초기화가 안 됩니다.
    Klipper 펌웨어 문제 해결을 위한 빌드와 플래시 절차 이미지

    menuconfig, build, flash, service restart 순서가 어떻게 이어지는지 정리한 다이어그램입니다.

    6. 재빌드와 재플래시가 필요한 경우, 어디서 실수하는지

    장치 경로와 설정이 모두 맞는데도 붙지 않으면, 그다음은 펌웨어 자체를 의심해야 합니다. 다만 여기서도 무턱대고 다시 굽는 것보다 왜 재플래시가 필요한 상황인지를 먼저 판단하는 편이 낫습니다.

    제가 보통 재플래시로 넘어가는 조건은 이렇습니다.

    • 장치는 열리는데 MCU 초기화가 안 된다
    • 방금 보드 정의를 바꿨다
    • 호스트 업데이트 후 MCU 쪽 재빌드 경고 또는 비정상 동작이 있다
    • 플래시 과정 자체가 의심스럽다 – 예를 들어 잘못된 대상 보드로 빌드했거나, 부트 모드 진입이 안 된 경우

    일반적인 빌드 흐름은 아래와 같습니다.

    cd ~/klipper
    make menuconfig
    make clean
    make

    make clean을 중간에 넣는 이유는 이전 빌드 산출물이 섞여 판단을 흐리는 일을 줄이기 위해서입니다. 특히 보드 종류나 옵션을 바꾼 뒤에는 이 단계가 더 안전합니다.

    시리얼 장치를 통한 일반적인 플래시 흐름은 다음 패턴을 많이 씁니다.

    sudo service klipper stop
    make flash FLASH_DEVICE=/dev/serial/by-id/usb-1a86_USB2.0-Serial-if00-port0
    sudo service klipper start

    여기서 실제로 많이 틀리는 지점은 네 군데입니다.

    • FLASH_DEVICE에 현재 장치가 아닌 예전 경로를 넣는 경우
    • Klipper 서비스를 안 멈춘 상태에서 플래시하는 경우
    • 보드가 make flash 대신 SD 카드 또는 제조사 전용 방식이 필요한 경우
    • 플래시 후 장치명이 바뀌었는데 printer.cfg를 갱신하지 않은 경우

    특히 STM32 계열이나 일부 클론 보드는 첫 Klipper 플래시를 SD 카드로 요구하는 경우가 있습니다. 공식 설치 문서도 이 가능성을 따로 언급합니다. 이때 make flash만 반복하면 원인을 잘못 짚게 됩니다.

    또 SD 카드 방식은 보드마다 파일명 재사용이 안 되는 경우, 또는 플래시 후 firmware.cur처럼 이름이 바뀌는 경우가 있어서, 파일만 넣었다고 바로 성공으로 판단하면 안 됩니다. 이런 부분은 제조사 문서를 같이 보는 게 안전합니다.

    7. 제가 자주 봤던 실제 원인 4가지와 근본 원인

    겉으로는 다 비슷한 연결 불가지만, 반복해서 나오는 패턴은 어느 정도 정해져 있습니다. 저는 아래 네 가지를 먼저 의심합니다.

    7-1. 가변 포트명 사용

    가장 흔합니다. /dev/ttyUSB0 또는 /dev/ttyACM0는 짧아서 편해 보이지만, 장기 안정성은 떨어집니다. 근본 원인은 Klipper가 틀린 포트를 보고 있는 게 아니라, 운영체제가 같은 종류의 장치를 다른 번호로 다시 배정하기 때문입니다. 해결은 간단합니다. /dev/serial/by-id/를 사용하세요.

    7-2. 플래시 후 장치명이 달라짐

    이건 생각보다 자주 놓칩니다. 사용자는 플래시가 끝났다고 생각하지만, 실제로는 플래시 후 USB 식별 문자열이 바뀌어서 예전 경로가 더 이상 유효하지 않은 경우가 많습니다. 이때 재플래시를 반복해도 증상은 그대로입니다. 플래시 직후 다시 ls /dev/serial/by-id/*를 실행해서 현재 경로를 기준으로 설정을 바꿔야 합니다.

    7-3. 권한 문제

    이때 근본 원인은 Klipper 설정이 아니라 호스트의 장치 접근 정책입니다. 로그에 Permission denied가 보이면, 먼저 어떤 사용자로 서비스가 돌고 있는지 확인하고, 그다음 실제 장치 파일의 그룹에 맞춰 권한을 부여해야 합니다. 배포판마다 그룹명이 다를 수 있다는 점도 꼭 같이 기억해두세요.

    7-4. 다른 프로세스가 포트를 점유함

    이 문제는 UI에서 잘 안 드러납니다. 사용자는 MCU 연결 실패라고 보지만, 운영체제 입장에서는 이미 다른 프로세스가 장치를 열고 있어서 Klipper가 들어갈 자리가 없는 겁니다. 근본 원인은 장치 충돌이지 펌웨어 불량이 아닙니다. 특히 플래시 단계에서 실패하면 이쪽 가능성이 더 큽니다.

    추가로 하나 더 말씀드리면, 케이블 문제는 생각보다 단순하지 않습니다. 전원은 들어오는데 데이터 라인이 불안정한 USB 케이블도 꽤 있습니다. 그래서 보드 전원이 들어온다고 통신까지 정상이라고 보면 안 됩니다. 장치가 아예 안 보이거나, 꽂을 때마다 커널 로그가 들쭉날쭉하다면 케이블 교체 테스트는 충분히 해볼 만합니다.

    8. 재현 가능한 시나리오로 보면 훨씬 빨리 잡힙니다

    제가 실제로 여러 번 본 흐름을 하나 적어보겠습니다. 초보자뿐 아니라 어느 정도 익숙한 분도 여기서 많이 걸립니다.

    1. 보드에 새 Klipper 펌웨어를 올립니다.
    2. 웹 UI에서 바로 Unable to Connect가 뜹니다.
    3. 사용자는 보통 빌드가 잘못됐나?부터 의심합니다.
    4. 그런데 SSH에서 ls /dev/serial/by-id/*를 다시 보면, 기존과 다른 새 경로가 잡혀 있습니다.
    5. printer.cfg의 serial:을 새 값으로 바꾸고 재시작하면 바로 붙습니다.

    이 시나리오가 주는 교훈은 분명합니다. 연결 불가가 보이면 바로 재플래시로 가지 말고, 플래시 이후 장치명이 바뀌었는지 먼저 확인할 것. 이 한 단계만 지켜도 불필요한 재작업이 꽤 줄어듭니다.

    반대로 이런 경우도 있습니다. 장치는 by-id에 보이고, serial:도 맞는데, 플래시만 계속 실패합니다. 이럴 땐 대부분 포트 점유 또는 보드가 요구하는 실제 플래시 방식이 make flash가 아닌 상황입니다. 같은 Klipper 오류처럼 보여도 보는 층위가 달라야 한다는 얘기죠.

    9. 검증: 어디까지 확인돼야 정상 복구로 볼 수 있나

    한 번 붙었다고 끝내면 안 됩니다. MCU 연결 문제는 간헐 복구가 제일 까다롭거든요. 화면이 살아났더라도 아래 기준까지는 확인해두는 편이 안전합니다.

    • Klipper 상태가 ready로 전환되는지
    • 재시작 후에도 같은 상태가 유지되는지
    • USB 케이블 재연결 뒤에도 같은 경로를 계속 쓰는지
    • klippy.log에 같은 연결 오류가 다시 반복되지 않는지

    제가 복구 검증에 자주 쓰는 최소 명령은 아래 정도입니다.

    sudo service klipper restart
    tail -n 50 ~/printer_data/logs/klippy.log

    여기서 판단은 이렇게 합니다.

    • 한 번은 붙는데 재부팅 후 깨진다: 대개 경로 선택이 불안정합니다. ttyUSB0 같은 가변 이름을 의심하세요.
    • 플래시 직후만 안 되다가 경로 수정 후 안정화된다: 포트 식별 문제가 맞을 가능성이 큽니다.
    • 여러 번 재시작해도 로그에 포트 열기 실패가 반복된다: 권한, 점유, 장치 인식, 케이블 쪽을 다시 봐야 합니다.
    • 장치는 잘 열리는데 MCU 초기화가 계속 실패한다: 보드 대상, 통신 방식, 펌웨어 재빌드 정합성으로 넘어가야 합니다.

    저는 여기서 한 번 더 엄격하게 봅니다. 재부팅 1회, 서비스 재시작 1회, 케이블 재연결 1회까지는 통과해야 “고쳤다”고 판단합니다. 그 전에는 그냥 운 좋게 한 번 붙은 상태일 수도 있거든요.

    Klipper 오류 해결 후 정상 ready 상태와 로그 검증 이미지

    연결 복구 후 상태 화면과 로그를 함께 점검하는 검증 단계를 표현한 이미지입니다.

    10. 자주 헷갈리는 포인트 정리

    10-1. 로그는 어디서 보나요?

    보통 ~/printer_data/logs/klippy.log입니다. 일부 환경에서는 /tmp/klippy.log를 보는 경우도 있지만, 요즘 많이 쓰는 Mainsail/Fluidd 계열 구성에선 전자가 먼저입니다. UI 팝업보다 이 로그가 훨씬 정보가 많습니다.

    10-2. 왜 by-id를 그렇게 강조하나요?

    ttyUSB0, ttyACM0는 사람이 보기엔 간단하지만 운영체제 입장에서는 고정 이름이 아닙니다. 반면 /dev/serial/by-id/는 장치 식별값 기반이라 훨씬 안정적입니다. 한두 번은 차이를 못 느껴도, 재부팅과 장치 추가가 반복되면 차이가 바로 납니다.

    10-3. by-id가 없으면 실패한 건가요?

    꼭 그렇진 않습니다. 일부 CH340 계열처럼 by-id가 깔끔하지 않은 보드는 by-path를 써야 할 수 있습니다. 다만 이 경우엔 USB 허브나 포트 위치가 바뀌면 경로도 달라질 수 있으니, 물리 포트 변경에 더 민감하다는 점은 감안하셔야 합니다.

    10-4. make flash가 안 되면 Klipper 자체 문제인가요?

    아닐 때가 많습니다. 서비스가 포트를 잡고 있거나, 보드가 SD 카드 방식이나 별도 부트로더 절차를 요구할 수 있습니다. 이때는 플래시 도구 실패와 MCU 연결 실패를 같은 문제로 보지 않는 게 중요합니다.

    10-5. 재시작 명령만 반복하면 되나요?

    설정 반영에는 도움이 되지만, 장치가 아예 안 보이거나 새 펌웨어를 실제로 올려야 하는 상황까지 해결해주진 않습니다. RESTART는 설정 재적용, 서비스 재시작은 호스트 프로세스 재기동, 재플래시는 MCU 코드 교체라는 차이를 구분하셔야 합니다.

    MCU 연결 문제와 Klipper 트러블슈팅 순서를 요약한 인포그래픽

    장치 경로, 설정, 권한, 재플래시 순서를 빠르게 훑을 수 있는 요약 인포그래픽입니다.

    11. 이런 상황이면 이렇게 결정하시면 됩니다

    장치가 아예 안 보인다면 설정 파일부터 열지 마세요. 케이블, 전원, USB 포트, 보드 부트 상태, 커널 로그를 먼저 확인하는 편이 맞습니다.

    장치는 보이는데 Unable to Connect가 뜬다면 우선순위는 거의 항상 같습니다. printer.cfg의 serial: 값, 그리고 klippy.log입니다. 특히 플래시 직후라면 장치명이 바뀌었는지를 먼저 보세요.

    장치도 보이고 경로도 맞는데 계속 안 붙는다면 그때는 포트 점유, 권한, 펌웨어 정합성으로 넘어가면 됩니다. 이 단계에서는 lsof, fuser, 서비스 중지 후 플래시, 보드별 플래시 방식 확인이 효율적입니다.

    제가 추천하는 실제 순서는 딱 이겁니다. 1) 장치 열거 확인, 2) 고정 경로 반영, 3) 로그 해석, 4) 포트 점유/권한 정리, 5) 마지막으로 재빌드와 재플래시. 이 순서로 가면 괜히 반나절씩 재설치하는 일을 많이 줄일 수 있습니다.

    다음 단계의 Klipper 오류가 MCU shutdown이나 Lost communication with MCU처럼 “붙긴 붙는데 출력 중 끊기는” 유형이라면 접근법이 조금 달라집니다. 이 블로그의 관련 Klipper 트러블슈팅 글도 이어서 보시면 흐름을 잡는 데 도움이 됩니다.

  • [3D Printer] Klipper 펌웨어 설치 및 고급 설정: 출력 품질 극대화 완벽 가이드

    마블링 같은 출력물… 그냥 두고 볼 수 없었습니다

    3D 프린터를 처음 샀을 때 기억 나시나요? 저는 당시 Marlin 펌웨어로 세팅하고 그냥 쓰고 있었는데, 출력물 표면에 물결 무늬(ringing 또는 ghosting이라고 부르는 현상)가 계속 생기는 거예요. 파라미터 이것저것 건드려봤는데 영 개선이 안 되더라고요. 그러다 동료 엔지니어한테서 처음 Klipper 펌웨어 얘기를 들었습니다. “그거 쓰면 진짜 달라져” 하는 말에 반신반의하면서 설치해봤는데… 솔직히 그 이후로 Marlin으로 돌아갈 생각이 전혀 없어요.

    이 글에서는 Klipper 설치부터 고급 설정까지, 제가 직접 삽질하면서 쌓은 경험을 최대한 실용적으로 풀어드리려 합니다. 3D프린터 펌웨어를 처음 바꿔보시는 분도, 이미 Klipper를 쓰고 있지만 최적화가 잘 안 되는 분도 도움이 되셨으면 좋겠네요.

    ▲ Klipper의 핵심 구조 — 라즈베리 파이(호스트)와 마이크로컨트롤러(MCU)가 역할을 나눠서 처리하는 방식입니다.

    Klipper 펌웨어란 무엇인가요? — 쉽게 말해서

    Klipper는 3D 프린터의 제어 로직을 마이크로컨트롤러(MCU) 단독으로 처리하지 않고, 라즈베리 파이(Raspberry Pi) 같은 싱글보드 컴퓨터와 역할을 분리해서 처리하는 오픈소스 3D프린터 펌웨어입니다.

    쉽게 말해서, 기존 Marlin 같은 펌웨어는 프린터 보드(예: SKR, RAMPS) 안에서 모든 계산을 혼자 다 처리했어요. 근데 그 보드들 성능이 그렇게 좋진 않잖아요. Klipper는 복잡한 수학 계산(G-code 파싱, 가감속 계산 등)을 라즈베리 파이에서 처리하고, 보드는 그냥 “이 모터를 이 타이밍에 이만큼 돌려”라는 저수준 명령만 받아서 실행하는 구조거든요.

    항목 Marlin 펌웨어 Klipper 펌웨어
    연산 위치 프린터 보드(MCU) 단독 라즈베리 파이 + MCU 분산
    설정 변경 펌웨어 재컴파일 필요 텍스트 파일 수정 후 재시작
    입력 성형(Input Shaping) 제한적 가속도계 연동 자동 보정 가능
    압력 선행(Pressure Advance) Linear Advance (설정 복잡) Pressure Advance (직관적)
    인터페이스 LCD 또는 별도 호스트 Mainsail/Fluidd 웹 UI
    다중 MCU 지원 어려움 기본 지원

    이 구조 덕분에 설정을 바꿀 때마다 펌웨어를 새로 컴파일해서 플래시할 필요가 없어요. printer.cfg 파일만 수정하고 Klipper를 재시작하면 끝입니다. 처음에 이게 얼마나 편한지 실감 못 했는데, 써보고 나서 “아 이래서 다들 Klipper 쓰는구나” 했습니다.

    준비물 및 환경 구성

    Klipper 설치 전에 필요한 것들을 정리해볼게요. 제가 쓰는 환경 기준으로 설명하겠지만, 대부분의 환경에 적용 가능합니다.

    하드웨어 요구사항

    • 싱글보드 컴퓨터: 라즈베리 파이 3B+ 이상 권장 (저는 Pi 4 2GB 사용)
    • 프린터 보드: SKR Mini E3, BTT Octopus, Creality 보드 등 대부분 지원
    • MicroSD 카드: 라즈베리 파이용 8GB 이상
    • USB 케이블: 라즈베리 파이 ↔ 프린터 보드 연결용 (데이터 전송 지원)

    소프트웨어 스택

    • Klipper: 실제 펌웨어 코어
    • Moonraker: Klipper와 웹 UI를 연결하는 API 서버
    • Mainsail 또는 Fluidd: 웹 기반 인터페이스 (저는 Mainsail 사용)
    • KIAUH(Klipper Installation And Update Helper): 설치 자동화 스크립트

    Klipper 설치 단계별 가이드

    자, 이제 본격적으로 Klipper 설치 과정입니다. 처음에는 좀 복잡해 보이는데, 한 번만 하고 나면 별거 아니에요. 차근차근 따라오세요.

    1단계: 라즈베리 파이 OS 설치

    라즈베리 파이 이미저(Raspberry Pi Imager)로 Raspberry Pi OS Lite (64-bit)를 설치합니다. GUI 없는 Lite 버전으로 충분하고, 오히려 더 가볍게 돌아가요.

    이미저에서 고급 설정으로 SSH 활성화와 Wi-Fi 설정까지 미리 해두면 나중에 편합니다. 저는 여기서 SSH 설정 안 해두고 나중에 모니터 연결해서 했던 기억이… 🤦

    2단계: SSH 접속 및 초기 업데이트

    # 라즈베리 파이에 SSH로 접속
    ssh pi@[라즈베리파이_IP주소]
    
    # 패키지 업데이트
    sudo apt update && sudo apt upgrade -y

    3단계: KIAUH로 Klipper, Moonraker, Mainsail 설치

    # KIAUH 다운로드
    cd ~
    git clone https://github.com/dw-0/kiauh.git
    
    # KIAUH 실행
    ./kiauh/kiauh.sh

    KIAUH 메뉴가 뜨면 순서대로 설치합니다:

    1. 1번 메뉴 (Install) 선택
    2. Klipper 설치
    3. Moonraker 설치
    4. Mainsail 또는 Fluidd 설치 (둘 중 하나)

    설치 중에 Python 가상환경 세팅이나 의존성 설치가 자동으로 이루어져요. 예전에는 이걸 수동으로 다 해야 했는데, KIAUH 덕분에 진짜 편해졌더라고요.

    4단계: 프린터 보드용 Klipper MCU 펌웨어 컴파일 및 플래시

    이 단계가 핵심입니다. 프린터 보드에 올릴 Klipper MCU 펌웨어를 라즈베리 파이에서 컴파일해야 해요.

    # Klipper 디렉토리로 이동
    cd ~/klipper
    
    # 메뉴 기반 설정 도구 실행
    make menuconfig

    여기서 본인 보드에 맞는 설정을 해줘야 합니다. 예를 들어 BTT SKR Mini E3 V3 기준으로는:

    • Micro-controller Architecture: STMicroelectronics STM32
    • Processor model: STM32G0B1
    • Bootloader offset: 8KiB bootloader
    • Communication interface: USB (on PA11/PA12)

    ⚠️ 주의: 보드마다 설정이 달라요. Klipper 공식 문서나 보드 제조사 GitHub에서 본인 보드에 맞는 설정을 반드시 확인하세요. 잘못된 설정으로 플래시하면 보드가 벽돌이 될 수 있거든요. 저도 한 번 당했는데, 다행히 DFU 모드로 복구했어요.

    # 설정 완료 후 컴파일
    make clean
    make -j4
    
    # 컴파일 결과물 위치: ~/klipper/out/klipper.bin

    컴파일된 klipper.bin을 SD카드에 복사해서 보드에 플래시하거나, USB DFU 방식으로 직접 플래시합니다. 방법은 보드마다 다르니 반드시 확인이 필요해요.

    ▲ Mainsail 웹 인터페이스에서 printer.cfg를 직접 편집하고 저장하면 바로 적용됩니다 — 펌웨어 재플래시 없이요.

    5단계: printer.cfg 기본 설정

    Klipper의 핵심 설정 파일인 printer.cfg를 작성합니다. 이게 Marlin에서 Configuration.h 역할을 한다고 보시면 돼요. 근데 훨씬 읽기 쉽고 수정하기 편합니다.

    # printer.cfg 기본 예시 (Cartesian 방식 프린터)
    
    [mcu]
    # 보드가 연결된 시리얼 포트 확인: ls /dev/serial/by-id/
    serial: /dev/serial/by-id/usb-Klipper_stm32g0b1xx_XXXXXXXXXXXXXXXX-if00
    
    [printer]
    kinematics: cartesian
    max_velocity: 300
    max_accel: 3000
    max_z_velocity: 5
    max_z_accel: 100
    
    [stepper_x]
    step_pin: PB13
    dir_pin: !PB12
    enable_pin: !PB14
    microsteps: 16
    rotation_distance: 40
    endstop_pin: ^PC0
    position_endstop: 0
    position_max: 235
    homing_speed: 50
    
    [stepper_y]
    step_pin: PB10
    dir_pin: !PB2
    enable_pin: !PB11
    microsteps: 16
    rotation_distance: 40
    endstop_pin: ^PC1
    position_endstop: 0
    position_max: 235
    homing_speed: 50
    
    [stepper_z]
    step_pin: PB0
    dir_pin: PC5
    enable_pin: !PB1
    microsteps: 16
    rotation_distance: 8
    endstop_pin: probe:z_virtual_endstop
    position_min: -5
    position_max: 250
    
    [extruder]
    step_pin: PB3
    dir_pin: !PB4
    enable_pin: !PD1
    microsteps: 16
    rotation_distance: 33.500
    nozzle_diameter: 0.400
    filament_diameter: 1.750
    heater_pin: PC8
    sensor_type: EPCOS 100K B57560G104F
    sensor_pin: PA0
    min_temp: 0
    max_temp: 250
    
    [heater_bed]
    heater_pin: PC9
    sensor_type: ATC Semitec 104GT-2
    sensor_pin: PC4
    min_temp: 0
    max_temp: 130

    처음에는 이게 양이 많아 보이는데, 사실 각 섹션이 뭘 의미하는지 한 번만 파악하면 Marlin보다 오히려 직관적이에요.

    Klipper 고급 설정 — 출력 품질 극대화

    자, 이제 진짜 Klipper의 진가를 발휘하는 고급 기능들입니다. 이게 제가 Klipper로 넘어온 가장 큰 이유예요.

    Pressure Advance (압력 선행 보정)

    Pressure Advance는 익스트루더가 필라멘트를 밀 때 노즐 내부에 생기는 압력 지연을 보정하는 기능입니다. 쉽게 말해, 코너 부분에서 필라멘트가 뭉치거나 늘어지는 현상을 잡아주는 거예요.

    [extruder]
    # 위 extruder 섹션에 추가
    pressure_advance: 0.05
    pressure_advance_smooth_time: 0.040

    정확한 값은 캘리브레이션 타워를 출력해서 찾아야 해요. Klipper 공식 문서에 캘리브레이션 방법이 잘 나와 있습니다. 저는 이거 세팅하고 나서 코너 품질이 확실히 달라졌더라고요. 특히 벤치마크 모델 출력할 때 차이가 눈에 띄었습니다.

    Input Shaping (입력 성형) — 링잉 제거의 핵심

    이게 Klipper의 킬러 기능이라고 생각합니다. Input Shaping(입력 성형)은 프린터 프레임이 진동할 때 생기는 링잉(ringing, 고스팅) 현상을 소프트웨어적으로 보정하는 기술이에요.

    가속도계(accelerometer)를 연결하면 자동으로 프린터의 공진 주파수를 측정해서 최적의 보정 필터를 적용해줍니다. 저는 ADXL345 모듈을 라즈베리 파이 SPI 핀에 연결해서 사용했어요.

    # ADXL345 가속도계 설정
    [adxl345]
    cs_pin: rpi:None
    spi_bus: spidev0.0
    
    [resonance_tester]
    accel_chip: adxl345
    probe_points:
        117.5, 117.5, 20
    # SSH에서 공진 주파수 측정 실행
    # Mainsail 콘솔 또는 SSH에서:
    SHAPER_CALIBRATE AXIS=X
    SHAPER_CALIBRATE AXIS=Y

    측정 결과를 바탕으로 Klipper가 자동으로 추천 필터를 알려줘요. 그걸 printer.cfg에 적용하면 됩니다:

    [input_shaper]
    shaper_freq_x: 45.8
    shaper_freq_y: 38.2
    shaper_type: mzv

    💡 팁: 가속도계가 없어도 수동으로 캘리브레이션 타워를 출력해서 주파수를 추정할 수 있어요. 다만 ADXL345 같은 저렴한 모듈을 하나 구해두면 훨씬 정확하고 빠르게 캘리브레이션할 수 있습니다.

    Bed Mesh Leveling (베드 메쉬 레벨링)

    베드가 완벽하게 평평한 경우는 거의 없죠. Bed Mesh는 베드 여러 포인트를 측정해서 높이 편차를 보정 맵으로 만들어 출력 중에 실시간으로 Z축을 조정하는 기능입니다.

    [bed_mesh]
    speed: 120
    horizontal_move_z: 5
    mesh_min: 10, 10
    mesh_max: 225, 225
    probe_count: 5, 5
    algorithm: bicubic

    Macro(매크로) 활용 — 반복 작업 자동화

    Klipper의 매크로 기능도 정말 편리해요. 자주 쓰는 작업을 버튼 하나로 실행할 수 있게 만들 수 있거든요.

    # 출력 시작 매크로 예시
    [gcode_macro START_PRINT]
    gcode:
        {% set BED_TEMP = params.BED_TEMP|default(60)|float %}
        {% set EXTRUDER_TEMP = params.EXTRUDER_TEMP|default(190)|float %}
        M140 S{BED_TEMP}
        G28
        BED_MESH_CALIBRATE
        M109 S{EXTRUDER_TEMP}
        M190 S{BED_TEMP}
        G92 E0
        G1 X5 Y20 Z0.3 F5000
        G1 X5 Y200 E15 F1500
        G92 E0
    
    [gcode_macro END_PRINT]
    gcode:
        G91
        G1 E-5 F3000
        G1 Z10 F3000
        G90
        G1 X0 Y220 F5000
        M104 S0
        M140 S0
        M84

    슬라이서(Slicer)에서 시작/종료 G-code를 START_PRINT BED_TEMP={material_bed_temperature} EXTRUDER_TEMP={material_print_temperature}처럼 설정하면, 슬라이서에서 설정한 온도가 자동으로 매크로에 전달돼요. 이거 처음 알았을 때 진짜 편하다 싶었습니다.

    ▲ Input Shaping 적용 전후 비교 — 공진 주파수 측정 그래프와 실제 출력물의 링잉(ghosting) 현상 개선 결과

    ⚠️ 트러블슈팅 — 제가 겪은 삽질들

    설치하면서 자주 만나는 문제들을 정리해봤어요. 저도 다 겪어봤던 것들이라 공감하실 분들 많을 거예요.

    문제 1: MCU 연결이 안 됨 (Unable to connect)

    가장 흔한 문제입니다. printer.cfg의 시리얼 포트가 맞는지 확인하세요.

    # 연결된 USB 장치 시리얼 ID 확인
    ls /dev/serial/by-id/
    
    # 출력 예시:
    # usb-Klipper_stm32g0b1xx_XXXXXXXXXXXXXXXX-if00

    이 경로를 그대로 printer.cfg의 [mcu] 섹션 serial:에 넣으면 됩니다. USB 케이블 불량인 경우도 꽤 있어요. 데이터 전송이 되는 케이블인지 확인해보세요.

    문제 2: Klipper 서비스 시작 후 에러 로그

    # Klipper 로그 실시간 확인
    tail -f ~/printer_data/logs/klippy.log
    
    # 서비스 상태 확인
    sudo systemctl status klipper

    대부분의 에러는 printer.cfg 설정 오류거든요. 로그를 보면 어느 섹션, 어느 파라미터에서 문제가 났는지 꽤 친절하게 알려줍니다.

    문제 3: 베드 레벨링 프로브 동작 안 함

    BLTouch나 CR Touch 같은 프로브를 쓰는 경우, 핀 설정이 까다로울 수 있어요. 특히 probe_with_touch_mode 옵션을 켜야 하는 경우도 있거든요. 저는 처음에 이거 몰라서 한참 헤맸습니다.

    [bltouch]
    sensor_pin: ^PC14
    control_pin: PA1
    pin_up_touch_mode_reports_triggered: False
    probe_with_touch_mode: True
    x_offset: -44
    y_offset: -10
    z_offset: 2.350

    문제 4: 압출량(Extruder) 캘리브레이션

    rotation_distance 값이 맞지 않으면 압출량이 부정확해집니다. 마크 테스트(Mark Test)로 캘리브레이션해야 해요.

    # 100mm 압출 명령 (Mainsail 콘솔에서)
    G91
    G1 E100 F100
    
    # 실제 압출된 길이를 측정하고 아래 공식으로 계산
    # 새 rotation_distance = 기존값 × (요청량 / 실제압출량)
    # 예: 33.5 × (100 / 98.5) = 34.01

    ✅ 결과 확인 — 이렇게 달라졌습니다

    Klipper 설정을 완료하고 나서 체감한 변화를 솔직하게 공유할게요.

    • 🎉 링잉(Ringing) 현상: Input Shaping 적용 후 거의 사라졌습니다. 코너 부분이 훨씬 깔끔해졌어요.
    • 🎉 코너 품질: Pressure Advance 세팅 후 코너 뭉침/늘어짐이 확실히 개선됐어요.
    • 🎉 출력 속도: Input Shaping 덕분에 고속 출력에서도 품질 저하가 줄어들었습니다. 가속도를 더 높게 설정할 수 있게 됐어요.
    • 🎉 운용 편의성: 설정 변경이 너무 편해요. 파라미터 하나 바꾸는 데 펌웨어 재컴파일이 필요 없으니까요.
    • 🎉 웹 인터페이스: Mainsail에서 실시간 모니터링, 파일 관리, 매크로 실행이 다 돼서 편합니다.

    물론 초기 세팅 난이도가 Marlin보다 높은 건 사실이에요. 라즈베리 파이 세팅, 리눅스 기본 조작, 각 보드별 펌웨어 컴파일 설정 등 진입 장벽이 있습니다. 근데 한 번만 넘어서면, 그 이후는 오히려 훨씬 편하거든요.

    ▲ Mainsail 대시보드 — 온도 그래프, 출력 진행률, 매크로 버튼 등을 웹 브라우저에서 실시간으로 모니터링할 수 있습니다.

    자주 묻는 질문 (FAQ)

    Q. Klipper가 모든 프린터 보드와 호환되나요?

    대부분의 주요 보드를 지원합니다. Klipper 공식 문서의 Config Reference 페이지에서 지원 MCU 목록을 확인할 수 있어요. STM32, AVR, RP2040 계열은 대부분 지원됩니다.

    Q. 라즈베리 파이 없이 Klipper를 쓸 수 있나요?

    네, 가능합니다. 라즈베리 파이 대신 오렌지 파이(Orange Pi), 일반 리눅스 PC도 호스트로 사용할 수 있어요.

    Q. Klipper 설치 후 기존 Marlin으로 되돌릴 수 있나요?

    네, 가능합니다. 프린터 보드에 Marlin 펌웨어를 다시 플래시하면 됩니다. 라즈베리 파이 쪽 Klipper 설정은 그냥 두거나 삭제하면 돼요.

    Q. Input Shaping에 가속도계가 반드시 필요한가요?

    필수는 아닙니다. 가속도계 없이 캘리브레이션 프린트로 수동으로 주파수를 추정할 수 있어요. 다만 ADXL345 같은 저렴한 모듈을 하나 구해두면 훨씬 정확하고 빠르게 캘리브레이션할 수 있습니다.

    마무리 — 그래서 Klipper, 써야 할까요?

    13년간 서버와 인프라를 다뤄온 입장에서, Klipper는 3D 프린터를 “설정 파일로 관리하는 시스템”으로 바꿔준 펌웨어라고 생각합니다. 코드로 인프라를 관리하는 IaC(Infrastructure as Code) 철학이랑 비슷한 느낌이랄까요.

    처음 설치가 좀 복잡한 건 사실입니다. 근데 그 이후로는 정말 편해요. 설정 하나 바꿀 때마다 Arduino IDE 켜고 컴파일하고 플래시하는 과정이 없어지는 것만으로도 충분히 투자할 가치가 있다고 생각합니다.

    처음엔 그냥 출력 품질 개선 목적으로 시작했는데, 이제는 홈랩 서버에서 Moonraker API로 자동화 스크립트도 돌리고, 출력 완료 시 알림도 보내고… 점점 재미있어지고 있어요. 혹시 이런 자동화 연동에 관심 있으신 분은 다음 글에서 Moonraker API 활용 자동화 방법도 다룰 예정이니 기대해주세요.

    질문이나 본인만의 Klipper 세팅 팁이 있으시면 댓글로 공유해주세요. 저도 아직 배우는 중이라, 다른 분들 경험도 궁금하거든요. 😊