urdf에서 mjcf로 갈아탔다..
isaac gym에서 지원하는 urdf로 character model을 만드려고 했는데
urdf에서는 ball joint를 지원하지 않아서 ball joint를 구현하기 위해서는 3개의 연속된 hinge joint를 배치해서 euler angle처럼 사용하는 식으로 해야한다고 하는데 완전히 잘 동작한다고 보기는 어려운 부분이 많아서 ball joint를 지원하면서도 isaac gym에서도 지원하는 mjcf 형식으로 character model을 만들기로 했다!
막막하지만 그래도 고!
https://ropiens.tistory.com/170
이 게시물을 참고하여 내 나름대로 공부하면서 정리해보았다.
panda로봇의 mjcf 파일을 살펴보자.
<mujoco model="panda">
<actuator>
<!-- Physical limits of the actuator. -->
<motor ctrllimited="true" ctrlrange="-80.0 80.0" joint="joint1" name="torq_j1"/>
<motor ctrllimited="true" ctrlrange="-80.0 80.0" joint="joint2" name="torq_j2"/>
<motor ctrllimited="true" ctrlrange="-80.0 80.0" joint="joint3" name="torq_j3"/>
<motor ctrllimited="true" ctrlrange="-80.0 80.0" joint="joint4" name="torq_j4"/>
<motor ctrllimited="true" ctrlrange="-80.0 80.0" joint="joint5" name="torq_j5"/>
<motor ctrllimited="true" ctrlrange="-12.0 12.0" joint="joint6" name="torq_j6"/>
<motor ctrllimited="true" ctrlrange="-12.0 12.0" joint="joint7" name="torq_j7"/>
</actuator>
<asset>
<mesh name="link0" file="meshes/link0.stl" />
<mesh name="link1" file="meshes/link1.stl" />
<mesh name="link2" file="meshes/link2.stl" />
<mesh name="link3" file="meshes/link3.stl" />
<mesh name="link4" file="meshes/link4.stl" />
<mesh name="link5" file="meshes/link5.stl" />
<mesh name="link6" file="meshes/link6.stl" />
<mesh name="link7" file="meshes/link7.stl" />
<mesh name="link0_vis" file="meshes/link0_vis.stl" />
<mesh name="link1_vis" file="meshes/link1_vis.stl" />
<mesh name="link2_vis" file="meshes/link2_vis.stl" />
<mesh name="link3_vis" file="meshes/link3_vis.stl" />
<mesh name="link4_vis" file="meshes/link4_vis.stl" />
<mesh name="link5_vis" file="meshes/link5_vis.stl" />
<mesh name="link6_vis" file="meshes/link6_vis.stl" />
<mesh name="link7_vis" file="meshes/link7_vis.stl" />
</asset>
<worldbody>
<body name="base" pos="0 0 0">
<!-- robot view -->
<camera mode="fixed" name="robotview" pos="1.0 0 0.4" quat="0.653 0.271 0.271 0.653"/>
<inertial diaginertia="0 0 0" mass="0" pos="0 0 0"/>
<!-- mount attached here -->
<body name="link0" pos="0 0 0">
<inertial pos="0 0 0.05" mass="4" diaginertia="0.4 0.4 0.4" />
<geom type="mesh" contype="0" conaffinity="0" group="1" mesh="link0_vis" name="link0_visual" rgba="1 1 1 1" />
<geom type="mesh" group="0" mesh="link0" name="link0_collision"/>
<body name="link1" pos="0 0 0.333">
<inertial pos="0 0 -0.07" mass="3" diaginertia="0.3 0.3 0.3" />
<joint name="joint1" pos="0 0 0" axis="0 0 1" limited="true" range="-2.8973 2.8973" damping="0.1"/>
<geom type="mesh" contype="0" conaffinity="0" group="1" mesh="link1_vis" name="link1_visual" rgba="1 1 1 1" />
<geom type="mesh" group="0" mesh="link1" name="link1_collision"/>
<body name="link2" pos="0 0 0" quat="0.707107 -0.707107 0 0">
<inertial pos="0 -0.1 0" mass="3" diaginertia="0.3 0.3 0.3" />
<joint name="joint2" pos="0 0 0" axis="0 0 1" limited="true" range="-1.7628 1.7628" damping="0.1"/>
<geom type="mesh" contype="0" conaffinity="0" group="1" mesh="link2_vis" name="link2_visual" rgba="1 1 1 1" />
<geom type="mesh" group="0" mesh="link2" name="link2_collision"/>
<body name="link3" pos="0 -0.316 0" quat="0.707107 0.707107 0 0">
<inertial pos="0.04 0 -0.05" mass="2" diaginertia="0.2 0.2 0.2" />
<joint name="joint3" pos="0 0 0" axis="0 0 1" limited="true" range="-2.8973 2.8973" damping="0.1"/>
<geom type="mesh" contype="0" conaffinity="0" group="1" mesh="link3_vis" name="link3_visual" rgba="1 1 1 1" />
<geom type="mesh" group="0" mesh="link3" name="link3_collision"/>
<body name="link4" pos="0.0825 0 0" quat="0.707107 0.707107 0 0">
<inertial pos="-0.04 0.05 0" mass="2" diaginertia="0.2 0.2 0.2" />
<joint name="joint4" pos="0 0 0" axis="0 0 1" limited="true" range="-3.0718 -0.0698" damping="0.1"/>
<geom type="mesh" contype="0" conaffinity="0" group="1" mesh="link4_vis" name="link4_visual" rgba="1 1 1 1" />
<geom type="mesh" group="0" mesh="link4" name="link4_collision"/>
<body name="link5" pos="-0.0825 0.384 0" quat="0.707107 -0.707107 0 0">
<inertial pos="0 0 -0.15" mass="2" diaginertia="0.2 0.2 0.2" />
<joint name="joint5" pos="0 0 0" axis="0 0 1" limited="true" range="-2.8973 2.8973" damping="0.1"/>
<geom type="mesh" contype="0" conaffinity="0" group="1" mesh="link5_vis" name="link5_visual" rgba="1 1 1 1" />
<geom type="mesh" group="0" mesh="link5" name="link5_collision"/>
<body name="link6" pos="0 0 0" quat="0.707107 0.707107 0 0">
<inertial pos="0.06 0 0" mass="1.5" diaginertia="0.1 0.1 0.1" />
<joint name="joint6" pos="0 0 0" axis="0 0 1" limited="true" range="-0.0175 3.7525" damping="0.01"/>
<geom type="mesh" contype="0" conaffinity="0" group="1" mesh="link6_vis" name="link6_visual" rgba="1 1 1 1" />
<geom type="mesh" group="0" mesh="link6" name="link6_collision"/>
<body name="link7" pos="0.088 0 0" quat="0.707107 0.707107 0 0">
<inertial pos="0 0 0.08" mass="0.5" diaginertia="0.05 0.05 0.05" />
<joint name="joint7" pos="0 0 0" axis="0 0 1" limited="true" range="-2.8973 2.8973" damping="0.01"/>
<geom type="mesh" contype="0" conaffinity="0" group="1" mesh="link7_vis" name="link7_visual" rgba="1. 1. 1. 1." />
<geom type="mesh" group="0" mesh="link7" name="link7_collision"/>
<!-- rotate 135deg to align physically to the tool-->
<body name="right_hand" pos="0 0 0.1065" quat="0.924 0 0 -0.383">
<inertial pos="0 0 0" mass="0.5" diaginertia="0.05 0.05 0.05" />
<!-- This camera points out from the eef. -->
<camera mode="fixed" name="eye_in_hand" pos="0.05 0 0" quat="0 0.707108 0.707108 0" fovy="75"/>
<!-- to add gripper -->
</body>
</body>
</body>
</body>
</body>
</body>
</body>
</body>
</body>
</body>
</worldbody>
</mujoco>
skel이나 urdf보다 가독성은 떨어지지만 정의가 직관적이고 model을 작성하는 입장에서 덜 헷갈려서 편리했다.
먼저 worldbody 태그쪽을 살펴보자!
1. <worldbody> 태그 분석
worldbody 태그쪽 코드 일부를 살펴보자.
<worldbody>
<body name="base" pos="0 0 0">
<!-- robot view -->
<camera mode="fixed" name="robotview" pos="1.0 0 0.4" quat="0.653 0.271 0.271 0.653"/>
<inertial diaginertia="0 0 0" mass="0" pos="0 0 0"/>
<!-- mount attached here -->
<body name="link0" pos="0 0 0">
<inertial pos="0 0 0.05" mass="4" diaginertia="0.4 0.4 0.4" />
<geom type="mesh" contype="0" conaffinity="0" group="1" mesh="link0_vis" name="link0_visual" rgba="1 1 1 1" />
<geom type="mesh" group="0" mesh="link0" name="link0_collision"/>
<body name="link1" pos="0 0 0.333">
<inertial pos="0 0 -0.07" mass="3" diaginertia="0.3 0.3 0.3" />
<joint name="joint1" pos="0 0 0" axis="0 0 1" limited="true" range="-2.8973 2.8973" damping="0.1"/>
<geom type="mesh" contype="0" conaffinity="0" group="1" mesh="link1_vis" name="link1_visual" rgba="1 1 1 1" />
<geom type="mesh" group="0" mesh="link1" name="link1_collision"/>
<body name="link2" pos="0 0 0" quat="0.707107 -0.707107 0 0">
태그들을 살펴보면
- 1) 로봇의 body (link) 태그
- 2) body(link)의 inertial 태그
- 3) body(link)의 geometry (visual과 collision) 태그
- 4) body와 body를 이어주는 joint 태그
로 크게 구성되어있다는 점을 알 수 있다.
1) <body> 태그
로봇의 body(link) 태그에서는 (link의 이름 + link의 position + 필요하다면 orientation)을 정의한다.
이때 coordinate frame은 항상 local이다.
즉 body의 position 및 orientation 정의는 항상 parent body의 frame을 기준으로한다.
ex)
<body name="link0" pos="0 0 0">
<body name="link1" pos="0 0 0.333">
<body name="link2" pos="0 0 0" quat="0.707107 -0.707107 0 0">
이때 orientation은 꼭 quat 로 표기할 필요는 없으며 axisangle이나 euler와 같은 형식으로도 표기할 수 있다.
2) <geom> 태그
<geom> 태그는 충돌 체크를 위한 collision 부분과 시각화를 위한 visual 부분으로 나누어져있다.
(여기서 geom 태그 내에서의 position과 orientation은 geom가 속한 body를 기준으로 기술된다.)
type으로 asset에서 정의한 mesh를 쓸 수도 있지만 box, ellipsoid, sphere, cylinder 등을 쓸수도 있다.
<geom type="mesh" contype="0" conaffinity="0" group="1" mesh="link0_vis" name="link0_visual" rgba="1 1 1 1" />
<geom type="mesh" group="0" mesh="link0" name="link0_collision"/>
**주의) 여기서 box size를 기술할때 half size로 기술해야한다.
즉, 2 x 2 x 2 사이즈의 box를 만들고 싶으면 size = "1 1 1"로 기술해야한다.
(1) group 속성
살펴보면 collision 부분과 visual 부분에 모두 group이라는 속성이 있다.
- group은 렌더링 활성화를 위한 속성이다.
- 디폴트로 0의 값을 가진다.
- 값이 0이라고 해서 비활성화를 하는 것은 아니며, 렌더링할 geom이 collision 부분인지 visual 부분인지 group을 짓는 것이 목적인 속성이다. 1의 값을 가지면 visual 부분, 0의 값을 가지면 collision 부분이다.
collision 부분(group = "0") 의 렌더링을 비활성화 하고자 한다면,
viewer.vopt.geomgroup[0] = 0
이라고 적어주면 된다.
(2) contype 속성, conaffinity 속성
- 충돌 감지 여부를 위한 속성이다.
- 두 속성은 모두 디폴트로 1의 값을 가진다.
- contype 속성과 conaffinity 속성 모두 0의 값을 가지면 충돌이 일어나지 않는다.
- 즉, visual geometry는 충돌이 일어나지 않으며, 오로지 시각화를 위한 용도이다.
3) <joint> 태그
- joint의 타입은 [free, ball, slide, hinge] 로 구성되어 있다.
- default type은 hinge(revolute)이다.
- body 내부에 정의된 joint의 역할은 parent와 child를 연결한다기보다는 그들 사이에 degree of freedom을 만들어낸다고 생각하면 된다. 만약 joint가 정의되지 않는다면 child body는 parent body에 붙어버려서 움직이는 것이 불가능해질 것이다.
- joint 역시 joint가 속한 body의 coordinate frame에 대해 정의된다.
2. <actuator> 태그 분석
로봇의 관절을 구동하기 위해서는 모든 joint에 대해 actuator를 작성해주어야한다.
actuator의 종류에는 총 5가지 [motor, position, velocity, clinder, muscle]이 있다.
나처럼 isaac gym에서 로드를 하는게 목적이고, ball joint를 사용한다면 다음과 같시 설정해주면 될 것 같다.
<motor name = 'left_up_leg' joint = 'left_up_leg' />
이런식으로만 적어도 isaac gym에서 모델 파일이 정상적을 잘 동작한다.
참고)
https://github.com/bulletphysics/bullet3/blob/master/data/mjcf/humanoid.xml
3. <asset> 태그 분석
asset은 mesh, skin, texture, material 등에 해당하는 파일의 경로나 속성을 한 번에 모아주는 역할을 한다.
아래의 예시는 panda robot의 asset 일부이며, link0 mesh 파일 경로는 meshes/link0.stl 라는 것이다.
<asset>
<mesh name="link0" file="meshes/link0.stl" />
<mesh name="link1" file="meshes/link1.stl" />
<mesh name="link2" file="meshes/link2.stl" />
<mesh name="link3" file="meshes/link3.stl" />
<mesh name="link4" file="meshes/link4.stl" />
<mesh name="link5" file="meshes/link5.stl" />
<mesh name="link6" file="meshes/link6.stl" />
<mesh name="link7" file="meshes/link7.stl" />
</asset
너무 러프하게 적어서 도움을 받는 사람이 있을까 싶지만 도움이 되길 바라며..끝!
참고하면 도움이 될만한 링크)
'연구 > 컴퓨터 그래픽스' 카테고리의 다른 글
blender에서 한 model의 facial motion을 다른 model에 적용하기 (0) | 2023.06.26 |
---|---|
angular velocity 구하는 방법 (0) | 2023.02.24 |
URDF 튜토리얼(3) (Adding Physical and Collision Properties to a URDF Model) (3) | 2023.01.19 |
URDF 튜토리얼(2) (Building a Movable Robot Model with URDF) (0) | 2023.01.19 |
URDF 튜토리얼(1) (Building Visual Robot Model) (1) | 2023.01.19 |