Skip to content

Commit b0cfbcd

Browse files
Update docs with camera/configs/more design philosophy
1 parent e279723 commit b0cfbcd

8 files changed

Lines changed: 613 additions & 385 deletions

docs/design_philosophy.md

Lines changed: 107 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,112 @@
11
# Design Philosophy
22

3-
## Reuse existing ROS2 infrastructure/community
3+
We follow a few design strategies in CRISP.
4+
This page describes our choices along with their respective pros and cons.
45

5-
Pros:
6-
- Large community with many users
7-
- TODO
6+
Our most important goal is to find a **meeting point between robotics and machine learning engineers.**
7+
On the one hand, robotics engineers are already familiar with ROS2 and experienced in control and manipulation in general.
8+
On the other hand, machine learning engineers who might not be familiar with these tools prefer to work with python-only environments.
9+
We try to bring the strengths of both worlds in this project.
810

9-
Cons:
10-
- "Framework Jail"
11+
## Reuse Existing ROS2 Infrastructure
1112

12-
## Distributed System
13+
We decided to build CRISP on top of [ROS2](https://docs.ros.org/) for several reasons:
14+
15+
**Pros:**
16+
17+
- **Large community**: Many users and developers already familiar with tools for interacting with ROS2 systems (e.g., [rviz2](https://github.com/ros2/rviz), [rqt](https://docs.ros.org/en/rolling/Concepts/Intermediate/About-RQt.html), [ros2 CLI](https://docs.ros.org/en/rolling/Tutorials/Beginner-CLI-Tools.html)).
18+
- **Existing ecosystem**: Well-tested packages for robot drivers, sensors, and visualization that we can leverage directly. The [ROS Index](https://index.ros.org/) lists thousands of available packages.
19+
- **Simplified setup with pixi + robostack**: We use [pixi](https://pixi.sh/) with [robostack](https://robostack.github.io/) to provide a conda-like development environment.
20+
This removes the traditional friction of ROS2 installation (no more sourcing setup.bash files or managing system dependencies) and makes it accessible to ML engineers accustomed to Python-centric workflows.
21+
22+
**Cons:**
23+
24+
- **"Framework jail"**: ROS2 imposes certain patterns (nodes, topics, executors) that may feel constraining for simple use cases.
25+
Users must work within the ROS2 paradigm even for straightforward scripts.
26+
27+
In all objects, we try to abstract away ROS2 details behind simple Python APIs:
28+
```python
29+
from crisp_py import Robot
30+
31+
robot = Robot(...) # ROS2 node creation is hidden and spinned up internally to receive/send data
32+
robot.wait_until_ready() # Waits for ROS2 topics to be alive
33+
print(robot.end_effector_pose) # Direct access to data without dealing with ROS2 messages
34+
```
35+
36+
## Configuration: YAML Files with Programmatic Freedom
37+
38+
CRISP uses YAML configuration files to define robots, sensors, and control pipelines.
39+
This provides a declarative way to set up common scenarios without writing code.
40+
41+
**Pros:**
42+
43+
- **Quick iteration**: Change parameters without modifying source code.
44+
45+
**Cons:**
46+
47+
- **Less flexibility**: Complex behaviors may be hard to express in YAML rather than code.
48+
49+
However, we also provide full programmatic access.
50+
Users can instantiate objects directly in Python and modify them freely when the YAML approach becomes limiting.
51+
This is particularly useful for:
52+
53+
- Rapid prototyping and debugging
54+
- *Custom components* that don't fit the YAML schema
55+
56+
Here is an example for the YAML config for an environment:
57+
```yaml
58+
gripper_mode: "absolute_continuous"
59+
60+
robot_config:
61+
robot_type: "franka"
62+
time_to_home: 2.0
63+
publish_frequency: 50.0
64+
home_config: [0.0, 0.1, 0.0,-1.94, 0.0, 2.0, 0.8]
65+
66+
gripper_config:
67+
min_value: 0.0
68+
max_value: 0.4
69+
joint_state_topic: /gripper/joint_states
70+
command_topic: /gripper/command
71+
72+
camera_configs:
73+
- camera_name: "primary"
74+
camera_frame: "primary_link"
75+
resolution: [256, 256]
76+
camera_color_image_topic: "third_person_camera/image_raw"
77+
camera_color_info_topic: "third_person_camera/camera_info"
78+
- camera_name: "wrist"
79+
camera_frame: "wrist_link"
80+
resolution: [256, 256]
81+
camera_color_image_topic: "wrist_camera/color/image_rect_raw"
82+
camera_color_info_topic: "wrist_camera/color/camera_info"
83+
84+
sensor_configs:
85+
- sensor_type: "force_torque"
86+
shape: [6,]
87+
name: "ft_sensor"
88+
data_topic: "external_wrench"
89+
```
90+
91+
See the [example config files](https://github.com/utiasDSL/crisp_gym/tree/main/crisp_gym/config) or [here](https://github.com/utiasDSL/crisp_py/tree/main/crisp_py/config), and [how to define your own configs](getting_started_config.md) for more details.
92+
93+
## Data Collection directly in LeRobot Format, no rosbags
94+
95+
CRISP collects data directly in [LeRobot](https://github.com/huggingface/lerobot) format at a single fixed frequency, rather than saving [ROS bags](https://docs.ros.org/en/rolling/Tutorials/Beginner-CLI-Tools/Recording-And-Playing-Back-Data/Recording-And-Playing-Back-Data.html) for post-processing.
96+
97+
The LeRobot format stores episodes as [HuggingFace datasets](https://huggingface.co/docs/datasets/), making it easy to share, version, and load data for training. Each episode contains synchronized observations (images, joint states) and actions at a consistent frequency.
98+
99+
**Pros:**
100+
101+
- **Minimizes the gap between teleoperation and policy deployment**: The data you collect is immediately ready for training without conversion steps. What you record is exactly what your policy will see.
102+
- **Consistent timing**: A single frequency ensures synchronized observations and actions, avoiding timestamp alignment issues common with bag files.
103+
- **Simpler pipeline**: No need to manage bag files, replay them, and transform to training formats.
104+
- **Easy sharing**: Datasets can be pushed directly to [HuggingFace Hub](https://huggingface.co/datasets) for collaboration.
105+
106+
**Cons:**
107+
108+
- **Less data captured**: You only save what's needed at the target frequency, potentially losing high-frequency sensor data that might be useful for debugging or alternative analysis.
109+
- **Less flexibility**: Post-hoc resampling or different observation combinations require re-collection.
110+
111+
The recording is handled by the [RecordingManager](https://github.com/utiasDSL/crisp_gym/tree/main/crisp_gym/record) and here is an example script showing how the recording works [record_with_leader_follower](https://github.com/utiasDSL/crisp_gym/blob/main/crisp_gym/scripts/record_lerobot_format_leader_follower.py)
112+
More details on recording can be found in the [getting started with the gym](getting_started_gym.md) documentation.

docs/examples_camera.md

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# Camera Examples
2+
3+
### Cameras
4+
5+
To add a camera, you will need to run it in a separate container as well.
6+
The cameras that we tested are:
7+
8+
- Any usb camera or webcam using the [ROS2 usb-cam](https://github.com/ros-drivers/usb_cam) package,
9+
- [Real Sense](https://github.com/IntelRealSense/realsense-ros/tree/ros2-master) which gives amazing ROS2 support,
10+
- and [Orbbec](https://github.com/orbbec/OrbbecSDK_ROS2).
11+
12+
Check the [demos](misc/demos.md) to see some examples with cameras
13+
14+
??? example "Example camera usage:"
15+
```py
16+
import cv2
17+
from crisp_py.camera import Camera, CameraConfig
18+
19+
camera_config = CameraConfig(
20+
camera_name="primary",
21+
resolution=(256, 256), # (1)!
22+
camera_color_image_topic="image_raw", # (2)!
23+
camera_color_info_topic="camera_info",
24+
)
25+
26+
camera = Camera(config=camera_config) # (3)!
27+
camera.wait_until_ready() # (4)!
28+
29+
cv2.imshow("Camera Image", camera.current_image) # (5)!
30+
cv2.waitKey(0)
31+
32+
```
33+
34+
1. You can define a custom resolution, independently of the resolution of the published image.
35+
2. Set here the topic of your custom camera name. crisp_py uses compressed images, so make sure that this topic is available as well.
36+
3. You can also pass `namespace="..."` to give the camera a namespace. This is required for a bimanual setup.
37+
4. Make sure that we received an image. This will fail with a timeout if the topic is wrong or the camera is not publishing.
38+
5. This will show you the latest received image!
39+
40+
41+
## Run a camera as a container
42+
43+
To run a camera as a container, use the following command:
44+
```bash
45+
docker compose run
46+
```
47+
48+
## Run a camera with `pixi/robostack`
49+
Here is an example of setting up and running the `usb_cam` ROS2 node using `pixi` and `robostack`.
50+
The USB camera that you use could be your laptop webcam or an external USB camera connected to your computer.
51+
First, create a folder `mkdir pixi_usb_cam, cd pixi_usb_cam` and create a `pixi.toml` file with the following content:
52+
53+
```toml title="pixi.toml"
54+
[workspace]
55+
authors = ["Your Name <your-email@domain.com>"]
56+
channels = ["conda-forge"]
57+
name = "test_usb_cam"
58+
platforms = ["linux-64"]
59+
version = "1.1.0"
60+
61+
[dependencies]
62+
python = "*"
63+
cmake = "*"
64+
poco = "*"
65+
libpsl = "*"
66+
67+
[target.linux.dependencies]
68+
libgl-devel = "*"
69+
70+
[environments]
71+
# humble = { features = ["humble"] }
72+
jazzy = { features = ["jazzy"] }
73+
74+
[feature.jazzy]
75+
channels = ["https://prefix.dev/robostack-jazzy"]
76+
77+
[feature.jazzy.dependencies]
78+
ros-jazzy-desktop = "*"
79+
ros-jazzy-image-transport = "*"
80+
ros-jazzy-image-transport-plugins = "*"
81+
colcon-common-extensions = "*"
82+
ros-jazzy-usb-cam = "*"
83+
84+
[feature.jazzy.tasks]
85+
usb_cam = "ros2 run usb_cam usb_cam_node_exe"
86+
```
87+
88+
Then in a terminal to start the `usb_cam` node run:
89+
```bash
90+
pixi run usb_cam
91+
```
92+
93+
Now camera images are being published. In a different terminal, you can run:
94+
```bash
95+
pixi shell -e jazzy
96+
ros2 topic list
97+
# rqt to also visualize the image
98+
```
99+
100+
## Access images from `crisp_py`
101+
102+
Using the Camera class from `crisp_py`:
103+
```python
104+
"""Simple example showing how to use the Camera class to capture and display an image."""
105+
106+
import cv2
107+
from crisp_py.camera import Camera, CameraConfig
108+
109+
camera_config = CameraConfig(
110+
camera_name="primary",
111+
camera_frame="primary_link",
112+
resolution=(256, 256),
113+
camera_color_image_topic="/camera_namespace/wrist_camera/color/image_rect_raw",
114+
camera_color_info_topic="/camera_namespace/wrist_camera/color/camera_info",
115+
)
116+
117+
camera = Camera(config=camera_config, namespace="")
118+
camera.wait_until_ready()
119+
120+
cv2.imshow("Camera Image", camera.current_image)
121+
cv2.waitKey(0)
122+
```
123+
124+
Or by defining a camera in a YAML configuration file:
125+
```yaml
126+
camera_name: "primary"
127+
camera_frame: "primary_link"
128+
resolution: [256, 256]
129+
camera_color_image_topic: "/camera_namespace/wrist_camera/color/image_rect_raw"
130+
camera_color_info_topic: "/camera_namespace/wrist_camera/color/camera_info"
131+
```
132+
133+
Then load the configuration and use the Camera class:
134+
135+
```python
136+
"""Example showing how to load camera configuration from a YAML file."""
137+
import cv2
138+
from crisp_py.camera import make_camera
139+
140+
camera = make_camera("your_config_file_name")
141+
camera.wait_until_ready()
142+
143+
cv2.imshow("Camera Image", camera.current_image)
144+
cv2.waitKey(0)
145+
```
146+
147+

docs/examples_sensor.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
### Sensors
2+
3+
You can add further sensors (Force Torque Sensor, Tactile Sensor...) by adding a custom `Sensor` that subscribes to a topic.
4+
Check the examples for more information.

0 commit comments

Comments
 (0)