LimX Luna SDK Development Guide

LunaSeptember 18, 2026Download PDFDownload Markdown
Version Date Description of Changes Remarks
V1.0 2026-08-26 Initial Release

1 SDK Introduction

1.1 High-Level Application Protocol Interface

1.1.1 Overview

The robot receives user request commands through the WebSocket communication port 5000, such as making the robot stand up, squat down, walk, etc. WebSocket is a real-time communication protocol that establishes a persistent connection between the robot and the user端 for fast and efficient transmission of control information and data.

1.1.2 Communication Protocol Format

When the robot receives commands from the client via WebSocket, data is transmitted using the JSON communication protocol. This approach offers significant advantages: WebSocket is a full-duplex communication protocol that establishes a real-time, low-latency connection between the client and server, particularly suitable for frequently interacting application scenarios. The JSON data protocol, with its concise and highly readable structure, ensures intuitive and clear data transmission, with cross-platform and cross-language compatibility. The combination of WebSocket and JSON is not only programming language-agnostic and applicable to various devices and systems, but also improves development flexibility and maintenance convenience.

  • The request data format contains the following fields:

    • accid: The robot's unique serial number, identifying its unique identity;
    • title: The command name, prefixed with "request_";
    • timestamp: The timestamp when the command is sent, in milliseconds;
    • guid: A unique command identifier used to distinguish different request commands. For synchronous interfaces, the guid value must be returned to the client in the "response_xxx" response message. After receiving the response message, the client can determine whether the command has been executed by comparing whether the guid value matches the value in the request command;
    • data: Contains the content of the request. Depending on specific requirements, it may include multiple sub-fields to store the data required by the request command, such as parameters for executing actions, text content for sending messages, etc.;
    • Example:
    {
      "accid": "HU_D02_001", # Robot's unique serial number, identifying its unique identity
      "title": "request_xxx",   # Command name, prefixed with "request_"
      "timestamp": 1672373633989, # Timestamp when the command is sent, in milliseconds
      "guid": "746d937cd8094f6a98c9577aaf213d98", # Unique command identifier, used to distinguish different request commands
      "data": {}  # Contains the content of the request command
    }
    
  • The response data format contains the following fields:

    • accid: The robot's unique serial number, identifying its unique identity;
    • title: The command name, prefixed with "response_";
    • timestamp: The timestamp when the command is sent, in milliseconds;
    • guid: Same as the guid value of the corresponding request command;
    • data: Should contain at least one "result" sub-field, used to store the execution result data of the request command. If needed, it may also include other sub-fields, such as error codes, error messages, and other information describing the operation result;
    • Example:
    {
      "accid": "HU_D02_001",   # Robot's unique serial number, identifying its unique identity
      "title": "response_xxx",  # Command name, prefixed with "response_"
      "timestamp": 1672373633989, # Timestamp when the command is sent, in milliseconds
      "guid": "746d937cd8094f6a98c9577aaf213d98", # Same as the guid value of the corresponding request command
      "data": { # Contains the specific data content of the response command
        "result": "success"  # "result" stores whether the request command was processed successfully, its value is: "success or fail_xxx"
      }
    }
    
  • Message Push: This is the process by which the robot proactively sends information to the client. This information can include the robot's serial number, current running status, executed operations, and other data. By promptly sending this information to the client, the robot can help the client better understand its working status, thereby better utilizing the services it provides. Its data format contains the following fields:

    • accid: The robot's unique serial number, identifying its unique identity;
    • title: The command name, prefixed with "notify_";
    • timestamp: The timestamp when the message is sent, in milliseconds;
    • guid: The guid value of the message, uniquely identifying this message;
    • data: Contains the message data content. Depending on specific requirements, it may include multiple sub-fields to store the data required by the request command;
    • Example:
    {
      "accid": "HU_D02_001",   # Robot's unique serial number, identifying its unique identity
      "title": "notify_xxx",  # Message name, prefixed with "notify_"
      "timestamp": 1672373633989, # Timestamp when the message is sent, in milliseconds
      "guid": "746d937cd8094f6a98c9577aaf213d98", # The guid value of the message, uniquely identifying this message
      "data": { } # Contains the message data content
    }
    

1.1.3 Communication Testing Method

Postman is a popular API development environment that can be used to test WebSocket interfaces. To test WebSocket interfaces using Postman, follow these steps:

  • Install Postman, download address: https://www.postman.com/downloads/?utm_source=postman-home;

  • Open Postman and create a WebSocket request;

  • Connect to the robot's wireless network

    • After the robot is powered on, use your personal computer to connect to the robot's Wi-Fi, the name format is usually "HU_D02_xxx"
    • Enter the Wi-Fi password: 12345678
  • Enter the WebSocket interface address in the request URL, for example, "ws://10.192.1.2:5000";

  • In "Message", enter the command request to be sent;

  • Click the "Send" button to send the request command;

  • After sending the command, you can receive the response message from the server. Use Postman's response window to view the data returned by the server and check whether it meets the expected result.

    图片展示的是Luna SDK开发指南中通信测试方法中使用Postman进行WebSocket请求的界面。界面上方显示“ws://10.192.1.2:5000 - My Workspace”。左侧有“Collections”“Environments”“History”等选项卡,当前选中“History”。中间部分显示了多个WebSocket连接记录,如“ws://10.192.1.2:5000”等。下方“Message”区域有“send”“params”“headers”“settings”等输入框,以及“JSON”“All”选项卡。底部“Response”区域展示了返回的JSON数据,有“Search”“Received Messages”“Clear Messages”等按钮。

1.2 Basic Function Protocol Interfaces

1.2.1 Set Audio Prompt Language

1.2.1.1 Request: request_set_audio_prompts_language

This protocol is used to set the robot's audio prompt language. After a successful request, the robot's subsequent voice prompts will use the specified language, and a switching confirmation prompt will be played to help the user confirm that the setting has taken effect. Request parameter, language values:

language Meaning User Perception
cn Chinese audio prompt Subsequent prompts use Chinese, and a Chinese switching confirmation prompt is played
en English audio prompt Subsequent prompts use English, and an English switching confirmation prompt is played
{
  "accid": "HU_D04_01_001",
  "title": "request_set_audio_prompts_language",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
    "language": "cn"
  }
}
1.2.1.2 Response: response_set_audio_prompts_language
{
  "accid": "HU_D04_01_001",
  "title": "response_set_audio_prompts_language",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
    "result": "success"
  }
}
1.2.1.2.1 result Values
result Meaning User Prompt Suggestion
success Setting successful Audio prompt language has been switched
fail_no_language Target language not provided Please select an audio prompt language
fail_invalid_language Language value not supported Currently only Chinese and English are supported
fail_write_robot_info Failed to save setting Setting failed, please try again later
fail_play_audio_prompt_service_not_ready Audio function not ready Audio function not ready, please try again later
fail_play_audio_prompt_call Switching confirmation prompt request failed Switching confirmation failed, please retry
fail_play_audio_prompt Switching confirmation prompt playback failed Confirmation prompt not heard, please retry
1.2.1.3 Message Push: none

1.2.2 Connect to Wi-Fi Hotspot

1.2.2.1 Request: request_connect_wifi

This protocol is used to send a request to the robot router, instructing the router to connect to a Wi-Fi hotspot with the specified SSID and return the connection result.

{
  "accid": "HU_D04_01_001",
  "title": "request_connect_wifi",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": { 
      "wifi_band": 0,  # Wi-Fi band: 0=5GHz, 1=2.4GHz
      "wifi_ssid": "Limx-Guests",  # Target Wi-Fi SSID (Wi-Fi name), case-sensitive, must match the actual hotspot
      "wifi_password": "LimX2024",  # Target Wi-Fi password, password for WPA2-PSK encrypted network
      "router_admin_password": "12345678"  # Robot router administrator password
  }
}
1.2.2.2 Response: response_connect_wifi
{
  "accid": "HU_D04_01_001",
  "title": "response_connect_wifi",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
      "result": "success"  # success
                           # fail_no_wifi_band: Wi-Fi band not specified
                           # fail_no_wifi_ssid: SSID not specified
                           # fail_no_wifi_password: password not specified
                           # fail_no_router_admin_password: administrator password not specified
  }
}

1.2.3 Query Wi-Fi Connection Status

1.2.3.1 Request: request_wifi_connection_status

This protocol is used by the client to send a Wi-Fi connection status query request to the robot router. After receiving the request, the router feeds back the core status information of the currently connected Wi-Fi, including the associated SSID, signal strength, and connection result, supporting the client in real-time perception of the device's network connection status. The client initiating a Wi-Fi connection status query must carry the robot router administrator password to complete identity verification.

