【实验】树莓派小车

树莓派小车实验报告
1 小车构造及环境配置
1.1 硬件搭建
- 
树莓派3B

 - 
两个PWM电机
 - 
两个红外传感器
 - 
一个超声波传感器

 - 
一个单目摄像头
 
1.2 系统烧录
- 使用
树莓派镜像烧录器
 
下载直达        https://downloads.raspberrypi.org/imager/imager_latest.exe
 优点:
- 可以直接在设置中配置网络环境
 - 可以选择多种操作系统
 
- 
操作步骤:
- 
下载镜像https://downloads.raspberrypi.org/raspios_arm64/images/raspios_arm64-2022-09-26/2022-09-22-raspios-bullseye-arm64.img.xz
 - 
选择自定义镜像

 - 
设置ssh和wifi
 
 - 
 
1.3 raspberry PI环境搭配
- 
首先对树莓派进行换源
* pi@raspberrypi:~ $ sudo nano /etc/apt/sources.list deb https://mirror.nju.edu.cn/debian/ bullseye main contrib non-free deb https://mirror.nju.edu.cn/debian-security/ bullseye-security main contrib non-free deb https://mirror.nju.edu.cn/debian bullseye-updates main contrib non-free * pi@raspberrypi:~ $ sudo nano /etc/apt/sources.list.d/raspi.list deb https://mirror.nju.edu.cn/raspberrypi/debian/ bullseye main - 
更新
sudo apt-get update sudo apt-get upgrade - 
安装OPENCV
sudo apt-get install python3-opencv - 
配置摄像头选项
sudo raspi-config找到Interface Options --> Camera -->打开摄像头YES
(可以在终端中查看device0是否存在)
 
1.4 PC端配置
- VS code连接Raspberry Pi

 
 配置SSH文件
#Read more about SSH config files: https://linux.die.net/man/5/ssh_config
Host copy								# PC名称,随便起
    HostName 192.168.43.162				# 树莓派地址,可以使用IP Scanner查看
    User pi								# 树莓派名称,在烧录SD卡的时候配置
    Port 22								# 默认22
几点注意事项:
HostName可以使用IP Scanner,如果是连接安卓手机可以通过手机热点直接查看,苹果手机不管是IP Scanner还是手机热点都看不了
改这个SSH会造成连不上GitHub的情况,如果想要重新连接GitHub,必须将上面注释,该车下面
Host github.com Hostname ssh.github.com Port 443
- 
下载VNC Viewer
连接方式也是通过SSH连接到小车地址
 
1.5 引脚分配

# 设置gpio口为BOARD编号规范
gpio.setmode(gpio.BOARD)
# 定义引脚
#	电机
pin1 = 12  # 左正
pin2 = 16  # 左反
pin3 = 18  # 右正
pin4 = 22  # 右反
ENA = 38   # 左边电机使能
ENB = 40   # 右边电机使能
#	超声波
TRIG = 13  # send-pin
ECHO = 15  # receive-pin
#	红外线
GPIO_Infrared_left = 29		# 左边红外线
GPIO_Infrared_right = 31	# 右边红外线
2 八字循迹
1.1 电机控制
def car_forward():  # 定义前进函数
    gpio.output(pin1, gpio.HIGH)  # 将pin1接口设置为高电压
    gpio.output(pin2, gpio.LOW)  # 将pin2接口设置为低电压
    gpio.output(pin3, gpio.HIGH)  # 将pin3接口设置为高电压
    gpio.output(pin4, gpio.LOW)  # 将pin4接口设置为低电压
def car_back():  # 定义后退函数
    gpio.output(pin1, gpio.LOW)
    gpio.output(pin2, gpio.HIGH)
    gpio.output(pin3, gpio.LOW)
    gpio.output(pin4, gpio.HIGH)
def car_left():  # 定义左转函数
    gpio.output(pin1, gpio.LOW)
    gpio.output(pin2, gpio.HIGH)
    gpio.output(pin3, gpio.HIGH)
    gpio.output(pin4, gpio.LOW)
