걷기는 풀렸다, 다음은 잡기다 — G1 양팔 매니퓰레이션에서 부딪힌 벽들 (계속)

G1이 가상환경에서 앞으로 걷는 데 성공한 뒤, 다음 목표를 정하는 건 어렵지 않았습니다. 걷기만 하는 로봇은 아무것도 옮길 수 없으니까요. 다음은 팔로 물건을 집고 옮기는 매니퓰레이션이어야 했습니다. 문제는 제가 이 목표를 너무 쉽게 봤다는 데 있었습니다. 손을 뻗어서 쥐고 옮기고 놓으면 되는 동작이라고 생각했는데, 실제로는 로봇의 손에 물건을 만질 수 있는 표면조차 없는 지점부터 다시 시작해야 했습니다.

이 글은 성공담이 아닙니다. 순서대로 부딪힌 문제와, 그걸 넘으며 지금 확정된 것과 아직 안 되는 것을 구분해 남기는 기록입니다.

진행 중인 기록입니다. 매니퓰레이션 학습은 아직 끝나지 않았고, 이 글도 결론이 아니라 지금까지의 중간 상태를 남기는 초안에 가깝습니다. 아래 “확정된 것과 아직 아닌 것”이 지금 이 순간의 경계선이고, 다음 결과가 나오면 이어서 갱신하겠습니다.

고정된 상태에서 잡기
100g 상자를 집어 옮기고 내려놓습니다. 637 스텝, 성공 1/1, 반복 3/3.
걷다가 멈춰서 잡기
멈추는 것까지는 되는데, 손을 뻗는 순간 균형이 무너지거나 물건을 놓칩니다.

같은 로봇, 같은 손인데 결과가 다른 이유는 팔이 아니라 접합부에 있었습니다.

손이 물건을 쥘 수 있게 되기까지 — 기초 단계에서 넷

시작은 손 자체였습니다. G1 몸통에 24개 관절을 가진 Inspire Hand를 붙인 자산을 준비하고 처음 손을 오므려 봤을 때, 손가락이 물체를 그대로 통과했습니다. 원본 손 에셋에는 충돌 메시가 아예 없었습니다 — 관절은 움직이지만 물리적으로 아무것도 만질 수 없는 손이었던 셈입니다. 손가락 끝마다 지름 12mm짜리 구체 콜라이더를 직접 추가해 한 손에 다섯 개씩, 총 열 개의 접촉 지점을 만들고 나서야 손이 실제로 물체 표면과 부딪히기 시작했습니다.

손이 만들어지자 이번엔 손목이 엉뚱한 방향으로 움직였습니다. 목표 자세를 관절 각도로 바꾸는 역기구학(IK) 계산에서, 관절 배열에는 골반이 포함되지만 물리 엔진이 실제로 계산하는 자코비안 텐서는 골반을 빼고 인덱싱한다는 걸 몰랐던 게 원인이었습니다. 고정 베이스와 유동 베이스를 서로 다른 공식으로 처리하도록 고치고 나서야 손목이 원하는 방향으로 움직이기 시작했습니다.

다음은 양손 타이밍이었습니다. 왼손이 먼저 닿고 오른손이 늦게 닿으면 그 사이 접촉력 차이만으로 물체가 옆으로 밀려났고, 붙잡은 채로 오래 고정해두면 손가락이 표면을 파고든 만큼의 에너지가 쌓였다가 손을 놓는 순간 터지듯 튕겨나갔습니다. 손이 닫히자마자 위치 고정을 풀고, 양손 접촉력이 임계치를 넘어선 뒤에야 다음 단계로 넘어가도록 순서를 다시 짜서 해결했습니다.

마지막은 무게였습니다. 0.35kg짜리 상자는 5mm밖에 들어올리지 못했습니다. 지금 확실하게 집고 옮기고 내려놓을 수 있는 건 0.10kg 상자뿐이라, 페이로드 상한을 올리는 건 다음 커리큘럼으로 남겨뒀습니다.

