四驱小车循迹实验-循迹实现

四驱小车循迹实验-循迹实现

    前两篇文章已经介绍了如何组装四驱小车以及小车的驱动类封装;接下来这篇文章将尝试驱动类调用以及小车循迹测试。
    小车组装文章: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系列函数/
jiujiang

评论已关闭。