Skip to content

Low-Level Communication Examples

Purpose: Guide users to set up a status monitoring program to get X30 runtime status information reported via UDP protocol.

Step 1: Modify X30 Motion Host Network Configuration

Section titled “Step 1: Modify X30 Motion Host Network Configuration”
  1. Log in to X30 motion host

    Connect to X30 WiFi, SSH into the motion host (192.168.1.103). The password for user ysc is ' (English single quote).

    Terminal window
    ssh ysc@192.168.1.103
  2. Navigate to the configuration file directory

    Terminal window
    cd /home/ysc/jy_exe/conf
  3. Edit the network.toml configuration file

    Terminal window
    vim network.toml
  4. Add the following configuration at the end of the file

    # UDP status reporting configuration
    [udp_status]
    ip = '192.168.1.105'
    target_port = 43897
    local_port = 43893
    ips = ["192.168.1.105", "192.168.1.106","xxxxx"] # List of IPs receiving status messages
    ports = [30001, 30001, xxxxx] # List of corresponding port numbers

    Configuration notes:

    • ips: Array of client IP addresses receiving UDP status messages
    • ports: Corresponding array of port numbers, matching the IP addresses one-to-one
    • Modify IP addresses according to your actual network environment
Terminal window
cd /home/ysc/jy_exe/scripts
./restart.sh

Step 3: Compile and Run the Status Monitoring Program

Section titled “Step 3: Compile and Run the Status Monitoring Program”
Terminal window
g++ UDPtest.cpp -o UDPtest
./UDPtest

After the program starts normally, it will display:

Start listening for robot status reports, port: 30001

When robot status data is received, it will display information similar to:

========================================
Received status data [From:192.168.1.103]
----------------------------------------
Robot name: X30_Robot
Current mileage: 1500 cm
Total mileage: 12500 cm
Current runtime: 3600 seconds
Total runtime: 86400 seconds
Current motion time: 1800 seconds
Total motion time: 43200 seconds
Joystick data: [0, 0.5, 0, 0]
Running mode: Auto
Emergency stop source: 0
Error state: 0x0
========================================

UDP status monitoring result

#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdint.h>
#define PORT 30001
struct RcsData {
char robot_name[15];
int32_t current_mileage;
int32_t total_mileage;
int32_t current_run_time;
int32_t total_run_time;
int32_t current_motion_time;
int32_t total_motion_time;
float joystick[4];
union {
struct {
uint8_t is_nav_mode;
uint8_t emergency_source;
uint8_t mode_reserved[8];
} rcs_state_list;
uint8_t rcs_state[10];
};
union {
struct {
uint32_t imu_error : 1;
uint32_t wifi_error : 1;
uint32_t driver_heat_warn : 1;
uint32_t driver_error : 1;
uint32_t motor_heat_warn : 1;
uint32_t battery_low_warn : 1;
uint32_t battery_heat_warn : 1;
uint32_t gpio_error : 1;
uint32_t cpu_heat_warn : 1;
uint32_t cpu_freq_warn : 1;
uint32_t reserved : 22;
} error_state_bit;
uint32_t error_state;
};
};
int main() {
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
std::cout << "Failed to create socket" << std::endl;
return -1;
}
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
std::cout << "Failed to bind port" << std::endl;
close(sockfd);
return -1;
}
std::cout << "Start listening for robot status reports, port: " << PORT << std::endl;
while (true) {
RcsData robot_data;
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
ssize_t recv_len = recvfrom(sockfd, &robot_data, sizeof(robot_data), 0,
(struct sockaddr*)&client_addr, &client_len);
if (recv_len == sizeof(robot_data)) {
char client_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(client_addr.sin_addr), client_ip, INET_ADDRSTRLEN);
std::cout << "========================================" << std::endl;
std::cout << "Received status data [From:" << client_ip << "]" << std::endl;
std::cout << "----------------------------------------" << std::endl;
std::cout << "Robot name: " << robot_data.robot_name << std::endl;
std::cout << "Current mileage: " << robot_data.current_mileage << " cm" << std::endl;
std::cout << "Total mileage: " << robot_data.total_mileage << " cm" << std::endl;
std::cout << "Current runtime: " << robot_data.current_run_time << " seconds" << std::endl;
std::cout << "Total runtime: " << robot_data.total_run_time << " seconds" << std::endl;
std::cout << "Current motion time: " << robot_data.current_motion_time << " seconds" << std::endl;
std::cout << "Total motion time: " << robot_data.total_motion_time << " seconds" << std::endl;
std::cout << "Joystick data: [" << robot_data.joystick[0] << ", "
<< robot_data.joystick[1] << ", "
<< robot_data.joystick[2] << ", "
<< robot_data.joystick[3] << "]" << std::endl;
std::cout << "Running mode: " << (robot_data.rcs_state_list.is_nav_mode ? "Auto" : "Manual") << std::endl;
std::cout << "Emergency stop source: " << static_cast<int>(robot_data.rcs_state_list.emergency_source) << std::endl;
std::cout << "Error state: 0x" << std::hex << robot_data.error_state << std::dec << std::endl;
if (robot_data.error_state_bit.imu_error) std::cout << "- IMU error" << std::endl;
if (robot_data.error_state_bit.wifi_error) std::cout << "- WiFi error" << std::endl;
if (robot_data.error_state_bit.driver_heat_warn) std::cout << "- Driver over-temperature warning" << std::endl;
if (robot_data.error_state_bit.driver_error) std::cout << "- Driver error" << std::endl;
if (robot_data.error_state_bit.motor_heat_warn) std::cout << "- Motor over-temperature warning" << std::endl;
if (robot_data.error_state_bit.battery_low_warn) std::cout << "- Low battery warning" << std::endl;
if (robot_data.error_state_bit.battery_heat_warn) std::cout << "- Battery over-temperature warning" << std::endl;
if (robot_data.error_state_bit.gpio_error) std::cout << "- GPIO error" << std::endl;
if (robot_data.error_state_bit.cpu_heat_warn) std::cout << "- CPU over-temperature warning" << std::endl;
if (robot_data.error_state_bit.cpu_freq_warn) std::cout << "- CPU frequency warning" << std::endl;
std::cout << "========================================" << std::endl;
}
}
close(sockfd);
return 0;
}

