diff --git a/Bug_Report.md b/.Doc/Bug_Report.md similarity index 100% rename from Bug_Report.md rename to .Doc/Bug_Report.md diff --git a/TODO.md b/.Doc/TODO.md similarity index 100% rename from TODO.md rename to .Doc/TODO.md diff --git a/VSCode+Ozone使用方法.md b/.Doc/VSCode+Ozone使用方法.md similarity index 96% rename from VSCode+Ozone使用方法.md rename to .Doc/VSCode+Ozone使用方法.md index 42c575a..1c576ff 100644 --- a/VSCode+Ozone使用方法.md +++ b/.Doc/VSCode+Ozone使用方法.md @@ -84,7 +84,7 @@ C语言代码由固定的词汇(关键字)按照固定的格式(语法) 对于单个.c文件,从C语言开始到单片机可识别的.bin文件,一般要经历以下几步: -![img](.assets/v2-2797ea99d0d38eb9996993bb0ad77ab2_720w.webp) +![img](../.assets/v2-2797ea99d0d38eb9996993bb0ad77ab2_720w.webp) 首先是编译**预处理**Preprocessing,这一步会展开宏并删除注释,将多余的空格去除。预处理之后会生成.i文件。 @@ -100,7 +100,7 @@ C语言代码由固定的词汇(关键字)按照固定的格式(语法) ### C语言内存模型 -image-20221112160213066 +image-20221112160213066 以上是C语言常见的内存模型,即C语言的代码块以及运行时使用的内存(包括函数、变量等)的组织方式。 @@ -130,7 +130,7 @@ RTOS创建任务的时候也会为每个任务分配一定的栈空间,它会 ### Debug外设工作原理 -![image-20221112145717063](.assets/image-20221112145717063.png) +![image-20221112145717063](../.assets/image-20221112145717063.png) DBG支持模块(红框标注部分,也可以看作一个外设)通过一条专用的AHB-AP总线和调试接口相连(Jtag或swd),并且有与**数据**和**外设**总线直接相连的桥接器。它还同时连接了中断嵌套管理器(因此同样可以捕获中断并进行debug)和ITM、DWT、FPB这些调试支持模块。因此DBG可以直接获取内存或片上外设内的数据而不需要占用CPU的资源,并将这些数据通过专用外设总线发送给调试器,进而在上位机中读取。 @@ -144,7 +144,7 @@ ITM是instrument trace macrocell指令追踪宏单元的缩写,它用于提供 ### GDB调试MCU原理 -![image-20221117121323757](.assets/image-20221117121323757.png) +![image-20221117121323757](../.assets/image-20221117121323757.png) 不论使用MDK(KEIL)还是VSCode还是Ozone,实际上背后的流程相同。首先GDB会建立TCP/IP端口并提供接口,调试服务器(Server)作为硬件调试器和GDB软件的桥梁,将硬件调试器的相关功能(也就是DBG外设支持的那些功能)映射到GDB的接口上(通过连接到GDB建立的端口)。之后启动调试,将可执行文件下载到目标MCU上,然后从main开始执行 @@ -182,7 +182,7 @@ typedef struct > > **VSCode上线了一款新的插件:** > -> ![image-20221201134906999](.assets/image-20221201134906999.png) +> ![image-20221201134906999](../.assets/image-20221201134906999.png) > > 支持一键配置Arm GNU工具链、MinGW64(make工具)和OpenOCD!可以尝试使用这个插件替代下面的配置流程。并且,此插件还提供了一键下载、一键调试的支持,只需要选择合适的下载器配置即可,全部都是图形化界面的操作! > @@ -200,15 +200,15 @@ typedef struct - **Cortex-Debug**,**Cortex-Debug: Device Support Pack - STM32F4**:提供调试支持。cortex debug还会自动帮助你安装一些调试相关的插件。 - **IntelliCode**,**Makfile Tools**:提供代码高亮支持 - ![image-20221112172157533](.assets/image-20221112172157533.png) + ![image-20221112172157533](../.assets/image-20221112172157533.png) - ![image-20221112172208749](.assets/image-20221112172208749.png) + ![image-20221112172208749](../.assets/image-20221112172208749.png) - ![image-20221112172221756](.assets/image-20221112172221756.png) + ![image-20221112172221756](../.assets/image-20221112172221756.png) - ![image-20221112172239386](.assets/image-20221112172239386.png) + ![image-20221112172239386](../.assets/image-20221112172239386.png) - ![image-20221112172254809](.assets/image-20221112172254809.png) + ![image-20221112172254809](../.assets/image-20221112172254809.png) > MinGW、Arm GNU toolchain和OpenOCD也可以通过**MSYS2**使用pacman包管理器(和apt/yum类似)直接安装,这种方法一步到位,**==这是更推荐使用的方式==**,请参看[附录5](##附录5:利用MSYS2安装依赖环境)。 > @@ -216,17 +216,17 @@ typedef struct - 安装MinGW,等待界面如下:(will be deprecated soon,请注意这种方法将会在主分支发布正式版的时候删除) - ![image-20221112172051589](.assets/image-20221112172051589.png) + ![image-20221112172051589](../.assets/image-20221112172051589.png) 安装好后,打开MinGW后将所有的支持包勾选,然后安装: - ![image-20221112172348408](.assets/image-20221112172348408.png) + ![image-20221112172348408](../.assets/image-20221112172348408.png) - ![image-20221112172420037](.assets/image-20221112172420037.png) + ![image-20221112172420037](../.assets/image-20221112172420037.png) 安装完以后,将MinGW的bin文件夹添加到环境变量中的path下,按下菜单键搜索**编辑系统环境变量**打开之后: - ![image-20221112172716320](.assets/image-20221112172716320.png) + ![image-20221112172716320](../.assets/image-20221112172716320.png) 图片看不清请打开原图。验证安装: @@ -236,7 +236,7 @@ typedef struct - 配置gcc-arm-none-eabi环境变量,**把压缩包解压以后放在某个地方**,然后同上,将工具链的bin添加到PATH:(will be deprecated soon,请注意这种方法将会在主分支发布正式版的时候删除) - ![image-20221112172858593](.assets/image-20221112172858593.png) + ![image-20221112172858593](../.assets/image-20221112172858593.png)
安装路径可能不一样,这里要使用你自己的路径而不是直接抄
@@ -254,11 +254,11 @@ typedef struct 在project manager标签页工具链选择makefile - ![image-20221112173534670](.assets/image-20221112173534670.png) + ![image-20221112173534670](../.assets/image-20221112173534670.png) 生成的目录结构如下: - ![image-20221112174211802](.assets/image-20221112174211802.png) + ![image-20221112174211802](../.assets/image-20221112174211802.png) Makefile就是我们要使用的构建规则文件。 @@ -288,7 +288,7 @@ VSCode常用快捷键包括: 为了提供完整的代码高亮支持,需要配置Makefile tools插件的make程序路径,`ctrl+,`打开设置,搜索make path找到设置并填写: -![image-20221113152513343](.assets/image-20221113152513343.png) +![image-20221113152513343](../.assets/image-20221113152513343.png) > mingw32-make就是下面介绍的make工具(配合makefile替代手动调用gcc)。这里之所以只要输入mingw32-make而不用完整路径,是因为我们将mingw的bin文件夹加入环境变量了,因此系统会在PATH下自动寻找对应项 @@ -314,7 +314,7 @@ mingw32-make -j24 # -j参数表示参与编译的线程数,一般使用-j12 > > 我对make的编译命令进行了静默处理,只输出error和warning以及最后的生成文件信息。如果想要解除静默(就是下面所说的“你可以看到大致如下的输出”),需要修改Makefile。**本仓库下的makefile中已经用注释标明。** -![image-20221112191712534](.assets/image-20221112191712534.png) +![image-20221112191712534](../.assets/image-20221112191712534.png) 就会开始编译了。你可以看到大致如下的输出: @@ -361,7 +361,7 @@ arm-none-eabi-objcopy -O binary -S build/basic_framework.elf build/basic_framewo 这样,你就可以点击VSCode工具栏上方的Terminal->Run task选择你刚刚配置的任务开始编译了。**更方便的方法是使用快捷键:`ctrl+shift+B`。** 之后要配置下载任务和调试任务等,也可以利用这种方法,新建一个xxx_task,实现一键下载、一键调试等。 -![image-20221112192133103](.assets/image-20221112192133103.png) +![image-20221112192133103](../.assets/image-20221112192133103.png) > 还没配置任务的时候,需要在Terminal标签页中选择Configure Tasks... 创建一个新的.json文件。 > @@ -371,13 +371,13 @@ arm-none-eabi-objcopy -O binary -S build/basic_framework.elf build/basic_framewo Makefile的大部分内容在CubeMX初始化的时候就会帮你生成。如果新增了.c的源文件,你需要在`C_SOURCES`中新增: -![image-20221112192509718](.assets/image-20221112192509718.png) +![image-20221112192509718](../.assets/image-20221112192509718.png) 换行需要在行尾加反斜杠\\ 如果新增了头文件,在`C_INCLUDES`中新增头文件所在的文件夹: -![image-20221112192610543](.assets/image-20221112192610543.png) +![image-20221112192610543](../.assets/image-20221112192610543.png) 换行需要在行尾加反斜杠\\ @@ -412,7 +412,7 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。 ***其他配置需要的文件已经全部在basic_framework中提供***,包括`openocd.cfg STM32F407.svd .vscode/launch.json`。 -![image-20221115215531879](.assets/image-20221115215531879.png) +![image-20221115215531879](../.assets/image-20221115215531879.png)
主要需要配置这三个路径,第四个gdbPath可以选配
@@ -422,7 +422,7 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。 然后选择run and debug标签页,在选项中选择你配置好的选项,开始调试。**或者使用快捷键:`F5`。** -![image-20221112180103750](.assets/image-20221112180103750.png) +![image-20221112180103750](../.assets/image-20221112180103750.png) 我们的仓库中默认提供了两种下载器的支持,dap-link(无线调试器属于这一种)和j-link(包括小的j-link OB和黑色大盒子jlink)。 @@ -430,13 +430,13 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。 开始调试后,显示的界面如下: -![](.assets/vscodedebug.png) +![](../.assets/vscodedebug.png) 1. 变量查看窗口,包括当前调用栈(当前作用域或代码块)内的局部变量、当前文件的静态变量和全局变量。register选项卡可以查看cpu内核的寄存器数值。 2. 变量watch窗口。右键单击要查看的变量,选择watch加入查看。 - ![image-20221113131044191](.assets/image-20221113131044191.png) + ![image-20221113131044191](../.assets/image-20221113131044191.png) 还支持直接运行到指针所选处(Run to Cursor)以及直接跳转到指针处执行(Jump to Cursor)。添加行内断点(若一个表达式由多个表达式组成)也是很方便的功能,可以帮助进一步定位bug。 @@ -444,7 +444,7 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。 VSCode提供的一个最大的便利就是,你可以将鼠标悬停在需要查看的变量上,**不需要添加到watch就能观察变量值。**如果是指针还可以自动解析,获取解引用后的值。结构体也支持直接展开。 - ![image-20221113133624273](.assets/image-20221113133624273.png) + ![image-20221113133624273](../.assets/image-20221113133624273.png) > **现在Cortex-Debug插件也已经支持live watch(变量动态监视)**,最高可设置的刷新频率为4Hz,足堪大用,我们可以宣告KEIL的时代已经落幕!但是更复杂,更高频率的变量观测以及可视化功能还是需要通过ozone完成。 @@ -524,13 +524,13 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。 1. 安装Ozone - ![image-20221116150122397](.assets/image-20221116150122397.png) + ![image-20221116150122397](../.assets/image-20221116150122397.png) 这一步注意选择install a new instance(安装一个新的实例)。后续一路确认即可。 2. 安装jlink - ![image-20221116193340770](.assets/image-20221116193340770.png) + ![image-20221116193340770](../.assets/image-20221116193340770.png) 这一步注意不要勾选update dll in other application,否则jlink会把ozone里面老的驱动和启动项替代掉。choose destination和ozone一样,选择install a new instance。如果安装了老的相同版本的jlink,请先卸载(版本相同不用管,直接新装一个)。 @@ -544,19 +544,19 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。 安装好两个软件之后,打开ozone后会显示一个new project wizard,如果没有打开,在工具栏的File-> New -> New project wizard。 -![image-20221113133904084](.assets/image-20221113133904084.png) +![image-20221113133904084](../.assets/image-20221113133904084.png) 选择M4内核,为了能够查看外设寄存器的值还需要svd文件。所有mcu的svd都在图中的文件夹里提供,当然你也可以使用我们仓库根目录下的文件。 -![image-20221116150901418](.assets/image-20221116150901418.png) +![image-20221116150901418](../.assets/image-20221116150901418.png) 接口选择swd,接口速度不需要太高,如果调试的时候需要观察大量的变量并且使用日志功能,可以调高这个值。如果连接了jlikn,上面的窗口中会显示。如果链接了dap-link,比如无线调试器,会出现Unknown CMSIS-dap。选择你要使用的调试器,然后继续。 -![image-20221113134252407](.assets/image-20221113134252407.png) +![image-20221113134252407](../.assets/image-20221113134252407.png) 选择构建之后生成的.elf文件(在项目文件夹下的build中)。这是调试器专用的文件格式,对其内容感兴趣可以自行搜索细节。此外ozone还支持.bin .hex .axf(最后一个是amr-cc,也就是keil的工具链会生成的)等格式。 -![image-20221113134605331](.assets/image-20221113134605331.png) +![image-20221113134605331](../.assets/image-20221113134605331.png) 这页不要动。如果希望保存jlink的调试日志,最后一个选项选择一个文件或者新建一个日志文件。 @@ -574,7 +574,7 @@ Project.SetOSPlugin(“plugin_name”) 支持的插件在Ozone的安装目录下的`Plugins/OS`目录: -![image-20221119174445067](.assets/image-20221119174445067.png) +![image-20221119174445067](../.assets/image-20221119174445067.png) 我们的项目是F4的板子,内核时Cortex-M4(CM4),因此选用`FreeRTOSPlugin_CM4.js`(输入的时候js后缀不用输)。 ozone默认输入的命令似乎有误,需要手动修改(这好像和ozone的版本有关,请留意) @@ -582,7 +582,7 @@ Project.SetOSPlugin(“plugin_name”) 下图的配置是笔者常用的layout。每个窗口是否显示、放在什么位置等都是可以自己定义的。通过工具栏的view选项卡可以自行选择需要展示的窗口。 -![](.assets/ozone.png) +![](../.assets/ozone.png) 1. 调试控制:和vscode类似 @@ -590,11 +590,11 @@ Project.SetOSPlugin(“plugin_name”) 如果不需要可视化查看变量变化的趋势,但是想不暂停查看变量的值,请右键点击变量,选择一个合适的refresh rate: - ![image-20221119173731119](.assets/image-20221119173731119.png) + ![image-20221119173731119](../.assets/image-20221119173731119.png) 如果是一个结构体,你可以为整个结构体都进行刷新率的配置,不需要手动一个个修改。**或直接右键点击窗口**,将refresh打勾: - ![image-20221119173918340](.assets/image-20221119173918340.png) + ![image-20221119173918340](../.assets/image-20221119173918340.png) 3. 断点和运行追踪管理 @@ -639,7 +639,7 @@ Project.SetOSPlugin(“plugin_name”) - 如果当前文件没有你要的变量,你想查看项目中的其他文件夹,在view-> source files中可以打开该项目所有的源文件,双击可以打开源文件。 - ![image-20221113142448939](.assets/image-20221113142448939.png) + ![image-20221113142448939](../.assets/image-20221113142448939.png) - **日志打印** @@ -687,7 +687,7 @@ CPU选项卡可以查看CPU的寄存器。 在网盘上下载`daplink_register_license.rar`,解压出来之后打开。**请关闭杀毒软件。** -![image-20221116152032104](.assets/image-20221116152032104.png) +![image-20221116152032104](../.assets/image-20221116152032104.png) 根据Ozone打开时提示的daplink的序列号,将其输入注册机,电机generate,就会生成5个license。 @@ -964,7 +964,7 @@ download_jlink: 安装包已经上传到了网盘的`EC/VSCode+Ozone环境配置/msys2-x86_64-20221028.exe`下,你也可以在msys2的官网直接下载,如果没有ladder速度可能会稍慢,镜像站的下载速度会快许多。安装之后,打开MSYS2 MSYS软件,他是一个类shell的界面,实际上它提供了包括mingw64、ucrt64、clang64等多种不同编译环境在内的一组类linux开发工具合集: -![image-20221119222946103](.assets/image-20221119222946103.png) +![image-20221119222946103](../.assets/image-20221119222946103.png) 输入以下命令然后一路回车即可: @@ -973,7 +973,7 @@ pacman -S mingw-w64-x86_64-toolchain mingw-w64-x86_64-arm-none-eabi-toolchain mi # 需要注意ctrl+V不是黏贴快捷键,而是Ins+Shift.或者右键点击空白处选择黏贴也可以. ``` -![image-20221119223148604](.assets/image-20221119223148604.png) +![image-20221119223148604](../.assets/image-20221119223148604.png)
比如上面这样,会让你选择,直接敲回车即可,等待安装
@@ -1006,7 +1006,7 @@ pacman -S mingw-w64-x86_64-toolchain mingw-w64-x86_64-arm-none-eabi-toolchain mi 修改好之后,便可以在vscode中使用了: -![image-20230723132711865](.assets/image-20230723132711865.png) +![image-20230723132711865](../.assets/image-20230723132711865.png) linux下熟悉的ls/mkdir/find/ld/cat等命令和工具也一应俱全了。 diff --git a/合理地进行PID参数整定.md b/.Doc/合理地进行PID参数整定.md similarity index 100% rename from 合理地进行PID参数整定.md rename to .Doc/合理地进行PID参数整定.md diff --git a/如何定位bug.md b/.Doc/如何定位bug.md similarity index 100% rename from 如何定位bug.md rename to .Doc/如何定位bug.md diff --git a/必须做&禁止做.md b/.Doc/必须做&禁止做.md similarity index 100% rename from 必须做&禁止做.md rename to .Doc/必须做&禁止做.md diff --git a/架构介绍与开发准则.md b/.Doc/架构介绍与开发准则.md similarity index 95% rename from 架构介绍与开发准则.md rename to .Doc/架构介绍与开发准则.md index 440d16b..190adcb 100644 --- a/架构介绍与开发准则.md +++ b/.Doc/架构介绍与开发准则.md @@ -1,7 +1,5 @@ # 2023 EC basic-framework -> **代码参考了哈工深南宫小樱战队的框架设计和RMUA官方开源RoboRTS-firmware框架,在此鸣谢。** - > 每个bsp/module/application都有对应文档,建议阅读之后再看代码&进行开发。框架的搭建思路和讲解视频戳这里:[basic_framework讲解](https://www.bilibili.com/video/BV1Bd4y1E7CN)。 > 开发之前必看的文档:**README.md & VSCode+Ozone使用方法.md** 。开发app层请看application目录下的文档,若要开发module以及bsp务必把上层文档也浏览一遍以熟悉接口定义的方式。 > **程序的运行流程和框架所有app/module/bsp的数据流图直接拉到本文档底部。** @@ -35,7 +33,7 @@ - **代码格式**: - 在vscode-设置-扩展-C/C++-C_Cpp:style下修改。默认为`Visual Studio`。编写完新的代码后,使用右键-格式化文档(注:请勿对cube生成的文件使用此操作)。此操作不会改变文档的内容,但会改变缩进、空行、符号位置等,使代码更加统一、整洁。 + 在vscode-设置-扩展-C/C++-C_Cpp:style下修改。默认为`Visual Studio`。编写完新的代码后,使用`右键-格式化`或`shift+alt+f`(请勿对cube生成的文件使用此操作否则重新生成异常)。此操作不会改变文档的内容,但会改变缩进、空行、符号位置等,使代码更加统一、整洁。 **在cubemx生成的文件(尤其是main.c和freertos.c)时,务必按照cubemx的提示将用户代码放在usercode注释代码块内,否则重新生成时会被覆盖.** @@ -189,7 +187,7 @@ ROOT:. │ .gitignore # git版本管理忽略文件 │ .mxproject # CubeMX项目文件 │ basic_framework.ioc # CubeMX初始化配置文件 -| debug_ozone.jdebug # ozone debug调试配置和缓存文件 +│ debug_ozone.jdebug # ozone debug调试配置和缓存文件 │ LICENSE # 开源协议文件 │ Makefile # 编译管理文件,为make(mingw32-make)命令的目标 │ openocd_dap.cfg # 用于OpenOCD调试使用的配置文件,dap用 @@ -199,13 +197,13 @@ ROOT:. │ stm32.jflash # jlink的烧录的配置文件,一键下载用 │ STM32F407.svd # F407外设地址映射文件,用于调试 │ STM32F407IGHx_FLASH.ld # F407IGH(C板MCU)目标FLASH地址和链接规则,用于编译(作为链接阶段的链接器) -| task.ps1 # powershell脚本,一键编译并进入ozone调试/reset开发板用 +│ task.ps1 # powershell脚本,一键编译并进入ozone调试/reset开发板用 │ TODO.md # 项目待完成的任务 │ VSCode+Ozone使用方法.md # 开发环境配置和前置知识介绍 │ 修改HAL配置时文件目录的更改.md # 重新配置CubeMX时的步骤和注意事项 │ 必须做&禁止做.md # 开发必看,规范和要求 -| 如何定位bug.md # 开发必看,快速定位bug并进行修复.还提供了一些debug典例 -| +│ 如何定位bug.md # 开发必看,快速定位bug并进行修复.还提供了一些debug典例 +│ ├─.vscode │ launch.json # 调试的配置文件 │ settings.json # 工作区配置文件,根据自己的需要配置 @@ -215,7 +213,7 @@ ROOT:. ├─application # 应用层 ├─bsp # 板级支持包 ├─modules # 模块层 -| +│ ├─Src #hal生成的外设初始化源文件 ├─Inc #hal生成的外设初始化头文件 ├─Drivers #hal driver和cmsis drivers @@ -230,11 +228,11 @@ ROOT:. ### 软件分层 -![image-20221113211942850](.assets/framework.png) + ### 运行任务 -![image-20230413195155471](.assets/image-20230413195155471.png) + ### 初始化流程 @@ -251,8 +249,8 @@ main函数唯一需要的函数是app层的`robot.c`中的`RobotInit()`函数, ### 程序运行流程 -![运行](.assets/总程序流程.png) +![](../.assets/image-20230725153635454.png) ### 程序数据流 -![数据流](.assets/数据流.png) +![](../.assets/dataflow.svg) diff --git a/让VSCode成为更称手的IDE.md b/.Doc/让VSCode成为更称手的IDE.md similarity index 100% rename from 让VSCode成为更称手的IDE.md rename to .Doc/让VSCode成为更称手的IDE.md diff --git a/.assets/dataflow.svg b/.assets/dataflow.svg new file mode 100644 index 0000000..a2af8bf --- /dev/null +++ b/.assets/dataflow.svg @@ -0,0 +1 @@ +图例:IMUapp模块应用data struct数据结构(类型)module间交互flow数据流出(颜色相同)bsp板级支持包         (应用)拥有(的模块)cmdgimbalchassisshootmaster_machineremote_controlpitch motor  yaw motorsuper_cap4 * motor2 * friction motorloader motormodulemessage_centergimbal_cmdgimbal_feedchassis_cmdchassis_feedshoot_cmdshoot_feed以每个模块都收到一次信息为例,展示完整的数据流rtos中的任务都运行一次云台模式+云台角度发射模式+射频底盘模式+运动速度pitch电机和底盘的offset+IMU数据底盘真实运动速度+裁判系统数据是否卡弹+剩余热量消息中心注册了多个话题MotorTaskINSTask    几乎连接到每个module上为了保持整洁这里不连线lid servo设置闭环设置参考设置反馈来源设置闭环设置参考设置反馈来源设置闭环设置参考设置反馈来源加速度角速度CANSPIUSARTreferee接收回调函数直接阻塞读取imu接收回调函数解析视觉报文接收回调函数解析遥控器键鼠数据解析裁判系统电机反馈数据超级电容功率电机反馈数据电机反馈数据多机通信UI绘制云台姿态数加速度底盘速度弹速电容控制量BSPRTOS loopTaskRobotTask(RTOS looptask)DaemonTaskRefereeTask \ No newline at end of file diff --git a/.assets/framework.png b/.assets/framework.png deleted file mode 100644 index 17aba95..0000000 Binary files a/.assets/framework.png and /dev/null differ diff --git a/.assets/image-20230413195155471.png b/.assets/image-20230413195155471.png deleted file mode 100644 index d2bbd52..0000000 Binary files a/.assets/image-20230413195155471.png and /dev/null differ diff --git a/.assets/image-20230725152433502.png b/.assets/image-20230725152433502.png new file mode 100644 index 0000000..2daf96e Binary files /dev/null and b/.assets/image-20230725152433502.png differ diff --git a/.assets/image-20230725153133419.png b/.assets/image-20230725153133419.png new file mode 100644 index 0000000..6a802f6 Binary files /dev/null and b/.assets/image-20230725153133419.png differ diff --git a/.assets/image-20230725153635454.png b/.assets/image-20230725153635454.png new file mode 100644 index 0000000..3785972 Binary files /dev/null and b/.assets/image-20230725153635454.png differ diff --git a/.assets/image-20230725154910307.png b/.assets/image-20230725154910307.png new file mode 100644 index 0000000..a4104db Binary files /dev/null and b/.assets/image-20230725154910307.png differ diff --git a/.assets/总程序流程.png b/.assets/总程序流程.png deleted file mode 100644 index fc9128a..0000000 Binary files a/.assets/总程序流程.png and /dev/null differ diff --git a/.assets/数据流.png b/.assets/数据流.png deleted file mode 100644 index f270f67..0000000 Binary files a/.assets/数据流.png and /dev/null differ diff --git a/README.md b/README.md index a62dad7..4cc5853 100644 --- a/README.md +++ b/README.md @@ -13,15 +13,27 @@ +--- + + + +## 功能介绍 + + + + + + + ## 架构 +总览。 + ### 软件栈 +image-20230725153133419 - -### 多任务协作 - - +在CubeMX初始化生成的依赖文件基础之上新增了可选的CMSIS-DSP和Segger RTT。 ### 设计思想 @@ -34,13 +46,50 @@ 有了上面的大体认知,我们分别介绍框架的三层结构。 - **bsp**即板级支持包,提供对开发板外设的软件抽象,让module层能使用和硬件无关的接口(由bsp提供)进行数据处理与交互。bsp层和ST的HAL为强耦合,与硬件直接绑定。若要向其他的ST芯片移植,基本不需要修改bsp层;若是其他单片机则建议保留**接口设计**,对接口调用进行重现实现。每一种外设的头文件中都定义了一个**XXXInstance**(xxx为外设名),其中包含了使用该外设所需要的所有数据,如发送/接收的数据,长度,id(如果有),父指针(指向module实例的指针,用于回调)等。由于C没有`class`,因此所有bsp的接口都需要传入一个额外的参数:XXXInstance*,用于实现c++的`this`指针以区分具体是哪一个实例调用了接口。 -- **module**即模块层,包括了需要开发板硬件外设支持的(一般用于通信)真实**硬件模组**如电机、舵机、imu、测距传感器,以及通过 + +- **module**即模块层,包括了需要开发板硬件外设支持的(一般用于通信)真实**硬件模组**如电机、舵机、imu、测距传感器,和通过软件实现的**算法**如PID、滤波器、状态观测器;还有用于兼容不同控制信息模块(遥控器/ps手柄/图传链路/上位机)的统一接口模块,以及为app层提供数据交互的message center。 + + module层仍然是基于实例的,一个app会包含多个module的instance。当app便可以用硬件无关的接口使用module,如要求电机以一定速度运动、关闭气阀、给超级电容或上位机发送一些反馈数据等。在有了方便的bsp之后,只需要在你构建的module中包含必须的bsp,然后为app提供合理的接口即可。 + +- **app**是框架层级中最高的部分。目前的框架设计里,会有多个app任务运行在freertos中,当然你也可以根据需要启动一些事件驱动的任务,所有的任务安排都放在`app/robot_task`中。当前的app层仅是一个机器人开发的示例,有了封装程度极高的module,你可以在app完成任何事情。 + + 目前的app设计里,可以兼容多块开发板的情况,通过**条件编译**切换开发板的位置。如步兵机器人可以将主控MCU放在云台上,而超级电容控制板同时作为底盘板。使用CAN/SPI/UART将两者连接,便可以通过**`app/robot_def.h`**中的宏完成设置。可以根据需要,设置更多的开发板(双云台哨兵、工程机器人)。 + + 这套框架可以轻松扩展到所有机器人上,在我们的仓库中,有步兵机器人、平衡步兵机器人、哨兵机器人、英雄机器人、工程机器人以及空中机器人的代码实例,皆按照本框架中的三层结构开发。若设计了新的机器人,只需要在robot_def.h中修改传感器的位置、底盘轮距轴距、拨弹盘容量、弹舱载弹量等参数便可以**立刻实现部署**。 + +至于bsp和module中每个instance的设计,我们采用了**面向对象**的C风格代码,整个框架也统一了变量和函数命名方式,调用层级和数据流十分清晰(下一个章节也有插图阐述)。 + +为了避免出现”底层代码包含上层头文件“的情况,我们让bsp层instance在注册时要求module提供数据发送/接收的回调函数指针,从而在发生对应中断或事件时完成对module函数的”反向调用“。事实上,你也可以进一步将这套思想放入app的设计中,当某个事件发生时触发app的任务,而不是将app的任务定时运行(这可以提高运行效率,降低cpu占用)。 + +bsp和module的instance在初始化时接口皆为**`XXXInstance* XXXRegister(XXX_Init_Config_s* conf)`**,传入该实例所需的config参数,返回一个实例指针(看作this指针),之后要调用模块的功能,传入该指针即可。我们还提供了守护线程,以供module选用,当异常情况发生时在LOG中发送warning、触发蜂鸣器或LED进行声光报警以及错误/离线回调函数,保证系统的鲁棒性和安全性。 + + + +--- ## 执行顺序与数据流 +### 初始化 +![image-20230725153635454](.assets/image-20230725153635454.png) + +### 任务结构 + +app、module和bsp都有相应的rtos任务。其中bsp为创建任务提供了封装工具bsp_tools,旨在将复杂的回调函数转移到任务中而不是在中断内执行,以保证系统响应的实时性和数据完整性。有一些module和app根据功能需要会创建定时任务或事件驱动的任务,这些任务都在初始化时注册,并在特定的时刻被唤醒或周期执行。 + +image-20230725152433502 + +### 数据流 + +![](.assets/dataflow.svg) + +
建议浏览器打开SVG查看
+ +​ + +--- @@ -60,25 +109,101 @@ ### IDE? -使用VSCode作为“IDE”。需要的插件支持均已经在[VSCode+Ozone使用方法.md](VSCode+Ozone使用方法.md)中给出。通过VSCode强大的插件系统、language server以及代码补全高亮助力效率倍增。编译则使用集成的task进行,还可以将开发环境终端加入VSCode进一步提升体验。基本的调试如变量&寄存器查看均已在插件中提供支持,`launch.json`可以进行高自由度的自定义。 +使用VSCode作为“IDE”。需要的插件支持均已经在[VSCode+Ozone使用方法.md](.Doc/VSCode+Ozone使用方法.md)中给出。通过VSCode强大的插件系统、language server以及代码补全高亮助力效率倍增。编译则使用集成的task进行,还可以将开发环境终端加入VSCode进一步提升体验。基本的调试如变量&寄存器查看均已在插件中提供支持,`launch.json`可以进行高自由度的自定义。 -`Git`集成与额外插件补充让版本管理和协作从未如此简单,`live share`把你的伙伴们聚在一起集思广益,一同对抗困难的bug。更多特性和开发技巧请参考"如何使用本框架"章节。 +`Git`集成与gitlens/gitgraph/githistory额外插件补充让版本管理和协作从未如此简单,`live share`把你的伙伴们聚在一起集思广益,一同对抗困难的bug。更多好用的插件、特性和开发技巧请参考"**如何使用本框架**"章节。 > **不论如何,请不要使用KEIL作为你的代码编辑器。** ### 调试和性能分析 -- 基础的调试可以在VSCode中完成。cortex-debug插件的最新版本已经支持多个gdb-server(jlink/stlink/openocd/pyocd)的live watch(动态变量监视)和变量示波器(可视化)。若不是有特别的需求,**请勿使用串口调试器**。 +- 基础的调试可以在VSCode中完成。cortex-debug插件的最新版本已经支持多个gdb-server(jlink/stlink/openocd/pyocd)的live watch(动态变量监视)和变量示波器(可视化)。若不是有特别的需求,*请勿使用串口调试器*。 - 有高速变量查看和数据记录、多路数据可视化的需求(如进行pid参数整定、查找难以定位的bug)时,使用**Segger Ozone**。 - FreeMaster也可以作为调试的备选项。 - 基本的、日常性能分析可以通过`bsp_dwt`完成。若要分析关于任务运行和每个函数执行的详细信息和时间,推荐使用**Segger Systemviewer**。 + + +--- + + + ## 如何使用本框架 +仓库中有各种各样的说明文档和使用帮助。 + +### 编译烧录 + +本项目是基于RoboMaster开发板C型的示例,MCU为STM32F407IG,使用了板载的imu bmi-088,驱动标准的步兵机器人:2自由度GM6020云台、m2006电机拨盘+2*m3508电机摩擦轮的发射机构和MG90舵机弹舱盖,以及带有超级电容控制器的4轮麦克纳姆底盘。 + +首先在`app/robot_def.h`中根据注释修改开发板和机器人配置,再在各个app中修改初始化配置(如电机id,上位机通信波特率/使用串口或VCP,imu速率,超级电容id等)。 + +接着根据[VSCode+Ozone使用方法.md](.Doc/VSCode+Ozone使用方法.md)配置好编译下载环境之后(***再次建议使用Msys2+mingw64/ucrt64/clang64的方式配置环境!***),在VSCode中打开项目,点击上方tab页的终端(terminal)->运行构建任务(run build task),便启动编译,若没有问题,最终会在终端中输出如下信息: + +![image-20230725154910307](.assets/image-20230725154910307.png) + +工具链会预测ram,ccram以及flash的使用情况,并报告最终二进制文件的大小和存放位置。 + +随后,通过调试器将开发板连接至你的电脑,点击上方tab页的终端(terminal)->运行任务(run task),选择download_dap or download_jlink(或你自己编写的stlink/ulink/...),便会开始下载,终端或jFlash中会提示擦除、下载、验证的进度。 + +想要调试,在左侧tab页选择合适的调试选项,按F5或图形界面的绿色小三角形按钮,开始调试。 + +**更详细的开发流程,请参照`.Doc/VSCode+Ozone使用方法.md`** + +### 基本文档 + +根目录下的README.md即本说明文档,帮助开发者速览本项目。 + +`.Doc`目录下有**8**个markdown文档,分别为: + +- Bug_Report.md :提供了一些提交issues的模板范例,若在使用中出现问题请按照模板提供信息。 +- TODO.md :框架后续开发计划和维护说明 +- **VSCode+Ozone使用方法.md** :重要,开发必看。介绍了当前开发工作流和传统KEIL开发的不同,先讲解一些与工具链有关的基础知识,然后说明了如何配置开发环境,安装必要的软件和一些”操作“。还涉及了VSCode编辑调试和Ozone示波器&trace功能的使用指南。 +- 合理地进行PID参数整定.md :介绍了如何为PID控制器进行参数整定,包括简单的经验准则和基于模型的前馈控制、扰动消除等方法。 +- 如何定位bug.md :当嵌入式开发出现bug时,以更高效地方法进行错误定位和复现。简单的调试器使用技巧。 +- 必须做&禁止做.md :字如其名 +- **架构介绍与开发准则.md** : 重要,必看。若你希望为bsp或module增添新的模块,组装新的app,请参照此文档的编码和命名规范进行。阅读该文档有助于理解并写出和框架代码风格一致的程序。内含该项目的**文件树**,以框架的工作目录。 +- 让VSCode成为更称手的IDE.md :安装好用的插件,对编辑器进行个性化配置,提升开发效率 + +### 阅读代码 + +框架中的三层结构都有详尽的注释帮助阅读和二次开发,三个抽象层都有各自总览的说明文档,而每个bsp/module/app都配有对应的个性化说明文档,提供了接口说明和改进或进一步开发的建议。 + +建议以自上而下的方式阅读代码,app-》module-》bsp,我们还提供了框架的说明视频,分别讲解每个抽象层和总体的设计思路,还有一些杂碎的开发相关知识:[basic_framework教程]() + +### VSCode集成工具 + +我们在`.vscode`下提供了编写好的一些任务,包括编译,烧录,启动RTT终端(LOG),启动Ozone调试等。有些功能需要配置vscode的插件设置或将一些可执行文件加入环境变量,这些步骤已经在[VSCode+Ozone使用方法.md](.Doc/VSCode+Ozone使用方法.md)中给出;`launch.json`里包含了最常见的四种调试任务:使用jlink-server/openocd,启动或附加调试。 + +### for pro-user + +Makefile提供了脚本化的Makefile.upgrade,使用后者可以获取更好的开发体验。 + +可以自行添加需要的编译优化,进行更高级别的定制。 + +ST官方现在将HAL放入github维护。想要获取最新的支持,可以自行下载,加入本项目编译。 + +若希望纯开源使用,可以自定义openocd调试和烧录选项,参考根目录的openocd_dap.cfg和openocd_jlink.cfg。 + +若希望自己编译特定版本的cmsis-dsp或cmsis-os,请前往官方的github仓库下载,将构建规则加入makefile。 + +我们还增加了CMakeLists.txt以融入更现代化的构建系统,若你希望使用cmake,相信你有能力配置相关的开发环境。可以参考我们的[***powerful_framework***](https://gitee.com/hnuyuelurm/powerful_framework). + +如果实时系统任务需要的栈空间不够,请在CubeMX初始化配置中增大任务栈。一些freertos支持的高级功能请自行在配置页开启宏定义后重新生成。 + +... +--- + ## 后续计划 + +- `.Doc/TODO.md`中列举了一些可能的功能增强和优化。 +- 为三个层级都增加入门级培训教程,可以单独运行各个模块以方便上手。 +- 优化pub-sub消息机制的性能,同时将app的任务尽可能修改为**状态机+事件驱动**的回调机制。 +- 使用Qt或命令行为机器人配置(主要是robot_def和各个任务中的module初始化配置)编写UI界面,实现无代码机器人部署。 +- 为框架编写ROSdriver,通过usb连接到上位机(NUC),合并视觉/算法和电控的工作流。 diff --git a/application/chassis/chassis.c b/application/chassis/chassis.c index 114fc3e..61b43d8 100644 --- a/application/chassis/chassis.c +++ b/application/chassis/chassis.c @@ -214,7 +214,7 @@ void ChassisTask() chassis_cmd_recv.wz = 0; break; case CHASSIS_FOLLOW_GIMBAL_YAW: // 跟随云台,不单独设置pid,以误差角度平方为速度输出 - chassis_cmd_recv.wz = -1.5 * chassis_cmd_recv.offset_angle * abs(chassis_cmd_recv.offset_angle); + chassis_cmd_recv.wz = -1.5f * chassis_cmd_recv.offset_angle * abs(chassis_cmd_recv.offset_angle); break; case CHASSIS_ROTATE: // 自旋,同时保持全向机动;当前wz维持定值,后续增加不规则的变速策略 chassis_cmd_recv.wz = 4000; diff --git a/application/robot_task.h b/application/robot_task.h index f9aa832..252e77b 100644 --- a/application/robot_task.h +++ b/application/robot_task.h @@ -6,6 +6,7 @@ #include "main.h" #include "cmsis_os.h" +#include "robot.h" #include "ins_task.h" #include "motor_task.h" #include "referee_task.h" @@ -53,9 +54,10 @@ void OSTaskInit() HTMotorControlInit(); // 没有注册HT电机则不会执行 } -void StartINSTASK(void const *argument) +__attribute__((noreturn)) void StartINSTASK(void const *argument) { - static float ins_start, ins_dt; + static float ins_start; + static float ins_dt; INS_Init(); // 确保BMI088被正确初始化. LOGINFO("[freeRTOS] INS Task Start"); for (;;) @@ -71,9 +73,10 @@ void StartINSTASK(void const *argument) } } -void StartMOTORTASK(void const *argument) +__attribute__((noreturn)) void StartMOTORTASK(void const *argument) { - static float motor_dt, motor_start; + static float motor_dt; + static float motor_start; LOGINFO("[freeRTOS] MOTOR Task Start"); for (;;) { @@ -86,9 +89,10 @@ void StartMOTORTASK(void const *argument) } } -void StartDAEMONTASK(void const *argument) +__attribute__((noreturn)) void StartDAEMONTASK(void const *argument) { - static float daemon_dt, daemon_start; + static float daemon_dt; + static float daemon_start; BuzzerInit(); LOGINFO("[freeRTOS] Daemon Task Start"); for (;;) @@ -104,9 +108,10 @@ void StartDAEMONTASK(void const *argument) } } -void StartROBOTTASK(void const *argument) +__attribute__((noreturn)) void StartROBOTTASK(void const *argument) { - static float robot_dt, robot_start; + static float robot_dt; + static float robot_start; LOGINFO("[freeRTOS] ROBOT core Task Start"); // 200Hz-500Hz,若有额外的控制任务如平衡步兵可能需要提升至1kHz for (;;) @@ -120,7 +125,7 @@ void StartROBOTTASK(void const *argument) } } -void StartUITASK(void const *argument) +__attribute__((noreturn)) void StartUITASK(void const *argument) { LOGINFO("[freeRTOS] UI Task Start"); MyUIInit(); diff --git a/bsp/bsp_tools.c b/bsp/bsp_tools.c index 5badf2e..efcdd1f 100644 --- a/bsp/bsp_tools.c +++ b/bsp/bsp_tools.c @@ -21,11 +21,11 @@ static osThreadId cbkid_list[MX_SIG_LIST_SIZE]; static CallbackTask_t cbkinfo_list[MX_SIG_LIST_SIZE]; // 死循环任务,执行cbk函数指针,每次执行完毕后等待sig信号 -static void CallbackTaskBase(const void *cbk) +__attribute__((noreturn)) static void CallbackTaskBase(void const *cbk) { - void (*cbk_func)(void *) = (void (*)(void *))((CallbackTask_t *)cbk)->callback; - void *ins = ((CallbackTask_t *)cbk)->ins; - uint32_t sig = ((CallbackTask_t *)cbk)->sig; + void (*cbk_func)(void const *) = (void (*)(void const *))((CallbackTask_t const *)cbk)->callback; + void const *ins = ((CallbackTask_t const *)cbk)->ins; + uint32_t sig = ((CallbackTask_t const *)cbk)->sig; for (;;) { @@ -46,7 +46,7 @@ uint32_t CreateCallbackTask(char *name, void *cbk, void *ins, osPriority priorit osThreadDef_t threadDef; threadDef.name = name; - threadDef.pthread = CallbackTaskBase; + threadDef.pthread = &CallbackTaskBase; threadDef.tpriority = priority; threadDef.instances = 0; threadDef.stacksize = 128; diff --git a/modules/motor/HTmotor/HT04.c b/modules/motor/HTmotor/HT04.c index a7ce0b4..fdfad15 100644 --- a/modules/motor/HTmotor/HT04.c +++ b/modules/motor/HTmotor/HT04.c @@ -48,7 +48,7 @@ static float uint_to_float(int x_int, float x_min, float x_max, int bits) static void HTMotorDecode(CANInstance *motor_can) { uint16_t tmp; // 用于暂存解析值,稍后转换成float数据,避免多次创建临时变量 - uint8_t *rxbuff = motor_can->rx_buff; + uint8_t const *rxbuff = motor_can->rx_buff; HTMotorInstance *motor = (HTMotorInstance *)motor_can->id; HTMotor_Measure_t *measure = &(motor->measure); // 将can实例中保存的id转换成电机实例的指针 @@ -127,9 +127,9 @@ HTMotorInstance *HTMotorInit(Motor_Init_Config_s *config) HTMotorEnable(motor); HTMotorSetMode(CMD_MOTOR_MODE, motor); // 确保电机已经上电并执行电机模式 - DWT_Delay(0.05); + DWT_Delay(0.05f); HTMotorCalibEncoder(motor); // 将当前编码器位置作为零位 - DWT_Delay(0.05); // 保证下一个电机发送时CAN是空闲的,注意应用在初始化模块的时候不应该进入中断 + DWT_Delay(0.05f); // 保证下一个电机发送时CAN是空闲的,注意应用在初始化模块的时候不应该进入中断 ht_motor_instance[idx++] = motor; return motor; } @@ -143,7 +143,7 @@ void HTMotorSetRef(HTMotorInstance *motor, float ref) * @brief 为了避免总线堵塞,为每个电机创建一个发送任务 * @param argument 传入的电机指针 */ -void HTMotorTask(void const *argument) +__attribute__((noreturn)) void HTMotorTask(void const *argument) { float set, pid_measure, pid_ref; HTMotorInstance *motor = (HTMotorInstance *)argument;