|
| 1 | +# Rigid Object Group |
| 2 | + |
| 3 | +```{currentmodule} embodichain.lab.sim |
| 4 | +``` |
| 5 | + |
| 6 | +The `RigidObjectGroup` class represents a logical collection of rigid objects that are created and managed together. It is useful for spawning multiple related rigid bodies (e.g., multi-part props, object sets) and performing batch operations such as resetting, applying transforms, or querying group-level observations. |
| 7 | + |
| 8 | +## Configuration |
| 9 | + |
| 10 | +Configured via the {class}`~cfg.RigidObjectGroupCfg` class. |
| 11 | + |
| 12 | +| Parameter | Type | Default | Description | |
| 13 | +| :--- | :--- | :--- | :--- | |
| 14 | +| `uid` | `str` | `None` | Unique identifier for the group. | |
| 15 | +| `rigid_objects` | `Dict[str, RigidObjectCfg]` | `MISSING` | Mapping from member uid to its `RigidObjectCfg`. Each entry spawns one rigid object. When `folder_path` is provided, this acts as a template. | |
| 16 | +| `body_type` | `Literal["dynamic","kinematic"]` | `"dynamic"` | Default body type applied to group members (can be overridden per-member). | |
| 17 | +| `folder_path` | `str | None` | `None` | Optional folder to initialize many objects from mesh files; if specified, `rigid_objects` should contain a template `RigidObjectCfg`. | |
| 18 | +| `max_num` | `int` | `1` | When `folder_path` is used, number of objects to sample/create from the folder. | |
| 19 | +| `ext` | `str` | `".obj"` | File extension filter when loading assets from `folder_path`. | |
| 20 | +| `init_pos` / `init_rot` | `Sequence` (optional) | group-level transform | Optional transform to apply as a base offset to all members. | |
| 21 | + |
| 22 | +Refer to {class}`~cfg.RigidObjectCfg` and {class}`~cfg.RigidBodyAttributesCfg` for per-member configuration options (mass, friction, restitution, collision options, shapes, etc.). |
| 23 | + |
| 24 | +### Folder-based initialization |
| 25 | + |
| 26 | +If `RigidObjectGroupCfg.folder_path` is specified, the group can be auto-populated from files under that folder. The `from_dict` implementation will: |
| 27 | + |
| 28 | +- list files with extension `ext` under `folder_path`, |
| 29 | +- select up to `max_num` files (wrapping if necessary), |
| 30 | +- copy the template `RigidObjectCfg` provided in `rigid_objects` and set each member's `shape.fpath` to the selected file path and give each member a generated uid. |
| 31 | + |
| 32 | +This makes it convenient to spawn many similar objects from an asset directory. |
| 33 | + |
| 34 | +## Setup & Initialization |
| 35 | + |
| 36 | +```python |
| 37 | +import torch |
| 38 | +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg |
| 39 | +from embodichain.lab.sim.shapes import CubeCfg |
| 40 | +from embodichain.lab.sim.objects import ( |
| 41 | + RigidObjectGroup, RigidObjectGroupCfg, RigidObjectCfg |
| 42 | +) |
| 43 | +from embodichain.lab.sim.cfg import RigidBodyAttributesCfg |
| 44 | + |
| 45 | +# 1. Initialize Simulation |
| 46 | +device = "cuda" if torch.cuda.is_available() else "cpu" |
| 47 | +sim_cfg = SimulationManagerCfg(sim_device=device) |
| 48 | +sim = SimulationManager(sim_cfg) |
| 49 | + |
| 50 | +# 2. Define shared physics attributes |
| 51 | +physics_attrs = RigidBodyAttributesCfg( |
| 52 | + mass=1.0, |
| 53 | + dynamic_friction=0.5, |
| 54 | + static_friction=0.5, |
| 55 | + restitution=0.1, |
| 56 | +) |
| 57 | + |
| 58 | +# 3. Create group config with multiple members |
| 59 | +group_cfg = RigidObjectGroupCfg( |
| 60 | + uid="obj_group", |
| 61 | + rigid_objects={ |
| 62 | + "cube_1": RigidObjectCfg(uid="cube_1", shape=CubeCfg(size=[0.1,0.1,0.1]), attrs=physics_attrs, init_pos=[0.0,0.0,1.0]), |
| 63 | + "cube_2": RigidObjectCfg(uid="cube_2", shape=CubeCfg(size=[0.2,0.2,0.2]), attrs=physics_attrs, init_pos=[0.5,0.0,1.0]), |
| 64 | + "cube_3": RigidObjectCfg(uid="cube_3", shape=CubeCfg(size=[0.3,0.3,0.3]), attrs=physics_attrs, init_pos=[-0.5,0.0,1.0]), |
| 65 | + } |
| 66 | +) |
| 67 | + |
| 68 | +# 4. Spawn the rigid object group |
| 69 | +obj_group: RigidObjectGroup = sim.add_rigid_object_group(cfg=group_cfg) |
| 70 | + |
| 71 | +# 5. Run or step simulation |
| 72 | +sim.update() |
| 73 | +``` |
| 74 | + |
| 75 | +The example `scripts/tutorials/sim/create_rigid_object_group.py` demonstrates creating and running a scene with a `RigidObjectGroup`. |
| 76 | + |
| 77 | +## Rigid Object Group — Common Methods & Attributes |
| 78 | + |
| 79 | + |
| 80 | +A group provides batch operations on multiple rigid objects. Key APIs include: |
| 81 | + |
| 82 | +| Method / Property | Return / Args | Description | |
| 83 | +| :--- | :--- | :--- | |
| 84 | +| `num_objects` | `int` | Number of objects in each group instance. | |
| 85 | +| `body_data` | `RigidBodyGroupData` | Data manager providing `pose`, `lin_vel`, `ang_vel` properties. | |
| 86 | +| `body_state` | `(N, M, 13)` | Full body state of all members: [x, y, z, qw, qx, qy, qz, lin_x, lin_y, lin_z, ang_x, ang_y, ang_z]. | |
| 87 | +| `get_local_pose(to_matrix=False)` | `(N, M, 7)` or `(N, M, 4, 4)` | Poses of all members across N envs; M = number of members. | |
| 88 | +| `set_local_pose(pose, env_ids=None, obj_ids=None)` | `pose: (N, M, 7)` or `(N, M, 4, 4)` | Set poses for specific environments and/or objects; requires `sim.update()` to apply. | |
| 89 | +| `get_user_ids()` | `(N, M)` | Get user IDs tensor for all members in the group. | |
| 90 | +| `clear_dynamics(env_ids=None)` | - | Reset velocities and clear all forces/torques for the group. | |
| 91 | +| `set_visual_material(mat, env_ids=None)` | `mat: VisualMaterial` | Change visual appearance for all members. | |
| 92 | +| `set_visible(visible=True)` | `visible: bool` | Set visibility for all members in the group. | |
| 93 | +| `set_physical_visible(visible=True, rgba=None)` | - | Set collision body visibility for debugging. | |
| 94 | +| `reset(env_ids=None)` | - | Reset all members to their initial configured transforms. | |
| 95 | + |
| 96 | +### Observation Shapes |
| 97 | + |
| 98 | +- Group member poses (`body_data.pose`): `(N, M, 7)` where N is number of environments and M is number of objects in the group. |
| 99 | +- Member linear velocities (`body_data.lin_vel`): `(N, M, 3)`. |
| 100 | +- Member angular velocities (`body_data.ang_vel`): `(N, M, 3)`. |
| 101 | +- Full body state (`body_state`): `(N, M, 13)` containing [position (3), orientation (4), linear velocity (3), angular velocity (3)]. |
| 102 | + |
| 103 | +Use these shapes when collecting vectorized observations for multi-environment training. |
| 104 | + |
| 105 | +## Best Practices |
| 106 | + |
| 107 | +- Groups are convenient for batch operations: resetting, setting visibility, and applying transforms to multiple objects together. |
| 108 | +- Use `obj_ids` parameter in `set_local_pose()` to control specific objects within the group rather than all members. |
| 109 | +- Prefer providing simplified collision meshes or enabling convex decomposition (`max_convex_hull_num` > 1) for complex visual meshes to improve physics stability. |
| 110 | +- `RigidObjectGroup` only supports `dynamic` and `kinematic` body types (not `static`). |
| 111 | +- When teleporting many members, batch pose updates and call `sim.update()` once to avoid synchronization overhead. |
| 112 | +- For GPU physics, set `SimulationManagerCfg.sim_device` to `cuda` and call `sim.init_gpu_physics()` before running simulations. |
| 113 | +- Use `clear_dynamics()` to reset velocities without changing poses. |
| 114 | + |
| 115 | +## Example: Working with Group Poses |
| 116 | + |
| 117 | +```python |
| 118 | +import torch |
| 119 | + |
| 120 | +# Get current poses of all members |
| 121 | +poses = obj_group.get_local_pose() # (N, M, 7) where N=num_envs, M=num_objects |
| 122 | + |
| 123 | +# Move specific objects in the group |
| 124 | +# Example: Move only the first object (cube_1) in all environments |
| 125 | +new_pose = torch.tensor([[[0.0, 1.0, 0.5, 1, 0, 0, 0]]], device=sim.device) # (1, 1, 7) |
| 126 | +obj_group.set_local_pose(new_pose, env_ids=[0], obj_ids=[0]) |
| 127 | +sim.update() |
| 128 | + |
| 129 | +# Access velocity data for all members |
| 130 | +linear_vels = obj_group.body_data.lin_vel # (N, M, 3) |
| 131 | +angular_vels = obj_group.body_data.ang_vel # (N, M, 3) |
| 132 | + |
| 133 | +# Reset all objects to initial configuration |
| 134 | +obj_group.reset() |
| 135 | +sim.update() |
| 136 | +``` |
| 137 | + |
| 138 | +## Integration with Sensors |
| 139 | + |
| 140 | +Members in a group behave like normal `RigidObject`s: they can be observed by cameras, attached to contact sensors. You can operate on individual members or treat the group as a single unit depending on your scenario. |
| 141 | + |
| 142 | +## Related Topics |
| 143 | + |
| 144 | +- Rigid objects: See the Rigid Object overview for single-body. |
| 145 | +- Soft bodies: Deformable objects have different observation semantics (vertex-level data). ([Soft Body Simulation Tutorial](https://dexforce.github.io/EmbodiChain/tutorial/create_softbody.html)) |
| 146 | +- Examples: `scripts/tutorials/sim/create_rigid_object_group.py` |
| 147 | + |
| 148 | + |
| 149 | +<!-- End of rigid object group overview --> |
0 commit comments