第七届工程训练大赛垃圾分类


前言

  本人有幸代表内蒙古工业大学参加内蒙古自治区的全国工程训练大赛省赛,并在初赛取得前三名的成绩。可惜后来决赛由于树莓派死机导致程序崩溃,从而无缘国赛。但是经过测试,我们的识别程序可以做到识别率95%,分类准确率90%以上。
  硬件设备:树莓派4B+8G(用于视觉识别以及播放视频)
       stm32f103zet6 (用于下位机控制电机进行分类)
  机械结构设计:双层履带交叉分拣
  本人具有嵌入式开发经验两年,可代指导单片机,linux,物联网视觉识别,各种机器人的大创、毕设、项目 具体联系:qq
1549843074


一、机械结构设计

1.Solidworks建模

  如图所示,采用双层履带结构

2.建模的不足以及改进

1.挡板的添加

  从上履带识别后,移交至第二层履带时。会出现飞出去的情况导致分类失败,于是我们在履带两侧以及垃圾桶整体四周加上挡板。这样情况大大改善。

  挡板:
在这里插入图片描述

2.履带防滑

  当进行调试过程中,如果出现瓶子、电池等容易滚的物体,很容易在投掷过程中滚下去导致无法实现识别。为此,我们决定在履带上用胶水粘上小突起,经检验这样能很好解决这个问题。
在这里插入图片描述

3.整体实物

  整体实物图:
在这里插入图片描述

  俯视图:

在这里插入图片描述

二、视觉识别部分

1.引入库

代码如下(示例):

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function


import argparse
import io
import time
import numpy as np
#import picamera
import cv2
import RPi.GPIO as GPIO

#import tensorflow as tf

from PIL import Image
from tflite_runtime.interpreter import Interpreter

2.识别部分

代码如下:

def load_labels(path):
  with open(path, 'r') as f:
    return {i: line.strip() for i, line in enumerate(f.readlines())}


def set_input_tensor(interpreter, image):
  tensor_index = interpreter.get_input_details()[0]['index']
  input_tensor = interpreter.tensor(tensor_index)()[0]
  input_tensor[:, :] = image


def classify_image(interpreter, image, top_k=1):
  """Returns a sorted array of classification results."""
  set_input_tensor(interpreter, image)
  interpreter.invoke()
  output_details = interpreter.get_output_details()[0]
  output = np.squeeze(interpreter.get_tensor(output_details['index']))

  # If the model is quantized (uint8 data), then dequantize the results
  if output_details['dtype'] == np.uint8:
    scale, zero_point = output_details['quantization']
    output = scale * (output - zero_point)

  ordered = np.argpartition(-output, top_k)
  return [(i, output[i]) for i in ordered[:top_k]]



