Skip to content

4.13 C99 SubPub 订阅发布接口

概述

C99 SubPub 提供 WebSocket 订阅发布能力,包含连接、断开、发送原始文本、启动后台接收、同步接收、订阅状态 / 寄存器 / IO。

对应头文件:

  • include/c_arm_sub_pub.h

推荐调用顺序

步骤接口说明
1Arm_Connect建立机器人会话。
2Arm_SubPub_Connect建立 SubPub WebSocket 连接;固定使用代理端口 5609
3Arm_SubPub_StartReceiving启动后台接收并注册消息回调。
4Arm_SubPub_SubscribeStatus / Arm_SubPub_SubscribeRegister / Arm_SubPub_SubscribeIo发起状态、寄存器或 IO 订阅。
5Arm_SubPub_Receive按需从 SDK 接收队列同步取消息。
6Arm_SubPub_Disconnect断开 SubPub WebSocket 连接。

接口签名

Arm_SubPub_Connect

c
int Arm_SubPub_Connect(ArmHandle* h, const char* teachPanelIp, int timeoutSecs);
说明
描述建立 SubPub WebSocket 连接。
请求参数h : ArmHandle* ,C99 会话句柄,通常来自 Arm_Create() ,业务接口需要先连接成功
teachPanelIp : const char* ,示教器地址;传 NULL 或空字符串时使用当前 Arm 会话绑定地址
timeoutSecs : int ,连接超时时间,单位秒
返回值STATUS_CODE 整数值; 0 表示成功,其他值按状态码处理
备注teachPanelIp 为空时使用当前 Arm 会话绑定的地址;同一实例已连接时再次调用返回成功,不重建连接。

Arm_SubPub_Disconnect

c
int Arm_SubPub_Disconnect(ArmHandle* h);
说明
描述断开 SubPub WebSocket 连接。
请求参数h : ArmHandle* ,C99 会话句柄,通常来自 Arm_Create() ,业务接口需要先连接成功
返回值STATUS_CODE 整数值; 0 表示成功,其他值按状态码处理

Arm_SubPub_IsConnected

c
int Arm_SubPub_IsConnected(ArmHandle* h);
说明
描述查询 SubPub 是否连接。
请求参数h : ArmHandle* ,C99 会话句柄,通常来自 Arm_Create() ,业务接口需要先连接成功
返回值已连接返回非 0 ,未连接返回 0
备注只表示 SubPub WebSocket 状态,不表示 Arm HTTP 会话状态。

Arm_SubPub_SendText

c
int Arm_SubPub_SendText(ArmHandle* h, const char* text);
说明
描述发送原始文本消息。
请求参数h : ArmHandle* ,C99 会话句柄,通常来自 Arm_Create() ,业务接口需要先连接成功
text : const char* ,待发送的原始文本
返回值STATUS_CODE 整数值; 0 表示成功,其他值按状态码处理

Arm_SubPub_StartReceiving

c
int Arm_SubPub_StartReceiving(ArmHandle* h, ArmSubPubMessageCallback callback);
说明
描述启动后台消息接收。
请求参数h : ArmHandle* ,C99 会话句柄,通常来自 Arm_Create() ,业务接口需要先连接成功
callback : ArmSubPubMessageCallback ,消息回调函数,收到 WebSocket 文本时调用
返回值STATUS_CODE 整数值; 0 表示成功,其他值按状态码处理
备注同一 SubPub 实例只保留一个活动回调,后一次调用会覆盖前一次。

Arm_SubPub_RemoveMessageHandler

c
int Arm_SubPub_RemoveMessageHandler(ArmHandle* h);
说明
描述移除消息回调。
请求参数h : ArmHandle* ,C99 会话句柄,通常来自 Arm_Create() ,业务接口需要先连接成功
返回值STATUS_CODE 整数值; 0 表示成功,其他值按状态码处理
备注移除当前活动回调,不清空 SDK 接收队列;未连接时调用也按成功处理。

Arm_SubPub_Receive

