作者:Sam (甄峰) sam_code@hotmail.com
0. 背景介绍:
近期要研究ROS Xtion Driver. 在ROS系统下, Xtion Driver是openni2_camera, 它读取Xtion数据并将数据发布到各Topic供其它Node使用。但研究下来,其实openni2_camera仅仅是冰山露出海面的部分。它构建了类似Linux Driver 中的Device,Driver 概念,并使用Manager管理Device。看起来很清晰,但数据处理,Device具体处理等庞大的部分,其实并不在这个包内。二是另有玄机。现在就将这部分内容大概的理一下。
近期要研究ROS Xtion Driver. 在ROS系统下, Xtion Driver是openni2_camera, 它读取Xtion数据并将数据发布到各Topic供其它Node使用。但研究下来,其实openni2_camera仅仅是冰山露出海面的部分。它构建了类似Linux Driver 中的Device,Driver 概念,并使用Manager管理Device。看起来很清晰,但数据处理,Device具体处理等庞大的部分,其实并不在这个包内。二是另有玄机。现在就将这部分内容大概的理一下。
1.
openni2_camera文件结构和组成研究:
这个Package是Asus
Xtion and Primesense Devices的Driver。
下载并察看之。
分析组成结构:
文件组成和结构的分析,照例是看CMakefiles.txt
A: 首先生成一个动态库,名为:libopenni2_wrapper.so:
add_library(openni2_wrapper src/openni2_convert.cpp
src/openni2_device.cpp
src/openni2_device_info.cpp
src/openni2_timer_filter.cpp
src/openni2_frame_listener.cpp
src/openni2_device_manager.cpp
src/openni2_exception.cpp
src/openni2_video_mode.cpp )
src/openni2_device.cpp
src/openni2_device_info.cpp
src/openni2_timer_filter.cpp
src/openni2_frame_listener.cpp
src/openni2_device_manager.cpp
src/openni2_exception.cpp
src/openni2_video_mode.cpp )
target_link_libraries(openni2_wrapper ${catkin_LIBRARIES}
${PC_OPENNI2_LIBRARIES} ${Boost_LIBRARIES} )
可以看到,它由src下的一些文件构成。同时,请注意,这个库依赖于${PC_OPENNI2_LIBRARIES}
它是谁呢?是/usr/lib/OpenNI2/Drivers中的各个库文件,这个库提供对设备的识别,操作,对数据的处理等大量的工作。
B:test_wrapper应用程序:
add_executable(test_wrapper test/test_wrapper.cpp )
target_link_libraries(test_wrapper openni2_wrapper
${Boost_LIBRARIES})
这个程序用来尝试使用A库。由test/test_wrapper.cpp构成,并依赖于A 库。
C:生成主要的动态库:libopenni2_driver_lib.so:
add_library(openni2_driver_lib src/openni2_driver.cpp )
target_link_libraries(openni2_driver_lib openni2_wrapper
${catkin_LIBRARIES} ${Boost_LIBRARIES} )
add_dependencies(openni2_driver_lib ${PROJECT_NAME}_gencfg
${PROJECT_NAME}_generate_messages_cpp)
它原来于A库。
D:nodelet 库:
add_library(openni2_camera_nodelet
ros/openni2_camera_nodelet.cpp )
target_link_libraries(openni2_camera_nodelet
openni2_driver_lib ${catkin_LIBRARIES} ${Boost_LIBRARIES} )
add_dependencies(openni2_camera_nodelet
${PROJECT_NAME}_gencfg)
这个是为nodelet创建的库。 它依赖于C库,则间接依赖于A库。
E:node:
add_executable(openni2_camera_node ros/openni2_camera_node.cpp
)
target_link_libraries(openni2_camera_node openni2_driver_lib
${catkin_LIBRARIES} ${Boost_LIBRARIES} )
add_dependencies(openni2_camera_node ${PROJECT_NAME}_gencfg
${PROJECT_NAME}_generate_messages_cpp)
与nodelet地位相同,但它是创建一个Node。利用Node发布Topic。
它依赖于C库,则间接依赖于A库。
F:list_devices, usb_reset应用程序:
比较简单的Linux程序,打开设备并设置。
2. libopenni2_wrapper.so 中各种概念(Manager, Device,
Driver)的分析:
2.1:
Manager:
class
OpenNI2DeviceManager:它主要用来管理Device。对插入和拔出设备进行监听。随时维护正在插入设备的列表。并得到他们的信息。
在构造函数中,
A: 首先调用底层库的: openni::OpenNI::initialize()
B: device_listener_ =
boost::make_shared(); 创建了OpenNI2DeviceListener
class 的对象。并给出对象指针。
先着重谈谈OpenNI2DeviceListener 这个Class。
它是 public openni::OpenNI::DeviceConnectedListener,
public openni::OpenNI::DeviceDisconnectedListener,
public openni::OpenNI::DeviceStateChangedListener
public openni::OpenNI::DeviceDisconnectedListener,
public openni::OpenNI::DeviceStateChangedListener
的子class.
在OpenNI2DeviceListener 构造函数中,它把自己的对象加入监听队列:
openni::OpenNI::addDeviceConnectedListener(this);
openni::OpenNI::addDeviceDisconnectedListener(this);
openni::OpenNI::addDeviceStateChangedListener(this);
openni::OpenNI::addDeviceDisconnectedListener(this);
openni::OpenNI::addDeviceStateChangedListener(this);
并获取已经连接的Device信息:
openni::Array device_info_list;
openni::OpenNI::enumerateDevices(&device_info_list);
openni::OpenNI::enumerateDevices(&device_info_list);
for
(int i = 0; i < device_info_list.getSize(); ++i)
{
onDeviceConnected(&device_info_list[i]);
}
{
onDeviceConnected(&device_info_list[i]);
}
并把这些设备记录下来。
它主要用来监听设备的连接和断开。
device_manager.getDevice(uri);
则返回一个新创建的Device。
2.2:Driver;
在构造函数中。
1.
利用OpenNI2DeviceManager的static函数getSingelton()获取到Manager。
2.
在initDevice()中,利用Manager的getDevice()获取到当前Device。(此处会初始化Device)
3. advertiseROSTopics();
现在主要分析advertiseROSTopics()