feat: add PnP laser solving and update 0xA5 frame to 4-float protocol

- Integrate PnP rectangle pose estimation + laser world coordinate computation from scripts/calibrate/laser_pnp.py
- Publish normalized measurement (laser/RECT) and reference (rect center) via Float32MultiArray
- Update gimbal 0xA5 frame to 18-byte format: measure_x, ref_x, measure_y, ref_y
- Add camera calibration, laser line params, and RECT_L/W constants
- Add corner ordering (TL/BL/BR/TR), SOLVEPNP_IPPE, and pose/laser visualization overlay
- Remove standalone vision_example.py (superseded by ROS2 nodes)
- Add scripts/calibrate/ with calibration and PnP tools
This commit is contained in:
dev01
2026-06-03 22:38:51 +08:00
parent 0340d40b84
commit fd3d6b7ab5
10 changed files with 2549 additions and 81 deletions
+13 -11
View File
@@ -1,4 +1,4 @@
# 云台通信协议指南
# 上位机通信协议指南
## 串口配置
@@ -15,37 +15,39 @@
| 帧头 | 长度 | 用途 |
|---|---|---|
| 0xA5 | 10 | 自动/视觉追踪数据 |
| 0xA6 | 11 | 手动控制数据 |
| 0xA5 | 18 | 自动/视觉追踪数据 |
| 0xA6 | 10 | 手动控制数据 |
| 0xA7 | 3 | 命令 |
| 0xA8 | 50 | 调试调参数据 |
---
## 1. 自动/视觉追踪数据帧 0xA5 (10 字节)
## 1. 自动/视觉追踪数据帧 0xA5 (18 字节)
**用途**: 视觉识别完成后持续发送跟踪误差。
**用途**: 视觉识别完成后持续发送目标测量值和参考值。固件侧 PID 内部计算误差 (ref - measure)。
```
[SOF:0xA5][error_x:4][error_y:4][checksum:1]
[SOF:0xA5][measure_x:4][ref_x:4][measure_y:4][ref_y:4][checksum:1]
```
| 偏移 | 长度 | 类型 | 含义 |
|---|---|---|---|
| 0 | 1 | uint8 | 帧头 0xA5 |
| 1 | 4 | float | 归一化 X 轴误差 |
| 5 | 4 | float | 归一化 Y 轴误差 |
| 9 | 1 | uint8 | checksum |
| 1 | 4 | float | X 轴测量值 (视觉检测目标位置) |
| 5 | 4 | float | X 轴参考值 (期望目标位置) |
| 9 | 4 | float | Y 轴测量值 (视觉检测目标位置) |
| 13 | 4 | float | Y 轴参考值 (期望目标位置) |
| 17 | 1 | uint8 | checksum |
**Python 写入示例**:
```python
import struct
def send_auto_tracking(ser, error_x: float, error_y: float):
def send_auto_tracking(ser, measure_x: float, ref_x: float, measure_y: float, ref_y: float):
data = bytearray()
data.append(0xA5)
data.extend(struct.pack('<ff', error_x, error_y))
data.extend(struct.pack('<ffff', measure_x, ref_x, measure_y, ref_y))
checksum = sum(data) & 0xFF
data.append(checksum)
ser.write(data)