第三篇:在ROS工程中使用QT开发界面笔记之---zmq数据流的发送与接收

1、zmq环境搭建

普通的socket是端对端的关系,ZMQ是N:M的关系,socket的连接需要显式地建立连接,销毁连接,选择协议(TCP/UDP)和错误处理,ZMQ屏蔽了这些细节,像是一个封装了的socket库,让网络编程变得更简单。ZMQ提供的套接字主要使用三种模式:‘请求-应答’,‘发布-订阅’,‘分布式’。我们采用与ROS一致的‘发布-订阅’模式进行数传。

Publisher-Subscriber模式,消息是单向流动的,发布者只能发布消息,不能接受消息;订阅者只能接受消息,不能发送消息(可参考 Redis 的发布和订阅方式)。服务端发布消息的过程中,如果有订阅者退出,不影响发布者继续发布消息,当订阅者再次连接上来,收到的消息是后来发布的消息。比较晚加入的订阅者,或者中途离开的订阅者,必然会丢掉一部分信息,如果发布者停止,所有的订阅者会阻塞,等发布者再次上线的时候继续接受消息。


 

1.1安装libzmq:

主机上安装zmq支持:sudo apt-get install libzmq3-dev

安装必须的库:sudo apt-get install libtool pkg-config build-essential autoconf automake

下载源码:git clone GitHub - zeromq/libzmq: ZeroMQ core engine in C++, implements ZMTP/3.1

./autogen.sh && ./configure && make -j 4

make check && make install && sudo ldconfig

这样就安装在了目录/usr/local下了,可以在/usr/local/lib下找到动态库,可以在/usr/local/include下找到头文件。


 

1.2安装cppzmq

由于ZMQ把核心和实现分开了。因此只装核心库是不够的。我们开发用C++下面安装语言的绑定库cppzmq

cd ..

git clone https://github.com/zeromq/cppzmq.git

cd cppzmq

sudo cp zmq.hpp /usr/local/include/

cd ..


 

1.3安装libsodium

git clone https://gitee.com/cybermadman/libsodium

cd libsodium

git checkout 1.0.10 //这里回退了几个版本,因为版本过高编译zmq时会出现-Werror=deprecated-declarations 错误,具体见zmq编译

./autogen.sh -f -s

./configure && make check

sudo make install

sudo ldconfig

cd ..


 

1.4安装zmqpp

git clone GitHub - zeromq/zmqpp: 0mq 'highlevel' C++ bindings

cd ./zmqpp/

make -j4 && sudo make install


 

1.5修改cmakelists.txtpackage.xml文件,使用第三方包

怎么直接用上面安装的zmqpp没有倒腾出来先让工程跑起来吧 ,就换作使用第三方包zmq_sup包的方法,这个包是同事给的就拿来用了

cmakelists.txt需要添加的内容如下:

find_package(catkin REQUIRED COMPONENTS

roscpp

zmq_sup

std_msgs

roslib)

catkin_package(

INCLUDE_DIRS include

CATKIN_DEPENDS roscpp std_msgs zmq_sup)

set(LIBS_ZMQ ${zmq_sup_SOURCE_DIR}/lib/x86/libzmq.so.5.2.5

${zmq_sup_SOURCE_DIR}/lib/x86/libzmqpp.so)

include_directories(include

${catkin_INCLUDE_DIRS}

${zmq_sup_SOURCE_DIR}/include)

add_executable(${PROJECT_NAME}_pubnode src/qtros_pubnode.cpp)

target_link_libraries(${PROJECT_NAME}_pubnode

${catkin_LIBRARIES}

${LIBS_ZMQ})

package.xml需要添加的内容如下:

<build_depend>zmq_sup</build_depend>

<build_depend>roslib</build_depend>

<build_export_depend>zmq_sup</build_export_depend>

<build_export_depend>roslib</build_export_depend>

<exec_depend>zmq_sup</exec_depend>

<exec_depend>roslib</exec_depend>

使用zmq库的时候需要include头文件

#include <zmqpp/zmqpp.hpp>

2、OPENCV环境搭建:

使用melodic自带的opencv,使用命令pkg-config --modversion opencv查看opencv版本为3.2.0,相应修改cmakelists.txt文件添加opencv配置

