文章目录

  • 1. 前言
  • 2. 系统定义
    • 2.1 硬件装置
    • 2.2 软件功能模块
      • 2.2.1 环境依赖
      • 2.2.2 软件模块
  • 3. 详细设计
    • 3.1 硬件设计
      • 3.1.1 硬件零件型号
      • 3.1.2 智能垃圾桶硬件整体结构
    • 3.2 软件设计
      • 3.2.1 超声波检测模块
      • 3.2.2 UI可视化模块
      • 3.2.3 图像预处理模块
      • 3.2.4 MobileNetV1图像分类模块
      • 3.2.5 舵机驱动模块
  • 4. 总结

1. 前言

  博客简单介绍了我本科毕业设计作品——智能分类垃圾桶。使用Raspberry Pi 3B+、舵机、摄像头、亚克力板等零件材料制作智能分类垃圾桶硬件平台;然后使用收集的垃圾图片数据集样本训练MobileNetV1轻量化网络和XGBoost分类器,配合TensorFlow Lite对MobileNetV1在Raspberry Pi上做进一步优化。在资源受限的Raspberry Pi 3B+开发板上实现垃圾分类投放。

2. 系统定义

2.1 硬件装置

  垃圾桶硬件装置应实现对行人投入垃圾的四分类投放(可回收垃圾、有害垃圾、厨余垃圾、其他垃圾)。垃圾桶硬件装置主要包含以下六点结构设计。
  (1) 四分类垃圾回收桶箱
  为实现对垃圾的四分类投放,智能垃圾桶装置设置四分类垃圾回收桶箱。将整个长方体桶箱平均分成四份,分别对应“可回收垃圾”、“有害垃圾”、“厨余垃圾”、“其他垃圾”四个垃圾大类类别。
  (2) 托盘
  托盘用来暂存待投放垃圾。待垃圾识别完成后,根据具体的识别结果进行分类投放。
  (3) 超声波
  为满足系统对垃圾投入有较快的响应速度要求,设置超声波传感器。该传感器检测托盘上是否有垃圾放置。若检测到垃圾,则启动分类程序,对待投放垃圾进行识别投放。
  (4) 摄像头
  摄像头作为系统中的垃圾图像采集装置。使用摄像头拍摄托盘上的垃圾图像,系统根据拍摄图像对垃圾进行分类识别。
  (5) 舵机
  舵机为垃圾桶的投放驱动模块,该模块共有两个舵机。当得到待投放垃圾的所属大类类别后,两舵机带动托盘旋转,实现对垃圾识别后的投放步骤。
  (6) 树莓派
  树莓派作为智能垃圾桶的计算设备,负责连接超声波、摄像头等传感器零件,并运行编写完成的软件程序。

2.2 软件功能模块

2.2.1 环境依赖

  软件功能模块所使用的主要依赖库如表2-1所示。

表2-1 主要依赖库统计

名称 版本 作用
操作系统 Raspbian Buster with desktop(September 2019) 为程序运行提供平台
编程语言 Python3.6 运行软件程序
深度学习框架 TensorFlow 1.15.0 使用MobileNetV1网络
机器学习框架 XGBoost 1.4.1 使用XGBoost分类器

2.2.2 软件模块

  系统软件功能模块分为超声波检测、UI可视化、图像预处理、MobileNetV1图像分类、舵机驱动共五个子模块。
  (1) 超声波检测
  超声波检测软件模块依托超声波传感器硬件,基于GPIO框架编写超声波硬件的使用程序,判断当前是否有垃圾待投放。
  (2) UI可视化
  可视化垃圾桶当前工作状态,以更直观的方式展示垃圾桶工作是否正常。
  (3) 图像预处理
  使用摄像头拍摄得到垃圾图像后,执行图像预处理算法对图片进行裁剪,去除无用的背景,便于后续的MobileNetV1图像分类。
  (4) MobileNetV1图像分类
  为满足系统的垃圾图像分类算法应具有较高的精度和实时性要求,垃圾图像分类软件模块基于MobileNetV1网络和XGBoost分类算法实现,输入为图像预处理模块得到的垃圾图像,输出垃圾类别。MobileNetV1与XGBoost结合,能够得到较好的分类精度。而MobileNetV1作为轻量化网络,再配合模型量化技术,能够满足实时性要求。
  (5) 舵机驱动
  舵机驱动软件模块依托舵机硬件,基于GPIO框架编写双舵机硬件的使用程序,使之能够根据垃圾图像分类模块的输出驱动舵机转动合适角度,从而将垃圾投入至正确的回收桶箱之中。

