SimToReal 概述

AKA-Sim2Real 是一个基于前视视角的自动驾驶模拟到真实(Sim2Real)系统,旨在通过模拟器采集人类驾驶数据,训练 ACT(Action Chunking Transformer)模型,并将训练好的策略迁移到真实小车上运行。


系统架构

┌─────────────────────────────────────────────────────────┐
│                     AKA-Sim2Real                        │
│                                                         │
│  ┌─────────────┐    ┌──────────────┐    ┌───────────┐  │
│  │  模拟器/真车  │───▶│  数据采集模块  │───▶│  数据集   │  │
│  │ (Sim/Real)  │    │  Episode API │    │ output/  │  │
│  └─────────────┘    └──────────────┘    │ dataset/ │  │
│         │                               └────┬─────┘  │
│         │                                    │        │
│         │           ┌──────────────┐    ┌────▼─────┐  │
│         │           │  ACT 模型推理  │◀───│ 模型训练  │  │
│         └──────────▶│  Inference   │    │Training  │  │
│                     │   Runtime    │    └──────────┘  │
│                     └──────────────┘                  │
└─────────────────────────────────────────────────────────┘

系统由三个核心部分组成:

模块说明
模拟器 / 真车接口提供前视视角仿真环境,支持键盘手动控制与自动推理两种模式
数据采集记录图像帧 + 车辆状态 + 动作,导出为结构化数据集
ACT 训练与推理基于 Action Chunking Transformer 进行模仿学习,支持 CVAE 与时序集成

技术栈

层级技术
后端框架FastAPI + Socket.IO (Python)
深度学习PyTorch + ResNet18 + Transformer
前端React + TypeScript + Socket.IO Client

文档目录

SimToReal 概述

AKA-Sim2Real 是一个基于前视视角的自动驾驶模拟到真实(Sim2Real)系统,旨在通过模拟器采集人类驾驶数据,训练 ACT(Action Chunking Transformer)模型,并将训练好的策略迁移到真实小车上运行。


系统架构

┌─────────────────────────────────────────────────────────┐
│                     AKA-Sim2Real                        │
│                                                         │
│  ┌─────────────┐    ┌──────────────┐    ┌───────────┐  │
│  │  模拟器/真车  │───▶│  数据采集模块  │───▶│  数据集   │  │
│  │ (Sim/Real)  │    │  Episode API │    │ output/  │  │
│  └─────────────┘    └──────────────┘    │ dataset/ │  │
│         │                               └────┬─────┘  │
│         │                                    │        │
│         │           ┌──────────────┐    ┌────▼─────┐  │
│         │           │  ACT 模型推理  │◀───│ 模型训练  │  │
│         └──────────▶│  Inference   │    │Training  │  │
│                     │   Runtime    │    └──────────┘  │
│                     └──────────────┘                  │
└─────────────────────────────────────────────────────────┘

系统由三个核心部分组成:

模块说明
模拟器 / 真车接口提供前视视角仿真环境,支持键盘手动控制与自动推理两种模式
数据采集记录图像帧 + 车辆状态 + 动作,导出为结构化数据集
ACT 训练与推理基于 Action Chunking Transformer 进行模仿学习,支持 CVAE 与时序集成

技术栈

层级技术
后端框架FastAPI + Socket.IO (Python)
深度学习PyTorch + ResNet18 + Transformer
前端React + TypeScript + Socket.IO Client

文档目录

快速开始

本节介绍如何在本地搭建并运行 AKA-Sim2Real 系统。


环境要求

依赖版本建议
Python3.10+
Node.js18+
PyTorch2.0+(支持 CUDA/MPS/CPU)

1. 克隆仓库

git clone <仓库地址>
cd AKA-Sim2Real

2. 安装后端依赖

cd backend
pip install -r requirements.txt

提示:推荐使用 conda 或 venv 创建独立 Python 环境,避免依赖冲突。


3. 安装前端依赖

cd ui
npm install

4. 启动后端服务

cd backend
python main.py

后端将运行在 http://localhost:8000

启动成功后,终端会输出类似以下信息:

INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

注意:后端启动时会尝试自动加载 output/train/model.pt,如果模型文件不存在,则以无模型状态运行(推理功能不可用,但数据采集和训练功能正常)。


5. 启动前端服务

新开一个终端窗口:

cd ui
npm run dev

前端将运行在 http://localhost:5173


6. 访问界面

在浏览器中打开 http://localhost:5173,可以看到:

  • Sim 页面:模拟器视角,用于数据采集与模拟推理
  • Real 页面:真实小车接口视图

目录结构说明

AKA-Sim2Real/
├── backend/          # Python 后端(FastAPI + Socket.IO)
│   ├── main.py       # 服务入口
│   ├── api/          # REST API 路由
│   ├── sio_handlers/ # Socket.IO 事件处理
│   └── services/     # 核心业务逻辑(ACT、训练、采集)
├── ui/               # React 前端
├── policies/         # ACT 模型定义与训练脚本
├── output/           # 运行时输出目录
│   ├── dataset/      # 采集的数据集
│   └── train/        # 训练输出(model.pt)
└── tests/act/        # ACT 最小回归测试

验证安装

运行 ACT 单元测试,验证核心链路正常:

python3 backend/run_act_checks.py

全部通过则说明 ACT 主链路(模型定义、推理、数据导出)运行正常。


下一步

数据采集

数据采集是 Sim2Real 流程的第一步。通过在模拟器中手动驾驶小车,系统会同步记录摄像头图像车辆状态控制动作,最终导出为结构化数据集供 ACT 模型训练使用。


