Study/Mujoco

Mujoco 장단점 & 플랫폼 만들기

hongtlee 2025. 6. 4. 10:54

리눅스 설치해서 ROS2 사용하는게 로봇 관련 작업에 제일 편하다.

하지만 어쩔 수 없는 이유로 윈도우 환경에서 로봇 시뮬레이션을 실행하고 싶을 수 있다. 

이때 선택할 수 있는 선지 중 Mujoco가 있다.

 

Mujoco가 무료라 사용에 용이해 보이지만 생각보다 시뮬레이터로 사용하기 까다롭다.

간단하게 feasibility을 보기 위해서는 RoboDK를 사용하는 것이 좋다. 하지만 RobodDK는 유료라는 점...

무료 버전으로도 적당히 테스트 할 수 있지만 규모가 커지면 유료 버전이 필요해진다. 또한 상업적 이용에 어렵다.

 

Mujoco를 사용한지 4달 뿐이라 초보지만 느낀바로는,

- 장점

* mujoco는 상업적 이용이 가능한 라이센스를 갖고 있고, c++17 라이브러리로 사용 가능해 확장성이 뛰어나다.

* 파이썬을 통해 stl로부터 map을 생성하고, 생성된 map 끼리 attachment site로 붙혀 더 큰 map을 생성할 수 있다.

* openGL을 사용해 시각화 할 수 있다.

* 충돌 감지할 수 있다.

 

- 단점

* low레벨부터 코드 구현해야 함

    * joint만 존재해서 로봇을 움직이기 위해 각 joint에 토크를 주는 방식으로 joint를 운동시킴
    * 익히 사용하는 moveJ, moveL 등이 없어서 직접 구현해야 함.

    * PD 컨트롤 등으로는 댐핑이 생겨 동역학을 통한 컨트롤에는 로봇에 떨림이 생김.

 

* Multi robot 조작 불편함

    * mjcf에서 prefix로 로봇을 구분 지어도, 실제 로봇 조작에 필요한 joint index등이 1차원 배열에 저장됨

    * 만약 로봇2의 joint1을 움직이고 싶으면 아래 코드처럼 index에 맞게 넣어줘야 함

...
data_->qpos[baseIndex_ + 0] = q_target.j1;
data_->qpos[baseIndex_ + 1] = q_target.j2;
data_->qpos[baseIndex_ + 2] = q_target.j3;
...

 

* 런타임 중 model(map) 수정이 안됨

    * 미리 MJCF에 생성한 object에 대해서 충돌 감지 및 역학 적용 가능

    * 새 model에 object를 추가하고 load해서 업데이트하면 가능하지만 속도 측면에서 불리함이 예상됨

    * 미리 더미 object를 맵에 생성하고 숨긴 후, 필요에 따라 더미를 옮기고 활성화하는 방법으로는 가능.

 

 

생각보다 단점이 어마무시하다. 특히 런타임 중 model(map) 수정이 안되는건 치명적이다. 이래선 SLAM 처럼 실시간 맵 생성해야 하는 분야에선 사용하기 어려울 것이다. (만약 mujoco에서 실시간 맵 생성 방법을 알고 계신다면 조언 부탁드립니다.)

실시간 맵 생성이 필수라면 CoppeliaSim이나 ROS2로 넘어가는게 현명하다. 

 

일단 6DOF 로봇 조작이 목적이므로 mujoco를 계속 사용해보긴 할 것이다.

 

사실 mujoco의 기능을 전부 사용하지도 않아 기껏해야 openGL 연동, 충돌감지만 사용하는 정도라 장단점은 4개월 차 사용자가 느낀 정도라 생각하면 된다.

 

 

 

사이트 프로젝트로 만들고 있는 시뮬레이터 플랫폼에서 사용하는 라이브러리는 다음과 같다.

1. Eigen

2. Mujoco

3. glfw

4. urdfdom

5. EAIK

 

결국 로봇을 테스트 하기 위해서 비슷한 과정을 거친다.

1. Map 생성

2. 타겟 지정

3. 타겟 지점에 대해 kinematics 풀기

4. 주변 환경에 대해 충돌 감지

5. 실행

 

1)

Map 생성에 좀 방법을 찾아야 한다. mujoco는 xml 기반의 mjcf를 사용하는데 로봇 생태계에서 대부분의 로봇은 URDF파일을 공유한다. Mujoco에서도 urdf를 지원하지만 어딘가 이상하다.

