commit 7b372aa0c4374a84c62507c3356454f7847a5d26
Author: HinSon <2636178756@qq.com>
Date: Mon Dec 27 17:23:19 2021 +0800
v2.1
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..a163563
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,53 @@
+cmake_minimum_required(VERSION 2.8)
+project(hins_se_driver)
+
+set( CMAKE_BUILD_TYPE Release )
+set( CMAKE_BUILD_TYPE Debug )
+if( CMAKE_BUILD_TYPE STREQUAL "Release")
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -std=c++11 -fPIC")
+else()
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -std=c++11 -fPIC")
+endif()
+
+
+file(GLOB_RECURSE HEADER_FILES include/*.h)
+file(GLOB_RECURSE SOURCE_FILES src/*.cpp)
+
+find_package(catkin REQUIRED COMPONENTS
+roscpp
+rospy
+std_msgs
+geometry_msgs
+sensor_msgs
+tf
+)
+
+catkin_package(
+ INCLUDE_DIRS include
+ LIBRARIES
+ CATKIN_DEPENDS )
+
+#set(lib_files )
+
+
+include_directories(include ${catkin_INCLUDE_DIRS})
+
+add_executable(${PROJECT_NAME} ${SOURCE_FILES} ${HEADER_FILES})
+target_link_libraries(${PROJECT_NAME} ${catkin_LIBRARIES} )
+
+# install executables and/or libraries
+install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}
+ ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
+ LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
+ RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
+)
+
+install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include
+DESTINATION "${CMAKE_INSTALL_PREFIX}" COMPONENT header)
+
+# install files
+foreach(dir launch)
+install(DIRECTORY ${dir}/
+DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/${dir})
+endforeach(dir)
+
diff --git a/CMakeLists.txt.user b/CMakeLists.txt.user
new file mode 100644
index 0000000..79b568f
--- /dev/null
+++ b/CMakeLists.txt.user
@@ -0,0 +1,375 @@
+
+
+
+
+
+ EnvironmentId
+ {0ecb8702-28d5-4134-b587-a0b8643a8bbb}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ false
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ UTF-8
+ false
+ 4
+ false
+ 80
+ true
+ false
+ 1
+ true
+ false
+ 0
+ true
+ true
+ 0
+ 8
+ true
+ 1
+ true
+ true
+ true
+ false
+
+
+
+ ProjectExplorer.Project.PluginSettings
+
+
+ true
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ 桌面
+ 桌面
+ {d6473b3e-f747-4f26-ab57-f336a893711c}
+ 0
+ 0
+ 0
+
+
+ /home/develop/lead_develop/build-hins_driver_laser
+
+
+
+
+ all
+
+ true
+ CMake Build
+
+ CMakeProjectManager.MakeStep
+
+ 1
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+
+ all
+
+ true
+ CMake Build
+
+ CMakeProjectManager.MakeStep
+
+ 1
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Default
+ Default
+ CMakeProjectManager.CMakeBuildConfiguration
+
+
+
+ CMAKE_BUILD_TYPE:STRING=Debug
+
+ /home/develop/lead_develop/build-hins_driver_laser
+
+
+
+
+ all
+
+ true
+ CMake Build
+
+ CMakeProjectManager.MakeStep
+
+ 1
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+
+ all
+
+ true
+ CMake Build
+
+ CMakeProjectManager.MakeStep
+
+ 1
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Debug
+ Debug
+ CMakeProjectManager.CMakeBuildConfiguration
+
+
+
+ CMAKE_BUILD_TYPE:STRING=Release
+
+ /home/develop/lead_develop/build-hins_driver_laser
+
+
+
+
+ all
+
+ true
+ CMake Build
+
+ CMakeProjectManager.MakeStep
+
+ 1
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+
+ all
+
+ true
+ CMake Build
+
+ CMakeProjectManager.MakeStep
+
+ 1
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Release
+ Release
+ CMakeProjectManager.CMakeBuildConfiguration
+
+
+
+ CMAKE_BUILD_TYPE:STRING=RelWithDebInfo
+
+ /home/develop/lead_develop/build-hins_driver_laser
+
+
+
+
+ all
+
+ true
+ CMake Build
+
+ CMakeProjectManager.MakeStep
+
+ 1
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+
+ all
+
+ true
+ CMake Build
+
+ CMakeProjectManager.MakeStep
+
+ 1
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Release with Debug Information
+ Release with Debug Information
+ CMakeProjectManager.CMakeBuildConfiguration
+
+
+
+ CMAKE_BUILD_TYPE:STRING=MinSizeRel
+
+ /home/develop/lead_develop/build-hins_driver_laser
+
+
+
+
+ all
+
+ true
+ CMake Build
+
+ CMakeProjectManager.MakeStep
+
+ 1
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+
+ all
+
+ true
+ CMake Build
+
+ CMakeProjectManager.MakeStep
+
+ 1
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Minimum Size Release
+ Minimum Size Release
+ CMakeProjectManager.CMakeBuildConfiguration
+
+ 5
+
+
+ 0
+ Deploy
+
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+ Deploy Configuration
+
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+
+ false
+ false
+ 1000
+
+ true
+
+ false
+ false
+ false
+ false
+ true
+ 0.01
+ 10
+ true
+ 1
+ 25
+
+ 1
+ true
+ false
+ true
+ valgrind
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+
+ 2
+
+
+ Custom Executable
+
+ ProjectExplorer.CustomExecutableRunConfiguration
+
+ 3768
+ false
+ true
+ false
+ false
+ true
+
+
+
+ 1
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 1
+
+
+ ProjectExplorer.Project.Updater.FileVersion
+ 20
+
+
+ Version
+ 20
+
+
diff --git a/include/connection_address.h b/include/connection_address.h
new file mode 100644
index 0000000..712b112
--- /dev/null
+++ b/include/connection_address.h
@@ -0,0 +1,75 @@
+/*********************************************************************
+*
+* Software License Agreement ()
+*
+* Copyright (c) 2020, HINS, Inc.
+* All rights reserved.
+*
+* Author: Hu Liankui
+* Create Date: 8/9/2020
+*********************************************************************/
+
+/**
+ * @brief tcp连接地址描述
+ */
+
+#pragma once
+
+#include
+
+using namespace std;
+
+namespace hins {
+
+class ConnectionAddress final
+{
+public:
+ ConnectionAddress(){;}
+ ConnectionAddress(const string& address, const int& port)
+ : address_(address)
+ , port_(port)
+ , description_("Connection address and port")
+ {}
+ ConnectionAddress(const string& address, const int& port, const string& description)
+ : address_(address)
+ , port_(port)
+ , description_(description)
+ {}
+
+ void SetAddress(const string& address)
+ {
+ address_ = address;
+ }
+
+ void SetPort(const int& port)
+ {
+ port_ = port;
+ }
+
+ void SetDescription(const string& description)
+ {
+ description_ = description;
+ }
+
+ const string GetAddress() const
+ {
+ return address_;
+ }
+
+ int GetPort() const
+ {
+ return port_;
+ }
+
+ const string GetDescription() const
+ {
+ return description_;
+ }
+
+private:
+ string address_;
+ int port_;
+ string description_;
+};
+
+}
diff --git a/include/hins/laser_data_receiver.h b/include/hins/laser_data_receiver.h
new file mode 100644
index 0000000..7e88e60
--- /dev/null
+++ b/include/hins/laser_data_receiver.h
@@ -0,0 +1,103 @@
+/*********************************************************************
+*
+* Software License Agreement ()
+*
+* Copyright (c) 2020, HINS, Inc.
+* All rights reserved.
+*
+* Author: Hu Liankui
+* Create Date: 8/9/2020
+*********************************************************************/
+
+/**
+ * @brief 兴颂激光雷达数据获取
+ */
+
+#pragma once
+
+#define BOOST_CB_DISABLE_DEBUG
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "connection_address.h"
+#include "hins/protoc.h"
+
+namespace hins{
+
+class LaserDataReceiver;
+using LaserDataReceiverPtr = LaserDataReceiver*;
+using LaserDataReceiverHdr = std::shared_ptr;
+
+class LaserDataReceiver final
+{
+public:
+ LaserDataReceiver(const ConnectionAddress &conn_info);
+
+ ~LaserDataReceiver();
+
+ int SyncWrite();
+ int SyncWrite(const std::array command);
+ bool Connect();
+
+ bool IsConnected();
+
+ void Disconnect();
+
+ bool CheckConnection();
+
+ ScanData GetFullScan();
+
+private:
+ void HandleSocketRead(const boost::system::error_code& error);
+
+ int32_t FindPacketStart();
+
+ /**
+ * @brief WriteBufferBack write data to buffer tail
+ * @param src
+ * @param num_bytes
+ */
+ void WriteBufferBack(char* src, std::size_t num_bytes);
+
+ /**
+ * @brief HandleNextPacket parse the data in ring buffer
+ * @return true - parse success; false - otherwise
+ */
+ bool HandleNextPacket();
+
+ bool RetrivePacket();
+
+ void ReadBufferFront(char* dst, const uint16_t& num_bytes);
+
+private:
+ ConnectionAddress conn_info_;
+ bool is_connected_;
+ boost::thread io_service_thread_;
+ boost::asio::io_service io_service_;
+
+ boost::asio::streambuf inbuf_; // Boost::Asio streambuffer
+ std::istream instream_; // Input stream
+
+ boost::asio::ip::tcp::socket* tcp_socket_ptr_; // reveiving socket
+
+ boost::circular_buffer ring_buffer_; // Internal ringbuffer for temporarily storing reveived data
+
+ std::mutex scan_mutex_; // Protection against data races between ROS and IO threads
+ std::condition_variable data_notifier_; // Data notification condition variable
+
+ std::deque scan_data_; // Double ended queue with sucessfully received and parsed data, organized as single complete scans
+ std::deque area_data_;
+
+ uint64_t last_data_time_; // time in seconds since epoch, when last data was received
+};
+
+}
+
diff --git a/include/hins/protoc.h b/include/hins/protoc.h
new file mode 100644
index 0000000..d2312af
--- /dev/null
+++ b/include/hins/protoc.h
@@ -0,0 +1,72 @@
+/*********************************************************************
+*
+* Software License Agreement ()
+*
+* Copyright (c) 2020, HINS, Inc.
+* All rights reserved.
+*
+* Author: Hu Liankui
+* Create Date: 8/9/2020
+*********************************************************************/
+
+#pragma once
+
+#include
+#include
+
+namespace hins {
+
+const std::array kStartCapture {0x52, 0x41, 0x75, 0x74, 0x6f, 0x01, 0x87, 0x80};
+
+struct ScanData
+{
+ // 距离数据
+ std::vector distance_data;
+
+ // 强度数据
+ std::vector amplitude_data;
+};
+
+struct AreaData
+{
+std::array identifier; // 标识符
+char channel; // 传感器通道值
+char input_state;
+char output_state;
+char led_state;
+uint16_t error_state;
+uint16_t check;
+};
+
+
+struct ShadowsFilterParam
+{
+ float min_angle;
+ float max_angle;
+ int neighbors; // 删除窗口
+ int window; // 搜索计算窗口
+ int shadows_filter_level;
+ int traverse_step; // 遍历步长
+};
+
+#pragma pack(1)
+
+struct XSPackageHeader
+{
+ char head[6]; // 5个标识符+一个预留位
+ uint16_t start_angle; // 起始角度
+ uint16_t end_angle; // 终止角度
+ uint16_t data_size; // 这个包里面总的测量点数
+};
+
+const uint16_t kXSPackageHeadSize = sizeof(XSPackageHeader);
+const uint16_t kXSAreaDataSize = sizeof(AreaData);
+const uint16_t kMaxDistance = 10000;
+const uint16_t kMaxIntensity = 30000;
+
+
+#pragma pack()
+
+
+}
+
diff --git a/include/hins/xingsong_driver.h b/include/hins/xingsong_driver.h
new file mode 100644
index 0000000..429629e
--- /dev/null
+++ b/include/hins/xingsong_driver.h
@@ -0,0 +1,73 @@
+/*********************************************************************
+ *
+ * Software License Agreement ()
+ *
+ * Copyright (c) 2020, HINS, Inc.
+ * All rights reserved.
+ *
+ * Author: Hu Liankui
+ * Create Date: 8/9/2020
+ *********************************************************************/
+
+/**
+ * @brief 兴颂激光雷达驱动
+ */
+
+#pragma once
+
+#include "hins/laser_data_receiver.h"
+#include
+namespace hins
+{
+
+ class XingSongDriver;
+ using XingSongDriverHdr = std::shared_ptr;
+
+ class XingSongDriver
+ {
+ public:
+ XingSongDriver(const ConnectionAddress &conn_info);
+ XingSongDriver(const ConnectionAddress &conn_info, ShadowsFilterParam shadows_filter_param_);
+ ~XingSongDriver();
+
+ bool StartCapturingTCP();
+
+ ScanData GetFullScan();
+
+ bool Connect()
+ {
+ return data_receiver_ptr_->Connect();
+ }
+
+ bool IsConnected()
+ {
+ return data_receiver_ptr_->IsConnected();
+ }
+
+ void Disconnect()
+ {
+ data_receiver_ptr_->Disconnect();
+ }
+
+ int SyncWrite(const std::array command)
+ {
+ return data_receiver_ptr_->SyncWrite(command);
+ }
+
+ private:
+ void RunMain();
+ void ShadowsFilterInit(int scan_num);
+ void ShadowsFilter(ScanData& data, int scan_num);
+
+ private:
+ ShadowsFilterParam shadows_filter_param_;
+ ConnectionAddress conn_info_;
+ LaserDataReceiverPtr data_receiver_ptr_;
+ std::thread guard_thread_;
+ std::vector shadows_filter_threshold_min_;
+ std::vector shadows_filter_threshold_max_;
+ set shadows_del_index_;
+ };
+
+
+}
diff --git a/include/utils.h b/include/utils.h
new file mode 100644
index 0000000..4e7e353
--- /dev/null
+++ b/include/utils.h
@@ -0,0 +1,34 @@
+/*********************************************************************
+*
+* Software License Agreement ()
+*
+* Copyright (c) 2020, HINS, Inc.
+* All rights reserved.
+*
+* Author: Hu Liankui
+* Create Date: 8/9/2020
+*********************************************************************/
+
+/**
+ * @brief useful tool
+ */
+
+#pragma once
+#include
+#include
+#include
+
+namespace hins {
+
+/**
+ * @brief Now ms timestamp
+ * @return
+ */
+static uint64_t Now()
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+}
+
+} // end of namespace hins
diff --git a/launch/hins_driver.launch~ b/launch/hins_driver.launch~
new file mode 100644
index 0000000..3215470
--- /dev/null
+++ b/launch/hins_driver.launch~
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/launch/hins_se_driver.launch b/launch/hins_se_driver.launch
new file mode 100644
index 0000000..7cf3f0e
--- /dev/null
+++ b/launch/hins_se_driver.launch
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/launch/laser.rviz b/launch/laser.rviz
new file mode 100644
index 0000000..2334a6b
--- /dev/null
+++ b/launch/laser.rviz
@@ -0,0 +1,149 @@
+Panels:
+ - Class: rviz/Displays
+ Help Height: 78
+ Name: Displays
+ Property Tree Widget:
+ Expanded:
+ - /Global Options1
+ - /Status1
+ - /LaserScan1
+ Splitter Ratio: 0.5
+ Tree Height: 549
+ - Class: rviz/Selection
+ Name: Selection
+ - Class: rviz/Tool Properties
+ Expanded:
+ - /2D Pose Estimate1
+ - /2D Nav Goal1
+ - /Publish Point1
+ Name: Tool Properties
+ Splitter Ratio: 0.5886790156364441
+ - Class: rviz/Views
+ Expanded:
+ - /Current View1
+ Name: Views
+ Splitter Ratio: 0.5
+ - Class: rviz/Time
+ Experimental: false
+ Name: Time
+ SyncMode: 0
+ SyncSource: ""
+Preferences:
+ PromptSaveOnExit: true
+Toolbars:
+ toolButtonStyle: 2
+Visualization Manager:
+ Class: ""
+ Displays:
+ - Alpha: 0.5
+ Cell Size: 1
+ Class: rviz/Grid
+ Color: 160; 160; 164
+ Enabled: true
+ Line Style:
+ Line Width: 0.029999999329447746
+ Value: Lines
+ Name: Grid
+ Normal Cell Count: 0
+ Offset:
+ X: 0
+ Y: 0
+ Z: 0
+ Plane: XY
+ Plane Cell Count: 10
+ Reference Frame:
+ Value: true
+ - Alpha: 1
+ Autocompute Intensity Bounds: true
+ Autocompute Value Bounds:
+ Max Value: 10
+ Min Value: -10
+ Value: true
+ Axis: Z
+ Channel Name: intensity
+ Class: rviz/LaserScan
+ Color: 255; 255; 255
+ Color Transformer: ""
+ Decay Time: 0
+ Enabled: true
+ Invert Rainbow: false
+ Max Color: 255; 255; 255
+ Min Color: 0; 0; 0
+ Name: LaserScan
+ Position Transformer: ""
+ Queue Size: 10
+ Selectable: true
+ Size (Pixels): 3
+ Size (m): 0.009999999776482582
+ Style: Flat Squares
+ Topic: /scan
+ Unreliable: false
+ Use Fixed Frame: true
+ Use rainbow: true
+ Value: true
+ Enabled: true
+ Global Options:
+ Background Color: 48; 48; 48
+ Default Light: true
+ Fixed Frame: laser
+ Frame Rate: 30
+ Name: root
+ Tools:
+ - Class: rviz/Interact
+ Hide Inactive Objects: true
+ - Class: rviz/MoveCamera
+ - Class: rviz/Select
+ - 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
+ Single click: true
+ Topic: /clicked_point
+ Value: true
+ Views:
+ Current:
+ Class: rviz/Orbit
+ Distance: 18.546350479125977
+ Enable Stereo Rendering:
+ Stereo Eye Separation: 0.05999999865889549
+ Stereo Focal Distance: 1
+ Swap Stereo Eyes: false
+ Value: false
+ Field of View: 0.7853981852531433
+ Focal Point:
+ X: 0
+ Y: 0
+ Z: 0
+ Focal Shape Fixed Size: true
+ Focal Shape Size: 0.05000000074505806
+ Invert Z Axis: false
+ Name: Current View
+ Near Clip Distance: 0.009999999776482582
+ Pitch: 0.7403981685638428
+ Target Frame:
+ Yaw: 5.36857795715332
+ Saved: ~
+Window Geometry:
+ Displays:
+ collapsed: false
+ Height: 846
+ Hide Left Dock: false
+ Hide Right Dock: false
+ QMainWindow State: 000000ff00000000fd000000040000000000000156000002b0fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d000002b0000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000002b0fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003d000002b0000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004f30000003efc0100000002fb0000000800540069006d00650100000000000004f3000002eb00fffffffb0000000800540069006d0065010000000000000450000000000000000000000282000002b000000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
+ Selection:
+ collapsed: false
+ Time:
+ collapsed: false
+ Tool Properties:
+ collapsed: false
+ Views:
+ collapsed: false
+ Width: 1267
+ X: 2208
+ Y: 231
diff --git a/package.xml b/package.xml
new file mode 100644
index 0000000..81463f9
--- /dev/null
+++ b/package.xml
@@ -0,0 +1,25 @@
+
+
+ hins_se_driver
+ 1.0.0
+ The hins navigation lidar driver package
+ Liankui Hu
+ HINS
+ http://xingsong.com
+ Liankui Hu
+
+ catkin
+ geometry_msgs
+ sensor_msgs
+ nav_msgs
+ roscpp
+ rospy
+ std_msgs
+
+ geometry_msgs
+ sensor_msgs
+ nav_msgs
+ roscpp
+ rospy
+ std_msgs
+
diff --git a/readme.txt b/readme.txt
new file mode 100644
index 0000000..4e5c894
--- /dev/null
+++ b/readme.txt
@@ -0,0 +1,18 @@
+1、防拖尾过滤功能
+ 方法 : 在launch文件内修改对应参数 : "shadows_filter_max_angle", "shadows_filter_min_angle", "shadows_filter_traverse_step", "shadows_filter_window", "shadows_filter_level"
+ 说明 : 以shadows_filter_traverse_step为步长,遍历雷达数据。每次搜索遍历点的后shadows_filter_window个点,若两者的垂直夹角小于shadows_filter_min_angle,或者大于shadows_filter_max_angle时,则将较长的点设置为60.001m
+ 1.当shadows_filter_level为-1时,按照具体参数配置过滤算法
+ 1)shadows_filter_max_angle : 筛选的夹角最大值
+ 2)shadows_filter_min_angle : 筛选的夹角最小值
+ 3)shadows_filter_traverse_step : 遍历点数的步长(每n个点检测一次)
+ 4)shadows_filter_window : 搜索窗口大小(检测遍历点的后n个值)
+ 2.当shadows_filter_level为0时,忽略参数设置,不增加防拖尾过滤功能
+ 3.当shadows_filter_level为1时,过滤速度较快,筛选角度大
+ 4.当shadows_filter_level为2时,过滤速度较慢,筛选角度大
+ 5.当shadows_filter_level为3时,过滤速度较慢,筛选角度小
+ 6.若launch文件没有设置以上参数,则默认如下:
+ 1)shadows_filter_level:-1 # 按照具体参数配置防拖尾过滤器
+ 2)shadows_filter_max_angle:175 # 筛选的夹角最大值为175度
+ 3)shadows_filter_min_angle:5 # 筛选的夹角最小值为5度
+ 4)shadows_filter_traverse_step:1 # 遍历每个点
+ 5)shadows_filter_window:2 # 搜索遍历点后2个点是否存在拖尾现象
diff --git a/src/hins/laser_data_receiver.cpp b/src/hins/laser_data_receiver.cpp
new file mode 100644
index 0000000..842af62
--- /dev/null
+++ b/src/hins/laser_data_receiver.cpp
@@ -0,0 +1,449 @@
+#include "hins/laser_data_receiver.h"
+#include "hins/protoc.h"
+#include "utils.h"
+#include
+#include
+
+// #define DEBUG
+namespace hins {
+
+LaserDataReceiver::LaserDataReceiver(const ConnectionAddress& conn_info)
+ : conn_info_(conn_info)
+ , is_connected_(false)
+ , inbuf_(4096)
+ , instream_(&inbuf_)
+ , tcp_socket_ptr_(0)
+ , ring_buffer_(65536)
+ , scan_data_()
+ , last_data_time_(hins::Now())
+{
+ std::cout << "Connecting to TCP data channel at hostname: " << conn_info.GetAddress()
+ << " tcp_port:" << conn_info.GetPort() << std::endl;
+
+ if(Connect())
+ std::cout << "Lidar connect success." << std::endl;
+ else
+ std::cout << "Lidar connect failed." << std::endl;
+}
+
+LaserDataReceiver::~LaserDataReceiver()
+{
+ Disconnect();
+
+ if(tcp_socket_ptr_)
+ delete tcp_socket_ptr_;
+}
+
+bool LaserDataReceiver::IsConnected()
+{
+ return is_connected_;
+}
+
+void LaserDataReceiver::Disconnect()
+{
+ is_connected_ = false;
+ try
+ {
+ if( tcp_socket_ptr_ != nullptr )
+ tcp_socket_ptr_->close();
+
+ io_service_.stop();
+ if( boost::this_thread::get_id() != io_service_thread_.get_id() )
+ io_service_thread_.join();
+
+ }
+ catch (std::exception& e)
+ {
+ std::cout << "Exception:" << e.what() << std::endl;
+ }
+ std::cout << "Disconnect." << std::endl;
+}
+
+bool LaserDataReceiver::CheckConnection()
+{
+ if( !IsConnected() )
+ return false;
+ if( (hins::Now() - last_data_time_)/1000.0 > 5.0 ) // 5.0s 断线
+ {
+ Disconnect();
+ std::cout << "超时断线,超时时间:" << (hins::Now() - last_data_time_)/1000.0 << std::endl;
+ return false;
+ }
+ return true;
+}
+
+ScanData LaserDataReceiver::GetFullScan()
+{
+ std::unique_lock lock(scan_mutex_);
+ while( CheckConnection() && scan_data_.size() < 2 )
+ data_notifier_.wait_for(lock, std::chrono::seconds(1));
+
+
+ ScanData data;
+ if( scan_data_.size() >= 2 && IsConnected())
+ {
+ data = ScanData(std::move(scan_data_.front()));
+ scan_data_.pop_front();
+ }
+ else
+ std::cout << "null data" << std::endl;
+ return data;
+}
+
+void LaserDataReceiver::HandleSocketRead(const boost::system::error_code &error)
+{
+ if(!error)
+ {
+ // 1. 将所有数据推送到缓冲区
+ instream_.clear();
+ while(!instream_.eof())
+ {
+ char buf[4096];
+ instream_.read(buf, 4096);
+ int bytes_read = instream_.gcount();
+ WriteBufferBack(buf, bytes_read); // 将 buf 的数据写到 ring_buffer_ 里
+ }
+
+ // 2. 继续读取数据,直到数据被读取完
+ while(HandleNextPacket()) {}
+
+ // 3. 继续异步读取数据
+ boost::asio::async_read(*tcp_socket_ptr_, inbuf_, boost::bind(&LaserDataReceiver::HandleSocketRead, this, boost::asio::placeholders::error));
+ }
+ else
+ {
+ if( error.value() != 995 )
+ std::cout << "ERROR: data connection error:"
+ << error.message()
+ << " "
+ << error.value()
+ << std::endl;
+ Disconnect();
+ }
+}
+
+int LaserDataReceiver::SyncWrite()
+{
+ boost::system::error_code ec;
+
+ int ret = tcp_socket_ptr_->write_some(boost::asio::buffer(kStartCapture), ec);
+ if(ec)
+ {
+ std::cout << "write failed:%" << boost::system::system_error(ec).what() << std::endl;
+ ret = -1;
+ }
+ #ifdef DEBUG
+ std::cout << "SyncWrite kStartCapture done" << std::endl;
+ #endif
+ return ret;
+}
+
+
+int LaserDataReceiver::SyncWrite(const std::array command)
+{
+ boost::system::error_code ec;
+
+ int ret = tcp_socket_ptr_->write_some(boost::asio::buffer(command), ec);
+ if(ec)
+ {
+ std::cout << "write failed:" << boost::system::system_error(ec).what() << std::endl;
+ ret = -1;
+ }
+ #ifdef DEBUG
+ std::cout << "SyncWrite command done" << std::endl;
+ #endif
+ return ret;
+}
+
+// CRC循环校验码-12位命令
+// 修改command的最后两位
+// 返回循环校验码的10进制数字
+unsigned int CRC_Verify_len12(std::array *command)
+{
+ unsigned int i, j;
+ unsigned int wCrc = 0xffff;
+ unsigned int wPolynom = 0xA001;
+ /*-------------------------------------*/
+ for (i = 0; i < 12 - 2; i++) // 后两位为校验位
+ {
+ wCrc ^= command->at(i);
+ for (j = 0; j < 8; j++)
+ {
+ if (wCrc & 0x0001)
+ {
+ wCrc = (wCrc >> 1) ^ wPolynom;
+ }
+ else
+ {
+ wCrc = wCrc >> 1;
+ }
+ }
+ }
+ unsigned int tmp1 = (wCrc & 0xff00) >> 8; // 高位
+ unsigned int tmp2 = (wCrc & 0x00ff); // 低位
+ command->at(10) = tmp2;
+ command->at(11) = tmp1;
+ return wCrc;
+}
+
+bool LaserDataReceiver::Connect()
+{
+ try
+ {
+ // 创建hostname/ip
+ boost::asio::ip::tcp::resolver resolver(io_service_);
+ boost::asio::ip::tcp::resolver::query query(conn_info_.GetAddress(), std::to_string(conn_info_.GetPort()));
+ boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
+ boost::asio::ip::tcp::resolver::iterator end;
+
+ if(nullptr == tcp_socket_ptr_)
+ {
+ tcp_socket_ptr_ = new boost::asio::ip::tcp::socket(io_service_);
+ }
+ else
+ {
+ delete tcp_socket_ptr_;
+ tcp_socket_ptr_ = new boost::asio::ip::tcp::socket(io_service_);
+ }
+
+ boost::system::error_code error = boost::asio::error::host_not_found;
+
+ // 迭代端点并建立连接
+ while (error && endpoint_iterator != end)
+ {
+ // tcp_socket_ptr_->close();
+ tcp_socket_ptr_->connect(*endpoint_iterator++, error);
+ }
+ if (error)
+ {
+ std::cout << "Connect failed." << error.message().c_str() << std::endl;
+ return false;
+ }
+
+ // 开始异步读取数据
+ boost::asio::async_read(*tcp_socket_ptr_, inbuf_, boost::bind(&LaserDataReceiver::HandleSocketRead, this, boost::asio::placeholders::error));
+ io_service_thread_ = boost::thread(boost::bind(&boost::asio::io_service::run, &io_service_));
+ is_connected_ = true;
+ }
+ catch (std::exception& e)
+ {
+ std::cout << "Exception:" << e.what() << std::endl;
+ is_connected_ = false;
+ return false;
+ }
+ return true;
+}
+
+// 根据协议寻找数据帧头
+int32_t LaserDataReceiver::FindPacketStart()
+{
+ if(ring_buffer_.size() < kXSPackageHeadSize)
+ return -1;
+
+ // 兴颂LS雷达数据的帧头
+ for(size_t i = 0; i < ring_buffer_.size() - 5; i++)
+ {
+ // 距离数据
+ if(0x43 == ((unsigned char)ring_buffer_[i]) &&
+ 0x6c == ((unsigned char)ring_buffer_[i+1]) &&
+ 0x6f == ((unsigned char)ring_buffer_[i+2]) &&
+ 0x75 == ((unsigned char)ring_buffer_[i+3]) &&
+ 0x64 == ((unsigned char)ring_buffer_[i+4]))
+ {
+ i = i << 2;
+ i |= 0x01; // bit0置1
+ return i;
+ }
+ else
+ // 区域数据
+ if(0x57 == ((unsigned char)ring_buffer_[i]) &&
+ 0x53 == ((unsigned char)ring_buffer_[i+1]) &&
+ 0x69 == ((unsigned char)ring_buffer_[i+2]) &&
+ 0x6d == ((unsigned char)ring_buffer_[i+3]) &&
+ 0x75 == ((unsigned char)ring_buffer_[i+4]))
+ {
+ i = i << 2;
+ i |= 0x02; // bit1置1
+ return i;
+ }
+ }
+ return -2;
+}
+
+// 将src数据写到 ring_buffer_ 里
+void LaserDataReceiver::WriteBufferBack(char *src, std::size_t num_bytes)
+{
+ if(ring_buffer_.size() + num_bytes > ring_buffer_.capacity())
+ throw std::exception();
+
+ ring_buffer_.resize(ring_buffer_.size() + num_bytes); // 修改 ring_buffer_ 的大小
+ char* pone = ring_buffer_.array_one().first; // ring_buffer_ 的 array_one 的头指针
+ std::size_t pone_size = ring_buffer_.array_one().second; // ring_buffer_ 的 array_one 的大小
+ char* ptwo = ring_buffer_.array_two().first; // ring_buffer_ 的 array_two 的头指针
+ std::size_t ptwo_size = ring_buffer_.array_two().second; // ring_buffer_ 的 array_two 的大小
+
+ // 将src数据写到 ring_buffer_ 里
+ if(ptwo_size >= num_bytes)
+ {
+ std::memcpy(ptwo + ptwo_size - num_bytes, src, num_bytes);
+ }
+ else
+ {
+ std::memcpy(pone + pone_size + ptwo_size - num_bytes, src, num_bytes - ptwo_size);
+ std::memcpy(ptwo, src + num_bytes - ptwo_size, ptwo_size);
+ }
+}
+
+bool LaserDataReceiver::HandleNextPacket()
+{
+ if(scan_data_.empty())
+ {
+ scan_data_.emplace_back();
+ }
+
+ if(RetrivePacket())
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+bool LaserDataReceiver::RetrivePacket()
+{
+ bool ret = false;
+ int16_t head_index = FindPacketStart(); // 寻找帧头
+ if(head_index < 0)
+ return ret;
+ // std::cout << "找到帧头了" << std::endl;
+ if(head_index & 0x01==1) // 距离数据
+ {
+ head_index = head_index >> 2;
+ // 寻找帧头并处理数据
+ if(ring_buffer_.size() - head_index >= kXSPackageHeadSize)
+ {
+ ring_buffer_.erase_begin(head_index); // 删除 帧头前的数据
+ head_index = 0;
+
+ // 1. 解析数据帧帧头
+ char head_buf[kXSPackageHeadSize];
+ ReadBufferFront(head_buf, kXSPackageHeadSize);
+
+ XSPackageHeader header;
+ header.start_angle = (unsigned char)head_buf[6] << 8; // 起始角度
+ header.start_angle |= (unsigned char)head_buf[7];
+ header.end_angle = (unsigned char)head_buf[8] << 8; // 终止角度
+ header.end_angle |= (unsigned char)head_buf[9];
+ header.data_size = (unsigned char)head_buf[10] << 8; // 测量点总数
+ header.data_size |= (unsigned char)head_buf[11];
+
+ std::unique_lock lock(scan_mutex_);
+
+ // 2. 解析帧内容
+ ScanData& scan_data = scan_data_.back();
+ uint16_t body_size = kXSPackageHeadSize + header.data_size * 4;
+
+ if((ring_buffer_.size() - head_index) >= body_size)
+ {
+ #ifdef DEBUG
+ std::cout << "begin:" << header.start_angle
+ << " end:" << header.end_angle
+ << " data_size:" << header.data_size
+ << std::endl;
+ #endif
+
+ char* body_buf = new char[body_size];
+ ReadBufferFront(body_buf, body_size); // 将当前帧的数据复制到 body_buf 中
+
+ ring_buffer_.erase_begin(head_index + body_size); // 删除 ring_buffer_ 的数据
+
+ for(int i = 0; i < header.data_size; i++)
+ {
+ unsigned short int distance;
+ unsigned short int intensity;
+ distance = (unsigned char)body_buf[i*4 + 13] << 8;
+ distance |= (unsigned char)body_buf[i*4 + 12];
+ intensity = (unsigned char)body_buf[i*4 + 15] << 8;
+ intensity |= (unsigned char)body_buf[i*4 + 14];
+
+ if(distance > kMaxDistance)
+ {
+ distance = kMaxDistance;
+ }
+ if(intensity > kMaxIntensity)
+ {
+ intensity = kMaxIntensity;
+ }
+
+ scan_data.distance_data.push_back(distance);
+ scan_data.amplitude_data.push_back(intensity);
+ }
+
+ delete [] body_buf;
+
+ if(header.end_angle == 315)
+ {
+ scan_data_.emplace_back();
+ if(scan_data_.size() > 5)
+ {
+ scan_data_.pop_front();
+ std::cout << "buffer data too many, drops it" << std::endl;
+ }
+ data_notifier_.notify_one();
+ last_data_time_ = hins::Now();
+ ret = true;
+ }
+
+ if(FindPacketStart() >= 0)
+ {
+ ret = true;
+ }
+ }
+ }
+ else
+ if(head_index & 0x02==1) // 区域数据
+ {
+ head_index = head_index >> 2;
+ if(ring_buffer_.size() - head_index >= kXSAreaDataSize)
+ {
+ AreaData area_data;
+ char area_buf[kXSPackageHeadSize];
+ ring_buffer_.erase_begin(head_index); // 删除 帧头前的数据
+ ReadBufferFront(area_buf, kXSPackageHeadSize);
+ area_data.channel = (unsigned char)area_buf[5]; // 传感器通道值
+ area_data.input_state = (unsigned char)area_buf[6];
+ area_data.output_state = (unsigned char)area_buf[7];
+ area_data.led_state = (unsigned char)area_buf[8];
+ area_data.error_state = (unsigned char)area_buf[9];
+ area_data.check = (unsigned char)area_buf[9];
+ }
+ }
+ }
+ return ret;
+}
+
+// 将ring_buffer_前num_bytes的数据拷贝到dst
+void LaserDataReceiver::ReadBufferFront(char *dst, const uint16_t &num_bytes)
+{
+ if( ring_buffer_.size() < num_bytes )
+ throw std::exception();
+
+ char* pone = ring_buffer_.array_one().first; // 指向环形缓冲区ring_buffer_的array_one的开始地址
+ std::size_t pone_size = ring_buffer_.array_one().second; // ring_buffer_的array_one的大小
+ char* ptwo = ring_buffer_.array_two().first; // 指向环形缓冲区ring_buffer_的array_two的开始地址
+
+ if( pone_size >= num_bytes ) // ring_buffer_的array_one的大小大于num_bytes
+ {
+ std::memcpy(dst, pone, num_bytes); // 复制环形缓冲区的数据到dst中
+ }
+ else
+ {
+ std::memcpy(dst, pone, pone_size); // 复制环形缓冲区的array_one数据到dst中
+ std::memcpy(dst + pone_size, ptwo, num_bytes - pone_size); // 复制环形缓冲区的array_two数据到dst中
+ }
+}
+
+}
diff --git a/src/hins/xingsong_driver.cpp b/src/hins/xingsong_driver.cpp
new file mode 100644
index 0000000..354a43e
--- /dev/null
+++ b/src/hins/xingsong_driver.cpp
@@ -0,0 +1,235 @@
+#include "hins/xingsong_driver.h"
+
+// #define DEBUG
+
+namespace hins {
+
+XingSongDriver::XingSongDriver(const ConnectionAddress &conn_info)
+ : conn_info_(conn_info)
+ , data_receiver_ptr_(nullptr)
+{
+ guard_thread_ = std::thread(&XingSongDriver::RunMain, this);
+ shadows_filter_param_.max_angle = -1.0;
+}
+
+XingSongDriver::XingSongDriver(const ConnectionAddress &conn_info, ShadowsFilterParam shadows_filter_param)
+ : conn_info_(conn_info)
+ , data_receiver_ptr_(nullptr)
+ , shadows_filter_param_(shadows_filter_param)
+{
+ guard_thread_ = std::thread(&XingSongDriver::RunMain, this);
+}
+
+XingSongDriver::~XingSongDriver()
+{
+ if(data_receiver_ptr_)
+ {
+ delete data_receiver_ptr_;
+ }
+}
+
+bool XingSongDriver::StartCapturingTCP()
+{
+ if(data_receiver_ptr_)
+ {
+ delete data_receiver_ptr_;
+ }
+
+ data_receiver_ptr_ = new LaserDataReceiver(conn_info_);
+ if(!data_receiver_ptr_->IsConnected())
+ {
+ return false;
+ }
+ if(data_receiver_ptr_->SyncWrite() > 0)
+ {
+ return true;
+ }
+ return false;
+}
+
+
+/*
+* 防拖尾过滤参数初始化
+*/
+void XingSongDriver::ShadowsFilterInit(int scan_num)
+{
+ shadows_filter_threshold_max_.clear();
+ shadows_filter_threshold_min_.clear();
+
+ float max, min, min_angle, max_angle, angle_increment;
+ angle_increment = 2*M_PI/(float)scan_num;
+ int window;
+
+ switch (shadows_filter_param_.shadows_filter_level)
+ {
+ case 1: // 快速,筛选角度大,搜索窗口小
+ min_angle = M_PI*5.0f/180.0f; // 转换为弧度制
+ max_angle = M_PI*175.0f/180.0f; // 转换为弧度制
+ window = 1;
+ break;
+
+ case 2: // 较慢,筛选角度大,搜索窗口适中
+ min_angle = M_PI*5.0f/180.0f; // 转换为弧度制
+ max_angle = M_PI*175.0f/180.0f; // 转换为弧度制
+ window = 3;
+ break;
+
+ case 3: // 较慢,筛选角度较小,搜索窗口大
+ min_angle = M_PI*15.0f/180.0f; // 转换为弧度制
+ max_angle = M_PI*165.0f/180.0f; // 转换为弧度制
+ window = 5;
+ break;
+
+ default: // 按照shadows_filter_param_配置
+ min_angle = M_PI*shadows_filter_param_.min_angle/180.0f; // 转换为弧度制
+ max_angle = M_PI*shadows_filter_param_.max_angle/180.0f; // 转换为弧度制
+ window = shadows_filter_param_.window;
+
+ break;
+ }
+#ifdef DEBUG
+ std::cout << "shadows_filter_level:" << shadows_filter_param_.shadows_filter_level
+ << " min_angle:" << shadows_filter_param_.min_angle
+ << " max_angle:" << shadows_filter_param_.max_angle
+ << std::endl;
+ std::cout << "max:";
+#endif
+ for(int i=0;i < window;i++)
+ {
+ max = sin(max_angle)/sin(M_PI-max_angle-angle_increment*(i+1));
+ min = sin(min_angle)/sin(M_PI-min_angle-angle_increment*(i+1));
+
+ shadows_filter_threshold_max_.push_back(max);
+ shadows_filter_threshold_min_.push_back(min);
+ #ifdef DEBUG
+ std::cout << shadows_filter_threshold_max_.back() << " ";
+ #endif
+ } // if(data.distance_data.size() != scan_all_point_num_)
+ // data.distance_data.clear();
+}
+
+
+/*
+* 防拖尾过滤
+*/
+void XingSongDriver::ShadowsFilter(ScanData& scan_data, int scan_num)
+{
+ #ifdef DEBUG
+ int del_num = 0;
+ #endif
+ // if(GetLaserSteadyTime() > 0)
+ // {
+ ShadowsFilterInit(scan_num);
+ // }
+ int search_index, search_index_tmp, del_index, del_index_tmp;
+ float a_b_rate;
+
+ // 清除上一次的删除点集合
+ shadows_del_index_.clear();
+
+ // 每traverse_step根激光计算一次
+ for (int i = 0; i < scan_num; i += shadows_filter_param_.traverse_step)
+ {
+ if(scan_data.distance_data[i] > kMaxDistance) // 如果search_index_tmp激光超出范围,则跳过
+ continue;
+
+ for(search_index = i+1; // 搜索[i,i+window]内是否存在拖影现象
+ search_index <= i + shadows_filter_param_.window;
+ search_index++)
+ {
+ search_index_tmp = search_index;
+
+ // 边界
+ if(search_index_tmp < 0)
+ search_index_tmp = 0;
+ else
+ if(search_index_tmp >= scan_num)
+ search_index_tmp = scan_num - 1;
+
+ if( (scan_data.distance_data[search_index_tmp] > kMaxDistance) || // 如果search_index_tmp激光超出范围,则跳过
+ (scan_data.distance_data[i] > kMaxDistance) )
+ continue;
+
+ a_b_rate = (float)scan_data.distance_data[i]/(float)scan_data.distance_data[search_index_tmp]; // i与search_index激光比较
+ if( (a_b_rate < shadows_filter_threshold_min_[abs(search_index_tmp-i-1)]) || // 如果存在拖影现象
+ (a_b_rate > shadows_filter_threshold_max_[abs(search_index_tmp-i-1)]) )
+ if (scan_data.distance_data[i] < scan_data.distance_data[search_index_tmp])
+ {
+ #ifdef DEBUG
+ del_num++;
+ #endif
+ // scan_data.distance_data[search_index_tmp] = kMaxDistance+1;
+ shadows_del_index_.insert(search_index_tmp);
+
+ }
+ else
+ {
+ #ifdef DEBUG
+ del_num++;
+ #endif
+ // scan_data.distance_data[i] = kMaxDistance + 1;
+ shadows_del_index_.insert(i);
+ }
+ }
+ }
+
+ // 删除拖尾点
+ for(auto iter = shadows_del_index_.begin(); iter != shadows_del_index_.end(); ++iter)
+ {
+ scan_data.distance_data[*iter] = kMaxDistance + 1;
+ }
+ #ifdef DEBUG
+ std::cout << "del_num:" << del_num << std::endl;
+ #endif
+}
+
+ScanData XingSongDriver::GetFullScan()
+{
+ if (data_receiver_ptr_)
+ {
+ if (shadows_filter_param_.max_angle < 0 || shadows_filter_param_.shadows_filter_level == 0)
+ return data_receiver_ptr_->GetFullScan();
+ ScanData fullscan = data_receiver_ptr_->GetFullScan();
+ int scan_num = fullscan.distance_data.size();
+ ShadowsFilter(fullscan, scan_num); // 过滤拖尾点
+ return fullscan;
+ }
+ else
+ return ScanData();
+}
+
+void XingSongDriver::RunMain()
+{
+ if(StartCapturingTCP())
+ {
+ std::cout << "兴颂雷达启动成功." << std::endl;
+ }
+ else
+ {
+ std::cout << "兴颂雷达启动失败,请检查网络连接." << std::endl;
+ }
+
+ while(true) // @todo: stop loop condition need to modified
+ {
+ if(IsConnected())
+ {
+ //
+ }
+ else
+ {
+ while(IsConnected()){
+ std::cout << "激光雷达断线,正在重新连接 ... " << std::endl;
+ if(StartCapturingTCP()){
+ std::cout << "激光雷达重新连接成功." << std::endl;
+ }
+ usleep(1000 * 50); // 50ms
+ }
+ }
+
+ usleep(1000*25); // 25ms
+ }
+
+ Disconnect();
+}
+
+}
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..b208345
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,110 @@
+#include
+#include
+#include "hins/xingsong_driver.h"
+
+using namespace hins;
+
+sensor_msgs::LaserScanPtr ToLaserScan(const ScanData &data, const float& start_angle, const float& end_angle, const std::string& frame_name);
+void ParamInit(ros::NodeHandle &nh_private ,ConnectionAddress &laser_conn_info, ShadowsFilterParam &shadows_filter_param);
+
+int main(int argc, char** argv){
+
+ // 1. ROS 初始化
+ ros::init(argc, argv, "hins_driver_laser");
+ ros::NodeHandle nh_;
+ ros::NodeHandle nh_private("~");
+
+ float start_angle, end_angle;
+ std::string topic_name,frame_name;
+ nh_private.param("start_angle", start_angle, 0.);
+ nh_private.param("end_angle", end_angle, 2 * M_PI);
+ nh_private.param("topic_name", topic_name, std::string("scan1"));
+ nh_private.param("frame_name", frame_name, std::string("laser1"));
+
+ ROS_INFO("advertise: %s", topic_name.c_str());
+ ros::Publisher scan_pub = nh_.advertise(topic_name, 3, true);
+
+ // 2. 雷达驱动
+ ConnectionAddress laser_conn_info;
+ ShadowsFilterParam shadows_filter_param;
+
+ // 初始化驱动参数
+ ParamInit(nh_private,laser_conn_info, shadows_filter_param);
+
+ // 启动雷达
+ XingSongDriverHdr driver_hdr = std::make_shared(laser_conn_info,shadows_filter_param);
+
+ // 3. ros 消息发布
+ ros::Rate r(50);
+ while(ros::ok()){
+ ScanData data = driver_hdr->GetFullScan();
+ sensor_msgs::LaserScanPtr scan_msg_ptr = ToLaserScan(data, start_angle, end_angle, frame_name);
+ if(scan_msg_ptr->ranges.size() != 0) // 如果数据长度有误,则不发布
+ {
+ scan_pub.publish(scan_msg_ptr);
+ }
+ r.sleep();
+ }
+}
+
+sensor_msgs::LaserScanPtr ToLaserScan(const ScanData &data, const float& start_angle, const float& end_angle, const std::string& frame_name)
+{
+ sensor_msgs::LaserScanPtr ret = boost::make_shared();
+
+ ret->header.frame_id = frame_name;
+ ret->header.stamp = ros::Time::now();
+
+ ret->range_min = 0.05;
+ ret->range_max = 60.0;
+ ret->angle_min = M_PI/2.0f;
+ ret->angle_max = 3.0 * M_PI/2.0f;
+
+ ret->time_increment = 1/20/float(data.distance_data.size()); // 一个周期时间除以扫描点数
+
+ ret->angle_increment = 1.5 * M_PI/float(data.distance_data.size());
+
+ ret->ranges.resize(data.distance_data.size(), 0);
+ ret->intensities.resize(data.amplitude_data.size(), 0);
+
+ for( std::size_t i = 0; i < data.distance_data.size(); i++ )
+ {
+ float angle = ret->angle_min + i * ret->angle_increment;
+
+ float dis = float(data.distance_data[i])/1000.0f;
+
+ if(angle < start_angle || angle > end_angle)
+ ret->ranges[i] = 1024.0;
+ else
+ ret->ranges[i] = dis;
+ ret->intensities[i] = data.amplitude_data[i];
+ }
+
+ return ret;
+}
+
+
+void ParamInit(ros::NodeHandle &nh_private ,ConnectionAddress &laser_conn_info, ShadowsFilterParam &shadows_filter_param)
+{
+ std::string server_address;
+ float start_angle, end_angle, shadows_filter_max_angle, shadows_filter_min_angle;
+ int port, shadows_filter_neighbors, shadows_filter_window, shadows_filter_level, shadows_filter_traverse_step;
+
+ nh_private.param("laser_ip", server_address, std::string("192.168.1.88"));
+ nh_private.param("laser_port", port, 8080);
+ nh_private.param("shadows_filter_max_angle", shadows_filter_max_angle, float(175.0));
+ nh_private.param("shadows_filter_min_angle", shadows_filter_min_angle, float(5.0));
+ nh_private.param("shadows_filter_neighbors", shadows_filter_neighbors, 1);
+ nh_private.param("shadows_filter_window", shadows_filter_window, 2);
+ nh_private.param("shadows_filter_traverse_step", shadows_filter_traverse_step, 1);
+ nh_private.param("shadows_filter_level", shadows_filter_level, -1); // 默认按照具体参数配置
+
+ laser_conn_info.SetAddress(server_address);
+ laser_conn_info.SetPort(port);
+
+ shadows_filter_param.max_angle = shadows_filter_max_angle;
+ shadows_filter_param.min_angle = shadows_filter_min_angle;
+ shadows_filter_param.neighbors = shadows_filter_neighbors;
+ shadows_filter_param.window = shadows_filter_window;
+ shadows_filter_param.traverse_step = shadows_filter_traverse_step;
+ shadows_filter_param.shadows_filter_level = shadows_filter_level;
+}
\ No newline at end of file