generated from hulk/gd32e23x_template_cmake_vscode
feat(VL53L4CD): 增加偏移校准支持并固化44mm安装偏移
- 新增 vl53l4cd_set_offset/get_offset/calibrate_offset - main 支持开机自动校准或启动时写回固定偏移 - 当前44mm哑光目标校准结果 offset=-9mm - 同步更新 README 与 CHANGES
This commit is contained in:
+26
-1
@@ -99,6 +99,31 @@ Src/VL53L4CD_Driver.c
|
||||
## 7. 当前已知限制
|
||||
|
||||
- 驱动只支持连续测距模式,`inter_measurement_ms` 非 0 会返回失败
|
||||
- 尚未实现距离阈值中断、Offset/Crosstalk 校准、自主低功耗模式、ULP 模式
|
||||
- 尚未实现 Crosstalk 校准、距离阈值中断、自主低功耗模式、ULP 模式
|
||||
- `DEBUG_VERBOSE` 全开时 IIC 调试打印会让 16K Flash 非常紧张,不建议常开
|
||||
- VL53L4CD 是单区传感器,不是多区测距
|
||||
|
||||
## 8. VL53L4CD 偏移校准
|
||||
|
||||
### 改动
|
||||
|
||||
- `Inc/VL53L4CD_Driver.h`:新增 `RANGE_OFFSET_MM`、`INNER_OFFSET_MM`、`OUTER_OFFSET_MM` 寄存器宏,以及偏移校准接口声明。
|
||||
- `Src/VL53L4CD_Driver.c`:
|
||||
- `vl53l4cd_set_offset()`:写入距离偏移量,寄存器值为 `offset_mm * 4`。
|
||||
- `vl53l4cd_get_offset()`:读取当前生效偏移量。
|
||||
- `vl53l4cd_calibrate_offset()`:清零偏移、热机 10 帧、采样有效测距结果,计算 `offset = 实际距离 - 平均距离` 并写回。
|
||||
- `Inc/board_config.h`:新增校准目标距离、采样次数、自动校准开关和固定偏移配置。
|
||||
- `Src/main.c`:初始化后支持自动校准或写回固定偏移。
|
||||
|
||||
### 当前校准结果
|
||||
|
||||
- 安装位置目标实际距离:44mm
|
||||
- 目标类型:橙色 3D 打印哑光件
|
||||
- 采样次数:20 次
|
||||
- 校准偏移:`-9mm`
|
||||
- 写回后串口输出稳定在约 41-47mm,多数为 44mm
|
||||
- `status: 0`,测距有效
|
||||
|
||||
### 说明
|
||||
|
||||
固定安装场景使用单点偏移校准即可。`VL53L4CD_AUTO_CALIB = CFG_ENABLE` 时每次开机自动校准,适合重新标定;校准完成后建议改为 `CFG_DISABLE`,使用 `VL53L4CD_CALIB_OFFSET_MM` 中的固定值,避免每次开机都依赖目标存在。
|
||||
|
||||
@@ -17,6 +17,12 @@
|
||||
/* 寄存器地址 */
|
||||
#define VL53L4CD_REG_I2C_SLAVE_DEVICE_ADDRESS 0x0001U
|
||||
#define VL53L4CD_REG_VHV_TIMEOUT_MACROP_LOOP_BOUND 0x0008U
|
||||
#define VL53L4CD_REG_XTALK_PLANE_OFFSET_KCPS 0x0016U
|
||||
#define VL53L4CD_REG_XTALK_X_PLANE_GRADIENT_KCPS 0x0018U
|
||||
#define VL53L4CD_REG_XTALK_Y_PLANE_GRADIENT_KCPS 0x001AU
|
||||
#define VL53L4CD_REG_RANGE_OFFSET_MM 0x001EU
|
||||
#define VL53L4CD_REG_INNER_OFFSET_MM 0x0020U
|
||||
#define VL53L4CD_REG_OUTER_OFFSET_MM 0x0022U
|
||||
#define VL53L4CD_REG_GPIO_HV_MUX_CTRL 0x0030U
|
||||
#define VL53L4CD_REG_GPIO_TIO_HV_STATUS 0x0031U
|
||||
#define VL53L4CD_REG_SYSTEM_INTERRUPT 0x0046U
|
||||
@@ -127,6 +133,30 @@ bool vl53l4cd_get_result(vl53l4cd_result_t *result);
|
||||
*/
|
||||
bool vl53l4cd_set_range_timing(uint8_t timing_budget_ms, uint32_t inter_measurement_ms);
|
||||
|
||||
/**
|
||||
* @brief 写入手动指定的距离偏移量
|
||||
* @param[in] offset_mm: 偏移量,单位 mm,可为负
|
||||
* @retval true: 成功; false: 失败
|
||||
*/
|
||||
bool vl53l4cd_set_offset(int16_t offset_mm);
|
||||
|
||||
/**
|
||||
* @brief 读取当前生效的距离偏移量
|
||||
* @param[out] offset_mm: 返回偏移量,单位 mm
|
||||
* @retval true: 成功; false: 失败
|
||||
*/
|
||||
bool vl53l4cd_get_offset(int16_t *offset_mm);
|
||||
|
||||
/**
|
||||
* @brief 以当前目标执行一次偏移校准
|
||||
* @param[in] target_distance_mm: 目标实际距离,单位 mm,范围 10..1000
|
||||
* @param[in] num_samples: 有效采样次数,范围 5..255
|
||||
* @param[out] measured_offset_mm: 计算得到的偏移量,单位 mm
|
||||
* @retval true: 校准并写入成功; false: 失败
|
||||
*/
|
||||
bool vl53l4cd_calibrate_offset(uint16_t target_distance_mm, uint16_t num_samples,
|
||||
int16_t *measured_offset_mm);
|
||||
|
||||
/**
|
||||
* @brief 读一个 8 位寄存器
|
||||
* @param[in] reg: 16 位寄存器地址
|
||||
|
||||
@@ -48,6 +48,13 @@
|
||||
#define RTT_PutChar(ch, c)
|
||||
#endif
|
||||
|
||||
/* >>>>>>>>>>>>>>>>>>>>[VL53L4CD OFFSET CALIBRATION]<<<<<<<<<<<<<<<<<<<< */
|
||||
|
||||
#define VL53L4CD_CALIB_TARGET_MM 44U // 当前安装位置的目标实际距离
|
||||
#define VL53L4CD_CALIB_SAMPLES 20U // 校准采样次数,ST 推荐 20
|
||||
#define VL53L4CD_AUTO_CALIB CFG_DISABLE // CFG_ENABLE: 每次开机自动校准; CFG_DISABLE: 使用下面固定偏移
|
||||
#define VL53L4CD_CALIB_OFFSET_MM (-9) // 校准后保存的固定偏移量,单位 mm,可为负
|
||||
|
||||
/* >>>>>>>>>>>>>>>>>>>>[RS485 MODE]<<<<<<<<<<<<<<<<<<<< */
|
||||
|
||||
#define RS485_MODE CFG_ENABLE // CFG_DISABLE: RS485 off; CFG_ENABLE: RS485 on
|
||||
|
||||
@@ -60,6 +60,10 @@
|
||||
| `DEBUG_VERBOSE` | `CFG_DISABLE` | 关闭 IIC 调试打印和启动 I2C 扫描 |
|
||||
| `COM_DEBUG` | `CFG_DISABLE` | 关闭命令帧调试打印 |
|
||||
| `SEGGER_RTT_DETECTION` | `CFG_DISABLE` | 关闭 SEGGER RTT |
|
||||
| `VL53L4CD_CALIB_TARGET_MM` | `44` | 当前安装位置的目标实际距离 |
|
||||
| `VL53L4CD_CALIB_SAMPLES` | `20` | 校准采样次数 |
|
||||
| `VL53L4CD_AUTO_CALIB` | `CFG_DISABLE` | 开机自动校准开关 |
|
||||
| `VL53L4CD_CALIB_OFFSET_MM` | `-9` | 当前固定的距离偏移量 |
|
||||
| `RS485_MODE` | `CFG_ENABLE` | 使用 RS485 串口输出 |
|
||||
| `SOFTWARE_IIC` | `CFG_DISABLE` | 使用硬件 I2C |
|
||||
|
||||
@@ -132,9 +136,29 @@ Distance: 830 mm | status: 0 | signal: 1128 kcps | ambient: 72 kcps | sigma: 3 m
|
||||
| `vl53l4cd_clear_interrupt()` | 清除测距完成中断 |
|
||||
| `vl53l4cd_get_result()` | 读取并解析测距结果 |
|
||||
| `vl53l4cd_set_range_timing()` | 设置 10-200ms 时序预算,当前仅支持连续模式 |
|
||||
| `vl53l4cd_set_offset(offset_mm)` | 写入手动指定的距离偏移量 |
|
||||
| `vl53l4cd_get_offset(&offset_mm)` | 读取当前生效的距离偏移量 |
|
||||
| `vl53l4cd_calibrate_offset(target_mm, samples, &offset)` | 对当前目标执行偏移校准并写回 |
|
||||
| `vl53l4cd_read_reg8/16()` | 读 8/16 位寄存器 |
|
||||
| `vl53l4cd_write_reg8/16()` | 写 8/16 位寄存器 |
|
||||
|
||||
## 偏移校准
|
||||
|
||||
VL53L4CD 出厂带有默认偏移,但器件之间存在差异,固定安装场景建议做一次单点校准。
|
||||
|
||||
当前安装位置的目标距离为 44mm,已通过 20 帧有效采样完成校准,校准得到的偏移量为 `-9mm`。固件在 `vl53l4cd_init()` 后调用 `vl53l4cd_set_offset(VL53L4CD_CALIB_OFFSET_MM)` 写回,因此每次上电都会保持校准结果。
|
||||
|
||||
需要重新校准时:
|
||||
|
||||
1. 把目标放在已知距离,例如 44mm。
|
||||
2. 将 `Inc/board_config.h` 中 `VL53L4CD_AUTO_CALIB` 改为 `CFG_ENABLE`。
|
||||
3. 上电后串口会打印 `VL53L4CD offset calibrated: X mm`。
|
||||
4. 把打印出的 `X` 填入 `VL53L4CD_CALIB_OFFSET_MM`,再将 `VL53L4CD_AUTO_CALIB` 改回 `CFG_DISABLE`。
|
||||
|
||||
也可以直接调用 `vl53l4cd_calibrate_offset()`,该函数会先清零偏移、热机 10 帧,再统计有效测距样本并计算 `offset = 实际距离 - 平均距离`,最后写入 `RANGE_OFFSET_MM (0x001E)`。
|
||||
|
||||
注意:单点偏移只修正当前固定距离的绝对误差。近距离高反射金属目标存在非线性,建议使用哑光目标。
|
||||
|
||||
### 修改时序预算
|
||||
|
||||
在 `Src/VL53L4CD_Driver.c` 的 `vl53l4cd_init()` 末尾:
|
||||
@@ -205,7 +229,7 @@ bss 2012
|
||||
## 已知限制
|
||||
|
||||
- 驱动只支持连续测距模式
|
||||
- 尚未实现距离阈值中断、Offset/Crosstalk 校准、自主低功耗模式、ULP 模式
|
||||
- 尚未实现 Crosstalk 校准、距离阈值中断、自主低功耗模式、ULP 模式
|
||||
- VL53L4CD 是单区传感器,不是多区测距
|
||||
- `DEBUG_VERBOSE` 全开时 IIC 调试打印会让 Flash 非常紧张
|
||||
|
||||
|
||||
@@ -94,6 +94,26 @@ bool vl53l4cd_clear_interrupt(void)
|
||||
return vl53l4cd_write_reg8(VL53L4CD_REG_SYSTEM_INTERRUPT_CLEAR, 0x01U);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 等待新的测距结果就绪
|
||||
* @param[in] timeout_ms: 超时时间,单位 ms
|
||||
* @retval true: 结果就绪; false: 超时或读取失败
|
||||
*/
|
||||
static bool vl53l4cd_wait_for_data_ready(uint32_t timeout_ms)
|
||||
{
|
||||
uint32_t elapsed_ms = 0U;
|
||||
|
||||
while (elapsed_ms < timeout_ms) {
|
||||
if (vl53l4cd_data_ready()) {
|
||||
return true;
|
||||
}
|
||||
delay_ms(1);
|
||||
elapsed_ms++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool vl53l4cd_get_result(vl53l4cd_result_t *result)
|
||||
{
|
||||
static const uint8_t status_rtn[24] = {
|
||||
@@ -191,6 +211,95 @@ bool vl53l4cd_set_range_timing(uint8_t timing_budget_ms, uint32_t inter_measurem
|
||||
(uint16_t)((uint16_t)ms_byte << 8 | ls_byte));
|
||||
}
|
||||
|
||||
bool vl53l4cd_set_offset(int16_t offset_mm)
|
||||
{
|
||||
uint16_t reg_value;
|
||||
|
||||
reg_value = (uint16_t)((int16_t)offset_mm * 4);
|
||||
|
||||
return vl53l4cd_write_reg16(VL53L4CD_REG_RANGE_OFFSET_MM, reg_value) &&
|
||||
vl53l4cd_write_reg16(VL53L4CD_REG_INNER_OFFSET_MM, 0U) &&
|
||||
vl53l4cd_write_reg16(VL53L4CD_REG_OUTER_OFFSET_MM, 0U);
|
||||
}
|
||||
|
||||
bool vl53l4cd_get_offset(int16_t *offset_mm)
|
||||
{
|
||||
uint16_t reg_value;
|
||||
int16_t raw;
|
||||
|
||||
if (offset_mm == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (!vl53l4cd_read_reg16(VL53L4CD_REG_RANGE_OFFSET_MM, ®_value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
raw = (int16_t)reg_value;
|
||||
*offset_mm = (int16_t)(raw / 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vl53l4cd_calibrate_offset(uint16_t target_distance_mm, uint16_t num_samples,
|
||||
int16_t *measured_offset_mm)
|
||||
{
|
||||
vl53l4cd_result_t result;
|
||||
int32_t distance_sum = 0;
|
||||
uint16_t valid_samples = 0;
|
||||
uint16_t i;
|
||||
int16_t average_distance;
|
||||
int16_t offset;
|
||||
|
||||
if (measured_offset_mm == NULL ||
|
||||
target_distance_mm < 10U || target_distance_mm > 1000U ||
|
||||
num_samples < 5U || num_samples > 255U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vl53l4cd_stop_ranging() ||
|
||||
!vl53l4cd_set_offset(0) ||
|
||||
!vl53l4cd_start_ranging()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 热机 10 帧,丢弃 */
|
||||
for (i = 0U; i < 10U; i++) {
|
||||
if (!vl53l4cd_wait_for_data_ready(VL53L4CD_DATA_TIMEOUT_MS)) {
|
||||
return false;
|
||||
}
|
||||
(void)vl53l4cd_clear_interrupt();
|
||||
(void)vl53l4cd_get_result(&result);
|
||||
}
|
||||
|
||||
/* 统计有效测距样本 */
|
||||
for (i = 0U; i < num_samples; i++) {
|
||||
if (!vl53l4cd_wait_for_data_ready(VL53L4CD_DATA_TIMEOUT_MS)) {
|
||||
return false;
|
||||
}
|
||||
(void)vl53l4cd_clear_interrupt();
|
||||
if (vl53l4cd_get_result(&result) &&
|
||||
result.range_status == VL53L4CD_STATUS_RANGE_VALID) {
|
||||
distance_sum += (int32_t)result.distance_mm;
|
||||
valid_samples++;
|
||||
}
|
||||
}
|
||||
|
||||
(void)vl53l4cd_stop_ranging();
|
||||
|
||||
if (valid_samples == 0U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
average_distance = (int16_t)(distance_sum / (int32_t)valid_samples);
|
||||
offset = (int16_t)((int16_t)target_distance_mm - average_distance);
|
||||
|
||||
if (!vl53l4cd_set_offset(offset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*measured_offset_mm = offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vl53l4cd_init(void)
|
||||
{
|
||||
uint16_t model_id = 0U;
|
||||
|
||||
+13
@@ -78,6 +78,19 @@ int main(void)
|
||||
#endif
|
||||
|
||||
if (vl53l4cd_init()) {
|
||||
#if VL53L4CD_AUTO_CALIB == CFG_ENABLE
|
||||
int16_t cal_offset = 0;
|
||||
|
||||
if (vl53l4cd_calibrate_offset(VL53L4CD_CALIB_TARGET_MM,
|
||||
VL53L4CD_CALIB_SAMPLES,
|
||||
&cal_offset)) {
|
||||
printf("VL53L4CD offset calibrated: %d mm\r\n", cal_offset);
|
||||
} else {
|
||||
printf("VL53L4CD offset calibration failed\r\n");
|
||||
}
|
||||
#else
|
||||
(void)vl53l4cd_set_offset(VL53L4CD_CALIB_OFFSET_MM);
|
||||
#endif
|
||||
vl53l4cd_start_ranging();
|
||||
printf("VL53L4CD ready\r\n");
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user