Skip to content

Commit 7ac780b

Browse files
committed
Merge branch 'master' into scene_mgmt
2 parents e911f8b + e1ce3c6 commit 7ac780b

21 files changed

+421
-88
lines changed

CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ set(RL_BUILD_DEMOS OFF)
3838
set(RL_BUILD_RL_SG OFF)
3939
set(RL_BUILD_TESTS OFF)
4040
set(RL_BUILD_EXTRAS OFF)
41+
set(BUILD_PYTHON_INTERFACE OFF)
42+
set(BUILD_DOCUMENTATION OFF)
4143

4244
option(INCLUDE_UTN_MODELS "Whether to include the private UTN models. Requires GITLAB_MODELS_TOKEN to be set to a valid token wit read_api permissions" OFF)
4345

@@ -51,7 +53,7 @@ find_package(MuJoCo REQUIRED)
5153
FetchContent_Declare(
5254
libfranka
5355
GIT_REPOSITORY https://github.com/frankaemika/libfranka.git
54-
GIT_TAG 0.13.3
56+
GIT_TAG 0.14.2
5557
GIT_PROGRESS TRUE
5658
EXCLUDE_FROM_ALL
5759
)
@@ -96,7 +98,7 @@ FetchContent_MakeAvailable(libfranka rl pybind11)
9698
if (${INCLUDE_UTN_MODELS})
9799
if (DEFINED GITLAB_MODELS_TOKEN)
98100
include(download_scenes)
99-
set(ref b13a8d55bacc6470ece0788c654739e5cdef9265)
101+
set(ref b8234983a5e35e222c955f9145ac4cd129827a8e)
100102
FetchContent_Declare(
101103
scenes
102104
URL "https://gitos.rrze.fau.de/api/v4/projects/1100/repository/archive?path=scenes&sha=${ref}"

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
PYSRC = python/rcsss
1+
PYSRC = python
22
CPPSRC = src
33
COMPILE_MODE = Release
44

cmake/Findpinocchio.cmake

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
if (NOT pinocchio_FOUND)
2+
if (NOT Python3_FOUND)
3+
set(pinocchio_FOUND FALSE)
4+
if (pinocchio_FIND_REQUIRED)
5+
message(FATAL_ERROR "Could not find pinocchio. Please install pinocchio using pip.")
6+
endif()
7+
return()
8+
endif()
9+
10+
# Check if the include directory exists
11+
cmake_path(APPEND Python3_SITELIB cmeel.prefix include OUTPUT_VARIABLE pinocchio_INCLUDE_DIRS)
12+
if (NOT EXISTS ${pinocchio_INCLUDE_DIRS})
13+
set(pinocchio_FOUND FALSE)
14+
if (pinocchio_FIND_REQUIRED)
15+
message(FATAL_ERROR "Could not find pinocchio. Please install pinocchio using pip.")
16+
endif()
17+
return()
18+
endif()
19+
20+
# Check if the library file exists
21+
cmake_path(APPEND Python3_SITELIB cmeel.prefix lib libpinocchio.so OUTPUT_VARIABLE pinocchio_library_path)
22+
if (NOT EXISTS ${pinocchio_library_path})
23+
set(pinocchio_FOUND FALSE)
24+
if (pinocchio_FIND_REQUIRED)
25+
message(FATAL_ERROR "Could not find pinocchio. Please install pinocchio using pip.")
26+
endif()
27+
return()
28+
endif()
29+
30+
# Extract version from the library filename
31+
file(GLOB pinocchio_dist_info "${Python3_SITELIB}/pin-*.dist-info")
32+
cmake_path(GET pinocchio_dist_info FILENAME pinocchio_library_filename)
33+
string(REPLACE "pin-" "" pinocchio_VERSION "${pinocchio_library_filename}")
34+
string(REPLACE ".dist-info" "" pinocchio_VERSION "${pinocchio_VERSION}")
35+
36+
# Create the imported target
37+
add_library(pinocchio::pinocchio SHARED IMPORTED)
38+
target_include_directories(pinocchio::pinocchio INTERFACE ${pinocchio_INCLUDE_DIRS})
39+
set_target_properties(
40+
pinocchio::pinocchio
41+
PROPERTIES
42+
IMPORTED_LOCATION "${pinocchio_library_path}"
43+
)
44+
set(pinocchio_FOUND TRUE)
45+
endif()

pyproject.toml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ version = "0.3.1"
88
description="Python Interface for libfranka to control the Franka Research 3 Robot"
99
dependencies = ["websockets>=11.0",
1010
"requests~=2.31",
11-
"numpy==2.0",
11+
"numpy",
1212
"typer~=0.9",
1313
"pydantic~=2.6",
1414
"gymnasium~=0.29.1",
@@ -23,7 +23,9 @@ dependencies = ["websockets>=11.0",
2323
"python-dotenv==1.0.1",
2424
"opencv-python~=4.10.0.84",
2525
# NOTE: when changing the mujoco version, also change it in requirements_dev.txt
26-
"mujoco==3.1.5"
26+
"mujoco==3.2.6",
27+
# NOTE: Same for pinocchio (pin)
28+
"pin==2.7.0"
2729
]
2830
readme = "README.md"
2931
maintainers = [
@@ -98,6 +100,8 @@ ignore = [
98100
"T201", # print() used
99101
"PLR5501", # elif to reduce indentation
100102
"PT018", # assertion should be broken down into multiple parts
103+
"NPY002",
104+
"G004", # Logging format string does not contain any placeholders
101105
]
102106

103107
[tool.pylint.format]

python/examples/env_cartesian_control.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import logging
22

3-
from dotenv import dotenv_values
43
from rcsss.control.fr3_desk import FCI, Desk, DummyResourceManager
54
from rcsss.control.utils import load_creds_fr3_desk
65
from rcsss.envs.base import ControlMode, RelativeTo, RobotInstance
@@ -45,6 +44,7 @@
4544

4645

4746
def main():
47+
resource_manger: FCI | DummyResourceManager
4848
if ROBOT_INSTANCE == RobotInstance.HARDWARE:
4949
user, pw = load_creds_fr3_desk()
5050
resource_manger = FCI(Desk(ROBOT_IP, user, pw), unlock=False, lock_when_done=False)
@@ -60,7 +60,7 @@ def main():
6060
collision_guard="lab",
6161
gripper_cfg=default_fr3_hw_gripper_cfg(),
6262
max_relative_movement=0.5,
63-
relative_to=RelativeTo.LAST_STEP
63+
relative_to=RelativeTo.LAST_STEP,
6464
)
6565
else:
6666
env_rel = fr3_sim_env(
@@ -70,12 +70,12 @@ def main():
7070
gripper_cfg=default_fr3_sim_gripper_cfg(),
7171
camera_set_cfg=default_mujoco_cameraset_cfg(),
7272
max_relative_movement=0.5,
73-
relative_to=RelativeTo.LAST_STEP
73+
relative_to=RelativeTo.LAST_STEP,
7474
)
7575
env_rel.get_wrapper_attr("sim").open_gui()
7676

7777
env_rel.reset()
78-
print(env_rel.unwrapped.robot.get_cartesian_position())
78+
print(env_rel.unwrapped.robot.get_cartesian_position()) # type: ignore
7979

8080
for _ in range(10):
8181
for _ in range(10):

python/examples/env_joint_control.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import logging
22

3-
import mujoco
43
import numpy as np
5-
import rcsss
6-
from dotenv import dotenv_values
74
from rcsss.control.fr3_desk import FCI, Desk, DummyResourceManager
85
from rcsss.control.utils import load_creds_fr3_desk
96
from rcsss.envs.base import ControlMode, RelativeTo, RobotInstance
@@ -48,6 +45,7 @@
4845

4946

5047
def main():
48+
resource_manger: FCI | DummyResourceManager
5149
if ROBOT_INSTANCE == RobotInstance.HARDWARE:
5250
user, pw = load_creds_fr3_desk()
5351
resource_manger = FCI(Desk(ROBOT_IP, user, pw), unlock=False, lock_when_done=False)

python/examples/fr3.py

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import logging
22
import sys
3-
from time import sleep
43

54
import numpy as np
65
import rcsss
7-
from dotenv import dotenv_values
86
from rcsss import sim
97
from rcsss._core.hw import FR3Config, IKController
108
from rcsss._core.sim import CameraType
@@ -57,54 +55,54 @@ def main():
5755
if "lab" not in rcsss.scenes:
5856
logger.error("This pip package was not built with the UTN lab models, aborting.")
5957
sys.exit()
58+
resource_manger: FCI | DummyResourceManager
6059
if ROBOT_INSTANCE == RobotInstance.HARDWARE:
6160
user, pw = load_creds_fr3_desk()
6261
resource_manger = FCI(Desk(ROBOT_IP, user, pw), unlock=False, lock_when_done=False)
6362
else:
6463
resource_manger = DummyResourceManager()
6564

6665
with resource_manger:
66+
robot: rcsss.common.Robot
67+
gripper: rcsss.common.Gripper
6768
if ROBOT_INSTANCE == RobotInstance.SIMULATION:
6869
simulation = sim.Sim(rcsss.scenes["fr3_empty_world"]["mjb"])
6970
urdf_path = get_urdf_path(URDF_PATH, allow_none_if_not_found=False)
71+
assert urdf_path is not None
7072
ik = rcsss.common.IK(urdf_path)
7173
robot = rcsss.sim.FR3(simulation, "0", ik)
7274
cfg = sim.FR3Config()
7375
cfg.tcp_offset = rcsss.common.Pose(rcsss.common.FrankaHandTCPOffset())
7476
cfg.realtime = False
7577
robot.set_parameters(cfg)
7678

77-
gripper_cfg = sim.FHConfig()
78-
gripper = sim.FrankaHand(simulation, "0", gripper_cfg)
79+
gripper_cfg_sim = sim.FHConfig()
80+
gripper = sim.FrankaHand(simulation, "0", gripper_cfg_sim)
7981

8082
# add camera to have a rendering gui
8183
cameras = {
82-
"default_free": SimCameraConfig(
83-
identifier="", type=int(CameraType.default_free)
84-
),
85-
"wrist": SimCameraConfig(
86-
identifier="eye-in-hand_0", type=int(CameraType.fixed)
87-
),
88-
# TODO: odd behavior when not both cameras are used: only last image is shown
84+
"default_free": SimCameraConfig(identifier="", type=int(CameraType.default_free)),
85+
"wrist": SimCameraConfig(identifier="eye-in-hand_0", type=int(CameraType.fixed)),
8986
}
9087
cam_cfg = SimCameraSetConfig(cameras=cameras, resolution_width=1280, resolution_height=720, frame_rate=20)
91-
camera_set = SimCameraSet(simulation, cam_cfg)
88+
camera_set = SimCameraSet(simulation, cam_cfg) # noqa: F841
9289
simulation.open_gui()
9390

9491
else:
9592
urdf_path = get_urdf_path(URDF_PATH, allow_none_if_not_found=False)
93+
assert urdf_path is not None
9694
ik = rcsss.common.IK(urdf_path)
97-
robot = rcsss.hw.FR3(ROBOT_IP, str(rcsss.scenes["lab"].parent / "fr3.urdf"), ik)
95+
robot = rcsss.hw.FR3(ROBOT_IP, ik)
9896
robot_cfg = FR3Config()
9997
robot_cfg.tcp_offset = rcsss.common.Pose(rcsss.common.FrankaHandTCPOffset())
10098
robot_cfg.controller = IKController.robotics_library
10199
robot.set_parameters(robot_cfg)
102100

103-
gripper_cfg = rcsss.hw.FHConfig()
104-
gripper_cfg.epsilon_inner = gripper_cfg.epsilon_outer = 0.1
105-
gripper_cfg.speed = 0.1
106-
gripper_cfg.force = 30
107-
gripper = rcsss.hw.FrankaHand(ROBOT_IP, gripper_cfg)
101+
gripper_cfg_hw = rcsss.hw.FHConfig()
102+
gripper_cfg_hw.epsilon_inner = gripper_cfg_hw.epsilon_outer = 0.1
103+
gripper_cfg_hw.speed = 0.1
104+
gripper_cfg_hw.force = 30
105+
gripper = rcsss.hw.FrankaHand(ROBOT_IP, gripper_cfg_hw)
108106
input("the robot is going to move, press enter whenever you are ready")
109107

110108
# move to home position and open gripper
@@ -120,7 +118,7 @@ def main():
120118
)
121119
if ROBOT_INSTANCE == RobotInstance.SIMULATION:
122120
simulation.step_until_convergence()
123-
logger.debug(f"IK success: {robot.get_state().ik_success}")
121+
logger.debug(f"IK success: {robot.get_state().ik_success}") # type: ignore
124122
logger.debug(f"sim converged: {simulation.is_converged()}")
125123

126124
# 5cm in y direction
@@ -129,7 +127,7 @@ def main():
129127
)
130128
if ROBOT_INSTANCE == RobotInstance.SIMULATION:
131129
simulation.step_until_convergence()
132-
logger.debug(f"IK success: {robot.get_state().ik_success}")
130+
logger.debug(f"IK success: {robot.get_state().ik_success}") # type: ignore
133131
logger.debug(f"sim converged: {simulation.is_converged()}")
134132

