physics-simulation について
Isaac Sim 6 と Kit 110 の物理設定を扱う実用スキルです。シーン設定、Prim ごとの構成、材質、ドライブ、センサー、バックエンド選択をスクリプトや例とともに説明します。
主な機能
- 01物理シーンとソルバーの設定
- 02剛体とコリジョンの構成
- 03接触材質とジョイントドライブ
- 04Newton と PhysX のバックエンド選択
- 05Prim 設定用ヘルパースクリプト
活用シーン
- 01剛体とコリジョンの設定
- 02接触の多いシーンや高速シーンの調整
- 03シミュレーション用バックエンドの選択
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ isaac-sim/ isaacsim --skill physics-simulationインストール後、Claude Code で/physics-simulationを入力して読み込まれたか確認します。
同梱ファイルexamples.mdscripts/prim_physics_setup.py
詳細
Isaac Sim での物理シミュレーション
目的
PhysicsScene と各プリムの剛体、コリジョン、マテリアル、ジョイントドライブ、ソルバーの選択、物理センサーを、実例を交えて設定します。
前提条件
- スタンドアロンの物理シミュレーションの場合:
source/librariesのビルドが完了しているか、対応するインストール済みのホイール/SDK が必要です。ほとんどの単体テストとヘッドレス物理テストでは GPU は不要です。 - Kit の設定、拡張機能の自動切り替え、タイムライン、ビューポートを扱う場合:ビルド済みの Isaac Sim と、
isaac-sim-orchestratorのシェル環境が必要です。
制限事項
- セクションに別途記載がない限り、Isaac Sim 6 / Kit 110 を対象とします。
- サポート対象外の特殊なケースについて、NVIDIA の公式ドキュメントに代わるものではありません。
トラブルシューティング
| エラー/症状 | 原因 | 解決策 |
|---|---|---|
| 黒いフレーム、または空のフレーム | ライトがない、または非 RTX のレンダーモード | ドームライト/キーライトを追加し、RTX/PathTracing の設定を確認します |
| ステージの読み込みまたは初回レンダリング時にハングする | MDL のコンパイル、またはステージが大きすぎる | isaac-sim-troubleshooting の切り分け手順に従います |
スタンドアロンライブラリと Kit アダプターの違い
スタンドアロンの物理シミュレーションの実装、バックエンドの登録、エンティティ、ランタイム制御には、source/libraries/isaacsim/physics/{manager,registration,entities,ovsim} と source/libraries/isaacsim/physics_engines/{ovnewton,ovphysx} のエンジンを使用します。isaacsim.physics_engines.ovstage はプライベートな OVStage ランタイム用のプロセスレベルのセットアップとネイティブハンドルのブリッジであり、物理エンジンではありません。
isaacsim.core.simulation_manager の設定、拡張機能の有効化と自動切り替え動作、Kit のタイムライン、ビューポート、SimulationApp は Kit アダプター経由で扱います。スタンドアロンモジュールのテストにこれらの起動フラグを適用しないでください。また、利用側のワークフローを確認せずに、ライブラリの PhysicsManager を Kit の SimulationManager と単に名前を置き換えれば使えるものと見なさないでください。
インポート時の登録が公開パッケージのドキュメントに記載されているスタンドアロンエンジンでは、そのパッケージを一度インポートし、PhysicsManager を介して選択してください。通常の例に、個別の activate() や shutdown() 呼び出しを追加する必要はありません。セットアップ、初期化、ステップ実行、無効化はマネージャーを通じて行い、マジック値ではなく Stage オブジェクトが返すステージ識別子を渡してください。エンティティファサードが操作をサポートしている場合は、生のシミュレーションビューや手動のテンソル変換よりも、RigidBodyEntity と ArticulationEntity を優先してください。
バックエンドを事前に有効化せず、例の通常の公開エントリポイントを実行するテストにしてください。これにより、登録漏れやライフサイクルの所有権の問題を検出できます。正準となる構文として、チェックアウトしたエンジンの API ドキュメントと対応する source/examples のシリーズを使用してください。古い例の互換性維持用ライフサイクルをコピーしないでください。
Isaac Sim 6.0 以降/Kit 110 を対象とします。両バックエンドは UsdPhysics.* を共有します。バックエンド固有の動作については、各セクションで説明します。
利用可能なスクリプト
| スクリプト | 目的 | 引数 |
|---|---|---|
scripts/prim_physics_setup.py | Isaac Sim/USD(Kit 110)向けの各プリムの物理設定ヘルパー | --help で確認してください |
スクリプトの実行
スキル実行ヘルパーを利用できるエージェントのランタイムでは、run_script() を使ってヘルパーを呼び出します。
run_script("scripts/prim_physics_setup.py", args=["--help"])
ビルド済みの Isaac Sim ツリーからは、_build/*/release 内で ./python.sh(Linux)または python.bat(Windows)を使って同じファイルを実行します。シミュレーターを必要としない場合は、シェルヘルパーを直接実行することもできます。
バックエンドの選択(Kit 110)
isaacsim.core.simulation_manager は物理エンジンを登録し、アクティブなエンジンを選択します。extension.toml の default_engine は "physx" ですが、一方で、isaacsim.physics.newton 拡張機能はデフォルトで auto_switch_on_startup = true になっているため、isaacsim.physics.newton を有効にするアプリ(標準の isaacsim.exp.full.kit も該当します)は、起動時に Newton がアクティブになります。
from isaacsim.core.simulation_manager import SimulationManager
SimulationManager.switch_physics_engine("newton") # or "physx"
print(SimulationManager.get_active_physics_engine())
# Inspect what is available
from isaacsim.physics.newton import get_available_physics_engines, get_active_physics_engine
print(get_available_physics_engines())
起動時にエンジンを明示的に指定してください。
--/exts/isaacsim.core.simulation_manager/default_engine=newton # or =physx
--/exts/isaacsim.physics.newton/auto_switch_on_startup=false # opt out of auto-switch
Newton の設定クラス(拡張機能の Python API。現時点ではユーザーガイドの RST には掲載されていません。拡張機能の API ドキュメントページ、または docs/isaacsim/physics/newton_physics.rst を参照してください)。
| クラス | 役割 |
|---|---|
isaacsim.physics.newton.NewtonConfig | シミュレーションごとの設定(CUDA グラフキャプチャ、Fabric 同期、接触/ジョイントのデフォルト値) |
XPBDSolverConfig | XPBD ソルバー(剛体+ソフトボディ) |
MuJoCoSolverConfig | MuJoCo Warp ソルバー |
isaacsim.physics.newton.tensors | NumPy/PyTorch/Warp フロントエンド |
Newton と PhysX はどちらも標準の UsdPhysics.Scene と PhysxSchema.PhysxSceneAPI を使用します。多くの PhysxSchema.* 属性は Newton でも引き続き適用され、Newton は omni.usd.schema.newton を介してソルバー設定を読み込みます。
スタックと参照順序
- このスキル:シーン設定、プリムごとの設定、接触マテリアル、ドライブ、センサー、読み戻し、バックエンドの選択。
usd-articulation:マルチリンクアーティキュレーション+Robot Schema オーバーレイ。urdf-mjcf-to-usd-conversion:インポーター設定(RL 用ドライブと遠隔操作用ドライブ)。isaac-sim-troubleshooting:Kit 110 で物理挙動に問題が発生した場合。
メカニズムのレシピ(衝撃、フィーダー、ドミノ、こま、クレードル、振り子波、脱進機)は実例にあります。
パート 1 — シーンレベルの設定
PhysicsScene の設定
from pxr import Usd, UsdGeom, UsdPhysics, PhysxSchema, Gf
ps = UsdPhysics.Scene.Define(stage, "/World/PhysicsScene")
ps.CreateGravityDirectionAttr().Set(Gf.Vec3f(0, 0, -1))
ps.CreateGravityMagnitudeAttr().Set(9.81)
px = PhysxSchema.PhysxSceneAPI.Apply(ps.GetPrim())
px.CreateTimeStepsPerSecondAttr().Set(240) # see Hz table below
px.CreateEnableCCDAttr().Set(True)
px.CreateEnableStabilizationAttr().Set(True)
px.CreateSolverTypeAttr().Set("TGS") # TGS or PGS; TGS preferred for articulations
物理 Hz の選択
| シナリオ | Hz | 備考 |
|---|---|---|
| 標準的な剛体シーン | 60–120 | 倉庫や一般的なシミュレーションのデフォルト |
| 積み重ね/接触が多いシーン | 240 | 接触を高精度に解決 |
| 高速衝突 | 2~4 サブステップで 120 | CCD と組み合わせます |
| 小型部品の振動(フィーダー) | 振動周波数の 4 倍以上、通常は 480 | 振動を正しく解決 |
| 回転する剛体/ジャイロ | 480 | 角運動量の数値精度を確保 |
| 剛性の高い接触連鎖(クレードル、脱進機) | 480 | ソルバーには多数のサブイテレーションが必要 |
**経験則:**物理のタイムステップは、システム内の最高周波数(振動、回転、接触剛性モード)の 4 倍より大きくする必要があります。
ソルバーの反復回数(剛体ごと)
必要な剛体の PhysxRigidBodyAPI に設定します。値を大きくすると精度が上がりますが、処理は遅くなります。
| シナリオ | 位置反復回数 | 速度反復回数 |
|---|---|---|
| 単純な剛体、転がり | 16 | 4 |
| 積み重ね | 32 | 8 |
| 複雑なジョイント/アーティキュレーション | 64 | 16 |
| 剛性の高い接触連鎖(クレードル、脱進機) | 64 | 32 |
pxrb = PhysxSchema.PhysxRigidBodyAPI.Apply(prim)
pxrb.CreateSolverPositionIterationCountAttr().Set(32)
pxrb.CreateSolverVelocityIterationCountAttr().Set(8)
pxrb.CreateEnableCCDAttr().Set(True)
安定化を無効にする場合
EnableStabilizationAttr はデフォルトで有効になっており、積み重ねた物体の静止を助けます。自由に回転する物体では角運動量を失わせます。次の場合は無効にしてください。
- 回転するこま、ジャイロ、フライホイール
- 振り子機構(時計の脱進機、振り子波)
- 角速度の保存が正しさの条件となるもの
px.CreateEnableStabilizationAttr().Set(False)
パート 2 — プリムごとの物理設定
RigidBody/Collision/Static/Kinematic
動的、静的、キネマティックな剛体の設定には、scripts/prim_physics_setup.py を使用します。RigidBodyAPI、MassAPI、CollisionAPI の適用手順を、実行可能な実装にまとめています。
ルール:RigidBodyAPI と CollisionAPI は同じプリムに適用してください。親と子に分けると、断続的に衝突が失敗する原因になります。
スケールを指定した静的コライダー — 位置を先に指定するパターン
CollisionAPI を直接適用した Cube プリムをスケーリングすると、PhysX が誤った衝突境界を使用します(物体が床をすり抜けます)。位置には親の xform を使用し、スケールには子のメッシュを使用します。
# CORRECT
xf = UsdGeom.Xform.Define(stage, "/World/Ground")
UsdGeom.Xformable(xf.GetPrim()).AddTranslateOp().Set(Gf.Vec3d(0, 0, -0.05))
mesh = UsdGeom.Cube.Define(stage, "/World/Ground/Mesh")
mesh.CreateSizeAttr().Set(1.0)
UsdGeom.Xformable(mesh.GetPrim()).AddScaleOp().Set(Gf.Vec3f(50.0, 50.0, 0.1))
UsdPhysics.CollisionAPI.Apply(mesh.GetPrim())
Cube.size=1.0 は、キューブの半径が 1.0 ではなく 0.5 であることを意味します。「スケール演算の値を半径と一致させたい」場合は、size=2.0 を使用してください。
質量と慣性
mass_api = UsdPhysics.MassAPI.Apply(prim)
mass_api.CreateMassAttr().Set(0.25) # kg
mass_api.CreateCenterOfMassAttr().Set(Gf.Vec3f(0, 0, 0.05)) # local
mass_api.CreateDiagonalInertiaAttr().Set(Gf.Vec3f(1e-4, 1e-4, 2e-4)) # kg·m²
URDF からインポートしたロボットでは、幾何形状から自動計算される慣性よりも、config.yaml で import_inertia_tensor: true を設定することを推奨します(urdf-mjcf-to-usd-conversion を参照)。
パート 3 — 接触マテリアル
def create_contact_material(stage, mat_path, static_friction=0.5,
dynamic_friction=0.4, restitution=0.1):
prim = stage.DefinePrim(mat_path)
mat = UsdPhysics.MaterialAPI.Apply(prim)
mat.CreateStaticFrictionAttr().Set(static_friction)
mat.CreateDynamicFrictionAttr().Set(dynamic_friction)
mat.CreateRestitutionAttr().Set(restitution)
return mat
参考値
| マテリアルの組み合わせ | 静摩擦係数 μ | 動摩擦係数 μ | 反発係数 |
|---|---|---|---|
| コンクリート同士 | 0.6 | 0.5 | 0.05 |
| 鋼材同士 | 0.74 | 0.57 | 0.6 |
| ゴム同士 | 0.8 | 0.7 | 0.5 |
| ゴムとコンクリート | 1.0 | 0.8 | 0.3 |
| 木材同士 | 0.5 | 0.3 | 0.2 |
| 一般的な金属 | 0.4 | 0.3 | 0.2 |
| プラスチック(サイコロ) | 0.4 | 0.3 | 0.3 |
| フェルト(カジノ) | 0.5 | 0.4 | 0.2 |
| 段ボールと鋼材 | 0.4 | 0.3 | 0.1 |
剛性の高い接触が連続する場合(ニュートンのゆりかご、脱進機など)は、各接触で最も高い反発係数が適用されるよう、PhysxMaterialAPI で restitutionCombineMode=max を設定してください。
パート 4 — 関節ドライブ
joint = stage.GetPrimAtPath("/World/Robot/joint_arm")
drive = UsdPhysics.DriveAPI.Apply(joint, "angular") # "angular" | "linear"
drive.CreateTypeAttr().Set("force") # "force" | "acceleration"
drive.CreateStiffnessAttr().Set(1000.0) # Kp (Nm/rad for angular)
drive.CreateDampingAttr().Set(100.0) # Kd (Nm·s/rad)
drive.CreateMaxForceAttr().Set(500.0) # torque/force limit
drive.CreateTargetPositionAttr().Set(0.0) # target (deg or m)
RL トレーニングでは、エージェントがトルクを直接指令します。config.yaml で drive_type を none に設定し、stiffness と damping を 0 にしてください(urdf-mjcf-to-usd-conversion を参照)。有効な PD ドライブは RL エージェントの制御と競合します。
回転振り子関節(時計の脱進機、振り子波など)では、関節の摩擦を 0 に設定してください。
joint_api = PhysxSchema.PhysxJointAPI.Apply(joint)
joint_api.CreateJointFrictionAttr().Set(0.0)
パート 5 — バックエンドの選択(Newton と PhysX)
簡単な選び方
| 希望する用途 | 使用するもの |
|---|---|
| 数千の環境を使った RL トレーニング | Newton(Featherstone または MuJoCo) |
| 微分可能なシミュレーション | Newton |
| Isaac Sim 5.x のレガシー PhysX シーン | PhysX |
| ソフトボディ、布、変形可能オブジェクト | Newton(VBD または XPBD) |
| MuJoCo のベースラインで検証済み | Newton SolverMuJoCo |
Newton ソルバー
| ソルバー | 座標系 | 微分可能 | 最適な用途 |
|---|---|---|---|
| SolverFeatherstone | 一般化座標系 | はい(Warp) | 多関節ロボット(マニピュレーター、脚式ロボットのデフォルト) |
| SolverMuJoCo | 一般化座標系 | はい(mujoco-warp) | 検証済みの移動動作、MuJoCo ポリシーの移植 |
| SolverXPBD | 最大座標系 | 部分的 | ソフト拘束、ケーブル、ロープ |
| SolverSemiImplicit | 最大座標系 | はい(Warp) | 高速なプロトタイピング、単純な剛体 |
| SolverVBD | (変形可能) | はい | ソフトボディ、変形可能オブジェクト |
Newton でも実行する必要がある、既存の PhysX 専用 USD アセットについては、physx-to-newton-conversion を参照してください。
Newton と PhysX の違い
| 項目 | PhysX | Newton |
|---|---|---|
| バックエンド | クローズドな C++/CUDA | Warp/CUDA(オープン、JIT) |
| 座標系 | 最大座標系(剛体ごとに 6DoF) | 一般化座標系(Featherstone)または最大座標系 |
| 微分可能 | いいえ | はい(ネイティブの Warp 自動微分) |
| マルチ GPU | 制限あり | はい(Warp のデバイス抽象化) |
| USD 統合 | スキーマ拡張 | ネイティブ USD ローダー |
| パフォーマンスの上限 | 4096 環境未満で良好 | 10K 以上の環境向けに設計 |
Newton + Torch — 初期化順序の重要事項
Newton の物理演算が安定する前に import torch を実行しないでください。CUDA コンテキストの競合により Kit がハングします。timeline.play() と安定化ループの後まで torch のインポートを遅らせてください。VRAM が不足する場合は、ポリシー推論で map_location="cpu" を使用してください。
Newton 固有の設定(Isaac Lab)
# config.yaml for URDF→USD conversion (Isaac Lab)
make_instanceable: true # CRITICAL for RL parallel envs
fix_base: false # true for fixed-base arm; false for mobile/legged
スキーマ全体については、urdf-mjcf-to-usd-conversion を参照してください。
パート 6 — 物理センサー
現在の名前空間は isaacsim.sensors.experimental.physics です(作成用クラスとランタイムクラスが対になっています)。従来の isaacsim.sensors.physics インポートパスも引き続き動作しますが、新しいコードでは非推奨です。
移行: 概念の対応関係と更新されたスクリプトについては、
isaacsim.sensors.physicsからisaacsim.sensors.experimental.physicsへの移行を参照してください。
接触
from isaacsim.sensors.experimental.physics import Contact, ContactSensor
import isaacsim.core.experimental.utils.app as app_utils
contact = Contact.create(
path="/World/Robot/foot/contact",
min_threshold=0.0, max_threshold=1e6, radius=-1, # -1 = use collision shape
)
sensor = ContactSensor(contact)
app_utils.play(commit=True) # required before get_data()
reading = sensor.get_data() # ContactSensorReading
IMU
from isaacsim.sensors.experimental.physics import IMU, IMUSensor
imu = IMU.create(path="/World/Robot/imu", tick_rate=200.0)
sensor = IMUSensor(imu, annotators=["linear_acceleration", "angular_velocity", "orientation"])
app_utils.play(commit=True)
frame = sensor.get_data() # returns IMUSensorReading
力/関節状態
同じモジュールのランタイム専用クラスです。個別の作成用タイプはなく、パスを指定して既存の関節をラップします。
from isaacsim.sensors.experimental.physics import EffortSensor, JointStateSensor
effort = EffortSensor("/World/Robot/joint_arm_1")
joint = JointStateSensor("/World/Robot/joint_arm_1")
app_utils.play(commit=True)
reading = effort.get_data() # EffortSensorReading
state = joint.get_data() # JointStateSensorReading
Raycast(シーンのクエリ)
import omni.physics.tensors as physics_tensors
sim_view = physics_tensors.create_simulation_view("cuda:0")
hit = sim_view.raycast_closest(origin, direction, max_dist)
より高精度なセンサーシミュレーション(LiDAR のスキャンパターン、マルチレイ、ベンダー製センサーモデル、深度/レーダー/音響)については、isaac-sim-sensor と isaac-camera を参照してください。これらは最新の isaacsim.sensors.experimental.rtx と .physics 名前空間を使用します。
パート 7 — 物理から USD への読み戻し(重要)
最もよくある、気づきにくいバグは、シミュレーション状態ではなく、作成済みの USD トランスフォームを読み取ることです。
| ソース | 返される値 | 使用するタイミング |
|---|---|---|
UsdGeom.XformCache.GetLocalToWorldTransform() | 作成済みの USD トランスフォーム(初期姿勢) | 再生前のエディター時のクエリ |
RigidPrim.get_world_pose() | シミュレーションされた状態 | シミュレーション中は常に |
Articulation.get_world_poses() (Kit 110) | アーティキュレートされた剛体のシミュレーションされた状態 | アーティキュレートされたロボット |
Dynamic Control (DC) dc.get_rigid_body_pose() | シミュレーションされた状態 | レガシー/簡易スクリプト |
シミュレーション中に XformCache が誤った値を返す理由
updateToUsd=True は物理状態を USD ステージレイヤーではなく、Fabric に書き込みます。XformCache は USD レイヤーを読み取るため、初期姿勢を返し続けます。
RigidPrim/GeomPrim のパターン(Kit 110)
from isaacsim.core.experimental.prims import RigidPrim
import isaacsim.core.experimental.utils.app as app_utils
rp = RigidPrim(paths="/World/Dice/Die_*")
app_utils.play(commit=True)
pos_wp, quat_wp = rp.get_world_poses() # warp arrays
positions = pos_wp.numpy() # (N, 3)
quaternions = quat_wp.numpy() # (N, 4) [w, x, y, z]
Articulation のパターン(Kit 110)
from isaacsim.core.experimental.prims import Articulation
import isaacsim.core.experimental.utils.app as app_utils
robot = Articulation("/World/Robot")
app_utils.play(commit=True) # required for tensor data
pos_wp, quat_wp = robot.get_world_poses()
dof_positions = robot.get_dof_positions().numpy() # (N, num_dofs)
dof_velocities = robot.get_dof_velocities().numpy()
J = robot.get_jacobian_matrices().numpy() # for IK
レガシーの isaacsim.core.api.articulations.Articulation/isaacsim.core.api.prims.RigidPrim も引き続き読み込めますが、isaacsim.core.experimental.* スタックに置き換えられています。
移行: より広範な
omni.isaac.*→isaacsim.*の名称変更マップについては、拡張機能の名称変更を参照してください。実験的な Articulation/RigidPrim API については、Python スクリプティングのインデックスを参照してください。
クォータニオンの規約
USD/Isaac は [w, x, y, z] を使用し、scipy は [x, y, z, w] を使用します。次のように変換します。
from scipy.spatial.transform import Rotation
r = Rotation.from_quat([quat[1], quat[2], quat[3], quat[0]])
euler = r.as_euler('xyz', degrees=True)
パート 8 — よくある注意点
CollisionAPIだけでは静的コライダーになります。動的にするにはRigidBodyAPIとCollisionAPIが必要です。- 同一 prim の要件:両方の API を同じ primに設定する必要があります。
- キネマティックボディ:RigidBodyAPI の有効/無効を切り替えるのではなく、
CreateKinematicEnabledAttr().Set(True)を使用します。 Cube.size=1.0は半径が 0.5 です。スケール操作の値を半径と一致させたい場合は、size=2.0を使用します。physics:velocityUSD 属性は実行時に PhysX に無視されます。timeline.play()の後にRigidPrim.set_linear_velocities()を使用します。physics:angularVelocityの単位は度/秒であり、rad/s ではありません。math.degrees()で変換します。SimulationContext.step(render=True)は、物理をレンダリングとともに進める唯一の信頼できる方法です。app.update()は物理を同期しません。- 実験的なセンサーでは
get_data()の前にapp_utils.play(commit=True)(またはtimeline.play())が必要です。レガシーのWorldフローからinitialize()を呼び出さないでください。 - Isaac Sim 5.1 以降では
get_rigid_body_state()は存在しません。isaacsim.core.experimental.primsのRigidPrim.get_world_poses()を使用してください。 - PhysX は、同じアイランド内の接触連鎖における連続的な運動量伝達を解決できません(実例 4:ニュートンのゆりかご — PhysX の同一アイランド接触の制限を参照)。
- 高速回転時のすり抜け:複合コライダーは、約 50 rad/s を超えると 5~6 秒後に機能しなくなります。より単純な凸包を使用するか、物理演算の Hz を上げてください。
- コントローラーを診断する前に:
PhysicsScene、アクティブなタイムライン、想定される Collision API が存在することを確認してください。
実例(衝撃、振動フィーダー、ジャイロ、ゆりかご、脱進機)
詳細は examples.md を参照してください。