week1
一、框架核心工作
本周完成了桌面端机器人 Demo 第一版的整体技术框架设计与基础代码搭建。目标是构建一个可扩展、可替换、便于多人协作开发的 Agent + VLA + LLM 解耦框架,使上层 Agent 可以根据用户自然语言输入,选择调用具身智能模型或通用大语言模型。
框架目录位于:
/home/czw1/ChenLong-Robot-Internship/agent_vla
整体架构设计如下:
用户输入
|
v
Agent API
|
+-- 机器人任务 -> VLA Service -> SmolVLA / LeRobot / 后续 Ascend NPU
|
+-- 通用问答 -> LLM Service -> OpenAI / Ollama / 本地大模型
本周实现了三个核心服务:
-
Agent API- 作为系统统一入口,接收用户输入。
- 根据用户输入判断是机器人任务还是通用问答。
- 将机器人任务映射为固定的
skill_id,例如ball_pick_v1。 - 根据路由结果调用 VLA Service 或 LLM Service。
-
VLA Service- 负责管理机器人技能。
- 提供
GET /v1/skills和POST /v1/execute接口。 - 当前实现了
mockprovider 和lerobot_rolloutprovider。 - 后续可以新增
ascend_vlaprovider,用于 Orange Pi AI Pro / Ascend NPU 推理。
-
LLM Service- 负责通用语言模型能力。
- 提供
POST /v1/generate接口。 - 当前实现了
mockprovider。 - 后续可以扩展 OpenAI、Ollama、Qwen、本地大模型等 provider。
当前核心代码结构如下:
agent_vla/
configs/
app.yaml # 全局配置:路由规则、技能、模型路径、服务地址
src/
common/ # 共享 schema、配置读取、HTTP 工具
agent_api/ # Agent 入口、意图路由、工具调用
vla_service/ # VLA 服务和 provider
llm_service/ # LLM 服务和 provider
scripts/
run_agent_api.sh
run_vla_service.sh
run_llm_service.sh
run_mock_stack_test.sh
smoke_test.sh
docs/
architecture.md
contracts.md
development_plan.md
框架中的核心解耦点是 src/common/schemas.py。Agent、VLA、LLM 三部分统一使用这里定义的请求和响应结构,包括:
UserRequest
AgentResponse
ToolCall
VLAExecuteRequest
VLAExecuteResponse
LLMGenerateRequest
LLMGenerateResponse
通过这种方式,Agent 不需要关心 VLA 底层是 LeRobot、PyTorch、ONNX、CANN 还是 Orange Pi NPU;也不需要关心 LLM 底层是 OpenAI、Ollama 还是本地模型。只要接口协议不变,底层 provider 可以独立替换。
本周还完成了 mock 栈测试:
cd /home/czw1/ChenLong-Robot-Internship/agent_vla
bash scripts/run_mock_stack_test.sh
测试结果:
- 输入“帮我把球捡起来”可以正确路由到
robot.pick_ball,并调用 VLA Service。 - 输入
pick ball可以正确路由到robot.pick_ball。 - 输入“北京有什么旅游景点”可以正确路由到
llm.general_qa,并调用 LLM Service。
整体来看,第一版框架已经具备以下能力:
- Agent、VLA、LLM 三方解耦。
- 支持通过配置注册机器人技能。
- 支持通过 provider 替换 VLA 或 LLM 后端。
- 支持 dry-run,便于在不控制真实机械臂的情况下联调接口。
- 为后续 Orange Pi AI Pro / Ascend NPU 部署预留了扩展位置。
二、模型核心工作
本周完成了 LeRobot / SmolVLA 相关环境调试、硬件链路验证、数据采集参数设计和训练部署方案设计。
当前硬件与环境约定如下:
系统环境:WSL2 Ubuntu 24.04
Python 环境:conda env lerobot
机器人框架:LeRobot
具身模型:SmolVLA
从臂:SO101 follower,/dev/ttyACM0
主臂:SO101 leader,/dev/ttyACM1
摄像头:USB Camera,/dev/video0
已完成的硬件链路验证包括:
- SO101 follower 从臂可以正常连接。
- SO101 leader 主臂可以正常连接。
- 主从臂 teleoperation 可以跑通。
- USB 摄像头可以被 OpenCV 识别。
- SmolVLA 相关依赖和 GPU 训练环境可用。
摄像头调试过程中确认了一个关键参数:摄像头实际回报 FPS 为 30。如果在 LeRobot 配置中写成 fps=10,会出现校验错误:
OpenCVCamera(0) failed to set fps=10 (actual_fps=30.0)
因此后续摄像头配置统一固定为:
--robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 160, height: 120, fps: 30, fourcc: MJPG} }"
这里选择 160x120 是为了保证 WSL2 + USB 摄像头 + SmolVLA 推理链路足够稳定。摄像头硬件 FPS 使用 30,而数据集保存频率使用 --dataset.fps=10,两者不是同一个参数。
第一版 SmolVLA 任务定义为:
Pick up the ball and place it in the target area.
也就是桌面静态捡球并放到目标区域。当前设计的数据集名称为:
czw1/so101_ball_pick_v1
正式采集命令设计如下:
source /home/czw1/miniforge3/etc/profile.d/conda.sh
conda activate lerobot
cd /home/czw1/lerobot
lerobot-record \
--robot.type=so101_follower \
--robot.port=/dev/ttyACM0 \
--robot.id=follower \
--robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 160, height: 120, fps: 30, fourcc: MJPG} }" \
--teleop.type=so101_leader \
--teleop.port=/dev/ttyACM1 \
--teleop.id=leader \
--dataset.repo_id=czw1/so101_ball_pick_v1 \
--dataset.single_task="Pick up the ball and place it in the target area." \
--dataset.fps=10 \
--dataset.episode_time_s=15 \
--dataset.reset_time_s=8 \
--dataset.num_episodes=60 \
--dataset.video=true \
--dataset.push_to_hub=false \
--display_data=false \
--resume=false
后续如果需要追加数据,保持同一个 dataset.repo_id,并将:
--resume=true
打开即可。
为了保证后续可迭代,本周还确定了数据集版本规则:
czw1/so101_ball_pick_v1 静态桌面捡球并放到目标区
czw1/so101_ball_pick_v2 增加球位置、光照、背景、起始姿态变化
czw1/so101_ball_handover_v1 人手递球,机械臂夹住后放置
czw1/so101_ball_roll_v1 慢速滚动球任务
czw1/so101_light_switch_v1 关灯任务
训练方面,由于当前只有一个真实摄像头,而 SmolVLA base 默认期望多个摄像头输入,因此训练时需要做两个处理:
--rename_map="{ observation.images.front: observation.images.camera1 }"
--policy.empty_cameras=2
其中 rename_map 用于把数据集中的 front 摄像头映射到 SmolVLA 期望的 camera1,empty_cameras=2 用于补齐另外两个空摄像头输入。
第一版训练命令设计如下:
source /home/czw1/miniforge3/etc/profile.d/conda.sh
conda activate lerobot
cd /home/czw1/lerobot
lerobot-train \
--policy.path=lerobot/smolvla_base \
--policy.repo_id=czw1/so101_ball_pick_smolvla_v1 \
--policy.push_to_hub=false \
--dataset.repo_id=czw1/so101_ball_pick_v1 \
--rename_map="{ observation.images.front: observation.images.camera1 }" \
--policy.empty_cameras=2 \
--batch_size=1 \
--steps=2000 \
--save_freq=500 \
--output_dir=outputs/train/so101_ball_pick_smolvla_v1 \
--job_name=so101_ball_pick_smolvla_v1 \
--policy.device=cuda \
--wandb.enable=false
如果效果不够,继续训练到 5000 steps:
lerobot-train \
--policy.path=lerobot/smolvla_base \
--policy.repo_id=czw1/so101_ball_pick_smolvla_v1 \
--policy.push_to_hub=false \
--dataset.repo_id=czw1/so101_ball_pick_v1 \
--rename_map="{ observation.images.front: observation.images.camera1 }" \
--policy.empty_cameras=2 \
--batch_size=1 \
--steps=5000 \
--save_freq=500 \
--output_dir=outputs/train/so101_ball_pick_smolvla_v1 \
--job_name=so101_ball_pick_smolvla_v1 \
--policy.device=cuda \
--wandb.enable=false \
--resume=true
部署测试方案使用 lerobot-rollout。考虑到当前链路推理速度较慢,先使用低频安全测试:
lerobot-rollout \
--robot.type=so101_follower \
--robot.port=/dev/ttyACM0 \
--robot.id=follower \
--robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 160, height: 120, fps: 30, fourcc: MJPG} }" \
--policy.path=/home/czw1/lerobot/outputs/train/so101_ball_pick_smolvla_v1/checkpoints/002000/pretrained_model \
--rename_map="{ observation.images.front: observation.images.camera1 }" \
--task="Pick up the ball and place it in the target area." \
--fps=1 \
--duration=15 \
--display_data=false \
--return_to_initial_position=false
这一部分的核心成果是:确定了第一版 SmolVLA 模型的任务、采集参数、训练参数、继续训练方式和部署测试方式,并且将这些参数与 agent_vla 框架中的 VLA Service 对接方式统一起来。训练完成后,只需要把 checkpoint 路径写入 configs/app.yaml,即可通过 Agent 调用 VLA 模型。
此外,本周还调研了可复用的“捡物块 / pick-place”基础模型方案。选择先从捡球、捡物块这类任务入手,主要是因为 pick-place 是桌面机器人最基础、最通用的动作单元,很多后续任务都可以拆解为类似能力:
捡球 -> 抓取物体 -> 移动到目标区域 -> 放下
放到桌子上 -> 抓取物体 -> 移动到桌面指定位置 -> 放下
整理桌面 -> 多次执行 pick-place
人手递物 -> 接近物体 -> 闭合夹爪 -> 移动到目标区
当前调研结论是:第一版不直接追求大而全的多任务模型,而是先训练一个稳定的 so101_ball_pick_smolvla_v1,把它作为可复用的桌面抓取基础模型。后续如果捡球效果稳定,再把数据扩展为更通用的捡物块模型,例如:
czw1/so101_pick_object_v1
该数据集可以逐步加入:
- 球
- 方块
- 小积木
- 轻量日用品
- 不同颜色和不同材质的小物体
对应的任务描述可以统一为:
Pick up the object and place it in the target area.
这样可以把模型从“只会捡球”扩展为“能捡常见小物体”,提高后续复用价值。对于 Agent 框架来说,这类能力可以注册成一个通用 VLA 技能:
pick_object_v1:
name: Pick up object
task_prompt: "Pick up the object and place it in the target area."
policy_path: /home/czw1/lerobot/outputs/train/so101_pick_object_smolvla_v1/checkpoints/...
后续 Agent 在理解用户指令时,可以把“捡球”“拿积木”“把这个东西放到目标区”等不同说法统一路由到同一个可复用的 pick_object_v1 技能,从而减少重复训练和重复开发成本。
三、下周主要工作
下周的主要目标是把当前框架从 mock 联调推进到真实模型闭环。
计划工作如下:
- 正式采集
czw1/so101_ball_pick_v1数据集,目标至少 60 条高质量演示。 - 使用 SmolVLA base 训练
so101_ball_pick_smolvla_v1,先训练 2000 steps。 - 使用
lerobot-rollout对捡球任务进行低频部署测试,统计基础成功率。 - 根据测试效果决定是否继续训练到 5000 steps 或补充采集数据。
- 将训练好的 checkpoint 路径写入
agent_vla/configs/app.yaml。 - 将 VLA Service 从
mockprovider 切换为lerobot_rolloutprovider。 - 让 Agent 通过
/v1/chat真实调用 VLA Service 执行捡球任务。 - 接入一个真实 LLM provider,例如 OpenAI、Ollama 或本地模型,用于替换当前 mock LLM。
- 优化 Agent 的意图识别方式,减少纯关键词匹配带来的误判。
- 在捡球任务稳定后,规划第二个技能,例如关灯或放到桌子上。
后续长期方向是将当前 WSL2 桌面端 Demo 逐步迁移到 Orange Pi AI Pro。初期可以让 Orange Pi 只运行 Agent,VLA 推理仍调用 WSL2 服务;等 SmolVLA 到 ONNX / Ascend NPU 的部署链路验证后,再新增 ascend_vla provider,使底层推理切换到 Orange Pi AI Pro / Ascend NPU,而 Agent 层接口保持不变。