10.阿里云识别垃圾类型项目

阿里云识别垃圾类型项目

1.对接SU-03T语音模块

garbage.c

#include <Python.h>
#include <string.h>
#include "garbage.h"

void garbage_init(void)
{
	Py_Initialize();
    PyObject *sys = PyImport_ImportModule("sys");
	PyObject *path = PyObject_GetAttrString(sys,"path");
    PyList_Append(path,PyUnicode_FromString("."));
}
void garbage_final(void)
{
	Py_Finalize();
}
char *garbage_category(char *category)
{
	PyObject *pModule = PyImport_ImportModule("garbage");
	if(!pModule)
	{
		PyErr_Print();
		printf("Error:failed to load garbage.py\n");
		goto FAILED_MODULE;
	}
	PyObject *pFunc = PyObject_GetAttrString(pModule,"alibaba_garbage");
	if(!pFunc)
	{
		PyErr_Print();
		printf("Error:failed to load funny\n");
		goto FAILED_FUNC;
	}
	PyObject *pValue = PyObject_CallObject(pFunc,NULL);
	if(!pValue){
		PyErr_Print();
		printf("Error:function call failed\n");
		goto FAILED_VALUE;
	}
	char *result = NULL;
	if(!PyArg_Parse(pValue,"s",&result)){
		PyErr_Print();
		printf("Error: parse failed");
		goto FAILED_VALUE;
	}
	printf("result:%s\n",result);
	category = (char *)malloc(sizeof(char)* (strlen(result)+1));
	memset(category,0,strlen(result)+1);
	strcpy(category,result);
FAILED_VALUE:
	Py_DECREF(pValue);
FAILED_FUNC:
	Py_DECREF(pFunc);
FAILED_MODULE:	
	Py_DECREF(pModule);

	return category;
}

garbage.h

#ifndef __GARBAGE__H
#define __GARBAGE__H

void garbage_init(void);
void garbage_final(void);
char *garbage_category(char *category);

#define WGET_CMD	    "wget http://127.0.0.1:8080/?action=snapshot -O /tmp/garbage.jpg"
#define CATEGORY_FILE	"/tmp/garbage.jpg"

#endif

garbage.py

# -*- coding: utf-8 -*-
# 引入依赖包
# pip install alibabacloud_imagerecog20190930

import os
import io
from urllib.request import urlopen
from alibabacloud_imagerecog20190930.client import Client
from alibabacloud_imagerecog20190930.models import ClassifyingRubbishAdvanceRequest
from alibabacloud_tea_openapi.models import Config
from alibabacloud_tea_util.models import RuntimeOptions

config = Config(
  # 创建AccessKey ID和AccessKey Secret,请参考https://help.aliyun.com/document_detail/175144.html。
  # 如果您用的是RAM用户的AccessKey,还需要为RAM用户授予权限AliyunVIAPIFullAccess,请参考https://help.aliyun.com/document_detail/145025.html
  # 从环境变量读取配置的AccessKey ID和AccessKey Secret。运行代码示例前必须先配置环境变量。
  access_key_id=os.environ.get('ALIBABA_CLOUD_ACCESS_KEY_ID'),
  access_key_secret=os.environ.get('ALIBABA_CLOUD_ACCESS_KEY_SECRET'),
  # 访问的域名
  endpoint='imagerecog.cn-shanghai.aliyuncs.com',
  # 访问的域名对应的region
  region_id='cn-shanghai'
)
def alibaba_garbage():
    #场景一:文件在本地
    img = open(r'/tmp/garbage.jpg', 'rb'
)
    #场景二:使用任意可访问的url
    #url = 'http://viapi-test.oss-cn-shanghai.aliyuncs.com/viapi-3.0domepic/imagerecog/ClassifyingRubbish/ClassifyingRubbish1.jpg'
    #img = io.BytesIO(urlopen(url).read())
    classifying_rubbish_request = ClassifyingRubbishAdvanceRequest()
    classifying_rubbish_request.image_urlobject = img
    runtime = RuntimeOptions()
    try:
      # 初始化Client
      client = Client(config)
      response = client.classifying_rubbish_advance(classifying_rubbish_request, runtime)
      # 获取整体结果
      #print(response.body)
      print(response.body.to_map()['Data']['Elements'][0]['Category'])
      return response.body.to_map()['Data']['Elements'][0]['Category']
    except Exception as error:
      return "获取失败"
#if __name__ == "__main__":
#    alibaba_garbage()

uartTool.c

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "wiringSerial.h"

