# Huawei Cloud Cloudrobo R2c

> Run the R2C (Robot-to-Cloud) data-plane client — start the robot-side edge client (Zenoh pub/sub with mTLS credential bundle, hardware adapter, translator, control loop). The credential bundle is produced by the robot skill's export-certificate command. This skill does NOT cover robot registration or certificate export (use the robot skill). Triggers include: r2c client, robot edge client, Zenoh, mTLS, credential bundle, hardware adapter, robot config, dry_run, observation recording, custom adapter, robot-to-cloud, R2C客户端, 硬件适配器, 机器人配置, 凭证包.

- Skill: `huaweicloud/huawei-cloud-cloudrobo-r2c` (Agent Skill, multi-file: 11 files)
- Install (CLI): `npx skillmds@latest add huaweicloud/huawei-cloud-cloudrobo-r2c`
- Raw SKILL.md: https://api.skillmd.com/api/skills/huaweicloud/huawei-cloud-cloudrobo-r2c/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: huaweicloud (https://skillmd.com/u/huaweicloud)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/huaweicloud/huawei-cloud-cloudrobo-r2c

---


> **Windows / PowerShell:** Examples use bash syntax. To run on Windows PowerShell:
> - Flatten `\` line continuations to a single line, or end lines with a backtick.
> - Set env vars with `$env:NAME="value"` instead of `export NAME="value"`.
> - Single-quoted JSON `'{"a":"b"}'` works as-is.

## Overview 概述

The `cloudrobo-r2c` skill operates the R2C (Robot-to-Cloud) data-plane SDK. Unlike other
cloudrobo skills that call REST APIs via `cloudrobo-service`, this skill runs **long-lived
data-plane processes** that use Zenoh pub/sub with Protobuf serialization and mTLS
authentication. It covers one CLI command: `r2c client` (robot edge client).

**Applicable scenarios:**

- **Robot edge client** — Start the robot-side process that bridges physical hardware to the
  cloud via Zenoh. Reads sensor observations from a hardware adapter, translates to R2C
  Protobuf messages, publishes to Zenoh, subscribes to cloud actions, translates back, and
  executes on hardware.
- **Custom adapter development** — Guide developers through implementing custom
  `IRobotHardwareAdapter` classes and `ConfigurableDeviceTranslator` mappings for robots
  not in the built-in adapter list.

**Architecture:**

```text
                          Zenoh pub/sub (mTLS)
  ┌─────────────┐  observations  ┌──────────────────┐
  │ Robot Edge  │ ─────────────► │                  │
  │ Client      │                │  Zenoh Router    │
  │ (r2c client)│ ◄───────────── │                  │
  └──────┬──────┘     actions    └──────────────────┘
         │
  ┌──────▼──────┐
  │ Hardware     │
  │ Adapter      │
  │ (robot arm,  │
  │  gripper...) │
  └─────────────┘

  Credential Bundle (from robot skill export-certificate)
  ├── device_info.json   (account_id, robot_id, permission_role)
  ├── zenoh.json         (mode, endpoints, mTLS config)
  ├── ca.pem             (CA certificate)
  ├── server_cert.pem    (client certificate — note: named server_cert.pem in the exported bundle)
  └── server_key.pem     (private key, optionally encrypted)
