PyBulet 조사2: 여러 구성 요소로 구성된 객체
시작
이것은 며칠 전에 쓴 PyBulet의 조사 보도의 후속 내용이다.
지난번PyBullet에 대한 기본 정보와 단순한 대상의 구축을 조사해 기재한 결과, 이번에는 여러 개의 구성 요소로 구성된 더욱 복잡한 모델의 구축을 조사했다.(지난번 보도를 읽지 않은 독자는 저쪽에서 한 번 보세요.)
꼼꼼한 내용 없이 기존 URDF 포맷 파일에 저장된 모델을 사용하고, 강화 학습을 빠르게 하려면 페이스북 리서치제pybulletX를 활용하는 것이 좋다.
소식을 소개하다도 썼고 관심 있는 사람도 보세요.
1. 여러 구성 요소 구조 이해
지난번과 마찬가지로 PyBullet의 API를 이용하여 모델을 구축하고자 하였으며, 다음URDF 형식에 설명한 블로그 글은 여러 구성 요소로 구성된 대상의 개념을 이해하기 위해 참고하였다.(개인적으로 XML을 쓰기 싫어서 프로그램으로 대응하고 싶어요.)
또 URDF 형식공식 자습서 페이지도 이미지를 잡는 데 도움이 된다.(특히 처음 그림은 이해하기 쉬우니 먼저 열어 보시면 좋겠습니다.)
링크(=link)로 불리는 부품은 조인트(=joint)를 통해 결합됩니다.링크 자체는 링크의 좌표계에서 마지막으로 설명한 충돌 판정용 객체 등을 구성하는 독립된 좌표계입니다.
스플라이스를 통해 연결된 링크는 모 피쳐 링크의 원점에서 시작하여 모 피쳐 링크의 원점을 이동, 회전 후에 배치합니다.
조인트는 가동 방법에 따라 다양한 종류가 있는데 하위 링크는 원점을 중심으로 이동한다.
PyBulet의 API에서 지정할 수 있는 것은
JOINT_REVOLUTE
, JOINT_PRISMATIC
, (축으로 이동), JOINT_FIXED
(고정) 및 공식 문서뿐입니다.Bulet3 자체도 다른 유형의 인터페이스를 지원하는데 설치도 내부에만 전달되는 C++ 함수처럼 보이는데 PyBullet부터 사용할 수 있는지 계속 조사가 필요하다.
또 존재설치 보기,
JOINT_REVOLUTE
,JOINT_PRISMATIC
,JOINT_SPHERICAL
,JOINT_PLANAR
,JOINT_FIXED
,JOINT_POINT2POINT
,JOINT_GEAR
등의 상수가 있다.Bulet3에서는 부모가 없는 주요 링크를'기초(=base)'라고 부르며 특수처리한다.링크 id로 관리하고 지정한 대상에 포함된 링크를 사용하며 기본적인 링크 id는
-1
입니다.화공식 문서에 기재된 것, 다음 장에 기재된 구조 시
-1
가 아니라0
....-1
는 오류 없이 대상을 표시하지 않습니다...함수를 통해 구축된 링크 인터페이스의 정보를 얻으면 친링크 id가
pybullet.getJointInfo
로 변합니다..수수께끼야.2. PyBulet의 구축
여러 개의 (하위) 링크를 포함하는 대상을 배치하려면 간단한 대상을 설정하는 것과 같은
-1
함수를 사용하십시오.이때
pybullet.createMultiBody
·(질량)·linkMasses
(충돌 판정용)·linkCollisionShapeIndices
·(외관)·linkVisualShapeIndices
(부체인에서 부체인의 원점 위치)·linkPositions
(부체인에서 부체인의 방향·회전)·linkOrientations
・linkInertialFramePositions
・linkInertialFrameOrientations
・linkParentIndices
・(이음매의 종류)・linkJointTypes
(이음매의 축)같은 길이의 목록에서 명확하게 지정해야 한다.많이 힘들었어요. 지정하지 않으면
linkJointAxis
과오류 발생.(오류 메시지에 무엇이 부족한지 알 수 없고 원본 코드에 오류가 발생한 조건을 확인했습니다.)obj_id = pybullet.createMultiBody(mass, box_cid, -1,
basePosition=[0, 0, 0.1],
linkMasses=[mass, mass],
linkCollisionShapeIndices=[-1, cylinder_cid],
linkVisualShapeIndices=[-1, -1],
linkPositions=[[0, 0, 0],[0,0.5,0.5]],
linkOrientations=[[0,0,0,1], [1,0,0,math.cos((3/8)*math.pi)]],
linkInertialFramePositions=[[0,0,0],[0,0,0]],
linkInertialFrameOrientations=[[0,0,0,1],[0,0,0,1]],
linkParentIndices=[0, 1],
linkJointTypes=[pybullet.JOINT_REVOLUTE, pybullet.JOINT_FIXED],
linkJointAxis=[[1,0,0],[1,0,0]],
physicsClientId=engine_id)
는 "All link arrays need to be same size."
함수를 통해 연축기의 가동 범위를 지정할 수 있다.실복을 읽다만 해당,
pybullet.changeDynamics
일 경우 가동 범위가 업데이트됩니다.pybullet.changeDynamics(obj_id,
1, # link id
jointLowerLimit=-1,
jointUpperLimit=1,
physicsClientId=engine_id)
단, PyBullet의 조작을 통해 가동 범위를 제한해도 접속 정보를 업데이트하지 않음 함수 때문에 jointLowerLimit <= jointUpperLimit
함수로 업데이트를 확인할 수 없습니다.3. 실제로 해보기
박자기처럼 상자 주위를 둥글게 움직일 수 있는 원통 대상을 만들어 봤다.
위의 GIF 아날로그 코드 on Google Colab
import pybullet
import matplotlib.pyplot as plt
from PIL import Image
from IPython import display as dd
import base64
import io
import math
# 物理エンジンの初期化
engine_id = pybullet.connect(pybullet.DIRECT)
# 重力
pybullet.setGravity(0,0,-10, physicsClientId=engine_id)
# 質量
mass = 50.0
fix_mass = 0
# 床の設置
plane_cid = pybullet.createCollisionShape(pybullet.GEOM_PLANE, meshScale=[0.05,0.05,0.05], physicsClientId=engine_id)
plane_id = pybullet.createMultiBody(fix_mass, plane_cid, physicsClientId=engine_id)
# 衝突判定用のオブジェクト(の雛形)
cylinder_cid = pybullet.createCollisionShape(pybullet.GEOM_CYLINDER, radius=0.1, height=1, physicsClientId=engine_id)
box_cid = pybullet.createCollisionShape(pybullet.GEOM_BOX, halfExtents=[0.1, 0.1, 0.1], physicsClientId=engine_id)
# 外観オブジェクト(の雛形)
r_vid = pybullet.createVisualShape(pybullet.GEOM_BOX, halfExtents=[0.1,0.1,0.1], rgbaColor=[1,0,0,1], physicsClientId=engine_id)
# 複数コンポーネントオブジェクトの構築
obj_id = pybullet.createMultiBody(10*mass, box_cid, r_vid,
basePosition=[0, 0, 0.1],
linkMasses=[fix_mass, mass],
linkCollisionShapeIndices=[-1, cylinder_cid],
linkVisualShapeIndices=[-1, -1], # 外観用オブジェクトを指定しない時は、 -1 を指定。
linkPositions=[[0, 0, 0],[0,0.5,0.5]],
linkOrientations=[[0,0,0,1], [1,0,0,math.cos((3/8)*math.pi)]],
linkInertialFramePositions=[[0,0,0],[0,0,0]],
linkInertialFrameOrientations=[[0,0,0,1],[0,0,0,1]],
linkParentIndices=[0, 1],
linkJointTypes=[pybullet.JOINT_REVOLUTE, pybullet.JOINT_FIXED],
linkJointAxis=[[1,0,0],[1,0,0]],
physicsClientId=engine_id)
# シミュレーションとカメラ画像の保存
gif = []
for i in range(2000):
if i % 10 == 0:
gif.append(Image.fromarray(pybullet.getCameraImage(512, 384, physicsClientId=engine_id)[2]))
pybullet.stepSimulation(physicsClientId=engine_id)
for i in range(2000):
pybullet.setJointMotorControl2(obj_id, 0, pybullet.TORQUE_CONTROL, force=600, physicsClientId=engine_id)
if i % 10 == 0:
gif.append(Image.fromarray(pybullet.getCameraImage(512, 384, physicsClientId=engine_id)[2]))
pybullet.stepSimulation(physicsClientId=engine_id)
# 画像をGIFとして書き出して表示
f = io.BytesIO()
gif[0].save(f, save_all=True, append_images=gif[1:],format="gif", loop=0)
f.seek(0)
b64 = base64.b64encode(f.read()).decode('ascii')
f.close()
display(dd.HTML(f'<img src="data:image/gif;base64,{b64}" />'))
4. 힘든 곳
하위 링크의 원점은
getJointInfo
에 의해 지정되고 (충돌 판정) 대상은 하위 링크의 원점에 위치하며 (가능) 엇갈려 놓을 수 없습니다.따라서 위의 박자기(임시) 실린더처럼 객체의 중심 주위 이외에 이음매가 있는 경우
linkPositions
등을 이용하여 이음매용 링크를 만들고 이 링크와 연관된 형태로 JOINT_REVOLUTE
평행으로 이동하는 대상JOINT_FIXED
을 구성해야 한다.이때 접두부의 품질
0
(고정)이든 적당한 품질이든 상관없다.총중량에 영향을 미치기 때문에 0
두는 게 좋을 것 같지만 부작용이 없으면 계속 조사해야 한다.순조롭지 않을 때 매우 큰 힘(모멘트와 중력)을 가하면 이음매의 제한을 쉽게 구분할 수 있다는 설정 방법이 좋지 않은지, 아니면 힘의 가하는 방식이 좋지 않은지 느낄 수 있다.
또한
setJointMotorControl2
에서 지정한 토크는 1단계stepSimulation
1회)에 유효합니다.5. 끝말
지난번에도 썼는데, PyBullet은 상당히 피곤해요.계속 조사하고 보도해.
가동 범위의 제한이 조금 나왔지만
changeDynamics
함수, 마찰 등 다양한 지정상능을 조사했다.조작에 있어 깊이 파고들어
setJointMotorControl2
,setJointMotorControlArray
및 대상 상태를 얻는 방법이 필요하다.또 화면의 범위, 각도 조정 등을 조사하지 않으면 사용할 수 없다.
(이번에 시뮬레이션한 각 대상의 크기가 작은 것은 카메라를 움직일 수 없기 때문이며, 더 크면 화면을 초과할 수 있기 때문이다.)
Reference
이 문제에 관하여(PyBulet 조사2: 여러 구성 요소로 구성된 객체), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/ymd_h/articles/381fa7cc4070e8텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)