gstcam开发(ROS+gstreamer)

写在前面

gstcam是github上一个开元的ros软件包,它巧妙地将gstream流媒体框架引入ROS系统。通过利用 gstreamer 实现一个标准的ROS API接口.比如捕获usb uav camera 的图像,然后转化成 ros中 sensor_msgs/Image类型的image话题,发布到ros中,供其他节点使用。

gscam_github
gscam_wiki
这里注意区别在ros中处理图像的其他的几种方式
opencv + ros 实现采集图像发布成话题
web_video_server功能包的使用 实现把话题传到网络

web_video_server功能包的主要功能是,在ROS系统中,比如某些话题发布了图像、视频的话题,通过这个功能包可以订阅这些话题,然后对图像压缩,通过网络传输出去,这样我们就可以通过网络的方式获取到这些图像和话题。

概述 gscam软件工作流程

gscam 首先在launch文件中,通过参数gstcam_config设置一条gstreamer pipeline :

v4l2src device=$(arg DEVICE) ! video/x-raw-rgb,framerate=$(arg FPS) ! ffmpegcolorspace

其实这条pipeline还不完整,只有两个Elements, 一个是从设备中获取图像的v4l2src, 还有一个是颜色空间转换的ffmpegcolorspace,中间的那个是输入到ffmpegcolorspace的格式设定,最基本的其实还缺少一个sink Element, 所以gscam主要就在这里做文章,它在程序中创建了一个appsink Element,然后添加到pipeline中。
在gstreamer中,appsrc、appsink这两个element及其重要,通过他们可以在pipeline中调用第三方的代码。gscam就是通过使用appsink, 创建了一个缓存队列buffer, 通过对内存中的这个buffer拷贝、转换成sensor_msgs/Image的。

源码分析

gscam.cpp 定义类  gscam.h 声明类  gscam_node.cpp创建对象,创建节点调用方法

//GSCam::configure()
//这些主要是获取 launch中的一些参数。
    if (!gsconfig_env && !gsconfig_rosparam_defined) {
      ROS_FATAL( "Problem getting GSCAM_CONFIG environment variable and 'gscam_config' rosparam is not set. This is needed to set up a gstreamer pipeline." );
      return false;
    } else if(gsconfig_env && gsconfig_rosparam_defined) {
      ROS_FATAL( "Both GSCAM_CONFIG environment variable and 'gscam_config' rosparam are set. Please only define one." );
      return false;
    } else if(gsconfig_env) {
      gsconfig_ = gsconfig_env;
      ROS_INFO_STREAM("Using gstreamer config from env: \""<\"");
    } else if(gsconfig_rosparam_defined) {
      gsconfig_ = gsconfig_rosparam;
      ROS_INFO_STREAM("Using gstreamer config from rosparam: \""<\"");
    }

//  bool GSCam::init_stream()
//这里是gstreamer的一些常规操作
gst_init(0,0);
//创建 appsink element
sink_ = gst_element_factory_make("appsink",NULL);
gst_app_sink_set_caps(GST_APP_SINK(sink_), caps);
//set_caps of appsink 就是指定格式,这一块写的很地道,值得借鉴
gst_caps_unref(caps);

gst_bin_add(GST_BIN(pipeline_), sink_)
gst_element_link(outelement, sink_)

//gstreamer管道好像需要时钟,这里可用选ros的 或者 gstreamer的
ros::Time now = ros::Time::now();
GstClockTime ct = gst_clock_get_time(clock);

//创建ROS 发布者
jpeg_pub_ = nh_.advertise<sensor_msgs::CompressedImage>("camera/image_raw/compressed",1);
cinfo_pub_ = nh_.advertise<sensor_msgs::CameraInfo>("camera/camera_info",1);
//根据image_encoding的方式不同,发布的话题也稍微不同
camera_pub_ = image_transport_.advertiseCamera("camera/image_raw", 1);

void GSCam::publish_stream()

//先启动流
gst_element_set_state(pipeline_, GST_STATE_PLAYING)
//然后在while(ros::ok)循环中
//取样
GstSample* sample = gst_app_sink_pull_sample(GST_APP_SINK(sink_));
//得到缓存buffer
GstBuffer* buf = gst_sample_get_buffer(sample);
GstMemory *memory = gst_buffer_get_memory(buf, 0)
//访问内存中数据
gst_memory_map(memory, &info, GST_MAP_READ);

//数据转换
std::copy(buf_data, (buf_data)+(buf_size),img->data.begin());

//数据封装
img->header = cinfo->header;
img->format = "jpeg";
img->data.resize(buf_size);

//发布
jpeg_pub_.publish(img);
cinfo_pub_.publish(cinfo);

//这里gstreamer支持了好几种编码方式,所以这个地方显得有点杂,但大致思路是一样的

//run 就是对方法的调用,gscam_node主要就是调用这个方法
this->configure()
this->init_stream()
this->publish_stream();//大循环
 this->cleanup_stream();

gscam_cmakelist分析

//gscam的CmakeList写的也很优秀,前面我的一篇博客专门分析过
find_package(PkgConfig)

pkg_check_modules(GSTREAMER QUIET gstreamer-0.10)
if(NOT GSTREAMER_FOUND)
  set(GSTREAMER_VERSION_1_x TRUE)
endif()
if(GSTREAMER_VERSION_1_x)
  message(STATUS "gst 1.0")
  pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0)
  pkg_check_modules(GST_APP REQUIRED gstreamer-app-1.0)
else()
  message(STATUS "gst 0.1")
  pkg_check_modules(GSTREAMER REQUIRED gstreamer-0.10)
  pkg_check_modules(GST_APP REQUIRED gstreamer-app-0.10)
endif()

总结

通过对gscam的学习,确实对ros以及在ros中对图像的操作有了一定的了解,我在gscam的基础之上也做了一些延伸和拓展,gscam只是把USB camera的图像拿到,转化成topic, 我想在这里有一个数据共享,一方面转化成topic供其他node使用,同时丰富一下这个pipiline,让图像还能通过网络发送出去。

你可能感兴趣的:(ROS机器人系统)