本人刚接触Arduino不久,此代码用于参加校内的比赛,采用是4个红外传感器来检测小车是否压倒黑线,小车是有两个电机,也就是两个由电机控制的大轮,和一个可以转动的小轮用来控制方向。
在烧写小车代码之前,需要确保Arduino的配置正确,选择正确的开发板端口
并且根据实际硬件的不同来连接小车的线路。
在我们实际小车在简易路线(没有坡度,障碍等因素影响)运行的过程当中呢,我们所需要面对的情况有直线、十字路口、小幅度弯道、大幅度弯道四种常见情况,为了更好的应对这几种情况,传感器的数量多当然要更加有优势。
这里四个红外传感器,也就是我们的循迹模块的情况(1为检测到黑线)如下:
基本情况:
1.小车红外向前方向,从左往右依次是1~4:
2.小车放置赛道的时候需要将黑线最好放置在2,3传感器之间
3.当数值为1时,表示检测到了黑线
直行:当我们小车没有传感器检测到黑线时,则为一般直行情况
当小车四个传感器全部检测到黑线时,表示遇到十字路口,依旧直行
传感器1 | 传感器2 | 传感器3 | 传感器4 | 情况 |
0 | 0 | 0 | 0 | 直行 |
1 | 1 | 1 | 1 | 直行 |
大幅度转弯:
因为我们默认小车上赛道的摆放方式是3,4传感器位于黑色赛道的两边,
当只有最外侧的1或4传感器检测到黑线的时候,就表明我们已经严重偏离了赛道,需要进行大幅度的矫正
当左侧或者右侧两个传感器都检测到黑线的时候,表示我们的小车遇到了转弯幅度更为大的弯道甚至是直角弯,这里同样需要进行大幅度转弯,甚至比上面的情况转弯幅度更大。因为在实际的调试过程当中,我发现,如何小车的转弯速度不够快,同样也会导致左侧或右侧两个传感器同时检测到黑线的情况,所以这样写也更为保险一些。
传感器1 | 传感器2 | 传感器3 | 传感器4 | 情况 |
1 | 0 | 0 | 0 | 大幅度左转 |
0 | 0 | 0 | 1 | 大幅度右转 |
1 | 1 | 0 | 0 | 大幅度左转 |
0 | 0 | 1 | 1 | 大幅度右转 |
小幅度转弯:当内侧传感器检测到黑线时,表示我们的小车轻微偏离轨道,则选择小幅度的进行矫正即可
传感器1 | 传感器2 | 传感器3 | 传感器4 | 情况 |
0 | 1 | 0 | 0 | 小幅度左转 |
0 | 0 | 1 | 0 | 小幅度右转 |
代码片段:
引脚定义片段,这里的引脚定义需要根据实际的板子的型号不同进行选择,我这里3,5,6,9引脚是带有~号样式的引脚,也就是可以使用PWM调速的引脚,这里只对PWM进行简单的使用说明,PWM的范围为0~255,数值越大电机转速越快。
以下为电机引脚的定义:
// 电机引脚定义
int LeftMotorGo = 3; // 左电机前进 (IN1)
int LeftMotorBack = 5; // 左电机后退 (IN2)
int RightMotorGo = 6; // 右电机前进 (IN3)
int RightMotorBack = 9; // 右电机后退 (IN4)
和电机相同,红外线传感器也需要在Arduino中进行定义说明:
// 红外传感器引脚定义
const int Sensor1 = 4; // 第一个红外传感器
const int Sensor2 = 7; // 第二个红外传感器
const int Sensor3 = 8; // 第三个红外传感器
const int Sensor4 = 12; // 第四个红外传感器
那定义完我们的引脚之后还要进,行其他的操作,分为两个部分一个是void setup(),
其另一个则是void loop()
在Arduino编程中,void setup()
用于初始化程序所需的设置和配置。它是Arduino程序的一部分,会在程序开始执行时自动调用。
在 void setup()
函数中,可以设置引脚的模式(如输入或输出),在下面的示例中,void setup()
函数执行以下操作:
- 配置电机引脚:通过调用
pinMode()
函数,将电机引脚(LeftMotorGo
,LeftMotorBack
,RightMotorGo
,RightMotorBack
) 设置为输出模式,用于控制电机的前进和后退。 - 配置红外传感器引脚:通过调用
pinMode()
函数,将红外传感器引脚(Sensor1
,Sensor2
,Sensor3
,Sensor4
) 设置为输入模式,用于接收来自传感器的信号。
这两个函数有一个最基本的区别就是,void setup()
函数只在程序开始时执行一次, void loop()
函数在循环中执行代码。
示例代码:
void setup() {
// 设置电机引脚为输出
pinMode(LeftMotorGo, OUTPUT);
pinMode(LeftMotorBack, OUTPUT);
pinMode(RightMotorGo, OUTPUT);
pinMode(RightMotorBack, OUTPUT);
// 设置红外传感器引脚为输入
pinMode(Sensor1, INPUT);
pinMode(Sensor2, INPUT);
pinMode(Sensor3, INPUT);
pinMode(Sensor4, INPUT);
}
在定义完之后,我们就来谈谈如何来实际控制我们小车电机的转速,这里我们引入另一个函数, analogWrite(),通过这个函数我们可以轻松的控制脉冲宽度调制 (PWM) 的方式输出模拟信号,从而来实现控制小车电机的转速。同样我们为了代码看起来更加简洁我们定义一个void 类型的函数以便于后面更加简单直观的控制我们的小车。
void Motor_Speed(int Left1_Speed, int Left2_Speed, int Right1_Speed, int Right2_Speed)
{
analogWrite(LeftMotorGo, Left1_Speed);
analogWrite(LeftMotorBack, Left2_Speed);
analogWrite(RightMotorGo, Right1_Speed);
analogWrite(RightMotorBack, Right2_Speed);
}
这个函数接收四个数值,分别对应四个速度,我们使用 analogWrite函数将接收的速度(PWM)传输到LeftMotorGo等四个变量上去。
在完成这一步的工作之后,我们就要进入我们的void loop()
函数当中去,让我们的小车开始实现循迹的功能:
那么在这里先简单介绍一下小车实现转弯的几种方式吧
1.正转+停转
2.正转+反转
3.停转+反转
一般就是这几种方式,我所选择的是2.正转+反转,因为我在调试的过程中发现,这种转弯方式更加的快速,对与轨道的吸附能力更强,冲出的情况较少。
以下为示例代码:
void loop() {
//读取红外传感器的值
int sensorValue1 = digitalRead(Sensor1);
int sensorValue2 = digitalRead(Sensor2);
int sensorValue3 = digitalRead(Sensor3);
int sensorValue4 = digitalRead(Sensor4);
//根据红外传感器的值控制小车的运动
if (sensorValue1 == 0 && sensorValue2 == 1 && sensorValue3 == 0 && sensorValue4 == 0) { //轻微偏离轨道,差速
Motor_Speed(85, 0, 255, 0);
//delay(25); //延迟一段时间,调整转弯幅度
} else if(sensorValue1 == 0 && sensorValue2 == 0 && sensorValue3 == 1 && sensorValue4 == 0) { //轻微偏离轨道,差速
Motor_Speed(240, 0, 85, 0);
//delay(25); //延迟一段时间,调整转弯幅度
} else if(sensorValue1 == 1 && sensorValue2 == 0 && sensorValue3 == 0 && sensorValue4 == 0) { //严重偏离轨道,反转
Motor_Speed(0, 155, 255, 0);
//delay(75); //延迟一段时间,调整转弯幅度
} else if(sensorValue1 == 0 && sensorValue2 == 0 && sensorValue3 == 0 && sensorValue4 == 1) { //严重偏离轨道,反转
Motor_Speed(255, 0, 0, 155);
//delay(75); //延迟一段时间,调整转弯幅度
} else if(sensorValue1 == 1 && sensorValue2 == 1 && sensorValue3 == 0 && sensorValue4 == 0) { //直角转弯,更大的转弯幅度
Motor_Speed(0, 245, 255, 0);
delay(40); //延迟一段时间,调整转弯幅度
} else if(sensorValue1 == 0 && sensorValue2 == 0 && sensorValue3 == 1 && sensorValue4 == 1) { //直角转弯,更大的转弯幅度
Motor_Speed(250, 0, 0, 255);
delay(40); //延迟一段时间,调整转弯幅度
} else { //除了左右转,就只剩下直走
Motor_Speed(240, 0, 255, 0);
}
}
上面这一段代码并不复杂我们先对四个红外传感器进行了初始化
int sensorValue1 = digitalRead(Sensor1);
int sensorValue2 = digitalRead(Sensor2);
int sensorValue3 = digitalRead(Sensor3);
int sensorValue4 = digitalRead(Sensor4);
然后使用了if(){}和else if(){}来实现小车循迹不同情况的判断,判断条件上述表格已经写出。在注释里,你会发现我有delay()函数,这个函数的作用是加一个延时,让小车在执行动作后停顿一下,具体时间具体设置,如果需要可以根据实际比赛情况进行调整。
在else条件当中,我将其他情况设置为了直走。
到此为止就是全部代码的展示,我也会在结尾附上全部的代码,在实际调试的过程中同样也会遇到很多实际的问题,这里我只说明一些我在调试的时候所遇到的问题,光是使用代码让小车直接实现良好的循迹当然不显示,想要有一个良好的循迹效果需要大家根据实际情况进行反复的调试,这个过程也相当有意思。
1.当你发现下车在经过黑线的时候红外传感器并没有反应,则需要调整红外传感器的灵敏度,一般在红外传感器上都会有一个类似与螺丝的地方,旋动它就可以调整灵敏度。
2.当你发现小车在拐弯过程中,小车检测到了黑线(红外指示灯闪烁)但是并未进行转弯操作,这种就是冲出现象,是小车的转弯力度太小了,小车还没来的及转弯就已经冲出去了。解决这个有两种方法:一是调大转弯差速,二是降低小车行驶速度。
3.小车正常直行无问题,但内侧接触到黑线之后,小车开始剧烈摆动,频繁接触到黑线,甚至冲出赛道。这种情况就是小幅度转弯时候的差速过于大,让小车转弯太过导致的,解决方法就是调小差速喽。
如果还有其余问题的话也欢迎积极交流分享,我暂时想到的问题就这么多。
小白第一次写博客,有什么写的不对,不好的地方欢迎大家指出,我虚心求教嘿嘿!
完整代码展示:
// 电机引脚定义
int LeftMotorGo = 3; // 左电机前进 (IN1)
int LeftMotorBack = 5; // 左电机后退 (IN2)
int RightMotorGo = 6; // 右电机前进 (IN3)
int RightMotorBack = 9; // 右电机后退 (IN4)
// 红外传感器引脚定义
const int Sensor1 = 4; // 第一个红外传感器
const int Sensor2 = 7; // 第二个红外传感器
const int Sensor3 = 8; // 第三个红外传感器
const int Sensor4 = 12; // 第四个红外传感器
void setup() {
// 设置电机引脚为输出
pinMode(LeftMotorGo, OUTPUT);
pinMode(LeftMotorBack, OUTPUT);
pinMode(RightMotorGo, OUTPUT);
pinMode(RightMotorBack, OUTPUT);
// 设置红外传感器引脚为输入
pinMode(Sensor1, INPUT);
pinMode(Sensor2, INPUT);
pinMode(Sensor3, INPUT);
pinMode(Sensor4, INPUT);
}
void Motor_Speed(int Left1_Speed, int Left2_Speed, int Right1_Speed, int Right2_Speed)
{
analogWrite(LeftMotorGo, Left1_Speed);
analogWrite(LeftMotorBack, Left2_Speed);
analogWrite(RightMotorGo, Right1_Speed);
analogWrite(RightMotorBack, Right2_Speed);
}
void loop() {
//读取红外传感器的值
int sensorValue1 = digitalRead(Sensor1);
int sensorValue2 = digitalRead(Sensor2);
int sensorValue3 = digitalRead(Sensor3);
int sensorValue4 = digitalRead(Sensor4);
//根据红外传感器的值控制小车的运动
if (sensorValue1 == 0 && sensorValue2 == 1 && sensorValue3 == 0 && sensorValue4 == 0) { //轻微偏离轨道,差速
Motor_Speed(85, 0, 255, 0);
//delay(25); //延迟一段时间,调整转弯幅度
} else if(sensorValue1 == 0 && sensorValue2 == 0 && sensorValue3 == 1 && sensorValue4 == 0) { //轻微偏离轨道,差速
Motor_Speed(240, 0, 85, 0);
//delay(25); //延迟一段时间,调整转弯幅度
} else if(sensorValue1 == 1 && sensorValue2 == 0 && sensorValue3 == 0 && sensorValue4 == 0) { //严重偏离轨道,反转
Motor_Speed(0, 155, 255, 0);
//delay(75); //延迟一段时间,调整转弯幅度
} else if(sensorValue1 == 0 && sensorValue2 == 0 && sensorValue3 == 0 && sensorValue4 == 1) { //严重偏离轨道,反转
Motor_Speed(255, 0, 0, 155);
//delay(75); //延迟一段时间,调整转弯幅度
} else if(sensorValue1 == 1 && sensorValue2 == 1 && sensorValue3 == 0 && sensorValue4 == 0) { //直角转弯,更大的转弯幅度
Motor_Speed(0, 245, 255, 0);
delay(40); //延迟一段时间,调整转弯幅度
} else if(sensorValue1 == 0 && sensorValue2 == 0 && sensorValue3 == 1 && sensorValue4 == 1) { //直角转弯,更大的转弯幅度
Motor_Speed(250, 0, 0, 255);
delay(40); //延迟一段时间,调整转弯幅度
} else { //除了左右转,就只剩下直走
Motor_Speed(240, 0, 255, 0);
}
}