From 2ffa84fc30ae67828e4d2288dfe7ef894576867f Mon Sep 17 00:00:00 2001 From: Xiaozd <738140091@qq.com> Date: Thu, 19 Nov 2020 20:15:14 +0800 Subject: [PATCH 001/261] feat: fix bug in use of std::move --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index f62508d0..42aa41c2 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit f62508d0b8751eddb4d3cc6decce1b5ff550814a +Subproject commit 42aa41c273c9b9f4e40f36f85b3463db0c759d82 From dfb3d67f8ed45c6ce23043df1de76c3e1fd6d533 Mon Sep 17 00:00:00 2001 From: Xiaozd <738140091@qq.com> Date: Mon, 23 Nov 2020 10:45:17 +0800 Subject: [PATCH 002/261] docs: fix bug in docs --- doc/howto/how_to_online_send_point_cloud_ros.md | 2 -- doc/howto/how_to_record_and_offline_decode_rosbag.md | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/doc/howto/how_to_online_send_point_cloud_ros.md b/doc/howto/how_to_online_send_point_cloud_ros.md index 81c9b12a..1e36559b 100644 --- a/doc/howto/how_to_online_send_point_cloud_ros.md +++ b/doc/howto/how_to_online_send_point_cloud_ros.md @@ -36,8 +36,6 @@ lidar: msop_port: 6699 difop_port: 7788 start_angle: 0 - Run the demo & play the rosbag. - end_angle: 360 min_distance: 0.2 max_distance: 200 diff --git a/doc/howto/how_to_record_and_offline_decode_rosbag.md b/doc/howto/how_to_record_and_offline_decode_rosbag.md index 3c9f6a47..46f67f15 100644 --- a/doc/howto/how_to_record_and_offline_decode_rosbag.md +++ b/doc/howto/how_to_record_and_offline_decode_rosbag.md @@ -92,6 +92,6 @@ Set up the ```ros_recv_packet_topic``` to the ```msop``` topic in the rosbag. ### 3.4 Run -Run the program & play rosbag. +Run the demo & play rosbag. From 952389152c946bfbc5ee4a6f2841741da323dbb3 Mon Sep 17 00:00:00 2001 From: Xiaozd <738140091@qq.com> Date: Fri, 27 Nov 2020 18:09:11 +0800 Subject: [PATCH 003/261] docs: update docs --- README.md | 14 +++++++------- README_CN.md | 14 +++++++------- src/rs_driver | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 7feb51a6..5828225d 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,13 @@ ### **1.1 LiDAR Support** -- RS16 -- RS32 -- RSBP -- RS128 -- RS80 -- RSM1-B3 -- RSHELIOS +- RS-LiDAR-16 +- RS-LiDAR-32 +- RS-Bpearl +- RS-Ruby +- RS-Ruby Lite +- RS-LiDAR-M1 +- RS-Helios ### 1.2 Point type support diff --git a/README_CN.md b/README_CN.md index 3f281581..c34d7183 100644 --- a/README_CN.md +++ b/README_CN.md @@ -5,13 +5,13 @@ ### **1.1 雷达型号支持** -- RS16 -- RS32 -- RSBP -- RS128 -- RS80 -- RSM1-B3 -- RSHELIOS +- RS-LiDAR-16 +- RS-LiDAR-32 +- RS-Bpearl +- RS-Ruby +- RS-Ruby Lite +- RS-LiDAR-M1 +- RS-Helios ### 1.2 点的类型支持 diff --git a/src/rs_driver b/src/rs_driver index 42aa41c2..e1844a78 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 42aa41c273c9b9f4e40f36f85b3463db0c759d82 +Subproject commit e1844a78b1ca7821f8d20dc25d915887a4f0325c From 65c4de3003dfdd6e55cb08cf114c186f23c0b050 Mon Sep 17 00:00:00 2001 From: Xiaozd <738140091@qq.com> Date: Fri, 18 Dec 2020 14:50:51 +0800 Subject: [PATCH 004/261] feat: update driver core --- src/msg/ros_msg_translator.h | 3 ++- src/rs_driver | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/msg/ros_msg_translator.h b/src/msg/ros_msg_translator.h index 5d02cde0..a1f8a002 100644 --- a/src/msg/ros_msg_translator.h +++ b/src/msg/ros_msg_translator.h @@ -92,7 +92,8 @@ inline PacketMsg toRsMsg(const LidarType& lidar_type, const PktType& pkt_type, inline rslidar_msgs::rslidarPacket toRosMsg(const PacketMsg& rs_msg) { rslidar_msgs::rslidarPacket ros_msg; - for (size_t i = 0; i < rs_msg.packet.size(); i++) + size_t pkt_size = rs_msg.packet.size(); + for (size_t i = 0; i < pkt_size; i++) { ros_msg.data[i] = rs_msg.packet[i]; } diff --git a/src/rs_driver b/src/rs_driver index e1844a78..43ea6108 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit e1844a78b1ca7821f8d20dc25d915887a4f0325c +Subproject commit 43ea61085cb553ae8a0788642534fb1c759c152b From ac14237c7ceaebdc2640cee0150f6d559c910310 Mon Sep 17 00:00:00 2001 From: Xiaozd <738140091@qq.com> Date: Tue, 22 Dec 2020 14:36:21 +0800 Subject: [PATCH 005/261] feat: update fov setting part --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 43ea6108..66247a43 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 43ea61085cb553ae8a0788642534fb1c759c152b +Subproject commit 66247a433e5f489da26b36dc988578e55383ce71 From 84bfc7f4b356d39c74f9c9eab91eb2fb3c3226e5 Mon Sep 17 00:00:00 2001 From: Xiaozd <738140091@qq.com> Date: Thu, 31 Dec 2020 17:23:58 +0800 Subject: [PATCH 006/261] feat: update driver core --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 66247a43..a89fa5c8 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 66247a433e5f489da26b36dc988578e55383ce71 +Subproject commit a89fa5c807a9b8edf9d6a8a749507c39d52899de From eea2025b98cbe53418d9d49737f6db426fc3ca06 Mon Sep 17 00:00:00 2001 From: Xiaozd <738140091@qq.com> Date: Mon, 4 Jan 2021 10:46:44 +0800 Subject: [PATCH 007/261] feat: add vlan support --- config/config.yaml | 10 +++++----- src/adapter/driver_adapter.hpp | 1 + src/rs_driver | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 739d893e..8c3552c2 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -1,5 +1,5 @@ common: - msg_source: 1 #0: not use Lidar + msg_source: 3 #0: not use Lidar #1: packet message comes from online Lidar #2: packet message comes from ROS or ROS2 #3: packet message comes from Pcap file @@ -9,11 +9,10 @@ common: send_point_cloud_ros: true #true: Send point cloud through ROS or ROS2 send_packet_proto: false #true: Send packets through Protobuf-UDP send_point_cloud_proto: false #true: Send point cloud through Protobuf-UDP - pcap_path: /home/robosense/lidar.pcap #The path of pcap file - + pcap_path: /home/xzd/Downloads/5m.pcap #The path of pcap file lidar: - driver: - lidar_type: RS128 #LiDAR type - RS16, RS32, RSBP, RS128, RS80, RSM1, RSHELIOS + lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RS128, RS80, RSM1, RSHELIOS frame_id: /rslidar #Frame id of message msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar @@ -21,8 +20,9 @@ lidar: end_angle: 360 #End angle of point cloud min_distance: 0.2 #Minimum distance of point cloud max_distance: 200 #Maximum distance of point cloud + use_vlan: true #Use vlan or not use_lidar_clock: false #True--Use the lidar clock as the message timestamp - #False-- Use the system clock as the timestamp + #False-- Use the system clock as the timestamp ros: ros_recv_packet_topic: /rslidar_packets #Topic used to receive lidar packets from ROS ros_send_packet_topic: /rslidar_packets #Topic used to send lidar packets through ROS diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index 102af338..7d889601 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -108,6 +108,7 @@ inline void DriverAdapter::init(const YAML::Node& config) yamlRead(driver_config, "msop_port", driver_param.input_param.msop_port, 6699); yamlRead(driver_config, "difop_port", driver_param.input_param.difop_port, 7788); yamlRead(driver_config, "read_pcap", driver_param.input_param.read_pcap, false); + yamlRead(driver_config, "use_vlan", driver_param.input_param.use_vlan, false); yamlRead(driver_config, "pcap_rate", driver_param.input_param.pcap_rate, 1); yamlRead(driver_config, "pcap_repeat", driver_param.input_param.pcap_repeat, false); yamlRead(driver_config, "pcap_path", driver_param.input_param.pcap_path, ""); diff --git a/src/rs_driver b/src/rs_driver index a89fa5c8..c0fd75a3 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit a89fa5c807a9b8edf9d6a8a749507c39d52899de +Subproject commit c0fd75a382886849bc8505c8661ed8da6e733385 From f4cf9042ab543b7fd7168eb1a9ff37dde490a80d Mon Sep 17 00:00:00 2001 From: YufanFang Date: Tue, 20 Apr 2021 16:50:22 +0800 Subject: [PATCH 008/261] chore: add install command when buiding using catkin Also, use roslib to get package path if building using catkin --- CHANGELOG.md | 6 ++++++ CMakeLists.txt | 42 +++++++++++++++++++++++++++++++++++---- config/config.yaml | 2 +- node/rslidar_sdk_node.cpp | 12 ++++++++++- package_ros1.xml | 2 ++ 5 files changed, 58 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9228a799..0967ad38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## unrelease + +### Added + - add install command when building using catkin + + ## v1.3.0 - 2020-11-10 ### Added diff --git a/CMakeLists.txt b/CMakeLists.txt index 43346c65..bbb002a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,8 +31,11 @@ if(roscpp_FOUND) message(=============================================================) message("-- ROS Found, Ros Support is turned On!") message(=============================================================) + + find_package(roslib QUIET) add_definitions(-DROS_FOUND) - include_directories(${roscpp_INCLUDE_DIRS}) + include_directories(${roscpp_INCLUDE_DIRS} ${roslib_INCLUDE_DIRS}) + set(ROS_LIBS ${roscpp_LIBRARIES} ${roslib_LIBRARIES}) else(roscpp_FOUND) message(=============================================================) message("-- ROS Not Found, Ros Support is turned Off!") @@ -87,13 +90,14 @@ link_directories(${PCL_LIBRARY_DIRS}) add_definitions(${PCL_DEFINITIONS}) #Catkin# if(${COMPILE_METHOD} STREQUAL "CATKIN") + add_definitions(-DRUN_IN_ROS_WORKSPACE) find_package(catkin REQUIRED COMPONENTS roscpp sensor_msgs + roslib ) - catkin_package( - CATKIN_DEPENDS sensor_msgs + CATKIN_DEPENDS sensor_msgs roslib ) endif(${COMPILE_METHOD} STREQUAL "CATKIN") #Include directory# @@ -103,6 +107,21 @@ add_subdirectory(src/rs_driver) find_package(rs_driver REQUIRED) include_directories(${rs_driver_INCLUDE_DIRS}) +#Catkin# +if(${COMPILE_METHOD} STREQUAL "CATKIN") + add_definitions(-DRUN_IN_ROS_WORKSPACE) + find_package(catkin REQUIRED COMPONENTS + roscpp + sensor_msgs + roslib + ) + + catkin_package( + CATKIN_DEPENDS sensor_msgs roslib + DEPENDS PCL yaml-cpp rs_driver + ) +endif(${COMPILE_METHOD} STREQUAL "CATKIN") + #======================== # Point Type Definition #======================== @@ -146,7 +165,22 @@ else(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) endif(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) #Ros# if(roscpp_FOUND) - target_link_libraries(rslidar_sdk_node ${roscpp_LIBRARIES}) + target_link_libraries(rslidar_sdk_node ${ROS_LIBS}) + if(${COMPILE_METHOD} STREQUAL "CATKIN") + install(TARGETS rslidar_sdk_node + RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}) + install(DIRECTORY launch/ + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch + PATTERN ".svn" EXCLUDE) + install(DIRECTORY config/ + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/config + PATTERN ".svn" EXCLUDE) + install(DIRECTORY rviz/ + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/rviz + PATTERN ".svn" EXCLUDE) + endif() endif(roscpp_FOUND) #Ros2# if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") diff --git a/config/config.yaml b/config/config.yaml index 8c3552c2..3b2ea99c 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -1,5 +1,5 @@ common: - msg_source: 3 #0: not use Lidar + msg_source: 2 #0: not use Lidar #1: packet message comes from online Lidar #2: packet message comes from ROS or ROS2 #3: packet message comes from Pcap file diff --git a/node/rslidar_sdk_node.cpp b/node/rslidar_sdk_node.cpp index 336416a9..d3eae107 100644 --- a/node/rslidar_sdk_node.cpp +++ b/node/rslidar_sdk_node.cpp @@ -32,6 +32,11 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "manager/adapter_manager.h" + +#ifdef ROS_FOUND + #include +#endif + using namespace robosense::lidar; std::mutex g_mtx; std::condition_variable g_cv; @@ -58,7 +63,12 @@ int main(int argc, char** argv) YAML::Node config; try { - config = YAML::LoadFile((std::string)PROJECT_PATH + "/config/config.yaml"); + #ifdef RUN_IN_ROS_WORKSPACE + std::string path = ros::package::getPath("rslidar_sdk") ; + #else + std::string path = (std::string)PROJECT_PATH; + #endif + config = YAML::LoadFile((std::string)PROJECT_PATH + "/config/config.yaml"); } catch (...) { diff --git a/package_ros1.xml b/package_ros1.xml index c354985b..accbc186 100644 --- a/package_ros1.xml +++ b/package_ros1.xml @@ -9,7 +9,9 @@ roscpp sensor_msgs + roslib roscpp sensor_msgs + roslib \ No newline at end of file From 0ce473a2e3df8b129e15eaacab8641f9a1b64657 Mon Sep 17 00:00:00 2001 From: YufanFang Date: Tue, 20 Apr 2021 17:00:15 +0800 Subject: [PATCH 009/261] chore: remove catkin_depend on yaml-cpp --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bbb002a4..18b89780 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,7 +118,6 @@ if(${COMPILE_METHOD} STREQUAL "CATKIN") catkin_package( CATKIN_DEPENDS sensor_msgs roslib - DEPENDS PCL yaml-cpp rs_driver ) endif(${COMPILE_METHOD} STREQUAL "CATKIN") From 622c481562f8634f3d2b8d37227824b7aa181100 Mon Sep 17 00:00:00 2001 From: zhangbaoxian Date: Wed, 28 Jul 2021 19:46:37 +0800 Subject: [PATCH 010/261] feat: support someip --- src/adapter/driver_adapter.hpp | 1 + src/rs_driver | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index 7d889601..8b0b4b85 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -109,6 +109,7 @@ inline void DriverAdapter::init(const YAML::Node& config) yamlRead(driver_config, "difop_port", driver_param.input_param.difop_port, 7788); yamlRead(driver_config, "read_pcap", driver_param.input_param.read_pcap, false); yamlRead(driver_config, "use_vlan", driver_param.input_param.use_vlan, false); + yamlRead(driver_config, "use_someip", driver_param.input_param.use_someip, false); yamlRead(driver_config, "pcap_rate", driver_param.input_param.pcap_rate, 1); yamlRead(driver_config, "pcap_repeat", driver_param.input_param.pcap_repeat, false); yamlRead(driver_config, "pcap_path", driver_param.input_param.pcap_path, ""); diff --git a/src/rs_driver b/src/rs_driver index c0fd75a3..d0d9f1c9 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit c0fd75a382886849bc8505c8661ed8da6e733385 +Subproject commit d0d9f1c99ab18bdfb5a2875d6d0e9b43b819fe03 From 7383c75333507556a5c2abf2ada080500236ae5d Mon Sep 17 00:00:00 2001 From: zhangbaoxian Date: Thu, 29 Jul 2021 18:48:19 +0800 Subject: [PATCH 011/261] feat: set the config_path in the launch file for install --- .gitignore | 1 + CMakeLists.txt | 20 ++++----------- config/config.yaml | 4 +-- create_debian.sh | 47 ++++++++++++++++++++++++++++++++++ doc/howto/how_to_create_deb.md | 28 ++++++++++++++++++++ launch/start.launch | 1 + node/rslidar_sdk_node.cpp | 23 +++++++++++------ 7 files changed, 99 insertions(+), 25 deletions(-) create mode 100755 create_debian.sh create mode 100644 doc/howto/how_to_create_deb.md diff --git a/.gitignore b/.gitignore index 581c6ddb..01b13ecd 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ cmake-build-debug/ version.h *.pb.cc *.pb.h +package.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index 18b89780..4011ddfb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ project(rslidar_sdk) #======================================= # Compile setup (ORIGINAL, CATKIN, COLCON) #======================================= -set(COMPILE_METHOD ORIGINAL) +set(COMPILE_METHOD CATKIN) #======================================= # Custom Point Type (XYZI, XYZIRT) @@ -41,6 +41,7 @@ else(roscpp_FOUND) message("-- ROS Not Found, Ros Support is turned Off!") message(=============================================================) endif(roscpp_FOUND) + #ROS2# find_package(rclcpp QUIET) if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") @@ -59,6 +60,7 @@ else(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") message("-- ROS2 Not Found, Ros2 Support is turned Off!") message(=============================================================) endif(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") + #Protobuf# find_package(Protobuf QUIET) find_program(PROTOC protoc) @@ -82,12 +84,14 @@ else(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) message("-- Protobuf Not Found, Protobuf Support is turned Off!") message(=============================================================) endif(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) + #Others# find_package(yaml-cpp REQUIRED) find_package(PCL QUIET REQUIRED) include_directories(${PCL_INCLUDE_DIRS}) link_directories(${PCL_LIBRARY_DIRS}) add_definitions(${PCL_DEFINITIONS}) + #Catkin# if(${COMPILE_METHOD} STREQUAL "CATKIN") add_definitions(-DRUN_IN_ROS_WORKSPACE) @@ -107,20 +111,6 @@ add_subdirectory(src/rs_driver) find_package(rs_driver REQUIRED) include_directories(${rs_driver_INCLUDE_DIRS}) -#Catkin# -if(${COMPILE_METHOD} STREQUAL "CATKIN") - add_definitions(-DRUN_IN_ROS_WORKSPACE) - find_package(catkin REQUIRED COMPONENTS - roscpp - sensor_msgs - roslib - ) - - catkin_package( - CATKIN_DEPENDS sensor_msgs roslib - ) -endif(${COMPILE_METHOD} STREQUAL "CATKIN") - #======================== # Point Type Definition #======================== diff --git a/config/config.yaml b/config/config.yaml index 3b2ea99c..a16e1891 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -1,5 +1,5 @@ common: - msg_source: 2 #0: not use Lidar + msg_source: 1 #0: not use Lidar #1: packet message comes from online Lidar #2: packet message comes from ROS or ROS2 #3: packet message comes from Pcap file @@ -9,7 +9,7 @@ common: send_point_cloud_ros: true #true: Send point cloud through ROS or ROS2 send_packet_proto: false #true: Send packets through Protobuf-UDP send_point_cloud_proto: false #true: Send point cloud through Protobuf-UDP - pcap_path: /home/xzd/Downloads/5m.pcap #The path of pcap file + pcap_path: /home/robosense/lidar.pcap #The path of pcap file lidar: - driver: lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RS128, RS80, RSM1, RSHELIOS diff --git a/create_debian.sh b/create_debian.sh new file mode 100755 index 00000000..d432b89a --- /dev/null +++ b/create_debian.sh @@ -0,0 +1,47 @@ +#! /usr/bin/env bash + +## install the python-bloom fakeroot + +function install_pkg() +{ + pkg_found=$(dpkg -l | grep ${1}) + if [[ $? -eq 0 ]] + then + echo "${1} already installed." + else + echo "Install ${1} ..." + sudo apt-get install ${1} -y + fi +} + +install_pkg python-bloom +install_pkg fakeroot + +echo -e "\n\033[1;32m ~~ (1). Delete old debian folders in the directory...\033[0m" +rm -rf debian/ obj-x86_64-linux-gnu/ + +echo -e "\n\033[1;32m ~~ (2). Delete any backup files...\033[0m" +find . -type f -name '*~' -delete + +echo -e "\n\033[1;32m ~~ (3). Create debian packages...\033[0m\n" +bloom-generate rosdebian --os-name ubuntu --os-version `echo $(lsb_release -sc)` --ros-distro `echo ${ROS_DISTRO}` + +# sed 's#dh_shlibdeps*#dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info#g' debian/rules +## when dpkg-shlibdeps: error: no dependency information found for +## adding bellow code to debian/rules +## +## override_dh_shlibdeps: +## dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info +## It is necessary to insert a TAB instead of spaces before "dh_shlibdeps ..." + +target_string=$(grep "dh_shlibdeps " debian/rules) +replace_string=" dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info" +sed -i "s#${target_string}#${replace_string}#g" debian/rules + +fakeroot debian/rules binary + +echo -e "\n\033[1;32m ~~ (4). Delete old debian folders in the directory...\033[0m" +rm -rf debian/ obj-x86_64-linux-gnu/ + +echo -e "\n\033[1;32m ~~ (5). Delete any backup files...\033[0m" +find . -type f -name '*~' -delete diff --git a/doc/howto/how_to_create_deb.md b/doc/howto/how_to_create_deb.md new file mode 100644 index 00000000..c2aa4b56 --- /dev/null +++ b/doc/howto/how_to_create_deb.md @@ -0,0 +1,28 @@ +# How to create deb + +## 1 Introduction + +Generating a ".deb" installable file is useful. + +## 2 Create deb +Just run the shell script: +``` +./create_debian.sh +``` +The deb file will be generated in the parent directory of `rslidar_sdk`. +## 3 Use the deb +Install the deb and set the right config_path. If leave the config_path empty, it will use the `config.yaml` in the ros package path. + +``` + + + + + + + +``` + + + + diff --git a/launch/start.launch b/launch/start.launch index dbf20789..849e3b25 100755 --- a/launch/start.launch +++ b/launch/start.launch @@ -1,5 +1,6 @@ + diff --git a/node/rslidar_sdk_node.cpp b/node/rslidar_sdk_node.cpp index d3eae107..27b5210b 100644 --- a/node/rslidar_sdk_node.cpp +++ b/node/rslidar_sdk_node.cpp @@ -34,7 +34,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "manager/adapter_manager.h" #ifdef ROS_FOUND - #include +#include #endif using namespace robosense::lidar; @@ -63,12 +63,12 @@ int main(int argc, char** argv) YAML::Node config; try { - #ifdef RUN_IN_ROS_WORKSPACE - std::string path = ros::package::getPath("rslidar_sdk") ; - #else - std::string path = (std::string)PROJECT_PATH; - #endif - config = YAML::LoadFile((std::string)PROJECT_PATH + "/config/config.yaml"); +#ifdef RUN_IN_ROS_WORKSPACE + std::string path = ros::package::getPath("rslidar_sdk"); +#else + std::string path = (std::string)PROJECT_PATH; +#endif + config = YAML::LoadFile((std::string)path + "/config/config.yaml"); } catch (...) { @@ -78,6 +78,13 @@ int main(int argc, char** argv) #ifdef ROS_FOUND ///< if ROS is found, call the ros::init function ros::init(argc, argv, "rslidar_sdk_node", ros::init_options::NoSigintHandler); + ros::NodeHandle priv_hh("~"); + std::string config_path; + priv_hh.param("config_path", config_path, std::string("")); + if (!config_path.empty()) + { + config = YAML::LoadFile(config_path); + } #endif #ifdef ROS2_FOUND ///< if ROS2 is found, call the rclcpp::init function @@ -95,4 +102,4 @@ int main(int argc, char** argv) g_cv.wait(lck); #endif return 0; -} \ No newline at end of file +} From f95417baed6f927956f8a84db6ef16d702482b23 Mon Sep 17 00:00:00 2001 From: zhangbaoxian Date: Thu, 29 Jul 2021 18:55:18 +0800 Subject: [PATCH 012/261] fix: update rs_driver core for someip --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index d0d9f1c9..18ffb092 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit d0d9f1c99ab18bdfb5a2875d6d0e9b43b819fe03 +Subproject commit 18ffb092b2ab56bcb56072abf80621f9b9b45fca From 113bee97aaed90b85e2f6e80e27b1f2544e1a1ac Mon Sep 17 00:00:00 2001 From: zhangbaoxian Date: Thu, 5 Aug 2021 15:07:40 +0800 Subject: [PATCH 013/261] fix: add the online someip support drvier core --- CHANGELOG.md | 3 ++- src/rs_driver | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0967ad38..9a7be36d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Added - add install command when building using catkin + - add use_vlan and use_someip support ## v1.3.0 - 2020-11-10 @@ -66,4 +67,4 @@ - Support ROS & Protobuf-UDP functions - \ No newline at end of file + diff --git a/src/rs_driver b/src/rs_driver index 18ffb092..8867b438 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 18ffb092b2ab56bcb56072abf80621f9b9b45fca +Subproject commit 8867b4386bbcf20e72ed9430ffb555cb9a796597 From fd174739d6ab784a616c8e69c6207d1b177b7861 Mon Sep 17 00:00:00 2001 From: zhangbaoxian Date: Tue, 10 Aug 2021 11:57:41 +0800 Subject: [PATCH 014/261] docs: update doc --- doc/intro/hiding_parameters_intro.md | 6 +++--- doc/intro/hiding_parameters_intro_cn.md | 6 ++++-- src/rs_driver | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/doc/intro/hiding_parameters_intro.md b/doc/intro/hiding_parameters_intro.md index 6d2cb532..bffee5e6 100644 --- a/doc/intro/hiding_parameters_intro.md +++ b/doc/intro/hiding_parameters_intro.md @@ -3,7 +3,6 @@ In order to make the config file as simple as possible, we selectively hide some of the parameters and give them a default value in the program. If not added to ```config.yaml```, the default values will be used. This document explains the meanings of these these hidden parameters. - ## 1 common ```yaml @@ -63,5 +62,6 @@ lidar: - ```wait_for_difop``` -- If set to false, the driver will not wait for difop packet and send out the point cloud immediately. The default value is ```true```. - ```saved_by_rows``` -- The default point cloud is stored in **column major order**, which means if there is a point msg.point_cloud_ptr->at(i) , the next point on the same ring should be msg.point_cloud_ptr->at(i+msg.height). If this parameter is set to ```true``` , the point cloud will be stored in **row major order**. - ```multi_cast_address``` -- If use multi-cast function, this parameter need to be set correctly. For more details, please refer to [Multi-Cast](../howto/how_to_use_multi_cast_function.md) - -- ```x, y, z, roll, pitch, yaw ``` -- The parameters to do cooridiante transformation. If the coordinate transformation function is enabled in driver core, the output point cloud will be transformed based on these parameters. For more details, please refer to [Coordinate Transformation](../howto/how_to_use_coordinate_transformation.md) \ No newline at end of file +- ```x, y, z, roll, pitch, yaw ``` -- The parameters to do cooridiante transformation. If the coordinate transformation function is enabled in driver core, the output point cloud will be transformed based on these parameters. For more details, please refer to [Coordinate Transformation](../howto/how_to_use_coordinate_transformation.md) +- ```use_vlan``` -- Whether to use vlan. The default value is false. Generally, after the VLAN NIC is configured, the VLAN fields in the data packets are automatically filtered out after the data passes through the VLAN NIC. This does not need to be set to true in this case. Set this parameter to true only when the recevied data contains the VLAN field. For example, pcap data that is not recorded by the VLAN NIC. +- ```use_someip``` -- Whether to use someip, default is false. Set this parameter to true if the packet contains the SOME/IP field. \ No newline at end of file diff --git a/doc/intro/hiding_parameters_intro_cn.md b/doc/intro/hiding_parameters_intro_cn.md index 3cb9738d..427cc7af 100644 --- a/doc/intro/hiding_parameters_intro_cn.md +++ b/doc/intro/hiding_parameters_intro_cn.md @@ -60,6 +60,8 @@ lidar: - ```num_pkts_split``` -- 用于分帧的包数,在 ```split_frame_mode = 3```时才生效,默认值为1。 - ```wait_for_difop``` -- 若设置为false, 驱动将不会等待difop包而是立即解析并发出点云。 默认值为```true```,也就是必须要有difop包才会进行点云解析。 - ```saved_by_rows``` -- 点云的默认储存方式为```按列储存```,也就是说假设有一个点msg.point_cloud_ptr->at(i) ,那么与这个点同一行的下一个点应该为msg.point_cloud_ptr->at(i+msg.height)。如果此参数设置为```true```,那么输出的点云将会```按行储存```。 -- ```multi_cast_address``` -- 如果雷达为组播模式,此参数需要被设置为组播的地址。具体使用方式可以参考 [组播模式](../howto/how_to_use_multi_cast_function_cn.md) +- ```multi_cast_address``` -- 如果雷达为组播模式,此参数需要被设置为组播的地址。具体使用方式可以参考 [组播模式](../howto/how_to_use_multi_cast_function_cn.md) 。 -- ```x, y, z, roll, pitch, yaw ``` -- 坐标变换参数,若启用了内核的坐标变换功能,将会使用此参数输出经过变换后的点云。x, y, z, 单位为```米```, roll, pitch, yaw, 单位为```弧度```。具体使用方式可以参考 [坐标变换功能](../howto/how_to_use_coordinate_transformation_cn.md) \ No newline at end of file +- ```x, y, z, roll, pitch, yaw ``` -- 坐标变换参数,若启用了内核的坐标变换功能,将会使用此参数输出经过变换后的点云。x, y, z, 单位为```米```, roll, pitch, yaw, 单位为```弧度```。具体使用方式可以参考 [坐标变换功能](../howto/how_to_use_coordinate_transformation_cn.md) 。 +- ```use_vlan``` -- 是否使用vlan,默认为false。一般设置好vlan虚拟网卡之后,数据经过vlan网卡之后,数据包里里面的vlan字段会自动过滤掉。这种情况不需要设置为true。仅当在接收数据有vlan字段,如使用不是vlan网卡录的pcap数据,需要设置为true。 +- ```use_someip``` -- 是否使用someip,默认为false。当数据包中有SOME/IP字段,需要设置为true。 \ No newline at end of file diff --git a/src/rs_driver b/src/rs_driver index 8867b438..17b0d568 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 8867b4386bbcf20e72ed9430ffb555cb9a796597 +Subproject commit 17b0d568c7226c43ad5b6c007a09b4d30b8120c7 From 56f8a5208f5260250d1872b1fbbdd603a6cd6b9a Mon Sep 17 00:00:00 2001 From: baoxianzhang Date: Tue, 10 Aug 2021 14:36:36 +0800 Subject: [PATCH 015/261] feat: update core submodule --- .gitmodules | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index bdbd212d..cfd2e6ab 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,4 @@ [submodule "src/rs_driver"] path = src/rs_driver - url = git@192.168.1.20:rs_share/rs_driver.git + url = https://github.com/RoboSense-LiDAR/rs_driver.git + branch = dev From 03e0b6169f360aee9c6d32e78d1159117721ea1d Mon Sep 17 00:00:00 2001 From: zhangbaoxian Date: Wed, 11 Aug 2021 20:29:26 +0800 Subject: [PATCH 016/261] feat: update drvier core, better someip support --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 17b0d568..28aced9c 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 17b0d568c7226c43ad5b6c007a09b4d30b8120c7 +Subproject commit 28aced9c4ba11f9121ded75fa01b39726a959be7 From da28431b507b4db4afb34eb0d88a53b48710f782 Mon Sep 17 00:00:00 2001 From: baoxianzhang Date: Wed, 11 Aug 2021 20:37:21 +0800 Subject: [PATCH 017/261] feat: update core driver for better someip support --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 17b0d568..28aced9c 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 17b0d568c7226c43ad5b6c007a09b4d30b8120c7 +Subproject commit 28aced9c4ba11f9121ded75fa01b39726a959be7 From c22bee6b64ed5b2ac35acf6d33c4bdce10e85b8b Mon Sep 17 00:00:00 2001 From: ronzheng Date: Wed, 27 Oct 2021 17:32:44 +0800 Subject: [PATCH 018/261] feat: replace point with point cloud as template param --- src/adapter/driver_adapter.hpp | 27 ++++-------------- src/msg/proto_msg_translator.h | 26 ++++++++--------- src/msg/ros_msg_translator.h | 6 ++-- src/msg/rs_msg/lidar_point_cloud_msg.h | 39 ++++++++++++++------------ src/rs_driver | 2 +- 5 files changed, 43 insertions(+), 57 deletions(-) diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index 8b0b4b85..9a8cbab4 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -54,15 +54,14 @@ class DriverAdapter : virtual public AdapterBase void decodePacket(const PacketMsg& msg); private: - void localPointsCallback(const PointCloudMsg& msg); + void localPointsCallback(const LidarPointCloudMsg& msg); void localScanCallback(const ScanMsg& msg); void localPacketCallback(const PacketMsg& msg); void localCameraTriggerCallback(const CameraTrigger& msg); void localExceptionCallback(const lidar::Error& msg); - LidarPointCloudMsg core2SDK(const lidar::PointCloudMsg& msg); private: - std::shared_ptr> driver_ptr_; + std::shared_ptr> driver_ptr_; std::vector> point_cloud_cb_vec_; std::vector> scan_cb_vec_; std::vector> packet_cb_vec_; @@ -72,7 +71,7 @@ class DriverAdapter : virtual public AdapterBase inline DriverAdapter::DriverAdapter() { - driver_ptr_.reset(new lidar::LidarDriver()); + driver_ptr_.reset(new lidar::LidarDriver()); thread_pool_ptr_.reset(new lidar::ThreadPool()); driver_ptr_->regExceptionCallback(std::bind(&DriverAdapter::localExceptionCallback, this, std::placeholders::_1)); } @@ -191,7 +190,7 @@ inline void DriverAdapter::regRecvCallback(const std::function point_cloud_msg; + LidarPointCloudMsg point_cloud_msg; if (driver_ptr_->decodeMsopScan(msg, point_cloud_msg)) { localPointsCallback(point_cloud_msg); @@ -203,11 +202,11 @@ inline void DriverAdapter::decodePacket(const PacketMsg& msg) driver_ptr_->decodeDifopPkt(msg); } -inline void DriverAdapter::localPointsCallback(const PointCloudMsg& msg) +inline void DriverAdapter::localPointsCallback(const LidarPointCloudMsg& msg) { for (auto iter : point_cloud_cb_vec_) { - thread_pool_ptr_->commit([this, msg, iter]() { iter(core2SDK(msg)); }); + thread_pool_ptr_->commit([this, msg, iter]() { iter(msg); }); } } @@ -251,19 +250,5 @@ inline void DriverAdapter::localExceptionCallback(const lidar::Error& msg) } } -inline LidarPointCloudMsg DriverAdapter::core2SDK(const lidar::PointCloudMsg& msg) -{ - LidarPointCloudMsg::PointCloudPtr point_cloud(new LidarPointCloudMsg::PointCloud); - point_cloud->points.assign(msg.point_cloud_ptr->begin(), msg.point_cloud_ptr->end()); - point_cloud->height = msg.height; - point_cloud->width = msg.width; - point_cloud->is_dense = msg.is_dense; - LidarPointCloudMsg point_cloud_msg(point_cloud); - point_cloud_msg.frame_id = msg.frame_id; - point_cloud_msg.timestamp = msg.timestamp; - point_cloud_msg.seq = msg.seq; - return std::move(point_cloud_msg); -} - } // namespace lidar } // namespace robosense diff --git a/src/msg/proto_msg_translator.h b/src/msg/proto_msg_translator.h index 32f1e61d..7f8ea73e 100644 --- a/src/msg/proto_msg_translator.h +++ b/src/msg/proto_msg_translator.h @@ -51,16 +51,16 @@ inline proto_msg::LidarPointCloud toProtoMsg(const LidarPointCloudMsg& rs_msg) proto_msg.set_timestamp(rs_msg.timestamp); proto_msg.set_seq(rs_msg.seq); proto_msg.set_frame_id(rs_msg.frame_id); - proto_msg.set_height(rs_msg.point_cloud_ptr->height); - proto_msg.set_width(rs_msg.point_cloud_ptr->width); - proto_msg.set_is_dense(rs_msg.point_cloud_ptr->is_dense); + proto_msg.set_height(rs_msg.height); + proto_msg.set_width(rs_msg.width); + proto_msg.set_is_dense(rs_msg.is_dense); - for (size_t i = 0; i < rs_msg.point_cloud_ptr->size(); i++) + for (size_t i = 0; i < rs_msg.size(); i++) { - proto_msg.add_data(rs_msg.point_cloud_ptr->points[i].x); - proto_msg.add_data(rs_msg.point_cloud_ptr->points[i].y); - proto_msg.add_data(rs_msg.point_cloud_ptr->points[i].z); - proto_msg.add_data(rs_msg.point_cloud_ptr->points[i].intensity); + proto_msg.add_data(rs_msg.points[i].x); + proto_msg.add_data(rs_msg.points[i].y); + proto_msg.add_data(rs_msg.points[i].z); + proto_msg.add_data(rs_msg.points[i].intensity); } return std::move(proto_msg); @@ -72,7 +72,6 @@ inline LidarPointCloudMsg toRsMsg(const proto_msg::LidarPointCloud& proto_msg) rs_msg.timestamp = proto_msg.timestamp(); rs_msg.seq = proto_msg.seq(); rs_msg.frame_id = proto_msg.frame_id(); - LidarPointCloudMsg::PointCloud* ptr_tmp = new LidarPointCloudMsg::PointCloud(); for (int i = 0; i < proto_msg.data_size(); i += 4) { PointT point; @@ -80,12 +79,11 @@ inline LidarPointCloudMsg toRsMsg(const proto_msg::LidarPointCloud& proto_msg) point.y = proto_msg.data(i + 1); point.z = proto_msg.data(i + 2); point.intensity = proto_msg.data(i + 3); - ptr_tmp->push_back(point); + rs_msg.points.push_back(point); } - ptr_tmp->height = proto_msg.height(); - ptr_tmp->width = proto_msg.width(); - ptr_tmp->is_dense = proto_msg.is_dense(); - rs_msg.point_cloud_ptr.reset(ptr_tmp); + rs_msg.height = proto_msg.height(); + rs_msg.width = proto_msg.width(); + rs_msg.is_dense = proto_msg.is_dense(); return rs_msg; } diff --git a/src/msg/ros_msg_translator.h b/src/msg/ros_msg_translator.h index a1f8a002..995d4750 100644 --- a/src/msg/ros_msg_translator.h +++ b/src/msg/ros_msg_translator.h @@ -56,7 +56,7 @@ namespace lidar inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) { sensor_msgs::PointCloud2 ros_msg; - pcl::toROSMsg(*rs_msg.point_cloud_ptr, ros_msg); + pcl::toROSMsg(rs_msg, ros_msg); ros_msg.header.stamp = ros_msg.header.stamp.fromSec(rs_msg.timestamp); ros_msg.header.frame_id = rs_msg.frame_id; ros_msg.header.seq = rs_msg.seq; @@ -152,7 +152,7 @@ namespace lidar inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) { sensor_msgs::msg::PointCloud2 ros_msg; - pcl::toROSMsg(*rs_msg.point_cloud_ptr, ros_msg); + pcl::toROSMsg(rs_msg, ros_msg); ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); ros_msg.header.stamp.nanosec = (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); ros_msg.header.frame_id = rs_msg.frame_id; @@ -222,4 +222,4 @@ inline rslidar_msg::msg::RslidarScan toRosMsg(const ScanMsg& rs_msg) } } // namespace lidar } // namespace robosense -#endif // ROS2_FOUND \ No newline at end of file +#endif // ROS2_FOUND diff --git a/src/msg/rs_msg/lidar_point_cloud_msg.h b/src/msg/rs_msg/lidar_point_cloud_msg.h index 412e2c89..49b41cdc 100644 --- a/src/msg/rs_msg/lidar_point_cloud_msg.h +++ b/src/msg/rs_msg/lidar_point_cloud_msg.h @@ -31,13 +31,22 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *********************************************************************************************************************/ #pragma once + #include #include + #include #include + +#ifdef POINT_TYPE_XYZI + +typedef pcl::PointXYZI PointT; + +#elif POINT_TYPE_XYZIRT + struct RsPointXYZIRT { - PCL_ADD_POINT4D; + uint8_t intensity; uint16_t ring = 0; double timestamp = 0; @@ -45,11 +54,9 @@ struct RsPointXYZIRT } EIGEN_ALIGN16; POINT_CLOUD_REGISTER_POINT_STRUCT(RsPointXYZIRT, (float, x, x)(float, y, y)(float, z, z)(uint8_t, intensity, intensity)( uint16_t, ring, ring)(double, timestamp, timestamp)) -#ifdef POINT_TYPE_XYZI -typedef pcl::PointXYZI PointT; -#elif POINT_TYPE_XYZIRT typedef RsPointXYZIRT PointT; + #endif namespace robosense @@ -63,24 +70,20 @@ namespace lidar * If Proto is turned on , we provide translation functions between Protobuf message and RoboSense message */ -struct alignas(16) LidarPointCloudMsg +template +class PointCloudT : public pcl::PointCloud { - typedef pcl::PointCloud PointCloud; - typedef pcl::PointCloud::Ptr PointCloudPtr; - typedef pcl::PointCloud::ConstPtr PointCloudConstPtr; - double timestamp = 0.0; - uint32_t seq = 0; - std::string frame_id = ""; +public: - PointCloudConstPtr point_cloud_ptr; ///< the point cloud pointer + typedef T_Point PointT; + typedef typename pcl::PointCloud::VectorType VectorT; - LidarPointCloudMsg() = default; - LidarPointCloudMsg(const PointCloudPtr& ptr) : point_cloud_ptr(ptr) - { - } - typedef std::shared_ptr Ptr; - typedef std::shared_ptr ConstPtr; + double timestamp = 0.0; + std::string frame_id = ""; ///< Point cloud frame id + uint32_t seq = 0; ///< Sequence number of message }; +typedef PointCloudT LidarPointCloudMsg; + } // namespace lidar } // namespace robosense diff --git a/src/rs_driver b/src/rs_driver index 28aced9c..c8e1ff8a 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 28aced9c4ba11f9121ded75fa01b39726a959be7 +Subproject commit c8e1ff8a74f39c7e49d0aa23ab9d9f01da233270 From 799053b4eb577e75f1583d8d6113a5602d70d47f Mon Sep 17 00:00:00 2001 From: ronzheng Date: Thu, 28 Oct 2021 10:34:50 +0800 Subject: [PATCH 019/261] feat: config as BP --- config/config.yaml | 3 ++- launch/start.launch | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index a16e1891..3131f6f4 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -12,7 +12,8 @@ common: pcap_path: /home/robosense/lidar.pcap #The path of pcap file lidar: - driver: - lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RS128, RS80, RSM1, RSHELIOS + lidar_type: RSBP #LiDAR type - RS16, RS32, RSBP, RS128, RS80, RSM1, RSHELIOS + angle_path: /mnt/share/channel_bp/angle.csv frame_id: /rslidar #Frame id of message msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar diff --git a/launch/start.launch b/launch/start.launch index 849e3b25..4fcfa14a 100755 --- a/launch/start.launch +++ b/launch/start.launch @@ -3,5 +3,5 @@ - + From 741c92ad2379aee472e20357b066433ced3844e5 Mon Sep 17 00:00:00 2001 From: ronzheng Date: Thu, 28 Oct 2021 10:38:39 +0800 Subject: [PATCH 020/261] fix: fix point cloud msg --- src/msg/rs_msg/lidar_point_cloud_msg.h | 2 +- src/rs_driver | 2 +- src/rs_driver_2 | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) create mode 160000 src/rs_driver_2 diff --git a/src/msg/rs_msg/lidar_point_cloud_msg.h b/src/msg/rs_msg/lidar_point_cloud_msg.h index 49b41cdc..10e2f631 100644 --- a/src/msg/rs_msg/lidar_point_cloud_msg.h +++ b/src/msg/rs_msg/lidar_point_cloud_msg.h @@ -46,7 +46,7 @@ typedef pcl::PointXYZI PointT; struct RsPointXYZIRT { - + PCL_ADD_POINT4D; uint8_t intensity; uint16_t ring = 0; double timestamp = 0; diff --git a/src/rs_driver b/src/rs_driver index c8e1ff8a..734bb08d 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit c8e1ff8a74f39c7e49d0aa23ab9d9f01da233270 +Subproject commit 734bb08d9a6e72e317c0e412bc87cebbaa07c4d3 diff --git a/src/rs_driver_2 b/src/rs_driver_2 new file mode 160000 index 00000000..d339c5d5 --- /dev/null +++ b/src/rs_driver_2 @@ -0,0 +1 @@ +Subproject commit d339c5d58b5d7ef3c2f07f128f088f6bc3269063 From c1cb24379d2e07a19aa5fd8eb7d9da35abcf7cf7 Mon Sep 17 00:00:00 2001 From: ronzheng Date: Thu, 28 Oct 2021 15:02:51 +0800 Subject: [PATCH 021/261] feat: disable thread pool --- src/adapter/driver_adapter.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index 9a8cbab4..b93a9d02 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -206,7 +206,8 @@ inline void DriverAdapter::localPointsCallback(const LidarPointCloudMsg& msg) { for (auto iter : point_cloud_cb_vec_) { - thread_pool_ptr_->commit([this, msg, iter]() { iter(msg); }); + //thread_pool_ptr_->commit([this, msg, iter]() { iter(msg); }); + iter(msg);; } } From a8747e71881fe60f013b541a7be49f64b9e4673b Mon Sep 17 00:00:00 2001 From: ronzheng Date: Sat, 30 Oct 2021 12:58:12 +0800 Subject: [PATCH 022/261] feat: diable vlan setting --- config/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.yaml b/config/config.yaml index 3131f6f4..40287ba3 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -21,7 +21,7 @@ lidar: end_angle: 360 #End angle of point cloud min_distance: 0.2 #Minimum distance of point cloud max_distance: 200 #Maximum distance of point cloud - use_vlan: true #Use vlan or not + use_vlan: false #Use vlan or not use_lidar_clock: false #True--Use the lidar clock as the message timestamp #False-- Use the system clock as the timestamp ros: From 7cec9b39996a4d1dbf648355c981ccc10ed809c1 Mon Sep 17 00:00:00 2001 From: ronzheng Date: Mon, 1 Nov 2021 10:53:05 +0800 Subject: [PATCH 023/261] feat: recover default config.yaml --- config/config.yaml | 4 +--- launch/start.launch | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 40287ba3..0c132002 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -12,8 +12,7 @@ common: pcap_path: /home/robosense/lidar.pcap #The path of pcap file lidar: - driver: - lidar_type: RSBP #LiDAR type - RS16, RS32, RSBP, RS128, RS80, RSM1, RSHELIOS - angle_path: /mnt/share/channel_bp/angle.csv + lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RS128, RS80, RSM1, RSHELIOS frame_id: /rslidar #Frame id of message msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar @@ -21,7 +20,6 @@ lidar: end_angle: 360 #End angle of point cloud min_distance: 0.2 #Minimum distance of point cloud max_distance: 200 #Maximum distance of point cloud - use_vlan: false #Use vlan or not use_lidar_clock: false #True--Use the lidar clock as the message timestamp #False-- Use the system clock as the timestamp ros: diff --git a/launch/start.launch b/launch/start.launch index 4fcfa14a..849e3b25 100755 --- a/launch/start.launch +++ b/launch/start.launch @@ -3,5 +3,5 @@ - + From 361935384e92d8845a958652ed51bdf44a7c5fef Mon Sep 17 00:00:00 2001 From: ronzheng Date: Mon, 1 Nov 2021 11:04:26 +0800 Subject: [PATCH 024/261] style: do clang-format --- src/adapter/driver_adapter.hpp | 5 +++-- src/msg/rs_msg/lidar_point_cloud_msg.h | 7 +++---- src/rs_driver_2 | 1 - src/utility/protobuf_communicator.hpp | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) delete mode 160000 src/rs_driver_2 diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index b93a9d02..8f095c85 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -206,8 +206,9 @@ inline void DriverAdapter::localPointsCallback(const LidarPointCloudMsg& msg) { for (auto iter : point_cloud_cb_vec_) { - //thread_pool_ptr_->commit([this, msg, iter]() { iter(msg); }); - iter(msg);; + // thread_pool_ptr_->commit([this, msg, iter]() { iter(msg); }); + iter(msg); + ; } } diff --git a/src/msg/rs_msg/lidar_point_cloud_msg.h b/src/msg/rs_msg/lidar_point_cloud_msg.h index 10e2f631..b7206132 100644 --- a/src/msg/rs_msg/lidar_point_cloud_msg.h +++ b/src/msg/rs_msg/lidar_point_cloud_msg.h @@ -74,16 +74,15 @@ template class PointCloudT : public pcl::PointCloud { public: - typedef T_Point PointT; typedef typename pcl::PointCloud::VectorType VectorT; double timestamp = 0.0; - std::string frame_id = ""; ///< Point cloud frame id - uint32_t seq = 0; ///< Sequence number of message + std::string frame_id = ""; ///< Point cloud frame id + uint32_t seq = 0; ///< Sequence number of message }; -typedef PointCloudT LidarPointCloudMsg; +typedef PointCloudT LidarPointCloudMsg; } // namespace lidar } // namespace robosense diff --git a/src/rs_driver_2 b/src/rs_driver_2 deleted file mode 160000 index d339c5d5..00000000 --- a/src/rs_driver_2 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d339c5d58b5d7ef3c2f07f128f088f6bc3269063 diff --git a/src/utility/protobuf_communicator.hpp b/src/utility/protobuf_communicator.hpp index 240f9fb0..90f17cfa 100644 --- a/src/utility/protobuf_communicator.hpp +++ b/src/utility/protobuf_communicator.hpp @@ -382,7 +382,7 @@ class ProtoCommunicator deadline_->async_wait(boost::bind(&ProtoCommunicator::checkDeadline, this)); } static void handleReceive(const boost::system::error_code& ec, std::size_t length, boost::system::error_code* out_ec, - std::size_t* out_length) + std::size_t* out_length) { *out_ec = ec; *out_length = length; From 1f9e1802bdca52cd7fad785e7e669749a5d8d3d5 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 1 Nov 2021 15:20:20 +0800 Subject: [PATCH 025/261] feat: update CHANGELOG.md --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a7be36d..314b7170 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Changelog -## unrelease +## v1.4.0 + +### Updated + - replace point with point cloud, as rs_driver's template parameter + - handle point cloud in rs_driver's thread + +## v1.3.1 ### Added - add install command when building using catkin From ad52e921e151db8d3ff96515214635bca1144e7e Mon Sep 17 00:00:00 2001 From: ronzheng Date: Thu, 4 Nov 2021 15:16:55 +0800 Subject: [PATCH 026/261] feat: support to bind host ip --- src/adapter/driver_adapter.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index 8f095c85..34f2d941 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -104,6 +104,7 @@ inline void DriverAdapter::init(const YAML::Node& config) yamlRead(driver_config, "cut_angle", driver_param.decoder_param.cut_angle, 0); yamlRead(driver_config, "device_ip", driver_param.input_param.device_ip, "192.168.1.200"); yamlRead(driver_config, "multi_cast_address", driver_param.input_param.multi_cast_address, "0.0.0.0"); + yamlRead(driver_config, "host_address", driver_param.input_param.host_address, "0.0.0.0"); yamlRead(driver_config, "msop_port", driver_param.input_param.msop_port, 6699); yamlRead(driver_config, "difop_port", driver_param.input_param.difop_port, 7788); yamlRead(driver_config, "read_pcap", driver_param.input_param.read_pcap, false); From e7d2e8b3e37ec3143dce559296c56405a9598562 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 4 Nov 2021 15:33:28 +0800 Subject: [PATCH 027/261] feat: update doc of binding host ip --- doc/intro/hiding_parameters_intro.md | 4 +++- doc/intro/hiding_parameters_intro_cn.md | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/intro/hiding_parameters_intro.md b/doc/intro/hiding_parameters_intro.md index bffee5e6..19d77ec1 100644 --- a/doc/intro/hiding_parameters_intro.md +++ b/doc/intro/hiding_parameters_intro.md @@ -44,6 +44,7 @@ lidar: wait_for_difop: true saved_by_rows: false multi_cast_address: 0.0.0.0 + host_address: 0.0.0.0 x: 0 y: 0 z: 0 @@ -62,6 +63,7 @@ lidar: - ```wait_for_difop``` -- If set to false, the driver will not wait for difop packet and send out the point cloud immediately. The default value is ```true```. - ```saved_by_rows``` -- The default point cloud is stored in **column major order**, which means if there is a point msg.point_cloud_ptr->at(i) , the next point on the same ring should be msg.point_cloud_ptr->at(i+msg.height). If this parameter is set to ```true``` , the point cloud will be stored in **row major order**. - ```multi_cast_address``` -- If use multi-cast function, this parameter need to be set correctly. For more details, please refer to [Multi-Cast](../howto/how_to_use_multi_cast_function.md) +- ```host_address``` -- If the host receives packets from multiple lidars via different IP addresses, use this parameter to specify destination ip of the lidar. - ```x, y, z, roll, pitch, yaw ``` -- The parameters to do cooridiante transformation. If the coordinate transformation function is enabled in driver core, the output point cloud will be transformed based on these parameters. For more details, please refer to [Coordinate Transformation](../howto/how_to_use_coordinate_transformation.md) - ```use_vlan``` -- Whether to use vlan. The default value is false. Generally, after the VLAN NIC is configured, the VLAN fields in the data packets are automatically filtered out after the data passes through the VLAN NIC. This does not need to be set to true in this case. Set this parameter to true only when the recevied data contains the VLAN field. For example, pcap data that is not recorded by the VLAN NIC. -- ```use_someip``` -- Whether to use someip, default is false. Set this parameter to true if the packet contains the SOME/IP field. \ No newline at end of file +- ```use_someip``` -- Whether to use someip, default is false. Set this parameter to true if the packet contains the SOME/IP field. diff --git a/doc/intro/hiding_parameters_intro_cn.md b/doc/intro/hiding_parameters_intro_cn.md index 427cc7af..10d89efc 100644 --- a/doc/intro/hiding_parameters_intro_cn.md +++ b/doc/intro/hiding_parameters_intro_cn.md @@ -43,6 +43,7 @@ lidar: wait_for_difop: true saved_by_rows: false multi_cast_address: 0.0.0.0 + host_address: 0.0.0.0 x: 0 y: 0 z: 0 @@ -61,7 +62,8 @@ lidar: - ```wait_for_difop``` -- 若设置为false, 驱动将不会等待difop包而是立即解析并发出点云。 默认值为```true```,也就是必须要有difop包才会进行点云解析。 - ```saved_by_rows``` -- 点云的默认储存方式为```按列储存```,也就是说假设有一个点msg.point_cloud_ptr->at(i) ,那么与这个点同一行的下一个点应该为msg.point_cloud_ptr->at(i+msg.height)。如果此参数设置为```true```,那么输出的点云将会```按行储存```。 - ```multi_cast_address``` -- 如果雷达为组播模式,此参数需要被设置为组播的地址。具体使用方式可以参考 [组播模式](../howto/how_to_use_multi_cast_function_cn.md) 。 +- ```host_address``` -- 如果主机上通过多个IP地址接收多个雷达的数据,则可以将此参数指定为雷达的目标IP。 - ```x, y, z, roll, pitch, yaw ``` -- 坐标变换参数,若启用了内核的坐标变换功能,将会使用此参数输出经过变换后的点云。x, y, z, 单位为```米```, roll, pitch, yaw, 单位为```弧度```。具体使用方式可以参考 [坐标变换功能](../howto/how_to_use_coordinate_transformation_cn.md) 。 - ```use_vlan``` -- 是否使用vlan,默认为false。一般设置好vlan虚拟网卡之后,数据经过vlan网卡之后,数据包里里面的vlan字段会自动过滤掉。这种情况不需要设置为true。仅当在接收数据有vlan字段,如使用不是vlan网卡录的pcap数据,需要设置为true。 -- ```use_someip``` -- 是否使用someip,默认为false。当数据包中有SOME/IP字段,需要设置为true。 \ No newline at end of file +- ```use_someip``` -- 是否使用someip,默认为false。当数据包中有SOME/IP字段,需要设置为true。 From d9ffeaf67eef418d66898ab9942d314e172291ca Mon Sep 17 00:00:00 2001 From: ronzheng Date: Fri, 5 Nov 2021 18:50:33 +0800 Subject: [PATCH 028/261] feat: support dense attribute --- src/adapter/driver_adapter.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index 34f2d941..96f2895a 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -95,6 +95,7 @@ inline void DriverAdapter::init(const YAML::Node& config) yamlRead(driver_config, "wait_for_difop", driver_param.wait_for_difop, true); yamlRead(driver_config, "saved_by_rows", driver_param.saved_by_rows, false); yamlRead(driver_config, "use_lidar_clock", driver_param.decoder_param.use_lidar_clock, false); + yamlRead(driver_config, "is_dense", driver_param.decoder_param.is_dense, false); yamlRead(driver_config, "min_distance", driver_param.decoder_param.min_distance, 0.2); yamlRead(driver_config, "max_distance", driver_param.decoder_param.max_distance, 200); yamlRead(driver_config, "start_angle", driver_param.decoder_param.start_angle, 0); From 6c09acd5f7d0e92af3ff4eff11031b6eba31fb6c Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 8 Nov 2021 10:06:47 +0800 Subject: [PATCH 029/261] feat: update is_dense doc --- doc/intro/hiding_parameters_intro.md | 2 ++ doc/intro/hiding_parameters_intro_cn.md | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/intro/hiding_parameters_intro.md b/doc/intro/hiding_parameters_intro.md index 19d77ec1..d733a1ef 100644 --- a/doc/intro/hiding_parameters_intro.md +++ b/doc/intro/hiding_parameters_intro.md @@ -38,6 +38,7 @@ lidar: max_distance: 200 use_lidar_clock: false angle_path: /home/robosense/angle.csv + is_dense: true split_frame_mode: 1 cut_angle: 0 num_pkts_split: 1 @@ -54,6 +55,7 @@ lidar: ``` - ```angle_path``` -- The path of the angle.csv. For latest version of LiDARs, this parameter can be ignored. +- ```is_dense``` -- Whether to discard NAN points. discard if ```true```, reserve if ```false```. The default value is ```false```. - ```split_frame_mode``` -- The mode to split the LiDAR frames. Default value is ```1```. - 1 -- Spliting frames depending on the cut_angle - 2 -- Spliting frames depending on a fixed number of packets diff --git a/doc/intro/hiding_parameters_intro_cn.md b/doc/intro/hiding_parameters_intro_cn.md index 10d89efc..140aaebf 100644 --- a/doc/intro/hiding_parameters_intro_cn.md +++ b/doc/intro/hiding_parameters_intro_cn.md @@ -37,9 +37,10 @@ lidar: max_distance: 200 use_lidar_clock: false angle_path: /home/robosense/angle.csv + is_dense: true split_frame_mode: 1 cut_angle: 0 - num_pkts_split: 1 + num_pkts_split: 1 wait_for_difop: true saved_by_rows: false multi_cast_address: 0.0.0.0 @@ -53,6 +54,7 @@ lidar: ``` - ```angle_path``` -- angle.csv外参文件的路径,仅用于调试,可忽略。 +- ```is_dense``` -- 输出的点云中是否剔除NAN points。```true```为剔除,```false```为不剔除。默认值为```false```。 - ```split_frame_mode``` -- 分帧模式设置,默认值为```1```。 - 1 -- 角度分帧 - 2 -- 固定包数分帧 From 977b581e9afca3cfe465b832b66a08cf65b874a4 Mon Sep 17 00:00:00 2001 From: ronzheng Date: Mon, 8 Nov 2021 12:05:27 +0800 Subject: [PATCH 030/261] feat: update rs_driver submodule link --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index bdbd212d..a6862c11 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "src/rs_driver"] path = src/rs_driver - url = git@192.168.1.20:rs_share/rs_driver.git + url = http://gitlab.robosense.cn/rs_share/rslidar/rs_driver.git From b5bde73c8d1e16135238f4f7968d15e26d59e22c Mon Sep 17 00:00:00 2001 From: ronzheng Date: Mon, 8 Nov 2021 18:17:41 +0800 Subject: [PATCH 031/261] feat: bind to the specified ip --- src/adapter/driver_adapter.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index 8b0b4b85..a2ac515e 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -105,6 +105,7 @@ inline void DriverAdapter::init(const YAML::Node& config) yamlRead(driver_config, "cut_angle", driver_param.decoder_param.cut_angle, 0); yamlRead(driver_config, "device_ip", driver_param.input_param.device_ip, "192.168.1.200"); yamlRead(driver_config, "multi_cast_address", driver_param.input_param.multi_cast_address, "0.0.0.0"); + yamlRead(driver_config, "host_address", driver_param.input_param.host_address, "0.0.0.0"); yamlRead(driver_config, "msop_port", driver_param.input_param.msop_port, 6699); yamlRead(driver_config, "difop_port", driver_param.input_param.difop_port, 7788); yamlRead(driver_config, "read_pcap", driver_param.input_param.read_pcap, false); From 5306ff3b4a18834bec053496075fe423cf4a9e67 Mon Sep 17 00:00:00 2001 From: ronzheng Date: Mon, 8 Nov 2021 18:38:13 +0800 Subject: [PATCH 032/261] feat: update submodule link --- .gitmodules | 3 ++- src/rs_driver | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index a6862c11..b7a6d10f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,4 @@ [submodule "src/rs_driver"] path = src/rs_driver - url = http://gitlab.robosense.cn/rs_share/rslidar/rs_driver.git + url = git@192.168.1.20:rs_share/rs_driver.git + branch = dev_opt diff --git a/src/rs_driver b/src/rs_driver index 734bb08d..890b61da 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 734bb08d9a6e72e317c0e412bc87cebbaa07c4d3 +Subproject commit 890b61daa5f645d80744429b6a7f454b924d7a4b From 34f6bbeffec22baa7636f6bc7581243d21d6848e Mon Sep 17 00:00:00 2001 From: ronzheng Date: Tue, 9 Nov 2021 16:59:01 +0800 Subject: [PATCH 033/261] feat: add callback_point_cloud_get --- src/adapter/driver_adapter.hpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index 96f2895a..70d9aaaa 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -54,7 +54,8 @@ class DriverAdapter : virtual public AdapterBase void decodePacket(const PacketMsg& msg); private: - void localPointsCallback(const LidarPointCloudMsg& msg); + std::shared_ptr localPointsGetCallback(void); + void localPointsCallback(std::shared_ptr msg); void localScanCallback(const ScanMsg& msg); void localPacketCallback(const PacketMsg& msg); void localCameraTriggerCallback(const CameraTrigger& msg); @@ -67,12 +68,14 @@ class DriverAdapter : virtual public AdapterBase std::vector> packet_cb_vec_; std::vector> camera_trigger_cb_vec_; lidar::ThreadPool::Ptr thread_pool_ptr_; + std::shared_ptr point_cloud_; }; inline DriverAdapter::DriverAdapter() { driver_ptr_.reset(new lidar::LidarDriver()); thread_pool_ptr_.reset(new lidar::ThreadPool()); + point_cloud_.reset (new LidarPointCloudMsg); driver_ptr_->regExceptionCallback(std::bind(&DriverAdapter::localExceptionCallback, this, std::placeholders::_1)); } @@ -154,7 +157,8 @@ inline void DriverAdapter::init(const YAML::Node& config) { driver_ptr_->initDecoderOnly(driver_param); } - driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localPointsCallback, this, std::placeholders::_1)); + driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localPointsCallback, this, std::placeholders::_1), + std::bind(&DriverAdapter::localPointsGetCallback, this)); driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localScanCallback, this, std::placeholders::_1)); driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localPacketCallback, this, std::placeholders::_1)); driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localCameraTriggerCallback, this, std::placeholders::_1)); @@ -192,8 +196,8 @@ inline void DriverAdapter::regRecvCallback(const std::functiondecodeMsopScan(msg, point_cloud_msg)) + std::shared_ptr point_cloud_msg; + if (driver_ptr_->decodeMsopScan(msg, *point_cloud_msg)) { localPointsCallback(point_cloud_msg); } @@ -204,13 +208,16 @@ inline void DriverAdapter::decodePacket(const PacketMsg& msg) driver_ptr_->decodeDifopPkt(msg); } -inline void DriverAdapter::localPointsCallback(const LidarPointCloudMsg& msg) +inline std::shared_ptr DriverAdapter::localPointsGetCallback(void) +{ + return point_cloud_; +} + +inline void DriverAdapter::localPointsCallback(std::shared_ptr msg) { for (auto iter : point_cloud_cb_vec_) { - // thread_pool_ptr_->commit([this, msg, iter]() { iter(msg); }); - iter(msg); - ; + iter(*msg); } } From 7c95c9fbf3651960e82c1312033f86c2bfe31ff9 Mon Sep 17 00:00:00 2001 From: zhangbaoxian Date: Thu, 11 Nov 2021 19:13:37 +0800 Subject: [PATCH 034/261] feat: update rs_lidar, support host_address --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 28aced9c..5908778c 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 28aced9c4ba11f9121ded75fa01b39726a959be7 +Subproject commit 5908778c1d1e333f5cd244dd70cd4257f36eeecd From 9828202a069c4686a54e1e380700240505d4cc79 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 16 Nov 2021 09:19:16 +0800 Subject: [PATCH 035/261] feat: change version to v1.4.1 --- CMakeLists.txt | 2 +- src/rs_driver | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4011ddfb..1768e973 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) cmake_policy(SET CMP0048 NEW) -project(rslidar_sdk) +project(rslidar_sdk 1.4.1) #======================================= # Compile setup (ORIGINAL, CATKIN, COLCON) diff --git a/src/rs_driver b/src/rs_driver index 890b61da..5036b8f8 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 890b61daa5f645d80744429b6a7f454b924d7a4b +Subproject commit 5036b8f8cdbf4930c465f3b6059733b7e52c9366 From bbf4311996e2fc1150dccf48f1733d5636927617 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 25 Nov 2021 14:30:48 +0800 Subject: [PATCH 036/261] feat: track to rs_driver --- config/config.yaml | 2 +- src/rs_driver | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index a16e1891..c3e7e5e0 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -20,7 +20,7 @@ lidar: end_angle: 360 #End angle of point cloud min_distance: 0.2 #Minimum distance of point cloud max_distance: 200 #Maximum distance of point cloud - use_vlan: true #Use vlan or not + wait_for_difop: true #Wait for DIFOP packet use_lidar_clock: false #True--Use the lidar clock as the message timestamp #False-- Use the system clock as the timestamp ros: diff --git a/src/rs_driver b/src/rs_driver index 5908778c..474b033e 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 5908778c1d1e333f5cd244dd70cd4257f36eeecd +Subproject commit 474b033e2eec71e85fdd1e7223f3087b307b7fdd From d4fd6751144c5f5a79b395074af71eb7f168fb79 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 3 Dec 2021 08:51:55 +0800 Subject: [PATCH 037/261] feat: support customer protocol No.1 --- src/adapter/driver_adapter.hpp | 1 + src/rs_driver | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index a2ac515e..b8e57be5 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -111,6 +111,7 @@ inline void DriverAdapter::init(const YAML::Node& config) yamlRead(driver_config, "read_pcap", driver_param.input_param.read_pcap, false); yamlRead(driver_config, "use_vlan", driver_param.input_param.use_vlan, false); yamlRead(driver_config, "use_someip", driver_param.input_param.use_someip, false); + yamlRead(driver_config, "use_custom_proto", driver_param.input_param.use_custom_proto, false); yamlRead(driver_config, "pcap_rate", driver_param.input_param.pcap_rate, 1); yamlRead(driver_config, "pcap_repeat", driver_param.input_param.pcap_repeat, false); yamlRead(driver_config, "pcap_path", driver_param.input_param.pcap_path, ""); diff --git a/src/rs_driver b/src/rs_driver index 474b033e..2b711a06 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 474b033e2eec71e85fdd1e7223f3087b307b7fdd +Subproject commit 2b711a069ac8605bf68d8edf67451759b6e15e63 From 0e8dd9cc7029506a0b20d969732a80d944b2d460 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 6 Dec 2021 10:14:56 +0800 Subject: [PATCH 038/261] feat: support customer protocol No.1 --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 2b711a06..35d9f101 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 2b711a069ac8605bf68d8edf67451759b6e15e63 +Subproject commit 35d9f101df83ce3c58385f0ae0c246d9c4e53b8c From 2d5f0ec638d6717d54b3a884c9ccacb687380490 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 13 Dec 2021 12:17:42 +0800 Subject: [PATCH 039/261] sync to rs_driver v1.4.3 --- CMakeLists.txt | 2 +- src/rs_driver | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1768e973..4011ddfb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) cmake_policy(SET CMP0048 NEW) -project(rslidar_sdk 1.4.1) +project(rslidar_sdk) #======================================= # Compile setup (ORIGINAL, CATKIN, COLCON) diff --git a/src/rs_driver b/src/rs_driver index 5036b8f8..72208b85 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 5036b8f8cdbf4930c465f3b6059733b7e52c9366 +Subproject commit 72208b857b2ee536db58b3012277411cf44a971b From 2081edce3f3c89e3c35a7f74e71625604fa3360b Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 20 Dec 2021 10:49:09 +0800 Subject: [PATCH 040/261] refac: adapter to rs_driver --- config/config.yaml | 2 +- src/adapter/adapter_base.hpp | 23 +++++---- src/adapter/driver_adapter.hpp | 71 +++++++++++++++++++------- src/adapter/packet_ros_adapter.hpp | 4 +- src/manager/adapter_manager.cpp | 18 +++++++ src/manager/adapter_manager.h | 4 +- src/msg/ros_msg_translator.h | 4 ++ src/msg/rs_msg/lidar_point_cloud_msg.h | 2 +- src/rs_driver | 2 +- 9 files changed, 96 insertions(+), 34 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 0c132002..6ffe156a 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -12,7 +12,7 @@ common: pcap_path: /home/robosense/lidar.pcap #The path of pcap file lidar: - driver: - lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RS128, RS80, RSM1, RSHELIOS + lidar_type: RS32 #LiDAR type - RS16, RS32, RSBP, RS128, RS80, RSM1, RSHELIOS frame_id: /rslidar #Frame id of message msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar diff --git a/src/adapter/adapter_base.hpp b/src/adapter/adapter_base.hpp index 76462c2c..6bb7bf8b 100644 --- a/src/adapter/adapter_base.hpp +++ b/src/adapter/adapter_base.hpp @@ -67,16 +67,18 @@ class AdapterBase virtual void init(const YAML::Node& config) = 0; virtual void start(); virtual void stop(); + virtual void sendPointCloud(const LidarPointCloudMsg& msg); + virtual void regRecvCallback(const std::function& callback); +#if 0 virtual void sendScan(const ScanMsg& msg); virtual void sendPacket(const PacketMsg& msg); - virtual void sendPointCloud(const LidarPointCloudMsg& msg); virtual void sendCameraTrigger(const CameraTrigger& msg); virtual void regRecvCallback(const std::function& callback); virtual void regRecvCallback(const std::function& callback); - virtual void regRecvCallback(const std::function& callback); virtual void regRecvCallback(const std::function& callback); virtual void decodeScan(const ScanMsg& msg); virtual void decodePacket(const PacketMsg& msg); +#endif }; inline AdapterBase::~AdapterBase() @@ -94,37 +96,39 @@ inline void AdapterBase::stop() return; } -inline void AdapterBase::sendScan(const ScanMsg& msg) +inline void AdapterBase::sendPointCloud(const LidarPointCloudMsg& msg) { return; } -inline void AdapterBase::sendPacket(const PacketMsg& msg) +inline void AdapterBase::regRecvCallback(const std::function& callback) { return; } -inline void AdapterBase::sendPointCloud(const LidarPointCloudMsg& msg) + +#if 0 +inline void AdapterBase::sendScan(const ScanMsg& msg) { return; } -inline void AdapterBase::sendCameraTrigger(const CameraTrigger& msg) +inline void AdapterBase::sendPacket(const PacketMsg& msg) { return; } -inline void AdapterBase::regRecvCallback(const std::function& callback) +inline void AdapterBase::sendCameraTrigger(const CameraTrigger& msg) { return; } -inline void AdapterBase::regRecvCallback(const std::function& callback) +inline void AdapterBase::regRecvCallback(const std::function& callback) { return; } -inline void AdapterBase::regRecvCallback(const std::function& callback) +inline void AdapterBase::regRecvCallback(const std::function& callback) { return; } @@ -143,6 +147,7 @@ inline void AdapterBase::decodePacket(const PacketMsg& msg) { return; } +#endif } // namespace lidar } // namespace robosense diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index 70d9aaaa..79ce9736 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -47,26 +47,32 @@ class DriverAdapter : virtual public AdapterBase void start(); void stop(); inline void regRecvCallback(const std::function& callback); +#if 0 inline void regRecvCallback(const std::function& callback); inline void regRecvCallback(const std::function& callback); inline void regRecvCallback(const std::function& callback); void decodeScan(const ScanMsg& msg); void decodePacket(const PacketMsg& msg); +#endif private: std::shared_ptr localPointsGetCallback(void); void localPointsCallback(std::shared_ptr msg); +#if 0 void localScanCallback(const ScanMsg& msg); void localPacketCallback(const PacketMsg& msg); void localCameraTriggerCallback(const CameraTrigger& msg); +#endif void localExceptionCallback(const lidar::Error& msg); private: std::shared_ptr> driver_ptr_; std::vector> point_cloud_cb_vec_; +#if 0 std::vector> scan_cb_vec_; std::vector> packet_cb_vec_; std::vector> camera_trigger_cb_vec_; +#endif lidar::ThreadPool::Ptr thread_pool_ptr_; std::shared_ptr point_cloud_; }; @@ -86,45 +92,52 @@ inline DriverAdapter::~DriverAdapter() inline void DriverAdapter::init(const YAML::Node& config) { + lidar::RSDriverParam driver_param; int msg_source; std::string lidar_type; + std::string input_type; uint16_t split_frame_mode; YAML::Node driver_config = yamlSubNodeAbort(config, "driver"); yamlReadAbort(config, "msg_source", msg_source); - yamlRead(driver_config, "frame_id", driver_param.frame_id, "rslidar"); - yamlRead(driver_config, "angle_path", driver_param.angle_path, ""); + //yamlRead(driver_config, "frame_id", driver_param.frame_id, "rslidar"); + yamlRead(driver_config, "angle_path", driver_param.decoder_param.angle_path, ""); yamlReadAbort(driver_config, "lidar_type", lidar_type); - yamlRead(driver_config, "wait_for_difop", driver_param.wait_for_difop, true); - yamlRead(driver_config, "saved_by_rows", driver_param.saved_by_rows, false); + yamlRead(driver_config, "wait_for_difop", driver_param.decoder_param.wait_for_difop, true); + //yamlRead(driver_config, "saved_by_rows", driver_param.saved_by_rows, false); yamlRead(driver_config, "use_lidar_clock", driver_param.decoder_param.use_lidar_clock, false); - yamlRead(driver_config, "is_dense", driver_param.decoder_param.is_dense, false); + yamlRead(driver_config, "is_dense", driver_param.decoder_param.dense_points, false); yamlRead(driver_config, "min_distance", driver_param.decoder_param.min_distance, 0.2); yamlRead(driver_config, "max_distance", driver_param.decoder_param.max_distance, 200); yamlRead(driver_config, "start_angle", driver_param.decoder_param.start_angle, 0); yamlRead(driver_config, "end_angle", driver_param.decoder_param.end_angle, 360); yamlRead(driver_config, "split_frame_mode", split_frame_mode, 1); - yamlRead(driver_config, "num_pkts_split", driver_param.decoder_param.num_pkts_split, 0); - yamlRead(driver_config, "cut_angle", driver_param.decoder_param.cut_angle, 0); - yamlRead(driver_config, "device_ip", driver_param.input_param.device_ip, "192.168.1.200"); + yamlRead(driver_config, "num_pkts_split", driver_param.decoder_param.num_blks_split, 0); + yamlRead(driver_config, "cut_angle", driver_param.decoder_param.split_angle, 0); + //yamlRead(driver_config, "device_ip", driver_param.input_param.device_ip, "192.168.1.200"); yamlRead(driver_config, "multi_cast_address", driver_param.input_param.multi_cast_address, "0.0.0.0"); yamlRead(driver_config, "host_address", driver_param.input_param.host_address, "0.0.0.0"); yamlRead(driver_config, "msop_port", driver_param.input_param.msop_port, 6699); yamlRead(driver_config, "difop_port", driver_param.input_param.difop_port, 7788); - yamlRead(driver_config, "read_pcap", driver_param.input_param.read_pcap, false); + //yamlRead(driver_config, "read_pcap", driver_param.input_param.read_pcap, false); yamlRead(driver_config, "use_vlan", driver_param.input_param.use_vlan, false); yamlRead(driver_config, "use_someip", driver_param.input_param.use_someip, false); - yamlRead(driver_config, "pcap_rate", driver_param.input_param.pcap_rate, 1); + yamlRead(driver_config, "pcap_rate", driver_param.input_param.pcap_rate, 1); yamlRead(driver_config, "pcap_repeat", driver_param.input_param.pcap_repeat, false); yamlRead(driver_config, "pcap_path", driver_param.input_param.pcap_path, ""); +#if 0 yamlRead(driver_config, "x", driver_param.decoder_param.transform_param.x, 0); yamlRead(driver_config, "y", driver_param.decoder_param.transform_param.y, 0); yamlRead(driver_config, "z", driver_param.decoder_param.transform_param.z, 0); yamlRead(driver_config, "roll", driver_param.decoder_param.transform_param.roll, 0); yamlRead(driver_config, "pitch", driver_param.decoder_param.transform_param.pitch, 0); yamlRead(driver_config, "yaw", driver_param.decoder_param.transform_param.yaw, 0); - driver_param.lidar_type = driver_param.strToLidarType(lidar_type); +#endif + + driver_param.lidar_type = strToLidarType(lidar_type); driver_param.decoder_param.split_frame_mode = SplitFrameMode(split_frame_mode); + +#if 0 if (config["camera"] && config["camera"].Type() != YAML::NodeType::Null) { for (size_t i = 0; i < config["camera"].size(); i++) @@ -145,23 +158,39 @@ inline void DriverAdapter::init(const YAML::Node& config) } } } - if (msg_source == MsgSource::MSG_FROM_LIDAR || msg_source == MsgSource::MSG_FROM_PCAP) +#endif + std::cout << "driver_adapter init" << std::endl; + switch (msg_source) { - if (!driver_ptr_->init(driver_param)) - { - RS_ERROR << "Driver Initialize Error...." << RS_REND; - exit(-1); - } + case MsgSource::MSG_FROM_LIDAR: + driver_param.input_type = InputType::ONLINE_LIDAR; + break; + case MsgSource::MSG_FROM_PCAP: + driver_param.input_type = InputType::PCAP_FILE; + break; + case MsgSource::MSG_FROM_ROS_PACKET: + driver_param.input_type = InputType::RAW_PACKET; + break; + } + + if (!driver_ptr_->init(driver_param)) + { + RS_ERROR << "Driver Initialize Error...." << RS_REND; + exit(-1); } +#if 0 else { driver_ptr_->initDecoderOnly(driver_param); } - driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localPointsCallback, this, std::placeholders::_1), - std::bind(&DriverAdapter::localPointsGetCallback, this)); +#endif + driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localPointsGetCallback, this), + std::bind(&DriverAdapter::localPointsCallback, this, std::placeholders::_1)); +#if 0 driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localScanCallback, this, std::placeholders::_1)); driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localPacketCallback, this, std::placeholders::_1)); driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localCameraTriggerCallback, this, std::placeholders::_1)); +#endif } inline void DriverAdapter::start() @@ -179,6 +208,7 @@ inline void DriverAdapter::regRecvCallback(const std::function& callback) { scan_cb_vec_.emplace_back(callback); @@ -207,6 +237,7 @@ inline void DriverAdapter::decodePacket(const PacketMsg& msg) { driver_ptr_->decodeDifopPkt(msg); } +#endif inline std::shared_ptr DriverAdapter::localPointsGetCallback(void) { @@ -221,6 +252,7 @@ inline void DriverAdapter::localPointsCallback(std::shared_ptrcommit([this, msg, iter]() { iter(msg); }); } } +#endif inline void DriverAdapter::localExceptionCallback(const lidar::Error& msg) { diff --git a/src/adapter/packet_ros_adapter.hpp b/src/adapter/packet_ros_adapter.hpp index e134fcbc..d344ee1f 100644 --- a/src/adapter/packet_ros_adapter.hpp +++ b/src/adapter/packet_ros_adapter.hpp @@ -79,7 +79,7 @@ inline void PacketRosAdapter::init(const YAML::Node& config) yamlRead(config["driver"], "lidar_type", lidar_type_str, "RS16"); yamlRead(config["ros"], "ros_recv_packet_topic", ros_recv_topic, "rslidar_packets"); yamlRead(config["ros"], "ros_send_packet_topic", ros_send_topic, "rslidar_packets"); - lidar_type_ = RSDriverParam::strToLidarType(lidar_type_str); + lidar_type_ = strToLidarType(lidar_type_str); if (msg_source == MsgSource::MSG_FROM_ROS_PACKET) { packet_sub_ = nh_->subscribe(ros_recv_topic + "_difop", 1, &PacketRosAdapter::localDifopCallback, this); @@ -244,4 +244,4 @@ inline void PacketRosAdapter::localDifopCallback(const rslidar_msg::msg::Rslidar } } // namespace lidar } // namespace robosense -#endif // ROS2_FOUND \ No newline at end of file +#endif // ROS2_FOUND diff --git a/src/manager/adapter_manager.cpp b/src/manager/adapter_manager.cpp index 7d51a6c3..3d9837d7 100644 --- a/src/manager/adapter_manager.cpp +++ b/src/manager/adapter_manager.cpp @@ -87,6 +87,7 @@ void AdapterManager::init(const YAML::Node& config) } break; +#if 0 case MsgSource::MSG_FROM_ROS_PACKET: // pkt from ros RS_INFO << "------------------------------------------------------" << RS_REND; RS_INFO << "Receive Packets From : ROS" << RS_REND; @@ -105,6 +106,7 @@ void AdapterManager::init(const YAML::Node& config) packet_receive_adapter_vec_[i]->regRecvCallback( std::bind(&AdapterBase::decodePacket, point_cloud_receive_adapter_vec_[i], std::placeholders::_1)); break; +#endif case MsgSource::MSG_FROM_PCAP: // pcap RS_INFO << "------------------------------------------------------" << RS_REND; @@ -127,6 +129,7 @@ void AdapterManager::init(const YAML::Node& config) } break; +#if 0 case MsgSource::MSG_FROM_PROTO_PACKET: // packets from proto RS_INFO << "------------------------------------------------------" << RS_REND; RS_INFO << "Receive Packets From : Protobuf-UDP" << RS_REND; @@ -161,12 +164,14 @@ void AdapterManager::init(const YAML::Node& config) createReceiver(lidar_config[i], AdapterType::PointCloudProtoAdapter)); packet_receive_adapter_vec_.emplace_back(nullptr); break; +#endif default: RS_ERROR << "Not use LiDAR or Wrong LiDAR message source! Abort!" << RS_REND; exit(-1); } +#if 0 /*Transmitter*/ if (send_packet_ros) { @@ -200,6 +205,7 @@ void AdapterManager::init(const YAML::Node& config) packet_receive_adapter_vec_[i]->regRecvCallback( std::bind(&AdapterBase::sendPacket, transmitter_ptr, std::placeholders::_1)); } +#endif if (send_point_cloud_ros) { RS_DEBUG << "------------------------------------------------------" << RS_REND; @@ -213,6 +219,7 @@ void AdapterManager::init(const YAML::Node& config) point_cloud_receive_adapter_vec_[i]->regRecvCallback( std::bind(&AdapterBase::sendPointCloud, transmitter_ptr, std::placeholders::_1)); } +#if 0 if (send_point_cloud_proto) { RS_DEBUG << "------------------------------------------------------" << RS_REND; @@ -240,6 +247,7 @@ void AdapterManager::init(const YAML::Node& config) point_cloud_receive_adapter_vec_[i]->regRecvCallback( std::bind(&AdapterBase::sendCameraTrigger, transmitter_ptr, std::placeholders::_1)); } +#endif } } @@ -253,6 +261,7 @@ void AdapterManager::start() iter->start(); } } +#if 0 if (packet_thread_flag_) { for (auto& iter : packet_receive_adapter_vec_) @@ -263,6 +272,7 @@ void AdapterManager::start() } } } +#endif } void AdapterManager::stop() @@ -275,6 +285,7 @@ void AdapterManager::stop() iter->stop(); } } +#if 0 if (packet_thread_flag_) { for (auto& iter : packet_receive_adapter_vec_) @@ -285,6 +296,7 @@ void AdapterManager::stop() } } } +#endif } std::shared_ptr AdapterManager::createReceiver(const YAML::Node& config, const AdapterType& adapter_type) @@ -297,6 +309,7 @@ std::shared_ptr AdapterManager::createReceiver(const YAML::Node& co receiver->init(config); break; +#if 0 case AdapterType::PacketRosAdapter: #if (ROS_FOUND || ROS2_FOUND) receiver = std::dynamic_pointer_cast(std::make_shared()); @@ -325,6 +338,7 @@ std::shared_ptr AdapterManager::createReceiver(const YAML::Node& co #else RS_ERROR << "Protobuf not found! Could not use Protobuf functions!" << RS_REND; exit(-1); +#endif #endif default: @@ -341,6 +355,7 @@ std::shared_ptr AdapterManager::createTransmitter(const YAML::Node& std::shared_ptr transmitter; switch (adapter_type) { +#if 0 case AdapterType::PacketRosAdapter: #if (ROS_FOUND || ROS2_FOUND) transmitter = std::dynamic_pointer_cast(std::make_shared()); @@ -359,6 +374,7 @@ std::shared_ptr AdapterManager::createTransmitter(const YAML::Node& #else RS_ERROR << "Protobuf not found! Could not use Protobuf functions!" << RS_REND; exit(-1); +#endif #endif case AdapterType::PointCloudRosAdapter: @@ -371,6 +387,7 @@ std::shared_ptr AdapterManager::createTransmitter(const YAML::Node& exit(-1); #endif +#if 0 case AdapterType::PointCloudProtoAdapter: #ifdef PROTO_FOUND transmitter = std::dynamic_pointer_cast(std::make_shared()); @@ -389,6 +406,7 @@ std::shared_ptr AdapterManager::createTransmitter(const YAML::Node& #else RS_ERROR << "ROS not found! Could not use ROS functions!" << RS_REND; exit(-1); +#endif #endif default: diff --git a/src/manager/adapter_manager.h b/src/manager/adapter_manager.h index 09ce5897..3423253b 100644 --- a/src/manager/adapter_manager.h +++ b/src/manager/adapter_manager.h @@ -72,11 +72,13 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include "utility/yaml_reader.hpp" #include "adapter/driver_adapter.hpp" -#include "adapter/packet_ros_adapter.hpp" #include "adapter/point_cloud_ros_adapter.hpp" +#if 0 +#include "adapter/packet_ros_adapter.hpp" #include "adapter/packet_protobuf_adapter.hpp" #include "adapter/point_cloud_protobuf_adapter.hpp" #include "adapter/camera_trigger_adapter.hpp" +#endif namespace robosense { diff --git a/src/msg/ros_msg_translator.h b/src/msg/ros_msg_translator.h index 995d4750..622d3309 100644 --- a/src/msg/ros_msg_translator.h +++ b/src/msg/ros_msg_translator.h @@ -62,6 +62,7 @@ inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) ros_msg.header.seq = rs_msg.seq; return std::move(ros_msg); } +#if 0 inline PacketMsg toRsMsg(const LidarType& lidar_type, const PktType& pkt_type, const rslidar_msgs::rslidarPacket& ros_msg) { @@ -132,6 +133,7 @@ inline std_msgs::Time toRosMsg(const CameraTrigger& rs_msg) ros_msg.data = ros_msg.data.fromSec(rs_msg.second); return ros_msg; } +#endif } // namespace lidar } // namespace robosense @@ -158,6 +160,7 @@ inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) ros_msg.header.frame_id = rs_msg.frame_id; return std::move(ros_msg); } +#if 0 inline PacketMsg toRsMsg(const LidarType& lidar_type, const PktType& pkt_type, const rslidar_msg::msg::RslidarPacket& ros_msg) { @@ -220,6 +223,7 @@ inline rslidar_msg::msg::RslidarScan toRosMsg(const ScanMsg& rs_msg) } return ros_msg; } +#endif } // namespace lidar } // namespace robosense #endif // ROS2_FOUND diff --git a/src/msg/rs_msg/lidar_point_cloud_msg.h b/src/msg/rs_msg/lidar_point_cloud_msg.h index b7206132..0e4e4c4c 100644 --- a/src/msg/rs_msg/lidar_point_cloud_msg.h +++ b/src/msg/rs_msg/lidar_point_cloud_msg.h @@ -78,7 +78,7 @@ class PointCloudT : public pcl::PointCloud typedef typename pcl::PointCloud::VectorType VectorT; double timestamp = 0.0; - std::string frame_id = ""; ///< Point cloud frame id + std::string frame_id = "rslidar"; ///< Point cloud frame id uint32_t seq = 0; ///< Sequence number of message }; diff --git a/src/rs_driver b/src/rs_driver index 72208b85..78dbc593 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 72208b857b2ee536db58b3012277411cf44a971b +Subproject commit 78dbc5938482e403a07e6c4f6651253e60430bfe From c1087407a3bd4ad1330a2f940467bb9e0905e4f7 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 20 Dec 2021 15:25:25 +0800 Subject: [PATCH 041/261] refac: refactory decoder --- src/adapter/driver_adapter.hpp | 15 ++-- src/msg/rs_msg/lidar_point_cloud_msg.h | 55 +----------- src/rs_driver | 2 +- src/utility/common.h | 6 +- src/utility/lock_queue.h | 101 +++++++++++++++++++++ src/utility/thread_pool.hpp | 120 +++++++++++++++++++++++++ src/utility/time.h | 47 ++++++++++ 7 files changed, 282 insertions(+), 64 deletions(-) create mode 100644 src/utility/lock_queue.h create mode 100644 src/utility/thread_pool.hpp create mode 100644 src/utility/time.h diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index 79ce9736..30a1f79b 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -173,6 +173,14 @@ inline void DriverAdapter::init(const YAML::Node& config) break; } + driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localPointsGetCallback, this), + std::bind(&DriverAdapter::localPointsCallback, this, std::placeholders::_1)); +#if 0 + driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localScanCallback, this, std::placeholders::_1)); + driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localPacketCallback, this, std::placeholders::_1)); + driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localCameraTriggerCallback, this, std::placeholders::_1)); +#endif + if (!driver_ptr_->init(driver_param)) { RS_ERROR << "Driver Initialize Error...." << RS_REND; @@ -183,13 +191,6 @@ inline void DriverAdapter::init(const YAML::Node& config) { driver_ptr_->initDecoderOnly(driver_param); } -#endif - driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localPointsGetCallback, this), - std::bind(&DriverAdapter::localPointsCallback, this, std::placeholders::_1)); -#if 0 - driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localScanCallback, this, std::placeholders::_1)); - driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localPacketCallback, this, std::placeholders::_1)); - driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localCameraTriggerCallback, this, std::placeholders::_1)); #endif } diff --git a/src/msg/rs_msg/lidar_point_cloud_msg.h b/src/msg/rs_msg/lidar_point_cloud_msg.h index 0e4e4c4c..64c89958 100644 --- a/src/msg/rs_msg/lidar_point_cloud_msg.h +++ b/src/msg/rs_msg/lidar_point_cloud_msg.h @@ -32,57 +32,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#include -#include +#include "rs_driver/msg/pcl_point_cloud_msg.h" +typedef PointCloudT LidarPointCloudMsg; -#include -#include - -#ifdef POINT_TYPE_XYZI - -typedef pcl::PointXYZI PointT; - -#elif POINT_TYPE_XYZIRT - -struct RsPointXYZIRT -{ - PCL_ADD_POINT4D; - uint8_t intensity; - uint16_t ring = 0; - double timestamp = 0; - EIGEN_MAKE_ALIGNED_OPERATOR_NEW -} EIGEN_ALIGN16; -POINT_CLOUD_REGISTER_POINT_STRUCT(RsPointXYZIRT, (float, x, x)(float, y, y)(float, z, z)(uint8_t, intensity, intensity)( - uint16_t, ring, ring)(double, timestamp, timestamp)) - -typedef RsPointXYZIRT PointT; - -#endif - -namespace robosense -{ -namespace lidar -{ -/** - * @brief Point cloud message for RoboSense SDK. - * @detail RoboSense LidarPointCloudMsg is defined for passing lidar point cloud accross different modules - * If ROS is turned on , we provide translation functions between ROS message and RoboSense message - * If Proto is turned on , we provide translation functions between Protobuf message and RoboSense message - */ - -template -class PointCloudT : public pcl::PointCloud -{ -public: - typedef T_Point PointT; - typedef typename pcl::PointCloud::VectorType VectorT; - - double timestamp = 0.0; - std::string frame_id = "rslidar"; ///< Point cloud frame id - uint32_t seq = 0; ///< Sequence number of message -}; - -typedef PointCloudT LidarPointCloudMsg; - -} // namespace lidar -} // namespace robosense diff --git a/src/rs_driver b/src/rs_driver index 78dbc593..17c87122 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 78dbc5938482e403a07e6c4f6651253e60430bfe +Subproject commit 17c87122c1e17e38b236b4f75b95140394cdf00e diff --git a/src/utility/common.h b/src/utility/common.h index a1de6592..2786322c 100644 --- a/src/utility/common.h +++ b/src/utility/common.h @@ -32,6 +32,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include "rs_driver/common/common_header.h" -#include "rs_driver/utility/time.h" -#include "rs_driver/utility/thread_pool.hpp" -#include "rs_driver/utility/lock_queue.h" +#include "utility/time.h" +#include "utility/thread_pool.hpp" +#include "lock_queue.h" diff --git a/src/utility/lock_queue.h b/src/utility/lock_queue.h new file mode 100644 index 00000000..56e19d12 --- /dev/null +++ b/src/utility/lock_queue.h @@ -0,0 +1,101 @@ +/********************************************************************************************************************* +Copyright (c) 2020 RoboSense +All rights reserved + +By downloading, copying, installing or using the software you agree to this license. If you do not agree to this +license, do not download, install, copy or use the software. + +License Agreement +For RoboSense LiDAR SDK Library +(3-clause BSD License) + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the names of the RoboSense, nor Suteng Innovation Technology, nor the names of other contributors may be used +to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*********************************************************************************************************************/ + +#pragma once +#include +namespace robosense +{ +namespace lidar +{ +template +class Queue +{ +public: + inline Queue() : is_task_finished_(true) + { + } + + inline T front() + { + std::lock_guard lock(mutex_); + return queue_.front(); + } + + inline void push(const T& value) + { + std::lock_guard lock(mutex_); + queue_.push(value); + } + + inline void pop() + { + std::lock_guard lock(mutex_); + if (!queue_.empty()) + { + queue_.pop(); + } + } + + inline T popFront() + { + T value; + std::lock_guard lock(mutex_); + if (!queue_.empty()) + { + value = std::move(queue_.front()); + queue_.pop(); + } + return value; + } + + inline void clear() + { + std::queue empty; + std::lock_guard lock(mutex_); + swap(empty, queue_); + } + + inline size_t size() + { + std::lock_guard lock(mutex_); + return queue_.size(); + } + +public: + std::queue queue_; + std::atomic is_task_finished_; + +private: + mutable std::mutex mutex_; +}; +} // namespace lidar +} // namespace robosense \ No newline at end of file diff --git a/src/utility/thread_pool.hpp b/src/utility/thread_pool.hpp new file mode 100644 index 00000000..d97c85a2 --- /dev/null +++ b/src/utility/thread_pool.hpp @@ -0,0 +1,120 @@ +/********************************************************************************************************************* +Copyright (c) 2020 RoboSense +All rights reserved + +By downloading, copying, installing or using the software you agree to this license. If you do not agree to this +license, do not download, install, copy or use the software. + +License Agreement +For RoboSense LiDAR SDK Library +(3-clause BSD License) + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the names of the RoboSense, nor Suteng Innovation Technology, nor the names of other contributors may be used +to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*********************************************************************************************************************/ + +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +namespace robosense +{ +namespace lidar +{ +constexpr uint16_t MAX_THREAD_NUM = 2; +struct Thread +{ + Thread() : start_(false) + { + } + std::shared_ptr thread_; + std::atomic start_; +}; +class ThreadPool +{ +public: + typedef std::shared_ptr Ptr; + inline ThreadPool() : stop_flag_(false), idl_thr_num_(MAX_THREAD_NUM) + { + for (int i = 0; i < idl_thr_num_; ++i) + { + pool_.emplace_back([this] { + while (!this->stop_flag_) + { + std::function task; + { + std::unique_lock lock{ this->mutex_ }; + this->cv_task_.wait(lock, [this] { return this->stop_flag_.load() || !this->tasks_.empty(); }); + if (this->stop_flag_ && this->tasks_.empty()) + return; + task = std::move(this->tasks_.front()); + this->tasks_.pop(); + } + idl_thr_num_--; + task(); + idl_thr_num_++; + } + }); + } + } + + inline ~ThreadPool() + { + stop_flag_.store(true); + cv_task_.notify_all(); + for (std::thread& thread : pool_) + { + thread.join(); + } + } + +public: + template + inline void commit(F&& f, Args&&... args) + { + if (stop_flag_.load()) + throw std::runtime_error("Commit on LiDAR threadpool is stopped."); + using RetType = decltype(f(args...)); + auto task = + std::make_shared>(std::bind(std::forward(f), std::forward(args)...)); + { + std::lock_guard lock{ mutex_ }; + tasks_.emplace([task]() { (*task)(); }); + } + cv_task_.notify_one(); + } + +private: + using Task = std::function; + std::vector pool_; + std::queue tasks_; + std::mutex mutex_; + std::condition_variable cv_task_; + std::atomic stop_flag_; + std::atomic idl_thr_num_; +}; +} // namespace lidar +} // namespace robosense diff --git a/src/utility/time.h b/src/utility/time.h new file mode 100644 index 00000000..266106d8 --- /dev/null +++ b/src/utility/time.h @@ -0,0 +1,47 @@ +/********************************************************************************************************************* +Copyright (c) 2020 RoboSense +All rights reserved + +By downloading, copying, installing or using the software you agree to this license. If you do not agree to this +license, do not download, install, copy or use the software. + +License Agreement +For RoboSense LiDAR SDK Library +(3-clause BSD License) + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the names of the RoboSense, nor Suteng Innovation Technology, nor the names of other contributors may be used +to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*********************************************************************************************************************/ + +#pragma once +#include +#include +namespace robosense +{ +namespace lidar +{ +inline double getTime(void) +{ + const auto t = std::chrono::system_clock::now(); + const auto t_sec = std::chrono::duration_cast>(t.time_since_epoch()); + return (double)t_sec.count(); +} +} // namespace lidar +} // namespace robosense From a896f3fb8019db2cb12197ed9b0214b71dd2cb89 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 21 Dec 2021 18:22:23 +0800 Subject: [PATCH 042/261] fix: fix raw packet play --- CMakeLists.txt | 1 + src/adapter/driver_adapter.hpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4011ddfb..8665578d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,6 +107,7 @@ endif(${COMPILE_METHOD} STREQUAL "CATKIN") #Include directory# include_directories(${PROJECT_SOURCE_DIR}/src) #Driver core# +add_definitions(-DENABLE_PUBLISH_RAW_MSG) add_subdirectory(src/rs_driver) find_package(rs_driver REQUIRED) include_directories(${rs_driver_INCLUDE_DIRS}) diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index 70d9aaaa..489452e6 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -196,7 +196,8 @@ inline void DriverAdapter::regRecvCallback(const std::function point_cloud_msg; + std::shared_ptr point_cloud_msg = + std::make_shared(); if (driver_ptr_->decodeMsopScan(msg, *point_cloud_msg)) { localPointsCallback(point_cloud_msg); From df960359b194421eeaf40c9cbdbc5c2d6c1bb888 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 21 Dec 2021 18:25:49 +0800 Subject: [PATCH 043/261] feat: sync to rs_driver dev_opt --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 72208b85..05cdc136 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 72208b857b2ee536db58b3012277411cf44a971b +Subproject commit 05cdc1364659fcd5ed2c68615811c11bec1c2183 From eab7d197dec498324d89bbbcdfe81c37991030b5 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 22 Dec 2021 09:10:53 +0800 Subject: [PATCH 044/261] feat: disable publishing raw msop/difop packets in default mode --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8665578d..7982bff5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,7 +107,7 @@ endif(${COMPILE_METHOD} STREQUAL "CATKIN") #Include directory# include_directories(${PROJECT_SOURCE_DIR}/src) #Driver core# -add_definitions(-DENABLE_PUBLISH_RAW_MSG) +#add_definitions(-DENABLE_PUBLISH_RAW_MSG) add_subdirectory(src/rs_driver) find_package(rs_driver REQUIRED) include_directories(${rs_driver_INCLUDE_DIRS}) From ceb534d79222c56d87ea1f8328decf67a1a4a808 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 27 Dec 2021 16:15:19 +0800 Subject: [PATCH 045/261] refac: adapt to rs_driver --- config/config.yaml | 2 +- src/adapter/driver_adapter.hpp | 55 +++++++++++++++++++-------------- src/manager/adapter_manager.cpp | 2 +- src/rs_driver | 2 +- 4 files changed, 34 insertions(+), 27 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 6ffe156a..3e6b48cf 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -12,7 +12,7 @@ common: pcap_path: /home/robosense/lidar.pcap #The path of pcap file lidar: - driver: - lidar_type: RS32 #LiDAR type - RS16, RS32, RSBP, RS128, RS80, RSM1, RSHELIOS + lidar_type: RS128 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RS80, RS128, RSM1 frame_id: /rslidar #Frame id of message msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index 30a1f79b..c393afd2 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -92,39 +92,47 @@ inline DriverAdapter::~DriverAdapter() inline void DriverAdapter::init(const YAML::Node& config) { + int msg_source; + yamlReadAbort(config, "msg_source", msg_source); + YAML::Node driver_config = yamlSubNodeAbort(config, "driver"); lidar::RSDriverParam driver_param; - int msg_source; + + // input related + yamlRead(driver_config, "multi_cast_address", driver_param.input_param.multi_cast_address, "0.0.0.0"); + yamlRead(driver_config, "host_address", driver_param.input_param.host_address, "0.0.0.0"); + yamlRead(driver_config, "msop_port", driver_param.input_param.msop_port, 6699); + yamlRead(driver_config, "difop_port", driver_param.input_param.difop_port, 7788); + yamlRead(driver_config, "use_vlan", driver_param.input_param.use_vlan, false); + yamlRead(driver_config, "use_someip", driver_param.input_param.use_someip, false); + yamlRead(driver_config, "pcap_path", driver_param.input_param.pcap_path, ""); + yamlRead(driver_config, "pcap_rate", driver_param.input_param.pcap_rate, 1); + yamlRead(driver_config, "pcap_repeat", driver_param.input_param.pcap_repeat, false); + + // decoder related std::string lidar_type; - std::string input_type; - uint16_t split_frame_mode; - YAML::Node driver_config = yamlSubNodeAbort(config, "driver"); - yamlReadAbort(config, "msg_source", msg_source); - //yamlRead(driver_config, "frame_id", driver_param.frame_id, "rslidar"); - yamlRead(driver_config, "angle_path", driver_param.decoder_param.angle_path, ""); yamlReadAbort(driver_config, "lidar_type", lidar_type); + driver_param.lidar_type = strToLidarType(lidar_type); + + // decoder yamlRead(driver_config, "wait_for_difop", driver_param.decoder_param.wait_for_difop, true); - //yamlRead(driver_config, "saved_by_rows", driver_param.saved_by_rows, false); yamlRead(driver_config, "use_lidar_clock", driver_param.decoder_param.use_lidar_clock, false); - yamlRead(driver_config, "is_dense", driver_param.decoder_param.dense_points, false); yamlRead(driver_config, "min_distance", driver_param.decoder_param.min_distance, 0.2); yamlRead(driver_config, "max_distance", driver_param.decoder_param.max_distance, 200); yamlRead(driver_config, "start_angle", driver_param.decoder_param.start_angle, 0); yamlRead(driver_config, "end_angle", driver_param.decoder_param.end_angle, 360); + yamlRead(driver_config, "is_dense", driver_param.decoder_param.dense_points, false); + + // mechanical decoder + yamlRead(driver_config, "angle_path", driver_param.decoder_param.angle_path, ""); + + uint16_t split_frame_mode; yamlRead(driver_config, "split_frame_mode", split_frame_mode, 1); - yamlRead(driver_config, "num_pkts_split", driver_param.decoder_param.num_blks_split, 0); + driver_param.decoder_param.split_frame_mode = SplitFrameMode(split_frame_mode); + yamlRead(driver_config, "cut_angle", driver_param.decoder_param.split_angle, 0); - //yamlRead(driver_config, "device_ip", driver_param.input_param.device_ip, "192.168.1.200"); - yamlRead(driver_config, "multi_cast_address", driver_param.input_param.multi_cast_address, "0.0.0.0"); - yamlRead(driver_config, "host_address", driver_param.input_param.host_address, "0.0.0.0"); - yamlRead(driver_config, "msop_port", driver_param.input_param.msop_port, 6699); - yamlRead(driver_config, "difop_port", driver_param.input_param.difop_port, 7788); - //yamlRead(driver_config, "read_pcap", driver_param.input_param.read_pcap, false); - yamlRead(driver_config, "use_vlan", driver_param.input_param.use_vlan, false); - yamlRead(driver_config, "use_someip", driver_param.input_param.use_someip, false); - yamlRead(driver_config, "pcap_rate", driver_param.input_param.pcap_rate, 1); - yamlRead(driver_config, "pcap_repeat", driver_param.input_param.pcap_repeat, false); - yamlRead(driver_config, "pcap_path", driver_param.input_param.pcap_path, ""); + yamlRead(driver_config, "num_pkts_split", driver_param.decoder_param.num_blks_split, 0); + #if 0 yamlRead(driver_config, "x", driver_param.decoder_param.transform_param.x, 0); yamlRead(driver_config, "y", driver_param.decoder_param.transform_param.y, 0); @@ -134,8 +142,6 @@ inline void DriverAdapter::init(const YAML::Node& config) yamlRead(driver_config, "yaw", driver_param.decoder_param.transform_param.yaw, 0); #endif - driver_param.lidar_type = strToLidarType(lidar_type); - driver_param.decoder_param.split_frame_mode = SplitFrameMode(split_frame_mode); #if 0 if (config["camera"] && config["camera"].Type() != YAML::NodeType::Null) @@ -159,7 +165,6 @@ inline void DriverAdapter::init(const YAML::Node& config) } } #endif - std::cout << "driver_adapter init" << std::endl; switch (msg_source) { case MsgSource::MSG_FROM_LIDAR: @@ -181,6 +186,8 @@ inline void DriverAdapter::init(const YAML::Node& config) driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localCameraTriggerCallback, this, std::placeholders::_1)); #endif + driver_param.print(); + if (!driver_ptr_->init(driver_param)) { RS_ERROR << "Driver Initialize Error...." << RS_REND; diff --git a/src/manager/adapter_manager.cpp b/src/manager/adapter_manager.cpp index 3d9837d7..55abb3ce 100644 --- a/src/manager/adapter_manager.cpp +++ b/src/manager/adapter_manager.cpp @@ -70,7 +70,7 @@ void AdapterManager::init(const YAML::Node& config) /*Receiver*/ switch (msg_source) { - case MsgSource::MSG_FROM_LIDAR: // use driver + case MsgSource::MSG_FROM_LIDAR: // online lidar RS_INFO << "------------------------------------------------------" << RS_REND; RS_INFO << "Receive Packets From : Online LiDAR" << RS_REND; RS_INFO << "Msop Port: " << lidar_config[i]["driver"]["msop_port"].as() << RS_REND; diff --git a/src/rs_driver b/src/rs_driver index 17c87122..9f5b8235 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 17c87122c1e17e38b236b4f75b95140394cdf00e +Subproject commit 9f5b82356f28308821d576f663ede5e03b88db8a From 55e3162ea970f335c25bb2a682b63d0e0b929435 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 28 Dec 2021 10:23:36 +0800 Subject: [PATCH 046/261] feat: support config_from_file option --- src/adapter/driver_adapter.hpp | 1 + src/rs_driver | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index c393afd2..1395c4ca 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -124,6 +124,7 @@ inline void DriverAdapter::init(const YAML::Node& config) yamlRead(driver_config, "is_dense", driver_param.decoder_param.dense_points, false); // mechanical decoder + yamlRead(driver_config, "config_from_file", driver_param.decoder_param.config_from_file, false); yamlRead(driver_config, "angle_path", driver_param.decoder_param.angle_path, ""); uint16_t split_frame_mode; diff --git a/src/rs_driver b/src/rs_driver index 9f5b8235..bf6f3c6f 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 9f5b82356f28308821d576f663ede5e03b88db8a +Subproject commit bf6f3c6fd95081bf3fe46ba0a2e130f655351621 From 0e46f1757665c4ff0870cf01c44036806db6f719 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 29 Dec 2021 11:30:03 +0800 Subject: [PATCH 047/261] refac: refactory adapter --- src/adapter/packet_ros_adapter.hpp | 53 +++++++++++++++++------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/src/adapter/packet_ros_adapter.hpp b/src/adapter/packet_ros_adapter.hpp index d344ee1f..29f0845b 100644 --- a/src/adapter/packet_ros_adapter.hpp +++ b/src/adapter/packet_ros_adapter.hpp @@ -44,7 +44,7 @@ class PacketRosAdapter : virtual public AdapterBase { public: PacketRosAdapter() = default; - ~PacketRosAdapter() = default; + virtual ~PacketRosAdapter() = default; void init(const YAML::Node& config); void regRecvCallback(const std::function& callback); void regRecvCallback(const std::function& callback); @@ -57,37 +57,40 @@ class PacketRosAdapter : virtual public AdapterBase private: std::unique_ptr nh_; + LidarType lidar_type_; std::vector> scan_cb_vec_; std::vector> packet_cb_vec_; ros::Publisher scan_pub_; ros::Publisher packet_pub_; ros::Subscriber scan_sub_; ros::Subscriber packet_sub_; - LidarType lidar_type_; }; inline void PacketRosAdapter::init(const YAML::Node& config) { - int msg_source; - bool send_packet_ros; - std::string ros_recv_topic; - std::string ros_send_topic; - std::string lidar_type_str; nh_ = std::unique_ptr(new ros::NodeHandle()); - yamlReadAbort(config, "msg_source", msg_source); - yamlRead(config, "send_packet_ros", send_packet_ros, false); + + std::string lidar_type_str; yamlRead(config["driver"], "lidar_type", lidar_type_str, "RS16"); - yamlRead(config["ros"], "ros_recv_packet_topic", ros_recv_topic, "rslidar_packets"); - yamlRead(config["ros"], "ros_send_packet_topic", ros_send_topic, "rslidar_packets"); lidar_type_ = strToLidarType(lidar_type_str); + + int msg_source; + yamlReadAbort(config, "msg_source", msg_source); if (msg_source == MsgSource::MSG_FROM_ROS_PACKET) { + std::string ros_recv_topic; + yamlRead(config["ros"], "ros_recv_packet_topic", ros_recv_topic, "rslidar_packets"); packet_sub_ = nh_->subscribe(ros_recv_topic + "_difop", 1, &PacketRosAdapter::localDifopCallback, this); scan_sub_ = nh_->subscribe(ros_recv_topic, 1, &PacketRosAdapter::localMsopCallback, this); send_packet_ros = false; } + + bool send_packet_ros; + yamlRead(config, "send_packet_ros", send_packet_ros, false); if (send_packet_ros) { + std::string ros_send_topic; + yamlRead(config["ros"], "ros_send_packet_topic", ros_send_topic, "rslidar_packets"); packet_pub_ = nh_->advertise(ros_send_topic + "_difop", 10); scan_pub_ = nh_->advertise(ros_send_topic, 10); } @@ -145,7 +148,7 @@ class PacketRosAdapter : virtual public AdapterBase { public: PacketRosAdapter() = default; - ~PacketRosAdapter(); + virtual ~PacketRosAdapter(); void init(const YAML::Node& config); void start(); void regRecvCallback(const std::function& callback); @@ -159,14 +162,15 @@ class PacketRosAdapter : virtual public AdapterBase private: std::shared_ptr node_ptr_; + LidarType lidar_type_; rclcpp::Publisher::SharedPtr scan_pub_; rclcpp::Publisher::SharedPtr packet_pub_; rclcpp::Subscription::SharedPtr scan_sub_; rclcpp::Subscription::SharedPtr packet_sub_; std::vector> scan_cb_vec_; std::vector> packet_cb_vec_; - LidarType lidar_type_; }; + inline PacketRosAdapter::~PacketRosAdapter() { stop(); @@ -174,28 +178,33 @@ inline PacketRosAdapter::~PacketRosAdapter() inline void PacketRosAdapter::init(const YAML::Node& config) { - int msg_source; - bool send_packet_ros; - std::string ros_recv_topic; - std::string ros_send_topic; - std::string lidar_type_str; node_ptr_.reset(new rclcpp::Node("rslidar_packets_adapter")); - yamlReadAbort(config, "msg_source", msg_source); - yamlRead(config, "send_packet_ros", send_packet_ros, false); + + std::string lidar_type_str; yamlRead(config["driver"], "lidar_type", lidar_type_str, "RS16"); - yamlRead(config["ros"], "ros_recv_packet_topic", ros_recv_topic, "rslidar_packets"); - yamlRead(config["ros"], "ros_send_packet_topic", ros_send_topic, "rslidar_packets"); lidar_type_ = RSDriverParam::strToLidarType(lidar_type_str); + + int msg_source; + yamlReadAbort(config, "msg_source", msg_source); if (msg_source == MsgSource::MSG_FROM_ROS_PACKET) { + std::string ros_recv_topic; + yamlRead(config["ros"], "ros_recv_packet_topic", ros_recv_topic, "rslidar_packets"); + packet_sub_ = node_ptr_->create_subscription( ros_recv_topic + "_difop", 10, [this](const rslidar_msg::msg::RslidarPacket::SharedPtr msg) { localDifopCallback(msg); }); scan_sub_ = node_ptr_->create_subscription( ros_recv_topic, 10, [this](const rslidar_msg::msg::RslidarScan::SharedPtr msg) { localMsopCallback(msg); }); } + + bool send_packet_ros; + yamlRead(config, "send_packet_ros", send_packet_ros, false); if (send_packet_ros) { + std::string ros_send_topic; + yamlRead(config["ros"], "ros_send_packet_topic", ros_send_topic, "rslidar_packets"); + packet_pub_ = node_ptr_->create_publisher(ros_send_topic + "_difop", 10); scan_pub_ = node_ptr_->create_publisher(ros_send_topic, 10); } From 5e003e12b3fc7d19027ccffd918f40ad890615fe Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 29 Dec 2021 18:22:23 +0800 Subject: [PATCH 048/261] refac: refactory rslidar_node --- node/rslidar_sdk_node.cpp | 79 +++++++++++++++-------- src/adapter/adapter_base.hpp | 7 ++- src/adapter/point_cloud_ros_adapter.hpp | 4 +- src/manager/adapter_manager.cpp | 83 ++++++++++++++++++++----- src/manager/adapter_manager.h | 15 ++--- src/msg/ros_msg_translator.h | 2 +- src/rs_driver | 2 +- src/utility/common.h | 2 + 8 files changed, 139 insertions(+), 55 deletions(-) diff --git a/node/rslidar_sdk_node.cpp b/node/rslidar_sdk_node.cpp index 27b5210b..9feaad41 100644 --- a/node/rslidar_sdk_node.cpp +++ b/node/rslidar_sdk_node.cpp @@ -30,76 +30,101 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *********************************************************************************************************************/ -#include +#include "rs_driver/macro/version.h" #include "manager/adapter_manager.h" +#include + #ifdef ROS_FOUND +#include #include #endif +#ifdef ROS2_FOUND +#include +#endif + using namespace robosense::lidar; + +#ifdef ROS2_FOUND std::mutex g_mtx; std::condition_variable g_cv; +#endif + static void sigHandler(int sig) { RS_MSG << "RoboSense-LiDAR-Driver is stopping....." << RS_REND; + #ifdef ROS_FOUND ros::shutdown(); -#endif +#else // ROS2_FOUND g_cv.notify_all(); +#endif } int main(int argc, char** argv) { signal(SIGINT, sigHandler); ///< bind ctrl+c signal with the sigHandler function + RS_TITLE << "********************************************************" << RS_REND; RS_TITLE << "********** **********" << RS_REND; - RS_TITLE << "********** RSLidar_SDK Version: v" << RSLIDAR_VERSION_MAJOR << "." << RSLIDAR_VERSION_MINOR << "." - << RSLIDAR_VERSION_PATCH << " **********" << RS_REND; + RS_TITLE << "********** RSLidar_SDK Version: v" << RSLIDAR_VERSION_MAJOR + << "." << RSLIDAR_VERSION_MINOR + << "." << RSLIDAR_VERSION_PATCH << " **********" << RS_REND; RS_TITLE << "********** **********" << RS_REND; RS_TITLE << "********************************************************" << RS_REND; - std::shared_ptr demo_ptr = std::make_shared(); - YAML::Node config; - try - { +#ifdef ROS_FOUND + ros::init(argc, argv, "rslidar_sdk_node", ros::init_options::NoSigintHandler); +#else // ROS2_FOUND + rclcpp::init(argc, argv); +#endif + + std::string config_path; + #ifdef RUN_IN_ROS_WORKSPACE - std::string path = ros::package::getPath("rslidar_sdk"); + config_path = ros::package::getPath("rslidar_sdk"); #else - std::string path = (std::string)PROJECT_PATH; + config_path = (std::string)PROJECT_PATH; #endif - config = YAML::LoadFile((std::string)path + "/config/config.yaml"); - } - catch (...) - { - RS_ERROR << "Config file format wrong! Please check the format(e.g. indentation) " << RS_REND; - return -1; - } -#ifdef ROS_FOUND ///< if ROS is found, call the ros::init function - ros::init(argc, argv, "rslidar_sdk_node", ros::init_options::NoSigintHandler); + config_path += "/config/config.yaml"; + +#ifdef ROS_FOUND ros::NodeHandle priv_hh("~"); - std::string config_path; - priv_hh.param("config_path", config_path, std::string("")); - if (!config_path.empty()) + + std::string path; + priv_hh.param("config_path", path, std::string("")); + if (!path.empty()) { - config = YAML::LoadFile(config_path); + config_path = path; } #endif -#ifdef ROS2_FOUND ///< if ROS2 is found, call the rclcpp::init function - rclcpp::init(argc, argv); -#endif + YAML::Node config; + try + { + config = YAML::LoadFile(config_path); + } + catch (...) + { + RS_ERROR << "The format of config file " << config_path + << " is wrong. Please check (e.g. indentation)." << RS_REND; + return -1; + } + std::shared_ptr demo_ptr = std::make_shared(); demo_ptr->init(config); demo_ptr->start(); + RS_MSG << "RoboSense-LiDAR-Driver is running....." << RS_REND; #ifdef ROS_FOUND ros::spin(); -#else +#else // ROS2_FOUND std::unique_lock lck(g_mtx); g_cv.wait(lck); #endif + return 0; } diff --git a/src/adapter/adapter_base.hpp b/src/adapter/adapter_base.hpp index 6bb7bf8b..2f2e703a 100644 --- a/src/adapter/adapter_base.hpp +++ b/src/adapter/adapter_base.hpp @@ -31,8 +31,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *********************************************************************************************************************/ #pragma once -#include "utility/common.h" -#include "utility/yaml_reader.hpp" + +//#include "utility/common.h" #include "rs_driver/msg/packet_msg.h" #include "rs_driver/msg/scan_msg.h" #include "msg/rs_msg/lidar_point_cloud_msg.h" @@ -41,6 +41,7 @@ namespace robosense { namespace lidar { + enum MsgSource { MSG_FROM_LIDAR = 1, @@ -49,6 +50,7 @@ enum MsgSource MSG_FROM_PROTO_PACKET = 4, MSG_FROM_PROTO_POINTCLOUD = 5 }; + enum class AdapterType { DriverAdapter, @@ -58,6 +60,7 @@ enum class AdapterType PacketProtoAdapter, CameraTriggerRosAdapter }; + class AdapterBase { public: diff --git a/src/adapter/point_cloud_ros_adapter.hpp b/src/adapter/point_cloud_ros_adapter.hpp index c7e0415c..583dfe25 100644 --- a/src/adapter/point_cloud_ros_adapter.hpp +++ b/src/adapter/point_cloud_ros_adapter.hpp @@ -31,7 +31,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *********************************************************************************************************************/ #pragma once + #ifdef ROS_FOUND + #include #include "adapter/adapter_base.hpp" #include "msg/ros_msg_translator.h" @@ -116,4 +118,4 @@ inline void PointCloudRosAdapter::sendPointCloud(const LidarPointCloudMsg& msg) } // namespace lidar } // namespace robosense -#endif // ROS2_FOUND \ No newline at end of file +#endif // ROS2_FOUND diff --git a/src/manager/adapter_manager.cpp b/src/manager/adapter_manager.cpp index 55abb3ce..3e756130 100644 --- a/src/manager/adapter_manager.cpp +++ b/src/manager/adapter_manager.cpp @@ -31,10 +31,21 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *********************************************************************************************************************/ #include "manager/adapter_manager.h" +#include "adapter/driver_adapter.hpp" +#include "adapter/point_cloud_ros_adapter.hpp" + +#if 0 +#include "adapter/packet_ros_adapter.hpp" +#include "adapter/packet_protobuf_adapter.hpp" +#include "adapter/point_cloud_protobuf_adapter.hpp" +#include "adapter/camera_trigger_adapter.hpp" +#endif + namespace robosense { namespace lidar { + AdapterManager::~AdapterManager() { stop(); @@ -44,89 +55,120 @@ void AdapterManager::init(const YAML::Node& config) { packet_thread_flag_ = false; point_cloud_thread_flag_ = false; + + YAML::Node common_config = yamlSubNodeAbort(config, "common"); + int msg_source = 0; - bool send_point_cloud_ros; + yamlRead(common_config, "msg_source", msg_source, 0); + bool send_packet_ros; + yamlRead(common_config, "send_packet_ros", send_packet_ros, false); + + bool send_point_cloud_ros; + yamlRead(common_config, "send_point_cloud_ros", send_point_cloud_ros, false); + bool send_point_cloud_proto; + yamlRead(common_config, "send_point_cloud_proto", send_point_cloud_proto, false); + bool send_packet_proto; + yamlRead(common_config, "send_packet_proto", send_packet_proto, false); + bool send_camera_trigger_ros; + yamlRead(common_config, "send_camera_trigger_ros", send_camera_trigger_ros, false); + std::string pcap_dir; double pcap_rate; bool pcap_repeat; - YAML::Node common_config = yamlSubNodeAbort(config, "common"); - yamlRead(common_config, "msg_source", msg_source, 0); - yamlRead(common_config, "send_packet_ros", send_packet_ros, false); - yamlRead(common_config, "send_point_cloud_ros", send_point_cloud_ros, false); - yamlRead(common_config, "send_point_cloud_proto", send_point_cloud_proto, false); - yamlRead(common_config, "send_packet_proto", send_packet_proto, false); - yamlRead(common_config, "send_camera_trigger_ros", send_camera_trigger_ros, false); yamlRead(common_config, "pcap_path", pcap_dir, ""); yamlRead(common_config, "pcap_rate", pcap_rate, 1); yamlRead(common_config, "pcap_repeat", pcap_repeat, true); + YAML::Node lidar_config = yamlSubNodeAbort(config, "lidar"); + for (uint8_t i = 0; i < lidar_config.size(); ++i) { AdapterBase::Ptr recv_ptr; - /*Receiver*/ + + // + // Receiver + // switch (msg_source) { case MsgSource::MSG_FROM_LIDAR: // online lidar + RS_INFO << "------------------------------------------------------" << RS_REND; RS_INFO << "Receive Packets From : Online LiDAR" << RS_REND; RS_INFO << "Msop Port: " << lidar_config[i]["driver"]["msop_port"].as() << RS_REND; RS_INFO << "Difop Port: " << lidar_config[i]["driver"]["difop_port"].as() << RS_REND; RS_INFO << "------------------------------------------------------" << RS_REND; + point_cloud_thread_flag_ = true; + lidar_config[i]["msg_source"] = (int)MsgSource::MSG_FROM_LIDAR; + recv_ptr = createReceiver(lidar_config[i], AdapterType::DriverAdapter); point_cloud_receive_adapter_vec_.push_back(recv_ptr); + if (send_packet_ros || send_packet_proto) { packet_receive_adapter_vec_.push_back(recv_ptr); packet_thread_flag_ = true; } + break; -#if 0 case MsgSource::MSG_FROM_ROS_PACKET: // pkt from ros + RS_INFO << "------------------------------------------------------" << RS_REND; RS_INFO << "Receive Packets From : ROS" << RS_REND; RS_INFO << "Msop Topic: " << lidar_config[i]["ros"]["ros_recv_packet_topic"].as() << RS_REND; RS_INFO << "Difop Topic: " << lidar_config[i]["ros"]["ros_recv_packet_topic"].as() << "_difop" << RS_REND; RS_INFO << "------------------------------------------------------" << RS_REND; + + send_packet_ros = false; point_cloud_thread_flag_ = false; packet_thread_flag_ = true; + lidar_config[i]["msg_source"] = (int)MsgSource::MSG_FROM_ROS_PACKET; - send_packet_ros = false; + point_cloud_receive_adapter_vec_.emplace_back(createReceiver(lidar_config[i], AdapterType::DriverAdapter)); packet_receive_adapter_vec_.emplace_back(createReceiver(lidar_config[i], AdapterType::PacketRosAdapter)); + +#if 0 packet_receive_adapter_vec_[i]->regRecvCallback( std::bind(&AdapterBase::decodeScan, point_cloud_receive_adapter_vec_[i], std::placeholders::_1)); packet_receive_adapter_vec_[i]->regRecvCallback( std::bind(&AdapterBase::decodePacket, point_cloud_receive_adapter_vec_[i], std::placeholders::_1)); - break; #endif + break; case MsgSource::MSG_FROM_PCAP: // pcap + RS_INFO << "------------------------------------------------------" << RS_REND; RS_INFO << "Receive Packets From : Pcap" << RS_REND; RS_INFO << "Msop Port: " << lidar_config[i]["driver"]["msop_port"].as() << RS_REND; RS_INFO << "Difop Port: " << lidar_config[i]["driver"]["difop_port"].as() << RS_REND; RS_INFO << "------------------------------------------------------" << RS_REND; + point_cloud_thread_flag_ = true; + lidar_config[i]["msg_source"] = (int)MsgSource::MSG_FROM_PCAP; + lidar_config[i]["driver"]["read_pcap"] = true; lidar_config[i]["driver"]["pcap_path"] = pcap_dir; lidar_config[i]["driver"]["pcap_rate"] = pcap_rate; lidar_config[i]["driver"]["pcap_repeat"] = pcap_repeat; + recv_ptr = createReceiver(lidar_config[i], AdapterType::DriverAdapter); point_cloud_receive_adapter_vec_.push_back(recv_ptr); + if (send_packet_ros || send_packet_proto) { packet_receive_adapter_vec_.push_back(recv_ptr); packet_thread_flag_ = true; } + break; #if 0 @@ -171,8 +213,9 @@ void AdapterManager::init(const YAML::Node& config) exit(-1); } -#if 0 - /*Transmitter*/ + // + // Transmitter + // if (send_packet_ros) { RS_DEBUG << "------------------------------------------------------" << RS_REND; @@ -181,14 +224,21 @@ void AdapterManager::init(const YAML::Node& config) RS_DEBUG << "Difop Topic: " << lidar_config[i]["ros"]["ros_send_packet_topic"].as() << "_difop" << RS_REND; RS_DEBUG << "------------------------------------------------------" << RS_REND; + lidar_config[i]["send_packet_ros"] = true; + AdapterBase::Ptr transmitter_ptr = createTransmitter(lidar_config[i], AdapterType::PacketRosAdapter); packet_transmit_adapter_vec_.emplace_back(transmitter_ptr); + +#if 0 packet_receive_adapter_vec_[i]->regRecvCallback( std::bind(&AdapterBase::sendScan, transmitter_ptr, std::placeholders::_1)); packet_receive_adapter_vec_[i]->regRecvCallback( std::bind(&AdapterBase::sendPacket, transmitter_ptr, std::placeholders::_1)); +#endif } + +#if 0 if (send_packet_proto) { RS_DEBUG << "------------------------------------------------------" << RS_REND; @@ -206,6 +256,7 @@ void AdapterManager::init(const YAML::Node& config) std::bind(&AdapterBase::sendPacket, transmitter_ptr, std::placeholders::_1)); } #endif + if (send_point_cloud_ros) { RS_DEBUG << "------------------------------------------------------" << RS_REND; @@ -213,12 +264,16 @@ void AdapterManager::init(const YAML::Node& config) RS_DEBUG << "PointCloud Topic: " << lidar_config[i]["ros"]["ros_send_point_cloud_topic"].as() << RS_REND; RS_DEBUG << "------------------------------------------------------" << RS_REND; + lidar_config[i]["send_point_cloud_ros"] = true; + AdapterBase::Ptr transmitter_ptr = createTransmitter(lidar_config[i], AdapterType::PointCloudRosAdapter); point_cloud_transmit_adapter_vec_.emplace_back(transmitter_ptr); + point_cloud_receive_adapter_vec_[i]->regRecvCallback( std::bind(&AdapterBase::sendPointCloud, transmitter_ptr, std::placeholders::_1)); } + #if 0 if (send_point_cloud_proto) { diff --git a/src/manager/adapter_manager.h b/src/manager/adapter_manager.h index 3423253b..16a01e08 100644 --- a/src/manager/adapter_manager.h +++ b/src/manager/adapter_manager.h @@ -70,23 +70,19 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ******************************************************************************************************************/ #pragma once + #include "utility/yaml_reader.hpp" -#include "adapter/driver_adapter.hpp" -#include "adapter/point_cloud_ros_adapter.hpp" -#if 0 -#include "adapter/packet_ros_adapter.hpp" -#include "adapter/packet_protobuf_adapter.hpp" -#include "adapter/point_cloud_protobuf_adapter.hpp" -#include "adapter/camera_trigger_adapter.hpp" -#endif +#include "adapter/adapter_base.hpp" namespace robosense { namespace lidar { + class AdapterManager { public: + AdapterManager() = default; ~AdapterManager(); void init(const YAML::Node& config); @@ -94,10 +90,10 @@ class AdapterManager void stop(); private: + std::shared_ptr createReceiver(const YAML::Node& config, const AdapterType& adapter_type); std::shared_ptr createTransmitter(const YAML::Node& config, const AdapterType& adapter_type); -private: bool packet_thread_flag_; bool point_cloud_thread_flag_; std::vector packet_receive_adapter_vec_; @@ -105,5 +101,6 @@ class AdapterManager std::vector packet_transmit_adapter_vec_; std::vector point_cloud_transmit_adapter_vec_; }; + } // namespace lidar } // namespace robosense diff --git a/src/msg/ros_msg_translator.h b/src/msg/ros_msg_translator.h index 622d3309..108ab36e 100644 --- a/src/msg/ros_msg_translator.h +++ b/src/msg/ros_msg_translator.h @@ -160,7 +160,7 @@ inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) ros_msg.header.frame_id = rs_msg.frame_id; return std::move(ros_msg); } -#if 0 +#if 1 inline PacketMsg toRsMsg(const LidarType& lidar_type, const PktType& pkt_type, const rslidar_msg::msg::RslidarPacket& ros_msg) { diff --git a/src/rs_driver b/src/rs_driver index bf6f3c6f..3a1ffa2c 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit bf6f3c6fd95081bf3fe46ba0a2e130f655351621 +Subproject commit 3a1ffa2c418468f1db922d2ba58bc43096d0d879 diff --git a/src/utility/common.h b/src/utility/common.h index 2786322c..eb8de336 100644 --- a/src/utility/common.h +++ b/src/utility/common.h @@ -31,7 +31,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *********************************************************************************************************************/ #pragma once + #include "rs_driver/common/common_header.h" #include "utility/time.h" #include "utility/thread_pool.hpp" #include "lock_queue.h" + From e07dfca2e435a549674a9ce349cf41adcda95002 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 30 Dec 2021 19:54:01 +0800 Subject: [PATCH 049/261] refac: refactory adapter --- src/adapter/adapter_base.hpp | 42 +-- src/adapter/driver_adapter.hpp | 132 ++++---- src/adapter/packet_protobuf_adapter.hpp | 307 ++++++------------- src/adapter/packet_ros_adapter.hpp | 166 +++++----- src/adapter/point_cloud_protobuf_adapter.hpp | 216 +++++++------ src/adapter/point_cloud_ros_adapter.hpp | 72 +++-- src/manager/adapter_manager.cpp | 2 + src/msg/ros_msg_translator.h | 110 +------ src/utility/yaml_reader.hpp | 3 + 9 files changed, 432 insertions(+), 618 deletions(-) diff --git a/src/adapter/adapter_base.hpp b/src/adapter/adapter_base.hpp index 2f2e703a..e8f3279b 100644 --- a/src/adapter/adapter_base.hpp +++ b/src/adapter/adapter_base.hpp @@ -64,14 +64,16 @@ enum class AdapterType class AdapterBase { public: + typedef std::shared_ptr Ptr; - AdapterBase() = default; - virtual ~AdapterBase(); - virtual void init(const YAML::Node& config) = 0; - virtual void start(); - virtual void stop(); - virtual void sendPointCloud(const LidarPointCloudMsg& msg); + + virtual void init(const YAML::Node& config) {} + virtual void start() {} + virtual void stop() {} virtual void regRecvCallback(const std::function& callback); + virtual ~AdapterBase() = default; + AdapterBase() = default; + #if 0 virtual void sendScan(const ScanMsg& msg); virtual void sendPacket(const PacketMsg& msg); @@ -82,33 +84,9 @@ class AdapterBase virtual void decodeScan(const ScanMsg& msg); virtual void decodePacket(const PacketMsg& msg); #endif -}; - -inline AdapterBase::~AdapterBase() -{ - stop(); -} - -inline void AdapterBase::start() -{ - return; -} - -inline void AdapterBase::stop() -{ - return; -} - -inline void AdapterBase::sendPointCloud(const LidarPointCloudMsg& msg) -{ - return; -} - -inline void AdapterBase::regRecvCallback(const std::function& callback) -{ - return; -} + virtual void sendPointCloud(const LidarPointCloudMsg& msg); +}; #if 0 inline void AdapterBase::sendScan(const ScanMsg& msg) diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index 1395c4ca..78423cca 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -31,6 +31,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *********************************************************************************************************************/ #pragma once + #include "adapter/adapter_base.hpp" #include "rs_driver/api/lidar_driver.h" @@ -38,56 +39,64 @@ namespace robosense { namespace lidar { + class DriverAdapter : virtual public AdapterBase { public: - DriverAdapter(); - ~DriverAdapter(); - void init(const YAML::Node& config); - void start(); - void stop(); - inline void regRecvCallback(const std::function& callback); + + virtual void init(const YAML::Node& config); + virtual void start(); + virtual void stop(); + + virtual void regRecvCallback(const std::function& callback); + inline void regRecvCallback(const std::function& callback); + #if 0 inline void regRecvCallback(const std::function& callback); - inline void regRecvCallback(const std::function& callback); inline void regRecvCallback(const std::function& callback); void decodeScan(const ScanMsg& msg); void decodePacket(const PacketMsg& msg); #endif + virtual ~DriverAdapter(); + DriverAdapter(); + private: - std::shared_ptr localPointsGetCallback(void); - void localPointsCallback(std::shared_ptr msg); + + void putException(const lidar::Error& msg); + std::shared_ptr getPointCloud(void); + void putPointCloud(std::shared_ptr msg); + void localPacketCallback(const PacketMsg& msg); + #if 0 void localScanCallback(const ScanMsg& msg); - void localPacketCallback(const PacketMsg& msg); void localCameraTriggerCallback(const CameraTrigger& msg); #endif - void localExceptionCallback(const lidar::Error& msg); -private: std::shared_ptr> driver_ptr_; std::vector> point_cloud_cb_vec_; + std::vector> packet_cb_vec_; + std::shared_ptr point_cloud_; #if 0 std::vector> scan_cb_vec_; - std::vector> packet_cb_vec_; std::vector> camera_trigger_cb_vec_; #endif - lidar::ThreadPool::Ptr thread_pool_ptr_; - std::shared_ptr point_cloud_; + // lidar::ThreadPool::Ptr thread_pool_ptr_; }; inline DriverAdapter::DriverAdapter() { + point_cloud_.reset (new LidarPointCloudMsg); +#if 0 driver_ptr_.reset(new lidar::LidarDriver()); thread_pool_ptr_.reset(new lidar::ThreadPool()); - point_cloud_.reset (new LidarPointCloudMsg); driver_ptr_->regExceptionCallback(std::bind(&DriverAdapter::localExceptionCallback, this, std::placeholders::_1)); +#endif } inline DriverAdapter::~DriverAdapter() { - driver_ptr_->stop(); +// driver_ptr_->stop(); } inline void DriverAdapter::init(const YAML::Node& config) @@ -179,8 +188,8 @@ inline void DriverAdapter::init(const YAML::Node& config) break; } - driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localPointsGetCallback, this), - std::bind(&DriverAdapter::localPointsCallback, this, std::placeholders::_1)); + driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::getPointCloud, this), + std::bind(&DriverAdapter::putPointCloud, this, std::placeholders::_1)); #if 0 driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localScanCallback, this, std::placeholders::_1)); driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localPacketCallback, this, std::placeholders::_1)); @@ -212,15 +221,39 @@ inline void DriverAdapter::stop() driver_ptr_->stop(); } -inline void DriverAdapter::regRecvCallback(const std::function& callback) +inline void DriverAdapter::putException(const lidar::Error& msg) { - point_cloud_cb_vec_.emplace_back(callback); + switch (msg.error_code_type) + { + case lidar::ErrCodeType::INFO_CODE: + RS_INFO << msg.toString() << RS_REND; + break; + case lidar::ErrCodeType::WARNING_CODE: + RS_WARNING << msg.toString() << RS_REND; + break; + case lidar::ErrCodeType::ERROR_CODE: + RS_ERROR << msg.toString() << RS_REND; + break; + } } -#if 0 -inline void DriverAdapter::regRecvCallback(const std::function& callback) +inline std::shared_ptr DriverAdapter::getPointCloud(void) { - scan_cb_vec_.emplace_back(callback); + return point_cloud_; +} + +inline void DriverAdapter::putPointCloud(std::shared_ptr msg) +{ + for (auto iter : point_cloud_cb_vec_) + { + iter(*msg); + } +} + +inline void DriverAdapter::regRecvCallback( + const std::function& callback) +{ + point_cloud_cb_vec_.emplace_back(callback); } inline void DriverAdapter::regRecvCallback(const std::function& callback) @@ -228,6 +261,21 @@ inline void DriverAdapter::regRecvCallback(const std::functioncommit([this, msg, iter]() { iter(msg); }); + } +} + +#if 0 +inline void DriverAdapter::regRecvCallback(const std::function& callback) +{ + scan_cb_vec_.emplace_back(callback); +} + inline void DriverAdapter::regRecvCallback(const std::function& callback) { camera_trigger_cb_vec_.emplace_back(callback); @@ -248,19 +296,6 @@ inline void DriverAdapter::decodePacket(const PacketMsg& msg) } #endif -inline std::shared_ptr DriverAdapter::localPointsGetCallback(void) -{ - return point_cloud_; -} - -inline void DriverAdapter::localPointsCallback(std::shared_ptr msg) -{ - for (auto iter : point_cloud_cb_vec_) - { - iter(*msg); - } -} - #if 0 inline void DriverAdapter::localScanCallback(const ScanMsg& msg) { @@ -270,14 +305,6 @@ inline void DriverAdapter::localScanCallback(const ScanMsg& msg) } } -inline void DriverAdapter::localPacketCallback(const PacketMsg& msg) -{ - for (auto iter : packet_cb_vec_) - { - thread_pool_ptr_->commit([this, msg, iter]() { iter(msg); }); - } -} - inline void DriverAdapter::localCameraTriggerCallback(const CameraTrigger& msg) { for (auto iter : camera_trigger_cb_vec_) @@ -287,21 +314,6 @@ inline void DriverAdapter::localCameraTriggerCallback(const CameraTrigger& msg) } #endif -inline void DriverAdapter::localExceptionCallback(const lidar::Error& msg) -{ - switch (msg.error_code_type) - { - case lidar::ErrCodeType::INFO_CODE: - RS_INFO << msg.toString() << RS_REND; - break; - case lidar::ErrCodeType::WARNING_CODE: - RS_WARNING << msg.toString() << RS_REND; - break; - case lidar::ErrCodeType::ERROR_CODE: - RS_ERROR << msg.toString() << RS_REND; - break; - } -} } // namespace lidar } // namespace robosense diff --git a/src/adapter/packet_protobuf_adapter.hpp b/src/adapter/packet_protobuf_adapter.hpp index 7a301705..69171d71 100644 --- a/src/adapter/packet_protobuf_adapter.hpp +++ b/src/adapter/packet_protobuf_adapter.hpp @@ -31,295 +31,174 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *********************************************************************************************************************/ #pragma once -#ifdef PROTO_FOUND + #include "adapter/adapter_base.hpp" #include "utility/protobuf_communicator.hpp" #include "msg/proto_msg_translator.h" + +#ifdef PROTO_FOUND + constexpr size_t PKT_RECEIVE_BUF_SIZE = 2000000; namespace robosense { namespace lidar { -class PacketProtoAdapter : virtual public AdapterBase + +class PacketProtoSource { public: - PacketProtoAdapter(); - ~PacketProtoAdapter(); void init(const YAML::Node& config); void start(); void stop(); - void regRecvCallback(const std::function& callback); - void regRecvCallback(const std::function& callback); - void sendScan(const ScanMsg& msg); - void sendPacket(const PacketMsg& msg); -private: - void localMsopCallback(const ScanMsg& msg); - void recvMsopPkts(); - void spliceMsopPkts(); - void sendMsop(); - void localDifopCallback(const PacketMsg& msg); - void recvDifopPkts(); - void spliceDifopPkts(); - void sendDifop(); + void regRecvCallback(const std::function& callback); private: - std::vector> scan_cb_vec_; - std::vector> packet_cb_vec_; - std::unique_ptr scan_proto_com_ptr_; - std::unique_ptr packet_proto_com_ptr_; - lidar::ThreadPool::Ptr thread_pool_ptr_; - lidar::Queue scan_send_queue_; - lidar::Queue packet_send_queue_; - lidar::Queue> scan_recv_queue_; - lidar::Queue> packet_recv_queue_; - lidar::Thread scan_recv_thread_; - lidar::Thread packet_recv_thread_; - int old_frmnum_; - int new_frmnum_; - void* scan_buff_; -}; -inline PacketProtoAdapter::PacketProtoAdapter() : old_frmnum_(0), new_frmnum_(0) -{ - thread_pool_ptr_.reset(new ThreadPool()); -} + void putPacket(const PacketMsg& msg); -inline PacketProtoAdapter::~PacketProtoAdapter() -{ - stop(); -} - -inline void PacketProtoAdapter::init(const YAML::Node& config) -{ - bool send_packet_proto; - int msg_source = 0; - std::string packet_send_ip; - std::string msop_send_port; - std::string difop_send_port; - uint16_t msop_recv_port; - uint16_t difop_recv_port; - yamlReadAbort(config, "msg_source", msg_source); - yamlRead(config, "send_packet_proto", send_packet_proto, false); - yamlReadAbort(config["proto"], "packet_send_ip", packet_send_ip); - yamlReadAbort(config["proto"], "msop_send_port", msop_send_port); - yamlReadAbort(config["proto"], "difop_send_port", difop_send_port); - yamlReadAbort(config["proto"], "msop_recv_port", msop_recv_port); - yamlReadAbort(config["proto"], "difop_recv_port", difop_recv_port); - scan_proto_com_ptr_.reset(new ProtoCommunicator); - packet_proto_com_ptr_.reset(new ProtoCommunicator); - if (msg_source == MsgSource::MSG_FROM_PROTO_PACKET) - { - if ((scan_proto_com_ptr_->initReceiver(msop_recv_port) == -1) || - (packet_proto_com_ptr_->initReceiver(difop_recv_port) == -1)) - { - RS_ERROR << "LidarPacketsReceiver: Create UDP Receiver Socket failed or Bind Network failed!" << RS_REND; - exit(-1); - } - send_packet_proto = false; - } - if (send_packet_proto) - { - if ((scan_proto_com_ptr_->initSender(msop_send_port, packet_send_ip) == -1) || - (packet_proto_com_ptr_->initSender(difop_send_port, packet_send_ip) == -1)) - { - RS_ERROR << "LidarPacketsReceiver: Create UDP Sender Socket failed ! " << RS_REND; - exit(-1); - } - } -} + std::unique_ptr pkt_proto_com_ptr_; + std::function cb_pkt_; + std::thread recv_thread_; + std::thread splice_thread_; +}; -inline void PacketProtoAdapter::start() +void PacketProtoSource::regRecvCallback(const std::function& cb_pkt) { - scan_buff_ = malloc(PKT_RECEIVE_BUF_SIZE); - scan_recv_thread_.start_ = true; - scan_recv_thread_.thread_.reset(new std::thread([this]() { recvMsopPkts(); })); - packet_recv_thread_.start_ = true; - packet_recv_thread_.thread_.reset(new std::thread([this]() { recvDifopPkts(); })); + cb_pkt_ = cb_pkt; } -inline void PacketProtoAdapter::stop() +inline void PacketProtoSource::putPacket(const PacketMsg& msg) { - if (scan_recv_thread_.start_.load()) + if (cb_pkt_) { - scan_recv_thread_.start_.store(false); - scan_recv_thread_.thread_->join(); - free(scan_buff_); - } - if (packet_recv_thread_.start_.load()) - { - packet_recv_thread_.start_.store(false); - packet_recv_thread_.thread_->join(); + cb_pkt_(msg); } } -inline void PacketProtoAdapter::regRecvCallback(const std::function& callback) +void PacketProtoSource::init(const YAML::Node& config) { - scan_cb_vec_.emplace_back(callback); -} + uint16_t packet_recv_port; + yamlReadAbort(config["proto"], "packet_recv_port", packet_recv_port); -inline void PacketProtoAdapter::regRecvCallback(const std::function& callback) -{ - packet_cb_vec_.emplace_back(callback); -} - -inline void PacketProtoAdapter::sendScan(const ScanMsg& msg) -{ - scan_send_queue_.push(msg); - if (scan_send_queue_.is_task_finished_.load()) + pkt_proto_com_ptr_.reset(new ProtoCommunicator); + int ret = pkt_proto_com_ptr_->initReceiver(packet_recv_port); + if (ret == -1) { - scan_send_queue_.is_task_finished_.store(false); - thread_pool_ptr_->commit([this]() { sendMsop(); }); + RS_ERROR << "Failed to create UDP receiver socket failed or bind." << RS_REND; + exit(-1); } } -inline void PacketProtoAdapter::sendPacket(const PacketMsg& msg) +inline void PacketProtoSource::start() { - packet_send_queue_.push(msg); - if (packet_send_queue_.is_task_finished_.load()) - { - packet_send_queue_.is_task_finished_.store(false); - thread_pool_ptr_->commit([this]() { sendDifop(); }); - } + recv_thread_ = std::thread(std::bind(&PacketProtoSource::recvPacket, this)); } -inline void PacketProtoAdapter::localMsopCallback(const ScanMsg& msg) +inline void PacketProtoSource::stop() { - for (auto& cb : scan_cb_vec_) - { - cb(msg); - } + thread.join(); } -inline void PacketProtoAdapter::recvMsopPkts() +inline void PacketProtoSource::recvPacket() { - bool start_check = true; - while (scan_recv_thread_.start_.load()) + while (packet_recv_thread_.start_.load()) { void* p_data = malloc(MAX_RECEIVE_LENGTH); + ProtoMsgHeader tmp_header; - int ret = scan_proto_com_ptr_->receiveProtoMsg(p_data, MAX_RECEIVE_LENGTH, tmp_header); - if (start_check) - { - if (tmp_header.msg_id == 0) - { - start_check = false; - } - else - { - continue; - } - } + int ret = packet_proto_com_ptr_->receiveProtoMsg(p_data, MAX_RECEIVE_LENGTH, tmp_header); if (ret == -1) { - RS_WARNING << "Packets Protobuf receiving error" << RS_REND; continue; } - scan_recv_queue_.push(std::make_pair(p_data, tmp_header)); - if (scan_recv_queue_.is_task_finished_.load()) - { - scan_recv_queue_.is_task_finished_.store(false); - thread_pool_ptr_->commit([&]() { spliceMsopPkts(); }); - } + + packet_recv_queue_.push(std::make_pair(p_data, tmp_header)); } } -inline void PacketProtoAdapter::spliceMsopPkts() +inline void PacketProtoSource::splicePacket() { - while (scan_recv_queue_.size() > 0) + while (1) { - if (scan_recv_thread_.start_.load()) - { - auto pair = scan_recv_queue_.front(); - old_frmnum_ = new_frmnum_; - new_frmnum_ = pair.second.frame_num; - memcpy((uint8_t*)scan_buff_ + pair.second.msg_id * SPLIT_SIZE, pair.first, SPLIT_SIZE); - if ((old_frmnum_ == new_frmnum_) && (pair.second.msg_id == pair.second.total_msg_cnt - 1)) - { - proto_msg::LidarScan proto_msg; - proto_msg.ParseFromArray(scan_buff_, pair.second.total_msg_length); - localMsopCallback(toRsMsg(proto_msg)); - } - } - free(scan_recv_queue_.front().first); - scan_recv_queue_.pop(); + auto pair = packet_recv_queue_.pop(); + + proto_msg::LidarPacket protomsg; + protomsg.ParseFromArray(pair.first, pair.second.msg_length); + + putPacket(toRsMsg(protomsg)); + free(packet_recv_queue_.front().first); } - scan_recv_queue_.is_task_finished_.store(true); } -inline void PacketProtoAdapter::sendMsop() +class PacketProtoAdapter : virtual public AdapterBase { - while (scan_send_queue_.size() > 0) - { - proto_msg::LidarScan proto_msg = toProtoMsg(scan_send_queue_.popFront()); - if (!scan_proto_com_ptr_->sendSplitMsg(proto_msg)) - { - RS_WARNING << "Msop packets Protobuf sending error" << RS_REND; - } - } - scan_send_queue_.is_task_finished_.store(true); +public: + + void init(const YAML::Node& config); + void start(); + void stop(); + void sendPacket(const PacketMsg& msg); + virtual ~PacketProtoAdapter(); + +private: + + void internSendPacket(); + + std::unique_ptr packet_proto_com_ptr_; + lidar::SyncQueue pkt_queue_; + std::thread send_thread_; +}; + +inline PacketProtoAdapter::~PacketProtoAdapter() +{ + stop(); } -inline void PacketProtoAdapter::localDifopCallback(const PacketMsg& msg) +inline void PacketProtoAdapter::init(const YAML::Node& config) { - for (auto& cb : packet_cb_vec_) + std::string packet_send_ip; + yamlReadAbort(config["proto"], "packet_send_ip", packet_send_ip); + std::string packet_send_port; + yamlReadAbort(config["proto"], "packet_send_port", packet_send_port); + + packet_proto_com_ptr_.reset(new ProtoCommunicator); + int ret = packet_proto_com_ptr_->initSender(packet_send_port, packet_send_ip); + if (ret == -1) { - cb(msg); + RS_ERROR << "LidarPacketsReceiver: Create UDP Sender Socket failed ! " << RS_REND; + exit(-1); } } -inline void PacketProtoAdapter::recvDifopPkts() +inline void PacketProtoAdapter::start() { - while (packet_recv_thread_.start_.load()) - { - void* p_data = malloc(MAX_RECEIVE_LENGTH); - ProtoMsgHeader tmp_header; - int ret = packet_proto_com_ptr_->receiveProtoMsg(p_data, MAX_RECEIVE_LENGTH, tmp_header); + send_thread_ = std::thread(std::bind(&PacketProtoAdapter::internSendPacket, this)); +} - if (ret == -1) - { - continue; - } - packet_recv_queue_.push(std::make_pair(p_data, tmp_header)); - if (packet_recv_queue_.is_task_finished_.load()) - { - packet_recv_queue_.is_task_finished_.store(false); - thread_pool_ptr_->commit([&]() { spliceDifopPkts(); }); - } - } +inline void PacketProtoAdapter::stop() +{ + to_exit_ = true; + send_thread_.join(); } -inline void PacketProtoAdapter::spliceDifopPkts() +inline void PacketProtoAdapter::sendPacket(const PacketMsg& msg) { - while (packet_recv_queue_.size() > 0) - { - if (packet_recv_thread_.start_.load()) - { - auto pair = packet_recv_queue_.front(); - proto_msg::LidarPacket protomsg; - protomsg.ParseFromArray(pair.first, pair.second.msg_length); - localDifopCallback(toRsMsg(protomsg)); - } - free(packet_recv_queue_.front().first); - packet_recv_queue_.pop(); - } - packet_recv_queue_.is_task_finished_.store(true); + pkt_queue_.push(msg); } -inline void PacketProtoAdapter::sendDifop() +inline void PacketProtoAdapter::internSendPacket() { - while (packet_send_queue_.size() > 0) + PacketMsg msg = pkt_send_queue_.popWait(1000); + proto_msg::LidarPacket proto_msg = toProtoMsg(msg); + if (!packet_proto_com_ptr_->sendSingleMsg(proto_msg)) { - proto_msg::LidarPacket proto_msg = toProtoMsg(packet_send_queue_.popFront()); - if (!packet_proto_com_ptr_->sendSingleMsg(proto_msg)) - { - RS_WARNING << "Difop packets Protobuf sending error" << RS_REND; - } + RS_WARNING << "Difop packets Protobuf sending error" << RS_REND; } - packet_send_queue_.is_task_finished_.store(true); } } // namespace lidar } // namespace robosense -#endif // PROTO_FOUND \ No newline at end of file +#endif // PROTO_FOUND + diff --git a/src/adapter/packet_ros_adapter.hpp b/src/adapter/packet_ros_adapter.hpp index 29f0845b..ec968941 100644 --- a/src/adapter/packet_ros_adapter.hpp +++ b/src/adapter/packet_ros_adapter.hpp @@ -31,119 +31,127 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *********************************************************************************************************************/ #pragma once -#ifdef ROS_FOUND -#include + #include "adapter/adapter_base.hpp" -#include "msg/ros_msg_translator.h" +//#include "msg/ros_msg_translator.h" namespace robosense { namespace lidar { -class PacketRosAdapter : virtual public AdapterBase -{ -public: - PacketRosAdapter() = default; - virtual ~PacketRosAdapter() = default; - void init(const YAML::Node& config); - void regRecvCallback(const std::function& callback); - void regRecvCallback(const std::function& callback); - void sendScan(const ScanMsg& msg); - void sendPacket(const PacketMsg& msg); - -private: - void localMsopCallback(const rslidar_msgs::rslidarScan& msg); - void localDifopCallback(const rslidar_msgs::rslidarPacket& msg); -private: - std::unique_ptr nh_; - LidarType lidar_type_; - std::vector> scan_cb_vec_; - std::vector> packet_cb_vec_; - ros::Publisher scan_pub_; - ros::Publisher packet_pub_; - ros::Subscriber scan_sub_; - ros::Subscriber packet_sub_; -}; +#ifdef ROS_FOUND +#include -inline void PacketRosAdapter::init(const YAML::Node& config) +inline PacketMsg toRsMsg(const rslidar_msgs::rslidarPacket& ros_msg) { - nh_ = std::unique_ptr(new ros::NodeHandle()); - - std::string lidar_type_str; - yamlRead(config["driver"], "lidar_type", lidar_type_str, "RS16"); - lidar_type_ = strToLidarType(lidar_type_str); + PacketMsg rs_msg(1500); +#if 0 + rs_msg.seq = ros_msg.header.seq; + rs_msg.timestamp = ros_msg.header.stamp.toSec(); + rs_msg.frame_id = ros_msg.header.frame_id; +#endif + for (size_t i = 0; i < pkt_length; i++) + { + rs_msg.packet[i] = ros_msg.data[i]; + } + return std::move(rs_msg); +} - int msg_source; - yamlReadAbort(config, "msg_source", msg_source); - if (msg_source == MsgSource::MSG_FROM_ROS_PACKET) +class PacketRosSource +{ +public: + void init(const YAML::Node& config) { std::string ros_recv_topic; yamlRead(config["ros"], "ros_recv_packet_topic", ros_recv_topic, "rslidar_packets"); - packet_sub_ = nh_->subscribe(ros_recv_topic + "_difop", 1, &PacketRosAdapter::localDifopCallback, this); - scan_sub_ = nh_->subscribe(ros_recv_topic, 1, &PacketRosAdapter::localMsopCallback, this); - send_packet_ros = false; + + nh_ = std::unique_ptr(new ros::NodeHandle()); + pkt_sub_ = nh_->subscribe(ros_recv_topic, 1, &PacketRosAdapter::putPacket, this); } - bool send_packet_ros; - yamlRead(config, "send_packet_ros", send_packet_ros, false); - if (send_packet_ros) + void regRecvCallback(const std::function& callback) { - std::string ros_send_topic; - yamlRead(config["ros"], "ros_send_packet_topic", ros_send_topic, "rslidar_packets"); - packet_pub_ = nh_->advertise(ros_send_topic + "_difop", 10); - scan_pub_ = nh_->advertise(ros_send_topic, 10); + cb_pkt_ = cb_pkt; } -} -inline void PacketRosAdapter::regRecvCallback(const std::function& callback) -{ - scan_cb_vec_.emplace_back(callback); -} +private: -inline void PacketRosAdapter::regRecvCallback(const std::function& callback) -{ - packet_cb_vec_.emplace_back(callback); -} + void putPacket(const rslidar_msgs::rslidarPacket& msg) + { + if (cb_pkt_) + { + cb_pkt_(toRsMsg(msg)); + } + } -inline void PacketRosAdapter::sendScan(const ScanMsg& msg) + std::unique_ptr nh_; + ros::Subscriber pkt_sub_; + std::function cb_pkt_; +}; + +inline rslidar_msgs::rslidarPacket toRosMsg(const PacketMsg& rs_msg) { - scan_pub_.publish(toRosMsg(msg)); + rslidar_msgs::rslidarPacket ros_msg; + size_t pkt_size = rs_msg.packet.size(); + for (size_t i = 0; i < pkt_size; i++) + { + ros_msg.data[i] = rs_msg.packet[i]; + } + return std::move(ros_msg); } -inline void PacketRosAdapter::sendPacket(const PacketMsg& msg) +class PacketRosAdapter : virtual public AdapterBase { - packet_pub_.publish(toRosMsg(msg)); -} +public: + + PacketRosAdapter() = default; + virtual ~PacketRosAdapter() = default; + + void init(const YAML::Node& config); + void sendPacket(const PacketMsg& msg); + +private: -inline void PacketRosAdapter::localMsopCallback(const rslidar_msgs::rslidarScan& msg) + std::unique_ptr nh_; + ros::Publisher pkt_pub_; +}; + +inline void PacketRosAdapter::init(const YAML::Node& config) { - for (auto& cb : scan_cb_vec_) - { - cb(toRsMsg(lidar_type_, PktType::MSOP, msg)); - } + std::string ros_send_topic; + yamlRead(config["ros"], "ros_send_packet_topic", ros_send_topic, "rslidar_packets"); + + nh_ = std::unique_ptr(new ros::NodeHandle()); + pkt_pub_ = nh_->advertise(ros_send_topic, 10); } -inline void PacketRosAdapter::localDifopCallback(const rslidar_msgs::rslidarPacket& msg) +inline void PacketRosAdapter::sendPacket(const PacketMsg& msg) { - for (auto& cb : packet_cb_vec_) - { - cb(toRsMsg(lidar_type_, PktType::DIFOP, msg)); - } + pkt_pub_.publish(toRosMsg(msg)); } -} // namespace lidar -} // namespace robosense #endif // ROS_FOUND #ifdef ROS2_FOUND #include -#include "adapter/adapter_base.hpp" -#include "msg/ros_msg_translator.h" -namespace robosense -{ -namespace lidar + +#if 0 +inline rslidar_msg::msg::RslidarPacket toRosMsg(const PacketMsg& rs_msg) { + rslidar_msg::msg::RslidarPacket ros_msg; +#if 0 + ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); + ros_msg.header.stamp.nanosec = (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); + ros_msg.header.frame_id = rs_msg.frame_id; +#endif + for (size_t i = 0; i < rs_msg.packet.size(); i++) + { + ros_msg.data[i] = rs_msg.packet[i]; + } + return std::move(ros_msg); +} + class PacketRosAdapter : virtual public AdapterBase { public: @@ -251,6 +259,6 @@ inline void PacketRosAdapter::localDifopCallback(const rslidar_msg::msg::Rslidar cb(toRsMsg(lidar_type_, PktType::DIFOP, *msg)); } } -} // namespace lidar -} // namespace robosense +#endif + #endif // ROS2_FOUND diff --git a/src/adapter/point_cloud_protobuf_adapter.hpp b/src/adapter/point_cloud_protobuf_adapter.hpp index 4bf42ec0..9216cdb8 100644 --- a/src/adapter/point_cloud_protobuf_adapter.hpp +++ b/src/adapter/point_cloud_protobuf_adapter.hpp @@ -31,146 +31,81 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *********************************************************************************************************************/ #pragma once + #ifdef PROTO_FOUND + #include "adapter/adapter_base.hpp" #include "utility/protobuf_communicator.hpp" #include "msg/proto_msg_translator.h" + constexpr size_t RECEIVE_BUF_SIZE = 10000000; namespace robosense { namespace lidar { -class PointCloudProtoAdapter : virtual public AdapterBase + +class PointCloudProtoSource : virtual public AdapterBase { public: + PointCloudProtoAdapter(); ~PointCloudProtoAdapter(); + void init(const YAML::Node& config); void start(); void stop(); void regRecvCallback(const std::function& callback); - void sendPointCloud(const LidarPointCloudMsg& msg); private: + void localCallback(const LidarPointCloudMsg& msg); - void sendPoints(); - void recvPoints(); - void splicePoints(); + void recvPointCloud(); + void splicePointCloud(); -private: - std::vector> point_cloud_cb_vec_; - lidar::Queue point_cloud_send_queue_; - lidar::Queue> point_cloud_recv_queue_; std::unique_ptr proto_com_ptr_; - lidar::ThreadPool::Ptr thread_pool_ptr_; lidar::Thread recv_thread_; + + std::function cb_pkt_; + lidar::Queue> point_cloud_recv_queue_; int old_frmnum_; int new_frmnum_; - void* buff_; }; -inline PointCloudProtoAdapter::PointCloudProtoAdapter() : old_frmnum_(0), new_frmnum_(0) +inline void PointCloudProtoSource::regRecvCallback( + const std::function& cb_pkt) { - thread_pool_ptr_.reset(new lidar::ThreadPool()); + cb_pkt_ = cb_pkt; } -inline PointCloudProtoAdapter::~PointCloudProtoAdapter() +inline void PointCloudProtoSource::putPointCloud(const LidarPointCloudMsg& rs_msg) { - stop(); -} - -inline void PointCloudProtoAdapter::init(const YAML::Node& config) -{ - int msg_source = 0; - bool send_point_cloud_proto; - std::string point_cloud_send_port; - std::string point_cloud_send_ip; - uint16_t point_cloud_recv_port; - proto_com_ptr_.reset(new ProtoCommunicator); - yamlReadAbort(config, "msg_source", msg_source); - yamlRead(config, "send_point_cloud_proto", send_point_cloud_proto, false); - yamlReadAbort(config["proto"], "point_cloud_send_port", point_cloud_send_port); - yamlReadAbort(config["proto"], "point_cloud_send_ip", point_cloud_send_ip); - yamlReadAbort(config["proto"], "point_cloud_recv_port", point_cloud_recv_port); - if (msg_source == MsgSource::MSG_FROM_PROTO_POINTCLOUD) - { - if (proto_com_ptr_->initReceiver(point_cloud_recv_port) == -1) - { - RS_ERROR << "PointCloudProtoAdapter: Create UDP Receiver Socket failed or Bind Network failed!" << RS_REND; - exit(-1); - } - send_point_cloud_proto = false; - } - if (send_point_cloud_proto) + if (cb_pkt_) { - if (proto_com_ptr_->initSender(point_cloud_send_port, point_cloud_send_ip) == -1) - { - RS_ERROR << "PointCloudProtoAdapter: Create UDP Sender Socket failed ! " << RS_REND; - exit(-1); - } + cb_pkt_(rs_msg); } } -inline void PointCloudProtoAdapter::start() +inline void PointCloudProtoSource::init(const YAML::Node& config) { - buff_ = malloc(RECEIVE_BUF_SIZE); - recv_thread_.start_ = true; - recv_thread_.thread_.reset(new std::thread([this]() { recvPoints(); })); -} - -inline void PointCloudProtoAdapter::stop() -{ - if (recv_thread_.start_.load()) - { - recv_thread_.start_.store(false); - recv_thread_.thread_->join(); - free(buff_); - } -} - -inline void PointCloudProtoAdapter::regRecvCallback(const std::function& callback) -{ - point_cloud_cb_vec_.emplace_back(callback); -} - -inline void PointCloudProtoAdapter::sendPointCloud(const LidarPointCloudMsg& msg) -{ - if (point_cloud_send_queue_.size() > 10) - { - RS_WARNING << "Point Cloud Protobuf Sender buffer over flow!" << RS_REND; - point_cloud_send_queue_.clear(); - } - point_cloud_send_queue_.push(msg); - if (point_cloud_send_queue_.is_task_finished_.load()) - { - point_cloud_send_queue_.is_task_finished_.store(false); - thread_pool_ptr_->commit([this]() { sendPoints(); }); - } -} + uint16_t point_cloud_recv_port; + yamlReadAbort(config["proto"], "point_cloud_recv_port", point_cloud_recv_port); -inline void PointCloudProtoAdapter::localCallback(const LidarPointCloudMsg& rs_msg) -{ - for (auto& cb : point_cloud_cb_vec_) + proto_com_ptr_.reset(new ProtoCommunicator); + int ret = proto_com_ptr_->initReceiver(point_cloud_recv_port); + if (ret == -1) { - cb(rs_msg); + RS_ERROR << "Create UDP Receiver Socket failed or Bind Network failed!" << RS_REND; + exit(-1); } } -inline void PointCloudProtoAdapter::sendPoints() +inline void PointCloudProtoSource::start() { - while (point_cloud_send_queue_.size() > 0) - { - proto_msg::LidarPointCloud proto_msg = toProtoMsg(point_cloud_send_queue_.popFront()); - if (!proto_com_ptr_->sendSplitMsg(proto_msg)) - { - RS_WARNING << "PointCloud Protobuf sending error" << RS_REND; - } - } - point_cloud_send_queue_.is_task_finished_.store(true); + recv_thread_ = std::thread(std::bind(&PointCloudProtoSource::recvPointCloud, this)); } -inline void PointCloudProtoAdapter::recvPoints() +inline void PointCloudProtoAdapter::recvPointCloud() { bool start_check = true; while (recv_thread_.start_.load()) @@ -205,7 +140,7 @@ inline void PointCloudProtoAdapter::recvPoints() } } -inline void PointCloudProtoAdapter::splicePoints() +inline void PointCloudProtoAdapter::splicePointCloud() { while (point_cloud_recv_queue_.size() > 0) { @@ -225,9 +160,94 @@ inline void PointCloudProtoAdapter::splicePoints() free(point_cloud_recv_queue_.front().first); point_cloud_recv_queue_.pop(); } - point_cloud_recv_queue_.is_task_finished_.store(true); } +inline void PointCloudProtoSource::stop() +{ + if (recv_thread_.start_.load()) + { + recv_thread_.start_.store(false); + recv_thread_.thread_->join(); + free(buff_); + } +} + +class PointCloudProtoAdapter : virtual public AdapterBase +{ +public: + + PointCloudProtoAdapter(); + ~PointCloudProtoAdapter(); + void init(const YAML::Node& config); + void start(); + void stop(); + + void sendPointCloud(const LidarPointCloudMsg& msg); + +private: + + void internSendPointCloud(); + + std::unique_ptr proto_com_ptr_; + std::thread send_thread_; + lidar::Queue point_cloud_send_queue_; +}; + +inline PointCloudProtoAdapter::PointCloudProtoAdapter() +{ +} + +inline PointCloudProtoAdapter::~PointCloudProtoAdapter() +{ + stop(); +} + +inline void PointCloudProtoAdapter::init(const YAML::Node& config) +{ + std::string point_cloud_send_port; + yamlReadAbort(config["proto"], "point_cloud_send_port", point_cloud_send_port); + std::string point_cloud_send_ip; + yamlReadAbort(config["proto"], "point_cloud_send_ip", point_cloud_send_ip); + + proto_com_ptr_.reset(new ProtoCommunicator); + if (proto_com_ptr_->initSender(point_cloud_send_port, point_cloud_send_ip) == -1) + { + RS_ERROR << "Create UDP Sender Socket failed ! " << RS_REND; + exit(-1); + } +} + +inline void PointCloudProtoAdapter::start() +{ + send_thread_ = std::thread(std::bind(&PacketProtoAdapter::internSendPointCloud, this)); +} + +inline void PointCloudProtoAdapter::stop() +{ + to_exit_ = true; + send_thread_.join(); +} + +inline void PointCloudProtoAdapter::sendPointCloud(const LidarPointCloudMsg& msg) +{ + point_cloud_send_queue_.push(msg); +} + +inline void PointCloudProtoAdapter::internSendPoints() +{ + while (point_cloud_send_queue_.size() > 0) + { + proto_msg::LidarPointCloud proto_msg = toProtoMsg(point_cloud_send_queue_.popFront()); + if (!proto_com_ptr_->sendSplitMsg(proto_msg)) + { + RS_WARNING << "PointCloud Protobuf sending error" << RS_REND; + } + } + point_cloud_send_queue_.is_task_finished_.store(true); +} + + } // namespace lidar } // namespace robosense -#endif // PROTO_FOUND \ No newline at end of file + +#endif // PROTO_FOUND diff --git a/src/adapter/point_cloud_ros_adapter.hpp b/src/adapter/point_cloud_ros_adapter.hpp index 583dfe25..00fcfd0b 100644 --- a/src/adapter/point_cloud_ros_adapter.hpp +++ b/src/adapter/point_cloud_ros_adapter.hpp @@ -32,23 +32,38 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#ifdef ROS_FOUND - -#include #include "adapter/adapter_base.hpp" -#include "msg/ros_msg_translator.h" +//#include "msg/ros_msg_translator.h" + +#include +#include namespace robosense { namespace lidar { -class PointCloudRosAdapter : virtual public AdapterBase + +#ifdef ROS_FOUND +#include + +inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) +{ + sensor_msgs::PointCloud2 ros_msg; + pcl::toROSMsg(rs_msg, ros_msg); + ros_msg.header.frame_id = rs_msg.frame_id; + ros_msg.header.stamp = ros_msg.header.stamp.fromSec(rs_msg.timestamp); + ros_msg.header.seq = rs_msg.seq; + return std::move(ros_msg); +} + +class PointCloudRosAdapter : public AdapterBase { public: - PointCloudRosAdapter() = default; - ~PointCloudRosAdapter() = default; + void init(const YAML::Node& config); void sendPointCloud(const LidarPointCloudMsg& msg); + ~PointCloudRosAdapter() = default; + PointCloudRosAdapter() = default; private: std::shared_ptr nh_; @@ -57,15 +72,12 @@ class PointCloudRosAdapter : virtual public AdapterBase inline void PointCloudRosAdapter::init(const YAML::Node& config) { - bool send_point_cloud_ros; std::string ros_send_topic; + yamlRead(config["ros"], + "ros_send_point_cloud_topic", ros_send_topic, "rslidar_points"); + nh_ = std::unique_ptr(new ros::NodeHandle()); - yamlRead(config, "send_point_cloud_ros", send_point_cloud_ros, false); - yamlRead(config["ros"], "ros_send_point_cloud_topic", ros_send_topic, "rslidar_points"); - if (send_point_cloud_ros) - { - point_cloud_pub_ = nh_->advertise(ros_send_topic, 10); - } + point_cloud_pub_ = nh_->advertise(ros_send_topic, 10); } inline void PointCloudRosAdapter::sendPointCloud(const LidarPointCloudMsg& msg) @@ -73,18 +85,22 @@ inline void PointCloudRosAdapter::sendPointCloud(const LidarPointCloudMsg& msg) point_cloud_pub_.publish(toRosMsg(msg)); } -} // namespace lidar -} // namespace robosense #endif // ROS_FOUND #ifdef ROS2_FOUND #include -#include "adapter/adapter_base.hpp" -#include "msg/ros_msg_translator.h" -namespace robosense -{ -namespace lidar + +inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) { + sensor_msgs::msg::PointCloud2 ros_msg; + pcl::toROSMsg(rs_msg, ros_msg); + ros_msg.header.frame_id = rs_msg.frame_id; + ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); + ros_msg.header.stamp.nanosec = + (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); + return std::move(ros_msg); +} + class PointCloudRosAdapter : virtual public AdapterBase { public: @@ -100,22 +116,20 @@ class PointCloudRosAdapter : virtual public AdapterBase inline void PointCloudRosAdapter::init(const YAML::Node& config) { - bool send_point_cloud_ros; std::string ros_send_topic; + yamlRead(config["ros"], + "ros_send_point_cloud_topic", ros_send_topic, "rslidar_points"); + node_ptr_.reset(new rclcpp::Node("rslidar_points_adapter")); - yamlRead(config, "send_point_cloud_ros", send_point_cloud_ros, false); - yamlRead(config["ros"], "ros_send_point_cloud_topic", ros_send_topic, "rslidar_points"); - if (send_point_cloud_ros) - { - point_cloud_pub_ = node_ptr_->create_publisher(ros_send_topic, 1); - } + point_cloud_pub_ = + node_ptr_->create_publisher(ros_send_topic, 1); } inline void PointCloudRosAdapter::sendPointCloud(const LidarPointCloudMsg& msg) { point_cloud_pub_->publish(toRosMsg(msg)); } +#endif } // namespace lidar } // namespace robosense -#endif // ROS2_FOUND diff --git a/src/manager/adapter_manager.cpp b/src/manager/adapter_manager.cpp index 3e756130..522d3371 100644 --- a/src/manager/adapter_manager.cpp +++ b/src/manager/adapter_manager.cpp @@ -73,8 +73,10 @@ void AdapterManager::init(const YAML::Node& config) bool send_packet_proto; yamlRead(common_config, "send_packet_proto", send_packet_proto, false); +#if 0 bool send_camera_trigger_ros; yamlRead(common_config, "send_camera_trigger_ros", send_camera_trigger_ros, false); +#endif std::string pcap_dir; double pcap_rate; diff --git a/src/msg/ros_msg_translator.h b/src/msg/ros_msg_translator.h index 108ab36e..d70be4af 100644 --- a/src/msg/ros_msg_translator.h +++ b/src/msg/ros_msg_translator.h @@ -53,80 +53,8 @@ namespace lidar /************************************************************************/ /**Translation functions between RoboSense message and ROS message**/ /************************************************************************/ -inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) -{ - sensor_msgs::PointCloud2 ros_msg; - pcl::toROSMsg(rs_msg, ros_msg); - ros_msg.header.stamp = ros_msg.header.stamp.fromSec(rs_msg.timestamp); - ros_msg.header.frame_id = rs_msg.frame_id; - ros_msg.header.seq = rs_msg.seq; - return std::move(ros_msg); -} -#if 0 -inline PacketMsg toRsMsg(const LidarType& lidar_type, const PktType& pkt_type, - const rslidar_msgs::rslidarPacket& ros_msg) -{ - size_t pkt_length; - switch (lidar_type) - { - case LidarType::RSM1: - if (pkt_type == PktType::MSOP) - { - pkt_length = MEMS_MSOP_LEN; - } - else - { - pkt_length = MEMS_DIFOP_LEN; - } - break; - default: - pkt_length = MECH_PKT_LEN; - break; - } - PacketMsg rs_msg(pkt_length); - for (size_t i = 0; i < pkt_length; i++) - { - rs_msg.packet[i] = ros_msg.data[i]; - } - return std::move(rs_msg); -} -inline rslidar_msgs::rslidarPacket toRosMsg(const PacketMsg& rs_msg) -{ - rslidar_msgs::rslidarPacket ros_msg; - size_t pkt_size = rs_msg.packet.size(); - for (size_t i = 0; i < pkt_size; i++) - { - ros_msg.data[i] = rs_msg.packet[i]; - } - return std::move(ros_msg); -} -inline ScanMsg toRsMsg(const LidarType& lidar_type, const PktType& pkt_type, const rslidar_msgs::rslidarScan& ros_msg) -{ - ScanMsg rs_msg; - rs_msg.seq = ros_msg.header.seq; - rs_msg.timestamp = ros_msg.header.stamp.toSec(); - rs_msg.frame_id = ros_msg.header.frame_id; - for (uint32_t i = 0; i < ros_msg.packets.size(); i++) - { - PacketMsg tmp = toRsMsg(lidar_type, pkt_type, ros_msg.packets[i]); - rs_msg.packets.emplace_back(std::move(tmp)); - } - return std::move(rs_msg); -} -inline rslidar_msgs::rslidarScan toRosMsg(const ScanMsg& rs_msg) -{ - rslidar_msgs::rslidarScan ros_msg; - ros_msg.header.stamp = ros_msg.header.stamp.fromSec(rs_msg.timestamp); - ros_msg.header.frame_id = rs_msg.frame_id; - ros_msg.header.seq = rs_msg.seq; - for (uint32_t i = 0; i < rs_msg.packets.size(); i++) - { - rslidar_msgs::rslidarPacket tmp = toRosMsg(rs_msg.packets[i]); - ros_msg.packets.emplace_back(std::move(tmp)); - } - return std::move(ros_msg); -} +#if 0 inline std_msgs::Time toRosMsg(const CameraTrigger& rs_msg) { std_msgs::Time ros_msg; @@ -151,16 +79,7 @@ namespace lidar /************************************************************************/ /**Translation functions between RoboSense message and ROS2 message**/ /************************************************************************/ -inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) -{ - sensor_msgs::msg::PointCloud2 ros_msg; - pcl::toROSMsg(rs_msg, ros_msg); - ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); - ros_msg.header.stamp.nanosec = (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); - ros_msg.header.frame_id = rs_msg.frame_id; - return std::move(ros_msg); -} -#if 1 + inline PacketMsg toRsMsg(const LidarType& lidar_type, const PktType& pkt_type, const rslidar_msg::msg::RslidarPacket& ros_msg) { @@ -188,15 +107,7 @@ inline PacketMsg toRsMsg(const LidarType& lidar_type, const PktType& pkt_type, } return std::move(rs_msg); } -inline rslidar_msg::msg::RslidarPacket toRosMsg(const PacketMsg& rs_msg) -{ - rslidar_msg::msg::RslidarPacket ros_msg; - for (size_t i = 0; i < rs_msg.packet.size(); i++) - { - ros_msg.data[i] = rs_msg.packet[i]; - } - return std::move(ros_msg); -} + inline ScanMsg toRsMsg(const LidarType& lidar_type, const PktType& pkt_type, const rslidar_msg::msg::RslidarScan& ros_msg) { @@ -210,20 +121,7 @@ inline ScanMsg toRsMsg(const LidarType& lidar_type, const PktType& pkt_type, } return rs_msg; } -inline rslidar_msg::msg::RslidarScan toRosMsg(const ScanMsg& rs_msg) -{ - rslidar_msg::msg::RslidarScan ros_msg; - ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); - ros_msg.header.stamp.nanosec = (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); - ros_msg.header.frame_id = rs_msg.frame_id; - for (uint32_t i = 0; i < rs_msg.packets.size(); i++) - { - rslidar_msg::msg::RslidarPacket tmp = toRosMsg(rs_msg.packets[i]); - ros_msg.packets.emplace_back(std::move(tmp)); - } - return ros_msg; -} -#endif + } // namespace lidar } // namespace robosense #endif // ROS2_FOUND diff --git a/src/utility/yaml_reader.hpp b/src/utility/yaml_reader.hpp index d01a680a..8b6c7a32 100644 --- a/src/utility/yaml_reader.hpp +++ b/src/utility/yaml_reader.hpp @@ -31,12 +31,15 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *********************************************************************************************************************/ #pragma once + #include #include "utility/common.h" + namespace robosense { namespace lidar { + template inline void yamlReadAbort(const YAML::Node& yaml, const std::string& key, T& out_val) { From c2e2b2afc87840b5b4672572d1e06c430219f85c Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 31 Dec 2021 18:27:47 +0800 Subject: [PATCH 050/261] refac: refactory adapter --- src/adapter/adapter_base.hpp | 102 ++++----- src/adapter/driver_adapter.hpp | 215 ++++--------------- src/adapter/packet_protobuf_adapter.hpp | 112 +++++----- src/adapter/packet_ros_adapter.hpp | 107 +++++---- src/adapter/point_cloud_protobuf_adapter.hpp | 114 ++++------ src/adapter/point_cloud_ros_adapter.hpp | 42 ++-- src/manager/adapter_manager.cpp | 4 - src/manager/adapter_manager.h | 4 + src/rs_driver | 2 +- src/utility/protobuf_communicator.hpp | 18 +- 10 files changed, 291 insertions(+), 429 deletions(-) diff --git a/src/adapter/adapter_base.hpp b/src/adapter/adapter_base.hpp index e8f3279b..64c7d49d 100644 --- a/src/adapter/adapter_base.hpp +++ b/src/adapter/adapter_base.hpp @@ -33,8 +33,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once //#include "utility/common.h" -#include "rs_driver/msg/packet_msg.h" -#include "rs_driver/msg/scan_msg.h" +#include "rs_driver/msg/packet.h" #include "msg/rs_msg/lidar_point_cloud_msg.h" namespace robosense @@ -42,7 +41,7 @@ namespace robosense namespace lidar { -enum MsgSource +enum SourceType { MSG_FROM_LIDAR = 1, MSG_FROM_ROS_PACKET = 2, @@ -51,84 +50,75 @@ enum MsgSource MSG_FROM_PROTO_POINTCLOUD = 5 }; -enum class AdapterType -{ - DriverAdapter, - PointCloudRosAdapter, - PointCloudProtoAdapter, - PacketRosAdapter, - PacketProtoAdapter, - CameraTriggerRosAdapter -}; - -class AdapterBase +class PointCloudDestination { public: + typedef std::shared_ptr Ptr; - typedef std::shared_ptr Ptr; - - virtual void init(const YAML::Node& config) {} + virtual void init(const YAML::Node& config){} virtual void start() {} virtual void stop() {} - virtual void regRecvCallback(const std::function& callback); - virtual ~AdapterBase() = default; - AdapterBase() = default; - -#if 0 - virtual void sendScan(const ScanMsg& msg); - virtual void sendPacket(const PacketMsg& msg); - virtual void sendCameraTrigger(const CameraTrigger& msg); - virtual void regRecvCallback(const std::function& callback); - virtual void regRecvCallback(const std::function& callback); - virtual void regRecvCallback(const std::function& callback); - virtual void decodeScan(const ScanMsg& msg); - virtual void decodePacket(const PacketMsg& msg); -#endif - virtual void sendPointCloud(const LidarPointCloudMsg& msg); + virtual ~PointCloudDestination() = default; }; -#if 0 -inline void AdapterBase::sendScan(const ScanMsg& msg) +class PacketDestination { - return; -} +public: + typedef std::shared_ptr Ptr; -inline void AdapterBase::sendPacket(const PacketMsg& msg) + virtual void init(const YAML::Node& config){} + virtual void start() {} + virtual void stop() {} + virtual void sendPacket(const Packet& msg); + virtual ~PacketDestination() = default; +}; +class Source { - return; -} +public: + typedef std::shared_ptr Ptr; -inline void AdapterBase::sendCameraTrigger(const CameraTrigger& msg) -{ - return; -} + virtual void init(SourceType src_type, const YAML::Node& config) {} + virtual void start() {} + virtual void stop() {} + virtual void regRecvCallback(PointCloudDestination::Ptr dst); + virtual void regRecvCallback(PacketDestination::Ptr dst); + virtual ~Source() = default; -inline void AdapterBase::regRecvCallback(const std::function& callback) -{ - return; -} +protected: + + void sendPacket(const Packet& msg); + void sendPointCloud(std::shared_ptr msg); + + std::vector pc_cb_vec_; + std::vector pkt_cb_vec_; +}; -inline void AdapterBase::regRecvCallback(const std::function& callback) +inline void Source::regRecvCallback(PacketDestination::Ptr dst) { - return; + pkt_cb_vec_.emplace_back(dst); } -inline void AdapterBase::regRecvCallback(const std::function& callback) +inline void Source::regRecvCallback(PointCloudDestination::Ptr dst) { - return; + pc_cb_vec_.emplace_back(dst); } -inline void AdapterBase::decodeScan(const ScanMsg& msg) +inline void Source::sendPacket(const Packet& msg) { - return; + for (auto iter : pkt_cb_vec_) + { + iter->sendPacket(msg); + } } -inline void AdapterBase::decodePacket(const PacketMsg& msg) +inline void Source::sendPointCloud(std::shared_ptr msg) { - return; + for (auto iter : pc_cb_vec_) + { + iter->sendPointCloud(*msg); + } } -#endif } // namespace lidar } // namespace robosense diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index 78423cca..8c537217 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -40,69 +40,42 @@ namespace robosense namespace lidar { -class DriverAdapter : virtual public AdapterBase +class DriverSource : public Source { public: - - virtual void init(const YAML::Node& config); + virtual void init(SourceType src, const YAML::Node& config); virtual void start(); virtual void stop(); + virtual void regRecvCallback(PacketDestination::Ptr dst); + virtual ~DriverSource(); - virtual void regRecvCallback(const std::function& callback); - inline void regRecvCallback(const std::function& callback); - -#if 0 - inline void regRecvCallback(const std::function& callback); - inline void regRecvCallback(const std::function& callback); - void decodeScan(const ScanMsg& msg); - void decodePacket(const PacketMsg& msg); -#endif - - virtual ~DriverAdapter(); - DriverAdapter(); - -private: +protected: - void putException(const lidar::Error& msg); std::shared_ptr getPointCloud(void); void putPointCloud(std::shared_ptr msg); - void localPacketCallback(const PacketMsg& msg); - -#if 0 - void localScanCallback(const ScanMsg& msg); - void localCameraTriggerCallback(const CameraTrigger& msg); -#endif + void putPacket(const Packet& msg); + void putException(const lidar::Error& msg); - std::shared_ptr> driver_ptr_; - std::vector> point_cloud_cb_vec_; - std::vector> packet_cb_vec_; std::shared_ptr point_cloud_; -#if 0 - std::vector> scan_cb_vec_; - std::vector> camera_trigger_cb_vec_; -#endif - // lidar::ThreadPool::Ptr thread_pool_ptr_; + std::shared_ptr> driver_ptr_; }; -inline DriverAdapter::DriverAdapter() +inline void DriverSource::init(SourceType src_type, const YAML::Node& config) { point_cloud_.reset (new LidarPointCloudMsg); -#if 0 + driver_ptr_.reset(new lidar::LidarDriver()); - thread_pool_ptr_.reset(new lidar::ThreadPool()); - driver_ptr_->regExceptionCallback(std::bind(&DriverAdapter::localExceptionCallback, this, std::placeholders::_1)); -#endif -} -inline DriverAdapter::~DriverAdapter() -{ -// driver_ptr_->stop(); -} + driver_ptr_->regRecvCallback(std::bind(&DriverSource::getPointCloud, this), + std::bind(&DriverSource::putPointCloud, this, std::placeholders::_1)); -inline void DriverAdapter::init(const YAML::Node& config) -{ + driver_ptr_->regExceptionCallback( + std::bind(&DriverSource::putException, this, std::placeholders::_1)); + +#if 0 int msg_source; yamlReadAbort(config, "msg_source", msg_source); +#endif YAML::Node driver_config = yamlSubNodeAbort(config, "driver"); lidar::RSDriverParam driver_param; @@ -143,177 +116,83 @@ inline void DriverAdapter::init(const YAML::Node& config) yamlRead(driver_config, "cut_angle", driver_param.decoder_param.split_angle, 0); yamlRead(driver_config, "num_pkts_split", driver_param.decoder_param.num_blks_split, 0); -#if 0 - yamlRead(driver_config, "x", driver_param.decoder_param.transform_param.x, 0); - yamlRead(driver_config, "y", driver_param.decoder_param.transform_param.y, 0); - yamlRead(driver_config, "z", driver_param.decoder_param.transform_param.z, 0); - yamlRead(driver_config, "roll", driver_param.decoder_param.transform_param.roll, 0); - yamlRead(driver_config, "pitch", driver_param.decoder_param.transform_param.pitch, 0); - yamlRead(driver_config, "yaw", driver_param.decoder_param.transform_param.yaw, 0); -#endif - - -#if 0 - if (config["camera"] && config["camera"].Type() != YAML::NodeType::Null) + switch (src_type) { - for (size_t i = 0; i < config["camera"].size(); i++) - { - double trigger_angle; - std::string frame_id; - yamlRead(config["camera"][i], "trigger_angle", trigger_angle, 0); - yamlRead(config["camera"][i], "frame_id", frame_id, "rs_camera"); - auto iter = driver_param.decoder_param.trigger_param.trigger_map.find(trigger_angle); - if (iter != driver_param.decoder_param.trigger_param.trigger_map.end()) - { - trigger_angle += (double)i / 1000.0; - driver_param.decoder_param.trigger_param.trigger_map.emplace(trigger_angle, frame_id); - } - else - { - driver_param.decoder_param.trigger_param.trigger_map.emplace(trigger_angle, frame_id); - } - } - } -#endif - switch (msg_source) - { - case MsgSource::MSG_FROM_LIDAR: + case SourceType::MSG_FROM_LIDAR: driver_param.input_type = InputType::ONLINE_LIDAR; break; - case MsgSource::MSG_FROM_PCAP: + case SourceType::MSG_FROM_PCAP: driver_param.input_type = InputType::PCAP_FILE; break; - case MsgSource::MSG_FROM_ROS_PACKET: + default: driver_param.input_type = InputType::RAW_PACKET; break; } - driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::getPointCloud, this), - std::bind(&DriverAdapter::putPointCloud, this, std::placeholders::_1)); -#if 0 - driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localScanCallback, this, std::placeholders::_1)); - driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localPacketCallback, this, std::placeholders::_1)); - driver_ptr_->regRecvCallback(std::bind(&DriverAdapter::localCameraTriggerCallback, this, std::placeholders::_1)); -#endif - driver_param.print(); - if (!driver_ptr_->init(driver_param)) { RS_ERROR << "Driver Initialize Error...." << RS_REND; exit(-1); } -#if 0 - else - { - driver_ptr_->initDecoderOnly(driver_param); - } -#endif } -inline void DriverAdapter::start() +inline void DriverSource::start() { driver_ptr_->start(); } -inline void DriverAdapter::stop() +inline DriverSource::~DriverSource() { - driver_ptr_->stop(); + stop(); } -inline void DriverAdapter::putException(const lidar::Error& msg) +inline void DriverSource::stop() { - switch (msg.error_code_type) - { - case lidar::ErrCodeType::INFO_CODE: - RS_INFO << msg.toString() << RS_REND; - break; - case lidar::ErrCodeType::WARNING_CODE: - RS_WARNING << msg.toString() << RS_REND; - break; - case lidar::ErrCodeType::ERROR_CODE: - RS_ERROR << msg.toString() << RS_REND; - break; - } + driver_ptr_->stop(); } -inline std::shared_ptr DriverAdapter::getPointCloud(void) +inline std::shared_ptr DriverSource::getPointCloud(void) { return point_cloud_; } -inline void DriverAdapter::putPointCloud(std::shared_ptr msg) -{ - for (auto iter : point_cloud_cb_vec_) - { - iter(*msg); - } -} - -inline void DriverAdapter::regRecvCallback( - const std::function& callback) -{ - point_cloud_cb_vec_.emplace_back(callback); -} - -inline void DriverAdapter::regRecvCallback(const std::function& callback) -{ - packet_cb_vec_.emplace_back(callback); -} - -inline void DriverAdapter::localPacketCallback(const PacketMsg& msg) -{ - for (auto iter : packet_cb_vec_) - { - iter(msg); - //thread_pool_ptr_->commit([this, msg, iter]() { iter(msg); }); - } -} - -#if 0 -inline void DriverAdapter::regRecvCallback(const std::function& callback) -{ - scan_cb_vec_.emplace_back(callback); -} - -inline void DriverAdapter::regRecvCallback(const std::function& callback) +inline void DriverSource::regRecvCallback(PacketDestination::Ptr dst) { - camera_trigger_cb_vec_.emplace_back(callback); -} + Source::regRecvCallback(dst); -inline void DriverAdapter::decodeScan(const ScanMsg& msg) -{ - std::shared_ptr point_cloud_msg; - if (driver_ptr_->decodeMsopScan(msg, *point_cloud_msg)) + if (pkt_cb_vec_.size() == 1) { - localPointsCallback(point_cloud_msg); + driver_ptr_->regRecvCallback( + std::bind(&DriverSource::putPacket, this, std::placeholders::_1)); } } -inline void DriverAdapter::decodePacket(const PacketMsg& msg) +inline void DriverSource::putPacket(const Packet& msg) { - driver_ptr_->decodeDifopPkt(msg); + sendPacket(msg); } -#endif -#if 0 -inline void DriverAdapter::localScanCallback(const ScanMsg& msg) +void DriverSource::putPointCloud(std::shared_ptr msg) { - for (auto iter : scan_cb_vec_) - { - thread_pool_ptr_->commit([this, msg, iter]() { iter(msg); }); - } + sendPointCloud(msg); } -inline void DriverAdapter::localCameraTriggerCallback(const CameraTrigger& msg) +inline void DriverSource::putException(const lidar::Error& msg) { - for (auto iter : camera_trigger_cb_vec_) + switch (msg.error_code_type) { - thread_pool_ptr_->commit([this, msg, iter]() { iter(msg); }); + case lidar::ErrCodeType::INFO_CODE: + RS_INFO << msg.toString() << RS_REND; + break; + case lidar::ErrCodeType::WARNING_CODE: + RS_WARNING << msg.toString() << RS_REND; + break; + case lidar::ErrCodeType::ERROR_CODE: + RS_ERROR << msg.toString() << RS_REND; + break; } } -#endif - } // namespace lidar } // namespace robosense diff --git a/src/adapter/packet_protobuf_adapter.hpp b/src/adapter/packet_protobuf_adapter.hpp index 69171d71..ac9e8ce4 100644 --- a/src/adapter/packet_protobuf_adapter.hpp +++ b/src/adapter/packet_protobuf_adapter.hpp @@ -34,168 +34,174 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "adapter/adapter_base.hpp" #include "utility/protobuf_communicator.hpp" -#include "msg/proto_msg_translator.h" +#include "rs_driver/utility/sync_queue.h" #ifdef PROTO_FOUND constexpr size_t PKT_RECEIVE_BUF_SIZE = 2000000; +class ProtoCommunicator; + namespace robosense { namespace lidar { -class PacketProtoSource +class ProtoPacketSource : DriverSource { public: - void init(const YAML::Node& config); - void start(); - void stop(); - void regRecvCallback(const std::function& callback); + virtual void init(SourceType src_type, const YAML::Node& config); + virtual void start(); + virtual void stop(); private: - void putPacket(const PacketMsg& msg); + void recvPacket(); + void splicePacket(); std::unique_ptr pkt_proto_com_ptr_; - std::function cb_pkt_; + //SyncQueue pkt_queue_; std::thread recv_thread_; std::thread splice_thread_; }; -void PacketProtoSource::regRecvCallback(const std::function& cb_pkt) +void ProtoPacketSource::init(SourceType src_type, const YAML::Node& config) { - cb_pkt_ = cb_pkt; -} - -inline void PacketProtoSource::putPacket(const PacketMsg& msg) -{ - if (cb_pkt_) - { - cb_pkt_(msg); - } -} + DriverSource::init(src_type, config); -void PacketProtoSource::init(const YAML::Node& config) -{ uint16_t packet_recv_port; yamlReadAbort(config["proto"], "packet_recv_port", packet_recv_port); +#if 0 pkt_proto_com_ptr_.reset(new ProtoCommunicator); int ret = pkt_proto_com_ptr_->initReceiver(packet_recv_port); - if (ret == -1) + if (ret < 0) { RS_ERROR << "Failed to create UDP receiver socket failed or bind." << RS_REND; exit(-1); } +#endif } -inline void PacketProtoSource::start() +inline void ProtoPacketSource::start() { - recv_thread_ = std::thread(std::bind(&PacketProtoSource::recvPacket, this)); + recv_thread_ = std::thread(std::bind(&ProtoPacketSource::recvPacket, this)); + splice_thread_ = std::thread(std::bind(&ProtoPacketSource::splicePacket, this)); } -inline void PacketProtoSource::stop() +inline void ProtoPacketSource::stop() { - thread.join(); + recv_thread_.join(); + splice_thread_.join(); } -inline void PacketProtoSource::recvPacket() +inline void ProtoPacketSource::recvPacket() { - while (packet_recv_thread_.start_.load()) +#if 0 + while (1) { void* p_data = malloc(MAX_RECEIVE_LENGTH); ProtoMsgHeader tmp_header; int ret = packet_proto_com_ptr_->receiveProtoMsg(p_data, MAX_RECEIVE_LENGTH, tmp_header); - if (ret == -1) + if (ret < 0) { continue; } - packet_recv_queue_.push(std::make_pair(p_data, tmp_header)); + pkt_queue_.push(std::make_pair(p_data, tmp_header)); } +#endif } -inline void PacketProtoSource::splicePacket() +inline void ProtoPacketSource::splicePacket() { +#if 0 while (1) { - auto pair = packet_recv_queue_.pop(); + auto pair = pkt_queue_.pop(); proto_msg::LidarPacket protomsg; protomsg.ParseFromArray(pair.first, pair.second.msg_length); - putPacket(toRsMsg(protomsg)); - free(packet_recv_queue_.front().first); + _driver_ptr_->decodePacket(toRsMsg(protomsg)); + + free(pkt_queue_.front().first); } +#endif } -class PacketProtoAdapter : virtual public AdapterBase +class ProtoPacketDestination : public PacketDestination { public: - void init(const YAML::Node& config); - void start(); - void stop(); - void sendPacket(const PacketMsg& msg); - virtual ~PacketProtoAdapter(); + virtual void init(const YAML::Node& config); + virtual void start(); + virtual void stop(); + virtual void sendPacket(const Packet& msg); + virtual ~ProtoPacketDestination(); private: void internSendPacket(); std::unique_ptr packet_proto_com_ptr_; - lidar::SyncQueue pkt_queue_; + SyncQueue pkt_queue_; std::thread send_thread_; + bool to_exit_; }; -inline PacketProtoAdapter::~PacketProtoAdapter() -{ - stop(); -} - -inline void PacketProtoAdapter::init(const YAML::Node& config) +inline void ProtoPacketDestination::init(const YAML::Node& config) { std::string packet_send_ip; yamlReadAbort(config["proto"], "packet_send_ip", packet_send_ip); std::string packet_send_port; yamlReadAbort(config["proto"], "packet_send_port", packet_send_port); +#if 0 packet_proto_com_ptr_.reset(new ProtoCommunicator); int ret = packet_proto_com_ptr_->initSender(packet_send_port, packet_send_ip); - if (ret == -1) + if (ret < -1) { RS_ERROR << "LidarPacketsReceiver: Create UDP Sender Socket failed ! " << RS_REND; exit(-1); } +#endif } -inline void PacketProtoAdapter::start() +inline void ProtoPacketDestination::start() { - send_thread_ = std::thread(std::bind(&PacketProtoAdapter::internSendPacket, this)); + send_thread_ = std::thread(std::bind(&ProtoPacketDestination::internSendPacket, this)); } -inline void PacketProtoAdapter::stop() +inline void ProtoPacketDestination::stop() { to_exit_ = true; send_thread_.join(); } -inline void PacketProtoAdapter::sendPacket(const PacketMsg& msg) +inline ProtoPacketDestination::~ProtoPacketDestination() +{ + stop(); +} + +inline void ProtoPacketDestination::sendPacket(const Packet& msg) { pkt_queue_.push(msg); } -inline void PacketProtoAdapter::internSendPacket() +inline void ProtoPacketDestination::internSendPacket() { +#if 0 PacketMsg msg = pkt_send_queue_.popWait(1000); + proto_msg::LidarPacket proto_msg = toProtoMsg(msg); if (!packet_proto_com_ptr_->sendSingleMsg(proto_msg)) { RS_WARNING << "Difop packets Protobuf sending error" << RS_REND; } +#endif } } // namespace lidar diff --git a/src/adapter/packet_ros_adapter.hpp b/src/adapter/packet_ros_adapter.hpp index ec968941..e7f83ad5 100644 --- a/src/adapter/packet_ros_adapter.hpp +++ b/src/adapter/packet_ros_adapter.hpp @@ -33,7 +33,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include "adapter/adapter_base.hpp" -//#include "msg/ros_msg_translator.h" +#include "msg/ros_msg/lidar_packet_ros.h" namespace robosense { @@ -43,92 +43,92 @@ namespace lidar #ifdef ROS_FOUND #include -inline PacketMsg toRsMsg(const rslidar_msgs::rslidarPacket& ros_msg) +inline Packet toRsMsg(const rslidar_msgs::rslidarPacket& ros_msg) { - PacketMsg rs_msg(1500); -#if 0 - rs_msg.seq = ros_msg.header.seq; - rs_msg.timestamp = ros_msg.header.stamp.toSec(); - rs_msg.frame_id = ros_msg.header.frame_id; -#endif - for (size_t i = 0; i < pkt_length; i++) + Packet rs_msg(1500); + //rs_msg.timestamp = ros_msg.header.stamp.toSec(); + //rs_msg.seq = ros_msg.header.seq; + //rs_msg.type = ros_msg.header.type; + //rs_msg.frame_id = ros_msg.header.frame_id; + for (size_t i = 0; i < 1500; i++) { - rs_msg.packet[i] = ros_msg.data[i]; + rs_msg.buf_[i] = ros_msg.data[i]; } return std::move(rs_msg); } -class PacketRosSource +class RosPacketSource : public DriverSource { public: - void init(const YAML::Node& config) - { - std::string ros_recv_topic; - yamlRead(config["ros"], "ros_recv_packet_topic", ros_recv_topic, "rslidar_packets"); - nh_ = std::unique_ptr(new ros::NodeHandle()); - pkt_sub_ = nh_->subscribe(ros_recv_topic, 1, &PacketRosAdapter::putPacket, this); - } - - void regRecvCallback(const std::function& callback) - { - cb_pkt_ = cb_pkt; - } + virtual void init(SourceType src_type, const YAML::Node& config); private: - void putPacket(const rslidar_msgs::rslidarPacket& msg) - { - if (cb_pkt_) - { - cb_pkt_(toRsMsg(msg)); - } - } + void putPacket(const rslidar_msgs::rslidarPacket& msg); std::unique_ptr nh_; ros::Subscriber pkt_sub_; - std::function cb_pkt_; }; -inline rslidar_msgs::rslidarPacket toRosMsg(const PacketMsg& rs_msg) +void RosPacketSource::init(SourceType src_type, const YAML::Node& config) +{ + DriverSource::init(src_type, config); + + std::string ros_recv_topic; + yamlRead(config["ros"], "ros_recv_packet_topic", + ros_recv_topic, "rslidar_packets"); + + nh_ = std::unique_ptr(new ros::NodeHandle()); + pkt_sub_ = nh_->subscribe(ros_recv_topic, 1, &RosPacketSource::putPacket, this); +} + +void RosPacketSource::putPacket(const rslidar_msgs::rslidarPacket& msg) +{ + driver_ptr_->decodePacket(toRsMsg(msg)); +} + +inline rslidar_msgs::rslidarPacket toRosMsg(const Packet& rs_msg) { rslidar_msgs::rslidarPacket ros_msg; - size_t pkt_size = rs_msg.packet.size(); - for (size_t i = 0; i < pkt_size; i++) + //rs_msg.timestamp = ros_msg.header.stamp.toSec(); + //rs_msg.seq = ros_msg.header.seq; + //rs_msg.type = ros_msg.header.type; + //rs_msg.frame_id = ros_msg.header.frame_id; + for (size_t i = 0; i < rs_msg.buf_.size(); i++) { - ros_msg.data[i] = rs_msg.packet[i]; + ros_msg.data[i] = rs_msg.buf_[i]; } return std::move(ros_msg); } -class PacketRosAdapter : virtual public AdapterBase +class RosPacketDestination : public PacketDestination { public: - PacketRosAdapter() = default; - virtual ~PacketRosAdapter() = default; - - void init(const YAML::Node& config); - void sendPacket(const PacketMsg& msg); + virtual void init(const YAML::Node& config); + virtual void sendPacket(const Packet& msg); + virtual ~RosPacketDestination() = default; private: std::unique_ptr nh_; - ros::Publisher pkt_pub_; + ros::Publisher pub_; }; -inline void PacketRosAdapter::init(const YAML::Node& config) +inline void RosPacketDestination::init(const YAML::Node& config) { std::string ros_send_topic; - yamlRead(config["ros"], "ros_send_packet_topic", ros_send_topic, "rslidar_packets"); + yamlRead(config["ros"], "ros_send_packet_topic", + ros_send_topic, "rslidar_packets"); nh_ = std::unique_ptr(new ros::NodeHandle()); - pkt_pub_ = nh_->advertise(ros_send_topic, 10); + pub_ = nh_->advertise(ros_send_topic, 10); } -inline void PacketRosAdapter::sendPacket(const PacketMsg& msg) +inline void RosPacketDestination::sendPacket(const Packet& msg) { - pkt_pub_.publish(toRosMsg(msg)); + pub_.publish(toRosMsg(msg)); } #endif // ROS_FOUND @@ -136,15 +136,13 @@ inline void PacketRosAdapter::sendPacket(const PacketMsg& msg) #ifdef ROS2_FOUND #include -#if 0 -inline rslidar_msg::msg::RslidarPacket toRosMsg(const PacketMsg& rs_msg) +inline rslidar_msg::msg::RslidarPacket toRosMsg(const Packet& rs_msg) { rslidar_msg::msg::RslidarPacket ros_msg; -#if 0 - ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); - ros_msg.header.stamp.nanosec = (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); - ros_msg.header.frame_id = rs_msg.frame_id; -#endif + //ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); + //ros_msg.header.stamp.nanosec = + // (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); + //ros_msg.header.frame_id = rs_msg.frame_id; for (size_t i = 0; i < rs_msg.packet.size(); i++) { ros_msg.data[i] = rs_msg.packet[i]; @@ -259,6 +257,5 @@ inline void PacketRosAdapter::localDifopCallback(const rslidar_msg::msg::Rslidar cb(toRsMsg(lidar_type_, PktType::DIFOP, *msg)); } } -#endif #endif // ROS2_FOUND diff --git a/src/adapter/point_cloud_protobuf_adapter.hpp b/src/adapter/point_cloud_protobuf_adapter.hpp index 9216cdb8..492d0274 100644 --- a/src/adapter/point_cloud_protobuf_adapter.hpp +++ b/src/adapter/point_cloud_protobuf_adapter.hpp @@ -36,7 +36,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "adapter/adapter_base.hpp" #include "utility/protobuf_communicator.hpp" -#include "msg/proto_msg_translator.h" constexpr size_t RECEIVE_BUF_SIZE = 10000000; @@ -45,68 +44,51 @@ namespace robosense namespace lidar { -class PointCloudProtoSource : virtual public AdapterBase +class ProtoPointCloudSource : public Source { public: - PointCloudProtoAdapter(); - ~PointCloudProtoAdapter(); - - void init(const YAML::Node& config); - void start(); - void stop(); - void regRecvCallback(const std::function& callback); + virtual void init(SourceType src_type, const YAML::Node& config); + virtual void start(); + virtual void stop(); + virtual ~ProtoPointCloudSource(); private: - void localCallback(const LidarPointCloudMsg& msg); void recvPointCloud(); void splicePointCloud(); std::unique_ptr proto_com_ptr_; - lidar::Thread recv_thread_; - - std::function cb_pkt_; - lidar::Queue> point_cloud_recv_queue_; + //SyncQueue> point_cloud_recv_queue_; + std::thread recv_thread_; int old_frmnum_; int new_frmnum_; }; -inline void PointCloudProtoSource::regRecvCallback( - const std::function& cb_pkt) -{ - cb_pkt_ = cb_pkt; -} - -inline void PointCloudProtoSource::putPointCloud(const LidarPointCloudMsg& rs_msg) -{ - if (cb_pkt_) - { - cb_pkt_(rs_msg); - } -} - -inline void PointCloudProtoSource::init(const YAML::Node& config) +inline void ProtoPointCloudSource::init(SourceType src_type, const YAML::Node& config) { uint16_t point_cloud_recv_port; yamlReadAbort(config["proto"], "point_cloud_recv_port", point_cloud_recv_port); +#if 0 proto_com_ptr_.reset(new ProtoCommunicator); int ret = proto_com_ptr_->initReceiver(point_cloud_recv_port); - if (ret == -1) + if (ret < 0) { RS_ERROR << "Create UDP Receiver Socket failed or Bind Network failed!" << RS_REND; exit(-1); } +#endif } -inline void PointCloudProtoSource::start() +inline void ProtoPointCloudSource::start() { - recv_thread_ = std::thread(std::bind(&PointCloudProtoSource::recvPointCloud, this)); + recv_thread_ = std::thread(std::bind(&ProtoPointCloudSource::recvPointCloud, this)); } -inline void PointCloudProtoAdapter::recvPointCloud() +inline void ProtoPointCloudSource::recvPointCloud() { +#if 0 bool start_check = true; while (recv_thread_.start_.load()) { @@ -124,7 +106,8 @@ inline void PointCloudProtoAdapter::recvPointCloud() continue; } } - if (ret == -1) + + if (ret < 0) { RS_WARNING << "PointCloud Protobuf receiving error" << RS_REND; continue; @@ -138,10 +121,12 @@ inline void PointCloudProtoAdapter::recvPointCloud() thread_pool_ptr_->commit([&]() { splicePoints(); }); } } +#endif } -inline void PointCloudProtoAdapter::splicePointCloud() +inline void ProtoPointCloudSource::splicePointCloud() { +#if 0 while (point_cloud_recv_queue_.size() > 0) { if (recv_thread_.start_.load()) @@ -154,35 +139,30 @@ inline void PointCloudProtoAdapter::splicePointCloud() { proto_msg::LidarPointCloud proto_msg; proto_msg.ParseFromArray(buff_, pair.second.total_msg_length); - localCallback(toRsMsg(proto_msg)); + + // sendPointCloud(toRsMsg(proto_msg)); } } free(point_cloud_recv_queue_.front().first); point_cloud_recv_queue_.pop(); } +#endif } -inline void PointCloudProtoSource::stop() +inline void ProtoPointCloudSource::stop() { - if (recv_thread_.start_.load()) - { - recv_thread_.start_.store(false); - recv_thread_.thread_->join(); - free(buff_); - } + recv_thread_.join(); } -class PointCloudProtoAdapter : virtual public AdapterBase +class ProtoPointCloudDestination : public PointCloudDestination { public: - PointCloudProtoAdapter(); - ~PointCloudProtoAdapter(); - void init(const YAML::Node& config); - void start(); - void stop(); - - void sendPointCloud(const LidarPointCloudMsg& msg); + virtual void init(const YAML::Node& config); + virtual void start(); + virtual void stop(); + virtual void sendPointCloud(const LidarPointCloudMsg& msg); + virtual ~ProtoPointCloudDestination() = default; private: @@ -190,51 +170,48 @@ class PointCloudProtoAdapter : virtual public AdapterBase std::unique_ptr proto_com_ptr_; std::thread send_thread_; - lidar::Queue point_cloud_send_queue_; + SyncQueue point_cloud_send_queue_; + bool to_exit_; }; -inline PointCloudProtoAdapter::PointCloudProtoAdapter() -{ -} - -inline PointCloudProtoAdapter::~PointCloudProtoAdapter() -{ - stop(); -} - -inline void PointCloudProtoAdapter::init(const YAML::Node& config) +inline void ProtoPointCloudDestination::init(const YAML::Node& config) { std::string point_cloud_send_port; yamlReadAbort(config["proto"], "point_cloud_send_port", point_cloud_send_port); std::string point_cloud_send_ip; yamlReadAbort(config["proto"], "point_cloud_send_ip", point_cloud_send_ip); +#if 0 proto_com_ptr_.reset(new ProtoCommunicator); - if (proto_com_ptr_->initSender(point_cloud_send_port, point_cloud_send_ip) == -1) + int ret = proto_com_ptr_->initSender(point_cloud_send_port, point_cloud_send_ip); + if (ret < 0) { RS_ERROR << "Create UDP Sender Socket failed ! " << RS_REND; exit(-1); } +#endif } -inline void PointCloudProtoAdapter::start() +inline void ProtoPointCloudDestination::start() { - send_thread_ = std::thread(std::bind(&PacketProtoAdapter::internSendPointCloud, this)); + send_thread_ = + std::thread(std::bind(&ProtoPointCloudDestination::internSendPointCloud, this)); } -inline void PointCloudProtoAdapter::stop() +inline void ProtoPointCloudDestination::stop() { to_exit_ = true; send_thread_.join(); } -inline void PointCloudProtoAdapter::sendPointCloud(const LidarPointCloudMsg& msg) +inline void ProtoPointCloudDestination::sendPointCloud(const LidarPointCloudMsg& msg) { point_cloud_send_queue_.push(msg); } -inline void PointCloudProtoAdapter::internSendPoints() +inline void ProtoPointCloudDestination::internSendPointCloud() { +#if 0 while (point_cloud_send_queue_.size() > 0) { proto_msg::LidarPointCloud proto_msg = toProtoMsg(point_cloud_send_queue_.popFront()); @@ -244,6 +221,7 @@ inline void PointCloudProtoAdapter::internSendPoints() } } point_cloud_send_queue_.is_task_finished_.store(true); +#endif } diff --git a/src/adapter/point_cloud_ros_adapter.hpp b/src/adapter/point_cloud_ros_adapter.hpp index 00fcfd0b..390af6a6 100644 --- a/src/adapter/point_cloud_ros_adapter.hpp +++ b/src/adapter/point_cloud_ros_adapter.hpp @@ -33,8 +33,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include "adapter/adapter_base.hpp" -//#include "msg/ros_msg_translator.h" - #include #include @@ -56,33 +54,32 @@ inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) return std::move(ros_msg); } -class PointCloudRosAdapter : public AdapterBase +class RosPointCloudDestination : public PointCloudDestination { public: - void init(const YAML::Node& config); - void sendPointCloud(const LidarPointCloudMsg& msg); - ~PointCloudRosAdapter() = default; - PointCloudRosAdapter() = default; + virtual void init(const YAML::Node& config); + virtual void sendPointCloud(const LidarPointCloudMsg& msg); + virtual ~RosPointCloudDestination() = default; private: std::shared_ptr nh_; - ros::Publisher point_cloud_pub_; + ros::Publisher pub_; }; -inline void PointCloudRosAdapter::init(const YAML::Node& config) +inline void RosPointCloudDestination::init(const YAML::Node& config) { std::string ros_send_topic; yamlRead(config["ros"], "ros_send_point_cloud_topic", ros_send_topic, "rslidar_points"); nh_ = std::unique_ptr(new ros::NodeHandle()); - point_cloud_pub_ = nh_->advertise(ros_send_topic, 10); + pub_ = nh_->advertise(ros_send_topic, 10); } -inline void PointCloudRosAdapter::sendPointCloud(const LidarPointCloudMsg& msg) +inline void RosPointCloudDestination::sendPointCloud(const LidarPointCloudMsg& msg) { - point_cloud_pub_.publish(toRosMsg(msg)); + pub_.publish(toRosMsg(msg)); } #endif // ROS_FOUND @@ -101,33 +98,32 @@ inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) return std::move(ros_msg); } -class PointCloudRosAdapter : virtual public AdapterBase +class RosPointCloudDestination : virtual public RosPointCloudDestination { public: - PointCloudRosAdapter() = default; - ~PointCloudRosAdapter() = default; - void init(const YAML::Node& config); - void sendPointCloud(const LidarPointCloudMsg& msg); + + virtual void init(const YAML::Node& config); + virtual void sendPointCloud(const LidarPointCloudMsg& msg); + virtual ~RosPointCloudDestination() = default; private: std::shared_ptr node_ptr_; - rclcpp::Publisher::SharedPtr point_cloud_pub_; + rclcpp::Publisher::SharedPtr pub_; }; -inline void PointCloudRosAdapter::init(const YAML::Node& config) +inline void RosPointCloudDestination::init(const YAML::Node& config) { std::string ros_send_topic; yamlRead(config["ros"], "ros_send_point_cloud_topic", ros_send_topic, "rslidar_points"); node_ptr_.reset(new rclcpp::Node("rslidar_points_adapter")); - point_cloud_pub_ = - node_ptr_->create_publisher(ros_send_topic, 1); + pub_ = node_ptr_->create_publisher(ros_send_topic, 1); } -inline void PointCloudRosAdapter::sendPointCloud(const LidarPointCloudMsg& msg) +inline void RosPointCloudDestination::sendPointCloud(const LidarPointCloudMsg& msg) { - point_cloud_pub_->publish(toRosMsg(msg)); + pub_->publish(toRosMsg(msg)); } #endif diff --git a/src/manager/adapter_manager.cpp b/src/manager/adapter_manager.cpp index 522d3371..3060f95a 100644 --- a/src/manager/adapter_manager.cpp +++ b/src/manager/adapter_manager.cpp @@ -33,13 +33,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "manager/adapter_manager.h" #include "adapter/driver_adapter.hpp" #include "adapter/point_cloud_ros_adapter.hpp" - -#if 0 #include "adapter/packet_ros_adapter.hpp" #include "adapter/packet_protobuf_adapter.hpp" #include "adapter/point_cloud_protobuf_adapter.hpp" -#include "adapter/camera_trigger_adapter.hpp" -#endif namespace robosense { diff --git a/src/manager/adapter_manager.h b/src/manager/adapter_manager.h index 16a01e08..e3c37410 100644 --- a/src/manager/adapter_manager.h +++ b/src/manager/adapter_manager.h @@ -91,15 +91,19 @@ class AdapterManager private: +#if 0 std::shared_ptr createReceiver(const YAML::Node& config, const AdapterType& adapter_type); std::shared_ptr createTransmitter(const YAML::Node& config, const AdapterType& adapter_type); bool packet_thread_flag_; bool point_cloud_thread_flag_; + std::vector packet_receive_adapter_vec_; std::vector point_cloud_receive_adapter_vec_; std::vector packet_transmit_adapter_vec_; std::vector point_cloud_transmit_adapter_vec_; +#endif + std::vector sources_; }; } // namespace lidar diff --git a/src/rs_driver b/src/rs_driver index 3a1ffa2c..87234688 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 3a1ffa2c418468f1db922d2ba58bc43096d0d879 +Subproject commit 87234688a113555827e621c0c2fa4d0ab541ae14 diff --git a/src/utility/protobuf_communicator.hpp b/src/utility/protobuf_communicator.hpp index 90f17cfa..e3c10bbb 100644 --- a/src/utility/protobuf_communicator.hpp +++ b/src/utility/protobuf_communicator.hpp @@ -31,7 +31,10 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *********************************************************************************************************************/ #pragma once + #ifdef PROTO_FOUND + +#if 0 #include #include #include @@ -43,21 +46,31 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#endif +#include +#if 0 #include #include #include +#endif + #define SPLIT_SIZE 5000 + #define MAX_RECEIVE_LENGTH 5200 +#if 0 + namespace robosense { namespace lidar { + enum class DataEndianType { RS_BIG_ENDIAN = 0, RS_SMALL_ENDIAN = 1 }; + template class CRSEndian { @@ -399,4 +412,7 @@ class ProtoCommunicator } // namespace lidar } // namespace robosense -#endif // PROTO_FOUND \ No newline at end of file +#endif + +#endif // PROTO_FOUND + From c57bf1c73f5aeb741ba5f504d12467967da77e5f Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 31 Dec 2021 18:48:12 +0800 Subject: [PATCH 051/261] refac: refactory adapter --- src/adapter/{adapter_base.hpp => adapter.hpp} | 20 ++-- src/adapter/camera_trigger_adapter.hpp | 96 ------------------- src/adapter/driver_adapter.hpp | 10 +- ...f_adapter.hpp => proto_packet_adapter.hpp} | 2 +- ...pter.hpp => proto_point_cloud_adapter.hpp} | 2 +- ...ros_adapter.hpp => ros_packet_adapter.hpp} | 4 +- ...dapter.hpp => ros_point_cloud_adapter.hpp} | 2 +- src/manager/adapter_manager.cpp | 8 +- src/manager/adapter_manager.h | 46 +-------- 9 files changed, 25 insertions(+), 165 deletions(-) rename src/adapter/{adapter_base.hpp => adapter.hpp} (99%) delete mode 100644 src/adapter/camera_trigger_adapter.hpp rename src/adapter/{packet_protobuf_adapter.hpp => proto_packet_adapter.hpp} (99%) rename src/adapter/{point_cloud_protobuf_adapter.hpp => proto_point_cloud_adapter.hpp} (99%) rename src/adapter/{packet_ros_adapter.hpp => ros_packet_adapter.hpp} (99%) rename src/adapter/{point_cloud_ros_adapter.hpp => ros_point_cloud_adapter.hpp} (99%) diff --git a/src/adapter/adapter_base.hpp b/src/adapter/adapter.hpp similarity index 99% rename from src/adapter/adapter_base.hpp rename to src/adapter/adapter.hpp index 64c7d49d..270b632e 100644 --- a/src/adapter/adapter_base.hpp +++ b/src/adapter/adapter.hpp @@ -32,7 +32,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -//#include "utility/common.h" #include "rs_driver/msg/packet.h" #include "msg/rs_msg/lidar_point_cloud_msg.h" @@ -41,15 +40,6 @@ namespace robosense namespace lidar { -enum SourceType -{ - MSG_FROM_LIDAR = 1, - MSG_FROM_ROS_PACKET = 2, - MSG_FROM_PCAP = 3, - MSG_FROM_PROTO_PACKET = 4, - MSG_FROM_PROTO_POINTCLOUD = 5 -}; - class PointCloudDestination { public: @@ -73,6 +63,16 @@ class PacketDestination virtual void sendPacket(const Packet& msg); virtual ~PacketDestination() = default; }; + +enum SourceType +{ + MSG_FROM_LIDAR = 1, + MSG_FROM_ROS_PACKET = 2, + MSG_FROM_PCAP = 3, + MSG_FROM_PROTO_PACKET = 4, + MSG_FROM_PROTO_POINTCLOUD = 5 +}; + class Source { public: diff --git a/src/adapter/camera_trigger_adapter.hpp b/src/adapter/camera_trigger_adapter.hpp deleted file mode 100644 index ddf6d432..00000000 --- a/src/adapter/camera_trigger_adapter.hpp +++ /dev/null @@ -1,96 +0,0 @@ -/********************************************************************************************************************* -Copyright (c) 2020 RoboSense -All rights reserved - -By downloading, copying, installing or using the software you agree to this license. If you do not agree to this -license, do not download, install, copy or use the software. - -License Agreement -For RoboSense LiDAR SDK Library -(3-clause BSD License) - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following -disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the names of the RoboSense, nor Suteng Innovation Technology, nor the names of other contributors may be used -to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*********************************************************************************************************************/ - -#pragma once -#ifdef ROS_FOUND -#include "adapter/adapter_base.hpp" -#include "msg/ros_msg_translator.h" -#include -#include - -namespace robosense -{ -namespace lidar -{ -class CameraTriggerRosAdapter : virtual public AdapterBase -{ -public: - CameraTriggerRosAdapter() = default; - ~CameraTriggerRosAdapter() = default; - void init(const YAML::Node& config); - void sendCameraTrigger(const CameraTrigger& msg); - -private: - std::shared_ptr nh_; - std::map pub_map_; -}; - -inline void CameraTriggerRosAdapter::init(const YAML::Node& config) -{ - nh_ = std::unique_ptr(new ros::NodeHandle()); - if (config["camera"] && config["camera"].Type() != YAML::NodeType::Null) - { - for (auto iter : config["camera"]) - { - std::string frame_id; - yamlRead(iter, "frame_id", frame_id, "rs_camera"); - ros::Publisher pub = nh_->advertise(frame_id + "_trigger", 10); - pub_map_.emplace(frame_id, pub); - } - } -} - -inline void CameraTriggerRosAdapter::sendCameraTrigger(const CameraTrigger& msg) -{ - auto iter = pub_map_.find(msg.first); - if (iter != pub_map_.end()) - { - iter->second.publish(toRosMsg(msg)); - } -} - -} // namespace lidar -} // namespace robosense -#endif // ROS_FOUND - -#ifdef ROS2_FOUND -#include "adapter/adapter_base.hpp" -#include "msg/ros_msg_translator.h" -#include "rclcpp/rclcpp.hpp" -namespace robosense -{ -namespace lidar -{ -///< Add in the future -} // namespace lidar -} // namespace robosense -#endif // ROS2_FOUND \ No newline at end of file diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index 8c537217..6c98c8b3 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -32,7 +32,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#include "adapter/adapter_base.hpp" +#include "adapter/adapter.hpp" #include "rs_driver/api/lidar_driver.h" namespace robosense @@ -63,20 +63,12 @@ class DriverSource : public Source inline void DriverSource::init(SourceType src_type, const YAML::Node& config) { point_cloud_.reset (new LidarPointCloudMsg); - driver_ptr_.reset(new lidar::LidarDriver()); - driver_ptr_->regRecvCallback(std::bind(&DriverSource::getPointCloud, this), std::bind(&DriverSource::putPointCloud, this, std::placeholders::_1)); - driver_ptr_->regExceptionCallback( std::bind(&DriverSource::putException, this, std::placeholders::_1)); -#if 0 - int msg_source; - yamlReadAbort(config, "msg_source", msg_source); -#endif - YAML::Node driver_config = yamlSubNodeAbort(config, "driver"); lidar::RSDriverParam driver_param; diff --git a/src/adapter/packet_protobuf_adapter.hpp b/src/adapter/proto_packet_adapter.hpp similarity index 99% rename from src/adapter/packet_protobuf_adapter.hpp rename to src/adapter/proto_packet_adapter.hpp index ac9e8ce4..c8f89d0a 100644 --- a/src/adapter/packet_protobuf_adapter.hpp +++ b/src/adapter/proto_packet_adapter.hpp @@ -32,7 +32,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#include "adapter/adapter_base.hpp" +#include "adapter/adapter.hpp" #include "utility/protobuf_communicator.hpp" #include "rs_driver/utility/sync_queue.h" diff --git a/src/adapter/point_cloud_protobuf_adapter.hpp b/src/adapter/proto_point_cloud_adapter.hpp similarity index 99% rename from src/adapter/point_cloud_protobuf_adapter.hpp rename to src/adapter/proto_point_cloud_adapter.hpp index 492d0274..7748de0c 100644 --- a/src/adapter/point_cloud_protobuf_adapter.hpp +++ b/src/adapter/proto_point_cloud_adapter.hpp @@ -34,7 +34,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifdef PROTO_FOUND -#include "adapter/adapter_base.hpp" +#include "adapter/adapter.hpp" #include "utility/protobuf_communicator.hpp" constexpr size_t RECEIVE_BUF_SIZE = 10000000; diff --git a/src/adapter/packet_ros_adapter.hpp b/src/adapter/ros_packet_adapter.hpp similarity index 99% rename from src/adapter/packet_ros_adapter.hpp rename to src/adapter/ros_packet_adapter.hpp index e7f83ad5..ccecb013 100644 --- a/src/adapter/packet_ros_adapter.hpp +++ b/src/adapter/ros_packet_adapter.hpp @@ -32,7 +32,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#include "adapter/adapter_base.hpp" +#include "adapter/adapter.hpp" #include "msg/ros_msg/lidar_packet_ros.h" namespace robosense @@ -136,6 +136,7 @@ inline void RosPacketDestination::sendPacket(const Packet& msg) #ifdef ROS2_FOUND #include +#if 0 inline rslidar_msg::msg::RslidarPacket toRosMsg(const Packet& rs_msg) { rslidar_msg::msg::RslidarPacket ros_msg; @@ -257,5 +258,6 @@ inline void PacketRosAdapter::localDifopCallback(const rslidar_msg::msg::Rslidar cb(toRsMsg(lidar_type_, PktType::DIFOP, *msg)); } } +#endif #endif // ROS2_FOUND diff --git a/src/adapter/point_cloud_ros_adapter.hpp b/src/adapter/ros_point_cloud_adapter.hpp similarity index 99% rename from src/adapter/point_cloud_ros_adapter.hpp rename to src/adapter/ros_point_cloud_adapter.hpp index 390af6a6..a883d1d5 100644 --- a/src/adapter/point_cloud_ros_adapter.hpp +++ b/src/adapter/ros_point_cloud_adapter.hpp @@ -32,7 +32,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#include "adapter/adapter_base.hpp" +#include "adapter/adapter.hpp" #include #include diff --git a/src/manager/adapter_manager.cpp b/src/manager/adapter_manager.cpp index 3060f95a..9831af0b 100644 --- a/src/manager/adapter_manager.cpp +++ b/src/manager/adapter_manager.cpp @@ -32,10 +32,10 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "manager/adapter_manager.h" #include "adapter/driver_adapter.hpp" -#include "adapter/point_cloud_ros_adapter.hpp" -#include "adapter/packet_ros_adapter.hpp" -#include "adapter/packet_protobuf_adapter.hpp" -#include "adapter/point_cloud_protobuf_adapter.hpp" +#include "adapter/ros_point_cloud_adapter.hpp" +#include "adapter/ros_packet_adapter.hpp" +#include "adapter/proto_packet_adapter.hpp" +#include "adapter/proto_point_cloud_adapter.hpp" namespace robosense { diff --git a/src/manager/adapter_manager.h b/src/manager/adapter_manager.h index e3c37410..bc4f2b99 100644 --- a/src/manager/adapter_manager.h +++ b/src/manager/adapter_manager.h @@ -29,50 +29,11 @@ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSE WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *********************************************************************************************************************/ -/******************************************************************************************************************** - * Basic struct: - * - * - * AdapterBase - * / | \ - * / | \ - * ROS: PacketRosAdapter | PointCloudRosAdapter - * Protobuf: PacketProtoAdapter | PointCloudProtoAdapter - * Driver: \ DriverAdapter / - * \ / \ / - * \ / \ / - * \ / \ / - * Packet PointCloud - * - * - * AdapterManager: - * - * step1 - * -msg_source=1 -> packet receiver: DriverAdapter; point cloud receiver: DriverAdapter - * -msg_source=2 -> packet receiver: PacketRosAdapter; point cloud receiver: DriverAdapter - * createReceiver ->-msg_source=3 -> packet receiver: DriverAdapter; point cloud receiver: DriverAdapter - * -msg_source=4 -> packet receiver: PacketProtoAdapter; point cloud receiver: DriverAdapter - * -msg_source=5 -> packet receiver: None; point cloud receiver: PointCloudProtoAdapter - * - * step2 - * - * -send_packet_ros=true -> PacketRosAdapter - * createTransmitter -> -send_point_cloud_ros=true -> PointCloudRosAdapter - * -send_packet_proto=true -> PacketProtoAdapter - * -send_point_cloud_proto=true -> PointCloudProtoAdapter - * - * step3 - * Register the transmitter's sending functions into the receiver - * - * step4 - * Start all the receivers - * - * ******************************************************************************************************************/ #pragma once #include "utility/yaml_reader.hpp" -#include "adapter/adapter_base.hpp" +#include "adapter/adapter.hpp" namespace robosense { @@ -83,12 +44,13 @@ class AdapterManager { public: - AdapterManager() = default; - ~AdapterManager(); void init(const YAML::Node& config); void start(); void stop(); + ~AdapterManager(); + AdapterManager() = default; + private: #if 0 From a222e7de588d1c83a7d43de0c0e83f3a14fa9f5b Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 31 Dec 2021 19:19:39 +0800 Subject: [PATCH 052/261] refac: refactory decoder --- src/adapter/proto_packet_adapter.hpp | 10 +++++----- src/adapter/proto_point_cloud_adapter.hpp | 10 +++++----- src/adapter/ros_packet_adapter.hpp | 6 +++++- src/manager/adapter_manager.cpp | 21 +++++++++++---------- src/manager/adapter_manager.h | 13 +------------ src/utility/protobuf_communicator.hpp | 2 -- 6 files changed, 27 insertions(+), 35 deletions(-) diff --git a/src/adapter/proto_packet_adapter.hpp b/src/adapter/proto_packet_adapter.hpp index c8f89d0a..6bc2c953 100644 --- a/src/adapter/proto_packet_adapter.hpp +++ b/src/adapter/proto_packet_adapter.hpp @@ -33,7 +33,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include "adapter/adapter.hpp" -#include "utility/protobuf_communicator.hpp" +//#include "utility/protobuf_communicator.hpp" #include "rs_driver/utility/sync_queue.h" #ifdef PROTO_FOUND @@ -60,7 +60,7 @@ class ProtoPacketSource : DriverSource void recvPacket(); void splicePacket(); - std::unique_ptr pkt_proto_com_ptr_; + //std::unique_ptr pkt_proto_com_ptr_; //SyncQueue pkt_queue_; std::thread recv_thread_; std::thread splice_thread_; @@ -146,8 +146,8 @@ class ProtoPacketDestination : public PacketDestination void internSendPacket(); - std::unique_ptr packet_proto_com_ptr_; - SyncQueue pkt_queue_; + //std::unique_ptr packet_proto_com_ptr_; + //SyncQueue pkt_queue_; std::thread send_thread_; bool to_exit_; }; @@ -188,7 +188,7 @@ inline ProtoPacketDestination::~ProtoPacketDestination() inline void ProtoPacketDestination::sendPacket(const Packet& msg) { - pkt_queue_.push(msg); + //pkt_queue_.push(msg); } inline void ProtoPacketDestination::internSendPacket() diff --git a/src/adapter/proto_point_cloud_adapter.hpp b/src/adapter/proto_point_cloud_adapter.hpp index 7748de0c..61be1ebb 100644 --- a/src/adapter/proto_point_cloud_adapter.hpp +++ b/src/adapter/proto_point_cloud_adapter.hpp @@ -35,7 +35,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifdef PROTO_FOUND #include "adapter/adapter.hpp" -#include "utility/protobuf_communicator.hpp" +//#include "utility/protobuf_communicator.hpp" constexpr size_t RECEIVE_BUF_SIZE = 10000000; @@ -58,7 +58,7 @@ class ProtoPointCloudSource : public Source void recvPointCloud(); void splicePointCloud(); - std::unique_ptr proto_com_ptr_; + //std::unique_ptr proto_com_ptr_; //SyncQueue> point_cloud_recv_queue_; std::thread recv_thread_; int old_frmnum_; @@ -168,9 +168,9 @@ class ProtoPointCloudDestination : public PointCloudDestination void internSendPointCloud(); - std::unique_ptr proto_com_ptr_; + //std::unique_ptr proto_com_ptr_; std::thread send_thread_; - SyncQueue point_cloud_send_queue_; + //SyncQueue point_cloud_send_queue_; bool to_exit_; }; @@ -206,7 +206,7 @@ inline void ProtoPointCloudDestination::stop() inline void ProtoPointCloudDestination::sendPointCloud(const LidarPointCloudMsg& msg) { - point_cloud_send_queue_.push(msg); + //point_cloud_send_queue_.push(msg); } inline void ProtoPointCloudDestination::internSendPointCloud() diff --git a/src/adapter/ros_packet_adapter.hpp b/src/adapter/ros_packet_adapter.hpp index ccecb013..b8fbaacf 100644 --- a/src/adapter/ros_packet_adapter.hpp +++ b/src/adapter/ros_packet_adapter.hpp @@ -258,6 +258,10 @@ inline void PacketRosAdapter::localDifopCallback(const rslidar_msg::msg::Rslidar cb(toRsMsg(lidar_type_, PktType::DIFOP, *msg)); } } -#endif +#endif #endif // ROS2_FOUND + +} // namespace lidar +} // namespace robosense + diff --git a/src/manager/adapter_manager.cpp b/src/manager/adapter_manager.cpp index 9831af0b..a65b45ec 100644 --- a/src/manager/adapter_manager.cpp +++ b/src/manager/adapter_manager.cpp @@ -32,7 +32,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "manager/adapter_manager.h" #include "adapter/driver_adapter.hpp" +#if 0 #include "adapter/ros_point_cloud_adapter.hpp" +#endif #include "adapter/ros_packet_adapter.hpp" #include "adapter/proto_packet_adapter.hpp" #include "adapter/proto_point_cloud_adapter.hpp" @@ -42,13 +44,9 @@ namespace robosense namespace lidar { -AdapterManager::~AdapterManager() -{ - stop(); -} - void AdapterManager::init(const YAML::Node& config) { +#if 0 packet_thread_flag_ = false; point_cloud_thread_flag_ = false; @@ -69,11 +67,6 @@ void AdapterManager::init(const YAML::Node& config) bool send_packet_proto; yamlRead(common_config, "send_packet_proto", send_packet_proto, false); -#if 0 - bool send_camera_trigger_ros; - yamlRead(common_config, "send_camera_trigger_ros", send_camera_trigger_ros, false); -#endif - std::string pcap_dir; double pcap_rate; bool pcap_repeat; @@ -302,6 +295,7 @@ void AdapterManager::init(const YAML::Node& config) } #endif } +#endif } void AdapterManager::start() @@ -352,6 +346,12 @@ void AdapterManager::stop() #endif } +AdapterManager::~AdapterManager() +{ + stop(); +} + +#if 0 std::shared_ptr AdapterManager::createReceiver(const YAML::Node& config, const AdapterType& adapter_type) { std::shared_ptr receiver; @@ -469,6 +469,7 @@ std::shared_ptr AdapterManager::createTransmitter(const YAML::Node& return transmitter; } +#endif } // namespace lidar } // namespace robosense diff --git a/src/manager/adapter_manager.h b/src/manager/adapter_manager.h index bc4f2b99..11321925 100644 --- a/src/manager/adapter_manager.h +++ b/src/manager/adapter_manager.h @@ -53,20 +53,9 @@ class AdapterManager private: -#if 0 - std::shared_ptr createReceiver(const YAML::Node& config, const AdapterType& adapter_type); - std::shared_ptr createTransmitter(const YAML::Node& config, const AdapterType& adapter_type); - - bool packet_thread_flag_; - bool point_cloud_thread_flag_; - - std::vector packet_receive_adapter_vec_; - std::vector point_cloud_receive_adapter_vec_; - std::vector packet_transmit_adapter_vec_; - std::vector point_cloud_transmit_adapter_vec_; -#endif std::vector sources_; }; } // namespace lidar } // namespace robosense + diff --git a/src/utility/protobuf_communicator.hpp b/src/utility/protobuf_communicator.hpp index e3c10bbb..08fc03d6 100644 --- a/src/utility/protobuf_communicator.hpp +++ b/src/utility/protobuf_communicator.hpp @@ -58,8 +58,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define MAX_RECEIVE_LENGTH 5200 -#if 0 - namespace robosense { namespace lidar From 6cb93a145e101a64f84f960c6ebe4ae76e00aa6d Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 4 Jan 2022 09:18:45 +0800 Subject: [PATCH 053/261] refac: refactory adapter --- CMakeLists.txt | 13 +++++++++++++ src/adapter/ros_packet_adapter.hpp | 3 ++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4011ddfb..45800736 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,8 @@ + cmake_minimum_required(VERSION 3.5) + cmake_policy(SET CMP0048 NEW) + project(rslidar_sdk) #======================================= @@ -17,6 +20,7 @@ set(POINT_TYPE XYZI) #======================== set(PROJECT_NAME rslidar_sdk) add_definitions(-DPROJECT_PATH="${PROJECT_SOURCE_DIR}") + set(CMAKE_BUILD_TYPE RELEASE) add_definitions(-O3) add_definitions(-std=c++14) @@ -27,6 +31,7 @@ add_compile_options(-Wall) #======================== #ROS# find_package(roscpp 1.12 QUIET) + if(roscpp_FOUND) message(=============================================================) message("-- ROS Found, Ros Support is turned On!") @@ -44,6 +49,7 @@ endif(roscpp_FOUND) #ROS2# find_package(rclcpp QUIET) + if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") find_package(ament_cmake REQUIRED) find_package(sensor_msgs REQUIRED) @@ -63,6 +69,7 @@ endif(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") #Protobuf# find_package(Protobuf QUIET) + find_program(PROTOC protoc) if(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) message(=============================================================) @@ -104,8 +111,10 @@ if(${COMPILE_METHOD} STREQUAL "CATKIN") CATKIN_DEPENDS sensor_msgs roslib ) endif(${COMPILE_METHOD} STREQUAL "CATKIN") + #Include directory# include_directories(${PROJECT_SOURCE_DIR}/src) + #Driver core# add_subdirectory(src/rs_driver) find_package(rs_driver REQUIRED) @@ -119,6 +128,7 @@ add_definitions(-DPOINT_TYPE_XYZI) elseif(${POINT_TYPE} STREQUAL "XYZIRT") add_definitions(-DPOINT_TYPE_XYZIRT) endif() + message(=============================================================) message("-- POINT_TYPE is ${POINT_TYPE}") message(=============================================================) @@ -152,6 +162,7 @@ else(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) ${rs_driver_LIBRARIES} ) endif(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) + #Ros# if(roscpp_FOUND) target_link_libraries(rslidar_sdk_node ${ROS_LIBS}) @@ -171,6 +182,7 @@ if(roscpp_FOUND) PATTERN ".svn" EXCLUDE) endif() endif(roscpp_FOUND) + #Ros2# if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") ament_target_dependencies(rslidar_sdk_node rclcpp sensor_msgs std_msgs rslidar_msg) @@ -185,3 +197,4 @@ if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") ) ament_package() endif(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") + diff --git a/src/adapter/ros_packet_adapter.hpp b/src/adapter/ros_packet_adapter.hpp index b8fbaacf..0ce389f4 100644 --- a/src/adapter/ros_packet_adapter.hpp +++ b/src/adapter/ros_packet_adapter.hpp @@ -33,7 +33,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include "adapter/adapter.hpp" -#include "msg/ros_msg/lidar_packet_ros.h" namespace robosense { @@ -42,6 +41,7 @@ namespace lidar #ifdef ROS_FOUND #include +#include "msg/ros_msg/lidar_packet_ros.h" inline Packet toRsMsg(const rslidar_msgs::rslidarPacket& ros_msg) { @@ -135,6 +135,7 @@ inline void RosPacketDestination::sendPacket(const Packet& msg) #ifdef ROS2_FOUND #include +#include "msg/ros_msg/lidar_packet_ros.h" #if 0 inline rslidar_msg::msg::RslidarPacket toRosMsg(const Packet& rs_msg) From 29f29f3a94cd9188d8de82369ca1db3e9ff35b59 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 6 Jan 2022 10:14:08 +0800 Subject: [PATCH 054/261] fix: fix warning of std::move, enable copy elision optimization --- src/adapter/driver_adapter.hpp | 3 ++- src/msg/proto_msg_translator.h | 2 +- src/msg/ros_msg_translator.h | 9 +++++---- src/rs_driver | 2 +- src/utility/yaml_reader.hpp | 2 +- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index b8e57be5..ee70d54e 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -260,11 +260,12 @@ inline LidarPointCloudMsg DriverAdapter::core2SDK(const lidar::PointCloudMsgheight = msg.height; point_cloud->width = msg.width; point_cloud->is_dense = msg.is_dense; + LidarPointCloudMsg point_cloud_msg(point_cloud); point_cloud_msg.frame_id = msg.frame_id; point_cloud_msg.timestamp = msg.timestamp; point_cloud_msg.seq = msg.seq; - return std::move(point_cloud_msg); + return point_cloud_msg; } } // namespace lidar diff --git a/src/msg/proto_msg_translator.h b/src/msg/proto_msg_translator.h index 32f1e61d..8841bbfe 100644 --- a/src/msg/proto_msg_translator.h +++ b/src/msg/proto_msg_translator.h @@ -63,7 +63,7 @@ inline proto_msg::LidarPointCloud toProtoMsg(const LidarPointCloudMsg& rs_msg) proto_msg.add_data(rs_msg.point_cloud_ptr->points[i].intensity); } - return std::move(proto_msg); + return proto_msg; } inline LidarPointCloudMsg toRsMsg(const proto_msg::LidarPointCloud& proto_msg) diff --git a/src/msg/ros_msg_translator.h b/src/msg/ros_msg_translator.h index a1f8a002..de20cd0f 100644 --- a/src/msg/ros_msg_translator.h +++ b/src/msg/ros_msg_translator.h @@ -156,7 +156,7 @@ inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); ros_msg.header.stamp.nanosec = (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); ros_msg.header.frame_id = rs_msg.frame_id; - return std::move(ros_msg); + return ros_msg; } inline PacketMsg toRsMsg(const LidarType& lidar_type, const PktType& pkt_type, const rslidar_msg::msg::RslidarPacket& ros_msg) @@ -178,12 +178,13 @@ inline PacketMsg toRsMsg(const LidarType& lidar_type, const PktType& pkt_type, pkt_length = MECH_PKT_LEN; break; } + PacketMsg rs_msg(pkt_length); for (size_t i = 0; i < pkt_length; i++) { rs_msg.packet[i] = ros_msg.data[i]; } - return std::move(rs_msg); + return rs_msg; } inline rslidar_msg::msg::RslidarPacket toRosMsg(const PacketMsg& rs_msg) { @@ -192,7 +193,7 @@ inline rslidar_msg::msg::RslidarPacket toRosMsg(const PacketMsg& rs_msg) { ros_msg.data[i] = rs_msg.packet[i]; } - return std::move(ros_msg); + return ros_msg; } inline ScanMsg toRsMsg(const LidarType& lidar_type, const PktType& pkt_type, const rslidar_msg::msg::RslidarScan& ros_msg) @@ -222,4 +223,4 @@ inline rslidar_msg::msg::RslidarScan toRosMsg(const ScanMsg& rs_msg) } } // namespace lidar } // namespace robosense -#endif // ROS2_FOUND \ No newline at end of file +#endif // ROS2_FOUND diff --git a/src/rs_driver b/src/rs_driver index 35d9f101..8f639e0a 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 35d9f101df83ce3c58385f0ae0c246d9c4e53b8c +Subproject commit 8f639e0af14a0d64e66bccb05bb45ca0796f5cd5 diff --git a/src/utility/yaml_reader.hpp b/src/utility/yaml_reader.hpp index d01a680a..fd03b1bd 100644 --- a/src/utility/yaml_reader.hpp +++ b/src/utility/yaml_reader.hpp @@ -75,7 +75,7 @@ inline YAML::Node yamlSubNodeAbort(const YAML::Node& yaml, const std::string& no RS_ERROR << " : Cannot find subnode " << node << ". Aborting!!!" << RS_REND; exit(-1); } - return std::move(ret); + return ret; } } // namespace lidar From a58d63cf0beea36466a14968d3eae77192d7e96a Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 6 Jan 2022 10:52:26 +0800 Subject: [PATCH 055/261] fix: fix launch.py, adapt to ros2 galactic --- launch/start.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/launch/start.py b/launch/start.py index 8e023706..64f07ff5 100755 --- a/launch/start.py +++ b/launch/start.py @@ -1,21 +1,20 @@ from launch import LaunchDescription from launch_ros.actions import Node from ament_index_python.packages import get_package_share_directory + def generate_launch_description(): rviz_config=get_package_share_directory('rslidar_sdk')+'/rviz/rviz2.rviz' return LaunchDescription([ Node( package='rslidar_sdk', - node_namespace='rslidar_sdk', - node_executable='rslidar_sdk_node', - output='screen', - node_name='rslidar_sdk_node' + executable='rslidar_sdk_node', + name='rslidar_sdk_node', + output='screen' ), Node( package='rviz2', - node_namespace='rviz2', - node_executable='rviz2', - node_name='rviz2', + executable='rviz2', + name='rviz2', arguments=['-d',rviz_config] ) - ]) \ No newline at end of file + ]) From f58ea90c3ff2d4fd27d2cb9e301265d6015878c0 Mon Sep 17 00:00:00 2001 From: mtlazaro Date: Fri, 4 Jun 2021 11:07:08 +0200 Subject: [PATCH 056/261] Adding ros param to use different config files --- node/rslidar_sdk_node.cpp | 46 ++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/node/rslidar_sdk_node.cpp b/node/rslidar_sdk_node.cpp index 27b5210b..1486d227 100644 --- a/node/rslidar_sdk_node.cpp +++ b/node/rslidar_sdk_node.cpp @@ -59,16 +59,31 @@ int main(int argc, char** argv) RS_TITLE << "********** **********" << RS_REND; RS_TITLE << "********************************************************" << RS_REND; - std::shared_ptr demo_ptr = std::make_shared(); - YAML::Node config; - try - { +#ifdef ROS_FOUND + ros::init(argc, argv, "rslidar_sdk_node", ros::init_options::NoSigintHandler); +#endif + +#ifdef ROS2_FOUND + rclcpp::init(argc, argv); +#endif + #ifdef RUN_IN_ROS_WORKSPACE - std::string path = ros::package::getPath("rslidar_sdk"); + std::string pkg_path = ros::package::getPath("rslidar_sdk"); #else - std::string path = (std::string)PROJECT_PATH; + std::string pkg_path = (std::string)PROJECT_PATH; +#endif + + std::string config_path = pkg_path + "/config/config.yaml"; + +#ifdef ROS_FOUND + ros::NodeHandle nh("~"); + nh.param("config_path", config_path, config_path); #endif - config = YAML::LoadFile((std::string)path + "/config/config.yaml"); + + YAML::Node config; + try + { + config = YAML::LoadFile(config_path); } catch (...) { @@ -76,23 +91,10 @@ int main(int argc, char** argv) return -1; } -#ifdef ROS_FOUND ///< if ROS is found, call the ros::init function - ros::init(argc, argv, "rslidar_sdk_node", ros::init_options::NoSigintHandler); - ros::NodeHandle priv_hh("~"); - std::string config_path; - priv_hh.param("config_path", config_path, std::string("")); - if (!config_path.empty()) - { - config = YAML::LoadFile(config_path); - } -#endif - -#ifdef ROS2_FOUND ///< if ROS2 is found, call the rclcpp::init function - rclcpp::init(argc, argv); -#endif - + std::shared_ptr demo_ptr = std::make_shared(); demo_ptr->init(config); demo_ptr->start(); + RS_MSG << "RoboSense-LiDAR-Driver is running....." << RS_REND; #ifdef ROS_FOUND From 1a92888d1f57fc73cc4ad9c715271454d6462b51 Mon Sep 17 00:00:00 2001 From: Tim Clephas Date: Thu, 1 Jul 2021 19:58:55 +0200 Subject: [PATCH 057/261] Add missing dependency on yaml-cpp --- package_ros1.xml | 6 +++++- package_ros2.xml | 10 ++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/package_ros1.xml b/package_ros1.xml index accbc186..04d7074e 100644 --- a/package_ros1.xml +++ b/package_ros1.xml @@ -5,13 +5,17 @@ The rslidar_sdk package robosense BSD + catkin roscpp sensor_msgs roslib + yaml-cpp roscpp sensor_msgs roslib - \ No newline at end of file + + + diff --git a/package_ros2.xml b/package_ros2.xml index 8682ce49..88126e3e 100644 --- a/package_ros2.xml +++ b/package_ros2.xml @@ -5,20 +5,22 @@ The rslidar_sdk package robosense BSD + ament_cmake rclcpp sensor_msgs std_msgs + yaml-cpp + rclcpp sensor_msgs std_msgs + rslidar_msg + ament_cmake - - - - + From 22603ea54da4d571db50810ee537cb92b17dae76 Mon Sep 17 00:00:00 2001 From: Tim Clephas Date: Thu, 1 Jul 2021 20:13:39 +0200 Subject: [PATCH 058/261] And other missing dependencies --- package_ros1.xml | 3 +++ package_ros2.xml | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/package_ros1.xml b/package_ros1.xml index 04d7074e..0af6875a 100644 --- a/package_ros1.xml +++ b/package_ros1.xml @@ -13,6 +13,9 @@ roslib yaml-cpp + libpcap + libpcl-all-dev + roscpp sensor_msgs roslib diff --git a/package_ros2.xml b/package_ros2.xml index 88126e3e..ee9d9637 100644 --- a/package_ros2.xml +++ b/package_ros2.xml @@ -9,15 +9,21 @@ ament_cmake rclcpp - sensor_msgs std_msgs + sensor_msgs yaml-cpp rclcpp sensor_msgs std_msgs + rclcpp + std_msgs + sensor_msgs rslidar_msg + yaml-cpp + libpcap + libpcl-all-dev ament_cmake From d72aab0e25b870e6e305dd03421fb9886ef6be61 Mon Sep 17 00:00:00 2001 From: Tim Clephas Date: Thu, 1 Jul 2021 20:22:15 +0200 Subject: [PATCH 059/261] pcl_conversions used but not configured --- CMakeLists.txt | 27 ++++++++++++++++++++------- package_ros1.xml | 4 ++++ package_ros2.xml | 2 ++ 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4011ddfb..1cf8fa66 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,9 +46,11 @@ endif(roscpp_FOUND) find_package(rclcpp QUIET) if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") find_package(ament_cmake REQUIRED) + find_package(std_msgs REQUIRED) find_package(sensor_msgs REQUIRED) find_package(rslidar_msg REQUIRED) - find_package(std_msgs REQUIRED) + find_package(pcl_conversions REQUIRED) + set(CMAKE_CXX_STANDARD 14) message(=============================================================) message("-- ROS2 Found, Ros2 Support is turned On!") @@ -95,17 +97,26 @@ add_definitions(${PCL_DEFINITIONS}) #Catkin# if(${COMPILE_METHOD} STREQUAL "CATKIN") add_definitions(-DRUN_IN_ROS_WORKSPACE) - find_package(catkin REQUIRED COMPONENTS - roscpp - sensor_msgs - roslib - ) + + find_package(catkin REQUIRED + COMPONENTS + roscpp + sensor_msgs + roslib + pcl_conversions + ) + catkin_package( - CATKIN_DEPENDS sensor_msgs roslib + CATKIN_DEPENDS + sensor_msgs + roslib + pcl_conversions ) endif(${COMPILE_METHOD} STREQUAL "CATKIN") + #Include directory# include_directories(${PROJECT_SOURCE_DIR}/src) + #Driver core# add_subdirectory(src/rs_driver) find_package(rs_driver REQUIRED) @@ -152,6 +163,7 @@ else(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) ${rs_driver_LIBRARIES} ) endif(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) + #Ros# if(roscpp_FOUND) target_link_libraries(rslidar_sdk_node ${ROS_LIBS}) @@ -171,6 +183,7 @@ if(roscpp_FOUND) PATTERN ".svn" EXCLUDE) endif() endif(roscpp_FOUND) + #Ros2# if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") ament_target_dependencies(rslidar_sdk_node rclcpp sensor_msgs std_msgs rslidar_msg) diff --git a/package_ros1.xml b/package_ros1.xml index 0af6875a..c07387a1 100644 --- a/package_ros1.xml +++ b/package_ros1.xml @@ -13,7 +13,11 @@ roslib yaml-cpp + roscpp + sensor_msgs + yaml-cpp libpcap + pcl_conversions libpcl-all-dev roscpp diff --git a/package_ros2.xml b/package_ros2.xml index ee9d9637..6483a5e6 100644 --- a/package_ros2.xml +++ b/package_ros2.xml @@ -8,6 +8,7 @@ ament_cmake + rclcpp std_msgs sensor_msgs @@ -23,6 +24,7 @@ rslidar_msg yaml-cpp libpcap + pcl_conversions libpcl-all-dev From 68bd643cce503c18390cb86bd2ca7dc6b97e1475 Mon Sep 17 00:00:00 2001 From: VictorLee Date: Thu, 24 Jun 2021 11:25:11 +0800 Subject: [PATCH 060/261] fix missing package.xml error when compile with ros. Signed-off-by: VictorLee --- CMakeLists.txt | 23 ++++++++++++++--------- package_ros1.xml | 9 +-------- package_ros2.xml | 9 --------- 3 files changed, 15 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cf8fa66..6d641669 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,11 +31,13 @@ if(roscpp_FOUND) message(=============================================================) message("-- ROS Found, Ros Support is turned On!") message(=============================================================) + add_definitions(-DROS_FOUND) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/package_ros1.xml ${CMAKE_CURRENT_SOURCE_DIR}/package.xml COPYONLY) find_package(roslib QUIET) - add_definitions(-DROS_FOUND) include_directories(${roscpp_INCLUDE_DIRS} ${roslib_INCLUDE_DIRS}) set(ROS_LIBS ${roscpp_LIBRARIES} ${roslib_LIBRARIES}) + else(roscpp_FOUND) message(=============================================================) message("-- ROS Not Found, Ros Support is turned Off!") @@ -45,18 +47,20 @@ endif(roscpp_FOUND) #ROS2# find_package(rclcpp QUIET) if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") + message(=============================================================) + message("-- ROS2 Found, Ros2 Support is turned On!") + message(=============================================================) + add_definitions(-DROS2_FOUND) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/package_ros2.xml ${CMAKE_CURRENT_SOURCE_DIR}/package.xml COPYONLY) + set(CMAKE_CXX_STANDARD 14) + find_package(ament_cmake REQUIRED) find_package(std_msgs REQUIRED) find_package(sensor_msgs REQUIRED) find_package(rslidar_msg REQUIRED) find_package(pcl_conversions REQUIRED) - - set(CMAKE_CXX_STANDARD 14) - message(=============================================================) - message("-- ROS2 Found, Ros2 Support is turned On!") - message(=============================================================) - add_definitions(-DROS2_FOUND) include_directories(${rclcpp_INCLUDE_DIRS}) + else(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") message(=============================================================) message("-- ROS2 Not Found, Ros2 Support is turned Off!") @@ -71,6 +75,7 @@ if(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) message("-- Protobuf Found, Protobuf Support is turned On!") message(=============================================================) add_definitions(-DPROTO_FOUND) + include_directories(${PROTOBUF_INCLUDE_DIRS}) SET(PROTO_FILE_PATH ${PROJECT_SOURCE_DIR}/src/msg/proto_msg) file(GLOB PROTOBUF_FILELIST ${PROTO_FILE_PATH}/*.proto) @@ -146,7 +151,7 @@ if(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) ${PROTO_FILE_PATH}/scan.pb.cc ${PROTO_FILE_PATH}/point_cloud.pb.cc ) - target_link_libraries(rslidar_sdk_node + target_link_libraries(rslidar_sdk_node ${PCL_LIBRARIES} ${YAML_CPP_LIBRARIES} ${PROTOBUF_LIBRARY} @@ -157,7 +162,7 @@ else(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) node/rslidar_sdk_node.cpp src/manager/adapter_manager.cpp ) - target_link_libraries(rslidar_sdk_node + target_link_libraries(rslidar_sdk_node ${PCL_LIBRARIES} ${YAML_CPP_LIBRARIES} ${rs_driver_LIBRARIES} diff --git a/package_ros1.xml b/package_ros1.xml index c07387a1..a44d16c3 100644 --- a/package_ros1.xml +++ b/package_ros1.xml @@ -8,21 +8,14 @@ catkin - roscpp - sensor_msgs - roslib yaml-cpp roscpp sensor_msgs - yaml-cpp + roslib libpcap pcl_conversions libpcl-all-dev - roscpp - sensor_msgs - roslib - diff --git a/package_ros2.xml b/package_ros2.xml index 6483a5e6..e1bb89ae 100644 --- a/package_ros2.xml +++ b/package_ros2.xml @@ -8,21 +8,12 @@ ament_cmake - - rclcpp - std_msgs - sensor_msgs yaml-cpp - rclcpp - sensor_msgs - std_msgs - rclcpp std_msgs sensor_msgs rslidar_msg - yaml-cpp libpcap pcl_conversions libpcl-all-dev From 0091a4807877e7893c27f30ecaefc9e5b5c0ed88 Mon Sep 17 00:00:00 2001 From: Baltashov Ilia Date: Fri, 17 Sep 2021 14:23:23 +0300 Subject: [PATCH 061/261] Added missing dependencies for build with catkin. --- CMakeLists.txt | 4 +++- package_ros1.xml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d641669..88ec85bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,19 +102,21 @@ add_definitions(${PCL_DEFINITIONS}) #Catkin# if(${COMPILE_METHOD} STREQUAL "CATKIN") add_definitions(-DRUN_IN_ROS_WORKSPACE) - find_package(catkin REQUIRED COMPONENTS roscpp sensor_msgs roslib + pcl_ros pcl_conversions ) catkin_package( CATKIN_DEPENDS + roscpp sensor_msgs roslib + pclros pcl_conversions ) endif(${COMPILE_METHOD} STREQUAL "CATKIN") diff --git a/package_ros1.xml b/package_ros1.xml index a44d16c3..d90ed2ac 100644 --- a/package_ros1.xml +++ b/package_ros1.xml @@ -14,8 +14,8 @@ sensor_msgs roslib libpcap + pcl_ros pcl_conversions libpcl-all-dev - From fb84866ee70a29525711079e6e8e70b9835e57f9 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 7 Jan 2022 15:22:57 +0800 Subject: [PATCH 062/261] fix: fix ros1 package.xml --- CMakeLists.txt | 1 - node/rslidar_sdk_node.cpp | 18 +++++++++++------- package_ros1.xml | 19 ++++++++++++------- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 88ec85bd..64f6accb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -116,7 +116,6 @@ if(${COMPILE_METHOD} STREQUAL "CATKIN") roscpp sensor_msgs roslib - pclros pcl_conversions ) endif(${COMPILE_METHOD} STREQUAL "CATKIN") diff --git a/node/rslidar_sdk_node.cpp b/node/rslidar_sdk_node.cpp index 1486d227..7c4e5359 100644 --- a/node/rslidar_sdk_node.cpp +++ b/node/rslidar_sdk_node.cpp @@ -67,18 +67,22 @@ int main(int argc, char** argv) rclcpp::init(argc, argv); #endif + std::string config_path; + +#ifdef ROS_FOUND + ros::NodeHandle nh("~"); + nh.param("config_path", config_path, std::string("")); +#endif + + if (config_path.empty()) + { #ifdef RUN_IN_ROS_WORKSPACE std::string pkg_path = ros::package::getPath("rslidar_sdk"); #else std::string pkg_path = (std::string)PROJECT_PATH; #endif - - std::string config_path = pkg_path + "/config/config.yaml"; - -#ifdef ROS_FOUND - ros::NodeHandle nh("~"); - nh.param("config_path", config_path, config_path); -#endif + config_path = pkg_path + "/config/config.yaml"; + } YAML::Node config; try diff --git a/package_ros1.xml b/package_ros1.xml index d90ed2ac..28814d5e 100644 --- a/package_ros1.xml +++ b/package_ros1.xml @@ -8,14 +8,19 @@ catkin + roscpp + sensor_msgs + roslib yaml-cpp + libpcap + pcl_ros + pcl_conversions + libpcl-all-dev - roscpp - sensor_msgs - roslib - libpcap - pcl_ros - pcl_conversions - libpcl-all-dev + roscpp + sensor_msgs + roslib + libpcap + pcl_conversions From 0e53dffaf0f41dd0a2102e2da558c64f4f58f533 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 7 Jan 2022 15:34:52 +0800 Subject: [PATCH 063/261] fix: enable copy elision optimization --- src/msg/ros_msg_translator.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/msg/ros_msg_translator.h b/src/msg/ros_msg_translator.h index de20cd0f..48411fe6 100644 --- a/src/msg/ros_msg_translator.h +++ b/src/msg/ros_msg_translator.h @@ -60,7 +60,7 @@ inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) ros_msg.header.stamp = ros_msg.header.stamp.fromSec(rs_msg.timestamp); ros_msg.header.frame_id = rs_msg.frame_id; ros_msg.header.seq = rs_msg.seq; - return std::move(ros_msg); + return ros_msg; } inline PacketMsg toRsMsg(const LidarType& lidar_type, const PktType& pkt_type, const rslidar_msgs::rslidarPacket& ros_msg) @@ -87,7 +87,7 @@ inline PacketMsg toRsMsg(const LidarType& lidar_type, const PktType& pkt_type, { rs_msg.packet[i] = ros_msg.data[i]; } - return std::move(rs_msg); + return rs_msg; } inline rslidar_msgs::rslidarPacket toRosMsg(const PacketMsg& rs_msg) { @@ -97,7 +97,7 @@ inline rslidar_msgs::rslidarPacket toRosMsg(const PacketMsg& rs_msg) { ros_msg.data[i] = rs_msg.packet[i]; } - return std::move(ros_msg); + return ros_msg; } inline ScanMsg toRsMsg(const LidarType& lidar_type, const PktType& pkt_type, const rslidar_msgs::rslidarScan& ros_msg) { @@ -111,7 +111,7 @@ inline ScanMsg toRsMsg(const LidarType& lidar_type, const PktType& pkt_type, con PacketMsg tmp = toRsMsg(lidar_type, pkt_type, ros_msg.packets[i]); rs_msg.packets.emplace_back(std::move(tmp)); } - return std::move(rs_msg); + return rs_msg; } inline rslidar_msgs::rslidarScan toRosMsg(const ScanMsg& rs_msg) { @@ -124,7 +124,7 @@ inline rslidar_msgs::rslidarScan toRosMsg(const ScanMsg& rs_msg) rslidar_msgs::rslidarPacket tmp = toRosMsg(rs_msg.packets[i]); ros_msg.packets.emplace_back(std::move(tmp)); } - return std::move(ros_msg); + return ros_msg; } inline std_msgs::Time toRosMsg(const CameraTrigger& rs_msg) { From c3ff1473554a3badea46976e61eaff5fed18a08a Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 7 Jan 2022 18:08:10 +0800 Subject: [PATCH 064/261] feat: update docs --- CHANGELOG.md | 9 +++++++-- README.md | 12 +++++++++--- README_CN.md | 12 +++++++++--- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a7be36d..dd1252b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,13 @@ ### Added - add install command when building using catkin - add use_vlan and use_someip support - - + - add use_vlan and use_someip support + - support customer protocol layer + - adapt to ros2 galactic + - get config file path from param (thanks to @mtlazaro, @Tim.Clephas) + - copy package.xml instead of renaming it manually (thanks to @VictorLee) + - add missing dependencies in build files. (thanks to @Tim.Clephas, @Baltashov.Ilia) + ## v1.3.0 - 2020-11-10 ### Added diff --git a/README.md b/README.md index 5828225d..bad28338 100644 --- a/README.md +++ b/README.md @@ -50,20 +50,26 @@ To run rslidar_sdk in ROS environment, ROS related libraries need to be installe **Ubuntu 18.04**: ros-melodic-desktop-full +**Ubuntu 20.04**: ros-noetic-desktop-full + **Installation**: please refer to http://wiki.ros.org -If you install ros-kinetic-desktop-full or ros-melodic-desktop-full, the corresponding PCL and Boost will be installed at the same time. It will bring you a lot of convenience since you don't need to handle the version confliction. Thus, **it's highly recommanded to install ros-distro-desktop-full**. +If you install ros-kinetic-desktop-full/ros-melodic-desktop-full/ros-noetic-desktop-full, the corresponding PCL and Boost will be installed at the same time. It will bring you a lot of convenience since you don't need to handle the version confliction. Thus, **it's highly recommanded to install ros-distro-desktop-full**. ### 3.2 ROS2 If use rslidar_sdk in ROS2 environment, ROS2 related libraries need to be installed. -**Ubuntu 16.04**: Not supportted +**Ubuntu 16.04**: Not supported **Ubuntu 18.04**: ROS2 eloquent desktop **Installation**: please refer to https://index.ros.org/doc/ros2/Installation/Eloquent/Linux-Install-Debians/ +**Ubuntu 20.04**: ROS2 galactic desktop + +**Installation**: please refer to https://docs.ros.org/en/galactic/Installation/Ubuntu-Install-Debians.html + **Note! Please avoid installing ROS and ROS2 on the same computer! This may cause conflict! Also you may need to install Yaml manually.** ### 3.3 Yaml(Essential) @@ -200,4 +206,4 @@ The following documents are some quick guides for using some of the most common [Coordinate Transformation](doc/howto/how_to_use_coordinate_transformation.md) -[Multi-Cast](doc/howto/how_to_use_multi_cast_function.md) \ No newline at end of file +[Multi-Cast](doc/howto/how_to_use_multi_cast_function.md) diff --git a/README_CN.md b/README_CN.md index c34d7183..de4d8034 100644 --- a/README_CN.md +++ b/README_CN.md @@ -45,13 +45,15 @@ git submodule update *若需在ROS环境下使用雷达驱动,则需安装ROS相关依赖库* -Ubuntu 16.04 - ROS kinetic desktop-full +Ubuntu 16.04 - ROS kinetic desktop-full Ubuntu 18.04 - ROS melodic desktop-full +Ubuntu 20.04 - ROS noetic desktop-full + 安装方式: 参考 http://wiki.ros.org -**如果安装了ROS kinetic desktop-full版或ROS melodic desktop-full版,那么兼容版本其他依赖库也应该同时被安装了,所以不需要重新安装它们以避免多个版本冲突引起的问题, 因此,强烈建议安装desktop-full版,这将节省大量的时间来逐个安装和配置库**。 +**如果安装了ROS kinetic desktop-full版、ROS melodic desktop-full版或ROS noetic desktop-full,那么兼容版本其他依赖库也应该同时被安装了,所以不需要重新安装它们以避免多个版本冲突引起的问题, 因此,强烈建议安装desktop-full版,这将节省大量的时间来逐个安装和配置库**。 ### 3.2 ROS2 @@ -63,6 +65,10 @@ Ubuntu 18.04 - ROS2 Eloquent desktop 安装方式:参考 https://index.ros.org/doc/ros2/Installation/Eloquent/Linux-Install-Debians/ +Ubuntu 20.04 - ROS2 Galactic desktop + +安装方式:参考 https://docs.ros.org/en/galactic/Installation/Ubuntu-Install-Debians.html + **注意! 请避免在同一台电脑上同时安装ROS和ROS2, 这可能会产生冲突! 同时还需要手动安装Yaml库。** ### 3.3 Yaml (必需) @@ -197,4 +203,4 @@ ros2 launch rslidar_sdk start.py [坐标变换功能](doc/howto/how_to_use_coordinate_transformation_cn.md) -[组播模式](doc/howto/how_to_use_multi_cast_function_cn.md) \ No newline at end of file +[组播模式](doc/howto/how_to_use_multi_cast_function_cn.md) From e2002b44d01738a85e6fd7a44b451577f5e25f63 Mon Sep 17 00:00:00 2001 From: Tim Clephas Date: Mon, 8 Nov 2021 15:10:08 +0100 Subject: [PATCH 065/261] Switch to supported ROS versions Kinetic is EOL already. --- README.md | 6 +++++- README_CN.md | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bad28338..abce8479 100644 --- a/README.md +++ b/README.md @@ -63,9 +63,13 @@ If use rslidar_sdk in ROS2 environment, ROS2 related libraries need to be instal **Ubuntu 16.04**: Not supported **Ubuntu 18.04**: ROS2 eloquent desktop - + **Installation**: please refer to https://index.ros.org/doc/ros2/Installation/Eloquent/Linux-Install-Debians/ +**Ubuntu 20.04**: ROS2 foxy desktop + +**Installation**: please refer to https:https://docs.ros.org/en/foxy/Installation/Ubuntu-Install-Debians.html + **Ubuntu 20.04**: ROS2 galactic desktop **Installation**: please refer to https://docs.ros.org/en/galactic/Installation/Ubuntu-Install-Debians.html diff --git a/README_CN.md b/README_CN.md index de4d8034..b188ab51 100644 --- a/README_CN.md +++ b/README_CN.md @@ -65,6 +65,10 @@ Ubuntu 18.04 - ROS2 Eloquent desktop 安装方式:参考 https://index.ros.org/doc/ros2/Installation/Eloquent/Linux-Install-Debians/ +Ubuntu 20.04 - ROS2 Foxy desktop + +安装方式:参考 https:https://docs.ros.org/en/foxy/Installation/Ubuntu-Install-Debians.html + Ubuntu 20.04 - ROS2 Galactic desktop 安装方式:参考 https://docs.ros.org/en/galactic/Installation/Ubuntu-Install-Debians.html From 6de3190c81d8a364f090a3e3e3d5cc849466233d Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 10 Jan 2022 10:39:11 +0800 Subject: [PATCH 066/261] feat: update CHANGELOG.md --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd1252b5..b7e0d514 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,10 @@ - add use_vlan and use_someip support - add use_vlan and use_someip support - support customer protocol layer - - adapt to ros2 galactic - - get config file path from param (thanks to @mtlazaro, @Tim.Clephas) - - copy package.xml instead of renaming it manually (thanks to @VictorLee) - - add missing dependencies in build files. (thanks to @Tim.Clephas, @Baltashov.Ilia) + - adapt to ros noetic, ros2 foxy/galactic (Thanks to @Tim.Clephas) + - get config file path from param (Thanks to @mtlazaro, @Tim.Clephas) + - copy package.xml instead of renaming it manually (Thanks to @VictorLee) + - add missing dependencies in build files. (Thanks to @Tim.Clephas, @Baltashov.Ilia) ## v1.3.0 - 2020-11-10 From 95570b67eb95b35a3e6d3ac9be13ec8adfdf1e80 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 10 Jan 2022 12:12:09 +0800 Subject: [PATCH 067/261] refac: refac adapter --- CMakeLists.txt | 27 +++++++++++++++++------ src/adapter/adapter.hpp | 7 +++--- src/adapter/proto_point_cloud_adapter.hpp | 15 ++++++++----- src/adapter/ros_packet_adapter.hpp | 10 ++++----- src/manager/adapter_manager.cpp | 4 ++-- src/rs_driver | 2 +- src/utility/common.h | 6 ++--- 7 files changed, 45 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 45800736..4d922cb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,11 +36,12 @@ if(roscpp_FOUND) message(=============================================================) message("-- ROS Found, Ros Support is turned On!") message(=============================================================) + add_definitions(-DROS_FOUND) find_package(roslib QUIET) - add_definitions(-DROS_FOUND) include_directories(${roscpp_INCLUDE_DIRS} ${roslib_INCLUDE_DIRS}) set(ROS_LIBS ${roscpp_LIBRARIES} ${roslib_LIBRARIES}) + else(roscpp_FOUND) message(=============================================================) message("-- ROS Not Found, Ros Support is turned Off!") @@ -51,16 +52,18 @@ endif(roscpp_FOUND) find_package(rclcpp QUIET) if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") - find_package(ament_cmake REQUIRED) - find_package(sensor_msgs REQUIRED) - find_package(rslidar_msg REQUIRED) - find_package(std_msgs REQUIRED) - set(CMAKE_CXX_STANDARD 14) message(=============================================================) message("-- ROS2 Found, Ros2 Support is turned On!") message(=============================================================) add_definitions(-DROS2_FOUND) include_directories(${rclcpp_INCLUDE_DIRS}) + set(CMAKE_CXX_STANDARD 14) + + find_package(ament_cmake REQUIRED) + find_package(sensor_msgs REQUIRED) + find_package(rslidar_msg REQUIRED) + find_package(std_msgs REQUIRED) + else(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") message(=============================================================) message("-- ROS2 Not Found, Ros2 Support is turned Off!") @@ -77,15 +80,19 @@ if(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) message(=============================================================) add_definitions(-DPROTO_FOUND) include_directories(${PROTOBUF_INCLUDE_DIRS}) + SET(PROTO_FILE_PATH ${PROJECT_SOURCE_DIR}/src/msg/proto_msg) + file(GLOB PROTOBUF_FILELIST ${PROTO_FILE_PATH}/*.proto) foreach(proto_file ${PROTOBUF_FILELIST}) message(STATUS "COMPILING ${proto_file} USING ${PROTOBUF_PROTOC_EXECUTABLE}") + execute_process(COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} --proto_path=${PROTO_FILE_PATH} --cpp_out=${PROTO_FILE_PATH} ${proto_file}) endforeach() + else(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) message(=============================================================) message("-- Protobuf Not Found, Protobuf Support is turned Off!") @@ -94,6 +101,7 @@ endif(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) #Others# find_package(yaml-cpp REQUIRED) + find_package(PCL QUIET REQUIRED) include_directories(${PCL_INCLUDE_DIRS}) link_directories(${PCL_LIBRARY_DIRS}) @@ -136,11 +144,13 @@ message(=============================================================) #======================== # Build Setup #======================== + #Protobuf# if(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) + add_executable(rslidar_sdk_node - node/rslidar_sdk_node.cpp src/manager/adapter_manager.cpp + node/rslidar_sdk_node.cpp ${PROTO_FILE_PATH}/packet.pb.cc ${PROTO_FILE_PATH}/scan.pb.cc ${PROTO_FILE_PATH}/point_cloud.pb.cc @@ -151,7 +161,9 @@ if(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) ${PROTOBUF_LIBRARY} ${rs_driver_LIBRARIES} ) + else(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) + add_executable(rslidar_sdk_node node/rslidar_sdk_node.cpp src/manager/adapter_manager.cpp @@ -161,6 +173,7 @@ else(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) ${YAML_CPP_LIBRARIES} ${rs_driver_LIBRARIES} ) + endif(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) #Ros# diff --git a/src/adapter/adapter.hpp b/src/adapter/adapter.hpp index 270b632e..55fee330 100644 --- a/src/adapter/adapter.hpp +++ b/src/adapter/adapter.hpp @@ -32,8 +32,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#include "rs_driver/msg/packet.h" #include "msg/rs_msg/lidar_point_cloud_msg.h" +#include "rs_driver/msg/packet.h" +#include "utility/yaml_reader.hpp" namespace robosense { @@ -48,7 +49,7 @@ class PointCloudDestination virtual void init(const YAML::Node& config){} virtual void start() {} virtual void stop() {} - virtual void sendPointCloud(const LidarPointCloudMsg& msg); + virtual void sendPointCloud(const LidarPointCloudMsg& msg) = 0; virtual ~PointCloudDestination() = default; }; @@ -60,7 +61,7 @@ class PacketDestination virtual void init(const YAML::Node& config){} virtual void start() {} virtual void stop() {} - virtual void sendPacket(const Packet& msg); + virtual void sendPacket(const Packet& msg) = 0; virtual ~PacketDestination() = default; }; diff --git a/src/adapter/proto_point_cloud_adapter.hpp b/src/adapter/proto_point_cloud_adapter.hpp index 61be1ebb..ccb2072d 100644 --- a/src/adapter/proto_point_cloud_adapter.hpp +++ b/src/adapter/proto_point_cloud_adapter.hpp @@ -86,6 +86,16 @@ inline void ProtoPointCloudSource::start() recv_thread_ = std::thread(std::bind(&ProtoPointCloudSource::recvPointCloud, this)); } +inline void ProtoPointCloudSource::stop() +{ + recv_thread_.join(); +} + +inline ProtoPointCloudSource::~ProtoPointCloudSource() +{ + stop(); +} + inline void ProtoPointCloudSource::recvPointCloud() { #if 0 @@ -149,11 +159,6 @@ inline void ProtoPointCloudSource::splicePointCloud() #endif } -inline void ProtoPointCloudSource::stop() -{ - recv_thread_.join(); -} - class ProtoPointCloudDestination : public PointCloudDestination { public: diff --git a/src/adapter/ros_packet_adapter.hpp b/src/adapter/ros_packet_adapter.hpp index 0ce389f4..d9fff326 100644 --- a/src/adapter/ros_packet_adapter.hpp +++ b/src/adapter/ros_packet_adapter.hpp @@ -33,16 +33,17 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include "adapter/adapter.hpp" +#include "adapter/driver_adapter.hpp" +#include "msg/ros_msg/lidar_packet_ros.h" + +#ifdef ROS_FOUND +#include namespace robosense { namespace lidar { -#ifdef ROS_FOUND -#include -#include "msg/ros_msg/lidar_packet_ros.h" - inline Packet toRsMsg(const rslidar_msgs::rslidarPacket& ros_msg) { Packet rs_msg(1500); @@ -135,7 +136,6 @@ inline void RosPacketDestination::sendPacket(const Packet& msg) #ifdef ROS2_FOUND #include -#include "msg/ros_msg/lidar_packet_ros.h" #if 0 inline rslidar_msg::msg::RslidarPacket toRosMsg(const Packet& rs_msg) diff --git a/src/manager/adapter_manager.cpp b/src/manager/adapter_manager.cpp index a65b45ec..a53c29a6 100644 --- a/src/manager/adapter_manager.cpp +++ b/src/manager/adapter_manager.cpp @@ -300,6 +300,7 @@ void AdapterManager::init(const YAML::Node& config) void AdapterManager::start() { +#if 0 if (point_cloud_thread_flag_) { for (auto& iter : point_cloud_receive_adapter_vec_) @@ -308,7 +309,6 @@ void AdapterManager::start() iter->start(); } } -#if 0 if (packet_thread_flag_) { for (auto& iter : packet_receive_adapter_vec_) @@ -324,6 +324,7 @@ void AdapterManager::start() void AdapterManager::stop() { +#if 0 if (point_cloud_thread_flag_) { for (auto& iter : point_cloud_receive_adapter_vec_) @@ -332,7 +333,6 @@ void AdapterManager::stop() iter->stop(); } } -#if 0 if (packet_thread_flag_) { for (auto& iter : packet_receive_adapter_vec_) diff --git a/src/rs_driver b/src/rs_driver index 87234688..740430d6 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 87234688a113555827e621c0c2fa4d0ab541ae14 +Subproject commit 740430d64734a6dce40cf47cdf8cf37b1091632e diff --git a/src/utility/common.h b/src/utility/common.h index eb8de336..fc5dbc67 100644 --- a/src/utility/common.h +++ b/src/utility/common.h @@ -33,7 +33,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include "rs_driver/common/common_header.h" -#include "utility/time.h" -#include "utility/thread_pool.hpp" -#include "lock_queue.h" +//#include "utility/time.h" +//#include "utility/thread_pool.hpp" +//#include "lock_queue.h" From 35a83c7fdd889ef673d255c4a2d6db07582f74e7 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 10 Jan 2022 15:34:11 +0800 Subject: [PATCH 068/261] refac: adapt to rs_driver --- node/rslidar_sdk_node.cpp | 2 +- src/adapter/adapter.hpp | 2 +- src/adapter/driver_adapter.hpp | 2 +- src/adapter/proto_packet_adapter.hpp | 2 +- src/msg/rs_msg/lidar_point_cloud_msg.h | 3 ++- src/rs_driver | 2 +- src/utility/common.h | 6 +++--- 7 files changed, 10 insertions(+), 9 deletions(-) diff --git a/node/rslidar_sdk_node.cpp b/node/rslidar_sdk_node.cpp index 9feaad41..aa0bf7a1 100644 --- a/node/rslidar_sdk_node.cpp +++ b/node/rslidar_sdk_node.cpp @@ -30,7 +30,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *********************************************************************************************************************/ -#include "rs_driver/macro/version.h" +#include "rs_driver/macro/version.hpp" #include "manager/adapter_manager.h" #include diff --git a/src/adapter/adapter.hpp b/src/adapter/adapter.hpp index 55fee330..20aff20d 100644 --- a/src/adapter/adapter.hpp +++ b/src/adapter/adapter.hpp @@ -33,8 +33,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include "msg/rs_msg/lidar_point_cloud_msg.h" -#include "rs_driver/msg/packet.h" #include "utility/yaml_reader.hpp" +#include "rs_driver/msg/packet.hpp" namespace robosense { diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index 6c98c8b3..053a63e2 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -33,7 +33,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include "adapter/adapter.hpp" -#include "rs_driver/api/lidar_driver.h" +#include "rs_driver/api/lidar_driver.hpp" namespace robosense { diff --git a/src/adapter/proto_packet_adapter.hpp b/src/adapter/proto_packet_adapter.hpp index 6bc2c953..3625f904 100644 --- a/src/adapter/proto_packet_adapter.hpp +++ b/src/adapter/proto_packet_adapter.hpp @@ -34,7 +34,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "adapter/adapter.hpp" //#include "utility/protobuf_communicator.hpp" -#include "rs_driver/utility/sync_queue.h" +#include "rs_driver/utility/sync_queue.hpp" #ifdef PROTO_FOUND diff --git a/src/msg/rs_msg/lidar_point_cloud_msg.h b/src/msg/rs_msg/lidar_point_cloud_msg.h index 64c89958..4ceb09f2 100644 --- a/src/msg/rs_msg/lidar_point_cloud_msg.h +++ b/src/msg/rs_msg/lidar_point_cloud_msg.h @@ -32,6 +32,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#include "rs_driver/msg/pcl_point_cloud_msg.h" +#include "rs_driver/msg/pcl_point_cloud_msg.hpp" + typedef PointCloudT LidarPointCloudMsg; diff --git a/src/rs_driver b/src/rs_driver index 740430d6..18d7ea4b 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 740430d64734a6dce40cf47cdf8cf37b1091632e +Subproject commit 18d7ea4bec9c297f30f109ce5a5833924080d1d1 diff --git a/src/utility/common.h b/src/utility/common.h index fc5dbc67..03a814c8 100644 --- a/src/utility/common.h +++ b/src/utility/common.h @@ -32,8 +32,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#include "rs_driver/common/common_header.h" -//#include "utility/time.h" +#include "rs_driver/common/common_header.hpp" +//#include "utility/time.hpp" //#include "utility/thread_pool.hpp" -//#include "lock_queue.h" +//#include "lock_queue.hpp" From 33768404b99ea9f34cce96e117ba63c64359b2bf Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 10 Jan 2022 16:28:05 +0800 Subject: [PATCH 069/261] refac: refactory --- .../{driver_adapter.hpp => driver_source.hpp} | 6 ++++-- src/adapter/proto_packet_adapter.hpp | 2 +- src/adapter/proto_point_cloud_adapter.hpp | 2 +- ...cket_adapter.hpp => ros_packet_source.hpp} | 21 ++++++++++++------- src/adapter/{adapter.hpp => source.hpp} | 4 +++- src/manager/adapter_manager.cpp | 6 ++++-- src/manager/adapter_manager.h | 2 +- 7 files changed, 28 insertions(+), 15 deletions(-) rename src/adapter/{driver_adapter.hpp => driver_source.hpp} (98%) rename src/adapter/{ros_packet_adapter.hpp => ros_packet_source.hpp} (98%) rename src/adapter/{adapter.hpp => source.hpp} (99%) diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_source.hpp similarity index 98% rename from src/adapter/driver_adapter.hpp rename to src/adapter/driver_source.hpp index 053a63e2..2ac00749 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_source.hpp @@ -32,8 +32,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#include "adapter/adapter.hpp" -#include "rs_driver/api/lidar_driver.hpp" +#include "adapter/source.hpp" + +#include namespace robosense { @@ -43,6 +44,7 @@ namespace lidar class DriverSource : public Source { public: + virtual void init(SourceType src, const YAML::Node& config); virtual void start(); virtual void stop(); diff --git a/src/adapter/proto_packet_adapter.hpp b/src/adapter/proto_packet_adapter.hpp index 3625f904..f637cc12 100644 --- a/src/adapter/proto_packet_adapter.hpp +++ b/src/adapter/proto_packet_adapter.hpp @@ -32,7 +32,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#include "adapter/adapter.hpp" +#include "adapter/source.hpp" //#include "utility/protobuf_communicator.hpp" #include "rs_driver/utility/sync_queue.hpp" diff --git a/src/adapter/proto_point_cloud_adapter.hpp b/src/adapter/proto_point_cloud_adapter.hpp index ccb2072d..0dc313f5 100644 --- a/src/adapter/proto_point_cloud_adapter.hpp +++ b/src/adapter/proto_point_cloud_adapter.hpp @@ -34,7 +34,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifdef PROTO_FOUND -#include "adapter/adapter.hpp" +#include "adapter/source.hpp" //#include "utility/protobuf_communicator.hpp" constexpr size_t RECEIVE_BUF_SIZE = 10000000; diff --git a/src/adapter/ros_packet_adapter.hpp b/src/adapter/ros_packet_source.hpp similarity index 98% rename from src/adapter/ros_packet_adapter.hpp rename to src/adapter/ros_packet_source.hpp index d9fff326..b6ce1b61 100644 --- a/src/adapter/ros_packet_adapter.hpp +++ b/src/adapter/ros_packet_source.hpp @@ -32,8 +32,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#include "adapter/adapter.hpp" -#include "adapter/driver_adapter.hpp" +#include "adapter/driver_source.hpp" #include "msg/ros_msg/lidar_packet_ros.h" #ifdef ROS_FOUND @@ -132,12 +131,20 @@ inline void RosPacketDestination::sendPacket(const Packet& msg) pub_.publish(toRosMsg(msg)); } +} // namespace lidar +} // namespace robosense + #endif // ROS_FOUND -#ifdef ROS2_FOUND +#if 0 +//#ifdef ROS2_FOUND #include -#if 0 +namespace robosense +{ +namespace lidar +{ + inline rslidar_msg::msg::RslidarPacket toRosMsg(const Packet& rs_msg) { rslidar_msg::msg::RslidarPacket ros_msg; @@ -260,9 +267,9 @@ inline void PacketRosAdapter::localDifopCallback(const rslidar_msg::msg::Rslidar } } -#endif -#endif // ROS2_FOUND - } // namespace lidar } // namespace robosense +#endif // ROS2_FOUND + + diff --git a/src/adapter/adapter.hpp b/src/adapter/source.hpp similarity index 99% rename from src/adapter/adapter.hpp rename to src/adapter/source.hpp index 20aff20d..3b5f9ec5 100644 --- a/src/adapter/adapter.hpp +++ b/src/adapter/source.hpp @@ -34,7 +34,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "msg/rs_msg/lidar_point_cloud_msg.h" #include "utility/yaml_reader.hpp" -#include "rs_driver/msg/packet.hpp" + +#include namespace robosense { @@ -121,5 +122,6 @@ inline void Source::sendPointCloud(std::shared_ptr msg) } } + } // namespace lidar } // namespace robosense diff --git a/src/manager/adapter_manager.cpp b/src/manager/adapter_manager.cpp index a53c29a6..262269e2 100644 --- a/src/manager/adapter_manager.cpp +++ b/src/manager/adapter_manager.cpp @@ -31,11 +31,13 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *********************************************************************************************************************/ #include "manager/adapter_manager.h" -#include "adapter/driver_adapter.hpp" + +#include "adapter/driver_source.hpp" #if 0 #include "adapter/ros_point_cloud_adapter.hpp" #endif -#include "adapter/ros_packet_adapter.hpp" +#include "adapter/ros_packet_source.hpp" + #include "adapter/proto_packet_adapter.hpp" #include "adapter/proto_point_cloud_adapter.hpp" diff --git a/src/manager/adapter_manager.h b/src/manager/adapter_manager.h index 11321925..dc4dbe0c 100644 --- a/src/manager/adapter_manager.h +++ b/src/manager/adapter_manager.h @@ -33,7 +33,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include "utility/yaml_reader.hpp" -#include "adapter/adapter.hpp" +#include "adapter/source.hpp" namespace robosense { From 3c9c9fb2dfe1c3893cf9d32379fcb1e75e3643ae Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 10 Jan 2022 16:59:01 +0800 Subject: [PATCH 070/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 8f639e0a..3b9f0f85 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 8f639e0af14a0d64e66bccb05bb45ca0796f5cd5 +Subproject commit 3b9f0f857b66874e22779cde4b233ac6e55bd3f6 From 5460ca37b0fd0c986f0d792319847189b4d1653d Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 10 Jan 2022 20:17:17 +0800 Subject: [PATCH 071/261] refac: format --- CMakeLists.txt | 2 +- node/rslidar_sdk_node.cpp | 6 +- .../{adapter_manager.cpp => node_manager.cpp} | 28 ++-- .../{adapter_manager.h => node_manager.hpp} | 8 +- ..._cloud_msg.h => lidar_point_cloud_msg.hpp} | 0 src/{adapter => source}/source.hpp | 27 ++-- .../source_driver.hpp} | 34 ++--- .../source_packet_proto.hpp} | 38 +++--- .../source_packet_ros.hpp} | 20 +-- .../source_pointcloud_proto.hpp} | 37 +++--- .../source_pointcloud_ros.hpp} | 37 ++++-- src/utility/{common.h => common.hpp} | 0 src/utility/lock_queue.h | 101 --------------- src/utility/thread_pool.hpp | 120 ------------------ src/utility/time.h | 47 ------- src/utility/yaml_reader.hpp | 3 +- 16 files changed, 124 insertions(+), 384 deletions(-) rename src/manager/{adapter_manager.cpp => node_manager.cpp} (96%) rename src/manager/{adapter_manager.h => node_manager.hpp} (95%) rename src/msg/rs_msg/{lidar_point_cloud_msg.h => lidar_point_cloud_msg.hpp} (100%) rename src/{adapter => source}/source.hpp (83%) rename src/{adapter/driver_source.hpp => source/source_driver.hpp} (87%) rename src/{adapter/proto_packet_adapter.hpp => source/source_packet_proto.hpp} (83%) rename src/{adapter/ros_packet_source.hpp => source/source_packet_ros.hpp} (93%) rename src/{adapter/proto_point_cloud_adapter.hpp => source/source_pointcloud_proto.hpp} (86%) rename src/{adapter/ros_point_cloud_adapter.hpp => source/source_pointcloud_ros.hpp} (87%) rename src/utility/{common.h => common.hpp} (100%) delete mode 100644 src/utility/lock_queue.h delete mode 100644 src/utility/thread_pool.hpp delete mode 100644 src/utility/time.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d922cb7..da23680f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,8 +149,8 @@ message(=============================================================) if(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) add_executable(rslidar_sdk_node - src/manager/adapter_manager.cpp node/rslidar_sdk_node.cpp + src/manager/node_manager.cpp ${PROTO_FILE_PATH}/packet.pb.cc ${PROTO_FILE_PATH}/scan.pb.cc ${PROTO_FILE_PATH}/point_cloud.pb.cc diff --git a/node/rslidar_sdk_node.cpp b/node/rslidar_sdk_node.cpp index aa0bf7a1..e3fa54ad 100644 --- a/node/rslidar_sdk_node.cpp +++ b/node/rslidar_sdk_node.cpp @@ -30,9 +30,9 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *********************************************************************************************************************/ -#include "rs_driver/macro/version.hpp" -#include "manager/adapter_manager.h" +#include "manager/node_manager.hpp" +#include #include #ifdef ROS_FOUND @@ -113,7 +113,7 @@ int main(int argc, char** argv) return -1; } - std::shared_ptr demo_ptr = std::make_shared(); + std::shared_ptr demo_ptr = std::make_shared(); demo_ptr->init(config); demo_ptr->start(); diff --git a/src/manager/adapter_manager.cpp b/src/manager/node_manager.cpp similarity index 96% rename from src/manager/adapter_manager.cpp rename to src/manager/node_manager.cpp index 262269e2..0aac0e19 100644 --- a/src/manager/adapter_manager.cpp +++ b/src/manager/node_manager.cpp @@ -30,23 +30,19 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *********************************************************************************************************************/ -#include "manager/adapter_manager.h" - -#include "adapter/driver_source.hpp" -#if 0 -#include "adapter/ros_point_cloud_adapter.hpp" -#endif -#include "adapter/ros_packet_source.hpp" - -#include "adapter/proto_packet_adapter.hpp" -#include "adapter/proto_point_cloud_adapter.hpp" +#include "manager/node_manager.hpp" +#include "source/source_driver.hpp" +#include "source/source_pointcloud_ros.hpp" +#include "source/source_packet_ros.hpp" +#include "source/source_packet_proto.hpp" +#include "source/source_pointcloud_proto.hpp" namespace robosense { namespace lidar { -void AdapterManager::init(const YAML::Node& config) +void NodeManager::init(const YAML::Node& config) { #if 0 packet_thread_flag_ = false; @@ -300,7 +296,7 @@ void AdapterManager::init(const YAML::Node& config) #endif } -void AdapterManager::start() +void NodeManager::start() { #if 0 if (point_cloud_thread_flag_) @@ -324,7 +320,7 @@ void AdapterManager::start() #endif } -void AdapterManager::stop() +void NodeManager::stop() { #if 0 if (point_cloud_thread_flag_) @@ -348,13 +344,13 @@ void AdapterManager::stop() #endif } -AdapterManager::~AdapterManager() +NodeManager::~NodeManager() { stop(); } #if 0 -std::shared_ptr AdapterManager::createReceiver(const YAML::Node& config, const AdapterType& adapter_type) +std::shared_ptr NodeManager::createReceiver(const YAML::Node& config, const AdapterType& adapter_type) { std::shared_ptr receiver; switch (adapter_type) @@ -404,7 +400,7 @@ std::shared_ptr AdapterManager::createReceiver(const YAML::Node& co return receiver; } -std::shared_ptr AdapterManager::createTransmitter(const YAML::Node& config, +std::shared_ptr NodeManager::createTransmitter(const YAML::Node& config, const AdapterType& adapter_type) { std::shared_ptr transmitter; diff --git a/src/manager/adapter_manager.h b/src/manager/node_manager.hpp similarity index 95% rename from src/manager/adapter_manager.h rename to src/manager/node_manager.hpp index dc4dbe0c..39e0bc84 100644 --- a/src/manager/adapter_manager.h +++ b/src/manager/node_manager.hpp @@ -33,14 +33,14 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include "utility/yaml_reader.hpp" -#include "adapter/source.hpp" +#include "source/source.hpp" namespace robosense { namespace lidar { -class AdapterManager +class NodeManager { public: @@ -48,8 +48,8 @@ class AdapterManager void start(); void stop(); - ~AdapterManager(); - AdapterManager() = default; + ~NodeManager(); + NodeManager() = default; private: diff --git a/src/msg/rs_msg/lidar_point_cloud_msg.h b/src/msg/rs_msg/lidar_point_cloud_msg.hpp similarity index 100% rename from src/msg/rs_msg/lidar_point_cloud_msg.h rename to src/msg/rs_msg/lidar_point_cloud_msg.hpp diff --git a/src/adapter/source.hpp b/src/source/source.hpp similarity index 83% rename from src/adapter/source.hpp rename to src/source/source.hpp index 3b5f9ec5..c5420d38 100644 --- a/src/adapter/source.hpp +++ b/src/source/source.hpp @@ -32,7 +32,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#include "msg/rs_msg/lidar_point_cloud_msg.h" +#include "msg/rs_msg/lidar_point_cloud_msg.hpp" + #include "utility/yaml_reader.hpp" #include @@ -42,28 +43,28 @@ namespace robosense namespace lidar { -class PointCloudDestination +class DestinationPointCloud { public: - typedef std::shared_ptr Ptr; + typedef std::shared_ptr Ptr; virtual void init(const YAML::Node& config){} virtual void start() {} virtual void stop() {} virtual void sendPointCloud(const LidarPointCloudMsg& msg) = 0; - virtual ~PointCloudDestination() = default; + virtual ~DestinationPointCloud() = default; }; -class PacketDestination +class DestinationPacket { public: - typedef std::shared_ptr Ptr; + typedef std::shared_ptr Ptr; virtual void init(const YAML::Node& config){} virtual void start() {} virtual void stop() {} virtual void sendPacket(const Packet& msg) = 0; - virtual ~PacketDestination() = default; + virtual ~DestinationPacket() = default; }; enum SourceType @@ -83,8 +84,8 @@ class Source virtual void init(SourceType src_type, const YAML::Node& config) {} virtual void start() {} virtual void stop() {} - virtual void regRecvCallback(PointCloudDestination::Ptr dst); - virtual void regRecvCallback(PacketDestination::Ptr dst); + virtual void regRecvCallback(DestinationPointCloud::Ptr dst); + virtual void regRecvCallback(DestinationPacket::Ptr dst); virtual ~Source() = default; protected: @@ -92,16 +93,16 @@ class Source void sendPacket(const Packet& msg); void sendPointCloud(std::shared_ptr msg); - std::vector pc_cb_vec_; - std::vector pkt_cb_vec_; + std::vector pc_cb_vec_; + std::vector pkt_cb_vec_; }; -inline void Source::regRecvCallback(PacketDestination::Ptr dst) +inline void Source::regRecvCallback(DestinationPacket::Ptr dst) { pkt_cb_vec_.emplace_back(dst); } -inline void Source::regRecvCallback(PointCloudDestination::Ptr dst) +inline void Source::regRecvCallback(DestinationPointCloud::Ptr dst) { pc_cb_vec_.emplace_back(dst); } diff --git a/src/adapter/driver_source.hpp b/src/source/source_driver.hpp similarity index 87% rename from src/adapter/driver_source.hpp rename to src/source/source_driver.hpp index 2ac00749..09a772d1 100644 --- a/src/adapter/driver_source.hpp +++ b/src/source/source_driver.hpp @@ -32,7 +32,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#include "adapter/source.hpp" +#include "source/source.hpp" #include @@ -41,15 +41,15 @@ namespace robosense namespace lidar { -class DriverSource : public Source +class SourceDriver : public Source { public: virtual void init(SourceType src, const YAML::Node& config); virtual void start(); virtual void stop(); - virtual void regRecvCallback(PacketDestination::Ptr dst); - virtual ~DriverSource(); + virtual void regRecvCallback(DestinationPacket::Ptr dst); + virtual ~SourceDriver(); protected: @@ -62,14 +62,14 @@ class DriverSource : public Source std::shared_ptr> driver_ptr_; }; -inline void DriverSource::init(SourceType src_type, const YAML::Node& config) +inline void SourceDriver::init(SourceType src_type, const YAML::Node& config) { point_cloud_.reset (new LidarPointCloudMsg); driver_ptr_.reset(new lidar::LidarDriver()); - driver_ptr_->regRecvCallback(std::bind(&DriverSource::getPointCloud, this), - std::bind(&DriverSource::putPointCloud, this, std::placeholders::_1)); + driver_ptr_->regRecvCallback(std::bind(&SourceDriver::getPointCloud, this), + std::bind(&SourceDriver::putPointCloud, this, std::placeholders::_1)); driver_ptr_->regExceptionCallback( - std::bind(&DriverSource::putException, this, std::placeholders::_1)); + std::bind(&SourceDriver::putException, this, std::placeholders::_1)); YAML::Node driver_config = yamlSubNodeAbort(config, "driver"); lidar::RSDriverParam driver_param; @@ -131,48 +131,48 @@ inline void DriverSource::init(SourceType src_type, const YAML::Node& config) } } -inline void DriverSource::start() +inline void SourceDriver::start() { driver_ptr_->start(); } -inline DriverSource::~DriverSource() +inline SourceDriver::~SourceDriver() { stop(); } -inline void DriverSource::stop() +inline void SourceDriver::stop() { driver_ptr_->stop(); } -inline std::shared_ptr DriverSource::getPointCloud(void) +inline std::shared_ptr SourceDriver::getPointCloud(void) { return point_cloud_; } -inline void DriverSource::regRecvCallback(PacketDestination::Ptr dst) +inline void SourceDriver::regRecvCallback(DestinationPacket::Ptr dst) { Source::regRecvCallback(dst); if (pkt_cb_vec_.size() == 1) { driver_ptr_->regRecvCallback( - std::bind(&DriverSource::putPacket, this, std::placeholders::_1)); + std::bind(&SourceDriver::putPacket, this, std::placeholders::_1)); } } -inline void DriverSource::putPacket(const Packet& msg) +inline void SourceDriver::putPacket(const Packet& msg) { sendPacket(msg); } -void DriverSource::putPointCloud(std::shared_ptr msg) +void SourceDriver::putPointCloud(std::shared_ptr msg) { sendPointCloud(msg); } -inline void DriverSource::putException(const lidar::Error& msg) +inline void SourceDriver::putException(const lidar::Error& msg) { switch (msg.error_code_type) { diff --git a/src/adapter/proto_packet_adapter.hpp b/src/source/source_packet_proto.hpp similarity index 83% rename from src/adapter/proto_packet_adapter.hpp rename to src/source/source_packet_proto.hpp index f637cc12..b754ffc7 100644 --- a/src/adapter/proto_packet_adapter.hpp +++ b/src/source/source_packet_proto.hpp @@ -32,7 +32,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#include "adapter/source.hpp" +#include "source/source.hpp" //#include "utility/protobuf_communicator.hpp" #include "rs_driver/utility/sync_queue.hpp" @@ -47,7 +47,7 @@ namespace robosense namespace lidar { -class ProtoPacketSource : DriverSource +class SourcePacketProto : SourceDriver { public: @@ -66,9 +66,9 @@ class ProtoPacketSource : DriverSource std::thread splice_thread_; }; -void ProtoPacketSource::init(SourceType src_type, const YAML::Node& config) +void SourcePacketProto::init(SourceType src_type, const YAML::Node& config) { - DriverSource::init(src_type, config); + SourceDriver::init(src_type, config); uint16_t packet_recv_port; yamlReadAbort(config["proto"], "packet_recv_port", packet_recv_port); @@ -84,19 +84,19 @@ void ProtoPacketSource::init(SourceType src_type, const YAML::Node& config) #endif } -inline void ProtoPacketSource::start() +inline void SourcePacketProto::start() { - recv_thread_ = std::thread(std::bind(&ProtoPacketSource::recvPacket, this)); - splice_thread_ = std::thread(std::bind(&ProtoPacketSource::splicePacket, this)); + recv_thread_ = std::thread(std::bind(&SourcePacketProto::recvPacket, this)); + splice_thread_ = std::thread(std::bind(&SourcePacketProto::splicePacket, this)); } -inline void ProtoPacketSource::stop() +inline void SourcePacketProto::stop() { recv_thread_.join(); splice_thread_.join(); } -inline void ProtoPacketSource::recvPacket() +inline void SourcePacketProto::recvPacket() { #if 0 while (1) @@ -115,7 +115,7 @@ inline void ProtoPacketSource::recvPacket() #endif } -inline void ProtoPacketSource::splicePacket() +inline void SourcePacketProto::splicePacket() { #if 0 while (1) @@ -132,7 +132,7 @@ inline void ProtoPacketSource::splicePacket() #endif } -class ProtoPacketDestination : public PacketDestination +class DestinationPacketProto : public DestinationPacket { public: @@ -140,7 +140,7 @@ class ProtoPacketDestination : public PacketDestination virtual void start(); virtual void stop(); virtual void sendPacket(const Packet& msg); - virtual ~ProtoPacketDestination(); + virtual ~DestinationPacketProto(); private: @@ -152,7 +152,7 @@ class ProtoPacketDestination : public PacketDestination bool to_exit_; }; -inline void ProtoPacketDestination::init(const YAML::Node& config) +inline void DestinationPacketProto::init(const YAML::Node& config) { std::string packet_send_ip; yamlReadAbort(config["proto"], "packet_send_ip", packet_send_ip); @@ -170,28 +170,28 @@ inline void ProtoPacketDestination::init(const YAML::Node& config) #endif } -inline void ProtoPacketDestination::start() +inline void DestinationPacketProto::start() { - send_thread_ = std::thread(std::bind(&ProtoPacketDestination::internSendPacket, this)); + send_thread_ = std::thread(std::bind(&DestinationPacketProto::internSendPacket, this)); } -inline void ProtoPacketDestination::stop() +inline void DestinationPacketProto::stop() { to_exit_ = true; send_thread_.join(); } -inline ProtoPacketDestination::~ProtoPacketDestination() +inline DestinationPacketProto::~DestinationPacketProto() { stop(); } -inline void ProtoPacketDestination::sendPacket(const Packet& msg) +inline void DestinationPacketProto::sendPacket(const Packet& msg) { //pkt_queue_.push(msg); } -inline void ProtoPacketDestination::internSendPacket() +inline void DestinationPacketProto::internSendPacket() { #if 0 PacketMsg msg = pkt_send_queue_.popWait(1000); diff --git a/src/adapter/ros_packet_source.hpp b/src/source/source_packet_ros.hpp similarity index 93% rename from src/adapter/ros_packet_source.hpp rename to src/source/source_packet_ros.hpp index b6ce1b61..deaa2cda 100644 --- a/src/adapter/ros_packet_source.hpp +++ b/src/source/source_packet_ros.hpp @@ -32,7 +32,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#include "adapter/driver_source.hpp" +#include "source/source_driver.hpp" #include "msg/ros_msg/lidar_packet_ros.h" #ifdef ROS_FOUND @@ -57,7 +57,7 @@ inline Packet toRsMsg(const rslidar_msgs::rslidarPacket& ros_msg) return std::move(rs_msg); } -class RosPacketSource : public DriverSource +class SourcePacketRos : public SourceDriver { public: @@ -71,19 +71,19 @@ class RosPacketSource : public DriverSource ros::Subscriber pkt_sub_; }; -void RosPacketSource::init(SourceType src_type, const YAML::Node& config) +void SourcePacketRos::init(SourceType src_type, const YAML::Node& config) { - DriverSource::init(src_type, config); + SourceDriver::init(src_type, config); std::string ros_recv_topic; yamlRead(config["ros"], "ros_recv_packet_topic", ros_recv_topic, "rslidar_packets"); nh_ = std::unique_ptr(new ros::NodeHandle()); - pkt_sub_ = nh_->subscribe(ros_recv_topic, 1, &RosPacketSource::putPacket, this); + pkt_sub_ = nh_->subscribe(ros_recv_topic, 1, &SourcePacketRos::putPacket, this); } -void RosPacketSource::putPacket(const rslidar_msgs::rslidarPacket& msg) +void SourcePacketRos::putPacket(const rslidar_msgs::rslidarPacket& msg) { driver_ptr_->decodePacket(toRsMsg(msg)); } @@ -102,13 +102,13 @@ inline rslidar_msgs::rslidarPacket toRosMsg(const Packet& rs_msg) return std::move(ros_msg); } -class RosPacketDestination : public PacketDestination +class DestinationPacketRos : public DestinationPacket { public: virtual void init(const YAML::Node& config); virtual void sendPacket(const Packet& msg); - virtual ~RosPacketDestination() = default; + virtual ~DestinationPacketRos() = default; private: @@ -116,7 +116,7 @@ class RosPacketDestination : public PacketDestination ros::Publisher pub_; }; -inline void RosPacketDestination::init(const YAML::Node& config) +inline void DestinationPacketRos::init(const YAML::Node& config) { std::string ros_send_topic; yamlRead(config["ros"], "ros_send_packet_topic", @@ -126,7 +126,7 @@ inline void RosPacketDestination::init(const YAML::Node& config) pub_ = nh_->advertise(ros_send_topic, 10); } -inline void RosPacketDestination::sendPacket(const Packet& msg) +inline void DestinationPacketRos::sendPacket(const Packet& msg) { pub_.publish(toRosMsg(msg)); } diff --git a/src/adapter/proto_point_cloud_adapter.hpp b/src/source/source_pointcloud_proto.hpp similarity index 86% rename from src/adapter/proto_point_cloud_adapter.hpp rename to src/source/source_pointcloud_proto.hpp index 0dc313f5..7bbd8aef 100644 --- a/src/adapter/proto_point_cloud_adapter.hpp +++ b/src/source/source_pointcloud_proto.hpp @@ -34,7 +34,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifdef PROTO_FOUND -#include "adapter/source.hpp" +#include "source/source.hpp" //#include "utility/protobuf_communicator.hpp" constexpr size_t RECEIVE_BUF_SIZE = 10000000; @@ -44,14 +44,14 @@ namespace robosense namespace lidar { -class ProtoPointCloudSource : public Source +class SourcePointCloudProto : public Source { public: virtual void init(SourceType src_type, const YAML::Node& config); virtual void start(); virtual void stop(); - virtual ~ProtoPointCloudSource(); + virtual ~SourcePointCloudProto(); private: @@ -65,7 +65,7 @@ class ProtoPointCloudSource : public Source int new_frmnum_; }; -inline void ProtoPointCloudSource::init(SourceType src_type, const YAML::Node& config) +inline void SourcePointCloudProto::init(SourceType src_type, const YAML::Node& config) { uint16_t point_cloud_recv_port; yamlReadAbort(config["proto"], "point_cloud_recv_port", point_cloud_recv_port); @@ -81,22 +81,22 @@ inline void ProtoPointCloudSource::init(SourceType src_type, const YAML::Node& c #endif } -inline void ProtoPointCloudSource::start() +inline void SourcePointCloudProto::start() { - recv_thread_ = std::thread(std::bind(&ProtoPointCloudSource::recvPointCloud, this)); + recv_thread_ = std::thread(std::bind(&SourcePointCloudProto::recvPointCloud, this)); } -inline void ProtoPointCloudSource::stop() +inline void SourcePointCloudProto::stop() { recv_thread_.join(); } -inline ProtoPointCloudSource::~ProtoPointCloudSource() +inline SourcePointCloudProto::~SourcePointCloudProto() { stop(); } -inline void ProtoPointCloudSource::recvPointCloud() +inline void SourcePointCloudProto::recvPointCloud() { #if 0 bool start_check = true; @@ -134,7 +134,7 @@ inline void ProtoPointCloudSource::recvPointCloud() #endif } -inline void ProtoPointCloudSource::splicePointCloud() +inline void SourcePointCloudProto::splicePointCloud() { #if 0 while (point_cloud_recv_queue_.size() > 0) @@ -159,7 +159,7 @@ inline void ProtoPointCloudSource::splicePointCloud() #endif } -class ProtoPointCloudDestination : public PointCloudDestination +class DestinationPointCloudProto : public DestinationPointCloud { public: @@ -167,7 +167,7 @@ class ProtoPointCloudDestination : public PointCloudDestination virtual void start(); virtual void stop(); virtual void sendPointCloud(const LidarPointCloudMsg& msg); - virtual ~ProtoPointCloudDestination() = default; + virtual ~DestinationPointCloudProto() = default; private: @@ -179,7 +179,7 @@ class ProtoPointCloudDestination : public PointCloudDestination bool to_exit_; }; -inline void ProtoPointCloudDestination::init(const YAML::Node& config) +inline void DestinationPointCloudProto::init(const YAML::Node& config) { std::string point_cloud_send_port; yamlReadAbort(config["proto"], "point_cloud_send_port", point_cloud_send_port); @@ -197,24 +197,24 @@ inline void ProtoPointCloudDestination::init(const YAML::Node& config) #endif } -inline void ProtoPointCloudDestination::start() +inline void DestinationPointCloudProto::start() { send_thread_ = - std::thread(std::bind(&ProtoPointCloudDestination::internSendPointCloud, this)); + std::thread(std::bind(&DestinationPointCloudProto::internSendPointCloud, this)); } -inline void ProtoPointCloudDestination::stop() +inline void DestinationPointCloudProto::stop() { to_exit_ = true; send_thread_.join(); } -inline void ProtoPointCloudDestination::sendPointCloud(const LidarPointCloudMsg& msg) +inline void DestinationPointCloudProto::sendPointCloud(const LidarPointCloudMsg& msg) { //point_cloud_send_queue_.push(msg); } -inline void ProtoPointCloudDestination::internSendPointCloud() +inline void DestinationPointCloudProto::internSendPointCloud() { #if 0 while (point_cloud_send_queue_.size() > 0) @@ -229,7 +229,6 @@ inline void ProtoPointCloudDestination::internSendPointCloud() #endif } - } // namespace lidar } // namespace robosense diff --git a/src/adapter/ros_point_cloud_adapter.hpp b/src/source/source_pointcloud_ros.hpp similarity index 87% rename from src/adapter/ros_point_cloud_adapter.hpp rename to src/source/source_pointcloud_ros.hpp index a883d1d5..aed01856 100644 --- a/src/adapter/ros_point_cloud_adapter.hpp +++ b/src/source/source_pointcloud_ros.hpp @@ -32,18 +32,19 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#include "adapter/adapter.hpp" +#include "source/source.hpp" + #include #include +#ifdef ROS_FOUND +#include + namespace robosense { namespace lidar { -#ifdef ROS_FOUND -#include - inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) { sensor_msgs::PointCloud2 ros_msg; @@ -54,20 +55,20 @@ inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) return std::move(ros_msg); } -class RosPointCloudDestination : public PointCloudDestination +class DestinationPointCloudRos : public DestinationPointCloud { public: virtual void init(const YAML::Node& config); virtual void sendPointCloud(const LidarPointCloudMsg& msg); - virtual ~RosPointCloudDestination() = default; + virtual ~DestinationPointCloudRos() = default; private: std::shared_ptr nh_; ros::Publisher pub_; }; -inline void RosPointCloudDestination::init(const YAML::Node& config) +inline void DestinationPointCloudRos::init(const YAML::Node& config) { std::string ros_send_topic; yamlRead(config["ros"], @@ -77,16 +78,24 @@ inline void RosPointCloudDestination::init(const YAML::Node& config) pub_ = nh_->advertise(ros_send_topic, 10); } -inline void RosPointCloudDestination::sendPointCloud(const LidarPointCloudMsg& msg) +inline void DestinationPointCloudRos::sendPointCloud(const LidarPointCloudMsg& msg) { pub_.publish(toRosMsg(msg)); } +} // namespace lidar +} // namespace robosense + #endif // ROS_FOUND #ifdef ROS2_FOUND #include +namespace robosense +{ +namespace lidar +{ + inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) { sensor_msgs::msg::PointCloud2 ros_msg; @@ -98,20 +107,20 @@ inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) return std::move(ros_msg); } -class RosPointCloudDestination : virtual public RosPointCloudDestination +class DestinationPointCloudRos : virtual public DestinationPointCloudRos { public: virtual void init(const YAML::Node& config); virtual void sendPointCloud(const LidarPointCloudMsg& msg); - virtual ~RosPointCloudDestination() = default; + virtual ~DestinationPointCloudRos() = default; private: std::shared_ptr node_ptr_; rclcpp::Publisher::SharedPtr pub_; }; -inline void RosPointCloudDestination::init(const YAML::Node& config) +inline void DestinationPointCloudRos::init(const YAML::Node& config) { std::string ros_send_topic; yamlRead(config["ros"], @@ -121,11 +130,13 @@ inline void RosPointCloudDestination::init(const YAML::Node& config) pub_ = node_ptr_->create_publisher(ros_send_topic, 1); } -inline void RosPointCloudDestination::sendPointCloud(const LidarPointCloudMsg& msg) +inline void DestinationPointCloudRos::sendPointCloud(const LidarPointCloudMsg& msg) { pub_->publish(toRosMsg(msg)); } -#endif } // namespace lidar } // namespace robosense + +#endif + diff --git a/src/utility/common.h b/src/utility/common.hpp similarity index 100% rename from src/utility/common.h rename to src/utility/common.hpp diff --git a/src/utility/lock_queue.h b/src/utility/lock_queue.h deleted file mode 100644 index 56e19d12..00000000 --- a/src/utility/lock_queue.h +++ /dev/null @@ -1,101 +0,0 @@ -/********************************************************************************************************************* -Copyright (c) 2020 RoboSense -All rights reserved - -By downloading, copying, installing or using the software you agree to this license. If you do not agree to this -license, do not download, install, copy or use the software. - -License Agreement -For RoboSense LiDAR SDK Library -(3-clause BSD License) - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following -disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the names of the RoboSense, nor Suteng Innovation Technology, nor the names of other contributors may be used -to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*********************************************************************************************************************/ - -#pragma once -#include -namespace robosense -{ -namespace lidar -{ -template -class Queue -{ -public: - inline Queue() : is_task_finished_(true) - { - } - - inline T front() - { - std::lock_guard lock(mutex_); - return queue_.front(); - } - - inline void push(const T& value) - { - std::lock_guard lock(mutex_); - queue_.push(value); - } - - inline void pop() - { - std::lock_guard lock(mutex_); - if (!queue_.empty()) - { - queue_.pop(); - } - } - - inline T popFront() - { - T value; - std::lock_guard lock(mutex_); - if (!queue_.empty()) - { - value = std::move(queue_.front()); - queue_.pop(); - } - return value; - } - - inline void clear() - { - std::queue empty; - std::lock_guard lock(mutex_); - swap(empty, queue_); - } - - inline size_t size() - { - std::lock_guard lock(mutex_); - return queue_.size(); - } - -public: - std::queue queue_; - std::atomic is_task_finished_; - -private: - mutable std::mutex mutex_; -}; -} // namespace lidar -} // namespace robosense \ No newline at end of file diff --git a/src/utility/thread_pool.hpp b/src/utility/thread_pool.hpp deleted file mode 100644 index d97c85a2..00000000 --- a/src/utility/thread_pool.hpp +++ /dev/null @@ -1,120 +0,0 @@ -/********************************************************************************************************************* -Copyright (c) 2020 RoboSense -All rights reserved - -By downloading, copying, installing or using the software you agree to this license. If you do not agree to this -license, do not download, install, copy or use the software. - -License Agreement -For RoboSense LiDAR SDK Library -(3-clause BSD License) - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following -disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the names of the RoboSense, nor Suteng Innovation Technology, nor the names of other contributors may be used -to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*********************************************************************************************************************/ - -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -namespace robosense -{ -namespace lidar -{ -constexpr uint16_t MAX_THREAD_NUM = 2; -struct Thread -{ - Thread() : start_(false) - { - } - std::shared_ptr thread_; - std::atomic start_; -}; -class ThreadPool -{ -public: - typedef std::shared_ptr Ptr; - inline ThreadPool() : stop_flag_(false), idl_thr_num_(MAX_THREAD_NUM) - { - for (int i = 0; i < idl_thr_num_; ++i) - { - pool_.emplace_back([this] { - while (!this->stop_flag_) - { - std::function task; - { - std::unique_lock lock{ this->mutex_ }; - this->cv_task_.wait(lock, [this] { return this->stop_flag_.load() || !this->tasks_.empty(); }); - if (this->stop_flag_ && this->tasks_.empty()) - return; - task = std::move(this->tasks_.front()); - this->tasks_.pop(); - } - idl_thr_num_--; - task(); - idl_thr_num_++; - } - }); - } - } - - inline ~ThreadPool() - { - stop_flag_.store(true); - cv_task_.notify_all(); - for (std::thread& thread : pool_) - { - thread.join(); - } - } - -public: - template - inline void commit(F&& f, Args&&... args) - { - if (stop_flag_.load()) - throw std::runtime_error("Commit on LiDAR threadpool is stopped."); - using RetType = decltype(f(args...)); - auto task = - std::make_shared>(std::bind(std::forward(f), std::forward(args)...)); - { - std::lock_guard lock{ mutex_ }; - tasks_.emplace([task]() { (*task)(); }); - } - cv_task_.notify_one(); - } - -private: - using Task = std::function; - std::vector pool_; - std::queue tasks_; - std::mutex mutex_; - std::condition_variable cv_task_; - std::atomic stop_flag_; - std::atomic idl_thr_num_; -}; -} // namespace lidar -} // namespace robosense diff --git a/src/utility/time.h b/src/utility/time.h deleted file mode 100644 index 266106d8..00000000 --- a/src/utility/time.h +++ /dev/null @@ -1,47 +0,0 @@ -/********************************************************************************************************************* -Copyright (c) 2020 RoboSense -All rights reserved - -By downloading, copying, installing or using the software you agree to this license. If you do not agree to this -license, do not download, install, copy or use the software. - -License Agreement -For RoboSense LiDAR SDK Library -(3-clause BSD License) - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following -disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the names of the RoboSense, nor Suteng Innovation Technology, nor the names of other contributors may be used -to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*********************************************************************************************************************/ - -#pragma once -#include -#include -namespace robosense -{ -namespace lidar -{ -inline double getTime(void) -{ - const auto t = std::chrono::system_clock::now(); - const auto t_sec = std::chrono::duration_cast>(t.time_since_epoch()); - return (double)t_sec.count(); -} -} // namespace lidar -} // namespace robosense diff --git a/src/utility/yaml_reader.hpp b/src/utility/yaml_reader.hpp index 8b6c7a32..22bedc56 100644 --- a/src/utility/yaml_reader.hpp +++ b/src/utility/yaml_reader.hpp @@ -33,7 +33,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include -#include "utility/common.h" + +#include "utility/common.hpp" namespace robosense { From 8a9a6a57f9dc44645794932e1c3b98af25fdb17f Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 11 Jan 2022 09:23:48 +0800 Subject: [PATCH 072/261] refac: refac node_manager --- src/manager/node_manager.cpp | 337 ++++------------------------- src/source/source_packet_proto.hpp | 2 +- 2 files changed, 44 insertions(+), 295 deletions(-) diff --git a/src/manager/node_manager.cpp b/src/manager/node_manager.cpp index 0aac0e19..ec0ac1e5 100644 --- a/src/manager/node_manager.cpp +++ b/src/manager/node_manager.cpp @@ -44,10 +44,6 @@ namespace lidar void NodeManager::init(const YAML::Node& config) { -#if 0 - packet_thread_flag_ = false; - point_cloud_thread_flag_ = false; - YAML::Node common_config = yamlSubNodeAbort(config, "common"); int msg_source = 0; @@ -65,25 +61,20 @@ void NodeManager::init(const YAML::Node& config) bool send_packet_proto; yamlRead(common_config, "send_packet_proto", send_packet_proto, false); - std::string pcap_dir; - double pcap_rate; - bool pcap_repeat; - yamlRead(common_config, "pcap_path", pcap_dir, ""); - yamlRead(common_config, "pcap_rate", pcap_rate, 1); - yamlRead(common_config, "pcap_repeat", pcap_repeat, true); - YAML::Node lidar_config = yamlSubNodeAbort(config, "lidar"); for (uint8_t i = 0; i < lidar_config.size(); ++i) { - AdapterBase::Ptr recv_ptr; + std::shared_ptr source; + + //AdapterBase::Ptr recv_ptr; // // Receiver // switch (msg_source) { - case MsgSource::MSG_FROM_LIDAR: // online lidar + case SourceType::MSG_FROM_LIDAR: // online lidar RS_INFO << "------------------------------------------------------" << RS_REND; RS_INFO << "Receive Packets From : Online LiDAR" << RS_REND; @@ -91,22 +82,11 @@ void NodeManager::init(const YAML::Node& config) RS_INFO << "Difop Port: " << lidar_config[i]["driver"]["difop_port"].as() << RS_REND; RS_INFO << "------------------------------------------------------" << RS_REND; - point_cloud_thread_flag_ = true; - - lidar_config[i]["msg_source"] = (int)MsgSource::MSG_FROM_LIDAR; - - recv_ptr = createReceiver(lidar_config[i], AdapterType::DriverAdapter); - point_cloud_receive_adapter_vec_.push_back(recv_ptr); - - if (send_packet_ros || send_packet_proto) - { - packet_receive_adapter_vec_.push_back(recv_ptr); - packet_thread_flag_ = true; - } - + source = std::make_shared(); + source->init((SourceType)msg_source, lidar_config[i]); break; - case MsgSource::MSG_FROM_ROS_PACKET: // pkt from ros + case SourceType::MSG_FROM_ROS_PACKET: // pkt from ros RS_INFO << "------------------------------------------------------" << RS_REND; RS_INFO << "Receive Packets From : ROS" << RS_REND; @@ -115,24 +95,11 @@ void NodeManager::init(const YAML::Node& config) << RS_REND; RS_INFO << "------------------------------------------------------" << RS_REND; - send_packet_ros = false; - point_cloud_thread_flag_ = false; - packet_thread_flag_ = true; - - lidar_config[i]["msg_source"] = (int)MsgSource::MSG_FROM_ROS_PACKET; - - point_cloud_receive_adapter_vec_.emplace_back(createReceiver(lidar_config[i], AdapterType::DriverAdapter)); - packet_receive_adapter_vec_.emplace_back(createReceiver(lidar_config[i], AdapterType::PacketRosAdapter)); - -#if 0 - packet_receive_adapter_vec_[i]->regRecvCallback( - std::bind(&AdapterBase::decodeScan, point_cloud_receive_adapter_vec_[i], std::placeholders::_1)); - packet_receive_adapter_vec_[i]->regRecvCallback( - std::bind(&AdapterBase::decodePacket, point_cloud_receive_adapter_vec_[i], std::placeholders::_1)); -#endif + source = std::make_shared(); + source->init((SourceType)msg_source, lidar_config[i]); break; - case MsgSource::MSG_FROM_PCAP: // pcap + case SourceType::MSG_FROM_PCAP: // pcap RS_INFO << "------------------------------------------------------" << RS_REND; RS_INFO << "Receive Packets From : Pcap" << RS_REND; @@ -140,71 +107,38 @@ void NodeManager::init(const YAML::Node& config) RS_INFO << "Difop Port: " << lidar_config[i]["driver"]["difop_port"].as() << RS_REND; RS_INFO << "------------------------------------------------------" << RS_REND; - point_cloud_thread_flag_ = true; - - lidar_config[i]["msg_source"] = (int)MsgSource::MSG_FROM_PCAP; - - lidar_config[i]["driver"]["read_pcap"] = true; - lidar_config[i]["driver"]["pcap_path"] = pcap_dir; - lidar_config[i]["driver"]["pcap_rate"] = pcap_rate; - lidar_config[i]["driver"]["pcap_repeat"] = pcap_repeat; - - recv_ptr = createReceiver(lidar_config[i], AdapterType::DriverAdapter); - point_cloud_receive_adapter_vec_.push_back(recv_ptr); - - if (send_packet_ros || send_packet_proto) - { - packet_receive_adapter_vec_.push_back(recv_ptr); - packet_thread_flag_ = true; - } - + source = std::make_shared(); + source->init((SourceType)msg_source, lidar_config[i]); break; -#if 0 - case MsgSource::MSG_FROM_PROTO_PACKET: // packets from proto + case SourceType::MSG_FROM_PROTO_PACKET: // packets from proto + RS_INFO << "------------------------------------------------------" << RS_REND; RS_INFO << "Receive Packets From : Protobuf-UDP" << RS_REND; RS_INFO << "Msop Port: " << lidar_config[i]["proto"]["msop_recv_port"].as() << RS_REND; RS_INFO << "Difop Port: " << lidar_config[i]["proto"]["difop_recv_port"].as() << RS_REND; RS_INFO << "------------------------------------------------------" << RS_REND; - point_cloud_thread_flag_ = false; - packet_thread_flag_ = true; - lidar_config[i]["msg_source"] = (int)MsgSource::MSG_FROM_PROTO_PACKET; - send_packet_proto = false; - point_cloud_receive_adapter_vec_.emplace_back(createReceiver(lidar_config[i], AdapterType::DriverAdapter)); - packet_receive_adapter_vec_.emplace_back(createReceiver(lidar_config[i], AdapterType::PacketProtoAdapter)); - packet_receive_adapter_vec_[i]->regRecvCallback( - std::bind(&AdapterBase::decodeScan, point_cloud_receive_adapter_vec_[i], std::placeholders::_1)); - packet_receive_adapter_vec_[i]->regRecvCallback( - std::bind(&AdapterBase::decodePacket, point_cloud_receive_adapter_vec_[i], std::placeholders::_1)); + + source = std::make_shared(); + source->init((SourceType)msg_source, lidar_config[i]); break; - case MsgSource::MSG_FROM_PROTO_POINTCLOUD: // point cloud from proto + case SourceType::MSG_FROM_PROTO_POINTCLOUD: // point cloud from proto + RS_INFO << "------------------------------------------------------" << RS_REND; RS_INFO << "Receive PointCloud From : Protobuf-UDP" << RS_REND; RS_INFO << "PointCloud Port: " << lidar_config[i]["proto"]["point_cloud_recv_port"].as() << RS_REND; RS_INFO << "------------------------------------------------------" << RS_REND; - point_cloud_thread_flag_ = true; - packet_thread_flag_ = false; - lidar_config[i]["msg_source"] = (int)MsgSource::MSG_FROM_PROTO_POINTCLOUD; - send_point_cloud_proto = false; - send_packet_ros = false; - send_packet_proto = false; - send_camera_trigger_ros = false; - point_cloud_receive_adapter_vec_.emplace_back( - createReceiver(lidar_config[i], AdapterType::PointCloudProtoAdapter)); - packet_receive_adapter_vec_.emplace_back(nullptr); + + source = std::make_shared(); + source->init((SourceType)msg_source, lidar_config[i]); break; -#endif default: - RS_ERROR << "Not use LiDAR or Wrong LiDAR message source! Abort!" << RS_REND; + RS_ERROR << "Wrong LiDAR message source:" << msg_source << "." << RS_REND; exit(-1); } - // - // Transmitter - // if (send_packet_ros) { RS_DEBUG << "------------------------------------------------------" << RS_REND; @@ -214,20 +148,11 @@ void NodeManager::init(const YAML::Node& config) << RS_REND; RS_DEBUG << "------------------------------------------------------" << RS_REND; - lidar_config[i]["send_packet_ros"] = true; - - AdapterBase::Ptr transmitter_ptr = createTransmitter(lidar_config[i], AdapterType::PacketRosAdapter); - packet_transmit_adapter_vec_.emplace_back(transmitter_ptr); - -#if 0 - packet_receive_adapter_vec_[i]->regRecvCallback( - std::bind(&AdapterBase::sendScan, transmitter_ptr, std::placeholders::_1)); - packet_receive_adapter_vec_[i]->regRecvCallback( - std::bind(&AdapterBase::sendPacket, transmitter_ptr, std::placeholders::_1)); -#endif + std::shared_ptr dst = std::make_shared(); + dst->init(lidar_config[i]); + source->regRecvCallback(dst); } -#if 0 if (send_packet_proto) { RS_DEBUG << "------------------------------------------------------" << RS_REND; @@ -236,15 +161,11 @@ void NodeManager::init(const YAML::Node& config) RS_DEBUG << "Difop Port: " << lidar_config[i]["proto"]["difop_send_port"].as() << RS_REND; RS_DEBUG << "Target IP: " << lidar_config[i]["proto"]["packet_send_ip"].as() << RS_REND; RS_DEBUG << "------------------------------------------------------" << RS_REND; - lidar_config[i]["send_packet_proto"] = true; - AdapterBase::Ptr transmitter_ptr = createTransmitter(lidar_config[i], AdapterType::PacketProtoAdapter); - packet_transmit_adapter_vec_.emplace_back(transmitter_ptr); - packet_receive_adapter_vec_[i]->regRecvCallback( - std::bind(&AdapterBase::sendScan, transmitter_ptr, std::placeholders::_1)); - packet_receive_adapter_vec_[i]->regRecvCallback( - std::bind(&AdapterBase::sendPacket, transmitter_ptr, std::placeholders::_1)); + + std::shared_ptr dst = std::make_shared(); + dst->init(lidar_config[i]); + source->regRecvCallback(dst); } -#endif if (send_point_cloud_ros) { @@ -254,16 +175,11 @@ void NodeManager::init(const YAML::Node& config) << RS_REND; RS_DEBUG << "------------------------------------------------------" << RS_REND; - lidar_config[i]["send_point_cloud_ros"] = true; - - AdapterBase::Ptr transmitter_ptr = createTransmitter(lidar_config[i], AdapterType::PointCloudRosAdapter); - point_cloud_transmit_adapter_vec_.emplace_back(transmitter_ptr); - - point_cloud_receive_adapter_vec_[i]->regRecvCallback( - std::bind(&AdapterBase::sendPointCloud, transmitter_ptr, std::placeholders::_1)); + std::shared_ptr dst = std::make_shared(); + dst->init(lidar_config[i]); + source->regRecvCallback(dst); } -#if 0 if (send_point_cloud_proto) { RS_DEBUG << "------------------------------------------------------" << RS_REND; @@ -271,77 +187,30 @@ void NodeManager::init(const YAML::Node& config) RS_DEBUG << "PointCloud Port: " << lidar_config[i]["proto"]["point_cloud_send_port"].as() << RS_REND; RS_DEBUG << "Target IP: " << lidar_config[i]["proto"]["point_cloud_send_ip"].as() << RS_REND; RS_DEBUG << "------------------------------------------------------" << RS_REND; - lidar_config[i]["send_point_cloud_proto"] = true; - AdapterBase::Ptr transmitter_ptr = createTransmitter(lidar_config[i], AdapterType::PointCloudProtoAdapter); - point_cloud_transmit_adapter_vec_.emplace_back(transmitter_ptr); - point_cloud_receive_adapter_vec_[i]->regRecvCallback( - std::bind(&AdapterBase::sendPointCloud, transmitter_ptr, std::placeholders::_1)); - } - if (send_camera_trigger_ros) - { - RS_DEBUG << "------------------------------------------------------" << RS_REND; - RS_DEBUG << "Send Camera Trigger To : ROS" << RS_REND; - for (auto iter : lidar_config[i]["camera"]) - { - RS_DEBUG << "Camera : " << iter["frame_id"].as() - << " Trigger Angle : " << iter["trigger_angle"].as() << RS_REND; - } - RS_DEBUG << "------------------------------------------------------" << RS_REND; - AdapterBase::Ptr transmitter_ptr = createTransmitter(lidar_config[i], AdapterType::CameraTriggerRosAdapter); - point_cloud_receive_adapter_vec_[i]->regRecvCallback( - std::bind(&AdapterBase::sendCameraTrigger, transmitter_ptr, std::placeholders::_1)); + + std::shared_ptr dst = std::make_shared(); + dst->init(lidar_config[i]); + source->regRecvCallback(dst); } -#endif } -#endif } void NodeManager::start() { -#if 0 - if (point_cloud_thread_flag_) - { - for (auto& iter : point_cloud_receive_adapter_vec_) - { - if (iter != nullptr) - iter->start(); - } - } - if (packet_thread_flag_) + for (auto& iter : sources_) { - for (auto& iter : packet_receive_adapter_vec_) - { - if (iter != nullptr) - { - iter->start(); - } - } + if (iter != nullptr) + iter->start(); } -#endif } void NodeManager::stop() { -#if 0 - if (point_cloud_thread_flag_) + for (auto& iter : sources_) { - for (auto& iter : point_cloud_receive_adapter_vec_) - { - if (iter != nullptr) - iter->stop(); - } + if (iter != nullptr) + iter->stop(); } - if (packet_thread_flag_) - { - for (auto& iter : packet_receive_adapter_vec_) - { - if (iter != nullptr) - { - iter->stop(); - } - } - } -#endif } NodeManager::~NodeManager() @@ -349,125 +218,5 @@ NodeManager::~NodeManager() stop(); } -#if 0 -std::shared_ptr NodeManager::createReceiver(const YAML::Node& config, const AdapterType& adapter_type) -{ - std::shared_ptr receiver; - switch (adapter_type) - { - case AdapterType::DriverAdapter: - receiver = std::dynamic_pointer_cast(std::make_shared()); - receiver->init(config); - break; - -#if 0 - case AdapterType::PacketRosAdapter: -#if (ROS_FOUND || ROS2_FOUND) - receiver = std::dynamic_pointer_cast(std::make_shared()); - receiver->init(config); - break; -#else - RS_ERROR << "ROS not found! Could not use ROS functions!" << RS_REND; - exit(-1); -#endif - - case AdapterType::PacketProtoAdapter: -#ifdef PROTO_FOUND - receiver = std::dynamic_pointer_cast(std::make_shared()); - receiver->init(config); - break; -#else - RS_ERROR << "Protobuf not found! Could not use Protobuf functions!" << RS_REND; - exit(-1); -#endif - - case AdapterType::PointCloudProtoAdapter: -#ifdef PROTO_FOUND - receiver = std::dynamic_pointer_cast(std::make_shared()); - receiver->init(config); - break; -#else - RS_ERROR << "Protobuf not found! Could not use Protobuf functions!" << RS_REND; - exit(-1); -#endif -#endif - - default: - RS_ERROR << "Create receiver failed. Abort!" << RS_REND; - exit(-1); - } - - return receiver; -} - -std::shared_ptr NodeManager::createTransmitter(const YAML::Node& config, - const AdapterType& adapter_type) -{ - std::shared_ptr transmitter; - switch (adapter_type) - { -#if 0 - case AdapterType::PacketRosAdapter: -#if (ROS_FOUND || ROS2_FOUND) - transmitter = std::dynamic_pointer_cast(std::make_shared()); - transmitter->init(config); - break; -#else - RS_ERROR << "ROS not found! Could not use ROS functions!" << RS_REND; - exit(-1); -#endif - - case AdapterType::PacketProtoAdapter: -#ifdef PROTO_FOUND - transmitter = std::dynamic_pointer_cast(std::make_shared()); - transmitter->init(config); - break; -#else - RS_ERROR << "Protobuf not found! Could not use Protobuf functions!" << RS_REND; - exit(-1); -#endif -#endif - - case AdapterType::PointCloudRosAdapter: -#if (ROS_FOUND || ROS2_FOUND) - transmitter = std::dynamic_pointer_cast(std::make_shared()); - transmitter->init(config); - break; -#else - RS_ERROR << "ROS not found! Could not use ROS functions!" << RS_REND; - exit(-1); -#endif - -#if 0 - case AdapterType::PointCloudProtoAdapter: -#ifdef PROTO_FOUND - transmitter = std::dynamic_pointer_cast(std::make_shared()); - transmitter->init(config); - break; -#else - RS_ERROR << "Protobuf not found! Could not use Protobuf functions!" << RS_REND; - exit(-1); -#endif - - case AdapterType::CameraTriggerRosAdapter: -#if (ROS_FOUND) ///< Camera trigger not support ROS2 yet - transmitter = std::dynamic_pointer_cast(std::make_shared()); - transmitter->init(config); - break; -#else - RS_ERROR << "ROS not found! Could not use ROS functions!" << RS_REND; - exit(-1); -#endif -#endif - - default: - RS_ERROR << "Create transmitter failed. Abort!" << RS_REND; - exit(-1); - } - - return transmitter; -} -#endif - } // namespace lidar } // namespace robosense diff --git a/src/source/source_packet_proto.hpp b/src/source/source_packet_proto.hpp index b754ffc7..0ece3959 100644 --- a/src/source/source_packet_proto.hpp +++ b/src/source/source_packet_proto.hpp @@ -47,7 +47,7 @@ namespace robosense namespace lidar { -class SourcePacketProto : SourceDriver +class SourcePacketProto : public SourceDriver { public: From 127abdd266040003c9902a53dedff8748d03cfdf Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 11 Jan 2022 14:23:58 +0800 Subject: [PATCH 073/261] refac: refactory node_manager --- src/manager/node_manager.cpp | 7 ++----- src/rs_driver | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/manager/node_manager.cpp b/src/manager/node_manager.cpp index ec0ac1e5..ed7c6b8b 100644 --- a/src/manager/node_manager.cpp +++ b/src/manager/node_manager.cpp @@ -67,11 +67,6 @@ void NodeManager::init(const YAML::Node& config) { std::shared_ptr source; - //AdapterBase::Ptr recv_ptr; - - // - // Receiver - // switch (msg_source) { case SourceType::MSG_FROM_LIDAR: // online lidar @@ -192,6 +187,8 @@ void NodeManager::init(const YAML::Node& config) dst->init(lidar_config[i]); source->regRecvCallback(dst); } + + sources_.emplace_back(source); } } diff --git a/src/rs_driver b/src/rs_driver index 18d7ea4b..c50fba26 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 18d7ea4bec9c297f30f109ce5a5833924080d1d1 +Subproject commit c50fba26f96d21aea414b74216e9c334a0abe81d From 9971f95042ec2d0c34e7c28cf7dcf7c4ea6fbf23 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 11 Jan 2022 15:50:29 +0800 Subject: [PATCH 074/261] fix: limit packet send queue --- src/adapter/packet_protobuf_adapter.hpp | 17 ++++++++++++++++- src/rs_driver | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/adapter/packet_protobuf_adapter.hpp b/src/adapter/packet_protobuf_adapter.hpp index 7a301705..13047aac 100644 --- a/src/adapter/packet_protobuf_adapter.hpp +++ b/src/adapter/packet_protobuf_adapter.hpp @@ -36,6 +36,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "utility/protobuf_communicator.hpp" #include "msg/proto_msg_translator.h" constexpr size_t PKT_RECEIVE_BUF_SIZE = 2000000; +constexpr size_t PKT_QUEUE_MAX_SIZE = 100; namespace robosense { @@ -107,8 +108,10 @@ inline void PacketProtoAdapter::init(const YAML::Node& config) yamlReadAbort(config["proto"], "difop_send_port", difop_send_port); yamlReadAbort(config["proto"], "msop_recv_port", msop_recv_port); yamlReadAbort(config["proto"], "difop_recv_port", difop_recv_port); + scan_proto_com_ptr_.reset(new ProtoCommunicator); packet_proto_com_ptr_.reset(new ProtoCommunicator); + if (msg_source == MsgSource::MSG_FROM_PROTO_PACKET) { if ((scan_proto_com_ptr_->initReceiver(msop_recv_port) == -1) || @@ -119,6 +122,7 @@ inline void PacketProtoAdapter::init(const YAML::Node& config) } send_packet_proto = false; } + if (send_packet_proto) { if ((scan_proto_com_ptr_->initSender(msop_send_port, packet_send_ip) == -1) || @@ -166,6 +170,11 @@ inline void PacketProtoAdapter::regRecvCallback(const std::function PKT_QUEUE_MAX_SIZE) + { + scan_send_queue_.clear(); + } + scan_send_queue_.push(msg); if (scan_send_queue_.is_task_finished_.load()) { @@ -176,6 +185,11 @@ inline void PacketProtoAdapter::sendScan(const ScanMsg& msg) inline void PacketProtoAdapter::sendPacket(const PacketMsg& msg) { + if (packet_send_queue_.size() > PKT_QUEUE_MAX_SIZE) + { + packet_send_queue_.clear(); + } + packet_send_queue_.push(msg); if (packet_send_queue_.is_task_finished_.load()) { @@ -258,6 +272,7 @@ inline void PacketProtoAdapter::sendMsop() RS_WARNING << "Msop packets Protobuf sending error" << RS_REND; } } + scan_send_queue_.is_task_finished_.store(true); } @@ -322,4 +337,4 @@ inline void PacketProtoAdapter::sendDifop() } // namespace lidar } // namespace robosense -#endif // PROTO_FOUND \ No newline at end of file +#endif // PROTO_FOUND diff --git a/src/rs_driver b/src/rs_driver index 8f639e0a..3b9f0f85 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 8f639e0af14a0d64e66bccb05bb45ca0796f5cd5 +Subproject commit 3b9f0f857b66874e22779cde4b233ac6e55bd3f6 From f411e76759b03947b41b2a400aaf0f10c09d14bb Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 12 Jan 2022 10:30:56 +0800 Subject: [PATCH 075/261] refac: tested pcap file --- config/config.yaml | 5 +++-- src/manager/node_manager.cpp | 4 ++++ src/rs_driver | 2 +- src/source/source_driver.hpp | 15 ++++++++------- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 3e6b48cf..4c8fedef 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -9,15 +9,16 @@ common: send_point_cloud_ros: true #true: Send point cloud through ROS or ROS2 send_packet_proto: false #true: Send packets through Protobuf-UDP send_point_cloud_proto: false #true: Send point cloud through Protobuf-UDP - pcap_path: /home/robosense/lidar.pcap #The path of pcap file lidar: - driver: - lidar_type: RS128 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RS80, RS128, RSM1 + lidar_type: RS32 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RS80, RS128, RSM1 frame_id: /rslidar #Frame id of message msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar start_angle: 0 #Start angle of point cloud end_angle: 360 #End angle of point cloud + pcap_path: /mnt/share/pcap/RS32/Rs32.pcap #The path of pcap file + wait_for_difop: true min_distance: 0.2 #Minimum distance of point cloud max_distance: 200 #Maximum distance of point cloud use_lidar_clock: false #True--Use the lidar clock as the message timestamp diff --git a/src/manager/node_manager.cpp b/src/manager/node_manager.cpp index ed7c6b8b..18865a25 100644 --- a/src/manager/node_manager.cpp +++ b/src/manager/node_manager.cpp @@ -197,7 +197,9 @@ void NodeManager::start() for (auto& iter : sources_) { if (iter != nullptr) + { iter->start(); + } } } @@ -206,7 +208,9 @@ void NodeManager::stop() for (auto& iter : sources_) { if (iter != nullptr) + { iter->stop(); + } } } diff --git a/src/rs_driver b/src/rs_driver index c50fba26..351a2884 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit c50fba26f96d21aea414b74216e9c334a0abe81d +Subproject commit 351a2884aee95f04672f007a3efcea7145c22584 diff --git a/src/source/source_driver.hpp b/src/source/source_driver.hpp index 09a772d1..e94c26b6 100644 --- a/src/source/source_driver.hpp +++ b/src/source/source_driver.hpp @@ -64,13 +64,6 @@ class SourceDriver : public Source inline void SourceDriver::init(SourceType src_type, const YAML::Node& config) { - point_cloud_.reset (new LidarPointCloudMsg); - driver_ptr_.reset(new lidar::LidarDriver()); - driver_ptr_->regRecvCallback(std::bind(&SourceDriver::getPointCloud, this), - std::bind(&SourceDriver::putPointCloud, this, std::placeholders::_1)); - driver_ptr_->regExceptionCallback( - std::bind(&SourceDriver::putException, this, std::placeholders::_1)); - YAML::Node driver_config = yamlSubNodeAbort(config, "driver"); lidar::RSDriverParam driver_param; @@ -124,6 +117,14 @@ inline void SourceDriver::init(SourceType src_type, const YAML::Node& config) } driver_param.print(); + + point_cloud_.reset(new LidarPointCloudMsg); + driver_ptr_.reset(new lidar::LidarDriver()); + driver_ptr_->regRecvCallback(std::bind(&SourceDriver::getPointCloud, this), + std::bind(&SourceDriver::putPointCloud, this, std::placeholders::_1)); + driver_ptr_->regExceptionCallback( + std::bind(&SourceDriver::putException, this, std::placeholders::_1)); + if (!driver_ptr_->init(driver_param)) { RS_ERROR << "Driver Initialize Error...." << RS_REND; From 648b01d7c9d88167fd3007bff22d1f5b5154c183 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 12 Jan 2022 15:09:50 +0800 Subject: [PATCH 076/261] feat: add rslidarPacket definitions --- src/msg/ros_msg/rslidarPacket.h | 238 ++++++++++++++++++++++++++++++ src/msg/ros_msg/rslidarPacket.msg | 4 + 2 files changed, 242 insertions(+) create mode 100644 src/msg/ros_msg/rslidarPacket.h create mode 100644 src/msg/ros_msg/rslidarPacket.msg diff --git a/src/msg/ros_msg/rslidarPacket.h b/src/msg/ros_msg/rslidarPacket.h new file mode 100644 index 00000000..ff2d44dd --- /dev/null +++ b/src/msg/ros_msg/rslidarPacket.h @@ -0,0 +1,238 @@ +// Generated by gencpp from file rslidar_sdk/rslidarPacket.msg +// DO NOT EDIT! + + +#ifndef RSLIDAR_SDK_MESSAGE_RSLIDARPACKET_H +#define RSLIDAR_SDK_MESSAGE_RSLIDARPACKET_H + + +#include +#include +#include + +#include +#include +#include +#include + +#include + +namespace rslidar_sdk +{ +template +struct rslidarPacket_ +{ + typedef rslidarPacket_ Type; + + rslidarPacket_() + : header() + , is_difop(0) + , is_frame_begin(0) + , data() { + } + rslidarPacket_(const ContainerAllocator& _alloc) + : header(_alloc) + , is_difop(0) + , is_frame_begin(0) + , data(_alloc) { + (void)_alloc; + } + + + + typedef ::std_msgs::Header_ _header_type; + _header_type header; + + typedef uint8_t _is_difop_type; + _is_difop_type is_difop; + + typedef uint8_t _is_frame_begin_type; + _is_frame_begin_type is_frame_begin; + + typedef std::vector::other > _data_type; + _data_type data; + + + + + + typedef boost::shared_ptr< ::rslidar_sdk::rslidarPacket_ > Ptr; + typedef boost::shared_ptr< ::rslidar_sdk::rslidarPacket_ const> ConstPtr; + +}; // struct rslidarPacket_ + +typedef ::rslidar_sdk::rslidarPacket_ > rslidarPacket; + +typedef boost::shared_ptr< ::rslidar_sdk::rslidarPacket > rslidarPacketPtr; +typedef boost::shared_ptr< ::rslidar_sdk::rslidarPacket const> rslidarPacketConstPtr; + +// constants requiring out of line definition + + + +template +std::ostream& operator<<(std::ostream& s, const ::rslidar_sdk::rslidarPacket_ & v) +{ +ros::message_operations::Printer< ::rslidar_sdk::rslidarPacket_ >::stream(s, "", v); +return s; +} + +} // namespace rslidar_sdk + +namespace ros +{ +namespace message_traits +{ + + + +// BOOLTRAITS {'IsFixedSize': False, 'IsMessage': True, 'HasHeader': True} +// {'std_msgs': ['/opt/ros/kinetic/share/std_msgs/cmake/../msg'], 'rslidar_sdk': ['/home/ron/dev/catkin_ws/src/rslidar_sdk/msg']} + +// !!!!!!!!!!! ['__class__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_parsed_fields', 'constants', 'fields', 'full_name', 'has_header', 'header_present', 'names', 'package', 'parsed_fields', 'short_name', 'text', 'types'] + + + + +template +struct IsFixedSize< ::rslidar_sdk::rslidarPacket_ > + : FalseType + { }; + +template +struct IsFixedSize< ::rslidar_sdk::rslidarPacket_ const> + : FalseType + { }; + +template +struct IsMessage< ::rslidar_sdk::rslidarPacket_ > + : TrueType + { }; + +template +struct IsMessage< ::rslidar_sdk::rslidarPacket_ const> + : TrueType + { }; + +template +struct HasHeader< ::rslidar_sdk::rslidarPacket_ > + : TrueType + { }; + +template +struct HasHeader< ::rslidar_sdk::rslidarPacket_ const> + : TrueType + { }; + + +template +struct MD5Sum< ::rslidar_sdk::rslidarPacket_ > +{ + static const char* value() + { + return "4b1cc155a9097c0cb935a7abf46d6eef"; + } + + static const char* value(const ::rslidar_sdk::rslidarPacket_&) { return value(); } + static const uint64_t static_value1 = 0x4b1cc155a9097c0cULL; + static const uint64_t static_value2 = 0xb935a7abf46d6eefULL; +}; + +template +struct DataType< ::rslidar_sdk::rslidarPacket_ > +{ + static const char* value() + { + return "rslidar_sdk/rslidarPacket"; + } + + static const char* value(const ::rslidar_sdk::rslidarPacket_&) { return value(); } +}; + +template +struct Definition< ::rslidar_sdk::rslidarPacket_ > +{ + static const char* value() + { + return "Header header\n\ +uint8 is_difop\n\ +uint8 is_frame_begin\n\ +uint8[] data\n\ +\n\ +================================================================================\n\ +MSG: std_msgs/Header\n\ +# Standard metadata for higher-level stamped data types.\n\ +# This is generally used to communicate timestamped data \n\ +# in a particular coordinate frame.\n\ +# \n\ +# sequence ID: consecutively increasing ID \n\ +uint32 seq\n\ +#Two-integer timestamp that is expressed as:\n\ +# * stamp.sec: seconds (stamp_secs) since epoch (in Python the variable is called 'secs')\n\ +# * stamp.nsec: nanoseconds since stamp_secs (in Python the variable is called 'nsecs')\n\ +# time-handling sugar is provided by the client library\n\ +time stamp\n\ +#Frame this data is associated with\n\ +# 0: no frame\n\ +# 1: global frame\n\ +string frame_id\n\ +"; + } + + static const char* value(const ::rslidar_sdk::rslidarPacket_&) { return value(); } +}; + +} // namespace message_traits +} // namespace ros + +namespace ros +{ +namespace serialization +{ + + template struct Serializer< ::rslidar_sdk::rslidarPacket_ > + { + template inline static void allInOne(Stream& stream, T m) + { + stream.next(m.header); + stream.next(m.is_difop); + stream.next(m.is_frame_begin); + stream.next(m.data); + } + + ROS_DECLARE_ALLINONE_SERIALIZER + }; // struct rslidarPacket_ + +} // namespace serialization +} // namespace ros + +namespace ros +{ +namespace message_operations +{ + +template +struct Printer< ::rslidar_sdk::rslidarPacket_ > +{ + template static void stream(Stream& s, const std::string& indent, const ::rslidar_sdk::rslidarPacket_& v) + { + s << indent << "header: "; + s << std::endl; + Printer< ::std_msgs::Header_ >::stream(s, indent + " ", v.header); + s << indent << "is_difop: "; + Printer::stream(s, indent + " ", v.is_difop); + s << indent << "is_frame_begin: "; + Printer::stream(s, indent + " ", v.is_frame_begin); + s << indent << "data[]" << std::endl; + for (size_t i = 0; i < v.data.size(); ++i) + { + s << indent << " data[" << i << "]: "; + Printer::stream(s, indent + " ", v.data[i]); + } + } +}; + +} // namespace message_operations +} // namespace ros + +#endif // RSLIDAR_SDK_MESSAGE_RSLIDARPACKET_H diff --git a/src/msg/ros_msg/rslidarPacket.msg b/src/msg/ros_msg/rslidarPacket.msg new file mode 100644 index 00000000..53e61424 --- /dev/null +++ b/src/msg/ros_msg/rslidarPacket.msg @@ -0,0 +1,4 @@ +Header header +uint8 is_difop +uint8 is_frame_begin +uint8[] data From 93fe32073741bd205ef3b45225b9a0220f994989 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 12 Jan 2022 17:09:48 +0800 Subject: [PATCH 077/261] refac: refactory packet ros --- config/config.yaml | 4 +-- src/manager/node_manager.cpp | 4 --- src/rs_driver | 2 +- src/source/source_packet_ros.hpp | 54 +++++++++++++++++--------------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 4c8fedef..d4289c24 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -1,5 +1,5 @@ common: - msg_source: 1 #0: not use Lidar + msg_source: 2 #0: not use Lidar #1: packet message comes from online Lidar #2: packet message comes from ROS or ROS2 #3: packet message comes from Pcap file @@ -17,12 +17,12 @@ lidar: difop_port: 7788 #Difop port of lidar start_angle: 0 #Start angle of point cloud end_angle: 360 #End angle of point cloud - pcap_path: /mnt/share/pcap/RS32/Rs32.pcap #The path of pcap file wait_for_difop: true min_distance: 0.2 #Minimum distance of point cloud max_distance: 200 #Maximum distance of point cloud use_lidar_clock: false #True--Use the lidar clock as the message timestamp #False-- Use the system clock as the timestamp + pcap_path: /mnt/share/pcap/RS32/Rs32.pcap #The path of pcap file ros: ros_recv_packet_topic: /rslidar_packets #Topic used to receive lidar packets from ROS ros_send_packet_topic: /rslidar_packets #Topic used to send lidar packets through ROS diff --git a/src/manager/node_manager.cpp b/src/manager/node_manager.cpp index 18865a25..24fa14a9 100644 --- a/src/manager/node_manager.cpp +++ b/src/manager/node_manager.cpp @@ -86,8 +86,6 @@ void NodeManager::init(const YAML::Node& config) RS_INFO << "------------------------------------------------------" << RS_REND; RS_INFO << "Receive Packets From : ROS" << RS_REND; RS_INFO << "Msop Topic: " << lidar_config[i]["ros"]["ros_recv_packet_topic"].as() << RS_REND; - RS_INFO << "Difop Topic: " << lidar_config[i]["ros"]["ros_recv_packet_topic"].as() << "_difop" - << RS_REND; RS_INFO << "------------------------------------------------------" << RS_REND; source = std::make_shared(); @@ -139,8 +137,6 @@ void NodeManager::init(const YAML::Node& config) RS_DEBUG << "------------------------------------------------------" << RS_REND; RS_DEBUG << "Send Packets To : ROS" << RS_REND; RS_DEBUG << "Msop Topic: " << lidar_config[i]["ros"]["ros_send_packet_topic"].as() << RS_REND; - RS_DEBUG << "Difop Topic: " << lidar_config[i]["ros"]["ros_send_packet_topic"].as() << "_difop" - << RS_REND; RS_DEBUG << "------------------------------------------------------" << RS_REND; std::shared_ptr dst = std::make_shared(); diff --git a/src/rs_driver b/src/rs_driver index 351a2884..0bdc40aa 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 351a2884aee95f04672f007a3efcea7145c22584 +Subproject commit 0bdc40aa620dd5921f0e091ac86f95ab23609935 diff --git a/src/source/source_packet_ros.hpp b/src/source/source_packet_ros.hpp index deaa2cda..c1b710b1 100644 --- a/src/source/source_packet_ros.hpp +++ b/src/source/source_packet_ros.hpp @@ -33,7 +33,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include "source/source_driver.hpp" -#include "msg/ros_msg/lidar_packet_ros.h" +#include "msg/ros_msg/rslidarPacket.h" #ifdef ROS_FOUND #include @@ -43,29 +43,30 @@ namespace robosense namespace lidar { -inline Packet toRsMsg(const rslidar_msgs::rslidarPacket& ros_msg) +inline Packet toRsMsg(const rslidar_sdk::rslidarPacket& ros_msg) { - Packet rs_msg(1500); - //rs_msg.timestamp = ros_msg.header.stamp.toSec(); - //rs_msg.seq = ros_msg.header.seq; - //rs_msg.type = ros_msg.header.type; - //rs_msg.frame_id = ros_msg.header.frame_id; - for (size_t i = 0; i < 1500; i++) + Packet rs_msg; + rs_msg.timestamp = ros_msg.header.stamp.toSec(); + rs_msg.seq = ros_msg.header.seq; + rs_msg.is_difop = ros_msg.is_difop; + rs_msg.is_frame_begin = ros_msg.is_frame_begin; + + for (size_t i = 0; i < ros_msg.data.size(); i++) { - rs_msg.buf_[i] = ros_msg.data[i]; + rs_msg.buf_.emplace_back(ros_msg.data[i]); } - return std::move(rs_msg); + + return rs_msg; } class SourcePacketRos : public SourceDriver { -public: - +public: virtual void init(SourceType src_type, const YAML::Node& config); private: - void putPacket(const rslidar_msgs::rslidarPacket& msg); + void putPacket(const rslidar_sdk::rslidarPacket& msg); std::unique_ptr nh_; ros::Subscriber pkt_sub_; @@ -81,25 +82,28 @@ void SourcePacketRos::init(SourceType src_type, const YAML::Node& config) nh_ = std::unique_ptr(new ros::NodeHandle()); pkt_sub_ = nh_->subscribe(ros_recv_topic, 1, &SourcePacketRos::putPacket, this); -} - -void SourcePacketRos::putPacket(const rslidar_msgs::rslidarPacket& msg) +} +void SourcePacketRos::putPacket(const rslidar_sdk::rslidarPacket& msg) { driver_ptr_->decodePacket(toRsMsg(msg)); } -inline rslidar_msgs::rslidarPacket toRosMsg(const Packet& rs_msg) +inline rslidar_sdk::rslidarPacket toRosMsg(const Packet& rs_msg) { - rslidar_msgs::rslidarPacket ros_msg; - //rs_msg.timestamp = ros_msg.header.stamp.toSec(); - //rs_msg.seq = ros_msg.header.seq; - //rs_msg.type = ros_msg.header.type; - //rs_msg.frame_id = ros_msg.header.frame_id; + rslidar_sdk::rslidarPacket ros_msg; + ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); + ros_msg.header.stamp.nsec = (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); + ros_msg.header.seq = rs_msg.seq; + ros_msg.header.frame_id = "/rslidar"; + ros_msg.is_difop = rs_msg.is_difop; + ros_msg.is_frame_begin = rs_msg.is_frame_begin; + for (size_t i = 0; i < rs_msg.buf_.size(); i++) { - ros_msg.data[i] = rs_msg.buf_[i]; + ros_msg.data.emplace_back(rs_msg.buf_[i]); } - return std::move(ros_msg); + + return ros_msg; } class DestinationPacketRos : public DestinationPacket @@ -123,7 +127,7 @@ inline void DestinationPacketRos::init(const YAML::Node& config) ros_send_topic, "rslidar_packets"); nh_ = std::unique_ptr(new ros::NodeHandle()); - pub_ = nh_->advertise(ros_send_topic, 10); + pub_ = nh_->advertise(ros_send_topic, 10); } inline void DestinationPacketRos::sendPacket(const Packet& msg) From 5b434b492bf62ecf95ea271bdcec6e734df1370b Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 12 Jan 2022 17:30:50 +0800 Subject: [PATCH 078/261] refac: refactory --- config/config.yaml | 6 +++--- src/rs_driver | 2 +- src/source/source_packet_ros.hpp | 10 +++++++--- src/source/source_pointcloud_ros.hpp | 10 +++++++--- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index d4289c24..cae9079c 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -1,18 +1,17 @@ common: - msg_source: 2 #0: not use Lidar + msg_source: 3 #0: not use Lidar #1: packet message comes from online Lidar #2: packet message comes from ROS or ROS2 #3: packet message comes from Pcap file #4: packet message comes from Protobuf-UDP #5: point cloud comes from Protobuf-UDP - send_packet_ros: false #true: Send packets through ROS or ROS2(Used to record packet) + send_packet_ros: false #true: Send packets through ROS or ROS2(Used to record packet) send_point_cloud_ros: true #true: Send point cloud through ROS or ROS2 send_packet_proto: false #true: Send packets through Protobuf-UDP send_point_cloud_proto: false #true: Send point cloud through Protobuf-UDP lidar: - driver: lidar_type: RS32 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RS80, RS128, RSM1 - frame_id: /rslidar #Frame id of message msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar start_angle: 0 #Start angle of point cloud @@ -24,6 +23,7 @@ lidar: #False-- Use the system clock as the timestamp pcap_path: /mnt/share/pcap/RS32/Rs32.pcap #The path of pcap file ros: + ros_frame_id: /rslidar #Frame id of message ros_recv_packet_topic: /rslidar_packets #Topic used to receive lidar packets from ROS ros_send_packet_topic: /rslidar_packets #Topic used to send lidar packets through ROS ros_send_point_cloud_topic: /rslidar_points #Topic used to send point cloud through ROS diff --git a/src/rs_driver b/src/rs_driver index 0bdc40aa..56cf0a0e 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 0bdc40aa620dd5921f0e091ac86f95ab23609935 +Subproject commit 56cf0a0e3927fc3ff94900a4cc5d9f6ca550379a diff --git a/src/source/source_packet_ros.hpp b/src/source/source_packet_ros.hpp index c1b710b1..92fcb21f 100644 --- a/src/source/source_packet_ros.hpp +++ b/src/source/source_packet_ros.hpp @@ -88,13 +88,13 @@ void SourcePacketRos::putPacket(const rslidar_sdk::rslidarPacket& msg) driver_ptr_->decodePacket(toRsMsg(msg)); } -inline rslidar_sdk::rslidarPacket toRosMsg(const Packet& rs_msg) +inline rslidar_sdk::rslidarPacket toRosMsg(const Packet& rs_msg, const std::string& frame_id) { rslidar_sdk::rslidarPacket ros_msg; ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); ros_msg.header.stamp.nsec = (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); ros_msg.header.seq = rs_msg.seq; - ros_msg.header.frame_id = "/rslidar"; + ros_msg.header.frame_id = frame_id; ros_msg.is_difop = rs_msg.is_difop; ros_msg.is_frame_begin = rs_msg.is_frame_begin; @@ -118,10 +118,14 @@ class DestinationPacketRos : public DestinationPacket std::unique_ptr nh_; ros::Publisher pub_; + std::string frame_id_; }; inline void DestinationPacketRos::init(const YAML::Node& config) { + yamlRead(config["ros"], + "ros_frame_id", frame_id_, "/rslidar"); + std::string ros_send_topic; yamlRead(config["ros"], "ros_send_packet_topic", ros_send_topic, "rslidar_packets"); @@ -132,7 +136,7 @@ inline void DestinationPacketRos::init(const YAML::Node& config) inline void DestinationPacketRos::sendPacket(const Packet& msg) { - pub_.publish(toRosMsg(msg)); + pub_.publish(toRosMsg(msg, frame_id_)); } } // namespace lidar diff --git a/src/source/source_pointcloud_ros.hpp b/src/source/source_pointcloud_ros.hpp index aed01856..24288567 100644 --- a/src/source/source_pointcloud_ros.hpp +++ b/src/source/source_pointcloud_ros.hpp @@ -45,13 +45,13 @@ namespace robosense namespace lidar { -inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) +inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const std::string& frame_id) { sensor_msgs::PointCloud2 ros_msg; pcl::toROSMsg(rs_msg, ros_msg); - ros_msg.header.frame_id = rs_msg.frame_id; ros_msg.header.stamp = ros_msg.header.stamp.fromSec(rs_msg.timestamp); ros_msg.header.seq = rs_msg.seq; + ros_msg.header.frame_id = frame_id; return std::move(ros_msg); } @@ -66,10 +66,14 @@ class DestinationPointCloudRos : public DestinationPointCloud private: std::shared_ptr nh_; ros::Publisher pub_; + std::string frame_id_; }; inline void DestinationPointCloudRos::init(const YAML::Node& config) { + yamlRead(config["ros"], + "ros_frame_id", frame_id_, "/rslidar"); + std::string ros_send_topic; yamlRead(config["ros"], "ros_send_point_cloud_topic", ros_send_topic, "rslidar_points"); @@ -80,7 +84,7 @@ inline void DestinationPointCloudRos::init(const YAML::Node& config) inline void DestinationPointCloudRos::sendPointCloud(const LidarPointCloudMsg& msg) { - pub_.publish(toRosMsg(msg)); + pub_.publish(toRosMsg(msg, frame_id_)); } } // namespace lidar From 580b6857903e2d120f5858182bdf3b25c358d77b Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 12 Jan 2022 17:59:43 +0800 Subject: [PATCH 079/261] refac: refactory node_manager --- src/manager/node_manager.cpp | 14 +++++++------- src/source/source.hpp | 9 ++++++++- src/source/source_driver.hpp | 13 ++++++++++--- src/source/source_packet_proto.hpp | 13 ++++++++++--- src/source/source_packet_ros.hpp | 14 +++++++++++--- src/source/source_pointcloud_proto.hpp | 11 +++++++++-- 6 files changed, 55 insertions(+), 19 deletions(-) diff --git a/src/manager/node_manager.cpp b/src/manager/node_manager.cpp index 24fa14a9..8495c40c 100644 --- a/src/manager/node_manager.cpp +++ b/src/manager/node_manager.cpp @@ -77,8 +77,8 @@ void NodeManager::init(const YAML::Node& config) RS_INFO << "Difop Port: " << lidar_config[i]["driver"]["difop_port"].as() << RS_REND; RS_INFO << "------------------------------------------------------" << RS_REND; - source = std::make_shared(); - source->init((SourceType)msg_source, lidar_config[i]); + source = std::make_shared(SourceType::MSG_FROM_LIDAR); + source->init(lidar_config[i]); break; case SourceType::MSG_FROM_ROS_PACKET: // pkt from ros @@ -89,7 +89,7 @@ void NodeManager::init(const YAML::Node& config) RS_INFO << "------------------------------------------------------" << RS_REND; source = std::make_shared(); - source->init((SourceType)msg_source, lidar_config[i]); + source->init(lidar_config[i]); break; case SourceType::MSG_FROM_PCAP: // pcap @@ -100,8 +100,8 @@ void NodeManager::init(const YAML::Node& config) RS_INFO << "Difop Port: " << lidar_config[i]["driver"]["difop_port"].as() << RS_REND; RS_INFO << "------------------------------------------------------" << RS_REND; - source = std::make_shared(); - source->init((SourceType)msg_source, lidar_config[i]); + source = std::make_shared(SourceType::MSG_FROM_PCAP); + source->init(lidar_config[i]); break; case SourceType::MSG_FROM_PROTO_PACKET: // packets from proto @@ -113,7 +113,7 @@ void NodeManager::init(const YAML::Node& config) RS_INFO << "------------------------------------------------------" << RS_REND; source = std::make_shared(); - source->init((SourceType)msg_source, lidar_config[i]); + source->init(lidar_config[i]); break; case SourceType::MSG_FROM_PROTO_POINTCLOUD: // point cloud from proto @@ -124,7 +124,7 @@ void NodeManager::init(const YAML::Node& config) RS_INFO << "------------------------------------------------------" << RS_REND; source = std::make_shared(); - source->init((SourceType)msg_source, lidar_config[i]); + source->init(lidar_config[i]); break; default: diff --git a/src/source/source.hpp b/src/source/source.hpp index c5420d38..c29229d6 100644 --- a/src/source/source.hpp +++ b/src/source/source.hpp @@ -81,22 +81,29 @@ class Source public: typedef std::shared_ptr Ptr; - virtual void init(SourceType src_type, const YAML::Node& config) {} + virtual void init(const YAML::Node& config) {} virtual void start() {} virtual void stop() {} virtual void regRecvCallback(DestinationPointCloud::Ptr dst); virtual void regRecvCallback(DestinationPacket::Ptr dst); virtual ~Source() = default; + Source(SourceType src_type); protected: void sendPacket(const Packet& msg); void sendPointCloud(std::shared_ptr msg); + SourceType src_type_; std::vector pc_cb_vec_; std::vector pkt_cb_vec_; }; +inline Source::Source(SourceType src_type) + : src_type_(src_type) +{ +} + inline void Source::regRecvCallback(DestinationPacket::Ptr dst) { pkt_cb_vec_.emplace_back(dst); diff --git a/src/source/source_driver.hpp b/src/source/source_driver.hpp index e94c26b6..d8cdd0f2 100644 --- a/src/source/source_driver.hpp +++ b/src/source/source_driver.hpp @@ -45,12 +45,14 @@ class SourceDriver : public Source { public: - virtual void init(SourceType src, const YAML::Node& config); + virtual void init(const YAML::Node& config); virtual void start(); virtual void stop(); virtual void regRecvCallback(DestinationPacket::Ptr dst); virtual ~SourceDriver(); + SourceDriver(SourceType src_type); + protected: std::shared_ptr getPointCloud(void); @@ -62,7 +64,12 @@ class SourceDriver : public Source std::shared_ptr> driver_ptr_; }; -inline void SourceDriver::init(SourceType src_type, const YAML::Node& config) +SourceDriver::SourceDriver(SourceType src_type) + : Source(src_type) +{ +} + +inline void SourceDriver::init(const YAML::Node& config) { YAML::Node driver_config = yamlSubNodeAbort(config, "driver"); lidar::RSDriverParam driver_param; @@ -103,7 +110,7 @@ inline void SourceDriver::init(SourceType src_type, const YAML::Node& config) yamlRead(driver_config, "cut_angle", driver_param.decoder_param.split_angle, 0); yamlRead(driver_config, "num_pkts_split", driver_param.decoder_param.num_blks_split, 0); - switch (src_type) + switch (src_type_) { case SourceType::MSG_FROM_LIDAR: driver_param.input_type = InputType::ONLINE_LIDAR; diff --git a/src/source/source_packet_proto.hpp b/src/source/source_packet_proto.hpp index 0ece3959..a5f59fd3 100644 --- a/src/source/source_packet_proto.hpp +++ b/src/source/source_packet_proto.hpp @@ -51,10 +51,12 @@ class SourcePacketProto : public SourceDriver { public: - virtual void init(SourceType src_type, const YAML::Node& config); + virtual void init(const YAML::Node& config); virtual void start(); virtual void stop(); + SourcePacketProto(); + private: void recvPacket(); @@ -66,9 +68,14 @@ class SourcePacketProto : public SourceDriver std::thread splice_thread_; }; -void SourcePacketProto::init(SourceType src_type, const YAML::Node& config) +SourcePacketProto::SourcePacketProto() + : SourceDriver(SourceType::MSG_FROM_PROTO_PACKET) +{ +} + +void SourcePacketProto::init(const YAML::Node& config) { - SourceDriver::init(src_type, config); + SourceDriver::init(config); uint16_t packet_recv_port; yamlReadAbort(config["proto"], "packet_recv_port", packet_recv_port); diff --git a/src/source/source_packet_ros.hpp b/src/source/source_packet_ros.hpp index 92fcb21f..7ada335b 100644 --- a/src/source/source_packet_ros.hpp +++ b/src/source/source_packet_ros.hpp @@ -62,7 +62,10 @@ inline Packet toRsMsg(const rslidar_sdk::rslidarPacket& ros_msg) class SourcePacketRos : public SourceDriver { public: - virtual void init(SourceType src_type, const YAML::Node& config); + + virtual void init(const YAML::Node& config); + + SourcePacketRos(); private: @@ -72,9 +75,14 @@ class SourcePacketRos : public SourceDriver ros::Subscriber pkt_sub_; }; -void SourcePacketRos::init(SourceType src_type, const YAML::Node& config) +SourcePacketRos::SourcePacketRos() + : SourceDriver(SourceType::MSG_FROM_ROS_PACKET) +{ +} + +void SourcePacketRos::init(const YAML::Node& config) { - SourceDriver::init(src_type, config); + SourceDriver::init(config); std::string ros_recv_topic; yamlRead(config["ros"], "ros_recv_packet_topic", diff --git a/src/source/source_pointcloud_proto.hpp b/src/source/source_pointcloud_proto.hpp index 7bbd8aef..20d1f255 100644 --- a/src/source/source_pointcloud_proto.hpp +++ b/src/source/source_pointcloud_proto.hpp @@ -48,11 +48,13 @@ class SourcePointCloudProto : public Source { public: - virtual void init(SourceType src_type, const YAML::Node& config); + virtual void init(const YAML::Node& config); virtual void start(); virtual void stop(); virtual ~SourcePointCloudProto(); + SourcePointCloudProto(); + private: void recvPointCloud(); @@ -65,7 +67,12 @@ class SourcePointCloudProto : public Source int new_frmnum_; }; -inline void SourcePointCloudProto::init(SourceType src_type, const YAML::Node& config) +SourcePointCloudProto::SourcePointCloudProto() + : Source(SourceType::MSG_FROM_PROTO_POINTCLOUD) +{ +} + +inline void SourcePointCloudProto::init(const YAML::Node& config) { uint16_t point_cloud_recv_port; yamlReadAbort(config["proto"], "point_cloud_recv_port", point_cloud_recv_port); From 574c53362429c9aa10600d1dc2746206e386beb4 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 13 Jan 2022 10:04:05 +0800 Subject: [PATCH 080/261] refac: refac soure_packet_proto --- config/config.yaml | 8 +-- src/source/source_packet_proto.hpp | 93 ++++++++++++++++++++++++++---- 2 files changed, 85 insertions(+), 16 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index cae9079c..da8054bc 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -23,18 +23,16 @@ lidar: #False-- Use the system clock as the timestamp pcap_path: /mnt/share/pcap/RS32/Rs32.pcap #The path of pcap file ros: - ros_frame_id: /rslidar #Frame id of message + ros_frame_id: /rslidar #Frame id of packet message and point cloud message ros_recv_packet_topic: /rslidar_packets #Topic used to receive lidar packets from ROS ros_send_packet_topic: /rslidar_packets #Topic used to send lidar packets through ROS ros_send_point_cloud_topic: /rslidar_points #Topic used to send point cloud through ROS proto: point_cloud_recv_port: 60021 #Port number used for receiving point cloud point_cloud_send_port: 60021 #Port number which the point cloud will be send to - msop_recv_port: 60022 #Port number used for receiving lidar msop packets - msop_send_port: 60022 #Port number which the msop packets will be send to - difop_recv_port: 60023 #Port number used for receiving lidar difop packets - difop_send_port: 60023 #Port number which the difop packets will be send to point_cloud_send_ip: 127.0.0.1 #Ip address which the point cloud will be send to + packet_recv_port: 60022 #Port number used to receiving lidar packets + packet_send_port: 60022 #Port number which the lidar packets will be send to packet_send_ip: 127.0.0.1 #Ip address which the lidar packets will be send to diff --git a/src/source/source_packet_proto.hpp b/src/source/source_packet_proto.hpp index a5f59fd3..e39245cc 100644 --- a/src/source/source_packet_proto.hpp +++ b/src/source/source_packet_proto.hpp @@ -36,6 +36,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //#include "utility/protobuf_communicator.hpp" #include "rs_driver/utility/sync_queue.hpp" +#include +#include + #ifdef PROTO_FOUND constexpr size_t PKT_RECEIVE_BUF_SIZE = 2000000; @@ -59,6 +62,8 @@ class SourcePacketProto : public SourceDriver private: + int initSocket(uint16_t port); + void recvPacket(); void splicePacket(); @@ -66,6 +71,7 @@ class SourcePacketProto : public SourceDriver //SyncQueue pkt_queue_; std::thread recv_thread_; std::thread splice_thread_; + int fd_; }; SourcePacketProto::SourcePacketProto() @@ -73,6 +79,49 @@ SourcePacketProto::SourcePacketProto() { } +inline int SourcePacketProto::initSocket(uint16_t port) +{ + int fd; + int flags; + int ret; + + fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) + { + std::cerr << "socket: " << std::strerror(errno) << std::endl; + goto failSocket; + } + + struct sockaddr_in host_addr; + memset(&host_addr, 0, sizeof(host_addr)); + host_addr.sin_family = AF_INET; + host_addr.sin_port = htons(port); + host_addr.sin_addr.s_addr = INADDR_ANY; + ret = bind(fd, (struct sockaddr*)&host_addr, sizeof(host_addr)); + if (ret < 0) + { + std::cerr << "bind: " << std::strerror(errno) << std::endl; + goto failBind; + } + + flags = fcntl(fd, F_GETFL, 0); + ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK); + if (ret < 0) + { + std::cerr << "setsockopt: " << std::strerror(errno) << std::endl; + goto failNonBlock; + } + + fd_ = fd; + return 0; + +failNonBlock: +failBind: + close(fd); +failSocket: + return -1; +} + void SourcePacketProto::init(const YAML::Node& config) { SourceDriver::init(config); @@ -151,30 +200,52 @@ class DestinationPacketProto : public DestinationPacket private: + int initSocket(uint16_t dst_port, const std::string& dst_ip); + void internSendPacket(); - //std::unique_ptr packet_proto_com_ptr_; - //SyncQueue pkt_queue_; + SyncQueue pkt_queue_; std::thread send_thread_; bool to_exit_; + int fd_; + struct sockaddr_in dst_addr_; }; + inline void DestinationPacketProto::init(const YAML::Node& config) { + uint16_t packet_send_port; + yamlReadAbort(config["proto"], "packet_send_port", packet_send_port); std::string packet_send_ip; yamlReadAbort(config["proto"], "packet_send_ip", packet_send_ip); - std::string packet_send_port; - yamlReadAbort(config["proto"], "packet_send_port", packet_send_port); -#if 0 - packet_proto_com_ptr_.reset(new ProtoCommunicator); - int ret = packet_proto_com_ptr_->initSender(packet_send_port, packet_send_ip); - if (ret < -1) + if (initSocket(packet_send_port, packet_send_ip) < 0) { - RS_ERROR << "LidarPacketsReceiver: Create UDP Sender Socket failed ! " << RS_REND; + RS_ERROR << "DestinationPacketProto: failed to create UDP sender socket." << RS_REND; exit(-1); } -#endif +} + +int DestinationPacketProto::initSocket(uint16_t dst_port, const std::string& dst_ip) +{ + struct sockaddr_in dst_addr = {0}; + dst_addr.sin_family = AF_INET; + dst_addr.sin_port = htons(dst_port); + dst_addr.sin_addr.s_addr = inet_addr(dst_ip.c_str()); + + int fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) + { + std::cerr << "socket: " << std::strerror(errno) << std::endl; + goto failSocket; + } + + memcpy (&dst_addr_, &dst_addr, sizeof(dst_addr)); + fd_ = fd; + return 0; + +failSocket: + return -1; } inline void DestinationPacketProto::start() @@ -195,7 +266,7 @@ inline DestinationPacketProto::~DestinationPacketProto() inline void DestinationPacketProto::sendPacket(const Packet& msg) { - //pkt_queue_.push(msg); + pkt_queue_.push(msg); } inline void DestinationPacketProto::internSendPacket() From d41838ddbbf83163fa0c2965df54c2dff2ff31ae Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 13 Jan 2022 14:27:57 +0800 Subject: [PATCH 081/261] refac: disalbe protobuf fun fow now --- config/config.yaml | 14 +++++++------- src/manager/node_manager.cpp | 28 ++++++++++++++++------------ 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index da8054bc..d4fad989 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -27,13 +27,13 @@ lidar: ros_recv_packet_topic: /rslidar_packets #Topic used to receive lidar packets from ROS ros_send_packet_topic: /rslidar_packets #Topic used to send lidar packets through ROS ros_send_point_cloud_topic: /rslidar_points #Topic used to send point cloud through ROS - proto: - point_cloud_recv_port: 60021 #Port number used for receiving point cloud - point_cloud_send_port: 60021 #Port number which the point cloud will be send to - point_cloud_send_ip: 127.0.0.1 #Ip address which the point cloud will be send to - packet_recv_port: 60022 #Port number used to receiving lidar packets - packet_send_port: 60022 #Port number which the lidar packets will be send to - packet_send_ip: 127.0.0.1 #Ip address which the lidar packets will be send to + #proto: + # point_cloud_recv_port: 60021 #Port number used for receiving point cloud + # point_cloud_send_port: 60021 #Port number which the point cloud will be send to + # point_cloud_send_ip: 127.0.0.1 #Ip address which the point cloud will be send to + # packet_recv_port: 60022 #Port number used to receiving lidar packets + # packet_send_port: 60022 #Port number which the lidar packets will be send to + # packet_send_ip: 127.0.0.1 #Ip address which the lidar packets will be send to diff --git a/src/manager/node_manager.cpp b/src/manager/node_manager.cpp index 8495c40c..613d6df1 100644 --- a/src/manager/node_manager.cpp +++ b/src/manager/node_manager.cpp @@ -104,6 +104,7 @@ void NodeManager::init(const YAML::Node& config) source->init(lidar_config[i]); break; +#if 0 case SourceType::MSG_FROM_PROTO_PACKET: // packets from proto RS_INFO << "------------------------------------------------------" << RS_REND; @@ -126,9 +127,10 @@ void NodeManager::init(const YAML::Node& config) source = std::make_shared(); source->init(lidar_config[i]); break; +#endif default: - RS_ERROR << "Wrong LiDAR message source:" << msg_source << "." << RS_REND; + RS_ERROR << "Unsupported LiDAR message source:" << msg_source << "." << RS_REND; exit(-1); } @@ -144,29 +146,30 @@ void NodeManager::init(const YAML::Node& config) source->regRecvCallback(dst); } - if (send_packet_proto) + if (send_point_cloud_ros) { RS_DEBUG << "------------------------------------------------------" << RS_REND; - RS_DEBUG << "Send Packets To : Protobuf-UDP" << RS_REND; - RS_DEBUG << "Msop Port: " << lidar_config[i]["proto"]["msop_send_port"].as() << RS_REND; - RS_DEBUG << "Difop Port: " << lidar_config[i]["proto"]["difop_send_port"].as() << RS_REND; - RS_DEBUG << "Target IP: " << lidar_config[i]["proto"]["packet_send_ip"].as() << RS_REND; + RS_DEBUG << "Send PointCloud To : ROS" << RS_REND; + RS_DEBUG << "PointCloud Topic: " << lidar_config[i]["ros"]["ros_send_point_cloud_topic"].as() + << RS_REND; RS_DEBUG << "------------------------------------------------------" << RS_REND; - std::shared_ptr dst = std::make_shared(); + std::shared_ptr dst = std::make_shared(); dst->init(lidar_config[i]); source->regRecvCallback(dst); } - if (send_point_cloud_ros) +#if 0 + if (send_packet_proto) { RS_DEBUG << "------------------------------------------------------" << RS_REND; - RS_DEBUG << "Send PointCloud To : ROS" << RS_REND; - RS_DEBUG << "PointCloud Topic: " << lidar_config[i]["ros"]["ros_send_point_cloud_topic"].as() - << RS_REND; + RS_DEBUG << "Send Packets To : Protobuf-UDP" << RS_REND; + RS_DEBUG << "Msop Port: " << lidar_config[i]["proto"]["msop_send_port"].as() << RS_REND; + RS_DEBUG << "Difop Port: " << lidar_config[i]["proto"]["difop_send_port"].as() << RS_REND; + RS_DEBUG << "Target IP: " << lidar_config[i]["proto"]["packet_send_ip"].as() << RS_REND; RS_DEBUG << "------------------------------------------------------" << RS_REND; - std::shared_ptr dst = std::make_shared(); + std::shared_ptr dst = std::make_shared(); dst->init(lidar_config[i]); source->regRecvCallback(dst); } @@ -183,6 +186,7 @@ void NodeManager::init(const YAML::Node& config) dst->init(lidar_config[i]); source->regRecvCallback(dst); } +#endif sources_.emplace_back(source); } From 9f884acf0b58aa972cc06a7a05fd607b4acd139e Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 14 Jan 2022 12:08:17 +0800 Subject: [PATCH 082/261] refac: fix packet msg loss problem --- src/rs_driver | 2 +- src/source/source_packet_ros.hpp | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/rs_driver b/src/rs_driver index 56cf0a0e..062906c3 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 56cf0a0e3927fc3ff94900a4cc5d9f6ca550379a +Subproject commit 062906c30286a79a150e1dae794015b0c8908dcd diff --git a/src/source/source_packet_ros.hpp b/src/source/source_packet_ros.hpp index 7ada335b..6f3bd755 100644 --- a/src/source/source_packet_ros.hpp +++ b/src/source/source_packet_ros.hpp @@ -89,7 +89,7 @@ void SourcePacketRos::init(const YAML::Node& config) ros_recv_topic, "rslidar_packets"); nh_ = std::unique_ptr(new ros::NodeHandle()); - pkt_sub_ = nh_->subscribe(ros_recv_topic, 1, &SourcePacketRos::putPacket, this); + pkt_sub_ = nh_->subscribe(ros_recv_topic, 100, &SourcePacketRos::putPacket, this); } void SourcePacketRos::putPacket(const rslidar_sdk::rslidarPacket& msg) { @@ -99,8 +99,7 @@ void SourcePacketRos::putPacket(const rslidar_sdk::rslidarPacket& msg) inline rslidar_sdk::rslidarPacket toRosMsg(const Packet& rs_msg, const std::string& frame_id) { rslidar_sdk::rslidarPacket ros_msg; - ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); - ros_msg.header.stamp.nsec = (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); + ros_msg.header.stamp = ros_msg.header.stamp.fromSec(rs_msg.timestamp); ros_msg.header.seq = rs_msg.seq; ros_msg.header.frame_id = frame_id; ros_msg.is_difop = rs_msg.is_difop; @@ -152,8 +151,7 @@ inline void DestinationPacketRos::sendPacket(const Packet& msg) #endif // ROS_FOUND -#if 0 -//#ifdef ROS2_FOUND +#ifdef ROS2_FOUND #include namespace robosense From 63238195cfb95f2d41507391203663cc823e2eea Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 14 Jan 2022 16:35:00 +0800 Subject: [PATCH 083/261] feat: support XYZIRT --- src/msg/rs_msg/lidar_point_cloud_msg.hpp | 4 ++++ src/rs_driver | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/msg/rs_msg/lidar_point_cloud_msg.hpp b/src/msg/rs_msg/lidar_point_cloud_msg.hpp index 4ceb09f2..c41e7125 100644 --- a/src/msg/rs_msg/lidar_point_cloud_msg.hpp +++ b/src/msg/rs_msg/lidar_point_cloud_msg.hpp @@ -34,5 +34,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "rs_driver/msg/pcl_point_cloud_msg.hpp" +#ifdef POINT_TYPE_XYZIRT +typedef PointCloudT LidarPointCloudMsg; +#else typedef PointCloudT LidarPointCloudMsg; +#endif diff --git a/src/rs_driver b/src/rs_driver index 062906c3..fd424354 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 062906c30286a79a150e1dae794015b0c8908dcd +Subproject commit fd424354ac20eac3eed6f4865c5d6f39208c4a24 From 13a13f7408659fc439d0afa7e443abf6fcd22552 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 17 Jan 2022 16:17:25 +0800 Subject: [PATCH 084/261] refac: format --- src/rs_driver | 2 +- src/source/source_driver.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rs_driver b/src/rs_driver index fd424354..ee202cd5 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit fd424354ac20eac3eed6f4865c5d6f39208c4a24 +Subproject commit ee202cd5d76736b830894e0db3531de135c5dd68 diff --git a/src/source/source_driver.hpp b/src/source/source_driver.hpp index d8cdd0f2..71bd869f 100644 --- a/src/source/source_driver.hpp +++ b/src/source/source_driver.hpp @@ -75,10 +75,10 @@ inline void SourceDriver::init(const YAML::Node& config) lidar::RSDriverParam driver_param; // input related - yamlRead(driver_config, "multi_cast_address", driver_param.input_param.multi_cast_address, "0.0.0.0"); - yamlRead(driver_config, "host_address", driver_param.input_param.host_address, "0.0.0.0"); yamlRead(driver_config, "msop_port", driver_param.input_param.msop_port, 6699); yamlRead(driver_config, "difop_port", driver_param.input_param.difop_port, 7788); + yamlRead(driver_config, "host_address", driver_param.input_param.host_address, "0.0.0.0"); + yamlRead(driver_config, "group_address", driver_param.input_param.group_address, "0.0.0.0"); yamlRead(driver_config, "use_vlan", driver_param.input_param.use_vlan, false); yamlRead(driver_config, "use_someip", driver_param.input_param.use_someip, false); yamlRead(driver_config, "pcap_path", driver_param.input_param.pcap_path, ""); From 7e78f1fd8cbe5177efb4cb5f32608ed18b16035f Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 17 Jan 2022 20:57:39 +0800 Subject: [PATCH 085/261] refac: rename --- src/manager/node_manager.cpp | 8 ++++---- src/rs_driver | 2 +- src/source/source.hpp | 8 ++++---- src/source/source_driver.hpp | 10 +++++----- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/manager/node_manager.cpp b/src/manager/node_manager.cpp index 613d6df1..01dae2cc 100644 --- a/src/manager/node_manager.cpp +++ b/src/manager/node_manager.cpp @@ -143,7 +143,7 @@ void NodeManager::init(const YAML::Node& config) std::shared_ptr dst = std::make_shared(); dst->init(lidar_config[i]); - source->regRecvCallback(dst); + source->regPacketCallback(dst); } if (send_point_cloud_ros) @@ -156,7 +156,7 @@ void NodeManager::init(const YAML::Node& config) std::shared_ptr dst = std::make_shared(); dst->init(lidar_config[i]); - source->regRecvCallback(dst); + source->regPointCloudCallback(dst); } #if 0 @@ -171,7 +171,7 @@ void NodeManager::init(const YAML::Node& config) std::shared_ptr dst = std::make_shared(); dst->init(lidar_config[i]); - source->regRecvCallback(dst); + source->regPacketCallback(dst); } if (send_point_cloud_proto) @@ -184,7 +184,7 @@ void NodeManager::init(const YAML::Node& config) std::shared_ptr dst = std::make_shared(); dst->init(lidar_config[i]); - source->regRecvCallback(dst); + source->regPointCloudCallback(dst); } #endif diff --git a/src/rs_driver b/src/rs_driver index ee202cd5..170df4e0 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit ee202cd5d76736b830894e0db3531de135c5dd68 +Subproject commit 170df4e0300da02ff2e5547c4d6e1f8e8e043699 diff --git a/src/source/source.hpp b/src/source/source.hpp index c29229d6..ddb27aad 100644 --- a/src/source/source.hpp +++ b/src/source/source.hpp @@ -84,8 +84,8 @@ class Source virtual void init(const YAML::Node& config) {} virtual void start() {} virtual void stop() {} - virtual void regRecvCallback(DestinationPointCloud::Ptr dst); - virtual void regRecvCallback(DestinationPacket::Ptr dst); + virtual void regPointCloudCallback(DestinationPointCloud::Ptr dst); + virtual void regPacketCallback(DestinationPacket::Ptr dst); virtual ~Source() = default; Source(SourceType src_type); @@ -104,12 +104,12 @@ inline Source::Source(SourceType src_type) { } -inline void Source::regRecvCallback(DestinationPacket::Ptr dst) +inline void Source::regPacketCallback(DestinationPacket::Ptr dst) { pkt_cb_vec_.emplace_back(dst); } -inline void Source::regRecvCallback(DestinationPointCloud::Ptr dst) +inline void Source::regPointCloudCallback(DestinationPointCloud::Ptr dst) { pc_cb_vec_.emplace_back(dst); } diff --git a/src/source/source_driver.hpp b/src/source/source_driver.hpp index 71bd869f..6fa038df 100644 --- a/src/source/source_driver.hpp +++ b/src/source/source_driver.hpp @@ -48,7 +48,7 @@ class SourceDriver : public Source virtual void init(const YAML::Node& config); virtual void start(); virtual void stop(); - virtual void regRecvCallback(DestinationPacket::Ptr dst); + virtual void regPacketCallback(DestinationPacket::Ptr dst); virtual ~SourceDriver(); SourceDriver(SourceType src_type); @@ -127,7 +127,7 @@ inline void SourceDriver::init(const YAML::Node& config) point_cloud_.reset(new LidarPointCloudMsg); driver_ptr_.reset(new lidar::LidarDriver()); - driver_ptr_->regRecvCallback(std::bind(&SourceDriver::getPointCloud, this), + driver_ptr_->regPointCloudCallback(std::bind(&SourceDriver::getPointCloud, this), std::bind(&SourceDriver::putPointCloud, this, std::placeholders::_1)); driver_ptr_->regExceptionCallback( std::bind(&SourceDriver::putException, this, std::placeholders::_1)); @@ -159,13 +159,13 @@ inline std::shared_ptr SourceDriver::getPointCloud(void) return point_cloud_; } -inline void SourceDriver::regRecvCallback(DestinationPacket::Ptr dst) +inline void SourceDriver::regPacketCallback(DestinationPacket::Ptr dst) { - Source::regRecvCallback(dst); + Source::regPacketCallback(dst); if (pkt_cb_vec_.size() == 1) { - driver_ptr_->regRecvCallback( + driver_ptr_->regPacketCallback( std::bind(&SourceDriver::putPacket, this, std::placeholders::_1)); } } From 774b0a0276ce0f3aa0dfddf2c7238e6cbdaad121 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 18 Jan 2022 10:03:57 +0800 Subject: [PATCH 086/261] refac: fix compiling warnings --- .gitmodules | 2 +- src/rs_driver | 2 +- src/source/source_pointcloud_ros.hpp | 4 ++-- src/utility/yaml_reader.hpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitmodules b/.gitmodules index b7a6d10f..3c296e3e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "src/rs_driver"] path = src/rs_driver - url = git@192.168.1.20:rs_share/rs_driver.git + url = http://gitlab.robosense.cn/rs_share/rslidar/rs_driver.git branch = dev_opt diff --git a/src/rs_driver b/src/rs_driver index 170df4e0..f2d677c1 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 170df4e0300da02ff2e5547c4d6e1f8e8e043699 +Subproject commit f2d677c1fcec1b6828564a1ac83525b06a8eea0c diff --git a/src/source/source_pointcloud_ros.hpp b/src/source/source_pointcloud_ros.hpp index 24288567..6adac1bc 100644 --- a/src/source/source_pointcloud_ros.hpp +++ b/src/source/source_pointcloud_ros.hpp @@ -52,7 +52,7 @@ inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const ros_msg.header.stamp = ros_msg.header.stamp.fromSec(rs_msg.timestamp); ros_msg.header.seq = rs_msg.seq; ros_msg.header.frame_id = frame_id; - return std::move(ros_msg); + return ros_msg; } class DestinationPointCloudRos : public DestinationPointCloud @@ -108,7 +108,7 @@ inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); ros_msg.header.stamp.nanosec = (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); - return std::move(ros_msg); + return ros_msg; } class DestinationPointCloudRos : virtual public DestinationPointCloudRos diff --git a/src/utility/yaml_reader.hpp b/src/utility/yaml_reader.hpp index 22bedc56..4c34609d 100644 --- a/src/utility/yaml_reader.hpp +++ b/src/utility/yaml_reader.hpp @@ -79,7 +79,7 @@ inline YAML::Node yamlSubNodeAbort(const YAML::Node& yaml, const std::string& no RS_ERROR << " : Cannot find subnode " << node << ". Aborting!!!" << RS_REND; exit(-1); } - return std::move(ret); + return ret; } } // namespace lidar From c77d4a2b879fda3c436ececaa2a23159348183d4 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 18 Jan 2022 10:18:35 +0800 Subject: [PATCH 087/261] refac: fix rviz frame_id --- rviz/rviz.rviz | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rviz/rviz.rviz b/rviz/rviz.rviz index 4a44e95a..3013295e 100644 --- a/rviz/rviz.rviz +++ b/rviz/rviz.rviz @@ -96,7 +96,7 @@ Visualization Manager: Global Options: Background Color: 48; 48; 48 Default Light: true - Fixed Frame: rslidar + Fixed Frame: //rslidar Frame Rate: 30 Name: root Tools: From 2340a6e840da69b5591958e7916ff6d80cc00a77 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 18 Jan 2022 14:21:53 +0800 Subject: [PATCH 088/261] refac: adapt to ros2 --- launch/start.py | 21 +--- src/source/source_packet_ros.hpp | 166 ++++++++++++--------------- src/source/source_pointcloud_ros.hpp | 4 +- 3 files changed, 83 insertions(+), 108 deletions(-) diff --git a/launch/start.py b/launch/start.py index 8e023706..a9031240 100755 --- a/launch/start.py +++ b/launch/start.py @@ -1,21 +1,12 @@ from launch import LaunchDescription from launch_ros.actions import Node from ament_index_python.packages import get_package_share_directory + def generate_launch_description(): + rviz_config=get_package_share_directory('rslidar_sdk')+'/rviz/rviz2.rviz' + return LaunchDescription([ - Node( - package='rslidar_sdk', - node_namespace='rslidar_sdk', - node_executable='rslidar_sdk_node', - output='screen', - node_name='rslidar_sdk_node' - ), - Node( - package='rviz2', - node_namespace='rviz2', - node_executable='rviz2', - node_name='rviz2', - arguments=['-d',rviz_config] - ) - ]) \ No newline at end of file + Node(namespace='rslidar_sdk', package='rslidar_sdk', executable='rslidar_sdk_node', output='screen'), + Node(namespace='rviz2', package='rviz2', executable='rviz2', arguments=['-d',rviz_config]) + ]) diff --git a/src/source/source_packet_ros.hpp b/src/source/source_packet_ros.hpp index 6f3bd755..d239b659 100644 --- a/src/source/source_packet_ros.hpp +++ b/src/source/source_packet_ros.hpp @@ -33,9 +33,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include "source/source_driver.hpp" -#include "msg/ros_msg/rslidarPacket.h" #ifdef ROS_FOUND +#include "msg/ros_msg/rslidarPacket.h" #include namespace robosense @@ -124,7 +124,7 @@ class DestinationPacketRos : public DestinationPacket private: std::unique_ptr nh_; - ros::Publisher pub_; + ros::Publisher pkt_pub_; std::string frame_id_; }; @@ -138,12 +138,12 @@ inline void DestinationPacketRos::init(const YAML::Node& config) ros_send_topic, "rslidar_packets"); nh_ = std::unique_ptr(new ros::NodeHandle()); - pub_ = nh_->advertise(ros_send_topic, 10); + pkt_pub_ = nh_->advertise(ros_send_topic, 10); } inline void DestinationPacketRos::sendPacket(const Packet& msg) { - pub_.publish(toRosMsg(msg, frame_id_)); + pkt_pub_.publish(toRosMsg(msg, frame_id_)); } } // namespace lidar @@ -152,6 +152,7 @@ inline void DestinationPacketRos::sendPacket(const Packet& msg) #endif // ROS_FOUND #ifdef ROS2_FOUND +#include "rslidar_msg/msg/rslidar_packet.hpp" #include namespace robosense @@ -159,126 +160,109 @@ namespace robosense namespace lidar { -inline rslidar_msg::msg::RslidarPacket toRosMsg(const Packet& rs_msg) +inline Packet toRsMsg(const rslidar_msg::msg::RslidarPacket& ros_msg) { - rslidar_msg::msg::RslidarPacket ros_msg; - //ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); - //ros_msg.header.stamp.nanosec = - // (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); - //ros_msg.header.frame_id = rs_msg.frame_id; - for (size_t i = 0; i < rs_msg.packet.size(); i++) + Packet rs_msg; + rs_msg.timestamp = ros_msg.header.stamp.sec + double(ros_msg.header.stamp.nanosec) / 1e9; + //rs_msg.seq = ros_msg.header.seq; + rs_msg.is_difop = ros_msg.is_difop; + rs_msg.is_frame_begin = ros_msg.is_frame_begin; + + for (size_t i = 0; i < ros_msg.data.size(); i++) { - ros_msg.data[i] = rs_msg.packet[i]; + rs_msg.buf_.emplace_back(ros_msg.data[i]); } - return std::move(ros_msg); + + return rs_msg; } -class PacketRosAdapter : virtual public AdapterBase -{ -public: - PacketRosAdapter() = default; - virtual ~PacketRosAdapter(); - void init(const YAML::Node& config); - void start(); - void regRecvCallback(const std::function& callback); - void regRecvCallback(const std::function& callback); - void sendScan(const ScanMsg& msg); - void sendPacket(const PacketMsg& msg); +class SourcePacketRos : public SourceDriver +{ +public: -private: - void localMsopCallback(const rslidar_msg::msg::RslidarScan::SharedPtr msg); - void localDifopCallback(const rslidar_msg::msg::RslidarPacket::SharedPtr msg); + virtual void init(const YAML::Node& config); + + SourcePacketRos(); private: + + void putPacket(const rslidar_msg::msg::RslidarPacket& msg); + std::shared_ptr node_ptr_; - LidarType lidar_type_; - rclcpp::Publisher::SharedPtr scan_pub_; - rclcpp::Publisher::SharedPtr packet_pub_; - rclcpp::Subscription::SharedPtr scan_sub_; - rclcpp::Subscription::SharedPtr packet_sub_; - std::vector> scan_cb_vec_; - std::vector> packet_cb_vec_; + rclcpp::Subscription::SharedPtr pkt_sub_; }; -inline PacketRosAdapter::~PacketRosAdapter() +SourcePacketRos::SourcePacketRos() + : SourceDriver(SourceType::MSG_FROM_ROS_PACKET) { - stop(); } -inline void PacketRosAdapter::init(const YAML::Node& config) +void SourcePacketRos::init(const YAML::Node& config) { + SourceDriver::init(config); + + std::string ros_recv_topic; + yamlRead(config["ros"], "ros_recv_packet_topic", + ros_recv_topic, "rslidar_packets"); + node_ptr_.reset(new rclcpp::Node("rslidar_packets_adapter")); + pkt_sub_ = node_ptr_->create_subscription(ros_recv_topic, 10, + std::bind(&SourcePacketRos::putPacket, this, std::placeholders::_1)); +} +void SourcePacketRos::putPacket(const rslidar_msg::msg::RslidarPacket& msg) +{ + driver_ptr_->decodePacket(toRsMsg(msg)); +} - std::string lidar_type_str; - yamlRead(config["driver"], "lidar_type", lidar_type_str, "RS16"); - lidar_type_ = RSDriverParam::strToLidarType(lidar_type_str); +inline rslidar_msg::msg::RslidarPacket toRosMsg(const Packet& rs_msg, const std::string& frame_id) +{ + rslidar_msg::msg::RslidarPacket ros_msg; + ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); + ros_msg.header.stamp.nanosec = (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); + //ros_msg.header.seq = rs_msg.seq; + ros_msg.header.frame_id = frame_id; + ros_msg.is_difop = rs_msg.is_difop; + ros_msg.is_frame_begin = rs_msg.is_frame_begin; - int msg_source; - yamlReadAbort(config, "msg_source", msg_source); - if (msg_source == MsgSource::MSG_FROM_ROS_PACKET) + for (size_t i = 0; i < rs_msg.buf_.size(); i++) { - std::string ros_recv_topic; - yamlRead(config["ros"], "ros_recv_packet_topic", ros_recv_topic, "rslidar_packets"); - - packet_sub_ = node_ptr_->create_subscription( - ros_recv_topic + "_difop", 10, - [this](const rslidar_msg::msg::RslidarPacket::SharedPtr msg) { localDifopCallback(msg); }); - scan_sub_ = node_ptr_->create_subscription( - ros_recv_topic, 10, [this](const rslidar_msg::msg::RslidarScan::SharedPtr msg) { localMsopCallback(msg); }); + ros_msg.data.emplace_back(rs_msg.buf_[i]); } - bool send_packet_ros; - yamlRead(config, "send_packet_ros", send_packet_ros, false); - if (send_packet_ros) - { - std::string ros_send_topic; - yamlRead(config["ros"], "ros_send_packet_topic", ros_send_topic, "rslidar_packets"); - - packet_pub_ = node_ptr_->create_publisher(ros_send_topic + "_difop", 10); - scan_pub_ = node_ptr_->create_publisher(ros_send_topic, 10); - } + return ros_msg; } -inline void PacketRosAdapter::start() +class DestinationPacketRos : public DestinationPacket { - std::thread t([this]() { rclcpp::spin(node_ptr_); }); - t.detach(); -} +public: -inline void PacketRosAdapter::regRecvCallback(const std::function& callback) -{ - scan_cb_vec_.emplace_back(callback); -} + virtual void init(const YAML::Node& config); + virtual void sendPacket(const Packet& msg); + virtual ~DestinationPacketRos() = default; -inline void PacketRosAdapter::regRecvCallback(const std::function& callback) -{ - packet_cb_vec_.emplace_back(callback); -} +private: -inline void PacketRosAdapter::sendScan(const ScanMsg& msg) -{ - scan_pub_->publish(toRosMsg(msg)); -} + std::shared_ptr node_ptr_; + rclcpp::Publisher::SharedPtr pkt_pub_; + std::string frame_id_; +}; -inline void PacketRosAdapter::sendPacket(const PacketMsg& msg) +inline void DestinationPacketRos::init(const YAML::Node& config) { - packet_pub_->publish(toRosMsg(msg)); -} + yamlRead(config["ros"], + "ros_frame_id", frame_id_, "/rslidar"); -inline void PacketRosAdapter::localMsopCallback(const rslidar_msg::msg::RslidarScan::SharedPtr msg) -{ - for (auto& cb : scan_cb_vec_) - { - cb(toRsMsg(lidar_type_, PktType::MSOP, *msg)); - } + std::string ros_send_topic; + yamlRead(config["ros"], "ros_send_packet_topic", + ros_send_topic, "rslidar_packets"); + + node_ptr_.reset(new rclcpp::Node("rslidar_packets_adapter")); + pkt_pub_ = node_ptr_->create_publisher(ros_send_topic, 10); } -inline void PacketRosAdapter::localDifopCallback(const rslidar_msg::msg::RslidarPacket::SharedPtr msg) +inline void DestinationPacketRos::sendPacket(const Packet& msg) { - for (auto& cb : packet_cb_vec_) - { - cb(toRsMsg(lidar_type_, PktType::DIFOP, *msg)); - } + pkt_pub_->publish(toRosMsg(msg, frame_id_)); } } // namespace lidar diff --git a/src/source/source_pointcloud_ros.hpp b/src/source/source_pointcloud_ros.hpp index 6adac1bc..1577fc0c 100644 --- a/src/source/source_pointcloud_ros.hpp +++ b/src/source/source_pointcloud_ros.hpp @@ -35,7 +35,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "source/source.hpp" #include -#include +//#include #ifdef ROS_FOUND #include @@ -111,7 +111,7 @@ inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) return ros_msg; } -class DestinationPointCloudRos : virtual public DestinationPointCloudRos +class DestinationPointCloudRos : virtual public DestinationPointCloud { public: From aeb0849bee4f92827a86a5cf3d118ea4d1fa06d0 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 18 Jan 2022 15:21:59 +0800 Subject: [PATCH 089/261] refac: adapt to ros1 --- rviz/rviz.rviz | 61 ++++---- .../{rslidarPacket.msg => RslidarPacket.msg} | 2 +- .../{rslidarPacket.h => rslidar_packet.hpp} | 143 ++++++++++-------- src/rs_driver | 2 +- src/source/source_packet_ros.hpp | 15 +- 5 files changed, 120 insertions(+), 103 deletions(-) rename src/msg/ros_msg/{rslidarPacket.msg => RslidarPacket.msg} (68%) rename src/msg/ros_msg/{rslidarPacket.h => rslidar_packet.hpp} (50%) diff --git a/rviz/rviz.rviz b/rviz/rviz.rviz index 3013295e..e3b70a87 100644 --- a/rviz/rviz.rviz +++ b/rviz/rviz.rviz @@ -3,9 +3,11 @@ Panels: Help Height: 75 Name: Displays Property Tree Widget: - Expanded: ~ + Expanded: + - /Global Options1 + - /Point Cloud1 Splitter Ratio: 0.5 - Tree Height: 846 + Tree Height: 790 - Class: rviz/Selection Name: Selection - Class: rviz/Tool Properties @@ -14,7 +16,7 @@ Panels: - /2D Nav Goal1 - /Publish Point1 Name: Tool Properties - Splitter Ratio: 0.588679016 + Splitter Ratio: 0.5886790156364441 - Class: rviz/Views Expanded: - /Current View1 @@ -31,7 +33,9 @@ Panels: Property Tree Widget: Expanded: ~ Splitter Ratio: 0.5 - Tree Height: 362 + Tree Height: 366 +Preferences: + PromptSaveOnExit: true Toolbars: toolButtonStyle: 2 Visualization Manager: @@ -52,16 +56,14 @@ Visualization Manager: Enabled: true Invert Rainbow: false Max Color: 255; 255; 255 - Max Intensity: 241 Min Color: 0; 0; 0 - Min Intensity: 1 Name: Point Cloud Position Transformer: XYZ Queue Size: 10 Selectable: true Size (Pixels): 1.5 - Size (m): 0.00999999978 - Style: Points + Size (m): 0.10000000149011612 + Style: Squares Topic: /rslidar_points Unreliable: false Use Fixed Frame: true @@ -73,7 +75,7 @@ Visualization Manager: Color: 160; 160; 164 Enabled: true Line Style: - Line Width: 0.0299999993 + Line Width: 0.029999999329447746 Value: Lines Name: Grid Normal Cell Count: 0 @@ -85,18 +87,20 @@ Visualization Manager: Plane Cell Count: 50 Reference Frame: Value: true - - Class: rviz/Axes + - Alpha: 1 + Class: rviz/Axes Enabled: true Length: 1 Name: Axes - Radius: 0.100000001 + Radius: 0.10000000149011612 Reference Frame: + Show Trail: false Value: true Enabled: true Global Options: Background Color: 48; 48; 48 Default Light: true - Fixed Frame: //rslidar + Fixed Frame: /rslidar Frame Rate: 30 Name: root Tools: @@ -107,7 +111,10 @@ Visualization Manager: - Class: rviz/FocusCamera - Class: rviz/Measure - Class: rviz/SetInitialPose + Theta std deviation: 0.2617993950843811 Topic: /initialpose + X std deviation: 0.5 + Y std deviation: 0.5 - Class: rviz/SetGoal Topic: /move_base_simple/goal - Class: rviz/PublishPoint @@ -117,33 +124,33 @@ Visualization Manager: Views: Current: Class: rviz/Orbit - Distance: 34.5997963 + Distance: 107.46170806884766 Enable Stereo Rendering: - Stereo Eye Separation: 0.0599999987 + Stereo Eye Separation: 0.05999999865889549 Stereo Focal Distance: 1 Swap Stereo Eyes: false Value: false + Field of View: 0.7853981852531433 Focal Point: - X: 1.4133122 - Y: -0.170824349 - Z: 1.69326282 + X: 1.4133121967315674 + Y: -0.1708243489265442 + Z: 1.6932628154754639 Focal Shape Fixed Size: true - Focal Shape Size: 0.0500000007 + Focal Shape Size: 0.05000000074505806 Invert Z Axis: false Name: Current View - Near Clip Distance: 0.00999999978 - Pitch: 0.359796703 + Near Clip Distance: 0.009999999776482582 + Pitch: 0.634796679019928 Target Frame: - Value: Orbit (rviz) - Yaw: 3.12499475 + Yaw: 3.9649996757507324 Saved: ~ Window Geometry: Displays: collapsed: false - Height: 1056 + Height: 1016 Hide Left Dock: false Hide Right Dock: true - QMainWindow State: 000000ff00000000fd00000004000000000000016a000003dafc0200000009fb0000001200530065006c0065006300740069006f006e00000000280000009b0000006100fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afc00000028000003da000000d700fffffffa000000010100000002fb0000000a0049006d0061006700650000000000ffffffff0000000000000000fb000000100044006900730070006c0061007900730100000000000001dd0000016a00fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fc00000351000000b10000000000fffffffa000000000100000002fb0000000a0049006d006100670065020000006e000000180000093800000420fb000000100044006900730070006c0061007900730000000000000001dd0000016a00ffffff000000010000010f000003dafc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a005600690065007700730000000028000003da000000ad00fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b2000000000000000000000002000009bf00000141fc0100000003fb0000000a0049006d0061006700650100000000000009bf0000000000000000fc00000000000009bf0000000000fffffffa000000000200000002fb0000000a0049006d006100670065020000071300000071000000c3000000c3fb0000000a0049006d0061006700650100000000000003e40000000000000000fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000009bf0000003bfc0100000002fb0000000800540069006d00650000000000000009bf0000030000fffffffb0000000800540069006d006501000000000000045000000000000000000000084f000003da00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 + QMainWindow State: 000000ff00000000fd00000004000000000000016a0000039efc0200000009fb0000001200530065006c0065006300740069006f006e00000000280000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afc0000003d0000039e000000c900fffffffa000000010100000002fb0000000a0049006d0061006700650000000000ffffffff0000000000000000fb000000100044006900730070006c0061007900730100000000000001dd0000015600fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fc00000351000000b10000000000fffffffa000000000100000002fb0000000a0049006d006100670065020000006e000000180000093800000420fb000000100044006900730070006c0061007900730000000000000001dd0000015600ffffff000000010000010f000003dafc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a005600690065007700730000000028000003da000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b2000000000000000000000002000009bf00000141fc0100000003fb0000000a0049006d0061006700650100000000000009bf0000000000000000fc00000000000009bf0000000000fffffffa000000000200000002fb0000000a0049006d006100670065020000071300000071000000c3000000c3fb0000000a0049006d0061006700650100000000000003e40000000000000000fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000009bf0000003bfc0100000002fb0000000800540069006d00650000000000000009bf000004f300fffffffb0000000800540069006d00650100000000000004500000000000000000000008580000039e00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 Selection: collapsed: false Time: @@ -152,6 +159,6 @@ Window Geometry: collapsed: false Views: collapsed: false - Width: 2495 - X: 65 - Y: 24 + Width: 2504 + X: 56 + Y: 27 diff --git a/src/msg/ros_msg/rslidarPacket.msg b/src/msg/ros_msg/RslidarPacket.msg similarity index 68% rename from src/msg/ros_msg/rslidarPacket.msg rename to src/msg/ros_msg/RslidarPacket.msg index 53e61424..b6a05f5e 100644 --- a/src/msg/ros_msg/rslidarPacket.msg +++ b/src/msg/ros_msg/RslidarPacket.msg @@ -1,4 +1,4 @@ -Header header +std_msgs/Header header uint8 is_difop uint8 is_frame_begin uint8[] data diff --git a/src/msg/ros_msg/rslidarPacket.h b/src/msg/ros_msg/rslidar_packet.hpp similarity index 50% rename from src/msg/ros_msg/rslidarPacket.h rename to src/msg/ros_msg/rslidar_packet.hpp index ff2d44dd..4a1a2906 100644 --- a/src/msg/ros_msg/rslidarPacket.h +++ b/src/msg/ros_msg/rslidar_packet.hpp @@ -1,9 +1,9 @@ -// Generated by gencpp from file rslidar_sdk/rslidarPacket.msg +// Generated by gencpp from file rslidar_msg/RslidarPacket.msg // DO NOT EDIT! -#ifndef RSLIDAR_SDK_MESSAGE_RSLIDARPACKET_H -#define RSLIDAR_SDK_MESSAGE_RSLIDARPACKET_H +#ifndef RSLIDAR_MSG_MESSAGE_RSLIDARPACKET_H +#define RSLIDAR_MSG_MESSAGE_RSLIDARPACKET_H #include @@ -17,20 +17,20 @@ #include -namespace rslidar_sdk +namespace rslidar_msg { template -struct rslidarPacket_ +struct RslidarPacket_ { - typedef rslidarPacket_ Type; + typedef RslidarPacket_ Type; - rslidarPacket_() + RslidarPacket_() : header() , is_difop(0) , is_frame_begin(0) , data() { } - rslidarPacket_(const ContainerAllocator& _alloc) + RslidarPacket_(const ContainerAllocator& _alloc) : header(_alloc) , is_difop(0) , is_frame_begin(0) @@ -56,130 +56,139 @@ struct rslidarPacket_ - typedef boost::shared_ptr< ::rslidar_sdk::rslidarPacket_ > Ptr; - typedef boost::shared_ptr< ::rslidar_sdk::rslidarPacket_ const> ConstPtr; + typedef boost::shared_ptr< ::rslidar_msg::RslidarPacket_ > Ptr; + typedef boost::shared_ptr< ::rslidar_msg::RslidarPacket_ const> ConstPtr; -}; // struct rslidarPacket_ +}; // struct RslidarPacket_ -typedef ::rslidar_sdk::rslidarPacket_ > rslidarPacket; +typedef ::rslidar_msg::RslidarPacket_ > RslidarPacket; -typedef boost::shared_ptr< ::rslidar_sdk::rslidarPacket > rslidarPacketPtr; -typedef boost::shared_ptr< ::rslidar_sdk::rslidarPacket const> rslidarPacketConstPtr; +typedef boost::shared_ptr< ::rslidar_msg::RslidarPacket > RslidarPacketPtr; +typedef boost::shared_ptr< ::rslidar_msg::RslidarPacket const> RslidarPacketConstPtr; // constants requiring out of line definition template -std::ostream& operator<<(std::ostream& s, const ::rslidar_sdk::rslidarPacket_ & v) +std::ostream& operator<<(std::ostream& s, const ::rslidar_msg::RslidarPacket_ & v) { -ros::message_operations::Printer< ::rslidar_sdk::rslidarPacket_ >::stream(s, "", v); +ros::message_operations::Printer< ::rslidar_msg::RslidarPacket_ >::stream(s, "", v); return s; } -} // namespace rslidar_sdk -namespace ros +template +bool operator==(const ::rslidar_msg::RslidarPacket_ & lhs, const ::rslidar_msg::RslidarPacket_ & rhs) { -namespace message_traits + return lhs.header == rhs.header && + lhs.is_difop == rhs.is_difop && + lhs.is_frame_begin == rhs.is_frame_begin && + lhs.data == rhs.data; +} + +template +bool operator!=(const ::rslidar_msg::RslidarPacket_ & lhs, const ::rslidar_msg::RslidarPacket_ & rhs) { + return !(lhs == rhs); +} +} // namespace rslidar_msg -// BOOLTRAITS {'IsFixedSize': False, 'IsMessage': True, 'HasHeader': True} -// {'std_msgs': ['/opt/ros/kinetic/share/std_msgs/cmake/../msg'], 'rslidar_sdk': ['/home/ron/dev/catkin_ws/src/rslidar_sdk/msg']} +namespace ros +{ +namespace message_traits +{ -// !!!!!!!!!!! ['__class__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_parsed_fields', 'constants', 'fields', 'full_name', 'has_header', 'header_present', 'names', 'package', 'parsed_fields', 'short_name', 'text', 'types'] template -struct IsFixedSize< ::rslidar_sdk::rslidarPacket_ > - : FalseType +struct IsMessage< ::rslidar_msg::RslidarPacket_ > + : TrueType { }; template -struct IsFixedSize< ::rslidar_sdk::rslidarPacket_ const> - : FalseType +struct IsMessage< ::rslidar_msg::RslidarPacket_ const> + : TrueType { }; template -struct IsMessage< ::rslidar_sdk::rslidarPacket_ > - : TrueType +struct IsFixedSize< ::rslidar_msg::RslidarPacket_ > + : FalseType { }; template -struct IsMessage< ::rslidar_sdk::rslidarPacket_ const> - : TrueType +struct IsFixedSize< ::rslidar_msg::RslidarPacket_ const> + : FalseType { }; template -struct HasHeader< ::rslidar_sdk::rslidarPacket_ > +struct HasHeader< ::rslidar_msg::RslidarPacket_ > : TrueType { }; template -struct HasHeader< ::rslidar_sdk::rslidarPacket_ const> +struct HasHeader< ::rslidar_msg::RslidarPacket_ const> : TrueType { }; template -struct MD5Sum< ::rslidar_sdk::rslidarPacket_ > +struct MD5Sum< ::rslidar_msg::RslidarPacket_ > { static const char* value() { return "4b1cc155a9097c0cb935a7abf46d6eef"; } - static const char* value(const ::rslidar_sdk::rslidarPacket_&) { return value(); } + static const char* value(const ::rslidar_msg::RslidarPacket_&) { return value(); } static const uint64_t static_value1 = 0x4b1cc155a9097c0cULL; static const uint64_t static_value2 = 0xb935a7abf46d6eefULL; }; template -struct DataType< ::rslidar_sdk::rslidarPacket_ > +struct DataType< ::rslidar_msg::RslidarPacket_ > { static const char* value() { - return "rslidar_sdk/rslidarPacket"; + return "rslidar_msg/RslidarPacket"; } - static const char* value(const ::rslidar_sdk::rslidarPacket_&) { return value(); } + static const char* value(const ::rslidar_msg::RslidarPacket_&) { return value(); } }; template -struct Definition< ::rslidar_sdk::rslidarPacket_ > +struct Definition< ::rslidar_msg::RslidarPacket_ > { static const char* value() { - return "Header header\n\ -uint8 is_difop\n\ -uint8 is_frame_begin\n\ -uint8[] data\n\ -\n\ -================================================================================\n\ -MSG: std_msgs/Header\n\ -# Standard metadata for higher-level stamped data types.\n\ -# This is generally used to communicate timestamped data \n\ -# in a particular coordinate frame.\n\ -# \n\ -# sequence ID: consecutively increasing ID \n\ -uint32 seq\n\ -#Two-integer timestamp that is expressed as:\n\ -# * stamp.sec: seconds (stamp_secs) since epoch (in Python the variable is called 'secs')\n\ -# * stamp.nsec: nanoseconds since stamp_secs (in Python the variable is called 'nsecs')\n\ -# time-handling sugar is provided by the client library\n\ -time stamp\n\ -#Frame this data is associated with\n\ -# 0: no frame\n\ -# 1: global frame\n\ -string frame_id\n\ -"; + return "std_msgs/Header header\n" +"uint8 is_difop\n" +"uint8 is_frame_begin\n" +"uint8[] data\n" +"\n" +"================================================================================\n" +"MSG: std_msgs/Header\n" +"# Standard metadata for higher-level stamped data types.\n" +"# This is generally used to communicate timestamped data \n" +"# in a particular coordinate frame.\n" +"# \n" +"# sequence ID: consecutively increasing ID \n" +"uint32 seq\n" +"#Two-integer timestamp that is expressed as:\n" +"# * stamp.sec: seconds (stamp_secs) since epoch (in Python the variable is called 'secs')\n" +"# * stamp.nsec: nanoseconds since stamp_secs (in Python the variable is called 'nsecs')\n" +"# time-handling sugar is provided by the client library\n" +"time stamp\n" +"#Frame this data is associated with\n" +"string frame_id\n" +; } - static const char* value(const ::rslidar_sdk::rslidarPacket_&) { return value(); } + static const char* value(const ::rslidar_msg::RslidarPacket_&) { return value(); } }; } // namespace message_traits @@ -190,7 +199,7 @@ namespace ros namespace serialization { - template struct Serializer< ::rslidar_sdk::rslidarPacket_ > + template struct Serializer< ::rslidar_msg::RslidarPacket_ > { template inline static void allInOne(Stream& stream, T m) { @@ -201,7 +210,7 @@ namespace serialization } ROS_DECLARE_ALLINONE_SERIALIZER - }; // struct rslidarPacket_ + }; // struct RslidarPacket_ } // namespace serialization } // namespace ros @@ -212,9 +221,9 @@ namespace message_operations { template -struct Printer< ::rslidar_sdk::rslidarPacket_ > +struct Printer< ::rslidar_msg::RslidarPacket_ > { - template static void stream(Stream& s, const std::string& indent, const ::rslidar_sdk::rslidarPacket_& v) + template static void stream(Stream& s, const std::string& indent, const ::rslidar_msg::RslidarPacket_& v) { s << indent << "header: "; s << std::endl; @@ -235,4 +244,4 @@ struct Printer< ::rslidar_sdk::rslidarPacket_ > } // namespace message_operations } // namespace ros -#endif // RSLIDAR_SDK_MESSAGE_RSLIDARPACKET_H +#endif // RSLIDAR_MSG_MESSAGE_RSLIDARPACKET_H diff --git a/src/rs_driver b/src/rs_driver index f2d677c1..6e6272c2 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit f2d677c1fcec1b6828564a1ac83525b06a8eea0c +Subproject commit 6e6272c22096ba4f6b6a05a707a40ecd31082317 diff --git a/src/source/source_packet_ros.hpp b/src/source/source_packet_ros.hpp index d239b659..a5e33569 100644 --- a/src/source/source_packet_ros.hpp +++ b/src/source/source_packet_ros.hpp @@ -35,7 +35,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "source/source_driver.hpp" #ifdef ROS_FOUND -#include "msg/ros_msg/rslidarPacket.h" +#include "msg/ros_msg/rslidar_packet.hpp" #include namespace robosense @@ -43,7 +43,7 @@ namespace robosense namespace lidar { -inline Packet toRsMsg(const rslidar_sdk::rslidarPacket& ros_msg) +inline Packet toRsMsg(const rslidar_msg::RslidarPacket& ros_msg) { Packet rs_msg; rs_msg.timestamp = ros_msg.header.stamp.toSec(); @@ -69,7 +69,7 @@ class SourcePacketRos : public SourceDriver private: - void putPacket(const rslidar_sdk::rslidarPacket& msg); + void putPacket(const rslidar_msg::RslidarPacket& msg); std::unique_ptr nh_; ros::Subscriber pkt_sub_; @@ -91,14 +91,15 @@ void SourcePacketRos::init(const YAML::Node& config) nh_ = std::unique_ptr(new ros::NodeHandle()); pkt_sub_ = nh_->subscribe(ros_recv_topic, 100, &SourcePacketRos::putPacket, this); } -void SourcePacketRos::putPacket(const rslidar_sdk::rslidarPacket& msg) + +void SourcePacketRos::putPacket(const rslidar_msg::RslidarPacket& msg) { driver_ptr_->decodePacket(toRsMsg(msg)); } -inline rslidar_sdk::rslidarPacket toRosMsg(const Packet& rs_msg, const std::string& frame_id) +inline rslidar_msg::RslidarPacket toRosMsg(const Packet& rs_msg, const std::string& frame_id) { - rslidar_sdk::rslidarPacket ros_msg; + rslidar_msg::RslidarPacket ros_msg; ros_msg.header.stamp = ros_msg.header.stamp.fromSec(rs_msg.timestamp); ros_msg.header.seq = rs_msg.seq; ros_msg.header.frame_id = frame_id; @@ -138,7 +139,7 @@ inline void DestinationPacketRos::init(const YAML::Node& config) ros_send_topic, "rslidar_packets"); nh_ = std::unique_ptr(new ros::NodeHandle()); - pkt_pub_ = nh_->advertise(ros_send_topic, 10); + pkt_pub_ = nh_->advertise(ros_send_topic, 10); } inline void DestinationPacketRos::sendPacket(const Packet& msg) From 89dcbdaa120ec37b9028940af032c45991884574 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 19 Jan 2022 15:07:33 +0800 Subject: [PATCH 090/261] refac: update help docs --- config/config.yaml | 2 +- doc/howto/how_to_offline_decode_pcap.md | 24 +++++--- doc/howto/how_to_offline_decode_pcap_cn.md | 17 +++--- .../how_to_online_send_point_cloud_ros.md | 17 +++--- .../how_to_online_send_point_cloud_ros_cn.md | 12 ++-- ...how_to_record_and_offline_decode_rosbag.md | 31 +++++----- ..._to_record_and_offline_decode_rosbag_cn.md | 29 ++++----- doc/howto/how_to_switch_point_type.md | 23 ++++--- doc/howto/how_to_switch_point_type_cn.md | 18 +++--- .../how_to_use_coordinate_transformation.md | 27 ++++---- ...how_to_use_coordinate_transformation_cn.md | 29 +++++---- doc/howto/how_to_use_multi_cast_function.md | 42 ++++--------- .../how_to_use_multi_cast_function_cn.md | 36 +++-------- doc/howto/how_to_use_multi_lidars.md | 35 ++++++----- doc/howto/how_to_use_multi_lidars_cn.md | 40 ++++++------ doc/howto/how_to_use_protobuf_function.md | 42 ++++++------- doc/howto/how_to_use_protobuf_function_cn.md | 31 ++++------ doc/intro/hiding_parameters_intro.md | 61 +++++++++---------- doc/intro/hiding_parameters_intro_cn.md | 53 ++++++++-------- doc/intro/parameter_intro.md | 56 ++++++++--------- doc/intro/parameter_intro_cn.md | 42 ++++++------- src/rs_driver | 2 +- src/source/source_driver.hpp | 6 +- 23 files changed, 324 insertions(+), 351 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index d4fad989..8fd6fb87 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -21,7 +21,7 @@ lidar: max_distance: 200 #Maximum distance of point cloud use_lidar_clock: false #True--Use the lidar clock as the message timestamp #False-- Use the system clock as the timestamp - pcap_path: /mnt/share/pcap/RS32/Rs32.pcap #The path of pcap file + pcap_path: /home/sti/dev/share/pcap/RS32/Rs32.pcap #The path of pcap file ros: ros_frame_id: /rslidar #Frame id of packet message and point cloud message ros_recv_packet_topic: /rslidar_packets #Topic used to receive lidar packets from ROS diff --git a/doc/howto/how_to_offline_decode_pcap.md b/doc/howto/how_to_offline_decode_pcap.md index 6a77a978..a5685c69 100644 --- a/doc/howto/how_to_offline_decode_pcap.md +++ b/doc/howto/how_to_offline_decode_pcap.md @@ -2,13 +2,19 @@ ## 1 Introduction -This document will show you how to decode pcap bag and send point cloud to ROS. Please make sure you have read the LiDAR user-guide and [Intro to parameters](doc/intro/parameter_intro.md) before reading this document. +This document illustrates how to decode pcap bag and send point cloud to ROS. + +Please make sure you have read the LiDAR user-guide and [Intro to parameters](doc/intro/parameter_intro.md) before reading this document. ## 2 Steps ### 2.1 Get the LiDAR port number -Please follow the instructions in LiDAR user-guide to connect the LiDAR and set up your computer's ip address. At this time, you should have already known your LiDAR's msop port number and difop port number. The default is ```msop-6699, difop-7788```. If you have no idea about what it is, please check the LiDAR user-guide first. +Please follow the instructions in LiDAR user-guide to connect the LiDAR, and set up your computer's ip address. + +At this time, you should have already known your LiDAR's msop port number and difop port number. The default is ```msop-6699, difop-7788```. + +If you have no idea about what it is, please check the LiDAR user-guide. ### 2.2 Set up the common part of the config file @@ -19,14 +25,11 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap ``` -Since the message come from the pcap bag, set ```msg_source = 3```. +The messages come from the pcap bag, so set ```msg_source = 3```. -Send point cloud to ROS so set ```send_point_cloud_ros = true```. - -Make sure the ```pcap_path``` is correct. +Send point cloud to ROS, so set ```send_point_cloud_ros = true```. ### 2.3 Set up the lidar-driver part of the config file @@ -34,7 +37,6 @@ Make sure the ```pcap_path``` is correct. lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -42,16 +44,20 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false + pcap_path: /home/robosense/lidar.pcap ``` +Set the ```pcap_path``` to the absolute path of the pcap file. + Set the ```lidar_type``` to your LiDAR type. -Set the ```msop_port``` and ```difop_port``` to your LiDAR's port number. +Set the ```msop_port``` and ```difop_port``` to the port number of your LiDAR. ### 2.4 Set up the lidar-ros part of the config file ```yaml ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points diff --git a/doc/howto/how_to_offline_decode_pcap_cn.md b/doc/howto/how_to_offline_decode_pcap_cn.md index b418d166..27aca4f3 100644 --- a/doc/howto/how_to_offline_decode_pcap_cn.md +++ b/doc/howto/how_to_offline_decode_pcap_cn.md @@ -2,13 +2,17 @@ ## 1 简介 -本文档将展示如何解码pcap包并发送点云数据到ROS。 在阅读本文档之前,请确保已阅读雷达用户手册和 [参数简介](../intro/parameter_intro.md) 。 +本文档将展示如何解码pcap包, 并发送点云数据到ROS。 + +在阅读本文档之前,请确保已阅读雷达用户手册和 [参数简介](../intro/parameter_intro.md) 。 ## 2 步骤 ### 2.1 获取数据端口号 -首先根据雷达用户手册连接雷达并设置好您的电脑的IP地址。此时应该已知雷达的msop端口号和difop端口号,默认值为```msop-6699, difop-7788```。 如果不清楚上述内容,请查看雷达用户手册。 +根据雷达用户手册连接雷达, 并设置好您的电脑的IP地址。 + +此时应该已知雷达的msop端口号和difop端口号,默认值为```msop-6699, difop-7788```。 如果不清楚上述内容,请查看雷达用户手册。 ### 2.2 设置参数文件的common部分 @@ -19,22 +23,18 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap ``` 由于消息来自pcap包,因此请设置 ```msg_source = 3``` 。 将点云发送到ROS以查看,因此设置 ```send_point_cloud_ros = true``` 。 -请确保路径```pcap_path``` 是正确的。 - ### 2.3 设置参数文件的 lidar-driver部分 ```yaml lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -42,10 +42,12 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false + pcap_path: /home/robosense/lidar.pcap ``` -将 ```lidar_type``` 设置为LiDAR类型 。 +将```pcap_path``` 设置为pcap文件的路径。 +将 ```lidar_type``` 设置为LiDAR类型 。 设置 ```msop_port``` 和 ```difop_port``` 为雷达数据端口号。 @@ -53,6 +55,7 @@ lidar: ```yaml ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points diff --git a/doc/howto/how_to_online_send_point_cloud_ros.md b/doc/howto/how_to_online_send_point_cloud_ros.md index 1e36559b..5ee226fc 100644 --- a/doc/howto/how_to_online_send_point_cloud_ros.md +++ b/doc/howto/how_to_online_send_point_cloud_ros.md @@ -2,13 +2,19 @@ ## 1 Introduction -This document will show you how to online connect a LiDAR and send point cloud to ROS. Please make sure you have read the LiDAR user-guide and [Intro to parameters](../intro/parameter_intro.md) before reading this document. +This document illustrates how to connect to an online LiDAR and send point cloud to ROS. + +Please make sure you have read the LiDAR user-guide and [Intro to parameters](../intro/parameter_intro.md) before reading this document. ## 2 Steps ### 2.1 Get the LiDAR port number -Please follow the instructions in LiDAR user-guide to connect the LiDAR and set up your computer's ip address. At this time, you should have already known your LiDAR's msop port number and difop port number. The default is ```msop-6699, difop-7788```. If you have no idea about what it is, please check the LiDAR user-guide first. +Please follow the instructions in LiDAR user-guide, to connect to the LiDAR and set up your computer's ip address. + +At this time, you should have already known your LiDAR's msop port number and difop port number. The default is ```msop-6699, difop-7788```. + +If you have no idea about what it is, please check the LiDAR user-guide. ### 2.2 Set up the common part of the config file @@ -19,7 +25,6 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap ``` Since the message come from the LiDAR, set ```msg_source = 1```. @@ -32,7 +37,6 @@ Send point cloud to ROS so set ```send_point_cloud_ros = true```. lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -50,6 +54,7 @@ Set the ```msop_port``` and ```difop_port``` to your LiDAR's port number. ```yaml ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points @@ -62,7 +67,3 @@ Set the ```ros_send_point_cloud_topic``` to the topic you want to send. Run the program. - - - - diff --git a/doc/howto/how_to_online_send_point_cloud_ros_cn.md b/doc/howto/how_to_online_send_point_cloud_ros_cn.md index 0b846b89..ba8054f3 100644 --- a/doc/howto/how_to_online_send_point_cloud_ros_cn.md +++ b/doc/howto/how_to_online_send_point_cloud_ros_cn.md @@ -2,13 +2,17 @@ ## 1 简介 -本文档描述了如何在线连接雷达并发送点云数据到ROS。在阅读本文档之前, 请确保已经阅读过雷达用户手册和[参数简介](../intro/parameter_intro.md) 。 +本文档描述了如何在线连接雷达,并发送点云数据到ROS。 + +在阅读本文档之前, 请确保已经阅读过雷达用户手册和[参数简介](../intro/parameter_intro.md) 。 ## 2 步骤 ### 2.1 获取数据端口号 -首先根据雷达用户手册连接雷达并设置好您的电脑的IP地址。此时应该已知雷达的msop端口号和difop端口号,默认值为```msop-6699, difop-7788```。 如果不清楚上述内容,请查看雷达用户手册。 +根据雷达用户手册连接雷达, 并设置好您的电脑的IP地址。 + +此时应该已知雷达的msop端口号和difop端口号,默认值为```msop-6699, difop-7788```。 如果不清楚上述内容,请查看雷达用户手册。 ### 2.2 设置参数文件的common部分 @@ -19,7 +23,6 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap ``` 由于消息来源于在线雷达,因此请设置```msg_source=1```。 @@ -32,7 +35,6 @@ common: lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -44,13 +46,13 @@ lidar: 将 ```lidar_type``` 设置为LiDAR类型 。 - 设置 ```msop_port``` 和 ```difop_port``` 为雷达数据端口号。 ### 2.4设置配置文件的lidar-ros部分 ```yaml ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points diff --git a/doc/howto/how_to_record_and_offline_decode_rosbag.md b/doc/howto/how_to_record_and_offline_decode_rosbag.md index 46f67f15..bdb42c3f 100644 --- a/doc/howto/how_to_record_and_offline_decode_rosbag.md +++ b/doc/howto/how_to_record_and_offline_decode_rosbag.md @@ -2,15 +2,17 @@ ## 1 Introduction -This document will show you how to record and decode rosbag. Please make sure you have read the LiDAR user-guide and [Intro to parameters](../intro/parameter_intro.md) before reading this document. +This document illustrates how to record and decode rosbag. + +Please make sure you have read the LiDAR user-guide and [Intro to parameters](../intro/parameter_intro.md) before reading this document. ## 2 Record ### 2.1 Send packet to ROS -We suppose you are connecting an online LiDAR and you have already sent out the point cloud to ROS. If you have no idea about this, please read [Online connect lidar and send point cloud through ROS](how_to_online_send_point_cloud_ros.md) first. +Suppose that you have finished to sent out the point cloud to ROS. If you have no idea about this, please read [Online connect lidar and send point cloud through ROS](how_to_online_send_point_cloud_ros.md) first. -Actually, you can record the point cloud message now and you don't need to run the driver again when you off-line play the bag. But the disadvantage is also obvious that the point cloud message is very large. So normally we recommend to record packets rather than point cloud message. +Though we can record the point cloud message into a bag and play it, the bag will be very large. So it is recommended to record packets rather than point cloud message. ```yaml common: @@ -19,7 +21,6 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap ``` In order to record packets, set ```send_packet_ros = true```. @@ -28,22 +29,25 @@ In order to record packets, set ```send_packet_ros = true```. ```yaml ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points ``` -User can also adjust the packets topic by adjust the ```ros_send_packet_topic``` in *lidar-ros* part of the config file. This topic represent the topic of the msop, and the topic of the difop will be ```msop-topic_difop```. e.g., the default topic value is set to ```rslidar_packets```, so the msop topic is ```rslidar_packets``` and the difop topic is ```rslidar_packets_difop```. The command to record bag is listed below. +User may change the packets topic by changing the ```ros_send_packet_topic```. + +This topic represent the topic of the msop and difop. + +Below is the command to record bag. ```sh -rosbag record /rslidar_packets /rslidar_packets_difop -O bag +rosbag record /rslidar_packets -O bag ``` -**If you set send_packet_ros = true, both two kinds of packets will be sent to ROS. And you must record both of these two kinds of packets.** - ## 3 Offline Decode -We suppose you have recorded a rosbag which contains msop packets with the topic ```rslidar_packets``` and difop packets with the topic ```rslidar_packets_difop```. +Suppose you have recorded a rosbag which contains msop and difop packets with the topic ```rslidar_packets```. ### 3.1 Set up the common part of the config file @@ -54,12 +58,11 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap ``` -Since the packets message come from the ROS, set ```msg_source = 2```. +Since the packets come from the ROS, set ```msg_source = 2```. -We want to send point cloud to ROS so set ```send_point_cloud_ros = true```. +To send point cloud to ROS, set ```send_point_cloud_ros = true```. ### 3.2 Set up the lidar-driver part of the config file @@ -67,7 +70,6 @@ We want to send point cloud to ROS so set ```send_point_cloud_ros = true```. lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -83,12 +85,13 @@ Set the ```lidar_type``` to your LiDAR type. ```yaml ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points ``` -Set up the ```ros_recv_packet_topic``` to the ```msop``` topic in the rosbag. +Set up the ```ros_recv_packet_topic``` to the msop and difop topic in the rosbag. ### 3.4 Run diff --git a/doc/howto/how_to_record_and_offline_decode_rosbag_cn.md b/doc/howto/how_to_record_and_offline_decode_rosbag_cn.md index 04f8af5a..31d8fb83 100644 --- a/doc/howto/how_to_record_and_offline_decode_rosbag_cn.md +++ b/doc/howto/how_to_record_and_offline_decode_rosbag_cn.md @@ -2,15 +2,17 @@ ## 1 简介 -本文档将展示如何记录与解码rosbag。 在阅读这本文档之前请先阅读雷达用户手册与[参数简介](../intro/parameter_intro.md) 。 +本文档将展示如何记录与解码rosbag。 + +在阅读这本文档之前请先阅读雷达用户手册与[参数简介](../intro/parameter_intro.md) 。 ## 2 录包 ### 2.1 将packet发送至ROS -首先在线连接雷达并将点云发送至ROS。如果对此不太了解, 请先阅读 [在线连接雷达并发送点云到ROS](how_to_online_send_point_cloud_ros_cn.md) 。 +这里假设,已经可以在线连接雷达并将点云发送至ROS。如果对此不太了解, 请先阅读 [在线连接雷达并发送点云到ROS](how_to_online_send_point_cloud_ros_cn.md) 。 -现在可以直接录制点云消息,这样在离线播包时不需要再另外运行驱动程序解包。但这种方法会导致录制的包非常大。 因此,通常建议记录雷达packet数据,而不是记录点云数据。 +虽然也可以直接录制点云消息,但录制点云消息的包非常大,所以通常还是建议录制雷达packet数据。 ```yaml common: @@ -19,31 +21,31 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap ``` -​ 为了记录雷达packet, 需要设置 ```send_packet_ros = true```。 +​要录制雷达packet, 设置 ```send_packet_ros = true```。 ### 2.2 根据对应话题录包 ```yaml ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points ``` -用户可以通过调整参数文件的 *lidar-ros* 部分中的 ```ros_send_packet_topic``` 来调整发送的话题。 该话题表示msop的话题,而difop的话题为``` msop-topic_difop```。 例: 默认话题设置为 ```rslidar_packets```,因此msop话题为 ```rslidar_packets```,而difop的话题为 ```rslidar_packets_difop```。录包的指令如下所示。 +用户可以通过改变```ros_send_packet_topic``` 来改变发送的话题。这个话题包括MSOP和DIFOP包。 + +录包的指令如下所示。 ```bash -rosbag record /rslidar_packets /rslidar_packets_difop -O bag +rosbag record /rslidar_packets -O bag ``` -**如果将send_packet_ros设置为true,则两种数据包都将发送到ROS。 录包时必须同时记录这两种数据。** - ## 3 离线解码 -假设录制了一个rosbag,其中包含话题为 *rslidar_packets* 的msop数据包和话题为 *rslidar_packets_difop*的difop数据包。 +假设录制了一个rosbag,其中包含话题为 *rslidar_packets* 的msop和DIFOP数据包。 ### 3.1 设置文件的 common部分 @@ -54,10 +56,9 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap ``` -由于数据包消息来自ROS,因此设置 ```msg_source = 2``` 。 +数据包消息来自ROS,因此设置 ```msg_source = 2``` 。 将点云发送到ROS,因此设置 ```send_point_cloud_ros = true```。 @@ -67,7 +68,6 @@ common: lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -83,12 +83,13 @@ lidar: ```yaml ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points ``` -将 ```ros_recv_packet_topic``` 设置为rosbag中的```msop```数据的话题。 +将 ```ros_recv_packet_topic``` 设置为rosbag中的MSOP和DIFOP数据的话题。 ### 3.4 运行 diff --git a/doc/howto/how_to_switch_point_type.md b/doc/howto/how_to_switch_point_type.md index ed90b8c9..1a33e172 100644 --- a/doc/howto/how_to_switch_point_type.md +++ b/doc/howto/how_to_switch_point_type.md @@ -2,7 +2,13 @@ ## 1 Introduction -This document will show you how to switch the point type. The supported point type is listed in README. To switch the type, open the ```CMakeLists.txt``` in the project and check the top of the file. Remember to **rebuild** the project after changing the point type. +This document illustrates how to switch the point type. + +The supported point type is listed in README. + +To switch the type, open the ```CMakeLists.txt``` in the project and change the variable POINT_TYPE. + +Remember to **rebuild** the project after changing it. ```cmake #======================================= @@ -11,11 +17,11 @@ This document will show you how to switch the point type. The supported point ty set(POINT_TYPE XYZI) ``` - - ## 2 XYZI -The default point type is the pcl official type```pcl::PointXYZI```. Here is an example of transforming the ros point cloud to pcl point cloud. User can take this as an reference in their receiving program. +The default point type is the pcl official type```pcl::PointXYZI```. + +Here is an example to transform the ros point cloud to pcl point cloud. User can take this as an reference in his/her own program. ```c++ pcl::PointCloud::Ptr cloud_ptr (new pcl::PointCloud); @@ -23,14 +29,16 @@ pcl::fromROSMsg(ros_msg, *cloud_ptr); ``` - ## 3 XYZIRT -Since this is the custom pcl point type, user needs to add the definition of the point in the receiving program. The definition is shown below. +This is a customized point type. User needs add the definition of the point in his/her own programs. + +The definition is as below. ```c++ #include #include + struct RsPointXYZIRT { PCL_ADD_POINT4D; @@ -39,11 +47,12 @@ struct RsPointXYZIRT double timestamp = 0; EIGEN_MAKE_ALIGNED_OPERATOR_NEW } EIGEN_ALIGN16; + POINT_CLOUD_REGISTER_POINT_STRUCT(RsPointXYZIRT, (float, x, x)(float, y, y)(float, z, z)(uint8_t, intensity, intensity)(uint16_t, ring, ring)(double, timestamp, timestamp)) ``` -Then user can transform the ros point cloud to pcl point cloud. +User can transform the ros point cloud to pcl point cloud. ```c++ pcl::PointCloud::Ptr cloud_ptr (new pcl::PointCloud); diff --git a/doc/howto/how_to_switch_point_type_cn.md b/doc/howto/how_to_switch_point_type_cn.md index e55a43b1..038b755b 100644 --- a/doc/howto/how_to_switch_point_type_cn.md +++ b/doc/howto/how_to_switch_point_type_cn.md @@ -2,7 +2,9 @@ ## 1 简介 -本文档将会介绍如何切换点的类型。目前支持的类型在README中有列出。切换点的类型时,首先打开项目根目录下的```CMakeLists.txt```文件,在文件顶部便可以选择点的类型。在改变类型后,需要重新编译整个工程。 +本文档将会介绍如何切换点的类型。目前支持的类型在README中有列出。 + +在项目根目录下的```CMakeLists.txt```文件中设置POINT_TYPE变量。改变类型后,需要重新编译整个工程。 ```cmake #======================================= @@ -11,26 +13,25 @@ set(POINT_TYPE XYZI) ``` - - ## 2 XYZI -默认的点的类型是pcl的官方类型```pcl::PointXYZI```. 此处给出了一个将ros点云消息转换成pcl点云的例子,用户在编写ros点云接收端时可以作为参考。 +默认的点类型是pcl的官方类型```pcl::PointXYZI```. + +此处给出了一个将ros点云消息转换成pcl点云的例子,用户在编写ros点云接收端时可以作为参考。 ```c++ pcl::PointCloud::Ptr cloud_ptr (new pcl::PointCloud); pcl::fromROSMsg(ros_msg, *cloud_ptr); ``` - - ## 3 XYZIRT -由于这是速腾自定义的点的类型,用户需要在接收端程序添加对应的点的定义,点的定义如下所示。 +由于这是速腾的自定义点类型,用户需要在接收端程序添加对应的点的定义,点的定义如下所示。 ```c++ #include #include + struct RsPointXYZIRT { PCL_ADD_POINT4D; @@ -39,11 +40,12 @@ struct RsPointXYZIRT double timestamp = 0; EIGEN_MAKE_ALIGNED_OPERATOR_NEW } EIGEN_ALIGN16; + POINT_CLOUD_REGISTER_POINT_STRUCT(RsPointXYZIRT, (float, x, x)(float, y, y)(float, z, z)(uint8_t, intensity, intensity)(uint16_t, ring, ring)(double, timestamp, timestamp)) ``` -然后即可调用pcl的转换函数将ros点云转换为pcl点云。 +可调用pcl的转换函数将ros点云转换为pcl点云。 ```c++ pcl::PointCloud::Ptr cloud_ptr (new pcl::PointCloud); diff --git a/doc/howto/how_to_use_coordinate_transformation.md b/doc/howto/how_to_use_coordinate_transformation.md index fdc411a5..ca00ad3b 100644 --- a/doc/howto/how_to_use_coordinate_transformation.md +++ b/doc/howto/how_to_use_coordinate_transformation.md @@ -1,8 +1,8 @@ # How to use the coordinate transformation function ## 1 Introduction - - **rslidar_sdk** has the coordinate transformation function built inside and it can output the transformed point cloud directly, which can help users saving time to do transformation for point cloud (e.g. for RS128, it costs about 3~5ms to do transformation for one frame point cloud). This document will show you how to use the transformation function. + +This document illustrate how to use the transformation function, and output the transformed point cloud. ## 2 Dependency @@ -16,7 +16,7 @@ ## 3 Compile -To enable the transformation function, the option ```ENABLE_TRANSFORM``` needs to be set to ```ON``` during the cmake process. +To enable the transformation function, set the option ```ENABLE_TRANSFORM``` to be ```ON``` during the cmake process. - Compile directly @@ -39,7 +39,9 @@ To enable the transformation function, the option ```ENABLE_TRANSFORM``` needs t ## 4 Set up parameters -User needs to set up the hiding parameter```x, y, z, roll, pitch ,yaw ``` in lidar part of the config.yaml. Please check the [Intro to hiding parameters](../intro/hiding_parameters_intro.md) for more details. Here is an example of the config.yaml. +User needs to set up the hiding parameter```x, y, z, roll, pitch ,yaw ``` in lidar part of the config.yaml. + +Please check the [Intro to hiding parameters](../intro/hiding_parameters_intro.md) for more details. Here is an example of the config.yaml. ```yaml common: @@ -48,11 +50,9 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -60,14 +60,15 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false - x: 1 - y: 0 - z: 2.5 - roll: 0.1 - pitch: 0.2 - yaw: 1.57 + pcap_path: /home/robosense/lidar.pcap + x: 1 + y: 0 + z: 2.5 + roll: 0.1 + pitch: 0.2 + yaw: 1.57 ``` ## 5 Run -Run the program. \ No newline at end of file +Run the program. diff --git a/doc/howto/how_to_use_coordinate_transformation_cn.md b/doc/howto/how_to_use_coordinate_transformation_cn.md index 7c89a761..224044bc 100644 --- a/doc/howto/how_to_use_coordinate_transformation_cn.md +++ b/doc/howto/how_to_use_coordinate_transformation_cn.md @@ -2,13 +2,11 @@ ## 1 简介 -**rslidar_sdk** 提供了内置的坐标变换功能,可以直接输出经过坐标变换后的点云,显著节省了用户对点云进行坐标变换的操作耗时(128线雷达一帧点云坐标变换耗时约3~5ms)。本文档将指导用户如何使用rslidar_sdk的内置坐标变换功能, 输出经过变换后的点云。 - - +本文档将展示如何使用rslidar_sdk的内置坐标变换功能, 输出经过变换后的点云。 ## 2 依赖介绍 -若希望启用坐标变换功能,需要安装以下依赖。 +要启用坐标变换功能,需要安装以下依赖。 - Eigen3 @@ -20,7 +18,7 @@ ## 3 编译 -若希望启用坐标变换的功能,在编译程序时需要将```ENABLE_TRANSFORM```选项设置为```ON```. +要启用坐标变换的功能,编译程序时需要将```ENABLE_TRANSFORM```选项设置为```ON```. - 直接编译 @@ -43,7 +41,9 @@ ## 4 参数设置 -用户需要设置lidar部分的隐藏参数```x, y, z, roll, pitch ,yaw ``` ,更多的细节可以参考[隐藏参数介绍](../intro/hiding_parameters_intro.md)。此处为参数文件的一个示例,用户可根据实际情况配置。 +用户需要设置lidar部分的隐藏参数```x, y, z, roll, pitch ,yaw ``` 。 + +更多的细节可以参考[隐藏参数介绍](../intro/hiding_parameters_intro.md)。此处为参数文件的一个示例,用户可根据实际情况配置。 ```yaml common: @@ -52,11 +52,9 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -64,14 +62,15 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false - x: 1 - y: 0 - z: 2.5 - roll: 0.1 - pitch: 0.2 - yaw: 1.57 + pcap_path: /home/robosense/lidar.pcap + x: 1 + y: 0 + z: 2.5 + roll: 0.1 + pitch: 0.2 + yaw: 1.57 ``` ## 5 运行 -运行程序。 \ No newline at end of file +运行程序。 diff --git a/doc/howto/how_to_use_multi_cast_function.md b/doc/howto/how_to_use_multi_cast_function.md index 821bb8a2..7a24becb 100644 --- a/doc/howto/how_to_use_multi_cast_function.md +++ b/doc/howto/how_to_use_multi_cast_function.md @@ -2,15 +2,21 @@ ## 1 Introduction -This document will show you how to use rslidar_sdk to receive point cloud from the LiDAR working in multi-cast mode. +This document illustrates how to use rslidar_sdk to receive Lidar packets in multi-cast mode. -## 2 Steps (Linux) +This document is only the Linux platform. -Suppose the multi-cast address of LiDAR is ```224.1.1.1```. +## 2 Steps + +Suppose the multicast group address of LiDAR is ```224.1.1.1```. and the host address is ```192.168.1.102```. + +The host address should be in the same network with the Lidar. In other words, the host can ping to the Lidar. ### 2.1 Set up hiding parameters -User need to set up the hiding parameter ```multi_cast_address``` in lidar part of the config.yaml. Please check the [Intro to hiding parameters](../intro/hiding_parameters_intro.md) for more details. Here is an example of the config.yaml. +User need to set up the hiding parameter ```group_address``` in lidar part of the config.yaml. Please check the [Intro to hiding parameters](../intro/hiding_parameters_intro.md) for more details. + +Here is an example of the config.yaml. ```yaml common: @@ -19,12 +25,11 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap lidar: - driver: lidar_type: RS128 - frame_id: /rslidar - multi_cast_address: 224.1.1.1 + group_address: 224.1.1.1 + host_address: 192.168.1.102 msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -32,29 +37,6 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false - -``` - - - -### 2.2 Set up the PC ip address - -In multi-cast case, the ip address of PC has no limit but user needs to make sure **the PC and LiDAR are in the same net work**, which means PC can ping to LiDAR. - -### 2.3 Add the PC to the group - -Use the following command to check the PC's ethernet card name: - -```bash -ifconfig -``` - -![ethernet](../img/ethernet.png) - -As the figure shows, the ethernet card name is ```enp2s0```. Then execute the following command to add the PC to the group (replace the ```enp2s0``` with your ethernet card name): - -``` -sudo route add -net 224.0.0.0/4 dev enp2s0 ``` ### 2.4 Run diff --git a/doc/howto/how_to_use_multi_cast_function_cn.md b/doc/howto/how_to_use_multi_cast_function_cn.md index b7eee5f8..26267e2e 100644 --- a/doc/howto/how_to_use_multi_cast_function_cn.md +++ b/doc/howto/how_to_use_multi_cast_function_cn.md @@ -4,13 +4,15 @@ 本文档将演示如何使用rslidar_sdk来接收组播模式下的雷达点云。 -## 2 步骤 (Linux) +## 2 步骤 -假设雷达的组播地址设置为```224.1.1.1```。 +假设雷达的组播地址设置为```224.1.1.1```, 主机地址为```192.168.1.102```。主机地址应该与雷达地址在同一网段,也就是说,主机能ping通雷达。 ### 2.1 设置隐藏参数 -用户首先需要将lidar部分的隐藏参数```multi_cast_address```设置为雷达的组播地址, 更多的细节可以参考[隐藏参数介绍](../intro/hiding_parameters_intro.md),此处为参数文件的一个示例,用户可根据实际情况配置。 +将lidar部分的隐藏参数```multi_cast_address```设置为雷达的组播地址, 更多的细节可以参考[隐藏参数介绍](../intro/hiding_parameters_intro.md)。 + +如下是参数文件的一个示例,用户可根据实际情况配置。 ```yaml common: @@ -19,12 +21,11 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap lidar: - driver: lidar_type: RS128 - frame_id: /rslidar - multi_cast_address: 224.1.1.1 + group_address: 224.1.1.1 + host_address: 192.168.1.102 msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -32,29 +33,6 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false - -``` - - - -### 2.2 设置电脑ip地址 - -在组播模式下,电脑的ip地址并没有严格限制,但用户需要确保**电脑与雷达的网络互通**, 也就是电脑必须能够ping通雷达。 - -### 2.3 将PC添加到组内 - -使用以下指令查看电脑的网卡名: - -```bash -ifconfig -``` - -![ethernet](../img/ethernet.png) - -如图所示,网卡名为```enp2s0```。 然后运行以下指令将电脑加入组内(将指令中的```enp2s0```替换为用户电脑的网卡名: - -``` -sudo route add -net 224.0.0.0/4 dev enp2s0 ``` ### 2.4 运行 diff --git a/doc/howto/how_to_use_multi_lidars.md b/doc/howto/how_to_use_multi_lidars.md index 5e2eec3d..7e3e5619 100644 --- a/doc/howto/how_to_use_multi_lidars.md +++ b/doc/howto/how_to_use_multi_lidars.md @@ -2,13 +2,19 @@ ## 1 Introduction -This document will show you how to send out multi-LiDARs point cloud with only one driver running. Theoretically, one driver can decoder unlimited number of LiDARs at the same time. For convenient, we will use three LiDARs as an example. Please make sure you have read the LiDAR user-guide and [Intro to parameters](../intro/parameter_intro.md) before reading this document. +This document illustrates how to send out multi-LiDARs point cloud with only one driver instance. + +Theoretically, one instance can decode unlimited number of LiDARs at the same time. Here we use three LiDARs. + +Please make sure you have read the LiDAR user-guide and [Intro to parameters](../intro/parameter_intro.md) before reading this document. ## 2 Online connect with multi-LiDARs ### 2.1 Get the data port number -Please follow the instructions in LiDAR user-guide to connect the LiDAR and set up your computer's ip address. At this time, you should have already known msop port number and difop port number for each LiDAR. If you have no idea about what it is, please check the LiDAR user-guide first. +Please follow the instructions in LiDAR user-guide, to connect to the LiDAR and set up your computer's ip address. + +At this time, you should have already known msop and difop port numbers of each LiDAR. If you have no idea about this, please check the LiDAR user-guide. ### 2.2 Set up the common part of the config file @@ -19,12 +25,11 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap ``` Since the message come from the LiDAR, set ```msg_source = 1```. -Send point cloud to ROS so set ```send_point_cloud_ros = true```. +Send point cloud to ROS, so set ```send_point_cloud_ros = true```. ### 2.3 Set up the lidar part of the config file @@ -32,7 +37,6 @@ Send point cloud to ROS so set ```send_point_cloud_ros = true```. lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -41,6 +45,7 @@ lidar: max_distance: 200 use_lidar_clock: false ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /middle/rslidar_packets ros_send_packet_topic: /middle/rslidar_packets ros_send_point_cloud_topic: /middle/rslidar_points @@ -55,7 +60,6 @@ lidar: packet_send_ip: 127.0.0.1 - driver: lidar_type: RSBP - frame_id: /rslidar msop_port: 1990 difop_port: 1991 start_angle: 0 @@ -64,6 +68,7 @@ lidar: max_distance: 200 use_lidar_clock: false ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /left/rslidar_packets ros_send_packet_topic: /left/rslidar_packets ros_send_point_cloud_topic: /left/rslidar_points @@ -78,7 +83,6 @@ lidar: packet_send_ip: 127.0.0.1 - driver: lidar_type: RSBP - frame_id: /rslidar msop_port: 2010 difop_port: 2011 start_angle: 0 @@ -87,6 +91,7 @@ lidar: max_distance: 200 use_lidar_clock: false ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /right/rslidar_packets ros_send_packet_topic: /right/rslidar_packets ros_send_point_cloud_topic: /right/rslidar_points @@ -122,12 +127,11 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap ``` -Since the packets message come from the ROS, set ```msg_source = 2```. +Since the packet messages come from the ROS, set ```msg_source = 2```. -We want to send point cloud to ROS so set ```send_point_cloud_ros = true```. +Send point cloud to ROS, so set ```send_point_cloud_ros = true```. ### 3.2 Set up the lidar part of the config file @@ -135,7 +139,6 @@ We want to send point cloud to ROS so set ```send_point_cloud_ros = true```. lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -144,6 +147,7 @@ lidar: max_distance: 200 use_lidar_clock: false ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /middle/rslidar_packets ros_send_packet_topic: /middle/rslidar_packets ros_send_point_cloud_topic: /middle/rslidar_points @@ -158,7 +162,6 @@ lidar: packet_send_ip: 127.0.0.1 - driver: lidar_type: RSBP - frame_id: /rslidar msop_port: 1990 difop_port: 1991 start_angle: 0 @@ -167,6 +170,7 @@ lidar: max_distance: 200 use_lidar_clock: false ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /left/rslidar_packets ros_send_packet_topic: /left/rslidar_packets ros_send_point_cloud_topic: /left/rslidar_points @@ -181,7 +185,6 @@ lidar: packet_send_ip: 127.0.0.1 - driver: lidar_type: RSBP - frame_id: /rslidar msop_port: 2010 difop_port: 2011 start_angle: 0 @@ -190,6 +193,7 @@ lidar: max_distance: 200 use_lidar_clock: false ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /right/rslidar_packets ros_send_packet_topic: /right/rslidar_packets ros_send_point_cloud_topic: /right/rslidar_points @@ -206,10 +210,11 @@ lidar: Set ```lidar_type``` for each LiDAR. -Set the ```ros_recv_packet_topic``` for each LiDAR which need to corresbond to the topic names in rosbag. +Set the ```ros_recv_packet_topic``` for each LiDAR. It is from the rosbag. Set ```ros_send_point_cloud_topic``` for each LiDAR. ### 3.3 Run -Run the program & play rosbag. +Run the program and play rosbag. + diff --git a/doc/howto/how_to_use_multi_lidars_cn.md b/doc/howto/how_to_use_multi_lidars_cn.md index a9172d79..f6de9265 100644 --- a/doc/howto/how_to_use_multi_lidars_cn.md +++ b/doc/howto/how_to_use_multi_lidars_cn.md @@ -2,13 +2,17 @@ ## 1 简介 -本文档将展示如何在仅运行一个驱动程序的情况解析并发送多台雷达的点云。理论上,一个驱动可以同时解码无限数量的雷达。为了方便起见,本文档将会使用三个雷达作为示例。在阅读本文档之前, 请确保已经阅读过雷达用户手册和[参数简介](../intro/parameter_intro.md) 。 +本文档将展示,在一个驱动程序实例中,解析并发送多台雷达的点云。这里使用三个雷达作为示例。 + +在阅读本文档之前, 请确保已经阅读过雷达用户手册和[参数简介](../intro/parameter_intro.md) 。 ## 2 在线解析多雷达 ### 2.1 获取数据端口号 -首先将三个雷达与计算机正确连接,此时应已知每个LiDAR的msop端口号 与 difop端口号。 如果不清楚上述内容,请查看雷达用户手册。 +将三个雷达与主机正确连接。 + +此时应改已经知道每个LiDAR的msop端口号与difop端口号。 如果不知道,请查看雷达用户手册。 ### 2.2 设置参数文件的common部分 @@ -19,12 +23,11 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap ``` -由于消息来源于在线雷达,因此请设置```msg_source=1```。 +消息来源于在线雷达,因此请设置```msg_source=1```。 -将点云发送到ROS以查看,因此设置 ```send_point_cloud_ros = true``` 。 +将点云发送到ROS,因此设置 ```send_point_cloud_ros = true``` 。 ### 2.3 设置配置文件中的lidar部分 @@ -32,7 +35,6 @@ common: lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -41,6 +43,7 @@ lidar: max_distance: 200 use_lidar_clock: false ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /middle/rslidar_packets ros_send_packet_topic: /middle/rslidar_packets ros_send_point_cloud_topic: /middle/rslidar_points @@ -55,7 +58,6 @@ lidar: packet_send_ip: 127.0.0.1 - driver: lidar_type: RSBP - frame_id: /rslidar msop_port: 1990 difop_port: 1991 start_angle: 0 @@ -64,6 +66,7 @@ lidar: max_distance: 200 use_lidar_clock: false ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /left/rslidar_packets ros_send_packet_topic: /left/rslidar_packets ros_send_point_cloud_topic: /left/rslidar_points @@ -78,7 +81,6 @@ lidar: packet_send_ip: 127.0.0.1 - driver: lidar_type: RSBP - frame_id: /rslidar msop_port: 2010 difop_port: 2011 start_angle: 0 @@ -87,6 +89,7 @@ lidar: max_distance: 200 use_lidar_clock: false ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /right/rslidar_packets ros_send_packet_topic: /right/rslidar_packets ros_send_point_cloud_topic: /right/rslidar_points @@ -101,11 +104,11 @@ lidar: packet_send_ip: 127.0.0.1 ``` -为每个雷达类型设置型号```lidar_type```。 +为每个雷达设置雷达类型```lidar_type```。 -为每个雷达设置对应的端口号 ```msop_port``` 和```difop_port``` 。 +为每个雷达设置端口号 ```msop_port``` 和```difop_port``` 。 -为每个雷达设置点云发送的话题```ros_send_point_cloud_topic```。 +为每个雷达设置发送点云的话题```ros_send_point_cloud_topic```。 ### 2.4 运行 @@ -122,10 +125,9 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap ``` -由于数据包消息来自ROS,因此设置 ```msg_source = 2``` 。 +数据包消息来自ROS,因此设置 ```msg_source = 2``` 。 将点云发送到ROS,因此设置 ```send_point_cloud_ros = true```。 @@ -135,7 +137,6 @@ common: lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -144,6 +145,7 @@ lidar: max_distance: 200 use_lidar_clock: false ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /middle/rslidar_packets ros_send_packet_topic: /middle/rslidar_packets ros_send_point_cloud_topic: /middle/rslidar_points @@ -158,7 +160,6 @@ lidar: packet_send_ip: 127.0.0.1 - driver: lidar_type: RSBP - frame_id: /rslidar msop_port: 1990 difop_port: 1991 start_angle: 0 @@ -167,6 +168,7 @@ lidar: max_distance: 200 use_lidar_clock: false ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /left/rslidar_packets ros_send_packet_topic: /left/rslidar_packets ros_send_point_cloud_topic: /left/rslidar_points @@ -181,7 +183,6 @@ lidar: packet_send_ip: 127.0.0.1 - driver: lidar_type: RSBP - frame_id: /rslidar msop_port: 2010 difop_port: 2011 start_angle: 0 @@ -190,6 +191,7 @@ lidar: max_distance: 200 use_lidar_clock: false ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /right/rslidar_packets ros_send_packet_topic: /right/rslidar_packets ros_send_point_cloud_topic: /right/rslidar_points @@ -204,11 +206,11 @@ lidar: packet_send_ip: 127.0.0.1 ``` -为每个雷达类型设置型号```lidar_type```。 +为每个雷达设置雷达类型```lidar_type```。 -为每个雷达设置接收的packet话题名```ros_recv_packet_topic```。 +为每个雷达设置接收的packet话题```ros_recv_packet_topic```。 -为每个雷达设置点云发送的话题```ros_send_point_cloud_topic```。 +为每个雷达设置发送点云的话题```ros_send_point_cloud_topic```。 ### 3.3 运行 diff --git a/doc/howto/how_to_use_protobuf_function.md b/doc/howto/how_to_use_protobuf_function.md index d36101e5..51d5e6b3 100644 --- a/doc/howto/how_to_use_protobuf_function.md +++ b/doc/howto/how_to_use_protobuf_function.md @@ -2,17 +2,17 @@ ## 1 Introduction -Suppose there are two computers, PC-A and PC-B and they are far away from each other. You connect LiDAR with PC-A and for some reasons, you want to use point cloud message in PC-B. At this time, you may need to use the protobuf functions. Typically, there are two ways to achieve this goal. +Suppose there are two computers, PC-A and PC-B, and they are far away from each other. For some reasons, you connect LiDAR with PC-A and use point cloud message in PC-B. To achieve this, you may need to use the protobuf functions. Typically, there are two ways to do this. - PC-A send out the packets message to PC-B. PC-B receive the packet message and decode it , then PC-B get the point cloud message and use it. - PC-A decode the packets message, get the point cloud and send out the point cloud message to PC-B. PC-B receive the point cloud message and use it directly. -We offer both of these two ways but we recommend first method rather than second method because the point cloud message is very large and it may take up your bandwidth. +This first way is recommended, because the point cloud message is very large and it may take up your bandwidth. ## 2 Send & Receive packets through Protobuf-UDP - We suppose you have already read [Intro to parameters](../intro/parameter_intro.md) and you already have a basic idea about the config file. +You are supposed to have already read [Intro to parameters](../intro/parameter_intro.md) and already have a basic idea about the config file. ### 2.1 PC-A(Sender) @@ -23,18 +23,16 @@ common: send_point_cloud_ros: false send_packet_proto: true send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap ``` Since the message come from the LiDAR, set ```msg_source = 1```. -Send packets through Protobuf-UDP so set ```send_packet_proto = true```. +Send packets through Protobuf-UDP, so set ```send_packet_proto = true```. ```yaml lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -43,6 +41,7 @@ lidar: max_distance: 200 use_lidar_clock: false ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points @@ -57,9 +56,9 @@ lidar: packet_send_ip: 127.0.0.1 ``` -Set the ```lidar_type``` to your LiDAR type. +Set the ```lidar_type``` for your LiDAR. -Set the ```msop_port``` and ```difop_port``` to your LiDAR's port number. +Set the ```msop_port``` and ```difop_port``` for your LiDAR. Set the ```msop_send_port```, ```difop_send_port```, and ```packet_send_ip```. @@ -72,18 +71,16 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap ``` Since the packets message come from protobuf-UDP, set ```msg_source = 4```. -Send point cloud to ROS so set ```send_point_cloud_ros = true```. +Send point cloud to ROS, so set ```send_point_cloud_ros = true```. ```yaml lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -92,6 +89,7 @@ lidar: max_distance: 200 use_lidar_clock: false ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points @@ -106,15 +104,15 @@ lidar: packet_send_ip: 127.0.0.1 ``` -Set the ```lidar_type``` to your LiDAR type. +Set the ```lidar_type``` for your LiDAR type. -Make sure the PC-B's ip address is same as the ```packet_send_ip``` set in PC-A's config.yaml. +Make sure the PC-B's ip address is same with the ```packet_send_ip``` set in PC-A's config.yaml. Set the ```msop_recv_port``` and ```difop_recv_port``` to be same with the ```msop_send_port``` and ```difop_send_port``` set in PC-A's config.yaml. ## 3 Send & receive point cloud through Protobuf-UDP -We suppose you have already read [Intro to parameters](../intro/parameter_intro.md) and you already have a basic idea about the config file. +You are supposed to have already read [Intro to parameters](../intro/parameter_intro.md) and have a basic idea about the config file. ### 3.1 PC-A(Sender) @@ -125,18 +123,16 @@ common: send_point_cloud_ros: false send_packet_proto: false send_point_cloud_proto: true - pcap_path: /home/robosense/lidar.pcap ``` Since the message come from the LiDAR, set ```msg_source = 1```. -Send point cloud through Protobuf-UDP so set ```send_point_cloud_proto = true```. +Send point cloud through Protobuf-UDP, so set ```send_point_cloud_proto = true```. ```yaml lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -145,6 +141,7 @@ lidar: max_distance: 200 use_lidar_clock: false ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points @@ -159,9 +156,9 @@ lidar: packet_send_ip: 127.0.0.1 ``` -Set the ```lidar_type``` to your LiDAR type. +Set the ```lidar_type``` for your LiDAR. -Set the ```msop_port``` and ```difop_port``` to your LiDAR's port number. +Set the ```msop_port``` and ```difop_port``` for your LiDAR. Set the ```point_cloud_send_port``` and ```point_cloud_send_ip``. @@ -174,18 +171,16 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap ``` Since the point cloud message come from protobuf-UDP, set ```msg_source = 5```. -Send point cloud to ROS so set ```send_point_cloud_ros = true```. +Send point cloud to ROS, so set ```send_point_cloud_ros = true```. ```yaml lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -194,6 +189,7 @@ lidar: max_distance: 200 use_lidar_clock: false ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points @@ -208,7 +204,7 @@ lidar: packet_send_ip: 127.0.0.1 ``` -Make sure the PC-B's ip address is same as the ```point_cloud_send_ip``` set in PC-A's config.yaml. +Make sure the PC-B's ip address is same with the ```point_cloud_send_ip``` set in PC-A's config.yaml. Set the ```point_cloud_recv_port``` to be same with the ```point_cloud_send_port``` set in PC-A's config.yaml. diff --git a/doc/howto/how_to_use_protobuf_function_cn.md b/doc/howto/how_to_use_protobuf_function_cn.md index ffb8dde3..4888ccf5 100644 --- a/doc/howto/how_to_use_protobuf_function_cn.md +++ b/doc/howto/how_to_use_protobuf_function_cn.md @@ -2,17 +2,17 @@ ## 1 简介 -假设有两台计算机,PC-A和PC-B,并且它们彼此相距很远。 将LiDAR与PC-A连接,由于某些原因,用户想在PC-B中使用点云消息。 此时,可能需要使用protobuf功能。 通常,有两种方法可以实现此目标。 +假设有两台计算机,PC-A和PC-B,并且它们彼此相距很远。 处于某些原因,LiDAR与PC-A连接,而用户想在PC-B中使用点云消息。这时需要使用protobuf功能。 通常有两种方法可以达到这个目的。 - PC-A将雷达packet消息发送到PC-B。 PC-B收到雷达packet消息并对其进行解码,然后PC-B获得点云消息并使用它。 - PC-A解码雷达packet消息,获取点云并将点云消息发送到PC-B。 PC-B收到点云消息并直接使用。 -rslidar_sdk提供这两种方式,但是通常建议使用第一种方法,因为点云消息非常大,对带宽有较高要求。 +一般建议使用第一种方法,因为点云消息非常大,对带宽有较高要求。 ## 2 通过Protobuf-UDP发送和接收 packets -​ 首先请阅读[参数简介](.. / intro / parameter_intro.md),了解基本的参数配置。 +​请阅读[参数简介](.. / intro / parameter_intro.md),了解基本的参数配置。 ### 2.1 PC-A(发送端) @@ -23,10 +23,9 @@ common: send_point_cloud_ros: false send_packet_proto: true send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap ``` -由于消息来源于在线雷达,因此请设置```msg_source=1```。 +消息来源于在线雷达,因此请设置```msg_source=1```。 将packet数据通过Protobuf-UDP发出,因此设置 ```send_packet_proto = true``` 。 @@ -34,7 +33,6 @@ common: lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -43,6 +41,7 @@ lidar: max_distance: 200 use_lidar_clock: false ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points @@ -73,10 +72,9 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap ``` -由于packet消息来源于protobuf-UDP,因此设置 ```msg_source = 4``` 。 +packet消息来源于protobuf-UDP,因此设置 ```msg_source = 4``` 。 将点云发送到ROS以查看,因此设置 ```send_point_cloud_ros = true``` 。 @@ -84,7 +82,6 @@ common: lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -93,6 +90,7 @@ lidar: max_distance: 200 use_lidar_clock: false ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points @@ -126,10 +124,9 @@ common: send_point_cloud_ros: false send_packet_proto: false send_point_cloud_proto: true - pcap_path: /home/robosense/lidar.pcap ``` -由于消息来源于在线雷达,因此请设置```msg_source=1```。 +消息来源于在线雷达,因此请设置```msg_source=1```。 将点云数据通过Protobuf-UDP发出,因此设置 ```send_point_cloud_proto = true``` 。 @@ -137,7 +134,6 @@ common: lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -146,6 +142,7 @@ lidar: max_distance: 200 use_lidar_clock: false ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points @@ -162,7 +159,6 @@ lidar: 将 ```lidar_type``` 设置为LiDAR类型 。 - 设置 ```msop_port``` 和 ```difop_port``` 为雷达数据端口号。 设置 ```point_cloud_send_port``` 和 ```point_cloud_send_ip```. @@ -176,18 +172,16 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap ``` -由于点云消息来源于protobuf-UDP,因此设置 ```msg_source = 5``` 。 +点云消息来源于protobuf-UDP,因此设置 ```msg_source = 5``` 。 -将点云发送到ROS以查看,因此设置 ```send_point_cloud_ros = true``` 。 +将点云发送到ROS,因此设置 ```send_point_cloud_ros = true``` 。 ```yaml lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -196,6 +190,7 @@ lidar: max_distance: 200 use_lidar_clock: false ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points @@ -210,7 +205,7 @@ lidar: packet_send_ip: 127.0.0.1 ``` -确认PC-B的ip地址与PC-A的配置文件中设置的```point_cloud_send_ip```一致。 +确认PC-B的ip地址, 与PC-A的配置文件中设置的```point_cloud_send_ip```一致。 将```point_cloud_recv_port```与PC-A的配置文件中设置的```point_cloud_send_port```设置为一致。 diff --git a/doc/intro/hiding_parameters_intro.md b/doc/intro/hiding_parameters_intro.md index d733a1ef..0d5f5bd2 100644 --- a/doc/intro/hiding_parameters_intro.md +++ b/doc/intro/hiding_parameters_intro.md @@ -1,7 +1,8 @@ # Introduction to hidden parameters -In order to make the config file as simple as possible, we selectively hide some of the parameters and give them a default value in the program. If not added to ```config.yaml```, the default values will be used. This document explains the meanings of these these hidden parameters. +In order to make the configuration file as simple as possible, we hide some parameters and use default values for them. +This document explains the meanings of these hidden parameters. ## 1 common @@ -12,24 +13,14 @@ common: send_point_cloud_ros: false send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap - pcap_repeat: true - pcap_rate: 1 ``` -- ```pcap_repeat``` -- The default value is ```true``` , you can add it back and set to false to prevent pcap read repeatedly. - -- ```pcap_rate``` -- The default value is ```1``` and the point cloud frequency is about 10hz. The larger the value is set, the faster the pcap bag is played. - - - ## 2 lidar ```yaml lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -37,14 +28,17 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false + pcap_path: /home/robosense/lidar.pcap + pcap_repeat: true + pcap_rate: 1 + config_from_file: false angle_path: /home/robosense/angle.csv - is_dense: true + dense_points: false split_frame_mode: 1 - cut_angle: 0 - num_pkts_split: 1 + split_angle: 0 + num_blks_split: 1 wait_for_difop: true - saved_by_rows: false - multi_cast_address: 0.0.0.0 + group_address: 0.0.0.0 host_address: 0.0.0.0 x: 0 y: 0 @@ -52,20 +46,25 @@ lidar: roll: 0 pitch: 0 yaw: 0 + use_vlan: false + use_someip: false ``` -- ```angle_path``` -- The path of the angle.csv. For latest version of LiDARs, this parameter can be ignored. -- ```is_dense``` -- Whether to discard NAN points. discard if ```true```, reserve if ```false```. The default value is ```false```. -- ```split_frame_mode``` -- The mode to split the LiDAR frames. Default value is ```1```. - - 1 -- Spliting frames depending on the cut_angle - - 2 -- Spliting frames depending on a fixed number of packets - - 3 -- Spliting frames depending on num_pkts_split -- ```cut_angle``` -- The angle(degree) to split frames. Only be used when ```split_frame_mode = 1```. The default value is ```0```. -- ```num_pkts_split``` -- The number of packets in one frame. Only be used when ```split_frame_mode = 3```. -- ```wait_for_difop``` -- If set to false, the driver will not wait for difop packet and send out the point cloud immediately. The default value is ```true```. -- ```saved_by_rows``` -- The default point cloud is stored in **column major order**, which means if there is a point msg.point_cloud_ptr->at(i) , the next point on the same ring should be msg.point_cloud_ptr->at(i+msg.height). If this parameter is set to ```true``` , the point cloud will be stored in **row major order**. -- ```multi_cast_address``` -- If use multi-cast function, this parameter need to be set correctly. For more details, please refer to [Multi-Cast](../howto/how_to_use_multi_cast_function.md) -- ```host_address``` -- If the host receives packets from multiple lidars via different IP addresses, use this parameter to specify destination ip of the lidar. -- ```x, y, z, roll, pitch, yaw ``` -- The parameters to do cooridiante transformation. If the coordinate transformation function is enabled in driver core, the output point cloud will be transformed based on these parameters. For more details, please refer to [Coordinate Transformation](../howto/how_to_use_coordinate_transformation.md) -- ```use_vlan``` -- Whether to use vlan. The default value is false. Generally, after the VLAN NIC is configured, the VLAN fields in the data packets are automatically filtered out after the data passes through the VLAN NIC. This does not need to be set to true in this case. Set this parameter to true only when the recevied data contains the VLAN field. For example, pcap data that is not recorded by the VLAN NIC. -- ```use_someip``` -- Whether to use someip, default is false. Set this parameter to true if the packet contains the SOME/IP field. +- ```pcap_repeat``` -- The default value is ```true```. Set it to ```false``` to prevent play pcap repeatedly. +- ```pcap_rate``` -- The default value is ```1```. The frequency of point cloud is about 10hz. The larger the value is, the faster the pcap bag is played. +- ```config_from_file``` -- Whether to read Lidar configuration from file. Only used for debug purpose, and can be ignored. +- ```angle_path``` -- The path of the angle.csv. Only used for debug purpose and can be ignored. +- ```dense_points``` -- Whether to discard NAN points. Discard if ```true```, reserve if ```false```. The default value is ```false```. +- ```split_frame_mode``` -- The way to split the LiDAR frames. Default value is ```1```. + - 1 -- Split frame depending on the split_angle + - 2 -- Split frame depending on a fixed number of blocks + - 3 -- Split frame depending on num_blks_split + +- ```split_angle``` -- The angle(in degree) to split frames. Only be used when ```split_frame_mode = 1```. The default value is ```0```. +- ```num_blks_split``` -- The number of blocks in one frame. Only be used when ```split_frame_mode = 3```. +- ```wait_for_difop``` -- If ```false```, the driver will not wait for difop packet(including lidar configuration data, especially angle data to calculate x, y, z), and send out the point cloud immediately. The default value is ```true```. +- ```group_address``` -- If use multi-cast function, this parameter needs to be set correctly. For more details, please refer to [Multi-Cast](../howto/how_to_use_multi_cast_function.md) +- ```host_address``` -- Needed in two conditions. If the host receives packets from multiple Lidars via different IP addresses, use this parameter to specify destination IPs of the Lidars; If group_address is set, it should be set, so it will be joined into the multicast group. +- ```x, y, z, roll, pitch, yaw ``` -- The parameters to do coordinate transformation. If the coordinate transformation function is enabled in driver core, the output point cloud will be transformed based on these parameters. For more details, please refer to [Coordinate Transformation](../howto/how_to_use_coordinate_transformation.md) +- ```use_vlan``` -- Whether to use VLAN. The default value is ```false```. This parameter is only needed for pcap file. If it contains packets with VLAN layer, ```use_vlan``` should set to true. In the case of online Lidar, the VLAN layer is stripped by the protocol layer, so use_vlan can be ignored. +- ```use_someip``` -- Whether to use SOME/IP. The default value is ```false```. Set this parameter to ```true``` if the packet contains the SOME/IP field. diff --git a/doc/intro/hiding_parameters_intro_cn.md b/doc/intro/hiding_parameters_intro_cn.md index 140aaebf..d920f5b9 100644 --- a/doc/intro/hiding_parameters_intro_cn.md +++ b/doc/intro/hiding_parameters_intro_cn.md @@ -1,6 +1,8 @@ # 隐藏参数介绍 -为了让参数配置文件尽可能简洁,我们选择隐藏了部分用户不常用到的参数并在程序内给予了它们默认值。 本文档将详细介绍这些隐藏参数,用户可自行选择是否要将它们添加回参数文件内。 +为了使配置文件config.yaml尽可能简洁,我们隐藏了部分不常用的参数,在代码中使用默认值。 + +本文档将详细介绍这些隐藏参数。用户可根据需要,将它们加入参数文件,重新设置。 ## 1 common @@ -11,39 +13,32 @@ common: send_point_cloud_ros: false send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap - pcap_repeat: true - pcap_rate: 1 ``` -- ```pcap_repeat``` -- 默认值为true, 用户可将其设置为false来禁用pcap循环播放功能。 - -- ```pcap_rate``` -- 默认值为1,点云频率约为10hz。 用户可调节此参数来控制pcap播放速度,设置的值越大,pcap播放速度越快。 - - - ## 2 lidar ```yaml lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 + pcap_path: /home/robosense/lidar.pcap + pcap_repeat: true + pcap_rate: 1 start_angle: 0 end_angle: 360 min_distance: 0.2 max_distance: 200 use_lidar_clock: false + config_from_file: false angle_path: /home/robosense/angle.csv - is_dense: true + dense_points: true split_frame_mode: 1 - cut_angle: 0 - num_pkts_split: 1 + split_angle: 0 + num_blks_split: 1 wait_for_difop: true - saved_by_rows: false - multi_cast_address: 0.0.0.0 + group_address: 0.0.0.0 host_address: 0.0.0.0 x: 0 y: 0 @@ -51,21 +46,25 @@ lidar: roll: 0 pitch: 0 yaw: 0 + use_vlan: false + use_someip: false ``` +- ```pcap_repeat``` -- 默认值为true, 用户可将其设置为false来禁用pcap循环播放功能。 +- ```pcap_rate``` -- 默认值为1,点云频率约为10hz。 用户可调节此参数来控制pcap播放速度,设置的值越大,pcap播放速度越快。 +- ```config_from_file``` -- 默认值为false, 是否从外参文件读入雷达配置信息,仅用于调试,可忽略。 - ```angle_path``` -- angle.csv外参文件的路径,仅用于调试,可忽略。 -- ```is_dense``` -- 输出的点云中是否剔除NAN points。```true```为剔除,```false```为不剔除。默认值为```false```。 +- ```dense_points``` -- 默认值为false。输出的点云中是否剔除NAN points。```true```为剔除,```false```为不剔除。 - ```split_frame_mode``` -- 分帧模式设置,默认值为```1```。 - 1 -- 角度分帧 - - 2 -- 固定包数分帧 - - 3 -- 自定义包数分帧 -- ```cut_angle``` -- 用于分帧的角度(单位为度), 在```split_frame_mode = 1``` 时才生效,默认值为```0```。 -- ```num_pkts_split``` -- 用于分帧的包数,在 ```split_frame_mode = 3```时才生效,默认值为1。 -- ```wait_for_difop``` -- 若设置为false, 驱动将不会等待difop包而是立即解析并发出点云。 默认值为```true```,也就是必须要有difop包才会进行点云解析。 -- ```saved_by_rows``` -- 点云的默认储存方式为```按列储存```,也就是说假设有一个点msg.point_cloud_ptr->at(i) ,那么与这个点同一行的下一个点应该为msg.point_cloud_ptr->at(i+msg.height)。如果此参数设置为```true```,那么输出的点云将会```按行储存```。 -- ```multi_cast_address``` -- 如果雷达为组播模式,此参数需要被设置为组播的地址。具体使用方式可以参考 [组播模式](../howto/how_to_use_multi_cast_function_cn.md) 。 -- ```host_address``` -- 如果主机上通过多个IP地址接收多个雷达的数据,则可以将此参数指定为雷达的目标IP。 + - 2 -- 固定block数分帧 + - 3 -- 自定义block数分帧 +- ```split_angle``` -- 用于分帧的角度(单位为度), 在```split_frame_mode = 1``` 时才生效,默认值为```0```。 +- ```num_blks_split``` -- 用于分帧的包数,在 ```split_frame_mode = 3```时才生效,默认值为1。 +- ```wait_for_difop``` -- 若设置为false, 驱动将不会等待DIFOP包(包含配置数据,尤其是角度信息),而是立即解析MSOP包并发出点云。 默认值为```true```,也就是必须要有DIFOP包才会进行点云解析。 +- ```group_address``` -- 如果雷达为组播模式,此参数需要被设置为组播的地址。具体使用方式可以参考 [组播模式](../howto/how_to_use_multi_cast_function_cn.md) 。 +- ```host_address``` -- 有两种情况需要这个选项。如果主机上通过多个IP地址接收多个雷达的数据,则可以将此参数指定为雷达的目标IP;如果设置了group_address,那也需要设置host_address,以便将这个IP地址的网卡加入组播组。 - ```x, y, z, roll, pitch, yaw ``` -- 坐标变换参数,若启用了内核的坐标变换功能,将会使用此参数输出经过变换后的点云。x, y, z, 单位为```米```, roll, pitch, yaw, 单位为```弧度```。具体使用方式可以参考 [坐标变换功能](../howto/how_to_use_coordinate_transformation_cn.md) 。 -- ```use_vlan``` -- 是否使用vlan,默认为false。一般设置好vlan虚拟网卡之后,数据经过vlan网卡之后,数据包里里面的vlan字段会自动过滤掉。这种情况不需要设置为true。仅当在接收数据有vlan字段,如使用不是vlan网卡录的pcap数据,需要设置为true。 -- ```use_someip``` -- 是否使用someip,默认为false。当数据包中有SOME/IP字段,需要设置为true。 +- ```use_vlan``` -- 默认为false,指定是否使用vlan。如果pcap文件中的packet带vlan层,则需要设置这个选项为true。其他情况下不需要。在线雷达的情况下,协议层到达驱动时,已经剥离vlan层,所以不需要设置这个选项。 +- ```use_someip``` -- 是否使用SOME/IP,默认为false。当数据包中有SOME/IP层,需要设置为true。 diff --git a/doc/intro/parameter_intro.md b/doc/intro/parameter_intro.md index 526dbfd5..d29e15b4 100644 --- a/doc/intro/parameter_intro.md +++ b/doc/intro/parameter_intro.md @@ -1,8 +1,8 @@ # Parameters Introduction -There is only one configure file ```config.yaml```, which is stored in ```rslidar_sdk/config```. The ```config.yaml``` can be divided into two parts, the common part and the lidar part . +There is only one configuration file ```config.yaml```, which is stored in ```rslidar_sdk/config```. The ```config.yaml``` can be divided into two parts, the common part and the lidar part. -*In multi-LiDARs case, the parameters in common part will be shared by all LiDARs, while the parameters in lidar part need to be adjust for each LiDAR.* +*In multi-LiDARs case, the parameters in common part will be shared by all LiDARs, while the parameters in lidar part need to be adjusted for each LiDAR.* **config.yaml is indentation sensitive! Please make sure the indentation is not changed when adjusting the parameters!** @@ -10,7 +10,7 @@ There is only one configure file ```config.yaml```, which is stored in ```rslida ## 1 Common -This part is used to decide the source of LiDAR data, and whether to publish point clouds or not. +This part specifies the source of LiDAR packets, and where to publish point clouds and packets. ```yaml common: @@ -19,20 +19,19 @@ common: send_point_cloud_ros: false send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap ``` - msg_source - - 0 -- Not use lidar. Basically you will never set this parameter to 0. + - 0 -- Unused. Basically you will never set this parameter to 0. - - 1 -- When connecting with a running lidar, set to 1. For more details, please refer to [Online connect lidar and send point cloud through ROS](../howto/how_to_online_send_point_cloud_ros.md) + - 1 -- The lidar packets come from online lidars. For more details, please refer to [Online connect lidar and send point cloud through ROS](../howto/how_to_online_send_point_cloud_ros.md) - - 2 -- The lidar packet come from ROS or ROS2. This will be used in offline decode rosbag. For more details, please refer to [Record rosbag & Offline decode rosbag](../howto/how_to_record_and_offline_decode_rosbag.md) + - 2 -- The lidar packets come from ROS or ROS2. This will be used to decode from an offline rosbag. For more details, please refer to [Record rosbag & Offline decode rosbag](../howto/how_to_record_and_offline_decode_rosbag.md) - - 3 -- The lidar packet come from offline pcap bag. For more details, please refer to [Decode pcap bag and send point cloud through ROS](../howto/how_to_offline_decode_pcap.md) + - 3 -- The lidar packets come from offline a pcap bag. For more details, please refer to [Decode pcap bag and send point cloud through ROS](../howto/how_to_offline_decode_pcap.md) - - 4 -- The lidar packet come from Protobuf-UDP. For more details, please refer to [Use protobuf send & receive](../howto/how_to_use_protobuf_function.md) + - 4 -- The lidar packets come from Protobuf-UDP. For more details, please refer to [Use protobuf send & receive](../howto/how_to_use_protobuf_function.md) - 5 -- The lidar point cloud come from Protobuf-UDP. For more details, please refer to [Use protobuf send & receive](../howto/how_to_use_protobuf_function.md) @@ -41,13 +40,12 @@ common: - true -- The lidar packets will be sent to ROS or ROS2. -*Since the ROS packet message is of a customized message type, you can't directly echo the topic through ROS. Mostly the packets are only used to record offline bag because the size is much smaller than point cloud.* +*Since the ROS packet message is of a customized message type, you can't directly echo the topic through ROS. Mostly the packets are only used to record offline rosbag because the size is much smaller than point cloud.* - send_point_cloud_ros - true -- The lidar point cloud will be sent to ROS or ROS2. - *The ROS point cloud type is the ROS official defined type -- sensor_msgs/PointCloud2, which means the point cloud can be visualized on ROS-Rviz directly. Also you can record the point cloud to rosbag but its size may be very large, that's why we suggest to record packets.* - send_packet_proto @@ -56,16 +54,11 @@ common: - send_point_cloud_proto - - true -- The lidar point cloud will be sent out as protobuf message through ethernet in UDP protocal. + - true -- The lidar point cloud will be sent out as protobuf message through ethernet by UDP protocal. *We suggest sending packets rather than point clouds through ethernet by protobuf because point cloud size is too large which may take up a lot of bandwidth.* -- pcap_path - - If the msg_source = 3, please make sure the pcap_path is correct, otherwise this paramter can be igonred. - - ## 2 lidar @@ -75,7 +68,6 @@ This part needs to be adjusted for every LiDAR seperately (in multi-LiDARs case) lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -83,7 +75,9 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false + pcap_path: /home/robosense/lidar.pcap ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points @@ -102,10 +96,6 @@ lidar: Supported types of LiDAR are listed in README. -- frame_id - - The frame id of the point cloud message. - - msop_port, difop_port The msop port and difop_port of LiDAR. *Please check these parameters first is no data received.* @@ -123,13 +113,15 @@ lidar: - true -- Use the lidar internal clock as the message timestamp - false -- Use the system clock as the message timestamp +- pcap_path + The absolute path of the pcap file. Valid if msg_source = 3. ## 3 Example -Here are two examples. The first configure file is for single LiDAR case and second is used for the case where there are 3 LiDARs. Please adjust the specific parameters according to your own case. +Here are two examples. The first configuration file is for single LiDAR, and the second is for 3 LiDARs. Please adjust the specific parameters according to your own case. -- Online connection to single LiDAR & Send point cloud to ROS +- Connect to one online LiDAR, Send point cloud to ROS ```yaml common: @@ -138,11 +130,9 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -150,7 +140,9 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false + pcap_path: /home/robosense/lidar.pcap ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points @@ -165,7 +157,7 @@ lidar: packet_send_ip: 127.0.0.1 ``` -- Online connection to three LiDARs & Send point cloud to ROS +- Connect to three online LiDARs, Send point cloud to ROS *Pay attention to the indentation of lidar part* @@ -176,11 +168,9 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -188,7 +178,9 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false + pcap_path: /home/robosense/lidar.pcap ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /middle/rslidar_packets ros_send_packet_topic: /middle/rslidar_packets ros_send_point_cloud_topic: /middle/rslidar_points @@ -203,7 +195,6 @@ lidar: packet_send_ip: 127.0.0.1 - driver: lidar_type: RSBP - frame_id: /rslidar msop_port: 1990 difop_port: 1991 start_angle: 0 @@ -211,7 +202,9 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false + pcap_path: /home/robosense/lidar.pcap ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /left/rslidar_packets ros_send_packet_topic: /left/rslidar_packets ros_send_point_cloud_topic: /left/rslidar_points @@ -226,7 +219,6 @@ lidar: packet_send_ip: 127.0.0.1 - driver: lidar_type: RSBP - frame_id: /rslidar msop_port: 2010 difop_port: 2011 start_angle: 0 @@ -234,7 +226,9 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false + pcap_path: /home/robosense/lidar.pcap ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /right/rslidar_packets ros_send_packet_topic: /right/rslidar_packets ros_send_point_cloud_topic: /right/rslidar_points diff --git a/doc/intro/parameter_intro_cn.md b/doc/intro/parameter_intro_cn.md index ae2fcbc7..86d0e2c2 100644 --- a/doc/intro/parameter_intro_cn.md +++ b/doc/intro/parameter_intro_cn.md @@ -1,12 +1,12 @@ # 参数介绍 -本工程只有一份参数文件 ```config.yaml```, 储存于```rslidar_sdk/config```文件夹内。 整个参数文件可以被分为两部分,common部分以及lidar部分。 *在多雷达情况下,common部分的参数设置将会被所有雷达共享,而lidar部分需要根据每台雷达实际情况分别进行设置。* +本工程只有一份参数文件 ```config.yaml```, 储存于```rslidar_sdk/config```文件夹内。 整个参数文件可以被分为两部分,common部分以及lidar部分。 *在多雷达的情况下,common部分的参数设置为所有雷达共享,而lidar部分,则针对每个雷达的实际情况分别设置。* -**参数文件config.yaml对缩进有严格的要求!请确保修改参数之后每行开头的缩进仍保持一致!** +**参数文件config.yaml遵循yaml格式,该格式对缩进有严格的要求。修改参数之后,请确保每行开头的缩进仍保持一致!** ## 1 Common -此部分用于设置雷达的消息来源,以及是否将结果发布。 +这部分设置雷达的消息来源,以及将结果发布到哪里。 ```yaml common: @@ -15,18 +15,17 @@ common: send_point_cloud_ros: false send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap ``` - msg_source - - 1 -- 连接在线雷达. 更多使用细节请参考[在线读取雷达数据发送到ROS](../howto/how_to_online_send_point_cloud_ros_cn.md)。 + - 1 -- 连接在线雷达。更多使用细节请参考[在线读取雷达数据发送到ROS](../howto/how_to_online_send_point_cloud_ros_cn.md)。 - 2 -- 离线解析ROS或ROS2的packet包。更多使用细节请参考 [录制ROS数据包&离线解析ROS数据包](doc/howto/how_to_record_and_offline_decode_rosbag_cn.md)。 - 3 -- 离线解析pcap包。更多使用细节请参考[离线解析Pcap包发送到ROS](doc/howto/how_to_offline_decode_pcap_cn.md)。 - - 4 -- 雷达消息来源为Protobuf-UDP的packet消息,更多使用细节请参考 [使用Protobuf发送&接收](../howto/how_to_use_protobuf_function_cn.md)。 + - 4 -- 雷达消息来源为Protobuf-UDP的Packet消息,更多使用细节请参考 [使用Protobuf发送&接收](../howto/how_to_use_protobuf_function_cn.md)。 - 5 -- 雷达消息来源为Protobuf-UDP的点云消息,更多使用细节请参考 [使用Protobuf发送&接收](../howto/how_to_use_protobuf_function_cn.md)。 @@ -52,21 +51,15 @@ common: *我们建议发送packet消息而不是点云,因为点云消息体积过大,对带宽有较高的要求。.* -- pcap_path - - 如果msg_dource = 3, 请确保此参数设置为正确的pcap包的路径。 - - ## 2 lidar -本部分需要根据不同的雷达进行设置(多雷达时)。 +本部分根据每个雷达的实际情况进行设置(在多雷达的情况下)。 ```yaml lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -74,7 +67,9 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false + pcap_path: /home/robosense/lidar.pcap ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points @@ -93,10 +88,6 @@ lidar: 目前支持的雷达型号已在README中列出。 -- frame_id - - 点云消息的frame_id。 - - msop_port, difop_port 点云的msop端口号和difop端口号。 *若收不到消息,请优先确认这两个参数是否配置正确。* @@ -114,6 +105,9 @@ lidar: - true -- 使用雷达时间作为消息时间戳。 - false -- 使用系统时间作为消息时间戳。 +- pcap_path + + pcap包的路径。当 msg_source=3 时有效。 ## 3 示例 @@ -127,11 +121,9 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -139,7 +131,9 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false + pcap_path: /home/robosense/lidar.pcap ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points @@ -165,11 +159,9 @@ common: send_point_cloud_ros: true send_packet_proto: false send_point_cloud_proto: false - pcap_path: /home/robosense/lidar.pcap lidar: - driver: lidar_type: RS128 - frame_id: /rslidar msop_port: 6699 difop_port: 7788 start_angle: 0 @@ -177,7 +169,9 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false + pcap_path: /home/robosense/lidar.pcap ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /middle/rslidar_packets ros_send_packet_topic: /middle/rslidar_packets ros_send_point_cloud_topic: /middle/rslidar_points @@ -192,7 +186,6 @@ lidar: packet_send_ip: 127.0.0.1 - driver: lidar_type: RSBP - frame_id: /rslidar msop_port: 1990 difop_port: 1991 start_angle: 0 @@ -200,7 +193,9 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false + pcap_path: /home/robosense/lidar.pcap ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /left/rslidar_packets ros_send_packet_topic: /left/rslidar_packets ros_send_point_cloud_topic: /left/rslidar_points @@ -215,7 +210,6 @@ lidar: packet_send_ip: 127.0.0.1 - driver: lidar_type: RSBP - frame_id: /rslidar msop_port: 2010 difop_port: 2011 start_angle: 0 @@ -223,7 +217,9 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false + pcap_path: /home/robosense/lidar.pcap ros: + ros_frame_id: /rslidar ros_recv_packet_topic: /right/rslidar_packets ros_send_packet_topic: /right/rslidar_packets ros_send_point_cloud_topic: /right/rslidar_points diff --git a/src/rs_driver b/src/rs_driver index 6e6272c2..b1e4bdcb 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 6e6272c22096ba4f6b6a05a707a40ecd31082317 +Subproject commit b1e4bdcb30a8e303e9ff32ac2f3fa952a4ecbef4 diff --git a/src/source/source_driver.hpp b/src/source/source_driver.hpp index 6fa038df..dc4e3674 100644 --- a/src/source/source_driver.hpp +++ b/src/source/source_driver.hpp @@ -97,7 +97,7 @@ inline void SourceDriver::init(const YAML::Node& config) yamlRead(driver_config, "max_distance", driver_param.decoder_param.max_distance, 200); yamlRead(driver_config, "start_angle", driver_param.decoder_param.start_angle, 0); yamlRead(driver_config, "end_angle", driver_param.decoder_param.end_angle, 360); - yamlRead(driver_config, "is_dense", driver_param.decoder_param.dense_points, false); + yamlRead(driver_config, "dense_points", driver_param.decoder_param.dense_points, false); // mechanical decoder yamlRead(driver_config, "config_from_file", driver_param.decoder_param.config_from_file, false); @@ -107,8 +107,8 @@ inline void SourceDriver::init(const YAML::Node& config) yamlRead(driver_config, "split_frame_mode", split_frame_mode, 1); driver_param.decoder_param.split_frame_mode = SplitFrameMode(split_frame_mode); - yamlRead(driver_config, "cut_angle", driver_param.decoder_param.split_angle, 0); - yamlRead(driver_config, "num_pkts_split", driver_param.decoder_param.num_blks_split, 0); + yamlRead(driver_config, "split_angle", driver_param.decoder_param.split_angle, 0); + yamlRead(driver_config, "num_blks_split", driver_param.decoder_param.num_blks_split, 0); switch (src_type_) { From 4c0777946a10c9f993b113db1a9152018c5d999e Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 20 Jan 2022 10:51:24 +0800 Subject: [PATCH 091/261] feat: support user layer --- src/adapter/driver_adapter.hpp | 1 + src/rs_driver | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index 489452e6..b58c81aa 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -114,6 +114,7 @@ inline void DriverAdapter::init(const YAML::Node& config) yamlRead(driver_config, "read_pcap", driver_param.input_param.read_pcap, false); yamlRead(driver_config, "use_vlan", driver_param.input_param.use_vlan, false); yamlRead(driver_config, "use_someip", driver_param.input_param.use_someip, false); + yamlRead(driver_config, "user_layer_bytes", driver_param.input_param.user_layer_bytes, 0); yamlRead(driver_config, "pcap_rate", driver_param.input_param.pcap_rate, 1); yamlRead(driver_config, "pcap_repeat", driver_param.input_param.pcap_repeat, false); yamlRead(driver_config, "pcap_path", driver_param.input_param.pcap_path, ""); diff --git a/src/rs_driver b/src/rs_driver index 05cdc136..46fa10a2 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 05cdc1364659fcd5ed2c68615811c11bec1c2183 +Subproject commit 46fa10a250742ef66397fd050a0c0854d78a15e7 From 76a3767657167f8e4f6d8985a0f7f5d6d6732ab5 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 24 Jan 2022 14:44:13 +0800 Subject: [PATCH 092/261] feat: support tail layer --- src/adapter/driver_adapter.hpp | 1 + src/rs_driver | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/adapter/driver_adapter.hpp b/src/adapter/driver_adapter.hpp index b58c81aa..e1989bdd 100644 --- a/src/adapter/driver_adapter.hpp +++ b/src/adapter/driver_adapter.hpp @@ -115,6 +115,7 @@ inline void DriverAdapter::init(const YAML::Node& config) yamlRead(driver_config, "use_vlan", driver_param.input_param.use_vlan, false); yamlRead(driver_config, "use_someip", driver_param.input_param.use_someip, false); yamlRead(driver_config, "user_layer_bytes", driver_param.input_param.user_layer_bytes, 0); + yamlRead(driver_config, "tail_layer_bytes", driver_param.input_param.tail_layer_bytes, 0); yamlRead(driver_config, "pcap_rate", driver_param.input_param.pcap_rate, 1); yamlRead(driver_config, "pcap_repeat", driver_param.input_param.pcap_repeat, false); yamlRead(driver_config, "pcap_path", driver_param.input_param.pcap_path, ""); diff --git a/src/rs_driver b/src/rs_driver index 46fa10a2..e50aa359 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 46fa10a250742ef66397fd050a0c0854d78a15e7 +Subproject commit e50aa35940c4af4b7dea11b113b0dcf47bfdeb67 From c9ae9a678e0ba8ed60c436fd32b82caed3573b00 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 25 Jan 2022 18:19:28 +0800 Subject: [PATCH 093/261] feat: support ruby_128 4.0 --- config/config.yaml | 2 +- src/rs_driver | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index c3e7e5e0..78208631 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -12,7 +12,7 @@ common: pcap_path: /home/robosense/lidar.pcap #The path of pcap file lidar: - driver: - lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RS128, RS80, RSM1, RSHELIOS + lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RS128, RS128_40, RS80, RSM1, RSHELIOS frame_id: /rslidar #Frame id of message msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar diff --git a/src/rs_driver b/src/rs_driver index 3b9f0f85..f6d35dc0 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 3b9f0f857b66874e22779cde4b233ac6e55bd3f6 +Subproject commit f6d35dc03d29d71c1a304bc84a79c948626adcee From c96855cdc34ed08029eaa5fb4f3d0f40999745f8 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 26 Jan 2022 17:42:12 +0800 Subject: [PATCH 094/261] feat: recover transform param --- src/source/source_driver.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/source/source_driver.hpp b/src/source/source_driver.hpp index dc4e3674..ebea7beb 100644 --- a/src/source/source_driver.hpp +++ b/src/source/source_driver.hpp @@ -110,6 +110,14 @@ inline void SourceDriver::init(const YAML::Node& config) yamlRead(driver_config, "split_angle", driver_param.decoder_param.split_angle, 0); yamlRead(driver_config, "num_blks_split", driver_param.decoder_param.num_blks_split, 0); + // transform + yamlRead(driver_config, "x", driver_param.decoder_param.transform_param.x, 0); + yamlRead(driver_config, "y", driver_param.decoder_param.transform_param.y, 0); + yamlRead(driver_config, "z", driver_param.decoder_param.transform_param.z, 0); + yamlRead(driver_config, "roll", driver_param.decoder_param.transform_param.roll, 0); + yamlRead(driver_config, "pitch", driver_param.decoder_param.transform_param.pitch, 0); + yamlRead(driver_config, "yaw", driver_param.decoder_param.transform_param.yaw, 0); + switch (src_type_) { case SourceType::MSG_FROM_LIDAR: From 87b29a01274bfe0863571687378879ac41625ec8 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 26 Jan 2022 18:07:17 +0800 Subject: [PATCH 095/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 3b9f0f85..f6d35dc0 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 3b9f0f857b66874e22779cde4b233ac6e55bd3f6 +Subproject commit f6d35dc03d29d71c1a304bc84a79c948626adcee From 0aba564e4a634a0c1fbb21731a19f7af5b8ea854 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 27 Jan 2022 15:44:44 +0800 Subject: [PATCH 096/261] feat: update CHANGELOG --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7e0d514..27604577 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,11 @@ # Changelog -## unrelease +## v1.3.1 - 2022-01-27 ### Added + - support the Ruby 4.0 Lidar - add install command when building using catkin - add use_vlan and use_someip support - - add use_vlan and use_someip support - support customer protocol layer - adapt to ros noetic, ros2 foxy/galactic (Thanks to @Tim.Clephas) - get config file path from param (Thanks to @mtlazaro, @Tim.Clephas) From bbcad31e57f25c65c1da7c80d9204ab6135d2853 Mon Sep 17 00:00:00 2001 From: Tim Clephas Date: Mon, 12 Jul 2021 11:07:18 +0200 Subject: [PATCH 097/261] Single package.xml file for both ROS1 and ROS2 --- .gitignore | 1 - README.md | 70 +++++++++++++++++------------------------------- README_CN.md | 44 ++++++++---------------------- package.xml | 25 +++++++++++++++++ package_ros1.xml | 26 ------------------ package_ros2.xml | 25 ----------------- 6 files changed, 60 insertions(+), 131 deletions(-) create mode 100644 package.xml delete mode 100644 package_ros1.xml delete mode 100644 package_ros2.xml diff --git a/.gitignore b/.gitignore index 01b13ecd..581c6ddb 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,3 @@ cmake-build-debug/ version.h *.pb.cc *.pb.h -package.xml diff --git a/README.md b/README.md index abce8479..ca7c9c55 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # **rslidar_sdk** - [中文介绍](README_CN.md) + [中文介绍](README_CN.md) ## 1 Introduction @@ -8,13 +8,13 @@ ### **1.1 LiDAR Support** -- RS-LiDAR-16 -- RS-LiDAR-32 -- RS-Bpearl -- RS-Ruby -- RS-Ruby Lite -- RS-LiDAR-M1 -- RS-Helios +- RS16 +- RS32 +- RSBP +- RS128 +- RS80 +- RSM1-B3 +- RSHELIOS ### 1.2 Point type support @@ -23,7 +23,7 @@ ## 2 Download -### 2.1 Download via Git +### 2.1 Download via Git Since rslidar_sdk project includes a submodule --- rs_driver, user needs to run the following commands after git clone to download the submodule properly. @@ -44,7 +44,7 @@ Instead of using Git, user can also access [rslidar_sdk_release](https://github. ### 3.1 ROS -To run rslidar_sdk in ROS environment, ROS related libraries need to be installed. +To run rslidar_sdk in ROS environment, ROS related libraries need to be installed. **Ubuntu 16.04**: ros-kinetic-desktop-full @@ -58,12 +58,12 @@ If you install ros-kinetic-desktop-full/ros-melodic-desktop-full/ros-noetic-desk ### 3.2 ROS2 -If use rslidar_sdk in ROS2 environment, ROS2 related libraries need to be installed. +If use rslidar_sdk in ROS2 environment, ROS2 related libraries need to be installed. **Ubuntu 16.04**: Not supported **Ubuntu 18.04**: ROS2 eloquent desktop - + **Installation**: please refer to https://index.ros.org/doc/ros2/Installation/Eloquent/Linux-Install-Debians/ **Ubuntu 20.04**: ROS2 foxy desktop @@ -76,7 +76,7 @@ If use rslidar_sdk in ROS2 environment, ROS2 related libraries need to be instal **Note! Please avoid installing ROS and ROS2 on the same computer! This may cause conflict! Also you may need to install Yaml manually.** -### 3.3 Yaml(Essential) +### 3.3 Yaml(Essential) version: >= v0.5.2 @@ -89,7 +89,7 @@ sudo apt-get update sudo apt-get install -y libyaml-cpp-dev ``` -### 3.4 Pcap(Essential) +### 3.4 Pcap(Essential) version: >=v1.7.4 @@ -117,7 +117,7 @@ We offer three ways to compile and run the driver. ### 4.1 Compile directly - In this way, user can use ROS facilities(not ROS2) if ROS master node is launched in advance via ```roscore```. Also, rviz can be launched seperately for visualization. + In this way, user can use ROS facilities(not ROS2) if ROS master node is launched in advance via ```roscore```. Also, rviz can be launched seperately for visualization. ```sh cd rslidar_sdk @@ -130,20 +130,9 @@ cmake .. && make -j4 ### 4.2 Compile with ROS catkin tools -(1) Open the *CMakeLists.txt* in the project,modify the line on top of the file **set(COMPILE_METHOD ORIGINAL)** to **set(COMPILE_METHOD CATKIN)**. - -```cmake -#======================================= -# Compile setup (ORIGINAL,CATKIN,COLCON) -#======================================= -set(COMPILE_METHOD CATKIN) -``` - -(2) Rename the file *package_ros1.xml* in the rslidar_sdk to *package.xml* - -(3) Create a new workspace folder, and create a *src* folder in it. Then put the rslidar_sdk project into the *src* folder. +(1) Create a new workspace folder, and create a *src* folder in it. Then put the rslidar_sdk project into the *src* folder. -(4) Go back to the root of workspace, run the following commands to compile and run. (if using zsh, replace the 2nd command with *source devel/setup.zsh*). +(2) Go back to the root of workspace, run the following commands to compile and run. (if using zsh, replace the 2nd command with *source devel/setup.zsh*). ```sh catkin_make @@ -153,22 +142,11 @@ roslaunch rslidar_sdk start.launch ### 4.3 Compile with ROS2-colcon -(1) Open the *CMakeLists.txt* in the project,modify the line on top of the file **set(COMPILE_METHOD ORIGINAL)** to **set(COMPILE_METHOD COLCON)**. - -```cmake -#======================================= -# Compile setup (ORIGINAL,CATKIN,COLCON) -#======================================= -set(COMPILE_METHOD COLCON) -``` - -(2) Rename the file *package_ros2.xml* in the rslidar_sdk to *package.xml* - -(3) Create a new workspace folder, and create a *src* folder in it. Then put the rslidar_sdk project in the *src* folder. +(1) Create a new workspace folder, and create a *src* folder in it. Then put the rslidar_sdk project in the *src* folder. -(4) Download the packet definition project in ROS2 through [link](https://github.com/RoboSense-LiDAR/rslidar_msg), then put the project rslidar_msg in the *src* folder you just created. +(2) Download the packet definition project in ROS2 through [link](https://github.com/RoboSense-LiDAR/rslidar_msg), then put the project rslidar_msg in the *src* folder you just created. -(5) Go back to the root of workspace, run the following commands to compile and run. (if using zsh, replace the 2nd command with *source install/setup.zsh*). +(3) Go back to the root of workspace, run the following commands to compile and run. (if using zsh, replace the 2nd command with *source install/setup.zsh*). ```sh colcon build @@ -180,7 +158,7 @@ ros2 launch rslidar_sdk start.py ## 5 Introduction to parameters -This section is very important since all functions and features provided by rslidar_sdk is configured via parameter modification. So please read the following links carefully. +This section is very important since all functions and features provided by rslidar_sdk is configured via parameter modification. So please read the following links carefully. [Intro to parameters](doc/intro/parameter_intro.md) @@ -206,8 +184,8 @@ The following documents are some quick guides for using some of the most common [Multi-LiDARs](doc/howto/how_to_use_multi_lidars.md) -[Switch Point Type](doc/howto/how_to_switch_point_type.md) +[Switch Point Type](doc/howto/how_to_switch_point_type.md) -[Coordinate Transformation](doc/howto/how_to_use_coordinate_transformation.md) +[Coordinate Transformation](doc/howto/how_to_use_coordinate_transformation.md) -[Multi-Cast](doc/howto/how_to_use_multi_cast_function.md) +[Multi-Cast](doc/howto/how_to_use_multi_cast_function.md) diff --git a/README_CN.md b/README_CN.md index b188ab51..21ba4c68 100644 --- a/README_CN.md +++ b/README_CN.md @@ -41,11 +41,11 @@ git submodule update ## 3 依赖介绍 -### 3.1 ROS +### 3.1 ROS *若需在ROS环境下使用雷达驱动,则需安装ROS相关依赖库* -Ubuntu 16.04 - ROS kinetic desktop-full +Ubuntu 16.04 - ROS kinetic desktop-full Ubuntu 18.04 - ROS melodic desktop-full @@ -77,7 +77,7 @@ Ubuntu 20.04 - ROS2 Galactic desktop ### 3.3 Yaml (必需) -版本号: >= v0.5.2 +版本号: >= v0.5.2 *若已安装ROS desktop-full, 可跳过* @@ -127,20 +127,9 @@ cmake .. && make -j4 ### 4.2 依赖于ROS-catkin编译 -(1) 打开工程内的*CMakeLists.txt*文件,将文件顶部的**set(COMPILE_METHOD ORIGINAL)**改为**set(COMPILE_METHOD CATKIN)**。 +(1) 新建一个文件夹作为工作空间,然后再新建一个名为*src*的文件夹, 将rslidar_sdk工程放入*src*文件夹内。 -```cmake -#======================================= -# Compile setup (ORIGINAL,CATKIN,COLCON) -#======================================= -set(COMPILE_METHOD CATKIN) -``` - -(2) 将rslidar_sdk工程目录下的*package_ros1.xml*文件重命名为*package.xml*。 - -(3) 新建一个文件夹作为工作空间,然后再新建一个名为*src*的文件夹, 将rslidar_sdk工程放入*src*文件夹内。 - -(4) 返回工作空间目录,执行以下命令即可编译&运行(若使用.zsh,将第二句指令替换为 *source devel/setup.zsh*)。 +(2) 返回工作空间目录,执行以下命令即可编译&运行(若使用.zsh,将第二句指令替换为 *source devel/setup.zsh*)。 ```sh catkin_make @@ -150,22 +139,11 @@ roslaunch rslidar_sdk start.launch ### 4.3 依赖于ROS2-colcon编译 -(1) 打开工程内的*CMakeLists.txt*文件,将文件顶部的**set(COMPILE_METHOD ORIGINAL)**改为**set(COMPILE_METHOD COLCON)**。 - -```cmake -#======================================= -# Compile setup (ORIGINAL,CATKIN,COLCON) -#======================================= -set(COMPILE_METHOD COLCON) -``` - -(2) 将rslidar_sdk工程目录下的*package_ros2.xml*文件重命名为*package.xml*。 - -(3) 新建一个文件夹作为工作空间,然后再新建一个名为*src*的文件夹, 将rslidar_sdk工程放入*src*文件夹内。 +(1) 新建一个文件夹作为工作空间,然后再新建一个名为*src*的文件夹, 将rslidar_sdk工程放入*src*文件夹内。 -(4) 通过[链接](https://github.com/RoboSense-LiDAR/rslidar_msg)下载ROS2环境下的雷达packet消息定义, 将rslidar_msg工程也放在刚刚新建的*src*文件夹内,与rslidar_sdk并列。 +(2) 通过[链接](https://github.com/RoboSense-LiDAR/rslidar_msg)下载ROS2环境下的雷达packet消息定义, 将rslidar_msg工程也放在刚刚新建的*src*文件夹内,与rslidar_sdk并列。 -(5) 返回工作空间目录,执行以下命令即可编译&运行(若使用.zsh,将第二句指令替换为 *source install/setup.zsh*)。 +(3) 返回工作空间目录,执行以下命令即可编译&运行(若使用.zsh,将第二句指令替换为 *source install/setup.zsh*)。 ```sh colcon build @@ -203,8 +181,8 @@ ros2 launch rslidar_sdk start.py [多雷达](doc/howto/how_to_use_multi_lidars_cn.md) -[切换点的类型](doc/howto/how_to_switch_point_type_cn.md) +[切换点的类型](doc/howto/how_to_switch_point_type_cn.md) -[坐标变换功能](doc/howto/how_to_use_coordinate_transformation_cn.md) +[坐标变换功能](doc/howto/how_to_use_coordinate_transformation_cn.md) -[组播模式](doc/howto/how_to_use_multi_cast_function_cn.md) +[组播模式](doc/howto/how_to_use_multi_cast_function_cn.md) diff --git a/package.xml b/package.xml new file mode 100644 index 00000000..1719b3ff --- /dev/null +++ b/package.xml @@ -0,0 +1,25 @@ + + + rslidar_sdk + 1.3.0 + The rslidar_sdk package + robosense + BSD + + catkin + ament_cmake + + libpcap-dev + libpcl-dev + libyaml-cpp-dev + pcl_conversions + rclcpp + roscpp + rslidar_msg + sensor_msgs + std_msgs + + + ament_cmake + + diff --git a/package_ros1.xml b/package_ros1.xml deleted file mode 100644 index 28814d5e..00000000 --- a/package_ros1.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - rslidar_sdk - 1.3.0 - The rslidar_sdk package - robosense - BSD - - catkin - - roscpp - sensor_msgs - roslib - yaml-cpp - libpcap - pcl_ros - pcl_conversions - libpcl-all-dev - - roscpp - sensor_msgs - roslib - libpcap - pcl_conversions - - diff --git a/package_ros2.xml b/package_ros2.xml deleted file mode 100644 index e1bb89ae..00000000 --- a/package_ros2.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - rslidar_sdk - 1.3.0 - The rslidar_sdk package - robosense - BSD - - ament_cmake - - yaml-cpp - - rclcpp - std_msgs - sensor_msgs - rslidar_msg - libpcap - pcl_conversions - libpcl-all-dev - - - ament_cmake - - - From 6c6e27ae58649fcb396aa34b548e4683fc1a1f46 Mon Sep 17 00:00:00 2001 From: Tim Clephas Date: Mon, 12 Jul 2021 11:19:06 +0200 Subject: [PATCH 098/261] Adhere to rosdep definitions --- package.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.xml b/package.xml index 1719b3ff..b3ce814b 100644 --- a/package.xml +++ b/package.xml @@ -9,15 +9,15 @@ catkin ament_cmake - libpcap-dev - libpcl-dev - libyaml-cpp-dev + libpcap + libpcl-all-dev pcl_conversions rclcpp roscpp rslidar_msg sensor_msgs std_msgs + yaml-cpp ament_cmake From 9cc5af0219f6934c35448ef893d8a776b1ef0d5c Mon Sep 17 00:00:00 2001 From: Tim Clephas Date: Mon, 12 Jul 2021 11:34:23 +0200 Subject: [PATCH 099/261] pcl_ros is also a dependency --- package.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/package.xml b/package.xml index b3ce814b..2c58bd5b 100644 --- a/package.xml +++ b/package.xml @@ -12,6 +12,7 @@ libpcap libpcl-all-dev pcl_conversions + pcl_ros rclcpp roscpp rslidar_msg From abcb79953730ce1234f0986fc1dfa15f0e103d36 Mon Sep 17 00:00:00 2001 From: Tim Clephas Date: Mon, 12 Jul 2021 11:48:58 +0200 Subject: [PATCH 100/261] pcl dependencies only for ROS1 --- package.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.xml b/package.xml index 2c58bd5b..b69b2809 100644 --- a/package.xml +++ b/package.xml @@ -12,7 +12,7 @@ libpcap libpcl-all-dev pcl_conversions - pcl_ros + pcl_ros rclcpp roscpp rslidar_msg From 21e10d0ae1b0c8717e41296ebc4c1429e855a065 Mon Sep 17 00:00:00 2001 From: Tim Clephas Date: Fri, 11 Feb 2022 16:47:09 +0100 Subject: [PATCH 101/261] Fix rebase --- CMakeLists.txt | 2 -- package.xml | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 64f6accb..70a537b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,6 @@ if(roscpp_FOUND) message("-- ROS Found, Ros Support is turned On!") message(=============================================================) add_definitions(-DROS_FOUND) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/package_ros1.xml ${CMAKE_CURRENT_SOURCE_DIR}/package.xml COPYONLY) find_package(roslib QUIET) include_directories(${roscpp_INCLUDE_DIRS} ${roslib_INCLUDE_DIRS}) @@ -51,7 +50,6 @@ if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") message("-- ROS2 Found, Ros2 Support is turned On!") message(=============================================================) add_definitions(-DROS2_FOUND) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/package_ros2.xml ${CMAKE_CURRENT_SOURCE_DIR}/package.xml COPYONLY) set(CMAKE_CXX_STANDARD 14) find_package(ament_cmake REQUIRED) diff --git a/package.xml b/package.xml index b69b2809..029a336b 100644 --- a/package.xml +++ b/package.xml @@ -15,6 +15,7 @@ pcl_ros rclcpp roscpp + roslib rslidar_msg sensor_msgs std_msgs From 57c164f14e4ec952241dde5513b84d2b4237c32c Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 17 Feb 2022 15:20:54 +0800 Subject: [PATCH 102/261] fix: copy packet.xml instead of move it --- README.md | 4 ++-- README_CN.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index abce8479..c09c6af8 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ cmake .. && make -j4 set(COMPILE_METHOD CATKIN) ``` -(2) Rename the file *package_ros1.xml* in the rslidar_sdk to *package.xml* +(2) Copy the file *package_ros1.xml* in the rslidar_sdk to *package.xml* (3) Create a new workspace folder, and create a *src* folder in it. Then put the rslidar_sdk project into the *src* folder. @@ -162,7 +162,7 @@ roslaunch rslidar_sdk start.launch set(COMPILE_METHOD COLCON) ``` -(2) Rename the file *package_ros2.xml* in the rslidar_sdk to *package.xml* +(2) Copy the file *package_ros2.xml* in the rslidar_sdk to *package.xml* (3) Create a new workspace folder, and create a *src* folder in it. Then put the rslidar_sdk project in the *src* folder. diff --git a/README_CN.md b/README_CN.md index b188ab51..1e36f93f 100644 --- a/README_CN.md +++ b/README_CN.md @@ -136,7 +136,7 @@ cmake .. && make -j4 set(COMPILE_METHOD CATKIN) ``` -(2) 将rslidar_sdk工程目录下的*package_ros1.xml*文件重命名为*package.xml*。 +(2) 将rslidar_sdk工程目录下的*package_ros1.xml*文件复制到*package.xml*。 (3) 新建一个文件夹作为工作空间,然后再新建一个名为*src*的文件夹, 将rslidar_sdk工程放入*src*文件夹内。 @@ -159,7 +159,7 @@ roslaunch rslidar_sdk start.launch set(COMPILE_METHOD COLCON) ``` -(2) 将rslidar_sdk工程目录下的*package_ros2.xml*文件重命名为*package.xml*。 +(2) 将rslidar_sdk工程目录下的*package_ros2.xml*文件复制到*package.xml*。 (3) 新建一个文件夹作为工作空间,然后再新建一个名为*src*的文件夹, 将rslidar_sdk工程放入*src*文件夹内。 From 883279949219b4dce076c7ccdbdbcdc0b42a1c0b Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 17 Feb 2022 16:13:09 +0800 Subject: [PATCH 103/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index f6d35dc0..7c3332e1 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit f6d35dc03d29d71c1a304bc84a79c948626adcee +Subproject commit 7c3332e1b1b033d7aa9a9082648ff699caa7bd40 From 8d8ae9a0dbc5cdf1a506731a85e1fb48e214dbf1 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 24 Feb 2022 14:58:57 +0800 Subject: [PATCH 104/261] feat: sync to rs_driver --- src/rs_driver | 2 +- src/source/source_driver.hpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/rs_driver b/src/rs_driver index 8614609f..a673db1f 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 8614609f161fb9be43ae9ef20b714cdf0cc5e176 +Subproject commit a673db1f3e799cf327d458f621e2f081085574c6 diff --git a/src/source/source_driver.hpp b/src/source/source_driver.hpp index ebea7beb..0311be5f 100644 --- a/src/source/source_driver.hpp +++ b/src/source/source_driver.hpp @@ -80,7 +80,6 @@ inline void SourceDriver::init(const YAML::Node& config) yamlRead(driver_config, "host_address", driver_param.input_param.host_address, "0.0.0.0"); yamlRead(driver_config, "group_address", driver_param.input_param.group_address, "0.0.0.0"); yamlRead(driver_config, "use_vlan", driver_param.input_param.use_vlan, false); - yamlRead(driver_config, "use_someip", driver_param.input_param.use_someip, false); yamlRead(driver_config, "pcap_path", driver_param.input_param.pcap_path, ""); yamlRead(driver_config, "pcap_rate", driver_param.input_param.pcap_rate, 1); yamlRead(driver_config, "pcap_repeat", driver_param.input_param.pcap_repeat, false); From b5ac848204a425768ce472b5256e73dff7648fe3 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 1 Mar 2022 11:05:57 +0800 Subject: [PATCH 105/261] fix: fix packet.xml --- package_ros1.xml | 2 +- package_ros2.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package_ros1.xml b/package_ros1.xml index 28814d5e..62104b72 100644 --- a/package_ros1.xml +++ b/package_ros1.xml @@ -1,7 +1,7 @@ rslidar_sdk - 1.3.0 + 1.3.2 The rslidar_sdk package robosense BSD diff --git a/package_ros2.xml b/package_ros2.xml index e1bb89ae..a77c646a 100644 --- a/package_ros2.xml +++ b/package_ros2.xml @@ -1,7 +1,7 @@ rslidar_sdk - 1.3.0 + 1.3.2 The rslidar_sdk package robosense BSD From eb9fb12e43f334611581cc500684ca1590d531ae Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 1 Mar 2022 11:09:59 +0800 Subject: [PATCH 106/261] feat: update CHANGELOG.md --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7e0d514..3c81976c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Changelog -## unrelease +## v1.3.2 - 2022-01-27 + +### Fixed +- Fix vesion to v1.3.2 + + +## v1.3.1 - 2022-01-27 ### Added - add install command when building using catkin From 3933289d62464ef09bca7d78f5c9a03c8ebbf1be Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 10 Feb 2022 11:14:38 +0800 Subject: [PATCH 107/261] feat: use point cloud queue --- src/rs_driver | 2 +- src/source/source_driver.hpp | 34 ++++++++++++++++++++++++---- src/source/source_packet_ros.hpp | 2 +- src/source/source_pointcloud_ros.hpp | 2 +- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/rs_driver b/src/rs_driver index a673db1f..f867bb69 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit a673db1f3e799cf327d458f621e2f081085574c6 +Subproject commit f867bb696e205969b9d10c87f5c38a54c7967e1d diff --git a/src/source/source_driver.hpp b/src/source/source_driver.hpp index 0311be5f..6047c42c 100644 --- a/src/source/source_driver.hpp +++ b/src/source/source_driver.hpp @@ -35,6 +35,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "source/source.hpp" #include +#include namespace robosense { @@ -59,9 +60,12 @@ class SourceDriver : public Source void putPointCloud(std::shared_ptr msg); void putPacket(const Packet& msg); void putException(const lidar::Error& msg); + void processPointCloud(); - std::shared_ptr point_cloud_; std::shared_ptr> driver_ptr_; + SyncQueue> free_point_cloud_queue_; + SyncQueue> point_cloud_queue_; + std::thread point_cloud_handle_thread_; }; SourceDriver::SourceDriver(SourceType src_type) @@ -132,12 +136,12 @@ inline void SourceDriver::init(const YAML::Node& config) driver_param.print(); - point_cloud_.reset(new LidarPointCloudMsg); driver_ptr_.reset(new lidar::LidarDriver()); driver_ptr_->regPointCloudCallback(std::bind(&SourceDriver::getPointCloud, this), std::bind(&SourceDriver::putPointCloud, this, std::placeholders::_1)); driver_ptr_->regExceptionCallback( std::bind(&SourceDriver::putException, this, std::placeholders::_1)); + point_cloud_handle_thread_ = std::thread(std::bind(&SourceDriver::processPointCloud, this)); if (!driver_ptr_->init(driver_param)) { @@ -163,7 +167,13 @@ inline void SourceDriver::stop() inline std::shared_ptr SourceDriver::getPointCloud(void) { - return point_cloud_; + std::shared_ptr point_cloud = free_point_cloud_queue_.pop(); + if (point_cloud.get() != NULL) + { + return point_cloud; + } + + return std::make_shared(); } inline void SourceDriver::regPacketCallback(DestinationPacket::Ptr dst) @@ -184,7 +194,23 @@ inline void SourceDriver::putPacket(const Packet& msg) void SourceDriver::putPointCloud(std::shared_ptr msg) { - sendPointCloud(msg); + point_cloud_queue_.push(msg); +} + +void SourceDriver::processPointCloud() +{ + while (1) + { + std::shared_ptr msg = point_cloud_queue_.popWait(1000); + if (msg.get() == NULL) + { + continue; + } + + sendPointCloud(msg); + + free_point_cloud_queue_.push(msg); + } } inline void SourceDriver::putException(const lidar::Error& msg) diff --git a/src/source/source_packet_ros.hpp b/src/source/source_packet_ros.hpp index a5e33569..58542874 100644 --- a/src/source/source_packet_ros.hpp +++ b/src/source/source_packet_ros.hpp @@ -92,7 +92,7 @@ void SourcePacketRos::init(const YAML::Node& config) pkt_sub_ = nh_->subscribe(ros_recv_topic, 100, &SourcePacketRos::putPacket, this); } -void SourcePacketRos::putPacket(const rslidar_msg::RslidarPacket& msg) +void SourcePacketRos::putPacket(const rslidar_msg::rslidarPacket& msg) { driver_ptr_->decodePacket(toRsMsg(msg)); } diff --git a/src/source/source_pointcloud_ros.hpp b/src/source/source_pointcloud_ros.hpp index 1577fc0c..278d29d8 100644 --- a/src/source/source_pointcloud_ros.hpp +++ b/src/source/source_pointcloud_ros.hpp @@ -131,7 +131,7 @@ inline void DestinationPointCloudRos::init(const YAML::Node& config) "ros_send_point_cloud_topic", ros_send_topic, "rslidar_points"); node_ptr_.reset(new rclcpp::Node("rslidar_points_adapter")); - pub_ = node_ptr_->create_publisher(ros_send_topic, 1); + pub_ = node_ptr_->create_publisher(ros_send_topic, 100); } inline void DestinationPointCloudRos::sendPointCloud(const LidarPointCloudMsg& msg) From 457c91119198e5dd160c1fa362f646077456818d Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 8 Mar 2022 18:46:26 +0800 Subject: [PATCH 108/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index e50aa359..54070782 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit e50aa35940c4af4b7dea11b113b0dcf47bfdeb67 +Subproject commit 54070782fb1bb8235495ba85be57e1a27d0c07ac From 77a7265dca62be938dafe917b6f37615bc0ed77f Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 9 Mar 2022 09:29:02 +0800 Subject: [PATCH 109/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 54070782..c5297e26 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 54070782fb1bb8235495ba85be57e1a27d0c07ac +Subproject commit c5297e264f89fd2275bc142da88a0a2110f6da08 From 34ac46b398add4e86c81d4a19d764f24afd8054d Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 9 Mar 2022 14:39:44 +0800 Subject: [PATCH 110/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 1ed9b293..ecfb48a6 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 1ed9b29388742e01e6652903838a45dd3e5d2cbf +Subproject commit ecfb48a67145b5d2dfc6215fc14c2381c75f68a1 From 464a3476767bbf1c00ecab0bc106fd0b730f2e00 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 15 Mar 2022 11:48:13 +0800 Subject: [PATCH 111/261] feat: update docs --- README.md | 103 ++++++++++++++++++++++++++------------------------- README_CN.md | 100 ++++++++++++++++++++++++------------------------- 2 files changed, 102 insertions(+), 101 deletions(-) diff --git a/README.md b/README.md index 5828225d..d46b419d 100644 --- a/README.md +++ b/README.md @@ -4,19 +4,28 @@ ## 1 Introduction -**rslidar_sdk** is the lidar driver software development kit running on Ubuntu operating system, which contains the lidar driver core, ROS support, ROS2 support and Protobuf-UDP communication functions. For users who want to get point cloud through ROS or ROS2, this software development kit can be used directly. For those who want to do advanced development or integrate the lidar driver into their own projects, please refer to the lidar driver core [rs_driver](https://github.com/RoboSense-LiDAR/rs_driver). +**rslidar_sdk** is the Software Development Kit of the RoboSense Lidar based on Ubuntu. It contains: -### **1.1 LiDAR Support** ++ The lidar driver core [rs_driver](https://github.com/RoboSense-LiDAR/rs_driver), ++ The ROS support, ++ The ROS2 support, ++ The Protobuf-UDP communication functions. + +To get point cloud through ROS/ROS2, please just use this SDK. + +To integrate the Lidar driver into your own projects, please use the rs_driver. + +### 1.1 LiDAR Supported - RS-LiDAR-16 - RS-LiDAR-32 - RS-Bpearl +- RS-Helios - RS-Ruby - RS-Ruby Lite - RS-LiDAR-M1 -- RS-Helios -### 1.2 Point type support +### 1.2 Point Type Supported - XYZI - x, y, z, intensity - XYZIRT - x, y, z, intensity, ring, timestamp @@ -25,7 +34,8 @@ ### 2.1 Download via Git -Since rslidar_sdk project includes a submodule --- rs_driver, user needs to run the following commands after git clone to download the submodule properly. +Download the rslidar_sdk as below. Since it contains the submodule rs_driver, please also use `git submodule` to download the submodule properly. + ```sh git clone https://github.com/RoboSense-LiDAR/rslidar_sdk.git @@ -36,7 +46,9 @@ git submodule update ### 2.2 Download directly -Instead of using Git, user can also access [rslidar_sdk_release](https://github.com/RoboSense-LiDAR/rslidar_sdk/releases) to download the latest version of rslidar_sdk. Please download the **rslidar_sdk.tar.gz** archive instead of Source code because the Source code zip file does not contain the submodule(rs_driver), which should be downloaded manaully. +Instead of using Git, user can also access [rslidar_sdk_release](https://github.com/RoboSense-LiDAR/rslidar_sdk/releases) to download the latest version of rslidar_sdk. + +Please download the **rslidar_sdk.tar.gz** archive instead of Source code. The Source code zip file does not contain the submodule rs_driver, so it has to be downloaded manaully. ![](doc/img/download_page.png) @@ -44,33 +56,31 @@ Instead of using Git, user can also access [rslidar_sdk_release](https://github. ### 3.1 ROS -To run rslidar_sdk in ROS environment, ROS related libraries need to be installed. - -**Ubuntu 16.04**: ros-kinetic-desktop-full +To run rslidar_sdk in the ROS environment, please install below libraries. ++ Ubuntu 16.04 - ros-kinetic-desktop-full ++ Ubuntu 18.04 - ros-melodic-desktop-full -**Ubuntu 18.04**: ros-melodic-desktop-full +For installation, please refer to http://wiki.ros.org. -**Installation**: please refer to http://wiki.ros.org +**It's highly recommanded to install ros-distro-desktop-full**. If you do so, the corresponding libraries, such as PCL, will be installed at the same time. -If you install ros-kinetic-desktop-full or ros-melodic-desktop-full, the corresponding PCL and Boost will be installed at the same time. It will bring you a lot of convenience since you don't need to handle the version confliction. Thus, **it's highly recommanded to install ros-distro-desktop-full**. +This brings a lot of convenience, since you don't have to handle version conflict. ### 3.2 ROS2 -If use rslidar_sdk in ROS2 environment, ROS2 related libraries need to be installed. +To use rslidar_sdk in the ROS2 environment, please install below libraries. ++ Ubuntu 16.04 - Not supported ++ Ubuntu 18.04 - ROS2 eloquent desktop -**Ubuntu 16.04**: Not supportted +For installation, please refer to https://index.ros.org/doc/ros2/Installation/Eloquent/Linux-Install-Debians/ -**Ubuntu 18.04**: ROS2 eloquent desktop +**Please do not install ROS and ROS2 on the same computer, to avoid possible conflict and manually install some libraries, such as Yaml.** -**Installation**: please refer to https://index.ros.org/doc/ros2/Installation/Eloquent/Linux-Install-Debians/ - -**Note! Please avoid installing ROS and ROS2 on the same computer! This may cause conflict! Also you may need to install Yaml manually.** - -### 3.3 Yaml(Essential) +### 3.3 Yaml (Essential) version: >= v0.5.2 -*If ros-distro-desktop-full is installed, this section can be skipped* +*If ros-distro-desktop-full is installed, this step can be skipped* Installation: @@ -79,35 +89,33 @@ sudo apt-get update sudo apt-get install -y libyaml-cpp-dev ``` -### 3.4 Pcap(Essential) +### 3.4 libpcap (Essential) -version: >=v1.7.4 +version: >= v1.7.4 -Installation: +Installation: ```sh sudo apt-get install -y libpcap-dev ``` -### 3.5 Protobuf(Optional) +### 3.5 Protobuf (Optional) -version:>=v2.6.1 +version: >= v2.6.1 -Installation : +Installation: ```sh sudo apt-get install -y libprotobuf-dev protobuf-compiler ``` - - ## 4 Compile & Run -We offer three ways to compile and run the driver. +Please compile and run the driver in three ways. ### 4.1 Compile directly - In this way, user can use ROS facilities(not ROS2) if ROS master node is launched in advance via ```roscore```. Also, rviz can be launched seperately for visualization. +In ROS (unfortunately not ROS2), user can compile it directly. please laucn ROS master node ```roscore``` in advance, and use ```rviz``` to visualize point cloud. ```sh cd rslidar_sdk @@ -116,11 +124,9 @@ cmake .. && make -j4 ./rslidar_sdk_node ``` - - ### 4.2 Compile with ROS catkin tools -(1) Open the *CMakeLists.txt* in the project,modify the line on top of the file **set(COMPILE_METHOD ORIGINAL)** to **set(COMPILE_METHOD CATKIN)**. +(1) On top of the file *CMakeLists.txt*,change the line **set(COMPILE_METHOD ORIGINAL)** to **set(COMPILE_METHOD CATKIN)**. ```cmake #======================================= @@ -129,7 +135,7 @@ cmake .. && make -j4 set(COMPILE_METHOD CATKIN) ``` -(2) Rename the file *package_ros1.xml* in the rslidar_sdk to *package.xml* +(2) Copy the file *package_ros1.xml* to *package.xml* in the rslidar_sdk . (3) Create a new workspace folder, and create a *src* folder in it. Then put the rslidar_sdk project into the *src* folder. @@ -141,9 +147,9 @@ source devel/setup.bash roslaunch rslidar_sdk start.launch ``` -### 4.3 Compile with ROS2-colcon +### 4.3 Compile with ROS2 colcon -(1) Open the *CMakeLists.txt* in the project,modify the line on top of the file **set(COMPILE_METHOD ORIGINAL)** to **set(COMPILE_METHOD COLCON)**. +(1) On top of the file *CMakeLists.txt*, change the line **set(COMPILE_METHOD ORIGINAL)** to **set(COMPILE_METHOD COLCON)**. ```cmake #======================================= @@ -152,7 +158,7 @@ roslaunch rslidar_sdk start.launch set(COMPILE_METHOD COLCON) ``` -(2) Rename the file *package_ros2.xml* in the rslidar_sdk to *package.xml* +(2) Copy the file *package_ros2.xml* to *package.xml* in the rslidar_sdk. (3) Create a new workspace folder, and create a *src* folder in it. Then put the rslidar_sdk project in the *src* folder. @@ -166,38 +172,33 @@ source install/setup.bash ros2 launch rslidar_sdk start.py ``` - - ## 5 Introduction to parameters -This section is very important since all functions and features provided by rslidar_sdk is configured via parameter modification. So please read the following links carefully. +To change behaviors of rslidar_sdk, change its parameters. please read the following links for detail information. [Intro to parameters](doc/intro/parameter_intro.md) [Intro to hidden parameters](doc/intro/hiding_parameters_intro.md) - - ## 6 Quick start -The following documents are some quick guides for using some of the most common features of the rslidar_sdk. The rslidar_sdk are not limited to the following modes of operation and users can use rslidar_sdk in their own way by modifying parameters. +Below are some quick guides to use rslidar_sdk. [Online connect lidar and send point cloud through ROS](doc/howto/how_to_online_send_point_cloud_ros.md) -[Record rosbag & Offline decode rosbag](doc/howto/how_to_record_and_offline_decode_rosbag.md) - [Decode pcap bag and send point cloud through ROS](doc/howto/how_to_offline_decode_pcap.md) +[Record rosbag & Offline decode rosbag](doc/howto/how_to_record_and_offline_decode_rosbag.md) +## 7 Advanced Topics -## 7 Advanced +[Switch Point Type](doc/howto/how_to_switch_point_type.md) -[Send & Receive via Protobuf](doc/howto/how_to_use_protobuf_function.md) +[Multi-Cast](doc/howto/how_to_use_multi_cast_function.md) [Multi-LiDARs](doc/howto/how_to_use_multi_lidars.md) -[Switch Point Type](doc/howto/how_to_switch_point_type.md) - [Coordinate Transformation](doc/howto/how_to_use_coordinate_transformation.md) -[Multi-Cast](doc/howto/how_to_use_multi_cast_function.md) \ No newline at end of file +[Send & Receive via Protobuf](doc/howto/how_to_use_protobuf_function.md) + diff --git a/README_CN.md b/README_CN.md index c34d7183..4b652154 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,28 +1,39 @@ # **rslidar_sdk** +[English Version](README.md) + ## 1 工程简介 - **rslidar_sdk** 为速腾聚创在Ubuntu环境下的雷达驱动软件包,包括了雷达驱动内核, ROS拓展功能,ROS2拓展功能,Protobuf-UDP通信拓展功能。对于没有二次开发需求的用户,或是想直接使用ROS或ROS2进行二次开发的用户,可直接使用本软件包, 配合ROS或ROS2自带的RVIZ可视化工具即可查看点云。 对于有更深一步二次开发需求,想将雷达驱动集成到自己工程内的客户, 请参考雷达驱动内核的相关文档,直接使用内核[rs_driver](https://github.com/RoboSense-LiDAR/rs_driver)进行二次开发。 -### **1.1 雷达型号支持** + **rslidar_sdk** 是速腾聚创在Ubuntu环境下的雷达驱动软件包。它包括: + + 雷达驱动内核[rs_driver](https://github.com/RoboSense-LiDAR/rs_driver), + + ROS拓展功能, + + ROS2拓展功能, + + Protobuf-UDP通信拓展功能。 + +如果希望基于ROS/ROS2进行二次开发,可以使用本软件包。配合ROS/ROS2自带的可视化工具rviz,可以查看点云。 + +如果希望将雷达驱动集成到自己的工程,作更深一步的二次开发,请基于rs_driver进行开发。 + +### 1.1 支持的雷达型号 - RS-LiDAR-16 - RS-LiDAR-32 - RS-Bpearl +- RS-Helios - RS-Ruby - RS-Ruby Lite - RS-LiDAR-M1 -- RS-Helios -### 1.2 点的类型支持 +### 1.2 支持的点类型 - XYZI - x, y, z, intensity - XYZIRT - x, y, z, intensity, ring, timestamp ## 2 下载 -### 2.1 使用git clone +### 2.1 使用 git clone - 由于rslidar_sdk项目中包含子模块驱动内核rs_driver, 因此在执行git clone 后还需要执行相关指令初始化并更新子模块。 +rslidar_sdk项目包含子模块驱动内核rs_driver。在执行git clone后,还需要执行相关指令,初始化并更新子模块。 ```sh git clone https://github.com/RoboSense-LiDAR/rslidar_sdk.git @@ -33,37 +44,33 @@ git submodule update ### 2.2 直接下载 -用户可以直接访问 [rslidar_sdk_release](https://github.com/RoboSense-LiDAR/rslidar_sdk/releases) 下载最新版本的rslidar_sdk. 请下载 **rslidar_sdk.tar.gz** 压缩包, 不要下载Source code。 因为Source code压缩包内不包含子模块rs_driver的代码, 用户还需自行下载rs_driver的代码放入其中才行。 - -![](doc/img/download_page.png) +用户可以直接访问 [rslidar_sdk_release](https://github.com/RoboSense-LiDAR/rslidar_sdk/releases) 下载最新版本的rslidar_sdk. +请下载 **rslidar_sdk.tar.gz** 压缩包,不要下载Source code。因为Source code压缩包内不包含子模块rs_driver的代码, 用户还需自行下载rs_driver的代码放入其中才行。 +![](doc/img/download_page.png) ## 3 依赖介绍 ### 3.1 ROS -*若需在ROS环境下使用雷达驱动,则需安装ROS相关依赖库* - -Ubuntu 16.04 - ROS kinetic desktop-full +在ROS环境下使用雷达驱动,需安装ROS相关依赖库。 ++ Ubuntu 16.04 - ROS kinetic desktop-full ++ Ubuntu 18.04 - ROS melodic desktop-full -Ubuntu 18.04 - ROS melodic desktop-full +安装方法请参考 http://wiki.ros.org。 -安装方式: 参考 http://wiki.ros.org - -**如果安装了ROS kinetic desktop-full版或ROS melodic desktop-full版,那么兼容版本其他依赖库也应该同时被安装了,所以不需要重新安装它们以避免多个版本冲突引起的问题, 因此,强烈建议安装desktop-full版,这将节省大量的时间来逐个安装和配置库**。 +**强烈建议安装ROS kinetic desktop-full版或ROS melodic desktop-full版。这个过程会自动安装一些兼容版本的依赖库,如PCL库等。这样可以避免花大量时间,去逐个安装和配置它们**。 ### 3.2 ROS2 -*若需在ROS2环境下使用雷达驱动,则需安装ROS2相关依赖库* - -Ubuntu 16.04 - 不支持 +在ROS2环境下使用雷达驱动,需安装ROS2相关依赖库。 ++ Ubuntu 16.04 - 不支持 ++ Ubuntu 18.04 - ROS2 Eloquent desktop -Ubuntu 18.04 - ROS2 Eloquent desktop +安装方法请参考 https://index.ros.org/doc/ros2/Installation/Eloquent/Linux-Install-Debians/ -安装方式:参考 https://index.ros.org/doc/ros2/Installation/Eloquent/Linux-Install-Debians/ - -**注意! 请避免在同一台电脑上同时安装ROS和ROS2, 这可能会产生冲突! 同时还需要手动安装Yaml库。** +**请不要在一台电脑上同时安装ROS和ROS2,以避免可能的版本冲突,和手工安装其他库(如Yaml)的麻烦。** ### 3.3 Yaml (必需) @@ -71,18 +78,18 @@ Ubuntu 18.04 - ROS2 Eloquent desktop *若已安装ROS desktop-full, 可跳过* -安装方式: +安装方法如下: ```sh sudo apt-get update sudo apt-get install -y libyaml-cpp-dev ``` -### 3.4 Pcap (必需) +### 3.4 libpcap (必需) -版本号: >=v1.7.4 +版本号: >= v1.7.4 -安装方式: +安装方法如下: ```sh sudo apt-get install -y libpcap-dev @@ -90,23 +97,21 @@ sudo apt-get install -y libpcap-dev ### 3.5 Protobuf (可选) -版本号: >=v2.6.1 +版本号: >= v2.6.1 -安装方式: +安装方法如下: ```sh sudo apt-get install -y libprotobuf-dev protobuf-compiler ``` - - ## 4 编译 & 运行 -我们提供三种编译&运行方式。 +可以使用三种方式编译、运行rslidar_sdk。 ### 4.1 直接编译 -按照如下指令即可编译运行程序。 直接编译也可以使用ROS相关功能(不包括ROS2),但需要在程序启动前**手动启动roscore**,启动后**手动打开rviz**才能看到可视化点云结果。 +在ROS1(不适用于ROS2)中,可以直接编译、运行程序。 请先启动**roscore**,再运行**rslidar_sdk_node**,最后运行**rviz**查看点云。 ```sh cd rslidar_sdk @@ -126,11 +131,11 @@ cmake .. && make -j4 set(COMPILE_METHOD CATKIN) ``` -(2) 将rslidar_sdk工程目录下的*package_ros1.xml*文件重命名为*package.xml*。 +(2) 将rslidar_sdk工程目录下的*package_ros1.xml*文件复制到*package.xml*。 (3) 新建一个文件夹作为工作空间,然后再新建一个名为*src*的文件夹, 将rslidar_sdk工程放入*src*文件夹内。 -(4) 返回工作空间目录,执行以下命令即可编译&运行(若使用.zsh,将第二句指令替换为 *source devel/setup.zsh*)。 +(4) 返回工作空间目录,执行以下命令即可编译、运行。如果使用.zsh,将第二行替换成 *source devel/setup.zsh*。 ```sh catkin_make @@ -153,9 +158,9 @@ set(COMPILE_METHOD COLCON) (3) 新建一个文件夹作为工作空间,然后再新建一个名为*src*的文件夹, 将rslidar_sdk工程放入*src*文件夹内。 -(4) 通过[链接](https://github.com/RoboSense-LiDAR/rslidar_msg)下载ROS2环境下的雷达packet消息定义, 将rslidar_msg工程也放在刚刚新建的*src*文件夹内,与rslidar_sdk并列。 +(4) 通过[链接](https://github.com/RoboSense-LiDAR/rslidar_msg),下载ROS2环境下的雷达packet消息定义,将rslidar_msg工程也放在刚刚新建的*src*文件夹内,与rslidar_sdk并列。 -(5) 返回工作空间目录,执行以下命令即可编译&运行(若使用.zsh,将第二句指令替换为 *source install/setup.zsh*)。 +(5) 返回工作空间目录,执行以下命令即可编译、运行。如果使用.zsh,将第二行替换为*source install/setup.zsh*。 ```sh colcon build @@ -163,38 +168,33 @@ source install/setup.bash ros2 launch rslidar_sdk start.py ``` - - ## 5 参数介绍 -参数介绍非常重要,请仔细阅读。 本软件包的所有功能都将通过配置参数文件来实现。 +rslidar_sdk的功能通过配置参数文件来实现,请仔细阅读。 [参数介绍](doc/intro/parameter_intro_cn.md) [隐藏参数介绍](doc/intro/hiding_parameters_intro_cn.md) - - ## 6 快速上手 -以下仅为一些常用功能的快速使用指南, 实际使用时并不仅限于以下几种工作模式, 可通过配置参数改变不同的工作模式。 +以下是一些常用功能的使用指南。 [在线读取雷达数据发送到ROS](doc/howto/how_to_online_send_point_cloud_ros_cn.md) -[录制ROS数据包&离线解析ROS数据包](doc/howto/how_to_record_and_offline_decode_rosbag_cn.md) - [离线解析Pcap包发送到ROS](doc/howto/how_to_offline_decode_pcap_cn.md) - +[录制ROS数据包&离线解析ROS数据包](doc/howto/how_to_record_and_offline_decode_rosbag_cn.md) ## 7 使用进阶 -[使用Protobuf发送&接收](doc/howto/how_to_use_protobuf_function_cn.md) +[切换点的类型](doc/howto/how_to_switch_point_type_cn.md) -[多雷达](doc/howto/how_to_use_multi_lidars_cn.md) +[组播模式](doc/howto/how_to_use_multi_cast_function_cn.md) -[切换点的类型](doc/howto/how_to_switch_point_type_cn.md) +[多雷达](doc/howto/how_to_use_multi_lidars_cn.md) [坐标变换功能](doc/howto/how_to_use_coordinate_transformation_cn.md) -[组播模式](doc/howto/how_to_use_multi_cast_function_cn.md) \ No newline at end of file +[使用Protobuf发送&接收](doc/howto/how_to_use_protobuf_function_cn.md) + From 42828c98b37c85f7d5b676d5ff3018be28fca217 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 15 Mar 2022 16:49:57 +0800 Subject: [PATCH 112/261] feat: update docs --- doc/intro/parameter_intro.md | 68 ++++++++++++++++----------------- doc/intro/parameter_intro_cn.md | 59 ++++++++++++++-------------- 2 files changed, 63 insertions(+), 64 deletions(-) diff --git a/doc/intro/parameter_intro.md b/doc/intro/parameter_intro.md index d29e15b4..183c3a5a 100644 --- a/doc/intro/parameter_intro.md +++ b/doc/intro/parameter_intro.md @@ -1,16 +1,16 @@ -# Parameters Introduction +# Introduction to Parameters -There is only one configuration file ```config.yaml```, which is stored in ```rslidar_sdk/config```. The ```config.yaml``` can be divided into two parts, the common part and the lidar part. +rslidar_sdk reads parameters from the configuration file ```config.yaml```, which is stored in ```rslidar_sdk/config```. -*In multi-LiDARs case, the parameters in common part will be shared by all LiDARs, while the parameters in lidar part need to be adjusted for each LiDAR.* - -**config.yaml is indentation sensitive! Please make sure the indentation is not changed when adjusting the parameters!** +`config.yaml` contains two parts, the `common` part and the `lidar` part. +rslidar_sdk supports multi-LiDARs case. The `common` part is shared by all LiDARs, while in the `lidar` part, each child node is for an individual Lidar. +**config.yaml is indentation sensitive! Please make sure the indentation is not changed after adjusting the parameters!** ## 1 Common -This part specifies the source of LiDAR packets, and where to publish point clouds and packets. +The `common` part specifies the source of LiDAR packets, and where to publish point clouds and packets. ```yaml common: @@ -23,46 +23,44 @@ common: - msg_source - - 0 -- Unused. Basically you will never set this parameter to 0. + - 0 -- Unused. Never set this parameter to 0. - - 1 -- The lidar packets come from online lidars. For more details, please refer to [Online connect lidar and send point cloud through ROS](../howto/how_to_online_send_point_cloud_ros.md) + - 1 -- LiDAR packets come from on-line LiDARs. For more details, please refer to [Online connect LiDAR and send point cloud through ROS](../howto/how_to_online_send_point_cloud_ros.md) - - 2 -- The lidar packets come from ROS or ROS2. This will be used to decode from an offline rosbag. For more details, please refer to [Record rosbag & Offline decode rosbag](../howto/how_to_record_and_offline_decode_rosbag.md) + - 2 -- LiDAR packets come from ROS/ROS2. It is used to decode from an off-line rosbag. For more details, please refer to [Record rosbag & Offline decode rosbag](../howto/how_to_record_and_offline_decode_rosbag.md) - - 3 -- The lidar packets come from offline a pcap bag. For more details, please refer to [Decode pcap bag and send point cloud through ROS](../howto/how_to_offline_decode_pcap.md) + - 3 -- LiDAR packets come from a PCAP bag. For more details, please refer to [Decode PCAP bag and send point cloud through ROS](../howto/how_to_offline_decode_pcap.md) - - 4 -- The lidar packets come from Protobuf-UDP. For more details, please refer to [Use protobuf send & receive](../howto/how_to_use_protobuf_function.md) + - 4 -- LiDAR packets come from Protobuf-UDP. For more details, please refer to [Use protobuf send & receive](../howto/how_to_use_protobuf_function.md) - - 5 -- The lidar point cloud come from Protobuf-UDP. For more details, please refer to [Use protobuf send & receive](../howto/how_to_use_protobuf_function.md) + - 5 -- LiDAR point cloud come from Protobuf-UDP. For more details, please refer to [Use protobuf send & receive](../howto/how_to_use_protobuf_function.md) - send_packet_ros - - true -- The lidar packets will be sent to ROS or ROS2. + - true -- LiDAR packets will be sent to ROS/ROS2. - -*Since the ROS packet message is of a customized message type, you can't directly echo the topic through ROS. Mostly the packets are only used to record offline rosbag because the size is much smaller than point cloud.* +*The ROS Packet message is of a customized message type, so you can't print its content via the ROS `echo` command. This option is used to record off-line Packet rosbags. For more details, please refer to the case of msg_source=2.* - send_point_cloud_ros - - true -- The lidar point cloud will be sent to ROS or ROS2. + - true -- The LiDAR point cloud will be sent to ROS/ROS2. - *The ROS point cloud type is the ROS official defined type -- sensor_msgs/PointCloud2, which means the point cloud can be visualized on ROS-Rviz directly. Also you can record the point cloud to rosbag but its size may be very large, that's why we suggest to record packets.* + *The ROS point cloud type is the ROS official defined type -- sensor_msgs/PointCloud2, so it can be visualized on the ROS `rviz` tool directly. It is not suggested to record the point cloud to rosbag, because its size may be very large. Please record Packets instead. Refer to the case of msg_source=2.* - send_packet_proto - - true -- The lidar packets will be sent out as protobuf message through ethernet by UDP protocal. + - true -- The Lidar packets will be sent out as Protobuf message by the UDP protocol. - send_point_cloud_proto - - true -- The lidar point cloud will be sent out as protobuf message through ethernet by UDP protocal. + - true -- The Lidar point cloud will be sent out as Protobuf message by the UDP protocol. -*We suggest sending packets rather than point clouds through ethernet by protobuf because point cloud size is too large which may take up a lot of bandwidth.* - +*The point cloud is too large, so it is suggested to send packets rather than point clouds. Please refer to the case of send_packet_proto=true.* ## 2 lidar -This part needs to be adjusted for every LiDAR seperately (in multi-LiDARs case). +The `lidar` part needs to be adjusted for every LiDAR seperately. ```yaml lidar: @@ -94,15 +92,15 @@ lidar: - lidar_type - Supported types of LiDAR are listed in README. + Supported LiDAR types are listed in the README file. - msop_port, difop_port - The msop port and difop_port of LiDAR. *Please check these parameters first is no data received.* + The MSOP port and DIFOP port to receive LiDAR packets. *If no data is received, please check these parameters first.* - start_angle, end_angle - The start angle and end angle of the point cloud, which should be set in range of 0~360°. (*start_angle **can** be larger than end_angle*). + The start angle and end angle of the point cloud, which should be in the range of 0~360°. *`start_angle` can be larger than `end_angle`*. - min_distance, max_distance @@ -110,18 +108,18 @@ lidar: - use_lidar_clock - - true -- Use the lidar internal clock as the message timestamp - - false -- Use the system clock as the message timestamp + - true -- Use the Lidar clock as the message timestamp + - false -- Use the host machine clock as the message timestamp - pcap_path - The absolute path of the pcap file. Valid if msg_source = 3. + The full path of the PCAP file. Valid if msg_source = 3. ## 3 Example -Here are two examples. The first configuration file is for single LiDAR, and the second is for 3 LiDARs. Please adjust the specific parameters according to your own case. +### 3.1 Single Lidar Case -- Connect to one online LiDAR, Send point cloud to ROS +Connect to 1 LiDAR of RS128, and send point cloud to ROS. ```yaml common: @@ -140,7 +138,6 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false - pcap_path: /home/robosense/lidar.pcap ros: ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets @@ -157,9 +154,11 @@ lidar: packet_send_ip: 127.0.0.1 ``` -- Connect to three online LiDARs, Send point cloud to ROS +### 3.2 Multi Lidar Case + +Connect to 1 LiDAR of RS128, and 2 LiDARs of RSBP, and send point cloud to ROS. -*Pay attention to the indentation of lidar part* +*Pay attention to the indentation of the `lidar` part* ```yaml common: @@ -178,7 +177,6 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false - pcap_path: /home/robosense/lidar.pcap ros: ros_frame_id: /rslidar ros_recv_packet_topic: /middle/rslidar_packets @@ -202,7 +200,6 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false - pcap_path: /home/robosense/lidar.pcap ros: ros_frame_id: /rslidar ros_recv_packet_topic: /left/rslidar_packets @@ -226,7 +223,6 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false - pcap_path: /home/robosense/lidar.pcap ros: ros_frame_id: /rslidar ros_recv_packet_topic: /right/rslidar_packets diff --git a/doc/intro/parameter_intro_cn.md b/doc/intro/parameter_intro_cn.md index 86d0e2c2..96f19e1d 100644 --- a/doc/intro/parameter_intro_cn.md +++ b/doc/intro/parameter_intro_cn.md @@ -1,12 +1,16 @@ # 参数介绍 -本工程只有一份参数文件 ```config.yaml```, 储存于```rslidar_sdk/config```文件夹内。 整个参数文件可以被分为两部分,common部分以及lidar部分。 *在多雷达的情况下,common部分的参数设置为所有雷达共享,而lidar部分,则针对每个雷达的实际情况分别设置。* +rslidar_sdk读取配置文件 ```config.yaml```,得到所有的参数。```config.yaml```在```rslidar_sdk/config```文件夹中。 -**参数文件config.yaml遵循yaml格式,该格式对缩进有严格的要求。修改参数之后,请确保每行开头的缩进仍保持一致!** +**config.yaml遵循YAML格式。该格式对缩进有严格要求。修改config.yaml之后,请确保每行开头的缩进仍保持一致!** -## 1 Common +config.yaml包括两部分:common部分 和 lidar部分。 -这部分设置雷达的消息来源,以及将结果发布到哪里。 +rslidar_sdk支持多个雷达。common部分为所有雷达共享。lidar部分,每一个子节点对应一个雷达,针对这个雷达的实际情况分别设置。 + +## 1 common部分 + +common部分设置雷达消息的源(Packet或点云从哪来)和目标(Packet或点云发布到哪去)。 ```yaml common: @@ -19,27 +23,27 @@ common: - msg_source - - 1 -- 连接在线雷达。更多使用细节请参考[在线读取雷达数据发送到ROS](../howto/how_to_online_send_point_cloud_ros_cn.md)。 + - 1 -- 连接在线雷达。更多使用细节,请参考[在线读取雷达数据发送到ROS](../howto/how_to_online_send_point_cloud_ros_cn.md)。 - - 2 -- 离线解析ROS或ROS2的packet包。更多使用细节请参考 [录制ROS数据包&离线解析ROS数据包](doc/howto/how_to_record_and_offline_decode_rosbag_cn.md)。 + - 2 -- 离线解析ROS/ROS2的Packet包。更多使用细节,请参考 [录制ROS数据包&离线解析ROS数据包](doc/howto/how_to_record_and_offline_decode_rosbag_cn.md)。 - - 3 -- 离线解析pcap包。更多使用细节请参考[离线解析Pcap包发送到ROS](doc/howto/how_to_offline_decode_pcap_cn.md)。 + - 3 -- 离线解析PCAP包。更多使用细节,请参考[离线解析PCAP包发送到ROS](doc/howto/how_to_offline_decode_pcap_cn.md)。 - - 4 -- 雷达消息来源为Protobuf-UDP的Packet消息,更多使用细节请参考 [使用Protobuf发送&接收](../howto/how_to_use_protobuf_function_cn.md)。 + - 4 -- 雷达消息来源为Protobuf-UDP的Packet消息,更多使用细节,请参考 [使用Protobuf发送&接收](../howto/how_to_use_protobuf_function_cn.md)。 - - 5 -- 雷达消息来源为Protobuf-UDP的点云消息,更多使用细节请参考 [使用Protobuf发送&接收](../howto/how_to_use_protobuf_function_cn.md)。 + - 5 -- 雷达消息来源为Protobuf-UDP的点云消息,更多使用细节,请参考 [使用Protobuf发送&接收](../howto/how_to_use_protobuf_function_cn.md)。 - send_packet_ros - - true -- 雷达packet消息将通过ROS或ROS2发出 + - true -- 雷达Packet消息将通过ROS/ROS2发出 - *由于雷达ROS packet消息为速腾聚创自定义ROS消息,因此用户无法直接echo话题查看消息具体内容。实际上packet主要用于录制离线ROS包,因为packet的体积小于点云。* + *雷达ROS packet消息为速腾聚创自定义ROS消息,用户使用ROS/ROS2 echo命令不能查看消息的具体内容。这个功能用于录制ROS/ROS2的Packet包,更多使用细节,请参考 [录制ROS数据包&离线解析ROS数据包](doc/howto/how_to_record_and_offline_decode_rosbag_cn.md)。* - send_point_cloud_ros - - true -- 雷达点云消息将通过ROS或ROS2发出 + - true -- 雷达点云消息将通过ROS/ROS2发出 - *点云消息类型为ROS官方定义的点云类型sensor_msgs/PointCloud2, 因此用户可以直接使用Rviz查看点云。同时,用户也可以选择录包时直接录制点云,但这样做包的体积会非常大,因此我们建议离线录制ROS包时录制packet消息。* + *点云消息的类型为ROS官方定义的点云类型sensor_msgs/PointCloud2, 用户可以使用Rviz直接查看点云。用户可以录制ROS/ROS2的点云包,但点云包的体积非常大,所以不建议这么做。更好的方式是录制Packet包,请参考send_packet_ros=true的情况。* - send_packet_proto @@ -49,12 +53,12 @@ common: - true -- 雷达点云消息将通过Protobuf-UDP发出 - *我们建议发送packet消息而不是点云,因为点云消息体积过大,对带宽有较高的要求。.* + *点云消息过大,对带宽有较高的要求,所以不建议这么做。更好的方式是发送Packet消息,请参考send_packet_proto=true的情况。* -## 2 lidar +## 2 lidar部分 -本部分根据每个雷达的实际情况进行设置(在多雷达的情况下)。 +lidar部分根据每个雷达的实际情况进行设置。 ```yaml lidar: @@ -86,33 +90,34 @@ lidar: - lidar_type - 目前支持的雷达型号已在README中列出。 + 支持的雷达型号在rslidar_sdk的README文件中列出。 - msop_port, difop_port - 点云的msop端口号和difop端口号。 *若收不到消息,请优先确认这两个参数是否配置正确。* + 接收MSOP/DIFOP Packet的msop端口号和difop端口号。 *若收不到消息,请优先确认这两个参数是否配置正确。* - start_angle, end_angle - 点云消息的起始角度和结束角度,此处设置为软件屏蔽,无法减小每帧点云的体积,只会将区域外的点设置为NAN点。 起始角和结束角的范围应在0~360°之间。(**起始角可以大于结束角**). + 点云消息的起始角度和结束角度。这个设置是软件屏蔽,将区域外的点设置为NAN点,不会减小每帧点云的体积。 start_angle和end_angle的范围是0~360°,**起始角可以大于结束角**. - min_distance, max_distance - 点云的最小距离和最大距离,此处设置为软件屏蔽,无法减小每帧点云的体积,只会将区域外的点设置为NAN点。 + 点云的最小距离和最大距离。这个设置是软件屏蔽,会将区域外的点设置为NAN点,不会减小每帧点云的体积。 - use_lidar_clock - true -- 使用雷达时间作为消息时间戳。 - - false -- 使用系统时间作为消息时间戳。 + - false -- 使用电脑主机时间作为消息时间戳。 - pcap_path pcap包的路径。当 msg_source=3 时有效。 - ## 3 示例 -在线连接一台雷达,并发送点云到ROS。 +### 3.1 单台雷达 + +在线连接1台RS128雷达,并发送点云到ROS。 ```yaml common: @@ -131,7 +136,6 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false - pcap_path: /home/robosense/lidar.pcap ros: ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets @@ -148,7 +152,9 @@ lidar: packet_send_ip: 127.0.0.1 ``` -在线连接3台雷达,并发送点云到ROS。 +### 3.2 单台雷达 + +在线连接1台RS128雷达和2台RSBP雷达,发送点云到ROS。 *注意lidar部分参数的缩进* @@ -169,7 +175,6 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false - pcap_path: /home/robosense/lidar.pcap ros: ros_frame_id: /rslidar ros_recv_packet_topic: /middle/rslidar_packets @@ -193,7 +198,6 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false - pcap_path: /home/robosense/lidar.pcap ros: ros_frame_id: /rslidar ros_recv_packet_topic: /left/rslidar_packets @@ -217,7 +221,6 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false - pcap_path: /home/robosense/lidar.pcap ros: ros_frame_id: /rslidar ros_recv_packet_topic: /right/rslidar_packets From 1f613258b652c57a4aee01d15db9448c9b6a0e92 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 16 Mar 2022 11:57:53 +0800 Subject: [PATCH 113/261] feat: update docs --- ...e_decode_pcap.md => how_to_decode_pcap.md} | 27 ++++++++-------- ...de_pcap_cn.md => how_to_decode_pcap_cn.md} | 32 ++++++++++--------- 2 files changed, 31 insertions(+), 28 deletions(-) rename doc/howto/{how_to_offline_decode_pcap.md => how_to_decode_pcap.md} (68%) rename doc/howto/{how_to_offline_decode_pcap_cn.md => how_to_decode_pcap_cn.md} (54%) diff --git a/doc/howto/how_to_offline_decode_pcap.md b/doc/howto/how_to_decode_pcap.md similarity index 68% rename from doc/howto/how_to_offline_decode_pcap.md rename to doc/howto/how_to_decode_pcap.md index a5685c69..8bf657a9 100644 --- a/doc/howto/how_to_offline_decode_pcap.md +++ b/doc/howto/how_to_decode_pcap.md @@ -1,8 +1,8 @@ -# How to decode pcap bag and send point cloud to ROS +# How to decode PCAP file ## 1 Introduction -This document illustrates how to decode pcap bag and send point cloud to ROS. +This document illustrates how to decode PCAP file, and send point cloud to ROS. Please make sure you have read the LiDAR user-guide and [Intro to parameters](doc/intro/parameter_intro.md) before reading this document. @@ -12,11 +12,13 @@ Please make sure you have read the LiDAR user-guide and [Intro to parameters](do Please follow the instructions in LiDAR user-guide to connect the LiDAR, and set up your computer's ip address. -At this time, you should have already known your LiDAR's msop port number and difop port number. The default is ```msop-6699, difop-7788```. +Please check the LiDAR user-guide, or use the 3rd-party tool(such as WireShark), to get your LiDAR's MSOP port number and DIFOP port number. The default values are ```msop-6699, difop-7788```. -If you have no idea about what it is, please check the LiDAR user-guide. +### 2.2 Set up the configuration file -### 2.2 Set up the common part of the config file +Set up the configuration file `config.yaml`. + +#### 2.2.1 common part ```yaml common: @@ -27,11 +29,11 @@ common: send_point_cloud_proto: false ``` -The messages come from the pcap bag, so set ```msg_source = 3```. +The messages come from the PCAP bag, so set ```msg_source = 3```. Send point cloud to ROS, so set ```send_point_cloud_ros = true```. -### 2.3 Set up the lidar-driver part of the config file +#### 2.2.2 lidar-driver part ```yaml lidar: @@ -47,13 +49,13 @@ lidar: pcap_path: /home/robosense/lidar.pcap ``` -Set the ```pcap_path``` to the absolute path of the pcap file. +Set the ```pcap_path``` to the absolute path of the PCAP file. Set the ```lidar_type``` to your LiDAR type. -Set the ```msop_port``` and ```difop_port``` to the port number of your LiDAR. +Set the ```msop_port``` and ```difop_port``` to the port numbers of your LiDAR. -### 2.4 Set up the lidar-ros part of the config file +#### 2.2.3 lidar-ros part ```yaml ros: @@ -63,9 +65,9 @@ ros: ros_send_point_cloud_topic: /rslidar_points ``` -Set the ```ros_send_point_cloud_topic``` to the topic you want to send. +Set the ```ros_send_point_cloud_topic``` to the topic you want to send to. -### 2.5 Run +### 2.3 Run Run the program. @@ -73,4 +75,3 @@ Run the program. - diff --git a/doc/howto/how_to_offline_decode_pcap_cn.md b/doc/howto/how_to_decode_pcap_cn.md similarity index 54% rename from doc/howto/how_to_offline_decode_pcap_cn.md rename to doc/howto/how_to_decode_pcap_cn.md index 27aca4f3..cb8363e4 100644 --- a/doc/howto/how_to_offline_decode_pcap_cn.md +++ b/doc/howto/how_to_decode_pcap_cn.md @@ -1,20 +1,22 @@ -# 如何解码pcap包并发送点云数据到ROS +# 如何解码PCAP包并发送点云数据到ROS ## 1 简介 -本文档将展示如何解码pcap包, 并发送点云数据到ROS。 +本文档展示如何解码PCAP包, 并发送点云数据到ROS。 在阅读本文档之前,请确保已阅读雷达用户手册和 [参数简介](../intro/parameter_intro.md) 。 ## 2 步骤 -### 2.1 获取数据端口号 +### 2.1 获取数据的端口号 -根据雷达用户手册连接雷达, 并设置好您的电脑的IP地址。 +根据雷达用户手册,连接雷达, 并设置好您的电脑的IP地址。 -此时应该已知雷达的msop端口号和difop端口号,默认值为```msop-6699, difop-7788```。 如果不清楚上述内容,请查看雷达用户手册。 +请参考雷达用户手册,或者使用第三方工具(WireShark等)抓包,得到雷达的目标MSOP端口和目标DIFOP端口。端口的默认值分别为`6699`和`7788`。 -### 2.2 设置参数文件的common部分 +### 2.2 设置参数文件 + +#### 2.2.1 common部分 ```yaml common: @@ -25,11 +27,11 @@ common: send_point_cloud_proto: false ``` -由于消息来自pcap包,因此请设置 ```msg_source = 3``` 。 +消息来自PCAP包,所以设置 ```msg_source = 3``` 。 -将点云发送到ROS以查看,因此设置 ```send_point_cloud_ros = true``` 。 +将点云发送到ROS以便查看,所以设置 ```send_point_cloud_ros = true``` 。 -### 2.3 设置参数文件的 lidar-driver部分 +#### 2.2.2 lidar-driver部分 ```yaml lidar: @@ -45,13 +47,13 @@ lidar: pcap_path: /home/robosense/lidar.pcap ``` -将```pcap_path``` 设置为pcap文件的路径。 +将```pcap_path``` 设置为PCAP文件的全路径。 -将 ```lidar_type``` 设置为LiDAR类型 。 +将 ```lidar_type``` 设置为LiDAR类型。 -设置 ```msop_port``` 和 ```difop_port``` 为雷达数据端口号。 +设置 ```msop_port``` 和 ```difop_port``` 为雷达数据的目标端口号,这里分别是6699和7788。 -### 2.4设置配置文件的lidar-ros部分 +#### 2.2.3 lidar-ros部分 ```yaml ros: @@ -61,8 +63,8 @@ ros: ros_send_point_cloud_topic: /rslidar_points ``` -将 ```ros_send_point_cloud_topic``` 设置为发送点云的话题。 +将 ```ros_send_point_cloud_topic``` 设置为发送点云的话题,这里是/rslidar_points。 -#### 2.5 运行 +### 2.3 运行 运行程序。 From 20ea16e30e19a131869eef79a78ef6d67c2d9c8f Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 16 Mar 2022 12:15:46 +0800 Subject: [PATCH 114/261] feat: update docs --- ...d_ros.md => how_to_decode_online_lidar.md} | 25 +++++++++---------- ...cn.md => how_to_decode_online_lidar_cn.md} | 23 +++++++++-------- doc/howto/how_to_decode_pcap.md | 2 -- doc/howto/how_to_decode_pcap_cn.md | 4 +-- 4 files changed, 27 insertions(+), 27 deletions(-) rename doc/howto/{how_to_online_send_point_cloud_ros.md => how_to_decode_online_lidar.md} (64%) rename doc/howto/{how_to_online_send_point_cloud_ros_cn.md => how_to_decode_online_lidar_cn.md} (68%) diff --git a/doc/howto/how_to_online_send_point_cloud_ros.md b/doc/howto/how_to_decode_online_lidar.md similarity index 64% rename from doc/howto/how_to_online_send_point_cloud_ros.md rename to doc/howto/how_to_decode_online_lidar.md index 5ee226fc..92901320 100644 --- a/doc/howto/how_to_online_send_point_cloud_ros.md +++ b/doc/howto/how_to_decode_online_lidar.md @@ -1,8 +1,8 @@ -# How to online connect lidar and send point cloud to ROS +# How to decode on-line LiDAR ## 1 Introduction -This document illustrates how to connect to an online LiDAR and send point cloud to ROS. +This document illustrates how to connect to an on-line LiDAR, and send point cloud to ROS. Please make sure you have read the LiDAR user-guide and [Intro to parameters](../intro/parameter_intro.md) before reading this document. @@ -10,13 +10,13 @@ Please make sure you have read the LiDAR user-guide and [Intro to parameters](.. ### 2.1 Get the LiDAR port number -Please follow the instructions in LiDAR user-guide, to connect to the LiDAR and set up your computer's ip address. +Please follow the instructions in LiDAR user-guide, to connect the LiDAR, and set up your computer's ip address. -At this time, you should have already known your LiDAR's msop port number and difop port number. The default is ```msop-6699, difop-7788```. +Please check the LiDAR user-guide, or use the 3rd-party tool(such as WireShark), to get your LiDAR's MSOP port number and DIFOP port number. The default values are ```msop-6699, difop-7788```. -If you have no idea about what it is, please check the LiDAR user-guide. +### 2.2 Set up the configuration file -### 2.2 Set up the common part of the config file +#### 2.2.1 common part ```yaml common: @@ -27,11 +27,11 @@ common: send_point_cloud_proto: false ``` -Since the message come from the LiDAR, set ```msg_source = 1```. +The message come from the LiDAR, so set ```msg_source = 1```. -Send point cloud to ROS so set ```send_point_cloud_ros = true```. +Send point cloud to ROS, so set ```send_point_cloud_ros = true```. -### 2.3 Set up the lidar-driver part of the config file +#### 2.2.2 lidar-driver part ```yaml lidar: @@ -50,7 +50,7 @@ Set the ```lidar_type``` to your LiDAR type. Set the ```msop_port``` and ```difop_port``` to your LiDAR's port number. -### 2.4 Set up the lidar-ros part of the config file +#### 2.2.3 lidar-ros part ```yaml ros: @@ -60,10 +60,9 @@ ros: ros_send_point_cloud_topic: /rslidar_points ``` -Set the ```ros_send_point_cloud_topic``` to the topic you want to send. +Set the ```ros_send_point_cloud_topic``` to the topic you want to send to. -### 2.5 Run +### 2.3 Run Run the program. - diff --git a/doc/howto/how_to_online_send_point_cloud_ros_cn.md b/doc/howto/how_to_decode_online_lidar_cn.md similarity index 68% rename from doc/howto/how_to_online_send_point_cloud_ros_cn.md rename to doc/howto/how_to_decode_online_lidar_cn.md index ba8054f3..665798bf 100644 --- a/doc/howto/how_to_online_send_point_cloud_ros_cn.md +++ b/doc/howto/how_to_decode_online_lidar_cn.md @@ -1,8 +1,8 @@ -# 如何在线连接雷达并发送点云数据到ROS +# 如何连接在线雷达 ## 1 简介 -本文档描述了如何在线连接雷达,并发送点云数据到ROS。 +本文档描述如何连接在线雷达,并发送点云数据到ROS。 在阅读本文档之前, 请确保已经阅读过雷达用户手册和[参数简介](../intro/parameter_intro.md) 。 @@ -12,9 +12,13 @@ 根据雷达用户手册连接雷达, 并设置好您的电脑的IP地址。 -此时应该已知雷达的msop端口号和difop端口号,默认值为```msop-6699, difop-7788```。 如果不清楚上述内容,请查看雷达用户手册。 +请参考雷达用户手册,或使用第三方工具(如WireShark等)得到雷达的MSOP端口号和DIFOP端口号。端口的默认值分别为```6699```和```7788```。 -### 2.2 设置参数文件的common部分 +### 2.2 设置参数文件 + +设置参数文件```config.yaml```。 + +#### 2.2.1 common部分 ```yaml common: @@ -25,11 +29,11 @@ common: send_point_cloud_proto: false ``` -由于消息来源于在线雷达,因此请设置```msg_source=1```。 +消息来源于在线雷达,因此请设置```msg_source=1```。 -将点云发送到ROS以查看,因此设置 ```send_point_cloud_ros = true``` 。 +将点云发送到ROS以便查看,因此设置 ```send_point_cloud_ros = true``` 。 -### 2.3 设置参数文件的 lidar-driver部分 +#### 2.2.2 lidar-driver部分 ```yaml lidar: @@ -48,7 +52,7 @@ lidar: 设置 ```msop_port``` 和 ```difop_port``` 为雷达数据端口号。 -### 2.4设置配置文件的lidar-ros部分 +#### 2.2.3 lidar-ros部分 ```yaml ros: @@ -60,8 +64,7 @@ ros: 将 ```ros_send_point_cloud_topic``` 设置为发送点云的话题。 -### 2.5 运行 +### 2.3 运行 运行程序。 - diff --git a/doc/howto/how_to_decode_pcap.md b/doc/howto/how_to_decode_pcap.md index 8bf657a9..685909d0 100644 --- a/doc/howto/how_to_decode_pcap.md +++ b/doc/howto/how_to_decode_pcap.md @@ -10,8 +10,6 @@ Please make sure you have read the LiDAR user-guide and [Intro to parameters](do ### 2.1 Get the LiDAR port number -Please follow the instructions in LiDAR user-guide to connect the LiDAR, and set up your computer's ip address. - Please check the LiDAR user-guide, or use the 3rd-party tool(such as WireShark), to get your LiDAR's MSOP port number and DIFOP port number. The default values are ```msop-6699, difop-7788```. ### 2.2 Set up the configuration file diff --git a/doc/howto/how_to_decode_pcap_cn.md b/doc/howto/how_to_decode_pcap_cn.md index cb8363e4..23cf195e 100644 --- a/doc/howto/how_to_decode_pcap_cn.md +++ b/doc/howto/how_to_decode_pcap_cn.md @@ -10,12 +10,12 @@ ### 2.1 获取数据的端口号 -根据雷达用户手册,连接雷达, 并设置好您的电脑的IP地址。 - 请参考雷达用户手册,或者使用第三方工具(WireShark等)抓包,得到雷达的目标MSOP端口和目标DIFOP端口。端口的默认值分别为`6699`和`7788`。 ### 2.2 设置参数文件 +设置参数文件```config.yaml```。 + #### 2.2.1 common部分 ```yaml From a09b185768bc4620f61c4ac773c915cbd3d027f9 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 16 Mar 2022 15:49:54 +0800 Subject: [PATCH 115/261] feat: update docs --- doc/howto/how_to_change_point_type.md | 53 ++++++++++++++++ doc/howto/how_to_change_point_type_cn.md | 54 ++++++++++++++++ ...ode_pcap.md => how_to_decode_pcap_file.md} | 0 ...ap_cn.md => how_to_decode_pcap_file_cn.md} | 4 +- ... => how_to_record_replay_packet_rosbag.md} | 0 ... how_to_record_replay_packet_rosbag_cn.md} | 0 doc/howto/how_to_switch_point_type.md | 61 ------------------- doc/howto/how_to_switch_point_type_cn.md | 54 ---------------- 8 files changed, 109 insertions(+), 117 deletions(-) create mode 100644 doc/howto/how_to_change_point_type.md create mode 100644 doc/howto/how_to_change_point_type_cn.md rename doc/howto/{how_to_decode_pcap.md => how_to_decode_pcap_file.md} (100%) rename doc/howto/{how_to_decode_pcap_cn.md => how_to_decode_pcap_file_cn.md} (94%) rename doc/howto/{how_to_record_and_offline_decode_rosbag.md => how_to_record_replay_packet_rosbag.md} (100%) rename doc/howto/{how_to_record_and_offline_decode_rosbag_cn.md => how_to_record_replay_packet_rosbag_cn.md} (100%) delete mode 100644 doc/howto/how_to_switch_point_type.md delete mode 100644 doc/howto/how_to_switch_point_type_cn.md diff --git a/doc/howto/how_to_change_point_type.md b/doc/howto/how_to_change_point_type.md new file mode 100644 index 00000000..2ade699b --- /dev/null +++ b/doc/howto/how_to_change_point_type.md @@ -0,0 +1,53 @@ +# How to change point type + +## 1 Introduction + +This document illustrates how to change the point type. + +To change the type, open the ```CMakeLists.txt``` of the project, and change the variable `POINT_TYPE`. Remember to **rebuild** the project after changing it. + +```cmake +#======================================= +# Custom Point Type (XYZI, XYZIRT) +#======================================= +set(POINT_TYPE XYZI) +``` + +## 2 XYZI + +If `POINT_TYPE` is `XYZI`, rslidar_sdk uses the PCL official type```pcl::PointXYZI```. + +``` +typedef pcl::PointXYZI PointXYZI; +``` + +rslidar_sdk transforms point cloud of `PointXYZI` to ROS message of `PointCloud2`,and publish it. + +``` + PointCloudT rs_msg; + sensor_msgs::msg::PointCloud2 ros_msg; + pcl::toROSMsg(rs_msg, ros_msg); +``` + +## 3 XYZIRT + +If `POINT_TYPE` is `XYZIRT`, rslidar_sdk uses the RoboSense defined type as below. + +```c++ +struct PointXYZIRT +{ + PCL_ADD_POINT4D; + uint8_t intensity; + uint16_t ring = 0; + double timestamp = 0; + EIGEN_MAKE_ALIGNED_OPERATOR_NEW +} EIGEN_ALIGN16; +``` + +rslidar_sdk transforms point cloud of `PointXYZIRT` to ROS message of `PointCloud2`,and publish it. + +```c++ +pcl::PointCloud::Ptr cloud_ptr (new pcl::PointCloud); +pcl::fromROSMsg(ros_msg, *cloud_ptr); +``` + diff --git a/doc/howto/how_to_change_point_type_cn.md b/doc/howto/how_to_change_point_type_cn.md new file mode 100644 index 00000000..6ef3c5e9 --- /dev/null +++ b/doc/howto/how_to_change_point_type_cn.md @@ -0,0 +1,54 @@ +# 如何改变点类型的定义 + +## 1 简介 + +本文档介绍如何改变点类型的定义。 + +在项目的```CMakeLists.txt```文件中设置`POINT_TYPE`变量。修改后,需要重新编译整个工程。 + +```cmake +#======================================= +# Custom Point Type (XYZI, XYZIRT) +#======================================= +set(POINT_TYPE XYZI) +``` + +## 2 XYZI + +`POINT_TYPE`为`XYZI`时,rslidar_sdk使用PCL官方定义的点类型```pcl::PointXYZI```. + +``` +typedef pcl::PointXYZI PointXYZI; +``` + +rslidar_sdk将基于`PointXYZI`的点云,转换为ROS的PointCloud2消息,再发布出去。 + +``` + PointCloudT rs_msg; + sensor_msgs::msg::PointCloud2 ros_msg; + pcl::toROSMsg(rs_msg, ros_msg); +``` + +## 3 XYZIRT + +`POINT_TYPE`为`XYZIRT`时,rslidar_sdk使用速腾自定义的点类型,定义如下。 + +```c++ +struct PointXYZIRT +{ + PCL_ADD_POINT4D; + uint8_t intensity; + uint16_t ring = 0; + double timestamp = 0; + EIGEN_MAKE_ALIGNED_OPERATOR_NEW +} EIGEN_ALIGN16; +``` + +rslidar_sdk将基于`PointXYZIRT`的点云,转换为ROS的PointCloud2消息,再发布出去。 + +``` + PointCloudT rs_msg; + sensor_msgs::msg::PointCloud2 ros_msg; + pcl::toROSMsg(rs_msg, ros_msg); +``` + diff --git a/doc/howto/how_to_decode_pcap.md b/doc/howto/how_to_decode_pcap_file.md similarity index 100% rename from doc/howto/how_to_decode_pcap.md rename to doc/howto/how_to_decode_pcap_file.md diff --git a/doc/howto/how_to_decode_pcap_cn.md b/doc/howto/how_to_decode_pcap_file_cn.md similarity index 94% rename from doc/howto/how_to_decode_pcap_cn.md rename to doc/howto/how_to_decode_pcap_file_cn.md index 23cf195e..efe49fbe 100644 --- a/doc/howto/how_to_decode_pcap_cn.md +++ b/doc/howto/how_to_decode_pcap_file_cn.md @@ -1,8 +1,8 @@ -# 如何解码PCAP包并发送点云数据到ROS +# 如何解码PCAP文件 ## 1 简介 -本文档展示如何解码PCAP包, 并发送点云数据到ROS。 +本文档展示如何解码PCAP文件, 并发送点云数据到ROS。 在阅读本文档之前,请确保已阅读雷达用户手册和 [参数简介](../intro/parameter_intro.md) 。 diff --git a/doc/howto/how_to_record_and_offline_decode_rosbag.md b/doc/howto/how_to_record_replay_packet_rosbag.md similarity index 100% rename from doc/howto/how_to_record_and_offline_decode_rosbag.md rename to doc/howto/how_to_record_replay_packet_rosbag.md diff --git a/doc/howto/how_to_record_and_offline_decode_rosbag_cn.md b/doc/howto/how_to_record_replay_packet_rosbag_cn.md similarity index 100% rename from doc/howto/how_to_record_and_offline_decode_rosbag_cn.md rename to doc/howto/how_to_record_replay_packet_rosbag_cn.md diff --git a/doc/howto/how_to_switch_point_type.md b/doc/howto/how_to_switch_point_type.md deleted file mode 100644 index 1a33e172..00000000 --- a/doc/howto/how_to_switch_point_type.md +++ /dev/null @@ -1,61 +0,0 @@ -# How to switch point type - -## 1 Introduction - -This document illustrates how to switch the point type. - -The supported point type is listed in README. - -To switch the type, open the ```CMakeLists.txt``` in the project and change the variable POINT_TYPE. - -Remember to **rebuild** the project after changing it. - -```cmake -#======================================= -# Custom Point Type (XYZI, XYZIRT) -#======================================= -set(POINT_TYPE XYZI) -``` - -## 2 XYZI - -The default point type is the pcl official type```pcl::PointXYZI```. - -Here is an example to transform the ros point cloud to pcl point cloud. User can take this as an reference in his/her own program. - -```c++ -pcl::PointCloud::Ptr cloud_ptr (new pcl::PointCloud); -pcl::fromROSMsg(ros_msg, *cloud_ptr); -``` - - -## 3 XYZIRT - -This is a customized point type. User needs add the definition of the point in his/her own programs. - -The definition is as below. - -```c++ -#include -#include - -struct RsPointXYZIRT -{ - PCL_ADD_POINT4D; - uint8_t intensity; - uint16_t ring = 0; - double timestamp = 0; - EIGEN_MAKE_ALIGNED_OPERATOR_NEW -} EIGEN_ALIGN16; - -POINT_CLOUD_REGISTER_POINT_STRUCT(RsPointXYZIRT, (float, x, x)(float, y, y)(float, z, z)(uint8_t, intensity, intensity)(uint16_t, ring, ring)(double, timestamp, timestamp)) - -``` - -User can transform the ros point cloud to pcl point cloud. - -```c++ -pcl::PointCloud::Ptr cloud_ptr (new pcl::PointCloud); -pcl::fromROSMsg(ros_msg, *cloud_ptr); -``` - diff --git a/doc/howto/how_to_switch_point_type_cn.md b/doc/howto/how_to_switch_point_type_cn.md deleted file mode 100644 index 038b755b..00000000 --- a/doc/howto/how_to_switch_point_type_cn.md +++ /dev/null @@ -1,54 +0,0 @@ -# 如何切换点的类型 - -## 1 简介 - -本文档将会介绍如何切换点的类型。目前支持的类型在README中有列出。 - -在项目根目录下的```CMakeLists.txt```文件中设置POINT_TYPE变量。改变类型后,需要重新编译整个工程。 - -```cmake -#======================================= -# Custom Point Type (XYZI, XYZIRT) -#======================================= -set(POINT_TYPE XYZI) -``` - -## 2 XYZI - -默认的点类型是pcl的官方类型```pcl::PointXYZI```. - -此处给出了一个将ros点云消息转换成pcl点云的例子,用户在编写ros点云接收端时可以作为参考。 - -```c++ -pcl::PointCloud::Ptr cloud_ptr (new pcl::PointCloud); -pcl::fromROSMsg(ros_msg, *cloud_ptr); -``` - -## 3 XYZIRT - -由于这是速腾的自定义点类型,用户需要在接收端程序添加对应的点的定义,点的定义如下所示。 - -```c++ -#include -#include - -struct RsPointXYZIRT -{ - PCL_ADD_POINT4D; - uint8_t intensity; - uint16_t ring = 0; - double timestamp = 0; - EIGEN_MAKE_ALIGNED_OPERATOR_NEW -} EIGEN_ALIGN16; - -POINT_CLOUD_REGISTER_POINT_STRUCT(RsPointXYZIRT, (float, x, x)(float, y, y)(float, z, z)(uint8_t, intensity, intensity)(uint16_t, ring, ring)(double, timestamp, timestamp)) - -``` - -可调用pcl的转换函数将ros点云转换为pcl点云。 - -```c++ -pcl::PointCloud::Ptr cloud_ptr (new pcl::PointCloud); -pcl::fromROSMsg(ros_msg, *cloud_ptr); -``` - From e347c7fe9fd81ed2c04a6cf6089fa14925763ab4 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 16 Mar 2022 16:35:33 +0800 Subject: [PATCH 116/261] feat: update docs --- .../how_to_record_replay_packet_rosbag.md | 45 +++++++++-------- .../how_to_record_replay_packet_rosbag_cn.md | 48 +++++++++++-------- 2 files changed, 52 insertions(+), 41 deletions(-) diff --git a/doc/howto/how_to_record_replay_packet_rosbag.md b/doc/howto/how_to_record_replay_packet_rosbag.md index bdb42c3f..22482e55 100644 --- a/doc/howto/how_to_record_replay_packet_rosbag.md +++ b/doc/howto/how_to_record_replay_packet_rosbag.md @@ -1,18 +1,19 @@ -# How to record and decode rosbag +# How to record and replay Packet rosbag ## 1 Introduction -This document illustrates how to record and decode rosbag. +This document illustrates how to record and replay MSOP/DIFOP Packet rosbag. -Please make sure you have read the LiDAR user-guide and [Intro to parameters](../intro/parameter_intro.md) before reading this document. +It is possible to record the point cloud message into a rosbag and replay it, but the point cloud rosbag is very large. rslidar_sdk provides a better way - record packet rosbag and replay it. + +Please be sure you have read the LiDAR user-guide and [Online connect lidar and send point cloud through ROS](how_to_online_send_point_cloud_ros.md). ## 2 Record ### 2.1 Send packet to ROS -Suppose that you have finished to sent out the point cloud to ROS. If you have no idea about this, please read [Online connect lidar and send point cloud through ROS](how_to_online_send_point_cloud_ros.md) first. +Here suppose that you have connected to an on-line LiDAR, and have sent the point cloud to ROS. -Though we can record the point cloud message into a bag and play it, the bag will be very large. So it is recommended to record packets rather than point cloud message. ```yaml common: @@ -23,9 +24,11 @@ common: send_point_cloud_proto: false ``` -In order to record packets, set ```send_packet_ros = true```. +To record packets, set ```send_packet_ros = true```. + +### 2.2 Record the topic of packet -### 2.2 Record according to the topic +To change the topic of packet, change ```ros_send_packet_topic```. This topic sends out both MSOP and DIFOP packets. ```yaml ros: @@ -35,21 +38,19 @@ ros: ros_send_point_cloud_topic: /rslidar_points ``` -User may change the packets topic by changing the ```ros_send_packet_topic```. - -This topic represent the topic of the msop and difop. - -Below is the command to record bag. +Record rosbag as below. ```sh rosbag record /rslidar_packets -O bag ``` -## 3 Offline Decode +## 3 Replay -Suppose you have recorded a rosbag which contains msop and difop packets with the topic ```rslidar_packets```. +Suppose you have recorded a rosbag, which contains MSOP/DIFOP packets with the topic ```/rslidar_packets```. -### 3.1 Set up the common part of the config file +### 3.1 Set Packet Source + +In `config.yaml`, set the `common` part. ```yaml common: @@ -60,11 +61,13 @@ common: send_point_cloud_proto: false ``` -Since the packets come from the ROS, set ```msg_source = 2```. +Packet is from the ROS, so set ```msg_source = 2```. To send point cloud to ROS, set ```send_point_cloud_ros = true```. -### 3.2 Set up the lidar-driver part of the config file +### 3.2 Set parameters of Lidar + +In `config.yaml`, set the `lidar-driver` part. ```yaml lidar: @@ -81,7 +84,9 @@ lidar: Set the ```lidar_type``` to your LiDAR type. -### 3.3 Set the lidar-ros part of the config file +### 3.3 Set Topic of packet. + +In `config.yaml`, set the `lidar-ros` part. ```yaml ros: @@ -91,10 +96,10 @@ ros: ros_send_point_cloud_topic: /rslidar_points ``` -Set up the ```ros_recv_packet_topic``` to the msop and difop topic in the rosbag. +To receive MSOP/DIFOP packest, set ```ros_recv_packet_topic``` to the topic in the rosbag. ### 3.4 Run -Run the demo & play rosbag. +Run the demo, and replay rosbag. diff --git a/doc/howto/how_to_record_replay_packet_rosbag_cn.md b/doc/howto/how_to_record_replay_packet_rosbag_cn.md index 31d8fb83..5162dff1 100644 --- a/doc/howto/how_to_record_replay_packet_rosbag_cn.md +++ b/doc/howto/how_to_record_replay_packet_rosbag_cn.md @@ -1,18 +1,18 @@ -# 如何录制与解码rosbag +# 如何录制与回放 Packet rosbag ## 1 简介 -本文档将展示如何记录与解码rosbag。 +本文档展示如何记录与回放MSOP/DIFOP rosbag。 -在阅读这本文档之前请先阅读雷达用户手册与[参数简介](../intro/parameter_intro.md) 。 +使用ROS可以录制点云rosbag消息并回放,但点云包非常大,所以rslidar_sdk提供更好的选择,也就是录制Packet rosbag并回放。 -## 2 录包 +在阅读本文档之前, 请先阅读雷达用户手册和 [在线连接雷达并发送点云到ROS](how_to_online_send_point_cloud_ros_cn.md) 。 -### 2.1 将packet发送至ROS +## 2 录制 -这里假设,已经可以在线连接雷达并将点云发送至ROS。如果对此不太了解, 请先阅读 [在线连接雷达并发送点云到ROS](how_to_online_send_point_cloud_ros_cn.md) 。 +### 2.1 将MSOP/DIFOP Packet发送至ROS -虽然也可以直接录制点云消息,但录制点云消息的包非常大,所以通常还是建议录制雷达packet数据。 +这里假设已经连接在线雷达,并能发送点云到ROS。 ```yaml common: @@ -23,9 +23,11 @@ common: send_point_cloud_proto: false ``` -​要录制雷达packet, 设置 ```send_packet_ros = true```。 +要录制Packet, 设置 ```send_packet_ros = true```。 -### 2.2 根据对应话题录包 +### 2.2 根据话题录制rosbag + +修改```ros_send_packet_topic```, 来改变发送的话题。这个话题包括MSOP Packet和DIFOP Packet。 ```yaml ros: @@ -35,19 +37,19 @@ ros: ros_send_point_cloud_topic: /rslidar_points ``` -用户可以通过改变```ros_send_packet_topic``` 来改变发送的话题。这个话题包括MSOP和DIFOP包。 - -录包的指令如下所示。 +ROS录制rosbag的指令如下。 ```bash rosbag record /rslidar_packets -O bag ``` -## 3 离线解码 +## 3 回放 + +假设录制了一个rosbag,其中包含话题为 `/rslidar_packets` 的MSOP/DIFOP Packet。 -假设录制了一个rosbag,其中包含话题为 *rslidar_packets* 的msop和DIFOP数据包。 +### 3.1 设置Packet源 -### 3.1 设置文件的 common部分 +配置`config.yaml`的`common`部分。 ```yaml common: @@ -58,11 +60,13 @@ common: send_point_cloud_proto: false ``` -数据包消息来自ROS,因此设置 ```msg_source = 2``` 。 +MSOP/DIFOP Packet来自ROS rosbag,因此设置 ```msg_source = 2``` 。 将点云发送到ROS,因此设置 ```send_point_cloud_ros = true```。 -### 3.2 设置配置文件的lidar-driver部分 +### 3.2 设置雷达参数 + +配置`config.yaml`的`lidar-driver`部分。 ```yaml lidar: @@ -79,21 +83,23 @@ lidar: 将 ```lidar_type``` 设置为LiDAR类型 。 -### 3.3 设置配置文件的lidar-ros部分 +### 3.3 设置接收Packet的主题 + +设置`config.yaml`的`lidar-ros`部分。 ```yaml ros: - ros_frame_id: /rslidar + ros_frame_id: /rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points ``` -将 ```ros_recv_packet_topic``` 设置为rosbag中的MSOP和DIFOP数据的话题。 +将 ```ros_recv_packet_topic``` 设置为rosbag中MSOP/DIFOP Packet的话题。 ### 3.4 运行 -运行程序并播放rosbag。 +运行程序,回放rosbag。 From be944bd8237fbf567647c5acbde206cee7021201 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 16 Mar 2022 17:35:39 +0800 Subject: [PATCH 117/261] feat: update docs --- .../how_to_use_coordinate_transformation.md | 25 ++++++++----------- ...how_to_use_coordinate_transformation_cn.md | 25 ++++++++----------- 2 files changed, 21 insertions(+), 29 deletions(-) diff --git a/doc/howto/how_to_use_coordinate_transformation.md b/doc/howto/how_to_use_coordinate_transformation.md index ca00ad3b..bf34c08d 100644 --- a/doc/howto/how_to_use_coordinate_transformation.md +++ b/doc/howto/how_to_use_coordinate_transformation.md @@ -1,28 +1,27 @@ -# How to use the coordinate transformation function +# How to use coordinate transformation ## 1 Introduction -This document illustrate how to use the transformation function, and output the transformed point cloud. +rslidar_sdk can transform the coordinate of point cloud. This document illustrate how to do so. -## 2 Dependency +Please check the [Intro to hiding parameters](../intro/hiding_parameters_intro.md) for more details. Here is an example of the config.yaml. -- Eigen3 +## 2 Dependency - Installation: +rslidar_sdk depends on the libeigen library to do coordinate transformation. Please install it first. - ```bash - sudo apt-get install libeigen3-dev - ``` +```bash +sudo apt-get install libeigen3-dev +``` ## 3 Compile -To enable the transformation function, set the option ```ENABLE_TRANSFORM``` to be ```ON``` during the cmake process. +To enable transformation, set the CMake option ```ENABLE_TRANSFORM```to be ```ON```. - Compile directly ```bash cmake -DENABLE_TRANSFORM=ON .. - make -j4 ``` - ROS @@ -37,11 +36,9 @@ To enable the transformation function, set the option ```ENABLE_TRANSFORM``` to colcon build --cmake-args '-DENABLE_TRANSFORM=ON' ``` -## 4 Set up parameters +## 4 Set LiDAR parameters -User needs to set up the hiding parameter```x, y, z, roll, pitch ,yaw ``` in lidar part of the config.yaml. - -Please check the [Intro to hiding parameters](../intro/hiding_parameters_intro.md) for more details. Here is an example of the config.yaml. +In the `lidar-driver` part of `config.yaml`, set the hiding parameter`x`, `y`, `z`, `roll`, `pitch` ,`yaw`. ```yaml common: diff --git a/doc/howto/how_to_use_coordinate_transformation_cn.md b/doc/howto/how_to_use_coordinate_transformation_cn.md index 224044bc..b51c1489 100644 --- a/doc/howto/how_to_use_coordinate_transformation_cn.md +++ b/doc/howto/how_to_use_coordinate_transformation_cn.md @@ -2,29 +2,26 @@ ## 1 简介 -本文档将展示如何使用rslidar_sdk的内置坐标变换功能, 输出经过变换后的点云。 +rslidar_sdk支持对点云进行坐标变换,本文档展示如何作这种变换。 -## 2 依赖介绍 +在阅读本文档之前,请确保已阅读雷达用户手册和[隐藏参数介绍](../intro/hiding_parameters_intro.md)。 -要启用坐标变换功能,需要安装以下依赖。 +## 2 安装依赖库 -- Eigen3 +rslidar_sdk的坐标变换基于libeigen库,所以要先安装它。 - 安装方式: - - ```bash - sudo apt-get install libeigen3-dev - ``` +```bash +sudo apt-get install libeigen3-dev +``` ## 3 编译 -要启用坐标变换的功能,编译程序时需要将```ENABLE_TRANSFORM```选项设置为```ON```. +要启用坐标变换,编译rslidar_sdk时,需要将```ENABLE_TRANSFORM```选项设置为```ON```. - 直接编译 ```bash cmake -DENABLE_TRANSFORM=ON .. - make -j4 ``` - ROS @@ -39,11 +36,9 @@ colcon build --cmake-args '-DENABLE_TRANSFORM=ON' ``` -## 4 参数设置 - -用户需要设置lidar部分的隐藏参数```x, y, z, roll, pitch ,yaw ``` 。 +## 4 设置雷达参数 -更多的细节可以参考[隐藏参数介绍](../intro/hiding_parameters_intro.md)。此处为参数文件的一个示例,用户可根据实际情况配置。 +在`config.yaml`中,设置`lidar-lidar`部分的参数`x`、, `y`、 `z`、 `roll`、 `pitch` 、`yaw`。 ```yaml common: From 1ddc3b43ae9241fb40e2c9f9abde8083e58e91fd Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 16 Mar 2022 20:22:39 +0800 Subject: [PATCH 118/261] feat: update docs --- doc/howto/online_lidar_advanced_topics.md | 179 ++++++++++++++++++ doc/howto/online_lidar_advanced_topics_cn.md | 184 +++++++++++++++++++ doc/img/12_broadcast.png | Bin 0 -> 11484 bytes doc/img/12_multi_lidars_ip.png | Bin 0 -> 23224 bytes doc/img/12_multi_lidars_port.png | Bin 0 -> 23361 bytes doc/img/12_multicast.png | Bin 0 -> 12267 bytes doc/img/12_unicast.png | Bin 0 -> 10593 bytes doc/img/12_user_layer.png | Bin 0 -> 10592 bytes doc/img/12_vlan.png | Bin 0 -> 15739 bytes doc/img/12_vlan_layer.png | Bin 0 -> 8219 bytes 10 files changed, 363 insertions(+) create mode 100644 doc/howto/online_lidar_advanced_topics.md create mode 100644 doc/howto/online_lidar_advanced_topics_cn.md create mode 100644 doc/img/12_broadcast.png create mode 100644 doc/img/12_multi_lidars_ip.png create mode 100644 doc/img/12_multi_lidars_port.png create mode 100644 doc/img/12_multicast.png create mode 100644 doc/img/12_unicast.png create mode 100644 doc/img/12_user_layer.png create mode 100644 doc/img/12_vlan.png create mode 100644 doc/img/12_vlan_layer.png diff --git a/doc/howto/online_lidar_advanced_topics.md b/doc/howto/online_lidar_advanced_topics.md new file mode 100644 index 00000000..9ea6e8cc --- /dev/null +++ b/doc/howto/online_lidar_advanced_topics.md @@ -0,0 +1,179 @@ +# Online Lidar - Advanced Topics + +## 1 Introduction + +The RoboSense Lidar may work in unicast/multicast/broadcast mode, with VLAN layer and with user layers. Also rslidar_sdk supports multi-LiDARs. + +This document illustrates how to configure rslidar_sdk in each case. + +Before reading this document, please be sure that you have read: ++ LiDAR user-guide ++ [Intro to parameters](../intro/parameter_intro.md) before reading this document ++ [Decode online Lidar](./how_to_decode_online_lidar.md) + +## 2 Unicast, Multicast and Broadcast + +### 2.1 Broadcast mode + +The Lidar sends MSOP/DIFOP packets to the host machine (rslidar_sdk runs on it). For simplicity, the DIFOP port is ommited here. ++ The Lidar sends to `255.255.255.255` : `6699`, and the host binds to port `6699`. + +![](../img/12_broadcast.png) + +Below is how to configure `config.yaml`. + +```yaml +common: + msg_source: 1 + send_point_cloud_ros: true + +lidar: + - driver: + lidar_type: RS32 + msop_port: 6699 + difop_port: 7788 +``` + +### 2.2 Unicast mode + +To reduce the network load, the Lidar is suggested to work in unicast mode. ++ The Lidar sends to `192.168.1.102` : `6699`, and the host binds to port `6699`. + +![](../img/12_unicast.png) + +Below is how to configure `config.yaml`. In fact, it same with the broadcast mode. + +```yaml +lidar: + - driver: + lidar_type: RS32 + msop_port: 6699 + difop_port: 7788 +``` + +### 2.3 Multicast mode + +The Lidar may also works in multicast mode. ++ The lidar sends to `224.1.1.1`:`6699` ++ The host binds to port `6699`. And it makes local NIC (Network Interface Card) join the multicast group `224.1.1.1`. The local NIC's IP is `192.168.1.102`. + +![](../img/12_multicast.png) + +Below is how to configure `config.yaml`. + +```yaml +lidar: + - driver: + lidar_type: RS32 + msop_port: 6699 + difop_port: 7788 + group_address: 224.1.1.1 + host_address: 192.168.1.102 +``` + +## 3 Multiple Lidars + +### 3.1 Different remote ports + +If you have two or more Lidars, it is suggested to set different remote ports. ++ First Lidar sends to `192.168.1.102`:`6699`, and the first driver instance binds to `6699`. ++ Second Lidar sends to `192.168.1.102`:`5599`, and the second driver instance binds to `5599`. + +![](../img/12_multi_lidars_port.png) + +Below is how to configure `config.yaml`. + +```yaml +lidar: + - driver: + lidar_type: RS32 + msop_port: 6699 + difop_port: 7788 + - driver: + lidar_type: RS32 + msop_port: 5599 + difop_port: 6688 +``` + +### 3.2 Different remote IPs + +An alternate way is to set different remote IPs. ++ The host has two NICs: `192.168.1.102` and `192.168.1.103`. ++ First Lidar sends to `192.168.1.102`:`6699`, and the first driver instance binds to `192.168.1.102:6699`. ++ Second Lidar sends to `192.168.1.103`:`6699`, and the second driver instance binds to `192.168.1.103:6699`. + +![](../img/12_multi_lidars_ip.png) + +Below is how to configure `config.yaml`. + +```yaml +lidar: + - driver: + lidar_type: RS32 + msop_port: 6699 + difop_port: 7788 + host_address: 192.168.1.102 + - driver: + lidar_type: RS32 + msop_port: 6699 + difop_port: 7788 + host_address: 192.168.1.103 +``` + +## 4 VLAN + +In some user cases, The Lidar may work on VLAN. Its packets have a VLAN layer. + +![](../img/12_vlan_layer.png) + +The driver cannot parse this packet. Instead, it depends on a virtual NIC to strip the VLAN layer. + +Below is an example. ++ The Lidar works on VLAN `80`. It sends packets to `192.168.1.102` : `6699`. The packet has a VLAN layer. ++ Suppose there is a physical NIC `eno1` on the host. It receives packets with VLAN layer. + +![](../img/12_vlan.png) + +To strip the VLAN layer, create a virtual NIC `eno1.80` on `eno1`, and assign IP `192.168.1.102` to it. + +``` +sudo apt-get install vlan -y +sudo modprobe 8021q + +sudo vconfig add eno1 80 +sudo ifconfig eno1.80 192.168.1.102 up +``` + +Now the driver may take `eno1.80` as a general NIC, and receives packets without VLAN layer. + +```yaml +lidar: + - driver: + lidar_type: RS32 + msop_port: 6699 + difop_port: 7788 +``` + +## 5 User Layer, Tail Layer + +In some user cases, User may add extra layers before or after the MSOP/DIFOP packet. ++ USER_LAYER is before the packet and TAIL_LAYER is after it. + +![](../img/12_user_layer.png) + +These extra layers are parts of UDP data. The driver can strip them. + +To strip them, just give their lengths in bytes. + +In the following example, USER_LAYER is 8 bytes, and TAIL_LAYER is 4 bytes. + +```yaml +lidar: + - driver: + lidar_type: RS32 + msop_port: 6699 + difop_port: 7788 + user_layer_bytes: 8 + tail_layer_bytes: 4 +``` + diff --git a/doc/howto/online_lidar_advanced_topics_cn.md b/doc/howto/online_lidar_advanced_topics_cn.md new file mode 100644 index 00000000..0197c641 --- /dev/null +++ b/doc/howto/online_lidar_advanced_topics_cn.md @@ -0,0 +1,184 @@ +# 在线雷达 - 高级主题 + +## 1 简介 + ++ RoboSense雷达可以工作在单播/组播/广播模式。 + ++ 可以运行在VLAN协议上。 + ++ 某些场景下,用户可以向Packet加入自己的层。 + ++ rslidar_sdk支持多个雷达。 + +本文描述在以上的场景下,如何配置rslidar_sdk。 + +在阅读本文档之前, 请确保已经阅读过: ++ 雷达用户手册 ++ [参数介绍](../intro/parameter_intro_cn.md) before reading this document ++ [连接在线雷达](./how_to_decode_online_lidar_cn.md) + +## 2 单播、组播、广播 + +### 2.1 广播 + +雷达发送 MSOP/DIFOP Packet到电脑主机。为简单起见,如下的图没有显示DIFOP端口。 ++ 雷达发送Packet到 `255.255.255.255` : `6699`, rslidar_sdk绑定到主机的端口 `6699`. + +![](../img/12_broadcast.png) + +如下是配置`config.yaml`的方式。 + +```yaml +common: + msg_source: 1 + send_point_cloud_ros: true + +lidar: + - driver: + lidar_type: RS32 + msop_port: 6699 + difop_port: 7788 +``` + +### 2.2 单播 + +为了减少网络负载,建议雷达使用单播模式。 ++ 雷达发送Packet到 `192.168.1.102` : `6699`, rslidar_sdk绑定端口 `6699`。 + +![](../img/12_unicast.png) + +如下是配置`config.yaml`的方式。这实际上与广播的方式一样。 + +```yaml +lidar: + - driver: + lidar_type: RS32 + msop_port: 6699 + difop_port: 7788 +``` + +### 2.3 组播 + +雷达也可以工作在组播模式。 ++ 雷达发送Packet到 `224.1.1.1`:`6699` ++ rslidar_sdk绑定到端口 `6699`。同时它将IP地址为`192.168.1.102`的本地网络接口加入组播组`224.1.1.1`。 + +![](../img/12_multicast.png) + +如下是配置`config.yaml`的方式。 + +```yaml +lidar: + - driver: + lidar_type: RS32 + msop_port: 6699 + difop_port: 7788 + group_address: 224.1.1.1 + host_address: 192.168.1.102 +``` + +## 3 多个雷达的情况 + +### 3.1 不同的目标端口 + +如果有两个或多个雷达,首选的配置是让它们有不同的目标端口。 ++ 第一个雷达发送Packet到 `192.168.1.102`:`6699`, 给rslidar_sdk配置的第一个driver节点绑定到`6699`。 ++ 第二个雷达发送Packet到 `192.168.1.102`:`5599`, 给rslidar_sdk配置的第二个driver节点绑定到`5599`。 + +![](../img/12_multi_lidars_port.png) + +如下是配置`config.yaml`的方式。 + +```yaml +lidar: + - driver: + lidar_type: RS32 + msop_port: 6699 + difop_port: 7788 + - driver: + lidar_type: RS32 + msop_port: 5599 + difop_port: 6688 +``` + +### 3.2 不同的目标IP + +也可以让多个雷达使用不同的目标IP。 ++ 主机有两个网卡, IP地址分别为`192.168.1.102` 和 `192.168.1.103`。 ++ 第一个雷达发送Packet到 `192.168.1.102`:`6699`, 给rslidar_sdk配置的第一个driver节点绑定到`192.168.1.102:6699`。 ++ 第二个雷达发送Packet到 `192.168.1.103`:`6699`, 给rslidar_sdk配置的第二个driver节点绑定到`192.168.1.103:6699`。 + +![](../img/12_multi_lidars_ip.png) + +如下是配置`config.yaml`的方式。 + +```yaml +lidar: + - driver: + lidar_type: RS32 + msop_port: 6699 + difop_port: 7788 + host_address: 192.168.1.102 + - driver: + lidar_type: RS32 + msop_port: 6699 + difop_port: 7788 + host_address: 192.168.1.103 +``` + +## 4 VLAN + +在某些场景下,雷达工作在VLAN层之上。MSOP/DIFOP Packet有VLAN层,如下图。 + +![](../img/12_vlan_layer.png) + +rslidar_sdk不能解析VLAN层。 + +需要一个虚拟网卡来剥除掉这一层。举例如下。 + ++ 雷达工作在VLAN id为`80`的VLAN层上。它发送Packet到`192.168.1.102` : `6699`,Packet有VLAN层。 ++ 假设主机上有一个支持VLAN的物理网卡`eno1`. 它接收带VLAN层的Packet。 + +![](../img/12_vlan.png) + +要剥离VLAN层,需要基于`eno1`,创建一个虚拟网卡`eno1.80`, 并且将它的IP设置为`192.168.1.102`。 + +```shell +sudo apt-get install vlan -y +sudo modprobe 8021q + +sudo vconfig add eno1 80 +sudo ifconfig eno1.80 192.168.1.102 up +``` + +现在,rslidar_sdk可以将`eno1.80`当做一个一般的网卡来处理,从这里接收不带VLAN层的Packet. + +```yaml +lidar: + - driver: + lidar_type: RS32 + msop_port: 6699 + difop_port: 7788 +``` + +## 5 User Layer, Tail Layer + +在某些场景下,用户可能在MSOP/DIFOP数据前后加入自己的层。 ++ 在前面的是USER_LAYER,在后面的是TAIL_LAYER。 + +![](../img/12_user_layer.png) + +这两个层是UDP数据的一部分,所以rslidar_sdk可以自己剥除它们。只需要指出这两个层的长度就可以了。 + +在下面的例子中,USER_LAYER是8字节,TAIL_LAYER是4字节。 + +```yaml +lidar: + - driver: + lidar_type: RS32 + msop_port: 6699 + difop_port: 7788 + user_layer_bytes: 8 + tail_layer_bytes: 4 +``` + diff --git a/doc/img/12_broadcast.png b/doc/img/12_broadcast.png new file mode 100644 index 0000000000000000000000000000000000000000..ebf2f4cb6d825136c5801fd2519285afd9b60649 GIT binary patch literal 11484 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 J1Ik#2{}1)=n~eYf literal 0 HcmV?d00001 diff --git a/doc/img/12_multi_lidars_ip.png b/doc/img/12_multi_lidars_ip.png new file mode 100644 index 0000000000000000000000000000000000000000..48e1e13829ee74fc173d0e735a6cb53986b10588 GIT binary patch literal 23224 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%0AW|8g3xTc@P9Ytv^9MMb5A@K= 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 SjX4t=>$Rfliwdw=(Ek9jq9D}( literal 0 HcmV?d00001 diff --git a/doc/img/12_multicast.png b/doc/img/12_multicast.png new file mode 100644 index 0000000000000000000000000000000000000000..fc39a8dcd41cef575b5da6cc794517ec971629e0 GIT binary patch literal 12267 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 BYcK!+ literal 0 HcmV?d00001 diff --git a/doc/img/12_unicast.png b/doc/img/12_unicast.png new file mode 100644 index 0000000000000000000000000000000000000000..65964a26ae9c2d8bd9bfd8df744634a340cd38a6 GIT binary patch literal 10593 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 literal 0 HcmV?d00001 diff --git a/doc/img/12_user_layer.png b/doc/img/12_user_layer.png new file mode 100644 index 0000000000000000000000000000000000000000..d7b31a08e165d44a9903211197f3b126ff2fc75f GIT binary patch literal 10592 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 literal 0 HcmV?d00001 diff --git a/doc/img/12_vlan.png b/doc/img/12_vlan.png new file mode 100644 index 0000000000000000000000000000000000000000..55f224b41673d34e38d64fb2e73f426f54c2d214 GIT binary patch literal 15739 zcmcJ$1yEdFyCn=EAqk!!K?8&U!QCx50UDR!5P~%B?i#EK!5eo;aCg@Z?lkVuxO-3Y z-kR^;`_DI1^-tAM)o}XM=A5(l*?T=}J$pT2N($1LXvAnpNJyApWF%COke(SJjsstz zB7Rpb_!uJoytb3kazsMH>VEnl$1`A&AR$p8eUT7Vb4xu~bWg?WS-d_`BzN5Ru44SN zFyr9<`8eDVN!gec{P}J3muwN-=uczUN!>evVZ;EzG2LE4cTV~rIBIT_g>1bj&qagW zkSiSyyhnzI#}+T{j9n7u<`$Fn{Efzr?k>PHoob3#YBNqluEoW_IrHMgUQq_&h~)

jI^bS%wSY6 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 literal 0 HcmV?d00001 From da9ca91da1c136db7a237fb589cbe1f65152e7b4 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 17 Mar 2022 09:34:28 +0800 Subject: [PATCH 119/261] feat: update docs --- doc/howto/how_to_use_multi_cast_function.md | 55 ----- .../how_to_use_multi_cast_function_cn.md | 51 ---- doc/howto/how_to_use_multi_lidars.md | 220 ------------------ doc/howto/how_to_use_multi_lidars_cn.md | 217 ----------------- doc/howto/online_lidar_advanced_topics.md | 12 +- doc/howto/online_lidar_advanced_topics_cn.md | 5 + 6 files changed, 16 insertions(+), 544 deletions(-) delete mode 100644 doc/howto/how_to_use_multi_cast_function.md delete mode 100644 doc/howto/how_to_use_multi_cast_function_cn.md delete mode 100644 doc/howto/how_to_use_multi_lidars.md delete mode 100644 doc/howto/how_to_use_multi_lidars_cn.md diff --git a/doc/howto/how_to_use_multi_cast_function.md b/doc/howto/how_to_use_multi_cast_function.md deleted file mode 100644 index 7a24becb..00000000 --- a/doc/howto/how_to_use_multi_cast_function.md +++ /dev/null @@ -1,55 +0,0 @@ -# How to use multi-cast function - -## 1 Introduction - -This document illustrates how to use rslidar_sdk to receive Lidar packets in multi-cast mode. - -This document is only the Linux platform. - -## 2 Steps - -Suppose the multicast group address of LiDAR is ```224.1.1.1```. and the host address is ```192.168.1.102```. - -The host address should be in the same network with the Lidar. In other words, the host can ping to the Lidar. - -### 2.1 Set up hiding parameters - -User need to set up the hiding parameter ```group_address``` in lidar part of the config.yaml. Please check the [Intro to hiding parameters](../intro/hiding_parameters_intro.md) for more details. - -Here is an example of the config.yaml. - -```yaml -common: - msg_source: 1 - send_packet_ros: false - send_point_cloud_ros: true - send_packet_proto: false - send_point_cloud_proto: false -lidar: - - driver: - lidar_type: RS128 - group_address: 224.1.1.1 - host_address: 192.168.1.102 - msop_port: 6699 - difop_port: 7788 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false -``` - -### 2.4 Run - -Run the program. - - - - - - - - - - - diff --git a/doc/howto/how_to_use_multi_cast_function_cn.md b/doc/howto/how_to_use_multi_cast_function_cn.md deleted file mode 100644 index 26267e2e..00000000 --- a/doc/howto/how_to_use_multi_cast_function_cn.md +++ /dev/null @@ -1,51 +0,0 @@ -# 如何使用组播功能 - -## 1 简介 - -本文档将演示如何使用rslidar_sdk来接收组播模式下的雷达点云。 - -## 2 步骤 - -假设雷达的组播地址设置为```224.1.1.1```, 主机地址为```192.168.1.102```。主机地址应该与雷达地址在同一网段,也就是说,主机能ping通雷达。 - -### 2.1 设置隐藏参数 - -将lidar部分的隐藏参数```multi_cast_address```设置为雷达的组播地址, 更多的细节可以参考[隐藏参数介绍](../intro/hiding_parameters_intro.md)。 - -如下是参数文件的一个示例,用户可根据实际情况配置。 - -```yaml -common: - msg_source: 1 - send_packet_ros: false - send_point_cloud_ros: true - send_packet_proto: false - send_point_cloud_proto: false -lidar: - - driver: - lidar_type: RS128 - group_address: 224.1.1.1 - host_address: 192.168.1.102 - msop_port: 6699 - difop_port: 7788 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false -``` - -### 2.4 运行 - -运行程序。 - - - - - - - - - - - diff --git a/doc/howto/how_to_use_multi_lidars.md b/doc/howto/how_to_use_multi_lidars.md deleted file mode 100644 index 7e3e5619..00000000 --- a/doc/howto/how_to_use_multi_lidars.md +++ /dev/null @@ -1,220 +0,0 @@ -# How to use multi-LiDARs - -## 1 Introduction - -This document illustrates how to send out multi-LiDARs point cloud with only one driver instance. - -Theoretically, one instance can decode unlimited number of LiDARs at the same time. Here we use three LiDARs. - -Please make sure you have read the LiDAR user-guide and [Intro to parameters](../intro/parameter_intro.md) before reading this document. - -## 2 Online connect with multi-LiDARs - -### 2.1 Get the data port number - -Please follow the instructions in LiDAR user-guide, to connect to the LiDAR and set up your computer's ip address. - -At this time, you should have already known msop and difop port numbers of each LiDAR. If you have no idea about this, please check the LiDAR user-guide. - -### 2.2 Set up the common part of the config file - -```yaml -common: - msg_source: 1 - send_packet_ros: false - send_point_cloud_ros: true - send_packet_proto: false - send_point_cloud_proto: false -``` - -Since the message come from the LiDAR, set ```msg_source = 1```. - -Send point cloud to ROS, so set ```send_point_cloud_ros = true```. - -### 2.3 Set up the lidar part of the config file - -```yaml -lidar: - - driver: - lidar_type: RS128 - msop_port: 6699 - difop_port: 7788 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false - ros: - ros_frame_id: /rslidar - ros_recv_packet_topic: /middle/rslidar_packets - ros_send_packet_topic: /middle/rslidar_packets - ros_send_point_cloud_topic: /middle/rslidar_points - proto: - point_cloud_recv_port: 60021 - point_cloud_send_port: 60021 - msop_recv_port: 60022 - msop_send_port: 60022 - difop_recv_port: 60023 - difop_send_port: 60023 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 - - driver: - lidar_type: RSBP - msop_port: 1990 - difop_port: 1991 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false - ros: - ros_frame_id: /rslidar - ros_recv_packet_topic: /left/rslidar_packets - ros_send_packet_topic: /left/rslidar_packets - ros_send_point_cloud_topic: /left/rslidar_points - proto: - point_cloud_recv_port: 60024 - point_cloud_send_port: 60024 - msop_recv_port: 60025 - msop_send_port: 60025 - difop_recv_port: 60026 - difop_send_port: 60026 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 - - driver: - lidar_type: RSBP - msop_port: 2010 - difop_port: 2011 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false - ros: - ros_frame_id: /rslidar - ros_recv_packet_topic: /right/rslidar_packets - ros_send_packet_topic: /right/rslidar_packets - ros_send_point_cloud_topic: /right/rslidar_points - proto: - point_cloud_recv_port: 60027 - point_cloud_send_port: 60027 - msop_recv_port: 60028 - msop_send_port: 60028 - difop_recv_port: 60029 - difop_send_port: 60029 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 -``` - -Set ```lidar_type``` for each LiDAR. - -Set ```msop_port``` and ```difop_port``` for each LiDAR. - -Set ```ros_send_point_cloud_topic``` for each LiDAR. - -### 2.4 Run - -Run the demo. - -## 3 Offline use rosbag with multi-LiDARs - -### 3.1 Set up the common part of the config file - -```yaml -common: - msg_source: 2 - send_packet_ros: false - send_point_cloud_ros: true - send_packet_proto: false - send_point_cloud_proto: false -``` - -Since the packet messages come from the ROS, set ```msg_source = 2```. - -Send point cloud to ROS, so set ```send_point_cloud_ros = true```. - -### 3.2 Set up the lidar part of the config file - -```yaml -lidar: - - driver: - lidar_type: RS128 - msop_port: 6699 - difop_port: 7788 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false - ros: - ros_frame_id: /rslidar - ros_recv_packet_topic: /middle/rslidar_packets - ros_send_packet_topic: /middle/rslidar_packets - ros_send_point_cloud_topic: /middle/rslidar_points - proto: - point_cloud_recv_port: 60021 - point_cloud_send_port: 60021 - msop_recv_port: 60022 - msop_send_port: 60022 - difop_recv_port: 60023 - difop_send_port: 60023 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 - - driver: - lidar_type: RSBP - msop_port: 1990 - difop_port: 1991 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false - ros: - ros_frame_id: /rslidar - ros_recv_packet_topic: /left/rslidar_packets - ros_send_packet_topic: /left/rslidar_packets - ros_send_point_cloud_topic: /left/rslidar_points - proto: - point_cloud_recv_port: 60024 - point_cloud_send_port: 60024 - msop_recv_port: 60025 - msop_send_port: 60025 - difop_recv_port: 60026 - difop_send_port: 60026 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 - - driver: - lidar_type: RSBP - msop_port: 2010 - difop_port: 2011 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false - ros: - ros_frame_id: /rslidar - ros_recv_packet_topic: /right/rslidar_packets - ros_send_packet_topic: /right/rslidar_packets - ros_send_point_cloud_topic: /right/rslidar_points - proto: - point_cloud_recv_port: 60027 - point_cloud_send_port: 60027 - msop_recv_port: 60028 - msop_send_port: 60028 - difop_recv_port: 60029 - difop_send_port: 60029 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 -``` - -Set ```lidar_type``` for each LiDAR. - -Set the ```ros_recv_packet_topic``` for each LiDAR. It is from the rosbag. - -Set ```ros_send_point_cloud_topic``` for each LiDAR. - -### 3.3 Run - -Run the program and play rosbag. - diff --git a/doc/howto/how_to_use_multi_lidars_cn.md b/doc/howto/how_to_use_multi_lidars_cn.md deleted file mode 100644 index f6de9265..00000000 --- a/doc/howto/how_to_use_multi_lidars_cn.md +++ /dev/null @@ -1,217 +0,0 @@ -# 如何使用多雷达 - -## 1 简介 - -本文档将展示,在一个驱动程序实例中,解析并发送多台雷达的点云。这里使用三个雷达作为示例。 - -在阅读本文档之前, 请确保已经阅读过雷达用户手册和[参数简介](../intro/parameter_intro.md) 。 - -## 2 在线解析多雷达 - -### 2.1 获取数据端口号 - -将三个雷达与主机正确连接。 - -此时应改已经知道每个LiDAR的msop端口号与difop端口号。 如果不知道,请查看雷达用户手册。 - -### 2.2 设置参数文件的common部分 - -```yaml -common: - msg_source: 1 - send_packet_ros: false - send_point_cloud_ros: true - send_packet_proto: false - send_point_cloud_proto: false -``` - -消息来源于在线雷达,因此请设置```msg_source=1```。 - -将点云发送到ROS,因此设置 ```send_point_cloud_ros = true``` 。 - -### 2.3 设置配置文件中的lidar部分 - -```yaml -lidar: - - driver: - lidar_type: RS128 - msop_port: 6699 - difop_port: 7788 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false - ros: - ros_frame_id: /rslidar - ros_recv_packet_topic: /middle/rslidar_packets - ros_send_packet_topic: /middle/rslidar_packets - ros_send_point_cloud_topic: /middle/rslidar_points - proto: - point_cloud_recv_port: 60021 - point_cloud_send_port: 60021 - msop_recv_port: 60022 - msop_send_port: 60022 - difop_recv_port: 60023 - difop_send_port: 60023 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 - - driver: - lidar_type: RSBP - msop_port: 1990 - difop_port: 1991 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false - ros: - ros_frame_id: /rslidar - ros_recv_packet_topic: /left/rslidar_packets - ros_send_packet_topic: /left/rslidar_packets - ros_send_point_cloud_topic: /left/rslidar_points - proto: - point_cloud_recv_port: 60024 - point_cloud_send_port: 60024 - msop_recv_port: 60025 - msop_send_port: 60025 - difop_recv_port: 60026 - difop_send_port: 60026 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 - - driver: - lidar_type: RSBP - msop_port: 2010 - difop_port: 2011 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false - ros: - ros_frame_id: /rslidar - ros_recv_packet_topic: /right/rslidar_packets - ros_send_packet_topic: /right/rslidar_packets - ros_send_point_cloud_topic: /right/rslidar_points - proto: - point_cloud_recv_port: 60027 - point_cloud_send_port: 60027 - msop_recv_port: 60028 - msop_send_port: 60028 - difop_recv_port: 60029 - difop_send_port: 60029 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 -``` - -为每个雷达设置雷达类型```lidar_type```。 - -为每个雷达设置端口号 ```msop_port``` 和```difop_port``` 。 - -为每个雷达设置发送点云的话题```ros_send_point_cloud_topic```。 - -### 2.4 运行 - -运行程序。 - -## 3 离线解析多雷达rosbag - -### 3.1 设置配置文件中的common部分 - -```yaml -common: - msg_source: 2 - send_packet_ros: false - send_point_cloud_ros: true - send_packet_proto: false - send_point_cloud_proto: false -``` - -数据包消息来自ROS,因此设置 ```msg_source = 2``` 。 - -将点云发送到ROS,因此设置 ```send_point_cloud_ros = true```。 - -### 3.2 设置配置文件中的lidar部分 - -```yaml -lidar: - - driver: - lidar_type: RS128 - msop_port: 6699 - difop_port: 7788 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false - ros: - ros_frame_id: /rslidar - ros_recv_packet_topic: /middle/rslidar_packets - ros_send_packet_topic: /middle/rslidar_packets - ros_send_point_cloud_topic: /middle/rslidar_points - proto: - point_cloud_recv_port: 60021 - point_cloud_send_port: 60021 - msop_recv_port: 60022 - msop_send_port: 60022 - difop_recv_port: 60023 - difop_send_port: 60023 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 - - driver: - lidar_type: RSBP - msop_port: 1990 - difop_port: 1991 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false - ros: - ros_frame_id: /rslidar - ros_recv_packet_topic: /left/rslidar_packets - ros_send_packet_topic: /left/rslidar_packets - ros_send_point_cloud_topic: /left/rslidar_points - proto: - point_cloud_recv_port: 60024 - point_cloud_send_port: 60024 - msop_recv_port: 60025 - msop_send_port: 60025 - difop_recv_port: 60026 - difop_send_port: 60026 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 - - driver: - lidar_type: RSBP - msop_port: 2010 - difop_port: 2011 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false - ros: - ros_frame_id: /rslidar - ros_recv_packet_topic: /right/rslidar_packets - ros_send_packet_topic: /right/rslidar_packets - ros_send_point_cloud_topic: /right/rslidar_points - proto: - point_cloud_recv_port: 60027 - point_cloud_send_port: 60027 - msop_recv_port: 60028 - msop_send_port: 60028 - difop_recv_port: 60029 - difop_send_port: 60029 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 -``` - -为每个雷达设置雷达类型```lidar_type```。 - -为每个雷达设置接收的packet话题```ros_recv_packet_topic```。 - -为每个雷达设置发送点云的话题```ros_send_point_cloud_topic```。 - -### 3.3 运行 - -运行程序并播放rosbag。 diff --git a/doc/howto/online_lidar_advanced_topics.md b/doc/howto/online_lidar_advanced_topics.md index 9ea6e8cc..ae4fcaad 100644 --- a/doc/howto/online_lidar_advanced_topics.md +++ b/doc/howto/online_lidar_advanced_topics.md @@ -2,7 +2,12 @@ ## 1 Introduction -The RoboSense Lidar may work in unicast/multicast/broadcast mode, with VLAN layer and with user layers. Also rslidar_sdk supports multi-LiDARs. +The RoboSense Lidar may work + ++ in unicast/multicast/broadcast mode, ++ with VLAN layer ++ with user layers. ++ Also rslidar_sdk supports multi-LiDARs. This document illustrates how to configure rslidar_sdk in each case. @@ -32,8 +37,13 @@ lidar: lidar_type: RS32 msop_port: 6699 difop_port: 7788 + ros: + ros_frame_id: /rslidar + ros_send_point_cloud_topic: /rslidar_points ``` +The `common` part and the `lidar-ros` part is listed here. They will be ommited in the following examples, since they are not changed. + ### 2.2 Unicast mode To reduce the network load, the Lidar is suggested to work in unicast mode. diff --git a/doc/howto/online_lidar_advanced_topics_cn.md b/doc/howto/online_lidar_advanced_topics_cn.md index 0197c641..a94717aa 100644 --- a/doc/howto/online_lidar_advanced_topics_cn.md +++ b/doc/howto/online_lidar_advanced_topics_cn.md @@ -38,8 +38,13 @@ lidar: lidar_type: RS32 msop_port: 6699 difop_port: 7788 + ros: + ros_frame_id: /rslidar + ros_send_point_cloud_topic: /rslidar_points ``` +这里列出了`common`部分和`lidar-ros`部分的设置。这两部分设置将在本文中后面的例子沿用,不再列出。 + ### 2.2 单播 为了减少网络负载,建议雷达使用单播模式。 From a373e157fd41fe75dab70e995e409b748cdfe696 Mon Sep 17 00:00:00 2001 From: Tim Clephas Date: Fri, 18 Mar 2022 12:26:52 +0100 Subject: [PATCH 120/261] No need to set COMPILE_METHOD --- CMakeLists.txt | 47 ++++++++++++++++++++--------------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 70a537b6..30d013df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,11 +2,6 @@ cmake_minimum_required(VERSION 3.5) cmake_policy(SET CMP0048 NEW) project(rslidar_sdk) -#======================================= -# Compile setup (ORIGINAL, CATKIN, COLCON) -#======================================= -set(COMPILE_METHOD CATKIN) - #======================================= # Custom Point Type (XYZI, XYZIRT) #======================================= @@ -45,7 +40,7 @@ endif(roscpp_FOUND) #ROS2# find_package(rclcpp QUIET) -if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") +if(rclcpp_FOUND) message(=============================================================) message("-- ROS2 Found, Ros2 Support is turned On!") message(=============================================================) @@ -59,11 +54,11 @@ if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") find_package(pcl_conversions REQUIRED) include_directories(${rclcpp_INCLUDE_DIRS}) -else(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") +else(rclcpp_FOUND) message(=============================================================) message("-- ROS2 Not Found, Ros2 Support is turned Off!") message(=============================================================) -endif(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") +endif(rclcpp_FOUND) #Protobuf# find_package(Protobuf QUIET) @@ -98,7 +93,7 @@ link_directories(${PCL_LIBRARY_DIRS}) add_definitions(${PCL_DEFINITIONS}) #Catkin# -if(${COMPILE_METHOD} STREQUAL "CATKIN") +if(roscpp_FOUND) add_definitions(-DRUN_IN_ROS_WORKSPACE) find_package(catkin REQUIRED COMPONENTS @@ -116,7 +111,7 @@ if(${COMPILE_METHOD} STREQUAL "CATKIN") roslib pcl_conversions ) -endif(${COMPILE_METHOD} STREQUAL "CATKIN") +endif(roscpp_FOUND) #Include directory# include_directories(${PROJECT_SOURCE_DIR}/src) @@ -171,25 +166,23 @@ endif(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) #Ros# if(roscpp_FOUND) target_link_libraries(rslidar_sdk_node ${ROS_LIBS}) - if(${COMPILE_METHOD} STREQUAL "CATKIN") - install(TARGETS rslidar_sdk_node - RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} - LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} - ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}) - install(DIRECTORY launch/ - DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch - PATTERN ".svn" EXCLUDE) - install(DIRECTORY config/ - DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/config - PATTERN ".svn" EXCLUDE) - install(DIRECTORY rviz/ - DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/rviz - PATTERN ".svn" EXCLUDE) - endif() + install(TARGETS rslidar_sdk_node + RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}) + install(DIRECTORY launch/ + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch + PATTERN ".svn" EXCLUDE) + install(DIRECTORY config/ + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/config + PATTERN ".svn" EXCLUDE) + install(DIRECTORY rviz/ + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/rviz + PATTERN ".svn" EXCLUDE) endif(roscpp_FOUND) #Ros2# -if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") +if(rclcpp_FOUND) ament_target_dependencies(rslidar_sdk_node rclcpp sensor_msgs std_msgs rslidar_msg) install(TARGETS rslidar_sdk_node @@ -201,4 +194,4 @@ if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") DESTINATION share/${PROJECT_NAME} ) ament_package() -endif(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") +endif(rclcpp_FOUND) From e4e509598015a57f776b024472be7df2909c8a8a Mon Sep 17 00:00:00 2001 From: Tim Clephas Date: Fri, 18 Mar 2022 12:33:24 +0100 Subject: [PATCH 121/261] Update steps in README --- README.md | 15 ++------------- README_CN.md | 15 ++------------- 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index bede7d20..01241cb7 100644 --- a/README.md +++ b/README.md @@ -130,9 +130,7 @@ cmake .. && make -j4 ### 4.2 Compile with ROS catkin tools -(1) Open the *CMakeLists.txt* in the project,modify the line on top of the file **set(COMPILE_METHOD ORIGINAL)** to **set(COMPILE_METHOD CATKIN)**. - -(2) Go back to the root of workspace, run the following commands to compile and run. (if using zsh, replace the 2nd command with *source devel/setup.zsh*). +(1) Run the following commands to compile and run. (if using zsh, replace the 2nd command with *source devel/setup.zsh*). ```sh catkin_make @@ -142,16 +140,7 @@ roslaunch rslidar_sdk start.launch ### 4.3 Compile with ROS2-colcon -(1) Open the *CMakeLists.txt* in the project,modify the line on top of the file **set(COMPILE_METHOD ORIGINAL)** to **set(COMPILE_METHOD COLCON)**. - -```cmake -#======================================= -# Compile setup (ORIGINAL,CATKIN,COLCON) -#======================================= -set(COMPILE_METHOD COLCON) -``` - -(3) Go back to the root of workspace, run the following commands to compile and run. (if using zsh, replace the 2nd command with *source install/setup.zsh*). +(1) Run the following commands to compile and run. (if using zsh, replace the 2nd command with *source install/setup.zsh*). ```sh colcon build diff --git a/README_CN.md b/README_CN.md index a6152242..6783c83a 100644 --- a/README_CN.md +++ b/README_CN.md @@ -127,9 +127,7 @@ cmake .. && make -j4 ### 4.2 依赖于ROS-catkin编译 -(1) 打开工程内的*CMakeLists.txt*文件,将文件顶部的**set(COMPILE_METHOD ORIGINAL)**改为**set(COMPILE_METHOD CATKIN)**。 - -(2) 返回工作空间目录,执行以下命令即可编译&运行(若使用.zsh,将第二句指令替换为 *source devel/setup.zsh*)。 +(1) 返回工作空间目录,执行以下命令即可编译&运行(若使用.zsh,将第二句指令替换为 *source devel/setup.zsh*)。 ```sh catkin_make @@ -139,16 +137,7 @@ roslaunch rslidar_sdk start.launch ### 4.3 依赖于ROS2-colcon编译 -(1) 打开工程内的*CMakeLists.txt*文件,将文件顶部的**set(COMPILE_METHOD ORIGINAL)**改为**set(COMPILE_METHOD COLCON)**。 - -```cmake -#======================================= -# Compile setup (ORIGINAL,CATKIN,COLCON) -#======================================= -set(COMPILE_METHOD COLCON) -``` - -(3) 返回工作空间目录,执行以下命令即可编译&运行(若使用.zsh,将第二句指令替换为 *source install/setup.zsh*)。 +(1) 返回工作空间目录,执行以下命令即可编译&运行(若使用.zsh,将第二句指令替换为 *source install/setup.zsh*)。 ```sh colcon build From 83ca5b235907c3b95b269e5d883e0f8faa5335e3 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 18 Mar 2022 20:25:47 +0800 Subject: [PATCH 122/261] format: format --- CMakeLists.txt | 62 ++++++++++++++++++---------- node/rslidar_sdk_node.cpp | 11 ++--- src/source/source_packet_ros.hpp | 2 +- src/source/source_pointcloud_ros.hpp | 1 - 4 files changed, 45 insertions(+), 31 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index da23680f..2dfa7f70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,7 @@ set(POINT_TYPE XYZI) # Project details / setup #======================== set(PROJECT_NAME rslidar_sdk) + add_definitions(-DPROJECT_PATH="${PROJECT_SOURCE_DIR}") set(CMAKE_BUILD_TYPE RELEASE) @@ -31,11 +32,12 @@ add_compile_options(-Wall) #======================== #ROS# find_package(roscpp 1.12 QUIET) - if(roscpp_FOUND) + message(=============================================================) - message("-- ROS Found, Ros Support is turned On!") + message("-- ROS Found. ROS Support is turned On!") message(=============================================================) + add_definitions(-DROS_FOUND) find_package(roslib QUIET) @@ -50,11 +52,12 @@ endif(roscpp_FOUND) #ROS2# find_package(rclcpp QUIET) - if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") + message(=============================================================) - message("-- ROS2 Found, Ros2 Support is turned On!") + message("-- ROS2 Found. ROS2 Support is turned On!") message(=============================================================) + add_definitions(-DROS2_FOUND) include_directories(${rclcpp_INCLUDE_DIRS}) set(CMAKE_CXX_STANDARD 14) @@ -66,18 +69,20 @@ if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") else(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") message(=============================================================) - message("-- ROS2 Not Found, Ros2 Support is turned Off!") + message("-- ROS2 Not Found. Ros2 Support is turned Off!") message(=============================================================) + endif(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") #Protobuf# find_package(Protobuf QUIET) - find_program(PROTOC protoc) if(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) + message(=============================================================) - message("-- Protobuf Found, Protobuf Support is turned On!") + message("-- Protobuf Found. Protobuf Support is turned On!") message(=============================================================) + add_definitions(-DPROTO_FOUND) include_directories(${PROTOBUF_INCLUDE_DIRS}) @@ -94,9 +99,11 @@ if(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) endforeach() else(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) + message(=============================================================) - message("-- Protobuf Not Found, Protobuf Support is turned Off!") + message("-- Protobuf Not Found. Protobuf Support is turned Off!") message(=============================================================) + endif(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) #Others# @@ -109,15 +116,18 @@ add_definitions(${PCL_DEFINITIONS}) #Catkin# if(${COMPILE_METHOD} STREQUAL "CATKIN") + add_definitions(-DRUN_IN_ROS_WORKSPACE) + find_package(catkin REQUIRED COMPONENTS roscpp sensor_msgs - roslib - ) - catkin_package( - CATKIN_DEPENDS sensor_msgs roslib - ) + roslib) + + catkin_package(CATKIN_DEPENDS + sensor_msgs + roslib) + endif(${COMPILE_METHOD} STREQUAL "CATKIN") #Include directory# @@ -166,19 +176,19 @@ else(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) add_executable(rslidar_sdk_node node/rslidar_sdk_node.cpp - src/manager/adapter_manager.cpp - ) + src/manager/adapter_manager.cpp) target_link_libraries(rslidar_sdk_node ${PCL_LIBRARIES} ${YAML_CPP_LIBRARIES} - ${rs_driver_LIBRARIES} - ) + ${rs_driver_LIBRARIES}) endif(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) #Ros# if(roscpp_FOUND) + target_link_libraries(rslidar_sdk_node ${ROS_LIBS}) + if(${COMPILE_METHOD} STREQUAL "CATKIN") install(TARGETS rslidar_sdk_node RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} @@ -194,20 +204,28 @@ if(roscpp_FOUND) DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/rviz PATTERN ".svn" EXCLUDE) endif() + endif(roscpp_FOUND) #Ros2# if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") - ament_target_dependencies(rslidar_sdk_node rclcpp sensor_msgs std_msgs rslidar_msg) + + ament_target_dependencies(rslidar_sdk_node + rclcpp + sensor_msgs + std_msgs + rslidar_msg) + install(TARGETS rslidar_sdk_node - DESTINATION lib/${PROJECT_NAME} - ) + DESTINATION lib/${PROJECT_NAME}) + install(DIRECTORY launch rviz - DESTINATION share/${PROJECT_NAME} - ) + DESTINATION share/${PROJECT_NAME}) + ament_package() + endif(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") diff --git a/node/rslidar_sdk_node.cpp b/node/rslidar_sdk_node.cpp index e3fa54ad..546917e5 100644 --- a/node/rslidar_sdk_node.cpp +++ b/node/rslidar_sdk_node.cpp @@ -38,9 +38,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifdef ROS_FOUND #include #include -#endif - -#ifdef ROS2_FOUND +#elif ROS2_FOUND #include #endif @@ -57,7 +55,7 @@ static void sigHandler(int sig) #ifdef ROS_FOUND ros::shutdown(); -#else // ROS2_FOUND +#elif ROS2_FOUND g_cv.notify_all(); #endif } @@ -76,7 +74,7 @@ int main(int argc, char** argv) #ifdef ROS_FOUND ros::init(argc, argv, "rslidar_sdk_node", ros::init_options::NoSigintHandler); -#else // ROS2_FOUND +#elif ROS2_FOUND rclcpp::init(argc, argv); #endif @@ -92,7 +90,6 @@ int main(int argc, char** argv) #ifdef ROS_FOUND ros::NodeHandle priv_hh("~"); - std::string path; priv_hh.param("config_path", path, std::string("")); if (!path.empty()) @@ -121,7 +118,7 @@ int main(int argc, char** argv) #ifdef ROS_FOUND ros::spin(); -#else // ROS2_FOUND +#elif ROS2_FOUND std::unique_lock lck(g_mtx); g_cv.wait(lck); #endif diff --git a/src/source/source_packet_ros.hpp b/src/source/source_packet_ros.hpp index 58542874..a5e33569 100644 --- a/src/source/source_packet_ros.hpp +++ b/src/source/source_packet_ros.hpp @@ -92,7 +92,7 @@ void SourcePacketRos::init(const YAML::Node& config) pkt_sub_ = nh_->subscribe(ros_recv_topic, 100, &SourcePacketRos::putPacket, this); } -void SourcePacketRos::putPacket(const rslidar_msg::rslidarPacket& msg) +void SourcePacketRos::putPacket(const rslidar_msg::RslidarPacket& msg) { driver_ptr_->decodePacket(toRsMsg(msg)); } diff --git a/src/source/source_pointcloud_ros.hpp b/src/source/source_pointcloud_ros.hpp index 278d29d8..f9e84a95 100644 --- a/src/source/source_pointcloud_ros.hpp +++ b/src/source/source_pointcloud_ros.hpp @@ -35,7 +35,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "source/source.hpp" #include -//#include #ifdef ROS_FOUND #include From c090da5c0add9f15fab683d312addc131889cb57 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 23 Mar 2022 15:13:37 +0800 Subject: [PATCH 123/261] feat: remove protobuf related --- config/config.yaml | 17 ++--------------- src/rs_driver | 2 +- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 8fd6fb87..2b611927 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -3,12 +3,8 @@ common: #1: packet message comes from online Lidar #2: packet message comes from ROS or ROS2 #3: packet message comes from Pcap file - #4: packet message comes from Protobuf-UDP - #5: point cloud comes from Protobuf-UDP - send_packet_ros: false #true: Send packets through ROS or ROS2(Used to record packet) + send_packet_ros: false #true: Send packets through ROS or ROS2(Used to record packet) send_point_cloud_ros: true #true: Send point cloud through ROS or ROS2 - send_packet_proto: false #true: Send packets through Protobuf-UDP - send_point_cloud_proto: false #true: Send point cloud through Protobuf-UDP lidar: - driver: lidar_type: RS32 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RS80, RS128, RSM1 @@ -21,19 +17,10 @@ lidar: max_distance: 200 #Maximum distance of point cloud use_lidar_clock: false #True--Use the lidar clock as the message timestamp #False-- Use the system clock as the timestamp - pcap_path: /home/sti/dev/share/pcap/RS32/Rs32.pcap #The path of pcap file + pcap_path: /home/robosense/lidar.pcap #The path of pcap file ros: ros_frame_id: /rslidar #Frame id of packet message and point cloud message ros_recv_packet_topic: /rslidar_packets #Topic used to receive lidar packets from ROS ros_send_packet_topic: /rslidar_packets #Topic used to send lidar packets through ROS ros_send_point_cloud_topic: /rslidar_points #Topic used to send point cloud through ROS - #proto: - # point_cloud_recv_port: 60021 #Port number used for receiving point cloud - # point_cloud_send_port: 60021 #Port number which the point cloud will be send to - # point_cloud_send_ip: 127.0.0.1 #Ip address which the point cloud will be send to - # packet_recv_port: 60022 #Port number used to receiving lidar packets - # packet_send_port: 60022 #Port number which the lidar packets will be send to - # packet_send_ip: 127.0.0.1 #Ip address which the lidar packets will be send to - - diff --git a/src/rs_driver b/src/rs_driver index f867bb69..2524d7a0 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit f867bb696e205969b9d10c87f5c38a54c7967e1d +Subproject commit 2524d7a0f52c87d65ae966cfcfd2a06ee9a7988d From 1ace90a117b44dc00dbf071b85d72c4ffb303409 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 23 Mar 2022 16:28:52 +0800 Subject: [PATCH 124/261] feat: sync to rs_driver --- CMakeLists.txt | 5 +++++ src/rs_driver | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7982bff5..21e0adfe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,11 @@ set(COMPILE_METHOD CATKIN) #======================================= set(POINT_TYPE XYZI) +option(ENABLE_PCAP_PARSE "Enable PCAP file parse" ON) +if(${ENABLE_PCAP_PARSE}) + add_definitions("-DENABLE_PCAP_PARSE") +endif(${ENABLE_PCAP_PARSE}) + #======================== # Project details / setup #======================== diff --git a/src/rs_driver b/src/rs_driver index c5297e26..8f5f62b2 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit c5297e264f89fd2275bc142da88a0a2110f6da08 +Subproject commit 8f5f62b21ef342dda037ccd18412bc3e0634d305 From b470ebe8833e40bfed7053340a2b89f5d2dfa342 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 23 Mar 2022 16:41:47 +0800 Subject: [PATCH 125/261] feat: update start.py --- launch/start.py | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/launch/start.py b/launch/start.py index 8e023706..a9031240 100755 --- a/launch/start.py +++ b/launch/start.py @@ -1,21 +1,12 @@ from launch import LaunchDescription from launch_ros.actions import Node from ament_index_python.packages import get_package_share_directory + def generate_launch_description(): + rviz_config=get_package_share_directory('rslidar_sdk')+'/rviz/rviz2.rviz' + return LaunchDescription([ - Node( - package='rslidar_sdk', - node_namespace='rslidar_sdk', - node_executable='rslidar_sdk_node', - output='screen', - node_name='rslidar_sdk_node' - ), - Node( - package='rviz2', - node_namespace='rviz2', - node_executable='rviz2', - node_name='rviz2', - arguments=['-d',rviz_config] - ) - ]) \ No newline at end of file + Node(namespace='rslidar_sdk', package='rslidar_sdk', executable='rslidar_sdk_node', output='screen'), + Node(namespace='rviz2', package='rviz2', executable='rviz2', arguments=['-d',rviz_config]) + ]) From 8bfaabbf89d1c1ccec950435d0c25515d14247fd Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 23 Mar 2022 17:14:53 +0800 Subject: [PATCH 126/261] feat: add source introductions --- .../img/class_destination_packet.png | Bin 0 -> 15313 bytes .../img/class_destination_pointcloud.png | Bin 0 -> 17429 bytes doc/src_intro/img/class_node_manager.png | Bin 0 -> 9430 bytes .../img/class_source_destination.png | Bin 0 -> 56893 bytes doc/src_intro/img/class_source_driver.png | Bin 0 -> 37864 bytes doc/src_intro/img/class_source_packet_ros.png | Bin 0 -> 29037 bytes doc/src_intro/rslidar_sdk_intro.md | 209 ++++++++++++++++++ src/rs_driver | 2 +- 8 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 doc/src_intro/img/class_destination_packet.png create mode 100644 doc/src_intro/img/class_destination_pointcloud.png create mode 100644 doc/src_intro/img/class_node_manager.png create mode 100644 doc/src_intro/img/class_source_destination.png create mode 100644 doc/src_intro/img/class_source_driver.png create mode 100644 doc/src_intro/img/class_source_packet_ros.png create mode 100644 doc/src_intro/rslidar_sdk_intro.md diff --git a/doc/src_intro/img/class_destination_packet.png b/doc/src_intro/img/class_destination_packet.png new file mode 100644 index 0000000000000000000000000000000000000000..b38f89ec65df009a1132924a83f34a2821289991 GIT binary patch literal 15313 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 UVjIHm`5=xRKB1PQYJT;90Msl~9{>OV literal 0 HcmV?d00001 diff --git a/doc/src_intro/img/class_node_manager.png b/doc/src_intro/img/class_node_manager.png new file mode 100644 index 0000000000000000000000000000000000000000..2729d4062ae2ae57179e1e89006fcd9547bf965d GIT binary patch literal 9430 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 z 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 literal 0 HcmV?d00001 diff --git a/doc/src_intro/img/class_source_driver.png b/doc/src_intro/img/class_source_driver.png new file mode 100644 index 0000000000000000000000000000000000000000..26e1916552b87802129927db25305c2be36ff8e6 GIT binary patch literal 37864 zcma&O2RPSl|2O_sDJipTkv+32$)4G=LLym}N>OH!oh=m7AY>#JQj{&bAzDaDl#yg5 zB>u1Sy6@lf+|Tp-J;(9CkNY~VF7fpl=lOoW*87Y$HPNM`<)o!hD0KRI+U67r)kXYs zh-NLmq80V482?)Dp|}4Gg+kv*{-H{dpy#4cwo>%9H7xzEkAL*Hc`>@8HaYB8o|>iO zwwFsh++4I&nl7SM{=(ilxzv)Ml^jaW`f@v>6TM|x@5yX*E^@vl8L=mOv-iPTwZ)9z zKd&p^5Xy~vKltRyy_cu^fBvbyekSwxT$PTt_I-!i3pF*W1~Jdh_)B$seY}*m?_f@& zg-e|5T+^4AVY1CvdbK$?I4nQKAHtXXnWlC#kZ)5?8=fBf^3*C$w)su-jdjj(vJX9n z>)D-+-241xn%OP5e0j)U<>j_tJKT|Rck)a!wqbU_kb{YTrP0#LEMMtmK)Y5t@ zoBhlTkE} zA3r{=#6W3%_Do{>dTLEgO@p$pii!&3l%H9V)7h0}m8GSn#I&@?(bxG;TU%+?(R0@= z{`#JD<3{}51LdiUJECd$lM3E^cP*-l(&ir-8*Betvac^=UFOW8%!fhC3+tp0R;kCb zZj9 zXl~!WO$oNhH_;GecI>*PPYJFMTc;(+%*W5a$|3L+Coy$_EM)`hGd>3Ja1 z@bszY&rd1=e}0r7eOt&vIrQ;~Hw_(~PR^cqMlP<{wRD_YB_%g z$J%*$Y2j$st@Wwf4qQmzek5BflD@mddEN5DFmKtZexCjN_bd2La4*jN*dQVzA}A4jPY!r^c&NL$2+q#V7N6*m^BV1< zj%46%&NIH2c$0P=vnDJyQDk>R-H|qlD9c{`LL6 zjI6Afyr7ANg~fdT^XD7&_4Qj{yok7WPfE(6Ca$qj+v`U!%i+U^DZy8+uq!Ak(z@c( z?v&bYj0-#+&>a)_uF&dkOlzy&nzd`4+AoXQRG;0sCxJV9e%|lReFxr$$KN*>J3gIU z{(CNtdpC3K-#IQ#O-%~rX(Yos%9}gZ43uJz0ZnctpN+@g6;V+ltU2bszh}U9Vc&I< zJAp?fhHCZNLt}4l7uY@&Uz{CXP3bOm-C%BEQF839`0T{T0}6Z{-9c18{fj$nU*{Q5 zeZODp)S0c*UEwM4sU~oPv$OL?b{Tc{#uJTEOxS!+v8hVV44c>-IN&_k96!=ut429A zJJMO;E~TMzB5=|G9Jxjpc&N?9?3BAF*Yq0H_acROB*p_$$J*xr1?GS`_9acn6Yzk)IWQ+At@1^s-1 zPa3lHUYP#sBpoJoZ@J;w*6rIj)z{Z6_>8lQTi+}4;j;AnTu0^g{Tfr-t>{H_L&;a_k`HQqo_WuV&EwNTCqGq*DW@*Qyy)m)%Q*1hFkMx3 zby9M2C~A{{v@`<)uc~&6_`b=(i)z_ccWtl8yK|!8$pkKX#c}PT_nqhq(GyHgPrY`H z%gNc9io(F7tp5GoT}M|}>N97~#BprjGx}FFBO?R#HDyvkO^sJrSeWd(Pu1rlabLK0 zs=2wjk?s-!9@PLE3MyVxwoWXCLaH^Y(jhmuXgq>}-~B<-K4*=u?x;tdqfj0_dSrtu z?JYmW;Opz_=kLFM(B5#&q0}Y%xf~^!MZ&7CrDYxV?K+C``6YJyCte}9Z;PF9cQ5h& zZsm9uOE}`egYDeh+@B{V5-y4CT_wtXrV{lfDlRTOGn4oFjT@c!9n=_^Sf%Wu3JOHW zKUT82_m*iG8O6Qw9~vGO*s)_XUe?j>Vm_boZmMnDwke;TrLnao56AZQ#DHwGDue6k z?)HujhO1YvDtM1wp6o;I3{Uz%swCD&eEF$ve` z>^RxSjsjER^MljL$%&DTEx*{P_Wa-CIV*RwIpnLnxz%#@wJ`B^8UdsDC=qd z9gWeOVkN`2DEZt(y=yqP`1|L@J@K3aDEtauBaD0E*h8-EI`swLb!GbzdQxgCeSbRD zhf&n+z5$nLyCCp4k#^YatkrcIl!T)Fc3 zbA8yz+dFJVMn;E@AKzeXY)lH;e6oqYem(l1YYl~p<{S%pl0<1_R!l{O!t-mp7$~N9 zthSM-`1@zSwM`zbqrz)6c``N#kAQ}r{=$U|Yv;y$!uYf<(D=S(;F8}s+>xofXU_$r zEiD&$boq5FQKJ zraOm@fqtcF9o)4r2v2E85`@QN!b^pFyG3{ z`+^oqp;Zi5IX8#L$cxUYJ^b>9Gs*-kp|#fdQ>wU6NHo z(gF{r%>4svNl6JB_v*QckFn?-6iQcD*P)|FMQ0AS&2-_lPNChh_-Be2THlvix}TNB zcjoBcjIy#FM~@w&eT^%jrjWLLco8dJr&rqF_{rZf6EzhT`@^>H-o4ZLBIi2PR<`0X==})^^%w0s@6FE6-a76tBqY=p=%7Ex&EcGRU#{A6mx2O2 zm;4EJ)Otmq@d9&>EnBt_bgEvT_9!)#mGlw{^*K&4F)<1){cyniq{fI0J&$q}b`IM$ zTCo@X{k(vcBK-XP;nnmv51kT6_d`>r(3+^0yS?7??Y$y}bU-sRGr-H%=g+lWTy7c6 znEiEnSP{Zw1!cM9u3c}<_r@)#uYYwd}|80;{#7>mk zzP+>5^%-+{6WR%ZSJ;+YS!0=)n9PP$+}zwW^8v=?E*lIpadB->Q>*3gShsGS^ZR@D zG_z5qk0yzkkqP_2KUv`wq%iDYRzH;st>D$*~-|JXfT0S;%SR5-vqpg4QW-|~m0eC(? zdLtHQhSAcNMbjRkTz|T$5%vlgjGt|%zGb21?bb8m@x%4b{+I6;7t4^H{qF7o4vN-qajlEPXbEkWSYg-PAIEx0t-SP zuzhS)Sy9=F{clTu*D-G2n(Kwn{(}_imZoV2#_;#BER5!78uVoVgQjz_G&#wlgGXit zEvM&naX7o)vsAnYY+cB`H%m16Mij8cLGc^9ZU=w>gpIFS9{Z&dxVU)(tE6e=^`Z00 zZm;v&ym$;#B{kwXcgh^9qe$9SFdlh%y&f&Z;BIxCtZ=+Q&ohPOKvY7MJZ*rOfsv7@ z$w?2FBS)S-eYzSoiz>3V$Th;q;}H>KG18LQXWoArc>ToN{BWM_}6 zU0LP=g48uK+K9DY;?lMwtnI5l$A)&V;PE-w zw6<(&uw`(hGY3sJ1XZH9%uV2VEC@$Ph(<}yFZ(LL5XzEy*-hi)rutVZU_hn0G6UZe*8GV7~uy6 z*7tch;x%TLwT){Zgv#{Q+_|DrcXD+$1BWo4zOrx#pZtwQmzRCG3S?GKotySnrE zh4X(GS^V#ITYh|h-(j_=!bZWpCMNVK35MmlMV9-3dVo6`pQmqU+Op+^*(lT%MyAte z&cv!%N=Y+?x6I66ydvYc3e6x2Z)%`9o{Kx>CA$U3#o;OH*KghsY|~!J5mzF;CVx!s zf2%RgN#nVu4*uGuY^=Pz47+yi8vj(yWqeJZWn!OWTuEtN(ztk`Xwvw!%i+WPcy%a$ zy5P6yi@VLzWUcbBxI?u|C9ckWdvT4>q>TV1+ic5%FJ0P1T8mqeP01=$JyMY=gyoT! zJ!~u6+`dt_)H+emN9XlBTpIwFtjA|{zzkNPfkr4iQ}a{Kjy(nu3c=`(%8~6h|WR@Ml*88=I!&8!F$De<29{5>#eP$!-oa)I)87=*Jo+5 z9}Tgb8vK+mt`wl0vYeBS4!?h2`ksB|S_i^x$H=keNX!9o8?M~VNS$XH*S$0XbY zE1%RXFCIVY=B5F?=j_?D1!g&G6}`v8fxN}H-8u2tP@;-{dU~2j4G>4jHvuS*yt{kN zqg0eC{7@5p8jj`gQb{WQP(piK2h*E4nep1iy~n)U0MPSRRw-&jaK zsbuOg^8%fa zf{Cy2?!1dux!xhQ`rPkkv?aB|ng;LGZ>H4Au0;L{4`0*w#Crq2f1j-hxw$_;j{{%7 zM%=n3$gLW{e(F;dQ4NR$g@uc^jFdov@WI>e)Elk-p~T#g>q^Y`~}ICIDPzA%u++4)I6 zs+%D5uhdqSv{EFj^LWqCha7uTpka|`lm)hvgjF8+`=hVdpE>u%T47o{dwVwkNNw#| zY`#laY5Q$$&2K1rAB7eq$Qm0Rb@X#x$PVwZH~j9uCMR#=6KOBbOi#CVcV8i>z5V6O zyd(kLWEAPQcMqfi#Hz0>&FoEDgs^75JRt>QODK>X& zTU&H!SeU*f>uZ!I*LOr;Ky5QDaOj=;@nIAtM3|o+|Lw>H9>4iZrWIa++is+5!aY zEx@atct;WL)}8VoVM?4kk8R#>V`KWG_o3T(cgf|#BzZf`oM4ew86*)We%{ZwR#GKV% zjma$Ciw7&;#mPw%e4Z@>i!vKO@vJB=e{Uu;1vnvfGGrEC#LHkxnr7*`XRpMmc3zo@ zsoHNU6qxTQ=%lt~z;Mao7o5{`bF4fob01Ejd+%9TSlHp-yJPy-FBYp$P>&44c#{b)MjzY7X3zM$p=YF3ow8*E&voMEr z?RNb5Yjm!tsH0CW(A~Oo$MC}=cLDx|8!gzbG?c%P*1eYIJ>}%&vawwG`4!L3iUPmf zK%o$O(3h!lZVv^&2u9Q8^mKjH>4tS0XSY1RA{(ZxtUUDc+K#p~&$DM0N56l6jXf9@ zB`PEov5}50;)j;maMsbsg#zw}ZFYYH$W8MIroQ0(5diZcMAm3g4N~^>Be}1e?19lL@Z-|P5UIks;IPc?h zjY4!3%2)yXByH_CkgGViAKn<<-H zMrJl`*<#$=+v_zqzMr3;ELX7kf$HhhdI*iTv84a^qQu&ViE}AN($}r)yLsoZVUKSL z)Iih&qk;!eI2+PdpyPyS4c92Gb=P4E8B{WxHBLy-l#IpG2ST_$?r z^m8FGj?Mh8?auC=o&j8j&Zn8Nw-Q&bUS<7op~2+30+oP(0N<@r+z@flAV(CG6=i=d zG*AM{O}c(P4u3&Kv3+!6y}P@+qv}>=dovoL1x7p*j-=lb z1DZJycy4Z7LsN5A*~5oSXzbYIxxcUt59*yh*iKme#u5ObPXc z;#ENJ4UeNCczyZ%=XcYE7*!~=YD<%09zBl>GmX9TawZ<#oftO!0@hOD{hbxXIbu%# z$X_gG=blnmo3f)xeM6qEU*GOu$=z+a`dG*Q(+#b63bku#nRo*Pz<- z?cTkAU`gMioUUv0HtT&KAhb}SiTe5Z)q&go?60+cVoYH?-4Gl)f3D5bQ|E)tv15hL z7rWlS*M$ih-U6b=(kqo^a>x~X-N@KDVkY|F!GjI*+nt*?4#aMUQiL@CR1*Sm4Ln0+ z%}H_dzQrJH4v@nO_$M2lEW4abl)*F8p5gq-SxV1La7ajqjEqb$d}S!~on>wo;N+&c zPgq`94~*&s6uK+n6;Wb7KDxH^_*%R);M@Zf(Lw(_DO6?gK-PU`hpi8=B)FvQ;?E2h zPa0TW)pAqUW}QmG~uq@mA=wXe13>8DK4X2M!0_i+=Ga&M%g^R`z3@JaKIK+ z72sCS@W{wJJNl=eU){NZSkd^r*G(;Z|0@fSbmdAEY^wrGleZmvJ#qWM^C9?Y0Wq=l zaB{Wa1smp`^e1YH!}$ejFl4z7G{M23l|K$iDpool9%cV5L<^?`+xByGT~3ky@$0^L zf{XN1Js};b$&|jhFr+^M@(`eTIcd^efx&-qD5`15;4<=<7G^M#W@ zg=>V2rwLSCjK-B^0y(khKsh}G&-}zsMJE!a0Q%9Yvf+vo_PA>GYM426ucJdGI%nWRZ=+@EE(XB6EHUkiM;yUdreT)^}hjykV~_hI6IJx{*jNl;Nj5%B zJd**);(t~_V+E?|gG0ZM)c%=JGP)*Dhjo47&K-&5nlOq7*CKkHkp`q3!xnI_IZCSv) ziH3QyuLAPT-p4K1E4{z3MSjEbwmCJ((FI65^jj1KxqTKEhBJv{)!p0M(A>P%`ktKz zB;~A}oG>wqyql-`YtS1n;ITsAl5uHeBm$qPC=HZqn-Zsp_U}PhOi)slxwmZTEOFKi zSo!;#XiacB3jbr(oP%ZQ0X?IlvN8vk{}0*q8K=QA2Ipp5cxgVnU_NUv1do-2BO1>9 zmGpEz#4FH|tQVBD%>2FIub``2st)Is*=s|>NP_LRp|VcB{{DNoiv?A~&Ek)qKR2@3 zzn@eu$lqT-a?ero@dK6;@p^vo`+e7ggL-ovb^wLIl;K*cQ&UrZ(?jbycb&9*xy?B@ z7g**BILzUf*Y|%ic67LcG6B}T_wcKVi}g2jsm&p`L;E@eK2Tg%)(8*`)yn?Molcvk z9gYoau;-nD8NYtqJQo2$r5>WpVbPpcV5!u65$VsJRbKuE@=mJb&?m z<(n@K3ftkI?HS8`Lt8FAY4O?3|nuQ0vpXIS^m4fU&9W zXUD{!Z}<$+7+J)1phsZKxtTKe2O?GDclK;H`m1J!tv<`a3!o5Ie}tdyHOtr5>6>ep zJ8XAW(Up1oOG_*98!hcA5}u$215-d!j>xE-*@PBw92`IX^5xA$2Ley<12Kl;ABu;- zg!&d8hFn5qR9>lOlxrC`Q06_?q@IqwdIs`q4@(xqT z>22XYSWPfa)a>l+Zel}0@8DNdLBk z#}HKD4IR9@Pp^R;0~8esp8DuS4}aAhghZ0+flO2U@FB~@)s#Kj&}vCu2o{tl7*1bJ z;DL$HyMTKklanHVa9TWQr(>ldWLf}ya^YiR;%8>BZHZNBe73pp4>S39UKtZD{BaEZBy#*ihRc8{8{<2|AGl_rAEiJTfe7^#ulA zsYX|lm?F9@_7kyGh+6}*@$`Ego!+_9($ZIzzNd(RubaTF0S)o%`NO!YRj|77jr==y zSblqOXKZm40W6Y8z`AO)mnz!G6u2LXZQgCsiL>3sj&JTB*ab5`AHXCHeO|CJ+@aDZ zp0c^EpMj1p7os!Xpgw;!>Zvi34zu50aPjkVs+`^NYwT@o)N)W&6~NZ(m@nnIANc;R zfPUy5IB*S;y1uqHYQn9%ca1Ods#$TyP7DreLE8}l!v%)U!{U7n_eN~f9Tn_>V|X&v zK`R+iwAsB+8ydpp;XYr-VzzQQC}=hVRC5z$uG88fPzQpZFn{(s2A)JHq#vvNFX18R zSy)`+QT9{U)^2NSdy{L(1|Dah%k;8CJLhGS^ZgT9@f-OZ1T2-hES|8 zfvSAG$FjgbJ_A$0P~>^32F#ldg}p@&#EO*49==#l!sB5Yo(?ocM{7KzRknDf~UcWPEQ%Az%SY3ZTBXx3@EY8vOQ6*vpdK zh_*JEw-+{1Onkf$MDO(X2x08qe&ppXIK+kamGZ{d70eFzFpDi``+9iXL>gt_A;GV~ zRI8(+M$oSs(!`lMAzj^uR7m?hV0mdb)lCpJn)~h_pQJ#;I6FxiVD81eOB zXL&VLNdps;Jm3ym=i_>@F){qanH@%ha6?Nuc9)kw8)Dh!9-j2G23`K5yqC(@si>%E zXlN*=jJe7ux@FP>?%-)<0sPri`rI`VtgKr4dokK&WvYcYDLs8X2xniV@7}M@ZOLv1 zE%t_x@75=^L^yYS{c+x~#UF-*3dA~%IZ?tZ(w8H509srUKC`t@7go!pPGO`5?2v;tu$!Vb1Q-57z zYO1hc>hes7T0@%NUE7Bq&`Z#0IPX~9ZMY)q9KN{kv4js+Dj;DfngyPoS@}u(B|x^* z{Ri-;6MYp->KZn7fUYj*)e9uxPr#!_vI8lw1_%hTDr$Uu3t!R>@{H{nv3}#eH~pVy zlqCA&*HeRjHjXwaW3#@Urp3B&16K1lKn*8Z!<6q*v3fu2>eRt8OcZWIt9A^46x~qz z44Y+bsF~1dTeGD{{1CgmnNGT~G7ys8^1;5!Xi1D-#6ciPpS z-$DY&X=y;ZP*yawbyBkmNh}m(9m(GTDE-}!&*T?p#NHv2(b1k#A&9jbZXW753Kg|s z#Gf~(s$9htJe?q2l5C*>R0!Fr-kVqydvV1xZ*BHPHOGV3NtMPkjpL3G=;_^2o_h5`s`E+ZH|`kT}a`9o}COj=90?9)CqN;Xm4JB7root+K8QKMr3eQZU~OyvK?@F zZv&PP(*a>B5&mq_DuHN>p&#GM$Ll?d3pY>Q=eK@9Hp3}^{lPa@E+Uh>VkI zK71&I9YXwsuV23=*+}L=dr5lua3?r$5_rg6n-a|lImv*RT8l$J;bn^{C|rq(dUUGa z1UEM{G^C9b)-5nusCEyDIf5cQJHq5W(U%U6WC&`o1MS=K9PRq`De>rRW`+!(k0E!#mzjOk`;71;cb2mCT)yj*7CRnQ?J z$wyy_oe41fT9?;W%&qTnl_(;)en{)`DJfMpJlwTy8y&>NB>#KpEWB@1FM3XX)_~e> zIr?{7T*<0TIuI&pq8t!~ee|7EYUWvhytp93XeSGrZ@-Ugz-xvi!%05;5_fhLCYOw)S4b9LIB!a?~l3AMc zbaizv!Ej1kOixTyhu}?2n~0=NZSCddSOmpSJ2SbMj$;00?I330T__b9%gG- z{$7lV!mYcZ@WKisZkmF}R#I5Z&CP+d4^&8;{g=lgQ3T__!NI|{_IzN{==M1Wt7N6; zhE>BQSkdSgb&ZW{P>;3mAFMv)=b1Rtkco(&3`*GyjKmZ~^EUEwJ;pg$O?I3CyHH zltRCSX(8zU5ljMm)CHOAJ3E>1l9Kfu?a>^WnVE}^bnqNKew^^h{}S>y*?@lPAY7aD z=s%LJYO!Xf@X96)y3O%fYnOwL-SIl{z$>7<48++P`L6k2 z?;QyDB?0lJg&E3nP+S?B2Eqy?Af3)W+K}{KU4uJ1yY*-^$%NO{QP!?qi`>2ze(#qr zU&7BKVe|RxS88+tNc*Dk!fD#4`l|dlfrUk48+z1eDk>h7liq&#c_No*W@;(~>=zw* z)o@NmdLK#zhn`^oTM?h;p~zW>5(Minx!Z`7hld_MNO*X79k2-&?9)HLf5tX`kJaW+ zZ}n04rx9>2suQ{BvI`?6U1qJZS@)pb1&0=#YP+%u#^a@PZS0i!g@t;A$FUo1YR@Aj zHxdHPB|^3o!}#@&Gs8OA@gO)=k6jJ|!d5$q8;9=|A(0*ha{0a1mEM zK}0}*Hl^8DVtZa6e&?yzd2~eXMdpn{&HD)}mv(hG(Y~Pim?)(C55L@kF%zQ+FAO8e z0_Ov`YZw}CfS%FN=B`72e@vW}&cA+dT0-eAdHFr(&o3W&{i$mf!z<9*aJyU-+DAEH zOd(Oo7DdAgH&iI$Avx7=A_>0_8|}>PA~di)j$ahX&N%E-KB#+e?kKe9JAZyCXCTiW z+@3^J5K_Gfup;NG!_NeppEyha8YH3`w6c6!TH*(i;UE&LLFT)=yANTyLi1KD4606q zwULKsL@`3amx8F25BNYlYRY?i{<-2#*k%Yh7Sn^zkPIo5+g#U6$;n%p zqleCm(#9f~{@Bs7N6|F@q_^JvFzBDFA!ea#NKDtjHpSduih<_juKs|qXKB(wUMfPc zT1i5UXWQhaM4pbENe48>p*e()mYGzAzu3K9kmP>&DSt075pbab>FwQ19{VdKDg4fz z3+j@%BV|_+jITH$@nO(kdHQR+lTvDO;=vl!3buE|Q3bMzK;TgP?$f?LZq$WM{8pRO z<=w9u4V#(03rR|1A|niFPHoD(92{bTRF~i2)@9GloxtK;3w%SUjGDh!ZA1h$U`@B&FdT$mnFv^7R+v;`nb@-cog_gvj zM174wf~H-iY97IKk^u**#n@jRVulfwKf*#oT_*aYV`De*_c?$gp$8G039R%f;xkef zKS9bT(f`@5X$ftE;ufW2R%UYM^l2H)ph7^e#|>g-G$S}2;Z0f^FtiqpyyWwShES#~md~tdAc4(-dM#IneLGMa4Q5P0O~RrGExo zZx}?-jzkG_y>H&R6N`J{LzvbNc*>U;!1wRppS08GAFHmeCcqEq=QBv-eE-U_h|5iV zy+`IDqrs3O|q<|Q7+crs{cLA;f2u<$H)5F?~XjbqQS$%L;GH5 zz;)!u4`Zxqe*Wx#iEmk$JYi-sLxS1$-4Bv+0R7U|-VreGG5z~@KC~kez(O5K1oC5I zf;payDU;m%{0**Ow=qP+e5HMDS!TlaKPr7%+S(wJ8}{9`-4_)n!cR~k%*uU-ZE-`n zD9nsZo$y-QT3e$4LZS-}DdCqZ!W~Y=2$vp(#5icn!+;qWDNlk{YTCc6KRN08Aq2u- zQ%lPRS1m0qHy}5I_w^7K35mrFl?D>7nhP)qUV|_FugyJ!6QSb;x;y{d_KQt-|EMEu95%=yt?J|aGMJ6WXOl*q}Q4s+Qq5x8Qon5(x z(NQCS4KA3Gnc0nJE>BHOEoS#^e9!~Q)fn<3gdn^z+&sk4j9z&1P(R$w&5yE*K@v%_ z8e@Aqf~0 z`{sntR^v{^MB*q-q1$``)u*DI056_@D`nOdwTO=E43CIV#0DRO)1w$-#EQCOO9M7Or)|YLxreL!d3!`ZVQ=l!>5- z$g^$I7hP<-ewe;l>lQKWaQ2fSCr`nN8>)Vj6hMbP5FWtTL$EnCBw07yH|$EurABuJ z%354pM0X|MP=YvV){Vk@VP77FH5ioAzv-dBC1$&h`N@+f1YAOj4+VxC1axV*BFQWi zUw{Rzv}5N^d@!F^-L&5MEBa0jw|EUx2S}v(qi_E}B=7lPlmPj zm79Ob-aF4HW<pim8GJj z`{g-<^(>p2qUEK+xPsD~BV61gQo8@Pt(&Hb45lz%9GG9l-z+k;QyQU1#k|s$8 z^r*?VKX4r)EtJx7T0tS9l>J;bqXT+#P5~zbD+_0C$9Z}A;}!fr;{#N{M{=&m-xfx| zlc2TMhRA*hBuca87^Z6)FAabF>IlO`vjRn3W)=OQQ$y_(zr3%E z{?<-lH7pru$?i#72Y9*69BeOa$Grzo*t3yr#>l@zeNefk6LNA^N*>e0GN_F1kl{? z+zKA*3S||TOvNb_ZFCP@zQ!ssSn7mx?le7|iqfuvZ!Ern)wowHumyyE? z0jMHvAIdHJ?$d&bz7ugUWQ{VEIRGY=?*&jd;=&st+#dX7e2DjUMbzS6L~hL{s&}DC zUO&DsWQt6U|F6R_Fsqf6m>3M~64Z{#X7)eY{~iRty)z@S%g~!jw94o=_C5w%s*Qvb zo>VB~oDH0qk>=p9rS;TF`n=eLxqXTvgAV55V}a^v{pE%3hCMs85My40wo2LB=l}P1 zKF;R|&=K$W?JtuTicls70;v!LV{v;22Ome9ujoH=CF zjyxB1_q8Q98$n+%ev)5xtxf!na7yE zLlt1_Kz`#3{U%X5@oCVCSa~-?(vukU@0Y)5kcR zSuWwU5LH#-lQ Po5cn3J(rk4TM-rw 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 O#*Q36BGF<-!2bbGTX-Y@ literal 0 HcmV?d00001 diff --git a/doc/src_intro/img/class_source_packet_ros.png b/doc/src_intro/img/class_source_packet_ros.png new file mode 100644 index 0000000000000000000000000000000000000000..91da7af2385819e22d3683406b98e851414c4e1c GIT binary patch literal 29037 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 Date: Thu, 24 Mar 2022 09:56:22 +0800 Subject: [PATCH 127/261] feat: add test cases --- doc/test_cases/rsliar_sdk_test_case.md | 83 ++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 doc/test_cases/rsliar_sdk_test_case.md diff --git a/doc/test_cases/rsliar_sdk_test_case.md b/doc/test_cases/rsliar_sdk_test_case.md new file mode 100644 index 00000000..7eea79f9 --- /dev/null +++ b/doc/test_cases/rsliar_sdk_test_case.md @@ -0,0 +1,83 @@ +**rslidar_sdk 测试用例** + +## 1 简介 + +这里的测试都在Ubuntu20.04系统和ROS/ROS2下进行。 + +测试用例级别: ++ P1 基本功能。失败将导致多数重要功能无法运行。 ++ P2 重要功能。系统中主要特性,失败则无法使用该特性。 ++ P3 可选功能。系统中次要特性,失败无法使用该特性。 + +## 2 功能测试 + +### 2.1 rslidar_sdk编译 + +| 级别 | 功能步骤简要说明 | 期望结果 | +|:------:|:--------------------------------------------------------|:--------------:| +| P1 | ROS1下,直接编译rsldiar_sdk | 编译成功 | +| P1 | ROS1下,catkin_make方式直接编译rsldiar_sdk | 编译成功 | +| P1 | ROS2下,colcon build方式编译rsldiar_sdk | 编译成功 | +| P1 | 用rsliar_sdk连接在线雷达 | rviz显示点云 | +| P1 | 用rslidar_sdk连接在线雷达,点为XYZI(或XYZIRT),打印点。 | rviz输出的点不包括(或包括)ring和timestamp | + +## 2.2 rslidar_sdk连接点云的正确性 + +这里需要测试点云正确性的雷达包括:RS16/RS32/RSBP/RSHELIOS/RS80/RS128/RSM1。 + +这里的测试可以替代rs_driver中的测试。也就是说,可以用rslidar_sdk+rviz替代rs_driver_viewer。 + +| 级别 | 功能步骤简要说明 | 期望结果 | +|:------:|:--------------------------------------------------------|:------------------------------:| +| P2 | 用rslidar_sdk依次连接每种雷达,雷达工作在单回波模式下 | rviz正常显示点云 | +| P2 | 用rslidar_sdk依次连接每种雷达,雷达工作在双回波模式下 | rviz正常显示点云 | + +## 2.3 rslidar_sdk连接在线雷达 + +| 级别 | 功能步骤简要说明 | 期望结果 | +|:------:|:--------------------------------------------------------|:------------------------------:| +| P1 | 用rslidar_sdk连接在线雷达,雷达工作在广播模式下, | rviz正常显示点云 | +| P2 | 用rslidar_sdk连接在线雷达,雷达工作在组播模式下 | rviz正常显示点云 | +| P2 | 用rslidar_sdk连接在线雷达,雷达工作在单播模式下 | rviz正常显示点云 | +| P2 | 用rslidar_sdk连接在线雷达,雷达包带USER_LAYER | rviz正常显示点云 | +| P2 | 用rslidar_sdk连接在线雷达,雷达包带TAIL_LAYER | rviz正常显示点云 | +| P2 | 启动两个雷达实例,连接两台雷达,雷达指定不同目标端口、相同目标IP | rviz正常显示两个(可能是叠加的)点云 | +| P2 | 启动两个雷达实例,连接两台雷达,雷达指定相同目标端口、不同目标IP | rviz正常显示两个(可能是叠加的)点云 | +| P2 | 用rslidar_sdk连接在线雷达,雷达不做时间同步,user_lidar_clock=true(或false),查看点的时间戳 | 时间戳是雷达时间(或主机时间) | +| P2 | 用rslidar_sdk连接在线雷达,dense_points = true(或false) | rviz正常显示点云 | +| P3 | 用rslidar_sdk连接在线雷达,设置错误的DIFOP端口,wait_for_difop=false | rviz显示扁平点云 | +| P3 | 用rslidar_sdk接在线雷达,设置错误的DIFOP端口,wait_for_difop=true | rviz不显示点云 | +| P2 | 用rslidar_sdk连接在线雷达,config_from_file=true,angle_path=angle.csv | rviz正常显示(非扁平的)点云 | +| P2 | 用rslidar_sdk连接在线雷达,split_frame_mode=by_angle,split_angle=0/90/180/270 | rviz正常显示点云 | +| P3 | 用rslidar_sdk连接在线雷达,split_frame_mode=by_fixed_pkts,num_pkts_split=N | rviz显示点云 | +| P3 | 用rslidar_sdk连接在线雷达,split_frame_mode=by_custome_pkts | rviz显示点云 | +| P3 | 用rslidar_sdk连接在线雷达,start_angle=90, end_angle=180 | rviz显示半圈的点云 | +| P3 | 用rslidar_sdk连接在线雷达,min_distance=1, end_angle=10 | rviz显示被裁剪的点云 | + +## 2.4 rslidar_sdk解析PCAP文件 +| 级别 | 功能步骤简要说明 | 期望结果 | +|:------:|:--------------------------------------------------------|:------------------------------:| +| P2 | 用rslidar_sdk解析PCAP文件 | rviz正常打印点云 | +| P3 | 用rslidar_sdk解析PCAP文件, PCAP的包带VLAN层 | rviz正常打印点云 | +| P3 | 用rslidar_sdk解析PCAP文件, pcap_repeat=true(或false) | 循环播放PCAP中的点云(或播放一遍退出) | +| P3 | 用rslidar_sdk解析PCAP文件, pcap_rate=0.5/1/2 | 点云播放速度变慢(或正常播放、加快) | + +## 2.5 其他功能 + +| 级别 | 功能步骤简要说明 | 期望结果 | +|:------:|:--------------------------------------------------------|:------------------------------:| +| P2 | 用rslidar_sdk连接在线雷达,录制Packet rosbag;再用rslidar_sdk从Packet rosbag读入Packet,输出点云。| rviz正确显示点云 | +| P2 | 用rslidar_sdk连接在线雷达,ENABLE_TRASFORM=TRUE,设置转换参数。 | 显示的点云坐标变换正确 | + +## 3 性能测试 + +## 3.1 针对工控机 + +在当下主流性能的工控机上,做如下测试。 + +| 级别 | 功能步骤简要说明 | 期望结果 | +|:------:|:--------------------------------------------------------|:------------------------------:| +| P2 | 用rslidar_sdk连接在线的RSHELIOS/RS128/RSM1雷达,测试rslidar_sdk的CPU占用率 | 低于期望值(值待定) | +| P2 | rslidar_sdk启动两个雷达实例,连接两个在线的RSHELIOS/RS128/RSM1雷达,测试rslidar_sdk的CPU占用率 | 低于期望值(值待定) | + + From 4867f52bc7a4afedcb1b8e7db6ebf37b0d67db9f Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 25 Mar 2022 09:36:37 +0800 Subject: [PATCH 128/261] feat: support m2 --- config/config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 0c132002..18b5ae9c 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -9,10 +9,10 @@ common: send_point_cloud_ros: true #true: Send point cloud through ROS or ROS2 send_packet_proto: false #true: Send packets through Protobuf-UDP send_point_cloud_proto: false #true: Send point cloud through Protobuf-UDP - pcap_path: /home/robosense/lidar.pcap #The path of pcap file + pcap_path: /home/sti/dev/share/pcap/M2/M2.pcap #The path of pcap file lidar: - driver: - lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RS128, RS80, RSM1, RSHELIOS + lidar_type: RSM2 #LiDAR type - RS16, RS32, RSBP, RS128, RS80, RSM1, RSM2, RSHELIOS frame_id: /rslidar #Frame id of message msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar From cc64aa4e58f38f99092ffa16c6f3fd58dd7852a7 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 25 Mar 2022 17:27:31 +0800 Subject: [PATCH 129/261] feat: add macro to enable publish raw messages --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 21e0adfe..bd3d8a71 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,11 @@ if(${ENABLE_PCAP_PARSE}) add_definitions("-DENABLE_PCAP_PARSE") endif(${ENABLE_PCAP_PARSE}) +option(ENABLE_PUBLISH_RAW_MSG "Enable Publish Raw Message" ON) +if(${ENABLE_PUBLISH_RAW_MSG}) +add_definitions(-D ENABLE_PUBLISH_RAW_MSG) +endif(${ENABLE_PUBLISH_RAW_MSG}) + #======================== # Project details / setup #======================== @@ -112,7 +117,6 @@ endif(${COMPILE_METHOD} STREQUAL "CATKIN") #Include directory# include_directories(${PROJECT_SOURCE_DIR}/src) #Driver core# -#add_definitions(-DENABLE_PUBLISH_RAW_MSG) add_subdirectory(src/rs_driver) find_package(rs_driver REQUIRED) include_directories(${rs_driver_INCLUDE_DIRS}) From b2d39de9c46f42b46dcc848d9e7619db1afbbb8a Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 29 Mar 2022 18:32:02 +0800 Subject: [PATCH 130/261] feat: sync to rs_driver --- .gitmodules | 2 +- src/rs_driver | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index b7a6d10f..b841f4eb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "src/rs_driver"] path = src/rs_driver - url = git@192.168.1.20:rs_share/rs_driver.git + url = git@gitlab.robosense.cn:rs_share/rslidar/rs_driver.git branch = dev_opt diff --git a/src/rs_driver b/src/rs_driver index 8f5f62b2..828f9c28 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 8f5f62b21ef342dda037ccd18412bc3e0634d305 +Subproject commit 828f9c2836265e253d6037e8bda7be1f063f4575 From 72a93cbdc873b61fed9c41581ad35cd6c42e2820 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 31 Mar 2022 15:16:32 +0800 Subject: [PATCH 131/261] feat: add option ENABLE_RECVMMSG --- CMakeLists.txt | 9 +++++++-- src/rs_driver | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bd3d8a71..472f4664 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ project(rslidar_sdk) #======================================= # Compile setup (ORIGINAL, CATKIN, COLCON) #======================================= -set(COMPILE_METHOD CATKIN) +set(COMPILE_METHOD COLCON) #======================================= # Custom Point Type (XYZI, XYZIRT) @@ -17,11 +17,16 @@ if(${ENABLE_PCAP_PARSE}) add_definitions("-DENABLE_PCAP_PARSE") endif(${ENABLE_PCAP_PARSE}) -option(ENABLE_PUBLISH_RAW_MSG "Enable Publish Raw Message" ON) +option(ENABLE_PUBLISH_RAW_MSG "Enable Publish Raw Message" OFF) if(${ENABLE_PUBLISH_RAW_MSG}) add_definitions(-D ENABLE_PUBLISH_RAW_MSG) endif(${ENABLE_PUBLISH_RAW_MSG}) +option(ENABLE_RECVMMSG "Enable recvmmsg() to receive MSOP message" ON) +if(${ENABLE_RECVMMSG}) + add_definitions("-DENABLE_RECVMMSG") +endif(${ENABLE_RECVMMSG}) + #======================== # Project details / setup #======================== diff --git a/src/rs_driver b/src/rs_driver index 828f9c28..d8be85ae 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 828f9c2836265e253d6037e8bda7be1f063f4575 +Subproject commit d8be85ae5fc7140991e904576d9be417215b46bd From 569e9091888504bebc9d46ddcdfbc9c8981edd10 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 1 Apr 2022 11:58:21 +0800 Subject: [PATCH 132/261] feat: update maintainer and version --- package_ros1.xml | 6 +++--- package_ros2.xml | 4 ++-- src/rs_driver | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package_ros1.xml b/package_ros1.xml index accbc186..83f31d47 100644 --- a/package_ros1.xml +++ b/package_ros1.xml @@ -1,9 +1,9 @@ rslidar_sdk - 1.3.0 + 1.5.0 The rslidar_sdk package - robosense + robosense BSD catkin @@ -14,4 +14,4 @@ roscpp sensor_msgs roslib - \ No newline at end of file + diff --git a/package_ros2.xml b/package_ros2.xml index 8682ce49..c342eec4 100644 --- a/package_ros2.xml +++ b/package_ros2.xml @@ -1,9 +1,9 @@ rslidar_sdk - 1.3.0 + 1.5.0 The rslidar_sdk package - robosense + robosense BSD ament_cmake diff --git a/src/rs_driver b/src/rs_driver index 825fdd5b..70bfcc3e 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 825fdd5b587884f71d67fdafe6f8e8a6c2d6332f +Subproject commit 70bfcc3e53bdc242cfaf08830087c68b6a2d1534 From 483a111d1287237f0cb6378c81fca0884a586316 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 7 Apr 2022 10:41:20 +0800 Subject: [PATCH 133/261] feat: support ruby_plus --- config/config.yaml | 2 +- src/rs_driver | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 2b611927..caeda4ca 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -7,7 +7,7 @@ common: send_point_cloud_ros: true #true: Send point cloud through ROS or ROS2 lidar: - driver: - lidar_type: RS32 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RS80, RS128, RSM1 + lidar_type: RS32 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RS128, RS80, RSRUBY_PLUS, RSM1 msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar start_angle: 0 #Start angle of point cloud diff --git a/src/rs_driver b/src/rs_driver index 70bfcc3e..245ab0f4 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 70bfcc3e53bdc242cfaf08830087c68b6a2d1534 +Subproject commit 245ab0f4a04362ca64505e9de02b14ca3555ce87 From 0139f96715eb78e86127da31c6b9c0725e329eb7 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 7 Apr 2022 18:48:57 +0800 Subject: [PATCH 134/261] feat: support rshelios_16p --- config/config.yaml | 2 +- src/rs_driver | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index caeda4ca..531258b0 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -7,7 +7,7 @@ common: send_point_cloud_ros: true #true: Send point cloud through ROS or ROS2 lidar: - driver: - lidar_type: RS32 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RS128, RS80, RSRUBY_PLUS, RSM1 + lidar_type: RS32 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RSHELIOS_16P, RS128, RS80, RSRUBY_PLUS, RSM1 msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar start_angle: 0 #Start angle of point cloud diff --git a/src/rs_driver b/src/rs_driver index 245ab0f4..3f301b41 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 245ab0f4a04362ca64505e9de02b14ca3555ce87 +Subproject commit 3f301b4134405b19a2dbea44a3cd39c4f61744c7 From b8470420565ce929080be0209cf478fe8de4124c Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 14 Apr 2022 17:19:29 +0800 Subject: [PATCH 135/261] feat: sync to rs_driver --- CMakeLists.txt | 2 +- config/config.yaml | 4 ++-- src/rs_driver | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 472f4664..62b59035 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ project(rslidar_sdk) #======================================= # Compile setup (ORIGINAL, CATKIN, COLCON) #======================================= -set(COMPILE_METHOD COLCON) +set(COMPILE_METHOD CATKIN) #======================================= # Custom Point Type (XYZI, XYZIRT) diff --git a/config/config.yaml b/config/config.yaml index 18b5ae9c..bfe16c37 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -9,10 +9,10 @@ common: send_point_cloud_ros: true #true: Send point cloud through ROS or ROS2 send_packet_proto: false #true: Send packets through Protobuf-UDP send_point_cloud_proto: false #true: Send point cloud through Protobuf-UDP - pcap_path: /home/sti/dev/share/pcap/M2/M2.pcap #The path of pcap file + pcap_path: /home/robosense/lidar.pcap #The path of pcap file lidar: - driver: - lidar_type: RSM2 #LiDAR type - RS16, RS32, RSBP, RS128, RS80, RSM1, RSM2, RSHELIOS + lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RS128, RS80, RSM1, RSM2, RSHELIOS frame_id: /rslidar #Frame id of message msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar diff --git a/src/rs_driver b/src/rs_driver index d8be85ae..354058d5 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit d8be85ae5fc7140991e904576d9be417215b46bd +Subproject commit 354058d5c983fcd7bbf36e2f1919280a44bf541f From 69554aeb13b64c7caf353ddda9028aafc5a77a14 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 15 Apr 2022 15:23:22 +0800 Subject: [PATCH 136/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 3f301b41..0a252df3 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 3f301b4134405b19a2dbea44a3cd39c4f61744c7 +Subproject commit 0a252df320c602f0e916274f321ee266580062a5 From 5ae813e22ee05475f32e6c19d03f2282759f2b58 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 21 Apr 2022 19:14:15 +0800 Subject: [PATCH 137/261] feat: tag v1.4.6 --- CHANGELOG.md | 6 ++++++ src/rs_driver | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 314b7170..1d5c68bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v1.4.6 + +### Added + - support user_layer_bytes and tail_layer_bytes + - support M2 + ## v1.4.0 ### Updated diff --git a/src/rs_driver b/src/rs_driver index 354058d5..76013bdb 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 354058d5c983fcd7bbf36e2f1919280a44bf541f +Subproject commit 76013bdb78d07af11a29da8fcdd27fe15cddcee8 From 160610aa95b5e0fc6d16d3ea7c972a3757769bc0 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 21 Apr 2022 20:55:52 +0800 Subject: [PATCH 138/261] fix: fix frame_id --- src/source/source_pointcloud_ros.hpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/source/source_pointcloud_ros.hpp b/src/source/source_pointcloud_ros.hpp index f9e84a95..65fc3269 100644 --- a/src/source/source_pointcloud_ros.hpp +++ b/src/source/source_pointcloud_ros.hpp @@ -99,11 +99,11 @@ namespace robosense namespace lidar { -inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) +inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const std::string& frame_id) { sensor_msgs::msg::PointCloud2 ros_msg; pcl::toROSMsg(rs_msg, ros_msg); - ros_msg.header.frame_id = rs_msg.frame_id; + ros_msg.header.frame_id = frame_id; ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); ros_msg.header.stamp.nanosec = (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); @@ -121,10 +121,14 @@ class DestinationPointCloudRos : virtual public DestinationPointCloud private: std::shared_ptr node_ptr_; rclcpp::Publisher::SharedPtr pub_; + std::string frame_id_; }; inline void DestinationPointCloudRos::init(const YAML::Node& config) { + yamlRead(config["ros"], + "ros_frame_id", frame_id_, "/rslidar"); + std::string ros_send_topic; yamlRead(config["ros"], "ros_send_point_cloud_topic", ros_send_topic, "rslidar_points"); @@ -135,7 +139,7 @@ inline void DestinationPointCloudRos::init(const YAML::Node& config) inline void DestinationPointCloudRos::sendPointCloud(const LidarPointCloudMsg& msg) { - pub_->publish(toRosMsg(msg)); + pub_->publish(toRosMsg(msg, frame_id_)); } } // namespace lidar From fe042323ccf3cb9628e754d897e2ba00046777a0 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 22 Apr 2022 12:16:58 +0800 Subject: [PATCH 139/261] feat: support M2 --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 2536e977..b9333ac9 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 2536e97787a3fa40a5d0c6d033b4fbb5f1c84470 +Subproject commit b9333ac9ab90b1257ec730dd44d4aae255527c7b From 5066e833c64b6b363ad8cda76d0b26de8df30b5c Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 22 Apr 2022 14:40:37 +0800 Subject: [PATCH 140/261] feat: disable recvmmsg() --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e4fdc0c8..9b87cacf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ if(${ENABLE_PUBLISH_RAW_MSG}) add_definitions(-D ENABLE_PUBLISH_RAW_MSG) endif(${ENABLE_PUBLISH_RAW_MSG}) -option(ENABLE_RECVMMSG "Enable recvmmsg() to receive MSOP message" ON) +option(ENABLE_RECVMMSG "Enable recvmmsg() to receive MSOP message" OFF) if(${ENABLE_RECVMMSG}) add_definitions("-DENABLE_RECVMMSG") endif(${ENABLE_RECVMMSG}) From 437ecca327391091a172580e0134f06b336fc952 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Sun, 24 Apr 2022 11:24:22 +0800 Subject: [PATCH 141/261] feat: sync to rs_driver --- CMakeLists.txt | 5 ----- config/config.yaml | 4 ++-- src/rs_driver | 2 +- src/source/source_driver.hpp | 2 ++ 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b87cacf..8a738274 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,11 +20,6 @@ if(${ENABLE_PCAP_PARSE}) add_definitions("-DENABLE_PCAP_PARSE") endif(${ENABLE_PCAP_PARSE}) -option(ENABLE_PUBLISH_RAW_MSG "Enable Publish Raw Message" OFF) -if(${ENABLE_PUBLISH_RAW_MSG}) -add_definitions(-D ENABLE_PUBLISH_RAW_MSG) -endif(${ENABLE_PUBLISH_RAW_MSG}) - option(ENABLE_RECVMMSG "Enable recvmmsg() to receive MSOP message" OFF) if(${ENABLE_RECVMMSG}) add_definitions("-DENABLE_RECVMMSG") diff --git a/config/config.yaml b/config/config.yaml index 601d1e91..429dd82b 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -1,5 +1,5 @@ common: - msg_source: 3 #0: not use Lidar + msg_source: 1 #0: not use Lidar #1: packet message comes from online Lidar #2: packet message comes from ROS or ROS2 #3: packet message comes from Pcap file @@ -7,7 +7,7 @@ common: send_point_cloud_ros: true #true: Send point cloud through ROS or ROS2 lidar: - driver: - lidar_type: RS32 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RSHELIOS_16P, RS128, RS80, RSRUBY_PLUS, RSM1, RSM2 + lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RSHELIOS_16P, RS128, RS80, RSRUBY_PLUS, RSM1, RSM2 msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar start_angle: 0 #Start angle of point cloud diff --git a/src/rs_driver b/src/rs_driver index b9333ac9..f1d85b03 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit b9333ac9ab90b1257ec730dd44d4aae255527c7b +Subproject commit f1d85b037ee015b0d316d650c33fde82a2d9ddb6 diff --git a/src/source/source_driver.hpp b/src/source/source_driver.hpp index 6047c42c..17ce261f 100644 --- a/src/source/source_driver.hpp +++ b/src/source/source_driver.hpp @@ -87,6 +87,8 @@ inline void SourceDriver::init(const YAML::Node& config) yamlRead(driver_config, "pcap_path", driver_param.input_param.pcap_path, ""); yamlRead(driver_config, "pcap_rate", driver_param.input_param.pcap_rate, 1); yamlRead(driver_config, "pcap_repeat", driver_param.input_param.pcap_repeat, false); + yamlRead(driver_config, "user_layer_bytes", driver_param.input_param.user_layer_bytes, 0); + yamlRead(driver_config, "tail_layer_bytes", driver_param.input_param.tail_layer_bytes, 0); // decoder related std::string lidar_type; From 68b53d8182bb8b6c7f1f54d85f68bb293d3ddc11 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 25 Apr 2022 09:59:48 +0800 Subject: [PATCH 142/261] sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index f1d85b03..95e02ba2 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit f1d85b037ee015b0d316d650c33fde82a2d9ddb6 +Subproject commit 95e02ba2d4dc5a13ddea48e21704fbc3c4d976ef From b8308c13845b1b3bc6a17cbb3891bbc9207caea4 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 25 Apr 2022 10:09:49 +0800 Subject: [PATCH 143/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 95e02ba2..0852ac08 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 95e02ba2d4dc5a13ddea48e21704fbc3c4d976ef +Subproject commit 0852ac084d523cd21e8c5e4681a6964df2f691c3 From 0d27b89683876209433c825cc83792dc9d414ffd Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 27 Apr 2022 15:11:06 +0800 Subject: [PATCH 144/261] feat: sync to rs_driver --- src/rs_driver | 2 +- src/source/source_packet_ros.hpp | 4 ++-- src/source/source_pointcloud_ros.hpp | 4 ++-- src/utility/common.hpp | 6 +----- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/rs_driver b/src/rs_driver index 0852ac08..e5628f63 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 0852ac084d523cd21e8c5e4681a6964df2f691c3 +Subproject commit e5628f639927adbbf9efc1d3db5c3248702f247d diff --git a/src/source/source_packet_ros.hpp b/src/source/source_packet_ros.hpp index a5e33569..fdfda8f7 100644 --- a/src/source/source_packet_ros.hpp +++ b/src/source/source_packet_ros.hpp @@ -132,7 +132,7 @@ class DestinationPacketRos : public DestinationPacket inline void DestinationPacketRos::init(const YAML::Node& config) { yamlRead(config["ros"], - "ros_frame_id", frame_id_, "/rslidar"); + "ros_frame_id", frame_id_, "rslidar"); std::string ros_send_topic; yamlRead(config["ros"], "ros_send_packet_topic", @@ -251,7 +251,7 @@ class DestinationPacketRos : public DestinationPacket inline void DestinationPacketRos::init(const YAML::Node& config) { yamlRead(config["ros"], - "ros_frame_id", frame_id_, "/rslidar"); + "ros_frame_id", frame_id_, "rslidar"); std::string ros_send_topic; yamlRead(config["ros"], "ros_send_packet_topic", diff --git a/src/source/source_pointcloud_ros.hpp b/src/source/source_pointcloud_ros.hpp index 65fc3269..f75f46b7 100644 --- a/src/source/source_pointcloud_ros.hpp +++ b/src/source/source_pointcloud_ros.hpp @@ -71,7 +71,7 @@ class DestinationPointCloudRos : public DestinationPointCloud inline void DestinationPointCloudRos::init(const YAML::Node& config) { yamlRead(config["ros"], - "ros_frame_id", frame_id_, "/rslidar"); + "ros_frame_id", frame_id_, "rslidar"); std::string ros_send_topic; yamlRead(config["ros"], @@ -127,7 +127,7 @@ class DestinationPointCloudRos : virtual public DestinationPointCloud inline void DestinationPointCloudRos::init(const YAML::Node& config) { yamlRead(config["ros"], - "ros_frame_id", frame_id_, "/rslidar"); + "ros_frame_id", frame_id_, "rslidar"); std::string ros_send_topic; yamlRead(config["ros"], diff --git a/src/utility/common.hpp b/src/utility/common.hpp index 03a814c8..fa96c83c 100644 --- a/src/utility/common.hpp +++ b/src/utility/common.hpp @@ -32,8 +32,4 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#include "rs_driver/common/common_header.hpp" -//#include "utility/time.hpp" -//#include "utility/thread_pool.hpp" -//#include "lock_queue.hpp" - +#include "rs_driver/common/rs_log.hpp" From 49c4332555caee3cc0bccbfa93b67a811fbd89dc Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 28 Apr 2022 12:14:56 +0800 Subject: [PATCH 145/261] fix: fix frame_id to rslidar --- config/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.yaml b/config/config.yaml index 429dd82b..6c23fc71 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -19,7 +19,7 @@ lidar: #False-- Use the system clock as the timestamp pcap_path: /home/robosense/lidar.pcap #The path of pcap file ros: - ros_frame_id: /rslidar #Frame id of packet message and point cloud message + ros_frame_id: rslidar #Frame id of packet message and point cloud message ros_recv_packet_topic: /rslidar_packets #Topic used to receive lidar packets from ROS ros_send_packet_topic: /rslidar_packets #Topic used to send lidar packets through ROS ros_send_point_cloud_topic: /rslidar_points #Topic used to send point cloud through ROS From a1cd3a7967ba335afe6a4d4d6e393e3b7be6b457 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 28 Apr 2022 14:36:26 +0800 Subject: [PATCH 146/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index e5628f63..79dd719d 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit e5628f639927adbbf9efc1d3db5c3248702f247d +Subproject commit 79dd719d29b9572f9435c1cde60a0ebce6f1aa98 From fef639357c63ea1bb8a19e7c2e22246263efe4ea Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 28 Apr 2022 14:52:45 +0800 Subject: [PATCH 147/261] feat: sync to rs_driver --- doc/test_cases/rsliar_sdk_test_case.md | 83 -------------------------- src/rs_driver | 2 +- 2 files changed, 1 insertion(+), 84 deletions(-) delete mode 100644 doc/test_cases/rsliar_sdk_test_case.md diff --git a/doc/test_cases/rsliar_sdk_test_case.md b/doc/test_cases/rsliar_sdk_test_case.md deleted file mode 100644 index 7eea79f9..00000000 --- a/doc/test_cases/rsliar_sdk_test_case.md +++ /dev/null @@ -1,83 +0,0 @@ -**rslidar_sdk 测试用例** - -## 1 简介 - -这里的测试都在Ubuntu20.04系统和ROS/ROS2下进行。 - -测试用例级别: -+ P1 基本功能。失败将导致多数重要功能无法运行。 -+ P2 重要功能。系统中主要特性,失败则无法使用该特性。 -+ P3 可选功能。系统中次要特性,失败无法使用该特性。 - -## 2 功能测试 - -### 2.1 rslidar_sdk编译 - -| 级别 | 功能步骤简要说明 | 期望结果 | -|:------:|:--------------------------------------------------------|:--------------:| -| P1 | ROS1下,直接编译rsldiar_sdk | 编译成功 | -| P1 | ROS1下,catkin_make方式直接编译rsldiar_sdk | 编译成功 | -| P1 | ROS2下,colcon build方式编译rsldiar_sdk | 编译成功 | -| P1 | 用rsliar_sdk连接在线雷达 | rviz显示点云 | -| P1 | 用rslidar_sdk连接在线雷达,点为XYZI(或XYZIRT),打印点。 | rviz输出的点不包括(或包括)ring和timestamp | - -## 2.2 rslidar_sdk连接点云的正确性 - -这里需要测试点云正确性的雷达包括:RS16/RS32/RSBP/RSHELIOS/RS80/RS128/RSM1。 - -这里的测试可以替代rs_driver中的测试。也就是说,可以用rslidar_sdk+rviz替代rs_driver_viewer。 - -| 级别 | 功能步骤简要说明 | 期望结果 | -|:------:|:--------------------------------------------------------|:------------------------------:| -| P2 | 用rslidar_sdk依次连接每种雷达,雷达工作在单回波模式下 | rviz正常显示点云 | -| P2 | 用rslidar_sdk依次连接每种雷达,雷达工作在双回波模式下 | rviz正常显示点云 | - -## 2.3 rslidar_sdk连接在线雷达 - -| 级别 | 功能步骤简要说明 | 期望结果 | -|:------:|:--------------------------------------------------------|:------------------------------:| -| P1 | 用rslidar_sdk连接在线雷达,雷达工作在广播模式下, | rviz正常显示点云 | -| P2 | 用rslidar_sdk连接在线雷达,雷达工作在组播模式下 | rviz正常显示点云 | -| P2 | 用rslidar_sdk连接在线雷达,雷达工作在单播模式下 | rviz正常显示点云 | -| P2 | 用rslidar_sdk连接在线雷达,雷达包带USER_LAYER | rviz正常显示点云 | -| P2 | 用rslidar_sdk连接在线雷达,雷达包带TAIL_LAYER | rviz正常显示点云 | -| P2 | 启动两个雷达实例,连接两台雷达,雷达指定不同目标端口、相同目标IP | rviz正常显示两个(可能是叠加的)点云 | -| P2 | 启动两个雷达实例,连接两台雷达,雷达指定相同目标端口、不同目标IP | rviz正常显示两个(可能是叠加的)点云 | -| P2 | 用rslidar_sdk连接在线雷达,雷达不做时间同步,user_lidar_clock=true(或false),查看点的时间戳 | 时间戳是雷达时间(或主机时间) | -| P2 | 用rslidar_sdk连接在线雷达,dense_points = true(或false) | rviz正常显示点云 | -| P3 | 用rslidar_sdk连接在线雷达,设置错误的DIFOP端口,wait_for_difop=false | rviz显示扁平点云 | -| P3 | 用rslidar_sdk接在线雷达,设置错误的DIFOP端口,wait_for_difop=true | rviz不显示点云 | -| P2 | 用rslidar_sdk连接在线雷达,config_from_file=true,angle_path=angle.csv | rviz正常显示(非扁平的)点云 | -| P2 | 用rslidar_sdk连接在线雷达,split_frame_mode=by_angle,split_angle=0/90/180/270 | rviz正常显示点云 | -| P3 | 用rslidar_sdk连接在线雷达,split_frame_mode=by_fixed_pkts,num_pkts_split=N | rviz显示点云 | -| P3 | 用rslidar_sdk连接在线雷达,split_frame_mode=by_custome_pkts | rviz显示点云 | -| P3 | 用rslidar_sdk连接在线雷达,start_angle=90, end_angle=180 | rviz显示半圈的点云 | -| P3 | 用rslidar_sdk连接在线雷达,min_distance=1, end_angle=10 | rviz显示被裁剪的点云 | - -## 2.4 rslidar_sdk解析PCAP文件 -| 级别 | 功能步骤简要说明 | 期望结果 | -|:------:|:--------------------------------------------------------|:------------------------------:| -| P2 | 用rslidar_sdk解析PCAP文件 | rviz正常打印点云 | -| P3 | 用rslidar_sdk解析PCAP文件, PCAP的包带VLAN层 | rviz正常打印点云 | -| P3 | 用rslidar_sdk解析PCAP文件, pcap_repeat=true(或false) | 循环播放PCAP中的点云(或播放一遍退出) | -| P3 | 用rslidar_sdk解析PCAP文件, pcap_rate=0.5/1/2 | 点云播放速度变慢(或正常播放、加快) | - -## 2.5 其他功能 - -| 级别 | 功能步骤简要说明 | 期望结果 | -|:------:|:--------------------------------------------------------|:------------------------------:| -| P2 | 用rslidar_sdk连接在线雷达,录制Packet rosbag;再用rslidar_sdk从Packet rosbag读入Packet,输出点云。| rviz正确显示点云 | -| P2 | 用rslidar_sdk连接在线雷达,ENABLE_TRASFORM=TRUE,设置转换参数。 | 显示的点云坐标变换正确 | - -## 3 性能测试 - -## 3.1 针对工控机 - -在当下主流性能的工控机上,做如下测试。 - -| 级别 | 功能步骤简要说明 | 期望结果 | -|:------:|:--------------------------------------------------------|:------------------------------:| -| P2 | 用rslidar_sdk连接在线的RSHELIOS/RS128/RSM1雷达,测试rslidar_sdk的CPU占用率 | 低于期望值(值待定) | -| P2 | rslidar_sdk启动两个雷达实例,连接两个在线的RSHELIOS/RS128/RSM1雷达,测试rslidar_sdk的CPU占用率 | 低于期望值(值待定) | - - diff --git a/src/rs_driver b/src/rs_driver index 79dd719d..82f4edc7 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 79dd719d29b9572f9435c1cde60a0ebce6f1aa98 +Subproject commit 82f4edc7d11345f26b65d42866cc885334b94d7c From c10875434a94154c6cf3cf7072fcedb144d67301 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 28 Apr 2022 14:57:57 +0800 Subject: [PATCH 148/261] sync to rs_driver --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index b841f4eb..1fc75fd1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "src/rs_driver"] path = src/rs_driver - url = git@gitlab.robosense.cn:rs_share/rslidar/rs_driver.git + url = https://github.com/RoboSense-LiDAR/rs_driver.git branch = dev_opt From 54e79602529e3793a0b42e3550a76e11bb0577e1 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 28 Apr 2022 15:12:22 +0800 Subject: [PATCH 149/261] feat: update docs --- doc/src_intro/rslidar_sdk_intro.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/src_intro/rslidar_sdk_intro.md b/doc/src_intro/rslidar_sdk_intro.md index 28776fe2..f3073df9 100644 --- a/doc/src_intro/rslidar_sdk_intro.md +++ b/doc/src_intro/rslidar_sdk_intro.md @@ -1,4 +1,4 @@ -# rslidar_sdk 源代码解析 +# rslidar_sdk v1.5.1 源代码解析 rslidar_sdk是基于ROS的雷达驱动。rslidar_sdk依赖rs_driver接收和解析MSOP/DIFOP Packet。 @@ -68,7 +68,7 @@ DestinationPointCloudRos在ROS主题`/rslidar_points`发布点云。 init()初始化DestinationPointCloudRos实例。 + 从YAML文件读入用户配置参数。 - + 读入`frame_id`,保存在成员`frame_id_`,默认值是`/rslidar`。 + + 读入`frame_id`,保存在成员`frame_id_`,默认值是`rslidar`。 + 读入ROS主题,保存在本地变量`ros_send_topic_`,默认值是`/rslidar_points`。 + 创建ROS主题发布器,保存在成员`pkt_sub_`. @@ -89,7 +89,7 @@ DestinationPacketRos在ROS主题`/rslidar_packets`发布MSOP/DIFOP Packet。 init()初始化DestinationPacketRos实例。 + 从YAML文件读入用户配置参数。 - + 读入`frame_id`,保存在成员`frame_id_`,默认值是`/rslidar` + + 读入`frame_id`,保存在成员`frame_id_`,默认值是`rslidar` + 读入ROS主题,保存在本地变量`ros_send_topic_`,默认值是`/rslidar_packets`。 + 创建ROS主题发布器,保存在成员`pkt_sub_`. @@ -171,7 +171,7 @@ putPacket()接收Packet,送到`driver_ptr_`解析。 ## 9 NodeManager -NodeManager管理Source实例,包括创建、初始化、启动、停止Source。它多个源,但是这些源的类型必须相同。 +NodeManager管理Source实例,包括创建、初始化、启动、停止Source。它支持多个源,但是这些源的类型必须相同。 + 成员`sources_[]`是一个Source实例的数组。 ![node_manager](./img/class_node_manager.png) From 4544019b0a72697a4a7fd4712c5dc1c997e939f7 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 6 May 2022 18:18:44 +0800 Subject: [PATCH 150/261] feat: support rsp80,48 --- config/config.yaml | 2 +- src/rs_driver | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 6c23fc71..9422f242 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -7,7 +7,7 @@ common: send_point_cloud_ros: true #true: Send point cloud through ROS or ROS2 lidar: - driver: - lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RSHELIOS_16P, RS128, RS80, RSRUBY_PLUS, RSM1, RSM2 + lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RSHELIOS_16P, RS128, RS80, RSP128, RSP80, RSP48, RSM1, RSM2 msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar start_angle: 0 #Start angle of point cloud diff --git a/src/rs_driver b/src/rs_driver index 82f4edc7..8a35426b 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 82f4edc7d11345f26b65d42866cc885334b94d7c +Subproject commit 8a35426b8789600b679f354af68bee088edb39bb From 163d3f07b6501547b76ba59afcf328df71ab9b2f Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 10 May 2022 18:25:12 +0800 Subject: [PATCH 151/261] feat: sync to rs_driver --- config/config.yaml | 2 +- src/rs_driver | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 9422f242..0d2f16df 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -7,7 +7,7 @@ common: send_point_cloud_ros: true #true: Send point cloud through ROS or ROS2 lidar: - driver: - lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RSHELIOS_16P, RS128, RS80, RSP128, RSP80, RSP48, RSM1, RSM2 + lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RSHELIOS_16P, RS128, RS80, RSP128, RSP80, RSP48, RSM1, RSM2, RSEOS msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar start_angle: 0 #Start angle of point cloud diff --git a/src/rs_driver b/src/rs_driver index 8a35426b..09acdecc 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 8a35426b8789600b679f354af68bee088edb39bb +Subproject commit 09acdecc666e5e7aeb8f155a8a9929f718b94370 From b0a975b4f46c986a449f8f29c49fdea7b8a2ff0c Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 11 May 2022 11:55:37 +0800 Subject: [PATCH 152/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 09acdecc..02035dca 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 09acdecc666e5e7aeb8f155a8a9929f718b94370 +Subproject commit 02035dca42662f76a7416c970631b2c26c2f4485 From bf255313aa779eeb4208c75f7477658a68b5fc73 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 11 May 2022 12:05:43 +0800 Subject: [PATCH 153/261] feat: sync to rs_driver --- CHANGELOG.md | 28 +++++++++++++++++++++------- src/rs_driver | 2 +- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d5c68bd..389ad2f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,22 +1,36 @@ # Changelog +## Unreleased + +### Changed + +## v1.5.1 + +### Changed +- merge refactory code from v1.5.0 + +## v1.5.1 + +### Changed +- refactory the project + ## v1.4.6 ### Added - - support user_layer_bytes and tail_layer_bytes - - support M2 +- support user_layer_bytes and tail_layer_bytes +- support M2 ## v1.4.0 -### Updated - - replace point with point cloud, as rs_driver's template parameter - - handle point cloud in rs_driver's thread +### Changed +- replace point with point cloud, as rs_driver's template parameter +- handle point cloud in rs_driver's thread ## v1.3.1 ### Added - - add install command when building using catkin - - add use_vlan and use_someip support +- add install command when building using catkin +- add use_vlan and use_someip support ## v1.3.0 - 2020-11-10 diff --git a/src/rs_driver b/src/rs_driver index 02035dca..a73dc741 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 02035dca42662f76a7416c970631b2c26c2f4485 +Subproject commit a73dc74190bea3ae2adb83ba43fe6379835076c5 From 666a2912c6b76023a421d9da31d047ce77a31db2 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 11 May 2022 15:24:02 +0800 Subject: [PATCH 154/261] feat: output tight point cloud --- src/source/source_pointcloud_ros.hpp | 101 +++++++++++++++++++++------ 1 file changed, 80 insertions(+), 21 deletions(-) diff --git a/src/source/source_pointcloud_ros.hpp b/src/source/source_pointcloud_ros.hpp index f75f46b7..81031d3d 100644 --- a/src/source/source_pointcloud_ros.hpp +++ b/src/source/source_pointcloud_ros.hpp @@ -34,7 +34,86 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "source/source.hpp" -#include +#include + +inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const std::string& frame_id) +{ + sensor_msgs::msg::PointCloud2 ros_msg; + + int fields = 4; +#ifdef POINT_TYPE_XYZIRT + fields = 6; +#endif + ros_msg.fields.clear(); + ros_msg.fields.reserve(fields); + + int offset = 0; + offset = addPointField(ros_msg, "x", 1, sensor_msgs::msg::PointField::FLOAT32, offset); + offset = addPointField(ros_msg, "y", 1, sensor_msgs::msg::PointField::FLOAT32, offset); + offset = addPointField(ros_msg, "z", 1, sensor_msgs::msg::PointField::FLOAT32, offset); + offset = addPointField(ros_msg, "intensity", 1, sensor_msgs::msg::PointField::UINT8, offset); +#ifdef POINT_TYPE_XYZIRT + offset = addPointField(ros_msg, "ring", 1, sensor_msgs::msg::PointField::UINT16, offset); + offset = addPointField(ros_msg, "timestamp", 1, sensor_msgs::msg::PointField::FLOAT64, offset); +#endif + +#if 0 + std::cout << "off:" << offset << std::endl; +#endif + + ros_msg.point_step = offset; + ros_msg.width = rs_msg.height; + ros_msg.height = rs_msg.width; + ros_msg.row_step = ros_msg.width * ros_msg.point_step; + ros_msg.is_dense = rs_msg.is_dense; + + + ros_msg.data.resize(ros_msg.point_step * ros_msg.width * ros_msg.height); + + sensor_msgs::PointCloud2Iterator iter_x_(ros_msg, "x"); + sensor_msgs::PointCloud2Iterator iter_y_(ros_msg, "y"); + sensor_msgs::PointCloud2Iterator iter_z_(ros_msg, "z"); + sensor_msgs::PointCloud2Iterator iter_intensity_(ros_msg, "intensity"); +#ifdef POINT_TYPE_XYZIRT + sensor_msgs::PointCloud2Iterator iter_ring_(ros_msg, "ring"); + sensor_msgs::PointCloud2Iterator iter_timestamp_(ros_msg, "timestamp"); +#endif + + for (size_t i = 0; i < rs_msg.points.size(); i++) + { + const LidarPointCloudMsg::PointT& point = rs_msg.points[i]; + + *iter_x_ = point.x; + *iter_y_ = point.y; + *iter_z_ = point.z; + *iter_intensity_ = point.intensity; + + iter_x_ = iter_x_ + 1; + iter_y_ = iter_y_ + 1; + iter_z_ = iter_z_ + 1; + iter_intensity_ = iter_intensity_ + 1; + +#ifdef POINT_TYPE_XYZIRT + *iter_ring_ = point.ring; + *iter_timestamp_ = point.timestamp; + + iter_ring_ = iter_ring_ + 1; + iter_timestamp_ = iter_timestamp_ + 1; +#endif + } + + ros_msg.header.frame_id = frame_id; + +#ifdef ROS_FOUND + ros_msg.header.seq = rs_msg.seq; + ros_msg.header.stamp = ros_msg.header.stamp.fromSec(rs_msg.timestamp); +#elif ROS2_FOUND + ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); + ros_msg.header.stamp.nanosec = (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); +#endif + + return ros_msg; +} #ifdef ROS_FOUND #include @@ -44,16 +123,6 @@ namespace robosense namespace lidar { -inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const std::string& frame_id) -{ - sensor_msgs::PointCloud2 ros_msg; - pcl::toROSMsg(rs_msg, ros_msg); - ros_msg.header.stamp = ros_msg.header.stamp.fromSec(rs_msg.timestamp); - ros_msg.header.seq = rs_msg.seq; - ros_msg.header.frame_id = frame_id; - return ros_msg; -} - class DestinationPointCloudRos : public DestinationPointCloud { public: @@ -99,16 +168,6 @@ namespace robosense namespace lidar { -inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const std::string& frame_id) -{ - sensor_msgs::msg::PointCloud2 ros_msg; - pcl::toROSMsg(rs_msg, ros_msg); - ros_msg.header.frame_id = frame_id; - ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); - ros_msg.header.stamp.nanosec = - (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); - return ros_msg; -} class DestinationPointCloudRos : virtual public DestinationPointCloud { From e12439cacaf8a6a7c739b8f5ac82eaeb0356c347 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 11 May 2022 16:08:00 +0800 Subject: [PATCH 155/261] feat: use tight point cloud --- src/source/source_pointcloud_ros.hpp | 97 +++++++++++++++++++++++----- 1 file changed, 81 insertions(+), 16 deletions(-) diff --git a/src/source/source_pointcloud_ros.hpp b/src/source/source_pointcloud_ros.hpp index 81031d3d..cf530c22 100644 --- a/src/source/source_pointcloud_ros.hpp +++ b/src/source/source_pointcloud_ros.hpp @@ -34,7 +34,13 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "source/source.hpp" -#include +#ifdef ROS_FOUND +#include + +namespace robosense +{ +namespace lidar +{ inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const std::string& frame_id) { @@ -102,27 +108,13 @@ inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, #endif } - ros_msg.header.frame_id = frame_id; - -#ifdef ROS_FOUND ros_msg.header.seq = rs_msg.seq; ros_msg.header.stamp = ros_msg.header.stamp.fromSec(rs_msg.timestamp); -#elif ROS2_FOUND - ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); - ros_msg.header.stamp.nanosec = (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); -#endif + ros_msg.header.frame_id = frame_id; return ros_msg; } -#ifdef ROS_FOUND -#include - -namespace robosense -{ -namespace lidar -{ - class DestinationPointCloudRos : public DestinationPointCloud { public: @@ -162,12 +154,85 @@ inline void DestinationPointCloudRos::sendPointCloud(const LidarPointCloudMsg& m #ifdef ROS2_FOUND #include +#include namespace robosense { namespace lidar { +inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const std::string& frame_id) +{ + sensor_msgs::msg::PointCloud2 ros_msg; + + int fields = 4; +#ifdef POINT_TYPE_XYZIRT + fields = 6; +#endif + ros_msg.fields.clear(); + ros_msg.fields.reserve(fields); + + int offset = 0; + offset = addPointField(ros_msg, "x", 1, sensor_msgs::msg::PointField::FLOAT32, offset); + offset = addPointField(ros_msg, "y", 1, sensor_msgs::msg::PointField::FLOAT32, offset); + offset = addPointField(ros_msg, "z", 1, sensor_msgs::msg::PointField::FLOAT32, offset); + offset = addPointField(ros_msg, "intensity", 1, sensor_msgs::msg::PointField::UINT8, offset); +#ifdef POINT_TYPE_XYZIRT + offset = addPointField(ros_msg, "ring", 1, sensor_msgs::msg::PointField::UINT16, offset); + offset = addPointField(ros_msg, "timestamp", 1, sensor_msgs::msg::PointField::FLOAT64, offset); +#endif + +#if 0 + std::cout << "off:" << offset << std::endl; +#endif + + ros_msg.point_step = offset; + ros_msg.width = rs_msg.height; + ros_msg.height = rs_msg.width; + ros_msg.row_step = ros_msg.width * ros_msg.point_step; + ros_msg.is_dense = rs_msg.is_dense; + + + ros_msg.data.resize(ros_msg.point_step * ros_msg.width * ros_msg.height); + + sensor_msgs::PointCloud2Iterator iter_x_(ros_msg, "x"); + sensor_msgs::PointCloud2Iterator iter_y_(ros_msg, "y"); + sensor_msgs::PointCloud2Iterator iter_z_(ros_msg, "z"); + sensor_msgs::PointCloud2Iterator iter_intensity_(ros_msg, "intensity"); +#ifdef POINT_TYPE_XYZIRT + sensor_msgs::PointCloud2Iterator iter_ring_(ros_msg, "ring"); + sensor_msgs::PointCloud2Iterator iter_timestamp_(ros_msg, "timestamp"); +#endif + + for (size_t i = 0; i < rs_msg.points.size(); i++) + { + const LidarPointCloudMsg::PointT& point = rs_msg.points[i]; + + *iter_x_ = point.x; + *iter_y_ = point.y; + *iter_z_ = point.z; + *iter_intensity_ = point.intensity; + + iter_x_ = iter_x_ + 1; + iter_y_ = iter_y_ + 1; + iter_z_ = iter_z_ + 1; + iter_intensity_ = iter_intensity_ + 1; + +#ifdef POINT_TYPE_XYZIRT + *iter_ring_ = point.ring; + *iter_timestamp_ = point.timestamp; + + iter_ring_ = iter_ring_ + 1; + iter_timestamp_ = iter_timestamp_ + 1; +#endif + } + + ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); + ros_msg.header.stamp.nanosec = (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); + ros_msg.header.frame_id = frame_id; + + return ros_msg; +} class DestinationPointCloudRos : virtual public DestinationPointCloud { From 5b08d0f6b77cd7efc8432f2e7c496306f9647446 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 11 May 2022 16:19:04 +0800 Subject: [PATCH 156/261] feat: use tight point cloud --- src/source/source_pointcloud_ros.hpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/source/source_pointcloud_ros.hpp b/src/source/source_pointcloud_ros.hpp index cf530c22..f9f7c4ef 100644 --- a/src/source/source_pointcloud_ros.hpp +++ b/src/source/source_pointcloud_ros.hpp @@ -36,15 +36,16 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifdef ROS_FOUND #include +#include namespace robosense { namespace lidar { -inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const std::string& frame_id) +inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const std::string& frame_id) { - sensor_msgs::msg::PointCloud2 ros_msg; + sensor_msgs::PointCloud2 ros_msg; int fields = 4; #ifdef POINT_TYPE_XYZIRT @@ -54,13 +55,13 @@ inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, ros_msg.fields.reserve(fields); int offset = 0; - offset = addPointField(ros_msg, "x", 1, sensor_msgs::msg::PointField::FLOAT32, offset); - offset = addPointField(ros_msg, "y", 1, sensor_msgs::msg::PointField::FLOAT32, offset); - offset = addPointField(ros_msg, "z", 1, sensor_msgs::msg::PointField::FLOAT32, offset); - offset = addPointField(ros_msg, "intensity", 1, sensor_msgs::msg::PointField::UINT8, offset); + offset = addPointField(ros_msg, "x", 1, sensor_msgs::PointField::FLOAT32, offset); + offset = addPointField(ros_msg, "y", 1, sensor_msgs::PointField::FLOAT32, offset); + offset = addPointField(ros_msg, "z", 1, sensor_msgs::PointField::FLOAT32, offset); + offset = addPointField(ros_msg, "intensity", 1, sensor_msgs::PointField::UINT8, offset); #ifdef POINT_TYPE_XYZIRT - offset = addPointField(ros_msg, "ring", 1, sensor_msgs::msg::PointField::UINT16, offset); - offset = addPointField(ros_msg, "timestamp", 1, sensor_msgs::msg::PointField::FLOAT64, offset); + offset = addPointField(ros_msg, "ring", 1, sensor_msgs::PointField::UINT16, offset); + offset = addPointField(ros_msg, "timestamp", 1, sensor_msgs::PointField::FLOAT64, offset); #endif #if 0 From e5dbcc1de896c95ac28d2e018b51d32a981c3d04 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 11 May 2022 16:43:44 +0800 Subject: [PATCH 157/261] feat: remove pcl dependecies --- CMakeLists.txt | 7 ------- src/msg/rs_msg/lidar_point_cloud_msg.hpp | 2 +- src/source/source_pointcloud_ros.hpp | 2 -- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a738274..68c73aaf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -119,11 +119,6 @@ endif(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) #Others# find_package(yaml-cpp REQUIRED) -find_package(PCL QUIET REQUIRED) -include_directories(${PCL_INCLUDE_DIRS}) -link_directories(${PCL_LIBRARY_DIRS}) -add_definitions(${PCL_DEFINITIONS}) - #Catkin# if(${COMPILE_METHOD} STREQUAL "CATKIN") @@ -176,7 +171,6 @@ if(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) ${PROTO_FILE_PATH}/point_cloud.pb.cc ) target_link_libraries(rslidar_sdk_node - ${PCL_LIBRARIES} ${YAML_CPP_LIBRARIES} ${PROTOBUF_LIBRARY} ${rs_driver_LIBRARIES} @@ -188,7 +182,6 @@ else(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) node/rslidar_sdk_node.cpp src/manager/adapter_manager.cpp) target_link_libraries(rslidar_sdk_node - ${PCL_LIBRARIES} ${YAML_CPP_LIBRARIES} ${rs_driver_LIBRARIES}) diff --git a/src/msg/rs_msg/lidar_point_cloud_msg.hpp b/src/msg/rs_msg/lidar_point_cloud_msg.hpp index c41e7125..476ad4cb 100644 --- a/src/msg/rs_msg/lidar_point_cloud_msg.hpp +++ b/src/msg/rs_msg/lidar_point_cloud_msg.hpp @@ -32,7 +32,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#include "rs_driver/msg/pcl_point_cloud_msg.hpp" +#include "rs_driver/msg/point_cloud_msg.hpp" #ifdef POINT_TYPE_XYZIRT typedef PointCloudT LidarPointCloudMsg; diff --git a/src/source/source_pointcloud_ros.hpp b/src/source/source_pointcloud_ros.hpp index f9f7c4ef..d9cd175f 100644 --- a/src/source/source_pointcloud_ros.hpp +++ b/src/source/source_pointcloud_ros.hpp @@ -74,7 +74,6 @@ inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const ros_msg.row_step = ros_msg.width * ros_msg.point_step; ros_msg.is_dense = rs_msg.is_dense; - ros_msg.data.resize(ros_msg.point_step * ros_msg.width * ros_msg.height); sensor_msgs::PointCloud2Iterator iter_x_(ros_msg, "x"); @@ -193,7 +192,6 @@ inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, ros_msg.row_step = ros_msg.width * ros_msg.point_step; ros_msg.is_dense = rs_msg.is_dense; - ros_msg.data.resize(ros_msg.point_step * ros_msg.width * ros_msg.height); sensor_msgs::PointCloud2Iterator iter_x_(ros_msg, "x"); From ec4999f38260c8189987c3dcb426ab2c77836038 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 12 May 2022 10:33:57 +0800 Subject: [PATCH 158/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index a73dc741..74d9f774 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit a73dc74190bea3ae2adb83ba43fe6379835076c5 +Subproject commit 74d9f774dfbfe101d8cab2e8f35a277a7da3bfbc From a5ad906627ced3fab78a5a8d3bf9bc63d5f849b1 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 17 May 2022 09:49:02 +0800 Subject: [PATCH 159/261] fix: fix warning of duplicated node name --- src/source/source_packet_ros.hpp | 13 +++++++++++-- src/source/source_pointcloud_ros.hpp | 7 ++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/source/source_packet_ros.hpp b/src/source/source_packet_ros.hpp index fdfda8f7..2460be9e 100644 --- a/src/source/source_packet_ros.hpp +++ b/src/source/source_packet_ros.hpp @@ -155,6 +155,7 @@ inline void DestinationPacketRos::sendPacket(const Packet& msg) #ifdef ROS2_FOUND #include "rslidar_msg/msg/rslidar_packet.hpp" #include +#include namespace robosense { @@ -206,7 +207,11 @@ void SourcePacketRos::init(const YAML::Node& config) yamlRead(config["ros"], "ros_recv_packet_topic", ros_recv_topic, "rslidar_packets"); - node_ptr_.reset(new rclcpp::Node("rslidar_packets_adapter")); + static int node_index = 0; + std::stringstream node_name; + node_name << "rslidar_packets_source_" << node_index++; + + node_ptr_.reset(new rclcpp::Node(node_name.str())); pkt_sub_ = node_ptr_->create_subscription(ros_recv_topic, 10, std::bind(&SourcePacketRos::putPacket, this, std::placeholders::_1)); } @@ -257,7 +262,11 @@ inline void DestinationPacketRos::init(const YAML::Node& config) yamlRead(config["ros"], "ros_send_packet_topic", ros_send_topic, "rslidar_packets"); - node_ptr_.reset(new rclcpp::Node("rslidar_packets_adapter")); + static int node_index = 0; + std::stringstream node_name; + node_name << "rslidar_packets_destination_" << node_index++; + + node_ptr_.reset(new rclcpp::Node(node_name.str())); pkt_pub_ = node_ptr_->create_publisher(ros_send_topic, 10); } diff --git a/src/source/source_pointcloud_ros.hpp b/src/source/source_pointcloud_ros.hpp index d9cd175f..917cd0bf 100644 --- a/src/source/source_pointcloud_ros.hpp +++ b/src/source/source_pointcloud_ros.hpp @@ -155,6 +155,7 @@ inline void DestinationPointCloudRos::sendPointCloud(const LidarPointCloudMsg& m #ifdef ROS2_FOUND #include #include +#include namespace robosense { @@ -256,7 +257,11 @@ inline void DestinationPointCloudRos::init(const YAML::Node& config) yamlRead(config["ros"], "ros_send_point_cloud_topic", ros_send_topic, "rslidar_points"); - node_ptr_.reset(new rclcpp::Node("rslidar_points_adapter")); + static int node_index = 0; + std::stringstream node_name; + node_name << "rslidar_points_destination_" << node_index++; + + node_ptr_.reset(new rclcpp::Node(node_name.str())); pub_ = node_ptr_->create_publisher(ros_send_topic, 100); } From 197863cc880085ddbfc29753311db7d4e385f7d4 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 17 May 2022 14:14:34 +0800 Subject: [PATCH 160/261] feat: default pcap_repeat to true --- src/source/source_driver.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source/source_driver.hpp b/src/source/source_driver.hpp index 17ce261f..a0743a37 100644 --- a/src/source/source_driver.hpp +++ b/src/source/source_driver.hpp @@ -86,7 +86,7 @@ inline void SourceDriver::init(const YAML::Node& config) yamlRead(driver_config, "use_vlan", driver_param.input_param.use_vlan, false); yamlRead(driver_config, "pcap_path", driver_param.input_param.pcap_path, ""); yamlRead(driver_config, "pcap_rate", driver_param.input_param.pcap_rate, 1); - yamlRead(driver_config, "pcap_repeat", driver_param.input_param.pcap_repeat, false); + yamlRead(driver_config, "pcap_repeat", driver_param.input_param.pcap_repeat, true); yamlRead(driver_config, "user_layer_bytes", driver_param.input_param.user_layer_bytes, 0); yamlRead(driver_config, "tail_layer_bytes", driver_param.input_param.tail_layer_bytes, 0); From 8b1f9eec32b29598b790666d715d08e1c0a73d4c Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 18 May 2022 11:58:28 +0800 Subject: [PATCH 161/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 74d9f774..6570e0a5 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 74d9f774dfbfe101d8cab2e8f35a277a7da3bfbc +Subproject commit 6570e0a5276ae3fd9a655a5bde20cb6679ba4277 From 4e70e44a82a245187400f25be9f5d264c22e9978 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 19 May 2022 17:11:33 +0800 Subject: [PATCH 162/261] feat: tag v1.5.2 --- doc/src_intro/rslidar_sdk_intro.md | 4 ++-- src/rs_driver | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/src_intro/rslidar_sdk_intro.md b/doc/src_intro/rslidar_sdk_intro.md index f3073df9..a3ae630a 100644 --- a/doc/src_intro/rslidar_sdk_intro.md +++ b/doc/src_intro/rslidar_sdk_intro.md @@ -1,4 +1,4 @@ -# rslidar_sdk v1.5.1 源代码解析 +# rslidar_sdk v1.5.2 源代码解析 rslidar_sdk是基于ROS的雷达驱动。rslidar_sdk依赖rs_driver接收和解析MSOP/DIFOP Packet。 @@ -179,7 +179,7 @@ NodeManager管理Source实例,包括创建、初始化、启动、停止Source ### 9.1 NodeManager::init() init()初始化NodeManger实例。 -+ 从.yaml文件得到用户配置参数 ++ 从config.yaml文件得到用户配置参数 + 本地变量`msg_source`,数据源类型 + 本地变量`send_point_cloud_ros`, 是否在ROS主题发送点云。 + 本地变量`send_packet_ros`,是否在ROS主题发送MSOP/DIFOP packet, diff --git a/src/rs_driver b/src/rs_driver index 74d9f774..4f436918 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 74d9f774dfbfe101d8cab2e8f35a277a7da3bfbc +Subproject commit 4f43691839d9479f61f7957e77a803977b2f0cb8 From 3f25c69295ec1dca178a0bfd52ead4656ffee24a Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 25 May 2022 10:53:09 +0800 Subject: [PATCH 163/261] feat: add option to receive with epoll() --- CMakeLists.txt | 7 ++++++- src/rs_driver | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 68c73aaf..bf5cca4d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ project(rslidar_sdk) #======================================= # Compile setup (ORIGINAL, CATKIN, COLCON) #======================================= -set(COMPILE_METHOD CATKIN) +set(COMPILE_METHOD COLCON) #======================================= # Custom Point Type (XYZI, XYZIRT) @@ -20,6 +20,11 @@ if(${ENABLE_PCAP_PARSE}) add_definitions("-DENABLE_PCAP_PARSE") endif(${ENABLE_PCAP_PARSE}) +option(ENABLE_EPOLL_RECEIVE "Receive packets with epoll() instead of select()" OFF) +if(${ENABLE_EPOLL_RECEIVE}) + add_definitions("-DENABLE_EPOLL_RECEIVE") +endif(${ENABLE_EPOLL_RECEIVE}) + option(ENABLE_RECVMMSG "Enable recvmmsg() to receive MSOP message" OFF) if(${ENABLE_RECVMMSG}) add_definitions("-DENABLE_RECVMMSG") diff --git a/src/rs_driver b/src/rs_driver index 4f436918..d32b3e4d 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 4f43691839d9479f61f7957e77a803977b2f0cb8 +Subproject commit d32b3e4db21fa61b21244825d977445877cdd4dc From ec4306d21ba2930fc3875dfe7078d6c833107b59 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 25 May 2022 10:56:44 +0800 Subject: [PATCH 164/261] feat: add option to transform point --- CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index bf5cca4d..d0265422 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,14 @@ if(${ENABLE_PCAP_PARSE}) add_definitions("-DENABLE_PCAP_PARSE") endif(${ENABLE_PCAP_PARSE}) +option(ENABLE_TRANSFORM "Enable transform functions" OFF) +if(${ENABLE_TRANSFORM}) + add_definitions("-DENABLE_TRANSFORM") + + find_package(Eigen3 REQUIRED) + include_directories(${EIGEN3_INCLUDE_DIR}) +endif(${ENABLE_TRANSFORM}) + option(ENABLE_EPOLL_RECEIVE "Receive packets with epoll() instead of select()" OFF) if(${ENABLE_EPOLL_RECEIVE}) add_definitions("-DENABLE_EPOLL_RECEIVE") From ca3068189707b7141b2970c1d195424b183a660d Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 25 May 2022 11:11:13 +0800 Subject: [PATCH 165/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index d32b3e4d..c685538d 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit d32b3e4db21fa61b21244825d977445877cdd4dc +Subproject commit c685538da0658112733b7b6825636aa27b37cd80 From 5c6632356c01d61ea54e99adae4ae010009f9c49 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 25 May 2022 11:17:36 +0800 Subject: [PATCH 166/261] feat: update CHANGELOG --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 389ad2f8..1be5d7f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,17 @@ ### Changed +## v1.5.2 + +### Changed +- sync to rs_driver + ## v1.5.1 ### Changed - merge refactory code from v1.5.0 -## v1.5.1 +## v1.5.0 ### Changed - refactory the project From b56683d68fac155414231175fac2287ded69e13b Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 26 May 2022 11:38:36 +0800 Subject: [PATCH 167/261] feat: support jumbo mode --- config/config.yaml | 2 +- src/rs_driver | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 0d2f16df..2aa96463 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -7,7 +7,7 @@ common: send_point_cloud_ros: true #true: Send point cloud through ROS or ROS2 lidar: - driver: - lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RSHELIOS_16P, RS128, RS80, RSP128, RSP80, RSP48, RSM1, RSM2, RSEOS + lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RSHELIOS_16P, RS128, RS80, RSP128, RSP80, RSP48, RSM1, RSM2, RSEOS, RSM1_JUMBO msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar start_angle: 0 #Start angle of point cloud diff --git a/src/rs_driver b/src/rs_driver index c685538d..0e565949 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit c685538da0658112733b7b6825636aa27b37cd80 +Subproject commit 0e5659498b60f56d2e40c675a2e0fd7a0dd1b4ba From 2d69575555e1e3f5b98d0fddb189eafaa7c702a8 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 30 May 2022 20:27:45 +0800 Subject: [PATCH 168/261] feat: use ros as default --- .gitignore | 1 - CMakeLists.txt | 2 +- package.xml | 17 +++++++++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 package.xml diff --git a/.gitignore b/.gitignore index 01b13ecd..581c6ddb 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,3 @@ cmake-build-debug/ version.h *.pb.cc *.pb.h -package.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index d0265422..1e8ea5f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ project(rslidar_sdk) #======================================= # Compile setup (ORIGINAL, CATKIN, COLCON) #======================================= -set(COMPILE_METHOD COLCON) +set(COMPILE_METHOD CATKIN) #======================================= # Custom Point Type (XYZI, XYZIRT) diff --git a/package.xml b/package.xml new file mode 100644 index 00000000..83f31d47 --- /dev/null +++ b/package.xml @@ -0,0 +1,17 @@ + + + rslidar_sdk + 1.5.0 + The rslidar_sdk package + robosense + BSD + catkin + + roscpp + sensor_msgs + roslib + + roscpp + sensor_msgs + roslib + From 9a90008a740d735dcfa8d3037ee86fa000e73f8f Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 31 May 2022 10:02:26 +0800 Subject: [PATCH 169/261] fix: fix compiling error when protobuf is unavailable --- CMakeLists.txt | 2 +- src/rs_driver | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e8ea5f1..4946697b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -193,7 +193,7 @@ else(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) add_executable(rslidar_sdk_node node/rslidar_sdk_node.cpp - src/manager/adapter_manager.cpp) + src/manager/node_manager.cpp) target_link_libraries(rslidar_sdk_node ${YAML_CPP_LIBRARIES} ${rs_driver_LIBRARIES}) diff --git a/src/rs_driver b/src/rs_driver index 0e565949..b9d5eb7d 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 0e5659498b60f56d2e40c675a2e0fd7a0dd1b4ba +Subproject commit b9d5eb7d22e5d7384cd64ef5e41a7a0f39b17b98 From 5af026790cbff21351384870ae7b3b57a9127cdc Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 31 May 2022 10:50:13 +0800 Subject: [PATCH 170/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index b9d5eb7d..126e90ef 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit b9d5eb7d22e5d7384cd64ef5e41a7a0f39b17b98 +Subproject commit 126e90ef7f42fe4bc391bc700bc0caca6ce9b6c8 From e6fac20b136f5b217e0118b759f2d38efd49f44b Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 1 Jun 2022 14:25:05 +0800 Subject: [PATCH 171/261] feat: tag v1.5.3 --- CHANGELOG.md | 10 ++++++++-- src/rs_driver | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1be5d7f4..1aa207ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,17 @@ ## Unreleased -### Changed +## v1.5.3 + +### Added +- Support Jumbo Mode + +### Fixed +- Fix compiling error when protobuf is unavailable ## v1.5.2 -### Changed +### Added - sync to rs_driver ## v1.5.1 diff --git a/src/rs_driver b/src/rs_driver index 126e90ef..bbb9f2b6 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 126e90ef7f42fe4bc391bc700bc0caca6ce9b6c8 +Subproject commit bbb9f2b689585a8ef9292c4423d307b7e47715fd From 0bcd91facd7a012ebe0f5332d4d7ac6ecd3cd080 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 9 Jun 2022 12:11:02 +0800 Subject: [PATCH 172/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 68bbbdef..50f4a91d 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 68bbbdef9a4708c7ff117a346cf482ea0bab1bc9 +Subproject commit 50f4a91d12d59c27f576a0c89160603097de68ac From 15472e5a438d4f806e2daee90ad4a0d4e97eb690 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 13 Jun 2022 16:06:49 +0800 Subject: [PATCH 173/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 50f4a91d..265bc871 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 50f4a91d12d59c27f576a0c89160603097de68ac +Subproject commit 265bc871ed0948572dc0e4f9dda2312a009d2080 From 5970e69d9b6a82074d75a218e55b59c99052446d Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 15 Jun 2022 11:09:51 +0800 Subject: [PATCH 174/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 265bc871..5e50bbde 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 265bc871ed0948572dc0e4f9dda2312a009d2080 +Subproject commit 5e50bbde1fd5f87c27b89fdb0f1f29604fdb07fe From c43bd28f3f609575d0de35a734611e627aae1174 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 16 Jun 2022 10:57:16 +0800 Subject: [PATCH 175/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 5e50bbde..6447c4b4 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 5e50bbde1fd5f87c27b89fdb0f1f29604fdb07fe +Subproject commit 6447c4b44931a4b4e9dd3365c7101910b89772bb From 879b9c9c28afa4b29d41ea271c41e7140e7a5ff3 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 16 Jun 2022 11:47:44 +0800 Subject: [PATCH 176/261] feat: support rs48 --- config/config.yaml | 2 +- src/rs_driver | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 2aa96463..48422007 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -7,7 +7,7 @@ common: send_point_cloud_ros: true #true: Send point cloud through ROS or ROS2 lidar: - driver: - lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RSHELIOS_16P, RS128, RS80, RSP128, RSP80, RSP48, RSM1, RSM2, RSEOS, RSM1_JUMBO + lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RSHELIOS_16P, RS128, RS80, RS48, RSP128, RSP80, RSP48, RSM1, RSM2, RSEOS, RSM1_JUMBO msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar start_angle: 0 #Start angle of point cloud diff --git a/src/rs_driver b/src/rs_driver index 6447c4b4..83c1e14d 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 6447c4b44931a4b4e9dd3365c7101910b89772bb +Subproject commit 83c1e14d8d8f7f71d8669612d8c5820f4dc40941 From b589aafc2740f2e11aaf2534f9b9439627f4ed7f Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 24 Jun 2022 09:17:14 +0800 Subject: [PATCH 177/261] feat: sync to rs_driver --- CMakeLists.txt | 5 ----- src/rs_driver | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4946697b..9d880ff5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,11 +15,6 @@ set(COMPILE_METHOD CATKIN) #======================================= set(POINT_TYPE XYZI) -option(ENABLE_PCAP_PARSE "Enable PCAP file parse" ON) -if(${ENABLE_PCAP_PARSE}) - add_definitions("-DENABLE_PCAP_PARSE") -endif(${ENABLE_PCAP_PARSE}) - option(ENABLE_TRANSFORM "Enable transform functions" OFF) if(${ENABLE_TRANSFORM}) add_definitions("-DENABLE_TRANSFORM") diff --git a/src/rs_driver b/src/rs_driver index 83c1e14d..609051ec 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 83c1e14d8d8f7f71d8669612d8c5820f4dc40941 +Subproject commit 609051ec4a4a860f31ec51a7c377c920c4fbdab8 From 4ad2f0c09b824c2598335bf5797d16c84fc0865f Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 24 Jun 2022 11:22:14 +0800 Subject: [PATCH 178/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 609051ec..2886e718 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 609051ec4a4a860f31ec51a7c377c920c4fbdab8 +Subproject commit 2886e718360b2f9a6c9f1204b768394922639ec5 From 805e0154e715aec1180152d582d3761f2ca9ed79 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 24 Jun 2022 15:40:24 +0800 Subject: [PATCH 179/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 2886e718..a6f2e418 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 2886e718360b2f9a6c9f1204b768394922639ec5 +Subproject commit a6f2e41897cb8191f83c89f1142a85cfe80125fe From f1b19eda9d738582b0bea80459cefcabc6304857 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 27 Jun 2022 17:43:11 +0800 Subject: [PATCH 180/261] feat: support ts_first_point --- src/rs_driver | 2 +- src/source/source_driver.hpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index a6f2e418..aa40f943 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit a6f2e41897cb8191f83c89f1142a85cfe80125fe +Subproject commit aa40f943163c4867dd24db683c865a6cdaa488fb diff --git a/src/source/source_driver.hpp b/src/source/source_driver.hpp index a0743a37..e4e8e576 100644 --- a/src/source/source_driver.hpp +++ b/src/source/source_driver.hpp @@ -103,6 +103,7 @@ inline void SourceDriver::init(const YAML::Node& config) yamlRead(driver_config, "start_angle", driver_param.decoder_param.start_angle, 0); yamlRead(driver_config, "end_angle", driver_param.decoder_param.end_angle, 360); yamlRead(driver_config, "dense_points", driver_param.decoder_param.dense_points, false); + yamlRead(driver_config, "ts_first_point", driver_param.decoder_param.ts_first_point, false); // mechanical decoder yamlRead(driver_config, "config_from_file", driver_param.decoder_param.config_from_file, false); From 7fe428c58fd6a62a353815e5c7046d786f053537 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 29 Jun 2022 09:42:59 +0800 Subject: [PATCH 181/261] feat: remove dependency on the protobuf library --- CMakeLists.txt | 59 ++++---------------------------------------------- src/rs_driver | 2 +- 2 files changed, 5 insertions(+), 56 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d880ff5..ade5c943 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,38 +92,6 @@ else(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") endif(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") -#Protobuf# -find_package(Protobuf QUIET) -find_program(PROTOC protoc) -if(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) - - message(=============================================================) - message("-- Protobuf Found. Protobuf Support is turned On!") - message(=============================================================) - - add_definitions(-DPROTO_FOUND) - include_directories(${PROTOBUF_INCLUDE_DIRS}) - - SET(PROTO_FILE_PATH ${PROJECT_SOURCE_DIR}/src/msg/proto_msg) - - file(GLOB PROTOBUF_FILELIST ${PROTO_FILE_PATH}/*.proto) - foreach(proto_file ${PROTOBUF_FILELIST}) - message(STATUS "COMPILING ${proto_file} USING ${PROTOBUF_PROTOC_EXECUTABLE}") - - execute_process(COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} - --proto_path=${PROTO_FILE_PATH} - --cpp_out=${PROTO_FILE_PATH} - ${proto_file}) - endforeach() - -else(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) - - message(=============================================================) - message("-- Protobuf Not Found. Protobuf Support is turned Off!") - message(=============================================================) - -endif(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) - #Others# find_package(yaml-cpp REQUIRED) @@ -168,33 +136,14 @@ message(=============================================================) # Build Setup #======================== -#Protobuf# -if(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) - - add_executable(rslidar_sdk_node - node/rslidar_sdk_node.cpp - src/manager/node_manager.cpp - ${PROTO_FILE_PATH}/packet.pb.cc - ${PROTO_FILE_PATH}/scan.pb.cc - ${PROTO_FILE_PATH}/point_cloud.pb.cc - ) - target_link_libraries(rslidar_sdk_node - ${YAML_CPP_LIBRARIES} - ${PROTOBUF_LIBRARY} - ${rs_driver_LIBRARIES} - ) - -else(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) +add_executable(rslidar_sdk_node + node/rslidar_sdk_node.cpp + src/manager/node_manager.cpp) - add_executable(rslidar_sdk_node - node/rslidar_sdk_node.cpp - src/manager/node_manager.cpp) - target_link_libraries(rslidar_sdk_node +target_link_libraries(rslidar_sdk_node ${YAML_CPP_LIBRARIES} ${rs_driver_LIBRARIES}) -endif(NOT PROTOC MATCHES "NOTFOUND" AND Protobuf_FOUND) - #Ros# if(roscpp_FOUND) diff --git a/src/rs_driver b/src/rs_driver index aa40f943..c4876ef7 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit aa40f943163c4867dd24db683c865a6cdaa488fb +Subproject commit c4876ef7b7d038ae1ee67ac09b3377e1256bf95a From 5230afc9c1ccbd7d05eaa273a0a7c855e52f0cc3 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 1 Jul 2022 12:04:13 +0800 Subject: [PATCH 182/261] feat: tag v1.5.4 --- CHANGELOG.md | 10 +++++++++- src/rs_driver | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1aa207ec..aa8e7348 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,15 @@ ## Unreleased -## v1.5.3 +## v1.5.4 - 2022-07-01 + +### Added +- Support the option to stamp the point cloud with the first point + +### Changed +- Remove the dependency on the protobuf library + +## v1.5.3 - 2022-06-01 ### Added - Support Jumbo Mode diff --git a/src/rs_driver b/src/rs_driver index c4876ef7..5ab60401 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit c4876ef7b7d038ae1ee67ac09b3377e1256bf95a +Subproject commit 5ab604015a8be7dc0595335304822cad88183c6e From 863b81b2c6c19b36d7f0e5319649347725330019 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 4 Jul 2022 09:32:37 +0800 Subject: [PATCH 183/261] feat: update docs --- doc/intro/hiding_parameters_intro.md | 2 ++ doc/intro/hiding_parameters_intro_cn.md | 5 +++-- src/rs_driver | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/doc/intro/hiding_parameters_intro.md b/doc/intro/hiding_parameters_intro.md index 0d5f5bd2..d6a1d099 100644 --- a/doc/intro/hiding_parameters_intro.md +++ b/doc/intro/hiding_parameters_intro.md @@ -34,6 +34,7 @@ lidar: config_from_file: false angle_path: /home/robosense/angle.csv dense_points: false + ts_first_point: false split_frame_mode: 1 split_angle: 0 num_blks_split: 1 @@ -55,6 +56,7 @@ lidar: - ```config_from_file``` -- Whether to read Lidar configuration from file. Only used for debug purpose, and can be ignored. - ```angle_path``` -- The path of the angle.csv. Only used for debug purpose and can be ignored. - ```dense_points``` -- Whether to discard NAN points. Discard if ```true```, reserve if ```false```. The default value is ```false```. +- ```ts_first_point``` -- Stamp the point cloud with the first point or the last one. Stamp with the first point if ```true```, else stamp with the last point if ```false```. The default value is ```false```. - ```split_frame_mode``` -- The way to split the LiDAR frames. Default value is ```1```. - 1 -- Split frame depending on the split_angle - 2 -- Split frame depending on a fixed number of blocks diff --git a/doc/intro/hiding_parameters_intro_cn.md b/doc/intro/hiding_parameters_intro_cn.md index d920f5b9..d684db71 100644 --- a/doc/intro/hiding_parameters_intro_cn.md +++ b/doc/intro/hiding_parameters_intro_cn.md @@ -33,7 +33,8 @@ lidar: use_lidar_clock: false config_from_file: false angle_path: /home/robosense/angle.csv - dense_points: true + dense_points: false + ts_first_point: false split_frame_mode: 1 split_angle: 0 num_blks_split: 1 @@ -55,6 +56,7 @@ lidar: - ```config_from_file``` -- 默认值为false, 是否从外参文件读入雷达配置信息,仅用于调试,可忽略。 - ```angle_path``` -- angle.csv外参文件的路径,仅用于调试,可忽略。 - ```dense_points``` -- 默认值为false。输出的点云中是否剔除NAN points。```true```为剔除,```false```为不剔除。 +- ```ts_first_point``` -- 默认值为false。点云的时间戳是否第一个点的时间。```true```为第一个点的时间,```false```为最后一个点的时间。 - ```split_frame_mode``` -- 分帧模式设置,默认值为```1```。 - 1 -- 角度分帧 - 2 -- 固定block数分帧 @@ -64,7 +66,6 @@ lidar: - ```wait_for_difop``` -- 若设置为false, 驱动将不会等待DIFOP包(包含配置数据,尤其是角度信息),而是立即解析MSOP包并发出点云。 默认值为```true```,也就是必须要有DIFOP包才会进行点云解析。 - ```group_address``` -- 如果雷达为组播模式,此参数需要被设置为组播的地址。具体使用方式可以参考 [组播模式](../howto/how_to_use_multi_cast_function_cn.md) 。 - ```host_address``` -- 有两种情况需要这个选项。如果主机上通过多个IP地址接收多个雷达的数据,则可以将此参数指定为雷达的目标IP;如果设置了group_address,那也需要设置host_address,以便将这个IP地址的网卡加入组播组。 - - ```x, y, z, roll, pitch, yaw ``` -- 坐标变换参数,若启用了内核的坐标变换功能,将会使用此参数输出经过变换后的点云。x, y, z, 单位为```米```, roll, pitch, yaw, 单位为```弧度```。具体使用方式可以参考 [坐标变换功能](../howto/how_to_use_coordinate_transformation_cn.md) 。 - ```use_vlan``` -- 默认为false,指定是否使用vlan。如果pcap文件中的packet带vlan层,则需要设置这个选项为true。其他情况下不需要。在线雷达的情况下,协议层到达驱动时,已经剥离vlan层,所以不需要设置这个选项。 - ```use_someip``` -- 是否使用SOME/IP,默认为false。当数据包中有SOME/IP层,需要设置为true。 diff --git a/src/rs_driver b/src/rs_driver index 5ab60401..4b3c3883 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 5ab604015a8be7dc0595335304822cad88183c6e +Subproject commit 4b3c38836e41165400d52c8ab0fcdd31dd981e1e From e4b6331bdfb3329beb317620c40ffa52c96d2c98 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 7 Jul 2022 09:57:16 +0800 Subject: [PATCH 184/261] feat: add option to use PCL point cloud --- CMakeLists.txt | 10 +++++++ src/msg/rs_msg/lidar_point_cloud_msg.hpp | 5 ++++ src/source/source_pointcloud_ros.hpp | 33 ++++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index ade5c943..380b4e5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,16 @@ if(${ENABLE_RECVMMSG}) add_definitions("-DENABLE_RECVMMSG") endif(${ENABLE_RECVMMSG}) +option(ENABLE_PCL_POINTCLOUD "Enable PCL Point Cloud" OFF) +if(${ENABLE_PCL_POINTCLOUD}) + add_definitions("-DENABLE_PCL_POINTCLOUD") + + find_package(PCL REQUIRED) + include_directories(${PCL_INCLUDE_DIRS}) + link_directories(${PCL_LIBRARY_DIRS}) + add_definitions(${PCL_DEFINITIONS}) +endif(${ENABLE_PCL_POINTCLOUD}) + #======================== # Project details / setup #======================== diff --git a/src/msg/rs_msg/lidar_point_cloud_msg.hpp b/src/msg/rs_msg/lidar_point_cloud_msg.hpp index 476ad4cb..ee8d8d7f 100644 --- a/src/msg/rs_msg/lidar_point_cloud_msg.hpp +++ b/src/msg/rs_msg/lidar_point_cloud_msg.hpp @@ -32,7 +32,11 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once +#ifdef ENABLE_PCL_POINTCLOUD +#include +#else #include "rs_driver/msg/point_cloud_msg.hpp" +#endif #ifdef POINT_TYPE_XYZIRT typedef PointCloudT LidarPointCloudMsg; @@ -40,3 +44,4 @@ typedef PointCloudT LidarPointCloudMsg; typedef PointCloudT LidarPointCloudMsg; #endif + diff --git a/src/source/source_pointcloud_ros.hpp b/src/source/source_pointcloud_ros.hpp index 917cd0bf..dca611a1 100644 --- a/src/source/source_pointcloud_ros.hpp +++ b/src/source/source_pointcloud_ros.hpp @@ -43,6 +43,20 @@ namespace robosense namespace lidar { +#ifdef ENABLE_PCL_POINTCLOUD + +inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const std::string& frame_id) +{ + sensor_msgs::PointCloud2 ros_msg; + pcl::toROSMsg(rs_msg, ros_msg); + ros_msg.header.stamp = ros_msg.header.stamp.fromSec(rs_msg.timestamp); + ros_msg.header.seq = rs_msg.seq; + ros_msg.header.frame_id = frame_id; + return ros_msg; +} + +#else + inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const std::string& frame_id) { sensor_msgs::PointCloud2 ros_msg; @@ -115,6 +129,8 @@ inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const return ros_msg; } +#endif + class DestinationPointCloudRos : public DestinationPointCloud { public: @@ -162,6 +178,21 @@ namespace robosense namespace lidar { +#ifdef ENABLE_PCL_POINTCLOUD + +inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) +{ + sensor_msgs::msg::PointCloud2 ros_msg; + pcl::toROSMsg(rs_msg, ros_msg); + ros_msg.header.frame_id = rs_msg.frame_id; + ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); + ros_msg.header.stamp.nanosec = + (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); + return ros_msg; +} + +#else + inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const std::string& frame_id) { sensor_msgs::msg::PointCloud2 ros_msg; @@ -234,6 +265,8 @@ inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, return ros_msg; } +#endif + class DestinationPointCloudRos : virtual public DestinationPointCloud { public: From 6cc1aaa52e51a86c500be4f91617a14c08ae306d Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 7 Jul 2022 10:06:40 +0800 Subject: [PATCH 185/261] feat: add option to use PCL point cloud --- src/source/source_pointcloud_ros.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/source/source_pointcloud_ros.hpp b/src/source/source_pointcloud_ros.hpp index dca611a1..9ee10510 100644 --- a/src/source/source_pointcloud_ros.hpp +++ b/src/source/source_pointcloud_ros.hpp @@ -34,6 +34,10 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "source/source.hpp" +#ifdef ENABLE_PCL_POINTCLOUD +#include +#endif + #ifdef ROS_FOUND #include #include @@ -180,11 +184,11 @@ namespace lidar #ifdef ENABLE_PCL_POINTCLOUD -inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) +inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const std::string& frame_id) { sensor_msgs::msg::PointCloud2 ros_msg; pcl::toROSMsg(rs_msg, ros_msg); - ros_msg.header.frame_id = rs_msg.frame_id; + ros_msg.header.frame_id = frame_id; ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); ros_msg.header.stamp.nanosec = (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); From 7a3d8230a0cb242e088201c17642112767d1c01e Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 7 Jul 2022 14:10:30 +0800 Subject: [PATCH 186/261] feat: output intensity as float32 --- src/source/source_pointcloud_ros.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/source/source_pointcloud_ros.hpp b/src/source/source_pointcloud_ros.hpp index 9ee10510..53f66c9e 100644 --- a/src/source/source_pointcloud_ros.hpp +++ b/src/source/source_pointcloud_ros.hpp @@ -76,7 +76,7 @@ inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const offset = addPointField(ros_msg, "x", 1, sensor_msgs::PointField::FLOAT32, offset); offset = addPointField(ros_msg, "y", 1, sensor_msgs::PointField::FLOAT32, offset); offset = addPointField(ros_msg, "z", 1, sensor_msgs::PointField::FLOAT32, offset); - offset = addPointField(ros_msg, "intensity", 1, sensor_msgs::PointField::UINT8, offset); + offset = addPointField(ros_msg, "intensity", 1, sensor_msgs::PointField::FLOAT32, offset); #ifdef POINT_TYPE_XYZIRT offset = addPointField(ros_msg, "ring", 1, sensor_msgs::PointField::UINT16, offset); offset = addPointField(ros_msg, "timestamp", 1, sensor_msgs::PointField::FLOAT64, offset); @@ -97,7 +97,7 @@ inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const sensor_msgs::PointCloud2Iterator iter_x_(ros_msg, "x"); sensor_msgs::PointCloud2Iterator iter_y_(ros_msg, "y"); sensor_msgs::PointCloud2Iterator iter_z_(ros_msg, "z"); - sensor_msgs::PointCloud2Iterator iter_intensity_(ros_msg, "intensity"); + sensor_msgs::PointCloud2Iterator iter_intensity_(ros_msg, "intensity"); #ifdef POINT_TYPE_XYZIRT sensor_msgs::PointCloud2Iterator iter_ring_(ros_msg, "ring"); sensor_msgs::PointCloud2Iterator iter_timestamp_(ros_msg, "timestamp"); @@ -212,7 +212,7 @@ inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, offset = addPointField(ros_msg, "x", 1, sensor_msgs::msg::PointField::FLOAT32, offset); offset = addPointField(ros_msg, "y", 1, sensor_msgs::msg::PointField::FLOAT32, offset); offset = addPointField(ros_msg, "z", 1, sensor_msgs::msg::PointField::FLOAT32, offset); - offset = addPointField(ros_msg, "intensity", 1, sensor_msgs::msg::PointField::UINT8, offset); + offset = addPointField(ros_msg, "intensity", 1, sensor_msgs::msg::PointField::FLOAT32, offset); #ifdef POINT_TYPE_XYZIRT offset = addPointField(ros_msg, "ring", 1, sensor_msgs::msg::PointField::UINT16, offset); offset = addPointField(ros_msg, "timestamp", 1, sensor_msgs::msg::PointField::FLOAT64, offset); @@ -233,7 +233,7 @@ inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, sensor_msgs::PointCloud2Iterator iter_x_(ros_msg, "x"); sensor_msgs::PointCloud2Iterator iter_y_(ros_msg, "y"); sensor_msgs::PointCloud2Iterator iter_z_(ros_msg, "z"); - sensor_msgs::PointCloud2Iterator iter_intensity_(ros_msg, "intensity"); + sensor_msgs::PointCloud2Iterator iter_intensity_(ros_msg, "intensity"); #ifdef POINT_TYPE_XYZIRT sensor_msgs::PointCloud2Iterator iter_ring_(ros_msg, "ring"); sensor_msgs::PointCloud2Iterator iter_timestamp_(ros_msg, "timestamp"); From 83926cfdbd7497a7e63b7e708606e4eb432095b6 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 11 Jul 2022 19:01:08 +0800 Subject: [PATCH 187/261] Revert "feat: add option to use PCL point cloud" This reverts commit 6cc1aaa52e51a86c500be4f91617a14c08ae306d. --- src/source/source_pointcloud_ros.hpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/source/source_pointcloud_ros.hpp b/src/source/source_pointcloud_ros.hpp index 53f66c9e..c6811769 100644 --- a/src/source/source_pointcloud_ros.hpp +++ b/src/source/source_pointcloud_ros.hpp @@ -34,10 +34,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "source/source.hpp" -#ifdef ENABLE_PCL_POINTCLOUD -#include -#endif - #ifdef ROS_FOUND #include #include @@ -184,11 +180,11 @@ namespace lidar #ifdef ENABLE_PCL_POINTCLOUD -inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const std::string& frame_id) +inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) { sensor_msgs::msg::PointCloud2 ros_msg; pcl::toROSMsg(rs_msg, ros_msg); - ros_msg.header.frame_id = frame_id; + ros_msg.header.frame_id = rs_msg.frame_id; ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); ros_msg.header.stamp.nanosec = (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); From d1caa5d9e45270dd98893bdd4b6ebc55dae50137 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 11 Jul 2022 19:01:42 +0800 Subject: [PATCH 188/261] Revert "feat: add option to use PCL point cloud" This reverts commit e4b6331bdfb3329beb317620c40ffa52c96d2c98. --- CMakeLists.txt | 10 ------- src/msg/rs_msg/lidar_point_cloud_msg.hpp | 5 ---- src/source/source_pointcloud_ros.hpp | 33 ------------------------ 3 files changed, 48 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 380b4e5f..ade5c943 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,16 +33,6 @@ if(${ENABLE_RECVMMSG}) add_definitions("-DENABLE_RECVMMSG") endif(${ENABLE_RECVMMSG}) -option(ENABLE_PCL_POINTCLOUD "Enable PCL Point Cloud" OFF) -if(${ENABLE_PCL_POINTCLOUD}) - add_definitions("-DENABLE_PCL_POINTCLOUD") - - find_package(PCL REQUIRED) - include_directories(${PCL_INCLUDE_DIRS}) - link_directories(${PCL_LIBRARY_DIRS}) - add_definitions(${PCL_DEFINITIONS}) -endif(${ENABLE_PCL_POINTCLOUD}) - #======================== # Project details / setup #======================== diff --git a/src/msg/rs_msg/lidar_point_cloud_msg.hpp b/src/msg/rs_msg/lidar_point_cloud_msg.hpp index ee8d8d7f..476ad4cb 100644 --- a/src/msg/rs_msg/lidar_point_cloud_msg.hpp +++ b/src/msg/rs_msg/lidar_point_cloud_msg.hpp @@ -32,11 +32,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#ifdef ENABLE_PCL_POINTCLOUD -#include -#else #include "rs_driver/msg/point_cloud_msg.hpp" -#endif #ifdef POINT_TYPE_XYZIRT typedef PointCloudT LidarPointCloudMsg; @@ -44,4 +40,3 @@ typedef PointCloudT LidarPointCloudMsg; typedef PointCloudT LidarPointCloudMsg; #endif - diff --git a/src/source/source_pointcloud_ros.hpp b/src/source/source_pointcloud_ros.hpp index c6811769..482d2e76 100644 --- a/src/source/source_pointcloud_ros.hpp +++ b/src/source/source_pointcloud_ros.hpp @@ -43,20 +43,6 @@ namespace robosense namespace lidar { -#ifdef ENABLE_PCL_POINTCLOUD - -inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const std::string& frame_id) -{ - sensor_msgs::PointCloud2 ros_msg; - pcl::toROSMsg(rs_msg, ros_msg); - ros_msg.header.stamp = ros_msg.header.stamp.fromSec(rs_msg.timestamp); - ros_msg.header.seq = rs_msg.seq; - ros_msg.header.frame_id = frame_id; - return ros_msg; -} - -#else - inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const std::string& frame_id) { sensor_msgs::PointCloud2 ros_msg; @@ -129,8 +115,6 @@ inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const return ros_msg; } -#endif - class DestinationPointCloudRos : public DestinationPointCloud { public: @@ -178,21 +162,6 @@ namespace robosense namespace lidar { -#ifdef ENABLE_PCL_POINTCLOUD - -inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg) -{ - sensor_msgs::msg::PointCloud2 ros_msg; - pcl::toROSMsg(rs_msg, ros_msg); - ros_msg.header.frame_id = rs_msg.frame_id; - ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); - ros_msg.header.stamp.nanosec = - (uint32_t)round((rs_msg.timestamp - ros_msg.header.stamp.sec) * 1e9); - return ros_msg; -} - -#else - inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const std::string& frame_id) { sensor_msgs::msg::PointCloud2 ros_msg; @@ -265,8 +234,6 @@ inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, return ros_msg; } -#endif - class DestinationPointCloudRos : virtual public DestinationPointCloud { public: From 61d835bd4c669ce5b65cd320360583ece28bbe13 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 20 Jul 2022 19:11:32 +0800 Subject: [PATCH 189/261] feat: update docs --- README.md | 17 ++++++++++++++--- README_CN.md | 18 +++++++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d46b419d..1d5829fb 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,18 @@ Please compile and run the driver in three ways. ### 4.1 Compile directly -In ROS (unfortunately not ROS2), user can compile it directly. please laucn ROS master node ```roscore``` in advance, and use ```rviz``` to visualize point cloud. +(1) On top of the file *CMakeLists.txt*,set the variable **COMPILE_METHOD** to **ORIGINAL**. + +```cmake +#======================================= +# Compile setup (ORIGINAL,CATKIN,COLCON) +#======================================= +set(COMPILE_METHOD ORIGINAL) +``` + +(2) In ROS (unfortunately not ROS2), user can compile it directly. + +Please laucn ROS master node ```roscore``` in advance, and use ```rviz``` to visualize point cloud. ```sh cd rslidar_sdk @@ -126,7 +137,7 @@ cmake .. && make -j4 ### 4.2 Compile with ROS catkin tools -(1) On top of the file *CMakeLists.txt*,change the line **set(COMPILE_METHOD ORIGINAL)** to **set(COMPILE_METHOD CATKIN)**. +(1) On top of the file *CMakeLists.txt*,set the variable **COMPILE_METHOD** to **CATKIN**. ```cmake #======================================= @@ -149,7 +160,7 @@ roslaunch rslidar_sdk start.launch ### 4.3 Compile with ROS2 colcon -(1) On top of the file *CMakeLists.txt*, change the line **set(COMPILE_METHOD ORIGINAL)** to **set(COMPILE_METHOD COLCON)**. +(1) On top of the file *CMakeLists.txt*,set the variable **COMPILE_METHOD** to **COLCON**. ```cmake #======================================= diff --git a/README_CN.md b/README_CN.md index 4b652154..34b3cb7e 100644 --- a/README_CN.md +++ b/README_CN.md @@ -111,7 +111,18 @@ sudo apt-get install -y libprotobuf-dev protobuf-compiler ### 4.1 直接编译 -在ROS1(不适用于ROS2)中,可以直接编译、运行程序。 请先启动**roscore**,再运行**rslidar_sdk_node**,最后运行**rviz**查看点云。 +(1) 打开工程内的*CMakeLists.txt*文件,将文件顶部的变量**COMPILE_METHOD**改为**ORIGINAL**. + +```cmake +#======================================= +# Compile setup (ORIGINAL,CATKIN,COLCON) +#======================================= +set(COMPILE_METHOD ORIGINAL) +``` + +(2) 在ROS1(不适用于ROS2)中,直接编译、运行程序。 + +请先启动**roscore**,再运行**rslidar_sdk_node**,最后运行**rviz**查看点云。 ```sh cd rslidar_sdk @@ -122,7 +133,8 @@ cmake .. && make -j4 ### 4.2 依赖于ROS-catkin编译 -(1) 打开工程内的*CMakeLists.txt*文件,将文件顶部的**set(COMPILE_METHOD ORIGINAL)**改为**set(COMPILE_METHOD CATKIN)**。 +(1) 打开工程内的*CMakeLists.txt*文件,将文件顶部的变量**COMPILE_METHOD**改为**CATKIN**. + ```cmake #======================================= @@ -145,7 +157,7 @@ roslaunch rslidar_sdk start.launch ### 4.3 依赖于ROS2-colcon编译 -(1) 打开工程内的*CMakeLists.txt*文件,将文件顶部的**set(COMPILE_METHOD ORIGINAL)**改为**set(COMPILE_METHOD COLCON)**。 +(1) 打开工程内的*CMakeLists.txt*文件,将文件顶部的变量**COMPILE_METHOD**改为**COLCON**. ```cmake #======================================= From d8ef81c554895172fe86b61b9d3e2dfc2fbe8461 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 25 Jul 2022 11:58:43 +0800 Subject: [PATCH 190/261] fix: fix compiling error on ros2 elequent --- src/source/source_packet_ros.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/source/source_packet_ros.hpp b/src/source/source_packet_ros.hpp index 2460be9e..4058ec00 100644 --- a/src/source/source_packet_ros.hpp +++ b/src/source/source_packet_ros.hpp @@ -188,7 +188,7 @@ class SourcePacketRos : public SourceDriver private: - void putPacket(const rslidar_msg::msg::RslidarPacket& msg); + void putPacket(const rslidar_msg::msg::RslidarPacket::SharedPtr msg) const; std::shared_ptr node_ptr_; rclcpp::Subscription::SharedPtr pkt_sub_; @@ -215,9 +215,10 @@ void SourcePacketRos::init(const YAML::Node& config) pkt_sub_ = node_ptr_->create_subscription(ros_recv_topic, 10, std::bind(&SourcePacketRos::putPacket, this, std::placeholders::_1)); } -void SourcePacketRos::putPacket(const rslidar_msg::msg::RslidarPacket& msg) + +void SourcePacketRos::putPacket(const rslidar_msg::msg::RslidarPacket::SharedPtr msg) const { - driver_ptr_->decodePacket(toRsMsg(msg)); + driver_ptr_->decodePacket(toRsMsg(*msg)); } inline rslidar_msg::msg::RslidarPacket toRosMsg(const Packet& rs_msg, const std::string& frame_id) From 09d3c5ab87740a377418b79632f024f12bc4a64b Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 25 Jul 2022 12:03:12 +0800 Subject: [PATCH 191/261] fix: fix launch file for ros2 elequent --- launch/start.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) mode change 100755 => 100644 launch/start.py diff --git a/launch/start.py b/launch/start.py old mode 100755 new mode 100644 index a9031240..52b1d835 --- a/launch/start.py +++ b/launch/start.py @@ -1,12 +1,21 @@ from launch import LaunchDescription from launch_ros.actions import Node from ament_index_python.packages import get_package_share_directory - def generate_launch_description(): - rviz_config=get_package_share_directory('rslidar_sdk')+'/rviz/rviz2.rviz' - return LaunchDescription([ - Node(namespace='rslidar_sdk', package='rslidar_sdk', executable='rslidar_sdk_node', output='screen'), - Node(namespace='rviz2', package='rviz2', executable='rviz2', arguments=['-d',rviz_config]) + Node( + package='rslidar_sdk', + node_namespace='rslidar_sdk', + node_name='rslidar_sdk_node' + node_executable='rslidar_sdk_node', + output='screen', + ), + Node( + package='rviz2', + node_namespace='rviz2', + node_name='rviz2', + node_executable='rviz2', + arguments=['-d',rviz_config] + ) ]) From e77ab151e9ef6927d9c5b855017c91e0abbff888 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 25 Jul 2022 15:06:51 +0800 Subject: [PATCH 192/261] Revert "fix: fix launch file for ros2 elequent" This reverts commit 09d3c5ab87740a377418b79632f024f12bc4a64b. --- launch/start.py | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) mode change 100644 => 100755 launch/start.py diff --git a/launch/start.py b/launch/start.py old mode 100644 new mode 100755 index 52b1d835..a9031240 --- a/launch/start.py +++ b/launch/start.py @@ -1,21 +1,12 @@ from launch import LaunchDescription from launch_ros.actions import Node from ament_index_python.packages import get_package_share_directory + def generate_launch_description(): + rviz_config=get_package_share_directory('rslidar_sdk')+'/rviz/rviz2.rviz' + return LaunchDescription([ - Node( - package='rslidar_sdk', - node_namespace='rslidar_sdk', - node_name='rslidar_sdk_node' - node_executable='rslidar_sdk_node', - output='screen', - ), - Node( - package='rviz2', - node_namespace='rviz2', - node_name='rviz2', - node_executable='rviz2', - arguments=['-d',rviz_config] - ) + Node(namespace='rslidar_sdk', package='rslidar_sdk', executable='rslidar_sdk_node', output='screen'), + Node(namespace='rviz2', package='rviz2', executable='rviz2', arguments=['-d',rviz_config]) ]) From e314c31be2fd19a1726560c8a4b86b1ff0a7dfba Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 25 Jul 2022 15:09:16 +0800 Subject: [PATCH 193/261] fix: support elequent start.py --- launch/elequent_start.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100755 launch/elequent_start.py diff --git a/launch/elequent_start.py b/launch/elequent_start.py new file mode 100755 index 00000000..98cc9e05 --- /dev/null +++ b/launch/elequent_start.py @@ -0,0 +1,21 @@ +from launch import LaunchDescription +from launch_ros.actions import Node +from ament_index_python.packages import get_package_share_directory +def generate_launch_description(): + rviz_config=get_package_share_directory('rslidar_sdk')+'/rviz/rviz2.rviz' + return LaunchDescription([ + Node( + package='rslidar_sdk', + node_namespace='rslidar_sdk', + node_name='rslidar_sdk_node', + node_executable='rslidar_sdk_node', + output='screen' + ), + Node( + package='rviz2', + node_namespace='rviz2', + node_name='rviz2', + node_executable='rviz2', + arguments=['-d',rviz_config] + ) + ]) From 12ef89a392c36cb4b39351d46acde9f78755874d Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 1 Aug 2022 12:57:33 +0800 Subject: [PATCH 194/261] feat: update READMEs --- README.md | 32 ++++++++++++++------------------ README_CN.md | 40 ++++++++++++++++++---------------------- 2 files changed, 32 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 1d5829fb..01328fe9 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,6 @@ + The lidar driver core [rs_driver](https://github.com/RoboSense-LiDAR/rs_driver), + The ROS support, + The ROS2 support, -+ The Protobuf-UDP communication functions. To get point cloud through ROS/ROS2, please just use this SDK. @@ -21,8 +20,13 @@ To integrate the Lidar driver into your own projects, please use the rs_driver. - RS-LiDAR-32 - RS-Bpearl - RS-Helios -- RS-Ruby -- RS-Ruby Lite +- RS-Helios-16P +- RS-Ruby-128 +- RS-Ruby-80 +- RS-Ruby-48 +- RS-Ruby-Plus-128 +- RS-Ruby-Plus-80 +- RS-Ruby-Plus-48 - RS-LiDAR-M1 ### 1.2 Point Type Supported @@ -57,8 +61,9 @@ Please download the **rslidar_sdk.tar.gz** archive instead of Source code. The S ### 3.1 ROS To run rslidar_sdk in the ROS environment, please install below libraries. -+ Ubuntu 16.04 - ros-kinetic-desktop-full -+ Ubuntu 18.04 - ros-melodic-desktop-full ++ Ubuntu 16.04 - ROS Kinetic desktop ++ Ubuntu 18.04 - ROS Melodic desktop ++ Ubuntu 20.04 - ROS Noetic desktop For installation, please refer to http://wiki.ros.org. @@ -70,7 +75,8 @@ This brings a lot of convenience, since you don't have to handle version conflic To use rslidar_sdk in the ROS2 environment, please install below libraries. + Ubuntu 16.04 - Not supported -+ Ubuntu 18.04 - ROS2 eloquent desktop ++ Ubuntu 18.04 - ROS2 Eloquent desktop ++ Ubuntu 20.04 - ROS2 Galactic desktop For installation, please refer to https://index.ros.org/doc/ros2/Installation/Eloquent/Linux-Install-Debians/ @@ -99,16 +105,6 @@ Installation: sudo apt-get install -y libpcap-dev ``` -### 3.5 Protobuf (Optional) - -version: >= v2.6.1 - -Installation: - -```sh -sudo apt-get install -y libprotobuf-dev protobuf-compiler -``` - ## 4 Compile & Run Please compile and run the driver in three ways. @@ -183,6 +179,8 @@ source install/setup.bash ros2 launch rslidar_sdk start.py ``` +Another version of start.py may be used, since it is different on different versios of ROS2. For example, elequent_start.py is used instead for ROS2 elequent. + ## 5 Introduction to parameters To change behaviors of rslidar_sdk, change its parameters. please read the following links for detail information. @@ -211,5 +209,3 @@ Below are some quick guides to use rslidar_sdk. [Coordinate Transformation](doc/howto/how_to_use_coordinate_transformation.md) -[Send & Receive via Protobuf](doc/howto/how_to_use_protobuf_function.md) - diff --git a/README_CN.md b/README_CN.md index 34b3cb7e..de602561 100644 --- a/README_CN.md +++ b/README_CN.md @@ -7,8 +7,7 @@ **rslidar_sdk** 是速腾聚创在Ubuntu环境下的雷达驱动软件包。它包括: + 雷达驱动内核[rs_driver](https://github.com/RoboSense-LiDAR/rs_driver), + ROS拓展功能, - + ROS2拓展功能, - + Protobuf-UDP通信拓展功能。 + + ROS2拓展功能 如果希望基于ROS/ROS2进行二次开发,可以使用本软件包。配合ROS/ROS2自带的可视化工具rviz,可以查看点云。 @@ -20,8 +19,13 @@ - RS-LiDAR-32 - RS-Bpearl - RS-Helios -- RS-Ruby -- RS-Ruby Lite +- RS-Helios-16P +- RS-Ruby-128 +- RS-Ruby-80 +- RS-Ruby-48 +- RS-Ruby-Plus-128 +- RS-Ruby-Plus-80 +- RS-Ruby-Plus-48 - RS-LiDAR-M1 ### 1.2 支持的点类型 @@ -54,19 +58,21 @@ git submodule update ### 3.1 ROS -在ROS环境下使用雷达驱动,需安装ROS相关依赖库。 -+ Ubuntu 16.04 - ROS kinetic desktop-full -+ Ubuntu 18.04 - ROS melodic desktop-full +在ROS环境下使用雷达驱动,需要安装ROS相关依赖库。 ++ Ubuntu 16.04 - ROS Kinetic desktop ++ Ubuntu 18.04 - ROS Melodic desktop ++ Ubuntu 20.04 - ROS Noetic desktop 安装方法请参考 http://wiki.ros.org。 -**强烈建议安装ROS kinetic desktop-full版或ROS melodic desktop-full版。这个过程会自动安装一些兼容版本的依赖库,如PCL库等。这样可以避免花大量时间,去逐个安装和配置它们**。 +**强烈建议安装ROS desktop-full版。这个过程会自动安装一些兼容版本的依赖库,如PCL库等。这样可以避免花大量时间,去逐个安装和配置它们**。 ### 3.2 ROS2 -在ROS2环境下使用雷达驱动,需安装ROS2相关依赖库。 +在ROS2环境下使用雷达驱动,需要安装ROS2相关依赖库。 + Ubuntu 16.04 - 不支持 + Ubuntu 18.04 - ROS2 Eloquent desktop ++ Ubuntu 20.04 - ROS2 Galactic desktop 安装方法请参考 https://index.ros.org/doc/ros2/Installation/Eloquent/Linux-Install-Debians/ @@ -95,17 +101,7 @@ sudo apt-get install -y libyaml-cpp-dev sudo apt-get install -y libpcap-dev ``` -### 3.5 Protobuf (可选) - -版本号: >= v2.6.1 - -安装方法如下: - -```sh -sudo apt-get install -y libprotobuf-dev protobuf-compiler -``` - -## 4 编译 & 运行 +## 4 编译、运行 可以使用三种方式编译、运行rslidar_sdk。 @@ -180,6 +176,8 @@ source install/setup.bash ros2 launch rslidar_sdk start.py ``` +不同ROS2版本start.py的格式可能不同,请使用对应版本的start.py。如ROS2 Elequent,请使用elequent_start.py。 + ## 5 参数介绍 rslidar_sdk的功能通过配置参数文件来实现,请仔细阅读。 @@ -208,5 +206,3 @@ rslidar_sdk的功能通过配置参数文件来实现,请仔细阅读。 [坐标变换功能](doc/howto/how_to_use_coordinate_transformation_cn.md) -[使用Protobuf发送&接收](doc/howto/how_to_use_protobuf_function_cn.md) - From 3ef4c2cb1a726c9769be3f9021fbb94e5bbba3b2 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 1 Aug 2022 14:20:16 +0800 Subject: [PATCH 195/261] feat: wait point_cloud_process_thread to exit --- src/source/source_driver.hpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/source/source_driver.hpp b/src/source/source_driver.hpp index e4e8e576..178cd0c7 100644 --- a/src/source/source_driver.hpp +++ b/src/source/source_driver.hpp @@ -65,11 +65,12 @@ class SourceDriver : public Source std::shared_ptr> driver_ptr_; SyncQueue> free_point_cloud_queue_; SyncQueue> point_cloud_queue_; - std::thread point_cloud_handle_thread_; + std::thread point_cloud_process_thread_; + bool to_exit_process_; }; SourceDriver::SourceDriver(SourceType src_type) - : Source(src_type) + : Source(src_type), to_exit_process_(false) { } @@ -144,7 +145,7 @@ inline void SourceDriver::init(const YAML::Node& config) std::bind(&SourceDriver::putPointCloud, this, std::placeholders::_1)); driver_ptr_->regExceptionCallback( std::bind(&SourceDriver::putException, this, std::placeholders::_1)); - point_cloud_handle_thread_ = std::thread(std::bind(&SourceDriver::processPointCloud, this)); + point_cloud_process_thread_ = std::thread(std::bind(&SourceDriver::processPointCloud, this)); if (!driver_ptr_->init(driver_param)) { @@ -166,6 +167,9 @@ inline SourceDriver::~SourceDriver() inline void SourceDriver::stop() { driver_ptr_->stop(); + + to_exit_process_ = true; + point_cloud_process_thread_.join(); } inline std::shared_ptr SourceDriver::getPointCloud(void) @@ -202,7 +206,7 @@ void SourceDriver::putPointCloud(std::shared_ptr msg) void SourceDriver::processPointCloud() { - while (1) + while (!to_exit_process_) { std::shared_ptr msg = point_cloud_queue_.popWait(1000); if (msg.get() == NULL) From a39736fb61eceaacd975914c6453c6af0bb0822f Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 1 Aug 2022 14:21:42 +0800 Subject: [PATCH 196/261] feat: update source_intro_doc --- doc/src_intro/rslidar_sdk_intro.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/src_intro/rslidar_sdk_intro.md b/doc/src_intro/rslidar_sdk_intro.md index a3ae630a..d3ed3a71 100644 --- a/doc/src_intro/rslidar_sdk_intro.md +++ b/doc/src_intro/rslidar_sdk_intro.md @@ -1,6 +1,6 @@ -# rslidar_sdk v1.5.2 源代码解析 +# rslidar_sdk v1.5.5 源代码解析 -rslidar_sdk是基于ROS的雷达驱动。rslidar_sdk依赖rs_driver接收和解析MSOP/DIFOP Packet。 +rslidar_sdk是基于ROS/ROS2的雷达驱动。rslidar_sdk依赖rs_driver接收和解析MSOP/DIFOP Packet。 rslidar_sdk的基本功能如下: + 从在线雷达或PCAP文件得到点云,通过ROS主题`/rslidar_points`发布。使用者可以订阅这个主题,在rviz中看到点云。 From 3ae8964dcdb13996e1b6ae30d65de1d53857198c Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 1 Aug 2022 14:31:29 +0800 Subject: [PATCH 197/261] fix: fix frame_id in help docs --- doc/howto/how_to_decode_online_lidar.md | 2 +- doc/howto/how_to_decode_online_lidar_cn.md | 2 +- doc/howto/how_to_decode_pcap_file.md | 2 +- doc/howto/how_to_decode_pcap_file_cn.md | 2 +- doc/howto/how_to_record_replay_packet_rosbag.md | 4 ++-- doc/howto/how_to_record_replay_packet_rosbag_cn.md | 4 ++-- doc/howto/how_to_use_coordinate_transformation.md | 4 ++-- doc/howto/how_to_use_coordinate_transformation_cn.md | 2 +- doc/howto/online_lidar_advanced_topics.md | 2 +- doc/howto/online_lidar_advanced_topics_cn.md | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/howto/how_to_decode_online_lidar.md b/doc/howto/how_to_decode_online_lidar.md index 92901320..9f66d32c 100644 --- a/doc/howto/how_to_decode_online_lidar.md +++ b/doc/howto/how_to_decode_online_lidar.md @@ -54,7 +54,7 @@ Set the ```msop_port``` and ```difop_port``` to your LiDAR's port number. ```yaml ros: - ros_frame_id: /rslidar + ros_frame_id: rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points diff --git a/doc/howto/how_to_decode_online_lidar_cn.md b/doc/howto/how_to_decode_online_lidar_cn.md index 665798bf..607e39a5 100644 --- a/doc/howto/how_to_decode_online_lidar_cn.md +++ b/doc/howto/how_to_decode_online_lidar_cn.md @@ -56,7 +56,7 @@ lidar: ```yaml ros: - ros_frame_id: /rslidar + ros_frame_id: rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points diff --git a/doc/howto/how_to_decode_pcap_file.md b/doc/howto/how_to_decode_pcap_file.md index 685909d0..7e51fb96 100644 --- a/doc/howto/how_to_decode_pcap_file.md +++ b/doc/howto/how_to_decode_pcap_file.md @@ -57,7 +57,7 @@ Set the ```msop_port``` and ```difop_port``` to the port numbers of your LiDAR. ```yaml ros: - ros_frame_id: /rslidar + ros_frame_id: rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points diff --git a/doc/howto/how_to_decode_pcap_file_cn.md b/doc/howto/how_to_decode_pcap_file_cn.md index efe49fbe..e739fd6c 100644 --- a/doc/howto/how_to_decode_pcap_file_cn.md +++ b/doc/howto/how_to_decode_pcap_file_cn.md @@ -57,7 +57,7 @@ lidar: ```yaml ros: - ros_frame_id: /rslidar + ros_frame_id: rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points diff --git a/doc/howto/how_to_record_replay_packet_rosbag.md b/doc/howto/how_to_record_replay_packet_rosbag.md index 22482e55..803ff70f 100644 --- a/doc/howto/how_to_record_replay_packet_rosbag.md +++ b/doc/howto/how_to_record_replay_packet_rosbag.md @@ -32,7 +32,7 @@ To change the topic of packet, change ```ros_send_packet_topic```. This topic se ```yaml ros: - ros_frame_id: /rslidar + ros_frame_id: rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points @@ -90,7 +90,7 @@ In `config.yaml`, set the `lidar-ros` part. ```yaml ros: - ros_frame_id: /rslidar + ros_frame_id: rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points diff --git a/doc/howto/how_to_record_replay_packet_rosbag_cn.md b/doc/howto/how_to_record_replay_packet_rosbag_cn.md index 5162dff1..28b0e1a0 100644 --- a/doc/howto/how_to_record_replay_packet_rosbag_cn.md +++ b/doc/howto/how_to_record_replay_packet_rosbag_cn.md @@ -31,7 +31,7 @@ common: ```yaml ros: - ros_frame_id: /rslidar + ros_frame_id: rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points @@ -89,7 +89,7 @@ lidar: ```yaml ros: - ros_frame_id: /rslidar + ros_frame_id: rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points diff --git a/doc/howto/how_to_use_coordinate_transformation.md b/doc/howto/how_to_use_coordinate_transformation.md index bf34c08d..71f01a32 100644 --- a/doc/howto/how_to_use_coordinate_transformation.md +++ b/doc/howto/how_to_use_coordinate_transformation.md @@ -1,12 +1,12 @@ # How to use coordinate transformation ## 1 Introduction - + rslidar_sdk can transform the coordinate of point cloud. This document illustrate how to do so. Please check the [Intro to hiding parameters](../intro/hiding_parameters_intro.md) for more details. Here is an example of the config.yaml. -## 2 Dependency +## 2 Dependencies rslidar_sdk depends on the libeigen library to do coordinate transformation. Please install it first. diff --git a/doc/howto/how_to_use_coordinate_transformation_cn.md b/doc/howto/how_to_use_coordinate_transformation_cn.md index b51c1489..0d4b2157 100644 --- a/doc/howto/how_to_use_coordinate_transformation_cn.md +++ b/doc/howto/how_to_use_coordinate_transformation_cn.md @@ -6,7 +6,7 @@ rslidar_sdk支持对点云进行坐标变换,本文档展示如何作这种变 在阅读本文档之前,请确保已阅读雷达用户手册和[隐藏参数介绍](../intro/hiding_parameters_intro.md)。 -## 2 安装依赖库 +## 2 依赖库 rslidar_sdk的坐标变换基于libeigen库,所以要先安装它。 diff --git a/doc/howto/online_lidar_advanced_topics.md b/doc/howto/online_lidar_advanced_topics.md index ae4fcaad..c03f1d0f 100644 --- a/doc/howto/online_lidar_advanced_topics.md +++ b/doc/howto/online_lidar_advanced_topics.md @@ -38,7 +38,7 @@ lidar: msop_port: 6699 difop_port: 7788 ros: - ros_frame_id: /rslidar + ros_frame_id: rslidar ros_send_point_cloud_topic: /rslidar_points ``` diff --git a/doc/howto/online_lidar_advanced_topics_cn.md b/doc/howto/online_lidar_advanced_topics_cn.md index a94717aa..b2fa16fd 100644 --- a/doc/howto/online_lidar_advanced_topics_cn.md +++ b/doc/howto/online_lidar_advanced_topics_cn.md @@ -39,7 +39,7 @@ lidar: msop_port: 6699 difop_port: 7788 ros: - ros_frame_id: /rslidar + ros_frame_id: rslidar ros_send_point_cloud_topic: /rslidar_points ``` From f1fd129a52495b9af517075aa92eb71b1569b9f6 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 1 Aug 2022 14:41:55 +0800 Subject: [PATCH 198/261] feat: update CHANGELOG --- CHANGELOG.md | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa8e7348..c6cef1f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,16 @@ -# Changelog +# ChangeLog ## Unreleased +## v1.5.5 - 2022-08-01 + +### Changed +- Output intensity in point cloud as float32 + +### Fixed +- Fix compiling and runtime error on ROS2 Elequent +- Fix frame_id in help docs + ## v1.5.4 - 2022-07-01 ### Added @@ -18,40 +27,17 @@ ### Fixed - Fix compiling error when protobuf is unavailable -## v1.5.2 - -### Added -- sync to rs_driver - -## v1.5.1 - -### Changed -- merge refactory code from v1.5.0 - ## v1.5.0 ### Changed - refactory the project -## v1.4.6 - ### Added - support user_layer_bytes and tail_layer_bytes - support M2 - -## v1.4.0 - -### Changed - replace point with point cloud, as rs_driver's template parameter - handle point cloud in rs_driver's thread -## v1.3.1 - -### Added -- add install command when building using catkin -- add use_vlan and use_someip support - - ## v1.3.0 - 2020-11-10 ### Added From c905a69c62b8fa648aaa250e230a7e90d546fa52 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 1 Aug 2022 14:57:13 +0800 Subject: [PATCH 199/261] feat: tag v1.5.5 --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 4b3c3883..2eb41dcb 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 4b3c38836e41165400d52c8ab0fcdd31dd981e1e +Subproject commit 2eb41dcb774caa1bf23072ef933b7f4747e0c4de From f19aaf2e4827c870d8d3187422326c48b537e3dc Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 12 Aug 2022 14:36:10 +0800 Subject: [PATCH 200/261] fix: fix hyperlinks in READMEs --- README.md | 12 +++++------- README_CN.md | 12 +++++------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 01328fe9..7a864ebc 100644 --- a/README.md +++ b/README.md @@ -193,19 +193,17 @@ To change behaviors of rslidar_sdk, change its parameters. please read the follo Below are some quick guides to use rslidar_sdk. -[Online connect lidar and send point cloud through ROS](doc/howto/how_to_online_send_point_cloud_ros.md) +[Online connect lidar and send point cloud through ROS](doc/howto/how_to_decode_online_lidar.md) -[Decode pcap bag and send point cloud through ROS](doc/howto/how_to_offline_decode_pcap.md) +[Decode pcap bag and send point cloud through ROS](doc/howto/how_to_decode_pcap_file.md) -[Record rosbag & Offline decode rosbag](doc/howto/how_to_record_and_offline_decode_rosbag.md) +[Record rosbag & Offline decode rosbag](doc/howto/how_to_record_replay_packet_rosbag.md) ## 7 Advanced Topics -[Switch Point Type](doc/howto/how_to_switch_point_type.md) +[Switch Point Type](doc/howto/how_to_change_point_type.md) -[Multi-Cast](doc/howto/how_to_use_multi_cast_function.md) - -[Multi-LiDARs](doc/howto/how_to_use_multi_lidars.md) +[Network configuration advanced topics](doc/howto/online_lidar_advanced_topics.md) [Coordinate Transformation](doc/howto/how_to_use_coordinate_transformation.md) diff --git a/README_CN.md b/README_CN.md index de602561..53476dbc 100644 --- a/README_CN.md +++ b/README_CN.md @@ -190,19 +190,17 @@ rslidar_sdk的功能通过配置参数文件来实现,请仔细阅读。 以下是一些常用功能的使用指南。 -[在线读取雷达数据发送到ROS](doc/howto/how_to_online_send_point_cloud_ros_cn.md) +[在线读取雷达数据发送到ROS](doc/howto/how_to_decode_online_lidar_cn.md) -[离线解析Pcap包发送到ROS](doc/howto/how_to_offline_decode_pcap_cn.md) +[离线解析PCAP包发送到ROS](doc/howto/how_to_decode_pcap_file_cn.md) -[录制ROS数据包&离线解析ROS数据包](doc/howto/how_to_record_and_offline_decode_rosbag_cn.md) +[录制ROS数据包&离线解析ROS数据包](doc/howto/how_to_record_replay_packet_rosbag_cn.md) ## 7 使用进阶 -[切换点的类型](doc/howto/how_to_switch_point_type_cn.md) +[切换点的类型](doc/howto/how_to_change_point_type_cn.md) -[组播模式](doc/howto/how_to_use_multi_cast_function_cn.md) - -[多雷达](doc/howto/how_to_use_multi_lidars_cn.md) +[网络配置的高级主题](doc/howto/online_lidar_advanced_topics_cn.md) [坐标变换功能](doc/howto/how_to_use_coordinate_transformation_cn.md) From c18482f8e147a4e163ff5eff75442c3aa129cacd Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 24 Aug 2022 10:57:51 +0800 Subject: [PATCH 201/261] feat: shift options from rs_driver here --- CMakeLists.txt | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ade5c943..a9493178 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,10 +28,20 @@ if(${ENABLE_EPOLL_RECEIVE}) add_definitions("-DENABLE_EPOLL_RECEIVE") endif(${ENABLE_EPOLL_RECEIVE}) -option(ENABLE_RECVMMSG "Enable recvmmsg() to receive MSOP message" OFF) -if(${ENABLE_RECVMMSG}) - add_definitions("-DENABLE_RECVMMSG") -endif(${ENABLE_RECVMMSG}) +option(ENABLE_DOUBLE_RCVBUF "Enable double size of RCVBUF" OFF) +if(${ENABLE_DOUBLE_RCVBUF}) + add_definitions("-DENABLE_DOUBLE_RCVBUF") +endif(${ENABLE_DOUBLE_RCVBUF}) + +option(ENABLE_WAIT_IF_QUEUE_EMPTY "Enable waiting for a while in handle thread if the queue is empty" OFF) +if(${ENABLE_WAIT_IF_QUEUE_EMPTY}) + add_definitions("-DENABLE_WAIT_IF_QUEUE_EMPTY") +endif(${ENABLE_WAIT_IF_QUEUE_EMPTY}) + +option(ENABLE_STAMP_WITH_LOCAL "Enable stamp point cloud with local time" OFF) +if(${ENABLE_STAMP_WITH_LOCAL}) + add_definitions("-DENABLE_STAMP_WITH_LOCAL") +endif(${ENABLE_STAMP_WITH_LOCAL}) #======================== # Project details / setup From c273b5c845e4b4349eb9c0e65d8580bcc744bc5a Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 30 Aug 2022 09:36:20 +0800 Subject: [PATCH 202/261] format: update docs --- README.md | 2 +- README_CN.md | 2 +- doc/{ => howto}/img/12_broadcast.png | Bin doc/{ => howto}/img/12_multi_lidars_ip.png | Bin doc/{ => howto}/img/12_multi_lidars_port.png | Bin doc/{ => howto}/img/12_multicast.png | Bin doc/{ => howto}/img/12_unicast.png | Bin doc/{ => howto}/img/12_user_layer.png | Bin doc/{ => howto}/img/12_vlan.png | Bin doc/{ => howto}/img/12_vlan_layer.png | Bin doc/{ => howto}/img/ethernet.png | Bin doc/howto/online_lidar_advanced_topics.md | 16 ++++++++-------- doc/howto/online_lidar_advanced_topics_cn.md | 14 +++++++------- {doc/img => img}/download_page.png | Bin 14 files changed, 17 insertions(+), 17 deletions(-) rename doc/{ => howto}/img/12_broadcast.png (100%) rename doc/{ => howto}/img/12_multi_lidars_ip.png (100%) rename doc/{ => howto}/img/12_multi_lidars_port.png (100%) rename doc/{ => howto}/img/12_multicast.png (100%) rename doc/{ => howto}/img/12_unicast.png (100%) rename doc/{ => howto}/img/12_user_layer.png (100%) rename doc/{ => howto}/img/12_vlan.png (100%) rename doc/{ => howto}/img/12_vlan_layer.png (100%) rename doc/{ => howto}/img/ethernet.png (100%) rename {doc/img => img}/download_page.png (100%) diff --git a/README.md b/README.md index 7a864ebc..66e60424 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ Instead of using Git, user can also access [rslidar_sdk_release](https://github. Please download the **rslidar_sdk.tar.gz** archive instead of Source code. The Source code zip file does not contain the submodule rs_driver, so it has to be downloaded manaully. -![](doc/img/download_page.png) +![](./img/download_page.png) ## 3 Dependencies diff --git a/README_CN.md b/README_CN.md index 53476dbc..7e1dc4ed 100644 --- a/README_CN.md +++ b/README_CN.md @@ -52,7 +52,7 @@ git submodule update 请下载 **rslidar_sdk.tar.gz** 压缩包,不要下载Source code。因为Source code压缩包内不包含子模块rs_driver的代码, 用户还需自行下载rs_driver的代码放入其中才行。 -![](doc/img/download_page.png) +![](./img/download_page.png) ## 3 依赖介绍 diff --git a/doc/img/12_broadcast.png b/doc/howto/img/12_broadcast.png similarity index 100% rename from doc/img/12_broadcast.png rename to doc/howto/img/12_broadcast.png diff --git a/doc/img/12_multi_lidars_ip.png b/doc/howto/img/12_multi_lidars_ip.png similarity index 100% rename from doc/img/12_multi_lidars_ip.png rename to doc/howto/img/12_multi_lidars_ip.png diff --git a/doc/img/12_multi_lidars_port.png b/doc/howto/img/12_multi_lidars_port.png similarity index 100% rename from doc/img/12_multi_lidars_port.png rename to doc/howto/img/12_multi_lidars_port.png diff --git a/doc/img/12_multicast.png b/doc/howto/img/12_multicast.png similarity index 100% rename from doc/img/12_multicast.png rename to doc/howto/img/12_multicast.png diff --git a/doc/img/12_unicast.png b/doc/howto/img/12_unicast.png similarity index 100% rename from doc/img/12_unicast.png rename to doc/howto/img/12_unicast.png diff --git a/doc/img/12_user_layer.png b/doc/howto/img/12_user_layer.png similarity index 100% rename from doc/img/12_user_layer.png rename to doc/howto/img/12_user_layer.png diff --git a/doc/img/12_vlan.png b/doc/howto/img/12_vlan.png similarity index 100% rename from doc/img/12_vlan.png rename to doc/howto/img/12_vlan.png diff --git a/doc/img/12_vlan_layer.png b/doc/howto/img/12_vlan_layer.png similarity index 100% rename from doc/img/12_vlan_layer.png rename to doc/howto/img/12_vlan_layer.png diff --git a/doc/img/ethernet.png b/doc/howto/img/ethernet.png similarity index 100% rename from doc/img/ethernet.png rename to doc/howto/img/ethernet.png diff --git a/doc/howto/online_lidar_advanced_topics.md b/doc/howto/online_lidar_advanced_topics.md index c03f1d0f..10ad9077 100644 --- a/doc/howto/online_lidar_advanced_topics.md +++ b/doc/howto/online_lidar_advanced_topics.md @@ -23,7 +23,7 @@ Before reading this document, please be sure that you have read: The Lidar sends MSOP/DIFOP packets to the host machine (rslidar_sdk runs on it). For simplicity, the DIFOP port is ommited here. + The Lidar sends to `255.255.255.255` : `6699`, and the host binds to port `6699`. -![](../img/12_broadcast.png) +![](./img/12_broadcast.png) Below is how to configure `config.yaml`. @@ -49,7 +49,7 @@ The `common` part and the `lidar-ros` part is listed here. They will be ommited To reduce the network load, the Lidar is suggested to work in unicast mode. + The Lidar sends to `192.168.1.102` : `6699`, and the host binds to port `6699`. -![](../img/12_unicast.png) +![](./img/12_unicast.png) Below is how to configure `config.yaml`. In fact, it same with the broadcast mode. @@ -67,7 +67,7 @@ The Lidar may also works in multicast mode. + The lidar sends to `224.1.1.1`:`6699` + The host binds to port `6699`. And it makes local NIC (Network Interface Card) join the multicast group `224.1.1.1`. The local NIC's IP is `192.168.1.102`. -![](../img/12_multicast.png) +![](./img/12_multicast.png) Below is how to configure `config.yaml`. @@ -89,7 +89,7 @@ If you have two or more Lidars, it is suggested to set different remote ports. + First Lidar sends to `192.168.1.102`:`6699`, and the first driver instance binds to `6699`. + Second Lidar sends to `192.168.1.102`:`5599`, and the second driver instance binds to `5599`. -![](../img/12_multi_lidars_port.png) +![](./img/12_multi_lidars_port.png) Below is how to configure `config.yaml`. @@ -112,7 +112,7 @@ An alternate way is to set different remote IPs. + First Lidar sends to `192.168.1.102`:`6699`, and the first driver instance binds to `192.168.1.102:6699`. + Second Lidar sends to `192.168.1.103`:`6699`, and the second driver instance binds to `192.168.1.103:6699`. -![](../img/12_multi_lidars_ip.png) +![](./img/12_multi_lidars_ip.png) Below is how to configure `config.yaml`. @@ -134,7 +134,7 @@ lidar: In some user cases, The Lidar may work on VLAN. Its packets have a VLAN layer. -![](../img/12_vlan_layer.png) +![](./img/12_vlan_layer.png) The driver cannot parse this packet. Instead, it depends on a virtual NIC to strip the VLAN layer. @@ -142,7 +142,7 @@ Below is an example. + The Lidar works on VLAN `80`. It sends packets to `192.168.1.102` : `6699`. The packet has a VLAN layer. + Suppose there is a physical NIC `eno1` on the host. It receives packets with VLAN layer. -![](../img/12_vlan.png) +![](./img/12_vlan.png) To strip the VLAN layer, create a virtual NIC `eno1.80` on `eno1`, and assign IP `192.168.1.102` to it. @@ -169,7 +169,7 @@ lidar: In some user cases, User may add extra layers before or after the MSOP/DIFOP packet. + USER_LAYER is before the packet and TAIL_LAYER is after it. -![](../img/12_user_layer.png) +![](./img/12_user_layer.png) These extra layers are parts of UDP data. The driver can strip them. diff --git a/doc/howto/online_lidar_advanced_topics_cn.md b/doc/howto/online_lidar_advanced_topics_cn.md index b2fa16fd..d7bd1ef3 100644 --- a/doc/howto/online_lidar_advanced_topics_cn.md +++ b/doc/howto/online_lidar_advanced_topics_cn.md @@ -24,7 +24,7 @@ 雷达发送 MSOP/DIFOP Packet到电脑主机。为简单起见,如下的图没有显示DIFOP端口。 + 雷达发送Packet到 `255.255.255.255` : `6699`, rslidar_sdk绑定到主机的端口 `6699`. -![](../img/12_broadcast.png) +![](./img/12_broadcast.png) 如下是配置`config.yaml`的方式。 @@ -50,7 +50,7 @@ lidar: 为了减少网络负载,建议雷达使用单播模式。 + 雷达发送Packet到 `192.168.1.102` : `6699`, rslidar_sdk绑定端口 `6699`。 -![](../img/12_unicast.png) +![](./img/12_unicast.png) 如下是配置`config.yaml`的方式。这实际上与广播的方式一样。 @@ -68,7 +68,7 @@ lidar: + 雷达发送Packet到 `224.1.1.1`:`6699` + rslidar_sdk绑定到端口 `6699`。同时它将IP地址为`192.168.1.102`的本地网络接口加入组播组`224.1.1.1`。 -![](../img/12_multicast.png) +![](./img/12_multicast.png) 如下是配置`config.yaml`的方式。 @@ -90,7 +90,7 @@ lidar: + 第一个雷达发送Packet到 `192.168.1.102`:`6699`, 给rslidar_sdk配置的第一个driver节点绑定到`6699`。 + 第二个雷达发送Packet到 `192.168.1.102`:`5599`, 给rslidar_sdk配置的第二个driver节点绑定到`5599`。 -![](../img/12_multi_lidars_port.png) +![](./img/12_multi_lidars_port.png) 如下是配置`config.yaml`的方式。 @@ -113,7 +113,7 @@ lidar: + 第一个雷达发送Packet到 `192.168.1.102`:`6699`, 给rslidar_sdk配置的第一个driver节点绑定到`192.168.1.102:6699`。 + 第二个雷达发送Packet到 `192.168.1.103`:`6699`, 给rslidar_sdk配置的第二个driver节点绑定到`192.168.1.103:6699`。 -![](../img/12_multi_lidars_ip.png) +![](./img/12_multi_lidars_ip.png) 如下是配置`config.yaml`的方式。 @@ -135,7 +135,7 @@ lidar: 在某些场景下,雷达工作在VLAN层之上。MSOP/DIFOP Packet有VLAN层,如下图。 -![](../img/12_vlan_layer.png) +![](./img/12_vlan_layer.png) rslidar_sdk不能解析VLAN层。 @@ -171,7 +171,7 @@ lidar: 在某些场景下,用户可能在MSOP/DIFOP数据前后加入自己的层。 + 在前面的是USER_LAYER,在后面的是TAIL_LAYER。 -![](../img/12_user_layer.png) +![](./img/12_user_layer.png) 这两个层是UDP数据的一部分,所以rslidar_sdk可以自己剥除它们。只需要指出这两个层的长度就可以了。 diff --git a/doc/img/download_page.png b/img/download_page.png similarity index 100% rename from doc/img/download_page.png rename to img/download_page.png From 48310eb64dbef99b408b9177bddf4b92893ccde6 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 31 Aug 2022 11:11:26 +0800 Subject: [PATCH 203/261] feat: remove unused files --- src/msg/proto_msg_translator.h | 140 ------------------ src/msg/ros_msg/lidar_packet_ros.h | 196 ------------------------- src/msg/ros_msg/lidar_scan_ros.h | 228 ----------------------------- src/msg/ros_msg_translator.h | 127 ---------------- 4 files changed, 691 deletions(-) delete mode 100644 src/msg/proto_msg_translator.h delete mode 100644 src/msg/ros_msg/lidar_packet_ros.h delete mode 100644 src/msg/ros_msg/lidar_scan_ros.h delete mode 100644 src/msg/ros_msg_translator.h diff --git a/src/msg/proto_msg_translator.h b/src/msg/proto_msg_translator.h deleted file mode 100644 index 7f8ea73e..00000000 --- a/src/msg/proto_msg_translator.h +++ /dev/null @@ -1,140 +0,0 @@ -/********************************************************************************************************************* -Copyright (c) 2020 RoboSense -All rights reserved - -By downloading, copying, installing or using the software you agree to this license. If you do not agree to this -license, do not download, install, copy or use the software. - -License Agreement -For RoboSense LiDAR SDK Library -(3-clause BSD License) - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following -disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the names of the RoboSense, nor Suteng Innovation Technology, nor the names of other contributors may be used -to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*********************************************************************************************************************/ - -#pragma once -#ifdef PROTO_FOUND -#include "msg/rs_msg/lidar_point_cloud_msg.h" -#include "rs_driver/msg/packet_msg.h" -#include "rs_driver/msg/scan_msg.h" -#include "msg/proto_msg/point_cloud.pb.h" -#include "msg/proto_msg/packet.pb.h" -#include "msg/proto_msg/scan.pb.h" -namespace robosense -{ -namespace lidar -{ -/************************************************************************/ -/**Translation functions between RoboSense message and protobuf message**/ -/************************************************************************/ -inline proto_msg::LidarPointCloud toProtoMsg(const LidarPointCloudMsg& rs_msg) -{ - proto_msg::LidarPointCloud proto_msg; - proto_msg.set_timestamp(rs_msg.timestamp); - proto_msg.set_seq(rs_msg.seq); - proto_msg.set_frame_id(rs_msg.frame_id); - proto_msg.set_height(rs_msg.height); - proto_msg.set_width(rs_msg.width); - proto_msg.set_is_dense(rs_msg.is_dense); - - for (size_t i = 0; i < rs_msg.size(); i++) - { - proto_msg.add_data(rs_msg.points[i].x); - proto_msg.add_data(rs_msg.points[i].y); - proto_msg.add_data(rs_msg.points[i].z); - proto_msg.add_data(rs_msg.points[i].intensity); - } - - return std::move(proto_msg); -} - -inline LidarPointCloudMsg toRsMsg(const proto_msg::LidarPointCloud& proto_msg) -{ - LidarPointCloudMsg rs_msg; - rs_msg.timestamp = proto_msg.timestamp(); - rs_msg.seq = proto_msg.seq(); - rs_msg.frame_id = proto_msg.frame_id(); - for (int i = 0; i < proto_msg.data_size(); i += 4) - { - PointT point; - point.x = proto_msg.data(i); - point.y = proto_msg.data(i + 1); - point.z = proto_msg.data(i + 2); - point.intensity = proto_msg.data(i + 3); - rs_msg.points.push_back(point); - } - rs_msg.height = proto_msg.height(); - rs_msg.width = proto_msg.width(); - rs_msg.is_dense = proto_msg.is_dense(); - return rs_msg; -} - -inline proto_msg::LidarScan toProtoMsg(const ScanMsg& rs_msg) -{ - proto_msg::LidarScan proto_msg; - proto_msg.set_timestamp(rs_msg.timestamp); - proto_msg.set_seq(rs_msg.seq); - for (auto iter : rs_msg.packets) - { - void* data_ptr = malloc(iter.packet.size()); - memcpy(data_ptr, iter.packet.data(), iter.packet.size()); - proto_msg.add_data(data_ptr, iter.packet.size()); - free(data_ptr); - } - return proto_msg; -} - -inline ScanMsg toRsMsg(const proto_msg::LidarScan& proto_msg) -{ - ScanMsg rs_msg; - rs_msg.timestamp = proto_msg.timestamp(); - rs_msg.seq = proto_msg.seq(); - for (int i = 0; i < proto_msg.data_size(); i++) - { - std::string data_str = proto_msg.data(i); - PacketMsg tmp_pkt(data_str.size()); - memcpy(tmp_pkt.packet.data(), data_str.data(), data_str.size()); - rs_msg.packets.emplace_back(std::move(tmp_pkt)); - } - return rs_msg; -} - -inline proto_msg::LidarPacket toProtoMsg(const PacketMsg& rs_msg) -{ - proto_msg::LidarPacket proto_msg; - void* data_ptr = malloc(rs_msg.packet.size()); - memcpy(data_ptr, rs_msg.packet.data(), rs_msg.packet.size()); - proto_msg.set_data(data_ptr, rs_msg.packet.size()); - free(data_ptr); - return proto_msg; -} - -inline PacketMsg toRsMsg(const proto_msg::LidarPacket& proto_msg) -{ - std::string data_str = proto_msg.data(); - PacketMsg rs_msg(data_str.size()); - memcpy(rs_msg.packet.data(), data_str.data(), data_str.size()); - return rs_msg; -} - -} // namespace lidar -} // namespace robosense -#endif // PROTO_FOUND diff --git a/src/msg/ros_msg/lidar_packet_ros.h b/src/msg/ros_msg/lidar_packet_ros.h deleted file mode 100644 index fbd820b2..00000000 --- a/src/msg/ros_msg/lidar_packet_ros.h +++ /dev/null @@ -1,196 +0,0 @@ -// Generated by gencpp from file rslidar_msgs/rslidarPacket.msg -// DO NOT EDIT! - -#pragma once - -#include -#include -#include - -#include -#include -#include -#include - -namespace rslidar_msgs -{ -template -struct rslidarPacket_ -{ - typedef rslidarPacket_ Type; - - rslidarPacket_() : stamp(), data() - { - data.assign(0); - } - rslidarPacket_(const ContainerAllocator& _alloc) : stamp(), data() - { - (void)_alloc; - data.assign(0); - } - - typedef ros::Time _stamp_type; - _stamp_type stamp; - - typedef boost::array _data_type; - _data_type data; - - typedef boost::shared_ptr< ::rslidar_msgs::rslidarPacket_ > Ptr; - typedef boost::shared_ptr< ::rslidar_msgs::rslidarPacket_ const> ConstPtr; - -}; // struct rslidarPacket_ - -typedef ::rslidar_msgs::rslidarPacket_ > rslidarPacket; - -typedef boost::shared_ptr< ::rslidar_msgs::rslidarPacket> rslidarPacketPtr; -typedef boost::shared_ptr< ::rslidar_msgs::rslidarPacket const> rslidarPacketConstPtr; - -// constants requiring out of line definition - -template -std::ostream& operator<<(std::ostream& s, const ::rslidar_msgs::rslidarPacket_& v) -{ - ros::message_operations::Printer< ::rslidar_msgs::rslidarPacket_ >::stream(s, "", v); - return s; -} - -} // namespace rslidar_msgs - -namespace ros -{ -namespace message_traits -{ -// BOOLTRAITS {'IsFixedSize': true, 'IsMessage': true, 'HasHeader': false} -// {'std_msgs': ['/opt/ros/kinetic/share/std_msgs/cmake/../msg'], 'rslidar_msgs': -// ['/home/xzd/catkin_ws/src/rs_driver/rslidar_msgs/msg']} - -// !!!!!!!!!!! ['__class__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__getattribute__', -// '__hash__', '__init__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', -// '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_parsed_fields', 'constants', 'fields', 'full_name', -// 'has_header', 'header_present', 'names', 'package', 'parsed_fields', 'short_name', 'text', 'types'] - -template -struct IsFixedSize< ::rslidar_msgs::rslidarPacket_ > : TrueType -{ -}; - -template -struct IsFixedSize< ::rslidar_msgs::rslidarPacket_ const> : TrueType -{ -}; - -template -struct IsMessage< ::rslidar_msgs::rslidarPacket_ > : TrueType -{ -}; - -template -struct IsMessage< ::rslidar_msgs::rslidarPacket_ const> : TrueType -{ -}; - -template -struct HasHeader< ::rslidar_msgs::rslidarPacket_ > : FalseType -{ -}; - -template -struct HasHeader< ::rslidar_msgs::rslidarPacket_ const> : FalseType -{ -}; - -template -struct MD5Sum< ::rslidar_msgs::rslidarPacket_ > -{ - static const char* value() - { - return "1e4288e00b9222ea477b73350bf24f51"; - } - - static const char* value(const ::rslidar_msgs::rslidarPacket_&) - { - return value(); - } - static const uint64_t static_value1 = 0x1e4288e00b9222eaULL; - static const uint64_t static_value2 = 0x477b73350bf24f51ULL; -}; - -template -struct DataType< ::rslidar_msgs::rslidarPacket_ > -{ - static const char* value() - { - return "rslidar_msgs/rslidarPacket"; - } - - static const char* value(const ::rslidar_msgs::rslidarPacket_&) - { - return value(); - } -}; - -template -struct Definition< ::rslidar_msgs::rslidarPacket_ > -{ - static const char* value() - { - return "# Raw LIDAR packet.\n\ -\n\ -timestamp # packet timestamp\n\ -uint8[1248] data # packet contents\n\ -\n\ -"; - } - - static const char* value(const ::rslidar_msgs::rslidarPacket_&) - { - return value(); - } -}; - -} // namespace message_traits -} // namespace ros - -namespace ros -{ -namespace serialization -{ -template -struct Serializer< ::rslidar_msgs::rslidarPacket_ > -{ - template - inline static void allInOne(Stream& stream, T m) - { - stream.next(m.stamp); - stream.next(m.data); - } - - ROS_DECLARE_ALLINONE_SERIALIZER -}; // struct rslidarPacket_ - -} // namespace serialization -} // namespace ros - -namespace ros -{ -namespace message_operations -{ -template -struct Printer< ::rslidar_msgs::rslidarPacket_ > -{ - template - static void stream(Stream& s, const std::string& indent, const ::rslidar_msgs::rslidarPacket_& v) - { - s << indent << "stamp: "; - Printer::stream(s, indent + " ", v.stamp); - s << indent << "data[]" << std::endl; - for (size_t i = 0; i < v.data.size(); ++i) - { - s << indent << " data[" << i << "]: "; - Printer::stream(s, indent + " ", v.data[i]); - } - } -}; - -} // namespace message_operations -} // namespace ros diff --git a/src/msg/ros_msg/lidar_scan_ros.h b/src/msg/ros_msg/lidar_scan_ros.h deleted file mode 100644 index 371197d8..00000000 --- a/src/msg/ros_msg/lidar_scan_ros.h +++ /dev/null @@ -1,228 +0,0 @@ -// Generated by gencpp from file rslidar_msgs/rslidarScan.msg -// DO NOT EDIT! - -#pragma once - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include "msg/ros_msg/lidar_packet_ros.h" - -namespace rslidar_msgs -{ -template -struct rslidarScan_ -{ - typedef rslidarScan_ Type; - - rslidarScan_() : header(), packets() - { - } - rslidarScan_(const ContainerAllocator& _alloc) : header(_alloc), packets(_alloc) - { - (void)_alloc; - } - - typedef ::std_msgs::Header_ _header_type; - _header_type header; - - typedef std::vector< - ::rslidar_msgs::rslidarPacket_, - typename ContainerAllocator::template rebind<::rslidar_msgs::rslidarPacket_>::other> - _packets_type; - _packets_type packets; - - typedef boost::shared_ptr<::rslidar_msgs::rslidarScan_> Ptr; - typedef boost::shared_ptr<::rslidar_msgs::rslidarScan_ const> ConstPtr; - -}; // struct rslidarScan_ - -typedef ::rslidar_msgs::rslidarScan_> rslidarScan; - -typedef boost::shared_ptr<::rslidar_msgs::rslidarScan> rslidarScanPtr; -typedef boost::shared_ptr<::rslidar_msgs::rslidarScan const> rslidarScanConstPtr; - -// constants requiring out of line definition - -template -std::ostream& operator<<(std::ostream& s, const ::rslidar_msgs::rslidarScan_& v) -{ - ros::message_operations::Printer<::rslidar_msgs::rslidarScan_>::stream(s, "", v); - return s; -} - -} // namespace rslidar_msgs - -namespace ros -{ -namespace message_traits -{ -// BOOLTRAITS {'IsFixedSize': false, 'IsMessage': true, 'HasHeader': true} -// {'std_msgs': ['/opt/ros/kinetic/share/std_msgs/cmake/../msg'], 'rslidar_msgs': -// ['/home/xzd/catkin_ws/src/rs_driver/rslidar_msgs/msg']} - -// !!!!!!!!!!! ['__class__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__getattribute__', -// '__hash__', '__init__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', -// '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_parsed_fields', 'constants', 'fields', 'full_name', -// 'has_header', 'header_present', 'names', 'package', 'parsed_fields', 'short_name', 'text', 'types'] - -template -struct IsFixedSize<::rslidar_msgs::rslidarScan_> : FalseType -{ -}; - -template -struct IsFixedSize<::rslidar_msgs::rslidarScan_ const> : FalseType -{ -}; - -template -struct IsMessage<::rslidar_msgs::rslidarScan_> : TrueType -{ -}; - -template -struct IsMessage<::rslidar_msgs::rslidarScan_ const> : TrueType -{ -}; - -template -struct HasHeader<::rslidar_msgs::rslidarScan_> : TrueType -{ -}; - -template -struct HasHeader<::rslidar_msgs::rslidarScan_ const> : TrueType -{ -}; - -template -struct MD5Sum<::rslidar_msgs::rslidarScan_> -{ - static const char* value() - { - return "ff6baa58985b528481871cbaf1bb342f"; - } - - static const char* value(const ::rslidar_msgs::rslidarScan_&) - { - return value(); - } - static const uint64_t static_value1 = 0xff6baa58985b5284ULL; - static const uint64_t static_value2 = 0x81871cbaf1bb342fULL; -}; - -template -struct DataType<::rslidar_msgs::rslidarScan_> -{ - static const char* value() - { - return "rslidar_msgs/rslidarScan"; - } - - static const char* value(const ::rslidar_msgs::rslidarScan_&) - { - return value(); - } -}; - -template -struct Definition<::rslidar_msgs::rslidarScan_> -{ - static const char* value() - { - return "# LIDAR scan packets.\n\ -\n\ -Header header # standard ROS message header\n\ -rslidarPacket[] packets # vector of raw packets\n\ -\n\ -================================================================================\n\ -MSG: std_msgs/Header\n\ -# Standard metadata for higher-level stamped data types.\n\ -# This is generally used to communicate timestamped data \n\ -# in a particular coordinate frame.\n\ -# \n\ -# sequence ID: consecutively increasing ID \n\ -uint32 seq\n\ -#Two-integer timestamp that is expressed as:\n\ -# * stamp.sec: seconds (stamp_secs) since epoch (in Python the variable is called 'secs')\n\ -# * stamp.nsec: nanoseconds since stamp_secs (in Python the variable is called 'nsecs')\n\ -# time-handling sugar is provided by the client library\n\ -timestamp\n\ -#Frame this data is associated with\n\ -# 0: no frame\n\ -# 1: global frame\n\ -string frame_id\n\ -\n\ -================================================================================\n\ -MSG: rslidar_msgs/rslidarPacket\n\ -# Raw LIDAR packet.\n\ -\n\ -timestamp # packet timestamp\n\ -uint8[1248] data # packet contents\n\ -\n\ -"; - } - - static const char* value(const ::rslidar_msgs::rslidarScan_&) - { - return value(); - } -}; - -} // namespace message_traits -} // namespace ros - -namespace ros -{ -namespace serialization -{ -template -struct Serializer<::rslidar_msgs::rslidarScan_> -{ - template - inline static void allInOne(Stream& stream, T m) - { - stream.next(m.header); - stream.next(m.packets); - } - - ROS_DECLARE_ALLINONE_SERIALIZER -}; // struct rslidarScan_ - -} // namespace serialization -} // namespace ros - -namespace ros -{ -namespace message_operations -{ -template -struct Printer<::rslidar_msgs::rslidarScan_> -{ - template - static void stream(Stream& s, const std::string& indent, const ::rslidar_msgs::rslidarScan_& v) - { - s << indent << "header: "; - s << std::endl; - Printer<::std_msgs::Header_>::stream(s, indent + " ", v.header); - s << indent << "packets[]" << std::endl; - for (size_t i = 0; i < v.packets.size(); ++i) - { - s << indent << " packets[" << i << "]: "; - s << std::endl; - s << indent; - Printer<::rslidar_msgs::rslidarPacket_>::stream(s, indent + " ", v.packets[i]); - } - } -}; - -} // namespace message_operations -} // namespace ros diff --git a/src/msg/ros_msg_translator.h b/src/msg/ros_msg_translator.h deleted file mode 100644 index d70be4af..00000000 --- a/src/msg/ros_msg_translator.h +++ /dev/null @@ -1,127 +0,0 @@ -/********************************************************************************************************************* -Copyright (c) 2020 RoboSense -All rights reserved - -By downloading, copying, installing or using the software you agree to this license. If you do not agree to this -license, do not download, install, copy or use the software. - -License Agreement -For RoboSense LiDAR SDK Library -(3-clause BSD License) - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following -disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the names of the RoboSense, nor Suteng Innovation Technology, nor the names of other contributors may be used -to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*********************************************************************************************************************/ - -#pragma once -#ifdef ROS_FOUND -#include -#include -#include -#include -#include -#include -#include -#include "msg/rs_msg/lidar_point_cloud_msg.h" -#include "msg/ros_msg/lidar_packet_ros.h" -#include "msg/ros_msg/lidar_scan_ros.h" -#include "rs_driver/msg/packet_msg.h" -#include "rs_driver/msg/scan_msg.h" -#include "rs_driver/driver/driver_param.h" - -namespace robosense -{ -namespace lidar -{ -/************************************************************************/ -/**Translation functions between RoboSense message and ROS message**/ -/************************************************************************/ - -#if 0 -inline std_msgs::Time toRosMsg(const CameraTrigger& rs_msg) -{ - std_msgs::Time ros_msg; - ros_msg.data = ros_msg.data.fromSec(rs_msg.second); - return ros_msg; -} -#endif - -} // namespace lidar -} // namespace robosense -#endif // ROS_FOUND - -#ifdef ROS2_FOUND -#include -#include -#include "rslidar_msg/msg/rslidar_packet.hpp" -#include "rslidar_msg/msg/rslidar_scan.hpp" -namespace robosense -{ -namespace lidar -{ -/************************************************************************/ -/**Translation functions between RoboSense message and ROS2 message**/ -/************************************************************************/ - -inline PacketMsg toRsMsg(const LidarType& lidar_type, const PktType& pkt_type, - const rslidar_msg::msg::RslidarPacket& ros_msg) -{ - size_t pkt_length; - switch (lidar_type) - { - case LidarType::RSM1: - if (pkt_type == PktType::MSOP) - { - pkt_length = MEMS_MSOP_LEN; - } - else - { - pkt_length = MEMS_DIFOP_LEN; - } - break; - default: - pkt_length = MECH_PKT_LEN; - break; - } - PacketMsg rs_msg(pkt_length); - for (size_t i = 0; i < pkt_length; i++) - { - rs_msg.packet[i] = ros_msg.data[i]; - } - return std::move(rs_msg); -} - -inline ScanMsg toRsMsg(const LidarType& lidar_type, const PktType& pkt_type, - const rslidar_msg::msg::RslidarScan& ros_msg) -{ - ScanMsg rs_msg; - rs_msg.timestamp = ros_msg.header.stamp.sec + double(ros_msg.header.stamp.nanosec) / 1e9; - rs_msg.frame_id = ros_msg.header.frame_id; - for (uint32_t i = 0; i < ros_msg.packets.size(); i++) - { - PacketMsg tmp = toRsMsg(lidar_type, pkt_type, ros_msg.packets[i]); - rs_msg.packets.emplace_back(std::move(tmp)); - } - return rs_msg; -} - -} // namespace lidar -} // namespace robosense -#endif // ROS2_FOUND From b95aaacdd395b6d8f6b3e47baeec69bb9ad87601 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 31 Aug 2022 14:32:00 +0800 Subject: [PATCH 204/261] feat: update docs --- doc/howto/online_lidar_advanced_topics.md | 10 +-- doc/howto/online_lidar_advanced_topics_cn.md | 15 ++-- doc/howto/pcap_file_advanced_topics.md | 85 ++++++++++++++++++++ doc/howto/pcap_file_advanced_topics_CN.md | 83 +++++++++++++++++++ 4 files changed, 180 insertions(+), 13 deletions(-) create mode 100644 doc/howto/pcap_file_advanced_topics.md create mode 100644 doc/howto/pcap_file_advanced_topics_CN.md diff --git a/doc/howto/online_lidar_advanced_topics.md b/doc/howto/online_lidar_advanced_topics.md index 10ad9077..cbc5f443 100644 --- a/doc/howto/online_lidar_advanced_topics.md +++ b/doc/howto/online_lidar_advanced_topics.md @@ -1,8 +1,8 @@ -# Online Lidar - Advanced Topics +# Online LiDAR - Advanced Topics ## 1 Introduction -The RoboSense Lidar may work +The RoboSense LiDAR may work + in unicast/multicast/broadcast mode, + with VLAN layer @@ -13,8 +13,8 @@ This document illustrates how to configure rslidar_sdk in each case. Before reading this document, please be sure that you have read: + LiDAR user-guide -+ [Intro to parameters](../intro/parameter_intro.md) before reading this document -+ [Decode online Lidar](./how_to_decode_online_lidar.md) ++ [Intro to parameters](../intro/parameter_intro.md) ++ [Decode online LiDAR](./how_to_decode_online_lidar.md) ## 2 Unicast, Multicast and Broadcast @@ -81,7 +81,7 @@ lidar: host_address: 192.168.1.102 ``` -## 3 Multiple Lidars +## 3 Multiple LiDARs ### 3.1 Different remote ports diff --git a/doc/howto/online_lidar_advanced_topics_cn.md b/doc/howto/online_lidar_advanced_topics_cn.md index d7bd1ef3..d512024c 100644 --- a/doc/howto/online_lidar_advanced_topics_cn.md +++ b/doc/howto/online_lidar_advanced_topics_cn.md @@ -2,19 +2,18 @@ ## 1 简介 -+ RoboSense雷达可以工作在单播/组播/广播模式。 +RoboSense雷达可以工作在如下的场景。 -+ 可以运行在VLAN协议上。 ++ 单播/组播/广播模式。 ++ 运行在VLAN协议上。 ++ 向Packet加入用户自己的层。 ++ 接入多个雷达。 -+ 某些场景下,用户可以向Packet加入自己的层。 - -+ rslidar_sdk支持多个雷达。 - -本文描述在以上的场景下,如何配置rslidar_sdk。 +本文描述在这些场景下如何配置rslidar_sdk。 在阅读本文档之前, 请确保已经阅读过: + 雷达用户手册 -+ [参数介绍](../intro/parameter_intro_cn.md) before reading this document ++ [参数介绍](../intro/parameter_intro_cn.md) + [连接在线雷达](./how_to_decode_online_lidar_cn.md) ## 2 单播、组播、广播 diff --git a/doc/howto/pcap_file_advanced_topics.md b/doc/howto/pcap_file_advanced_topics.md new file mode 100644 index 00000000..f502e4e4 --- /dev/null +++ b/doc/howto/pcap_file_advanced_topics.md @@ -0,0 +1,85 @@ +# Online LiDAR - Advanced Topics + +## 1 Introduction + +The RoboSense LiDAR may work ++ in unicast/multicast/broadcast mode, ++ with VLAN layer ++ with user layers. ++ Also rslidar_sdk supports multi-LiDARs. + +This document illustrates how to configure rslidar_sdk in each case. + +Before reading this document, please be sure that you have read: ++ LiDAR user-guide ++ [Intro to parameters](../intro/parameter_intro.md) ++ [Online LiDAR - Advanced Topics](./online_lidar_advanced_topics_cn.md) + +## 2 General Case + +Generally, below code is for decoding a PCAP file in these cases. ++ Broadcast/multicast/unicast mode ++ There are multiple LiDars in a file. + +```yaml +common: + msg_source: 3 + send_point_cloud_ros: true + +lidar: + - driver: + lidar_type: RS32 + pcap_path: /home/robosense/lidar.pcap + msop_port: 6699 + difop_port: 7788 + ros: + ros_frame_id: rslidar + ros_send_point_cloud_topic: /rslidar_points +``` + +The only exception is "Multiple Lidars with same ports but different IPs", which is not supported now. + +## 3 VLAN + +In some user cases, The LiDar may work on VLAN. Its packets have a VLAN layer. + +![](./img/12_vlan_layer.png) + +rs_driver decodes PCAP file and gets all parts of MSOP packets, including the VLAN layer. + +To strip the VLAN layer, just set `use_vlan: true`. + +```yaml +lidar: + - driver: + lidar_type: RS32 + pcap_path: /home/robosense/lidar.pcap + msop_port: 6699 + difop_port: 7788 + use_vlan: true +``` + +## 4 User Layer, Tail Layer + +In some user cases, User may add extra layers before or/and after the MSOP/DIFOP packet. ++ USER_LAYER is before the packet and TAIL_LAYER is after it. + +![](./img/12_user_layer.png) + +These extra layers are parts of UDP data. The driver can strip them. + +To strip them, just give their lengths in bytes. + +In the following example, USER_LAYER is 8 bytes, and TAIL_LAYER is 4 bytes. + +```yaml +lidar: + - driver: + lidar_type: RS32 + pcap_path: /home/robosense/lidar.pcap + msop_port: 6699 + difop_port: 7788 + user_layer_bytes: 8 + tail_layer_bytes: 4 +``` + diff --git a/doc/howto/pcap_file_advanced_topics_CN.md b/doc/howto/pcap_file_advanced_topics_CN.md new file mode 100644 index 00000000..1dc69f57 --- /dev/null +++ b/doc/howto/pcap_file_advanced_topics_CN.md @@ -0,0 +1,83 @@ +# PCAP文件 - 高级主题 + +## 1 简介 + +RoboSense雷达可以工作在如下场景。 ++ 单播/组播/广播模式 ++ 运行在VLAN协议上 ++ 向Packet中加入用户自己的层 ++ 接入多个雷达 + +本文说明在每种场景下,如何配置rslidar_sdk。 + +在阅读本文之前,请先阅读: ++ 雷达用户使用手册 ++ [参数介绍](../intro/parameter_intro.md) ++ [在线雷达-高级主题](./online_lidar_advanced_topics_cn.md) + +## 2 一般场景 + +在下列场景下,使用如下配置解码PCAP文件。 ++ 广播/组播/单播模式 ++ PCAP文件中有多个雷达 + +```yaml +common: + msg_source: 3 + send_point_cloud_ros: true + +lidar: + - driver: + lidar_type: RS32 + pcap_path: /home/robosense/lidar.pcap + msop_port: 6699 + difop_port: 7788 + ros: + ros_frame_id: rslidar + ros_send_point_cloud_topic: /rslidar_points +``` + +一个例外是:PCAP文件中有多个雷达数据,但这些雷达目的端口相同,使用不同的目的IP地址来区分。这种情况不支持。 + +## 3 VLAN + +有些场景下,雷达工作在VLAN环境下。这时MSOP/DIFOP包带VLAN层,如下图。 + +![](./img/12_vlan_layer.png) + +rs_driver使用libpcap库解析PCAP文件,可以得到完整的、包括VLAN层的MSOP/DIFOP包。 + +要剥除VLAN层,只需要设置`use_vlan: true`。 + +```yaml +lidar: + - driver: + lidar_type: RS32 + pcap_path: /home/robosense/lidar.pcap + msop_port: 6699 + difop_port: 7788 + use_vlan: true +``` + +## 4 User Layer, Tail Layer + +某些场景下,用户可能在MSOP/DIFOP数据前后加入自己的层。 ++ USER_LAYER 在MSOP/DIFOP数据之前,TAIL_LAYER在MSOP/DIFOP数据之后。 + +![](./img/12_user_layer.png) + +这些层是UDP数据的一部分,所以rs_driver可以自己剥除他们。只需要告诉它每个层的字节数就可以。 + +如下的例子中,指定USER_LAYER为8字节,TAIL_LAYER为4字节。 + +```yaml +lidar: + - driver: + lidar_type: RS32 + pcap_path: /home/robosense/lidar.pcap + msop_port: 6699 + difop_port: 7788 + user_layer_bytes: 8 + tail_layer_bytes: 4 +``` + From f65c122694f0099ef66c6c4faa0479bd1ede82f3 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 31 Aug 2022 15:01:23 +0800 Subject: [PATCH 205/261] feat: update docs --- README.md | 14 +++++++++----- README_CN.md | 18 ++++++++++-------- ...pe_cn.md => how_to_change_point_type_CN.md} | 0 ..._cn.md => how_to_decode_online_lidar_CN.md} | 2 +- doc/howto/how_to_decode_pcap_file.md | 2 +- ...ile_cn.md => how_to_decode_pcap_file_CN.md} | 2 +- .../how_to_record_replay_packet_rosbag.md | 2 +- ...> how_to_record_replay_packet_rosbag_CN.md} | 2 +- ...how_to_use_coordinate_transformation_CN.md} | 2 +- ...n.md => how_to_use_protobuf_function_CN.md} | 2 +- ...n.md => online_lidar_advanced_topics_CN.md} | 4 ++-- doc/howto/pcap_file_advanced_topics.md | 4 ++-- doc/howto/pcap_file_advanced_topics_CN.md | 4 ++-- ...tro_cn.md => hiding_parameters_intro_CN.md} | 0 ...meter_intro_cn.md => parameter_intro_CN.md} | 0 ...ar_sdk_intro.md => rslidar_sdk_intro_CN.md} | 0 16 files changed, 32 insertions(+), 26 deletions(-) rename doc/howto/{how_to_change_point_type_cn.md => how_to_change_point_type_CN.md} (100%) rename doc/howto/{how_to_decode_online_lidar_cn.md => how_to_decode_online_lidar_CN.md} (96%) rename doc/howto/{how_to_decode_pcap_file_cn.md => how_to_decode_pcap_file_CN.md} (97%) rename doc/howto/{how_to_record_replay_packet_rosbag_cn.md => how_to_record_replay_packet_rosbag_CN.md} (94%) rename doc/howto/{how_to_use_coordinate_transformation_cn.md => how_to_use_coordinate_transformation_CN.md} (95%) rename doc/howto/{how_to_use_protobuf_function_cn.md => how_to_use_protobuf_function_CN.md} (98%) rename doc/howto/{online_lidar_advanced_topics_cn.md => online_lidar_advanced_topics_CN.md} (97%) rename doc/intro/{hiding_parameters_intro_cn.md => hiding_parameters_intro_CN.md} (100%) rename doc/intro/{parameter_intro_cn.md => parameter_intro_CN.md} (100%) rename doc/src_intro/{rslidar_sdk_intro.md => rslidar_sdk_intro_CN.md} (100%) diff --git a/README.md b/README.md index 66e60424..ae4eb187 100644 --- a/README.md +++ b/README.md @@ -193,17 +193,21 @@ To change behaviors of rslidar_sdk, change its parameters. please read the follo Below are some quick guides to use rslidar_sdk. -[Online connect lidar and send point cloud through ROS](doc/howto/how_to_decode_online_lidar.md) +[Connect to online LiDAR and send point cloud through ROS](doc/howto/how_to_decode_online_lidar.md) -[Decode pcap bag and send point cloud through ROS](doc/howto/how_to_decode_pcap_file.md) +[Decode PCAP file and send point cloud through ROS](doc/howto/how_to_decode_pcap_file.md) -[Record rosbag & Offline decode rosbag](doc/howto/how_to_record_replay_packet_rosbag.md) +[Change Point Type](doc/howto/how_to_change_point_type.md) ## 7 Advanced Topics -[Switch Point Type](doc/howto/how_to_change_point_type.md) +[Online Lidar - advanced topics](doc/howto/online_lidar_advanced_topics.md) -[Network configuration advanced topics](doc/howto/online_lidar_advanced_topics.md) +[PCAP file - advanced topics](doc/howto/pcap_file_advanced_topics.md) [Coordinate Transformation](doc/howto/how_to_use_coordinate_transformation.md) +[Record rosbag & Replay it](doc/howto/how_to_record_replay_packet_rosbag.md) + +## + diff --git a/README_CN.md b/README_CN.md index 7e1dc4ed..91ff7e80 100644 --- a/README_CN.md +++ b/README_CN.md @@ -182,25 +182,27 @@ ros2 launch rslidar_sdk start.py rslidar_sdk的功能通过配置参数文件来实现,请仔细阅读。 -[参数介绍](doc/intro/parameter_intro_cn.md) +[参数介绍](doc/intro/parameter_intro_CN.md) -[隐藏参数介绍](doc/intro/hiding_parameters_intro_cn.md) +[隐藏参数介绍](doc/intro/hiding_parameters_intro_CN.md) ## 6 快速上手 以下是一些常用功能的使用指南。 -[在线读取雷达数据发送到ROS](doc/howto/how_to_decode_online_lidar_cn.md) +[连接在线雷达数据并发送点云到ROS](doc/howto/how_to_decode_online_lidar_CN.md) -[离线解析PCAP包发送到ROS](doc/howto/how_to_decode_pcap_file_cn.md) +[解析PCAP包并发送点云到ROS](doc/howto/how_to_decode_pcap_file_CN.md) -[录制ROS数据包&离线解析ROS数据包](doc/howto/how_to_record_replay_packet_rosbag_cn.md) +[切换点类型](doc/howto/how_to_change_point_type_CN.md) ## 7 使用进阶 -[切换点的类型](doc/howto/how_to_change_point_type_cn.md) +[在线雷达-高级主题](doc/howto/online_lidar_advanced_topics_CN.md) -[网络配置的高级主题](doc/howto/online_lidar_advanced_topics_cn.md) +[PCAP文件-高级主题](doc/howto/pcap_file_advanced_topics_CN.md) -[坐标变换功能](doc/howto/how_to_use_coordinate_transformation_cn.md) +[点云坐标变换](doc/howto/how_to_use_coordinate_transformation_CN.md) + +[录制ROS数据包然后播放它](doc/howto/how_to_record_replay_packet_rosbag_CN.md) diff --git a/doc/howto/how_to_change_point_type_cn.md b/doc/howto/how_to_change_point_type_CN.md similarity index 100% rename from doc/howto/how_to_change_point_type_cn.md rename to doc/howto/how_to_change_point_type_CN.md diff --git a/doc/howto/how_to_decode_online_lidar_cn.md b/doc/howto/how_to_decode_online_lidar_CN.md similarity index 96% rename from doc/howto/how_to_decode_online_lidar_cn.md rename to doc/howto/how_to_decode_online_lidar_CN.md index 607e39a5..0a7ac74e 100644 --- a/doc/howto/how_to_decode_online_lidar_cn.md +++ b/doc/howto/how_to_decode_online_lidar_CN.md @@ -4,7 +4,7 @@ 本文档描述如何连接在线雷达,并发送点云数据到ROS。 -在阅读本文档之前, 请确保已经阅读过雷达用户手册和[参数简介](../intro/parameter_intro.md) 。 +在阅读本文档之前, 请确保已经阅读过雷达用户手册和[参数简介](../intro/parameter_intro_CN.md) 。 ## 2 步骤 diff --git a/doc/howto/how_to_decode_pcap_file.md b/doc/howto/how_to_decode_pcap_file.md index 7e51fb96..bd73fb63 100644 --- a/doc/howto/how_to_decode_pcap_file.md +++ b/doc/howto/how_to_decode_pcap_file.md @@ -4,7 +4,7 @@ This document illustrates how to decode PCAP file, and send point cloud to ROS. -Please make sure you have read the LiDAR user-guide and [Intro to parameters](doc/intro/parameter_intro.md) before reading this document. +Please make sure you have read the LiDAR user-guide and [Intro to parameters](../intro/parameter_intro.md) before reading this document. ## 2 Steps diff --git a/doc/howto/how_to_decode_pcap_file_cn.md b/doc/howto/how_to_decode_pcap_file_CN.md similarity index 97% rename from doc/howto/how_to_decode_pcap_file_cn.md rename to doc/howto/how_to_decode_pcap_file_CN.md index e739fd6c..596dfdc2 100644 --- a/doc/howto/how_to_decode_pcap_file_cn.md +++ b/doc/howto/how_to_decode_pcap_file_CN.md @@ -4,7 +4,7 @@ 本文档展示如何解码PCAP文件, 并发送点云数据到ROS。 -在阅读本文档之前,请确保已阅读雷达用户手册和 [参数简介](../intro/parameter_intro.md) 。 +在阅读本文档之前,请确保已阅读雷达用户手册和 [参数简介](../intro/parameter_intro_CN.md) 。 ## 2 步骤 diff --git a/doc/howto/how_to_record_replay_packet_rosbag.md b/doc/howto/how_to_record_replay_packet_rosbag.md index 803ff70f..ccd2a6ca 100644 --- a/doc/howto/how_to_record_replay_packet_rosbag.md +++ b/doc/howto/how_to_record_replay_packet_rosbag.md @@ -6,7 +6,7 @@ This document illustrates how to record and replay MSOP/DIFOP Packet rosbag. It is possible to record the point cloud message into a rosbag and replay it, but the point cloud rosbag is very large. rslidar_sdk provides a better way - record packet rosbag and replay it. -Please be sure you have read the LiDAR user-guide and [Online connect lidar and send point cloud through ROS](how_to_online_send_point_cloud_ros.md). +Please be sure you have read the LiDAR user-guide and [Connect to online LiDAR and send point cloud through ROS](how_to_decode_online_lidar.md). ## 2 Record diff --git a/doc/howto/how_to_record_replay_packet_rosbag_cn.md b/doc/howto/how_to_record_replay_packet_rosbag_CN.md similarity index 94% rename from doc/howto/how_to_record_replay_packet_rosbag_cn.md rename to doc/howto/how_to_record_replay_packet_rosbag_CN.md index 28b0e1a0..6600e1b6 100644 --- a/doc/howto/how_to_record_replay_packet_rosbag_cn.md +++ b/doc/howto/how_to_record_replay_packet_rosbag_CN.md @@ -6,7 +6,7 @@ 使用ROS可以录制点云rosbag消息并回放,但点云包非常大,所以rslidar_sdk提供更好的选择,也就是录制Packet rosbag并回放。 -在阅读本文档之前, 请先阅读雷达用户手册和 [在线连接雷达并发送点云到ROS](how_to_online_send_point_cloud_ros_cn.md) 。 +在阅读本文档之前, 请先阅读雷达用户手册和 [连接在线雷达并发送点云到ROS](./how_to_decode_online_lidar_CN.md) 。 ## 2 录制 diff --git a/doc/howto/how_to_use_coordinate_transformation_cn.md b/doc/howto/how_to_use_coordinate_transformation_CN.md similarity index 95% rename from doc/howto/how_to_use_coordinate_transformation_cn.md rename to doc/howto/how_to_use_coordinate_transformation_CN.md index 0d4b2157..6e45c1e7 100644 --- a/doc/howto/how_to_use_coordinate_transformation_cn.md +++ b/doc/howto/how_to_use_coordinate_transformation_CN.md @@ -4,7 +4,7 @@ rslidar_sdk支持对点云进行坐标变换,本文档展示如何作这种变换。 -在阅读本文档之前,请确保已阅读雷达用户手册和[隐藏参数介绍](../intro/hiding_parameters_intro.md)。 +在阅读本文档之前,请确保已阅读雷达用户手册和[隐藏参数介绍](../intro/hiding_parameters_intro_CN.md)。 ## 2 依赖库 diff --git a/doc/howto/how_to_use_protobuf_function_cn.md b/doc/howto/how_to_use_protobuf_function_CN.md similarity index 98% rename from doc/howto/how_to_use_protobuf_function_cn.md rename to doc/howto/how_to_use_protobuf_function_CN.md index 4888ccf5..a2fc7e5e 100644 --- a/doc/howto/how_to_use_protobuf_function_cn.md +++ b/doc/howto/how_to_use_protobuf_function_CN.md @@ -12,7 +12,7 @@ ## 2 通过Protobuf-UDP发送和接收 packets -​请阅读[参数简介](.. / intro / parameter_intro.md),了解基本的参数配置。 +请阅读[参数简介](../intro/parameter_intro_CN.md),了解基本的参数配置。 ### 2.1 PC-A(发送端) diff --git a/doc/howto/online_lidar_advanced_topics_cn.md b/doc/howto/online_lidar_advanced_topics_CN.md similarity index 97% rename from doc/howto/online_lidar_advanced_topics_cn.md rename to doc/howto/online_lidar_advanced_topics_CN.md index d512024c..b06570e8 100644 --- a/doc/howto/online_lidar_advanced_topics_cn.md +++ b/doc/howto/online_lidar_advanced_topics_CN.md @@ -13,8 +13,8 @@ RoboSense雷达可以工作在如下的场景。 在阅读本文档之前, 请确保已经阅读过: + 雷达用户手册 -+ [参数介绍](../intro/parameter_intro_cn.md) -+ [连接在线雷达](./how_to_decode_online_lidar_cn.md) ++ [参数介绍](../intro/parameter_intro_CN.md) ++ [连接在线雷达](./how_to_decode_online_lidar_CN.md) ## 2 单播、组播、广播 diff --git a/doc/howto/pcap_file_advanced_topics.md b/doc/howto/pcap_file_advanced_topics.md index f502e4e4..b01f8b76 100644 --- a/doc/howto/pcap_file_advanced_topics.md +++ b/doc/howto/pcap_file_advanced_topics.md @@ -1,4 +1,4 @@ -# Online LiDAR - Advanced Topics +# PCAP File - Advanced Topics ## 1 Introduction @@ -13,7 +13,7 @@ This document illustrates how to configure rslidar_sdk in each case. Before reading this document, please be sure that you have read: + LiDAR user-guide + [Intro to parameters](../intro/parameter_intro.md) -+ [Online LiDAR - Advanced Topics](./online_lidar_advanced_topics_cn.md) ++ [Online LiDAR - Advanced Topics](./online_lidar_advanced_topics.md) ## 2 General Case diff --git a/doc/howto/pcap_file_advanced_topics_CN.md b/doc/howto/pcap_file_advanced_topics_CN.md index 1dc69f57..35041690 100644 --- a/doc/howto/pcap_file_advanced_topics_CN.md +++ b/doc/howto/pcap_file_advanced_topics_CN.md @@ -12,8 +12,8 @@ RoboSense雷达可以工作在如下场景。 在阅读本文之前,请先阅读: + 雷达用户使用手册 -+ [参数介绍](../intro/parameter_intro.md) -+ [在线雷达-高级主题](./online_lidar_advanced_topics_cn.md) ++ [参数介绍](../intro/parameter_intro_CN.md) ++ [在线雷达-高级主题](./online_lidar_advanced_topics_CN.md) ## 2 一般场景 diff --git a/doc/intro/hiding_parameters_intro_cn.md b/doc/intro/hiding_parameters_intro_CN.md similarity index 100% rename from doc/intro/hiding_parameters_intro_cn.md rename to doc/intro/hiding_parameters_intro_CN.md diff --git a/doc/intro/parameter_intro_cn.md b/doc/intro/parameter_intro_CN.md similarity index 100% rename from doc/intro/parameter_intro_cn.md rename to doc/intro/parameter_intro_CN.md diff --git a/doc/src_intro/rslidar_sdk_intro.md b/doc/src_intro/rslidar_sdk_intro_CN.md similarity index 100% rename from doc/src_intro/rslidar_sdk_intro.md rename to doc/src_intro/rslidar_sdk_intro_CN.md From cc175fa45cf8b03ba64d15c44ba16a9c1a06627d Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 31 Aug 2022 15:14:21 +0800 Subject: [PATCH 206/261] feat: update docs --- doc/intro/hiding_parameters_intro.md | 2 +- doc/intro/hiding_parameters_intro_CN.md | 4 ++-- doc/intro/parameter_intro.md | 10 +++------- doc/intro/parameter_intro_CN.md | 12 ++++-------- 4 files changed, 10 insertions(+), 18 deletions(-) diff --git a/doc/intro/hiding_parameters_intro.md b/doc/intro/hiding_parameters_intro.md index d6a1d099..6bb498c7 100644 --- a/doc/intro/hiding_parameters_intro.md +++ b/doc/intro/hiding_parameters_intro.md @@ -65,7 +65,7 @@ lidar: - ```split_angle``` -- The angle(in degree) to split frames. Only be used when ```split_frame_mode = 1```. The default value is ```0```. - ```num_blks_split``` -- The number of blocks in one frame. Only be used when ```split_frame_mode = 3```. - ```wait_for_difop``` -- If ```false```, the driver will not wait for difop packet(including lidar configuration data, especially angle data to calculate x, y, z), and send out the point cloud immediately. The default value is ```true```. -- ```group_address``` -- If use multi-cast function, this parameter needs to be set correctly. For more details, please refer to [Multi-Cast](../howto/how_to_use_multi_cast_function.md) +- ```group_address``` -- If use multi-cast function, this parameter needs to be set correctly. For more details, please refer to [Online LiDAR - Advanced Topics](../howto/online_lidar_advanced_topics.md) - ```host_address``` -- Needed in two conditions. If the host receives packets from multiple Lidars via different IP addresses, use this parameter to specify destination IPs of the Lidars; If group_address is set, it should be set, so it will be joined into the multicast group. - ```x, y, z, roll, pitch, yaw ``` -- The parameters to do coordinate transformation. If the coordinate transformation function is enabled in driver core, the output point cloud will be transformed based on these parameters. For more details, please refer to [Coordinate Transformation](../howto/how_to_use_coordinate_transformation.md) - ```use_vlan``` -- Whether to use VLAN. The default value is ```false```. This parameter is only needed for pcap file. If it contains packets with VLAN layer, ```use_vlan``` should set to true. In the case of online Lidar, the VLAN layer is stripped by the protocol layer, so use_vlan can be ignored. diff --git a/doc/intro/hiding_parameters_intro_CN.md b/doc/intro/hiding_parameters_intro_CN.md index d684db71..631049cc 100644 --- a/doc/intro/hiding_parameters_intro_CN.md +++ b/doc/intro/hiding_parameters_intro_CN.md @@ -64,8 +64,8 @@ lidar: - ```split_angle``` -- 用于分帧的角度(单位为度), 在```split_frame_mode = 1``` 时才生效,默认值为```0```。 - ```num_blks_split``` -- 用于分帧的包数,在 ```split_frame_mode = 3```时才生效,默认值为1。 - ```wait_for_difop``` -- 若设置为false, 驱动将不会等待DIFOP包(包含配置数据,尤其是角度信息),而是立即解析MSOP包并发出点云。 默认值为```true```,也就是必须要有DIFOP包才会进行点云解析。 -- ```group_address``` -- 如果雷达为组播模式,此参数需要被设置为组播的地址。具体使用方式可以参考 [组播模式](../howto/how_to_use_multi_cast_function_cn.md) 。 +- ```group_address``` -- 如果雷达为组播模式,此参数需要被设置为组播的地址。具体使用方式可以参考[在线雷达 - 高级主题](../howto/online_lidar_advanced_topics_CN.md) 。 - ```host_address``` -- 有两种情况需要这个选项。如果主机上通过多个IP地址接收多个雷达的数据,则可以将此参数指定为雷达的目标IP;如果设置了group_address,那也需要设置host_address,以便将这个IP地址的网卡加入组播组。 -- ```x, y, z, roll, pitch, yaw ``` -- 坐标变换参数,若启用了内核的坐标变换功能,将会使用此参数输出经过变换后的点云。x, y, z, 单位为```米```, roll, pitch, yaw, 单位为```弧度```。具体使用方式可以参考 [坐标变换功能](../howto/how_to_use_coordinate_transformation_cn.md) 。 +- ```x, y, z, roll, pitch, yaw ``` -- 坐标变换参数,若启用了内核的坐标变换功能,将会使用此参数输出经过变换后的点云。x, y, z, 单位为```米```, roll, pitch, yaw, 单位为```弧度```。具体使用方式可以参考 [坐标变换功能](../howto/how_to_use_coordinate_transformation_CN.md) 。 - ```use_vlan``` -- 默认为false,指定是否使用vlan。如果pcap文件中的packet带vlan层,则需要设置这个选项为true。其他情况下不需要。在线雷达的情况下,协议层到达驱动时,已经剥离vlan层,所以不需要设置这个选项。 - ```use_someip``` -- 是否使用SOME/IP,默认为false。当数据包中有SOME/IP层,需要设置为true。 diff --git a/doc/intro/parameter_intro.md b/doc/intro/parameter_intro.md index 183c3a5a..ab06cfc3 100644 --- a/doc/intro/parameter_intro.md +++ b/doc/intro/parameter_intro.md @@ -25,15 +25,11 @@ common: - 0 -- Unused. Never set this parameter to 0. - - 1 -- LiDAR packets come from on-line LiDARs. For more details, please refer to [Online connect LiDAR and send point cloud through ROS](../howto/how_to_online_send_point_cloud_ros.md) + - 1 -- LiDAR packets come from on-line LiDARs. For more details, please refer to [Connect to online LiDAR and send point cloud through ROS](../howto/how_to_decode_online_lidar.md) - - 2 -- LiDAR packets come from ROS/ROS2. It is used to decode from an off-line rosbag. For more details, please refer to [Record rosbag & Offline decode rosbag](../howto/how_to_record_and_offline_decode_rosbag.md) + - 2 -- LiDAR packets come from ROS/ROS2. It is used to decode from an off-line rosbag. For more details, please refer to [Record rosbag & Replay it](../howto/how_to_record_replay_packet_rosbag.md) - - 3 -- LiDAR packets come from a PCAP bag. For more details, please refer to [Decode PCAP bag and send point cloud through ROS](../howto/how_to_offline_decode_pcap.md) - - - 4 -- LiDAR packets come from Protobuf-UDP. For more details, please refer to [Use protobuf send & receive](../howto/how_to_use_protobuf_function.md) - - - 5 -- LiDAR point cloud come from Protobuf-UDP. For more details, please refer to [Use protobuf send & receive](../howto/how_to_use_protobuf_function.md) + - 3 -- LiDAR packets come from a PCAP bag. For more details, please refer to [Decode PCAP file and send point cloud through ROS](../howto/how_to_decode_pcap_file.md) - send_packet_ros diff --git a/doc/intro/parameter_intro_CN.md b/doc/intro/parameter_intro_CN.md index 96f19e1d..6f7f3590 100644 --- a/doc/intro/parameter_intro_CN.md +++ b/doc/intro/parameter_intro_CN.md @@ -23,21 +23,17 @@ common: - msg_source - - 1 -- 连接在线雷达。更多使用细节,请参考[在线读取雷达数据发送到ROS](../howto/how_to_online_send_point_cloud_ros_cn.md)。 + - 1 -- 连接在线雷达。更多使用细节,请参考[连接在线雷达并发送点云到ROS](../howto/how_to_decode_online_lidar_CN.md)。 - - 2 -- 离线解析ROS/ROS2的Packet包。更多使用细节,请参考 [录制ROS数据包&离线解析ROS数据包](doc/howto/how_to_record_and_offline_decode_rosbag_cn.md)。 + - 2 -- 离线解析ROS/ROS2的Packet包。更多使用细节,请参考 [录制ROS数据包然后播放它](../howto/how_to_record_replay_packet_rosbag_CN.md)。 - - 3 -- 离线解析PCAP包。更多使用细节,请参考[离线解析PCAP包发送到ROS](doc/howto/how_to_offline_decode_pcap_cn.md)。 - - - 4 -- 雷达消息来源为Protobuf-UDP的Packet消息,更多使用细节,请参考 [使用Protobuf发送&接收](../howto/how_to_use_protobuf_function_cn.md)。 - - - 5 -- 雷达消息来源为Protobuf-UDP的点云消息,更多使用细节,请参考 [使用Protobuf发送&接收](../howto/how_to_use_protobuf_function_cn.md)。 + - 3 -- 离线解析PCAP包。更多使用细节,请参考[离线解析PCAP包并发送点云到ROS](../howto/how_to_decode_pcap_file_CN.md)。 - send_packet_ros - true -- 雷达Packet消息将通过ROS/ROS2发出 - *雷达ROS packet消息为速腾聚创自定义ROS消息,用户使用ROS/ROS2 echo命令不能查看消息的具体内容。这个功能用于录制ROS/ROS2的Packet包,更多使用细节,请参考 [录制ROS数据包&离线解析ROS数据包](doc/howto/how_to_record_and_offline_decode_rosbag_cn.md)。* + *雷达ROS packet消息为速腾聚创自定义ROS消息,用户使用ROS/ROS2 echo命令不能查看消息的具体内容。这个功能用于录制ROS/ROS2的Packet包,更多使用细节,请参考msg_source=2的情况。 - send_point_cloud_ros From eb79eb313c6899059321d0481d21bb2ae8b3c89a Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 31 Aug 2022 17:10:11 +0800 Subject: [PATCH 207/261] feat: update CHANGLOG --- CHANGELOG.md | 17 +++++++---------- src/rs_driver | 2 +- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6cef1f2..45718c41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,13 @@ -# ChangeLog +# CHANGELOG ## Unreleased +## v1.5.6 - 2022-09-01 + +### Added ++ Add a few build options according to rs_driver ++ Update help documents + ## v1.5.5 - 2022-08-01 ### Changed @@ -47,7 +53,6 @@ - Add different point types( XYZI & XYZIRT) ### Changed - - Update driver core, please refer to CHANGELOG in rs_driver for details - Update some documents - Change angle_path argument to hiding parameter @@ -57,15 +62,11 @@ - Remove RSAUTO for lidar type - Remove device_ip argument - - ## v1.2.1 - 2020-09-04 ### Fixed - - Fix bug in driver core, please refer to changelog in rs_driver for details. - ## v1.2.0 - 2020-09-01 ### Added @@ -75,11 +76,9 @@ - Update driver core, please refer to changelog in rs_driver for details - Update the compiler version from C++11 to C++14 - ## v1.1.0 - 2020-07-01 ### Added - - Add ROS2 support ### Changed @@ -93,9 +92,7 @@ ## v1.0.0 - 2020-06-01 ### Added - - New program structure - - Support ROS & Protobuf-UDP functions diff --git a/src/rs_driver b/src/rs_driver index 2eb41dcb..80178882 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 2eb41dcb774caa1bf23072ef933b7f4747e0c4de +Subproject commit 80178882e533d9b6121111f7a95be3cccec95d9a From d16b26d345a0d10329e061765187a95e247783da Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 1 Sep 2022 09:41:48 +0800 Subject: [PATCH 208/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 80178882..bc0ef3e6 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 80178882e533d9b6121111f7a95be3cccec95d9a +Subproject commit bc0ef3e66708ae3fd58add8f067f35703661f342 From 59d6dd454a860ae043f5eb2cf489a63d041c4828 Mon Sep 17 00:00:00 2001 From: Marcin Nagi Date: Mon, 12 Sep 2022 09:16:40 +0200 Subject: [PATCH 209/261] add ros2 parameter handle --- node/rslidar_sdk_node.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/node/rslidar_sdk_node.cpp b/node/rslidar_sdk_node.cpp index 546917e5..be310192 100644 --- a/node/rslidar_sdk_node.cpp +++ b/node/rslidar_sdk_node.cpp @@ -66,9 +66,8 @@ int main(int argc, char** argv) RS_TITLE << "********************************************************" << RS_REND; RS_TITLE << "********** **********" << RS_REND; - RS_TITLE << "********** RSLidar_SDK Version: v" << RSLIDAR_VERSION_MAJOR - << "." << RSLIDAR_VERSION_MINOR - << "." << RSLIDAR_VERSION_PATCH << " **********" << RS_REND; + RS_TITLE << "********** RSLidar_SDK Version: v" << RSLIDAR_VERSION_MAJOR << "." << RSLIDAR_VERSION_MINOR << "." + << RSLIDAR_VERSION_PATCH << " **********" << RS_REND; RS_TITLE << "********** **********" << RS_REND; RS_TITLE << "********************************************************" << RS_REND; @@ -81,17 +80,23 @@ int main(int argc, char** argv) std::string config_path; #ifdef RUN_IN_ROS_WORKSPACE - config_path = ros::package::getPath("rslidar_sdk"); + config_path = ros::package::getPath("rslidar_sdk"); #else - config_path = (std::string)PROJECT_PATH; + config_path = (std::string)PROJECT_PATH; #endif - config_path += "/config/config.yaml"; + config_path += "/config/config.yaml"; #ifdef ROS_FOUND ros::NodeHandle priv_hh("~"); std::string path; priv_hh.param("config_path", path, std::string("")); +#elif ROS2_FOUND + std::shared_ptr nd = rclcpp::Node::make_shared("param_handle"); + std::string path = nd->declare_parameter("config_path", ""); +#endif + +#if defined(ROS_FOUND) || defined(ROS2_FOUND) if (!path.empty()) { config_path = path; @@ -105,8 +110,7 @@ int main(int argc, char** argv) } catch (...) { - RS_ERROR << "The format of config file " << config_path - << " is wrong. Please check (e.g. indentation)." << RS_REND; + RS_ERROR << "The format of config file " << config_path << " is wrong. Please check (e.g. indentation)." << RS_REND; return -1; } From 35d8f52a7c80334f4657b5766bd46e8de8f4cfad Mon Sep 17 00:00:00 2001 From: Marcin Nagi Date: Mon, 12 Sep 2022 09:19:06 +0200 Subject: [PATCH 210/261] add logging of the configuration file path loading --- node/rslidar_sdk_node.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/node/rslidar_sdk_node.cpp b/node/rslidar_sdk_node.cpp index be310192..55813af4 100644 --- a/node/rslidar_sdk_node.cpp +++ b/node/rslidar_sdk_node.cpp @@ -107,6 +107,10 @@ int main(int argc, char** argv) try { config = YAML::LoadFile(config_path); + RS_INFO << "--------------------------------------------------------" << RS_REND; + RS_INFO << "Config loaded from PATH:" << RS_REND; + RS_INFO << config_path << RS_REND; + RS_INFO << "--------------------------------------------------------" << RS_REND; } catch (...) { From ae8c0f9bdbf301c5f01f73dd3a21393ada5972a1 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 23 Sep 2022 15:21:46 +0800 Subject: [PATCH 211/261] feat: remove dependency on protobuf lib --- src/manager/node_manager.cpp | 2 - src/msg/proto_msg/packet.proto | 9 - src/msg/proto_msg/point_cloud.proto | 16 - src/msg/proto_msg/scan.proto | 11 - src/source/source_packet_proto.hpp | 288 ----------------- src/source/source_pointcloud_proto.hpp | 242 -------------- src/utility/protobuf_communicator.hpp | 416 ------------------------- 7 files changed, 984 deletions(-) delete mode 100644 src/msg/proto_msg/packet.proto delete mode 100644 src/msg/proto_msg/point_cloud.proto delete mode 100644 src/msg/proto_msg/scan.proto delete mode 100644 src/source/source_packet_proto.hpp delete mode 100644 src/source/source_pointcloud_proto.hpp delete mode 100644 src/utility/protobuf_communicator.hpp diff --git a/src/manager/node_manager.cpp b/src/manager/node_manager.cpp index 01dae2cc..61cf8e54 100644 --- a/src/manager/node_manager.cpp +++ b/src/manager/node_manager.cpp @@ -34,8 +34,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "source/source_driver.hpp" #include "source/source_pointcloud_ros.hpp" #include "source/source_packet_ros.hpp" -#include "source/source_packet_proto.hpp" -#include "source/source_pointcloud_proto.hpp" namespace robosense { diff --git a/src/msg/proto_msg/packet.proto b/src/msg/proto_msg/packet.proto deleted file mode 100644 index 783636d1..00000000 --- a/src/msg/proto_msg/packet.proto +++ /dev/null @@ -1,9 +0,0 @@ -syntax="proto2"; -package proto_msg; - -message LidarPacket -{ - optional bytes data = 1; -} - - diff --git a/src/msg/proto_msg/point_cloud.proto b/src/msg/proto_msg/point_cloud.proto deleted file mode 100644 index 0f3d7635..00000000 --- a/src/msg/proto_msg/point_cloud.proto +++ /dev/null @@ -1,16 +0,0 @@ -syntax="proto2"; -package proto_msg; - -message LidarPointCloud -{ - optional double timestamp = 1; - optional uint32 seq = 2; - optional string frame_id = 3; - optional uint32 height=4; - optional uint32 width=5; - optional bool is_dense=6; - repeated float data = 7; - -} - - diff --git a/src/msg/proto_msg/scan.proto b/src/msg/proto_msg/scan.proto deleted file mode 100644 index d430f258..00000000 --- a/src/msg/proto_msg/scan.proto +++ /dev/null @@ -1,11 +0,0 @@ -syntax="proto2"; -package proto_msg; - -message LidarScan -{ - optional double timestamp = 1; - optional uint32 seq=2; - repeated bytes data = 3; -} - - diff --git a/src/source/source_packet_proto.hpp b/src/source/source_packet_proto.hpp deleted file mode 100644 index e39245cc..00000000 --- a/src/source/source_packet_proto.hpp +++ /dev/null @@ -1,288 +0,0 @@ -/********************************************************************************************************************* -Copyright (c) 2020 RoboSense -All rights reserved - -By downloading, copying, installing or using the software you agree to this license. If you do not agree to this -license, do not download, install, copy or use the software. - -License Agreement -For RoboSense LiDAR SDK Library -(3-clause BSD License) - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following -disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the names of the RoboSense, nor Suteng Innovation Technology, nor the names of other contributors may be used -to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*********************************************************************************************************************/ - -#pragma once - -#include "source/source.hpp" -//#include "utility/protobuf_communicator.hpp" -#include "rs_driver/utility/sync_queue.hpp" - -#include -#include - -#ifdef PROTO_FOUND - -constexpr size_t PKT_RECEIVE_BUF_SIZE = 2000000; - -class ProtoCommunicator; - -namespace robosense -{ -namespace lidar -{ - -class SourcePacketProto : public SourceDriver -{ -public: - - virtual void init(const YAML::Node& config); - virtual void start(); - virtual void stop(); - - SourcePacketProto(); - -private: - - int initSocket(uint16_t port); - - void recvPacket(); - void splicePacket(); - - //std::unique_ptr pkt_proto_com_ptr_; - //SyncQueue pkt_queue_; - std::thread recv_thread_; - std::thread splice_thread_; - int fd_; -}; - -SourcePacketProto::SourcePacketProto() - : SourceDriver(SourceType::MSG_FROM_PROTO_PACKET) -{ -} - -inline int SourcePacketProto::initSocket(uint16_t port) -{ - int fd; - int flags; - int ret; - - fd = socket(PF_INET, SOCK_DGRAM, 0); - if (fd < 0) - { - std::cerr << "socket: " << std::strerror(errno) << std::endl; - goto failSocket; - } - - struct sockaddr_in host_addr; - memset(&host_addr, 0, sizeof(host_addr)); - host_addr.sin_family = AF_INET; - host_addr.sin_port = htons(port); - host_addr.sin_addr.s_addr = INADDR_ANY; - ret = bind(fd, (struct sockaddr*)&host_addr, sizeof(host_addr)); - if (ret < 0) - { - std::cerr << "bind: " << std::strerror(errno) << std::endl; - goto failBind; - } - - flags = fcntl(fd, F_GETFL, 0); - ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK); - if (ret < 0) - { - std::cerr << "setsockopt: " << std::strerror(errno) << std::endl; - goto failNonBlock; - } - - fd_ = fd; - return 0; - -failNonBlock: -failBind: - close(fd); -failSocket: - return -1; -} - -void SourcePacketProto::init(const YAML::Node& config) -{ - SourceDriver::init(config); - - uint16_t packet_recv_port; - yamlReadAbort(config["proto"], "packet_recv_port", packet_recv_port); - -#if 0 - pkt_proto_com_ptr_.reset(new ProtoCommunicator); - int ret = pkt_proto_com_ptr_->initReceiver(packet_recv_port); - if (ret < 0) - { - RS_ERROR << "Failed to create UDP receiver socket failed or bind." << RS_REND; - exit(-1); - } -#endif -} - -inline void SourcePacketProto::start() -{ - recv_thread_ = std::thread(std::bind(&SourcePacketProto::recvPacket, this)); - splice_thread_ = std::thread(std::bind(&SourcePacketProto::splicePacket, this)); -} - -inline void SourcePacketProto::stop() -{ - recv_thread_.join(); - splice_thread_.join(); -} - -inline void SourcePacketProto::recvPacket() -{ -#if 0 - while (1) - { - void* p_data = malloc(MAX_RECEIVE_LENGTH); - - ProtoMsgHeader tmp_header; - int ret = packet_proto_com_ptr_->receiveProtoMsg(p_data, MAX_RECEIVE_LENGTH, tmp_header); - if (ret < 0) - { - continue; - } - - pkt_queue_.push(std::make_pair(p_data, tmp_header)); - } -#endif -} - -inline void SourcePacketProto::splicePacket() -{ -#if 0 - while (1) - { - auto pair = pkt_queue_.pop(); - - proto_msg::LidarPacket protomsg; - protomsg.ParseFromArray(pair.first, pair.second.msg_length); - - _driver_ptr_->decodePacket(toRsMsg(protomsg)); - - free(pkt_queue_.front().first); - } -#endif -} - -class DestinationPacketProto : public DestinationPacket -{ -public: - - virtual void init(const YAML::Node& config); - virtual void start(); - virtual void stop(); - virtual void sendPacket(const Packet& msg); - virtual ~DestinationPacketProto(); - -private: - - int initSocket(uint16_t dst_port, const std::string& dst_ip); - - void internSendPacket(); - - SyncQueue pkt_queue_; - std::thread send_thread_; - bool to_exit_; - int fd_; - struct sockaddr_in dst_addr_; -}; - - -inline void DestinationPacketProto::init(const YAML::Node& config) -{ - uint16_t packet_send_port; - yamlReadAbort(config["proto"], "packet_send_port", packet_send_port); - std::string packet_send_ip; - yamlReadAbort(config["proto"], "packet_send_ip", packet_send_ip); - - if (initSocket(packet_send_port, packet_send_ip) < 0) - { - RS_ERROR << "DestinationPacketProto: failed to create UDP sender socket." << RS_REND; - exit(-1); - } -} - -int DestinationPacketProto::initSocket(uint16_t dst_port, const std::string& dst_ip) -{ - struct sockaddr_in dst_addr = {0}; - dst_addr.sin_family = AF_INET; - dst_addr.sin_port = htons(dst_port); - dst_addr.sin_addr.s_addr = inet_addr(dst_ip.c_str()); - - int fd = socket(PF_INET, SOCK_DGRAM, 0); - if (fd < 0) - { - std::cerr << "socket: " << std::strerror(errno) << std::endl; - goto failSocket; - } - - memcpy (&dst_addr_, &dst_addr, sizeof(dst_addr)); - fd_ = fd; - return 0; - -failSocket: - return -1; -} - -inline void DestinationPacketProto::start() -{ - send_thread_ = std::thread(std::bind(&DestinationPacketProto::internSendPacket, this)); -} - -inline void DestinationPacketProto::stop() -{ - to_exit_ = true; - send_thread_.join(); -} - -inline DestinationPacketProto::~DestinationPacketProto() -{ - stop(); -} - -inline void DestinationPacketProto::sendPacket(const Packet& msg) -{ - pkt_queue_.push(msg); -} - -inline void DestinationPacketProto::internSendPacket() -{ -#if 0 - PacketMsg msg = pkt_send_queue_.popWait(1000); - - proto_msg::LidarPacket proto_msg = toProtoMsg(msg); - if (!packet_proto_com_ptr_->sendSingleMsg(proto_msg)) - { - RS_WARNING << "Difop packets Protobuf sending error" << RS_REND; - } -#endif -} - -} // namespace lidar -} // namespace robosense -#endif // PROTO_FOUND - diff --git a/src/source/source_pointcloud_proto.hpp b/src/source/source_pointcloud_proto.hpp deleted file mode 100644 index 20d1f255..00000000 --- a/src/source/source_pointcloud_proto.hpp +++ /dev/null @@ -1,242 +0,0 @@ -/********************************************************************************************************************* -Copyright (c) 2020 RoboSense -All rights reserved - -By downloading, copying, installing or using the software you agree to this license. If you do not agree to this -license, do not download, install, copy or use the software. - -License Agreement -For RoboSense LiDAR SDK Library -(3-clause BSD License) - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following -disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the names of the RoboSense, nor Suteng Innovation Technology, nor the names of other contributors may be used -to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*********************************************************************************************************************/ - -#pragma once - -#ifdef PROTO_FOUND - -#include "source/source.hpp" -//#include "utility/protobuf_communicator.hpp" - -constexpr size_t RECEIVE_BUF_SIZE = 10000000; - -namespace robosense -{ -namespace lidar -{ - -class SourcePointCloudProto : public Source -{ -public: - - virtual void init(const YAML::Node& config); - virtual void start(); - virtual void stop(); - virtual ~SourcePointCloudProto(); - - SourcePointCloudProto(); - -private: - - void recvPointCloud(); - void splicePointCloud(); - - //std::unique_ptr proto_com_ptr_; - //SyncQueue> point_cloud_recv_queue_; - std::thread recv_thread_; - int old_frmnum_; - int new_frmnum_; -}; - -SourcePointCloudProto::SourcePointCloudProto() - : Source(SourceType::MSG_FROM_PROTO_POINTCLOUD) -{ -} - -inline void SourcePointCloudProto::init(const YAML::Node& config) -{ - uint16_t point_cloud_recv_port; - yamlReadAbort(config["proto"], "point_cloud_recv_port", point_cloud_recv_port); - -#if 0 - proto_com_ptr_.reset(new ProtoCommunicator); - int ret = proto_com_ptr_->initReceiver(point_cloud_recv_port); - if (ret < 0) - { - RS_ERROR << "Create UDP Receiver Socket failed or Bind Network failed!" << RS_REND; - exit(-1); - } -#endif -} - -inline void SourcePointCloudProto::start() -{ - recv_thread_ = std::thread(std::bind(&SourcePointCloudProto::recvPointCloud, this)); -} - -inline void SourcePointCloudProto::stop() -{ - recv_thread_.join(); -} - -inline SourcePointCloudProto::~SourcePointCloudProto() -{ - stop(); -} - -inline void SourcePointCloudProto::recvPointCloud() -{ -#if 0 - bool start_check = true; - while (recv_thread_.start_.load()) - { - void* p_data = malloc(MAX_RECEIVE_LENGTH); - ProtoMsgHeader tmp_header; - int ret = proto_com_ptr_->receiveProtoMsg(p_data, MAX_RECEIVE_LENGTH, tmp_header); - if (start_check) - { - if (tmp_header.msg_id == 0) - { - start_check = false; - } - else - { - continue; - } - } - - if (ret < 0) - { - RS_WARNING << "PointCloud Protobuf receiving error" << RS_REND; - continue; - } - - point_cloud_recv_queue_.push(std::make_pair(p_data, tmp_header)); - - if (point_cloud_recv_queue_.is_task_finished_.load()) - { - point_cloud_recv_queue_.is_task_finished_.store(false); - thread_pool_ptr_->commit([&]() { splicePoints(); }); - } - } -#endif -} - -inline void SourcePointCloudProto::splicePointCloud() -{ -#if 0 - while (point_cloud_recv_queue_.size() > 0) - { - if (recv_thread_.start_.load()) - { - auto pair = point_cloud_recv_queue_.front(); - old_frmnum_ = new_frmnum_; - new_frmnum_ = pair.second.frame_num; - memcpy((uint8_t*)buff_ + pair.second.msg_id * SPLIT_SIZE, pair.first, SPLIT_SIZE); - if ((old_frmnum_ == new_frmnum_) && (pair.second.msg_id == pair.second.total_msg_cnt - 1)) - { - proto_msg::LidarPointCloud proto_msg; - proto_msg.ParseFromArray(buff_, pair.second.total_msg_length); - - // sendPointCloud(toRsMsg(proto_msg)); - } - } - free(point_cloud_recv_queue_.front().first); - point_cloud_recv_queue_.pop(); - } -#endif -} - -class DestinationPointCloudProto : public DestinationPointCloud -{ -public: - - virtual void init(const YAML::Node& config); - virtual void start(); - virtual void stop(); - virtual void sendPointCloud(const LidarPointCloudMsg& msg); - virtual ~DestinationPointCloudProto() = default; - -private: - - void internSendPointCloud(); - - //std::unique_ptr proto_com_ptr_; - std::thread send_thread_; - //SyncQueue point_cloud_send_queue_; - bool to_exit_; -}; - -inline void DestinationPointCloudProto::init(const YAML::Node& config) -{ - std::string point_cloud_send_port; - yamlReadAbort(config["proto"], "point_cloud_send_port", point_cloud_send_port); - std::string point_cloud_send_ip; - yamlReadAbort(config["proto"], "point_cloud_send_ip", point_cloud_send_ip); - -#if 0 - proto_com_ptr_.reset(new ProtoCommunicator); - int ret = proto_com_ptr_->initSender(point_cloud_send_port, point_cloud_send_ip); - if (ret < 0) - { - RS_ERROR << "Create UDP Sender Socket failed ! " << RS_REND; - exit(-1); - } -#endif -} - -inline void DestinationPointCloudProto::start() -{ - send_thread_ = - std::thread(std::bind(&DestinationPointCloudProto::internSendPointCloud, this)); -} - -inline void DestinationPointCloudProto::stop() -{ - to_exit_ = true; - send_thread_.join(); -} - -inline void DestinationPointCloudProto::sendPointCloud(const LidarPointCloudMsg& msg) -{ - //point_cloud_send_queue_.push(msg); -} - -inline void DestinationPointCloudProto::internSendPointCloud() -{ -#if 0 - while (point_cloud_send_queue_.size() > 0) - { - proto_msg::LidarPointCloud proto_msg = toProtoMsg(point_cloud_send_queue_.popFront()); - if (!proto_com_ptr_->sendSplitMsg(proto_msg)) - { - RS_WARNING << "PointCloud Protobuf sending error" << RS_REND; - } - } - point_cloud_send_queue_.is_task_finished_.store(true); -#endif -} - -} // namespace lidar -} // namespace robosense - -#endif // PROTO_FOUND diff --git a/src/utility/protobuf_communicator.hpp b/src/utility/protobuf_communicator.hpp deleted file mode 100644 index 08fc03d6..00000000 --- a/src/utility/protobuf_communicator.hpp +++ /dev/null @@ -1,416 +0,0 @@ -/********************************************************************************************************************* -Copyright (c) 2020 RoboSense -All rights reserved - -By downloading, copying, installing or using the software you agree to this license. If you do not agree to this -license, do not download, install, copy or use the software. - -License Agreement -For RoboSense LiDAR SDK Library -(3-clause BSD License) - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following -disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the names of the RoboSense, nor Suteng Innovation Technology, nor the names of other contributors may be used -to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*********************************************************************************************************************/ - -#pragma once - -#ifdef PROTO_FOUND - -#if 0 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif -#include -#if 0 -#include -#include -#include -#endif - -#define SPLIT_SIZE 5000 - -#define MAX_RECEIVE_LENGTH 5200 - -namespace robosense -{ -namespace lidar -{ - -enum class DataEndianType -{ - RS_BIG_ENDIAN = 0, - RS_SMALL_ENDIAN = 1 -}; - -template -class CRSEndian -{ -public: - typedef typename std::shared_ptr Ptr; - typedef typename std::shared_ptr ConstPtr; - -public: - CRSEndian() - { - unsigned char* p_char = (unsigned char*)(&magic_data_); - if (*p_char == magic_big_endian_[0] && (*(p_char + 1)) == magic_big_endian_[1] && - (*(p_char + 2)) == magic_big_endian_[2] && (*(p_char + 3)) == magic_big_endian_[3]) - { - host_endian_type_ = DataEndianType::RS_BIG_ENDIAN; - } - else - { - host_endian_type_ = DataEndianType::RS_SMALL_ENDIAN; - } - } - -public: - DataEndianType getHostEndian() - { - return host_endian_type_; - } - - int toTargetEndianArray(T t, void* p_array, const unsigned int& max_size, const DataEndianType& dst_endian) - { - unsigned int t_size = sizeof(T); - assert(t_size <= max_size); - assert(p_array != nullptr); - if (host_endian_type_ != dst_endian) - { - char* p_data_ = (char*)(&t); - unsigned int t_size_h = t_size / 2; - for (unsigned int idx = 0; idx < t_size_h; ++idx) - { - char tmp = p_data_[idx]; - unsigned int swapIdx = t_size - idx - 1; - p_data_[idx] = p_data_[swapIdx]; - p_data_[swapIdx] = tmp; - } - } - memcpy(p_array, &t, t_size); - return 0; - } - - int toHostEndianValue(T& t, const void* p_array, const unsigned int& max_size, const DataEndianType& src_endian) - { - unsigned int t_size = sizeof(T); - assert(p_array != nullptr); - assert(t_size <= max_size); - if (src_endian != host_endian_type_) - { - char* p_data_ = (char*)(p_array); - unsigned int t_size_h = t_size / 2; - for (unsigned idx = 0; idx < t_size_h; ++idx) - { - char tmp = p_data_[idx]; - unsigned int swapIdx = t_size - idx - 1; - p_data_[idx] = p_data_[swapIdx]; - p_data_[swapIdx] = tmp; - } - } - memcpy(&t, p_array, t_size); - return 0; - } - -private: - DataEndianType host_endian_type_; - const unsigned int magic_data_ = 0xA1B2C3D4; - const unsigned char magic_small_endian_[4] = { (unsigned char)0xD4, (unsigned char)0xC3, (unsigned char)0xB2, - (unsigned char)0xA1 }; - const unsigned char magic_big_endian_[4] = { (unsigned char)0xA1, (unsigned char)0xB2, (unsigned char)0xC3, - (unsigned char)0xD4 }; -}; - -struct alignas(16) ProtoMsgHeader -{ - unsigned int frame_num; - unsigned int total_msg_cnt; - unsigned int msg_id; - unsigned int msg_length; - unsigned int total_msg_length; - - ProtoMsgHeader() - { - frame_num = 0; - total_msg_cnt = 0; - msg_id = 0; - msg_length = 0; - total_msg_length = 0; - } - bool toTargetEndianArray(char* p_array, const unsigned int maxArraySize, - const DataEndianType dst_endian = DataEndianType::RS_BIG_ENDIAN) const - { - if (p_array == nullptr || maxArraySize < sizeof(ProtoMsgHeader)) - { - return false; - } - - CRSEndian uint32Endian; - CRSEndian uint64Endian; - - int offset = 0; - uint32Endian.toTargetEndianArray(frame_num, p_array + offset, maxArraySize - offset, dst_endian); - - offset += sizeof(unsigned int); - uint32Endian.toTargetEndianArray(total_msg_cnt, p_array + offset, maxArraySize - offset, dst_endian); - - offset += sizeof(unsigned int); - uint32Endian.toTargetEndianArray(msg_id, p_array + offset, maxArraySize - offset, dst_endian); - - offset += sizeof(unsigned int); - uint32Endian.toTargetEndianArray(msg_length, p_array + offset, maxArraySize - offset, dst_endian); - - offset += sizeof(unsigned int); - uint32Endian.toTargetEndianArray(total_msg_length, p_array + offset, maxArraySize - offset, dst_endian); - return true; - } - bool toHostEndianValue(const char* p_array, const unsigned int arraySize, - const DataEndianType src_endian = DataEndianType::RS_BIG_ENDIAN) - { - if (p_array == nullptr || arraySize < sizeof(ProtoMsgHeader)) - { - return false; - } - CRSEndian uint32Endian; - CRSEndian uint64Endian; - - int offset = 0; - uint32Endian.toHostEndianValue(frame_num, p_array + offset, arraySize - offset, src_endian); - - offset += sizeof(unsigned int); - uint32Endian.toHostEndianValue(total_msg_cnt, p_array + offset, arraySize - offset, src_endian); - - offset += sizeof(unsigned int); - uint32Endian.toHostEndianValue(msg_id, p_array + offset, arraySize - offset, src_endian); - - offset += sizeof(unsigned int); - uint32Endian.toHostEndianValue(msg_length, p_array + offset, arraySize - offset, src_endian); - - offset += sizeof(unsigned int); - uint32Endian.toHostEndianValue(total_msg_length, p_array + offset, arraySize - offset, src_endian); - return true; - } -}; -using boost::asio::deadline_timer; -using boost::asio::ip::udp; -/** - * @brief Protobuf UDP transmission basic class - * @note Initialize socket sender and receiver, and define send function and receive function - */ -class ProtoCommunicator -{ -public: - ProtoCommunicator() = default; - ~ProtoCommunicator() = default; - - /** - * @brief intilize the socket sender - * @param proto_send_port: destination port - * @param proto_send_ip: destination IP address - * @retval 0: success -1: failed - */ - inline int initSender(std::string proto_send_port, std::string proto_send_ip) - { - try - { - send_sock_ptr_.reset(new udp::socket(io_service_, udp::endpoint(udp::v4(), 0))); - boost::asio::socket_base::broadcast option(true); - send_sock_ptr_->set_option(option); - udp::resolver resolver(io_service_); - udp::resolver::query query(udp::v4(), proto_send_ip, proto_send_port); - iterator_ = resolver.resolve(query); - } - catch (...) - { - RS_ERROR << "Proto Sender Port is already used! Abort!" << RS_REND; - exit(-1); - } - return 0; - } - /** - * @brief Initialize the socket receiver - * @param proto_recv_port: the receiver port number - * @retval 0:success -1:failed - */ - inline int initReceiver(uint16_t proto_recv_port) - { - try - { - recv_sock_ptr_.reset(new udp::socket(io_service_, udp::endpoint(udp::v4(), proto_recv_port))); - deadline_.reset(new deadline_timer(io_service_)); - } - catch (...) - { - RS_ERROR << "Proto Receiver Port is already used! Abort!" << RS_REND; - exit(-1); - } - deadline_->expires_at(boost::posix_time::pos_infin); - checkDeadline(); - return 0; - } - - /* message send function & message receive function */ - /** - * @brief the message send function - * @note serialize the message to protobuf and send it - * @param *pMsgData: data - * @param &header: header - * @retval >=0 : success -1: failed - */ - inline int sendProtoMsg(const void* pMsgData, const ProtoMsgHeader& header) - { - int sendLen = header.msg_length + sizeof(ProtoMsgHeader); - char* sendBuffer = (char*)malloc(sendLen); - memset(sendBuffer, 0, sendLen); - header.toTargetEndianArray(sendBuffer, sizeof(ProtoMsgHeader), DataEndianType::RS_BIG_ENDIAN); - if (header.msg_length > 0) - { - memcpy(sendBuffer + sizeof(ProtoMsgHeader), pMsgData, header.msg_length); - } - int ret = send_sock_ptr_->send_to(boost::asio::buffer(sendBuffer, sendLen), *iterator_); - free(sendBuffer); - return ret; - } - /** - * @brief message receive function - * @note receive the message and deserilize it - * @param *pMsgData: the output message - * @param msgMaxLen: max receive message length - * @param &header: output header - * @retval >=0: success -1: failed - */ - inline int receiveProtoMsg(void* pMsgData, const int msgMaxLen, ProtoMsgHeader& header) - { - deadline_->expires_from_now(boost::posix_time::seconds(1)); - boost::system::error_code ec = boost::asio::error::would_block; - std::size_t ret = 0; - char* pRecvBuffer = (char*)malloc(msgMaxLen + sizeof(ProtoMsgHeader)); - recv_sock_ptr_->async_receive(boost::asio::buffer(pRecvBuffer, msgMaxLen + sizeof(ProtoMsgHeader)), - boost::bind(&ProtoCommunicator::handleReceive, _1, _2, &ec, &ret)); - do - { - io_service_.run_one(); - } while (ec == boost::asio::error::would_block); - if (ec) - { - free(pRecvBuffer); - return -1; - } - header.toHostEndianValue(pRecvBuffer, sizeof(ProtoMsgHeader), DataEndianType::RS_BIG_ENDIAN); - if (ret < (std::size_t)(header.msg_length + sizeof(ProtoMsgHeader))) - { - free(pRecvBuffer); - return -1; - } - if (header.msg_length > 0) - { - memcpy(pMsgData, pRecvBuffer + sizeof(ProtoMsgHeader), header.msg_length); - } - free(pRecvBuffer); - return ret; - } - - template - bool sendSplitMsg(const T& msg) - { - void* buf = malloc(msg.ByteSize() + SPLIT_SIZE); - msg.SerializeToArray(buf, msg.ByteSize()); - int pkt_num = ceil(1.0 * msg.ByteSize() / SPLIT_SIZE); - ProtoMsgHeader tmp_header; - tmp_header.frame_num = msg.seq(); - tmp_header.msg_length = SPLIT_SIZE; - tmp_header.total_msg_cnt = pkt_num; - tmp_header.total_msg_length = msg.ByteSize(); - for (int i = 0; i < pkt_num; i++) - { - tmp_header.msg_id = i; - void* tmp_buf = malloc(SPLIT_SIZE); - memcpy(tmp_buf, (uint8_t*)buf + i * SPLIT_SIZE, SPLIT_SIZE); - if (sendProtoMsg(tmp_buf, tmp_header) == -1) - { - free(tmp_buf); - free(buf); - return false; - } - free(tmp_buf); - usleep(2); - } - free(buf); - return true; - } - - template - bool sendSingleMsg(const T& msg) - { - ProtoMsgHeader tmp_header; - tmp_header.msg_length = msg.ByteSize(); - void* buf = malloc(tmp_header.msg_length); - msg.SerializeToArray(buf, tmp_header.msg_length); - if (sendProtoMsg(buf, tmp_header) == -1) - { - free(buf); - return false; - } - free(buf); - return true; - } - -private: - inline void checkDeadline() - { - if (deadline_->expires_at() <= deadline_timer::traits_type::now()) - { - recv_sock_ptr_->cancel(); - deadline_->expires_at(boost::posix_time::pos_infin); - } - deadline_->async_wait(boost::bind(&ProtoCommunicator::checkDeadline, this)); - } - static void handleReceive(const boost::system::error_code& ec, std::size_t length, boost::system::error_code* out_ec, - std::size_t* out_length) - { - *out_ec = ec; - *out_length = length; - } - -private: - /* UDP socket related varibles */ - boost::asio::io_service io_service_; - udp::resolver::iterator iterator_; - std::unique_ptr send_sock_ptr_; - std::unique_ptr recv_sock_ptr_; - std::unique_ptr deadline_; -}; - -} // namespace lidar -} // namespace robosense -#endif - -#endif // PROTO_FOUND - From d74c1f8c42b468a3ab9f1fd00f9671d414101e45 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Fri, 23 Sep 2022 18:09:58 +0800 Subject: [PATCH 212/261] format: format cmake scripts --- CMakeLists.txt | 98 +++++++++++++++++++++++++------------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a9493178..0fed17d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,19 +1,16 @@ - cmake_minimum_required(VERSION 3.5) - cmake_policy(SET CMP0048 NEW) - project(rslidar_sdk) #======================================= -# Compile setup (ORIGINAL, CATKIN, COLCON) +# Custom Point Type (XYZI, XYZIRT) #======================================= -set(COMPILE_METHOD CATKIN) +set(POINT_TYPE XYZI) #======================================= -# Custom Point Type (XYZI, XYZIRT) +# Compile setup (ORIGINAL, CATKIN, COLCON) #======================================= -set(POINT_TYPE XYZI) +set(COMPILE_METHOD CATKIN) option(ENABLE_TRANSFORM "Enable transform functions" OFF) if(${ENABLE_TRANSFORM}) @@ -50,16 +47,34 @@ set(PROJECT_NAME rslidar_sdk) add_definitions(-DPROJECT_PATH="${PROJECT_SOURCE_DIR}") -set(CMAKE_BUILD_TYPE RELEASE) -add_definitions(-O3) +if (CMAKE_BUILD_TYPE STREQUAL "") + set(CMAKE_BUILD_TYPE Release) + add_definitions(-O3) +endif() + add_definitions(-std=c++14) add_compile_options(-Wall) +#======================== +# Point Type Definition +#======================== +if(${POINT_TYPE} STREQUAL "XYZI") + add_definitions(-DPOINT_TYPE_XYZI) +elseif(${POINT_TYPE} STREQUAL "XYZIRT") + add_definitions(-DPOINT_TYPE_XYZIRT) +endif() + +message(=============================================================) +message("-- POINT_TYPE is ${POINT_TYPE}") +message(=============================================================) + #======================== # Dependencies Setup #======================== + #ROS# find_package(roscpp 1.12 QUIET) + if(roscpp_FOUND) message(=============================================================) @@ -72,14 +87,33 @@ if(roscpp_FOUND) include_directories(${roscpp_INCLUDE_DIRS} ${roslib_INCLUDE_DIRS}) set(ROS_LIBS ${roscpp_LIBRARIES} ${roslib_LIBRARIES}) + #Catkin# + if(${COMPILE_METHOD} STREQUAL "CATKIN") + + add_definitions(-DRUN_IN_ROS_WORKSPACE) + + find_package(catkin REQUIRED COMPONENTS + roscpp + sensor_msgs + roslib) + + catkin_package(CATKIN_DEPENDS + sensor_msgs + roslib) + + endif(${COMPILE_METHOD} STREQUAL "CATKIN") + else(roscpp_FOUND) + message(=============================================================) message("-- ROS Not Found, Ros Support is turned Off!") message(=============================================================) + endif(roscpp_FOUND) #ROS2# find_package(rclcpp QUIET) + if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") message(=============================================================) @@ -96,6 +130,7 @@ if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") find_package(std_msgs REQUIRED) else(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") + message(=============================================================) message("-- ROS2 Not Found. Ros2 Support is turned Off!") message(=============================================================) @@ -105,22 +140,6 @@ endif(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") #Others# find_package(yaml-cpp REQUIRED) -#Catkin# -if(${COMPILE_METHOD} STREQUAL "CATKIN") - - add_definitions(-DRUN_IN_ROS_WORKSPACE) - - find_package(catkin REQUIRED COMPONENTS - roscpp - sensor_msgs - roslib) - - catkin_package(CATKIN_DEPENDS - sensor_msgs - roslib) - -endif(${COMPILE_METHOD} STREQUAL "CATKIN") - #Include directory# include_directories(${PROJECT_SOURCE_DIR}/src) @@ -129,19 +148,6 @@ add_subdirectory(src/rs_driver) find_package(rs_driver REQUIRED) include_directories(${rs_driver_INCLUDE_DIRS}) -#======================== -# Point Type Definition -#======================== -if(${POINT_TYPE} STREQUAL "XYZI") -add_definitions(-DPOINT_TYPE_XYZI) -elseif(${POINT_TYPE} STREQUAL "XYZIRT") -add_definitions(-DPOINT_TYPE_XYZIRT) -endif() - -message(=============================================================) -message("-- POINT_TYPE is ${POINT_TYPE}") -message(=============================================================) - #======================== # Build Setup #======================== @@ -157,22 +163,16 @@ target_link_libraries(rslidar_sdk_node #Ros# if(roscpp_FOUND) - target_link_libraries(rslidar_sdk_node ${ROS_LIBS}) + target_link_libraries(rslidar_sdk_node + ${ROS_LIBS}) if(${COMPILE_METHOD} STREQUAL "CATKIN") + install(TARGETS rslidar_sdk_node RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}) - install(DIRECTORY launch/ - DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch - PATTERN ".svn" EXCLUDE) - install(DIRECTORY config/ - DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/config - PATTERN ".svn" EXCLUDE) - install(DIRECTORY rviz/ - DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/rviz - PATTERN ".svn" EXCLUDE) + endif() endif(roscpp_FOUND) @@ -182,8 +182,8 @@ if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") ament_target_dependencies(rslidar_sdk_node rclcpp - sensor_msgs std_msgs + sensor_msgs rslidar_msg) install(TARGETS From a773e28a3593511051fabaa243255330231eeea9 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 26 Sep 2022 15:34:17 +0800 Subject: [PATCH 213/261] feat: remove dependency on protobuf lib --- src/manager/node_manager.cpp | 54 ------------------------------------ 1 file changed, 54 deletions(-) diff --git a/src/manager/node_manager.cpp b/src/manager/node_manager.cpp index 61cf8e54..3646fb31 100644 --- a/src/manager/node_manager.cpp +++ b/src/manager/node_manager.cpp @@ -102,31 +102,6 @@ void NodeManager::init(const YAML::Node& config) source->init(lidar_config[i]); break; -#if 0 - case SourceType::MSG_FROM_PROTO_PACKET: // packets from proto - - RS_INFO << "------------------------------------------------------" << RS_REND; - RS_INFO << "Receive Packets From : Protobuf-UDP" << RS_REND; - RS_INFO << "Msop Port: " << lidar_config[i]["proto"]["msop_recv_port"].as() << RS_REND; - RS_INFO << "Difop Port: " << lidar_config[i]["proto"]["difop_recv_port"].as() << RS_REND; - RS_INFO << "------------------------------------------------------" << RS_REND; - - source = std::make_shared(); - source->init(lidar_config[i]); - break; - - case SourceType::MSG_FROM_PROTO_POINTCLOUD: // point cloud from proto - - RS_INFO << "------------------------------------------------------" << RS_REND; - RS_INFO << "Receive PointCloud From : Protobuf-UDP" << RS_REND; - RS_INFO << "PointCloud Port: " << lidar_config[i]["proto"]["point_cloud_recv_port"].as() << RS_REND; - RS_INFO << "------------------------------------------------------" << RS_REND; - - source = std::make_shared(); - source->init(lidar_config[i]); - break; -#endif - default: RS_ERROR << "Unsupported LiDAR message source:" << msg_source << "." << RS_REND; exit(-1); @@ -157,35 +132,6 @@ void NodeManager::init(const YAML::Node& config) source->regPointCloudCallback(dst); } -#if 0 - if (send_packet_proto) - { - RS_DEBUG << "------------------------------------------------------" << RS_REND; - RS_DEBUG << "Send Packets To : Protobuf-UDP" << RS_REND; - RS_DEBUG << "Msop Port: " << lidar_config[i]["proto"]["msop_send_port"].as() << RS_REND; - RS_DEBUG << "Difop Port: " << lidar_config[i]["proto"]["difop_send_port"].as() << RS_REND; - RS_DEBUG << "Target IP: " << lidar_config[i]["proto"]["packet_send_ip"].as() << RS_REND; - RS_DEBUG << "------------------------------------------------------" << RS_REND; - - std::shared_ptr dst = std::make_shared(); - dst->init(lidar_config[i]); - source->regPacketCallback(dst); - } - - if (send_point_cloud_proto) - { - RS_DEBUG << "------------------------------------------------------" << RS_REND; - RS_DEBUG << "Send PointCloud To : Protobuf-UDP" << RS_REND; - RS_DEBUG << "PointCloud Port: " << lidar_config[i]["proto"]["point_cloud_send_port"].as() << RS_REND; - RS_DEBUG << "Target IP: " << lidar_config[i]["proto"]["point_cloud_send_ip"].as() << RS_REND; - RS_DEBUG << "------------------------------------------------------" << RS_REND; - - std::shared_ptr dst = std::make_shared(); - dst->init(lidar_config[i]); - source->regPointCloudCallback(dst); - } -#endif - sources_.emplace_back(source); } } From 959c039e94696c5e953df5a54e5bed4db8d2eeee Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Mon, 26 Sep 2022 15:34:45 +0800 Subject: [PATCH 214/261] format: format cmake scripts --- CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0fed17d5..10899372 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,7 +78,7 @@ find_package(roscpp 1.12 QUIET) if(roscpp_FOUND) message(=============================================================) - message("-- ROS Found. ROS Support is turned On!") + message("-- ROS Found. ROS Support is turned On.") message(=============================================================) add_definitions(-DROS_FOUND) @@ -106,7 +106,7 @@ if(roscpp_FOUND) else(roscpp_FOUND) message(=============================================================) - message("-- ROS Not Found, Ros Support is turned Off!") + message("-- ROS Not Found. ROS Support is turned Off.") message(=============================================================) endif(roscpp_FOUND) @@ -117,7 +117,7 @@ find_package(rclcpp QUIET) if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") message(=============================================================) - message("-- ROS2 Found. ROS2 Support is turned On!") + message("-- ROS2 Found. ROS2 Support is turned On.") message(=============================================================) add_definitions(-DROS2_FOUND) @@ -132,7 +132,7 @@ if(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") else(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") message(=============================================================) - message("-- ROS2 Not Found. Ros2 Support is turned Off!") + message("-- ROS2 Not Found. ROS2 Support is turned Off.") message(=============================================================) endif(rclcpp_FOUND AND ${COMPILE_METHOD} STREQUAL "COLCON") From d3383180ead72320e8e2a6dabba0ca1963669f4a Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 27 Sep 2022 10:39:49 +0800 Subject: [PATCH 215/261] feat: support packet rosbag v1.3.2 --- CMakeLists.txt | 5 + ...k_along_with_rslidar_sdk_node_v1.3.x_CN.md | 111 +++++++++ doc/howto/img/20_packet_rosbag.png | Bin 0 -> 45459 bytes src/msg/ros_msg/rslidar_packet_legacy.hpp | 196 +++++++++++++++ src/msg/ros_msg/rslidar_scan_legacy.hpp | 228 ++++++++++++++++++ src/source/source_packet_ros.hpp | 66 ++++- 6 files changed, 604 insertions(+), 2 deletions(-) create mode 100644 doc/howto/how_to_work_along_with_rslidar_sdk_node_v1.3.x_CN.md create mode 100644 doc/howto/img/20_packet_rosbag.png create mode 100644 src/msg/ros_msg/rslidar_packet_legacy.hpp create mode 100644 src/msg/ros_msg/rslidar_scan_legacy.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 10899372..bdb88443 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,11 @@ if(${ENABLE_STAMP_WITH_LOCAL}) add_definitions("-DENABLE_STAMP_WITH_LOCAL") endif(${ENABLE_STAMP_WITH_LOCAL}) +option(ENABLE_SOURCE_PACKET_LEGACY "Enable ROS Source of MSOP/DIFOP Packet v1.3.x" OFF) +if(${ENABLE_SOURCE_PACKET_LEGACY}) + add_definitions("-DENABLE_SOURCE_PACKET_LEGACY") +endif(${ENABLE_SOURCE_PACKET_LEGACY}) + #======================== # Project details / setup #======================== diff --git a/doc/howto/how_to_work_along_with_rslidar_sdk_node_v1.3.x_CN.md b/doc/howto/how_to_work_along_with_rslidar_sdk_node_v1.3.x_CN.md new file mode 100644 index 00000000..ee3b18e4 --- /dev/null +++ b/doc/howto/how_to_work_along_with_rslidar_sdk_node_v1.3.x_CN.md @@ -0,0 +1,111 @@ +# 如何与rslidar_sdk_node v1.3.x共存? + +## 1 问题描述 + +`rslidar_sdk_node` `v1.3.x`和`v1.5.x`的配置方式不同。除了如下两个可能有交互的场景外, 两者各自运行,没有关系。 + ++ `rslidar_sdk_node`在主题`/rslidar_points`下发布点云,rosbag订阅并录制到一个cloud rosbag文件。后面rosbag又会回放这个文件,发布到`/rslidar_points`,`rslidar_sdk_node`订阅并播放它。 + ++ `rslidar_sdk_node`在主题`/rslidar_packets`下发布原始的`MSOP/DIFOP Packet`,rosbag订阅并录制到一个packet rosbag文件。后面rosbag又会回放这个文件到`/rslidar_packets`,`rslidar_sdk_node`订阅并播放它。 + +第一种场景下,`v1.3.x`和`v1.5.x`发布的点云格式相同,所以`v1.3.x`录制的点云,在`v1.5.x`上播放是没有问题的。 + +第二种场景下,`v1.3.x`将MSOP/DIFOP Packet分别发布在两个主题`/rslidar_packets`和`/rslidar_packets_difop`下,而`v1.5.x`将MSOP/DIFOP Packet发布在单个主题`/rslidar_packets`下,而且`v1.3.x`和`v1.5.x`的消息定义也不同,所以`v1.3.x`录制的packet rosbag在`v1.5.x`上不能播放。ROS会检测出这两种格式的MD5 Checksum不匹配并报错。 + +本文说明如何配置`rslidar_sdk` `v1.5.x`,让它在第二种场景下可以同时播放`v1.3.x`和`v1.5.x`的packet rosbag。 + +## 2 场景说明 + +场景说明如下。 ++ 2个雷达,`Lidar1`是运行`v1.3.x`的雷达,`Lidar2`是运行`v1.5.x`的雷达。 ++ 1台主机,用于分析`Lidar1`和`Lidar2`的数据。 + +![](./img/20_packet_rosbag.png) + +## 3 步骤 + + +### 3.1 配置 v1.3.x 雷达 + +使用`v1.3.x` `rslidar_sdk_node`录制pacekt rosbag。 + +按照默认的`config.yaml`的配置,消息发布到主题`/rslidar_packets`和`/rslidar_packets_difop`下。 + +``` +common: + msg_source: 1 #0: not use Lidar + #1: packet message comes from online Lidar + #2: packet message comes from ROS or ROS2 + #3: packet message comes from Pcap file + #4: packet message comes from Protobuf-UDP + #5: point cloud comes from Protobuf-UDP + send_packet_ros: true #true: Send packets through ROS or ROS2(Used to record packet) + send_point_cloud_ros: true #true: Send point cloud through ROS or ROS2 +lidar: + - driver: + lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RS128, RS80, RSM1 + msop_port: 6699 #Msop port of lidar + difop_port: 7788 #Difop port of lidar + ros: + ros_send_packet_topic: /rslidar_packets #Topic used to send lidar packets through ROS + ros_send_point_cloud_topic: /rslidar_points #Topic used to send point cloud through ROS +``` + +### 3.2 配置 v1.5.x 雷达 + +使用`v1.5.6` `rslidar_sdk_node`录制packet rosbag。 + +为了与`v1.3.2`的消息区别,将消息输出到主题`/rslidar_packets_v2`下。 + +``` +common: + msg_source: 1 #0: not use Lidar + #1: packet message comes from online Lidar + #2: packet message comes from ROS or ROS2 + #3: packet message comes from Pcap file + send_packet_ros: true #true: Send packets through ROS or ROS2(Used to record packet) + send_point_cloud_ros: true #true: Send point cloud through ROS or ROS2 +lidar: + - driver: + lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RS128, RS80, RS48, RSM1 + msop_port: 6699 #Msop port of lidar + difop_port: 7788 #Difop port of lidar + ros: + ros_send_packet_topic: /rslidar_packets_v2 #Topic used to send lidar packets through ROS + ros_send_point_cloud_topic: /rslidar_points #Topic used to send point cloud through ROS +``` + + +### 3.3 配置 v1.5.x 主机 + ++ 打开CMake编译选项`ENABLE_SOURCE_PACKET_LEGACY=ON`,编译`rslidar_sdk`。 + +``` +# CMakeLists.txt + +option(ENABLE_SOURCE_PACKET_LEGACY "Enable ROS Source of MSOP/DIFOP Packet v1.3.x" ON) +``` + ++ 在`config.yaml`中,增加一个配置项`ros_recv_packet_topic_legacy`: `/rslidar_packets`。这样`rslidar_sdk_node`将同时订阅两个主题。 + + 订阅`/rslidar_packets`和`/rslidar_packets_difop`,读入`v1.3.x`的消息 + + 订阅`/rslidar_packets_v2`,读入`v1.5.x`的消息 + +``` +common: + msg_source: 1 #0: not use Lidar + #1: packet message comes from online Lidar + #2: packet message comes from ROS or ROS2 + #3: packet message comes from Pcap file + send_packet_ros: false #true: Send packets through ROS or ROS2(Used to record packet) + send_point_cloud_ros: true #true: Send point cloud through ROS or ROS2 +lidar: + - driver: + lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RS128, RS80, RS48, RSM1 + msop_port: 6699 #Msop port of lidar + difop_port: 7788 #Difop port of lidar + ros: + ros_recv_packet_topic_legacy: /rslidar_packets #Topic used to receive lidar packets from ROS + ros_recv_packet_topic: /rslidar_packets_v2 #Topic used to receive lidar packets from ROS + ros_send_point_cloud_topic: /rslidar_points #Topic used to send point cloud through ROS +``` + diff --git a/doc/howto/img/20_packet_rosbag.png b/doc/howto/img/20_packet_rosbag.png new file mode 100644 index 0000000000000000000000000000000000000000..90d823b49b137ebd397731fc56bba9e7e2905ae4 GIT binary patch literal 45459 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 D)KHX% literal 0 HcmV?d00001 diff --git a/src/msg/ros_msg/rslidar_packet_legacy.hpp b/src/msg/ros_msg/rslidar_packet_legacy.hpp new file mode 100644 index 00000000..fbd820b2 --- /dev/null +++ b/src/msg/ros_msg/rslidar_packet_legacy.hpp @@ -0,0 +1,196 @@ +// Generated by gencpp from file rslidar_msgs/rslidarPacket.msg +// DO NOT EDIT! + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +namespace rslidar_msgs +{ +template +struct rslidarPacket_ +{ + typedef rslidarPacket_ Type; + + rslidarPacket_() : stamp(), data() + { + data.assign(0); + } + rslidarPacket_(const ContainerAllocator& _alloc) : stamp(), data() + { + (void)_alloc; + data.assign(0); + } + + typedef ros::Time _stamp_type; + _stamp_type stamp; + + typedef boost::array _data_type; + _data_type data; + + typedef boost::shared_ptr< ::rslidar_msgs::rslidarPacket_ > Ptr; + typedef boost::shared_ptr< ::rslidar_msgs::rslidarPacket_ const> ConstPtr; + +}; // struct rslidarPacket_ + +typedef ::rslidar_msgs::rslidarPacket_ > rslidarPacket; + +typedef boost::shared_ptr< ::rslidar_msgs::rslidarPacket> rslidarPacketPtr; +typedef boost::shared_ptr< ::rslidar_msgs::rslidarPacket const> rslidarPacketConstPtr; + +// constants requiring out of line definition + +template +std::ostream& operator<<(std::ostream& s, const ::rslidar_msgs::rslidarPacket_& v) +{ + ros::message_operations::Printer< ::rslidar_msgs::rslidarPacket_ >::stream(s, "", v); + return s; +} + +} // namespace rslidar_msgs + +namespace ros +{ +namespace message_traits +{ +// BOOLTRAITS {'IsFixedSize': true, 'IsMessage': true, 'HasHeader': false} +// {'std_msgs': ['/opt/ros/kinetic/share/std_msgs/cmake/../msg'], 'rslidar_msgs': +// ['/home/xzd/catkin_ws/src/rs_driver/rslidar_msgs/msg']} + +// !!!!!!!!!!! ['__class__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__getattribute__', +// '__hash__', '__init__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', +// '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_parsed_fields', 'constants', 'fields', 'full_name', +// 'has_header', 'header_present', 'names', 'package', 'parsed_fields', 'short_name', 'text', 'types'] + +template +struct IsFixedSize< ::rslidar_msgs::rslidarPacket_ > : TrueType +{ +}; + +template +struct IsFixedSize< ::rslidar_msgs::rslidarPacket_ const> : TrueType +{ +}; + +template +struct IsMessage< ::rslidar_msgs::rslidarPacket_ > : TrueType +{ +}; + +template +struct IsMessage< ::rslidar_msgs::rslidarPacket_ const> : TrueType +{ +}; + +template +struct HasHeader< ::rslidar_msgs::rslidarPacket_ > : FalseType +{ +}; + +template +struct HasHeader< ::rslidar_msgs::rslidarPacket_ const> : FalseType +{ +}; + +template +struct MD5Sum< ::rslidar_msgs::rslidarPacket_ > +{ + static const char* value() + { + return "1e4288e00b9222ea477b73350bf24f51"; + } + + static const char* value(const ::rslidar_msgs::rslidarPacket_&) + { + return value(); + } + static const uint64_t static_value1 = 0x1e4288e00b9222eaULL; + static const uint64_t static_value2 = 0x477b73350bf24f51ULL; +}; + +template +struct DataType< ::rslidar_msgs::rslidarPacket_ > +{ + static const char* value() + { + return "rslidar_msgs/rslidarPacket"; + } + + static const char* value(const ::rslidar_msgs::rslidarPacket_&) + { + return value(); + } +}; + +template +struct Definition< ::rslidar_msgs::rslidarPacket_ > +{ + static const char* value() + { + return "# Raw LIDAR packet.\n\ +\n\ +timestamp # packet timestamp\n\ +uint8[1248] data # packet contents\n\ +\n\ +"; + } + + static const char* value(const ::rslidar_msgs::rslidarPacket_&) + { + return value(); + } +}; + +} // namespace message_traits +} // namespace ros + +namespace ros +{ +namespace serialization +{ +template +struct Serializer< ::rslidar_msgs::rslidarPacket_ > +{ + template + inline static void allInOne(Stream& stream, T m) + { + stream.next(m.stamp); + stream.next(m.data); + } + + ROS_DECLARE_ALLINONE_SERIALIZER +}; // struct rslidarPacket_ + +} // namespace serialization +} // namespace ros + +namespace ros +{ +namespace message_operations +{ +template +struct Printer< ::rslidar_msgs::rslidarPacket_ > +{ + template + static void stream(Stream& s, const std::string& indent, const ::rslidar_msgs::rslidarPacket_& v) + { + s << indent << "stamp: "; + Printer::stream(s, indent + " ", v.stamp); + s << indent << "data[]" << std::endl; + for (size_t i = 0; i < v.data.size(); ++i) + { + s << indent << " data[" << i << "]: "; + Printer::stream(s, indent + " ", v.data[i]); + } + } +}; + +} // namespace message_operations +} // namespace ros diff --git a/src/msg/ros_msg/rslidar_scan_legacy.hpp b/src/msg/ros_msg/rslidar_scan_legacy.hpp new file mode 100644 index 00000000..b9837e11 --- /dev/null +++ b/src/msg/ros_msg/rslidar_scan_legacy.hpp @@ -0,0 +1,228 @@ +// Generated by gencpp from file rslidar_msgs/rslidarScan.msg +// DO NOT EDIT! + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include "msg/ros_msg/rslidar_packet_legacy.hpp" + +namespace rslidar_msgs +{ +template +struct rslidarScan_ +{ + typedef rslidarScan_ Type; + + rslidarScan_() : header(), packets() + { + } + rslidarScan_(const ContainerAllocator& _alloc) : header(_alloc), packets(_alloc) + { + (void)_alloc; + } + + typedef ::std_msgs::Header_ _header_type; + _header_type header; + + typedef std::vector< + ::rslidar_msgs::rslidarPacket_, + typename ContainerAllocator::template rebind<::rslidar_msgs::rslidarPacket_>::other> + _packets_type; + _packets_type packets; + + typedef boost::shared_ptr<::rslidar_msgs::rslidarScan_> Ptr; + typedef boost::shared_ptr<::rslidar_msgs::rslidarScan_ const> ConstPtr; + +}; // struct rslidarScan_ + +typedef ::rslidar_msgs::rslidarScan_> rslidarScan; + +typedef boost::shared_ptr<::rslidar_msgs::rslidarScan> rslidarScanPtr; +typedef boost::shared_ptr<::rslidar_msgs::rslidarScan const> rslidarScanConstPtr; + +// constants requiring out of line definition + +template +std::ostream& operator<<(std::ostream& s, const ::rslidar_msgs::rslidarScan_& v) +{ + ros::message_operations::Printer<::rslidar_msgs::rslidarScan_>::stream(s, "", v); + return s; +} + +} // namespace rslidar_msgs + +namespace ros +{ +namespace message_traits +{ +// BOOLTRAITS {'IsFixedSize': false, 'IsMessage': true, 'HasHeader': true} +// {'std_msgs': ['/opt/ros/kinetic/share/std_msgs/cmake/../msg'], 'rslidar_msgs': +// ['/home/xzd/catkin_ws/src/rs_driver/rslidar_msgs/msg']} + +// !!!!!!!!!!! ['__class__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__getattribute__', +// '__hash__', '__init__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', +// '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_parsed_fields', 'constants', 'fields', 'full_name', +// 'has_header', 'header_present', 'names', 'package', 'parsed_fields', 'short_name', 'text', 'types'] + +template +struct IsFixedSize<::rslidar_msgs::rslidarScan_> : FalseType +{ +}; + +template +struct IsFixedSize<::rslidar_msgs::rslidarScan_ const> : FalseType +{ +}; + +template +struct IsMessage<::rslidar_msgs::rslidarScan_> : TrueType +{ +}; + +template +struct IsMessage<::rslidar_msgs::rslidarScan_ const> : TrueType +{ +}; + +template +struct HasHeader<::rslidar_msgs::rslidarScan_> : TrueType +{ +}; + +template +struct HasHeader<::rslidar_msgs::rslidarScan_ const> : TrueType +{ +}; + +template +struct MD5Sum<::rslidar_msgs::rslidarScan_> +{ + static const char* value() + { + return "ff6baa58985b528481871cbaf1bb342f"; + } + + static const char* value(const ::rslidar_msgs::rslidarScan_&) + { + return value(); + } + static const uint64_t static_value1 = 0xff6baa58985b5284ULL; + static const uint64_t static_value2 = 0x81871cbaf1bb342fULL; +}; + +template +struct DataType<::rslidar_msgs::rslidarScan_> +{ + static const char* value() + { + return "rslidar_msgs/rslidarScan"; + } + + static const char* value(const ::rslidar_msgs::rslidarScan_&) + { + return value(); + } +}; + +template +struct Definition<::rslidar_msgs::rslidarScan_> +{ + static const char* value() + { + return "# LIDAR scan packets.\n\ +\n\ +Header header # standard ROS message header\n\ +rslidarPacket[] packets # vector of raw packets\n\ +\n\ +================================================================================\n\ +MSG: std_msgs/Header\n\ +# Standard metadata for higher-level stamped data types.\n\ +# This is generally used to communicate timestamped data \n\ +# in a particular coordinate frame.\n\ +# \n\ +# sequence ID: consecutively increasing ID \n\ +uint32 seq\n\ +#Two-integer timestamp that is expressed as:\n\ +# * stamp.sec: seconds (stamp_secs) since epoch (in Python the variable is called 'secs')\n\ +# * stamp.nsec: nanoseconds since stamp_secs (in Python the variable is called 'nsecs')\n\ +# time-handling sugar is provided by the client library\n\ +timestamp\n\ +#Frame this data is associated with\n\ +# 0: no frame\n\ +# 1: global frame\n\ +string frame_id\n\ +\n\ +================================================================================\n\ +MSG: rslidar_msgs/rslidarPacket\n\ +# Raw LIDAR packet.\n\ +\n\ +timestamp # packet timestamp\n\ +uint8[1248] data # packet contents\n\ +\n\ +"; + } + + static const char* value(const ::rslidar_msgs::rslidarScan_&) + { + return value(); + } +}; + +} // namespace message_traits +} // namespace ros + +namespace ros +{ +namespace serialization +{ +template +struct Serializer<::rslidar_msgs::rslidarScan_> +{ + template + inline static void allInOne(Stream& stream, T m) + { + stream.next(m.header); + stream.next(m.packets); + } + + ROS_DECLARE_ALLINONE_SERIALIZER +}; // struct rslidarScan_ + +} // namespace serialization +} // namespace ros + +namespace ros +{ +namespace message_operations +{ +template +struct Printer<::rslidar_msgs::rslidarScan_> +{ + template + static void stream(Stream& s, const std::string& indent, const ::rslidar_msgs::rslidarScan_& v) + { + s << indent << "header: "; + s << std::endl; + Printer<::std_msgs::Header_>::stream(s, indent + " ", v.header); + s << indent << "packets[]" << std::endl; + for (size_t i = 0; i < v.packets.size(); ++i) + { + s << indent << " packets[" << i << "]: "; + s << std::endl; + s << indent; + Printer<::rslidar_msgs::rslidarPacket_>::stream(s, indent + " ", v.packets[i]); + } + } +}; + +} // namespace message_operations +} // namespace ros diff --git a/src/source/source_packet_ros.hpp b/src/source/source_packet_ros.hpp index 4058ec00..529aa927 100644 --- a/src/source/source_packet_ros.hpp +++ b/src/source/source_packet_ros.hpp @@ -35,6 +35,12 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "source/source_driver.hpp" #ifdef ROS_FOUND + +#ifdef ENABLE_SOURCE_PACKET_LEGACY +#include "msg/ros_msg/rslidar_packet_legacy.hpp" +#include "msg/ros_msg/rslidar_scan_legacy.hpp" +#endif + #include "msg/ros_msg/rslidar_packet.hpp" #include @@ -69,10 +75,18 @@ class SourcePacketRos : public SourceDriver private: +#ifdef ENABLE_SOURCE_PACKET_LEGACY + void putPacketLegacy(const rslidar_msgs::rslidarScan& msg); + void putPacketDifopLegacy(const rslidar_msgs::rslidarPacket& msg); + ros::Subscriber pkt_sub_legacy_; + ros::Subscriber pkt_sub_difop_legacy_; + LidarType lidar_type_; +#endif + void putPacket(const rslidar_msg::RslidarPacket& msg); + ros::Subscriber pkt_sub_; std::unique_ptr nh_; - ros::Subscriber pkt_sub_; }; SourcePacketRos::SourcePacketRos() @@ -84,14 +98,62 @@ void SourcePacketRos::init(const YAML::Node& config) { SourceDriver::init(config); + nh_ = std::unique_ptr(new ros::NodeHandle()); + +#ifdef ENABLE_SOURCE_PACKET_LEGACY + std::string lidar_type; + yamlReadAbort(config["driver"], "lidar_type", lidar_type); + lidar_type_ = strToLidarType(lidar_type); + + std::string ros_recv_topic_legacy; + yamlRead(config["ros"], "ros_recv_packet_legacy_topic", + ros_recv_topic_legacy, "rslidar_packets"); + + pkt_sub_legacy_ = nh_->subscribe(ros_recv_topic_legacy, 1, &SourcePacketRos::putPacketLegacy, this); + pkt_sub_difop_legacy_ = nh_->subscribe(ros_recv_topic_legacy + "_difop", 1, &SourcePacketRos::putPacketDifopLegacy, this); +#endif + std::string ros_recv_topic; yamlRead(config["ros"], "ros_recv_packet_topic", ros_recv_topic, "rslidar_packets"); - nh_ = std::unique_ptr(new ros::NodeHandle()); pkt_sub_ = nh_->subscribe(ros_recv_topic, 100, &SourcePacketRos::putPacket, this); + } +#ifdef ENABLE_SOURCE_PACKET_LEGACY +inline Packet toRsMsg(const rslidar_msgs::rslidarPacket& ros_msg, LidarType lidar_type, bool isDifop) +{ + size_t pkt_len = 1248; + if (lidar_type == LidarType::RSM1) + { + pkt_len = isDifop ? 256 : 1210; + } + + Packet rs_msg; + for (size_t i = 0; i < pkt_len; i++) + { + rs_msg.buf_.emplace_back(ros_msg.data[i]); + } + + return rs_msg; +} + +void SourcePacketRos::putPacketLegacy(const rslidar_msgs::rslidarScan& msg) +{ + for (uint32_t i = 0; i < msg.packets.size(); i++) + { + const rslidar_msgs::rslidarPacket& packet = msg.packets[i]; + driver_ptr_->decodePacket(toRsMsg(packet, lidar_type_, false)); + } +} + +void SourcePacketRos::putPacketDifopLegacy(const rslidar_msgs::rslidarPacket& msg) +{ + driver_ptr_->decodePacket(toRsMsg(msg, lidar_type_, true)); +} +#endif + void SourcePacketRos::putPacket(const rslidar_msg::RslidarPacket& msg) { driver_ptr_->decodePacket(toRsMsg(msg)); From 6eed8e6200a0673a268ae506cd6552da2ab51f44 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 27 Sep 2022 16:49:25 +0800 Subject: [PATCH 216/261] feat: add option to send point cloud row by row --- src/source/source_pointcloud_ros.hpp | 145 +++++++++++++++++++++------ 1 file changed, 113 insertions(+), 32 deletions(-) diff --git a/src/source/source_pointcloud_ros.hpp b/src/source/source_pointcloud_ros.hpp index 482d2e76..6d1887b3 100644 --- a/src/source/source_pointcloud_ros.hpp +++ b/src/source/source_pointcloud_ros.hpp @@ -43,7 +43,7 @@ namespace robosense namespace lidar { -inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const std::string& frame_id) +inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const std::string& frame_id, bool send_by_rows) { sensor_msgs::PointCloud2 ros_msg; @@ -85,27 +85,58 @@ inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const sensor_msgs::PointCloud2Iterator iter_timestamp_(ros_msg, "timestamp"); #endif - for (size_t i = 0; i < rs_msg.points.size(); i++) + if (send_by_rows) { - const LidarPointCloudMsg::PointT& point = rs_msg.points[i]; + for (size_t i = 0; i < rs_msg.height; i++) + { + for (size_t j = 0; j < rs_msg.width; j++) + { + const LidarPointCloudMsg::PointT& point = rs_msg.points[i + j * rs_msg.height]; + + *iter_x_ = point.x; + *iter_y_ = point.y; + *iter_z_ = point.z; + *iter_intensity_ = point.intensity; + + iter_x_ = iter_x_ + 1; + iter_y_ = iter_y_ + 1; + iter_z_ = iter_z_ + 1; + iter_intensity_ = iter_intensity_ + 1; - *iter_x_ = point.x; - *iter_y_ = point.y; - *iter_z_ = point.z; - *iter_intensity_ = point.intensity; +#ifdef POINT_TYPE_XYZIRT + *iter_ring_ = point.ring; + *iter_timestamp_ = point.timestamp; + + iter_ring_ = iter_ring_ + 1; + iter_timestamp_ = iter_timestamp_ + 1; +#endif + } + } + } + else + { + for (size_t i = 0; i < rs_msg.points.size(); i++) + { + const LidarPointCloudMsg::PointT& point = rs_msg.points[i]; - iter_x_ = iter_x_ + 1; - iter_y_ = iter_y_ + 1; - iter_z_ = iter_z_ + 1; - iter_intensity_ = iter_intensity_ + 1; + *iter_x_ = point.x; + *iter_y_ = point.y; + *iter_z_ = point.z; + *iter_intensity_ = point.intensity; + + iter_x_ = iter_x_ + 1; + iter_y_ = iter_y_ + 1; + iter_z_ = iter_z_ + 1; + iter_intensity_ = iter_intensity_ + 1; #ifdef POINT_TYPE_XYZIRT - *iter_ring_ = point.ring; - *iter_timestamp_ = point.timestamp; + *iter_ring_ = point.ring; + *iter_timestamp_ = point.timestamp; - iter_ring_ = iter_ring_ + 1; - iter_timestamp_ = iter_timestamp_ + 1; + iter_ring_ = iter_ring_ + 1; + iter_timestamp_ = iter_timestamp_ + 1; #endif + } } ros_msg.header.seq = rs_msg.seq; @@ -127,10 +158,19 @@ class DestinationPointCloudRos : public DestinationPointCloud std::shared_ptr nh_; ros::Publisher pub_; std::string frame_id_; + bool send_by_rows_; }; inline void DestinationPointCloudRos::init(const YAML::Node& config) { + yamlRead(config["ros"], + "ros_send_by_rows", send_by_rows_, false); + + bool dense_points; + yamlRead(config["driver"], "dense_points", dense_points, false); + if (dense_points) + send_by_rows_ = false; + yamlRead(config["ros"], "ros_frame_id", frame_id_, "rslidar"); @@ -144,7 +184,7 @@ inline void DestinationPointCloudRos::init(const YAML::Node& config) inline void DestinationPointCloudRos::sendPointCloud(const LidarPointCloudMsg& msg) { - pub_.publish(toRosMsg(msg, frame_id_)); + pub_.publish(toRosMsg(msg, frame_id_, send_by_rows_)); } } // namespace lidar @@ -162,7 +202,7 @@ namespace robosense namespace lidar { -inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const std::string& frame_id) +inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const std::string& frame_id, bool send_by_rows) { sensor_msgs::msg::PointCloud2 ros_msg; @@ -204,27 +244,59 @@ inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, sensor_msgs::PointCloud2Iterator iter_timestamp_(ros_msg, "timestamp"); #endif - for (size_t i = 0; i < rs_msg.points.size(); i++) + + if (send_by_rows) { - const LidarPointCloudMsg::PointT& point = rs_msg.points[i]; + for (size_t i = 0; i < rs_msg.height; i++) + { + for (size_t j = 0; j < rs_msg.width; j++) + { + const LidarPointCloudMsg::PointT& point = rs_msg.points[i + j * rs_msg.height]; + + *iter_x_ = point.x; + *iter_y_ = point.y; + *iter_z_ = point.z; + *iter_intensity_ = point.intensity; + + iter_x_ = iter_x_ + 1; + iter_y_ = iter_y_ + 1; + iter_z_ = iter_z_ + 1; + iter_intensity_ = iter_intensity_ + 1; - *iter_x_ = point.x; - *iter_y_ = point.y; - *iter_z_ = point.z; - *iter_intensity_ = point.intensity; +#ifdef POINT_TYPE_XYZIRT + *iter_ring_ = point.ring; + *iter_timestamp_ = point.timestamp; + + iter_ring_ = iter_ring_ + 1; + iter_timestamp_ = iter_timestamp_ + 1; +#endif + } + } + } + else + { + for (size_t i = 0; i < rs_msg.points.size(); i++) + { + const LidarPointCloudMsg::PointT& point = rs_msg.points[i]; + + *iter_x_ = point.x; + *iter_y_ = point.y; + *iter_z_ = point.z; + *iter_intensity_ = point.intensity; - iter_x_ = iter_x_ + 1; - iter_y_ = iter_y_ + 1; - iter_z_ = iter_z_ + 1; - iter_intensity_ = iter_intensity_ + 1; + iter_x_ = iter_x_ + 1; + iter_y_ = iter_y_ + 1; + iter_z_ = iter_z_ + 1; + iter_intensity_ = iter_intensity_ + 1; #ifdef POINT_TYPE_XYZIRT - *iter_ring_ = point.ring; - *iter_timestamp_ = point.timestamp; + *iter_ring_ = point.ring; + *iter_timestamp_ = point.timestamp; - iter_ring_ = iter_ring_ + 1; - iter_timestamp_ = iter_timestamp_ + 1; + iter_ring_ = iter_ring_ + 1; + iter_timestamp_ = iter_timestamp_ + 1; #endif + } } ros_msg.header.stamp.sec = (uint32_t)floor(rs_msg.timestamp); @@ -246,10 +318,19 @@ class DestinationPointCloudRos : virtual public DestinationPointCloud std::shared_ptr node_ptr_; rclcpp::Publisher::SharedPtr pub_; std::string frame_id_; + bool send_by_rows_; }; inline void DestinationPointCloudRos::init(const YAML::Node& config) { + yamlRead(config["ros"], + "ros_send_by_rows", send_by_rows_, false); + + bool dense_points; + yamlRead(config["driver"], "dense_points", dense_points, false); + if (dense_points) + send_by_rows_ = false; + yamlRead(config["ros"], "ros_frame_id", frame_id_, "rslidar"); @@ -267,7 +348,7 @@ inline void DestinationPointCloudRos::init(const YAML::Node& config) inline void DestinationPointCloudRos::sendPointCloud(const LidarPointCloudMsg& msg) { - pub_->publish(toRosMsg(msg, frame_id_)); + pub_->publish(toRosMsg(msg, frame_id_, send_by_rows_)); } } // namespace lidar From 4de3fd1d0ddb453b9feb1a65f687a5e1dbefa70b Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 27 Sep 2022 17:54:25 +0800 Subject: [PATCH 217/261] feat: remove dependency on protobuf library --- doc/howto/how_to_use_protobuf_function.md | 220 ------------------ doc/howto/how_to_use_protobuf_function_CN.md | 223 ------------------- doc/intro/hiding_parameters_intro.md | 3 +- doc/intro/hiding_parameters_intro_CN.md | 4 - doc/intro/parameter_intro.md | 72 +----- doc/intro/parameter_intro_CN.md | 72 +----- 6 files changed, 11 insertions(+), 583 deletions(-) delete mode 100644 doc/howto/how_to_use_protobuf_function.md delete mode 100644 doc/howto/how_to_use_protobuf_function_CN.md diff --git a/doc/howto/how_to_use_protobuf_function.md b/doc/howto/how_to_use_protobuf_function.md deleted file mode 100644 index 51d5e6b3..00000000 --- a/doc/howto/how_to_use_protobuf_function.md +++ /dev/null @@ -1,220 +0,0 @@ -# How to use protobuf functions to send & receive message - -## 1 Introduction - -Suppose there are two computers, PC-A and PC-B, and they are far away from each other. For some reasons, you connect LiDAR with PC-A and use point cloud message in PC-B. To achieve this, you may need to use the protobuf functions. Typically, there are two ways to do this. - -- PC-A send out the packets message to PC-B. PC-B receive the packet message and decode it , then PC-B get the point cloud message and use it. - -- PC-A decode the packets message, get the point cloud and send out the point cloud message to PC-B. PC-B receive the point cloud message and use it directly. - -This first way is recommended, because the point cloud message is very large and it may take up your bandwidth. - -## 2 Send & Receive packets through Protobuf-UDP - -You are supposed to have already read [Intro to parameters](../intro/parameter_intro.md) and already have a basic idea about the config file. - -### 2.1 PC-A(Sender) - -```yaml -common: - msg_source: 1 - send_packet_ros: false - send_point_cloud_ros: false - send_packet_proto: true - send_point_cloud_proto: false -``` - -Since the message come from the LiDAR, set ```msg_source = 1```. - -Send packets through Protobuf-UDP, so set ```send_packet_proto = true```. - -```yaml -lidar: - - driver: - lidar_type: RS128 - msop_port: 6699 - difop_port: 7788 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false - ros: - ros_frame_id: /rslidar - ros_recv_packet_topic: /rslidar_packets - ros_send_packet_topic: /rslidar_packets - ros_send_point_cloud_topic: /rslidar_points - proto: - point_cloud_recv_port: 60021 - point_cloud_send_port: 60021 - msop_recv_port: 60022 - msop_send_port: 60022 - difop_recv_port: 60023 - difop_send_port: 60023 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 -``` - -Set the ```lidar_type``` for your LiDAR. - -Set the ```msop_port``` and ```difop_port``` for your LiDAR. - -Set the ```msop_send_port```, ```difop_send_port```, and ```packet_send_ip```. - -### 2.2 PC-B(Receiver) - -```yaml -common: - msg_source: 4 - send_packet_ros: false - send_point_cloud_ros: true - send_packet_proto: false - send_point_cloud_proto: false -``` - -Since the packets message come from protobuf-UDP, set ```msg_source = 4```. - -Send point cloud to ROS, so set ```send_point_cloud_ros = true```. - -```yaml -lidar: - - driver: - lidar_type: RS128 - msop_port: 6699 - difop_port: 7788 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false - ros: - ros_frame_id: /rslidar - ros_recv_packet_topic: /rslidar_packets - ros_send_packet_topic: /rslidar_packets - ros_send_point_cloud_topic: /rslidar_points - proto: - point_cloud_recv_port: 60021 - point_cloud_send_port: 60021 - msop_recv_port: 60022 - msop_send_port: 60022 - difop_recv_port: 60023 - difop_send_port: 60023 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 -``` - -Set the ```lidar_type``` for your LiDAR type. - -Make sure the PC-B's ip address is same with the ```packet_send_ip``` set in PC-A's config.yaml. - -Set the ```msop_recv_port``` and ```difop_recv_port``` to be same with the ```msop_send_port``` and ```difop_send_port``` set in PC-A's config.yaml. - -## 3 Send & receive point cloud through Protobuf-UDP - -You are supposed to have already read [Intro to parameters](../intro/parameter_intro.md) and have a basic idea about the config file. - -### 3.1 PC-A(Sender) - -```yaml -common: - msg_source: 1 - send_packet_ros: false - send_point_cloud_ros: false - send_packet_proto: false - send_point_cloud_proto: true -``` - -Since the message come from the LiDAR, set ```msg_source = 1```. - -Send point cloud through Protobuf-UDP, so set ```send_point_cloud_proto = true```. - -```yaml -lidar: - - driver: - lidar_type: RS128 - msop_port: 6699 - difop_port: 7788 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false - ros: - ros_frame_id: /rslidar - ros_recv_packet_topic: /rslidar_packets - ros_send_packet_topic: /rslidar_packets - ros_send_point_cloud_topic: /rslidar_points - proto: - point_cloud_recv_port: 60021 - point_cloud_send_port: 60021 - msop_recv_port: 60022 - msop_send_port: 60022 - difop_recv_port: 60023 - difop_send_port: 60023 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 -``` - -Set the ```lidar_type``` for your LiDAR. - -Set the ```msop_port``` and ```difop_port``` for your LiDAR. - -Set the ```point_cloud_send_port``` and ```point_cloud_send_ip``. - -### 3.2 PC-B(Receiver) - -```yaml -common: - msg_source: 5 - send_packet_ros: false - send_point_cloud_ros: true - send_packet_proto: false - send_point_cloud_proto: false -``` - -Since the point cloud message come from protobuf-UDP, set ```msg_source = 5```. - -Send point cloud to ROS, so set ```send_point_cloud_ros = true```. - -```yaml -lidar: - - driver: - lidar_type: RS128 - msop_port: 6699 - difop_port: 7788 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false - ros: - ros_frame_id: /rslidar - ros_recv_packet_topic: /rslidar_packets - ros_send_packet_topic: /rslidar_packets - ros_send_point_cloud_topic: /rslidar_points - proto: - point_cloud_recv_port: 60021 - point_cloud_send_port: 60021 - msop_recv_port: 60022 - msop_send_port: 60022 - difop_recv_port: 60023 - difop_send_port: 60023 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 -``` - -Make sure the PC-B's ip address is same with the ```point_cloud_send_ip``` set in PC-A's config.yaml. - -Set the ```point_cloud_recv_port``` to be same with the ```point_cloud_send_port``` set in PC-A's config.yaml. - - - - - - - - - - - diff --git a/doc/howto/how_to_use_protobuf_function_CN.md b/doc/howto/how_to_use_protobuf_function_CN.md deleted file mode 100644 index a2fc7e5e..00000000 --- a/doc/howto/how_to_use_protobuf_function_CN.md +++ /dev/null @@ -1,223 +0,0 @@ -# 如何使用Protobuf函数发送和接收消息 - -## 1 简介 - -假设有两台计算机,PC-A和PC-B,并且它们彼此相距很远。 处于某些原因,LiDAR与PC-A连接,而用户想在PC-B中使用点云消息。这时需要使用protobuf功能。 通常有两种方法可以达到这个目的。 - -- PC-A将雷达packet消息发送到PC-B。 PC-B收到雷达packet消息并对其进行解码,然后PC-B获得点云消息并使用它。 - -- PC-A解码雷达packet消息,获取点云并将点云消息发送到PC-B。 PC-B收到点云消息并直接使用。 - -一般建议使用第一种方法,因为点云消息非常大,对带宽有较高要求。 - -## 2 通过Protobuf-UDP发送和接收 packets - -请阅读[参数简介](../intro/parameter_intro_CN.md),了解基本的参数配置。 - -### 2.1 PC-A(发送端) - -```yaml -common: - msg_source: 1 - send_packet_ros: false - send_point_cloud_ros: false - send_packet_proto: true - send_point_cloud_proto: false -``` - -消息来源于在线雷达,因此请设置```msg_source=1```。 - -将packet数据通过Protobuf-UDP发出,因此设置 ```send_packet_proto = true``` 。 - -```yaml -lidar: - - driver: - lidar_type: RS128 - msop_port: 6699 - difop_port: 7788 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false - ros: - ros_frame_id: /rslidar - ros_recv_packet_topic: /rslidar_packets - ros_send_packet_topic: /rslidar_packets - ros_send_point_cloud_topic: /rslidar_points - proto: - point_cloud_recv_port: 60021 - point_cloud_send_port: 60021 - msop_recv_port: 60022 - msop_send_port: 60022 - difop_recv_port: 60023 - difop_send_port: 60023 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 -``` - -将 ```lidar_type``` 设置为LiDAR类型 。 - - -设置 ```msop_port``` 和 ```difop_port``` 为雷达数据端口号。 - -设置 ```msop_send_port```, ```difop_send_port```, 和 ```packet_send_ip```. - -### 2.2 PC-B(接收端) - -```yaml -common: - msg_source: 4 - send_packet_ros: false - send_point_cloud_ros: true - send_packet_proto: false - send_point_cloud_proto: false -``` - -packet消息来源于protobuf-UDP,因此设置 ```msg_source = 4``` 。 - -将点云发送到ROS以查看,因此设置 ```send_point_cloud_ros = true``` 。 - -```yaml -lidar: - - driver: - lidar_type: RS128 - msop_port: 6699 - difop_port: 7788 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false - ros: - ros_frame_id: /rslidar - ros_recv_packet_topic: /rslidar_packets - ros_send_packet_topic: /rslidar_packets - ros_send_point_cloud_topic: /rslidar_points - proto: - point_cloud_recv_port: 60021 - point_cloud_send_port: 60021 - msop_recv_port: 60022 - msop_send_port: 60022 - difop_recv_port: 60023 - difop_send_port: 60023 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 -``` - -将 ```lidar_type``` 设置为LiDAR类型 。 - -确认PC-B的ip地址与PC-A的配置文件中设置的```packet_send_ip```一致。 - -将```msop_recv_port```和```difop_recv_port```与PC-A的配置文件中设置的```msop_send_port```和```difop_send_port```设置为一致。 - -## 3 通过Protobuf-UDP发送和接收点云 - -首先请阅读[参数简介](... / intro / parameter_intro.md),了解基本的参数配置。 - -### 3.1 PC-A(发送端) - -```yaml -common: - msg_source: 1 - send_packet_ros: false - send_point_cloud_ros: false - send_packet_proto: false - send_point_cloud_proto: true -``` - -消息来源于在线雷达,因此请设置```msg_source=1```。 - -将点云数据通过Protobuf-UDP发出,因此设置 ```send_point_cloud_proto = true``` 。 - -```yaml -lidar: - - driver: - lidar_type: RS128 - msop_port: 6699 - difop_port: 7788 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false - ros: - ros_frame_id: /rslidar - ros_recv_packet_topic: /rslidar_packets - ros_send_packet_topic: /rslidar_packets - ros_send_point_cloud_topic: /rslidar_points - proto: - point_cloud_recv_port: 60021 - point_cloud_send_port: 60021 - msop_recv_port: 60022 - msop_send_port: 60022 - difop_recv_port: 60023 - difop_send_port: 60023 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 -``` - -将 ```lidar_type``` 设置为LiDAR类型 。 - -设置 ```msop_port``` 和 ```difop_port``` 为雷达数据端口号。 - -设置 ```point_cloud_send_port``` 和 ```point_cloud_send_ip```. - -### 3.2 PC-B(接收端) - -```yaml -common: - msg_source: 5 - send_packet_ros: false - send_point_cloud_ros: true - send_packet_proto: false - send_point_cloud_proto: false -``` - -点云消息来源于protobuf-UDP,因此设置 ```msg_source = 5``` 。 - -将点云发送到ROS,因此设置 ```send_point_cloud_ros = true``` 。 - -```yaml -lidar: - - driver: - lidar_type: RS128 - msop_port: 6699 - difop_port: 7788 - start_angle: 0 - end_angle: 360 - min_distance: 0.2 - max_distance: 200 - use_lidar_clock: false - ros: - ros_frame_id: /rslidar - ros_recv_packet_topic: /rslidar_packets - ros_send_packet_topic: /rslidar_packets - ros_send_point_cloud_topic: /rslidar_points - proto: - point_cloud_recv_port: 60021 - point_cloud_send_port: 60021 - msop_recv_port: 60022 - msop_send_port: 60022 - difop_recv_port: 60023 - difop_send_port: 60023 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 -``` - -确认PC-B的ip地址, 与PC-A的配置文件中设置的```point_cloud_send_ip```一致。 - -将```point_cloud_recv_port```与PC-A的配置文件中设置的```point_cloud_send_port```设置为一致。 - - - - - - - - - - - - - diff --git a/doc/intro/hiding_parameters_intro.md b/doc/intro/hiding_parameters_intro.md index 6bb498c7..5fdee9fe 100644 --- a/doc/intro/hiding_parameters_intro.md +++ b/doc/intro/hiding_parameters_intro.md @@ -48,7 +48,6 @@ lidar: pitch: 0 yaw: 0 use_vlan: false - use_someip: false ``` - ```pcap_repeat``` -- The default value is ```true```. Set it to ```false``` to prevent play pcap repeatedly. @@ -69,4 +68,4 @@ lidar: - ```host_address``` -- Needed in two conditions. If the host receives packets from multiple Lidars via different IP addresses, use this parameter to specify destination IPs of the Lidars; If group_address is set, it should be set, so it will be joined into the multicast group. - ```x, y, z, roll, pitch, yaw ``` -- The parameters to do coordinate transformation. If the coordinate transformation function is enabled in driver core, the output point cloud will be transformed based on these parameters. For more details, please refer to [Coordinate Transformation](../howto/how_to_use_coordinate_transformation.md) - ```use_vlan``` -- Whether to use VLAN. The default value is ```false```. This parameter is only needed for pcap file. If it contains packets with VLAN layer, ```use_vlan``` should set to true. In the case of online Lidar, the VLAN layer is stripped by the protocol layer, so use_vlan can be ignored. -- ```use_someip``` -- Whether to use SOME/IP. The default value is ```false```. Set this parameter to ```true``` if the packet contains the SOME/IP field. + diff --git a/doc/intro/hiding_parameters_intro_CN.md b/doc/intro/hiding_parameters_intro_CN.md index 631049cc..8747d7fb 100644 --- a/doc/intro/hiding_parameters_intro_CN.md +++ b/doc/intro/hiding_parameters_intro_CN.md @@ -11,8 +11,6 @@ common: msg_source: 1 send_packet_ros: false send_point_cloud_ros: false - send_packet_proto: false - send_point_cloud_proto: false ``` ## 2 lidar @@ -48,7 +46,6 @@ lidar: pitch: 0 yaw: 0 use_vlan: false - use_someip: false ``` - ```pcap_repeat``` -- 默认值为true, 用户可将其设置为false来禁用pcap循环播放功能。 @@ -68,4 +65,3 @@ lidar: - ```host_address``` -- 有两种情况需要这个选项。如果主机上通过多个IP地址接收多个雷达的数据,则可以将此参数指定为雷达的目标IP;如果设置了group_address,那也需要设置host_address,以便将这个IP地址的网卡加入组播组。 - ```x, y, z, roll, pitch, yaw ``` -- 坐标变换参数,若启用了内核的坐标变换功能,将会使用此参数输出经过变换后的点云。x, y, z, 单位为```米```, roll, pitch, yaw, 单位为```弧度```。具体使用方式可以参考 [坐标变换功能](../howto/how_to_use_coordinate_transformation_CN.md) 。 - ```use_vlan``` -- 默认为false,指定是否使用vlan。如果pcap文件中的packet带vlan层,则需要设置这个选项为true。其他情况下不需要。在线雷达的情况下,协议层到达驱动时,已经剥离vlan层,所以不需要设置这个选项。 -- ```use_someip``` -- 是否使用SOME/IP,默认为false。当数据包中有SOME/IP层,需要设置为true。 diff --git a/doc/intro/parameter_intro.md b/doc/intro/parameter_intro.md index ab06cfc3..55528eff 100644 --- a/doc/intro/parameter_intro.md +++ b/doc/intro/parameter_intro.md @@ -17,8 +17,6 @@ common: msg_source: 1 send_packet_ros: false send_point_cloud_ros: false - send_packet_proto: false - send_point_cloud_proto: false ``` - msg_source @@ -42,17 +40,6 @@ common: - true -- The LiDAR point cloud will be sent to ROS/ROS2. *The ROS point cloud type is the ROS official defined type -- sensor_msgs/PointCloud2, so it can be visualized on the ROS `rviz` tool directly. It is not suggested to record the point cloud to rosbag, because its size may be very large. Please record Packets instead. Refer to the case of msg_source=2.* - -- send_packet_proto - - - true -- The Lidar packets will be sent out as Protobuf message by the UDP protocol. - -- send_point_cloud_proto - - - true -- The Lidar point cloud will be sent out as Protobuf message by the UDP protocol. - - -*The point cloud is too large, so it is suggested to send packets rather than point clouds. Please refer to the case of send_packet_proto=true.* ## 2 lidar @@ -71,19 +58,10 @@ lidar: use_lidar_clock: false pcap_path: /home/robosense/lidar.pcap ros: - ros_frame_id: /rslidar + ros_frame_id: rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points - proto: - point_cloud_recv_port: 60021 - point_cloud_send_port: 60021 - msop_recv_port: 60022 - msop_send_port: 60022 - difop_recv_port: 60023 - difop_send_port: 60023 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 ``` - lidar_type @@ -122,8 +100,6 @@ common: msg_source: 1 send_packet_ros: false send_point_cloud_ros: true - send_packet_proto: false - send_point_cloud_proto: false lidar: - driver: lidar_type: RS128 @@ -135,19 +111,10 @@ lidar: max_distance: 200 use_lidar_clock: false ros: - ros_frame_id: /rslidar + ros_frame_id: rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points - proto: - point_cloud_recv_port: 60021 - point_cloud_send_port: 60021 - msop_recv_port: 60022 - msop_send_port: 60022 - difop_recv_port: 60023 - difop_send_port: 60023 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 ``` ### 3.2 Multi Lidar Case @@ -161,8 +128,6 @@ common: msg_source: 1 send_packet_ros: false send_point_cloud_ros: true - send_packet_proto: false - send_point_cloud_proto: false lidar: - driver: lidar_type: RS128 @@ -174,19 +139,10 @@ lidar: max_distance: 200 use_lidar_clock: false ros: - ros_frame_id: /rslidar + ros_frame_id: rslidar ros_recv_packet_topic: /middle/rslidar_packets ros_send_packet_topic: /middle/rslidar_packets ros_send_point_cloud_topic: /middle/rslidar_points - proto: - point_cloud_recv_port: 60021 - point_cloud_send_port: 60021 - msop_recv_port: 60022 - msop_send_port: 60022 - difop_recv_port: 60023 - difop_send_port: 60023 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 - driver: lidar_type: RSBP msop_port: 1990 @@ -197,19 +153,10 @@ lidar: max_distance: 200 use_lidar_clock: false ros: - ros_frame_id: /rslidar + ros_frame_id: rslidar ros_recv_packet_topic: /left/rslidar_packets ros_send_packet_topic: /left/rslidar_packets ros_send_point_cloud_topic: /left/rslidar_points - proto: - point_cloud_recv_port: 60024 - point_cloud_send_port: 60024 - msop_recv_port: 60025 - msop_send_port: 60025 - difop_recv_port: 60026 - difop_send_port: 60026 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 - driver: lidar_type: RSBP msop_port: 2010 @@ -220,18 +167,9 @@ lidar: max_distance: 200 use_lidar_clock: false ros: - ros_frame_id: /rslidar + ros_frame_id: rslidar ros_recv_packet_topic: /right/rslidar_packets ros_send_packet_topic: /right/rslidar_packets ros_send_point_cloud_topic: /right/rslidar_points - proto: - point_cloud_recv_port: 60027 - point_cloud_send_port: 60027 - msop_recv_port: 60028 - msop_send_port: 60028 - difop_recv_port: 60029 - difop_send_port: 60029 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 ``` diff --git a/doc/intro/parameter_intro_CN.md b/doc/intro/parameter_intro_CN.md index 6f7f3590..d1a3de53 100644 --- a/doc/intro/parameter_intro_CN.md +++ b/doc/intro/parameter_intro_CN.md @@ -17,8 +17,6 @@ common: msg_source: 1 send_packet_ros: false send_point_cloud_ros: false - send_packet_proto: false - send_point_cloud_proto: false ``` - msg_source @@ -41,17 +39,6 @@ common: *点云消息的类型为ROS官方定义的点云类型sensor_msgs/PointCloud2, 用户可以使用Rviz直接查看点云。用户可以录制ROS/ROS2的点云包,但点云包的体积非常大,所以不建议这么做。更好的方式是录制Packet包,请参考send_packet_ros=true的情况。* -- send_packet_proto - - - true -- 雷达packet消息将通过Protobuf-UDP发出 - -- send_point_cloud_proto - - - true -- 雷达点云消息将通过Protobuf-UDP发出 - - *点云消息过大,对带宽有较高的要求,所以不建议这么做。更好的方式是发送Packet消息,请参考send_packet_proto=true的情况。* - - ## 2 lidar部分 lidar部分根据每个雷达的实际情况进行设置。 @@ -69,19 +56,10 @@ lidar: use_lidar_clock: false pcap_path: /home/robosense/lidar.pcap ros: - ros_frame_id: /rslidar + ros_frame_id: rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points - proto: - point_cloud_recv_port: 60021 - point_cloud_send_port: 60021 - msop_recv_port: 60022 - msop_send_port: 60022 - difop_recv_port: 60023 - difop_send_port: 60023 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 ``` - lidar_type @@ -120,8 +98,6 @@ common: msg_source: 1 send_packet_ros: false send_point_cloud_ros: true - send_packet_proto: false - send_point_cloud_proto: false lidar: - driver: lidar_type: RS128 @@ -133,19 +109,10 @@ lidar: max_distance: 200 use_lidar_clock: false ros: - ros_frame_id: /rslidar + ros_frame_id: rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets ros_send_point_cloud_topic: /rslidar_points - proto: - point_cloud_recv_port: 60021 - point_cloud_send_port: 60021 - msop_recv_port: 60022 - msop_send_port: 60022 - difop_recv_port: 60023 - difop_send_port: 60023 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 ``` ### 3.2 单台雷达 @@ -159,8 +126,6 @@ common: msg_source: 1 send_packet_ros: false send_point_cloud_ros: true - send_packet_proto: false - send_point_cloud_proto: false lidar: - driver: lidar_type: RS128 @@ -172,19 +137,10 @@ lidar: max_distance: 200 use_lidar_clock: false ros: - ros_frame_id: /rslidar + ros_frame_id: rslidar ros_recv_packet_topic: /middle/rslidar_packets ros_send_packet_topic: /middle/rslidar_packets ros_send_point_cloud_topic: /middle/rslidar_points - proto: - point_cloud_recv_port: 60021 - point_cloud_send_port: 60021 - msop_recv_port: 60022 - msop_send_port: 60022 - difop_recv_port: 60023 - difop_send_port: 60023 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 - driver: lidar_type: RSBP msop_port: 1990 @@ -195,19 +151,10 @@ lidar: max_distance: 200 use_lidar_clock: false ros: - ros_frame_id: /rslidar + ros_frame_id: rslidar ros_recv_packet_topic: /left/rslidar_packets ros_send_packet_topic: /left/rslidar_packets ros_send_point_cloud_topic: /left/rslidar_points - proto: - point_cloud_recv_port: 60024 - point_cloud_send_port: 60024 - msop_recv_port: 60025 - msop_send_port: 60025 - difop_recv_port: 60026 - difop_send_port: 60026 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 - driver: lidar_type: RSBP msop_port: 2010 @@ -218,18 +165,9 @@ lidar: max_distance: 200 use_lidar_clock: false ros: - ros_frame_id: /rslidar + ros_frame_id: rslidar ros_recv_packet_topic: /right/rslidar_packets ros_send_packet_topic: /right/rslidar_packets ros_send_point_cloud_topic: /right/rslidar_points - proto: - point_cloud_recv_port: 60027 - point_cloud_send_port: 60027 - msop_recv_port: 60028 - msop_send_port: 60028 - difop_recv_port: 60029 - difop_send_port: 60029 - point_cloud_send_ip: 127.0.0.1 - packet_send_ip: 127.0.0.1 ``` From 5ef154f728457589fc277dddf4c863364d8fd45a Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Tue, 27 Sep 2022 18:05:36 +0800 Subject: [PATCH 218/261] feat: update docs about ros_send_by_rows --- doc/intro/hiding_parameters_intro.md | 1 - doc/intro/hiding_parameters_intro_CN.md | 1 - doc/intro/parameter_intro.md | 13 +++++++++++++ doc/intro/parameter_intro_CN.md | 15 +++++++++++++++ 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/doc/intro/hiding_parameters_intro.md b/doc/intro/hiding_parameters_intro.md index 5fdee9fe..6b9420bd 100644 --- a/doc/intro/hiding_parameters_intro.md +++ b/doc/intro/hiding_parameters_intro.md @@ -54,7 +54,6 @@ lidar: - ```pcap_rate``` -- The default value is ```1```. The frequency of point cloud is about 10hz. The larger the value is, the faster the pcap bag is played. - ```config_from_file``` -- Whether to read Lidar configuration from file. Only used for debug purpose, and can be ignored. - ```angle_path``` -- The path of the angle.csv. Only used for debug purpose and can be ignored. -- ```dense_points``` -- Whether to discard NAN points. Discard if ```true```, reserve if ```false```. The default value is ```false```. - ```ts_first_point``` -- Stamp the point cloud with the first point or the last one. Stamp with the first point if ```true```, else stamp with the last point if ```false```. The default value is ```false```. - ```split_frame_mode``` -- The way to split the LiDAR frames. Default value is ```1```. - 1 -- Split frame depending on the split_angle diff --git a/doc/intro/hiding_parameters_intro_CN.md b/doc/intro/hiding_parameters_intro_CN.md index 8747d7fb..a5828c08 100644 --- a/doc/intro/hiding_parameters_intro_CN.md +++ b/doc/intro/hiding_parameters_intro_CN.md @@ -52,7 +52,6 @@ lidar: - ```pcap_rate``` -- 默认值为1,点云频率约为10hz。 用户可调节此参数来控制pcap播放速度,设置的值越大,pcap播放速度越快。 - ```config_from_file``` -- 默认值为false, 是否从外参文件读入雷达配置信息,仅用于调试,可忽略。 - ```angle_path``` -- angle.csv外参文件的路径,仅用于调试,可忽略。 -- ```dense_points``` -- 默认值为false。输出的点云中是否剔除NAN points。```true```为剔除,```false```为不剔除。 - ```ts_first_point``` -- 默认值为false。点云的时间戳是否第一个点的时间。```true```为第一个点的时间,```false```为最后一个点的时间。 - ```split_frame_mode``` -- 分帧模式设置,默认值为```1```。 - 1 -- 角度分帧 diff --git a/doc/intro/parameter_intro.md b/doc/intro/parameter_intro.md index 55528eff..db11ec4b 100644 --- a/doc/intro/parameter_intro.md +++ b/doc/intro/parameter_intro.md @@ -56,6 +56,7 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false + dense_points: false pcap_path: /home/robosense/lidar.pcap ros: ros_frame_id: rslidar @@ -85,10 +86,22 @@ lidar: - true -- Use the Lidar clock as the message timestamp - false -- Use the host machine clock as the message timestamp +- dense_points + + Whether to discard NAN points. The default value is ```false```. + - Discard if ```true``` + - reserve if ```false```. + - pcap_path The full path of the PCAP file. Valid if msg_source = 3. +- ros_send_by_rows + + Meaningful only for Mechanical Lidars, and valid if dense_points = false。 + - true -- send point cloud row by row + - false -- send point cloud clolumn by column + ## 3 Example ### 3.1 Single Lidar Case diff --git a/doc/intro/parameter_intro_CN.md b/doc/intro/parameter_intro_CN.md index d1a3de53..22df3019 100644 --- a/doc/intro/parameter_intro_CN.md +++ b/doc/intro/parameter_intro_CN.md @@ -54,8 +54,10 @@ lidar: min_distance: 0.2 max_distance: 200 use_lidar_clock: false + dense_points: false pcap_path: /home/robosense/lidar.pcap ros: + ros_send_by_rows: false ros_frame_id: rslidar ros_recv_packet_topic: /rslidar_packets ros_send_packet_topic: /rslidar_packets @@ -83,10 +85,23 @@ lidar: - true -- 使用雷达时间作为消息时间戳。 - false -- 使用电脑主机时间作为消息时间戳。 +- dense_points + + 输出的点云中是否剔除NAN points。默认值为false。 + - true 为剔除, + - false为不剔除。 + - pcap_path pcap包的路径。当 msg_source=3 时有效。 +- ros_send_by_rows + + 只对机械式雷达有意义,且只有当dense_points = false时才有效。 + - true -- 发送点云时,按照一行一行的顺序排列点 + - false -- 发送点云时,按照一列一列的顺序排列点 + + ## 3 示例 ### 3.1 单台雷达 From 1915cf591446215e0c2bb1ff3ab028d57e5152fe Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Wed, 28 Sep 2022 19:10:13 +0800 Subject: [PATCH 219/261] feat: support packet rosbag v1.3.2 --- .../how_to_work_along_with_rslidar_sdk_node_v1.3.x_CN.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/howto/how_to_work_along_with_rslidar_sdk_node_v1.3.x_CN.md b/doc/howto/how_to_work_along_with_rslidar_sdk_node_v1.3.x_CN.md index ee3b18e4..ed591da4 100644 --- a/doc/howto/how_to_work_along_with_rslidar_sdk_node_v1.3.x_CN.md +++ b/doc/howto/how_to_work_along_with_rslidar_sdk_node_v1.3.x_CN.md @@ -86,7 +86,7 @@ lidar: option(ENABLE_SOURCE_PACKET_LEGACY "Enable ROS Source of MSOP/DIFOP Packet v1.3.x" ON) ``` -+ 在`config.yaml`中,增加一个配置项`ros_recv_packet_topic_legacy`: `/rslidar_packets`。这样`rslidar_sdk_node`将同时订阅两个主题。 ++ 在`config.yaml`中,增加一个配置项`ros_recv_packet_legacy_topic`: `/rslidar_packets`。这样`rslidar_sdk_node`将同时订阅两个主题。 + 订阅`/rslidar_packets`和`/rslidar_packets_difop`,读入`v1.3.x`的消息 + 订阅`/rslidar_packets_v2`,读入`v1.5.x`的消息 @@ -104,7 +104,7 @@ lidar: msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar ros: - ros_recv_packet_topic_legacy: /rslidar_packets #Topic used to receive lidar packets from ROS + ros_recv_packet_legacy_topic: /rslidar_packets #Topic used to receive lidar packets from ROS ros_recv_packet_topic: /rslidar_packets_v2 #Topic used to receive lidar packets from ROS ros_send_point_cloud_topic: /rslidar_points #Topic used to send point cloud through ROS ``` From a1374b8e6dba62ab390cf89921d4e419f3dfe079 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Thu, 29 Sep 2022 15:44:31 +0800 Subject: [PATCH 220/261] feat: support RSBPV4 --- config/config.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/config.yaml b/config/config.yaml index 48422007..ad9b2acf 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -7,7 +7,8 @@ common: send_point_cloud_ros: true #true: Send point cloud through ROS or ROS2 lidar: - driver: - lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RSHELIOS_16P, RS128, RS80, RS48, RSP128, RSP80, RSP48, RSM1, RSM2, RSEOS, RSM1_JUMBO + lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RSBPV4, RSHELIOS, RSHELIOS_16P, RS128, RS80, RS48, RSP128, RSP80, RSP48, + # RSM1, RSM2, RSEOS, RSM1_JUMBO msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar start_angle: 0 #Start angle of point cloud From 396a4b03ff9d24c7ab18c88f9715548cdea00f96 Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Sun, 9 Oct 2022 17:33:06 +0800 Subject: [PATCH 221/261] feat: update docs --- doc/src_intro/rslidar_sdk_intro_CN.md | 50 ++++++++++++++------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/doc/src_intro/rslidar_sdk_intro_CN.md b/doc/src_intro/rslidar_sdk_intro_CN.md index d3ed3a71..2f4fc00c 100644 --- a/doc/src_intro/rslidar_sdk_intro_CN.md +++ b/doc/src_intro/rslidar_sdk_intro_CN.md @@ -1,4 +1,6 @@ -# rslidar_sdk v1.5.5 源代码解析 +# rslidar_sdk v1.5.7 源代码解析 + +## 1 简介 rslidar_sdk是基于ROS/ROS2的雷达驱动。rslidar_sdk依赖rs_driver接收和解析MSOP/DIFOP Packet。 @@ -8,7 +10,7 @@ rslidar_sdk的基本功能如下: + 从ROS主题`/rslidar_packets`得到MSOP/DIFOP Packet,解析得到点云,再发布到主题`/rslidar_points`。 + 这里的主题`/rslidar_packets`,由使用者通过回放Packet rosbag文件发布。 -## 1 Source 与 Destination +## 2 Source 与 Destination 如前面所说,rslidar_sdk从在线雷达、PCAP文件、ROS主题这三种源得到MSOP/DIFOP Packet,将Packet发布到ROS主题/rslidar_packets`/rslidar_packets`,将点云发布到目标 - ROS主题`/rslidar_points`。 + Source定义源接口 @@ -17,21 +19,21 @@ rslidar_sdk的基本功能如下: ![source](./img/class_source_destination.png) -## 2 DestinationPointCloud +### 2.1 DestinationPointCloud DestinationPointCloud定义发送点云的接口。 + 虚拟成员函数init()对DestinationPointCloud实例初始化 + 虚拟成员函数start()启动实例 + 虚拟成员函数sendPointCloud()发送PointCloud消息 -## 3 DestinationPacket +### 2.2 DestinationPacket DestinationPacket定义发送MSOP/DIFOP Packet的接口。 + 虚拟成员函数init()对DestinationPacket实例初始化 + 虚拟成员函数start()启动实例 + 虚拟成员函数sendPacket()启动发送Packet消息 -## 4 Source +### 2.3 Source Source是定义源的接口。 @@ -56,7 +58,7 @@ Source是定义源的接口。 + 虚拟成员函数regPointCloudCallback()将PointCloudDestination实例注册到`point_cb_vec_[]`。 + 虚拟成员函数regPacketCallback()将PacketDestination实例注册到`packet_cb_vec_[]`。 -## 5 DestinationPointCloudRos +### 2.4 DestinationPointCloudRos DestinationPointCloudRos在ROS主题`/rslidar_points`发布点云。 + 成员`pkt_pub_`是ROS主题发布器。 @@ -64,7 +66,7 @@ DestinationPointCloudRos在ROS主题`/rslidar_points`发布点云。 ![destination pointcloud ros](./img/class_destination_pointcloud.png) -### 5.1 DestinationPointCloudRos::init() +#### 2.4.1 DestinationPointCloudRos::init() init()初始化DestinationPointCloudRos实例。 + 从YAML文件读入用户配置参数。 @@ -72,12 +74,12 @@ init()初始化DestinationPointCloudRos实例。 + 读入ROS主题,保存在本地变量`ros_send_topic_`,默认值是`/rslidar_points`。 + 创建ROS主题发布器,保存在成员`pkt_sub_`. -### 5.2 DestinationPointCloudRos::sendPointCloud() +#### 2.4.2 DestinationPointCloudRos::sendPointCloud() sendPacket()在ROS主题`/rslidar_points`发布点云。 + 调用Publisher::publish()发布ROS格式的点云消息。 -## 6 DestinationPacketRos +### 2.5 DestinationPacketRos DestinationPacketRos在ROS主题`/rslidar_packets`发布MSOP/DIFOP Packet。 + 成员`pkt_sub_`是ROS主题发布器。 @@ -85,7 +87,7 @@ DestinationPacketRos在ROS主题`/rslidar_packets`发布MSOP/DIFOP Packet。 ![destination packet ros](./img/class_destination_packet.png) -### 6.1 DestinationPacketRos::init() +#### 2.5.1 DestinationPacketRos::init() init()初始化DestinationPacketRos实例。 + 从YAML文件读入用户配置参数。 @@ -93,12 +95,12 @@ init()初始化DestinationPacketRos实例。 + 读入ROS主题,保存在本地变量`ros_send_topic_`,默认值是`/rslidar_packets`。 + 创建ROS主题发布器,保存在成员`pkt_sub_`. -### 6.2 DestinationPacketRos::sendPacket() +#### 2.5.2 DestinationPacketRos::sendPacket() sendPacket()在ROS主题`/rslidar_packets`发布MOSP/DIFOP packet。 + 调用Publisher::publish()发布ROS格式的Packet消息。 -## 7 SourceDriver +### 2.6 SourceDriver SourceDriver从在线雷达和PCAP文件得到MSOP/DIFOP Packet,并解析得到点云。 + 成员`driver_ptr_`是rs_driver驱动的实例,也就是LidarDriver。 @@ -107,7 +109,7 @@ SourceDriver从在线雷达和PCAP文件得到MSOP/DIFOP Packet,并解析得 ![source driver](./img/class_source_driver.png) -### 7.1 SourceDriver::init() +#### 2.6.1 SourceDriver::init() init()初始化SourceDriver实例。 + 读取YAML配置文件,得到雷达的用户配置参数。 @@ -118,35 +120,35 @@ init()初始化SourceDriver实例。 + 调用LidarDriver::init(),初始化`driver_ptr_`。 + 创建、启动点云处理线程`point_cloud_handle_thread_`, 线程函数是processPointCloud()。 -### 7.2 SourceDriver::getPointCloud() +#### 2.6.2 SourceDriver::getPointCloud() getPointCloud()给成员`driver_ptr_`提供空闲的点云。 + 优先从成员`free_point_cloud_queue_`得到点云。 + 如果得不到,分配新的点云。 -### 7.3 SourceDriver::putPointCloud() +#### 2.6.3 SourceDriver::putPointCloud() putPointCloud()给从成员`driver_ptr_`得到填充好的点云。 + 将得到的点云推送到成员`point_cloud_queue_`,等待处理。 -### 7.4 SourceDriver::processPointCloud() +#### 2.6.4 SourceDriver::processPointCloud() processPointCloud()处理点云。在while循环中, + 从待处理点云的队列`point_cloud_queue_`,得到点云, + 调用sendPointCloud(),其中调用成员`pc_cb_vec_[]`中的DestinationPointCloud实例,发送点云。 + 回收点云,放入空闲点云的队列`free_cloud_queue_`,待下次使用。 -### 7.5 SourceDriver::regPacketCallback() +#### 2.6.5 SourceDriver::regPacketCallback() regPacketCallback()用来注册DestinationPacket。 + 调用Source::regPacketCallback(),将DestinationPacket实例,加入成员`pkt_cb_vec_[]`。 + 如果这是首次要求Packet(`pkt_cb_vec_[]`的第1个实例),调用LidarDriver::regPacketCallback(),向`driver_ptr_`注册Packet回调函数,开始接收Packet。回调函数是putPacket()。 -### 7.6 SourceDriver::putPacket() +#### 2.6.6 SourceDriver::putPacket() putPacket()调用sendPacket(),其中调用成员`pkt_cb_vec_[]`中的所有实例,发送MSOP/DIFOP Packet。 -## 8 SourcePacketRos +### 2.7 SourcePacketRos SourcePacketRos在ROS主题`/rslidar_packets`得到MSOP/DIFOP Packet,解析后得到点云。 + SourcePacketRos从SourceDriver派生,而不是直接从Source派生,是因为它用SourceDriver解析Packet得到点云。 @@ -154,7 +156,7 @@ SourcePacketRos在ROS主题`/rslidar_packets`得到MSOP/DIFOP Packet,解析后 ![source](./img/class_source_packet_ros.png) -### 8.1 SourcePacketRos::init() +#### 2.7.1 SourcePacketRos::init() init()初始化SourcePacketRos实例。 + 调用SourceDriver::init()初始化成员`driver_ptr_`。 @@ -163,20 +165,20 @@ init()初始化SourcePacketRos实例。 + 得到接收Packet的主题,默认值为`/rslidar_packets`。 + 创建Packet主题的订阅器,也就是成员`pkt_sub_`,接收函数是putPacket()。 -### 8.2 SourcePacketRos::putPacket() +#### 2.7.2 SourcePacketRos::putPacket() putPacket()接收Packet,送到`driver_ptr_`解析。 + 调用LidarDriver::decodePacket(),将Packet喂给`driver_ptr_`。 + 点云的接收,使用SourceDriver的已有实现。 -## 9 NodeManager +## 3 NodeManager NodeManager管理Source实例,包括创建、初始化、启动、停止Source。它支持多个源,但是这些源的类型必须相同。 + 成员`sources_[]`是一个Source实例的数组。 ![node_manager](./img/class_node_manager.png) -### 9.1 NodeManager::init() +### 3.1 NodeManager::init() init()初始化NodeManger实例。 + 从config.yaml文件得到用户配置参数 @@ -193,7 +195,7 @@ init()初始化NodeManger实例。 + 如果在ROS主题发送Packet(`send_packet_ros` = `true`),则创建DestinationPacketRos实例、初始化,调用Source::regPacketCallback()将它加入Source的`pkt_cb_vec_[]`。 + 将Source实例,加入成员`sources_[]`。 -### 9.2 NodeManager::start() +### 3.2 NodeManager::start() start()启动成员`sources_[]`中的所有实例。 From e4302625003326b4117965fdeb1e6eaf36e6825e Mon Sep 17 00:00:00 2001 From: "ron.zheng" Date: Sun, 9 Oct 2022 17:34:43 +0800 Subject: [PATCH 222/261] feat: update CHANGELOG --- CHANGELOG.md | 7 +++++++ src/rs_driver | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45718c41..cd8b4598 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ ## Unreleased +## v1.5.7 - 2022-10-09 + +### Added +- Seperate RSBPV4 from RSBP +- Support to receive MSOP/DIFOP packet from rosbag v1.3.x +- Support option ros_send_by_rows + ## v1.5.6 - 2022-09-01 ### Added diff --git a/src/rs_driver b/src/rs_driver index bc0ef3e6..9774fbf8 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit bc0ef3e66708ae3fd58add8f067f35703661f342 +Subproject commit 9774fbf83c0e5c6c17cabb565ba28e5757ce751f From b9ea5b37ac64173b69cfb652c7d0862b4a99535e Mon Sep 17 00:00:00 2001 From: ronzheng Date: Mon, 31 Oct 2022 15:48:08 +0800 Subject: [PATCH 223/261] feat: suport ROS humble --- README.md | 7 +++++++ README_CN.md | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/README.md b/README.md index ae4eb187..92512916 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,7 @@ To use rslidar_sdk in the ROS2 environment, please install below libraries. + Ubuntu 16.04 - Not supported + Ubuntu 18.04 - ROS2 Eloquent desktop + Ubuntu 20.04 - ROS2 Galactic desktop ++ Ubuntu 22.04 - ROS2 Humble desktop For installation, please refer to https://index.ros.org/doc/ros2/Installation/Eloquent/Linux-Install-Debians/ @@ -165,6 +166,12 @@ roslaunch rslidar_sdk start.launch set(COMPILE_METHOD COLCON) ``` +If compile on The ROS2 Humble, set **-std** to **c++17** in *CMakeLists.txt*. This is because the Humble depends on C++17. + +```cmake +add_definitions(-std=c++17) +``` + (2) Copy the file *package_ros2.xml* to *package.xml* in the rslidar_sdk. (3) Create a new workspace folder, and create a *src* folder in it. Then put the rslidar_sdk project in the *src* folder. diff --git a/README_CN.md b/README_CN.md index 91ff7e80..9e864051 100644 --- a/README_CN.md +++ b/README_CN.md @@ -73,6 +73,7 @@ git submodule update + Ubuntu 16.04 - 不支持 + Ubuntu 18.04 - ROS2 Eloquent desktop + Ubuntu 20.04 - ROS2 Galactic desktop ++ Ubuntu 22.04 - ROS2 Humble desktop 安装方法请参考 https://index.ros.org/doc/ros2/Installation/Eloquent/Linux-Install-Debians/ @@ -162,6 +163,12 @@ roslaunch rslidar_sdk start.launch set(COMPILE_METHOD COLCON) ``` +如果是在ROS2 Humble编译,需要修改*CMakeLists.txt*中的如下行,将**-std**改为**c++17**。这是因为Humble的依赖库本身是基于C++17的。 + +```cmake +add_definitions(-std=c++17) +``` + (2) 将rslidar_sdk工程目录下的*package_ros2.xml*文件重命名为*package.xml*。 (3) 新建一个文件夹作为工作空间,然后再新建一个名为*src*的文件夹, 将rslidar_sdk工程放入*src*文件夹内。 @@ -178,6 +185,7 @@ ros2 launch rslidar_sdk start.py 不同ROS2版本start.py的格式可能不同,请使用对应版本的start.py。如ROS2 Elequent,请使用elequent_start.py。 + ## 5 参数介绍 rslidar_sdk的功能通过配置参数文件来实现,请仔细阅读。 From ba684edabf034ae388a579b235cf7325b487a04f Mon Sep 17 00:00:00 2001 From: ronzheng Date: Mon, 7 Nov 2022 15:51:03 +0800 Subject: [PATCH 224/261] feat: recover config.yaml --- config/config.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index a2602f6d..ad9b2acf 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -1,5 +1,5 @@ common: - msg_source: 3 #0: not use Lidar + msg_source: 1 #0: not use Lidar #1: packet message comes from online Lidar #2: packet message comes from ROS or ROS2 #3: packet message comes from Pcap file @@ -9,8 +9,8 @@ lidar: - driver: lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RSBPV4, RSHELIOS, RSHELIOS_16P, RS128, RS80, RS48, RSP128, RSP80, RSP48, # RSM1, RSM2, RSEOS, RSM1_JUMBO - msop_port: 1990 #Msop port of lidar - difop_port: 1991 #Difop port of lidar + msop_port: 6699 #Msop port of lidar + difop_port: 7788 #Difop port of lidar start_angle: 0 #Start angle of point cloud end_angle: 360 #End angle of point cloud wait_for_difop: true @@ -18,7 +18,7 @@ lidar: max_distance: 200 #Maximum distance of point cloud use_lidar_clock: false #True--Use the lidar clock as the message timestamp #False-- Use the system clock as the timestamp - pcap_path: /mnt/shared/pcap/M1/m1_1990_1991.pcap #The path of pcap file + pcap_path: /home/robosense/lidar.pcap #The path of pcap file ros: ros_frame_id: rslidar #Frame id of packet message and point cloud message ros_recv_packet_topic: /rslidar_packets #Topic used to receive lidar packets from ROS From 94c07c84848ea5cfe4ea5c88a09cbe04eb9e8098 Mon Sep 17 00:00:00 2001 From: ronzheng Date: Mon, 7 Nov 2022 16:17:15 +0800 Subject: [PATCH 225/261] feat: update docs --- README.md | 2 ++ README_CN.md | 2 ++ src/rs_driver | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 92512916..f889585a 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ To integrate the Lidar driver into your own projects, please use the rs_driver. - RS-Ruby-Plus-80 - RS-Ruby-Plus-48 - RS-LiDAR-M1 +- RS-LiDAR-M2 +- RS-LiDAR-EOS ### 1.2 Point Type Supported diff --git a/README_CN.md b/README_CN.md index 9e864051..d0e68e9e 100644 --- a/README_CN.md +++ b/README_CN.md @@ -27,6 +27,8 @@ - RS-Ruby-Plus-80 - RS-Ruby-Plus-48 - RS-LiDAR-M1 +- RS-LiDAR-M2 +- RS-LiDAR-EOS ### 1.2 支持的点类型 diff --git a/src/rs_driver b/src/rs_driver index 9774fbf8..d56e5000 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 9774fbf83c0e5c6c17cabb565ba28e5757ce751f +Subproject commit d56e50004573c0ca0a200df68764bd2f169f1b03 From a5069da966dfed901e0b3bbc523a5139fb8bb448 Mon Sep 17 00:00:00 2001 From: ronzheng Date: Mon, 7 Nov 2022 18:09:38 +0800 Subject: [PATCH 226/261] feat: suport ROS humble --- CMakeLists.txt | 5 +++++ README.md | 6 ------ README_CN.md | 6 ------ 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bdb88443..79c879e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,7 +57,12 @@ if (CMAKE_BUILD_TYPE STREQUAL "") add_definitions(-O3) endif() +if($ENV{ROS_DISTRO} STREQUAL "humble") # the ros2 humble requires c++17 +add_definitions(-std=c++17) +else() add_definitions(-std=c++14) +endif() + add_compile_options(-Wall) #======================== diff --git a/README.md b/README.md index f889585a..e86a21ad 100644 --- a/README.md +++ b/README.md @@ -168,12 +168,6 @@ roslaunch rslidar_sdk start.launch set(COMPILE_METHOD COLCON) ``` -If compile on The ROS2 Humble, set **-std** to **c++17** in *CMakeLists.txt*. This is because the Humble depends on C++17. - -```cmake -add_definitions(-std=c++17) -``` - (2) Copy the file *package_ros2.xml* to *package.xml* in the rslidar_sdk. (3) Create a new workspace folder, and create a *src* folder in it. Then put the rslidar_sdk project in the *src* folder. diff --git a/README_CN.md b/README_CN.md index d0e68e9e..2da1a4ff 100644 --- a/README_CN.md +++ b/README_CN.md @@ -165,12 +165,6 @@ roslaunch rslidar_sdk start.launch set(COMPILE_METHOD COLCON) ``` -如果是在ROS2 Humble编译,需要修改*CMakeLists.txt*中的如下行,将**-std**改为**c++17**。这是因为Humble的依赖库本身是基于C++17的。 - -```cmake -add_definitions(-std=c++17) -``` - (2) 将rslidar_sdk工程目录下的*package_ros2.xml*文件重命名为*package.xml*。 (3) 新建一个文件夹作为工作空间,然后再新建一个名为*src*的文件夹, 将rslidar_sdk工程放入*src*文件夹内。 From 923d6c0b0068ee6a9d61616c8a11446292df4e27 Mon Sep 17 00:00:00 2001 From: ronzheng Date: Fri, 11 Nov 2022 12:01:18 +0800 Subject: [PATCH 227/261] feat: rename RSEOS to RSE1 --- README.md | 2 +- README_CN.md | 2 +- config/config.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f889585a..6587081d 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ To integrate the Lidar driver into your own projects, please use the rs_driver. - RS-Ruby-Plus-48 - RS-LiDAR-M1 - RS-LiDAR-M2 -- RS-LiDAR-EOS +- RS-LiDAR-E1 ### 1.2 Point Type Supported diff --git a/README_CN.md b/README_CN.md index d0e68e9e..b8658955 100644 --- a/README_CN.md +++ b/README_CN.md @@ -28,7 +28,7 @@ - RS-Ruby-Plus-48 - RS-LiDAR-M1 - RS-LiDAR-M2 -- RS-LiDAR-EOS +- RS-LiDAR-E1 ### 1.2 支持的点类型 diff --git a/config/config.yaml b/config/config.yaml index ad9b2acf..a325868f 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -8,7 +8,7 @@ common: lidar: - driver: lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RSBPV4, RSHELIOS, RSHELIOS_16P, RS128, RS80, RS48, RSP128, RSP80, RSP48, - # RSM1, RSM2, RSEOS, RSM1_JUMBO + # RSM1, RSM1_JUMBO, RSM2, RSE1 msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar start_angle: 0 #Start angle of point cloud From 3b0c3ce00df65b182e66302e08943ca65b2c445b Mon Sep 17 00:00:00 2001 From: ronzheng Date: Wed, 16 Nov 2022 15:03:40 +0800 Subject: [PATCH 228/261] fix: fix doc of point type --- doc/howto/how_to_change_point_type.md | 60 ++++++++++++++++------ doc/howto/how_to_change_point_type_CN.md | 63 +++++++++++++++++------- 2 files changed, 90 insertions(+), 33 deletions(-) diff --git a/doc/howto/how_to_change_point_type.md b/doc/howto/how_to_change_point_type.md index 2ade699b..59d0333e 100644 --- a/doc/howto/how_to_change_point_type.md +++ b/doc/howto/how_to_change_point_type.md @@ -4,7 +4,7 @@ This document illustrates how to change the point type. -To change the type, open the ```CMakeLists.txt``` of the project, and change the variable `POINT_TYPE`. Remember to **rebuild** the project after changing it. +In ```CMakeLists.txt``` of the project, change the variable `POINT_TYPE`. Remember to **rebuild** the project after changing it. ```cmake #======================================= @@ -15,20 +15,36 @@ set(POINT_TYPE XYZI) ## 2 XYZI -If `POINT_TYPE` is `XYZI`, rslidar_sdk uses the PCL official type```pcl::PointXYZI```. +If `POINT_TYPE` is `XYZI`, rslidar_sdk uses the RoboSense defined type as below. -``` -typedef pcl::PointXYZI PointXYZI; +```c++ +struct PointXYZI +{ + float x; + float y; + float z; + uint8_t intensity; +}; ``` rslidar_sdk transforms point cloud of `PointXYZI` to ROS message of `PointCloud2`,and publish it. -``` - PointCloudT rs_msg; - sensor_msgs::msg::PointCloud2 ros_msg; - pcl::toROSMsg(rs_msg, ros_msg); +```c++ + sensor_msgs::PointCloud2 ros_msg; + addPointField(ros_msg, "x", 1, sensor_msgs::PointField::FLOAT32, offset); + addPointField(ros_msg, "y", 1, sensor_msgs::PointField::FLOAT32, offset); + addPointField(ros_msg, "z", 1, sensor_msgs::PointField::FLOAT32, offset); + addPointField(ros_msg, "intensity", 1, sensor_msgs::PointField::FLOAT32, offset); + + // + // copy points from point cloud of `PointXYZI` to `PointCloud2` + // + ... + ``` +Here `intensity` of `PointCloud2` is `float` type, not `uint8_t`. This is because most ROS based applications require `intensity` of `float` type. + ## 3 XYZIRT If `POINT_TYPE` is `XYZIRT`, rslidar_sdk uses the RoboSense defined type as below. @@ -36,18 +52,32 @@ If `POINT_TYPE` is `XYZIRT`, rslidar_sdk uses the RoboSense defined type as belo ```c++ struct PointXYZIRT { - PCL_ADD_POINT4D; + float x; + float y; + float z; uint8_t intensity; - uint16_t ring = 0; - double timestamp = 0; - EIGEN_MAKE_ALIGNED_OPERATOR_NEW -} EIGEN_ALIGN16; + uint16_t ring; + double timestamp; +}; ``` rslidar_sdk transforms point cloud of `PointXYZIRT` to ROS message of `PointCloud2`,and publish it. ```c++ -pcl::PointCloud::Ptr cloud_ptr (new pcl::PointCloud); -pcl::fromROSMsg(ros_msg, *cloud_ptr); + sensor_msgs::PointCloud2 ros_msg; + addPointField(ros_msg, "x", 1, sensor_msgs::PointField::FLOAT32, offset); + addPointField(ros_msg, "y", 1, sensor_msgs::PointField::FLOAT32, offset); + addPointField(ros_msg, "z", 1, sensor_msgs::PointField::FLOAT32, offset); + addPointField(ros_msg, "intensity", 1, sensor_msgs::PointField::FLOAT32, offset); +#ifdef POINT_TYPE_XYZIRT + sensor_msgs::PointCloud2Iterator iter_ring_(ros_msg, "ring"); + sensor_msgs::PointCloud2Iterator iter_timestamp_(ros_msg, "timestamp"); +#endif + + // + // copy points from point cloud of `PointXYZIRT` to `PointCloud2` + // + ... + ``` diff --git a/doc/howto/how_to_change_point_type_CN.md b/doc/howto/how_to_change_point_type_CN.md index 6ef3c5e9..3172746f 100644 --- a/doc/howto/how_to_change_point_type_CN.md +++ b/doc/howto/how_to_change_point_type_CN.md @@ -15,40 +15,67 @@ set(POINT_TYPE XYZI) ## 2 XYZI -`POINT_TYPE`为`XYZI`时,rslidar_sdk使用PCL官方定义的点类型```pcl::PointXYZI```. +`POINT_TYPE`为`XYZI`时,rslidar_sdk使用RoboSense自定义的点类型```PointXYZI```. -``` -typedef pcl::PointXYZI PointXYZI; +```c++ +struct PointXYZI +{ + float x; + float y; + float z; + uint8_t intensity; +}; ``` -rslidar_sdk将基于`PointXYZI`的点云,转换为ROS的PointCloud2消息,再发布出去。 +rslidar_sdk将基于`PointXYZI`的点云,转换为ROS的`PointCloud2`消息,再发布出去。 +```c++ + sensor_msgs::PointCloud2 ros_msg; + addPointField(ros_msg, "x", 1, sensor_msgs::PointField::FLOAT32, offset); + addPointField(ros_msg, "y", 1, sensor_msgs::PointField::FLOAT32, offset); + addPointField(ros_msg, "z", 1, sensor_msgs::PointField::FLOAT32, offset); + addPointField(ros_msg, "intensity", 1, sensor_msgs::PointField::FLOAT32, offset); + + // + // copy points from point cloud of `PointXYZI` to `PointCloud2` + // + ... ``` - PointCloudT rs_msg; - sensor_msgs::msg::PointCloud2 ros_msg; - pcl::toROSMsg(rs_msg, ros_msg); -``` + +这里`PointCloud2`中的`intensity`是`float`类型,而不是`uint8_t`类型。这是因为大多数基于ROS的程序都希望`float`类型的`intensity`。 ## 3 XYZIRT -`POINT_TYPE`为`XYZIRT`时,rslidar_sdk使用速腾自定义的点类型,定义如下。 +`POINT_TYPE`为`XYZIRT`时,rslidar_sdk使用RoboSense自定义的点类型```PointXYZRT```。 ```c++ struct PointXYZIRT { - PCL_ADD_POINT4D; + float x; + float y; + float z; uint8_t intensity; - uint16_t ring = 0; - double timestamp = 0; - EIGEN_MAKE_ALIGNED_OPERATOR_NEW -} EIGEN_ALIGN16; + uint16_t ring; + double timestamp; +}; ``` rslidar_sdk将基于`PointXYZIRT`的点云,转换为ROS的PointCloud2消息,再发布出去。 -``` - PointCloudT rs_msg; - sensor_msgs::msg::PointCloud2 ros_msg; - pcl::toROSMsg(rs_msg, ros_msg); +```c++ + sensor_msgs::PointCloud2 ros_msg; + addPointField(ros_msg, "x", 1, sensor_msgs::PointField::FLOAT32, offset); + addPointField(ros_msg, "y", 1, sensor_msgs::PointField::FLOAT32, offset); + addPointField(ros_msg, "z", 1, sensor_msgs::PointField::FLOAT32, offset); + addPointField(ros_msg, "intensity", 1, sensor_msgs::PointField::FLOAT32, offset); +#ifdef POINT_TYPE_XYZIRT + sensor_msgs::PointCloud2Iterator iter_ring_(ros_msg, "ring"); + sensor_msgs::PointCloud2Iterator iter_timestamp_(ros_msg, "timestamp"); +#endif + + // + // copy points from point cloud of `PointXYZIRT` to `PointCloud2` + // + ... ``` From 0d6c2f9b7b637e322afb12611ec090d66bb7628b Mon Sep 17 00:00:00 2001 From: ronzheng Date: Mon, 28 Nov 2022 18:09:56 +0800 Subject: [PATCH 229/261] feat: format with operator++ --- src/source/source_pointcloud_ros.hpp | 48 ++++++++++++++-------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/source/source_pointcloud_ros.hpp b/src/source/source_pointcloud_ros.hpp index 6d1887b3..67c8fdc6 100644 --- a/src/source/source_pointcloud_ros.hpp +++ b/src/source/source_pointcloud_ros.hpp @@ -98,17 +98,17 @@ inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const *iter_z_ = point.z; *iter_intensity_ = point.intensity; - iter_x_ = iter_x_ + 1; - iter_y_ = iter_y_ + 1; - iter_z_ = iter_z_ + 1; - iter_intensity_ = iter_intensity_ + 1; + ++iter_x_; + ++iter_y_; + ++iter_z_; + ++iter_intensity_; #ifdef POINT_TYPE_XYZIRT *iter_ring_ = point.ring; *iter_timestamp_ = point.timestamp; - iter_ring_ = iter_ring_ + 1; - iter_timestamp_ = iter_timestamp_ + 1; + ++iter_ring_; + ++iter_timestamp_; #endif } } @@ -124,17 +124,17 @@ inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const *iter_z_ = point.z; *iter_intensity_ = point.intensity; - iter_x_ = iter_x_ + 1; - iter_y_ = iter_y_ + 1; - iter_z_ = iter_z_ + 1; - iter_intensity_ = iter_intensity_ + 1; + ++iter_x_; + ++iter_y_;; + ++iter_z_; + ++iter_intensity_; #ifdef POINT_TYPE_XYZIRT *iter_ring_ = point.ring; *iter_timestamp_ = point.timestamp; - iter_ring_ = iter_ring_ + 1; - iter_timestamp_ = iter_timestamp_ + 1; + ++iter_ring_; + ++iter_timestamp_; #endif } } @@ -258,17 +258,17 @@ inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, *iter_z_ = point.z; *iter_intensity_ = point.intensity; - iter_x_ = iter_x_ + 1; - iter_y_ = iter_y_ + 1; - iter_z_ = iter_z_ + 1; - iter_intensity_ = iter_intensity_ + 1; + ++iter_x_; + ++iter_y_; + ++iter_z_; + ++iter_intensity_; #ifdef POINT_TYPE_XYZIRT *iter_ring_ = point.ring; *iter_timestamp_ = point.timestamp; - iter_ring_ = iter_ring_ + 1; - iter_timestamp_ = iter_timestamp_ + 1; + ++iter_ring_; + ++iter_timestamp_; #endif } } @@ -284,17 +284,17 @@ inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, *iter_z_ = point.z; *iter_intensity_ = point.intensity; - iter_x_ = iter_x_ + 1; - iter_y_ = iter_y_ + 1; - iter_z_ = iter_z_ + 1; - iter_intensity_ = iter_intensity_ + 1; + ++iter_x_; + ++iter_y_; + ++iter_z_; + ++iter_intensity_; #ifdef POINT_TYPE_XYZIRT *iter_ring_ = point.ring; *iter_timestamp_ = point.timestamp; - iter_ring_ = iter_ring_ + 1; - iter_timestamp_ = iter_timestamp_ + 1; + ++iter_ring_; + ++iter_timestamp_; #endif } } From 68e95f8ea8f23ae2d41e353f116d9785d13093c8 Mon Sep 17 00:00:00 2001 From: ronzheng Date: Tue, 29 Nov 2022 14:28:38 +0800 Subject: [PATCH 230/261] fix: fix width and height of point cloud --- src/source/source_pointcloud_ros.hpp | 29 +++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/source/source_pointcloud_ros.hpp b/src/source/source_pointcloud_ros.hpp index 67c8fdc6..a756d289 100644 --- a/src/source/source_pointcloud_ros.hpp +++ b/src/source/source_pointcloud_ros.hpp @@ -54,6 +54,17 @@ inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const ros_msg.fields.clear(); ros_msg.fields.reserve(fields); + if (send_by_rows) + { + ros_msg.width = rs_msg.width; + ros_msg.height = rs_msg.height; + } + else + { + ros_msg.width = rs_msg.height; // exchange width and height to be compatible with pcl::PointCloud<> + ros_msg.height = rs_msg.width; + } + int offset = 0; offset = addPointField(ros_msg, "x", 1, sensor_msgs::PointField::FLOAT32, offset); offset = addPointField(ros_msg, "y", 1, sensor_msgs::PointField::FLOAT32, offset); @@ -69,11 +80,8 @@ inline sensor_msgs::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, const #endif ros_msg.point_step = offset; - ros_msg.width = rs_msg.height; - ros_msg.height = rs_msg.width; ros_msg.row_step = ros_msg.width * ros_msg.point_step; ros_msg.is_dense = rs_msg.is_dense; - ros_msg.data.resize(ros_msg.point_step * ros_msg.width * ros_msg.height); sensor_msgs::PointCloud2Iterator iter_x_(ros_msg, "x"); @@ -213,6 +221,17 @@ inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, ros_msg.fields.clear(); ros_msg.fields.reserve(fields); + if (send_by_rows) + { + ros_msg.width = rs_msg.width; + ros_msg.height = rs_msg.height; + } + else + { + ros_msg.width = rs_msg.height; // exchange width and height to be compatible with pcl::PointCloud<> + ros_msg.height = rs_msg.width; + } + int offset = 0; offset = addPointField(ros_msg, "x", 1, sensor_msgs::msg::PointField::FLOAT32, offset); offset = addPointField(ros_msg, "y", 1, sensor_msgs::msg::PointField::FLOAT32, offset); @@ -228,11 +247,8 @@ inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, #endif ros_msg.point_step = offset; - ros_msg.width = rs_msg.height; - ros_msg.height = rs_msg.width; ros_msg.row_step = ros_msg.width * ros_msg.point_step; ros_msg.is_dense = rs_msg.is_dense; - ros_msg.data.resize(ros_msg.point_step * ros_msg.width * ros_msg.height); sensor_msgs::PointCloud2Iterator iter_x_(ros_msg, "x"); @@ -244,7 +260,6 @@ inline sensor_msgs::msg::PointCloud2 toRosMsg(const LidarPointCloudMsg& rs_msg, sensor_msgs::PointCloud2Iterator iter_timestamp_(ros_msg, "timestamp"); #endif - if (send_by_rows) { for (size_t i = 0; i < rs_msg.height; i++) From ace835b87b40235052a9ba849e6c5484123de1d4 Mon Sep 17 00:00:00 2001 From: ronzheng Date: Thu, 8 Dec 2022 18:49:06 +0800 Subject: [PATCH 231/261] feat: update CHANGELOG --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd8b4598..b860c82b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ ## Unreleased +## v1.5.8 - 2022-12-09 + +### Added +- Support ROS2/Humble Hawksbill +- rename RSEOS as RSE1 + +### Fixed +- Fix wrong widthxheight while ros_send_by_rows=true + + ## v1.5.7 - 2022-10-09 ### Added From 28f4dac943c04139007ff7759f344a35d7e17d52 Mon Sep 17 00:00:00 2001 From: ronzheng Date: Thu, 8 Dec 2022 18:49:43 +0800 Subject: [PATCH 232/261] feat: update docs --- README.md | 37 ++++++--- README_CN.md | 70 ++++++++++-------- ..._along_with_rslidar_sdk_node_v1.3.x_CN.md} | 20 +++-- ...type.md => 05_how_to_change_point_type.md} | 14 +++- ...N.md => 05_how_to_change_point_type_CN.md} | 14 +++- ...ar.md => 06_how_to_decode_online_lidar.md} | 22 +++--- ...md => 06_how_to_decode_online_lidar_CN.md} | 24 +++--- ....md => 07_online_lidar_advanced_topics.md} | 60 +++++++-------- ... => 07_online_lidar_advanced_topics_CN.md} | 60 +++++++-------- ..._file.md => 08_how_to_decode_pcap_file.md} | 24 +++--- ...CN.md => 08_how_to_decode_pcap_file_CN.md} | 24 +++--- ...ics.md => 09_pcap_file_advanced_topics.md} | 28 ++++--- ....md => 09_pcap_file_advanced_topics_CN.md} | 28 ++++--- ...0_how_to_use_coordinate_transformation.md} | 24 ++++-- ...ow_to_use_coordinate_transformation_CN.md} | 24 ++++-- ... 11_how_to_record_replay_packet_rosbag.md} | 28 ++++--- ..._how_to_record_replay_packet_rosbag_CN.md} | 30 +++++--- ..._create_deb.md => 12_how_to_create_deb.md} | 17 +++-- ...ket_rosbag.png => 04_01_packet_rosbag.png} | Bin .../{12_broadcast.png => 07_01_broadcast.png} | Bin .../img/{12_unicast.png => 07_02_unicast.png} | Bin .../{12_multicast.png => 07_03_multicast.png} | Bin ...s_port.png => 07_04_multi_lidars_port.png} | Bin ...idars_ip.png => 07_05_multi_lidars_ip.png} | Bin ...12_vlan_layer.png => 07_06_vlan_layer.png} | Bin doc/howto/img/{12_vlan.png => 07_07_vlan.png} | Bin ...12_user_layer.png => 07_08_user_layer.png} | Bin doc/howto/img/ethernet.png | Bin 81068 -> 0 bytes ...rameter_intro.md => 02_parameter_intro.md} | 24 +++--- ...r_intro_CN.md => 02_parameter_intro_CN.md} | 25 ++++--- ...intro.md => 03_hiding_parameters_intro.md} | 14 ++-- ...CN.md => 03_hiding_parameters_intro_CN.md} | 14 ++-- doc/src_intro/rslidar_sdk_intro_CN.md | 8 +- ...nload_page.png => 01_01_download_page.png} | Bin 34 files changed, 386 insertions(+), 247 deletions(-) rename doc/howto/{how_to_work_along_with_rslidar_sdk_node_v1.3.x_CN.md => 04_how_to_work_along_with_rslidar_sdk_node_v1.3.x_CN.md} (96%) rename doc/howto/{how_to_change_point_type.md => 05_how_to_change_point_type.md} (96%) rename doc/howto/{how_to_change_point_type_CN.md => 05_how_to_change_point_type_CN.md} (96%) rename doc/howto/{how_to_decode_online_lidar.md => 06_how_to_decode_online_lidar.md} (83%) rename doc/howto/{how_to_decode_online_lidar_CN.md => 06_how_to_decode_online_lidar_CN.md} (84%) rename doc/howto/{online_lidar_advanced_topics.md => 07_online_lidar_advanced_topics.md} (86%) rename doc/howto/{online_lidar_advanced_topics_CN.md => 07_online_lidar_advanced_topics_CN.md} (87%) rename doc/howto/{how_to_decode_pcap_file.md => 08_how_to_decode_pcap_file.md} (84%) rename doc/howto/{how_to_decode_pcap_file_CN.md => 08_how_to_decode_pcap_file_CN.md} (85%) rename doc/howto/{pcap_file_advanced_topics.md => 09_pcap_file_advanced_topics.md} (86%) rename doc/howto/{pcap_file_advanced_topics_CN.md => 09_pcap_file_advanced_topics_CN.md} (86%) rename doc/howto/{how_to_use_coordinate_transformation.md => 10_how_to_use_coordinate_transformation.md} (82%) rename doc/howto/{how_to_use_coordinate_transformation_CN.md => 10_how_to_use_coordinate_transformation_CN.md} (87%) rename doc/howto/{how_to_record_replay_packet_rosbag.md => 11_how_to_record_replay_packet_rosbag.md} (87%) rename doc/howto/{how_to_record_replay_packet_rosbag_CN.md => 11_how_to_record_replay_packet_rosbag_CN.md} (86%) rename doc/howto/{how_to_create_deb.md => 12_how_to_create_deb.md} (86%) rename doc/howto/img/{20_packet_rosbag.png => 04_01_packet_rosbag.png} (100%) rename doc/howto/img/{12_broadcast.png => 07_01_broadcast.png} (100%) rename doc/howto/img/{12_unicast.png => 07_02_unicast.png} (100%) rename doc/howto/img/{12_multicast.png => 07_03_multicast.png} (100%) rename doc/howto/img/{12_multi_lidars_port.png => 07_04_multi_lidars_port.png} (100%) rename doc/howto/img/{12_multi_lidars_ip.png => 07_05_multi_lidars_ip.png} (100%) rename doc/howto/img/{12_vlan_layer.png => 07_06_vlan_layer.png} (100%) rename doc/howto/img/{12_vlan.png => 07_07_vlan.png} (100%) rename doc/howto/img/{12_user_layer.png => 07_08_user_layer.png} (100%) delete mode 100644 doc/howto/img/ethernet.png rename doc/intro/{parameter_intro.md => 02_parameter_intro.md} (95%) rename doc/intro/{parameter_intro_CN.md => 02_parameter_intro_CN.md} (94%) rename doc/intro/{hiding_parameters_intro.md => 03_hiding_parameters_intro.md} (94%) rename doc/intro/{hiding_parameters_intro_CN.md => 03_hiding_parameters_intro_CN.md} (94%) rename img/{download_page.png => 01_01_download_page.png} (100%) diff --git a/README.md b/README.md index 04444fbb..fc8506cb 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ -# **rslidar_sdk** +# 1 **rslidar_sdk** [中文介绍](README_CN.md) + + ## 1 Introduction **rslidar_sdk** is the Software Development Kit of the RoboSense Lidar based on Ubuntu. It contains: @@ -36,6 +38,8 @@ To integrate the Lidar driver into your own projects, please use the rs_driver. - XYZI - x, y, z, intensity - XYZIRT - x, y, z, intensity, ring, timestamp + + ## 2 Download ### 2.1 Download via Git @@ -55,8 +59,9 @@ git submodule update Instead of using Git, user can also access [rslidar_sdk_release](https://github.com/RoboSense-LiDAR/rslidar_sdk/releases) to download the latest version of rslidar_sdk. Please download the **rslidar_sdk.tar.gz** archive instead of Source code. The Source code zip file does not contain the submodule rs_driver, so it has to be downloaded manaully. +![](./img/01_01_download_page.png) + -![](./img/download_page.png) ## 3 Dependencies @@ -108,6 +113,8 @@ Installation: sudo apt-get install -y libpcap-dev ``` + + ## 4 Compile & Run Please compile and run the driver in three ways. @@ -184,33 +191,39 @@ ros2 launch rslidar_sdk start.py Another version of start.py may be used, since it is different on different versios of ROS2. For example, elequent_start.py is used instead for ROS2 elequent. + + ## 5 Introduction to parameters To change behaviors of rslidar_sdk, change its parameters. please read the following links for detail information. -[Intro to parameters](doc/intro/parameter_intro.md) +[Intro to parameters](doc/intro/02_parameter_intro.md) + +[Intro to hidden parameters](doc/intro/03_hiding_parameters_intro.md) + -[Intro to hidden parameters](doc/intro/hiding_parameters_intro.md) ## 6 Quick start Below are some quick guides to use rslidar_sdk. -[Connect to online LiDAR and send point cloud through ROS](doc/howto/how_to_decode_online_lidar.md) +[Connect to online LiDAR and send point cloud through ROS](doc/howto/06_how_to_decode_online_lidar.md) + +[Decode PCAP file and send point cloud through ROS](doc/howto/08_how_to_decode_pcap_file.md) + +[Change Point Type](doc/howto/05_how_to_change_point_type.md) -[Decode PCAP file and send point cloud through ROS](doc/howto/how_to_decode_pcap_file.md) -[Change Point Type](doc/howto/how_to_change_point_type.md) ## 7 Advanced Topics -[Online Lidar - advanced topics](doc/howto/online_lidar_advanced_topics.md) +[Online Lidar - Advanced topics](doc/howto/07_online_lidar_advanced_topics.md) + +[PCAP file - Advanced topics](doc/howto/09_pcap_file_advanced_topics.md) -[PCAP file - advanced topics](doc/howto/pcap_file_advanced_topics.md) +[Coordinate Transformation](doc/howto/10_how_to_use_coordinate_transformation.md) -[Coordinate Transformation](doc/howto/how_to_use_coordinate_transformation.md) +[Record rosbag & Replay it](doc/howto/11_how_to_record_replay_packet_rosbag.md) -[Record rosbag & Replay it](doc/howto/how_to_record_replay_packet_rosbag.md) -## diff --git a/README_CN.md b/README_CN.md index 34602bc9..484a9d15 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,8 +1,10 @@ -# **rslidar_sdk** +# 1 **rslidar_sdk** [English Version](README.md) -## 1 工程简介 + + +## 1.1 工程简介 **rslidar_sdk** 是速腾聚创在Ubuntu环境下的雷达驱动软件包。它包括: + 雷达驱动内核[rs_driver](https://github.com/RoboSense-LiDAR/rs_driver), @@ -13,7 +15,7 @@ 如果希望将雷达驱动集成到自己的工程,作更深一步的二次开发,请基于rs_driver进行开发。 -### 1.1 支持的雷达型号 +### 1.1.1 支持的雷达型号 - RS-LiDAR-16 - RS-LiDAR-32 @@ -30,14 +32,16 @@ - RS-LiDAR-M2 - RS-LiDAR-E1 -### 1.2 支持的点类型 +### 1.1.2 支持的点类型 - XYZI - x, y, z, intensity - XYZIRT - x, y, z, intensity, ring, timestamp -## 2 下载 -### 2.1 使用 git clone + +## 1.2 下载 + +### 1.2.1 使用 git clone rslidar_sdk项目包含子模块驱动内核rs_driver。在执行git clone后,还需要执行相关指令,初始化并更新子模块。 @@ -48,17 +52,18 @@ git submodule init git submodule update ``` -### 2.2 直接下载 +### 1.2.2 直接下载 用户可以直接访问 [rslidar_sdk_release](https://github.com/RoboSense-LiDAR/rslidar_sdk/releases) 下载最新版本的rslidar_sdk. 请下载 **rslidar_sdk.tar.gz** 压缩包,不要下载Source code。因为Source code压缩包内不包含子模块rs_driver的代码, 用户还需自行下载rs_driver的代码放入其中才行。 +![](./img/01_01_download_page.png) + -![](./img/download_page.png) -## 3 依赖介绍 +## 1.3 依赖介绍 -### 3.1 ROS +### 1.3.1 ROS 在ROS环境下使用雷达驱动,需要安装ROS相关依赖库。 + Ubuntu 16.04 - ROS Kinetic desktop @@ -69,7 +74,7 @@ git submodule update **强烈建议安装ROS desktop-full版。这个过程会自动安装一些兼容版本的依赖库,如PCL库等。这样可以避免花大量时间,去逐个安装和配置它们**。 -### 3.2 ROS2 +### 1.3.2 ROS2 在ROS2环境下使用雷达驱动,需要安装ROS2相关依赖库。 + Ubuntu 16.04 - 不支持 @@ -81,7 +86,7 @@ git submodule update **请不要在一台电脑上同时安装ROS和ROS2,以避免可能的版本冲突,和手工安装其他库(如Yaml)的麻烦。** -### 3.3 Yaml (必需) +### 1.3.3 Yaml (必需) 版本号: >= v0.5.2 @@ -94,7 +99,7 @@ sudo apt-get update sudo apt-get install -y libyaml-cpp-dev ``` -### 3.4 libpcap (必需) +### 1.3.4 libpcap (必需) 版本号: >= v1.7.4 @@ -104,11 +109,13 @@ sudo apt-get install -y libyaml-cpp-dev sudo apt-get install -y libpcap-dev ``` -## 4 编译、运行 + + +## 1.4 编译、运行 可以使用三种方式编译、运行rslidar_sdk。 -### 4.1 直接编译 +### 1.4.1 直接编译 (1) 打开工程内的*CMakeLists.txt*文件,将文件顶部的变量**COMPILE_METHOD**改为**ORIGINAL**. @@ -130,7 +137,7 @@ cmake .. && make -j4 ./rslidar_sdk_node ``` -### 4.2 依赖于ROS-catkin编译 +### 1.4.2 依赖于ROS-catkin编译 (1) 打开工程内的*CMakeLists.txt*文件,将文件顶部的变量**COMPILE_METHOD**改为**CATKIN**. @@ -154,7 +161,7 @@ source devel/setup.bash roslaunch rslidar_sdk start.launch ``` -### 4.3 依赖于ROS2-colcon编译 +### 1.4.3 依赖于ROS2-colcon编译 (1) 打开工程内的*CMakeLists.txt*文件,将文件顶部的变量**COMPILE_METHOD**改为**COLCON**. @@ -182,31 +189,36 @@ ros2 launch rslidar_sdk start.py 不同ROS2版本start.py的格式可能不同,请使用对应版本的start.py。如ROS2 Elequent,请使用elequent_start.py。 -## 5 参数介绍 + +## 1.5 参数介绍 rslidar_sdk的功能通过配置参数文件来实现,请仔细阅读。 -[参数介绍](doc/intro/parameter_intro_CN.md) +[参数介绍](doc/intro/02_parameter_intro_CN.md) + +[隐藏参数介绍](doc/intro/03_hiding_parameters_intro_CN.md) -[隐藏参数介绍](doc/intro/hiding_parameters_intro_CN.md) -## 6 快速上手 + +## 1.6 快速上手 以下是一些常用功能的使用指南。 -[连接在线雷达数据并发送点云到ROS](doc/howto/how_to_decode_online_lidar_CN.md) +[连接在线雷达数据并发送点云到ROS](doc/howto/06_how_to_decode_online_lidar_CN.md) + +[解析PCAP包并发送点云到ROS](doc/howto/08_how_to_decode_pcap_file_CN.md) + +[切换点类型](doc/howto/05_how_to_change_point_type_CN.md) -[解析PCAP包并发送点云到ROS](doc/howto/how_to_decode_pcap_file_CN.md) -[切换点类型](doc/howto/how_to_change_point_type_CN.md) -## 7 使用进阶 +## 1.7 使用进阶 -[在线雷达-高级主题](doc/howto/online_lidar_advanced_topics_CN.md) +[在线雷达-高级主题](doc/howto/07_online_lidar_advanced_topics_CN.md) -[PCAP文件-高级主题](doc/howto/pcap_file_advanced_topics_CN.md) +[PCAP文件-高级主题](doc/howto/09_pcap_file_advanced_topics_CN.md) -[点云坐标变换](doc/howto/how_to_use_coordinate_transformation_CN.md) +[点云坐标变换](doc/howto/10_how_to_use_coordinate_transformation_CN.md) -[录制ROS数据包然后播放它](doc/howto/how_to_record_replay_packet_rosbag_CN.md) +[录制ROS数据包然后播放它](doc/howto/11_how_to_record_replay_packet_rosbag_CN.md) diff --git a/doc/howto/how_to_work_along_with_rslidar_sdk_node_v1.3.x_CN.md b/doc/howto/04_how_to_work_along_with_rslidar_sdk_node_v1.3.x_CN.md similarity index 96% rename from doc/howto/how_to_work_along_with_rslidar_sdk_node_v1.3.x_CN.md rename to doc/howto/04_how_to_work_along_with_rslidar_sdk_node_v1.3.x_CN.md index ed591da4..50bf6b61 100644 --- a/doc/howto/how_to_work_along_with_rslidar_sdk_node_v1.3.x_CN.md +++ b/doc/howto/04_how_to_work_along_with_rslidar_sdk_node_v1.3.x_CN.md @@ -1,6 +1,8 @@ -# 如何与rslidar_sdk_node v1.3.x共存? +# 4 如何与rslidar_sdk_node v1.3.x共存? -## 1 问题描述 + + +## 4.1 问题描述 `rslidar_sdk_node` `v1.3.x`和`v1.5.x`的配置方式不同。除了如下两个可能有交互的场景外, 两者各自运行,没有关系。 @@ -14,18 +16,20 @@ 本文说明如何配置`rslidar_sdk` `v1.5.x`,让它在第二种场景下可以同时播放`v1.3.x`和`v1.5.x`的packet rosbag。 -## 2 场景说明 + + +## 4.2 场景说明 场景说明如下。 + 2个雷达,`Lidar1`是运行`v1.3.x`的雷达,`Lidar2`是运行`v1.5.x`的雷达。 + 1台主机,用于分析`Lidar1`和`Lidar2`的数据。 -![](./img/20_packet_rosbag.png) +![](./img/04_01_packet_rosbag.png) -## 3 步骤 +## 4.3 步骤 -### 3.1 配置 v1.3.x 雷达 +### 4.3.1 配置 v1.3.x 雷达 使用`v1.3.x` `rslidar_sdk_node`录制pacekt rosbag。 @@ -51,7 +55,7 @@ lidar: ros_send_point_cloud_topic: /rslidar_points #Topic used to send point cloud through ROS ``` -### 3.2 配置 v1.5.x 雷达 +### 4.3.2 配置 v1.5.x 雷达 使用`v1.5.6` `rslidar_sdk_node`录制packet rosbag。 @@ -76,7 +80,7 @@ lidar: ``` -### 3.3 配置 v1.5.x 主机 +### 4.3.3 配置 v1.5.x 主机 + 打开CMake编译选项`ENABLE_SOURCE_PACKET_LEGACY=ON`,编译`rslidar_sdk`。 diff --git a/doc/howto/how_to_change_point_type.md b/doc/howto/05_how_to_change_point_type.md similarity index 96% rename from doc/howto/how_to_change_point_type.md rename to doc/howto/05_how_to_change_point_type.md index 59d0333e..5dd6924a 100644 --- a/doc/howto/how_to_change_point_type.md +++ b/doc/howto/05_how_to_change_point_type.md @@ -1,6 +1,8 @@ -# How to change point type +# 5 How to change point type -## 1 Introduction + + +## 5.1 Introduction This document illustrates how to change the point type. @@ -13,7 +15,9 @@ In ```CMakeLists.txt``` of the project, change the variable `POINT_TYPE`. Rememb set(POINT_TYPE XYZI) ``` -## 2 XYZI + + +## 5.2 XYZI If `POINT_TYPE` is `XYZI`, rslidar_sdk uses the RoboSense defined type as below. @@ -45,7 +49,9 @@ rslidar_sdk transforms point cloud of `PointXYZI` to ROS message of `PointCloud2 Here `intensity` of `PointCloud2` is `float` type, not `uint8_t`. This is because most ROS based applications require `intensity` of `float` type. -## 3 XYZIRT + + +## 5.3 XYZIRT If `POINT_TYPE` is `XYZIRT`, rslidar_sdk uses the RoboSense defined type as below. diff --git a/doc/howto/how_to_change_point_type_CN.md b/doc/howto/05_how_to_change_point_type_CN.md similarity index 96% rename from doc/howto/how_to_change_point_type_CN.md rename to doc/howto/05_how_to_change_point_type_CN.md index 3172746f..08eca6ca 100644 --- a/doc/howto/how_to_change_point_type_CN.md +++ b/doc/howto/05_how_to_change_point_type_CN.md @@ -1,6 +1,8 @@ -# 如何改变点类型的定义 +# 5 如何改变点类型的定义 -## 1 简介 + + +## 5.1 简介 本文档介绍如何改变点类型的定义。 @@ -13,7 +15,9 @@ set(POINT_TYPE XYZI) ``` -## 2 XYZI + + +## 5.2 XYZI `POINT_TYPE`为`XYZI`时,rslidar_sdk使用RoboSense自定义的点类型```PointXYZI```. @@ -44,7 +48,9 @@ rslidar_sdk将基于`PointXYZI`的点云,转换为ROS的`PointCloud2`消息, 这里`PointCloud2`中的`intensity`是`float`类型,而不是`uint8_t`类型。这是因为大多数基于ROS的程序都希望`float`类型的`intensity`。 -## 3 XYZIRT + + +## 5.3 XYZIRT `POINT_TYPE`为`XYZIRT`时,rslidar_sdk使用RoboSense自定义的点类型```PointXYZRT```。 diff --git a/doc/howto/how_to_decode_online_lidar.md b/doc/howto/06_how_to_decode_online_lidar.md similarity index 83% rename from doc/howto/how_to_decode_online_lidar.md rename to doc/howto/06_how_to_decode_online_lidar.md index 9f66d32c..905afca1 100644 --- a/doc/howto/how_to_decode_online_lidar.md +++ b/doc/howto/06_how_to_decode_online_lidar.md @@ -1,22 +1,24 @@ -# How to decode on-line LiDAR +# 6 How to decode on-line LiDAR -## 1 Introduction +## 6.1 Introduction This document illustrates how to connect to an on-line LiDAR, and send point cloud to ROS. -Please make sure you have read the LiDAR user-guide and [Intro to parameters](../intro/parameter_intro.md) before reading this document. +Please make sure you have read the LiDAR user-guide and [Intro to parameters](../intro/02_parameter_intro.md) before reading this document. -## 2 Steps -### 2.1 Get the LiDAR port number + +## 6.2 Steps + +### 6.2.1 Get the LiDAR port number Please follow the instructions in LiDAR user-guide, to connect the LiDAR, and set up your computer's ip address. Please check the LiDAR user-guide, or use the 3rd-party tool(such as WireShark), to get your LiDAR's MSOP port number and DIFOP port number. The default values are ```msop-6699, difop-7788```. -### 2.2 Set up the configuration file +### 6.2.2 Set up the configuration file -#### 2.2.1 common part +#### 6.2.2.1 common part ```yaml common: @@ -31,7 +33,7 @@ The message come from the LiDAR, so set ```msg_source = 1```. Send point cloud to ROS, so set ```send_point_cloud_ros = true```. -#### 2.2.2 lidar-driver part +#### 6.2.2.2 lidar-driver part ```yaml lidar: @@ -50,7 +52,7 @@ Set the ```lidar_type``` to your LiDAR type. Set the ```msop_port``` and ```difop_port``` to your LiDAR's port number. -#### 2.2.3 lidar-ros part +#### 6.2.2.3 lidar-ros part ```yaml ros: @@ -62,7 +64,7 @@ ros: Set the ```ros_send_point_cloud_topic``` to the topic you want to send to. -### 2.3 Run +### 6.2.3 Run Run the program. diff --git a/doc/howto/how_to_decode_online_lidar_CN.md b/doc/howto/06_how_to_decode_online_lidar_CN.md similarity index 84% rename from doc/howto/how_to_decode_online_lidar_CN.md rename to doc/howto/06_how_to_decode_online_lidar_CN.md index 0a7ac74e..6dda0f5b 100644 --- a/doc/howto/how_to_decode_online_lidar_CN.md +++ b/doc/howto/06_how_to_decode_online_lidar_CN.md @@ -1,24 +1,28 @@ -# 如何连接在线雷达 +# 6 如何连接在线雷达 -## 1 简介 + + +## 6.1 简介 本文档描述如何连接在线雷达,并发送点云数据到ROS。 -在阅读本文档之前, 请确保已经阅读过雷达用户手册和[参数简介](../intro/parameter_intro_CN.md) 。 +在阅读本文档之前, 请确保已经阅读过雷达用户手册和[参数简介](../intro/02_parameter_intro_CN.md) 。 + + -## 2 步骤 +## 6.2 步骤 -### 2.1 获取数据端口号 +### 6.2.1 获取数据端口号 根据雷达用户手册连接雷达, 并设置好您的电脑的IP地址。 请参考雷达用户手册,或使用第三方工具(如WireShark等)得到雷达的MSOP端口号和DIFOP端口号。端口的默认值分别为```6699```和```7788```。 -### 2.2 设置参数文件 +### 6.2.2 设置参数文件 设置参数文件```config.yaml```。 -#### 2.2.1 common部分 +#### 6.2.2.1 common部分 ```yaml common: @@ -33,7 +37,7 @@ common: 将点云发送到ROS以便查看,因此设置 ```send_point_cloud_ros = true``` 。 -#### 2.2.2 lidar-driver部分 +#### 6.2.2.2 lidar-driver部分 ```yaml lidar: @@ -52,7 +56,7 @@ lidar: 设置 ```msop_port``` 和 ```difop_port``` 为雷达数据端口号。 -#### 2.2.3 lidar-ros部分 +#### 6.2.2.3 lidar-ros部分 ```yaml ros: @@ -64,7 +68,7 @@ ros: 将 ```ros_send_point_cloud_topic``` 设置为发送点云的话题。 -### 2.3 运行 +### 6.2.3 运行 运行程序。 diff --git a/doc/howto/online_lidar_advanced_topics.md b/doc/howto/07_online_lidar_advanced_topics.md similarity index 86% rename from doc/howto/online_lidar_advanced_topics.md rename to doc/howto/07_online_lidar_advanced_topics.md index cbc5f443..62baf8ec 100644 --- a/doc/howto/online_lidar_advanced_topics.md +++ b/doc/howto/07_online_lidar_advanced_topics.md @@ -1,6 +1,8 @@ -# Online LiDAR - Advanced Topics +# 7 Online LiDAR - Advanced Topics -## 1 Introduction + + +## 7.1 Introduction The RoboSense LiDAR may work @@ -13,17 +15,18 @@ This document illustrates how to configure rslidar_sdk in each case. Before reading this document, please be sure that you have read: + LiDAR user-guide -+ [Intro to parameters](../intro/parameter_intro.md) -+ [Decode online LiDAR](./how_to_decode_online_lidar.md) ++ [Intro to parameters](../intro/02_parameter_intro.md) ++ [Decode online LiDAR](./06_how_to_decode_online_lidar.md) + -## 2 Unicast, Multicast and Broadcast -### 2.1 Broadcast mode +## 7.2 Unicast, Multicast and Broadcast + +### 7.2.1 Broadcast mode The Lidar sends MSOP/DIFOP packets to the host machine (rslidar_sdk runs on it). For simplicity, the DIFOP port is ommited here. + The Lidar sends to `255.255.255.255` : `6699`, and the host binds to port `6699`. - -![](./img/12_broadcast.png) +![](./img/07_01_broadcast.png) Below is how to configure `config.yaml`. @@ -44,12 +47,11 @@ lidar: The `common` part and the `lidar-ros` part is listed here. They will be ommited in the following examples, since they are not changed. -### 2.2 Unicast mode +### 7.2.2 Unicast mode To reduce the network load, the Lidar is suggested to work in unicast mode. + The Lidar sends to `192.168.1.102` : `6699`, and the host binds to port `6699`. - -![](./img/12_unicast.png) +![](./img/07_02_unicast.png) Below is how to configure `config.yaml`. In fact, it same with the broadcast mode. @@ -61,13 +63,12 @@ lidar: difop_port: 7788 ``` -### 2.3 Multicast mode +### 7.2.3 Multicast mode The Lidar may also works in multicast mode. + The lidar sends to `224.1.1.1`:`6699` + The host binds to port `6699`. And it makes local NIC (Network Interface Card) join the multicast group `224.1.1.1`. The local NIC's IP is `192.168.1.102`. - -![](./img/12_multicast.png) +![](./img/07_03_multicast.png) Below is how to configure `config.yaml`. @@ -81,15 +82,16 @@ lidar: host_address: 192.168.1.102 ``` -## 3 Multiple LiDARs -### 3.1 Different remote ports + +## 7.3 Multiple LiDARs + +### 7.3.1 Different remote ports If you have two or more Lidars, it is suggested to set different remote ports. + First Lidar sends to `192.168.1.102`:`6699`, and the first driver instance binds to `6699`. + Second Lidar sends to `192.168.1.102`:`5599`, and the second driver instance binds to `5599`. - -![](./img/12_multi_lidars_port.png) +![](./img/07_04_multi_lidars_port.png) Below is how to configure `config.yaml`. @@ -105,14 +107,13 @@ lidar: difop_port: 6688 ``` -### 3.2 Different remote IPs +### 7.3.2 Different remote IPs An alternate way is to set different remote IPs. + The host has two NICs: `192.168.1.102` and `192.168.1.103`. + First Lidar sends to `192.168.1.102`:`6699`, and the first driver instance binds to `192.168.1.102:6699`. + Second Lidar sends to `192.168.1.103`:`6699`, and the second driver instance binds to `192.168.1.103:6699`. - -![](./img/12_multi_lidars_ip.png) +![](./img/07_05_multi_lidars_ip.png) Below is how to configure `config.yaml`. @@ -130,19 +131,19 @@ lidar: host_address: 192.168.1.103 ``` -## 4 VLAN -In some user cases, The Lidar may work on VLAN. Its packets have a VLAN layer. -![](./img/12_vlan_layer.png) +## 7.4 VLAN + +In some user cases, The Lidar may work on VLAN. Its packets have a VLAN layer. +![](./img/07_06_vlan_layer.png) The driver cannot parse this packet. Instead, it depends on a virtual NIC to strip the VLAN layer. Below is an example. + The Lidar works on VLAN `80`. It sends packets to `192.168.1.102` : `6699`. The packet has a VLAN layer. + Suppose there is a physical NIC `eno1` on the host. It receives packets with VLAN layer. - -![](./img/12_vlan.png) +![](./img/07_07_vlan.png) To strip the VLAN layer, create a virtual NIC `eno1.80` on `eno1`, and assign IP `192.168.1.102` to it. @@ -164,12 +165,13 @@ lidar: difop_port: 7788 ``` -## 5 User Layer, Tail Layer + + +## 7.5 User Layer, Tail Layer In some user cases, User may add extra layers before or after the MSOP/DIFOP packet. + USER_LAYER is before the packet and TAIL_LAYER is after it. - -![](./img/12_user_layer.png) +![](./img/07_08_user_layer.png) These extra layers are parts of UDP data. The driver can strip them. diff --git a/doc/howto/online_lidar_advanced_topics_CN.md b/doc/howto/07_online_lidar_advanced_topics_CN.md similarity index 87% rename from doc/howto/online_lidar_advanced_topics_CN.md rename to doc/howto/07_online_lidar_advanced_topics_CN.md index b06570e8..a6ece182 100644 --- a/doc/howto/online_lidar_advanced_topics_CN.md +++ b/doc/howto/07_online_lidar_advanced_topics_CN.md @@ -1,6 +1,8 @@ -# 在线雷达 - 高级主题 +# 7 在线雷达 - 高级主题 -## 1 简介 + + +## 7.1 简介 RoboSense雷达可以工作在如下的场景。 @@ -13,17 +15,18 @@ RoboSense雷达可以工作在如下的场景。 在阅读本文档之前, 请确保已经阅读过: + 雷达用户手册 -+ [参数介绍](../intro/parameter_intro_CN.md) -+ [连接在线雷达](./how_to_decode_online_lidar_CN.md) ++ [参数介绍](../intro/02_parameter_intro_CN.md) ++ [连接在线雷达](./06_how_to_decode_online_lidar_CN.md) + -## 2 单播、组播、广播 -### 2.1 广播 +## 7.2 单播、组播、广播 + +### 7.2.1 广播 雷达发送 MSOP/DIFOP Packet到电脑主机。为简单起见,如下的图没有显示DIFOP端口。 + 雷达发送Packet到 `255.255.255.255` : `6699`, rslidar_sdk绑定到主机的端口 `6699`. - -![](./img/12_broadcast.png) +![](./img/07_01_broadcast.png) 如下是配置`config.yaml`的方式。 @@ -44,12 +47,11 @@ lidar: 这里列出了`common`部分和`lidar-ros`部分的设置。这两部分设置将在本文中后面的例子沿用,不再列出。 -### 2.2 单播 +### 7.2.2 单播 为了减少网络负载,建议雷达使用单播模式。 + 雷达发送Packet到 `192.168.1.102` : `6699`, rslidar_sdk绑定端口 `6699`。 - -![](./img/12_unicast.png) +![](./img/07_02_unicast.png) 如下是配置`config.yaml`的方式。这实际上与广播的方式一样。 @@ -61,13 +63,12 @@ lidar: difop_port: 7788 ``` -### 2.3 组播 +### 7.2.3 组播 雷达也可以工作在组播模式。 + 雷达发送Packet到 `224.1.1.1`:`6699` + rslidar_sdk绑定到端口 `6699`。同时它将IP地址为`192.168.1.102`的本地网络接口加入组播组`224.1.1.1`。 - -![](./img/12_multicast.png) +![](./img/07_03_multicast.png) 如下是配置`config.yaml`的方式。 @@ -81,15 +82,16 @@ lidar: host_address: 192.168.1.102 ``` -## 3 多个雷达的情况 -### 3.1 不同的目标端口 + +## 7.3 多个雷达的情况 + +### 7.3.1 不同的目标端口 如果有两个或多个雷达,首选的配置是让它们有不同的目标端口。 + 第一个雷达发送Packet到 `192.168.1.102`:`6699`, 给rslidar_sdk配置的第一个driver节点绑定到`6699`。 + 第二个雷达发送Packet到 `192.168.1.102`:`5599`, 给rslidar_sdk配置的第二个driver节点绑定到`5599`。 - -![](./img/12_multi_lidars_port.png) +![](./img/07_04_multi_lidars_port.png) 如下是配置`config.yaml`的方式。 @@ -105,14 +107,13 @@ lidar: difop_port: 6688 ``` -### 3.2 不同的目标IP +### 7.3.2 不同的目标IP 也可以让多个雷达使用不同的目标IP。 + 主机有两个网卡, IP地址分别为`192.168.1.102` 和 `192.168.1.103`。 + 第一个雷达发送Packet到 `192.168.1.102`:`6699`, 给rslidar_sdk配置的第一个driver节点绑定到`192.168.1.102:6699`。 + 第二个雷达发送Packet到 `192.168.1.103`:`6699`, 给rslidar_sdk配置的第二个driver节点绑定到`192.168.1.103:6699`。 - -![](./img/12_multi_lidars_ip.png) +![](./img/07_05_multi_lidars_ip.png) 如下是配置`config.yaml`的方式。 @@ -130,11 +131,12 @@ lidar: host_address: 192.168.1.103 ``` -## 4 VLAN -在某些场景下,雷达工作在VLAN层之上。MSOP/DIFOP Packet有VLAN层,如下图。 -![](./img/12_vlan_layer.png) +## 7.4 VLAN + +在某些场景下,雷达工作在VLAN层之上。MSOP/DIFOP Packet有VLAN层,如下图。 +![](./img/07_06_vlan_layer.png) rslidar_sdk不能解析VLAN层。 @@ -142,8 +144,7 @@ rslidar_sdk不能解析VLAN层。 + 雷达工作在VLAN id为`80`的VLAN层上。它发送Packet到`192.168.1.102` : `6699`,Packet有VLAN层。 + 假设主机上有一个支持VLAN的物理网卡`eno1`. 它接收带VLAN层的Packet。 - -![](../img/12_vlan.png) +![](./img/07_07_vlan.png) 要剥离VLAN层,需要基于`eno1`,创建一个虚拟网卡`eno1.80`, 并且将它的IP设置为`192.168.1.102`。 @@ -165,12 +166,13 @@ lidar: difop_port: 7788 ``` -## 5 User Layer, Tail Layer + + +## 7.5 User Layer, Tail Layer 在某些场景下,用户可能在MSOP/DIFOP数据前后加入自己的层。 + 在前面的是USER_LAYER,在后面的是TAIL_LAYER。 - -![](./img/12_user_layer.png) +![](./img/07_08_user_layer.png) 这两个层是UDP数据的一部分,所以rslidar_sdk可以自己剥除它们。只需要指出这两个层的长度就可以了。 diff --git a/doc/howto/how_to_decode_pcap_file.md b/doc/howto/08_how_to_decode_pcap_file.md similarity index 84% rename from doc/howto/how_to_decode_pcap_file.md rename to doc/howto/08_how_to_decode_pcap_file.md index bd73fb63..a6d2661c 100644 --- a/doc/howto/how_to_decode_pcap_file.md +++ b/doc/howto/08_how_to_decode_pcap_file.md @@ -1,22 +1,26 @@ -# How to decode PCAP file +# 8 How to decode PCAP file -## 1 Introduction + + +## 8.1 Introduction This document illustrates how to decode PCAP file, and send point cloud to ROS. -Please make sure you have read the LiDAR user-guide and [Intro to parameters](../intro/parameter_intro.md) before reading this document. +Please make sure you have read the LiDAR user-guide and [Intro to parameters](../intro/02_parameter_intro.md) before reading this document. + + -## 2 Steps +## 8.2 Steps -### 2.1 Get the LiDAR port number +### 8.2.1 Get the LiDAR port number Please check the LiDAR user-guide, or use the 3rd-party tool(such as WireShark), to get your LiDAR's MSOP port number and DIFOP port number. The default values are ```msop-6699, difop-7788```. -### 2.2 Set up the configuration file +### 8.2.2 Set up the configuration file Set up the configuration file `config.yaml`. -#### 2.2.1 common part +#### 8.2.2.1 common part ```yaml common: @@ -31,7 +35,7 @@ The messages come from the PCAP bag, so set ```msg_source = 3```. Send point cloud to ROS, so set ```send_point_cloud_ros = true```. -#### 2.2.2 lidar-driver part +#### 8.2.2.2 lidar-driver part ```yaml lidar: @@ -53,7 +57,7 @@ Set the ```lidar_type``` to your LiDAR type. Set the ```msop_port``` and ```difop_port``` to the port numbers of your LiDAR. -#### 2.2.3 lidar-ros part +#### 8.2.2.3 lidar-ros part ```yaml ros: @@ -65,7 +69,7 @@ ros: Set the ```ros_send_point_cloud_topic``` to the topic you want to send to. -### 2.3 Run +### 8.2.3 Run Run the program. diff --git a/doc/howto/how_to_decode_pcap_file_CN.md b/doc/howto/08_how_to_decode_pcap_file_CN.md similarity index 85% rename from doc/howto/how_to_decode_pcap_file_CN.md rename to doc/howto/08_how_to_decode_pcap_file_CN.md index 596dfdc2..c5fd4cb9 100644 --- a/doc/howto/how_to_decode_pcap_file_CN.md +++ b/doc/howto/08_how_to_decode_pcap_file_CN.md @@ -1,22 +1,26 @@ -# 如何解码PCAP文件 +# 8 如何解码PCAP文件 -## 1 简介 + + +## 8.1 简介 本文档展示如何解码PCAP文件, 并发送点云数据到ROS。 -在阅读本文档之前,请确保已阅读雷达用户手册和 [参数简介](../intro/parameter_intro_CN.md) 。 +在阅读本文档之前,请确保已阅读雷达用户手册和 [参数简介](../intro/02_parameter_intro_CN.md) 。 + + -## 2 步骤 +## 8.2 步骤 -### 2.1 获取数据的端口号 +### 8.2.1 获取数据的端口号 请参考雷达用户手册,或者使用第三方工具(WireShark等)抓包,得到雷达的目标MSOP端口和目标DIFOP端口。端口的默认值分别为`6699`和`7788`。 -### 2.2 设置参数文件 +### 8.2.2 设置参数文件 设置参数文件```config.yaml```。 -#### 2.2.1 common部分 +#### 8.2.2.1 common部分 ```yaml common: @@ -31,7 +35,7 @@ common: 将点云发送到ROS以便查看,所以设置 ```send_point_cloud_ros = true``` 。 -#### 2.2.2 lidar-driver部分 +#### 8.2.2.2 lidar-driver部分 ```yaml lidar: @@ -53,7 +57,7 @@ lidar: 设置 ```msop_port``` 和 ```difop_port``` 为雷达数据的目标端口号,这里分别是6699和7788。 -#### 2.2.3 lidar-ros部分 +#### 8.2.2.3 lidar-ros部分 ```yaml ros: @@ -65,6 +69,6 @@ ros: 将 ```ros_send_point_cloud_topic``` 设置为发送点云的话题,这里是/rslidar_points。 -### 2.3 运行 +### 8.2.3 运行 运行程序。 diff --git a/doc/howto/pcap_file_advanced_topics.md b/doc/howto/09_pcap_file_advanced_topics.md similarity index 86% rename from doc/howto/pcap_file_advanced_topics.md rename to doc/howto/09_pcap_file_advanced_topics.md index b01f8b76..cb939a6c 100644 --- a/doc/howto/pcap_file_advanced_topics.md +++ b/doc/howto/09_pcap_file_advanced_topics.md @@ -1,6 +1,8 @@ -# PCAP File - Advanced Topics +# 9 PCAP File - Advanced Topics -## 1 Introduction + + +## 9.1 Introduction The RoboSense LiDAR may work + in unicast/multicast/broadcast mode, @@ -12,10 +14,12 @@ This document illustrates how to configure rslidar_sdk in each case. Before reading this document, please be sure that you have read: + LiDAR user-guide -+ [Intro to parameters](../intro/parameter_intro.md) -+ [Online LiDAR - Advanced Topics](./online_lidar_advanced_topics.md) ++ [Intro to parameters](../intro/02_parameter_intro.md) ++ [Online LiDAR - Advanced Topics](./07_online_lidar_advanced_topics.md) + -## 2 General Case + +## 9.2 General Case Generally, below code is for decoding a PCAP file in these cases. + Broadcast/multicast/unicast mode @@ -39,11 +43,12 @@ lidar: The only exception is "Multiple Lidars with same ports but different IPs", which is not supported now. -## 3 VLAN -In some user cases, The LiDar may work on VLAN. Its packets have a VLAN layer. -![](./img/12_vlan_layer.png) +## 9.3 VLAN + +In some user cases, The LiDar may work on VLAN. Its packets have a VLAN layer. +![](./img/07_06_vlan_layer.png) rs_driver decodes PCAP file and gets all parts of MSOP packets, including the VLAN layer. @@ -59,12 +64,13 @@ lidar: use_vlan: true ``` -## 4 User Layer, Tail Layer + + +## 9.4 User Layer, Tail Layer In some user cases, User may add extra layers before or/and after the MSOP/DIFOP packet. + USER_LAYER is before the packet and TAIL_LAYER is after it. - -![](./img/12_user_layer.png) +![](./img/07_08_user_layer.png) These extra layers are parts of UDP data. The driver can strip them. diff --git a/doc/howto/pcap_file_advanced_topics_CN.md b/doc/howto/09_pcap_file_advanced_topics_CN.md similarity index 86% rename from doc/howto/pcap_file_advanced_topics_CN.md rename to doc/howto/09_pcap_file_advanced_topics_CN.md index 35041690..1a3dbf1f 100644 --- a/doc/howto/pcap_file_advanced_topics_CN.md +++ b/doc/howto/09_pcap_file_advanced_topics_CN.md @@ -1,6 +1,8 @@ -# PCAP文件 - 高级主题 +# 9 PCAP文件 - 高级主题 -## 1 简介 + + +## 9.1 简介 RoboSense雷达可以工作在如下场景。 + 单播/组播/广播模式 @@ -12,10 +14,12 @@ RoboSense雷达可以工作在如下场景。 在阅读本文之前,请先阅读: + 雷达用户使用手册 -+ [参数介绍](../intro/parameter_intro_CN.md) -+ [在线雷达-高级主题](./online_lidar_advanced_topics_CN.md) ++ [参数介绍](../intro/02_parameter_intro_CN.md) ++ [在线雷达-高级主题](./07_online_lidar_advanced_topics_CN.md) + -## 2 一般场景 + +## 9.2 一般场景 在下列场景下,使用如下配置解码PCAP文件。 + 广播/组播/单播模式 @@ -39,11 +43,12 @@ lidar: 一个例外是:PCAP文件中有多个雷达数据,但这些雷达目的端口相同,使用不同的目的IP地址来区分。这种情况不支持。 -## 3 VLAN -有些场景下,雷达工作在VLAN环境下。这时MSOP/DIFOP包带VLAN层,如下图。 -![](./img/12_vlan_layer.png) +## 9.3 VLAN + +有些场景下,雷达工作在VLAN环境下。这时MSOP/DIFOP包带VLAN层,如下图。 +![](./img/07_06_vlan_layer.png) rs_driver使用libpcap库解析PCAP文件,可以得到完整的、包括VLAN层的MSOP/DIFOP包。 @@ -59,12 +64,13 @@ lidar: use_vlan: true ``` -## 4 User Layer, Tail Layer + + +## 9.4 User Layer, Tail Layer 某些场景下,用户可能在MSOP/DIFOP数据前后加入自己的层。 + USER_LAYER 在MSOP/DIFOP数据之前,TAIL_LAYER在MSOP/DIFOP数据之后。 - -![](./img/12_user_layer.png) +![](./img/07_08_user_layer.png) 这些层是UDP数据的一部分,所以rs_driver可以自己剥除他们。只需要告诉它每个层的字节数就可以。 diff --git a/doc/howto/how_to_use_coordinate_transformation.md b/doc/howto/10_how_to_use_coordinate_transformation.md similarity index 82% rename from doc/howto/how_to_use_coordinate_transformation.md rename to doc/howto/10_how_to_use_coordinate_transformation.md index 71f01a32..d38e24ae 100644 --- a/doc/howto/how_to_use_coordinate_transformation.md +++ b/doc/howto/10_how_to_use_coordinate_transformation.md @@ -1,12 +1,16 @@ -# How to use coordinate transformation +# 10 How to use coordinate transformation -## 1 Introduction + + +## 10.1 Introduction rslidar_sdk can transform the coordinate of point cloud. This document illustrate how to do so. -Please check the [Intro to hiding parameters](../intro/hiding_parameters_intro.md) for more details. Here is an example of the config.yaml. +Please check the [Intro to hiding parameters](../intro/03_hiding_parameters_intro.md) for more details. Here is an example of the config.yaml. + -## 2 Dependencies + +## 10.2 Dependencies rslidar_sdk depends on the libeigen library to do coordinate transformation. Please install it first. @@ -14,7 +18,9 @@ rslidar_sdk depends on the libeigen library to do coordinate transformation. Ple sudo apt-get install libeigen3-dev ``` -## 3 Compile + + +## 10.3 Compile To enable transformation, set the CMake option ```ENABLE_TRANSFORM```to be ```ON```. @@ -36,7 +42,9 @@ To enable transformation, set the CMake option ```ENABLE_TRANSFORM```to be ```ON colcon build --cmake-args '-DENABLE_TRANSFORM=ON' ``` -## 4 Set LiDAR parameters + + +## 10.4 Set LiDAR parameters In the `lidar-driver` part of `config.yaml`, set the hiding parameter`x`, `y`, `z`, `roll`, `pitch` ,`yaw`. @@ -66,6 +74,8 @@ lidar: yaw: 1.57 ``` -## 5 Run + + +## 10.5 Run Run the program. diff --git a/doc/howto/how_to_use_coordinate_transformation_CN.md b/doc/howto/10_how_to_use_coordinate_transformation_CN.md similarity index 87% rename from doc/howto/how_to_use_coordinate_transformation_CN.md rename to doc/howto/10_how_to_use_coordinate_transformation_CN.md index 6e45c1e7..3895a2be 100644 --- a/doc/howto/how_to_use_coordinate_transformation_CN.md +++ b/doc/howto/10_how_to_use_coordinate_transformation_CN.md @@ -1,12 +1,16 @@ -# 如何使用坐标变换功能 +# 10 如何使用坐标变换功能 -## 1 简介 + + +## 10.1 简介 rslidar_sdk支持对点云进行坐标变换,本文档展示如何作这种变换。 -在阅读本文档之前,请确保已阅读雷达用户手册和[隐藏参数介绍](../intro/hiding_parameters_intro_CN.md)。 +在阅读本文档之前,请确保已阅读雷达用户手册和[隐藏参数介绍](../intro/03_hiding_parameters_intro_CN.md)。 + -## 2 依赖库 + +## 10.2 依赖库 rslidar_sdk的坐标变换基于libeigen库,所以要先安装它。 @@ -14,7 +18,9 @@ rslidar_sdk的坐标变换基于libeigen库,所以要先安装它。 sudo apt-get install libeigen3-dev ``` -## 3 编译 + + +## 10.3 编译 要启用坐标变换,编译rslidar_sdk时,需要将```ENABLE_TRANSFORM```选项设置为```ON```. @@ -36,7 +42,9 @@ sudo apt-get install libeigen3-dev colcon build --cmake-args '-DENABLE_TRANSFORM=ON' ``` -## 4 设置雷达参数 + + +## 10.4 设置雷达参数 在`config.yaml`中,设置`lidar-lidar`部分的参数`x`、, `y`、 `z`、 `roll`、 `pitch` 、`yaw`。 @@ -66,6 +74,8 @@ lidar: yaw: 1.57 ``` -## 5 运行 + + +## 10.5 运行 运行程序。 diff --git a/doc/howto/how_to_record_replay_packet_rosbag.md b/doc/howto/11_how_to_record_replay_packet_rosbag.md similarity index 87% rename from doc/howto/how_to_record_replay_packet_rosbag.md rename to doc/howto/11_how_to_record_replay_packet_rosbag.md index ccd2a6ca..32a307cc 100644 --- a/doc/howto/how_to_record_replay_packet_rosbag.md +++ b/doc/howto/11_how_to_record_replay_packet_rosbag.md @@ -1,16 +1,20 @@ -# How to record and replay Packet rosbag +# 11 How to record and replay Packet rosbag -## 1 Introduction + + +## 11.1 Introduction This document illustrates how to record and replay MSOP/DIFOP Packet rosbag. It is possible to record the point cloud message into a rosbag and replay it, but the point cloud rosbag is very large. rslidar_sdk provides a better way - record packet rosbag and replay it. -Please be sure you have read the LiDAR user-guide and [Connect to online LiDAR and send point cloud through ROS](how_to_decode_online_lidar.md). +Please be sure you have read the LiDAR user-guide and [Connect to online LiDAR and send point cloud through ROS](./06_how_to_decode_online_lidar.md). + -## 2 Record -### 2.1 Send packet to ROS +## 11.2 Record + +### 11.2.1 Send packet to ROS Here suppose that you have connected to an on-line LiDAR, and have sent the point cloud to ROS. @@ -26,7 +30,7 @@ common: To record packets, set ```send_packet_ros = true```. -### 2.2 Record the topic of packet +### 11.2.2 Record the topic of packet To change the topic of packet, change ```ros_send_packet_topic```. This topic sends out both MSOP and DIFOP packets. @@ -44,11 +48,13 @@ Record rosbag as below. rosbag record /rslidar_packets -O bag ``` -## 3 Replay + + +## 11.3 Replay Suppose you have recorded a rosbag, which contains MSOP/DIFOP packets with the topic ```/rslidar_packets```. -### 3.1 Set Packet Source +### 11.3.1 Set Packet Source In `config.yaml`, set the `common` part. @@ -65,7 +71,7 @@ Packet is from the ROS, so set ```msg_source = 2```. To send point cloud to ROS, set ```send_point_cloud_ros = true```. -### 3.2 Set parameters of Lidar +### 11.3.2 Set parameters of Lidar In `config.yaml`, set the `lidar-driver` part. @@ -84,7 +90,7 @@ lidar: Set the ```lidar_type``` to your LiDAR type. -### 3.3 Set Topic of packet. +### 11.3.3 Set Topic of packet. In `config.yaml`, set the `lidar-ros` part. @@ -98,7 +104,7 @@ ros: To receive MSOP/DIFOP packest, set ```ros_recv_packet_topic``` to the topic in the rosbag. -### 3.4 Run +### 11.3.4 Run Run the demo, and replay rosbag. diff --git a/doc/howto/how_to_record_replay_packet_rosbag_CN.md b/doc/howto/11_how_to_record_replay_packet_rosbag_CN.md similarity index 86% rename from doc/howto/how_to_record_replay_packet_rosbag_CN.md rename to doc/howto/11_how_to_record_replay_packet_rosbag_CN.md index 6600e1b6..d2d93e1f 100644 --- a/doc/howto/how_to_record_replay_packet_rosbag_CN.md +++ b/doc/howto/11_how_to_record_replay_packet_rosbag_CN.md @@ -1,16 +1,20 @@ -# 如何录制与回放 Packet rosbag +# 11 如何录制与回放 Packet rosbag -## 1 简介 + + +## 11.1 简介 本文档展示如何记录与回放MSOP/DIFOP rosbag。 使用ROS可以录制点云rosbag消息并回放,但点云包非常大,所以rslidar_sdk提供更好的选择,也就是录制Packet rosbag并回放。 -在阅读本文档之前, 请先阅读雷达用户手册和 [连接在线雷达并发送点云到ROS](./how_to_decode_online_lidar_CN.md) 。 +在阅读本文档之前, 请先阅读雷达用户手册和 [连接在线雷达并发送点云到ROS](./06_how_to_decode_online_lidar_CN.md) 。 + + -## 2 录制 +## 11.2 录制 -### 2.1 将MSOP/DIFOP Packet发送至ROS +### 11.2.1 将MSOP/DIFOP Packet发送至ROS 这里假设已经连接在线雷达,并能发送点云到ROS。 @@ -25,7 +29,7 @@ common: 要录制Packet, 设置 ```send_packet_ros = true```。 -### 2.2 根据话题录制rosbag +### 11.2.2 根据话题录制rosbag 修改```ros_send_packet_topic```, 来改变发送的话题。这个话题包括MSOP Packet和DIFOP Packet。 @@ -43,11 +47,13 @@ ROS录制rosbag的指令如下。 rosbag record /rslidar_packets -O bag ``` -## 3 回放 + + +## 11.3 回放 假设录制了一个rosbag,其中包含话题为 `/rslidar_packets` 的MSOP/DIFOP Packet。 -### 3.1 设置Packet源 +### 11.3.1 设置Packet源 配置`config.yaml`的`common`部分。 @@ -64,7 +70,7 @@ MSOP/DIFOP Packet来自ROS rosbag,因此设置 ```msg_source = 2``` 。 将点云发送到ROS,因此设置 ```send_point_cloud_ros = true```。 -### 3.2 设置雷达参数 +### 11.3.2 设置雷达参数 配置`config.yaml`的`lidar-driver`部分。 @@ -83,7 +89,7 @@ lidar: 将 ```lidar_type``` 设置为LiDAR类型 。 -### 3.3 设置接收Packet的主题 +### 11.3.3 设置接收Packet的主题 设置`config.yaml`的`lidar-ros`部分。 @@ -97,7 +103,9 @@ ros: 将 ```ros_recv_packet_topic``` 设置为rosbag中MSOP/DIFOP Packet的话题。 -### 3.4 运行 + + +### 11.3.4 运行 运行程序,回放rosbag。 diff --git a/doc/howto/how_to_create_deb.md b/doc/howto/12_how_to_create_deb.md similarity index 86% rename from doc/howto/how_to_create_deb.md rename to doc/howto/12_how_to_create_deb.md index c2aa4b56..b183eaaf 100644 --- a/doc/howto/how_to_create_deb.md +++ b/doc/howto/12_how_to_create_deb.md @@ -1,16 +1,24 @@ -# How to create deb +# 12 How to create deb -## 1 Introduction + + +## 12.1 Introduction Generating a ".deb" installable file is useful. -## 2 Create deb + + +## 12.2 Create deb + Just run the shell script: ``` ./create_debian.sh ``` The deb file will be generated in the parent directory of `rslidar_sdk`. -## 3 Use the deb + + +## 12.3 Use the deb + Install the deb and set the right config_path. If leave the config_path empty, it will use the `config.yaml` in the ros package path. ``` @@ -25,4 +33,3 @@ Install the deb and set the right config_path. If leave the config_path empty, i - diff --git a/doc/howto/img/20_packet_rosbag.png b/doc/howto/img/04_01_packet_rosbag.png similarity index 100% rename from doc/howto/img/20_packet_rosbag.png rename to doc/howto/img/04_01_packet_rosbag.png diff --git a/doc/howto/img/12_broadcast.png b/doc/howto/img/07_01_broadcast.png similarity index 100% rename from doc/howto/img/12_broadcast.png rename to doc/howto/img/07_01_broadcast.png diff --git a/doc/howto/img/12_unicast.png b/doc/howto/img/07_02_unicast.png similarity index 100% rename from doc/howto/img/12_unicast.png rename to doc/howto/img/07_02_unicast.png diff --git a/doc/howto/img/12_multicast.png b/doc/howto/img/07_03_multicast.png similarity index 100% rename from doc/howto/img/12_multicast.png rename to doc/howto/img/07_03_multicast.png diff --git a/doc/howto/img/12_multi_lidars_port.png b/doc/howto/img/07_04_multi_lidars_port.png similarity index 100% rename from doc/howto/img/12_multi_lidars_port.png rename to doc/howto/img/07_04_multi_lidars_port.png diff --git a/doc/howto/img/12_multi_lidars_ip.png b/doc/howto/img/07_05_multi_lidars_ip.png similarity index 100% rename from doc/howto/img/12_multi_lidars_ip.png rename to doc/howto/img/07_05_multi_lidars_ip.png diff --git a/doc/howto/img/12_vlan_layer.png b/doc/howto/img/07_06_vlan_layer.png similarity index 100% rename from doc/howto/img/12_vlan_layer.png rename to doc/howto/img/07_06_vlan_layer.png diff --git a/doc/howto/img/12_vlan.png b/doc/howto/img/07_07_vlan.png similarity index 100% rename from doc/howto/img/12_vlan.png rename to doc/howto/img/07_07_vlan.png diff --git a/doc/howto/img/12_user_layer.png b/doc/howto/img/07_08_user_layer.png similarity index 100% rename from doc/howto/img/12_user_layer.png rename to doc/howto/img/07_08_user_layer.png diff --git a/doc/howto/img/ethernet.png b/doc/howto/img/ethernet.png deleted file mode 100644 index 329d7c819fd81f8e89f4b47e35c9824697319d16..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 81068 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 diff --git a/doc/intro/parameter_intro.md b/doc/intro/02_parameter_intro.md similarity index 95% rename from doc/intro/parameter_intro.md rename to doc/intro/02_parameter_intro.md index db11ec4b..8b92ab8e 100644 --- a/doc/intro/parameter_intro.md +++ b/doc/intro/02_parameter_intro.md @@ -1,4 +1,4 @@ -# Introduction to Parameters +# 2 Introduction to Parameters rslidar_sdk reads parameters from the configuration file ```config.yaml```, which is stored in ```rslidar_sdk/config```. @@ -8,7 +8,9 @@ rslidar_sdk supports multi-LiDARs case. The `common` part is shared by all LiDAR **config.yaml is indentation sensitive! Please make sure the indentation is not changed after adjusting the parameters!** -## 1 Common + + +## 2.1 Common The `common` part specifies the source of LiDAR packets, and where to publish point clouds and packets. @@ -23,11 +25,11 @@ common: - 0 -- Unused. Never set this parameter to 0. - - 1 -- LiDAR packets come from on-line LiDARs. For more details, please refer to [Connect to online LiDAR and send point cloud through ROS](../howto/how_to_decode_online_lidar.md) + - 1 -- LiDAR packets come from on-line LiDARs. For more details, please refer to [Connect to online LiDAR and send point cloud through ROS](../howto/06_how_to_decode_online_lidar.md) - - 2 -- LiDAR packets come from ROS/ROS2. It is used to decode from an off-line rosbag. For more details, please refer to [Record rosbag & Replay it](../howto/how_to_record_replay_packet_rosbag.md) + - 2 -- LiDAR packets come from ROS/ROS2. It is used to decode from an off-line rosbag. For more details, please refer to [Record rosbag & Replay it](../howto/11_how_to_record_replay_packet_rosbag.md) - - 3 -- LiDAR packets come from a PCAP bag. For more details, please refer to [Decode PCAP file and send point cloud through ROS](../howto/how_to_decode_pcap_file.md) + - 3 -- LiDAR packets come from a PCAP bag. For more details, please refer to [Decode PCAP file and send point cloud through ROS](../howto/08_how_to_decode_pcap_file.md) - send_packet_ros @@ -41,7 +43,9 @@ common: *The ROS point cloud type is the ROS official defined type -- sensor_msgs/PointCloud2, so it can be visualized on the ROS `rviz` tool directly. It is not suggested to record the point cloud to rosbag, because its size may be very large. Please record Packets instead. Refer to the case of msg_source=2.* -## 2 lidar + + +## 2.2 lidar The `lidar` part needs to be adjusted for every LiDAR seperately. @@ -102,9 +106,11 @@ lidar: - true -- send point cloud row by row - false -- send point cloud clolumn by column -## 3 Example -### 3.1 Single Lidar Case + +## 2.3 Examples + +### 2.3.1 Single Lidar Case Connect to 1 LiDAR of RS128, and send point cloud to ROS. @@ -130,7 +136,7 @@ lidar: ros_send_point_cloud_topic: /rslidar_points ``` -### 3.2 Multi Lidar Case +### 2.3.2 Multi Lidar Case Connect to 1 LiDAR of RS128, and 2 LiDARs of RSBP, and send point cloud to ROS. diff --git a/doc/intro/parameter_intro_CN.md b/doc/intro/02_parameter_intro_CN.md similarity index 94% rename from doc/intro/parameter_intro_CN.md rename to doc/intro/02_parameter_intro_CN.md index 22df3019..f96389b3 100644 --- a/doc/intro/parameter_intro_CN.md +++ b/doc/intro/02_parameter_intro_CN.md @@ -1,4 +1,4 @@ -# 参数介绍 +# 2 参数介绍 rslidar_sdk读取配置文件 ```config.yaml```,得到所有的参数。```config.yaml```在```rslidar_sdk/config```文件夹中。 @@ -8,7 +8,9 @@ config.yaml包括两部分:common部分 和 lidar部分。 rslidar_sdk支持多个雷达。common部分为所有雷达共享。lidar部分,每一个子节点对应一个雷达,针对这个雷达的实际情况分别设置。 -## 1 common部分 + + +## 2.1 common部分 common部分设置雷达消息的源(Packet或点云从哪来)和目标(Packet或点云发布到哪去)。 @@ -21,11 +23,11 @@ common: - msg_source - - 1 -- 连接在线雷达。更多使用细节,请参考[连接在线雷达并发送点云到ROS](../howto/how_to_decode_online_lidar_CN.md)。 + - 1 -- 连接在线雷达。更多使用细节,请参考[连接在线雷达并发送点云到ROS](../howto/06_how_to_decode_online_lidar_CN.md)。 - - 2 -- 离线解析ROS/ROS2的Packet包。更多使用细节,请参考 [录制ROS数据包然后播放它](../howto/how_to_record_replay_packet_rosbag_CN.md)。 + - 2 -- 离线解析ROS/ROS2的Packet包。更多使用细节,请参考 [录制ROS数据包然后播放它](../howto/11_how_to_record_replay_packet_rosbag_CN.md)。 - - 3 -- 离线解析PCAP包。更多使用细节,请参考[离线解析PCAP包并发送点云到ROS](../howto/how_to_decode_pcap_file_CN.md)。 + - 3 -- 离线解析PCAP包。更多使用细节,请参考[离线解析PCAP包并发送点云到ROS](../howto/08_how_to_decode_pcap_file_CN.md)。 - send_packet_ros @@ -39,7 +41,11 @@ common: *点云消息的类型为ROS官方定义的点云类型sensor_msgs/PointCloud2, 用户可以使用Rviz直接查看点云。用户可以录制ROS/ROS2的点云包,但点云包的体积非常大,所以不建议这么做。更好的方式是录制Packet包,请参考send_packet_ros=true的情况。* -## 2 lidar部分 + + + + +## 2.2 lidar部分 lidar部分根据每个雷达的实际情况进行设置。 @@ -102,9 +108,10 @@ lidar: - false -- 发送点云时,按照一列一列的顺序排列点 -## 3 示例 -### 3.1 单台雷达 +## 2.3 示例 + +### 2.3.1 单台雷达 在线连接1台RS128雷达,并发送点云到ROS。 @@ -130,7 +137,7 @@ lidar: ros_send_point_cloud_topic: /rslidar_points ``` -### 3.2 单台雷达 +### 2.3.2 单台雷达 在线连接1台RS128雷达和2台RSBP雷达,发送点云到ROS。 diff --git a/doc/intro/hiding_parameters_intro.md b/doc/intro/03_hiding_parameters_intro.md similarity index 94% rename from doc/intro/hiding_parameters_intro.md rename to doc/intro/03_hiding_parameters_intro.md index 6b9420bd..0e2388ef 100644 --- a/doc/intro/hiding_parameters_intro.md +++ b/doc/intro/03_hiding_parameters_intro.md @@ -1,10 +1,12 @@ -# Introduction to hidden parameters +# 3 Introduction to hidden parameters In order to make the configuration file as simple as possible, we hide some parameters and use default values for them. This document explains the meanings of these hidden parameters. -## 1 common + + +## 3.1 common ```yaml common: @@ -15,7 +17,9 @@ common: send_point_cloud_proto: false ``` -## 2 lidar + + +## 3.2 lidar ```yaml lidar: @@ -63,8 +67,8 @@ lidar: - ```split_angle``` -- The angle(in degree) to split frames. Only be used when ```split_frame_mode = 1```. The default value is ```0```. - ```num_blks_split``` -- The number of blocks in one frame. Only be used when ```split_frame_mode = 3```. - ```wait_for_difop``` -- If ```false```, the driver will not wait for difop packet(including lidar configuration data, especially angle data to calculate x, y, z), and send out the point cloud immediately. The default value is ```true```. -- ```group_address``` -- If use multi-cast function, this parameter needs to be set correctly. For more details, please refer to [Online LiDAR - Advanced Topics](../howto/online_lidar_advanced_topics.md) +- ```group_address``` -- If use multi-cast function, this parameter needs to be set correctly. For more details, please refer to [Online LiDAR - Advanced Topics](../howto/07_online_lidar_advanced_topics.md) - ```host_address``` -- Needed in two conditions. If the host receives packets from multiple Lidars via different IP addresses, use this parameter to specify destination IPs of the Lidars; If group_address is set, it should be set, so it will be joined into the multicast group. -- ```x, y, z, roll, pitch, yaw ``` -- The parameters to do coordinate transformation. If the coordinate transformation function is enabled in driver core, the output point cloud will be transformed based on these parameters. For more details, please refer to [Coordinate Transformation](../howto/how_to_use_coordinate_transformation.md) +- ```x, y, z, roll, pitch, yaw ``` -- The parameters to do coordinate transformation. If the coordinate transformation function is enabled in driver core, the output point cloud will be transformed based on these parameters. For more details, please refer to [Coordinate Transformation](../howto/10_how_to_use_coordinate_transformation.md) - ```use_vlan``` -- Whether to use VLAN. The default value is ```false```. This parameter is only needed for pcap file. If it contains packets with VLAN layer, ```use_vlan``` should set to true. In the case of online Lidar, the VLAN layer is stripped by the protocol layer, so use_vlan can be ignored. diff --git a/doc/intro/hiding_parameters_intro_CN.md b/doc/intro/03_hiding_parameters_intro_CN.md similarity index 94% rename from doc/intro/hiding_parameters_intro_CN.md rename to doc/intro/03_hiding_parameters_intro_CN.md index a5828c08..0a1900ad 100644 --- a/doc/intro/hiding_parameters_intro_CN.md +++ b/doc/intro/03_hiding_parameters_intro_CN.md @@ -1,10 +1,12 @@ -# 隐藏参数介绍 +# 3 隐藏参数介绍 为了使配置文件config.yaml尽可能简洁,我们隐藏了部分不常用的参数,在代码中使用默认值。 本文档将详细介绍这些隐藏参数。用户可根据需要,将它们加入参数文件,重新设置。 -## 1 common + + +## 3.1 common ```yaml common: @@ -13,7 +15,9 @@ common: send_point_cloud_ros: false ``` -## 2 lidar + + +## 3.2 lidar ```yaml lidar: @@ -60,7 +64,7 @@ lidar: - ```split_angle``` -- 用于分帧的角度(单位为度), 在```split_frame_mode = 1``` 时才生效,默认值为```0```。 - ```num_blks_split``` -- 用于分帧的包数,在 ```split_frame_mode = 3```时才生效,默认值为1。 - ```wait_for_difop``` -- 若设置为false, 驱动将不会等待DIFOP包(包含配置数据,尤其是角度信息),而是立即解析MSOP包并发出点云。 默认值为```true```,也就是必须要有DIFOP包才会进行点云解析。 -- ```group_address``` -- 如果雷达为组播模式,此参数需要被设置为组播的地址。具体使用方式可以参考[在线雷达 - 高级主题](../howto/online_lidar_advanced_topics_CN.md) 。 +- ```group_address``` -- 如果雷达为组播模式,此参数需要被设置为组播的地址。具体使用方式可以参考[在线雷达 - 高级主题](../howto/07_online_lidar_advanced_topics_CN.md) 。 - ```host_address``` -- 有两种情况需要这个选项。如果主机上通过多个IP地址接收多个雷达的数据,则可以将此参数指定为雷达的目标IP;如果设置了group_address,那也需要设置host_address,以便将这个IP地址的网卡加入组播组。 -- ```x, y, z, roll, pitch, yaw ``` -- 坐标变换参数,若启用了内核的坐标变换功能,将会使用此参数输出经过变换后的点云。x, y, z, 单位为```米```, roll, pitch, yaw, 单位为```弧度```。具体使用方式可以参考 [坐标变换功能](../howto/how_to_use_coordinate_transformation_CN.md) 。 +- ```x, y, z, roll, pitch, yaw ``` -- 坐标变换参数,若启用了内核的坐标变换功能,将会使用此参数输出经过变换后的点云。x, y, z, 单位为```米```, roll, pitch, yaw, 单位为```弧度```。具体使用方式可以参考 [坐标变换功能](../howto/10_how_to_use_coordinate_transformation_CN.md) 。 - ```use_vlan``` -- 默认为false,指定是否使用vlan。如果pcap文件中的packet带vlan层,则需要设置这个选项为true。其他情况下不需要。在线雷达的情况下,协议层到达驱动时,已经剥离vlan层,所以不需要设置这个选项。 diff --git a/doc/src_intro/rslidar_sdk_intro_CN.md b/doc/src_intro/rslidar_sdk_intro_CN.md index 2f4fc00c..c5e6cb1f 100644 --- a/doc/src_intro/rslidar_sdk_intro_CN.md +++ b/doc/src_intro/rslidar_sdk_intro_CN.md @@ -1,4 +1,6 @@ -# rslidar_sdk v1.5.7 源代码解析 +# rslidar_sdk v1.5.8 源代码解析 + + ## 1 简介 @@ -10,6 +12,8 @@ rslidar_sdk的基本功能如下: + 从ROS主题`/rslidar_packets`得到MSOP/DIFOP Packet,解析得到点云,再发布到主题`/rslidar_points`。 + 这里的主题`/rslidar_packets`,由使用者通过回放Packet rosbag文件发布。 + + ## 2 Source 与 Destination 如前面所说,rslidar_sdk从在线雷达、PCAP文件、ROS主题这三种源得到MSOP/DIFOP Packet,将Packet发布到ROS主题/rslidar_packets`/rslidar_packets`,将点云发布到目标 - ROS主题`/rslidar_points`。 @@ -171,6 +175,8 @@ putPacket()接收Packet,送到`driver_ptr_`解析。 + 调用LidarDriver::decodePacket(),将Packet喂给`driver_ptr_`。 + 点云的接收,使用SourceDriver的已有实现。 + + ## 3 NodeManager NodeManager管理Source实例,包括创建、初始化、启动、停止Source。它支持多个源,但是这些源的类型必须相同。 diff --git a/img/download_page.png b/img/01_01_download_page.png similarity index 100% rename from img/download_page.png rename to img/01_01_download_page.png From 0f600028b178a2dce777a7515bc630c92237c685 Mon Sep 17 00:00:00 2001 From: ronzheng Date: Fri, 9 Dec 2022 09:46:41 +0800 Subject: [PATCH 233/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index d56e5000..0383b918 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit d56e50004573c0ca0a200df68764bd2f169f1b03 +Subproject commit 0383b918e54a0d5d7020c26fa07292de2cfca399 From d9d6b9b453e28f15db0bab3f4746440064d91ea3 Mon Sep 17 00:00:00 2001 From: ronzheng Date: Fri, 10 Feb 2023 11:36:02 +0800 Subject: [PATCH 234/261] feat: increase send and receive buffer to avoid packet loss --- src/source/source_packet_ros.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/source/source_packet_ros.hpp b/src/source/source_packet_ros.hpp index 529aa927..00ab6d98 100644 --- a/src/source/source_packet_ros.hpp +++ b/src/source/source_packet_ros.hpp @@ -201,7 +201,7 @@ inline void DestinationPacketRos::init(const YAML::Node& config) ros_send_topic, "rslidar_packets"); nh_ = std::unique_ptr(new ros::NodeHandle()); - pkt_pub_ = nh_->advertise(ros_send_topic, 10); + pkt_pub_ = nh_->advertise(ros_send_topic, 100); } inline void DestinationPacketRos::sendPacket(const Packet& msg) @@ -274,7 +274,7 @@ void SourcePacketRos::init(const YAML::Node& config) node_name << "rslidar_packets_source_" << node_index++; node_ptr_.reset(new rclcpp::Node(node_name.str())); - pkt_sub_ = node_ptr_->create_subscription(ros_recv_topic, 10, + pkt_sub_ = node_ptr_->create_subscription(ros_recv_topic, 100, std::bind(&SourcePacketRos::putPacket, this, std::placeholders::_1)); } @@ -330,7 +330,7 @@ inline void DestinationPacketRos::init(const YAML::Node& config) node_name << "rslidar_packets_destination_" << node_index++; node_ptr_.reset(new rclcpp::Node(node_name.str())); - pkt_pub_ = node_ptr_->create_publisher(ros_send_topic, 10); + pkt_pub_ = node_ptr_->create_publisher(ros_send_topic, 100); } inline void DestinationPacketRos::sendPacket(const Packet& msg) From 55a875c5d48d10f130ed1cd418f802ea888fd9c1 Mon Sep 17 00:00:00 2001 From: ronzheng Date: Fri, 17 Feb 2023 16:54:29 +0800 Subject: [PATCH 235/261] feat: update docs --- CHANGELOG.md | 9 +++++++-- doc/src_intro/rslidar_sdk_intro_CN.md | 2 +- src/rs_driver | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b860c82b..bfee00ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,12 @@ -# CHANGELOG - +# CHANGELOG ## Unreleased +## v1.5.9 - 2023-02-17 + +### Changed +- Increase sending DDS buffer queue to avoid packet loss + + ## v1.5.8 - 2022-12-09 ### Added diff --git a/doc/src_intro/rslidar_sdk_intro_CN.md b/doc/src_intro/rslidar_sdk_intro_CN.md index c5e6cb1f..99815030 100644 --- a/doc/src_intro/rslidar_sdk_intro_CN.md +++ b/doc/src_intro/rslidar_sdk_intro_CN.md @@ -1,4 +1,4 @@ -# rslidar_sdk v1.5.8 源代码解析 +# rslidar_sdk v1.5.9 源代码解析 diff --git a/src/rs_driver b/src/rs_driver index 0383b918..d90fa561 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 0383b918e54a0d5d7020c26fa07292de2cfca399 +Subproject commit d90fa561b35270318b0dfc86a126f17a71b0e160 From 07f17be2386ca7541dbea4aba2ed309652d6fc2d Mon Sep 17 00:00:00 2001 From: ronzheng Date: Fri, 17 Feb 2023 16:56:14 +0800 Subject: [PATCH 236/261] feat: sync to rs_driver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index d90fa561..3c36c089 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit d90fa561b35270318b0dfc86a126f17a71b0e160 +Subproject commit 3c36c089277cb366603f1bc4b5d406ee911dfb80 From 1d44d5fd58ed6c359746a77af0ff38e52e78da7a Mon Sep 17 00:00:00 2001 From: ronzheng Date: Mon, 27 Feb 2023 15:34:13 +0800 Subject: [PATCH 237/261] feat: add RsCompressedImage msg --- src/msg/ros_msg/RsCompressedImage.msg | 3 + src/msg/ros_msg/rs_compressed_image.hpp | 237 ++++++++++++++++++++++++ 2 files changed, 240 insertions(+) create mode 100644 src/msg/ros_msg/RsCompressedImage.msg create mode 100644 src/msg/ros_msg/rs_compressed_image.hpp diff --git a/src/msg/ros_msg/RsCompressedImage.msg b/src/msg/ros_msg/RsCompressedImage.msg new file mode 100644 index 00000000..a912af68 --- /dev/null +++ b/src/msg/ros_msg/RsCompressedImage.msg @@ -0,0 +1,3 @@ +std_msgs/Header header +uint8 type +uint8[] data diff --git a/src/msg/ros_msg/rs_compressed_image.hpp b/src/msg/ros_msg/rs_compressed_image.hpp new file mode 100644 index 00000000..f0a391d3 --- /dev/null +++ b/src/msg/ros_msg/rs_compressed_image.hpp @@ -0,0 +1,237 @@ +// Generated by gencpp from file rscamera_msg/RsCompressedImage.msg +// DO NOT EDIT! + + +#ifndef RSCAMERA_MESSAGE_RSCOMPRESSEDIMAGE_H +#define RSCAMERA_MESSAGE_RSCOMPRESSEDIMAGE_H + + +#include +#include +#include + +#include +#include +#include +#include + +#include + +namespace rscamera_msg +{ +template +struct RsCompressedImage_ +{ + typedef RsCompressedImage_ Type; + + RsCompressedImage_() + : header() + , type(0) + , data() { + } + RsCompressedImage_(const ContainerAllocator& _alloc) + : header(_alloc) + , type(0) + , data(_alloc) { + (void)_alloc; + } + + + + typedef ::std_msgs::Header_ _header_type; + _header_type header; + + typedef uint8_t _type_type; + _type_type type; + + typedef std::vector::template rebind_alloc> _data_type; + _data_type data; + + + + + + typedef boost::shared_ptr< ::rscamera_msg::RsCompressedImage_ > Ptr; + typedef boost::shared_ptr< ::rscamera_msg::RsCompressedImage_ const> ConstPtr; + +}; // struct RsCompressedImage_ + +typedef ::rscamera_msg::RsCompressedImage_ > RsCompressedImage; + +typedef boost::shared_ptr< ::rscamera_msg::RsCompressedImage > RsCompressedImagePtr; +typedef boost::shared_ptr< ::rscamera_msg::RsCompressedImage const> RsCompressedImageConstPtr; + +// constants requiring out of line definition + + + +template +std::ostream& operator<<(std::ostream& s, const ::rscamera_msg::RsCompressedImage_ & v) +{ +ros::message_operations::Printer< ::rscamera_msg::RsCompressedImage_ >::stream(s, "", v); +return s; +} + + +template +bool operator==(const ::rscamera_msg::RsCompressedImage_ & lhs, const ::rscamera_msg::RsCompressedImage_ & rhs) +{ + return lhs.header == rhs.header && + lhs.type == rhs.type && + lhs.data == rhs.data; +} + +template +bool operator!=(const ::rscamera_msg::RsCompressedImage_ & lhs, const ::rscamera_msg::RsCompressedImage_ & rhs) +{ + return !(lhs == rhs); +} + + +} // namespace rscamera_msg + +namespace ros +{ +namespace message_traits +{ + + + + + +template +struct IsMessage< ::rscamera_msg::RsCompressedImage_ > + : TrueType + { }; + +template +struct IsMessage< ::rscamera_msg::RsCompressedImage_ const> + : TrueType + { }; + +template +struct IsFixedSize< ::rscamera_msg::RsCompressedImage_ > + : FalseType + { }; + +template +struct IsFixedSize< ::rscamera_msg::RsCompressedImage_ const> + : FalseType + { }; + +template +struct HasHeader< ::rscamera_msg::RsCompressedImage_ > + : TrueType + { }; + +template +struct HasHeader< ::rscamera_msg::RsCompressedImage_ const> + : TrueType + { }; + + +template +struct MD5Sum< ::rscamera_msg::RsCompressedImage_ > +{ + static const char* value() + { + return "4044c7c7aa754eb9dc4031aaf0ca91a7"; + } + + static const char* value(const ::rscamera_msg::RsCompressedImage_&) { return value(); } + static const uint64_t static_value1 = 0x4044c7c7aa754eb9ULL; + static const uint64_t static_value2 = 0xdc4031aaf0ca91a7ULL; +}; + +template +struct DataType< ::rscamera_msg::RsCompressedImage_ > +{ + static const char* value() + { + return "rscamera_msg/RsCompressedImage"; + } + + static const char* value(const ::rscamera_msg::RsCompressedImage_&) { return value(); } +}; + +template +struct Definition< ::rscamera_msg::RsCompressedImage_ > +{ + static const char* value() + { + return "std_msgs/Header header\n" +"uint8 type\n" +"uint8[] data\n" +"\n" +"================================================================================\n" +"MSG: std_msgs/Header\n" +"# Standard metadata for higher-level stamped data types.\n" +"# This is generally used to communicate timestamped data \n" +"# in a particular coordinate frame.\n" +"# \n" +"# sequence ID: consecutively increasing ID \n" +"uint32 seq\n" +"#Two-integer timestamp that is expressed as:\n" +"# * stamp.sec: seconds (stamp_secs) since epoch (in Python the variable is called 'secs')\n" +"# * stamp.nsec: nanoseconds since stamp_secs (in Python the variable is called 'nsecs')\n" +"# time-handling sugar is provided by the client library\n" +"time stamp\n" +"#Frame this data is associated with\n" +"string frame_id\n" +; + } + + static const char* value(const ::rscamera_msg::RsCompressedImage_&) { return value(); } +}; + +} // namespace message_traits +} // namespace ros + +namespace ros +{ +namespace serialization +{ + + template struct Serializer< ::rscamera_msg::RsCompressedImage_ > + { + template inline static void allInOne(Stream& stream, T m) + { + stream.next(m.header); + stream.next(m.type); + stream.next(m.data); + } + + ROS_DECLARE_ALLINONE_SERIALIZER + }; // struct RsCompressedImage_ + +} // namespace serialization +} // namespace ros + +namespace ros +{ +namespace message_operations +{ + +template +struct Printer< ::rscamera_msg::RsCompressedImage_ > +{ + template static void stream(Stream& s, const std::string& indent, const ::rscamera_msg::RsCompressedImage_& v) + { + s << indent << "header: "; + s << std::endl; + Printer< ::std_msgs::Header_ >::stream(s, indent + " ", v.header); + s << indent << "type: "; + Printer::stream(s, indent + " ", v.type); + s << indent << "data[]" << std::endl; + for (size_t i = 0; i < v.data.size(); ++i) + { + s << indent << " data[" << i << "]: "; + Printer::stream(s, indent + " ", v.data[i]); + } + } +}; + +} // namespace message_operations +} // namespace ros + +#endif // RSCAMERA_MESSAGE_RSCOMPRESSEDIMAGE_H From f0a7f3e79af1c053642b80220d3aca0ebe068ecb Mon Sep 17 00:00:00 2001 From: luhuadong Date: Thu, 2 Mar 2023 16:47:27 +0800 Subject: [PATCH 238/261] docs: remove duplicate text --- doc/src_intro/rslidar_sdk_intro_CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src_intro/rslidar_sdk_intro_CN.md b/doc/src_intro/rslidar_sdk_intro_CN.md index 99815030..e56337c7 100644 --- a/doc/src_intro/rslidar_sdk_intro_CN.md +++ b/doc/src_intro/rslidar_sdk_intro_CN.md @@ -16,7 +16,7 @@ rslidar_sdk的基本功能如下: ## 2 Source 与 Destination -如前面所说,rslidar_sdk从在线雷达、PCAP文件、ROS主题这三种源得到MSOP/DIFOP Packet,将Packet发布到ROS主题/rslidar_packets`/rslidar_packets`,将点云发布到目标 - ROS主题`/rslidar_points`。 +如前面所说,rslidar_sdk从在线雷达、PCAP文件、ROS主题这三种源得到MSOP/DIFOP Packet,将Packet发布到ROS主题`/rslidar_packets`,将点云发布到目标 - ROS主题`/rslidar_points`。 + Source定义源接口 + DestinationPointCloud定义发送点云的目标接口。 + DestinationPacket定义发送MSOP/DIFOP Packet的目标接口。 From d9dc998a92991a99c5609778691cf3cd47226113 Mon Sep 17 00:00:00 2001 From: ronzheng Date: Tue, 11 Apr 2023 14:48:06 +0800 Subject: [PATCH 239/261] feat: sync to rs_driver --- CHANGELOG.md | 6 ++++++ config/config.yaml | 2 +- src/rs_driver | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfee00ff..0a53e707 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # CHANGELOG ## Unreleased +## v1.5.10 - 2023-02-17 + +### Changed +- Merge RSBPV4 into RSBP + + ## v1.5.9 - 2023-02-17 ### Changed diff --git a/config/config.yaml b/config/config.yaml index a325868f..77b90ed7 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -7,7 +7,7 @@ common: send_point_cloud_ros: true #true: Send point cloud through ROS or ROS2 lidar: - driver: - lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RSBPV4, RSHELIOS, RSHELIOS_16P, RS128, RS80, RS48, RSP128, RSP80, RSP48, + lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RSHELIOS_16P, RS128, RS80, RS48, RSP128, RSP80, RSP48, # RSM1, RSM1_JUMBO, RSM2, RSE1 msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar diff --git a/src/rs_driver b/src/rs_driver index 3c36c089..ef1bdd45 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 3c36c089277cb366603f1bc4b5d406ee911dfb80 +Subproject commit ef1bdd45ee4df51e5acb57b64e49d8fed233039c From c43170d2c66e33a908eab2fd21088b068c964730 Mon Sep 17 00:00:00 2001 From: "felix.huang" Date: Fri, 26 Apr 2024 15:48:09 +0800 Subject: [PATCH 240/261] feat:Enable modify socket buffer size --- CHANGELOG.md | 5 +++++ src/rs_driver | 2 +- src/source/source_driver.hpp | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a53e707..58ea3d5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # CHANGELOG ## Unreleased +## v1.5.11 2023-12-18 + +### Changed +- Enable modify socket buffer size. + ## v1.5.10 - 2023-02-17 ### Changed diff --git a/src/rs_driver b/src/rs_driver index ef1bdd45..27827f84 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit ef1bdd45ee4df51e5acb57b64e49d8fed233039c +Subproject commit 27827f84c78fb47acdb1d4d0bfe5f9ea1e745b2d diff --git a/src/source/source_driver.hpp b/src/source/source_driver.hpp index 178cd0c7..148fefdc 100644 --- a/src/source/source_driver.hpp +++ b/src/source/source_driver.hpp @@ -90,7 +90,7 @@ inline void SourceDriver::init(const YAML::Node& config) yamlRead(driver_config, "pcap_repeat", driver_param.input_param.pcap_repeat, true); yamlRead(driver_config, "user_layer_bytes", driver_param.input_param.user_layer_bytes, 0); yamlRead(driver_config, "tail_layer_bytes", driver_param.input_param.tail_layer_bytes, 0); - + yamlRead(driver_config, "socket_recv_buf", driver_param.input_param.socket_recv_buf, 106496); // decoder related std::string lidar_type; yamlReadAbort(driver_config, "lidar_type", lidar_type); From eca1572a8d31045c63ea2be1b16ed5e8b32ffce2 Mon Sep 17 00:00:00 2001 From: "felix.huang" Date: Mon, 6 May 2024 11:33:42 +0800 Subject: [PATCH 241/261] feat:update CMakeLists --- CMakeLists.txt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 79c879e7..93238026 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,16 +25,21 @@ if(${ENABLE_EPOLL_RECEIVE}) add_definitions("-DENABLE_EPOLL_RECEIVE") endif(${ENABLE_EPOLL_RECEIVE}) -option(ENABLE_DOUBLE_RCVBUF "Enable double size of RCVBUF" OFF) -if(${ENABLE_DOUBLE_RCVBUF}) - add_definitions("-DENABLE_DOUBLE_RCVBUF") -endif(${ENABLE_DOUBLE_RCVBUF}) +option(ENABLE_MODIFY_RECVBUF "Enable modify size of RECVBUF" ON) +if(${ENABLE_MODIFY_RECVBUF}) + add_definitions("-DENABLE_MODIFY_RECVBUF") +endif(${ENABLE_MODIFY_RECVBUF}) option(ENABLE_WAIT_IF_QUEUE_EMPTY "Enable waiting for a while in handle thread if the queue is empty" OFF) if(${ENABLE_WAIT_IF_QUEUE_EMPTY}) add_definitions("-DENABLE_WAIT_IF_QUEUE_EMPTY") endif(${ENABLE_WAIT_IF_QUEUE_EMPTY}) +option(ENABLE_DIFOP_PARSE "Enable parsing DIFOP Packet" ON) +if(${ENABLE_DIFOP_PARSE}) + add_definitions("-DENABLE_DIFOP_PARSE") +endif(${ENABLE_DIFOP_PARSE}) + option(ENABLE_STAMP_WITH_LOCAL "Enable stamp point cloud with local time" OFF) if(${ENABLE_STAMP_WITH_LOCAL}) add_definitions("-DENABLE_STAMP_WITH_LOCAL") From 21a74bfd25987906af54b9285ae5a54785611380 Mon Sep 17 00:00:00 2001 From: "felix.huang" Date: Mon, 6 May 2024 11:50:33 +0800 Subject: [PATCH 242/261] feat:sync to rs_driver --- CHANGELOG.md | 6 ++++++ CMakeLists.txt | 1 + src/rs_driver | 2 +- src/source/source_driver.hpp | 1 - 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58ea3d5b..969734b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # CHANGELOG ## Unreleased +## Unreleased +## v1.5.12 2023-12-28 +### Fixed +- Fix bug in getting device info and status. +- Fix bug in getting device temperature. + ## v1.5.11 2023-12-18 ### Changed diff --git a/CMakeLists.txt b/CMakeLists.txt index 93238026..1d28e77b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,7 @@ if(${ENABLE_STAMP_WITH_LOCAL}) add_definitions("-DENABLE_STAMP_WITH_LOCAL") endif(${ENABLE_STAMP_WITH_LOCAL}) + option(ENABLE_SOURCE_PACKET_LEGACY "Enable ROS Source of MSOP/DIFOP Packet v1.3.x" OFF) if(${ENABLE_SOURCE_PACKET_LEGACY}) add_definitions("-DENABLE_SOURCE_PACKET_LEGACY") diff --git a/src/rs_driver b/src/rs_driver index 27827f84..e3428806 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 27827f84c78fb47acdb1d4d0bfe5f9ea1e745b2d +Subproject commit e34288068ab07a671a4a65083a78b189dc706f38 diff --git a/src/source/source_driver.hpp b/src/source/source_driver.hpp index 148fefdc..f41c09aa 100644 --- a/src/source/source_driver.hpp +++ b/src/source/source_driver.hpp @@ -213,7 +213,6 @@ void SourceDriver::processPointCloud() { continue; } - sendPointCloud(msg); free_point_cloud_queue_.push(msg); From c8b64a07446e0effd3a50fb529596b65b30e3a0e Mon Sep 17 00:00:00 2001 From: "felix.huang" Date: Fri, 10 May 2024 17:04:17 +0800 Subject: [PATCH 243/261] feat:sync to rs_driver --- CHANGELOG.md | 9 ++++++++- config/config.yaml | 5 ++--- doc/src_intro/rslidar_sdk_intro_CN.md | 2 +- src/rs_driver | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 969734b4..f6365484 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # CHANGELOG ## Unreleased - +## v1.5.13 2024-05-10 +### Added +- Support RSMX. +### Fixed +- Update timestamp parsing unit and the number of packets per frame in decoder_RSE1. +- Update firing_tss of Helios/Helios16P/RubyPlus. +- Fix compilation bug of unit test. +- Remove duplicate text "/rslidar_packets" by @luhuadong. ## Unreleased ## v1.5.12 2023-12-28 ### Fixed diff --git a/config/config.yaml b/config/config.yaml index 77b90ed7..4e0ab7c7 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -8,7 +8,7 @@ common: lidar: - driver: lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RSHELIOS_16P, RS128, RS80, RS48, RSP128, RSP80, RSP48, - # RSM1, RSM1_JUMBO, RSM2, RSE1 + # RSM1, RSM1_JUMBO, RSM2, RSE1, RSMX. msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar start_angle: 0 #Start angle of point cloud @@ -17,11 +17,10 @@ lidar: min_distance: 0.2 #Minimum distance of point cloud max_distance: 200 #Maximum distance of point cloud use_lidar_clock: false #True--Use the lidar clock as the message timestamp - #False-- Use the system clock as the timestamp + #False-- Use the system clock as the timestamp pcap_path: /home/robosense/lidar.pcap #The path of pcap file ros: ros_frame_id: rslidar #Frame id of packet message and point cloud message ros_recv_packet_topic: /rslidar_packets #Topic used to receive lidar packets from ROS ros_send_packet_topic: /rslidar_packets #Topic used to send lidar packets through ROS ros_send_point_cloud_topic: /rslidar_points #Topic used to send point cloud through ROS - diff --git a/doc/src_intro/rslidar_sdk_intro_CN.md b/doc/src_intro/rslidar_sdk_intro_CN.md index 99815030..e56337c7 100644 --- a/doc/src_intro/rslidar_sdk_intro_CN.md +++ b/doc/src_intro/rslidar_sdk_intro_CN.md @@ -16,7 +16,7 @@ rslidar_sdk的基本功能如下: ## 2 Source 与 Destination -如前面所说,rslidar_sdk从在线雷达、PCAP文件、ROS主题这三种源得到MSOP/DIFOP Packet,将Packet发布到ROS主题/rslidar_packets`/rslidar_packets`,将点云发布到目标 - ROS主题`/rslidar_points`。 +如前面所说,rslidar_sdk从在线雷达、PCAP文件、ROS主题这三种源得到MSOP/DIFOP Packet,将Packet发布到ROS主题`/rslidar_packets`,将点云发布到目标 - ROS主题`/rslidar_points`。 + Source定义源接口 + DestinationPointCloud定义发送点云的目标接口。 + DestinationPacket定义发送MSOP/DIFOP Packet的目标接口。 diff --git a/src/rs_driver b/src/rs_driver index e3428806..68859d49 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit e34288068ab07a671a4a65083a78b189dc706f38 +Subproject commit 68859d49373adcdb6ef2ea328d075164ee89d9e9 From b74b36bc71000ce27dc1cdc37f9fbf320e16a8e0 Mon Sep 17 00:00:00 2001 From: "felix.huang" Date: Fri, 10 May 2024 18:13:26 +0800 Subject: [PATCH 244/261] feat:update CHANGELOG --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6365484..4af4876d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ # CHANGELOG -## Unreleased + ## v1.5.13 2024-05-10 ### Added - Support RSMX. @@ -8,7 +8,7 @@ - Update firing_tss of Helios/Helios16P/RubyPlus. - Fix compilation bug of unit test. - Remove duplicate text "/rslidar_packets" by @luhuadong. -## Unreleased + ## v1.5.12 2023-12-28 ### Fixed - Fix bug in getting device info and status. From cbcf21d3d707d93bbd94bcb3926bb6ed8fa10525 Mon Sep 17 00:00:00 2001 From: "felix.huang" Date: Tue, 16 Jul 2024 14:25:52 +0800 Subject: [PATCH 245/261] feat:sync to rs_driver --- CHANGELOG.md | 6 ++++++ src/rs_driver | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4af4876d..6a9e05ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## v1.5.14 2024-07-15 +### Added +- Support multiple lidars with different multicast addresses and the same port. +### Fixed +- Fixed the bug that only one lidar was parsed correctly when multiple bp4.0 were used. + ## v1.5.13 2024-05-10 ### Added - Support RSMX. diff --git a/src/rs_driver b/src/rs_driver index 68859d49..46e9463b 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 68859d49373adcdb6ef2ea328d075164ee89d9e9 +Subproject commit 46e9463bf1af7e0592597ad022e0c7e79f850f1f From e058d257e34a7a7a972eb737488ab86fc7c45cc2 Mon Sep 17 00:00:00 2001 From: Tim Clephas Date: Thu, 25 Jul 2024 15:03:35 +0200 Subject: [PATCH 246/261] roslib only for ROS1 --- package.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.xml b/package.xml index d951aefe..e6726d11 100644 --- a/package.xml +++ b/package.xml @@ -15,7 +15,7 @@ pcl_ros rclcpp roscpp - roslib + roslib rslidar_msg sensor_msgs std_msgs From f22e46720464c435fb499be9bf8bfec35a085e37 Mon Sep 17 00:00:00 2001 From: Tim Clephas Date: Fri, 26 Jul 2024 09:53:21 +0200 Subject: [PATCH 247/261] Restore libpcap as it's header is included --- package.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/package.xml b/package.xml index 415f1f74..e9a97908 100644 --- a/package.xml +++ b/package.xml @@ -9,6 +9,7 @@ catkin ament_cmake + libpcap pcl_ros rclcpp roscpp From cc6a0d64ccb890e3120a1395d6be2c9799da1633 Mon Sep 17 00:00:00 2001 From: Tim Clephas Date: Fri, 2 Aug 2024 10:30:52 +0200 Subject: [PATCH 248/261] Fix version number with tag --- package.xml | 2 +- package_ros1.xml | 2 +- package_ros2.xml | 5 +---- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/package.xml b/package.xml index 83f31d47..69078d67 100644 --- a/package.xml +++ b/package.xml @@ -1,7 +1,7 @@ rslidar_sdk - 1.5.0 + 1.5.14 The rslidar_sdk package robosense BSD diff --git a/package_ros1.xml b/package_ros1.xml index 83f31d47..69078d67 100644 --- a/package_ros1.xml +++ b/package_ros1.xml @@ -1,7 +1,7 @@ rslidar_sdk - 1.5.0 + 1.5.14 The rslidar_sdk package robosense BSD diff --git a/package_ros2.xml b/package_ros2.xml index c342eec4..51437fee 100644 --- a/package_ros2.xml +++ b/package_ros2.xml @@ -1,7 +1,7 @@ rslidar_sdk - 1.5.0 + 1.5.14 The rslidar_sdk package robosense BSD @@ -19,6 +19,3 @@ - - - From d3f8cad4c81ccc37b2e103adcd6e488f1deefee1 Mon Sep 17 00:00:00 2001 From: Tim Clephas Date: Fri, 2 Aug 2024 22:48:46 +0200 Subject: [PATCH 249/261] Allow --config-path as argument for now as ROS2 nodes are inconsistent --- node/rslidar_sdk_node.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/node/rslidar_sdk_node.cpp b/node/rslidar_sdk_node.cpp index 546917e5..b2ba14e3 100644 --- a/node/rslidar_sdk_node.cpp +++ b/node/rslidar_sdk_node.cpp @@ -88,6 +88,15 @@ int main(int argc, char** argv) config_path += "/config/config.yaml"; +// Pick up --config-path argument from command line +for (int i = 1; i < argc; i++) { + std::string arg = argv[i]; + if (arg == "--config-path" && i + 1 < argc) { + config_path = argv[i + 1]; + break; + } +} + #ifdef ROS_FOUND ros::NodeHandle priv_hh("~"); std::string path; From 7b0166f5174a29fa3f07340c6fe7215c93acb395 Mon Sep 17 00:00:00 2001 From: "felix.huang" Date: Mon, 5 Aug 2024 11:58:31 +0800 Subject: [PATCH 250/261] [submodule]:[feat]:sync to rsdriver --- src/rs_driver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rs_driver b/src/rs_driver index 46e9463b..80c93b94 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 46e9463bf1af7e0592597ad022e0c7e79f850f1f +Subproject commit 80c93b94c1c69fff88f821a33db86901985e1c71 From dd4afc493a56b28c3c21752f11c7e5abd74a0ca2 Mon Sep 17 00:00:00 2001 From: "felix.huang" Date: Mon, 5 Aug 2024 12:09:30 +0800 Subject: [PATCH 251/261] [Doc]:[feat]:update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a9e05ca..50c1e6be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Support multiple lidars with different multicast addresses and the same port. ### Fixed - Fixed the bug that only one lidar was parsed correctly when multiple bp4.0 were used. +- Fix version number in the package.xml. ## v1.5.13 2024-05-10 ### Added From 5b9d2eace6be2ef7e7a5044a621aadd8310c8180 Mon Sep 17 00:00:00 2001 From: "felix.huang" Date: Mon, 5 Aug 2024 12:13:48 +0800 Subject: [PATCH 252/261] [Doc]:[feat]:update CHANGELOG, add support --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50c1e6be..8a0e0f61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ - Support multiple lidars with different multicast addresses and the same port. ### Fixed - Fixed the bug that only one lidar was parsed correctly when multiple bp4.0 were used. -- Fix version number in the package.xml. +- Fix version number in the package.xml by @Timple. ## v1.5.13 2024-05-10 ### Added From aa3381d610b0dc2f15a0ea5cbae5167b42c4201f Mon Sep 17 00:00:00 2001 From: "felix.huang" Date: Thu, 8 Aug 2024 14:41:59 +0800 Subject: [PATCH 253/261] [submodule]:[feat]:sync to rs-driver --- CHANGELOG.md | 4 ++++ config/config.yaml | 2 +- node/rslidar_sdk_node.cpp | 11 ++++++----- package.xml | 2 +- package_ros1.xml | 2 +- package_ros2.xml | 2 +- src/rs_driver | 2 +- 7 files changed, 15 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a0e0f61..334fd8aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +## v1.5.15 2024-08-07 +### Added +- Support RSM3. + ## v1.5.14 2024-07-15 ### Added - Support multiple lidars with different multicast addresses and the same port. diff --git a/config/config.yaml b/config/config.yaml index 4e0ab7c7..6d0564d4 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -8,7 +8,7 @@ common: lidar: - driver: lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RSHELIOS_16P, RS128, RS80, RS48, RSP128, RSP80, RSP48, - # RSM1, RSM1_JUMBO, RSM2, RSE1, RSMX. + # RSM1, RSM1_JUMBO, RSM2, RSM3, RSE1, RSMX. msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar start_angle: 0 #Start angle of point cloud diff --git a/node/rslidar_sdk_node.cpp b/node/rslidar_sdk_node.cpp index 55813af4..49d543bb 100644 --- a/node/rslidar_sdk_node.cpp +++ b/node/rslidar_sdk_node.cpp @@ -66,8 +66,9 @@ int main(int argc, char** argv) RS_TITLE << "********************************************************" << RS_REND; RS_TITLE << "********** **********" << RS_REND; - RS_TITLE << "********** RSLidar_SDK Version: v" << RSLIDAR_VERSION_MAJOR << "." << RSLIDAR_VERSION_MINOR << "." - << RSLIDAR_VERSION_PATCH << " **********" << RS_REND; + RS_TITLE << "********** RSLidar_SDK Version: v" << RSLIDAR_VERSION_MAJOR + << "." << RSLIDAR_VERSION_MINOR + << "." << RSLIDAR_VERSION_PATCH << " **********" << RS_REND; RS_TITLE << "********** **********" << RS_REND; RS_TITLE << "********************************************************" << RS_REND; @@ -80,12 +81,12 @@ int main(int argc, char** argv) std::string config_path; #ifdef RUN_IN_ROS_WORKSPACE - config_path = ros::package::getPath("rslidar_sdk"); + config_path = ros::package::getPath("rslidar_sdk"); #else - config_path = (std::string)PROJECT_PATH; + config_path = (std::string)PROJECT_PATH; #endif - config_path += "/config/config.yaml"; + config_path += "/config/config.yaml"; #ifdef ROS_FOUND ros::NodeHandle priv_hh("~"); diff --git a/package.xml b/package.xml index 69078d67..e6395039 100644 --- a/package.xml +++ b/package.xml @@ -1,7 +1,7 @@ rslidar_sdk - 1.5.14 + 1.5.15 The rslidar_sdk package robosense BSD diff --git a/package_ros1.xml b/package_ros1.xml index 69078d67..e6395039 100644 --- a/package_ros1.xml +++ b/package_ros1.xml @@ -1,7 +1,7 @@ rslidar_sdk - 1.5.14 + 1.5.15 The rslidar_sdk package robosense BSD diff --git a/package_ros2.xml b/package_ros2.xml index 51437fee..afdb56d9 100644 --- a/package_ros2.xml +++ b/package_ros2.xml @@ -1,7 +1,7 @@ rslidar_sdk - 1.5.14 + 1.5.15 The rslidar_sdk package robosense BSD diff --git a/src/rs_driver b/src/rs_driver index 80c93b94..20219617 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 80c93b94c1c69fff88f821a33db86901985e1c71 +Subproject commit 20219617218ce26d78b8fa3321765aee91d44a34 From 1357d6670ed0d3dbcf4a21f8b2179f34a498ce66 Mon Sep 17 00:00:00 2001 From: "felix.huang" Date: Thu, 8 Aug 2024 15:51:06 +0800 Subject: [PATCH 254/261] [Doc]:[feat]:update README --- README.md | 2 ++ README_CN.md | 2 ++ src/rs_driver | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fc8506cb..1afbb088 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,9 @@ To integrate the Lidar driver into your own projects, please use the rs_driver. - RS-Ruby-Plus-48 - RS-LiDAR-M1 - RS-LiDAR-M2 +- RS-LiDAR-M3 - RS-LiDAR-E1 +- RS-LiDAR-MX ### 1.2 Point Type Supported diff --git a/README_CN.md b/README_CN.md index 484a9d15..3c1146d0 100644 --- a/README_CN.md +++ b/README_CN.md @@ -30,7 +30,9 @@ - RS-Ruby-Plus-48 - RS-LiDAR-M1 - RS-LiDAR-M2 +- RS-LiDAR-M3 - RS-LiDAR-E1 +- RS-LiDAR-MX ### 1.1.2 支持的点类型 diff --git a/src/rs_driver b/src/rs_driver index 20219617..ada83297 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit 20219617218ce26d78b8fa3321765aee91d44a34 +Subproject commit ada8329742228c1277f419f0f1667d208ac502ba From 7198d6a4372c9bb96b0fea16694118947c0dc353 Mon Sep 17 00:00:00 2001 From: Tim Clephas Date: Mon, 26 Aug 2024 15:49:26 +0200 Subject: [PATCH 255/261] Drop manual argument parsing --- node/rslidar_sdk_node.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/node/rslidar_sdk_node.cpp b/node/rslidar_sdk_node.cpp index 90218275..49d543bb 100644 --- a/node/rslidar_sdk_node.cpp +++ b/node/rslidar_sdk_node.cpp @@ -88,15 +88,6 @@ int main(int argc, char** argv) config_path += "/config/config.yaml"; -// Pick up --config-path argument from command line -for (int i = 1; i < argc; i++) { - std::string arg = argv[i]; - if (arg == "--config-path" && i + 1 < argc) { - config_path = argv[i + 1]; - break; - } -} - #ifdef ROS_FOUND ros::NodeHandle priv_hh("~"); std::string path; From a5159cb4ad0469741a212f277892cad128927c62 Mon Sep 17 00:00:00 2001 From: "felix.huang" Date: Tue, 27 Aug 2024 21:02:46 +0800 Subject: [PATCH 256/261] [launch]:[feat]:load config path frome ros2 param --- CHANGELOG.md | 7 +++++++ README.md | 27 ++------------------------- README_CN.md | 28 ++-------------------------- launch/start.py | 4 +++- package.xml | 2 +- src/rs_driver | 2 +- 6 files changed, 16 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 334fd8aa..9bf62aed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # CHANGELOG +## v1.5.16 2024-08-27 +### Added +- Load config path frome ros2 param. +### Fixed +- Use single package.xml file for both ROS1 and ROS2 @Timple. +- Update msop protocol of RSMX. + ## v1.5.15 2024-08-07 ### Added - Support RSM3. diff --git a/README.md b/README.md index 1414cc1c..b382855e 100644 --- a/README.md +++ b/README.md @@ -119,31 +119,8 @@ sudo apt-get install -y libpcap-dev ## 4 Compile & Run -Please compile and run the driver in three ways. -### 4.1 Compile directly - -(1) On top of the file *CMakeLists.txt*,set the variable **COMPILE_METHOD** to **ORIGINAL**. - -```cmake -#======================================= -# Compile setup (ORIGINAL,CATKIN,COLCON) -#======================================= -set(COMPILE_METHOD ORIGINAL) -``` - -(2) In ROS (unfortunately not ROS2), user can compile it directly. - -Please laucn ROS master node ```roscore``` in advance, and use ```rviz``` to visualize point cloud. - -```sh -cd rslidar_sdk -mkdir build && cd build -cmake .. && make -j4 -./rslidar_sdk_node -``` - -### 4.2 Compile with ROS catkin tools +### 4.1 Compile with ROS catkin tools (1) Run the following commands to compile and run. (if using zsh, replace the 2nd command with *source devel/setup.zsh*). @@ -153,7 +130,7 @@ source devel/setup.bash roslaunch rslidar_sdk start.launch ``` -### 4.3 Compile with ROS2 colcon +### 4.2 Compile with ROS2 colcon (1) Run the following commands to compile and run. (if using zsh, replace the 2nd command with *source install/setup.zsh*). diff --git a/README_CN.md b/README_CN.md index f5912af4..14eb493a 100644 --- a/README_CN.md +++ b/README_CN.md @@ -115,31 +115,7 @@ sudo apt-get install -y libpcap-dev ## 1.4 编译、运行 -可以使用三种方式编译、运行rslidar_sdk。 - -### 1.4.1 直接编译 - -(1) 打开工程内的*CMakeLists.txt*文件,将文件顶部的变量**COMPILE_METHOD**改为**ORIGINAL**. - -```cmake -#======================================= -# Compile setup (ORIGINAL,CATKIN,COLCON) -#======================================= -set(COMPILE_METHOD ORIGINAL) -``` - -(2) 在ROS1(不适用于ROS2)中,直接编译、运行程序。 - -请先启动**roscore**,再运行**rslidar_sdk_node**,最后运行**rviz**查看点云。 - -```sh -cd rslidar_sdk -mkdir build && cd build -cmake .. && make -j4 -./rslidar_sdk_node -``` - -### 1.4.2 依赖于ROS-catkin编译 +### 1.4.1 依赖于ROS-catkin编译 (1) 返回工作空间目录,执行以下命令即可编译&运行(若使用.zsh,将第二句指令替换为 *source devel/setup.zsh*)。 @@ -149,7 +125,7 @@ source devel/setup.bash roslaunch rslidar_sdk start.launch ``` -### 1.4.3 依赖于ROS2-colcon编译 +### 1.4.2 依赖于ROS2-colcon编译 (1) 返回工作空间目录,执行以下命令即可编译&运行(若使用.zsh,将第二句指令替换为 *source install/setup.zsh*)。 diff --git a/launch/start.py b/launch/start.py index a9031240..ecc86a79 100755 --- a/launch/start.py +++ b/launch/start.py @@ -6,7 +6,9 @@ def generate_launch_description(): rviz_config=get_package_share_directory('rslidar_sdk')+'/rviz/rviz2.rviz' + config_file = '' # your config file path + return LaunchDescription([ - Node(namespace='rslidar_sdk', package='rslidar_sdk', executable='rslidar_sdk_node', output='screen'), + Node(namespace='rslidar_sdk', package='rslidar_sdk', executable='rslidar_sdk_node', output='screen', parameters=[{'config_path': config_file}]), Node(namespace='rviz2', package='rviz2', executable='rviz2', arguments=['-d',rviz_config]) ]) diff --git a/package.xml b/package.xml index 121fa1ac..39d9158a 100644 --- a/package.xml +++ b/package.xml @@ -1,7 +1,7 @@ rslidar_sdk - 1.5.15 + 1.5.16 The rslidar_sdk package robosense BSD diff --git a/src/rs_driver b/src/rs_driver index ada83297..ba07ba49 160000 --- a/src/rs_driver +++ b/src/rs_driver @@ -1 +1 @@ -Subproject commit ada8329742228c1277f419f0f1667d208ac502ba +Subproject commit ba07ba49565c8f1df745c8effaf64f39ac83a0ef From 178b7a59912fabfb7a0c0e09a690fd1686a74dbe Mon Sep 17 00:00:00 2001 From: "felix.huang" Date: Wed, 28 Aug 2024 10:28:22 +0800 Subject: [PATCH 257/261] [Doc]:[feat]:update CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bf62aed..505bb240 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ## v1.5.16 2024-08-27 ### Added - Load config path frome ros2 param. +### Changed +- Remove the original compilation method. ### Fixed - Use single package.xml file for both ROS1 and ROS2 @Timple. - Update msop protocol of RSMX. From a4c8ffc4ac2ee110bb6fda3450fb83438fdc13df Mon Sep 17 00:00:00 2001 From: "felix.huang" Date: Wed, 28 Aug 2024 11:15:29 +0800 Subject: [PATCH 258/261] [Doc]:[feat]:update ReadMe --- README.md | 9 +++++++-- README_CN.md | 10 ++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b382855e..98106616 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,9 @@ sudo apt-get install -y libpcap-dev ### 4.1 Compile with ROS catkin tools -(1) Run the following commands to compile and run. (if using zsh, replace the 2nd command with *source devel/setup.zsh*). +(1) Create a new workspace folder, and create a *src* folder in it. Then put the rslidar_sdk project into the *src* folder. + +(2) Go back to the root of workspace, run the following commands to compile and run. (if using zsh, replace the 2nd command with *source devel/setup.zsh*). ```sh catkin_make @@ -132,8 +134,11 @@ roslaunch rslidar_sdk start.launch ### 4.2 Compile with ROS2 colcon -(1) Run the following commands to compile and run. (if using zsh, replace the 2nd command with *source install/setup.zsh*). +(1) Create a new workspace folder, and create a *src* folder in it. Then put the rslidar_sdk project in the *src* folder. + +(2) Download the packet definition project in ROS2 through [link](https://github.com/RoboSense-LiDAR/rslidar_msg), then put the project rslidar_msg in the *src* folder you just created. +(3) Go back to the root of workspace, run the following commands to compile and run. (if using zsh, replace the 2nd command with *source install/setup.zsh*). ```sh colcon build source install/setup.bash diff --git a/README_CN.md b/README_CN.md index 14eb493a..7ac9a82b 100644 --- a/README_CN.md +++ b/README_CN.md @@ -117,7 +117,9 @@ sudo apt-get install -y libpcap-dev ### 1.4.1 依赖于ROS-catkin编译 -(1) 返回工作空间目录,执行以下命令即可编译&运行(若使用.zsh,将第二句指令替换为 *source devel/setup.zsh*)。 +(1) 新建一个文件夹作为工作空间,然后再新建一个名为*src*的文件夹, 将rslidar_sdk工程放入*src*文件夹内。 + +(2) 返回工作空间目录,执行以下命令即可编译&运行(若使用.zsh,将第二句指令替换为 *source devel/setup.zsh*)。 ```sh catkin_make @@ -127,7 +129,11 @@ roslaunch rslidar_sdk start.launch ### 1.4.2 依赖于ROS2-colcon编译 -(1) 返回工作空间目录,执行以下命令即可编译&运行(若使用.zsh,将第二句指令替换为 *source install/setup.zsh*)。 +(1) 新建一个文件夹作为工作空间,然后再新建一个名为*src*的文件夹, 将rslidar_sdk工程放入*src*文件夹内。 + +(2) 通过[链接](https://github.com/RoboSense-LiDAR/rslidar_msg),下载ROS2环境下的雷达packet消息定义,将rslidar_msg工程也放在刚刚新建的*src*文件夹内,与rslidar_sdk并列。 + +(3) 返回工作空间目录,执行以下命令即可编译、运行。如果使用.zsh,将第二行替换为*source install/setup.zsh*。 ```sh colcon build From 5d8e1e4493702e4025f4e219388cdc4d96a9a07e Mon Sep 17 00:00:00 2001 From: "felix.huang" Date: Wed, 28 Aug 2024 11:30:56 +0800 Subject: [PATCH 259/261] [xml]:[feat]:update email --- package.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.xml b/package.xml index 39d9158a..02ad159d 100644 --- a/package.xml +++ b/package.xml @@ -3,7 +3,7 @@ rslidar_sdk 1.5.16 The rslidar_sdk package - robosense + robosense BSD catkin From 43b2c98dd08020817138d5770e311c44561116d0 Mon Sep 17 00:00:00 2001 From: Rafael Martin Date: Thu, 19 Sep 2024 13:30:16 +0200 Subject: [PATCH 260/261] cicd: added jenkinsfile --- .github/Jenkinsfile | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/Jenkinsfile diff --git a/.github/Jenkinsfile b/.github/Jenkinsfile new file mode 100644 index 00000000..4b59e7b0 --- /dev/null +++ b/.github/Jenkinsfile @@ -0,0 +1 @@ +buildPackage() From c6620e3da876575ceda3d7425d3f98f4549deae1 Mon Sep 17 00:00:00 2001 From: Roberto Carta Date: Wed, 20 Nov 2024 09:16:00 +0100 Subject: [PATCH 261/261] Adapted to new parameters --- CMakeLists.txt | 2 +- config/config.yaml | 2 +- launch/start.launch | 2 ++ node/rslidar_sdk_node.cpp | 24 ++++++++++++++++++++++-- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 70adc205..be0a1d47 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ project(rslidar_sdk) #======================================= # Custom Point Type (XYZI, XYZIRT) #======================================= -set(POINT_TYPE XYZI) +set(POINT_TYPE XYZIRT) option(ENABLE_TRANSFORM "Enable transform functions" OFF) if(${ENABLE_TRANSFORM}) diff --git a/config/config.yaml b/config/config.yaml index 6d0564d4..6757335d 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -7,7 +7,7 @@ common: send_point_cloud_ros: true #true: Send point cloud through ROS or ROS2 lidar: - driver: - lidar_type: RSM1 #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RSHELIOS_16P, RS128, RS80, RS48, RSP128, RSP80, RSP48, + lidar_type: RSHELIOS_16P #LiDAR type - RS16, RS32, RSBP, RSHELIOS, RSHELIOS_16P, RS128, RS80, RS48, RSP128, RSP80, RSP48, # RSM1, RSM1_JUMBO, RSM2, RSM3, RSE1, RSMX. msop_port: 6699 #Msop port of lidar difop_port: 7788 #Difop port of lidar diff --git a/launch/start.launch b/launch/start.launch index 849e3b25..25b89068 100755 --- a/launch/start.launch +++ b/launch/start.launch @@ -1,4 +1,6 @@ + + diff --git a/node/rslidar_sdk_node.cpp b/node/rslidar_sdk_node.cpp index 49d543bb..084b00d3 100644 --- a/node/rslidar_sdk_node.cpp +++ b/node/rslidar_sdk_node.cpp @@ -86,7 +86,9 @@ int main(int argc, char** argv) config_path = (std::string)PROJECT_PATH; #endif - config_path += "/config/config.yaml"; + //config_path += "/config/config.yaml"; + std::string rslidar_config_file = (std::string)PROJECT_PATH + "/config/config.yaml"; + ros::param::get("rslidar_config_file", rslidar_config_file); #ifdef ROS_FOUND ros::NodeHandle priv_hh("~"); @@ -107,7 +109,8 @@ int main(int argc, char** argv) YAML::Node config; try { - config = YAML::LoadFile(config_path); + //config = YAML::LoadFile(config_path); + config = YAML::LoadFile(rslidar_config_file); RS_INFO << "--------------------------------------------------------" << RS_REND; RS_INFO << "Config loaded from PATH:" << RS_REND; RS_INFO << config_path << RS_REND; @@ -118,6 +121,23 @@ int main(int argc, char** argv) RS_ERROR << "The format of config file " << config_path << " is wrong. Please check (e.g. indentation)." << RS_REND; return -1; } + + std::string lidar_type = ""; + priv_hh.param("lidar_type", lidar_type, lidar_type); + if (lidar_type != "") + config["lidar"][0]["driver"]["lidar_type"] = lidar_type; + int msop_port = -1; + priv_hh.param("msop_port", msop_port, msop_port); + if (msop_port != -1) + config["lidar"][0]["driver"]["msop_port"] = msop_port; + int difop_port = -1; + priv_hh.param("difop_port", difop_port, difop_port); + if (difop_port != -1) + config["lidar"][0]["driver"]["difop_port"] = difop_port; + std::string ros_frame_id = ""; + priv_hh.param("frame_id", ros_frame_id, ros_frame_id); + if (ros_frame_id != "") + config["lidar"][0]["ros"]["ros_frame_id"] = ros_frame_id; std::shared_ptr demo_ptr = std::make_shared(); demo_ptr->init(config);