第一章为什么选 STM32H743无人船主控芯片选型实战做无人船的第一步不是写代码是选芯片。芯片选错了后面全是坑。1. 一张图看懂选型困局2024 年我要做一台能自主航行的无人船。需求很明确必须能做的事: ✅ 实时采集 8 路传感器数据 (GPS/IMU/雷达/LiDAR/遥控器/...) ✅ 运行路径规划算法 (D* Lite DWA, 实时规划绕开障碍) ✅ 输出 PWM/CAN 控制推进器 ✅ 4G 联网 地面站通信 ✅ 看门狗保命 (死机了能自己重启) 可选加分: ○ 运行轻量 CNN 做水面目标识别 ○ 多船协同编队 ○ OTA 远程升级摆在面前三条路方案代表芯片单价上手难度A: 单片机裸跑STM32H743¥40★★★B: Linux 伴机树莓派 CM4 STM32¥400★★★★★C: 纯 Linux全志 T113 / NXP i.MX¥80★★★★2. 为什么我选了方案 A而且没后悔2.1 Linux 伴机方案 — 看着美好坑太深刚开始我也心动过方案 B——STM32 做实时控制树莓派跑路径规划和 AI。画了个很漂亮的架构图┌─────────────┐ UART/SPI ┌──────────────┐ │ 树莓派 CM4 │◄──────────────►│ STM32H743 │ │ │ │ │ │ 路径规划 │ │ PID控制 │ │ 视觉识别 │ │ 传感器采集 │ │ 4G通信 │ │ 推进器输出 │ │ 地面站 │ │ 看门狗 │ └─────────────┘ └──────────────┘在纸上画了一个月实际动手一周就放弃了。原因坑 1两块芯片之间的通信是瓶颈路径规划需要 LiDAR 数据240Hz 帧率、30m 距离、每个点 0.357°。树莓派上跑完 DWA结果通过串口传给 STM32。多了几十毫秒延迟。船以 2m/s 运动50ms 延迟 10cm 误差。撞浮标只需要一次延迟。坑 2电源系统复杂度翻倍两块芯片、两路供电、上电时序、掉电保护。船在海上颠簸多一个连接点多一个故障点。坑 3我一个人开发维护两套代码库STM32 写 C、树莓派写 Python/C。调试时两个终端来回切。每次改通信协议两边都要改。坑 4成本无人船不是无人机船体推进器电池已经很贵了。再加树莓派整机成本上一个台阶。2.2 纯 Linux 方案 — 实时性是个硬伤全志 T113 跑 Linux RT-Preempt 补丁理论上能到百微秒级实时响应。但中断延迟不确定Linux 内核可能在任意时刻关中断推进器的 PWM 输出必须 50Hz 精准Linux 做不到硬件定时器的抖动水平。启动时间Linux 从加电到飞控就绪要 5-10 秒单片机 200ms 就起来了。船下水前通电等着很正常但万一海上重启10 秒够船飘出多远没有成熟生态Pixhawk/CUAV 的硬件生态围绕 STM32 建了十年。用 Linux 意味着传感器驱动全得自己写。2.3 纯单片机方案 — 刚好够用的上限STM32H743 作为 Cortex-M7 旗舰关键参数CPU: 480 MHz (双发射, ~2 DMIPS/MHz) RAM: 996 KB SRAM (DTCM 128K AXI 512K SRAM1/2/3/4) Flash: 2 MB FPU: 双精度硬浮点 DSP: SIMD 指令集 DMAMUX: 16通道灵活路由 OS: FreeRTOS (抢占式, 1000Hz tick)480MHz 做路径规划够不够实测数据我们的项目操作 周期/秒 CPU% ───────────────────────────────────────── EKF 导航融合 550K 0.1% PID 混控 (50Hz) 200K 0.04% D* Lite 全局规划 (1Hz) 100K 0.02% DWA 局部规划 (10Hz, 400轨迹) 4,920K 0.89% LiDAR Bresenham 射线 (M10) 1,100K 0.2% 雷达栅格融合 (33Hz) 825K 0.15% 8路串口 网络协议栈 1,500K 0.27% FreeRTOS 内核 600K 0.11% ───────────────────────────────────────── 稳态合计 ~9,800K ~1.8%只有 1.8%远没到 H743 的极限。有人会说480MHz 才用 1.8% 是因为你们算法太简单。不是的——是因为架构上做了正确的选择代价地图放在 DTCM。DTCM 是 CPU 的紧耦合内存零等待周期。DWA 每秒查 12 万次栅格如果放普通 SRAM 上每次访问多等 3-5 个周期CPU 占用直接翻倍。sin/cos 用查表不用 FPU。DWA 每条轨迹 30 步每步算一次 sin 和 cos。400 条轨迹 × 30 步 × 2 24000 次三角函数。如果调sinf()每次 ~28 周期硬件 FPU。我们预计算了 360 条目的查表查一次 ~5 周期。省了 5 倍。DLite 是增量更新*。障碍物变了不用全量重搜 6400 个节点只更新受影响的 25 个5×5 邻域。1Hz 重规划几乎不占 CPU。这些优化在 Linux 代码里很难做——因为 Linux 的设计哲学是通用不是极致。3. 真正重要的不是 CPU 频率选 STM32H7 系列最关键的理由其实是这三个3.1 内存架构Cortex-M7 内核 │ ├── ITCM (64KB, 零等待) ← CPU 直连, 跑中断服务最快 ├── DTCM (128KB, 零等待) ← CPU 直连, 放高频数据 │ └── AXI 总线矩阵 ──┬── AXI SRAM (512KB) ← DMA 缓冲区 ├── SRAM1 (128KB) ├── SRAM2 (128KB) ├── SRAM3 (32KB) └── SRAM4 (64KB)H7 有两个零等待内存ITCM 和 DTCMCPU 访问它们没有任何等待周期。代价地图、EKF 状态、任务栈——全部放 DTCM。DWA 每秒查 12 万次栅格全部零等待。ESP32 也有 520KB SRAM但分区分得碎而且没有 CPU 紧耦合内存。查栅格的延迟是 H743 的 3-5 倍。3.2 DMAMUX — 8 路串口并发不打架这是 H7 系列独有的杀手特性。在 F4 上每个串口绑定固定的 DMA 流串口多了必然冲突。H7 有 DMAMUX——16 个通道可以灵活路由任意外设到任意 DMA 流// H7: 8个串口各自独占一个 DMA 通道, 互不干扰[COM1]{DMA1_Stream0,DMAREQ_ID_USART1_RX,41},[COM2]{DMA1_Stream1,DMAREQ_ID_USART2_RX,43},[COM3]{DMA1_Stream2,DMAREQ_ID_USART3_RX,45},[COM4]{DMA1_Stream3,DMAREQ_ID_UART4_RX,63},[COM5]{DMA1_Stream4,DMAREQ_ID_UART5_RX,65},[COM6]{DMA1_Stream5,DMAREQ_ID_USART6_RX,71},[COM7]{DMA1_Stream6,DMAREQ_ID_UART7_RX,79},[COM8]{DMA1_Stream7,DMAREQ_ID_UART8_RX,81},无人船 8 路串口同时收发——GPS (COM3, 10Hz)、雷达 (COM4, 33Hz)、LiDAR (COM6, 460800bps/240Hz帧率)、遥控器 (COM2, 50Hz)、4G 模块 (LPUART1)——没有 DMAMUX 根本扛不住。3.3 生态ST 的 HAL 库虽然被骂臃肿但对于一个人开发来说它是救命稻草。不用手写寄存器不用对着 3000 页参考手册查位定义。配一个 I2C 三行代码HAL_I2C_Init(hi2c4);HAL_I2C_Master_Transmit(hi2c4,addr,data,len,timeout);加上 Keil MDK 的调试体验——J-Link 接上就能看变量、寄存器、调用栈。一个人开发快速定位 bug 比省几 KB 代码重要得多。4. 为什么从 H723 升级到 H743我们一开始用的是 H723ZG后来换了 H743ZITx。不是因为 CPU 不够快都是 480MHz 级别而是因为内存资源H723ZGH743ZITxAXI SRAM128 KB512 KBFlash1 MB2 MBFDCAN3 路2 路UART10 路8 路128KB AXI SRAM 放完 DMA 缓冲 FreeRTOS Heap 通用数据空间非常紧。H743 的 512KB AXI 让所有内存焦虑都消除了。外设少了H723 多了 FDCAN3、I2C5、UART9/10但我们用不到那些多余的。芯片迁移花了一天。因为我们项目里所有硬件定义集中在cc_h7_def.h一个文件里——换芯片只改这一个文件和.sct分散加载脚本。核心控制代码一行没动。5. 选型总结场景 推荐方案 ────────────────────────────────────────── 做产品、有团队、跑视觉 Linux 伴机 (CM4STM32) 做科研、要发论文、不管功耗 NVIDIA Jetson 做开源、一个人、先跑稳再跑快 STM32H743 ← 我们 做低端玩具船、几块钱的成本 ESP32我们的选择不是最好的是在当前约束下最优解。一个人开发 → 不要搞分布式系统伴机方案两块芯片通信是额外的复杂度。先跑稳再跑快 → 不要过早优化硬件H743 还有 98% CPU 闲置。要开源 → 选最大的生态系统ST 的社区和文档是国产芯片比不了的。6. 本章代码看看我们怎么初始化芯片// main.c — 精简版intmain(void){bsp_init();// ① 时钟 480MHz GPIO DMA 外设path_planner_init(...);// ② 代价地图 D* Lite DWA 初始化radar_task_init();// ③ MR72 雷达采集任务lidar_task_init();// ④ M10 LiDAR 采集任务// ... 创建其他 15 个 FreeRTOS 任务 ...vTaskStartScheduler();// ⑤ 启动调度器 (永不返回)}// cc_h7_def.h — 换芯片只改这里// H743 AXI SRAM: 512KB// DTCM: 128KB// 引脚定义全部集中在这里#defineCAN1_RX_PORTGPIOD#defineLIDAR_UART_PORTCOM6#defineRADAR_UART_PORTCOM47. 踩过的坑坑 1H723 和 H743 的外设不一样H723 有 3 路 FDCAN、5 路 I2C、10 路 UART。H743 只有 2 路 FDCAN、4 路 I2C、8 路 UART。我们把 H723 的代码直接拿到 H743 编译31 个错误——全是FDCAN3、I2C5、UART9、USART10不存在。教训换芯片前先对比数据手册的外设章节别想当然都是 H7 应该一样。坑 2代价地图放 AXI SRAM 上 DWA 慢 3.6 倍一开始我们把代价地图放在AXI SRAM因为空间大。DWA 规划一帧从 ~0.5ms 变成 ~1.8ms——虽然看起来不多但 DWA 跑 10Hz每个周期只有 100ms 时间窗突然多占了 1.3ms 会让其他任务被挤压。换成 DTCM 后恢复正常。H7 的 DTCM 是最宝贵的资源DWA 必须用。坑 3LiDAR 天气检测死锁我们的 M10 LiDAR 每帧只有 42 个点。但传感器融合代码里有个LIDAR_TYPICAL_MIN 100——意思是至少 100 个有效点才算建立了天气基线。结果 M10 永远达不到 100天气自适应功能彻底死锁。改成 30 就好了。这种硬编码常量是给之前设计的 RPLIDAR S2E2000 点/帧用的换 LiDAR 型号必须同步更新。8. 下一章预告第二章从 main.c 到 FreeRTOS — 嵌入式实时系统启动全流程bsp_init 里到底初始化了什么15 个 FreeRTOS 任务怎么创建、怎么分配优先级、怎么避免互相踩踏看门狗怎么监视所有任务的心跳本文是《从零搭建无人船控制系统》系列第一篇。项目地址[煜坤 YuKun]开源准备中。作者一个人、一台电脑、一条船。慢就是快走稳每一步。
《从零搭建无人船控制系统-第一篇》
发布时间:2026/7/8 10:14:14
第一章为什么选 STM32H743无人船主控芯片选型实战做无人船的第一步不是写代码是选芯片。芯片选错了后面全是坑。1. 一张图看懂选型困局2024 年我要做一台能自主航行的无人船。需求很明确必须能做的事: ✅ 实时采集 8 路传感器数据 (GPS/IMU/雷达/LiDAR/遥控器/...) ✅ 运行路径规划算法 (D* Lite DWA, 实时规划绕开障碍) ✅ 输出 PWM/CAN 控制推进器 ✅ 4G 联网 地面站通信 ✅ 看门狗保命 (死机了能自己重启) 可选加分: ○ 运行轻量 CNN 做水面目标识别 ○ 多船协同编队 ○ OTA 远程升级摆在面前三条路方案代表芯片单价上手难度A: 单片机裸跑STM32H743¥40★★★B: Linux 伴机树莓派 CM4 STM32¥400★★★★★C: 纯 Linux全志 T113 / NXP i.MX¥80★★★★2. 为什么我选了方案 A而且没后悔2.1 Linux 伴机方案 — 看着美好坑太深刚开始我也心动过方案 B——STM32 做实时控制树莓派跑路径规划和 AI。画了个很漂亮的架构图┌─────────────┐ UART/SPI ┌──────────────┐ │ 树莓派 CM4 │◄──────────────►│ STM32H743 │ │ │ │ │ │ 路径规划 │ │ PID控制 │ │ 视觉识别 │ │ 传感器采集 │ │ 4G通信 │ │ 推进器输出 │ │ 地面站 │ │ 看门狗 │ └─────────────┘ └──────────────┘在纸上画了一个月实际动手一周就放弃了。原因坑 1两块芯片之间的通信是瓶颈路径规划需要 LiDAR 数据240Hz 帧率、30m 距离、每个点 0.357°。树莓派上跑完 DWA结果通过串口传给 STM32。多了几十毫秒延迟。船以 2m/s 运动50ms 延迟 10cm 误差。撞浮标只需要一次延迟。坑 2电源系统复杂度翻倍两块芯片、两路供电、上电时序、掉电保护。船在海上颠簸多一个连接点多一个故障点。坑 3我一个人开发维护两套代码库STM32 写 C、树莓派写 Python/C。调试时两个终端来回切。每次改通信协议两边都要改。坑 4成本无人船不是无人机船体推进器电池已经很贵了。再加树莓派整机成本上一个台阶。2.2 纯 Linux 方案 — 实时性是个硬伤全志 T113 跑 Linux RT-Preempt 补丁理论上能到百微秒级实时响应。但中断延迟不确定Linux 内核可能在任意时刻关中断推进器的 PWM 输出必须 50Hz 精准Linux 做不到硬件定时器的抖动水平。启动时间Linux 从加电到飞控就绪要 5-10 秒单片机 200ms 就起来了。船下水前通电等着很正常但万一海上重启10 秒够船飘出多远没有成熟生态Pixhawk/CUAV 的硬件生态围绕 STM32 建了十年。用 Linux 意味着传感器驱动全得自己写。2.3 纯单片机方案 — 刚好够用的上限STM32H743 作为 Cortex-M7 旗舰关键参数CPU: 480 MHz (双发射, ~2 DMIPS/MHz) RAM: 996 KB SRAM (DTCM 128K AXI 512K SRAM1/2/3/4) Flash: 2 MB FPU: 双精度硬浮点 DSP: SIMD 指令集 DMAMUX: 16通道灵活路由 OS: FreeRTOS (抢占式, 1000Hz tick)480MHz 做路径规划够不够实测数据我们的项目操作 周期/秒 CPU% ───────────────────────────────────────── EKF 导航融合 550K 0.1% PID 混控 (50Hz) 200K 0.04% D* Lite 全局规划 (1Hz) 100K 0.02% DWA 局部规划 (10Hz, 400轨迹) 4,920K 0.89% LiDAR Bresenham 射线 (M10) 1,100K 0.2% 雷达栅格融合 (33Hz) 825K 0.15% 8路串口 网络协议栈 1,500K 0.27% FreeRTOS 内核 600K 0.11% ───────────────────────────────────────── 稳态合计 ~9,800K ~1.8%只有 1.8%远没到 H743 的极限。有人会说480MHz 才用 1.8% 是因为你们算法太简单。不是的——是因为架构上做了正确的选择代价地图放在 DTCM。DTCM 是 CPU 的紧耦合内存零等待周期。DWA 每秒查 12 万次栅格如果放普通 SRAM 上每次访问多等 3-5 个周期CPU 占用直接翻倍。sin/cos 用查表不用 FPU。DWA 每条轨迹 30 步每步算一次 sin 和 cos。400 条轨迹 × 30 步 × 2 24000 次三角函数。如果调sinf()每次 ~28 周期硬件 FPU。我们预计算了 360 条目的查表查一次 ~5 周期。省了 5 倍。DLite 是增量更新*。障碍物变了不用全量重搜 6400 个节点只更新受影响的 25 个5×5 邻域。1Hz 重规划几乎不占 CPU。这些优化在 Linux 代码里很难做——因为 Linux 的设计哲学是通用不是极致。3. 真正重要的不是 CPU 频率选 STM32H7 系列最关键的理由其实是这三个3.1 内存架构Cortex-M7 内核 │ ├── ITCM (64KB, 零等待) ← CPU 直连, 跑中断服务最快 ├── DTCM (128KB, 零等待) ← CPU 直连, 放高频数据 │ └── AXI 总线矩阵 ──┬── AXI SRAM (512KB) ← DMA 缓冲区 ├── SRAM1 (128KB) ├── SRAM2 (128KB) ├── SRAM3 (32KB) └── SRAM4 (64KB)H7 有两个零等待内存ITCM 和 DTCMCPU 访问它们没有任何等待周期。代价地图、EKF 状态、任务栈——全部放 DTCM。DWA 每秒查 12 万次栅格全部零等待。ESP32 也有 520KB SRAM但分区分得碎而且没有 CPU 紧耦合内存。查栅格的延迟是 H743 的 3-5 倍。3.2 DMAMUX — 8 路串口并发不打架这是 H7 系列独有的杀手特性。在 F4 上每个串口绑定固定的 DMA 流串口多了必然冲突。H7 有 DMAMUX——16 个通道可以灵活路由任意外设到任意 DMA 流// H7: 8个串口各自独占一个 DMA 通道, 互不干扰[COM1]{DMA1_Stream0,DMAREQ_ID_USART1_RX,41},[COM2]{DMA1_Stream1,DMAREQ_ID_USART2_RX,43},[COM3]{DMA1_Stream2,DMAREQ_ID_USART3_RX,45},[COM4]{DMA1_Stream3,DMAREQ_ID_UART4_RX,63},[COM5]{DMA1_Stream4,DMAREQ_ID_UART5_RX,65},[COM6]{DMA1_Stream5,DMAREQ_ID_USART6_RX,71},[COM7]{DMA1_Stream6,DMAREQ_ID_UART7_RX,79},[COM8]{DMA1_Stream7,DMAREQ_ID_UART8_RX,81},无人船 8 路串口同时收发——GPS (COM3, 10Hz)、雷达 (COM4, 33Hz)、LiDAR (COM6, 460800bps/240Hz帧率)、遥控器 (COM2, 50Hz)、4G 模块 (LPUART1)——没有 DMAMUX 根本扛不住。3.3 生态ST 的 HAL 库虽然被骂臃肿但对于一个人开发来说它是救命稻草。不用手写寄存器不用对着 3000 页参考手册查位定义。配一个 I2C 三行代码HAL_I2C_Init(hi2c4);HAL_I2C_Master_Transmit(hi2c4,addr,data,len,timeout);加上 Keil MDK 的调试体验——J-Link 接上就能看变量、寄存器、调用栈。一个人开发快速定位 bug 比省几 KB 代码重要得多。4. 为什么从 H723 升级到 H743我们一开始用的是 H723ZG后来换了 H743ZITx。不是因为 CPU 不够快都是 480MHz 级别而是因为内存资源H723ZGH743ZITxAXI SRAM128 KB512 KBFlash1 MB2 MBFDCAN3 路2 路UART10 路8 路128KB AXI SRAM 放完 DMA 缓冲 FreeRTOS Heap 通用数据空间非常紧。H743 的 512KB AXI 让所有内存焦虑都消除了。外设少了H723 多了 FDCAN3、I2C5、UART9/10但我们用不到那些多余的。芯片迁移花了一天。因为我们项目里所有硬件定义集中在cc_h7_def.h一个文件里——换芯片只改这一个文件和.sct分散加载脚本。核心控制代码一行没动。5. 选型总结场景 推荐方案 ────────────────────────────────────────── 做产品、有团队、跑视觉 Linux 伴机 (CM4STM32) 做科研、要发论文、不管功耗 NVIDIA Jetson 做开源、一个人、先跑稳再跑快 STM32H743 ← 我们 做低端玩具船、几块钱的成本 ESP32我们的选择不是最好的是在当前约束下最优解。一个人开发 → 不要搞分布式系统伴机方案两块芯片通信是额外的复杂度。先跑稳再跑快 → 不要过早优化硬件H743 还有 98% CPU 闲置。要开源 → 选最大的生态系统ST 的社区和文档是国产芯片比不了的。6. 本章代码看看我们怎么初始化芯片// main.c — 精简版intmain(void){bsp_init();// ① 时钟 480MHz GPIO DMA 外设path_planner_init(...);// ② 代价地图 D* Lite DWA 初始化radar_task_init();// ③ MR72 雷达采集任务lidar_task_init();// ④ M10 LiDAR 采集任务// ... 创建其他 15 个 FreeRTOS 任务 ...vTaskStartScheduler();// ⑤ 启动调度器 (永不返回)}// cc_h7_def.h — 换芯片只改这里// H743 AXI SRAM: 512KB// DTCM: 128KB// 引脚定义全部集中在这里#defineCAN1_RX_PORTGPIOD#defineLIDAR_UART_PORTCOM6#defineRADAR_UART_PORTCOM47. 踩过的坑坑 1H723 和 H743 的外设不一样H723 有 3 路 FDCAN、5 路 I2C、10 路 UART。H743 只有 2 路 FDCAN、4 路 I2C、8 路 UART。我们把 H723 的代码直接拿到 H743 编译31 个错误——全是FDCAN3、I2C5、UART9、USART10不存在。教训换芯片前先对比数据手册的外设章节别想当然都是 H7 应该一样。坑 2代价地图放 AXI SRAM 上 DWA 慢 3.6 倍一开始我们把代价地图放在AXI SRAM因为空间大。DWA 规划一帧从 ~0.5ms 变成 ~1.8ms——虽然看起来不多但 DWA 跑 10Hz每个周期只有 100ms 时间窗突然多占了 1.3ms 会让其他任务被挤压。换成 DTCM 后恢复正常。H7 的 DTCM 是最宝贵的资源DWA 必须用。坑 3LiDAR 天气检测死锁我们的 M10 LiDAR 每帧只有 42 个点。但传感器融合代码里有个LIDAR_TYPICAL_MIN 100——意思是至少 100 个有效点才算建立了天气基线。结果 M10 永远达不到 100天气自适应功能彻底死锁。改成 30 就好了。这种硬编码常量是给之前设计的 RPLIDAR S2E2000 点/帧用的换 LiDAR 型号必须同步更新。8. 下一章预告第二章从 main.c 到 FreeRTOS — 嵌入式实时系统启动全流程bsp_init 里到底初始化了什么15 个 FreeRTOS 任务怎么创建、怎么分配优先级、怎么避免互相踩踏看门狗怎么监视所有任务的心跳本文是《从零搭建无人船控制系统》系列第一篇。项目地址[煜坤 YuKun]开源准备中。作者一个人、一台电脑、一条船。慢就是快走稳每一步。