3. 详细设计

3.1 硬件设计

3.1.1 硬件零件型号

表3-1 零件型号统计

零件 型号 作用
超声波传感器 HC-SR04 检测托盘上有无垃圾放置
摄像头 Epcbook 1080P免驱USB摄像头 采集垃圾图像
舵机-0 DS3115 可控角度90° 15KG扭矩 带动托盘转动
舵机-1 DS3218 可控角度360° 20KG扭矩 带动旋转圆盘转动
开发板 Raspberry Pi 3B+ 核心计算设备
拓展板 小R科技 PWR.A53机器人驱动拓展版 拓展Raspberry引脚与供电接口
电源 12V 2200mAh 锂电池 供电
显示屏 RaspberryPi 3.5寸电容USB触摸显示屏 显示UI界面

3.1.2 智能垃圾桶硬件整体结构

  装置实现垃圾四分类投放(可回收垃圾、有害垃圾、厨余垃圾、其他垃圾),其主视图、俯视图以及双层舵机结构分别如图3-1、3-2、3-3所示。
  主视图展示了装置的整体结构以及摄像头、托盘、回收桶箱的位置,如图3-1所示。

图3-1 智能垃圾桶装置-主视图

  装置俯视图中清晰展示了四分类垃圾回收桶箱与“可回收垃圾”、“有害垃圾”、“厨余垃圾”、“其他垃圾”四个垃圾类别的对应关系,并从俯视角度展示了超声波和托盘的位置。智能垃圾桶装置俯视图如图3-2所示。

图3-2 智能垃圾桶装置-俯视图

  双层舵机结构中舵机-1与旋转圆盘连接,用以驱动旋转圆盘转动。舵机-0与托盘连接,用来驱动托盘转动。超声波传感器置于托盘侧面,检测托盘上是否有垃圾放置。双层舵机结构如图3-3所示。

图3-3 智能垃圾桶装置-双层舵机结构

3.2 软件设计

3.2.1 超声波检测模块

  超声波模块固定在托盘旁边,使用超声波传感器可测量放置于托盘表面的垃圾距超声波传感器的距离D1D_1D1​。D2D_2D2​为无垃圾放置时超声波传感器测得的距离数据,D2=14cmD_2=14cmD2​=14cm。若满足0<D1<D20<D_1<D_20<D1​<D2​,则认为此时托盘表面有物品放置,即装置有垃圾待分类,若不满足,则认为装置无垃圾待分类。
  超声波传感器距离测量函数代码如下。

# -*- coding: utf-8 -*-
"""
Created on Sat Dec 12 21:33:42 2020@author: qiqi此文件用于实现四分类垃圾桶的5个超声波测距的控制"""import time
import RPi.GPIO as GPIOGPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)def getDistance(TRIG=None, ECHO=None):'''函数功能:获取ECHO与TRIG指定的超声波传感器测定的距离''''''TRIG为超声波发射脚位,ECHO为超声波接收脚位'''if TRIG is None or ECHO is None:print('引脚未接好')return 0GPIO.output(TRIG,GPIO.HIGH)time.sleep(0.1)GPIO.output(TRIG,GPIO.LOW)while not GPIO.input(ECHO):passt1 = time.time()while GPIO.input(ECHO):passt2 = time.time()Distence = (t2-t1)*340/2*100return Distencedef ultrasonic(pin):dis = pin.copy()key = list(pin.keys())for k in key:dis[k] = getDistance(TRIG=pin[k][0], ECHO=pin[k][1])return dis

