news 2026/5/6 13:32:57

SpireMS如何发布接收消息

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpireMS如何发布接收消息

如何发布接收消息

这篇文档只回答一件事:如何用 SpireMS 在 Python 和 C++ 里发布、订阅消息。

目标:

  • 人能快速照着跑通
  • AI 能直接提取代码和步骤
  • 示例尽量短
  • 示例不依赖你本地特定的视频或图片文件

1. 先决条件

1.1 启动 Core

先启动Core,只需要启动一次:

smscore

如果你是源码开发环境,也可以直接:

python-mspirems.core

1.2 Python 环境

推荐在项目根目录执行:

python-mpipinstall-e.

如果你只是使用已发布版本:

python-mpipinstallspirems

1.3 C++ 环境

先安装 C++ SDK:

cdspirems_cppmkdir-pbuildcdbuild cmake..sudomakeinstall

如果系统还没有 OpenCV 和 CMake:

sudoaptupdatesudoaptinstall-ycmake libopencv-dev

2. Python:最常用的发布与订阅

Python 常用导入:

fromspiremsimportPublisher,Subscriber,def_msgfromspiremsimportcvimg2sms,sms2cvimg,tensor2sms,sms2tensor

2.1 字符串消息

消息类型:std_msgs::String

发布:

importtimefromspiremsimportPublisher,def_msg pub=Publisher("/demo/string","std_msgs::String")try:whileTrue:msg=def_msg("std_msgs::String")msg["data"]="hello spirems"pub.publish(msg)time.sleep(1.0)exceptKeyboardInterrupt:pub.kill()

订阅:

fromspiremsimportSubscriberdefcallback(msg):print("recv:",msg["data"])sub=Subscriber("/demo/string","std_msgs::String",callback)sub.join()

2.2 压缩图像消息

消息类型:sensor_msgs::CompressedImage

适合:

  • 普通图像传输
  • 跨机器传输
  • 对带宽比较敏感的场景

发布:

importtimeimportcv2importnumpyasnpfromspiremsimportPublisher,cvimg2sms pub=Publisher("/demo/image","sensor_msgs::CompressedImage")try:whileTrue:img=np.zeros((480,640,3),dtype=np.uint8)cv2.putText(img,"SpireMS",(180,240),cv2.FONT_HERSHEY_SIMPLEX,2.0,(0,255,0),3)msg=cvimg2sms(img,frame_id="camera")pub.publish(msg)time.sleep(0.05)exceptKeyboardInterrupt:pub.kill()

订阅:

importcv2fromspiremsimportSubscriber,sms2cvimgdefcallback(msg):img=sms2cvimg(msg)cv2.imshow("compressed image",img)cv2.waitKey(1)sub=Subscriber("/demo/image","sensor_msgs::CompressedImage",callback)sub.join()

2.3 共享内存图像消息

消息类型:memory_msgs::RawImage

适合:

  • 本机大图像低延迟传输
  • 高频图像流

注意:

  • 共享内存消息主要用于 Linux / macOS 本机进程间传输
  • 发送端和接收端需要在同一台机器上

发布:

importtimeimportcv2importnumpyasnpfromspiremsimportPublisher pub=Publisher("/demo/raw_image","memory_msgs::RawImage")try:whileTrue:img=np.zeros((720,1280,3),dtype=np.uint8)cv2.circle(img,(640,360),120,(255,0,0),-1)cv2.putText(img,"SHM",(560,370),cv2.FONT_HERSHEY_SIMPLEX,2.0,(255,255,255),3)msg=pub.cvimg2sms_mem(img)pub.publish(msg)time.sleep(0.02)exceptKeyboardInterrupt:pub.kill()

订阅:

importcv2fromspiremsimportSubscriber,sms2cvimgdefcallback(msg):img=sms2cvimg(msg)cv2.imshow("raw image",img)cv2.waitKey(1)sub=Subscriber("/demo/raw_image","memory_msgs::RawImage",callback)sub.join()

