yfzhoucs/TinyLanguageRobots
1
1"""2@author: Olivier Sigaud3A merge between two sources:4* Adaptation of the MountainCar Environment from the "FAReinforcement" library5of Jose Antonio Martin H. (version 1.0), adapted by 'Tom Schaul, tom@idsia.ch'6and then modified by Arnaud de Broissia7* the gym MountainCar environment8itself from9http://incompleteideas.net/sutton/MountainCar/MountainCar1.cp10permalink: https://perma.cc/6Z2N-PFWC11"""12# apple: https://unsplash.com/images/food/apple13# orange: https://unsplash.com/s/photos/orange14# wood: https://architextures.org/textures/category/wood15import math16from typing import Optional17 18import numpy as np19 20import gym21from gym import spaces22# from gym.envs.classic_control import utils23from gym.error import DependencyNotInstalled24# from gym.utils.renderer import Renderer25import pygame26import scipy27import yaml28from collections import OrderedDict29import copy30 31 32class TinyUR5Env(gym.Env):33 """34 ### Description35 The Mountain Car MDP is a deterministic MDP that consists of a car placed stochastically36 at the bottom of a sinusoidal valley, with the only possible actions being the accelerations37 that can be applied to the car in either direction. The goal of the MDP is to strategically38 accelerate the car to reach the goal state on top of the right hill. There are two versions39 of the mountain car domain in gym: one with discrete actions and one with continuous.40 This version is the one with continuous actions.41 This MDP first appeared in [Andrew Moore's PhD Thesis (1990)](https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-209.pdf)42 ```43 @TECHREPORT{Moore90efficientmemory-based,44 author = {Andrew William Moore},45 title = {Efficient Memory-based Learning for Robot Control},46 institution = {University of Cambridge},47 year = {1990}48 }49 ```50 ### Observation Space51 The observation is a `ndarray` with shape `(2,)` where the elements correspond to the following:52 | Num | Observation | Min | Max | Unit |53 |-----|--------------------------------------|------|-----|--------------|54 | 0 | position of the car along the x-axis | -Inf | Inf | position (m) |55 | 1 | velocity of the car | -Inf | Inf | position (m) |56 ### Action Space57 The action is a `ndarray` with shape `(1,)`, representing the directional force applied on the car.58 The action is clipped in the range `[-1,1]` and multiplied by a power of 0.0015.59 ### Transition Dynamics:60 Given an action, the mountain car follows the following transition dynamics:61 *velocity<sub>t+1</sub> = velocity<sub>t+1</sub> + force * self.power - 0.0025 * cos(3 * position<sub>t</sub>)*62 *position<sub>t+1</sub> = position<sub>t</sub> + velocity<sub>t+1</sub>*63 where force is the action clipped to the range `[-1,1]` and power is a constant 0.0015.64 The collisions at either end are inelastic with the velocity set to 0 upon collision with the wall.65 The position is clipped to the range [-1.2, 0.6] and velocity is clipped to the range [-0.07, 0.07].66 ### Reward67 A negative reward of *-0.1 * action<sup>2</sup>* is received at each timestep to penalise for68 taking actions of large magnitude. If the mountain car reaches the goal then a positive reward of +10069 is added to the negative reward for that timestep.70 ### Starting State71 The position of the car is assigned a uniform random value in `[-0.6 , -0.4]`.72 The starting velocity of the car is always assigned to 0.73 ### Episode End74 The episode ends if either of the following happens:75 1. Termination: The position of the car is greater than or equal to 0.45 (the goal position on top of the right hill)76 2. Truncation: The length of the episode is 999.77 ### Arguments78 ```79 gym.make('MountainCarContinuous-v0')80 ```81 ### Version History82 * v0: Initial versions release (1.0.0)83 """84 85 metadata = {86 "render_modes": ["human", "rgb_array", "single_rgb_array"],87 "render_fps": 30,88 }89 90 # def __init__(self, yaml_file='config.yaml', render_mode: Optional[str] = None, goal_velocity=0, initializer=None):91 def __init__(self, config, render_mode: Optional[str] = None, goal_velocity=0):92 93 # with open(yaml_file, "r") as stream:94 # try:95 # config = yaml.safe_load(stream)96 # # print(config, type(config))97 # except yaml.YAMLError as exc:98 # print(exc)99 # # exit()100 101 # if initializer is not None:102 # config = initializer.initialize103 self.config = config104 105 self.min_action = -np.pi * 2 - 0.01106 self.max_action = np.pi * 2 + 0.01107 self.min_position = -1.2108 self.max_position = 0.6109 self.max_speed = 0.07110 self.goal_position = (111 0.45 # was 0.5 in gym, 0.45 in Arnaud de Broissia's version112 )113 self.goal_velocity = goal_velocity114 self.power = 0.0015115 116 self.low_state = np.array(117 [self.min_position, -self.max_speed], dtype=np.float32118 )119 self.high_state = np.array(120 [self.max_position, self.max_speed], dtype=np.float32121 )122 123 self.render_mode = render_mode124 # self.renderer = Renderer(self.render_mode, self._render)125 126 self.scale = config['scale']127 self.screen_width = int(config['desk_width'] * self.scale)128 self.screen_height = int(config['desk_height'] * self.scale)129 self.robot_base_xy = [config['robot']['base_x'] * self.scale, config['robot']['base_y'] * self.scale]130 self.tool_center_point = config['robot']['tool_center_point_distance'] * self.scale131 self.tool_img_mid_point = config['robot']['tool_img_mid_point'] * self.scale132 self.screen = None133 self.clock = None134 self.isopen = True135 136 self.action_space = spaces.Box(137 low=self.min_action, high=self.max_action, shape=(4,), dtype=np.float32138 )139 self.observation_space = spaces.Box(140 low=self.min_action, high=self.max_action, shape=(4,), dtype=np.float32141 )142 143 if 'init_joints' not in config:144 self.robot_joints = np.zeros((4,), dtype=np.float32)145 self.robot_joints[0] = -1.57146 self.robot_joints[1] = 1.57147 self.robot_joints[2] = 0148 self.robot_joints_init = np.zeros((4,), dtype=np.float32)149 self.robot_joints_init[0] = -1.57150 self.robot_joints_init[1] = 1.57151 self.robot_joints_init[2] = 0152 else:153 self.robot_joints = np.zeros((4,), dtype=np.float32)154 for i in range(4):155 self.robot_joints[i] = config['init_joints'][i]156 self.robot_joints_init = copy.deepcopy(self.robot_joints) 157 self.lim_length = config['objects']['lim']['length'] * self.scale158 159 self.Kp = 15160 self.dt = 0.003161 162 self.manip_objs = OrderedDict()163 self.env_objs = {}164 for obj in config['objects']:165 # print(obj)166 # print(config['objects'][obj])167 obj_img = pygame.image.load(config['objects'][obj]['image'])168 169 if 'position' not in config['objects'][obj]:170 self.env_objs[obj] = {}171 self.env_objs[obj]['size_xy'] = [config['objects'][obj]['size']['x'] * self.scale, 172 config['objects'][obj]['size']['y'] * self.scale]173 174 self.env_objs[obj]['image'] = \175 pygame.transform.smoothscale(176 obj_img, 177 self.env_objs[obj]['size_xy'])178 179 if 'position' in config['objects'][obj]:180 self.manip_objs[obj] = {}181 self.manip_objs[obj]['size_xy'] = [config['objects'][obj]['size']['x'] * self.scale, 182 config['objects'][obj]['size']['y'] * self.scale]183 self.manip_objs[obj]['pos_xy'] = [config['objects'][obj]['position']['x'] * self.scale, 184 config['objects'][obj]['position']['y'] * self.scale]185 self.manip_objs[obj]['pos_z'] = config['objects'][obj]['position']['z'] * self.scale186 self.manip_objs[obj]['size_z'] = config['objects'][obj]['size']['z'] * self.scale187 self.manip_objs[obj]['orientation'] = 0.188 self.manip_objs[obj]['lru_score'] = 0189 190 self.manip_objs[obj]['image'] = \191 pygame.transform.smoothscale(192 obj_img, 193 self.manip_objs[obj]['size_xy'])194 # exit()195 196 # print(self.manip_objs)197 self.eef_z = 120 * self.scale198 self.grab = None199 self.grab_position = None200 self.grab_position_z = None201 self.grab_orientation = None202 self.highest_lru_score = 0203 204 205 def _eef_(self):206 207 start_x = 0208 start_y = 0209 end_x = self.robot_base_xy[0]210 end_y = self.robot_base_xy[1]211 angle = 0212 for i in range(self.robot_joints.shape[0] - 1):213 if i < 2:214 start_x = end_x215 start_y = end_y216 angle = angle + self.robot_joints[i]217 end_x = start_x + np.sin(angle) * self.lim_length218 end_y = start_y + np.cos(angle) * self.lim_length219 # mid_x = (start_x + end_x) / 2220 # mid_y = (start_y + end_y) / 2221 222 elif i == 2:223 start_x = end_x224 start_y = end_y225 angle = angle + self.robot_joints[i]226 end_x = start_x + np.sin(angle) * self.tool_center_point227 end_y = start_y + np.cos(angle) * self.tool_center_point228 # mid_x = (start_x + end_x) / 2229 # mid_y = (start_y + end_y) / 2230 return np.array([end_x, end_y])231 232 233 def _eef_orientation_(self):234 # print('joints0', self.robot_joints[0], self.robot_joints[1], self.robot_joints[2])235 # print('joints1', float(self.robot_joints[0]), float(self.robot_joints[1]), float(self.robot_joints[2]))236 return float(self.robot_joints[0]) + float(self.robot_joints[1]) + float(self.robot_joints[2])237 # return float(self.robot_joints[0] + self.robot_joints[1] + self.robot_joints[2])238 239 240 def _l2_(self, eef, position):241 return ((eef[0] - position[0]) ** 2 + (eef[1] - position[1]) ** 2) ** (1/2)242 243 244 def _grab_(self, position, eef):245 grab = (self._l2_(eef, position) < 50 * self.scale)246 # print(self._l2_(eef, position))247 return grab248 249 250 def _grab_z_(self, env_obj, eef_z):251 lower_bound = env_obj['pos_z']252 upper_bound = env_obj['pos_z'] + env_obj['size_z']253 # print(f'bounds: {lower_bound}, {upper_bound}')254 if eef_z >= lower_bound and eef_z <= upper_bound:255 return True256 else:257 return False258 259 260 def _gripper_closed_(self):261 if self.robot_joints[-1] >= 0:262 return True263 else:264 return False265 266 267 def _get_serialized_objs_(self):268 objs = OrderedDict()269 keys = [270 'size_xy',271 'pos_xy',272 'pos_z',273 'size_z',274 'orientation',275 'lru_score',276 ]277 for obj in self.manip_objs:278 objs[obj] = {}279 for key in keys:280 objs[obj][key] = self.manip_objs[obj][key]281 return objs282 283 def _max_speed_(self, disp, lim):284 if disp > lim:285 return lim286 if disp < -lim:287 return -lim288 return disp289 290 def step(self, action: np.ndarray, eef_z=None):291 # print([self.manip_objs[env_obj]['lru_score'] for env_obj in self.manip_objs if 'pos_xy' in self.manip_objs[env_obj]])292 # print(action, self.robot_joints)293 # Convert a possible numpy bool to a Python bool.294 terminated = False295 reward = 0296 297 # action is target angles of the joints298 assert action.shape[0] == self.robot_joints.shape[0]299 for i in range(action.shape[0]):300 # print('before change', self.robot_joints[i])301 # self.robot_joints[i] = self.robot_joints[i] + self.Kp * self._ang_diff(action[i], self.robot_joints[i]) * self.dt302 # self.robot_joints[i] = self.robot_joints[i] + self._max_speed_(303 # self._ang_diff(action[i], self.robot_joints[i]), self.Kp * self.dt)304 # print('after change', self.robot_joints[i])305 self.robot_joints[i] = self.robot_joints[i] + self.Kp * 2 * self._ang_diff(action[i], self.robot_joints[i]) * self.dt306 307 308 eef = self._eef_()309 if eef_z is not None:310 self.eef_z = eef_z * self.scale311 # print(f'eef_z: {self.eef_z}')312 313 # print('grab', self.grab)314 if self.grab is not None:315 assert self.grab_orientation is not None316 self.manip_objs[self.grab]['pos_xy'] = eef + self.grab_position317 self.manip_objs[self.grab]['pos_z'] = self.eef_z + self.grab_position_z318 # print('grab orientation', self.grab_orientation)319 # print('eef orientation', self._eef_orientation_())320 self.manip_objs[self.grab]['orientation'] = self._eef_orientation_() + self.grab_orientation321 # print('orientation', self.manip_objs[self.grab]['orientation'])322 323 if self.manip_objs[self.grab]['pos_z'] < 0:324 self.manip_objs[self.grab]['pos_z'] = 0325 self.grab_position_z = self.manip_objs[self.grab]['pos_z'] - self.eef_z326 # print(self.grab_position, eef, self.positions[1], 1)327 328 # self.grab = None329 # self.grab_position = None330 if self._gripper_closed_():331 if self.grab is None:332 for obj in self.manip_objs:333 if 'pos_xy' not in self.manip_objs[obj]:334 continue335 if self._grab_(self.manip_objs[obj]['pos_xy'], eef) and self._grab_z_(self.manip_objs[obj], self.eef_z):336 self.grab = obj337 self.grab_position = self.manip_objs[obj]['pos_xy'] - eef338 self.grab_position_z = self.manip_objs[self.grab]['pos_z'] - self.eef_z339 assert self.manip_objs[self.grab]['orientation'] is not None340 self.grab_orientation = self.manip_objs[self.grab]['orientation'] - self._eef_orientation_()341 self.highest_lru_score += 1342 self.manip_objs[obj]['lru_score'] = self.highest_lru_score343 self.manip_objs.move_to_end(obj, last=False)344 break345 else:346 self.grab = None347 self.grab_position = None348 self.grab_position_z = None349 self.grab_orientation = None350 # print(self.grab_position, eef, self.positions[1], 2)351 352 353 # self.renderer.render_step()354 355 state = {356 'joints': copy.deepcopy(self.robot_joints),357 'eef': copy.deepcopy(self._eef_()),358 'eef_z': copy.deepcopy(self.eef_z),359 'eef_orientation': copy.deepcopy(self._eef_orientation_()),360 'positions': copy.deepcopy(self._get_serialized_objs_()),361 'grabbed_object': copy.deepcopy(self.grab),362 'grab_position': copy.deepcopy(self.grab_position),363 'grab_position_z': copy.deepcopy(self.grab_position_z),364 'grab_orientation': copy.deepcopy(self.grab_orientation),365 'scale': copy.deepcopy(self.scale),366 }367 368 return state, reward, terminated, {}369 370 def reset(371 self,372 *,373 seed: Optional[int] = None,374 return_info: bool = False,375 options: Optional[dict] = None376 ):377 super().reset(seed=seed)378 # Note that if you use custom reset bounds, it may lead to out-of-bound379 # state/observations.380 # low, high = utils.maybe_parse_reset_bounds(options, -0.6, -0.4)381 # self.state = np.array([self.np_random.uniform(low=low, high=high), 0])382 self.state = np.array([self.np_random.uniform(low=-0.6, high=-0.4), 0])383 # self.renderer.reset()384 # self.renderer.render_step()385 if not return_info:386 return np.array(self.state, dtype=np.float32)387 else:388 return np.array(self.state, dtype=np.float32), {}389 390 def _height(self, xs):391 return np.sin(3 * xs) * 0.45 + 0.55392 393 394 def _ang_diff(self, theta1, theta2):395 # Returns the difference between two angles in the range -pi to +pi396 # print('angle diff', (theta1 - theta2 + np.pi) % (2 * np.pi) - np.pi)397 # print(f'theta1 {theta1} theta2 {theta2}')398 return (theta1 - theta2 + np.pi) % (2 * np.pi) - np.pi399 400 def render(self, mode="human"):401 # if self.render_mode is not None:402 # return self.renderer.get_renders()403 # else:404 # return self._render(mode)405 return self._render(mode)406 407 408 def _blitRotate(self, surf, image, origin, pivot, angle):409 image_rect = image.get_rect(topleft = (origin[0] - pivot[0], origin[1]-pivot[1]))410 offset_center_to_pivot = pygame.math.Vector2(origin) - image_rect.center411 rotated_offset = offset_center_to_pivot.rotate(-angle)412 rotated_image_center = (origin[0] - rotated_offset.x, origin[1] - rotated_offset.y)413 rotated_image = pygame.transform.rotate(image, angle)414 rotated_image_rect = rotated_image.get_rect(center = rotated_image_center)415 surf.blit(rotated_image, rotated_image_rect)416 417 418 def get_pos_xy(self, manip_obj):419 return self.manip_objs[manip_obj]['pos_xy']420 421 422 def get_pos_orientation(self, manip_obj):423 return self.manip_objs[manip_obj]['orientation']424 425 426 def ik(self, xyo):427 428 def x_constraint(q, xyo):429 """Returns the corresponding hand xy coordinates for430 a given set of joint angle values [shoulder, elbow, wrist],431 and the above defined arm segment lengths, L432 q : np.array433 the list of current joint angles434 xy : np.array435 current xy position (not used)436 returns : np.array437 the difference between current and desired x position438 """439 xy = xyo[:2]440 xy = [self.scale * x for x in xy]441 return self.lim_length * np.sin(q[0]) + self.lim_length * np.sin(q[0] + q[1]) + self.tool_center_point * np.sin(q[0] + q[1] + q[2]) - xy[0]442 443 def y_constraint(q, xyo):444 """Returns the corresponding hand xy coordinates for445 a given set of joint angle values [shoulder, elbow, wrist],446 and the above defined arm segment lengths, L447 q : np.array448 the list of current joint angles449 xy : np.array450 current xy position (not used)451 returns : np.array452 the difference between current and desired y position453 """454 xy = xyo[:2]455 xy = [self.scale * x for x in xy]456 return self.lim_length * np.cos(q[0]) + self.lim_length * np.cos(q[0] + q[1]) + self.tool_center_point * np.cos(q[0] + q[1] + q[2]) - xy[1]457 458 def sin_o_constraint(q, xyo):459 """Returns the corresponding hand xy coordinates for460 a given set of joint angle values [shoulder, elbow, wrist],461 and the above defined arm segment lengths, L462 q : np.array463 the list of current joint angles464 xy : np.array465 current xy position (not used)466 returns : np.array467 the difference between current and desired y position468 """469 470 o = xyo[-1]471 return (np.sin(q[0] + q[1] + q[2]) - np.sin(o)) ** 2472 473 def cos_o_constraint(q, xyo):474 """Returns the corresponding hand xy coordinates for475 a given set of joint angle values [shoulder, elbow, wrist],476 and the above defined arm segment lengths, L477 q : np.array478 the list of current joint angles479 xy : np.array480 current xy position (not used)481 returns : np.array482 the difference between current and desired y position483 """484 485 o = xyo[-1]486 return (np.cos(q[0] + q[1] + q[2]) - np.cos(o)) ** 2 + (np.sin(q[0] + q[1] + q[2]) - np.sin(o)) ** 2487 488 def distance_to_default(q, *args):489 """Objective function to minimize490 Calculates the euclidean distance through joint space to the491 default arm configuration. The weight list allows the penalty of492 each joint being away from the resting position to be scaled493 differently, such that the arm tries to stay closer to resting494 state more for higher weighted joints than those with a lower495 weight.496 q : np.array497 the list of current joint angles498 returns : scalar499 euclidean distance to the default arm position500 """501 # weights found with trial and error,502 # get some wrist bend, but not much503 weight = [1, 1, 0.5]504 try:505 action = np.sqrt(np.sum([(qi - q0i)**2 * wi506 for qi, q0i, wi in zip(q, self.robot_joints_init.tolist()[:-1], weight)]))507 except Exception:508 print(Exception)509 return action510 511 if len(xyo) == 3:512 ik_result = scipy.optimize.fmin_slsqp(513 func=distance_to_default,514 x0=self.robot_joints,515 eqcons=[x_constraint,516 y_constraint,517 # sin_o_constraint,518 cos_o_constraint],519 # uncomment to add in min / max angles for the joints520 # ieqcons=[joint_limits_upper_constraint,521 # joint_limits_lower_constraint],522 args=(xyo,),523 iprint=0) # iprint=0 suppresses output524 elif len(xyo) == 2:525 ik_result = scipy.optimize.fmin_slsqp(526 func=distance_to_default,527 x0=self.robot_joints,528 eqcons=[x_constraint,529 y_constraint,530 # sin_o_constraint,531 ],532 # uncomment to add in min / max angles for the joints533 # ieqcons=[joint_limits_upper_constraint,534 # joint_limits_lower_constraint],535 args=(xyo,),536 iprint=0) # iprint=0 suppresses output537 return ik_result538 539 def _calculate_img_starting_pos(self, img_pos, img_size):540 x = img_pos[0] - img_size[0] / 2541 y = img_pos[1] - img_size[1] / 2542 return [x, y]543 544 def _render(self, mode="human"):545 assert mode in self.metadata["render_modes"]546 547 try:548 import pygame549 from pygame import gfxdraw550 except ImportError:551 raise DependencyNotInstalled(552 "pygame is not installed, run `pip install gym[classic_control]`"553 )554 555 if self.screen is None:556 pygame.init()557 if mode == "human":558 pygame.display.init()559 self.screen = pygame.display.set_mode(560 (self.screen_width, self.screen_height)561 )562 else: # mode in {"rgb_array", "single_rgb_array"}563 self.screen = pygame.Surface((self.screen_width, self.screen_height))564 if self.clock is None:565 self.clock = pygame.time.Clock()566 567 # world_width = 200568 # scale = self.screen_width / world_width569 570 self.surf = pygame.Surface((self.screen_width, self.screen_height))571 self.surf.fill((255, 255, 255))572 573 574 self.surf.blit(self.env_objs['wood']['image'], (0, 0))575 for obj in list(self.manip_objs.keys())[::-1]:576 if 'pos_xy' in self.manip_objs[obj]:577 578 try:579 image_transformed = pygame.transform.rotate(580 self.manip_objs[obj]['image'], np.rad2deg(self.manip_objs[obj]['orientation']))581 except Exception as e:582 print(e)583 print(self.manip_objs[obj]['orientation'], np.rad2deg(self.manip_objs[obj]['orientation']))584 # print(obj, self.manip_objs[obj]['orientation'])585 new_rect = image_transformed.get_rect()586 # self.surf.blit(image_lim_transformed, (mid_x - new_rect[2] / 2, mid_y - new_rect[3] / 2))587 588 589 self.surf.blit(image_transformed, self._calculate_img_starting_pos(590 self.manip_objs[obj]['pos_xy'],591 [new_rect[2], new_rect[3]]592 ))593 # self.surf.blit(self.image_apple, self.positions[0] - self.size[0] / 2)594 # self.surf.blit(self.image_orange, self.positions[1] - self.size[1] / 2)595 # self.surf.blit(self.image_banana, self.positions[2] - self.size[2] / 2)596 597 start_x = 0598 start_y = 0599 end_x = self.robot_base_xy[0]600 end_y = self.robot_base_xy[1]601 angle = 0602 for i in range(self.robot_joints.shape[0] - 1):603 if i < 2:604 start_x = end_x605 start_y = end_y606 angle = angle + self.robot_joints[i]607 end_x = start_x + np.sin(angle) * self.lim_length608 end_y = start_y + np.cos(angle) * self.lim_length609 mid_x = (start_x + end_x) / 2610 mid_y = (start_y + end_y) / 2611 612 image_lim_transformed = pygame.transform.rotate(self.env_objs['lim']['image'], np.rad2deg(angle))613 new_rect = image_lim_transformed.get_rect()614 self.surf.blit(image_lim_transformed, (mid_x - new_rect[2] / 2, mid_y - new_rect[3] / 2))615 elif i == 2:616 start_x = end_x617 start_y = end_y618 angle = angle + self.robot_joints[i]619 620 # print('gripper angle:', self.robot_joints[-1])621 if self._gripper_closed_():622 mid_x = start_x + np.sin(angle) * (self.env_objs['gripper_closed']['size_xy'][1] / 2 + 38 * self.scale)623 mid_y = start_y + np.cos(angle) * (self.env_objs['gripper_closed']['size_xy'][1] / 2 + 38 * self.scale)624 image_gripper_closed_transformed = pygame.transform.rotate(self.env_objs['gripper_closed']['image'], np.rad2deg(angle))625 new_rect = image_gripper_closed_transformed.get_rect()626 self.surf.blit(image_gripper_closed_transformed, (mid_x - new_rect[2] / 2, mid_y - new_rect[3] / 2))627 else:628 mid_x = start_x + np.sin(angle) * (self.env_objs['gripper_open']['size_xy'][1] / 2 + 38 * self.scale)629 mid_y = start_y + np.cos(angle) * (self.env_objs['gripper_open']['size_xy'][1] / 2 + 38 * self.scale)630 image_gripper_open_transformed = pygame.transform.rotate(self.env_objs['gripper_open']['image'], np.rad2deg(angle))631 new_rect = image_gripper_open_transformed.get_rect()632 self.surf.blit(image_gripper_open_transformed, (mid_x - new_rect[2] / 2, mid_y - new_rect[3] / 2))633 634 # self.surf = pygame.transform.flip(self.surf, False, True)635 self.screen.blit(self.surf, (0, 0))636 if mode == "human":637 pygame.event.pump()638 self.clock.tick(self.metadata["render_fps"])639 pygame.display.flip()640 641 elif mode in {"rgb_array", "single_rgb_array"}:642 return np.transpose(643 np.array(pygame.surfarray.pixels3d(self.screen)), axes=(1, 0, 2)644 )645 646 def close(self):647 if self.screen is not None:648 import pygame649 650 pygame.display.quit()651 pygame.quit()652 self.isopen = False653 654 def get_base_xy(self):655 return self.robot_base_xy656 657 def get_joint_angles(self):658 return self.robot_joints659 660 661if __name__ == '__main__':662 # env = TinyUR5Env(render_mode='rgb_array')663 env = TinyUR5Env(render_mode='human')664 665 observation, info = env.reset(seed=42, return_info=True)666 667 for i in range(1000):668 print(i)669 input()670 action = env.action_space.sample()671 observation, reward, done, info = env.step(action)672 img = env.render()673 # print(img[0].shape)674 675 if done:676 observation, info = env.reset(return_info=True)677 env.close()678 