# STM32H7 Autonomous Lawnmower - AI Coding Instructions ## Project Overview GPS-guided autonomous lawnmower built on STM32H743VITx using FreeRTOS. The system integrates RTK GPS/IMU navigation, 4G connectivity, remote control (SBUS), and Python telemetry for precision lawn mowing with path tracking. ## Architecture & Data Flow ### Layered Structure - **HAL/** - Hardware abstraction: UART, GPIO, MCU flash (thin wrappers over STM32 HAL) - **FML/** - Functional modules: GPS parsing, motion control, Internet/4G, SBUS, PWM, Bluetooth - **APL/** - Application tasks: motion control task, TCP/UDP clients, NTRIP RTK, Shell - **Core/** - STM32 HAL/FreeRTOS initialization (CubeMX-generated, user code in `USER CODE BEGIN/END` blocks) - **HIDOLibrary/** - Reusable utilities: AT command parser, timers, queues, Modbus, Shell ### UART Allocation (6 ports) ```c UART1 (921600) -> Debug output (DBG_Printf) UART2 (115200) -> GPS module (GPRMI/GPIMU protocol) UART3 (115200) -> 4G module (AT commands) UART4 (100000) -> SBUS remote control (inverted, 9-bit, even parity) UART5 (921600) -> Python telemetry link (JSON reports) UART6 (115200) -> Bluetooth module ``` ### Control Flow (75 Hz Motion Task) 1. **GPS/IMU polling** ¡ú `GPS_GetGPRMI()` / `GPS_GetGPIMU()` for position (ENU) + heading 2. **Pure pursuit** ¡ú `MC_Compute()` calculates forward speed + yaw rate 3. **PWM output** ¡ú TIM3 CH1/CH2 (1000-2000?s) for motor/steering ESCs 4. **Telemetry** ¡ú `PythonLink_ReportControl()` sends JSON to Python at 75 Hz ### Critical Threading - **High priority (P4)**: `MotionControl_TaskEntry` runs at 75 Hz (13ms period) for real-time control - **Normal priority (P1)**: `app_task` polls all modules (GPS, Internet, SBUS, Python) with 5ms semaphore timeout - **ISR triggers**: UART RX interrupts wake `app_task` via `app_trigger_from_isr()` for low-latency processing ## Development Patterns ### STM32CubeMX Integration **NEVER** edit HAL init code outside `USER CODE BEGIN/END` markers in `Core/Src/main.c`, `stm32h7xx_it.c`. Regeneration will overwrite unprotected code. Place user logic in: - Peripheral init: `USER CODE BEGIN 2` (after `MX_*_Init()`) - Main loop: `USER CODE END WHILE` - Custom includes: `USER CODE BEGIN Includes` ### UART Module Pattern All UART communication uses centralized `Uart_Register()` + `Uart_Init()`: ```c Uart_Register(UART_ID_GPS, &huart2); // Bind HAL handle ST_UartInit init = { .m_eRxMode = UART_RX_MODE_DMA, .m_pu8RxBuf = rx_buffer, .m_u32RxBufSize = 256 }; Uart_Init(UART_ID_GPS, &init); ``` ### GPS Data Flow - **Parser**: `GPS_RecvFsm()` state machine recognizes `$GPRMI` (23 fields: lat/lon/alt, velocity, attitude) and `$GPIMU` (9 fields: accel, gyro, temp) - **Access**: Always call `GPS_GetGPRMI(&gprmi)` and check `gprmi.m_bValid` before using data - **Coordinate transform**: `Geo_GprmiToENU()` converts WGS84 to local ENU (origin at `MC_CFG_ORIGIN_LAT_DEG`/`LON_DEG`) ### Motion Control Workflow 1. **Path definition**: Edit `FML/motion_path_data.c` with ENU (x,y) waypoints 2. **Tuning**: Adjust PID gains in `FML/motion_config.h` (`heading_kp`, `xtrack_kp`, lookahead distances) 3. **Safety**: Controller stops (`MC_CFG_PWM_CENTER_US = 1500?s`) if GPS invalid >200ms 4. **State machine**: `MC_STAGE_GOTO_START` ¡ú `MC_STAGE_FOLLOW_PATH` ¡ú `MC_STAGE_FINISHED` ### Global Parameters (Flash-backed) All runtime config in `g_com_map[]` (512-entry array) defined in `APL/global_param.h`: - Network: `IP_0..3`, `UDP_PORT`, `TCP_IP_0..3`, `TCP_PORT` - Device: `DEV_ID`, `VERSION` - Control: `RTKCTRL_INDEX`, `GPS_HZ` Save changes via `save_com_map_to_flash()` to persist across reboots. ## Build & Debug ### Keil MDK-ARM Project - Project file: `MDK-ARM/STM32H743.uvprojx` - Target: STM32H743VITx (480 MHz, 128 KB DTCM, 512 KB SRAM) - Defines: `USE_HAL_DRIVER`, `STM32H743xx`, `_USE_OS_` (FreeRTOS) - Debugger: J-Link (settings in `MDK-ARM/DebugConfig/`) - Output: `MDK-ARM/STM32H743/STM32H743.hex` ### Key Build Flags - FPU enabled (`configENABLE_FPU = 1`) - hardware floating-point acceleration active - MicroLIB enabled (`useUlib = 1`) - required for printf float support - FreeRTOS heap: 20 KB (`configTOTAL_HEAP_SIZE`) - D-Cache/I-Cache commented out in `main()` - likely due to DMA coherency issues ### Debugging Tips - **DBG_Printf()** outputs to UART1 at 921600 baud (requires `DBG_Init()` in app startup) - **Stack monitoring**: `uxTaskGetStackHighWaterMark()` reports minimum free stack (already in motion task) - **Watchdog**: System resets if `g_com_map[MAP_SIGN_INDEX] != 0x55AA` (corruption check in `IdleTask()`) ## Common Tasks ### Adding a New UART Module 1. Create `FML/NewModule.c/.h` with `NewModule_Init()`, `NewModule_Poll()` 2. Register UART in `app_main()`: `Uart_Register(UART_ID_NEW, &huartX)` 3. Add `NewModule_Poll()` to `app_task()` main loop 4. Use `Uart_Send(UART_ID_NEW, data, len)` for TX ### Modifying Motion Path 1. Edit `g_motion_path_xy[]` in `FML/motion_path_data.c` (ENU coordinates in meters) 2. Update `g_motion_path_point_count` 3. Rebuild - no runtime config needed (compiled in) ### Tuning Pure Pursuit - **Lookahead**: Increase `lookahead_max_m` for smoother curves, decrease for tighter following - **Speed**: Adjust `base_speed_mps` (0.5-2.0 m/s typical for lawn mowing) - **Heading PID**: Start with `heading_kp=2.0`, `heading_kd=0.1`; increase Kp if response too slow ### Python Telemetry Integration JSON reports via UART5 (921600 baud): - **Control**: `{"type":"control","forward":1.2,"turn":0.3,"freq":75.0,...}` (75 Hz) - **Pose**: `{"type":"pose","pos":[10.5,5.2,0.1],"heading":45.0,...}` (1 Hz) - **Stack**: `{"type":"stack","task":"Motion","free":512,...}` (0.1 Hz) ## Conventions ### Naming - **Types**: `ST_CamelCase` (structs), `E_CamelCase` (enums), `FN_CamelCase` (function pointers) - **Functions**: `Module_PascalCase()` (public), `l_camelCase()` (static local) - **Variables**: `m_prefix` (struct members), `g_prefix` (globals), `l_prefix` (static locals) - **Parameters**: `_prefixName` for function arguments ### File Organization - **Module pairs**: Always create `.h` + `.c` (even for small modules) - **Init/Poll pattern**: Public modules expose `Module_Init()` called once, `Module_Poll()` called in main loop - **No dynamic allocation** in motion-critical paths (ISRs, motion task) - all buffers pre-allocated ### Error Handling - Return `HIDO_OK` (0) / `HIDO_ERR` (-1) for success/failure - Check `*_valid` flags before using GPS/IMU data - Watchdog reset as last resort for fatal errors ## External Dependencies ### Hardware Modules - **GPS**: Custom protocol (GPRMI/GPIMU) over UART2 - see `FML/GPS_GPRMI_GPIMU_ʵÏÖ˵Ã÷.md` - **4G**: AT command interface (Module.c uses `HIDO_ATLite` parser) - **SBUS**: Futaba protocol, 16 channels - see `FML/SBUS_ʹÓÃ˵Ã÷.md` ### Libraries - **HIDO**: Custom embedded library (queues, timers, AT parser, Shell) - headers in `HIDOLibrary/Include/` - **FreeRTOS**: v10.3.1 with CMSIS-RTOS2 wrapper - **STM32 HAL**: H7 series drivers in `Drivers/STM32H7xx_HAL_Driver/` --- *Generated for STM32H7 autonomous lawnmower project. Last updated: 2025-11-24*