이 네 가지를 넘고 나서는 골반을 고정한 상태에서 637개 제어 스텝 동안 집기·옮기기·내려놓기가 한 번에 성공했고(1/1), 같은 조건을 세 번 반복해도 전부 성공했습니다(3/3). 스크립트가 좌표만 텔레포트시킨 결과가 아니라, 접촉 물리로 실제 힘이 오가는 조건에서 나온 결과라는 점이 중요합니다. 여기까지는 확정된 성과입니다.

걷다가 멈춰서 잡으려 하자, 다리를 더 학습시키는 쪽으로 세 번 헛다리를 짚었습니다

전진 보행에 성공한 정책은 그대로 얼려두고, 걸어가다 멈춘 뒤 팔만 뻗어 잡는 방식을 시도했습니다. 걷기 → 제동 → 정지 → 매니퓰레이션 전환 자체는 문제없었고, 복도를 걸어 목표 지점까지 이동하는 것도 성공했습니다. 그런데 실제로 손을 뻗는 순간 양손 접촉 타이밍이 어긋나거나 무게중심이 학습된 범위 밖으로 밀려나면서, 1,009번째 스텝에서 균형이 무너졌습니다.

균형이 문제라면 다리에 보정(residual) 동작을 더 학습시키면 될 거라 생각했습니다. 걷기 정책 가중치는 그대로 둔 채 다리 12개 관절에만 보정값을 얹는 컨트롤러를 학습시켰는데, 첫 결과물은 최대 이탈 거리 2.716m로 개선되는 듯 보였지만 이어서 학습한 세 모델은 오히려 3.096~3.161m로 더 나빠졌습니다. 원인은 다리의 능력이 아니라, 고정 상태에서 학습해둔 팔 동작과 걷다 멈춘 상태에서 실제로 필요한 팔 동작의 분포가 서로 다르다는 데 있었습니다. 게다가 목표 지점에서 멀어질수록 지수적으로 줄어드는 보상 함수 때문에, 크게 벗어난 순간부터는 “돌아오라”는 신호 자체가 거의 사라지고 있었습니다.

보상 함수와 학습 조건을 다시 설계해 이어서 학습시키자 이번엔 여덟 번의 반복 시험 모두 넘어지지 않는, 고무적인 결과가 나왔습니다. 그런데 이 결과를 실제 손목 궤적을 재생하는 조건에 넣자마자 무너졌습니다. 추적해보니 원인은 어이없었습니다 — 정지 환경의 매니퓰레이션 스텝 카운터가 0으로 고정돼 있어서, 손목 명령이 내부적으로 0이 곱해져 아예 전달되지 않고 있었습니다. 팔이 하나도 안 움직인 채로 “균형을 지켰다”는 가짜 성공이었던 셈입니다. 버그를 고치고 실제 손목 이동을 반영하자 처음의 좋은 결과는 사라졌고, 15초 부근에서 다시 넘어졌습니다.

다리 12개로 부족하다면 허리 3개 관절까지 보정 권한을 넓히면 어떨까 싶어 15개 관절 컨트롤러도 시도했습니다. 넘어지기까지 걸린 시간과 최대 기울기는 확실히 개선됐지만, 결정적 지표인 골반 이동 거리는 오히려 1.86m까지 벌어져 허용 기준(0.2m)의 아홉 배를 넘겼습니다. 허리는 순간적인 충격을 흡수해 “당장 쓰러지는 것”은 늦출 수 있었지만, 로봇을 원래 자리에 붙잡아두는 능력은 없었습니다. 넘어짐 지연과 자세 유지는 서로 다른 문제라는 걸 이때 구분하게 됐습니다.

발이 어딜 딛고 있는지부터 다시 물었습니다

