@@ -421,6 +421,8 @@ def __init__(
421421 self .lead_env : gym .Env | None = None
422422 self .sim : simulation .Sim | None = None
423423
424+ self ._rel_env : dict [str , bool ] = {}
425+
424426 # make sure all envs are the same type (sim/real)
425427 for env in self .envs :
426428 if self .PLATFORM is None :
@@ -430,12 +432,26 @@ def __init__(
430432 assert (
431433 self .envs [env ].get_wrapper_attr ("PLATFORM" ) == self .PLATFORM
432434 ), "all envs must have the same platform!"
435+ self ._rel_env [env ] = self ._env_relative (self .envs [env ]) # type: ignore
436+
433437 self ._runs_in_sim = self .PLATFORM == RobotPlatform .SIMULATION
434438 if self ._runs_in_sim :
435439 self ._inject_main_greenlet ()
436440 assert isinstance (self .lead_env , SimEnv ), "something is wrong with the env, the base should be type SimEnv"
437441 self .sim = self .lead_env .get_wrapper_attr ("sim" )
438442
443+ def _env_relative (self , env : gym .Wrapper ):
444+ max_depth = 100
445+ while True :
446+ if isinstance (env , RelativeActionSpace ):
447+ return True
448+ if isinstance (env , SimEnv | HardwareEnv ):
449+ return False
450+ if max_depth < 0 :
451+ return False
452+ max_depth -= 1
453+ env = env .env # type: ignore
454+
439455 def _inject_main_greenlet (self ):
440456 main_gr = getcurrent ()
441457 for env_item in self .envs .values ():
@@ -444,15 +460,19 @@ def _inject_main_greenlet(self):
444460 ), "something is wrong with the env, the base should be type SimEnv"
445461 env_item .unwrapped .main_greenlet = main_gr
446462
447- def _translate_pose (self , key , dic , to_world = True ):
463+ def _translate_pose (self , key , dic , to_world = True , relative = True ):
448464 r2w = self .robot_to_shared_base_frame .get (key , common .Pose ())
449465 if not to_world :
450466 r2w = r2w .inverse ()
451467 if "tquat" in dic :
452- p = r2w * common .Pose (translation = dic ["tquat" ][:3 ], quaternion = dic ["tquat" ][3 :]) * r2w .inverse ()
468+ p = r2w * common .Pose (translation = dic ["tquat" ][:3 ], quaternion = dic ["tquat" ][3 :])
469+ if relative :
470+ p *= r2w .inverse ()
453471 dic ["tquat" ] = np .concatenate ([p .translation (), p .rotation_q ()])
454472 if "xyzrpy" in dic :
455- p = r2w * common .Pose (translation = dic ["xyzrpy" ][:3 ], rpy_vector = dic ["xyzrpy" ][3 :]) * r2w .inverse ()
473+ p = r2w * common .Pose (translation = dic ["xyzrpy" ][:3 ], rpy_vector = dic ["xyzrpy" ][3 :])
474+ if relative :
475+ p *= r2w .inverse ()
456476 dic ["xyzrpy" ] = p .xyzrpy ()
457477
458478 return dic
@@ -470,7 +490,7 @@ def make_step_gr(env_to_step):
470490 step_greenlets [key ] = gr
471491
472492 # Translate action
473- act = self ._translate_pose (key , action [key ], to_world = False )
493+ act = self ._translate_pose (key , action [key ], to_world = False , relative = self . _rel_env [ key ] )
474494
475495 # Switch to robot greenlet. It will run until RobotSimWrapper.step switches back.
476496 gr .switch (act )
@@ -493,10 +513,10 @@ def make_step_gr(env_to_step):
493513 ob , r , t , tr , info [key ] = step_greenlets [key ].switch ()
494514 else :
495515 # HARDWARE path
496- act = self ._translate_pose (key , action [key ], to_world = False )
516+ act = self ._translate_pose (key , action [key ], to_world = False , relative = self . _rel_env [ key ] )
497517 ob , r , t , tr , info [key ] = env .step (act )
498518
499- obs [key ] = self ._translate_pose (key , ob , to_world = True )
519+ obs [key ] = self ._translate_pose (key , ob , to_world = True , relative = False )
500520 reward += float (r )
501521 terminated = terminated or t
502522 truncated = truncated or tr
@@ -539,7 +559,7 @@ def make_reset_gr(env_to_reset, s, o):
539559 # HARDWARE path
540560 ob , i = env .reset (seed = seed_ [key ], options = options_ [key ])
541561
542- obs [key ] = self ._translate_pose (key , ob , to_world = True )
562+ obs [key ] = self ._translate_pose (key , ob , to_world = True , relative = False )
543563 info [key ] = i
544564
545565 return obs , info
0 commit comments