Wi-Fi 버그가 삐 소리를 낼 때

ROSMASTER M3 Pro를 디버깅하며, 틀린 가설을 하나씩 지워간 날.

오늘의 계획은 단순했다. ROSMASTER M3 Pro의 공장 기본 설정을 한 시간 정도 검증하고, 전체 백업에 한 걸음 더 다가가는 것.

물론 “한 시간만 디버깅하자”는 로보틱스판 “차고에서 한 가지만 고치고 올게”와 비슷한 말이다. 소프트웨어 엔지니어라면 이 이야기가 어떻게 끝나는지 알 것이다.

M3 Pro에는 Jetson Orin NX 16GB가 들어 있고, 자체 Wi-Fi 핫스팟 M3P-LAB을 만든다.

ROSMASTER M3 Pro의 전면 전원 버튼, 섀시, 바퀴를 가까이서 보여 주는 모습

전원 버튼은 단순했다. 그 뒤의 상태는 그렇지 않았다.

Wi-Fi가 수상해 보였다

공장 기본 원격 개발 설정을 시험하던 중, 방향에 따라 처리량 차이가 유난히 크다는 것을 발견했다.

5 GHz에서는 다음과 같았다.

  • Mac → M3 Pro: ~105–120 Mbps
  • M3 Pro → Mac: ~10–20 Mbps

공장 기본 2.4 GHz 설정에서는 다음과 같았다.

  • Mac → M3 Pro: ~40 Mbps
  • M3 Pro → Mac: ~15–20 Mbps

신호 세기는 대략 -46 to -48 dBm으로 좋았고, 병렬 TCP 스트림을 네 개로 늘려도 병목은 사라지지 않았다.

Mac에서 M3 Pro로는 105–120 Mbps, M3 Pro에서 Mac으로는 10–20 Mbps인 방향별 Wi-Fi 처리량

같은 Wi-Fi. 완전히 다른 출퇴근길.

그래서 Wi-Fi 소프트웨어 스택이 의심스러워졌다. 이 보드는 Realtek RTL8822CE를 사용한다. 공장 Jetson 이미지는 Realtek의 rtl8822ce 벤더 드라이버를 로드하고, Linux에는 upstream rtw88 계열도 있다. 언젠가 드라이버 A/B 테스트를 해보는 것은 자연스러운 실험이 됐다.

하지만 아직은 아니다.

먼저 측정한다. 다음에 백업한다. 망가뜨리는 일은 그다음에 전문적으로 한다.

5 GHz와 몇 가지 power-management 설정을 잠시 시험한 뒤에는 공장 네트워크 기본 상태를 복원하고 확인했다. 2.4 GHz, Channel 1, 20 MHz, 15 dBm TX power, 공장 power-management 값, 192.168.8.88, 활성 상태의 핫스팟이다.

그러다 네트워크가 사라졌다

어느 순간 Mac은 여전히 M3P-LAB에 연결된 것처럼 보였지만, 로봇은 ping과 SSH에 응답하지 않았다. 드라이버가 더 유죄처럼 보였다.

M3 Pro의 LCD는 약 1분 후 blank 되도록 설정해 둔 상태라, Jetson이 어떤 형태로든 sleep 상태에 들어가는 것 아닐까 하는 가능성도 있었다. 이 가설은 시험하기 쉬웠다. continuous ping을 실행해 둔 채 기다렸다. 디스플레이는 검게 꺼졌다. ping은 계속됐다.

검은 화면 != 잠든 Jetson

용의자 하나를 목록에서 지웠다.

그때 배터리를 확인했다

ROS 2 /battery topic은 10.57 V를 보고했다. 반복 측정도 거의 정확히 그 값에 머물렀다.

실제 ROS 2 배터리 출력 data 10.574913024902344를 보여 주는 터미널 스타일 시각 자료

10.57 V: 이야기의 반전.

M3 Pro는 완전 충전 시 전압이 약 12.6 V인 3S lithium battery pack을 쓴다. 10.57 V라면 배터리가 분명히 낮아지고 있는 상태였다.

이제 질문은 더 이상 “Wi-Fi 드라이버가 고장 났나?”가 아니었다. “Wi-Fi 드라이버가 불행한가, 낮은 전압이 시스템을 불안정하게 만드는가, 아니면 둘이 나를 상대로 작은 동맹을 맺은 것인가?”가 됐다.

이것이 Physical AI에서 배우는 것 중 하나다. backend service라면 네트워킹 버그 때문에 보통 배터리를 확인하지 않는다. 로봇에서는 하드웨어가 결국 모든 소프트웨어 디버깅 대화에 참여한다.

재부팅이 증거를 먹어버렸다

다음으로 해야 할 일은 이전 부팅의 kernel과 NetworkManager 로그를 보는 것이었다. 하지만 결과는 no persistent journal was found였다.

M3 Pro는 이전 부팅의 journal을 디스크에 보존하지 않고 있었다. 나는 이미 로봇을 재시작했고, 실패 시점에서 가장 유용했던 증거는 사라졌다.

재부팅은 많은 문제를 고친다. 가끔은 현장 보존도 함께 없앤다.

다음부터는 reboot button이 등장하기 전에 진단 로그부터 저장해야 한다.

