@@ -89,6 +89,7 @@ def __init__(self, cfg: ArticulationCfg, *, name: str = "robot") -> None:
8989 self ._action_scale_tensor : torch .Tensor = torch .empty (0 )
9090 self ._actuators : dict [str , ActuatorBase ] = {}
9191 self ._joint_pos_target : torch .Tensor = torch .empty (0 )
92+ self ._gravity_w : torch .Tensor = torch .empty (0 )
9293 self ._data : RobotState | None = None
9394
9495 # ------------------------------------------------------------------ spawn / bind
@@ -118,6 +119,10 @@ def bind(self, num_envs: int, device: str) -> None:
118119 self ._default_joint_pos .unsqueeze (0 ).expand (num_envs , - 1 ).contiguous ()
119120 )
120121 self ._data = RobotState (num_envs , self ._num_dofs , self ._num_links , device )
122+ # Cached constant gravity vector, broadcast across envs. Built once at bind to keep
123+ # ``refresh`` allocation-free on the hot path (called every step + every reset).
124+ self ._gravity_w = torch .zeros (num_envs , 3 , device = device )
125+ self ._gravity_w [:, 2 ] = - 1.0
121126 self ._assemble_actuators ()
122127
123128 # ------------------------------------------------------------------ internals
@@ -253,14 +258,14 @@ def refresh(self) -> None:
253258 rs = self ._data
254259 robot = self ._gs_handle
255260 try :
256- rs .root_pos = to_tensor (robot .get_pos (), self ._device )
257- rs .root_quat = to_tensor (robot .get_quat (), self ._device )
258- rs .root_lin_vel_w = to_tensor (robot .get_vel (), self ._device )
259- rs .root_ang_vel_w = to_tensor (robot .get_ang (), self ._device )
261+ rs .root_pos . copy_ ( to_tensor (robot .get_pos (), self ._device ) )
262+ rs .root_quat . copy_ ( to_tensor (robot .get_quat (), self ._device ) )
263+ rs .root_lin_vel_w . copy_ ( to_tensor (robot .get_vel (), self ._device ) )
264+ rs .root_ang_vel_w . copy_ ( to_tensor (robot .get_ang (), self ._device ) )
260265 joint_pos_full = to_tensor (robot .get_dofs_position (), self ._device )
261266 joint_vel_full = to_tensor (robot .get_dofs_velocity (), self ._device )
262- rs .joint_pos = joint_pos_full .index_select (- 1 , self ._actuated_dof_idx )
263- rs .joint_vel = joint_vel_full .index_select (- 1 , self ._actuated_dof_idx )
267+ rs .joint_pos . copy_ ( joint_pos_full .index_select (- 1 , self ._actuated_dof_idx ) )
268+ rs .joint_vel . copy_ ( joint_vel_full .index_select (- 1 , self ._actuated_dof_idx ) )
264269 except AttributeError :
265270 pass
266271 for attr , target in (
@@ -277,13 +282,14 @@ def refresh(self) -> None:
277282 except Exception :
278283 continue
279284 tensor = to_tensor (value , self ._device )
285+ # Genesis may return either (num_envs, num_links, ...) or the bare (num_links, ...)
286+ # shape on older single-env builds; ``expand`` broadcasts without allocating.
280287 if tensor .dim () == 2 :
281288 tensor = tensor .unsqueeze (0 ).expand (self ._num_envs , - 1 , - 1 )
282- setattr (rs , target , tensor )
289+ getattr (rs , target ). copy_ ( tensor )
283290 rs .root_lin_vel_b = quat_rotate_inverse (rs .root_quat , rs .root_lin_vel_w )
284291 rs .root_ang_vel_b = quat_rotate_inverse (rs .root_quat , rs .root_ang_vel_w )
285- gravity_w = torch .tensor ([0.0 , 0.0 , - 1.0 ], device = self ._device ).expand_as (rs .root_lin_vel_w )
286- rs .projected_gravity_b = quat_rotate_inverse (rs .root_quat , gravity_w )
292+ rs .projected_gravity_b = quat_rotate_inverse (rs .root_quat , self ._gravity_w )
287293
288294 def write_joint_state (
289295 self ,
0 commit comments