学习arduino几个月,代码和硬件搭建可能有一些不合理的地方,希望各位多多指正。
暑假突然想到可以用小型的光源来引导小车跟踪鞋子,于是就着手准备材料了。初步的想法是将光源固定在鞋子上,走路时小车就会一直跟在身后。
这里使用了arduino uno作为主控板,DFRobot的小车底盘以及L298驱动扩展版,夏普距离传感器和一个小型充电宝。
小车两侧安置红外传感器用以判断方向,由于使用的发射器的范围不大,为防止发射器和传感器不在一个水平线上,每一侧我都安装了两个。另外在小车第二层的底部固定了一个红外测距,用以在方向调整完后判断并调整与发射器的距离。大致的调整过程如下:
首先调整方向,当左侧传感器返回数值远大于右侧时,说明小车左侧更靠近发射器,因此控制小车左转使其正对发射器,当右侧传感器返回数值远大于右侧时,则控制小车右转。
方向调整完毕以后读取红外测距的数值,当距离小于等于10厘米时小车后退,距离在10厘米和17厘米之间静止不动,距离超过17厘米则前进。
2种特殊情况:
1.小车距离鞋子太近,即使转动很小,两侧的传感器数值变化仍然很大,容易陷入左转-右转-左转-右转的死循环中,因此当距离小于5厘米时调整距离优先,后退之后再判断方向。
2.当发射器于小车的距离过大时,左右红外传感器的返回数值皆为0,小车将停止之前的动作并静止不动,等待发射器再次接近。
由于小车判定方向时只需要接受红外光源一小段时间,因此红外发射器不需要持续发射,因此买了一个兼容arduino的小型红外发射模块,以前做项目时用的小型号主控板,每0.1s给一个20ms的高电平,这样电流不会超过限定值。由于设定小车每个动作持续0.2s,判断+执行一个动作的总时间不会超过0.3s,一秒内可以完成三次调整。
目前由于小车太重,速度跟不上,行走时很容易跟丢。这里先发一个拿鞋子引路的视频,各位谅解哈
以下是代码(编程水平有限,判断条件的子函数写的有点乱):
[mw_shl_code=cpp,true]/*
接线:
距离传感器A0
左下红外传感器A2
左上红外传感器A3
右下红外传感器A4
右上红外传感器A5
每个传感器都接扩展板上的vcc和gnd
*/
char E1 = 10;
char M1 = 12;
char E2 = 11;
char M2 = 13;
char disPin = A0;
char IRLL = A2;
char IRLU = A3;
char IRRL = A4;
char IRRU = A5;
int valLL;
int valRL;
int valLU;
int valRU;
int t = 200;
int current;
double dis;
void setup() {
//Serial.begin(9600);
pinMode(disPin, INPUT);
pinMode(IRLL, INPUT);
pinMode(IRRL, INPUT);
pinMode(IRLU, INPUT);
pinMode(IRRU, INPUT);
}
void loop() {
valLL = analogRead(IRLL);
valRL = analogRead(IRRL);
valLU = analogRead(IRLU);
valRU = analogRead(IRRU);
current = checkStatus(valLL, valLU, valRL, valRU);
switch (current) {
case 1:
turnL(130);
/*Serial.print("Turn Left -- leftLower : ");
Serial.print(valLL);
Serial.print(" rightLower : ");
Serial.print(valRL);
Serial.print(" leftUpper : ");
Serial.print(valLU);
Serial.print(" rightUpper : ");
Serial.println(valRU);*/
delay(t);
break;
case 2:
turnR(130);
/*Serial.print("Turn Right -- leftLower : ");
Serial.print(valLL);
Serial.print(" rightLower : ");
Serial.print(valRL);
Serial.print(" leftUpper : ");
Serial.print(valLU);
Serial.print(" rightUpper : ");
Serial.println(valRU);*/
delay(t);
break;
case 3:
back(180,180);
/*Serial.print("Right in the middle -- leftLower : ");
Serial.print(valLL);
Serial.print(" rightLower : ");
Serial.print(valRL);
Serial.print(" leftUpper : ");
Serial.print(valLU);
Serial.print(" rightUpper : ");
Serial.print(valRU);
Serial.print(" distance: ");
Serial.print(dis);
Serial.print("cm ");
Serial.println("back");*/
delay(t);
break;
case 4:
brake();
/*Serial.print("Right in the middle -- leftLower : ");
Serial.print(valLL);
Serial.print(" rightLower : ");
Serial.print(valRL);
Serial.print(" leftUpper : ");
Serial.print(valLU);
Serial.print(" rightUpper : ");
Serial.print(valRU);
Serial.print(" distance: ");
Serial.print(dis);
Serial.print("cm ");
Serial.println("stop");*/
delay(t);
break;
case 5:
advance(180,180);
/* Serial.print("Right in the middle -- leftLower : ");
Serial.print(valLL);
Serial.print(" rightLower : ");
Serial.print(valRL);
Serial.print(" leftUpper : ");
Serial.print(valLU);
Serial.print(" rightUpper : ");
Serial.print(valRU);
Serial.print(" distance: ");
Serial.print(dis);
Serial.print("cm ");
Serial.println("advance");*/
delay(t);
break;
case 6:
brake();
/* Serial.print("Out of range -- leftLower : ");
Serial.print(valLL);
Serial.print(" rightLower : ");
Serial.print(valRL);
Serial.print(" leftUpper : ");
Serial.print(valLU);
Serial.print(" rightUpper : ");
Serial.print(valRU);*/
delay(t);
break;
default:
break;
}
}
int checkStatus(int leftLowerValue, int leftUpperValue, int rightLowerValue, int rightUpperValue){
static unsigned long last; //记录上一次收到红外线的时间
int carStatus = 0;
uint16_t value = analogRead (disPin);
dis = 2076.0 / (value - 11.0);
//任一传感器返回大于100的数值则说明收到了发射源的红外线
if ( leftLowerValue >= 100 || leftUpperValue >= 100 || rightLowerValue >= 100 || rightUpperValue >= 100 )
{
if( leftLowerValue - rightLowerValue > 180 || leftUpperValue - rightUpperValue > 180 )
{
carStatus = 1;
}
else if ( rightLowerValue - leftLowerValue > 180 || rightUpperValue - leftUpperValue > 180 )
{
carStatus = 2;
}
//若方向调整完毕,测量距离
else
{
if (dis < 100 ){
if( dis <= 10 ) carStatus = 3;
else if( dis > 10 && dis < 17 ) carStatus = 4;
else carStatus = 5; //测量距离并作出相应的动作
}
}
last = millis();
if( dis <= 10 ) carStatus = 3; //方向不正但是距离过近时调整距离优先
}
else if(millis() - last > 500)
{
carStatus = 6; //当连续500ms没有探测到红外线时说明光源过远,停止小车当前动作
}
return carStatus;
}
void advance(int alspeed, int arspeed){
digitalWrite(M1,LOW);
analogWrite(E1,alspeed);
digitalWrite(M2,HIGH);
analogWrite(E2,arspeed);
}
void back(int blspeed, int brspeed){
digitalWrite(M1,HIGH);
analogWrite(E1,blspeed);
digitalWrite(M2,LOW);
analogWrite(E2,brspeed);
}
void turnR(int trspeed){
digitalWrite(M1,LOW);
analogWrite(E1,trspeed);
digitalWrite(M2,LOW);
analogWrite(E2,trspeed);
}
void turnL(int tlspeed){
digitalWrite(M1,HIGH);
analogWrite(E1,tlspeed);
digitalWrite(M2,HIGH);
analogWrite(E2,tlspeed);
}
void brake(){
digitalWrite(M1,LOW);
digitalWrite(E1,LOW);
digitalWrite(M2,LOW);
digitalWrite(E2,LOW);
}[/mw_shl_code]
最后附上实物图一张
|