Skip to content

Commit daef12b

Browse files
authored
Merge pull request #309 from RobotControlStack/juelg/hardware-fixes
fix: franka hardware testing
2 parents 207899f + 432b7a1 commit daef12b

31 files changed

Lines changed: 1730 additions & 284 deletions

.dockerignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,10 @@
11
**/build/
2+
real*
3+
test*
4+
sim*
5+
transfer_cube
6+
single_pick*
7+
ball_maze
8+
candy
9+
*.parquet
10+
*venv*

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ PYSRC = python
22
CPPSRC = src
33
COMPILE_MODE = Release
44
LINT_EXCLUDE_RUFF = --exclude examples/teleop/SimPublisher
5-
LINT_EXCLUDE_MYPY = 'build|examples/teleop/SimPublisher'
5+
LINT_EXCLUDE_MYPY = 'build|examples/teleop/SimPublisher|examples/inference/franka.py'
66

77
# CPP
88
cppcheckformat:

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Traditional robotics middleware (like ROS/ROS2) and complex motion planning pipe
2626
* **Zero ROS Overhead:** No complex message-passing, middleware, or network configuration required. Run natively in Python with a lightweight C++ backend.
2727
* **Frictionless Sim-to-Real:** Train your Reinforcement Learning or VLA policies in our MuJoCo Gymnasium wrapper, and deploy the *exact same code* directly to physical hardware.
2828
* **Synchronous Execution:** Optimized specifically for the highly parallelized, synchronous data collection required by modern ML workflows.
29-
* **Ready-to-Use Apps:** Ships with pre-built applications for data collection via teleoperation and remote model inference via [vlagents](https://github.com/RobotControlStack/vlagents).
29+
* **Ready-to-Use Apps:** Ships with pre-built applications for data collection via teleoperation and remote model inference via [vlagents](https://github.com/RobotControlStack/vlagents). See [examples/teleop/README.md](examples/teleop/README.md) and [examples/inference/README.md](examples/inference/README.md).
3030

3131
## 🧩 Wrapper-Based Architecture
3232

@@ -132,7 +132,7 @@ pip install rcs-core
132132

133133
### From Source
134134

135-
Make sure that common build tools (i.e., `build-essential`) and a C++ compiler like `gcc` or `clang` are installed on your system/conda/docker.
135+
Make sure that common build tools (i.e., `build-essential`), python headers and a C++ compiler like `gcc` or `clang` are installed on your system/conda/docker.
136136

137137
*RCS works best in Python 3.11, and all extensions have been tested to work in 3.11.*
138138

@@ -196,6 +196,7 @@ For full documentation, including advanced installation, modular usage, and API
196196
Useful quick-reference pages:
197197
- **[RCS Conventions](https://robotcontrolstack.org/user_guide/conventions)** for quaternion order, frames, Euler angles, and gripper semantics
198198
- **[Sim Scene Configuration](https://robotcontrolstack.org/user_guide/scene_configuration)** for `SimEnvCreatorConfig`, scene frames, and example setup patterns
199+
- **[Apps](https://robotcontrolstack.org/apps/index)** for the teleoperation and inference example entry points
199200
- **[libfranka Version Info](https://robotcontrolstack.org/extensions/libfranka_versions)** for the currently pinned `rcs_fr3` and `rcs_panda` `libfranka` versions and local-install guidance
200201

201202
## 🤝 Contribution

docker/Dockerfile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
2020
libglfw3-dev \
2121
libpoco-dev \
2222
ninja-build \
23+
liburdfdom-dev \
2324
&& rm -rf /var/lib/apt/lists/*
2425

2526
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
@@ -53,7 +54,11 @@ RUN chmod +x /usr/local/bin/link-editable-source \
5354
&& uv pip install --no-build-isolation /opt/rcs-src/extensions/rcs_fr3 \
5455
&& uv pip install /opt/rcs-src/extensions/rcs_realsense \
5556
&& uv pip install /opt/rcs-src/extensions/rcs_robotiq2f85 \
56-
&& uv pip install /opt/rcs-src/extensions/rcs_zed
57+
&& uv pip install /opt/rcs-src/extensions/rcs_zed \
58+
&& uv pip install /opt/rcs-src/examples/teleop/SimPublisher \
59+
&& uv pip install /opt/rcs-src/2f85-python-driver \
60+
&& uv pip install /opt/rcs-src/vlagents \
61+
&& uv pip install /opt/rcs-src/rcs_duobench
5762

5863
WORKDIR /workspace/robot-control-stack
5964

docker/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Notes:
2323
- `~/zed_models` is mounted into `/usr/local/zed/resources` to match the direct `docker run` setup.
2424
- `/dev/dri` is masked inside the container so host Mesa/AMD render nodes do not override the NVIDIA runtime devices.
2525
- NVIDIA PRIME/GLX environment variables are exported to bias OpenGL/EGL selection toward the NVIDIA stack when using X11 forwarding.
26-
- Python source changes are picked up from the mounted repo, including `extensions/rcs_zed`.
26+
- The simulator still bootstraps EGL for offscreen MuJoCo camera rendering; set `RCS_MUJOCO_DISABLE_EGL=1` only if you intentionally want to disable that path.
27+
- Python source changes are picked up from the mounted repo.
2728
- If you change C++ code in `rcs` or `rcs_fr3`, rebuild the image.
2829
- For non-GPU hosts, comment out the GPU-related lines in `docker/compose/dev.yml`.

docker/link-editable-source.sh

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,21 @@ fi
1010

1111
SITE_PACKAGES="$(python -c 'import sysconfig; print(sysconfig.get_paths()["purelib"])')"
1212

13-
link_mixed_package() {
13+
link_compiled_package() {
1414
src_dir="$1"
1515
dst_dir="$2"
16-
keep_dir_name="${3:-}"
1716

1817
if [ ! -d "$src_dir" ] || [ ! -d "$dst_dir" ]; then
1918
return
2019
fi
2120

22-
# Replace only the Python sources from the mounted repo and keep compiled
23-
# artifacts that were installed into site-packages during image build.
24-
for path in "$src_dir"/* "$src_dir"/.[!.]* "$src_dir"/..?*; do
25-
[ -e "$path" ] || continue
26-
name="$(basename "$path")"
27-
if [ -n "$keep_dir_name" ] && [ "$name" = "$keep_dir_name" ]; then
28-
continue
29-
fi
30-
rm -rf "$dst_dir/$name"
31-
cp -as "$path" "$dst_dir/$name"
32-
done
21+
tmp_keep="$(mktemp -d)"
22+
find "$dst_dir" -maxdepth 1 \( -name '_core*.so' -o -name 'lib*.so*' \) -exec mv {} "$tmp_keep/" \;
23+
rm -rf "$dst_dir"
24+
mkdir -p "$dst_dir"
25+
cp -as "$src_dir/." "$dst_dir/"
26+
find "$tmp_keep" -maxdepth 1 -type f -exec mv {} "$dst_dir/" \;
27+
rmdir "$tmp_keep"
3328
}
3429

3530
link_pure_python_package() {
@@ -44,8 +39,9 @@ link_pure_python_package() {
4439
ln -s "$src_dir" "$dst_dir"
4540
}
4641

47-
link_mixed_package "$REPO_ROOT/python/rcs" "$SITE_PACKAGES/rcs" "_core"
48-
link_mixed_package "$REPO_ROOT/extensions/rcs_fr3/src/rcs_fr3" "$SITE_PACKAGES/rcs_fr3" "_core"
42+
link_compiled_package "$REPO_ROOT/python/rcs" "$SITE_PACKAGES/rcs"
43+
link_compiled_package "$REPO_ROOT/extensions/rcs_fr3/src/rcs_fr3" "$SITE_PACKAGES/rcs_fr3"
4944
link_pure_python_package "$REPO_ROOT/extensions/rcs_realsense/src/rcs_realsense" "$SITE_PACKAGES/rcs_realsense"
5045
link_pure_python_package "$REPO_ROOT/extensions/rcs_robotiq2f85/src/rcs_robotiq2f85" "$SITE_PACKAGES/rcs_robotiq2f85"
5146
link_pure_python_package "$REPO_ROOT/extensions/rcs_zed/src/rcs_zed" "$SITE_PACKAGES/rcs_zed"
47+
link_pure_python_package "$REPO_ROOT/vlagents" "$SITE_PACKAGES/vlagents"

docs/apps/index.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Apps
2+
3+
RCS ships with ready-to-use applications for common operator workflows such as robot teleoperation and remote policy inference.
4+
5+
## Teleoperation
6+
7+
Use the Franka teleoperation app when you want to collect demonstrations or directly control a robot from an operator interface.
8+
9+
- Example guide: [examples/teleop/README.md](../../examples/teleop/README.md)
10+
- Main script: [examples/teleop/franka.py](../../examples/teleop/franka.py)
11+
12+
The current example focuses on Franka teleoperation with Meta Quest 3 and GELLO-based setups.
13+
14+
## Inference
15+
16+
Use the Franka inference app when you want to run a remote policy server, for example through `vlagents`, against an RCS hardware environment.
17+
18+
- Example guide: [examples/inference/README.md](../../examples/inference/README.md)
19+
- Main script: [examples/inference/franka.py](../../examples/inference/franka.py)
20+
- Example config: [examples/inference/franka.json](../../examples/inference/franka.json)
21+
22+
The inference example expects a compatible policy server to already be running and explains the runtime keyboard commands and config fields in its README.

docs/index.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ getting_started/index
3131
user_guide/index
3232
```
3333

34+
```{toctree}
35+
:maxdepth: 2
36+
:caption: Apps
37+
38+
apps/index
39+
```
40+
3441
```{toctree}
3542
:maxdepth: 2
3643
:caption: API

examples/inference/README.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Franka Inference Example
2+
3+
This folder contains a hardware-oriented inference example for running a `vlagents` policy server against the Franka duo setup in [franka.py](franka.py) with configuration from [franka.json](franka.json).
4+
5+
## Policy Server
6+
7+
Before starting `franka.py`, make sure a `vlagents` policy server is already running. The example connects to a remote agent with:
8+
9+
- `vlagents_host`
10+
- `vlagents_port`
11+
- `vlagents_model`
12+
13+
The policy server setup and supported launch commands are documented in:
14+
15+
- [RobotControlStack/vlagents](https://github.com/RobotControlStack/vlagents)
16+
- [vlagents/README.md](../../vlagents/README.md)
17+
18+
Typical server startup looks like:
19+
20+
```shell
21+
python -m vlagents start-server lerobot --port 20000 --host 0.0.0.0 --kwargs '{"policy_name": "act", "checkpoint_path": "<path to pretrained_model>", "n_action_steps": 1}'
22+
```
23+
24+
For other policies such as `pi05` or `xvla`, use the matching startup command from the `vlagents` README and make sure the values in `franka.json` point at that server.
25+
26+
## Config File
27+
28+
[franka.json](franka.json) is an example config, not a universal default. You should review and usually change these values before running inference:
29+
30+
- `vlagents_host`: Hostname or IP address where the policy server is running.
31+
- `vlagents_port`: Port exposed by the policy server.
32+
- `vlagents_model`: Agent id passed to `vlagents`, for example `lerobot`.
33+
- `instruction`: Natural-language task instruction sent to the policy on reset.
34+
- `robot_keys`: Robot ordering used to pack observations and unpack actions. The script assumes one 8-value action block per robot in this order: `7` joint values plus `1` gripper value.
35+
- `jpeg_encoding`: Whether observations are sent to the policy server using JPEG-compressed images.
36+
- `on_same_machine`: Set this according to whether the policy server runs on the same machine as the control process.
37+
- `fps`: Control loop target frequency used by the local rate limiter.
38+
- `record_path`: Output directory used when recording episodes.
39+
- `n_action_steps`: If `null`, the script requests one action per control step. If set to an integer greater than `0`, the script buffers that many actions from each policy response chunk.
40+
- `max_rel_mov_joints`: Maximum allowed relative joint movement per step when running in joint control mode.
41+
- `max_rel_mov_cart`: Maximum allowed relative Cartesian translation and rotation per step when running in Cartesian modes.
42+
43+
The current `franka.py` example also contains hardware-specific constants for robot IPs, camera serials, gripper serials, and frame mappings. Those live in the script itself, so update [franka.py](franka.py) if your hardware setup differs.
44+
45+
## Runtime Keys
46+
47+
When [franka.py](franka.py) is running, it waits for keyboard input on stdin. The active commands are:
48+
49+
- `e`: Start an episode without recording.
50+
- `r`: Start an episode and begin recording to `record_path`.
51+
- `s`: Mark the current episode as successful and reset the environment.
52+
- `q`: Stop the current episode and reset the environment.
53+
- `o`: Reload `franka.json`, reconnect the `vlagents` client, reset the environment, and clear any buffered actions.
54+
- `x`: Exit the program.
55+
56+
## Observation And Action Mapping
57+
58+
The script translates RCS observations to the `vlagents` `Obs` format as follows:
59+
60+
- Every camera frame in `obs["frames"]` is converted to RGB and resized to `224x224`.
61+
- State is built by iterating through `robot_keys` in order and concatenating each robot's `joints` and `gripper` values.
62+
63+
Action decoding is also order-dependent:
64+
65+
- For each robot in `robot_keys`, the script reads `8` values from the policy action vector.
66+
- Values `0:7` become the robot joint command.
67+
- Value `7:8` becomes the robot gripper command.
68+
69+
That means `robot_keys` must match the policy's expected robot ordering exactly.
70+
71+
## Running
72+
73+
After the policy server is up and `franka.json` is configured, run:
74+
75+
```shell
76+
python examples/inference/franka.py
77+
```
78+
79+
If the policy server is unreachable, the script will keep retrying connection until it becomes available or you exit.

examples/inference/franka.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"vlagents_host": "localhost",
3+
"vlagents_port": 20000,
4+
"vlagents_model": "lerobot",
5+
"instruction": "use the left arm to place the white cube in the white bowl; use the right arm to place the black cube in the black bowl",
6+
"robot_keys": [
7+
"left",
8+
"right"
9+
],
10+
"jpeg_encoding": true,
11+
"on_same_machine": false,
12+
"fps": 30,
13+
"record_path": "inference_recordings_bin_sort_duobench_xvla_bin_sort_real_2026-05-20_23-25-47_040000",
14+
"n_action_steps": 30,
15+
"max_rel_mov_joints": 0.08726646259971647,
16+
"max_rel_mov_cart": [
17+
0.5,
18+
1.5707963267948966
19+
]
20+
}

0 commit comments

Comments
 (0)