{
  "accid": "HU_D04_01_001",
  "title": "request_wifi_connection_status",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
      "router_admin_password": "12345678"  # Robot router administrator password
  }
}
1.2.3.2 Response: response_wifi_connection_status

After receiving the query request, the robot router returns the current actual Wi-Fi connection status for client-side parsing, display, or subsequent business processing.

{
  "accid": "HU_D04_01_001",
  "title": "response_wifi_connection_status",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
      "ssid": "Limx-Guests",
      "signal": -56,        # Unit: dBm
      "result": "success"   # success
                            # fail_disconnected
  }
}

1.2.4 Enter Ready State

The robot slowly assumes a ready posture.

1.2.4.1 Request: request_prepare

Controls the robot to enter a standing state.

{
  "accid": "HU_D04_01_001",
  "title": "request_prepare",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": { }
}
1.2.4.2 Response: response_prepare
{
  "accid": "HU_D04_01_001",
  "title": "response_prepare",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
      "result": "success"  # success, fail_motor: motor error
  }
}

1.2.5 Control Robot Walking

1.2.5.1 Enter Walking Mode

The robot enters walking mode and can receive velocity commands.

1.2.5.2 Request: request_set_walk_mode
{
  "accid": "HU_D04_01_001",
  "title": "request_set_walk_mode",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {}
}
1.2.5.3 Response: response_set_walk_mode
{
  "accid": "HU_D04_01_001",
  "title": "response_set_walk_mode",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
      "result": "success"  # success, fail_motor: motor error
  }
}

1.2.6 Control Robot Walking

In mobile operation mode, control the robot to walk through this protocol (requires > 10 Hz command issuance). Please note that in whole-body operation mode, this protocol interface is invalid.

1.2.6.1 Request: request_set_walk_vel
{
  "accid": "HU_D04_01_001",
  "title": "request_set_walk_vel",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
    "x": 0.0,   #  Forward/backward velocity ratio, value range [-1, 1]
    "y": 0.0,   #  Lateral walking velocity ratio, value range [-1, 1]
    "yaw": 0.0  #  Rotational angular velocity ratio, value range [-1, 1]
  }
}
1.2.6.2 Response: response_set_walk_vel

This message is returned when command execution fails; no response is returned on successful execution.

{
  "accid": "HU_D04_01_001",
  "title": "response_set_walk_vel",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
    "result": "fail_motor"  # fail_imu: IMU error, fail_motor: motor error
  }
}
1.2.6.3 Message Push: none

1.2.7 Enter Damping Mode

All robot motors stop active motion, with noticeable damping when swung.

1.2.7.1 Request: request_damping
{
  "accid": "HU_D04_01_001",
  "title": "request_damping",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {}
}
1.2.7.2 Response: response_damping
{
  "accid": "HU_D04_01_001",
  "title": "response_damping",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
      "result": "success" # fail_motor: motor error
  }
}

1.2.8 Enter Zero Torque Mode

All robot motors stop active motion, with no damping when swung.

1.2.8.1 Request: request_zero_torque
{
  "accid": "HU_D04_01_001",
  "title": "request_zero_torque",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {}
}
1.2.8.2 Response: response_zero_torque
{
  "accid": "HU_D04_01_001",
  "title": "response_zero_torque",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
      "result": "success" # fail_motor: motor error
  }
}

1.2.9 Enter Standing Command

💡 Interface Function: Starts robot operation. After the robot is powered on, calling this interface transitions the robot into the standing state.
Parameter mode: [lying: robot is lying on the ground hanging: robot is suspended ]
Return: Returns after the robot has successfully stood up.
Requirement Link:

1.2.9.1 Request: request_standup
{
  "accid": "HU_D04_01_001",
  "title": "request_standup",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
      "mode": "lying" // "lying": robot is currently lying/sitting  or
                      // "hanging": robot is currently suspended
                      // If there is no "mode" field, the default robot state is "sitting"
  }
}
1.2.9.2 Response: response_standup
{
  "accid": "HU_D04_01_001",
  "title": "response_standup",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
      "result": "success" # fail_motor: motor error
                          # fail_invalid_cmd: parameter error
                          # fail_invalid_mode: robot state error
                          # fail_timeout: execution timeout error
  }
}

1.2.10 Enter Lying Down Command

1.2.10.1 Request: request_lie_down

💡 This interface can be called in Walk state

{
  "accid": "HU_D04_01_001",
  "title": "request_lie_down",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {}
}
1.2.10.2 Response: response_lie_down
{
  "accid": "HU_D04_01_001",
  "title": "response_lie_down",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
      "result": "success" # fail_motor: motor error
  }
}

1.2.11 Robot Dance

1.2.11.1 Switch Robot to Dance Mode
1.2.11.1.1 Request: request_enter_dance_mode
{
  "accid": "HU_D04_01_001",
  "title": "request_enter_dance_mode",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
    # 0: Exit dance mode
    # 1: Enter dance mode 
    "mode": 0
  }
}
1.2.11.1.2 Response: response_enter_dance_mode
{
  "accid": "HU_D04_01_001",
  "title": "response_enter_dance_mode",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
      "result": "success" # fail_motor
  }
}
1.2.11.2 Get Dance List
1.2.11.2.1 Request: request_get_dance_list
{
  "accid": "HU_D04_01_001",
  "title": "request_get_dance_list",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {}
}
1.2.11.2.2 Response: response_get_dance_list

    "accid": "HU_D04_01_001",
    "title": "response_get_dance_list",
    "guid": "746d937cd8094f6a98c9577aaf213d98",
    "timestamp": 1672373633989,
    "data": {
        "result": "success",
        "code": 0,
        "dances": [
            {
                "id": "DAN-14",
                "index": 0,
                "name": "\u70ed\u70c8",
                "english_name": "One and Only Dance",
                "rc_mapping": "one_and_only_dance",
                "duration": 10
            },
            {
                "id": "DAN-08",
                "index": 1,
                "name": "\u4f4e\u4fd7\u5c0f\u8bf4",
                "english_name": "Pulp Fiction Dance",
                "rc_mapping": "pulp_fiction_dance",
                "duration": 10
            }
        ]
    }
}
1.2.11.3 Robot Dancing
1.2.11.3.1 Request: request_dance

💡 Execution prerequisite: Currently in action library mode

{
  "accid": "HU_D04_01_001",
  "title": "request_dance",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
    "name": "one_and_only_dance"  # Dance name from the rc_mapping field
  }
}
1.2.11.3.2 Response: response_dance
{
  "accid": "HU_D04_01_001",
  "title": "response_dance",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
      "result": "success" # fail_motor
  }
}
1.2.11.3.3 Message Push: notify_dance

This message is pushed after the dance is completed or if execution fails during the process.

{
  "accid": "HU_D04_01_001",
  "title": "notify_dance",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
      "result": "success" # fail_motor
  }
}

1.2.12 Robot Action Library

1.2.12.1 Action Interruption
1.2.12.1.1 Request: request_interrupt_action_joystick
{
  "accid": "HU_D04_01_001",
  "title": "request_interrupt_action_joystick",
  "timestamp": 1779355330784,
  "guid": "32cef03a-5563-4b21-9bbb-3e65a8c9ae9e",
  "data": {}
}
1.2.12.1.2 Response:
{
  "accid": "HU_D04_01_001",
  "title": "response_interrupt_action_joystick",
  "guid": "32cef03a-5563-4b21-9bbb-3e65a8c9ae9e",
  "timestamp": 1779355330784,
  "data": {
    "result": "success"
  }
}
1.2.12.2 Get Action Library Status

💡 Interface Description:
(1) After the robot enters the action library, whether it is in action library/atomic execution/dance mode, "action_library_mode": "action_library"
(2) When the robot is executing an atomic action or dancing, "action_library_state": "running"