def main():

  parser = argparse.ArgumentParser(
      formatter_class=argparse.ArgumentDefaultsHelpFormatter)
  parser.add_argument(
      '--model', help='File path of .tflite file.', required=True)
  parser.add_argument(
      '--labels', help='File path of labels file.', required=True)
  args = parser.parse_args()

  labels = load_labels(args.labels)

  #interpreter = tf.lite.Interpreter(args.model)
  interpreter = Interpreter(args.model)

  interpreter.allocate_tensors()
  _, height, width, _ = interpreter.get_input_details()[0]['shape']

  #with picamera.PiCamera(resolution=(640, 480), framerate=30) as camera:
    #camera.start_preview()

  cap = cv2.VideoCapture(0)
  #擷取畫面 寬度 設定為640
  cap.set(cv2.CAP_PROP_FRAME_WIDTH,640)
  #擷取畫面 高度 設定為480
  cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

  key_detect = 0
  times=1
  while (key_detect==0):
    ret,image_src =cap.read(0)

    frame_width=image_src.shape[1]
    frame_height=image_src.shape[0]

    cut_d=int((frame_width-frame_height)/2)
    crop_img=image_src[0:frame_height,cut_d:(cut_d+frame_height)]

    image=cv2.resize(crop_img,(224,224),interpolation=cv2.INTER_AREA)

    start_time = time.time()
    if (times==1):
      results = classify_image(interpreter, image)
      elapsed_ms = (time.time() - start_time) * 1000
      label_id, prob = results[0]

      print(labels[label_id],prob)
      num=int(label_id)
        cv2.putText(crop_img,labels[label_id] + " " + str(round(prob,3)), (5,30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 1, cv2.LINE_AA)

    times=times+1
    if (times>1):
      times=1

    cv2.imshow('Detecting....',crop_img)



    if cv2.waitKey(1) & 0xFF == ord('q'):
      key_detect = 1

  cap.release()
  cv2.destroyAllWindows()

if __name__ == '__main__':
  main()

以上基于tenserflow,tenserflow适合在树莓派上跑,但是如果数据集过大就会崩溃(我们就是因为这个原因,止步于省赛)建议数据集采样图片时控制在2000张左右,不然会崩


三、上下位机通信方式:

1.高低电平通信:

   最开始因为下位机仅仅需要接受树莓派识别结果,而结果种类只有四种,于是乎最开始想到的是:树莓派往gpio写高低电平,stm32浮空输入电平结果,通过排列组合进行通信。源码如下:

	communicate.h:
	#define Type_2  PEin(10)// PF13
	#define Type_3  PEin(11)// PF14
	#define Type_4  PEin(12)// PF15
	#define Type_5  PEin(13)// PF16

	#define  Nothing                     0
	#define  hazardous_waste      1
	#define  other_waste              2
	#define  Recyclable_waste     3
	#define  Kitchen_waste          4

	void communicate_Init(void);//初始化
	int  adjust(void);


	communicate.c:

	void communicate_Init(void)
	{
 
	 GPIO_InitTypeDef  GPIO_InitStructure;
 	
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);	
 	 //使能PB,PE端口时钟
	
 	GPIO_InitStructure.GPIO_Pin =GPIO_Pin_10 |GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13;				 	
 	//LED0-->PB.5 端口配置
 	GPIO_InitStructure.GPIO_Mode =   GPIO_Mode_IN_FLOATING; 	
 		 //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	
	 	 //IO口速度为50MHz
 	GPIO_Init(GPIOE, &GPIO_InitStructure);					
 	 //根据设定参数初始化GPIOB.5
 	GPIO_SetBits(GPIOE,GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13);						
 	 //PB.5 输出高
	}

	int adjust(void){//判断函数
	  delay_ms(10);//防抖
    if(Type_2==0&&Type_3==1&&Type_4==1&&Type_5==1)//第一个树莓派io输出低电平为可回收
    return Recyclable_waste;
		if(Type_2==1&&Type_3==0&&Type_4==1&&Type_5==1)//第二个io输出低电平为有害垃圾
    return hazardous_waste;
    if(Type_2==1&&Type_3==1&&Type_4==0&&Type_5==1)//第三个输出低电平为其他
    return other_waste;
		if(Type_2==1&&Type_3==1&&Type_4==1&&Type_5==0)//第四个输出低电平为厨余垃圾
    return Kitchen_waste;
		return 0;
	}

1.2高低电平树莓派部分:

	GPIO.setmode(GPIO.BCM)
    GPIO.setup(2,GPIO.OUT)
    GPIO.setup(3,GPIO.OUT)
    GPIO.setup(4,GPIO.OUT)
    GPIO.setup(17,GPIO.OUT)

    if num == 0:
        GPIO.output(2,GPIO.HIGH)
        GPIO.output(3,GPIO.HIGH)
        GPIO.output(4,GPIO.HIGH)
        GPIO.output(17,GPIO.HIGH)
        print('')

    elif num == 1:
        GPIO.output(2,GPIO.LOW)
        GPIO.output(3,GPIO.HIGH)
        GPIO.output(4,GPIO.HIGH)
        GPIO.output(17,GPIO.HIGH)
        print('可回收垃圾')

    elif num == 2:
        GPIO.output(2,GPIO.HIGH)
        GPIO.output(3,GPIO.LOW)
        GPIO.output(4,GPIO.HIGH)
        GPIO.output(17,GPIO.HIGH)
        print('有害垃圾')

    elif num == 3:
        GPIO.output(2,GPIO.HIGH)
        GPIO.output(3,GPIO.HIGH)
        GPIO.output(4,GPIO.LOW)
        GPIO.output(17,GPIO.HIGH)
        print('其他垃圾')

    elif num == 4:
        GPIO.output(2,GPIO.HIGH)
        GPIO.output(3,GPIO.HIGH)
        GPIO.output(4,GPIO.HIGH)
        GPIO.output(17,GPIO.LOW)
        print('厨余垃圾')

    else:
        GPIO.output(2,GPIO.HIGH)
        GPIO.output(3,GPIO.HIGH)
        GPIO.output(4,GPIO.HIGH)
        GPIO.output(17,GPIO.HIGH)

