Compare commits

...

10 Commits

Author SHA1 Message Date
NeoZng 276fee9352 给makefile插件增加自动生成compile commands数据库的支持,避免无法自动配置 2023-10-27 16:19:27 +08:00
NeoZng d764e0f940 完善了环境配置说明和TODOlist 2023-09-27 23:18:39 +08:00
NeoZng 50479fc16c 完善文档 2023-09-27 22:52:26 +08:00
NeoZng 145e886618 完善readme功能说明 2023-09-24 18:07:16 +08:00
NeoZng 3139ab11b6 fix typo 2023-08-03 12:23:47 +08:00
NeoZng 903698251e 补充文档和框架讲解视频链接 2023-07-27 23:15:41 +08:00
NeoZng 8a476e6ee1 完成所有文档,发布正式版1.0 2023-07-26 23:23:27 +08:00
NeoZng ce90b3852c readme增加module单独测试用例,增加工程和平衡步兵展示gif 2023-07-26 22:13:58 +08:00
NeoZng cb3aeb4063 添加cmakelists的支持,修复了一些静态检查warning 2023-07-26 14:31:49 +08:00
NeoZng 668848a1e8 更新readme badges 2023-07-25 20:35:57 +08:00
21 changed files with 479 additions and 107 deletions

View File

@ -48,6 +48,8 @@
### 待完成
Unicom
- [ ] 为键鼠/遥控器/ps手柄/视觉上位机等各种控制器提供一套统一的接口,把发来数据转化为标准的控制数据,包括底盘速度云台角度等等
- [ ] 给每个模块增加调试的条件编译并增加bsp log的输出。或直接在运行时添加log等级输出不同的信息。
@ -57,11 +59,14 @@
舵机模块需要预先定义90/180/360连续旋转的电机类型并且能够设定max和min位置。
- [x] 编写舵机模块(待测试和优化)
- [ ] 可能需要串口舵机的支持?
#### imu
- [ ] 完善bmi088模块和算法的交互添加异步量测更新的SO3上的IEKF
> 继续使用四元数S3也许是一个更好的选择改动较小且运算开销也较小。后续考虑修改一套ESKF_INS并移植到框架中。
#### ==master_machine==
- [ ] 增加IMU数据的时间戳
@ -69,6 +74,8 @@
- [ ] 重构seasky protocol的接口
- [ ] 增加数据未更新的处理
需要一个更简单的协议以加快速度。若有必要可能需要重新编写一个简单的调试上位机UI。
### 待优化
@ -78,10 +85,20 @@
当前实现为buzzer是单独的module若需要蜂鸣器警报的module可以自行包含buzzer.h以创建不同情况下的警报如电机离线、堵转、遥控器离线等。
也许还有其他方式提醒离线和异常。
目前急需一个无线遥控继电器,防止机器人的急停模式失效。
#### BMI088
- [ ] 完善和SO3 IEKF的交互增加异步任务的唤醒和数据传递IMU中断唤起任务
根据BMI088的datasheet在初始标定完成后将gyro和acc都设置为中断触发当数据准备好时传感器会在对应的引脚输出跳变通过EXTI捕获跳变并触发中断在回调函数中启动SPI DMA传输。陀螺仪数据来到时进行姿态的预测即propagation加速度计数据到来时进行量测更新correct
也许需要找到一种更好的方式构建INS任务以方便和其他模块、应用的交互。
另外若要进一步提升自瞄效果在姿态得到更新时陀螺仪和imu的数据到来时需要额外的引脚连接到相机上完成硬触发采集以获得更好的时间对齐效果防止视觉得到的姿态数据发生漂移。目前视觉端假设姿态更新的频率是1khz当前每次完成姿态解算都会向上位机发送当前的姿态
#### remote_control
- [ ] 增加长按/短按检测 (是否有必要?)

View File