```
> `--bundle` accepts the access-config **zip directly** (or an extracted directory); the SDK resolves
> the certificate paths inside `zenoh.json` (which references a `certs/`-style layout) automatically.
> Do not manually rename the cert files.

The R2C data plane is decoupled from the CloudRobo REST API. The platform's `cloudrobo-service`
handles robot registration and certificate export (covered by the `robot` skill); the R2C
SDK consumes the exported credential bundle to establish mTLS-authenticated Zenoh sessions.

## Prerequisites 前置条件

- See `references/cli-installation-guide.md` for CLI installation, R2C package extras, and
  credential bundle preparation.
- A valid **credential bundle** — produced by `cloudrobo robot export-certificate` (robot skill).
  The bundle contains `device_info.json`, `zenoh.json`, `ca.pem`, `server_cert.pem`, and
  `server_key.pem`.
- A **robot config YAML** — defines the hardware adapter, translator, and device-to-R2C
  field mappings.
- The robot must be **registered** on the CloudRobo platform (use the `robot` skill: create →
  export-certificate). The `robot_id` in the credential bundle identifies the robot.

## Workflow 工作流

### Robot Edge Client Startup Workflow 机器人边缘客户端启动

Scenario: "Start the R2C client on the robot to stream observations and execute cloud actions."

1. **Start the client** — Launch the edge client with the credential bundle and robot config.
   `export-certificate` writes `cert_config_<robot-name>_<timestamp>.zip` into the output
   **directory** — pass that zip path to `--bundle`:
   ```bash
   cloudrobo r2c client --bundle <path/to/cert_config_*.zip> --robot-config config/robot_dummy_config.yaml
   ```
   If the private key is encrypted, you will be prompted for a password (or use
   `--private-key-password` / `--private-key-password-env`).
2. **Verify connection** — Check log output for "Heartbeat auto publish started" and
   "Starting cloudroboclient" messages. The client publishes observations and subscribes to
   actions in a control loop.
3. **Stop** — Press Ctrl+C for graceful shutdown (hardware disconnect → session close).

### Dry-Run Testing Workflow 干运行测试

Scenario: "Test the R2C client without moving the real robot."

1. **Set dry_run** — In the robot config YAML, set `runtime.dry_run: true`. This publishes
   real observations but does not execute received actions (logs only).
2. **Start client** — Launch with the dummy adapter or real hardware:
   ```bash
   cloudrobo r2c client --bundle <bundle> --robot-config config/robot_dummy_config.yaml
   ```
3. **Verify observation publishing** — Check logs for observation publish events. On the
   cloud side, verify observations are received.
4. **Test action receiving** — From the cloud adapter or a test publisher, send a test action.
   Verify the action is logged but not executed (dry_run mode).
5. **Disable dry_run** — Set `runtime.dry_run: false` and restart for real execution.

### Custom Adapter Development Workflow 自定义适配器开发

Scenario: "My robot is not in the built-in adapter list. How do I add support?"

The R2C SDK provides two approaches for custom adapters: **entry_point registration**
(recommended for reusable, shareable adapters) and **CLI override** (for quick prototyping).

**Approach A: Entry-Point Registration (Recommended) 入口点注册（推荐）**

1. **Review the guide** — See `references/custom-adapter-guide.md` for the full development guide.
2. **Implement adapter class** — Create a class implementing `IRobotHardwareAdapter`
   (`connect()`, `disconnect()`, `get_observation()`, `send_action()`).
3. **Implement factory function** — Create a factory function that returns an adapter instance:
   `def create_my_adapter(config, **kwargs) -> IRobotHardwareAdapter`.
4. **Register via entry_point** — In your package's `pyproject.toml`, register under
   `[project.entry-points."r2c_sdk.adapters"]`: `my_robot = "my_adapter_module:create_my_adapter"`.
5. **Install package** — `pip install .` registers the adapter under the
   `r2c_sdk.adapters` entry-point group, making it discoverable by the SDK's
   `AdapterRegistry` (used by `RobotFactory` and robot-config schema validation).
6. **Configure** — Set `hardware.type: "my_robot"` (matching the entry_point name) in the
   robot config YAML. No `--hardware-class` CLI override needed.
7. **Optionally register commands** — Use `register_command_class()` in `__post_init__` for
   custom commands (e.g., `go_home`), then reference them in `hardware.config.commands` in
   the robot config.
8. **Configure translator** — Use `ConfigurableDeviceTranslator` with `device_to_r2c` and
   `r2c_to_device` mapping sections in the robot config YAML.
9. **Test with dry_run** — Validate config → start client with `dry_run: true` → verify
   observation publishing and action logging.
10. **Test real execution** — Disable dry_run and verify the robot moves correctly.

**Approach B: CLI Override (Quick Prototyping) CLI 覆盖（快速原型）**

1. **Implement adapter class** — Same as above, but no entry_point registration needed.
2. **Configure** — Set `hardware.type: "custom"` and `hardware.class_path` to the dotted
   import path of your adapter class in the robot config YAML. Alternatively, use
   `--hardware-class my_pkg.my_module.MyAdapter` on the CLI.
3. **Test with dry_run** — Validate config → start client with `dry_run: true` → verify
   observation publishing and action logging.
4. **Test real execution** — Disable dry_run and verify the robot moves correctly.

> **When to use which:** Use entry_point registration when the adapter will be reused across
> projects or shared with other teams. Use CLI override for one-off testing or when you
> cannot create a separate package.

### Observation Recording Workflow 观测录制

Scenario: "Record observations for later playback analysis."

1. **Start with --record** — `cloudrobo r2c client --bundle <bundle> --robot-config <config> --record ./observations.pkl`
2. **Operate** — Run the robot normally; observations are serialized to the `.pkl` file.
3. **Playback** — Use the `playback` adapter type with the recorded file for replay.

## CLI Command Format Standard CLI命令格式标准

```bash
cloudrobo r2c client [OPTIONS]
```

| Feature | Description | Example |
|---------|-------------|---------|
| Command group | `r2c` (registered via entry point) | `cloudrobo r2c` |
| Subcommand | `client` | `cloudrobo r2c client` |
| Credential bundle | `--bundle <path>` (zip or directory, recommended) | `--bundle ./cert.zip` |
| Client config | `--client-config <path>` (default `config/client_config.yaml`) | alternative to `--bundle` |
| Robot config | `--robot-config <path>` (default `config/robot_dummy_config.yaml`) | `--robot-config config/robot_jaka_sdk_config.yaml` |
| Endpoints | `--endpoints tls/127.0.0.1:7447` (comma-separated) | Zenoh router address |
| Output format | Log output to stdout/stderr | structured logging |
| Long-running | Runs until Ctrl+C or `--duration` | `--duration 60` |

## Core Commands 核心命令

### Start Robot Edge Client

```bash
cloudrobo r2c client --bundle <path/to/cert_config_*.zip> --robot-config config/robot_dummy_config.yaml [--client-config config/client_config.yaml] [--duration 0] [--log-level INFO] [--log-file ./r2c.log] [--record ./observations.pkl] [--hardware-class my_pkg.my_module.MyAdapter] [--translator-class my_pkg.my_module.MyTranslator] [--private-key-password <password>] [--private-key-password-env <ENV_VAR>] [--no-prompt-password]
```

Alternative (without bundle, using client config + explicit parameters):

```bash
cloudrobo r2c client --client-config config/client_config.yaml --project-id <project-id> --device-id <device-id> --endpoints tls/127.0.0.1:7447 --mode peer --robot-config config/robot_dummy_config.yaml
```

**Connection priority:** `--bundle` (recommended) > `--client-config` > explicit CLI params
(requires `--project-id` and `--device-id`).

**Lifecycle:** `load_yaml(robot_config)` → `build_session(args)` →
`_maybe_start_heartbeats(session, robot_config)` → `build_sync_robot_client(...)` →
`hardware_adapter.connect()` → `robot_client.start()` → wait (duration or Ctrl+C) →
`robot_client.stop()` → `hardware_adapter.disconnect()` → `session.close()`.

| Parameter | Default | Description |
|-----------|---------|-------------|
| `--bundle` | None | Path to credential bundle zip/dir (recommended; supersedes client-config) |
| `--client-config` | `config/client_config.yaml` | Path to R2C client config YAML |
| `--project-id` | None | Project ID (required if no bundle and no client-config) |
| `--device-id` | None | Device ID (required if no bundle and no client-config) |
| `--client-id` | None | Client ID (defaults to `sync-robot-client`) |
| `--endpoints` | `""` | Comma-separated Zenoh endpoints, e.g. `tls/127.0.0.1:7447` |
| `--mode` | `peer` | Zenoh mode: `peer` or `client` |
| `--endpoint-role` | None | `connect` (active, default) or `listen` (passive) |
| `--robot-config` | `config/robot_dummy_config.yaml` | Path to robot config YAML |
| `--hardware-class` | None | Dotted class path for custom IRobotHardwareAdapter |
| `--translator-class` | None | Dotted class path for custom IDeviceTranslator |
| `--duration` | `0.0` | Run duration in seconds; 0 = run forever |
| `--log-level` | `INFO` | Logging level: CRITICAL/ERROR/WARNING/INFO/DEBUG/NOTSET |
| `--log-file` | None | Rotating log file path (100 MB max, 5 backups) |
| `--record` | None | Path to save recorded observations (.pkl) |
| `--private-key-password` | None | Password for encrypted server_key.pem |
| `--private-key-password-env` | None | Environment variable name holding the password |
| `--prompt-password` | True (default) | Prompt for password only when encrypted key detected |
| `--no-prompt-password` | False | Never prompt; fail if password required |

### Built-in Hardware Adapters

The following hardware adapter types are registered via `r2c_sdk.adapters` entry points
and can be used by setting `hardware.type` in the robot config YAML:

| Adapter | Description |
|---------|-------------|
| `dummy` | Simulated robot for testing and development |
| `a1z` | A1Z + G1Z gripper (6-DOF arm, GALAXEA-A1Z SDK via SocketCAN) |
| `lerobot` | LeRobot-compatible robots (SO-101, etc.) |
| `ros2` | ROS 2 based robots |
| `raw_sdk` | Vendor SDK via VendorSDKHardwareAdapter |
| `jaka` | Jaka robotic arms |
| `ur5e_rtde` | Universal Robots UR5e via RTDE |
| `zenoh_ros1` | ROS 1 robots via Zenoh bridge |
| `flexiv` | Flexiv robotic arms |
| `playback` | Replay recorded observations |
| `moz1` | MOZ1 robot |
| `q25` | Q25 robot (direct SDK) |
| `q25_ros2` | Q25 robot via ROS 2 |
| `tsd` | TSD robot |

The `a1z` adapter is registered in `pyproject.toml` but requires the `[a1z]` extra
(`python-can`, `pin`) and the GALAXEA-A1Z SDK. Installing `cloudrobo-r2c[all]` includes it.

Custom adapters can also be loaded via `--hardware-class` (dotted import path) or
`hardware.type: "custom"` + `hardware.class_path` in the robot config.
See `references/custom-adapter-guide.md` for details.

## Parameter Confirmation 参数确认

| Parameter | Source | Required | Confirmation Needed |
|-----------|--------|----------|---------------------|
| `--bundle` | User (from robot skill export-certificate) | Yes (recommended) | Verify file exists and is readable |
| `--robot-config` | User | Yes | Ensure YAML is valid before starting |
| `--client-config` | User | No (fallback to bundle) | — |
| `--project-id` / `--device-id` | User | Yes (if no bundle) | Verify against platform registration |
| `--endpoints` | User or bundle | No (from bundle) | Verify Zenoh router is reachable |
| `--hardware-class` | User | No | Verify class implements IRobotHardwareAdapter |
| `--duration` | User | No | 0 = run forever; set a value for timed tests |
| `--record` | User | No | Ensure output path is writable |
| `--private-key-password` | User | No (only if key encrypted) | Masked; never echo back |

**Starting the client is a long-running, externally visible operation.**
Confirm the credential bundle, robot config, and endpoint reachability before launching.

## Reference Documents 参考文档

- [CLI Installation Guide](references/cli-installation-guide.md) — cloudrobo CLI installation, R2C package extras, credential bundle preparation
- [Authentication & Access Control](references/iam-policies.md) — mTLS credential bundle model, Zenoh security
- [Dataflow Diagram](references/dataflow-diagram.md) — Mermaid data flow diagrams for R2C data plane
- [Verification Method](references/verification-method.md) — Verification method details
- [Acceptance Criteria](references/acceptance-criteria.md) — Acceptance criteria
- [Client Config Reference](references/client-config-catalog.md) — client_config.yaml field mapping, Zenoh QoS settings
- [Robot Config Reference](references/robot-config-catalog.md) — Robot config YAML schema (v2.1), hardware/translator/mapping sections
- [Custom Adapter Guide](references/custom-adapter-guide.md) — IRobotHardwareAdapter interface, ConfigurableDeviceTranslator, dry_run testing

## Edge Cases 边界情况

| Scenario | Handling |
|----------|----------|
| Missing credential bundle | Client fails with error; use `cloudrobo robot export-certificate` to produce one |
| Encrypted private key | Prompt for password (default), or use `--private-key-password` / `--private-key-password-env`; `--no-prompt-password` fails if password required |
| Invalid robot config | Client startup fails with `ValidationError` details listing all schema errors |
| Unknown hardware adapter type | Use `custom` type with `--hardware-class` for unlisted robots; see built-in adapters list above |
| Third-party adapter not found after install | Verify entry_point is registered in `pyproject.toml` under `[project.entry-points."r2c_sdk.adapters"]`; reinstall with `pip install -e .` |
| Zenoh connection failure | Client fails with `R2CConnectionError`; check endpoints, TLS certificates, and network |
| dry_run mode | Observations are published normally; received actions are logged but not executed on hardware |
| Duration 0 | Client runs indefinitely until Ctrl+C or process termination |
| Robot config missing required fields | Client startup fails with `ValidationError` for missing `hardware.type`, `translator.type`, or mapping sections |
| Heartbeat disabled | Set `runtime.heartbeat.enabled: false` in robot config; no heartbeat messages sent |
| Observation recording | `--record` path must be writable; observations saved as `.pkl` (pickle format) |
| Config directory resolution | `_config_dir` is injected into robot_config for relative path resolution (e.g., custom adapter modules) |
| Keyboard control | Enabled via `runtime.keyboard_control.enabled: true`; space=pause/resume, h=go_home (when paused), e=graceful exit |
| Action timeout | `runtime.action_response_timeout_s` controls wait time; backoff configured via `_initial_s` and `_backoff` |
| Action chunk alignment | `runtime.enable_action_chunk_alignment` prevents trajectory jumps; default false |
| Async request fusion | `runtime.async_request` configures observation fusion strategy (replace/weighted_average/nearest_neighbor) |
| Cross-skill dependency | This skill depends on the `robot` skill for credential bundle production; it does not call the robot skill directly |
| API paths | This skill does not call REST APIs; it uses Zenoh pub/sub with Protobuf serialization |
| Mutating operations | Starting `r2c client` is a long-running process; confirm parameters before launch |
| `obs://` paths | Not applicable to this skill; R2C uses Zenoh topics, not object storage |

