前篇文章介绍了如何实现最简单的节点间内存共享。但因为篇幅所限,并没有深入介绍怎么将其实用化。本篇我们将用之前专门介绍的循环队列内存共享技术,将一个节点的图像数据直接共享给另外的节点。 为了比较内存共享机制和ROS自带的话题传输机制,本文用:ROS系统学习5—OpenCV的使用这篇文章提供的图像发送和接收节点做对比。结果发现用自带的话题传输机制传一张1080p的图像延时大概在600ms,而用内存共享机制传输延时只有10ms左右,性能相差了几十倍。 另外,ROS自身也提供了nodelet做内存共享,只是本人研究了几天发现特别乱就放弃了,感觉这东西迟早要被抛弃(事实上ROS2.0就不用这种机制了),如果有老哥有兴趣也可以去研究下。 下面贴出实现代码,其中最重要的“shmobject.h”在循环队列内存共享已经提供过,需要的可以直接去那边下。 发送节点:
#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <opencv2/highgui/highgui.hpp>
#include <cv_bridge/cv_bridge.h>
#include <stdio.h>
#include "../../shmobject.h"
int main(int argc, char** argv)
{
ros::init(argc, argv, "image_publisher");
ros::NodeHandle nh;
cv::Mat image = cv::imread("/home/weixin/图片/2.jpeg", CV_LOAD_IMAGE_COLOR);
if(image.empty())
{
printf("open error\n");
}
shmobject shmobj(10+image.rows*image.step,10,66);//共享内存对象
unsigned char* shmdata=NULL;
ros::Rate loop_rate(1);//每秒5帧
while (nh.ok())
{
shmdata=shmobj.requiredata();//要求数据
if(shmdata!=NULL)
{
memcpy(&shmdata[10],image.data,image.rows*image.step);
shmobj.updatashm(shmdata);//更新数据,可被读取
ROS_INFO("I send");
}
ros::spinOnce();
loop_rate.sleep();
}
shmobj.writerelease();
}
接收节点:
#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <opencv2/highgui/highgui.hpp>
#include <cv_bridge/cv_bridge.h>
#include "../../shmobject.h"
int main(int argc, char **argv)
{
ros::init(argc, argv, "image_listener");
ros::NodeHandle nh;
image_transport::ImageTransport it(nh);
shmobject shmobj(66);
ros::Rate loop_rate(30);//每秒5帧
cv::Mat image(1080,1920,CV_8UC3);
while (nh.ok())
{
unsigned char *readdata= shmobj.getdataforread();
if(readdata!=NULL)//表示已经获取到可读数据
{
ROS_INFO("I heard");
memcpy(image.data,&readdata[10],image.rows*image.step);
// cv::imshow("",image);
// cv::waitKey(3);
// printf("图像显示\n");
readdata[0]=0;//读取完成标志位
}
else
{
//printf("无可读数据,请等待写入,稍候重试\n");
}
loop_rate.sleep();
}
image.release();
ros::spin();
shmobj.readrelease();
}