采集的数据格式

每个时间步采集以下数据:

字段类型说明
imageRGB 图像帧模拟器前视摄像头画面
state[vel_left, vel_right]左右轮速度(当前车辆状态)
action[vel_left, vel_right]左右轮控制指令

状态维度和动作维度均为 2,分别对应左轮速度和右轮速度。


数据采集步骤

1. 启动系统

确保后端和前端均已启动(参见快速开始),在浏览器中打开 Sim 页面。

2. 控制小车

使用键盘控制小车行驶:

按键动作
W / 前进
S / 后退
A / 左转
D / 右转

3. 开始录制

点击界面上的 "开始采集" 按钮,系统进入录制模式,此时每个控制帧的图像、状态和动作均会被记录。

4. 停止录制

完成一段演示后,点击 "停止采集" 按钮。数据会自动导出到:

output/dataset/

数据集结构

导出后的数据集组织结构如下:

output/dataset/
├── episode_0/
│   ├── images/        # 每帧图像(PNG 格式)
│   ├── states.npy     # 状态序列 [N, 2]
│   └── actions.npy    # 动作序列 [N, 2]
├── episode_1/
│   └── ...
└── stats.json         # 数据集统计信息(均值、标准差)

stats.json 保存了状态和动作的归一化统计量,推理时也需要用到:

{
  "state_mean": [0.0, 0.0],
  "state_std":  [1.0, 1.0],
  "action_mean": [0.0, 0.0],
  "action_std":  [1.0, 1.0]
}

采集建议

  • 数量:建议至少采集 100 个样本(帧)才能开始训练,样本越多模型越稳定
  • 多样性:涵盖直行、左转、右转等多种驾驶场景,提升模型泛化能力
  • 一致性:每段演示应保持合理的驾驶行为,避免急停急转等极端操作

REST API(高级用法)

数据采集功能也通过 REST API 暴露,可用于自动化脚本:

方法路径说明
POST/api/episode/start开始采集
POST/api/episode/stop停止采集并导出
GET/api/episode/list列出所有 episode
DELETE/api/episode/{id}删除指定 episode

下一步

数据采集完成后,继续进行 模型训练

模型训练

采集到足够的演示数据后,即可训练 ACT(Action Chunking Transformer)模型。训练过程由后端的训练编排器(Training Orchestrator)自动完成,无需手动干预。


训练前提

  • 已完成数据采集,数据保存在 output/dataset/
  • 数据集中至少有 100 个样本

启动训练

在前端界面点击 "开始训练" 按钮,或通过 REST API 触发:

curl -X POST http://localhost:8000/api/training/start

训练流程详解

训练器(backend/services/training/orchestrator.py)执行以下步骤:

数据集加载
    │
    ▼
构建 ACT 配置
    │
    ▼
初始化模型(ACTModel)
    │
    ▼
训练循环(L1 Loss + KL Loss)
    │
    ▼
保存模型检查点
output/train/model.pt(含 CVAE 潜变量统计)

损失函数

ACT 使用两个损失项联合训练:

损失公式说明
重建损失L1(predicted_actions, gt_actions)动作预测的主要监督信号
KL 散度KL(q(z|obs,action) ∥ p(z|obs))CVAE 正则项,权重为 kl_weight=0.1

总损失:Loss = L1_loss + kl_weight × KL_loss


默认超参数

参数默认值说明
state_dim2状态维度(左右轮速)
action_dim2动作维度(左右轮指令)
action_chunk_size8每次预测的动作步数
hidden_dim512Transformer 隐层维度
num_attention_heads8多头注意力头数
num_encoder_layers4Transformer 编码器层数
num_decoder_layers4Transformer 解码器层数
dim_feedforward3200前馈网络中间维度
kl_weight0.1KL 散度损失权重
latent_dim32CVAE 潜变量维度
use_cvaeTrue是否启用 CVAE

训练输出

训练完成后,模型保存在:

output/train/
├── model.pt           # 完整模型检查点(含 CVAE 潜变量统计)
└── final_model.pt     # 最终模型(如启用了 CVAE 则包含 latent stats)

检查点内容:

{
    "model_state_dict": ...,   # 模型权重
    "config": { ... },         # ACT 配置字典
    "latent_mean": ...,        # CVAE 潜变量均值(用于推理时采样)
    "latent_std":  ...,        # CVAE 潜变量标准差
}

查看训练状态

通过 REST API 查询训练进度:

# 获取训练状态
curl http://localhost:8000/api/training/status

# 停止训练
curl -X POST http://localhost:8000/api/training/stop

单独运行训练脚本(高级)

如需在命令行直接运行训练(不通过 Web 界面):

python policies/models/act/train_act.py \
    --dataset_dir output/dataset \
    --output_dir output/train

下一步

训练完成后,继续进行 模型推理,让小车自主行驶。

模型推理

模型推理阶段,系统使用训练好的 ACT 模型替代人工操控,实现小车自主驾驶。系统同时支持**模拟器(Sim)真实小车(Real)**两种模式。


推理前提

  • 已完成模型训练output/train/model.pt 存在
  • 后端和前端均已启动

加载模型

方式一:自动加载(推荐)

后端启动时会自动尝试加载 output/train/model.pt,无需手动操作。可通过以下接口确认模型状态:

curl http://localhost:8000/health

返回示例:

{
  "model_loaded": true,
  "device": "mps"
}

方式二:前端手动加载

在界面上点击 "加载模型" 按钮,系统会加载最新的模型检查点。

方式三:REST API

curl -X POST http://localhost:8000/api/inference/load