3.2.2 UI可视化模块

  可视化UI界面可以直观输出智能垃圾桶工作状态功能,主要包括:展示摄像头拍摄图片经过预处理后得到的需要进行分类的图片、输出分类识别的结果(该垃圾属于哪个大类)。
  图形化界面依靠智能垃圾桶终端搭载的电容显示屏显示,使用PyQt5工具编程实现。图形界面如图3-4所示。

图3-4 图形化界面

  图形界面完整代码如下。

# -*- coding: utf-8 -*-
"""
Created on Fri Dec 11 20:59:15 2020@author: qiqi此文件用于实现四分类垃圾桶两个UI界面的显示工作"""import sys
import warnings
import threading
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QTimer,QDateTime
warnings.filterwarnings('ignore')information = {'垃圾类别':'电池', '任务是否完成':'任务完成', '满载情况':'未满载', '摄像头画面帧':None, '窗口':None, '宣传视频帧':None}class showTrash(QWidget):def __init__(self):super().__init__()self.initUI()def initUI(self):desktop = QApplication.desktop()self.label_0 = QtWidgets.QLabel(self) #用来显示垃圾类别self.label_0.resize(desktop.width()*0.4, desktop.height()*0.2)self.label_0.move(desktop.width()*0.1, desktop.height()*0.15)self.label_1 = QtWidgets.QLabel(self) #用来显示任务是否完成self.label_1.resize(desktop.width()*0.4, desktop.height()*0.2)self.label_1.move(desktop.width()*0.1, desktop.height()*0.35)self.label_2 = QtWidgets.QLabel(self) #用来显示满载情况self.label_2.resize(desktop.width()*0.4, desktop.height()*0.2)self.label_2.move(desktop.width()*0.1, desktop.height()*0.55)self.label_3 = QtWidgets.QLabel(self) #用来摄像头画面self.label_3.resize(desktop.width()*0.5, desktop.height()*0.5)self.label_3.move(desktop.width()*0.5, desktop.height()*0.15)self.setWindowTitle('垃圾桶工作状态')self.setGeometry(600, 600, 1000, 500)self.showMaximized()def setupUi(self):self.Timer=QTimer()     #自定义QTimerself.Timer.start(100)   #每0.1秒运行一次self.Timer.timeout.connect(self.update)   #连接updateself.Timer.timeout.connect(self.showImage) QtCore.QMetaObject.connectSlotsByName(self)def update(self):self.label_0.setText(information['垃圾类别'])self.label_0.setStyleSheet('color:rgb(10,10,10,255);font-size:20px;font-weight:bold;font-family:Roman times;')self.label_1.setText(information['任务是否完成'])self.label_1.setStyleSheet('color:rgb(10,10,10,255);font-size:20px;font-weight:bold;font-family:Roman times;')self.label_2.setText(information['满载情况'])self.label_2.setStyleSheet('color:rgb(10,10,10,255);font-size:20px;font-weight:bold;font-family:Roman times;')def showImage(self):frame = information['摄像头画面帧']heigt, width, _ = frame.shapepixmap = QImage(frame, width, heigt, QImage.Format_RGB888)pixmap = QPixmap.fromImage(pixmap)self.label_3.setPixmap(pixmap)class showVideo(QWidget):def __init__(self):super().__init__()self.initUI()def initUI(self):desktop = QApplication.desktop()self.label = QtWidgets.QLabel(self)self.label.resize(desktop.width()*0.99, desktop.height()*0.79)self.label.move(desktop.width()*0.01, desktop.height()*0.01)self.setWindowTitle('宣传视频')self.showMaximized()def setupUi(self):self.Timer=QTimer()     #自定义QTimerself.Timer.start(100)   #每0.1秒运行一次self.Timer.timeout.connect(self.showImage) QtCore.QMetaObject.connectSlotsByName(self)def showImage(self):frame = information['宣传视频帧']heigt, width, _ = frame.shapepixmap = QImage(frame, width, heigt, QImage.Format_RGB888)pixmap = QPixmap.fromImage(pixmap)self.label.setPixmap(pixmap)if information['窗口'] == '垃圾分类':self.close()class Thread(threading.Thread):def __init__(self, window, *args, **kwargs):super(Thread, self).__init__(*args, **kwargs)threading.Thread.__init__(self)self._stop_event = threading.Event()self.window = windowdef stop(self):self._stop_event.set()def stopped(self):return self._stop_event.is_set()def run(self):app = QApplication(sys.argv)if self.window == '视频播放':ui = showVideo()else:ui = showTrash()ui.setupUi()app.exec_()def showUI():thread = Thread('垃圾分类')thread.start()information['窗口'] = '垃圾分类'thread.join()