c
int Arm_SubPub_Receive(ArmHandle* h, int timeoutMs, char* outBuf, size_t bufSize, size_t* outLen);
说明
描述同步接收一条消息。
请求参数h : ArmHandle* ,C99 会话句柄,通常来自 Arm_Create() ,业务接口需要先连接成功
timeoutMs : int ,接收超时时间,单位毫秒
outBuf : char* ,输出字符串缓冲区,由调用方分配
bufSize : size_t ,输出缓冲区大小,包含结尾 \0 的空间
outLen : size_t* ,输出消息所需总字节数,包含结尾 \0
返回值STATUS_CODE 整数值; 0 表示成功,其他值按状态码处理
备注超时返回接收超时状态码;未连接返回未连接状态码;缓冲区不足时 outLen 写入所需字节数。

Arm_SubPub_SubscribeStatus

c
int Arm_SubPub_SubscribeStatus(ArmHandle* h, const int* topics, size_t count, int frequency);
说明
描述订阅机器人状态主题。
请求参数h : ArmHandle* ,C99 会话句柄,通常来自 Arm_Create() ,业务接口需要先连接成功
topics : const int* ,状态主题数组
count : size_t ,数组元素数量
frequency : int ,订阅频率参数
返回值STATUS_CODE 整数值; 0 表示成功,其他值按状态码处理

Arm_SubPub_SubscribeRegister

c
int Arm_SubPub_SubscribeRegister(ArmHandle* h, int regType, const int* regIds, size_t count, int frequency);
说明
描述订阅寄存器主题。
请求参数h : ArmHandle* ,C99 会话句柄,通常来自 Arm_Create() ,业务接口需要先连接成功
regType : int ,寄存器主题类型
regIds : const int* ,寄存器编号数组
count : size_t ,数组元素数量
frequency : int ,订阅频率参数
返回值STATUS_CODE 整数值; 0 表示成功,其他值按状态码处理

Arm_SubPub_SubscribeIo

c
int Arm_SubPub_SubscribeIo(ArmHandle* h, const int* ioTypes, const int* ioIds, size_t count, int frequency);
说明
描述订阅 IO 主题。
请求参数h : ArmHandle* ,C99 会话句柄,通常来自 Arm_Create() ,业务接口需要先连接成功
ioTypes : const int* ,IO 主题类型数组
ioIds : const int* ,IO 编号数组
count : size_t ,数组元素数量
frequency : int ,订阅频率参数
返回值STATUS_CODE 整数值; 0 表示成功,其他值按状态码处理

回调和 topic

c
typedef void (*ArmSubPubMessageCallback)(const char* jsonStr, size_t len);
类型说明
ArmRobotTopicType机器人状态主题,例如 ARM_ROBOT_TOPIC_JOINT_POSITIONARM_ROBOT_TOPIC_SERVO_STATUS
ArmRegTopicType寄存器主题,包含 ARM_REG_TOPIC_RARM_REG_TOPIC_MRARM_REG_TOPIC_SRARM_REG_TOPIC_PR
ArmIoTopicTypeIO 主题,包含 ARM_IO_TOPIC_DIARM_IO_TOPIC_DOARM_IO_TOPIC_AIARM_IO_TOPIC_AO
规则
jsonStrUTF-8 JSON 文本
len文本长度,不含结尾 \0
回调线程WebSocket 消息到达线程
ReceiveoutLen 回写所需总字节数,包含结尾 \0
缓冲区不足Arm_SubPub_Receive 返回 BUFFER_TOO_SMALL
接收队列SDK 接收队列上限为 100 条,超过上限时丢弃最旧消息
回调覆盖同一实例后注册的回调会覆盖前一次回调
回调重入回调中避免直接调用连接、断开、启动接收或移除回调类接口

回调里只做轻量处理,耗时逻辑转交业务线程。

连接与订阅规则

