-
智能车环岛浅析(电磁+摄像头)
2019-06-19 22:09:16看到网上对于环岛的介绍微乎其微,想着写点什么,对于一些没有祖传代码和资料的同学起到一点指导和抛砖引玉的作用把,看了一些国一国二的代码,发现跟自己想的方法基本一致,所以个人认为应该能对没有思路的同学有...写在前面:
看到网上对于环岛的介绍微乎其微,想着写点什么,对于一些没有祖传代码和资料的同学起到一点指导和抛砖引玉的作用把,看了一些国一国二的代码,发现跟自己想的方法基本一致,所以个人认为应该能对没有思路的同学有一点启发,当然,比赛最主要的就是锻炼个人能力,条条大路通环岛,希望同学们不要被我的这种方法所局限,自己的思想无论在何时都是要有的,当然,由于本人能力不足等原因,如果有错误欢迎批评指出。
摄像头入环
1识别环岛
想着入环岛,那么最基本的肯定要先做到识别,对于环岛的识别,我个人的思想是分为五部分即可,以右环岛为例
1 在第一部分时,你会发现右边赛道宽度突然变宽,而左边赛道正常(可以区分环岛和十字(十字为两边发生突变))
这时候便可以加一个标志位1,
2.在第二部分,我们可以看到左边赛道无突变,右边赛道丢线(检测不到黑点),各位应该都有丢线标志位
这时便有环岛标志位2
3在第三部分(标志位1和标志位2成立),我们可以看到右边赛道先是逐渐变窄,之后便是逐渐变宽,这时候可以得到标志位3
并且记录下右赛道刚开始变宽时的行位置
4.之后你会发现右边赛道再次丢线,最后一个标志位
5。当然少不了最后的V(赛道宽度发生突变)
识别其实不难,大家可以根据自己的图像来具体修改,具体识别会有不同,但有思路即可,你会发现3,4,5在一幅图像中,也可以根据这些来进行判断,(当然,今年各位应该都是电磁+摄像头,这样的话环岛识别便更为简单,电磁信号变为双倍,并且摄像头有少许标志位,便可以很简单的判断出环岛,)之后便是最重要的补线了
补线
补线便是根据1和2点根据斜率连接,最小二乘法拟合得到相应的中线
1点 :右边界为直线,上一次左边界-这次左边界>10(这一行赛道宽度-上一行赛道宽度>10) 并记录下该行左边界位置,即为1点
2点: 前面有提到过,右边界为直线,这一行左边界-上一行左边界>2 记录下此时左右边界位置 右边界为2点
3点: 2点的左边界即为3点
4.如果为左环岛,则右边界为直道。
赛道边界法:
如果不用拟合直线,可以考虑以1点作为赛道右边界,然后右边界往前依次递增(右环岛为递减) 直到2点处,也可得到不错的入环效果
具体方法是假设1点为x行y列 2点为x2行y2列 用y-y1得到列数差,x-x1得到行数差 最后列数差/行数差=每行递减值Y
然后从1点开始,往前一直到2点行每行右边界依次右移 Y 即可得到得到图像
举个例子 1点为55行 左边界为20列 (55,20) 2点为30行 右边界为70列(30,70) 那么每行递减值 = (70-20)/(55-30) = 2 这样每行位移2即可 当然还可以有一些其他处理让它更接近圆环
至于最小二乘法拟合直线相信各位都有了解,只要能成功识别1,2两点,拟合补线便是处理问题了
当然,今年由于限高,可能你的小车看不到2和3点,如果为一下特征,仍然是1点补线,但是从1点到另一边界有赛道的最后一行即可
2停止补线
当车辆进入环内后,可以停止补线了,这时候按照正常寻线来跑即可
需要注意的是,这里的停止补线标志位要写好,因为小车每次入环的速度和位置是不同的,如果停止补线误判的话会有很大问题
3出环岛补线
出环岛补线
当图中的右赛道边界先减小后增大时的,改行的右边界位置即为补线位置
上一次右边界-这次右边界>10(这一行赛道宽度-上一行赛道宽度>10) 记录右边界位置
或者出环岛用电磁出环也可
毕竟环岛入环是要把他作为一个圆环弯道来处理,不管用什么方法、只要你最后得到的补线能够更好的接近圆环弯道,转向就会越精确,只要1,2两点能够很好识别,怎么让他更好的接近圆环处理,更好的方法需要你的聪慧去发现,同时,入环写好了,出环其实思路一样,
电磁入环
电磁入环是五电感入环
(电感可以改为8字电感)
具体方法为:
中间电感一个阀值来识别环岛,识别完成竖直差比和进环,进入后切换水平差比和寻迹,出环时标志位检测用水平电感,延时一定时间或编码器积分清标志即可。
我们可以这样想,如果是单纯水平电感遇到弯道,会流畅的转向,而在遇到环岛时,我们把竖直电感作为转向环,是不是相当于正常入弯呢
简单来说,两个不同差和比即可
Turn_Offset = (float) (LAD-RAD)/(float)(LAD+RAD+MAD)*100;//经典差和比
Turn_Offset2 = (float) (L1AD-R1AD)/(float)(L1AD+R1AD+MAD)*100;//竖直电感差和比
当然左竖直电感与与右竖直电感进行差比和 ,还有这一些处理,比如如何适应大小环,入环如何完美和出环稳定性等
这些问题还是要处理的(可修改PID参数来调节), 当然希望大家能独立思考下,
总结:
基于今年应该都是电磁+摄像头,可以说在赛道元素处理上即难了,又简单了难是对于新手小白(博主)来说,要同时学习处理电磁和摄像头,并且多了一些元素,再加上会车,对小白不是很友好
简单是电磁+摄像头之后,一些赛道元素可以更好的处理 ,比如环岛,如果单摄像头或者单电磁入环不稳定,可以考虑两个加权,达到较稳定状态,就可以跑得不错。
总的来说可以是,电感阈值 || 摄像头环岛检测 来判断环岛 (有上帝之光摄像头环岛识别不良) 之后电磁入环还是摄像头入环就要个人考虑了
感觉有用的话,点个赞再走呗!
-
恩智浦智能车竞赛鹰眼国赛程序环岛(稳定).rar
2021-02-01 15:07:21适合参加智能车竞赛的参赛人员用于学习 -
2020第十五届全国大学生智能汽车竞赛——5电感稳定姿态进环岛
2020-12-20 12:33:195电感稳定姿态进环岛写在前面 写在前面 我写了一篇总的博客,分享了我参加了十五届智能车竞赛的经历哦~ 2020第十五届全国大学生智能汽车竞赛——基础四轮组入门看这一篇就够了!5电感稳定姿态进环岛
写在前面
我写了一篇总的博客,分享了我参加了十五届智能车竞赛的经历哦~
2020第十五届全国大学生智能汽车竞赛——基础四轮组入门看这一篇就够了!
接下来所有的分享都是依据我这个开源工程里的代码
!!! !!!
!!! !!!
!!! !!!
!!! !!! !!! !!!
!!! !!! !!!
!!! !!!
https://github.com/LittleGenius12138/nxp_smart_car/tree/master
我采用的电感摆放方式是这样的,5个电感均采用横电感的摆放方式
完整链接在我的 古月居博客,传送门在下面: -
【智能车Code review】——环岛的判定与补线操作
2020-08-09 11:45:57以右环岛为例: k_left:左线的斜率 rou_of_left:左线的方差 last_rou_of_left:上一帧的左线方差 l_start:左线第一行为黑的所在行 right_turn_down; right_turn_middle; right_turn_up; 左线的下、中、上拐点 ...系列文章
【智能车Code review】—曲率计算、最小二乘法拟合
【智能车Code review】——坡道图像与控制处理
【智能车Code review】——拐点的寻找
【智能车Code review】——小S与中S道路判断
【智能车Code review】——环岛的判定与补线操作
智能车复工日记【1】——菜单索引回顾
智能车复工日记【2】——普通PID、变结构PID、微分先行PID、模糊PID、专家PID
智能车复工日记【3】:图像处理——基本扫线和基本特征提取和十字补线
智能车复工日记【4】:关于图像的上下位机的调整问题总结
智能车复工日记【5】:起跑线的识别与车库入库
智能车复工日记【6】:有bug的模糊PID记录
智能车复工日记【7】:关于会车的图像问题
智能车复工日记【N】:图像处理——环岛debug记录(持续更新)【1】效果展示图
状态1、状态2
状态3
状态4、状态5
状态6
状态7
状态8
【2】状态机设定需要的参数
以右环岛为例:
k_left:左线的斜率
rou_of_left:左线的方差
last_rou_of_left:上一帧的左线方差
l_start:左线第一行为黑的所在行
right_turn_down;
right_turn_middle;
right_turn_up;
左线的下、中、上拐点
fiv_width[i]:第i行的赛道宽度
leftline_duan_dian:左线跳变严重的所在行
if (j >= 2 && (lefetline[j] - lefetline[j - 1]) <= -20) leftline_duan_dian = j;
flag_shizi:是否为十字的标志
huandao_size:当前环岛的大小,一般来说是人工设定的。
huandao_memory:环岛的状态
huandao_flag_R_L:左右环岛区分标志函数
void R_mend_rightline_right_island(byte type, byte flag_R_L) { if (flag_R_L == 2) { if (type == 1 || type == 2)//从下拐点开始往上拉,拉到上拐点下五行 { byte j = 0; if (right_turn_down[0] >= 5) { advanced_regression(2, right_turn_down[0] - 2, right_turn_down[0], right_turn_middle[0] - 1, right_turn_middle[0]); //regression(2, right_turn_down[0], right_turn_middle[0]); for (j = (byte)right_turn_down[0]; j <= (byte)right_turn_middle[0]; j++) { int jicun = (int)(parameterB * j + parameterA); if (jicun >= 185) jicun = 185; else if (jicun <= 0) jicun = 0; rightline[j] = (byte)jicun; //centerline[j] = (byte)((rightline[j] + lefetline[j]) / 2); } before_zuohuandao_k = parameterB; before_zuohuandao_b = parameterA; } else { int delta = right_turn_middle[0] - 0; if (delta == 0) delta = 1; float k = (right_turn_middle[1] - rightline[0]) * 1.0f / delta; float b = rightline[0]; for (j = (byte)0; j <= (byte)right_turn_middle[0]; j++) { int jicun = ((int)(k * j + b)); if (jicun >= 185) jicun = 185; else if (jicun <= 0) jicun = 0; rightline[j] = (byte)jicun; } } } else if (type == 3) { byte j = 0; int delta = right_turn_middle[0] - 0; if (delta == 0) delta = 1; float k = (right_turn_middle[1] - rightline[0]) * 1.0f / delta; float b = rightline[0]; for (j = (byte)0; j <= (byte)right_turn_middle[0]; j++) { int jicun = ((int)(k * j + b)); if (jicun >= 185) jicun = 185; else if (jicun <= 0) jicun = 0; rightline[j] = (byte)jicun; } //byte j = 0; advanced_regression(2, right_turn_down[0] - 2, right_turn_down[0], right_turn_middle[0] - 1, right_turn_middle[0]); regression(2, right_turn_middle[0]-7, right_turn_middle[0]-1); //for (j = 0; j <= (byte)right_turn_middle[0]; j++) //{ // int jicun = (int)(before_zuohuandao_k * j + before_zuohuandao_b); // if (jicun >= 185) jicun = 185; // else if (jicun <= 0) jicun = 0; // rightline[j] = (byte)jicun; // //centerline[j] = (byte)((rightline[j] + lefetline[j]) / 2); //} } else if (type == 8) { byte j = 0; //advanced_regression(2, right_turn_down[0] - 2, right_turn_down[0], right_turn_middle[0] - 1, right_turn_middle[0]); if (right_turn_up[0] <= 5 && right_turn_up[0] != 0) { regression(2, r_sec_start, r_sec_start + 3); for (j = 0; j <= (byte)r_sec_start; j++) { int jicun = (int)(parameterB * j + parameterA); if (jicun >= 185) jicun = 185; else if (jicun <= 0) jicun = 0; rightline[j] = (byte)jicun; //centerline[j] = (byte)((rightline[j] + lefetline[j]) / 2); } } else if (right_turn_up[0] >= 5 && right_turn_up[1] <= 4 && break_hangshu >= right_turn_up[0]) { regression(2, right_turn_up[0], break_hangshu); for (j = 0; j <= (byte)right_turn_up[0]; j++) { int jicun = (int)(parameterB * j + parameterA); if (jicun >= 185) jicun = 185; else if (jicun <= 0) jicun = 0; rightline[j] = (byte)jicun; //centerline[j] = (byte)((rightline[j] + lefetline[j]) / 2); } } else { int delta = right_turn_up[0] - 0; if (delta == 0) delta = 1; float k = (right_turn_up[1] - rightline[0]) * 1.0f / delta; float b = rightline[0]; for (j = (byte)0; j <= (byte)right_turn_up[0]; j++) { int jicun = ((int)(k * j + b)); if (jicun >= 185) jicun = 185; else if (jicun <= 0) jicun = 0; rightline[j] = (byte)jicun; } //regression(2, right_turn_up[0], right_turn_up[0] + 2); //for (j = 0; j <= (byte)right_turn_up[0]; j++) //{ // int jicun = (int)(parameterB * j + parameterA); // if (jicun >= 185) jicun = 185; // else if (jicun <= 0) jicun = 0; // rightline[j] = (byte)jicun; // //centerline[j] = (byte)((rightline[j] + lefetline[j]) / 2); //} } } } } void R_mend_leftline_right_island(byte type, byte flag_R_L) { if (flag_R_L == 2) { // SetText("TYPE:" + type); if (type == 4) { byte j = 0; if (right_turn_up[0] >= 4) { int delta = right_turn_up[0] - 3; if (delta == 0) delta = 1; float k = (right_turn_up[1] - lefetline[3]) * 1.0f / (delta * 1.0f); // setText用户自定义("斜率" + k); float b = lefetline[3] - k * 3; if (right_turn_up[0] <= 24) { right_turn_up[0] = 24; } for (j = (byte)3; j <= (byte)right_turn_up[0]; j++) { int jicun = ((int)(k * j + b)); if (jicun >= 185) jicun = 185; else if (jicun <= 0) jicun = 0; lefetline[j] = (byte)jicun; //centerline[j] = (byte)((rightline[j] + lefetline[j]) / 2); } //advanced_LeastSquareCalc_Curve(1, 4, 10, (byte)(right_turn_up[0] - 3), (byte)(right_turn_up[0] - 1)); //for (j = (byte)3; j <= break_hangshu - 1; j++) //{ // int jicun = ((int)(curve_a * j * j + curve_b)); // if (jicun >= 185) jicun = 185; // else if (jicun <= 0) jicun = 0; // lefetline[j] = (byte)jicun; // //centerline[j] = (byte)((rightline[j] + lefetline[j]) / 2); //} } else { } } else if (type == 5) //重新扫线,从左边往右边扫 { byte j = 0; if (right_turn_up[0] >= 4 && (last_memory == 4 || leftline_duan_dian >= 40)) { setText用户自定义("拟合直线"); int delta = right_turn_up[0] - 3; if (delta == 0) delta = 1; float k = (right_turn_up[1] - lefetline[3]) * 1.0f / (delta * 1.0f); float b = lefetline[3] - k * 3; if (right_turn_up[0] <= 24) { right_turn_up[0] = 24; for (int ss = 0; ss <= 24; ss++) { rightline[ss] = 0; } } for (j = (byte)3; j <= (byte)right_turn_up[0]; j++) { int jicun = ((int)(k * j + b)); if (jicun >= 185) jicun = 185; else if (jicun <= 0) jicun = 0; lefetline[j] = (byte)jicun; //centerline[j] = (byte)((rightline[j] + lefetline[j]) / 2); } //advanced_LeastSquareCalc_Curve(1, 4, 10, (byte)(right_turn_up[0] - 3), (byte)(right_turn_up[0] - 1)); //setText用户自定义("拟合曲线"); //for (j = (byte)3; j <= right_turn_up[0]; j++) //{ // int jicun = ((int)(curve_a * j * j + curve_b)); // if (jicun >= 185) jicun = 185; // else if (jicun <= 0) jicun = 0; // lefetline[j] = (byte)jicun; // //centerline[j] = (byte)((rightline[j] + lefetline[j]) / 2); //} } else if (leftline_duan_dian < 40 || right_turn_up[0]<4) { //advanced_regression(2, right_turn_up[0] - 2, right_turn_down[0], right_turn_middle[0] - 1, right_turn_middle[0]); if (leftline_duan_dian + 5 <= break_hangshu) { regression(1, leftline_duan_dian, break_hangshu); parameterA = lefetline[0]; if (parameterB <= -5) parameterB = -5; setText用户自定义("斜率拟合" + parameterB); } else { int delta = break_hangshu - 0; if (delta == 0) delta = 1; parameterB = (rightline[break_hangshu] - lefetline[0])*1.0f / delta; parameterA = lefetline[0]; setText用户自定义("斜率计算" + parameterB); } if (leftline_duan_dian <= 24) { leftline_duan_dian = 24; for (int ss = 0; ss <= 24; ss++) { rightline[ss] = 0; } } for (j = 0; j <= (byte)break_hangshu; j++) { int jicun = (int)(parameterB * j + parameterA); if (jicun >= 185) jicun = 185; else if (jicun <= 0) jicun = 0; lefetline[j] = (byte)jicun; //centerline[j] = (byte)((rightline[j] + lefetline[j]) / 2); } } } else if (type == 6) { byte j = 0; byte youguai_y = 0; byte youguai_x = 0; byte leftguai_y = 0; byte leftguai_x = 0; /***找左下拐点***********/ for (j = 2; j <= 60; j++) { if (lefetline[j - 1] - lefetline[j - 2] <= 0 && lefetline[j] - lefetline[j - 1] >= 0 && (lefetline[j + 1] - lefetline[j] > 0) && leftfindflag[j - 2] == 1 && leftfindflag[j - 1] == 1 && leftfindflag[j] == 1) { leftguai_y = (byte)(j - 1); leftguai_x = lefetline[j - 1]; break; } } for (j = 8; j <= 60; j++) { //右连接处 if (rightline[j] != 0) { youguai_y = j; youguai_x = rightline[j]; break; } } if (leftguai_y != 0 && leftguai_x != 0 && youguai_y != 4 && youguai_x != 0) { SetText("找到右上拐点"); SetText("右上拐点坐标:" + youguai_y + " " + youguai_x); SetText("找到左下拐点"); SetText("左下拐点坐标:" + leftguai_y + " " + leftguai_x); if (youguai_y >= leftguai_y + 4) { SetText("要减速了"); jiansu_flag = 1; } else jiansu_flag = 0; //开始拉线 int delta = youguai_y - leftguai_y; if (delta == 0) delta = 1; float k = (youguai_x - leftguai_x) * 1.0f / delta; float b = leftguai_x - k * leftguai_y; if (youguai_y >= leftguai_y) { for (j = (byte)leftguai_y; j <= (byte)youguai_y; j++) { int jicun = ((int)(k * j + b)); if (jicun >= 185) jicun = 185; else if (jicun <= 0) jicun = 0; lefetline[j] = (byte)jicun; } } } } else if (type == 7 && (long_turn_flag_left <= 55 || rou_of_left >= 5000) && ((flag_blank_out_huandao == 1 && l_start >= 16) || flag_blank_out_huandao == 0)) { jiansu_flag = 0; byte j = 0; byte youguai_y = r_sec_start; byte youguai_x = 0; byte leftguai_y = 0; byte leftguai_x = lefetline[0]; setText用户自定义("左线最后一行所在列数" + lefetline[break_hangshu]); if (left_turn_down[0] != 0 && left_turn_down[0] <= 40 && left_turn_down[1]>=140) { leftguai_y = (byte)left_turn_down[0]; leftguai_x = (byte)left_turn_down[1]; } if (r_sec_start >= 10) { youguai_y = r_sec_start; } else { youguai_y = break_hangshu; } if (l_start >= 5) flag_blank_out_huandao = 1; setText用户自定义("l_start" + l_start); SetText("找到右上拐点"); SetText("右上拐点坐标:" + youguai_y + " " + youguai_x); SetText("找到左下拐点"); SetText("左下拐点坐标:" + leftguai_y + " " + leftguai_x); //开始拉线 //if (youguai_x <= 1 && youguai_y <= 25) //{ youguai_y = break_hangshu; if (lefetline[break_hangshu] <= 55) { youguai_x = lefetline[break_hangshu]; } // } int delta = youguai_y - leftguai_y; if (delta == 0) delta = 1; float k = (youguai_x - leftguai_x) * 1.0f / delta; float b = leftguai_x - k * leftguai_y; for (j = (byte)leftguai_y; j <= (byte)youguai_y; j++) { int jicun = ((int)(k * j + b)); if (jicun >= 185) jicun = 185; else if (jicun <= 0) jicun = 0; lefetline[j] = (byte)jicun; //纠正右线 if (rightline[j] > lefetline[j]) rightline[j] = lefetline[j]; } if (youguai_y <= 27) { for (j = youguai_y; j <= break_hangshu; j++) { rightline[j] = 0; lefetline[j] = 0; } } } else if (type == 8) { flag_blank_out_huandao = 0; } } }
void juge_left_succesive_and_if_k_limit() { //可能是环岛的地带 -0.17 if (podao_flag == 0 && huandao_flag_R_L != 1 && huandao_memory <= 5 && k_left < -0.03 && k_left > -1.5 && flag_find_huan_rightmiddle_point == 1 && rou_of_left <= 380 && last_rou_of_left <= 380 && l_start <= 20) { /*******行驶到环岛出口或者在行驶到环岛出口前********/ if (huandao_memory <= 3 && flag_rukou2 == 0) { // 30 if (right_jiao == 1 && ((right_turn_middle[0] >= 28 && r_start >= 14 && rightline[5] <= 10 && fiv_width[10] >= 130 && fiv_width[15] <= 183 && fiv_width[20] <= 181 && fiv_width[22] <= 180 && rou_of_right >= 1800 && last_rou_of_right >= 1800 && !(right_turn_up[0] <= 30 && right_turn_up[0] >= 3 && left_turn_up[0] <= 30 && left_turn_up[0] >= 3) && fiv_width[40] <= 100) || (rightline[5] <= 10 && r_start >= 14 && break_hangshu - long_turn_flag_left <= 5 && break_hangshu - long_turn_flag_right > 10 && fiv_width[10] >= 161 && fiv_width[15] >= 157 && fiv_width[20] >= 153 && fiv_width[25] >= 127 && fiv_width[40] <= 100 && flag_shizi == 0) || (rightline[5] <= 10 && r_start >= 14 && break_hangshu - long_turn_flag_left <= 5 && break_hangshu - long_turn_flag_right > 10 && fiv_width[10] >= 141 && fiv_width[10] <= 158 && fiv_width[15] >= 137 && fiv_width[15] <= 154 && fiv_width[20] >= 132 && fiv_width[20] <= 149 && fiv_width[25] >= 127 && fiv_width[25] <= 145 && fiv_width[40] <= 100 && flag_shizi == 0) || (rightline[5] <= 10 && r_start >= 14 && break_hangshu - long_turn_flag_left <= 3 && break_hangshu - long_turn_flag_right > 7 && fiv_width[10] >= 133 && fiv_width[10] <= 158 && fiv_width[15] >= 128 && fiv_width[15] <= 154 && fiv_width[20] >= 120 && fiv_width[20] <= 149 && fiv_width[25] >= 113 && fiv_width[25] <= 145 && fiv_width[40] <= 100 && flag_shizi == 0) || (huandao_size == 100 && r_start >= 30 && break_hangshu - long_turn_flag_left <= 2 && break_hangshu - long_turn_flag_right > 8 && fiv_width[10] >= 110 && centerline[0] <= 80 && fiv_width[10] <= 130 && fiv_width[15] >= 105 && fiv_width[15] <= 110 && fiv_width[20] >= 99 && fiv_width[20] <= 115 && fiv_width[25] >= 90 && fiv_width[25] <= 100 && fiv_width[40] <= 100 && flag_shizi == 0) ) ) { //setText用户自定义("1"); huandao_flag = 1; huandao_flag_R_L = 2; // SetText("行驶到环岛出口(没进环岛呢)"); huandao_memory = 3; huandao_procedure_variable = 1; } else if (huandao_procedure_variable == 0 && right_turn_down[0] <= 25 && right_turn_down[0] > 0 && ((rou_of_right >= 7000 && last_rou_of_right >= 8000) || (long_turn_flag_left >= 50 && long_turn_flag_right < 20 && last_rou_of_right >= 1000))) { huandao_flag = 1; huandao_flag_R_L = 2; huandao_memory = 2; // SetText("行驶到环岛出口前(没进环岛呢)(近)"); 30 条件放松一点 if (/*right_turn_down[0] <= 10 &&*/ (rightline[5] <= 10 && right_turn_middle[0] >= 28 && r_start >= 14 && fiv_width[15] <= 183 && fiv_width[20] <= 183 && fiv_width[22] <= 183 && rou_of_right >= 1800 && last_rou_of_right >= 1800 && !(right_turn_up[0] <= 30 && right_turn_up[0] >= 3 && left_turn_up[0] <= 30 && left_turn_up[0] >= 3) && fiv_width[40] <= 100) || (rightline[5] <= 10 && r_start >= 14 && break_hangshu - long_turn_flag_left <= 5 && break_hangshu - long_turn_flag_right > 10 && fiv_width[10] >= 163 && fiv_width[15] >= 160 && fiv_width[20] >= 157 && fiv_width[25] >= 127 && fiv_width[40] <= 100 && flag_shizi == 0)) { // SetText("行驶到环岛出口(没进环岛呢)"); huandao_memory = 3; //setText用户自定义("2"); huandao_procedure_variable = 1; } } else if (huandao_memory == 2 || huandao_memory == 1) { if (/*right_turn_down[0] <= 10 &&*/ (rightline[5] <= 10 && right_turn_middle[0] >= 28 && r_start >= 14 && fiv_width[15] <= 183 && fiv_width[20] <= 183 && fiv_width[22] <= 183 && rou_of_right >= 1800 && last_rou_of_right >= 1800 && !(right_turn_up[0] <= 30 && right_turn_up[0] >= 3 && left_turn_up[0] <= 30 && left_turn_up[0] >= 3)) || (rightline[5] <= 10 && r_start >= 14 && break_hangshu - long_turn_flag_left <= 5 && break_hangshu - long_turn_flag_right > 10 && fiv_width[10] >= 163 && fiv_width[15] >= 160 && fiv_width[20] >= 157 && fiv_width[25] >= 127 && flag_shizi == 0)) { // SetText("行驶到环岛出口(没进环岛呢)"); huandao_memory = 3; huandao_procedure_variable = 1; } } else if (huandao_procedure_variable == 0 && right_turn_down[0] > 25 && right_turn_down[0] <= 40 && rou_of_right >= 7000 && last_rou_of_right >= 8000 && long_turn_flag_left >= 50 && break_hangshu <= 66 && long_turn_flag <= 50 && fiv_width[10] > 110 && fiv_width[15] > 105) { huandao_flag = 1; huandao_flag_R_L = 2; huandao_memory = 1; // SetText("行驶到环岛出口前(没进环岛呢)(远)"); } else if (huandao_memory <= 4 && right_turn_middle[0] >= 20 /*&& right_turn_middle[0] <= 55*/ && huandao_procedure_variable == 1 && r_start <= 5) { huandao_flag = 1; huandao_flag_R_L = 2; flag_rukou = 1; huandao_memory = 4; // SetText("行驶到环岛入口前(没进环岛呢)"); } } else if (huandao_memory <= 4 && right_turn_middle[0] >= 20 && /*right_turn_middle[0] <= 55 &&*/ huandao_procedure_variable == 1 && r_start <= 5) { huandao_flag = 1; flag_rukou = 1; huandao_memory = 4; // SetText("行驶到环岛入口前(没进环岛呢)"); } else if (huandao_flag_R_L != 1 && huandao_memory <= 5 && huandao_memory >= 4 && fiv_width[10] >= 140 && fiv_width[15] >= 130 && ((right_turn_up[0] <= 33 && right_turn_up[0] > 0) || (leftline_duan_dian <= 30 && leftline_duan_dian != 0)) && huandao_procedure_variable == 1) { huandao_flag = 1; flag_rukou2 = 1; huandao_memory = 5; // SetText("行驶到环岛入口(没进环岛呢)"); } } else if (huandao_flag_R_L != 1 && huandao_memory <= 4 && right_turn_middle[0] >= 20 && right_turn_middle[0] <= 55 && huandao_procedure_variable == 1 && r_start <= 5) { huandao_flag = 1; flag_rukou = 1; huandao_memory = 4; } else if (huandao_flag_R_L != 1 && huandao_memory <= 5 && huandao_memory >= 4 && fiv_width[10] >= 140 && fiv_width[15] >= 130 && ((right_turn_up[0] <= 33 && right_turn_up[0] > 0) || (leftline_duan_dian <= 30 && leftline_duan_dian != 0)) && huandao_procedure_variable == 1) { huandao_flag = 1; flag_rukou2 = 1; huandao_memory = 5; //SetText("rightfindflag[1]" + rightfindflag[1]); //SetText("rightfindflag[2]" + rightfindflag[2]); if (huandao_flag_R_L != 1 && huandao_memory == 5 && (( fiv_width[10]<=133 &&fiv_width[15]<=123 && r_start>=20) ||(r_start >= 20 && leftfindflag[5] != 0 && leftfindflag[6] != 0 && leftfindflag[7] != 0 && leftfindflag[8] != 0 && lefetline[leftline_duan_dian] <= 65 && leftline_duan_dian <= 38) || (leftfindflag[5] != 0 && leftfindflag[6] != 0 && leftfindflag[7] != 0 && leftfindflag[8] != 0 && leftline_duan_dian <= 25))) { huandao_flag = 1; huandao_memory = 6; //flag_rukou = 3; // SetText("已经进去了"); } //SetText("行驶到环岛入口(没进环岛呢)"); } else if (huandao_flag_R_L != 1 && huandao_memory == 5 && ((fiv_width[10] <= 133 && fiv_width[15] <= 123 && r_start >= 20)||(r_start >= 20 && leftfindflag[5] != 0 && leftfindflag[6] != 0 && leftfindflag[7] != 0 && leftfindflag[8] != 0 && lostleft_times <= 10 && leftline_duan_dian <= 42) || (r_start >= 20 && leftfindflag[5] != 0 && leftfindflag[6] != 0 && leftfindflag[7] != 0 && leftfindflag[8] != 0 && leftline_duan_dian <= 38) || (leftfindflag[5] != 0 && leftfindflag[6] != 0 && leftfindflag[7] != 0 && leftfindflag[8] != 0 && leftline_duan_dian <= 25))) { huandao_flag = 1; huandao_memory = 6; //flag_rukou = 3; // SetText("已经进去了"); } else if (huandao_flag_R_L != 1 && huandao_memory == 6 && left_turn_down[0] >= 1 && left_turn_down[0] <= 27 && left_turn_down[1] > 25 && flag_memory_6 >= 4) { huandao_flag = 1; huandao_memory = 7; //SetText("出环了"); } else if (huandao_flag_R_L != 1 && huandao_memory == 7 && (My_Abs(right_turn_up[0] - (l_start - 4)) >= 5) && (fiv_width[10] < 182 && fiv_width[15] < 182) &&(((left_turn_down[0] == 0 || left_turn_down[0]>=43) && right_turn_up[0] >= 15 && right_turn_up[0] <= 51 && right_turn_up[1] <= 100 && r_start >= 26 && rou_of_left <= 5000 /*&& rightline[break_hangshu] < 85*/) || ((left_turn_down[0] == 0 || left_turn_down[0] >= 43) && right_turn_up[0] >= 15 && right_turn_up[0] <= 51 && right_turn_up[1] >= 20 && right_turn_up[1] <= 100 && rou_of_left <= 5000 /*&& rightline[break_hangshu] < 85*/) || ((left_turn_down[0] == 0 || left_turn_down[0] >= 43) && long_turn_flag_left >= 40 && k_left >= -1.5 && k_left < 0 && lefetline[0] < 155 && l_first_notget >= 40/*&& rou_of_left <= 5000 && rightline[break_hangshu] < 85*/) || ((left_turn_down[0] == 0 || left_turn_down[0] >= 43) && right_turn_up[0] >= 35 && right_turn_up[0] <= 51 && right_turn_up[1] >= 20 && right_turn_up[1] <= 100 && rou_of_left <= 5000) || ((left_turn_down[0] == 0 || left_turn_down[0] >= 43) && huandao_size ==50 && right_turn_up[0] >= 15 && right_turn_up[0] <= 51 && right_turn_up[1] >= 10 && right_turn_up[1] <= 50 && rou_of_left <= 5000))) { huandao_flag = 1; huandao_memory = 8; SetText("第二次到入口了"); } else if (huandao_flag_R_L != 1 && ((fps_out_huan_island >= 10 && huandao_size >= 80) || (huandao_size <= 70)) && huandao_memory >= 8 && (fps_out_huan_island >= fps_set_out_HUAN_Island || ( ((right_turn_up[0] < 25 && right_turn_up[0] != 0) || ((right_turn_up[0] >= 50 || right_turn_up[0] == 0) && fiv_width[10] >= 120 && fiv_width[10] <= 135 && fiv_width[15] >= 110 && fiv_width[15] <= 128)) || (fiv_width[30] >= 60 && fiv_width[30] <= 103 && fiv_width[25] >= 68 && fiv_width[25] <= 115 && (My_Abs(long_turn_flag_left - long_turn_flag_right) <= 5 || (lostleft_times == 0 && lostright_times == 0)))) && ((rightfindflag[15] == 1 && rightfindflag[16] == 1 && rightfindflag[17] == 1 && rightfindflag[18] == 1) || (r_sec_start == 0 && l_sec_start == 0)))) { huandao_memory = 9; huan_order++; cross_road_times++; //SetText("完全脱离环岛,可以清除标志了"); clear_huandao_data(); } R_mend_leftline_right_island(huandao_memory, huandao_flag_R_L); R_mend_rightline_right_island(huandao_memory, huandao_flag_R_L); last_memory = huandao_memory; if (huandao_memory == 8 && huandao_flag_R_L != 1) { fps_out_huan_island++; setText用户自定义("fps_out_huan_island" + fps_out_huan_island); } if (huandao_memory >= 1 && huandao_flag_R_L != 1) { setText用户自定义("huandaosize" + huandao_size); } byte j = 0; if (huandao_memory <= 5 && huandao_memory != 0) { for (j = 0; j < 70; j++) { //LCenter[j] = forecast_centerline[j]; centerline[j] = (byte)((lefetline[j] + rightline[j]) / 2); LCenter[j] = centerline[j]; L_black[j] = lefetline[j]; R_black[j] = rightline[j]; } } else { for (j = 0; j < break_hangshu; j++) { //LCenter[j] = forecast_centerline[j]; centerline[j] = (byte)((lefetline[j] + rightline[j]) / 2); LCenter[j] = centerline[j]; L_black[j] = lefetline[j]; R_black[j] = rightline[j]; } } show_condition_of_huan(); }
-
智能车复工日记【N】:图像处理——环岛debug记录(持续更新)
2020-04-10 23:56:51左环岛出现问题: 这时候应该用左上点来进行修补。检查为何没有补线。 关键是四状态和五状态的切换 修改参数为30; 效果有所改善,延时了状态5的到来。 问题2: 接下来的问题: 状态7的问题: 状态7问题修复, ...代码以及思路整理:
系列文章
【智能车Code review】—曲率计算、最小二乘法拟合
【智能车Code review】——坡道图像与控制处理
【智能车Code review】——拐点的寻找
【智能车Code review】——小S与中S道路判断
【智能车Code review】——环岛的判定与补线操作
智能车复工日记【1】——菜单索引回顾
智能车复工日记【2】——普通PID、变结构PID、微分先行PID、模糊PID、专家PID
智能车复工日记【3】:图像处理——基本扫线和基本特征提取和十字补线
智能车复工日记【4】:关于图像的上下位机的调整问题总结
智能车复工日记【5】:起跑线的识别与车库入库
智能车复工日记【6】:有bug的模糊PID记录
智能车复工日记【7】:关于会车的图像问题
智能车复工日记【N】:图像处理——环岛debug记录(持续更新)4.10号更新
问题1
左环岛出现问题:
这时候应该用左上点来进行修补。检查为何没有补线。
关键是四状态和五状态的切换
修改参数为30;
效果有所改善,延时了状态5的到来。
问题2
接下来的问题:
状态7的问题:
状态7问题修复,
问题3
但是状态8进早了,原因:
左上拐点找到了,却是因为图像左上角糊了。
修改之后,bug消失。
同时对右环做对称处理:
问题4
同时发现下坡flag在判断后要清除掉。
问题5
//对2020.1.19 16.20.20进行处理,发现问题: 十字误判成右环岛:
原因:由于右线在55行以上存在环岛所以计算曲率时,曲率变大;
补救措施:限制计算曲率的点,最远处不可以超过57;
并且将拟合和计算方差的最后的点置换为curvity_point2。这样减少离群点的影响。
原本以为是上面的问题,结果发现,没用,是左下角的问题:
左下角有图像,导致l_start不等于0,然后计算曲率以及方差也就不同了,如何解决这个问题?显然这种十字部分容易误判环岛,可以考虑其他变量特征的限制!!!
先休息会儿。
加入新变量:
byte R_first_notget = 0;
byte L_first_notget = 0;
问题6
拟合且计算方差的依据(以左线为例):起始点既和L_start(也就是为L_first_get)有关也和L_first_notget有关,还和L_sec_get有关
什么时候以L_start(第一次黑)为开始?
解决方案:
问题7
又出现了问题:
这次就是单纯地曲率计算有问题了,右线曲率太大了!!
修改曲率限制:第三点改为50以下,并将第二点的运算放到第三点确定之后。
问题解决。
问题8
发现右环岛7状态有问题,没有补线,观察问题:
由于是用r_start点拉线,此时显然不可以,考虑用r_sec_start点;
问题解决。
问题9
另外的一个小问题:
8状态出早了
将r_start!=0减去,并且将9状态条件限制一下
对左环岛进行对偶操作。
然后对扫线的时候的拟合线进行进一步限制
然后将固定扫线改为继承性扫线
问题10
发现假如将速度调高,有时候5状态和6状态的切换不流畅,必须一帧一帧地慢放才不会误操作,所以将限制条件打注释
问题11
又发现问题,卡循环了,只知道是在环岛部分卡的。检查!
卡在这儿,因为右上点为0
修改成这样就行了
对左环岛进行对偶操作。
今天就进行到这儿,下位机先不忙做调整。5.4号更新
先交代一下之前没有上传的debug记录:
当时设定的阈值为7,现在更改为13。效果好点了。左线也做同样调整。
问题1
这一帧图像竟然判断成环岛1状态了,查找问题:
由于是继承性扫线,显然扫到了很高的行数,然后右线的曲率就大了,方差也大了。
现在增加限制条件,连续两帧的方差都大才能进入环岛状态1或2。
也就是增加新变量last_row:
左环岛对称处理,bug解决。
接下来跑st的图像:
问题2
100的左环岛,目前应该是7状态,但是却被误判为8状态。问题:
这里被判断为左上拐点,此时应该加以限制。左上拐点的列坐标不能大于175.
右环岛对偶操作:
同时要杜绝左上拐点在下面的情况:补线的时候限制左上拐点:
问题3
同时8状态补线找的点也需要改进:
右环岛同样操作:
问题4
还要解决,出环岛接十字的情况,这时候要将环岛状态清除:
改限制中拐点,不改限制上拐点。
我们重新找一下出环岛的特征。else if (huandao_flag_R_L != 2 && huandao_memory >= 8 && (left_turn_up[0] <= 25 || ( fiv_width[35]>=80 && fiv_width[35] <=90 && fiv_width[30] >= 90 && fiv_width[30] <= 100 && fiv_width[25] >= 100 && fiv_width[25] <= 110)) && (leftfindflag[2] == 1 && leftfindflag[4] == 1 && leftfindflag[16] == 1 && leftfindflag[15] == 1 && leftfindflag[16] == 1 && leftfindflag[17] == 1 && leftfindflag[18] == 1)) { huandao_memory = 9; //SetText("完全脱离环岛,可以清除标志了"); clear_huandao_data(); }
这样问题解决。
对右环岛进行对偶操作。
问题5
发现3状态跳不到4状态,
将这一条件去除。右环岛对偶操作。
问题解决。
问题6
5状态没有进6状态。
发现问题:
限制条件改为25
左环岛对称处理。
Bug解决
问题7
刚到7状态就变为8状态,找BUG:
限制右上拐点的列坐标,同时修改行数>=25
左环对偶操作。
问题8
误判左环岛,可以通过右线的曲率进行限制。但是发现由于我们之前限制了曲率的最后一个点的取值在50行之前,所以此时曲率并不是很大。所以准备引入新变量。
由于我发现,正入十字的最后几帧特别容易判断成环岛的3状态。
加入限制,如果左右两个上拐点同时存在并且都小于30的话,不是环岛3状态。
问题解决,对右环做对称操作。
隐患评估:(可能在异弯接环的入环存在问题)
对判断环岛大条件中加入last直线的方差。
这一帧的左线曲率不知为何这么大:
这里对计算方差的函数进行更改。在曲率的限制条件的地方或上一个条件:
对右曲率计算进行对偶操作;
这会是右线方差大了,找原因;
问题9
原本限制的是小于36,我们修改限制为40.
结果发现还是不行,然后观察得到:
是曲率的原因现将左曲率min修改为-0.3
发现还是不对.
明明从上面计算,为何方差会这么大?
原来拟合出来的线并不符合整体趋势,这该怎么办?
我们限制一下,如果参与计算方差的点总共不超过12个我们就对其限制幅度,让他小于7000;5.5号更新
这边由于断线的缘故导致计算方差错误,这该怎么办呢???
D:\上位机图像文件夹\上位机图像\上位机图像\2020.1.16 11.15.33注意!!!!
解决思路:
1、 扫线
2、 环岛状态上做文章
这是第630帧,其实在第628帧就应该开始了,
不符合的地方有:
左斜率
修改之后,成功识别为状态2;
但是没有进状态3的问题仍然存在:
找到原因了,因为之前为了防止出十字判断成环岛,我对赛道宽度进行了限制,从而导致此时没有识别出来。
修改之后发现并不是这个问题:
此时其实可以这样写,如果已经判断成12状态了,三状态的宽度限制可以稍作放松。
发现问题还是上次的那个,方差计算有问题。
结果发现是break取的点有问题,假如在60行以内没有找到就直接继承的原来的break点了,现在,将所有扫线的程序都进行观察并修改这个问题。
即包装好的扫线程序以及部分十字区域代码进行修改。
问题解决。 -
14届恩智浦智能车普通四轮组国赛程序.zip
2020-03-25 23:56:00这是我14届恩智浦智能车比赛的国赛程序,十字,环岛,都能够跑下来,参加普通四轮组的可以参考参考,芯片是K60. -
基于椭圆拟合的环岛识别方法
2020-10-27 21:25:05比赛要求智能车能检测到环岛并从入口驶入,在绕行约 270°后驶出环岛,其中,能否高响应、高鲁棒性地检测环岛是后续进出环岛等步骤的基础。本文根据计算机视觉中的多视图几何学证明了环岛椭圆投影的存在,使用优化的... -
恩智浦智能车竞赛圆环入口识别1.1- 摄像头代码.rar
2021-02-01 15:10:45用于处理环岛 -
红外寻迹小车基于K128单片机的红外对管飞思卡尔智能车(5个对管)程序部分
2021-01-06 20:11:19基于K128单片机的红外对管飞思卡尔智能车(5个对管)软件部分包括: 出库 直行模块 大,小弯道 环岛 s弯 停车 #include "headfile.h" #include "math.h" int median; /////舵机中值 float error=0; //////偏差 ... -
【智能车Code review】——拐点的寻找
2020-08-09 11:44:30ROUNDISLAND:环岛拐点 rightfindflag[i]:表示第i行的右线是否被找到,1为找到,0为没有找到 flag_find_huan_rightdown_point :找到环岛右下拐点标志 flag_find_huan_rightmiddle_point:找到环岛右中拐点标志 找拐点... -
第十三届恩智浦智能车平衡组
2018-08-02 11:00:41比赛刚结束,谈谈做车的体会,很幸运获得华南赛区一等奖,今年直立决赛是对抗赛,观赏性有点低,环岛是今年才有,再加上颠婆,很多人都跪在了这里,对我们第一次参赛的很有优势,过不了颠婆车要适当增重才行,还有... -
智能车竞赛摄像头算法里丢边,补线,质量矩的个人理解
2020-07-08 19:25:48丢边:智能车在一些特殊情况(如大弯,十字,环岛)里,并不能完整识别到边界,这种情况叫做丢边 补线:在丢边的情况下,需要对丢失的边界进行补线 质量矩:摄像头采集数据后,对不同行采集的值有不同权重,这样权重... -
新学期伊始,同学们就开始为十六届智能车竞赛出谋划策了
2020-09-07 11:23:25近期,很多同学也开始为新的一届全国大学生智能车竞赛出谋划策 挖坑设井 了。下面让我们看看他们的奇思妙想 歪点子 吧。 ○ 关于新型赛道元素 卓大大,今年的比赛结束啦。又到了为下一届比赛提建议(祸害下一届)的... -
2020第十五届全国大学生智能汽车竞赛——4X4矩阵键盘+Flash调参系统
2021-01-08 17:30:365电感感知赛道普通元素写在前面func.c文件键盘扫描函数 接下来所有的分享都是依据我这个开源工程...我写了一篇总的博客,分享了我参加了十五届智能车竞赛的经历哦还请多多捧场啦,环岛和车库的处理在这里面有写的哦 202 -
智能车复工日记【4】:关于图像的上下位机的调整问题总结
2020-05-07 22:59:11问题1:环岛判断函数,last方差,find_guaidian()函数放置位置不同 在上位机中,每帧图像的处理放在ImageProcess()函数中, void ImageProcess() { //int straight_search_line = 13; //int curve_search_line =... -
智能车复工日记【3】:图像处理——基本扫线和基本特征提取和十字补线
2020-04-06 14:51:39目录前言基本扫线(除了进入环岛状态或者坡道或者十字路口的普通扫线)基本数据和初步特征进一步特征提取1、计算并且显示前n行左右线各丢失数目(不break和break的都有)2、计算左右线方差(以右线为例)【a】计算右... -
北京亦庄智能道路
2018-12-08 11:50:19北京亦庄智能道路 ** 测试车辆从博大大厦停车场出发由中和街右转进入荣华中路,沿荣华中路向南,经荣华南路,到达荣华南路与荣昌东街的环岛,在环岛左转到荣昌东街,到在荣昌东街与宏达南路十字路口右转,在景园街... -
环型赛道
2020-03-26 19:00:45今年智能车竞赛赛道元素中引入了环形赛道,心中一直有一个担忧,生怕参赛队伍问,你们这帮脑残的猪尾汇,谁见过只有一入一出的马路环岛呢?而且还这么圆。 今天看到手机百度新闻上的这组照片,心里稍微平静了一些。 ... -
脑残的猪尾汇
2020-01-31 00:30:53今年智能车竞赛赛道元素中引入了环形赛道,心中一直有一个担忧,生怕参赛队伍问,你们这帮脑残的猪尾汇,谁见过只有一入一出的马路环岛呢?而且还这么圆。 今天看到手机百度新闻上的这组照片,心里稍微平静了一些。 ...
-
MySQL 数据库的基本操作(数据完整性约束)
-
MySQL 多实例安装 及配置主从复制实验环境
-
Python函数库深度详解(1)
-
Unity RUST 逆向安全开发
-
docker-duplicity:安装了重复的简单高山docker镜像-源码
-
Galera 高可用 MySQL 集群(PXC v5.7+Hapro)
-
Web项目导入经验
-
好久没写文了
-
剑指Offer-61和为s的连续正数序列
-
PPT大神之路高清教程
-
连续积分圆-源码
-
oracle中增加索引SQL,解决全表扫描
-
Docker gitlab
-
网络抓取挑战:第12周作业-源码
-
基于半导体光放大器的超宽带三重态信号的产生
-
MySQL 存储过程(创建海量数据实验环境)
-
keycloak (docker版)
-
MySQL 备份与恢复详解(高低版本 迁移;不同字符集 相互转换;表
-
paddedsize.m
-
腾讯、阿里、京东、华为等一线大厂,年薪 80w 架构师的 Redis 什么水平?