## Verification Method 验证方法

### Specification Compliance Verification 规范合规验证

```bash
bash scripts/test-cli-commands.sh
```

### Functional Testing 功能测试

```bash
# CLI (optionally scope workspace tests: bash scripts/test-cli-commands.sh -w <workspace-id>)
bash scripts/test-cli-commands.sh
```

### Test Cases 测试用例

See `templates/test-vars.json` for the full test case list covering client startup, dry_run scenarios, and observation recording.

### Verification Checklist 验证清单

- `r2c client` with `--bundle` and a valid robot config starts and logs heartbeat/connection messages
- `r2c client` with `dry_run: true` publishes observations but does not execute actions
- Encrypted private key triggers password prompt (or fails with `--no-prompt-password`)
- `--duration N` stops the client after N seconds
- `--record` produces a non-empty `.pkl` file
- `--log-file` produces a rotating log file

## Best Practices 最佳实践

- Verify your robot config YAML is valid before starting the client to catch configuration errors early
- Use `--bundle` (recommended) instead of explicit `--project-id`/`--device-id` for simpler setup
- Refer to the built-in adapters list above to identify which robot types are supported
- Start with `dry_run: true` to verify observation publishing without risking robot movement
- Use the `dummy` adapter for development and testing when real hardware is unavailable
- Set `--duration` for timed tests instead of running indefinitely during development
- Use `--log-level DEBUG` and `--log-file` for detailed troubleshooting
- Use `--private-key-password-env` instead of `--private-key-password` to avoid secrets in shell history
- For custom adapters, implement all four `IRobotHardwareAdapter` methods and test with `dry_run` first
- Use `ConfigurableDeviceTranslator` (config-driven mapping) instead of writing a custom translator class when possible
- Record observations with `--record` for offline analysis and playback testing
- Keep heartbeat enabled (default) for connection health monitoring; disable only for debugging
- The credential bundle is produced by the `robot` skill — do not attempt to create one manually

