rc_lidar
This commit is contained in:
parent
096e317353
commit
15e01f4892
63
caijian.py
Executable file
63
caijian.py
Executable file
@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env python3
|
||||
import rclpy
|
||||
from rclpy.node import Node
|
||||
from sensor_msgs.msg import PointCloud2, PointField
|
||||
import numpy as np
|
||||
import struct
|
||||
from sklearn.cluster import DBSCAN
|
||||
|
||||
class LidarFilterNode(Node):
|
||||
def __init__(self):
|
||||
super().__init__('caijian_node')
|
||||
self.publisher_ = self.create_publisher(PointCloud2, '/livox/lidar_filtered', 10)
|
||||
self.subscription = self.create_subscription(
|
||||
PointCloud2,
|
||||
'/livox/lidar/pointcloud',
|
||||
self.filter_callback,
|
||||
10)
|
||||
self.get_logger().info('caijian_node started, numpy filtering z in [1.5,3]m, distance<=12m, remove isolated points')
|
||||
|
||||
def filter_callback(self, msg):
|
||||
num_points = msg.width * msg.height
|
||||
data = np.frombuffer(msg.data, dtype=np.uint8)
|
||||
points = np.zeros((num_points, 4), dtype=np.float32) # x, y, z, intensity
|
||||
|
||||
for i in range(num_points):
|
||||
offset = i * msg.point_step
|
||||
x = struct.unpack_from('f', data, offset)[0]
|
||||
y = struct.unpack_from('f', data, offset + 4)[0]
|
||||
z = struct.unpack_from('f', data, offset + 8)[0]
|
||||
intensity = struct.unpack_from('f', data, offset + 12)[0]
|
||||
points[i] = [x, y, z, intensity]
|
||||
|
||||
z_mask = (points[:,2] >= 1.5) & (points[:,2] <= 3.0)
|
||||
dist_mask = np.linalg.norm(points[:,:3], axis=1) <= 12.0
|
||||
mask = z_mask & dist_mask
|
||||
filtered_points = points[mask]
|
||||
|
||||
# 使用DBSCAN去除孤立点
|
||||
if filtered_points.shape[0] > 0:
|
||||
clustering = DBSCAN(eps=0.3, min_samples=5).fit(filtered_points[:,:3])
|
||||
core_mask = clustering.labels_ != -1
|
||||
filtered_points = filtered_points[core_mask]
|
||||
|
||||
fields = [
|
||||
PointField(name='x', offset=0, datatype=PointField.FLOAT32, count=1),
|
||||
PointField(name='y', offset=4, datatype=PointField.FLOAT32, count=1),
|
||||
PointField(name='z', offset=8, datatype=PointField.FLOAT32, count=1),
|
||||
PointField(name='intensity', offset=12, datatype=PointField.FLOAT32, count=1),
|
||||
]
|
||||
filtered_points_list = filtered_points.tolist()
|
||||
import sensor_msgs_py.point_cloud2 as pc2
|
||||
filtered_msg = pc2.create_cloud(msg.header, fields, filtered_points_list)
|
||||
self.publisher_.publish(filtered_msg)
|
||||
|
||||
def main(args=None):
|
||||
rclpy.init(args=args)
|
||||
node = LidarFilterNode()
|
||||
rclpy.spin(node)
|
||||
node.destroy_node()
|
||||
rclpy.shutdown()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
75
pcd2pgm.py
Executable file
75
pcd2pgm.py
Executable file
@ -0,0 +1,75 @@
|
||||
import rclpy
|
||||
from rclpy.node import Node
|
||||
from sensor_msgs.msg import PointCloud2
|
||||
from nav_msgs.msg import OccupancyGrid
|
||||
import numpy as np
|
||||
import struct
|
||||
import time
|
||||
|
||||
class PointCloudToGrid(Node):
|
||||
def __init__(self):
|
||||
super().__init__('pointcloud_to_grid')
|
||||
self.subscription = self.create_subscription(
|
||||
PointCloud2,
|
||||
'/livox/lidar_filtered',
|
||||
self.pointcloud_callback,
|
||||
10)
|
||||
self.publisher = self.create_publisher(OccupancyGrid, '/lidar_grid', 10)
|
||||
self.grid_size = 2000
|
||||
self.resolution = 0.02
|
||||
self.origin_x = -20.0
|
||||
self.origin_y = -20.0
|
||||
self.points_buffer = []
|
||||
self.last_header = None
|
||||
# 定时器每0.5秒触发一次
|
||||
self.timer = self.create_timer(0.5, self.publish_grid)
|
||||
|
||||
def pointcloud_callback(self, msg):
|
||||
points = self.pointcloud2_to_xyz_array(msg)
|
||||
self.points_buffer.append(points)
|
||||
self.last_header = msg.header # 保存最新header用于地图消息
|
||||
|
||||
def publish_grid(self):
|
||||
if not self.points_buffer:
|
||||
return
|
||||
# 合并0.5秒内所有点
|
||||
all_points = np.concatenate(self.points_buffer, axis=0)
|
||||
grid = np.zeros((self.grid_size, self.grid_size), dtype=np.int8)
|
||||
for x, y, z in all_points:
|
||||
if z < 2.0:
|
||||
ix = int((x - self.origin_x) / self.resolution)
|
||||
iy = int((y - self.origin_y) / self.resolution)
|
||||
if 0 <= ix < self.grid_size and 0 <= iy < self.grid_size:
|
||||
grid[iy, ix] = 100
|
||||
grid_msg = OccupancyGrid()
|
||||
if self.last_header:
|
||||
grid_msg.header = self.last_header
|
||||
grid_msg.info.resolution = self.resolution
|
||||
grid_msg.info.width = self.grid_size
|
||||
grid_msg.info.height = self.grid_size
|
||||
grid_msg.info.origin.position.x = self.origin_x
|
||||
grid_msg.info.origin.position.y = self.origin_y
|
||||
grid_msg.data = grid.flatten().tolist()
|
||||
self.publisher.publish(grid_msg)
|
||||
self.points_buffer.clear() # 清空缓存
|
||||
|
||||
def pointcloud2_to_xyz_array(self, cloud_msg):
|
||||
# 解析 PointCloud2 数据为 numpy 数组
|
||||
fmt = 'fff' # x, y, z
|
||||
point_step = cloud_msg.point_step
|
||||
data = cloud_msg.data
|
||||
points = []
|
||||
for i in range(0, len(data), point_step):
|
||||
x, y, z = struct.unpack_from(fmt, data, i)
|
||||
points.append([x, y, z])
|
||||
return np.array(points)
|
||||
|
||||
def main(args=None):
|
||||
rclpy.init(args=args)
|
||||
node = PointCloudToGrid()
|
||||
rclpy.spin(node)
|
||||
node.destroy_node()
|
||||
rclpy.shutdown()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in New Issue
Block a user