저전압도 완전한 설명은 아니었다

재부팅 후에도 배터리는 여전히 약 10.57 V였다. continuous ping을 실행한 채 로봇을 idle 상태로 뒀다. LCD는 꺼졌다. 시간이 흘렀다. 네트워크는 살아 있었다.

그래서 단순한 가설, low battery + idle time = dead Wi-Fi 역시 성립하지 않았다.

이 시점에는 적어도 세 가지의 그럴듯한 가능성이 있었다.

  1. RTL8822CE AP-mode 드라이버에 TX-side 문제가 있다.
  2. 낮은 배터리 전압은 더 높은 시스템 부하에서만 중요해진다.
  3. 두 요인이 모두 기여하고 있다.

안타깝게도 실제 버그는 한 번에 하나씩만 나타나 주는 만큼 친절하지 않다.

무언가를 교체하기 전에 제조사에 묻기

드라이버를 바로 바꾸는 대신, 측정값을 Yahboom 기술 지원에 보내고 안내를 요청했다. Orin NX 버전에서 AP-mode 처리량 비대칭이 알려진 문제인지, 로봇 → 워크스테이션 처리량을 어느 정도로 기대하는지, M3P-LAB이 지속적인 ROS 2 camera/LiDAR traffic을 위한 것인지, Raspberry Pi 버전은 다른 Wi-Fi stack을 쓰는지, 더 새로운 지원 드라이버나 system image가 있는지, upstream rtw88을 지원하는지, 진지한 원격 ROS 2 작업에는 외부 5 GHz access point를 이용한 STA mode를 권하는지, 그리고 약 10.5–10.6 V 배터리가 시스템 전체가 꺼지기 전에 Wi-Fi나 PCIe를 불안정하게 만들 수 있는지를 물었다.

다음 실험은 그 답변에도 일부 달려 있다.

그러다 로봇이 마침내 설명했다

이때쯤에는 디버깅을 멈추고, 실제로 로보틱스처럼 보이는 일을 하고 싶었다. 전면 RGB camera를 켜고 controller를 잡은 뒤, M3 Pro를 집 안에서 잠깐 first-person-view로 움직여 볼 계획이었다.

그때 로봇이 갑자기 길고 큰 소리를 냈다. 삐이이이이이이이이.

앞서 본 10.57 V를 생각하면 이는 매우 높은 가능성으로 low-battery warning이었지만, 공식적으로 증명하지는 못했다. Linux를 종료하고 로봇 전원을 껐다.

한 저녁 동안 iperf3, driver parameter, ROS topic, Wi-Fi 설정, 사라진 journal log를 보다가, 결국 로봇이 그날 가장 명확한 진단 메시지를 제공했다.

“야. 충전해.”

조사는 어디까지 왔나

아직 증명된 것은 없다. 10–20 Mbps M3 Pro → workstation 처리량은 의심스럽다. camera, depth, LiDAR, point cloud와 유용한 ROS 2 데이터의 상당수가 정확히 그 방향으로 흐르기 때문이다. 하지만 전원을 변수에서 제거하기 전까지 드라이버를 탓하고 싶지는 않다.

다음의 깨끗한 실험 순서는 이렇다.

  1. 배터리를 완전히 충전한다.
  2. 같은 방향별 iperf3 테스트를 반복한다.
  3. 테스트 중 Wi-Fi, NetworkManager, kernel, battery 로그를 수집한다.
  4. 지속적인 robot → PC traffic을 재현한다.
  5. 공장 기본 전체 disk-image backup을 만든다.
  6. Yahboom의 답변을 검토한다.
  7. 그다음에만 적절하다면 공장 드라이버와 더 새로운/upstream 대안을 A/B 테스트한다.

오늘은 해결책으로 끝나지 않았다. 대신 더 나은 것, 즉 더 명확한 다음 실험으로 끝났다.

마지막 문제 하나

이제 그날 저녁에 남은 가장 중요한 시스템 작업은 엔지니어를 sleep mode에 넣는 것이라고 생각했다.

로봇은 꺼져 있었다. 배터리는 낮았다. 나는 피곤했다. 완벽했다. 충전기에 연결하고 자고, 내일 계속하면 된다.

그런데 Yahboom의 충전 가이드가 생각났다. 배터리를 무인 상태로 충전하지 말 것. 그래서 전원이 꺼진 로봇과 LED가 달린 작은 charging adapter를 바라보게 됐다.

로봇은 재충전한다. 나는, 아무래도 감시해야 한다.

기계가 주인보다 더 나은 충전 루틴을 갖고 있다는 건 꽤 불공평하다. 내가 원했던 아키텍처는 이랬다.

Robot charges. Human sleeps.

현재의 아키텍처는 이렇다.

Robot charges. Human watches robot charging. Human battery continues toward 0%.

아마 다음 중요한 M3 Pro 업그레이드는 SLAM, vision-language-action model, autonomous manipulation이 아닐지도 모른다. 어쩌면 단순히 이것이다.

Kai가 자는 동안 스스로 안전하게 충전하기.

그것이 이 프로젝트에서 내 삶의 질을 실제로 개선하는 첫 autonomous capability가 될지도 모른다.