3.2.3 图像预处理模块

  (1) 去除托盘外部无用背景
  智能垃圾桶摄像头拍摄的图片如图3-5(aaa)所示,由于智能垃圾桶摄像头与托盘位置相对固定,可先将托盘外的无用图像进行去除,将源图像3-5(aaa)与mask图像进行对应位置像素按位与运算,得到去除结果。mask图像如图3-5(bbb)所示,托盘外部无用背景去除结果如图3-5(ccc)所示。

img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img = np.bitwise_and(img, mask)

  (2) 削减图像局部过亮区域的光照强度
  由于实际环境的复杂性,拍摄的图像可能出现部分区域过亮的情况,边缘检测时容易将过亮区域误判为边缘,从而对图像预处理造成不利影响。因此,使用一种不均匀光照补偿算法来削减图像局部过亮区域的光照强度,降低其造成的不利影响。
  算法主要步骤:
  i.i.i. 将RGB三通道的步骤(1)结果图像灰度化,得到单通道图像III,记图像III的宽为W0W_0W0​,高为H0H_0H0​;
  ii.ii.ii. 求得灰度图III的平均值,记为uuu;
  iii.iii.iii. 指定超参数blockSize=16blockSize=16blockSize=16,若W0W_0W0​和H0H_0H0​不是blockSizeblockSizeblockSize正整数倍,则先使用双立方插值法将图像宽和高转化为W0′W_0'W0′​和H0′H_0'H0′​,其中W0’=(⌊W0/blockSize⌋+1)∗blockSize,H0′=(⌊H0/blockSize⌋+1)∗blockSizeW_0’=(⌊W_0/blockSize⌋+1)*blockSize,H_0'=(⌊H_0/blockSize⌋+1)*blockSizeW0​’=(⌊W0​/blockSize⌋+1)∗blockSize,H0′​=(⌊H0​/blockSize⌋+1)∗blockSize。 将整幅图片划分成M∗NM*NM∗N个边长为blockSizeblockSizeblockSize的正方形,其中M=W0′/blockSizeM=W_0'/blockSizeM=W0′​/blockSize,N=H0′/blockSizeN=H_0'/blockSizeN=H0′​/blockSize。求出每块的平均值,得到子块的亮度矩阵DDD(维度为M∗NM*NM∗N);
  iv.iv.iv. 用矩阵DDD的每个元素减去灰度图III的平均值uuu,得到子块的亮度差值矩阵EEE;
  v.v.v. 用双立方插值法,将矩阵EEE调整成宽为W0W_0W0​,高为H0H_0H0​的亮度分布矩阵RRR;
  vi.vi.vi. 得到矫正后的图像result=I−Rresult=I-Rresult=I−R;
  vii.vii.vii. 使用7∗77*77∗7高斯滤波对图像resultresultresult进行平滑处理,平滑处理后的resultresultresult即为算法输出。
  算法效果如图3-5(ddd)所示。

