STM32
直播中

is.milk

12年用户 494经验值
私信 关注
[问答]

垃圾分类系统机械结构是怎样去设计的

垃圾分类系统机械结构是怎样去设计的?
垃圾分类系统的上下位机是如何进行通信的?

回帖(2)

王凤英

2021-12-22 16:03:51
一、机械结构设计

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) 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 u***_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("rn您发送的消息为:rnrn");
                        for(t=0;t                         {
                                USART_SendData(USART1, USART_RX_BUF[t]);//向串口1发送数据
                                while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
                        }


                       
                }
               
}


}






int USB_adjust(void){
    u***_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;//错误标志位
}


提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。
四、下位机电机驱动部分

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);


}
举报

李霞

2021-12-22 16:04:03
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;}


                           }
                        }
}

}
五、炸电机:

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

更多回帖

×
20
完善资料,
赚取积分