tips:如果你不知道什么是markdown,建议使用typora或vscode(安装Office Viewer(Markdown Editor)等相关markdown插件)打开此文件,以获得更优的阅读体验
所有代码文件的编码是GB2312
-
如果你是大佬,可以跳过我们的项目了,我们的车车只能勉强完赛,而且鲁棒性低
-
如果你是萌新,对于程序的整体结构一头雾水,可以尝试继续看看此文档;
-
如果你是来寻找灵感的,我们项目其实挺拉的,这里给一些我们项目为数不多的关键点指路:
- imgproc.c文件里面大津法和逆透视都是抄的,逆透视配合这个项目使用(为防止各种原因导致的仓库丢失或适配问题,我复制了一份我们用的逆透视到此仓库根目录下),注意逆透视只需要初始化一下就能直接调用了,原理是初始化一个映射,之后直接调用映射获得逆透视结果,几乎不浪费时间,这个代码还是挺厉害的
- imgproc.c里面的搜线是自中间往两边搜的,效果还行,凑活能跑,但是元素识别没写(虽然我们最后用电磁跑)
- 电磁过环岛在main.c的elec_handler函数里面,注释有提到,是用编码器半开环过的,可能不太实用,如果是刚开始尝试过环岛可以换成延时(注意不是直接调用delay函数,会出大问题,需要定义一个计数器count每次中断+1,根据中断时间计算计数器数值,计算公式在
pit.h中Delay_cnt_calc函数,我们的定时器中断时间是1ms,所以直接返回x,如果不是1ms需要改这里的函数,main.c文件的elec_handler函数有用到) - 编码器均值滤波可以直接抄
motor.c的Speed_Low_Filter函数 - adc的卡尔曼滤波可以直接抄
Read_ADC.c的kfp_init_son,kfp_init,kalman_filter函数
我们首先来认识一般情况下一个基础项目的文件结构:
- libraries:我们的程序在运行时要用到的库函数,在智能车竞赛中,这些函数一般由逐飞或龙丘提供,取决于你购买的是谁家的主板。对于这些函数的使用方法,一般逐飞或龙丘商家会提供许多例程(可以找淘宝客服索要),可以通过查看例程来了解使用。例程一般还用来调试硬件某个外设是否正常工作。例程一般分两部分,一部分是芯片自带的例程(也一般是逐飞或龙丘写的),包括pit、uart、pwm(这些是类似于芯片的基础功能)等的使用方法;还有逐飞或龙丘提供的外设例程,比如舵机、电机、屏幕、摄像头、adc等一堆外设
- project:此文件夹存放我们实际编写的代码和程序编译时产生的文件,通常会有
code和user文件夹,以及一个芯片对应的工程文件夹。- 不同的芯片一般会有不同的软件帮助编译你的项目(当然可以只下载工具链然后在命令行操作编译,下载这些软件可以帮助我们一键编译),我们的是
mrs文件夹,对应沁恒芯片的mounriver studio软件,还可能是arm家的keil5之类的软件,对应项目文件夹名一般为MDK之类的。 - code:此文件夹存放你编写的程序,其他芯片也是一样
- user:此文件夹一般存放
main.c,main.h,isr.c,isr.h。其中main文件是程序运行主文件,程序运行从这里开始,一般在这里放置所有的初始化代码。isr文件一般用来放置各种中断,我们常用的是pit中断,初始化pit后会定时触发对应的中断,运行中断代码。 - 某些智能车项目会用到双核处理,一般可以在user文件夹内通过文件名发现。
- 不同的芯片一般会有不同的软件帮助编译你的项目(当然可以只下载工具链然后在命令行操作编译,下载这些软件可以帮助我们一键编译),我们的是
- main文件内main函数,进行所有外设初始化
循环:{
- main函数while循环(内部可以放置一些代码,也可以空置,但似乎一定要有)
- 中断函数(isr.c中TIM6):写一个总的
handler函数放到code文件夹中(我实际放到了main.c,那里已经成狮山代码了),然后在中断函数处调用。对于中断的使用,参考逐飞或龙丘提供的pit例程。
}
- 我们不需要自己手动创建一个新项目,在gitee(是程序猿们分享代码的地方,类似的还有github)上逐飞或龙丘会开源对应的空项目,一般搜索
逐飞+芯片型号即可,一般会和例程以及板子的原理图之类的放在一块。 - 如果不出意外的话,你会在我们的项目文件夹中看到除了上述提及的两个文件夹之外的文件夹:
- .git:是Git的相关文件,Git是一种版本控制工具,可以帮助程序猿进行版本控制和多人协作开发,具体使用方法请自行搜索
- .gitignore:也是Git相关的,请自行搜索作用
- .idea和CMakeLists.txt:使用CLine开发时配置的东西,另一个队友非要用CLion搞这些,我的建议还是使用芯片对应的IDE,以完成比赛任务为主。
- 2021校内赛3.1:是我们这年校内赛的代码,很简单,但是和我们的项目的大体控制思路是相同的,看不懂我们的代码建议先看校赛代码。
- 你可能在网上搜索资料时会反复看到“上位机”一词,如果你是第一次做车,建议先跳过这部分,如果你是大佬,相信你能找到相关资源(我可能会将匿名上位机给到社团,可以询问相关负责人)。如果你是新手但是手痒难耐,可以尝试逐飞提供的摄像头上位机以及虚拟示波器(应该可以向客服索要到相关软件,我也可能会给到社团,如果需要可以询问相关负责人)
- 我在b站找到了一个帮助做逆透视的小软件,效果还不错,项目地址:https://github.com/wu58430/RUBO-UDIPM.git
- 注意比赛时只有15分钟左右时间(我们今年是这样的,第一天15分钟第二天8分钟)给你调车以及跑成绩,其他时间基本没有条件调车或者根本碰不到车。如果你是用摄像头巡线,省赛场地曝光很玄学,需要调很久,提前注意下;如果你是用电磁巡线,注意在铺赛道的时候尝试换用一些不同粗细的导线铺场地,效果会有很大不同,我就被这个坑了,比赛时刺激调运放:(
谁也不敢说自己熟悉c语言的编写,以下注意事项建议仔细阅读,否则大概率过不了编译还找不到哪里出问题:
- 首先我们要明确.h文件和.c文件其实是一样的,唯一区别是.h文件的代码会由
#ifndef xxx和#endif包含起来,作用是声明一个变量。对于“声明”,意思是.h文件向同一项目下的其他文件告知某个函数已经定义过了,你可以调用他,使用他,修改他。变量的声明格式为extern 变量类型 变量名称;,注意变量的声明不可以赋初值,变量的定义才可以赋初值;函数的声明格式为函数返回值类型 函数名(形参类型 形参名)。 - 一般来说,对于某个外设或功能,我们新开一个文件编写对应的函数以及变量,例如电机对应的文件
motor.c和motor.h。c文件放置函数具体的内容以及变量定义,h文件放置函数的声明以及需要在其他文件调用的变量的声明。当h文件放置变量定义时,一般会报错变量重复定义,原因是当多个文件include该头文件时,重复定义了变量,但是声明时是可以多次声明的,这也是为什么变量声明不能赋初值。 - pit中断时长要长于中断函数的运行时间,否则会导致无法预测的奇怪错误。测试函数的运行时长可以使用计时器timer,例程一般也会有,或者可以自己再逐飞libraries里面找一找以timer命名的文件。调用方法参考main.c的img_handler函数,不同芯片可能有不同的方式。
后面是原本这个文件存放的内容,是一些在做车车过程中遇到的坑以及给队友写的车车调试帮助
可以在code/config.h文件中进行一些配置,如:
- 指定车辆类别
- 电机调试模式,可以通过蓝牙在上位机虚拟示波器中显示左右轮数据
- 舵机调试模式,可以通过蓝牙在上位机虚拟示波器中显示舵机偏差
- 双击打开即可
- 双击界面下方的
COMx|Baud=xxxxxx|Data Length = 8...,可以打开一个窗口,调整Baud rate(波特率)为115200,Comm No.为蓝牙USB接在电脑的串口号,其他为默认(可以通过default按钮将示波器参数重置)。 - 现象:电脑与车车配对,蓝灯长亮;发送数据时,蓝灯闪烁;未连接时红灯亮;未通电全灭
- 从正看屏幕方向,屏幕右边自上到下四个按键分别为1,2,3,4
- 按键123指代速度低中高(小车10/20/30,大车15/23/30)三挡
除非先前已经通过调试获得其他pid参数,否则必须依照提供的电机pid参数数量级烧录
除非先前已经通过调试获得其他pid参数,否则必须依照提供的电机pid参数数量级烧录
除非先前已经通过调试获得其他pid参数,否则必须依照提供的电机pid参数数量级烧录
- 电机pid在
code/motor.c的PID_param_init()函数内,注意需要同时调左右轮,一般情况下两个轮一样的pid就行。理论上只调pi就可以得到目标效果。先调p再i最后d,参数数量级参考:kp0.06,ki0.000038 - 舵机pid是
code/servo.c的elec_Kp函数,只需要调pd,参数数量级参考:kp15,kd0.9
- 显示屏最上方的图像很卡,显示屏最后一行
imgproc time:数量级为一千:可能的原因是车车没有插蓝牙模块,卡在高频IO - 舵机不动:重插一下舵机线;车车没有放到赛道上;赛道电磁线没通电
- 舵机乱抖:检查
code/config.h文件内车车类型是否指定正确 - 电机不动:车车没有放到赛道上;赛道电磁线没通电
- 示波器没数据,蓝牙模块蓝灯常亮:检查示波器软件参数是否填对(参见
示波器使用相关);检查code/config.h文件内是否开启舵机调试/电机调试 - 烧不进去程序:换个烧录线;检查烧录线是否插紧
- 开机白屏:用printf大法判断是否进入while1。前者检查一下外设是否都插上了(特别注意,有来有去的两个数据脚要反着接),后者检查一下中断是否有死循环。
- MounriverStudio烧程序提示要升级芯片:别升级,退回IDE的版本到1.84。国产软件辣鸡得很,不要对新版本抱有期望。
- 外设别用胶带缠在杆子上:杆子导电,必能点亮外设
- 使用万用表别手抖:一根表笔同时戳到VCC和GND。。。。。/doge
- 12V的导线的接头要修剪干净,不能露出来毛:毛刺够长能搭到旁边的负极打火
- 最好别有悬空的杜邦线引脚:同上,指不定车车跑着跑着就放烟花咯,说不定怀里还能多一只宵宫老婆🤤🤤🤤/doge
- 板子尽量用绝缘胶带缠一下,防止电路板被短路,现象是显示屏异常黑屏等
对于18届比赛情况,我可以悲观的说,由于口罩原因,我们的传承基本断层,获得过国奖的学长已经在为硕导打工/考研等,留给我们的资料仅仅是学长在年初的讲座和传承代码(但是当时我们什么也不会,根本听不懂QAQ)。我们的项目代码baseline都是我靠自学和参考其他看不懂的资料一个个字母敲出来的,随后有计科队友加入并帮助完善和进一步编写模块代码,总之就是好难😭😭😭