树莓派综合项目2:智能小车(一)四轮驱动

2021-02-26 23:14:06 浏览数 (1)

一、介绍

  树莓派的小项目中,我首选了智能小车这个项目作为我探索的第一个目标,因为和很多小朋友一样,对遥控小汽车有种喜欢,特别是有过小时候欲求而不得的经历的大人们哈。

  其实也还有现实因素考虑,智能小车是地上跑的,比天上飞的水下潜的操作方便、简单、便宜,所需要的元素和技术也比较全面,市场上现有的硬件也很多,资料也较多,作为新手村入场很不错!

  然则事实很打脸,这哪是1级的新手村啊,起码是10级的副本地图,没人带的话,结果可想而知。

  2018年6月8日购买的,今天才正式开玩,中间虽说很多事情耽误了但也拖得够久的了,主要是送的视频资料讲解内容很浅显,对编程的解释不够细,而且只有C 的源码,虽然本人有过开发C 的浅薄经验,但自我鉴定级别很低。现在有个这么好学好用的Python,不想去倒腾C 了,可那时Python也不会啊!那先运行商家的C 吧,组装好车后编译半天,车不动啊,咨询淘宝店家,不搭理你!现在发现可能是树莓派的GND和拓展板的GND没连接的缘故。

  后来一想,还是回新手村老实升级吧!

  于是入手了几本树莓派开发的书和Python入门书,学了一段时间后发现,雾里探花,总不得劲,不真实!

  这种实践类课程还是得做实验才最有效,淘宝上选了一套树莓派传感器套餐,每种传感器一个实验,从原理到接线,再到编程,简单但清晰明了,一个个实验下来,收获满满。

  学到现在,估计10多级了,离开新手村再去当初那个副本瞧瞧,我觉得用Python,用自己的思想,重写智能小车的所有功能,不是梦想,而是现实了!有挑战,但很上瘾哦(´-ω-`)!

智能小车(一)四轮驱动

  下面是大部分的零配件,可以自行选购,价格都不贵哈,总共就几百块:

  一个项目初看时很大很难,但分解成若干个小部分后就简单了。大家可以选购套餐,整体便宜,也可以用到什么买什么,不浪费。基础实验打牢地基后,复杂应用也没多复杂了,这里我像搭积木一样,一个功能一个功能的实现智能小车的构建,首先本章实现对四个轮子的初步控制。

  如果对电机驱动模块一点都不清楚的,建议先看另外一篇基础文章,请参考树莓派基础实验34:L298N模块驱动直流电机实验。

  以后也是,复杂内容的基础版本会在文集:树莓派基础实验当中讲解。

二、组件

★Raspberry Pi 3主板*1

★树莓派电源*1

★40P软排线*1

★L298N扩展板模块*1

★智能小车底板模块*1

★减速电机和车轮*4

★面包板*1

★跳线若干

三、实验原理

小车底盘俯视图

车底图

L298N驱动扩展板

L298N内部等效图

(一)车身及小零件

车身及零件可以自己DIY,但我觉得重点在后面编程当中,淘宝上买一个直接用更好,好的车身底盘可以匹配好多种板子,螺丝孔也很多,方便美观。

(二)L298N驱动扩展板

L298N是ST公司生产的一种高电压、大电流电机驱动芯片。该芯片采用15脚封装,主要特点是:工作电压高,最高工作电压可达46V;输出电流大,瞬间峰值电流可达3A,持续工作电流为2A;额定功率25W。

内含两个H桥的高电压大电流全桥式驱动器,可以用来驱动直流电动机和步进电动机、继电器线圈等感性负载;采用标准逻辑电平信号控制;具有两个使能控制端,在不受输入信号影响的情况下允许或禁止器件工作有一个逻辑电源输入端,使内部逻辑电路部分在低电压下工作;可以外接检测电阻,将变化量反馈给控制电路。

使用L298N芯片驱动电机,该芯片可以驱动一台两相步进电机或四相步进电机,也可以驱动两台直流电机,并联时可以驱动四台电机。

L298N特点:

• 1、具有信号指示。

• 2、转速可调

• 3、抗干扰能力强

• 4、具有过电压和过电流保护

• 5、可单独控制两台直流电机

• 6、可单独控制一台步进电机

• 7、PWM脉宽平滑调速

• 8、可实现正反转

直流电机的控制实例:

使用直流/步进两用驱动器可以驱动两台直流电机。分别为M1和M2。引脚A,B可用于输入PWM脉宽调制信号对电机进行调速控制。(如果无须调速可将两引脚接5V,使电机工作在最高速状态,既将短接帽短接)

实现电机正反转就更容易了,输入信号端IN1接高电平,输入端IN2接低电平,电机M1正转。(如果信号端IN1接低电平, IN2接高电平,电机M1反转。)控制另一台电机是同样的方式,输入信号端IN3接高电平,输入端IN4接低电平,电机M2正转。(反之则反转),PWM信号端A控制M1调速,PWM信号端B控制M2调速。

这里的L298N驱动扩展板实际上在L298N的基础上扩展了很多其它传感器,是一个多功能的智能小车扩展板。

多功能L298N智能小车扩展板

本章只实验能否成功驱动四轮旋转,其它的接口和功能以后的章节再使用。

关于L298N驱动电机的更基础、更详细的内容,请参考树莓派基础实验34:L298N模块驱动直流电机实验。

四、实验步骤

第1步: 连接电路。

树莓派(name)

树莓派(BOARD)

L298N小车扩展板

GPIO.0

11

ENA

GPIO.2

13

IN1

GPIO.3

15

IN2

GPIO.1

12

ENB

GPIO.4

16

IN3

GPIO.5

18

IN4

GND

GND

电池组供电负极

关于这里树莓派GND、L298N小车扩展板的电池组供电负极相连,是特殊情况下的情况,经测试发现: 如果树莓派用的是充电头供电,而L298N扩展板用的是电池组供电,这两个负极必须相连,否则马达不动。 如果树莓派用的是L298N扩展板接出来的5V供电,即两者同一个电源,则这里不用连接。

L298N小车扩展板

电池组

树莓派

电压表头

马达

电池 (-)

电池 (-)

5V供电

电源接口

(-)

(-)

T1(L后)

(-)

T2(L前)

(-)

T3(R前)

(-)

T4(R后)

(-)

刚开始时使用了面包板接线,GPIO使用的BCM模式,后来为了方便路面移动测试,让树莓派使用了多功能L298N智能小车扩展板上的5V供电,并且GPIO改用了BOARD模式。

智能小车四轮驱动电路图

面包板接法

扩展板供电接法1

扩展板供电接法2

第2步: 编写程序。本次编程创建了一个树莓派小车的类,便于后期多模块编程调用。关于L298N模块更基础的编程内容可以参考树莓派基础实验34:L298N模块驱动直流电机实验。这里与基础实验不同的是要控制4个电机,而L298N模块只能驱动2路直流电机,所以小车里的左边两个车轮是并联的,由1路同时控制,右边亦然。

  所以该车的行进控制与履带车的行进控制类似:

前进和后退很简单,左右两边的方向都朝前或朝后,速度一致; 原地顺时针旋转时,左边轮子前进,右边轮子后退,速度一致; 原地逆时针旋转时,左边轮子后退,右边轮子前进,速度一致; 偏左前进时,左右两边的方向都朝前,左轮速度比右轮速度慢一点; 偏右前进时,左右两边的方向都朝前,左轮速度比右轮速度快一点; 偏左后退时,左右两边的方向都朝后,左轮速度比右轮速度慢一点; 偏右后退时,左右两边的方向都朝后,左轮速度比右轮速度快一点;

代码语言:txt复制
#!/usr/bin/env python
import RPi.GPIO as GPIO
import time

class SMPcar:
    '''控制小车四轮动作的类'''
    ENA = 11  #使能信号A,左边两轮
    IN1 = 13  #信号输入1
    IN2 = 15  #信号输入2
    ENB = 12  #使能信号B,右边两轮
    IN3 = 16  #信号输入3
    IN4 = 18  #信号输入4

    GPIO.setwarnings(False) #关闭警告

    def setGPIO(self):
        '''初始化引脚'''
        GPIO.setmode(GPIO.BOARD)
        GPIO.setup(SMPcar.ENA, GPIO.OUT)
        GPIO.setup(SMPcar.IN1, GPIO.OUT)
        GPIO.setup(SMPcar.IN2, GPIO.OUT)
        
        GPIO.setup(SMPcar.ENB, GPIO.OUT)
        GPIO.setup(SMPcar.IN3, GPIO.OUT)
        GPIO.setup(SMPcar.IN4, GPIO.OUT)
    
    def pwm(self,pwm): 
        '''初始化PWM(脉宽调制),返回PWM对象'''
        EN_pwm = GPIO.PWM(pwm, 500)
        EN_pwm.start(0)
        return EN_pwm

    def changespeed(self,pwm,speed):
        '''通过脉宽调制改变占空比改变马达转速'''
        pwm.ChangeDutyCycle(speed)
    
    def clockwise(self,in1_pin,in2_pin):
        '''马达顺时针转的信号
      若电机旋转方向不正确,交换电机的正负极'''
        GPIO.output(in1_pin, 1)
        GPIO.output(in2_pin, 0)
 
    def counter_clockwise(self,in1_pin,in2_pin):
        '''马达逆时针转的信号'''
        GPIO.output(in1_pin, 0)
        GPIO.output(in2_pin, 1)
    
    def stop_car(self,in1_pin,in2_pin):
        '''马达制动的信号
       使能信号为低电平,或者高电平(占空比设为100,
       IN1和IN2都为0或1时)马达制动'''
        GPIO.output(in1_pin, 0)
        GPIO.output(in2_pin, 0)
     
        
    def destroy(self,A,B):
        '''结束程序时清空GPIO状态,
        若不清空状态,再次运行时会有警告'''
        A.stop()
        B.stop()
        GPIO.cleanup()    # Release resource


if __name__ == '__main__':     # Program start from here

    try:
        smpcar = SMPcar() #创建树莓派小车对象
        smpcar.setGPIO()  #初始化引脚

        ENA_pwm=smpcar.pwm(smpcar.ENA) #初始化使能信号PWM,ENA为左边车轮
        ENB_pwm=smpcar.pwm(smpcar.ENB) #初始化使能信号PWM,ENB为右边车轮
        
        while True:
            '''通过输入的命令改变马达转动
这里是考虑到后期,远程控制也是发送控制代码实现控制,
这里采用这种方式也很方便'''
            cmd = input("Command, E.g. ff30ff30 :")
            direction = cmd[0] #只输入字母b时,小车刹车
            A_direction = cmd[0:2] #字符串0/1两位为控制A(左边车轮)方向信号
            B_direction = cmd[4:6] #4/5位为控制B(右边车轮)方向信号
        
            A_speed = cmd[2:4] #字符串2/3两位为控制A(左边车轮占空比)速度信号
            B_speed = cmd[6:8] #字符串6/7两位为控制B(右边车轮占空比)速度信号
            print (A_direction,B_direction,A_speed,B_speed) #测试用
        
            if A_direction == "ff": #控制A(左边车轮)顺时针信号
                smpcar.clockwise(smpcar.IN1,smpcar.IN2)
            if A_direction == "00": #控制A(左边车轮)逆时针信号
                smpcar.counter_clockwise(smpcar.IN1,smpcar.IN2)
            if B_direction == "ff": #控制B(右边车轮)顺时针信号
                smpcar.clockwise(smpcar.IN3,smpcar.IN4)
            if B_direction == "00": #控制B(右边车轮)逆时针信号
                smpcar.counter_clockwise(smpcar.IN3,smpcar.IN4)

            if direction == "b": #小车刹车,IN1和IN2都为0,马达制动
                smpcar.stop_car(smpcar.IN1,smpcar.IN2)
                smpcar.stop_car(smpcar.IN3,smpcar.IN4)
                continue #跳出本次循环

            # 通过输入的两位数字设置占空比,改变马达转速
            smpcar.changespeed(ENA_pwm,int(A_speed))
            smpcar.changespeed(ENB_pwm,int(B_speed))

    except KeyboardInterrupt:  # When 'Ctrl C' is pressed, the child program destroy() will be  executed.
        smpcar.destroy(ENA_pwm,ENB_pwm)
    finally:
        smpcar.destroy(ENA_pwm,ENB_pwm)

下一章会实现本地的图形界面控制。

  实验结果示例:

实验结果实验结果

这个项目的代码90%是我原创瞎写的,有需要参考的同学可以下载:

树莓派智能小车项目python源代码下载

0 人点赞