├── .gitignore
├── CMakeLists.txt
├── LICENSE
├── README.md
├── include
└── ros_api.h
├── launch
├── ld06.launch
├── ld19.launch
├── viewer_ld06_kinetic_melodic.launch
├── viewer_ld06_noetic.launch
├── viewer_ld19_kinetic_melodic.launch
└── viewer_ld19_noetic.launch
├── ldlidar_driver
├── include
│ ├── core
│ │ ├── ldlidar_datatype.h
│ │ └── ldlidar_driver.h
│ ├── dataprocess
│ │ └── lipkg.h
│ ├── filter
│ │ └── tofbf.h
│ ├── logger
│ │ └── log_module.h
│ ├── networkcom
│ │ └── network_socket_interface_linux.h
│ └── serialcom
│ │ └── serial_interface_linux.h
└── src
│ ├── core
│ └── ldlidar_driver.cpp
│ ├── dataprocess
│ └── lipkg.cpp
│ ├── filter
│ └── tofbf.cpp
│ ├── logger
│ └── log_module.cpp
│ ├── networkcom
│ └── network_socket_interface_linux.cpp
│ └── serialcom
│ └── serial_interface_linux.cpp
├── package.xml
├── rules
└── ldlidar.rules
├── rviz
├── ldlidar_kinetic_melodic.rviz
└── ldlidar_noetic.rviz
├── scripts
├── create_udev_rules.sh
└── delete_udev_rules.sh
└── src
├── listen_node
└── listen_node.cpp
└── publish_node
└── main.cpp
/.gitignore:
--------------------------------------------------------------------------------
1 | *.json
2 | *.zip
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 | project(ldlidar_stl_ros)
3 |
4 | ## Compile as C++11, supported in ROS Kinetic and newer
5 | set (IS_WARLL "OFF") # "ON" or "OFF"
6 | if(${IS_WARLL} MATCHES "OFF")
7 | set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
8 | message(STATUS "optional:-std=c++11")
9 | else()
10 | set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra ${CMAKE_CXX_FLAGS}")
11 | message(STATUS "optional:-std=c++11 -Wall -Wextra ")
12 | endif()
13 |
14 | # set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g ")
15 | # set (CMAKE_VERBOSE_MAKEFILE ON)
16 |
17 | ## Find catkin macros and libraries
18 | ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
19 | ## is used, also find other catkin packages
20 | find_package(catkin REQUIRED COMPONENTS
21 | roscpp
22 | sensor_msgs
23 | )
24 |
25 | ## System dependencies are found with CMake's conventions
26 | # find_package(Boost REQUIRED COMPONENTS system)
27 |
28 |
29 | ## Uncomment this if the package has a setup.py. This macro ensures
30 | ## modules and global scripts declared therein get installed
31 | ## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
32 | # catkin_python_setup()
33 |
34 | ################################################
35 | ## Declare ROS messages, services and actions ##
36 | ################################################
37 |
38 | ## To declare and build messages, services or actions from within this
39 | ## package, follow these steps:
40 | ## * Let MSG_DEP_SET be the set of packages whose message types you use in
41 | ## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
42 | ## * In the file package.xml:
43 | ## * add a build_depend tag for "message_generation"
44 | ## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET
45 | ## * If MSG_DEP_SET isn't empty the following dependency has been pulled in
46 | ## but can be declared for certainty nonetheless:
47 | ## * add a exec_depend tag for "message_runtime"
48 | ## * In this file (CMakeLists.txt):
49 | ## * add "message_generation" and every package in MSG_DEP_SET to
50 | ## find_package(catkin REQUIRED COMPONENTS ...)
51 | ## * add "message_runtime" and every package in MSG_DEP_SET to
52 | ## catkin_package(CATKIN_DEPENDS ...)
53 | ## * uncomment the add_*_files sections below as needed
54 | ## and list every .msg/.srv/.action file to be processed
55 | ## * uncomment the generate_messages entry below
56 | ## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)
57 |
58 | ## Generate messages in the 'msg' folder
59 | # add_message_files(
60 | # FILES
61 | # Message1.msg
62 | # Message2.msg
63 | # )
64 |
65 | ## Generate services in the 'srv' folder
66 | # add_service_files(
67 | # FILES
68 | # Service1.srv
69 | # Service2.srv
70 | # )
71 |
72 | ## Generate actions in the 'action' folder
73 | # add_action_files(
74 | # FILES
75 | # Action1.action
76 | # Action2.action
77 | # )
78 |
79 | ## Generate added messages and services with any dependencies listed here
80 | # generate_messages(
81 | # DEPENDENCIES
82 | # std_msgs # Or other packages containing msgs
83 | # )
84 |
85 | ################################################
86 | ## Declare ROS dynamic reconfigure parameters ##
87 | ################################################
88 |
89 | ## To declare and build dynamic reconfigure parameters within this
90 | ## package, follow these steps:
91 | ## * In the file package.xml:
92 | ## * add a build_depend and a exec_depend tag for "dynamic_reconfigure"
93 | ## * In this file (CMakeLists.txt):
94 | ## * add "dynamic_reconfigure" to
95 | ## find_package(catkin REQUIRED COMPONENTS ...)
96 | ## * uncomment the "generate_dynamic_reconfigure_options" section below
97 | ## and list every .cfg file to be processed
98 |
99 | ## Generate dynamic reconfigure parameters in the 'cfg' folder
100 | # generate_dynamic_reconfigure_options(
101 | # cfg/DynReconf1.cfg
102 | # cfg/DynReconf2.cfg
103 | # )
104 |
105 | ###################################
106 | ## catkin specific configuration ##
107 | ###################################
108 | ## The catkin_package macro generates cmake config files for your package
109 | ## Declare things to be passed to dependent projects
110 | ## INCLUDE_DIRS: uncomment this if your package contains header files
111 | ## LIBRARIES: libraries you create in this project that dependent projects also need
112 | ## CATKIN_DEPENDS: catkin_packages dependent projects also need
113 | ## DEPENDS: system dependencies of this project that dependent projects also need
114 | catkin_package(
115 | # INCLUDE_DIRS include
116 | # LIBRARIES ldlidar
117 | # CATKIN_DEPENDS other_catkin_pkg
118 | # DEPENDS system_lib
119 | )
120 |
121 | ###########
122 | ## Build ##
123 | ###########
124 |
125 | ## Specify additional locations of header files
126 | ## Your package locations should be listed before other locations
127 | include_directories(
128 | ${CMAKE_CURRENT_SOURCE_DIR}/include
129 | ${CMAKE_CURRENT_SOURCE_DIR}/ldlidar_driver/include/core/
130 | ${CMAKE_CURRENT_SOURCE_DIR}/ldlidar_driver/include/dataprocess/
131 | ${CMAKE_CURRENT_SOURCE_DIR}/ldlidar_driver/include/filter/
132 | ${CMAKE_CURRENT_SOURCE_DIR}/ldlidar_driver/include/logger/
133 | ${CMAKE_CURRENT_SOURCE_DIR}/ldlidar_driver/include/networkcom/
134 | ${CMAKE_CURRENT_SOURCE_DIR}/ldlidar_driver/include/serialcom/
135 | ${catkin_INCLUDE_DIRS}
136 | )
137 |
138 | file(GLOB LDLIDAR_DRI_CORE ${CMAKE_CURRENT_SOURCE_DIR}/ldlidar_driver/src/core/*.cpp)
139 | file(GLOB LDLIDAR_DRI_DATARPC ${CMAKE_CURRENT_SOURCE_DIR}/ldlidar_driver/src/dataprocess/*.cpp)
140 | file(GLOB LDLIDAR_DRI_FILTER ${CMAKE_CURRENT_SOURCE_DIR}/ldlidar_driver/src/filter/*.cpp)
141 | file(GLOB LDLIDAR_DRI_LOGGER ${CMAKE_CURRENT_SOURCE_DIR}/ldlidar_driver/src/logger/*.cpp)
142 | file(GLOB LDLIDAR_DRI_NETWORK ${CMAKE_CURRENT_SOURCE_DIR}/ldlidar_driver/src/networkcom/*.cpp)
143 | file(GLOB LDLIDAR_DRI_SERIAL ${CMAKE_CURRENT_SOURCE_DIR}/ldlidar_driver/src/serialcom/*.cpp)
144 |
145 | file(GLOB MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/publish_node/*.cpp)
146 | file(GLOB LISTEN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/listen_node/*.cpp)
147 |
148 | add_executable(${PROJECT_NAME}_node
149 | ${MAIN_SRC}
150 | ${LDLIDAR_DRI_CORE}
151 | ${LDLIDAR_DRI_DATARPC}
152 | ${LDLIDAR_DRI_FILTER}
153 | ${LDLIDAR_DRI_LOGGER}
154 | ${LDLIDAR_DRI_NETWORK}
155 | ${LDLIDAR_DRI_SERIAL}
156 | )
157 | target_link_libraries(${PROJECT_NAME}_node pthread ${catkin_LIBRARIES})
158 |
159 | add_executable(${PROJECT_NAME}_listen_node
160 | ${LISTEN_SRC}
161 | )
162 | target_link_libraries(${PROJECT_NAME}_listen_node ${catkin_LIBRARIES})
163 |
164 | ## Declare a C++ library
165 | # add_library(${PROJECT_NAME}
166 | # src/${PROJECT_NAME}/ldlidar.cpp
167 | # )
168 |
169 | ## Add cmake target dependencies of the library
170 | ## as an example, code may need to be generated before libraries
171 | ## either from message generation or dynamic reconfigure
172 | # add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
173 |
174 | ## Declare a C++ executable
175 | ## With catkin_make all packages are built within a single CMake context
176 | ## The recommended prefix ensures that target names across packages don't collide
177 | # add_executable(${PROJECT_NAME}_node src/ldlidar_node.cpp)
178 |
179 | ## Rename C++ executable without prefix
180 | ## The above recommended prefix causes long target names, the following renames the
181 | ## target back to the shorter version for ease of user use
182 | ## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
183 | # set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")
184 |
185 | ## Add cmake target dependencies of the executable
186 | ## same as for the library above
187 | # add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
188 |
189 | ## Specify libraries to link a library or executable target against
190 | # target_link_libraries(${PROJECT_NAME}_node
191 | # ${catkin_LIBRARIES}
192 | # )
193 |
194 | #############
195 | ## Install ##
196 | #############
197 |
198 | # all install targets should use catkin DESTINATION variables
199 | # See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html
200 |
201 | ## Mark executable scripts (Python etc.) for installation
202 | ## in contrast to setup.py, you can choose the destination
203 | # install(PROGRAMS
204 | # scripts/my_python_script
205 | # DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
206 | # )
207 | install(PROGRAMS
208 | scripts/create_udev_rules.sh
209 | scripts/delete_udev_rules.sh
210 | DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
211 | )
212 |
213 | ## Mark executables and/or libraries for installation
214 | # install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_node
215 | # ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
216 | # LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
217 | # RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
218 | # )
219 | install(TARGETS ${PROJECT_NAME}_node ${PROJECT_NAME}_listen_node
220 | ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
221 | LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
222 | RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
223 | )
224 |
225 | ## Mark cpp header files for installation
226 | # install(DIRECTORY include/${PROJECT_NAME}/
227 | # DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
228 | # FILES_MATCHING PATTERN "*.h"
229 | # PATTERN ".svn" EXCLUDE
230 | # )
231 |
232 | ## Mark other files for installation (e.g. launch and bag files, etc.)
233 | # install(FILES
234 | # # myfile1
235 | # # myfile2
236 | # DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
237 | # )
238 | install(DIRECTORY launch rules rviz
239 | DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
240 | )
241 |
242 | #############
243 | ## Testing ##
244 | #############
245 |
246 | ## Add gtest based cpp test target and link libraries
247 | # catkin_add_gtest(${PROJECT_NAME}-test test/test_ldlidar.cpp)
248 | # if(TARGET ${PROJECT_NAME}-test)
249 | # target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
250 | # endif()
251 |
252 | ## Add folders to be run by python nosetests
253 | # catkin_add_nosetests(test)
254 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 SHENZHEN LDROBOT CO., LTD. All rights
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | - [cn](#操作指南)
2 | - [en](#Instructions)
3 | # 操作指南
4 |
5 | >此SDK仅适用于深圳乐动机器人有限公司销售的激光雷达产品,产品型号为:
6 | > - LDROBOT LiDAR LD06
7 | > - LDROBOT LiDAR LD19
8 | ## 0. 获取雷达的ROS功能包
9 | ```bash
10 | cd ~
11 |
12 | mkdir -p ldlidar_ros_ws/src
13 |
14 | cd ldlidar_ros_ws/src
15 |
16 | git clone https://github.com/ldrobotSensorTeam/ldlidar_stl_ros.git
17 | # 或者
18 | git clone https://gitee.com/ldrobotSensorTeam/ldlidar_stl_ros.git
19 | ```
20 |
21 | ## 1. 系统设置
22 | - 第一步,通过板载串口或者USB转串口模块(例如,cp2102模块)的方式使雷达连接到你的系统主板.
23 | - 第二步,设置雷达在系统中挂载的串口设备-x权限(以/dev/ttyUSB0为例)
24 | - 实际使用时,根据雷达在你的系统中的实际挂载情况来设置,可以使用`ls -l /dev`命令查看.
25 |
26 | ``` bash
27 | cd ~/ldlidar_ros_ws
28 |
29 | sudo chmod 777 /dev/ttyUSB0
30 | ```
31 | - 第三步,修改`launch/`目录下雷达产品型号对应的lanuch文件中的`port_name`值,以ld06.launch为例,如下所示.
32 |
33 | ```xml
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 |
67 |
68 |
69 |
70 |
71 | ```
72 | ## 2. 编译方法
73 | - 安装src/目录下功能包的依赖
74 | ```bash
75 | cd ~/ldlidar_ros_ws
76 |
77 | rosdep install --from-paths src --ignore-src -r -y
78 | ```
79 | - 使用catkin编译
80 | ```bash
81 | cd ~/ldlidar_ros_ws
82 |
83 | catkin_make
84 | ```
85 | ## 3. 运行方法
86 |
87 | ### 3.1. 设置功能包环境变量
88 |
89 | - 编译完成后需要将编译生成的相关文件加入环境变量,便于 ROS 环境可以识别, 执行命令如下所示, 该命令是临时给终端加入环境变量,意味着您如果重
90 | 新打开新的终端,也需要重新执行如下命令.
91 |
92 | ```bash
93 | cd ~/ldlidar_ros_ws
94 |
95 | source devel/setup.bash
96 | ```
97 | - 为了重新打开终端后,永久不用执行上述添加环境变量的命令,可以进行如下操作.
98 |
99 | ```bash
100 | echo "source ~/ldlidar_ros_ws/devel/setup.bash" >> ~/.bashrc
101 |
102 | source ~/.bashrc
103 | ```
104 | ### 3.2. 启动激光雷达节点
105 |
106 | - 产品型号为 LDROBOT LiDAR LD06
107 | - 启动ld06 lidar node:
108 | ``` bash
109 | roslaunch ldlidar_stl_ros ld06.launch
110 | ```
111 | - 启动ld06 lidar node并显示激光数据在Rviz上:
112 | ``` bash
113 | # if ROS_DISTRO in 'kinetic' or 'melodic'
114 | roslaunch ldlidar_stl_ros viewer_ld06_kinetic_melodic.launch
115 | # if ROS_DISTRO in 'noetic'
116 | roslaunch ldlidar_stl_ros viewer_ld06_noetic.launch
117 | ```
118 |
119 | - 产品型号为 LDROBOT LiDAR LD19
120 | - 启动ld19 lidar node:
121 | ``` bash
122 | roslaunch ldlidar_stl_ros ld19.launch
123 | ```
124 | - 启动ld19 lidar node并显示激光数据在Rviz上:
125 | ``` bash
126 | # if ROS_DISTRO in 'kinetic' or 'melodic'
127 | roslaunch ldlidar_stl_ros viewer_ld19_kinetic_melodic.launch
128 | # if ROS_DISTRO in 'noetic'
129 | roslaunch ldlidar_stl_ros viewer_ld19_noetic.launch
130 | ```
131 |
132 | ## 4. 测试
133 |
134 | > 代码支持ubuntu16.04 ROS kinetic、ubuntu18.04 ROS melodic、ubuntu20.04 ROS noetic版本下测试,使用rviz可视化。
135 |
136 | - 新打开一个终端 (Ctrl + Alt + T),并通过Rviz工具打开readme文件所在目录的rviz文件夹下面的rviz配置文件
137 | ```bash
138 | rviz
139 | ```
140 | # Instructions
141 |
142 | > This SDK is only applicable to the LiDAR products sold by Shenzhen LDROBOT Co., LTD. The product models are :
143 | > - LDROBOT LiDAR LD06
144 | > - LDROBOT LiDAR LD19
145 | ## step0: get LiDAR ROS Package
146 | ```bash
147 | cd ~
148 |
149 | mkdir -p ldlidar_ros_ws/src
150 |
151 | cd ldlidar_ros_ws/src
152 |
153 | git clone https://github.com/ldrobotSensorTeam/ldlidar_stl_ros.git
154 | # or
155 | git clone https://gitee.com/ldrobotSensorTeam/ldlidar_stl_ros.git
156 | ```
157 | ## step 1: system setup
158 | - Connect the LiDAR to your system motherboard via an onboard serial port or usB-to-serial module (for example, CP2102 module).
159 |
160 | - Set the -x permission for the serial port device mounted by the radar in the system (for example, /dev/ttyUSB0)
161 |
162 | - In actual use, the LiDAR can be set according to the actual mounted status of your system, you can use 'ls -l /dev' command to view.
163 |
164 | ``` bash
165 | cd ~/ldlidar_ros_ws
166 |
167 | sudo chmod 777 /dev/ttyUSB0
168 | ```
169 | - Modify the `port_name` value in the Lanuch file corresponding to the radar product model under `launch/`, using `ld06.launch` as an example, as shown below.
170 |
171 | ``` xml
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
205 |
206 |
207 |
208 |
209 | ```
210 | ## step 2: build
211 | - install package depend
212 | ```bash
213 | cd ~/ldlidar_ros_ws
214 |
215 | rosdep install --from-paths src --ignore-src -r -y
216 | ```
217 |
218 | - build compile
219 | ```bash
220 | cd ~/ldlidar_ros_ws
221 |
222 | catkin_make
223 | ```
224 | ## step 3: run
225 |
226 | ### step3.1: package environment variable settings
227 |
228 | - After the compilation is completed, you need to add the relevant files generated by the compilation to the environment variables, so that the ROS environment can recognize them. The execution command is as follows. This command is to temporarily add environment variables to the terminal, which means that if you reopen a new terminal, you also need to re-execute it. The following command.
229 |
230 | ```bash
231 | cd ~/ldlidar_ros_ws
232 |
233 | source devel/setup.bash
234 | ```
235 |
236 | - In order to never need to execute the above command to add environment variables after reopening the terminal, you can do the following.
237 |
238 | ```bash
239 | echo "source ~/ldlidar_ros_ws/devel/setup.bash" >> ~/.bashrc
240 |
241 | source ~/.bashrc
242 | ```
243 | ### step3.2: start LiDAR node
244 |
245 | - The product is LDROBOT LiDAR LD06
246 | - start ld06 lidar node:
247 | ``` bash
248 | roslaunch ldlidar_stl_ros ld06.launch
249 | ```
250 | - start ld06 lidar node and show on the Rviz:
251 | ``` bash
252 | # if ROS_DISTRO in 'kinetic' or 'melodic'
253 | roslaunch ldlidar_stl_ros viewer_ld06_kinetic_melodic.launch
254 | # if ROS_DISTRO in 'noetic'
255 | roslaunch ldlidar_stl_ros viewer_ld06_noetic.launch
256 | ```
257 |
258 | - The product is LDROBOT LiDAR LD19
259 | - start ld19 lidar node:
260 | ``` bash
261 | roslaunch ldlidar_stl_ros ld19.launch
262 | ```
263 | - start ld19 lidar node and show on the Rviz:
264 | ``` bash
265 | # if ROS_DISTRO in 'kinetic' or 'melodic'
266 | roslaunch ldlidar_stl_ros viewer_ld19_kinetic_melodic.launch
267 | # if ROS_DISTRO in 'noetic'
268 | roslaunch ldlidar_stl_ros viewer_ld19_noetic.launch
269 | ```
270 |
271 | ## step 4: test
272 |
273 | > The code was tested under ubuntu16.04 ROS kinetic、ubuntu18.04 ROS melodic、ubuntu20.04 ROS noetic, using rviz visualization.
274 |
275 | - new a terminal (Ctrl + Alt + T) and use Rviz tool,open the rviz config file below the rviz folder of the readme file directory
276 | ```bash
277 | rviz
278 | ```
--------------------------------------------------------------------------------
/include/ros_api.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file ros_api.h
3 | * @author LDRobot (support@ldrobot.com)
4 | * @brief ros lib interface
5 | * This code is only applicable to LDROBOT LiDAR products
6 | * sold by Shenzhen LDROBOT Co., LTD
7 | * @version 0.1
8 | * @date 2021-10-28
9 | *
10 | * @copyright Copyright (c) 2021 SHENZHEN LDROBOT CO., LTD. All rights
11 | * reserved.
12 | * Licensed under the MIT License (the "License");
13 | * you may not use this file except in compliance with the License.
14 | * You may obtain a copy of the License in the file LICENSE
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | */
21 | #ifndef __ROS_API_H__
22 | #define __ROS_API_H__
23 |
24 | #include
25 | #include
26 | #include
27 |
28 | struct LaserScanSetting
29 | {
30 | std::string frame_id;
31 | bool laser_scan_dir;
32 | bool enable_angle_crop_func;
33 | double angle_crop_min;
34 | double angle_crop_max;
35 | };
36 |
37 | #endif //__ROS_API_H__
38 |
39 | /********************* (C) COPYRIGHT SHENZHEN LDROBOT CO., LTD *******END OF
40 | * FILE ********/
--------------------------------------------------------------------------------
/launch/ld06.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 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/launch/ld19.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 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/launch/viewer_ld06_kinetic_melodic.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/launch/viewer_ld06_noetic.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/launch/viewer_ld19_kinetic_melodic.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/launch/viewer_ld19_noetic.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/ldlidar_driver/include/core/ldlidar_datatype.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file pointdata.h
3 | * @author LDRobot (support@ldrobot.com)
4 | * @brief lidar point data structure
5 | * This code is only applicable to LDROBOT products
6 | * sold by Shenzhen LDROBOT Co., LTD
7 | * @version 0.1
8 | * @date 2021-11-09
9 | *
10 | * @copyright Copyright (c) 2021 SHENZHEN LDROBOT CO., LTD. All rights
11 | * reserved.
12 | * Licensed under the MIT License (the "License");
13 | * you may not use this file except in compliance with the License.
14 | * You may obtain a copy of the License in the file LICENSE
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | */
21 | #ifndef _LDLIDAR_POINT_DATA_H_
22 | #define _LDLIDAR_POINT_DATA_H_
23 |
24 | #include
25 |
26 | #include
27 | #include
28 |
29 | #define ANGLE_TO_RADIAN(angle) ((angle)*3141.59 / 180000)
30 | #define RADIAN_TO_ANGLED(angle) ((angle)*180000 / 3141.59)
31 |
32 | namespace ldlidar {
33 |
34 | enum class LDType {
35 | NO_VERSION,
36 | LD_06,
37 | LD_19,
38 | STL_06P,
39 | STL_26,
40 | STL_27L,
41 | };
42 |
43 | enum class LidarStatus {
44 | NORMAL, // 雷达正常,可获取点云数据
45 | ERROR, // 表明雷达出现异常错误,可获取雷达反馈的错误码了解具体错误,具体错误由错误码对应二进制值的对应位决定
46 | DATA_TIME_OUT, // 雷达点云数据包发布超时
47 | DATA_WAIT, // 雷达点云数据包发布等待
48 | STOP, // 未启动Driver
49 | };
50 |
51 | struct PointData {
52 | // Polar coordinate representation
53 | float angle; // Angle ranges from 0 to 359 degrees
54 | uint16_t distance; // Distance is measured in millimeters
55 | uint8_t intensity; // Intensity is 0 to 255
56 | //! System time when first range was measured in nanoseconds
57 | uint64_t stamp;
58 | // Cartesian coordinate representation
59 | double x;
60 | double y;
61 | PointData(float angle, uint16_t distance, uint8_t intensity, uint64_t stamp = 0, double x = 0,
62 | double y = 0) {
63 | this->angle = angle;
64 | this->distance = distance;
65 | this->intensity = intensity;
66 | this->stamp = stamp;
67 | this->x = x;
68 | this->y = y;
69 | }
70 | PointData() {}
71 | };
72 |
73 | typedef std::vector Points2D;
74 |
75 | struct LaserScan {
76 | //! System time when first range was measured in nanoseconds
77 | uint64_t stamp;
78 | //! Array of laser point
79 | Points2D points;
80 |
81 | LaserScan &operator=(const LaserScan &data) {
82 | this->stamp = data.stamp;
83 | this->points = data.points;
84 | return *this;
85 | }
86 | };
87 |
88 | } // namespace ldlidar
89 |
90 | #endif // _POINT_DATA_H_
91 |
92 | /********************* (C) COPYRIGHT SHENZHEN LDROBOT CO., LTD *******END OF
93 | * FILE ********/
--------------------------------------------------------------------------------
/ldlidar_driver/include/core/ldlidar_driver.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file ldlidar_driver.h
3 | * @author LDRobot (support@ldrobot.com)
4 | * @brief ldlidar processing App
5 | * This code is only applicable to LDROBOT LiDAR LD14
6 | * products sold by Shenzhen LDROBOT Co., LTD
7 | * @version 0.1
8 | * @date 2021-05-12
9 | *
10 | * @copyright Copyright (c) 2022 SHENZHEN LDROBOT CO., LTD. All rights
11 | * reserved.
12 | * Licensed under the MIT License (the "License");
13 | * you may not use this file except in compliance with the License.
14 | * You may obtain a copy of the License in the file LICENSE
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | */
21 | #ifndef __LDLIDAR_NODE_H__
22 | #define __LDLIDAR_NODE_H__
23 |
24 | #include
25 | #include
26 |
27 | #include "serial_interface_linux.h"
28 | #include "network_socket_interface_linux.h"
29 | #include "lipkg.h"
30 | #include "log_module.h"
31 |
32 | namespace ldlidar {
33 |
34 | typedef enum CommunicationMode {
35 | COMM_NO_NULL,
36 | COMM_SERIAL_MODE, /* serial communication */
37 | COMM_UDP_CLIENT_MODE, /* network communication for UDP client */
38 | COMM_UDP_SERVER_MODE, /* network communication for UDP server */
39 | COMM_TCP_CLIENT_MODE, /* network communication for TCP client */
40 | COMM_TCP_SERVER_MODE /* network communication for TCP server */
41 | }CommunicationModeTypeDef;
42 |
43 | class LDLidarDriver {
44 | public:
45 | LDLidarDriver();
46 | ~LDLidarDriver();
47 |
48 | /**
49 | * @brief get lidar sdk version number
50 | * @param none
51 | * @retval string type, for example is "v2.3.0"
52 | */
53 | std::string GetLidarSdkVersionNumber(void);
54 |
55 | /**
56 | * @brief start lidar device handle node
57 | * @param product_name
58 | * ldlidar product type: ldlidar::LDType, value:
59 | * - ldlidar::LDType::NOVER
60 | * - ldlidar::LDType::LD_06
61 | * ....
62 | * - else definition in "ldlidar_driver/include/ldlidar_datatype.h"
63 | * @param serial_port_name
64 | * serial device system path, eg: "/dev/ttyUSB0"
65 | * @param serial_baudrate
66 | * serial communication baudrate value(> 0), unit is bit/s.
67 | * @retval value is true, start is success;
68 | * value is false, start is failed.
69 | */
70 | bool Start(LDType product_name,
71 | std::string serial_port_name,
72 | uint32_t serial_baudrate = 115200,
73 | CommunicationModeTypeDef comm_mode = COMM_SERIAL_MODE);
74 |
75 | bool Start(LDType product_name,
76 | const char* server_ip,
77 | const char* server_port,
78 | CommunicationModeTypeDef comm_mode = COMM_TCP_CLIENT_MODE);
79 |
80 | /**
81 | * @brief stop lidar device handle node
82 | * @param none
83 | * @retval value is true, stop is success;
84 | * value is false, stop is failed.
85 | */
86 | bool Stop(void);
87 |
88 | /**
89 | * @brief Whether the connection of the communication channel is normal after the lidar is powered on
90 | * @param[in]
91 | * *@param timeout: Wait timeout, in milliseconds
92 | * @retval if times >= timeout, return false, communication connection is fail;
93 | * if "times < timeout", return ture, communication connection is successful.
94 | */
95 | bool WaitLidarCommConnect(int64_t timeout);
96 |
97 | /**
98 | * @brief get lidar laser scan point cloud data
99 | * @param [output]
100 | * *@param dst: type is ldlidar::Point2D, value is laser scan point cloud data
101 | * @param [in]
102 | * *@param timeout: Wait timeout, in milliseconds
103 | * @retval value is ldlidar::LidarStatus Enum Type, definition in "ldlidar_driver/include/ldlidar_datatype.h", value is:
104 | * ldlidar::LidarStatus::NORMAL // 雷达正常
105 | * lldlidar::LidarStatus::ERROR // 雷达异常错误
106 | * ....
107 | */
108 | LidarStatus GetLaserScanData(Points2D& dst, int64_t timeout = 1000);
109 |
110 | LidarStatus GetLaserScanData(LaserScan& dst, int64_t timeout = 1000);
111 |
112 | /**
113 | * @brief get lidar laser scan frequence
114 | * @param [output]
115 | * *@param spin_hz: value unit is hz.
116 | * @retval value is true, get lidar laser scan frequence is success;
117 | * value is false, get lidar laser scan ferquence is fail.
118 | */
119 | bool GetLidarScanFreq(double& spin_hz);
120 |
121 | /**
122 | * @brief register get timestamp handle functional.
123 | * @param [input]
124 | * *@param get_timestamp_handle: type is `uint64_t (*)(void)`, value is pointer get timestamp fuction.
125 | * @retval none
126 | */
127 | void RegisterGetTimestampFunctional(std::function get_timestamp_handle);
128 |
129 | /**
130 | * @brief open or close filter algorithnm process
131 | * @param [input]
132 | * *@param is_enable: value is true, open filter process;
133 | * value is false, close filter process.
134 | * @retval none
135 | */
136 | void EnableFilterAlgorithnmProcess(bool is_enable);
137 |
138 | /**
139 | * @brief When the lidar is in an error state, get the error code fed back by the lidar
140 | * @param none
141 | * @retval errcode
142 | */
143 | // uint8_t GetLidarErrorCode(void);
144 |
145 | static bool IsOk() { return is_ok_; }
146 |
147 | static void SetIsOkStatus(bool status) { is_ok_ = status;}
148 |
149 | private:
150 | std::string sdk_version_number_;
151 | static bool is_ok_;
152 | bool is_start_flag_;
153 | std::function register_get_timestamp_handle_;
154 | LiPkg* comm_pkg_;
155 | SerialInterfaceLinux* comm_serial_;
156 | TCPSocketInterfaceLinux* comm_tcp_network_;
157 | UDPSocketInterfaceLinux* comm_udp_network_;
158 | std::chrono::_V2::steady_clock::time_point last_pubdata_times_;
159 | };
160 |
161 | } // namespace ldlidar
162 |
163 | #endif // __LDLIDAR_DRIVER_H__
164 | /********************* (C) COPYRIGHT SHENZHEN LDROBOT CO., LTD *******END OF
165 | * FILE ********/
--------------------------------------------------------------------------------
/ldlidar_driver/include/dataprocess/lipkg.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file lipkg.h
3 | * @author LDRobot (support@ldrobot.com)
4 | * @brief LiDAR data protocol processing App
5 | * This code is only applicable to LDROBOT LiDAR LD06 products
6 | * sold by Shenzhen LDROBOT Co., LTD
7 | * @version 0.1
8 | * @date 2021-10-28
9 | *
10 | * @copyright Copyright (c) 2021 SHENZHEN LDROBOT CO., LTD. All rights
11 | * reserved.
12 | * Licensed under the MIT License (the "License");
13 | * you may not use this file except in compliance with the License.
14 | * You may obtain a copy of the License in the file LICENSE
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | */
21 |
22 | #ifndef __LIPKG_H
23 | #define __LIPKG_H
24 |
25 |
26 | #include
27 | #include
28 | #include
29 |
30 | #include
31 |
32 | #include "ldlidar_datatype.h"
33 | #include "tofbf.h"
34 |
35 | namespace ldlidar {
36 |
37 | enum {
38 | PKG_HEADER = 0x54,
39 | PKG_VER_LEN = 0x2C,
40 | POINT_PER_PACK = 12,
41 | };
42 |
43 | typedef struct __attribute__((packed)) {
44 | uint16_t distance;
45 | uint8_t intensity;
46 | } LidarPointStructDef;
47 |
48 | typedef struct __attribute__((packed)) {
49 | uint8_t header;
50 | uint8_t ver_len;
51 | uint16_t speed;
52 | uint16_t start_angle;
53 | LidarPointStructDef point[POINT_PER_PACK];
54 | uint16_t end_angle;
55 | uint16_t timestamp;
56 | uint8_t crc8;
57 | } LiDARFrameTypeDef;
58 |
59 | class LiPkg {
60 | public:
61 | LiPkg();
62 | ~LiPkg();
63 |
64 | // set product type (belong to enum class LDType)
65 | void SetProductType(LDType type_number);
66 | // get Lidar spin speed (Hz)
67 | double GetSpeed(void);
68 | // get lidar spind speed (degree per second) origin
69 | uint16_t GetSpeedOrigin(void);
70 | // get time stamp of the packet
71 | uint16_t GetTimestamp(void);
72 | // get lidar measure frequence(Hz)
73 | int GetLidarMeasurePointFrequence(void);
74 |
75 | void CommReadCallback(const char *byte, size_t len);
76 |
77 | bool GetLaserScanData(Points2D& out);
78 |
79 | void RegisterTimestampGetFunctional(std::function timestamp_handle);
80 |
81 | bool GetLidarPowerOnCommStatus(void);
82 |
83 | void EnableFilter(bool is_enable);
84 |
85 | LidarStatus GetLidarStatus(void);
86 |
87 | void ClearDataProcessStatus(void) {
88 | is_frame_ready_ = false;
89 | is_poweron_comm_normal_ = false;
90 | lidarstatus_ = LidarStatus::NORMAL;
91 | last_pkg_timestamp_ = 0;
92 | first_frame_ = true;
93 | }
94 |
95 |
96 | private:
97 | LDType product_type_;
98 | uint16_t timestamp_;
99 | double speed_;
100 | bool is_frame_ready_;
101 | bool is_poweron_comm_normal_;
102 | bool is_filter_;
103 | LidarStatus lidarstatus_;
104 | int measure_point_frequence_;
105 | std::function get_timestamp_;
106 | uint64_t last_pkg_timestamp_;
107 | bool first_frame_;
108 |
109 | LiDARFrameTypeDef pkg_;
110 | Points2D frame_tmp_;
111 | Points2D laser_scan_data_;
112 | std::mutex mutex_lock1_;
113 | std::mutex mutex_lock2_;
114 |
115 |
116 | // parse single packet
117 | bool AnalysisOne(uint8_t byte);
118 | bool Parse(const uint8_t* data, long len);
119 | // combine stantard data into data frames and calibrate
120 | bool AssemblePacket();
121 | void SetFrameReady(void);
122 | void SetLaserScanData(Points2D& src);
123 |
124 | // Get lidar data frame ready flag
125 | bool IsFrameReady(void);
126 | // Lidar data frame readiness flag reset
127 | void ResetFrameReady(void);
128 | };
129 |
130 | } // namespace ldlidar
131 |
132 | #endif //__LIPKG_H
133 |
134 | /********************* (C) COPYRIGHT SHENZHEN LDROBOT CO., LTD *******END OF
135 | * FILE ********/
--------------------------------------------------------------------------------
/ldlidar_driver/include/filter/tofbf.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file tofbf.h
3 | * @author LDRobot (support@ldrobot.com)
4 | * @brief LiDAR near-range filtering algorithm
5 | * This code is only applicable to LDROBOT LiDAR LD06 products
6 | * sold by Shenzhen LDROBOT Co., LTD
7 | * @version 0.1
8 | * @date 2021-10-28
9 | *
10 | * @copyright Copyright (c) 2021 SHENZHEN LDROBOT CO., LTD. All rights
11 | * reserved.
12 | * Licensed under the MIT License (the "License");
13 | * you may not use this file except in compliance with the License.
14 | * You may obtain a copy of the License in the file LICENSE
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | */
21 |
22 | #ifndef __TOFBF_H_
23 | #define __TOFBF_H_
24 |
25 | #include
26 |
27 | #include
28 | #include
29 |
30 | #include
31 | #include
32 |
33 | #include "ldlidar_datatype.h"
34 |
35 | namespace ldlidar {
36 |
37 | enum class FilterType{
38 | NO_FILTER,
39 | NEAR_FILTER,
40 | NOISE_FILTER
41 | };
42 |
43 | class Tofbf {
44 | public:
45 | Tofbf(int speed, LDType type);
46 | ~Tofbf();
47 | std::vector Filter(const std::vector &tmp) const;
48 |
49 | private:
50 | FilterType filter_type_;
51 | // Low intensity threshold
52 | int intensity_low_;
53 | // Discrete points require higher intensity
54 | int intensity_single_;
55 | // Default scan frequency, to change, read according to radar protocol
56 | int scan_frequency_;
57 | double curr_speed_;
58 | Tofbf() = delete;
59 | Tofbf(const Tofbf &) = delete;
60 | Tofbf &operator=(const Tofbf &) = delete;
61 | std::vector NearFilter(const std::vector &tmp) const;
62 | std::vector NoiseFilter(const std::vector &tmp) const;
63 | };
64 |
65 | } // namespace ldlidar
66 |
67 | #endif //__TOFBF_H_
68 |
69 | /********************* (C) COPYRIGHT SHENZHEN LDROBOT CO., LTD *******END OF
70 | * FILE ********/
--------------------------------------------------------------------------------
/ldlidar_driver/include/logger/log_module.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file ldlidar_logger.h
3 | * @author LDRobot (support@ldrobot.com)
4 | * @brief
5 | * @version 0.1
6 | * @date 2022.08.10
7 | * @note
8 | * @copyright Copyright (c) 2022 SHENZHEN LDROBOT CO., LTD. All rights reserved.
9 | * Licensed under the MIT License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License in the file LICENSE
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | **/
18 | #ifndef __LOGMODULE_H_
19 | #define __LOGMODULE_H_
20 |
21 |
22 | #define LINUX
23 |
24 | #define ENABLE_LOG_DIS_OUTPUT
25 |
26 | #define ENABLE_CONSOLE_LOG_DIS
27 |
28 | //#define ENABLE_LOG_WRITE_TO_FILE
29 |
30 | #define LOGFILEPATH "./ldlidar-driver.log"
31 |
32 | #include
33 | #include
34 | #include
35 | #include
36 |
37 | #ifndef LINUX
38 | #include
39 | #else
40 | //#include
41 | #include
42 | #define printf_s(fileptr,str) (fprintf(fileptr,"%s",str))
43 | #define __in
44 | #endif // ??????????????????????
45 |
46 |
47 | struct LogVersion {
48 | int n_version;
49 | std::string str_descruble;
50 | };
51 |
52 |
53 | class ILogRealization {
54 | public:
55 | virtual ~ILogRealization() {
56 |
57 | }
58 | virtual void Initializion(const char* path = NULL) = 0;
59 | virtual void LogPrintInf(const char* str) = 0;
60 | void free() {
61 | free(this);
62 | //this = NULL;
63 | };
64 | private:
65 | virtual void free(ILogRealization *plogger) = 0 ;
66 | };
67 |
68 |
69 | #define ILOGFREE(LogRealizationClass) virtual void free(ILogRealization* plogger) \
70 | { \
71 | LogRealizationClass* prealization = static_cast(plogger); \
72 | if (prealization != NULL){ delete prealization;} \
73 | }
74 |
75 | class LogPrint :public ILogRealization {
76 | public:
77 | virtual void Initializion(const char* path = NULL);
78 | virtual void free(ILogRealization *plogger);
79 | virtual void LogPrintInf(const char* str);
80 | };
81 |
82 | #ifndef LINUX
83 | class LogOutputString :public ILogRealization {
84 | public:
85 | virtual void Initializion(const char* path = NULL) {
86 | return ;
87 | }
88 |
89 | virtual void LogPrintInf(const char* str) {
90 | OutputDebugString((LPCTSTR)str);
91 | OutputDebugString("\r\n");
92 | }
93 |
94 | ILOGFREE(LogOutputString)
95 | /*
96 | virtual void free(ILogRealization *plogger)
97 | {
98 | LogOutputString* poutput = static_cast(plogger);
99 | if (poutput != NULL)
100 | {
101 | delete poutput;
102 | }
103 | }
104 | */
105 | };
106 | #endif
107 |
108 |
109 | class LogModule {
110 | public:
111 | enum LogLevel {
112 | DEBUG_LEVEL,
113 | WARNING_LEVEL,
114 | ERROR_LEVEL,
115 | INFO_LEVEL
116 | };
117 |
118 | struct LOGMODULE_INFO {
119 | LogLevel loglevel;
120 | std::string str_filename;
121 | std::string str_funcname;
122 | int n_linenumber;
123 | }logInfo_;
124 |
125 | ILogRealization* p_realization_;
126 | public:
127 | static LogModule* GetInstance( __in const char* filename, __in const char* funcname,__in int lineno, LogLevel level, ILogRealization*plog = NULL);
128 | static LogModule* GetInstance(LogLevel level, ILogRealization*plog = NULL);
129 |
130 | void LogPrintInf(const char* format,...);
131 | void LogPrintNoLocationInf(const char* format,...);
132 |
133 | private:
134 | LogModule();
135 |
136 | ~LogModule();
137 |
138 | void InitLock();
139 |
140 | void RealseLock();
141 |
142 | void Lock();
143 |
144 | void UnLock();
145 |
146 | std::string GetCurrentTime();
147 |
148 | inline uint64_t GetCurrentLocalTimeStamp() {
149 | //// 获取系统时间戳
150 | std::chrono::time_point tp =
151 | std::chrono::time_point_cast(std::chrono::system_clock::now());
152 | auto tmp = std::chrono::duration_cast(tp.time_since_epoch());
153 | return (uint64_t)tmp.count();
154 | }
155 |
156 | std::string GetFormatValue(std::string str_value);
157 |
158 | std::string GetFormatValue(int n_value);
159 |
160 | std::string GetLevelValue(int level);
161 |
162 | static LogModule* s_plog_module_;
163 |
164 | #ifndef LINUX
165 | CRITICAL_SECTION mutex_lock_;
166 | #else
167 | pthread_mutex_t mutex_lock_;
168 | #endif
169 |
170 |
171 | };
172 |
173 | //// 以下功能支持所处文件、函数、行号信息的打印
174 | #define LOG(level,format,...) LogModule::GetInstance(__FILE__, __FUNCTION__, __LINE__,level)->LogPrintInf(format,__VA_ARGS__);
175 | #ifdef ENABLE_LOG_DIS_OUTPUT
176 | #define LD_LOG_DEBUG(format,...) LOG(LogModule::DEBUG_LEVEL,format,__VA_ARGS__)
177 | #define LD_LOG_INFO(format,...) LOG(LogModule::INFO_LEVEL,format,__VA_ARGS__)
178 | #define LD_LOG_WARN(format,...) LOG(LogModule::WARNING_LEVEL,format,__VA_ARGS__)
179 | #define LD_LOG_ERROR(format,...) LOG(LogModule::ERROR_LEVEL,format,__VA_ARGS__)
180 | #else
181 | #define LD_LOG_DEBUG(format,...) do {} while(0)
182 | #define LD_LOG_INFO(format,...) do {} while(0)
183 | #define LD_LOG_WARN(format,...) do {} while(0)
184 | #define LD_LOG_ERROR(format,...) do {} while(0)
185 | #endif
186 | //// 以下功能不支持所处文件、函数、行号信息的打印
187 | #ifdef ENABLE_LOG_DIS_OUTPUT
188 | #define LOG_NO_DESCRI(level,format,...) LogModule::GetInstance(level)->LogPrintNoLocationInf(format,__VA_ARGS__);
189 | #define LDS_LOG_DEBUG(format,...) LOG_NO_DESCRI(LogModule::DEBUG_LEVEL,format,__VA_ARGS__)
190 | #define LDS_LOG_INFO(format,...) LOG_NO_DESCRI(LogModule::INFO_LEVEL,format,__VA_ARGS__)
191 | #define LDS_LOG_WARN(format,...) LOG_NO_DESCRI(LogModule::WARNING_LEVEL,format,__VA_ARGS__)
192 | #define LDS_LOG_ERROR(format,...) LOG_NO_DESCRI(LogModule::ERROR_LEVEL,format,__VA_ARGS__)
193 | #else
194 | #define LDS_LOG_DEBUG(format,...) do {} while(0)
195 | #define LDS_LOG_INFO(format,...) do {} while(0)
196 | #define LDS_LOG_WARN(format,...) do {} while(0)
197 | #define LDS_LOG_ERROR(format,...) do {} while(0)
198 | #endif
199 |
200 | #endif//__LDLIDAR_LOGGER_H__
201 | /********************* (C) COPYRIGHT SHENZHEN LDROBOT CO., LTD *******END OF FILE ********/
--------------------------------------------------------------------------------
/ldlidar_driver/include/networkcom/network_socket_interface_linux.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file network_socket_interface_linux.h
3 | * @author LDRobot (support@ldrobot.com)
4 | * @brief linux network App
5 | * @version 0.1
6 | * @date 2022-09-05
7 | *
8 | * @copyright Copyright (c) 2022 SHENZHEN LDROBOT CO., LTD. All rights
9 | * reserved.
10 | * Licensed under the MIT License (the "License");
11 | * you may not use this file except in compliance with the License.
12 | * You may obtain a copy of the License in the file LICENSE
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 |
20 | #ifndef __SOCKET_INTERFACE_LINUX_H__
21 | #define __SOCKET_INTERFACE_LINUX_H__
22 |
23 | #include
24 | #include
25 | #include
26 | #include
27 |
28 | #include
29 | #include
30 | #include
31 | #include
32 |
33 | #include
34 | #include
35 | #include
36 |
37 | #include
38 | #include
39 | #include
40 | #include
41 | #include
42 | #include
43 | #include
44 | #include
45 |
46 | namespace ldlidar {
47 |
48 | typedef enum NetworkCommDevEnum {
49 | NET_NULL,
50 | UDP_SERVER,
51 | UDP_CLIENT,
52 | TCP_SERVER,
53 | TCP_CLIENT
54 | }NetCommDevTypeDef;
55 |
56 | class UDPSocketInterfaceLinux {
57 | public:
58 | UDPSocketInterfaceLinux();
59 |
60 | ~UDPSocketInterfaceLinux();
61 |
62 | bool CreateSocket(NetCommDevTypeDef obj, const char *ip, const char *port);
63 |
64 | bool CloseSocket();
65 |
66 | bool TransToNet(uint8_t *tx_buf, uint32_t tx_buff_len, uint32_t *tx_len);
67 |
68 | void SetRecvCallback(std::function callback);
69 |
70 | bool IsClientAck() { return is_server_recv_ack_flag_.load();}
71 |
72 | private:
73 | std::thread *recv_thread_;
74 | long long recv_count_;
75 | int32_t com_sockfd_;
76 | NetCommDevTypeDef ncd_;
77 | std::atomic is_cmd_created_, recv_thread_exit_flag_, is_server_recv_ack_flag_;
78 | std::function recv_callback_;
79 | std::string server_ip_, server_port_;
80 | std::string client_ip_, client_port_;
81 |
82 | bool IsCreated() { return is_cmd_created_.load(); }
83 |
84 | bool RecvFromNet(uint8_t *rx_buf , uint32_t rx_buff_len, uint32_t *rx_len);
85 |
86 | static void RecvThreadProc(void *param);
87 | };
88 |
89 |
90 | class TCPSocketInterfaceLinux {
91 | public:
92 | TCPSocketInterfaceLinux();
93 |
94 | ~TCPSocketInterfaceLinux();
95 |
96 | bool CreateSocket(NetCommDevTypeDef obj, const char *ip, const char *port);
97 |
98 | bool CloseSocket();
99 |
100 | bool TransToNet(uint8_t *tx_buf, uint32_t tx_buff_len, uint32_t *tx_len);
101 |
102 | void SetRecvCallback(std::function callback);
103 |
104 |
105 |
106 | private:
107 | std::thread *recv_thread_;
108 | long long recv_count_;
109 | int32_t com_sockfd_;
110 | int32_t listend_client_sockfd_; //// server model used
111 | NetCommDevTypeDef ncd_;
112 | std::atomic is_cmd_created_, recv_thread_exit_flag_;
113 | std::function recv_callback_;
114 |
115 | bool IsCreated() { return is_cmd_created_.load(); }
116 |
117 | bool RecvFromNet(uint8_t *rx_buf , uint32_t rx_buff_len, uint32_t *rx_len);
118 |
119 | static void RecvThreadProc(void *param);
120 | };
121 |
122 | } // namespace ldlidar
123 | #endif // __SOCKET_INTERFACE_LINUX_H__
124 | /********************* (C) COPYRIGHT SHENZHEN LDROBOT CO., LTD *******END OF
125 | * FILE ********/
--------------------------------------------------------------------------------
/ldlidar_driver/include/serialcom/serial_interface_linux.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file cmd_interface_linux.h
3 | * @author LDRobot (support@ldrobot.com)
4 | * @brief linux serial port App
5 | * @version 0.1
6 | * @date 2021-10-28
7 | *
8 | * @copyright Copyright (c) 2021 SHENZHEN LDROBOT CO., LTD. All rights
9 | * reserved.
10 | * Licensed under the MIT License (the "License");
11 | * you may not use this file except in compliance with the License.
12 | * You may obtain a copy of the License in the file LICENSE
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 |
20 | #ifndef __LINUX_SERIAL_PORT_H__
21 | #define __LINUX_SERIAL_PORT_H__
22 |
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | namespace asmtermios {
31 | #include
32 | }
33 | #include
34 | #include
35 |
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include
41 | #include
42 | #include
43 | #include
44 |
45 | namespace ldlidar {
46 |
47 | class SerialInterfaceLinux {
48 | public:
49 | SerialInterfaceLinux();
50 | ~SerialInterfaceLinux();
51 | // open serial port
52 | bool Open(std::string &port_name, uint32_t com_baudrate);
53 | // close serial port
54 | bool Close();
55 | // receive from port channel data
56 | bool ReadFromIO(uint8_t *rx_buf, uint32_t rx_buf_len, uint32_t *rx_len);
57 | // transmit data to port channel
58 | bool WriteToIo(const uint8_t *tx_buf, uint32_t tx_buf_len, uint32_t *tx_len);
59 | // set receive port channel data callback deal with fuction
60 | void SetReadCallback(std::function callback) {
61 | read_callback_ = callback;
62 | }
63 | // whether open
64 | bool IsOpened() { return is_cmd_opened_.load(); };
65 |
66 | private:
67 | std::thread *rx_thread_;
68 | long long rx_count_;
69 | int32_t com_handle_;
70 | uint32_t com_baudrate_;
71 | std::atomic is_cmd_opened_, rx_thread_exit_flag_;
72 | std::function read_callback_;
73 | static void RxThreadProc(void *param);
74 | };
75 |
76 | } // namespace ldlidar
77 |
78 | #endif //__LINUX_SERIAL_PORT_H__
79 |
80 | /********************* (C) COPYRIGHT SHENZHEN LDROBOT CO., LTD *******END OF
81 | * FILE ********/
--------------------------------------------------------------------------------
/ldlidar_driver/src/core/ldlidar_driver.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file ldlidar_driver.cpp
3 | * @author LDRobot (support@ldrobot.com)
4 | * @brief ldlidar processing App
5 | * This code is only applicable to LDROBOT LiDAR LD14
6 | * products sold by Shenzhen LDROBOT Co., LTD
7 | * @version 0.1
8 | * @date 2021-05-12
9 | *
10 | * @copyright Copyright (c) 2022 SHENZHEN LDROBOT CO., LTD. All rights
11 | * reserved.
12 | * Licensed under the MIT License (the "License");
13 | * you may not use this file except in compliance with the License.
14 | * You may obtain a copy of the License in the file LICENSE
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | */
21 | #include "ldlidar_driver.h"
22 |
23 | namespace ldlidar {
24 |
25 | bool LDLidarDriver::is_ok_ = false;
26 |
27 | LDLidarDriver::LDLidarDriver()
28 | : sdk_version_number_("v3.0.3"),
29 | is_start_flag_(false),
30 | register_get_timestamp_handle_(nullptr),
31 | comm_pkg_(new LiPkg()),
32 | comm_serial_(new SerialInterfaceLinux()),
33 | comm_tcp_network_(new TCPSocketInterfaceLinux()),
34 | comm_udp_network_(new UDPSocketInterfaceLinux()) {
35 | last_pubdata_times_ = std::chrono::steady_clock::now();
36 | }
37 |
38 | LDLidarDriver::~LDLidarDriver() {
39 | if (comm_pkg_ != nullptr) {
40 | delete comm_pkg_;
41 | }
42 |
43 | if (comm_serial_ != nullptr) {
44 | delete comm_serial_;
45 | }
46 |
47 | if (comm_tcp_network_ != nullptr) {
48 | delete comm_tcp_network_;
49 | }
50 |
51 | if (comm_udp_network_ != nullptr) {
52 | delete comm_udp_network_;
53 | }
54 | }
55 |
56 | std::string LDLidarDriver::GetLidarSdkVersionNumber(void) {
57 | return sdk_version_number_;
58 | }
59 |
60 | bool LDLidarDriver::Start(LDType product_name,
61 | std::string serial_port_name,
62 | uint32_t serial_baudrate,
63 | CommunicationModeTypeDef comm_mode) {
64 | if (is_start_flag_) {
65 | return true;
66 | }
67 |
68 | if (LDType::NO_VERSION == product_name) {
69 | LD_LOG_ERROR("input is abnormal.","");
70 | return false;
71 | }
72 |
73 | if (serial_port_name.empty() || (0 == serial_baudrate)) {
74 | LD_LOG_ERROR("input serial param error.","");
75 | return false;
76 | }
77 |
78 | if (register_get_timestamp_handle_ == nullptr) {
79 | LD_LOG_ERROR("get timestamp fuctional is not register.","");
80 | return false;
81 | }
82 |
83 | comm_pkg_->ClearDataProcessStatus();
84 | comm_pkg_->RegisterTimestampGetFunctional(register_get_timestamp_handle_);
85 | comm_pkg_->SetProductType(product_name);
86 |
87 | if (COMM_SERIAL_MODE == comm_mode) {
88 | comm_serial_->SetReadCallback(std::bind(&LiPkg::CommReadCallback, comm_pkg_, std::placeholders::_1, std::placeholders::_2));
89 | if (!(comm_serial_->Open(serial_port_name, serial_baudrate))) {
90 | LD_LOG_ERROR("serial is not open:%s", serial_port_name.c_str());
91 | return false;
92 | }
93 | } else {
94 | LD_LOG_ERROR("input value is not \"ldlidar::COMM_SERIAL_MODE\"","");
95 | return false;
96 | }
97 |
98 | is_start_flag_ = true;
99 |
100 | SetIsOkStatus(true);
101 |
102 | return true;
103 | }
104 |
105 | bool LDLidarDriver::Start(LDType product_name,
106 | const char* server_ip,
107 | const char* server_port,
108 | CommunicationModeTypeDef comm_mode) {
109 |
110 | if (is_start_flag_) {
111 | return true;
112 | }
113 |
114 | if (LDType::NO_VERSION == product_name) {
115 | LD_LOG_ERROR("input is abnormal.","");
116 | return false;
117 | }
118 |
119 | if ((server_ip == nullptr) || (server_port == nullptr)) {
120 | LD_LOG_ERROR("input server_ip or server_port is null","");
121 | return false;
122 | }
123 |
124 | if ((COMM_NO_NULL == comm_mode) || (COMM_SERIAL_MODE == comm_mode)) {
125 | LDS_LOG_ERROR("input comm_mode param is error.","");
126 | return false;
127 | }
128 |
129 | if (register_get_timestamp_handle_ == nullptr) {
130 | LD_LOG_ERROR("get timestamp fuctional is not register.","");
131 | return false;
132 | }
133 |
134 | comm_pkg_->ClearDataProcessStatus();
135 | comm_pkg_->RegisterTimestampGetFunctional(register_get_timestamp_handle_);
136 | comm_pkg_->SetProductType(product_name);
137 |
138 | switch (comm_mode) {
139 | case COMM_TCP_CLIENT_MODE: {
140 | comm_tcp_network_->SetRecvCallback(std::bind(&LiPkg::CommReadCallback, comm_pkg_, std::placeholders::_1, std::placeholders::_2));
141 | bool result = comm_tcp_network_->CreateSocket(TCP_CLIENT, server_ip, server_port);
142 | if (!result) {
143 | LD_LOG_ERROR("client host: create socket is fail.","");
144 | return false;
145 | }
146 | LDS_LOG_INFO("client host: create socket is ok.","");
147 | }
148 | break;
149 | case COMM_TCP_SERVER_MODE: {
150 | comm_tcp_network_->SetRecvCallback(std::bind(&LiPkg::CommReadCallback, comm_pkg_, std::placeholders::_1, std::placeholders::_2));
151 | bool result = comm_tcp_network_->CreateSocket(TCP_SERVER, server_ip, server_port);
152 | if (!result) {
153 | LD_LOG_ERROR("server host: create socket is fail.","");
154 | return false;
155 | }
156 | LDS_LOG_INFO("server host: create socket is ok.","");
157 | }
158 | break;
159 | case COMM_UDP_CLIENT_MODE: {
160 | comm_udp_network_->SetRecvCallback(std::bind(&LiPkg::CommReadCallback, comm_pkg_, std::placeholders::_1, std::placeholders::_2));
161 | bool result = comm_udp_network_->CreateSocket(UDP_CLIENT, server_ip, server_port);
162 | if (!result) {
163 | LD_LOG_ERROR("client host: create socket is fail.","");
164 | return false;
165 | }
166 | // 主动向服务端发布消息使服务端保存客户端ip,port 信息,建立沟通渠道
167 | uint8_t trans_buf[4] = {0xa5, 0x5a, 0x00, 0x00};
168 | uint32_t tx_len;
169 | if (!comm_udp_network_->TransToNet((uint8_t *)trans_buf, sizeof(trans_buf), &tx_len)) {
170 | LD_LOG_ERROR("client host: send request to server is fail. %s", strerror(errno));
171 | return false;
172 | }
173 | LDS_LOG_INFO("client host: create socket is ok.","");
174 | }
175 | break;
176 | case COMM_UDP_SERVER_MODE: {
177 | comm_udp_network_->SetRecvCallback(std::bind(&LiPkg::CommReadCallback, comm_pkg_, std::placeholders::_1, std::placeholders::_2));
178 | bool result = comm_udp_network_->CreateSocket(UDP_SERVER, server_ip, server_port);
179 | if (!result) {
180 | LD_LOG_ERROR("server host: create socket is fail.","");
181 | return false;
182 | }
183 | LDS_LOG_INFO("server host: create socket is ok.","");
184 | LDS_LOG_INFO("server host: wait client ack connect..","");
185 | while (!comm_udp_network_->IsClientAck()) {
186 | usleep(1000);
187 | }
188 | }
189 | break;
190 | default: {
191 | LDS_LOG_ERROR("input comm_mode param is error.","");
192 | return false;
193 | }
194 | break;
195 | }
196 |
197 | is_start_flag_ = true;
198 |
199 | SetIsOkStatus(true);
200 |
201 | return true;
202 | }
203 |
204 | bool LDLidarDriver::Stop(void) {
205 | if (!is_start_flag_) {
206 | return true;
207 | }
208 |
209 | comm_serial_->Close();
210 | comm_tcp_network_->CloseSocket();
211 | comm_udp_network_->CloseSocket();
212 |
213 | is_start_flag_ = false;
214 |
215 | SetIsOkStatus(false);
216 |
217 | return true;
218 | }
219 |
220 | bool LDLidarDriver::WaitLidarCommConnect(int64_t timeout) {
221 | auto last_time = std::chrono::steady_clock::now();
222 |
223 | bool is_recvflag = false;
224 | do {
225 | if (comm_pkg_->GetLidarPowerOnCommStatus()) {
226 | is_recvflag = true;
227 | }
228 | usleep(1000);
229 | } while (!is_recvflag && (std::chrono::duration_cast(
230 | std::chrono::steady_clock::now() - last_time).count() < timeout));
231 |
232 | if (is_recvflag) {
233 | last_pubdata_times_ = std::chrono::steady_clock::now();
234 | return true;
235 | } else {
236 | return false;
237 | }
238 | }
239 |
240 | LidarStatus LDLidarDriver::GetLaserScanData(Points2D& dst, int64_t timeout) {
241 | if (!is_start_flag_) {
242 | return LidarStatus::STOP;
243 | }
244 |
245 | LidarStatus status = comm_pkg_->GetLidarStatus();
246 | if (LidarStatus::NORMAL == status) {
247 | if (comm_pkg_->GetLaserScanData(dst)) {
248 | last_pubdata_times_ = std::chrono::steady_clock::now();
249 | return LidarStatus::NORMAL;
250 | }
251 |
252 | if (std::chrono::duration_cast(std::chrono::steady_clock::now() - last_pubdata_times_).count() > timeout) {
253 | return LidarStatus::DATA_TIME_OUT;
254 | } else {
255 | return LidarStatus::DATA_WAIT;
256 | }
257 | } else {
258 | last_pubdata_times_ = std::chrono::steady_clock::now();
259 | return status;
260 | }
261 | }
262 |
263 | LidarStatus LDLidarDriver::GetLaserScanData(LaserScan& dst, int64_t timeout) {
264 | if (!is_start_flag_) {
265 | return LidarStatus::STOP;
266 | }
267 |
268 | LidarStatus status = comm_pkg_->GetLidarStatus();
269 | if (LidarStatus::NORMAL == status) {
270 | Points2D recvpcd;
271 | if (comm_pkg_->GetLaserScanData(recvpcd)) {
272 | last_pubdata_times_ = std::chrono::steady_clock::now();
273 | dst.stamp = recvpcd.front().stamp;
274 | dst.points = recvpcd;
275 | return LidarStatus::NORMAL;
276 | }
277 |
278 | if (std::chrono::duration_cast(std::chrono::steady_clock::now() - last_pubdata_times_).count() > timeout) {
279 | return LidarStatus::DATA_TIME_OUT;
280 | } else {
281 | return LidarStatus::DATA_WAIT;
282 | }
283 | } else {
284 | last_pubdata_times_ = std::chrono::steady_clock::now();
285 | return status;
286 | }
287 | }
288 |
289 | bool LDLidarDriver::GetLidarScanFreq(double& spin_hz) {
290 | if (!is_start_flag_) {
291 | return false;
292 | }
293 | spin_hz = comm_pkg_->GetSpeed();
294 |
295 | return true;
296 | }
297 |
298 | void LDLidarDriver::RegisterGetTimestampFunctional(std::function get_timestamp_handle) {
299 | register_get_timestamp_handle_ = get_timestamp_handle;
300 | }
301 |
302 | void LDLidarDriver::EnableFilterAlgorithnmProcess(bool is_enable) {
303 | comm_pkg_->EnableFilter(is_enable);
304 | }
305 |
306 | // uint8_t LDLidarDriver::GetLidarErrorCode(void) {
307 | // if (!is_start_flag_) {
308 | // return 0x00;
309 | // }
310 | // uint8_t errcode = comm_pkg_->GetLidarErrorCode();
311 | // return errcode;
312 | // }
313 |
314 | } // namespace ldlidar
315 | /********************* (C) COPYRIGHT SHENZHEN LDROBOT CO., LTD *******END OF
316 | * FILE ********/
--------------------------------------------------------------------------------
/ldlidar_driver/src/dataprocess/lipkg.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file lipkg.cpp
3 | * @author LDRobot (support@ldrobot.com)
4 | * @brief LiDAR data protocol processing App
5 | * This code is only applicable to LDROBOT LiDAR LD06 products
6 | * sold by Shenzhen LDROBOT Co., LTD
7 | * @version 0.1
8 | * @date 2021-10-28
9 | *
10 | * @copyright Copyright (c) 2021 SHENZHEN LDROBOT CO., LTD. All rights
11 | * reserved.
12 | * Licensed under the MIT License (the "License");
13 | * you may not use this file except in compliance with the License.
14 | * You may obtain a copy of the License in the file LICENSE
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | */
21 |
22 | #include "lipkg.h"
23 |
24 | namespace ldlidar {
25 |
26 | static const uint8_t CrcTable[256] = {
27 | 0x00, 0x4d, 0x9a, 0xd7, 0x79, 0x34, 0xe3, 0xae, 0xf2, 0xbf, 0x68, 0x25,
28 | 0x8b, 0xc6, 0x11, 0x5c, 0xa9, 0xe4, 0x33, 0x7e, 0xd0, 0x9d, 0x4a, 0x07,
29 | 0x5b, 0x16, 0xc1, 0x8c, 0x22, 0x6f, 0xb8, 0xf5, 0x1f, 0x52, 0x85, 0xc8,
30 | 0x66, 0x2b, 0xfc, 0xb1, 0xed, 0xa0, 0x77, 0x3a, 0x94, 0xd9, 0x0e, 0x43,
31 | 0xb6, 0xfb, 0x2c, 0x61, 0xcf, 0x82, 0x55, 0x18, 0x44, 0x09, 0xde, 0x93,
32 | 0x3d, 0x70, 0xa7, 0xea, 0x3e, 0x73, 0xa4, 0xe9, 0x47, 0x0a, 0xdd, 0x90,
33 | 0xcc, 0x81, 0x56, 0x1b, 0xb5, 0xf8, 0x2f, 0x62, 0x97, 0xda, 0x0d, 0x40,
34 | 0xee, 0xa3, 0x74, 0x39, 0x65, 0x28, 0xff, 0xb2, 0x1c, 0x51, 0x86, 0xcb,
35 | 0x21, 0x6c, 0xbb, 0xf6, 0x58, 0x15, 0xc2, 0x8f, 0xd3, 0x9e, 0x49, 0x04,
36 | 0xaa, 0xe7, 0x30, 0x7d, 0x88, 0xc5, 0x12, 0x5f, 0xf1, 0xbc, 0x6b, 0x26,
37 | 0x7a, 0x37, 0xe0, 0xad, 0x03, 0x4e, 0x99, 0xd4, 0x7c, 0x31, 0xe6, 0xab,
38 | 0x05, 0x48, 0x9f, 0xd2, 0x8e, 0xc3, 0x14, 0x59, 0xf7, 0xba, 0x6d, 0x20,
39 | 0xd5, 0x98, 0x4f, 0x02, 0xac, 0xe1, 0x36, 0x7b, 0x27, 0x6a, 0xbd, 0xf0,
40 | 0x5e, 0x13, 0xc4, 0x89, 0x63, 0x2e, 0xf9, 0xb4, 0x1a, 0x57, 0x80, 0xcd,
41 | 0x91, 0xdc, 0x0b, 0x46, 0xe8, 0xa5, 0x72, 0x3f, 0xca, 0x87, 0x50, 0x1d,
42 | 0xb3, 0xfe, 0x29, 0x64, 0x38, 0x75, 0xa2, 0xef, 0x41, 0x0c, 0xdb, 0x96,
43 | 0x42, 0x0f, 0xd8, 0x95, 0x3b, 0x76, 0xa1, 0xec, 0xb0, 0xfd, 0x2a, 0x67,
44 | 0xc9, 0x84, 0x53, 0x1e, 0xeb, 0xa6, 0x71, 0x3c, 0x92, 0xdf, 0x08, 0x45,
45 | 0x19, 0x54, 0x83, 0xce, 0x60, 0x2d, 0xfa, 0xb7, 0x5d, 0x10, 0xc7, 0x8a,
46 | 0x24, 0x69, 0xbe, 0xf3, 0xaf, 0xe2, 0x35, 0x78, 0xd6, 0x9b, 0x4c, 0x01,
47 | 0xf4, 0xb9, 0x6e, 0x23, 0x8d, 0xc0, 0x17, 0x5a, 0x06, 0x4b, 0x9c, 0xd1,
48 | 0x7f, 0x32, 0xe5, 0xa8};
49 |
50 | uint8_t CalCRC8(const uint8_t *data, uint16_t data_len) {
51 | uint8_t crc = 0;
52 | while (data_len--) {
53 | crc = CrcTable[(crc ^ *data) & 0xff];
54 | data++;
55 | }
56 | return crc;
57 | }
58 |
59 | LiPkg::LiPkg()
60 | : product_type_(LDType::NO_VERSION),
61 | timestamp_(0),
62 | speed_(0),
63 | is_frame_ready_(false),
64 | is_poweron_comm_normal_(false),
65 | is_filter_(true),
66 | lidarstatus_(LidarStatus::NORMAL),
67 | measure_point_frequence_(4500),
68 | get_timestamp_(nullptr),
69 | last_pkg_timestamp_(0),
70 | first_frame_(true) {
71 |
72 | }
73 |
74 | LiPkg::~LiPkg() {
75 |
76 | }
77 |
78 | void LiPkg::SetProductType(LDType type_number) {
79 | product_type_ = type_number;
80 | switch (type_number) {
81 | case LDType::LD_06:
82 | case LDType::LD_19:
83 | measure_point_frequence_ = 4500;
84 | break;
85 | case LDType::STL_06P:
86 | case LDType::STL_26:
87 | measure_point_frequence_ = 5000;
88 | break;
89 | case LDType::STL_27L:
90 | measure_point_frequence_ = 21600;
91 | break;
92 | default :
93 | measure_point_frequence_ = 4500;
94 | break;
95 | }
96 | }
97 |
98 | bool LiPkg::AnalysisOne(uint8_t byte) {
99 | static enum {
100 | HEADER,
101 | VER_LEN,
102 | DATA,
103 | } state = HEADER;
104 | static uint16_t count = 0;
105 | static uint8_t tmp[128] = {0};
106 | static uint16_t pkg_count = sizeof(LiDARFrameTypeDef);
107 |
108 | switch (state) {
109 | case HEADER:
110 | if (byte == PKG_HEADER) {
111 | tmp[count++] = byte;
112 | state = VER_LEN;
113 | }
114 | break;
115 | case VER_LEN:
116 | if (byte == PKG_VER_LEN) {
117 | tmp[count++] = byte;
118 | state = DATA;
119 | } else {
120 | state = HEADER;
121 | count = 0;
122 | return false;
123 | }
124 | break;
125 | case DATA:
126 | tmp[count++] = byte;
127 | if (count >= pkg_count) {
128 | memcpy((uint8_t *)&pkg_, tmp, pkg_count);
129 | uint8_t crc = CalCRC8((uint8_t *)&pkg_, pkg_count - 1);
130 | state = HEADER;
131 | count = 0;
132 | if (crc == pkg_.crc8) {
133 | return true;
134 | } else {
135 | return false;
136 | }
137 | }
138 | break;
139 | default:
140 | break;
141 | }
142 |
143 | return false;
144 | }
145 |
146 | bool LiPkg::Parse(const uint8_t *data, long len) {
147 | for (int i = 0; i < len; i++) {
148 | if (AnalysisOne(data[i])) {
149 | is_poweron_comm_normal_ = true;
150 | // parse a package is success
151 | double diff = (pkg_.end_angle / 100 - pkg_.start_angle / 100 + 360) % 360;
152 | if (diff <= ((double)pkg_.speed * POINT_PER_PACK / measure_point_frequence_ * 1.5)) {
153 |
154 | if (0 == last_pkg_timestamp_) {
155 | last_pkg_timestamp_ = get_timestamp_();
156 | continue;
157 | }
158 | uint64_t current_pack_stamp = get_timestamp_();
159 | int pkg_point_number = POINT_PER_PACK;
160 | double pack_stamp_point_step =
161 | static_cast(current_pack_stamp - last_pkg_timestamp_) / static_cast(pkg_point_number - 1);
162 |
163 | speed_ = pkg_.speed; // Degrees per second
164 | timestamp_ = pkg_.timestamp; // In milliseconds
165 | uint32_t diff = ((uint32_t)pkg_.end_angle + 36000 - (uint32_t)pkg_.start_angle) % 36000;
166 | float step = diff / (POINT_PER_PACK - 1) / 100.0;
167 | float start = (double)pkg_.start_angle / 100.0;
168 | PointData data;
169 | for (int i = 0; i < POINT_PER_PACK; i++) {
170 | data.distance = pkg_.point[i].distance;
171 | data.angle = start + i * step;
172 | if (data.angle >= 360.0) {
173 | data.angle -= 360.0;
174 | }
175 | data.intensity = pkg_.point[i].intensity;
176 | data.stamp = static_cast(last_pkg_timestamp_ + (pack_stamp_point_step * i));
177 | frame_tmp_.push_back(PointData(data.angle, data.distance, data.intensity, data.stamp));
178 | }
179 |
180 | last_pkg_timestamp_ = current_pack_stamp; //// update last pkg timestamp
181 | }
182 | }
183 | }
184 |
185 | return true;
186 | }
187 |
188 | bool LiPkg::AssemblePacket() {
189 | float last_angle = 0;
190 | Points2D tmp, data;
191 | int count = 0;
192 |
193 | for (auto n : frame_tmp_) {
194 | // wait for enough data, need enough data to show a circle
195 | // enough data has been obtained
196 | if ((n.angle < 20.0) && (last_angle > 340.0)) {
197 | if ((count * GetSpeed()) > (measure_point_frequence_ * 1.4)) {
198 | if (count >= (int)frame_tmp_.size()) {
199 | frame_tmp_.clear();
200 | } else {
201 | frame_tmp_.erase(frame_tmp_.begin(), frame_tmp_.begin() + count);
202 | }
203 | return false;
204 | }
205 |
206 | data.insert(data.begin(), frame_tmp_.begin(), frame_tmp_.begin() + count);
207 |
208 | if (is_filter_) {
209 | Tofbf tofbfLd(speed_, product_type_);
210 | tmp = tofbfLd.Filter(data);
211 | } else {
212 | tmp = data;
213 | }
214 |
215 | std::sort(tmp.begin(), tmp.end(), [](PointData a, PointData b) { return a.stamp < b.stamp; });
216 |
217 | if (tmp.size() > 0) {
218 | if (first_frame_) {
219 | first_frame_ = false;
220 | } else {
221 | SetLaserScanData(tmp);
222 | SetFrameReady();
223 | }
224 |
225 | if (count >= (int)frame_tmp_.size()) {
226 | frame_tmp_.clear();
227 | } else {
228 | frame_tmp_.erase(frame_tmp_.begin(), frame_tmp_.begin() + count);
229 | }
230 | return true;
231 | }
232 | }
233 | count++;
234 |
235 | if ((count * GetSpeed()) > (measure_point_frequence_ * 2)) {
236 | if (count >= (int)frame_tmp_.size()) {
237 | frame_tmp_.clear();
238 | } else {
239 | frame_tmp_.erase(frame_tmp_.begin(), frame_tmp_.begin() + count);
240 | }
241 | return false;
242 | }
243 |
244 | last_angle = n.angle;
245 | }
246 |
247 | return false;
248 | }
249 |
250 | double LiPkg::GetSpeed(void) {
251 | return (speed_ / 360.0); // unit is hz
252 | }
253 |
254 | uint16_t LiPkg::GetSpeedOrigin(void) {
255 | return speed_;
256 | }
257 |
258 | uint16_t LiPkg::GetTimestamp(void) {
259 | return timestamp_;
260 | }
261 |
262 | int LiPkg::GetLidarMeasurePointFrequence(void) {
263 | return measure_point_frequence_;
264 | }
265 |
266 | bool LiPkg::IsFrameReady(void) {
267 | std::lock_guard lg(mutex_lock1_);
268 | return is_frame_ready_;
269 | }
270 |
271 | void LiPkg::ResetFrameReady(void) {
272 | std::lock_guard lg(mutex_lock1_);
273 | is_frame_ready_ = false;
274 | }
275 |
276 | void LiPkg::SetFrameReady(void) {
277 | std::lock_guard lg(mutex_lock1_);
278 | is_frame_ready_ = true;
279 | }
280 |
281 | bool LiPkg::GetLaserScanData(Points2D& out) {
282 | if (IsFrameReady()) {
283 | ResetFrameReady();
284 | {
285 | std::lock_guard lg(mutex_lock2_);
286 | out = laser_scan_data_;
287 | }
288 | return true;
289 | } else {
290 | return false;
291 | }
292 | }
293 |
294 | void LiPkg::SetLaserScanData(Points2D& src) {
295 | std::lock_guard lg(mutex_lock2_);
296 | laser_scan_data_ = src;
297 | }
298 |
299 | void LiPkg::RegisterTimestampGetFunctional(std::function timestamp_handle) {
300 | get_timestamp_ = timestamp_handle;
301 | }
302 |
303 | bool LiPkg::GetLidarPowerOnCommStatus(void) {
304 | if (is_poweron_comm_normal_) {
305 | is_poweron_comm_normal_ = false;
306 | return true;
307 | } else {
308 | return false;
309 | }
310 | }
311 |
312 | void LiPkg::EnableFilter(bool is_enable) {
313 | is_filter_ = is_enable;
314 | }
315 |
316 | LidarStatus LiPkg::GetLidarStatus(void) {
317 | return lidarstatus_;
318 | }
319 |
320 | void LiPkg::CommReadCallback(const char *byte, size_t len) {
321 | if (this->Parse((uint8_t *)byte, len)) {
322 | this->AssemblePacket();
323 | }
324 | }
325 |
326 | } // namespace ldlidar
327 | /********************* (C) COPYRIGHT SHENZHEN LDROBOT CO., LTD *******END OF
328 | * FILE ********/
--------------------------------------------------------------------------------
/ldlidar_driver/src/filter/tofbf.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file tofbf.cpp
3 | * @author LDRobot (support@ldrobot.com)
4 | * @brief LiDAR near-range filtering algorithm
5 | * This code is only applicable to LDROBOT LiDAR LD06 products
6 | * sold by Shenzhen LDROBOT Co., LTD
7 | * @version 0.1
8 | * @date 2021-10-28
9 | *
10 | * @copyright Copyright (c) 2021 SHENZHEN LDROBOT CO., LTD. All rights
11 | * reserved.
12 | * Licensed under the MIT License (the "License");
13 | * you may not use this file except in compliance with the License.
14 | * You may obtain a copy of the License in the file LICENSE
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | */
21 |
22 | #include "tofbf.h"
23 |
24 | namespace ldlidar {
25 |
26 | /**
27 | * @brief Construct a new Tofbf:: Tofbf object
28 | * @param [in]
29 | * @param speed current lidar speed
30 | */
31 | Tofbf::Tofbf(int speed, LDType type) {
32 | curr_speed_ = speed; // ldliar spin speed, unit is Degrees per second
33 | switch (type)
34 | {
35 | case LDType::LD_06:
36 | case LDType::LD_19:
37 | intensity_low_ = 15;
38 | intensity_single_ = 220;
39 | scan_frequency_ = 4500;
40 | filter_type_ = FilterType::NEAR_FILTER;
41 | break;
42 | case LDType::STL_06P:
43 | case LDType::STL_26:
44 | case LDType::STL_27L:
45 | filter_type_ = FilterType::NOISE_FILTER;
46 | break;
47 | default:
48 | std::cout << "[ldrobot] tofbf input ldlidar type error!" << std::endl;
49 | filter_type_ = FilterType::NO_FILTER;
50 | break;
51 | }
52 | }
53 |
54 | Tofbf::~Tofbf() {}
55 |
56 | /**
57 | * @brief The tof lidar filter
58 | * @param [in]
59 | * @param tmp lidar point data
60 | * @return std::vector
61 | */
62 | std::vector Tofbf::Filter(
63 | const std::vector &tmp) const {
64 | std::vector normal;
65 |
66 | switch(filter_type_){
67 | case FilterType::NEAR_FILTER:
68 | normal = NearFilter(tmp);
69 | break;
70 |
71 | case FilterType::NOISE_FILTER:
72 | normal = NoiseFilter(tmp);
73 | break;
74 |
75 | default:
76 | normal = tmp;
77 | break;
78 | }
79 |
80 | return normal;
81 | }
82 |
83 | std::vector Tofbf::NearFilter(
84 | const std::vector &tmp) const {
85 | std::vector normal, pending, item;
86 | std::vector> group;
87 |
88 | // Remove points within 5m
89 | for (auto n : tmp) {
90 | if (n.distance < 5000) {
91 | pending.push_back(n);
92 | } else {
93 | normal.push_back(n);
94 | }
95 | }
96 |
97 | if (tmp.empty()) return normal;
98 |
99 | double angle_delta_up_limit = curr_speed_ / scan_frequency_ * 2;
100 |
101 | // sort
102 | std::sort(pending.begin(), pending.end(),
103 | [](PointData a, PointData b) { return a.angle < b.angle; });
104 |
105 | PointData last(-10, 0, 0);
106 | // group
107 | for (auto n : pending) {
108 | if (fabs(n.angle - last.angle) > angle_delta_up_limit ||
109 | fabs(n.distance - last.distance) > last.distance * 0.03) {
110 | if (item.empty() == false) {
111 | group.push_back(item);
112 | item.clear();
113 | }
114 | }
115 | item.push_back(n);
116 | last = n;
117 | }
118 | // push back last item
119 | if (item.empty() == false) group.push_back(item);
120 |
121 | if (group.empty()) return normal;
122 |
123 | // Connection 0 degree and 359 degree
124 | auto first_item = group.front().front();
125 | auto last_item = group.back().back();
126 | if (fabs(first_item.angle + 360.f - last_item.angle) < angle_delta_up_limit &&
127 | fabs(first_item.distance - last_item.distance) < last.distance * 0.03) {
128 | group.front().insert(group.front().begin(), group.back().begin(), group.back().end());
129 | group.erase(group.end() - 1);
130 | }
131 | // selection
132 | for (auto n : group) {
133 | if (n.size() == 0) continue;
134 | // No filtering if there are many points
135 | if (n.size() > 15) {
136 | normal.insert(normal.end(), n.begin(), n.end());
137 | continue;
138 | }
139 |
140 | // Filter out those with few points
141 | if (n.size() < 3) {
142 | int c = 0;
143 | for (auto m : n) {
144 | c += m.intensity;
145 | }
146 | c /= n.size();
147 | if (c < intensity_single_) {
148 | for (auto& point: n) {
149 | point.distance = 0;
150 | point.intensity = 0;
151 | }
152 | normal.insert(normal.end(), n.begin(), n.end());
153 | continue;
154 | }
155 | }
156 |
157 | // Calculate the mean value of distance and intensity
158 | double intensity_avg = 0;
159 | double dis_avg = 0;
160 | for (auto m : n) {
161 | intensity_avg += m.intensity;
162 | dis_avg += m.distance;
163 | }
164 | intensity_avg /= n.size();
165 | dis_avg /= n.size();
166 |
167 | // High intensity, no filtering
168 | if (intensity_avg > intensity_low_) {
169 | normal.insert(normal.end(), n.begin(), n.end());
170 | continue;
171 | } else {
172 | for (auto& point : n) {
173 | point.distance = 0;
174 | point.intensity = 0;
175 | }
176 | normal.insert(normal.end(), n.begin(), n.end());
177 | continue;
178 | }
179 | }
180 |
181 | return normal;
182 | }
183 |
184 | std::vector Tofbf::NoiseFilter(
185 | const std::vector &tmp) const {
186 | std::vector normal;
187 | PointData last_data, next_data;
188 |
189 | if (tmp.empty()) return normal;
190 |
191 | // Traversing the point data
192 | int count = 0;
193 | for (auto n : tmp) {
194 | if(count == 0) {
195 | last_data = tmp[tmp.size() - 1];
196 | } else {
197 | last_data = tmp[count - 1];
198 | }
199 |
200 | if(count == (int)(tmp.size() - 1)) {
201 | next_data = tmp[0];
202 | } else {
203 | next_data =tmp[count + 1];
204 | }
205 | count++;
206 |
207 | // Remove points with the opposite trend within 500mm
208 | if(n.distance < 500) {
209 | if((n.distance + 10 < last_data.distance && n.distance + 10 < next_data.distance)
210 | || (n.distance > last_data.distance + 10 && n.distance > next_data.distance + 10)) {
211 | if(n.intensity < 60) {
212 | n.intensity = 0;
213 | n.distance = 0;
214 | normal.push_back(n);
215 | continue;
216 | }
217 | } else if((n.distance + 7 < last_data.distance && n.distance + 7 < next_data.distance)
218 | || (n.distance > last_data.distance + 7 && n.distance > next_data.distance + 7)) {
219 | if(n.intensity < 45) {
220 | n.intensity = 0;
221 | n.distance = 0;
222 | normal.push_back(n);
223 | continue;
224 | }
225 | } else if((n.distance + 5 < last_data.distance && n.distance + 5 < next_data.distance)
226 | || (n.distance > last_data.distance + 5 && n.distance > next_data.distance + 5)) {
227 | if(n.intensity < 30) {
228 | n.intensity = 0;
229 | n.distance = 0;
230 | normal.push_back(n);
231 | continue;
232 | }
233 | }
234 | }
235 |
236 | // Remove points with very low intensity within 5m
237 | if (n.distance < 5000) {
238 | if(n.distance < 200) {
239 | if(n.intensity < 25) {
240 | n.intensity = 0;
241 | n.distance = 0;
242 | normal.push_back(n);
243 | continue;
244 | }
245 | } else {
246 | if(n.intensity < 10) {
247 | n.intensity = 0;
248 | n.distance = 0;
249 | normal.push_back(n);
250 | continue;
251 | }
252 | }
253 |
254 | if((n.distance + 30 < last_data.distance || n.distance > last_data.distance + 30)
255 | &&(n.distance + 30 < next_data.distance || n.distance > next_data.distance + 30)) {
256 | if((n.distance < 2000 && n.intensity < 30) || n.intensity < 20) {
257 | n.intensity = 0;
258 | n.distance = 0;
259 | normal.push_back(n);
260 | continue;
261 | }
262 | }
263 | }
264 | normal.push_back(n);
265 | }
266 | return normal;
267 | }
268 |
269 | } // namespace ldlidar
270 |
271 | /********************* (C) COPYRIGHT SHENZHEN LDROBOT CO., LTD *******END OF
272 | * FILE ********/
--------------------------------------------------------------------------------
/ldlidar_driver/src/logger/log_module.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file ldlidar_logger.cpp
3 | * @author LDRobot (support@ldrobot.com)
4 | * @brief
5 | * @version 0.1
6 | * @date 2022.08.10
7 | * @note
8 | * @copyright Copyright (c) 2022 SHENZHEN LDROBOT CO., LTD. All rights reserved.
9 | * Licensed under the MIT License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License in the file LICENSE
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | **/
18 | #include "log_module.h"
19 |
20 | #include
21 | #include
22 |
23 | #ifndef LINUX
24 | #include
25 | #pragma comment(lib, "comsuppw.lib")
26 | #else
27 | #include
28 | #endif
29 |
30 | //使用vswprintf会出现奔溃的情况如果,传入数据大于 VA_PARAMETER_MAX 就会出现崩溃
31 | #define VA_PARAMETER_MAX (1024 * 2)
32 |
33 | LogModule* LogModule::s_plog_module_ = NULL;
34 |
35 |
36 | LogModule* LogModule::GetInstance(__in const char* filename, __in const char* funcname, __in int lineno,LogLevel level,ILogRealization*plog) {
37 | if (s_plog_module_ == NULL) {
38 | s_plog_module_ = new LogModule();
39 | }
40 | s_plog_module_->logInfo_.str_filename = filename;
41 | s_plog_module_->logInfo_.str_funcname = funcname;
42 | s_plog_module_->logInfo_.n_linenumber = lineno;
43 | s_plog_module_->logInfo_.loglevel = level;
44 |
45 | if (plog != NULL) {
46 | s_plog_module_->p_realization_->free();
47 | s_plog_module_->p_realization_ = plog;
48 | }
49 | return s_plog_module_;
50 | }
51 |
52 | LogModule* LogModule::GetInstance(LogLevel level, ILogRealization*plog) {
53 | if (s_plog_module_ == NULL) {
54 | s_plog_module_ = new LogModule();
55 | }
56 | s_plog_module_->logInfo_.loglevel = level;
57 |
58 | if (plog != NULL) {
59 | s_plog_module_->p_realization_->free();
60 | s_plog_module_->p_realization_ = plog;
61 | }
62 | return s_plog_module_;
63 | }
64 |
65 | LogModule::LogModule() {
66 | logInfo_.n_linenumber = -1;
67 | logInfo_.str_filename = "";
68 | logInfo_.str_funcname = "";
69 | #ifndef LINUX
70 | p_realization = new LogOutputString();
71 | #else
72 | p_realization_ = new LogPrint();
73 | #endif
74 | InitLock();
75 | }
76 |
77 | LogModule::~LogModule() {
78 | RealseLock();
79 | }
80 |
81 | void LogModule::LogPrintInf(const char* format,...) {
82 | Lock();
83 | if (p_realization_) {
84 | std::string str_temp;
85 | // manufacture
86 | str_temp.append("[LDS]");
87 | //LogLevel
88 | str_temp.append(GetLevelValue(logInfo_.loglevel));
89 | switch (logInfo_.loglevel) {
90 | case DEBUG_LEVEL: {
91 | //时间戳 uint is seconds
92 | char s_stamp[100] = {0};
93 | uint64_t timestamp = GetCurrentLocalTimeStamp();
94 | #ifdef __LP64__
95 | snprintf(s_stamp, 100, "[%lu.%lu]", (timestamp/1000000000), (timestamp%1000000000));
96 | #else
97 | #ifdef _WIN64
98 | snprintf(s_stamp, 100, "[%lu.%lu]", (timestamp/1000000000), (timestamp%1000000000));
99 | #else
100 | snprintf(s_stamp, 100, "[%llu.%llu]", (timestamp/1000000000), (timestamp%1000000000));
101 | #endif
102 | #endif
103 | str_temp.append(s_stamp);
104 | }
105 | break;
106 | default: {
107 | //时间 [week month day hours:minutes:seconds year]
108 | str_temp.append(GetFormatValue(GetCurrentTime()));
109 | }
110 | break;
111 | }
112 |
113 | //文件名称
114 | str_temp.append(GetFormatValue(logInfo_.str_filename));
115 | str_temp.append(GetFormatValue(logInfo_.str_funcname));
116 | //行号
117 | str_temp.append(GetFormatValue(logInfo_.n_linenumber));
118 |
119 | va_list ptr;
120 | va_start(ptr, format);
121 | char c_value[VA_PARAMETER_MAX] = {0};
122 | vsnprintf(c_value,sizeof(c_value),format,ptr);
123 | va_end(ptr);
124 |
125 | str_temp.append(GetFormatValue(c_value));
126 |
127 | p_realization_->LogPrintInf(str_temp.c_str());
128 | }
129 | UnLock();
130 | }
131 |
132 | void LogModule::LogPrintNoLocationInf(const char* format,...) {
133 | Lock();
134 | if (p_realization_) {
135 | std::string str_temp;
136 | // manufacture
137 | str_temp.append("[LDS]");
138 | //LogLevel
139 | str_temp.append(GetLevelValue(logInfo_.loglevel));
140 |
141 | //时间戳 uint is seconds
142 | char s_stamp[100] = {0};
143 | uint64_t timestamp = GetCurrentLocalTimeStamp();
144 | #ifdef __LP64__
145 | snprintf(s_stamp, 100, "[%lu.%lu]", (timestamp/1000000000), (timestamp%1000000000));
146 | #else
147 | #ifdef _WIN64
148 | snprintf(s_stamp, 100, "[%lu.%lu]", (timestamp/1000000000), (timestamp%1000000000));
149 | #else
150 | snprintf(s_stamp, 100, "[%llu.%llu]", (timestamp/1000000000), (timestamp%1000000000));
151 | #endif
152 | #endif
153 | str_temp.append(s_stamp);
154 |
155 | va_list ptr;
156 | va_start(ptr, format);
157 | char c_value[VA_PARAMETER_MAX] = {0};
158 | vsnprintf(c_value,sizeof(c_value),format,ptr);
159 | va_end(ptr);
160 |
161 | str_temp.append(GetFormatValue(c_value));
162 |
163 | p_realization_->LogPrintInf(str_temp.c_str());
164 | }
165 | UnLock();
166 | }
167 |
168 | void LogModule::InitLock() {
169 | #ifndef LINUX
170 | InitializeCriticalSection(&mutex_lock_);
171 | #else
172 | pthread_mutex_init(&mutex_lock_,NULL);
173 | #endif
174 | }
175 |
176 | void LogModule::RealseLock() {
177 | #ifndef LINUX
178 | DeleteCriticalSection(&mutex_lock_);
179 | #else
180 | pthread_mutex_unlock(&mutex_lock_);
181 | #endif
182 | }
183 |
184 | void LogModule::Lock() {
185 | #ifndef LINUX
186 | EnterCriticalSection(&mutex_lock_);
187 | #else
188 | pthread_mutex_lock(&mutex_lock_);
189 | #endif
190 | }
191 |
192 | void LogModule::UnLock() {
193 | #ifndef LINUX
194 | LeaveCriticalSection(&mutex_lock_);
195 | #else
196 | pthread_mutex_unlock(&mutex_lock_);
197 | #endif
198 | }
199 |
200 | std::string LogModule::GetCurrentTime() {
201 | std::string curr_time;
202 | //Current date/time based on current time
203 | time_t now = time(0);
204 | // Convert current time to string
205 | curr_time.assign(ctime(&now));
206 | // Last charactor of currentTime is "\n", so remove it
207 | std::string current_time = curr_time.substr(0, curr_time.size()-1);
208 | return current_time;
209 | }
210 |
211 | std::string LogModule::GetFormatValue(std::string str_value) {
212 | std::string str_temp;
213 | str_temp.append("[");
214 | str_temp.append(str_value);
215 | str_temp.append("]");
216 | return str_temp;
217 | }
218 |
219 | std::string LogModule::GetFormatValue(int n_value) {
220 | std::string str_temp;
221 | str_temp.append("[");
222 | char c_value[16];
223 | sprintf(c_value,"%d",n_value);
224 | str_temp.append(c_value);
225 | str_temp.append("]");
226 | return str_temp;
227 | }
228 |
229 | std::string LogModule::GetLevelValue(int level){
230 | std::string tmp;
231 | switch (level) {
232 | case DEBUG_LEVEL:
233 | tmp = "DEBUG";
234 | break;
235 | case WARNING_LEVEL:
236 | tmp = "WARNING";
237 | break;
238 | case ERROR_LEVEL:
239 | tmp = "ERROR";
240 | break;
241 | case INFO_LEVEL:
242 | tmp = "INFO";
243 | break;
244 | default:
245 | tmp = "UnKnown";
246 | break;
247 | }
248 | std::string str_temp;
249 | str_temp.append("[");
250 | str_temp.append(tmp);
251 | str_temp.append("]");
252 | return str_temp;
253 | }
254 |
255 | void LogPrint::Initializion(const char* path) {
256 | printf("%s", path);
257 | return ;
258 | }
259 |
260 | void LogPrint::free(ILogRealization *plogger) {
261 | LogPrint* pOutput = static_cast(plogger);
262 | if (pOutput != NULL) {
263 | delete pOutput;
264 | }
265 | }
266 |
267 | void LogPrint::LogPrintInf(const char* str) {
268 | #ifdef ENABLE_CONSOLE_LOG_DIS
269 | printf("%s\r\n", str);
270 | #endif
271 |
272 | #ifdef ENABLE_LOG_WRITE_TO_FILE
273 | FILE *fp = fopen(LOGFILEPATH,"a");
274 | if(!fp) {
275 | printf("%s open filed!\n", LOGFILEPATH);
276 | return ;
277 | }
278 | printf_s(fp,str);
279 | printf_s(fp,"\r\n");
280 | fclose(fp);
281 | #endif
282 | }
283 |
284 | /********************* (C) COPYRIGHT SHENZHEN LDROBOT CO., LTD *******END OF FILE ********/
--------------------------------------------------------------------------------
/ldlidar_driver/src/networkcom/network_socket_interface_linux.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file network_socket_interface_linux.cpp
3 | * @author LDRobot (support@ldrobot.com)
4 | * @brief linux network App
5 | * @version 0.1
6 | * @date 2022-09-05
7 | *
8 | * @copyright Copyright (c) 2022 SHENZHEN LDROBOT CO., LTD. All rights
9 | * reserved.
10 | * Licensed under the MIT License (the "License");
11 | * you may not use this file except in compliance with the License.
12 | * You may obtain a copy of the License in the file LICENSE
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 |
20 | #include "network_socket_interface_linux.h"
21 | #include "log_module.h"
22 |
23 | #define MAX_RECV_BUF_LEN 4096
24 |
25 | namespace ldlidar {
26 |
27 | UDPSocketInterfaceLinux::UDPSocketInterfaceLinux() : recv_thread_(nullptr),
28 | recv_count_(0),
29 | com_sockfd_(-1),
30 | ncd_(NET_NULL),
31 | is_cmd_created_(false),
32 | recv_thread_exit_flag_(true),
33 | is_server_recv_ack_flag_(false),
34 | recv_callback_(nullptr) {
35 |
36 | }
37 |
38 | UDPSocketInterfaceLinux::~UDPSocketInterfaceLinux() {
39 | CloseSocket();
40 | }
41 |
42 | bool UDPSocketInterfaceLinux::CreateSocket(NetCommDevTypeDef obj, const char *ip, const char *port) {
43 |
44 | if (is_cmd_created_ == true) {
45 | return true;
46 | }
47 |
48 | if ((ip == nullptr) || (port == nullptr)) {
49 | LD_LOG_ERROR("UDP,input ip address or port number is null","");
50 | return false;
51 | }
52 |
53 | if ((UDP_CLIENT == obj) || (UDP_SERVER == obj)) {
54 | com_sockfd_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
55 | if(com_sockfd_ == -1) {
56 | LD_LOG_DEBUG("UDP,fail to socket. %s", strerror(errno));
57 | return false;
58 | }
59 | } else {
60 | LD_LOG_ERROR("UDP,input value is error","");
61 | return false;
62 | }
63 |
64 | struct sockaddr_in net_addr;
65 | int addrlen = sizeof(net_addr);
66 | bzero(&net_addr, sizeof(net_addr));
67 | net_addr.sin_family = AF_INET;
68 | net_addr.sin_addr.s_addr = inet_addr(ip);
69 | net_addr.sin_port = htons((short)atoi(port));
70 |
71 | if(obj == UDP_SERVER){
72 | if(-1 == bind(com_sockfd_, (const struct sockaddr*)&net_addr, (socklen_t)addrlen)) {
73 | LD_LOG_ERROR("UDP,fail to bind. %s", strerror(errno));
74 | if (com_sockfd_ != -1) {
75 | close(com_sockfd_);
76 | com_sockfd_ = -1;
77 | }
78 | return false;
79 | }
80 | LDS_LOG_INFO("UDP,bind success..","");
81 | }
82 |
83 | ncd_ = obj;
84 | server_ip_ = ip;
85 | server_port_ = port;
86 |
87 | // create recv process thread.
88 | recv_thread_exit_flag_ = false;
89 | recv_thread_ = new std::thread(RecvThreadProc, this);
90 | is_cmd_created_ = true;
91 |
92 | return true;
93 | }
94 |
95 | bool UDPSocketInterfaceLinux::CloseSocket() {
96 | if (is_cmd_created_ == false) {
97 | return true;
98 | }
99 |
100 | recv_thread_exit_flag_ = true;
101 |
102 | if (com_sockfd_ != -1) {
103 | close(com_sockfd_);
104 | com_sockfd_ = -1;
105 | }
106 |
107 | if ((recv_thread_ != nullptr) && recv_thread_->joinable()) {
108 | recv_thread_->join();
109 | delete recv_thread_;
110 | recv_thread_ = nullptr;
111 | }
112 |
113 | is_cmd_created_ = false;
114 |
115 | return true;
116 | }
117 |
118 | bool UDPSocketInterfaceLinux::RecvFromNet(uint8_t *rx_buf , uint32_t rx_buff_len, uint32_t *rx_len) {
119 | static timespec timeout = {0, (long)(100 * 1e6)};
120 | int32_t len = -1;
121 | struct sockaddr_in sender_addr_inf;
122 | bzero(&sender_addr_inf, sizeof(sender_addr_inf));
123 | int addrlen = sizeof(struct sockaddr_in);
124 |
125 | if (IsCreated()) {
126 | //// setting and init fd table
127 | fd_set recv_fds;
128 | FD_ZERO(&recv_fds);
129 | FD_SET(com_sockfd_, &recv_fds);
130 | int ret = pselect(com_sockfd_ + 1, &recv_fds, NULL, NULL, &timeout, NULL);
131 | if (ret < 0) {
132 | // select was interrputed
133 | if (errno == EINTR) {
134 | return false;
135 | }
136 | } else if (ret == 0) {
137 | // timeout
138 | return false;
139 | }
140 |
141 | if (FD_ISSET(com_sockfd_, &recv_fds)) {
142 | len = (int32_t)recvfrom(com_sockfd_, rx_buf, rx_buff_len, 0,
143 | (struct sockaddr *)&sender_addr_inf, (socklen_t *)&addrlen);
144 | if ((len != -1) && (rx_len != nullptr)) {
145 | *rx_len = len;
146 |
147 | std::string sender_ip = inet_ntoa(sender_addr_inf.sin_addr);
148 | uint16_t sender_port = ntohs(sender_addr_inf.sin_port);
149 | char sender_port_str[10] = {0};
150 | snprintf(sender_port_str, 10, "%d", sender_port);
151 |
152 | if (ncd_ == UDP_SERVER) {
153 | if (!is_server_recv_ack_flag_.load()) {
154 | ///// 保存与服务端通信的客户端IP和端口号,仅支持一对一
155 | client_ip_ = sender_ip;
156 | client_port_ = sender_port_str;
157 | is_server_recv_ack_flag_.store(true);
158 | }
159 | }
160 |
161 | // printf("Recv lens:%d\n", len);
162 | // printf("Sender IP:%s\n", sender_ip.c_str());
163 | // printf("Sender port:%s\n", sender_port_str);
164 | }
165 | }
166 | }
167 |
168 | return ((len == -1) ? false : true);
169 | }
170 |
171 | bool UDPSocketInterfaceLinux::TransToNet(uint8_t *tx_buf, uint32_t tx_buff_len, uint32_t *tx_len) {
172 | int32_t len = -1;
173 | struct sockaddr_in recver_net_addr;
174 | int addrlen = sizeof(recver_net_addr);
175 | bzero(&recver_net_addr, sizeof(recver_net_addr));
176 | recver_net_addr.sin_family = AF_INET;
177 |
178 | if (IsCreated()) {
179 | if (ncd_ == UDP_CLIENT) {
180 | recver_net_addr.sin_addr.s_addr = inet_addr(server_ip_.c_str());
181 | recver_net_addr.sin_port = htons((short)atoi(server_port_.c_str()));
182 | } else if (ncd_ == UDP_SERVER) {
183 | if (!is_server_recv_ack_flag_.load()) {
184 | return false;
185 | } else {
186 | recver_net_addr.sin_addr.s_addr = inet_addr(client_ip_.c_str());
187 | recver_net_addr.sin_port = htons((short)atoi(client_port_.c_str()));
188 | }
189 | }
190 |
191 | len = (int32_t)sendto(com_sockfd_, tx_buf, tx_buff_len, 0,
192 | (struct sockaddr *)&recver_net_addr, (socklen_t)addrlen);
193 | if ((len != -1) && (tx_len != nullptr)) {
194 | *tx_len = len;
195 | // printf("send lens:%d\n", len);
196 | // printf("Reciver IP:%s\n", inet_ntoa(recver_net_addr.sin_addr));
197 | // printf("Reciver port:%d\n", ntohs(recver_net_addr.sin_port));
198 | }
199 | }
200 |
201 | return ((len == -1) ? false : true);
202 | }
203 |
204 | void UDPSocketInterfaceLinux::SetRecvCallback(std::function callback) {
205 | recv_callback_ = callback;
206 | }
207 |
208 | void UDPSocketInterfaceLinux::RecvThreadProc(void *param) {
209 | UDPSocketInterfaceLinux *cmd_if = (UDPSocketInterfaceLinux *)param;
210 | char *recieve_buff = new char[MAX_RECV_BUF_LEN + 1];
211 |
212 | while (!cmd_if->recv_thread_exit_flag_.load()) {
213 | uint32_t recved = 0;
214 | bool res = cmd_if->RecvFromNet((uint8_t *)recieve_buff, MAX_RECV_BUF_LEN, &recved);
215 | if (res && recved) {
216 | cmd_if->recv_count_ += recved;
217 | if (cmd_if->recv_callback_ != nullptr) {
218 | cmd_if->recv_callback_(recieve_buff, recved);
219 | }
220 | }
221 | }
222 |
223 | delete[] recieve_buff;
224 | }
225 |
226 |
227 | TCPSocketInterfaceLinux::TCPSocketInterfaceLinux() : recv_thread_(nullptr),
228 | recv_count_(0),
229 | com_sockfd_(-1),
230 | listend_client_sockfd_(-1),
231 | is_cmd_created_(false),
232 | recv_thread_exit_flag_(false),
233 | recv_callback_(nullptr) {
234 |
235 | }
236 |
237 | TCPSocketInterfaceLinux::~TCPSocketInterfaceLinux() {
238 | CloseSocket();
239 | }
240 |
241 | bool TCPSocketInterfaceLinux::CreateSocket(NetCommDevTypeDef obj, const char *ip, const char *port) {
242 | if (is_cmd_created_ == true) {
243 | return true;
244 | }
245 |
246 | if ((ip == nullptr) || (port == nullptr)) {
247 | LD_LOG_ERROR("TCP,input ip address or port number is null","");
248 | return false;
249 | }
250 |
251 | if ((TCP_CLIENT == obj) || (TCP_SERVER == obj)) {
252 | com_sockfd_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
253 | if(com_sockfd_ == -1) {
254 | LD_LOG_DEBUG("TCP,fail to socket. %s", strerror(errno));
255 | return false;
256 | }
257 | } else {
258 | LD_LOG_ERROR("TCP,input value is error","");
259 | return false;
260 | }
261 |
262 | struct sockaddr_in net_addr;
263 | int addrlen = sizeof(net_addr);
264 | bzero(&net_addr, sizeof(net_addr));
265 | net_addr.sin_family = AF_INET;
266 | net_addr.sin_addr.s_addr = inet_addr(ip);
267 | net_addr.sin_port = htons((short)atoi(port));
268 |
269 | ncd_ = obj;
270 |
271 | if (TCP_SERVER == obj) {
272 | // bind sockfd
273 | if (-1 == bind(com_sockfd_,(const struct sockaddr*)&net_addr,(socklen_t)addrlen)) {
274 | LD_LOG_ERROR("TCP,fail to bind. %s", strerror(errno));
275 | if (com_sockfd_ != -1) {
276 | close(com_sockfd_);
277 | com_sockfd_ = -1;
278 | }
279 | return false;
280 | }
281 | LDS_LOG_INFO("TCP,bind success..","");
282 |
283 | // sockfd in listen
284 | if (-1 == listen(com_sockfd_, 1)) {
285 | LD_LOG_ERROR("TCP,fail to listen. %s", strerror(errno));
286 | if (com_sockfd_ != -1) {
287 | close(com_sockfd_);
288 | com_sockfd_ = -1;
289 | }
290 | return false;
291 | }
292 | LDS_LOG_INFO("TCP,wait client connect.","");
293 |
294 | // wait client request. one by one
295 | struct sockaddr_in client_addr;
296 | int addrlens = sizeof(client_addr);
297 | bzero(&client_addr, sizeof(client_addr));
298 |
299 | if (-1 == (listend_client_sockfd_ = accept(com_sockfd_, (struct sockaddr*)&client_addr, (socklen_t*)&addrlens))) {
300 | LD_LOG_ERROR("TCP,fail to accept. %s", strerror(errno));
301 | if (com_sockfd_ != -1) {
302 | close(com_sockfd_);
303 | com_sockfd_ = -1;
304 | }
305 | return false;
306 | }
307 | LDS_LOG_INFO("TCP,connect_client_fd: %d", listend_client_sockfd_);
308 | LDS_LOG_INFO("TCP,client port: %d", ntohs(client_addr.sin_port));
309 | LDS_LOG_INFO("TCP,client ip: %s", inet_ntoa(client_addr.sin_addr));
310 |
311 | } else if (TCP_CLIENT == obj) {
312 | // connect to server
313 | if (-1 == connect(com_sockfd_, (const struct sockaddr*)&net_addr, (socklen_t)addrlen)) {
314 | LD_LOG_ERROR("TCP,connect server error. %s", strerror(errno));
315 | if (com_sockfd_ != -1) {
316 | close(com_sockfd_);
317 | com_sockfd_ = -1;
318 | }
319 | return false;
320 | }
321 | LDS_LOG_INFO("TCP,connect server success.","");
322 | }
323 |
324 | // create recv process thread.
325 | recv_thread_exit_flag_ = false;
326 | recv_thread_ = new std::thread(RecvThreadProc, this);
327 | is_cmd_created_ = true;
328 |
329 | return true;
330 | }
331 |
332 | bool TCPSocketInterfaceLinux::CloseSocket() {
333 | if (is_cmd_created_ == false) {
334 | return true;
335 | }
336 |
337 | recv_thread_exit_flag_ = true;
338 |
339 | if (com_sockfd_ != -1) {
340 | close(com_sockfd_);
341 | com_sockfd_ = -1;
342 | }
343 |
344 | if (listend_client_sockfd_ != -1) {
345 | close(listend_client_sockfd_);
346 | listend_client_sockfd_ = -1;
347 | }
348 |
349 | if ((recv_thread_ != nullptr) && recv_thread_->joinable()) {
350 | recv_thread_->join();
351 | delete recv_thread_;
352 | recv_thread_ = nullptr;
353 | }
354 |
355 | is_cmd_created_ = false;
356 |
357 | return true;
358 | }
359 |
360 | bool TCPSocketInterfaceLinux::RecvFromNet(uint8_t *rx_buf , uint32_t rx_buff_len, uint32_t *rx_len) {
361 | static timespec timeout = {0, (long)(100 * 1e6)};
362 | int32_t len = -1;
363 |
364 | if (IsCreated()) {
365 | if (TCP_CLIENT == ncd_) {
366 | //// io multiplexing
367 | fd_set recv_fds;
368 | FD_ZERO(&recv_fds);
369 | FD_SET(com_sockfd_, &recv_fds);
370 | int ret = pselect(com_sockfd_ + 1, &recv_fds, NULL, NULL, &timeout, NULL);
371 | if (ret < 0) {
372 | // select was interrputed
373 | if (errno == EINTR) {
374 | return false;
375 | }
376 | } else if (ret == 0) {
377 | // timeout
378 | return false;
379 | }
380 |
381 | if (FD_ISSET(com_sockfd_, &recv_fds)) {
382 | len = (int32_t)recv(com_sockfd_, rx_buf, rx_buff_len, 0);
383 | if ((len != -1) && (rx_len != nullptr)) {
384 | *rx_len = len;
385 | }
386 | }
387 | } else if (TCP_SERVER == ncd_) {
388 | fd_set recv_fds;
389 | FD_ZERO(&recv_fds);
390 | FD_SET(listend_client_sockfd_, &recv_fds);
391 | int ret = pselect(listend_client_sockfd_ + 1, &recv_fds, NULL, NULL, &timeout, NULL);
392 | if (ret < 0) {
393 | // select was interrputed
394 | if (errno == EINTR) {
395 | return false;
396 | }
397 | } else if (ret == 0) {
398 | // timeout
399 | return false;
400 | }
401 |
402 | if (FD_ISSET(listend_client_sockfd_, &recv_fds)) {
403 | len = (int32_t)recv(listend_client_sockfd_, rx_buf, rx_buff_len, 0);
404 | if ((len != -1) && (rx_len != nullptr)) {
405 | *rx_len = len;
406 | }
407 | }
408 | }
409 | }
410 |
411 | return ((len == -1) ? false : true);
412 | }
413 |
414 | bool TCPSocketInterfaceLinux::TransToNet(uint8_t *tx_buf, uint32_t tx_buff_len, uint32_t *tx_len) {
415 | int32_t len = 1;
416 |
417 | if (IsCreated()) {
418 | if (TCP_CLIENT == ncd_) {
419 | len = (int32_t)send(com_sockfd_, tx_buf, tx_buff_len, 0);
420 | if ((len != -1) && (tx_len == nullptr)) {
421 | *tx_len = len;
422 | }
423 | } else if (TCP_SERVER == ncd_) {
424 | len = (int32_t)send(listend_client_sockfd_, tx_buf, tx_buff_len, 0);
425 | if ((len != -1) && (tx_len != nullptr)) {
426 | *tx_len = len;
427 | }
428 | }
429 | }
430 |
431 | return ((len == -1) ? false : true);
432 | }
433 |
434 | void TCPSocketInterfaceLinux::SetRecvCallback(std::function callback) {
435 | recv_callback_ = callback;
436 | }
437 |
438 | void TCPSocketInterfaceLinux::RecvThreadProc(void *param) {
439 | TCPSocketInterfaceLinux *cmd_if = (TCPSocketInterfaceLinux *)param;
440 | char *recieve_buff = new char[MAX_RECV_BUF_LEN + 1];
441 |
442 | while (!cmd_if->recv_thread_exit_flag_.load()) {
443 | uint32_t recved = 0;
444 | bool res = cmd_if->RecvFromNet((uint8_t *)recieve_buff, MAX_RECV_BUF_LEN, &recved);
445 | if (res && recved) {
446 | cmd_if->recv_count_ += recved;
447 | if (cmd_if->recv_callback_ != nullptr) {
448 | cmd_if->recv_callback_(recieve_buff, recved);
449 | }
450 | }
451 | }
452 |
453 | delete[] recieve_buff;
454 | }
455 |
456 | } // namespace ldlidar
457 | /********************* (C) COPYRIGHT SHENZHEN LDROBOT CO., LTD *******END OF
458 | * FILE ********/
--------------------------------------------------------------------------------
/ldlidar_driver/src/serialcom/serial_interface_linux.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file cmd_interface_linux.cpp
3 | * @author LDRobot (support@ldrobot.com)
4 | * @brief linux serial port App
5 | * @version 0.1
6 | * @date 2021-10-28
7 | *
8 | * @copyright Copyright (c) 2021 SHENZHEN LDROBOT CO., LTD. All rights
9 | * reserved.
10 | * Licensed under the MIT License (the "License");
11 | * you may not use this file except in compliance with the License.
12 | * You may obtain a copy of the License in the file LICENSE
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 |
20 | #include "serial_interface_linux.h"
21 | #include "log_module.h"
22 |
23 |
24 | #define MAX_ACK_BUF_LEN 4096
25 |
26 | namespace ldlidar {
27 |
28 | SerialInterfaceLinux::SerialInterfaceLinux()
29 | : rx_thread_(nullptr), rx_count_(0), read_callback_(nullptr) {
30 | com_handle_ = -1;
31 | com_baudrate_ = 0;
32 | }
33 |
34 | SerialInterfaceLinux::~SerialInterfaceLinux() { Close(); }
35 |
36 | bool SerialInterfaceLinux::Open(std::string &port_name, uint32_t com_baudrate) {
37 | int flags = (O_RDWR | O_NOCTTY | O_NONBLOCK);
38 |
39 | com_handle_ = open(port_name.c_str(), flags);
40 | if (-1 == com_handle_) {
41 | LD_LOG_ERROR("Open open error,%s", strerror(errno));
42 | return false;
43 | }
44 |
45 | com_baudrate_ = com_baudrate;
46 |
47 | struct asmtermios::termios2 options;
48 | if (ioctl(com_handle_, _IOC(_IOC_READ, 'T', 0x2A, sizeof(struct asmtermios::termios2)), &options)) {
49 | LD_LOG_ERROR("TCGETS2 first error,%s", strerror(errno));
50 | if (com_handle_ != -1) {
51 | close(com_handle_);
52 | com_handle_ = -1;
53 | }
54 | return false;
55 | }
56 |
57 | options.c_cflag |= (tcflag_t)(CLOCAL | CREAD | CS8);
58 | options.c_cflag &= (tcflag_t) ~(CSTOPB | PARENB);
59 | options.c_lflag &= (tcflag_t) ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL |
60 | ISIG | IEXTEN); //|ECHOPRT
61 | options.c_oflag &= (tcflag_t) ~(OPOST);
62 | options.c_iflag &= (tcflag_t) ~(IXON | IXOFF | INLCR | IGNCR | ICRNL | IGNBRK);
63 |
64 | options.c_cflag &= ~CBAUD;
65 | options.c_cflag |= BOTHER;
66 | options.c_ispeed = this->com_baudrate_;
67 | options.c_ospeed = this->com_baudrate_;
68 |
69 | options.c_cc[VMIN] = 0;
70 | options.c_cc[VTIME] = 0;
71 |
72 | if (ioctl(com_handle_, _IOC(_IOC_WRITE, 'T', 0x2B, sizeof(struct asmtermios::termios2)), &options)) {
73 | LD_LOG_ERROR("TCSETS2 error,%s", strerror(errno));
74 | if (com_handle_ != -1) {
75 | close(com_handle_);
76 | com_handle_ = -1;
77 | }
78 | return false;
79 | }
80 |
81 | if (ioctl(com_handle_, _IOC(_IOC_READ, 'T', 0x2A, sizeof(struct asmtermios::termios2)), &options)) {
82 | LD_LOG_ERROR("TCGETS2 second error,%s", strerror(errno));
83 | if (com_handle_ != -1) {
84 | close(com_handle_);
85 | com_handle_ = -1;
86 | }
87 | return false;
88 | }
89 |
90 | LDS_LOG_INFO("Actual BaudRate reported:%d", options.c_ospeed);
91 |
92 | tcflush(com_handle_, TCIFLUSH);
93 |
94 | rx_thread_exit_flag_ = false;
95 | rx_thread_ = new std::thread(RxThreadProc, this);
96 | is_cmd_opened_ = true;
97 |
98 | return true;
99 | }
100 |
101 | bool SerialInterfaceLinux::Close() {
102 | if (is_cmd_opened_ == false) {
103 | return true;
104 | }
105 |
106 | rx_thread_exit_flag_ = true;
107 |
108 | if (com_handle_ != -1) {
109 | close(com_handle_);
110 | com_handle_ = -1;
111 | }
112 |
113 | if ((rx_thread_ != nullptr) && rx_thread_->joinable()) {
114 | rx_thread_->join();
115 | delete rx_thread_;
116 | rx_thread_ = nullptr;
117 | }
118 |
119 | is_cmd_opened_ = false;
120 |
121 | return true;
122 | }
123 |
124 | bool SerialInterfaceLinux::ReadFromIO(uint8_t *rx_buf, uint32_t rx_buf_len,
125 | uint32_t *rx_len) {
126 | static timespec timeout = {0, (long)(100 * 1e6)};
127 | int32_t len = -1;
128 |
129 | if (IsOpened()) {
130 | fd_set read_fds;
131 | FD_ZERO(&read_fds);
132 | FD_SET(com_handle_, &read_fds);
133 | int r = pselect(com_handle_ + 1, &read_fds, NULL, NULL, &timeout, NULL);
134 | if (r < 0) {
135 | // Select was interrupted
136 | if (errno == EINTR) {
137 | return false;
138 | }
139 | } else if (r == 0) { // timeout
140 | return false;
141 | }
142 |
143 | if (FD_ISSET(com_handle_, &read_fds)) {
144 | len = (int32_t)read(com_handle_, rx_buf, rx_buf_len);
145 | if ((len != -1) && rx_len) {
146 | *rx_len = len;
147 | }
148 | }
149 | }
150 | return len == -1 ? false : true;
151 | }
152 |
153 | bool SerialInterfaceLinux::WriteToIo(const uint8_t *tx_buf, uint32_t tx_buf_len,
154 | uint32_t *tx_len) {
155 | int32_t len = -1;
156 |
157 | if (IsOpened()) {
158 | len = (int32_t)write(com_handle_, tx_buf, tx_buf_len);
159 | if ((len != -1) && tx_len) {
160 | *tx_len = len;
161 | }
162 | }
163 | return len == -1 ? false : true;
164 | }
165 |
166 | void SerialInterfaceLinux::RxThreadProc(void *param) {
167 | SerialInterfaceLinux *cmd_if = (SerialInterfaceLinux *)param;
168 | char *rx_buf = new char[MAX_ACK_BUF_LEN + 1];
169 | while (!cmd_if->rx_thread_exit_flag_.load()) {
170 | uint32_t readed = 0;
171 | bool res = cmd_if->ReadFromIO((uint8_t *)rx_buf, MAX_ACK_BUF_LEN, &readed);
172 | if (res && readed) {
173 | cmd_if->rx_count_ += readed;
174 | if (cmd_if->read_callback_ != nullptr) {
175 | cmd_if->read_callback_(rx_buf, readed);
176 | }
177 | }
178 | }
179 |
180 | delete[] rx_buf;
181 | }
182 |
183 | } // namespace ldlidar
184 |
185 | /********************* (C) COPYRIGHT SHENZHEN LDROBOT CO., LTD *******END OF
186 | * FILE ********/
--------------------------------------------------------------------------------
/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | ldlidar_stl_ros
4 | 3.0.0
5 | The ldlidar package
6 |
7 |
8 |
9 |
10 | SHENZHEN LDROBOT CO., LTD.
11 |
12 |
13 |
14 |
15 |
16 | MIT
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | catkin
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | roscpp
76 | sensor_msgs
77 | tf
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/rules/ldlidar.rules:
--------------------------------------------------------------------------------
1 | # set the udev rule , make the device_port be fixed by ldlidar
2 | # CP210x USB Device
3 | KERNEL=="ttyUSB*", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", MODE:="0777", SYMLINK+="ldlidar"
4 |
5 |
--------------------------------------------------------------------------------
/rviz/ldlidar_kinetic_melodic.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 | - /LaserScan1
10 | Splitter Ratio: 0.5
11 | Tree Height: 613
12 | - Class: rviz/Selection
13 | Name: Selection
14 | - Class: rviz/Tool Properties
15 | Expanded:
16 | - /2D Pose Estimate1
17 | - /2D Nav Goal1
18 | - /Publish Point1
19 | Name: Tool Properties
20 | Splitter Ratio: 0.588679016
21 | - Class: rviz/Views
22 | Expanded:
23 | - /Current View1
24 | Name: Views
25 | Splitter Ratio: 0.5
26 | - Class: rviz/Time
27 | Experimental: false
28 | Name: Time
29 | SyncMode: 0
30 | SyncSource: LaserScan
31 | Toolbars:
32 | toolButtonStyle: 2
33 | Visualization Manager:
34 | Class: ""
35 | Displays:
36 | - Alpha: 0.5
37 | Cell Size: 1
38 | Class: rviz/Grid
39 | Color: 160; 160; 164
40 | Enabled: true
41 | Line Style:
42 | Line Width: 0.0299999993
43 | Value: Lines
44 | Name: Grid
45 | Normal Cell Count: 0
46 | Offset:
47 | X: 0
48 | Y: 0
49 | Z: 0
50 | Plane: XY
51 | Plane Cell Count: 20
52 | Reference Frame:
53 | Value: true
54 | - Class: rviz/Axes
55 | Enabled: false
56 | Length: 1
57 | Name: Axes
58 | Radius: 0.100000001
59 | Reference Frame:
60 | Value: false
61 | - Class: rviz/TF
62 | Enabled: true
63 | Frame Timeout: 15
64 | Frames:
65 | All Enabled: true
66 | base_laser:
67 | Value: true
68 | base_link:
69 | Value: true
70 | Marker Scale: 1
71 | Name: TF
72 | Show Arrows: true
73 | Show Axes: true
74 | Show Names: true
75 | Tree:
76 | base_link:
77 | base_laser:
78 | {}
79 | Update Interval: 0
80 | Value: true
81 | - Alpha: 1
82 | Autocompute Intensity Bounds: true
83 | Autocompute Value Bounds:
84 | Max Value: 10
85 | Min Value: -10
86 | Value: true
87 | Axis: Z
88 | Channel Name: intensity
89 | Class: rviz/LaserScan
90 | Color: 255; 255; 255
91 | Color Transformer: Intensity
92 | Decay Time: 0
93 | Enabled: true
94 | Invert Rainbow: false
95 | Max Color: 255; 255; 255
96 | Max Intensity: 249
97 | Min Color: 0; 0; 0
98 | Min Intensity: 35
99 | Name: LaserScan
100 | Position Transformer: XYZ
101 | Queue Size: 10
102 | Selectable: true
103 | Size (Pixels): 3
104 | Size (m): 0.00999999978
105 | Style: Points
106 | Topic: /scan
107 | Unreliable: false
108 | Use Fixed Frame: true
109 | Use rainbow: true
110 | Value: true
111 | Enabled: true
112 | Global Options:
113 | Background Color: 48; 48; 48
114 | Default Light: true
115 | Fixed Frame: base_laser
116 | Frame Rate: 30
117 | Name: root
118 | Tools:
119 | - Class: rviz/Interact
120 | Hide Inactive Objects: true
121 | - Class: rviz/MoveCamera
122 | - Class: rviz/Select
123 | - Class: rviz/FocusCamera
124 | - Class: rviz/Measure
125 | - Class: rviz/SetInitialPose
126 | Topic: /initialpose
127 | - Class: rviz/SetGoal
128 | Topic: /move_base_simple/goal
129 | - Class: rviz/PublishPoint
130 | Single click: true
131 | Topic: /clicked_point
132 | Value: true
133 | Views:
134 | Current:
135 | Class: rviz/Orbit
136 | Distance: 26.3351135
137 | Enable Stereo Rendering:
138 | Stereo Eye Separation: 0.0599999987
139 | Stereo Focal Distance: 1
140 | Swap Stereo Eyes: false
141 | Value: false
142 | Focal Point:
143 | X: 0
144 | Y: 0
145 | Z: 0
146 | Focal Shape Fixed Size: true
147 | Focal Shape Size: 0.0500000007
148 | Invert Z Axis: false
149 | Name: Current View
150 | Near Clip Distance: 0.00999999978
151 | Pitch: 1.56979632
152 | Target Frame:
153 | Value: Orbit (rviz)
154 | Yaw: 3.13039947
155 | Saved: ~
156 | Window Geometry:
157 | Displays:
158 | collapsed: false
159 | Height: 894
160 | Hide Left Dock: false
161 | Hide Right Dock: false
162 | QMainWindow State: 000000ff00000000fd00000004000000000000016a000002f4fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006100fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c0061007900730100000028000002f4000000d700fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000002f4fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a005600690065007700730100000028000002f4000000ad00fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000007450000003efc0100000002fb0000000800540069006d00650100000000000007450000030000fffffffb0000000800540069006d00650100000000000004500000000000000000000004c0000002f400000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
163 | Selection:
164 | collapsed: false
165 | Time:
166 | collapsed: false
167 | Tool Properties:
168 | collapsed: false
169 | Views:
170 | collapsed: false
171 | Width: 1861
172 | X: 57
173 | Y: 24
174 |
--------------------------------------------------------------------------------
/rviz/ldlidar_noetic.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 | - /TF1
10 | - /LaserScan1
11 | Splitter Ratio: 0.5
12 | Tree Height: 557
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.5886790156364441
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: LaserScan
32 | Preferences:
33 | PromptSaveOnExit: true
34 | Toolbars:
35 | toolButtonStyle: 2
36 | Visualization Manager:
37 | Class: ""
38 | Displays:
39 | - Alpha: 0.5
40 | Cell Size: 1
41 | Class: rviz/Grid
42 | Color: 160; 160; 164
43 | Enabled: true
44 | Line Style:
45 | Line Width: 0.029999999329447746
46 | Value: Lines
47 | Name: Grid
48 | Normal Cell Count: 0
49 | Offset:
50 | X: 0
51 | Y: 0
52 | Z: 0
53 | Plane: XY
54 | Plane Cell Count: 20
55 | Reference Frame:
56 | Value: true
57 | - Alpha: 1
58 | Class: rviz/Axes
59 | Enabled: false
60 | Length: 1
61 | Name: Axes
62 | Radius: 0.05000000074505806
63 | Reference Frame:
64 | Show Trail: false
65 | Value: false
66 | - Class: rviz/TF
67 | Enabled: true
68 | Frame Timeout: 15
69 | Frames:
70 | All Enabled: true
71 | base_laser:
72 | Value: true
73 | base_link:
74 | Value: true
75 | Marker Alpha: 1
76 | Marker Scale: 1
77 | Name: TF
78 | Show Arrows: true
79 | Show Axes: true
80 | Show Names: true
81 | Tree:
82 | base_link:
83 | base_laser:
84 | {}
85 | Update Interval: 0
86 | Value: true
87 | - Alpha: 1
88 | Autocompute Intensity Bounds: true
89 | Autocompute Value Bounds:
90 | Max Value: 10
91 | Min Value: -10
92 | Value: true
93 | Axis: Z
94 | Channel Name: intensity
95 | Class: rviz/LaserScan
96 | Color: 255; 255; 255
97 | Color Transformer: Intensity
98 | Decay Time: 0
99 | Enabled: true
100 | Invert Rainbow: false
101 | Max Color: 255; 255; 255
102 | Min Color: 0; 0; 0
103 | Name: LaserScan
104 | Position Transformer: XYZ
105 | Queue Size: 10
106 | Selectable: true
107 | Size (Pixels): 3
108 | Size (m): 0.029999999329447746
109 | Style: Flat Squares
110 | Topic: /scan
111 | Unreliable: false
112 | Use Fixed Frame: true
113 | Use rainbow: true
114 | Value: true
115 | Enabled: true
116 | Global Options:
117 | Background Color: 48; 48; 48
118 | Default Light: true
119 | Fixed Frame: base_laser
120 | Frame Rate: 30
121 | Name: root
122 | Tools:
123 | - Class: rviz/Interact
124 | Hide Inactive Objects: true
125 | - Class: rviz/MoveCamera
126 | - Class: rviz/Select
127 | - Class: rviz/FocusCamera
128 | - Class: rviz/Measure
129 | - Class: rviz/SetInitialPose
130 | Theta std deviation: 0.2617993950843811
131 | Topic: /initialpose
132 | X std deviation: 0.5
133 | Y std deviation: 0.5
134 | - Class: rviz/SetGoal
135 | Topic: /move_base_simple/goal
136 | - Class: rviz/PublishPoint
137 | Single click: true
138 | Topic: /clicked_point
139 | Value: true
140 | Views:
141 | Current:
142 | Class: rviz/Orbit
143 | Distance: 11.079298973083496
144 | Enable Stereo Rendering:
145 | Stereo Eye Separation: 0.05999999865889549
146 | Stereo Focal Distance: 1
147 | Swap Stereo Eyes: false
148 | Value: false
149 | Field of View: 0.7853981852531433
150 | Focal Point:
151 | X: 0
152 | Y: 0
153 | Z: 0
154 | Focal Shape Fixed Size: true
155 | Focal Shape Size: 0.05000000074505806
156 | Invert Z Axis: false
157 | Name: Current View
158 | Near Clip Distance: 0.009999999776482582
159 | Pitch: 1.4397964477539062
160 | Target Frame:
161 | Yaw: 3.135404348373413
162 | Saved: ~
163 | Window Geometry:
164 | Displays:
165 | collapsed: false
166 | Height: 854
167 | Hide Left Dock: false
168 | Hide Right Dock: false
169 | QMainWindow State: 000000ff00000000fd000000040000000000000156000002b8fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d000002b8000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000002b8fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003d000002b8000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000007400000003efc0100000002fb0000000800540069006d0065010000000000000740000002eb00fffffffb0000000800540069006d00650100000000000004500000000000000000000004cf000002b800000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
170 | Selection:
171 | collapsed: false
172 | Time:
173 | collapsed: false
174 | Tool Properties:
175 | collapsed: false
176 | Views:
177 | collapsed: false
178 | Width: 1856
179 | X: 62
180 | Y: 27
181 |
--------------------------------------------------------------------------------
/scripts/create_udev_rules.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | echo "remap the device serial port(ttyUSBX) to ldlidar"
4 | echo "ldlidar usb connection as /dev/ldlidar , check it using the command : ls -l /dev|grep ttyUSB"
5 | echo "start copy ldlidar.rules to /etc/udev/rules.d/"
6 | sudo cp `rospack find ldlidar_stl_ros`/rules/ldlidar.rules /etc/udev/rules.d/
7 | echo " "
8 | echo "Restarting udev"
9 | echo ""
10 | sudo udevadm control --reload-rules
11 | sudo service udev restart
12 | sudo udevadm trigger
13 | echo "finish "
14 |
--------------------------------------------------------------------------------
/scripts/delete_udev_rules.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | echo "delete remap the device serial port(ttyUSBX) to ldlidar"
4 | echo "sudo rm /etc/udev/rules.d/ldlidar.rules"
5 | sudo rm /etc/udev/rules.d/ldlidar.rules
6 | echo " "
7 | echo "Restarting udev"
8 | echo ""
9 | sudo udevadm control --reload-rules
10 | sudo service udev restart
11 | sudo udevadm trigger
12 | echo "finish delete"
13 |
--------------------------------------------------------------------------------
/src/listen_node/listen_node.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file listen_node.cpp
3 | * @author LDRobot (marketing1@ldrobot.com)
4 | * @brief
5 | * @version 0.1
6 | * @date 2022.04.08
7 | * @note
8 | * @copyright Copyright (c) 2020 SHENZHEN LDROBOT CO., LTD. All rights reserved.
9 | * Licensed under the MIT License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License in the file LICENSE
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | **/
18 | #include
19 | #include
20 |
21 | #include
22 | #include
23 |
24 | #define RADIAN_TO_DEGREES(angle) ((angle)*180000/3141.59)
25 |
26 | void LidarMsgCallback(const sensor_msgs::LaserScan::ConstPtr& data)
27 | {
28 | ROS_INFO_STREAM("[ldrobot]------listen lidar message-------");
29 | unsigned int lens = static_cast((data->angle_max - data->angle_min) / data->angle_increment);
30 | ROS_INFO_STREAM("[ldrobot] angle_min: " << RADIAN_TO_DEGREES(data->angle_min) << " "
31 | << "angle_max: " << RADIAN_TO_DEGREES(data->angle_max));
32 | ROS_INFO_STREAM("[ldrobot] point size: " << data->ranges.size());
33 | for (unsigned int i = 0; i < lens; i++) {
34 | ROS_INFO_STREAM("[ldrobot] angle: " << RADIAN_TO_DEGREES((data->angle_min + i * data->angle_increment)) << " "
35 | << "range: " << data->ranges[i] << " "
36 | << "intensites: " << data->intensities[i]);
37 | }
38 | }
39 |
40 | int main(int argc, char **argv)
41 | {
42 | ros::init(argc, argv, "ldldiar_listen_node");
43 | ros::NodeHandle nh; // create a ROS Node
44 | ros::NodeHandle n("~");
45 | std::string topic_name;
46 |
47 | n.param("topic_name", topic_name, std::string("scan"));
48 |
49 | if (topic_name.empty()) {
50 | ROS_ERROR("[ldrobot] [ldldiar_listen_node] input param is null");
51 | exit(EXIT_FAILURE);
52 | } else {
53 | ROS_INFO("[ldrobot] [ldldiar_listen_node] input param is %s", topic_name.c_str());
54 | }
55 |
56 | ros::Subscriber msg_subs = nh.subscribe(topic_name, 10, &LidarMsgCallback);
57 | ROS_INFO("[ldrobot] start ldldiar message subscribe node");
58 |
59 | ros::Rate loop_rate(10);
60 | while (ros::ok()) {
61 | ros::spinOnce();
62 | loop_rate.sleep();
63 | }
64 |
65 | return 0;
66 | }
67 |
68 | /********************* (C) COPYRIGHT SHENZHEN LDROBOT CO., LTD *******END OF FILE ********/
69 |
--------------------------------------------------------------------------------
/src/publish_node/main.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file main.cpp
3 | * @author LDRobot (marketing1@ldrobot.com)
4 | * @brief main process App
5 | * This code is only applicable to LDROBOT LiDAR LD06 products
6 | * sold by Shenzhen LDROBOT Co., LTD
7 | * @version 0.1
8 | * @date 2021-10-28
9 | *
10 | * @copyright Copyright (c) 2021 SHENZHEN LDROBOT CO., LTD. All rights
11 | * reserved.
12 | * Licensed under the MIT License (the "License");
13 | * you may not use this file except in compliance with the License.
14 | * You may obtain a copy of the License in the file LICENSE
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | */
21 | #include "ros_api.h"
22 | #include "ldlidar_driver.h"
23 |
24 | void ToLaserscanMessagePublish(ldlidar::Points2D& src, double lidar_spin_freq,
25 | LaserScanSetting& setting, ros::Publisher& lidarpub);
26 |
27 | uint64_t GetSystemTimeStamp(void);
28 |
29 | int main(int argc, char **argv) {
30 | ros::init(argc, argv, "ldldiar_publisher");
31 | ros::NodeHandle nh; // create a ROS Node
32 | ros::NodeHandle nh_private("~");
33 | std::string product_name;
34 | std::string topic_name;
35 | std::string port_name;
36 | int serial_port_baudrate;
37 | LaserScanSetting setting;
38 | ldlidar::LDType type_name;
39 |
40 | nh_private.getParam("product_name", product_name);
41 | nh_private.getParam("topic_name", topic_name);
42 | nh_private.param("frame_id", setting.frame_id, std::string("base_laser"));
43 | nh_private.getParam("port_name", port_name);
44 | nh_private.param("port_baudrate", serial_port_baudrate, int(230400));
45 | nh_private.param("laser_scan_dir", setting.laser_scan_dir, bool(true));
46 | nh_private.param("enable_angle_crop_func", setting.enable_angle_crop_func, bool(false));
47 | nh_private.param("angle_crop_min", setting.angle_crop_min, double(0.0));
48 | nh_private.param("angle_crop_max", setting.angle_crop_max, double(0.0));
49 |
50 | ldlidar::LDLidarDriver* ldlidarnode = new ldlidar::LDLidarDriver();
51 |
52 | ROS_INFO("LDLiDAR SDK Pack Version is: %s", ldlidarnode->GetLidarSdkVersionNumber().c_str());
53 | ROS_INFO("ROS params input:");
54 | ROS_INFO(": %s", product_name.c_str());
55 | ROS_INFO(": %s", topic_name.c_str());
56 | ROS_INFO(": %s", setting.frame_id.c_str());
57 | ROS_INFO(": %s", port_name.c_str());
58 | ROS_INFO(": %d", serial_port_baudrate);
59 | ROS_INFO(": %s", (setting.laser_scan_dir?"Counterclockwise":"Clockwise"));
60 | ROS_INFO(": %s", (setting.enable_angle_crop_func?"true":"false"));
61 | ROS_INFO(": %f", setting.angle_crop_min);
62 | ROS_INFO(": %f", setting.angle_crop_max);
63 |
64 | if (product_name == "LDLiDAR_LD06") {
65 | type_name = ldlidar::LDType::LD_06;
66 | } else if (product_name == "LDLiDAR_LD19") {
67 | type_name = ldlidar::LDType::LD_19;
68 | } else {
69 | ROS_ERROR("Error, input is illegal.");
70 | exit(EXIT_FAILURE);
71 | }
72 |
73 | ldlidarnode->RegisterGetTimestampFunctional(std::bind(&GetSystemTimeStamp));
74 |
75 | ldlidarnode->EnableFilterAlgorithnmProcess(true);
76 |
77 | if (ldlidarnode->Start(type_name, port_name, serial_port_baudrate, ldlidar::COMM_SERIAL_MODE)) {
78 | ROS_INFO("ldlidar node start is success");
79 | } else {
80 | ROS_ERROR("ldlidar node start is fail");
81 | exit(EXIT_FAILURE);
82 | }
83 |
84 | if (ldlidarnode->WaitLidarCommConnect(3000)) {
85 | ROS_INFO("ldlidar communication is normal.");
86 | } else {
87 | ROS_ERROR("ldlidar communication is abnormal.");
88 | exit(EXIT_FAILURE);
89 | }
90 |
91 |
92 | ros::Publisher lidar_pub =
93 | nh.advertise(topic_name, 10); // create a ROS topic
94 |
95 | ros::Rate r(10); //10hz
96 | ldlidar::Points2D laser_scan_points;
97 | double lidar_scan_freq;
98 | ROS_INFO("Publish topic message:ldlidar scan data .");
99 |
100 | while (ros::ok()) {
101 |
102 | switch (ldlidarnode->GetLaserScanData(laser_scan_points, 1500)){
103 | case ldlidar::LidarStatus::NORMAL:
104 | ldlidarnode->GetLidarScanFreq(lidar_scan_freq);
105 | ToLaserscanMessagePublish(laser_scan_points, lidar_scan_freq, setting, lidar_pub);
106 | break;
107 | case ldlidar::LidarStatus::DATA_TIME_OUT:
108 | ROS_ERROR("get ldlidar data is time out, please check your lidar device.");
109 | break;
110 | case ldlidar::LidarStatus::DATA_WAIT:
111 | break;
112 | default:
113 | break;
114 | }
115 |
116 | r.sleep();
117 | }
118 |
119 | ldlidarnode->Stop();
120 |
121 | delete ldlidarnode;
122 | ldlidarnode = nullptr;
123 |
124 | return 0;
125 | }
126 |
127 | void ToLaserscanMessagePublish(ldlidar::Points2D& src, double lidar_spin_freq,
128 | LaserScanSetting& setting, ros::Publisher& lidarpub) {
129 | float angle_min, angle_max, range_min, range_max, angle_increment;
130 | float scan_time;
131 | ros::Time start_scan_time;
132 | static ros::Time end_scan_time;
133 | static bool first_scan = true;
134 |
135 | start_scan_time = ros::Time::now();
136 | scan_time = (start_scan_time - end_scan_time).toSec();
137 |
138 | if (first_scan) {
139 | first_scan = false;
140 | end_scan_time = start_scan_time;
141 | return;
142 | }
143 |
144 | // Adjust the parameters according to the demand
145 | angle_min = 0;
146 | angle_max = (2 * M_PI);
147 | range_min = 0.02;
148 | range_max = 12;
149 | int beam_size = static_cast(src.size());
150 | angle_increment = (angle_max - angle_min) / (float)(beam_size -1);
151 |
152 | // Calculate the number of scanning points
153 | if (lidar_spin_freq > 0) {
154 | sensor_msgs::LaserScan output;
155 | output.header.stamp = start_scan_time;
156 | output.header.frame_id = setting.frame_id;
157 | output.angle_min = angle_min;
158 | output.angle_max = angle_max;
159 | output.range_min = range_min;
160 | output.range_max = range_max;
161 | output.angle_increment = angle_increment;
162 | if (beam_size <= 1) {
163 | output.time_increment = 0;
164 | } else {
165 | output.time_increment = scan_time / (float)(beam_size - 1);
166 | }
167 | output.scan_time = scan_time;
168 | // First fill all the data with Nan
169 | output.ranges.assign(beam_size, std::numeric_limits::quiet_NaN());
170 | output.intensities.assign(beam_size, std::numeric_limits::quiet_NaN());
171 |
172 | for (auto point : src) {
173 | float range = point.distance / 1000.f; // distance unit transform to meters
174 | float intensity = point.intensity; // laser receive intensity
175 | float dir_angle = point.angle;
176 |
177 | if ((point.distance == 0) && (point.intensity == 0)) { // filter is handled to 0, Nan will be assigned variable.
178 | range = std::numeric_limits::quiet_NaN();
179 | intensity = std::numeric_limits::quiet_NaN();
180 | }
181 |
182 | if (setting.enable_angle_crop_func) { // Angle crop setting, Mask data within the set angle range
183 | if ((dir_angle >= setting.angle_crop_min) && (dir_angle <= setting.angle_crop_max)) {
184 | range = std::numeric_limits::quiet_NaN();
185 | intensity = std::numeric_limits::quiet_NaN();
186 | }
187 | }
188 |
189 | float angle = ANGLE_TO_RADIAN(dir_angle); // Lidar angle unit form degree transform to radian
190 | int index = static_cast(ceil((angle - angle_min) / angle_increment));
191 | if (index < beam_size) {
192 | if (index < 0) {
193 | ROS_ERROR("[ldrobot] error index: %d, beam_size: %d, angle: %f, angle_min: %f, angle_increment: %f",
194 | index, beam_size, angle, angle_min, angle_increment);
195 | }
196 |
197 | if (setting.laser_scan_dir) {
198 | int index_anticlockwise = beam_size - index - 1;
199 | // If the current content is Nan, it is assigned directly
200 | if (std::isnan(output.ranges[index_anticlockwise])) {
201 | output.ranges[index_anticlockwise] = range;
202 | } else { // Otherwise, only when the distance is less than the current
203 | // value, it can be re assigned
204 | if (range < output.ranges[index_anticlockwise]) {
205 | output.ranges[index_anticlockwise] = range;
206 | }
207 | }
208 | output.intensities[index_anticlockwise] = intensity;
209 | } else {
210 | // If the current content is Nan, it is assigned directly
211 | if (std::isnan(output.ranges[index])) {
212 | output.ranges[index] = range;
213 | } else { // Otherwise, only when the distance is less than the current
214 | // value, it can be re assigned
215 | if (range < output.ranges[index]) {
216 | output.ranges[index] = range;
217 | }
218 | }
219 | output.intensities[index] = intensity;
220 | }
221 | }
222 | }
223 | lidarpub.publish(output);
224 | end_scan_time = start_scan_time;
225 | }
226 | }
227 |
228 | uint64_t GetSystemTimeStamp(void) {
229 | std::chrono::time_point tp =
230 | std::chrono::time_point_cast(std::chrono::system_clock::now());
231 | auto tmp = std::chrono::duration_cast(tp.time_since_epoch());
232 | return ((uint64_t)tmp.count());
233 | }
234 |
235 | /********************* (C) COPYRIGHT SHENZHEN LDROBOT CO., LTD *******END OF
236 | * FILE ********/
237 |
--------------------------------------------------------------------------------