로봇, 사기 전에 화면 속에서 먼저 써봤습니다 (2편) — MuJoCo 설치와 SO-101 첫 구동
터미널에 명령 몇 줄을 넣자 창이 하나 떴습니다. 회색 바닥 위에 로봇팔 하나. 마우스로 팔을 끌어 봤는데 꿈쩍도 하지 않더군요. 돌아간 것은 팔이 아니라 카메라 시점이었습니다. 이번 편에서 가장 크게 배운 것은 설치 방법이 아니라 그 사실이었습니다.
왜 MuJoCo였고, 왜 SO-101이었나
선택지는 여러 개였습니다. 엔비디아 아이작 심, 게이제보, 그 외에도 여럿이죠. 그중 MuJoCo로 시작한 이유는 세 가지입니다.
첫째, 무료이고 노트북에서 돕니다. 로봇 회사들이 가상 환경에서 먼저 넘어뜨려 보는 장면을 보면 대단한 장비가 필요할 것 같지만, 팔 한 대를 띄우고 관절을 돌려 보는 데는 비싼 GPU가 필요하지 않았습니다. 1편에서 정한 원칙이 첫 줄부터 지켜진 셈이죠.
둘째, 물리 엔진이 진짜입니다. 중력과 질량, 마찰, 접촉력을 실제로 계산합니다. 이 말을 그냥 믿기는 싫어서 직접 확인해 봤는데, 그 이야기는 바로 아래에 적습니다.
셋째, 모델이 풍부합니다. 로봇팔부터 사족보행, 휴머노이드까지 대표 기종이 무료로 공개돼 있어 나중에 갈아 끼워 볼 수 있습니다. 여러 로봇을 비교하는 것이 이 시리즈의 목적이니 이 조건이 컸습니다.
그런데 시뮬레이터를 고른 것과 로봇을 고른 것은 다른 문제입니다. 시뮬레이션만 하고 끝낼 생각이라면 어떤 모델을 띄우든 상관없죠. 제 목적은 사기 전 예습이니, 화면 속 그 팔을 실제로 살 수 있어야 합니다.
그래서 첫 로봇은 SO-101(SO-ARM101)로 정했습니다. 판매 중인 LeRobot 계열 오픈소스 6축 로봇팔이고, 공식 시뮬레이션 모델이 무료로 공개돼 있으며, 입문용으로 부담스럽지 않은 가격대입니다. 사려던 그 팔을 화면에서 그대로 다뤄 본다는 것이 이 시리즈의 전제입니다.
엔진이 진짜인지, 물체를 떨어뜨려 확인했습니다
"물리가 진짜"라는 문장은 광고에도 쓰입니다. 그래서 두 가지를 직접 재 봤습니다.
하나는 자유낙하입니다. 물체를 공중에 놓고 떨어뜨린 다음, 바닥에 닿기까지 걸린 시간을 고등학교 공식과 비교했습니다. 낙하 거리는 h = ½gt²이므로 1m를 떨어지는 데 걸리는 이론 시간은 0.452초입니다. 시뮬레이터가 돌려준 값은 이론값과 2% 안쪽에서 맞았습니다.
다른 하나는 접촉력입니다. 물체를 테이블에 올려놓고 테이블이 떠받치는 힘을 읽어 무게와 대조했습니다. 두 값이 일치하더군요. 화면이 그림을 그리는 게 아니라 방정식을 푼다는 뜻입니다.
정직하게 덧붙입니다. 이 2%는 정밀도 인증이 아닙니다. 적분 간격을 어떻게 잡느냐에 따라 달라지는 값이고, 제가 확인한 것은 이 숫자가 지어낸 값은 아니라는 수준이죠. 화면의 결과를 실물의 근사치로 읽어도 되는지만 판단하면 됐으니 그 정도로 충분했습니다.
설치에서 두 번 데였습니다
설치 자체는 간단합니다. 다만 두 가지를 안 지키면 고생하죠. 제가 먼저 데였으니 적어 둡니다.
첫째, 동기화가 걸리지 않는 폴더에서 작업하십시오. 원드라이브나 구글 드라이브 폴더 안에서는 네이티브 프로그램이 깨집니다. 파일이 실시간으로 잠기고 풀리기 때문이죠. 저는 모르고 한참 헤맸습니다.
준비 과정은 두 운영체제가 거의 같습니다. 갈리는 것은 가상환경을 켜는 한 줄뿐이더군요.
윈도우 · PowerShell
mkdir C:\robot-sim
cd C:\robot-sim
py -3 -m venv .venv
.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install mujoco numpy
macOS · 터미널
mkdir -p ~/robot-sim
cd ~/robot-sim
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install mujoco numpy
그다음 SO-101 공식 시뮬 파일(scene.xml, so101_new_calib.xml, assets 메시 폴더)을 받아 models/SO101 아래에 둡니다. 공식 저장소 TheRobotStudio/SO-ARM100의 Simulation/SO101 경로에 있습니다.
둘째, 창을 띄우는 명령이 운영체제마다 다릅니다. 윈도우는 python으로 그냥 실행하면 되지만 macOS는 mjpython으로 실행해야 합니다. python으로 띄우면 launch_passive requires mjpython 오류가 나죠. macOS의 GUI 스레드 제약 때문이고, mjpython은 MuJoCo를 설치할 때 함께 들어옵니다. 오류 문구만 보면 설치가 잘못된 것 같지만 그렇지 않습니다.
윈도우 : python so101_control.py
macOS : mjpython so101_control.py
마우스로는 안 움직입니다. 숫자로 움직입니다
여기서 이번 편의 핵심이 나옵니다. 뷰어에서 마우스를 끄는 동작은 그냥 보기용입니다. 진짜 제어는 코드로 목표 관절각을 명령하는 것입니다.
파이썬에서 data.ctrl 배열에 목표 각도를 써넣으면, 모델에 정의된 서보가 팔을 그 자세로 끌고 갑니다. 각도는 도가 아니라 라디안으로 넣습니다.
d.ctrl[:] = np.radians([30, -40, 45, 20, 0, 20]) # 관절 6개의 목표각
이 구조가 중요한 이유가 있습니다. 실제 SO-101의 서보모터에 "이 각도로 가라"고 위치 명령을 보내는 방식이 이것과 같습니다. 화면 안에서 익힌 감각이 그대로 실물로 이어진다는 뜻이죠. 참고로 이런 위치 제어기는 목표 각도를 유지하기 위해 가만히 서 있을 때도 전류를 태웁니다. 화면에서는 공짜인 그 일이 실물에서는 발열로 돌아옵니다.
여러 자세를 순서대로 엮으면 동작 루틴이 됩니다. 손을 벌리고, 내리고, 오므리고, 들어 올리는 식이죠. 여기까지가 이번 편에서 도달한 지점입니다.
여기까지의 과정을 한 벌로 묶어 두었습니다. 윈도우용 run-windows.bat과 macOS용 run-mac.command 두 가지입니다. 더블클릭하면 전용 환경을 만들고 MuJoCo를 받은 뒤 SO-101을 띄웁니다. 키보드 1~6으로 관절을 고르고 대괄호 키로 각도를 조절합니다.
맺음말
돌아보면 여기까지는 순조로웠습니다. 팔을 띄우고, 코드로 원하는 자세를 만들고, 동작을 엮는 일은 생각보다 직관적이었습니다. 설치 함정 두 개를 빼면 막힌 곳도 없었죠. 그래서 다음 단계도 당연히 될 줄 알았습니다. "이제 물건을 집어서 옮겨 보자." 전혀 아니었습니다. 다음 편은 그 실패담입니다.
참고 자료