find_package(OpenCV REQUIRED)

include_directories(

include

${catkin_INCLUDE_DIRS}

${OpenCV_INCLUDE_DIRS}

${zmq_sup_SOURCE_DIR}/include

)

target_link_libraries(${PROJECT_NAME}_pubnode

${catkin_LIBRARIES}

${OpenCV_LIBS}

${LIBS_ZMQ}

)

package.xml不需要更改,但要注意使用opencv时候需要include头文件

#include <opencv2/opencv.hpp>

3zmq数据流的发送与接收

3.1.发送端的节点将图片pub出去

发送节点的实现步骤:

1.定义 context

2.设置socket_typepublish

3.context type定义发送端的socket

4.绑定IP地址和端口号

zmqpp::context context_;

const std::string addr_port = "tcp://192.168.43.233:5555";

zmqpp::socket_type type = zmqpp::socket_type::publish;

zmqpp::socket socket_ = zmqpp::socket(context_,type);

socket_.bind(addr_port);

5.读取图像,用zmq的socket的send函数发送:

std::string pkg_path = ros::package::getPath("qtros");

cv::Mat img = cv::imread(pkg_path+"/data/zmqpubsub.jpg");

while (ros::ok())//节点持续发图

{

std::vector<uint8_t> vec_data;

cv::imencode(".jpg", img, vec_data);

std::string str_data;

str_data.assign(vec_data.begin(), vec_data.end());

zmqpp::message message;

message << "map" <<str_data;//将图像数据添加”map”后保存为zmq消息

socket_.send(message);

ROS_INFO("image send");

sleep(1);//休眠1秒钟

}

3.2接收端的节点将图片sub进来

就在之前创建的mainwindow中添加一个Qlable,用接收节点qtshow_node.cppmain函数将图片界面显示

#include <ros/ros.h>

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])

{

ros::init(argc,argv,"qtshow_node");

ros::NodeHandle nh;

QApplication a(argc, argv);

mainwindow w;//在mainwindow.cpp中写槽函数接收并界面显示图片

w.show();

return a.exec();

}

在mainwindow.h中定义槽函数:

private slots:

void showFrame();

在mainwindow.cpp实现。

定义接收端的zmq socket上下文和类型:

#include "mainwindow.h"

#include "ui_mainwindow.h"

#include <opencv2/opencv.hpp>

#include <ros/ros.h>

#include <ros/package.h>

#include <QTimer>

#include <zmqpp/zmqpp.hpp>

static zmqpp::context context_;

static const std::string addr_port = "tcp://192.168.30.43:5555";

static zmqpp::socket_type type = zmqpp::socket_type::subscribe;

static zmqpp::socket socket_ = zmqpp::socket(context_,type);


 

显示窗口的主函数如下:

mainwindow::mainwindow(QWidget *parent) :

QWidget(parent),

ui(new Ui::mainwindow)

{

ui->setupUi(this);

QTimer *timer = new QTimer(this);

timer->start(1000);//定时器的频率设置为1000代表每秒一次

connect(timer, SIGNAL(timeout()), this, SLOT(showFrame()));

//定时器触发槽函数持续接收并刷新显示图片

}

槽函数处理接收端zmq数据的步骤:

1.订阅topic为“map”,即发送端添加在图片数据前的内容

2. connect ip地址和端口

3.用receive接收zmq消息

void mainwindow::showFrame()

{

socket_.subscribe("map");

socket_.connect(addr_port);

zmqpp::message message_1;

socket_.receive(message_1);

std::string topic;

std::string data_str;

message_1 >> topic >> data_str;

std::vector<uint8_t> data_vec;

data_vec.assign(data_str.begin(), data_str.end());

cv::Mat frame1 = cv::imdecode(data_vec, CV_LOAD_IMAGE_COLOR);

QImage showVideo1 = QImage((const unsigned char*)(frame1.data),frame1.cols,frame1.rows,frame1.step,QImage::Format_RGB888);

ui->label->setPixmap(QPixmap::fromImage(showVideo1.scaled(ui->label->size(),Qt::KeepAspectRatio,Qt::SmoothTransformation)));

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值