다음으로 시도한 건 실제 발바닥 접촉력을 읽어 균형을 잡는 컨트롤러였습니다. 단일 환경에서는 35초짜리 성공이 나왔지만, 여덟 개 환경에서 동시에 재현하자 성공률이 12.5%로 떨어졌습니다. 원인을 파보니 더 근본적인 문제였습니다 — 지금 쓰는 GPU 물리 시뮬레이션 경로는 발바닥이 정확히 어느 지점을 딛고 있는지를 안정적으로 돌려주지 못했습니다. 마찰 계수를 올리거나 발 움직임 허용 범위를 완화해도 증상만 이동할 뿐, 다리 게인을 아무리 조정해도 소용없는 이유가 컨트롤러가 아니라 그 컨트롤러가 받는 감각 정보 쪽에 있었던 것입니다.

그래서 접촉 위치를 직접 재는 대신, 로봇의 질량 분포와 물리 제약을 수식으로 풀어 필요한 관절 힘을 역산하는 방식(constrained inverse dynamics)으로 접근을 바꿨습니다. 좌표계 혼용과 부호 오류라는 구현 버그 두 개를 고치고 나서야 처음으로 재현 가능한 성공이 나왔습니다 — 여덟 번 반복, 각 5초, 팔을 움직이지 않는 조건에서 발 이동 1cm 미만으로 전부 통과했습니다. 다만 이건 “팔을 안 움직였을 때”의 성공이었습니다. 손목이 실제로 뻗기 시작하면 팔에서 오는 반작용력이 다리가 감당할 수 있는 마찰 한계를 넘어섰고, 다리 12개·다리+허리 15개·전신 29개로 구조를 세 번 바꿔가며 시도해도 같은 방식으로 무너졌습니다. 같은 실패가 서로 다른 구조에서 세 번 넘게 반복됐다는 건 계수를 더 조정한다고 풀릴 문제가 아니라는 신호였습니다. 그래서 내부 게인 조정은 멈추고, 접촉을 더 명시적으로 다루는 다른 계열의 컨트롤러로 넘어갔습니다.

컨트롤러를 바꾸고 나서 — 양손 이동은 뚫렸고, 접촉 직전에서 다시 막혔습니다

양팔이 움직이기 전에 무게중심이 어느 쪽으로 쏠릴지 미리 계산해 골반 자세를 앞서 보정하는 방식을 시도했습니다. 왼쪽 손목 20mm 이동은 통과 기준(1mm 이내 오차)을 넘겼지만, 오른쪽은 1.34~1.43mm에서 멈췄습니다. 이유는 무게중심이 아니라 오른쪽 손목 피치 관절이 물리적 상한을 약 0.5밀리라디안 넘어서고 있었기 때문이었습니다. 팔에만 적용하는 관절-한계 회피 목표를 추가하고, 다리가 제동 여력을 다 쓰기 전에 팔 가속도를 낮추는 단계를 더하자 결과가 확실히 갈렸습니다. 왼쪽·오른쪽 순차 이동은 0.959mm·0.779mm, 양손 동시 이동은 0.996mm·0.589mm 오차로 통과했고 발 이동은 최대 7.44mm에 그쳤습니다. 손목을 정해진 위치로 평행이동시키는 것까지는 뚫린 셈입니다.

이어서 안전 감시 범위를 팔을 포함한 29개 관절 전체로 넓히고 사전 파지 자세를 시켜보니, 18초 동안 넘어지지 않고 발 이동도 거의 없었습니다. 다만 이건 안전장치가 잘 작동한다는 확인이지 실제로 물건을 잡았다는 결과는 아니었습니다. 다음으로 드러난 문제는 표현 방식의 불일치였습니다 — 손목 위치 기준점이 상자 중심에서 한참 벗어나 있었는데, 정작 손가락 끝은 이미 상자 표면에서 22~23mm까지 가까워진 상태였습니다. 이 어긋난 기준으로 손을 오므리자 왼쪽은 살짝 닿았지만 오른쪽은 아예 닿지 않았습니다. 접근 방식을 세 번 바꿔봐도 양손이 동시에 눌러붙는 조건은 만들지 못해서, 국소적인 궤적·게인 조정은 여기서 멈췄습니다.

