本章节主要讲解如何获取灰度传感器值以及如何使用灰度传感器循迹
灰度传感器简介
灰度传感器如图 1 所示:
灰度传感器 使用一对抗干扰较强的光电传感器,其中发射管的光源采用高亮白色聚光 LED,发射管端发出的光线通过不同环境背景的反射之后,最终由光敏接收管来接收,光敏接收管的阻抗随反射光线的强弱变化而变化(反射光线越强,阻值越小),最后通过分压和运放比较电路实现数字/模拟信号的双输出。
灰度传感器模块对白光反射强弱不同背景环境有非常好的识别效果,背景差异越大,分辨效果越好。灰度传感器相比普通红外传感器有着更高的抗干扰能力。
灰度传感器检测原理
灰度传感器是一组模拟传感器,由一只发光二极管和一只光敏接收管组成,二者安装在同一面上。 灰度传感器利用不同颜色的检测背景对光的反射程度不同,同时光敏接收管接收到不同检测面返回的光线,其阻值也不同的原理进行颜色深浅检测。
当光敏接收管接收到的光线越强, 它的阻值就越小, 即地面背景灰度越深或者离地距离越远, 光敏二极管的阻值越大。
在有效的检测距离内,发光二极管发出白光,照射在检测面上,检测面反射部分光线, 光敏接收管检测此光线的强度并通过分压电路和运放比较电路将其转换模拟/数字信号,最后通过机器人主板上的模拟/数字口输入到微控制器进行处理。
电路分析
在上图所示灰度传感器检测电路中,LED1~3为发射补光管, LEDP1为光敏接收管,U1为比较运放芯片LM393A。用户可根据是否使用比较运放芯片决定使用模拟量或数字量。
使用模拟量时,ADC端的电压通过光电二极管分压得到,由光电二极管的特性曲线可得,当光电二极管接收光线弱时,光电二极管阻值趋向于无穷,此时ADC端电压接近于0。反之,当光电二极管接收光线强时,光电二极管阻值趋向于0,此时ADC端电压接近5V,由于不用颜色对于光的吸收程度不同,ADC端反映的值也不同,由此可根据光电二极管的值判断小车处于线的位置。
使用数字量时,当地面背景为深色或者高灰度值时, 经地面反射后进入光敏接收管端的光线较少, 2端输出的电压较高,经比较器比较后1端输出低电平控制三极管导通,GPIO输出高电平。同理当地面背景为浅色或者低灰度值时, 经地面反射后进入光敏接收管端的光线较多, 2端输出的电压较低,经比较器比较后1端输出低电平控制三极管截止,GPIO输出低电平。
数字量可满足大部分MCU,用户通过调节电位器RPOT1即可设定循迹阈值,而模拟量需要MCU具备ADC转化功能,将转化的数字量比较赛道路线的阈值即可获得和数字量一样的效果。相比之下,使用模拟量相对简单,但是需要消耗的MCU资源较多,而数字量不方便调节,但目前大多数MCU的IO口均有检测电平输入功能,用户无需二次配置。
循迹原理
巡线原理
1.先在平整的路面上调小车走直线。通过调整小车左右电机的速度,尽可能的让小车走直线,这样可以减少在巡线过程中调整的次数,可以让小车跑的更快。
2.巡线过程中,小车偏离线,如图1左,小车向左偏,应该增加左侧电机的速度,减小右侧的速度,减小或增加的量,根据小车实际情况修改测试。如图1右,小车向右偏,则相反。
3.靠近中心的探头照到线,调整的量要小些,越是离中心探头远的管子照到线,调整的量要越大。
4.调整的时候,切记不要将其中一个轮子停下来或者倒转。要用差速来调整方向这样车行走比较稳,而且速度要快。
路口判断
路口判断,如图2所示,以7路巡线传感器为例,1号探头用来判断左侧T型路口。7号探头用来判断右侧T型路口。1和7同时照到线,用来判断十字路口。
转弯判断
1.巡线走到需要转弯的路口,如图3。
2.车继续向前走一小段,让小车的旋转中心点靠近线的交叉点。小车有编码器可以用编码器精确控制,或没有编码器可以用延时,让车继续向前走一段时间,这些都需要实际写代码测试。
3.小车原地转弯,直到中间的探头(4号),照到线。这是转到第一个路口,若这条线是设定的路线,则巡线向前走,若不是这条线,继续旋转,等待中间的探头照到线,则转到了下一个路口。
循迹小车功能实现
灰度部分
uint8_t stop_way = 0;//停止线检测 uint8_t sensor_val[5];//灰度返回值 uint16_t gray_state = 0x0;//当前灰度状态 uint16_t gray_status[2]={0},gray_status_backup[2][20]={0};//灰度传感器状态与历史值 uint32_t gray_status_worse=0; //灰度管异常状态计数器 /**************************** 函数名称: 函数作用:5路循迹获取状态 函数参数:无 函数返回值:当前巡线状态 16进制 ****************************/ uint16_t Sensor_GetState(void) { uint16_t State = 0X0000; // sensor_val[0] = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0); // sensor_val[1] = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1); // sensor_val[2] = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_2); // sensor_val[3] = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_3); // sensor_val[4] = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_4); // // State |= (sensor_val[4] << 4); // State |= (sensor_val[3] << 3); // State |= (sensor_val[2] << 2); // State |= (sensor_val[1] << 1); // State |= (sensor_val[0] << 0); for(int8_t i=4;i>=0;i--) { sensor_val[i] = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0<<i); State |= (sensor_val[i]<<i); } return State; } void gray_check(void) { gray_state = Sensor_GetState(); //记录上一次传感器量 for(uint16_t i=19;i>0;i--) { gray_status_backup[0][i]=gray_status_backup[0][i-1]; } gray_status_backup[0][0]=gray_status[0]; //灰度检测 switch(gray_state) { case 0x01:gray_status[0] = 4; gray_status_worse/=2;break; //00001b case 0x03:gray_status[0] = 3; gray_status_worse/=2;break; //00011b case 0x02:gray_status[0] = 2; gray_status_worse/=2;break; //00010b case 0x06:gray_status[0] = 1; gray_status_worse/=2;break; //00110b case 0x04:gray_status[0] = 0; gray_status_worse/=2;break; //00100b case 0x0C:gray_status[0] = -1;gray_status_worse/=2;break; //01100b case 0x08:gray_status[0] = -2;gray_status_worse/=2;break; //01000b case 0x18:gray_status[0] = -3;gray_status_worse/=2;break; //11000b case 0x10:gray_status[0] = -4;gray_status_worse/=2;break; //10000b case 0x00:gray_status[0] = gray_status_backup[0][0];gray_status_worse++;break; //00000b default://其它特殊情况单独判断 { gray_status[0]=gray_status_backup[0][0]; gray_status_worse++; } } switch(gray_state)//停止线检测 { case 0x0F://01111b case 0x1E://11110b case 0x1F://11111b { stop_way++; } break; } }
主函数部分
/** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_TIM3_Init(); MX_TIM2_Init(); MX_TIM4_Init(); /* USER CODE BEGIN 2 */ HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2); HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_ALL); HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_ALL); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { motor_ctrl(500+gray_status[0]*100,-(500-gray_status[0]*100)); Get_Encoder(); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }
可以观察到小车延黑线行驶
循迹效果
需要代码的朋友可以点击以下链接下载,有问题请私信我。