平台参考:原厂 V1.0.1(RK-KF-YF-355)介绍 RMSL 在 Linux SDK 下的使用及开发接口。RMSL 是结构光 3D 相机,集成 3 万点散斑投射器、500 万像素 RGB 摄像头、100 万像素全局曝光红外摄像头及红外照明激光源,用于支付、门禁、手势/肢体识别、高精度 3D 建模等。具体 ArmSoM 板卡、内核与 BSP 适配未经验证;必须核对 USB 供电、依赖库和设备节点。本文性能数字为原厂示例,不是 ArmSoM 实测,未执行命令。中文使用中文原图,英俄德使用英文原图。
1. RMSL模组接口简介
1.1 概述
Rockchip RMSL模组是USB即插即用设备,它可以同时有三路输出,即Depth, RGB, IR。其中Depth输出YUYV数据,RGB及IR输出MJPG数据。
| Video | 最大分辨率 | 格式 | 帧率 | 描述 |
|---|---|---|---|---|
| Depth | 640x480 | YUYV | 15fps | 输出视差图,可根据算法转换成深度图或点云图 |
| RGB | 1920x1080 | MJPG | 30fps | 彩色视频输出,可解码为NV12格式 |
| IR | 640x480 | MJPG | 15fps | 红外视频输出,可解码为NV12格式 |
1.2 RMSL模组的型号
RK RMSL模组的型号可从SN码中获取,当前支持的RK结构光型号如下:
| 型号 | 匹配的SN码 | 接口 |
|---|---|---|
| RMSL201-1301 | R2011301xxxxxxxxx | USB |
1.3 Buildroot中配置
在Buildroot Linux SDK中,开发接口及参考demo位于app/demo/rmsl目录下。默认SDK发布版本没有编译该程序,需要用戶将Buildroot编译宏开关 BR2_PACKAGE_APP_DEMO_RMSL 使能后才可以编译。该程序依赖的如下应用包也需要使能。BR2_PACKAGE_CAMERA_ENGINE_RKISP,用于获取V4L2数据流BR2_PACKAGE_MPP,用于解码MJPGBR2_PACKAGE_LINUX_RGA,用于对YUV数据做处理,以便显示BR2_PACKAGE_LIBDRM,用于显示于屏幕上(可选)注意:若未发现该宏开关或无rmsl demo代码,请更新到最新SDK,或通过github仓库获取。external/camera_engine_rkisp/需要更新到 86dc5bf1 apps: rkisp_api: add usb camerasupports 。若SDK未更新到最新,可通过github仓库获取。
1.4 编译和运行
在SDK目录下,通过如下命令进行模块编译,
# make app_demo
如需要重新编译,可通过命令:
# make app_demo-dirclean
# make app_demo
编译完成后会生成两个可执行文件rmsl_linux_demo及rmsl_tool。
# ls -1 /usr/bin/rmsl*
/usr/bin/rmsl_linux_demo
/usr/bin/rmsl_tool
因为依赖较多,建议用戶按1.3小节配置完后,重编译整个Buildroot。接上RMSL模组,可通过rmsl_tool获取设备信息。获取设备节点信息
# rmsl_tool --list_devices
Device /dev/video6 info:
usb interface: UVC DEPTH
driver name: uvcvideo
card type: RV1108
bus_info: usb-ff340000.usb-1
Device /dev/video8 info:
usb interface: UVC RGB
driver name: uvcvideo
card type: RV1108
bus_info: usb-ff340000.usb-1
Device /dev/video10 info:
usb interface: UVC IR
driver name: uvcvideo
card type: RV1108
bus_info: usb-ff340000.usb-1
上例说明如下:共有三个video设备节点/dev/video6, /dev/video8, /dev/video10,分别为DEPTH, RGB, IR设备显示出其它信息如USB设备节点,驱动信息查询RMSL的SN码及软件版本
# rmsl_tool --get_sn --get_version --device /dev/video6
SN: R2011301200801448
Version: 2.2.0
在获取数据流前应首先初始化设备
# rmsl_tool --init --device /dev/video6
在结束数据流之后应反初始化设备
# rmsl_tool --deinit --device /dev/video6
在结束数据流之后,也可以reset设备
# rmsl_tool --reset --device /dev/video6
完成init之后,v4l2-ctl、vlc等开源工具是能够获取数据流的,需要注意数据流的格式及大小。rmsl demo中提供的另外一个工具rmsl_linux_demo用于演示完整的init、获取数据流、解码、deinit、显示等功能。此时,不必先用rmsl_tool 工具做初始化工作。查看rmsl_linux_demo的使用帮助
# rmsl_linux_demo --help
Usage of rmsl_linux_demo:
To display and/or save decode frames to files:
--screen-width, screen width, required if need display
--screen-height, screen height, required if need display
--no-display, disable display, by default it's enabled
--save-ir-to, path to save IR decoded frames in NV12
--save-depth-to, path to save DEPTH decoded frames with bpp = 16
--save-rgb-to, path to save RGB decoded frames in NV12
如上所示,rmsl_linux_demo提供了获取数据流并保存成文件、显示在屏幕上的功能。默认情况下显示功能是打开的,如果不需要显示,使用–no-display参数禁用。将图像显示在屏幕上
# rmsl_linux_demo --screen-width 1536 --screen-height 2048
UVC DEPTH: /dev/video5: draw in (0, 480)[640 x 480]
UVC RGB: /dev/video7: draw in (320, 0)[640 x 480]
UVC IR: /dev/video9: draw in (640, 480)[640 x 480]