Purpose: Guide users to get X30 robot dog’s real-time basic status information via TCP protocol.

Ensure the monitoring host and X30 navigation host are on the same network segment. X30 navigation host default IP: 192.168.1.106, TCP port 30000.

Verify connectivity:

Terminal window
nc -zv 192.168.1.106 30000

Step 2: Compile and Run the Status Query Program

Section titled “Step 2: Compile and Run the Status Query Program”
Terminal window
g++ TCPtest.cpp -o TCPtest
./TCPtest

After the program starts normally, it will display:

=== X30 Robot Dog Real-Time Status Program ===
Connecting to robot dog 192.168.1.106:30000...
Connected successfully
Sending status query request...
Sent successfully: 175 bytes

When a response is received:

=== Received robot dog status response ===
Response length: 689 bytes
Response content:
<?xml version="1.0" encoding="UTF-8"?>
<PatrolDevice>
<Type>1002</Type>
<Command>1</Command>
<Time>2025-11-12 14:30:25</Time>
<Items>
<MotionState>2</MotionState>
<PosX>1.5</PosX><PosY>2.3</PosY><PosZ>0.0</PosZ>
<Roll>0.05</Roll><Pitch>-0.02</Pitch><Yaw>1.57</Yaw>
<Speed>0.5</Speed>
<CurOdom>0.15</CurOdom><SumOdom>12.5</SumOdom>
<Electricity>85</Electricity>
<Location>0</Location>
<GaitState>0</GaitState>
<MotorState>0</MotorState>
<ChargeState>0</ChargeState>
<ControlMode>1</ControlMode>
<OnDockState>0</OnDockState>
</Items>
</PatrolDevice>

To implement other features (e.g., dispatching navigation tasks Type=1003), simply modify the XML data construction and response parsing parts in the code. Refer to the message type definitions in Communication Architecture for details.