1.2.12.2.1 Request: request_get_action_library_status
{
  "accid": "HU_D04_01_001",
  "title": "request_get_action_library_status",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {}
}
1.2.12.2.2 Response: response_get_action_library_status
{
  "accid": "HU_D04_01_001",
  "title": "get_action_library_status",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
      "action_library_mode": "action_library" // or "remote_control"
      "action_library_state": "running"       //or "idle"
      "result": "success" # fail_motor
  }
}
1.2.12.3 Switch Robot to Action Library Mode
1.2.12.3.1 Request: request_set_motion_engine
{
  "accid": "HU_D04_01_001",
  "title": "request_set_motion_engine",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
    # 0: Exit action library mode
    # 1: Enter action library mode 
    "mode": 0
  }
}
1.2.12.3.2 Response: response_set_motion_engine
{
  "accid": "HU_D04_01_001",
  "title": "response_set_motion_engine",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
      "result": "success" # fail_motor
  }
}
1.2.12.4 Execute Action Library
1.2.12.4.1 Request: request_action_sync
{
  "accid": "HU_D04_01_001",
  "title": "request_action_sync",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
      "name": "one_and_only_dance,this_way_please"  ,
                                    # name: multiple dances/multiple actions/mix of dances and actions, separated by ","
      "music": "bgm1.wav,bgm2.wav,"   # Optional, only supports .wav format files                             
  }
}
1.2.12.4.2 Response: response_action_sync
{
  "accid": "HU_D04_01_001",
  "title": "response_action_sync",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
      "result": "success" # fail_motor
  }
}
1.2.12.5 Get Action Library List
1.2.12.5.1 Request: request_get_atomic_motion_list
{
  "accid": "HU_D04_01_001",
  "title": "request_get_atomic_motion_list",
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {}
}
1.2.12.5.2 Response: response_get_atomic_motion_list
{
    "accid": "HU_D04_01_001",
    "title": "response_get_atomic_motion_list",
    "guid": "746d937cd8094f6a98c9577aaf213d98",
    "timestamp": 287883835,
    "data": {
        "result": "success",
        "motion_list": [
            {
                "id": "MON-01",
                "rc_mapping": "greeting1",
                "duration": 7,
                "motion_index": 0,
                "motion_name_cn": "侧身打招呼",
                "motion_name_en": "Greeting1"
            },
            {
                "id": "MON-02",
                "rc_mapping": "greeting2",
                "duration": 9,
                "motion_index": 1,
                "motion_name_cn": "抬腿打招呼",
                "motion_name_en": "Greeting2"
            }
            ......
        ],
        "count": 2
    }
}

1.2.13 Global Message Protocol Interface

1.2.14 Robot Status Information

Robot status information is periodically reported through this protocol, including the following content:

  • accid: Robot serial number

  • title: notify_robot_info

  • timestamp: The timestamp when the message is sent, in milliseconds

  • guid: The guid value of the message, uniquely identifying this message

  • data: Contains the message content, example:

    {
      "accid": "HU_D04_01_001", 
      "title": "notify_robot_info", 
      "timestamp": 1672373633989,
      "guid": "746d937cd8094f6a98c9577aaf213d98",
      "data": {
        "result": []
      }
    }
    
1.2.14.1 Battery Data
{
  "accid": "HU_D04_01_001", 
  "title": "notify_robot_info", 
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
    "result": [
        ......
        {
                "level": 0,
                "name": "peripheral",
                "message": "OK",
                "hardware_id": "peripheral",
                "values": [
                    {
                        "key": "bmsconn",
                        "value": "ON"
                    },
                    {
                        "key": "bat_chg",
                        "value": "OFF"
                    },
                    {
                        "key": "bat_off",
                        "value": "OFF"
                    },
                    {
                        "key": "bat_prt",
                        "value": "0"
                    },
                    {
                        "key": "bat_vol",
                        "value": "48830"
                    },
                    {
                        "key": "bat_cur",
                        "value": "2870"
                    },
                    {
                        "key": "battery",
                        "value": "29"
                    },
                    {
                        "key": "bat_temp0",
                        "value": "430"
                    },
                    {
                        "key": "bat_temp2",
                        "value": "430"
                    },
                    {
                        "key": "bat_temp4",
                        "value": "400"
                    },
                    {
                        "key": "battery_capacity",
                        "value": "9000mAh"
                    }
                ]
            },
    ]
  }
}
Field Meaning
bmsconn Battery connection status: [OFF: Not connected, ON: Connected]
bat_chg Battery charger status: [OFF: Not connected, ON: Connected]
bat_off Battery pre-shutdown status: [OFF: Power off after 1s, ON: Normal]
bat_prt Battery fault code: [0: Normal, non-zero: Abnormal]
bat_vol Battery real-time voltage, unit: mV
bat_cur Battery real-time current, unit: mA
battery Battery charge percentage 0~100
bat_temp0 Battery temperature 0~100, unit: x10℃
bat_temp2 Battery temperature 0~100, unit: x10℃
bat_temp4 Battery temperature 0~100, unit: x10℃
1.2.14.2 Joystick Information Data (Only included in Lite models)
{
  "accid": "HU_D04_01_001", 
  "title": "notify_robot_info", 
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
    "result": [
        ......
        {
                "level": 0,
                "name": "peripheral",
                "message": "OK",
                "hardware_id": "peripheral",
                "values": [
                    {
                        "key": "joystickconn",
                        "value": "ON"
                    },
                    {
                        "key": "joysticksignal",
                        "value": "1"
                    },
                    {
                        "key": "joystickbattery",
                        "value": "2"
                    }
                ]
            },
    ]
  }
}
Field Meaning
joystickconn Joystick connection status: [OFF: Not connected, ON: Connected]
joysticksignal Joystick signal strength: [0-4, higher is stronger]
joystickbattery Joystick battery information: [0:0%~20%
1:21%~40%
2:41%~60%
3:61%~80%
4:81%~100%]
1.2.14.3 System Information
{
  "accid": "HU_D04_01_001", 
  "title": "notify_robot_info", 
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
      "result": [
          {
              "level": 0,
              "name": "system_info",
              "message": "system info",
              "hardware_id": "system_info",
              "values": [
                #### Fields common to both Oli and Luna
                {
                  "key": "ability_running",
                  "value": "ZeroTorque"
                },
                {
                  "key": "ecm_version",
                  "value": "1.1.2"
                },
                {
                  "key": "mode",
                  "value": "Remote"
                },
                {
                  "key": "motor_version",
                  "value": "1: 0.0.9; 2: 0.0.9; 3: 0.0.9; 4: 0.0.9; 5: 0.0.9; 6: 0.0.9; 7: 0.0.9; 8: 0.0.9; 9: 0.0.9; 10: 0.0.9; 11: 0.0.9; 12: 0.0.9; 13: 0.0.9; 14: 0.0.9; 15: 0.0.9; 16: 0.0.9; "
                },
                {
                  "key": "pms_version",
                  "value": "2.1.8"
                },
                {
                  "key": "robot_status",
                  "value": "ZeroTorque"
                },
                {
                  "key": "version",
                  "value": "robot-hu-d-2.1.0.20251225062343"
                },
                {
                  "key": "sn",
                  "value": "HU_D04_01_131"
                },
                ########## Luna-specific fields
                { "key": "sdk_lite_led_enable", "value": "1" },
                { "key": "sdk_lite_led_has_params", "value": "1" },
                { "key": "sdk_lite_led_mode", "value": "0" },
                { "key": "sdk_lite_led_state", "value": "1" },
                { "key": "sdk_lite_led_color", "value": "4" },
                { "key": "sdk_lite_led_brightness", "value": "3" },
                { "key": "sdk_lite_leds", "value": "" },
                {"key": "walk_gait", "value":"walk"}
              ]
        }
    ]
  }
}

Common to both Oli and Luna

Field Meaning
version Main controller version
ecm_version Master station version
pms_version Power distribution board version
motor_version Motor version
sn Robot serial number
robot_status Robot current status
ability_running Robot currently running controller

Luna-specific fields

Field Meaning
sdk_lite_led_enable() Luna LED effect control switch: 0=off, 1=on
sdk_lite_led_has_params Whether Luna LED effect parameters already exist: 0=no, 1=yes
sdk_lite_led_mode Luna LED effect control mode: 0=overall LED effect control, 1=individual LED RGB control
sdk_lite_led_state Overall LED effect status, valid when mode=0
sdk_lite_led_color Overall LED effect color, valid when mode=0
sdk_lite_led_brightness Overall LED effect brightness, valid when mode=0, range 0-5
sdk_lite_leds Individual LED RGB flat array string, valid when mode=1, e.g. 255,0,0,0,255,0
    If mode = 1 for individual RGB control:
    { "key": "sdk_lite_led_mode", "value": "1" },
    { "key": "sdk_lite_led_state", "value": "" },
    { "key": "sdk_lite_led_color", "value": "" },
    { "key": "sdk_lite_led_brightness", "value": "" },
    { "key": "sdk_lite_leds", "value": "255,0,0,0,255,0,0,0,255" }
    When disabled:
    { "key": "sdk_lite_led_enable", "value": "0" },
    { "key": "sdk_lite_led_has_params", "value": "0" },
    { "key": "sdk_lite_led_mode", "value": "" },
    { "key": "sdk_lite_led_state", "value": "" },
    { "key": "sdk_lite_led_color", "value": "" },
    { "key": "sdk_lite_led_brightness", "value": "" },
    { "key": "sdk_lite_leds", "value": "" }
