【Pybulletサンプル解説】変形するオブジェクトを生成【deformable_torus.py】

お疲れ様です。秋並です。

Pybullet公式gitリポジトリのサンプルコードを解説するシリーズです（一覧は[こちら](https://qiita.com/akinami/items/7b433b60aeb5115ba4d7)）。

<br>

今回は、deformable_torus.pyを解説します。（コードのリンクは[こちら](https://github.com/bulletphysics/bullet3/blob/master/examples/pybullet/examples/deformable_torus.py)）

本コードを実行すると、剛体のオブジェクトと、変形するオブジェクトが生成されます。

![deformable_torus.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2030125/071e74fb-1e5e-f8ee-22b8-3acf764e316b.gif)


# 使用している機能
本コードは、以下の機能を使用して「変形するオブジェクトが生成可能なワールドに設定」「urdfファイルからオブジェクトの生成」「ソフトボディのオブジェクトの生成」を実現できます。

## 変形するオブジェクトが生成可能なワールドに設定
`resetSimulation` 関数を使用することで、シミュレーションをリセットできます。

```python
pybullet.resetSimulation(mode)
```
- `mode`：どのモードでシミュレーションをリセットするか
  - `RESET_USE_REDUCED_DEFORMABLE_WORLD`の場合「変形するオブジェクト」が生成可能になります。

## urdfファイルからオブジェクトの生成
`loadURDF` 関数を使用することで、urdfファイルからオブジェクトを生成できます。

```python
pybullet.loadURDF(urdfFile, position)
```
- `urdfFile`：生成するオブジェクトのurdfファイル
  -  ワールドが`RESET_USE_REDUCED_DEFORMABLE_WORLD`の場合、変形するオブジェクトを生成できます
- `position`：オブジェクトの生成位置

## ソフトボディのオブジェクトの生成
`loadSoftBody` 関数を使用することで、ソフトボディのオブジェクトを生成できます。
`loadUrdf`関数と同様に、ワールドが`RESET_USE_REDUCED_DEFORMABLE_WORLD`の場合、変形するオブジェクトを生成できます。
```python
softBodyId = pybullet.loadSoftBody(objectFile, 
                                    simFileName, 
                                    mass, 
                                    useNeoHookean, 
                                    NeoHookeanMu, 
                                    NeoHookeanLambda, 
                                    NeoHookeanDamping, 
                                    collisionMargin, 
                                    useSelfCollision, 
                                    frictionCoeff, 
                                    repulsionStiffness
)
```
- `softBodyId`：ソフトボディのオブジェクトのID
- `objectFile`：ソフトボディのオブジェクトのファイル
- `simFileName`：シミュレーションファイル
- `mass`：重量
- `useNeoHookean`：ネオフック材料モデルの使用
- `NeoHookeanMu`：ネオフック材料のパラメータ1
- `NeoHookeanLambda`：ネオフック材料のパラメータ2
- `NeoHookeanDamping`：ネオフック材料のパラメータ3
- `collisionMargin`：衝突マージン
- `useSelfCollision`：自己衝突の使用
- `frictionCoeff`：摩擦係数
- `repulsionStiffness`：反発剛性

# コメントをつけたサンプルコード
サンプルコードにコメントをつけたものが以下になります（もともとあった不要と思われるコメント等については削除しています）

```python
import pybullet as p
from time import sleep
import pybullet_data

# PybulletをGUIモードで接続
physicsClient = p.connect(p.GUI)

# Pybulletに関するデータパスを取得
p.setAdditionalSearchPath(pybullet_data.getDataPath())

# シミュレーションを「変形可能なワールド」にリセットする
p.resetSimulation(p.RESET_USE_DEFORMABLE_WORLD)

# カメラの位置/姿勢をリセット
p.resetDebugVisualizerCamera(3,-420,-30,[0.3,0.9,-2])

# 重力を設定
p.setGravity(0, 0, -10)

# テクスチャをロードする
tex = p.loadTexture("uvmap.png")

# 床のオブジェクトを生成
planeId = p.loadURDF("plane.urdf", [0,0,-2])

# ボックスのオブジェクトを生成
boxId = p.loadURDF("cube.urdf", [0,3,2],useMaximalCoordinates = True)

# ソフトボディのオブジェクトの生成
bunnyId = p.loadSoftBody("torus/torus_textured.obj", simFileName="torus.vtk", mass = 3, useNeoHookean = 1, NeoHookeanMu = 180, NeoHookeanLambda = 600, NeoHookeanDamping = 0.01, collisionMargin = 0.006, useSelfCollision = 1, frictionCoeff = 0.5, repulsionStiffness = 800)

# オブジェクトにテクスチャを適用
p.changeVisualShape(bunnyId, -1, rgbaColor=[1,1,1,1], textureUniqueId=tex, flags=0)

# 変形するオブジェクトを設定
bunny2 = p.loadURDF("torus_deform.urdf", [0,1,0.5], flags=p.URDF_USE_SELF_COLLISION)

# オブジェクトにテクスチャを適用
p.changeVisualShape(bunny2, -1, rgbaColor=[1,1,1,1], textureUniqueId=tex, flags=0)

# sdfのボクセルのサイズを0.25に設定
p.setPhysicsEngineParameter(sparseSdfVoxelSize=0.25)

# リアルタイムシミュレーションモードをOFFに設定
p.setRealTimeSimulation(0)

# Pybulletが接続されている間、ループを繰り返す
while p.isConnected():

  # シミュレーションを1時刻分進める
  p.stepSimulation()

  # カメラ画像を取得
  p.getCameraImage(320,200)

  # 重力を設定
  p.setGravity(0,0,-10)
```