#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string>
#include <ctime>
#define SERVER_IP "192.168.1.106" // Robot dog IP address
#define PORT 30000 // Robot dog TCP service port
// X30 protocol header structure (fixed 16 bytes)
struct x30ProtocolHeader {
unsigned char sync1; // Sync char 1: 0xEB
unsigned char sync2; // Sync char 2: 0x90
unsigned char sync3; // Sync char 3: 0xEB
unsigned char sync4; // Sync char 4: 0x90
unsigned short dataLength; // XML data length (little-endian)
unsigned short messageID; // Message ID (little-endian)
unsigned char reserved[8]; // Reserved field
};
// Get current time string
std::string getCurrentTime() {
time_t now = time(0);
struct tm tstruct;
char buf[80];
tstruct = *localtime(&now);
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tstruct);
return buf;
}
int main() {
std::cout << "=== X30 Robot Dog Real-Time Status Program ===" << std::endl;
// Create TCP socket
int client_fd = socket(AF_INET, SOCK_STREAM, 0);
if (client_fd < 0) {
perror("Failed to create socket");
return -1;
}
// Configure server address
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr);
// Connect to robot dog
std::cout << "Connecting to robot dog " << SERVER_IP << ":" << PORT << "..." << std::endl;
if (connect(client_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Connection failed");
close(client_fd);
return -1;
}
std::cout << "Connected successfully" << std::endl;
// Construct XML data for getting real-time status
// Type=1002: Get real-time basic status
std::string xmlData = R"(<?xml version="1.0" encoding="UTF-8"?>
<PatrolDevice>
<Type>1002</Type>
<Command>1</Command>
<Time>)" + getCurrentTime() + R"(</Time>
<Items/>
</PatrolDevice>)";
// Construct complete protocol message: 16-byte header + XML data
unsigned short xmlLength = xmlData.length();
char message[16 + xmlLength];
x30ProtocolHeader* header = (x30ProtocolHeader*)message;
header->sync1 = 0xEB;
header->sync2 = 0x90;
header->sync3 = 0xEB;
header->sync4 = 0x90;
header->dataLength = xmlLength;
header->messageID = 1;
memset(header->reserved, 0x00, 8);
memcpy(message + 16, xmlData.c_str(), xmlLength);
// Send status query command
std::cout << "Sending status query request..." << std::endl;
ssize_t send_len = send(client_fd, message, 16 + xmlLength, 0);
if (send_len < 0) {
perror("Send failed");
close(client_fd);
return -1;
}
std::cout << "Sent successfully: " << send_len << " bytes" << std::endl;
// Receive robot dog response
char responseBuffer[4096];
ssize_t recv_len = recv(client_fd, responseBuffer, sizeof(responseBuffer) - 1, 0);
if (recv_len > 0) {
responseBuffer[recv_len] = '\0';
std::cout << "\n=== Received robot dog status response ===" << std::endl;
std::cout << "Response length: " << recv_len << " bytes" << std::endl;
if(recv_len > 16) {
std::string responseXml(responseBuffer + 16, recv_len - 16);
std::cout << "Response content:" << std::endl;
std::cout << responseXml << std::endl;
auto parseField = [&](const std::string& field) -> std::string {
size_t start = responseXml.find("<" + field + ">");
if (start == std::string::npos) return "Unknown";
start += field.length() + 2;
size_t end = responseXml.find("</" + field + ">", start);
if (end == std::string::npos) return "Unknown";
return responseXml.substr(start, end - start);
};
std::cout << "\n=== Key Status Information ===" << std::endl;
std::cout << "Position: (" << parseField("PosX") << ", " << parseField("PosY") << ", " << parseField("PosZ") << ")" << std::endl;
std::cout << "Orientation: (" << parseField("Roll") << ", " << parseField("Pitch") << ", " << parseField("Yaw") << ")" << std::endl;
std::cout << "Speed: " << parseField("Speed") << " m/s" << std::endl;
std::cout << "Battery: " << parseField("Electricity") << "%" << std::endl;
std::string motionState = parseField("MotionState");
std::cout << "Motion state: " << motionState;
if (motionState == "0") std::cout << " (Lying down)";
else if (motionState == "1") std::cout << " (Standing up)";
else if (motionState == "2") std::cout << " (Initial standing)";
else if (motionState == "3") std::cout << " (Force-controlled standing)";
else if (motionState == "4") std::cout << " (Stepping)";
else if (motionState == "5") std::cout << " (Lying down)";
else if (motionState == "6") std::cout << " (Soft emergency stop)";
else if (motionState == "7") std::cout << " (Fall)";
std::cout << std::endl;
std::string controlMode = parseField("ControlMode");
std::cout << "Control mode: " << (controlMode == "0" ? "Manual mode" : "Auto mode") << std::endl;
}
} else {
std::cout << "No response received" << std::endl;
}
close(client_fd);
std::cout << "\nConnection closed" << std::endl;
return 0;
}
  • Network connectivity: Ensure X30 and the monitoring host are on the same network segment, and TCP port 30000 is accessible
  • Configuration consistency: The port number in network.toml must match the monitoring program’s listening port, and IP addresses must be the actual IP addresses of the monitoring host