|
import pybullet |
|
from pybullet_utils.bullet_client import BulletClient |
|
import pybullet_data |
|
import threading |
|
from time import sleep |
|
import numpy as np |
|
import os |
|
from consts import BOUNDS, COLORS, PIXEL_SIZE, CORNER_POS |
|
from shapely.geometry import box |
|
|
|
|
|
|
|
class Robotiq2F85: |
|
"""Gripper handling for Robotiq 2F85.""" |
|
|
|
def __init__(self, robot, tool, p): |
|
self.robot = robot |
|
self.tool = tool |
|
self._p = p |
|
pos = [0.1339999999999999, -0.49199999999872496, 0.5] |
|
rot = self._p.getQuaternionFromEuler([np.pi, 0, np.pi]) |
|
urdf = 'robotiq_2f_85/robotiq_2f_85.urdf' |
|
self.body = self._p.loadURDF(urdf, pos, rot) |
|
self.n_joints = self._p.getNumJoints(self.body) |
|
self.activated = False |
|
|
|
|
|
self._p.createConstraint(self.robot, tool, self.body, 0, jointType=self._p.JOINT_FIXED, jointAxis=[0, 0, 0], parentFramePosition=[0, 0, 0], childFramePosition=[0, 0, -0.07], childFrameOrientation=self._p.getQuaternionFromEuler([0, 0, np.pi / 2])) |
|
|
|
|
|
for i in range(self._p.getNumJoints(self.body)): |
|
self._p.changeDynamics(self.body, i, lateralFriction=10.0, spinningFriction=1.0, rollingFriction=1.0, frictionAnchor=True) |
|
|
|
|
|
self.motor_joint = 1 |
|
self.constraints_thread = threading.Thread(target=self.step) |
|
self.constraints_thread.daemon = True |
|
self.constraints_thread.start() |
|
|
|
|
|
|
|
def step(self): |
|
while True: |
|
try: |
|
currj = [self._p.getJointState(self.body, i)[0] for i in range(self.n_joints)] |
|
indj = [6, 3, 8, 5, 10] |
|
targj = [currj[1], -currj[1], -currj[1], currj[1], currj[1]] |
|
self._p.setJointMotorControlArray(self.body, indj, self._p.POSITION_CONTROL, targj, positionGains=np.ones(5)) |
|
except: |
|
return |
|
sleep(0.001) |
|
|
|
|
|
def activate(self): |
|
self._p.setJointMotorControl2(self.body, self.motor_joint, self._p.VELOCITY_CONTROL, targetVelocity=1, force=10) |
|
self.activated = True |
|
|
|
|
|
def release(self): |
|
self._p.setJointMotorControl2(self.body, self.motor_joint, self._p.VELOCITY_CONTROL, targetVelocity=-1, force=10) |
|
self.activated = False |
|
|
|
|
|
|
|
|
|
def detect_contact(self): |
|
obj, _, ray_frac = self.check_proximity() |
|
if self.activated: |
|
empty = self.grasp_width() < 0.01 |
|
cbody = self.body if empty else obj |
|
if obj == self.body or obj == 0: |
|
return False |
|
return self.external_contact(cbody) |
|
|
|
|
|
|
|
|
|
def external_contact(self, body=None): |
|
if body is None: |
|
body = self.body |
|
pts = self._p.getContactPoints(bodyA=body) |
|
pts = [pt for pt in pts if pt[2] != self.body] |
|
return len(pts) > 0 |
|
|
|
def check_grasp(self): |
|
while self.moving(): |
|
sleep(0.001) |
|
success = self.grasp_width() > 0.01 |
|
return success |
|
|
|
def grasp_width(self): |
|
lpad = np.array(self._p.getLinkState(self.body, 4)[0]) |
|
rpad = np.array(self._p.getLinkState(self.body, 9)[0]) |
|
dist = np.linalg.norm(lpad - rpad) - 0.047813 |
|
return dist |
|
|
|
def check_proximity(self): |
|
ee_pos = np.array(self._p.getLinkState(self.robot, self.tool)[0]) |
|
tool_pos = np.array(self._p.getLinkState(self.body, 0)[0]) |
|
vec = (tool_pos - ee_pos) / np.linalg.norm((tool_pos - ee_pos)) |
|
ee_targ = ee_pos + vec |
|
ray_data = self._p.rayTest(ee_pos, ee_targ)[0] |
|
obj, link, ray_frac = ray_data[0], ray_data[1], ray_data[2] |
|
return obj, link, ray_frac |
|
|
|
|
|
|
|
class PickPlaceEnv(): |
|
|
|
def __init__(self, render=False, high_res=False, high_frame_rate=False): |
|
self.dt = 1/480 |
|
self.sim_step = 0 |
|
|
|
|
|
|
|
self._p = BulletClient(connection_mode=pybullet.DIRECT) |
|
self._p.configureDebugVisualizer(self._p.COV_ENABLE_GUI, 0) |
|
self._p.setPhysicsEngineParameter(enableFileCaching=0) |
|
assets_path = os.path.dirname(os.path.abspath("")) |
|
self._p.setAdditionalSearchPath(assets_path) |
|
self._p.setAdditionalSearchPath(pybullet_data.getDataPath()) |
|
self._p.setTimeStep(self.dt) |
|
|
|
self.home_joints = (np.pi / 2, -np.pi / 2, np.pi / 2, -np.pi / 2, 3 * np.pi / 2, 0) |
|
self.home_ee_euler = (np.pi, 0, np.pi) |
|
self.ee_link_id = 9 |
|
self.tip_link_id = 10 |
|
self.gripper = None |
|
|
|
self.render = render |
|
self.high_res = high_res |
|
self.high_frame_rate = high_frame_rate |
|
|
|
def reset(self, object_list): |
|
self._p.resetSimulation(self._p.RESET_USE_DEFORMABLE_WORLD) |
|
self._p.setGravity(0, 0, -9.8) |
|
self.cache_video = [] |
|
|
|
|
|
self._p.configureDebugVisualizer(self._p.COV_ENABLE_RENDERING, 0) |
|
|
|
|
|
self._p.loadURDF("plane.urdf", [0, 0, -0.001]) |
|
self.robot_id = self._p.loadURDF("ur5e/ur5e.urdf", [0, 0, 0], flags=self._p.URDF_USE_MATERIAL_COLORS_FROM_MTL) |
|
self.ghost_id = self._p.loadURDF("ur5e/ur5e.urdf", [0, 0, -10]) |
|
self.joint_ids = [self._p.getJointInfo(self.robot_id, i) for i in range(self._p.getNumJoints(self.robot_id))] |
|
self.joint_ids = [j[0] for j in self.joint_ids if j[2] == self._p.JOINT_REVOLUTE] |
|
|
|
|
|
for i in range(len(self.joint_ids)): |
|
self._p.resetJointState(self.robot_id, self.joint_ids[i], self.home_joints[i]) |
|
|
|
|
|
if self.gripper is not None: |
|
while self.gripper.constraints_thread.is_alive(): |
|
self.constraints_thread_active = False |
|
self.gripper = Robotiq2F85(self.robot_id, self.ee_link_id, self._p) |
|
self.gripper.release() |
|
|
|
|
|
plane_shape = self._p.createCollisionShape(self._p.GEOM_BOX, halfExtents=[0.3, 0.3, 0.001]) |
|
plane_visual = self._p.createVisualShape(self._p.GEOM_BOX, halfExtents=[0.3, 0.3, 0.001]) |
|
plane_id = self._p.createMultiBody(0, plane_shape, plane_visual, basePosition=[0, -0.5, 0]) |
|
self._p.changeVisualShape(plane_id, -1, rgbaColor=[0.2, 0.2, 0.2, 1.0]) |
|
|
|
|
|
self.object_list = object_list |
|
self.obj_name_to_id = {} |
|
obj_xyz = np.zeros((0, 3)) |
|
for obj_name in object_list: |
|
if ('block' in obj_name) or ('bowl' in obj_name): |
|
|
|
|
|
while True: |
|
rand_x = np.random.uniform(BOUNDS[0, 0] + 0.1, BOUNDS[0, 1] - 0.1) |
|
rand_y = np.random.uniform(BOUNDS[1, 0] + 0.1, BOUNDS[1, 1] - 0.1) |
|
rand_xyz = np.float32([rand_x, rand_y, 0.03]).reshape(1, 3) |
|
if len(obj_xyz) == 0: |
|
obj_xyz = np.concatenate((obj_xyz, rand_xyz), axis=0) |
|
break |
|
else: |
|
nn_dist = np.min(np.linalg.norm(obj_xyz - rand_xyz, axis=1)).squeeze() |
|
if nn_dist > 0.15: |
|
obj_xyz = np.concatenate((obj_xyz, rand_xyz), axis=0) |
|
break |
|
|
|
object_color = COLORS[obj_name.split(' ')[0]] |
|
object_type = obj_name.split(' ')[1] |
|
object_position = rand_xyz.squeeze() |
|
if object_type == 'block': |
|
object_shape = self._p.createCollisionShape(self._p.GEOM_BOX, halfExtents=[0.02, 0.02, 0.02]) |
|
object_visual = self._p.createVisualShape(self._p.GEOM_BOX, halfExtents=[0.02, 0.02, 0.02]) |
|
object_id = self._p.createMultiBody(0.01, object_shape, object_visual, basePosition=object_position) |
|
elif object_type == 'bowl': |
|
object_position[2] = 0 |
|
object_id = self._p.loadURDF("bowl/bowl.urdf", object_position, useFixedBase=1) |
|
self._p.changeVisualShape(object_id, -1, rgbaColor=object_color) |
|
self.obj_name_to_id[obj_name] = object_id |
|
|
|
|
|
self._p.configureDebugVisualizer(self._p.COV_ENABLE_RENDERING, 1) |
|
|
|
for _ in range(200): |
|
self._p.stepSimulation() |
|
|
|
|
|
self.init_pos = {name: self.get_obj_pos(name) for name in object_list} |
|
|
|
return self.get_observation() |
|
|
|
def servoj(self, joints): |
|
"""Move to target joint positions with position control.""" |
|
self._p.setJointMotorControlArray( |
|
bodyIndex=self.robot_id, |
|
jointIndices=self.joint_ids, |
|
controlMode=self._p.POSITION_CONTROL, |
|
targetPositions=joints, |
|
positionGains=[0.01]*6) |
|
|
|
def movep(self, position): |
|
"""Move to target end effector position.""" |
|
joints = self._p.calculateInverseKinematics( |
|
bodyUniqueId=self.robot_id, |
|
endEffectorLinkIndex=self.tip_link_id, |
|
targetPosition=position, |
|
targetOrientation=self._p.getQuaternionFromEuler(self.home_ee_euler), |
|
maxNumIterations=100) |
|
self.servoj(joints) |
|
|
|
def get_ee_pos(self): |
|
ee_xyz = np.float32(self._p.getLinkState(self.robot_id, self.tip_link_id)[0]) |
|
return ee_xyz |
|
|
|
def step(self, action=None): |
|
"""Do pick and place motion primitive.""" |
|
pick_pos, place_pos = action['pick'].copy(), action['place'].copy() |
|
|
|
|
|
hover_xyz = np.float32([pick_pos[0], pick_pos[1], 0.2]) |
|
if pick_pos.shape[-1] == 2: |
|
pick_xyz = np.append(pick_pos, 0.025) |
|
else: |
|
pick_xyz = pick_pos |
|
pick_xyz[2] = 0.025 |
|
if place_pos.shape[-1] == 2: |
|
place_xyz = np.append(place_pos, 0.15) |
|
else: |
|
place_xyz = place_pos |
|
place_xyz[2] = 0.15 |
|
|
|
|
|
ee_xyz = self.get_ee_pos() |
|
while np.linalg.norm(hover_xyz - ee_xyz) > 0.01: |
|
self.movep(hover_xyz) |
|
self.step_sim_and_render() |
|
ee_xyz = self.get_ee_pos() |
|
|
|
while np.linalg.norm(pick_xyz - ee_xyz) > 0.01: |
|
self.movep(pick_xyz) |
|
self.step_sim_and_render() |
|
ee_xyz = self.get_ee_pos() |
|
|
|
|
|
self.gripper.activate() |
|
for _ in range(240): |
|
self.step_sim_and_render() |
|
while np.linalg.norm(hover_xyz - ee_xyz) > 0.01: |
|
self.movep(hover_xyz) |
|
self.step_sim_and_render() |
|
ee_xyz = self.get_ee_pos() |
|
|
|
for _ in range(50): |
|
self.step_sim_and_render() |
|
|
|
|
|
while np.linalg.norm(place_xyz - ee_xyz) > 0.01: |
|
self.movep(place_xyz) |
|
self.step_sim_and_render() |
|
ee_xyz = self.get_ee_pos() |
|
|
|
|
|
while (not self.gripper.detect_contact()) and (place_xyz[2] > 0.03): |
|
place_xyz[2] -= 0.001 |
|
self.movep(place_xyz) |
|
for _ in range(3): |
|
self.step_sim_and_render() |
|
self.gripper.release() |
|
for _ in range(240): |
|
self.step_sim_and_render() |
|
place_xyz[2] = 0.2 |
|
ee_xyz = self.get_ee_pos() |
|
while np.linalg.norm(place_xyz - ee_xyz) > 0.01: |
|
self.movep(place_xyz) |
|
self.step_sim_and_render() |
|
ee_xyz = self.get_ee_pos() |
|
place_xyz = np.float32([0, -0.5, 0.2]) |
|
while np.linalg.norm(place_xyz - ee_xyz) > 0.01: |
|
self.movep(place_xyz) |
|
self.step_sim_and_render() |
|
ee_xyz = self.get_ee_pos() |
|
|
|
observation = self.get_observation() |
|
reward = self.get_reward() |
|
done = False |
|
info = {} |
|
return observation, reward, done, info |
|
|
|
def set_alpha_transparency(self, alpha: float) -> None: |
|
for id in range(20): |
|
visual_shape_data = self._p.getVisualShapeData(id) |
|
for i in range(len(visual_shape_data)): |
|
object_id, link_index, _, _, _, _, _, rgba_color = visual_shape_data[i] |
|
rgba_color = list(rgba_color[0:3]) + [alpha] |
|
self._p.changeVisualShape( |
|
self.robot_id, linkIndex=i, rgbaColor=rgba_color) |
|
self._p.changeVisualShape( |
|
self.gripper.body, linkIndex=i, rgbaColor=rgba_color) |
|
|
|
def step_sim_and_render(self): |
|
self._p.stepSimulation() |
|
self.sim_step += 1 |
|
|
|
interval = 40 if self.high_frame_rate else 60 |
|
|
|
if self.sim_step % interval == 0 and self.render: |
|
self.cache_video.append(self.get_camera_image()) |
|
|
|
def get_camera_image(self): |
|
if not self.high_res: |
|
image_size = (240, 240) |
|
intrinsics = (120., 0, 120., 0, 120., 120., 0, 0, 1) |
|
else: |
|
image_size=(360, 360) |
|
intrinsics=(180., 0, 180., 0, 180., 180., 0, 0, 1) |
|
color, _, _, _, _ = self.render_image(image_size, intrinsics) |
|
return color |
|
|
|
def get_reward(self): |
|
return None |
|
|
|
def get_observation(self): |
|
observation = {} |
|
|
|
|
|
color, depth, position, orientation, intrinsics = self.render_image() |
|
|
|
|
|
points = self.get_pointcloud(depth, intrinsics) |
|
position = np.float32(position).reshape(3, 1) |
|
rotation = self._p.getMatrixFromQuaternion(orientation) |
|
rotation = np.float32(rotation).reshape(3, 3) |
|
transform = np.eye(4) |
|
transform[:3, :] = np.hstack((rotation, position)) |
|
points = self.transform_pointcloud(points, transform) |
|
heightmap, colormap, xyzmap = self.get_heightmap(points, color, BOUNDS, PIXEL_SIZE) |
|
|
|
observation["image"] = colormap |
|
observation["xyzmap"] = xyzmap |
|
|
|
return observation |
|
|
|
def render_image(self, image_size=(720, 720), intrinsics=(360., 0, 360., 0, 360., 360., 0, 0, 1)): |
|
|
|
|
|
position = (0, -0.85, 0.4) |
|
orientation = (np.pi / 4 + np.pi / 48, np.pi, np.pi) |
|
orientation = self._p.getQuaternionFromEuler(orientation) |
|
zrange = (0.01, 10.) |
|
noise=True |
|
|
|
|
|
lookdir = np.float32([0, 0, 1]).reshape(3, 1) |
|
updir = np.float32([0, -1, 0]).reshape(3, 1) |
|
rotation = self._p.getMatrixFromQuaternion(orientation) |
|
rotm = np.float32(rotation).reshape(3, 3) |
|
lookdir = (rotm @ lookdir).reshape(-1) |
|
updir = (rotm @ updir).reshape(-1) |
|
lookat = position + lookdir |
|
focal_len = intrinsics[0] |
|
znear, zfar = (0.01, 10.) |
|
viewm = self._p.computeViewMatrix(position, lookat, updir) |
|
fovh = (image_size[0] / 2) / focal_len |
|
fovh = 180 * np.arctan(fovh) * 2 / np.pi |
|
|
|
|
|
aspect_ratio = image_size[1] / image_size[0] |
|
projm = self._p.computeProjectionMatrixFOV(fovh, aspect_ratio, znear, zfar) |
|
|
|
|
|
_, _, color, depth, segm = self._p.getCameraImage( |
|
width=image_size[1], |
|
height=image_size[0], |
|
viewMatrix=viewm, |
|
projectionMatrix=projm, |
|
shadow=1, |
|
flags=self._p.ER_SEGMENTATION_MASK_OBJECT_AND_LINKINDEX, |
|
renderer=self._p.ER_BULLET_HARDWARE_OPENGL) |
|
|
|
|
|
color_image_size = (image_size[0], image_size[1], 4) |
|
color = np.array(color, dtype=np.uint8).reshape(color_image_size) |
|
color = color[:, :, :3] |
|
if noise: |
|
color = np.int32(color) |
|
color += np.int32(np.random.normal(0, 3, color.shape)) |
|
color = np.uint8(np.clip(color, 0, 255)) |
|
|
|
|
|
depth_image_size = (image_size[0], image_size[1]) |
|
zbuffer = np.float32(depth).reshape(depth_image_size) |
|
depth = (zfar + znear - (2 * zbuffer - 1) * (zfar - znear)) |
|
depth = (2 * znear * zfar) / depth |
|
if noise: |
|
depth += np.random.normal(0, 0.003, depth.shape) |
|
|
|
intrinsics = np.float32(intrinsics).reshape(3, 3) |
|
return color, depth, position, orientation, intrinsics |
|
|
|
def get_pointcloud(self, depth, intrinsics): |
|
"""Get 3D pointcloud from perspective depth image. |
|
Args: |
|
depth: HxW float array of perspective depth in meters. |
|
intrinsics: 3x3 float array of camera intrinsics matrix. |
|
Returns: |
|
points: HxWx3 float array of 3D points in camera coordinates. |
|
""" |
|
height, width = depth.shape |
|
xlin = np.linspace(0, width - 1, width) |
|
ylin = np.linspace(0, height - 1, height) |
|
px, py = np.meshgrid(xlin, ylin) |
|
px = (px - intrinsics[0, 2]) * (depth / intrinsics[0, 0]) |
|
py = (py - intrinsics[1, 2]) * (depth / intrinsics[1, 1]) |
|
points = np.float32([px, py, depth]).transpose(1, 2, 0) |
|
return points |
|
|
|
def transform_pointcloud(self, points, transform): |
|
"""Apply rigid transformation to 3D pointcloud. |
|
Args: |
|
points: HxWx3 float array of 3D points in camera coordinates. |
|
transform: 4x4 float array representing a rigid transformation matrix. |
|
Returns: |
|
points: HxWx3 float array of transformed 3D points. |
|
""" |
|
padding = ((0, 0), (0, 0), (0, 1)) |
|
homogen_points = np.pad(points.copy(), padding, |
|
'constant', constant_values=1) |
|
for i in range(3): |
|
points[Ellipsis, i] = np.sum(transform[i, :] * homogen_points, axis=-1) |
|
return points |
|
|
|
def get_heightmap(self, points, colors, bounds, pixel_size): |
|
"""Get top-down (z-axis) orthographic heightmap image from 3D pointcloud. |
|
Args: |
|
points: HxWx3 float array of 3D points in world coordinates. |
|
colors: HxWx3 uint8 array of values in range 0-255 aligned with points. |
|
bounds: 3x2 float array of values (rows: X,Y,Z; columns: min,max) defining |
|
region in 3D space to generate heightmap in world coordinates. |
|
pixel_size: float defining size of each pixel in meters. |
|
Returns: |
|
heightmap: HxW float array of height (from lower z-bound) in meters. |
|
colormap: HxWx3 uint8 array of backprojected color aligned with heightmap. |
|
xyzmap: HxWx3 float array of XYZ points in world coordinates. |
|
""" |
|
width = int(np.round((bounds[0, 1] - bounds[0, 0]) / pixel_size)) |
|
height = int(np.round((bounds[1, 1] - bounds[1, 0]) / pixel_size)) |
|
heightmap = np.zeros((height, width), dtype=np.float32) |
|
colormap = np.zeros((height, width, colors.shape[-1]), dtype=np.uint8) |
|
xyzmap = np.zeros((height, width, 3), dtype=np.float32) |
|
|
|
|
|
ix = (points[Ellipsis, 0] >= bounds[0, 0]) & (points[Ellipsis, 0] < bounds[0, 1]) |
|
iy = (points[Ellipsis, 1] >= bounds[1, 0]) & (points[Ellipsis, 1] < bounds[1, 1]) |
|
iz = (points[Ellipsis, 2] >= bounds[2, 0]) & (points[Ellipsis, 2] < bounds[2, 1]) |
|
valid = ix & iy & iz |
|
points = points[valid] |
|
colors = colors[valid] |
|
|
|
|
|
|
|
iz = np.argsort(points[:, -1]) |
|
points, colors = points[iz], colors[iz] |
|
px = np.int32(np.floor((points[:, 0] - bounds[0, 0]) / pixel_size)) |
|
py = np.int32(np.floor((points[:, 1] - bounds[1, 0]) / pixel_size)) |
|
px = np.clip(px, 0, width - 1) |
|
py = np.clip(py, 0, height - 1) |
|
heightmap[py, px] = points[:, 2] - bounds[2, 0] |
|
for c in range(colors.shape[-1]): |
|
colormap[py, px, c] = colors[:, c] |
|
xyzmap[py, px, c] = points[:, c] |
|
colormap = colormap[::-1, :, :] |
|
xv, yv = np.meshgrid(np.linspace(BOUNDS[0, 0], BOUNDS[0, 1], height), |
|
np.linspace(BOUNDS[1, 0], BOUNDS[1, 1], width)) |
|
xyzmap[:, :, 0] = xv |
|
xyzmap[:, :, 1] = yv |
|
xyzmap = xyzmap[::-1, :, :] |
|
heightmap = heightmap[::-1, :] |
|
return heightmap, colormap, xyzmap |
|
|
|
def on_top_of(self, obj_a, obj_b): |
|
""" |
|
check if obj_a is on top of obj_b |
|
condition 1: l2 distance on xy plane is less than a threshold |
|
condition 2: obj_a is higher than obj_b |
|
""" |
|
obj_a_pos = self.get_obj_pos(obj_a) |
|
obj_b_pos = self.get_obj_pos(obj_b) |
|
xy_dist = np.linalg.norm(obj_a_pos[:2] - obj_b_pos[:2]) |
|
if obj_b in CORNER_POS: |
|
is_near = xy_dist < 0.06 |
|
return is_near |
|
elif 'bowl' in obj_b: |
|
is_near = xy_dist < 0.06 |
|
is_higher = obj_a_pos[2] > obj_b_pos[2] |
|
return is_near and is_higher |
|
else: |
|
is_near = xy_dist < 0.04 |
|
is_higher = obj_a_pos[2] > obj_b_pos[2] |
|
return is_near and is_higher |
|
|
|
def get_obj_id(self, obj_name): |
|
try: |
|
if obj_name in self.obj_name_to_id: |
|
obj_id = self.obj_name_to_id[obj_name] |
|
else: |
|
obj_name = obj_name.replace('circle', 'bowl').replace('square', 'block').replace('small', '').strip() |
|
obj_id = self.obj_name_to_id[obj_name] |
|
return obj_id |
|
except: |
|
raise Exception('Object name "{}" not found'.format(obj_name)) |
|
|
|
def get_obj_pos(self, obj_name): |
|
obj_name = obj_name.replace('the', '').replace('_', ' ').strip() |
|
if obj_name in CORNER_POS: |
|
position = np.float32(np.array(CORNER_POS[obj_name])) |
|
else: |
|
pick_id = self.get_obj_id(obj_name) |
|
pose = self._p.getBasePositionAndOrientation(pick_id) |
|
position = np.float32(pose[0]) |
|
return position |
|
|
|
def get_bounding_box(self, obj_name): |
|
obj_id = self.get_obj_id(obj_name) |
|
return self._p.getAABB(obj_id) |
|
|
|
|
|
class LMP_wrapper(): |
|
|
|
def __init__(self, env, cfg, render=False): |
|
self.env = env |
|
self._cfg = cfg |
|
self.object_names = list(self._cfg['env']['init_objs']) |
|
|
|
self._min_xy = np.array(self._cfg['env']['coords']['bottom_left']) |
|
self._max_xy = np.array(self._cfg['env']['coords']['top_right']) |
|
self._range_xy = self._max_xy - self._min_xy |
|
|
|
self._table_z = self._cfg['env']['coords']['table_z'] |
|
self.render = render |
|
|
|
def is_obj_visible(self, obj_name): |
|
return obj_name in self.object_names |
|
|
|
def get_obj_names(self): |
|
return self.object_names[::] |
|
|
|
def denormalize_xy(self, pos_normalized): |
|
return pos_normalized * self._range_xy + self._min_xy |
|
|
|
def get_corner_positions(self): |
|
unit_square = box(0, 0, 1, 1) |
|
normalized_corners = np.array(list(unit_square.exterior.coords))[:4] |
|
corners = np.array(([self.denormalize_xy(corner) for corner in normalized_corners])) |
|
return corners |
|
|
|
def get_side_positions(self): |
|
side_xs = np.array([0, 0.5, 0.5, 1]) |
|
side_ys = np.array([0.5, 0, 1, 0.5]) |
|
normalized_side_positions = np.c_[side_xs, side_ys] |
|
side_positions = np.array(([self.denormalize_xy(corner) for corner in normalized_side_positions])) |
|
return side_positions |
|
|
|
def get_obj_pos(self, obj_name): |
|
|
|
return self.env.get_obj_pos(obj_name)[:2] |
|
|
|
def get_obj_position_np(self, obj_name): |
|
return self.get_pos(obj_name) |
|
|
|
def get_bbox(self, obj_name): |
|
|
|
|
|
bbox = self.env.get_bounding_box(obj_name) |
|
return bbox |
|
|
|
def get_color(self, obj_name): |
|
for color, rgb in COLORS.items(): |
|
if color in obj_name: |
|
return rgb |
|
|
|
def pick_place(self, pick_pos, place_pos): |
|
pick_pos_xyz = np.r_[pick_pos, [self._table_z]] |
|
place_pos_xyz = np.r_[place_pos, [self._table_z]] |
|
pass |
|
|
|
def put_first_on_second(self, arg1, arg2): |
|
|
|
|
|
pick_pos = self.get_obj_pos(arg1) if isinstance(arg1, str) else arg1 |
|
place_pos = self.get_obj_pos(arg2) if isinstance(arg2, str) else arg2 |
|
self.env.step(action={'pick': pick_pos, 'place': place_pos}) |
|
|
|
def get_robot_pos(self): |
|
|
|
return self.env.get_ee_pos() |
|
|
|
def goto_pos(self, position_xy): |
|
|
|
ee_xyz = self.env.get_ee_pos() |
|
position_xyz = np.concatenate([position_xy, ee_xyz[-1]]) |
|
while np.linalg.norm(position_xyz - ee_xyz) > 0.01: |
|
self.env.movep(position_xyz) |
|
self.env.step_sim_and_render() |
|
ee_xyz = self.env.get_ee_pos() |
|
|
|
def follow_traj(self, traj): |
|
for pos in traj: |
|
self.goto_pos(pos) |
|
|
|
def get_corner_positions(self): |
|
normalized_corners = np.array([ |
|
[0, 1], |
|
[1, 1], |
|
[0, 0], |
|
[1, 0] |
|
]) |
|
return np.array(([self.denormalize_xy(corner) for corner in normalized_corners])) |
|
|
|
def get_side_positions(self): |
|
normalized_sides = np.array([ |
|
[0.5, 1], |
|
[1, 0.5], |
|
[0.5, 0], |
|
[0, 0.5] |
|
]) |
|
return np.array(([self.denormalize_xy(side) for side in normalized_sides])) |
|
|
|
def get_corner_name(self, pos): |
|
corner_positions = self.get_corner_positions() |
|
corner_idx = np.argmin(np.linalg.norm(corner_positions - pos, axis=1)) |
|
return ['top left corner', 'top right corner', 'bottom left corner', 'botom right corner'][corner_idx] |
|
|
|
def get_side_name(self, pos): |
|
side_positions = self.get_side_positions() |
|
side_idx = np.argmin(np.linalg.norm(side_positions - pos, axis=1)) |
|
return ['top side', 'right side', 'bottom side', 'left side'][side_idx] |