
# 星海图A1Z
本章节介绍如何将**Galaxea A1Z** 六轴机械臂（含G1Z夹爪）通过**LeRobot插件路径** 经r2c_sdk端到端接入**CloudRobo平台** ：上位机以r2c_sdk.cloudroboclient直驱硬件（观测上行、动作下行），云端策略服务订阅观测并下发推理动作，同时配合a1z-teleop项目完成遥操作数据采集，数据可直接用于LeRobot训练。与docs/a1z_cloudrobo_接入指南.md（hardware.type: a1z，A1Z SDK raw 直驱适配器）不同，本文基于**通用LeRobot硬件适配器** （hardware.type: lerobot）+ 第三方机器人插件lerobot_robot_galaxea_a1z（注册名 galaxea_a1z_follower）。该插件与数采项目共用同一份实现与标定文件，保证**数采、训练、云端推理三者的动作坐标系与相机特征完全一致**。
**关键区别**：插件以pip包形式安装，LeRobot 0.6.1的register_third_party_plugins()会自动发现并注册robot.type。
#### 一、依赖组件版本速查表（务必核对）
表1组件版本要求及说明 
| 组件            | 版本要求                                      | 说明                                                                        |
|:---|:---|:---|
| 操作系统          | Ubuntu 22.04/24.04                        | 内核 **≥ 6.8.0-124**（SocketCAN 兼容），否则按 Galaxea 官方指引打补丁。                     |
| Miniforge     | 最新版（conda-forge）                          | 安装至\~/miniforge3，自带mamba。                                                 |
| Python        | **3.12**                                  | conda 环境lerobot061与 2c_sdk（requires-python \>=3.12）一致。                    |
| LeRobot       | **0.6.1**                                 | pip install lerobot==0.6.1；插件按0.6.x API编写。                                |
| PyTorch       | 随LeRobot安装（PyPI Linux wheel 自带 CUDA 12.x） | 如果GPU驱动仅支持旧CUDA，先按对应index装 torch再装lerobot。                                |
| ffmpeg        | conda-forge版                              | LeRobot视频解码（TorchCodec）需要。                                                |
| A1Z SDK       | GALAXEA-A1Z（包名 a1z）                       | 官方A1Z Python SDK，pip install -e 安装。                                       |
| a1z-teleop    | git@github.com:xxxxxx/a1z-teleop.git      | 数采工程，含从臂插件lerobot_robot_galaxea_a1z与主臂插件 lerobot_teleoperator_stararm102。 |
| hw-r2c-sdk    | 最新版本                                      | Python ≥3.12；eclipse-zenoh 1.9.0、protobuf 7.35.0。                         |
| USB-CANFD 适配器 | HHS Pro-II（a8fa:8598）                     | gs_usb内核驱动，1Mbps。                                                         |
   