说明
WebSocket 端口SubPub 固定使用代理端口 5609
空地址连接teachPanelIpNULL 或空字符串时,使用 Arm_Connect() 绑定的地址。
多实例多个 ArmHandle* 可分别建立 SubPub 连接;断开其中一个时,其他实例保持各自连接状态。
订阅频率frequency 单位为 Hz;状态、寄存器、IO 订阅都使用该频率字段。
原始文本Arm_SubPub_SendText 用于调试或自定义协议;常规状态、寄存器、IO 数据优先使用订阅接口。

最小调用示例

c
#include <stdio.h>  // 引入 printf,用于打印 SubPub 连接状态
#include "c_arm_api.h"  // 引入 C99 SDK 总头文件
int main(void)  // 示例程序入口
{  // 进入示例主函数
    ArmHandle* h = Arm_Create();  // 创建 C99 会话句柄
    if (h == NULL) {  // 判断句柄是否创建失败
        return 1;  // 创建失败时退出
    }  // 结束句柄判断
    if (Arm_Connect(h, "10.27.1.2", "10.27.1.102") != 0) {  // 连接控制器
        Arm_Destroy(h);  // 连接失败时释放句柄
        return 1;  // 返回错误
    }  // 结束连接判断
    int ret = Arm_SubPub_Connect(h, "10.27.1.102", 10);  // 建立 SubPub 连接
    printf("sub_pub_connected=%d\n", Arm_SubPub_IsConnected(h));  // 打印 SubPub 连接状态
    Arm_SubPub_Disconnect(h);  // 断开 SubPub 连接
    Arm_Disconnect(h);  // 断开机器人连接
    Arm_Destroy(h);  // 销毁句柄
    return ret == 0 ? 0 : 1;  // 根据连接结果返回
}  // 结束示例主函数

场景化示例

c
void OnMessage(const char* jsonStr, size_t len)  // 定义消息回调
{  // 进入消息回调
    (void)jsonStr;  // 示例中保留 JSON 文本
    (void)len;  // 示例中保留文本长度
}  // 结束消息回调
int topics[1] = {ARM_ROBOT_TOPIC_JOINT_POSITION};  // 准备机器人状态主题列表
int regIds[2] = {1, 2};  // 准备寄存器编号列表
int ioTypes[1] = {ARM_IO_TOPIC_DI};  // 准备 IO 类型列表
int ioIds[1] = {1};  // 准备 IO 编号列表
char msg[2048] = {0};  // 准备同步接收缓冲区
size_t msgLen = 0U;  // 准备接收消息长度
int connectRet = Arm_SubPub_Connect(h, NULL, 10);  // 建立 SubPub 连接
int receiveRet = Arm_SubPub_StartReceiving(h, OnMessage);  // 启动后台接收
int statusRet = Arm_SubPub_SubscribeStatus(h, topics, 1, 200);  // 订阅关节位置主题
int regRet = Arm_SubPub_SubscribeRegister(h, ARM_REG_TOPIC_R, regIds, 2, 100);  // 订阅 R1 / R2
int ioRet = Arm_SubPub_SubscribeIo(h, ioTypes, ioIds, 1, 50);  // 订阅 DI1
int textRet = Arm_SubPub_SendText(h, "{\"cmd\":\"ping\"}");  // 发送原始文本
int syncRet = Arm_SubPub_Receive(h, 1000, msg, sizeof(msg), &msgLen);  // 同步接收一条消息
int removeRet = Arm_SubPub_RemoveMessageHandler(h);  // 移除消息回调
int disconnectRet = Arm_SubPub_Disconnect(h);  // 断开 SubPub 连接
(void)connectRet;  // 示例中保留状态码
(void)receiveRet;  // 示例中保留状态码
(void)statusRet;  // 示例中保留状态码
(void)regRet;  // 示例中保留状态码
(void)ioRet;  // 示例中保留状态码
(void)textRet;  // 示例中保留状态码
(void)syncRet;  // 示例中保留状态码
(void)removeRet;  // 示例中保留状态码
(void)disconnectRet;  // 示例中保留状态码

示例代码