지금까지 확정된 것과 아직 아닌 것

확정된 것: 팔 그래프트가 붙은 G1은 여전히 걷고 멈추고 안정적으로 넘겨받을 수 있습니다. 골반을 고정한 상태에서는 물체를 실제로 쥐고 옮기고 놓는 것도 확인됐습니다. 손가락 24개 관절과 접촉 물리, 양손 협응까지 시뮬레이션에서 정상 작동합니다. 팔을 움직이지 않는 조건이라면, 접촉을 명시적으로 다루는 새 균형 컨트롤러로 로봇을 세워둘 수도 있습니다. 여기에 더해, 양쪽 손목을 각각 또는 동시에 20mm씩 평행이동시키는 동작도 넘어짐 없이 통과했습니다.

아직 아닌 것: 걷다가 멈춰서 실제로 손을 뻗어 잡는 것(floating-base pick)은 여전히 통과하지 못했습니다. 걷기 → 멈추기 → 잡기로 이어지는 연속 동작도 완성되지 않았습니다. 손목을 원하는 각도로 돌리는 것, 미리 힘을 준 채 접근하는 것, 들어올리고 내려놓는 것은 아직 물리적으로 검증된 적이 없습니다. 더 큰 매니퓰레이션 정책을 이 위에 얹어 학습시키거나 실제 로봇 제어 경로에 연결하는 단계는 시작하지 않았습니다. 한 번의 우연한 성공이나 안전장치를 꺼서 얻은 결과는 성과로 세지 않는다는 기준도 그대로 유지합니다.

이 실험에서 남는 진짜 교훈은 “휴머노이드 매니퓰레이션 스택을 완성했다”가 아닙니다. 겉보기 장벽이 하나씩 걷힐 때마다 진짜 원인이 좁혀져 온 과정입니다. 손 에셋 문제 → 손가락 충돌 → 자코비안 인덱싱 → 끊어진 손목 명령 경로 → 접촉 위치 감지 → 관절 한계 회피 → 그리고 지금은, 수학적으로 타당한 해와 시뮬레이터가 실제로 구현하는 접촉 운동 사이의 간극입니다.

앞으로 어떻게 할 것인가

다음으로 확인할 건 세 가지로 좁혀집니다. 첫째, 손바닥 기준 파지 프레임을 명시적으로 정의해 손목 목표 지점과 손끝 실제 위치를 하나의 좌표계로 통일합니다. 둘째, 손끝 형태를 반영한 여유 공간(fingertip-envelope)을 계산에 넣어서, 손끝이 이미 표면에 닿아있는데 기준점만 멀리 있는 것처럼 인식하는 착시를 없앱니다. 셋째, 힘으로 실제로 실현 가능한 중간 경유 자세를 먼저 정의한 뒤에 물리 재생으로 돌아갑니다 — 계산상으로만 풀리고 실제 관절 가속도·접촉력이 못 따라가는 해는 더 이상 성공으로 세지 않습니다.

이 세 가지를 순서대로 통과시켜 오른쪽 접촉 실패를 먼저 없애고, 그다음에야 들어올리기·내려놓기, 그리고 걷기 → 멈추기 → 잡기로 이어지는 연속 동작을 다시 시도할 계획입니다. 이 단계를 건너뛰고 자연어 명령을 관절 명령으로 옮기는 VLA 통합으로 먼저 넘어가는 건, 물체를 놓치는 원인을 그대로 안고 다음 단계로 가는 것과 같습니다. 검증된 접촉 인식 컨트롤러가 지금 남은 간극을 실제로 좁혀주는지, 그 답이 나오면 다음 글에서 이어서 다루겠습니다. 그 이후의 중간 보고는 접촉을 하나씩 빼며 확인한 기록에 이어서 남겼습니다.

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