Upgrade lên D405: khi nào nên thay GoPro trong UMI và cách làm
Đây là bài 6 trong series UMI + VLA. Bài này dành cho người đã có working UMI pipeline (bài 2-5) và đang cân nhắc dùng Intel RealSense D405 thay cho GoPro.
Disclosure: Bài viết có thể chứa affiliate/referral links.
TL;DR: D405 thêm RGB-D gần gripper, hữu ích cho contact estimation và object segmentation. Nhưng nó không phải drop-in replacement — bạn phải xây tracking riêng, recorder riêng, và converter riêng. Nếu pipeline GoPro của bạn đang hoạt động, đừng upgrade trừ khi có lý do cụ thể.
Tại sao GoPro và D405 khác nhau hoàn toàn
Trong UMI gốc, GoPro không chỉ là camera. Nó làm 3 việc cùng lúc:
GoPro trong UMI:
1. Camera observation (fisheye 155° wrist view)
2. IMU source (accelerometer + gyroscope cho SLAM)
3. Visual odometry base (feature-rich fisheye cho ORB-SLAM3)
RealSense D405 không có IMU tích hợp (khác với D435i). FOV của D405 hẹp hơn nhiều. Scripts SLAM pipeline trong repo (01_extract_gopro_imu.py, 03_batch_slam.py) được viết đặc biệt cho GoPro format.
| Hạng mục | GoPro (UMI gốc) | RealSense D405 |
|---|---|---|
| FOV | Fisheye ~155° | 87° × 58° (RGB) |
| IMU | Có sẵn | Không có |
| Depth | Không có | Có (short-range, ~0.1–0.5m) |
| UMI SLAM scripts | Hoạt động trực tiếp ✓ | Cần custom adapter ✗ |
| Upstream support | Đầy đủ ✓ | Không có trong upstream ✗ |
Khi nào D405 thực sự đáng làm
Upgrade sang D405 chỉ đáng khi bạn cần ít nhất 1 trong 4 thứ này:
-
Contact estimation — bạn muốn biết chính xác khi nào fingertip chạm object. Depth từ D405 cho point cloud gần gripper (~0.1-0.5m range), tốt hơn nhiều so với RGB-only cho grasping.
-
Object segmentation — task của bạn có nhiều vật thể tương tự, depth giúp segment 3D object bounds chính xác hơn.
-
Partial occlusion — object bị che khuất một phần trong RGB, depth giúp estimate pose từ visible surface.
-
Sensor redundancy — bạn muốn cả RGB (observation) và depth (feature) như 2 nguồn thông tin riêng biệt.
Đừng upgrade nếu:
- Pipeline GoPro đang hoạt động và policy đủ tốt
- Bạn muốn "cải thiện" mà không biết D405 giải quyết vấn đề gì cụ thể
- Bạn chưa có working tracker 6DoF (xem bên dưới)
Thứ bạn PHẢI tự xây khi dùng D405
Đây là phần mà nhiều người bỏ qua: D405 cần custom infrastructure, không phải chỉ đổi camera:
1. External 6DoF tracking
D405 không thể tự SLAM giống GoPro. Bạn cần:
| Option | Độ chính xác | Chi phí | Setup phức tạp |
|---|---|---|---|
| Mocap (OptiTrack/Vicon) | Rất cao (<0.5mm) | Cao ($5k-50k) | Cao |
| SteamVR tracker | Cao (~1-3mm) | Trung bình (~$150/tracker) | Trung bình |
| AprilTag/ArUco rig | Trung bình (~5-10mm) | Thấp | Thấp |
| RGB-D SLAM (custom) | Thấp-trung (drift) | Thấp | Rất cao |
Khuyến nghị: SteamVR tracker hoặc mocap cho lab setup. AprilTag rig cho budget setup nhưng cần cẩn thận với drift ở vùng occlusion.
Nếu chọn RGB-D SLAM tự build (dùng Open3D hoặc ORB-SLAM3 RGB-D mode): đây là research project, không phải engineering task. Bạn phải validate drift với ground truth, xử lý texture-poor surfaces, và handle tracking loss recovery. Không phù hợp cho người mới.
2. Custom recorder
UMI repo không có recorder cho D405. Bạn phải tự viết script sync:
# Skeleton — đây là starting point, KHÔNG phải production code
# Bạn phải thêm: error handling, proper shutdown, latency measurement
import pyrealsense2 as rs
import numpy as np
# Setup D405 streams
pipe = rs.pipeline()
cfg = rs.config()
cfg.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)
cfg.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)
# Start aligned depth
align = rs.align(rs.stream.color)
profile = pipe.start(cfg)
# Intrinsics (lưu một lần, dùng cho calibration)
color_intr = profile.get_stream(rs.stream.color).as_video_stream_profile().get_intrinsics()
print("D405 intrinsics:", color_intr)
# Recording loop
frames_rgb = []
frames_depth = []
timestamps = []
for i in range(90): # 3 giây tại 30fps
frames = pipe.wait_for_frames()
aligned = align.process(frames)
color = aligned.get_color_frame()
depth = aligned.get_depth_frame()
ts = frames.get_timestamp() / 1000.0 # ms → s
frames_rgb.append(np.asanyarray(color.get_data()))
frames_depth.append(np.asanyarray(depth.get_data()))
timestamps.append(ts)
pipe.stop()
print(f"Recorded {len(timestamps)} frames, FPS ≈ {len(timestamps)/(timestamps[-1]-timestamps[0]):.1f}")
Script thực tế phải sync với tracker poses và gripper width trong cùng loop.
3. Custom data converter
Không có script nào trong UMI repo chuyển D405 data sang replay_buffer.zarr.zip hoặc LeRobot format. Bạn phải tự viết converter map:
D405 color frames + D405 depth frames
+ External tracker poses
+ Gripper width measurements
↓ (custom converter)
UMI replay buffer keys:
robot0_eef_pos, robot0_eef_rot_axis_angle
robot0_gripper_width
camera0_rgb, camera0_depth (nếu model support)
Kiến trúc đúng cho UMI-D405
Hardware:
D405 (wrist RGB-D observation)
+ External tracker gắn cứng vào gripper body
+ Gripper width sensor (ArUco tag hoặc encoder)
Software:
Custom sync recorder
→ lưu: color.mp4, depth.zarr, poses.csv, width.csv, timestamps.csv
Calibration:
→ D405 intrinsics (camera_matrix, dist_coeffs)
→ T_gripper_camera (rigid transform từ gripper body → camera)
→ T_tracker_gripper (nếu dùng mocap/VR)
Custom converter:
→ Ghép RGB-D + pose + width → replay buffer hoặc LeRobot format
Calibration quan trọng nhất: T_gripper_camera — transform cứng từ gripper body đến D405 optical frame. Nếu sai, action của policy sẽ lệch so với camera observation. Dùng ChArUco board và hand-eye calibration.
Depth có dùng được cho VLA không?
Câu hỏi thực tế: VLA của bạn có nhận depth input không?
GR00T/GR00T-LeRobot (NVIDIA): Hỗ trợ tùy version và config. Kiểm tra branch bạn đang dùng có modality.json support depth key không trước khi invest vào depth pipeline.
Diffusion Policy UMI baseline: Config mặc định dùng RGB-only. Để thêm depth, cần custom encoder (ví dụ: concat depth vào RGB channel, hoặc dùng separate depth encoder). Không có trong official config sẵn.
Khuyến nghị thực dụng:
- Train RGB-only baseline trước với D405 color stream
- Nếu baseline hoạt động, mới thêm depth như feature bổ sung
- Test: model có cải thiện với depth không? Nếu không → giữ RGB-only
D405 depth thực tế có vấn đề gì?
| Vấn đề | Nguyên nhân | Fix |
|---|---|---|
| Vật thể bóng/trong suốt mất depth | Stereo depth fail | Dùng matte props khi thu data |
| Depth lệch RGB | Stereo baseline không align | Dùng rs.align(), lưu intrinsics/extrinsics |
| Depth quá nhiễu ở edge | Stereo disparity noise | Spatial/temporal filter của librealsense |
| Depth không cover gần <10cm | D405 min range limit | Điều chỉnh camera position |
| Model VLA không improve với depth | Depth features không được dùng | Verify dataloader đọc depth đúng |
Checklist quyết định trước khi upgrade
Trả lời những câu hỏi này trước khi mua D405:
[ ] GoPro pipeline hiện tại có hoạt động tốt không?
→ Nếu không, fix GoPro pipeline trước.
[ ] Bạn có vấn đề cụ thể mà D405 giải quyết không?
→ Nếu không biết, giữ GoPro.
[ ] Bạn đã chọn external 6DoF tracking solution chưa?
→ Nếu chưa, D405 sẽ không có pose data.
[ ] Bạn sẵn sàng viết custom recorder + converter không?
→ Ước tính 2-4 tuần cho người có kinh nghiệm.
[ ] VLA bạn dùng support depth input không?
→ Check trước khi invest vào depth pipeline.
[ ] RGB-only D405 baseline đã test chưa?
→ Nếu chưa, test RGB-only trước rồi quyết định thêm depth.
Nguồn tham khảo
- Intel RealSense D405 product page
- pyrealsense2 documentation
- ORB-SLAM3 repo (RGB-D mode)
- real-stanford/universal_manipulation_interface
- UMI paper (Chi et al., 2024)