# 巡线机器人4--变速巡线

机器人在胶带上摇摇晃晃,艰难前行,时常出线。要改善这个状况。

# 情景分析

  1. 传感器并不是瞬间就离开了胶带的,记住,我们的程序1秒钟执行成千上万次。在靠近胶带边沿时,传感器能分辨出偏离了胶带多少。机器人需要在没有脱离胶带前就调整姿态。
  2. 分析下上一节的程序,左边的轮子是由右边的传感器决定的。如果右边的传感器在胶带上,意味着左边轮子前进一些没有问题。如果已经不在胶带上,那么需要停止,不然机器人越是偏离胶带。我们只设置了固定的速度,实际上可以根据偏离的程度,来计算一下可变的速度。
  3. 对于左边轮子,如果右边传感器感应到偏离胶带,应该减速,并且越偏离越应该将速度降低。如果没有偏离,可以用正常的速度前进。还记得避障课程里面的map函数吗?将偏离的程度映射成速度就可以了。map的输入范围是纸张感应值到胶带感应值之间的一个数字,对应的输出范围是停止到正常的速度,映射参数是当前的传感器读数,结果是要设置的速度。
  4. 上一节程序开机时根据纸张和胶带的感应数值来计算参考值,随着机器人移动,纸张和胶带可能会出现更大或者更小的感应值,那么在map函数就可能出现避障教程中的那个bug。所以巡线过程中,出现比纸张靠参考值P小的感应值(不论是左边还是右边传感器),都应该设置P为最小的数值。同理,要保证T最大。map函数的工作范围才正确。
uml diagram

# 流程解析

  1. 程序开始需要定义变量int P = 0用来保存纸张的参考值,int T = 0,用来保存胶带的参考值。
  2. 定义变量int VL = 0保存左边传感器的感应值,int VR = 0保存右边传感器的感应值。
  3. 同样地开机让机器人右转,并碰到胶带,停住。现在右边的传感器是在胶带上,左边传感器在纸张上。分别保存到变量T = analogRead(A0)P = analogRead(A1),计算速度时,要参照这两个数,判断偏离胶带有多远。
  4. 程序进入loop,分别读取两个传感器VR = analogRead(A0)VL = analogRead(A1)
  5. VL应该是在P和T之间的一个数(VR也是)。但因为P,T只是在程序开头设置的数,后面机器人可能走到比开始时更偏黑色的胶带或者更偏白色的纸张上,那么就有可能在P,T范围外面。T是比P大的数(胶带的感应值比纸张感应值大),如果出现比它大的数,就把T设置成这个大的数:T = max(T, VL),同理,T = max(T, VR)。对于纸张参考值,也是同样的推理有:P = min(P, VL)P = min(P, VR)
  6. 现在VL肯定不会是大于T或者小于T的数了。如果数值比较接近P,那么应该认为左边传感器比较靠近纸,右边的马达速度就应该慢一些,等待左边马达前进,将机器人推回胶带上。反过来如果比较接近T(靠近胶带),那么就可以放心地前进。右边的马达根据VL在从P到T之间的位置,对应速度由慢到快R.forward(map(VL, P, T, 0, 120)),同理L.forward(map(VR, P, T, 0, 120))
  7. 重复步骤4到步骤6。机器人一直仔细地调整速度。
uml diagram

# 参考程序

  • oseppBlock IDE程序

  • Arduino IDE程序
#include <oseppRobot.h>

OseppTBMotor L(12, 11);
OseppTBMotor R(8, 3, LOW);
int P = 0;      //纸张的参考值
int T = 0;      //胶带的参考值
int VL = 0;     //左边传感器的感应值
int VR = 0;     //右边传感器的感应值

void setup() {
    L.forward(60);
    R.backward(60);
    //等待碰到胶带
    while (analogRead(A0) - analogRead(A1) < 300) {
    }
    //分别记录初始的纸张胶带参考值
    T = analogRead(A0);
    P = analogRead(A1);
}

void loop() {
    //分别读取左边,右边的传感器感应值,并保存到变量
    VR = analogRead(A0);
    VL = analogRead(A1);
    //动态地更新参考值,保持T最大,P最小
    T = max(T, VL);
    T = max(T, VR);
    P = min(P, VL);
    P = min(P, VR);
    //根据感应值,参考值来计算速度
    L.forward(map(VR, P, T, 0, 120));
    R.forward(map(VL, P, T, 0, 120));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 运行结果

同之前一样放置机器人。打开电源,机器人找到胶带后尝试跟着走,并仔细地调整姿态。对比之前的程序看看有没有进步。尝试适当地提高或者降低速度。

# 课程解读

  1. 程序里使用了4个变量,因为要多次用到传感器的值,所以把它们先保存到变量VL,VR。读取以后,动态更新纸张参考值P为最小值,胶带参考值T为最大值。map函数的结果才会符合预期。
  2. max(value1,value2)函数可以返回value1,value2中较大的数,T=max(T,VL)表示把T设置成T和VL中较大的数,再次对VR使用,T就成了T,VL,VR中最大的数,比较常用的方法是T=max(T,max(VL,VR)),和我们的用法是等效的。同理min(value1,value2)得到两个数中较小的一个。
  3. 机器人走完一圈后,程序才收集到整条线路真正的最大最小参考值。走第二圈时,机器人会更熟悉线路。因为开始的时候,参考范围比较小,例如400到800。如果测量到600,计算出速度是60。走完一圈后,参考范围可能变大了。例如变成100到900。再次测量到600的值,计算出来的速度75。这个时候的600确定更接近胶带,所以速度更快。

备注:你可能会觉得oseppBlock IDE中的积木描述非常不通顺,oseppBlock IDE是为了使用Arduino IDE做准备的工具,所以要在最大程度上与原本的函数格式保持一致,请多对照Arduino IDE的代码。

# oseppBlock操作视频

# ArduinoIDE操作视频