# Draft **Repository Path**: Why7788/draft ## Basic Information - **Project Name**: Draft - **Description**: 机器人队全向轮以实践模板框架 - **Primary Language**: Unknown - **License**: AFL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-08-07 - **Last Updated**: 2023-12-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 代码编写规范 #### 介绍 机器人队全向轮以实践模板框架 #### 软件架构 总的来说就是每个文件夹中,.c文件放.c,.h放.h文件。keil内的工程结构与电脑上的文件结构一致 1. Algorithm文件夹中放算法文件,包括pid、滤波等 2. APPs文件夹中放具体实现的功能,比如小车的运动,运动学解算等 3. Devices文件夹中放对设备的控制文件,比如电机协议以及控制 4. BSP文件夹中放对板子上外设的操作,比如CAN通信的具体实现,串口通信每帧数据的编写等 5. Tasks文件中放最终的简洁的任务函数。 #### 代码排版 推荐使用[Keil代码自动排版配置工具AStyle_keil astyle_CDamogu的博客-CSDN博客](https://blog.csdn.net/qq_33704787/article/details/126089602) 可以自动辅助排版,使用默认的代码风格即可(缩进四个字符,运算符两侧都加括号,花括号另起一行,括号内变量统一用空格隔开等) #### 函数变量及其接口 ```c // 假设现在要实现一个任务Robot_Control,它需要用到底盘的各种数据和函数。 // 第一步在APPs对应的具体功能的.h文件中建立两个结构体,一个装数据,一个装函数,如: /* 底盘运动 */ typedef struct { float targetXRaw; //底盘x轴原始数据 float targetYRaw; //底盘y轴原始数据 float targetZRaw; //底盘z轴原始数据 float LpfAttFactor; //底盘滤波系数 float targetXLPF; //底盘x轴滤波后数据 float targetYLPF; //底盘y轴滤波后数据 float targetZLPF; //底盘z轴滤波后数据 float speedLimit; //底盘速度限制 uint16_t OmegaLimit; //底盘速度限制 float Trace_Distance; //跟随装甲板距离 float FollowtargetYawRaw; //底盘目标Yaw轴跟随云台原始数据 float FollowtargetYawLPF; //底盘Yaw轴跟随云台滤波后数据 float SpeedChange_Factor; //速度改变因子 float SpeedLimit_Factor; //限速因子 uint8_t mode; //底盘控制模式 uint8_t swingFlag; //扭腰标志位 float spinSpeed; //自旋速度 float swingSpeed; //扭腰速度 uint8_t PowerOverflowFlag; //超功率标志位 } Chassis_t; typedef struct { void (*Chassis_Init)(void); void (*Chassis_processing)(float Vx, float Vy, float VOmega); void (*ChassisCapControl)(void); } Chassis_FUN_t; // 强烈建议在必要的时候使用枚举、位域、联合体等数据结构精简代码和内存 // 第二步编写对应的代码即可 // 此处省略数据的获取以及具体的函数 // 第三步创建初始化宏定义,即对应着结构体的结构。如对应上方的两个结构体,初始化宏定义应该为(第一个没有找到对应的在哪里,找了个其他数据结构体的): #define LBWHEEL_PID_PARAM \ { \ 0, \ 0, \ 0, \ 0, \ 0, \ 13.0f, \ 0.5f, \ 0.0f, \ 0, \ 0, \ 0, \ 0, \ M3508_MaxOutput, \ 3000, \ &Incremental_PID, \ } #define Chassis_FUNGroundInit \ { \ &Chassis_Init, \ &Chassis_processing, \ &ChassisCapControl, \ } // 第四步,连接。也就是建立一个真正要用的对应的结构体变量,然后取等号就可以。需要注意的是,这一步之前所有宏定义中用到的东西都要定义好。尤其需要注意的就是函数,一定要在这一步之前先把对应的函数声明了。 // 最后也可以像他一样undef,把之前用的宏定义删了,节省空间。 Chassis_FUN_t Chassis_FUN = Chassis_FUNGroundInit; #undef Chassis_FUNGroundInit ``` 即努力向面向对象编程的方向靠近。 #### 变量以及函数命名 1. 不应使用拼音来进行命名,所使用的英文单词除非常用外不可缩写,应尽量保持可读性。 可以缩写的单词如: ``` argument 可缩写为 arg buffer 可缩写为 buff clock 可缩写为 clk command 可缩写为 cmd compare 可缩写为 cmp configuration 可缩写为 cfg device 可缩写为 dev error 可缩写为 err hexadecimal 可缩写为 hex increment 可缩写为 inc initialize 可缩写为 init maximum 可缩写为 max message 可缩写为 msg minimum 可缩写为 min parameter 可缩写为 para previous 可缩写为 prev register 可缩写为 reg semaphore 可缩写为 sem statistic 可缩写为 stat synchronize 可缩写为 sync temp 可缩写为 tmp function 可缩写为 fun ``` 2. 变量与函数命名统一采用**下划线分隔单词**的方法来命名,尽量**首字母大写**,对于特殊名词可以全部大写。 分隔单词的顺序应尽量采用从目标到功能的方法,如 M2006_Array_Data或M2006_Data表示M2006的数组,M2006_Fun来表示M2006用到的函数等 3. 对于私有的函数或者变量,不希望引用的,应在名字前加上两个下划线__.、 4. 尽量避免命名中出现数字,除非有明显的指向。否则难以理解其意思 #### 变量以及函数定义 1. 能使用函数的地方尽量使用函数,除非不得以否则不要使用包含过多参数的宏定义 2. 文件留出的接口应该清晰明了 3. 供外部使用的变量可以在头文件中extern,且只能通过包含头文件的方式使用其他 .c 提供的接口,禁止在.c 中通过 extern 的方式使用外部函数接口、变量。如果有只想让部分包含该头文件的文件使用这些接口,可以再开一个头文件单独extern这些变量。 若a.c使用了b.c定义的foo()函数,则应当在b.h中声明extern int foo(int input);并在a.c中通过#include 来使用foo。禁止通过在a.c中直接写extern int foo(int input);来使用foo,后面这种写法容易在foo改变时可能导致声明和定义不一致。 4. 每个函数应该只有一个清晰的功能,同理每个结构体变量也应该只有一个清晰的储存内容,不需要面面俱到 5. 重复代码应该尽量提炼成函数,不要一味的复制粘贴。有必要的话可以将跨文件使用的重复函数单独放置在一个文件中 6. 每行的代码长度不应该超过80,过长的语句应该使用换行等方法缩短; 如果是函数的形参定义过长,应让各个形参以第一个括号为起始分行对齐。 #### 头文件 1. 应避免头文件嵌套的问题,尽量避免囊括过多不必要用不到的头文件 2. 每个.c文件应该有一个同名的.h文件用来声明对外的函数接口 3. 总是编写#include保护符 ```c #ifndef VOS_INCLUDE_TIMER_TIMER_H #define VOS_INCLUDE_TIMER_TIMER_H ... #endif ``` 4. 尽量避免在头文件中定义变量,这样有可能导致头文件被其他.c文件包含而导致变量重复定义 5. 头文件的功能也应该尽量单一。 #### 注释 1. 注释应该简洁明了,标注在语句的上方或右侧。 2. 标注在语句上方的注释应用 ```c /* content */ ``` 标注在语句右侧的注释应用 ```c // content ```