はじめに
「Pythonで、ちゃんとした物理エンジンを動かしたい!」 という願いを叶えてくれるのがPybulletです。
少し使うのが難しいですが
特徴として
- オープンソースである
- ロボットのシミュレーションも行える (URDFなども読み込める)
- 深度画像、セグメンテーション画像なども取得可能、raytestなども利用可能
- 強化学習用の環境が一部提供されている
などが挙げられ、物理シミュレーション、ロボティクス、AIなど様々な分野で利用できます。
(実際に研究者も使っているツールです)
今回の実行環境について
Google Colaboratoryで実行しています。
ランタイムはGPUの方がいいですが、CPUでも動きます。
(CPUだと最初のpipインストールが10分くらいかかる)
ローカルのノートPCなどで実行しようとするとかなり重たいですが、UIで動かせるという利点があります。
インストール、インポート
Colabでやっているのでコマンドの前に「!」がついていますが環境に応じて変えてください
インストール
!pip install pybullet
インポート
import pybullet
gitのクローン
強化学習用の環境やロボットのモデル(URDFファイルなど)が読み込める。
(URDF、SDF、Objなどの形式でR2D2, Kukaのロボットアーム, レースカーなど色々なものが用意されている)
!git clone https://github.com/bulletphysics/bullet3.git
色々な設定で使うのでこちらもインポート
import pybullet_data
物理エンジンへの接続
今回はColabでやっているので
physicsClient = pybullet.connect(pybullet.DIRECT)
もしローカルで実行する場合は
physicsClient = pybullet.connect(pybullet.GUI)
環境の設定
基本設定
pybullet.setAdditionalSearchPath(pybullet_data.getDataPath())
重力を設定する
pybullet.setgravity(gravx,gravy,gravz)
gravx: x軸方向の重力
gravy: y軸方向の重力
gravz: z軸方向の重力
(全てfloat)
基本的には(地球上において)
pybullet.setgravity(0,0,-9.8)
物体のロード
URDF(Universal Robot Description File)のファイルを読み込める変形しやすい物体(布など)も読み込める
URDFはROSなどで用いられる
object=pybullet.loadURDF('~~~.urdf')
loadSDF:SDFファイルを読み込める
loadMJCF:MuJoCo MJCFのxmlを読み込める
VTK や OBJ 形式の変形しやすい物体(布など)を読み込める
object=pybullet.loadSoftBody('.obj')
カメラ画像の受け取り
RGB、Depth、セグメンテーション画像が受け取れます。AIの学習(特に強化学習)をする際に非常に便利な機能です。
width, height, rgbPixels, depthPixels, segmentationMaskBuffer = pybullet.getCameraImage(width, height, ...)
セグメンテーションマスク(segmentationMaskBuffer)
カメラ設定
getCameraImageの引数
pybullet.getCameraImage(width, height, viewMatrix , projectionMatrix, lightDirection, lightColor, lightDistance, shadow, lightAmbientCoeff, lightDiffuseCoeff, lightSpecularCoeff, renderer)
主なパラメーター | 意味 |
---|---|
width | 画像の横幅 |
height | 画像の高さ |
viewMatrix | カメラの位置、方向など(下記参照) |
projectionMatrix | カメラの撮影設定(下記参照) |
lightDirection | ライトの方向ベクトル lightDirection= (x,y,z) |
lightColor | ライトの色 lightColor=(R,G,B) |
lightDistance | ライトの距離 |
shadow | 影をつけるかどうか: 1→影をつける 0→影をつけない |
カメラの位置、方向など
viewMatrix = pybullet.computeViewMatrix(cameraEyePosition=[0, 0, 2],cameraTargetPosition=[0, 0, 0],cameraUpVector=[0, 1, 0])
主なパラメーター | 意味 |
---|---|
cameraEyePosition | カメラの位置 |
cameraTargetPosition | カメラが写す中心座標 |
cameraUpVector | カメラの上面の法線ベクトル※ |
※カメラが中心座標をどのくらい見下ろすor見上げるのかを決める
カメラの撮影設定
projectionMatrix = pybullet.computeProjectionMatrixFOV(fov=45.0,aspect=1.0,nearVal=0.1,farVal=3.1)
主なパラメーター | 意味 |
---|---|
fov | カメラが写す範囲の広さ |
aspect | アスペクト(画像の縦横比) |
nearVal | カメラが写す最小の距離 |
farVal | カメラが写す最大の距離 |
シミュレーション結果の表示・保存
下のコードを実行すると、3次元直交座標(0,0,3)から、重力加速度9.8でヒューマノイドが自由落下するシミュレーション結果をGIFファイルで保存できます。
from PIL import Image
pybullet.resetSimulation()
pybullet.setAdditionalSearchPath(pybullet_data.getDataPath())
pybullet.setGravity(0,0,-9.8)
timestep = 1. / 240.
pybullet.setTimeStep(timestep)
floor = pybullet.loadURDF("plane.urdf")
startposition = [0,0,3] # x,y,z
startorient = pybullet.getQuaternionFromEuler([0,0,3.14])
Humanoid = pybullet.loadURDF("./bullet3/data/humanoid/nao.urdf",startposition, startorient)
# 記事冒頭のボールを落下させるシミュレーションでは "./bullet3/data/sphere2.urdf"を指定
frame = []
for t in range (400):
pybullet.stepSimulation()
if t % 8 == 0:
width, height, rgbImg, depthImg, segImg = pybullet.getCameraImage(360,240)
frame.append(rgbImg)
images =[]
for im in frame:
img = Image.fromarray(im)
images.append(img)
images[0].save('my_simulation.gif',save_all=True, append_images=images[:], optimize=False, duration=40, loop=0)
実行結果
ヒューマノイドの設定(色、コリジョンなど)はURDFを編集することで変更できます。
最後に
今回は、Pybulletの基本的な使い方を紹介しました。
自分もまだわからない部分が多いので、たくさん使って勉強していきたいと思います。
間違いなどがあれば遠慮なくコメントで指摘をお願いします。
以下の関連記事では実際にPybulletでロボットを動かす方法を解説しています