2026-06-25 16:35:39 +07:00
2026-06-25 16:35:39 +07:00

Olei Lidar Driver

Driver UDP độc lập (C++17, không phụ thuộc CMake/ROS) cho lidar Olei. Tự nhận diện họ giao thức (Family A/B) theo từng gói, hỗ trợ chạy nhiều lidar song song.

Kiến trúc

File Vai trò
olei_lidar.hpp API: Point, Scan, ModelConfig, class Driver
olei_lidar.cpp Parse Family A (0xFAF0) & Family B (0xFEF0), CRC, gom scan
example.cpp Demo 1 lidar, recv_scan() blocking
test_dual.cpp Demo 2 lidar song song (2 thread)

Ba họ giao thức:

  • Family A (0xFAF0) — VB/VF/LR-1F. Header 20B + block 3B/điểm. Có CRC32.
  • Family B (0xFEF0) — LR-1BS5/LR-1BS2. Header 40B (preamble 0x010F + frame id ở offset [2-3], chuỗi tên model ASCII ở offset [7-17)) + block 8B/điểm.
  • Family C / protocol V3 (0xFEAC) — GS1-5. Header 48B, block 2/4B/điểm tùy byte Types. Port từ driver C# OleiGS15Driver.cs (RobotNet10.RobotApp), CHƯA verify bằng phần cứng GS1-5 thật (không có thiết bị để sniff) — chỉ test bằng packet giả lập tự dựng theo đúng cấu trúc header.

Góc điểm đo (Point::angle_deg) luôn ở hệ có dấu [-180, 180], 0 = phía trước, dương = bên trái.

Kết nối lidar

Mạng tham chiếu trên host này (/home/robotics):

eth0: 192.168.100.100/24
  ├─ front (scan_1): DeviceIp 192.168.100.11, DevicePort 2368
  └─ rear  (scan_2): DeviceIp 192.168.100.12, DevicePort 2369

(Khớp với RobotApp/RobotNet10.RobotApp/appsettings.json, các mục Olei-front/Olei-rear.)

Kiểm tra kết nối trước khi test:

ip -4 addr show eth0          # phải thấy inet 192.168.100.100/24
ping -c1 192.168.100.11        # front
ping -c1 192.168.100.12        # rear

Lưu ý quan trọng: nếu RobotNet10.RobotApp đang chạy, nó bind sẵn port 2368/2369 (không bật SO_REUSEPORT) → driver standalone sẽ bind lỗi (Khong mo duoc socket... interface khong ton tai?). Kiểm tra ai đang giữ port:

ss -lunp | grep -E '2368|2369'

Build

Không có CMakeLists, chỉ dùng g++ thuần:

g++ -std=c++17 -O2 -pthread -Wall -Wextra -o test_dual test_dual.cpp olei_lidar.cpp
g++ -std=c++17 -O2 -pthread -Wall -Wextra -o example   example.cpp   olei_lidar.cpp

Test thử

2 lidar song song

./test_dual

In ra 5 scan mỗi bên, kèm số điểm, timestamp, error status, và model đã tự dò được (model=...).

1 lidar

Sửa model/IP/port trong example.cpp rồi build lại, hoặc gọi trực tiếp:

olei::Driver drv(olei::MODEL_AUTO, "192.168.100.100", 2369);
drv.open();
olei::Scan scan;
drv.recv_scan(scan, 2000);

Sniff packet thô (debug khi nghi ngờ offset header)

python3 - <<'EOF'
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("192.168.100.100", 2369))   # đổi port theo lidar cần xem
data, addr = s.recvfrom(4096)
print("from", addr, "len", len(data))
print(data[:40].hex(' '))
EOF

Luôn ưu tiên capture thật hơn là tin comment trong code — comment mô tả ý định lúc viết, không phải offset đã verify trên thiết bị thật.

Chọn ModelConfig

Constant FOV (deg, có dấu) Khi dùng
MODEL_VB -135…135 2D 270°, Family A
MODEL_VF -180…180 2D 360°, Family A
MODEL_LR1F -180…180 2D 360° 50m, Family A
MODEL_LR1BS5 -180…180 2D 360°, Family B
MODEL_LR16F -135…135 3D 16-line
MODEL_GS15 -180…180 2D 360°, Family C/V3 — chưa verify hardware thật
MODEL_AUTO -180…180 (mặc định, có thể tự thu hẹp) Không biết trước model

MODEL_AUTO: chỉ có tác dụng tự-dò với Family B (đọc chuỗi tên model trong header). Driver luôn lưu lại tên thật đọc từ packet (vd "OLELR-1BS5", "OLELR-1BS2") — gọi drv.detected_model() để xem (trả về "AUTO" nếu chưa nhận gói Family B nào). FOV chỉ tự thu hẹp khi tên đó khớp một entry trong kModelTable (olei_lidar.cpp); nếu không khớp, FOV giữ nguyên mặc định 360° (-180..180, không mất điểm) — an toàn nhưng có thể giữ lại điểm ngoài FOV thật của thiết bị nếu thiết bị đó không quét tròn.

Family A không mang chuỗi tên model trong packet, nên MODEL_AUTO trên thiết bị Family A cũng giữ nguyên FOV rộng — phải chỉ định model cụ thể (VD MODEL_VB) nếu muốn thu hẹp FOV cho thiết bị góc hẹp.

Description
No description provided
Readme 556 KiB