前两篇文章已经介绍了如何组装四驱小车以及小车的驱动类封装;接下来这篇文章将尝试驱动类调用以及小车循迹测试。
小车组装文章:https://www.shumeijiang.com/2021/09/23/四驱小车循迹实验-小车组装/ 。
小车驱动类封装文章:https://www.shumeijiang.com/2021/09/23/四驱小车循迹实验-直流电机驱动封装/ 。
#循迹实验效果
#实现效果:
从上面gif图以及视频可看到,小车遇到直线会直行前进,由于手工贴的胶带不是很直所以小车会实时调整前进的角度;当遇到转弯时,同样会一点点进行转弯直到寻找到黑线线条;
传感器示例
上图模拟小车前面并排的三个红外避障传感器,分别是ONE,TWO,THREEE;默认黑线位于TWO传感器正下方为直行;由于小车要不停向前移动,但是黑线有弯曲或者转弯的情况,所以小车会出现三个传感器分别接触黑线的情况;通过不同的传感器被触发事件,从而得出小车现在的行走方向以及判断是否要做方向调整,具体原理如下(1为检测到黑线触发事件,0为未检测到黑线):
1、ONE=1,THREE=0 说明黑线偏转右侧,此时小车应向右转向;
2、ONE=0,THREE=1 说明黑线偏转左侧,此时小车应向左转向;
3、ONE=0,TWO=1,THREE=0 说明黑线在中心方向,小车需直行;
4、ONE=1,TWO=1,THREE=1 说明遇到横线,小车需停顿;
5、ONE=0,TWO=0,THREE=0 说明小车失去黑线,此时需寻找或者停止。
#实现代码
#!/usr/bin/env python
#coding:utf-8
'''
from JiuJiang
树莓酱的操作实例
http:://www.shumeijiang.com
'''
import RPi.GPIO as GPIO
import time
GPIO.setwarnings(False)
#引入驱动类
from baseAct import baseAct
#实例化驱动类并赋值四个电机所占引脚值
act = baseAct(17, 16, 13, 12, 19, 18, 21, 20)
#三个传感器检测黑线
senseOne = 22
senseTwo = 23
senseThree = 24
#一个检测障碍物
checkPin = 25
GPIO.setmode(GPIO.BCM)
GPIO.setup(senseOne, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(senseTwo, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(senseThree, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(checkPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#事件注册 注意不同传感器触发事件不同
GPIO.add_event_detect(senseOne, GPIO.RISING, bouncetime=200)
GPIO.add_event_detect(senseTwo, GPIO.FALLING, bouncetime=200)
GPIO.add_event_detect(senseThree, GPIO.RISING, bouncetime=200)
GPIO.add_event_detect(checkPin, GPIO.FALLING, bouncetime=200)
#检测事件
def check_event(pin):
status = GPIO.event_detected(pin)
return status
#检测状态
def check_status(pin):
status = GPIO.input(pin)
return status
#find
done = False
try:
while not done:
#障碍物检测
front_status = check_event(checkPin)
print("front status is %d"% front_status)
if front_status == 1:
print('有障碍物 停止')
act.act_backward(0.5, 50, 50)
done = True
break
#检测各传感器状态
#status = find_way(senseOne, senseTwo, senseThree)
sOne = check_event(senseOne)
sTwo = check_event(senseTwo)
sThree = check_event(senseThree)
print('sOne is %d'% sOne)
print('sTwo is %d'% sTwo)
print('sThreee is %d' % sThree)
way_type = 'forward'
#继续前行
if sOne == 0 and sThree==0:
act.act_forward(0.15, 50, 40, True)
print('forward')
#遇到横线停顿
elif sOne == 1 and sThree == 1:
time.sleep(0.5)
print('wait')
#向右侧转弯调整
elif sOne == 1 and sThree == 0:
#act.turn_right(0.15, 50, 40)
#检测是否居中
find = False
while not find:
oneStatus = check_event(senseOne)
twoStatus = check_event(senseTwo)
threeStatus = check_event(senseThree)
print('run right---->>')
print('one status is %d'% oneStatus)
print('two status is %d'% twoStatus)
print('three status is %d'% threeStatus)
if oneStatus==0 and twoStatus==1 and threeStatus==0:
find = True
break
act.turn_right(0.15, 55, 45, True)
time.sleep(0.2)
print('right')
way_type = 'right'
#向左侧转弯调整
elif sOne == 0 and sThree == 1:
find = False
while not find:
oneStatus = check_event(senseOne)
twoStatus = check_event(senseTwo)
threeStatus = check_event(senseThree)
print('run left<<----')
print('one status is %d'% oneStatus)
print('two status is %d'% twoStatus)
print('three status is %d'% threeStatus)
if oneStatus==0 and twoStatus==1 and threeStatus==0:
find = True
break
act.turn_left(0.15, 55, 45, True)
time.sleep(0.2)
print('left')
way_type = 'left'
else:
pass
print('once')
#time.sleep(0.2)
#if sOne==0 and sTwo==0 and sThree==0:
#act.act_break()
#print('stop!!!!')
#break
except KeyboardInterrupt:
pass
GPIO.cleanup()
从上面的代码可以看到循迹的策略和流程如下:
1、首先注册one和three分别一个RISING(低变高)事件,因为默认情况下这两个传感器没有遇到黑线而是地板,所以触发低电平事件(传感器低电平触发检测);
2、two注册一个FALLING(高变低)事件,因为默认two传感器红外被黑色线条吸收,从而不产生障碍物检测,所以检测状态为高电平;
3、checkPin为小车前方障碍物检测,如果遇到前方障碍物,小车停车并后退,这个不是重点不做详细介绍;
4、one、two、three传感器的防抖时间bouncetime,异或说检测间隔为200毫秒,这个可以自己调节,主要用于探测黑线的频率;
5、紧接着进入一个while循环,每次都检测三个传感器状态,当发现:
(1)one和three都没有触发RISING事件,我们认为此时黑线还在中间,所以直行;
(2)one和three都触发RISING事件,说明遇到横线,所以停顿;
(3)one触发,three没有触发,说明直行后黑线弯曲,触发了右侧one传感器;为了黑线居中,这个时候小车就需要右转,但是由于不知道黑线弯曲程度(后续可实验图像识别),所以小车进入一个找线环节,以0.15秒的步伐,一点点右转,同时占空比调为55,赫兹设置为45,降低右转速度;当two传感器触发FALLING事件,说明小车归正,则继续触发直行策略,以此类推;
(4)one没有触发,three触发,说明直行后黑线向左弯曲,触发左转动作,具体细节同右转相似;
6、如此,小车便会直行、停顿、左转和右转;当然程序还有很多不足的地方,后续还会继续优化。
#事件检测(边沿检测)部分可参考文章:https://www.shumeijiang.com/2020/03/15/gpio之event_detected系列函数/ 。