1.2.14.4 Motor Status Information
{
  "accid": "HU_D04_01_001", 
  "title": "notify_robot_info", 
  "timestamp": 1672373633989,
  "guid": "746d937cd8094f6a98c9577aaf213d98",
  "data": {
      "result": [
          {
                "level": 1,
                "name": "ethercatCommunicationExp",
                "message": "WARN",
                "hardware_id": "ethercat",
                "values": [
                    {
                        "key": "ethercatCommunicationExp",
                        "value": "motor 17 MOTOR_LOST triggered HALF_STAND"
                    },
                    {
                        "key": "ethercatResetNormal",
                        "value": "ok!"
                    }
                ]
          }
    ]
  }
}
Field Meaning
level Exception level [0:ok 1:warn 2:error]
name Exception type
message Level string
hardware_id Hardware ID
values All exception sets for this hardware

1.2.15 Remote Controller Data

Robot remote controller data is reported through this protocol:

  • accid: Robot serial number

  • title: notify_joy_data

  • timestamp: The timestamp when the message is sent, in milliseconds

  • guid: The guid value of the message, uniquely identifying this message

  • data: Contains the message content, example:

    {
      "accid": "HU_D04_01_001", 
      "title": "notify_joy_data", 
      "timestamp": 1672373633989,
      "guid": "746d937cd8094f6a98c9577aaf213d98",
      "data": {
        "axes": [],     # Joystick axis data
        "buttons": []   # Button data
      }
    }
    

1.2.16 Protocol Interface Call Examples

1.2.16.1 Python Example Implementation
  • Environment preparation: Taking Ubuntu 20.04 as an example, install the following dependencies

    sudo apt install python3-dev python3-pip
    sudo pip install websocket-client==1.8.0
    
  • Run the script

    python humanoid.py
    
  • humanoid.py implementation

    💡 - ACCID: Replace with the actual software SN

  • ROBOT_IP: Generally, 127.0.0.1 for simulation, 10.192.1.2 for real robot
import json
import uuid
import threading
import time
import websocket
from datetime import datetime

# Replace this ACCID value with your robot's actual serial number (SN)
ACCID = None

# Replace it with the real IP address of the robot. 
# Usually, for simulation, it is: 127.0.0.1
# for a real machine, it is: 10.192.1.2
ROBOT_IP = "10.192.1.2"

# Atomic flag for graceful exit
should_exit = False

# WebSocket client instance
ws_client = None

# Generate dynamic GUID
def generate_guid():
    return str(uuid.uuid4())

# Send WebSocket request with title and data
def send_request(title, data=None):
    global ACCID
    if data is None:
        data = {}

    # Create message structure with necessary fields
    message = {
        "accid": ACCID,
        "title": title,
        "timestamp": int(time.time() * 1000),  # Current timestamp in milliseconds
        "guid": generate_guid(),
        "data": data
    }

    message_str = json.dumps(message)

    # Send the message through WebSocket if client is connected
    if ws_client:
        ws_client.send(message_str)

# Handle user commands
def handle_commands():
    global should_exit
    while not should_exit:
        command = input("Enter command ('prepare', 'damping', 'zero') or 'exit' to quit:\n")

        if command == "exit":
            should_exit = True  # Set exit flag to stop the loop
            break
        elif command == "prepare":
            send_request("request_prepare")  # request_prepare
        elif command == "damping":
            send_request("request_damping")  # request_damping
        elif command == "zero":
            send_request("request_zero_torque")  # request_zero_torque

# WebSocket on_open callback
def on_open(ws):
    print("Connected!")
    # Start handling commands in a separate thread
    threading.Thread(target=handle_commands, daemon=True).start()

# WebSocket on_message callback
def on_message(ws, message):
    global ACCID
    root = json.loads(message)
    title = root.get("title", "")
    ACCID = root.get("accid", None)

    if title != "notify_robot_info":
        print(f"Received message: {message}")  # Print the received message

# WebSocket on_close callback
def on_close(ws, close_status_code, close_msg):
    print("Connection closed.")

# Close WebSocket connection
def close_connection(ws):
    ws.close()

def main():
    global ws_client

    # Create WebSocket client instance
    ws_client = websocket.WebSocketApp(
        f"ws://{ROBOT_IP}:5000",  # WebSocket server URI
        on_open=on_open,
        on_message=on_message,
        on_close=on_close
    )

    # Configure socket send and receive buffer sizes
    # Increase send buffer size to 2MB (default is typically much smaller)
    # This helps prevent data loss when sending large messages or high-frequency data
    ws_client.sock_opt = [("socket", "SO_SNDBUF", 2 * 1024 * 1024)]

    # Increase receive buffer size to 2MB
    # This allows handling larger incoming messages without truncation
    ws_client.sock_opt.append(("socket", "SO_RCVBUF", 2 * 1024 * 1024))

    # Run WebSocket client loop
    print("Press Ctrl+C to exit.")
    ws_client.run_forever()

if __name__ == "__main__":
    main()