2.4 共享内存 Tensor

消息类型:memory_msgs::Tensor

适合:

  • 模型输入输出
  • 任意维度数组
  • 图像张量、特征图、点云特征等

发布:

importtimeimportnumpyasnpfromspiremsimportPublisher,tensor2sms pub=Publisher("/demo/tensor","memory_msgs::Tensor")try:whileTrue:tensor=(np.random.rand(3,224,224)*255).astype(np.float32)msg=tensor2sms(tensor,"demo_tensor_mem")pub.publish(msg)time.sleep(0.05)exceptKeyboardInterrupt:pub.kill()

订阅:

fromspiremsimportSubscriber,sms2tensordefcallback(msg):tensor=sms2tensor(msg)print("shape:",tensor.shape,"dtype:",tensor.dtype,"mean:",float(tensor.mean()))sub=Subscriber("/demo/tensor","memory_msgs::Tensor",callback)sub.join()

2.5 任意类型消息

最简单的“任意结构消息”写法是使用std_msgs::Null

它的含义是:不强约束字段,你可以按需扩展字段。

发布:

importtimefromspiremsimportPublisher,def_msg pub=Publisher("/demo/any","std_msgs::Null")cnt=0try:whileTrue:msg=def_msg("std_msgs::Null")msg["cnt"]=cnt msg["name"]="spirems"msg["ok"]=Truemsg["pos"]=[1.0,2.0,3.0]msg["meta"]={"source":"python","version":1}pub.publish(msg)cnt+=1time.sleep(1.0)exceptKeyboardInterrupt:pub.kill()

订阅:

fromspiremsimportSubscriberdefcallback(msg):print(msg)sub=Subscriber("/demo/any","std_msgs::Null",callback)sub.join()

2.6 任意预定义类型消息

如果你要发送已经定义好的消息,建议优先用def_msg()初始化,再写字段。

例如geometry_msgs::Pose

fromspiremsimportPublisher,def_msg pub=Publisher("/demo/pose","geometry_msgs::Pose")msg=def_msg("geometry_msgs::Pose")msg["position"]["x"]=1.0msg["position"]["y"]=2.0msg["position"]["z"]=3.0msg["orientation"]["x"]=0.0msg["orientation"]["y"]=0.0msg["orientation"]["z"]=0.0msg["orientation"]["w"]=1.0pub.publish(msg)

3. C++:最常用的发布与订阅

常用头文件:

#include<sms_core.h>

3.1 字符串消息

发布:

#include<sms_core.h>intmain(){sms::Publisherpub("/demo/string_cpp","std_msgs::String");while(true){nlohmann::json msg=sms::def_msg("std_msgs::String");msg["data"]="hello spirems from cpp";pub.publish(msg);sms::msleep(1000);}return0;}

订阅:

#include<iostream>#include<sms_core.h>voidcallback(nlohmann::json msg){std::cout<<"recv: "<<msg["data"]<<std::endl;}intmain(){sms::Subscribersub("/demo/string_cpp","std_msgs::String",callback);sub.join();return0;}

3.2 压缩图像消息

发布:

#include<opencv2/opencv.hpp>#include<sms_core.h>intmain(){sms::Publisherpub("/demo/image_cpp","sensor_msgs::CompressedImage");while(true){cv::Mat img=cv::Mat::zeros(480,640,CV_8UC3);cv::putText(img,"SpireMS C++",cv::Point(120,240),cv::FONT_HERSHEY_SIMPLEX,1.5,cv::Scalar(0,255,0),3);nlohmann::json msg=sms::cvimg2sms(img);pub.publish(msg);sms::msleep(50);}return0;}

订阅:

#include<opencv2/opencv.hpp>#include<sms_core.h>voidcallback(nlohmann::json msg){cv::Mat img=sms::sms2cvimg(msg);cv::imshow("compressed image cpp",img);cv::waitKey(1);}intmain(){sms::Subscribersub("/demo/image_cpp","sensor_msgs::CompressedImage",callback);sub.join();return0;}

