Skip to content

Commit 75c8174

Browse files
committed
feat(hw): added UR5 python package
1 parent 8bc900a commit 75c8174

File tree

4 files changed

+188
-0
lines changed

4 files changed

+188
-0
lines changed

extensions/rcs_ur5e/pyproject.toml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[build-system]
2+
requires = ["setuptools"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "rcs_ur5e"
7+
version = "0.4.0"
8+
description="RCS UR5e module"
9+
dependencies = [
10+
"rcs==0.4.0",
11+
]
12+
readme = "README.md"
13+
maintainers = [
14+
{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" },
15+
]
16+
authors = [
17+
{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" },
18+
{ name = "Pierre Krack", email = "pierre.krack@utn.de" },
19+
]
20+
requires-python = ">=3.10"
21+
classifiers = [
22+
"Development Status :: 3 - Alpha",
23+
"License :: OSI Approved :: GNU Affero General Public License v3 (AGPLv3)",
24+
"Programming Language :: Python :: 3",
25+
]
26+

extensions/rcs_ur5e/src/rcs_ur5e/__init__.py

Whitespace-only changes.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import logging
2+
3+
import gymnasium as gym
4+
from rcs.camera.hw import HardwareCameraSet
5+
from rcs.envs.base import (
6+
CameraSetWrapper,
7+
ControlMode,
8+
GripperWrapper,
9+
RelativeActionSpace,
10+
RelativeTo,
11+
RobotEnv,
12+
)
13+
from rcs.envs.creators import RCSHardwareEnvCreator
14+
15+
from rcs_ur5e.src.rcs_ur5e.hw import RobtiQGripper, UR5e
16+
17+
logger = logging.getLogger(__name__)
18+
logger.setLevel(logging.INFO)
19+
20+
21+
class RCSUR5eEnvCreator(RCSHardwareEnvCreator):
22+
def __call__( # type: ignore
23+
self,
24+
ip: str,
25+
urdf_path: str,
26+
camera_set: HardwareCameraSet | None = None,
27+
max_relative_movement: float | tuple[float, float] | None = None,
28+
relative_to: RelativeTo = RelativeTo.LAST_STEP,
29+
) -> gym.Env:
30+
robot = UR5e(ip, urdf_path=urdf_path)
31+
env: gym.Env = RobotEnv(robot, ControlMode.JOINTS)
32+
33+
gripper = RobtiQGripper()
34+
env = GripperWrapper(env, gripper, binary=False)
35+
36+
if camera_set is not None:
37+
camera_set.start()
38+
camera_set.wait_for_frames()
39+
logger.info("CameraSet started")
40+
env = CameraSetWrapper(env, camera_set)
41+
42+
if max_relative_movement is not None:
43+
env = RelativeActionSpace(env, max_mov=max_relative_movement, relative_to=relative_to)
44+
45+
return env
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
from dataclasses import dataclass
2+
import typing
3+
4+
import numpy as np
5+
6+
from rcs import common
7+
8+
@dataclass(kw_only=True)
9+
class UR5eConfig(common.RobotConfig):
10+
some_custom_config: str = "default_value"
11+
def __post_init__(self):
12+
super().__init__()
13+
14+
15+
@dataclass(kw_only=True)
16+
class UR5eState(common.RobotState):
17+
some_custom_state: float = 0.0
18+
def __post_init__(self):
19+
super().__init__()
20+
21+
22+
class UR5e: #(common.Robot): # should inherit and implement common.Robot, but currently there is a bug that needs to be fixed
23+
def __init__(self, ip: str, urdf_path: str):
24+
self.ik = common.RL(urdf_path=urdf_path)
25+
self._config = UR5eConfig() # with default values
26+
self._config.robot_platform = common.RobotPlatform.HARDWARE
27+
self._config.robot_type = common.RobotType.SO101
28+
29+
# TODO initialize the robot with the ip
30+
31+
def get_cartesian_position(self) -> common.Pose:
32+
# TODO: remove code below and return the cartesian position from the robot
33+
return self.ik.forward(self.get_joint_position())
34+
35+
def get_ik(self) -> common.IK | None:
36+
return self.ik
37+
38+
def get_joint_position(self) -> np.ndarray[tuple[typing.Literal[6]], np.dtype[np.float64]]: # type: ignore
39+
# TODO: remove code below and return the joint position from the robot
40+
return np.zeros(6)
41+
42+
43+
def get_parameters(self) -> UR5eConfig:
44+
return self._config
45+
46+
def set_parameters(self, robot_cfg: UR5eConfig) -> None:
47+
self._config = robot_cfg
48+
49+
def get_state(self) -> UR5eState:
50+
return UR5eState
51+
52+
def move_home(self) -> None:
53+
# TODO: check that the q_home in include/rcs/Robot.h is correct
54+
home = typing.cast(
55+
np.ndarray[tuple[typing.Literal[6]], np.dtype[np.float64]],
56+
common.robots_meta_config(common.RobotType.SO101).q_home,
57+
)
58+
self.set_joint_position(home)
59+
60+
def reset(self) -> None:
61+
# TODO: any reset stuff
62+
pass
63+
64+
def set_cartesian_position(self, pose: common.Pose) -> None:
65+
# TODO: remove code below and use robots way to set cartesian position
66+
# or (configurable with the config) use impediance to move to the pose
67+
joints = self.ik.ik(pose, q0=self.get_joint_position())
68+
if joints is not None:
69+
self.set_joint_position(joints)
70+
71+
def set_joint_position(self, q: np.ndarray[tuple[typing.Literal[6]], np.dtype[np.float64]]) -> None: # type: ignore
72+
# TODO
73+
pass
74+
75+
76+
77+
class RobtiQGripper: # (common.Gripper):
78+
def __init__(self):
79+
# TODO: initialize the gripper
80+
pass
81+
82+
def get_normalized_width(self) -> float:
83+
# value between 0 and 1 (0 is closed)
84+
return 0
85+
86+
def grasp(self) -> None:
87+
"""
88+
Close the gripper to grasp an object.
89+
"""
90+
self.shut()
91+
92+
# def is_grasped(self) -> bool: ...
93+
94+
def open(self) -> None:
95+
"""
96+
Open the gripper to its maximum width.
97+
"""
98+
self.set_normalized_width(1.0)
99+
100+
def reset(self) -> None:
101+
# TODO: any reset stuff
102+
pass
103+
104+
def set_normalized_width(self, width: float, _: float = 0) -> None:
105+
"""
106+
Set the gripper width to a normalized value between 0 and 1.
107+
"""
108+
if not (0 <= width <= 1):
109+
msg = f"Width must be between 0 and 1, got {width}."
110+
raise ValueError(msg)
111+
# TODO: set gripper width
112+
113+
def shut(self) -> None:
114+
"""
115+
Close the gripper.
116+
"""
117+
self.set_normalized_width(0.0)

0 commit comments

Comments
 (0)