3.13 TopicPubSub Subscribe/Publish Class
Overview
TopicPubSub provides WebSocket-based real-time subscribe/publish capabilities. The recommended entry point is Arm::sub_pub :
- Call
Arm::Connect()first. - Then call
arm.sub_pub.Connect(). - Start receiving.
- Subscribe to status / register / IO topics.
Recommended Usage
cpp
Arm arm;
STATUS_CODE ret = arm.Connect("10.27.1.254");
if (ret != STATUS_CODE::OK) {
return;
}
ret = arm.sub_pub.Connect();if (ret != STATUS_CODE::OK) {
arm.Disconnect();
return;
}
arm.sub_pub.StartReceiving( [](const Json::Value& message) {
// Parse message here; hand time-consuming work to an application thread.
}
);
arm.topicPubSub.SubscribeStatus({RobotTopicType::JOINT_POSITION});Scenario Examples
The snippets below cover connection and receiving, topic subscription, active send/receive, and connection cleanup. They assume the arm object has already completed Arm::Connect() .
Connect and Start Callback Receiving
cpp
STATUS_CODE connectRet = arm.sub_pub.Connect("", 10);
if (connectRet != STATUS_CODE::OK || !arm.sub_pub.IsConnected()) {
return;
}
STATUS_CODE receiveRet = arm.sub_pub.StartReceiving(
[](const Json::Value& message) {
const Json::Value copy = message;
(void)copy;
}
);Subscribe to Status, Register, and IO Topics
cpp
STATUS_CODE statusRet = arm.sub_pub.SubscribeStatus(
{RobotTopicType::JOINT_POSITION},
200
);
STATUS_CODE regRet = arm.sub_pub.SubscribeRegister(
RegTopicType::R,
{1, 2},
100
);
STATUS_CODE ioRet = arm.sub_pub.SubscribeIo(
{{IOTopicType::DI, 1}},
50
);Send Text and Read from the Queue
cpp
STATUS_CODE sendRet = arm.sub_pub.SendText("{\"cmd\":\"ping\"}");
auto [message, messageRet] = arm.sub_pub.Receive(1000);
(void)sendRet;
(void)message;
(void)messageRet;Remove Callback and Disconnect
cpp
STATUS_CODE removeRet = arm.sub_pub.RemoveMessageHandler();
STATUS_CODE disconnectRet = arm.sub_pub.Disconnect();
(void)removeRet;
(void)disconnectRet;Example code:
cpp
#include "multi_instance_isolation/run.h"
#include "subscribe_topics/run.h"
#include "send_receive_text/run.h"
int main(void)
{
// [ZH] 默认只调用一个门面方法;如需体验其他接口,请把下一行替换成下面任意一行。
// [EN] The main function calls only one facade by default. Replace the next line with any line below to try other APIs.
return RunSubPubBasicSubscribeTopics();
// return RunSubPubBasicSendReceiveText();
// return RunSubPubBasicMultiInstanceIsolation();
}Interface Overview
cpp
Connect(const std::string& teachPanelIp = "", int32_t timeoutSecs = 10) -> STATUS_CODE
IsConnected() const -> bool
StartReceiving(const MessageHandler& handler) -> STATUS_CODE
SubscribeStatus(const std::vector<ROBOT_TOPIC_TYPE>& topics, int32_t frequency = 200) -> STATUS_CODE
SubscribeRegister(const REG_TOPIC_TYPE& regType, const std::vector<int32_t>& regIds, int32_t frequency = 200) -> STATUS_CODE
SubscribeIo(const std::vector<std::pair<IO_TOPIC_TYPE, int32_t>>& ioList, int32_t frequency = 200) -> STATUS_CODE
SendText(const std::string& text) -> STATUS_CODE
RemoveMessageHandler() -> STATUS_CODE
Receive(int32_t timeoutMs = 5000) -> std::pair<Json::Value, STATUS_CODE>
Disconnect() -> STATUS_CODE| Method | Input | Output | Key Behavior |
|---|---|---|---|
Connect | Optional address, handshake timeout in seconds | STATUS_CODE | When the address is empty, uses the TP/IP bound during Arm::Connect() first |
IsConnected | None | bool | Reflects only the sub_pub WebSocket connection state |
StartReceiving | One JSON callback | STATUS_CODE | Starts background receiving; a later callback replaces the previous one |
SubscribeStatus | Topic list, frequency | STATUS_CODE | Sends the addTopic command |
SubscribeRegister | Register type, ID list, frequency | STATUS_CODE | Sends the addRegTopic command |
SubscribeIo | IO type + ID list, frequency | STATUS_CODE | Sends the addIoTopic command |
SendText | Raw text | STATUS_CODE | Sends raw text |
RemoveMessageHandler | None | STATUS_CODE | Removes the active callback without affecting the SDK receive queue |
Receive | Timeout in milliseconds | std::pair<Json::Value, STATUS_CODE> | Reads the next message from the SDK receive queue |
Disconnect | None | STATUS_CODE | Closes the current WebSocket connection |
Detailed Semantics
Connect
Signature
cpp
STATUS_CODE Connect(const std::string& teachPanelIp = "", int32_t timeoutSecs = 10);| Item | Description |
|---|---|
teachPanelIp | Uses the explicitly passed address. When empty, uses the target address already bound by Arm::Connect() first |
timeoutSecs | WebSocket handshake timeout, default 10 seconds |
| Return | OK / INVALID_IP_ADDRESS / other error codes from the connection phase |
Constraints and Behavior
- When using
arm.sub_pub, usually call parameterlessConnect(). - When instantiating
TopicPubSubseparately, an address must be passed explicitly. - Fixed proxy WebSocket port
5609is used. - If the same
TopicPubSubinstance is already connected, calling again returnsOKand reuses the current connection. - Multiple
Arm/TopicPubSubinstances can coexist concurrently in the same process. Disconnecting one instance does not affect the WebSocket network environment of other instances. Multi-instance isolation example:
cpp
#include <iostream>
#include <json/json.h>
#include <string>
#include <utility>
#include "arm_api.h"
#include "status_code.h"
#include "multi_instance_isolation/run.h"
namespace {
std::pair<Json::Value, STATUS_CODE> SendPingAndReceive(
Arm& arm,
const std::string& source
)
{
Json::Value request;
request["cmd"] = "ping";
request["param"]["source"] = source;
Json::StreamWriterBuilder builder;
builder["indentation"] = "";
STATUS_CODE sendRet = arm.topicPubSub.SendText(Json::writeString(builder, request));
if (sendRet != STATUS_CODE::OK) {
return std::make_pair(Json::Value(), sendRet);
}
return arm.topicPubSub.Receive(5000);
}
} // namespace
/**
* 多实例 TopicPubSub 隔离门面。
* @return 0 表示成功,否则返回 1。
*/
int RunSubPubBasicMultiInstanceIsolation(void)
{
// [ZH] 请把下面地址替换成当前机器人控制器 IP 和示教器 IP。
// [EN] Replace the following addresses with the current controller IP and teach panel IP.
const std::string controllerIp = "10.27.1.2";
const std::string teachPanelIp = "10.27.1.102";
Arm armA;
Arm armB;
STATUS_CODE armConnectRetA = armA.Connect(controllerIp, teachPanelIp);
STATUS_CODE armConnectRetB = armB.Connect(controllerIp, teachPanelIp);
if (armConnectRetA != STATUS_CODE::OK || armConnectRetB != STATUS_CODE::OK) {
std::cerr << "[cpp17_sub_pub] 多实例连接失败 / Multi-instance connect failed, A="
<< static_cast<int>(armConnectRetA) << ", B="
<< static_cast<int>(armConnectRetB) << "\n";
armA.Disconnect();
armB.Disconnect();
return 1;
}
STATUS_CODE subPubConnectRetA = armA.topicPubSub.Connect(teachPanelIp, 10);
STATUS_CODE subPubConnectRetB = armB.topicPubSub.Connect(teachPanelIp, 10);
auto [ackA, ackRetA] = SendPingAndReceive(armA, "cpp17_multi_instance_A");
STATUS_CODE disconnectRetA = armA.topicPubSub.Disconnect();
auto [ackB, ackRetB] = SendPingAndReceive(
armB,
"cpp17_multi_instance_B_after_A_disconnect"
);
STATUS_CODE disconnectRetB = armB.topicPubSub.Disconnect();
Json::StreamWriterBuilder builder;
builder["indentation"] = "";
std::cout << "[cpp17_sub_pub] ArmA Connect 状态码 / ArmA connect status code: "
<< static_cast<int>(subPubConnectRetA) << "\n";
std::cout << "[cpp17_sub_pub] ArmB Connect 状态码 / ArmB connect status code: "
<< static_cast<int>(subPubConnectRetB) << "\n";
std::cout << "[cpp17_sub_pub] ArmA Receive 状态码 / ArmA receive status code: "
<< static_cast<int>(ackRetA) << ", 消息 / Message: "
<< Json::writeString(builder, ackA) << "\n";
std::cout << "[cpp17_sub_pub] ArmA Disconnect 状态码 / ArmA disconnect status code: "
<< static_cast<int>(disconnectRetA) << "\n";
std::cout << "[cpp17_sub_pub] ArmB Receive 状态码 / ArmB receive status code: "
<< static_cast<int>(ackRetB) << ", 消息 / Message: "
<< Json::writeString(builder, ackB) << "\n";
std::cout << "[cpp17_sub_pub] ArmB Disconnect 状态码 / ArmB disconnect status code: "
<< static_cast<int>(disconnectRetB) << "\n";
armA.Disconnect();
armB.Disconnect();
std::cout << "[cpp17_sub_pub] 多实例隔离示例结束 / Multi-instance isolation example finished\n";
const bool success =
subPubConnectRetA == STATUS_CODE::OK &&
subPubConnectRetB == STATUS_CODE::OK &&
ackRetA == STATUS_CODE::OK &&
disconnectRetA == STATUS_CODE::OK &&
ackRetB == STATUS_CODE::OK &&
disconnectRetB == STATUS_CODE::OK;
return success ? 0 : 1;
}IsConnected
Signature
cpp
bool IsConnected() const;Constraints and Behavior
- This checks the sub_pub WebSocket, not the
ArmHTTP session. - After
Arm::Connect()succeeds,arm.sub_pub.IsConnected()is stillfalse; it becomestrueonly afterarm.sub_pub.Connect()succeeds.
StartReceiving
Signature
cpp
STATUS_CODE StartReceiving(const MessageHandler& handler);Input
| Parameter | Type | Description |
|---|---|---|
handler | std::function<void(const Json::Value&)> | Message callback |
Output
- Success: returns
OK - Not connected: returns
NOT_CONNECTED
Constraints and Behavior
- One
TopicPubSubinstance keeps only one active callback. A later call replaces the previous callback. - The callback receives an already parsed
Json::Value. - The callback is triggered when a WebSocket message arrives.
- The SDK receive queue limit is
100messages. When the limit is exceeded, the oldest messages are discarded. - Keep callback logic lightweight. Move time-consuming work to an application thread.
- Do not directly call
Arm::Connect(),Arm::Disconnect(),SubPub::Connect(),SubPub::Disconnect(),StartReceiving(), orRemoveMessageHandler()from the callback. These reentrant operations may returnOTHER_ERRor have no effect.
SubscribeStatus
Signature
cpp
STATUS_CODE SubscribeStatus(
const std::vector<ROBOT_TOPIC_TYPE>& topics,
int32_t frequency = 200
);| Item | Description |
|---|---|
topics | Topic list to subscribe to. See ROBOT_TOPIC_TYPE constants |
frequency | Subscription frequency in Hz, default 200 |
| Subscription behavior | Adds robot status topics |
SubscribeRegister
Signature
cpp
STATUS_CODE SubscribeRegister(
const REG_TOPIC_TYPE& regType,
const std::vector<int32_t>& regIds,
int32_t frequency = 200
);| Item | Description |
|---|---|
regType | Register type. See REG_TOPIC_TYPE |
regIds | Register ID list |
frequency | Subscription frequency in Hz |
| Subscription behavior | Adds register topics |
SubscribeIo
Signature
cpp
STATUS_CODE SubscribeIo(
const std::vector<std::pair<IO_TOPIC_TYPE, int32_t>>& ioList,
int32_t frequency = 200
);| Item | Description |
|---|---|
ioList | Each item is (ioType, ioId) |
frequency | Subscription frequency in Hz |
| Subscription behavior | Adds IO topics |
SendText
Signature
cpp
STATUS_CODE SendText(const std::string& text);Sends raw text directly. If you only need status, register, or IO subscriptions, prefer the subscription APIs above.
RemoveMessageHandler
Signature
cpp
STATUS_CODE RemoveMessageHandler();Constraints and Behavior
- One
TopicPubSubinstance has only one active callback, so this removes the current callback. - After the callback is removed,
Receive()can still read from the SDK receive queue. - Returns
OKeven if it is not currently connected.
Receive
Signature
cpp
std::pair<Json::Value, STATUS_CODE> Receive(int32_t timeoutMs = 5000);| Item | Description |
|---|---|
timeoutMs | Timeout, default 5000ms |
| Success return | Json::Value + OK |
| Timeout return | Empty Json::Value + SUB_PUB_RECEIVE_TIMEOUT |
| Disconnected return | Empty Json::Value + NOT_CONNECTED |
Disconnect
Signature
cpp
STATUS_CODE Disconnect();Disconnects the current WebSocket connection. If it is not currently connected, returns OK .