3.3 共享内存图像消息

发布:

#include<opencv2/opencv.hpp>#include<sms_core.h>intmain(){sms::mem_init();sms::Publisherpub("/demo/raw_image_cpp","memory_msgs::RawImage");while(true){cv::Mat img=cv::Mat::zeros(720,1280,CV_8UC3);cv::rectangle(img,cv::Rect(300,180,680,360),cv::Scalar(255,0,0),-1);cv::putText(img,"SHM CPP",cv::Point(430,380),cv::FONT_HERSHEY_SIMPLEX,2.0,cv::Scalar(255,255,255),3);nlohmann::json msg=pub.cvimg2sms_mem(img);pub.publish(msg);sms::msleep(20);}return0;}

订阅:

#include<opencv2/opencv.hpp>#include<sms_core.h>voidcallback(nlohmann::json msg){cv::Mat img=sms::sms2cvimg(msg);cv::imshow("raw image cpp",img);cv::waitKey(1);}intmain(){sms::mem_init();sms::Subscribersub("/demo/raw_image_cpp","memory_msgs::RawImage",callback);sub.join();return0;}

3.4 共享内存 Tensor

发布:

#include<vector>#include<sms_core.h>intmain(){sms::mem_init();sms::Publisherpub("/demo/tensor_cpp","memory_msgs::Tensor");while(true){std::vector<float>data(3*4,0.0f);for(size_t i=0;i<data.size();++i){data[i]=static_cast<float>(i);}nlohmann::json msg=sms::tensor2sms(data.data(),{3,4},"demo_tensor_cpp_mem");pub.publish(msg);sms::msleep(1000);}return0;}

订阅:

#include<iostream>#include<vector>#include<sms_core.h>voidcallback(nlohmann::json msg){std::vector<float>tensor_data;std::vector<int>tensor_shape;sms::sms2tensor(msg,tensor_data,tensor_shape);std::cout<<"shape: [";for(size_t i=0;i<tensor_shape.size();++i){std::cout<<tensor_shape[i]<<(i+1==tensor_shape.size()?"":", ");}std::cout<<"], first="<<tensor_data[0]<<std::endl;}intmain(){sms::mem_init();sms::Subscribersub("/demo/tensor_cpp","memory_msgs::Tensor",callback);sub.join();return0;}

3.5 任意类型消息

发布:

#include<sms_core.h>intmain(){sms::Publisherpub("/demo/any_cpp","std_msgs::Null");intcnt=0;while(true){nlohmann::json msg=sms::def_msg("std_msgs::Null");msg["cnt"]=cnt++;msg["name"]="spirems_cpp";msg["ok"]=true;msg["pos"]={1.0,2.0,3.0};msg["meta"]={{"source","cpp"},{"version",1}};pub.publish(msg);sms::msleep(1000);}return0;}

订阅:

#include<iostream>#include<sms_core.h>voidcallback(nlohmann::json msg){std::cout<<msg.dump(2)<<std::endl;}intmain(){sms::Subscribersub("/demo/any_cpp","std_msgs::Null",callback);sub.join();return0;}

4. C++ 最小 CMakeLists.txt

如果你想把上面的 C++ 示例直接编译运行,可以使用下面这个最小CMakeLists.txt

cmake_minimum_required(VERSION 3.10) project(spirems_demo) find_package(OpenCV REQUIRED) find_package(SpireMS REQUIRED) add_executable(str_sender str_sender.cpp) target_include_directories(str_sender PRIVATE ${SpireMS_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS}) target_link_libraries(str_sender ${SpireMS_LIBS} ${OpenCV_LIBS})

编译:

mkdir-pbuildcdbuild cmake..make-j

5. 如何选择消息类型

5.1 文本、小数据

优先用:

  • std_msgs::String
  • std_msgs::Number
  • std_msgs::Boolean

5.2 已定义结构化消息