int mySerialOpen (const char *device, const int baud)
{
	struct termios options ;
	speed_t myBaud ;
	int 	status, fd ;
	switch (baud)
	{
		case    9600:	myBaud =    B9600 ; break ;
		case  115200:	myBaud =  B115200 ; break ;
		default:
      		return -2 ;
	}
	if ((fd = open (device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1)
    return -1 ;

  fcntl (fd, F_SETFL, O_RDWR) ;
// Get and modify current options:
  tcgetattr (fd, &options) ;
  cfmakeraw   (&options) ;
  cfsetispeed (&options, myBaud) ;
  cfsetospeed (&options, myBaud) ;
  options.c_cflag |= (CLOCAL | CREAD) ;
  options.c_cflag &= ~PARENB ;
  options.c_cflag &= ~CSTOPB ;
  options.c_cflag &= ~CSIZE ;
  options.c_cflag |= CS8 ;
  options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ;
  options.c_oflag &= ~OPOST ;

  options.c_cc [VMIN]  =   0 ;
  options.c_cc [VTIME] = 100 ;	// Ten seconds (100 deciseconds)
  tcsetattr (fd, TCSANOW, &options) ;
  ioctl (fd, TIOCMGET, &status);
  status |= TIOCM_DTR ;
  status |= TIOCM_RTS ;
  ioctl (fd, TIOCMSET, &status);
  usleep (10000) ;	// 10mS
  return fd ;

}

void serialSendString (const int fd, const unsigned char *s,int len)
{
	int ret;
	ret = write (fd, s, len) ;
	if (ret < 0)
		 printf("Serial Putchar Error\n");
}

int serialGetString (const int fd,unsigned char *buffer)
{
	int n_read;
  	n_read = read (fd,buffer,32);
  	return n_read;
}

uartTool.h

#ifndef __UAERT__H
#define __UAERT__H

int mySerialOpen (const char *device, const int baud);
void serialSendString (const int fd, const unsigned char *s ,int len);
int serialGetString (const int fd,unsigned char *buffer);

#define SERIAL_DEV   "/dev/ttyS5"
#define BAUD		 115200

#endif

main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "uartTool.h"
#include "garbage.h"

static int detect_process(const char * process_name) //判断进程是否在运行
{
	int n = -1;
	FILE *strm;
	char buf[128]={0};
	sprintf(buf,"ps -ax | grep %s|grep -v grep", process_name);
	if((strm = popen(buf, "r")) != NULL)
	{
		if(fgets(buf, sizeof(buf), strm) != NULL)
		{
			n = atoi(buf);
		}
	}else{
		return -1;
	}
	pclose(strm);
	return n;
}

int main(int argc, char *argv[])
{
	int serial_fd = -1;
	int len = 0;
	int ret = -1;
	unsigned char buffer[6] = {0xAA,0x55,0x00,0x00,0x55,0xAA};
	char *category = NULL;
	ret = detect_process("mjpg_streamer");
	if(-1 == ret){
		goto END;
	}
	garbage_init();
	serial_fd = mySerialOpen(SERIAL_DEV,BAUD);
	if(-1 == serial_fd){
		goto END;
	}
	while(1){
		len = serialGetString(serial_fd,buffer);
		printf("len=%d, buf[2]=0x%x\n",len, buffer[2]);
		if(len > 0 && buffer[2] == 0x46){
			buffer[2] = 0x00;
			system(WGET_CMD);
			category = garbage_category(category);
			if(strstr(category,"干垃圾")){
				buffer[2] = 0x41;
			}else if(strstr(category,"湿垃圾")){
				buffer[2] = 0x42;
			}else if(strstr(category,"可回收垃圾")){
				buffer[2] = 0x43;
			}else if(strstr(category,"有害垃圾")){
				buffer[2] = 0x44;
			}else {
				buffer[2] = 0x45;
			}
			
			serialSendString(serial_fd,buffer,6);
			buffer[2] = 0x00;
			remove(CATEGORY_FILE);
		}	
	}
    close(serial_fd);
	END:
		garbage_final();
	
	return 0;
}

编译:

gcc *.c *.h -o test -I /usr/include/python3.10 -l python3.10

2.增加开盖功能

实现功能:使用语音模块和摄像头在香橙派上做垃圾智能分类识别,同时根据识别结果开关不同的垃圾

桶的盖子。

2.1环境准备:

实物图:

垃圾桶粘贴位置示意图:

2.2.代码实现

  • 增加用于实现开光盖(驱动舵机)的源码文件(pwm.c):
#include "wiringPi.h"
#include "softPwm.h"
#include "pwm.h"

//舵机的频率50hz pwmFreq = 1x10^6 /(100xrang) , rang为200步,频率为50hz
void pwm_write(int pwm_pin)
{
    pinMode(pwm_pin,OUTPUT);
    softPwmCreate(pwm_pin,0,200); //rang设置周期为200步,周期20ms
    softPwmWrite(pwm_pin,10);//1ms 45度
    delay(1000);
    softPwmStop(pwm_pin);
}

void pwm_stop (int pwm_pin)
{
    pinMode(pwm_pin,OUTPUT);
    softPwmCreate(pwm_pin,0,200); //rang设置周期为200步,周期20ms
    softPwmWrite(pwm_pin,5);//0.5ms 0度
    delay(1000);
    softPwmStop(pwm_pin);
}

pwm.h

#ifndef __PWM__H
#define __PWM__H

#define PWM_GARBAGE 7
#define PWM_RECOVERABLE_GARBAGE 5

    void pwm_write(int pwm_pin);
    void pwm_stop (int pwm_pin);
#endif
  • main.c里增加调用舵机的控制代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wiringPi.h>
#include <unistd.h>
#include "uartTool.h"
#include "garbage.h"
#include "pwm.h"

static int detect_process(const char * process_name) //判断进程是否在运行
{
	int n = -1;
	FILE *strm;
	char buf[128]={0};
	sprintf(buf,"ps -ax | grep %s|grep -v grep", process_name);
	if((strm = popen(buf, "r")) != NULL)
	{
		if(fgets(buf, sizeof(buf), strm) != NULL)
		{
			n = atoi(buf);
		}
	}else{
		return -1;
	}
	pclose(strm);
	return n;
}

int main(int argc, char *argv[])
{
	int serial_fd = -1;
	int len = 0;
	int ret = -1;
	unsigned char buffer[6] = {0xAA,0x55,0x00,0x00,0x55,0xAA};
	char *category = NULL;
    //外设初始化
	wiringPiSetup();
	garbage_init();
	ret = detect_process("mjpg_streamer");
	if(-1 == ret){
		printf("mjpg_streamer deivce failed!\n");
		goto END;
	}
	serial_fd = mySerialOpen(SERIAL_DEV,BAUD);
	if(-1 == serial_fd){
		goto END;
	}
	while(1){
		len = serialGetString(serial_fd,buffer);
		printf("len=%d, buf[2]=0x%x\n",len, buffer[2]);
		if(len > 0 && buffer[2] == 0x46){
			buffer[2] = 0x00;
			system(WGET_CMD);
			category = garbage_category(category);
			if(strstr(category,"干垃圾")){
				buffer[2] = 0x41;
			}else if(strstr(category,"湿垃圾")){
				buffer[2] = 0x42;
			}else if(strstr(category,"可回收垃圾")){
				buffer[2] = 0x43;
			}else if(strstr(category,"有害垃圾")){
				buffer[2] = 0x44;
			}else {
				buffer[2] = 0x45;
			}
			
			serialSendString(serial_fd,buffer,6);
			if (buffer[2] == 0x43)
			{
				pwm_write(PWM_RECOVERABLE_GARBAGE);
				delay(2000);
				pwm_stop(PWM_RECOVERABLE_GARBAGE);
			}
			else if (buffer[2] != 0x45)
			{
				printf("start\n");
				pwm_write(PWM_GARBAGE);
				delay(2000);
				pwm_stop(PWM_GARBAGE);
			}
			buffer[2] = 0x00;
			remove(CATEGORY_FILE);
		}	
	}
    close(serial_fd);
	END:
		garbage_final();
	
	return 0;
}

编译执行:

gcc *.c *.h -o test -I /usr/include/python3.10 -l python3.10 -lwiringPi
sudo -E ./test #用户执行会保留当前环境变量以及权限,sudo不会去更改权限

编译时报错,需要链接到外设-lwiringPi

/usr/bin/ld: /tmp/ccX9lAkP.o: in function main': main.c:(.text+0x144): undefined reference to wiringPiSetup'
/usr/bin/ld: main.c:(.text+0x2bc): undefined reference to delay' /usr/bin/ld: /tmp/ccs2p2IE.o: in function pwm_write':
pwm.c:(.text+0x14): undefined reference to pinMode' /usr/bin/ld: pwm.c:(.text+0x24): undefined reference to softPwmCreate'
/usr/bin/ld: pwm.c:(.text+0x30): undefined reference to softPwmWrite' /usr/bin/ld: pwm.c:(.text+0x38): undefined reference to delay'
/usr/bin/ld: pwm.c:(.text+0x40): undefined reference to softPwmStop' /usr/bin/ld: /tmp/ccs2p2IE.o: in function pwm_stop':
pwm.c:(.text+0x64): undefined reference to pinMode' /usr/bin/ld: pwm.c:(.text+0x74): undefined reference to softPwmCreate'
/usr/bin/ld: pwm.c:(.text+0x80): undefined reference to softPwmWrite' /usr/bin/ld: pwm.c:(.text+0x88): undefined reference to delay'
/usr/bin/ld: pwm.c:(.text+0x90): undefined reference to `softPwmStop'
collect2: error: ld returned 1 exit status

3.项目代码优化

main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wiringPi.h>
#include <unistd.h>
#include <pthread.h>

#include "uartTool.h"
#include "garbage.h"
#include "pwm.h"

int serial_fd = -1;
pthread_cond_t cond;
pthread_mutex_t mutex;

static int detect_process(const char * process_name) //判断进程是否在运行
{
	int n = -1;
	FILE *strm;
	char buf[128]={0};
	sprintf(buf,"ps -ax | grep %s|grep -v grep", process_name);
	if((strm = popen(buf, "r")) != NULL)
	{
		if(fgets(buf, sizeof(buf), strm) != NULL)
		{
			n = atoi(buf);
		}
	}else{
		return -1;
	}
	pclose(strm);
	return n;
}

void *pget_voice(void *arg)
{
	unsigned char buffer[6] = {0xAA,0x55,0x00,0x00,0x55,0xAA};
	int len = 0;
	printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
	if(-1 == serial_fd){
		printf("%s|%s|%d:open serial failed\n",__FILE__,__func__,__LINE__);
		pthread_exit(0);
	}
	printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
	while(1){
		len = serialGetString(serial_fd,buffer);
		printf("len=%d, buf[2]=0x%x\n",len, buffer[2]);
		if(len > 0 && buffer[2] == 0x46){
			pthread_mutex_lock(&mutex);
			buffer[2] = 0x00;
			pthread_cond_signal(&cond);
			pthread_mutex_unlock(&mutex);
		}
	}
	pthread_exit(0);
}

void *psend_voice(void *arg)
{
	//分离父线程,不需要父线程等待子线程
	pthread_detach(pthread_self());
	unsigned char *buffer = (unsigned char *)arg;
	printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
	if(-1 == serial_fd){
		printf("%s|%s|%d:open serial failed\n",__FILE__,__func__,__LINE__);
		pthread_exit(0);
	}
	if(NULL != buffer){
		printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
		serialSendString(serial_fd,buffer,6);
	}
	pthread_exit(0);
}
void *popen_trash_can(void *arg)
{
	//分离父线程,不需要父线程等待子线程
	pthread_detach(pthread_self());
	unsigned char *buffer = (unsigned char *)arg;
	if (buffer[2] == 0x43)
	{
		printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
		pwm_write(PWM_RECOVERABLE_GARBAGE);
		delay(2000);
		pwm_stop(PWM_RECOVERABLE_GARBAGE);
	}
	else if (buffer[2] != 0x45)
	{
		printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
		printf("start\n");
		pwm_write(PWM_GARBAGE);
		delay(2000);
		pwm_stop(PWM_GARBAGE);
	}
	pthread_exit(0);
}
void *pcategory(void *arg)
{
	unsigned char buffer[6] = {0xAA,0x55,0x00,0x00,0x55,0xAA};
	char *category = NULL;
	pthread_t send_voice_tid, trash_tid;
	while(1){
		printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
		pthread_mutex_lock(&mutex);
		pthread_cond_wait(&cond,&mutex);
		pthread_mutex_unlock(&mutex);

		printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
		buffer[2] = 0x00;
		system(WGET_CMD);
		if(0 == access(CATEGORY_FILE,F_OK)){
			category = garbage_category(category);
			if(strstr(category,"干垃圾")){
				buffer[2] = 0x41;
			}else if(strstr(category,"湿垃圾")){
				buffer[2] = 0x42;
			}else if(strstr(category,"可回收垃圾")){
				buffer[2] = 0x43;
			}else if(strstr(category,"有害垃圾")){
				buffer[2] = 0x44;
			}else {
				buffer[2] = 0x45;
			}
		}
		//开启语音播报线程
		pthread_create(&send_voice_tid,NULL,psend_voice,(void *)buffer);
		//打开垃圾桶
		pthread_create(&trash_tid,NULL,popen_trash_can,(void *)buffer);

		remove(CATEGORY_FILE);
	}
	pthread_exit(0);
}
int main(int argc, char *argv[])
{
	int ret = -1;
	pthread_t send_voice_tid;
	pthread_t category_tid;

	//外设初始化
	wiringPiSetup();
	garbage_init();
	ret = detect_process("mjpg_streamer");
	if(-1 == ret){
		printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
		printf("mjpg_streamer deivce failed!\n");
		goto END;
	}
	serial_fd = mySerialOpen(SERIAL_DEV,BAUD);
	if(-1 == serial_fd){
		printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
		goto END;
	}
	//开语言线程
	pthread_create(&send_voice_tid,NULL,pget_voice,NULL);
	//阿里云识别线程
	pthread_create(&category_tid,NULL,pcategory,NULL);

	pthread_join(send_voice_tid,NULL);
	pthread_join(category_tid,NULL);

	pthread_mutex_destroy(&mutex);
	pthread_cond_destroy(&cond);

	close(serial_fd);
	END:
		garbage_final();
	
	return 0;
}

编译:

gcc *.c *.h -o test -I /usr/include/python3.10 -l python3.10 -lwiringPi -lpthread
sudo -E ./test

4.oled显示

myoled.c

#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>

#include "oled.h"
#include "font.h"
#include "myoled.h"

#define FILENAME  "/dev/i2c-3"
static struct display_info disp;
int oled_show(void *arg) 
{
	unsigned char *buffer = (unsigned char *)arg;
	oled_putstrto(&disp, 0, 9+1, "This garbage is :");
	disp.font = font2;
    switch (buffer[2])
    {
    case 0x41:
        oled_putstrto(&disp, 0, 20, "dry waste");
        break;
    case 0x42:
        oled_putstrto(&disp, 0, 20, "wet waste");
        break;
    case 0x43:
        oled_putstrto(&disp, 0, 20, "recyclable waste");
        break;
    case 0x44:
        oled_putstrto(&disp, 0, 20, "hazardous waste");
        break;
    case 0x45:
        oled_putstrto(&disp, 0, 20, "recognition failed");
        break;
    default:
        break;
    }    
    disp.font = font2;
	oled_send_buffer(&disp);

	return 0;
}

int myoled_init(void)
{
    int e = -1;
	disp.address = OLED_I2C_ADDR;
	disp.font = font2;
	e = oled_open(&disp, FILENAME);
    e = oled_init(&disp);
    return e;
} 

myoled.h

#ifndef __MYOLED__H
#define __MYOLED_H
    int myoled_init(void);
    int oled_show(void *arg);
#endif

main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wiringPi.h>
#include <unistd.h>
#include <pthread.h>

#include "uartTool.h"
#include "garbage.h"
#include "pwm.h"
#include "myoled.h"

int serial_fd = -1;
pthread_cond_t cond;
pthread_mutex_t mutex;

static int detect_process(const char * process_name) //判断进程是否在运行
{
	int n = -1;
	FILE *strm;
	char buf[128]={0};
	sprintf(buf,"ps -ax | grep %s|grep -v grep", process_name);
	if((strm = popen(buf, "r")) != NULL)
	{
		if(fgets(buf, sizeof(buf), strm) != NULL)
		{
			n = atoi(buf);
		}
	}else{
		return -1;
	}
	pclose(strm);
	return n;
}

void *pget_voice(void *arg)
{
	unsigned char buffer[6] = {0xAA,0x55,0x00,0x00,0x55,0xAA};
	int len = 0;
	printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
	if(-1 == serial_fd){
		printf("%s|%s|%d:open serial failed\n",__FILE__,__func__,__LINE__);
		pthread_exit(0);
	}
	printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
	while(1){
		len = serialGetString(serial_fd,buffer);
		printf("len=%d, buf[2]=0x%x\n",len, buffer[2]);
		if(len > 0 && buffer[2] == 0x46){
			pthread_mutex_lock(&mutex);
			buffer[2] = 0x00;
			pthread_cond_signal(&cond);
			pthread_mutex_unlock(&mutex);
		}
	}
	pthread_exit(0);
}

void *psend_voice(void *arg)
{
	//分离父线程,不需要父线程等待子线程
	pthread_detach(pthread_self());
	unsigned char *buffer = (unsigned char *)arg;
	printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
	if(-1 == serial_fd){
		printf("%s|%s|%d:open serial failed\n",__FILE__,__func__,__LINE__);
		pthread_exit(0);
	}
	if(NULL != buffer){
		printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
		serialSendString(serial_fd,buffer,6);
	}
	pthread_exit(0);
}
void *popen_trash_can(void *arg)
{
	//分离父线程,不需要父线程等待子线程
	pthread_detach(pthread_self());
	unsigned char *buffer = (unsigned char *)arg;
	if (buffer[2] == 0x43)
	{
		printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
		pwm_write(PWM_RECOVERABLE_GARBAGE);
		delay(2000);
		pwm_stop(PWM_RECOVERABLE_GARBAGE);
	}
	else if (buffer[2] != 0x45)
	{
		printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
		printf("start\n");
		pwm_write(PWM_GARBAGE);
		delay(2000);
		pwm_stop(PWM_GARBAGE);
	}
	pthread_exit(0);
}

void *pmyoled_show(void *arg)
{
	pthread_detach(pthread_self());
	printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
	unsigned char *buffer = (unsigned char *)arg;
	oled_show(buffer);
	printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
	pthread_exit(0);
}
void *pcategory(void *arg)
{
	unsigned char buffer[6] = {0xAA,0x55,0x00,0x00,0x55,0xAA};
	char *category = NULL;
	pthread_t send_voice_tid, trash_tid,myoled_tid;
	while(1){
		printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
		pthread_mutex_lock(&mutex);
		pthread_cond_wait(&cond,&mutex);
		pthread_mutex_unlock(&mutex);

		printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
		buffer[2] = 0x00;
		system(WGET_CMD);
		if(0 == access(CATEGORY_FILE,F_OK)){
			//category = garbage_category(category);
			category = "可回收垃圾";
			if(strstr(category,"干垃圾")){
				buffer[2] = 0x41;
			}else if(strstr(category,"湿垃圾")){
				buffer[2] = 0x42;
			}else if(strstr(category,"可回收垃圾")){
				buffer[2] = 0x43;
			}else if(strstr(category,"有害垃圾")){
				buffer[2] = 0x44;
			}else {
				buffer[2] = 0x45;
			}
		}
		//开启语音播报线程
		pthread_create(&send_voice_tid,NULL,psend_voice,(void *)buffer);
		//打开垃圾桶
		pthread_create(&trash_tid,NULL,popen_trash_can,(void *)buffer);
		//oled显示
		pthread_create(&myoled_tid,NULL,pmyoled_show,(void *)buffer);
		remove(CATEGORY_FILE);
	}
	pthread_exit(0);
}
int main(int argc, char *argv[])
{
	int ret = -1;
	pthread_t send_voice_tid;
	pthread_t category_tid;

	//外设初始化
	wiringPiSetup();
	//阿里云垃圾识别初始化
	garbage_init();
	//oled初始化
	ret = myoled_init();
	if(-1 == ret){
		printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
		printf("myoled_init failed!\n");
		goto END;
	}
	ret = detect_process("mjpg_streamer");
	if(-1 == ret){
		printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
		printf("mjpg_streamer deivce failed!\n");
		goto END;
	}
	serial_fd = mySerialOpen(SERIAL_DEV,BAUD);
	if(-1 == serial_fd){
		printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
		goto END;
	}
	//开语言线程
	pthread_create(&send_voice_tid,NULL,pget_voice,NULL);
	//阿里云识别线程
	pthread_create(&category_tid,NULL,pcategory,NULL);

	pthread_join(send_voice_tid,NULL);
	pthread_join(category_tid,NULL);

	pthread_mutex_destroy(&mutex);
	pthread_cond_destroy(&cond);

	close(serial_fd);
	END:
		garbage_final();
	
	return 0;
}

编译:

gcc *.c *.h -o test -I /usr/include/python3.10 -l python3.10 -lwiringPi -lpthread
sudo -E ./test

5.增加网络功能

5.1.TCP心跳机制解决Soket异常断开问题

Socket客户端得断开情形无非就两种情况:

​ 1.客户端能够发送状态给服务器;正常断开,强制关闭客户端等,客户端能够做出反应。

​ 2.客户端不能发送状态给服务器;突然断网,断电,客户端卡死等,客户端根本没机会做出反应,服

​ 务器更不了解客户端状态,导致服务器异常等待。

为了解决上述问题,引入TCP心跳包机制:

​ 心跳包的实现,心跳包就是服务器定时向客户端发送查询信息,如果客户端有回应就代表连接正常,

类似于linux系统的看门狗机制。心跳包的机制有一种方法就是采用TCP_KEEPALIVE机制,它是一种用于

检测TCP连接是否存活的机制,它的原理是在一定时间内没有数据往来时,发送探测包给对方,如果对方

没有响应,就认为连接已经断开。TCP_KEEPALIVE机制可以通过设置一些参数来调整,如探测时间间

隔、探测次数等。

Linux内核提供了通过sysctl命令查看和配置TCP KeepAlive参数的方法。

  • 查看当前系统的TCP KeepAlive参数
sysctl net.ipv4.tcp_keepalive_time 
sysctl net.ipv4.tcp_keepalive_probes 
sysctl net.ipv4.tcp_keepalive_intvl
  • 修改TCP KeepAlive参数
sysctl net.ipv4.tcp_keepalive_time=3600

5.2.C语言实现TCP KeepAlive功能

对于Socket而言,可以在程序中通过socket选项开启TCP KeepAlive功能,并配置参数。对应的Socket选

项分别为 SO_KEEPALIVETCP_KEEPIDLETCP_KEEPCNTTCP_KEEPINTVL

发送心跳包实现:

int keepalive = 1; // 开启TCP KeepAlive功能
int keepidle = 5; // tcp_keepalive_time 3s内没收到数据开始发送心跳包
int keepcnt = 3; // tcp_keepalive_probes 每次发送心跳包的时间间隔,单位秒
int keepintvl = 3; // tcp_keepalive_intvl 每3s发送一次心跳包

setsockopt(c_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive,
sizeof(keepalive));
setsockopt(c_fd, SOL_TCP, TCP_KEEPIDLE, (void *) &keepidle, sizeof
(keepidle));
setsockopt(c_fd, SOL_TCP, TCP_KEEPCNT, (void *)&keepcnt, sizeof
(keepcnt));
setsockopt(c_fd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepintvl, sizeof
(keepintvl));

5.3.使用心跳包进行代码实现:

socket.c

#include "socket.h"

int socket_init(const char *ipaddr,const char *ipport)
{
    int s_fd = -1;
    int ret = -1;
    struct sockaddr_in s_addr;
    memset(&s_addr,0,sizeof(struct sockaddr_in));

    //1.socket
    s_fd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == s_fd){
        perror("socket");
        return -1;
    }

    s_addr.sin_family = AF_INET;
    s_addr.sin_port = htons(atoi(ipport));
    inet_aton(ipaddr,&s_addr.sin_addr);
    //2.bind
    ret = bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
    if(-1 == ret){
        perror("bind");
        return -1;
    }

    //3.listen
    ret = listen(s_fd,1);
    if(-1 == ret){
        perror("listen");
        return -1;
    }
    return s_fd;
}

socket.h

#ifndef __SOCKET__H
#define __SOCKET__H
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <errno.h>
#define IPADDR "192.168.4.129" //填写自己实际的ip地址
#define IPPORT "8989"
#define BUF_SIZE 6
    int socket_init(const char *ipaddr, const char *ipport);
#endif

main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wiringPi.h>
#include <unistd.h>
#include <pthread.h>

#include "uartTool.h"
#include "garbage.h"
#include "pwm.h"
#include "myoled.h"
#include "socket.h"

int serial_fd = -1;
pthread_cond_t cond;
pthread_mutex_t mutex;

static int detect_process(const char * process_name) //判断进程是否在运行
{
	int n = -1;
	FILE *strm;
	char buf[128]={0};
	sprintf(buf,"ps -ax | grep %s|grep -v grep", process_name);
	if((strm = popen(buf, "r")) != NULL)
	{
		if(fgets(buf, sizeof(buf), strm) != NULL)
		{
			n = atoi(buf);
		}
	}else{
		return -1;
	}
	pclose(strm);
	return n;
}

void *pget_voice(void *arg)
{
	unsigned char buffer[6] = {0xAA,0x55,0x00,0x00,0x55,0xAA};
	int len = 0;
	printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
	if(-1 == serial_fd){
		printf("%s|%s|%d:open serial failed\n",__FILE__,__func__,__LINE__);
		pthread_exit(0);
	}
	printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
	while(1){
		len = serialGetString(serial_fd,buffer);
		printf("len=%d, buf[2]=0x%x\n",len, buffer[2]);
		if(len > 0 && buffer[2] == 0x46){
			pthread_mutex_lock(&mutex);
			buffer[2] = 0x00;
			pthread_cond_signal(&cond);
			pthread_mutex_unlock(&mutex);
		}
	}
	pthread_exit(0);
}

void *psend_voice(void *arg)
{
	//分离父线程,不需要父线程等待子线程
	pthread_detach(pthread_self());
	unsigned char *buffer = (unsigned char *)arg;
	printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
	if(-1 == serial_fd){
		printf("%s|%s|%d:open serial failed\n",__FILE__,__func__,__LINE__);
		pthread_exit(0);
	}
	if(NULL != buffer){
		printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
		serialSendString(serial_fd,buffer,6);
	}
	pthread_exit(0);
}
void *popen_trash_can(void *arg)
{
	//分离父线程,不需要父线程等待子线程
	pthread_detach(pthread_self());
	unsigned char *buffer = (unsigned char *)arg;
	if (buffer[2] == 0x43)
	{
		printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
		pwm_write(PWM_RECOVERABLE_GARBAGE);
		delay(2000);
		pwm_stop(PWM_RECOVERABLE_GARBAGE);
	}
	else if (buffer[2] != 0x45)
	{
		printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
		pwm_write(PWM_GARBAGE);
		delay(2000);
		pwm_stop(PWM_GARBAGE);
	}
	pthread_exit(0);
}

void *pmyoled_show(void *arg)
{
	pthread_detach(pthread_self());
	printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
	unsigned char *buffer = (unsigned char *)arg;
	//oled初始化
	if(-1 == myoled_init()){
		printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
		printf("myoled_init failed!\n");
	}
	oled_show(buffer);
	printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);
	pthread_exit(0);
}
void *pcategory(void *arg)
{
	unsigned char buffer[6] = {0xAA,0x55,0x00,0x00,0x55,0xAA};
	char *category = NULL;
	pthread_t send_voice_tid, trash_tid,myoled_tid;
	while(1){
		printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
		pthread_mutex_lock(&mutex);
		pthread_cond_wait(&cond,&mutex);
		pthread_mutex_unlock(&mutex);

		printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
		buffer[2] = 0x00;
		system(WGET_CMD);
		if(0 == access(CATEGORY_FILE,F_OK)){
			//category = garbage_category(category);
			category = "湿垃圾";
			if(strstr(category,"干垃圾")){
				buffer[2] = 0x41;
			}else if(strstr(category,"湿垃圾")){
				buffer[2] = 0x42;
			}else if(strstr(category,"可回收垃圾")){
				buffer[2] = 0x43;
			}else if(strstr(category,"有害垃圾")){
				buffer[2] = 0x44;
			}else {
				buffer[2] = 0x45;
			}
		}
		//开启语音播报线程
		pthread_create(&send_voice_tid,NULL,psend_voice,(void *)buffer);
		//打开垃圾桶
		pthread_create(&trash_tid,NULL,popen_trash_can,(void *)buffer);
		//oled显示
		pthread_create(&myoled_tid,NULL,pmyoled_show,(void *)buffer);
		remove(CATEGORY_FILE);
	}
	pthread_exit(0);
}
void *pget_socket(void *arg){
	int s_fd = -1;
	int c_fd = -1;
	char buffer[6];
	int n_read = -1;
	struct sockaddr_in c_addr;
	s_fd = socket_init(IPADDR,IPPORT);
	int len = sizeof(struct sockaddr_in);
	while(1){
		c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&len);

		int keepalive = 1; // 开启TCP KeepAlive功能
		int keepidle = 5; // tcp_keepalive_time 3s内没收到数据开始发送心跳包
		int keepcnt = 3; // tcp_keepalive_probes 每次发送心跳包的时间间隔,单位秒
		int keepintvl = 3; // tcp_keepalive_intvl 每3s发送一次心跳包

		setsockopt(c_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive,
		sizeof(keepalive));
		setsockopt(c_fd, SOL_TCP, TCP_KEEPIDLE, (void *) &keepidle, sizeof
		(keepidle));
		setsockopt(c_fd, SOL_TCP, TCP_KEEPCNT, (void *)&keepcnt, sizeof
		(keepcnt));
		setsockopt(c_fd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepintvl, sizeof
		(keepintvl));

		printf("%s|%s|%d: Accept a connection from %s:%d\n", __FILE__, __func__,
__LINE__, inet_ntoa(c_addr.sin_addr), ntohs(c_addr.sin_port));
		if(-1 == c_fd){
			perror("accept");
			continue;
		}
		while (1)
		{
			memset(buffer,0,sizeof(buffer));
			n_read = recv(c_fd,buffer,sizeof(buffer),0);
			if(n_read > 0){
				if(strstr(buffer,"open")){
					pthread_mutex_lock(&mutex);
					pthread_cond_signal(&cond);
					pthread_mutex_unlock(&mutex);
				}
			}else if( 0 == n_read || -1 == n_read){
				break;
			}
		}
		close(c_fd);
	}
	pthread_exit(0);
}

int main(int argc, char *argv[])
{
	int ret = -1;
	pthread_t send_voice_tid;
	pthread_t category_tid;
	pthread_t socket_tid;

	//外设初始化
	wiringPiSetup();
	//阿里云垃圾识别初始化
	garbage_init();

	ret = detect_process("mjpg_streamer");
	if(-1 == ret){
		printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
		printf("mjpg_streamer deivce failed!\n");
		goto END;
	}
	serial_fd = mySerialOpen(SERIAL_DEV,BAUD);
	if(-1 == serial_fd){
		printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
		goto END;
	}
	//开语言线程
	pthread_create(&send_voice_tid,NULL,pget_voice,NULL);
	//阿里云识别线程
	pthread_create(&category_tid,NULL,pcategory,NULL);
	//网络服务线程
	pthread_create(&socket_tid,NULL,pget_socket,NULL);

	pthread_join(send_voice_tid,NULL);
	pthread_join(category_tid,NULL);
	pthread_join(socket_tid,NULL);

	pthread_mutex_destroy(&mutex);
	pthread_cond_destroy(&cond);

	close(serial_fd);
	END:
		garbage_final();
	
	return 0;
}

编译:

gcc *.c *.h -o test -I /usr/include/python3.10 -l python3.10 -lwiringPi -lpthread
sudo -E ./test
posted @ 2025-05-29 11:25  站着说话不腰疼  阅读(34)  评论(0)    收藏  举报