1.2.16.2 Linux C++ Example
  • Install dependencies: Taking Ubuntu 20.04 as an example, install websocketpp, nlohmann/json, and boost dependencies:

    sudo apt-get install libboost-all-dev libwebsocketpp-dev nlohmann-json3-dev
    
  • Compile the code

    g++ -std=c++11 humanoid humanoid.cpp -o humanoid humanoid -lssl -lcrypto -lboost_system -lpthread
    
  • Run the program

    ./humanoid
    
  • humanoid.cpp implementation

    #include <iostream>
    #include <atomic>
    #include <string>
    #include <thread>
    #include <chrono>
    #include <websocketpp/client.hpp>
    #include <websocketpp/config/asio.hpp> 
    #include <nlohmann/json.hpp>
    #include <boost/uuid/uuid.hpp>
    #include <boost/uuid/uuid_generators.hpp>
    #include <boost/uuid/uuid_io.hpp>
    
    using json = nlohmann::json;
    using websocketpp::client;
    using websocketpp::connection_hdl;
    
    // Replace this value with the actual serial number (SN) of the robot.
    static std::string ACCID = "";
    
    // Replace it with the real IP address of the robot. 
    // Usually, for simulation, it is: 127.0.0.1 
    // for a real machine, it is: 10.192.1.2
    const std::string ROBOT_IP = "10.192.1.2";
    
    // WebSocket client instance
    static client<websocketpp::config::asio> ws_client;
    
    // Atomic flag for graceful exit
    static std::atomic<bool> should_exit(false);
    
    // Connection handle for sending messages
    static connection_hdl current_hdl;
    
    // Generate dynamic GUID
    static std::string generate_guid() {
      boost::uuids::random_generator gen;
      boost::uuids::uuid u = gen();
      return boost::uuids::to_string(u);
    }
    
    // Send WebSocket request with title and data
    static void send_request(const std::string& title, const json& data = json::object()) {
      json message;
    
      // Adding necessary fields to the message
      message["accid"] = ACCID;
      message["title"] = title;
      message["timestamp"] = std::chrono::duration_cast<std::chrono::milliseconds>(
                                  std::chrono::system_clock::now().time_since_epoch()).count();
      message["guid"] = generate_guid();
      message["data"] = data;
    
      std::string message_str = message.dump();
    
      // Send the message through WebSocket
      ws_client.send(current_hdl, message_str, websocketpp::frame::opcode::text);
    }
    
    // Handle user commands
    void handle_commands() {
      std::cout << "Enter command ('prepare', 'damping', 'zero') or 'exit' to quit:\n";
      while (!should_exit) {
          std::string command;
          std::cin >> command;
    
          if (command == "exit") {
              should_exit = true;
              return;
          } else if (command == "prepare") {
              send_request("request_prepare");
          } else if (command == "damping") {
              send_request("request_damping");
          } else if (command == "zero") {
              send_request("request_zero_torque");
          }
    
          sleep(1);
    
          std::cout << "\nEnter command ('prepare', 'damping', 'zero') or 'exit' to quit:\n";
      }
    }
    
    // WebSocket open callback
    static void on_open(connection_hdl hdl) {
      std::cout << "Connected!" << std::endl;
    
      // Save connection handle for sending messages later
      current_hdl = hdl;
    
      // Start handling commands in a separate thread
      std::thread(handle_commands).detach();
    }
    
    // WebSocket TCP initialization handler
    static void on_tcp_init(connection_hdl hdl)
    {
    auto con = ws_client.get_con_from_hdl(hdl);
    
    // Obtain the underlying TCP socket
    auto& socket = con->get_socket().lowest_layer();
    
    // Configure socket options
    try {
      boost::system::error_code ec;
    
      // Set send buffer size (e.g., 2MB)
      const size_t sendBufferSize = 2 * 1024 * 1024;
      socket.set_option(websocketpp::lib::asio::socket_base::send_buffer_size(sendBufferSize), ec);
    
      if (ec) 
      {
        printf("Failed to set send buffer size: %s", ec.message().c_str());
      }
    
      // Set receive buffer size (e.g., 2MB)
      const size_t recvBufferSize = 2 * 1024 * 1024;
      socket.set_option(websocketpp::lib::asio::socket_base::receive_buffer_size(recvBufferSize), ec);
    
      if (ec) 
      {
        printf("Failed to set receive buffer size: %s", ec.message().c_str());
      }
    
      // Disable Nagle's algorithm to reduce latency
      socket.set_option(websocketpp::lib::asio::ip::tcp::no_delay(true), ec);
    
      if (ec)
      {
        printf("Failed to disable Nagle's algorithm: %s", ec.message().c_str());
      }
    } catch (const std::exception& e) {
      printf("Socket configuration exception: %s", e.what());
    }
    }
    
    // WebSocket message callback
    static void on_message(connection_hdl hdl, client<websocketpp::config::asio>::message_ptr msg) {
    // Parse JSON data from message payload
    json data = json::parse(msg->get_payload());
    
    // Extract 'accid' field if present
    if (data.contains("accid") && data["accid"].is_string() && ACCID.empty()) {
        ACCID = data["accid"].get<std::string>();
    }
    
    if (msg->get_payload().find("notify_robot_info") == std::string::npos) {
        std::cout << "Received message: " << msg->get_payload() << std::endl;
    }
    }
    
    // WebSocket close callback
    static void on_close(connection_hdl hdl) {
      std::cout << "Connection closed." << std::endl;
    }
    
    // Close WebSocket connection
    static void close_connection(connection_hdl hdl) {
      ws_client.close(hdl, websocketpp::close::status::normal, "Normal closure");  // Close connection normally
    }
    
    int main() {
      ws_client.init_asio();  // Initialize ASIO for WebSocket client
    
      ws_client.set_access_channels(websocketpp::log::alevel::none);
    
      // Set WebSocket event handlers
      ws_client.set_open_handler(&on_open);  // Set open handler
      ws_client.set_message_handler(&on_message);  // Set message handler
      ws_client.set_close_handler(&on_close);  // Set close handler
      ws_client.set_tcp_init_handler(&on_tcp_init); // Set tcp init handler
    
      std::string server_uri = "ws://" + ROBOT_IP + ":5000";  // WebSocket server URI
    
      websocketpp::lib::error_code ec;
      client<websocketpp::config::asio>::connection_ptr con = ws_client.get_connection(server_uri, ec);  // Get connection pointer
    
      if (ec) {
          std::cout << "Error: " << ec.message() << std::endl;
          return 1;  // Exit if connection error occurs
      }
    
      connection_hdl hdl = con->get_handle();  // Get connection handle
      ws_client.connect(con);  // Connect to server
      std::cout << "Press Ctrl+C to exit." << std::endl;
    
      // Run the WebSocket client loop
      ws_client.run();
    
      return 0;
    }
    
    
Function Name subscribeImuData
Function Prototype void subscribeImuData(std::function<void(const ImuDataConstPtr&)> cb);
Description Subscribe to the robot's IMU data and call the specified callback function when new IMU data is received.
Parameters cb: Callback function for processing new IMU data.
Return Value None

Remarks:

The ImuData data structure prototype is as follows:

/**
 * @struct ImuData
 *
 * @brief Struct representing robot IMU data based on sensor feedback.
 *
 * This struct encapsulates IMU data, including accelerometer, gyroscope, and quaternion.
 */
struct ImuData {
  uint64_t stamp; // Timestamp in nanoseconds, typically indicating when this data was recorded or generated.
  float acc[3];   // Stores IMU accelerometer data to track linear acceleration along three axes (X, Y, Z).
  float gyro[3];  // Stores IMU gyroscope data to track angular velocity or rotation rate along three axes (X, Y, Z).
  float quat[4];  // Stores IMU quaternion data representing orientation in 3D space (w, x, y, z).
};

// Smart pointer type aliases
typedef std::shared_ptr<ImuData> ImuDataPtr;
typedef std::shared_ptr<ImuData const> ImuDataConstPtr;

Code Example:

#include <thread>

// Include limxsdk::Humanoid header to import the Humanoid class
#include "limxsdk/humanoid.h"  

// Use limxsdk namespace to simplify references to the Humanoid class
using namespace limxsdk;  

int main(int argc, char *argv[]){
  // Get the singleton instance of the Humanoid class
  Humanoid* robot = Humanoid::getInstance();  

  // Default robot IP address
  std::string robot_ip = "127.0.0.1";
  if (argc > 1)
  {
    // If command-line arguments are provided, use them as the robot IP address
    robot_ip = argv[1];
  }

  // Initialize the communication runtime environment for the motion control algorithm
  if (!robot->init(robot_ip))
  {
    // Exit if initialization fails
    exit(1); 
  }

  // Subscribe to robot status updates with a callback function
  robot->subscribeImuData([&](const ImuDataConstPtr& msg) {
    // Process received ImuData data here
    // Note: The callback function is called when ImuData is received
  });

  // Infinite loop to keep the program running
  while (true)
  {
    // Sleep for 1000 milliseconds
    std::this_thread::sleep_for(std::chrono::milliseconds(1000)); 
  }
  return 0;
}

1.3 Logs and Data Packets

The robot system automatically records: robot IMU data (ImuData), robot state data (/joint/state), and robot control data (/joint/cmd), and other important data. These data are crucial for robot motion control analysis. In addition, the robot also records runtime log data for troubleshooting and performance optimization when needed. When the computer is connected to the robot's Wi-Fi hotspot, you can access it by entering http://10.192.1.2:8090 in the browser and download these data. This process provides convenience for robot monitoring, maintenance, and debugging.

图片展示的是Luna系统中数据包可视化分析方法中数据包下载后的界面。在浏览器地址栏输入“10.192.1.2:8090”后,进入目录“/home/lmx/bigdata”,显示“3 items”,有“Upload”按钮,下方列出“bag”“log”“ota”三个目录,其中“bag”目录最后修改时间为“07 Nov 25 14:44 CST (52 seconds ago)”,“log”“ota”目录最后修改时间为“07 Nov 25 14:40 CST (4 minutes ago)”。该图与上下文介绍的下载.bag文件后使用PlotJuggler工具加载和分析数据包数据相呼应。

1.3.1 Data Packet Visualization Analysis Method

  • Data Packet Download: After downloading the .bag file, you can use the PlotJuggler visualization tool to load and analyze these packet data. It is particularly important to note that if you downloaded a .bag.active file, you need to use the following Shell command to reindex the .bag.active file and generate a new .bag file for PlotJuggler to load.

    rosbag reindex your_file.bag.active
    mv your_file.bag.active your_file.bag
    
  • Visualization View: Start the PlotJuggler visualization tool through the Shell command rosrun plotjuggler plotjuggler -n. Load the data packet and analyze the data as shown in the figure below.

    图片展示了Luna SDK中使用PlotJuggler可视化分析数据包的界面。界面左侧有“Load bag”按钮,用于加载数据包。右侧是数据可视化区域,显示了三条曲线,分别以红色、蓝色和绿色呈现,横轴为时间,纵轴为不同数据。该图对应文档中“Data Packet Visualization Analysis Method”部分,直观呈现了使用PlotJuggler加载和分析数据包后的可视化效果,辅助说明数据包可视化分析的操作及结果展示。

1.3.2 Log and Diagnostic Tracking Point Data

The following figures show the log and tracking point structured data respectively. They can be used for troubleshooting and performance optimization when needed.

