| ¶Ô±ÈÐÂÎļþ |
| | |
| | | --- |
| | | alwaysApply: true |
| | | --- |
| | | # AIå©ææ ¸å¿è§å |
| | | |
| | | ## ä¸é¶æ®µå·¥ä½æµ |
| | | |
| | | ### é¶æ®µä¸ï¼åæé®é¢ |
| | | |
| | | **å£°ææ ¼å¼**ï¼`ãåæé®é¢ã` |
| | | |
| | | **ç®ç** |
| | | å 为å¯è½åå¨å¤ä¸ªå¯éæ¹æ¡ï¼è¦ååºæ£ç¡®çå³çï¼éè¦è¶³å¤ç便®ã |
| | | |
| | | **å¿
é¡»åçäº**ï¼ |
| | | - çè§£æçæå¾ï¼å¦æææ§ä¹è¯·é®æ |
| | | - æç´¢ææç¸å
³ä»£ç |
| | | - è¯å«é®é¢æ ¹å |
| | | |
| | | **主å¨åç°é®é¢** |
| | | - åç°éå¤ä»£ç |
| | | - è¯å«ä¸åççå½å |
| | | - åç°å¤ä½ç代ç ãç±» |
| | | - åç°å¯è½è¿æ¶ç设计 |
| | | - åç°è¿äºå¤æç设计ãè°ç¨ |
| | | - åç°ä¸ä¸è´çç±»åå®ä¹ |
| | | - è¿ä¸æ¥æç´¢ä»£ç ï¼çæ¯å¦æ´å¤§èå´å
æç±»ä¼¼é®é¢ |
| | | |
| | | åå®ä»¥ä¸äºé¡¹ï¼å°±å¯ä»¥åææé®äºã |
| | | |
| | | **ç»å¯¹ç¦æ¢**ï¼ |
| | | - â ä¿®æ¹ä»»ä½ä»£ç |
| | | - â æ¥äºç»åºè§£å³æ¹æ¡ |
| | | - â è·³è¿æç´¢åçè§£æ¥éª¤ |
| | | - â ä¸åæå°±æ¨èæ¹æ¡ |
| | | |
| | | **é¶æ®µè½¬æ¢è§å** |
| | | æ¬é¶æ®µä½ è¦åææé®ã |
| | | 妿åå¨å¤ä¸ªä½ æ æ³ææ©çæ¹æ¡ï¼è¦é®æï¼ä½ä¸ºæé®çä¸é¨åã |
| | | å¦ææ²¡æéè¦é®æçï¼åç´æ¥è¿å
¥ä¸ä¸é¶æ®µã |
| | | |
| | | ### é¶æ®µäºï¼å¶å®æ¹æ¡ |
| | | **å£°ææ ¼å¼**ï¼`ãå¶å®æ¹æ¡ã` |
| | | |
| | | **åç½®æ¡ä»¶**ï¼ |
| | | - ææç¡®åçäºå
³é®ææ¯å³çã |
| | | |
| | | **å¿
é¡»åçäº**ï¼ |
| | | - ååºåæ´ï¼æ°å¢ãä¿®æ¹ãå é¤ï¼çæä»¶ï¼ç®è¦æè¿°æ¯ä¸ªæä»¶çåå |
| | | - æ¶é¤éå¤é»è¾ï¼å¦æåç°éå¤ä»£ç ï¼å¿
é¡»éè¿å¤ç¨ææ½è±¡æ¥æ¶é¤ |
| | | - ç¡®ä¿ä¿®æ¹åç代ç 符åDRYåååè¯å¥½çæ¶æè®¾è®¡ |
| | | |
| | | 妿æ°åç°äºåææ¶éçå
³é®å³çï¼å¨è¿ä¸ªé¶æ®µä½ è¿å¯ä»¥ç»§ç»é®æï¼ç´å°æ²¡æä¸æç¡®çé®é¢ä¹åï¼æ¬é¶æ®µç»æã |
| | | æ¬é¶æ®µä¸å
许èªå¨åæ¢å°ä¸ä¸é¶æ®µã |
| | | |
| | | ### é¶æ®µä¸ï¼æ§è¡æ¹æ¡ |
| | | **å£°ææ ¼å¼**ï¼`ãæ§è¡æ¹æ¡ã` |
| | | |
| | | **å¿
é¡»åçäº**ï¼ |
| | | - ä¸¥æ ¼æç
§é宿¹æ¡å®ç° |
| | | - ä¿®æ¹åè¿è¡ç±»åæ£æ¥ |
| | | |
| | | **ç»å¯¹ç¦æ¢**ï¼ |
| | | - â æäº¤ä»£ç ï¼é¤éç¨æ·æç¡®è¦æ±ï¼ |
| | | - å¯å¨å¼åæå¡å¨ |
| | | |
| | | 妿å¨è¿ä¸ªé¶æ®µåç°äºæ¿ä¸åçé®é¢ï¼è¯·åææé®ã |
| | | |
| | | æ¶å°ç¨æ·æ¶æ¯æ¶ï¼ä¸è¬ä»ãåæé®é¢ãé¶æ®µå¼å§ï¼é¤éç¨æ·æç¡®æå®é¶æ®µçååã |
| | |
| | | [PreviousLibFiles] |
| | | LibFiles=Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_tim.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_tim_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_cortex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_cortex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_rcc.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_rcc_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_bus.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_rcc.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_crs.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_system.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_utils.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_flash.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_flash_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_gpio.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_gpio_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_gpio.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_hsem.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_hsem.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_dma.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_dma_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_dma.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_dmamux.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_mdma.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_pwr.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_pwr_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_pwr.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_def.h;Drivers\STM32H7xx_HAL_Driver\Inc\Legacy\stm32_hal_legacy.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_i2c.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_i2c_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_exti.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_exti.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_tim.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_uart.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_usart.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_lpuart.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_uart_ex.h;Middlewares\Third_Party\FreeRTOS\Source\include\croutine.h;Middlewares\Third_Party\FreeRTOS\Source\include\deprecated_definitions.h;Middlewares\Third_Party\FreeRTOS\Source\include\event_groups.h;Middlewares\Third_Party\FreeRTOS\Source\include\FreeRTOS.h;Middlewares\Third_Party\FreeRTOS\Source\include\list.h;Middlewares\Third_Party\FreeRTOS\Source\include\message_buffer.h;Middlewares\Third_Party\FreeRTOS\Source\include\mpu_prototypes.h;Middlewares\Third_Party\FreeRTOS\Source\include\mpu_wrappers.h;Middlewares\Third_Party\FreeRTOS\Source\include\portable.h;Middlewares\Third_Party\FreeRTOS\Source\include\projdefs.h;Middlewares\Third_Party\FreeRTOS\Source\include\queue.h;Middlewares\Third_Party\FreeRTOS\Source\include\semphr.h;Middlewares\Third_Party\FreeRTOS\Source\include\stack_macros.h;Middlewares\Third_Party\FreeRTOS\Source\include\StackMacros.h;Middlewares\Third_Party\FreeRTOS\Source\include\stream_buffer.h;Middlewares\Third_Party\FreeRTOS\Source\include\task.h;Middlewares\Third_Party\FreeRTOS\Source\include\timers.h;Middlewares\Third_Party\FreeRTOS\Source\include\atomic.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\freertos_mpool.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\freertos_os2.h;Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM4F\portmacro.h;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_tim.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_tim_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_cortex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rcc.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rcc_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_flash.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_flash_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_gpio.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_hsem.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_dma.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_dma_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_mdma.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pwr.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pwr_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_i2c.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_i2c_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_exti.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_uart.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_uart_ex.c;Middlewares\Third_Party\FreeRTOS\Source\croutine.c;Middlewares\Third_Party\FreeRTOS\Source\event_groups.c;Middlewares\Third_Party\FreeRTOS\Source\list.c;Middlewares\Third_Party\FreeRTOS\Source\queue.c;Middlewares\Third_Party\FreeRTOS\Source\stream_buffer.c;Middlewares\Third_Party\FreeRTOS\Source\tasks.c;Middlewares\Third_Party\FreeRTOS\Source\timers.c;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.c;Middlewares\Third_Party\FreeRTOS\Source\portable\MemMang\heap_4.c;Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM4F\port.c;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_tim.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_tim_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_cortex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_cortex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_rcc.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_rcc_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_bus.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_rcc.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_crs.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_system.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_utils.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_flash.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_flash_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_gpio.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_gpio_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_gpio.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_hsem.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_hsem.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_dma.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_dma_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_dma.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_dmamux.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_mdma.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_pwr.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_pwr_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_pwr.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_def.h;Drivers\STM32H7xx_HAL_Driver\Inc\Legacy\stm32_hal_legacy.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_i2c.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_i2c_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_exti.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_exti.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_tim.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_uart.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_usart.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_lpuart.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_uart_ex.h;Middlewares\Third_Party\FreeRTOS\Source\include\croutine.h;Middlewares\Third_Party\FreeRTOS\Source\include\deprecated_definitions.h;Middlewares\Third_Party\FreeRTOS\Source\include\event_groups.h;Middlewares\Third_Party\FreeRTOS\Source\include\FreeRTOS.h;Middlewares\Third_Party\FreeRTOS\Source\include\list.h;Middlewares\Third_Party\FreeRTOS\Source\include\message_buffer.h;Middlewares\Third_Party\FreeRTOS\Source\include\mpu_prototypes.h;Middlewares\Third_Party\FreeRTOS\Source\include\mpu_wrappers.h;Middlewares\Third_Party\FreeRTOS\Source\include\portable.h;Middlewares\Third_Party\FreeRTOS\Source\include\projdefs.h;Middlewares\Third_Party\FreeRTOS\Source\include\queue.h;Middlewares\Third_Party\FreeRTOS\Source\include\semphr.h;Middlewares\Third_Party\FreeRTOS\Source\include\stack_macros.h;Middlewares\Third_Party\FreeRTOS\Source\include\StackMacros.h;Middlewares\Third_Party\FreeRTOS\Source\include\stream_buffer.h;Middlewares\Third_Party\FreeRTOS\Source\include\task.h;Middlewares\Third_Party\FreeRTOS\Source\include\timers.h;Middlewares\Third_Party\FreeRTOS\Source\include\atomic.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\freertos_mpool.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\freertos_os2.h;Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM4F\portmacro.h;Drivers\CMSIS\Device\ST\STM32H7xx\Include\stm32h743xx.h;Drivers\CMSIS\Device\ST\STM32H7xx\Include\stm32h7xx.h;Drivers\CMSIS\Device\ST\STM32H7xx\Include\system_stm32h7xx.h;Drivers\CMSIS\Device\ST\STM32H7xx\Include\system_stm32h7xx.h;Drivers\CMSIS\Device\ST\STM32H7xx\Source\Templates\system_stm32h7xx.c; |
| | | LibFiles=Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_tim.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_tim_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_cortex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_cortex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_rcc.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_rcc_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_bus.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_rcc.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_crs.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_system.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_utils.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_flash.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_flash_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_gpio.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_gpio_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_gpio.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_hsem.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_hsem.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_dma.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_dma_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_dma.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_dmamux.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_mdma.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_pwr.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_pwr_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_pwr.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_def.h;Drivers\STM32H7xx_HAL_Driver\Inc\Legacy\stm32_hal_legacy.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_i2c.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_i2c_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_exti.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_exti.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_tim.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_uart.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_usart.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_lpuart.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_uart_ex.h;Middlewares\Third_Party\FreeRTOS\Source\include\croutine.h;Middlewares\Third_Party\FreeRTOS\Source\include\deprecated_definitions.h;Middlewares\Third_Party\FreeRTOS\Source\include\event_groups.h;Middlewares\Third_Party\FreeRTOS\Source\include\FreeRTOS.h;Middlewares\Third_Party\FreeRTOS\Source\include\list.h;Middlewares\Third_Party\FreeRTOS\Source\include\message_buffer.h;Middlewares\Third_Party\FreeRTOS\Source\include\mpu_prototypes.h;Middlewares\Third_Party\FreeRTOS\Source\include\mpu_wrappers.h;Middlewares\Third_Party\FreeRTOS\Source\include\portable.h;Middlewares\Third_Party\FreeRTOS\Source\include\projdefs.h;Middlewares\Third_Party\FreeRTOS\Source\include\queue.h;Middlewares\Third_Party\FreeRTOS\Source\include\semphr.h;Middlewares\Third_Party\FreeRTOS\Source\include\stack_macros.h;Middlewares\Third_Party\FreeRTOS\Source\include\StackMacros.h;Middlewares\Third_Party\FreeRTOS\Source\include\stream_buffer.h;Middlewares\Third_Party\FreeRTOS\Source\include\task.h;Middlewares\Third_Party\FreeRTOS\Source\include\timers.h;Middlewares\Third_Party\FreeRTOS\Source\include\atomic.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\freertos_mpool.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\freertos_os2.h;Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM4F\portmacro.h;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_tim.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_tim_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_cortex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rcc.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rcc_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_flash.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_flash_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_gpio.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_hsem.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_dma.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_dma_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_mdma.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pwr.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pwr_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_i2c.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_i2c_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_exti.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_uart.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_uart_ex.c;Middlewares\Third_Party\FreeRTOS\Source\croutine.c;Middlewares\Third_Party\FreeRTOS\Source\event_groups.c;Middlewares\Third_Party\FreeRTOS\Source\list.c;Middlewares\Third_Party\FreeRTOS\Source\queue.c;Middlewares\Third_Party\FreeRTOS\Source\stream_buffer.c;Middlewares\Third_Party\FreeRTOS\Source\tasks.c;Middlewares\Third_Party\FreeRTOS\Source\timers.c;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.c;Middlewares\Third_Party\FreeRTOS\Source\portable\MemMang\heap_4.c;Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM4F\port.c;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_tim.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_tim_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_cortex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_cortex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_rcc.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_rcc_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_bus.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_rcc.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_crs.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_system.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_utils.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_flash.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_flash_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_gpio.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_gpio_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_gpio.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_hsem.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_hsem.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_dma.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_dma_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_dma.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_dmamux.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_mdma.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_pwr.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_pwr_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_pwr.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_def.h;Drivers\STM32H7xx_HAL_Driver\Inc\Legacy\stm32_hal_legacy.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_i2c.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_i2c_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_exti.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_exti.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_tim.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_uart.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_usart.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_lpuart.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_uart_ex.h;Middlewares\Third_Party\FreeRTOS\Source\include\croutine.h;Middlewares\Third_Party\FreeRTOS\Source\include\deprecated_definitions.h;Middlewares\Third_Party\FreeRTOS\Source\include\event_groups.h;Middlewares\Third_Party\FreeRTOS\Source\include\FreeRTOS.h;Middlewares\Third_Party\FreeRTOS\Source\include\list.h;Middlewares\Third_Party\FreeRTOS\Source\include\message_buffer.h;Middlewares\Third_Party\FreeRTOS\Source\include\mpu_prototypes.h;Middlewares\Third_Party\FreeRTOS\Source\include\mpu_wrappers.h;Middlewares\Third_Party\FreeRTOS\Source\include\portable.h;Middlewares\Third_Party\FreeRTOS\Source\include\projdefs.h;Middlewares\Third_Party\FreeRTOS\Source\include\queue.h;Middlewares\Third_Party\FreeRTOS\Source\include\semphr.h;Middlewares\Third_Party\FreeRTOS\Source\include\stack_macros.h;Middlewares\Third_Party\FreeRTOS\Source\include\StackMacros.h;Middlewares\Third_Party\FreeRTOS\Source\include\stream_buffer.h;Middlewares\Third_Party\FreeRTOS\Source\include\task.h;Middlewares\Third_Party\FreeRTOS\Source\include\timers.h;Middlewares\Third_Party\FreeRTOS\Source\include\atomic.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\freertos_mpool.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\freertos_os2.h;Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM4F\portmacro.h;Drivers\CMSIS\Device\ST\STM32H7xx\Include\stm32h743xx.h;Drivers\CMSIS\Device\ST\STM32H7xx\Include\stm32h7xx.h;Drivers\CMSIS\Device\ST\STM32H7xx\Include\system_stm32h7xx.h;Drivers\CMSIS\Device\ST\STM32H7xx\Include\system_stm32h7xx.h;Drivers\CMSIS\Device\ST\STM32H7xx\Source\Templates\system_stm32h7xx.c;Drivers\CMSIS\Include\cmsis_armcc.h;Drivers\CMSIS\Include\cmsis_armclang.h;Drivers\CMSIS\Include\cmsis_armclang_ltm.h;Drivers\CMSIS\Include\cmsis_compiler.h;Drivers\CMSIS\Include\cmsis_gcc.h;Drivers\CMSIS\Include\cmsis_iccarm.h;Drivers\CMSIS\Include\cmsis_version.h;Drivers\CMSIS\Include\core_armv81mml.h;Drivers\CMSIS\Include\core_armv8mbl.h;Drivers\CMSIS\Include\core_armv8mml.h;Drivers\CMSIS\Include\core_cm0.h;Drivers\CMSIS\Include\core_cm0plus.h;Drivers\CMSIS\Include\core_cm1.h;Drivers\CMSIS\Include\core_cm23.h;Drivers\CMSIS\Include\core_cm3.h;Drivers\CMSIS\Include\core_cm33.h;Drivers\CMSIS\Include\core_cm35p.h;Drivers\CMSIS\Include\core_cm4.h;Drivers\CMSIS\Include\core_cm7.h;Drivers\CMSIS\Include\core_sc000.h;Drivers\CMSIS\Include\core_sc300.h;Drivers\CMSIS\Include\mpu_armv7.h;Drivers\CMSIS\Include\mpu_armv8.h;Drivers\CMSIS\Include\tz_context.h; |
| | | |
| | | [PreviousUsedKeilFiles] |
| | | SourceFiles=..\Core\Src\main.c;..\Core\Src\freertos.c;..\Core\Src\stm32h7xx_it.c;..\Core\Src\stm32h7xx_hal_msp.c;..\Core\Src\stm32h7xx_hal_timebase_tim.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_tim.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_tim_ex.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_cortex.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rcc.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rcc_ex.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_flash.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_flash_ex.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_gpio.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_hsem.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_dma.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_dma_ex.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_mdma.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pwr.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pwr_ex.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_i2c.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_i2c_ex.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_exti.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_uart.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_uart_ex.c;..\Middlewares\Third_Party\FreeRTOS\Source\croutine.c;..\Middlewares\Third_Party\FreeRTOS\Source\event_groups.c;..\Middlewares\Third_Party\FreeRTOS\Source\list.c;..\Middlewares\Third_Party\FreeRTOS\Source\queue.c;..\Middlewares\Third_Party\FreeRTOS\Source\stream_buffer.c;..\Middlewares\Third_Party\FreeRTOS\Source\tasks.c;..\Middlewares\Third_Party\FreeRTOS\Source\timers.c;..\Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.c;..\Middlewares\Third_Party\FreeRTOS\Source\portable\MemMang\heap_4.c;..\Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM4F\port.c;..\Drivers\CMSIS\Device\ST\STM32H7xx\Source\Templates\system_stm32h7xx.c;..\Core\Src\system_stm32h7xx.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_tim.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_tim_ex.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_cortex.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rcc.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rcc_ex.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_flash.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_flash_ex.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_gpio.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_hsem.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_dma.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_dma_ex.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_mdma.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pwr.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pwr_ex.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_i2c.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_i2c_ex.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_exti.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_uart.c;..\Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_uart_ex.c;..\Middlewares\Third_Party\FreeRTOS\Source\croutine.c;..\Middlewares\Third_Party\FreeRTOS\Source\event_groups.c;..\Middlewares\Third_Party\FreeRTOS\Source\list.c;..\Middlewares\Third_Party\FreeRTOS\Source\queue.c;..\Middlewares\Third_Party\FreeRTOS\Source\stream_buffer.c;..\Middlewares\Third_Party\FreeRTOS\Source\tasks.c;..\Middlewares\Third_Party\FreeRTOS\Source\timers.c;..\Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.c;..\Middlewares\Third_Party\FreeRTOS\Source\portable\MemMang\heap_4.c;..\Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM4F\port.c;..\Drivers\CMSIS\Device\ST\STM32H7xx\Source\Templates\system_stm32h7xx.c;..\Core\Src\system_stm32h7xx.c;;;..\Middlewares\Third_Party\FreeRTOS\Source\croutine.c;..\Middlewares\Third_Party\FreeRTOS\Source\event_groups.c;..\Middlewares\Third_Party\FreeRTOS\Source\list.c;..\Middlewares\Third_Party\FreeRTOS\Source\queue.c;..\Middlewares\Third_Party\FreeRTOS\Source\stream_buffer.c;..\Middlewares\Third_Party\FreeRTOS\Source\tasks.c;..\Middlewares\Third_Party\FreeRTOS\Source\timers.c;..\Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.c;..\Middlewares\Third_Party\FreeRTOS\Source\portable\MemMang\heap_4.c;..\Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM4F\port.c; |
| | |
| | | #include "AppConfig.h" |
| | | #include "DBG.h" |
| | | #include "EG800FSM.h" |
| | | |
| | | #include "arm_math.h" |
| | | /******************************************************************************* |
| | | * Macro * |
| | | *******************************************************************************/ |
| | |
| | | #define configTICK_RATE_HZ ((TickType_t)1000) |
| | | #define configMAX_PRIORITIES ( 56 ) |
| | | #define configMINIMAL_STACK_SIZE ((uint16_t)128) |
| | | #define configTOTAL_HEAP_SIZE ((size_t)32768) /* å¢å å°32KBï¼å15KBå¯è½ä¸å¤ */ |
| | | #define configTOTAL_HEAP_SIZE ((size_t)15360) |
| | | #define configMAX_TASK_NAME_LEN ( 16 ) |
| | | #define configUSE_TRACE_FACILITY 1 |
| | | #define configUSE_16_BIT_TICKS 0 |
| | |
| | | <flags>2</flags> |
| | | <showCmd>3</showCmd> |
| | | <MinPosition> |
| | | <xPos>-1</xPos> |
| | | <yPos>-1</yPos> |
| | | <xPos>-32000</xPos> |
| | | <yPos>-32000</yPos> |
| | | </MinPosition> |
| | | <MaxPosition> |
| | | <xPos>-1</xPos> |
| | |
| | | <MDIClientArea> |
| | | <RegID>0</RegID> |
| | | <MDITabState> |
| | | <Len>4012</Len> |
| | | <Data>0100000004000000010000000100000001000000010000000000000002000000000000000100000001000000000000002800000028000000010000002A000000080000000100000047453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C464D4C5C496E7465726E65745C4D6F64756C655C45473830305C454738303046534D2E63000000000A454738303046534D2E6300000000C5D4F200FFFFFFFF40453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C4D444B2D41524D5C737461727475705F73746D33326837343378782E730000000015737461727475705F73746D33326837343378782E7300000000FFDC7800FFFFFFFF52453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C4D6964646C6577617265735C54686972645F50617274795C4672656552544F535C536F757263655C7461736B732E6300000000077461736B732E6300000000BECEA100FFFFFFFF2C453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C41504C5C6170702E6300000000056170702E6300000000F0A0A100FFFFFFFF5B453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C4D6964646C6577617265735C54686972645F50617274795C4672656552544F535C536F757263655C696E636C7564655C73656D7068722E68000000000873656D7068722E6800000000BCA8E100FFFFFFFF38453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C464D4C5C496E7465726E65745C536F636B65742E630000000008536F636B65742E63000000009CC1B600FFFFFFFF4A453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C464D4C5C496E7465726E65745C4D6F64756C655C45473830305C45473830304472697665722E63000000000D45473830304472697665722E6300000000F7B88600FFFFFFFF2C453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C464D4C5C4442472E6300000000054442472E6300000000D9ADC200FFFFFFFF32453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C41504C5C554450436C69656E742E63000000000B554450436C69656E742E6300000000A5C2D700FFFFFFFF2D453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C48414C5C556172742E630000000006556172742E6300000000B3A6BE00FFFFFFFF32453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C436F72655C5372635C6D61696E2E6300000000066D61696E2E6300000000EAD6A300FFFFFFFF32453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C464D4C5C626C7565746F6F74682E63000000000B626C7565746F6F74682E6300000000F6FA7D00FFFFFFFF35453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C41504C5C676C6F62616C5F706172616D2E63000000000E676C6F62616C5F706172616D2E6300000000B5E99D00FFFFFFFF32453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C41504C5C417070436F6E6669672E68000000000B417070436F6E6669672E68000000005FC3CF00FFFFFFFF31453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C48414C5C4D4355466C6173682E63000000000A4D4355466C6173682E6300000000C1838300FFFFFFFF3A453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C436F72655C5372635C73746D3332683778785F69742E63000000000E73746D3332683778785F69742E6300000000CACAD500FFFFFFFF35453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C41504C5C676C6F62616C5F706172616D2E68000000000E676C6F62616C5F706172616D2E6800000000C5D4F200FFFFFFFF59453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C447269766572735C53544D3332483778785F48414C5F4472697665725C5372635C73746D3332683778785F68616C5F666C6173682E63000000001573746D3332683778785F68616C5F666C6173682E6300000000FFDC7800FFFFFFFF59453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C447269766572735C53544D3332483778785F48414C5F4472697665725C496E635C73746D3332683778785F68616C5F666C6173682E68000000001573746D3332683778785F68616C5F666C6173682E6800000000BECEA100FFFFFFFF31453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C41504C5C4E545249504170702E63000000000A4E545249504170702E6300000000F0A0A100FFFFFFFF2E453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C41504C5C5368656C6C2E6300000000075368656C6C2E6300000000BCA8E100FFFFFFFF32453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C41504C5C544350436C69656E742E63000000000B544350436C69656E742E63000000009CC1B600FFFFFFFF43453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C4849444F4C6962726172795C496E636C7564655C4849444F5F5368656C6C2E68000000000C4849444F5F5368656C6C2E6800000000F7B88600FFFFFFFF24443A5C4B65696C5F76355C41524D5C41524D43435C696E636C7564655C737464696F2E680000000007737464696F2E6800000000D9ADC200FFFFFFFF2C453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C464D4C5C4750532E6300000000054750532E6300000000A5C2D700FFFFFFFF2D453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C48414C5C556172742E680000000006556172742E6800000000B3A6BE00FFFFFFFF58453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C447269766572735C53544D3332483778785F48414C5F4472697665725C5372635C73746D3332683778785F68616C5F756172742E63000000001473746D3332683778785F68616C5F756172742E6300000000EAD6A300FFFFFFFF3F453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C436F72655C5372635C73746D3332683778785F68616C5F6D73702E63000000001373746D3332683778785F68616C5F6D73702E6300000000F6FA7D00FFFFFFFF3A453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C41504C5C73657269616C5F61745F636D645F6170702E63000000001373657269616C5F61745F636D645F6170702E6300000000B5E99D00FFFFFFFF2D453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C464D4C5C534255532E630000000006534255532E63000000005FC3CF00FFFFFFFF45453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C4849444F4C6962726172795C496E636C7564655C4849444F5F545970654465662E68000000000E4849444F5F545970654465662E6800000000C1838300FFFFFFFF64453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C4D6964646C6577617265735C54686972645F50617274795C4672656552544F535C536F757263655C434D5349535F52544F535F56325C636D7369735F6F73322E63000000000B636D7369735F6F73322E6300000000CACAD500FFFFFFFF32453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C464D4C5C70776D5F6374726F6C2E63000000000B70776D5F6374726F6C2E6300000000C5D4F200FFFFFFFF42453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C4849444F4C6962726172795C496E636C7564655C4849444F5F5574696C2E68000000000B4849444F5F5574696C2E6800000000FFDC7800FFFFFFFF32453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C464D4C5C70776D5F6374726F6C2E68000000000B70776D5F6374726F6C2E6800000000BECEA100FFFFFFFF33453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C464D4C5C507974686F6E4C696E6B2E63000000000C507974686F6E4C696E6B2E6300000000F0A0A100FFFFFFFF49453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C4849444F4C6962726172795C496E636C7564655C4849444F5F4D6F6462757343524331362E6800000000124849444F5F4D6F6462757343524331362E6800000000BCA8E100FFFFFFFF33453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C464D4C5C507974686F6E4C696E6B2E68000000000C507974686F6E4C696E6B2E68000000009CC1B600FFFFFFFF5D453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C4D6964646C6577617265735C54686972645F50617274795C4672656552544F535C536F757263655C696E636C7564655C4672656552544F532E68000000000A4672656552544F532E6800000000F7B88600FFFFFFFF2C453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C464D4C5C4750532E6800000000054750532E6800000000D9ADC200FFFFFFFF64453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C4D6964646C6577617265735C54686972645F50617274795C4672656552544F535C536F757263655C434D5349535F52544F535F56325C636D7369735F6F73322E68000000000B636D7369735F6F73322E6800000000A5C2D700FFFFFFFF6D453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C4D6964646C6577617265735C54686972645F50617274795C4672656552544F535C536F757263655C706F727461626C655C525644535C41524D5F434D34465C706F72746D6163726F2E68000000000B706F72746D6163726F2E6800000000B3A6BE00FFFFFFFF0100000010000000C5D4F200FFDC7800BECEA100F0A0A100BCA8E1009CC1B600F7B88600D9ADC200A5C2D700B3A6BE00EAD6A300F6FA7D00B5E99D005FC3CF00C1838300CACAD500010000000000000002000000670100006600000000060000C0010000</Data> |
| | | <Len>365</Len> |
| | | <Data>0100000004000000010000000100000001000000010000000000000002000000000000000100000001000000000000002800000028000000010000000200000001000000010000003E453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C436F72655C5372635C73797374656D5F73746D3332683778782E63000000001273797374656D5F73746D3332683778782E6300000000F6FA7D00FFFFFFFF43453A5C4749545C4C61776E6D6F7765725F53544D333248375C53544D3332483734335C447269766572735C434D5349535C496E636C7564655C636F72655F636D372E68000000000A636F72655F636D372E6800000000FFDC7800FFFFFFFF0100000010000000C5D4F200FFDC7800BECEA100F0A0A100BCA8E1009CC1B600F7B88600D9ADC200A5C2D700B3A6BE00EAD6A300F6FA7D00B5E99D005FC3CF00C1838300CACAD5000100000000000000020000006701000066000000000600005D020000</Data> |
| | | </MDITabState> |
| | | </MDIClientArea> |
| | | <ViewEx> |
| | |
| | | <RecentRowIndex>0</RecentRowIndex> |
| | | <RectRecentDocked> |
| | | <Len>16</Len> |
| | | <Data>03000000660000006001000090010000</Data> |
| | | <Data>0300000066000000600100002D020000</Data> |
| | | </RectRecentDocked> |
| | | <RectRecentFloat> |
| | | <Len>16</Len> |
| | |
| | | <RecentRowIndex>0</RecentRowIndex> |
| | | <RectRecentDocked> |
| | | <Len>16</Len> |
| | | <Data>03000000660000006001000090010000</Data> |
| | | <Data>0300000066000000600100002D020000</Data> |
| | | </RectRecentDocked> |
| | | <RectRecentFloat> |
| | | <Len>16</Len> |
| | |
| | | <RecentRowIndex>0</RecentRowIndex> |
| | | <RectRecentDocked> |
| | | <Len>16</Len> |
| | | <Data>03000000660000006001000090010000</Data> |
| | | <Data>0300000066000000600100002D020000</Data> |
| | | </RectRecentDocked> |
| | | <RectRecentFloat> |
| | | <Len>16</Len> |
| | |
| | | <RecentRowIndex>0</RecentRowIndex> |
| | | <RectRecentDocked> |
| | | <Len>16</Len> |
| | | <Data>03000000660000006001000090010000</Data> |
| | | <Data>0300000066000000600100002D020000</Data> |
| | | </RectRecentDocked> |
| | | <RectRecentFloat> |
| | | <Len>16</Len> |
| | |
| | | <RecentRowIndex>0</RecentRowIndex> |
| | | <RectRecentDocked> |
| | | <Len>16</Len> |
| | | <Data>03000000C4010000FD050000F5020000</Data> |
| | | <Data>0300000061020000FD050000F5020000</Data> |
| | | </RectRecentDocked> |
| | | <RectRecentFloat> |
| | | <Len>16</Len> |
| | | <Data>8A000000A1000000C20200000F010000</Data> |
| | | <Data>D80000009A020000D8060000FB030000</Data> |
| | | </RectRecentFloat> |
| | | </Window> |
| | | <Window> |
| | |
| | | <IsActivated>0</IsActivated> |
| | | <MRUWidth>32767</MRUWidth> |
| | | <PinState>0</PinState> |
| | | <RecentFrameAlignment>4096</RecentFrameAlignment> |
| | | <RecentFrameAlignment>32768</RecentFrameAlignment> |
| | | <RecentRowIndex>0</RecentRowIndex> |
| | | <RectRecentDocked> |
| | | <Len>16</Len> |
| | | <Data>03000000C4010000FD050000F5020000</Data> |
| | | <Data>0300000061020000FD050000F5020000</Data> |
| | | </RectRecentDocked> |
| | | <RectRecentFloat> |
| | | <Len>16</Len> |
| | | <Data>8A000000A1000000C20200000F010000</Data> |
| | | <Data>D80000009A020000D8060000FB030000</Data> |
| | | </RectRecentFloat> |
| | | </Window> |
| | | <Window> |
| | |
| | | <RecentRowIndex>0</RecentRowIndex> |
| | | <RectRecentDocked> |
| | | <Len>16</Len> |
| | | <Data>03000000660000006001000068020000</Data> |
| | | <Data>03000000660000006001000090010000</Data> |
| | | </RectRecentDocked> |
| | | <RectRecentFloat> |
| | | <Len>16</Len> |
| | |
| | | <IsActivated>0</IsActivated> |
| | | <MRUWidth>32767</MRUWidth> |
| | | <PinState>0</PinState> |
| | | <RecentFrameAlignment>4096</RecentFrameAlignment> |
| | | <RecentFrameAlignment>32768</RecentFrameAlignment> |
| | | <RecentRowIndex>0</RecentRowIndex> |
| | | <RectRecentDocked> |
| | | <Len>16</Len> |
| | | <Data>03000000C4010000FD050000F5020000</Data> |
| | | <Data>0300000061020000FD050000F5020000</Data> |
| | | </RectRecentDocked> |
| | | <RectRecentFloat> |
| | | <Len>16</Len> |
| | | <Data>8A000000A1000000C20200000F010000</Data> |
| | | <Data>D80000009A020000D8060000FB030000</Data> |
| | | </RectRecentFloat> |
| | | </Window> |
| | | <Window> |
| | |
| | | <IsActivated>0</IsActivated> |
| | | <MRUWidth>32767</MRUWidth> |
| | | <PinState>0</PinState> |
| | | <RecentFrameAlignment>4096</RecentFrameAlignment> |
| | | <RecentFrameAlignment>32768</RecentFrameAlignment> |
| | | <RecentRowIndex>0</RecentRowIndex> |
| | | <RectRecentDocked> |
| | | <Len>16</Len> |
| | | <Data>03000000C40100007D070000F5020000</Data> |
| | | <Data>0300000061020000FD05000092030000</Data> |
| | | </RectRecentDocked> |
| | | <RectRecentFloat> |
| | | <Len>16</Len> |
| | | <Data>8A000000A10000006D0100005D020000</Data> |
| | | <Data>D80000009A020000D8060000FB030000</Data> |
| | | </RectRecentFloat> |
| | | </Window> |
| | | <Window> |
| | |
| | | <IsActivated>0</IsActivated> |
| | | <MRUWidth>32767</MRUWidth> |
| | | <PinState>0</PinState> |
| | | <RecentFrameAlignment>4096</RecentFrameAlignment> |
| | | <RecentFrameAlignment>32768</RecentFrameAlignment> |
| | | <RecentRowIndex>0</RecentRowIndex> |
| | | <RectRecentDocked> |
| | | <Len>16</Len> |
| | | <Data>03000000C40100007D070000F5020000</Data> |
| | | <Data>0300000061020000FD05000092030000</Data> |
| | | </RectRecentDocked> |
| | | <RectRecentFloat> |
| | | <Len>16</Len> |
| | | <Data>8A000000A10000006D0100005D020000</Data> |
| | | <Data>D80000009A020000D8060000FB030000</Data> |
| | | </RectRecentFloat> |
| | | </Window> |
| | | <Window> |
| | |
| | | <IsActivated>0</IsActivated> |
| | | <MRUWidth>32767</MRUWidth> |
| | | <PinState>0</PinState> |
| | | <RecentFrameAlignment>4096</RecentFrameAlignment> |
| | | <RecentFrameAlignment>32768</RecentFrameAlignment> |
| | | <RecentRowIndex>0</RecentRowIndex> |
| | | <RectRecentDocked> |
| | | <Len>16</Len> |
| | | <Data>03000000C40100007D070000F5020000</Data> |
| | | <Data>0300000061020000FD05000092030000</Data> |
| | | </RectRecentDocked> |
| | | <RectRecentFloat> |
| | | <Len>16</Len> |
| | | <Data>8A000000A10000006D0100005D020000</Data> |
| | | <Data>D80000009A020000D8060000FB030000</Data> |
| | | </RectRecentFloat> |
| | | </Window> |
| | | <Window> |
| | |
| | | </RectRecentFloat> |
| | | </Window> |
| | | <DockMan> |
| | | <Len>3312</Len> |
| | | <Data>000000000B000000000000000020000000000000FFFFFFFFFFFFFFFFC4000000BD00000070040000C1000000000000000100000004000000010000000000000000000000FFFFFFFF08000000CB00000057010000CC000000F08B00005A01000079070000D601000045890000FFFF02000B004354616262656450616E650020000000000000C40000006600000070040000D4000000C40000004F00000070040000BD0000000000000040280046080000000B446973617373656D626C7900000000CB00000001000000FFFFFFFFFFFFFFFF14506572666F726D616E636520416E616C797A6572000000005701000001000000FFFFFFFFFFFFFFFF14506572666F726D616E636520416E616C797A657200000000CC00000001000000FFFFFFFFFFFFFFFF0E4C6F67696320416E616C797A657200000000F08B000001000000FFFFFFFFFFFFFFFF0D436F646520436F766572616765000000005A01000001000000FFFFFFFFFFFFFFFF11496E737472756374696F6E205472616365000000007907000001000000FFFFFFFFFFFFFFFF0F53797374656D20416E616C797A657200000000D601000001000000FFFFFFFFFFFFFFFF104576656E742053746174697374696373000000004589000001000000FFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000000001000000FFFFFFFFCB00000001000000FFFFFFFFCB000000000000000040000000000000FFFFFFFFFFFFFFFFAC0300004F000000B0030000A5010000000000000200000004000000010000000000000000000000FFFFFFFF2B000000E2050000CA0900002D8C00002E8C00002F8C0000308C0000318C0000328C0000338C0000348C0000358C0000368C0000378C0000388C0000398C00003A8C00003B8C00003C8C00003D8C00003E8C00003F8C0000408C0000418C000050C3000051C3000052C3000053C3000054C3000055C3000056C3000057C3000058C3000059C300005AC300005BC300005CC300005DC300005EC300005FC3000060C3000061C3000062C3000063C3000001800040000000000000B00300006600000070040000BC010000B00300004F00000070040000A501000000000000404100462B0000000753796D626F6C7300000000E205000001000000FFFFFFFFFFFFFFFF0A5472616365204461746100000000CA09000001000000FFFFFFFFFFFFFFFF00000000002D8C000001000000FFFFFFFFFFFFFFFF00000000002E8C000001000000FFFFFFFFFFFFFFFF00000000002F8C000001000000FFFFFFFFFFFFFFFF0000000000308C000001000000FFFFFFFFFFFFFFFF0000000000318C000001000000FFFFFFFFFFFFFFFF0000000000328C000001000000FFFFFFFFFFFFFFFF0000000000338C000001000000FFFFFFFFFFFFFFFF0000000000348C000001000000FFFFFFFFFFFFFFFF0000000000358C000001000000FFFFFFFFFFFFFFFF0000000000368C000001000000FFFFFFFFFFFFFFFF0000000000378C000001000000FFFFFFFFFFFFFFFF0000000000388C000001000000FFFFFFFFFFFFFFFF0000000000398C000001000000FFFFFFFFFFFFFFFF00000000003A8C000001000000FFFFFFFFFFFFFFFF00000000003B8C000001000000FFFFFFFFFFFFFFFF00000000003C8C000001000000FFFFFFFFFFFFFFFF00000000003D8C000001000000FFFFFFFFFFFFFFFF00000000003E8C000001000000FFFFFFFFFFFFFFFF00000000003F8C000001000000FFFFFFFFFFFFFFFF0000000000408C000001000000FFFFFFFFFFFFFFFF0000000000418C000001000000FFFFFFFFFFFFFFFF000000000050C3000001000000FFFFFFFFFFFFFFFF000000000051C3000001000000FFFFFFFFFFFFFFFF000000000052C3000001000000FFFFFFFFFFFFFFFF000000000053C3000001000000FFFFFFFFFFFFFFFF000000000054C3000001000000FFFFFFFFFFFFFFFF000000000055C3000001000000FFFFFFFFFFFFFFFF000000000056C3000001000000FFFFFFFFFFFFFFFF000000000057C3000001000000FFFFFFFFFFFFFFFF000000000058C3000001000000FFFFFFFFFFFFFFFF000000000059C3000001000000FFFFFFFFFFFFFFFF00000000005AC3000001000000FFFFFFFFFFFFFFFF00000000005BC3000001000000FFFFFFFFFFFFFFFF00000000005CC3000001000000FFFFFFFFFFFFFFFF00000000005DC3000001000000FFFFFFFFFFFFFFFF00000000005EC3000001000000FFFFFFFFFFFFFFFF00000000005FC3000001000000FFFFFFFFFFFFFFFF000000000060C3000001000000FFFFFFFFFFFFFFFF000000000061C3000001000000FFFFFFFFFFFFFFFF000000000062C3000001000000FFFFFFFFFFFFFFFF000000000063C3000001000000FFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000000001000000FFFFFFFFE205000001000000FFFFFFFFE2050000000000000010000001000000FFFFFFFFFFFFFFFF630100004F00000067010000A901000001000000020000100400000001000000CAFEFFFF3F060000FFFFFFFF05000000ED0300006D000000C3000000C4000000739400000180001000000100000000000000660000006301000098020000000000004F00000063010000A90100000000000040410056050000000750726F6A65637401000000ED03000001000000FFFFFFFFFFFFFFFF05426F6F6B73010000006D00000001000000FFFFFFFFFFFFFFFF0946756E6374696F6E7301000000C300000001000000FFFFFFFFFFFFFFFF0954656D706C6174657301000000C400000001000000FFFFFFFFFFFFFFFF09526567697374657273000000007394000001000000FFFFFFFFFFFFFFFF00000000000000000000000000000000000000000000000001000000FFFFFFFFED03000001000000FFFFFFFFED030000000000000080000000000000FFFFFFFFFFFFFFFF0000000091010000700400009501000000000000010000000400000001000000000000000000000000000000000000000000000001000000C6000000FFFFFFFF0F0000008F070000930700009407000095070000960700009007000091070000B5010000B801000038030000B9050000BA050000BB050000BC050000CB0900000180008000000000000000000000AC010000700400002E0200000000000095010000700400001702000000000000404100460F0000001343616C6C20537461636B202B204C6F63616C73000000008F07000001000000FFFFFFFFFFFFFFFF0755415254202331000000009307000001000000FFFFFFFFFFFFFFFF0755415254202332000000009407000001000000FFFFFFFFFFFFFFFF0755415254202333000000009507000001000000FFFFFFFFFFFFFFFF15446562756720287072696E74662920566965776572000000009607000001000000FFFFFFFFFFFFFFFF0757617463682031000000009007000001000000FFFFFFFFFFFFFFFF0757617463682032000000009107000001000000FFFFFFFFFFFFFFFF10547261636520457863657074696F6E7300000000B501000001000000FFFFFFFFFFFFFFFF0E4576656E7420436F756E7465727300000000B801000001000000FFFFFFFFFFFFFFFF09554C494E4B706C7573000000003803000001000000FFFFFFFFFFFFFFFF084D656D6F7279203100000000B905000001000000FFFFFFFFFFFFFFFF084D656D6F7279203200000000BA05000001000000FFFFFFFFFFFFFFFF084D656D6F7279203300000000BB05000001000000FFFFFFFFFFFFFFFF084D656D6F7279203400000000BC05000001000000FFFFFFFFFFFFFFFF105472616365204E617669676174696F6E00000000CB09000001000000FFFFFFFFFFFFFFFFFFFFFFFF0000000001000000000000000000000001000000FFFFFFFF38020000950100003C0200001702000000000000020000000400000000000000000000000000000000000000000000000000000002000000C6000000FFFFFFFF8F07000001000000FFFFFFFF8F07000001000000C6000000000000000080000001000000FFFFFFFFFFFFFFFF00000000A901000000060000AD0100000100000001000010040000000100000076FDFFFF02010000FFFFFFFF06000000C5000000C7000000B4010000D2010000CF0100007794000001800080000001000000000000009C02000080070000FD03000000000000AD010000000600000E0300000000000040820056060000000C4275696C64204F757470757401000000C500000001000000FFFFFFFFFFFFFFFF0D46696E6420496E2046696C657301000000C700000001000000FFFFFFFFFFFFFFFF0A4572726F72204C69737400000000B401000001000000FFFFFFFFFFFFFFFF0E536F757263652042726F7773657200000000D201000001000000FFFFFFFFFFFFFFFF0E416C6C205265666572656E63657300000000CF01000001000000FFFFFFFFFFFFFFFF0742726F77736572010000007794000001000000FFFFFFFFFFFFFFFF00000000000000000000000000000000000000000000000001000000FFFFFFFFC500000001000000FFFFFFFFC5000000000000000000000000000000</Data> |
| | | <Len>3332</Len> |
| | | <Data>000000000B000000000000000020000000000000FFFFFFFFFFFFFFFFC4000000BD00000070040000C1000000000000000100000004000000010000000000000000000000FFFFFFFF08000000CB00000057010000CC000000F08B00005A01000079070000D601000045890000FFFF02000B004354616262656450616E650020000000000000C40000006600000070040000D4000000C40000004F00000070040000BD0000000000000040280046080000000B446973617373656D626C7900000000CB00000001000000FFFFFFFFFFFFFFFF14506572666F726D616E636520416E616C797A6572000000005701000001000000FFFFFFFFFFFFFFFF14506572666F726D616E636520416E616C797A657200000000CC00000001000000FFFFFFFFFFFFFFFF0E4C6F67696320416E616C797A657200000000F08B000001000000FFFFFFFFFFFFFFFF0D436F646520436F766572616765000000005A01000001000000FFFFFFFFFFFFFFFF11496E737472756374696F6E205472616365000000007907000001000000FFFFFFFFFFFFFFFF0F53797374656D20416E616C797A657200000000D601000001000000FFFFFFFFFFFFFFFF104576656E742053746174697374696373000000004589000001000000FFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000000001000000FFFFFFFFCB00000001000000FFFFFFFFCB000000000000000040000000000000FFFFFFFFFFFFFFFFAC0300004F000000B0030000A5010000000000000200000004000000010000000000000000000000FFFFFFFF2B000000E2050000CA0900002D8C00002E8C00002F8C0000308C0000318C0000328C0000338C0000348C0000358C0000368C0000378C0000388C0000398C00003A8C00003B8C00003C8C00003D8C00003E8C00003F8C0000408C0000418C000050C3000051C3000052C3000053C3000054C3000055C3000056C3000057C3000058C3000059C300005AC300005BC300005CC300005DC300005EC300005FC3000060C3000061C3000062C3000063C3000001800040000000000000B00300006600000070040000BC010000B00300004F00000070040000A501000000000000404100462B0000000753796D626F6C7300000000E205000001000000FFFFFFFFFFFFFFFF0A5472616365204461746100000000CA09000001000000FFFFFFFFFFFFFFFF00000000002D8C000001000000FFFFFFFFFFFFFFFF00000000002E8C000001000000FFFFFFFFFFFFFFFF00000000002F8C000001000000FFFFFFFFFFFFFFFF0000000000308C000001000000FFFFFFFFFFFFFFFF0000000000318C000001000000FFFFFFFFFFFFFFFF0000000000328C000001000000FFFFFFFFFFFFFFFF0000000000338C000001000000FFFFFFFFFFFFFFFF0000000000348C000001000000FFFFFFFFFFFFFFFF0000000000358C000001000000FFFFFFFFFFFFFFFF0000000000368C000001000000FFFFFFFFFFFFFFFF0000000000378C000001000000FFFFFFFFFFFFFFFF0000000000388C000001000000FFFFFFFFFFFFFFFF0000000000398C000001000000FFFFFFFFFFFFFFFF00000000003A8C000001000000FFFFFFFFFFFFFFFF00000000003B8C000001000000FFFFFFFFFFFFFFFF00000000003C8C000001000000FFFFFFFFFFFFFFFF00000000003D8C000001000000FFFFFFFFFFFFFFFF00000000003E8C000001000000FFFFFFFFFFFFFFFF00000000003F8C000001000000FFFFFFFFFFFFFFFF0000000000408C000001000000FFFFFFFFFFFFFFFF0000000000418C000001000000FFFFFFFFFFFFFFFF000000000050C3000001000000FFFFFFFFFFFFFFFF000000000051C3000001000000FFFFFFFFFFFFFFFF000000000052C3000001000000FFFFFFFFFFFFFFFF000000000053C3000001000000FFFFFFFFFFFFFFFF000000000054C3000001000000FFFFFFFFFFFFFFFF000000000055C3000001000000FFFFFFFFFFFFFFFF000000000056C3000001000000FFFFFFFFFFFFFFFF000000000057C3000001000000FFFFFFFFFFFFFFFF000000000058C3000001000000FFFFFFFFFFFFFFFF000000000059C3000001000000FFFFFFFFFFFFFFFF00000000005AC3000001000000FFFFFFFFFFFFFFFF00000000005BC3000001000000FFFFFFFFFFFFFFFF00000000005CC3000001000000FFFFFFFFFFFFFFFF00000000005DC3000001000000FFFFFFFFFFFFFFFF00000000005EC3000001000000FFFFFFFFFFFFFFFF00000000005FC3000001000000FFFFFFFFFFFFFFFF000000000060C3000001000000FFFFFFFFFFFFFFFF000000000061C3000001000000FFFFFFFFFFFFFFFF000000000062C3000001000000FFFFFFFFFFFFFFFF000000000063C3000001000000FFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000000001000000FFFFFFFFE205000001000000FFFFFFFFE2050000000000000010000001000000FFFFFFFFFFFFFFFF630100004F000000670100004602000001000000020000100400000001000000CAFEFFFF3F060000FFFFFFFF05000000ED0300006D000000C3000000C40000007394000001800010000001000000000000006600000063010000C0010000000000004F00000063010000460200000000000040410056050000000750726F6A65637401000000ED03000001000000FFFFFFFFFFFFFFFF05426F6F6B73010000006D00000001000000FFFFFFFFFFFFFFFF0946756E6374696F6E7301000000C300000001000000FFFFFFFFFFFFFFFF0954656D706C6174657301000000C400000001000000FFFFFFFFFFFFFFFF09526567697374657273000000007394000001000000FFFFFFFFFFFFFFFF00000000000000000000000000000000000000000000000001000000FFFFFFFFED03000001000000FFFFFFFFED030000000000000080000000000000FFFFFFFFFFFFFFFF0000000091010000700400009501000000000000010000000400000001000000000000000000000000000000000000000000000001000000C6000000FFFFFFFF0F0000008F070000930700009407000095070000960700009007000091070000B5010000B801000038030000B9050000BA050000BB050000BC050000CB0900000180008000000000000000000000AC010000700400002E0200000000000095010000700400001702000000000000404100460F0000001343616C6C20537461636B202B204C6F63616C73000000008F07000001000000FFFFFFFFFFFFFFFF0755415254202331000000009307000001000000FFFFFFFFFFFFFFFF0755415254202332000000009407000001000000FFFFFFFFFFFFFFFF0755415254202333000000009507000001000000FFFFFFFFFFFFFFFF15446562756720287072696E74662920566965776572000000009607000001000000FFFFFFFFFFFFFFFF0757617463682031000000009007000001000000FFFFFFFFFFFFFFFF0757617463682032000000009107000001000000FFFFFFFFFFFFFFFF10547261636520457863657074696F6E7300000000B501000001000000FFFFFFFFFFFFFFFF0E4576656E7420436F756E7465727300000000B801000001000000FFFFFFFFFFFFFFFF09554C494E4B706C7573000000003803000001000000FFFFFFFFFFFFFFFF084D656D6F7279203100000000B905000001000000FFFFFFFFFFFFFFFF084D656D6F7279203200000000BA05000001000000FFFFFFFFFFFFFFFF084D656D6F7279203300000000BB05000001000000FFFFFFFFFFFFFFFF084D656D6F7279203400000000BC05000001000000FFFFFFFFFFFFFFFF105472616365204E617669676174696F6E00000000CB09000001000000FFFFFFFFFFFFFFFFFFFFFFFF0000000001000000000000000000000001000000FFFFFFFF38020000950100003C0200001702000000000000020000000400000000000000000000000000000000000000000000000000000002000000C6000000FFFFFFFF8F07000001000000FFFFFFFF8F07000001000000C6000000000000000080000001000000FFFFFFFFFFFFFFFF0000000046020000000600004A0200000100000001000010040000000100000001FEFFFFB500000000000000000000000000000001000000FFFFFFFF06000000C5000000C7000000B4010000D2010000CF0100007794000001800080000001000000D80000009A020000D8060000FB030000000000004A020000000600000E0300000000000040820056060000000C4275696C64204F757470757401000000C500000001000000FFFFFFFFFFFFFFFF0D46696E6420496E2046696C657301000000C700000001000000FFFFFFFFFFFFFFFF0A4572726F72204C69737400000000B401000001000000FFFFFFFFFFFFFFFF0E536F757263652042726F7773657200000000D201000001000000FFFFFFFFFFFFFFFF0E416C6C205265666572656E63657300000000CF01000001000000FFFFFFFFFFFFFFFF0742726F77736572010000007794000001000000FFFFFFFFFFFFFFFF0000000000000000000000000000000000000000000000000000000001000000FFFFFFFFC500000001000000FFFFFFFFC5000000000000000000000000000000</Data> |
| | | </DockMan> |
| | | <ToolBar> |
| | | <RegID>59392</RegID> |
| | | <Name>File</Name> |
| | | <Buttons> |
| | | <Len>2623</Len> |
| | | <Data>00200000010000002800FFFF01001100434D4643546F6F6C426172427574746F6E00E100000000000000000000000000000000000000000000000100000001000000018001E100000000000001000000000000000000000000000000000100000001000000018003E1000000000000020000000000000000000000000000000001000000010000000180CD7F0000000000000300000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF000000000000000000000000000100000001000000018023E100000000040004000000000000000000000000000000000100000001000000018022E100000000040005000000000000000000000000000000000100000001000000018025E10000000000000600000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000001802BE10000000000000700000000000000000000000000000000010000000100000001802CE10000000004000800000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000001807A8A0000000000000900000000000000000000000000000000010000000100000001807B8A0000000004000A00000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180D3B00000000000000B000000000000000000000000000000000100000001000000018015B10000000004000C0000000000000000000000000000000001000000010000000180F4B00000000004000D000000000000000000000000000000000100000001000000018036B10000000004000E00000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180FF88000000000400460000000000000000000000000000000001000000010000000180FE880000000004004500000000000000000000000000000000010000000100000001800B810000000004001300000000000000000000000000000000010000000100000001800C810000000004001400000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180F0880000020000000F000000000000000000000000000000000100000001000000FFFF0100120043555646696E64436F6D626F427574746F6EE80300000000000000000000000000000000000000000000000100000001000000960000000200205000000000104C4F524157414E5F4A4F494E4D4F444596000000000000000500047465737400104C4F524157414E5F4A4F494E4D4F4445114368616E67654C6F72614368616E6E656C086C6F72616D6F64650000000000000000000000000000000000000000018024E10000000000001100000000000000000000000000000000010000000100000001800A810000000000001200000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF000000000000000000000000000100000001000000FFFF01001500434D4643546F6F6C4261724D656E75427574746F6E2280000002000000150000002153746172742F53746F70202644656275672053657373696F6E094374726C2B46350000000000000000000000000100000001000000000000000000000001000000020021802280000000000000150000002153746172742F53746F70202644656275672053657373696F6E094374726C2B4635000000000000000000000000010000000100000000000000000000000100000000002180E0010000000000007500000021456E65726779204D6561737572656D656E742026776974686F75742044656275670000000000000000000000000100000001000000000000000000000001000000000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180C488000000000000160000000000000000000000000000000001000000010000000180C988000000000400180000000000000000000000000000000001000000010000000180C788000000000000190000000000000000000000000000000001000000010000002180C8880000000000001700000027264B696C6C20416C6C20427265616B706F696E747320696E2043757272656E7420546172676574000000000000000000000000010000000100000000000000000000000100000003002180C8880000000000001700000027264B696C6C20416C6C20427265616B706F696E747320696E2043757272656E7420546172676574000000000000000000000000010000000100000000000000000000000100000000002180E50100000000000078000000264B696C6C20416C6C20427265616B706F696E747320696E204163746976652050726F6A656374000000000000000000000000010000000100000000000000000000000100000000002180E601000000000000790000002F4B696C6C20416C6C20427265616B706F696E747320696E204D756C74692D50726F6A65637420576F726B73706163650000000000000000000000000100000001000000000000000000000001000000000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000021804C010000020001001A0000000F2650726F6A6563742057696E646F77000000000000000000000000010000000100000000000000000000000100000008002180DD880000000000001A0000000750726F6A656374000000000000000000000000010000000100000000000000000000000100000000002180DC8B0000000000003A00000005426F6F6B73000000000000000000000000010000000100000000000000000000000100000000002180E18B0000000000003B0000000946756E6374696F6E73000000000000000000000000010000000100000000000000000000000100000000002180E28B000000000000400000000954656D706C6174657300000000000000000000000001000000010000000000000000000000010000000000218018890000000000003D0000000E536F757263652042726F777365720000000000000000000000000100000001000000000000000000000001000000000021800000000000000400FFFFFFFF00000000000000000001000000000000000100000000000000000000000100000000002180D988000000000000390000000C4275696C64204F7574707574000000000000000000000000010000000100000000000000000000000100000000002180E38B000000000000410000000B46696E64204F75747075740000000000000000000000000100000001000000000000000000000001000000000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180FB7F0000000000001B000000000000000000000000000000000100000001000000000000000446696C65C6030000</Data> |
| | | <Len>2716</Len> |
| | | <Data>00200000010000002800FFFF01001100434D4643546F6F6C426172427574746F6E00E100000000000000000000000000000000000000000000000100000001000000018001E100000000000001000000000000000000000000000000000100000001000000018003E1000000000000020000000000000000000000000000000001000000010000000180CD7F0000000000000300000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF000000000000000000000000000100000001000000018023E100000000040004000000000000000000000000000000000100000001000000018022E100000000040005000000000000000000000000000000000100000001000000018025E10000000000000600000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000001802BE10000000004000700000000000000000000000000000000010000000100000001802CE10000000004000800000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000001807A8A0000000000000900000000000000000000000000000000010000000100000001807B8A0000000004000A00000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180D3B00000000000000B000000000000000000000000000000000100000001000000018015B10000000004000C0000000000000000000000000000000001000000010000000180F4B00000000004000D000000000000000000000000000000000100000001000000018036B10000000004000E00000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180FF88000000000400460000000000000000000000000000000001000000010000000180FE880000000004004500000000000000000000000000000000010000000100000001800B810000000004001300000000000000000000000000000000010000000100000001800C810000000004001400000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180F0880000020000000F000000000000000000000000000000000100000001000000FFFF0100120043555646696E64436F6D626F427574746F6EE803000000000000000000000000000000000000000000000001000000010000009600000002002050000000000D5F5F4650555F50524553454E5496000000000000000B000A5F5F4650555F555345440C41524D5F4D4154485F434D37000D5F5F4650555F50524553454E5404656C7365105F5F5441524745545F4650555F5646500B4650555F50524553454E54037468651378506F727453746172745363686564756C65720C707276456E61626C655646500B3D307845303030454438380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018024E10000000000001100000000000000000000000000000000010000000100000001800A810000000000001200000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF000000000000000000000000000100000001000000FFFF01001500434D4643546F6F6C4261724D656E75427574746F6E2280000002000000150000002153746172742F53746F70202644656275672053657373696F6E094374726C2B46350000000000000000000000000100000001000000000000000000000001000000020021802280000000000000150000002153746172742F53746F70202644656275672053657373696F6E094374726C2B4635000000000000000000000000010000000100000000000000000000000100000000002180E0010000000000007500000021456E65726779204D6561737572656D656E742026776974686F75742044656275670000000000000000000000000100000001000000000000000000000001000000000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180C488000000000400160000000000000000000000000000000001000000010000000180C988000000000400180000000000000000000000000000000001000000010000000180C788000000000000190000000000000000000000000000000001000000010000002180C8880000000000001700000027264B696C6C20416C6C20427265616B706F696E747320696E2043757272656E7420546172676574000000000000000000000000010000000100000000000000000000000100000003002180C8880000000000001700000027264B696C6C20416C6C20427265616B706F696E747320696E2043757272656E7420546172676574000000000000000000000000010000000100000000000000000000000100000000002180E50100000000000078000000264B696C6C20416C6C20427265616B706F696E747320696E204163746976652050726F6A656374000000000000000000000000010000000100000000000000000000000100000000002180E601000000000000790000002F4B696C6C20416C6C20427265616B706F696E747320696E204D756C74692D50726F6A65637420576F726B73706163650000000000000000000000000100000001000000000000000000000001000000000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000021804C010000020001001A0000000F2650726F6A6563742057696E646F77000000000000000000000000010000000100000000000000000000000100000008002180DD880000000000001A0000000750726F6A656374000000000000000000000000010000000100000000000000000000000100000000002180DC8B0000000000003A00000005426F6F6B73000000000000000000000000010000000100000000000000000000000100000000002180E18B0000000000003B0000000946756E6374696F6E73000000000000000000000000010000000100000000000000000000000100000000002180E28B000000000000400000000954656D706C6174657300000000000000000000000001000000010000000000000000000000010000000000218018890000000000003D0000000E536F757263652042726F777365720000000000000000000000000100000001000000000000000000000001000000000021800000000000000400FFFFFFFF00000000000000000001000000000000000100000000000000000000000100000000002180D988000000000000390000000C4275696C64204F7574707574000000000000000000000000010000000100000000000000000000000100000000002180E38B000000000000410000000B46696E64204F75747075740000000000000000000000000100000001000000000000000000000001000000000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180FB7F0000000000001B000000000000000000000000000000000100000001000000000000000446696C65C6030000</Data> |
| | | </Buttons> |
| | | <OriginalItems> |
| | | <Len>1423</Len> |
| | |
| | | <Name>Build</Name> |
| | | <Buttons> |
| | | <Len>978</Len> |
| | | <Data>00200000010000001000FFFF01001100434D4643546F6F6C426172427574746F6ECF7F0000000000001C0000000000000000000000000000000001000000010000000180D07F0000000002001D000000000000000000000000000000000100000001000000018030800000000000001E000000000000000000000000000000000100000001000000FFFF01001500434D4643546F6F6C4261724D656E75427574746F6EC7040000000000006A0000000C4261746368204275696C2664000000000000000000000000010000000100000000000000000000000100000004000580C7040000000000006A0000000C4261746368204275696C266400000000000000000000000001000000010000000000000000000000010000000000058046070000000000006B0000000D42617463682052656275696C640000000000000000000000000100000001000000000000000000000001000000000005804707000000000000FFFFFFFF0B426174636820436C65616E0100000000000000000000000100000001000000000000000000000001000000000005809E8A0000000000001F0000000F4261746326682053657475702E2E2E000000000000000000000000010000000100000000000000000000000100000000000180D17F0000000004002000000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000001804C8A0000000000002100000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF000000000000000000000000000100000001000000FFFF01001900434D4643546F6F6C426172436F6D626F426F78427574746F6EBA00000000000000000000000000000000000000000000000001000000010000009600000003002050000000000953544D333248373433960000000000000001000953544D333248373433000000000180EB880000000000002200000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180C07F000000000000230000000000000000000000000000000001000000010000000180B08A000000000400240000000000000000000000000000000001000000010000000180A8010000000000004E00000000000000000000000000000000010000000100000001807202000000000000530000000000000000000000000000000001000000010000000180BE010000000000005000000000000000000000000000000000010000000100000000000000054275696C64DC010000</Data> |
| | | <Data>00200000010000001000FFFF01001100434D4643546F6F6C426172427574746F6ECF7F0000000004001C0000000000000000000000000000000001000000010000000180D07F0000000002001D000000000000000000000000000000000100000001000000018030800000000000001E000000000000000000000000000000000100000001000000FFFF01001500434D4643546F6F6C4261724D656E75427574746F6EC7040000000000006A0000000C4261746368204275696C2664000000000000000000000000010000000100000000000000000000000100000004000580C7040000000000006A0000000C4261746368204275696C266400000000000000000000000001000000010000000000000000000000010000000000058046070000000000006B0000000D42617463682052656275696C640000000000000000000000000100000001000000000000000000000001000000000005804707000000000000FFFFFFFF0B426174636820436C65616E0100000000000000000000000100000001000000000000000000000001000000000005809E8A0000000000001F0000000F4261746326682053657475702E2E2E000000000000000000000000010000000100000000000000000000000100000000000180D17F0000000004002000000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000001804C8A0000000000002100000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF000000000000000000000000000100000001000000FFFF01001900434D4643546F6F6C426172436F6D626F426F78427574746F6EBA00000000000000000000000000000000000000000000000001000000010000009600000003002050000000000953544D333248373433960000000000000001000953544D333248373433000000000180EB880000000000002200000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180C07F000000000000230000000000000000000000000000000001000000010000000180B08A000000000400240000000000000000000000000000000001000000010000000180A8010000000000004E00000000000000000000000000000000010000000100000001807202000000000000530000000000000000000000000000000001000000010000000180BE010000000000005000000000000000000000000000000000010000000100000000000000054275696C64DC010000</Data> |
| | | </Buttons> |
| | | <OriginalItems> |
| | | <Len>583</Len> |
| | |
| | | <Name>Debug</Name> |
| | | <Buttons> |
| | | <Len>2373</Len> |
| | | <Data>00200000000000001900FFFF01001100434D4643546F6F6C426172427574746F6ECC880000000000002500000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF000000000000000000000000000100000001000000018017800000000000002600000000000000000000000000000000010000000100000001801D800000000000002700000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000001801A800000000000002800000000000000000000000000000000010000000100000001801B80000000000000290000000000000000000000000000000001000000010000000180E57F0000000000002A00000000000000000000000000000000010000000100000001801C800000000000002B00000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF000000000000000000000000000100000001000000018000890000000000002C00000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180E48B0000000000002D0000000000000000000000000000000001000000010000000180F07F0000000000002E0000000000000000000000000000000001000000010000000180E8880000000000003700000000000000000000000000000000010000000100000001803B010000000000002F0000000000000000000000000000000001000000010000000180BB8A00000000000030000000000000000000000000000000000100000001000000FFFF01001500434D4643546F6F6C4261724D656E75427574746F6E0E01000000000000310000000D57617463682057696E646F7773000000000000000000000000010000000100000000000000000000000100000003001380D88B00000000000031000000085761746368202631000000000000000000000000010000000100000000000000000000000100000000001380D98B00000000000031000000085761746368202632000000000000000000000000010000000100000000000000000000000100000000001380CE01000000000000FFFFFFFF0C576174636820416E63686F720100000000000000010000000000000001000000000000000000000001000000000013800F01000000000000320000000E4D656D6F72792057696E646F7773000000000000000000000000010000000100000000000000000000000100000004001380D28B00000000000032000000094D656D6F7279202631000000000000000000000000010000000100000000000000000000000100000000001380D38B00000000000032000000094D656D6F7279202632000000000000000000000000010000000100000000000000000000000100000000001380D48B00000000000032000000094D656D6F7279202633000000000000000000000000010000000100000000000000000000000100000000001380D58B00000000000032000000094D656D6F72792026340000000000000000000000000100000001000000000000000000000001000000000013801001000000000000330000000E53657269616C2057696E646F77730000000000000000000000000100000001000000000000000000000001000000040013809307000000000000330000000855415254202326310000000000000000000000000100000001000000000000000000000001000000000013809407000000000000330000000855415254202326320000000000000000000000000100000001000000000000000000000001000000000013809507000000000000330000000855415254202326330000000000000000000000000100000001000000000000000000000001000000000013809607000000000000330000001626446562756720287072696E746629205669657765720000000000000000000000000100000001000000000000000000000001000000000013803C010000000000007200000010416E616C797369732057696E646F7773000000000000000000000000010000000100000000000000000000000100000004001380658A000000000000340000000F264C6F67696320416E616C797A6572000000000000000000000000010000000100000000000000000000000100000000001380DC7F0000000000003E0000001526506572666F726D616E636520416E616C797A6572000000000000000000000000010000000100000000000000000000000100000000001380E788000000000000380000000E26436F646520436F766572616765000000000000000000000000010000000100000000000000000000000100000000001380CD01000000000000FFFFFFFF0F416E616C7973697320416E63686F7201000000000000000100000000000000010000000000000000000000010000000000138053010000000000003F0000000D54726163652057696E646F77730000000000000000000000000100000001000000000000000000000001000000010013805401000000000000FFFFFFFF115472616365204D656E7520416E63686F720100000000000000010000000000000001000000000000000000000001000000000013802901000000000000350000001553797374656D205669657765722057696E646F77730000000000000000000000000100000001000000000000000000000001000000010013804B01000000000000FFFFFFFF1453797374656D2056696577657220416E63686F720100000000000000010000000000000001000000000000000000000001000000000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000013800189000000000000360000000F26546F6F6C626F782057696E646F7700000000000000000000000001000000010000000000000000000000010000000300138044C5000000000000FFFFFFFF0E5570646174652057696E646F77730100000000000000010000000000000001000000000000000000000001000000000013800000000000000400FFFFFFFF000000000000000000010000000000000001000000000000000000000001000000000013805B01000000000000FFFFFFFF12546F6F6C626F78204D656E75416E63686F72010000000000000001000000000000000100000000000000000000000100000000000000000005446562756764020000</Data> |
| | | <Data>00200000000000001900FFFF01001100434D4643546F6F6C426172427574746F6ECC880000000000002500000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF000000000000000000000000000100000001000000018017800000000000002600000000000000000000000000000000010000000100000001801D800000000000002700000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000001801A800000000000002800000000000000000000000000000000010000000100000001801B80000000000000290000000000000000000000000000000001000000010000000180E57F0000000000002A00000000000000000000000000000000010000000100000001801C800000000000002B00000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF000000000000000000000000000100000001000000018000890000000000002C00000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180E48B0000000000002D0000000000000000000000000000000001000000010000000180F07F0000000000002E0000000000000000000000000000000001000000010000000180E8880000000000003700000000000000000000000000000000010000000100000001803B010000000000002F0000000000000000000000000000000001000000010000000180BB8A00000000000030000000000000000000000000000000000100000001000000FFFF01001500434D4643546F6F6C4261724D656E75427574746F6E0E01000000000000310000000D57617463682057696E646F7773000000000000000000000000010000000100000000000000000000000100000003001380D88B00000000000031000000085761746368202631000000000000000000000000010000000100000000000000000000000100000000001380D98B00000000000031000000085761746368202632000000000000000000000000010000000100000000000000000000000100000000001380CE01000000000000FFFFFFFF0C576174636820416E63686F720000000000000000010000000000000001000000000000000000000001000000000013800F01000000000000320000000E4D656D6F72792057696E646F7773000000000000000000000000010000000100000000000000000000000100000004001380D28B00000000000032000000094D656D6F7279202631000000000000000000000000010000000100000000000000000000000100000000001380D38B00000000000032000000094D656D6F7279202632000000000000000000000000010000000100000000000000000000000100000000001380D48B00000000000032000000094D656D6F7279202633000000000000000000000000010000000100000000000000000000000100000000001380D58B00000000000032000000094D656D6F72792026340000000000000000000000000100000001000000000000000000000001000000000013801001000000000000330000000E53657269616C2057696E646F77730000000000000000000000000100000001000000000000000000000001000000040013809307000000000000330000000855415254202326310000000000000000000000000100000001000000000000000000000001000000000013809407000000000000330000000855415254202326320000000000000000000000000100000001000000000000000000000001000000000013809507000000000000330000000855415254202326330000000000000000000000000100000001000000000000000000000001000000000013809607000000000000330000001626446562756720287072696E746629205669657765720000000000000000000000000100000001000000000000000000000001000000000013803C010000000000007200000010416E616C797369732057696E646F7773000000000000000000000000010000000100000000000000000000000100000004001380658A000000000000340000000F264C6F67696320416E616C797A6572000000000000000000000000010000000100000000000000000000000100000000001380DC7F0000000000003E0000001526506572666F726D616E636520416E616C797A6572000000000000000000000000010000000100000000000000000000000100000000001380E788000000000000380000000E26436F646520436F766572616765000000000000000000000000010000000100000000000000000000000100000000001380CD01000000000000FFFFFFFF0F416E616C7973697320416E63686F7200000000000000000100000000000000010000000000000000000000010000000000138053010000000000003F0000000D54726163652057696E646F77730000000000000000000000000100000001000000000000000000000001000000010013805401000000000000FFFFFFFF115472616365204D656E7520416E63686F720000000000000000010000000000000001000000000000000000000001000000000013802901000000000000350000001553797374656D205669657765722057696E646F77730000000000000000000000000100000001000000000000000000000001000000010013804B01000000000000FFFFFFFF1453797374656D2056696577657220416E63686F720000000000000000010000000000000001000000000000000000000001000000000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000013800189000000000000360000000F26546F6F6C626F782057696E646F7700000000000000000000000001000000010000000000000000000000010000000300138044C5000000000000FFFFFFFF0E5570646174652057696E646F77730000000000000000010000000000000001000000000000000000000001000000000013800000000000000400FFFFFFFF000000000000000000010000000000000001000000000000000000000001000000000013805B01000000000000FFFFFFFF12546F6F6C626F78204D656E75416E63686F72000000000000000001000000000000000100000000000000000000000100000000000000000005446562756764020000</Data> |
| | | </Buttons> |
| | | <OriginalItems> |
| | | <Len>898</Len> |
| | |
| | | <ActiveMDIGroup>0</ActiveMDIGroup> |
| | | <MDIGroup> |
| | | <Size>100</Size> |
| | | <ActiveTab>8</ActiveTab> |
| | | <ActiveTab>1</ActiveTab> |
| | | <Doc> |
| | | <Name>..\FML\Internet\Module\EG800\EG800FSM.c</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>237</TopLine> |
| | | <CurrentLine>251</CurrentLine> |
| | | <Name>../Core/Src/system_stm32h7xx.c</Name> |
| | | <ColumnNumber>41</ColumnNumber> |
| | | <TopLine>176</TopLine> |
| | | <CurrentLine>187</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>startup_stm32h743xx.s</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>230</TopLine> |
| | | <CurrentLine>243</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>../Middlewares/Third_Party/FreeRTOS/Source/tasks.c</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>3638</TopLine> |
| | | <CurrentLine>3650</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>..\APL\app.c</Name> |
| | | <ColumnNumber>9</ColumnNumber> |
| | | <TopLine>46</TopLine> |
| | | <CurrentLine>54</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>../Middlewares/Third_Party/FreeRTOS/Source/include/semphr.h</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>278</TopLine> |
| | | <CurrentLine>289</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>..\FML\Internet\Socket.c</Name> |
| | | <ColumnNumber>18</ColumnNumber> |
| | | <TopLine>686</TopLine> |
| | | <CurrentLine>700</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>..\FML\Internet\Module\EG800\EG800Driver.c</Name> |
| | | <ColumnNumber>44</ColumnNumber> |
| | | <TopLine>645</TopLine> |
| | | <CurrentLine>654</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>..\FML\DBG.c</Name> |
| | | <ColumnNumber>35</ColumnNumber> |
| | | <TopLine>421</TopLine> |
| | | <CurrentLine>435</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>..\APL\UDPClient.c</Name> |
| | | <ColumnNumber>4</ColumnNumber> |
| | | <TopLine>474</TopLine> |
| | | <CurrentLine>485</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>..\HAL\Uart.c</Name> |
| | | <ColumnNumber>5</ColumnNumber> |
| | | <TopLine>78</TopLine> |
| | | <CurrentLine>92</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>../Core/Src/main.c</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>125</TopLine> |
| | | <CurrentLine>126</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>..\FML\bluetooth.c</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>153</TopLine> |
| | | <CurrentLine>167</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>..\APL\global_param.c</Name> |
| | | <ColumnNumber>22</ColumnNumber> |
| | | <TopLine>36</TopLine> |
| | | <CurrentLine>49</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>..\APL\AppConfig.h</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>26</TopLine> |
| | | <CurrentLine>40</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>..\HAL\MCUFlash.c</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>267</TopLine> |
| | | <CurrentLine>278</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>../Core/Src/stm32h7xx_it.c</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>104</TopLine> |
| | | <CurrentLine>105</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>..\APL\global_param.h</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>57</TopLine> |
| | | <CurrentLine>66</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>../Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_flash.c</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>288</TopLine> |
| | | <CurrentLine>302</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>../Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_flash.h</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>181</TopLine> |
| | | <CurrentLine>192</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>..\APL\NTRIPApp.c</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>1</TopLine> |
| | | <CurrentLine>1</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>..\APL\Shell.c</Name> |
| | | <ColumnNumber>19</ColumnNumber> |
| | | <TopLine>223</TopLine> |
| | | <CurrentLine>224</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>..\APL\TCPClient.c</Name> |
| | | <ColumnNumber>13</ColumnNumber> |
| | | <TopLine>60</TopLine> |
| | | <CurrentLine>71</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>../HIDOLibrary/Include/HIDO_Shell.h</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>3</TopLine> |
| | | <CurrentLine>17</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>D:\Keil_v5\ARM\ARMCC\include\stdio.h</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>1</TopLine> |
| | | <CurrentLine>1</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>..\FML\GPS.c</Name> |
| | | <ColumnNumber>83</ColumnNumber> |
| | | <TopLine>220</TopLine> |
| | | <CurrentLine>234</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>../HAL/Uart.h</Name> |
| | | <ColumnNumber>15</ColumnNumber> |
| | | <TopLine>36</TopLine> |
| | | <CurrentLine>42</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>../Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart.c</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>306</TopLine> |
| | | <CurrentLine>307</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>../Core/Src/stm32h7xx_hal_msp.c</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>371</TopLine> |
| | | <CurrentLine>385</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>..\APL\serial_at_cmd_app.c</Name> |
| | | <ColumnNumber>21</ColumnNumber> |
| | | <TopLine>4</TopLine> |
| | | <CurrentLine>14</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>..\FML\SBUS.c</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>262</TopLine> |
| | | <CurrentLine>276</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>../HIDOLibrary/Include/HIDO_TYpeDef.h</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>29</TopLine> |
| | | <CurrentLine>39</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>251</TopLine> |
| | | <CurrentLine>265</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>..\FML\pwm_ctrol.c</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>136</TopLine> |
| | | <CurrentLine>150</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>../HIDOLibrary/Include/HIDO_Util.h</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>1</TopLine> |
| | | <CurrentLine>1</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>../FML/pwm_ctrol.h</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>1</TopLine> |
| | | <CurrentLine>1</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>..\FML\PythonLink.c</Name> |
| | | <ColumnNumber>12</ColumnNumber> |
| | | <TopLine>385</TopLine> |
| | | <CurrentLine>399</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>E:\GIT\Lawnmower_STM32H7\STM32H743\HIDOLibrary\Include\HIDO_ModbusCRC16.h</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>1</TopLine> |
| | | <CurrentLine>1</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>..\FML\PythonLink.h</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>20</TopLine> |
| | | <CurrentLine>32</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>../Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>929</TopLine> |
| | | <CurrentLine>939</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>../FML/GPS.h</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>1</TopLine> |
| | | <CurrentLine>1</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.h</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>87</TopLine> |
| | | <CurrentLine>101</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | | </Doc> |
| | | <Doc> |
| | | <Name>../Middlewares/Third_Party/FreeRTOS/Source/portable/RVDS/ARM_CM4F/portmacro.h</Name> |
| | | <ColumnNumber>0</ColumnNumber> |
| | | <TopLine>65</TopLine> |
| | | <CurrentLine>74</CurrentLine> |
| | | <Name>../Drivers/CMSIS/Include/core_cm7.h</Name> |
| | | <ColumnNumber>8</ColumnNumber> |
| | | <TopLine>122</TopLine> |
| | | <CurrentLine>134</CurrentLine> |
| | | <Folding>1</Folding> |
| | | <ContractedFolders></ContractedFolders> |
| | | <PaneID>0</PaneID> |
| | |
| | | <v6Rtti>0</v6Rtti> |
| | | <VariousControls> |
| | | <MiscControls></MiscControls> |
| | | <Define>USE_PWR_LDO_SUPPLY,USE_HAL_DRIVER,STM32H743xx,_USE_OS_,_RTK_MODE_,__EC600S__,__APP_CODE__,__USE_UWB__,__USE_NTRIP__</Define> |
| | | <Define>USE_PWR_LDO_SUPPLY,USE_HAL_DRIVER,STM32H743xx,_USE_OS_,ARM_MATH_DSP</Define> |
| | | <Undefine></Undefine> |
| | | <IncludePath>../Core/Inc;../Drivers/STM32H7xx_HAL_Driver/Inc;../Drivers/STM32H7xx_HAL_Driver/Inc/Legacy;../Middlewares/Third_Party/FreeRTOS/Source/include;../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2;../Middlewares/Third_Party/FreeRTOS/Source/portable/RVDS/ARM_CM4F;../Drivers/CMSIS/Device/ST/STM32H7xx/Include;../Drivers/CMSIS/Include;../HIDOLibrary/Include;../HAL;../FML;../APL;../FML/Internet;../FML/Internet/Module;../FML/Internet/Module/EG800</IncludePath> |
| | | </VariousControls> |
| | |
| | | <RTE> |
| | | <apis/> |
| | | <components> |
| | | <component Cclass="CMSIS" Cgroup="CORE" Cvendor="ARM" Cversion="5.2.0" condition="ARMv6_7_8-M Device"> |
| | | <package name="CMSIS" schemaVersion="1.3" url="http://www.keil.com/pack/" vendor="ARM" version="5.5.1"/> |
| | | <component Cclass="CMSIS" Cgroup="CORE" Cvendor="ARM" Cversion="5.5.0" condition="ARMv6_7_8-M Device"> |
| | | <package name="CMSIS" schemaVersion="1.3" url="http://www.keil.com/pack/" vendor="ARM" version="5.8.0"/> |
| | | <targetInfos> |
| | | <targetInfo name="STM32H743"/> |
| | | </targetInfos> |
| | | </component> |
| | | <component Cclass="CMSIS" Cgroup="DSP" Cvariant="Source" Cvendor="ARM" Cversion="1.9.0-dev" condition="CMSIS DSP"> |
| | | <package name="CMSIS" schemaVersion="1.3" url="http://www.keil.com/pack/" vendor="ARM" version="5.8.0"/> |
| | | <targetInfos> |
| | | <targetInfo name="STM32H743"/> |
| | | </targetInfos> |
| | |
| | | "stm32h743\heap_4.o" |
| | | "stm32h743\port.o" |
| | | "..\HIDOLibrary\HIDOLibrary.lib" |
| | | "stm32h743\basicmathfunctions.o" |
| | | "stm32h743\basicmathfunctionsf16.o" |
| | | "stm32h743\bayesfunctions.o" |
| | | "stm32h743\bayesfunctionsf16.o" |
| | | "stm32h743\commontables.o" |
| | | "stm32h743\commontablesf16.o" |
| | | "stm32h743\complexmathfunctions.o" |
| | | "stm32h743\complexmathfunctionsf16.o" |
| | | "stm32h743\controllerfunctions.o" |
| | | "stm32h743\distancefunctions.o" |
| | | "stm32h743\distancefunctionsf16.o" |
| | | "stm32h743\fastmathfunctions.o" |
| | | "stm32h743\fastmathfunctionsf16.o" |
| | | "stm32h743\filteringfunctions.o" |
| | | "stm32h743\filteringfunctionsf16.o" |
| | | "stm32h743\interpolationfunctions.o" |
| | | "stm32h743\interpolationfunctionsf16.o" |
| | | "stm32h743\matrixfunctions.o" |
| | | "stm32h743\matrixfunctionsf16.o" |
| | | "stm32h743\quaternionmathfunctions.o" |
| | | "stm32h743\svmfunctions.o" |
| | | "stm32h743\svmfunctionsf16.o" |
| | | "stm32h743\statisticsfunctions.o" |
| | | "stm32h743\statisticsfunctionsf16.o" |
| | | "stm32h743\supportfunctions.o" |
| | | "stm32h743\supportfunctionsf16.o" |
| | | "stm32h743\transformfunctions.o" |
| | | "stm32h743\transformfunctionsf16.o" |
| | | --strict --scatter "STM32H743\STM32H743.sct" |
| | | --summary_stderr --info summarysizes --map --load_addr_map_info --xref --callgraph --symbols |
| | | --info sizes --info totals --info unused --info veneers |
| | |
| | | ../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 -I../Middlewares/Third |
| | | _Party/FreeRTOS/Source/portable/RVDS/ARM_CM4F -I../Drivers/CMSIS/Device/ST/STM3 |
| | | 2H7xx/Include -I../Drivers/CMSIS/Include -I.\RTE\_STM32H743 -ID:\Users\zhyin\Ap |
| | | pData\Local\Arm\Packs\ARM\CMSIS\5.8.0\CMSIS\Core\Include --predefine="__UVISION |
| | | _VERSION SETA 530" --predefine="_RTE_ SETA 1" --predefine="STM32H743xx SETA 1" |
| | | --predefine="_RTE_ SETA 1" --list=startup_stm32h743xx.lst startup_stm32h743xx.s |
| | | pData\Local\Arm\Packs\ARM\CMSIS\5.8.0\CMSIS\Core\Include -ID:\Users\zhyin\AppDa |
| | | ta\Local\Arm\Packs\ARM\CMSIS\5.8.0\CMSIS\DSP\Include -ID:\Users\zhyin\AppData\L |
| | | ocal\Arm\Packs\ARM\CMSIS\5.8.0\CMSIS\DSP\PrivateInclude --predefine="__UVISION_ |
| | | VERSION SETA 530" --predefine="_RTE_ SETA 1" --predefine="STM32H743xx SETA 1" - |
| | | -predefine="_RTE_ SETA 1" --list=startup_stm32h743xx.lst startup_stm32h743xx.s |
| | | |
| | | |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | Apache License |
| | | Version 2.0, January 2004 |
| | | http://www.apache.org/licenses/ |
| | | |
| | | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
| | | |
| | | 1. Definitions. |
| | | |
| | | "License" shall mean the terms and conditions for use, reproduction, |
| | | and distribution as defined by Sections 1 through 9 of this document. |
| | | |
| | | "Licensor" shall mean the copyright owner or entity authorized by |
| | | the copyright owner that is granting the License. |
| | | |
| | | "Legal Entity" shall mean the union of the acting entity and all |
| | | other entities that control, are controlled by, or are under common |
| | | control with that entity. For the purposes of this definition, |
| | | "control" means (i) the power, direct or indirect, to cause the |
| | | direction or management of such entity, whether by contract or |
| | | otherwise, or (ii) ownership of fifty percent (50%) or more of the |
| | | outstanding shares, or (iii) beneficial ownership of such entity. |
| | | |
| | | "You" (or "Your") shall mean an individual or Legal Entity |
| | | exercising permissions granted by this License. |
| | | |
| | | "Source" form shall mean the preferred form for making modifications, |
| | | including but not limited to software source code, documentation |
| | | source, and configuration files. |
| | | |
| | | "Object" form shall mean any form resulting from mechanical |
| | | transformation or translation of a Source form, including but |
| | | not limited to compiled object code, generated documentation, |
| | | and conversions to other media types. |
| | | |
| | | "Work" shall mean the work of authorship, whether in Source or |
| | | Object form, made available under the License, as indicated by a |
| | | copyright notice that is included in or attached to the work |
| | | (an example is provided in the Appendix below). |
| | | |
| | | "Derivative Works" shall mean any work, whether in Source or Object |
| | | form, that is based on (or derived from) the Work and for which the |
| | | editorial revisions, annotations, elaborations, or other modifications |
| | | represent, as a whole, an original work of authorship. For the purposes |
| | | of this License, Derivative Works shall not include works that remain |
| | | separable from, or merely link (or bind by name) to the interfaces of, |
| | | the Work and Derivative Works thereof. |
| | | |
| | | "Contribution" shall mean any work of authorship, including |
| | | the original version of the Work and any modifications or additions |
| | | to that Work or Derivative Works thereof, that is intentionally |
| | | submitted to Licensor for inclusion in the Work by the copyright owner |
| | | or by an individual or Legal Entity authorized to submit on behalf of |
| | | the copyright owner. For the purposes of this definition, "submitted" |
| | | means any form of electronic, verbal, or written communication sent |
| | | to the Licensor or its representatives, including but not limited to |
| | | communication on electronic mailing lists, source code control systems, |
| | | and issue tracking systems that are managed by, or on behalf of, the |
| | | Licensor for the purpose of discussing and improving the Work, but |
| | | excluding communication that is conspicuously marked or otherwise |
| | | designated in writing by the copyright owner as "Not a Contribution." |
| | | |
| | | "Contributor" shall mean Licensor and any individual or Legal Entity |
| | | on behalf of whom a Contribution has been received by Licensor and |
| | | subsequently incorporated within the Work. |
| | | |
| | | 2. Grant of Copyright License. Subject to the terms and conditions of |
| | | this License, each Contributor hereby grants to You a perpetual, |
| | | worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
| | | copyright license to reproduce, prepare Derivative Works of, |
| | | publicly display, publicly perform, sublicense, and distribute the |
| | | Work and such Derivative Works in Source or Object form. |
| | | |
| | | 3. Grant of Patent License. Subject to the terms and conditions of |
| | | this License, each Contributor hereby grants to You a perpetual, |
| | | worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
| | | (except as stated in this section) patent license to make, have made, |
| | | use, offer to sell, sell, import, and otherwise transfer the Work, |
| | | where such license applies only to those patent claims licensable |
| | | by such Contributor that are necessarily infringed by their |
| | | Contribution(s) alone or by combination of their Contribution(s) |
| | | with the Work to which such Contribution(s) was submitted. If You |
| | | institute patent litigation against any entity (including a |
| | | cross-claim or counterclaim in a lawsuit) alleging that the Work |
| | | or a Contribution incorporated within the Work constitutes direct |
| | | or contributory patent infringement, then any patent licenses |
| | | granted to You under this License for that Work shall terminate |
| | | as of the date such litigation is filed. |
| | | |
| | | 4. Redistribution. You may reproduce and distribute copies of the |
| | | Work or Derivative Works thereof in any medium, with or without |
| | | modifications, and in Source or Object form, provided that You |
| | | meet the following conditions: |
| | | |
| | | (a) You must give any other recipients of the Work or |
| | | Derivative Works a copy of this License; and |
| | | |
| | | (b) You must cause any modified files to carry prominent notices |
| | | stating that You changed the files; and |
| | | |
| | | (c) You must retain, in the Source form of any Derivative Works |
| | | that You distribute, all copyright, patent, trademark, and |
| | | attribution notices from the Source form of the Work, |
| | | excluding those notices that do not pertain to any part of |
| | | the Derivative Works; and |
| | | |
| | | (d) If the Work includes a "NOTICE" text file as part of its |
| | | distribution, then any Derivative Works that You distribute must |
| | | include a readable copy of the attribution notices contained |
| | | within such NOTICE file, excluding those notices that do not |
| | | pertain to any part of the Derivative Works, in at least one |
| | | of the following places: within a NOTICE text file distributed |
| | | as part of the Derivative Works; within the Source form or |
| | | documentation, if provided along with the Derivative Works; or, |
| | | within a display generated by the Derivative Works, if and |
| | | wherever such third-party notices normally appear. The contents |
| | | of the NOTICE file are for informational purposes only and |
| | | do not modify the License. You may add Your own attribution |
| | | notices within Derivative Works that You distribute, alongside |
| | | or as an addendum to the NOTICE text from the Work, provided |
| | | that such additional attribution notices cannot be construed |
| | | as modifying the License. |
| | | |
| | | You may add Your own copyright statement to Your modifications and |
| | | may provide additional or different license terms and conditions |
| | | for use, reproduction, or distribution of Your modifications, or |
| | | for any such Derivative Works as a whole, provided Your use, |
| | | reproduction, and distribution of the Work otherwise complies with |
| | | the conditions stated in this License. |
| | | |
| | | 5. Submission of Contributions. Unless You explicitly state otherwise, |
| | | any Contribution intentionally submitted for inclusion in the Work |
| | | by You to the Licensor shall be under the terms and conditions of |
| | | this License, without any additional terms or conditions. |
| | | Notwithstanding the above, nothing herein shall supersede or modify |
| | | the terms of any separate license agreement you may have executed |
| | | with Licensor regarding such Contributions. |
| | | |
| | | 6. Trademarks. This License does not grant permission to use the trade |
| | | names, trademarks, service marks, or product names of the Licensor, |
| | | except as required for reasonable and customary use in describing the |
| | | origin of the Work and reproducing the content of the NOTICE file. |
| | | |
| | | 7. Disclaimer of Warranty. Unless required by applicable law or |
| | | agreed to in writing, Licensor provides the Work (and each |
| | | Contributor provides its Contributions) on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| | | implied, including, without limitation, any warranties or conditions |
| | | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
| | | PARTICULAR PURPOSE. You are solely responsible for determining the |
| | | appropriateness of using or redistributing the Work and assume any |
| | | risks associated with Your exercise of permissions under this License. |
| | | |
| | | 8. Limitation of Liability. In no event and under no legal theory, |
| | | whether in tort (including negligence), contract, or otherwise, |
| | | unless required by applicable law (such as deliberate and grossly |
| | | negligent acts) or agreed to in writing, shall any Contributor be |
| | | liable to You for damages, including any direct, indirect, special, |
| | | incidental, or consequential damages of any character arising as a |
| | | result of this License or out of the use or inability to use the |
| | | Work (including but not limited to damages for loss of goodwill, |
| | | work stoppage, computer failure or malfunction, or any and all |
| | | other commercial damages or losses), even if such Contributor |
| | | has been advised of the possibility of such damages. |
| | | |
| | | 9. Accepting Warranty or Additional Liability. While redistributing |
| | | the Work or Derivative Works thereof, You may choose to offer, |
| | | and charge a fee for, acceptance of support, warranty, indemnity, |
| | | or other liability obligations and/or rights consistent with this |
| | | License. However, in accepting such obligations, You may act only |
| | | on Your own behalf and on Your sole responsibility, not on behalf |
| | | of any other Contributor, and only if You agree to indemnify, |
| | | defend, and hold each Contributor harmless for any liability |
| | | incurred by, or claims asserted against, such Contributor by reason |
| | | of your accepting any such warranty or additional liability. |
| | | |
| | | END OF TERMS AND CONDITIONS |
| | | |
| | | APPENDIX: How to apply the Apache License to your work. |
| | | |
| | | To apply the Apache License to your work, attach the following |
| | | boilerplate notice, with the fields enclosed by brackets "{}" |
| | | replaced with your own identifying information. (Don't include |
| | | the brackets!) The text should be enclosed in the appropriate |
| | | comment syntax for the file format. We also recommend that a |
| | | file or class name and description of purpose be included on the |
| | | same "printed page" as the copyright notice for easier |
| | | identification within third-party archives. |
| | | |
| | | Copyright {yyyy} {name of copyright owner} |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | |
| | | Mcu.Pin8=PA2 |
| | | Mcu.Pin9=PA3 |
| | | Mcu.PinsNb=36 |
| | | Mcu.ThirdPartyNb=0 |
| | | Mcu.ThirdParty0=STMicroelectronics.X-CUBE-ALGOBUILD.1.4.0 |
| | | Mcu.ThirdPartyNb=1 |
| | | Mcu.UserConstants= |
| | | Mcu.UserName=STM32H743VITx |
| | | MxCube.Version=6.15.0 |
| | |
| | | SH.S_TIM3_CH2.ConfNb=1 |
| | | SH.S_TIM4_CH1.0=TIM4_CH1,Input_Capture1_from_TI1 |
| | | SH.S_TIM4_CH1.ConfNb=1 |
| | | STMicroelectronics.X-CUBE-ALGOBUILD.1.4.0_SwParameter=LibraryCcDSPOoLibraryJjDSPOoLibrary\:true; |
| | | TIM1.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_DISABLE |
| | | TIM1.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1 |
| | | TIM1.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2 |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 2.65,-5.83;30.10,-52.70;30.10,-52.70;32.70,-53.19;32.70,-53.19;2.02,-0.80;2.02,-0.80;4.15,-0.48;4.15,-0.48;34.49,-52.28;34.49,-52.28;36.26,-51.34;36.26,-51.34;6.28,-0.15;6.28,-0.15;8.40,0.17;8.40,0.17;38.02,-50.40;38.02,-50.40;39.79,-49.45;39.79,-49.45;10.53,0.49;10.53,0.49;12.66,0.82;12.66,0.82;41.56,-48.51;41.56,-48.51;43.32,-47.57;43.32,-47.57;14.79,1.14;14.79,1.14;16.92,1.46;16.92,1.46;45.09,-46.63;45.09,-46.63;46.82,-45.64;46.82,-45.64;19.05,1.79;19.05,1.79;21.18,2.11;21.18,2.11;48.53,-44.60;48.53,-44.60;50.24,-43.56;50.24,-43.56;23.30,2.43;23.30,2.43;25.43,2.76;25.43,2.76;51.95,-42.52;51.95,-42.52;53.66,-41.48;53.66,-41.48;27.56,3.08;27.56,3.08;29.77,3.27;29.77,3.27;55.37,-40.44 |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | { |
| | | "path_file": "E:/GIT/Lawnmower_STM32H7/python/gecaolujing2.txt", |
| | | "origin_gga": "$GNGGA,064327.100,3949.8885025,N,11616.7556143,E,4,31,0.52,46.617,M,-6.678,M,1.0,0409*7E", |
| | | "serial_port": "COM17" |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # 硬件å¨ç¯ (HITL) ä»¿çæ¦è¿° |
| | | |
| | | 为äºå¨ STM32H7 ä¸éªè¯è¿å¨æ§å¶ç®æ³ï¼åæ¶é¿å
çå®å²èç¯å¢å¸¦æ¥çé£é©ï¼`python/hitl` åç®å½è´è´£å®ç°çµè仿ç â STM32H7 çéç¯è°è¯å·¥å
·ãæ ¸å¿ç®æ ï¼ |
| | | |
| | | - **ä¼ æå¨ä»¿ç**ï¼Python 端以 GPS 模åçå®åè®®è¾åº `$GPFMI`ï¼10â¯Hzï¼å `$GPIMU`ï¼100â¯Hzï¼æ°æ®ï¼éè¿ä¸²å£ 2 è¾å
¥å° STM32H7ã |
| | | - **æ§å¶éç¯**ï¼STM32H7 卿¥æ¶å°ä»¿çä¼ æå¨æ°æ®åæ§è¡åææ§å¶ç®æ³ï¼å¹¶ä¾ç
§ `PythonLink` åè®®ï¼åè¿ã转å两个éï¼éè¿ä¸²å£ 2 åä¼ ç» Pythonï¼é©±å¨ä»¿ç卿´æ°è½¦è¾ç¶æã |
| | | - **æ¥å¿éé**ï¼STM32H7 éè¿ä¸²å£ 5ï¼921600â¯bpsï¼è¾åºè°è¯æ¥å¿ï¼Python ç«¯å®æ¶è§£æä¸ä¿åï¼ä¸ºå®è½¦è°è¯æä¾åèã |
| | | |
| | | ## 串å£ä¸åè®®æ å° |
| | | |
| | | | åè½ | STM32H7 ä¸²å£ | æ¹å | åè®®/å
容 | é¢ç | |
| | | | --- | --- | --- | --- | --- | |
| | | | ä¼ æå¨ä»¿çè¾å
¥ | UART2 (RX) | Python â STM32 | `$GPFMI`, `$GPIMU` | 10â¯Hz / 100â¯Hz | |
| | | | æ§å¶è¾åºåä¼ | UART2 (TX) | STM32 â Python | `PythonLink` æ§å¶å¸§ï¼åè¿/转åï¼ | â æ§å¶é¢ç | |
| | | | è°è¯æ¥å¿ | UART5 (TX) | STM32 â Python | çº¯ææ¬æåè®®æ¥å¿ | 宿¶ï¼921600â¯bps | |
| | | |
| | | ## æ°æ®æµæµç¨å¾ |
| | | |
| | | ```mermaid |
| | | flowchart LR |
| | | subgraph PC仿ç端 |
| | | Sim[仿çå¨\nç¶æç§¯å] |
| | | GPFMI[GPFMI帧çæ\n10 Hz] |
| | | GPIMU[GPIMU帧çæ\n100 Hz] |
| | | CtrlRx[PythonLinkæ§å¶å¸§æ¥æ¶] |
| | | LogSink[串å£5æ¥å¿è§£æ/ä¿å] |
| | | end |
| | | subgraph STM32H7 |
| | | UART2["UART2\n(GPS/IMUè¾å
¥ & æ§å¶è¾åº)"] |
| | | CtrlAlgo[è¿å¨æ§å¶ç®æ³\n(PID + 纯è·è¸ª)] |
| | | UART5["UART5\n(921600) æ¥å¿è¾åº"] |
| | | end |
| | | |
| | | Sim --> GPFMI --> |UART2 TX| UART2 |
| | | Sim --> GPIMU --> |UART2 TX| UART2 |
| | | UART2 --> CtrlAlgo |
| | | CtrlAlgo --> |åè¿/è½¬åæ§å¶å¸§| UART2 --> CtrlRx --> Sim |
| | | CtrlAlgo --> |è¿è¡æ¥å¿| UART5 --> |串å£5 RX| LogSink |
| | | ``` |
| | | |
| | | ## åç»å®ç°è¦ç¹ |
| | | |
| | | 1. **åè®®å¤ç¨**ï¼ä¸¥æ ¼å¤ç¨ç°æ GPS `$GPFMI`/`$GPIMU` è¾åºæ ¼å¼ä¸ `PythonLink` æ§å¶å¸§ï¼ä¿è¯å®è½¦ä¸ä»¿çé´å¯æ ç¼åæ¢ã |
| | | 2. **æ¶é´åæ¥**ï¼ä»¿çå¨å
é¨éç»´æ¤ UTC æ¶é´æ³ï¼Week/ToW ä¸ `hhmmss.ss`ï¼ï¼è®© STM32H7 é»è¾ä¿æä¸è´ã |
| | | 3. **é«é¢ä»»å¡åå**ï¼å»ºè®®ä½¿ç¨ç¬ç«çº¿ç¨/弿¥ä»»å¡åå«åé 10â¯Hz ä¸ 100â¯Hz æ°æ®å¸§ï¼å¹¶å¯¹æ§å¶åä¼ ãæ¥å¿æ¥æ¶è¿è¡éé»å¡å¤çã |
| | | 4. **ä»¿çæ¨¡å**ï¼åç»å¯æ©å±ä¸ºè¯»åè§åè·¯å¾ï¼å©ç¨ ENU åæ ç³»è¿è¡è¿å¨å¦ç§¯åï¼å¹¶æç»ææ å°åç»çº¬åº¦/æ¯å¯¼éã |
| | | 5. **æ°æ®æä¹
å**ï¼æ¥å¿ä¸ä»¿çé
ç½®ï¼è·¯å¾ãåå§åç¹ã串å£å·ï¼åºä¿å以便å¤ç°æµè¯åºæ¯ã |
| | | |
| | | 该 README å°ä½ä¸º HITL åç³»ç»ç设计索å¼ï¼å
·ä½å®ç°ä½äºåç®å½ä¸ç Python 模åä¸ã |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | """ |
| | | 硬件å¨ç¯ (HITL) 仿çåå
ã |
| | | |
| | | 该å
å°å
å«: |
| | | - GPS/IMU æ°æ®ä»¿çä¸åè®®å°è£
|
| | | - PythonLink æ§å¶å¸§æ¡¥æ¥ |
| | | - 䏲壿¥å¿è§£æå·¥å
· |
| | | """ |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | """ |
| | | å·®é履带è¿å¨å¦/å¨å妿¨¡åã |
| | | """ |
| | | |
| | | from __future__ import annotations |
| | | |
| | | import dataclasses |
| | | import math |
| | | import random |
| | | from typing import Tuple |
| | | |
| | | GRAVITY = 9.80665 # m/s^2 |
| | | |
| | | |
| | | def _clamp(value: float, min_value: float, max_value: float) -> float: |
| | | return max(min_value, min(max_value, value)) |
| | | |
| | | |
| | | def _wrap_angle(rad: float) -> float: |
| | | """Wrap angle to [-pi, pi).""" |
| | | pi2 = math.tau # 2*pi |
| | | while rad >= math.pi: |
| | | rad -= pi2 |
| | | while rad < -math.pi: |
| | | rad += pi2 |
| | | return rad |
| | | |
| | | |
| | | @dataclasses.dataclass |
| | | class DifferentialDriveState: |
| | | east: float = 0.0 |
| | | north: float = 0.0 |
| | | up: float = 0.0 |
| | | heading: float = 0.0 # rad, æ°å¦åæ ç³» (ä¸=0, CCW>0) |
| | | linear_velocity: float = 0.0 # m/s |
| | | angular_velocity: float = 0.0 # rad/s |
| | | pitch_deg: float = 0.0 |
| | | roll_deg: float = 0.0 |
| | | east_velocity: float = 0.0 |
| | | north_velocity: float = 0.0 |
| | | up_velocity: float = 0.0 |
| | | body_accel_g: Tuple[float, float, float] = (0.0, 0.0, -1.0) |
| | | gyro_deg_s: Tuple[float, float, float] = (0.0, 0.0, 0.0) |
| | | temperature_c: float = 30.0 |
| | | |
| | | def copy(self) -> "DifferentialDriveState": |
| | | return dataclasses.replace(self) |
| | | |
| | | |
| | | class DifferentialDriveModel: |
| | | """åéæå·®é履带模åï¼å¯æ¨¡æåå°è½¬åã""" |
| | | |
| | | def __init__( |
| | | self, |
| | | track_width: float = 0.8, |
| | | max_linear_speed: float = 2.0, |
| | | max_linear_accel: float = 1.5, |
| | | max_angular_speed: float = math.radians(120.0), |
| | | max_angular_accel: float = math.radians(180.0), |
| | | ): |
| | | self.track_width = track_width |
| | | self.max_linear_speed = max_linear_speed |
| | | self.max_linear_accel = max_linear_accel |
| | | self.max_angular_speed = max_angular_speed |
| | | self.max_angular_accel = max_angular_accel |
| | | self.state = DifferentialDriveState() |
| | | self._rng = random.Random(42) |
| | | |
| | | def reset(self, east: float = 0.0, north: float = 0.0, up: float = 0.0, heading_deg: float = 0.0): |
| | | self.state = DifferentialDriveState(east=east, north=north, up=up, heading=math.radians(heading_deg)) |
| | | |
| | | def step(self, target_linear: float, target_angular: float, dt: float) -> DifferentialDriveState: |
| | | if dt <= 0.0: |
| | | return self.state |
| | | |
| | | target_linear = _clamp(target_linear, -self.max_linear_speed, self.max_linear_speed) |
| | | target_angular = _clamp(target_angular, -self.max_angular_speed, self.max_angular_speed) |
| | | |
| | | dv = target_linear - self.state.linear_velocity |
| | | max_dv = self.max_linear_accel * dt |
| | | dv = _clamp(dv, -max_dv, max_dv) |
| | | linear_acc = dv / dt |
| | | self.state.linear_velocity += dv |
| | | |
| | | dw = target_angular - self.state.angular_velocity |
| | | max_dw = self.max_angular_accel * dt |
| | | dw = _clamp(dw, -max_dw, max_dw) |
| | | angular_acc = dw / dt |
| | | self.state.angular_velocity += dw |
| | | |
| | | # æ´æ°å§¿æä¸ä½ç½® |
| | | self.state.heading = _wrap_angle(self.state.heading + self.state.angular_velocity * dt) |
| | | cos_h = math.cos(self.state.heading) |
| | | sin_h = math.sin(self.state.heading) |
| | | self.state.east += self.state.linear_velocity * cos_h * dt |
| | | self.state.north += self.state.linear_velocity * sin_h * dt |
| | | self.state.up += 0.0 # 坿©å±å°å½¢æ¨¡å |
| | | |
| | | # é度 (ENU) |
| | | self.state.east_velocity = self.state.linear_velocity * cos_h |
| | | self.state.north_velocity = self.state.linear_velocity * sin_h |
| | | self.state.up_velocity = 0.0 |
| | | |
| | | # ä½è½´å é度ï¼ååå é度 + åå¿å é度 |
| | | lateral_acc = self.state.linear_velocity * self.state.angular_velocity |
| | | ax_g = linear_acc / GRAVITY |
| | | ay_g = lateral_acc / GRAVITY |
| | | az_g = -1.0 # å设水平å°é¢ |
| | | self.state.body_accel_g = ( |
| | | ax_g + self._rng.gauss(0.0, 0.002), |
| | | ay_g + self._rng.gauss(0.0, 0.002), |
| | | az_g + self._rng.gauss(0.0, 0.0005), |
| | | ) |
| | | |
| | | # å§¿æè¿ä¼¼ï¼ç±å é度åéæ å°æå°è§åº¦ |
| | | self.state.pitch_deg = math.degrees(math.atan2(ax_g, 1.0)) |
| | | self.state.roll_deg = math.degrees(math.atan2(-ay_g, 1.0)) |
| | | |
| | | self.state.gyro_deg_s = ( |
| | | self._rng.gauss(0.0, 0.01), |
| | | self._rng.gauss(0.0, 0.01), |
| | | math.degrees(self.state.angular_velocity) + self._rng.gauss(0.0, 0.1), |
| | | ) |
| | | |
| | | temp_drift = self._rng.gauss(0.0, 0.0005) |
| | | self.state.temperature_c += temp_drift |
| | | |
| | | return self.state |
| | | |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | """ |
| | | å°çåæ ä¸åè系转æ¢å·¥å
·ã |
| | | |
| | | æä¾ä»¥ä¸è½åï¼ |
| | | - è§£æ GGA/èªå®ä¹æ ¼å¼çåç¹é
ç½® |
| | | - WGS-84 ä¸ç LLA â ECEF â ENU äºè½¬ |
| | | - å° ENU åæ åç®ä¸ºç»çº¬åº¦ |
| | | """ |
| | | |
| | | from __future__ import annotations |
| | | |
| | | import dataclasses |
| | | import math |
| | | from typing import Optional, Tuple |
| | | |
| | | WGS84_A = 6378137.0 # åé¿è½´ |
| | | WGS84_F = 1 / 298.257223563 |
| | | WGS84_E2 = WGS84_F * (2 - WGS84_F) |
| | | WGS84_B = WGS84_A * (1 - WGS84_F) |
| | | WGS84_EP2 = (WGS84_A ** 2 - WGS84_B ** 2) / (WGS84_B ** 2) |
| | | |
| | | |
| | | def dm_to_decimal(dm_value: float) -> float: |
| | | """度å转åè¿å¶åº¦ã""" |
| | | degrees = int(dm_value // 100) |
| | | minutes = dm_value - degrees * 100 |
| | | return degrees + minutes / 60.0 |
| | | |
| | | |
| | | @dataclasses.dataclass(frozen=True) |
| | | class Origin: |
| | | """ENU åèåç¹ã""" |
| | | |
| | | latitude_deg: float |
| | | longitude_deg: float |
| | | altitude_m: float |
| | | |
| | | def __post_init__(self): |
| | | object.__setattr__(self, "latitude_rad", math.radians(self.latitude_deg)) |
| | | object.__setattr__(self, "longitude_rad", math.radians(self.longitude_deg)) |
| | | object.__setattr__(self, "ecef", geo_to_ecef(self.latitude_deg, self.longitude_deg, self.altitude_m)) |
| | | |
| | | |
| | | def parse_origin(origin_geo: str) -> Origin: |
| | | """ |
| | | è§£æåç¹æè¿°: |
| | | 1) 纯 GGA æ¥æ: "$GNGGA,..." |
| | | 2) ç®å: "3949.8890,N,11616.7555,E[,alt]" |
| | | """ |
| | | text = (origin_geo or "").strip() |
| | | if not text: |
| | | raise ValueError("åç¹å符串ä¸è½ä¸ºç©º") |
| | | |
| | | if text.startswith("$") and "GGA" in text.upper(): |
| | | parts = text.split(",") |
| | | if len(parts) < 10: |
| | | raise ValueError("GGA æ¥æåæ®µæ°éä¸è¶³") |
| | | lat_dm = float(parts[2]) |
| | | lat_dir = parts[3].upper() |
| | | lon_dm = float(parts[4]) |
| | | lon_dir = parts[5].upper() |
| | | alt = float(parts[9]) |
| | | |
| | | lat = dm_to_decimal(lat_dm) |
| | | lon = dm_to_decimal(lon_dm) |
| | | if lat_dir == "S": |
| | | lat = -lat |
| | | if lon_dir == "W": |
| | | lon = -lon |
| | | return Origin(lat, lon, alt) |
| | | |
| | | # å
¼å®¹ ",lat,N,lon,E" æ "lat,N,lon,E" |
| | | text = text.lstrip(",") |
| | | parts = [p.strip() for p in text.split(",") if p.strip()] |
| | | if len(parts) not in (4, 5): |
| | | raise ValueError("åç¹æ ¼å¼åºä¸º 'lat,N,lon,E[,alt]' æ GGA æ¥æ") |
| | | lat_dm = float(parts[0]) |
| | | lat_dir = parts[1].upper() |
| | | lon_dm = float(parts[2]) |
| | | lon_dir = parts[3].upper() |
| | | alt = float(parts[4]) if len(parts) == 5 else 0.0 |
| | | |
| | | lat = dm_to_decimal(lat_dm) |
| | | lon = dm_to_decimal(lon_dm) |
| | | if lat_dir == "S": |
| | | lat = -lat |
| | | if lon_dir == "W": |
| | | lon = -lon |
| | | return Origin(lat, lon, alt) |
| | | |
| | | |
| | | def geo_to_ecef(lat_deg: float, lon_deg: float, alt_m: float) -> Tuple[float, float, float]: |
| | | """ç»çº¬åº¦ â ECEFã""" |
| | | lat_rad = math.radians(lat_deg) |
| | | lon_rad = math.radians(lon_deg) |
| | | sin_lat = math.sin(lat_rad) |
| | | cos_lat = math.cos(lat_rad) |
| | | sin_lon = math.sin(lon_rad) |
| | | cos_lon = math.cos(lon_rad) |
| | | |
| | | N = WGS84_A / math.sqrt(1 - WGS84_E2 * sin_lat * sin_lat) |
| | | x = (N + alt_m) * cos_lat * cos_lon |
| | | y = (N + alt_m) * cos_lat * sin_lon |
| | | z = (N * (1 - WGS84_E2) + alt_m) * sin_lat |
| | | return x, y, z |
| | | |
| | | |
| | | def ecef_to_enu(dx: float, dy: float, dz: float, lat0_rad: float, lon0_rad: float) -> Tuple[float, float, float]: |
| | | """ECEF å·®å¼ â ENUã""" |
| | | sin_lat = math.sin(lat0_rad) |
| | | cos_lat = math.cos(lat0_rad) |
| | | sin_lon = math.sin(lon0_rad) |
| | | cos_lon = math.cos(lon0_rad) |
| | | |
| | | east = -sin_lon * dx + cos_lon * dy |
| | | north = -sin_lat * cos_lon * dx - sin_lat * sin_lon * dy + cos_lat * dz |
| | | up = cos_lat * cos_lon * dx + cos_lat * sin_lon * dy + sin_lat * dz |
| | | return east, north, up |
| | | |
| | | |
| | | def enu_to_ecef(east: float, north: float, up: float, lat0_rad: float, lon0_rad: float) -> Tuple[float, float, float]: |
| | | """ENU â ECEF å·®å¼ã""" |
| | | sin_lat = math.sin(lat0_rad) |
| | | cos_lat = math.cos(lat0_rad) |
| | | sin_lon = math.sin(lon0_rad) |
| | | cos_lon = math.cos(lon0_rad) |
| | | |
| | | dx = -sin_lon * east - sin_lat * cos_lon * north + cos_lat * cos_lon * up |
| | | dy = cos_lon * east - sin_lat * sin_lon * north + cos_lat * sin_lon * up |
| | | dz = cos_lat * north + sin_lat * up |
| | | return dx, dy, dz |
| | | |
| | | |
| | | def ecef_to_lla(x: float, y: float, z: float) -> Tuple[float, float, float]: |
| | | """ECEF â LLAã""" |
| | | p = math.hypot(x, y) |
| | | theta = math.atan2(WGS84_A * z, WGS84_B * p) |
| | | sin_theta = math.sin(theta) |
| | | cos_theta = math.cos(theta) |
| | | |
| | | lon = math.atan2(y, x) |
| | | lat = math.atan2( |
| | | z + WGS84_EP2 * WGS84_B * sin_theta ** 3, |
| | | p - WGS84_E2 * WGS84_A * cos_theta ** 3, |
| | | ) |
| | | |
| | | N = WGS84_A / math.sqrt(1 - WGS84_E2 * math.sin(lat) ** 2) |
| | | alt = p / math.cos(lat) - N |
| | | return math.degrees(lat), math.degrees(lon), alt |
| | | |
| | | |
| | | def enu_to_lla(east: float, north: float, up: float, origin: Origin) -> Tuple[float, float, float]: |
| | | """å° ENU åæ è½¬æ¢ä¸ºå®æ¶ç»çº¬åº¦ã""" |
| | | dx, dy, dz = enu_to_ecef(east, north, up, origin.latitude_rad, origin.longitude_rad) |
| | | x = origin.ecef[0] + dx |
| | | y = origin.ecef[1] + dy |
| | | z = origin.ecef[2] + dz |
| | | return ecef_to_lla(x, y, z) |
| | | |
| | | |
| | | def heading_math_to_nav(heading_rad: float) -> float: |
| | | """ |
| | | å°æ°å¦åæ ç³» (ä¸ä¸º0°, CCW为æ£) çèªåè§è½¬æ¢ä¸ºå¯¼èªåæ ç³» (å为0°, 顺æ¶é为æ£)ã |
| | | """ |
| | | heading_deg = math.degrees(heading_rad) |
| | | nav = (90.0 - heading_deg) % 360.0 |
| | | if nav < 0: |
| | | nav += 360.0 |
| | | return nav |
| | | |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | """ |
| | | ä¸ STM32H7 交äºçåè®®å°è£
ï¼ |
| | | - æé $GPRMI / $GPIMU å¥å |
| | | - è§£æ PythonLink æ§å¶å¸§ |
| | | """ |
| | | |
| | | from __future__ import annotations |
| | | |
| | | import math |
| | | import struct |
| | | from dataclasses import dataclass |
| | | from datetime import datetime, timezone |
| | | from typing import Callable, Optional, Tuple |
| | | |
| | | GPS_EPOCH = datetime(1980, 1, 6, tzinfo=timezone.utc) |
| | | |
| | | |
| | | def _ensure_utc(dt: datetime) -> datetime: |
| | | if dt.tzinfo is None: |
| | | return dt.replace(tzinfo=timezone.utc) |
| | | return dt.astimezone(timezone.utc) |
| | | |
| | | |
| | | def gps_week_and_tow(timestamp: datetime) -> Tuple[int, float]: |
| | | dt = _ensure_utc(timestamp) |
| | | delta = dt - GPS_EPOCH |
| | | total_seconds = delta.total_seconds() |
| | | week = int(total_seconds // 604800) |
| | | tow = total_seconds - week * 604800 |
| | | return week, tow |
| | | |
| | | |
| | | def format_hhmmss(timestamp: datetime, decimals: int = 3) -> str: |
| | | dt = _ensure_utc(timestamp) |
| | | base = dt.strftime("%H%M%S") |
| | | frac = dt.microsecond / 1_000_000.0 |
| | | frac_str = f"{frac:.{decimals}f}".split(".")[1] |
| | | return f"{base}.{frac_str}" |
| | | |
| | | |
| | | def nmea_checksum(sentence_without_star: str) -> str: |
| | | cs = 0 |
| | | for ch in sentence_without_star[1:]: # è·³è¿ $ |
| | | cs ^= ord(ch) |
| | | return f"{cs:02X}" |
| | | |
| | | |
| | | def build_gprmi_sentence( |
| | | timestamp: datetime, |
| | | lat_deg: float, |
| | | lon_deg: float, |
| | | alt_m: float, |
| | | east_vel: float, |
| | | north_vel: float, |
| | | up_vel: float, |
| | | heading_deg: float, |
| | | pitch_deg: float, |
| | | roll_deg: float, |
| | | *, |
| | | lat_std: float = 0.008, |
| | | lon_std: float = 0.008, |
| | | alt_std: float = 0.02, |
| | | vel_std: float = 0.02, |
| | | heading_std: float = 0.1, |
| | | pitch_std: float = 0.1, |
| | | roll_std: float = 0.1, |
| | | baseline_m: float = 1.0, |
| | | sat_count: int = 20, |
| | | ambiguity_count: int = 18, |
| | | quality: int = 4, |
| | | ) -> bytes: |
| | | timestamp = _ensure_utc(timestamp) |
| | | utc_str = format_hhmmss(timestamp, decimals=2) |
| | | week, tow = gps_week_and_tow(timestamp) |
| | | |
| | | fields = [ |
| | | utc_str, |
| | | str(week), |
| | | f"{tow:.3f}", |
| | | f"{lat_deg:.9f}", |
| | | f"{lon_deg:.9f}", |
| | | f"{alt_m:.3f}", |
| | | f"{lat_std:.3f}", |
| | | f"{lon_std:.3f}", |
| | | f"{alt_std:.3f}", |
| | | f"{east_vel:.3f}", |
| | | f"{north_vel:.3f}", |
| | | f"{up_vel:.3f}", |
| | | f"{vel_std:.3f}", |
| | | f"{heading_deg:.3f}", |
| | | f"{pitch_deg:.3f}", |
| | | f"{roll_deg:.3f}", |
| | | f"{heading_std:.3f}", |
| | | f"{pitch_std:.3f}", |
| | | f"{roll_std:.3f}", |
| | | f"{baseline_m:.3f}", |
| | | str(int(sat_count)), |
| | | str(int(ambiguity_count)), |
| | | str(int(quality)), |
| | | ] |
| | | |
| | | body = "$GPRMI," + ",".join(fields) |
| | | checksum = nmea_checksum(body) |
| | | sentence = f"{body}*{checksum}\r\n" |
| | | return sentence.encode("ascii") |
| | | |
| | | |
| | | def build_gpimu_sentence( |
| | | timestamp: datetime, |
| | | accel_g: Tuple[float, float, float], |
| | | gyro_deg_s: Tuple[float, float, float], |
| | | temperature_c: float, |
| | | ) -> bytes: |
| | | timestamp = _ensure_utc(timestamp) |
| | | utc_str = format_hhmmss(timestamp, decimals=3) |
| | | |
| | | fields = [ |
| | | utc_str, |
| | | f"{accel_g[0]:+.4f}", |
| | | f"{accel_g[1]:+.4f}", |
| | | f"{accel_g[2]:+.4f}", |
| | | f"{gyro_deg_s[0]:+.4f}", |
| | | f"{gyro_deg_s[1]:+.4f}", |
| | | f"{gyro_deg_s[2]:+.4f}", |
| | | f"{temperature_c:.2f}", |
| | | ] |
| | | |
| | | body = "$GPIMU," + ",".join(fields) |
| | | checksum = nmea_checksum(body) |
| | | sentence = f"{body}*{checksum}\r\n" |
| | | return sentence.encode("ascii") |
| | | |
| | | |
| | | def _pwm_to_velocity(value: int, center: int = 1500, span: int = 500, max_speed: float = 1.5) -> float: |
| | | ratio = _clamp((value - center) / span, -1.0, 1.0) |
| | | return ratio * max_speed |
| | | |
| | | |
| | | def _clamp(val: float, min_val: float, max_val: float) -> float: |
| | | return max(min_val, min(max_val, val)) |
| | | |
| | | |
| | | def _decode_payload(payload: bytes) -> Tuple[float, float]: |
| | | if len(payload) == 8: |
| | | forward, turn = struct.unpack("<ff", payload) |
| | | return forward, turn |
| | | if len(payload) == 4: |
| | | steering_pwm, throttle_pwm = struct.unpack("<HH", payload) |
| | | # éæ°æ å°ï¼è½¬å PWM â yaw rateï¼æ²¹é¨ PWM â 线é度 |
| | | forward = _pwm_to_velocity(throttle_pwm) |
| | | turn = math.radians(_pwm_to_velocity(steering_pwm, max_speed=90.0)) |
| | | return forward, turn |
| | | raise ValueError(f"䏿¯æçæ§å¶è´è½½é¿åº¦: {len(payload)}") |
| | | |
| | | |
| | | @dataclass |
| | | class PythonLinkFrame: |
| | | forward: float |
| | | turn: float |
| | | |
| | | |
| | | class PythonLinkDecoder: |
| | | """ |
| | | è§£æ PythonLink æ§å¶å¸§ (0xAA 0x55 ... 0D 0A)ã |
| | | """ |
| | | |
| | | FRAME_HEADER = b"\xAA\x55" |
| | | FRAME_FOOTER = b"\x0D\x0A" |
| | | TYPE_CONTROL = 0x10 |
| | | |
| | | def __init__(self, on_frame: Callable[[PythonLinkFrame], None]): |
| | | self._buffer = bytearray() |
| | | self._on_frame = on_frame |
| | | |
| | | def feed(self, data: bytes): |
| | | if not data: |
| | | return |
| | | self._buffer.extend(data) |
| | | while True: |
| | | start = self._find_header() |
| | | if start < 0: |
| | | self._buffer.clear() |
| | | return |
| | | if start > 0: |
| | | del self._buffer[:start] |
| | | if len(self._buffer) < 9: |
| | | return |
| | | frame_len = self._expected_frame_length() |
| | | if frame_len is None or len(self._buffer) < frame_len: |
| | | return |
| | | frame = bytes(self._buffer[:frame_len]) |
| | | del self._buffer[:frame_len] |
| | | try: |
| | | parsed = self._parse_frame(frame) |
| | | if parsed: |
| | | self._on_frame(parsed) |
| | | except Exception: |
| | | # 䏢弿 æå¸§ï¼ç»§ç»æç´¢ |
| | | continue |
| | | |
| | | def _find_header(self) -> int: |
| | | data = bytes(self._buffer) |
| | | idx = data.find(self.FRAME_HEADER) |
| | | return idx |
| | | |
| | | def _expected_frame_length(self) -> Optional[int]: |
| | | if len(self._buffer) < 5: |
| | | return None |
| | | payload_len = int.from_bytes(self._buffer[3:5], "little") |
| | | return 2 + 1 + 2 + payload_len + 2 + 2 # header + type + len + payload + checksum + footer |
| | | |
| | | def _parse_frame(self, frame: bytes) -> Optional[PythonLinkFrame]: |
| | | if not (frame.startswith(self.FRAME_HEADER) and frame.endswith(self.FRAME_FOOTER)): |
| | | return None |
| | | frame_type = frame[2] |
| | | if frame_type != self.TYPE_CONTROL: |
| | | return None |
| | | payload_len = int.from_bytes(frame[3:5], "little") |
| | | payload_start = 5 |
| | | payload_end = payload_start + payload_len |
| | | payload = frame[payload_start:payload_end] |
| | | checksum_received = int.from_bytes(frame[payload_end:payload_end + 2], "little") |
| | | checksum_calc = sum(frame[2:payload_end]) & 0xFFFF |
| | | if checksum_received != checksum_calc: |
| | | raise ValueError("æ ¡éªåä¸å¹é
") |
| | | forward, turn = _decode_payload(payload) |
| | | return PythonLinkFrame(forward=forward, turn=turn) |
| | | |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | """ |
| | | 硬件å¨ç¯ (HITL) 仿çå¨ï¼çæ $GPRMI/$GPIMU ä¼ æå¨æ°æ®ï¼å¹¶ä¸ STM32H7 éè¿ PythonLink éç¯ã |
| | | """ |
| | | |
| | | from __future__ import annotations |
| | | |
| | | import dataclasses |
| | | import math |
| | | import threading |
| | | import time |
| | | from datetime import datetime, timedelta, timezone |
| | | from typing import Callable |
| | | |
| | | import serial |
| | | |
| | | from . import geo |
| | | from .dynamics import DifferentialDriveModel, DifferentialDriveState |
| | | from .protocols import ( |
| | | PythonLinkDecoder, |
| | | PythonLinkFrame, |
| | | build_gpimu_sentence, |
| | | build_gprmi_sentence, |
| | | ) |
| | | |
| | | |
| | | @dataclasses.dataclass |
| | | class HitlConfig: |
| | | """HITL 仿çè¿è¡å¿
éçé
置项ã""" |
| | | |
| | | uart2_port: str # STM32 UART2 (GPS/IMU è¾å
¥ + æ§å¶è¾åº) |
| | | uart5_port: str | None # STM32 UART5 æ¥å¿è¾åº |
| | | origin_gga: str |
| | | initial_enu: tuple[float, float, float] = (0.0, 0.0, 0.0) |
| | | initial_heading_deg: float = 0.0 |
| | | gps_baudrate: int = 460800 |
| | | log_baudrate: int = 921600 |
| | | track_width: float = 0.78 |
| | | baseline_distance: float = 0.9 |
| | | max_linear_speed: float = 2.0 |
| | | max_angular_speed_deg: float = 140.0 |
| | | |
| | | |
| | | class SerialEndpoint: |
| | | """线ç¨å®å
¨ç串å£å
è£
ã""" |
| | | |
| | | port: str | None |
| | | baudrate: int |
| | | timeout: float |
| | | _serial: serial.Serial | None |
| | | _lock: threading.Lock |
| | | |
| | | def __init__(self, port: str | None, baudrate: int, timeout: float = 0.0): |
| | | self.port = port |
| | | self.baudrate = baudrate |
| | | self.timeout = timeout |
| | | self._serial = None |
| | | self._lock = threading.Lock() |
| | | |
| | | def open(self): |
| | | if not self.port: |
| | | return |
| | | if self._serial and self._serial.is_open: |
| | | return |
| | | self._serial = serial.Serial( |
| | | self.port, |
| | | self.baudrate, |
| | | timeout=self.timeout, |
| | | write_timeout=0, |
| | | ) |
| | | self._serial.reset_input_buffer() |
| | | self._serial.reset_output_buffer() |
| | | |
| | | def close(self): |
| | | if self._serial: |
| | | try: |
| | | self._serial.close() |
| | | finally: |
| | | self._serial = None |
| | | |
| | | def write(self, data: bytes): |
| | | if not data or not self._serial: |
| | | return |
| | | with self._lock: |
| | | _ = self._serial.write(data) |
| | | |
| | | def read(self, size: int = 1) -> bytes: |
| | | if not self._serial: |
| | | return b"" |
| | | try: |
| | | return self._serial.read(size) |
| | | except serial.SerialException: |
| | | return b"" |
| | | |
| | | def readline(self) -> bytes: |
| | | if not self._serial: |
| | | return b"" |
| | | try: |
| | | return self._serial.readline() |
| | | except serial.SerialException: |
| | | return b"" |
| | | |
| | | |
| | | class HitlSimulator: |
| | | """çµè仿çç¯å¢ä¸ STM32H7 æ§å¶æ¿ä¹é´çæ¡¥æ¢ã""" |
| | | |
| | | config: HitlConfig |
| | | origin: geo.Origin |
| | | model: DifferentialDriveModel |
| | | _state_lock: threading.Lock |
| | | _latest_state: DifferentialDriveState |
| | | _target_linear: float |
| | | _target_angular: float |
| | | _sim_time: datetime |
| | | uart2: SerialEndpoint |
| | | log_uart: SerialEndpoint |
| | | _decoder: PythonLinkDecoder |
| | | _running: threading.Event |
| | | _threads: list[threading.Thread] |
| | | on_control: Callable[[float, float], None] | None |
| | | on_log: Callable[[str], None] | None |
| | | |
| | | def __init__(self, config: HitlConfig): |
| | | self.config = config |
| | | self.origin = geo.parse_origin(config.origin_gga) |
| | | self.model = DifferentialDriveModel( |
| | | track_width=config.track_width, |
| | | max_linear_speed=config.max_linear_speed, |
| | | max_angular_speed=math.radians(config.max_angular_speed_deg), |
| | | ) |
| | | self.model.reset( |
| | | east=config.initial_enu[0], |
| | | north=config.initial_enu[1], |
| | | up=config.initial_enu[2], |
| | | heading_deg=config.initial_heading_deg, |
| | | ) |
| | | self._state_lock = threading.Lock() |
| | | self._latest_state = self.model.state.copy() |
| | | self._target_linear = 0.0 |
| | | self._target_angular = 0.0 |
| | | self._sim_time = _initial_timestamp_from_gga(config.origin_gga) |
| | | |
| | | self.uart2 = SerialEndpoint(config.uart2_port, config.gps_baudrate, timeout=0.0) |
| | | self.log_uart = SerialEndpoint(config.uart5_port, config.log_baudrate, timeout=0.1) |
| | | |
| | | self._decoder = PythonLinkDecoder(self._handle_control_frame) |
| | | self._running = threading.Event() |
| | | self._threads = [] |
| | | |
| | | self.on_control = None |
| | | self.on_log = None |
| | | |
| | | # ------------------------------------------------------------------ # |
| | | # çå½å¨æ |
| | | # ------------------------------------------------------------------ # |
| | | def start(self): |
| | | if self._running.is_set(): |
| | | return |
| | | self.uart2.open() |
| | | self.log_uart.open() |
| | | self._running.set() |
| | | self._threads = [ |
| | | threading.Thread(target=self._loop_physics, name="hitl-phys", daemon=True), |
| | | threading.Thread(target=self._loop_gprmi, name="hitl-gprmi", daemon=True), |
| | | threading.Thread(target=self._loop_gpimu, name="hitl-gpimu", daemon=True), |
| | | threading.Thread(target=self._loop_control, name="hitl-ctrl", daemon=True), |
| | | threading.Thread(target=self._loop_log, name="hitl-log", daemon=True), |
| | | ] |
| | | for t in self._threads: |
| | | t.start() |
| | | |
| | | def stop(self): |
| | | if not self._running.is_set(): |
| | | return |
| | | self._running.clear() |
| | | for t in self._threads: |
| | | t.join(timeout=1.0) |
| | | self._threads.clear() |
| | | self.uart2.close() |
| | | self.log_uart.close() |
| | | |
| | | # ------------------------------------------------------------------ # |
| | | # çº¿ç¨ |
| | | # ------------------------------------------------------------------ # |
| | | def _loop_physics(self): |
| | | last = time.perf_counter() |
| | | while self._running.is_set(): |
| | | now = time.perf_counter() |
| | | dt = max(now - last, 1e-4) |
| | | last = now |
| | | with self._state_lock: |
| | | state = self.model.step(self._target_linear, self._target_angular, dt).copy() |
| | | self._latest_state = state |
| | | self._sim_time += timedelta(seconds=dt) |
| | | time.sleep(0.005) |
| | | |
| | | def _loop_gprmi(self): |
| | | period = 0.1 # 10 Hz |
| | | while self._running.is_set(): |
| | | start = time.perf_counter() |
| | | sentence = self._build_gprmi_sentence() |
| | | if sentence: |
| | | self.uart2.write(sentence) |
| | | self._sleep_remaining(start, period) |
| | | |
| | | def _loop_gpimu(self): |
| | | period = 0.01 # 100 Hz |
| | | while self._running.is_set(): |
| | | start = time.perf_counter() |
| | | sentence = self._build_gpimu_sentence() |
| | | if sentence: |
| | | self.uart2.write(sentence) |
| | | self._sleep_remaining(start, period) |
| | | |
| | | def _loop_control(self): |
| | | while self._running.is_set(): |
| | | data = self.uart2.read(128) |
| | | if data: |
| | | self._decoder.feed(data) |
| | | else: |
| | | time.sleep(0.002) |
| | | |
| | | def _loop_log(self): |
| | | if not self.config.uart5_port: |
| | | while self._running.is_set(): |
| | | time.sleep(0.5) |
| | | return |
| | | while self._running.is_set(): |
| | | line = self.log_uart.readline() |
| | | if not line: |
| | | time.sleep(0.01) |
| | | continue |
| | | text = line.decode("utf-8", errors="replace").strip() |
| | | if text and self.on_log: |
| | | self.on_log(text) |
| | | |
| | | # ------------------------------------------------------------------ # |
| | | # æé 帧 |
| | | # ------------------------------------------------------------------ # |
| | | def _build_gprmi_sentence(self) -> bytes | None: |
| | | state, timestamp = self._snapshot() |
| | | lat, lon, alt = geo.enu_to_lla(state.east, state.north, state.up, self.origin) |
| | | heading_nav = geo.heading_math_to_nav(state.heading) |
| | | return build_gprmi_sentence( |
| | | timestamp=timestamp, |
| | | lat_deg=lat, |
| | | lon_deg=lon, |
| | | alt_m=alt, |
| | | east_vel=state.east_velocity, |
| | | north_vel=state.north_velocity, |
| | | up_vel=state.up_velocity, |
| | | heading_deg=heading_nav, |
| | | pitch_deg=state.pitch_deg, |
| | | roll_deg=state.roll_deg, |
| | | baseline_m=self.config.baseline_distance, |
| | | ) |
| | | |
| | | def _build_gpimu_sentence(self) -> bytes | None: |
| | | state, timestamp = self._snapshot() |
| | | return build_gpimu_sentence( |
| | | timestamp=timestamp, |
| | | accel_g=state.body_accel_g, |
| | | gyro_deg_s=state.gyro_deg_s, |
| | | temperature_c=state.temperature_c, |
| | | ) |
| | | |
| | | # ------------------------------------------------------------------ # |
| | | # å·¥å
· |
| | | # ------------------------------------------------------------------ # |
| | | def _snapshot(self) -> tuple[DifferentialDriveState, datetime]: |
| | | with self._state_lock: |
| | | return self._latest_state.copy(), self._sim_time |
| | | |
| | | def _handle_control_frame(self, frame: PythonLinkFrame): |
| | | with self._state_lock: |
| | | self._target_linear = frame.forward |
| | | self._target_angular = frame.turn |
| | | if self.on_control: |
| | | self.on_control(frame.forward, frame.turn) |
| | | |
| | | @staticmethod |
| | | def _sleep_remaining(start: float, period: float): |
| | | elapsed = time.perf_counter() - start |
| | | remaining = period - elapsed |
| | | if remaining > 0: |
| | | time.sleep(remaining) |
| | | |
| | | |
| | | def _initial_timestamp_from_gga(gga: str) -> datetime: |
| | | parts = (gga or "").split(",") |
| | | if len(parts) > 1 and parts[1]: |
| | | time_str = parts[1] |
| | | try: |
| | | hh = int(time_str[0:2]) |
| | | mm = int(time_str[2:4]) |
| | | ss = int(time_str[4:6]) |
| | | frac = float("0." + time_str.split(".")[1]) if "." in time_str else 0.0 |
| | | today = datetime.now(timezone.utc).date() |
| | | base = datetime(today.year, today.month, today.day, tzinfo=timezone.utc) |
| | | return base.replace(hour=hh, minute=mm, second=ss, microsecond=int(frac * 1_000_000)) |
| | | except (ValueError, IndexError): |
| | | pass |
| | | return datetime.now(timezone.utc) |
| | | |
| | |
| | | import time |
| | | import json |
| | | import math |
| | | from typing import Optional, Tuple |
| | | import threading |
| | | import queue |
| | | from pathlib import Path |
| | | from typing import Callable, Dict, Optional, Tuple |
| | | |
| | | from serial.tools import list_ports |
| | | from gps_imu_receiver import GPSIMUReceiver, GPSData, IMUData |
| | | from mower_controller import MowerController, wrap_angle |
| | | |
| | | try: |
| | | from PyQt5 import QtCore, QtGui, QtWidgets |
| | | except Exception: |
| | | QtWidgets = None |
| | | |
| | | BASE_DIR = Path(__file__).resolve().parent |
| | | GUI_STATE_FILE = BASE_DIR / "gui_state.json" |
| | | GUI_STATE_DEFAULT = { |
| | | "path_file": "", |
| | | "origin_gga": "", |
| | | "serial_port": "", |
| | | } |
| | | |
| | | |
| | | def load_gui_state() -> Dict[str, str]: |
| | | state = dict(GUI_STATE_DEFAULT) |
| | | try: |
| | | if GUI_STATE_FILE.exists(): |
| | | with GUI_STATE_FILE.open('r', encoding='utf-8') as f: |
| | | data = json.load(f) |
| | | if isinstance(data, dict): |
| | | state.update(data) |
| | | except Exception as exc: |
| | | print(f"[WARN] 读å GUI é
置失败: {exc}") |
| | | return state |
| | | |
| | | |
| | | def save_gui_state(state: Dict[str, str]) -> None: |
| | | try: |
| | | GUI_STATE_FILE.parent.mkdir(parents=True, exist_ok=True) |
| | | with GUI_STATE_FILE.open('w', encoding='utf-8') as f: |
| | | json.dump(state, f, ensure_ascii=False, indent=2) |
| | | except Exception as exc: |
| | | print(f"[WARN] ä¿å GUI é
置失败: {exc}") |
| | | |
| | | |
| | | EARTH_RADIUS_M = 6378137.0 |
| | | WGS84_A = 6378137.0 # åé¿è½´ |
| | |
| | | return east, north, up |
| | | |
| | | |
| | | if QtWidgets: |
| | | class ZoomableGraphicsView(QtWidgets.QGraphicsView): |
| | | """æ¯ææ»è½®ç¼©æ¾ä¸ææ½çè§å¾""" |
| | | |
| | | def __init__(self, scene, parent=None): |
| | | super().__init__(scene, parent) |
| | | self.setRenderHint(QtGui.QPainter.Antialiasing, True) |
| | | self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag) |
| | | self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse) |
| | | self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse) |
| | | self.setViewportUpdateMode(QtWidgets.QGraphicsView.SmartViewportUpdate) |
| | | self._zoom = 0 |
| | | |
| | | def wheelEvent(self, event: QtGui.QWheelEvent): |
| | | zoom_in_factor = 1.15 |
| | | zoom_out_factor = 1 / zoom_in_factor |
| | | |
| | | if event.angleDelta().y() > 0: |
| | | factor = zoom_in_factor |
| | | self._zoom += 1 |
| | | else: |
| | | factor = zoom_out_factor |
| | | self._zoom -= 1 |
| | | |
| | | if self._zoom > 50: |
| | | self._zoom = 50 |
| | | return |
| | | if self._zoom < -50: |
| | | self._zoom = -50 |
| | | return |
| | | |
| | | self.scale(factor, factor) |
| | | |
| | | def reset_zoom(self): |
| | | self._zoom = 0 |
| | | self.resetTransform() |
| | | |
| | | |
| | | class QtRealtimeDashboard(QtWidgets.QMainWindow): |
| | | """主线ç¨ä¸ç Qt ç¶æé¢æ¿ï¼å®æ¶ä»éååæ°æ®å·æ°""" |
| | | |
| | | def __init__( |
| | | self, |
| | | controller, |
| | | data_queue: queue.Queue, |
| | | gui_state: Dict[str, str], |
| | | persist_state: Callable[[Dict[str, str]], None], |
| | | ): |
| | | super().__init__() |
| | | self.controller = controller |
| | | self.data_queue = data_queue |
| | | self.gui_state = gui_state or {} |
| | | self.persist_state_cb = persist_state |
| | | self.control_thread: Optional[threading.Thread] = None |
| | | self._last_gui_consume_log = 0.0 |
| | | self._fit_applied = False |
| | | self._path_rect = QtCore.QRectF() |
| | | self.path_points = list(controller.path_points or []) |
| | | |
| | | self.setWindowTitle("Lawnmower è¿å¨æ§å¶è°è¯çé¢") |
| | | self.resize(1200, 680) |
| | | |
| | | self._build_ui() |
| | | self.set_path_points(self.path_points, refit=True) |
| | | self._refresh_serial_ports(initial=True) |
| | | self._apply_saved_values() |
| | | self._update_serial_ui() |
| | | self._update_control_buttons() |
| | | |
| | | self.timer = QtCore.QTimer() |
| | | self.timer.timeout.connect(self._drain_queue) |
| | | self.timer.start(80) # ~12.5Hz å·æ° |
| | | |
| | | def _build_ui(self): |
| | | central = QtWidgets.QWidget() |
| | | layout = QtWidgets.QHBoxLayout(central) |
| | | self.setCentralWidget(central) |
| | | |
| | | self.scene = QtWidgets.QGraphicsScene() |
| | | self.view = ZoomableGraphicsView(self.scene) |
| | | layout.addWidget(self.view, stretch=3) |
| | | |
| | | self.path_pen = QtGui.QPen(QtGui.QColor("gray")) |
| | | self.path_pen.setStyle(QtCore.Qt.DashLine) |
| | | self.path_pen.setWidthF(0.8) |
| | | self.path_pen.setCosmetic(True) |
| | | self.path_item = self.scene.addPath(QtGui.QPainterPath(), self.path_pen) |
| | | |
| | | trail_pen = QtGui.QPen(QtGui.QColor("blue")) |
| | | trail_pen.setWidthF(1.0) |
| | | trail_pen.setCosmetic(True) |
| | | self.trail_path_item = self.scene.addPath(QtGui.QPainterPath(), trail_pen) |
| | | |
| | | self.heading_item = self.scene.addLine(0, 0, 0, 0, QtGui.QPen(QtGui.QColor("red"), 2)) |
| | | robot_pen = QtGui.QPen(QtGui.QColor("red")) |
| | | robot_brush = QtGui.QBrush(QtGui.QColor("red")) |
| | | self.robot_item = self.scene.addEllipse(-0.3, -0.3, 0.6, 0.6, robot_pen, robot_brush) |
| | | target_pen = QtGui.QPen(QtGui.QColor("green")) |
| | | target_brush = QtGui.QBrush(QtGui.QColor("green")) |
| | | self.target_item = self.scene.addEllipse(-0.3, -0.3, 0.6, 0.6, target_pen, target_brush) |
| | | |
| | | right_panel = QtWidgets.QWidget() |
| | | right_layout = QtWidgets.QVBoxLayout(right_panel) |
| | | right_layout.setContentsMargins(8, 0, 0, 0) |
| | | layout.addWidget(right_panel, stretch=2) |
| | | |
| | | path_group = QtWidgets.QGroupBox("è·¯å¾æä»¶") |
| | | path_layout = QtWidgets.QVBoxLayout(path_group) |
| | | path_row = QtWidgets.QHBoxLayout() |
| | | self.path_line = QtWidgets.QLineEdit() |
| | | self.path_browse_btn = QtWidgets.QPushButton("æµè§") |
| | | self.path_load_btn = QtWidgets.QPushButton("å è½½") |
| | | path_row.addWidget(self.path_line, stretch=1) |
| | | path_row.addWidget(self.path_browse_btn) |
| | | path_layout.addLayout(path_row) |
| | | path_layout.addWidget(self.path_load_btn, alignment=QtCore.Qt.AlignRight) |
| | | right_layout.addWidget(path_group) |
| | | |
| | | origin_group = QtWidgets.QGroupBox("åç¹ (GGA)") |
| | | origin_layout = QtWidgets.QVBoxLayout(origin_group) |
| | | self.origin_input = QtWidgets.QLineEdit() |
| | | self.origin_update_btn = QtWidgets.QPushButton("æ´æ°åç¹") |
| | | origin_layout.addWidget(self.origin_input) |
| | | origin_layout.addWidget(self.origin_update_btn, alignment=QtCore.Qt.AlignRight) |
| | | right_layout.addWidget(origin_group) |
| | | |
| | | serial_group = QtWidgets.QGroupBox("串å£è®¾ç½®") |
| | | serial_layout = QtWidgets.QVBoxLayout(serial_group) |
| | | serial_row = QtWidgets.QHBoxLayout() |
| | | self.port_combo = QtWidgets.QComboBox() |
| | | self.port_refresh_btn = QtWidgets.QPushButton("å·æ°") |
| | | serial_row.addWidget(self.port_combo, stretch=1) |
| | | serial_row.addWidget(self.port_refresh_btn) |
| | | serial_layout.addLayout(serial_row) |
| | | self.serial_toggle_btn = QtWidgets.QPushButton("æå¼ä¸²å£") |
| | | serial_layout.addWidget(self.serial_toggle_btn) |
| | | right_layout.addWidget(serial_group) |
| | | |
| | | control_group = QtWidgets.QGroupBox("è¿å¨æ§å¶") |
| | | control_layout = QtWidgets.QHBoxLayout(control_group) |
| | | self.start_button = QtWidgets.QPushButton("å¼å§") |
| | | self.stop_button = QtWidgets.QPushButton("忢") |
| | | self.stop_button.setEnabled(False) |
| | | control_layout.addWidget(self.start_button) |
| | | control_layout.addWidget(self.stop_button) |
| | | right_layout.addWidget(control_group) |
| | | |
| | | follow_row = QtWidgets.QHBoxLayout() |
| | | self.follow_checkbox = QtWidgets.QCheckBox("è·é车è¾") |
| | | self.follow_checkbox.setChecked(True) |
| | | self.freq_label = QtWidgets.QLabel("æ§å¶é¢ç: --.- Hz") |
| | | self.freq_label.setStyleSheet("font-family: Consolas, 'Courier New'; font-size: 12px;") |
| | | follow_row.addWidget(self.follow_checkbox) |
| | | follow_row.addWidget(self.freq_label) |
| | | follow_row.addStretch() |
| | | right_layout.addLayout(follow_row) |
| | | |
| | | self.info_label = QtWidgets.QLabel() |
| | | self.info_label.setAlignment(QtCore.Qt.AlignTop | QtCore.Qt.AlignLeft) |
| | | self.info_label.setStyleSheet("font-family: Consolas, 'Courier New'; font-size: 12px;") |
| | | info_scroll = QtWidgets.QScrollArea() |
| | | info_scroll.setWidgetResizable(True) |
| | | info_scroll.setWidget(self.info_label) |
| | | info_scroll.setMinimumWidth(320) |
| | | right_layout.addWidget(info_scroll, stretch=1) |
| | | |
| | | self.path_browse_btn.clicked.connect(self._browse_path_file) |
| | | self.path_load_btn.clicked.connect(self._load_path_from_ui) |
| | | self.origin_update_btn.clicked.connect(self._update_origin_from_ui) |
| | | self.port_refresh_btn.clicked.connect(lambda: self._refresh_serial_ports(initial=False)) |
| | | self.serial_toggle_btn.clicked.connect(self._toggle_serial_connection) |
| | | self.start_button.clicked.connect(self._start_control) |
| | | self.stop_button.clicked.connect(self._stop_control) |
| | | |
| | | def _apply_saved_values(self): |
| | | path_file = self.gui_state.get("path_file", "") |
| | | if path_file: |
| | | self.path_line.setText(path_file) |
| | | origin = self.gui_state.get("origin_gga", "") |
| | | if origin: |
| | | self.origin_input.setText(origin) |
| | | saved_port = self.gui_state.get("serial_port", "") |
| | | if saved_port: |
| | | index = self.port_combo.findText(saved_port) |
| | | if index >= 0: |
| | | self.port_combo.setCurrentIndex(index) |
| | | |
| | | def set_path_points(self, path_points, refit=False): |
| | | self._init_path(path_points or []) |
| | | if refit: |
| | | self._fit_applied = False |
| | | self._ensure_initial_view() |
| | | |
| | | def _init_path(self, path_points): |
| | | self.path_points = list(path_points or []) |
| | | painter_path = QtGui.QPainterPath() |
| | | if not self.path_points: |
| | | self.path_item.setPath(painter_path) |
| | | self.scene.setSceneRect(-10, -10, 20, 20) |
| | | self._path_rect = self.scene.sceneRect() |
| | | return |
| | | |
| | | first = True |
| | | for px, py in self.path_points: |
| | | py = -py |
| | | if first: |
| | | painter_path.moveTo(px, py) |
| | | first = False |
| | | else: |
| | | painter_path.lineTo(px, py) |
| | | self.path_item.setPath(painter_path) |
| | | |
| | | xs = [p[0] for p in self.path_points] |
| | | ys = [-p[1] for p in self.path_points] |
| | | margin = 2.0 |
| | | min_x, max_x = min(xs), max(xs) |
| | | min_y, max_y = min(ys), max(ys) |
| | | if min_x == max_x: |
| | | min_x -= 1 |
| | | max_x += 1 |
| | | if min_y == max_y: |
| | | min_y -= 1 |
| | | max_y += 1 |
| | | self.scene.setSceneRect(min_x - margin, min_y - margin, (max_x - min_x) + 2 * margin, (max_y - min_y) + 2 * margin) |
| | | self._path_rect = self.scene.sceneRect() |
| | | |
| | | def _drain_queue(self): |
| | | updated = False |
| | | processed = 0 |
| | | while True: |
| | | try: |
| | | data = self.data_queue.get_nowait() |
| | | except queue.Empty: |
| | | break |
| | | self._apply_update(data) |
| | | updated = True |
| | | processed += 1 |
| | | if updated: |
| | | self.data_queue.task_done() |
| | | now = time.time() |
| | | if now - self._last_gui_consume_log > 1.0: |
| | | print(f"[GUI] Qt颿¿å·æ° {processed} æ¡æ°æ®ï¼éåå©ä½ {self.data_queue.qsize()}") |
| | | self._last_gui_consume_log = now |
| | | |
| | | def _apply_update(self, data): |
| | | pos_xyz = data["pos_xyz"] |
| | | heading_deg = data["heading_deg"] |
| | | trail_points = data["trail"] |
| | | target_point = data["target"] |
| | | info_str = data["info_str"] |
| | | control_freq = data.get("control_freq_hz") |
| | | |
| | | path = QtGui.QPainterPath() |
| | | first = True |
| | | for px, py, _pz in trail_points[-1500:]: |
| | | py = -py |
| | | if first: |
| | | path.moveTo(px, py) |
| | | first = False |
| | | else: |
| | | path.lineTo(px, py) |
| | | self.trail_path_item.setPath(path) |
| | | |
| | | x = pos_xyz[0] |
| | | y = -pos_xyz[1] |
| | | self.robot_item.setRect(x - 0.3, y - 0.3, 0.6, 0.6) |
| | | |
| | | arrow_len = 1.0 |
| | | heading_rad = math.radians(heading_deg) |
| | | dx = arrow_len * math.cos(heading_rad) |
| | | dy = arrow_len * math.sin(heading_rad) |
| | | self.heading_item.setLine(x, y, x + dx, y - dy) |
| | | |
| | | if target_point: |
| | | tx = target_point[0] |
| | | ty = -target_point[1] |
| | | self.target_item.setRect(tx - 0.3, ty - 0.3, 0.6, 0.6) |
| | | else: |
| | | self.target_item.setRect(0, 0, 0, 0) |
| | | |
| | | self.info_label.setText(info_str) |
| | | if self.follow_checkbox.isChecked(): |
| | | self._center_on_robot(x, y) |
| | | if control_freq is not None: |
| | | self.freq_label.setText(f"æ§å¶é¢ç: {control_freq:5.1f} Hz") |
| | | |
| | | def _ensure_initial_view(self): |
| | | if not self._fit_applied and not self._path_rect.isNull(): |
| | | self.view.reset_zoom() |
| | | self.view.fitInView(self._path_rect, QtCore.Qt.KeepAspectRatio) |
| | | self._fit_applied = True |
| | | |
| | | def _center_on_robot(self, scene_x, scene_y): |
| | | self.view.centerOn(scene_x, scene_y) |
| | | |
| | | def _browse_path_file(self): |
| | | current = self.path_line.text().strip() |
| | | start_dir = Path(current).parent if current else BASE_DIR |
| | | file_name, _ = QtWidgets.QFileDialog.getOpenFileName( |
| | | self, |
| | | "éæ©è·¯å¾æä»¶", |
| | | str(start_dir), |
| | | "è·¯å¾æä»¶ (*.txt *.json);;æææä»¶ (*)", |
| | | ) |
| | | if file_name: |
| | | self.path_line.setText(file_name) |
| | | |
| | | def _load_path_from_ui(self): |
| | | if self.controller.is_running(): |
| | | QtWidgets.QMessageBox.warning(self, "è·¯å¾", "请å
忢è¿å¨æ§å¶ï¼åå 载路å¾ã") |
| | | return |
| | | path_file = self.path_line.text().strip() |
| | | if not path_file: |
| | | QtWidgets.QMessageBox.warning(self, "è·¯å¾", "请å
éæ©è·¯å¾æä»¶ã") |
| | | return |
| | | if not Path(path_file).exists(): |
| | | QtWidgets.QMessageBox.warning(self, "è·¯å¾", "è·¯å¾æä»¶ä¸åå¨ã") |
| | | return |
| | | if self.controller.load_path(path_file): |
| | | self.set_path_points(self.controller.path_points, refit=True) |
| | | self._save_state({"path_file": path_file}) |
| | | QtWidgets.QMessageBox.information(self, "è·¯å¾", "è·¯å¾å è½½æåã") |
| | | self._update_control_buttons() |
| | | else: |
| | | QtWidgets.QMessageBox.warning(self, "è·¯å¾", "è·¯å¾å 载失败ï¼è¯·æ£æ¥æä»¶å
容ã") |
| | | |
| | | def _update_origin_from_ui(self): |
| | | if self.controller.is_running(): |
| | | QtWidgets.QMessageBox.warning(self, "åç¹", "请å
忢è¿å¨æ§å¶ï¼åæ´æ°åç¹ã") |
| | | return |
| | | origin = self.origin_input.text().strip() |
| | | try: |
| | | self.controller.set_origin_geo(origin) |
| | | except ValueError as exc: |
| | | QtWidgets.QMessageBox.warning(self, "åç¹", f"åç¹è§£æå¤±è´¥: {exc}") |
| | | return |
| | | self._save_state({"origin_gga": origin}) |
| | | QtWidgets.QMessageBox.information(self, "åç¹", "åç¹å·²æ´æ°ã") |
| | | |
| | | def _refresh_serial_ports(self, initial: bool = False): |
| | | ports = [p.device for p in list_ports.comports()] |
| | | saved_port = self.gui_state.get("serial_port", "") |
| | | if initial and saved_port and saved_port not in ports: |
| | | ports.append(saved_port) |
| | | current = self.port_combo.currentText() |
| | | self.port_combo.blockSignals(True) |
| | | self.port_combo.clear() |
| | | self.port_combo.addItems(ports) |
| | | target = saved_port or current |
| | | if target: |
| | | index = self.port_combo.findText(target) |
| | | if index >= 0: |
| | | self.port_combo.setCurrentIndex(index) |
| | | self.port_combo.blockSignals(False) |
| | | |
| | | def _toggle_serial_connection(self): |
| | | if self.controller.is_connected(): |
| | | if self.controller.is_running(): |
| | | QtWidgets.QMessageBox.warning(self, "串å£", "请å
忢è¿å¨æ§å¶ï¼åå
³é串å£ã") |
| | | return |
| | | self.controller.disconnect() |
| | | QtWidgets.QMessageBox.information(self, "串å£", "串å£å·²å
³éã") |
| | | else: |
| | | port = self.port_combo.currentText().strip() |
| | | if not port: |
| | | QtWidgets.QMessageBox.warning(self, "串å£", "没æå¯ç¨ä¸²å£ï¼è¯·å
è¿æ¥è®¾å¤ã") |
| | | return |
| | | try: |
| | | self.controller.set_port(port) |
| | | except RuntimeError as exc: |
| | | QtWidgets.QMessageBox.warning(self, "串å£", str(exc)) |
| | | return |
| | | if not self.controller.connect(): |
| | | QtWidgets.QMessageBox.warning(self, "串å£", "䏲壿å¼å¤±è´¥ï¼è¯·æ£æ¥è¿æ¥ã") |
| | | return |
| | | self._save_state({"serial_port": port}) |
| | | QtWidgets.QMessageBox.information(self, "串å£", f"ä¸²å£ {port} å·²æå¼ã") |
| | | self._update_serial_ui() |
| | | self._update_control_buttons() |
| | | |
| | | def _start_control(self): |
| | | if self._is_control_running(): |
| | | return |
| | | if not self.controller.mower_ctrl: |
| | | QtWidgets.QMessageBox.warning(self, "æ§å¶", "请å
å è½½è·¯å¾æä»¶ã") |
| | | return |
| | | if not self.controller.is_connected(): |
| | | QtWidgets.QMessageBox.warning(self, "æ§å¶", "请å
æå¼ä¸²å£ã") |
| | | return |
| | | |
| | | self.start_button.setEnabled(False) |
| | | self.stop_button.setEnabled(True) |
| | | |
| | | def control_entry(): |
| | | try: |
| | | self.controller.run() |
| | | except Exception as exc: |
| | | print(f"[ERROR] æ§å¶çº¿ç¨å¼å¸¸: {exc}") |
| | | QtCore.QMetaObject.invokeMethod( |
| | | self, |
| | | "_show_error_message", |
| | | QtCore.Qt.QueuedConnection, |
| | | QtCore.Q_ARG(str, f"æ§å¶çº¿ç¨å¼å¸¸: {exc}"), |
| | | ) |
| | | finally: |
| | | QtCore.QMetaObject.invokeMethod(self, "_on_control_finished", QtCore.Qt.QueuedConnection) |
| | | |
| | | self.control_thread = threading.Thread(target=control_entry, daemon=True) |
| | | self.control_thread.start() |
| | | self._update_control_buttons() |
| | | |
| | | def _stop_control(self): |
| | | if not self._is_control_running(): |
| | | return |
| | | self.controller.stop() |
| | | self.stop_button.setEnabled(False) |
| | | |
| | | def _is_control_running(self) -> bool: |
| | | return bool(self.control_thread and self.control_thread.is_alive()) |
| | | |
| | | def _save_state(self, updates: Dict[str, str]): |
| | | self.gui_state.update(updates) |
| | | if self.persist_state_cb: |
| | | self.persist_state_cb(updates) |
| | | |
| | | def _update_serial_ui(self): |
| | | connected = self.controller.is_connected() |
| | | self.serial_toggle_btn.setText("å
³é串å£" if connected else "æå¼ä¸²å£") |
| | | self.port_combo.setEnabled(not connected) |
| | | self.port_refresh_btn.setEnabled(not connected) |
| | | |
| | | def _update_control_buttons(self): |
| | | can_start = bool(self.controller.mower_ctrl and self.controller.is_connected() and not self._is_control_running()) |
| | | self.start_button.setEnabled(can_start) |
| | | self.stop_button.setEnabled(self._is_control_running()) |
| | | |
| | | @QtCore.pyqtSlot() |
| | | def _on_control_finished(self): |
| | | self.control_thread = None |
| | | self._update_control_buttons() |
| | | self.stop_button.setEnabled(False) |
| | | |
| | | @QtCore.pyqtSlot(str) |
| | | def _show_error_message(self, message: str): |
| | | QtWidgets.QMessageBox.warning(self, "é误", message) |
| | | |
| | | def closeEvent(self, event): |
| | | self._stop_control() |
| | | if self.control_thread: |
| | | self.control_thread.join(timeout=3.0) |
| | | if self.controller.is_connected(): |
| | | self.controller.disconnect() |
| | | super().closeEvent(event) |
| | | else: |
| | | QtRealtimeDashboard = None |
| | | |
| | | |
| | | class GuiBridge: |
| | | """æ§å¶çº¿ç¨å Qt 主线ç¨åéæ°æ®çæ¡¥æ¥å¨""" |
| | | |
| | | def __init__(self): |
| | | self.queue: queue.Queue = queue.Queue(maxsize=50) |
| | | self._last_publish_log = 0.0 |
| | | |
| | | def publish(self, data): |
| | | try: |
| | | self.queue.put_nowait(data) |
| | | except queue.Full: |
| | | try: |
| | | self.queue.get_nowait() |
| | | except queue.Empty: |
| | | pass |
| | | try: |
| | | self.queue.put_nowait(data) |
| | | except queue.Full: |
| | | pass |
| | | now = time.time() |
| | | if now - self._last_publish_log > 1.0: |
| | | print(f"[GUI] å叿°æ®å°éåï¼å½åé¿åº¦ {self.queue.qsize()}ï¼æ¾ç¤ºä½ç½® {data.get('pos_xyz')}") |
| | | self._last_publish_log = now |
| | | |
| | | |
| | | class ControlCommandSender: |
| | | """æ§å¶å½ä»¤åéå¨ - åé转ååæ²¹é¨æ§å¶ä¿¡å·ç»STM32""" |
| | | |
| | |
| | | def __init__(self, port: str, baudrate: int = 921600, |
| | | offset_xyz: Tuple[float, float, float] = (0.0, 0.0, 0.0), |
| | | origin_geo: Optional[str] = None, |
| | | origin_alt_m: Optional[float] = None): |
| | | origin_alt_m: Optional[float] = None, |
| | | gui_bridge: Optional[GuiBridge] = None): |
| | | """ |
| | | åå§å宿¶æ§å¶å¨ |
| | | |
| | |
| | | self.port = port |
| | | self.baudrate = baudrate |
| | | self.offset_xyz = offset_xyz |
| | | self.origin_geo = origin_geo or "" |
| | | self.origin_latlon: Optional[Tuple[float, float]] = None |
| | | self.origin_altitude: Optional[float] = origin_alt_m |
| | | self.origin_lat_rad: Optional[float] = None |
| | | self.origin_lon_rad: Optional[float] = None |
| | | self.origin_ecef: Optional[Tuple[float, float, float]] = None |
| | | |
| | | if origin_geo: |
| | | try: |
| | | lat, lon, alt = _parse_origin_geo(origin_geo) |
| | | self.origin_latlon = (lat, lon) |
| | | # å¦æè§£æåºé«åº¦ï¼ä¸æªæå¨æå®ï¼åä¼å
使ç¨è§£æåºçé«åº¦ |
| | | if alt is not None and self.origin_altitude is None: |
| | | self.origin_altitude = alt |
| | | print(f"[INFO] ä»åç¹é
ç½®ä¸è§£æåºé«åº¦: {self.origin_altitude:.3f} m") |
| | | |
| | | print(f"[INFO] åæ åç¹è®¾ç½®: 纬度={self.origin_latlon[0]:.8f}°, ç»åº¦={self.origin_latlon[1]:.8f}°") |
| | | except ValueError as exc: |
| | | raise ValueError(f"åç¹åæ è§£æå¤±è´¥: {exc}") from exc |
| | | try: |
| | | self._apply_origin_geo(self.origin_geo) |
| | | except ValueError as exc: |
| | | raise ValueError(f"åç¹åæ è§£æå¤±è´¥: {exc}") from exc |
| | | |
| | | # GPS/IMUæ¥æ¶å¨ |
| | | self.receiver = GPSIMUReceiver(port, baudrate) |
| | | self.receiver: Optional[GPSIMUReceiver] = None |
| | | |
| | | # æ§å¶å½ä»¤åéå¨ (å
±ç¨åä¸ä¸ªä¸²å£) |
| | | self.cmd_sender = None |
| | |
| | | # æ°æ®ç¼å |
| | | self.latest_gps: Optional[GPSData] = None |
| | | self.latest_imu: Optional[IMUData] = None |
| | | self.path_points = [] |
| | | self.trail_points = [] |
| | | self.last_log_time = 0.0 |
| | | self.gui_bridge = gui_bridge |
| | | self._stop_event = threading.Event() |
| | | self._last_gui_publish_log = 0.0 |
| | | |
| | | # ç»è®¡ |
| | | self.control_count = 0 |
| | | self.control_freq_hz = 0.0 |
| | | self._freq_sample_time: Optional[float] = None |
| | | self._freq_sample_count = 0 |
| | | self._running = False |
| | | |
| | | def load_path(self, path_file: str) -> bool: |
| | | """ |
| | |
| | | } |
| | | |
| | | self.mower_ctrl = MowerController(path_points, params=params) |
| | | self.path_points = path_points |
| | | self.trail_points = [] |
| | | print("[INFO] è¿å¨æ§å¶å¨åå§å宿") |
| | | return True |
| | | |
| | |
| | | |
| | | def connect(self) -> bool: |
| | | """è¿æ¥ä¸²å£""" |
| | | if self.is_connected(): |
| | | print("[INFO] 串å£å·²è¿æ¥") |
| | | return True |
| | | if not self.port: |
| | | print("[ERROR] æªæå®ä¸²å£ç«¯å£") |
| | | return False |
| | | self.receiver = GPSIMUReceiver(self.port, self.baudrate) |
| | | if not self.receiver.connect(): |
| | | self.receiver = None |
| | | return False |
| | | |
| | | # å建æ§å¶å½ä»¤åéå¨ (å
±ç¨ä¸²å£å¯¹è±¡) |
| | |
| | | |
| | | def disconnect(self): |
| | | """æå¼è¿æ¥""" |
| | | self.receiver.disconnect() |
| | | if self.receiver: |
| | | self.receiver.disconnect() |
| | | self.receiver = None |
| | | self.cmd_sender = None |
| | | |
| | | def is_connected(self) -> bool: |
| | | return bool(self.receiver and self.receiver.serial and self.receiver.serial.is_open) |
| | | |
| | | def is_running(self) -> bool: |
| | | return self._running |
| | | |
| | | def set_port(self, port: str): |
| | | if self.is_connected(): |
| | | raise RuntimeError("请å
å
³éå½å串å£ï¼ååæ¢ç«¯å£") |
| | | self.port = port.strip() |
| | | |
| | | def stop(self): |
| | | """请æ±åæ¢æ§å¶å¾ªç¯""" |
| | | self._stop_event.set() |
| | | |
| | | def _update_visualizer( |
| | | self, |
| | | pos_xyz, |
| | | heading_deg: float, |
| | | pitch: float, |
| | | roll: float, |
| | | forward: int, |
| | | turn: int, |
| | | status: str, |
| | | stage: str, |
| | | target_xy: Optional[Tuple[float, float]], |
| | | ): |
| | | if not self.gui_bridge: |
| | | return |
| | | |
| | | info_lines = [ |
| | | f"ç¶æ: {status}", |
| | | f"é¶æ®µ: {stage}", |
| | | f"æ§å¶é¢ç: {self.control_freq_hz:5.1f} Hz", |
| | | "", |
| | | "ä½ç½® (ENU, m):", |
| | | f" E: {pos_xyz[0]:+7.2f}", |
| | | f" N: {pos_xyz[1]:+7.2f}", |
| | | f" U: {pos_xyz[2]:+7.2f}", |
| | | "", |
| | | "å§¿æ (deg):", |
| | | f" Heading: {heading_deg:+7.2f}", |
| | | f" Pitch : {pitch:+7.2f}", |
| | | f" Roll : {roll:+7.2f}", |
| | | "", |
| | | f"æ§å¶è¾åº: F={forward:+4d}, T={turn:+4d}", |
| | | ] |
| | | if target_xy: |
| | | info_lines.append(f"çåç¹: ({target_xy[0]:+.2f}, {target_xy[1]:+.2f})") |
| | | |
| | | info_str = "\n".join(info_lines) |
| | | |
| | | if self.gui_bridge: |
| | | trail_snapshot = list(self.trail_points[-1500:]) |
| | | payload = { |
| | | "info_str": info_str, |
| | | "pos_xyz": pos_xyz, |
| | | "heading_deg": heading_deg, |
| | | "trail": trail_snapshot, |
| | | "target": target_xy, |
| | | "control_freq_hz": self.control_freq_hz, |
| | | } |
| | | self.gui_bridge.publish(payload) |
| | | now = time.time() |
| | | if now - self._last_gui_publish_log > 1.0: |
| | | print(f"[GUI] æ§å¶çº¿ç¨æ¨éæ°æ® pos={pos_xyz}, heading={heading_deg:.2f}, trail={len(trail_snapshot)}, target={target_xy}") |
| | | self._last_gui_publish_log = now |
| | | |
| | | def _record_control_tick(self, current_time: float): |
| | | if self._freq_sample_time is None: |
| | | self._freq_sample_time = current_time |
| | | self._freq_sample_count = 1 |
| | | return |
| | | self._freq_sample_count += 1 |
| | | window = current_time - self._freq_sample_time |
| | | if window >= 1.0: |
| | | self.control_freq_hz = self._freq_sample_count / max(window, 1e-6) |
| | | self._freq_sample_count = 0 |
| | | self._freq_sample_time = current_time |
| | | |
| | | def _apply_origin_geo(self, origin_geo: Optional[str]): |
| | | origin_geo = (origin_geo or "").strip() |
| | | self.origin_latlon = None |
| | | self.origin_ecef = None |
| | | self.origin_lat_rad = None |
| | | self.origin_lon_rad = None |
| | | if not origin_geo: |
| | | return |
| | | lat, lon, alt = _parse_origin_geo(origin_geo) |
| | | self.origin_latlon = (lat, lon) |
| | | if alt is not None: |
| | | self.origin_altitude = alt |
| | | print(f"[INFO] ä»åç¹é
ç½®ä¸è§£æåºé«åº¦: {self.origin_altitude:.3f} m") |
| | | print(f"[INFO] åæ åç¹è®¾ç½®: 纬度={self.origin_latlon[0]:.8f}°, ç»åº¦={self.origin_latlon[1]:.8f}°") |
| | | |
| | | def set_origin_geo(self, origin_geo: str): |
| | | """æ´æ°åç¹åæ é
ç½®""" |
| | | self.origin_geo = origin_geo.strip() |
| | | self._apply_origin_geo(self.origin_geo) |
| | | |
| | | def _ensure_origin_reference(self, fallback_altitude: float): |
| | | """ç¡®ä¿å·²æ ¹æ®åç¹ç»çº¬åº¦åå§åECEFåºå""" |
| | |
| | | if not self.mower_ctrl: |
| | | print("[ERROR] 请å
å è½½è·¯å¾æä»¶") |
| | | return |
| | | if self._running: |
| | | print("[WARN] æ§å¶å¾ªç¯å·²å¨è¿è¡") |
| | | return |
| | | if not self.is_connected() or not self.receiver: |
| | | print("[ERROR] 请å
è¿æ¥ä¸²å£") |
| | | return |
| | | if not self.cmd_sender: |
| | | print("[ERROR] æ§å¶å½ä»¤åé卿ªå°±ç»ª") |
| | | return |
| | | |
| | | self._stop_event.clear() |
| | | self._running = True |
| | | |
| | | print("[INFO] å¼å§å®æ¶æ§å¶... (æ Ctrl+C 忢)") |
| | | print("[INFO] çå¾
GPSæ°æ®...") |
| | | |
| | | receiver = self.receiver |
| | | try: |
| | | start_time = time.time() |
| | | last_stats_time = start_time |
| | | self.last_log_time = start_time |
| | | |
| | | # çå¾
第ä¸ä¸ªææçGPSæ°æ® |
| | | gps_ready = False |
| | | while not gps_ready: |
| | | while not gps_ready and not self._stop_event.is_set(): |
| | | gps_data, imu_data = self.receiver.receive_packet() |
| | | |
| | | if gps_data: |
| | |
| | | if imu_data: |
| | | self.latest_imu = imu_data |
| | | |
| | | if self._stop_event.is_set(): |
| | | return |
| | | |
| | | print("[INFO] å¼å§æ§å¶å¾ªç¯") |
| | | |
| | | while True: |
| | | while not self._stop_event.is_set(): |
| | | current_time = time.time() |
| | | |
| | | # æ¥æ¶æ°æ® (éé»å¡å¼ï¼å¿«é轮询) |
| | | gps_data, imu_data = self.receiver.receive_packet() |
| | | gps_data, imu_data = receiver.receive_packet() if receiver else (None, None) |
| | | |
| | | if gps_data: |
| | | self.latest_gps = gps_data |
| | |
| | | if self.latest_gps: |
| | | # 转æ¢GPSæ°æ®å°æ¬å°åæ |
| | | x, y, z, heading, vx, vy = self._convert_gps_to_local(self.latest_gps) |
| | | self.trail_points.append((x, y, z)) |
| | | if len(self.trail_points) > 4000: |
| | | self.trail_points.pop(0) |
| | | |
| | | # æ´æ°æ§å¶å¨ç¶æ (åªç¨x,y) |
| | | self.mower_ctrl.update_gps((x, y), heading, (vx, vy), current_time) |
| | |
| | | |
| | | # è®¡ç®æ§å¶ä¿¡å· |
| | | control_output = self.mower_ctrl.compute_control(current_time) |
| | | control_info = control_output.get('info', {}) |
| | | forward_signal = control_output['forward'] # -100~100 |
| | | turn_signal = control_output['turn'] # -100~100 |
| | | |
| | |
| | | self.cmd_sender.send_control_command(steering_pwm, throttle_pwm) |
| | | |
| | | self.control_count += 1 |
| | | self._record_control_tick(current_time) |
| | | self.last_control_time = current_time |
| | | |
| | | # æå°æ§å¶ä¿¡æ¯ (éä½é¢ç) |
| | | if self.control_count % 74 == 0: # æ¯ç§æå°ä¸æ¬¡ |
| | | status = control_output['info'].get('status', 'running') |
| | | xte = control_output['info'].get('xte', 0) |
| | | gps_heading = self.latest_gps.heading_angle |
| | | gps_pitch = self.latest_gps.pitch_angle |
| | | gps_roll = self.latest_gps.roll_angle |
| | | |
| | | # æå°æ§å¶ä¿¡æ¯ (2Hz) |
| | | if current_time - self.last_log_time >= 0.5: |
| | | status = control_info.get('status', 'running') |
| | | xte = control_info.get('xte', 0) |
| | | # æ°å¦è§åº¦è½¬å°çè§åº¦ï¼heading_err_deg |
| | | # 注æ control_output['info']['heading_err'] æ¯å¼§åº¦ |
| | | heading_err_deg = math.degrees(control_output['info'].get('heading_err', 0)) |
| | | |
| | | # è·åææ°çå§¿æè§ (ä¼å
ä½¿ç¨ GPS æ°æ®ï¼IMU ä½ä¸ºè¾
婿é«é¢è¡¥å
ï¼è¿éç´æ¥ç¨ GPS ç»æä½ä¸çè§åº¦) |
| | | # GPSData ä¸: heading_angle(0-360), pitch_angle, roll_angle |
| | | # 齿¯è§åº¦å¶ |
| | | gps_heading = self.latest_gps.heading_angle |
| | | gps_pitch = self.latest_gps.pitch_angle |
| | | gps_roll = self.latest_gps.roll_angle |
| | | |
| | | heading_err_deg = math.degrees(control_info.get('heading_err', 0)) |
| | | |
| | | print(f"[LOG] POS_ENU: {x:.3f}, {y:.3f}, {z:.3f} | " |
| | | f"ATT(H/P/R): {gps_heading:.2f}°, {gps_pitch:.2f}°, {gps_roll:.2f}° | " |
| | | f"CTRL: S={status}, F={forward_signal}, T={turn_signal}, Err={xte:.2f}m") |
| | | self.last_log_time = current_time |
| | | |
| | | stage_label = control_info.get('stage', getattr(self.mower_ctrl, 'stage', '')) |
| | | target_xy = control_info.get('target_xy') |
| | | self._update_visualizer( |
| | | (x, y, z), |
| | | gps_heading, |
| | | gps_pitch, |
| | | gps_roll, |
| | | forward_signal, |
| | | turn_signal, |
| | | control_info.get('status', 'running'), |
| | | stage_label if stage_label else 'unknown', |
| | | target_xy, |
| | | ) |
| | | |
| | | # æ£æ¥æ¯å¦å®æ |
| | | if control_output['info'].get('status') == 'finished': |
| | | if control_info.get('status') == 'finished': |
| | | print("[INFO] è·¯å¾è·è¸ªå®æ!") |
| | | self.stop() |
| | | break |
| | | |
| | | # ç»è®¡ä¿¡æ¯ (æ¯10ç§) |
| | |
| | | |
| | | except KeyboardInterrupt: |
| | | print("\n[INFO] ç¨æ·ä¸æ") |
| | | self.stop() |
| | | |
| | | finally: |
| | | self._running = False |
| | | self._stop_event.clear() |
| | | # åé忢å½ä»¤ (ä¸ä½å¼) |
| | | print("[INFO] åé忢å½ä»¤...") |
| | | for _ in range(5): |
| | | self.cmd_sender.send_control_command(1500, 1500) |
| | | time.sleep(0.02) |
| | | if self.cmd_sender: |
| | | print("[INFO] åé忢å½ä»¤...") |
| | | for _ in range(5): |
| | | self.cmd_sender.send_control_command(1500, 1500) |
| | | time.sleep(0.02) |
| | | |
| | | # æå°æç»ç»è®¡ |
| | | print("\n========== æç»ç»è®¡ ==========") |
| | | print(f"æ»æ§å¶æ¬¡æ°: {self.control_count}") |
| | | print(f"GPSæ°æ®å
: {self.receiver.gps_count}") |
| | | print(f"IMUæ°æ®å
: {self.receiver.imu_count}") |
| | | print(f"å½ä»¤åé: {self.cmd_sender.get_stats()}") |
| | | print(f"é误计æ°: {self.receiver.error_count}") |
| | | if receiver: |
| | | print(f"GPSæ°æ®å
: {receiver.gps_count}") |
| | | print(f"IMUæ°æ®å
: {receiver.imu_count}") |
| | | if self.cmd_sender: |
| | | print(f"å½ä»¤åé: {self.cmd_sender.get_stats()}") |
| | | if receiver: |
| | | print(f"é误计æ°: {receiver.error_count}") |
| | | print("==============================\n") |
| | | |
| | | |
| | | def main(): |
| | | """䏻彿°""" |
| | | # é
ç½® |
| | | PORT = "COM17" # æ ¹æ®å®é
æ
åµä¿®æ¹ |
| | | BAUDRATE = 921600 |
| | | PATH_FILE = "gecaolujing2.txt" # è·¯å¾æä»¶ |
| | | OFFSET_XYZ = (0.0, 0.0, 0.0) # 车è¾ä¸å¿ç¸å¯¹GPS天线çENUåç§»(ç±³): (ä¸, å, 天) |
| | | |
| | | # åç¹ç»çº¬åº¦ (æ¯æ GGA æ¥ææç®ç¥æ ¼å¼) |
| | | # 示ä¾GGA: "$GNGGA,060956.700,3949.8890014,N,11616.7555551,E,4,20,0.68,46.621,M,-6.679,M,1.0,0409*7F" |
| | | ORIGIN_GEO = "$GNGGA,060956.700,3949.8890014,N,11616.7555551,E,4,20,0.68,46.621,M,-6.679,M,1.0,0409*7F" |
| | | |
| | | ORIGIN_ALT = None # åç¹æµ·æ(ç±³)ï¼å¯éãè¥GGAæ¥æä¸å
嫿µ·æï¼ä¼èªå¨ä½¿ç¨æ¥æä¸çæµ·æã |
| | | |
| | | # å建æ§å¶å¨ |
| | | DEFAULT_PORT = "COM17" |
| | | DEFAULT_PATH_FILE = "gecaolujing2.txt" |
| | | DEFAULT_ORIGIN_GGA = "$GNGGA,060956.700,3949.8890014,N,11616.7555551,E,4,20,0.68,46.621,M,-6.679,M,1.0,0409*7F" |
| | | OFFSET_XYZ = (0.0, 0.0, 0.0) |
| | | |
| | | gui_state = load_gui_state() |
| | | selected_port = gui_state.get("serial_port") or DEFAULT_PORT |
| | | origin_geo = gui_state.get("origin_gga") or DEFAULT_ORIGIN_GGA |
| | | path_file = gui_state.get("path_file") |
| | | |
| | | gui_bridge = GuiBridge() if QtWidgets else None |
| | | |
| | | controller = RealtimeController( |
| | | PORT, |
| | | selected_port, |
| | | BAUDRATE, |
| | | offset_xyz=OFFSET_XYZ, |
| | | origin_geo=ORIGIN_GEO, |
| | | origin_alt_m=ORIGIN_ALT |
| | | origin_geo=origin_geo, |
| | | origin_alt_m=None, |
| | | gui_bridge=gui_bridge, |
| | | ) |
| | | |
| | | # å è½½è·¯å¾ |
| | | if not controller.load_path(PATH_FILE): |
| | | print("[ERROR] è·¯å¾å 载失败ï¼éåº") |
| | | return |
| | | |
| | | # è¿æ¥ä¸²å£ |
| | | if not controller.connect(): |
| | | print("[ERROR] 串å£è¿æ¥å¤±è´¥ï¼éåº") |
| | | return |
| | | |
| | | # è¿è¡æ§å¶å¾ªç¯ |
| | | try: |
| | | controller.run() |
| | | finally: |
| | | controller.disconnect() |
| | | |
| | | # é¢å è½½è·¯å¾æä»¶ï¼è¥åå¨ï¼ |
| | | candidate_path = path_file or DEFAULT_PATH_FILE |
| | | if candidate_path and Path(candidate_path).exists(): |
| | | controller.load_path(candidate_path) |
| | | |
| | | def persist_state(updates: Dict[str, str]): |
| | | gui_state.update(updates) |
| | | save_gui_state(gui_state) |
| | | |
| | | if gui_bridge and QtWidgets: |
| | | app = QtWidgets.QApplication.instance() or QtWidgets.QApplication([]) |
| | | dashboard = QtRealtimeDashboard(controller, gui_bridge.queue, gui_state, persist_state) |
| | | dashboard.show() |
| | | try: |
| | | app.exec_() |
| | | finally: |
| | | controller.stop() |
| | | controller.disconnect() |
| | | else: |
| | | # æ Qtç¯å¢æ¶ï¼æ²¿ç¨æ§çå½ä»¤è¡å·¥ä½æµ |
| | | if not controller.path_points and Path(DEFAULT_PATH_FILE).exists(): |
| | | controller.load_path(DEFAULT_PATH_FILE) |
| | | if not controller.connect(): |
| | | print("[ERROR] 串å£è¿æ¥å¤±è´¥ï¼éåº") |
| | | return |
| | | try: |
| | | controller.run() |
| | | finally: |
| | | controller.disconnect() |
| | | |
| | | |
| | | if __name__ == "__main__": |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | """HITL åç³»ç»æµè¯å
ã""" |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | """ |
| | | pytest é
ç½®ï¼å°ä»åºç python/ ç®å½å å
¥ sys.pathï¼ä¾¿äºç´æ¥å¯¼å
¥ hitl å
ã |
| | | """ |
| | | |
| | | import sys |
| | | from pathlib import Path |
| | | |
| | | PYTHON_DIR = Path(__file__).resolve().parents[1] |
| | | if str(PYTHON_DIR) not in sys.path: |
| | | sys.path.insert(0, str(PYTHON_DIR)) |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import math |
| | | |
| | | import pytest |
| | | |
| | | from hitl.dynamics import DifferentialDriveModel |
| | | |
| | | |
| | | def test_straight_motion_updates_position(): |
| | | model = DifferentialDriveModel() |
| | | model.reset() |
| | | state = model.step(target_linear=1.0, target_angular=0.0, dt=1.0) |
| | | assert state.east == pytest.approx(1.0, rel=0.05) |
| | | assert state.north == pytest.approx(0.0, abs=0.05) |
| | | assert state.heading == pytest.approx(0.0, abs=1e-3) |
| | | |
| | | |
| | | def test_in_place_rotation_changes_heading(): |
| | | model = DifferentialDriveModel() |
| | | model.reset() |
| | | state = model.step(target_linear=0.0, target_angular=math.radians(90.0), dt=1.0) |
| | | assert math.degrees(state.heading) == pytest.approx(90.0, abs=1.0) |
| | | assert abs(state.linear_velocity) < 1e-6 |
| | | |
| | | |
| | | def test_velocity_limits_respected(): |
| | | model = DifferentialDriveModel(max_linear_speed=0.5, max_linear_accel=0.5) |
| | | model.reset() |
| | | state = model.step(target_linear=2.0, target_angular=0.0, dt=0.2) |
| | | assert state.linear_velocity <= model.max_linear_speed + 1e-6 |
| | | |
| | | |
| | | def test_body_acceleration_contains_gravity(): |
| | | model = DifferentialDriveModel() |
| | | model.reset() |
| | | state = model.step(target_linear=0.0, target_angular=0.0, dt=0.1) |
| | | ax, ay, az = state.body_accel_g |
| | | assert -1.05 < az < -0.95 # éåæ¹å |
| | | assert abs(ax) < 0.05 |
| | | assert abs(ay) < 0.05 |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import math |
| | | |
| | | import pytest |
| | | |
| | | from hitl import geo |
| | | |
| | | |
| | | GGA_SAMPLE = "$GNGGA,080112.000,3949.8105069,N,11616.6876082,E,4,44,0.42,48.502,M,-6.684,M,1.0,0409*73" |
| | | |
| | | |
| | | def test_parse_origin_from_gga(): |
| | | origin = geo.parse_origin(GGA_SAMPLE) |
| | | assert origin.latitude_deg == pytest.approx(39.830175115) |
| | | assert origin.longitude_deg == pytest.approx(116.278126803) |
| | | assert origin.altitude_m == pytest.approx(48.502) |
| | | |
| | | |
| | | def test_parse_origin_short_format(): |
| | | origin = geo.parse_origin("3949.8105,N,11616.6876,E,50.0") |
| | | assert origin.latitude_deg == pytest.approx(39.830175) |
| | | assert origin.longitude_deg == pytest.approx(116.278126) |
| | | assert origin.altitude_m == pytest.approx(50.0) |
| | | |
| | | |
| | | def test_enu_roundtrip_accuracy(): |
| | | origin = geo.parse_origin(GGA_SAMPLE) |
| | | east, north, up = 5.0, -3.0, 1.2 |
| | | lat, lon, alt = geo.enu_to_lla(east, north, up, origin) |
| | | x, y, z = geo.geo_to_ecef(lat, lon, alt) |
| | | dx = x - origin.ecef[0] |
| | | dy = y - origin.ecef[1] |
| | | dz = z - origin.ecef[2] |
| | | east_rt, north_rt, up_rt = geo.ecef_to_enu(dx, dy, dz, origin.latitude_rad, origin.longitude_rad) |
| | | |
| | | assert east_rt == pytest.approx(east, abs=0.01) |
| | | assert north_rt == pytest.approx(north, abs=0.01) |
| | | assert up_rt == pytest.approx(up, abs=0.01) |
| | | |
| | | |
| | | def test_heading_math_to_nav(): |
| | | assert geo.heading_math_to_nav(math.radians(0.0)) == pytest.approx(90.0) |
| | | assert geo.heading_math_to_nav(math.radians(90.0)) == pytest.approx(0.0) |
| | | assert geo.heading_math_to_nav(math.radians(-90.0)) == pytest.approx(180.0) |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import struct |
| | | from datetime import datetime, timezone |
| | | |
| | | import pytest |
| | | |
| | | from hitl import protocols |
| | | |
| | | |
| | | def _calc_checksum(sentence: str) -> str: |
| | | cs = 0 |
| | | for ch in sentence[1:]: |
| | | cs ^= ord(ch) |
| | | return f"{cs:02X}" |
| | | |
| | | |
| | | def test_build_gprmi_sentence_format(): |
| | | ts = datetime(2025, 11, 21, 8, 1, 12, tzinfo=timezone.utc) |
| | | sentence = protocols.build_gprmi_sentence( |
| | | timestamp=ts, |
| | | lat_deg=39.8301751, |
| | | lon_deg=116.2781268, |
| | | alt_m=48.5, |
| | | east_vel=0.2, |
| | | north_vel=0.1, |
| | | up_vel=0.0, |
| | | heading_deg=123.4, |
| | | pitch_deg=1.2, |
| | | roll_deg=-0.6, |
| | | ).decode("ascii") |
| | | |
| | | assert sentence.startswith("$GPRMI,") |
| | | assert sentence.endswith("\r\n") |
| | | body, checksum = sentence.strip()[0:sentence.index("*")], sentence[sentence.index("*") + 1 : sentence.index("*") + 3] |
| | | assert checksum == _calc_checksum(body) |
| | | fields = body.split(",") |
| | | assert len(fields) == 24 # $GPRMI + 23 ä¸ªåæ®µ |
| | | |
| | | |
| | | def test_build_gpimu_sentence_format(): |
| | | ts = datetime(2025, 11, 21, 8, 1, 12, tzinfo=timezone.utc) |
| | | sentence = protocols.build_gpimu_sentence( |
| | | timestamp=ts, |
| | | accel_g=(0.01, -0.02, -0.99), |
| | | gyro_deg_s=(0.1, 0.2, -0.3), |
| | | temperature_c=29.5, |
| | | ).decode("ascii") |
| | | |
| | | assert sentence.startswith("$GPIMU,") |
| | | body = sentence.strip()[0:sentence.index("*")] |
| | | checksum = sentence[sentence.index("*") + 1 : sentence.index("*") + 3] |
| | | assert checksum == _calc_checksum(body) |
| | | assert len(body.split(",")) == 9 # $GPIMU + 8 åæ®µ |
| | | |
| | | |
| | | def _build_control_frame(payload: bytes) -> bytes: |
| | | header = b"\xAA\x55" |
| | | frame_type = b"\x10" |
| | | length = struct.pack("<H", len(payload)) |
| | | checksum = (sum(frame_type + length + payload)) & 0xFFFF |
| | | footer = b"\x0D\x0A" |
| | | return header + frame_type + length + payload + struct.pack("<H", checksum) + footer |
| | | |
| | | |
| | | def test_pythonlink_decoder_float_payload(): |
| | | received = [] |
| | | decoder = protocols.PythonLinkDecoder(lambda frame: received.append(frame)) |
| | | frame = _build_control_frame(struct.pack("<ff", 1.2, -0.4)) |
| | | decoder.feed(frame[:5]) |
| | | decoder.feed(frame[5:]) |
| | | |
| | | assert len(received) == 1 |
| | | assert received[0].forward == pytest.approx(1.2) |
| | | assert received[0].turn == pytest.approx(-0.4) |
| | | |
| | | |
| | | def test_pythonlink_decoder_pwm_payload(): |
| | | received = [] |
| | | decoder = protocols.PythonLinkDecoder(lambda frame: received.append(frame)) |
| | | frame = _build_control_frame(struct.pack("<HH", 2000, 1600)) |
| | | decoder.feed(frame) |
| | | |
| | | assert len(received) == 1 |
| | | assert received[0].forward == pytest.approx(0.3, rel=0.05) # (1600-1500)/500 * 1.5 |
| | | assert received[0].turn == pytest.approx(1.5708, rel=0.05) |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import struct |
| | | import time |
| | | |
| | | import pytest |
| | | |
| | | from hitl import simulator as simulator_mod |
| | | |
| | | GGA_SAMPLE = "$GNGGA,080112.000,3949.8105069,N,11616.6876082,E,4,44,0.42,48.502,M,-6.684,M,1.0,0409*73" |
| | | |
| | | |
| | | def _build_control_frame(payload: bytes) -> bytes: |
| | | header = b"\xAA\x55" |
| | | frame_type = b"\x10" |
| | | length = struct.pack("<H", len(payload)) |
| | | checksum = (sum(frame_type + length + payload)) & 0xFFFF |
| | | footer = b"\x0D\x0A" |
| | | return header + frame_type + length + payload + struct.pack("<H", checksum) + footer |
| | | |
| | | |
| | | class FakeSerialEndpoint: |
| | | def __init__(self, port: str | None, baudrate: int, timeout: float = 0.0): |
| | | self.port = port |
| | | self.baudrate = baudrate |
| | | self.timeout = timeout |
| | | self.opened = False |
| | | self.writes: list[bytes] = [] |
| | | self._read_buffer = bytearray() |
| | | |
| | | def open(self): |
| | | if self.port is None: |
| | | return |
| | | self.opened = True |
| | | |
| | | def close(self): |
| | | self.opened = False |
| | | |
| | | def write(self, data: bytes): |
| | | if not data: |
| | | return |
| | | self.writes.append(bytes(data)) |
| | | |
| | | def read(self, size: int = 1) -> bytes: |
| | | if not self._read_buffer: |
| | | return b"" |
| | | size = min(size, len(self._read_buffer)) |
| | | chunk = self._read_buffer[:size] |
| | | del self._read_buffer[:size] |
| | | return bytes(chunk) |
| | | |
| | | def readline(self) -> bytes: |
| | | return b"" |
| | | |
| | | def inject(self, data: bytes): |
| | | self._read_buffer.extend(data) |
| | | |
| | | |
| | | def test_simulator_emits_sensor_frames(monkeypatch): |
| | | monkeypatch.setattr(simulator_mod, "SerialEndpoint", FakeSerialEndpoint) |
| | | |
| | | config = simulator_mod.HitlConfig( |
| | | uart2_port="SIM", |
| | | uart5_port=None, |
| | | origin_gga=GGA_SAMPLE, |
| | | initial_enu=(0.0, 0.0, 0.0), |
| | | ) |
| | | sim = simulator_mod.HitlSimulator(config) |
| | | received_controls: list[tuple[float, float]] = [] |
| | | sim.on_control = lambda f, t: received_controls.append((f, t)) |
| | | |
| | | sim.start() |
| | | time.sleep(0.25) |
| | | |
| | | frame = _build_control_frame(struct.pack("<ff", 0.5, 0.2)) |
| | | sim.uart2.inject(frame) |
| | | time.sleep(0.05) |
| | | sim.stop() |
| | | |
| | | gprmi_count = sum(1 for pkt in sim.uart2.writes if pkt.startswith(b"$GPRMI")) |
| | | gpimu_count = sum(1 for pkt in sim.uart2.writes if pkt.startswith(b"$GPIMU")) |
| | | |
| | | assert gprmi_count >= 2 |
| | | assert gpimu_count >= 10 |
| | | assert received_controls, "æ§å¶å¸§æªè¢«è§£æ" |
| | | assert received_controls[-1][0] == pytest.approx(0.5, rel=0.1) |
| | | assert received_controls[-1][1] == pytest.approx(0.2, rel=0.1) |
| | | |