Skip to content

4.13 C99 SubPub 구독/발행 인터페이스

개요

C99 SubPub 은 WebSocket 구독/발행 기능을 제공합니다. 연결, 연결 해제, 원시 텍스트 전송, 백그라운드 수신 시작, 동기 수신, 상태/레지스터/IO 구독을 포함합니다.

해당 헤더 파일:

  • include/c_arm_sub_pub.h

권장 호출 순서

단계인터페이스설명
1Arm_Connect로봇 세션을 생성합니다.
2Arm_SubPub_ConnectSubPub WebSocket 연결을 생성합니다. 프록시 포트 5609 를 고정으로 사용합니다.
3Arm_SubPub_StartReceiving백그라운드 수신을 시작하고 메시지 콜백을 등록합니다.
4Arm_SubPub_SubscribeStatus / Arm_SubPub_SubscribeRegister / Arm_SubPub_SubscribeIo상태, 레지스터 또는 IO 구독을 시작합니다.
5Arm_SubPub_Receive필요할 때 SDK 수신 큐에서 메시지를 동기적으로 가져옵니다.
6Arm_SubPub_DisconnectSubPub 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 , 연결 timeout 시간, 단위는 초
반환값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 , 수신 timeout 시간, 단위는 밀리초
outBuf : char* , 호출자가 할당하는 출력 문자열 버퍼
bufSize : size_t , 끝의 \0 공간을 포함한 출력 버퍼 크기
outLen : size_t* , 출력 메시지에 필요한 총 바이트 수. 끝의 \0 을 포함합니다.
반환값STATUS_CODE 정수값. 0 은 성공을 의미하며, 그 외 값은 상태 코드로 처리합니다.
비고timeout 시 수신 timeout 상태 코드를 반환합니다. 미연결 상태에서는 미연결 상태 코드를 반환합니다. 버퍼가 부족하면 outLen 에 필요한 바이트 수를 씁니다.

Arm_SubPub_SubscribeStatus

c
int Arm_SubPub_SubscribeStatus(ArmHandle* h, const int* topics, size_t count, int frequency);
항목설명
설명로봇 상태 topic을 구독합니다.
요청 파라미터h : ArmHandle* , C99 세션 핸들. 일반적으로 Arm_Create() 에서 얻으며, 업무 인터페이스 호출 전 연결이 성공해야 합니다.
topics : const int* , 상태 topic 배열
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);
항목설명
설명레지스터 topic을 구독합니다.
요청 파라미터h : ArmHandle* , C99 세션 핸들. 일반적으로 Arm_Create() 에서 얻으며, 업무 인터페이스 호출 전 연결이 성공해야 합니다.
regType : int , 레지스터 topic 타입
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 topic을 구독합니다.
요청 파라미터h : ArmHandle* , C99 세션 핸들. 일반적으로 Arm_Create() 에서 얻으며, 업무 인터페이스 호출 전 연결이 성공해야 합니다.
ioTypes : const int* , IO topic 타입 배열
ioIds : const int* , IO 번호 배열
count : size_t , 배열 요소 수
frequency : int , 구독 주파수 파라미터
반환값STATUS_CODE 정수값. 0 은 성공을 의미하며, 그 외 값은 상태 코드로 처리합니다.

콜백 및 topic

c
typedef void (*ArmSubPubMessageCallback)(const char* jsonStr, size_t len);
타입설명
ArmRobotTopicType로봇 상태 topic. 예: ARM_ROBOT_TOPIC_JOINT_POSITION , ARM_ROBOT_TOPIC_SERVO_STATUS
ArmRegTopicType레지스터 topic. ARM_REG_TOPIC_R , ARM_REG_TOPIC_MR , ARM_REG_TOPIC_SR , ARM_REG_TOPIC_PR 등을 포함합니다.
ArmIoTopicTypeIO topic. ARM_IO_TOPIC_DI , ARM_IO_TOPIC_DO , ARM_IO_TOPIC_AI , ARM_IO_TOPIC_AO 등을 포함합니다.
항목규칙
jsonStrUTF-8 JSON 텍스트
len텍스트 길이. 끝의 \0 은 포함하지 않습니다.
콜백 스레드WebSocket 메시지가 도착한 스레드
ReceiveoutLen 은 필요한 총 바이트 수를 기록하며 끝의 \0 을 포함합니다.
버퍼 부족Arm_SubPub_ReceiveBUFFER_TOO_SMALL 을 반환합니다.
수신 큐SDK 수신 큐 한도는 100 개이며, 한도를 초과하면 가장 오래된 메시지를 버립니다.
콜백 덮어쓰기같은 인스턴스에서 나중에 등록한 콜백이 이전 콜백을 덮어씁니다.
콜백 재진입콜백 안에서 연결, 연결 해제, 수신 시작, 콜백 제거 계열 인터페이스를 직접 호출하지 마십시오.

콜백에서는 가벼운 처리만 수행하고, 시간이 오래 걸리는 로직은 업무 스레드로 넘기십시오.

연결 및 구독 규칙

항목설명
WebSocket 포트SubPub은 프록시 포트 5609 를 고정으로 사용합니다.
빈 주소 연결teachPanelIpNULL 또는 빈 문자열이면 Arm_Connect() 에 바인딩된 주소를 사용합니다.
다중 인스턴스여러 ArmHandle* 가 각각 SubPub 연결을 생성할 수 있습니다. 그중 하나를 끊어도 다른 인스턴스는 각자의 연결 상태를 유지합니다.
구독 주파수frequency 단위는 Hz입니다. 상태, 레지스터, IO 구독 모두 이 주파수 필드를 사용합니다.
원시 텍스트Arm_SubPub_SendText 는 디버깅 또는 사용자 정의 프로토콜에 사용합니다. 일반 상태, 레지스터, IO 데이터는 구독 인터페이스를 우선 사용하십시오.

최소 호출 예제

c
#include <stdio.h>  // SubPub 연결 상태를 출력하기 위한 printf
#include "c_arm_api.h"  // C99 SDK 최상위 헤더
int main(void)  // 예제 프로그램 진입점
{  // 예제 main 함수 시작
    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;  // 연결 결과에 따라 반환
}  // 예제 main 함수 종료

시나리오 예제

c
void OnMessage(const char* jsonStr, size_t len)  // 메시지 콜백 정의
{  // 메시지 콜백 시작
    (void)jsonStr;  // 예제에서 JSON 텍스트 보관
    (void)len;  // 예제에서 텍스트 길이 보관
}  // 메시지 콜백 종료
int topics[1] = {ARM_ROBOT_TOPIC_JOINT_POSITION};  // 로봇 상태 topic 목록 준비
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);  // 관절 위치 topic 구독
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;
}