这张图片显示的是访问机器人Wi-Fi热点提供的Web页面,页面地址为10.192.1.2:8090,目录为/home/firm/bigdata,其中存在3个项目,项目包含名称、类型、大小、最后修改时间等信息。页面中名称为“log”的目录被红色框标注出来,该目录属于机器人记录的运行日志数据,结合上下文可知,这正是用于机器人故障排查与性能优化所需的日志数据目录,该页面提供了访问、下载机器人相关数据的途径。

1.4 Robot Software Upgrade

We enter the robot management page through the browser and select the locally pre-downloaded robot software version for upgrade. The specific steps are as follows:

  • Please select and connect to your robot's Wi-Fi hotspot, password: 12345678
  1. Access the management page:

  2. Select and upgrade software:

    • Select "Version Management -> Browse -> Upgrade" in sequence.
    • After the upgrade is completed, the robot's main control computer will automatically restart.

2 Motion Training Method Reference

2.1 Training Method Selection

Method Applicable Scenarios Main Process Prerequisites
Bon & Flux Platform accessible, wishing to reduce local environment setup work Bon retargeting → Flux training → cloud desktop/local simulation → export Bon, Flux accounts and valid computing power quota
Local Offline Training Data cannot leave the domain, platform unreachable, or need for high-frequency parameter tuning iterations GMR local retargeting → LimxMimic local training → local simulation → export Ubuntu, NVIDIA GPU, official repository access permissions
flowchart LR
A[Raw Motion Capture Data] --> B{Select Training Method}
B -->|Platform| C[Bon Retargeting]
C --> D[Flux Training]
B -->|Local| E[GMR Retargeting]
E --> F[LimxMimic Training]
D --> G[Policy Playback and Simulation]
F --> G
G --> H[Unified Export Deployment Package]
H --> I[8080 Upload]
I --> J[SDK Call and Real Robot Verification]

❗ The final deployment specifications for both routes are the same. Training, playback, and export must use the motion data and checkpoint corresponding to the same task. Do not mix products from different motions, different code versions, or different task configurations.

2.2 Platform Training Based on BON & Flux Training

2.2.1 User Business Full Process

User Business Full Process

Note: When Bon is not online, retargeting can be completed through local scripts

2.2.2 BON & Flux Training Product User Manual

Product Description Status Timeline Official Website Product User Manual
LimX BON BON is a full-process motion data pipeline management platform built for embodied intelligent robots, covering the complete data chain from motion capture upload, Retargeting, to quality assessment and training data export. In Development Expected to launch in September bon.limxdynamics.com
LimX Flux Training Flux Training is a cloud-based algorithm training platform specifically built for embodied intelligence, providing ready-to-use GPU computing power with pre-installed mainstream simulation environments (such as Isaac Gym, Isaac Sim), and engineering adaptations, allowing developers to say goodbye to tedious configurations and focus on algorithm training and robot innovation research. Launched Full capabilities available, model conversion launched on 9.3 https://flux.limxdynamics.com

2.3 Local Offline Training

2.3.1 Computer and Software Requirements

  • Recommended Ubuntu 22.04, NVIDIA graphics card and available drivers.
  • Minimum recommendation: 16-core CPU, 24 GB VRAM, 32 GB RAM; reserve at least 25 GB of disk space.
  • Install Git, Git LFS, Miniconda or Anaconda.
  • GitHub account needs access to GMR, Luna robot description repository, and official LimxMimic training repository.

💡 Testing confirms that the business training methods for Luna L03 and L04 are consistent; the current public export tool fixedly uses the 141-dimensional observation and 27-dimensional action of HU_L03_01 Parallel Deploy Gravity. The task name, robot configuration, and export tool must come from the same version of the official delivery package. Do not mix L03/L04 configurations on your own.

2.3.2 Download Code and Prepare Directory

cd ~
git clone --branch limx --single-branch \
  https://github.com/limx-retarget/GMR.git GMR
git clone https://github.com/limx-luna/luna-beyondmimic.git whole_body_tracking
mkdir -p ~/data

Subsequently, use ~/GMR uniformly for retargeting, and use ~/whole_body_tracking for motion preparation, training, playback, and export. Place the original motion files in ~/data, and try to use English for file names and paths without spaces.

2.3.3 Install GMR Environment

cd ~/GMR
git lfs install
git lfs pull
git config submodule.assets/luna-description.url \
  https://github.com/limx-luna/luna-description.git
git submodule update --init assets/luna-description

conda create -n gmr python=3.10 -y
conda activate gmr
python -m pip install -e .
conda install -c conda-forge libstdcxx-ng -y

❗ If the submodule shows Permission denied or Repository not found, it means the account lacks Luna description repository permissions. You should apply for permissions first. Do not skip the submodule or copy asset files of unknown versions.

2.3.4 Determine Original Data Type

Input Processing Entry Key Confirmation Items
Luna Retargeting NPY Direct preview and training Must be generated by the official GMR/Bon process, not any NumPy file
SMPL-X NPZ smplx_to_robot.py pose, root, trans and frame rate fields are complete
Ordinary BVH bvh_to_robot.py Confirm lafan1, nokov, fzmotion, soma or noitom format and actual frame rate
Xsens 3ds Max BVH xsens_bvh_to_robot.py Confirm displacement unit; centimeters use 0.01, millimeters use 0.001
Video, FBX, CSV, etc. Convert first The current official process cannot read directly

2.3.5 Retarget to Luna Motion

The following commands only execute the one corresponding to the data type:

conda activate gmr
cd ~/GMR
mkdir -p output

# Ordinary BVH example: modify format and motion_fps according to actual data
python scripts/bvh_to_robot.py \
  --bvh_file ~/data/walk.bvh \
  --format nokov \
  --motion_fps 50 \
  --robot limx_luna \
  --save_path output/my_motion.npy

# Xsens 3ds Max BVH example
python scripts/xsens_bvh_to_robot.py \
  --bvh_file ~/data/walk_xsens.bvh \
  --robot limx_luna \
  --bvh_format 3DSM \
  --scale 0.01 \
  --reset_to_zero \
  --save_path output/my_motion.npy

When the BVH type is unknown, you should first confirm the acquisition device and export template with the data provider. Incorrect format, frame rate, or unit often manifests as the robot moving sideways, body leaving the ground, or abnormal limb directions.

2.3.6 Preview Retargeted Motion

conda activate gmr
cd ~/GMR
python scripts/vis_robot_motion.py \
  --robot limx_luna \
  --robot_motion_path output/my_motion.npy

Confirm that the overall direction, limb posture, foot contact, and motion tail have no obvious abnormalities. In a pure SSH environment, you can temporarily skip the preview, but you must complete simulation verification after training.

2.3.7 Install LimxMimic Training Environment

conda create -n limxmimic python=3.10.15 -y
conda env config vars set PYTHONNOUSERSITE=1 -n limxmimic
conda env config vars set OMNI_KIT_ACCEPT_EULA=Y -n limxmimic
conda activate limxmimic

python -m pip install --upgrade pip
python -m pip install "setuptools==75.8.0" wheel
python -m pip install torch==2.5.1 torchvision==0.20.1 \
  --index-url https://download.pytorch.org/whl/cu118
python -m pip install --no-cache-dir "isaacsim[all,extscache]==4.5.0" \
  --extra-index-url https://pypi.nvidia.com

cd ~
git clone --branch v2.1.0 --depth 1 \
  https://github.com/isaac-sim/IsaacLab.git IsaacLab-2.1.0
cd ~/IsaacLab-2.1.0
echo "setuptools<81" > ~/isaaclab-build-constraints.txt
export PIP_CONSTRAINT=~/isaaclab-build-constraints.txt
export TERM=xterm
./isaaclab.sh --install

cd ~/whole_body_tracking
git submodule update --init --recursive
python -m pip install -e source/whole_body_tracking

GMR and LimxMimic use two independent Conda environments. Retargeting commands run in gmr, and training and export commands run in limxmimic.

2.3.8 Pre-training Check

conda activate limxmimic
cd ~/whole_body_tracking
python scripts/prepare_motion.py \
  --input ~/GMR/output/my_motion.npy \
  --output motions/my_motion_parallel_tail10.npz \
  --robot hu_l03_parallel \
  --linkage_report motions/my_motion_linkage_report.json \
  --force_tail

This step is used to explicitly check parallel linkage solving, tail frames, and kinematics results. The generated NPZ is a diagnostic intermediate file; the current recommended training, playback, and combined export still uniformly pass in the same trusted NPY, and the tool internally executes a consistent motion preparation process.

2.3.9 Start Training