![](https://support.huaweicloud.com/sdkreference-cloudrobo/public_sys-resources/caution_3.0-zh-cn.png)
**不要**把LeRobot装在Python 3.13环境，也不要混用0.4.x/0.5.x时代的"拷贝插件进lerobot源码树"安装方式，0.6.1 的插件机制完全不同。
#### 二、硬件清单与接线安装
硬件清单与接线安装如[表2]和[表3]所示。
 表2硬件清单说明 
| 硬件            | 型号/规格                 | 用途           | 关键参数                                         |
|:---|:---|:---|:---|
| 机械臂           | Galaxea A1Z           | 6自由度协作臂      | CAN 通信（CAN ID 1--6），MIT 力控电机，无制动器            |
| 夹爪            | Galaxea G1Z           | 末端执行器        | CAN ID 7，力位混合控制，SDK 原生 Gripper类              |
| USB-CANFD 适配器 | HHS Pro-II（a8fa:8598） | 上位机与机械臂CAN通信 | SocketCAN / gs_usb 驱动，1 Mbps                 |
| 转接盒           | 随附                    | 电源+CAN信号转接   | -                                            |
| 电源适配器         | 随附（24V）               | 机械臂供电        | 含电路开关按键                                      |
| G 夹 ×2        | 随附                    | 机械臂固定于桌面     | -                                            |
| 相机 ×2（可选）     | USB UVC               | 腕部 + 头部/全局视角 | 推荐 640×480@30（腕部）、960×540@30（全局）             |
| 上位机           | Linux PC              | 运行r2c_sdk    | Python 3.12，内核 ≥6.8.0-124                    |
| 主臂（仅数采）       | Star-Arm-102          | 遥操作主臂        | 7 个 Fashionstar UART 伺服，/dev/ttyUSB0，12V 10A |
   
 表3接线安装说明 
| 连接             | 说明      |
|:---|:---|
| 将机械臂连接到转接盒     | 自带线缆直连。 |
| 将CAN盒连接到转接盒    | 自带线缆直连。 |
| 将CAN盒连接到上位机    | USB线。   |
| 将电源适配器连接到转接盒   | 自带线缆直连。 |
| 将AC电源线连接到电源适配器 | 含开关按键。  |
   
#### 开机顺序（重要）
1. 插USB-CANFD适配器。
2. 初始化 CAN 总线。
3. **从臂上电**（打开电源开关，等待1\~2秒自检）。
4. 数采场景最后给主臂（Star-Arm-102）上电。
 
![](https://support.huaweicloud.com/sdkreference-cloudrobo/public_sys-resources/warning_3.0-zh-cn.png)
**安全警告**：
- A1Z关节电机**无制动器**，断电后机械臂会因重力下坠。
- 操作时保持工作空间清空；首次真实控制时人站在工作空间外、手靠近电源开关。
 
#### 三、软件环境安装（安装Miniforge + LeRobot + r2c_sdk）
需要安装Miniforge、LeRobot、r2c_sdk。
#### 安装Miniforge
1. 执行如下命令，检查系统信息。 
   ```
   uname -r        # 应 ≥ 6.8.0-124；低于此版本可能导致 CAN 通信异常（电机使能无反馈）
   python3 --version
   ```
   
   
2. 执行如下命令，安装Miniforge。 
   ```
   wget "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh"
   bash Miniforge3-$(uname)-$(uname -m).sh          # 默认安装到 ~/miniforge3
   # 安装脚本最后选择 yes 执行 conda init，然后重新打开终端
   conda --version
   ```
   
   
3. 执行以下命令，创建conda环境lerobot061（Python 3.12）。 
   ```
   conda create -y -n lerobot061 python=3.12
   conda activate lerobot061 
   python -V            # 应为 Python 3.12.x
   ```
   
   ```
   conda activate lerobot061  
   # 视频解码依赖（TorchCodec 需要 ffmpeg）
   conda install ffmpeg -c conda-forge  
   # LeRobot 0.6.1（PyPI Linux wheel 自动携带 CUDA 12.x 版 torch）
   pip install lerobot==0.6.1  
   # 验证版本（务必是 0.6.x）
   python -c "import lerobot; print(lerobot.__version__)"   # 应输出 0.6.1
   ```
   - 如果GPU驱动较旧（仅支持CUDA 11.x），执行以下命令先安装匹配的torch再安装lerobot。
     ```
     pip install torch --index-url https://download.pytorch.org/whl/cu118。
     ```
     
   
   
   
   - 编译报错时，执行以下命令补安装。
     ```
     sudo apt-get install cmake build-essential python3-dev pkg-config libavformat-dev libavcodec-dev libavdevice-dev libavutil-dev libswscale-dev libswresample-dev libavfilter-dev。
     ```
     
   
   
   
   
 
#### 安装A1Z SDK与LeRobot 插件（来自 a1z-teleop 工程）
a1z-teleop数采工程（**GitHub：git@github.com:xxxxxx/a1z-teleop.git**）同时提供从臂插件lerobot_robot_galaxea_a1z（注册名 galaxea_a1z_follower）与主臂插件lerobot_teleoperator_stararm102。
1. 执行以下命令，云端接入只使用从臂插件，执行setup.sh脚本会一并安装，无需额外操作。 
   ```
   cd ~/project 
   git clone git@github.com:xxxxxx/a1z-teleop.git 
   cd a1z-teleop  
   # 自动激活 lerobot061，安装 A1Z SDK + 主/从臂插件，并运行安装校验
   # A1Z SDK 路径按实际指定（官方 GALAXEA-A1Z 仓库，包名 a1z）
   A1Z_SDK=/path/to/GALAXEA-A1Z bash setup.sh
   ```
   
   
2. 执行setup.sh脚本，完成以下步骤（可重复执行）。 
   1. 校验当前环境为lerobot061且LeRobot版本为0.6.x。
   
   2. pip install -e $A1Z_SDK：A1Z SDK（包名a1z，提供CAN 驱动/运动学/动力学）。
   
   3. pip install fashionstar_uart_sdk pyserial：主臂UART伺服SDK（数采用）。
   
   4. pip install -e plugins/teleoperator-stararm102：主臂插件（数采用）。
   
   5. pip install -e plugins/robot-galaxea-a1z ：**从臂插件（云端接入用）。**
   
   6. 自动运行 scripts/verify_install.py 校验导入、ChoiceRegistry注册与CLI实例化路径。
   
   7. 插件**不修改lerobot源码树**：pip包名以lerobot_robot_ 开头即会被LeRobot 0.6.1的register_third_party_plugins() 自动发现，通过@RobotConfig.register_subclass("galaxea_a1z_follower") 注册robot.type。
   
   
   
   
 
#### 安装r2c_sdk到lerobot061环境
机器人侧必须让r2c_sdk与LeRobot运行在**同一个Python 环境**里，hardware.type: lerobot的适配器在运行时需要 import lerobot、draccus并加载第三方插件。因此将r2c_sdk以editable方式装入lerobot061。
执行以下命令，安装r2c_sdk到lerobot061环境。
```
conda activate lerobot061 
cd /path/to/r2c_sdk_python 
pip install -e .
# 依赖自动安装：eclipse-zenoh==1.9.0、protobuf==7.35.1、opencv-python-headless 等
# lerobot / draccus 由 lerobot061 环境已提供，无需重复安装
python -c "from r2c_sdk import ClientConfig, SyncRobotClient; print('r2c_sdk OK')"
```
![](https://support.huaweicloud.com/sdkreference-cloudrobo/public_sys-resources/caution_3.0-zh-cn.png)
r2c_sdk要求Python ≥3.12（requires-python = "\>=3.12"），这是必须用Python 3.12创建环境的原因，不要放宽。
#### 四、CAN总线初始化与硬件链路验证
1. **每次开机后执行一次（需sudo），** 加载gs_usb内核模块（内核缺失时自动insmod预编译gs_usb.ko），把HHS适配器（a8fa:8598）绑定到gs_usb，自动定位USB CAN接口（**不一定叫** **can0，以脚本输出为准** ），以**1 Mbps** 启动。
   
   ```
   cd ~/project/a1z-teleop 
   sudo bash setup_follower_can.sh
   ```
   
   
2. 执行以下命令，验证硬件链路。 
   ```
   # ① 接口状态
   ip -d link show can0          # 应显示 can state ERROR-ACTIVE, bitrate 1000000 
   # ② 给机械臂上电后扫描在线 CAN ID（1-6 = 手臂电机, 7 = 夹爪）
   cd ~/project/a1z-teleop python scripts/scan_can_ids.py can0  
   # ③ 可选：监听 CAN 帧
   candump can0
   ```
   ![](https://support.huaweicloud.com/sdkreference-cloudrobo/public_sys-resources/note_3.0-zh-cn.png)
   接口名不是can0时：所有启动命令均可用CAN=canX环境变量覆盖，机器人配置中的 hardware.config.robot.can_channel也要改成实际接口名。
   
   
 
#### 五、机械臂标定
标定是**关键前置步骤**：记录从臂零位 home_rad、各关节行程范围range_min_rad/range_max_rad 与夹爪行程 grip_min_norm/grip_max_norm。
#### 交互式标定（首次使用必须）
```
conda activate lerobot061 
cd ~/project/a1z-teleop  
# 只标定从臂（云端接入只需从臂；主臂联标见 §10.2）
lerobot-calibrate \    
    --robot.type=galaxea_a1z_follower \    
    --robot.can_channel=can0 \    
    --robot.id=follower_a1z
```
标定流程（交互式，按Enter推进）：
1. 从臂进入柔顺模式（kp=0，可用手推动）。
2. **① 零位**：手动把从臂推到零位姿态（推荐自然操作姿态：臂前伸、肘微弯、夹爪半开），扶稳后按 Enter ------ 记录 home_rad。
3. **② 限位** ：按Enter开始，把**每个关节缓慢转到两端极限**来回扫一遍，扫完按Enter，记录range_min_rad / range_max_rad（与 SDK 硬件限位取交集）。
4. **③ 夹爪**：按Enter开始，把夹爪【完全张开】和【完全闭合】各做一次，按Enter，记录 grip_min_norm / grip_max_norm。
#### 标定文件位置
```
~/.cache/huggingface/lerobot/calibration/robots/galaxea_a1z_follower/follower_a1z.json
```
文件包含home_rad、range_min_rad、range_max_rad、grip_min_norm、grip_max_norm五个字段。机器人配置中robot.id: follower_a1z与robot.calibration_dir: null（默认 HF 缓存目录）即指向此文件。
#### 云端无人值守运行要点
- 云端/无人值守部署**必须提前标定好**，且配置中显式runtime.robot_connect.calibrate: false，否则robot.connect() 检测到缺标定文件时会进入交互式input()标定流程并卡死。
- 采集与推理**同机**时标定文件天然共享，无需重复标定；换臂或零位漂移后需重标。
- teleop_input: rad（云端推理模式）下数学上不依赖home_rad，仅钳到硬件限位，但return_to_zero_on_exit回零仍依赖标定，**建议始终保留标定文件**。
 
#### 六、机器人配置文件详解
以config/robot_a1z_lerobot_v2_config.yaml为基准（v2相对v1的关键变更已写在文件头部注释中）。以下逐段说明。
#### runtime运行参数
```
runtime:
  publish_hz: 15.0                  # 观测发布/动作执行频率 (Hz)，建议 10–30
  max_duration_s: 0.0               # 0 = 一直运行，Ctrl+C 停止
  dry_run: false                    # true = 只发观测不执行动作（安全调试）
  action_response_timeout_s: 5.0    # 发布观测后等待 action 超时 (秒)
  max_enqueue_actions_per_chunk: -1 # 每次 chunk 最多入队步数，-1 = 全部
  enable_action_chunk_alignment: false
  publish_trigger_threshold: 0
  skip_initial_observations: 1      # 启动时跳过首帧观测，让动作队列预填充
  async_request: {enabled: false}   # 异步请求融合（默认关闭）
  keyboard_control: {enabled: true} # 键盘控制（空格/暂停, h/回home, e/退出）
```
- 未写 heartbeat 段时心跳**默认开启**（每 5 s 上报 status: ONLINE, mode: AUTO到 .../state/heartbeats），CloudRobo 平台据此判断设备在线；可按需显式配置heartbeat: {enabled: true, interval_ms: 1000, status: "ONLINE", mode: "AUTO"}。
- **首次接入务必先 dry_run: true** 验证数据流，确认无误后再改回 false。
 
#### hardware：通用LeRobot适配器
```
hardware:
  type: "lerobot"              # r2c_sdk 内置通用适配器 (entry_point 名)
  config:
    runtime:
      robot_connect:
        calibrate: false       # 无人值守必须 false（需已提前标定，见 §6.3）
    robot:
      type: galaxea_a1z_follower   # 插件注册名
      id: follower_a1z             # 标定文件名 = calibration_dir/{id}.json
      calibration_dir: null        # null = 默认 HF 缓存目录
      can_channel: can0            # 按 setup_follower_can.sh 实际输出修改
      gravity_comp_factor: 1.0     # 重力补偿 (0=关, 1=全补偿)
      control_freq_hz: 150         # 150 而非 250：降低 gs_usb CAN 负载
      teleop_input: rad            # 云端动作 = 绝对弧度，钳到硬件限位
      joint_sign: [1,1,1,1,1,1]    # 仅 leader_deg 模式生效；rad 模式不使用
      scale: 1.0                   # 仅 leader_deg 模式生效
      max_step_rad: 0.06           # 每次 setpoint 变化硬上限 (rad)
      max_joint_vel_deg_s: 50.0    # 最大关节速度 (deg/s)
      max_joint_travel_deg: null   # 相对零位 ±N° 软限位；null = 仅标定范围
      return_to_zero_on_exit: true # 退出时平滑回零
      return_speed_deg_s: 25.0
      enable_gripper: true
      gripper_sign: 1              # ★ 必须 +1，见下方说明
      # 以下为独立 MotorB 夹爪驱动遗留参数，SDK 原生夹爪激活时不生效
      gripper_can_id: 7
      gripper_kp: 15.0
      gripper_kd: 0.4
      gripper_max_step_rad: 0.4
      gripper_margin: 0.10
      cameras:
        cam_wrist:            # 腕部相机（键名与 ACT 数据集 observation.images.* 一致）
          type: opencv
          index_or_path: 4    # 对应 /dev/video4，建议改用设备路径防漂移
          width: 640
          height: 480
          fps: 30
        cam_external:         # 头部/全局相机
          type: opencv
          index_or_path: 13   # 对应 /dev/video13（RealSense 515 RGB 最低原生档）
          width: 960
          height: 540
          fps: 30
    commands:
      go_home:
        type: go_home
        joint_names: [joint_1, joint_2, joint_3, joint_4, joint_5, joint_6]
        joints: [...]         # 6 个绝对关节角 (rad)，取自 follower_a1z.json 的 home_rad
        gripper: open
```
关键说明：
- **gripper_sign: +1必须保持**：SDK原生Gripper约定0=闭合，1=张开；插件配置默认 -1 是独立 MotorB 驱动时代的遗留值。若此处用 -1，云端推理的夹爪开合方向会与训练数据相反。
- **相机键名**cam_wrist / cam_external必须与训练数据集的observation.images.cam_wrist / observation.images.cam_external完全一致，否则策略服务（config/cloud_a1z_act_config.yaml）的特征对齐会失败。
- /dev/videoN编号随重启漂移，**推荐使用设备路径**index_or_path: /dev/video13 或/dev/v4l/by-id/...稳定路径。
- go_home 只支持 joints（list + joint_names 或 dict），不支持pose_euler/pose_quat（LeRobot无IK）。
 
#### device_to_r2c：设备观测数据到R2C上行
A1Z get_observation() 输出键：joint_1..joint_6（rad）、gripper（归一化：0=闭合；1=张开）、相机名（RGB ndarray）。
```
device_to_r2c:
  task: A1Z arm teleoperation
  image_encoding: jpeg
  mappings:
    - target_key: "joint_states.names"
      default: ["arm_joint1", ..., "arm_joint6", "gripper"]
    - target_key: "joint_states.position"      # [j1..j6 (rad), gripper (0~1)]
      source_paths: ["joint_1", "joint_2", "joint_3", "joint_4", "joint_5", "joint_6", "gripper"]
    - target_key: "images.color.front"         # R2C 上行通道名
      source_path: "cam_external"
      transforms: [ndarray_to_jpeg]
    - target_key: "images.color.wrist"
      source_path: "cam_wrist"
      transforms: [ndarray_to_jpeg]
```
注意区分两层命名：**设备键名** cam_external/cam_wrist（对齐训练数据集特征），**R2C上行通道名**images.color.front/images.color.wrist。
#### r2c_to_device：云端动作到设备指令
```
r2c_to_device:
  mappings:
    - target: "joint_1"       # 6 个关节：source_index 0..5
      source: "joint_states.position"
      source_index: 0
      required: true
    # ... joint_2 .. joint_6 依次 source_index 1..5
    - target: "gripper"       # 夹爪：source_index 6
      source: "joint_states.position"
      source_index: 6
      required: false         # 云端只发 6 关节时夹爪保持当前位置
```
云端joint_states.position为7元素list：\[j1..j6 (rad), gripper (0\~1)\]。teleop_input: rad模式下插件直接使用绝对弧度，与 gripper_sign: +1 配合，开合方向与训练数据一致。
#### 七、执行r2c_sdk CLI（cloudroboclient）
执行r2c_sdk CLI（cloudroboclient）测试相关配置是否能正常连接机器人。
#### dry_run冒烟测试（不执行动作）
```
conda activate lerobot061
cd /path/to/r2c_sdk_python
python -m r2c_sdk.cloudroboclient \
  --robot-config config/robot_a1z_lerobot_v2_config.yaml \
  --bundle config/配置文件名.zip \
  --log-level DEBUG \
  --duration 30
```
此时将robot_a1z_lerobot_v2_config.yaml 中的runtime.dry_run临时改为true。
预期日志：插件注册成功、RobotConfig 解码成功、观测正常发布、动作以\[DRY_RUN\]打印但不执行。
#### 真实硬件启动
```
# 前置：CAN 已初始化（§5）、机械臂已上电、标定已完成（§6）
# 将 dry_run 改回 false 后：
python -m r2c_sdk.cloudroboclient \
  --robot-config config/robot_a1z_lerobot_v2_config.yaml \
  --bundle config/配置文件名.zip \
  --log-level INFO \
  --log-file /tmp/a1z_r2c.log
```
启动后预期日志：
```
Creating new robot instance from adapter config. Using robot config decoder: _default_robot_config_decoder Building robot instance via lerobot.robots.make_robot_from_config. Adapter connected successfully. Heartbeat auto publish started (interval_ms=5000, ...)
```
此时机械臂进入位置保持模式（重力补偿 + PD），锁定在当前姿态。
#### （可选）观测录制
```
python -m r2c_sdk.cloudroboclient \
  --bundle config/配置文件名.zip \
  --robot-config config/robot_a1z_lerobot_v2_config.yaml \
  --record recordings/a1z_demo.r2cr
```
#### 键盘控制
表4按键功能说明 
| 按键      | 功能                         | 条件    |
|:---|:---|:---|
| Space键  | 暂停/恢复。                     | 任意时刻。 |
| h键      | 回Home位（执行go_home命令）        | 暂停时。  |
| q键      | 优雅退出（回 Home \> 断开连接 \> 退出） | 暂停时。  |
| Ctrl+C键 | 强制终止（退出时按配置平滑回零）           | 任意时刻。 |
   
键盘控制在非TTY终端（部分IDE内嵌终端）可能不响应，请在真实终端运行。
#### 八、接入CloudRobo平台
参照如下步骤接入接入CloudRobo平台。
#### 连接配置（三种方式）
- **方式一：ClientConfig YAML** （推荐，便于版本管理）
  config/client_config.yaml：
  ```
  project_id: "<CloudRobo 平台分配的项目 ID>"
  device_id: "<设备 ID，项目内唯一>"
  client_id: "a1z-001"
  endpoints: ["tcp/<平台 Zenoh Router 地址>:7447"]  # 由平台/管理员提供
  mode: "client"          # client = 仅经 Router 转发；peer = 支持 P2P 直连
  protocol: "zenoh"
  ```
  
  ```
  python -m r2c_sdk.cloudroboclient \
    --client-config config/client_config.yaml \
    --robot-config config/robot_a1z_lerobot_v2_config.yaml
  ```
  
 
- **方式二：显式CLI参数**
  ```
  python -m r2c_sdk.cloudroboclient \
    --project-id "<project-id>" \
    --device-id "<device-id>" \
    --endpoints "tcp/<router-host>:7447" \
    --mode client \
    --robot-config config/robot_a1z_lerobot_v2_config.yaml
  ```
  
- **方式三：Bundle凭证包** （生产环境推荐，含project_id、endpoints、TLS证书）
  ```
  python -m r2c_sdk.cloudroboclient \
    --bundle /path/to/credential_bundle.zip \
    --robot-config config/robot_a1z_lerobot_v2_config.yaml
  ```
  --bundle优先级最高；包含TLS证书时可用--private-key-password / --private-key-password-env / --prompt-password提供私钥密码。
  
#### 平台侧验证
1. **设备在线**：CloudRobo 平台控制台应能看到设备在线（依赖心跳.../state/heartbeats，默认 5 s 一次，可在 config 中调快）。
2. **观测上行**：平台端能看到 .../inference/observations 的关节状态与两路图像。
3. **动作闭环**：策略服务启动后，动作经 .../inference/actions 下发，机械臂开始执行推理轨迹（日志中每步动作 send_action 有 DEBUG 记录）。
4. **弱网/大模型场景**：把 runtime.action_response_timeout_s 调到 ≥30 s，避免超时重发风暴。
 
#### 九、数采安装与配置（a1z-teleop）
数据采集基于 **a1z-teleop** 工程（LeRobot 0.6.1 遥操作方案，**GitHub：git@github.com:xxxxxx/a1z-teleop.git**）：用 Star-Arm-102 主臂（Leader，UART 伺服）驱动作 A1Z 从臂（Follower，CAN 电机），数据以LeRobot v3.0 格式（parquet + 视频）落盘，可直接 lerobot_train 训练。
#### 数采硬件与权限
- 主臂Star-Arm-102：USB（CH340，/dev/ttyUSB0），12V 10A供电；
- 一次性安装串口udev规则（否则每次插拔后权限变回 root:dialout）：
```
sudo bash ~/project/a1z-teleop/setup_leader_uart.sh
```
#### 主从臂联合标定（首次使用必须）
```
cd ~/project/a1z-teleop 
bash calibrate.sh        # LEADER_PORT=/dev/ttyUSB1 CAN=can1 bash calibrate.sh 可覆盖端口
```
依次完成：
1. 从臂标定。
2. 主臂标定：握着主臂摆出**与从臂零位相同的姿态**扶稳按 Enter记录homing_offset_deg，再逐关节扫限位。
标定文件：
```
~/.cache/huggingface/lerobot/calibration/robots/galaxea_a1z_follower/follower_a1z.json   # 从臂 
~/.cache/huggingface/lerobot/calibration/teleoperators/stararm102_leader/leader1.json    # 主臂
```
#### 实时遥操作验证
```
bash scripts/teleop.sh
# 更保守速度: bash scripts/teleop.sh --robot.max_joint_vel_deg_s=20
# Ctrl-C 停止，从臂自动回零
```
先用python scripts/test_teleop.py --dry-run检查各关节方向（观察 "target" 列），
方向反了用--flip N反转并同步到采集命令的 joint_sign。
#### 数据采集（推荐 absolute_rad 模式）
```
cd ~/project/a1z-teleop
REPO_ID=my_user/my_dataset TASK="pick and place" bash scripts/record.sh \
    --teleop.output_mode=absolute_rad \
    --teleop.joint_sign='[-1, 1, 1, 1, -1, -1]' \
    --teleop.gripper_sign=1 \
    --robot.teleop_input=rad \
    --robot.gripper_sign=1 \
    --robot.cameras='{cam_external: {type: opencv, index_or_path: /dev/video13, width: 960, height: 540, fps: 30},
                      cam_wrist:    {type: opencv, index_or_path: /dev/video4,  width: 640, height: 480, fps: 30}}' \
    --dataset.episode_time_s=300 --dataset.reset_time_s=5 --dataset.num_episodes=100
```
- 环境变量：REPO_ID（数据集名）、TASK（任务描述）、EPISODES（默认 10）。
- 操作键：**→（右方向键）** 结束当前 episode，**←（左方向键）** 重录上一个episode，**Esc**停止采集。
- 相机键名 cam_external/cam_wrist 与云端推理配置一致；/dev/video13（RealSense 515 RGB）最低原生档为 960×540（无 640×480 模式），比 1280×720 少约 44% 像素，降低 ACT 训练显存压力。
- 数据保存在本地 \~/.cache/huggingface/lerobot/\<repo_id\>/；加 --dataset.push_to_hub=true可上传Hub。
- 续录已有数据集：追加--resume=true。
**为什么推荐absolute_rad**：
1. action 与 observation.state同坐标系同单位（绝对弧度），策略可利用"恒等先验"（action ≈ 当前状态即保持不动），冷启动稳定、收敛快。
2. 推理侧 teleop_input="rad" 不依赖标定零位，换臂/零位漂移不破坏动作基准。
3. 数据自包含可移植，与主流开源数据集惯例一致。
**前提（务必确认）**：采集前必须完成从臂标定，主臂absolute_rad输出需要读follower_a1z.json的home_rad，文件缺失时只警告并静默退化为相对弧度，录出的数据坐标系错误。joint_sign也必须先用 test_teleop.py --dry-run验证。
#### 数据集结构与训练
```
~/.cache/huggingface/lerobot/<repo_id>/
├── meta/        # info.json (v3.0, fps, 特征定义)、episodes/、tasks.jsonl、stats.json
├── data/        # parquet 帧数据
└── videos/      # 视频帧
```
特征：observation.state（7维：joint_1..joint_6弧度+gripper 归一化）、
action（absolute_rad模式下同为弧度）、observation.images.\*。
ACT训练示例：
```
conda activate lerobot061
cd ~/project/a1z-teleop
lerobot-train \
    --policy.type=act \
    --policy.push_to_hub=false \
    --dataset.repo_id=<repo_id> \
    --output_dir=outputs/train \
    --job_name=act_a1z \
    --steps=100000 --batch_size=16 --num_workers=8 \
    --save_freq=20000 --eval_steps=10000 \
    --wandb.enable=false
```
#### 数采到云端推理衔接要点
表5要点说明 
| 要点       | 数采（record.sh）                                  | 云端推理（v2 config + cloud config）                             |
|:---|:---|:---|
| 动作坐标系    | absolute_rad + teleop_input=rad                | teleop_input: rad（同一插件同一实现）                                |
| 夹爪方向     | --teleop.gripper_sign=1 --robot.gripper_sign=1 | gripper_sign: 1                                            |
| 相机键名     | cam_wrist / cam_external                       | cam_wrist / cam_external（R2C 通道名 images.color.wrist/front） |
| 观测 state | 7维\[j1..j6, gripper\]                          | 7维\[j1..j6, gripper\]                                      |
| 标定文件     | follower_a1z.json                              | follower_a1z.json（rad 模式不依赖零位，但保留用于回零）                     |
   
三者共用同一份插件实现与标定文件，是"数采 \> 训练 \> 云端推理"闭环一致性的保证。
#### 十、端到端上线检查清单
按顺序逐项打勾：
1. 内核 ≥6.8.0-124；Miniforge安装完成。
2. conda 环境 lerobot061（Python 3.12）已创建，LeRobot **0.6.1** + ffmpeg就绪。
3. A1Z SDK、两个插件（bash setup.sh）安装并通过verify_install.py。
4. r2c_sdk pip install -e . 完成，python -c "import r2c_sdk" 通过。
5. CAN 适配器插入 → sudo bash setup_follower_can.sh → ip -d link show 为UP。
6. 机械臂上电 → scan_can_ids.py 能扫到ID 1--7。
7. 从臂标定完成，\~/.cache/huggingface/lerobot/calibration/robots/galaxea_a1z_follower/follower_a1z.json存在。
8. config/robot_a1z_lerobot_v2_config.yaml：can_channel与实际接口一致、calibrate: false、gripper_sign: 1、teleop_input: rad、相机索引/路径正确。
9. dry_run 冒烟通过（观测发布、动作映射打印正常）。
10. client_config.yaml 的 project_id/device_id/endpoints/mode与平台下发一致。
11. 真实启动：平台可见设备在线、观测上行。
12. 云端策略服务启动，动作闭环、机械臂按推理执行。
13. （数采）主臂 udev 权限、联标、record.sh录制1\~2个episode并抽查数据。
 
#### 十一、常见问题
表6常见问题解决方法 
| 常见问题                                                 | 可能原因                                       | 解决方法                                                                                   |
|:---|:---|:---|
| CAN接口未出现/ 无CAN帧                                      | 适配器未插、驱动未加载。                               | sudo bash setup_follower_can.sh；dmesg \| grep gs_usb                                   |
| 电机使能无反馈                                              | 内核过旧。                                      | 升级内核到 ≥6.8.0-124 或按 Galaxea官方指引打补丁。                                                    |
| invalid choice（lerobot CLI 不认识 galaxea_a1z_follower） | 插件未装或环境未激活。                                | conda activate lerobot061 \&\& bash setup.sh；lerobot-calibrate --help \| grep galaxea。 |
| 启动时 Couldn't find a choice class / draccus解码失败       | 插件未注册（第三方插件未自动发现）。                         | 确认pip show lerobot_robot_galaxea_a1z；确认环境内 lerobot为0.6.x。                              |
| import插件报 (unknown location)                         | 同名无 __init__.py目录遮蔽已装包。                    | 检查 PYTHONPATH 是否含空条目导致cwd入路径。                                                          |
| 启动后卡在交互式标定                                           | robot_connect.calibrate未设false或标定文件缺失。     | 先标定（§6.1），再设 calibrate: false。                                                         |
| 夹爪开合方向与训练数据相反                                        | gripper_sign用了遗留默认-1。                      | 改为 +1。                                                                                 |
| 云端动作被钳制/机械臂不动                                        | dry_run: true 未改回；teleop_input 与策略输出坐标系不符。 | 改回 false；确认策略输出为绝对弧度。                                                                  |
| 观测无图像                                                | 相机索引漂移.                                    | v4l2-ctl --list-devices 确认，改用设备路径/dev/videoN或by-id。                                    |
| ModuleNotFoundError: No module named 'a1z'           | A1Z SDK未装入当前环境。                            | A1Z_SDK=/path/to/GALAXEA-A1Z bash setup.sh。                                            |
| 平台显示设备离线                                             | 心跳被禁或网络不通。                                 | 检查runtime.heartbeat配置与 endpoints连通性。                                                   |
| 机械臂下坠/抖动                                             | 重力补偿异常或增益过高。                               | 检查 gravity_comp_factor、max_joint_vel_deg_s，降低kp调试。                                     |
| 键盘控制无响应                                              | 非TTY终端。                                    | 在真实终端中运行。                                                                              |
   