上图显示了在RK3288屏幕上(1536x2048)的三个视频,从上到下、左到右,分别为RGB,DEPTH,IR。大小都是640x480。其中深度图是直接将视差图以RGB565格式显示出来。不显示图像,但将解码后的帧保存下来
# rmsl_linux_demo --no-display \
--save-ir-to /tmp/ir.bin \
--save-rgb-to /tmp/rgb.bin \
--save-depth-to /tmp/depth.bin
上例中禁用了显示功能,且将三路帧数据分别保存到文件中。其中,ir.bin,保存640x480 NV12帧数据rgb.bin,保存640x480 NV12帧数据depth.bin,保存640x480 深度数据,每个像素2个字节以上三例中,数据流大小默认都是640 * 480,但RGB摄像头可以支持1080p的输出。抓取的文件若在PC机上可以用YUVPlayer(windows环境)或mplayer(Linux环境)查看。其中,mplayer使用可以参考如下命令。
# mplayer /tmp/ir.bin -loop 0 -demuxer rawvideo -fps 15 \
-rawvideo w=640:h=480:size=$((640*480*3/2)):format=nv12
# mplayer /tmp/rgb.bin -loop 0 -demuxer rawvideo -fps 15 \
-rawvideo w=640:h=480:size=$((640*480*3/2)):format=nv12
# mplayer /tmp/depth.bin -loop 0 -demuxer rawvideo -fps 15 \
-rawvideo w=640:h=480:size=$((640*480*2)):format=rgb16
2. demo代码简介
代码位于app/demo/rmsl/目录,包含了RMSL的设置、查询接口,获取数据流并解码、显示功能。
# tree app/demo/rmsl/
app/demo/rmsl/
├── CMakeLists.txt
├── main.c # rmsl_linux_demo的主程序
├── rkdrm_display.c # ⽤于overlay直接显⽰
├── rkdrm_display.h
├── rmsl_api.h # rmsl 主要接⼝定义
├── rmsl_ctrl.c # rmsl 控制、查询等⽅法的实现
├── rmsl_depth.c # 深度图转换的实现
├── rmsl_tool.c # rmsl_tool的主程序
├── vpu_decode.c # vpu jpeg硬件解码接⼝
└── vpu_decode.h
2.1 RMSL控制接口
获取版本
int rmsl_get_version(int fd, char *ver, int size);
参数说明:fd,/dev/video节点对应的文件描述符ver,返回的版本号size,ver数组的大小,应不小RMSL_DATA_SIZE_QUERY成功则返回0,其它值表示错误。获取SN号
int rmsl_get_sn(int fd, char *sn, int size);
参数说明:fd,/dev/video节点对应的文件描述符sn,返回的SN号size,sn数组的大小,应不小RMSL_DATA_SIZE_QUERY成功则返回0,其它值表示错误。初始化/反初始化设备
int rmsl_init_device(int fd);
int rmsl_deinit_device(int fd);
初始化或反初始化设备,使得video节点能够输出数据。
参数说明:fd,/dev/video节点对应的文件描述符成功则返回0,其它值表示错误。重置设备
int rmsl_reset_device(int fd);
参数说明:fd,/dev/video节点对应的文件描述符成功则返回0,其它值表示错误。进入待机
int rmsl_suspend_device(int fd);
参数说明:fd,/dev/video节点对应的文件描述符成功则返回0,其它值表示错误。获取各输出设备的节点名称
int rmsl_get_devices(char *dev_depth, char *dev_ir, char *dev_rgb, int silent);
获取三个视频设备的节点名称,如/dev/video6, /dev/video8等参数说明:dev_depth,返回Depth设备的路径dev_ir,返回IR设备的路径dev_rgb,返回RGB设备的路径silent,1表示不输出log;0会打印一些log成功则返回0,其它值表示错误。转换点云图及深度图
int rmsl_get_point_cloud_depth(const uint16_t *pIn, struct rmsl_pc *pc_out,
uint16_t *depth_out, int width, int height);
根据视差图转换点云图及深度图。参数说明:pIn,Depth 设备输出的视差图帧数据,BPP为16pc_out,点云图输出结果。如果为NULL,不计算点云图depth_out,深度图输出结果。如果为NULL,不计算深度图width,图像的宽height,图像的高
返回值:等于0表示成功计算小于0表示错误大于0表示模组原始的帧数据已经是深度图,不需要计算。(目前无此场景)
2.2 获取数据流
在rmsl_linux_demo中,使用到了rkisp_api.so获取数据流。与普通的USB Camera模组相比,要多一个初始化操作。rkisp_api.so详细接口请参考《Rockchip_Developer_Guide_Linux_Camera_EN.pdf》。
2.3 解码
该demo中使用Rockchip MPP库解码MJPG。将从rkisp_api获取到的数据流交给MPP解码。MPP要求源数据拷⻉一次,考虑到MJPG的每帧的数据量很小,性能上几无影响。解码后的Buffer由RGA分配,这里主要是因为后级需要有可能需要RGA拷⻉以便显示。主要接口:
ret = vpu_decode_jpeg_init(&ctx->decoder, ctx->width, ctx->height);
while (has new frame)
vpu_decode_jpeg_doing(&ctx->decoder, ctx->cur_frame->buf,
ctx->cur_frame->size, ctx->rga_bo_fd, ctx->rga_bo.ptr);
vpu_decode_jpeg_done(&ctx->decoder);
其中:decoder,vpu解码句柄rga_bo_fd,RGA buffer句柄rga_bo.ptr,RGA buffer的虚拟地址
2.4 显示
为尽可能高效地处理数据流并兼顾Rockchip不同芯片的特性,rmsl_linux_demo的显示直接使用了libdrm的接口,将三幅图像通过RGA拷⻉到目标Buffer的具体偏移处,最后送到Rockchip VOP的overlay显示层。主要流程如下图。
彩色Camera MJPG帧 红外Camera MJPG帧

