JoyIn Robot Control
Control JoyIn AI robots through the official OpenAPI. Supports W-1 (Walle) and M-1 (Mini) robots.
Setup
OpenClaw Configuration
Add the following to ~/.openclaw/openclaw.json:
{
"skills": {
"entries": {
"joyin-robot-control": {
"enabled": true,
"apiKey": "YOUR_AUTH_KEY",
"env": {
"JOYIN_API_BASE": "https://api-open-test.joyin-ai.com",
"JOYIN_AUTH_KEY": "YOUR_AUTH_KEY",
"JOYIN_DEVICE_SN": "YOUR_DEVICE_SN",
"JOYIN_DEVICE_TYPE_ID": "3"
}
}
}
}
}
See {baseDir}/openclaw.config.example.json5 for a full template.
Environment Variables
| Variable | Required | Description |
|---|---|---|
JOYIN_API_BASE | Yes | API base URL (test: https://api-open-test.joyin-ai.com) |
JOYIN_AUTH_KEY | Yes | Authorization key (contact JoyIn staff to obtain) |
JOYIN_DEVICE_SN | Yes | Target device serial number |
JOYIN_DEVICE_TYPE_ID | No | 3 for Walle (default), 2 for Mini |
OpenClaw injects these via skills.entries.*.env at agent run time. They are scoped to the run and do not leak into the global shell environment.
Tool
python3 {baseDir}/scripts/robot_cmd.py <command> [options]
Agent Workflow Rules (IMPORTANT)
ALWAYS run preflight before sending any robot command. This checks whether the device is online, its battery level, and current work mode.
Decision flow:
1. Run: python3 {baseDir}/scripts/robot_cmd.py preflight
2. Check the result:
- "ready": false → Tell the user why (offline / OTA / low battery). Do NOT send commands.
- "ready": true, with "note" about current mode → Inform the user, then proceed.
- "ready": true, idle → Proceed with the command.
3. Execute the requested command.
4. Report the result to the user.
State-aware behavior:
| current_status | Meaning | What to do |
|---|---|---|
offline | Device not connected | Tell user. Do not send commands. |
idle | Ready | Proceed normally. |
follow | Following a person | Warn before sending conflicting commands (e.g. remote_control). Use stop first. |
remote_control | Joystick active | Already in RC mode. Can send move commands directly. |
patrol | Patrolling | Warn before interrupting. Use stop first. |
go_charge | Returning to charger | Warn before interrupting. |
guard | Monitoring | Warn before interrupting. |
ota | Firmware updating | Do NOT send any commands. Wait. |
build_map | Building SLAM map | Do NOT interrupt. |
active_action | Performing action | Conflicts with follow. Use stop first if needed. |
Battery rules:
- < 10% and not charging → Suggest
chargecommand before any movement. - < 5% → Refuse movement commands, only allow
chargeandstatus.
Quick Examples
# ALWAYS run preflight check first
python3 {baseDir}/scripts/robot_cmd.py preflight
# Move robot forward
python3 {baseDir}/scripts/robot_cmd.py move --direction forward
# Stop all movement
python3 {baseDir}/scripts/robot_cmd.py stop
# Make robot say something
python3 {baseDir}/scripts/robot_cmd.py tts --text "你好,我是你的机器人助手"
# Check device status (battery, online, charging)
python3 {baseDir}/scripts/robot_cmd.py status
# Get live video stream URL
python3 {baseDir}/scripts/robot_cmd.py live_pull_url
Command Reference
1. Movement — Remote Control
Enter / Exit remote control mode:
python3 {baseDir}/scripts/robot_cmd.py rc_enter
python3 {baseDir}/scripts/robot_cmd.py rc_exit
Chassis movement (8 directions, send continuously at ~100ms interval, robot stops when commands stop):
python3 {baseDir}/scripts/robot_cmd.py move --direction forward
python3 {baseDir}/scripts/robot_cmd.py move --direction backward
python3 {baseDir}/scripts/robot_cmd.py move --direction left
python3 {baseDir}/scripts/robot_cmd.py move --direction right
python3 {baseDir}/scripts/robot_cmd.py move --direction left_up
python3 {baseDir}/scripts/robot_cmd.py move --direction right_up
python3 {baseDir}/scripts/robot_cmd.py move --direction left_down
python3 {baseDir}/scripts/robot_cmd.py move --direction right_down
# Stop chassis movement
python3 {baseDir}/scripts/robot_cmd.py move_stop
Head control (Walle only) — up/down/left/right, send continuously at ~100ms:
python3 {baseDir}/scripts/robot_cmd.py head --direction up
python3 {baseDir}/scripts/robot_cmd.py head --direction down
python3 {baseDir}/scripts/robot_cmd.py head --direction left
python3 {baseDir}/scripts/robot_cmd.py head --direction right
python3 {baseDir}/scripts/robot_cmd.py head --direction stop
Arm control (Walle only) — left_arm or right_arm:
python3 {baseDir}/scripts/robot_cmd.py arm --side left --direction up
python3 {baseDir}/scripts/robot_cmd.py arm --side left --direction down
python3 {baseDir}/scripts/robot_cmd.py arm --side left --direction stop
python3 {baseDir}/scripts/robot_cmd.py arm --side right --direction up
python3 {baseDir}/scripts/robot_cmd.py arm --side right --direction stop
Reset position (Walle only):
python3 {baseDir}/scripts/robot_cmd.py reset --target all # reset all
python3 {baseDir}/scripts/robot_cmd.py reset --target head # reset head only
python3 {baseDir}/scripts/robot_cmd.py reset --target arm # reset arms only
2. Fixed Actions (Mini only)
python3 {baseDir}/scripts/robot_cmd.py car_on # 上车
python3 {baseDir}/scripts/robot_cmd.py car_off # 下车
python3 {baseDir}/scripts/robot_cmd.py standup # 站立
python3 {baseDir}/scripts/robot_cmd.py boot_off # 收脚
python3 {baseDir}/scripts/robot_cmd.py boot_on # 卡脚
python3 {baseDir}/scripts/robot_cmd.py hello # 打招呼
python3 {baseDir}/scripts/robot_cmd.py hello_off # 收手
python3 {baseDir}/scripts/robot_cmd.py head_up # 抬头
python3 {baseDir}/scripts/robot_cmd.py head_down # 回头 (低头)
python3 {baseDir}/scripts/robot_cmd.py charge # 回充电桩
python3 {baseDir}/scripts/robot_cmd.py charge_stop # 停止回充
3. Emergency Stop
python3 {baseDir}/scripts/robot_cmd.py stop # 急停,停止所有移动和功能
4. Voice — TTS
# Play text on device speaker
python3 {baseDir}/scripts/robot_cmd.py tts --text "你好世界"
# Play text then close microphone (keep_silent=1)
python3 {baseDir}/scripts/robot_cmd.py tts --text "请安静" --keep-silent
5. Device Status & Preflight
# Pre-flight check (ALWAYS run this before any command)
python3 {baseDir}/scripts/robot_cmd.py preflight
# Returns: ready (bool), current_status, battery, is_charging, issues[], suggestion
# Get raw device status
python3 {baseDir}/scripts/robot_cmd.py status
Preflight response example (ready):
{
"ready": true,
"current_status": "idle",
"current_status_name": "空闲",
"battery": 85,
"is_charging": false,
"note": "Device is online and idle. Ready to accept commands."
}
Preflight response example (not ready):
{
"ready": false,
"current_status": "offline",
"battery": -1,
"issues": ["Device is OFFLINE — cannot accept commands"],
"suggestion": "Device is OFFLINE — cannot accept commands"
}
6. Live Video
# Start push stream from device camera
python3 {baseDir}/scripts/robot_cmd.py live_push --status 1
# Stop push stream
python3 {baseDir}/scripts/robot_cmd.py live_push --status 0
# Get pull stream URL (HLS/RTMP)
python3 {baseDir}/scripts/robot_cmd.py live_pull_url
# Get push URL
python3 {baseDir}/scripts/robot_cmd.py live_push_url
7. ASR Result
# Get the robot's latest speech recognition result
python3 {baseDir}/scripts/robot_cmd.py asr_result
8. WiFi Configuration
# Configure robot WiFi (base64-encoded SSID and password)
python3 {baseDir}/scripts/robot_cmd.py wifi --ssid "MyWiFi" --password "12345678"
9. LLM Configuration (register your own model)
# Register a custom LLM
python3 {baseDir}/scripts/robot_cmd.py llm_register --name "My GPT" --base-url "https://api.openai.com/v1" --api-key "sk-xxx" --model "gpt-4"
# List registered LLMs
python3 {baseDir}/scripts/robot_cmd.py llm_list
# Update a registered LLM
python3 {baseDir}/scripts/robot_cmd.py llm_update --id 123 --model "gpt-4o"
10. Agent Configuration
# Create an agent with a registered LLM
python3 {baseDir}/scripts/robot_cmd.py agent_create --name "My Agent" --llm-id 123
# List agents
python3 {baseDir}/scripts/robot_cmd.py agent_list
# Update agent
python3 {baseDir}/scripts/robot_cmd.py agent_update --id 123 --name "New Name"
# Bind agent to a device
python3 {baseDir}/scripts/robot_cmd.py agent_bind --agent-id 123
# Query device's bound agent
python3 {baseDir}/scripts/robot_cmd.py agent_query
# Reset device to default JoyIn agent
python3 {baseDir}/scripts/robot_cmd.py agent_reset
Device Types
| Type ID | Model | Codename | Key Capabilities |
|---|---|---|---|
| 3 | W-1 (Walle) | walle | Chassis + head + arm control, 8-direction joystick, position reset |
| 2 | M-1 (Mini) | mini | Chassis control, fixed body actions (standup/car/hello/head), charging |
API Protocol
- Base URL:
https://api-open-test.joyin-ai.com(test) - Auth: All requests carry 3 headers —
Authorization,Device-Sn,Device-Type-Id - Robot commands:
POST /v1/device/interaction/cmdwith body{"cmd_type":"...","status":"...","name":"...","data":{...}} - Response format:
{"code": 200, "msg": "success", "data": {...}}
Important Notes
- The device must be online for commands to work.
- Joystick commands (move/head/arm) need to be sent continuously at ~100ms intervals. The robot stops automatically when commands stop arriving.
keep_silent=1on TTS means the microphone will be closed after playback.- Some APIs (LLM config, Agent config) are marked as "开发中" and may not be fully available.