def unevenLightCompensate(img, blockSize):'''去除图像中的光照不均匀'''if len(img.shape) == 2:gray = imgelse:gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)average = np.mean(gray)rows_new = int(np.ceil(gray.shape[0] / blockSize))cols_new = int(np.ceil(gray.shape[1] / blockSize))blockImage = np.zeros((rows_new, cols_new), dtype=np.float32)for r in range(rows_new):for c in range(cols_new):rowmin = r * blockSizerowmax = (r + 1) * blockSizeif (rowmax > gray.shape[0]):rowmax = gray.shape[0]colmin = c * blockSizecolmax = (c + 1) * blockSizeif (colmax > gray.shape[1]):colmax = gray.shape[1]imageROI = gray[rowmin:rowmax, colmin:colmax]temaver = np.mean(imageROI)blockImage[r, c] = temaverblockImage = blockImage - averageblockImage2 = cv2.resize(blockImage, (gray.shape[1], gray.shape[0]), interpolation=cv2.INTER_CUBIC)gray2 = gray.astype(np.float32)dst = gray2 - blockImage2dst[dst > 255] = 255dst = dst.astype(np.uint8)dst = cv2.GaussianBlur(dst, (7, 7), 0)return dst

  (3) 边缘检测
  本环节使用Canny算法实现边缘检测,对步骤(2)得到不均匀光照补偿后的图像执行Canny算法,算法的两个阈值参数设置为:低阈值=50,高阈值=100。图3-5(eee)为边缘检测后的效果图。

def edge_demo(image):'''使用Canny算法对image进行边缘检测,输入image为彩色图像'''edge_output = cv2.Canny(image, 50, 100)return edge_output

  (4) 消除图像细小噪声并平滑边界
  观察图3-5(eee),发现电池的边缘被成功检测出来。但仅含边缘的图像并不适合做分割操作。因此,对边缘检测的输出图像执行腐蚀和膨胀操作。腐蚀和膨胀操作结合具备消除噪声和连接极大值区域的作用。
  图3-5(fff)为腐蚀膨胀后的效果图。通过效果图可以发现,虽然腐蚀膨胀后仍含有少量噪声区域,但电池所在的区域已经成为最主要的连通区域,方便被分割出来。

def smooth(image):'''将image图像中的垃圾使用矩阵框圈出,返回矩形框的四个顶点的坐标(box)'''''''以图片左下角为原点,box[0]为左下角顶点,box[1]为左上角''''''box[2]右下角,box[3]右上角,closed为边缘检测经过腐蚀膨胀后的图像'''kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (35, 35))closed = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel)closed = cv2.erode(closed, None, iterations=4)closed = cv2.dilate(closed, None, iterations=4)_, cnts, _ = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)if len(cnts) == 0:return None, Nonec = sorted(cnts, key=cv2.contourArea, reverse=True)[0]# compute the rotated bounding box of the largest contourrect = cv2.minAreaRect(c)box = np.int0(cv2.boxPoints(rect))# draw a bounding box arounded the detected barcode and display the imagereturn box, closed

  (5) 裁剪目标区域
  i.i.i. 上一步骤结束后,先对腐蚀膨胀输出图像进行轮廓检测,得到轮廓数组contourscontourscontours,contourscontourscontours每个元素是一个像素点集合,存储组成该轮廓的所有像素点;
  ii.ii.ii. 原始图像经步骤(1)、(2)、(3)、(4)后,电池所在的目标区域为腐蚀膨胀后图像的最大连通区域。因此,在寻找到的所有轮廓中,构成电池所在目标区域的轮廓包含的像素点数量最多。在轮廓数组contourscontourscontours中找出像素点最多的轮廓,记为maxContourmaxContourmaxContour;
  iii.iii.iii. 使用最小外接矩形函数计算得到maxContourmaxContourmaxContour的最小外接矩形boxboxbox,如图3-5(ggg)所示;
  iv.iv.iv. 在原始图像中将boxboxbox对应的区域裁剪出来,得到裁剪目标区域步骤的处理结果,如图3-5(hhh)所示。
  v.v.v. 将图像尺寸调整为224∗224224*224224∗224,如图3-5(iii)所示。

