编写小车控制程序

小车控制程序主要分为两部分,小车控制程序和远程遥控程序。小车控制程序用来控制前进、后退、左传弯、右转弯、停止等动作。而远程遥控程序用来遥控小车,可以在电脑端控制,但是不太方便。还有一种选择是可以通过手机遥控小车,可以通过蓝牙通信实现。如果你看到了源代码,就会发现小车程序非常简单易懂。

下面先介绍小车控制部分,还记得上一节介绍的如何通过树莓派GPIO输出信号控制控制小车运动方式吗?

GPIO 13/15 GPIO 31 GPIO 33 GPIO 35 GPIO 37 小车运动方式
高电平 高电平 低电平 高电平 低电平 前进
高电平 低电平 高电平 低电平 高电平 后退
高电平 低电平 高电平 高电平 低电平 左转
高电平 高电平 低电平 低电平 高电平 右转
低电平 - - - - 停止

通过给GPIO 13, 15输出高电平,配合GPIO 31、33、35、 37端口高或低电平,可以控制小车运动起来。通过给GPIO 13、15输出低电平,可以让小车停下来。小车的速度是通过频率和占空比2个参数控制的,其中频率是指高电平脉冲波动的频率,占空比是指一个波动周期中高电平的时长占比。

如下图所示,3.3V是高电平,0V是低电平,图中3个高电平脉冲频率是一样的,占空比第一个最小,第三个最大。不能理解输出的高电平脉冲,频率越高、占空比越大,则小车动力动力越大,跑得也越快。

pwm

但是这两个参数的值都要设定在合理范围内,超过合理范围是不生效的。占空比因为是百分比,所以范围是[0.0, 100.0],频率值可以在具体调试过程中,找到相对比较合理的范围值。下面给出小车控制程序。

import time
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BOARD) # 设置针脚编号模式为1~40顺序编号
GPIO.setwarnings(False) 

########电机驱动接口定义#################
ENA = 13    # L298使能A
ENB = 15    # L298使能B
IN1 = 31    # 电机接口1
IN2 = 33    # 电机接口2
IN3 = 35    # 电机接口3
IN4 = 37    # 电机接口4

frequency = 30 # 高电平脉冲频率
dc = 50 # 占空比,高电平时间占比

#########电机初始化为LOW#################
GPIO.setup(ENA, GPIO.OUT, initial=GPIO.LOW)
ENA_pwm = GPIO.PWM(ENA, frequency)
ENA_pwm.start(0)
ENA_pwm.ChangeDutyCycle(dc)
GPIO.setup(IN1, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(IN2, GPIO.OUT, initial=GPIO.LOW)

GPIO.setup(ENB, GPIO.OUT, initial=GPIO.LOW)
ENB_pwm = GPIO.PWM(ENB, frequency)
ENB_pwm.start(0)
ENB_pwm.ChangeDutyCycle(dc)
GPIO.setup(IN3, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(IN4, GPIO.OUT, initial=GPIO.LOW)

def Motor_Forward():
    print( 'motor forward' )
    GPIO.output(ENA, True)
    GPIO.output(ENB, True)
    GPIO.output(IN1, False)
    GPIO.output(IN2, True)
    GPIO.output(IN3, False)
    GPIO.output(IN4, True)

def Motor_Backward():
    print( 'motor_backward' )
    GPIO.output(ENA, True)
    GPIO.output(ENB, True)
    GPIO.output(IN1, True)
    GPIO.output(IN2, False)
    GPIO.output(IN3, True)
    GPIO.output(IN4, False)

def Motor_TurnLeft():
    print( 'motor_turnleft' )
    GPIO.output(ENA, True)
    GPIO.output(ENB, True)
    GPIO.output(IN1, True)
    GPIO.output(IN2, False)
    GPIO.output(IN3, False)
    GPIO.output(IN4, True)

def Motor_TurnRight():
    print( 'motor_turnright' )
    GPIO.output(ENA, True)
    GPIO.output(ENB, True)
    GPIO.output(IN1, False)
    GPIO.output(IN2, True)
    GPIO.output(IN3, True)
    GPIO.output(IN4, False)

def Motor_Stop():
    print( 'motor_stop' )
    GPIO.output(ENA, False)
    GPIO.output(ENB, False)
    GPIO.output(IN1, False)
    GPIO.output(IN2, False)
    GPIO.output(IN3, False)
    GPIO.output(IN4, False)

程序整体逻辑非常简洁易懂,可以参考注释。然后现在安装下树莓派蓝牙相关软件。

sudo apt-get install pi-bluetooth bluez bluez-firmware blueman
sudo apt-get install libbluetooth-dev
sudo reboot
pip install pybluez

查看下蓝牙服务是否正常。

systemctl status bluetooth

修改下面的配置

sudo vi /lib/systemd/system/bluetooth.service

ExecStart=/usr/lib/bluetooth/bluetoothd

改为

ExecStart=/usr/lib/bluetooth/bluetoothd -C

刚刚修改的地方下面增加一行

ExecStartPost=/usr/bin/sdptool add SP

重启蓝牙服务

sudo systemctl daemon-reload
sudo systemctl restart bluetooth

使树莓派蓝牙可被手机扫描到

sudo hciconfig hci0 piscan

接下来编写小车蓝牙通信代码,这样就可以通过手机蓝牙和小车配对,并连接上小车进行操控,下面给出相关代码。

import bluetooth
##########蓝牙连接接收命令##################
server_sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM )

port = 1
server_sock.bind(('', port))
server_sock.listen(1)

# 只有一个客户端可以连接上,并控制小车
# 小车进程不会退出,直到主动kill进程
while True:

    print('ready accept connection...')

    # 接受客户端连接
    client_sock, address = server_sock.accept()
    print('Accepted connection from ', address)

    while True:
        try:
            # 读取命令字符
            action = int ( client_sock.recv(1024) )
            print('received action [%s]' % action)

            # 控制小车执行命令
            if action == 1:       # 前进
                Motor_Forward()
            elif action == 2:     # 后退
                Motor_Backward()
            elif action == 3:     # 左转
                Motor_TurnLeft()
                time.sleep(0.05)
                Motor_Stop()
            elif action == 4:     # 右转
                Motor_TurnRight()
                time.sleep(0.05)
                Motor_Stop()
            elif action == 5:     # 停止
                Motor_Stop()
            elif action == 6:     # clockwise circle
                Motor_TurnRight()
            elif action == 7:     # anti-clockwise circle
                Motor_TurnLeft()
            else:                 # 未知命令,小车停止
                Motor_Stop()
        except:

            # 遇到意外,小车停止,断开蓝牙连接
            print('except...')
            Motor_Stop()
            break

        #finally:

    # 断开客户端连接
    client_sock.close()
    print('close connection from ', address)

蓝牙通信暂时采用的是经典蓝牙RFCOMM协议,目前来说足够用了。找个Android手机和小车进行蓝牙配对,然后在Android手机上装个蓝牙串口App,就可以连接上小车进行远程遥控了。通过手机端蓝牙串口发送相应指令(上面代码指令为数字1~7,命令可以自定义),小车控制程序接收到就会执行相应指令控制小车运动。

小车控制代码部署到小车上面,就可以调试小车功能了,调整完毕后可以让小车控制程序开机自启动,这样打开小车后,手机就可以连接上来进行遥控了。

ssh登录上小车,输入

$crontab -e

添加下面一行,退出保存,重启树莓派

@reboot cd /home/pi/pywork/works/car; python3 car.py &

OK,现在小车控制程序已经调试并部署完成了,给小车锂电池组和充电宝充好点,带上小车到附近广场测试一番吧!