conda activate limxmimic
cd ~/whole_body_tracking
python scripts/rsl_rl/train.py \
  --task=Tracking-Flat-HU-L03-Parallel-Deploy-Gravity-v0 \
  --motion_file ~/GMR/output/my_motion.npy \
  --motion_force_tail \
  --num_envs 4096 \
  --headless \
  --max_iterations 15000 \
  --logger tensorboard

When the training directory appears in the terminal and iteration information is continuously updated, it means training has started normally. When VRAM is insufficient, reduce --num_envs to 2048 or 1024 in sequence. Do not modify the task name and observation/action dimensions.

2.3.10 Playback and Export

# Playback the checkpoint from the same training run
python scripts/rsl_rl/play.py \
  --task=Tracking-Flat-HU-L03-Parallel-Deploy-Gravity-v0 \
  --checkpoint /path/to/model_14999.pt \
  --motion_file ~/GMR/output/my_motion.npy \
  --motion_force_tail \
  --num_envs 1 \
  env.commands.motion.debug_vis=false \
  env.scene.contact_forces.debug_vis=false

# Export the complete deployment package
python tools/offline_onnx_exporter/export_policy_and_reference.py \
  --checkpoint /path/to/model_14999.pt \
  --motion ~/GMR/output/my_motion.npy \
  --output_path exported/my_motion

2.4 Training Engineering, Adjustable Parameters and Interface Red Lines

2.4.1 Repository Directory Structure

The repository is divided into two major parts: source/ is the training code installed as a Python package, and scripts/ is the directly executable command-line tools. Daily configuration changes are in source/, and daily process runs are in scripts/.

whole_body_tracking/
├── scripts/                         Command-line tools, execute directly
│   ├── rsl_rl/
│   │   ├── train.py                 Start training
│   │   ├── play.py                  Playback policy, also exports ONNX
│   │   └── cli_args.py              Training/playback command-line parameters
│   ├── solve_parallel_linkage.py    Solve closed-chain degrees of freedom
│   ├── npy_to_npz.py                Retargeting npy to training npz
│   ├── append_motion_tail.py        Add tail frames that maintain the terminal posture
│   ├── verify_motion_npz.py         Verify npz with forward kinematics (hard gate)
│   ├── dump_articulation_order.py   Print the canonical joint/rigid body order of the model
│   └── replay_npz.py                Directly playback reference motions in Isaac Sim
│
├── source/whole_body_tracking/whole_body_tracking/
│   ├── tasks/tracking/
│   │   ├── tracking_env_cfg.py      Total configuration for rewards, terminations, domain randomization, observations
│   │   ├── mdp/
│   │   │   ├── commands.py          Reference motion loading, error calculation, adaptive sampling
│   │   │   ├── rewards.py           Reward function implementation
│   │   │   ├── terminations.py      Termination condition implementation
│   │   │   ├── events.py            Domain randomization implementation
│   │   │   └── observations.py      Observation item implementation
│   │   └── config/hu_l03/
│   │       ├── parallel_env_cfg.py  Environment configuration for closed-chain variant
│   │       └── agents/
│   │           └── rsl_rl_ppo_cfg.py  PPO hyperparameters and network structure
│   ├── robots/
│   │   └── hu_l03_parallel.py       Closed-chain model actuator gains, armature, action scaling
│   ├── assets/HU_L03_description/   Robot USD / URDF / MJCF
│   └── utils/exporter.py            ONNX export and metadata
│
├── motions/                         Converted npz reference motions
├── logs/rsl_rl/                     Training products: checkpoint, TensorBoard, exported ONNX
├── export_specs/                    Offline ONNX export specification files
└── tools/offline_onnx_exporter/     Independent export tool not dependent on Isaac Sim

2.4.2 Configuration File Quick Reference

Modification Target Corresponding File
Rewards, termination thresholds, domain randomization tasks/tracking/tracking_env_cfg.py
Curriculum sampling parameters MotionCommandCfg in tasks/tracking/mdp/commands.py
Add a new reward function tasks/tracking/mdp/rewards.py
PPO hyperparameters, network width config/hu_l03/agents/rsl_rl_ppo_cfg.py
Actuator stiffness and damping robots/hu_l03_parallel.py
Observation items config/hu_l03/parallel_env_cfg.py, but do not modify

2.4.3 Interface Red Line: Observation and Action Items Cannot Be Modified

It is forbidden to add, delete, or adjust observation items, observation order, action dimensions, and action order. These contents constitute the fixed interface contract between the policy and the robot's lower-level controller. After modification, the policy cannot be correctly deployed.

Item Reason for Not Being Modifiable
Observation Each item and its order are written into ONNX metadata. The lower-level controller concatenates the input vector according to a fixed layout. Adding or deleting items or changing the order will cause input misalignment.
Action The 27-dimensional actions correspond to specific motor slots respectively. Changing the width or order will cause control commands to be sent to the wrong joints.

The current task Tracking-Flat-HU-L03-Parallel-Deploy-Gravity-v0 uses 141-dimensional observation, 27-dimensional action:

command(54) + base_ang_vel(3) + projected_gravity(3)
            + joint_pos(27) + joint_vel(27) + actions(27) = 141

Deploy means that global position, state-estimated linear velocity, and sensorless link degrees of freedom that the lower-level controller cannot directly obtain have been removed; Gravity means that the gravity direction directly provided by the IMU is retained.

2.4.4 Reward Parameters

Rewards are a relatively safe adjustment entry, defined in RewardsCfg of tracking_env_cfg.py.

Reward Item Weight std Main Impact After Increasing
motion_global_anchor_pos 0.5 0.3 Torso world position fits more tightly, but at the cost of local posture degrees of freedom
motion_global_anchor_ori 0.5 0.4 More accurate torso orientation
motion_body_pos 1.0 0.3 More accurate limb positions, the main constraint for motion similarity
motion_body_ori 1.0 0.4 More accurate limb orientations
motion_body_lin_vel 1.0 1.0 Linear velocity and motion rhythm closer to the reference
motion_body_ang_vel 1.0 3.14 Rotation rhythm closer to the reference
action_rate_l2 −0.1 Smoother actions, less jitter, but slower response
joint_limit −10.0 Stronger avoidance of joint limits, may conflict with reference motions close to the limits
undesired_contacts −0.1 Reduce contact with parts other than feet and hands

💡 std is usually more worth prioritizing adjustment than weight. The tracking reward adopts the exp(−error² / std²) form; the smaller the std, the stricter the constraint, and the larger the std, the higher the tolerance range. The six motion_* items define the task itself and are not recommended for deletion.

2.4.5 Termination Conditions

Termination conditions are defined in TerminationsCfg, which directly determines whether the policy has the opportunity to learn the complete motion.

Termination Item Default Threshold Meaning
time_out 10 s (500 steps) Normal end, not a failure
anchor_pos 0.25 m Maximum allowable deviation of torso anchor height from the reference
anchor_ori 0.8 Deviation of torso tilt from the reference
ee_body_pos 0.25 m Maximum allowable deviation of any end height of both ankles and both wrists from the reference

You can use "threshold ÷ peak vertical velocity of the end" to estimate the fault tolerance window. For example, if the peak velocity is 2 m/s and the threshold is 0.25 m, the policy is only allowed to lag by about 0.125 seconds. When the completion rate of large leg lifts, jumps, or standing-up motions is persistently low, and the failure reason is concentrated in ee_body_pos, you can evaluate relaxing the threshold to 0.4–0.5 m.

2.4.6 Domain Randomization

Increasing randomization can improve real-robot robustness, but will reduce training speed and simulation tracking accuracy.

Parameter Default Range Effect
physics_material static friction 0.3–1.6 Cover different ground friction conditions
physics_material dynamic friction 0.3–1.2 Affect sliding characteristics after contact
physics_material elasticity 0.0–0.5 Control ground contact rebound
add_joint_default_pos ±0.01 rad Simulate joint zero calibration errors
base_com x ±0.025 m, y/z ±0.05 m Simulate torso center of mass deviation, has a large impact on balance
push_robot interval 1–3 s Control external disturbance frequency
push_robot velocity xy ±0.5 m/s, yaw ±0.78 rad/s Increasing can improve anti-disturbance ability, but will interfere with fine motions

2.4.7 Curriculum Sampling

Curriculum sampling is defined in MotionCommandCfg, used to determine from which time point of the motion each reset starts.

