数据类型
本篇描述 SDK 对外结构体的数据形态:源码、成员含义、字节布局。如何获取这些数据、指针能活多久,见 API 参考。
结构体按内存所有权分两类:
- SDK 填充型(订阅回调):
Pose、Point、CloudFrame、Imu、ImageFrame、ErrCodeFrame—— 由 SDK 拥有,变长指针仅回调期内有效。 - 调用方分配型(同步查询/入参):
Options、RecordStatus、各*Calib、DeviceInfo、InitPose—— 内存由调用方分配,无堆指针,无需free。
注:同一份数据在 C 头(snake_case,如
pos_x)与 C++ 头(camelCase,如posX)里字段名不同,这是遵循编码规范对两种语言的不同要求,不是笔误。C++ 结构体是 C 结构体的镜像。
基础与状态类型
Error / xg_err_t
typedef enum {
XG_OK = 0,
XG_ERR_INVALID_ARG = -1,
XG_ERR_NOT_CONNECTED = -2,
XG_ERR_TIMEOUT = -3,
XG_ERR_REJECTED = -4,
XG_ERR_DEVICE_ERROR = -5,
XG_ERR_PROTOCOL = -6,
XG_ERR_INTERNAL = -7,
} xg_err_t;
数值锁定,一经发布只允许追加。各值含义见 API 参考。
RecordState / xg_record_state_t
typedef enum {
XG_REC_IDLE = 0, // 待机,可以开始录制
XG_REC_STARTING = 1, // 启动中,尚未开始出数据
XG_REC_RECORDING = 2, // 录制中
XG_REC_STOPPING = 3, // 停止中
XG_REC_ERROR = 4, // 故障,详见 message
} xg_record_state_t;
设备内部状态远多于此,SDK 归并为五态。业务只判断 state 与 warning,不要解析 rawCode。
RecordStatus / xg_record_status_t
struct RecordStatus {
RecordState state; // 归并后的对外状态
bool warning; // 存在需关注的异常,但不阻塞当前操作
std::int32_t rawCode; // 设备原始状态码,仅供排障
std::string message; // 人可读说明,UTF-8
};
| 字段 | 类型 | 说明 |
|---|---|---|
state | 枚举 | 归并态 |
warning | bool | true = 有告警但不阻塞当前 state 允许的操作 |
rawCode | int32 | 设备原码,仅日志,跨版本不稳 |
message | string | 始终以 '\0' 结尾(C 侧为 char[256]) |
warning 典型:Recording + 建图异常(仅录包,仍可停);Idle + 上次工程后处理异常(设备仍可用)。Error 态阻塞开录。属调用方分配型,无堆指针。
Options / xg_options_t
struct Options {
std::string deviceIp{""}; // 设备 IP,必填
std::uint16_t port{0}; // 0 = 默认 7448
std::uint32_t connectTimeoutMs{0}; // 0 = 默认 5000ms
};
| C | C++ | 约束 |
|---|---|---|
device_ip[64] | deviceIp | 必填;空或过长 → InvalidArg |
port | port | modeling_app 端口;0 = 默认 7448 |
connect_timeout_ms | connectTimeoutMs | 0 = 5000 ms |
订阅数据结构(SDK 填充型)
Pose
注:SDK 对外输出的位姿以设备(IMU)系为基准(R_W_I,原点在设备 IMU 点)。载体安装变换由集成方计算。见核心概念。
struct Pose {
double timestampSec;
float posX, posY, posZ;
float quatW, quatX, quatY, quatZ;
float velX, velY, velZ;
float gyroX, gyroY, gyroZ;
std::uint32_t errorCode;
bool isLocal;
};
| C++ 字段 | 类型 | 单位 | 含义 |
|---|---|---|---|
timestampSec | double | s | 时间戳 |
posX/Y/Z | float | m | 设备 IMU 点的世界坐标 |
quatW/X/Y/Z | float | — | 单位四元数(W←I),(1,0,0,0) = 无旋转 |
velX/Y/Z | float | m/s | 设备(IMU)系线速度 |
gyroX/Y/Z | float | rad/s | 设备(IMU)系角速度 |
errorCode | uint32 | — | 定位故障码,0 = 正常 |
isLocal | bool | — | 保留字段:恒为 0,勿使用 |
字节布局(C 侧 xg_pose_t,64 位小端;跨平台以 offsetof/sizeof 为准):
| 偏移 | 字段 | 类型 | 字节 |
|---|---|---|---|
| 0 | struct_size | size_t | 8 |
| 8 | timestamp_sec | double | 8 |
| 16 | pos_x/y/z | float×3 | 12 |
| 28 | quat_w/x/y/z | float×4 | 16 |
| 44 | vel_x/y/z | float×3 | 12 |
| 56 | gyro_x/y/z | float×3 | 12 |
| 68 | error_code | uint32 | 4 |
| 72 | is_local | uint8 | 1 |
| 73 | reserved[3] | uint8×3 | 3 |
Point / xg_point_t
typedef struct { float x, y, z, intensity; } xg_point_t;
单个点的 POD 表示,C++ 直接复用。16 字节,无 padding,x/y/z/intensity 偏移 0/4/8/12。数组内存与 ROS PointCloud2 的 XYZI(float32×4)逐字节一致,可直接 memcpy。
CloudFrame
注:
subscribeCloud为设备(IMU)系、~10Hz 的重定位配准点云(NDT 产物,不是每帧雷达扫描);subscribeRawCloud为雷达系、~10Hz 的去畸变单帧。两者共用本结构体。
struct CloudFrame {
const xg_point_t* points; // 点数组,仅回调期间有效
std::size_t count; // 点数量
double timestampSec; // 时间戳(秒)
std::uint32_t seq; // 帧序号,自订阅起递增(SDK 本地序号)
};
points ─► [ point[0] | point[1] | ... | point[count-1] ]
└16B┘ 每个 = {x,y,z,intensity} float×4
points 仅回调期内有效,下一帧覆盖,留用须回调内深拷贝。
Imu
struct Imu {
double timestampSec;
float accX, accY, accZ; // m/s^2
float gyrX, gyrY, gyrZ; // rad/s
};
纯标量、无堆指针,回调参数可整体按值保存。
CameraId / xg_camera_id_t
typedef enum {
XG_CAMERA_LEFT = 0, // camera/left
XG_CAMERA_CENTER = 1, // camera/center
XG_CAMERA_RIGHT = 2, // camera/right
} xg_camera_id_t;
注:此枚举(0/1/2)与
getCameraCalib(0..3)的标定索引不是同一套映射。
ImageFrame
struct ImageFrame {
CameraId cameraId;
double timestampSec;
const uint8_t* jpegData; // JPEG 裸数据,仅回调期间有效
std::size_t jpegSize;
std::uint32_t seq;
};
回调交付的 jpegData/jpegSize 就是纯 JPEG(含 SOI/EOI),SDK 已解析掉线上的 16 字节头部。jpegData 回调返回即失效,留用须 memcpy。当前格式恒为 JPEG。
ErrCodeFrame / ErrCodeEntry
struct ErrCodeEntry {
std::uint32_t code{0};
std::uint64_t timestamp{0}; // 微秒
};
struct ErrCodeFrame {
std::vector<ErrCodeEntry> entries;
};
| 字段 | 类型 | 含义 |
|---|---|---|
code | uint32 | 模块错误码 |
timestamp | uint64 | 时间戳(微秒) |
entries | vector(C++)/ 裸指针(C) | 错误码数组 |
C 侧字节布局(xg_err_code_entry_t,注意 padding):code(4) + padding(4) + timestamp(8),sizeof == 16(非 12)。跨平台解析勿假设紧凑排布。C++ 侧 entries 是已拷出的 vector,不是裸指针。
同步查询与入参结构(调用方分配型)
内存由调用方分配,无 SDK 拥有的堆指针,字符串为定长内嵌数组,无需 free/delete;C 侧调用前须置 struct_size,C++ 封装代填。
CameraCalib
struct CameraCalib {
uint32_t width, height;
float fx, fy, cx, cy;
float distortion[4]; // kb4: k1..k4;pinhole: k1,k2,p1,p2
std::string model; // "kb4" / "pinhole"
float pose[16]; // 相对 cam0 的 4x4 变换(行优先)
bool calibrated;
};
ImuCalib
struct ImuCalib {
float accelBias[3]; // 加速度计零偏 Ba
float gyroBias[3]; // 陀螺仪零偏 Bg
float accelTransform[9]; // Ta 3x3(行优先)
float accelScale[9]; // Ka 3x3(行优先)
float gyroTransform[9]; // Tg 3x3(行优先)
float gyroScale[9]; // Kg 3x3(行优先)
float extrinsicImuLidar[16]; // T_imu_lidar:Lidar 点 → IMU 系,4x4 行优先
bool calibrated;
};
LidarCalib
struct LidarCalib {
float extrinsicImuLidar[16]; // T_imu_lidar:Lidar 点 → IMU 系,4x4 行优先
float extrinsicCameraLidar[16]; // T_cam0_lidar:Lidar 点 → Cam0 系,4x4 行优先
std::string lidarType;
bool calibrated;
};
注:矩阵一律 4×4 行优先;
T_a_b表示把 b 系下的点变换到 a 系(从右往左读)。
DeviceInfo
struct DeviceInfo {
float batteryLevel; // %
float batteryTemp; // ℃
float batteryVoltage; // V
std::int64_t diskTotalKb, diskUsedKb; // KB
std::int64_t memTotalKb, memUsedKb; // KB
std::uint8_t rtkState; // RTK 状态;X-Brain 无 RTK,恒为默认值,勿使用
std::uint8_t satelliteNum;// 卫星数;X-Brain 无 RTK,恒为默认值,勿使用
std::int32_t modelingState; // 内部建图码,仅参考,非 RecordState
};
rtkState / satelliteNum 是 SDK 头文件为带 RTK 的设备预留的字段,X-Brain 不含 RTK 模块,这两个字段恒为默认值,请勿使用。不映射设备中的电池 type/cycle、CPU 负载等字段。
InitPose
struct InitPose {
double timestampSec;
float posX, posY, posZ; // 世界/地图系位置(m)
float quatX, quatY, quatZ, quatW; // 朝向;模长须 > 0.1
};
这是重定位先验(入参),不是查询结果。写入语义见 API 参考。
工程路径
C 侧为 xg_data_path_t { char path[512]; };C++ 侧直接以 std::string* 出参:Error getDataPath(std::string* path)。
地图管理结构(重定位地图)
用于地图管理接口(uploadMap / setActiveMap / listMaps / deleteMap)。宏 XG_MAP_ID_MAX = 128(mapId 最大长度含结尾 '\0')。
MapUploadOptions
uploadMap 的入参(调用方分配型,C 须 struct_size)。
struct MapUploadOptions {
std::string localMapDir; // 本机地图数据根目录(含 location_map.las 与 loc_database/)
std::string mapId; // 地图标识,仅允许 [A-Za-z0-9_-]
std::uint32_t chunkSize{0}; // 分片字节数,0 = SDK 默认(512KB)
bool useGzip{false}; // 是否 gzip 打包,默认不压缩
};
| C++ 字段 | C 字段 | 类型 | 说明 |
|---|---|---|---|
localMapDir | local_map_dir | string / const char* | 本机地图根目录,非空 |
mapId | map_id | string / const char* | 地图标识,非空,仅 [A-Za-z0-9_-];设备端落盘为 <map_id>/ |
chunkSize | chunk_size | uint32 | 分片字节数,0 = 默认 512KB |
useGzip | use_gzip | bool / uint8 | 是否 gzip 打包,默认否 |
MapFileEntry
单个地图文件条目(MapInfo.files 的元素)。
struct MapFileEntry {
std::string path; // 相对 <mapId>/ 的路径,如 "loc_database/vlad.proto"
std::int64_t size{0}; // 文件字节数
std::int64_t mtime{0}; // 修改时间(Unix 秒)
};
注:C 侧对应
xg_map_file_entry_t,其中path为const char*,指向 SDK 内部缓冲,仅本次xg_list_maps调用有效。
MapInfo
单个地图信息(listMaps 出参的元素)。
struct MapInfo {
std::string mapId;
bool isActive{false}; // 是否为当前激活地图
std::int64_t totalSize{0}; // 该地图所有文件总字节数
std::vector<MapFileEntry> files;
};
注:C 侧对应
xg_map_info_t,map_id为定长char[XG_MAP_ID_MAX],files为const xg_map_file_entry_t*+file_count(指针仅本次调用有效)。
MapList(仅 C 侧)
C 侧 listMaps 的出参容器(调用方分配型,须 struct_size):
typedef struct {
size_t struct_size; // 必须填 sizeof(xg_map_list_t)
const xg_map_info_t* maps; // 地图信息数组,仅本次调用有效
size_t count; // 地图数量
} xg_map_list_t;
注:C 侧
maps及其内部files/path指针指向 SDK 内部缓冲,仅本次调用有效,下次调用覆盖,需持久化请立即深拷贝,禁止free/delete。C++ 侧listMaps(std::vector<MapInfo>*)已代为深拷贝,无此限制。
MapProgressCallback(仅 C 侧)
typedef void (*xg_map_progress_cb_t)(float progress, void* user_data);
上传进度回调,progress 范围 [0.0, 1.0]。C++ 侧用 std::function<void(float)> 传入。