小车与避障原理

一、小车运动模块

小车主要是分为动力模块和控制模块,动力模块由驱动板,直流电机加轮子以及外接供电的锂电池组成。控制模块就是树莓派了,连接驱动板对电机进行控制,实现对小车运动的控制。
==注意事项==:当小车不转的时候,一定要注意,驱动板和树莓派是否构成一个完整的回路(共地)。
其次是不同的直流电机和供电,会导致小车速度不同,然后会影响避障策略的设置,此时需要调整延时时间即可,若各位有比较好的意见,请在评论区留言,欢迎进行交流。
本文涉及的驱动板是L298n驱动板,长下面这个样子,有IN1–IN4共4个输入接口,对应OUT1–OUT4,ENA、ENB共两个使能接口,一个5V,一个12V和一个GND的电源接口,具体参数,有兴趣的可以下载看一下,由于无法直接放文件,所以可以点这里下载
![L298n驱动板](https://img-blog.csdnimg.cn/20200427000108138.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5MDQ3NDYx,size_16,color_FFFFFF,t_70 =360x360)

二、避障原理

在了解避障决策之前,让我们先对障碍物类型进行一个分类,各位看官道友也可以根据自己的喜好对障碍物进行分类,然后设置不同的避障决策。
在这里插入图片描述

箭头代表了传感器的探测方向,本文正前方的箭头设置为红外传感器,左右的为超声波传感器。由于红外传感器只有一个,由于红外传感器设计的探测范围问题,容易出现侧前方出现障碍物,识别不准障碍物类型的情况,可适当添加传感器。
==建议:==使用同款传感器和T型板的话,建议对红外传感器的连接线进行一下改动,将母头改成公头。方便和T型板进行连接。
采用的是一种比较简单的避障决策,用一张图,可以用以下这张图来体现。
在这里插入图片描述

三、实现

从这里开始就要注意各个部件连接的接口号了,我们为方便统一管理,创建一个config.ini的配置文件,用于管理硬件连接的pin口编号。云台后续再进行添加管理。之后的连线,也主要都是通过看配置文件里面,就比较方便,不用一个个文件看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[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。
然后读取配置文件。

1
2
config = configparser.ConfigParser()
config.read("config.ini")

(1)将传感器整合。

将各个障碍物类型进行分类后,设置几个传感器配合,对障碍物类型进行判别,同时可以传参给树莓派进行避障策略选择。创建名为sense.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 传感器探测障碍物类型
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
然后里面的有一些注释,没有删,各位将就着看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 小车的控制代码
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在这里是无用的,在后面是会用到的,不然不好退出自动避障切换成手动操作。