def car_right():  # 定义右转函数
    gpio.output(pin1, gpio.HIGH)
    gpio.output(pin2, gpio.LOW)
    gpio.output(pin3, gpio.LOW)
    gpio.output(pin4, gpio.HIGH)
def car_stop():  # 定义停止函数
    gpio.output(pin1, gpio.LOW)
    gpio.output(pin2, gpio.LOW)
    gpio.output(pin3, gpio.LOW)
    gpio.output(pin4, gpio.LOW)
1.2 图像捕捉与处理
1.2.1 摄像头处理
# 打开摄像头,图像尺寸640*480(长*高)
cap = cv2.VideoCapture(0)
# 设置捕捉到的图像为480*640
cap.set(3, 640)
cap.set(4, 480)
1.2.2 图像处理
import time
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
cap.set(3, 640)
cap.set(4, 480)
while (1):
    ret, frame = cap.read()
    cv2.imshow('frame', dst)  # 展示每一帧
    # 转化为灰度图
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    cv2.imshow('gray', gray)  # 展示灰度图
    # 大津法二值化
    retval, dst = cv2.threshold(gray, 100, 255, cv2.THRESH_OTSU)
    # 膨胀,白区域变大
    dst = cv2.dilate(dst, None, iterations=2)
    cv2.imshow('dilate_frame', dst)  # 展示每一帧
    # 腐蚀,白区域变小
    dst = cv2.erode(dst, None, iterations=6)
    cv2.imshow('erode_frame', dst)  # 展示每一帧
    # 找到连续白色像素点最宽的那条
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
# 释放清理
cap.release()
cv2.destroyAllWindows()
代码讲解
ret, frame = cap.read() cv2.imshow('frame', dst)![]()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) cv2.imshow('gray', gray) # 展示灰度图![]()
这里我们先是将图像进行二值化
retval, dst = cv2.threshold(gray, 100, 255, cv2.THRESH_OTSU)这个阈值取决于环境
# 膨胀,白区域变大 dst = cv2.dilate(dst, None, iterations=2) cv2.imshow('dilate_frame', dst) # 展示每一帧![]()
如果只对图像进行膨胀则在边界处提取不够明显!!
# 腐蚀,白区域变小 dst = cv2.erode(dst, None, iterations=6) cv2.imshow('erode_frame', dst) # 展示每一帧![]()
如果只对图像进行腐蚀则图像特征不明显!!!
# 膨胀,白区域变大 dst = cv2.dilate(dst, None, iterations=2) cv2.imshow('dilate_frame', dst) # 展示每一帧 # 腐蚀,白区域变小 dst = cv2.erode(dst, None, iterations=6) cv2.imshow('erode_frame', dst) # 展示每一帧![]()
1.2.3 结果展示
此处推荐先对图像进行高斯滤波

1.3 循迹策略
寻找第400行像素,找到最长的一段白色像素集合作为赛道,寻找赛道中点与320作为比较进行左右判断
# 单看第400行的像素值
# print(dst.shape)
color = dst[400]
# 找到连续白色像素点最宽的那条
road_set = []
road_set_length = []
road = []
for i in range(len(color)):
    if (i == 639):
        road_set.append(road)
        road_set_length.append(len(road))
        break
    if color[i] == 255 and color[i + 1] == 255:
        road.append(i)
    elif (len(road) > 20 and color[i + 1] != 255):
        road_set.append(road)
        road_set_length.append(len(road))
        road = []
if (len(road_set_length) == 0):
    center = 320
elif (len(road) == 0):
    center = 320
else:
    index_ = road_set_length.index(max(road_set_length))
    road = road_set[index_]
    center = (min(road) + max(road)) / 2
# 计算出center与标准中心点的偏移量
# 如果为正,应该左转
direction = center - 320
print(direction)
threshold = 90                  #右转阈值
threshold_neg = -40      		#左转阈值
if abs(direction) >= threshold:
    # 右转
    if direction > threshold:
        car_forward()
        pwm1.ChangeDutyCycle(25 + direction / 18)
        pwm2.ChangeDutyCycle(0)
        if(direction>120 and direction <150):
            time.sleep(0.3)
        elif(direction >= 150):
            time.sleep(0.5)
                # 左转
    elif direction < threshold_neg:
        car_forward()
        pwm1.ChangeDutyCycle(0)
        pwm2.ChangeDutyCycle(25 + abs(direction) / 12)
        if(abs(direction)>120 and abs(direction)<150):
            time.sleep(0.3)
        elif(abs(direction)>=150):
            time.sleep(0.5)