def rotate(img, box):'''旋转图像并剪裁'''pt1, pt2, pt3, pt4 = boxwithRect = math.sqrt((pt4[0] - pt1[0]) ** 2 + (pt4[1] - pt1[1]) ** 2)  # 矩形框的宽度angle = math.acos((pt4[0] - pt1[0]) / withRect) * (180 / math.pi)  # 矩形框旋转角度if pt4[1]>pt1[1]:info = '顺时针旋转'else:info = '逆时针旋转'angle=-angleheight = img.shape[0]  # 原始图像高度width = img.shape[1]   # 原始图像宽度rotateMat = cv2.getRotationMatrix2D((width / 2, height / 2), angle, 1)  # 按angle角度旋转图像heightNew = int(width * math.fabs(math.sin(math.radians(angle))) + height * math.fabs(math.cos(math.radians(angle))))widthNew = int(height * math.fabs(math.sin(math.radians(angle))) + width * math.fabs(math.cos(math.radians(angle))))rotateMat[0, 2] += (widthNew - width) / 2rotateMat[1, 2] += (heightNew - height) / 2imgRotation = cv2.warpAffine(img, rotateMat, (widthNew, heightNew), borderValue=(255, 255, 255))# 旋转后图像的四点坐标[[pt1[0]], [pt1[1]]] = np.dot(rotateMat, np.array([[pt1[0]], [pt1[1]], [1]]))[[pt3[0]], [pt3[1]]] = np.dot(rotateMat, np.array([[pt3[0]], [pt3[1]], [1]]))[[pt2[0]], [pt2[1]]] = np.dot(rotateMat, np.array([[pt2[0]], [pt2[1]], [1]]))[[pt4[0]], [pt4[1]]] = np.dot(rotateMat, np.array([[pt4[0]], [pt4[1]], [1]]))# 处理反转的情况if pt2[1]>pt4[1]:pt2[1],pt4[1]=pt4[1],pt2[1]if pt1[0]>pt3[0]:pt1[0],pt3[0]=pt3[0],pt1[0]imgOut = imgRotation[int(pt2[1]):int(pt4[1]), int(pt1[0]):int(pt3[0])]imgOut = cv2.resize(imgOut, (image_height, image_width),)return imgOut, info

图3-4 图像预处理各步骤效果图

3.2.4 MobileNetV1图像分类模块

  (1) 基于MobileNetV1与XGBoost的垃圾图像分类算法
  基于MobileNetV1与XGBoost的垃圾图像分类算法输入一张经过预处理的垃圾图片,得到预测的小类类别,最终的输出为该小类类别所所属的大类类别。例如:输入一张易拉罐图片,预测得到小类类别为易拉罐,将易拉罐小类所属的大类类别可回收垃圾作为输出。
  本文采用MobileNet系列中的MobileNetV1网络,原生MobileNetV1网络输出Softmax层结点数量为1000(对应1000类别)。本文将Softmax层结点数改为15(对应15个垃圾小类)进行训练。在进行预测时砍掉Softmax层,直接输出Softmax层前的全局池化层输出结果,长度为1024的一维向量。XGBoost算法输入为MobileNetV1网络的输出(长度为1024的一维向量),输出为分类结果(15个垃圾小类之一)。

  (2) 垃圾图像分类算法优化技巧
   a. 数据增强
  在MobileNetV1与XGBoost网络训练过程中使用数据增强策略,对原始图片使用随机翻转、旋转、裁剪等手段生成不同的图片数据,以此获得更多的数据训练网络。原始数据集见博客末尾的百度网盘链接。
  使用TensorFlow框架的ImageDataGenerator工具对训练集数据使用随机裁剪、旋转等手段进行扩充。ImageDataGenerator工具参数设置如表3-2所示。

表4-2 ImageDataGenerator参数设置

Parameter Value
rotation_range 180
width_shift_range 0.2
height_shift_range 0.2
shear_range 0.2
zoom_range 0.2
fill_mode ‘nearest’
cval 0.0
horizontal_flip True
vertical_flip True
rescale 1./255

  b. 迁移学习
  使用迁移学习技巧训练MobileNetV1网络,即在ImageNet预训练模型基础上对MobileNetV1权重进行微调。使用TensorFlow框架提供的Keras接口实现MobileNetV1加载ImageNet预训练权重。
  c. 模型量化
  模型量化方法可以实现减小模型尺寸、减少模型内存消耗以及加快模型推理速度等目标。
  使用TensorFlow Lite工具,对训练完成的MobileNetV1网络进行量化,将32位浮点数运算量化为16位浮点数运算。使用TF Lite工具可在维持原有精度的基础上大幅降低模型推理预测耗时,这点在Raspberry Pi 3B+得到了良好的体现。
  使用TensorFlow将H5模型文件转化为TFLite文件的Python代码如下,原H5文件和输出的TFLite文件均在models子目录下。

