Files
ASER/App/laser/Laser Manager.md
2026-03-31 23:30:33 +08:00

6.5 KiB
Raw Permalink Blame History

激光雷达管理模块 (Laser Manager) 🚀

本模块专为 STM32H7 + FreeRTOS 环境打造,用于同时驱动和解析 4 路单点激光雷达2 路连续流 STP-23L2 路文本流 ATK-MS53L1M

采用 DMA 环形缓冲 + 串口空闲中断 (IDLE) + RTOS 事件驱动 架构,彻底消灭单字节中断引起的 CPU 拥堵,是适用于机器人底盘避障与路径规划的“企业级”底层驱动。 核心特性

  1. 零中断阻塞:所有数据均由硬件 DMA 搬运CPU 仅在数据接收过半/完成或触发 IDLE 空闲时被唤醒。

  2. 免 Cache 物理隔离:基于 MPU 划分专用 .dma_buffer 特区,彻底杜绝 Cortex-M7 的 Cache 一致性导致的数据乱码或 USB 掉线问题。

  3. 极速解析算法

    • STP 协议:采用 O(1) 环形指针流式提取,0 内存搬运 (memmove)

    • ATK 协议:采用 O(1) 字符特征匹配,彻底抛弃耗时的 strstrstrtol 标准库函数。

  4. 高质量数据输出:内置 滑动中值滤波 (Median Filter),有效剔除玻璃反光、灰尘引起的突发测距尖峰,提供平滑稳定的控制级数据。

  5. 安全可靠

    • 采用 taskENTER_CRITICAL() 保护快照读取,杜绝多线程数据撕裂。

    • 严格区分中断上下文 (FROM_ISR) 与任务上下文的临界区调用。

    • 内置 HAL_UART_ErrorCallback,在遭受电磁干扰触发 ORE/FE 错误时自动重启 DMA永久防死机。


⚙️ 移植与配置指南

第一步STM32CubeMX 硬件配置

  1. MPU 设置 (极其重要)

    • 进入 Cortex-M7 -> MPU Control

    • Enable MPU

    • Region 1: Base Address = 0x30000000, Size = 32KB

    • Access Permission: ALL ACCESS PERMITTED

    • Cacheable: Disable (彻底关闭该区域的 D-Cache)

  2. 串口与 DMA 设置

    • STP 雷达 (如 USART2, UART4 - 230400bps):添加 RX DMA模式选 Circular (数据宽度 Byte)。优先级建议设为 High

    • ATK 雷达 (如 USART3, USART6 - 115200bps):添加 RX DMA模式选 Circular。优先级设为 Medium

    • NVIC:必须开启这 4 个串口的全局中断 (Global Interrupt)

第二步:链接脚本 (.ld) 配置

打开工程的链接脚本(如 STM32H743XX_FLASH.ld),在 RAM_D2 区域添加 .dma_buffer 段定义:

代码段 /* 给雷达 DMA 专门划分的免 Cache 区域 */ .dma_buffer (NOLOAD) : { . = ALIGN(32); *(.dma_buffer) (.dma_buffer) . = ALIGN(32); } >RAM_D2

第三步:中断回调接管

确保在 usart.cmain.c删除或注释掉 旧的串口接收回调,因为 laser_manager.c 底部已经重写了以下函数并接管了整个链路:

  • HAL_UART_RxCpltCallback

  • HAL_UART_RxHalfCpltCallback

  • HAL_UARTEx_RxEventCallback (用于处理 IDLE)

  • HAL_UART_ErrorCallback (用于自动恢复错误)


💻 API 使用说明

1. 数据结构概览

C typedef struct { uint16_t distance_mm; // 经过中值滤波处理后平滑的距离值 (推荐用于避障控制) uint16_t raw_distance_mm; // 传感器吐出的原始跳动距离值 (仅供调试观察) uint8_t valid; // 数据是否有效 (1:有效, 0:无效) uint8_t online; // 雷达是否在线 (未超时) uint8_t fault_code; // 故障码 (0x00:正常, 0x80:掉线超时) uint32_t update_tick_ms; // 最后一次数据刷新的系统 tick } laser_simple_data_t;

2. 初始化与任务启动

在 FreeRTOS 调度器启动前(或统一的应用初始化任务中)调用初始化接口。它会自动配置并开启 DMA同时创建一个高优先级的解析守护任务。

C #include "laser/laser_manager.h"

// 在 main.c 或 app_tasks.c 初始化阶段调用
LASER_SIMPLE_Init();

3. 数据轮询与读取 (应用层)

在你的应用周期任务中(如 100ms 测试任务或控制任务),调用 Poll 并获取快照指针:

C void AppTasks_RunLaserTestTask_Impl(void *argument) { const laser_simple_snapshot_t *snap; uint32_t print_divider = 0;

    LASER_SIMPLE_Init();

    for(;;)
    {
        // 1. 触发状态机巡检 (更新在线状态/超时)
        LASER_SIMPLE_Poll(HAL_GetTick());

        // 2. 获取绝对安全、无撕裂的全局数据快照
        snap = LASER_SIMPLE_GetSnapshot();

        // 3. 降频打印 (例如每 500ms 打印一次)
        if (++print_divider >= 5) 
        {
            print_divider = 0;
            printf("F_STP [Filter:%4umm, Raw:%4umm] Valid:%d Fault:%02X\r\n",
                   snap->ch[LASER_CH_FRONT_STP].distance_mm,
                   snap->ch[LASER_CH_FRONT_STP].raw_distance_mm,
                   snap->ch[LASER_CH_FRONT_STP].valid,
                   snap->ch[LASER_CH_FRONT_STP].fault_code);
        }

        osDelay(100); // 维持高频巡检节拍 (切勿大于雷达设定的 Timeout 时间)
    }
}

4. 便捷测距接口

如果你的小车只需要知道“前方/后方离障碍物最近是多少”,可以直接调用辅助接口:

C // 获取前/后两路雷达中,最近且有效的平滑距离值 (毫米) uint16_t front_min_dist = LASER_SIMPLE_GetFrontNearest(); uint16_t rear_min_dist = LASER_SIMPLE_GetRearNearest();


常见问题 (Troubleshooting)

Q: 烧录程序后USB 虚拟串口无法识别 (或电脑提示无法识别的 USB 设备)

A: 请检查 MPU 配置是否生效,以及链接脚本中是否正确加入了 .dma_buffer。如果 DMA 数组被编译器分配到了带有 D-Cache 的内存中USB 外设会因为内存一致性冲突而死机。

Q: 雷达数据一直是 0且终端不停输出 FaultCode 0x80

A: 0x80 代表超时掉线。请检查:

  1. 雷达硬件连线RX/TX 是否接反)。

  2. CubeMX 中 4 个串口是否正确开启了全局中断(未开启中断将无法唤醒解析任务)。

  3. 波特率是否匹配STP: 230400ATK: 115200)。

Q: 想要调整中值滤波的平滑程度?

A:laser_manager.c 顶部修改 #define FILTER_WIN_SZ 3U。改为 5U 会更平滑,但会增加几毫秒的系统响应延迟。通常 3 是最佳平衡点。