修改doc存放位置,增加代码静态检查,完成了README文档,修复了.assets图片分辨率低的问题

This commit is contained in:
NeoZng 2023-07-25 16:12:38 +08:00
parent fa4a78a7a1
commit cdb1d209fc
22 changed files with 210 additions and 81 deletions

View File

@ -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语言内存模型
<img src=".assets/image-20221112160213066.png" alt="image-20221112160213066" style="zoom:80%;" />
<img src="../.assets/image-20221112160213066.png" alt="image-20221112160213066" style="zoom:80%;" />
以上是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)
不论使用MDKKEIL还是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工具链、MinGW64make工具和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添加到PATHwill be deprecated soon请注意这种方法将会在主分支发布正式版的时候删除
![image-20221112172858593](.assets/image-20221112172858593.png)
![image-20221112172858593](../.assets/image-20221112172858593.png)
<center>安装路径可能不一样,这里要使用你自己的路径而不是直接抄</center>
@ -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)
<center>主要需要配置这三个路径第四个gdbPath可以选配</center>
@ -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-M4CM4因此选用`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)
<center>比如上面这样,会让你选择,直接敲回车即可,等待安装</center>
@ -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等命令和工具也一应俱全了。

View File

@ -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)
<img src="../.assets/image-20230725153133419.png" style="zoom:67%;" />
### 运行任务
![image-20230413195155471](.assets/image-20230413195155471.png)
<img src="../.assets/image-20230725152433502.png" style="zoom: 50%;" />
### 初始化流程
@ -251,8 +249,8 @@ main函数唯一需要的函数是app层的`robot.c`中的`RobotInit()`函数,
### 程序运行流程
![运行](.assets/总程序流程.png)
![](../.assets/image-20230725153635454.png)
### 程序数据流
![数据流](.assets/数据流.png)
![](../.assets/dataflow.svg)

1
.assets/dataflow.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 274 KiB

141
README.md
View File

@ -13,15 +13,27 @@
---
## 功能介绍
## 架构
总览。
### 软件栈
<img src=".assets/image-20230725153133419.png" alt="image-20230725153133419" style="zoom: 67%;" />
### 多任务协作
在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根据功能需要会创建定时任务或事件驱动的任务这些任务都在初始化时注册并在特定的时刻被唤醒或周期执行。
<img src=".assets/image-20230725152433502.png" alt="image-20230725152433502" style="zoom:50%;" />
### 数据流
![](.assets/dataflow.svg)
<center>建议浏览器打开SVG查看<center>
---
@ -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-serverjlink/stlink/openocd/pyocd的live watch动态变量监视和变量示波器可视化。若不是有特别的需求**请勿使用串口调试器**。
- 基础的调试可以在VSCode中完成。cortex-debug插件的最新版本已经支持多个gdb-serverjlink/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上位机通信波特率/使用串口或VCPimu速率超级电容id等
接着根据[VSCode+Ozone使用方法.md](.Doc/VSCode+Ozone使用方法.md)配置好编译下载环境之后(***再次建议使用Msys2+mingw64/ucrt64/clang64的方式配置环境***在VSCode中打开项目点击上方tab页的终端terminal->运行构建任务run build task),便启动编译,若没有问题,最终会在终端中输出如下信息:
![image-20230725154910307](.assets/image-20230725154910307.png)
工具链会预测ramccram以及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合并视觉/算法和电控的工作流。

View File

@ -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;

View File

@ -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();

View File

@ -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;

View File

@ -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;