Skip to content

Commit 1550d5e

Browse files
authored
Merge pull request #140 from utn-mi/juelg/refactor-ik
refactor(ik): moved rl ik code into IK class in common module
2 parents 65dfbb6 + fe986ad commit 1550d5e

21 files changed

Lines changed: 248 additions & 239 deletions

File tree

python/rcsss/_core/common.pyi

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ __all__ = [
1414
"GConfig",
1515
"GState",
1616
"Gripper",
17+
"IK",
1718
"IdentityRotMatrix",
1819
"IdentityRotQuartVec",
1920
"IdentityTranslation",
@@ -43,6 +44,12 @@ class Gripper:
4344
def set_normalized_width(self, width: float, force: float = 0) -> None: ...
4445
def shut(self) -> None: ...
4546

47+
class IK:
48+
def __init__(self, urdf_path: str, max_duration_ms: int = 300) -> None: ...
49+
def ik(
50+
self, pose: Pose, q0: numpy.ndarray[typing.Literal[7], numpy.dtype[numpy.float64]], tcp_offset: Pose = ...
51+
) -> numpy.ndarray[typing.Literal[7], numpy.dtype[numpy.float64]] | None: ...
52+
4653
class NRobotsWithGripper:
4754
def __init__(self, robots_with_gripper: list[RobotWithGripper]) -> None: ...
4855
def get_cartesian_position(self, idxs: list[int]) -> list[Pose]: ...
@@ -143,6 +150,7 @@ class RState:
143150
class Robot:
144151
def get_base_pose_in_world_coordinates(self) -> Pose: ...
145152
def get_cartesian_position(self) -> Pose: ...
153+
def get_ik(self) -> IK | None: ...
146154
def get_joint_position(self) -> numpy.ndarray[typing.Literal[7], numpy.dtype[numpy.float64]]: ...
147155
def get_parameters(self) -> RConfig: ...
148156
def get_state(self) -> RState: ...

python/rcsss/_core/hw/__init__.pyi

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,15 @@ class FHState(rcsss._core.common.GState):
4747
def width(self) -> float: ...
4848

4949
class FR3(rcsss._core.common.Robot):
50-
def __init__(self, ip: str, filename: str | None = None) -> None: ...
50+
def __init__(self, ip: str, ik: rcsss._core.common.IK | None = None) -> None: ...
5151
def automatic_error_recovery(self) -> None: ...
5252
def double_tap_robot_to_continue(self) -> None: ...
5353
def get_parameters(self) -> FR3Config: ...
5454
def get_state(self) -> FR3State: ...
55-
def set_cartesian_position_internal(self, pose: rcsss._core.common.Pose) -> None: ...
56-
def set_cartesian_position_rl(
55+
def set_cartesian_position_ik(
5756
self, pose: rcsss._core.common.Pose, max_time: float, elbow: float | None, max_force: float | None = 5
5857
) -> None: ...
58+
def set_cartesian_position_internal(self, pose: rcsss._core.common.Pose) -> None: ...
5959
def set_default_robot_behavior(self) -> None: ...
6060
def set_guiding_mode(self, enabled: bool) -> None: ...
6161
def set_parameters(self, cfg: FR3Config) -> bool: ...

python/rcsss/_core/sim.pyi

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,12 @@ class FHState(rcsss._core.common.GState):
8686
def max_unnormalized_width(self) -> float: ...
8787

8888
class FR3(rcsss._core.common.Robot):
89-
def __init__(self, sim: Sim, id: str, rlmdl: str) -> None: ...
89+
def __init__(self, sim: Sim, id: str, ik: rcsss._core.common.IK) -> None: ...
9090
def get_parameters(self) -> FR3Config: ...
9191
def get_state(self) -> FR3State: ...
9292
def set_parameters(self, cfg: FR3Config) -> bool: ...
9393

9494
class FR3Config(rcsss._core.common.RConfig):
95-
ik_duration_in_milliseconds: int
9695
joint_rotational_tolerance: float
9796
realtime: bool
9897
seconds_between_callbacks: float

python/rcsss/control/record.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from typing import cast
55

66
import numpy as np
7-
from rcsss import hw
7+
from rcsss import common, hw
88

99
np.set_printoptions(precision=27)
1010

@@ -194,7 +194,8 @@ def __init__(
194194
poses: list[Pose] | None = None,
195195
urdf_path: str | None = None,
196196
):
197-
self.r: dict[str, hw.FR3] = {key: hw.FR3(ip, urdf_path) for key, ip in name2ip.items()}
197+
self.ik = common.IK(urdf_path) if urdf_path else None
198+
self.r: dict[str, hw.FR3] = {key: hw.FR3(ip, self.ik) for key, ip in name2ip.items()}
198199
# TODO: this config should be given to the constructor
199200
cfg = hw.FHConfig()
200201
cfg.epsilon_inner = 0.1

python/rcsss/control/vive.py

Lines changed: 41 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,28 @@
11
import logging
22
import threading
3+
import typing
34
from enum import IntFlag, auto
45
from socket import AF_INET, SOCK_DGRAM, socket
56
from struct import pack, unpack
67

7-
import gymnasium as gym
88
import numpy as np
9-
import rcsss
109
from rcsss._core.common import RPY, Pose
11-
from rcsss._core.sim import CameraType
12-
from rcsss.camera.sim import SimCameraConfig, SimCameraSet, SimCameraSetConfig
13-
from rcsss.config import read_config_yaml
14-
from rcsss.control.fr3_desk import FCI, Desk
1510
from rcsss.envs.base import (
16-
CameraSetWrapper,
1711
ControlMode,
18-
FR3Env,
1912
GripperDictType,
20-
GripperWrapper,
2113
LimitedTQuartRelDictType,
2214
RelativeActionSpace,
23-
RelativeTo,
15+
RobotInstance,
16+
)
17+
from rcsss.envs.factories import (
18+
default_fr3_hw_gripper_cfg,
19+
default_fr3_hw_robot_cfg,
20+
default_fr3_sim_gripper_cfg,
21+
default_fr3_sim_robot_cfg,
22+
default_mujoco_cameraset_cfg,
23+
fr3_hw_env,
24+
fr3_sim_env,
2425
)
25-
from rcsss.envs.hw import FR3HW
26-
from rcsss.envs.sim import CollisionGuard, FR3Sim
27-
from rcsss.sim import FR3, FR3Config, Sim
2826

2927
# import matplotlib.pyplot as plt
3028

@@ -34,16 +32,18 @@
3432
EGO_LOCK = False
3533
VIVE_HOST = "192.168.100.1"
3634
VIVE_PORT = 54321
37-
USE_REAL_ROBOT = True
3835
INCLUDE_ROTATION = True
3936
ROBOT_IP = "192.168.101.1"
37+
ROBOT_INSTANCE = RobotInstance.HARDWARE
4038

4139

4240
class Button(IntFlag):
4341
L_TRIGGER = auto()
4442
L_SQUEEZE = auto()
43+
LT_CLICK = auto()
4544
R_TRIGGER = auto()
4645
R_SQUEEZE = auto()
46+
RT_CLICK = auto()
4747

4848

4949
class UDPViveActionServer(threading.Thread):
@@ -200,91 +200,38 @@ def environment_step_loop(self):
200200
self._env.step(action)
201201

202202

203-
def hw():
204-
205-
cfg = read_config_yaml("config.yaml")
206-
d = Desk(ROBOT_IP, cfg.hw.username, cfg.hw.password)
207-
with FCI(d, unlock=False, lock_when_done=False):
208-
209-
robot = rcsss.hw.FR3(ROBOT_IP, str(rcsss.scenes["lab"].parent / "fr3.urdf"))
210-
rcfg = rcsss.hw.FR3Config()
211-
rcfg.tcp_offset = rcsss.common.Pose(rcsss.common.FrankaHandTCPOffset())
212-
rcfg.speed_factor = 0.2
213-
rcfg.controller = rcsss.hw.IKController.robotics_library
214-
robot.set_parameters(rcfg)
215-
216-
# env = FR3Env(robot, ControlMode.CARTESIAN_TQuart)
217-
env = FR3Env(robot, ControlMode.JOINTS)
218-
env_hw: gym.Env = FR3HW(env)
219-
gripper_cfg = rcsss.hw.FHConfig()
220-
gripper_cfg.epsilon_inner = gripper_cfg.epsilon_outer = 0.5
221-
gripper_cfg.speed = 0.1
222-
gripper_cfg.force = 30
223-
gripper = rcsss.hw.FrankaHand(ROBOT_IP, gripper_cfg)
224-
# gripper.homing()
225-
env_hw = GripperWrapper(env_hw, gripper, binary=True)
226-
227-
# TODO: camera
228-
env_hw = CollisionGuard.env_from_xml_paths(
229-
env_hw,
230-
str(rcsss.scenes["fr3_empty_world"]),
231-
str(rcsss.scenes["lab"].parent / "fr3.urdf"),
232-
gripper=True,
233-
check_home_collision=False,
234-
camera=True,
203+
def main():
204+
# if ROBOT_INSTANCE == RobotInstance.HARDWARE:
205+
# user, pw = load_creds_fr3_desk()
206+
# resource_manger = FCI(Desk(ROBOT_IP, user, pw), unlock=False, lock_when_done=False)
207+
# else:
208+
# resource_manger = DummyResourceManager()
209+
210+
# with resource_manger:
211+
212+
if ROBOT_INSTANCE == RobotInstance.HARDWARE:
213+
env_rel = fr3_hw_env(
214+
ip=ROBOT_IP,
215+
control_mode=ControlMode.CARTESIAN_TQuart,
216+
robot_cfg=default_fr3_hw_robot_cfg(),
217+
collision_guard=False,
218+
gripper_cfg=default_fr3_hw_gripper_cfg(),
219+
max_relative_movement=0.5,
220+
)
221+
else:
222+
env_rel = fr3_sim_env(
235223
control_mode=ControlMode.CARTESIAN_TQuart,
236-
tcp_offset=rcsss.common.Pose(rcsss.common.FrankaHandTCPOffset()),
224+
# control_mode=ControlMode.JOINTS,
225+
robot_cfg=default_fr3_sim_robot_cfg(),
226+
gripper_cfg=default_fr3_sim_gripper_cfg(),
227+
camera_set_cfg=default_mujoco_cameraset_cfg(),
228+
max_relative_movement=0.5,
237229
)
238230

239-
env_rel = RelativeActionSpace(env_hw, relative_to=RelativeTo.CONFIGURED_ORIGIN)
240-
env_rel.reset()
241-
with UDPViveActionServer(VIVE_HOST, VIVE_PORT, env_rel) as action_server:
242-
action_server.environment_step_loop()
243-
244-
245-
def sim():
246-
simulation = Sim(rcsss.scenes["fr3_empty_world"])
247-
robot = FR3(simulation, "0", str(rcsss.scenes["lab"].parent / "fr3.urdf"))
248-
fr3_config = FR3Config()
249-
fr3_config.realtime = False
250-
# TODO: We might need a TCP offset with only translation here
251-
env_sim = FR3Sim(FR3Env(robot, ControlMode.JOINTS), simulation)
252-
253-
cameras = {
254-
"wrist": SimCameraConfig(identifier="eye-in-hand_0", type=int(CameraType.fixed)),
255-
"default_free": SimCameraConfig(identifier="", type=int(CameraType.default_free)),
256-
}
257-
cam_cfg = SimCameraSetConfig(cameras=cameras, resolution_width=640, resolution_height=480, frame_rate=10)
258-
camera_set = SimCameraSet(simulation, cam_cfg)
259-
env_cam: gym.Env = CameraSetWrapper(env_sim, camera_set)
260-
261-
gripper_cfg = rcsss.sim.FHConfig()
262-
gripper = rcsss.sim.FrankaHand(simulation, "0", gripper_cfg)
263-
env_cam = GripperWrapper(env_cam, gripper)
264-
265-
env_cam = CollisionGuard.env_from_xml_paths(
266-
env_cam,
267-
str(rcsss.scenes["fr3_empty_world"]),
268-
str(rcsss.scenes["lab"].parent / "fr3.urdf"),
269-
gripper=True,
270-
camera=False,
271-
check_home_collision=False,
272-
control_mode=ControlMode.CARTESIAN_TQuart,
273-
)
274-
env_rel = RelativeActionSpace(env_cam, relative_to=RelativeTo.CONFIGURED_ORIGIN)
275231
env_rel.reset()
276-
with UDPViveActionServer(VIVE_HOST, VIVE_PORT, env_rel) as action_server:
277-
action_server.environment_step_loop()
278-
279232

280-
def main():
281-
if "lab" not in rcsss.scenes:
282-
logger.error("This pip package was not built with the UTN lab models, aborting.")
283-
return
284-
if USE_REAL_ROBOT:
285-
hw()
286-
else:
287-
sim()
233+
with UDPViveActionServer(VIVE_HOST, VIVE_PORT, typing.cast(RelativeActionSpace, env_rel)) as action_server:
234+
action_server.environment_step_loop()
288235

289236

290237
if __name__ == "__main__":

python/rcsss/envs/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,11 +457,11 @@ def check_depth(depth):
457457
camera_name: (
458458
{
459459
self.RGB_KEY: frame.camera.color.data,
460+
self.DEPTH_KEY: frame.camera.depth.data, # type: ignore
460461
}
461462
if check_depth(frame.camera.depth)
462463
else {
463464
self.RGB_KEY: frame.camera.color.data,
464-
self.DEPTH_KEY: frame.camera.depth.data, # type: ignore
465465
}
466466
)
467467
for camera_name, frame in frameset.frames.items()

python/rcsss/envs/factories.py

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import logging
2-
import sys
2+
import os
3+
from os import PathLike
34

45
import gymnasium as gym
56
import rcsss
@@ -63,12 +64,17 @@ def fr3_hw_env(
6364
gripper_cfg: rcsss.hw.FHConfig | None = None,
6465
camera_set: BaseHardwareCameraSet | None = None,
6566
max_relative_movement: float | None = None,
67+
urdf_path: str | None = None,
6668
) -> gym.Env:
67-
if "lab" not in rcsss.scenes:
68-
# TODO: mujoco xml and urdf as arguments
69-
logger.error("This pip package was not built with the UTN lab models, aborting.")
70-
sys.exit()
71-
robot = rcsss.hw.FR3(ip, str(rcsss.scenes["lab"].parent / "fr3.urdf"))
69+
if urdf_path is None and "lab" in rcsss.scenes:
70+
urdf_path = str(rcsss.scenes["lab"].parent / "fr3.urdf")
71+
assert os.path.exists(urdf_path), "Automatic deduced urdf path does not exist. Corrupted models directory."
72+
logger.info("Using automatic found urdf.")
73+
elif urdf_path is None:
74+
logger.warning("No urdf path was found. Proceeding, but set_cartesian methods will result in errors.")
75+
76+
ik = rcsss.common.IK(urdf_path) if urdf_path is not None else None
77+
robot = rcsss.hw.FR3(ip, ik)
7278
robot.set_parameters(robot_cfg)
7379

7480
env: gym.Env = FR3Env(robot, ControlMode.JOINTS if collision_guard else control_mode)
@@ -102,7 +108,6 @@ def fr3_hw_env(
102108
def default_fr3_sim_robot_cfg():
103109
cfg = sim.FR3Config()
104110
cfg.tcp_offset = rcsss.common.Pose(rcsss.common.FrankaHandTCPOffset())
105-
cfg.ik_duration_in_milliseconds = 300
106111
cfg.realtime = False
107112
return cfg
108113

@@ -126,12 +131,24 @@ def fr3_sim_env(
126131
gripper_cfg: rcsss.sim.FHConfig | None = None,
127132
camera_set_cfg: SimCameraSetConfig | None = None,
128133
max_relative_movement: float | None = None,
134+
urdf_path: str | None = None,
135+
mjcf: str | PathLike = "fr3_empty_world",
129136
) -> gym.Env[ObsArmsGrCam, LimitedJointsRelDictType]:
130-
if "lab" not in rcsss.scenes:
131-
logger.error("This pip package was not built with the UTN lab models, aborting.")
132-
sys.exit()
133-
simulation = sim.Sim(rcsss.scenes["fr3_empty_world"])
134-
robot = rcsss.sim.FR3(simulation, "0", str(rcsss.scenes["lab"].parent / "fr3.urdf"))
137+
138+
if urdf_path is None and "lab" in rcsss.scenes:
139+
urdf_path = str(rcsss.scenes["lab"].parent / "fr3.urdf")
140+
assert os.path.exists(urdf_path), "Automatic deduced urdf path does not exist. Corrupted models directory."
141+
logger.info("Using automatic found urdf.")
142+
elif urdf_path is None:
143+
msg = "This pip package was not built with the UTN lab models, please pass the urdf and mjcf path."
144+
raise ValueError(msg)
145+
146+
if mjcf not in rcsss.scenes:
147+
logger.warning("mjcf not found as key in scenes, interpreting mjcf as path the mujoco scene xml")
148+
149+
simulation = sim.Sim(rcsss.scenes.get(mjcf, mjcf)) # type: ignore
150+
ik = rcsss.common.IK(urdf_path)
151+
robot = rcsss.sim.FR3(simulation, "0", ik)
135152
robot.set_parameters(robot_cfg)
136153
env: gym.Env = FR3Env(robot, control_mode)
137154
env = FR3Sim(env, simulation)

python/rcsss/envs/sim.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ def env_from_xml_paths(
108108
cls,
109109
env: gym.Env,
110110
mjmld: str,
111-
rlmdl: str,
111+
urdf: str,
112112
id="0",
113113
gripper=False,
114114
check_home_collision=True,
@@ -118,9 +118,9 @@ def env_from_xml_paths(
118118
) -> "CollisionGuard":
119119
assert isinstance(env.unwrapped, FR3Env)
120120
simulation = sim.Sim(mjmld)
121-
robot = rcsss.sim.FR3(simulation, id, rlmdl)
121+
ik = rcsss.common.IK(urdf, max_duration_ms=300)
122+
robot = rcsss.sim.FR3(simulation, id, ik)
122123
cfg = sim.FR3Config()
123-
cfg.ik_duration_in_milliseconds = 300
124124
cfg.realtime = False
125125
if tcp_offset is not None:
126126
cfg.tcp_offset = tcp_offset

src/common/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
add_library(common)
2-
target_sources(common PRIVATE Pose.cpp NRobotsWithGripper.cpp Robot.cpp)
3-
target_link_libraries(common PUBLIC Eigen3::Eigen)
2+
target_sources(common PRIVATE Pose.cpp NRobotsWithGripper.cpp Robot.cpp IK.cpp)
3+
target_link_libraries(common PUBLIC Eigen3::Eigen mdl)

0 commit comments

Comments
 (0)