2.stm32串口通信部分:

void usb_communicate(void){
  u16 t;
	u16 len;
	if(USART_RX_STA&0x8000){//防抖
				delay_ms(100);
		    delay_ms(100);

  if(USART_RX_STA&0x8000)
		{					   
			len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
			printf("\r\n您发送的消息为:\r\n\r\n");
			for(t=0;t<len;t++)
			{
				USART_SendData(USART1, USART_RX_BUF[t]);//向串口1发送数据
				while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
			}

			
		}
		
}

}



int USB_adjust(void){
    usb_communicate();
	 if(USART_RX_BUF[0]=='0'){
		 USART_RX_STA=0;
		 return Nothing  ;//没有垃圾
	 }
   if(USART_RX_BUF[0]=='1'){
		 		USART_RX_STA=0;
		return  Recyclable_waste ;
	                         }//可回收
	 if(USART_RX_BUF[0]=='2'){
		 		USART_RX_STA=0;
		 	 return hazardous_waste ;
		}//有害
	  if(USART_RX_BUF[0]=='3'){
				USART_RX_STA=0;
		 return  other_waste;}//可回收垃圾
		if(USART_RX_BUF[0]=='4'){
				USART_RX_STA=0;
		return Kitchen_waste;}//厨余垃圾
				USART_RX_STA=0;
   return EOF;//错误标志位
}


四、下位机电机驱动部分

1.电机:涡轮蜗杆电机(履带负载较大,不可直接用步进直流电机)

驱动:l298N(12V)

//.h
#ifndef __MOTOR_H
#define __MOTOR_H	 
#include "sys.h"

#define IN_1 PFout(1)// PB5
#define IN_2 PFout(2)// PE5	
#define IN_3 PFout(3)// PB5
#define IN_4 PFout(4)// PE5	


#define ZHENGXIANG  0
#define FANXIANG    1
#define STOP        2

void motor_Init(void);//初始化
void zongxiang_run(u16 model);
void hengxiang_run(u16 model);
void _delay_s(u16 s);	

void  stop(void);
void  Recyclable_waste_work(void);//可回收3号
void   hazardous_waste_work(void);//有害垃圾1号
void   other_waste_waste_work(void);//其他垃圾2号
void  Kitchen_waste_waste_work(void);//厨余垃圾4号
#endif
//.c
#include "motor.h"
#include "delay.h"


#define ZHENGXIANG  0
#define FANXIANG    1
#define STOP        2
void motor_Init(void)
{
 
 GPIO_InitTypeDef  GPIO_InitStructure;
 	
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE);	 //使能PB,PE端口时钟
	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;				 //LED0-->PB.5 端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
 GPIO_Init(GPIOF, &GPIO_InitStructure);					 //根据设定参数初始化GPIOB.5
 

}

void hengxiang_run(u16 model){
		switch(model){
			case 	ZHENGXIANG : {
			      IN_3=0;
						IN_4=1;
						break;
			}
		  case  FANXIANG :{
			      IN_3=1;
				    IN_4=0;
						break;
			}
		  case  STOP:{
			      IN_3=1;
						IN_4=1;
						break;
			
			}
		
		}
}

 void zongxiang_run(u16 model){
		switch(model){
			case 	ZHENGXIANG : {
			      IN_1=0;
						IN_2=1;
						break;
			}
		  case  FANXIANG :{
			      IN_1=1;
				    IN_2=0;
						break;
			}
		  case  STOP:{
			      IN_1=1;
						IN_2=1;
						break;
			
			}
		
		}
}

void _delay_s(u16 s){
   int i; 
	for(i=0;i<=s;i++)
		delay_ms(1000);


}



void  Recyclable_waste_work(void){//可回收3号

        hengxiang_run(FANXIANG);
        zongxiang_run(FANXIANG);
	      _delay_s(5);
	      zongxiang_run(STOP);
        hengxiang_run(STOP);
        _delay_s(1);

}

