树莓派遥控视频小车(附代码)

树莓派遥控视频小车

实现功能

基于树莓派3B+的视频车:可遥控,显示小车两*度舵机支架上的摄像头视频。
1.  启动小车程序
2. 小车控制线程和摄像头线程运行
3.  使用遥控器可遥控小车行走,并控制两*度的摄像头舵机支架调整摄像头视野

树莓派遥控视频小车(附代码)

硬件材料

  1. 树莓派3B+
  2. 32G及以上TF卡
  3. PS2手柄
  4. 12V(或其他)电池
  5. L298N电机驱动模块
  6. 稳压模块(12V/或其他 转 5V)用于树莓派供电及舵机供电
  7. 小车底盘(带舵机、电机的方便些)
  8. 树莓派CSI摄像头
  9. 其他(舵机支架、开关等)

控制程序

PS2手柄驱动程序

PS2手柄实现功能如图:
树莓派遥控视频小车(附代码)

import RPi.GPIO as GPIO
import time
import spidev#linux环境下用于spi通讯
import io
import cv2
import os
os.environ['SDL_VIDEODRIVE'] = 'x11'
from time import ctime,sleep,time

#手柄按键定义
PSB_SELECT = 1
PSB_L3 =  2
PSB_R3 =  3
PSB_START = 4
PSB_PAD_UP = 5
PSB_PAD_RIGHT = 6
PSB_PAD_DOWN  = 7
PSB_PAD_LEFT  = 8
PSB_L2 = 9
PSB_R2 = 10
PSB_L1 = 11
PSB_R1 = 12
PSB_TRIANGLE = 13
PSB_CIRCLE = 14
PSB_CROSS  = 15
PSB_SQUARE = 16

#摇杆的数据
PSS_RX = 5    #右边摇杆X轴数据
PSS_RY = 6    #右边摇杆Y轴数据
PSS_LX = 7    #左边摇杆X轴数据
PSS_LY = 8    #右边摇杆Y轴数据

#PS2引脚设置,接树莓派引脚
PS2_DAT_PIN = 10 #接MOS
PS2_CMD_PIN = 9  #接MIS
PS2_SEL_PIN = 25 #接CS  
PS2_CLK_PIN = 11 #接SCK