@ -4,11 +4,6 @@
[TOC]
> TODO
>
> 1. 添加一键编译+启用ozone调试脚本使得整个进一步流程自动化
> 2. 增加更多的背景知识介绍
## 前言
了解过嵌入式开发的你一定接触过Keil这款20世纪风格UI的IDE伴随很多人度过了学习单片机的岁月。然而由于其缺少代码补全、高亮和静态检查的支持以及为人诟病的一系列逆天的设置、极慢的编译速度特别是在开发HAL库时很多开发者开始转向其他IDE。
@ -42,31 +37,15 @@ CubeMX进行初始化 --> VSCode编写代/进行编译/简单调试 --> Ozone变
3. C语言基础[程序设计入门——C语言](https://www.icourse163.org/course/ZJU-199001?from=searchPage&outVendor=zw_mooc_pcssjg_)
***务必学完以上课程再开始本教程的学习。***
***务必学完以上课程再开始本教程的学习,以及后续的开发。***
万丈高楼不可平地而起,地基不牢只会导致递归学习。
> 如果有可能,还应该学习:[哈佛大学公开课计算机科学cs50](https://open.163.com/newview/movie/courseintro?newurl=%2Fspecial%2Fopencourse%2Fcs50.html)。你将会对单片机和计算机有不同的理解。
## 预备知识
1. 软件安装(队伍NAS和资料硬盘内提供了所有必要的依赖,安装包和插件,目录是`/EC/VSCode+Ozone环境配置`)请以公共账号登陆网盘ip地址为`49.123.113.2:5212`,账号`public@rm.cloud`,密码`public`。
所有安装包也可以在此百度网盘链接下获得:[archive.zip](https://pan.baidu.com/s/1sO_EI4cToyIAcScOQx-JSg?pwd=6666)
```shell
# 网盘中的文件:
basic_framework.zip # 本仓库文件,注意,可能不为最新,建议从仓库clone并定时pull
daplink_register_license.rar # daplink license注册机
gcc-arm-none-eabi-10.3-2021.10-win32.zip # arm-gnu-toolchain
JLinkARM.dll # 修改过的jlink运行链接库
JLink_Windows_V722b.exe # JLink软件包
mingw-get-setup.exe # mingw工具链
OpenOCD.zip # OpenOCD
Ozone_doc.pdf # Ozone使用手册
Ozone_Windows_V324_x86.exe # Ozone安装包
VSCodeUserSetup-x64-1.73.1.exe # VSCode安装包
```
2. C语言从源代码到.bin和.hex等机器代码的编译和链接过程
1. C语言从源代码到.bin和.hex等机器代码的编译和链接过程
3. C语言的内存模型
@ -178,6 +157,28 @@ typedef struct
> ***所有需要编辑的配置文件都已经在basic_framework的仓库中提供如果不会写照猫画虎。***
- **软件安装**
队伍NAS和资料硬盘内提供了所有必要的依赖,安装包和插件,目录是`/EC/VSCode+Ozone环境配置`请以公共账号登陆网盘ip地址为`49.123.113.2:5212`,账号`public@rm.cloud`,密码`public`。
对于非队内的开发者,我们提供了网盘下载方式。所有安装包也可以在此百度网盘链接下获得:[archive.zip](https://pan.baidu.com/s/1sO_EI4cToyIAcScOQx-JSg?pwd=6666)
```shell
# 网盘中的文件:
basic_framework.zip # 本仓库文件,注意为了保证最新,建议从仓库clone并定时pull或自动fetch
daplink_register_license.rar # daplink license注册机
gcc-arm-none-eabi-10.3-2021.10-win32.zip # arm-gnu-toolchain注意这个版本太老编译最新的框架可能出现一些编译参数不支持的情况。请通过Msys2直接安装或到arm官网下载最新的12.x版本。
JLinkARM.dll # 修改过的jlink运行链接库
JLink_Windows_V722b.exe # JLink软件包
mingw-get-setup.exe # mingw工具链更推荐的方式是使用msys2安装
OpenOCD.zip # OpenOCD
Ozone_doc.pdf # Ozone使用手册
Ozone_Windows_V324_x86.exe # Ozone安装包
VSCodeUserSetup-x64-1.73.1.exe # VSCode安装包
# 最佳实践是下载msys2并在mingw64中安装软件包
# 如果你喜欢clang可以使用clang下的arm工具链。
```
> 2022-12-01更新
>
> **VSCode上线了一款新的插件**
@ -197,8 +198,8 @@ typedef struct
- **C/C++**提供C/C++的调试和代码高亮支持
- **Better C++ Syntax**:提供更丰富的代码高亮和智能提示
- **C/C++ Snippets**:提供代码块(关键字)补全
- **Cortex-Debug****Cortex-Debug: Device Support Pack - STM32F4**提供调试支持。cortex debug还会自动帮助你安装一些调试相关的插件。
- **IntelliCode****Makfile Tools**:提供代码高亮支持
- **Cortex-Debug****Cortex-Debug: Device Support Pack - STM32F4**提供调试支持。cortex debug还会自动帮助你安装一些调试相关的插件包括RTOS支持和内存查看等
- **IntelliCode****Makfile Tools**:提供代码高亮支持。喜欢clang的同学可以使用clangd。
![image-20221112172157533](../.assets/image-20221112172157533.png)
@ -232,7 +233,9 @@ typedef struct
打开命令行win+Rcmd回车输入`gcc -v`,如果没有报错,并输出了一堆路径和参数说明安装成功。
安装完之后建议将ming的bin文件夹下的ming32-make.exe复制一份并将copy更名为make.exe
安装完之后建议将ming的bin文件夹下的mingw32-make.exe复制一份并将copy更名为make.exe
> 当然更推荐的方式是将MinGW终端集成到VSCode中防止类linux环境和Win的环境冲突特别是你的电脑中安装了其他工具链的时候如MSVC、LLVM等。
- 配置gcc-arm-none-eabi环境变量**把压缩包解压以后放在某个地方**然后同上将工具链的bin添加到PATHwill be deprecated soon请注意这种方法将会在主分支发布正式版的时候删除

View File

@ -4,5 +4,29 @@ Ozone的实时变量可视化监测(示波器)功能可以很好地帮助我们
## 调试顺序
先内环,后外环。若有已知的外部扰动如阻力、重力等可以在**保持kp不变**的情况下添加积分环节,并查看达到稳态时积分的输出,该输出值可以作为**前馈**作用通过feedforward_ptr一同送入下一个串级控制器。
先内环,后外环。若有已知的外部扰动如阻力、重力等可以在**保持kp不变**的情况下添加积分环节,并查看达到稳态时积分的输出,该输出值可以作为**前馈**作用通过feedforward_ptr一同送入下一个串级控制器。在没有模型的时候计算前馈一般通过**数据驱动**的方法,如稳态误差-参考值关系拟合。
经典的经验式整定方法有简单的Ziegler-Nicols法和Cohen-Coon法还有需要一定的系统辨识的Chien-Hrones-Reswick、Tyreus-Luyben和Skogestad法。这些方法在网络上或提出方法的论文中都有详尽的说明这里不再赘述。
我们可以使用上述方法确定一套参数的初值,再根据时域表现进行精细的参数调整。
以笔者个人的纯调参无模型云台调试经验,可以进行如下步骤:
1. 首先整定P参数使用二分法确定大致范围。将电机参考速度和实际速度在Ozone示波器同一窗口中打开以观察时域表现。把pid的ref值添加到变量观测方便修改只要修改ref值每次就可以触发阶跃信号输入。当P达到欠阻尼且波动只有一个周期只有超调一个峰开始添加D参数。
2. 添加微分参数。务必打开微分滤波器并根据你的闭环带宽速度环要跟随的频率设置滤波系数。目前使用的是一阶低通滤波后续考虑增加高阶滤波器和特殊的带宽滤波器切比雪夫、巴特沃斯等。调节D参数至P进入临界阻尼或过阻尼的状态没有超调
3. 交替增大比例系数和微分系数,直到出现不可控的微分抖动,然后减小两者的值直到出现一个合适的平衡(调个大概即可,没有模型的情况下很难达到均衡)
4. **固定PD参数**,查看不同目标值的**静差**。如果没有对云台进行建模则拟合目标值与静差的关系线性、多项式、指数、对数并将该值作为前馈加入系统以补偿PD无法影响的扰动项。
5. 增加额外的积分控制以消除前馈模型不准确带来的影响。务必使用积分分离和变速积分。参数不要求精细,一般来说大致即可。
## model-based控制
无模型的控制显然存在其劣势和效果上限,为了提高性能,我们需要对云台进行建模。
建模的方式包括动力学方程推导和数据驱动的系统辨识。
动力学方程的推导即分析系统的输入(电机的扭矩)和输出(速度/角度的关系得到系统动态的微分方程然后使输入等于微分方程中除输出外的项从而让输出的动态变为简单的一阶线性常微分方程以最快的方式到达期望位置。此时再额外增加PID控制器用于补偿建模得到的系统和实际不匹配造成的误差。建模考虑的因素越全面建模的效果可能会越好。
系统辨识的经典方法是伯德图法即频域分析。通过给定一系列的正弦输入,观察系统的输出表现得到系统的相频曲线和幅频特性曲线,并选择一个特定结构的系统对曲线进行拟合(最小二乘或极大似然估计),对得到的系统应用超前-滞后补偿控制器以确定合适的PID参数在裕度和带宽之间权衡使得系统的频率响应满足设计要求。
Ozone可以非常方便的获取系统的频率响应数据。

View File

@ -16,6 +16,8 @@
本框架使用stm32cubemx生成基于makefile编译系统后期拟修改为cmake+nijna+makefile以提高编译速度对于目前的版本您可以考虑自行安装ccache以提高编译速度使用arm gnu工具链开发利用arm-none-eabi-gcc编译make命令,命令行为mingw32-make
> 目前已经支持CMakeLists构建。
> ***==deprecated==***若需使用keil5开发请在stm32cubemx的`project manager`标签页下将工具链改为MDK然后在keil中自行添加所需包含的.c文件和头文件。关于如何在keil下添加dsplib请参考文档。在vscode中也有**KEIL assistant**和**Embedded IDE**插件可供使用。
>
> ***强烈推荐使用VSCode进行开发Ozone进行调试。***
@ -110,6 +112,23 @@
} CANInstance;
```
## 其他IDE支持
你还可以尝试VSC的EIDE插件+ozone的方式开发ac5/6工具链的程序。ac5/6工具链由于为arm出品的商业闭源软件对mcu硬件架构的针对性优化更多编译出来的程序优化效果往往更好、体积更小执行速度快过arm-gnu工具链。
另外的可能是Visual Studio + VisualGDB根据VisualGDB的官网进行配置即可可以利用VS提供的各种测试调试性能分析功能。对于熟悉VS丰富的功能支持的开发者可以选择此方式。
还可以尝试VSC的插件KEIL assistant通过此法你需要在根目录打开cubeide配置文件在project manager标签页选择将工具链改为MDK**我们非常不推荐这种方式**。若要使用CubeIDE也在相同的地方修改工具链。
***不过开发本框架的最佳实践仍然是VSCode+Ozone。***
> 只要你学习了[VSCode+Ozone使用方法](./VSCode+Ozone使用方法.md)文档内的*预备知识* 掌握了工具链的用途和原理之后不论换用什么IDE什么编译器你都可以切换自如。
## BSP层(Board Sopport Package)
- 主要功能实现对STM HAL的封装功能进一步抽象硬件。
@ -190,6 +209,8 @@ ROOT:.
│ debug_ozone.jdebug # ozone debug调试配置和缓存文件
│ LICENSE # 开源协议文件
│ Makefile # 编译管理文件,为make(mingw32-make)命令的目标
| Makefile.upgrade # 编译管理文件的升级版, 资深用户使用
| CMakeLists.txt # cmake构建规则, 资深用户使用
│ openocd_dap.cfg # 用于OpenOCD调试使用的配置文件,dap用
│ openocd_jlink.cfg # 用于OpenOCD调试使用的配置文件,jlink用
│ README.md # 本说明文档
@ -198,11 +219,6 @@ ROOT:.
│ STM32F407.svd # F407外设地址映射文件,用于调试
│ STM32F407IGHx_FLASH.ld # F407IGH(C板MCU)目标FLASH地址和链接规则,用于编译(作为链接阶段的链接器)
│ task.ps1 # powershell脚本,一键编译并进入ozone调试/reset开发板用
│ TODO.md # 项目待完成的任务
│ VSCode+Ozone使用方法.md # 开发环境配置和前置知识介绍
│ 修改HAL配置时文件目录的更改.md # 重新配置CubeMX时的步骤和注意事项
│ 必须做&禁止做.md # 开发必看,规范和要求
│ 如何定位bug.md # 开发必看,快速定位bug并进行修复.还提供了一些debug典例
├─.vscode
│ launch.json # 调试的配置文件
@ -210,14 +226,17 @@ ROOT:.
│ tasks.json # 任务配置文件,包括一键编译下载调试等
├─.assets # 说明文档的图片
├─.Doc # 本框架的各类说明文档
├─.github # github action CI支持文件
├─application # 应用层
├─bsp # 板级支持包
├─modules # 模块层
├─Src #hal生成的外设初始化源文件
├─Inc #hal生成的外设初始化头文件
├─Drivers #hal driver和cmsis drivers
└─Middlewares # STusb ext , rtos , segger rtt等
├─Src # hal生成的外设初始化源文件
├─Inc # hal生成的外设初始化头文件
├─Drivers # hal driver和cmsis drivers
└─Middlewares # STusb ext, rtos, segger rtt等
```
## BSP/Module/Application介绍

View File

@ -6,29 +6,72 @@ VSCode的各种配置如快捷键、高亮颜色、主题、界面形状和位
## 快捷键
不管使用什么软件,基本的快捷键一定可以帮助你提高效率,更专注于当前正在做的事——减少双手离开主键盘区的频率和时间。
常用的快捷键已经在[VSCode的基础操作](VSCode+Ozone使用方法.md)中介绍这里推荐一些shortcuts的组合可以直接`ctrl+k&s`打开快捷键设置或进入`setting.json`手动修改。当然,你不一定要和我们的建议完全一致,**根据自己的习惯定制才是最好的!**
- `ctrl+;`设置为移动到行尾,同时保留`end`,这样在输完函数参数之后不用按`→`或使用鼠标
- `alt+j/k`设置为向左向右移动,这样在修改的时候不用按方向键;可以设置组合键达到”移动到符号末尾”的功能实现按符号或单词移动
- `tab`改为移动到下一个建议(智能提示),`enter`设置为接受当前建议。如果只有一个建议,`tab`直接接受;`alt+tab`移动到上一个建议。
- 设置一个组合键用于选中当前单词
- 记住当前文件查找和全局查找的组合,最好再学习一下**正则表达式**。还有”选中当前所有出现“,可以快速定位当前文件有哪些地方用了这个变量/函数。
- 熟练使用`ctrl+tab`切换当前已经打开的文件
- 可以在`setting.json`中将`task.json`中的任务绑定成你需要的快捷键,比如默认`ctrl+shift+b`是构建任务。把一些常用的命令行操作写成task通过快捷键瞬间触发。
- 善用右键菜单中的peek xxx功能、展开调用层级和头文件/源文件跳转以及git查看文件差异的功能这在理清代码结构、查看之前的更改的时候非常有用。当然不是让你按右键是使用快捷键。如果你的键盘上有一个像文件一样的图标当你聚焦在编辑区的时候可以按下它来替代右键展开菜单
- more...
## 提高效率
*若你使用触控板和笔记本电脑,也可以利用触控板实现一些实在找不到的快捷键功能。*一开始你可能会决定快捷键难记又难按,当你熟练之后,却会在无形之中极大提升你的效率。
## 代码高亮
虽然VSCode默认的语法高亮已经吊打KEIL和CubeIDE之流但你是否发现变量全是浅蓝色字符串、数值字面量内部也无法区分无出其右我们可以自定义各种entity的颜色
建议让copilot协助你完成打开`setting.json`开始设置吧:
- global、private member、public member、local设置为不同的颜色
- 私有函数和公开函数设置为不同的颜色
- static函数设置特殊的颜色
- 函数参数变量设置不同的颜色?
## 终端工具
你至少应该学习bashmsys2中会集成一套类linux的bash工具的基础指令如果有可能也学习一下powershell。在chatGPT或者Copilot的帮助下这易如反掌。当它们无能为力时请务必查阅**官方文档**而不是在CSDN中💩里淘🪙。
为你的终端配置好看的颜色、字体和背景,但不要花太多时间。一定要让你的终端具有补全和历史记录记忆功能。
学会在命令行中使用一些常用的git操作虽然vscode中已经提供了强大的图形化集成。
务必学习vi/vim/nano的基础操作。
熟悉在终端中创建/追加/移动/复制/删除文件和文件夹。
学习gnu工具链的简单指令协助你与编译报错信息一起定位bug和错误常常是undefined reference或未定义函数、未定义就使用
也许了解一下shell的工作原理或者更多现代操作系统的运行架构
> 为basic_framework通过串口/SWD建立一套简单的cmd有很多开源代码的实现期待你的PR
## 进一步提高效率
首先,快捷键一定要按的顺手,最好能让双手处于标准指法的起始状态就可以轻松触发。一定不要超过三个键,否则按起来手掌大开大合。
建议打开函数的自动括号补全一般在对应语言的插件设置中寻找同时习惯snippets的使用并根据自己的需要自定义一些方便的snippets。
如果你认为vim很酷那它确实很酷。vscode中有fake-vim插件喜欢折腾的话vim会让你在双手始终保持在键盘区劈里啪啦地编码只不过学习成本较高曲线复杂。
你最好升级一下默认的shellwindows下有好看的poshlinux则有广为流传的zsh。具体如何配置自行查阅**官方文档**。
记住最好将不同软件开发使用的环境隔离开所以你需要把msys2集成到vscode中macOS和linux用户忽略
把开发中常用但又繁琐的流程自动化,积累一套你自己的脚本库。
....

BIN
.assets/balance.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 MiB

BIN
.assets/engineering.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 MiB

View File

@ -17,4 +17,9 @@ jobs:
- uses: actions/checkout@v3
- name: make
run: make -j12
run: make -j12
- uses: seanmiddleditch/gha-setup-ninja@master
- name: ninja
run: cd build && cmake -G Ninja .. && ninja

3
.gitignore vendored
View File

@ -51,5 +51,4 @@ build
./idea
.vscode/.cortex-debug.peripherals.state.json
.vscode/.cortex-debug.registers.state.json
*.jdebug*
settings.json
*.jdebug*

64
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,64 @@
{
"files.associations": {
"robot_def.h": "c",
"bsp_dwt.h": "c",
"dji_motor.h": "c",
"message_center.h": "c",
"super_cap.h": "c",
"can_comm.h": "c",
"lqr.h": "c",
"math.h": "c",
"stdint.h": "c",
"general_def.h": "c",
"lk9025.h": "c",
"arm_math.h": "c",
"bmi088driver.h": "c",
"bmi088middleware.h": "c",
"bmi088_regndef.h": "c",
"bmi088reg.h": "c",
"balance.h": "c",
"stdlib.h": "c",
"memory.h": "c",
"bsp_usart.h": "c",
"compare": "c",
"limits": "c",
"*.tcc": "c",
"type_traits": "c",
"bsp_log.h": "c",
"segger_rtt.h": "c",
"referee.h": "c",
"referee_communication.h": "c",
"vmc_project.h": "c",
"user_lib.h": "c",
"quaternionekf.h": "c",
"bsp_usb.h": "c",
"robot.h": "c",
"rm_referee.h": "c",
"stdio.h": "c",
"crc.h": "c",
"bmi088.h": "c",
"cmath": "c",
"ht04.h": "c",
"gain_table.h": "c",
"referee_task.h": "c",
"task.h": "c",
"robot_task.h": "c",
"motor_task.h": "c",
"bsp_flash.h": "c",
"bsp_iic.h": "c",
"usbd_cdc_if.h": "c",
"kf.h": "c",
"none.h": "c",
"buzzer.h": "c",
"bsp_pwm.h": "c",
"main.h": "c",
"stm32f4xx_hal_conf.h": "c",
"master_process.h": "c",
"bsp_can.h": "c",
"can.h": "c"
},
"cortex-debug.variableUseNaturalFormat": true,
"C_Cpp.default.configurationProvider": "ms-vscode.makefile-tools",
// "C_Cpp.default.compilerPath": "D:\\Msys2\\mingw64\\bin\\arm-none-eabi-gcc.exe"
"makefile.compileCommandsPath": "build/compile_commands.json"
}

115
CMakeLists.txt Normal file
View File

@ -0,0 +1,115 @@
cmake_minimum_required(VERSION 3.16)
# /, Ninja,可以加快编译速度(相比make)
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
#
set(CMAKE_C_COMPILER_FORCED TRUE) # skip compiler test
set(CMAKE_CXX_COMPILER_FORCED TRUE)
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_ASM_COMPILER arm-none-eabi-gcc)
set(CMAKE_OBJCOPY arm-none-eabi-objcopy)
set(CMAKE_OBJDUMP arm-none-eabi-objdump)
set(SIZE arm-none-eabi-size)
set(CMAKE_AR arm-none-eabi-ar)
set(CMAKE_C_STANDARD 11)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
#
project(basic_framework C ASM)
#
set(CMAKE_BUILD_TYPE Debug) # Debug Release RelWithDebInfo MinSizeRel
# board specific settings, arch/fpu/instruction
set(MCU_FLAGS -mcpu=cortex-m4 -mthumb -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16)
set(LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/STM32F407IGHx_FLASH.ld") #
set(DSP_NAME "libCMSISDSP.a") # DSP
link_directories(${CMAKE_SOURCE_DIR}/Middlewares/ST/ARM/DSP/Lib)
# Generic compiler settings for optimization and basic link lib
add_compile_options(-pipe ${MCU_FLAGS} -Wall -Werror -fmessage-length=0 # basic options
-ffunction-sections -fdata-sections -fno-common # optimize options
)
add_link_options(-pipe ${MCU_FLAGS} -T${LINKER_SCRIPT} -Wl,--no-warn-rwx-segments # close RWX warning
-lm -lc -lnosys # lib options
-Wl,--gc-sections -flto -specs=nano.specs -specs=nosys.specs # optimize options
-Wl,-Map=${PROJECT_BINARY_DIR}/${PROJECT_NAME}.map -Wl,--cref -Wl,--print-memory-usage # map options
) # if your executable is too large , try option '-s' to strip symbols
# add_compile_definitions() works for compile stage
# while add_definitions() works for both compile and link stage
add_definitions(
-DUSE_HAL_DRIVER
-DSTM32F407xx
-DARM_MATH_CM4
) # need -D<macro> to define macro
# add inc
#
function(include_sub_directories_recursively root_dir)
if (IS_DIRECTORY ${root_dir}) #
message("include dir: " ${root_dir})
include_directories(${root_dir})
endif()
file(GLOB ALL_SUB RELATIVE ${root_dir} ${root_dir}/*) # ALL_SUB
foreach(sub ${ALL_SUB})
if (IS_DIRECTORY ${root_dir}/${sub})
include_sub_directories_recursively(${root_dir}/${sub}) #
endif()
endforeach()
endfunction()
include_sub_directories_recursively(${CMAKE_SOURCE_DIR}/Drivers)
include_sub_directories_recursively(${CMAKE_SOURCE_DIR}/Middlewares)
include_sub_directories_recursively(${CMAKE_SOURCE_DIR}/bsp)
include_sub_directories_recursively(${CMAKE_SOURCE_DIR}/modules)
include_sub_directories_recursively(${CMAKE_SOURCE_DIR}/application)
include_sub_directories_recursively(${CMAKE_SOURCE_DIR}/Inc)
# add source, only surfix .c
file(GLOB_RECURSE SOURCES
"Drivers/*.c"
"Src/*.c"
"Middlewares/*.c"
"bsp/*.c"
"modules/*.c"
"application/*.c"
)
#
# ENABLE_LANGUAGE(ASM)
set(ASM_SOURCES
startup_stm32f407xx.s
Middlewares/Third_Party/SEGGER/RTT/SEGGER_RTT_ASM_ARMv7M.s
)
set_source_files_properties(${ASM_SOURCES} PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp")
# Build types
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
message(STATUS "Maximum optimization for speed")
add_compile_options(-Ofast)
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
message(STATUS "Maximum optimization for speed, debug info included")
add_compile_options(-Ofast -g)
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel")
message(STATUS "Maximum optimization for size")
add_compile_options(-Os)
else ()
message(STATUS "Minimal optimization, debug info included")
add_compile_options(-Og -g -gdwarf-2)
add_definitions(-DESC_DEBUG) # ESC Debug
endif ()
# build binary and hex file
add_executable(${PROJECT_NAME}.elf ${SOURCES} ${ASM_SOURCES} ${LINKER_SCRIPT})
target_link_libraries(${PROJECT_NAME}.elf ${DSP_NAME} m) # link DSP lib and math lib
add_custom_command(
TARGET ${PROJECT_NAME}.elf POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -Oihex $<TARGET_FILE:${PROJECT_NAME}.elf> ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.hex
COMMAND ${CMAKE_OBJCOPY} -Obinary $<TARGET_FILE:${PROJECT_NAME}.elf> ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.bin
COMMENT "Building hex & bin file..."
COMMENT "EXCUTABLE SIZE:"
COMMAND ${SIZE} ${PROJECT_NAME}.elf
)

136
README.md
View File

@ -7,12 +7,17 @@
<p>
<img src="https://img.shields.io/badge/version-beta-blue"/>
<img src="https://img.shields.io/badge/license-MIT-green"/>
<img src="https://github.com/HNUYueLuRM/basic_framework/actions/workflows/c-cpp.yml/badge.svg"/>
</p>
<p>
<img src="https://gitee.com/HNUYueLuRM/basic_framework/badge/star.svg"/>
<img src="https://gitee.com/HNUYueLuRM/basic_framework/badge/fork.svg"/>
</p>
<h4><p><font face="仿宋">最棒的嵌入式电控开源?!</p></h>
<h5><p><font face="consolas">Best RoboMaster embedded EC open-source code ever?</p></h>
</div>
> ***也许不是最好的?但一定是最完整最详细最适合上手的电控开源!***
[TOC]
@ -32,11 +37,23 @@
## 功能介绍和展示
这是湖南大学RoboMaster跃鹿战队电控组2022-2023赛季的通用嵌入式控制框架可用于**机器人主控**、自研模组imu/测距等各种传感器、超级电容控制器等。该框架旨在打造上手简单、易于移植、高代码复用、层级分明、结构清晰的一套SDK供队内使用&RM参赛队伍&嵌入式开发者交流学习。
### 起源
通过精心设计的bsp和module支持以及成熟的app示例该框架可以在短时间内为不同类型和结构的机器人轻松构建电控程序可扩展性和可维护性相较目前的大部分开源代码和本队的老代码提升巨大
这是湖南大学RoboMaster跃鹿战队电控组2022-2023赛季的通用嵌入式控制框架可用于**机器人主控**、自研模组imu/测距等各种传感器)、超级电容控制器等
同时相较于传统的基于KEIL MDK开发的工作流我们提供了基于arm-gnu工具链+VSCode/Clion+Ozone&Systemviewer/FreeMaster的现代化开发工作流你再也不用面对上个世纪的UI忍受没有补全和高亮的代码了在配套现代化开发工具支持下将极大提高电控开发效率和调试效率。硬件模块测试和整车联调从未如此简单
从目前的RoboMaster开源社区来看大部分队伍都没有一套规则统一符合较大规模软件开发原则的框架有些学校连不同兵种代码都相去甚远甚至连队伍用于传承的代码注释都寥寥无几全靠师傅带徒弟言传身教。当然不乏有广东工业大学DynamicX开源的rm_control这样规范且先进的系统但基于Linux、ROS、C++的这套软件栈对于新人来说还是过于复杂(但我们很推荐熟悉基本工具的同学使用!)。
### 优势
为此basic_framework应运而生。该框架旨在打造上手简单、易于移植、高代码复用、层级分明、结构清晰的一套SDK供队内使用&RM参赛队伍&嵌入式开发者交流学习。通过精心设计的bsp和module支持以及成熟的app示例该框架可以在短时间内为不同类型和结构的机器人**轻松构建**电控程序,**可扩展性**和**可维护性**相较目前的大部分开源代码和本队的老代码提升巨大。
同时相较于传统的基于KEIL MDK开发的工作流我们推出了基于arm-gnu工具链+VSCode/Clion+Ozone&Systemviewer/FreeMaster的**现代化开发工作流**和非**常完善配套教程**你再也不用面对上个世纪的UI忍受没有补全和高亮的代码了在现代化开发工具支持下将**极大提高电控开发效率和调试效率**。硬件模块测试和整车联调从未**如此简单方便**
> 用软件开发的思想设计嵌入式系统是一种降维打击
>
> <p align=right>—— 沃兹基·烁德</p>
### 效果展示
![](.assets/allrobot.jpg)
@ -51,8 +68,58 @@
<center>展示中的视觉识别与预测算法是基于rm_vision打造的</center>
3. 工程机器人流程化抓取矿石/兑换矿石/救援’
![engineering](.assets/engineering.gif)
4. 平衡步兵机器人
![balance](.assets/balance.gif)
这些机器人的程序均基于basic_framework打造已在我们的仓库中提供[HNUYueLuRM](https://gitee.com/hnuyuelurm)
> 更多测试视频可以关注我们的bilibili账号[湖南大学跃鹿战队](https://space.bilibili.com/522795884)或在bilibili搜索跃鹿战队观看我们的比赛视频。
### 可用功能
你可以基于这些良好抽象的功能打造自己的模块或应用。
#### bsp封装
| 功能类别 | 模块 |
| ---------- | ----------------------- |
| 通信类外设 | usart spi i2c can usb |
| 日志 | log flash |
| 功能型 | gpio(exti) pwm adc |
| 辅助 | dwt |
#### 模块封装
| 功能类别 | 模块 |
| -------- | ------------------------------------------------------------ |
| 电机 | DJI、HT海泰04、瓴控LK、步进电机、舵机 |
| 通信 | 多板通信(基于CAN)、seasky协议上位机通信、裁判系统数据/UI/多机、vofa协议、DT7-DR16遥控器 |
| 功能模块 | 蜂鸣器、oled、bmi088、ist8310、超级电容、TFminiPlus、 |
| 应用支持 | 常用算法库、守护线程、消息中心 |
#### 应用封装
作为命令发布主体的robot_cmd
用于步兵、英雄、哨兵、无人机的gimbal
麦克纳姆轮/全向轮底盘的chassis
平衡步兵的底盘balance_chassis
装配了发射机构的机器人的shoot
---
## 架构
总览。
@ -65,31 +132,41 @@
### 设计思想
框架在结构上分为三层bsp/module/app。整体使用的设计模式是**结构层级模式**,即每个“类”包含需要使用的底层“类”,通过组装不同的基础模实现更强大的功能而最顶层的app之间则通过**pub-sub消息机制**进行解耦,使得在编写代码时不会出现相互包含的情况。
1. ***首先,总览框架的设计模式。***
**pub-sub机制的体现**以本仓库的app层为例包含了chassisgimbalshootcmd四个应用每个应用都对应了机器人上的不同模组。cmd应用负责从机器人控制信号来源遥控器/上位机/环境传感器)处获取信息并解析成各个**执行单元的实际动作**(电机/舵机/气缸/阀门等的扭矩/速度/位置/角度/开度等),并将此信息**发布**出去。chassis、gimbal、shoot等包含了执行单元的应用则**订阅**这些消息,并通过自己包含的子模块,调用它们的接口实现动作
框架在结构上分为三层bsp/module/app。整体使用的设计模式是**结构层级模式**即每个“类”包含需要使用的底层“类”通过组装不同的基础模实现更强大的功能。而最顶层的app之间则通过**pub-sub消息机制**进行解耦,使得在编写代码时不会出现相互包含的情况
**结构层级模式的体现**以chassis应用为例chassis中包含了4个底盘电机模块。当chassis收到cmd应用的信息希望让底盘以1m/s的速度前进。chassis首先根据底盘的类型舵轮/麦克纳姆轮/全向轮/平衡底盘)以及对应的动力学/运动学解算函数计算得到每个电机的输目标输入值此时chassis将输入通过电机模块motor module的接口将设定值告知电机。而每个电机模块又有各自的PID计算模块和自身电流&速度&角度传感器的信息可以计算出最终需要的电流设定值。假设该电机使用CAN协议与电调通信则电机通过自身包含的CANInstancebsp_can提供用于和实际硬件交互电机模块将设定值电流值或其他指令按照通信协议组织在CAN报文中通过CANInstance提供的接口把最终控制数据发送给电调实现控制闭环。可以看到**包含关系为chassis∈motor∈bspcan**。
我们希望通过bsp对硬件的抽象使得module的编写更为轻松不需要考虑底层的硬件具体是如何运作的再通过module的外接模块的抽象使得app的编写可以通过完全硬件无关的方式考虑达到*”只阅读module的说明文档就能迅速开发应用 ”*的程度。bsp和module的设计愿景就是成为人们常说的***中间件**。*
有了上面的大体认知,我们分别介绍框架的三层结构
**pub-sub机制的体现**以本仓库的app层为例包含了chassisgimbalshootcmd四个应用每个应用都对应了机器人上的不同模组。cmd应用负责从机器人控制信号来源遥控器/上位机/环境传感器)处获取信息并解析成各个**执行单元的实际动作**(电机/舵机/气缸/阀门等的扭矩/速度/位置/角度/开度等),并将此信息**发布**出去。chassis、gimbal、shoot等包含了执行单元的应用则**订阅**这些消息,并通过自己包含的子模块,调用它们的接口实现动作
- **bsp**即板级支持包提供对开发板外设的软件抽象让module层能使用和硬件无关的接口由bsp提供进行数据处理与交互。bsp层和ST的HAL为强耦合与硬件直接绑定。若要向其他的ST芯片移植基本不需要修改bsp层若是其他单片机则建议保留**接口设计**,对接口调用进行重现实现。每一种外设的头文件中都定义了一个**XXXInstance**xxx为外设名其中包含了使用该外设所需要的所有数据如发送/接收的数据长度id如果有父指针指向module实例的指针用于回调等。由于C没有`class`因此所有bsp的接口都需要传入一个额外的参数XXXInstance*用于实现c++的`this`指针以区分具体是哪一个实例调用了接口
**结构层级模式的体现**以chassis应用为例chassis中包含了4个底盘电机模块。当chassis收到cmd应用的信息希望让底盘以1m/s的速度前进。chassis首先根据底盘的类型舵轮/麦克纳姆轮/全向轮/平衡底盘)以及对应的动力学/运动学解算函数计算得到每个电机的输目标输入值此时chassis将输入通过电机模块motor module的接口将设定值告知电机。而每个电机模块又有各自的PID计算模块和自身电流&速度&角度传感器的信息可以计算出最终需要的电流设定值。假设该电机使用CAN协议与电调通信则电机通过自身包含的CANInstancebsp_can提供用于和实际硬件交互电机模块将设定值电流值或其他指令按照通信协议组织在CAN报文中通过CANInstance提供的接口把最终控制数据发送给电调实现控制闭环。从调用来看三个层级的**包含关系为chassis∈motor∈bspcan**
- **module**即模块层,包括了需要开发板硬件外设支持的(一般用于通信)真实**硬件模组**如电机、舵机、imu、测距传感器和通过软件实现的**算法**如PID、滤波器、状态观测器还有用于兼容不同控制信息模块遥控器/ps手柄/图传链路/上位机的统一接口模块以及为app层提供数据交互的message center。
2. ***有了上面的大体认知,我们分别介绍框架的三层结构。***
module层仍然是基于实例的一个app会包含多个module的instance。当app便可以用硬件无关的接口使用module如要求电机以一定速度运动、关闭气阀、给超级电容或上位机发送一些反馈数据等。在有了方便的bsp之后只需要在你构建的module中包含必须的bsp然后为app提供合理的接口即可
- **bsp**即板级支持包提供对开发板外设的软件抽象让module层能使用和硬件无关的接口由bsp提供进行数据处理与交互
- **app**是框架层级中最高的部分。目前的框架设计里会有多个app任务运行在freertos中当然你也可以根据需要启动一些事件驱动的任务所有的任务安排都放在`app/robot_task`中。当前的app层仅是一个机器人开发的示例有了封装程度极高的module你可以在app完成任何事情
bsp层和ST的HAL为强耦合与硬件直接绑定。若要向其他的ST芯片移植基本不需要修改bsp层若是其他单片机则建议保留**接口设计**,对接口调用进行重现实现。每一种外设的头文件中都定义了一个**XXXInstance**xxx为外设名其中包含了使用该外设所需要的所有数据如发送/接收的数据长度id如果有父指针指向module实例的指针用于回调等。由于C没有`class`因此所有bsp的接口都需要传入一个额外的参数XXXInstance*用于实现c++的`this`指针以区分具体是哪一个实例调用了接口
目前的app设计里可以兼容多块开发板的情况通过**条件编译**切换开发板的位置。如步兵机器人可以将主控MCU放在云台上而超级电容控制板同时作为底盘板。使用CAN/SPI/UART将两者连接便可以通过**`app/robot_def.h`**中的宏完成设置。可以根据需要,设置更多的开发板(双云台哨兵、工程机器人)
- **module**即模块层,包括了需要开发板硬件外设支持的(一般用于通信)真实**硬件模组**如电机、舵机、imu、测距传感器和通过软件实现的**算法**如PID、滤波器、状态观测器还有用于兼容不同控制信息模块遥控器/ps手柄/图传链路/上位机的统一接口模块以及为app层提供数据交互的message center
这套框架可以轻松扩展到所有机器人上在我们的仓库中有步兵机器人、平衡步兵机器人、哨兵机器人、英雄机器人、工程机器人以及空中机器人的代码实例皆按照本框架中的三层结构开发。若设计了新的机器人只需要在robot_def.h中修改传感器的位置、底盘轮距轴距、拨弹盘容量、弹舱载弹量等参数便可以**立刻实现部署**
module层仍然是基于实例的一个app会包含多个module的instance。当app便可以用硬件无关的接口使用module如要求电机以一定速度运动、关闭气阀、给超级电容或上位机发送一些反馈数据等。在有了方便的bsp之后只需要在你构建的module中包含必须的bsp然后为app提供合理易用的接口即可
至于bsp和module中每个instance的设计我们采用了**面向对象**的C风格代码整个框架也统一了变量和函数命名方式调用层级和数据流十分清晰下一个章节也有插图阐述
- **app**是框架层级中最高的部分。目前的框架设计里会有多个app任务运行在freertos中当然你也可以根据需要启动一些事件驱动的任务所有的任务安排都放在`app/robot_task`中。当前的app层仅是一个机器人开发的示例有了封装程度极高的module你可以在app完成任何事情
为了避免出现”底层代码包含上层头文件“的情况我们让bsp层instance在注册时要求module提供数据发送/接收的回调函数指针从而在发生对应中断或事件时完成对module函数的”反向调用“。事实上你也可以进一步将这套思想放入app的设计中当某个事件发生时触发app的任务而不是将app的任务定时运行这可以提高运行效率降低cpu占用)。
目前的app设计里可以兼容多块开发板的情况通过**条件编译**切换开发板的位置。如步兵机器人可以将主控MCU放在云台上而超级电容控制板同时作为底盘板。使用CAN/SPI/UART将两者连接便可以通过**`app/robot_def.h`**中的宏完成设置。可以根据需要,设置更多的开发板(双云台哨兵、工程机器人)。
bsp和module的instance在初始化时接口皆为**`XXXInstance* XXXRegister(XXX_Init_Config_s* conf)`**传入该实例所需的config参数返回一个实例指针看作this指针之后要调用模块的功能传入该指针即可。我们还提供了守护线程以供module选用当异常情况发生时在LOG中发送warning、触发蜂鸣器或LED进行声光报警以及错误/离线回调函数,保证系统的鲁棒性和安全性。
这套框架可以轻松扩展到所有机器人上在我们的仓库中有步兵机器人、平衡步兵机器人、哨兵机器人、英雄机器人、工程机器人以及空中机器人的代码实例皆按照本框架中的三层结构开发。若设计了新的机器人只需要在robot_def.h中修改传感器的位置、底盘轮距轴距、拨弹盘容量、弹舱载弹量等参数便可以**立刻实现部署**。
3. ***知道了每个层级的结构之后,我们再谈谈如何进行每层的开发。***
对于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进行声光报警以及错误/离线回调函数,保证系统的鲁棒性和安全性。
而对于app的开发由于底层接口已经设计的较为完善不同的机器人可以直接**`fork`** basic_framework的代码开发app层。当bsp和module有功能更新时只需要通过git的cherry-pick-commit功能将更新拉取到自己的仓库**获得动态的热更新而无需手动合并分支!**
@ -175,9 +252,11 @@ app、module和bsp都有相应的rtos任务。其中bsp为创建任务提供了
随后通过调试器将开发板连接至你的电脑点击上方tab页的终端terminal->运行任务run task)选择download_dap or download_jlink或你自己编写的stlink/ulink/...便会开始下载终端或jFlash中会提示擦除、下载、验证的进度。
想要调试在左侧tab页选择合适的调试选项按F5或图形界面的绿色小三角形按钮开始调试。
想要调试在左侧tab页选择合适的调试选项按F5或图形界面的绿色小三角形按钮开始调试。当然调试器的设置也请参考配置文档主要是将可执行文件路劲加入环境变量的PATH。
**更详细的开发流程,请参照`.Doc/VSCode+Ozone使用方法.md`**
**更详细的开发流程和本仓库工作流的最佳实践,请参照`.Doc/VSCode+Ozone使用方法.md`**,里面介绍了开发所需的前置知识、环境配置,以及工具链原理、使用方法等。
要对本仓库进行开发,务必先阅读`.Doc/架构介绍与开发指南.md`,内含本仓库组织结构的**文件树**。若你希望使用其他工具链或IDE里面也有相关说明。
### 基本文档
@ -187,7 +266,7 @@ app、module和bsp都有相应的rtos任务。其中bsp为创建任务提供了
- [Bug_Report](.Doc/Bug_Report.md) 提供了一些提交issues的模板范例若在使用中出现问题请按照模板提供信息。
- [TODO](.Doc/TODO.md) :框架后续开发计划和维护说明
- **[VSCode+Ozone使用方法.md](VSCode+Ozone使用方法.md)** **重要**上手必看。介绍了当前开发工作流和传统KEIL开发的不同先讲解一些与工具链有关的基础知识然后说明了如何配置开发环境安装必要的软件和一些”操作“。还涉及了VSCode编辑调试和Ozone示波器&trace功能的使用指南。
- **[VSCode+Ozone使用方法](.Doc/VSCode+Ozone使用方法.md)** **重要**上手必看。介绍了当前开发工作流和传统KEIL开发的不同先讲解一些与工具链有关的基础知识然后说明了如何配置开发环境安装必要的软件和一些”操作“。还涉及了VSCode编辑调试和Ozone示波器&trace功能的使用指南。
- [合理地进行PID参数整定](.Doc/合理地进行PID参数整定.md) 介绍了如何为PID控制器进行参数整定包括简单的经验准则和基于模型的前馈控制、扰动消除等方法。
- [如何定位bug](.Doc/如何定位bug.md) 当嵌入式开发出现bug时以更高效地方法进行错误定位和复现。简单的调试器使用技巧。
- [必须做&禁止做](.Doc/必须做&禁止做.md) :字如其名
@ -198,7 +277,20 @@ app、module和bsp都有相应的rtos任务。其中bsp为创建任务提供了
框架中的三层结构都有详尽的注释帮助阅读和二次开发三个抽象层都有各自总览的说明文档而每个bsp/module/app都配有对应的个性化说明文档提供了接口说明和改进或进一步开发的建议。
建议以自上而下的方式阅读代码app-》module-》bsp我们还提供了框架的说明视频分别讲解每个抽象层和总体的设计思路还有一些杂碎的开发相关知识[basic_framework教程]()
建议以自上而下的方式阅读代码app-》module-》bsp为此我们还提供了框架的说明视频分别讲解每个抽象层和总体的设计思路介绍了bsp的依赖HAL还有一些杂碎的开发相关知识[basic_framework教程](https://space.bilibili.com/522795884/channel/collectiondetail)
### 运行单个bsp/module测试
**每个bsp和module的文件夹中都有各自的说明文档**,测试用例和使用方法都在文档中给出,非常方便。
想要进行硬件查错、连线检查或测试,如测试开发板功能(外设)是否完好,电机电调能否正常使用,或给新人提供教学,只要:
1. 将main.c中的`RoboInit()`函数删除,然后包含`bsp_init.h`头文件,在原`RoboInit()`的位置添加一个`BSPInit()`
2. 包含用于测试的bsp或module头文件根据说明文档的用例初始化对应的支持包或模块即可。
3. 同时可以将实时系统的初始化注释或删除,在`main.c`的`while(1)`主循环中进行测试,也可以使用`bsp_tim.h`提供的定时任务。
4. 编译,下载,运行,调试。
我们为机械和视觉的同学能方便测试硬件模块的好坏,设计了一套通过串口和遥控器控制的**硬件功能测试程序**,使得其他技术组成员可以操作这个”黑箱“,在没有电控组成员的时候也不会卡住其他队员的进度。
### VSCode集成工具
@ -245,6 +337,6 @@ ST官方现在将HAL放入github维护。想要获取最新的支持可以自
## 致谢
本框架设计参考了哈尔滨工业大学深圳南工骁鹰🦅战队的EC_framework以及RoboMaster官方的RoboRTS-firmware🤖。姿态解算改进自哈尔滨工程大学创之翼🛩的四元数EKF姿态解算。裁判系统数据解析移植了深圳大学RoboPilot2021年电控英雄开源代码。
本框架设计参考了哈尔滨工业大学深圳南工骁鹰🦅战队的EC_framework以及RoboMaster官方的RoboRTS-firmware🤖。姿态解算改进自哈尔滨工程大学创之翼🛩的四元数EKF姿态解算。裁判系统数据解析移植了深圳大学RoboPilot2021年电控英雄开源代码。
感谢2022-2023赛季跃鹿战队电控组参与新框架测试和开发的队员们包括设计出机器人平台的机械组队员还有一起联调的视觉组队员以及负责拍摄、记录、宣传的运营组成员。

View File

@ -5,8 +5,8 @@ BSP
> TODO:
> 1. 增加硬件和软件CRC支持,统一不同crc顺序和计算码的调用方式
bsp的功能是提供对片上外设的封装即单片机芯片内部拥有的功能的封装。在开发板pcb上集成的模块应该放在module层而不是这里。
bsp的功能是提供对片上MCU中外设的封装,即单片机芯片内部拥有的功能的封装。**在开发板pcb上集成的模块(蜂鸣器加热电阻wifi等)应该放在module层而不是这里**
bsp应该提供几种接口。包括初始化接口一般命名为`XXXRegister()`(对于只有一个instance的可以叫`XXXInit()`,但建议统一风格都叫register)调用此模块实现的必要功能如通信型外设CubeMX下的connectivity提供接收和发送的接口以及接收完成的数据回调函数。
bsp应该提供几种接口。包括初始化接口一般命名为`XXXRegister()`(对于只有一个instance的可以叫`XXXInit()`,但建议统一风格都叫register)调用此模块实现的必要功能如通信型外设CubeMX下的connectivity提供接收和发送的接口以及接收完成、发送完成(若有必要,或有发送队列需求)的数据回调函数。
bsp_tools.h中提供了将bsp数据接收回调函数设置为任务的接口通过这种方式可以进一步提高整个系统的实时性同时保证高优先级的任务一定按时执行。
- bsp_tools.h中提供了将bsp数据接收回调函数设置为任务的接口通过这种方式可以进一步提高整个系统的实时性同时保证高优先级的任务一定按时执行。

View File

@ -106,7 +106,7 @@ CANInstance *CANRegister(CAN_Init_Config_s *config)
uint8_t CANTransmit(CANInstance *_instance, float timeout)
{
static uint32_t busy_count;
static float wait_time;
static volatile float wait_time __attribute__((unused)); // for cancel warning
float dwt_start = DWT_GetTimeline_ms();
while (HAL_CAN_GetTxMailboxesFreeLevel(_instance->can_handle) == 0) // 等待邮箱空闲
{

View File

@ -188,31 +188,31 @@ static uint8_t BMI088GyroInit(BMI088Instance *bmi088)
*/
static void BMI088AccSPIFinishCallback(SPIInstance *spi)
{
static BMI088Instance *bmi088;
bmi088 = (BMI088Instance *)(spi->id);
// static BMI088Instance *bmi088;
// bmi088 = (BMI088Instance *)(spi->id);
// 若第一次读取加速度,则在这里启动温度读取
// 如果使用异步姿态更新,此处唤醒量测更新的任务
}
static void BMI088GyroSPIFinishCallback(SPIInstance *spi)
{
static BMI088Instance *bmi088;
bmi088 = (BMI088Instance *)(spi->id);
// static BMI088Instance *bmi088;
// bmi088 = (BMI088Instance *)(spi->id);
// 若不是异步,啥也不做;否则启动姿态的预测步(propagation)
}
static void BMI088AccINTCallback(GPIOInstance *gpio)
{
static BMI088Instance *bmi088;
bmi088 = (BMI088Instance *)(gpio->id);
// static BMI088Instance *bmi088;
// bmi088 = (BMI088Instance *)(gpio->id);
// 启动加速度计数据读取(和温度读取,如果有必要),并转换为实际值
// 读取完毕会调用BMI088AccSPIFinishCallback
}
static void BMI088GyroINTCallback(GPIOInstance *gpio)
{
static BMI088Instance *bmi088;
bmi088 = (BMI088Instance *)(gpio->id);
// static BMI088Instance *bmi088;
// bmi088 = (BMI088Instance *)(gpio->id);
// 启动陀螺仪数据读取,并转换为实际值
// 读取完毕会调用BMI088GyroSPIFinishCallback
}
@ -258,6 +258,7 @@ uint8_t BMI088Acquire(BMI088Instance *bmi088, BMI088_Data_t *data_store)
// 如果数据还没准备好,则返回空数据?或者返回上一次的数据?或者返回错误码? @todo
if (bmi088->update_flag.imu_ready == 0)
return 0;
return 1;
}
/* pre calibrate parameter to go here */
@ -286,7 +287,6 @@ void BMI088CalibrateIMU(BMI088Instance *_bmi088)
// 一次性参数用完就丢,不用static
float startTime; // 开始标定时间,用于确定是否超时
uint16_t CaliTimes = 6000; // 标定次数(6s)
uint8_t buf[6] = {0}; // buffer
float gyroMax[3], gyroMin[3]; // 保存标定过程中读取到的数据最大值判断是否满足标定环境
float gNormTemp, gNormMax, gNormMin; // 同上,计算矢量范数(模长)
float gyroDiff[3], gNormDiff; // 每个轴的最大角速度跨度及其模长

View File

@ -4,7 +4,7 @@
#include "string.h"
static PWMInstance *buzzer;
static uint8_t idx;
// static uint8_t idx;
static BuzzzerInstance *buzzer_list[BUZZER_DEVICE_CNT] = {0};
/**
@ -84,6 +84,8 @@ void BuzzerTask()
case OCTAVE_7:
PWMSetPeriod(buzzer, (float)1 / SiFreq);
break;
default:
break;
}
break;
}

View File

@ -95,7 +95,7 @@ CANCommInstance *CANCommInit(CANComm_Init_Config_s *comm_config)
ins->can_ins = CANRegister(&comm_config->can_config);
Daemon_Init_Config_s daemon_config = {
.callback = NULL,
.callback = CANCommLostCallback,
.owner_id = (void *)ins,
.reload_count = comm_config->daemon_count,
};

View File

@ -18,8 +18,6 @@ float gyroDiff[3], gNormDiff;
uint8_t caliOffset = 1;
int16_t caliCount = 0;
static uint32_t offset_cal_DWT_Count = 0;
IMU_Data_t BMI088;
#if defined(BMI088_USE_SPI)
@ -333,17 +331,7 @@ void BMI088_Read(IMU_Data_t *bmi088)
{
static uint8_t buf[8] = {0};
static int16_t bmi088_raw_temp;
static float dt = 1.0;
static uint8_t first_read_flag = 0;
if (!first_read_flag)
{
first_read_flag = 1;
DWT_GetDeltaT(&offset_cal_DWT_Count);
}
else
{
dt = DWT_GetDeltaT(&offset_cal_DWT_Count) * 1000.0;
}
BMI088_accel_read_muli_reg(BMI088_ACCEL_XOUT_L, buf, 6);
bmi088_raw_temp = (int16_t)((buf[1]) << 8) | buf[0];

View File

@ -1,7 +1,8 @@
#include "bsp_dwt.h"
#include "ist8310.h"
#include "memory.h"
#include "stdlib.h"
#include "bsp_log.h"
#include <memory.h>
#include <stdlib.h>
// 一般这个模块只有一个实例,所以直接保存在这里,实际上不保存也可以,application可以自己保存
static IST8310Instance *ist8310_instance = NULL; // 用于存储IST8310实例的指针
@ -91,7 +92,7 @@ IST8310Instance *IST8310Init(IST8310_Init_Config_s *config)
IICAccessMem(ist->iic, ist8310_write_reg_data_error[i][0], &check_who_i_am, 1, IIC_READ_MEM, 1); // 读回自身id
if (check_who_i_am != ist8310_write_reg_data_error[i][1])
while (1)
ist8310_write_reg_data_error[i][2]; // 掉线/写入失败/未知错误,会返回对应的错误码
LOGERROR("[ist8310] init error, code %d", ist8310_write_reg_data_error[i][2]); // 掉线/写入失败/未知错误,会返回对应的错误码
}
ist8310_instance = ist; // 保存ist8310实例的指针

View File

@ -36,11 +36,11 @@ void LEDSwitch(LEDInstance *_led, uint8_t led_switch)
void LEDShow(uint32_t aRGB)
{
static uint8_t alpha;
static uint16_t red, green, blue;
// static uint8_t alpha;
// static uint16_t red, green, blue;
alpha = (aRGB & 0xFF000000) >> 24;
red = ((aRGB & 0x00FF0000) >> 16) * alpha;
green = ((aRGB & 0x0000FF00) >> 8) * alpha;
blue = ((aRGB & 0x000000FF) >> 0) * alpha;
// alpha = (aRGB & 0xFF000000) >> 24;
// red = ((aRGB & 0x00FF0000) >> 16) * alpha;
// green = ((aRGB & 0x0000FF00) >> 8) * alpha;
// blue = ((aRGB & 0x000000FF) >> 0) * alpha;
}

View File

@ -80,7 +80,7 @@ LKMotorInstance *LKMotorInit(Motor_Init_Config_s *config)
lkmotor_instance[idx++] = motor;
Daemon_Init_Config_s daemon_config = {
.callback = NULL,
.callback = LKMotorLostCallback,
.owner_id = motor,
.reload_count = 5, // 50ms
};