Skip to content

Commit 4352f1c

Browse files
committed
fix(sim): CoverWrapper wrapper for correct resetting
There is now a CoverWrapper which needs to be added at the top of the stack. It ensures that the sim is correctly reset before the wrappers assume a clean sim state. Its only strictly necessary for simulator environments but also works for hardware environments.
1 parent 6afbd26 commit 4352f1c

10 files changed

Lines changed: 52 additions & 21 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ from rcs.envs.base import (
5252
RelativeTo,
5353
RobotWrapper,
5454
SimEnv,
55+
CoverWrapper,
5556
)
5657
from rcs.envs.sim import GripperWrapperSim, RobotSimWrapper
5758
from rcs.envs.utils import (
@@ -98,6 +99,7 @@ if __name__ == "__main__":
9899

99100
# relative actions bounded by 10cm translation and 10 degree rotation
100101
env = RelativeActionSpace(env, max_mov=(0.1, np.deg2rad(10)), relative_to=RelativeTo.LAST_STEP)
102+
env = CoverWrapper(env)
101103

102104
env.get_wrapper_attr("sim").open_gui()
103105
# wait for gui to open

examples/fr3/fr3_readme.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
RelativeTo,
1212
RobotWrapper,
1313
SimEnv,
14+
CoverWrapper,
1415
)
1516
from rcs.envs.sim import GripperWrapperSim, RobotSimWrapper
1617
from rcs.envs.utils import (
@@ -57,6 +58,7 @@
5758

5859
# relative actions bounded by 10cm translation and 10 degree rotation
5960
env = RelativeActionSpace(env, max_mov=(0.1, np.deg2rad(10)), relative_to=RelativeTo.LAST_STEP)
61+
env = CoverWrapper(env)
6062

6163
env.get_wrapper_attr("sim").open_gui()
6264
# wait for gui to open

extensions/rcs_fr3/src/rcs_fr3/creators.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
RelativeActionSpace,
1919
RelativeTo,
2020
RobotWrapper,
21+
CoverWrapper,
2122
)
2223
from rcs.envs.creators import RCSHardwareEnvCreator
2324
from rcs.hand.tilburg_hand import TilburgHand
@@ -125,6 +126,7 @@ def __call__( # type: ignore
125126
# )
126127
if relative_to != RelativeTo.NONE:
127128
env = RelativeActionSpace(env, max_mov=max_relative_movement, relative_to=relative_to)
129+
env = CoverWrapper(env)
128130

129131
return env
130132

@@ -173,6 +175,7 @@ def __call__( # type: ignore
173175
camera_set.wait_for_frames()
174176
logger.info("CameraSet started")
175177
env = CameraSetWrapper(env, camera_set)
178+
env = CoverWrapper(env)
176179
return env
177180

178181

extensions/rcs_panda/src/rcs_panda/creators.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
RelativeActionSpace,
1515
RelativeTo,
1616
RobotWrapper,
17+
CoverWrapper,
1718
)
1819
from rcs.envs.creators import RCSHardwareEnvCreator
1920
from rcs.hand.tilburg_hand import TilburgHand
@@ -106,6 +107,7 @@ def __call__( # type: ignore
106107
# )
107108
if max_relative_movement is not None:
108109
env = RelativeActionSpace(env, max_mov=max_relative_movement, relative_to=relative_to)
110+
env = CoverWrapper(env)
109111

110112
return env
111113

@@ -153,4 +155,5 @@ def __call__( # type: ignore
153155
camera_set.wait_for_frames()
154156
logger.info("CameraSet started")
155157
env = CameraSetWrapper(env, camera_set)
158+
env = CoverWrapper(env)
156159
return env

extensions/rcs_so101/src/rcs_so101/creators.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
RelativeActionSpace,
1111
RelativeTo,
1212
RobotWrapper,
13+
CoverWrapper,
1314
)
1415
from rcs.envs.creators import RCSHardwareEnvCreator
1516
from rcs_so101 import SO101IK
@@ -48,6 +49,7 @@ def __call__( # type: ignore
4849

4950
if max_relative_movement is not None:
5051
env = RelativeActionSpace(env, max_mov=max_relative_movement, relative_to=relative_to)
52+
env = CoverWrapper(env)
5153

5254
return env
5355

extensions/rcs_ur5e/src/rcs_ur5e/creators.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
RelativeActionSpace,
1111
RelativeTo,
1212
RobotWrapper,
13+
CoverWrapper,
1314
)
1415
from rcs.envs.creators import RCSHardwareEnvCreator
1516
from rcs_ur5e.hw import RobotiQGripper, UR5e, UR5eConfig
@@ -51,5 +52,6 @@ def __call__( # type: ignore
5152

5253
if max_relative_movement is not None:
5354
env = RelativeActionSpace(env, max_mov=max_relative_movement, relative_to=relative_to)
55+
env = CoverWrapper(env)
5456

5557
return env

extensions/rcs_xarm7/src/rcs_xarm7/creators.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
RelativeActionSpace,
1313
RelativeTo,
1414
RobotWrapper,
15+
CoverWrapper,
1516
)
1617
from rcs.envs.creators import RCSHardwareEnvCreator
1718
from rcs.hand.tilburg_hand import THConfig, TilburgHand
@@ -49,5 +50,6 @@ def __call__( # type: ignore
4950

5051
if max_relative_movement is not None:
5152
env = RelativeActionSpace(env, max_mov=max_relative_movement, relative_to=relative_to)
53+
env = CoverWrapper(env)
5254

5355
return env

python/rcs/envs/base.py

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,7 @@ def step_sim(self):
244244
else:
245245
self.sim.step_until_convergence()
246246

247-
def reset_sim(self):
248-
self.sim.reset()
247+
def apply_sim_state(self):
249248
self.sim.step(1)
250249

251250

@@ -255,7 +254,20 @@ def reset(
255254
if self.main_greenlet is not None:
256255
self.main_greenlet.switch()
257256
else:
258-
self.reset_sim()
257+
self.apply_sim_state()
258+
return super().reset(seed=seed, options=options)
259+
260+
class CoverWrapper(gym.Wrapper):
261+
"""The CoverWrapper must be the last wrapper on the stack
262+
263+
Only strictly necessary for simulator environments, but also works for hardware environments.
264+
It takes care of resetting the simulator before any other wrapper resets its state, already assuming
265+
a fresh simulator state.
266+
"""
267+
def reset(self, *, seed: int | None = None, options: dict[str, Any] | None = None) -> tuple[dict[str, Any], dict[str, Any]]:
268+
if self.env.get_wrapper_attr("PLATFORM") == RobotPlatform.SIMULATION:
269+
sim = cast(simulation.Sim, self.get_wrapper_attr("sim"))
270+
sim.reset()
259271
return super().reset(seed=seed, options=options)
260272

261273

@@ -333,25 +345,28 @@ def action(self, action: dict[str, Any]) -> dict[str, Any]:
333345
):
334346
msg = "Given type is not matching control mode!"
335347
raise RuntimeError(msg)
348+
last_action = self.prev_action
336349
self.prev_action = copy.deepcopy(action)
337350

351+
# shallow copy
352+
action = dict(action)
338353
if self.get_base_control_mode() == ControlMode.JOINTS and (
339-
self.prev_action is None
340-
or not np.allclose(action[self.joints_key], self.prev_action[self.joints_key], atol=1e-03, rtol=0)
354+
last_action is None
355+
or not np.allclose(action[self.joints_key], last_action[self.joints_key], atol=1e-03, rtol=0)
341356
):
342357
self.robot.set_joint_position(action[self.joints_key])
343358
action.pop(self.joints_key)
344359
elif self.get_base_control_mode() == ControlMode.CARTESIAN_TRPY and (
345-
self.prev_action is None
346-
or not np.allclose(action[self.trpy_key], self.prev_action[self.trpy_key], atol=1e-03, rtol=0)
360+
last_action is None
361+
or not np.allclose(action[self.trpy_key], last_action[self.trpy_key], atol=1e-03, rtol=0)
347362
):
348363
self.robot.set_cartesian_position(
349364
common.Pose(translation=action[self.trpy_key][:3], rpy_vector=action[self.trpy_key][3:])
350365
)
351366
action.pop(self.trpy_key)
352367
elif self.get_base_control_mode() == ControlMode.CARTESIAN_TQuat and (
353-
self.prev_action is None
354-
or not np.allclose(action[self.tquat_key], self.prev_action[self.tquat_key], atol=1e-03, rtol=0)
368+
last_action is None
369+
or not np.allclose(action[self.tquat_key], last_action[self.tquat_key], atol=1e-03, rtol=0)
355370
):
356371
self.robot.set_cartesian_position(
357372
common.Pose(translation=action[self.tquat_key][:3], quaternion=action[self.tquat_key][3:])
@@ -361,18 +376,13 @@ def action(self, action: dict[str, Any]) -> dict[str, Any]:
361376

362377
def observation(self, observation: dict, info: dict[str, Any]) -> tuple[dict[str, Any], dict[str, Any]]:
363378
observation.update(self.get_robot_obs())
364-
# if self.env.get_wrapper_attr("PLATFORM") == RobotPlatform.SIMULATION:
365-
# sim_robot = cast(SimRobot, self.robot)
366-
# state = sim_robot.get_state()
367-
# info["collision"] = state.collision
368-
# info["ik_success"] = state.ik_success
369-
# info["is_sim_converged"] = self.env.get_wrapper_attr("sim").is_converged()
370379
return observation, info
371380

372381

373382
def reset(
374383
self, *, seed: int | None = None, options: dict[str, Any] | None = None
375384
) -> tuple[dict[str, Any], dict[str, Any]]:
385+
self.prev_action = None
376386
self.robot.reset()
377387
if self.home_on_reset:
378388
self.robot.move_home()
@@ -405,6 +415,7 @@ def __init__(
405415
else:
406416
self.robot2world = robot2world
407417
self.lead_env: gym.Env | None = None
418+
self.sim: simulation.Sim | None = None
408419

409420
# make sure all envs are the same type (sim/real)
410421
for env in self.envs:
@@ -416,6 +427,9 @@ def __init__(
416427
self._runs_in_sim = self.PLATFORM == RobotPlatform.SIMULATION
417428
if self._runs_in_sim:
418429
self._inject_main_greenlet()
430+
assert isinstance(self.lead_env, SimEnv), "something is wrong with the env, the base should be type SimEnv"
431+
self.sim = self.lead_env.get_wrapper_attr("sim")
432+
419433

420434
def _inject_main_greenlet(self):
421435
main_gr = getcurrent()
@@ -471,9 +485,7 @@ def make_step_gr(env_to_step):
471485
if self._runs_in_sim:
472486
# SIM path: 3. UP: Gather observations
473487
# Resume robot greenlet. It returns the step results.
474-
res = step_greenlets[key].switch()
475-
ob, r, t, tr, i = res
476-
488+
ob, r, t, tr, info[key] = step_greenlets[key].switch()
477489
else:
478490
# HARDWARE path
479491
act = self._translate_pose(key, action[key], to_world=False)
@@ -510,9 +522,9 @@ def make_reset_gr(env_to_reset, s, o):
510522
reset_greenlets[key] = gr
511523
gr.switch()
512524

513-
# SIM path: 2. SIM: reset
525+
# SIM path: 2. SIM: apply state from rested wrappers
514526
assert isinstance(self.lead_env, SimEnv)
515-
self.lead_env.reset_sim()
527+
self.lead_env.apply_sim_state()
516528

517529

518530
for key, env in self.envs.items():

python/rcs/envs/creators.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
RelativeTo,
2121
RobotWrapper,
2222
SimEnv,
23+
CoverWrapper,
2324
)
2425
from rcs.envs.sim import (
2526
GripperWrapperSim,
@@ -128,6 +129,7 @@ def __call__( # type: ignore
128129
# )
129130
if max_relative_movement is not None:
130131
env = RelativeActionSpace(env, max_mov=max_relative_movement, relative_to=relative_to)
132+
env = CoverWrapper(env)
131133

132134
return env
133135

@@ -186,6 +188,7 @@ def __call__( # type: ignore
186188
BaseCameraSet, SimCameraSet(simulation, cameras, physical_units=True, render_on_demand=True)
187189
)
188190
env = CameraSetWrapper(env, camera_set, include_depth=True)
191+
env = CoverWrapper(env)
189192
return env
190193

191194

python/rcs/rpc/server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def reset(self, **kwargs):
2626
@rpyc.exposed
2727
def get_robot_obs(self):
2828
"""Get the current observation using the Wrapper base class if available."""
29-
return self.get_wrapper_attr("get_robot_obs")()
29+
return self.env.get_wrapper_attr("get_robot_obs")()
3030

3131
@rpyc.exposed
3232
def unwrapped(self):

0 commit comments

Comments
 (0)