Low-Level Communication Examples
Getting X30 Runtime Status via UDP
Section titled “Getting X30 Runtime Status via UDP”Purpose: Guide users to set up a status monitoring program to get X30 runtime status information reported via UDP protocol.
Configuration Steps
Section titled “Configuration Steps”Step 1: Modify X30 Motion Host Network Configuration
Section titled “Step 1: Modify X30 Motion Host Network Configuration”-
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 -
Navigate to the configuration file directory
Terminal window cd /home/ysc/jy_exe/conf -
Edit the network.toml configuration file
Terminal window vim network.toml -
Add the following configuration at the end of the file
# UDP status reporting configuration[udp_status]ip = '192.168.1.105'target_port = 43897local_port = 43893ips = ["192.168.1.105", "192.168.1.106","xxxxx"] # List of IPs receiving status messagesports = [30001, 30001, xxxxx] # List of corresponding port numbersConfiguration notes:
ips: Array of client IP addresses receiving UDP status messagesports: Corresponding array of port numbers, matching the IP addresses one-to-one- Modify IP addresses according to your actual network environment
Step 2: Restart Motion Service
Section titled “Step 2: Restart Motion Service”cd /home/ysc/jy_exe/scripts./restart.shStep 3: Compile and Run the Status Monitoring Program
Section titled “Step 3: Compile and Run the Status Monitoring Program”g++ UDPtest.cpp -o UDPtest./UDPtestStep 4: Verify Configuration
Section titled “Step 4: Verify Configuration”After the program starts normally, it will display:
Start listening for robot status reports, port: 30001When robot status data is received, it will display information similar to:
========================================Received status data [From:192.168.1.103]----------------------------------------Robot name: X30_RobotCurrent mileage: 1500 cmTotal mileage: 12500 cmCurrent runtime: 3600 secondsTotal runtime: 86400 secondsCurrent motion time: 1800 secondsTotal motion time: 43200 secondsJoystick data: [0, 0.5, 0, 0]Running mode: AutoEmergency stop source: 0Error state: 0x0========================================
UDP Status Monitoring Example Code
Section titled “UDP Status Monitoring Example Code”#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;}Getting X30 Real-Time Status via TCP
Section titled “Getting X30 Real-Time Status via TCP”Purpose: Guide users to get X30 robot dog’s real-time basic status information via TCP protocol.
Configuration Steps
Section titled “Configuration Steps”Step 1: Confirm Network Connection
Section titled “Step 1: Confirm Network Connection”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:
nc -zv 192.168.1.106 30000Step 2: Compile and Run the Status Query Program
Section titled “Step 2: Compile and Run the Status Query Program”g++ TCPtest.cpp -o TCPtest./TCPtestStep 3: Verify Configuration
Section titled “Step 3: Verify Configuration”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 successfullySending status query request...Sent successfully: 175 bytesWhen a response is received:
=== Received robot dog status response ===Response length: 689 bytesResponse 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>Feature Extension
Section titled “Feature Extension”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.
TCP Status Query Example Code
Section titled “TCP Status Query Example Code”#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 stringstd::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.tomlmust match the monitoring program’s listening port, and IP addresses must be the actual IP addresses of the monitoring host