else:
    car_forward()
    pwm1.ChangeDutyCycle(20)
    pwm2.ChangeDutyCycle(20)
1.4 结果展示
3 乒乓球跟踪
1.1 图像处理
import cv2
import numpy as np
# https://www.cnblogs.com/bjxqmy/p/12333022.html
# https://blog.csdn.net/weixin_44237705/article/details/109021812
import RPi.GPIO as gpio
import time
# 定义引脚
pin1 = 12  # 左正
pin2 = 16  # 左反
pin3 = 18  # 右正
pin4 = 22  # 右反
ENA = 38
ENB = 40
# 设置gpio口为BOARD编号规范
gpio.setmode(gpio.BOARD)
# 设置gpio口为输出
gpio.setup(pin1, gpio.OUT)
gpio.setup(pin2, gpio.OUT)
gpio.setup(pin3, gpio.OUT)
gpio.setup(pin4, gpio.OUT)
gpio.setup(ENA, gpio.OUT)
gpio.setup(ENB, gpio.OUT)
# 设置PWM波,频率为500Hz
pwm1 = gpio.PWM(ENA, 50)
pwm2 = gpio.PWM(ENB, 50)
pwm1.start(0)
pwm2.start(0)
def car_forward():  # 定义前进函数
    gpio.output(pin1, gpio.HIGH)  # 将pin1接口设置为高电压
    gpio.output(pin2, gpio.LOW)  # 将pin2接口设置为低电压
    gpio.output(pin3, gpio.HIGH)  # 将pin3接口设置为高电压
    gpio.output(pin4, gpio.LOW)  # 将pin4接口设置为低电压
def car_back():  # 定义后退函数
    gpio.output(pin1, gpio.LOW)
    gpio.output(pin2, gpio.HIGH)
    gpio.output(pin3, gpio.LOW)
    gpio.output(pin4, gpio.HIGH)
def car_left():  # 定义左转函数
    gpio.output(pin1, gpio.LOW)
    gpio.output(pin2, gpio.HIGH)
    gpio.output(pin3, gpio.HIGH)
    gpio.output(pin4, gpio.LOW)
def car_right():  # 定义右转函数
    gpio.output(pin1, gpio.HIGH)
    gpio.output(pin2, gpio.LOW)
    gpio.output(pin3, gpio.LOW)
    gpio.output(pin4, gpio.HIGH)
def car_stop():  # 定义停止函数
    gpio.output(pin1, gpio.LOW)
    gpio.output(pin2, gpio.LOW)
    gpio.output(pin3, gpio.LOW)
    gpio.output(pin4, gpio.LOW)
def empty(a):
    pass
def draw_direction(img, lx, ly, nx, ny):
    dx = nx - lx
    dy = ny - ly
    if abs(dx) < 4 and abs(dy) < 4:
        dx = 0
        dy = 0
    else:
        r = (dx ** 2 + dy ** 2) ** 0.5
        dx = int(dx / r * 40)
        dy = int(dy / r * 40)
        # print(dx, dy)
    cv2.arrowedLine(img, (60, 100), (60 + dx, 100 + dy), (0, 255, 0), 2)
    # print(nx-lx, ny-ly)   # 噪声一般为+-1
    # cv2.arrowedLine(img, (150, 150), (150+(nx-lx), 150+(ny-ly)), (0, 0, 255), 2, 0, 0, 0.2)
