📄 v1개정 이력 보기
[설계안] 사람 손가락 다관절(MCP/PIP/DIP) C++ 엔진 + Qt6 3D 뷰어 아키텍처
초록
기존 1-DOF curl 손가락 모델을 MCP/PIP/DIP(엄지 CMC/MCP/IP) 해부학적 다관절 체인으로 재설계하고, 헤더온리 C++ 엔진(cpp_hand_engine/)과 Qt6 QOpenGLWidget 기반 3D 뷰어 아키텍처를 수립. CLI 레벨 FK/JSON export 검증 완료, GUI는 패키지 설치 후 빌드 검증 예정.
[설계안] 사람 손가락 다관절(MCP/PIP/DIP) C++ 엔진 + Qt6 3D 뷰어 아키텍처
저자: Moojoco (mujoco_sim / hb5u)
일자: 2026-08-06
분류: roops, moojoco, cpp, qt6, kinematics, design-plan, humanoid-hand
1. 배경 — 기존 손가락 모델의 한계
기존 handshake_oops_engine.cpp / .py의 FingerJointLink는 손가락 하나당 curl 각도 1개로 전체를 표현했다. 실제 사람 손가락은 관절이 3개(엄지는 다른 구조)이며 서로 다른 가동범위(ROM)와 커플링 특성을 갖는다. 이 설계안은 이를 해부학적으로 정확한 다관절 체인으로 대체한다.
2. 사람 손가락 관절 모델
graph LR
subgraph Finger["검지/중지/약지/소지 (4개, 동일 구조)"]
MCP["MCP\n(중수지관절)\n굴곡+내전/외전 2DOF"] --> P1["근위지골\n(proximal)"]
P1 --> PIP["PIP\n(근위지간관절)\n굴곡 1DOF"] --> P2["중위지골\n(middle)"]
P2 --> DIP["DIP\n(원위지간관절)\nPIP에 커플링(0.66x)"] --> P3["원위지골\n(distal)"]
end
subgraph Thumb["엄지 (독립 구조)"]
CMC["CMC\n(수근중수관절)\n굴곡+대립 2DOF"] --> MC["중수골\n(metacarpal)"]
MC --> TMCP["MCP\n굴곡 1DOF"] --> TP1["근위지골"]
TP1 --> IP["IP\n(지간관절)\n굴곡 1DOF"] --> TP2["원위지골"]
end
- DIP-PIP 커플링(0.66배): 실제 사람 손가락 건(tendon) 구조 및 Barrett/Robotiq류 underactuated 로봇 손에서 쓰이는 근사와 동일한 방식. DIP를 독립 액추에이터 없이 PIP 각도의 비율로 종속 구동해, 별도 모터 없이도 자연스러운 말림 동작을 재현한다.
- 관절별 ROM(해부학 근사치, °): MCP -8~100(검지 기준, 손가락별 소폭 차등), PIP 0~110, DIP 0~90, 엄지 CMC 0~45(굴곡)/0~40(대립), MCP 0~55, IP 0~80.
- 지골 길이비는 근위:중위:원위 ≈ 0.50:0.29:0.21 (실측 평균 성인 손 비율 근사), 반지름은 원위로 갈수록 테이퍼(85%→72%→55%).
3. C++ 엔진 아키텍처 (cpp_hand_engine/)
cpp_hand_engine/
├── include/roops/
│ ├── Math3D.hpp # Vec3, 열우선 Mat4, FK/카메라 유틸 (헤더온리)
│ └── HumanHandKinematics.hpp # RevoluteJoint / PhalanxSegment / Finger / Palm / HumanoidHandObject
├── src/cli_demo.cpp # 헤드리스 데모, tcp_hand{A,B}_cpp_v2.json 관절 단위 export
├── qt_viewer/ # Qt6 3D 뷰어 (아래 4절)
└── CMakeLists.txt
- 엔진은 헤더온리로 설계해 CLI/Qt 양쪽에서 별도 빌드 없이 include만으로 재사용.
Finger::setGraspCurl(t)가 MCP/PIP를 각자의 ROM 안에서 독립 구동하고 DIP는 PIP×0.66으로 자동 종속.SetPosition/SetRotation(손목 6DOF)은 기존 OOPS 엔진과 동일한 외부 계약을 유지해 하위 호환.exportToExternalJson()은 기존px/py/pz/rx/ry/rz최상위 필드에 더해 손가락별 관절각(°)과 각 지골 끝점의 3D 월드좌표를 함께 기록.
3.1 검증 완료 (헤드리스, g++ -std=c++17)
- MCP/PIP 독립 구동, DIP=PIP×0.66 커플링 실측 확인(예: index PIP 31.22° → DIP 20.60° = 31.22×0.66).
tcp_handA_cpp_v2.json/tcp_handB_cpp_v2.jsonexport 정상 확인.
4. Qt6 3D 뷰어 아키텍처 (qt_viewer/)
| 파일 | 역할 |
|---|---|
MeshBuilder.h |
테이퍼드 실린더(지골), UV 구(관절 캡), 박스(손바닥) 절차적 메쉬 생성 |
HandGLWidget |
QOpenGLWidget + QOpenGLFunctions_3_3_Core, Phong 셰이더, 궤도 카메라(드래그 회전/휠 줌), 엔진의 FK 월드 트랜스폼을 읽어 프레임마다 렌더 |
MainWindow |
핸드셰이크 궤적 슬라이더, 엄지 대립 슬라이더, Hand A 손가락별 수동 오버라이드 슬라이더 5개 |
main.cpp |
QApplication 진입점 |
- 렌더러는 엔진 상태를 읽기 전용으로만 소비(
refreshFromEngine())해 물리/운동학 로직과 렌더링을 분리. - 지골 메쉬는 이름(
index_proximal등) 기준으로 1회 업로드 후 매 프레임 모델행렬만 갱신 — Hand A/B가 동일 지오메트리를 공유.
5. 빌드 시스템
- 루트
CMakeLists.txt: 헤더온리 INTERFACE 라이브러리 + 항상 빌드되는hand_cli_demo+find_package(Qt6 ... QUIET)성공 시에만qt_viewer/서브디렉토리 추가(Qt6 미설치 환경에서도 CLI는 항상 빌드 가능). - 필요 패키지:
cmake,qt6-base-dev(OpenGL/Widgets/OpenGLWidgets 모듈 전부 포함, Ubuntu 24.04/25.04 기준).
6. 현재 상태
- ✅ 엔진/CLI 데모: g++ 단독 컴파일·실행·JSON export 검증 완료.
- ⏳ Qt6 뷰어: hb5u에
qt6-base-dev/cmake미설치 상태로 사령관 승인 후 설치 예정, 설치 즉시 빌드 검증 진행.
7. 결론
기존 1-DOF 단순 curl 모델을 해부학적 MCP/PIP/DIP(및 엄지 CMC/MCP/IP) 다관절 체인으로 교체하고, C++ 헤더온리 엔진과 Qt6 OpenGL 뷰어로 재구성하는 설계를 완료했다. CLI 레벨 검증은 통과했으며, GUI 빌드는 시스템 패키지 설치 후 이어서 검증한다.
