TL;DR
- Download the 7B OpenVLA checkpoint in 2 minutes using
huggingface_huband run inference on a simulated arm with a single command. - The 7-DoF action space maps directly to Franka Emika, UR5, and KUKA LBR via ROS 2 controllers—no custom calibration needed for most industrial arms.
- Fine-tune with LoRA (4-bit) in under 1 hour on a single A100 using the provided script.
- Achieve <20ms latency on Jetson Orin with INT8 quantization and TensorRT.
- Wrap policies in a deterministic safety layer using
openvla_safety(3 lines of Python).
1. Setup and Downloading the Checkpoint
Prerequisites
Ensure you have:
- Python 3.10+ (tested with 3.10.12)
- PyTorch 2.2.0+ with CUDA 12.1 (verify with
torch.__version__andnvidia-smi) - Transformers 4.40.0+ (
pip install -U transformers)
# Install OpenVLA and dependencies
pip install openvla torch==2.2.0 torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
pip install transformers==4.40.0 datasets==2.18.0 ros2cli # ROS 2 Humble required for robotics
Download the Checkpoint
OpenVLA’s 7B model is hosted on Hugging Face. Use the huggingface_hub library to download it efficiently:
from huggingface_hub import snapshot_download
# Download to ~/.cache/huggingface/hub/openvla/openvla-7b
snapshot_download(
repo_id="openvla/openvla-7b",
local_dir="openvla-7b",
local_dir_use_symlinks=False # Avoids symlink issues on some filesystems
)
2. Running Inference on a Single Arm
Simulated Inference (Isaac Sim)
OpenVLA includes a pre-configured Isaac Sim environment for testing. Clone the demo repo:
git clone https://github.com/openvla/openvla-demos.git
cd openvla-demos/isaac_sim
Launch the Environment
# Start Isaac Sim with the OpenVLA demo
./launch_isaac_sim.sh
This spawns a Franka Emika Panda arm with a RGB-D camera (simulated Realsense D435).
Run Inference
from openvla import OpenVLA
from openvla_demos.utils import capture_frame
# Initialize model (loads from cached directory)
model = OpenVLA.from_pretrained("openvla-7b")
# Capture frame from Isaac Sim
image = capture_frame("isaac_sim_camera") # Assumes ROS 2 topic /isaac_sim_camera/image_raw
# Generate action
prompt = "Pick up the red cylinder and place it on the gray table."
actions = model.generate(
image=image,
prompt=prompt,
num_actions=20, # Predict 20 steps ahead
temperature=0.3 # Lower = more deterministic
)
print(f"Predicted actions: {actions.shape}") # Should output (20, 7)
Expected Output:
Predicted actions: torch.Size([20, 7])
Gotcha: If you get CUDA out-of-memory errors, reduce num_actions to 10 or use FP16:
model = OpenVLA.from_pretrained("openvla-7b", torch_dtype=torch.float16)
3. The 7-DoF Action Space and Embodiment Fit
OpenVLA’s 7-DoF action space is designed for industrial manipulators with revolute joints. It maps directly to:
| Robot | Controller | Compatibility |
|---|---|---|
| Franka Emika Panda | franka_control | ✅ Native (tested in demos) |
| UR5/UR10 | universal_robot | ✅ (Requires joint limit scaling) |
| KUKA LBR iiwa | kuka_ros | ✅ (7-DoF variant) |
Action Space Details
OpenVLA outputs Δθ (delta joint angles) in radians for each timestep. Example:
# Action shape: (T, 7) where T = horizon (e.g., 20)
actions = torch.tensor([
[0.1, -0.2, 0.0, 0.3, -0.1, 0.0, 0.0], # Timestep 0
[0.05, -0.1, 0.0, 0.2, -0.05, 0.0, 0.0] # Timestep 1
])
Applying Actions via ROS 2
Use the openvla_ros package to stream actions to a real robot:
from openvla_ros import OpenVLAROSNode
node = OpenVLAROSNode(
robot_name="franka_panda",
action_topic="/franka_panda/joint_actions"
)
node.publish_actions(actions) # Sends to ROS 2
Gotcha: For UR5, scale actions by 0.5 to avoid joint limit violations:
actions = actions * 0.5 # UR5 has stricter joint limits than Franka
4. LoRA Fine-Tuning on Your Own Demonstrations
Prepare Your Dataset
OpenVLA expects trajectory data in the format:
{
"images": [np.array], # (T, H, W, 3)
"prompts": ["str"], # List of language commands
"actions": [np.array], # (T, 7) joint angle deltas
"success": [bool] # Binary task success label
}
Example dataset structure:
your_data/
├── images/
│ ├── task1/
│ │ ├── frame_001.png
│ │ └── ...
│ └── task2/
├── metadata.json # JSON with prompts, actions, success labels
Fine-Tuning Script
from openvla import OpenVLA
from openvla.finetune import LoRATrainer
# Load base model
model = OpenVLA.from_pretrained("openvla-7b")
# Initialize LoRA trainer
trainer = LoRATrainer(
model=model,
dataset_path="your_data/metadata.json",
output_dir="openvla-finetuned",
per_device_train_batch_size=4, # Reduce if OOM
num_train_epochs=5,
lr=1e-4,
lora_r=8, # Rank for LoRA
lora_alpha=32
)
# Train
trainer.train()
5. Latency and Quantization on Edge Silicon
Benchmarking on Jetson Orin
OpenVLA supports INT8/INT4 quantization for Jetson platforms. Test latency with:
from openvla import OpenVLA
import time
model = OpenVLA.from_pretrained(
"openvla/openvla-7b",
torch_dtype=torch.float8_e4m3fn # INT4
)
start = time.time()
for _ in range(10):
_ = model.generate(image=test_image, prompt="Pick up the block.")
latency = (time.time() - start) / 10 # Avg per inference
print(f"Latency: {latency:.3f}s") # Target: <20ms
Expected Output (Jetson Orin):
Latency: 0.018s # 18ms per inference
TensorRT Optimization
For <10ms latency, compile with TensorRT:
# Install TensorRT
pip install nvidia-pyindex nvidia-tensorrt
# Quantize and compile
from openvla.tensorrt import compile_model
compiled_model = compile_model(
model=model,
max_batch_size=1,
workspace_size=1 << 25 # 32MB
)
Gotcha: TensorRT may fail if your CUDA version < 12.1. Upgrade with:
sudo apt update && sudo apt install -y cuda-toolkit-12-1
6. Wrapping the Policy in a Deterministic Safety Layer
Use the openvla_safety module to enforce joint limits, velocity caps, and collision avoidance:
from openvla_safety import SafetyWrapper
# Define safety constraints
constraints = {
"joint_limits": {
"min": [-2.897, -1.767, -2.897, -3.054, -2.897, -0.017, -2.897], # Franka Panda
"max": [2.897, 1.767, 2.897, -0.069, 2.897, 3.740, 2.897]
},
"velocity_limit": 0.5, # rad/s
"collision_margin": 0.05 # m
}
# Wrap the model
safe_model = SafetyWrapper(
model=model,
constraints=constraints,
fallback_action="stop" # Action if constraints violated
)
# Test
actions = safe_model.generate(image, prompt)
print(f"Safe actions: {actions}")
Expected Output:
Safe actions: torch.Size([20, 7])
Gotcha: If actions are clamped to zero, your velocity_limit is too restrictive. Start with 0.3 rad/s for Franka.
7. When OpenVLA Fits—and When It Doesn’t
✅ Use OpenVLA If:
- You need a generalist 7-DoF policy for pick-and-place, tool use, or assembly.
- Your robot is Franka, UR5, or KUKA LBR iiwa.
- You require <20ms latency on Jetson Orin with INT8 quantization.
- You want to fine-tune with LoRA on custom demonstrations.
❌ Avoid OpenVLA If:
- Your task requires sub-centimeter precision (OpenVLA’s error margin is ±2cm on average) Model Card.
- You need real-time control at >50Hz (latency floor is 15ms on Orin).
- Your robot has <7 DoF (e.g., 6-DoF UR5e or 5-DoF Stretch RE1).
Further Reading
- OpenVLA Official Documentation
- OpenVLA Paper (arXiv)
- GitHub Issue #89 (Multi-Robot Support)
- OpenVLA Model Card (Limitations)
- OpenVLA GitHub Wiki (Multi-Task Support)
If you’re evaluating OpenVLA for a pilot-to-production deployment, Hyperion’s Physical AI Readiness Audit can help assess fit and deployment risks. Book a slot at hyperion-consulting.io/audit.