def Hough_circle(imgGray, canvas):
    # 基于霍夫圆检测找圆,包含了必要的模糊步骤
    # 在imgGray中查找圆,在canvas中绘制结果
    # canvas必须是shape为[x, y, 3]的图片
    global Hough_x, Hough_y
    img = cv2.medianBlur(imgGray, 3)
    img = cv2.GaussianBlur(img, (17, 19), 0)
    # cv2.imshow("Blur", img)
    # cv2.waitKey(30)
    circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1, 200,
                               param1=20, param2=50, minRadius=30, maxRadius=70)
    try:
        # try语法保证在找到圆的前提下才进行绘制
        circles = np.uint16(np.around(circles))
        # print("circ:",circles)
        # 经测试,circles为:[[[c0_x, c0_y, c0_r], [c1_x, c1_y, c1_r], ...]]
        # 所以for i in circles[0, :]:中的i为每一个圆的xy坐标和半径
    except:
        pass
    else:
        for i in circles[0, :]:
            # draw the outer circle
            cv2.circle(canvas, (i[0], i[1]), i[2], (255, 100, 0), 2)
            # draw the center of the circle
            cv2.circle(canvas, (i[0], i[1]), 2, (0, 0, 255), 3)
            Hough_x = i[0]
            Hough_y = i[1]