global Handkey
scan=[0x01,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
Data=[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
MASK = [PSB_SELECT,PSB_L3,PSB_R3,PSB_START,PSB_PAD_UP,PSB_PAD_RIGHT,PSB_PAD_DOWN,PSB_PAD_LEFT,PSB_L2,PSB_R2,PSB_L1,PSB_R1,PSB_TRIANGLE,PSB_CIRCLE,PSB_CROSS,PSB_SQUARE]

#设置GPIO口为BCM编码方式
GPIO.setmode(GPIO.BCM)
#忽略警告信息
GPIO.setwarnings(False)

#spi初始化 
def spi_init():
    spi = spidev.SpiDev()
    spi.open(0,0)
    GPIO.setup(PS2_CMD_PIN,GPIO.OUT,initial=GPIO.HIGH)
    GPIO.setup(PS2_CLK_PIN,GPIO.OUT,initial=GPIO.HIGH)
    GPIO.setup(PS2_DAT_PIN, GPIO.IN)
    GPIO.setup(PS2_SEL_PIN,GPIO.OUT,initial=GPIO.HIGH)
    
#读取PS2摇杆的模拟值
def PS2_AnologaData(button):
    return Data[button] 
    
#清空接受PS2的数据
def PS2_ClearData():
    Data[:]=[]
    
#读取PS2的数据
def PS2_ReadData(command):
    res = 0
    j = 1 
    i = 0
    for i in range(8):
        if command & 0x01:
            GPIO.output(PS2_CMD_PIN, GPIO.HIGH)
        else:
            GPIO.output(PS2_CMD_PIN, GPIO.LOW)
        command = command >> 1
        sleep(0.000008)
        GPIO.output(PS2_CLK_PIN, GPIO.LOW)
        sleep(0.000008)
        if GPIO.input(PS2_DAT_PIN):
            res = res + j
        j = j << 1
        GPIO.output(PS2_CLK_PIN, GPIO.HIGH)
        sleep(0.000008)
    GPIO.output(PS2_CMD_PIN, GPIO.HIGH)
    sleep(0.00004)
    return res
    
#PS2获取按键类型
def PS2_Datakey():
    global Data
    global scan
    index = 0
    i = 0
    PS2_ClearData()
    GPIO.output(PS2_SEL_PIN, GPIO.LOW)
    for i in range(9):
        Data.append( PS2_ReadData(scan[i]))
    GPIO.output(PS2_SEL_PIN, GPIO.HIGH)
    
    Handkey = (Data[4] << 8) | Data[3]
    for index in range(16):
        if Handkey & (1 << (MASK[index] - 1)) == 0:
            return index+1
    return 0

运动控制程序

接线图如下:
树莓派遥控视频小车(附代码)

#初始化就GPIO口
def init():
    #直流电机pwm
    global pwm_ENA
    #转向舵机pwm
    global pwm_servo
    #舵机支架pwm
    global p1
    global p2
    GPIO.setup(ENA,GPIO.OUT,initial=GPIO.HIGH)
    GPIO.setup(IN1,GPIO.OUT,initial=GPIO.LOW)
    GPIO.setup(IN2,GPIO.OUT,initial=GPIO.LOW)
    GPIO.setup(ServoPin, GPIO.OUT)
    GPIO.setup(cmotor1,GPIO.OUT)
    GPIO.setup(cmotor2,GPIO.OUT)
    pwm_ENA = GPIO.PWM(ENA, 100)
    p1=GPIO.PWM(cmotor1,50)
    p2=GPIO.PWM(cmotor2,50)
    pwm_servo = GPIO.PWM(ServoPin, 50)
    pwm_servo.start(0)
    p1.start(0)
    p2.start(0)
    pwm_ENA.start(0)

#摄像头显示视频线程
def pi_capture():
    global is_capture_running
    print("Start capture") 
    cap = cv2.VideoCapture(0)
    is_capture_running = True
    while is_capture_running:
        ret,frame = cap.read()
        cv2.imshow("img",frame)
        if cv2.waitKey(1) & 0xFF == ord("q"):
            break
    is_capture_running = False
    
def run():
    GPIO.output(IN1, GPIO.HIGH)
    GPIO.output(IN2, GPIO.LOW)
    pwm_ENA.ChangeDutyCycle(CarSpeedControl)
    pwm_servo.ChangeDutyCycle(2.5+10*138/180)
    time.sleep(0.02)
    pwm_servo.ChangeDutyCycle(0)
#小车后退
def back():
    GPIO.output(IN1, GPIO.LOW)
    GPIO.output(IN2, GPIO.HIGH)
    pwm_ENA.ChangeDutyCycle(CarSpeedControl)
    pwm_servo.ChangeDutyCycle(2.5+10*138/180)
    time.sleep(0.02)
    pwm_servo.ChangeDutyCycle(0)

#小车左转   
def left():
    GPIO.output(IN1, GPIO.HIGH)
    GPIO.output(IN2, GPIO.LOW)
    pwm_ENA.ChangeDutyCycle(CarSpeedControl)
    pwm_servo.ChangeDutyCycle(2.5+10*96/180)
    time.sleep(0.02)
    pwm_servo.ChangeDutyCycle(0)

#小车右转
def right():
    GPIO.output(IN1, GPIO.HIGH)
    GPIO.output(IN2, GPIO.LOW)
    pwm_ENA.ChangeDutyCycle(CarSpeedControl)
    pwm_servo.ChangeDutyCycle(2.5+10*180/180)
    time.sleep(0.02)
    pwm_servo.ChangeDutyCycle(0)
   #小车沿左后方后退
def downleft():
    GPIO.output(IN1, GPIO.LOW)
    GPIO.output(IN2, GPIO.HIGH)
    pwm_ENA.ChangeDutyCycle(CarSpeedControl)
    pwm_servo.ChangeDutyCycle(2.5+10*96/180)
    time.sleep(0.02)
    pwm_servo.ChangeDutyCycle(0)
#小车沿右下方后退
def downright():
    GPIO.output(IN1, GPIO.LOW)
    GPIO.output(IN2, GPIO.HIGH)
    pwm_ENA.ChangeDutyCycle(CarSpeedControl)
    pwm_servo.ChangeDutyCycle(2.5+10*180/180)
    time.sleep(0.02)
    pwm_servo.ChangeDutyCycle(0)
    
#小车停止   
def brake():
   GPIO.output(IN1, GPIO.LOW)
   GPIO.output(IN2, GPIO.LOW)
   pwm_ENA.ChangeDutyCycle(0)
   pwm_servo.ChangeDutyCycle(2.5+10*138/180)
   time.sleep(0.02)
   pwm_servo.ChangeDutyCycle(0)
def cmotor11():
    p1.ChangeDutyCycle(2.5+10*angle1/180)
    time.sleep(0.02)
    p1.ChangeDutyCycle(0)
def cmotor22():
    p2.ChangeDutyCycle(2.5+10*angle2/180)
    time.sleep(0.02)
    #p2.ChangeDutyCycle(0)
def control():
    global CarSpeedControl,angle1,angle2
    global PS2_KEY
    global CarSpeedControl
    print("Start control!")
    try:
        init()
        ps.spi_init()
        while True:
            PS2_KEY = ps.PS2_Datakey()
            print('state is:',PS2_KEY)
            #PSB_SELECT键按下
            if PS2_KEY == PSB_SELECT:
                print ("PSB_SELECT")
            #PSB_R3键按下,舵机归位
            elif PS2_KEY == PSB_R3:
                print ("PSB_R3")
            #PSB_START键按下
            elif PS2_KEY == PSB_START:
                print ("PSB_START")
                #g_Carstate=enDOWNRIGHT
            #PSB_PAD_UP键按下,小车前进
            elif PS2_KEY == PSB_PAD_UP:
                g_Carstate = enRUN
                print ("PSB_PAD_UP")
            #PSB_PAD_RIGHT键按下,小车右转
            elif PS2_KEY == PSB_PAD_RIGHT:
                g_Carstate = enRIGHT
                print ("PSB_PAD_RIGHT") 
     
            #PSB_PAD_DOWN键按下,小车后退
            elif PS2_KEY == PSB_PAD_DOWN:
                g_Carstate = enBACK
                print ("PSB_PAD_DOWN")
            #PSB_PAD_LEFT键按下,小车左转
            elif PS2_KEY == PSB_PAD_LEFT:
                g_Carstate = enLEFT
                print ("PSB_PAD_LEFT")             
            #L2键按下,小车每次加速
            elif PS2_KEY == PSB_L2:
                print ("PSB_L2_SPEED+")
                CarSpeedControl += 10
                if CarSpeedControl > 100:
                    CarSpeedControl = 100
            #R2键按下,小车每次减速
            elif PS2_KEY == PSB_R2:
                print ("PSB_R2_SPEED-")
                CarSpeedControl -= 10
                if CarSpeedControl < 0:
                    CarSpeedControl = 0
            #L1键按下
            elif PS2_KEY == PSB_L1:
                g_Carstate=enDOWNRIGHT
                print ("PSB_L1")
                
                #downright()
            #R1键按下
            elif PS2_KEY == PSB_R1:
                g_Carstate=enDOWNLEFT
                print ("PSB_R1")
                
                #downleft()
            #按下按键或右摇杆控制摄像头舵机支架调整视野
            elif PS2_KEY ==PSB_TRIANGLE:
                print('camera_down')
                angle1+=10
                if angle1>180:
                    angle1=180
                cmotor11()
            elif PS2_KEY ==PSB_CROSS:
                print('camera_up')
                angle1-=10
                if angle1<0:
                    angle1=0
                cmotor11()
            elif PS2_KEY ==PSB_SQUARE:
                print('camera_left')
                angle2+=10
                if angle2>180:
                    angle2=180
                cmotor22()
            elif PS2_KEY ==PSB_CIRCLE:
                print('camera_right')
                angle2-=10
                if angle2<-0:
                    angle2=-0
                cmotor22()
            
            else:
                g_Carstate = enSTOP

            time.sleep(0.2)
    except KeyboardInterrupt:
        pass

源码链接

完整代码链接: 源码Gitee.

扩展功能

去年用这个底盘玩了一下Github上的深度学习视觉巡线小车项目,已经试过可以用这个树莓派小车可以跑起来,挺有意思的各位有兴趣可以参考一下,附上大佬的项目地址:链接: link

上一篇:linux合并bilibili下载的blv视频


下一篇:简单JS倒计时