内容
# VELMA
视觉启用的大型语言模型操作臂。VELMA 是一个桌面级 SO-101 臂,在 MuJoCo 中运行,通过视觉完成完整的拾取和放置任务。固定侧面摄像头可以将物体定位到约一厘米范围内,腕部摄像头围绕该物体旋转五次,三角测量到约 1 毫米精度。机械臂根据这些坐标抓取和放置物体,可以通过 MCP 由大型语言模型驱动,也可以通过终端控制面板手动驱动。
## 目录
```
so101-Models/
main.py 入口点:加载 config.yaml,启动 MCP 服务器(或硬件后端)
config.yaml 运行时配置(后端、查看器开启/关闭、端口、LLM 提供商)
requirements.txt 机器人虚拟环境依赖
server/ MCP 服务器 — 15 种工具(见下文)
perception/ 查找物体(粗略)+ 腕部三角测量 + 边车客户端
requirements.txt 感知边车虚拟环境依赖(torch CPU + ultralytics + transformers)
percept_venv/ torch/SAM/Depth-Anything 边车解释器(CPU)
wrist_refine.py 感知/wrist_triangulate.py 使用的腕部摄像头悬停/状态帮助函数
robot/, kinematics/, models/ 后端、逆运动学、MuJoCo 场景
control_panel.py 终端 UI,通过 MCP 服务器手动驱动机械臂
agent.py 连接任意 LLM(Ollama/OpenAI 兼容)到机械臂的薄 MCP 客户端
SKILL.md 系统提示指南,用于驱动机械臂的 LLM(由 agent.py 提供)
.mcp.json CLI 工具的 MCP 服务器入口(Claude Code、Codex CLI 等)
venv/ 机器人解释器(MuJoCo,无 torch)
```
## 安装
两个虚拟环境是唯一重要的部分。从固定的依赖项中重新创建它们(在 `so101-Models/` 目录内运行):
```bash
# 机器人虚拟环境(渲染 MuJoCo,运行 MCP 服务器 — 无 torch)
python3 -m venv venv && ./venv/bin/pip install -r requirements.txt
# 感知边车虚拟环境(torch CPU + ultralytics + transformers;需要 Python 3.11/3.12)
python3.11 -m venv percept_venv && ./percept_venv/bin/pip install -r perception/requirements.txt
```
然后,可选地,运行设置向导以编写 `config.yaml`(后端、LLM 连接、服务器端口)— 它是一个配置助手,不是安装的一部分:
```bash
./venv/bin/python setup.py
```
一个具有合理默认值的 `config.yaml` 已经包含在这个仓库中,因此只有在需要更改某些内容时才需要运行 `setup.py`(例如,切换到硬件后端或添加 API 密钥)。
## 运行服务器(无界面 — 感知所需)
感知需要离屏渲染,因此在 **没有** 查看器的情况下运行服务器:
```bash
SO101_VIEWER=0 MUJOCO_GL=egl ./venv/bin/python main.py
```
`SO101_SCENE=models/so101/<scene>.xml` 覆盖场景(默认 `pick_and_place_scene.xml`)。设置 `SO101_VIEWER=1` 以观察机械臂 — 但此时感知被禁用(离屏和屏幕渲染器不能在此框中共存)。
## 手动驱动
在第二个终端中:
```bash
./venv/bin/python control_panel.py
```
它连接到正在运行的服务器,列出 15 种工具及其实时模式,并允许您调用任意工具,输入有引导。**任何 MCP 客户端必须设置长读取超时**(面板使用 `read_timeout_seconds=300`)— `grasp`/`place`/`stop_recording` 需要几秒钟,超时中间的客户端会将服务器关闭。
## 连接大型语言模型
在运行无界面服务器(上面)的情况下,选择以下两个路径之一:
**A. 支持 MCP 的 CLI 工具**(Claude Code、Codex CLI、Gemini CLI、Cursor 等):此仓库的 `.mcp.json` 已经指向 `http://localhost:3001/mcp` — 只需在 `so101-Models/` 目录内运行 CLI 工具(例如 `claude`)。如果更改了 `config.yaml` 的 `server.port`,请重新运行 `./venv/bin/python setup.py`(服务器设置)以重新生成 `.mcp.json` 以匹配。
**B. 任意 Ollama / OpenAI 兼容模型**,通过捆绑的薄代理:
```bash
./venv/bin/python agent.py --model gemma3:4b --task "pick up the red cube and place it in the container"
```
`agent.py` 将模型 `SKILL.md` 作为系统提示加上服务器的实时工具模式(从不硬编码,因此不会偏离服务器实际公开的内容),并在工具调用之间进行中继 — 它不会注入过程或对模型进行第二猜测。有关端点/模型标志的详细信息,请参见 `agent.py --help`(`LLM_BASE_URL`、`LLM_API_KEY`、`--mode auto|native|text`)。
## 拾取和放置路径(LLM 调用)
物体的位置是 **测量** 的,而不是给定的:
1. `find_object("the red cube")` — 粗略的 `(x, y)` 来自固定侧面摄像头(~cm,足以瞄准)。
2. `triangulate("the red cube", x, y)` — 精炼到一个准备抓取的 3D 点,借助腕部摄像头(~1 mm)。如果 `confidence < 0.6`,视图不一致 — 重新运行 `find_object` 或拒绝。
3. `grasp(x, y, z, trust_coords=true, grip_width_mm=width_mm+10)` — 温和的,从不敲击顶部的抓取。
4. `find_object("the container")` — 容器的位置也被测量,而不是假设的。
5. `place(container_x, container_y, 0.05)` — 将物体放下;检查 `cube_in_container`。
## 15 种工具
感知:`find_object`、`triangulate`。状态:`get_robot_state`、`capture_cameras`、`get_initial_instructions`。操作:`grasp`、`place`。运动:`move_to_position`、`set_joint_angles`。夹持器:`set_gripper`、`open_gripper`、`close_gripper`。控制:`reset_scene`、`start_recording`、`stop_recording`。
## 诚实说明
感知路径(`find_object` → `triangulate`)仅为测量 — 其中没有任何内容读取真实值。`get_robot_state` 和每个工具的返回状态故意 **省略** 立方体和容器的真实位置,因此 LLM 不能通过从状态中读取答案来简化感知(需要真实值进行评分的基准测试工具可以选择通过设置 `SO101_EXPOSE_TRUTH=1` 启动服务器来选择加入 — 在连接 LLM 时绝不能设置此选项)。
在 `grasp` 本身中保留了两个内部读取真实值(物体形状用于从不敲击拒绝和位置漂移中止保护),并且待删除。完整的审计、确切位置和严重程度:[`research/HONESTY_REVIEW.md`](../research/HONESTY_REVIEW.md)。