MPP解码 MPP解码
深度Camera帧 彩色NV12帧 红外NV12帧
算法计算 算法计算 RGA拷⻉ RGA转码成rgb565并拷⻉ RGA转码rgb565并拷⻉
深度图 点云图 三路图像合并后的显示Buffer
VOP overlay层显示
这里做了两个假设:假设只有一个overlay层可用。因此使用RGA拷⻉图像到目标Buffer的不同偏移中。例如px30/rk3326就只有一个overlay层将视差图以RGB565显示。显示主要是示例,RGB565的BPP刚好也是16,显示出来只为看清物体的轮廓虽然多了一步RGA转码及拷⻉,但RGA硬件能快速地完成。该demo在px30、rk3288、rk3399平台上能以15fps显示。因为IR及Depth Camera只有15fps,故最多也只有15fps的帧率。性能上可以考虑如下的优化方式:如果有多个overlay层可用,NV12格式可以直接用单独的层显示。共需要三个overlay层,两个用作彩色及红外NV12帧显示,另一个给深度图显示。这样可以省去RGA转码及/或拷⻉部分。RGBCamera也可以达到30fps的帧率。多线程化可提升并发性,特别是在需要处理点云图时,涉及到浮点运算
2.4.1 与QT应用程序结合
用戶如需要QT应用程序来实现如菜单、按键等UI组件,可预留出视频区域,并在需要视频显示时,以rmsl_linux_demo作为参考,将overlay层固定到预留区域中。需要注意的是,overlay层(视频)总是在UI之上,因此如有弹出对话框、菜单等与视频区域重叠,可将视频暂时隐去。以上仅是提供一种参考思路,请开发工程师自由发挥。
3. 常⻅QA
3.1 打开Camera后设备断开
原因是供电不足导致,请使用外接电源的USB hub供电。
原稿差异附录
英文返回值说明写“A positive 0”,中文为“大于0表示原始帧已为深度图无需计算(目前无此情况)”。保留此差异,接口返回语义应以实际库实现为准。以下不同代码保留另一原稿写法,属于独立示例,勿直接拼接执行。
EN PDF p.8 · 38
# tree app/demo/rmsl/
app/demo/rmsl/
├── CMakeLists.txt
├── main.c # main of rmsl_linux_demo
├── rkdrm_display.c # use DRM to display directly on Overlay Plane of
Rockchip devices
├── rkdrm_display.h
├── rmsl_api.h # RMSL API Definition
├── rmsl_ctrl.c # Implementation of rmsl control, query and other
routines
├── rmsl_depth.c # Implementation of depth image conversion
├── rmsl_tool.c # The rmsl_tool source code
├── vpu_decode.c # vpu jpeg hardware decoding interface
└── vpu_decode.h
