diff --git a/.github/workflows/build_wheels.yaml b/.github/workflows/build_wheels.yaml index 59b98f57..393c31e8 100644 --- a/.github/workflows/build_wheels.yaml +++ b/.github/workflows/build_wheels.yaml @@ -7,20 +7,23 @@ on: jobs: build_core_wheels: - name: Build core wheels - runs-on: ubuntu-latest + name: Build core wheels on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - macos-14 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 + name: core-wheels-${{ matrix.os }} path: ./wheelhouse/*.whl build_cpp_extension_wheels: @@ -33,15 +36,15 @@ jobs: extension: - rcs_fr3 - rcs_panda - - rcs_robotics_library - rcs_so101 steps: - uses: actions/checkout@v4 + # extensions are built on linux, so they need the linux core wheels - uses: actions/download-artifact@v4 with: - name: core-wheels + name: core-wheels-ubuntu-latest path: dist/core - name: Install root Debian dependencies @@ -81,7 +84,6 @@ jobs: extension: - rcs_realsense - rcs_robotiq2f85 - - rcs_tacto - rcs_ur5e - rcs_usb_cam - rcs_xarm7 @@ -90,9 +92,10 @@ jobs: steps: - uses: actions/checkout@v4 + # extensions are built on linux, so they need the linux core wheels - uses: actions/download-artifact@v4 with: - name: core-wheels + name: core-wheels-ubuntu-latest path: dist/core - name: Install root Debian dependencies diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6a2379a5..eb6bea24 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -129,7 +129,6 @@ jobs: extension: - rcs_fr3 - rcs_panda - - rcs_robotics_library - rcs_so101 runs-on: ubuntu-latest steps: diff --git a/.gitignore b/.gitignore index ace8e6a5..ad434e17 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,4 @@ docs/_build CLAUDE.md uv.lock *.parquet - +wheelhouse diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c21dfa5..80d6e253 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,77 @@ +## v0.7.3 (2026-10-06) + +### Feat + +- **yam**: is grasped property +- **YAM**: force limiter for YAM gripper +- **sim**: current gl context for mac +- mac os compilation support +- **wrappers**: gripper prev action obs and threshold +- **scenes**: add zed cameras to droid setup +- new droid camera mount +- added droid zed wrist mount +- added zed2i +- **scenes**: add empty world droid +- add single fr3 mount mesh +- **sim**: adds configureable kp and kv gains for sim robots +- **extensions**: robotiq cli for serials +- **extensions**: robotiq bump +- **franka**: approach before controller start +- **franka**: add policy_rate config option +- add tquat_flange to robot observation +- add flange in sim +- **interface**: add get_cartesian_flange_position +- **franka**: add get_cartesian_flange_position method +- **franka**: tcp offset defaults to desk +- **zed**: added intrinsics cli command +- **fr3/panda**: config for collision values +- **fr3/panda**: add max torque values to config +- **cli**: camera episode video export +- **yaml**: teleop example with cameras +- **yam**: dual arm support +- **yam**: add quest teleop +- yam example +- **extension**: initial yam implementation +- **sim**: yam integration +- **franka**: pd coefficients in controllers +- **franka**: torque safety limit per joint +- **extension**: taxim integration (#319) +- **franka**: added droid setup config + +### Fix + +- **YAM**: YAM gripper set normalize with uses force +- joint limits in fr3, xarm and so101 +- **wrappers**: always send arm commands instead of skipping near-identical ones +- allow only positive frame rate +- **hw**: move rate limit to bottom of stack +- viewer process as deamon to avoid open gui on program close +- **wrappers**: binary prev action obs wrong location +- reset in storage wrapper to pass seed and options +- **sim**: added solref and solimp for cubes +- **assets**: zed2i fovy +- **scenes**: robot frame objects automatically get grav comp prefix +- **sim**: zed2i camera rotation +- **ik**: tcp offset applied correctly in pin forward +- **scenes**: mutation of q_home in empty world fr3 +- **examples**: added policy rate to for low level pd controller in franka examples +- pybind pure override +- virtual get_cartesian_flange_position +- **franka**: reset also returns franka state +- **franka**: desk ignore realtime control +- **teleop**: increase quest reqd frequency to avoid alias effect +- **yam**: ruckig version +- **yam**: async +- **franka cli**: untangle home and gripper +- **zed**: remove hidden realsense dependency +- **example**: remove thread for sim inference +- **config**: single arm robot compatible with teleop + +### Refactor + +- remove unused robotics library extension and urdf assets +- **franka**: use thread safe value class + ## v0.7.2 (2026-06-24) ### Fix diff --git a/CMakeLists.txt b/CMakeLists.txt index a9d48a8b..bc18ee7e 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.2 + VERSION 0.7.3 DESCRIPTION "Robot Control Stack Library" ) diff --git a/Makefile b/Makefile index a8f89c3f..655fe690 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,14 @@ PYSRC = python CPPSRC = src COMPILE_MODE = Release +WHEELHOUSE = wheelhouse +CORE_WHEELHOUSE = ${WHEELHOUSE}/core +PY_EXT_WHEELHOUSE = ${WHEELHOUSE}/py_extensions +CPP_EXT_WHEELHOUSE = ${WHEELHOUSE}/cpp_extensions +PY_EXTENSIONS ?= rcs_realsense rcs_robotiq2f85 rcs_ur5e rcs_usb_cam rcs_xarm7 rcs_zed +CPP_EXTENSIONS ?= rcs_fr3 rcs_panda rcs_so101 +# set to pypi to publish to the real index +PYPI_REPOSITORY ?= testpypi LINT_EXCLUDE_RUFF = --exclude examples/teleop/SimPublisher LINT_EXCLUDE_MYPY = 'build|examples/teleop/SimPublisher|examples/inference/franka.py' @@ -68,4 +76,34 @@ bump: commit: cz commit -.PHONY: cppcheckformat cppformat cpplint gcccompile clangcompile stubgen pycheckformat pyformat pylint ruff mypy pytest bump commit +buildcorewheels: + rm -rf ${CORE_WHEELHOUSE} + cibuildwheel --platform auto --output-dir ${CORE_WHEELHOUSE} . + twine check ${CORE_WHEELHOUSE}/*.whl + +uploadcorewheels: + twine upload --repository ${PYPI_REPOSITORY} ${CORE_WHEELHOUSE}/*.whl + +buildpyextensionwheels: + rm -rf ${PY_EXT_WHEELHOUSE} + for ext in ${PY_EXTENSIONS}; do \ + uv build --wheel --out-dir ${PY_EXT_WHEELHOUSE} extensions/$$ext || exit 1; \ + done + twine check ${PY_EXT_WHEELHOUSE}/*.whl + +uploadpyextensionwheels: + twine upload --repository ${PYPI_REPOSITORY} ${PY_EXT_WHEELHOUSE}/*.whl + +buildcppextensionwheels: + rm -rf ${CPP_EXT_WHEELHOUSE} + rm -rf dist/core && mkdir -p dist/core + cp ${CORE_WHEELHOUSE}/*.whl dist/core/ + for ext in ${CPP_EXTENSIONS}; do \ + cibuildwheel --platform auto --output-dir ${CPP_EXT_WHEELHOUSE} extensions/$$ext || exit 1; \ + done + twine check ${CPP_EXT_WHEELHOUSE}/*.whl + +uploadcppextensionwheels: + twine upload --repository ${PYPI_REPOSITORY} ${CPP_EXT_WHEELHOUSE}/*.whl + +.PHONY: cppcheckformat cppformat cpplint gcccompile clangcompile stubgen pycheckformat pyformat pylint ruff mypy pytest bump commit buildcorewheels uploadcorewheels buildpyextensionwheels uploadpyextensionwheels buildcppextensionwheels uploadcppextensionwheels diff --git a/assets/robots/fr3/fr3.urdf b/assets/robots/fr3/fr3.urdf deleted file mode 100644 index c2a869e8..00000000 --- a/assets/robots/fr3/fr3.urdf +++ /dev/null @@ -1,276 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/assets/robots/fr3/fr3.xml b/assets/robots/fr3/fr3.xml index 1e7d892d..409bb62b 100644 --- a/assets/robots/fr3/fr3.xml +++ b/assets/robots/fr3/fr3.xml @@ -80,13 +80,13 @@ - + - + @@ -99,14 +99,14 @@ - + - @@ -115,7 +115,7 @@ - @@ -129,7 +129,7 @@ - diff --git a/assets/robots/so101/so101.urdf b/assets/robots/so101/so101.urdf deleted file mode 100644 index 5dd02d24..00000000 --- a/assets/robots/so101/so101.urdf +++ /dev/null @@ -1,460 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - transmission_interface/SimpleTransmission - - hardware_interface/PositionJointInterface - - - hardware_interface/PositionJointInterface - 1 - - - - - - - - - - - - - - transmission_interface/SimpleTransmission - - hardware_interface/PositionJointInterface - - - hardware_interface/PositionJointInterface - 1 - - - - - - - - - - - - - - transmission_interface/SimpleTransmission - - hardware_interface/PositionJointInterface - - - hardware_interface/PositionJointInterface - 1 - - - - - - - - - - - - - - - transmission_interface/SimpleTransmission - - hardware_interface/PositionJointInterface - - - hardware_interface/PositionJointInterface - 1 - - - - - - - - - - - - - - transmission_interface/SimpleTransmission - - hardware_interface/PositionJointInterface - - - hardware_interface/PositionJointInterface - 1 - - - - - - - - - - - - - - transmission_interface/SimpleTransmission - - hardware_interface/PositionJointInterface - - - hardware_interface/PositionJointInterface - 1 - - - - \ No newline at end of file diff --git a/assets/robots/so101/so101.xml b/assets/robots/so101/so101.xml index b5bb31d1..efd1109f 100644 --- a/assets/robots/so101/so101.xml +++ b/assets/robots/so101/so101.xml @@ -82,7 +82,7 @@ - + @@ -147,7 +147,7 @@ - + diff --git a/assets/robots/ur5e/ur5e.urdf b/assets/robots/ur5e/ur5e.urdf deleted file mode 100644 index 7925a88c..00000000 --- a/assets/robots/ur5e/ur5e.urdf +++ /dev/null @@ -1,360 +0,0 @@ - - - - - - - - - - transmission_interface/SimpleTransmission - - hardware_interface/PositionJointInterface - - - 1 - - - - transmission_interface/SimpleTransmission - - hardware_interface/PositionJointInterface - - - 1 - - - - transmission_interface/SimpleTransmission - - hardware_interface/PositionJointInterface - - - 1 - - - - transmission_interface/SimpleTransmission - - hardware_interface/PositionJointInterface - - - 1 - - - - transmission_interface/SimpleTransmission - - hardware_interface/PositionJointInterface - - - 1 - - - - transmission_interface/SimpleTransmission - - hardware_interface/PositionJointInterface - - - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/development/cpp_extension.md b/docs/development/cpp_extension.md index 42deac43..df89c0ff 100644 --- a/docs/development/cpp_extension.md +++ b/docs/development/cpp_extension.md @@ -55,4 +55,3 @@ rcs_mycppext/ ## Examples - **rcs_fr3**: Implements the driver for the Franka Research 3 robot in C++ using `libfranka`. -- **rcs_robotics_library**: Wraps the Robotics Library (RL) for kinematics and path planning. diff --git a/docs/extensions/index.md b/docs/extensions/index.md index 89964125..a576bdad 100644 --- a/docs/extensions/index.md +++ b/docs/extensions/index.md @@ -14,7 +14,6 @@ rcs_yam 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 f33539cb..5b286ecf 100644 --- a/docs/extensions/overview.md +++ b/docs/extensions/overview.md @@ -43,7 +43,6 @@ RCS comes with several supported extensions: - **rcs_realsense**: Support for Intel RealSense cameras. - **rcs_usb_cam**: Support for generic USB webcams. - **rcs_tacto**: Integration with the Tacto tactile sensor simulator. -- **rcs_robotics_library**: Integration with the Robotics Library (RL). - **rcs_robotiq2f85**: Integration with the Robotiq 2F-85 Gripper. ## Creating Extensions diff --git a/docs/extensions/rcs_robotics_library.md b/docs/extensions/rcs_robotics_library.md deleted file mode 100644 index 92dd54dd..00000000 --- a/docs/extensions/rcs_robotics_library.md +++ /dev/null @@ -1,17 +0,0 @@ -# RCS Robotics Library Extension - -This extension provides integration with the [Robotics Library (RL)](https://www.roboticslibrary.org/) for kinematics and path planning. - -## Installation - -```shell -sudo apt install $(cat extensions/rcs_robotics_library/debian_deps.txt) -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/extensions/rcs_fr3/CMakeLists.txt b/extensions/rcs_fr3/CMakeLists.txt index c64a92eb..b5365fcb 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.2 + VERSION 0.7.3 DESCRIPTION "RCS Libfranka integration" ) diff --git a/extensions/rcs_fr3/pyproject.toml b/extensions/rcs_fr3/pyproject.toml index dd29b836..a53e9bf1 100644 --- a/extensions/rcs_fr3/pyproject.toml +++ b/extensions/rcs_fr3/pyproject.toml @@ -8,15 +8,15 @@ requires = [ "cmake", "ninja", "pin==3.7.0", - "rcs-core>=0.7.2", + "rcs-core>=0.7.3", ] build-backend = "scikit_build_core.build" [project] name = "rcs_fr3" -version = "0.7.2" +version = "0.7.3" description = "RCS libfranka integration" -dependencies = ["rcs-core>=0.7.2", "frankik"] +dependencies = ["rcs-core>=0.7.3", "frankik"] readme = "README.md" license = "AGPL-3.0-or-later" maintainers = [{ name = "Tobias Juelg", email = "tobias.juelg@utn.de" }] @@ -24,6 +24,14 @@ authors = [{ name = "Tobias Juelg", email = "tobias.juelg@utn.de" }] requires-python = ">=3.11" +[dependency-groups] +build_deps = [ + "pin==3.7.0", + "cmeel-urdfdom<5", + "cmeel-tinyxml2<11", + "scikit-build-core>=0.3.3", +] + [tool.scikit-build] build.verbose = true build.targets = ["_core"] @@ -33,7 +41,15 @@ wheel.packages = ["src/rcs_fr3"] install.components = ["python_package"] [tool.cibuildwheel] -skip = ["cp314*", "*-musllinux*"] +build = ["cp311-*", "cp312-*", "cp313-*"] +skip = ["*-musllinux*"] +before-build = "pip install --upgrade pip && pip install --group {package}/pyproject.toml:build_deps cmake ninja && pip install --no-index --no-deps --find-links {project}/dist/core rcs-core" +build-frontend = { name = "pip", args = ["--no-build-isolation"] } +environment = { SKBUILD_BUILD_DIR = "/tmp/rcs-build/{wheel_tag}" } + +[tool.cibuildwheel.linux] +archs = ["x86_64"] +manylinux-x86_64-image = "manylinux_2_28" 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] diff --git a/extensions/rcs_fr3/src/hw/Franka.h b/extensions/rcs_fr3/src/hw/Franka.h index 410ffe8c..7d875f9a 100644 --- a/extensions/rcs_fr3/src/hw/Franka.h +++ b/extensions/rcs_fr3/src/hw/Franka.h @@ -80,10 +80,10 @@ struct FrankaConfig : common::RobotConfig { Eigen::Matrix joint_limits = (Eigen::Matrix(2, 7) << // low 7‐tuple - -2.3093, - -1.5133, -2.4937, -2.7478, -2.4800, 0.8521, -2.6895, + -2.3476, + -1.5454, -2.4937, -2.7714, -2.5100, 0.7773, -2.7045, // high 7‐tuple - 2.3093, 1.5133, 2.4937, -0.4461, 2.4800, 4.2094, 2.6895) + 2.3476, 1.5454, 2.4937, -0.4226, 2.5100, 4.2841, 2.7045) .finished(); }; diff --git a/extensions/rcs_fr3/src/rcs_fr3/_core/__init__.pyi b/extensions/rcs_fr3/src/rcs_fr3/_core/__init__.pyi index 78b6b4cc..72a3c964 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.2" +__version__: str = "0.7.3" diff --git a/extensions/rcs_fr3/src/rcs_fr3/creators.py b/extensions/rcs_fr3/src/rcs_fr3/creators.py index e9804164..36e4f3f9 100644 --- a/extensions/rcs_fr3/src/rcs_fr3/creators.py +++ b/extensions/rcs_fr3/src/rcs_fr3/creators.py @@ -7,7 +7,12 @@ import rcs.hand.tilburg_hand from frankik import FrankaKinematics from rcs._core.common import BaseCameraConfig, Gripper, GripperConfig, Kinematics, Pose -from rcs.camera.hw import DummyCalibrationStrategy, HardwareCamera, HardwareCameraSet +from rcs.camera.hw import ( + CalibrationStrategy, + DummyCalibrationStrategy, + HardwareCamera, + HardwareCameraSet, +) from rcs.envs.base import ( CameraSetWrapper, ControlMode, @@ -62,8 +67,6 @@ class HardwareCameraCreatorConfig: def _create_realsense_camera(cfg: HardwareCameraCreatorConfig) -> HardwareCamera: try: - from rcs.camera.hw import CalibrationStrategy - # from rcs_realsense.calibration import FR3BaseArucoCalibration from rcs_realsense.camera import RealSenseCameraSet except ImportError as e: @@ -81,7 +84,6 @@ def _create_realsense_camera(cfg: HardwareCameraCreatorConfig) -> HardwareCamera def _create_zed_camera(cfg: HardwareCameraCreatorConfig) -> HardwareCamera: try: - from rcs.camera.hw import CalibrationStrategy from rcs_zed.camera import ZEDCameraSet except ImportError as e: msg = "ZED camera support requires the `rcs_zed` extension to be installed." diff --git a/extensions/rcs_panda/CMakeLists.txt b/extensions/rcs_panda/CMakeLists.txt index 0f7c061f..63731d07 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.2 + VERSION 0.7.3 DESCRIPTION "RCS Libfranka integration" ) diff --git a/extensions/rcs_panda/pyproject.toml b/extensions/rcs_panda/pyproject.toml index 6622a6f1..8d24c488 100644 --- a/extensions/rcs_panda/pyproject.toml +++ b/extensions/rcs_panda/pyproject.toml @@ -7,15 +7,15 @@ requires = [ "pybind11", "cmake", "ninja", - "rcs-core>=0.7.2", + "rcs-core>=0.7.3", ] build-backend = "scikit_build_core.build" [project] name = "rcs_panda" -version = "0.7.2" +version = "0.7.3" description = "RCS libfranka integration" -dependencies = ["rcs-core>=0.7.2"] +dependencies = ["rcs-core>=0.7.3"] readme = "README.md" license = "AGPL-3.0-or-later" maintainers = [{ name = "Tobias Juelg", email = "tobias.juelg@utn.de" }] @@ -23,6 +23,14 @@ authors = [{ name = "Tobias Juelg", email = "tobias.juelg@utn.de" }] requires-python = ">=3.11" +[dependency-groups] +build_deps = [ + "pin==3.7.0", + "cmeel-urdfdom<5", + "cmeel-tinyxml2<11", + "scikit-build-core>=0.3.3", +] + [tool.scikit-build] build.verbose = true build.targets = ["_core"] @@ -32,7 +40,15 @@ wheel.packages = ["src/rcs_panda"] install.components = ["python_package"] [tool.cibuildwheel] -skip = ["cp314*", "*-musllinux*"] +build = ["cp311-*", "cp312-*", "cp313-*"] +skip = ["*-musllinux*"] +before-build = "pip install --upgrade pip && pip install --group {package}/pyproject.toml:build_deps cmake ninja && pip install --no-index --no-deps --find-links {project}/dist/core rcs-core" +build-frontend = { name = "pip", args = ["--no-build-isolation"] } +environment = { SKBUILD_BUILD_DIR = "/tmp/rcs-build/{wheel_tag}" } + +[tool.cibuildwheel.linux] +archs = ["x86_64"] +manylinux-x86_64-image = "manylinux_2_28" 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] diff --git a/extensions/rcs_panda/src/rcs_panda/_core/__init__.pyi b/extensions/rcs_panda/src/rcs_panda/_core/__init__.pyi index 78b6b4cc..72a3c964 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.2" +__version__: str = "0.7.3" diff --git a/extensions/rcs_panda/src/rcs_panda/creators.py b/extensions/rcs_panda/src/rcs_panda/creators.py index cf2e09d6..28bace5a 100644 --- a/extensions/rcs_panda/src/rcs_panda/creators.py +++ b/extensions/rcs_panda/src/rcs_panda/creators.py @@ -5,7 +5,12 @@ import gymnasium as gym import rcs.hand.tilburg_hand from rcs._core.common import BaseCameraConfig, Gripper, GripperConfig, GripperType -from rcs.camera.hw import DummyCalibrationStrategy, HardwareCamera, HardwareCameraSet +from rcs.camera.hw import ( + CalibrationStrategy, + DummyCalibrationStrategy, + HardwareCamera, + HardwareCameraSet, +) from rcs.envs.base import ( CameraSetWrapper, ControlMode, @@ -38,7 +43,6 @@ class HardwareCameraCreatorConfig: def _create_realsense_camera(cfg: HardwareCameraCreatorConfig) -> HardwareCamera: try: - from rcs.camera.hw import CalibrationStrategy # from rcs_realsense.calibration import FR3BaseArucoCalibration from rcs_realsense.camera import RealSenseCameraSet diff --git a/extensions/rcs_realsense/pyproject.toml b/extensions/rcs_realsense/pyproject.toml index e093495c..63574b1f 100644 --- a/extensions/rcs_realsense/pyproject.toml +++ b/extensions/rcs_realsense/pyproject.toml @@ -4,12 +4,12 @@ build-backend = "setuptools.build_meta" [project] name = "rcs_realsense" -version = "0.7.2" +version = "0.7.3" description = "RCS realsense module" readme = "README.md" license = "AGPL-3.0-or-later" dependencies = [ - "rcs-core>=0.7.2", + "rcs-core>=0.7.3", "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 bc8c296f..4910b9ec 100644 --- a/extensions/rcs_realsense/src/rcs_realsense/__init__.py +++ b/extensions/rcs_realsense/src/rcs_realsense/__init__.py @@ -1 +1 @@ -__version__ = "0.7.2" +__version__ = "0.7.3" diff --git a/extensions/rcs_robotics_library/CMakeLists.txt b/extensions/rcs_robotics_library/CMakeLists.txt deleted file mode 100644 index e27f0940..00000000 --- a/extensions/rcs_robotics_library/CMakeLists.txt +++ /dev/null @@ -1,64 +0,0 @@ -cmake_minimum_required(VERSION 3.19) - -project( - rcs_fr3 - LANGUAGES C CXX - VERSION 0.7.2 - DESCRIPTION "RCS robotics library integration" -) - -set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) - -set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) # Allow us to set options for subprojects - -cmake_policy(SET CMP0048 NEW) # Set version in project -# Allow target properties affecting visibility during linking in static libraries -set(CMAKE_POLICY_DEFAULT_CMP0063 NEW) -cmake_policy(SET CMP0072 NEW) # Use GLVND instead of legacy libGL.so -cmake_policy(SET CMP0135 NEW) # Use timestamp of file extraction not download -cmake_policy(SET CMP0140 NEW) # Check return arguments - -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) - -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) -set(CMAKE_POLICY_VERSION_MINIMUM 3.5) - -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) - -set(BUILD_SHARED_LIBS OFF) -set(CMAKE_POSITION_INDEPENDENT_CODE ON) - -set(RL_BUILD_DEMOS OFF) -set(RL_BUILD_RL_SG OFF) -set(RL_BUILD_TESTS OFF) -set(RL_BUILD_EXTRAS OFF) -set(BUILD_PYTHON_INTERFACE OFF) -set(BUILD_DOCUMENTATION OFF) - -include(FetchContent) - -find_package(Eigen3 REQUIRED) -find_package(Python3 COMPONENTS Interpreter Development.Module REQUIRED) -find_package(pinocchio REQUIRED) -find_package(rcs REQUIRED) - -FetchContent_Declare(rl - GIT_REPOSITORY https://github.com/roboticslibrary/rl.git - GIT_TAG 0b3797215345a1d37903634095361233d190b2e6 - GIT_PROGRESS TRUE - EXCLUDE_FROM_ALL -) -FetchContent_Declare(pybind11 - GIT_REPOSITORY https://github.com/pybind/pybind11.git - GIT_TAG v2.13.4 - GIT_PROGRESS TRUE - EXCLUDE_FROM_ALL -) - -FetchContent_MakeAvailable(rl pybind11) - -add_subdirectory(src) diff --git a/extensions/rcs_robotics_library/Makefile b/extensions/rcs_robotics_library/Makefile deleted file mode 100644 index 858bd6c9..00000000 --- a/extensions/rcs_robotics_library/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -PYSRC = src -CPPSRC = src -COMPILE_MODE = Release - -# CPP -cppcheckformat: - clang-format --dry-run -Werror -i $(shell find ${CPPSRC} -name '*.cpp' -o -name '*.cc' -o -name '*.h') - -cppformat: - clang-format -Werror -i $(shell find ${CPPSRC} -name '*.cpp' -o -name '*.cc' -o -name '*.h') - -cpplint: - clang-tidy -p=build --warnings-as-errors='*' $(shell find ${CPPSRC} -name '*.cpp' -o -name '*.cc' -name '*.h') - -# import errors -# clang-tidy -p=build --warnings-as-errors='*' $(shell find extensions/rcs_fr3/src -name '*.cpp' -o -name '*.cc' -name '*.h') - -gcccompile: - cmake -DCMAKE_BUILD_TYPE=${COMPILE_MODE} -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -B build -G Ninja - cmake --build build --target _core - -clangcompile: - cmake -DCMAKE_BUILD_TYPE=${COMPILE_MODE} -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -B build -G Ninja - cmake --build build --target _core - -# Auto generation of CPP binding stub files -stubgen: - pybind11-stubgen -o src --numpy-array-use-type-var rcs_robotics_library - find ./src -name '*.pyi' -print | xargs sed -i '1s/^/# ATTENTION: auto generated from C++ code, use `make stubgen` to update!\n/' - find ./src -not -path "./src/rcs_robotics_library/_core/*" -name '*.pyi' -delete - find ./src/rcs_robotics_library/_core -name '*.pyi' -print | xargs sed -i 's/tuple\[typing\.Literal\[\([0-9]\+\)\], typing\.Literal\[1\]\]/tuple\[typing\.Literal[\1]\]/g' - find ./src/rcs_robotics_library/_core -name '*.pyi' -print | xargs sed -i 's/tuple\[\([M|N]\), typing\.Literal\[1\]\]/tuple\[\1\]/g' - ruff check --fix src/rcs_robotics_library/_core - isort src/rcs_robotics_library/_core - black src/rcs_robotics_library/_core - - - -.PHONY: cppcheckformat cppformat cpplint gcccompile clangcompile stubgen diff --git a/extensions/rcs_robotics_library/README.md b/extensions/rcs_robotics_library/README.md deleted file mode 100644 index 600e55a6..00000000 --- a/extensions/rcs_robotics_library/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# 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 -sudo apt install $(cat debian_deps.txt) -``` - -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/cmake/Findpinocchio.cmake b/extensions/rcs_robotics_library/cmake/Findpinocchio.cmake deleted file mode 100644 index fcefcf5c..00000000 --- a/extensions/rcs_robotics_library/cmake/Findpinocchio.cmake +++ /dev/null @@ -1,68 +0,0 @@ -if (NOT pinocchio_FOUND) - if (NOT Python3_FOUND) - set(pinocchio_FOUND FALSE) - if (pinocchio_FIND_REQUIRED) - message(FATAL_ERROR "Could not find pinocchio. Please install pinocchio using pip.") - endif() - return() - endif() - - # Check if the include directory exists - cmake_path(APPEND Python3_SITELIB cmeel.prefix include OUTPUT_VARIABLE pinocchio_INCLUDE_DIRS) - if (NOT EXISTS ${pinocchio_INCLUDE_DIRS}) - set(pinocchio_FOUND FALSE) - if (pinocchio_FIND_REQUIRED) - message(FATAL_ERROR "Could not find pinocchio. Please install pinocchio using pip.") - endif() - return() - endif() - - # Check if the library file exists - cmake_path(APPEND Python3_SITELIB cmeel.prefix lib libpinocchio_default.so OUTPUT_VARIABLE pinocchio_library_path) - if (NOT EXISTS ${pinocchio_library_path}) - set(pinocchio_FOUND FALSE) - if (pinocchio_FIND_REQUIRED) - message(FATAL_ERROR "Could not find pinocchio. Please install pinocchio using pip.") - endif() - return() - endif() - - # Check if the library file exists - cmake_path(APPEND Python3_SITELIB cmeel.prefix lib libpinocchio_parsers.so OUTPUT_VARIABLE pinocchio_parsers_path) - if (NOT EXISTS ${pinocchio_parsers_path}) - set(pinocchio_FOUND FALSE) - if (pinocchio_FIND_REQUIRED) - message(FATAL_ERROR "Could not find pinocchio parsers path. Please install pinocchio using pip.") - endif() - return() - endif() - - # Extract version from the library filename - file(GLOB pinocchio_dist_info "${Python3_SITELIB}/pin-*.dist-info") - cmake_path(GET pinocchio_dist_info FILENAME pinocchio_library_filename) - string(REPLACE "pin-" "" pinocchio_VERSION "${pinocchio_library_filename}") - string(REPLACE ".dist-info" "" pinocchio_VERSION "${pinocchio_VERSION}") - - # Create the imported target - add_library(pinocchio::pinocchio SHARED IMPORTED) - target_include_directories(pinocchio::pinocchio INTERFACE ${pinocchio_INCLUDE_DIRS}) - set_target_properties(pinocchio::pinocchio - PROPERTIES - IMPORTED_LOCATION "${pinocchio_library_path}" - ) - - add_library(pinocchio::parsers SHARED IMPORTED) - target_include_directories(pinocchio::parsers INTERFACE ${pinocchio_INCLUDE_DIRS}) - set_target_properties(pinocchio::parsers - PROPERTIES - IMPORTED_LOCATION "${pinocchio_parsers_path}" - ) - - add_library(pinocchio::all INTERFACE IMPORTED) - set_target_properties(pinocchio::all - PROPERTIES - INTERFACE_LINK_LIBRARIES "pinocchio::pinocchio;pinocchio::parsers" - ) - set(pinocchio_FOUND TRUE) - -endif() diff --git a/extensions/rcs_robotics_library/cmake/Findrcs.cmake b/extensions/rcs_robotics_library/cmake/Findrcs.cmake deleted file mode 100644 index bd89b83e..00000000 --- a/extensions/rcs_robotics_library/cmake/Findrcs.cmake +++ /dev/null @@ -1,46 +0,0 @@ -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-core using pip.") - endif() - return() - endif() - - # Check if the include directory exists - 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. 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") - if (NOT EXISTS ${rcs_library_path}) - set(rcs_FOUND FALSE) - if (rcs_FIND_REQUIRED) - message(FATAL_ERROR "Could not find rcs. Please install rcs-core using pip.") - endif() - return() - endif() - - # Extract version from the library filename - # file(GLOB rcs_dist_info "${Python3_SITELIB}/rcs-*.dist-info") - # cmake_path(GET rcs_dist_info FILENAME rcs_library_filename) - # string(REPLACE "rcs-" "" rcs_VERSION "${rcs_library_filename}") - # string(REPLACE ".dist-info" "" rcs_VERSION "${rcs_VERSION}") - - # Create the imported target - add_library(rcs SHARED IMPORTED) - target_include_directories(rcs INTERFACE ${rcs_INCLUDE_DIRS}) - set_target_properties( - rcs - PROPERTIES - IMPORTED_LOCATION "${rcs_library_path}" - ) - set(rcs_FOUND TRUE) -endif() diff --git a/extensions/rcs_robotics_library/debian_deps.txt b/extensions/rcs_robotics_library/debian_deps.txt deleted file mode 100644 index c8c23b8b..00000000 --- a/extensions/rcs_robotics_library/debian_deps.txt +++ /dev/null @@ -1,8 +0,0 @@ -libxslt-dev -libcoin-dev -libccd-dev -libboost-all-dev -liblzma-dev -libxml2-dev -libxslt1-dev -libeigen3-dev \ No newline at end of file diff --git a/extensions/rcs_robotics_library/pyproject.toml b/extensions/rcs_robotics_library/pyproject.toml deleted file mode 100644 index fd214b2d..00000000 --- a/extensions/rcs_robotics_library/pyproject.toml +++ /dev/null @@ -1,46 +0,0 @@ -[build-system] -requires = [ - "build", - "wheel", - "setuptools>=45", - "scikit-build-core>=0.3.3", - "pybind11", - "cmake", - "ninja", - "rcs-core>=0.7.2", -] -build-backend = "scikit_build_core.build" - -[project] -name = "rcs_robotics_library" -version = "0.7.2" -description = "RCS robotics library integration" -readme = "README.md" -license = "AGPL-3.0-or-later" -dependencies = ["rcs-core>=0.7.2"] -maintainers = [{ name = "Tobias Juelg", email = "tobias.juelg@utn.de" }] -authors = [ - { name = "Tobias Juelg", email = "tobias.juelg@utn.de" }, - { name = "Pierre Krack", email = "pierre.krack@utn.de" }, -] -requires-python = ">=3.11" - - -[tool.scikit-build] -build.verbose = true -build.targets = ["_core"] -logging.level = "INFO" -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"] - -[tool.isort] -profile = "black" diff --git a/extensions/rcs_robotics_library/src/CMakeLists.txt b/extensions/rcs_robotics_library/src/CMakeLists.txt deleted file mode 100644 index a458c164..00000000 --- a/extensions/rcs_robotics_library/src/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -target_include_directories(rcs INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) -add_subdirectory(pybind) diff --git a/extensions/rcs_robotics_library/src/pybind/CMakeLists.txt b/extensions/rcs_robotics_library/src/pybind/CMakeLists.txt deleted file mode 100644 index 09d0acae..00000000 --- a/extensions/rcs_robotics_library/src/pybind/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -pybind11_add_module(_core MODULE rcs.cpp) -target_link_libraries(_core PRIVATE rcs mdl pinocchio::all) -target_compile_definitions(_core PRIVATE VERSION_INFO=${PROJECT_VERSION}) - -set_target_properties(_core PROPERTIES - INSTALL_RPATH "$ORIGIN;$ORIGIN/../rcs;$ORIGIN/../cmeel.prefix/lib" - INTERPROCEDURAL_OPTIMIZATION TRUE -) - -# in pip -install(TARGETS _core DESTINATION rcs_robotics_library COMPONENT python_package) diff --git a/extensions/rcs_robotics_library/src/pybind/RL.h b/extensions/rcs_robotics_library/src/pybind/RL.h deleted file mode 100644 index 71c8e11b..00000000 --- a/extensions/rcs_robotics_library/src/pybind/RL.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef RCS_RL_H -#define RCS_RL_H - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace rcs { -namespace robotics_library { - -class RoboticsLibraryIK : public rcs::common::Kinematics { - private: - const int random_restarts = 0; - const double eps = 1e-3; - struct { - std::shared_ptr mdl; - std::shared_ptr kin; - std::shared_ptr ik; - } rl_data; - - public: - RoboticsLibraryIK(const std::string& urdf_path, size_t max_duration_ms = 300) - : rl_data() { - this->rl_data.mdl = rl::mdl::UrdfFactory().create(urdf_path); - this->rl_data.kin = - std::dynamic_pointer_cast(this->rl_data.mdl); - this->rl_data.ik = std::make_shared( - this->rl_data.kin.get()); - this->rl_data.ik->setRandomRestarts(this->random_restarts); - this->rl_data.ik->setEpsilon(this->eps); - this->rl_data.ik->setDuration(std::chrono::milliseconds(max_duration_ms)); - } - std::optional inverse( - const rcs::common::Pose& pose, const rcs::common::VectorXd& q0, - const rcs::common::Pose& tcp_offset = - rcs::common::Pose::Identity()) override { - // pose is assumed to be in the robots coordinate frame - this->rl_data.kin->setPosition(q0); - this->rl_data.kin->forwardPosition(); - rcs::common::Pose new_pose = pose * tcp_offset.inverse(); - - this->rl_data.ik->addGoal(new_pose.affine_matrix(), 0); - bool success = this->rl_data.ik->solve(); - if (success) { - // is this forward needed and is it mabye possible to call - // this on the model? - this->rl_data.kin->forwardPosition(); - return this->rl_data.kin->getPosition(); - } else { - return std::nullopt; - } - } - rcs::common::Pose forward(const rcs::common::VectorXd& q0, - const rcs::common::Pose& tcp_offset) override { - // pose is assumed to be in the robots coordinate frame - this->rl_data.kin->setPosition(q0); - this->rl_data.kin->forwardPosition(); - rcs::common::Pose pose = this->rl_data.kin->getOperationalPosition(0); - // apply the tcp offset - return pose * tcp_offset.inverse(); - } -}; - -} // namespace robotics_library -} // namespace rcs - -#endif // RCS_RL_H diff --git a/extensions/rcs_robotics_library/src/pybind/rcs.cpp b/extensions/rcs_robotics_library/src/pybind/rcs.cpp deleted file mode 100644 index 094daab7..00000000 --- a/extensions/rcs_robotics_library/src/pybind/rcs.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include -#include -#include -#include - -#include - -#include "RL.h" -#include "rcs/Kinematics.h" -#include "rl/mdl/UrdfFactory.h" - -// TODO: define exceptions - -#define STRINGIFY(x) #x -#define MACRO_STRINGIFY(x) STRINGIFY(x) - -namespace py = pybind11; - -PYBIND11_MODULE(_core, m) { - m.doc() = R"pbdoc( - Robot Control Stack Python Bindings - ----------------------- - - .. currentmodule:: _core - - .. autosummary:: - :toctree: _generate - - )pbdoc"; -#ifdef VERSION_INFO - m.attr("__version__") = MACRO_STRINGIFY(VERSION_INFO); -#else - m.attr("__version__") = "dev"; -#endif - - // HARDWARE MODULE - auto rl = m.def_submodule("rl", "rcs robotics library module"); - - py::object kinematics = - (py::object)py::module_::import("rcs").attr("common").attr("Kinematics"); - py::class_>( - rl, "RoboticsLibraryIK", kinematics) - .def(py::init(), py::arg("urdf_path"), - py::arg("max_duration_ms") = 300); -} diff --git a/extensions/rcs_robotics_library/src/rcs_robotics_library/__init__.py b/extensions/rcs_robotics_library/src/rcs_robotics_library/__init__.py deleted file mode 100644 index ff5f354a..00000000 --- a/extensions/rcs_robotics_library/src/rcs_robotics_library/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from rcs_robotics_library._core import __version__, rl - -__all__ = [ - "rl", - "__version__", -] 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 deleted file mode 100644 index d574dd50..00000000 --- a/extensions/rcs_robotics_library/src/rcs_robotics_library/_core/__init__.pyi +++ /dev/null @@ -1,19 +0,0 @@ -# ATTENTION: auto generated from C++ code, use `make stubgen` to update! -""" - - Robot Control Stack Python Bindings - ----------------------- - - .. currentmodule:: _core - - .. autosummary:: - :toctree: _generate - - -""" -from __future__ import annotations - -from . import rl - -__all__: list[str] = ["rl"] -__version__: str = "0.7.2" diff --git a/extensions/rcs_robotics_library/src/rcs_robotics_library/_core/rl.pyi b/extensions/rcs_robotics_library/src/rcs_robotics_library/_core/rl.pyi deleted file mode 100644 index d0001745..00000000 --- a/extensions/rcs_robotics_library/src/rcs_robotics_library/_core/rl.pyi +++ /dev/null @@ -1,12 +0,0 @@ -# ATTENTION: auto generated from C++ code, use `make stubgen` to update! -""" -rcs robotics library module -""" -from __future__ import annotations - -import rcs._core.common - -__all__: list[str] = ["RoboticsLibraryIK"] - -class RoboticsLibraryIK(rcs._core.common.Kinematics): - def __init__(self, urdf_path: str, max_duration_ms: int = 300) -> None: ... diff --git a/extensions/rcs_robotiq2f85/pyproject.toml b/extensions/rcs_robotiq2f85/pyproject.toml index 02b02c22..d042108b 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.2" +version = "0.7.3" description="RCS RobotiQ module" dependencies = [ - "rcs-core>=0.7.2", + "rcs-core>=0.7.3", "robotiq2f==0.2.0", "typer~=0.9", ] diff --git a/extensions/rcs_robotiq2f85/src/rcs_robotiq2f85/__init__.py b/extensions/rcs_robotiq2f85/src/rcs_robotiq2f85/__init__.py index bc8c296f..4910b9ec 100644 --- a/extensions/rcs_robotiq2f85/src/rcs_robotiq2f85/__init__.py +++ b/extensions/rcs_robotiq2f85/src/rcs_robotiq2f85/__init__.py @@ -1 +1 @@ -__version__ = "0.7.2" +__version__ = "0.7.3" diff --git a/extensions/rcs_so101/CMakeLists.txt b/extensions/rcs_so101/CMakeLists.txt index 472128ef..40bae400 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.2 + VERSION 0.7.3 DESCRIPTION "RCS so101 ik" ) diff --git a/extensions/rcs_so101/pyproject.toml b/extensions/rcs_so101/pyproject.toml index 33b71daf..97497f3f 100644 --- a/extensions/rcs_so101/pyproject.toml +++ b/extensions/rcs_so101/pyproject.toml @@ -7,21 +7,29 @@ requires = [ "pybind11", "cmake", "ninja", - "rcs-core>=0.7.2", + "rcs-core>=0.7.3", ] build-backend = "scikit_build_core.build" [project] name = "rcs_so101" -version = "0.7.2" +version = "0.7.3" description = "RCS SO101 module" -dependencies = ["rcs-core>=0.7.2", "lerobot==0.3.3"] +dependencies = ["rcs-core>=0.7.3", "lerobot==0.3.3"] readme = "README.md" 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" +[dependency-groups] +build_deps = [ + "pin==3.7.0", + "cmeel-urdfdom<5", + "cmeel-tinyxml2<11", + "scikit-build-core>=0.3.3", +] + [tool.scikit-build] build.verbose = true build.targets = ["_core"] @@ -31,7 +39,15 @@ wheel.packages = ["src/rcs_so101"] install.components = ["python_package"] [tool.cibuildwheel] -skip = ["cp314*", "*-musllinux*"] +build = ["cp311-*", "cp312-*", "cp313-*"] +skip = ["*-musllinux*"] +before-build = "pip install --upgrade pip && pip install --group {package}/pyproject.toml:build_deps cmake ninja && pip install --no-index --no-deps --find-links {project}/dist/core rcs-core" +build-frontend = { name = "pip", args = ["--no-build-isolation"] } +environment = { SKBUILD_BUILD_DIR = "/tmp/rcs-build/{wheel_tag}" } + +[tool.cibuildwheel.linux] +archs = ["x86_64"] +manylinux-x86_64-image = "manylinux_2_28" 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] diff --git a/extensions/rcs_so101/src/rcs_so101/_core/__init__.pyi b/extensions/rcs_so101/src/rcs_so101/_core/__init__.pyi index 1baf0df9..7276f647 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.2" +__version__: str = "0.7.3" diff --git a/extensions/rcs_so101/src/rcs_so101/creators.py b/extensions/rcs_so101/src/rcs_so101/creators.py index 696da475..7381b497 100644 --- a/extensions/rcs_so101/src/rcs_so101/creators.py +++ b/extensions/rcs_so101/src/rcs_so101/creators.py @@ -4,7 +4,7 @@ import gymnasium as gym from rcs._core.common import BaseCameraConfig -from rcs.camera.hw import HardwareCamera, HardwareCameraSet +from rcs.camera.hw import CalibrationStrategy, HardwareCamera, HardwareCameraSet from rcs.envs.base import ( CameraSetWrapper, ControlMode, @@ -32,7 +32,6 @@ class HardwareCameraCreatorConfig: def _create_realsense_camera(cfg: HardwareCameraCreatorConfig) -> HardwareCamera: try: - from rcs.camera.hw import CalibrationStrategy from rcs_realsense.calibration import FR3BaseArucoCalibration from rcs_realsense.camera import RealSenseCameraSet except ImportError as e: diff --git a/extensions/rcs_tacto/README.md b/extensions/rcs_tacto/README.md index b48e0414..a9902aca 100644 --- a/extensions/rcs_tacto/README.md +++ b/extensions/rcs_tacto/README.md @@ -7,13 +7,9 @@ Documentation: ## Installation -Install from PyPI: - -```shell -pip install rcs-tacto -``` - -Warning: plain `pip install rcs-tacto` will install the published `rcs-core` dependency from PyPI. +`mujoco-tacto` is not published on PyPI, so it is pinned as a direct git reference in +`pyproject.toml`. As a consequence this extension is installable from a checkout but cannot be +published to PyPI, and it is not part of the wheel build workflow. Install from a local checkout: diff --git a/extensions/rcs_tacto/pyproject.toml b/extensions/rcs_tacto/pyproject.toml index 576b67ea..5abca0a5 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.2" +version = "0.7.3" description = "RCS integration of tacto" dependencies = [ - "rcs-core>=0.7.2", + "rcs-core>=0.7.3", "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 bc8c296f..4910b9ec 100644 --- a/extensions/rcs_tacto/src/rcs_tacto/__init__.py +++ b/extensions/rcs_tacto/src/rcs_tacto/__init__.py @@ -1 +1 @@ -__version__ = "0.7.2" +__version__ = "0.7.3" diff --git a/extensions/rcs_taxim/pyproject.toml b/extensions/rcs_taxim/pyproject.toml index 15e7a6e6..fbff8682 100644 --- a/extensions/rcs_taxim/pyproject.toml +++ b/extensions/rcs_taxim/pyproject.toml @@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta" [project] name = "rcs_taxim" -version = "0.7.2" +version = "0.7.3" description = "RCS integration of mujoco-taxim" dependencies = [ - "rcs>=0.7.2", + "rcs-core>=0.7.3", "omegaconf", "mujoco-taxim@git+https://github.com/utn-air/mujoco-taxim.git@norm2tex", ] diff --git a/extensions/rcs_taxim/src/rcs_taxim/__init__.py b/extensions/rcs_taxim/src/rcs_taxim/__init__.py index bc8c296f..4910b9ec 100644 --- a/extensions/rcs_taxim/src/rcs_taxim/__init__.py +++ b/extensions/rcs_taxim/src/rcs_taxim/__init__.py @@ -1 +1 @@ -__version__ = "0.7.2" +__version__ = "0.7.3" diff --git a/extensions/rcs_ur5e/pyproject.toml b/extensions/rcs_ur5e/pyproject.toml index 497530cd..fee72473 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.2" +version = "0.7.3" description = "RCS UR5e module" -dependencies = ["rcs-core>=0.7.2", "ur_rtde==1.6.1"] +dependencies = ["rcs-core>=0.7.3", "ur_rtde==1.6.1"] readme = "README.md" license = "AGPL-3.0-or-later" maintainers = [ diff --git a/extensions/rcs_ur5e/src/rcs_ur5e/__init__.py b/extensions/rcs_ur5e/src/rcs_ur5e/__init__.py index deee221c..fa1c54b7 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.2" +__version__ = "0.7.3" __all__ = [ "configs", diff --git a/extensions/rcs_ur5e/src/rcs_ur5e/creators.py b/extensions/rcs_ur5e/src/rcs_ur5e/creators.py index 70d984f4..f89f3880 100644 --- a/extensions/rcs_ur5e/src/rcs_ur5e/creators.py +++ b/extensions/rcs_ur5e/src/rcs_ur5e/creators.py @@ -4,7 +4,7 @@ import gymnasium as gym from rcs._core.common import BaseCameraConfig, Gripper, GripperConfig -from rcs.camera.hw import HardwareCamera, HardwareCameraSet +from rcs.camera.hw import CalibrationStrategy, HardwareCamera, HardwareCameraSet from rcs.envs.base import ( CameraSetWrapper, ControlMode, @@ -33,7 +33,6 @@ class HardwareCameraCreatorConfig: def _create_realsense_camera(cfg: HardwareCameraCreatorConfig) -> HardwareCamera: try: - from rcs.camera.hw import CalibrationStrategy from rcs_realsense.calibration import FR3BaseArucoCalibration from rcs_realsense.camera import RealSenseCameraSet except ImportError as e: diff --git a/extensions/rcs_usb_cam/pyproject.toml b/extensions/rcs_usb_cam/pyproject.toml index a78c3852..33e14d95 100644 --- a/extensions/rcs_usb_cam/pyproject.toml +++ b/extensions/rcs_usb_cam/pyproject.toml @@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta" [project] name = "rcs_usb_cam" -version = "0.7.2" +version = "0.7.3" description = "RCS USB Camera module" readme = "README.md" license = "AGPL-3.0-or-later" -dependencies = ["rcs-core>=0.7.2", "opencv-python~=4.10.0"] +dependencies = ["rcs-core>=0.7.3", "opencv-python~=4.10.0"] maintainers = [ { name = "Tobias Juelg", email = "tobias.juelg@utn.de" }, { name = "Seongjin Bien", email = "seongjin.bien@utn.de" }, diff --git a/extensions/rcs_xarm7/pyproject.toml b/extensions/rcs_xarm7/pyproject.toml index 3671b0ba..066425f1 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.2" +version = "0.7.3" description = "RCS xArm7 module" -dependencies = ["rcs-core>=0.7.2", "xarm-python-sdk==1.17.0"] +dependencies = ["rcs-core>=0.7.3", "xarm-python-sdk==1.17.0"] readme = "README.md" license = "AGPL-3.0-or-later" maintainers = [ diff --git a/extensions/rcs_xarm7/src/rcs_xarm7/__init__.py b/extensions/rcs_xarm7/src/rcs_xarm7/__init__.py index aea67f74..06fe62cc 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.2" +__version__ = "0.7.3" __all__ = [ "configs", diff --git a/extensions/rcs_xarm7/src/rcs_xarm7/creators.py b/extensions/rcs_xarm7/src/rcs_xarm7/creators.py index 42ea2ecd..a4edb2be 100644 --- a/extensions/rcs_xarm7/src/rcs_xarm7/creators.py +++ b/extensions/rcs_xarm7/src/rcs_xarm7/creators.py @@ -6,7 +6,7 @@ import gymnasium as gym from rcs._core.common import BaseCameraConfig -from rcs.camera.hw import HardwareCamera, HardwareCameraSet +from rcs.camera.hw import CalibrationStrategy, HardwareCamera, HardwareCameraSet from rcs.envs.base import ( CameraSetWrapper, ControlMode, @@ -36,7 +36,6 @@ class HardwareCameraCreatorConfig: def _create_realsense_camera(cfg: HardwareCameraCreatorConfig) -> HardwareCamera: try: - from rcs.camera.hw import CalibrationStrategy from rcs_realsense.calibration import FR3BaseArucoCalibration from rcs_realsense.camera import RealSenseCameraSet except ImportError as e: diff --git a/extensions/rcs_yam/pyproject.toml b/extensions/rcs_yam/pyproject.toml index 3295c872..30b321fe 100644 --- a/extensions/rcs_yam/pyproject.toml +++ b/extensions/rcs_yam/pyproject.toml @@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta" [project] name = "rcs_yam" -version = "0.7.2" +version = "0.7.3" description = "RCS YAM module" dependencies = [ - "rcs-core>=0.7.2", + "rcs-core>=0.7.3", # i2rt is not published on PyPI, so it is pinned to a commit of the upstream repository. # A direct reference makes this project unpublishable to PyPI, see README.md. "i2rt @ git+https://github.com/i2rt-robotics/i2rt@main", # tested commit: b9d8704c593aee4ef129d644f881564b8f2c4f6b diff --git a/extensions/rcs_yam/src/rcs_yam/__init__.py b/extensions/rcs_yam/src/rcs_yam/__init__.py index f8ffe7a2..d33f4a65 100644 --- a/extensions/rcs_yam/src/rcs_yam/__init__.py +++ b/extensions/rcs_yam/src/rcs_yam/__init__.py @@ -1,6 +1,6 @@ from rcs_yam import configs, creators, hw -__version__ = "0.7.2" +__version__ = "0.7.3" __all__ = [ "configs", diff --git a/extensions/rcs_yam/src/rcs_yam/configs.py b/extensions/rcs_yam/src/rcs_yam/configs.py index c1b134fd..2d7a6f13 100644 --- a/extensions/rcs_yam/src/rcs_yam/configs.py +++ b/extensions/rcs_yam/src/rcs_yam/configs.py @@ -13,6 +13,9 @@ class DefaultYamHardwareEnv(RCSYamConfigEnvCreator): channel = "can0" + # in N, <=0 turns off the limit + # 50 N is the default from YAM + gripper_force = 50.0 def config(self) -> YamHardwareEnvCreatorConfig: robot_type = RobotType("Yam") @@ -20,6 +23,7 @@ def config(self) -> YamHardwareEnvCreatorConfig: robot_cfg = YamConfig( channel=self.channel, gripper_type_id="linear_4310", + gripper_force=self.gripper_force, async_control=False, robot_type=robot_type, kinematic_model_path=rcs.ROBOTS[robot_type].mjcf_model_path, @@ -45,9 +49,12 @@ def config(self) -> YamHardwareEnvCreatorConfig: class DefaultYamDualMultiHardwareEnv(RCSYamMultiConfigEnvCreator): left_channel = "can0" right_channel = "can1" + # in N, <=0 turns off the limit + gripper_force = 50 def config(self) -> YamMultiHardwareEnvCreatorConfig: base = DefaultYamHardwareEnv() + base.gripper_force = self.gripper_force base.channel = self.left_channel left_cfg = base.config() diff --git a/extensions/rcs_yam/src/rcs_yam/creators.py b/extensions/rcs_yam/src/rcs_yam/creators.py index b38823b8..aa42554a 100644 --- a/extensions/rcs_yam/src/rcs_yam/creators.py +++ b/extensions/rcs_yam/src/rcs_yam/creators.py @@ -4,7 +4,12 @@ import gymnasium as gym from rcs._core.common import BaseCameraConfig, GripperConfig -from rcs.camera.hw import DummyCalibrationStrategy, HardwareCamera, HardwareCameraSet +from rcs.camera.hw import ( + CalibrationStrategy, + DummyCalibrationStrategy, + HardwareCamera, + HardwareCameraSet, +) from rcs.envs.base import ( CameraSetWrapper, ControlMode, @@ -34,7 +39,6 @@ class HardwareCameraCreatorConfig: def _create_realsense_camera(cfg: HardwareCameraCreatorConfig) -> HardwareCamera: try: - from rcs.camera.hw import CalibrationStrategy from rcs_realsense.camera import RealSenseCameraSet except ImportError as e: msg = "RealSense camera support requires the `rcs_realsense` extension to be installed." diff --git a/extensions/rcs_yam/src/rcs_yam/hw.py b/extensions/rcs_yam/src/rcs_yam/hw.py index 24063733..3142b471 100644 --- a/extensions/rcs_yam/src/rcs_yam/hw.py +++ b/extensions/rcs_yam/src/rcs_yam/hw.py @@ -10,10 +10,40 @@ import typing import numpy as np +from i2rt.robots.get_robot import get_yam_robot +from i2rt.robots.utils import ArmType, GripperForceLimiter, GripperType from rcs.common_typing import RobotConfigKwargs from rcs import common +# Torque in Nm i2rt feeds forward to break the stiction of the gripper screw (utils.py:648). It +# adds no grip force, but a cap below it leaves the fingers unable to move at all. +I2RT_FRICTION_COMPENSATION = 0.3 + +I2RT_DEFAULT_GRIPPER_FORCE = 50.0 + +SHUT_FORCE = 1.0 + +GRASP_WIDTH_TOLERANCE = 0.02 +GRASP_EFFORT_THRESHOLD = 0.5 + + +class YamGripperForceLimiter(GripperForceLimiter): + def __init__( + self, + *args: typing.Any, + friction_compensation: float = I2RT_FRICTION_COMPENSATION, + **kwargs: typing.Any, + ): + super().__init__(*args, **kwargs) + self.friction_compensation = friction_compensation + + def update(self, gripper_state: dict[str, float]) -> float: # type: ignore[override] + cap = float(self.gripper_force_torque_map(current_angle=gripper_state["current_qpos"])) + slack = (cap + self.friction_compensation) / self._kp + measured = gripper_state["current_qpos"] + return float(np.clip(gripper_state["target_qpos"], measured - slack, measured + slack)) + class YamConfig(common.RobotConfig): """Configuration of a single YAM arm on one CAN bus.""" @@ -33,6 +63,8 @@ def __init__( max_joint_velocity: float = 0.5, move_home_duration: float = 2.0, gripper_limits_override: np.ndarray | None = None, + gripper_force: float | None = None, + gripper_friction_compensation: float = I2RT_FRICTION_COMPENSATION, **kwargs: typing.Unpack[RobotConfigKwargs], ): super().__init__(**kwargs) @@ -56,6 +88,12 @@ def __init__( self.move_home_duration = move_home_duration # If set, skips the calibration run that would otherwise drive the fingers to both stops. self.gripper_limits_override = gripper_limits_override + # Force in newtons the fingers close and hold with. None keeps the i2rt default of 50 N, a + # value <= 0 disables limiting and the gripper squeezes at full kp. + self.gripper_force = gripper_force + # To measure it for an arm, command a close at a negligible `gripper_force` and raise this + # until the fingers just start to move. + self.gripper_friction_compensation = gripper_friction_compensation class Yam(common.Robot): @@ -65,21 +103,22 @@ class Yam(common.Robot): def __init__(self, cfg: YamConfig, ik: common.Kinematics): super().__init__() - from i2rt.robots.get_robot import get_yam_robot - from i2rt.robots.utils import ArmType, GripperType - self._closed = True self.ik = ik self._config = cfg self._dof = int(cfg.dof) + self._arm_type = ArmType.from_string_name(cfg.arm_type_id) + self._gripper_type = GripperType.from_string_name(cfg.gripper_type_id) self._robot = get_yam_robot( channel=cfg.channel, - arm_type=ArmType.from_string_name(cfg.arm_type_id), - gripper_type=GripperType.from_string_name(cfg.gripper_type_id), + arm_type=self._arm_type, + gripper_type=self._gripper_type, gripper_limits_override=cfg.gripper_limits_override, ) self._closed = False self._has_gripper = self._robot.num_dofs() > self._dof + if cfg.gripper_force is not None: + self.set_gripper_force(cfg.gripper_force) self._lock = threading.Lock() # Seeding the target from the measured state avoids a jump on the first partial command. self._target = np.asarray(self._robot.get_joint_pos(), dtype=np.float64).copy() @@ -120,6 +159,17 @@ def get_gripper_width(self) -> float: self._assert_gripper() return float(np.asarray(self._robot.get_joint_pos(), dtype=np.float64)[self._dof]) + def get_gripper_effort(self) -> float: + """Torque in Nm the gripper motor currently applies, useful to watch a grasp stall.""" + self._assert_gripper() + return float(self._robot.get_observations()["gripper_eff"][0]) + + def get_commanded_gripper_width(self) -> float: + """Normalized width the fingers are travelling towards, as last written to the target.""" + self._assert_gripper() + with self._lock: + return float(self._target[self._dof]) + def get_cartesian_position(self) -> common.Pose: # `Kinematics.forward` applies the inverse of the offset it is handed, so the TCP is composed # here instead, to match the pose `SimRobot::get_cartesian_position` reports in simulation. @@ -143,6 +193,24 @@ def set_gripper_width(self, width: float) -> None: self._assert_gripper() self._command(gripper=float(np.clip(width, 0.0, 1.0))) + def set_gripper_force(self, force: float, friction_compensation: float | None = None) -> None: + """Set the force in newtons the fingers close and hold with, <= 0 disables limiting.""" + self._assert_gripper() + if friction_compensation is None: + friction_compensation = self._config.gripper_friction_compensation + if force > 0: + gripper_index = self._robot._gripper_index + self._robot._gripper_force_limiter = YamGripperForceLimiter( + max_force=force, + gripper_type=self._gripper_type, + arm_type=self._arm_type, + kp=float(self._robot._kp[gripper_index]), + friction_compensation=friction_compensation, + ) + self._robot._limit_gripper_force = force + self._config.gripper_force = force + self._config.gripper_friction_compensation = friction_compensation + def move_home(self) -> None: if self._config.q_home is None: msg = "No home position configured." @@ -209,27 +277,50 @@ def __init__(self, cfg: common.GripperConfig, robot: Yam): super().__init__() self._cfg = cfg self._robot = robot + self._state = common.GripperState() def get_config(self) -> common.GripperConfig: return self._cfg + def get_state(self) -> common.GripperState: + return self._state + + def is_grasped(self) -> bool: + """True while an object holds the fingers short of the width they are closing to.""" + short_of_target = self.get_normalized_width() - self._robot.get_commanded_gripper_width() + if short_of_target <= GRASP_WIDTH_TOLERANCE: + return False + return abs(self._robot.get_gripper_effort()) > GRASP_EFFORT_THRESHOLD + def get_normalized_width(self) -> float: return self._robot.get_gripper_width() def set_normalized_width(self, width: float, force: float = 0) -> None: + """Move the fingers to `width`, 0 is closed and 1 is open, force in newtons.""" if not (0 <= width <= 1): msg = f"Width must be between 0 and 1, got {width}." raise ValueError(msg) + if force < 0: + msg = f"Force must be positive, got {force}. Turn limiting off with `Yam.set_gripper_force`." + raise ValueError(msg) + if force == 0: + self._robot.set_gripper_force(I2RT_DEFAULT_GRIPPER_FORCE) + else: + self._robot.set_gripper_force(force) self._robot.set_gripper_width(width) def open(self) -> None: self.set_normalized_width(1.0) def grasp(self) -> None: + """Close the fingers at the force the arm is configured with.""" + force = self._robot.get_config().gripper_force + self._robot.set_gripper_force(I2RT_DEFAULT_GRIPPER_FORCE if force is None else force) self.set_normalized_width(0.0) def shut(self) -> None: - self.set_normalized_width(0.0) + """Close the fingers without gripping.""" + self.set_normalized_width(0.0, force=SHUT_FORCE) def reset(self) -> None: self.open() diff --git a/extensions/rcs_zed/pyproject.toml b/extensions/rcs_zed/pyproject.toml index 2ed6d4b9..b2683fb8 100644 --- a/extensions/rcs_zed/pyproject.toml +++ b/extensions/rcs_zed/pyproject.toml @@ -4,12 +4,12 @@ build-backend = "setuptools.build_meta" [project] name = "rcs_zed" -version = "0.7.2" +version = "0.7.3" description = "RCS ZED camera module" readme = "README.md" license = "AGPL-3.0-or-later" dependencies = [ - "rcs-core>=0.7.2", + "rcs-core>=0.7.3", "opencv-python~=4.10.0", "typer~=0.9", ] diff --git a/include/rcs/Robot.h b/include/rcs/Robot.h index 6186314f..cf33b36d 100644 --- a/include/rcs/Robot.h +++ b/include/rcs/Robot.h @@ -61,10 +61,10 @@ struct RobotConfig { Eigen::Matrix joint_limits = (Eigen::Matrix(2, 7) << // low 7‐tuple - -2.3093, - -1.5133, -2.4937, -2.7478, -2.4800, 0.8521, -2.6895, + -2.3476, + -1.5454, -2.4937, -2.7714, -2.5100, 0.7773, -2.7045, // high 7‐tuple - 2.3093, 1.5133, 2.4937, -0.4461, 2.4800, 4.2094, 2.6895) + 2.3476, 1.5454, 2.4937, -0.4226, 2.5100, 4.2841, 2.7045) .finished(); virtual ~RobotConfig() {}; }; diff --git a/pyproject.toml b/pyproject.toml index 21f28587..2079ea41 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,7 @@ build-backend = "scikit_build_core.build" [project] name = "rcs_core" -version = "0.7.2" +version = "0.7.3" 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", @@ -72,6 +72,8 @@ dev = [ "clang-tidy", "ninja", "cmake", + "cibuildwheel==2.22.0", + "twine~=6.0", ] build_deps = [ "mujoco==3.10.0", @@ -82,11 +84,20 @@ build_deps = [ ] [tool.cibuildwheel] -skip = ["cp314*", "*-musllinux*"] -# Install X11 headers needed to compile GLFW -before-all = "yum install -y libXi-devel libXcursor-devel libXinerama-devel libXrandr-devel glfw-devel" -# Exclude MuJoCo AND Pinocchio from being bundled. -repair-wheel-command = "auditwheel repair -w {dest_dir} {wheel} --exclude libmujoco.so.* --exclude libpinocchio_default.so.3.7.0 --exclude libpinocchio_parsers.so.3.7.0" +build = ["cp311-*", "cp312-*", "cp313-*"] +skip = ["*-musllinux*"] +before-build = "pip install --upgrade pip && pip install --group {package}/pyproject.toml:build_deps wheel setuptools cmake ninja" +environment = { SKBUILD_BUILD_DIR = "/tmp/rcs-build/{wheel_tag}" } + +[tool.cibuildwheel.linux] +archs = ["x86_64"] +manylinux-x86_64-image = "manylinux_2_28" +before-all = "yum install -y epel-release && yum install -y libXi-devel libXcursor-devel libXinerama-devel libXrandr-devel glfw-devel" +repair-wheel-command = "auditwheel repair -w {dest_dir} {wheel} --exclude libmujoco.so.3.10.0 --exclude libpinocchio_default.so.3.7.0 --exclude libpinocchio_parsers.so.3.7.0" + +[tool.cibuildwheel.macos] +archs = ["arm64"] +repair-wheel-command = "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel} --exclude libmujoco --exclude libpinocchio" [tool.scikit-build] build.verbose = true @@ -187,7 +198,6 @@ version_files = [ "extensions/rcs_fr3/CMakeLists.txt:VERSION", "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-core>=(.*)\"", # --- Panda Extension --- @@ -196,12 +206,6 @@ version_files = [ "extensions/rcs_panda/pyproject.toml:version", "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-core>=(.*)\"", - # --- SO101 --- "extensions/rcs_so101/CMakeLists.txt:VERSION", "extensions/rcs_so101/src/rcs_so101/_core/__init__.pyi:__version__", diff --git a/python/rcs/__init__.py b/python/rcs/__init__.py index cf7fe01c..d8ed06a9 100644 --- a/python/rcs/__init__.py +++ b/python/rcs/__init__.py @@ -110,8 +110,8 @@ class RobotMetaConfig: q_home=np.array([0.0, -np.pi / 4, 0.0, -3 * np.pi / 4, 0.0, np.pi / 2, 0.0]), joint_limits=np.array( [ - [-2.3093, -1.5133, -2.4937, -2.7478, -2.4800, 0.8521, -2.6895], - [2.3093, 1.5133, 2.4937, -0.4461, 2.4800, 4.2094, 2.6895], + [-2.3476, -1.5454, -2.4937, -2.7714, -2.5100, 0.7773, -2.7045], + [2.3476, 1.5454, 2.4937, -0.4226, 2.5100, 4.2841, 2.7045], ] ), ), @@ -148,8 +148,8 @@ class RobotMetaConfig: q_home=np.array([0, -45.0 / 180.0 * np.pi, 0, 15.0 / 180.0 * np.pi, 0, -25.0 / 180.0 * np.pi, 0]), joint_limits=np.array( [ - [-2 * np.pi, -2.094395, -2 * np.pi, -3.92699, -2 * np.pi, -np.pi, -2 * np.pi], - [2 * np.pi, 2.059488, 2 * np.pi, 0.191986, 2 * np.pi, 1.692969, 2 * np.pi], + [-2 * np.pi, -2.059488, -2 * np.pi, -0.191986, -2 * np.pi, -1.692969, -2 * np.pi], + [2 * np.pi, 2.094395, 2 * np.pi, 3.92699, 2 * np.pi, np.pi, 2 * np.pi], ] ), ), diff --git a/python/rcs/_core/__init__.pyi b/python/rcs/_core/__init__.pyi index 5a27ade9..bc3a20fd 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.2" +__version__: str = "0.7.3" diff --git a/python/rcs/envs/base.py b/python/rcs/envs/base.py index 20b9ebcd..0d1b6261 100644 --- a/python/rcs/envs/base.py +++ b/python/rcs/envs/base.py @@ -219,7 +219,11 @@ def __init__(self, frequency: float | None = None) -> None: None disables rate limiting. """ super().__init__() - assert frequency is not None and frequency > 0, "frequency must be set to a positive value" + if frequency is None: + _logger.warning( + "No control frequency set: steps are not rate limited and may command the robot " + "faster than it can handle, which can damage the hardware." + ) self.frame_rate = SimpleFrameRate(frequency, "Hardware Loop") def step(self, action: dict[str, Any]) -> tuple[dict[str, Any], float, bool, bool, dict]: @@ -350,7 +354,6 @@ def __init__(self, env, robot: common.Robot, control_mode: ControlMode, home_on_ self.joints_key = get_space_keys(JointsDictType)[0] self.trpy_key = get_space_keys(TRPYDictType)[0] self.tquat_key = get_space_keys(TQuatDictType)[0] - self.prev_action: dict | None = None def get_unwrapped_control_mode(self, idx: int) -> ControlMode: """Returns the unwrapped control mode at a certain index. 0 is the base control mode, -1 the last.""" @@ -395,29 +398,17 @@ def action(self, action: dict[str, Any]) -> dict[str, Any]: ): msg = "Given type is not matching control mode!" raise RuntimeError(msg) - last_action = self.prev_action - self.prev_action = copy.deepcopy(action) - # shallow copy action = dict(action) - if self.get_base_control_mode() == ControlMode.JOINTS and ( - last_action is None - or not np.allclose(action[self.joints_key], last_action[self.joints_key], atol=1e-03, rtol=0) - ): + if self.get_base_control_mode() == ControlMode.JOINTS: self.robot.set_joint_position(action[self.joints_key]) action.pop(self.joints_key) - elif self.get_base_control_mode() == ControlMode.CARTESIAN_TRPY and ( - last_action is None - or not np.allclose(action[self.trpy_key], last_action[self.trpy_key], atol=1e-03, rtol=0) - ): + elif self.get_base_control_mode() == ControlMode.CARTESIAN_TRPY: self.robot.set_cartesian_position( common.Pose(translation=action[self.trpy_key][:3], rpy_vector=action[self.trpy_key][3:]) ) action.pop(self.trpy_key) - elif self.get_base_control_mode() == ControlMode.CARTESIAN_TQuat and ( - last_action is None - or not np.allclose(action[self.tquat_key], last_action[self.tquat_key], atol=1e-03, rtol=0) - ): + elif self.get_base_control_mode() == ControlMode.CARTESIAN_TQuat: self.robot.set_cartesian_position( common.Pose(translation=action[self.tquat_key][:3], quaternion=action[self.tquat_key][3:]) ) @@ -432,7 +423,6 @@ def observation(self, observation: dict, info: dict[str, Any]) -> tuple[dict[str def reset( self, *, seed: int | None = None, options: dict[str, Any] | None = None ) -> tuple[dict[str, Any], dict[str, Any]]: - self.prev_action = None self.robot.reset() if self.home_on_reset: exception = True diff --git a/python/rcs/envs/scenes.py b/python/rcs/envs/scenes.py index 6cedeae3..16ca88f9 100644 --- a/python/rcs/envs/scenes.py +++ b/python/rcs/envs/scenes.py @@ -354,7 +354,6 @@ def create_env_from_model(self, cfg: SimEnvCreatorConfig, mjmodel: MjModel) -> g kinematic_model_path, attachment_site, ) - # ik = rcs_robotics_library._core.rl.RoboticsLibraryIK(cfg.robot_cfgs[lead_robot_name].kinematic_model_path) env = self.add_robot_env(prefixed_cfg, robot_name, env, simulation, ik) if prefixed_cfg.gripper_cfgs is not None: diff --git a/python/rcs/utils.py b/python/rcs/utils.py index 506ee18f..18b33edc 100644 --- a/python/rcs/utils.py +++ b/python/rcs/utils.py @@ -18,10 +18,13 @@ def __init__(self, frame_rate: float | None, loop_name: str = "SimpleFrameRate") It allows you to call it in a loop, and it will sleep the necessary time to maintain the desired frame rate. Args: - frame_rate (float): The desired frame rate in frames per second. + frame_rate (float): The desired frame rate in frames per second (Hz). """ self.t: float | None = None self._last_print: float | None = None + assert ( + frame_rate is None or frame_rate > 0 + ), "frame_rate must be set to a positive value representing frames per second (Hz)" self.frame_rate = frame_rate self.loop_name = loop_name