그래도 map 생성은 쉽다.

import mujoco
import math

# 빈 스펙(옵션·asset 정도만 남긴 최소 스펙)
base_spec = mujoco.MjSpec.from_file("./minimal_world.xml")

# ur5e.xml과 tool.xml을 각각 스펙으로 로드
parent_spec = mujoco.MjSpec.from_file("./universal_robots_ur5e/ur5e.xml")
child_spec = mujoco.MjSpec.from_file("./universal_robots_ur5e/ur5e.xml")

# 1) 부모 스펙을 붙이면서 prefix
base_spec.attach(parent_spec, site=base_spec.worldbody.sites[0], prefix="robot1_")

# 부모 스펙(ur5e.xml)에서 attachment_site를 찾습니다.
new_site = base_spec.worldbody.add_site(name="robot2_base_attachment_site",
                                     pos=[-0.9, -0.9, 0],  # 원하는 위치 (예시)
                                     euler=[0.0, 0.0, math.pi])      # 원하는 회전 (예시)

# attachment_site에 child_spec(tool.xml)을 부착합니다.
# 기본 동작은 얕은 복사가 되어, child_spec의 변경이 부모에 영향을 줍니다.
attached_frame = base_spec.attach(child_spec, site=new_site, prefix="robot2_")

# 필요 시, attached_frame의 이름에 prefix, suffix를 추가할 수 있습니다.
# 예: attached_frame = parent_spec.attach(child_spec, site=attachment_site, prefix="tool_", suffix="_child")

# 최종적으로 스펙을 컴파일하여 모델 생성
model = base_spec.compile()

# MjSpec 객체를 XML 문자열로 변환
xml_string = base_spec.to_xml()
xml_string = xml_string.replace("<default/>", "").replace("<default />", "")

# XML 문자열을 파일로 저장합니다.
with open("multi_without_tool_model.xml", "w", encoding="utf-8") as f:
    f.write(xml_string)

print("Merged model saved to multi_model.xml")

 

URDF 생성하는 좋은 도구가 있는지 모르겠지만, mjcf 생성하는게 훨씬 쉽다.

특히 ROS2에서 어려웠던 부분이 multi robot인데, mujoco에서는 ROS2에 비하면 쉬운 편이다.

 

2) 타겟 지정

application에 따라 달라질 것이다. 용접, pick & place 등에 따라 달라질 것.

CAD로부터 point 추출할 생각이다.

어쩌면 2d 이미지 활용할 수 있다면 좋을지도. 포인트클라우드를 얻을 수 있는 카메라는 비싸다..

 

3) Kinematics 풀기

처음에는 동역학으로 PD-control로 moveJ, moveL 구현했지만, 댐핑이 있어 로봇이 떨린다.

이게 훨씬 현실적이겠지만 포기하고 시뮬레이터 시간에 따른 위치를 스플라인 보간법을 통해 구한 후 kinematics를 풀었다.

그리고, 각 시간에 맞춰 mj_forward(model_, data_); 명령으로 강제 이동시켰다.

 

다만, Modern Robotics를 통해 구하는 inverse kinemtics는  1:1 대응이다. 즉, 하나의 target에 대해 6DOF 로봇은 16(or 8)개의 해를 가지는데, 자코비안을 통해 error을 0으로 보내는 수치적 방법을 사용하기에 1개의 joint해만 구할 수 있으며 시작 joint도 필요하다.

 

이에 해석적으로 inverse kinematics을 풀어 모든 해를 구할 수 있도록 해야하는데, 가장 유명한 것이 OpenRave의 IKFast이다.

문제는 너무 옛날 패키지라 윈도우에서 설치도 어려울 뿐더러 리눅스를 가더라도 wheel이 마땅치 않아 20.04에 ROS Noetic을 설치해야 한다.

 

대안으로 EAIK(https://github.com/OstermD/EAIK)를 찾았다. nR 로봇에 대해 subproblem을 풀어 IKFast보다 더 빠르게 역기구학 해를 구하는 라이브러리다. 계속 업데이트 중이지만 일단 사용해보려 한다.

 

4) 충돌 감지는 mujoco 사용

 

5) 이상이 없으면 실행하면 된다.

충돌이 발생하면 이제 충돌 없도록 target의 위치를 바꿔줘가며 테스트하는 노가다가 시작될 것이다.

 

더 나아가면 PRM, RRT와 같은 motion planning이 필요해진다.