青夏 发表于 2018-4-25 10:44:55

巡线问题小议

本帖最后由 微笑的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 提供了他写的巡线代码。我们后面将以他的代码为基础进一步的改进。
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={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=digitalRead(A0);
sensor=digitalRead(A1);
sensor=digitalRead(A2);
sensor=digitalRead(A3);
sensor=digitalRead(A4);

if((sensor==0)&&(sensor==0)&&(sensor==0)&&(sensor==0)&&(sensor==1))
error=4;
else if((sensor==0)&&(sensor==0)&&(sensor==0)&&(sensor==1)&&(sensor==1))
error=3;
else if((sensor==0)&&(sensor==0)&&(sensor==0)&&(sensor==1)&&(sensor==0))
error=2;
else if((sensor==0)&&(sensor==0)&&(sensor==1)&&(sensor==1)&&(sensor==0))
error=1;
else if((sensor==0)&&(sensor==0)&&(sensor==1)&&(sensor==0)&&(sensor==0))
error=0;
else if((sensor==0)&&(sensor==1)&&(sensor==1)&&(sensor==0)&&(sensor==0))
error=-1;
else if((sensor==0)&&(sensor==1)&&(sensor==0)&&(sensor==0)&&(sensor==0))
error=-2;
else if((sensor==1)&&(sensor==1)&&(sensor==0)&&(sensor==0)&&(sensor==0))
error=-3;
else if((sensor==1)&&(sensor==0)&&(sensor==0)&&(sensor==0)&&(sensor==0))
error=-4;
else if((sensor==0)&&(sensor==0)&&(sensor==0)&&(sensor==0)&&(sensor==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);
}

参考文献:

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



安卓机器人 发表于 2018-4-26 07:58:14

根据这个思路提示,最好的办法就是用小车反复实践验证,5.1来试一试

青出于蓝 发表于 2019-8-24 17:55:26

理论正解,建议传感器数量可以多加几个,更方便解读。

gada888 发表于 2019-8-25 09:25:03

不错的分享
页: [1]
查看完整版本: 巡线问题小议