启动自动推理

前端操作

点击 "自动推理" 按钮,系统进入自动驾驶模式:

  1. 摄像头每帧捕获当前图像
  2. 图像与车辆状态输入 ACT 模型
  3. 模型输出动作块(action chunk,8 个时间步)
  4. 取第一个动作执行,循环往复

Socket.IO 事件

推理通过 Socket.IO 实时传输控制指令:

事件方向说明
start_inference客户端 → 服务端启动自动推理
stop_inference客户端 → 服务端停止自动推理
inference_action服务端 → 客户端下发控制动作

推理流程详解

摄像头图像 ──┐
             ├──▶ ACTInferenceRuntime.infer()
车辆状态   ──┘         │
                       ├── 图像预处理(ResNet18 归一化)
                       ├── 状态归一化
                       ├── Transformer 编码解码
                       ├── 输出 action chunk [8, 2]
                       ├── (可选)时序集成(Temporal Ensembling)
                       └── 动作反归一化 → 发送给小车

图像预处理:图像统一缩放并按 ImageNet 均值/方差归一化后送入 ResNet18 视觉编码器。

状态归一化:使用数据集中保存的 state_meanstate_std 进行 Z-score 归一化。

动作反归一化:输出的动作使用 action_meanaction_std 还原为真实控制量。


时序集成(Temporal Ensembling)

时序集成是 ACT 论文中提出的平滑技术,通过对多个历史 action chunk 的加权融合来减少控制抖动。

启用方式(设置环境变量):

export ACT_TEMPORAL_ENSEMBLING=1
python backend/main.py

衰减权重temporal_ensembling_weight 配置参数控制(默认 0.5),值越小融合越平滑。

注意:当前默认关闭时序集成,适合大多数场景。如控制输出存在抖动,可尝试开启。


Sim 与 Real 模式

系统同时支持两个 Socket.IO 命名空间:

命名空间用途
/sim模拟器推理,控制虚拟小车
/real真实小车推理,通过硬件接口控制实体小车

两个命名空间使用相同的推理逻辑,仅底层执行器(模拟器控制器 vs 真实硬件驱动)不同。


推理 REST API

方法路径说明
GET/health查询模型加载状态
POST/api/inference/load加载模型
POST/api/inference/reset重置推理上下文(清空时序集成缓存)

推理调试

查看后端日志中的推理输出,确认模型正常运行:

INFO: 加载 ACT 模型...
INFO: 状态归一化: mean=[0.0, 0.0], std=[1.0, 1.0]
INFO: 动作归一化: mean=[0.0, 0.0], std=[1.0, 1.0]
INFO: ACT 模型加载完成,使用设备: mps

若模型未加载时触发推理,系统会返回零动作 [0.0, 0.0] 并打印警告日志,而非抛出异常,保证系统鲁棒性。

ACT 模型架构

ACT(Action Chunking Transformer)是一种基于 Transformer 的模仿学习策略,通过预测**动作块(action chunk)**而非单步动作来实现平滑、稳定的控制输出。


整体架构图

                     ┌──────────────────────────────────────┐
                     │           ACTModel                   │
                     │                                      │
  图像输入            │  ┌──────────────┐                   │
  (H×W×3) ─────────▶│  │  RGBEncoder   │──▶ 视觉特征 (D)   │
                     │  │  (ResNet18)   │                   │
                     │  └──────────────┘         │          │
                     │                           │          │
  状态输入            │  ┌──────────────┐         │          │
  [vel_l, vel_r] ──▶│  │ StateEncoder  │──▶ 状态特征 (D)   │
                     │  │    (MLP)      │         │          │
                     │  └──────────────┘         │          │
                     │                           ▼          │
  ┌──────────┐       │               ┌────────────────┐     │
  │   CVAE   │──────▶│               │ Transformer    │     │
  │ (训练时)  │  z   │               │ Encoder-Decoder│     │
  └──────────┘       │               └────────┬───────┘     │
                     │                        │             │
                     │                        ▼             │
                     │               ┌────────────────┐     │
                     │               │  动作预测头     │     │
                     │               │  (Linear)      │     │
                     │               └────────────────┘     │
                     │                        │             │
                     └────────────────────────┼─────────────┘
                                              │
                                              ▼
                              action_chunk [chunk_size, action_dim]
                              (默认 8 步 × 2 维)

核心组件

1. RGBEncoder(视觉编码器)

  • 骨干网络:ResNet18(ImageNet 预训练)
  • 输入:归一化后的 RGB 图像
  • 输出:展平的视觉特征向量,投影到 hidden_dim(默认 512)
  • 图像预处理:resize → ImageNet 均值/方差归一化

2. StateEncoder(状态编码器)

  • 结构:简单 MLP(多层感知机)
  • 输入:归一化后的车辆状态 [vel_left, vel_right](维度 2)
  • 输出:状态特征向量(维度 hidden_dim

3. CVAE(条件变分自编码器)

CVAE 在训练阶段引入潜变量 z,为动作预测提供多模态表达能力。

训练时:
  encoder: (观测, 动作序列) → (μ, σ) → z ~ N(μ, σ²)

推理时:
  z ~ N(latent_mean, latent_std)  # 从训练分布中采样
  或 z = 0                        # 使用零向量(确定性推理)

KL 散度损失约束潜变量分布接近标准正态分布:

KL Loss = KL(N(μ, σ²) ∥ N(0, I))

4. Transformer Encoder-Decoder

参数默认值
hidden_dim512
num_attention_heads8
num_encoder_layers4
num_decoder_layers4
dim_feedforward3200
  • 编码器:将视觉特征 + 状态特征 + CVAE 潜变量拼接,经多层自注意力编码为上下文表示
  • 解码器:以可学习的动作查询(action queries)为输入,通过交叉注意力从编码器上下文中提取信息,输出 action_chunk_size 个动作向量

5. 动作预测头

线性层将 Transformer 解码器的输出投影到动作空间(维度 action_dim=2),输出归一化后的动作块。


动作块(Action Chunking)

ACT 的核心创新之一是不预测单步动作,而是一次性预测 action_chunk_size 步的动作序列(默认 8 步)。

优势

  • 缓解复合误差(compound error)
  • 提升长序列动作的时间一致性
  • 减少控制器与环境之间的高频交互需求

执行策略:推理时每次只执行 action chunk 的第一步动作(或使用时序集成),下一帧重新预测。


时序集成(Temporal Ensembling)

时序集成通过加权融合多个历史 action chunk 的预测,进一步平滑控制输出。

当前动作 = α × 当前 chunk[0] + (1-α) × 历史融合动作

权重衰减系数 αtemporal_ensembling_weight,默认 0.5)控制历史信息的保留程度:

  • 值越大:跟随最新预测,响应速度快
  • 值越小:保留更多历史,控制更平滑

代码层次结构

policies/models/act/
├── modeling_act.py         # ACTModel、RGBEncoder、StateEncoder、CVAE、Transformer 层
├── configuration_act.py    # ACTConfig 数据类
├── defaults.py             # DEFAULT_ACT_CONFIG 与 build_act_config()
└── train_act.py            # 独立训练脚本

backend/services/inference/
├── checkpoint.py           # 检查点加载、模型实例化、统计量读取
├── preprocess.py           # 图像预处理、状态/动作归一化与反归一化
├── execution.py            # TemporalEnsemblingPolicy(时序集成)
└── runtime.py              # ACTInferenceRuntime(推理运行时装配)

训练损失汇总

