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 towiringPiSetup'
/usr/bin/ld: main.c:(.text+0x2bc): undefined reference todelay' /usr/bin/ld: /tmp/ccs2p2IE.o: in functionpwm_write':
pwm.c:(.text+0x14): undefined reference topinMode' /usr/bin/ld: pwm.c:(.text+0x24): undefined reference tosoftPwmCreate'
/usr/bin/ld: pwm.c:(.text+0x30): undefined reference tosoftPwmWrite' /usr/bin/ld: pwm.c:(.text+0x38): undefined reference todelay'
/usr/bin/ld: pwm.c:(.text+0x40): undefined reference tosoftPwmStop' /usr/bin/ld: /tmp/ccs2p2IE.o: in functionpwm_stop':
pwm.c:(.text+0x64): undefined reference topinMode' /usr/bin/ld: pwm.c:(.text+0x74): undefined reference tosoftPwmCreate'
/usr/bin/ld: pwm.c:(.text+0x80): undefined reference tosoftPwmWrite' /usr/bin/ld: pwm.c:(.text+0x88): undefined reference todelay'
/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_KEEPALIVE 、 TCP_KEEPIDLE 、 TCP_KEEPCNT 、 TCP_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

浙公网安备 33010602011771号