树莓派综合项目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源代码下载

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342