c99/sub_pub_basic/src/main.cpp
cpp
#include <stdio.h>

extern "C" {
#include "c_arm_api.h"
}

int main(void)
{
    // [ZH] 本示例直接在源码中写死连接地址,不解析命令行参数。
    // [EN] This example hard-codes the connection addresses in the source code and does not parse command-line arguments.
    // [ZH] 创建并连接 SDK 句柄。
    // [EN] Create the SDK handle and connect to the robot.
    ArmHandle* handle = Arm_Create();
    if (handle == NULL) {
        printf("[c99_sub_pub] 创建句柄失败 / Failed to create the handle\n");
        return 1;
    }
    int ret = Arm_Connect(handle, "10.27.1.2", "10.27.1.102");
    if (ret != 0) {
        printf("[c99_sub_pub] 连接失败 / Connect failed, 状态码 / Status code: %d\n", ret);
        Arm_Destroy(handle);
        return 1;
    }
    printf("[c99_sub_pub] 机器人连接成功 / Robot connected successfully\n");

    // [ZH] 建立订阅连接并打印连接状态。
    // [EN] Establish the subscription connection and print the connection state.
    ret = Arm_SubPub_Connect(handle, "10.27.1.102", 10);
    printf("[c99_sub_pub] Connect 状态码 / Connect status code: %d\n", ret);
    printf("[c99_sub_pub] 当前连接状态 / Current connection state: %d\n", Arm_SubPub_IsConnected(handle));

    // [ZH] 顺序执行回调注册、主题订阅、发送和接收接口。
    // [EN] Execute the callback registration, subscriptions, send, and receive APIs in sequence.
    ret = Arm_SubPub_StartReceiving(handle, NULL);
    printf("[c99_sub_pub] StartReceiving 状态码 / StartReceiving status code: %d\n", ret);
    int statusTopics[1] = {ARM_ROBOT_TOPIC_JOINT_POSITION};
    ret = Arm_SubPub_SubscribeStatus(handle, statusTopics, 1U, 200);
    printf("[c99_sub_pub] SubscribeStatus 状态码 / SubscribeStatus status code: %d\n", ret);
    int regIds[2] = {1, 2};
    ret = Arm_SubPub_SubscribeRegister(handle, ARM_REG_TOPIC_R, regIds, 2U, 200);
    printf("[c99_sub_pub] SubscribeRegister 状态码 / SubscribeRegister status code: %d\n", ret);
    int ioTypes[1] = {ARM_IO_TOPIC_DI};
    int ioIds[1] = {1};
    ret = Arm_SubPub_SubscribeIo(handle, ioTypes, ioIds, 1U, 200);
    printf("[c99_sub_pub] SubscribeIo 状态码 / SubscribeIo status code: %d\n", ret);
    ret = Arm_SubPub_SendText(handle, "{\"cmd\":\"ping\",\"param\":{\"source\":\"c99_example\"}}");
    printf("[c99_sub_pub] SendText 状态码 / SendText status code: %d\n", ret);
    char message[2048] = {0};
    size_t messageLen = 0U;
    ret = Arm_SubPub_Receive(handle, 5000, message, sizeof(message), &messageLen);
    printf("[c99_sub_pub] Receive 状态码 / Receive status code: %d, 长度 / Length: %zu, 消息 / Message: %s\n", ret, messageLen, message);
    ret = Arm_SubPub_RemoveMessageHandler(handle);
    printf("[c99_sub_pub] RemoveMessageHandler 状态码 / RemoveMessageHandler status code: %d\n", ret);
    ret = Arm_SubPub_Disconnect(handle);
    printf("[c99_sub_pub] Disconnect 状态码 / Disconnect status code: %d\n", ret);

    // [ZH] 断开机器人连接并销毁句柄。
    // [EN] Disconnect the robot and destroy the handle.
    Arm_Disconnect(handle);
    Arm_Destroy(handle);
    printf("[c99_sub_pub] 示例结束 / Example finished\n");
    return 0;
}