损失项权重说明
L1 重建损失1.0预测动作块与真实动作的 L1 误差
KL 散度0.1(kl_weightCVAE 潜变量正则化

总损失 = L1_loss + 0.1 × KL_loss


参考资料

UI 文档

本节介绍 AKA-Sim2Real 前端的架构、页面和组件。


页面概览

页面路由用途
SimPage/模拟器视角,用于数据采集与模拟推理
RealPage/real真实小车控制接口

技术栈

  • 框架: React 19 + TypeScript
  • 路由: React Router DOM 7
  • 状态管理: Zustand
  • 样式: Tailwind CSS 4
  • HTTP 客户端: Ky
  • 实时通信: Socket.IO Client
  • 构建工具: Vite 7

目录结构

ui/src/
├── main.tsx              # 应用入口
├── App.tsx               # 根组件,路由配置
├── index.css             # Tailwind 入口
├── api/
│   ├── api.ts            # REST API 客户端
│   ├── socket.ts         # Socket.IO 客户端工厂
│   └── realCar.ts        # 真实小车 HTTP API
├── models/
│   └── types.ts          # 共享 TypeScript 类型
├── stores/
│   └── simCarStore.ts    # Zustand 状态管理
└── pages/
    ├── SimPage/          # 模拟器页面
    ├── RealPage/         # 真实小车页面
    └── NotFound.tsx      # 404 页面

核心概念

页面详解


SimPage

路由: /

模拟器主页面,用于数据采集与模型推理测试。

布局结构

┌─────────────────────────────────────────────────────────────┐
│                      SimPage                                │
├───────────────────────────────┬─────────────────────────────┤
│                               │       RightPanel             │
│        TopDownView            │  ┌─────────────────────┐    │
│       (俯视画布)              │  │   FirstPersonView   │    │
│                               │  │   (第一视角)          │    │
│   [小车站 + 障碍物 + 地图]    │  └─────────────────────┘    │
│                               │  ┌─────────────────────┐    │
│                               │  │    LogConsole       │    │
│                               │  │   (日志控制台)       │    │
├───────────────────────────────┴─────────────────────────────┤
│                   TrainingControl + InferenceControl         │
└─────────────────────────────────────────────────────────────┘

核心功能

  1. 键盘控制: WASD/方向键控制小车运动
  2. 数据采集: 录制驾驶演示数据
  3. 训练控制: 启动/停止模型训练
  4. 推理测试: 加载模型进行模拟推理
  5. 实时日志: 显示后端运行日志

Socket.IO 事件

事件名方向说明
actionemit发送动作指令
car_state_updatelisten接收小车状态更新
collect_dataemit发送采集数据
training_progresslisten接收训练进度
act_infer_resultlisten接收推理结果

RealPage

路由: /real

真实小车控制页面,用于连接和控制物理机器人。

布局结构

┌─────────────────────────────────────────────────────────────┐
│                      RealPage                                │
├─────────────────────────────────┬─────────────────────────────┤
│                                 │        RealRightPanel       │
│       RealCameraView            │  ┌─────────────────────┐    │
│      (浏览器摄像头)              │  │     Car IP 配置      │    │
│                                 │  │   连接状态显示        │    │
│                                 │  │   电机状态显示        │    │
├─────────────────────────────────┴─────────────────────────────┤
│                      控制面板                                  │
│     [连接] [前进] [后退] [左转] [右转] [停止]                   │
└─────────────────────────────────────────────────────────────┘

核心功能

  1. 摄像头访问: 使用浏览器 API 获取小车摄像头画面
  2. IP 配置: 设置小车 IP 地址
  3. 电机控制: HTTP 请求控制小车电机
  4. 状态监控: 显示心跳和电机状态

API 通信

真实小车通过 HTTP API 直接通信:

// 发送心跳
carHeartbeat(carIP)

// 获取电机状态
motorStatusAt(carIP)

// 直接控制电机
motorDirect(carIP, leftVel, rightVel)

// 小车整体控制
carControl(carIP, action)

组件详解


SimPage 组件

TopDownView

俯视画布组件,展示小车、障碍物和地图。

文件: pages/SimPage/TopDownView.tsx

功能:

  • Canvas 绑定的 2D 地图渲染
  • 键盘事件监听(WASD/方向键)
  • 小车位置和角度显示
  • 障碍物绘制

状态依赖: 监听 simCarStore 获取小车状态


RightPanel

右侧面板容器,包含第一视角视图和日志控制台。

文件: pages/SimPage/RightPanel.tsx

子组件:

  • FirstPersonView(第一视角渲染)
  • LogConsole(日志显示)

InferenceControl

推理控制面板。

文件: pages/SimPage/InferenceControl.tsx

功能:

  • 加载训练好的模型
  • 单步推理测试
  • 自动推理模式

TrainingControl

训练和数据采集控制面板。

文件: pages/SimPage/TrainingControl.tsx

功能:

  • Episode 管理(开始/结束/保存)
  • 数据采集开关
  • FPS 配置
  • 训练启动/停止

LogConsole

实时日志显示组件。

文件: pages/SimPage/LogConsole.tsx

功能:

  • Socket.IO log_message 事件监听
  • 自动滚动到底部
  • 日志级别过滤(可选)

RealPage 组件

RealCameraView

浏览器摄像头访问组件。

文件: pages/RealPage/RealCameraView.tsx

功能:

  • navigator.mediaDevices.getUserMedia 获取视频流
  • 设备选择下拉框
  • 视频预览显示

RealRightPanel

真实小车右侧状态面板。

文件: pages/RealPage/RealRightPanel.tsx

功能:

  • 小车 IP 输入
  • 连接状态指示
  • 电机状态显示

共享组件

actionMapping

键盘按键到动作的映射工具。

文件: pages/SimPage/actionMapping.ts

映射关系:

按键动作
W / ↑forward
S / ↓backward
A / ←turn_left
D / →turn_right
Qforward_left
Eforward_right
Zbackward_left
Cbackward_right
Spacestop

状态管理


Zustand Store

使用 Zustand 进行轻量级状态管理。

simCarStore

文件: stores/simCarStore.ts

管理模拟器小车状态。

interface CarState {
  x: number;        // 小车 X 坐标
  y: number;        // 小车 Y 坐标
  angle: number;   // 小车角度 (弧度)
  vel_left: number;  // 左轮速度
  vel_right: number; // 右轮速度
}

const initialState: CarState = {
  x: 400,
  y: 300,
  angle: -Math.PI / 2,
  vel_left: 0,
  vel_right: 0,
};

Actions

Action说明
setCarState(state)更新小车状态
resetCarState()重置为初始状态

页面级 State

除全局 Store 外,各页面使用 useState 管理本地状态。

SimPage

State类型说明
isRecordingboolean是否正在录制
episodeCountnumberEpisode 数量
trainingStatusstring训练状态
inferenceResultobject推理结果

RealPage

State类型说明
carIPstring小车 IP 地址
isConnectedboolean连接状态
cameraDevicesMediaDeviceInfo[]摄像头设备列表
motorStatusobject电机状态

API 通信


REST API

使用 Ky HTTP 客户端与后端通信。

基础配置: api/api.ts

const api = ky.create({
  prefixUrl: '/api',
  headers: { 'Content-Type': 'application/json' },
});

端点列表

方法路径说明
POSTdataset/collect采集训练图片数据
POSTtrain启动模型训练
POSTtrain/stop停止训练
POSTact/load_trained加载训练好的模型

Socket.IO

实时双向通信,用于模拟器状态同步和日志推送。

Socket 工厂

文件: api/socket.ts

createSocket(namespace: string): Socket

创建命名空间的 Socket 实例:

实例命名空间用途
simSocket/sim模拟器状态同步
realSocket/real真实小车控制

事件列表

Emit 事件 (前端 → 后端)

事件数据格式说明
action{ action: string }发送动作指令
reset_car_state-重置小车状态
get_car_state-请求当前状态
collect_data{ image: string, state: object }采集数据
start_episode{ episodeId: number }开始 Episode
end_episode{ episodeId: number }结束 Episode
finalize_episode{ episodeId: number }保存 Episode
act_infer{ image: string, state: object }推理请求

Listen 事件 (后端 → 前端)

事件数据格式说明
connected-连接成功
car_state_updateCarState小车状态更新
collection_count{ count: number }采集数量
episode_infoEpisodeInfoEpisode 信息
training_progress{ epoch: number, loss: number }训练进度
act_infer_result{ action: string }推理结果
log_message{ level: string, message: string }日志消息

真实小车 HTTP API

文件: api/realCar.ts

直接向小车 IP 发送 HTTP 请求。

接口列表

函数HTTP 方法路径说明
carHeartbeatGET/api/heartbeat发送心跳
motorStatusAtGET/api/motor/status获取电机状态
motorDirectPOST/api/motor/direct直接控制电机
carControlPOST/api/car/control小车整体控制
carTimeSyncGET/api/time/sync时间同步

使用示例

import { carControl, motorDirect } from '@/api/realCar';

// 控制小车前进
await carControl(carIP, 'forward');

// 直接控制电机速度
await motorDirect(carIP, 100, 100);

MuJoCo

MuJoCo(Multi-Joint dynamics with Contact)是一个高效的物理仿真引擎,广泛用于机器人学和强化学习研究。

学习资源

文档

安装指南

本指南旨在帮助不同系统的开发者快速搭建 MuJoCo 虚拟仿真环境,重点针对 Linux (Debian/WSL) 进行了优化。

如果使用强化学习,推荐安装如下pip包

# 提供强化学习(RL)的标准化环境接口
pip install gymnasium

# 录制视频或制作 GIF 动图
pip install imageio

# 处理庞大的矩阵和数组数学运算
pip install numpy

# 深度学习框架
pip install torch  

Linux 安装 (Debian/WSL)

  1. 安装miniconda

打开 Linux 系统终端,依次运行以下命令进行静默安装:

# 1. 创建 miniconda 安装文件夹
mkdir -p ~/miniconda3

# 2. 从官方源下载最新的 Linux 安装包 (大概 140MB,稍微等进度条跑完)
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/miniconda.sh

# 3. 执行静默安装 (-b 代表后台静默,-u 代表更新,-p 指定绝对路径)
bash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3

# 4. 安装完后,把刚才下载的安装包删掉,节约空间!(可选)
rm ~/miniconda3/miniconda.sh

# 5. 初始化 conda,让你的终端认识 conda 命令
~/miniconda3/bin/conda init bash
  1. 激活并初始化 Conda

为了让刚才的配置立刻生效,需要刷新当前终端

source ~/.bashrc

验证成功标志:终端命令行最左边出现 (base) 前缀!

  1. 接受协议与创建Python环境

重要提示:由于新版 Conda 的合规要求,第一次下载包前需要接受服务条款,否则会触发报错。

miniconda_bug

请执行以下命令接受 Anaconda 官方服务条款

conda tos accept

miniconda_bug

创建一个独立的 Python 3.10 环境:

# 创建一个名叫 mujoco_env 的环境,并指定 python 版本为 3.10
conda create -n mujoco_env python=3.10 -y
  1. 激活环境
# 激活进入专属环境
conda activate mujoco_env
  1. 安装 MuJoCo
# 安装 MuJoCo 引擎
pip install mujoco
  1. 代码测试

创建 test_mujoco.py 文件

import mujoco
import mujoco.viewer

model = mujoco.MjModel.from_xml_string("""
<mujoco>
  <worldbody>
    <body>
      <geom type="box" size=".1 .1 .1" rgba="1 0 0 1"/>
    </body>
  </worldbody>
</mujoco>
""")

data = mujoco.MjData(model)

with mujoco.viewer.launch_passive(model, data) as viewer:
    while viewer.is_running():
        mujoco.mj_step(model, data)
        viewer.sync()
  1. 通过python运行
python test_mujoco.py
  1. 若弹出包含红色方块的 3D 软件窗口,则表示安装成功

linux_init

温馨提示:建议第4步下载速度慢,可配置清华镜像源:

pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

Macos 安装

  1. 安装miniconda

要安装miniconda,请按照官方安装指南

  1. 创建干净的 Python 环境
conda create -n mujoco python=3.10
conda activate mujoco
  1. 安装 MuJoCo
pip install mujoco
  1. 用代码测试

创建 test_mujoco.py 文件

import mujoco
import mujoco.viewer

model = mujoco.MjModel.from_xml_string("""
<mujoco>
  <worldbody>
    <body>
      <geom type="sphere" size="0.1"/>
    </body>
  </worldbody>
</mujoco>
""")

data = mujoco.MjData(model)

with mujoco.viewer.launch_passive(model, data) as viewer:
    while viewer.is_running():
        mujoco.mj_step(model, data)
        viewer.sync()
  1. 通过mjpython运行
mjpython test_mujoco.py
  1. 弹出软件窗口为安装成功

mac_init

Windows 安装

Windows 用户有两种选择:快速查看或 Python 开发环境(推荐两者都做)

A. 快速查看 (免配置)

  1. 下载并解压 MuJoCo点击下载MuJoCo 3.5.0 Windows 压缩包

sha256校验:mujoco-3.5.0-windows-x86_64.zip.sha256 877d0dfbceac3de90a874c41e0f20c568d104e8ca19de955c0482e3b63832519

  1. 解压后双击 bin/simulate.exe

windows_init

  1. 双击上图的simulate.exe后,会同时打开两个窗口
    注意:这里的shell窗口不要关闭(最小化即可)

windows_init1

  1. 鼠标拖拽,mujoco-3.5.0-windows-x86_64/model/humanoid/humanoid.xml ,下的文件到MuJoCo窗口,即可查看效果

windows_init2


B. 开发环境 (推荐使用PyCharm + Miniconda使用)

  1. 安装环境

安装 Miniconda:前往 官方下载

安装 PyCharm:前往 官方下载

  1. 创建环境

在Anaconda Powershell Prompt 或 Anaconda Prompt 中执行以下命令:

conda create -n mujoco_env python=3.10 -y
conda activate mujoco_env
  1. 安装库
pip install mujoco
pip install gymnasium
pip install imageio
  1. 在PyCharm环境下运行代码测试

创建 test_mujoco.py 文件

import mujoco
import mujoco.viewer

model = mujoco.MjModel.from_xml_string("""
<mujoco>
  <worldbody>
    <body>
      <geom type="box" size=".1 .1 .1" rgba="1 1 1 1"/>
    </body>
  </worldbody>
</mujoco>
""")

data = mujoco.MjData(model)

with mujoco.viewer.launch_passive(model, data) as viewer:
    while viewer.is_running():
        mujoco.mj_step(model, data)
        viewer.sync()
  1. 在PyCharm环境下运行 python test_mujoco.py,弹出软件窗口为安装成功

windows_init3

No.1 第一个 MuJoCo 仿真

本节通过一个最小示例,帮助你快速上手 MuJoCo XML 建模与 Python 仿真脚本。


文件说明

本节的示例文件位于 mujoco/No_1/ 目录下:

mujoco/No_1/
├── hello.xml   # MuJoCo XML 场景描述文件
└── no_1.py     # Python 仿真脚本

hello.xml 详解

完整内容

<mujoco>
    <!-- 全局仿真选项:重力加速度 -->
    <option gravity="0 0 -9.81"/>

    <!-- 编译器设置:角度单位使用弧度 -->
    <compiler angle="radian"/>

    <!-- 视觉渲染设置 -->
    <visual>
        <headlight ambient="0.1 0.1 0.1"/>
    </visual>

    <!-- 资产定义:可复用的材质 -->
    <asset>
        <material name="white" rgba="1 1 1 1"/>
    </asset>

    <!-- worldbody: 物理世界中的所有物体 -->
    <worldbody>
        <!-- 场景光源 -->
        <light diffuse=".5 .5 .5" pos="0 0 3" dir="0 0 -1"/>

        <!-- 地面(红色平面) -->
        <geom type="plane" size="1 1 0.5" rgba=".9 0 0 1"/>

        <!-- 物体 1:白色盒子,z=1 -->
        <body pos="0 0 1" euler="0 0 0">
            <joint type="free"/>
            <inertial pos="0 0 0" mass="1" diaginertia="0.01 0.01 0.01"/>
            <geom type="box" size=".1 .2 .3" material="white"/>
        </body>

        <!-- 物体 2:青色盒子,z=2,pitch=90°(侧立) -->
        <body pos="0 0 2" euler="0 90 0">
            <joint type="free"/>
            <inertial pos="0 0 0" mass="1" diaginertia="0.01 0.01 0.01"/>
            <geom type="box" size=".1 .2 .3" rgba="0 .9 .9 1"/>
        </body>

        <!-- 物体 3:灰色球体,z=3 -->
        <body pos="0 0 3" euler="0 0 0">
            <joint type="free"/>
            <inertial pos="0 0 0" mass="1" diaginertia="0.01 0.01 0.01"/>
            <geom type="sphere" size=".1" rgba=".5 .5 .5 1"/>
        </body>
    </worldbody>
</mujoco>

元素说明

<option>

全局仿真选项。

  • gravity="0 0 -9.81":标准重力加速度 9.81 m/s²(向下)

<compiler>

编译器设置。

  • angle="radian":角度单位使用弧度(默认是角度),这样 euler 值可以直接写数值如 90 表示 90°

<visual>

渲染视觉设置。

  • headlight:场景主光源的亮度

<asset>

可复用的资产定义。

  • material:定义可复用的材质(name="white",rgba 白色),在 geom 中通过 material="white" 引用

<worldbody>

物理世界的根容器,包含所有物体。

<light>

场景光源。

  • diffuse:漫反射颜色(灰白色)
  • pos:光源位置(上方 3 米)
  • dir:光照方向(沿 -z,即向下)

<geom> 地面

  • type="plane":平面
  • size="1 1 0.5":半尺寸(x=1, y=1, z=0.5 → 全尺寸 2×2×1 米)
  • rgba=".9 0 0 1":红色

<body>

刚体,可内嵌关节、惯性、几何体。

属性说明
pos初始位置(世界坐标系)
euler初始欧拉角(roll pitch yaw,弧度)

三个刚体的配置:

物体poseulergeom 类型颜色
物体 1z=10 0 0(水平)box白色(material)
物体 2z=20 90 0(侧立)box青色
物体 3z=30 0 0sphere灰色

<joint>

关节,连接 body 与父级(或世界)。

  • type="free":自由关节,物体不受任何约束,可在 6 个自由度上自由运动(平移 + 旋转)

<inertial>

刚体的质量分布特性。

属性说明
pos质心在 body 本地坐标系中的位置
mass质量(kg)
diaginertia惯性张量的三个主对角元素(Ixx, Iyy, Izz)

提示:如果不手动指定 inertial,MuJoCo 会根据 geom 的形状和默认密度自动计算。

<geom> 物体几何体

  • type:形状类型,支持 boxspherecylindercapsuleplaneellipsoid
  • size:半尺寸向量
    • box:size="0.1 0.2 0.3" → 全尺寸 0.2×0.4×0.6 米
    • sphere:size="0.1" → 半径 0.1 米
  • rgba:颜色 + 透明度(RGBA,各通道 0~1)
  • material:引用 <asset> 中定义的材质(优先于 rgba)

no_1.py 详解

import mujoco
import mujoco.viewer

# 1. 从 XML 文件加载模型
model = mujoco.MjModel.from_xml_path('hello.xml')

# 2. 创建仿真数据容器
data = mujoco.MjData(model)

# 3. 启动交互式查看器
with mujoco.viewer.launch_passive(model, data) as viewer:
    # 4. 主循环:每帧推进一次仿真
    while viewer.is_running():
        mujoco.mj_step(model, data)   # 执行一步仿真(默认 dt=0.002s)
        viewer.sync()                  # 同步查看器显示
步骤说明
MjModel.from_xml_path()解析 XML 构建物理模型
MjData存储仿真运行时数据(位置、速度、力等)
mj_step()推进一个仿真时间步
viewer.sync()将仿真状态同步到可视化窗口

运行方法

mujoco/No_1/ 目录下执行:

mjpython no_1.py

运行效果:三个物体同时从不同高度自由下落,落到红色地面上后弹起/静止。


常见错误

1. ValueError: XML Error: Schema violation: unrecognized element

原因:XML 中有拼写错误的标签名,如 <gemo><intertial><muhoco>

解决:检查并修正标签拼写,确认是 <geom><inertial><mujoco>

2. 物体没有出现或直接穿透地面

原因inertial 未指定且 geom 没有定义时,MuJoCo 可能使用了零质量。

解决:确保每个 body 下都有 <inertial mass="..."/> 或让 geom 的密度足够大。

3. mjpython: command not found

原因mujoco 包未正确安装,或 mjpython 不在 PATH 中。

解决

pip install mujoco
# 或直接用 python 运行
python no_1.py

No.2 交互式仿真与鼠标控制

本节介绍如何使用 GLFW 窗口创建交互式 3D 仿真,包括鼠标视角控制和控制器回调。


文件说明

本节的示例文件位于 mujoco/No_2/temp_mjcpy/ 目录下:

mujoco/No_2/temp_mjcpy/
├── ball.xml              # MuJoCo XML 场景描述文件
├── projectile.py         # 基础交互式仿真脚本
└── template_mujoco.py    # 带详细注释的模板脚本

ball.xml 详解

一个简单的弹球场景:

<mujoco>
  <worldbody>
    <!-- 场景光源 -->
    <light diffuse=".5 .5 .5" pos="0 0 3" dir="0 0 -1"/>

    <!-- 红色平面地面 -->
    <geom type="plane" size="10 1 0.1" rgba=".9 0 0 1"/>

    <!-- 绿色小球,初始位置 z=1 -->
    <body pos="0 0 1">
      <joint type="free"/>
      <geom type="sphere" size=".1" rgba="0 .9 0 1"/>
    </body>
  </worldbody>
</mujoco>
元素说明
plane平面地面,半尺寸 10×1×0.1
sphere绿色小球,半径 0.1

template_mujoco.py 详解

核心结构

import mujoco as mj
from mujoco.glfw import glfw
import numpy as np
import os

# 1. 模型加载
model = mj.MjModel.from_xml_path(xml_path)
data = mj.MjData(model)
cam = mj.MjvCamera()      # 视角相机
opt = mj.MjvOption()      # 可视化选项

# 2. GLFW 窗口初始化
glfw.init()
window = glfw.create_window(1200, 900, "Demo", None, None)
glfw.make_context_current(window)
glfw.swap_interval(1)

# 3. 可视化数据结构
scene = mj.MjvScene(model, maxgeom=10000)
context = mj.MjrContext(model, mj.mjtFontScale.mjFONTSCALE_150.value)

# 4. 注册回调函数
glfw.set_key_callback(window, keyboard)
glfw.set_cursor_pos_callback(window, mouse_move)
glfw.set_mouse_button_callback(window, mouse_button)
glfw.set_scroll_callback(window, scroll)
mj.set_mjcb_control(controller)

# 5. 主循环
while not glfw.window_should_close(window):
    mj.mj_step(model, data)
    # 渲染...
    glfw.poll_events()

glfw.terminate()

回调函数

controller

每步仿真前调用的控制回调,可写入外力:

def controller(model, data):
    """控制回调,每 mj_step 前自动调用"""
    pass

projectile.py 中的示例实现了空气阻力:

def controller(model, data):
    vx, vy, vz = data.qvel[0], data.qvel[1], data.qvel[2]
    v = np.sqrt(vx**2 + vy**2 + vz**2)
    c = 1.0  # 阻力系数
    data.qfrc_applied[0] = -c * v * vx
    data.qfrc_applied[1] = -c * v * vy
    data.qfrc_applied[2] = -c * v * vz

keyboard

键盘事件处理:

def keyboard(window, key, scancode, act, mods):
    if act == glfw.PRESS and key == glfw.KEY_BACKSPACE:
        mj.mj_resetData(model, data)
        mj.mj_forward(model, data)
按键动作
Backspace重置仿真到初始状态

mouse_move

鼠标拖动改变视角:

组合动作
左键拖动旋转视角
右键拖动移动视角
中键拖动缩放
Shift + 拖动切换交互模式

scroll

滚轮缩放视角。


交互操作

视角控制

操作功能
左键拖动旋转视角(水平/垂直)
右键拖动移动视角
滚轮缩放
Shift + 拖动切换模式

键盘

按键功能
Backspace重置仿真

初始条件设置

# 设置小球初始位置
data.qpos[2] = 0.1

# 设置小球初速度 (vx=2, vy=0, vz=5)
data.qvel[0] = 2.0
data.qvel[2] = 5.0

# 设置相机视角
cam.azimuth = 90.0
cam.distance = 8.0
cam.elevation = -45.0

运行方法

mujoco/No_2/temp_mjcpy/ 目录下执行:

python projectile.py
# 或带注释模板
python template_mujoco.py

运行效果:绿色弹球以初速度 (2, 0, 5) 抛出,受重力下落并受空气阻力影响。


与 No.1 的区别

特性No.1 (Passive)No.2 (GLFW)
窗口mujoco.viewer 被动窗口GLFW 主动创建窗口
视角控制受限鼠标自由控制
控制回调mj.set_mjcb_control
渲染控制自动同步手动调用 mjr_render
帧率控制自动手动控制循环频率