网上有不少关于在ubuntu下uvc相机连接ros的教程,然而双鱼眼相机在ubuntu下连接ros的教程非常少。通过这篇文章我想把具体的操作方法给大家介绍一下,方便大家搞研究或者搞自己干一些有趣的事情,把时间浪费在不必要的地方上。
相机用的是理光的全景相机 (型号: THETA S)网上查了一下价格大概1800左右。具体图片如下。
这里说一下注意事项, 理光相机THETA系列下有好几种型号,之前我用了THETA V型号,一直连接不上好像和uvc驱动不兼容,也尝试了通过wifi连接也失败了。。。 用的ROS包是这个github上面的,出的错和别人的也一样,参见这里。在之后我也试了其他几种方法,也都不行。最后我在某个论坛上发现有人说过用 THETA S 型号通过libuvc这个包可以连接,于是我冒着失败的风险自掏腰包买了 THETA S相机,最后终于成功了! (虽说比 THETA V便宜)
总之就是推荐大家用THETA S型号,THETA V型号比较新,没多少人用过,自己踩坑问题太多。
1. 安装libuvc_camera
ros kinetic版本:
sudo apt-get install ros-kinetic-libuvc-camera
ros melodic版本:
sudo apt-get install ros-melodic-libuvc-camera
2. 写roslaunch文件
安装完libuvc_camera包后,需要写一个roslaunch文件来调用libuvc_camera这个包(这个包好像不在 wifi 下用不了)。
这个文件保存在/catkin_ws/src目录下就行, 我给他取名为 libuvc_camera.launch
, 文件如下直接复制就可以.
<launch>
<node name="libuvc_camera" pkg="libuvc_camera" type="camera_node" output="screen">
<param name="vendor" value="0x05ca" />
<param name="product" value="0x2711" />
<param name="width" value="1280" />
<param name="height" value="720" />
<param name="video_mode" value="mjpeg" />
<param name="frame_rate" value="14.985" />
</node>
</launch>
这里这一行和
这一行分别需要针对自己的设备做一下修改, 这一部分就是指定自己的设备, 让libuvc_camera这个包知道相机的名称, 那么怎么查询自己的相机呢?
把THETA S 通过usb线连接到电脑, 此时非常重要的一步就是把THETA S相机切换到数据线连接模式 , 切换方法为 先按住最上边的电源键
, 然后过1秒后按住最下面的
相机模式切换键
,再过差不多1秒后电源键
松手,最后再过1秒后相机模式切换键
松手. 这时相机回变成下图的样子.
摄像图标下面 Live 亮了就说明模式切换对了.
这时打开电脑的Terminal, 输入lsusb
可以看到我们的设备就是Bus 001 Device 007: ID 05ca:2711 Ricoh Co., Ltd
这一行. 现在我们已经找到THETA S的名称了, 回到libuvc_camera.launch
文件把 0x05ca 和 0x2711 改进去.
,
然后保存退出.
非常重要一点: 一定要先把相机切换成数据线连接模式,再用$ lsusb 查询, 不然查询的名称会是另一个!!! 一定注意先后顺序, 查出数据线连接模式下的名称!
目前我们已经
接下来, 介绍一下运行步骤
1.修改相机文件的权限
进入到设备文件路径/dev/bus/usb/001
此时会看到有好几个文件, 这个跟电脑上插入usb设备的顺序有关, 一般数字最大的就是最后一次插的 (也就是我们刚刚插的相机), 用 $lsusb 查询一下名称也可以. 然后 sudo chmod 777 <文件名>
(每次连接电脑的时候都需要修改一次权限)
此时需要的准备都全部完成了.
2. 运行
进入 libuvc_camera.launch
文件所在路径, 用roslaunch启动
此时, 数据已经连接到ros上了, 发布在 /image_raw
话题上.
在终端中输出rostopic echo /image_raw
可以查看是不是动态的显示一堆数字, 如果是就说明图像数据成功发送到这个话题上了。
我们可以用 python 的程序订阅一下上面的消息, 看看图像是怎么样的。 (把ros的消息格式转到OpenCV格式显示 )
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*
import rospy
from sensor_msgs.msg import Image
import cv2
import cv_bridge
class GetImg:
def __init__(self):
self.bridge = cv_bridge.CvBridge()
self.image_sub = rospy.Subscriber('/image_raw', Image, self.image_callback)
def image_callback(self,msg):
image = self.bridge.imgmsg_to_cv2(msg,desired_encoding='bgr8')
cv2.imshow("a",image)
cv2.waitKey(1)
if __name__ == "__main__":
rospy.init_node('A')
gt = GetImg()
rospy.spin()
程序直接在终端里运行需要改变权限, 通过sudo chmod 777 <程序名>
改变权限后, 再 ./<程序名>
运行.
图像如下 (没洗头所以把帽子戴上了-_-"
代码里面, 通过image = self.bridge.imgmsg_to_cv2(msg,desired_encoding='bgr8')
这一行已经把ros的msg格式换到了OpenCV格式, 之后就可以进行各种处理了。
比如把图片转换到HSV空间
用OpenCV的cv2.Canny( ) 边缘检测
用双经度算法把其中一幅鱼眼图像展开, 虽说效果不太理想…
#include
#include
#include
#include
#include
using namespace std;
void callback(const sensor_msgs::ImageConstPtr& msg)
{
try
{
cv::imshow("view", cv_bridge::toCvShare(msg, "bgr8")->image);
cv::waitKey(3);
}
catch(cv_bridge::Exception& e)
{
ROS_ERROR("cannot convert from '%s' to 'bgr8'", msg->encoding.c_str());
}
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "sub");
ros::NodeHandle n;
cv::namedWindow("view");
cv::startWindowThread();
image_transport::ImageTransport it(n);
image_transport::Subscriber sub = it.subscribe("/image_raw", 30, callback);
ros::spin();
cv::destroyWindow("view");
return 0;
}
C++情况下需要编译,先在~/catkin_ws/src
下创建功能包,具体怎么创建有其他比较详细的教程。这里我创建的功能包名为cpptest,对~/catkin_ws/src/cpptest
里面的 CMakeLists.txt 和 package.xml 分别进行修改,添加依赖。
CMakeLists.txt (除了初始的roscpp 之外还用到其他库,都把他们添加进来,自己需要使用别的库同理也可以自定义添加)
cmake_minimum_required(VERSION 2.8.3)
project(cpptest)
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
image_transport
std_msgs
cv_bridge
)
find_package(OpenCV REQUIRED)
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES basics
# CATKIN_DEPENDS rospy
# DEPENDS system_lib
)
include_directories(
${catkin_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS}
)
add_executable(cpptest src/ImgTest.cpp)
target_link_libraries( cpptest ${OpenCV_LIBS} ${catkin_LIBRARIES})
package.xml (同理也要改进来)
<?xml version="1.0"?>
<package format="2">
<name>cpptest</name>
<version>0.0.0</version>
<description>The cpptest package</description>
<maintainer email="[email protected]">mgn</maintainer>
<license>TODO</license>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>roscpp</build_depend>
<build_depend>rospy</build_depend>
<build_depend>opencv2</build_depend>
<build_depend>std_msgs</build_depend>
<build_depend>image_transport</build_depend>
<build_depend>cv_bridge</build_depend>
<build_export_depend>roscpp</build_export_depend>
<build_export_depend>rospy</build_export_depend>
<build_export_depend>opencv2</build_export_depend>
<build_export_depend>std_msgs</build_export_depend>
<build_export_depend>image_transport</build_export_depend>
<build_export_depend>cv_bridge</build_export_depend>
<exec_depend>roscpp</exec_depend>
<exec_depend>rospy</exec_depend>
<exec_depend>opencv2</exec_depend>
<exec_depend>std_msgs</exec_depend>
<exec_depend>image_transport</exec_depend>
<exec_depend>cv_bridge</exec_depend>
<export>
</export>
</package>
改完之后回到 ~/catkin_ws
目录,在终端输入 catkin_make 进行编译,然后在启动 roscore 的情况下输入 rosrun cpptest cpptest
同样也可以得到摄像头实时传回来的图片。这里面第一个 cpptest 指的是我们刚才创建功能包的名, 第二个cpptest是我们在这个功能包下定义的这个小项目的名字。
这篇文章主要目的是为了方便大家搞360度全景图像的相关研究时, 在摄像头连接ubuntu系统ros里面运行时避开不必要的坑, 节省时间少走弯路。 同时在这一篇博客中接着介绍了如何把导出的原图像展开为全景图像。 希望能帮助大家.