135133
# 5cm in z direction
@@ -138,7 +136,7 @@ def main():
138136
)
139137
if ROBOT_INSTANCE == RobotInstance.SIMULATION:
140138
simulation.step_until_convergence()
141-
logger.debug(f"IK success: {robot.get_state().ik_success}")
139+
logger.debug(f"IK success: {robot.get_state().ik_success}") # type: ignore
142140
logger.debug(f"sim converged: {simulation.is_converged()}")
143141

144142
# rotate the arm 90 degrees around the inverted y and z axis
@@ -148,7 +146,7 @@ def main():
148146
robot.set_cartesian_position(new_pose)
149147
if ROBOT_INSTANCE == RobotInstance.SIMULATION:
150148
simulation.step_until_convergence()
151-
logger.debug(f"IK success: {robot.get_state().ik_success}")
149+
logger.debug(f"IK success: {robot.get_state().ik_success}") # type: ignore
152150
logger.debug(f"sim converged: {simulation.is_converged()}")
153151

154152
if ROBOT_INSTANCE == RobotInstance.HARDWARE:
@@ -162,7 +160,7 @@ def main():
162160
)
163161
if ROBOT_INSTANCE == RobotInstance.SIMULATION:
164162
simulation.step_until_convergence()
165-
logger.debug(f"IK success: {robot.get_state().ik_success}")
163+
logger.debug(f"IK success: {robot.get_state().ik_success}") # type: ignore
166164
logger.debug(f"sim converged: {simulation.is_converged()}")
167165

