|
2 | 2 | from typing import Any, cast |
3 | 3 |
|
4 | 4 | import gymnasium as gym |
5 | | -import numpy as np |
6 | 5 | from rcs._core.common import RobotPlatform |
7 | | -from rcs.envs.base import GripperWrapper |
8 | 6 | from rcs.envs.space_utils import ActObsInfoWrapper |
9 | 7 |
|
10 | | -import rcs |
11 | 8 | from rcs import sim |
12 | 9 |
|
13 | 10 | logger = logging.getLogger(__name__) |
@@ -43,36 +40,6 @@ def reset( |
43 | 40 | return super().reset(seed=seed, options=options) |
44 | 41 |
|
45 | 42 |
|
46 | | -class SimStateObservationWrapper(ActObsInfoWrapper): |
47 | | - STATE_KEY = "sim_state" |
48 | | - STATE_SPEC_KEY = "sim_state_spec" |
49 | | - STATE_SIZE_KEY = "sim_state_size" |
50 | | - |
51 | | - def __init__(self, env): |
52 | | - super().__init__(env) |
53 | | - assert self.env.get_wrapper_attr("PLATFORM") == RobotPlatform.SIMULATION, "Base environment must be simulation." |
54 | | - self.sim = cast(sim.Sim, self.get_wrapper_attr("sim")) |
55 | | - self._state_spec = self.sim.get_state_spec() |
56 | | - self._include_state_spec_in_next_step = True |
57 | | - |
58 | | - def observation(self, observation: dict[str, Any], info: dict[str, Any]) -> tuple[dict[str, Any], dict[str, Any]]: |
59 | | - observation = dict(observation) |
60 | | - sim_state = self.sim.get_state() |
61 | | - observation[self.STATE_KEY] = sim_state |
62 | | - observation[self.STATE_SIZE_KEY] = sim_state.shape[0] |
63 | | - if self._include_state_spec_in_next_step: |
64 | | - observation[self.STATE_SPEC_KEY] = self._state_spec |
65 | | - self._include_state_spec_in_next_step = False |
66 | | - return observation, info |
67 | | - |
68 | | - def reset( |
69 | | - self, *, seed: int | None = None, options: dict[str, Any] | None = None |
70 | | - ) -> tuple[dict[str, Any], dict[str, Any]]: |
71 | | - obs, info = super().reset(seed=seed, options=options) |
72 | | - self._include_state_spec_in_next_step = True |
73 | | - return obs, info |
74 | | - |
75 | | - |
76 | 43 | class GripperWrapperSim(ActObsInfoWrapper): |
77 | 44 | def __init__(self, env): |
78 | 45 | super().__init__(env) |
@@ -127,187 +94,6 @@ def observation(self, observation: dict[str, Any], info: dict[str, Any]) -> tupl |
127 | 94 | return observation, info |
128 | 95 |
|
129 | 96 |
|
130 | | -class RandomObjectPos(gym.Wrapper): |
131 | | - """ |
132 | | - Wrapper to randomly re-place an object in the lab environments. |
133 | | - Given the object's joint name and initial pose, its x, y coordinates are randomized, while z remains fixed. |
134 | | - If include_rotation is true, the object's z-axis rotation (yaw) is also randomized. |
135 | | -
|
136 | | - Args: |
137 | | - env (gym.Env): The environment to wrap. |
138 | | - simulation (sim.Sim): The simulation instance. |
139 | | - joint_name (str): The name of the free joint attached to the object to manipulate. |
140 | | - init_object_pose (rcs.common.Pose): The initial pose of the object. |
141 | | - include_rotation (bool): Whether to include rotation in the randomization. |
142 | | - """ |
143 | | - |
144 | | - def __init__( |
145 | | - self, |
146 | | - env: gym.Env, |
147 | | - joint_name: str, |
148 | | - init_object_pose: rcs.common.Pose, |
149 | | - include_position: bool = True, |
150 | | - include_rotation: bool = False, |
151 | | - x_scale: float = 0.2, |
152 | | - y_scale: float = 0.2, |
153 | | - x_offset: float = 0.1, |
154 | | - y_offset: float = 0.1, |
155 | | - ): |
156 | | - super().__init__(env) |
157 | | - self.joint_name = joint_name |
158 | | - self.init_object_pose = init_object_pose |
159 | | - self.include_position = include_position |
160 | | - self.include_rotation = include_rotation |
161 | | - self.x_scale = x_scale |
162 | | - self.y_scale = y_scale |
163 | | - self.x_offset = x_offset |
164 | | - self.y_offset = y_offset |
165 | | - |
166 | | - def reset( |
167 | | - self, *, seed: int | None = None, options: dict[str, Any] | None = None |
168 | | - ) -> tuple[dict[str, Any], dict[str, Any]]: |
169 | | - if options is not None and "RandomObjectPos.init_object_pose" in options: |
170 | | - assert isinstance( |
171 | | - options["RandomObjectPos.init_object_pose"], rcs.common.Pose |
172 | | - ), "RandomObjectPos.init_object_pose must be a rcs.common.Pose" |
173 | | - |
174 | | - self.init_object_pose = options["RandomObjectPos.init_object_pose"] |
175 | | - print("Got random object pos!\n", self.init_object_pose) |
176 | | - del options["RandomObjectPos.init_object_pose"] |
177 | | - obs, info = super().reset(seed=seed, options=options) |
178 | | - |
179 | | - pos_z = self.init_object_pose.translation()[2] |
180 | | - if self.include_position: |
181 | | - pos_x = self.init_object_pose.translation()[0] + np.random.random() * self.x_scale + self.x_offset |
182 | | - pos_y = self.init_object_pose.translation()[1] + np.random.random() * self.y_scale + self.y_offset |
183 | | - else: |
184 | | - pos_x = self.init_object_pose.translation()[0] |
185 | | - pos_y = self.init_object_pose.translation()[1] |
186 | | - |
187 | | - quat = self.init_object_pose.rotation_q() # xyzw format |
188 | | - if self.include_rotation: |
189 | | - random_z_rotation = (np.random.random() - 0.5) * (0.7071068 * 2) |
190 | | - self.get_wrapper_attr("sim").data.joint(self.joint_name).qpos = [ |
191 | | - pos_x, |
192 | | - pos_y, |
193 | | - pos_z, |
194 | | - quat[3] + random_z_rotation, |
195 | | - quat[0], |
196 | | - quat[1], |
197 | | - quat[2] + random_z_rotation, |
198 | | - ] |
199 | | - else: |
200 | | - self.get_wrapper_attr("sim").data.joint(self.joint_name).qpos = [ |
201 | | - pos_x, |
202 | | - pos_y, |
203 | | - pos_z, |
204 | | - quat[3], |
205 | | - quat[0], |
206 | | - quat[1], |
207 | | - quat[2], |
208 | | - ] |
209 | | - |
210 | | - return obs, info |
211 | | - |
212 | | - |
213 | | -class RandomCubePos(gym.Wrapper): |
214 | | - """Wrapper to randomly place cube in the lab environments. |
215 | | -
|
216 | | - Works only for single robot |
217 | | - """ |
218 | | - |
219 | | - def __init__(self, env: gym.Env, include_rotation: bool = False, cube_joint_name="box_joint"): |
220 | | - super().__init__(env) |
221 | | - self.include_rotation = include_rotation |
222 | | - self.cube_joint_name = cube_joint_name |
223 | | - |
224 | | - def reset( |
225 | | - self, *, seed: int | None = None, options: dict[str, Any] | None = None |
226 | | - ) -> tuple[dict[str, Any], dict[str, Any]]: |
227 | | - obs, info = super().reset(seed=seed, options=options) |
228 | | - |
229 | | - iso_cube = np.array([0.498, 0.0, 0.226]) |
230 | | - iso_cube_pose = rcs.common.Pose(translation=np.array(iso_cube), rpy_vector=np.array([0, 0, 0])) # type: ignore |
231 | | - iso_cube = self.get_wrapper_attr("robot").to_pose_in_world_coordinates(iso_cube_pose).translation() |
232 | | - pos_z = 0.0288 |
233 | | - pos_x = iso_cube[0] + np.random.random() * 0.2 - 0.1 |
234 | | - pos_y = iso_cube[1] + np.random.random() * 0.2 - 0.1 |
235 | | - |
236 | | - if self.include_rotation: |
237 | | - self.get_wrapper_attr("sim").data.joint(self.cube_joint_name).qpos = [ |
238 | | - pos_x, |
239 | | - pos_y, |
240 | | - pos_z, |
241 | | - 2 * np.random.random() - 1, |
242 | | - 0, |
243 | | - 0, |
244 | | - 1, |
245 | | - ] |
246 | | - else: |
247 | | - self.get_wrapper_attr("sim").data.joint(self.cube_joint_name).qpos = [pos_x, pos_y, pos_z, 0, 0, 0, 1] |
248 | | - |
249 | | - return obs, info |
250 | | - |
251 | | - |
252 | | -class PickCubeSuccessWrapper(gym.Wrapper): |
253 | | - """ |
254 | | - Wrapper to check if the cube is successfully picked up in the FR3SimplePickUpSim environment. |
255 | | - Cube must be lifted 10 cm above the robot base. |
256 | | - Computes a reward between 0 and 1 based on: |
257 | | - - TCP to object distance |
258 | | - - cube z height |
259 | | - - whether the arm is standing still once the task is solved. |
260 | | - """ |
261 | | - |
262 | | - def __init__(self, env, cube_geom_name="box_geom"): |
263 | | - super().__init__(env) |
264 | | - assert isinstance(self.get_wrapper_attr("robot"), sim.SimRobot), "Robot must be a sim.SimRobot instance." |
265 | | - self._robot = cast(sim.SimRobot, self.get_wrapper_attr("robot")) |
266 | | - self.sim = self.env.get_wrapper_attr("sim") |
267 | | - self.cube_geom_name = cube_geom_name |
268 | | - self.home_pose = self._robot.get_cartesian_position() |
269 | | - self._gripper_closing = 0 |
270 | | - self._gripper = self.get_wrapper_attr("gripper") |
271 | | - |
272 | | - def step(self, action: dict[str, Any]): # type: ignore |
273 | | - obs, reward, _, truncated, info = super().step(action) |
274 | | - if ( |
275 | | - self._gripper.get_normalized_width() > 0.01 |
276 | | - and self._gripper.get_normalized_width() < 0.99 |
277 | | - and obs["gripper"] == GripperWrapper.BINARY_GRIPPER_CLOSED |
278 | | - ): |
279 | | - self._gripper_closing += 1 |
280 | | - else: |
281 | | - self._gripper_closing = 0 |
282 | | - cube_pose = rcs.common.Pose(translation=self.sim.data.geom(self.cube_geom_name).xpos) |
283 | | - cube_pose = self._robot.to_pose_in_robot_coordinates(cube_pose) |
284 | | - tcp_to_obj_dist = np.linalg.norm(cube_pose.translation() - self._robot.get_cartesian_position().translation()) |
285 | | - obj_to_goal_dist = 0.10 - min(cube_pose.translation()[-1], 0.10) |
286 | | - obj_to_goal_dist = np.linalg.norm(cube_pose.translation() - self.home_pose.translation()) |
287 | | - # NOTE: 4 depends on the time passing between each step. |
288 | | - is_grasped = ( |
289 | | - self._gripper_closing >= 4 # gripper is closing since more than 4 steps |
290 | | - and obs["gripper"] == GripperWrapper.BINARY_GRIPPER_CLOSED # command is still close |
291 | | - and tcp_to_obj_dist <= 0.01 # tcp to cube center is max 1cm |
292 | | - ) |
293 | | - success = obj_to_goal_dist <= 0.022 and info["is_grasped"] |
294 | | - movement = np.linalg.norm(self.sim.data.qvel) |
295 | | - |
296 | | - reaching_reward = 1 - np.tanh(5 * tcp_to_obj_dist) |
297 | | - place_reward = 1 - np.tanh(5 * obj_to_goal_dist) |
298 | | - static_reward = 1 - np.tanh(5 * movement) |
299 | | - info["is_grasped"] = is_grasped |
300 | | - info["success"] = success |
301 | | - reward = reaching_reward + place_reward * is_grasped + static_reward * success |
302 | | - reward /= 3 # type: ignore |
303 | | - return obs, reward, success, truncated, info |
304 | | - |
305 | | - def reset(self, *, seed: int | None = None, options: dict[str, Any] | None = None): |
306 | | - obs, info = super().reset() |
307 | | - self.home_pose = self._robot.get_cartesian_position() |
308 | | - return obs, info |
309 | | - |
310 | | - |
311 | 97 | class DigitalTwin(gym.Wrapper): |
312 | 98 | def __init__(self, env, twin_env): |
313 | 99 | super().__init__(env) |
|
0 commit comments