上午:开会(介绍赛事)
下午:
1.TC264用的开发环境是ads,严格按照ads的说明书操作。下载程序到MCU不需要像STC那样用ISP,直接用ads里面的一个小黄点。
逐飞库TC264各个量的解析
2.在用ads下载时下载成功显示的“Flashing was successfull”
晚上:
1.写了一个“我眼中的PID”
2.FTM模块是由多个FTM寄存器组成,用于计数,也可以说一个神奇的模块(高级定时器模块),
[跟我学OSKinetis]第8课-FTM的PWM、输入捕获、正交解码
3.数字舵机比模拟舵机多内置一个MCU,更精确,但这不说明数字舵机就比模拟舵机好用
4.核心板与单片机,母版是测试用的单片机加很多拓展那个
5.驱动电路可以简单理解一个升压电路
6.USB转TTL模块的作用是电脑供电是5V,但通信模块对应的是3.3V的电压,所以可以把这个模块理解一个降压器
7.NRF模块就是插在核心板上用来发送蓝牙数据的那个
8.ADC:连续的模拟信号转离散的数字信号
上午:
继续完善PID控制的博客,看C语言精讲
1.龙邱科技的TC264
2.龙邱科技类似于逐飞科技,都是学习智能车的好地方,两者的淘宝详细页面都有对应学习资料
逐飞TC264淘宝详细页面
龙邱TC264淘宝详细页面
3.Debug模式与Release,可能出现Debug不报错,Release报错的情况
4.ads导入工程
5.校赛使用车模(C车模)
下午:
安装Qt5.9.4、Cmake3.20.5、Opencv4.53,Cmake和Qt搞定了,Opencv还没有弄好
晚上:
1.继续安装opencv,MinGW 就是 GCC 的 Windows 版本 。
mingw的安装包(官网打不开,这个是直接找的安装包)
2.win10系统下的QT+cmake+opencv的安装(小白,超详细教程)
最后一步mingw32-make的前提是要先安装mingw
3.排线的母头是排座那种(被插),公头是尖的
上午:
继续琢磨如何在Qt下使用opencv,在11点过暂时放弃了,确实弄不出来,后面再说吧
1.Opencv的安装路径不能包含中文
2.windows同一个盘中不能有两个名字相同的文件,大小写变化不能改变文件属性,比如说不能叫QQ和qq,二者不共存,会造成你放在同一层目录时,后来的会被吃到前一个里面去
下午:
在台风天的工作,在徐学长和王学长的帮助下终于解决了opencv的问题,太激动了,那接下来继续看图像处理的go文件了
opencv专题:
1.解决了头文件opencv2\opencv.hpp: No such file or directory的问题
2.有时候在Qt中编译出错可以尝试把它注释掉,在.pro和MATLAB等特殊文件中注释是#,其他一般都是//
3.文件目录在windows下一般选择用/,而不是
4.被注释掉的这一行是会报错的,只不过通过注释强行忽略了
5.#include
6.点“readData”后去找储存的图片,然后J是读取下一帧,K是读取前一阵,G是一直播放,再按一次暂停。
模块结束
1.opencv也只是一个工具,工具只要掌握它的使用
2.总钻风的差比和算法:这是最简单的摄像头算法,用两个像素点的值计算,abs(a-b)*100/(a+b)),乘100是为避免浮点数,加快运算速度
3.*CCD(英文全称:Charge-coupled+Device,中文全称:电荷耦合元件),是一种光学器件,可将光学信号转换为数字信号
线性CCD简介
【思路】线性CCD & 摄像头搜线方案 By“逐飞科技”
这就是巡线
4.时序图:二维图,依据时间顺序纵向排列
5.VScode里面将UTF-8替换为GBK,是为了处理中文乱码问题
6.#ifdef与#endif的作用及用法
7.学习名称空间,using namespace std
傍晚:
继续学习图像处理
1.逐飞和龙邱的TC264都是照着英飞凌公司的样片制作
2.基于TC264的摄像头、编码器、舵机使用视频教程–逐飞科技
3.RGB(红绿蓝):常说的显示器RGB色域,就是由这三原色组成。
4.学习成像原理
上午:
继续学习图像处理
1.获取灰度直方图:通过直方图能获取更好的边界阈值,实质为两个数组,一个用来记录像素点的灰度值,另一个记录此灰度值出现的个数,根据两个数组绘制直方图(初中学的);
类似这种 ↓
这种 ↓
数字图像处理(15): 灰度直方图(matplotlib 和OpenCV 绘制直方图)
归一化直方图:指将纵坐标换为此灰度级出现的概率
2.大津算法(OTSU)又称为最大类间方差法,目的:寻找全局图像的阈值。也叫基于阈值的分割算法
OTSU算法(大津法—最大类间方差法)原理及实现
下午:
1.种子生长算法:包括泛洪法,扫描线法,区段法三种
种子生长算法
2.电磁及摄像头(总钻风)寻迹算法浅析–逐飞科技
3.阳光算法,即之前提到的OTSU大津算法
4.allmap是摄像头真正采集到的,basemap是由allmap进行搜边界得到的,leftmap由basemap搜而得到
晚上:
上了学校的PCB网课,除此之外好像也没做什么了
1.色环电阻读数
这个例子中的27000Ω的举例是差一个颜色的,最后的银色表示误差率
白天帮同学安软件
上午:
用AD画原理图(作业)
2.电感
3.线是Ctrl+W,请区别线与引脚,引脚具有电气特性,线没有;且在AD中,线是可以斜着,但引脚线都是横平竖直
4.Designator——序列号,Comment——名称
5.改元器件都是在元件库里面改的,而不是在原理图上
下午:
1.补一个qt的问题,这个错因是opencv的版本问题,解决方案是在mainwindows里加#include
2.sch原理图里面的CLK端口是时钟端口
晚上:
轮廓提取浅谈(实现绘制basemap)
1.白色是0,黑色是1,边缘赋值2(转换后)
2.insidemap一般在有终点线(出发线)时会有显示黑色
3.为什么是YX,而不是XY,是因为最初定义的是uint8_t allmap[YM][XM],YM与XM是图像的XY极限
4.与递归有关的四个if,是在最初找的那个点的四周的情况,所以我们才看到y不变,x加减1,;x不变,y加减1
5.因为basemap是通过allmap形成的,当allmap里面出现黑点,就是allmap[Y][X]=1时对应于basemap[Y][X]取2,即找到的边缘点,多个边缘点形成线
晚上上课
1.永远左上角为1,开始逆时针转
2.丝印层:PCB最外层,用于注解,白色
3.双列直插(DIP封装)、贴片(SOP封装)
4.AD里面的线不能放缩,不是图片;但在sch原理图里面的矩形可以拖拽
杂:
1.轮廓在人眼中有方向趋势,在机器看来是一堆点,全部边沿点拼成轮廓
2.白底,黑边界,找边界,对于灰度图,二维图像,两个点差值,临界时的黑白点差值大于固定值(阈值)就可以认定为边界。
3.白不是绝对白,黑不是绝对黑,一个灰度图,两个点的差值是不断变化的,每时每刻都需要去计算那一个阈值。
4.峰峰值:是指一个周期内信号最高值和最低值之间差的值
一阶矩:一阶矩就是期望值,换句话说就是平均数
5.大津法:首先计算对象是每一行或者整张图片,计算它们像素点的平均值和峰峰值,通过判断一整行的平均值是否大于峰峰值的一半,大致就可以判断出黑白。在此基础上,又保证这两个点的像素值的差小于平均值的一半,这样就得到了一种颜色时的阈值。
上午:
1.排针里面的1~12指管脚的名称,而不是序列号;左上角P3是序列号,下面的Header 12是名称
2.最开始创建一个新的一定要创建项目,不是直接创建原理图,不然一被意外关闭就没了
3.网络标签(P+N)、网络标号:有助于模块化,一个传送门
4.电源端口,右键可选择不同的
5.在原理图里面的线是有电气特性的,而元件库里面的线没有
6.电容叫cap
电容容值表示,105也是一种
7.Y键是取关于原点对称(翻转的一种)
8.DAC、ADC,数字模拟转换器,D→A和A→D,Digital(数字的)、analog(模拟的)
9.RESET:复位按键
10.XTAL:库当中的XTAL就是晶振
11通用No ERC标号:细红×,代表这个口不接(快捷键P+V+N)
12.阵列式粘贴:对于黄色框的多引脚直接绘制,E+Y,记住要点那个初始的第一个
下午:
1.一键标注原理图中问号(针对序列号):工具+标注+原理图标注+Reset All+接受变更(创建ECO)+执行变更
画好两个,剩下的按住Shift走,也可以实现数字规律排列
巡线
1.种子生长法目的:获得赛道引导线(中线)
2.全局变量一般储存在内存中,局部变量存储的区域就是栈,因为图像处理所需容量大,所以需要进行简单的内存分配
3.流程
4.简记对于祖传代码的学习流程
一、看go文件里面的对于各个赛道元素的处理,直线、左右转等,它们分别对应一个函数;二、图像上位机里面,这些参数对应的图像处理得到的边界,它们只是代称,如果要转换为代码中的变量需要在mainwindow.cpp去找它们真实反映的是哪一个参量,真实的参量出现在代码中,如果在看代码时遇到它们记得按上述流程查找它们的含义。
晚上:
1.搜图会反复用到这个函数,把leftmap、rightmap、basemap等都当做map代入
2.原本按照灰度值,黑色为0,经常这样转换后,黑色为1,白色为0了
3.经过search函数后(allmap到basemap),图像变成0和2,0为白色,2为边界
4.状态机:状态机是有限状态自动机的简称,是现实事物运行规则抽象而成的一个数学模型。
5.最小二乘法:可用于识别直线、曲线或圆弧
6.boom表:指工程的元器件选型表
7.AD打开封装管理器时报错no valid components to change:原因所有工程没有放在一个项目下
8.编译时报错“has only one pin”,直接添加一个No ERC标号就不报错了,其实这个错误的原因是网络标号只有一个,软件找不到它对应的另一个(即单端网络)
晚上上课
1.走线从直到竖夹角135度
2.AD里面单位有英制和国标两种,ml和ms
上午:
1.PCB封装:是电子设计图纸与实物间的映射体
焊盘:用于焊接器件
1脚标识:用于区分正反
阻焊:作用是防止绿油(阻焊油俗称绿油)覆盖,包裹在焊盘外围
通孔:打通的小孔,Multi-Layer
表贴:在板子上面一层用焊锡连接器件,Top Layer
一个完整PCB封装需要的内容
2.小贴士——输入法:因为AD里面会用到很多快捷键,所以建议把输入法换成美式键盘
3.如何找元件对应封装:元器件的手册里面会有
例:二极管
4.切换3D状态:Ctrl+D,转向拖拽Shft+鼠标右键
5.测距:R+P
6.丝印层:画丝印在丝印层画,AD下方的Top overlay。画线:P+L
7.移动指定距离:M+通过x,y移动选中对象
8.在PCB图中按D,选第二个,去实现元器件的导入
下午:
1.极性电容与普通电容:左为极性,右为普通
2.按住Shift加鼠标拖动,可以把元器件拖出来
3.因为封装不同的原因,建议全部都调用一个库里面的,或者说严格按照boom表来找封装
4.出现unknown pin
Altium Designer 更新到PCB时出现unknown pin
如何使用嘉立创导出原理和PCB:
前提:注册
1.来到嘉立创EDA(相当于一个在线的AD),而不是嘉立创官网或嘉立创商城
2.点左边的元件库,找到需要的,放置在图纸上,保存,找到导出即可得到工程文件
晚上:
结构体
1.结构体里面的“.”表示访问结构体的元素
2.结构体:学长的代码很多由结构体组成,就像下面的例子,today这个结构体是由day、month、year三个元素组成,再进一步判断,这可以用判断赛道元素
3.两个结构变量是可以赋值的
上课记录
1.数字电路的地:单片机的地;模拟电路的地,是外部的;用0欧电阻或0欧电感来数字电路和模拟电路的共地
2.覆铜:所谓覆铜,就是将PCB上闲置的空间作为基准面,然后用固体铜填充,这些铜区又称为灌铜。覆铜的意义在于,减小地线阻抗,提高抗干扰能力;降低压降,提高电源效率;还有,与地线相连,减小环路面积。
上午:
1.枚举:
★定义:是用变量名称来代替数字常量,大括号内的“名字”叫符号常量,只能是int,枚举中的符号常量是从0开始递增的,这就导致最后一个符号常量的值就是它前面的符号常量个数
★枚举可以相当于int、float,这样的变量类型,但不好
2.结构
★一个结构是复合的数据类型。如下,一个date就包含两个变量
★结构类型和结构变量的区别
★TC264用hex下载文件的教程
下午:
读代码
★leftmap和rightmap是由basemap删线形成的,用于转向用
★图像最上方[YM][XM],YM是60,XM是47
晚上:休息了
上午:
ads软件学习
★我们使用的TC264DA,在新建文件时型号选TC26xDA
★P10 5是接单片机,MCU3V3不是用单片机供电的意思,只是一个正极取的名字,是个代称
下午和晚上记的因为电脑意外关机而丢失了,所以没了
补
★Image2Lcd的安装,用于将图像变成.c文件
★PctoLCD2002:用于将汉字生成十六进制,我的应用场景是龙邱历程中显示屏的汉字显示
昨天忘记保存了,今天要汲取教训
上午:
★DMA相当于CPU的小弟,帮忙进行一些数据传输
★找边缘点分左右、上下、左上到右下、左下到右上。下面的例子是用正负判断
★物体或人的影子在赛道上也会被摄像头认定为边缘,需进一步做处理
★SCCB是改编版IIC,可以理解为IIC的作用
★TC264是从CPU0开始运行
★干簧管(继电器)停车时用
★CPU0中放执行时间较长的程序;CPU1中放控制算法
★CPU0和CPU1是不能同时执行某个函数的,如果要执行某个函数,比方说先让0执行,0执行完后进行标志位判断,0是否执行完了,if判断里面写CPU1需要干嘛
★采集的图像不是全部都要使用,采集完储存在一个数组内后,后面要实现什么功能,我们去调用完整图像的部分做处理
下午:
★allmap中白黑交界没有所谓的边缘线,而在basemap中红色充当了这一角色,作为白黑的分界线。
★图像中的YM和XM还是按照直角坐标系去理解,虽然一个图像对应的二维数组为[YM][XM],但左右移动变化的是X,上下移动变化的是Y
晚上:无
上午:
★C语言中的math.h对应到C++中为cmath,不再有尾缀(拓展名)
★通过图像判断方向的原理是绘制一个一次函数图像,看斜率和截距
★这里面出现的管脚都是可以作为电平输出的
框架
★模块:电机模块、舵机模块、摄像头模块
下午:
★总线:总线(Bus)是计算机各种功能部件之间传送信息的公共通信干线,它是由导线组成的传输线束, 按照计算机所传输的信息种类,计算机的总线可以划分为数据总线、地址总线和控制总线,分别用来传输数据、数据地址和控制信号。——百度
★总线频率:人们常常以MHz表示的速度来描述总线频率。与晶振频率相关
★电机频率一般在10K到20K
★编码器的英文是encoder,缩写为ENC
★PWM的管脚:我们选择不同的PWM脚作为脉冲输入与输出。
★左边为PWM,右边dir
★ads中很多管脚前置名
★DMA,摄像头会用到DMA传输数据,Camera_Flag是是否搬运完原图像的标志位,在DMA.h中被改变
★向量号是用哪个内核来管理,
晚上:
★OLED屏是单色的,数据量比较小
★通过定时器计数数值来反应电机当前速度
★关闭总中断→获取总线频率→所有模块的初始化→开启总中断
★改进:1.targetspeed写在电机驱动的那一块2.舵机PID控制3.左右电机特性的原因可能targetspeed不同
自己弄的代码(第一版)
#include //各个模块的头文件 //所有头文件还是要保留的,毕竟要调用它的历程
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "LQ_ImageProcess.h"
App_Cpu0 g_AppCpu0; // brief CPU 0 global data
IfxCpu_mutexLock mutexCpu0InitIsOk = 1; // CPU0 初始化完成标志位
volatile char mutexCpu0TFTIsOk=0; // CPU1 0占用/1释放 TFT
float servo_duty = 舵机中值 ;
int core0_main (void)
{
/****************************系统自带的*******************************/
//char txt[16];
// 关闭CPU总中断
IfxCpu_disableInterrupts(); //一来先关闭一下,防止上一次开着
// 关闭看门狗,如果不设置看门狗喂狗需要关闭
IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
// 读取总线频率 //相当于keil中的borad_init
g_AppCpu0.info.pllFreq = IfxScuCcu_getPllFrequency();
g_AppCpu0.info.cpuFreq = IfxScuCcu_getCpuFrequency(IfxCpu_getCoreIndex());
g_AppCpu0.info.sysFreq = IfxScuCcu_getSpbFrequency();
g_AppCpu0.info.stmFreq = IfxStm_getFrequency(&MODULE_STM0);
/****************************系统自带的*******************************/
//需要初始化的模块电机、舵机、摄像头、屏幕 //采集和数据处理可以放中断里
ATOM_PWM_InitConfig(ATOMPWM0,0,100); //左电机PWM脚P23.1,电机电机初始化占空比为0,频率为14000
ENC_InitConfig(ENC2_InPut_P33_7,ENC2_Dir_P33_6); //初始化左编码器
ATOM_PWM_InitConfig(ATOMPWM1,0,100); //右电机PWM脚P32.4
ENC_InitConfig(ENC6_InPut_P20_3,ENC6_Dir_P20_0); //初始化右编码器
ATOM_PWM_InitConfig(ATOMSERVO1, 1500, 50); //ATOMSERVO1用的P33.10口作为舵机PWM输出口,servo是伺服的意思,3010的最佳工作频率为50HZ,初始值为1.5ms中值
CAMERA_Init(50); //P2是信号脚,摄像头初始化 //里面数字表示摄像头帧率fps
//OLED_Init(); //以OLED为例
//OLED_CLS(); //LCD清屏
// 开启CPU总中断
IfxCpu_enableInterrupts();
while (1) //主循环
{
/****************************摄像头的使用*************************************/
if (Camera_Flag == 2) //Camera_Flag是是否搬运完原图像的标志位
{
CAMERA_Reprot(); //上报数据给上位机 串口速度比较慢 注意上位机图像宽高设置为120*188
Get_Use_Image(); // 图像压缩,提取部分使用的数据
Camera_Flag = 0; // 清除摄像头采集完成标志位 如果不清除,则不会再次采集数据
Get_Bin_Image(1); // 二值化 //括号内数字表示模式的选择
OLED_Road(LCDH, LCDW, (unsigned char *)Bin_Image); // OLED动态显示摄像头图像
}
Seek_Road();
/****************************摄像头的使用*************************************/
//OFFSET0、1、2是Seek_Road算出来的结果,面积为负数,数值越大说明越偏左边;如果面积为正数,数值越大说明越偏右边
if(OFFSET>0)
{
crossforleft();
}
else if (OFFSET<0)
{
crossforright();
}
else if (OFFSET==0)
{
targetspeed = 700;
realspeed = ENC_GetCounter(ENC2_InPut_P33_7); //获取左电机编码器PWM脚P33.7的脉冲数值,为了让左右电机转速基本相同,传入PID用同一个偏差
这还有一个计数器清空的过程
if(左偏)
{
servo_duty += 10;
}
if(右偏)
{
servo_duty -= 10;
}
error = targetspeed - realspeed ; //偏差= 理想速度 - 当前速度,偏差用于代入PID函数中,用计数器的值直接反应速度
leftspeed_duty = PidLocCtrl(leftspeed_pid,error); //电机位置式控制
rightspeed_duty = PidLocCtrl(rightspeed_pid,error);
ATOM_PWM_SetDuty(IfxGtm_ATOM0_6_TOUT42_P23_1_OUT,leftspeed_duty); //用占空比控制左右电机的PWM
ATOM_PWM_SetDuty(IfxGtm_ATOM0_5_TOUT40_P32_4_OUT,rightspeed_duty); //上面输入的duty是否需要做处理?
}
}
}
昨天大致写了小车的代码,只去写了一个功能,今天进一步去完善它
上午:
★左右两个编码器计数值一正一负,因为是头对头排列的
★初始化时钟频率
★执行函数Seek_Road后得到的应该是error值,再代入舵机的PID控制中,完成转向
★Seek_Road将图像划分为为由近到远三个区域,信任度由近到远递减,将三者加权算误差
★将图像划分区域后,例如左右两个区域,分别记录两边的黑点个数,只不过两边分别记为正和负,用左右两边黑点正负相加后的正负来衡量左偏和右偏
★转弯电机差速转,辅助过弯,使其更加平滑
★两个电机机械特性不同,所以为了达到相同的转速所对应的占空比是不同的,正因为如此需要用两个计数器计数
下午:
★offset的值与绝对的中值0是存在偏差的,用这个偏差
★进环岛可以找到一个跳变点,可能代码实现比较困难
★十字:有线→丢线→有线(边缘)
★所有程序在while(1)中:无法实现程序嵌套、占用资源
★飞线有两种:一种是因为设计缺陷,人为在印刷电路板外面两个节点上直接连着的;还有一种是特殊的信号线
★起跑线:白点黑点交叉循环出现,例如循环出现10次就可以把它视为起跑线了
★出库:固定打角一定时间
★补线是辅助判断,补线的触发条件是识别到了特殊点
★PWM信号的频率是可以设定,我们所常说的10K到20K是电机PWM的频率,而实际工程中一般选用13K到17K,因为10K和20K都会影响到电感的采集,造成干扰。如果频率太低,电机就表现为一卡一卡的,一转一停。如果频率太高,电机转速太快,容易烧坏。
★因为TC264自身结构的特殊性,它的每个PWM通道可以输出不同频率的波,所以每个通道都需要设置频率
★占空比的最大值被设置了,逐飞和龙邱都是10000
★ads中对工程进行rename容易造成工程被替代,所以不要随意进行改名
★ads也是可以实现导入多个工程,之前说不行,今天我发现可以,在导入的时候选择更高一级的目录,它的projects会自动搜索此大目录下所有符合ads工程的文件,然后一件添加就可以了,下面那个是否加入工作区勾选与否都行。
晚上:看视频学习,记录不在这
第二版
#include //各个模块的头文件 //所有头文件还是要保留的,毕竟要调用它的历程
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "LQ_ImageProcess.h"
App_Cpu0 g_AppCpu0; // brief CPU 0 global data
IfxCpu_mutexLock mutexCpu0InitIsOk = 1; // CPU0 初始化完成标志位
volatile char mutexCpu0TFTIsOk=0; // CPU1 0占用/1释放 TFT
/*左电机*/
/*右电机*/
/*舵机*/
float servo_duty = 舵机中值 ;
float Last_servo_error = 0;
int core0_main (void)
{
/****************************系统自带的*******************************/
//char txt[16];
// 关闭CPU总中断
IfxCpu_disableInterrupts(); //一来先关闭一下,防止上一次开着
// 关闭看门狗,如果不设置看门狗喂狗需要关闭
IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
// 读取总线频率 //相当于keil中的borad_init
g_AppCpu0.info.pllFreq = IfxScuCcu_getPllFrequency();
g_AppCpu0.info.cpuFreq = IfxScuCcu_getCpuFrequency(IfxCpu_getCoreIndex());
g_AppCpu0.info.sysFreq = IfxScuCcu_getSpbFrequency();
g_AppCpu0.info.stmFreq = IfxStm_getFrequency(&MODULE_STM0);
/****************************系统自带的*******************************/
//需要初始化的模块电机、舵机、摄像头、屏幕 //采集和数据处理可以放中断里
ATOM_PWM_InitConfig(ATOMPWM0,0,100); //左电机PWM脚P23.1,电机电机初始化占空比为0,频率为14000
ENC_InitConfig(ENC2_InPut_P33_7,ENC2_Dir_P33_6); //初始化左编码器
ATOM_PWM_InitConfig(ATOMPWM1,0,100); //右电机PWM脚P32.4
ENC_InitConfig(ENC6_InPut_P20_3,ENC6_Dir_P20_0); //初始化右编码器
ATOM_PWM_InitConfig(ATOMSERVO1, 1500, 50); //ATOMSERVO1用的P33.10口作为舵机PWM输出口,servo是伺服的意思,3010的最佳工作频率为50HZ,初始值为1.5ms中值
CAMERA_Init(50); //P2是信号脚,摄像头初始化 //里面数字表示摄像头帧率fps
// 开启CPU总中断
IfxCpu_enableInterrupts();
while (1) //主循环
{
/****************************摄像头的使用*************************************/
if (Camera_Flag == 2) //Camera_Flag是是否搬运完原图像的标志位
{
CAMERA_Reprot(); //上报数据给上位机 串口速度比较慢 注意上位机图像宽高设置为120*188
Get_Use_Image(); // 图像压缩,提取部分使用的数据
Camera_Flag = 0; // 清除摄像头采集完成标志位 如果不清除,则不会再次采集数据
Get_Bin_Image(1); // 二值化 //括号内数字表示模式的选择
OLED_Road(LCDH, LCDW, (unsigned char *)Bin_Image); // OLED动态显示摄像头图像
}
Seek_Road(); //获得的三个OFFSET是需要进一步处理转换为舵机error的
error = 此时的OFFSET0 - 上一次的OFFSET0;
/****************************摄像头的使用*************************************/
//OFFSET0、1、2是Seek_Road算出来的结果,面积为负数,数值越大说明越偏左边;如果面积为正数,数值越大说明越偏右边
/*if(OFFSET>0) 左转
{
crossforleft();
}
else if (OFFSET<0) 右转 //对于偏差的判断已经被内涵在图像处理算error那里了,error给舵机
{
crossforright();
}
else if (OFFSET==0) 直走
{
*/
//OFFSET0是距离车子最远的一段,OFFSET2是最近的
targetSpeed1 = targetspeed2 = 700;
realSpeed1 = ENC_GetCounter(ENC2_InPut_P33_7); //获取左电机编码器PWM脚P33.7的脉冲数值,为了让左右电机转速基本相同,传入PID用同一个偏差
realSpeed2 = ENC_GetCounter(ENC6_InPut_P20_3); //1表示左,2表示右
//原本在计数器使用完后还有一个计数器清零的过程,但龙邱库里把它放到ENC_GetCounter里面去了,所以就不用了
/****************************舵机转向*************************************/
//通过舵机的转向就可以实现转向了,这里面是用到了摄像头的,因为OFFSET是通过摄像头算出的值
/*方案一:首先试试OFFSET不用0和1,只用2做判断OFFSET作为当前的值*/
servo_error = OFFSET2 - 0; //在赛道正中间左右黑点正负应该抵消掉(第一次)因为中点为0,所以OFFSET其实就代表当前的误差*/
servo_duty = constrain_float(servo_duty,-700,700); //舵机限幅
servo_duty = PidIncCtrl(servo_pid,servo_error); //舵机控制,Inc表示增量式
/*方案二:用上0、1、2三个OFFSET,三者加权算一个值*/
/****************************舵机转向*************************************/
motor_error1 = targetSpeed1 - realSpeed1 ; //偏差= 理想速度 - 当前速度,偏差用于代入PID函数中,用计数器的值直接反应速度
motor_error2 = targetSpeed2 - realSpeed2 ;
leftSpeed_duty = PidLocCtrl(leftSpeed_pid,motor_error1); //电机控制,Loc表示位置式
rightSpeed_duty = PidLocCtrl(rightSpeed_pid,motor_error2);
/***********************************
ATOM_PWM_SetDuty(IfxGtm_ATOM0_6_TOUT42_P23_1_OUT,leftspeed_duty); //用占空比控制左右电机的PWM
ATOM_PWM_SetDuty(IfxGtm_ATOM0_5_TOUT40_P32_4_OUT,rightspeed_duty); //上面输入的duty是否需要做处理? //需要,只不过是通过MotorCtrl函数
***********************************/
MotorCtrl(leftSpeed_duty,-rightSpeed_duty); //因为电机的放置原因,这里是有正负之分的,这里面是没有限幅的,需要自己补上
TOM_PWM_SetDuty(ATOMSERVO1,error,50);//管脚+占空比+频率 舵机控制 //3010的最佳工作频率为50HZ
}
}
}
上午:
●ads可以直接导出工程文件的,指工程包含的文件夹
*** TFT屏幕***
●TFT彩屏采用的SPI串行接口通信
●龙邱和逐飞的TFT屏管脚名字不同不用太在意,每个管脚的作用是一样的,逐飞多一个BL脚,背光控制输入脚,背光控制是屏幕背光的PWM控制,不用太在意
●我们用的TFT的脚和龙邱的历程是不同的,使用前需要到龙邱的TFT.c里面改;因为我们也是有8个脚的,有BL脚,龙邱只有7个脚,
●在龙邱历程中,cs脚是默认拉低的,cs可以理解为SPI通信的许可位,拉低表示许可,好像这脚也叫使能脚
●在初始化TFT屏幕后紧接着是清屏的操作,清屏指的是全屏显示单色画面
下午:
●镜像:可以被理解为一个虚拟机的快照,里面包含了需要部署的应用程序和它所关联的库
●增量式PID对微分项限幅
晚上:
●在剪排针的时候建议预留两个管脚,因为剪的时候容易破坏管脚
上午:
★因为每个模块被写为了一个.cpp文件,所以在跨文件使用已被定义的变量时,要用extern进行一次声明
下午:
★GPIO外部中断与STM外部中断区别:stm中断就是一个周期中断,可以设置出现中断的时间,而GPIO就是一个外部中断而已
★学长代码里面PID有一个数组,用于记录四次编码器的值,这个数组是用来滤波的,因为编码器也是一个器件,也存在噪声;在motor.c的这里,对三次进行取平均,如果有一次算出来的值太大,有异常就以上一次为准。
★二次函数变速是看的曲率,曲率大速度慢,曲率小速度快,曲率是LSMI.DK,在speed.c里面做判断
★并不是所有引脚都有既输入又输出,对于ADC输入引脚,功能比较固定,有仅输入的限制
★RAM是随机存取存储器,速度快
晚上:
晚上:
最小二乘法:当取值为一串数据的算术平均值(全部相加除以数量),此时取得偏差平方的最小值(因为是一个二次函数,所以存在极值)
我休息去了,什么都没干
玄学内容:
容忍值可以理解为阈值
畸变系数
栅头栅尾、栅区
种子生长法的栈
下午:
看代码
●图像畸变,可以理解为图像变形
●yaw叫偏航
●图像压缩:去除不必要信息
●图像更新:指再一次拿新点给图像赋值
●leftmap和rightmap的初值都是0,全白
●if (II.bnum_all),只要不冲出赛道,一般都是会执行的
(试试截长图的形式,因为打字我这边是需要一张一张图片导入的,有点麻烦)
就在这里收尾吧,首先是因为我发现csdn博客太长,字太多会卡,至少我卡了,而且暑假留校的学习基本上进入尾声了,后面还会有几天的日子更多看计算机二级的知识了,再学英语,接近二十天的暑假留校学习,还是有一些收获的,但我感觉还不太够,还是有很多需要提升的地方,主要是一部分时间在摸鱼休息,感觉看一整天还是挺累的,看到后面头昏目眩了,这种情况在最初的时候更多一些,现在摸鱼多了,这种情况也就少了,就到这吧,开学再战,到时候分版块记录吧。
That’s all.