frameWidth = 640
frameHeight = 480
cap = cv2.VideoCapture(0)  # 0对应笔记本自带摄像头
cap.set(3, frameWidth)  # set中,这里的3,下面的4和10是类似于功能号的东西,数字的值没有实际意义
cap.set(4, frameHeight)
cap.set(10, 80)  # 设置亮度
pulse_ms = 30
standard_area = 7000  # 设置乒乓球的标准大小,如果area大于这个值就要退后,如果小于这个值就前进
# 调试用代码,用来产生控制滑条
# cv2.namedWindow("HSV")
# cv2.resizeWindow("HSV", 640, 300)
# cv2.createTrackbar("HUE Min", "HSV", 4, 179, empty)
# cv2.createTrackbar("SAT Min", "HSV", 180, 255, empty)
# cv2.createTrackbar("VALUE Min", "HSV", 156, 255, empty)
# cv2.createTrackbar("HUE Max", "HSV", 32, 179, empty)
# cv2.createTrackbar("SAT Max", "HSV", 255, 255, empty)
# cv2.createTrackbar("VALUE Max", "HSV", 255, 255, empty)
lower = np.array([4, 180, 156])  # 适用于橙色乒乓球4<=h<=32
upper = np.array([32, 255, 255])
targetPos_x = 0  # 颜色检测得到的x坐标
targetPos_y = 0  # 颜色检测得到的y坐标
lastPos_x = 0  # 上一帧图像颜色检测得到的x坐标
lastPos_y = 0  # 上一帧图像颜色检测得到的y坐标
lastarea = 0
Hough_x = 0  # 霍夫圆检测得到的x坐标
Hough_y = 0  # 霍夫圆检测得到的y坐标
# ColorXs = []        # 这些是用来存储x,y坐标的列表,便于后期写入文件
# ColorYs = []
# HoughXs = []
# HoughYs = []
while True:
    _, img = cap.read()
    # 霍夫圆检测前的处理Start
    b, g, r = cv2.split(img)  # 分离三个颜色
    r = np.int16(r)  # 将红色与蓝色转换为int16,为了后期做差
    b = np.int16(b)
    r_minus_b = r - b  # 红色通道减去蓝色通道,得到r_minus_b
    r_minus_b = (r_minus_b + abs(r_minus_b)) / 2  # r_minus_b中小于0的全部转换为0
    r_minus_b = np.uint8(r_minus_b)  # 将数据类型转换回uint8
    # 霍夫圆检测前的处理End
    imgHough = img.copy()  # 用于绘制识别结果和输出
    imgHsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    imgMask = cv2.inRange(imgHsv, lower, upper)  # 获取遮罩
    imgOutput = cv2.bitwise_and(img, img, mask=imgMask)
    contours, hierarchy = cv2.findContours(imgMask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)  # 查找轮廓
    # https://blog.csdn.net/laobai1015/article/details/76400725
    # CV_RETR_EXTERNAL 只检测最外围轮廓 RETE_FREE
    # CV_CHAIN_APPROX_NONE 保存物体边界上所有连续的轮廓点到contours向量内 CHAIN_APPROX_SIMPLE
    # print(np.array(contours).shape)     #查看提取的轮廓数量
    imgMask = cv2.cvtColor(imgMask, cv2.COLOR_GRAY2BGR)  # 转换后,后期才能够与原画面拼接,否则与原图维数不同
    # 下面的代码查找包围框,并绘制
    x, y, w, h = 0, 0, 0, 0
    for cnt in contours:
        area = cv2.contourArea(cnt)
        if area > 300:
            print("area", area)
            x, y, w, h = cv2.boundingRect(cnt)
            lastarea = area
            lastPos_x = targetPos_x
            lastPos_y = targetPos_y
            targetPos_x = int(x + w / 2)
            targetPos_y = int(y + h / 2)
            print("<targetPos_x,targetPos_y", targetPos_x, targetPos_y)
            cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
            cv2.circle(img, (targetPos_x, targetPos_y), 2, (0, 255, 0), 4)
    # 坐标(图像内的)
    cv2.putText(img, "({:0<2d}, {:0<2d})".format(targetPos_x, targetPos_y), (20, 30),
                cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 2)  # 文字
    draw_direction(img, lastPos_x, lastPos_y, targetPos_x, targetPos_y)
    # 霍夫圆检测Start
    Hough_circle(r_minus_b, imgHough)
    cv2.imshow("R_Minus_B", r_minus_b)
    cv2.putText(imgHough, "({:0<2d}, {:0<2d})".format(Hough_x, Hough_y), (20, 30),
                cv2.FONT_HERSHEY_PLAIN, 1, (255, 100, 0), 2)
    # 霍夫圆检测End
    imgStack = np.hstack([img, imgHough])
    # imgStack = np.hstack([img, imgMask])            # 拼接
    cv2.imshow('Horizontal Stacking', imgStack)  # 显示
    # ColorXs.append(targetPos_x)     # 坐标存入列表
    # ColorYs.append(targetPos_y)
    # HoughXs.append(Hough_x)
    # HoughYs.append(Hough_y)
    # 让小车跟踪乒乓球
    x_delta = targetPos_x - 320
    y_delta = targetPos_y - 240
    # 霍夫
    # x_delta = Hough_x - 320
    # y_delta = Hough_y - 240
    x_threshold = 40
    y_threshold = 30  # 阈值 可修改
    # 先调整左右方向,再前进后退
    if (abs(x_delta) <= x_threshold):
        # 球在中间
        if (abs(y_delta) <= y_threshold):
            # 正中间
            car_stop()
        elif (y_delta < y_threshold * -1):
            # 球在中上,前进
            car_forward()
            pwm1.ChangeDutyCycle(25)
            pwm2.ChangeDutyCycle(25)
        else:
            # 球在中下,后退
            car_back()
            pwm1.ChangeDutyCycle(25)
            pwm2.ChangeDutyCycle(25)
    elif (x_delta < x_threshold * -1):
        # 球在左边
        if (y_delta > y_threshold):
            # 球在左下,向右下方后退
            car_back()
            pwm1.ChangeDutyCycle(20 + abs(x_delta) / 20)
            pwm2.ChangeDutyCycle(0)
        else:
            # 球在左上、左中,向左上方前进
            car_forward()
            pwm1.ChangeDutyCycle(0)
            pwm2.ChangeDutyCycle(20 + abs(x_delta) / 20)
    else:
        # 球在右边
        if (y_delta > y_threshold):
            # 球在右下,向左下方后退
            car_back()
            pwm1.ChangeDutyCycle(0)
            pwm2.ChangeDutyCycle(20 + x_delta / 20)
        else:
            # 球在右上、右中,向右上方前进
            car_forward()
            pwm1.ChangeDutyCycle(20 + x_delta / 20)
            pwm2.ChangeDutyCycle(0)
    if cv2.waitKey(pulse_ms) & 0xFF == ord('q'):  # 按下“q”推出(英文输入法)
        print("Quit\n")
        break
cap.release()
cv2.destroyAllWindows()
将图像转换成HSV
1.2 图像结果