# -*- coding: utf-8 -*-
"""
Created on Thu Oct 15 15:35:58 2020@author: qiqi
"""import tensorflow as tf
from tensorflow.keras.models import load_model, ModelMobileNetV1 = load_model('models/MobileNetV1.h5')
MobileNetV1 = Model(inputs=MobileNetV1.input, outputs=MobileNetV1.get_layer('global_average_pooling2d').output)converter = tf.lite.TFLiteConverter.from_keras_model(MobileNetV1)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_types = [tf.float16]
tflite_quant_model = converter.convert()
open('models/MobileNetV1.tflite', 'wb').write(tflite_quant_model)

3.2.5 舵机驱动模块

  舵机驱动模块基于双舵机硬件实现,根据垃圾图像分类模块结果驱动舵机旋转,具体而言分为以下步骤。舵机部分源码整合在了程序main模块中。
   (1) 根据图像分类模块得到的垃圾大类类别,控制舵机-1旋转指定角度,从而带动旋转圆盘转动,使得固定在旋转圆盘上的托盘旋转至对应的垃圾大类回收桶箱正上方。托盘初始位置位于有害垃圾回收桶箱正上方。若垃圾大类类别为有害垃圾,则舵机-1不转动;若垃圾大类类别为可回收垃圾,则舵机-1顺时针转动270°;若垃圾大类类别为厨余垃圾,则舵机-1顺时针转动180°;若垃圾大类类别为其他垃圾,则舵机-1顺时针转动90°。
  (2) 舵机-1旋转完成后,舵机-0逆时针旋转90°带动托盘转动。托盘移开后等待2s,垃圾自动掉落至正确回收桶箱中。
  (3) 舵机-0与舵机-1归位,重新回到最初状态,等待下一次任务。