Parameter Default Value Impact
adaptive_kernel_size 1 When 1, failures are only recorded at the current time point; when long motions are stuck at a fixed difficulty point, it can be adjusted to 5, allowing sampling to cover the process before entering the difficulty point
adaptive_uniform_ratio 0.1 Ensure all time periods have the minimum sampling amount, avoid computing power concentrated on a single difficulty point
adaptive_alpha 0.001 Control the update speed of the failure histogram; increasing makes the response faster but more volatile
pose_range / velocity_range Subject to configuration Control initial state disturbance during reset, increasing can improve robustness

2.4.8 PPO Hyperparameters and Network

Defined in config/hu_l03/agents/rsl_rl_ppo_cfg.py. The default configuration is suitable for most motions, and modification is not recommended without clear evidence.

Parameter Default Value Description
Network [512, 256, 128], ELU Only consider widening when the observation dimension increases significantly; the current observation dimension is prohibited from modification
num_steps_per_env 24 Number of sampling steps per environment per round
learning_rate 1e-3, adaptive The actual learning rate is scheduled by desired KL feedback
desired_kl 0.01 Main update step size control parameter; smaller is more stable but slower training
entropy_coef 0.005 Increasing enhances exploration, too large will cause action jitter
gamma / lam 0.99 / 0.95 Discount factor and GAE parameter
max_iterations 30000 Can be overridden from the command line, in practice 15000 rounds usually enter the convergence interval

2.4.9 Actuator Gains

Actuator gains are defined in robots/hu_l03_parallel.py, uniformly calculated from natural frequency, damping ratio, and armature in the manufacturer's MJCF:

NATURAL_FREQ = 10 * 2 * pi   # 10 Hz
DAMPING_RATIO = 2.0

stiffness = armature * NATURAL_FREQ ** 2
damping = 2 * DAMPING_RATIO * armature * NATURAL_FREQ
  • NATURAL_FREQ increase: Tracking is stiffer and more accurate, but the real robot is more prone to jitter.
  • DAMPING_RATIO increase: The system is more stable, but the response is more sluggish.
  • soft_joint_pos_limit_factor defaults to 0.9; it can be carefully increased when reference motions need to be close to the limits.

❗ Adjusting gains should modify the unified constants. Do not arbitrarily change values joint by joint, so as not todisrupt the relative relationship between individual joints. Any parameter adjustment result must re-complete simulation and real-robot safety verification.

3 Dance Motion Simulation Cloud Desktop Verification

3.1 Cloud Desktop Creation

  1. Register and log in to Flux Training (https://internal.limxdynamics.com/user/login)
  2. Recharge the account (for redemption codes, please contact LimX Dynamics sales colleagues)
  3. Select "Cloud Desktop" and click Add

这张图片是Luna SDK开发指南中“云桌面创建”步骤里的对应页面,页面左侧是功能导航栏,“Cloud Desktop”选项呈高亮选中状态;页面主区域标题为“Cloud Desktop”,配有运行云桌面的示意图,下方有说明文字介绍云桌面的作用是运行虚拟桌面实例,负责计算、存储和资源调度;页面底部还有蓝色的“Create”按钮,用于创建新的云桌面,对应步骤3中“选择‘Cloud Desktop’并点击Add”的操作指引。

  1. Create a new cloud desktop and select configuration parameters

    1. Computing power: Select as needed, 3 tiers available, 5880 16G/24G/48G
    2. Image system: Scroll to the bottom and select the image dedicated to Luna secondary development
    3. System disk: Select as needed, 2 tiers available, 100G and 200G
    4. Auto shutdown: Select as needed, the identification criterion is whether the mouse is moved

    这张图片是创建云桌面的操作界面,对应文档中创建云桌面流程里的“Create Cloud Desktop”页面。页面左侧导航栏已选中“Cloud Desktop”选项,右侧为云桌面配置区域,包含“Cloud Desktop Name”输入框、“Resource Specification”等配置项,界面还呈现了系统磁盘、自动关机等配置相关内容,底部有“Create”和“Cancel”按钮,该界面用于进行云桌面创建的参数设置,匹配文档中步骤4提及的创建新云桌面并选择配置参数的操作内容。

  2. Create and power on, wait for boot

这张图片是Luna SDK开发指南中云桌面创建步骤里的相关界面,对应Luna二次开发专用的云桌面配置信息展示界面。界面明确标注该云桌面为Luna二次开发专用,基于Linux Ubuntu22.04系统,搭配IsaacSim4.5与IsaacLab2.1.0,存储费用按0.05元每小时(约1.2元每天)计算,右上角显示状态为“Pending”,界面中间还有一个灰色的链接图标。

  1. Click Login

图片展示的是Luna Training Simulation的云桌面创建界面。界面中显示“Luna-Training-Simulation”云桌面正在运行,其配置为Linux Ubuntu22.04 + IsaacSim4.5 + IsaacLab2.1.0(Luna二开专用),计算费用为8.15 CNY/hr,存储费用为0.05 CNY/hr。界面右下角有“+ Create”按钮,下方有“Running”状态标识,中间有一个蓝色的链接图标,箭头指向该图标,提示点击链接可进行相关操作。

  1. Login to use

图片展示的是Luna SDK开发指南中Cloud Desktop创建流程中登录界面。画面中显示“Welcome to Ubuntu 20.04.5 LTS”字样,背景为紫色几何图案。画面右上角有“52 MB”标识,下方弹出“Connect Your Online Accounts”窗口,提示可连接Google、GitHub、Microsoft等账号。该图片对应文档中“Cloud Desktop Creation”步骤里“Login to use”环节,直观呈现了登录界面样式。

3.2 Simulation Running

In the home directory, there is a LunaSim folder. Enter this folder:

cd ~/LunaSim

Run the one-click simulation startup script:

./start_sim.sh

Wait for the simulation to start, the robot stands in the simulation environment

图片展示的是Luna SDK中Dance Motion Simulation的云桌面验证中,机器人在模拟环境中的状态。画面中机器人位于网格背景的中心,姿态为站立,双手自然下垂。画面左下角显示了Time、Size、CPU等信息,右下角有Robot Velocity的图表。该图与文档中“Dance Verification”部分对应,用于说明在完成相关操作后,机器人会在模拟环境中执行动作,以验证Dance Motion Simulation功能。

3.3 Dance Verification

After the simulation is started, open the browser and enter 127.0.0.1:8080 in the browser address bar to enter the robot configuration interface

这张图片展示的是Luna SDK相关的机器人配置操作界面,整体为深色界面风格,左侧为功能导航栏,中间区域显示带LIMX Luna标识的人形机器人虚拟形象,右侧分为设备信息展示板块,上方是基本信息栏,标注了机器人名称、ID等内容,下方以绿色进度条呈现内存占用为9%、CPU使用率为21.7%的状态,该界面对应舞蹈验证环节中,打开浏览器输入127.0.0.1:8080后进入的机器人配置界面,可用于后续模型相关配置操作。

After observing that the simulation connection is normal, select Model Configuration

图片展示的是Luna机器人配置界面中的模型配置页面。左侧导航栏有“模型配置”等选项,当前选中“模型配置”。页面上方有“模型列表”“动作”“竹签”三个标签,红色箭头指向“模型列表”标签。下方是模型列表区域,显示了多个模型名称、动作、竹签、模型大小等信息,如“Luna_1000”“Luna_10000”等,部分模型右侧有“删除”按钮。该图片与文档中“Dance Verification”部分上下文对应,用于说明在机器人配置界面进行模型配置的操作步骤。

Select "Select Folder", select the folder containing the trained policy.onnx, reference trajectory reference.txt, and configuration file param.yaml, name the action you added, and click Upload:

图片展示的是Luna SDK中Dance Verification步骤中模型配置界面。界面中“模型配置类型”下,有“Luna”和“Luna_1”两个选项,其中“Luna”被红色框突出显示。下方“模型列表”中列出了多个模型名称及对应信息。该图片与文档中“Dance Verification”步骤相关,用于指导用户在Luna SDK中进行Dance动作验证时,选择正确的模型配置类型。

When the model list shows the newly added action as shown in the figure below, you can click Execute, and Luna will execute the action in the simulation

图片展示的是Luna SDK中Dance Verification步骤中模型列表界面。列表中包含多个动作名称,如“跳跳”,“爱情鸟”等,每行有中英文名称、执行器、来源、时长等信息,右侧有“执行”按钮。其中“跳跳”动作被红色框突出显示,其执行器为“open dance”,来源为“本地”,时长6s,右侧也有“执行”按钮。该图片与文档中Dance Verification步骤相关,用于指导用户在模型列表中选择特定动作进行执行操作。
#(注:内容由AI生成)