在上节已经实现了单张图片的ROS实现,而在现实中,我们一般是使用摄像头来获取图像,这次要实现在ROS中使用摄像头传输图像,我使用的是罗技的usb网络摄像头,首先我们需要获取摄像头的型号,如下所示:
yake@yake-K42JE:~$ lsusb Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 001 Device 002: ID 8087:0020 Intel Corp. Integrated Rate Matching Hub Bus 002 Device 002: ID 8087:0020 Intel Corp. Integrated Rate Matching Hub Bus 001 Device 003: ID 04f2:b1e5 Chicony Electronics Co., Ltd Bus 002 Device 003: ID 046d:c058 Logitech, Inc. M115 Mouse Bus 002 Device 008: ID 046d:0825 Logitech, Inc. Webcam C270
我所使用的是罗技的C270网络摄像头.接下来我们要为摄像头安装驱动,我使用的是cheese点击打开链接,这个驱动的好处是在ubuntu环境下直接apt-get获得
yake@yake-K42JE:~$ sudo apt-get install cheese
首先还是要创建一个包,写一个驱动摄像头的文件,命名为my_publisher.cpp,作用是获取图像并打包成ros格式发送出去,创建包的方法与单张图片一样,my_publisher.cpp内容如下:
#include <ros/ros.h> #include <image_transport/image_transport.h> #include <opencv2/highgui/highgui.hpp> #include <cv_bridge/cv_bridge.h> #include <sstream> // for converting the command line parameter to integer int main(int argc, char** argv) { // Check if video source has been passed as a parameter if(argv[1] == NULL) { ROS_INFO("argv[1]=NULL\n"); return 1; } ros::init(argc, argv, "image_publisher"); ros::NodeHandle nh; image_transport::ImageTransport it(nh); image_transport::Publisher pub = it.advertise("camera/image", 1); // Convert the passed as command line parameter index for the video device to an integer std::istringstream video_sourceCmd(argv[1]); int video_source; // Check if it is indeed a number if(!(video_sourceCmd >> video_source)) { ROS_INFO("video_sourceCmd is %d\n",video_source); return 1; } cv::VideoCapture cap(video_source); // Check if video device can be opened with the given index if(!cap.isOpened()) { ROS_INFO("can not opencv video device\n"); return 1; } cv::Mat frame; sensor_msgs::ImagePtr msg; ros::Rate loop_rate(5); while (nh.ok()) { cap >> frame; // Check if grabbed frame is actually full with some content if(!frame.empty()) { msg = cv_bridge::CvImage(std_msgs::Header(), "bgr8", frame).toImageMsg(); pub.publish(msg); //cv::Wait(1); } ros::spinOnce(); loop_rate.sleep(); } }
#include <ros/ros.h> #include <image_transport/image_transport.h> #include <opencv2/highgui/highgui.hpp> #include <cv_bridge/cv_bridge.h> void imageCallback(const sensor_msgs::ImageConstPtr& msg) { try { cv::imshow("view", cv_bridge::toCvShare(msg, "bgr8")->image); // cv::WaitKey(30); } catch (cv_bridge::Exception& e) { ROS_ERROR("Could not convert from '%s' to 'bgr8'.", msg->encoding.c_str()); } } int main(int argc, char **argv) { ros::init(argc, argv, "image_listener"); ros::NodeHandle nh; cv::namedWindow("view"); cv::startWindowThread(); image_transport::ImageTransport it(nh); image_transport::Subscriber sub = it.subscribe("camera/image", 1, imageCallback); ros::spin(); cv::destroyWindow("view"); }
find_package(OpenCV REQUIRED) # add the publisher example add_executable(my_publisher src/my_publisher.cpp) target_link_libraries(my_publisher ${catkin_LIBRARIES} ${OpenCV_LIBRARIES}) # add the subscriber example add_executable(my_subscriber src/my_subscriber.cpp) target_link_libraries(my_subscriber ${catkin_LIBRARIES} ${OpenCV_LIBRARIES})
yake@yake-K42JE:~/ros_ws$ catkin_make
yake@yake-K42JE:~$ roscore
运行my_publisher节点.(如果运行不起来,需要先source devel/setup.bash)
yake@yake-K42JE:~/video_ros$ rosrun learning_image_transport my_publisher 0这时候会看到我们的摄像头灯已经亮起来了,0代表默认摄像头,如果有多个摄像头,则第二个是1,依次类推.
接下来运行my_subscriber节点来接收图像
yake@yake-K42JE:~/video_ros$ rosrun learning_image_transport my_subscriber