树莓派综合项目2:智能小车(五)红外避障
一、介绍
阅读本篇文章前建议先参考前期文章:
树莓派基础实验34:L298N模块驱动直流电机实验,学习了单个电机的简单驱动。
树莓派综合项目2:智能小车(一)四轮驱动,实现了代码输入对四个电机的简单控制。
树莓派综合项目2:智能小车(二)tkinter图形界面控制,实现了本地图形界面控制小车的前进后退、转向和原地转圈。
树莓派综合项目2:智能小车(三)无线电遥控,实现了无线电遥控设备控制小车的前进后退、转向和原地转圈。
树莓派综合项目2:智能小车(四)超声波避障,实现了超声波传感器实时感知小车前方障碍物的距离,当距离近于某个阈值时,小车自动减速,再低于某个阈值时自动刹车,然后倒车至安全距离。
本实验中将使用HJ-IR2红外光电传感器,探测到物体即输出脉冲,输入到树莓派中处理,再对电机驱动模块进行控制,实现壁障的功能,这样的避障小车又称为简单的避障机器人。
其它基础内容可以参考文集:树莓派基础实验。
二、组件
★Raspberry Pi 3 B+全套*1
★睿思凯Frsky XM+ 迷你接收机*1
★电平反向器模块*1
★睿思凯Frsky Taranis X9D PLUS SE2019遥控器*1
★L298N扩展板模块*1
★智能小车底板模块*1
★减速电机和车轮*4
★HC-SR04超声波模块*1
★HJ-IR2红外光电传感器*2
★跳线若干
三、实验原理
HJ-IR2红外光电传感器本实验原理和超声波避障相似,红外传感器就是一个红外对射开关,通电状态下,红外发射头发射红外信号,经过目标反射后接收头接收此信号,并输出一个低电平信号,树莓派采集这个低电平信号后采取相应措施避障。
传感器参数探测距离调节
若没有被任何一个探头检测到障碍物,小车直行;左边探头检测到障碍物时小车向右转,右边探头检测到障碍物时小车向左转。
关于红外传感器的基础知识请参见树莓派基础实验28:红外避障传感器实验。
四、实验步骤
第1步: 连接电路。这里对红外避障外的连线方法不在累述,请参考树莓派综合项目2:智能小车(四)超声波避障。
树莓派(name) | 树莓派(BOARD) | 红外探测模块 |
---|---|---|
GPIO.21 | 29 | 左侧红外输出 |
GPIO.22 | 31 | 右侧红外输出 |
5V | 5V | 两个模块的VCC |
GND | GND | 两个模块的GND |
第2步: motor_4w.py,moving_control.py,sbus_receiver_pi.py,ultrasonic.py文件的编码这里不再累述,参考树莓派综合项目2:智能小车(四)超声波避障。
第3步:编写红外探测模块,文件名为infrared.py,与树莓派基础实验28:红外避障传感器实验中的Python程序基本相同,只是设置了类,重构了程序。
infrared.py:
#!/usr/bin/env python3
#-*- coding: utf-8 -*-
#本模块只含Infrared()一个类,用于红外避障模块测出是否有障碍物
#有障碍物时返回值0,无障碍物时返回值1
import RPi.GPIO as GPIO
import time
class Infrared():
InfraredPinLeft = 29 #左侧模块的输出连接树莓派29号针脚
InfraredPinRight = 31
def setup(self):
GPIO.setmode(GPIO.BOARD)
GPIO.setup(Infrared.InfraredPinLeft, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(Infrared.InfraredPinRight, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def infra_detect(self):
infra_left_value = 1
infra_right_value = 1
if (0 == GPIO.input(Infrared.InfraredPinLeft)): #当检测到障碍物时,输出低电平信号
infra_left_value = 0
if (0 == GPIO.input(Infrared.InfraredPinRight)): #当检测到障碍物时,输出低电平信号
infra_right_value = 0
return infra_left_value,infra_right_value
def destroy(self):
GPIO.cleanup()
if __name__ == "__main__":
try:
infrared = Infrared()
infrared.setup()
while True:
infra_left_value,infra_right_value = infrared.infra_detect()
print('infra_left_value=%d infra_right_value=%d'%(infra_left_value,infra_right_value) )
time.sleep(0.1)
except KeyboardInterrupt:
infrared.destroy()
第4步: 编写树莓派智能小车的主程序,文件名为smartcar.py,将这5个Python文件放入一个文件夹后,只运行本文件就可以了。
主程序中加入了infra_control()红外避障函数,实现了没有障碍物时小车直行;左边探头检测到障碍物时小车向右转,右边探头检测到障碍物时小车向左转。
smartcar.py:
#!/usr/bin/env python
#-*- coding: utf-8 -*-
#本模块为树莓派小车的主程序,
from motor_4w import Motor_4w
from sbus_receiver_pi import SBUSReceiver
from moving_control import MovingControl
from ultrasonic import Ultrasonic
from infrared import Infrared
import time
acc_value_sbus_enable = 1 #使能是否执行SBUS油门信号,为0时使遥控器油门信号无效
sbus_receiver = SBUSReceiver('/dev/ttyAMA0') #初始化SBUS信号接收实例
smp_car = Motor_4w() #初始化电机控制实例
smp_car.setGPIO() #初始化引脚
ENA_pwm = smp_car.pwm(smp_car.ENA) #初始化使能信号PWM,A为左边车轮
ENB_pwm = smp_car.pwm(smp_car.ENB) #初始化使能信号PWM,B为右边车轮
smartcar = MovingControl(smp_car,ENA_pwm,ENB_pwm) #初始化车辆运动控制实例
ultr = Ultrasonic() #初始化超声波实例
ultr.setup() #初始化超声波引脚
infrared = Infrared() #初始化红外避障实例
infrared.setup() #初始化红外避障引脚
def ultra_control():
'''超声波传感器控制'''
global acc_value_sbus_enable
dis = ultr.distance()
print('distance= %.1f cm\n' %dis)
if dis < 50:
#当障碍距离小于50cm时,不执行SBUS油门信号
if smartcar.acc_value > 40:
#当障碍距离小于50cm,且油门大于40时,油门设定为40,为防冲撞减速
smartcar.acc_value = 40
smartcar.accelerator() #调节油门
if dis < 10:
#如果测距小于10cm时,先停车再倒车0.3秒
smartcar.brake()
smartcar.reverse()
time.sleep(0.3)
def infra_control():
'''红外避障传感器控制'''
infra_left_value = 1 #值默认为1时,表示无障碍物
infra_right_value = 1
infra_left_value,infra_right_value = infrared.infra_detect()
if infra_left_value == 0: #值为0时,表示左侧检测到障碍物
#smartcar.acc_value=80
smartcar.accelerator(1,0) #控制小车向右偏转
time.sleep(0.5) #向右偏转行进0.5秒
if infra_right_value == 0:
#smartcar.acc_value=80
smartcar.accelerator(0,1)
time.sleep(0.5)
print('infra_left_value=%d infra_right_value=%d'%(infra_left_value,infra_right_value) )
def sbus_control():
'''无线电控制'''
sbus_receiver.update() #获取一个完整的帧数据
global acc_value_sbus_enable
aileron_value = sbus_receiver.get_rx_channel(0) #1通道为副翼通道,这里控制车原地转向
elevator_value = sbus_receiver.get_rx_channel(1)#2通道为升降舵通道,这里控制车前进后退
rudder_value = sbus_receiver.get_rx_channel(3)#4通道为方向舵通道,这里控制车左右偏移行进
if acc_value_sbus_enable == 1:
#使能SBUS信号的油门控制
acc_value_sbus = 172 #3通道,即油门的值,最低时为172
if sbus_receiver.get_rx_channel(2):
acc_value_sbus = sbus_receiver.get_rx_channel(2) #3通道为油门通道,这里控制车速度
#将172~1811的油门通道值转换为0~100的占空比信号,
smartcar.acc_value = int(100*(acc_value_sbus-172)/(1811-172))
print('original.acc_value=',smartcar.acc_value) #检测SBUS信号的油门值
ultra_control() #超声波避障
infra_control() #红外避障
print('disposed.acc_value=',smartcar.acc_value) #检测超声波函数处理后的油门值
if 970 < rudder_value < 1100: #没有左右偏移时,中间值为992,但遥控器微调时会有上下浮动
pass #没有左右偏移时
elif rudder_value >=1100: #向右偏移行进时
rate_right = (1811.0 - rudder_value)/(1811-1100)
#最大值一般为1811,这里使用浮点类型,所以一定要使用1811.0
smartcar.accelerator(1,rate_right)
elif rudder_value <=970: #向左偏移行进时
rate_left = (rudder_value - 172.0)/(970-172)
#最小值为172,这里使用浮点类型,所以一定要使用172.0
smartcar.accelerator(rate_left,1)
print('elevator_value=%d,aileron_value=%d,rudder_value=%d'%(elevator_value,aileron_value,rudder_value))#测试数据用
if aileron_value >= 1100: #原地左转弯
smartcar.leftTurn()
smartcar.accelerator()
elif aileron_value <= 970: #原地右转弯
smartcar.rightTurn()
smartcar.accelerator()
else :
smartcar.brake() #停车
if elevator_value >=1100: #前进
smartcar.forward()
elif elevator_value <=970: #后退
smartcar.reverse()
#循环最后,这里不能再用停车了
try:
while True:
time.sleep(0.01)
sbus_control()
except KeyboardInterrupt:
smp_car.destroy(ENA_pwm,ENB_pwm)
finally:
smp_car.destroy(ENA_pwm,ENB_pwm)
这个项目的代码90%是我原创瞎写的,有需要参考的同学可以下载:
树莓派智能小车项目python源代码下载