1.3 结果分析
我们最终没有选择使用霍夫检测,因为霍夫检测虽然在不太明亮的环境下检测效果好,但是当检测物体运动之后,检测效果很差,而只用色差的方法寻找边缘,能够很快的反应,它的缺点只有受光线影响,光照越强,检测效果越好。
4 红外避障
太简单了,就只放代码
import RPi.GPIO as gpio
import time
# 定义引脚
pin1 = 12  # 左正
pin2 = 16  # 左反
pin3 = 18  # 右正
pin4 = 22  # 右反
ENA = 38
ENB = 40
GPIO_Infrared_left = 29
GPIO_Infrared_right = 31
gpio.setwarnings(False)
# 设置gpio口为BOARD编号规范
gpio.setmode(gpio.BOARD)
# 设置gpio口为输出
gpio.setup(pin1, gpio.OUT)
gpio.setup(pin2, gpio.OUT)
gpio.setup(pin3, gpio.OUT)
gpio.setup(pin4, gpio.OUT)
gpio.setup(ENA, gpio.OUT)
gpio.setup(ENB, gpio.OUT)
gpio.setup(GPIO_Infrared_left, gpio.IN)
gpio.setup(GPIO_Infrared_right, gpio.IN)
# 设置PWM波,频率为50Hz
pwm1 = gpio.PWM(ENA, 50)
pwm2 = gpio.PWM(ENB, 50)
pwm1.start(0)
pwm2.start(0)
def car_forward():  # 定义前进函数
    gpio.output(pin1, gpio.HIGH)  # 将pin1接口设置为高电压
    gpio.output(pin2, gpio.LOW)  # 将pin2接口设置为低电压
    gpio.output(pin3, gpio.HIGH)  # 将pin3接口设置为高电压
    gpio.output(pin4, gpio.LOW)  # 将pin4接口设置为低电压
def car_back():  # 定义后退函数
    gpio.output(pin1, gpio.LOW)
    gpio.output(pin2, gpio.HIGH)
    gpio.output(pin3, gpio.LOW)
    gpio.output(pin4, gpio.HIGH)
def car_left():  # 定义左转函数
    gpio.output(pin1, gpio.LOW)
    gpio.output(pin2, gpio.HIGH)
    gpio.output(pin3, gpio.HIGH)
    gpio.output(pin4, gpio.LOW)
def car_right():  # 定义右转函数
    gpio.output(pin1, gpio.HIGH)
    gpio.output(pin2, gpio.LOW)
    gpio.output(pin3, gpio.LOW)
    gpio.output(pin4, gpio.HIGH)
def car_stop():  # 定义停止函数
    gpio.output(pin1, gpio.LOW)
    gpio.output(pin2, gpio.LOW)
    gpio.output(pin3, gpio.LOW)
    gpio.output(pin4, gpio.LOW)
def InfraredMeasure():
    left_measure = gpio.input(GPIO_Infrared_left)  # if there is an obstacle, GPIO will become 0; else, GPIO_input = 1;
    right_measure = gpio.input(GPIO_Infrared_right)
    return [left_measure, right_measure]
def avoidance(left,right):
    if(left==0 and right !=0 ):
        car_back()
        pwm1.ChangeDutyCycle(25)
        pwm2.ChangeDutyCycle(25)
        time.sleep(1)
        car_right()
        pwm1.ChangeDutyCycle(40)
        pwm2.ChangeDutyCycle(40)
        print("detect obstacles in the left!")
        time.sleep(1)
    elif(left==0 and right ==0):
        car_back()
        pwm1.ChangeDutyCycle(40)
        pwm2.ChangeDutyCycle(40)
        print("detect obstacles in the left and right!")
        time.sleep(1)
    elif(left == 1 and right ==0):
        car_back()
        pwm1.ChangeDutyCycle(25)
        pwm2.ChangeDutyCycle(25)
        time.sleep(2)
        car_left()
        pwm1.ChangeDutyCycle(40)
        pwm2.ChangeDutyCycle(40)
        print("detect obstacles in the right!")
        time.sleep(1)
    else:
        car_forward()
        pwm1.ChangeDutyCycle(30)
        pwm2.ChangeDutyCycle(30)
def loop():
    while True:
        car_forward()
        pwm1.ChangeDutyCycle(30)
        pwm2.ChangeDutyCycle(30)
        [left, right] = InfraredMeasure()
        print(left,right)
        avoidance(left,right)
def destroy():
    gpio.cleanup()