优先用:

  • geometry_msgs::*
  • sensor_msgs::*
  • spirecv_msgs::*

写法:

  • def_msg("消息类型")
  • 再按字段赋值

5.3 本机大图像/大 Tensor

优先用:

  • memory_msgs::RawImage
  • memory_msgs::Tensor

特点:

  • 延迟更低
  • 拷贝更少
  • 只适合同机共享内存场景

5.4 暂时没有固定结构

优先用:

  • std_msgs::Null

适合:

  • 调试
  • 快速验证
  • 临时自由字段消息

6. 最常见问题

6.1No module named spirems

建议:

python-mpipinstall-e.

或者在项目根目录运行:

PYTHONPATH=. python your_script.py

6.2 共享内存消息收不到

先检查:

  • 发送端和接收端是否在同一台机器
  • 是否使用了memory_msgs::RawImage/memory_msgs::Tensor
  • Linux / macOS 下共享内存扩展是否正常

6.3 图像能发但显示不出来

先检查:

  • 接收端是否调用了sms2cvimg(msg)
  • cv2.imshow()后是否调用了cv2.waitKey(1)
  • 发送消息类型是否和订阅类型一致

7. 仓库内可参考的现成示例

Python:

  • test/string_sender_test.py
  • test/string_receiver_test.py
  • test/image_sender_test.py
  • test/image_receiver_test.py
  • test/share_mem_sender_test.py
  • test/share_mem_receiver_test.py
  • test/any_sender_test.py
  • test/any_receiver_test.py
  • spirems/demo/tensor_mem_pub_demo.py
  • spirems/demo/tensor_mem_sub_demo.py

C++:

  • spirems_cpp/demo/str_sender_test.cpp
  • spirems_cpp/demo/str_receiver_test.cpp
  • spirems_cpp/demo/image_sender_test.cpp
  • spirems_cpp/demo/share_mem_sender_test.cpp
  • spirems_cpp/demo/share_mem_receiver_test.cpp
  • spirems_cpp/demo/tensor_mem_sender_test.cpp
  • spirems_cpp/demo/tensor_mem_receiver_test.cpp

8. 一句话总结

  • 小消息:直接Publisher + def_msg + Subscriber
  • 图像跨机:sensor_msgs::CompressedImage
  • 大图像本机:memory_msgs::RawImage
  • 张量本机:memory_msgs::Tensor
  • 临时自由结构:std_msgs::Null

照着上面的最小示例复制运行即可。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/6 13:30:50

魔兽地图转换与修复终极指南:w3x2lni如何拯救你的地图文件

魔兽地图转换与修复终极指南&#xff1a;w3x2lni如何拯救你的地图文件 【免费下载链接】w3x2lni 魔兽地图格式转换工具 项目地址: https://gitcode.com/gh_mirrors/w3/w3x2lni 你是否曾因魔兽地图版本不兼容而烦恼&#xff1f;是否遇到过重要地图文件损坏却束手无策&…

作者头像 李华
网站建设 2026/5/6 13:30:02

终极鸣潮工具箱:一键解锁120FPS与智能抽卡分析完整指南

终极鸣潮工具箱&#xff1a;一键解锁120FPS与智能抽卡分析完整指南 【免费下载链接】WaveTools &#x1f9f0;鸣潮工具箱 项目地址: https://gitcode.com/gh_mirrors/wa/WaveTools WaveTools&#xff08;鸣潮工具箱&#xff09;是一款专为《鸣潮》PC玩家打造的免费开源工…

作者头像 李华
网站建设 2026/5/6 13:28:57

实战指南:基于快马平台快速构建cad三维模型在线交互展示页

今天在做一个CAD三维模型在线展示的需求时&#xff0c;发现用传统方式从零开发太耗时。经过摸索&#xff0c;发现用InsCode(快马)平台可以快速实现这个功能&#xff0c;整个过程比想象中简单很多。这里记录下具体实现思路和关键点&#xff0c;给有类似需求的同学参考。 项目背景…

作者头像 李华