From 3916344e82f2199002541719b66a76218e4fbfc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=BClg?= Date: Sun, 21 Jun 2026 13:12:24 -0700 Subject: [PATCH 01/15] docs: added documentation for assets path --- README.md | 10 ++++++++++ docs/getting_started/index.md | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/README.md b/README.md index d88d7365..8579cb4d 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,16 @@ pip install -ve . ``` +### RCS Asset Cache + +RCS resolves its asset directory from the `RCS_PREFIX` environment variable. When it is unset, RCS defaults to `~/.rcs`. + +On import, RCS checks whether that path exists. If it does not, it downloads the matching asset archive from GitHub into that location automatically. + +```shell +export RCS_PREFIX=/path/to/rcs-assets +``` + ### Via PyPI/pip *Coming soon...* diff --git a/docs/getting_started/index.md b/docs/getting_started/index.md index cdfac035..72ef4747 100644 --- a/docs/getting_started/index.md +++ b/docs/getting_started/index.md @@ -36,6 +36,16 @@ pip install -ve . For a docker deployment, see the `docker` folder in the repository. +## RCS Asset Cache + +RCS resolves its asset directory from the `RCS_PREFIX` environment variable. If `RCS_PREFIX` is not set, it defaults to `~/.rcs`. + +On import, RCS checks whether that path exists. If it does not, it downloads the matching asset archive from GitHub into that location automatically. + +```shell +export RCS_PREFIX=/path/to/rcs-assets +``` + ## Basic Usage The python package is called `rcs`. From e2b57f0abf69387994ede1831e0fc2722deae04b Mon Sep 17 00:00:00 2001 From: Tobias Juelg Date: Mon, 22 Jun 2026 01:11:30 +0200 Subject: [PATCH 02/15] fix(pypi): pin compatible pinocchio runtime deps --- pyproject.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index ca7d0c3d..430a8da9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,9 @@ dependencies = [ "simplejpeg", "mujoco==3.2.6", "pin==3.7.0", + # pin 3.7.0 currently resolves against older urdfdom/tinyxml SONAMEs at runtime + "cmeel-urdfdom<5", + "cmeel-tinyxml2<11", "greenlet", "duckdb", "pandas", @@ -74,6 +77,8 @@ dev = [ build_deps = [ "mujoco==3.2.6", "pin==3.7.0", + "cmeel-urdfdom<5", + "cmeel-tinyxml2<11", ] [tool.cibuildwheel] From 4f77cbf5585b3448a13857cc4952f4022250b031 Mon Sep 17 00:00:00 2001 From: Tobias Juelg Date: Mon, 22 Jun 2026 01:11:30 +0200 Subject: [PATCH 03/15] fix(egl): fail fast when rendering is requested without egl --- python/rcs/camera/sim.py | 2 ++ python/rcs/sim/egl_bootstrap.py | 29 ++++++++++++++++++++++++++--- src/rcs/utils.cpp | 8 ++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/python/rcs/camera/sim.py b/python/rcs/camera/sim.py index a374bc97..d508165a 100644 --- a/python/rcs/camera/sim.py +++ b/python/rcs/camera/sim.py @@ -11,6 +11,7 @@ from rcs._core.sim import SimCameraConfig from rcs._core.sim import SimCameraSet as _SimCameraSet from rcs.camera.interface import BaseCameraSet, CameraFrame, DataFrame, Frame, FrameSet +from rcs.sim import egl_bootstrap from rcs import sim @@ -31,6 +32,7 @@ def __init__( self.cameras = cameras self.physical_units = physical_units + egl_bootstrap.require("simulation camera rendering") super().__init__(simulation, cameras, render_on_demand=render_on_demand) self._sim: sim.Sim diff --git a/python/rcs/sim/egl_bootstrap.py b/python/rcs/sim/egl_bootstrap.py index 57884bde..9aa2d95a 100644 --- a/python/rcs/sim/egl_bootstrap.py +++ b/python/rcs/sim/egl_bootstrap.py @@ -10,12 +10,15 @@ import os _egl_available = False +_egl_error = None _addr_make_current = None _egl_display = None _egl_context = None name = ctypes.util.find_library("EGL") -if name is not None: +if name is None: + _egl_error = "Could not find libEGL via ctypes.util.find_library('EGL')." +else: try: import mujoco.egl from mujoco.egl import GLContext @@ -26,8 +29,28 @@ _egl_display = int(mujoco.egl.EGL_DISPLAY.address) _egl_context = int(_ctx._context.address) _egl_available = True - except Exception: - pass + except Exception as exc: + _egl_error = f"Failed to initialize MuJoCo EGL context: {exc!r}" + + +def is_available() -> bool: + return _egl_available + + +def failure_reason() -> str | None: + return _egl_error + + +def require(feature: str = "offscreen rendering"): + if _egl_available: + return + reason = _egl_error or "unknown EGL initialization failure" + message = ( + f"EGL is required for {feature}, but it is not available. {reason} " + "If you do not need rendering, run RCS without simulation cameras/viewers. " + "If you do need headless rendering, install the system EGL/OpenGL runtime libraries." + ) + raise RuntimeError(message) def bootstrap(): diff --git a/src/rcs/utils.cpp b/src/rcs/utils.cpp index d348375b..18a4e58b 100644 --- a/src/rcs/utils.cpp +++ b/src/rcs/utils.cpp @@ -18,6 +18,14 @@ void bootstrap_egl(uintptr_t fn_addr, uintptr_t dpy, uintptr_t ctx) { } void ensure_current() { + if (g_makeCurrent == nullptr || g_display == EGL_NO_DISPLAY || + g_context == EGL_NO_CONTEXT) { + throw std::runtime_error( + "EGL rendering was requested, but EGL was not bootstrapped. " + "This usually means libEGL or the MuJoCo EGL context is unavailable. " + "Run without cameras/viewers if you do not need rendering, or install " + "the required system EGL/OpenGL runtime libraries."); + } if (!g_makeCurrent(g_display, g_surface, g_surface, g_context)) throw std::runtime_error("eglMakeCurrent failed"); } From 0593811acd646cfc4228847d315b8934826f30f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=BClg?= Date: Wed, 24 Jun 2026 21:30:24 -0700 Subject: [PATCH 04/15] chore: rename python package to rcs_core --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 430a8da9..c7c3de94 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,9 +13,9 @@ requires = [ build-backend = "scikit_build_core.build" [project] -name = "rcs" +name = "rcs_core" version = "0.7.1" -description = "A Lean Ecosystem for Robot Learning at Scale" +description = "A lean, ROS-free sim-to-real framework for training and deploying Vision-Language-Action (VLA) models and RL agents. Native MuJoCo Gymnasium wrappers with synchronous execution for Franka, UR5e, xArm, and SO101." dependencies = [ "websockets>=11.0", "requests~=2.31", From e01e84f0fed54314e447ec02ab4dfe12730ef0b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=BClg?= Date: Wed, 24 Jun 2026 22:04:38 -0700 Subject: [PATCH 05/15] chore: remove global pynput dependency --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c7c3de94..2ffc4658 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,6 @@ dependencies = [ "etils[epath]>=1.7.0", "glfw~=2.7", "pyopengl~=3.1.9", - "pynput>=1.7.7", "pillow>=10.3", "python-dotenv>=1.0.1", "opencv-python~=4.10.0.84", From ece23f83114e87040322e9d1973814e3733d1117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=BClg?= Date: Wed, 24 Jun 2026 22:04:48 -0700 Subject: [PATCH 06/15] =?UTF-8?q?bump:=20version=200.7.1=20=E2=86=92=200.7?= =?UTF-8?q?.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 8 ++++++++ CMakeLists.txt | 2 +- extensions/rcs_fr3/CMakeLists.txt | 2 +- extensions/rcs_fr3/pyproject.toml | 4 ++-- extensions/rcs_fr3/src/rcs_fr3/_core/__init__.pyi | 2 +- extensions/rcs_panda/CMakeLists.txt | 2 +- extensions/rcs_panda/pyproject.toml | 4 ++-- extensions/rcs_panda/src/rcs_panda/_core/__init__.pyi | 2 +- extensions/rcs_realsense/pyproject.toml | 4 ++-- extensions/rcs_realsense/src/rcs_realsense/__init__.py | 2 +- extensions/rcs_robotics_library/CMakeLists.txt | 2 +- extensions/rcs_robotics_library/pyproject.toml | 4 ++-- .../src/rcs_robotics_library/_core/__init__.pyi | 2 +- extensions/rcs_robotiq2f85/pyproject.toml | 4 ++-- .../rcs_robotiq2f85/src/rcs_robotiq2f85/__init__.py | 2 +- extensions/rcs_so101/CMakeLists.txt | 2 +- extensions/rcs_so101/pyproject.toml | 4 ++-- extensions/rcs_so101/src/rcs_so101/_core/__init__.pyi | 2 +- extensions/rcs_tacto/pyproject.toml | 4 ++-- extensions/rcs_tacto/src/rcs_tacto/__init__.py | 2 +- extensions/rcs_ur5e/pyproject.toml | 4 ++-- extensions/rcs_ur5e/src/rcs_ur5e/__init__.py | 2 +- extensions/rcs_xarm7/pyproject.toml | 4 ++-- extensions/rcs_xarm7/src/rcs_xarm7/__init__.py | 2 +- pyproject.toml | 2 +- python/rcs/_core/__init__.pyi | 2 +- 26 files changed, 42 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3525275..9c21dfa5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## v0.7.2 (2026-06-24) + +### Fix + +- **egl**: fail fast when rendering is requested without egl +- **pypi**: pin compatible pinocchio runtime deps +- sim reset (#314) + ## v0.7.1 (2026-06-02) ### Feat diff --git a/CMakeLists.txt b/CMakeLists.txt index 972a0a5f..a9d48a8b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.5) project( rcs LANGUAGES C CXX - VERSION 0.7.1 + VERSION 0.7.2 DESCRIPTION "Robot Control Stack Library" ) diff --git a/extensions/rcs_fr3/CMakeLists.txt b/extensions/rcs_fr3/CMakeLists.txt index a6213135..46689427 100644 --- a/extensions/rcs_fr3/CMakeLists.txt +++ b/extensions/rcs_fr3/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.24) project( rcs_fr3 LANGUAGES C CXX - VERSION 0.7.1 + VERSION 0.7.2 DESCRIPTION "RCS Libfranka integration" ) diff --git a/extensions/rcs_fr3/pyproject.toml b/extensions/rcs_fr3/pyproject.toml index aeb0d289..d62c3370 100644 --- a/extensions/rcs_fr3/pyproject.toml +++ b/extensions/rcs_fr3/pyproject.toml @@ -13,9 +13,9 @@ build-backend = "scikit_build_core.build" [project] name = "rcs_fr3" -version = "0.7.1" +version = "0.7.2" description = "RCS libfranka integration" -dependencies = ["rcs>=0.7.1", "frankik"] +dependencies = ["rcs>=0.7.2", "frankik"] readme = "README.md" maintainers = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] authors = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] diff --git a/extensions/rcs_fr3/src/rcs_fr3/_core/__init__.pyi b/extensions/rcs_fr3/src/rcs_fr3/_core/__init__.pyi index 7a5f99cc..78b6b4cc 100644 --- a/extensions/rcs_fr3/src/rcs_fr3/_core/__init__.pyi +++ b/extensions/rcs_fr3/src/rcs_fr3/_core/__init__.pyi @@ -16,4 +16,4 @@ from __future__ import annotations from . import hw __all__: list[str] = ["hw"] -__version__: str = "0.7.1" +__version__: str = "0.7.2" diff --git a/extensions/rcs_panda/CMakeLists.txt b/extensions/rcs_panda/CMakeLists.txt index 775e2235..01a83198 100644 --- a/extensions/rcs_panda/CMakeLists.txt +++ b/extensions/rcs_panda/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.24) project( rcs_panda LANGUAGES C CXX - VERSION 0.7.1 + VERSION 0.7.2 DESCRIPTION "RCS Libfranka integration" ) diff --git a/extensions/rcs_panda/pyproject.toml b/extensions/rcs_panda/pyproject.toml index f3552688..7194a38b 100644 --- a/extensions/rcs_panda/pyproject.toml +++ b/extensions/rcs_panda/pyproject.toml @@ -12,9 +12,9 @@ build-backend = "scikit_build_core.build" [project] name = "rcs_panda" -version = "0.7.1" +version = "0.7.2" description = "RCS libfranka integration" -dependencies = ["rcs>=0.7.1"] +dependencies = ["rcs>=0.7.2"] readme = "README.md" maintainers = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] authors = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] diff --git a/extensions/rcs_panda/src/rcs_panda/_core/__init__.pyi b/extensions/rcs_panda/src/rcs_panda/_core/__init__.pyi index 7a5f99cc..78b6b4cc 100644 --- a/extensions/rcs_panda/src/rcs_panda/_core/__init__.pyi +++ b/extensions/rcs_panda/src/rcs_panda/_core/__init__.pyi @@ -16,4 +16,4 @@ from __future__ import annotations from . import hw __all__: list[str] = ["hw"] -__version__: str = "0.7.1" +__version__: str = "0.7.2" diff --git a/extensions/rcs_realsense/pyproject.toml b/extensions/rcs_realsense/pyproject.toml index 8dc82aa6..addfbd8f 100644 --- a/extensions/rcs_realsense/pyproject.toml +++ b/extensions/rcs_realsense/pyproject.toml @@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta" [project] name = "rcs_realsense" -version = "0.7.1" +version = "0.7.2" description = "RCS realsense module" dependencies = [ - "rcs>=0.7.1", + "rcs>=0.7.2", "pyrealsense2~=2.55.1", "pupil_apriltags", "diskcache", diff --git a/extensions/rcs_realsense/src/rcs_realsense/__init__.py b/extensions/rcs_realsense/src/rcs_realsense/__init__.py index a5f830a2..bc8c296f 100644 --- a/extensions/rcs_realsense/src/rcs_realsense/__init__.py +++ b/extensions/rcs_realsense/src/rcs_realsense/__init__.py @@ -1 +1 @@ -__version__ = "0.7.1" +__version__ = "0.7.2" diff --git a/extensions/rcs_robotics_library/CMakeLists.txt b/extensions/rcs_robotics_library/CMakeLists.txt index a9849ae4..e27f0940 100644 --- a/extensions/rcs_robotics_library/CMakeLists.txt +++ b/extensions/rcs_robotics_library/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.19) project( rcs_fr3 LANGUAGES C CXX - VERSION 0.7.1 + VERSION 0.7.2 DESCRIPTION "RCS robotics library integration" ) diff --git a/extensions/rcs_robotics_library/pyproject.toml b/extensions/rcs_robotics_library/pyproject.toml index c0b6e00f..a3a1079a 100644 --- a/extensions/rcs_robotics_library/pyproject.toml +++ b/extensions/rcs_robotics_library/pyproject.toml @@ -12,10 +12,10 @@ build-backend = "scikit_build_core.build" [project] name = "rcs_robotics_library" -version = "0.7.1" +version = "0.7.2" description = "RCS robotics library integration" readme = "README.md" -dependencies = ["rcs>=0.7.1"] +dependencies = ["rcs>=0.7.2"] maintainers = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] authors = [ { name = "Tobias Jülg", email = "tobias.juelg@utn.de" }, diff --git a/extensions/rcs_robotics_library/src/rcs_robotics_library/_core/__init__.pyi b/extensions/rcs_robotics_library/src/rcs_robotics_library/_core/__init__.pyi index 7e130934..d574dd50 100644 --- a/extensions/rcs_robotics_library/src/rcs_robotics_library/_core/__init__.pyi +++ b/extensions/rcs_robotics_library/src/rcs_robotics_library/_core/__init__.pyi @@ -16,4 +16,4 @@ from __future__ import annotations from . import rl __all__: list[str] = ["rl"] -__version__: str = "0.7.1" +__version__: str = "0.7.2" diff --git a/extensions/rcs_robotiq2f85/pyproject.toml b/extensions/rcs_robotiq2f85/pyproject.toml index 17625268..6168b7bf 100644 --- a/extensions/rcs_robotiq2f85/pyproject.toml +++ b/extensions/rcs_robotiq2f85/pyproject.toml @@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta" [project] name = "rcs_robotiq2f85" -version = "0.7.1" +version = "0.7.2" description="RCS RobotiQ module" dependencies = [ - "rcs>=0.7.1", + "rcs>=0.7.2", "2f85-python-driver @ git+https://github.com/RobotControlStack/2f85-python-driver.git", ] readme = "README.md" diff --git a/extensions/rcs_robotiq2f85/src/rcs_robotiq2f85/__init__.py b/extensions/rcs_robotiq2f85/src/rcs_robotiq2f85/__init__.py index a5f830a2..bc8c296f 100644 --- a/extensions/rcs_robotiq2f85/src/rcs_robotiq2f85/__init__.py +++ b/extensions/rcs_robotiq2f85/src/rcs_robotiq2f85/__init__.py @@ -1 +1 @@ -__version__ = "0.7.1" +__version__ = "0.7.2" diff --git a/extensions/rcs_so101/CMakeLists.txt b/extensions/rcs_so101/CMakeLists.txt index 3633b530..472128ef 100644 --- a/extensions/rcs_so101/CMakeLists.txt +++ b/extensions/rcs_so101/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.19) project( rcs_so101 LANGUAGES C CXX - VERSION 0.7.1 + VERSION 0.7.2 DESCRIPTION "RCS so101 ik" ) diff --git a/extensions/rcs_so101/pyproject.toml b/extensions/rcs_so101/pyproject.toml index a4d45705..41fe4559 100644 --- a/extensions/rcs_so101/pyproject.toml +++ b/extensions/rcs_so101/pyproject.toml @@ -12,9 +12,9 @@ build-backend = "scikit_build_core.build" [project] name = "rcs_so101" -version = "0.7.1" +version = "0.7.2" description = "RCS SO101 module" -dependencies = ["rcs>=0.7.1", "lerobot==0.3.3"] +dependencies = ["rcs>=0.7.2", "lerobot==0.3.3"] readme = "README.md" maintainers = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] authors = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] diff --git a/extensions/rcs_so101/src/rcs_so101/_core/__init__.pyi b/extensions/rcs_so101/src/rcs_so101/_core/__init__.pyi index 45ef0245..1baf0df9 100644 --- a/extensions/rcs_so101/src/rcs_so101/_core/__init__.pyi +++ b/extensions/rcs_so101/src/rcs_so101/_core/__init__.pyi @@ -16,4 +16,4 @@ from __future__ import annotations from . import so101_ik __all__: list[str] = ["so101_ik"] -__version__: str = "0.7.1" +__version__: str = "0.7.2" diff --git a/extensions/rcs_tacto/pyproject.toml b/extensions/rcs_tacto/pyproject.toml index 01e0121c..387f7bf3 100644 --- a/extensions/rcs_tacto/pyproject.toml +++ b/extensions/rcs_tacto/pyproject.toml @@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta" [project] name = "rcs_tacto" -version = "0.7.1" +version = "0.7.2" description = "RCS integration of tacto" dependencies = [ - "rcs>=0.7.1", + "rcs>=0.7.2", "omegaconf", "mujoco-tacto@git+https://github.com/utn-air/mujoco-tacto.git@main", ] diff --git a/extensions/rcs_tacto/src/rcs_tacto/__init__.py b/extensions/rcs_tacto/src/rcs_tacto/__init__.py index a5f830a2..bc8c296f 100644 --- a/extensions/rcs_tacto/src/rcs_tacto/__init__.py +++ b/extensions/rcs_tacto/src/rcs_tacto/__init__.py @@ -1 +1 @@ -__version__ = "0.7.1" +__version__ = "0.7.2" diff --git a/extensions/rcs_ur5e/pyproject.toml b/extensions/rcs_ur5e/pyproject.toml index 59cb36b3..bedef490 100644 --- a/extensions/rcs_ur5e/pyproject.toml +++ b/extensions/rcs_ur5e/pyproject.toml @@ -4,9 +4,9 @@ build-backend = "setuptools.build_meta" [project] name = "rcs_ur5e" -version = "0.7.1" +version = "0.7.2" description = "RCS UR5e module" -dependencies = ["rcs>=0.7.1", "ur_rtde==1.6.1"] +dependencies = ["rcs>=0.7.2", "ur_rtde==1.6.1"] readme = "README.md" maintainers = [ { name = "Johannes Hechtl", email = "johannes.hechtl@siemens.com" }, diff --git a/extensions/rcs_ur5e/src/rcs_ur5e/__init__.py b/extensions/rcs_ur5e/src/rcs_ur5e/__init__.py index 08d80bee..deee221c 100644 --- a/extensions/rcs_ur5e/src/rcs_ur5e/__init__.py +++ b/extensions/rcs_ur5e/src/rcs_ur5e/__init__.py @@ -1,6 +1,6 @@ from rcs_ur5e import configs, creators, hw -__version__ = "0.7.1" +__version__ = "0.7.2" __all__ = [ "configs", diff --git a/extensions/rcs_xarm7/pyproject.toml b/extensions/rcs_xarm7/pyproject.toml index 488b8c07..ec6902b4 100644 --- a/extensions/rcs_xarm7/pyproject.toml +++ b/extensions/rcs_xarm7/pyproject.toml @@ -4,9 +4,9 @@ build-backend = "setuptools.build_meta" [project] name = "rcs_xarm7" -version = "0.7.1" +version = "0.7.2" description = "RCS xArm7 module" -dependencies = ["rcs>=0.7.1", "xarm-python-sdk==1.17.0"] +dependencies = ["rcs>=0.7.2", "xarm-python-sdk==1.17.0"] readme = "README.md" maintainers = [ { name = "Tobias Jülg", email = "tobias.juelg@utn.de" }, diff --git a/extensions/rcs_xarm7/src/rcs_xarm7/__init__.py b/extensions/rcs_xarm7/src/rcs_xarm7/__init__.py index 7c0cb857..aea67f74 100644 --- a/extensions/rcs_xarm7/src/rcs_xarm7/__init__.py +++ b/extensions/rcs_xarm7/src/rcs_xarm7/__init__.py @@ -1,6 +1,6 @@ from rcs_xarm7 import configs, creators, hw -__version__ = "0.7.1" +__version__ = "0.7.2" __all__ = [ "configs", diff --git a/pyproject.toml b/pyproject.toml index 2ffc4658..e1f05d18 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,7 @@ build-backend = "scikit_build_core.build" [project] name = "rcs_core" -version = "0.7.1" +version = "0.7.2" description = "A lean, ROS-free sim-to-real framework for training and deploying Vision-Language-Action (VLA) models and RL agents. Native MuJoCo Gymnasium wrappers with synchronous execution for Franka, UR5e, xArm, and SO101." dependencies = [ "websockets>=11.0", diff --git a/python/rcs/_core/__init__.pyi b/python/rcs/_core/__init__.pyi index 7d6df81b..d1d5add8 100644 --- a/python/rcs/_core/__init__.pyi +++ b/python/rcs/_core/__init__.pyi @@ -16,4 +16,4 @@ from __future__ import annotations from . import common, sim __all__: list[str] = ["common", "sim"] -__version__: str = "0.7.1" +__version__: str = "0.8.0" From e6a1c10ee08855d41fcab073e992aed33a4b5a8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=BClg?= Date: Fri, 26 Jun 2026 12:05:55 -0700 Subject: [PATCH 07/15] build: rename rcs to rcs-core - fix rcs package name in extensions - added rcs as dependency in build process - improved robustness of downloading assets --- README.md | 10 ++++--- extensions/rcs_fr3/cmake/Findrcs.cmake | 29 ++++++++++++++----- extensions/rcs_fr3/pyproject.toml | 3 +- extensions/rcs_panda/cmake/Findrcs.cmake | 29 ++++++++++++++----- extensions/rcs_panda/pyproject.toml | 3 +- extensions/rcs_realsense/pyproject.toml | 2 +- .../rcs_robotics_library/cmake/Findrcs.cmake | 29 ++++++++++++++----- .../rcs_robotics_library/pyproject.toml | 3 +- extensions/rcs_robotiq2f85/pyproject.toml | 2 +- extensions/rcs_so101/cmake/Findrcs.cmake | 29 ++++++++++++++----- extensions/rcs_so101/pyproject.toml | 3 +- extensions/rcs_tacto/pyproject.toml | 2 +- extensions/rcs_ur5e/pyproject.toml | 2 +- extensions/rcs_xarm7/pyproject.toml | 2 +- pyproject.toml | 19 ++++++------ python/rcs/__init__.py | 6 +++- 16 files changed, 122 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index 8579cb4d..d6e9f722 100644 --- a/README.md +++ b/README.md @@ -148,8 +148,13 @@ pip install 'pip>=25.1' pip install --group build_deps # install rcs -pip install -ve . +pip install -ve . --no-build-isolation +``` + +### Via PyPI/pip +```shell +pip install rcs-core ``` ### RCS Asset Cache @@ -162,9 +167,6 @@ On import, RCS checks whether that path exists. If it does not, it downloads the export RCS_PREFIX=/path/to/rcs-assets ``` -### Via PyPI/pip - -*Coming soon...* ## 🦾 Hardware Extensions diff --git a/extensions/rcs_fr3/cmake/Findrcs.cmake b/extensions/rcs_fr3/cmake/Findrcs.cmake index 08456ccc..595d53bb 100644 --- a/extensions/rcs_fr3/cmake/Findrcs.cmake +++ b/extensions/rcs_fr3/cmake/Findrcs.cmake @@ -2,28 +2,43 @@ if (NOT rcs_FOUND) if (NOT Python3_FOUND) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs. Please install rcs using pip.") + message(FATAL_ERROR "Could not find rcs 1. Please install rcs-core using pip.") + endif() + return() + endif() + + execute_process( + COMMAND + ${Python3_EXECUTABLE} + -c + "import importlib.util; import pathlib; spec = importlib.util.find_spec('rcs'); print(pathlib.Path(next(iter(spec.submodule_search_locations))).resolve() if spec and spec.submodule_search_locations else '')" + OUTPUT_VARIABLE rcs_package_dir + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if (NOT rcs_package_dir) + set(rcs_FOUND FALSE) + if (rcs_FIND_REQUIRED) + message(FATAL_ERROR "Could not find rcs 2. Please install rcs-core using pip.") endif() return() endif() # Check if the include directory exists - cmake_path(APPEND Python3_SITELIB rcs include OUTPUT_VARIABLE rcs_INCLUDE_DIRS) + cmake_path(APPEND rcs_package_dir include OUTPUT_VARIABLE rcs_INCLUDE_DIRS) if (NOT EXISTS ${rcs_INCLUDE_DIRS}) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs. Please install rcs using pip.") + message(FATAL_ERROR "Could not find rcs 3. Please install rcs-core using pip.") endif() return() endif() # Check if the library file exists - cmake_path(APPEND Python3_SITELIB rcs OUTPUT_VARIABLE rcs_library_path) - file(GLOB rcs_library_path "${rcs_library_path}/librcs.so") + set(rcs_library_path "${rcs_package_dir}/librcs.so") if (NOT EXISTS ${rcs_library_path}) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs. Please install rcs using pip.") + message(FATAL_ERROR "Could not find rcs 4. Please install rcs-core using pip.") endif() return() endif() @@ -43,4 +58,4 @@ if (NOT rcs_FOUND) IMPORTED_LOCATION "${rcs_library_path}" ) set(rcs_FOUND TRUE) -endif() \ No newline at end of file +endif() diff --git a/extensions/rcs_fr3/pyproject.toml b/extensions/rcs_fr3/pyproject.toml index d62c3370..f8ff1cde 100644 --- a/extensions/rcs_fr3/pyproject.toml +++ b/extensions/rcs_fr3/pyproject.toml @@ -8,6 +8,7 @@ requires = [ "cmake", "ninja", "pin==3.7.0", + "rcs-core>=0.7.2", ] build-backend = "scikit_build_core.build" @@ -15,7 +16,7 @@ build-backend = "scikit_build_core.build" name = "rcs_fr3" version = "0.7.2" description = "RCS libfranka integration" -dependencies = ["rcs>=0.7.2", "frankik"] +dependencies = ["rcs-core>=0.7.2", "frankik"] readme = "README.md" maintainers = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] authors = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] diff --git a/extensions/rcs_panda/cmake/Findrcs.cmake b/extensions/rcs_panda/cmake/Findrcs.cmake index 08456ccc..595d53bb 100644 --- a/extensions/rcs_panda/cmake/Findrcs.cmake +++ b/extensions/rcs_panda/cmake/Findrcs.cmake @@ -2,28 +2,43 @@ if (NOT rcs_FOUND) if (NOT Python3_FOUND) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs. Please install rcs using pip.") + message(FATAL_ERROR "Could not find rcs 1. Please install rcs-core using pip.") + endif() + return() + endif() + + execute_process( + COMMAND + ${Python3_EXECUTABLE} + -c + "import importlib.util; import pathlib; spec = importlib.util.find_spec('rcs'); print(pathlib.Path(next(iter(spec.submodule_search_locations))).resolve() if spec and spec.submodule_search_locations else '')" + OUTPUT_VARIABLE rcs_package_dir + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if (NOT rcs_package_dir) + set(rcs_FOUND FALSE) + if (rcs_FIND_REQUIRED) + message(FATAL_ERROR "Could not find rcs 2. Please install rcs-core using pip.") endif() return() endif() # Check if the include directory exists - cmake_path(APPEND Python3_SITELIB rcs include OUTPUT_VARIABLE rcs_INCLUDE_DIRS) + cmake_path(APPEND rcs_package_dir include OUTPUT_VARIABLE rcs_INCLUDE_DIRS) if (NOT EXISTS ${rcs_INCLUDE_DIRS}) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs. Please install rcs using pip.") + message(FATAL_ERROR "Could not find rcs 3. Please install rcs-core using pip.") endif() return() endif() # Check if the library file exists - cmake_path(APPEND Python3_SITELIB rcs OUTPUT_VARIABLE rcs_library_path) - file(GLOB rcs_library_path "${rcs_library_path}/librcs.so") + set(rcs_library_path "${rcs_package_dir}/librcs.so") if (NOT EXISTS ${rcs_library_path}) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs. Please install rcs using pip.") + message(FATAL_ERROR "Could not find rcs 4. Please install rcs-core using pip.") endif() return() endif() @@ -43,4 +58,4 @@ if (NOT rcs_FOUND) IMPORTED_LOCATION "${rcs_library_path}" ) set(rcs_FOUND TRUE) -endif() \ No newline at end of file +endif() diff --git a/extensions/rcs_panda/pyproject.toml b/extensions/rcs_panda/pyproject.toml index 7194a38b..1d89f057 100644 --- a/extensions/rcs_panda/pyproject.toml +++ b/extensions/rcs_panda/pyproject.toml @@ -7,6 +7,7 @@ requires = [ "pybind11", "cmake", "ninja", + "rcs-core>=0.7.2", ] build-backend = "scikit_build_core.build" @@ -14,7 +15,7 @@ build-backend = "scikit_build_core.build" name = "rcs_panda" version = "0.7.2" description = "RCS libfranka integration" -dependencies = ["rcs>=0.7.2"] +dependencies = ["rcs-core>=0.7.2"] readme = "README.md" maintainers = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] authors = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] diff --git a/extensions/rcs_realsense/pyproject.toml b/extensions/rcs_realsense/pyproject.toml index addfbd8f..07817b81 100644 --- a/extensions/rcs_realsense/pyproject.toml +++ b/extensions/rcs_realsense/pyproject.toml @@ -7,7 +7,7 @@ name = "rcs_realsense" version = "0.7.2" description = "RCS realsense module" dependencies = [ - "rcs>=0.7.2", + "rcs-core>=0.7.2", "pyrealsense2~=2.55.1", "pupil_apriltags", "diskcache", diff --git a/extensions/rcs_robotics_library/cmake/Findrcs.cmake b/extensions/rcs_robotics_library/cmake/Findrcs.cmake index 08456ccc..595d53bb 100644 --- a/extensions/rcs_robotics_library/cmake/Findrcs.cmake +++ b/extensions/rcs_robotics_library/cmake/Findrcs.cmake @@ -2,28 +2,43 @@ if (NOT rcs_FOUND) if (NOT Python3_FOUND) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs. Please install rcs using pip.") + message(FATAL_ERROR "Could not find rcs 1. Please install rcs-core using pip.") + endif() + return() + endif() + + execute_process( + COMMAND + ${Python3_EXECUTABLE} + -c + "import importlib.util; import pathlib; spec = importlib.util.find_spec('rcs'); print(pathlib.Path(next(iter(spec.submodule_search_locations))).resolve() if spec and spec.submodule_search_locations else '')" + OUTPUT_VARIABLE rcs_package_dir + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if (NOT rcs_package_dir) + set(rcs_FOUND FALSE) + if (rcs_FIND_REQUIRED) + message(FATAL_ERROR "Could not find rcs 2. Please install rcs-core using pip.") endif() return() endif() # Check if the include directory exists - cmake_path(APPEND Python3_SITELIB rcs include OUTPUT_VARIABLE rcs_INCLUDE_DIRS) + cmake_path(APPEND rcs_package_dir include OUTPUT_VARIABLE rcs_INCLUDE_DIRS) if (NOT EXISTS ${rcs_INCLUDE_DIRS}) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs. Please install rcs using pip.") + message(FATAL_ERROR "Could not find rcs 3. Please install rcs-core using pip.") endif() return() endif() # Check if the library file exists - cmake_path(APPEND Python3_SITELIB rcs OUTPUT_VARIABLE rcs_library_path) - file(GLOB rcs_library_path "${rcs_library_path}/librcs.so") + set(rcs_library_path "${rcs_package_dir}/librcs.so") if (NOT EXISTS ${rcs_library_path}) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs. Please install rcs using pip.") + message(FATAL_ERROR "Could not find rcs 4. Please install rcs-core using pip.") endif() return() endif() @@ -43,4 +58,4 @@ if (NOT rcs_FOUND) IMPORTED_LOCATION "${rcs_library_path}" ) set(rcs_FOUND TRUE) -endif() \ No newline at end of file +endif() diff --git a/extensions/rcs_robotics_library/pyproject.toml b/extensions/rcs_robotics_library/pyproject.toml index a3a1079a..3be07bbf 100644 --- a/extensions/rcs_robotics_library/pyproject.toml +++ b/extensions/rcs_robotics_library/pyproject.toml @@ -7,6 +7,7 @@ requires = [ "pybind11", "cmake", "ninja", + "rcs-core>=0.7.2", ] build-backend = "scikit_build_core.build" @@ -15,7 +16,7 @@ name = "rcs_robotics_library" version = "0.7.2" description = "RCS robotics library integration" readme = "README.md" -dependencies = ["rcs>=0.7.2"] +dependencies = ["rcs-core>=0.7.2"] maintainers = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] authors = [ { name = "Tobias Jülg", email = "tobias.juelg@utn.de" }, diff --git a/extensions/rcs_robotiq2f85/pyproject.toml b/extensions/rcs_robotiq2f85/pyproject.toml index 6168b7bf..144fcae1 100644 --- a/extensions/rcs_robotiq2f85/pyproject.toml +++ b/extensions/rcs_robotiq2f85/pyproject.toml @@ -7,7 +7,7 @@ name = "rcs_robotiq2f85" version = "0.7.2" description="RCS RobotiQ module" dependencies = [ - "rcs>=0.7.2", + "rcs-core>=0.7.2", "2f85-python-driver @ git+https://github.com/RobotControlStack/2f85-python-driver.git", ] readme = "README.md" diff --git a/extensions/rcs_so101/cmake/Findrcs.cmake b/extensions/rcs_so101/cmake/Findrcs.cmake index 08456ccc..595d53bb 100644 --- a/extensions/rcs_so101/cmake/Findrcs.cmake +++ b/extensions/rcs_so101/cmake/Findrcs.cmake @@ -2,28 +2,43 @@ if (NOT rcs_FOUND) if (NOT Python3_FOUND) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs. Please install rcs using pip.") + message(FATAL_ERROR "Could not find rcs 1. Please install rcs-core using pip.") + endif() + return() + endif() + + execute_process( + COMMAND + ${Python3_EXECUTABLE} + -c + "import importlib.util; import pathlib; spec = importlib.util.find_spec('rcs'); print(pathlib.Path(next(iter(spec.submodule_search_locations))).resolve() if spec and spec.submodule_search_locations else '')" + OUTPUT_VARIABLE rcs_package_dir + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if (NOT rcs_package_dir) + set(rcs_FOUND FALSE) + if (rcs_FIND_REQUIRED) + message(FATAL_ERROR "Could not find rcs 2. Please install rcs-core using pip.") endif() return() endif() # Check if the include directory exists - cmake_path(APPEND Python3_SITELIB rcs include OUTPUT_VARIABLE rcs_INCLUDE_DIRS) + cmake_path(APPEND rcs_package_dir include OUTPUT_VARIABLE rcs_INCLUDE_DIRS) if (NOT EXISTS ${rcs_INCLUDE_DIRS}) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs. Please install rcs using pip.") + message(FATAL_ERROR "Could not find rcs 3. Please install rcs-core using pip.") endif() return() endif() # Check if the library file exists - cmake_path(APPEND Python3_SITELIB rcs OUTPUT_VARIABLE rcs_library_path) - file(GLOB rcs_library_path "${rcs_library_path}/librcs.so") + set(rcs_library_path "${rcs_package_dir}/librcs.so") if (NOT EXISTS ${rcs_library_path}) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs. Please install rcs using pip.") + message(FATAL_ERROR "Could not find rcs 4. Please install rcs-core using pip.") endif() return() endif() @@ -43,4 +58,4 @@ if (NOT rcs_FOUND) IMPORTED_LOCATION "${rcs_library_path}" ) set(rcs_FOUND TRUE) -endif() \ No newline at end of file +endif() diff --git a/extensions/rcs_so101/pyproject.toml b/extensions/rcs_so101/pyproject.toml index 41fe4559..7ea34566 100644 --- a/extensions/rcs_so101/pyproject.toml +++ b/extensions/rcs_so101/pyproject.toml @@ -7,6 +7,7 @@ requires = [ "pybind11", "cmake", "ninja", + "rcs-core>=0.7.2", ] build-backend = "scikit_build_core.build" @@ -14,7 +15,7 @@ build-backend = "scikit_build_core.build" name = "rcs_so101" version = "0.7.2" description = "RCS SO101 module" -dependencies = ["rcs>=0.7.2", "lerobot==0.3.3"] +dependencies = ["rcs-core>=0.7.2", "lerobot==0.3.3"] readme = "README.md" maintainers = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] authors = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] diff --git a/extensions/rcs_tacto/pyproject.toml b/extensions/rcs_tacto/pyproject.toml index 387f7bf3..fd7381a9 100644 --- a/extensions/rcs_tacto/pyproject.toml +++ b/extensions/rcs_tacto/pyproject.toml @@ -7,7 +7,7 @@ name = "rcs_tacto" version = "0.7.2" description = "RCS integration of tacto" dependencies = [ - "rcs>=0.7.2", + "rcs-core>=0.7.2", "omegaconf", "mujoco-tacto@git+https://github.com/utn-air/mujoco-tacto.git@main", ] diff --git a/extensions/rcs_ur5e/pyproject.toml b/extensions/rcs_ur5e/pyproject.toml index bedef490..5f3da01d 100644 --- a/extensions/rcs_ur5e/pyproject.toml +++ b/extensions/rcs_ur5e/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta" name = "rcs_ur5e" version = "0.7.2" description = "RCS UR5e module" -dependencies = ["rcs>=0.7.2", "ur_rtde==1.6.1"] +dependencies = ["rcs-core>=0.7.2", "ur_rtde==1.6.1"] readme = "README.md" maintainers = [ { name = "Johannes Hechtl", email = "johannes.hechtl@siemens.com" }, diff --git a/extensions/rcs_xarm7/pyproject.toml b/extensions/rcs_xarm7/pyproject.toml index ec6902b4..b8897e93 100644 --- a/extensions/rcs_xarm7/pyproject.toml +++ b/extensions/rcs_xarm7/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta" name = "rcs_xarm7" version = "0.7.2" description = "RCS xArm7 module" -dependencies = ["rcs>=0.7.2", "xarm-python-sdk==1.17.0"] +dependencies = ["rcs-core>=0.7.2", "xarm-python-sdk==1.17.0"] readme = "README.md" maintainers = [ { name = "Tobias Jülg", email = "tobias.juelg@utn.de" }, diff --git a/pyproject.toml b/pyproject.toml index e1f05d18..eda6ebd6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,6 +78,7 @@ build_deps = [ "pin==3.7.0", "cmeel-urdfdom<5", "cmeel-tinyxml2<11", + "scikit-build-core>=0.3.3", ] [tool.cibuildwheel] @@ -187,44 +188,44 @@ version_files = [ "extensions/rcs_fr3/src/rcs_fr3/_core/__init__.pyi:__version__", "extensions/rcs_fr3/pyproject.toml:version", # The line below updates the dependency string "rcs>=x.y.z" - "extensions/rcs_fr3/pyproject.toml:\"rcs>=(.*)\"", + "extensions/rcs_fr3/pyproject.toml:\"rcs-core>=(.*)\"", # --- Panda Extension --- "extensions/rcs_panda/CMakeLists.txt:VERSION", "extensions/rcs_panda/src/rcs_panda/_core/__init__.pyi:__version__", "extensions/rcs_panda/pyproject.toml:version", - "extensions/rcs_panda/pyproject.toml:\"rcs>=(.*)\"", + "extensions/rcs_panda/pyproject.toml:\"rcs-core>=(.*)\"", # --- Robotics Library --- "extensions/rcs_robotics_library/CMakeLists.txt:VERSION", "extensions/rcs_robotics_library/src/rcs_robotics_library/_core/__init__.pyi:__version__", "extensions/rcs_robotics_library/pyproject.toml:version", - "extensions/rcs_robotics_library/pyproject.toml:\"rcs>=(.*)\"", + "extensions/rcs_robotics_library/pyproject.toml:\"rcs-core>=(.*)\"", # --- SO101 --- "extensions/rcs_so101/CMakeLists.txt:VERSION", "extensions/rcs_so101/src/rcs_so101/_core/__init__.pyi:__version__", "extensions/rcs_so101/pyproject.toml:version", - "extensions/rcs_so101/pyproject.toml:\"rcs>=(.*)\"", + "extensions/rcs_so101/pyproject.toml:\"rcs-core>=(.*)\"", # --- Other Extensions --- "extensions/rcs_realsense/pyproject.toml:version", "extensions/rcs_realsense/src/rcs_realsense/__init__.py:__version__", - "extensions/rcs_realsense/pyproject.toml:\"rcs>=(.*)\"", + "extensions/rcs_realsense/pyproject.toml:\"rcs-core>=(.*)\"", "extensions/rcs_xarm7/pyproject.toml:version", "extensions/rcs_xarm7/src/rcs_xarm7/__init__.py:__version__", - "extensions/rcs_xarm7/pyproject.toml:\"rcs>=(.*)\"", + "extensions/rcs_xarm7/pyproject.toml:\"rcs-core>=(.*)\"", "extensions/rcs_ur5e/pyproject.toml:version", "extensions/rcs_ur5e/src/rcs_ur5e/__init__.py:__version__", - "extensions/rcs_ur5e/pyproject.toml:\"rcs>=(.*)\"", + "extensions/rcs_ur5e/pyproject.toml:\"rcs-core>=(.*)\"", "extensions/rcs_tacto/pyproject.toml:version", "extensions/rcs_tacto/src/rcs_tacto/__init__.py:__version__", - "extensions/rcs_tacto/pyproject.toml:\"rcs>=(.*)\"", + "extensions/rcs_tacto/pyproject.toml:\"rcs-core>=(.*)\"", "extensions/rcs_robotiq2f85/pyproject.toml:version", "extensions/rcs_robotiq2f85/src/rcs_robotiq2f85/__init__.py:__version__", - "extensions/rcs_robotiq2f85/pyproject.toml:\"rcs>=(.*)\"", + "extensions/rcs_robotiq2f85/pyproject.toml:\"rcs-core>=(.*)\"", ] diff --git a/python/rcs/__init__.py b/python/rcs/__init__.py index 459ebf0f..106ed229 100644 --- a/python/rcs/__init__.py +++ b/python/rcs/__init__.py @@ -15,6 +15,7 @@ from rcs import camera, envs, hand, sim GITHUB_ASSET_ARCHIVE_URL = "https://github.com/RobotControlStack/robot-control-stack/archive/refs/tags/{tag}.zip" +REQUIRED_ASSET = Path("assets/scenes/empty_world/scene.xml") def download_assets( @@ -56,6 +57,9 @@ def get_prefix( assets_dirname: str = "assets", download_fn: Callable[[str, Path, str, str], None] = download_assets, ) -> str: + def has_required_assets(prefix: Path) -> bool: + return (prefix / REQUIRED_ASSET).is_file() + if env_prefix: prefix = Path(env_prefix).expanduser().resolve() else: @@ -65,7 +69,7 @@ def get_prefix( prefix = default_prefix.resolve() assets_dir = prefix / assets_dirname - if not assets_dir.is_dir(): + if not assets_dir.is_dir() or not has_required_assets(prefix): prefix.mkdir(parents=True, exist_ok=True) print(f"Assets not found at {assets_dir}, downloading them now.") download_fn(version, prefix, github_asset_archive_url, assets_dirname) From a8498fa0e48134a4cdd613b8c516aa20659c5853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=BClg?= Date: Fri, 26 Jun 2026 13:01:31 -0700 Subject: [PATCH 08/15] ci: python wheel building --- .github/workflows/build_wheels.yaml | 100 ++++++++++++++++++++++++++ .github/workflows/ci.yaml | 2 +- extensions/rcs_usb_cam/pyproject.toml | 4 +- extensions/rcs_zed/pyproject.toml | 4 +- pyproject.toml | 8 +++ python/rcs/_core/__init__.pyi | 2 +- 6 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/build_wheels.yaml diff --git a/.github/workflows/build_wheels.yaml b/.github/workflows/build_wheels.yaml new file mode 100644 index 00000000..fc272ef1 --- /dev/null +++ b/.github/workflows/build_wheels.yaml @@ -0,0 +1,100 @@ +name: Build and Publish Wheels + +on: + workflow_dispatch: + release: + types: [published] + +jobs: + build_core_wheels: + name: Build core wheels + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Build core wheels + uses: pypa/cibuildwheel@v2.22.0 + env: + CIBW_ARCHS_LINUX: x86_64 + CIBW_BUILD: cp311-* cp312-* cp313-* + + - uses: actions/upload-artifact@v4 + with: + name: core-wheels + path: ./wheelhouse/*.whl + + build_extension_wheels: + name: Build ${{ matrix.extension }} wheels on Python ${{ matrix.python-version }} + needs: [build_core_wheels] + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.11", "3.12", "3.13"] + extension: + - rcs_fr3 + - rcs_panda + - rcs_robotics_library + - rcs_so101 + - rcs_realsense + - rcs_robotiq2f85 + - rcs_tacto + - rcs_ur5e + - rcs_usb_cam + - rcs_xarm7 + - rcs_zed + + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + name: core-wheels + path: dist/core + + - name: Install root Debian dependencies + run: | + sudo apt-get update + sudo xargs -a debian_deps.txt apt-get install -y + + - name: Install extension Debian dependencies + run: | + deps_file="extensions/${{ matrix.extension }}/debian_deps.txt" + if [ -f "${deps_file}" ]; then + sudo xargs -a "${deps_file}" apt-get install -y + fi + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + cache: pip + + - name: Build extension wheel + env: + PIP_FIND_LINKS: ${{ github.workspace }}/dist/core + run: | + python -m pip install --upgrade pip + python -m pip install build + python -m build --wheel "extensions/${{ matrix.extension }}" + + - uses: actions/upload-artifact@v4 + with: + name: wheels-${{ matrix.extension }}-py${{ matrix.python-version }} + path: extensions/${{ matrix.extension }}/dist/*.whl + + upload_pypi: + needs: [build_core_wheels, build_extension_wheels] + runs-on: ubuntu-latest + if: github.event_name == 'release' && github.event.action == 'published' + environment: pypi + permissions: + id-token: write + steps: + - uses: actions/download-artifact@v4 + with: + pattern: "*wheels*" + merge-multiple: true + path: dist + + - uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a439df47..b81d0fbb 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -141,7 +141,7 @@ jobs: - name: Install RCS run: pip install -ve . --group dev - name: Install extension - run: pip install -ve extensions/${{ matrix.extension }} + run: pip install -ve extensions/${{ matrix.extension }} --no-build-isolation - name: Check that stub files are up-to-date run: make -C extensions/${{ matrix.extension }} stubgen && git diff --exit-code - name: Check clang format diff --git a/extensions/rcs_usb_cam/pyproject.toml b/extensions/rcs_usb_cam/pyproject.toml index 4a39396b..fa365498 100644 --- a/extensions/rcs_usb_cam/pyproject.toml +++ b/extensions/rcs_usb_cam/pyproject.toml @@ -4,9 +4,9 @@ build-backend = "setuptools.build_meta" [project] name = "rcs_usb_cam" -version = "0.5.0" +version = "0.7.2" description = "RCS USB Camera module" -dependencies = ["rcs>=0.5.2", "opencv-python~=4.10.0"] +dependencies = ["rcs-core>=0.7.2", "opencv-python~=4.10.0"] maintainers = [ { name = "Tobias Jülg", email = "tobias.juelg@utn.de" }, { name = "Seongjin Bien", email = "seongjin.bien@utn.de" }, diff --git a/extensions/rcs_zed/pyproject.toml b/extensions/rcs_zed/pyproject.toml index 51694e69..89d3b851 100644 --- a/extensions/rcs_zed/pyproject.toml +++ b/extensions/rcs_zed/pyproject.toml @@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta" [project] name = "rcs_zed" -version = "0.6.3" +version = "0.7.2" description = "RCS ZED camera module" dependencies = [ - "rcs>=0.6.3", + "rcs-core>=0.7.2", "opencv-python~=4.10.0", "pupil_apriltags", "diskcache", diff --git a/pyproject.toml b/pyproject.toml index eda6ebd6..5bfb8d16 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -228,4 +228,12 @@ version_files = [ "extensions/rcs_robotiq2f85/pyproject.toml:version", "extensions/rcs_robotiq2f85/src/rcs_robotiq2f85/__init__.py:__version__", "extensions/rcs_robotiq2f85/pyproject.toml:\"rcs-core>=(.*)\"", + + "extensions/rcs_usb_cam/pyproject.toml:version", + "extensions/rcs_usb_cam/src/rcs_usb_cam/__init__.py:__version__", + "extensions/rcs_usb_cam/pyproject.toml:\"rcs-core>=(.*)\"", + + "extensions/rcs_zed/pyproject.toml:version", + "extensions/rcs_zed/src/rcs_zed/__init__.py:__version__", + "extensions/rcs_zed/pyproject.toml:\"rcs-core>=(.*)\"", ] diff --git a/python/rcs/_core/__init__.pyi b/python/rcs/_core/__init__.pyi index d1d5add8..5a27ade9 100644 --- a/python/rcs/_core/__init__.pyi +++ b/python/rcs/_core/__init__.pyi @@ -16,4 +16,4 @@ from __future__ import annotations from . import common, sim __all__: list[str] = ["common", "sim"] -__version__: str = "0.8.0" +__version__: str = "0.7.2" From c5bcf2786ffcd197385a75794bebcdf14f2fb96a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=BClg?= Date: Fri, 26 Jun 2026 16:04:43 -0700 Subject: [PATCH 09/15] docs: updated install instructions - updated install instructions - updated licenses and readmes --- README.md | 3 + docs/extensions/index.md | 2 + docs/extensions/overview.md | 11 ++- docs/extensions/rcs_fr3.md | 60 ++++++--------- docs/extensions/rcs_panda.md | 32 +++++++- docs/extensions/rcs_realsense.md | 10 ++- docs/extensions/rcs_robotics_library.md | 10 ++- docs/extensions/rcs_robotiq2f85.md | 11 ++- docs/extensions/rcs_so101.md | 9 ++- docs/extensions/rcs_tacto.md | 7 ++ docs/extensions/rcs_ur5e.md | 37 +++++++++ docs/extensions/rcs_usb_cam.md | 7 ++ docs/extensions/rcs_xarm7.md | 25 +++++- docs/extensions/rcs_zed.md | 27 +++++++ extensions/README.md | 10 ++- extensions/rcs_fr3/README.md | 77 ++++++++++++------- extensions/rcs_fr3/pyproject.toml | 1 + extensions/rcs_panda/README.md | 77 ++++++++++++------- extensions/rcs_panda/pyproject.toml | 1 + extensions/rcs_realsense/README.md | 34 +++++++- extensions/rcs_realsense/pyproject.toml | 2 + extensions/rcs_robotics_library/README.md | 37 ++++++++- .../rcs_robotics_library/pyproject.toml | 1 + extensions/rcs_robotiq2f85/README.md | 38 +++++++-- extensions/rcs_so101/README.md | 45 +++++++++-- extensions/rcs_so101/pyproject.toml | 1 + extensions/rcs_tacto/README.md | 35 +++++++-- extensions/rcs_tacto/pyproject.toml | 1 + extensions/rcs_ur5e/README.md | 56 ++++++++++++++ extensions/rcs_ur5e/pyproject.toml | 1 + extensions/rcs_usb_cam/README.md | 34 +++++++- extensions/rcs_usb_cam/pyproject.toml | 2 + extensions/rcs_xarm7/README.md | 49 ++++++++++++ extensions/rcs_xarm7/pyproject.toml | 1 + extensions/rcs_zed/README.md | 52 +++++++------ extensions/rcs_zed/pyproject.toml | 2 + 36 files changed, 649 insertions(+), 159 deletions(-) create mode 100644 docs/extensions/rcs_ur5e.md create mode 100644 docs/extensions/rcs_zed.md create mode 100644 extensions/rcs_ur5e/README.md create mode 100644 extensions/rcs_xarm7/README.md diff --git a/README.md b/README.md index d6e9f722..40cc1659 100644 --- a/README.md +++ b/README.md @@ -176,6 +176,9 @@ To install a specific robot extension (example for Franka FR3): ```shell sudo apt install $(cat extensions/rcs_fr3/debian_deps.txt) +pip install rcs-fr3 + +# or install it locally pip install -ve extensions/rcs_fr3 ``` diff --git a/docs/extensions/index.md b/docs/extensions/index.md index 58c0391e..6a6e19d0 100644 --- a/docs/extensions/index.md +++ b/docs/extensions/index.md @@ -7,10 +7,12 @@ overview rcs_fr3 rcs_panda rcs_xarm7 +rcs_ur5e rcs_so101 rcs_realsense rcs_usb_cam rcs_tacto rcs_robotics_library rcs_robotiq2f85 +rcs_zed ``` diff --git a/docs/extensions/overview.md b/docs/extensions/overview.md index 84334d4e..8494cba0 100644 --- a/docs/extensions/overview.md +++ b/docs/extensions/overview.md @@ -11,10 +11,17 @@ An extension is a separate Python package that integrates with RCS. Extensions c ## Installing Extensions -Extensions are typically installed via `pip`. +Extensions are typically installed from PyPI. ```shell -pip install -ve extensions/rcs_fr3 +pip install rcs-fr3 +``` + +For local development from a checkout of this repository, first install RCS itself from the repository root and then install the extension via its path: + +```shell +pip install -ve . --no-build-isolation +pip install -ve extensions/rcs_fr3 --no-build-isolation ``` ## Available Extensions diff --git a/docs/extensions/rcs_fr3.md b/docs/extensions/rcs_fr3.md index 4204c06d..865661f1 100644 --- a/docs/extensions/rcs_fr3.md +++ b/docs/extensions/rcs_fr3.md @@ -5,9 +5,15 @@ This extension provides support for the Franka Research 3 (FR3) robot in RCS. ## Installation ```shell -# from root directory sudo apt install $(cat extensions/rcs_fr3/debian_deps.txt) -pip install -ve extensions/rcs_fr3 +pip install rcs-fr3 +``` + +For local development from this repository: + +```shell +pip install -ve . --no-build-isolation +pip install -ve extensions/rcs_fr3 --no-build-isolation ``` ### Configuration @@ -22,41 +28,25 @@ DESK_PASSWORD=... ## Usage ```python -import rcs_fr3 -from rcs_fr3._core import hw -from rcs_fr3.desk import FCI, ContextManager, Desk, load_creds_franka_desk -import rcs -import numpy as np - -ROBOT_IP = "172.16.0.2" # Replace with your robot IP - -user, pw = load_creds_franka_desk() -with FCI(Desk(ROBOT_IP, user, pw), unlock=False, lock_when_done=False): - robot_meta = rcs.ROBOTS[rcs.common.RobotType.FR3] - ik = rcs.common.Pin(robot_meta.mjcf_model_path, robot_meta.attachment_site) - - # Configure Robot - robot = hw.Franka(ROBOT_IP, ik) - robot_cfg = hw.FR3Config() - robot_cfg.tcp_offset = rcs.common.Pose(rcs.common.FrankaHandTCPOffset()) - robot.set_config(robot_cfg) - - # Configure Gripper - gripper_cfg_hw = hw.FHConfig() - gripper_cfg_hw.epsilon_inner = gripper_cfg_hw.epsilon_outer = 0.1 - gripper_cfg_hw.speed = 0.1 - gripper_cfg_hw.force = 30 - gripper = hw.FrankaHand(ROBOT_IP, gripper_cfg_hw) - - # Move Robot - robot.set_cartesian_position( - robot.get_cartesian_position() * rcs.common.Pose(translation=np.array([0.05, 0, 0])) - ) - - # Grasp - gripper.grasp() +from rcs.envs.base import ControlMode, RelativeTo +from rcs_fr3.configs import DefaultFR3HardwareEnv + +env_creator = DefaultFR3HardwareEnv() +env_creator.ip = "192.168.101.1" + +cfg = env_creator.config() +cfg.control_mode = ControlMode.CARTESIAN_TQuat +cfg.camera_cfgs = None +cfg.max_relative_movement = 0.5 +cfg.relative_to = RelativeTo.LAST_STEP + +env = env_creator.create_env(cfg) +obs, info = env.reset() +print(env.get_wrapper_attr("robot").get_cartesian_position()) ``` +For a maintained example, see `examples/fr3/fr3_env_cartesian_control.py`. + ## CLI The extension defines useful commands to handle the FR3 robot without the need to use the Desk Website. diff --git a/docs/extensions/rcs_panda.md b/docs/extensions/rcs_panda.md index 21737704..7458d025 100644 --- a/docs/extensions/rcs_panda.md +++ b/docs/extensions/rcs_panda.md @@ -5,11 +5,35 @@ This extension provides support for the Franka Emika Panda robot in RCS. ## Installation ```shell -# from root directory -sudo apt install $(cat extensions/rcs_fr3/debian_deps.txt) -pip install -ve extensions/rcs_panda +sudo apt install $(cat extensions/rcs_panda/debian_deps.txt) +pip install rcs-panda +``` + +For local development from this repository: + +```shell +pip install -ve . --no-build-isolation +pip install -ve extensions/rcs_panda --no-build-isolation ``` ## Usage -Please refer to the `rcs_fr3` documentation for similar usage patterns, or check the examples in the repository. +```python +from rcs.envs.base import ControlMode, RelativeTo +from rcs_panda.configs import DefaultPandaHardwareEnv + +env_creator = DefaultPandaHardwareEnv() +env_creator.ip = "192.168.4.100" + +cfg = env_creator.config() +cfg.control_mode = ControlMode.CARTESIAN_TQuat +cfg.camera_cfgs = None +cfg.max_relative_movement = 0.2 +cfg.relative_to = RelativeTo.LAST_STEP + +env = env_creator.create_env(cfg) +obs, info = env.reset() +print(env.get_wrapper_attr("robot").get_cartesian_position()) +``` + +For a maintained example, see `extensions/rcs_panda/src/rcs_panda/panda_env_cartesian_control.py`. diff --git a/docs/extensions/rcs_realsense.md b/docs/extensions/rcs_realsense.md index 578b3373..e9db6cf0 100644 --- a/docs/extensions/rcs_realsense.md +++ b/docs/extensions/rcs_realsense.md @@ -5,11 +5,19 @@ This extension provides support for Intel RealSense cameras in RCS. ## Installation ```shell +pip install rcs-realsense +``` + +For local development: + +```shell +pip install -ve . --no-build-isolation pip install -ve extensions/rcs_realsense ``` ## CLI ```shell -python -m rcs_realsense --help +python -m rcs_realsense serials +python -m rcs_realsense rgb-view ``` diff --git a/docs/extensions/rcs_robotics_library.md b/docs/extensions/rcs_robotics_library.md index 2c6893e8..92dd54dd 100644 --- a/docs/extensions/rcs_robotics_library.md +++ b/docs/extensions/rcs_robotics_library.md @@ -5,7 +5,13 @@ This extension provides integration with the [Robotics Library (RL)](https://www ## Installation ```shell -# from root directory sudo apt install $(cat extensions/rcs_robotics_library/debian_deps.txt) -pip install -ve extensions/rcs_robotics_library +pip install rcs-robotics-library +``` + +For local development from this repository: + +```shell +pip install -ve . --no-build-isolation +pip install -ve extensions/rcs_robotics_library --no-build-isolation ``` diff --git a/docs/extensions/rcs_robotiq2f85.md b/docs/extensions/rcs_robotiq2f85.md index de0334e8..3a620b17 100644 --- a/docs/extensions/rcs_robotiq2f85.md +++ b/docs/extensions/rcs_robotiq2f85.md @@ -5,6 +5,13 @@ This extension provides support for Robotiq 2F-85 Gripper in RCS. ## Installation ```shell +pip install rcs-robotiq2f85 +``` + +For local development: + +```shell +pip install -ve . --no-build-isolation pip install -ve extensions/rcs_robotiq2f85 ``` @@ -20,9 +27,9 @@ chmod 777 /dev/ttyUSB0 ## Usage ```python -from rcs_robotiq2f85 import RobotiQGripper +from rcs_robotiq2f85 import RobotiQ2F85GripperConfig, RobotiQGripper -gripper = RobotiQGripper('') +gripper = RobotiQGripper(RobotiQ2F85GripperConfig(serial_number="")) gripper.reset() gripper.shut() print(gripper.get_normalized_width()) diff --git a/docs/extensions/rcs_so101.md b/docs/extensions/rcs_so101.md index 48576d05..bd058eb7 100644 --- a/docs/extensions/rcs_so101.md +++ b/docs/extensions/rcs_so101.md @@ -5,5 +5,12 @@ This extension provides support for the SO101 robot in RCS. ## Installation ```shell -pip install -ve extensions/rcs_so101 +pip install rcs-so101 +``` + +For local development from this repository: + +```shell +pip install -ve . --no-build-isolation +pip install -ve extensions/rcs_so101 --no-build-isolation ``` diff --git a/docs/extensions/rcs_tacto.md b/docs/extensions/rcs_tacto.md index a1b94112..104c5244 100644 --- a/docs/extensions/rcs_tacto.md +++ b/docs/extensions/rcs_tacto.md @@ -5,5 +5,12 @@ This extension provides integration with the [Tacto](https://github.com/facebook ## Installation ```shell +pip install rcs-tacto +``` + +For local development: + +```shell +pip install -ve . --no-build-isolation pip install -ve extensions/rcs_tacto ``` diff --git a/docs/extensions/rcs_ur5e.md b/docs/extensions/rcs_ur5e.md new file mode 100644 index 00000000..3070ddc2 --- /dev/null +++ b/docs/extensions/rcs_ur5e.md @@ -0,0 +1,37 @@ +# RCS UR5e Extension + +This extension provides support for the UR5e robot in RCS. + +## Installation + +```shell +pip install rcs-ur5e +``` + +For local development: + +```shell +pip install -ve . --no-build-isolation +pip install -ve extensions/rcs_ur5e +``` + +## Usage + +```python +from rcs.envs.base import ControlMode, RelativeTo +from rcs_ur5e.configs import DefaultUR5eHardwareEnv + +env_creator = DefaultUR5eHardwareEnv() +env_creator.ip = "192.168.1.15" + +cfg = env_creator.config() +cfg.control_mode = ControlMode.CARTESIAN_TQuat +cfg.camera_cfgs = None +cfg.max_relative_movement = 0.2 +cfg.relative_to = RelativeTo.LAST_STEP + +env = env_creator.create_env(cfg) +obs, info = env.reset() +``` + +For a maintained example, see `examples/ur5e/ur5e_env_cartesian_control.py`. diff --git a/docs/extensions/rcs_usb_cam.md b/docs/extensions/rcs_usb_cam.md index aaa27574..3f8f3dbc 100644 --- a/docs/extensions/rcs_usb_cam.md +++ b/docs/extensions/rcs_usb_cam.md @@ -5,5 +5,12 @@ This extension provides support for generic USB webcams in RCS. ## Installation ```shell +pip install rcs-usb-cam +``` + +For local development: + +```shell +pip install -ve . --no-build-isolation pip install -ve extensions/rcs_usb_cam ``` diff --git a/docs/extensions/rcs_xarm7.md b/docs/extensions/rcs_xarm7.md index 43449254..2dcbe801 100644 --- a/docs/extensions/rcs_xarm7.md +++ b/docs/extensions/rcs_xarm7.md @@ -5,9 +5,32 @@ This extension provides support for the xArm7 robot in RCS. ## Installation ```shell +pip install rcs-xarm7 +``` + +For local development: + +```shell +pip install -ve . --no-build-isolation pip install -ve extensions/rcs_xarm7 ``` ## Usage -Please refer to the examples in the repository for usage details. +```python +from rcs.envs.base import ControlMode, RelativeTo +from rcs_xarm7.configs import DefaultXArm7HardwareEnv + +env_creator = DefaultXArm7HardwareEnv() +env_creator.ip = "192.168.1.245" + +cfg = env_creator.config() +cfg.control_mode = ControlMode.CARTESIAN_TQuat +cfg.max_relative_movement = 0.5 +cfg.relative_to = RelativeTo.LAST_STEP + +env = env_creator.create_env(cfg) +obs, info = env.reset() +``` + +For a maintained example, see `examples/xarm7/xarm7_env_cartesian_control.py`. diff --git a/docs/extensions/rcs_zed.md b/docs/extensions/rcs_zed.md new file mode 100644 index 00000000..fcf7a5ee --- /dev/null +++ b/docs/extensions/rcs_zed.md @@ -0,0 +1,27 @@ +# RCS ZED Extension + +This extension provides support for Stereolabs ZED cameras in RCS. + +## Installation + +- You need a PC with an Nvidia GPU and CUDA 12.8 installed. +- Install the ZED SDK from Stereolabs. +- Install the Python bindings from `zed-python-api`. + +```shell +pip install rcs-zed +``` + +For local development: + +```shell +pip install -ve . --no-build-isolation +pip install -ve extensions/rcs_zed +``` + +## CLI + +```shell +python -m rcs_zed serials +python -m rcs_zed rgb-view +``` diff --git a/extensions/README.md b/extensions/README.md index 8cdb1ed6..f7021c0c 100644 --- a/extensions/README.md +++ b/extensions/README.md @@ -2,6 +2,14 @@ RCS supports various hardware extensions for robots and sensors. +All extensions depend on [`rcs-core`](https://pypi.org/project/rcs-core/). If you install an extension directly from PyPI, pip will pull the published `rcs-core` package automatically. + +For local development against this repository, install the main package first from the repository root: + +```shell +pip install -ve . --no-build-isolation +``` + For detailed documentation on available extensions and how to create your own, please visit: -**[robotcontrolstack.org/extensions](https://robotcontrolstack.org/extensions)** \ No newline at end of file +**[robotcontrolstack.org/extensions](https://robotcontrolstack.org/extensions)** diff --git a/extensions/rcs_fr3/README.md b/extensions/rcs_fr3/README.md index 27bb68ec..75d32926 100644 --- a/extensions/rcs_fr3/README.md +++ b/extensions/rcs_fr3/README.md @@ -1,49 +1,70 @@ -# RCS FR3 Hardware Extension -Extension to control the fr3 with rcs. +# RCS FR3 Extension + +Support for the Franka Research 3 (FR3) robot in RCS. + +This extension depends on [`rcs-core`](https://pypi.org/project/rcs-core/). +Documentation: ## Installation + +Install the Debian dependency first: + ```shell -# go to this directory sudo apt install $(cat debian_deps.txt) -pip install -ve . ``` -Add your FR3 credentials to a `.env` file like this: +Install from PyPI: + +```shell +pip install rcs-fr3 +``` + +Warning: plain `pip install rcs-fr3` will install the published `rcs-core` dependency from PyPI. + +Install from a local checkout for development: + +```shell +pip install -ve . --no-build-isolation +``` + +If you want this extension to use your local RCS checkout instead of the published `rcs-core` package, first install the main package from the repository root: + +```shell +pip install -ve . --no-build-isolation +pip install -ve extensions/rcs_fr3 --no-build-isolation +``` + +Add your FR3 Desk credentials to a `.env` file: + ```env DESK_USERNAME=... DESK_PASSWORD=... ``` ## Usage + ```python -import rcs_fr3 -from rcs_fr3._core import hw +from rcs.envs.base import ControlMode, RelativeTo from rcs_fr3.configs import DefaultFR3HardwareEnv -from rcs_fr3.desk import FCI, ContextManager, Desk, load_creds_franka_desk -user, pw = load_creds_franka_desk() -with FCI(Desk(ROBOT_IP, user, pw), unlock=False, lock_when_done=False): - creator = DefaultFR3HardwareEnv() - creator.ip = ROBOT_IP - cfg = creator.config() - ik = rcs.common.Pin(cfg.robot_cfg.kinematic_model_path, cfg.robot_cfg.attachment_site) - robot = hw.Franka(cfg.robot_cfg, ik) - gripper = hw.FrankaHand(cfg.gripper_cfg) - robot.set_cartesian_position( - robot.get_cartesian_position() * rcs.common.Pose(translation=np.array([0.05, 0, 0])) - ) - gripper.grasp() -``` -For more examples see the [examples](../../examples/) folder. -You can switch to hardware by setting the following flag: -```python -ROBOT_INSTANCE = RobotPlatform.HARDWARE -# ROBOT_INSTANCE = RobotPlatform.SIMULATION + +env_creator = DefaultFR3HardwareEnv() +env_creator.ip = "192.168.101.1" + +cfg = env_creator.config() +cfg.control_mode = ControlMode.CARTESIAN_TQuat +cfg.camera_cfgs = None +cfg.max_relative_movement = 0.5 +cfg.relative_to = RelativeTo.LAST_STEP + +env = env_creator.create_env(cfg) +obs, info = env.reset() +print(env.get_wrapper_attr("robot").get_cartesian_position()) ``` +For a maintained end-to-end example, see [examples/fr3/fr3_env_cartesian_control.py](../../examples/fr3/fr3_env_cartesian_control.py). ## CLI -Defines useful commands to handle the FR3 robot without the need to use the Desk Website. -You can see the available subcommands as follows: + ```shell python -m rcs_fr3 --help ``` diff --git a/extensions/rcs_fr3/pyproject.toml b/extensions/rcs_fr3/pyproject.toml index f8ff1cde..262aa987 100644 --- a/extensions/rcs_fr3/pyproject.toml +++ b/extensions/rcs_fr3/pyproject.toml @@ -18,6 +18,7 @@ version = "0.7.2" description = "RCS libfranka integration" dependencies = ["rcs-core>=0.7.2", "frankik"] readme = "README.md" +license = { text = "AGPL-3.0-or-later" } maintainers = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] authors = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] requires-python = ">=3.11" diff --git a/extensions/rcs_panda/README.md b/extensions/rcs_panda/README.md index 125f49ea..eda281a1 100644 --- a/extensions/rcs_panda/README.md +++ b/extensions/rcs_panda/README.md @@ -1,49 +1,70 @@ -# RCS Panda Hardware Extension -Extension to control the panda with rcs. +# RCS Panda Extension + +Support for the Franka Emika Panda robot in RCS. + +This extension depends on [`rcs-core`](https://pypi.org/project/rcs-core/). +Documentation: ## Installation + +Install the Debian dependency first: + ```shell -# go to this directory sudo apt install $(cat debian_deps.txt) -pip install -ve . ``` -Add your Panda credentials to a `.env` file like this: +Install from PyPI: + +```shell +pip install rcs-panda +``` + +Warning: plain `pip install rcs-panda` will install the published `rcs-core` dependency from PyPI. + +Install from a local checkout for development: + +```shell +pip install -ve . --no-build-isolation +``` + +If you want this extension to use your local RCS checkout instead of the published `rcs-core` package, first install the main package from the repository root: + +```shell +pip install -ve . --no-build-isolation +pip install -ve extensions/rcs_panda --no-build-isolation +``` + +Add your Panda Desk credentials to a `.env` file: + ```env DESK_USERNAME=... DESK_PASSWORD=... ``` ## Usage + ```python -import rcs_panda -from rcs_panda._core import hw +from rcs.envs.base import ControlMode, RelativeTo from rcs_panda.configs import DefaultPandaHardwareEnv -from rcs_panda.desk import FCI, ContextManager, Desk, load_creds_franka_desk -user, pw = load_creds_franka_desk() -with FCI(Desk(ROBOT_IP, user, pw), unlock=False, lock_when_done=False): - creator = DefaultPandaHardwareEnv() - creator.ip = ROBOT_IP - cfg = creator.config() - ik = rcs.common.Pin(cfg.robot_cfg.kinematic_model_path, cfg.robot_cfg.attachment_site) - robot = hw.Franka(cfg.robot_cfg, ik) - gripper = hw.FrankaHand(cfg.gripper_cfg) - robot.set_cartesian_position( - robot.get_cartesian_position() * rcs.common.Pose(translation=np.array([0.05, 0, 0])) - ) - gripper.grasp() -``` -For more examples see the [examples](../../examples/) folder. -You can switch to hardware by setting the following flag: -```python -ROBOT_INSTANCE = RobotPlatform.HARDWARE -# ROBOT_INSTANCE = RobotPlatform.SIMULATION + +env_creator = DefaultPandaHardwareEnv() +env_creator.ip = "192.168.4.100" + +cfg = env_creator.config() +cfg.control_mode = ControlMode.CARTESIAN_TQuat +cfg.camera_cfgs = None +cfg.max_relative_movement = 0.2 +cfg.relative_to = RelativeTo.LAST_STEP + +env = env_creator.create_env(cfg) +obs, info = env.reset() +print(env.get_wrapper_attr("robot").get_cartesian_position()) ``` +For a maintained example, see [src/rcs_panda/panda_env_cartesian_control.py](src/rcs_panda/panda_env_cartesian_control.py). ## CLI -Defines useful commands to handle the FR3 robot without the need to use the Desk Website. -You can see the available subcommands as follows: + ```shell python -m rcs_panda --help ``` diff --git a/extensions/rcs_panda/pyproject.toml b/extensions/rcs_panda/pyproject.toml index 1d89f057..75069022 100644 --- a/extensions/rcs_panda/pyproject.toml +++ b/extensions/rcs_panda/pyproject.toml @@ -17,6 +17,7 @@ version = "0.7.2" description = "RCS libfranka integration" dependencies = ["rcs-core>=0.7.2"] readme = "README.md" +license = { text = "AGPL-3.0-or-later" } maintainers = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] authors = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] requires-python = ">=3.11" diff --git a/extensions/rcs_realsense/README.md b/extensions/rcs_realsense/README.md index f0ad1dd4..662d58d8 100644 --- a/extensions/rcs_realsense/README.md +++ b/extensions/rcs_realsense/README.md @@ -1,10 +1,36 @@ -# RCS Realsense Cameras -Package installation: +# RCS RealSense Extension + +Support for Intel RealSense cameras in RCS. + +This extension depends on [`rcs-core`](https://pypi.org/project/rcs-core/). +Documentation: + +## Installation + +Install from PyPI: + +```shell +pip install rcs-realsense +``` + +Warning: plain `pip install rcs-realsense` will install the published `rcs-core` dependency from PyPI. + +Install from a local checkout: + ```shell pip install -ve . ``` -Usage: + +If you want this extension to use your local RCS checkout instead of the published `rcs-core` package, first install the main package from the repository root: + +```shell +pip install -ve . --no-build-isolation +pip install -ve extensions/rcs_realsense +``` + +## CLI + ```shell python -m rcs_realsense serials python -m rcs_realsense rgb-view -``` \ No newline at end of file +``` diff --git a/extensions/rcs_realsense/pyproject.toml b/extensions/rcs_realsense/pyproject.toml index 07817b81..7c8b5f33 100644 --- a/extensions/rcs_realsense/pyproject.toml +++ b/extensions/rcs_realsense/pyproject.toml @@ -6,6 +6,8 @@ build-backend = "setuptools.build_meta" name = "rcs_realsense" version = "0.7.2" description = "RCS realsense module" +readme = "README.md" +license = { text = "AGPL-3.0-or-later" } dependencies = [ "rcs-core>=0.7.2", "pyrealsense2~=2.55.1", diff --git a/extensions/rcs_robotics_library/README.md b/extensions/rcs_robotics_library/README.md index 96069664..600e55a6 100644 --- a/extensions/rcs_robotics_library/README.md +++ b/extensions/rcs_robotics_library/README.md @@ -1,12 +1,41 @@ -# RCS Extension for the Robotics Library -Implements access to the C++ library "Robotics Library". +# RCS Robotics Library Extension + +Integration with the [Robotics Library (RL)](https://www.roboticslibrary.org/) for kinematics and path planning. + +This extension depends on [`rcs-core`](https://pypi.org/project/rcs-core/). +Documentation: ## Installation + +Install the Debian dependencies first: + ```shell -# go to this directory sudo apt install $(cat debian_deps.txt) -pip install -ve . +``` + +Install from PyPI: + +```shell +pip install rcs-robotics-library +``` + +Warning: plain `pip install rcs-robotics-library` will install the published `rcs-core` dependency from PyPI. + +Install from a local checkout for development: + +```shell +pip install -ve . --no-build-isolation +``` + +If you want this extension to use your local RCS checkout instead of the published `rcs-core` package, first install the main package from the repository root: + +```shell +pip install -ve . --no-build-isolation +pip install -ve extensions/rcs_robotics_library --no-build-isolation ``` ## Usage +```python +from rcs_robotics_library import rl +``` diff --git a/extensions/rcs_robotics_library/pyproject.toml b/extensions/rcs_robotics_library/pyproject.toml index 3be07bbf..5e88dabb 100644 --- a/extensions/rcs_robotics_library/pyproject.toml +++ b/extensions/rcs_robotics_library/pyproject.toml @@ -16,6 +16,7 @@ name = "rcs_robotics_library" version = "0.7.2" description = "RCS robotics library integration" readme = "README.md" +license = { text = "AGPL-3.0-or-later" } dependencies = ["rcs-core>=0.7.2"] maintainers = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] authors = [ diff --git a/extensions/rcs_robotiq2f85/README.md b/extensions/rcs_robotiq2f85/README.md index 3522d8ca..21afb65e 100644 --- a/extensions/rcs_robotiq2f85/README.md +++ b/extensions/rcs_robotiq2f85/README.md @@ -1,28 +1,52 @@ -# RCS Robotiq 2F-85 Gripper Hardware Extension -Extension to use the Robotiq 2F-85 Gripper with rcs. +# RCS Robotiq 2F-85 Extension + +Support for the Robotiq 2F-85 gripper in RCS. + +This extension depends on [`rcs-core`](https://pypi.org/project/rcs-core/). +Documentation: ## Installation + +Install from PyPI: + +```shell +pip install rcs-robotiq2f85 +``` + +Warning: plain `pip install rcs-robotiq2f85` will install the published `rcs-core` dependency from PyPI. + +Install from a local checkout: + ```shell pip install -ve . ``` -Get the serial number of the gripper with this command: +If you want this extension to use your local RCS checkout instead of the published `rcs-core` package, first install the main package from the repository root: + +```shell +pip install -ve . --no-build-isolation +pip install -ve extensions/rcs_robotiq2f85 +``` + +Get the serial number of the gripper: + ```shell udevadm info -a -n /dev/ttyUSB0 | grep serial ``` -Provide the necessary permission: +Provide device permissions if needed: + ```shell chmod 777 /dev/ttyUSB0 ``` ## Usage + ```python -from rcs_robotiq2f85 import RobotiQGripper, RobotiQ2F85GripperConfig +from rcs_robotiq2f85 import RobotiQ2F85GripperConfig, RobotiQGripper -gripper = RobotiQGripper(RobotiQ2F85GripperConfig(serial_number='')) +gripper = RobotiQGripper(RobotiQ2F85GripperConfig(serial_number="")) gripper.reset() gripper.shut() print(gripper.get_normalized_width()) ``` - diff --git a/extensions/rcs_so101/README.md b/extensions/rcs_so101/README.md index c0333f8b..aec667dd 100644 --- a/extensions/rcs_so101/README.md +++ b/extensions/rcs_so101/README.md @@ -1,13 +1,42 @@ # RCS SO101 Extension -## Package Dependency Issue Workaround -The extension for SO101 depends on the `lerobot` package, which depends on `opencv-python-headless`, which uninstalls RCS' own `opencv-python` dependency install. -Since the extension doesn't care about the OpenCV-dependent parts of `lerobot`, this package works fine even with the full `opencv-python`, but it needs to be re-installed manually. -You can do it by the following: +Support for the SO101 robot in RCS. + +This extension depends on [`rcs-core`](https://pypi.org/project/rcs-core/). +Documentation: + +## Installation + +Install from PyPI: + +```shell +pip install rcs-so101 +``` + +Warning: plain `pip install rcs-so101` will install the published `rcs-core` dependency from PyPI. + +Install from a local checkout for development: + +```shell +pip install -ve . --no-build-isolation ``` -pip uninstall opencv-python-headless -pip uninstall opencv-python + +If you want this extension to use your local RCS checkout instead of the published `rcs-core` package, first install the main package from the repository root: + +```shell +pip install -ve . --no-build-isolation +pip install -ve extensions/rcs_so101 --no-build-isolation +``` + +## OpenCV Workaround + +This extension depends on `lerobot`, which can pull in `opencv-python-headless` and replace the `opencv-python` variant expected by RCS. + +If that happens, reinstall OpenCV like this: + +```shell +pip uninstall -y opencv-python-headless opencv-python pip install opencv-python~=4.10.0.84 ``` -which will reinstall the correct version of OpenCV to the environment. -Unfortunately, there's no easy automated solution for it, so it needs to be done manually each time this extension is installed with `pip install -e .`. \ No newline at end of file + +For current examples, see [examples/so101](../../examples/so101). diff --git a/extensions/rcs_so101/pyproject.toml b/extensions/rcs_so101/pyproject.toml index 7ea34566..2a3c45aa 100644 --- a/extensions/rcs_so101/pyproject.toml +++ b/extensions/rcs_so101/pyproject.toml @@ -17,6 +17,7 @@ version = "0.7.2" description = "RCS SO101 module" dependencies = ["rcs-core>=0.7.2", "lerobot==0.3.3"] readme = "README.md" +license = { text = "AGPL-3.0-or-later" } maintainers = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] authors = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] requires-python = ">=3.11" diff --git a/extensions/rcs_tacto/README.md b/extensions/rcs_tacto/README.md index 3951f76e..b48e0414 100644 --- a/extensions/rcs_tacto/README.md +++ b/extensions/rcs_tacto/README.md @@ -1,8 +1,33 @@ -# TACTO integration for RCS -This package can be installed by running `pip install -e extensions/rcs_tacto` from the RCS repository root. +# RCS Tacto Extension -An example on how to create the environment is found in `{REPO_ROOT}/examples/grasp_digit_demo.py`. +Integration with the Tacto tactile sensor simulator. -Particularly, take a look at `FR3TactoSimplePickUpSimEnvCreator` to understand how Tacto is inserted into the RCS stack. +This extension depends on [`rcs-core`](https://pypi.org/project/rcs-core/). +Documentation: -Note that it is rather tricky to get the correct contact simulation settings to allow for a robust grasping of objects, so when using it, you will need to play around with the simulation settings. We recommend taking a look at the corresponding [MuJoCo documentation](https://mujoco.readthedocs.io/en/stable/computation/index.html) for more tips. \ No newline at end of file +## Installation + +Install from PyPI: + +```shell +pip install rcs-tacto +``` + +Warning: plain `pip install rcs-tacto` will install the published `rcs-core` dependency from PyPI. + +Install from a local checkout: + +```shell +pip install -ve . +``` + +If you want this extension to use your local RCS checkout instead of the published `rcs-core` package, first install the main package from the repository root: + +```shell +pip install -ve . --no-build-isolation +pip install -ve extensions/rcs_tacto +``` + +An example environment is available in [examples/fr3/grasp_digit_demo.py](../../examples/fr3/grasp_digit_demo.py). + +In particular, `FR3TactoSimplePickUpSimEnvCreator` shows how Tacto is integrated into the RCS stack. diff --git a/extensions/rcs_tacto/pyproject.toml b/extensions/rcs_tacto/pyproject.toml index fd7381a9..c31bc919 100644 --- a/extensions/rcs_tacto/pyproject.toml +++ b/extensions/rcs_tacto/pyproject.toml @@ -12,6 +12,7 @@ dependencies = [ "mujoco-tacto@git+https://github.com/utn-air/mujoco-tacto.git@main", ] readme = "README.md" +license = { text = "AGPL-3.0-or-later" } maintainers = [ { name = "Tobias Jülg", email = "tobias.juelg@utn.de" }, { name = "Seongjin Bien", email = "seongjin.bien@utn.de" }, diff --git a/extensions/rcs_ur5e/README.md b/extensions/rcs_ur5e/README.md new file mode 100644 index 00000000..c9babe22 --- /dev/null +++ b/extensions/rcs_ur5e/README.md @@ -0,0 +1,56 @@ +# RCS UR5e Extension + +Support for the UR5e robot in RCS. + +This extension depends on [`rcs-core`](https://pypi.org/project/rcs-core/). +Documentation: + +## Installation + +Install from PyPI: + +```shell +pip install rcs-ur5e +``` + +Warning: plain `pip install rcs-ur5e` will install the published `rcs-core` dependency from PyPI. + +Install from a local checkout: + +```shell +pip install -ve . +``` + +If you want this extension to use your local RCS checkout instead of the published `rcs-core` package, first install the main package from the repository root: + +```shell +pip install -ve . --no-build-isolation +pip install -ve extensions/rcs_ur5e +``` + +## Safety Notes + +- This controller does not implement compliant force control. +- Verify the configured home pose before moving real hardware. +- Start at low speed and only increase after confirming motion is safe. + +## Usage + +```python +from rcs.envs.base import ControlMode, RelativeTo +from rcs_ur5e.configs import DefaultUR5eHardwareEnv + +env_creator = DefaultUR5eHardwareEnv() +env_creator.ip = "192.168.1.15" + +cfg = env_creator.config() +cfg.control_mode = ControlMode.CARTESIAN_TQuat +cfg.camera_cfgs = None +cfg.max_relative_movement = 0.2 +cfg.relative_to = RelativeTo.LAST_STEP + +env = env_creator.create_env(cfg) +obs, info = env.reset() +``` + +For a maintained example, see [examples/ur5e/ur5e_env_cartesian_control.py](../../examples/ur5e/ur5e_env_cartesian_control.py). diff --git a/extensions/rcs_ur5e/pyproject.toml b/extensions/rcs_ur5e/pyproject.toml index 5f3da01d..efad4cc9 100644 --- a/extensions/rcs_ur5e/pyproject.toml +++ b/extensions/rcs_ur5e/pyproject.toml @@ -8,6 +8,7 @@ version = "0.7.2" description = "RCS UR5e module" dependencies = ["rcs-core>=0.7.2", "ur_rtde==1.6.1"] readme = "README.md" +license = { text = "AGPL-3.0-or-later" } maintainers = [ { name = "Johannes Hechtl", email = "johannes.hechtl@siemens.com" }, ] diff --git a/extensions/rcs_usb_cam/README.md b/extensions/rcs_usb_cam/README.md index efa94a5b..5ed35c55 100644 --- a/extensions/rcs_usb_cam/README.md +++ b/extensions/rcs_usb_cam/README.md @@ -1,9 +1,35 @@ -# RCS USC Cameras -Package installation: +# RCS USB Camera Extension + +Support for generic USB webcams in RCS. + +This extension depends on [`rcs-core`](https://pypi.org/project/rcs-core/). +Documentation: + +## Installation + +Install from PyPI: + +```shell +pip install rcs-usb-cam +``` + +Warning: plain `pip install rcs-usb-cam` will install the published `rcs-core` dependency from PyPI. + +Install from a local checkout: + ```shell pip install -ve . ``` -Usage: + +If you want this extension to use your local RCS checkout instead of the published `rcs-core` package, first install the main package from the repository root: + +```shell +pip install -ve . --no-build-isolation +pip install -ve extensions/rcs_usb_cam +``` + +## CLI + ```shell python -m rcs_usb_cam rgb-view -``` \ No newline at end of file +``` diff --git a/extensions/rcs_usb_cam/pyproject.toml b/extensions/rcs_usb_cam/pyproject.toml index fa365498..b2426094 100644 --- a/extensions/rcs_usb_cam/pyproject.toml +++ b/extensions/rcs_usb_cam/pyproject.toml @@ -6,6 +6,8 @@ build-backend = "setuptools.build_meta" name = "rcs_usb_cam" version = "0.7.2" description = "RCS USB Camera module" +readme = "README.md" +license = { text = "AGPL-3.0-or-later" } dependencies = ["rcs-core>=0.7.2", "opencv-python~=4.10.0"] maintainers = [ { name = "Tobias Jülg", email = "tobias.juelg@utn.de" }, diff --git a/extensions/rcs_xarm7/README.md b/extensions/rcs_xarm7/README.md new file mode 100644 index 00000000..4d4e325b --- /dev/null +++ b/extensions/rcs_xarm7/README.md @@ -0,0 +1,49 @@ +# RCS xArm7 Extension + +Support for the xArm7 robot in RCS. + +This extension depends on [`rcs-core`](https://pypi.org/project/rcs-core/). +Documentation: + +## Installation + +Install from PyPI: + +```shell +pip install rcs-xarm7 +``` + +Warning: plain `pip install rcs-xarm7` will install the published `rcs-core` dependency from PyPI. + +Install from a local checkout: + +```shell +pip install -ve . +``` + +If you want this extension to use your local RCS checkout instead of the published `rcs-core` package, first install the main package from the repository root: + +```shell +pip install -ve . --no-build-isolation +pip install -ve extensions/rcs_xarm7 +``` + +## Usage + +```python +from rcs.envs.base import ControlMode, RelativeTo +from rcs_xarm7.configs import DefaultXArm7HardwareEnv + +env_creator = DefaultXArm7HardwareEnv() +env_creator.ip = "192.168.1.245" + +cfg = env_creator.config() +cfg.control_mode = ControlMode.CARTESIAN_TQuat +cfg.max_relative_movement = 0.5 +cfg.relative_to = RelativeTo.LAST_STEP + +env = env_creator.create_env(cfg) +obs, info = env.reset() +``` + +For a maintained example, see [examples/xarm7/xarm7_env_cartesian_control.py](../../examples/xarm7/xarm7_env_cartesian_control.py). diff --git a/extensions/rcs_xarm7/pyproject.toml b/extensions/rcs_xarm7/pyproject.toml index b8897e93..af0fce1d 100644 --- a/extensions/rcs_xarm7/pyproject.toml +++ b/extensions/rcs_xarm7/pyproject.toml @@ -8,6 +8,7 @@ version = "0.7.2" description = "RCS xArm7 module" dependencies = ["rcs-core>=0.7.2", "xarm-python-sdk==1.17.0"] readme = "README.md" +license = { text = "AGPL-3.0-or-later" } maintainers = [ { name = "Tobias Jülg", email = "tobias.juelg@utn.de" }, { name = "Ken Nakahara", email = "knakahara@lasr.org" }, diff --git a/extensions/rcs_zed/README.md b/extensions/rcs_zed/README.md index 6352d1e6..495c02c8 100644 --- a/extensions/rcs_zed/README.md +++ b/extensions/rcs_zed/README.md @@ -1,43 +1,51 @@ -# Zed Camera Extension +# RCS ZED Extension + +Support for Stereolabs ZED cameras in RCS. + +This extension depends on [`rcs-core`](https://pypi.org/project/rcs-core/). +Documentation: ## Installation -- You need a PC with an Nvidia GPU and CUDA 12.8 installed (12.x is probably fine) -- Download and install the Zed SDK from [here](https://www.stereolabs.com/en-fr/developers/release) -- Install the python bindings with the manual [here](https://github.com/stereolabs/zed-python-api) -Or just use the docker shipped with RCS. Checkout [this readme](../../docker/README.md) to build and start the docker. The tools shown below are available inside the docer container. +- You need a PC with an Nvidia GPU and CUDA 12.8 installed. +- Install the ZED SDK from [Stereolabs](https://www.stereolabs.com/en-fr/developers/release). +- Install the Python bindings from the [zed-python-api](https://github.com/stereolabs/zed-python-api). + +Install from PyPI: + +```shell +pip install rcs-zed +``` + +Warning: plain `pip install rcs-zed` will install the published `rcs-core` dependency from PyPI. + +Install from a local checkout: -Package installation: ```shell pip install -ve . ``` +If you want this extension to use your local RCS checkout instead of the published `rcs-core` package, first install the main package from the repository root: -## Usage +```shell +pip install -ve . --no-build-isolation +pip install -ve extensions/rcs_zed +``` +## CLI ```shell python -m rcs_zed serials python -m rcs_zed rgb-view ``` -### Permissions +## Permissions + ```shell -# if in docker, run this on your host system sudo usermod -a -G video,plugdev $USER ``` -### Tools to check your Zed -Most relevant is the `ZED_Diagnostic`, use this to check what exactly is not working. - -| Command / Tool | What it does | When to use it | -| :--- | :--- | :--- | -| **`ZED_Explorer`** | Live video feed & recording | To check image quality, adjust exposure, and record **.SVO** files. | -| **`ZED_Depth_Viewer`** | 3D Depth & Point Cloud | To see the "Neural" depth in action and check 3D accuracy. | -| **`ZED_Diagnostic`** | Hardware/Software Health | Use this first if something feels "broken." | -| **`ZED_Sensor_Viewer`** | IMU & Magnetometer | To see real-time data from the accelerometer and gyroscope. | -| **`ZED_Studio`** | Multi-Camera Management | If you have more than one ZED connected at once. | -| **`ZEDfu`** | Spatial Mapping | To "scan" a room and create a 3D mesh in real-time. | +## Connection Diagnostics -### Issues with the connection -- see [this article](https://support.stereolabs.com/hc/en-us/articles/207635225-How-to-fix-USB-3-0-bandwidth-and-connection-issues) \ No newline at end of file +- Use `ZED_Diagnostic` first if something appears broken. +- See the Stereolabs USB troubleshooting guide: diff --git a/extensions/rcs_zed/pyproject.toml b/extensions/rcs_zed/pyproject.toml index 89d3b851..c6bc05c8 100644 --- a/extensions/rcs_zed/pyproject.toml +++ b/extensions/rcs_zed/pyproject.toml @@ -6,6 +6,8 @@ build-backend = "setuptools.build_meta" name = "rcs_zed" version = "0.7.2" description = "RCS ZED camera module" +readme = "README.md" +license = { text = "AGPL-3.0-or-later" } dependencies = [ "rcs-core>=0.7.2", "opencv-python~=4.10.0", From 4a1510a0eb0bcfacaf0af885eadd9f799bf227fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=BClg?= Date: Fri, 26 Jun 2026 16:44:26 -0700 Subject: [PATCH 10/15] docs: added libfranka version documentation --- README.md | 17 ++++++++--------- docs/extensions/index.md | 1 + docs/extensions/libfranka_versions.md | 18 ++++++++++++++++++ extensions/rcs_fr3/README.md | 2 ++ extensions/rcs_fr3/pyproject.toml | 3 +++ extensions/rcs_panda/README.md | 2 ++ extensions/rcs_panda/pyproject.toml | 3 +++ 7 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 docs/extensions/libfranka_versions.md diff --git a/README.md b/README.md index 40cc1659..3d8c35f2 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,13 @@ if __name__ == "__main__": > **Note:** This and other examples can be found in the [`examples/`]() folder. ## 🛠️ Installation +* *For Python >3.11: The `rcs_realsense` extension won't work due to the `pyrealsense2` version RCS utilizes.* +* *For Python >3.12: The `ompl` python module is currently not available on PyPI. If OMPL is not used, it is safe to remove this dependency in `pyproject.toml`.* +### Via PyPI/pip + +```shell +pip install rcs-core +``` ### From Source @@ -129,11 +136,7 @@ Make sure that common build tools (i.e., `build-essential`) and a C++ compiler l *RCS works best in Python 3.11, and all extensions have been tested to work in 3.11.* -* *For Python >3.11: The `rcs_realsense` extension won't work due to the `pyrealsense2` version RCS utilizes.* -* *For Python >3.12: The `ompl` python module is currently not available on PyPI. If OMPL is not used, it is safe to remove this dependency in `pyproject.toml`.* - ```shell - # clone repository git clone https://github.com/RobotControlStack/robot-control-stack.git cd robot-control-stack @@ -151,11 +154,6 @@ pip install --group build_deps pip install -ve . --no-build-isolation ``` -### Via PyPI/pip - -```shell -pip install rcs-core -``` ### RCS Asset Cache @@ -198,6 +196,7 @@ For full documentation, including advanced installation, modular usage, and API Useful quick-reference pages: - **[RCS Conventions](https://robotcontrolstack.org/user_guide/conventions)** for quaternion order, frames, Euler angles, and gripper semantics - **[Sim Scene Configuration](https://robotcontrolstack.org/user_guide/scene_configuration)** for `SimEnvCreatorConfig`, scene frames, and example setup patterns +- **[libfranka Version Info](https://robotcontrolstack.org/extensions/libfranka_versions)** for the currently pinned `rcs_fr3` and `rcs_panda` `libfranka` versions and local-install guidance ## 🤝 Contribution diff --git a/docs/extensions/index.md b/docs/extensions/index.md index 6a6e19d0..67ce5944 100644 --- a/docs/extensions/index.md +++ b/docs/extensions/index.md @@ -4,6 +4,7 @@ :maxdepth: 2 overview +libfranka_versions rcs_fr3 rcs_panda rcs_xarm7 diff --git a/docs/extensions/libfranka_versions.md b/docs/extensions/libfranka_versions.md new file mode 100644 index 00000000..9a465221 --- /dev/null +++ b/docs/extensions/libfranka_versions.md @@ -0,0 +1,18 @@ +# libfranka Versions + +This page documents the `libfranka` version currently pinned by the RCS Franka extensions in their CMake configuration. + +## `rcs_fr3` + +- Current `libfranka` version: `0.20.3` +- CMake source: [extensions/rcs_fr3/CMakeLists.txt](https://github.com/RobotControlStack/robot-control-stack/blob/main/extensions/rcs_fr3/CMakeLists.txt) +- Note: this information reflects the current CMake pin and may become outdated if the version is bumped in a future change. + +When installing `rcs-fr3` from PyPI, this `libfranka` version is fixed by the published package. If you need to change the `libfranka` version, use a local source install and update the CMake configuration there. + +## `rcs_panda` + +- Current `libfranka` version: `0.9.2` +- CMake source: [extensions/rcs_panda/CMakeLists.txt](https://github.com/RobotControlStack/robot-control-stack/blob/main/extensions/rcs_panda/CMakeLists.txt) + +When installing `rcs-panda` from PyPI, this `libfranka` version is fixed by the published package. If you need to change the `libfranka` version, use a local source install and update the CMake configuration there. diff --git a/extensions/rcs_fr3/README.md b/extensions/rcs_fr3/README.md index 75d32926..2a4eb2ba 100644 --- a/extensions/rcs_fr3/README.md +++ b/extensions/rcs_fr3/README.md @@ -34,6 +34,8 @@ pip install -ve . --no-build-isolation pip install -ve extensions/rcs_fr3 --no-build-isolation ``` +For `libfranka` version details, see . + Add your FR3 Desk credentials to a `.env` file: ```env diff --git a/extensions/rcs_fr3/pyproject.toml b/extensions/rcs_fr3/pyproject.toml index 262aa987..2b71c80f 100644 --- a/extensions/rcs_fr3/pyproject.toml +++ b/extensions/rcs_fr3/pyproject.toml @@ -32,6 +32,9 @@ build-dir = "build" wheel.packages = ["src/rcs_fr3"] install.components = ["python_package"] +[tool.cibuildwheel] +skip = ["cp314*", "*-musllinux*"] + [tool.black] line-length = 120 target-version = ["py310"] diff --git a/extensions/rcs_panda/README.md b/extensions/rcs_panda/README.md index eda281a1..b1581269 100644 --- a/extensions/rcs_panda/README.md +++ b/extensions/rcs_panda/README.md @@ -34,6 +34,8 @@ pip install -ve . --no-build-isolation pip install -ve extensions/rcs_panda --no-build-isolation ``` +For `libfranka` version details, see . + Add your Panda Desk credentials to a `.env` file: ```env diff --git a/extensions/rcs_panda/pyproject.toml b/extensions/rcs_panda/pyproject.toml index 75069022..6fee796e 100644 --- a/extensions/rcs_panda/pyproject.toml +++ b/extensions/rcs_panda/pyproject.toml @@ -31,6 +31,9 @@ build-dir = "build" wheel.packages = ["src/rcs_panda"] install.components = ["python_package"] +[tool.cibuildwheel] +skip = ["cp314*", "*-musllinux*"] + [tool.black] line-length = 120 target-version = ["py310"] From d618fed85ba6359b3ad72fca0c26c49433bdbfb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=BClg?= Date: Fri, 26 Jun 2026 17:01:55 -0700 Subject: [PATCH 11/15] build: auditwheel repair and readded libpoco --- extensions/rcs_fr3/CMakeLists.txt | 18 +++++++++++++++++- extensions/rcs_fr3/pyproject.toml | 1 + extensions/rcs_panda/CMakeLists.txt | 18 +++++++++++++++++- extensions/rcs_panda/pyproject.toml | 1 + extensions/rcs_robotics_library/pyproject.toml | 4 ++++ extensions/rcs_so101/pyproject.toml | 4 ++++ 6 files changed, 44 insertions(+), 2 deletions(-) diff --git a/extensions/rcs_fr3/CMakeLists.txt b/extensions/rcs_fr3/CMakeLists.txt index 46689427..c64a92eb 100644 --- a/extensions/rcs_fr3/CMakeLists.txt +++ b/extensions/rcs_fr3/CMakeLists.txt @@ -88,7 +88,23 @@ FetchContent_Declare( OVERRIDE_FIND_PACKAGE ) -FetchContent_MakeAvailable(pybind11 Eigen3 tinyxml2 console_bridge) +# --- POCO C++ Libraries --- +set(ENABLE_TESTS OFF CACHE BOOL "Disable POCO tests" FORCE) +set(ENABLE_DATA_MYSQL OFF CACHE BOOL "Disable POCO MySQL" FORCE) +set(ENABLE_DATA_ODBC OFF CACHE BOOL "Disable POCO ODBC" FORCE) +set(ENABLE_PAGECOMPILER OFF CACHE BOOL "Disable POCO PageCompiler" FORCE) +set(ENABLE_PAGECOMPILER_FILE2PAGE OFF CACHE BOOL "" FORCE) + +FetchContent_Declare( + Poco + GIT_REPOSITORY https://github.com/pocoproject/poco.git + GIT_TAG poco-1.13.3-release + GIT_PROGRESS TRUE + EXCLUDE_FROM_ALL + OVERRIDE_FIND_PACKAGE +) + +FetchContent_MakeAvailable(pybind11 Eigen3 tinyxml2 console_bridge Poco) if(NOT TARGET Eigen3::Eigen3) add_library(Eigen3::Eigen3 ALIAS eigen) endif() diff --git a/extensions/rcs_fr3/pyproject.toml b/extensions/rcs_fr3/pyproject.toml index 2b71c80f..b2b0a262 100644 --- a/extensions/rcs_fr3/pyproject.toml +++ b/extensions/rcs_fr3/pyproject.toml @@ -34,6 +34,7 @@ install.components = ["python_package"] [tool.cibuildwheel] skip = ["cp314*", "*-musllinux*"] +repair-wheel-command = "auditwheel repair -w {dest_dir} {wheel} --exclude librcs.so --exclude libpinocchio_default.so.3.7.0 --exclude libpinocchio_parsers.so.3.7.0" [tool.black] line-length = 120 diff --git a/extensions/rcs_panda/CMakeLists.txt b/extensions/rcs_panda/CMakeLists.txt index 01a83198..ac50970b 100644 --- a/extensions/rcs_panda/CMakeLists.txt +++ b/extensions/rcs_panda/CMakeLists.txt @@ -75,7 +75,23 @@ FetchContent_Declare( OVERRIDE_FIND_PACKAGE ) -FetchContent_MakeAvailable(pybind11 Eigen3 console_bridge) +# --- POCO C++ Libraries --- +set(ENABLE_TESTS OFF CACHE BOOL "Disable POCO tests" FORCE) +set(ENABLE_DATA_MYSQL OFF CACHE BOOL "Disable POCO MySQL" FORCE) +set(ENABLE_DATA_ODBC OFF CACHE BOOL "Disable POCO ODBC" FORCE) +set(ENABLE_PAGECOMPILER OFF CACHE BOOL "Disable POCO PageCompiler" FORCE) +set(ENABLE_PAGECOMPILER_FILE2PAGE OFF CACHE BOOL "" FORCE) + +FetchContent_Declare( + Poco + GIT_REPOSITORY https://github.com/pocoproject/poco.git + GIT_TAG poco-1.13.3-release + GIT_PROGRESS TRUE + EXCLUDE_FROM_ALL + OVERRIDE_FIND_PACKAGE +) + +FetchContent_MakeAvailable(pybind11 Eigen3 console_bridge Poco) if(NOT TARGET Eigen3::Eigen3) add_library(Eigen3::Eigen3 ALIAS eigen) endif() diff --git a/extensions/rcs_panda/pyproject.toml b/extensions/rcs_panda/pyproject.toml index 6fee796e..2eb3d4f8 100644 --- a/extensions/rcs_panda/pyproject.toml +++ b/extensions/rcs_panda/pyproject.toml @@ -33,6 +33,7 @@ install.components = ["python_package"] [tool.cibuildwheel] skip = ["cp314*", "*-musllinux*"] +repair-wheel-command = "auditwheel repair -w {dest_dir} {wheel} --exclude librcs.so --exclude libpinocchio_default.so.3.7.0 --exclude libpinocchio_parsers.so.3.7.0" [tool.black] line-length = 120 diff --git a/extensions/rcs_robotics_library/pyproject.toml b/extensions/rcs_robotics_library/pyproject.toml index 5e88dabb..1a9bf297 100644 --- a/extensions/rcs_robotics_library/pyproject.toml +++ b/extensions/rcs_robotics_library/pyproject.toml @@ -34,6 +34,10 @@ build-dir = "build" wheel.packages = ["src/rcs_robotics_library"] install.components = ["python_package"] +[tool.cibuildwheel] +skip = ["cp314*", "*-musllinux*"] +repair-wheel-command = "auditwheel repair -w {dest_dir} {wheel} --exclude librcs.so --exclude libpinocchio_default.so.3.7.0 --exclude libpinocchio_parsers.so.3.7.0" + [tool.black] line-length = 120 target-version = ["py310"] diff --git a/extensions/rcs_so101/pyproject.toml b/extensions/rcs_so101/pyproject.toml index 2a3c45aa..88c3cd20 100644 --- a/extensions/rcs_so101/pyproject.toml +++ b/extensions/rcs_so101/pyproject.toml @@ -30,6 +30,10 @@ build-dir = "build" wheel.packages = ["src/rcs_so101"] install.components = ["python_package"] +[tool.cibuildwheel] +skip = ["cp314*", "*-musllinux*"] +repair-wheel-command = "auditwheel repair -w {dest_dir} {wheel} --exclude librcs.so --exclude libpinocchio_default.so.3.7.0 --exclude libpinocchio_parsers.so.3.7.0" + [tool.black] line-length = 120 target-version = ["py310"] From 479832270e61bbc55ba3b360233ade7212f894bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=BClg?= Date: Fri, 26 Jun 2026 17:58:17 -0700 Subject: [PATCH 12/15] build(panda): fr3 copy over --- extensions/rcs_panda/CMakeLists.txt | 12 ++- .../scripts/materialize_fr3_sources.py | 86 +++++++++++++++++++ 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 extensions/rcs_panda/scripts/materialize_fr3_sources.py diff --git a/extensions/rcs_panda/CMakeLists.txt b/extensions/rcs_panda/CMakeLists.txt index ac50970b..0f7c061f 100644 --- a/extensions/rcs_panda/CMakeLists.txt +++ b/extensions/rcs_panda/CMakeLists.txt @@ -44,6 +44,16 @@ find_package(Python3 COMPONENTS Interpreter Development.Module REQUIRED) find_package(pinocchio REQUIRED) find_package(rcs REQUIRED) +set(RCS_PANDA_MATERIALIZED_SRC_DIR "${CMAKE_CURRENT_BINARY_DIR}/materialized_src_fr3") +execute_process( + COMMAND + ${Python3_EXECUTABLE} + "${CMAKE_CURRENT_SOURCE_DIR}/scripts/materialize_fr3_sources.py" + --project-root "${CMAKE_CURRENT_SOURCE_DIR}" + --output-dir "${RCS_PANDA_MATERIALIZED_SRC_DIR}" + COMMAND_ERROR_IS_FATAL ANY +) + FetchContent_Declare( libfranka GIT_REPOSITORY https://github.com/frankaemika/libfranka.git @@ -101,4 +111,4 @@ endif() FetchContent_MakeAvailable(libfranka) set_target_properties(franka PROPERTIES CXX_STANDARD 17) -add_subdirectory(src_fr3) +add_subdirectory("${RCS_PANDA_MATERIALIZED_SRC_DIR}" src_fr3) diff --git a/extensions/rcs_panda/scripts/materialize_fr3_sources.py b/extensions/rcs_panda/scripts/materialize_fr3_sources.py new file mode 100644 index 00000000..b575134b --- /dev/null +++ b/extensions/rcs_panda/scripts/materialize_fr3_sources.py @@ -0,0 +1,86 @@ +from __future__ import annotations + +import argparse +import os +import shutil +import subprocess +import tempfile +from pathlib import Path + +try: + import tomllib +except ModuleNotFoundError: # pragma: no cover + import tomli as tomllib # type: ignore + + +REPO_URL = "https://github.com/RobotControlStack/robot-control-stack.git" + + +def load_version(project_root: Path) -> str: + data = tomllib.loads((project_root / "pyproject.toml").read_text()) + return data["project"]["version"] + + +def find_shared_source(project_root: Path) -> Path: + env_override = os.environ.get("RCS_FR3_SOURCE_DIR") + if env_override: + candidate = Path(env_override).resolve() + if (candidate / "CMakeLists.txt").is_file(): + return candidate + msg = f"RCS_FR3_SOURCE_DIR does not point to a valid FR3 source tree: {candidate}" + raise FileNotFoundError(msg) + + sibling = (project_root.parent / "rcs_fr3" / "src").resolve() + if (sibling / "CMakeLists.txt").is_file(): + return sibling + + version = load_version(project_root) + tmpdir = Path(tempfile.mkdtemp(prefix="rcs_panda_fr3_")) + try: + subprocess.run( + ["git", "clone", "--depth", "1", "--branch", f"v{version}", REPO_URL, str(tmpdir)], + check=True, + ) + except subprocess.CalledProcessError: + shutil.rmtree(tmpdir, ignore_errors=True) + tmpdir = Path(tempfile.mkdtemp(prefix="rcs_panda_fr3_")) + subprocess.run( + ["git", "clone", "--depth", "1", REPO_URL, str(tmpdir)], + check=True, + ) + cloned = tmpdir / "extensions" / "rcs_fr3" / "src" + if not (cloned / "CMakeLists.txt").is_file(): + msg = f"Could not locate FR3 shared sources in cloned repo at {cloned}" + raise FileNotFoundError(msg) + return cloned + + +def copy_file(src: Path, dest: Path) -> None: + dest.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(src, dest) + + +def materialize(project_root: Path, output_dir: Path) -> None: + shared_src = find_shared_source(project_root) + panda_src = project_root / "src_fr3" + + if output_dir.exists(): + shutil.rmtree(output_dir) + output_dir.mkdir(parents=True, exist_ok=True) + + copy_file(shared_src / "CMakeLists.txt", output_dir / "CMakeLists.txt") + shutil.copytree(shared_src / "hw", output_dir / "hw") + copy_file(panda_src / "pybind" / "CMakeLists.txt", output_dir / "pybind" / "CMakeLists.txt") + copy_file(shared_src / "pybind" / "rcs.cpp", output_dir / "pybind" / "rcs.cpp") + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument("--project-root", type=Path, required=True) + parser.add_argument("--output-dir", type=Path, required=True) + args = parser.parse_args() + materialize(args.project_root.resolve(), args.output_dir.resolve()) + + +if __name__ == "__main__": + main() From c62b3c6a88e2723d8234f0a46c6e7897427dffdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=BClg?= Date: Fri, 26 Jun 2026 21:53:19 -0700 Subject: [PATCH 13/15] build: fix rcs find path --- extensions/rcs_fr3/cmake/Findrcs.cmake | 27 +++++-------------- extensions/rcs_panda/cmake/Findrcs.cmake | 27 +++++-------------- .../rcs_robotics_library/cmake/Findrcs.cmake | 27 +++++-------------- extensions/rcs_so101/cmake/Findrcs.cmake | 27 +++++-------------- 4 files changed, 24 insertions(+), 84 deletions(-) diff --git a/extensions/rcs_fr3/cmake/Findrcs.cmake b/extensions/rcs_fr3/cmake/Findrcs.cmake index 595d53bb..bd89b83e 100644 --- a/extensions/rcs_fr3/cmake/Findrcs.cmake +++ b/extensions/rcs_fr3/cmake/Findrcs.cmake @@ -2,43 +2,28 @@ if (NOT rcs_FOUND) if (NOT Python3_FOUND) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs 1. Please install rcs-core using pip.") - endif() - return() - endif() - - execute_process( - COMMAND - ${Python3_EXECUTABLE} - -c - "import importlib.util; import pathlib; spec = importlib.util.find_spec('rcs'); print(pathlib.Path(next(iter(spec.submodule_search_locations))).resolve() if spec and spec.submodule_search_locations else '')" - OUTPUT_VARIABLE rcs_package_dir - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - if (NOT rcs_package_dir) - set(rcs_FOUND FALSE) - if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs 2. Please install rcs-core using pip.") + message(FATAL_ERROR "Could not find rcs. Please install rcs-core using pip.") endif() return() endif() # Check if the include directory exists - cmake_path(APPEND rcs_package_dir include OUTPUT_VARIABLE rcs_INCLUDE_DIRS) + cmake_path(APPEND Python3_SITELIB rcs include OUTPUT_VARIABLE rcs_INCLUDE_DIRS) if (NOT EXISTS ${rcs_INCLUDE_DIRS}) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs 3. Please install rcs-core using pip.") + message(FATAL_ERROR "Could not find rcs. Please install rcs-core using pip.") endif() return() endif() # Check if the library file exists - set(rcs_library_path "${rcs_package_dir}/librcs.so") + cmake_path(APPEND Python3_SITELIB rcs OUTPUT_VARIABLE rcs_library_path) + file(GLOB rcs_library_path "${rcs_library_path}/librcs.so") if (NOT EXISTS ${rcs_library_path}) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs 4. Please install rcs-core using pip.") + message(FATAL_ERROR "Could not find rcs. Please install rcs-core using pip.") endif() return() endif() diff --git a/extensions/rcs_panda/cmake/Findrcs.cmake b/extensions/rcs_panda/cmake/Findrcs.cmake index 595d53bb..bd89b83e 100644 --- a/extensions/rcs_panda/cmake/Findrcs.cmake +++ b/extensions/rcs_panda/cmake/Findrcs.cmake @@ -2,43 +2,28 @@ if (NOT rcs_FOUND) if (NOT Python3_FOUND) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs 1. Please install rcs-core using pip.") - endif() - return() - endif() - - execute_process( - COMMAND - ${Python3_EXECUTABLE} - -c - "import importlib.util; import pathlib; spec = importlib.util.find_spec('rcs'); print(pathlib.Path(next(iter(spec.submodule_search_locations))).resolve() if spec and spec.submodule_search_locations else '')" - OUTPUT_VARIABLE rcs_package_dir - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - if (NOT rcs_package_dir) - set(rcs_FOUND FALSE) - if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs 2. Please install rcs-core using pip.") + message(FATAL_ERROR "Could not find rcs. Please install rcs-core using pip.") endif() return() endif() # Check if the include directory exists - cmake_path(APPEND rcs_package_dir include OUTPUT_VARIABLE rcs_INCLUDE_DIRS) + cmake_path(APPEND Python3_SITELIB rcs include OUTPUT_VARIABLE rcs_INCLUDE_DIRS) if (NOT EXISTS ${rcs_INCLUDE_DIRS}) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs 3. Please install rcs-core using pip.") + message(FATAL_ERROR "Could not find rcs. Please install rcs-core using pip.") endif() return() endif() # Check if the library file exists - set(rcs_library_path "${rcs_package_dir}/librcs.so") + cmake_path(APPEND Python3_SITELIB rcs OUTPUT_VARIABLE rcs_library_path) + file(GLOB rcs_library_path "${rcs_library_path}/librcs.so") if (NOT EXISTS ${rcs_library_path}) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs 4. Please install rcs-core using pip.") + message(FATAL_ERROR "Could not find rcs. Please install rcs-core using pip.") endif() return() endif() diff --git a/extensions/rcs_robotics_library/cmake/Findrcs.cmake b/extensions/rcs_robotics_library/cmake/Findrcs.cmake index 595d53bb..bd89b83e 100644 --- a/extensions/rcs_robotics_library/cmake/Findrcs.cmake +++ b/extensions/rcs_robotics_library/cmake/Findrcs.cmake @@ -2,43 +2,28 @@ if (NOT rcs_FOUND) if (NOT Python3_FOUND) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs 1. Please install rcs-core using pip.") - endif() - return() - endif() - - execute_process( - COMMAND - ${Python3_EXECUTABLE} - -c - "import importlib.util; import pathlib; spec = importlib.util.find_spec('rcs'); print(pathlib.Path(next(iter(spec.submodule_search_locations))).resolve() if spec and spec.submodule_search_locations else '')" - OUTPUT_VARIABLE rcs_package_dir - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - if (NOT rcs_package_dir) - set(rcs_FOUND FALSE) - if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs 2. Please install rcs-core using pip.") + message(FATAL_ERROR "Could not find rcs. Please install rcs-core using pip.") endif() return() endif() # Check if the include directory exists - cmake_path(APPEND rcs_package_dir include OUTPUT_VARIABLE rcs_INCLUDE_DIRS) + cmake_path(APPEND Python3_SITELIB rcs include OUTPUT_VARIABLE rcs_INCLUDE_DIRS) if (NOT EXISTS ${rcs_INCLUDE_DIRS}) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs 3. Please install rcs-core using pip.") + message(FATAL_ERROR "Could not find rcs. Please install rcs-core using pip.") endif() return() endif() # Check if the library file exists - set(rcs_library_path "${rcs_package_dir}/librcs.so") + cmake_path(APPEND Python3_SITELIB rcs OUTPUT_VARIABLE rcs_library_path) + file(GLOB rcs_library_path "${rcs_library_path}/librcs.so") if (NOT EXISTS ${rcs_library_path}) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs 4. Please install rcs-core using pip.") + message(FATAL_ERROR "Could not find rcs. Please install rcs-core using pip.") endif() return() endif() diff --git a/extensions/rcs_so101/cmake/Findrcs.cmake b/extensions/rcs_so101/cmake/Findrcs.cmake index 595d53bb..bd89b83e 100644 --- a/extensions/rcs_so101/cmake/Findrcs.cmake +++ b/extensions/rcs_so101/cmake/Findrcs.cmake @@ -2,43 +2,28 @@ if (NOT rcs_FOUND) if (NOT Python3_FOUND) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs 1. Please install rcs-core using pip.") - endif() - return() - endif() - - execute_process( - COMMAND - ${Python3_EXECUTABLE} - -c - "import importlib.util; import pathlib; spec = importlib.util.find_spec('rcs'); print(pathlib.Path(next(iter(spec.submodule_search_locations))).resolve() if spec and spec.submodule_search_locations else '')" - OUTPUT_VARIABLE rcs_package_dir - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - if (NOT rcs_package_dir) - set(rcs_FOUND FALSE) - if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs 2. Please install rcs-core using pip.") + message(FATAL_ERROR "Could not find rcs. Please install rcs-core using pip.") endif() return() endif() # Check if the include directory exists - cmake_path(APPEND rcs_package_dir include OUTPUT_VARIABLE rcs_INCLUDE_DIRS) + cmake_path(APPEND Python3_SITELIB rcs include OUTPUT_VARIABLE rcs_INCLUDE_DIRS) if (NOT EXISTS ${rcs_INCLUDE_DIRS}) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs 3. Please install rcs-core using pip.") + message(FATAL_ERROR "Could not find rcs. Please install rcs-core using pip.") endif() return() endif() # Check if the library file exists - set(rcs_library_path "${rcs_package_dir}/librcs.so") + cmake_path(APPEND Python3_SITELIB rcs OUTPUT_VARIABLE rcs_library_path) + file(GLOB rcs_library_path "${rcs_library_path}/librcs.so") if (NOT EXISTS ${rcs_library_path}) set(rcs_FOUND FALSE) if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs 4. Please install rcs-core using pip.") + message(FATAL_ERROR "Could not find rcs. Please install rcs-core using pip.") endif() return() endif() From 2e0f56a74dc580015f1ece5c8eb1867d7eef41ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=BClg?= Date: Fri, 26 Jun 2026 22:30:07 -0700 Subject: [PATCH 14/15] build: fix license and author name --- extensions/rcs_fr3/pyproject.toml | 6 +++--- extensions/rcs_panda/pyproject.toml | 6 +++--- extensions/rcs_realsense/pyproject.toml | 6 +++--- extensions/rcs_robotics_library/pyproject.toml | 6 +++--- extensions/rcs_robotiq2f85/pyproject.toml | 6 +++--- extensions/rcs_so101/pyproject.toml | 6 +++--- extensions/rcs_tacto/pyproject.toml | 4 ++-- extensions/rcs_ur5e/pyproject.toml | 4 ++-- extensions/rcs_usb_cam/pyproject.toml | 4 ++-- extensions/rcs_xarm7/pyproject.toml | 6 +++--- extensions/rcs_zed/pyproject.toml | 6 +++--- pyproject.toml | 4 ++-- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/extensions/rcs_fr3/pyproject.toml b/extensions/rcs_fr3/pyproject.toml index b2b0a262..dd29b836 100644 --- a/extensions/rcs_fr3/pyproject.toml +++ b/extensions/rcs_fr3/pyproject.toml @@ -18,9 +18,9 @@ version = "0.7.2" description = "RCS libfranka integration" dependencies = ["rcs-core>=0.7.2", "frankik"] readme = "README.md" -license = { text = "AGPL-3.0-or-later" } -maintainers = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] -authors = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] +license = "AGPL-3.0-or-later" +maintainers = [{ name = "Tobias Juelg", email = "tobias.juelg@utn.de" }] +authors = [{ name = "Tobias Juelg", email = "tobias.juelg@utn.de" }] requires-python = ">=3.11" diff --git a/extensions/rcs_panda/pyproject.toml b/extensions/rcs_panda/pyproject.toml index 2eb3d4f8..6622a6f1 100644 --- a/extensions/rcs_panda/pyproject.toml +++ b/extensions/rcs_panda/pyproject.toml @@ -17,9 +17,9 @@ version = "0.7.2" description = "RCS libfranka integration" dependencies = ["rcs-core>=0.7.2"] readme = "README.md" -license = { text = "AGPL-3.0-or-later" } -maintainers = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] -authors = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] +license = "AGPL-3.0-or-later" +maintainers = [{ name = "Tobias Juelg", email = "tobias.juelg@utn.de" }] +authors = [{ name = "Tobias Juelg", email = "tobias.juelg@utn.de" }] requires-python = ">=3.11" diff --git a/extensions/rcs_realsense/pyproject.toml b/extensions/rcs_realsense/pyproject.toml index 7c8b5f33..e093495c 100644 --- a/extensions/rcs_realsense/pyproject.toml +++ b/extensions/rcs_realsense/pyproject.toml @@ -7,15 +7,15 @@ name = "rcs_realsense" version = "0.7.2" description = "RCS realsense module" readme = "README.md" -license = { text = "AGPL-3.0-or-later" } +license = "AGPL-3.0-or-later" dependencies = [ "rcs-core>=0.7.2", "pyrealsense2~=2.55.1", "pupil_apriltags", "diskcache", ] -maintainers = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] -authors = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] +maintainers = [{ name = "Tobias Juelg", email = "tobias.juelg@utn.de" }] +authors = [{ name = "Tobias Juelg", email = "tobias.juelg@utn.de" }] requires-python = ">=3.11" [tool.black] diff --git a/extensions/rcs_robotics_library/pyproject.toml b/extensions/rcs_robotics_library/pyproject.toml index 1a9bf297..fd214b2d 100644 --- a/extensions/rcs_robotics_library/pyproject.toml +++ b/extensions/rcs_robotics_library/pyproject.toml @@ -16,11 +16,11 @@ name = "rcs_robotics_library" version = "0.7.2" description = "RCS robotics library integration" readme = "README.md" -license = { text = "AGPL-3.0-or-later" } +license = "AGPL-3.0-or-later" dependencies = ["rcs-core>=0.7.2"] -maintainers = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] +maintainers = [{ name = "Tobias Juelg", email = "tobias.juelg@utn.de" }] authors = [ - { name = "Tobias Jülg", email = "tobias.juelg@utn.de" }, + { name = "Tobias Juelg", email = "tobias.juelg@utn.de" }, { name = "Pierre Krack", email = "pierre.krack@utn.de" }, ] requires-python = ">=3.11" diff --git a/extensions/rcs_robotiq2f85/pyproject.toml b/extensions/rcs_robotiq2f85/pyproject.toml index 144fcae1..4584132e 100644 --- a/extensions/rcs_robotiq2f85/pyproject.toml +++ b/extensions/rcs_robotiq2f85/pyproject.toml @@ -12,10 +12,10 @@ dependencies = [ ] readme = "README.md" maintainers = [ - { name = "Tobias Jülg", email = "tobias.juelg@utn.de" }, + { name = "Tobias Juelg", email = "tobias.juelg@utn.de" }, ] authors = [ - { name = "Tobias Jülg", email = "tobias.juelg@utn.de" }, + { name = "Tobias Juelg", email = "tobias.juelg@utn.de" }, ] requires-python = ">=3.11" -license = { text = "AGPL-3.0-or-later" } +license = "AGPL-3.0-or-later" diff --git a/extensions/rcs_so101/pyproject.toml b/extensions/rcs_so101/pyproject.toml index 88c3cd20..33b71daf 100644 --- a/extensions/rcs_so101/pyproject.toml +++ b/extensions/rcs_so101/pyproject.toml @@ -17,9 +17,9 @@ version = "0.7.2" description = "RCS SO101 module" dependencies = ["rcs-core>=0.7.2", "lerobot==0.3.3"] readme = "README.md" -license = { text = "AGPL-3.0-or-later" } -maintainers = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] -authors = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] +license = "AGPL-3.0-or-later" +maintainers = [{ name = "Tobias Juelg", email = "tobias.juelg@utn.de" }] +authors = [{ name = "Tobias Juelg", email = "tobias.juelg@utn.de" }] requires-python = ">=3.11" [tool.scikit-build] diff --git a/extensions/rcs_tacto/pyproject.toml b/extensions/rcs_tacto/pyproject.toml index c31bc919..576b67ea 100644 --- a/extensions/rcs_tacto/pyproject.toml +++ b/extensions/rcs_tacto/pyproject.toml @@ -12,9 +12,9 @@ dependencies = [ "mujoco-tacto@git+https://github.com/utn-air/mujoco-tacto.git@main", ] readme = "README.md" -license = { text = "AGPL-3.0-or-later" } +license = "AGPL-3.0-or-later" maintainers = [ - { name = "Tobias Jülg", email = "tobias.juelg@utn.de" }, + { name = "Tobias Juelg", email = "tobias.juelg@utn.de" }, { name = "Seongjin Bien", email = "seongjin.bien@utn.de" }, ] authors = [{ name = "Seongjin Bien", email = "seongjin.bien@utn.de" }] diff --git a/extensions/rcs_ur5e/pyproject.toml b/extensions/rcs_ur5e/pyproject.toml index efad4cc9..497530cd 100644 --- a/extensions/rcs_ur5e/pyproject.toml +++ b/extensions/rcs_ur5e/pyproject.toml @@ -8,12 +8,12 @@ version = "0.7.2" description = "RCS UR5e module" dependencies = ["rcs-core>=0.7.2", "ur_rtde==1.6.1"] readme = "README.md" -license = { text = "AGPL-3.0-or-later" } +license = "AGPL-3.0-or-later" maintainers = [ { name = "Johannes Hechtl", email = "johannes.hechtl@siemens.com" }, ] authors = [ - { name = "Tobias Jülg", email = "tobias.juelg@utn.de" }, + { name = "Tobias Juelg", email = "tobias.juelg@utn.de" }, { name = "Johannes Hechtl", email = "johannes.hechtl@siemens.com" }, ] requires-python = ">=3.11" diff --git a/extensions/rcs_usb_cam/pyproject.toml b/extensions/rcs_usb_cam/pyproject.toml index b2426094..a78c3852 100644 --- a/extensions/rcs_usb_cam/pyproject.toml +++ b/extensions/rcs_usb_cam/pyproject.toml @@ -7,10 +7,10 @@ name = "rcs_usb_cam" version = "0.7.2" description = "RCS USB Camera module" readme = "README.md" -license = { text = "AGPL-3.0-or-later" } +license = "AGPL-3.0-or-later" dependencies = ["rcs-core>=0.7.2", "opencv-python~=4.10.0"] maintainers = [ - { name = "Tobias Jülg", email = "tobias.juelg@utn.de" }, + { name = "Tobias Juelg", email = "tobias.juelg@utn.de" }, { name = "Seongjin Bien", email = "seongjin.bien@utn.de" }, ] authors = [{ name = "Seongjin Bien", email = "seongjin.bien@utn.de" }] diff --git a/extensions/rcs_xarm7/pyproject.toml b/extensions/rcs_xarm7/pyproject.toml index af0fce1d..3671b0ba 100644 --- a/extensions/rcs_xarm7/pyproject.toml +++ b/extensions/rcs_xarm7/pyproject.toml @@ -8,13 +8,13 @@ version = "0.7.2" description = "RCS xArm7 module" dependencies = ["rcs-core>=0.7.2", "xarm-python-sdk==1.17.0"] readme = "README.md" -license = { text = "AGPL-3.0-or-later" } +license = "AGPL-3.0-or-later" maintainers = [ - { name = "Tobias Jülg", email = "tobias.juelg@utn.de" }, + { name = "Tobias Juelg", email = "tobias.juelg@utn.de" }, { name = "Ken Nakahara", email = "knakahara@lasr.org" }, ] authors = [ - { name = "Tobias Jülg", email = "tobias.juelg@utn.de" }, + { name = "Tobias Juelg", email = "tobias.juelg@utn.de" }, { name = "Ken Nakahara", email = "knakahara@lasr.org" }, ] requires-python = ">=3.11" diff --git a/extensions/rcs_zed/pyproject.toml b/extensions/rcs_zed/pyproject.toml index c6bc05c8..5289ec2e 100644 --- a/extensions/rcs_zed/pyproject.toml +++ b/extensions/rcs_zed/pyproject.toml @@ -7,7 +7,7 @@ name = "rcs_zed" version = "0.7.2" description = "RCS ZED camera module" readme = "README.md" -license = { text = "AGPL-3.0-or-later" } +license = "AGPL-3.0-or-later" dependencies = [ "rcs-core>=0.7.2", "opencv-python~=4.10.0", @@ -15,8 +15,8 @@ dependencies = [ "diskcache", "typer~=0.9", ] -maintainers = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] -authors = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] +maintainers = [{ name = "Tobias Juelg", email = "tobias.juelg@utn.de" }] +authors = [{ name = "Tobias Juelg", email = "tobias.juelg@utn.de" }] requires-python = ">=3.11" [tool.black] diff --git a/pyproject.toml b/pyproject.toml index 5bfb8d16..dda7fda7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,9 +46,9 @@ dependencies = [ "pandas", ] readme = "README.md" -maintainers = [{ name = "Tobias Jülg", email = "tobias.juelg@utn.de" }] +maintainers = [{ name = "Tobias Juelg", email = "tobias.juelg@utn.de" }] authors = [ - { name = "Tobias Jülg", email = "tobias.juelg@utn.de" }, + { name = "Tobias Juelg", email = "tobias.juelg@utn.de" }, { name = "Pierre Krack", email = "pierre.krack@utn.de" }, { name = "Seongjin Bien", email = "seongjin.bien@utn.de" }, ] From 53f0d75d3d7fc2bbd10f3ed81a417328be1bf2b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=BClg?= Date: Fri, 26 Jun 2026 23:12:45 -0700 Subject: [PATCH 15/15] ci: fix wheel and cibuildwheel for pipy uploading --- .github/workflows/build_wheels.yaml | 57 +++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build_wheels.yaml b/.github/workflows/build_wheels.yaml index fc272ef1..59b98f57 100644 --- a/.github/workflows/build_wheels.yaml +++ b/.github/workflows/build_wheels.yaml @@ -23,19 +23,62 @@ jobs: name: core-wheels path: ./wheelhouse/*.whl - build_extension_wheels: - name: Build ${{ matrix.extension }} wheels on Python ${{ matrix.python-version }} + build_cpp_extension_wheels: + name: Build C++ extension wheels for ${{ matrix.extension }} needs: [build_core_wheels] runs-on: ubuntu-latest strategy: fail-fast: false matrix: - python-version: ["3.11", "3.12", "3.13"] extension: - rcs_fr3 - rcs_panda - rcs_robotics_library - rcs_so101 + + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + name: core-wheels + path: dist/core + + - name: Install root Debian dependencies + run: | + sudo apt-get update + sudo xargs -a debian_deps.txt apt-get install -y + + - name: Install extension Debian dependencies + run: | + deps_file="extensions/${{ matrix.extension }}/debian_deps.txt" + if [ -f "${deps_file}" ]; then + sudo xargs -a "${deps_file}" apt-get install -y + fi + + - name: Build C++ extension wheels + uses: pypa/cibuildwheel@v2.22.0 + env: + CIBW_ARCHS_LINUX: x86_64 + CIBW_BUILD: cp311-* cp312-* cp313-* + PIP_FIND_LINKS: /project/dist/core + with: + package-dir: extensions/${{ matrix.extension }} + output-dir: extensions/${{ matrix.extension }}/wheelhouse + + - uses: actions/upload-artifact@v4 + with: + name: wheels-${{ matrix.extension }} + path: extensions/${{ matrix.extension }}/wheelhouse/*.whl + + build_python_extension_wheels: + name: Build pure Python wheel for ${{ matrix.extension }} + needs: [build_core_wheels] + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + extension: - rcs_realsense - rcs_robotiq2f85 - rcs_tacto @@ -67,10 +110,10 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 with: - python-version: ${{ matrix.python-version }} + python-version: "3.11" cache: pip - - name: Build extension wheel + - name: Build pure Python wheel env: PIP_FIND_LINKS: ${{ github.workspace }}/dist/core run: | @@ -80,11 +123,11 @@ jobs: - uses: actions/upload-artifact@v4 with: - name: wheels-${{ matrix.extension }}-py${{ matrix.python-version }} + name: wheels-${{ matrix.extension }} path: extensions/${{ matrix.extension }}/dist/*.whl upload_pypi: - needs: [build_core_wheels, build_extension_wheels] + needs: [build_core_wheels, build_cpp_extension_wheels, build_python_extension_wheels] runs-on: ubuntu-latest if: github.event_name == 'release' && github.event.action == 'published' environment: pypi