├── .clang-format ├── .gitignore ├── README.md ├── changelog_cn.md ├── changelog_en.md ├── doc ├── readme.md └── readme_cn.md ├── license ├── rslidar ├── CHANGELOG.rst ├── CMakeLists.txt └── package.xml ├── rslidar_driver ├── CMakeLists.txt ├── cfg │ └── rslidarNode.cfg ├── nodelet_rslidar.xml ├── package.xml └── src │ ├── CMakeLists.txt │ ├── input.cc │ ├── input.h │ ├── nodelet.cc │ ├── rsdriver.cpp │ ├── rsdriver.h │ └── rslidar_node.cpp ├── rslidar_msgs ├── CMakeLists.txt ├── msg │ ├── rslidarPacket.msg │ └── rslidarScan.msg └── package.xml ├── rslidar_pointcloud ├── CMakeLists.txt ├── cfg │ └── CloudNode.cfg ├── data │ ├── lidar1 │ │ ├── ChannelNum.csv │ │ ├── angle.csv │ │ └── curves.csv │ ├── lidar2 │ │ ├── ChannelNum.csv │ │ ├── angle.csv │ │ └── curves.csv │ ├── rs_bpearl │ │ ├── ChannelNum.csv │ │ └── angle.csv │ ├── rs_lidar_16 │ │ ├── ChannelNum.csv │ │ ├── angle.csv │ │ └── curves.csv │ └── rs_lidar_32 │ │ ├── ChannelNum.csv │ │ ├── CurveRate.csv │ │ ├── angle.csv │ │ └── curves.csv ├── launch │ ├── cloud_nodelet.launch │ ├── rs_bpearl.launch │ ├── rs_lidar_16.launch │ ├── rs_lidar_32.launch │ └── two_lidar.launch ├── nodelets.xml ├── package.xml ├── rviz_cfg │ └── rslidar.rviz └── src │ ├── CMakeLists.txt │ ├── cloud_node.cc │ ├── cloud_nodelet.cc │ ├── convert.cc │ ├── convert.h │ ├── rawdata.cc │ └── rawdata.h ├── rslidar_sync ├── CMakeLists.txt ├── README.md ├── launch │ ├── left_lidar.launch │ ├── middle_lidar.launch │ ├── right_lidar.launch │ ├── rslidar_sync_2lidar.launch │ └── rslidar_sync_3lidar.launch ├── package.xml ├── rviz_cfg │ └── time_sync.rviz └── src │ ├── timesync_2lidar.cpp │ └── timesync_3lidar.cpp └── test_doc └── test_guide_cn.md /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: Google 3 | AccessModifierOffset: -2 4 | ConstructorInitializerIndentWidth: 2 5 | AlignEscapedNewlinesLeft: false 6 | AlignTrailingComments: true 7 | AllowAllParametersOfDeclarationOnNextLine: false 8 | AllowShortIfStatementsOnASingleLine: false 9 | AllowShortLoopsOnASingleLine: false 10 | AllowShortFunctionsOnASingleLine: None 11 | AllowShortLoopsOnASingleLine: false 12 | AlwaysBreakTemplateDeclarations: true 13 | AlwaysBreakBeforeMultilineStrings: false 14 | BreakBeforeBinaryOperators: false 15 | BreakBeforeTernaryOperators: false 16 | BreakConstructorInitializersBeforeComma: true 17 | BinPackParameters: true 18 | ColumnLimit: 120 19 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 20 | DerivePointerBinding: false 21 | PointerBindsToType: true 22 | ExperimentalAutoDetectBinPacking: false 23 | IndentCaseLabels: true 24 | MaxEmptyLinesToKeep: 1 25 | NamespaceIndentation: None 26 | ObjCSpaceBeforeProtocolList: true 27 | PenaltyBreakBeforeFirstCallParameter: 19 28 | PenaltyBreakComment: 60 29 | PenaltyBreakString: 1 30 | PenaltyBreakFirstLessLess: 1000 31 | PenaltyExcessCharacter: 1000 32 | PenaltyReturnTypeOnItsOwnLine: 90 33 | SpacesBeforeTrailingComments: 2 34 | Cpp11BracedListStyle: false 35 | Standard: Auto 36 | IndentWidth: 2 37 | TabWidth: 2 38 | UseTab: Never 39 | IndentFunctionDeclarationAfterType: false 40 | SpacesInParentheses: false 41 | SpacesInAngles: false 42 | SpaceInEmptyParentheses: false 43 | SpacesInCStyleCastParentheses: false 44 | SpaceAfterControlStatementKeyword: true 45 | SpaceBeforeAssignmentOperators: true 46 | ContinuationIndentWidth: 4 47 | SortIncludes: false 48 | SpaceAfterCStyleCast: false 49 | 50 | # Configure each individual brace in BraceWrapping 51 | BreakBeforeBraces: Custom 52 | 53 | # Control of individual brace wrapping cases 54 | BraceWrapping: { 55 | AfterClass: 'true' 56 | AfterControlStatement: 'true' 57 | AfterEnum : 'true' 58 | AfterFunction : 'true' 59 | AfterNamespace : 'true' 60 | AfterStruct : 'true' 61 | AfterUnion : 'true' 62 | BeforeCatch : 'true' 63 | BeforeElse : 'true' 64 | IndentBraces : 'false' 65 | } 66 | ... 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # GNU global tags 2 | GTAGS 3 | GRTAGS 4 | GSYMS 5 | GPATH 6 | 7 | # Python byte-compile file 8 | __pycache__/ 9 | *.py[co] 10 | .ycm_extra_conf.py 11 | # editor backup files 12 | *~ 13 | \#*\# 14 | 15 | # backup files 16 | *.bak 17 | 18 | # Eclipse 19 | .cproject 20 | .project 21 | .pydevproject 22 | .settings/ 23 | 24 | # Visual Studio Code 25 | .vscode/ 26 | 27 | # CLion 28 | .idea/ 29 | cmake-build-debug/ 30 | 31 | # clang-format 32 | #.clang-format 33 | 34 | # ROSBag files 35 | *.bag 36 | 37 | # Environments 38 | .env 39 | .venv 40 | env/ 41 | venv/ 42 | ENV/ 43 | 44 | # Autoware Resources 45 | *.pcap 46 | *.pcd 47 | *.bag 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This project is no longer maintained. Please use our new driver sdk [rslidar_sdk](https://github.com/RoboSense-LiDAR/rslidar_sdk). 2 | 3 | [rslidar_sdk](https://github.com/RoboSense-LiDAR/rslidar_sdk) supports ROS, ROS2, protobuf, and you can even use driver core [rs_driver](https://github.com/RoboSense-LiDAR/rs_driver) in Windows. 4 | 5 | [rs_driver](https://github.com/RoboSense-LiDAR/rs_driver) supports all kind of RoboSense's lidars by now. 6 | -------------------------------------------------------------------------------- /changelog_cn.md: -------------------------------------------------------------------------------- 1 | # RSLidar ROS驱动修改记录 2 | 3 | ### V1.0.0(2017-09-29) 4 | --- 5 | 初版提交 6 | 7 | ### V2.0.0(2017-11-23) 8 | --- 9 | * 1.加入距离随温度的补偿功能。 10 | * 2.移除OpenCV相关的代码 11 | 12 | ### V3.0.0(2018-05-10) 13 | --- 14 | * 1.加入RS-LiDAR-32的功能支持。 15 | * 2.将温度补偿更新到30~71℃。 16 | * 3.使用新的代码架构。 17 | * 4.改变反射率的计算方法。 18 | * 5.兼容不同的标定文件格式。 19 | * 6.加入多雷达时间同步功能。 20 | 21 | ### V3.1.0(2018-07-14) 22 | --- 23 | * 1.在反射率计算中加入温度补偿功能。 24 | * 2.移除package.xml中多余的依赖项。 25 | 26 | ### V4.0.0(2019-04-11) 27 | --- 28 | * 1.新增距离参数**max_distance**和**min_distance**到launch文件设置功能。 29 | * 2.加入difop包解析功能。 30 | * 3.兼容适配0.5cm分辨率雷达。 31 | * 4.修复1cm分辨率雷达解析错误问题。 32 | * 5.增加反射率计算mode=3,直接输出反射强度值,不需要计算标定公式计算。 33 | * 6.新增支持解析雷达**双回波模式**数据。 34 | * 7.将多雷达同步功能的获取时间戳代码从input.cc移到rsdriver.cpp。 35 | * 8.增加**resolution**和**intensity**通过launch文件设置,可以适配bag数据中没有记录difop包的情况。 36 | * 9.增加因为坐标变换引起的XYZ补偿代码。 37 | * 10.规范化代码。 38 | * 11.增加根据水平角度分帧的功能。 39 | 40 | ### V4.1.0(2019-09-11) 41 | --- 42 | * 1.修复不同回波模式下packet_rate参数计算错误问题。 43 | * 2.新增从RS32线的difop包中读取角度标定值。 44 | * 3.更改打印信息输出内容,便于识别打印信息来源。 45 | * 4.更改三角函数计算到查表方式,优化代码执行效率。 46 | * 5.更改不同雷达镜头到转体中心的坐标换。 47 | * 6.修改默认分帧方式到角度分帧,且修改包数分帧的报数对应18K点频设备。 48 | * 7.新增RSBPEARL配置。 49 | 50 | ### V4.1.0(2019-09-11) 51 | --- 52 | * 1.修复BPearl的角度解析错误。 53 | * 2.修复当LiDAR被设置了FOV后出现的角度差值计算错误。 -------------------------------------------------------------------------------- /changelog_en.md: -------------------------------------------------------------------------------- 1 | ## RSLidar ROS Driver Changelog 2 | 3 | ### V1.0.0(2017-09-29) 4 | --- 5 | first release for mutil node version 6 | 7 | ### V2.0.0(2017-11-23) 8 | --- 9 | * 1.Add the temperature compensation for distance. 10 | * 2.Remove the OpenCV code. 11 | 12 | ### V3.0.0(2018-05-10) 13 | --- 14 | * 1.Add new feature: add the RS-LiDAR-32 support 15 | * 2.Fix bug: modify the temperature compensation range to 30~71 degree centigrade. 16 | * 3.Use the new code structure. 17 | * 4.Add new feature: modify the intensity calculation formula. 18 | * 5.Add new feature: compatible with the different calibration files. 19 | * 6.Add new feature: add the multi lidar synchronization function. 20 | 21 | ### V3.1.0(2018-07-14) 22 | --- 23 | * 1.Add new feature: Add temperature compensation in internsity caculation. 24 | * 2.Remove uncessary dependency in package.xml 25 | 26 | ### V4.0.0(2019-04-11) 27 | --- 28 | * 1.Add new feature: add new parameter name and value in launch file where max_distance is used to set maximum distance and min_distance is used to set minimum distance. 29 | * 2.Add the difop packets parser code. 30 | * 3.Add new feature: compatible with firmware which's output distance resolution is 0.5cm. 31 | * 4.Fix bug: fix the wrong distance and coordination of point cloud when output distance resolution of firmware is 1cm. 32 | * 5.Add new feature: compatible with firmware which's output intensity directly without calibration formula (intensity_mode = 3). 33 | * 6.Add new feature: add 'Dual Return' packet parser support 34 | * 7.Move timestamp getting code for multiple lidar 's synchronization from input.cc to rsdriver.cpp 35 | * 8.Add 'Resolution' and 'intensity_mode' parameter into launch file so that it can compatible with the bag files that did not record the difop packets. 36 | * 9.Fix bug: add coordinate transformation compensation into the XYZ calculation 37 | * 10.Normalize the code 38 | * 11.Add the horizontal angle framing code 39 | 40 | ### V4.1.0(2019-09-11) 41 | --- 42 | * 1.Fix bug: fix the packet_rate calculation bug for different return mode. 43 | * 2.Add the function for reading the calibrated angle from difop of RS32. 44 | * 3.Update the log format to make it more clear to know the source of the information. 45 | * 4.Change the trigonometric function calculation to look-up table, this can improve the code performance efficiency. 46 | * 5.Change the coordinate transformation compensation for different lidars. 47 | * 6.Change the scan split way to angle by default. Change the packet_rate value corresponding to 18K sampling rate. 48 | * 7.Add RSBPEARL configuration support. 49 | 50 | ### V4.1.1(2019-11-29) 51 | --- 52 | * 1. Fix bug: fix the angle parsing bug for BPearl 53 | * 2. Fix bug: fix the angle difference error when we set the specific FOV of LiDAR 54 | -------------------------------------------------------------------------------- /doc/readme.md: -------------------------------------------------------------------------------- 1 | #### 1. Prerequisites 2 | (1) Install a ubuntu PC. We suggested Ubuntu 14.04 or Ubuntu 16.04. Please do not use virtual machine. 3 | (2) Install ros full-desktop version. We tried Indigo and Kinect. 4 | (3) Please also install libpcap-dev. 5 | 6 | #### 2. Install 7 | (1). Copy the whole rslidar ROS driver directory into ROS workspace, i.e "~/catkin_ws/src". 8 | 9 | (2). Check the file attributes: 10 | 11 | ``` 12 | cd ~/catkin_ws/src/ros_rslidar/rslidar_drvier 13 | chmod 777 cfg/* 14 | cd ~/catkin_ws/src/ros_rslidar/rslidar_pointcloud 15 | chmod 777 cfg/* 16 | ``` 17 | 18 | (3). Then to compile the source code and to install it: 19 | 20 | ``` 21 | cd ~/catkin_ws 22 | catkin_make 23 | ``` 24 | #### 3. Configure PC IP 25 | By default, the RSLIDAR is configured to **192.168.1.200** as its device IP and **192.168.1.102** as PC IP that it would communicate. The default **MSOP port is 6699** while **DIFOP port is 7788**. 26 | So you need configure your PC IP as a static one **192.168.1.102**. 27 | 28 | #### 4. Run as independent node 29 | We have provide example launch files under rslidar_pointcloud/launch, we can run the launch file to view the point cloud data. For example, if we want to view RS-LiDAR-16 real time data: 30 | (1). Open a new terminal and run: 31 | 32 | ``` 33 | cd ~/catkin_ws 34 | source devel/setup.bash 35 | roslaunch rslidar_pointcloud rs_lidar_16.launch 36 | ``` 37 | 38 | (2). Open a new terminal and run: 39 | 40 | ``` 41 | rviz 42 | ``` 43 | Set the Fixed Frame to "**rslidar**". 44 | Add a Pointcloud2 type and set the topic to "**rslidar_points**". 45 | 46 | #### 5. Run as nodelet 47 | We can also run the driver node and cloud node as a nodelet. 48 | Open a new terminal and run: 49 | 50 | ``` 51 | cd ~/catkin_ws 52 | source devel/setup.bash 53 | roslaunch rslidar_pointcloud cloud_nodelet.launch 54 | ``` 55 | Then we can run view the pointcloud via "rviz" 56 | 57 | #### 6. About the lidar calibration parameters 58 | Under "**rslidar_pointcloud/data**" directory, you can find the lidar calibration parameters files for the exact sensor. By default the launch file "rs_lidar_16.launch" load the three files: 59 | - rslidar_pointcloud/data/rs_lidar_16/angle.csv 60 | - rslidar_pointcloud/data/rs_lidar_16/ChannelNum.csv 61 | - rslidar_pointcloud/data/rs_lidar_16/curves.csv. 62 | 63 | If you have more than one RSLIDAR, you can create new sub-directories under the "**rslidar_pointcloud/data/**", and put the data files into it.Then you need rewrite the launch file to start you lidar. We have put an example launch file "two_lidar.launch" to load two lidars together for reference. 64 | 65 | **Begin from 2018.09.01** 66 | In the launch file, we could set the MSOP port and DIFOP port. 67 | MSOP port is used for receive the main point cloud data, while DIFOP port is used for receive the device information data. If we set the right DIFOP port, we will get the lidar calibration parameters from the DIFOP packets not from the files, so can ignore the local lidar calibration files. About how to check the DIFOP port, please reference the Appendix G in RS-LiDARR manual. 68 | 69 | ### 3.Parameters instruction 70 | There are some parameters need to be set in the launch files for operating LiDAR correctly. 71 | * model: Assign the LiDAR model.There are three selection:RS32,RS16 and RSBPEARL. 72 | * device_ip:Set the LiDAR network ip address. 73 | * msop_port:LiDAR MSOP network port number. 74 | * difop_port:LiDAR DIFOP network port number 75 | * lidar_param_path:The location for the calibration files. 76 | * pcap:The location for the pcap which needs to be parse. After setting this parameter, the online connection for LiDAR will stop. 77 | * curves_path:Assign the location for reflectivity calibration files. Just valid for intensity_mode=1 and intensity_mode=2. 78 | * angle_path:Assign the location for angle calibration files. 79 | * channel_path:Assign the location for distance calibration files. 80 | * curves_rate_path:Assign the location for reflectivity coefficient. This can be set to null by default. 81 | * max_distance:The upper limit for distance. 82 | * min_distance:The lower limit for distance. 83 | * resolution_type:The LSB for distance."0.5cm" or "1cm" . 84 | * intensity_mode:The mode for reflectivity.1, 2 or 3. 85 | * cut_angle:The scan split way for using angle. -------------------------------------------------------------------------------- /doc/readme_cn.md: -------------------------------------------------------------------------------- 1 | # RSLidar ROS 驱动说明 2 | 3 | ### 1. 依赖 4 | * 1.安装ubuntu系统的电脑,推荐Ubuntu14.04或Ubuntu16.04,不要使用虚拟机 5 | * 2.安装 ROS full-desktop版本。建议安装Indigo或Kinect 6 | * 3.安装libpcap-dev 7 | 8 | ### 2. 安装和使用 9 | * 1.将这个rslidar驱动拷贝到ROS工作区,例如“~/catkin_ws/src" 10 | * 2.设置文件访问属性 11 | ``` 12 | cd ~/catkin_ws/src/ros_rslidar/rslidar_drvier 13 | chmod 777 cfg/* 14 | cd ~/catkin_ws/src/ros_rslidar/rslidar_pointcloud 15 | chmod 777 cfg/* 16 | ``` 17 | * 3.编译和安装 18 | ``` 19 | cd ~/catkin_ws 20 | catkin_make 21 | ``` 22 | 23 | * 4.设置PC ip 24 | 默认情况下,RSLIDAR雷达设备ip设置为**192.168.1.200**,而PC ip则设置为**192.168.1.102**;同时默认**MSOP**端口为**6699**,**DIFOP**端口为**7788**. 所以需将PC ip设置为静态ip **192.168.1.102**才能和雷达通信。 25 | 26 | * 5.以node方式运行 27 | 这里提供示例launch文件,可以运行launch文件来观看点云数据。观看RS-LIDAR-16实时点云数据例子操作如下: 28 | 29 | * 1)打开一个终端并执行以下命令 30 | ``` 31 | cd ~/catkin_ws 32 | source devel/setup.bash 33 | roslaunch rslidar_pointcloud rs_lidar_16.launch 34 | ``` 35 | * 2)新开一个终端并执行命令: 36 | ``` 37 | rviz 38 | ``` 39 | 然后设置Fixed Frame为**“rslidar”**,接着添加Pointcloud2 类型和设置topic为**“rslidar_points"**。 40 | 41 | * 6.以nodelet方式运行 42 | 同时支持driver node和cloud node以nodelet方式运行。打开终端并执行以下命令: 43 | ``` 44 | cd ~/catkin_ws 45 | source devel/setup.bash 46 | roslaunch rslidar_pointcloud cloud_nodelet.launch 47 | ``` 48 | 然后运行“rviz”来观看点云。 49 | 50 | * 7.雷达校准参数 51 | **“rslidar_pointcloud/data”**目录下,存放雷达的校准参数文件。通过默认launch文件“rs_lidar_16.launch”加载以下3个文件: 52 | 53 | * rslidar_pointcloud/data/rs_lidar_16/angle.csv 54 | * rslidar_pointcloud/data/rs_lidar_16/ChannelNum.csv 55 | * rslidar_pointcloud/data/rs_lidar_16/curves.csv. 56 | 57 | 如果要新增加雷达,可在**“rslidar_pointcloud/data/”**新建子目录,然后将校准参数文件放到子目录,接着修改launch文件,启动雷达雷达即可。launch文件修改可参考two_lidar.launch文件。 58 | 59 | **2018.09.01**之后在launch文件,可实现设置MSOP和DIFOP的端口。MSOP端口用于接收点云数据;而DIFOP端口用于接收雷达信息数据。如果DIFOP端口设置正确,可通过DIFOP数据包获取雷达的校准参数,而不用再通过校准文件,那可以忽略本地的雷达校准文件。如何检查DIFOP端口,可参考RS_LiDAR用户手册的附录G章节。 60 | 61 | ### 3.参数说明 62 | 雷达有一些参数需要设置,需要通过launch文件进行传递。 63 | * model: 指定雷达类型。目前三个选项 RS32、RS16 和RSBPEARL,分别指32线、16线、补盲雷达 64 | * device_ip:雷达ip 65 | * msop_port:MSOP数据包接收端口 66 | * difop_port:DIFOP数据包接收端口 67 | * lidar_param_path:雷达标定参数文件存放位置 68 | * pcap:要解析的pcap包存放路径。注意指定此参数,则驱动就不会接收从雷达发出的数据 69 | * curves_path:指定反射率标定文件curves.csv完整路径。针对intensity_mode为1和2。 70 | * angle_path:指定角度标定文件angle.csv完整路径 71 | * channel_path:指定距离补偿文件ChannelNum.csv完整路径。一般使用默认全0参数即可。 72 | * curves_rate_path:指定反射率洗漱标定文件CurveRate.csv完整路径。一般不需要 73 | * max_distance:指定点云距离上限 74 | * min_distance:指定点云距离下限 75 | * resolution_type:指定雷达距离解析分辨类型,"0.5cm" 和 "1cm" 二选一 76 | * intensity_mode:指定雷达反射率模式,分别为1,2,3 三选一 77 | * cut_angle:采用角度分帧方式 -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-2020 RoboSense, and others 2 | All rights reserved 3 | 4 | By downloading, copying, installing or using the software you agree to this license. If you do not agree to this license, do not download, install, copy or use the software. 5 | 6 | License Agreement 7 | For RoboSense LiDAR ROS Library 8 | (3-clause BSD License) 9 | 10 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 11 | 12 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 13 | 14 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 15 | 16 | 3. Neither the names of the Robosense, nor Suteng Innovation Technology, nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 19 | 20 | -------------------------------------------------------------------------------- /rslidar/CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | Change history 2 | ============== 3 | 4 | 1.0.0 (2018-12-03): first release for mutil node version 5 | -------------------------------------------------------------------------------- /rslidar/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.3) 2 | project(rslidar) 3 | find_package(catkin REQUIRED) 4 | catkin_metapackage() 5 | -------------------------------------------------------------------------------- /rslidar/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | rslidar 4 | 1.1.0 5 | 6 | Basic ROS support for the Robosense 3D LIDARs. 7 | 8 | Tony Zhang 9 | Tony Zhang 10 | BSD 11 | 12 | catkin 13 | 14 | rslidar_driver 15 | rslidar_msgs 16 | rslidar_pointcloud 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /rslidar_driver/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.3) 2 | project(rslidar_driver) 3 | 4 | add_compile_options(-std=c++11) 5 | set(CMAKE_BUILD_TYPE Release)#RelWithDebInfo 6 | ## Find catkin macros and libraries 7 | ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) 8 | ## is used, also find other catkin packages 9 | set(${PROJECT_NAME}_CATKIN_DEPS 10 | angles 11 | pcl_ros 12 | roscpp 13 | roslib 14 | sensor_msgs 15 | tf 16 | dynamic_reconfigure 17 | diagnostic_updater 18 | rslidar_msgs 19 | nodelet 20 | ) 21 | 22 | set(libpcap_LIBRARIES -lpcap) 23 | 24 | find_package(catkin REQUIRED COMPONENTS 25 | ${${PROJECT_NAME}_CATKIN_DEPS} 26 | pcl_conversions 27 | rospy 28 | std_msgs 29 | genmsg 30 | cv_bridge 31 | message_generation 32 | ) 33 | 34 | find_package(Boost COMPONENTS signals) 35 | find_package(Boost REQUIRED COMPONENTS thread) 36 | find_package(PkgConfig REQUIRED) 37 | 38 | 39 | include_directories(${Boost_INCLUDE_DIR} ${catkin_INCLUDE_DIRS} 40 | ${dynamic_reconfigure_PACKAGE_PATH}/cmake/cfgbuild.cmake) 41 | 42 | generate_dynamic_reconfigure_options(cfg/rslidarNode.cfg) 43 | 44 | catkin_package( 45 | CATKIN_DEPENDS ${${PROJECT_NAME}_CATKIN_DEPS} 46 | CATKIN_DEPENDS message_runtime std_msgs 47 | ) 48 | 49 | add_subdirectory(src) 50 | 51 | -------------------------------------------------------------------------------- /rslidar_driver/cfg/rslidarNode.cfg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | PACKAGE = "rslidar_driver" 3 | NODE_NAME = "fullscan_puber" 4 | PARAMS_NAME = "rslidarNode" 5 | 6 | from math import pi 7 | from dynamic_reconfigure.parameter_generator_catkin import * 8 | 9 | gen = ParameterGenerator() 10 | 11 | gen.add("time_offset", double_t, 0, "A manually calibrated offset (in seconds) to add to the timestamp before publication of a message.", 12 | 0.0, -1.0, 1.0) 13 | 14 | exit(gen.generate(PACKAGE, NODE_NAME, PARAMS_NAME)) 15 | -------------------------------------------------------------------------------- /rslidar_driver/nodelet_rslidar.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Publish raw rslidar data packets. 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /rslidar_driver/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | rslidar_driver 4 | 1.0.0 5 | segmentation 6 | 7 | Tony 8 | Tony Zhang 9 | BSD 10 | 11 | catkin 12 | 13 | angles 14 | nodelet 15 | pcl_conversions 16 | pcl_ros 17 | pluginlib 18 | roscpp 19 | roslib 20 | sensor_msgs 21 | tf 22 | dynamic_reconfigure 23 | roslaunch 24 | rostest 25 | tf2_ros 26 | message_generation 27 | rospy 28 | std_msgs 29 | rslidar_input 30 | pcl_conversions 31 | pcl_ros 32 | libpcl-all-dev 33 | rslidar_msgs 34 | diagnostic_updater 35 | 36 | 37 | angles 38 | pcl_ros 39 | nodelet 40 | pluginlib 41 | 42 | roscpp 43 | roslib 44 | rospy 45 | sensor_msgs 46 | tf 47 | 48 | dynamic_reconfigure 49 | message_runtime 50 | pcl_conversions 51 | pcl_ros 52 | libpcl-all 53 | std_msgs 54 | rslidar_msgs 55 | diagnostic_updater 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /rslidar_driver/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(rslidar_input input.cc) 2 | target_link_libraries(rslidar_input 3 | ${catkin_LIBRARIES} 4 | ${libpcap_LIBRARIES}) 5 | 6 | add_library(rslidar_driver rsdriver.cpp) 7 | target_link_libraries(rslidar_driver 8 | rslidar_input 9 | ${catkin_LIBRARIES}) 10 | 11 | # build the nodelet version 12 | add_library(driver_nodelet nodelet.cc rsdriver.cpp) 13 | target_link_libraries(driver_nodelet 14 | rslidar_input 15 | ${catkin_LIBRARIES} 16 | ) 17 | 18 | add_executable(rslidar_node rslidar_node.cpp) 19 | 20 | if(catkin_EXPORTED_TARGETS) 21 | add_dependencies(rslidar_input ${catkin_EXPORTED_TARGETS}) 22 | endif() 23 | 24 | target_link_libraries(rslidar_node 25 | rslidar_driver 26 | rslidar_input 27 | ${catkin_LIBRARIES} 28 | ${libpcap_LIBRARIES} 29 | ) 30 | 31 | -------------------------------------------------------------------------------- /rslidar_driver/src/input.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2020 Robosense Authors 3 | * License: Modified BSD Software License Agreement 4 | * 5 | * $Id$ 6 | */ 7 | 8 | /** \file 9 | * 10 | * Input classes for the Robosense 3D LIDAR: 11 | * 12 | * Input -- base class used to access the data independently of 13 | * its source 14 | * 15 | * InputSocket -- derived class reads live data from the device 16 | * via a UDP socket 17 | * 18 | * InputPCAP -- derived class provides a similar interface from a 19 | * PCAP dump 20 | */ 21 | #include "input.h" 22 | 23 | extern volatile sig_atomic_t flag; 24 | namespace rslidar_driver 25 | { 26 | static const size_t packet_size = sizeof(rslidar_msgs::rslidarPacket().data); 27 | 28 | //////////////////////////////////////////////////////////////////////// 29 | // Input base class implementation 30 | //////////////////////////////////////////////////////////////////////// 31 | 32 | /** @brief constructor 33 | * 34 | * @param private_nh ROS private handle for calling node. 35 | * @param port UDP port number. 36 | */ 37 | Input::Input(ros::NodeHandle private_nh, uint16_t port) : private_nh_(private_nh), port_(port) 38 | { 39 | npkt_update_flag_ = false; 40 | cur_rpm_ = 600; 41 | return_mode_ = 1; 42 | 43 | private_nh.param("device_ip", devip_str_, std::string("")); 44 | if (!devip_str_.empty()) 45 | { 46 | ROS_INFO_STREAM("[driver][input] accepting packets from IP address: " << devip_str_); 47 | } 48 | } 49 | 50 | int Input::getRpm(void) 51 | { 52 | return cur_rpm_; 53 | } 54 | 55 | int Input::getReturnMode(void) 56 | { 57 | return return_mode_; 58 | } 59 | 60 | bool Input::getUpdateFlag(void) 61 | { 62 | return npkt_update_flag_; 63 | } 64 | 65 | void Input::clearUpdateFlag(void) 66 | { 67 | npkt_update_flag_ = false; 68 | } 69 | //////////////////////////////////////////////////////////////////////// 70 | // InputSocket class implementation 71 | //////////////////////////////////////////////////////////////////////// 72 | 73 | /** @brief constructor 74 | * 75 | * @param private_nh ROS private handle for calling node. 76 | * @param port UDP port number 77 | */ 78 | InputSocket::InputSocket(ros::NodeHandle private_nh, uint16_t port) : Input(private_nh, port) 79 | { 80 | sockfd_ = -1; 81 | 82 | if (!devip_str_.empty()) 83 | { 84 | inet_aton(devip_str_.c_str(), &devip_); 85 | } 86 | 87 | ROS_INFO_STREAM("[driver][socket] Opening UDP socket: port " << port); 88 | sockfd_ = socket(PF_INET, SOCK_DGRAM, 0); 89 | if (sockfd_ == -1) 90 | { 91 | ROS_ERROR("[driver][socket] create socket fail"); 92 | return; 93 | } 94 | 95 | int opt = 1; 96 | if (setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, (const void*)&opt, sizeof(opt))) 97 | { 98 | ROS_ERROR("[driver][socket] setsockopt fail"); 99 | return; 100 | } 101 | 102 | sockaddr_in my_addr; // my address information 103 | memset(&my_addr, 0, sizeof(my_addr)); // initialize to zeros 104 | my_addr.sin_family = AF_INET; // host byte order 105 | my_addr.sin_port = htons(port); // port in network byte order 106 | my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill in my IP 107 | 108 | if (bind(sockfd_, (sockaddr*)&my_addr, sizeof(sockaddr)) == -1) 109 | { 110 | ROS_ERROR("[driver][socket] socket bind fail"); 111 | return; 112 | } 113 | 114 | if (fcntl(sockfd_, F_SETFL, O_NONBLOCK | FASYNC) < 0) 115 | { 116 | ROS_ERROR("[driver][socket] fcntl fail"); 117 | return; 118 | } 119 | } 120 | 121 | /** @brief destructor */ 122 | InputSocket::~InputSocket(void) 123 | { 124 | (void)close(sockfd_); 125 | } 126 | 127 | /** @brief Get one rslidar packet. */ 128 | int InputSocket::getPacket(rslidar_msgs::rslidarPacket* pkt, const double time_offset) 129 | { 130 | double time1 = ros::Time::now().toSec(); 131 | struct pollfd fds[1]; 132 | fds[0].fd = sockfd_; 133 | fds[0].events = POLLIN; 134 | static const int POLL_TIMEOUT = 1000; // one second (in msec) 135 | 136 | sockaddr_in sender_address; 137 | socklen_t sender_address_len = sizeof(sender_address); 138 | while (flag == 1) 139 | { 140 | // Receive packets that should now be available from the 141 | // socket using a blocking read. 142 | // poll() until input available 143 | do 144 | { 145 | int retval = poll(fds, 1, POLL_TIMEOUT); 146 | if (retval < 0) // poll() error? 147 | { 148 | if (errno != EINTR) 149 | { 150 | ROS_ERROR("[driver][socket] poll() error: %s", strerror(errno)); 151 | } 152 | return 1; 153 | } 154 | if (retval == 0) // poll() timeout? 155 | { 156 | ROS_WARN("[driver][socket] Rslidar poll() timeout"); 157 | 158 | char buffer_data[8] = "re-con"; 159 | memset(&sender_address, 0, sender_address_len); // initialize to zeros 160 | sender_address.sin_family = AF_INET; // host byte order 161 | sender_address.sin_port = htons(MSOP_DATA_PORT_NUMBER); // port in network byte order, set any value 162 | sender_address.sin_addr.s_addr = devip_.s_addr; // automatically fill in my IP 163 | sendto(sockfd_, &buffer_data, strlen(buffer_data), 0, (sockaddr*)&sender_address, sender_address_len); 164 | return 1; 165 | } 166 | if ((fds[0].revents & POLLERR) || (fds[0].revents & POLLHUP) || (fds[0].revents & POLLNVAL)) // device error? 167 | { 168 | ROS_ERROR("[driver][socket] poll() reports Rslidar error"); 169 | return 1; 170 | } 171 | } while ((fds[0].revents & POLLIN) == 0); 172 | ssize_t nbytes = recvfrom(sockfd_, &pkt->data[0], packet_size, 0, (sockaddr*)&sender_address, &sender_address_len); 173 | 174 | if (nbytes < 0) 175 | { 176 | if (errno != EWOULDBLOCK) 177 | { 178 | ROS_ERROR("[driver][socket] recvfail"); 179 | return 1; 180 | } 181 | } 182 | else if ((size_t)nbytes == packet_size) 183 | { 184 | if (devip_str_ != "" && sender_address.sin_addr.s_addr != devip_.s_addr) 185 | { 186 | continue; 187 | } 188 | else 189 | { 190 | break; // done 191 | } 192 | } 193 | 194 | ROS_WARN_STREAM("[driver][socket] incomplete rslidar packet read: " << nbytes << " bytes"); 195 | } 196 | if (flag == 0) 197 | { 198 | abort(); 199 | } 200 | 201 | if (pkt->data[0] == 0xA5 && pkt->data[1] == 0xFF && pkt->data[2] == 0x00 && pkt->data[3] == 0x5A) 202 | {//difop 203 | int rpm = (pkt->data[8]<<8)|pkt->data[9]; 204 | int mode = 1; 205 | 206 | if ((pkt->data[45] == 0x08 && pkt->data[46] == 0x02 && pkt->data[47] >= 0x09) || (pkt->data[45] > 0x08) 207 | || (pkt->data[45] == 0x08 && pkt->data[46] > 0x02)) 208 | { 209 | if (pkt->data[300] != 0x01 && pkt->data[300] != 0x02) 210 | { 211 | mode = 0; 212 | } 213 | } 214 | 215 | if (cur_rpm_ != rpm || return_mode_ != mode) 216 | { 217 | cur_rpm_ = rpm; 218 | return_mode_ = mode; 219 | 220 | npkt_update_flag_ = true; 221 | } 222 | } 223 | // Average the times at which we begin and end reading. Use that to 224 | // estimate when the scan occurred. Add the time offset. 225 | double time2 = ros::Time::now().toSec(); 226 | pkt->stamp = ros::Time((time2 + time1) / 2.0 + time_offset); 227 | 228 | return 0; 229 | } 230 | 231 | //////////////////////////////////////////////////////////////////////// 232 | // InputPCAP class implementation 233 | //////////////////////////////////////////////////////////////////////// 234 | 235 | /** @brief constructor 236 | * 237 | * @param private_nh ROS private handle for calling node. 238 | * @param port UDP port number 239 | * @param packet_rate expected device packet frequency (Hz) 240 | * @param filename PCAP dump file name 241 | */ 242 | InputPCAP::InputPCAP(ros::NodeHandle private_nh, uint16_t port, double packet_rate, std::string filename, 243 | bool read_once, bool read_fast, double repeat_delay) 244 | : Input(private_nh, port), packet_rate_(packet_rate), filename_(filename) 245 | { 246 | pcap_ = NULL; 247 | empty_ = true; 248 | 249 | // get parameters using private node handle 250 | private_nh.param("read_once", read_once_, false); 251 | private_nh.param("read_fast", read_fast_, false); 252 | private_nh.param("repeat_delay", repeat_delay_, 0.0); 253 | 254 | if (read_once_) 255 | { 256 | ROS_INFO("[driver][pcap] Read input file only once."); 257 | } 258 | if (read_fast_) 259 | { 260 | ROS_INFO("[driver][pcap] Read input file as quickly as possible."); 261 | } 262 | if (repeat_delay_ > 0.0) 263 | { 264 | ROS_INFO("[driver][pcap] Delay %.3f seconds before repeating input file.", repeat_delay_); 265 | } 266 | 267 | // Open the PCAP dump file 268 | // ROS_INFO("Opening PCAP file \"%s\"", filename_.c_str()); 269 | ROS_INFO_STREAM("[driver][pcap] Opening PCAP file " << filename_); 270 | if ((pcap_ = pcap_open_offline(filename_.c_str(), errbuf_)) == NULL) 271 | { 272 | ROS_FATAL("[driver][pcap] Error opening rslidar socket dump file."); 273 | return; 274 | } 275 | 276 | std::stringstream filter; 277 | if (devip_str_ != "") // using specific IP? 278 | { 279 | filter << "src host " << devip_str_ << " && "; 280 | } 281 | filter << "udp dst port " << port; 282 | int ret = pcap_compile(pcap_, &pcap_packet_filter_, filter.str().c_str(), 1, PCAP_NETMASK_UNKNOWN); 283 | if (ret < 0) 284 | { 285 | ROS_FATAL_STREAM("[driver][pcap] pcap compile filter fail. filter: "<= 0) 306 | { 307 | // Skip packets not for the correct port and from the 308 | // selected IP address. 309 | if (!devip_str_.empty() && (0 == pcap_offline_filter(&pcap_packet_filter_, header, pkt_data))) 310 | continue; 311 | 312 | // Keep the reader from blowing through the file. 313 | if (read_fast_ == false) 314 | packet_rate_.sleep(); 315 | 316 | 317 | memcpy(&pkt->data[0], pkt_data + 42, packet_size); 318 | 319 | if (pkt->data[0] == 0xA5 && pkt->data[1] == 0xFF && pkt->data[2] == 0x00 && pkt->data[3] == 0x5A) 320 | {//difop 321 | int rpm = (pkt->data[8]<<8)|pkt->data[9]; 322 | int mode = 1; 323 | 324 | if ((pkt->data[45] == 0x08 && pkt->data[46] == 0x02 && pkt->data[47] >= 0x09) || (pkt->data[45] > 0x08) 325 | || (pkt->data[45] == 0x08 && pkt->data[46] > 0x02)) 326 | { 327 | if (pkt->data[300] != 0x01 && pkt->data[300] != 0x02) 328 | { 329 | mode = 0; 330 | } 331 | } 332 | 333 | if (cur_rpm_ != rpm || return_mode_ != mode) 334 | { 335 | cur_rpm_ = rpm; 336 | return_mode_ = mode; 337 | 338 | npkt_update_flag_ = true; 339 | } 340 | } 341 | 342 | pkt->stamp = ros::Time::now(); // time_offset not considered here, as no 343 | // synchronization required 344 | empty_ = false; 345 | return 0; // success 346 | } 347 | 348 | if (empty_) // no data in file? 349 | { 350 | ROS_ERROR("[driver][pcap] Error %d reading rslidar packet: %s", res, pcap_geterr(pcap_)); 351 | return -1; 352 | } 353 | 354 | if (read_once_) 355 | { 356 | ROS_INFO("[driver][pcap] end of file reached -- done reading."); 357 | return -1; 358 | } 359 | 360 | if (repeat_delay_ > 0.0) 361 | { 362 | ROS_INFO("[driver][pcap] end of file reached -- delaying %.3f seconds.", repeat_delay_); 363 | usleep(rint(repeat_delay_ * 1000000.0)); 364 | } 365 | 366 | ROS_INFO("[driver][pcap] replaying rslidar dump file"); 367 | 368 | // I can't figure out how to rewind the file, because it 369 | // starts with some kind of header. So, close the file 370 | // and reopen it with pcap. 371 | pcap_close(pcap_); 372 | pcap_ = pcap_open_offline(filename_.c_str(), errbuf_); 373 | empty_ = true; // maybe the file disappeared? 374 | } // loop back and try again 375 | 376 | if (flag == 0) 377 | { 378 | abort(); 379 | } 380 | } 381 | } 382 | -------------------------------------------------------------------------------- /rslidar_driver/src/input.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2020 Robosense Authors 3 | * License: Modified BSD Software License Agreement 4 | * 5 | * $Id$ 6 | */ 7 | 8 | /** \file 9 | * 10 | * Input classes for the Robosense LIDAR: 11 | * 12 | * Input -- base class used to access the data independently of 13 | * its source 14 | * 15 | * InputSocket -- derived class reads live data from the device 16 | * via a UDP socket 17 | * 18 | * InputPCAP -- derived class provides a similar interface from a 19 | * PCAP dump 20 | */ 21 | 22 | #ifndef __RSLIDAR_INPUT_H_ 23 | #define __RSLIDAR_INPUT_H_ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | namespace rslidar_driver 43 | { 44 | static uint16_t MSOP_DATA_PORT_NUMBER = 6699; // rslidar default data port on PC 45 | static uint16_t DIFOP_DATA_PORT_NUMBER = 7788; // rslidar default difop data port on PC 46 | /** 47 | * 从在线的网络数据或离线的网络抓包数据(pcap文件)中提取出lidar的原始数据,即packet数据包 48 | * @brief The Input class, 49 | * 50 | * @param private_nh 一个NodeHandled,用于通过节点传递参数 51 | * @param port 52 | * @returns 0 if successful, 53 | * -1 if end of file 54 | * >0 if incomplete packet (is this possible?) 55 | */ 56 | class Input 57 | { 58 | public: 59 | Input(ros::NodeHandle private_nh, uint16_t port); 60 | 61 | virtual ~Input() 62 | { 63 | } 64 | 65 | virtual int getPacket(rslidar_msgs::rslidarPacket* pkt, const double time_offset) = 0; 66 | 67 | int getRpm(void); 68 | int getReturnMode(void); 69 | bool getUpdateFlag(void); 70 | void clearUpdateFlag(void); 71 | 72 | protected: 73 | ros::NodeHandle private_nh_; 74 | uint16_t port_; 75 | std::string devip_str_; 76 | int cur_rpm_; 77 | int return_mode_; 78 | bool npkt_update_flag_; 79 | }; 80 | 81 | /** @brief Live rslidar input from socket. */ 82 | class InputSocket : public Input 83 | { 84 | public: 85 | InputSocket(ros::NodeHandle private_nh, uint16_t port = MSOP_DATA_PORT_NUMBER); 86 | 87 | virtual ~InputSocket(); 88 | 89 | virtual int getPacket(rslidar_msgs::rslidarPacket* pkt, const double time_offset); 90 | 91 | private: 92 | private: 93 | int sockfd_; 94 | in_addr devip_; 95 | 96 | }; 97 | 98 | /** @brief rslidar input from PCAP dump file. 99 | * 100 | * Dump files can be grabbed by libpcap 101 | */ 102 | class InputPCAP : public Input 103 | { 104 | public: 105 | InputPCAP(ros::NodeHandle private_nh, uint16_t port = MSOP_DATA_PORT_NUMBER, double packet_rate = 0.0, 106 | std::string filename = "", bool read_once = false, bool read_fast = false, double repeat_delay = 0.0); 107 | 108 | virtual ~InputPCAP(); 109 | 110 | virtual int getPacket(rslidar_msgs::rslidarPacket* pkt, const double time_offset); 111 | 112 | private: 113 | ros::Rate packet_rate_; 114 | std::string filename_; 115 | pcap_t* pcap_; 116 | bpf_program pcap_packet_filter_; 117 | char errbuf_[PCAP_ERRBUF_SIZE]; 118 | bool empty_; 119 | bool read_once_; 120 | bool read_fast_; 121 | double repeat_delay_; 122 | }; 123 | } 124 | 125 | #endif // __RSLIDAR_INPUT_H 126 | -------------------------------------------------------------------------------- /rslidar_driver/src/nodelet.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2020 Robosense Authors 3 | * License: Modified BSD Software License Agreement 4 | * 5 | * $Id$ 6 | */ 7 | 8 | /** \file 9 | * 10 | * ROS driver nodelet for the Robosense 3D LIDARs 11 | */ 12 | 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include "rsdriver.h" 21 | 22 | volatile sig_atomic_t flag = 1; 23 | 24 | namespace rslidar_driver 25 | { 26 | class DriverNodelet : public nodelet::Nodelet 27 | { 28 | public: 29 | DriverNodelet() : running_(false) 30 | { 31 | } 32 | 33 | ~DriverNodelet() 34 | { 35 | if (running_) 36 | { 37 | NODELET_INFO("[driver][nodelet] shutting down driver thread"); 38 | running_ = false; 39 | deviceThread_->join(); 40 | NODELET_INFO("[driver][nodelet] sdriver thread stopped"); 41 | } 42 | } 43 | 44 | private: 45 | virtual void onInit(void); 46 | virtual void devicePoll(void); 47 | 48 | volatile bool running_; ///< device thread is running 49 | boost::shared_ptr deviceThread_; 50 | 51 | boost::shared_ptr dvr_; ///< driver implementation class 52 | }; 53 | 54 | void DriverNodelet::onInit() 55 | { 56 | // start the driver 57 | dvr_.reset(new rslidarDriver(getNodeHandle(), getPrivateNodeHandle())); 58 | 59 | // spawn device poll thread 60 | running_ = true; 61 | deviceThread_ = boost::shared_ptr(new boost::thread(boost::bind(&DriverNodelet::devicePoll, this))); 62 | // NODELET_INFO("DriverNodelet onInit"); 63 | } 64 | 65 | /** @brief Device poll thread main loop. */ 66 | void DriverNodelet::devicePoll() 67 | { 68 | while (ros::ok() && dvr_->poll()) 69 | { 70 | ros::spinOnce(); 71 | } 72 | } 73 | } 74 | 75 | // Register this plugin with pluginlib. Names must match nodelet_rslidar.xml. 76 | // 77 | // parameters are: class type, base class type 78 | PLUGINLIB_EXPORT_CLASS(rslidar_driver::DriverNodelet, nodelet::Nodelet) 79 | -------------------------------------------------------------------------------- /rslidar_driver/src/rsdriver.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2020 Robosense Authors 3 | * License: Modified BSD Software License Agreement 4 | * 5 | * $Id$ 6 | */ 7 | 8 | /** \file 9 | * 10 | * ROS driver implementation for the Robosense 3D LIDARs 11 | */ 12 | #include "rsdriver.h" 13 | #include 14 | 15 | namespace rslidar_driver 16 | { 17 | static const unsigned int POINTS_ONE_CHANNEL_PER_SECOND = 18000; 18 | static const unsigned int BLOCKS_ONE_CHANNEL_PER_PKT = 12; 19 | 20 | rslidarDriver::rslidarDriver(ros::NodeHandle node, ros::NodeHandle private_nh) 21 | { 22 | skip_num_ = 0; 23 | // use private node handle to get parameters 24 | private_nh.param("frame_id", config_.frame_id, std::string("rslidar")); 25 | 26 | std::string tf_prefix = tf::getPrefixParam(private_nh); 27 | ROS_DEBUG_STREAM("tf_prefix: " << tf_prefix); 28 | config_.frame_id = tf::resolve(tf_prefix, config_.frame_id); 29 | 30 | // get model name, validate string, determine packet rate 31 | private_nh.param("model", config_.model, std::string("RS16")); 32 | double packet_rate; // packet frequency (Hz) 33 | std::string model_full_name; 34 | 35 | // product model 36 | if (config_.model == "RS16") 37 | { 38 | //for 0.18 degree horizontal angle resolution 39 | //packet_rate = 840; 40 | //for 0.2 degree horizontal angle resolution 41 | packet_rate = 750; 42 | model_full_name = "RS-LiDAR-16"; 43 | } 44 | else if (config_.model == "RS32") 45 | { 46 | //for 0.18 degree horizontal angle resolution 47 | //packet_rate = 1690; 48 | //for 0.2 degree horizontal angle resolution 49 | packet_rate = 1500; 50 | model_full_name = "RS-LiDAR-32"; 51 | } 52 | else if (config_.model == "RSBPEARL") 53 | { 54 | packet_rate = 1500; 55 | model_full_name = "RSBPEARL"; 56 | } 57 | else if (config_.model == "RSBPEARL_MINI") 58 | { 59 | packet_rate = 1500; 60 | model_full_name = "RSBPEARL_MINI"; 61 | } 62 | else 63 | { 64 | ROS_ERROR_STREAM("[driver] unknown LIDAR model: " << config_.model); 65 | packet_rate = 2600.0; 66 | } 67 | std::string deviceName(std::string("Robosense ") + model_full_name); 68 | 69 | private_nh.param("rpm", config_.rpm, 600.0); 70 | double frequency = (config_.rpm / 60.0); // expected Hz rate 71 | 72 | // default number of packets for each scan is a single revolution 73 | // (fractions rounded up) 74 | 75 | int npackets = (int)ceil(packet_rate / frequency); 76 | private_nh.param("npackets", config_.npackets, npackets); 77 | ROS_INFO_STREAM("[driver] publishing " << config_.npackets << " packets per scan"); 78 | 79 | std::string dump_file; 80 | private_nh.param("pcap", dump_file, std::string("")); 81 | 82 | int msop_udp_port; 83 | private_nh.param("msop_port", msop_udp_port, (int)MSOP_DATA_PORT_NUMBER); 84 | int difop_udp_port; 85 | private_nh.param("difop_port", difop_udp_port, (int)DIFOP_DATA_PORT_NUMBER); 86 | 87 | double cut_angle; 88 | private_nh.param("cut_angle", cut_angle, -0.01); 89 | if (cut_angle < 0.0) 90 | { 91 | ROS_INFO_STREAM("[driver] Cut at specific angle feature deactivated."); 92 | } 93 | else if (cut_angle < 360) 94 | { 95 | ROS_INFO_STREAM("[driver] Cut at specific angle feature activated. " 96 | "Cutting rslidar points always at " 97 | << cut_angle << " degree."); 98 | } 99 | else 100 | { 101 | ROS_ERROR_STREAM("[driver] cut_angle parameter is out of range. Allowed range is " 102 | << "between 0.0 and 360 negative values to deactivate this feature."); 103 | cut_angle = -0.01; 104 | } 105 | 106 | // Convert cut_angle from radian to one-hundredth degree, 107 | // which is used in rslidar packets 108 | config_.cut_angle = static_cast(cut_angle * 100); 109 | 110 | // Initialize dynamic reconfigure 111 | srv_ = boost::make_shared >(private_nh); 112 | dynamic_reconfigure::Server::CallbackType f; 113 | f = boost::bind(&rslidarDriver::callback, this, _1, _2); 114 | srv_->setCallback(f); // Set callback function und call initially 115 | 116 | // initialize diagnostics 117 | diagnostics_.setHardwareID(deviceName); 118 | const double diag_freq = packet_rate / config_.npackets; 119 | diag_max_freq_ = diag_freq; 120 | diag_min_freq_ = diag_freq; 121 | // ROS_INFO("expected frequency: %.3f (Hz)", diag_freq); 122 | 123 | using namespace diagnostic_updater; 124 | diag_topic_.reset(new TopicDiagnostic("rslidar_packets", diagnostics_, 125 | FrequencyStatusParam(&diag_min_freq_, &diag_max_freq_, 0.1, 10), 126 | TimeStampStatusParam())); 127 | 128 | // open rslidar input device or file 129 | if (dump_file != "") // have PCAP file? 130 | { 131 | // read data from packet capture file 132 | msop_input_.reset(new rslidar_driver::InputPCAP(private_nh, msop_udp_port, packet_rate, dump_file)); 133 | difop_input_.reset(new rslidar_driver::InputPCAP(private_nh, difop_udp_port, packet_rate, dump_file)); 134 | } 135 | else 136 | { 137 | // read data from live socket 138 | msop_input_.reset(new rslidar_driver::InputSocket(private_nh, msop_udp_port)); 139 | difop_input_.reset(new rslidar_driver::InputSocket(private_nh, difop_udp_port)); 140 | } 141 | 142 | // raw packet output topic 143 | std::string output_packets_topic; 144 | private_nh.param("output_packets_topic", output_packets_topic, std::string("rslidar_packets")); 145 | msop_output_ = node.advertise(output_packets_topic, 10); 146 | 147 | std::string output_difop_topic; 148 | private_nh.param("output_difop_topic", output_difop_topic, std::string("rslidar_packets_difop")); 149 | difop_output_ = node.advertise(output_difop_topic, 10); 150 | 151 | difop_thread_ = boost::shared_ptr(new boost::thread(boost::bind(&rslidarDriver::difopPoll, this))); 152 | 153 | private_nh.param("time_synchronization", time_synchronization_, false); 154 | 155 | if (time_synchronization_) 156 | { 157 | output_sync_ = node.advertise("sync_header", 1); 158 | skip_num_sub_ = node.subscribe("skippackets_num", 1, &rslidarDriver::skipNumCallback, 159 | (rslidarDriver*)this, ros::TransportHints().tcpNoDelay(true)); 160 | } 161 | } 162 | 163 | /** poll the device 164 | * 165 | * @returns true unless end of file reached 166 | */ 167 | bool rslidarDriver::poll(void) 168 | { // Allocate a new shared pointer for zero-copy sharing with other nodelets. 169 | rslidar_msgs::rslidarScanPtr scan(new rslidar_msgs::rslidarScan); 170 | 171 | // Since the rslidar delivers data at a very high rate, keep 172 | // reading and publishing scans as fast as possible. 173 | if (config_.cut_angle >= 0) // Cut at specific angle feature enabled 174 | { 175 | scan->packets.reserve(config_.npackets); 176 | rslidar_msgs::rslidarPacket tmp_packet; 177 | while (true) 178 | { 179 | while (true) 180 | { 181 | int rc = msop_input_->getPacket(&tmp_packet, config_.time_offset); 182 | if (rc == 0) 183 | break; // got a full packet? 184 | if (rc < 0) 185 | return false; // end of file reached? 186 | } 187 | scan->packets.push_back(tmp_packet); 188 | 189 | static int ANGLE_HEAD = -36001; // note: cannot be set to -1, or stack smashing 190 | static int last_azimuth = ANGLE_HEAD; 191 | 192 | int azimuth = 256 * tmp_packet.data[44] + tmp_packet.data[45]; 193 | // int azimuth = *( (u_int16_t*) (&tmp_packet.data[azimuth_data_pos])); 194 | 195 | // Handle overflow 35999->0 196 | if (azimuth < last_azimuth) 197 | { 198 | last_azimuth -= 36000; 199 | } 200 | // Check if currently passing cut angle 201 | if (last_azimuth != ANGLE_HEAD && last_azimuth < config_.cut_angle && azimuth >= config_.cut_angle) 202 | { 203 | last_azimuth = azimuth; 204 | break; // Cut angle passed, one full revolution collected 205 | } 206 | last_azimuth = azimuth; 207 | } 208 | } 209 | else // standard behaviour 210 | { 211 | if (difop_input_->getUpdateFlag()) 212 | { 213 | int packets_rate = ceil(POINTS_ONE_CHANNEL_PER_SECOND/BLOCKS_ONE_CHANNEL_PER_PKT); 214 | int mode = difop_input_->getReturnMode(); 215 | if (config_.model == "RS16" && (mode == 1 || mode == 2)) 216 | { 217 | packets_rate = ceil(packets_rate/2); 218 | } 219 | else if ((config_.model == "RS32" || config_.model == "RSBPEARL" || config_.model == "RSBPEARL_MINI") && (mode == 0)) 220 | { 221 | packets_rate = packets_rate*2; 222 | } 223 | config_.rpm = difop_input_->getRpm(); 224 | config_.npackets = ceil(packets_rate*60/config_.rpm); 225 | 226 | difop_input_->clearUpdateFlag(); 227 | 228 | ROS_INFO_STREAM("[driver] update npackets. rpm: "<packets.resize(config_.npackets); 231 | // use in standard behaviour only 232 | while (skip_num_) 233 | { 234 | while (true) 235 | { 236 | // keep reading until full packet received 237 | int rc = msop_input_->getPacket(&scan->packets[0], config_.time_offset); 238 | if (rc == 0) 239 | break; // got a full packet? 240 | if (rc < 0) 241 | return false; // end of file reached? 242 | } 243 | --skip_num_; 244 | } 245 | 246 | for (int i = 0; i < config_.npackets; ++i) 247 | { 248 | while (true) 249 | { 250 | // keep reading until full packet received 251 | int rc = msop_input_->getPacket(&scan->packets[i], config_.time_offset); 252 | if (rc == 0) 253 | break; // got a full packet? 254 | if (rc < 0) 255 | return false; // end of file reached? 256 | } 257 | } 258 | 259 | if (time_synchronization_) 260 | { 261 | sensor_msgs::TimeReference sync_header; 262 | // it is already the msop msg 263 | // if (pkt->data[0] == 0x55 && pkt->data[1] == 0xaa && pkt->data[2] == 0x05 && pkt->data[3] == 0x0a) 264 | // use the first packets 265 | rslidar_msgs::rslidarPacket pkt = scan->packets[0]; 266 | struct tm stm; 267 | memset(&stm, 0, sizeof(stm)); 268 | stm.tm_year = (int)pkt.data[20] + 100; 269 | stm.tm_mon = (int)pkt.data[21] - 1; 270 | stm.tm_mday = (int)pkt.data[22]; 271 | stm.tm_hour = (int)pkt.data[23]; 272 | stm.tm_min = (int)pkt.data[24]; 273 | stm.tm_sec = (int)pkt.data[25]; 274 | double stamp_double = mktime(&stm) + 0.001 * (256 * pkt.data[26] + pkt.data[27]) + 275 | 0.000001 * (256 * pkt.data[28] + pkt.data[29]); 276 | sync_header.header.stamp = ros::Time(stamp_double); 277 | 278 | output_sync_.publish(sync_header); 279 | } 280 | } 281 | 282 | // publish message using time of last packet read 283 | // ROS_DEBUG("[driver] Publishing a full rslidar scan."); 284 | scan->header.stamp = scan->packets.back().stamp; 285 | scan->header.frame_id = config_.frame_id; 286 | msop_output_.publish(scan); 287 | 288 | // notify diagnostics that a message has been published, updating its status 289 | diag_topic_->tick(scan->header.stamp); 290 | diagnostics_.update(); 291 | 292 | return true; 293 | } 294 | 295 | void rslidarDriver::difopPoll(void) 296 | { 297 | // reading and publishing scans as fast as possible. 298 | rslidar_msgs::rslidarPacketPtr difop_packet_ptr(new rslidar_msgs::rslidarPacket); 299 | while (ros::ok()) 300 | { 301 | // keep reading 302 | rslidar_msgs::rslidarPacket difop_packet_msg; 303 | int rc = difop_input_->getPacket(&difop_packet_msg, config_.time_offset); 304 | if (rc == 0) 305 | { 306 | // ROS_DEBUG("[driver] Publishing a difop data."); 307 | *difop_packet_ptr = difop_packet_msg; 308 | difop_output_.publish(difop_packet_ptr); 309 | } 310 | if (rc < 0) 311 | return; // end of file reached? 312 | ros::spinOnce(); 313 | } 314 | } 315 | 316 | void rslidarDriver::callback(rslidar_driver::rslidarNodeConfig& config, uint32_t level) 317 | { 318 | // ROS_INFO("[driver] Reconfigure Request"); 319 | config_.time_offset = config.time_offset; 320 | } 321 | 322 | // add for time synchronization 323 | void rslidarDriver::skipNumCallback(const std_msgs::Int32::ConstPtr& skip_num) 324 | { 325 | // std::cout << "Enter skipNumCallback: " << skip_num->data << std::endl; 326 | skip_num_ = skip_num->data; 327 | } 328 | } // namespace rslidar_driver 329 | -------------------------------------------------------------------------------- /rslidar_driver/src/rsdriver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2020 Robosense Authors 3 | * License: Modified BSD Software License Agreement 4 | * 5 | * $Id$ 6 | */ 7 | 8 | /** \file 9 | * 10 | * ROS driver interface for the Robosense 3D LIDARs 11 | */ 12 | #ifndef _RSDRIVER_H_ 13 | #define _RSDRIVER_H_ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "input.h" 27 | 28 | namespace rslidar_driver 29 | { 30 | class rslidarDriver 31 | { 32 | public: 33 | /** 34 | * @brief rslidarDriver 35 | * @param node raw packet output topic 36 | * @param private_nh 通过这个节点传参数 37 | */ 38 | rslidarDriver(ros::NodeHandle node, ros::NodeHandle private_nh); 39 | 40 | ~rslidarDriver() 41 | { 42 | } 43 | 44 | bool poll(void); 45 | void difopPoll(void); 46 | 47 | private: 48 | /// Callback for dynamic reconfigure 49 | void callback(rslidar_driver::rslidarNodeConfig& config, uint32_t level); 50 | /// Callback for skip num for time synchronization 51 | void skipNumCallback(const std_msgs::Int32::ConstPtr& skip_num); 52 | 53 | /// Pointer to dynamic reconfigure service srv_ 54 | boost::shared_ptr > srv_; 55 | 56 | // configuration parameters 57 | struct 58 | { 59 | std::string frame_id; ///< tf frame ID 60 | std::string model; ///< device model name 61 | int npackets; ///< number of packets to collect 62 | double rpm; ///< device rotation rate (RPMs) 63 | double time_offset; ///< time in seconds added to each time stamp 64 | int cut_angle; 65 | } config_; 66 | 67 | boost::shared_ptr msop_input_; 68 | boost::shared_ptr difop_input_; 69 | ros::Publisher msop_output_; 70 | ros::Publisher difop_output_; 71 | ros::Publisher output_sync_; 72 | // Converter convtor_; 73 | /** diagnostics updater */ 74 | diagnostic_updater::Updater diagnostics_; 75 | double diag_min_freq_; 76 | double diag_max_freq_; 77 | boost::shared_ptr diag_topic_; 78 | boost::shared_ptr difop_thread_; 79 | 80 | // add for time synchronization 81 | bool time_synchronization_; 82 | uint32_t skip_num_; 83 | ros::Subscriber skip_num_sub_; 84 | }; 85 | 86 | } // namespace rslidar_driver 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /rslidar_driver/src/rslidar_node.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2020 Robosense Authors 3 | * License: Modified BSD Software License Agreement 4 | * 5 | * $Id$ 6 | */ 7 | 8 | /** \file 9 | * 10 | * ROS driver node for the Robosense 3D LIDARs. 11 | */ 12 | #include 13 | #include "rsdriver.h" 14 | #include "std_msgs/String.h" 15 | 16 | using namespace rslidar_driver; 17 | volatile sig_atomic_t flag = 1; 18 | 19 | static void my_handler(int sig) 20 | { 21 | flag = 0; 22 | } 23 | 24 | int main(int argc, char** argv) 25 | { 26 | ros::init(argc, argv, "rsdriver"); 27 | ros::NodeHandle node; 28 | ros::NodeHandle private_nh("~"); 29 | 30 | signal(SIGINT, my_handler); 31 | 32 | // start the driver 33 | rslidar_driver::rslidarDriver dvr(node, private_nh); 34 | // loop until shut down or end of file 35 | while (ros::ok() && dvr.poll()) 36 | { 37 | ros::spinOnce(); 38 | } 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /rslidar_msgs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.3) 2 | project(rslidar_msgs) 3 | 4 | find_package(catkin REQUIRED COMPONENTS message_generation std_msgs) 5 | 6 | add_message_files( 7 | DIRECTORY msg 8 | FILES 9 | rslidarPacket.msg 10 | rslidarScan.msg 11 | ) 12 | generate_messages(DEPENDENCIES std_msgs) 13 | 14 | catkin_package( 15 | CATKIN_DEPENDS message_runtime std_msgs 16 | ) 17 | -------------------------------------------------------------------------------- /rslidar_msgs/msg/rslidarPacket.msg: -------------------------------------------------------------------------------- 1 | # Raw LIDAR packet. 2 | 3 | time stamp # packet timestamp 4 | uint8[1248] data # packet contents 5 | 6 | -------------------------------------------------------------------------------- /rslidar_msgs/msg/rslidarScan.msg: -------------------------------------------------------------------------------- 1 | # LIDAR scan packets. 2 | 3 | Header header # standard ROS message header 4 | rslidarPacket[] packets # vector of raw packets 5 | -------------------------------------------------------------------------------- /rslidar_msgs/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | rslidar_msgs 4 | 1.0.0 5 | 6 | ROS message definitions for Rslidar 3D LIDARs. 7 | 8 | Tony Zhang 9 | Tony Zhang 10 | BSD 11 | 12 | 13 | catkin 14 | 15 | message_generation 16 | std_msgs 17 | 18 | message_runtime 19 | std_msgs 20 | 21 | 22 | -------------------------------------------------------------------------------- /rslidar_pointcloud/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.3) 2 | project(rslidar_pointcloud) 3 | 4 | add_compile_options(-std=c++11) 5 | set(CMAKE_BUILD_TYPE Release)#RelWithDebInfo 6 | set(${PROJECT_NAME}_CATKIN_DEPS 7 | angles 8 | nodelet 9 | pcl_ros 10 | roscpp 11 | roslib 12 | sensor_msgs 13 | tf 14 | rslidar_driver 15 | rslidar_msgs 16 | dynamic_reconfigure 17 | ) 18 | 19 | find_package(catkin REQUIRED COMPONENTS 20 | ${${PROJECT_NAME}_CATKIN_DEPS} pcl_conversions) 21 | find_package(Boost COMPONENTS signals) 22 | find_package(PkgConfig REQUIRED) 23 | include_directories(${catkin_INCLUDE_DIRS} 24 | ${dynamic_reconfigure_PACKAGE_PATH}/cmake/cfgbuild.cmake 25 | ) 26 | 27 | generate_dynamic_reconfigure_options(cfg/CloudNode.cfg) 28 | 29 | catkin_package( 30 | CATKIN_DEPENDS ${${PROJECT_NAME}_CATKIN_DEPS} 31 | ) 32 | 33 | add_subdirectory(src) 34 | -------------------------------------------------------------------------------- /rslidar_pointcloud/cfg/CloudNode.cfg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | PACKAGE = "rslidar_pointcloud" 3 | 4 | from math import pi 5 | from dynamic_reconfigure.parameter_generator_catkin import * 6 | 7 | gen = ParameterGenerator() 8 | 9 | gen.add("time_offset", double_t, 0, "A manually calibrated offset (in seconds) to add to the timestamp before publication of a message.", 10 | 0.0, -1.0, 1.0) 11 | 12 | 13 | exit(gen.generate(PACKAGE, "cloud_node", "CloudNode")) 14 | -------------------------------------------------------------------------------- /rslidar_pointcloud/data/lidar1/ChannelNum.csv: -------------------------------------------------------------------------------- 1 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 2 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 3 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 4 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 5 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 6 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 7 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 8 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 9 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 10 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 11 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 12 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 13 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 14 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 15 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 16 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 17 | -------------------------------------------------------------------------------- /rslidar_pointcloud/data/lidar1/angle.csv: -------------------------------------------------------------------------------- 1 | -14.9559 2 | -12.9460 3 | -10.9169 4 | -8.9541 5 | -6.9592 6 | -4.9829 7 | -2.9588 8 | -0.9274 9 | 15.0228 10 | 13.0276 11 | 10.9686 12 | 8.9960 13 | 7.0298 14 | 5.0611 15 | 3.0160 16 | 1.0455 17 | -------------------------------------------------------------------------------- /rslidar_pointcloud/data/lidar1/curves.csv: -------------------------------------------------------------------------------- 1 | 20.26,21.02,21.47,19.81,20.92,16.34,18.38,15,15.33,14.47,15.02,14.75,15.6,15.65,15.46,15.18 2 | 3.236,3.362,3.43,3.171,3.346,2.614,2.941,2.394,2.454,2.313,2.405,2.363,2.515,2.504,2.46,2.436 3 | 1.186,1.354,2.171,1.237,1.271,1.57,1.145,1.57,1.608,1.533,1.51,1.353,1.106,1.39,1.673,1.599 4 | 14.23,25.42,15.47,6.734,21.44,8.996,5.323,4.386,5.528,3.97,5.492,5.227,3.239,5.394,5.955,4.877 5 | 0.07468,0.0859,0.06859,0.07038,0.07101,0.05011,0.05272,0.04714,0.05424,0.05364,0.05385,0.05084,0.04908,0.04862,0.04714,0.04714 6 | -1.235,-1.606,-1.112,-1.006,-1.223,-0.7429,-0.8428,-0.6681,-0.8384,-0.889,-0.8348,-0.7302,-0.7143,-0.7469,-0.6935,-0.6681 7 | 14.77,20.7,13.32,11.86,17.38,9.332,12.01,7.657,9.517,8.638,9.538,8.7,9.396,8.464,8.901,7.657 8 | -------------------------------------------------------------------------------- /rslidar_pointcloud/data/lidar2/ChannelNum.csv: -------------------------------------------------------------------------------- 1 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 2 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 3 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 4 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 5 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 6 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 7 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 8 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 9 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 10 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 11 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 12 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 13 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 14 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 15 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 16 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 17 | -------------------------------------------------------------------------------- /rslidar_pointcloud/data/lidar2/angle.csv: -------------------------------------------------------------------------------- 1 | -15.0762 2 | -13.0208 3 | -10.9997 4 | -9.0204 5 | -7.0192 6 | -5.0006 7 | -3.0410 8 | -1.0384 9 | 15.0094 10 | 12.9868 11 | 10.9307 12 | 8.9855 13 | 6.9487 14 | 5.0006 15 | 2.9696 16 | 1.0026 17 | -------------------------------------------------------------------------------- /rslidar_pointcloud/data/lidar2/curves.csv: -------------------------------------------------------------------------------- 1 | 20.26,21.02,21.47,19.81,20.92,16.34,18.38,15,15.33,14.47,15.02,14.75,15.6,15.65,15.46,15.18 2 | 3.236,3.362,3.43,3.171,3.346,2.614,2.941,2.394,2.454,2.313,2.405,2.363,2.515,2.504,2.46,2.436 3 | 1.186,1.354,2.171,1.237,1.271,1.57,1.145,1.57,1.608,1.533,1.51,1.353,1.106,1.39,1.673,1.599 4 | 14.23,25.42,15.47,6.734,21.44,8.996,5.323,4.386,5.528,3.97,5.492,5.227,3.239,5.394,5.955,4.877 5 | 0.07468,0.0859,0.06859,0.07038,0.07101,0.05011,0.05272,0.04714,0.05424,0.05364,0.05385,0.05084,0.04908,0.04862,0.04714,0.04714 6 | -1.235,-1.606,-1.112,-1.006,-1.223,-0.7429,-0.8428,-0.6681,-0.8384,-0.889,-0.8348,-0.7302,-0.7143,-0.7469,-0.6935,-0.6681 7 | 14.77,20.7,13.32,11.86,17.38,9.332,12.01,7.657,9.517,8.638,9.538,8.7,9.396,8.464,8.901,7.657 8 | -------------------------------------------------------------------------------- /rslidar_pointcloud/data/rs_bpearl/ChannelNum.csv: -------------------------------------------------------------------------------- 1 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 2 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 3 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 4 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 5 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 6 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 7 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 8 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 9 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 10 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 11 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 12 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 13 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 14 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 15 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 16 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 17 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 18 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 19 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 20 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 21 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 22 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 23 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 24 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 25 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 26 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 27 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 28 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 29 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 30 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 31 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 32 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 33 | 31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81 34 | -------------------------------------------------------------------------------- /rslidar_pointcloud/data/rs_bpearl/angle.csv: -------------------------------------------------------------------------------- 1 | 89.5,0 2 | 86.6875,0 3 | 83.875,0 4 | 81.0625,0 5 | 78.25,0 6 | 75.4375,0 7 | 72.625,0 8 | 69.8125,0 9 | 67,0 10 | 64.1875,0 11 | 61.375,0 12 | 58.5625,0 13 | 55.75,0 14 | 52.9375,0 15 | 50.125,0 16 | 47.3125,0 17 | 44.5,0 18 | 41.6875,0 19 | 38.875,0 20 | 36.0625,0 21 | 33.25,0 22 | 30.4375,0 23 | 27.625,0 24 | 24.8125,0 25 | 22,0 26 | 19.1875,0 27 | 16.375,0 28 | 13.5625,0 29 | 10.75,0 30 | 7.9375,0 31 | 5.125,0 32 | 2.3125,0 33 | -------------------------------------------------------------------------------- /rslidar_pointcloud/data/rs_lidar_16/ChannelNum.csv: -------------------------------------------------------------------------------- 1 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 2 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 3 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 4 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 5 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 6 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 7 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 8 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 9 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 10 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 11 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 12 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 13 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 14 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 15 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 16 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 17 | -------------------------------------------------------------------------------- /rslidar_pointcloud/data/rs_lidar_16/angle.csv: -------------------------------------------------------------------------------- 1 | -14.9994 2 | -12.9766 3 | -10.9894 4 | -8.9750 5 | -6.9734 6 | -4.9900 7 | -2.9946 8 | -0.9918 9 | 14.9860 10 | 12.9630 11 | 10.9756 12 | 8.9960 13 | 6.9945 14 | 5.0113 15 | 2.9803 16 | 1.0133 -------------------------------------------------------------------------------- /rslidar_pointcloud/data/rs_lidar_16/curves.csv: -------------------------------------------------------------------------------- 1 | 20.26,21.02,21.47,19.81,20.92,16.34,18.38,15,15.33,14.47,15.02,14.75,15.6,15.65,15.46,15.18 2 | 3.236,3.362,3.43,3.171,3.346,2.614,2.941,2.394,2.454,2.313,2.405,2.363,2.515,2.504,2.46,2.436 3 | 1.186,1.354,2.171,1.237,1.271,1.57,1.145,1.57,1.608,1.533,1.51,1.353,1.106,1.39,1.673,1.599 4 | 14.23,25.42,15.47,6.734,21.44,8.996,5.323,4.386,5.528,3.97,5.492,5.227,3.239,5.394,5.955,4.877 5 | 0.07468,0.0859,0.06859,0.07038,0.07101,0.05011,0.05272,0.04714,0.05424,0.05364,0.05385,0.05084,0.04908,0.04862,0.04714,0.04714 6 | -1.235,-1.606,-1.112,-1.006,-1.223,-0.7429,-0.8428,-0.6681,-0.8384,-0.889,-0.8348,-0.7302,-0.7143,-0.7469,-0.6935,-0.6681 7 | 14.77,20.7,13.32,11.86,17.38,9.332,12.01,7.657,9.517,8.638,9.538,8.7,9.396,8.464,8.901,7.657 8 | -------------------------------------------------------------------------------- /rslidar_pointcloud/data/rs_lidar_32/ChannelNum.csv: -------------------------------------------------------------------------------- 1 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 2 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 3 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 4 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 5 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 6 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 7 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 8 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 9 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 10 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 11 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 12 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 13 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 14 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 15 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 16 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 17 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 18 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 19 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 20 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 21 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 22 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 23 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 24 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 25 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 26 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 27 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 28 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 29 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 30 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 31 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 32 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 33 | 31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81 34 | -------------------------------------------------------------------------------- /rslidar_pointcloud/data/rs_lidar_32/CurveRate.csv: -------------------------------------------------------------------------------- 1 | 1 2 | 1 3 | 1 4 | 1 5 | 1 6 | 1 7 | 1 8 | 1 9 | 1 10 | 1 11 | 1 12 | 1 13 | 1 14 | 1 15 | 1 16 | 1 17 | 1 18 | 1 19 | 1 20 | 1 21 | 1 22 | 1 23 | 1 24 | 1 25 | 1 26 | 1 27 | 1 28 | 1 29 | 1 30 | 1 31 | 1 32 | 1 33 | -------------------------------------------------------------------------------- /rslidar_pointcloud/data/rs_lidar_32/angle.csv: -------------------------------------------------------------------------------- 1 | -10.2637,9.1205 2 | 0.2972,-7.1203 3 | -6.4063,8.9109 4 | -0.0179,-1.7781 5 | 2.2794,9.1205 6 | -0.3330,3.5716 7 | 3.2973,-6.8380 8 | -0.6670,8.7856 9 | 4.6136,9.1205 10 | 1.6849,-7.1555 11 | 7.0176,-6.7674 12 | 1.2972,-1.8139 13 | 10.2983,9.0507 14 | 1.0000,3.4859 15 | 15.0167,-6.9439 16 | 0.7028,8.9007 17 | -25.0000,-6.6968 18 | -2.2794,-7.3317 19 | -14.6380,-6.6614 20 | -2.6670,-2.0000 21 | -7.9100,-6.7674 22 | -3.0179,3.3932 23 | -5.4070,-6.8380 24 | -3.2973,8.8060 25 | -3.6492,-7.1908 26 | -1.0179,-7.2965 27 | -4.0534,-1.8643 28 | -1.3330,-1.8139 29 | -4.3864,3.4932 30 | -1.6312,3.5716 31 | -4.6492,8.8060 32 | -1.9821,8.7308 -------------------------------------------------------------------------------- /rslidar_pointcloud/data/rs_lidar_32/curves.csv: -------------------------------------------------------------------------------- 1 | 9.146,14.59,9.765,11.67,10.89,6.767,12.25,6.767,9.641,14.28,11.4,18.12,10.25,19.72,18.15,19.6,16.01,13.77,14.51,13.82,9.894,12.95,8.204,11.97,13.65,15.78,15.14,14.57,11.65,12.28,3.5,12.31 2 | 1.471,2.336,1.564,1.868,1.74,1.084,1.957,1.084,1.543,2.286,1.82,3.231,1.64,3.157,2.884,3.135,2.558,2.203,2.321,2.211,1.584,2.071,1.299,1.916,2.182,2.524,2.423,2.333,1.862,1.972,0.5675,1.972 3 | 4.091,1.158,2.611,2.033,1.861,5.428,1.166,5.428,2.306,1.546,1.328,3.672,2.915,3.027,0.8046,2.81,1.283,0.9306,1.263,1.102,1.683,2.184,2.304,5.983,1.695,1.106,1.08,2.36,3.328,2.908,2.633,3.482 4 | 6.06,4.316,4.457,4.847,6.098,5.203,4.178,5.203,6.216,7.532,4.563,8.926,6.743,7.91,7.246e-08,7.586,8.587,4.376,3.76,5.592,6.678,8.152,3.622,6.286,6.715,7.819,5.758,4.781,8.349,6.168,6.162,6.204 5 | 0.07359,0.05948,0.05485,0.08061,0.05223,0.1015,0.05232,0.1015,0.06199,0.06027,0.06084,0.07249,0.08784,0.07249,0.0688,0.07249,0.2397,0.06514,0.05794,0.05276,0.06672,0.06231,0.06167,0.07097,0.0631,0.06867,0.05846,0.06226,0.0602,0.0594,0.06162,0.1272 6 | -1.207,-0.4436,-0.5708,-1.042,-0.8002,-1.576,-0.6504,-1.576,-1.063,-0.5388,-0.4561,-0.8357,-1.002,-0.8357,-0.696,-0.8357,-3.747,-0.6581,-0.6612,-0.6709,-0.6868,-0.7484,-0.9373,-0.9974,-0.5119,-0.4602,-0.6081,-0.8116,-0.6385,-0.6696,-0.6901,-2.445 7 | 13.02,9.64,6.718,10.79,11.49,14.06,8.267,14.06,12.36,10.2,6.484,8.279,11.72,8.279,7.048,8.279,32.67,11.99,7.598,10.62,9.679,11.77,8.828,10.03,9.267,11.96,10.68,9.459,10.36,9.944,9.401,21.9 8 | -------------------------------------------------------------------------------- /rslidar_pointcloud/launch/cloud_nodelet.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /rslidar_pointcloud/launch/rs_bpearl.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /rslidar_pointcloud/launch/rs_lidar_16.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /rslidar_pointcloud/launch/rs_lidar_32.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /rslidar_pointcloud/launch/two_lidar.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /rslidar_pointcloud/nodelets.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Aggregates points from multiple packets, publishing PointCloud2. 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /rslidar_pointcloud/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | rslidar_pointcloud 4 | 1.0.0 5 | 6 | Point cloud conversions for rslidar 3D LIDARs. 7 | 8 | Tony 9 | Tony Zhang 10 | George Wang 11 | Piyush Khandelwal 12 | Jesse Vera 13 | BSD 14 | 15 | catkin 16 | 17 | angles 18 | nodelet 19 | pcl_conversions 20 | pcl_ros 21 | pluginlib 22 | roscpp 23 | roslib 24 | sensor_msgs 25 | tf 26 | rslidar_driver 27 | rslidar_msgs 28 | dynamic_reconfigure 29 | 30 | 31 | roslaunch 32 | rostest 33 | tf2_ros 34 | 35 | angles 36 | nodelet 37 | pcl_ros 38 | pluginlib 39 | 40 | roscpp 41 | roslib 42 | sensor_msgs 43 | tf 44 | rslidar_driver 45 | rslidar_msgs 46 | 47 | dynamic_reconfigure 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /rslidar_pointcloud/rviz_cfg/rslidar.rviz: -------------------------------------------------------------------------------- 1 | Panels: 2 | - Class: rviz/Displays 3 | Help Height: 89 4 | Name: Displays 5 | Property Tree Widget: 6 | Expanded: 7 | - /Global Options1 8 | - /Status1 9 | - /Grid1 10 | - /PointCloud21 11 | - /PointCloud21/Autocompute Value Bounds1 12 | - /Axes1 13 | Splitter Ratio: 0.5 14 | Tree Height: 733 15 | - Class: rviz/Selection 16 | Name: Selection 17 | - Class: rviz/Tool Properties 18 | Expanded: 19 | - /2D Pose Estimate1 20 | - /2D Nav Goal1 21 | - /Publish Point1 22 | Name: Tool Properties 23 | Splitter Ratio: 0.588679016 24 | - Class: rviz/Views 25 | Expanded: 26 | - /Current View1 27 | Name: Views 28 | Splitter Ratio: 0.5 29 | - Class: rviz/Time 30 | Experimental: false 31 | Name: Time 32 | SyncMode: 0 33 | SyncSource: PointCloud2 34 | Visualization Manager: 35 | Class: "" 36 | Displays: 37 | - Alpha: 0.5 38 | Cell Size: 10 39 | Class: rviz/Grid 40 | Color: 160; 160; 164 41 | Enabled: true 42 | Line Style: 43 | Line Width: 0.0299999993 44 | Value: Lines 45 | Name: Grid 46 | Normal Cell Count: 0 47 | Offset: 48 | X: 0 49 | Y: 0 50 | Z: 0 51 | Plane: XY 52 | Plane Cell Count: 20 53 | Reference Frame: 54 | Value: true 55 | - Alpha: 1 56 | Autocompute Intensity Bounds: true 57 | Autocompute Value Bounds: 58 | Max Value: 135.535004 59 | Min Value: -69.2572021 60 | Value: false 61 | Axis: X 62 | Channel Name: intensity 63 | Class: rviz/PointCloud2 64 | Color: 255; 255; 255 65 | Color Transformer: Intensity 66 | Decay Time: 0 67 | Enabled: true 68 | Invert Rainbow: false 69 | Max Color: 255; 255; 255 70 | Max Intensity: 226 71 | Min Color: 0; 0; 0 72 | Min Intensity: 1 73 | Name: PointCloud2 74 | Position Transformer: XYZ 75 | Queue Size: 255 76 | Selectable: true 77 | Size (Pixels): 2 78 | Size (m): 0.00999999978 79 | Style: Points 80 | Topic: /rslidar_points 81 | Unreliable: true 82 | Use Fixed Frame: true 83 | Use rainbow: true 84 | Value: true 85 | - Class: rviz/Axes 86 | Enabled: true 87 | Length: 1 88 | Name: Axes 89 | Radius: 0.100000001 90 | Reference Frame: 91 | Value: true 92 | Enabled: true 93 | Global Options: 94 | Background Color: 48; 48; 48 95 | Default Light: true 96 | Fixed Frame: rslidar 97 | Frame Rate: 10 98 | Name: root 99 | Tools: 100 | - Class: rviz/Interact 101 | Hide Inactive Objects: true 102 | - Class: rviz/MoveCamera 103 | - Class: rviz/Select 104 | - Class: rviz/FocusCamera 105 | - Class: rviz/Measure 106 | - Class: rviz/SetInitialPose 107 | Topic: /initialpose 108 | - Class: rviz/SetGoal 109 | Topic: /move_base_simple/goal 110 | - Class: rviz/PublishPoint 111 | Single click: true 112 | Topic: /clicked_point 113 | Value: true 114 | Views: 115 | Current: 116 | Class: rviz/ThirdPersonFollower 117 | Distance: 49.6928291 118 | Enable Stereo Rendering: 119 | Stereo Eye Separation: 0.0599999987 120 | Stereo Focal Distance: 1 121 | Swap Stereo Eyes: false 122 | Value: false 123 | Focal Point: 124 | X: 4.06498575 125 | Y: -10.8205557 126 | Z: -2.45250994e-05 127 | Focal Shape Fixed Size: true 128 | Focal Shape Size: 0.0500000007 129 | Invert Z Axis: false 130 | Name: Current View 131 | Near Clip Distance: 0.00999999978 132 | Pitch: 1.14480078 133 | Target Frame: aft_mapped 134 | Value: ThirdPersonFollower (rviz) 135 | Yaw: 4.18355608 136 | Saved: ~ 137 | Window Geometry: 138 | Displays: 139 | collapsed: false 140 | Height: 1027 141 | Hide Left Dock: false 142 | Hide Right Dock: true 143 | QMainWindow State: 000000ff00000000fd00000004000000000000016a00000377fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006100fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000002800000377000000d700fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f00000394fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000002800000394000000ad00fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e100000197000000030000073f00000040fc0100000002fb0000000800540069006d006501000000000000073f0000030000fffffffb0000000800540069006d00650100000000000004500000000000000000000005cf0000037700000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 144 | Selection: 145 | collapsed: false 146 | Time: 147 | collapsed: false 148 | Tool Properties: 149 | collapsed: false 150 | Views: 151 | collapsed: true 152 | Width: 1855 153 | X: 65 154 | Y: 43 155 | -------------------------------------------------------------------------------- /rslidar_pointcloud/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(rslidar_data rawdata.cc) 2 | target_link_libraries(rslidar_data 3 | ${catkin_LIBRARIES} 4 | ${libpcap_LIBRARIES}) 5 | 6 | add_library(rslidar_point convert.cc) 7 | target_link_libraries(rslidar_point 8 | rslidar_data 9 | ${catkin_LIBRARIES}) 10 | 11 | 12 | add_library(cloud_nodelet cloud_nodelet.cc) 13 | target_link_libraries(cloud_nodelet rslidar_point 14 | ${catkin_LIBRARIES}) 15 | 16 | add_executable(cloud_node cloud_node.cc) 17 | 18 | if(catkin_EXPORTED_TARGETS) 19 | add_dependencies(rslidar_data ${catkin_EXPORTED_TARGETS}) 20 | endif() 21 | 22 | target_link_libraries(cloud_node 23 | rslidar_point 24 | ${catkin_LIBRARIES} 25 | ${libpcap_LIBRARIES}) 26 | -------------------------------------------------------------------------------- /rslidar_pointcloud/src/cloud_node.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2020 Robosense Authors 3 | * License: Modified BSD Software License Agreement 4 | * 5 | * $Id$ 6 | */ 7 | 8 | /** \file 9 | 10 | This ROS node converts raw Robosense 3D LIDAR packets to PointCloud2. 11 | 12 | */ 13 | #include "convert.h" 14 | 15 | /** Main node entry point. */ 16 | int main(int argc, char** argv) 17 | { 18 | ros::init(argc, argv, "cloud_node"); 19 | ros::NodeHandle node; 20 | ros::NodeHandle priv_nh("~"); 21 | 22 | // create conversion class, which subscribes to raw data 23 | rslidar_pointcloud::Convert conv(node, priv_nh); 24 | 25 | // handle callbacks until shut down 26 | ros::spin(); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /rslidar_pointcloud/src/cloud_nodelet.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2020 Robosense Authors 3 | * License: Modified BSD Software License Agreement 4 | * 5 | * $Id$ 6 | */ 7 | 8 | /** @file 9 | 10 | This ROS nodelet converts raw Robosense 3D LIDAR packets to a 11 | PointCloud2. 12 | 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include "convert.h" 20 | 21 | namespace rslidar_pointcloud 22 | { 23 | class CloudNodelet : public nodelet::Nodelet 24 | { 25 | public: 26 | CloudNodelet() 27 | { 28 | } 29 | ~CloudNodelet() 30 | { 31 | } 32 | 33 | private: 34 | virtual void onInit(); 35 | boost::shared_ptr conv_; 36 | }; 37 | 38 | /** @brief Nodelet initialization. */ 39 | void CloudNodelet::onInit() 40 | { 41 | conv_.reset(new Convert(getNodeHandle(), getPrivateNodeHandle())); 42 | } 43 | 44 | } // namespace rslidar_pointcloud 45 | 46 | // Register this plugin with pluginlib. Names must match nodelets.xml. 47 | // 48 | // parameters: class type, base class type 49 | PLUGINLIB_EXPORT_CLASS(rslidar_pointcloud::CloudNodelet, nodelet::Nodelet) 50 | -------------------------------------------------------------------------------- /rslidar_pointcloud/src/convert.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2020 Robosense Authors 3 | * License: Modified BSD Software License Agreement 4 | * 5 | * $Id$ 6 | */ 7 | 8 | /** @file 9 | 10 | This class converts raw Robosense 3D LIDAR packets to PointCloud2. 11 | 12 | */ 13 | #include "convert.h" 14 | #include 15 | 16 | namespace rslidar_pointcloud 17 | { 18 | std::string model; 19 | 20 | /** @brief Constructor. */ 21 | Convert::Convert(ros::NodeHandle node, ros::NodeHandle private_nh) : data_(new rslidar_rawdata::RawData()) 22 | { 23 | data_->loadConfigFile(node, private_nh); // load lidar parameters 24 | private_nh.param("model", model, std::string("RS16")); 25 | 26 | // advertise output point cloud (before subscribing to input data) 27 | std::string output_points_topic; 28 | private_nh.param("output_points_topic", output_points_topic, std::string("rslidar_points")); 29 | output_ = node.advertise(output_points_topic, 10); 30 | 31 | srv_ = boost::make_shared >(private_nh); 32 | dynamic_reconfigure::Server::CallbackType f; 33 | f = boost::bind(&Convert::callback, this, _1, _2); 34 | srv_->setCallback(f); 35 | 36 | // subscribe to rslidarScan packets 37 | std::string input_packets_topic; 38 | private_nh.param("input_packets_topic", input_packets_topic, std::string("rslidar_packets")); 39 | rslidar_scan_ = node.subscribe(input_packets_topic, 10, &Convert::processScan, (Convert*)this, 40 | ros::TransportHints().tcpNoDelay(true)); 41 | } 42 | 43 | void Convert::callback(rslidar_pointcloud::CloudNodeConfig& config, uint32_t level) 44 | { 45 | // ROS_INFO("[cloud][convert] Reconfigure Request"); 46 | // config_.time_offset = config.time_offset; 47 | } 48 | 49 | /** @brief Callback for raw scan messages. */ 50 | void Convert::processScan(const rslidar_msgs::rslidarScan::ConstPtr& scanMsg) 51 | { 52 | pcl::PointCloud::Ptr outPoints(new pcl::PointCloud); 53 | outPoints->header.stamp = pcl_conversions::toPCL(scanMsg->header).stamp; 54 | outPoints->header.frame_id = scanMsg->header.frame_id; 55 | outPoints->clear(); 56 | if (model == "RS16") 57 | { 58 | outPoints->height = 16; 59 | outPoints->width = 24 * (int)scanMsg->packets.size(); 60 | outPoints->is_dense = false; 61 | outPoints->resize(outPoints->height * outPoints->width); 62 | } 63 | else if (model == "RS32" || model == "RSBPEARL" || model == "RSBPEARL_MINI") 64 | { 65 | outPoints->height = 32; 66 | outPoints->width = 12 * (int)scanMsg->packets.size(); 67 | outPoints->is_dense = false; 68 | outPoints->resize(outPoints->height * outPoints->width); 69 | } 70 | 71 | // process each packet provided by the driver 72 | 73 | data_->block_num = 0; 74 | for (size_t i = 0; i < scanMsg->packets.size(); ++i) 75 | { 76 | data_->unpack(scanMsg->packets[i], outPoints); 77 | } 78 | sensor_msgs::PointCloud2 outMsg; 79 | pcl::toROSMsg(*outPoints, outMsg); 80 | 81 | output_.publish(outMsg); 82 | } 83 | } // namespace rslidar_pointcloud 84 | -------------------------------------------------------------------------------- /rslidar_pointcloud/src/convert.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2020 Robosense Authors 3 | * License: Modified BSD Software License Agreement 4 | * 5 | * $Id$ 6 | */ 7 | 8 | /** @file 9 | 10 | This class converts raw Robosense 3D LIDAR packets to PointCloud2. 11 | 12 | */ 13 | #ifndef _CONVERT_H_ 14 | #define _CONVERT_H_ 15 | 16 | #include 17 | #include 18 | #include 19 | #include "rawdata.h" 20 | 21 | namespace rslidar_pointcloud 22 | { 23 | class Convert 24 | { 25 | public: 26 | Convert(ros::NodeHandle node, ros::NodeHandle private_nh); 27 | 28 | ~Convert() 29 | { 30 | } 31 | 32 | private: 33 | void callback(rslidar_pointcloud::CloudNodeConfig& config, uint32_t level); 34 | 35 | void processScan(const rslidar_msgs::rslidarScan::ConstPtr& scanMsg); 36 | 37 | /// Pointer to dynamic reconfigure service srv_ 38 | boost::shared_ptr > srv_; 39 | 40 | boost::shared_ptr data_; 41 | ros::Subscriber rslidar_scan_; 42 | ros::Publisher output_; 43 | }; 44 | 45 | } // namespace rslidar_pointcloud 46 | #endif 47 | -------------------------------------------------------------------------------- /rslidar_pointcloud/src/rawdata.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2020 Robosense Authors 3 | * License: Modified BSD Software License Agreement 4 | * 5 | * $Id$ 6 | */ 7 | 8 | /** 9 | * @file 10 | * 11 | * RSLIDAR 3D LIDAR data accessor class implementation. 12 | * 13 | * Class for unpacking raw Robosense 3D LIDAR packets into useful 14 | * formats. 15 | * 16 | */ 17 | #include "rawdata.h" 18 | 19 | namespace rslidar_rawdata 20 | { 21 | RawData::RawData() 22 | { 23 | this->is_init_angle_ = false; 24 | this->is_init_curve_ = false; 25 | this->is_init_top_fw_ = false; 26 | } 27 | 28 | void RawData::loadConfigFile(ros::NodeHandle node, ros::NodeHandle private_nh) 29 | { 30 | std::string anglePath, curvesPath, channelPath, curvesRatePath; 31 | std::string model; 32 | std::string sub_model; 33 | std::string resolution_param; 34 | private_nh.param("model", model, std::string("RS16")); 35 | private_nh.param("curves_path", curvesPath, std::string("")); 36 | private_nh.param("angle_path", anglePath, std::string("")); 37 | private_nh.param("channel_path", channelPath, std::string("")); 38 | private_nh.param("curves_rate_path", curvesRatePath, std::string("")); 39 | private_nh.param("start_angle", start_angle_, int(0)); 40 | private_nh.param("end_angle", end_angle_, int(360)); 41 | 42 | ROS_INFO_STREAM("[cloud][rawdata] lidar model: " << model); 43 | if (start_angle_ < 0 || start_angle_ > 360 || end_angle_ < 0 || end_angle_ > 360) 44 | { 45 | start_angle_ = 0; 46 | end_angle_ = 360; 47 | ROS_INFO_STREAM("[cloud][rawdata] start and end angle select feature deactivated."); 48 | } 49 | else 50 | { 51 | ROS_INFO_STREAM("[cloud][rawdata] start and end angle feature activated."); 52 | } 53 | 54 | angle_flag_ = true; 55 | if (start_angle_ > end_angle_) 56 | { 57 | angle_flag_ = false; 58 | // ROS_INFO_STREAM("[cloud][rawdata] Start angle is smaller than end angle, not the normal state!"); 59 | } 60 | 61 | ROS_INFO_STREAM("[cloud][rawdata] start_angle: " << start_angle_ << " end_angle: " << end_angle_ 62 | << " angle_flag: " << angle_flag_); 63 | start_angle_ = start_angle_ * 100; 64 | end_angle_ = end_angle_ * 100; 65 | 66 | private_nh.param("max_distance", max_distance_, 200.0f); 67 | private_nh.param("min_distance", min_distance_, 0.4f); 68 | 69 | ROS_INFO_STREAM("[cloud][rawdata] distance threshlod, max: " << max_distance_ << " m, min: " << min_distance_ 70 | << " m"); 71 | 72 | intensity_mode_ = 3; 73 | info_print_flag_ = false; 74 | private_nh.param("resolution_type", resolution_param, std::string("0.5cm")); 75 | private_nh.param("intensity_mode", intensity_mode_, 1); 76 | 77 | if (resolution_param == "0.5cm") 78 | { 79 | dis_resolution_mode_ = 0; 80 | } 81 | else 82 | { 83 | dis_resolution_mode_ = 1; 84 | } 85 | 86 | ROS_INFO_STREAM("[cloud][rawdata] initialize resolution type: " << (dis_resolution_mode_ ? "1 cm" : "0.5 cm") 87 | << ", intensity mode: " << intensity_mode_); 88 | 89 | if (model == "RS16") 90 | { 91 | numOfLasers = 16; 92 | Rx_ = 0.03825; 93 | Ry_ = -0.01088; 94 | Rz_ = 0; 95 | } 96 | else if (model == "RS32") 97 | { 98 | numOfLasers = 32; 99 | TEMPERATURE_RANGE = 50; 100 | Rx_ = 0.03997; 101 | Ry_ = -0.01087; 102 | Rz_ = 0; 103 | isBpearlLidar_ = false; 104 | } 105 | else if(model == "RSBPEARL") 106 | { 107 | numOfLasers = 32; 108 | TEMPERATURE_RANGE = 50; 109 | Rx_ = 0.01697; 110 | Ry_ = -0.0085; 111 | Rz_ = 0.12644; 112 | isBpearlLidar_ = true; 113 | } 114 | else if (model == "RSBPEARL_MINI") 115 | { 116 | numOfLasers = 32; 117 | TEMPERATURE_RANGE = 50; 118 | Rx_ = 0.01473; 119 | Ry_ = 0.0085; 120 | Rz_ = 0.09427; 121 | isBpearlLidar_ = true; 122 | } 123 | else 124 | { 125 | std::cout << "Bad model!" << std::endl; 126 | } 127 | 128 | intensityFactor = 51; 129 | 130 | // return mode default 131 | return_mode_ = 1; 132 | 133 | // lookup table init 134 | this->cos_lookup_table_.resize(36000); 135 | this->sin_lookup_table_.resize(36000); 136 | for (unsigned int i = 0; i < 36000; i++) 137 | { 138 | double rad = RS_TO_RADS(i / 100.0f); 139 | 140 | this->cos_lookup_table_[i] = std::cos(rad); 141 | this->sin_lookup_table_[i] = std::sin(rad); 142 | } 143 | 144 | /// 读参数文件 2017-02-27 145 | FILE* f_inten = fopen(curvesPath.c_str(), "r"); 146 | int loopi = 0; 147 | int loopj = 0; 148 | int loop_num; 149 | if (!f_inten) 150 | { 151 | ROS_WARN_STREAM("[cloud][rawdata] " << curvesPath << " does not exist"); 152 | } 153 | else 154 | { 155 | fseek(f_inten, 0, SEEK_END); //定位到文件末 156 | int size = ftell(f_inten); //文件长度 157 | 158 | if (size > 10000) //老版的curve 159 | { 160 | Curvesis_new = false; 161 | loop_num = 1600; 162 | } 163 | else 164 | { 165 | Curvesis_new = true; 166 | loop_num = 7; 167 | } 168 | fseek(f_inten, 0, SEEK_SET); 169 | while (!feof(f_inten)) 170 | { 171 | float a[32]; 172 | loopi++; 173 | 174 | if (loopi > loop_num) 175 | break; 176 | if (numOfLasers == 16) 177 | { 178 | int tmp = fscanf(f_inten, "%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f\n", &a[0], &a[1], &a[2], &a[3], 179 | &a[4], &a[5], &a[6], &a[7], &a[8], &a[9], &a[10], &a[11], &a[12], &a[13], &a[14], &a[15]); 180 | } 181 | else if (numOfLasers == 32) 182 | { 183 | int tmp = fscanf(f_inten, 184 | "%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f," 185 | "%f,%f,%f,%f\n", 186 | &a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7], &a[8], &a[9], &a[10], &a[11], &a[12], 187 | &a[13], &a[14], &a[15], &a[16], &a[17], &a[18], &a[19], &a[20], &a[21], &a[22], &a[23], &a[24], 188 | &a[25], &a[26], &a[27], &a[28], &a[29], &a[30], &a[31]); 189 | } 190 | if (Curvesis_new) 191 | { 192 | for (loopj = 0; loopj < numOfLasers; loopj++) 193 | { 194 | aIntensityCal[loopi - 1][loopj] = a[loopj]; 195 | } 196 | } 197 | else 198 | { 199 | for (loopj = 0; loopj < numOfLasers; loopj++) 200 | { 201 | aIntensityCal_old[loopi - 1][loopj] = a[loopj]; 202 | } 203 | } 204 | // ROS_INFO_STREAM("new is " << a[0]); 205 | } 206 | fclose(f_inten); 207 | } 208 | //============================================================= 209 | FILE* f_angle = fopen(anglePath.c_str(), "r"); 210 | if (!f_angle) 211 | { 212 | ROS_WARN_STREAM("[cloud][rawdata] " << anglePath << " does not exist"); 213 | } 214 | else 215 | { 216 | float b[32], d[32]; 217 | int loopk = 0; 218 | int loopn = 0; 219 | while (!feof(f_angle)) 220 | { 221 | int tmp = fscanf(f_angle, "%f,%f\n", &b[loopk], &d[loopk]); 222 | loopk++; 223 | if (loopk > (numOfLasers - 1)) 224 | break; 225 | } 226 | for (loopn = 0; loopn < numOfLasers; loopn++) 227 | { 228 | VERT_ANGLE[loopn] = b[loopn] * 100; 229 | HORI_ANGLE[loopn] = d[loopn] * 100; 230 | } 231 | 232 | if (numOfLasers == 16) 233 | { 234 | memset(HORI_ANGLE, 0, sizeof(HORI_ANGLE)); 235 | } 236 | 237 | fclose(f_angle); 238 | } 239 | 240 | //============================================================= 241 | FILE* f_channel = fopen(channelPath.c_str(), "r"); 242 | if (!f_channel) 243 | { 244 | ROS_WARN_STREAM("[cloud][rawdata] " << channelPath << " does not exist"); 245 | } 246 | else 247 | { 248 | int loopl = 0; 249 | int loopm = 0; 250 | int c[51]; 251 | int tempMode = 1; 252 | while (!feof(f_channel)) 253 | { 254 | if (numOfLasers == 16) 255 | { 256 | int tmp = fscanf(f_channel, 257 | "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%" 258 | "d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", 259 | &c[0], &c[1], &c[2], &c[3], &c[4], &c[5], &c[6], &c[7], &c[8], &c[9], &c[10], &c[11], &c[12], 260 | &c[13], &c[14], &c[15], &c[16], &c[17], &c[18], &c[19], &c[20], &c[21], &c[22], &c[23], &c[24], 261 | &c[25], &c[26], &c[27], &c[28], &c[29], &c[30], &c[31], &c[32], &c[33], &c[34], &c[35], &c[36], 262 | &c[37], &c[38], &c[39], &c[40]); 263 | } 264 | else 265 | { 266 | int tmp = fscanf(f_channel, 267 | "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%" 268 | "d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", 269 | &c[0], &c[1], &c[2], &c[3], &c[4], &c[5], &c[6], &c[7], &c[8], &c[9], &c[10], &c[11], &c[12], 270 | &c[13], &c[14], &c[15], &c[16], &c[17], &c[18], &c[19], &c[20], &c[21], &c[22], &c[23], &c[24], 271 | &c[25], &c[26], &c[27], &c[28], &c[29], &c[30], &c[31], &c[32], &c[33], &c[34], &c[35], &c[36], 272 | &c[37], &c[38], &c[39], &c[40], &c[41], &c[42], &c[43], &c[44], &c[45], &c[46], &c[47], &c[48], 273 | &c[49], &c[50]); 274 | } 275 | for (loopl = 0; loopl < TEMPERATURE_RANGE + 1; loopl++) 276 | { 277 | g_ChannelNum[loopm][loopl] = c[tempMode * loopl]; 278 | } 279 | loopm++; 280 | if (loopm > (numOfLasers - 1)) 281 | { 282 | break; 283 | } 284 | } 285 | fclose(f_channel); 286 | } 287 | 288 | if (numOfLasers == 32) 289 | { 290 | FILE* f_curvesRate = fopen(curvesRatePath.c_str(), "r"); 291 | if (!f_curvesRate) 292 | { 293 | ROS_WARN_STREAM("[cloud][rawdata] " << curvesRatePath << " does not exist"); 294 | for (int i = 0; i < 32; ++i) 295 | { 296 | CurvesRate[i] = 1.0; 297 | } 298 | } 299 | else 300 | { 301 | int loopk = 0; 302 | while (!feof(f_curvesRate)) 303 | { 304 | int tmp = fscanf(f_curvesRate, "%f\n", &CurvesRate[loopk]); 305 | loopk++; 306 | if (loopk > (numOfLasers - 1)) 307 | break; 308 | } 309 | fclose(f_curvesRate); 310 | } 311 | } 312 | 313 | // receive difop data 314 | // subscribe to difop rslidar packets, if not right correct data in difop, it will not revise the correct data in the 315 | // VERT_ANGLE, HORI_ANGLE etc. 316 | difop_sub_ = node.subscribe("rslidar_packets_difop", 10, &RawData::processDifop, (RawData*)this); 317 | temperature_pub_ = node.advertise("temperature", 10); 318 | } 319 | 320 | void RawData::processDifop(const rslidar_msgs::rslidarPacket::ConstPtr& difop_msg) 321 | { 322 | // std::cout << "Enter difop callback!" << std::endl; 323 | const uint8_t* data = &difop_msg->data[0]; 324 | bool is_support_dual_return = false; 325 | 326 | // check header 327 | if (data[0] != 0xa5 || data[1] != 0xff || data[2] != 0x00 || data[3] != 0x5a) 328 | { 329 | return; 330 | } 331 | 332 | // uint8_t save_return_mode = return_mode_; 333 | // return mode check 334 | if ((data[45] == 0x08 && data[46] == 0x02 && data[47] >= 0x09) || (data[45] > 0x08) || 335 | (data[45] == 0x08 && data[46] > 0x02)) 336 | { 337 | is_support_dual_return = true; 338 | if (data[300] == 0x01 || data[300] == 0x02) 339 | { 340 | return_mode_ = data[300]; 341 | } 342 | else 343 | { 344 | return_mode_ = 0; 345 | } 346 | } 347 | else 348 | { 349 | is_support_dual_return = false; 350 | return_mode_ = 1; 351 | } 352 | // 353 | if (!this->is_init_top_fw_) 354 | { 355 | if ((data[41] == 0x00 && data[42] == 0x00 && data[43] == 0x00) || 356 | (data[41] == 0xff && data[42] == 0xff && data[43] == 0xff) || 357 | (data[41] == 0x55 && data[42] == 0xaa && data[43] == 0x5a) || 358 | (data[41] == 0xe9 && data[42] == 0x01 && data[43] == 0x00)) 359 | { 360 | dis_resolution_mode_ = 1; // 1cm resolution 361 | // std::cout << "The distance resolution is 1cm" << std::endl; 362 | } 363 | else 364 | { 365 | dis_resolution_mode_ = 0; // 0.5cm resolution 366 | // std::cout << "The distance resolution is 0.5cm" << std::endl; 367 | } 368 | this->is_init_top_fw_ = true; 369 | } 370 | 371 | if (!this->is_init_curve_) 372 | { 373 | bool curve_flag = true; 374 | // check difop reigon has beed flashed the right data 375 | if ((data[50] == 0x00 || data[50] == 0xff) && (data[51] == 0x00 || data[51] == 0xff) && 376 | (data[52] == 0x00 || data[52] == 0xff) && (data[53] == 0x00 || data[53] == 0xff)) 377 | { 378 | curve_flag = false; 379 | } 380 | 381 | // TODO check why rsview here no 32 laser, be more careful the new, old version 382 | // Init curves 383 | if (curve_flag) 384 | { 385 | unsigned char checkbit; 386 | int bit1, bit2; 387 | for (int loopn = 0; loopn < numOfLasers; ++loopn) 388 | { 389 | // check the curves' parameter in difop 390 | checkbit = *(data + 50 + loopn * 15) ^ *(data + 50 + loopn * 15 + 1); 391 | for (int loopm = 1; loopm < 7; ++loopm) 392 | { 393 | checkbit = checkbit ^ (*(data + 50 + loopn * 15 + loopm * 2)) ^ (*(data + 50 + loopn * 15 + loopm * 2 + 1)); 394 | } 395 | if (checkbit != *(data + 50 + loopn * 15 + 14)) 396 | { 397 | return; 398 | } 399 | } 400 | for (int loopn = 0; loopn < numOfLasers; ++loopn) 401 | { 402 | // calculate curves' parameters 403 | bit1 = static_cast(*(data + 50 + loopn * 15)); 404 | bit2 = static_cast(*(data + 50 + loopn * 15 + 1)); 405 | aIntensityCal[0][loopn] = (bit1 * 256 + bit2) * 0.001; 406 | bit1 = static_cast(*(data + 50 + loopn * 15 + 2)); 407 | bit2 = static_cast(*(data + 50 + loopn * 15 + 3)); 408 | aIntensityCal[1][loopn] = (bit1 * 256 + bit2) * 0.001; 409 | bit1 = static_cast(*(data + 50 + loopn * 15 + 4)); 410 | bit2 = static_cast(*(data + 50 + loopn * 15 + 5)); 411 | aIntensityCal[2][loopn] = (bit1 * 256 + bit2) * 0.001; 412 | bit1 = static_cast(*(data + 50 + loopn * 15 + 6)); 413 | bit2 = static_cast(*(data + 50 + loopn * 15 + 7)); 414 | aIntensityCal[3][loopn] = (bit1 * 256 + bit2) * 0.001; 415 | bit1 = static_cast(*(data + 50 + loopn * 15 + 8)); 416 | bit2 = static_cast(*(data + 50 + loopn * 15 + 9)); 417 | aIntensityCal[4][loopn] = (bit1 * 256 + bit2) * 0.00001; 418 | bit1 = static_cast(*(data + 50 + loopn * 15 + 10)); 419 | bit2 = static_cast(*(data + 50 + loopn * 15 + 11)); 420 | aIntensityCal[5][loopn] = -(bit1 * 256 + bit2) * 0.0001; 421 | bit1 = static_cast(*(data + 50 + loopn * 15 + 12)); 422 | bit2 = static_cast(*(data + 50 + loopn * 15 + 13)); 423 | aIntensityCal[6][loopn] = (bit1 * 256 + bit2) * 0.001; 424 | } 425 | this->is_init_curve_ = true; 426 | ROS_INFO_STREAM("[cloud][rawdata] curves data is wrote in difop packet!"); 427 | Curvesis_new = true; 428 | } 429 | 430 | if ((data[290] != 0x00) && (data[290] != 0xff)) 431 | { 432 | intensityFactor = static_cast(*(data + 290)); // intensity factor introduced since than 20181115 433 | } 434 | 435 | if ((data[291] == 0x00) || (data[291] == 0xff) || (data[291] == 0xa1)) 436 | { 437 | intensity_mode_ = 1; // mode for the top firmware lower than T6R23V8(16) or T9R23V6(32) 438 | } 439 | else if (data[291] == 0xb1) 440 | { 441 | intensity_mode_ = 2; // mode for the top firmware higher than T6R23V8(16) or T9R23V6(32) 442 | } 443 | else if (data[291] == 0xc1) 444 | { 445 | intensity_mode_ = 3; // mode for the top firmware higher than T6R23V9 446 | } 447 | 448 | } 449 | 450 | if (!this->is_init_angle_) 451 | { 452 | // check header 453 | { 454 | bool angle_flag = true; 455 | if (numOfLasers == 16) 456 | { 457 | // check difop reigon has beed flashed the right data 458 | if ((data[1165] == 0x00 || data[1165] == 0xff) && (data[1166] == 0x00 || data[1166] == 0xff) && 459 | (data[1167] == 0x00 || data[1167] == 0xff) && (data[1168] == 0x00 || data[1168] == 0xff)) 460 | { 461 | angle_flag = false; 462 | } 463 | } 464 | else if (numOfLasers == 32) 465 | { 466 | if ((data[468] == 0x00 || data[468] == 0xff) && (data[469] == 0x00 || data[469] == 0xff) && 467 | (data[470] == 0x00 || data[470] == 0xff)) 468 | { 469 | angle_flag = false; 470 | } 471 | } 472 | 473 | // angle 474 | if (angle_flag) 475 | { 476 | // TODO check the HORI_ANGLE 477 | int bit1, bit2, bit3, symbolbit; 478 | if (numOfLasers == 16) 479 | { 480 | for (int loopn = 0; loopn < 16; ++loopn) 481 | { 482 | if (loopn < 8) 483 | { 484 | symbolbit = -1; 485 | } 486 | else 487 | { 488 | symbolbit = 1; 489 | } 490 | bit1 = static_cast(*(data + 1165 + loopn * 3)); 491 | bit2 = static_cast(*(data + 1165 + loopn * 3 + 1)); 492 | bit3 = static_cast(*(data + 1165 + loopn * 3 + 2)); 493 | VERT_ANGLE[loopn] = (bit1 * 256 * 256 + bit2 * 256 + bit3) * symbolbit * 0.01f; 494 | // std::cout << VERT_ANGLE[loopn] << std::endl; 495 | // TODO 496 | HORI_ANGLE[loopn] = 0; 497 | } 498 | } 499 | else if (numOfLasers == 32) 500 | { 501 | for (int loopn = 0; loopn < 32; ++loopn) 502 | { 503 | // vertical angle 504 | bit1 = static_cast(*(data + 468 + loopn * 3)); 505 | if (bit1 == 0) 506 | symbolbit = 1; 507 | else if (bit1 == 1) 508 | symbolbit = -1; 509 | bit2 = static_cast(*(data + 468 + loopn * 3 + 1)); 510 | bit3 = static_cast(*(data + 468 + loopn * 3 + 2)); 511 | if (isBpearlLidar_) 512 | VERT_ANGLE[loopn] = (bit2 * 256 + bit3) * symbolbit * 0.01f * 100; 513 | else 514 | VERT_ANGLE[loopn] = (bit2 * 256 + bit3) * symbolbit * 0.001f * 100; 515 | // horizontal offset angle 516 | bit1 = static_cast(*(data + 564 + loopn * 3)); 517 | if (bit1 == 0) 518 | symbolbit = 1; 519 | else if (bit1 == 1) 520 | symbolbit = -1; 521 | bit2 = static_cast(*(data + 564 + loopn * 3 + 1)); 522 | bit3 = static_cast(*(data + 564 + loopn * 3 + 2)); 523 | if (isBpearlLidar_) 524 | HORI_ANGLE[loopn] = (bit2 * 256 + bit3) * symbolbit * 0.01f * 100; 525 | else 526 | HORI_ANGLE[loopn] = (bit2 * 256 + bit3) * symbolbit * 0.001f * 100; 527 | } 528 | } 529 | 530 | this->is_init_angle_ = true; 531 | ROS_INFO_STREAM("[cloud][rawdata] angle data is wrote in difop packet!"); 532 | } 533 | } 534 | } 535 | 536 | if (!info_print_flag_) 537 | { 538 | info_print_flag_ = true; 539 | 540 | // print info 541 | float prin_dis; 542 | if (dis_resolution_mode_ == 0) 543 | { 544 | prin_dis = 0.5; 545 | } 546 | else 547 | { 548 | prin_dis = 1; 549 | } 550 | ROS_INFO_STREAM("[cloud][rawdata] distance resolution is: " << prin_dis << " cm, intensity mode is: Mode " 551 | << intensity_mode_); 552 | if (is_support_dual_return == false) 553 | { 554 | ROS_INFO_STREAM("[cloud][rawdata] lidar only support single return wave!"); 555 | } 556 | else 557 | { 558 | if (return_mode_ == 0) 559 | { 560 | ROS_INFO_STREAM("[cloud][rawdata] lidar support dual return wave, the current mode is: dual"); 561 | } 562 | else if (return_mode_ == 1) 563 | { 564 | ROS_INFO_STREAM("[cloud][rawdata] lidar support dual return wave, the current mode is: strongest"); 565 | } 566 | else if (return_mode_ == 2) 567 | { 568 | ROS_INFO_STREAM("[cloud][rawdata] lidar support dual return wave, the current mode is: last"); 569 | } 570 | } 571 | 572 | ROS_INFO_STREAM("[cloud][rawdata] difop intensity mode: "< 0.0 && azimuth_f < 3000.0) 595 | { 596 | azimuth_f = azimuth_f + HORI_ANGLE[passageway] + 36000.0f; 597 | } 598 | else 599 | { 600 | azimuth_f = azimuth_f + HORI_ANGLE[passageway]; 601 | } 602 | azimuth = (int)azimuth_f; 603 | azimuth = ((azimuth%36000)+36000)%36000; 604 | 605 | return azimuth; 606 | } 607 | 608 | //------------------------------------------------------------ 609 | //校准反射强度值 610 | float RawData::calibrateIntensity(float intensity, int calIdx, int distance) 611 | { 612 | if (intensity_mode_ == 3) 613 | { 614 | return intensity; 615 | } 616 | else 617 | { 618 | int algDist; 619 | int sDist; 620 | float realPwr; 621 | float refPwr; 622 | float tempInten; 623 | float distance_f; 624 | float endOfSection1, endOfSection2; 625 | int temp = estimateTemperature(temper); 626 | 627 | realPwr = std::max((float)(intensity / (1 + (temp - TEMPERATURE_MIN) / 24.0f)), 1.0f); 628 | 629 | if (intensity_mode_ == 1) 630 | { 631 | // transform the one byte intensity value to two byte 632 | if ((int)realPwr < 126) 633 | realPwr = realPwr * 4.0f; 634 | else if ((int)realPwr >= 126 && (int)realPwr < 226) 635 | realPwr = (realPwr - 125.0f) * 16.0f + 500.0f; 636 | else 637 | realPwr = (realPwr - 225.0f) * 256.0f + 2100.0f; 638 | } 639 | else if (intensity_mode_ == 2) 640 | { 641 | // the caculation for the firmware after T6R23V8(16) and T9R23V6(32) 642 | if ((int)realPwr < 64) 643 | realPwr = realPwr; 644 | else if ((int)realPwr >= 64 && (int)realPwr < 176) 645 | realPwr = (realPwr - 64.0f) * 4.0f + 64.0f; 646 | else 647 | realPwr = (realPwr - 176.0f) * 16.0f + 512.0f; 648 | } 649 | else 650 | { 651 | ROS_WARN("[cloud][rawdata] The intensity mode is not right"); 652 | } 653 | 654 | int indexTemper = estimateTemperature(temper) - TEMPERATURE_MIN; 655 | 656 | // limit sDist 657 | sDist = (distance > g_ChannelNum[calIdx][indexTemper]) ? distance : g_ChannelNum[calIdx][indexTemper]; 658 | 659 | // minus the static offset (this data is For the intensity cal useage only) 660 | algDist = sDist - g_ChannelNum[calIdx][indexTemper]; 661 | if (dis_resolution_mode_ == 0) 662 | { 663 | distance_f = (float)algDist * DISTANCE_RESOLUTION_NEW; 664 | } 665 | else 666 | { 667 | distance_f = (float)algDist * DISTANCE_RESOLUTION; 668 | } 669 | distance_f = (distance_f > this->max_distance_) ? this->max_distance_ : distance_f; 670 | 671 | // calculate intensity ref curves 672 | float refPwr_temp = 0.0f; 673 | int order = 3; 674 | endOfSection1 = 5.0f; 675 | endOfSection2 = 40.0; 676 | 677 | if (intensity_mode_ == 1) 678 | { 679 | if (distance_f <= endOfSection1) 680 | { 681 | refPwr_temp = aIntensityCal[0][calIdx] * exp(aIntensityCal[1][calIdx] - aIntensityCal[2][calIdx] * distance_f) + 682 | aIntensityCal[3][calIdx]; 683 | } 684 | else 685 | { 686 | for (int i = 0; i < order; i++) 687 | { 688 | refPwr_temp += aIntensityCal[i + 4][calIdx] * (pow(distance_f, order - 1 - i)); 689 | } 690 | } 691 | } 692 | else if (intensity_mode_ == 2) 693 | { 694 | if (distance_f <= endOfSection1) 695 | { 696 | refPwr_temp = aIntensityCal[0][calIdx] * exp(aIntensityCal[1][calIdx] - aIntensityCal[2][calIdx] * distance_f) + 697 | aIntensityCal[3][calIdx]; 698 | } 699 | else if (distance_f > endOfSection1 && distance_f <= endOfSection2) 700 | { 701 | for (int i = 0; i < order; i++) 702 | { 703 | refPwr_temp += aIntensityCal[i + 4][calIdx] * (pow(distance_f, order - 1 - i)); 704 | } 705 | } 706 | else 707 | { 708 | float refPwr_temp0 = 0.0f; 709 | float refPwr_temp1 = 0.0f; 710 | for (int i = 0; i < order; i++) 711 | { 712 | refPwr_temp0 += aIntensityCal[i + 4][calIdx] * (pow(40.0f, order - 1 - i)); 713 | refPwr_temp1 += aIntensityCal[i + 4][calIdx] * (pow(39.0f, order - 1 - i)); 714 | } 715 | refPwr_temp = 0.3f * (refPwr_temp0 - refPwr_temp1) * distance_f + refPwr_temp0; 716 | } 717 | } 718 | else 719 | { 720 | ROS_WARN("[cloud][rawdata] The intensity mode is not right"); 721 | } 722 | 723 | refPwr = std::max(std::min(refPwr_temp, 500.0f), 4.0f); 724 | 725 | tempInten = (intensityFactor * refPwr) / realPwr; 726 | if (numOfLasers == 32) 727 | { 728 | tempInten = tempInten * CurvesRate[calIdx]; 729 | } 730 | tempInten = (int)tempInten > 255 ? 255.0f : tempInten; 731 | return tempInten; 732 | } 733 | } 734 | 735 | //------------------------------------------------------------ 736 | //校准反射强度值 old 737 | float RawData::calibrateIntensity_old(float intensity, int calIdx, int distance) 738 | { 739 | int algDist; 740 | int sDist; 741 | int uplimitDist; 742 | float realPwr; 743 | float refPwr; 744 | float tempInten; 745 | 746 | int temp = estimateTemperature(temper); 747 | realPwr = std::max((float)(intensity / (1 + (temp - TEMPERATURE_MIN) / 24.0f)), 1.0f); 748 | // realPwr = intensity; 749 | 750 | if ((int)realPwr < 126) 751 | realPwr = realPwr * 4.0f; 752 | else if ((int)realPwr >= 126 && (int)realPwr < 226) 753 | realPwr = (realPwr - 125.0f) * 16.0f + 500.0f; 754 | else 755 | realPwr = (realPwr - 225.0f) * 256.0f + 2100.0f; 756 | 757 | int indexTemper = estimateTemperature(temper) - TEMPERATURE_MIN; 758 | uplimitDist = g_ChannelNum[calIdx][indexTemper] + 1400; 759 | sDist = (distance > g_ChannelNum[calIdx][indexTemper]) ? distance : g_ChannelNum[calIdx][indexTemper]; 760 | sDist = (sDist < uplimitDist) ? sDist : uplimitDist; 761 | // minus the static offset (this data is For the intensity cal useage only) 762 | algDist = sDist - g_ChannelNum[calIdx][indexTemper]; 763 | // algDist = algDist < 1400? algDist : 1399; 764 | refPwr = aIntensityCal_old[algDist][calIdx]; 765 | 766 | tempInten = (51 * refPwr) / realPwr; 767 | if (numOfLasers == 32) 768 | { 769 | tempInten = tempInten * CurvesRate[calIdx]; 770 | } 771 | tempInten = (int)tempInten > 255 ? 255.0f : tempInten; 772 | return tempInten; 773 | } 774 | 775 | //------------------------------------------------------------ 776 | int RawData::isABPacket(int distance) 777 | { 778 | int ABflag = 0; 779 | if ((distance & 32768) != 0) 780 | { 781 | ABflag = 1; // B 782 | } 783 | else 784 | { 785 | ABflag = 0; // A 786 | } 787 | return ABflag; 788 | } 789 | 790 | //------------------------------------------------------------ 791 | float RawData::computeTemperature(unsigned char bit1, unsigned char bit2) 792 | { 793 | float Temp; 794 | float bitneg = bit2 & 128; // 10000000 795 | float highbit = bit2 & 127; // 01111111 796 | float lowbit = bit1 >> 3; 797 | if (bitneg == 128) 798 | { 799 | Temp = -1 * (highbit * 32 + lowbit) * 0.0625f; 800 | } 801 | else 802 | { 803 | Temp = (highbit * 32 + lowbit) * 0.0625f; 804 | } 805 | 806 | return Temp; 807 | } 808 | 809 | //------------------------------------------------------------ 810 | int RawData::estimateTemperature(float Temper) 811 | { 812 | int temp = (int)floor(Temper + 0.5); 813 | if (temp < TEMPERATURE_MIN) 814 | { 815 | temp = TEMPERATURE_MIN; 816 | } 817 | else if (temp > TEMPERATURE_MIN + TEMPERATURE_RANGE) 818 | { 819 | temp = TEMPERATURE_MIN + TEMPERATURE_RANGE; 820 | } 821 | 822 | return temp; 823 | } 824 | //------------------------------------------------------------ 825 | 826 | /** @brief convert raw packet to point cloud 827 | * 828 | * @param pkt raw packet to unpack 829 | * @param pc shared pointer to point cloud (points are appended) 830 | */ 831 | void RawData::unpack(const rslidar_msgs::rslidarPacket& pkt, pcl::PointCloud::Ptr pointcloud) 832 | { 833 | // check pkt header 834 | if (pkt.data[0] != 0x55 || pkt.data[1] != 0xAA || pkt.data[2] != 0x05 || pkt.data[3] != 0x0A) 835 | { 836 | return; 837 | } 838 | 839 | if (numOfLasers == 32) 840 | { 841 | unpack_RS32(pkt, pointcloud); 842 | return; 843 | } 844 | float azimuth; // 0.01 dgree 845 | float intensity; 846 | float azimuth_diff; 847 | float azimuth_corrected_f; 848 | int azimuth_corrected; 849 | 850 | const raw_packet_t* raw = (const raw_packet_t*)&pkt.data[42]; 851 | 852 | if (tempPacketNum < 75 && tempPacketNum > 0) 853 | { 854 | tempPacketNum++; 855 | } 856 | else 857 | { 858 | temper = computeTemperature(pkt.data[38], pkt.data[39]); 859 | tempPacketNum = 1; 860 | std_msgs::Float32 temperature_msgs; 861 | temperature_msgs.data = temper; 862 | temperature_pub_.publish(temperature_msgs); 863 | } 864 | 865 | for (int block = 0; block < BLOCKS_PER_PACKET; block++, this->block_num++) // 1 packet:12 data blocks 866 | { 867 | if (UPPER_BANK != raw->blocks[block].header) 868 | { 869 | ROS_INFO_STREAM_THROTTLE(180, "[cloud][rawdata] skipping RSLIDAR DIFOP packet"); 870 | break; 871 | } 872 | 873 | 874 | azimuth = (float)(256 * raw->blocks[block].rotation_1 + raw->blocks[block].rotation_2); 875 | 876 | int azi1, azi2; 877 | if (block < (BLOCKS_PER_PACKET - 1)) // 12 878 | { 879 | // int azi1, azi2; 880 | azi1 = 256 * raw->blocks[block + 1].rotation_1 + raw->blocks[block + 1].rotation_2; 881 | azi2 = 256 * raw->blocks[block].rotation_1 + raw->blocks[block].rotation_2; 882 | } 883 | else 884 | { 885 | 886 | azi1 = 256 * raw->blocks[block].rotation_1 + raw->blocks[block].rotation_2; 887 | azi2 = 256 * raw->blocks[block - 1].rotation_1 + raw->blocks[block - 1].rotation_2; 888 | 889 | } 890 | uint16_t diff = (36000 + azi1 - azi2) % 36000; 891 | if (diff > 100) //to avoid when the lidar is set to specific FOV that cause the big difference between angle 892 | { 893 | diff = 0; 894 | } 895 | azimuth_diff = (float)(diff); 896 | 897 | for (int firing = 0, k = 0; firing < RS16_FIRINGS_PER_BLOCK; firing++) // 2 898 | { 899 | for (int dsr = 0; dsr < RS16_SCANS_PER_FIRING; dsr++, k += RAW_SCAN_SIZE) // 16 3 900 | { 901 | if (0 == return_mode_) 902 | { 903 | azimuth_corrected_f = azimuth + (azimuth_diff * (dsr * RS16_DSR_TOFFSET)) / RS16_FIRING_TOFFSET; 904 | } 905 | else 906 | { 907 | azimuth_corrected_f = azimuth + (azimuth_diff * ((dsr * RS16_DSR_TOFFSET) + (firing * RS16_FIRING_TOFFSET)) / 908 | RS16_BLOCK_TDURATION); 909 | } 910 | azimuth_corrected = ((int)round(azimuth_corrected_f)) % 36000; // convert to integral value... 911 | 912 | union two_bytes tmp; 913 | tmp.bytes[1] = raw->blocks[block].data[k]; 914 | tmp.bytes[0] = raw->blocks[block].data[k + 1]; 915 | int distance = tmp.uint; 916 | 917 | // read intensity 918 | intensity = raw->blocks[block].data[k + 2]; 919 | if (Curvesis_new) 920 | intensity = calibrateIntensity(intensity, dsr, distance); 921 | else 922 | intensity = calibrateIntensity_old(intensity, dsr, distance); 923 | 924 | float distance2 = pixelToDistance(distance, dsr); 925 | if (dis_resolution_mode_ == 0) // distance resolution is 0.5cm 926 | { 927 | distance2 = distance2 * DISTANCE_RESOLUTION_NEW; 928 | } 929 | else 930 | { 931 | distance2 = distance2 * DISTANCE_RESOLUTION; 932 | } 933 | 934 | int arg_horiz = (azimuth_corrected + 36000) % 36000; 935 | int arg_horiz_orginal = arg_horiz; 936 | int arg_vert = ((VERT_ANGLE[dsr]) % 36000 + 36000) % 36000; 937 | 938 | pcl::PointXYZI point; 939 | 940 | if (distance2 > max_distance_ || distance2 < min_distance_ || 941 | (angle_flag_ && (arg_horiz < start_angle_ || arg_horiz > end_angle_)) || 942 | (!angle_flag_ && (arg_horiz > end_angle_ && arg_horiz < start_angle_))) // invalid distance 943 | { 944 | point.x = NAN; 945 | point.y = NAN; 946 | point.z = NAN; 947 | point.intensity = 0; 948 | pointcloud->at(2 * this->block_num + firing, dsr) = point; 949 | } 950 | else 951 | { 952 | // If you want to fix the rslidar X aixs to the front side of the cable, please use the two line below 953 | 954 | point.x = distance2 * this->cos_lookup_table_[arg_vert] * this->cos_lookup_table_[arg_horiz] + 955 | Rx_ * this->cos_lookup_table_[arg_horiz_orginal]; 956 | point.y = -distance2 * this->cos_lookup_table_[arg_vert] * this->sin_lookup_table_[arg_horiz] - 957 | Rx_ * this->sin_lookup_table_[arg_horiz_orginal]; 958 | point.z = distance2 * this->sin_lookup_table_[arg_vert] + Rz_; 959 | point.intensity = intensity; 960 | pointcloud->at(2 * this->block_num + firing, dsr) = point; 961 | } 962 | } 963 | } 964 | } 965 | } 966 | 967 | void RawData::unpack_RS32(const rslidar_msgs::rslidarPacket& pkt, pcl::PointCloud::Ptr pointcloud) 968 | { 969 | float azimuth; // 0.01 dgree 970 | float intensity; 971 | float azimuth_diff; 972 | float azimuth_corrected_f; 973 | int azimuth_corrected; 974 | 975 | const raw_packet_t* raw = (const raw_packet_t*)&pkt.data[42]; 976 | 977 | if (tempPacketNum < 150 && tempPacketNum > 0) 978 | { 979 | tempPacketNum++; 980 | } 981 | else 982 | { 983 | temper = computeTemperature(pkt.data[38], pkt.data[39]); 984 | tempPacketNum = 1; 985 | std_msgs::Float32 temperature_msgs; 986 | temperature_msgs.data = temper; 987 | temperature_pub_.publish(temperature_msgs); 988 | } 989 | 990 | for (int block = 0; block < BLOCKS_PER_PACKET; block++, this->block_num++) // 1 packet:12 data blocks 991 | { 992 | if (UPPER_BANK != raw->blocks[block].header) 993 | { 994 | ROS_INFO_STREAM_THROTTLE(180, "[cloud][rawdata] skipping RSLIDAR DIFOP packet"); 995 | break; 996 | } 997 | 998 | azimuth = (float)(256 * raw->blocks[block].rotation_1 + raw->blocks[block].rotation_2); 999 | 1000 | int azi1, azi2; 1001 | if (0 == return_mode_) 1002 | { // dual return mode 1003 | if (block < (BLOCKS_PER_PACKET - 2)) // 12 1004 | { 1005 | azi1 = 256 * raw->blocks[block + 2].rotation_1 + raw->blocks[block + 2].rotation_2; 1006 | azi2 = 256 * raw->blocks[block].rotation_1 + raw->blocks[block].rotation_2; 1007 | } 1008 | else 1009 | { 1010 | azi1 = 256 * raw->blocks[block].rotation_1 + raw->blocks[block].rotation_2; 1011 | azi2 = 256 * raw->blocks[block - 2].rotation_1 + raw->blocks[block - 2].rotation_2; 1012 | } 1013 | } 1014 | else 1015 | { 1016 | if (block < (BLOCKS_PER_PACKET - 1)) // 12 1017 | { 1018 | azi1 = 256 * raw->blocks[block + 1].rotation_1 + raw->blocks[block + 1].rotation_2; 1019 | azi2 = 256 * raw->blocks[block].rotation_1 + raw->blocks[block].rotation_2; 1020 | } 1021 | else 1022 | { 1023 | azi1 = 256 * raw->blocks[block].rotation_1 + raw->blocks[block].rotation_2; 1024 | azi2 = 256 * raw->blocks[block - 1].rotation_1 + raw->blocks[block - 1].rotation_2; 1025 | } 1026 | } 1027 | uint16_t diff = (36000 + azi1 - azi2) % 36000; 1028 | if (diff > 100) //to avoid when the lidar is set to specific FOV that cause the big difference between angle 1029 | { 1030 | diff = 0; 1031 | } 1032 | azimuth_diff = (float)(diff); 1033 | 1034 | if (dis_resolution_mode_ == 0) // distance resolution is 0.5cm and delete the AB packet mechanism 1035 | { 1036 | for (int dsr = 0, k = 0; dsr < RS32_SCANS_PER_FIRING * RS32_FIRINGS_PER_BLOCK; dsr++, k += RAW_SCAN_SIZE) // 16 3 1037 | { 1038 | int dsr_temp; 1039 | if (dsr >= 16) 1040 | { 1041 | dsr_temp = dsr - 16; 1042 | } 1043 | else 1044 | { 1045 | dsr_temp = dsr; 1046 | } 1047 | azimuth_corrected_f = azimuth + (azimuth_diff * ((dsr_temp * RS32_DSR_TOFFSET)) / RS32_BLOCK_TDURATION); 1048 | azimuth_corrected = correctAzimuth(azimuth_corrected_f, dsr); 1049 | 1050 | union two_bytes tmp; 1051 | tmp.bytes[1] = raw->blocks[block].data[k]; 1052 | tmp.bytes[0] = raw->blocks[block].data[k + 1]; 1053 | int distance = tmp.uint; 1054 | 1055 | // read intensity 1056 | intensity = (float)raw->blocks[block].data[k + 2]; 1057 | intensity = calibrateIntensity(intensity, dsr, distance); 1058 | 1059 | float distance2 = pixelToDistance(distance, dsr); 1060 | distance2 = distance2 * DISTANCE_RESOLUTION_NEW; 1061 | 1062 | int arg_horiz_orginal = (int)azimuth_corrected_f % 36000; 1063 | int arg_horiz = azimuth_corrected; 1064 | int arg_vert = ((VERT_ANGLE[dsr]) % 36000 + 36000) % 36000; 1065 | pcl::PointXYZI point; 1066 | 1067 | if (distance2 > max_distance_ || distance2 < min_distance_ || 1068 | (angle_flag_ && (arg_horiz < start_angle_ || arg_horiz > end_angle_)) || 1069 | (!angle_flag_ && (arg_horiz > end_angle_ && arg_horiz < start_angle_))) // invalid distance 1070 | { 1071 | point.x = NAN; 1072 | point.y = NAN; 1073 | point.z = NAN; 1074 | point.intensity = 0; 1075 | pointcloud->at(this->block_num, dsr) = point; 1076 | } 1077 | else 1078 | { 1079 | // If you want to fix the rslidar X aixs to the front side of the cable, please use the two line below 1080 | point.x = distance2 * this->cos_lookup_table_[arg_vert] * this->cos_lookup_table_[arg_horiz] + 1081 | Rx_ * this->cos_lookup_table_[arg_horiz_orginal]; 1082 | point.y = -distance2 * this->cos_lookup_table_[arg_vert] * this->sin_lookup_table_[arg_horiz] - 1083 | Rx_ * this->sin_lookup_table_[arg_horiz_orginal]; 1084 | point.z = distance2 * this->sin_lookup_table_[arg_vert] + Rz_; 1085 | point.intensity = intensity; 1086 | pointcloud->at(this->block_num, dsr) = point; 1087 | } 1088 | } 1089 | } 1090 | else 1091 | { 1092 | // Estimate the type of packet 1093 | union two_bytes tmp_flag; 1094 | tmp_flag.bytes[1] = raw->blocks[block].data[0]; 1095 | tmp_flag.bytes[0] = raw->blocks[block].data[1]; 1096 | int ABflag = isABPacket(tmp_flag.uint); 1097 | 1098 | int k = 0; 1099 | int index; 1100 | for (int dsr = 0; dsr < RS32_SCANS_PER_FIRING * RS32_FIRINGS_PER_BLOCK; dsr++, k += RAW_SCAN_SIZE) // 16 3 1101 | { 1102 | if (ABflag == 1 && dsr < 16) 1103 | { 1104 | index = k + 48; 1105 | } 1106 | else if (ABflag == 1 && dsr >= 16) 1107 | { 1108 | index = k - 48; 1109 | } 1110 | else 1111 | { 1112 | index = k; 1113 | } 1114 | 1115 | int dsr_temp; 1116 | if (dsr >= 16) 1117 | { 1118 | dsr_temp = dsr - 16; 1119 | } 1120 | else 1121 | { 1122 | dsr_temp = dsr; 1123 | } 1124 | azimuth_corrected_f = azimuth + (azimuth_diff * ((dsr_temp * RS32_DSR_TOFFSET)) / RS32_BLOCK_TDURATION); 1125 | azimuth_corrected = correctAzimuth(azimuth_corrected_f, dsr); 1126 | 1127 | union two_bytes tmp; 1128 | tmp.bytes[1] = raw->blocks[block].data[index]; 1129 | tmp.bytes[0] = raw->blocks[block].data[index + 1]; 1130 | int ab_flag_in_block = isABPacket(tmp.uint); 1131 | int distance = tmp.uint - ab_flag_in_block * 32768; 1132 | 1133 | // read intensity 1134 | intensity = (float)raw->blocks[block].data[index + 2]; 1135 | intensity = calibrateIntensity(intensity, dsr, distance); 1136 | 1137 | float distance2 = pixelToDistance(distance, dsr); 1138 | distance2 = distance2 * DISTANCE_RESOLUTION; 1139 | 1140 | int arg_horiz_orginal = (int)azimuth_corrected_f % 36000; 1141 | int arg_horiz = azimuth_corrected; 1142 | int arg_vert = ((VERT_ANGLE[dsr]) % 36000 + 36000) % 36000; 1143 | 1144 | pcl::PointXYZI point; 1145 | 1146 | if (distance2 > max_distance_ || distance2 < min_distance_ || 1147 | (angle_flag_ && (arg_horiz < start_angle_ || arg_horiz > end_angle_)) || 1148 | (!angle_flag_ && (arg_horiz > end_angle_ && arg_horiz < start_angle_))) // invalid distance 1149 | { 1150 | point.x = NAN; 1151 | point.y = NAN; 1152 | point.z = NAN; 1153 | point.intensity = 0; 1154 | pointcloud->at(this->block_num, dsr) = point; 1155 | } 1156 | else 1157 | { 1158 | // If you want to fix the rslidar X aixs to the front side of the cable, please use the two line below 1159 | point.x = distance2 * this->cos_lookup_table_[arg_vert] * this->cos_lookup_table_[arg_horiz] + 1160 | Rx_ * this->cos_lookup_table_[arg_horiz_orginal]; 1161 | point.y = -distance2 * this->cos_lookup_table_[arg_vert] * this->sin_lookup_table_[arg_horiz] - 1162 | Rx_ * this->sin_lookup_table_[arg_horiz_orginal]; 1163 | point.z = distance2 * this->sin_lookup_table_[arg_vert] + Rz_; 1164 | point.intensity = intensity; 1165 | pointcloud->at(this->block_num, dsr) = point; 1166 | } 1167 | } 1168 | } 1169 | } 1170 | } 1171 | 1172 | } // namespace rslidar_rawdata 1173 | -------------------------------------------------------------------------------- /rslidar_pointcloud/src/rawdata.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2020 Robosense Authors 3 | * License: Modified BSD Software License Agreement 4 | * 5 | * $Id$ 6 | */ 7 | 8 | /** @file 9 | * 10 | * @brief Interfaces for interpreting raw packets from the Robosense 3D LIDAR. 11 | * 12 | */ 13 | 14 | #ifndef _RAWDATA_H 15 | #define _RAWDATA_H 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "std_msgs/String.h" 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | namespace rslidar_rawdata 29 | { 30 | // static const float ROTATION_SOLUTION_ = 0.18f; //水平角分辨率 10hz 31 | static const int SIZE_BLOCK = 100; 32 | static const int RAW_SCAN_SIZE = 3; 33 | static const int SCANS_PER_BLOCK = 32; 34 | static const int BLOCK_DATA_SIZE = (SCANS_PER_BLOCK * RAW_SCAN_SIZE); // 96 35 | 36 | static const float ROTATION_RESOLUTION = 0.01f; /**< degrees 旋转角分辨率*/ 37 | static const uint16_t ROTATION_MAX_UNITS = 36000; /**< hundredths of degrees */ 38 | 39 | static const float DISTANCE_MAX = 200.0f; /**< meters */ 40 | static const float DISTANCE_MIN = 0.4f; /**< meters */ 41 | static const float DISTANCE_RESOLUTION = 0.01f; /**< meters */ 42 | static const float DISTANCE_RESOLUTION_NEW = 0.005f; /**< meters */ 43 | static const float DISTANCE_MAX_UNITS = (DISTANCE_MAX / DISTANCE_RESOLUTION + 1.0f); 44 | /** @todo make this work for both big and little-endian machines */ 45 | static const uint16_t UPPER_BANK = 0xeeff; // 46 | static const uint16_t LOWER_BANK = 0xddff; 47 | 48 | /** Special Defines for RS16 support **/ 49 | static const int RS16_FIRINGS_PER_BLOCK = 2; 50 | static const int RS16_SCANS_PER_FIRING = 16; 51 | static const float RS16_BLOCK_TDURATION = 100.0f; // [µs] 52 | static const float RS16_DSR_TOFFSET = 3.0f; // [µs] 53 | static const float RS16_FIRING_TOFFSET = 50.0f; // [µs] 54 | 55 | /** Special Defines for RS32 support **/ 56 | static const int RS32_FIRINGS_PER_BLOCK = 1; 57 | static const int RS32_SCANS_PER_FIRING = 32; 58 | static const float RS32_BLOCK_TDURATION = 50.0f; // [µs] 59 | static const float RS32_DSR_TOFFSET = 3.0f; // [µs] 60 | static const float RL32_FIRING_TOFFSET = 50.0f; // [µs] 61 | 62 | static const int TEMPERATURE_MIN = 31; 63 | 64 | #define RS_TO_RADS(x) ((x) * (M_PI) / 180) 65 | /** \brief Raw rslidar data block. 66 | * 67 | * Each block contains data from either the upper or lower laser 68 | * bank. The device returns three times as many upper bank blocks. 69 | * 70 | * use stdint.h types, so things work with both 64 and 32-bit machines 71 | */ 72 | // block 73 | typedef struct raw_block 74 | { 75 | uint16_t header; ///< UPPER_BANK or LOWER_BANK 76 | uint8_t rotation_1; 77 | uint8_t rotation_2; /// combine rotation1 and rotation2 together to get 0-35999, divide by 100 to get degrees 78 | uint8_t data[BLOCK_DATA_SIZE]; // 96 79 | } raw_block_t; 80 | 81 | /** used for unpacking the first two data bytes in a block 82 | * 83 | * They are packed into the actual data stream misaligned. I doubt 84 | * this works on big endian machines. 85 | */ 86 | union two_bytes 87 | { 88 | uint16_t uint; 89 | uint8_t bytes[2]; 90 | }; 91 | 92 | static const int PACKET_SIZE = 1248; 93 | static const int BLOCKS_PER_PACKET = 12; 94 | static const int PACKET_STATUS_SIZE = 4; 95 | static const int SCANS_PER_PACKET = (SCANS_PER_BLOCK * BLOCKS_PER_PACKET); 96 | 97 | /** \brief Raw Rsldar packet. 98 | * 99 | * revolution is described in the device manual as incrementing 100 | * (mod 65536) for each physical turn of the device. Our device 101 | * seems to alternate between two different values every third 102 | * packet. One value increases, the other decreases. 103 | * 104 | * \todo figure out if revolution is only present for one of the 105 | * two types of status fields 106 | * 107 | * status has either a temperature encoding or the microcode level 108 | */ 109 | typedef struct raw_packet 110 | { 111 | raw_block_t blocks[BLOCKS_PER_PACKET]; 112 | uint16_t revolution; 113 | uint8_t status[PACKET_STATUS_SIZE]; 114 | } raw_packet_t; 115 | 116 | /** \brief RSLIDAR data conversion class */ 117 | class RawData 118 | { 119 | public: 120 | RawData(); 121 | 122 | ~RawData() 123 | { 124 | this->cos_lookup_table_.clear(); 125 | this->sin_lookup_table_.clear(); 126 | } 127 | 128 | /*load the cablibrated files: angle, distance, intensity*/ 129 | void loadConfigFile(ros::NodeHandle node, ros::NodeHandle private_nh); 130 | 131 | /*unpack the RS16 UDP packet and opuput PCL PointXYZI type*/ 132 | void unpack(const rslidar_msgs::rslidarPacket& pkt, pcl::PointCloud::Ptr pointcloud); 133 | 134 | /*unpack the RS32 UDP packet and opuput PCL PointXYZI type*/ 135 | void unpack_RS32(const rslidar_msgs::rslidarPacket& pkt, pcl::PointCloud::Ptr pointcloud); 136 | 137 | /*compute temperature*/ 138 | float computeTemperature(unsigned char bit1, unsigned char bit2); 139 | 140 | /*estimate temperature*/ 141 | int estimateTemperature(float Temper); 142 | 143 | /*calibrated the disctance*/ 144 | float pixelToDistance(int pixelValue, int passageway); 145 | 146 | /*calibrated the azimuth*/ 147 | int correctAzimuth(float azimuth_f, int passageway); 148 | 149 | /*calibrated the intensity*/ 150 | float calibrateIntensity(float inten, int calIdx, int distance); 151 | float calibrateIntensity_old(float inten, int calIdx, int distance); 152 | 153 | /*estimate the packet type*/ 154 | int isABPacket(int distance); 155 | 156 | void processDifop(const rslidar_msgs::rslidarPacket::ConstPtr& difop_msg); 157 | ros::Subscriber difop_sub_; 158 | ros::Publisher temperature_pub_; 159 | bool is_init_curve_; 160 | bool is_init_angle_; 161 | bool is_init_top_fw_; 162 | int block_num = 0; 163 | int intensity_mode_; 164 | int intensityFactor; 165 | 166 | private: 167 | float Rx_; // the optical center position in the lidar coordination in x direction 168 | float Ry_; // the optical center position in the lidar coordination in y direction, for now not used 169 | float Rz_; // the optical center position in the lidar coordination in z direction 170 | int start_angle_; 171 | int end_angle_; 172 | float max_distance_; 173 | float min_distance_; 174 | int dis_resolution_mode_; 175 | int return_mode_; 176 | bool info_print_flag_; 177 | bool isBpearlLidar_; 178 | bool angle_flag_; 179 | 180 | /* cos/sin lookup table */ 181 | std::vector cos_lookup_table_; 182 | std::vector sin_lookup_table_; 183 | }; 184 | 185 | static int VERT_ANGLE[32]; 186 | static int HORI_ANGLE[32]; 187 | static float aIntensityCal[7][32]; 188 | static float aIntensityCal_old[1600][32]; 189 | static bool Curvesis_new = true; 190 | static int g_ChannelNum[32][51]; 191 | static float CurvesRate[32]; 192 | 193 | static float temper = 31.0; 194 | static int tempPacketNum = 0; 195 | static int numOfLasers = 16; 196 | static int TEMPERATURE_RANGE = 40; 197 | } // namespace rslidar_rawdata 198 | 199 | #endif // __RAWDATA_H 200 | -------------------------------------------------------------------------------- /rslidar_sync/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.3) 2 | project(rslidar_sync) 3 | find_package(catkin REQUIRED roscpp roslib std_msgs sensor_msgs message_filters) 4 | catkin_package() 5 | 6 | include_directories(include 7 | ${catkin_INCLUDE_DIRS}) 8 | 9 | add_executable(rslidar_sync_2lidar_node src/timesync_2lidar.cpp) 10 | target_link_libraries(rslidar_sync_2lidar_node 11 | ${catkin_LIBRARIES} 12 | ) 13 | 14 | add_executable(rslidar_sync_3lidar_node src/timesync_3lidar.cpp) 15 | target_link_libraries(rslidar_sync_3lidar_node 16 | ${catkin_LIBRARIES} 17 | ) 18 | -------------------------------------------------------------------------------- /rslidar_sync/README.md: -------------------------------------------------------------------------------- 1 | # rslidar_sync multilidar time synchronization package 2 | 3 | # How to use 4 | 5 | + Connect multiple lidars with the same GPS. The system time of the lidars will be the same with the GPS time. 6 | 7 | + Modify the lidar ip, port and namespace in the launch/rslidar_sync_nlidar.launch (n = 2 or 3). Please make sure the time_synchronization param value is true. 8 | 9 | + Build and launch the rslidar_sync_nlidar.launch. 10 | ``` 11 | roslaunch rslidar_sync rslidar_sync_2lidar.launch 12 | ``` 13 | or 14 | ``` 15 | roslaunch rslidar_sync rslidar_sync_3lidar.launch 16 | ``` 17 | 18 | + Check the time synchronization result. 19 | ``` 20 | rostopic echo /sync_packet_diff 21 | ``` 22 | It shows like this, n < 4 says good time synchronization. n >= 4 says bad result. 23 | ``` 24 | sync diff packets: n 25 | ``` 26 | If it doesn't show any message, please check the synchronization board or GPS connection. And you may also check the scanx_topic timestamp are near enough (no more than 0.1s). 27 | ``` 28 | rostopic echo /left/sync_header 29 | rostopic echo /right/sync_header 30 | rostopic echo /middle/sync_header 31 | ``` 32 | -------------------------------------------------------------------------------- /rslidar_sync/launch/left_lidar.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /rslidar_sync/launch/middle_lidar.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /rslidar_sync/launch/right_lidar.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /rslidar_sync/launch/rslidar_sync_2lidar.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /rslidar_sync/launch/rslidar_sync_3lidar.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /rslidar_sync/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | rslidar_sync 4 | 1.0.0 5 | synchronizing lidar data with time stamps 6 | 7 | baoxianzhang 8 | baoxianzhang 9 | BSD 10 | 11 | catkin 12 | roscpp 13 | sensor_msgs 14 | std_msgs 15 | message_filters 16 | 17 | roscpp 18 | sensor_msgs 19 | std_msgs 20 | message_filters 21 | 22 | -------------------------------------------------------------------------------- /rslidar_sync/rviz_cfg/time_sync.rviz: -------------------------------------------------------------------------------- 1 | Panels: 2 | - Class: rviz/Displays 3 | Help Height: 78 4 | Name: Displays 5 | Property Tree Widget: 6 | Expanded: 7 | - /Global Options1 8 | - /Status1 9 | - /Lidar11 10 | - /Lidar21 11 | Splitter Ratio: 0.5 12 | Tree Height: 775 13 | - Class: rviz/Selection 14 | Name: Selection 15 | - Class: rviz/Tool Properties 16 | Expanded: 17 | - /2D Pose Estimate1 18 | - /2D Nav Goal1 19 | - /Publish Point1 20 | Name: Tool Properties 21 | Splitter Ratio: 0.588679016 22 | - Class: rviz/Views 23 | Expanded: 24 | - /Current View1 25 | Name: Views 26 | Splitter Ratio: 0.5 27 | - Class: rviz/Time 28 | Experimental: false 29 | Name: Time 30 | SyncMode: 0 31 | SyncSource: Lidar1 32 | Visualization Manager: 33 | Class: "" 34 | Displays: 35 | - Alpha: 0.5 36 | Cell Size: 1 37 | Class: rviz/Grid 38 | Color: 160; 160; 164 39 | Enabled: true 40 | Line Style: 41 | Line Width: 0.0299999993 42 | Value: Lines 43 | Name: Grid 44 | Normal Cell Count: 0 45 | Offset: 46 | X: 0 47 | Y: 0 48 | Z: 0 49 | Plane: XY 50 | Plane Cell Count: 10 51 | Reference Frame: 52 | Value: true 53 | - Alpha: 1 54 | Autocompute Intensity Bounds: true 55 | Autocompute Value Bounds: 56 | Max Value: 10 57 | Min Value: -10 58 | Value: true 59 | Axis: Z 60 | Channel Name: intensity 61 | Class: rviz/PointCloud2 62 | Color: 255; 255; 255 63 | Color Transformer: Intensity 64 | Decay Time: 0 65 | Enabled: true 66 | Invert Rainbow: false 67 | Max Color: 255; 255; 255 68 | Max Intensity: 255.949997 69 | Min Color: 0; 0; 0 70 | Min Intensity: 0.251422614 71 | Name: Lidar1 72 | Position Transformer: XYZ 73 | Queue Size: 10 74 | Selectable: true 75 | Size (Pixels): 3 76 | Size (m): 0.0500000007 77 | Style: Flat Squares 78 | Topic: /ns1/rslidar_points 79 | Unreliable: false 80 | Use Fixed Frame: true 81 | Use rainbow: true 82 | Value: true 83 | - Alpha: 1 84 | Autocompute Intensity Bounds: true 85 | Autocompute Value Bounds: 86 | Max Value: 10 87 | Min Value: -10 88 | Value: true 89 | Axis: Z 90 | Channel Name: intensity 91 | Class: rviz/PointCloud2 92 | Color: 255; 255; 255 93 | Color Transformer: Intensity 94 | Decay Time: 0 95 | Enabled: true 96 | Invert Rainbow: false 97 | Max Color: 255; 255; 255 98 | Max Intensity: 255.389999 99 | Min Color: 0; 0; 0 100 | Min Intensity: 0.26383543 101 | Name: Lidar2 102 | Position Transformer: XYZ 103 | Queue Size: 10 104 | Selectable: true 105 | Size (Pixels): 3 106 | Size (m): 0.0500000007 107 | Style: Flat Squares 108 | Topic: /ns2/rslidar_points 109 | Unreliable: false 110 | Use Fixed Frame: true 111 | Use rainbow: true 112 | Value: true 113 | Enabled: true 114 | Global Options: 115 | Background Color: 48; 48; 48 116 | Default Light: true 117 | Fixed Frame: rslidar 118 | Frame Rate: 30 119 | Name: root 120 | Tools: 121 | - Class: rviz/Interact 122 | Hide Inactive Objects: true 123 | - Class: rviz/MoveCamera 124 | - Class: rviz/Select 125 | - Class: rviz/FocusCamera 126 | - Class: rviz/Measure 127 | - Class: rviz/SetInitialPose 128 | Topic: /initialpose 129 | - Class: rviz/SetGoal 130 | Topic: /move_base_simple/goal 131 | - Class: rviz/PublishPoint 132 | Single click: true 133 | Topic: /clicked_point 134 | Value: true 135 | Views: 136 | Current: 137 | Class: rviz/Orbit 138 | Distance: 39.3154106 139 | Enable Stereo Rendering: 140 | Stereo Eye Separation: 0.0599999987 141 | Stereo Focal Distance: 1 142 | Swap Stereo Eyes: false 143 | Value: false 144 | Focal Point: 145 | X: -4.96815443 146 | Y: -4.25982523 147 | Z: 0.00407630112 148 | Focal Shape Fixed Size: true 149 | Focal Shape Size: 0.0500000007 150 | Invert Z Axis: false 151 | Name: Current View 152 | Near Clip Distance: 0.00999999978 153 | Pitch: 1.56979632 154 | Target Frame: 155 | Value: Orbit (rviz) 156 | Yaw: 5.79858398 157 | Saved: ~ 158 | Window Geometry: 159 | Displays: 160 | collapsed: false 161 | Height: 1056 162 | Hide Left Dock: false 163 | Hide Right Dock: false 164 | QMainWindow State: 000000ff00000000fd00000004000000000000016a00000396fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006400fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000002800000396000000dd00fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f00000396fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000002800000396000000b000fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e100000197000000030000073f0000003efc0100000002fb0000000800540069006d006501000000000000073f0000030000fffffffb0000000800540069006d00650100000000000004500000000000000000000004ba0000039600000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 165 | Selection: 166 | collapsed: false 167 | Time: 168 | collapsed: false 169 | Tool Properties: 170 | collapsed: false 171 | Views: 172 | collapsed: false 173 | Width: 1855 174 | X: 1985 175 | Y: 24 176 | -------------------------------------------------------------------------------- /rslidar_sync/src/timesync_2lidar.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2020 Robosense Authors 3 | * License: Modified BSD Software License Agreement 4 | * 5 | * $Id$ 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | ros::Publisher g_skippackets_num_pub1; 17 | ros::Publisher g_skippackets_num_pub2; 18 | ros::Publisher g_maxnum_diff_packetnum_pub; 19 | int g_packet_duration_us = 1200; 20 | bool comparePair(const std::pair a, const std::pair b) 21 | { 22 | return a.second < b.second; 23 | } 24 | 25 | void scanCallback(const sensor_msgs::TimeReference::ConstPtr& scan_msg1, 26 | const sensor_msgs::TimeReference::ConstPtr& scan_msg2) 27 | { 28 | // calculate the first packet timestamp difference (us) 29 | double time1 = scan_msg1->header.stamp.sec * 1e6 + scan_msg1->header.stamp.nsec * 0.001; 30 | double time2 = scan_msg2->header.stamp.sec * 1e6 + scan_msg2->header.stamp.nsec * 0.001; 31 | 32 | std::vector > lidar_vector; 33 | lidar_vector.push_back(std::make_pair(1, time1)); 34 | lidar_vector.push_back(std::make_pair(2, time2)); 35 | std::sort(lidar_vector.begin(), lidar_vector.end(), comparePair); 36 | unsigned delta_skip = (lidar_vector[1].second - lidar_vector[0].second) / g_packet_duration_us; 37 | 38 | std_msgs::String msg; 39 | std::stringstream ss; 40 | ss << "sync diff packets: " << delta_skip; 41 | ; 42 | msg.data = ss.str(); 43 | g_maxnum_diff_packetnum_pub.publish(msg); 44 | 45 | std_msgs::Int32 skip_num; 46 | skip_num.data = 1; 47 | if (delta_skip > 0) 48 | { 49 | if (lidar_vector[0].first == 1) 50 | { 51 | g_skippackets_num_pub1.publish(skip_num); 52 | } 53 | else if (lidar_vector[0].first == 2) 54 | { 55 | g_skippackets_num_pub2.publish(skip_num); 56 | } 57 | } 58 | else 59 | { 60 | // std::cout << "Synchronizer!" << std::endl; 61 | } 62 | } 63 | 64 | int main(int argc, char** argv) 65 | { 66 | ros::init(argc, argv, "rs_sync"); 67 | ros::NodeHandle nh; 68 | ros::NodeHandle nh_private("~"); 69 | 70 | // get the topic parameters 71 | std::string scan1_topic("/left/sync_header"); 72 | std::string scan2_topic("/right/sync_header"); 73 | if (!nh_private.getParam(std::string("scan1_topic"), scan1_topic)) 74 | { 75 | ROS_ERROR_STREAM("[sync-2] Can't get scan1_topic, use the default scan1_topic: "< scan_sub1(nh, scan1_topic, 1); 130 | message_filters::Subscriber scan_sub2(nh, scan2_topic, 1); 131 | typedef message_filters::sync_policies::ApproximateTime 132 | ScanSyncPolicy; 133 | message_filters::Synchronizer scan_sync(ScanSyncPolicy(10), scan_sub1, scan_sub2); 134 | scan_sync.registerCallback(boost::bind(&scanCallback, _1, _2)); 135 | 136 | g_skippackets_num_pub1 = nh.advertise(skippackets1_topic, 1, true); 137 | g_skippackets_num_pub2 = nh.advertise(skippackets2_topic, true); 138 | 139 | std::string sync_packet_diff_topic("/sync_packet_diff"); 140 | if (!nh_private.getParam(std::string("sync_packet_diff_topic"), sync_packet_diff_topic)) 141 | { 142 | ROS_ERROR_STREAM("[sync-2] Can't get sync_packet_diff_topic, use the default sync_packet_diff_topic: " 143 | <(sync_packet_diff_topic, 1, true); 151 | 152 | ros::spin(); 153 | return 0; 154 | } 155 | -------------------------------------------------------------------------------- /rslidar_sync/src/timesync_3lidar.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2020 Robosense Authors 3 | * License: Modified BSD Software License Agreement 4 | * 5 | * $Id$ 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | ros::Publisher g_skippackets_num_pub1; 17 | ros::Publisher g_skippackets_num_pub2; 18 | ros::Publisher g_skippackets_num_pub3; 19 | ros::Publisher g_maxnum_diff_packetnum_pub; 20 | int g_packet_duration_us = 1200; 21 | bool comparePair(const std::pair a, const std::pair b) 22 | { 23 | return a.second < b.second; 24 | } 25 | 26 | void scanCallback(const sensor_msgs::TimeReference::ConstPtr& scan_msg1, 27 | const sensor_msgs::TimeReference::ConstPtr& scan_msg2, 28 | const sensor_msgs::TimeReference::ConstPtr scan_msg3) 29 | { 30 | // calculate the first packet timestamp difference (us) 31 | double time1 = scan_msg1->header.stamp.sec * 1e6 + scan_msg1->header.stamp.nsec * 0.001; 32 | double time2 = scan_msg2->header.stamp.sec * 1e6 + scan_msg2->header.stamp.nsec * 0.001; 33 | double time3 = scan_msg3->header.stamp.sec * 1e6 + scan_msg3->header.stamp.nsec * 0.001; 34 | 35 | std::vector > lidar_vector; 36 | lidar_vector.push_back(std::make_pair(1, time1)); 37 | lidar_vector.push_back(std::make_pair(2, time2)); 38 | lidar_vector.push_back(std::make_pair(3, time3)); 39 | 40 | std::sort(lidar_vector.begin(), lidar_vector.end(), comparePair); 41 | 42 | unsigned skip_big = (lidar_vector[2].second - lidar_vector[0].second) / g_packet_duration_us; 43 | unsigned skip_small = (lidar_vector[1].second - lidar_vector[0].second) / g_packet_duration_us; 44 | 45 | std_msgs::String msg; 46 | std::stringstream ss; 47 | ss << "sync diff packets: " << skip_big; 48 | msg.data = ss.str(); 49 | g_maxnum_diff_packetnum_pub.publish(msg); 50 | 51 | std_msgs::Int32 skip_num; 52 | if (skip_big > 1 && skip_small > 0) 53 | { 54 | // oldest skip 2 packets 55 | skip_num.data = 2; 56 | if (lidar_vector[0].first == 1) 57 | { 58 | g_skippackets_num_pub1.publish(skip_num); 59 | } 60 | else if (lidar_vector[0].first == 2) 61 | { 62 | g_skippackets_num_pub2.publish(skip_num); 63 | } 64 | else if (lidar_vector[0].first == 3) 65 | { 66 | g_skippackets_num_pub3.publish(skip_num); 67 | } 68 | 69 | // middle skip 1 packets 70 | skip_num.data = 1; 71 | if (lidar_vector[1].first == 1) 72 | { 73 | g_skippackets_num_pub1.publish(skip_num); 74 | } 75 | else if (lidar_vector[1].first == 2) 76 | { 77 | g_skippackets_num_pub2.publish(skip_num); 78 | } 79 | else if (lidar_vector[1].first == 3) 80 | { 81 | g_skippackets_num_pub3.publish(skip_num); 82 | } 83 | } 84 | else if (skip_big > 0 && skip_small == 0) 85 | { 86 | // oldest skip 2 packets 87 | skip_num.data = 1; 88 | if (lidar_vector[0].first == 1) 89 | { 90 | g_skippackets_num_pub1.publish(skip_num); 91 | } 92 | else if (lidar_vector[0].first == 2) 93 | { 94 | g_skippackets_num_pub2.publish(skip_num); 95 | } 96 | else if (lidar_vector[0].first == 3) 97 | { 98 | g_skippackets_num_pub3.publish(skip_num); 99 | } 100 | 101 | // middle skip 1 packets 102 | skip_num.data = 1; 103 | if (lidar_vector[1].first == 1) 104 | { 105 | g_skippackets_num_pub1.publish(skip_num); 106 | } 107 | else if (lidar_vector[1].first == 2) 108 | { 109 | g_skippackets_num_pub2.publish(skip_num); 110 | } 111 | else if (lidar_vector[1].first == 3) 112 | { 113 | g_skippackets_num_pub3.publish(skip_num); 114 | } 115 | } 116 | else if (skip_small > 0) 117 | { 118 | skip_num.data = 1; 119 | if (lidar_vector[0].first == 1) 120 | { 121 | g_skippackets_num_pub1.publish(skip_num); 122 | } 123 | else if (lidar_vector[0].first == 2) 124 | { 125 | g_skippackets_num_pub2.publish(skip_num); 126 | } 127 | else if (lidar_vector[0].first == 3) 128 | { 129 | g_skippackets_num_pub3.publish(skip_num); 130 | } 131 | else 132 | { 133 | ROS_ERROR("[sync-3] Oldest lidar skip one packet!"); 134 | // std::cerr << "Oldest lidar skip one packet!" << std::endl; 135 | } 136 | } 137 | if (skip_big == 0) 138 | { 139 | // std::cout << "3 lidar synchronizer!" << std::endl; 140 | } 141 | // std::cout << std::endl; 142 | } 143 | 144 | int main(int argc, char** argv) 145 | { 146 | ros::init(argc, argv, "rs_sync"); 147 | ros::NodeHandle nh; 148 | ros::NodeHandle nh_private("~"); 149 | 150 | // get the topic parameters 151 | std::string scan1_topic("/left/sync_header"); 152 | std::string scan2_topic("/right/sync_header"); 153 | std::string scan3_topic("/middle/sync_header"); 154 | if (!nh_private.getParam(std::string("scan1_topic"), scan1_topic)) 155 | { 156 | ROS_ERROR_STREAM("[sync-3] Can't get scan1_topic, use the default scan1_topic: "< scan_sub1(nh, scan1_topic, 1); 227 | message_filters::Subscriber scan_sub2(nh, scan2_topic, 1); 228 | message_filters::Subscriber scan_sub3(nh, scan3_topic, 1); 229 | typedef message_filters::sync_policies::ApproximateTime 231 | ScanSyncPolicy; 232 | message_filters::Synchronizer scan_sync(ScanSyncPolicy(10), scan_sub1, scan_sub2, scan_sub3); 233 | scan_sync.registerCallback(boost::bind(&scanCallback, _1, _2, _3)); 234 | 235 | g_skippackets_num_pub1 = nh.advertise(skippackets1_topic.c_str(), 1, true); 236 | g_skippackets_num_pub2 = nh.advertise(skippackets2_topic.c_str(), 1, true); 237 | g_skippackets_num_pub3 = nh.advertise(skippackets3_topic.c_str(), 1, true); 238 | 239 | std::string sync_packet_diff_topic("/sync_packet_diff"); 240 | if (!nh_private.getParam(std::string("sync_packet_diff_topic"), sync_packet_diff_topic)) 241 | { 242 | ROS_ERROR_STREAM("[sync-3] Can't get sync_packet_diff_topic, use the default sync_packet_diff_topic: " 243 | <(sync_packet_diff_topic, 1, true); 250 | 251 | ros::spin(); 252 | return 0; 253 | } 254 | -------------------------------------------------------------------------------- /test_doc/test_guide_cn.md: -------------------------------------------------------------------------------- 1 | # RSLidar ROS 驱动测试说明 2 | 3 | **修订日期:2019-03-18** 4 | 5 | 6 | ## 1. 版本号 7 | **v1.1.0** 8 | 9 | 10 | ## 2. 版本更新内容 11 | | 序号 | 简要 | 详细 | 备注 | 12 | | ---- | ---------------------------------------------------- | ----------------------- | ---- | 13 | | 1 | 新增:Launch文件可设置点云极限距离| 新增launch文件的配置参数:max_distance和min_distance来设置点云显示的最大距离和最小距离,如果没有设置此参数,则使用默认值:200m(最大), 0.2m(最小) | 无 | 14 | | 2 | Bug修复:点云坐标计算错误问题| 修复在1cm距离精度的固件中,点云距离和点云坐标错误的问题 | 无 | 15 | | 3 | 新增:兼容0.5cm距离精度固件 | 兼容0.5cm距离精度的固件| 无 | 16 | | 4 | 新增:增加对新反射率模式:Mode3的支持|由于新增反射率模式:Mode3,驱动增加对此支持解析| 无 | 17 | | 5 | 新增:增加双回波功能支持|驱动自动识别雷达的回波模式,并进行数据包相应解析处理|无| 18 | | 6 | 新增:支持resolution和intensity launch文件设置|在launch文件里设置指定,驱动根据参数进行设置|无| 19 | 20 | ## 3. 版本遗留问题 21 | | 序号 | 简要 | 详细 | 规避 | 效果 | 22 | | ---- | -------------- | ------------------------------ | --------------------------------- | -------------------------------- | 23 | 24 | 25 | ## 4. 版本自测概要 26 | 27 | |序号 | 操作 | 结果 | 备注 | 28 | |----|--------|----|------------------------------| 29 | | 1 | 用不同线数、不同距离精度的Pcap测试实际识别的距离精度,将点云距离与实际距离做比对 | Y | 环境为ubuntu_16.04+ROS_Kinetic | 30 | | 2 | 用不同线数、不同距离精度的Pcap测试实际识别的反射率模式,并与DIFOP包中第291Byte比对|Y | 环境为ubuntu_16.04+ROS_Kinetic | 31 | | 3 | 用不同线数、不同距离精度的Pcap测试极限距离,通过设置max_distance和min_distance的值,观察点云显示是否正常|Y | 环境为ubuntu_16.04+ROS_Kinetic | 32 | | 4 | 拿支持双回波的雷达,查看双回波模式下点云是否正常 | Y |目前只有16线雷达有双回波的正式版本| 33 | | 5 | launch文件设置不同resolution和intensity,看驱动是否生效 | Y |无| 34 | 35 | ## 5. 版本测试建议 36 | | 序号 | 测试点 | 建议 | 依据 | 备注 | 37 | | ---- | -------------- | ---------------------------------------------- | ------------------------------------------------------------ | ---- | 38 | | 1 | 使用不同线数,不同距离精度的Pcap或者雷达对距离精度、反射率模式、极限距离进行测试 | | 无 |无| 39 | | 2 | 双回波功能测试|双回波功能比较难测,可咨询固件同事协助 | 无 | 无| 40 | | 3 | 多个雷达同步功能的代码有调整,请测试功能是否正常 || 无 | 无| 41 | 42 | --------------------------------------------------------------------------------