168166
# grasp the object
@@ -177,7 +175,7 @@ def main():
177175
)
178176
if ROBOT_INSTANCE == RobotInstance.SIMULATION:
179177
simulation.step_until_convergence()
180-
logger.debug(f"IK success: {robot.get_state().ik_success}")
178+
logger.debug(f"IK success: {robot.get_state().ik_success}") # type: ignore
181179
logger.debug(f"sim converged: {simulation.is_converged()}")
182180

183181
if ROBOT_INSTANCE == RobotInstance.HARDWARE:

python/examples/grasp_demo.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import logging
2+
from typing import Any, cast
3+
4+
import gymnasium as gym
5+
import mujoco
6+
import numpy as np
7+
from rcsss._core.common import Pose
8+
from rcsss.envs.base import FR3Env, GripperWrapper
9+
10+
logger = logging.getLogger(__name__)
11+
logger.setLevel(logging.INFO)
12+
13+
14+
class PickUpDemo:
15+
def __init__(self, env: gym.Env):
16+
self.env = env
17+
self.unwrapped: FR3Env = cast(FR3Env, self.env.unwrapped)
18+
self.home_pose = self.unwrapped.robot.get_cartesian_position()
19+
20+
def _action(self, pose: Pose, gripper: float) -> dict[str, Any]:
21+
return {"xyzrpy": pose.xyzrpy(), "gripper": gripper}
22+
23+
def get_object_pose(self, geom_name) -> Pose:
24+
model = self.env.get_wrapper_attr("sim").model
25+
data = self.env.get_wrapper_attr("sim").data
26+
27+
geom_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_GEOM, geom_name)
28+
return Pose(translation=data.geom_xpos[geom_id], rotation=data.geom_xmat[geom_id].reshape(3, 3))
29+
30+
def generate_waypoints(self, start_pose: Pose, end_pose: Pose, num_waypoints: int) -> list[Pose]:
31+
waypoints = []
32+
for i in range(num_waypoints + 1):
33+
t = i / (num_waypoints + 1)
34+
waypoints.append(start_pose.interpolate(end_pose, t))
35+
return waypoints
36+
37+
def step(self, action: dict) -> dict:
38+
return self.env.step(action)[0]
39+
40+
def plan_linear_motion(self, geom_name: str, delta_up: float, num_waypoints: int = 20) -> list[Pose]:
41+
end_eff_pose = self.unwrapped.robot.get_cartesian_position()
42+
43+
goal_pose = self.get_object_pose(geom_name=geom_name)
44+
# goal pose is above the object and gripper coordinate must flip z-axis (end effector base rotation is [1, 0, 0, 0])
45+
# be careful we define identity quaternion as as [0, 0, 0, 1]
46+
# this does not work if the object is flipped
47+
goal_pose *= Pose(translation=np.array([0, 0, delta_up]), quaternion=np.array([1, 0, 0, 0]))
48+
49+
return self.generate_waypoints(end_eff_pose, goal_pose, num_waypoints=num_waypoints)
50+
51+
def execute_motion(self, waypoints: list[Pose], gripper: float = GripperWrapper.BINARY_GRIPPER_OPEN) -> dict:
52+
for i in range(1, len(waypoints)):
53+
# calculate delta action
54+
delta_action = waypoints[i] * waypoints[i - 1].inverse()
55+
obs = self.step(self._action(delta_action, gripper))
56+
return obs
57+
58+
def approach(self, geom_name: str):
59+
waypoints = self.plan_linear_motion(geom_name=geom_name, delta_up=0.2, num_waypoints=5)
60+
self.execute_motion(waypoints=waypoints, gripper=GripperWrapper.BINARY_GRIPPER_OPEN)
61+
62+
def grasp(self, geom_name: str):
63+
64+
waypoints = self.plan_linear_motion(geom_name=geom_name, delta_up=0, num_waypoints=15)
65+
self.execute_motion(waypoints=waypoints, gripper=GripperWrapper.BINARY_GRIPPER_OPEN)
66+
67+
self.step(self._action(Pose(), GripperWrapper.BINARY_GRIPPER_CLOSED))
68+
69+
waypoints = self.plan_linear_motion(geom_name=geom_name, delta_up=0.2, num_waypoints=20)
70+
self.execute_motion(waypoints=waypoints, gripper=GripperWrapper.BINARY_GRIPPER_CLOSED)
71+
72+
def move_home(self):
73+
end_eff_pose = self.unwrapped.robot.get_cartesian_position()
74+
waypoints = self.generate_waypoints(end_eff_pose, self.home_pose, num_waypoints=10)
75+
self.execute_motion(waypoints=waypoints, gripper=GripperWrapper.BINARY_GRIPPER_CLOSED)
76+
77+
def pickup(self, geom_name: str):
78+
self.approach(geom_name)
79+
self.grasp(geom_name)
80+
self.move_home()
81+
82+
83+
def main():
84+
env = gym.make("rcs/SimplePickUpSim-v0", render_mode="human", delta_actions=True)
85+
env.reset()
86+
controller = PickUpDemo(env)
87+
controller.pickup("yellow_box_geom")
88+
89+
90+
if __name__ == "__main__":
91+
main()

0 commit comments

Comments
 (0)