try:
    loop()
except KeyboardInterrupt:
    destroy()
5 超声波避障
import RPi.GPIO as gpio
import time
# 定义引脚
pin1 = 12  # 左正
pin2 = 16  # 左反
pin3 = 18  # 右正
pin4 = 22  # 右反
ENA = 38
ENB = 40
TRIG = 13  # send-pin
ECHO = 15  # receive-pin
# 设置gpio口为BOARD编号规范
gpio.setmode(gpio.BOARD)
# 设置gpio口为输出
gpio.setup(pin1, gpio.OUT)
gpio.setup(pin2, gpio.OUT)
gpio.setup(pin3, gpio.OUT)
gpio.setup(pin4, gpio.OUT)
gpio.setup(ENA, gpio.OUT)
gpio.setup(ENB, gpio.OUT)
# 设置PWM波,频率为50Hz
pwm1 = gpio.PWM(ENA, 50)
pwm2 = gpio.PWM(ENB, 50)
pwm1.start(0)
pwm2.start(0)
def car_forward():  # 定义前进函数
    gpio.output(pin1, gpio.HIGH)  # 将pin1接口设置为高电压
    gpio.output(pin2, gpio.LOW)  # 将pin2接口设置为低电压
    gpio.output(pin3, gpio.HIGH)  # 将pin3接口设置为高电压
    gpio.output(pin4, gpio.LOW)  # 将pin4接口设置为低电压
def car_back():  # 定义后退函数
    gpio.output(pin1, gpio.LOW)
    gpio.output(pin2, gpio.HIGH)
    gpio.output(pin3, gpio.LOW)
    gpio.output(pin4, gpio.HIGH)
def car_left():  # 定义左转函数
    gpio.output(pin1, gpio.LOW)
    gpio.output(pin2, gpio.HIGH)
    gpio.output(pin3, gpio.HIGH)
    gpio.output(pin4, gpio.LOW)
def car_right():  # 定义右转函数
    gpio.output(pin1, gpio.HIGH)
    gpio.output(pin2, gpio.LOW)
    gpio.output(pin3, gpio.LOW)
    gpio.output(pin4, gpio.HIGH)
def car_stop():  # 定义停止函数
    gpio.output(pin1, gpio.LOW)
    gpio.output(pin2, gpio.LOW)
    gpio.output(pin3, gpio.LOW)
    gpio.output(pin4, gpio.LOW)
def setup():
    gpio.setup(TRIG, gpio.OUT, initial=gpio.LOW)
    gpio.setup(ECHO, gpio.IN)
    gpio.setwarnings(False)  # 关闭警告
def distance():
    gpio.output(TRIG, 1)  # 给Trig一个10US以上的高电平
    time.sleep(0.00001)
    gpio.output(TRIG, 0)
    # 等待低电平结束,然后记录时间
    while gpio.input(ECHO) == 0:  # 捕捉 echo 端输出上升沿
        pass
    time1 = time.time()
    # 等待高电平结束,然后记录时间
    while gpio.input(ECHO) == 1:  # 捕捉 echo 端输出下降沿
        pass
    time2 = time.time()
    during = time2 - time1
    # ECHO高电平时刻时间减去低电平时刻时间,所得时间为超声波传播时间
    return during * 340 / 2 * 100
# 超声波传播速度为340m/s,最后单位米换算为厘米,所以乘以100
def loop():
    while True:
        dis = distance()
        print(dis, "cm\n")
        # print dis, 'cm'
        # print ''
        time.sleep(0.3)
        car_forward()
        pwm1.ChangeDutyCycle(30)
        pwm2.ChangeDutyCycle(30)
        if (dis < 30):
            car_back()
            pwm1.ChangeDutyCycle(40)
            pwm2.ChangeDutyCycle(40)
            time.sleep(1)
            car_forward()
            pwm1.ChangeDutyCycle(40)
            pwm2.ChangeDutyCycle(0)
            time.sleep(1)
def destroy():
    gpio.cleanup()
if __name__ == "__main__":
    setup()
    try:
        loop()
    except KeyboardInterrupt:
        destroy()



                
            
浙公网安备 33010602011771号