4. 总结

  博客记录了我本科毕业设计的主要内容。作品很low,没有什么实用价值。可能是由于我们大组只有我一个人做了软硬件结合作品,而其他人都是纯软件,最后毕设成绩还不错。感谢评审老师搭救!!!
  博客只提供了部分源码,完整源码见我的Github(https://github.com/jiaozi12/Intelligent-Trash-Can)。各位大佬觉得没那么差的话,欢迎给Star!!!
  垃圾图片数据集和作品演示视频请见百度网盘链接(https://pan.baidu.com/s/1o9NG4A6d91b6Hc8rRexp8w),提取码:n0qu。

计算机本科毕业设计-智能分类垃圾桶相关推荐

  1. 计算机本科毕业设计:毕业设计、论文要点及我们面对毕业答辩应持有的态度

    文章目录 前言 一.对于毕业设计 1.1.选题 1.2.中期自查 1.3.毕业设计答辩 二.对于毕业论文 三.我们应持有的态度 3.1.人尽其才 3.2.恪尽职守 3.3.全力以赴 3.4.做好自己 ...

  2. 计算机专业毕业设计致谢,计算机本科毕业设计致谢

    毕业设计是教学过程的最后阶段采用的一种总结性的实践教学环节.通过毕业设计,学生可以综合应用所学的各种理论知识和技能,进行全面.系统.严格的技术及基本能力的练习.通常情况下,仅对大专以上学校要求在毕业前 ...

  3. 综合项目——智能分类垃圾桶

    综合项目--智能分类垃圾桶 一.讲在前面 之前做过许多项目,也写了许多工程代码,但是一直没能好好整理,导致我每做一个新的项目就跟重头开始似的,为了更好进行代码资料的管理,我决定开辟这个博客,作为我资料 ...

  4. 基于ArduinoUNO的LD3320语音识别+SYN6288语音合成的智能分类垃圾桶

    文章目录 写在前面 器件 连接 部分代码 运行结果 小结 写在前面 接上一篇文章,这次是集合了语音识别+语音合成(就是语音播报实现一种反馈)+SG90舵机实现垃圾桶的开与闭,给出上篇文章链接,如果对L ...

  5. 计算机本科毕业设计选哪个方向的课题比较好?

    在做计算机程序的时候首先第一步就是要先吧主题弄清楚,到底是需要用什么主题去做程序,这个是最重要的一步,只有吧主题确定好了,那题目就简单了,不管你是要做网站,系统还是说做小程序等等都容易很多了.以下则是 ...

  6. 硬件篇:基于微信小程序的智能分类垃圾桶(详细介绍)

    硬件选择 因为我们需要实现的主要功能是控制四个垃圾桶的开合,所以舵机是必不可少的,至于用什么来控制舵机,我直接就选择了51单片机(因为我只学了51),明确了主要的硬件,进一步细化目标,用微信小程序通过 ...

  7. 基于pytorch的人工智能分类垃圾桶

    Hello,大家好,作者终于考完研了,现在开始更新自己以前的科研项目来供大家一起学习参考,开源共享,作者github网址:https://github.com/czzq1999,欢迎加油一起学习,一起 ...

  8. 无法获取 dpkg 前端锁_济南一小区分类垃圾桶上了锁?闲置不用惹居民质疑

    齐鲁晚报·齐鲁壹点记者 任玉停 目前,济南正在大力推行垃圾分类,不少社区也陆续引进了智能分类垃圾桶等相关设备.然而,家住市中区鲁能领秀城27区的业主李先生向齐鲁晚报·齐鲁壹点反映称,小区里的分类垃圾桶 ...

  9. 计算机本科学生毕业设计课题,计算机科学与技术本科毕业设计选题.doc

    计算机科学与技术本科毕业设计选题 毕 业 设 计(论文)任 务 书 专业:计算机科学与技术 级别:2007 姓名: 毕业设计(论文)题目: 毕业设计(论文)内容: (包括主要部分,但并不局限) 1.课 ...

最新文章

  1. shell 获取字符串/文件的MD5值
  2. boost::log模块实现如何同时对多个文件执行日志记录的测试程序
  3. mysql表定义外键语法_mysql设置外键的语法怎么写?
  4. 虚幻4 捏脸和换装系统实现
  5. 婚宴座位图html5,婚礼小知识,婚宴座位怎么安排才不得罪人(主桌)
  6. 数字化园区、智慧园区、物业管理、园区设备、房屋资源、维修业务、巡查管理、招商管理、商业租售管理,收支管理,合同管理,人员管理,日常维护,巡检管理,报检报修、物业驾驶舱、axure原型、rp原型
  7. Linux 命令(22)—— touch 命令
  8. 运维人员需重视非技术能力(老鸟经验分享)
  9. 服务器iis限制ip访问网站吗,利用IIS实现网站后台IP登录限制
  10. 【图像增强】基于matlab GSA灰度图像增强【含Matlab源码 1172期】
  11. thymeleaf使用总结
  12. cmd识别java命令却不识别javac
  13. c语言alt 小键盘,ALT+小键盘输入《泡MM好招》
  14. 苹果MacBook Pro usb连接iPhone反复重连解决方法
  15. 零基础学Docker【3】 | 一文带你快速进行Docker实战
  16. Bluetooth Profile Specification之1.2 A2DP 之Audio Codec(音频编解码器)-MPEG-1,2 Audio和MPEG-2, 4 AAC
  17. 【科研】博士学位论文评阅书
  18. win10网络不出现计算机列表,win10系统电脑不显示无线网络的解决方法
  19. 10月1日 - 10月7日,国庆
  20. 计算机网络经典选择题20道

热门文章

  1. android视频用什么组件,一个简单的移动端视频组件的实现
  2. ppt编写一个抽奖系统_PPT抽奖程序
  3. Python之signal模块详解
  4. 十位数连加 c语言,用C语言编写一个简易计算器可实现加减乘除,连加连减,连乖连除....
  5. 公司“内部管理混乱,工作很难开展”!
  6. dingdang robot:一个开源的中文智能音箱项目
  7. Android学习笔记——活动,从创建到销毁
  8. 手机芯片性能排名天梯图2022
  9. 华为软件测试工程师无线产品线实习生第一次视频面试
  10. sfm算法之三角化(三角测量)