8998| 3
|
[讨论] 巡线问题小议 |
本帖最后由 微笑的rockets 于 2018-5-31 11:18 编辑 今天在群里有老师询问怎样写巡线路口的问题,试着简单的回答了一下。 然后突然想到,可能真的有很多人其实对这个还是有疑问,于是斗胆将自己不成熟的想法发布上来,抛砖引玉,希望大家能批评指正。 问题是由这张图引起的。 如果让机器人知道在第二个路口转弯。 我觉得想要解决这样的问题,首先要分析地图。 于是我把这个地图进行了简化,也就是二值化。把黑色的定义为1,把白色的定义为0,于是有了下图。 那我们就可以进行分析了 想象一下,你现在有一个读数据的设备,读取的数据按队列进入, 读入到010表示在直线上 读入111表示到了横线上 读入010表示又到了直线上 且前面读到111表示过路口,计数加1 直到读到又一个010且前面读到111表示又过了一个路口,计数加1,发现计数现在为2,转弯 于是这个问题应该这样就解决了。 那么扩展开来说,是不是当我们读到了 类似于 010 111 010 这样的一个数组就表示是一个路口呢? 于是,只要和这个数组进行比对,凡是和这个相同的就是路口 如果,我们给定更多的特征数组,进行比对,是不是就可以有更多的方法了。 比如如果读到 000 000 000 那接下来做什么动作? 比如读到 000 100 100 做什么动作? ---------------------------------------------------------------------------------------------------------------------------- 在巡线的过程中还有一个问题,也会经常碰到,那就是到底多少个传感器才够? 我觉得回答这个问题,其实还蛮困难的。 我来试着回答一下吧。 其实根据上面的那个图,我们可以认为最简单的巡线,一个巡线传感器就可以了。只要确保传感器时刻读取到的线是1即可。 非1的时候,我们通过各种方法找到1即可。但在实际操作的过程中个,会发现非常的困难,你非1的时候,到底是左转还是右转?都是非常纠结的问题。 那我们引入另外一个传感器,就变成了两个。这里就出现了4种情况。 11 线上 00 线外 10 偏右 01 偏左 那对应的情况正如上表所列,只要对应给出相应的处理方法就可以了。所以理论上两个也能解决问题,是吗? 但是地图上突然出现了十字交叉路口,路口和路上的情况是一致的,不是吗? 显然两个传感器无法很好的解决这个问题。为什么是无法很好的解决呢? 因为其实如果想象一下,你扫动读取,就可以获得一个区间的数据,但是就需要很多数据的处理,会形成更复杂的问题。 于是我们可以再增加一个传感器。 于是我们获得了一个这样的数据情况表。 000 线外 001 更偏左 010 中线 011 偏左 100 更偏右 101 夹角 110 偏右 111 路口 因此有了这张真值表,我们也清楚的了解到我们车的状况。 所以我们是不是可以大致认为巡线3个就够了呢?我的理解,大致上差不多了。 但是,这里出现了但是,为了能更好的巡线,我们总是倾向用更多的传感器,这是为什么呢? 这里就要说到分辨率的问题,我们将地图抽象成了一张由0和1组成的表格,我们按尺寸来划分,就会发现,当我把一个个的像素编程数字,那点和点之间的距离就非常的关键。 这和我们机器人所安装传感器的位置和距离息息相关。如果我的线只有1cm,我传感器的安装距离就要尽可能的在这个范围内。超过了这个范围,可能得到的数据表就完全和他的行为不一致了。 越多的传感器电位,可以帮助机器更好的进行控制,比如在驱动电机的时候可以引入PID的控制,让运动更准更稳。 前几天和同事在聊天,不知道为什么讨论到了巡线的一些问题,同事指出巡线没有那么的理想化,我的想法是,我们先在理想条件下理清思路,然后再一点点加上限制条件,或者增加辅助功能就可以更好的解决问题。 类似于机器人的外形,传感器的位置,转弯半径等都需要在后面的程序中考虑到。 另外在程序中,我们经常会用到if……else……等方法或者switch等语句来实现以上这种操作。最近看到翁凯老师的一些观点,觉得用在这里特别的合适。 翁凯老师认为,在高级语言端应该将数据或者状态和逻辑进行一个分离。用表的方式来重构之前if……else……,switch……case……等代码。 而我觉得在巡线小车的场景里,这样的操作给整个程序编写带来的好处应该说是非常有价值的。 如果我们将这个逻辑代码和数据分离后,我们的整个的操作,其实就是为不同的状态找到处理的数据。 这么说突然觉得是查找表格的节奏。感觉好像简单了很多的样子。 在人工智能的领域,通过人工智能来进行状态的判断,建立不同的数据处理模式,自动的建立数据和状态的联系,感觉好像找到了新的解法。 以上做了一些关于逻辑层面,数据层面的分析。后期会考虑将实际的搭建和电机控制等思考逐步补充进来。 随手写了一些不成熟的想法,希望能给大家带来一些不同的思路。 如果有任何问题,也欢迎大家批评。 感谢@Angelo 提供了他写的巡线代码。我们后面将以他的代码为基础进一步的改进。 [mw_shl_code=cpp,true]float Kp=0,Ki=0,Kd=0; float error=0, P=0, I=0, D=0, PID_value=0; float previous_error=0, previous_I=0; int sensor[5]={0, 0, 0, 0, 0}; int initial_motor_speed=100; void read_sensor_values(void); void calculate_pid(void); void motor_control(void); void setup() { pinMode(9,OUTPUT); //PWM Pin 1 pinMode(10,OUTPUT); //PWM Pin 2 pinMode(4,OUTPUT); //Left Motor Pin 1 pinMode(5,OUTPUT); //Left Motor Pin 2 pinMode(6,OUTPUT); //Right Motor Pin 1 pinMode(7,OUTPUT); //Right Motor Pin 2 Serial.begin(9600); //Enable Serial Communications } void loop() { read_sensor_values(); calculate_pid(); motor_control(); } void read_sensor_values() { sensor[0]=digitalRead(A0); sensor[1]=digitalRead(A1); sensor[2]=digitalRead(A2); sensor[3]=digitalRead(A3); sensor[4]=digitalRead(A4); if((sensor[0]==0)&&(sensor[1]==0)&&(sensor[2]==0)&&(sensor[4]==0)&&(sensor[4]==1)) error=4; else if((sensor[0]==0)&&(sensor[1]==0)&&(sensor[2]==0)&&(sensor[4]==1)&&(sensor[4]==1)) error=3; else if((sensor[0]==0)&&(sensor[1]==0)&&(sensor[2]==0)&&(sensor[4]==1)&&(sensor[4]==0)) error=2; else if((sensor[0]==0)&&(sensor[1]==0)&&(sensor[2]==1)&&(sensor[4]==1)&&(sensor[4]==0)) error=1; else if((sensor[0]==0)&&(sensor[1]==0)&&(sensor[2]==1)&&(sensor[4]==0)&&(sensor[4]==0)) error=0; else if((sensor[0]==0)&&(sensor[1]==1)&&(sensor[2]==1)&&(sensor[4]==0)&&(sensor[4]==0)) error=-1; else if((sensor[0]==0)&&(sensor[1]==1)&&(sensor[2]==0)&&(sensor[4]==0)&&(sensor[4]==0)) error=-2; else if((sensor[0]==1)&&(sensor[1]==1)&&(sensor[2]==0)&&(sensor[4]==0)&&(sensor[4]==0)) error=-3; else if((sensor[0]==1)&&(sensor[1]==0)&&(sensor[2]==0)&&(sensor[4]==0)&&(sensor[4]==0)) error=-4; else if((sensor[0]==0)&&(sensor[1]==0)&&(sensor[2]==0)&&(sensor[4]==0)&&(sensor[4]==0)) if(error==-4) error=-5; else error=5; } void calculate_pid() { P = error; I = I + previous_I; D = error-previous_error; PID_value = (Kp*P) + (Ki*I) + (Kd*D); previous_I=I; previous_error=error; } void motor_control() { // Calculating the effective motor speed: int left_motor_speed = initial_motor_speed-PID_value; int right_motor_speed = initial_motor_speed+PID_value; // The motor speed should not exceed the max PWM value constrain(left_motor_speed,0,255); constrain(right_motor_speed,0,255); analogWrite(9,initial_motor_speed-PID_value); //Left Motor Speed analogWrite(10,initial_motor_speed+PID_value); //Right Motor Speed //following lines of code are to make the bot move forward /*The pin numbers and high, low values might be different depending on your connections */ digitalWrite(4,HIGH); digitalWrite(5,LOW); digitalWrite(6,LOW); digitalWrite(7,HIGH); }[/mw_shl_code] 参考文献: https://www.zhihu.com/question/37943171/answer/119525120 https://mc.dfrobot.com.cn/forum.p ... =%E5%B7%A1%E7%BA%BF https://github.com/samvrit/Proje ... ollower/pid/pid.pde |
© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed