Initial commit

This commit is contained in:
2026-07-03 16:31:37 +07:00
commit 899c7c637d
1939 changed files with 641750 additions and 0 deletions

View File

@@ -0,0 +1,233 @@
# Olei LiDAR Sensor - Implementation Notes
## Tổng Quan
Project này cung cấp một high-performance server để nhận và phân giải dữ liệu từ Olei LiDAR Sensor (LR-1F / LR-1BS) qua giao thức UDP/IP.
## Kiến Trúc
### 1. Data Structures
#### `LidarHeader` (40 bytes)
- Struct với `StructLayout(LayoutKind.Sequential, Pack = 1)` để đảm bảo layout memory chính xác
- Chứa thông tin frame ID, protocol version, distance scale, rotation rate, error status, v.v.
- Các property helper để dễ dàng truy cập thông tin (RotationRate, IsCounterClockwise, HasError, etc.)
#### `LidarDataBlock` (8 bytes)
- Struct cho mỗi measurement point
- Chứa angle (0-35999 = 0°-359.99°), distance, signal strength
- Methods để chuyển đổi sang degrees/radians và Cartesian coordinates (X, Y)
#### `LidarDataPacket` (1240 bytes total)
- Class chứa header + 150 data blocks
- Methods để lọc và iterate qua valid data points
- Hỗ trợ conversion sang Cartesian coordinates
### 2. Parser
#### `LidarPacketParser`
- **Zero-allocation parsing** sử dụng `Span<byte>``ReadOnlySpan<byte>`
- Sử dụng `MemoryMarshal.Read<T>()` cho fast struct deserialization
- Validation methods để kiểm tra packet nhanh mà không cần parse toàn bộ
- Static class - không cần instantiation
### 3. Server
#### `OleiLidarServer`
- **Dedicated Thread** với `ThreadPriority.AboveNormal` cho receiving
- **ArrayPool<byte>** để reuse buffers, giảm GC pressure
- **ConcurrentBag** để pool LidarDataPacket objects cho reuse
- **Event-based callbacks** cho data và error handling
- Thread-safe operations với `Interlocked` cho counters
- Proper `IDisposable` implementation cho resource cleanup
## Tối Ưu Hiệu Suất
### 1. Memory Optimization
#### Buffer Pooling
```csharp
private readonly ArrayPool<byte> _bufferPool = ArrayPool<byte>.Shared;
byte[] buffer = _bufferPool.Rent(size);
// ... use buffer ...
_bufferPool.Return(buffer);
```
#### Packet Pooling (Automatic)
```csharp
private readonly ConcurrentBag<LidarDataPacket> _packetPool;
// Get from pool or create new
if (!_packetPool.TryTake(out var packet))
packet = new LidarDataPacket();
// ... use packet ...
// Automatically returned to pool after event handlers complete
// User doesn't need to call ReturnPacketToPool!
```
### 2. Zero-Allocation Parsing
#### Using Span<byte>
```csharp
public static bool TryParse(ReadOnlySpan<byte> data, LidarDataPacket packet)
{
// No allocation - direct memory access
header = MemoryMarshal.Read<LidarHeader>(data);
}
```
### 3. Thread Optimization
#### Dedicated Receive Thread
- Thread riêng biệt với priority cao chỉ cho receiving
- Tránh context switching và latency
- Non-blocking với small sleep để prevent busy-waiting
```csharp
_receiveThread = new Thread(ReceiveLoop)
{
Name = "OleiLidar-Receive",
IsBackground = true,
Priority = ThreadPriority.AboveNormal
};
```
### 4. Struct vs Class
- **Struct** cho `LidarHeader``LidarDataBlock`: Stack allocation, no GC
- **Class** cho `LidarDataPacket`: Chứa array lớn, pooling cho reuse
## Usage Pattern
### Basic Usage
```csharp
using var server = new OleiLidarServer(2368);
server.DataReceived += (sender, e) =>
{
var packet = e.Packet;
// Process data
foreach (var block in packet.GetValidDataBlocks())
{
double angle = block.GetAngleDegrees();
double distance = block.GetDistance(packet.Header.DistanceScale);
// ... process ...
}
// Packet is automatically returned to pool after handler completes
// No manual pooling needed!
};
server.Start();
```
## Performance Characteristics
### Expected Performance
- **Throughput**: > 1000 packets/second
- **Latency**: < 1ms per packet processing
- **Memory**: Minimal allocation sau warm-up (thanks to pooling)
- **CPU**: Low overhead do zero-allocation parsing
### Profiling Tips
1. Monitor `TotalPacketsReceived` vs `TotalPacketsParsed` để detect packet loss
2. Track `TotalParseErrors` để detect data corruption
3. Monitor memory usage - should be flat after initial warm-up
4. GC collections should be minimal
## Thread Safety
- Server có thể start/stop từ bất kỳ thread nào (protected by lock)
- Event callbacks được raised từ receive thread
- Statistics counters sử dụng `Interlocked` cho atomic operations
- Packet pool sử dụng `ConcurrentBag` (thread-safe)
## Error Handling
### Hardware Errors
Server tự động detect và report lỗi từ LiDAR:
- Motor fault (BIT0)
- Abnormal voltage (BIT1)
- Temperature fault (BIT2)
Access qua:
```csharp
if (packet.Header.HasError)
{
bool motorFault = packet.Header.HasMotorFault;
bool voltageFault = packet.Header.HasAbnormalVoltage;
bool tempFault = packet.Header.HasTemperatureFault;
}
```
### Network Errors
Tất cả network errors được catch và raised qua `ErrorOccurred` event.
## Best Practices
1. **Don't store packet references** - Packets are automatically pooled and reused:
```csharp
// ❌ WRONG - packet will be reused!
LidarDataPacket? stored = null;
server.DataReceived += (s, e) => { stored = e.Packet; };
// ✅ CORRECT - copy data if needed
server.DataReceived += (s, e) => {
var points = e.Packet.GetValidPoints().ToList();
};
```
2. **Process quickly** - Handler runs on receive thread, avoid long operations
3. **Subscribe to ErrorOccurred event** để monitor issues
4. **Use statistics** để track health (`GetStatistics()`)
5. **Dispose properly** để cleanup resources
## Configuration
### UDP Buffer Size
Default: 1MB receive buffer
```csharp
_udpClient.Client.ReceiveBufferSize = 1024 * 1024;
```
### Packet Pool Size
Initial: 10 packets, Max: 50 packets
Có thể adjust trong constructor nếu cần.
## Testing
### Unit Tests
Test các component riêng lẻ:
- `LidarPacketParser.TryParse()` với test data
- Header và DataBlock property accessors
- Validation logic
### Integration Tests
Test với real sensor hoặc UDP packet simulator:
```csharp
// Send test packet
using var client = new UdpClient();
byte[] testData = CreateTestPacket();
client.Send(testData, testData.Length, "localhost", 2368);
```
## Future Enhancements
1. **Async/Await Support**: Add async version of server
2. **Recording**: Add packet recording to file
3. **Replay**: Add packet replay from file
4. **Filtering**: Add built-in distance/angle filtering
5. **Visualization**: Add real-time visualization support
6. **Multi-Sensor**: Support multiple sensors simultaneously
## Dependencies
- **.NET 10.0**
- **System.Buffers** (ArrayPool)
- **System.Collections.Concurrent** (ConcurrentBag)
- **System.Net.Sockets** (UdpClient)
- **System.Runtime.InteropServices** (MemoryMarshal)
## License
Project này là một phần của RobotNet10.