写在前面
列出一些我之前写的底盘调试的博客,在看这篇文章之前最好看一下,便于理解
在之前的文章里,我已经讲过了光电传感器回传的数据格式以及基本的购物机器人的姿态调整方案,那么在这篇文章里我将分享购物机器人是如何识别导航线以及完成直走类动作
车子的俯瞰图
赛场循迹线
模式A和B
因为购物机器人的运动需求,我们将其运动状态分为了模式A和模式B,模式A就是购物机器人行进时其中线是和导航线重合的,而模式B前进时,购物机器人的停车条件就是前面的光电传感器感知到了白线
示意图如下:
那么为什么要有这2种模式的区别呢?这是因为我们摄像头是放在前面车头的,因此在遍历仓库和货架的时候,前端停车更便于摄像头拍照,因此就设计出了模式B。
思路讲解
流程图
循迹概述
首先我们需要获取到S1和S2总共8颗循迹灯的状态,并以该循迹灯作为我们购物机器人的运动依据,在模式A下面,我们只用到了uart6Rx[0]和uart7Rx[1]这2个数组元素的数据,为什么?这就跟我们模式A的运行模式有关了,因为模式A的运行模式时购物机器人中线与导航线重合,因此只需要用到前后的光电传感器的中间部分就可以了。
有了循迹灯的状态之后就需要做逻辑判断了,在循迹时,购物机器人会接收到树莓派通过串口发送过来的指令,指令里会包含模式,运动方式(前进,后退,左转,右转),以及前进格数,因此在做运动时需要对运动方式进行判断,我将运动方式进行了分类,前进后退一类,左转右转为一类,不同的类别有不同的识别方式以及速度控制,在模式A的情况下走完指定格数就相当于时完成了任务,就会停车等待树莓派命令,没有树莓派的命令底盘是不会动的,保持停止状态。
程序分析
首先是寻迹了,因为模式A的时候车子的中心线和导航线是重合的,因此循迹的时候uart6Rx[0]和uart7Rx[1]的相应感应灯对准循迹线就可以了。这2个数组的8个元素分别对应的就是前后各4个S1,S2循迹灯的状态,具体内容在这篇博客里:
购物机器人的路径感知以及姿态调整方案
mid_sen1[motor_f_r]=((~uart7Rx[1])&0x40)>>6;
mid_sen1[motor_f_l]=((~uart7Rx[1])&0x10)>>4;
mid_sen1[motor_b_l]=((~uart6Rx[0])&0x08)>>3;
mid_sen1[motor_b_r]=((~uart6Rx[0])&0x02)>>1;
mid_sen2[motor_f_r]=(uart7Rx[1]&0x80)>>7;
mid_sen2[motor_f_l]=(uart7Rx[1]&0x08)>>3;
mid_sen2[motor_b_l]=(uart6Rx[0]&0x10)>>4;
mid_sen2[motor_b_r]=(uart6Rx[0]&0x01);
获取了S1,S2数组状态之后就需要进行运动控制了,在运动控制中,我将前进,后退分为了一组,左转右转分为了一组
if((MOV_STA==RUN)||(MOV_STA==BACK)||(MOV_STA==GET_WALL)){
switch(cut_spd){
case 0:
if ((mid_cnt-cross_sta)==(STEP-1)){
if(speed<=low_speed){
speed += add_val;
}else{
cut_spd=1;
}
}else if(speed<high_speed) //加速过程
speed += add_val;
break;
case 1:
if((((uart7Rx[1]&0xff)==0xff)&&(MOV_STA==RUN))||(((uart6Rx[0]&0xff)==0xff)&&(MOV_STA==BACK))){
cut_spd = 2;
}else if(speed<high_speed) //加速过程
speed += add_val;
break;
case 2:
if((speed>=low_speed)){
speed-=cut_val;
}
break;
}
}else{
switch(cut_spd){
case 0:
if ((mid_cnt-cross_sta)==(STEP-1)){
if(turn_speed<=low_speed){
turn_speed+= add_val;
}else{
cut_spd=1;
}
}else if(turn_speed<mid_speed){ //加速过程
turn_speed+= add_val;
}
break;
case 1:
if(((uart7Rx[0]&0x01)==0x01&&(MOV_STA==LEFT))||((uart7Rx[1]&0x80)==0x80&&(MOV_STA==RIGHT))){
cut_spd = 2;
}else if(turn_speed<mid_speed) //加速过程
turn_speed += add_val;
break;
case 2:
if((speed>=turn_lowspeed)){
turn_speed-=cut_val;
}
break;
}
}
假设树莓派发送的指令是需要购物机器人走N个格子。
购物机器人设定为走到1个白线交叉点(十字叉)就认为走了1格,即中间的2个光电传感器感知到白线了就认为走到了一格。
MOV_STA是芯片接收到的树莓派发送的指令状态,当其为RUN或者BACK的时候我们会进入第一个判断语句,我将其称为直走类别。在直走类别中,我将购物车分为了3个阶段的运动状态。
阶段1(cut_spd=0)是运动状态的判断,如果购物机器人下一格不是第N个格子的话就会处于一直加速状态,直到速度达到最高速度为止。如果购物机器人下一个要走的格子(十字叉)是接收到要走的第N格子(十字叉)时,如果此时购物机器人连最低速度都没有达到的话,我优先让其加速到最低速度(针对解决起点启动的问题),如果速度已经高于最低速度,购物机器人会进入阶段2(cut_spd=1),阶段2代表购物机器人从第N-1个格子走到第N个格子的开始阶段。
阶段2(cut_spd=1)时,当购物机器人前面的光电传感器碰到了白线之后,说明购物机器人中间的光电传感器快要到下一个十字叉了,购物机器人需要减速了,此时进入阶段3(cut_spd=1)。
阶段3(cut_spd=1)就是减速到最低速度,直到走到第N个格子为止。
(づ ̄3 ̄)づ╭❤~一键三连,这次一定(๑•̀ㅂ•́)و✧