配合传感器实现小车运动+自动避障
小车与避障原理
一、小车运动模块
小车主要是分为动力模块和控制模块,动力模块由驱动板,直流电机加轮子以及外接供电的锂电池组成。控制模块就是树莓派了,连接驱动板对电机进行控制,实现对小车运动的控制。
注意事项:当小车不转的时候,一定要注意,驱动板和树莓派是否构成一个完整的回路(共地)。
其次是不同的直流电机和供电,会导致小车速度不同,然后会影响避障策略的设置,此时需要调整延时时间即可,若各位有比较好的意见,请在评论区留言,欢迎进行交流。
本文涉及的驱动板是L298n驱动板,长下面这个样子,有IN1–IN4共4个输入接口,对应OUT1–OUT4,ENA、ENB共两个使能接口,一个5V,一个12V和一个GND的电源接口,具体参数,有兴趣的可以下载看一下,由于无法直接放文件,所以可以点这里下载
二、避障原理
在了解避障决策之前,让我们先对障碍物类型进行一个分类,各位看官道友也可以根据自己的喜好对障碍物进行分类,然后设置不同的避障决策。
箭头代表了传感器的探测方向,本文正前方的箭头设置为红外传感器,左右的为超声波传感器。由于红外传感器只有一个,由于红外传感器设计的探测范围问题,容易出现侧前方出现障碍物,识别不准障碍物类型的情况,可适当添加传感器。
==建议:==使用同款传感器和T型板的话,建议对红外传感器的连接线进行一下改动,将母头改成公头。方便和T型板进行连接。
采用的是一种比较简单的避障决策,用一张图,可以用以下这张图来体现。
三、实现
从这里开始就要注意各个部件连接的接口号了,我们为方便统一管理,创建一个config.ini的配置文件,用于管理硬件连接的pin口编号。云台后续再进行添加管理。之后的连线,也主要都是通过看配置文件里面,就比较方便,不用一个个文件看。
[car]
# This is the parmaters that will control the car's wheels
# The number is the interface number if GPIO(GPIO.BCM)
#board 11 12 13 15
IN1 = 17
IN2 = 18
IN3 = 27
IN4 = 22
[ultrasonic]
#BCM 25 6 12 5
#control ultrasonic detection distance for obstacle avoidance
Trigger_l = 25
Trigger_r =6
Echo_l = 12
Echo_r = 5
[infrared]
#BCM 20 detected = 20CM
single_pin = 20
使用了配置文件之后,就需要import configparser。
然后读取配置文件。
config = configparser.ConfigParser()
config.read("config.ini")
(1)将传感器整合。
将各个障碍物类型进行分类后,设置几个传感器配合,对障碍物类型进行判别,同时可以传参给树莓派进行避障策略选择。创建名为sense.py。
import RPi.GPIO as GPIO
import time
import configparser
from infrared import Infrared
from ultrasonic import Ultrasonic
#Define the number of all the GPIO taht used for 4wd car
class Sense():
def __init__(self):
config = configparser.ConfigParser()
config.read("config.ini")
trigger_l=config.getint("ultrasonic","Trigger_l")
trigger_r=config.getint("ultrasonic","Trigger_r")
echo_l=config.getint("ultrasonic","Echo_l")
echo_r=config.getint("ultrasonic","Echo_r")
single_pin=config.getint("infrared","single_pin")
self.Sonic_l = Ultrasonic(trigger_l,echo_l)
self.Sonic_r = Ultrasonic(trigger_r,echo_r)
self.Infrared = Infrared(single_pin)
#get obstacles type
def detection(self):
#NO Obstacles or 20cm safe distance type 0
if self.Infrared.check_distance() == "OK":
return "Fgo"
#Obstacles ahead
#self.Infrared.check_distance() == "Warning"
else :
l_d = self.Sonic_l.get_distance()
r_d = self.Sonic_r.get_distance()
#Obstacles ahead&&right =safe type a
if ((l_d>=30)and(r_d>=30)):
return "Lgo"
#Obstacles ahead&&right R>L type b
elif ((l_d<=30)
and(r_d>30)):
return "Rgo"
#Obstacles ahead&&right L>R type c
elif ((l_d>30)
and(r_d<=30)):
return "Lgo"
#Obstacles ahead&&right L&R<safe type d
elif ((l_d<30)
and(r_d<30)):
return "Bgo"
def ask_distance_l(self):
return self.Sonic_l.get_distance()
def ask_distance_r(self):
return self.Sonic_r.get_distance()
if __name__ == '__main__':
t = Sense()
while True:
s=t.detection()
print(s)
time.sleep(0.5)
(2)小车的运动代码
此时小车这边的基本控制代码如下:
创建一个carCtrl.py
然后里面的有一些注释,没有删,各位将就着看。
import RPi.GPIO as GPIO
import time
import configparser
from sense import Sense
#Define the number of all the GPIO taht used for 4wd car
class CAR():
delay_tl = 0.45
delay_tr = 0.5
delay_30 = 0.4
def __init__(self):
config = configparser.ConfigParser()
config.read("config.ini")
self.IN1=config.getint("car","IN1")
self.IN2=config.getint("car","IN2")
self.IN3=config.getint("car","IN3")
self.IN4=config.getint("car","IN4")
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False) #avoid GPIO warning
GPIO.setup(self.IN1,GPIO.OUT)
GPIO.setup(self.IN2,GPIO.OUT)
GPIO.setup(self.IN3,GPIO.OUT)
GPIO.setup(self.IN4,GPIO.OUT)
self.reset()
self.sense = Sense()
def reset(self):
#Rest all the GPIO as LOW
GPIO.output(self.IN1,False)
GPIO.output(self.IN2,False)
GPIO.output(self.IN3,False)
GPIO.output(self.IN4,False)
def __forward(self):
# self.reset()
GPIO.output(self.IN1,True)
GPIO.output(self.IN2,False)
GPIO.output(self.IN3,True)
GPIO.output(self.IN4,False)
def __backward(self):
# self.reset()
GPIO.output(self.IN1,False)
GPIO.output(self.IN2,True)
GPIO.output(self.IN3,False)
GPIO.output(self.IN4,True)
def __turnright(self):
# self.reset()
GPIO.output(self.IN1,True)
GPIO.output(self.IN2,False)
GPIO.output(self.IN3,False)
GPIO.output(self.IN4,True)
def __turnleft(self):
# self.reset()
GPIO.output(self.IN1,False)
GPIO.output(self.IN2,True)
GPIO.output(self.IN3,True)
GPIO.output(self.IN4,False)
def __stop(self):
self.reset()
def CarMove(self,direction,loop):
if direction == 'F':
self.__forward()
elif direction == 'B':
self.__backward()
elif direction == 'R':
self.__turnright()
elif direction == 'L':
self.__turnleft()
elif direction == 'Auto':
self.autorun(loop)
elif direction == 'S':
self.__stop()
elif direction == 'E':
GPIO.cleanup()
exit()
# else:
# print("The input error! please input:F,B,L,R,S")
#下面的代码都是用于避障的函数,里面所有的loop都是之后要用到的。
#the methods is used to strategy and run
def backx(self,loop):
while loop:
self.__backward()
time.sleep(0.2)
self.reset()
l_d = self.sense.ask_distance_l()
r_d = self.sense.ask_distance_r()
if r_d > 30:
#get a safe distance
self.__backward()
time.sleep(0.2)
#turn right 90
self.__turnright()
time.sleep(self.delay_tr)
#advance 30cm
self.__forward()
time.sleep(self.delay_30)
#turn left 90
self.__turnleft()
time.sleep(self.delay_tl)
break
if l_d > 30:
#get a safe distance
self.__backward()
time.sleep(0.2)
#turn left 90
self.__turnleft()
time.sleep(self.delay_tl)
#advance 30cm
self.__forward()
time.sleep(self.delay_30)
#turn right 90
self.__turnright()
time.sleep(self.delay_tr)
break
def Lgox(self,loop):
while loop:
self.__forward()
time.sleep(0.2)
r_d = self.sense.ask_distance_r()
if r_d > 30:
#advance 15cm
self.__forward()
time.sleep(0.2)
#turn right 90
self.__turnright()
time.sleep(self.delay_tr)
break
def Rgox(self,loop):
while loop:
self.__forward()
time.sleep(0.2)
l_d = self.sense.ask_distance_l()
if l_d > 30:
#advance 15cm
self.__forward()
time.sleep(0.2)
#turn left 90
self.__turnleft()
time.sleep(self.delay_tl)
break
#run and strategy
def autorun(self,loop):
# self.sense = Sense()
# while True:
#get obstacle type
self.reset()
strategy = self.sense.detection()
if strategy == "Fgo":
self.__forward()
time.sleep(0.05)
elif strategy == "Bgo":
self.backx(loop)
elif strategy == "Lgo":
self.__backward()
time.sleep(0.1)
#turn left 90
self.__turnleft()
time.sleep(self.delay_tl)
#return original direction
self.Lgox(loop)
elif strategy == "Rgo":
self.__backward()
time.sleep(0.1)
#turn left 90
self.__turnright()
time.sleep(self.delay_tr)
#return original direction
self.Rgox(loop)
#通过调整占空比来改变小车速度,行自行发挥
'''def changeSpeed():
leftpwm = GPIO.PWM(ENA,50)
leftpwm = stop()
leftpwm = start(100)
leftpwm = ChangeDutyCycle(50)
print('changeSpeed'+50)
'''
'''
#control test
# changeSpeed()
RaspCar=CAR()
RaspCar.autorun()
#turn angle test
'''
if __name__=='__main__':
RaspCar=CAR()
while(True):
direction = input("Please input direction:")
print(direction)
RaspCar.CarMove(direction,True)
time.sleep(0.5)
direction = "S"
RaspCar.CarMove(direction,True)
在测试的时候,请注意loop在这里是无用的,在后面是会用到的,不然不好退出自动避障切换成手动操作。