上次推送中我们已经能够利用现成的角点检测代码,完成事件相机数据的角点检测,并调用了rpg_dvs_ros这个package进行了显示。这次我们自己完成一个package,实现一个简单的功能:将事件相机的极性进行翻转。这个操作可能没有什么实际意义,但方便我们去熟悉基本Event的数据格式,以及与dvs_renderer、数据集.bag的对接,同时熟悉package编写方法。
一、基础知识
在编写ros中的package代码之前,我们需要首先对Event的数据形式,dvs_renderer的启动等有一定了解。
1、消息类型
在rpg_dvs_ros包的dvs_msgs/msg中定义了两个数据类型,分别是:Event.msg与EventArray.msg。根据名称我们可以推测出来,Event就是单独一个事件,而EventArray是为了避免单个事件发送频率过高,而组成的一组事件流。具体的数据格式如下:
图:左:单独event的数据,具有坐标,时间戳和极性;右:EventArray数据,具有图像宽度和高度,以及event数据数组
在catkin_ws执行编译后,会在 ./devel/include/dvs_msgs/ 下生成Event.h与EventArray.h文件,编写代码时需要include这些头文件;另外在CMakeLists中也要加入相关头文件。
2、dvs_renderer相关
dvs_renderer是dvs渲染器/显示器,用于显示dvs相关数据。从dvs_renderer/src/renderer.cpp中可以看出,dvs_renderer主要订阅了的消息有:events, image等,并发布名为”dvs_rendering”的数据。分析可知,dvs_renderer经过处理image和events后,将数据整理生成了”dvs_rendering”,可以由rqt_image_view进行显示。
3、dvs_mono.launch文件
查看launch/dvs_mono.launch文件,可以看出这个文件主要启动了三个node。
node 1:dvs_ros_driver 这个应该是安装实体相机后需要用到的参数,暂时不用考虑
node 2:名为dsv_renderer的node,来自pkg名为dvs_renderer的dvs_renderer节点:主要操作:1. 将/dvs/events数据remap到了events中。即运行rosbag时会产生的topic为”/dvs/evets”,而dvs_renderer节点中订阅的topic名为”events”,所以进行remap,让dvs_renderer能够找到topic
node 3:名为”image_view”的node,是pkg名为”rqt_image_view”中的”rqt_image_view”节点,将dvs_renderer中publish出的”dvs_rendering”话题进行remap到”rqt_image_view”所订阅的”image”话题。
图:dvs_mono.launch启动的三个node:dvs驱动、dvs_renderer和显示窗口
4、小结:
若想可视化,需要dvs_renderer订阅rosbag发布的话题,并进行rendering后由rqt_image_view订阅dvs_renderer发布的dvs_rendering。所以我们如果对bag中数据进行加工,需要从rosbag这里接过数据,进行处理,之后发布让dvs_renderer接收,并继续后面的显示即可。最终完成的节点关系如下图:
节点订阅关系:/dvs_ivt_render_node是我们设计的用于显示翻转后数据的节点,其接受了由/Inverter_node节点翻转后的数据,以及视频原图,最终输出翻转的事件/events_ivt用于后续显示。而下面一路,是用作对比的,原有的dvs_renderer获取图像进行显示/events_ori的方法。可以看出,上面数据相对于下面这路多了一个/inverter_node节点进行翻转
二、手写一个事件极性翻转节点
所谓翻转极性,就是将事件相机产生数据的极性进行改变:0变1,1变0。整个过程涉及到了:创建一个package,ros话题的发布与订阅,事件相机数据的处理。
1、创建一个package
使用catkin_create_pkg指令在catkin_ws/src文件夹下创建一个名为test的package。
$ catkin_create_pkg test
此时内部生成了两个最基础的文件,CMakeLists.txt与package.xml,分别是编译时需要用到的文件,与package相关的配置文件。暂时不需要理解。
2、创建一个Inverter类
在test的package下,创建include/inverter.h文件,编写内容如下:
a) 首先包含ros最基本的头文件,之后需包含对事件相机数据处理时需要的”EventArray.h”。
b) 一个Inverter需要创建一个ros节点,节点分别订阅和发布消息,同时需要一个回调函数,用于处理订阅收到的事件相机数据
3、编写Inverter的具体内容
在构造函数中,将ros节点发布一个名为”/invert_events”的话题,订阅名为”/dvs/events”的话题。在回调函数中,对事件相机数据进行处理:
a) 创建invertMsg数据,并将相关信息进行赋值;
b) 对于EventArray中的每一个事件,分别对极性进行取反并存储到invertMsg的events数组中;
c) 发布极性取反后的数据。
4、main函数
main函数就相对简单许多,只需要创建一个Inverter,便在Inveter的默认构造函数中自动完成了消息订阅发布与回调数据处理
5、修改CMakeLists.txt
为了编译文件,需要修改CMakeLists.txt,如下:
a) 首先是cmake的基本操作,project名称需要与package一致,为test
b) 之后寻找catkin_simle包,这个包对后面查找头文件、链接库的链接等非常重要
c) 启动catkin_simple()和catkin_package()宏定义
d) 将inverter.h的头文件加进去,同时包含catkin_INCLUDE_DIRS中包含的头文件
e) 使用cs_add_executable()生成inverter可执行程序(节点)
6、修改package.xml文件
包含catkin_simple这个buildtool和dvs_msgs这个数据类型即可,
7、编译
回到catkin_ws目录下,执行catkin build指令进行编译。完成后我们就可以启动这些节点了。
8、编写launch文件
launch文件可以一次性启动多个节点,同时修改相关参数。在test目录中创建launch/inverter.launch文件。
文件共创建了5个节点,分别是:interter节点,两个dvs_renderer节点和两个可视化rqt_image_view节点。
a) inverter节点:没有过多的解释,启动一个”test”的package下的”inverter”节点,命名为”inverter_node”
b) dvs_renderer节点1:启动一个节点,将其订阅的events数据remap为rosbag运行时发布的数据”/dvs/events”;同时将image数据remap为rosbag运行时发布的”/dvs/image_raw”数据;将发布的”dvs_rendering”数据更名为”/events_ori”,便于区分极性反转前后的rendering后的名称
c) dvs_renderer节点2:这次订阅的是由interter节点发布的”/invert_events”数据。由于inverter节点在代码中发布的topic名就是这个,所以不需要在inverter节点中重新remap;同时将rendering后的话题修改为”/event_ivt”
d) 启动两个rqt_image_view。之后手动选择”/event_ori”和”/event_int”进行显示。
9、运行
a) 运行roscore
b) 运行rosbag数据:rosbag play <path-to-your-dataset>/xxx.bag
c) 运行roslaunch: roslaunch test inverter.launch
10、运行结果
在两个启动的窗口中,分别选择”/event_oir”与”/event_ivt”,可以看出事件极性完全反了过来。
三、源码下载
本文中的inverter示例已经上传至github:https://github.com/LarryDong/dvs_inverter,希望可以帮助大家理解这些基础内容。