void   hazardous_waste_work(void){//有害垃圾1号
	     zongxiang_run(ZHENGXIANG);
	     hengxiang_run(FANXIANG);
	     _delay_s(5);
	     zongxiang_run(STOP);
       hengxiang_run(STOP);
	     _delay_s(1);
	
}

void   other_waste_waste_work(void){//其他垃圾2号
	    hengxiang_run(ZHENGXIANG);
	    zongxiang_run(ZHENGXIANG);
	    _delay_s(5);
	    zongxiang_run(STOP);
      hengxiang_run(STOP);
	    _delay_s(1);
	
}

void  Kitchen_waste_waste_work(void){//厨余垃圾
	    hengxiang_run(ZHENGXIANG);
	    zongxiang_run(FANXIANG);
	    _delay_s(5);
	    zongxiang_run(STOP);
      hengxiang_run(STOP);
	    _delay_s(1);

}
void stop(void){

	      zongxiang_run(STOP);
        hengxiang_run(STOP);

}

2.有关于延时的改进:

   本人在调试时发现keil环境中:delay_ms(1000)和delay_ms(3000)差别不大,竟然有以下发现:

     void _delay_s(u16 s){
   int i; 
	for(i=0;i<=s;i++)
		delay_ms(1000);
}//明显好于s*delay_ms(1000)

3.stm32主函数:

int main(void)
 {	 
//  u16 adcx;
//	float temp;
	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 	//串口初始化为115200
 	LED_Init();			     //LED端口初始化
	LCD_Init();			 	
 	Adc_Init();		  		//ADC初始化

	POINT_COLOR=RED;//设置字体为红色 
	LCD_ShowString(60,50,200,16,16,"Elite STM32");	
	LCD_ShowString(60,70,200,16,16,"ADC TEST");	
	LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
	LCD_ShowString(60,110,200,16,16,"2015/1/14");	
	//显示提示信息
	POINT_COLOR=BLUE;//设置字体为蓝色
	LCD_ShowString(60,130,200,16,16,"ADC_CH0_VAL:");	      
	LCD_ShowString(60,150,200,16,16,"ADC_CH0_VOL:0.000V");	
	 motor_Init();
	while(1)
	{
      if(adjust()){
			  delay_ms(200);
				delay_ms(200);
        
				switch(adjust()){
					case hazardous_waste:{//有害垃圾分类
						hazardous_waste_work();
						_delay_s(5);
					  break;}
				  case other_waste :{//其他垃圾分类
						other_waste_waste_work();
						_delay_s(5);
					  break;}
					case  Recyclable_waste :{//可回收垃圾分类
						Recyclable_waste_work();
						_delay_s(5);
					  break;}
					case  Kitchen_waste :{//厨余垃圾分类
						 Kitchen_waste_waste_work();
						_delay_s(5);
					   break;}
					default :{	//没垃圾				
						stop();
					  break;}

   			}
			}
}
 
} 

五、炸电机:

  在调试过程中,我们炸了六个电机驱动,弄坏了一个步进电机。原因:一夜炸了六个电机驱动,我们依次排查电路接线、程序,最后竟然是电池的原因!!!
这个已经成为传奇

  机械由秦俊酉大力支持;
  视觉部分是吉飞敏提供。

  • 81
    点赞
  • 347
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 44
    评论
工程训练赛中,多垃圾分类是一个常见的任务。参赛者通常会使用不同的硬件设备和训练方法来完成这个任务。例如,有人使用Jetson Nano 4B作为垃圾桶的控制器,使用自己的Win10电脑进行垃圾分类训练\[2\]。在训练过程中,数据集的大小和训练时间是需要考虑的因素。虽然本地训练的数据集没有网站上的20MB限制,但是数据集越大,训练时间就越长。一般来说,迭代次数在60左右,当loss降到0.1左右,accuracy为0.9左右时,模型的效果还算可以\[1\]。此外,为了提高模型的准确性,建议保证光亮的环境下拍摄数据集,并确保各物体数据集之间有明显的差异和丰富的背景\[1\]。 #### 引用[.reference_title] - *1* *3* [第七届工程训练比赛之智能垃圾分类](https://blog.csdn.net/qq_54693299/article/details/115942615)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [第七届全国大学生工程训练大赛智能+赛道生活垃圾分类垃圾训练步骤(win10+yolov4-tiny)](https://blog.csdn.net/qq_43577213/article/details/118420376)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 44
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十六师兄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值