基于Linux的垃圾分类项目
功能需求
-
语音接入控制垃圾分类识别,并触发垃圾桶的开关盖
-
回顾二阶段的Socket编程,实现Sockect发送指令远程控制垃圾分类识别,并触发垃圾桶的开关盖
-
图像识别垃圾分类功能
-
语音播报垃圾物品类型
-
OLED显示垃圾物品类型
-
根据垃圾类型开关不同类型垃圾桶
图像处理使用阿里SDK支持Python和Java接口,目的是引入C语言的Python调用,感受大厂做的算法bug。
此接口是人工智能接口,阿里云识别模型是通过训练后的模型,精准度取决于训练程度,人工智能范畴 在常规嵌入式设备负责执行居多。
说白的嵌入式设备负责数据采集,然后转发给人工智能识别后,拿到结果进行执行器动作。
阿里云垃圾识别方案
接入阿里云
在垃圾分类的项目中,我们采用阿里云视觉智能开发平台的接口来做垃圾分类的识别方案,通过上传 本地的拍照下的垃圾图片,通过阿里提供的接口来识别出该垃圾是干垃圾、湿垃圾、回收垃圾还是有害 垃圾。
对应官网地址如下:
https://vision.aliyun.com/
然后在上面的输入框输入“垃圾分类”:
可以跳转到对应的垃圾分类的“免费开通"和”技术文档页面“:
能力展示-阿里云视觉智能开放平台 (aliyun.com)
可以先选择"技术文档"查看下使用方法:
根据上面描述的指引,蓝色为可点进去的详细说明,完成注册及运行环境的搭建。
重点:
- 开通阿里云账号及图像识别服务,用自己支付宝即可开通。
- 创建并获取AccessKey ID和Secret。
- 在Linux或开发板上安装所需的SDK。
- 根据示例代码进行修改垃圾分类识别。
- 选择免费开通,通过自己的支付宝或者账号登录即可。
- 登录完成后,即可在产品控制台->点击获取Acce Token获取 对应的AccessKey ID和AccessKey Secret
当然,在第一次获取到AccessKey ID和AccessKey Secret,需要点击创建AccessKey, 然后最好把 AccessKey.csv下载下来备份,不然会找不到AccessKey Secret就需要重新创建。
- 在ubuntu 22.04或者众志开发板(orangepi 3.0.6)上安装图像识别(imagerecog)SDK
sudo apt install python3-pip
pip3 install alibabacloud_imagerecog20190930
- 同时配置Linux环境,根据自己实际的ACCESS_KEY_ID和ACCESS_KEY_SECRET,下面的两行写入到家目 录下的.bashrc中:
export ALIBABA_CLOUD_ACCESS_KEY_ID=“你的ID” #根据自己实际的ID填写
export ALIBABA_CLOUD_ACCESS_KEY_SECRET="你的SECRET" #根据自己实际的SECRET填写
vi ~/.bashrc 和 /etc/profile #然后在末尾输入上面两行后保存
- 然后退出终端重新登录下,此时再执行export,能看到这两个Key的存在。
- 抄袭”文件在本地或文件不在同一地域OSS“示例代码,命名为rubbish.py。
- 同时将场景二注释,场景一代码打开,并输入自己测试图片的路径,如下:
rubbish.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 alicloud_classify_Rubbish():
#场景一:文件在本地
img = open(r'/home/orangepi/Project/rubbish/test.jpg', 'rb')
#场景二:使用任意可访问的url
#url = 'https://viapi-test-bj.oss-cn-beijing.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)
return response.body.to_map()['Data']['Elements'][0]['Category']
except Exception as error:
# 获取整体报错信息
print(error)
# 获取单个字段
print(error.code)
if __name__ == "__main__":
alicloud_classify_Rubbish()
其中 "/home/orangepi/Project/rubbish/test.jpg"
为本地测试用图片(根据在线文档要求:图像类型:JPEG、JPG、PNG,图像大小:不大于3 MB,图像分辨率:不限制图像分辨率,但图像分辨率太高可能会导致API识别超时,超时时间为5秒) 测试图片如下:
然后用 python3 rubbish.py
命令测试运行:
orangepi@orangepizero2:~/Project/rubbish$ python3 rubbish.py
{'Data': {'Elements': [{'Category': '干垃圾', 'CategoryScore': 0.9020999999999999, 'Rubbish': '', 'RubbishScore': 0.0}], 'Sensitive': False}, 'RequestId': '75252D93-CF27-59CB-90A9-5F66D5D929BF'}
如上,测试成功,说明阿里云垃圾分类方案对接成功。
C语言调用阿里云Python接口
rubbish.py
采用上面的代码。
rubbish.c
参照有参python函数的做法, 实封装并现以下代码(rubbish.c):
#include <Python.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void rubbish_Init(void)
{
Py_Initialize();
PyObject *sys = PyImport_ImportModule("sys");
PyObject *path = PyObject_GetAttrString(sys, "path");
PyList_Append(path, PyUnicode_FromString("."));
}
void rubbish_Finalize(void)
{
Py_Finalize();
}
char *alicloud_rubbish_category(char *category)
{
PyObject *pModule = PyImport_ImportModule("rubbish");
if (!pModule)
{
PyErr_Print();
printf("Error: failed to load rubbish.py\n");
goto FAILED_MODULE;
}
PyObject *pFunc = PyObject_GetAttrString(pModule, "alicloud_classify_Rubbish");
if (!pFunc)
{
PyErr_Print();
printf("Error: failed to load classify_Rubbish\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\n");
goto FAILED_RESULT;
}
category = (char *)malloc(sizeof(char) * (strlen(result) + 1));
memset(category, '\0', (strlen(result) + 1));
strncpy(category, result, (strlen(result) + 1));
FAILED_RESULT:
Py_DECREF(pValue);
FAILED_VALUE:
Py_DECREF(pFunc);
FAILED_FUNC:
Py_DECREF(pModule);
FAILED_MODULE:
return category;
}
rubbish.h
头文件(rubbish.h)如下:
#ifndef _RUBBISH_H
#define _RUBBISH_H
void rubbish_Init(void);
void rubbish_Finalize(void);
char *alicloud_rubbish_category(char *category);
#endif
main.c
测试代码(main.c)如下:
#include <stdio.h>
#include <stdlib.h>
#include "rubbish.h"
int main()
{
char *category = NULL;
garbage_init();
category = rubbish_category(category);
printf("category=%s\n", category);
rubbish_Finalize();
free(category);
return 0;
}
然要编译和运行这个程序,可以使用以下命令(假设使用的是gcc编译器和Python 3.10版本):
gcc -o rubbish main.c rubbish.c rubbish.h -I /usr/include/python3.10/ -lpython3.10 ./garbagetest
输出:
category=干垃圾
香橙派使用摄像头
详细可参考《OrangePi_Zero2_H616用户手册v4.0.pdf》 中的3.13.6 USB摄像头测试章节。
语音模块配置
进入语音模块官网http://www.smartpi.cn/#/,配置词条和识别后的串口输入输出指令,如下:
Pin引脚配置:
唤醒词定义:
控制详情:
语音模块和阿里云结合
环境准备
将语音模块接在UART5的位置。
在orange pi 3.0.6上确认已经配置开启了uart5:(overlays=uart5)
orangepi@orangepizero2:~/garbage$ cat /boot/orangepiEnv.txt
verbosity=1
bootlogo=false
console=both
disp_mode=1920x1080p60
overlay_prefix=sun50i-h616
rootdev=UUID=15a0010c-94e1-412f-b030-199e90c16cb1
rootfstype=ext4
overlays=uart5 i2c3
usbstoragequirks=0x2537:0x1066:u,0x2537:0x1068:u
同时将USB摄像头接到香橙派上,确认已经运行了mjpg-streamer服务
orangepi@orangepizero2:~/garbage$ ps ax | grep mjpg
rubbish.py
同上
加入mySerial.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>
int my_serialOpen (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 my_serialPuts(const int fd, const char *s, int len)
{
int n_write = write(fd, s, len);
if(n_write == -1)
{
perror("write");
exit(-1);
}
}
int my_serialGets(const int fd, unsigned char *buffer)
{
int n_read = read(fd, buffer, 32);
if(n_read == -1)
{
perror("read");
exit(-1);
}
return n_read;
}
char* serialGetchar (const int fd)
{
char *x;
if (read (fd, x, 1) != 1)
exit(-1);
return x;
}
mySerial.h
#ifndef _MYSERIAL_H_
#define _MYSERIAL_H_
#define SERIAL_DEV "/dev/ttyS5"
#define BAUD 115200
int my_serialOpen (const char *device, const int baud);
void my_serialPuts(const int fd, unsigned char *s, int len);
int my_serialGets(const int fd, const char *buffer);
char* serialGetchar(const int fd);
#endif
rubbish.c
#include <Python.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void rubbish_Init(void)
{
Py_Initialize();
PyObject *sys = PyImport_ImportModule("sys");
PyObject *path = PyObject_GetAttrString(sys, "path");
PyList_Append(path, PyUnicode_FromString("."));
}
void rubbish_Finalize(void)
{
Py_Finalize();
}
char *alicloud_rubbish_category(char *category)
{
PyObject *pModule = PyImport_ImportModule("rubbish");
if (!pModule)
{
PyErr_Print();
printf("Error: failed to load rubbish.py\n");
goto FAILED_MODULE;
}
PyObject *pFunc = PyObject_GetAttrString(pModule, "alicloud_classify_Rubbish");
if (!pFunc)
{
PyErr_Print();
printf("Error: failed to load classify_Rubbish\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\n");
goto FAILED_RESULT;
}
category = (char *)malloc(sizeof(char) * (strlen(result) + 1));
memset(category, '\0', (strlen(result) + 1));
strncpy(category, result, (strlen(result) + 1));
FAILED_RESULT:
Py_DECREF(pValue);
FAILED_VALUE:
Py_DECREF(pFunc);
FAILED_FUNC:
Py_DECREF(pModule);
FAILED_MODULE:
return category;
}
rubbish.h
#ifndef _RUBBISH_H
#define _RUBBISH_H
#define WGET_CMD "wget http://127.0.0.1:8080/?action=snapshot -O /home/orangepi/Project/rubbish/rubbish.jpg"
#define RUBBISH_FILE "/home/orangepi/Project/rubbish/rubbish.jpg"
void rubbish_Init(void);
void rubbish_Finalize(void);
char *alicloud_rubbish_category(char *category);
#endif
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h> /* Definition of AT_* constants */
#include <unistd.h>
#include "rubbish.h"
#include "mySerial.h"
int detect_process(char *process_name)
{
FILE *file;
int pid;
char cmd[64] = {'\0'};
char buffer[128] = {'\0'};
sprintf(cmd, "ps -ax | grep %s | grep -v grep", process_name);
file = popen(cmd, "r");
if(file != NULL)
{
if(fgets(buffer, sizeof(buffer), file) != NULL)
{
pid = atoi(buffer);
return pid;
}
else
{
return -1;
}
}
else
{
return -1;
}
pclose(file);
return pid;
}
int main()
{
int len = -1;
int serial_fd = -1;
int result_detect_process = -1;
char *category = NULL;
char *ret_strstr = (char *)malloc(1024);
unsigned char buffer[6] = {0xAA, 0x55, 0x00, 0x00, 0x55, 0xAA};
rubbish_Init();
result_detect_process = detect_process("mjpg_streamer");
if(-1 == result_detect_process)
{
perror("detect_process");
goto END;
}
serial_fd = my_serialOpen(SERIAL_DEV, BAUD);
if(-1 == serial_fd)
{
perror("my_serialOpen");
goto END;
}
while(1)
{
len = my_serialGets(serial_fd, buffer);
if(len > 0 && buffer[2] == 0x46)
{
buffer[2] = 0x00;
system(WGET_CMD);
printf("------------------------------------\n");
if(access(RUBBISH_FILE, F_OK) == 0)
{
printf("====================================\n");
category = alicloud_rubbish_category(category);
printf("category = %s\n", category);
if(strstr(category, "干垃圾") != NULL)
{
buffer[2] = 0x41;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
else if(strstr(category, "湿垃圾"))
{
buffer[2] = 0x42;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
else if(strstr(category, "可回收垃圾"))
{
buffer[2] = 0x43;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
else if(strstr(category, "有害垃圾"))
{
buffer[2] = 0x44;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
else
{
buffer[2] = 0x45;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
//printf("ret_strstr = %s\n", ret_strstr);
}
else
{
buffer[2] = 0x45;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
my_serialPuts(serial_fd, buffer, 6);
buffer[2] = 0x00;
remove(RUBBISH_FILE);
}
}
END:
rubbish_Finalize();
return 0;
}
增加垃圾桶及开关盖功能
实现功能:使用语音模块和摄像头在香橙派上做垃圾智能分类识别, 同时根据识别结果开关不同的垃圾桶的盖子。
环境准备
流程图
flowchart LR
B(开始)
B --> C[阿里云Python接口初始化]
C --> D[香橙派 串口初始化]
D --> E{判断是否打开失败}
E --> F[香橙派读取语音模块数据]
F --> G{是否读取到语晋模块AA 5546 00 55 AA数据}
G --> |是| H[香橙派拍照]
G --> |否| F[香橙派读取语音模块数据]
H --> I{判断./rubbish.jpg文件是否存在}
I --> |是| J{执行阿里云垃圾分类接口}
I --> |否| K[写对应的AA 55 45 00 55 AA 串口数据给语音模块 语音摄报]
J --> |是| L[写对应的AA 55 4* 00 55 AA 串口数据给语音模块,语音播报]
J --> |否| F[香橙派读取语音模块数据]
K --> F[香橙派读取语音模块数据]
L --> F[香橙派读取语音模块数据]
pwm.c
#include <wiringPi.h>
#include <softPwm.h>
void pwm_write(int pwm_pin)
{
pinMode(pwm_pin, OUTPUT);
softPwmCreate(pwm_pin, 0, 200);
softPwmWrite(pwm_pin, 25);
delay(1000);
softPwmStop(pwm_pin);
}
void pwm_stop(int pwm_pin)
{
pinMode(pwm_pin, OUTPUT);
softPwmCreate(pwm_pin, 0, 200);
softPwmWrite(pwm_pin, 5);
delay(1000);
softPwmStop(pwm_pin);
}
pwm.h
#ifndef _PWM_H_
#define _PWM_H_
#define PWM_OTHER_RUBBISH 7
#define PWM_RECOVERABLE_RUBBISH 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 <fcntl.h>
#include <unistd.h>
#include <wiringPi.h>
#include "rubbish.h"
#include "mySerial.h"
#include "pwm.h"
int detect_process(char *process_name)
{
FILE *file;
int pid;
char cmd[64] = {'\0'};
char buffer[128] = {'\0'};
sprintf(cmd, "ps -ax | grep %s | grep -v grep", process_name);
file = popen(cmd, "r");
if(file != NULL)
{
if(fgets(buffer, sizeof(buffer), file) != NULL)
{
pid = atoi(buffer);
return pid;
}
else
{
return -1;
}
}
else
{
return -1;
}
pclose(file);
return pid;
}
int main()
{
int len = -1;
int serial_fd = -1;
int result_detect_process = -1;
char *category = NULL;
char *ret_strstr = (char *)malloc(1024);
unsigned char buffer[6] = {0xAA, 0x55, 0x00, 0x00, 0x55, 0xAA};
rubbish_Init();
if (wiringPiSetup() == -1)
{
exit(1);
}
result_detect_process = detect_process("mjpg_streamer");
if(-1 == result_detect_process)
{
perror("detect_process");
goto END;
}
serial_fd = my_serialOpen(SERIAL_DEV, BAUD);
if(-1 == serial_fd)
{
perror("my_serialOpen");
goto END;
}
while(1)
{
len = my_serialGets(serial_fd, buffer);
if(len > 0 && buffer[2] == 0x46)
{
buffer[2] = 0x00;
system(WGET_CMD);
printf("------------------------------------\n");
if(access(RUBBISH_FILE, F_OK) == 0)
{
printf("====================================\n");
category = alicloud_rubbish_category(category);
printf("category = %s\n", category);
if(strstr(category, "干垃圾") != NULL)
{
buffer[2] = 0x41;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
else if(strstr(category, "湿垃圾"))
{
buffer[2] = 0x42;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
else if(strstr(category, "可回收垃圾"))
{
buffer[2] = 0x43;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
else if(strstr(category, "有害垃圾"))
{
buffer[2] = 0x44;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
else
{
buffer[2] = 0x45;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
//printf("ret_strstr = %s\n", ret_strstr);
}
else
{
buffer[2] = 0x45;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
my_serialPuts(serial_fd, buffer, 6);
if(buffer[2] == 0x43)
{
pwm_write(PWM_RECOVERABLE_RUBBISH);
delay(2300);
pwm_stop(PWM_RECOVERABLE_RUBBISH);
}
else if(buffer[2] != 0x45)
{
pwm_write(PWM_OTHER_RUBBISH);
delay(2300);
pwm_stop(PWM_OTHER_RUBBISH);
}
buffer[2] = 0x00;
remove(RUBBISH_FILE);
}
}
END:
rubbish_Finalize();
return 0;
}
项目代码优化
在之前实现的代码中, 主函数是单线程执行的, 导致整个代码的可扩展性非常差,比如想加OLED显示 或者添加网络控制变得非常复杂, 而且执行一次识别开关盖的流程非常长。因此,调整下代码架构,增加并发功能、提升代码的可扩展性 和执行效率。
流程图
main.c
修改 main.c
代码,调整整体 main
函数的代码架构,利用多线程实现具体的功能(用到了线程里的条件变量控制线程间的数据同步)如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <wiringPi.h>
#include "rubbish.h"
#include "mySerial.h"
#include "pwm.h"
int len = -1;
int serial_fd = -1;
pthread_mutex_t mutex;
pthread_cond_t cond;
int detect_process(char *process_name)
{
FILE *file;
int pid;
char cmd[64] = {'\0'};
char buffer[128] = {'\0'};
sprintf(cmd, "ps -ax | grep %s | grep -v grep", process_name);
file = popen(cmd, "r");
if(file != NULL)
{
if(fgets(buffer, sizeof(buffer), file) != NULL)
{
pid = atoi(buffer);
return pid;
}
else
{
return -1;
}
}
else
{
return -1;
}
pclose(file);
return pid;
}
void* send_voice(void *arg)
{
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
pthread_detach(pthread_self());
unsigned char *buffer = (unsigned char *)arg;
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
if(NULL != buffer)
{
my_serialPuts(serial_fd, buffer, 6);
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
}
pthread_exit(0);
}
void* trash_can(void *arg)
{
pthread_detach(pthread_self());
unsigned char *buffer = (unsigned char *)arg;
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
if(buffer[2] == 0x43)
{
pwm_write(PWM_RECOVERABLE_RUBBISH);
delay(2300);
pwm_stop(PWM_RECOVERABLE_RUBBISH);
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
}
else if(buffer[2] != 0x45)
{
pwm_write(PWM_OTHER_RUBBISH);
delay(2300);
pwm_stop(PWM_OTHER_RUBBISH);
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
}
pthread_exit(0);
}
void* get_voice()
{
unsigned char buffer[6] = {0xAA, 0x55, 0x00, 0x00, 0X55, 0xAA};
while(1)
{
len = my_serialGets(serial_fd, buffer);
if(len > 0 && buffer[2] == 0x46)
{
// system(WGET_CMD);
pthread_mutex_lock(&mutex);
buffer[2] = 0x00;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
}
pthread_exit(0);
}
void* get_category()
{
char *category = NULL;
pthread_t send_voice_tid;
pthread_t trash_can_tid;
unsigned char buffer[6] = {0xAA, 0x55, 0x00, 0x00, 0X55, 0xAA};
while(1)
{
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
buffer[2] = 0x00;
system(WGET_CMD);
if(access(RUBBISH_FILE, F_OK) == 0)
{
category = alicloud_rubbish_category(category);
printf("category = %s\n", category);
if(strstr(category, "干垃圾") != NULL)
{
buffer[2] = 0x41;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
else if(strstr(category, "湿垃圾"))
{
buffer[2] = 0x42;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
else if(strstr(category, "可回收垃圾"))
{
buffer[2] = 0x43;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
else if(strstr(category, "有害垃圾"))
{
buffer[2] = 0x44;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
else
{
buffer[2] = 0x45;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
//printf("ret_strstr = %s\n", ret_strstr);
}
else
{
buffer[2] = 0x45;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
if(pthread_create(&send_voice_tid, NULL, send_voice, buffer) != 0)
{
perror("pthread_create1");
exit(-1);
}
if(pthread_create(&trash_can_tid, NULL, trash_can, buffer) != 0)
{
perror("pthread_create2");
exit(-1);
}
remove(RUBBISH_FILE);
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
}
pthread_exit(0);
}
int main()
{
int result_detect_process = -1;
char *ret_strstr = (char *)malloc(1024);
pthread_t get_voice_tid;
pthread_t get_category_tid;
rubbish_Init();
if (wiringPiSetup() == -1)
{
exit(1);
}
result_detect_process = detect_process("mjpg_streamer");
if(-1 == result_detect_process)
{
perror("detect_process");
goto END;
}
serial_fd = my_serialOpen(SERIAL_DEV, BAUD);
if(-1 == serial_fd)
{
perror("my_serialOpen");
goto END;
}
pthread_create(&get_voice_tid, NULL, get_voice, NULL);
pthread_create(&get_category_tid, NULL, get_category, NULL);
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_join(get_voice_tid, NULL);
pthread_join(get_category_tid, NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
close(serial_fd);
END:
rubbish_Finalize();
return 0;
}
增加OLED显示功能
myOLED.c
直接添在rubbish项目中添加2个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"
struct display_info disp;
void oled_show(void *arg)
{
int i;
unsigned char *buffer = (unsigned char *)arg;
oled_putstrto(&disp, 1, 9+1, "Rubbish recognition : ");
disp.font = font2;
oled_send_buffer(&disp);
switch(buffer[2])
{
case 0x41:
oled_putstrto(&disp, 3, 18+2, "dry rubbish");
break;
case 0x42:
oled_putstrto(&disp, 1, 18+2, "wet rubbish");
break;
case 0x43:
oled_putstrto(&disp, 1, 18+2, "recyclable rubbish");
break;
case 0x44:
oled_putstrto(&disp, 1, 18+2, "hazardous rubbish");
break;
case 0x45:
oled_putstrto(&disp, 1, 18+2, "recognition failure");
break;
default:
break;
}
disp.font = font2;
oled_send_buffer(&disp);
disp.font = font3;
for (i = 0; i < 100; i++) {
oled_putstrto(&disp, 135-i, 36+4, "===");
oled_send_buffer(&disp);
}
}
void show_error(int err, int add)
{
printf("\nERROR: %i, %i\n\n", err, add);
}
void myOled_init(void)
{
int e;
disp.address = OLED_I2C_ADDR;
disp.font = font2;
e = oled_open(&disp, FILENAME);
if (e < 0)
{
show_error(1, e);
}
else
{
e = oled_init(&disp);
}
}
myOLED.h
#ifndef _MYOLED_H_
#define _MYOLED_H_
#define FILENAME "/dev/i2c-3"
void oled_show(void *argv);
void myOled_init(void);
#endif
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <wiringPi.h>
#include "rubbish.h"
#include "mySerial.h"
#include "pwm.h"
#include "myOLED.h"
int len = -1;
int serial_fd = -1;
pthread_mutex_t mutex;
pthread_cond_t cond;
int detect_process(char *process_name)
{
FILE *file;
int pid;
char cmd[64] = {'\0'};
char buffer[128] = {'\0'};
sprintf(cmd, "ps -ax | grep %s | grep -v grep", process_name);
file = popen(cmd, "r");
if(file != NULL)
{
if(fgets(buffer, sizeof(buffer), file) != NULL)
{
pid = atoi(buffer);
return pid;
}
else
{
return -1;
}
}
else
{
return -1;
}
pclose(file);
return pid;
}
void* send_voice(void *arg)
{
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
pthread_detach(pthread_self());
unsigned char *buffer = (unsigned char *)arg;
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
if(NULL != buffer)
{
my_serialPuts(serial_fd, buffer, 6);
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
}
pthread_exit(0);
}
void* trash_can(void *arg)
{
pthread_detach(pthread_self());
unsigned char *buffer = (unsigned char *)arg;
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
if(buffer[2] == 0x43)
{
pwm_write(PWM_RECOVERABLE_RUBBISH);
delay(2300);
pwm_stop(PWM_RECOVERABLE_RUBBISH);
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
}
else if(buffer[2] != 0x45)
{
pwm_write(PWM_OTHER_RUBBISH);
delay(2300);
pwm_stop(PWM_OTHER_RUBBISH);
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
}
pthread_exit(0);
}
void* myOled_show(void *arg)
{
pthread_detach(pthread_self());
myOled_init();
oled_show(arg);
pthread_exit(0);
}
void* get_voice()
{
unsigned char buffer[6] = {0xAA, 0x55, 0x00, 0x00, 0X55, 0xAA};
while(1)
{
len = my_serialGets(serial_fd, buffer);
if(len > 0 && buffer[2] == 0x46)
{
// system(WGET_CMD);
pthread_mutex_lock(&mutex);
buffer[2] = 0x00;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
}
pthread_exit(0);
}
void* get_category()
{
char *category = NULL;
pthread_t send_voice_tid;
pthread_t trash_can_tid;
pthread_t myOled_show_tid;
unsigned char buffer[6] = {0xAA, 0x55, 0x00, 0x00, 0X55, 0xAA};
while(1)
{
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
buffer[2] = 0x00;
system(WGET_CMD);
if(access(RUBBISH_FILE, F_OK) == 0)
{
category = alicloud_rubbish_category(category);
printf("category = %s\n", category);
if(strstr(category, "干垃圾") != NULL)
{
buffer[2] = 0x41;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
else if(strstr(category, "湿垃圾"))
{
buffer[2] = 0x42;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
else if(strstr(category, "可回收垃圾"))
{
buffer[2] = 0x43;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
else if(strstr(category, "有害垃圾"))
{
buffer[2] = 0x44;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
else
{
buffer[2] = 0x45;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
//printf("ret_strstr = %s\n", ret_strstr);
}
else
{
buffer[2] = 0x45;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
if(pthread_create(&send_voice_tid, NULL, send_voice, buffer) != 0)
{
perror("pthread_create1");
exit(-1);
}
if(pthread_create(&trash_can_tid, NULL, trash_can, buffer) != 0)
{
perror("pthread_create2");
exit(-1);
}
if(pthread_create(&myOled_show_tid, NULL, myOled_show, buffer) != 0)
{
perror("pthread_create2");
exit(-1);
}
remove(RUBBISH_FILE);
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
}
pthread_exit(0);
}
int main()
{
int result_detect_process = -1;
char *ret_strstr = (char *)malloc(1024);
pthread_t get_voice_tid;
pthread_t get_category_tid;
rubbish_Init();
if (wiringPiSetup() == -1)
{
exit(1);
}
result_detect_process = detect_process("mjpg_streamer");
if(-1 == result_detect_process)
{
perror("detect_process");
goto END;
}
serial_fd = my_serialOpen(SERIAL_DEV, BAUD);
if(-1 == serial_fd)
{
perror("my_serialOpen");
goto END;
}
pthread_create(&get_voice_tid, NULL, get_voice, NULL);
pthread_create(&get_category_tid, NULL, get_category, NULL);
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_join(get_voice_tid, NULL);
pthread_join(get_category_tid, NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
close(serial_fd);
END:
rubbish_Finalize();
return 0;
}
增加网络控制功能
TCP 心跳机制解决Soket异常断开问题
socket_Sever.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "socket_Sever.h"
int socket_init()
{
int s_fd;
struct sockaddr_in s_addr;
memset(&s_addr, 0, sizeof(struct sockaddr_in));
s_fd = socket(AF_INET,SOCK_STREAM,0);
if(s_fd == -1)
{
perror("socket");
exit(-1);
}
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(atoi(MY_PORT));
inet_aton(MY_IP_ADDRESS, &s_addr.sin_addr);
//2.bind
int result_bind = bind(s_fd, (struct sockaddr *)&s_addr, sizeof(struct sockaddr_in));
if (-1 == result_bind)
{
perror("bind");
return -1;
}
//3.listen
int result_listen = listen(s_fd, 1);
if (-1 == result_listen)
{
perror("listen");
return -1;
}
return s_fd;
}
socket_Sever.h
#ifndef _SOCKET_SEVER_H_
#define _SOCKET_SEVER_H_
#define MY_IP_ADDRESS "192.168.1.82"
#define MY_PORT "8888"
int socket_init();
#endif
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <wiringPi.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include "rubbish.h"
#include "mySerial.h"
#include "pwm.h"
#include "myOLED.h"
#include "socket_Sever.h"
int len = -1;
int serial_fd = -1;
pthread_mutex_t mutex;
pthread_cond_t cond;
int detect_process(char *process_name)
{
FILE *file;
int pid;
char cmd[64] = {'\0'};
char buffer[128] = {'\0'};
sprintf(cmd, "ps -ax | grep %s | grep -v grep", process_name);
file = popen(cmd, "r");
if(file != NULL)
{
if(fgets(buffer, sizeof(buffer), file) != NULL)
{
pid = atoi(buffer);
return pid;
}
else
{
return -1;
}
}
else
{
return -1;
}
pclose(file);
return pid;
}
void* send_voice(void *arg)
{
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
pthread_detach(pthread_self());
unsigned char *buffer = (unsigned char *)arg;
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
if(NULL != buffer)
{
my_serialPuts(serial_fd, buffer, 6);
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
}
pthread_exit(0);
}
void* trash_can(void *arg)
{
pthread_detach(pthread_self());
unsigned char *buffer = (unsigned char *)arg;
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
if(buffer[2] == 0x43)
{
pwm_write(PWM_RECOVERABLE_RUBBISH);
delay(2300);
pwm_stop(PWM_RECOVERABLE_RUBBISH);
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
}
else if(buffer[2] != 0x45)
{
pwm_write(PWM_OTHER_RUBBISH);
delay(2300);
pwm_stop(PWM_OTHER_RUBBISH);
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
}
pthread_exit(0);
}
void* myOled_show(void *arg)
{
pthread_detach(pthread_self());
myOled_init();
oled_show(arg);
pthread_exit(0);
}
void* get_voice()
{
unsigned char buffer[6] = {0xAA, 0x55, 0x00, 0x00, 0X55, 0xAA};
while(1)
{
len = my_serialGets(serial_fd, buffer);
if(len > 0 && buffer[2] == 0x46)
{
// system(WGET_CMD);
pthread_mutex_lock(&mutex);
buffer[2] = 0x00;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
}
pthread_exit(0);
}
void* get_category()
{
char *category = NULL;
pthread_t send_voice_tid;
pthread_t trash_can_tid;
pthread_t myOled_show_tid;
unsigned char buffer[6] = {0xAA, 0x55, 0x00, 0x00, 0X55, 0xAA};
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
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(access(RUBBISH_FILE, F_OK) == 0)
{
category = alicloud_rubbish_category(category);
printf("category = %s\n", category);
if(strstr(category, "干垃圾") != NULL)
{
buffer[2] = 0x41;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
else if(strstr(category, "湿垃圾"))
{
buffer[2] = 0x42;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
else if(strstr(category, "可回收垃圾"))
{
buffer[2] = 0x43;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
else if(strstr(category, "有害垃圾"))
{
buffer[2] = 0x44;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
else
{
buffer[2] = 0x45;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
//printf("ret_strstr = %s\n", ret_strstr);
}
else
{
buffer[2] = 0x45;
printf("[%d]: 0x%2X\n", __LINE__, buffer[2]);
//my_serialPuts(serial_fd, buffer, 6);
}
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
if(pthread_create(&send_voice_tid, NULL, send_voice, buffer) != 0)
{
perror("pthread_create1");
exit(-1);
}
if(pthread_create(&trash_can_tid, NULL, trash_can, buffer) != 0)
{
perror("pthread_create2");
exit(-1);
}
if(pthread_create(&myOled_show_tid, NULL, myOled_show, buffer) != 0)
{
perror("pthread_create2");
exit(-1);
}
remove(RUBBISH_FILE);
printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
}
pthread_exit(0);
}
void* socket_sever()
{
int s_fd;
int c_fd;
ssize_t n_receive;
struct sockaddr_in c_addr;
char receive_buf[8] = {'\0'};
memset(&c_addr, 0, sizeof(struct sockaddr_in));
s_fd = socket_init();
printf("%s|%s|%d:s_fd=%d\n", __FILE__, __func__, __LINE__, s_fd);
sleep(3);
int addrlen = sizeof(struct sockaddr_in);
while(1)
{
memset(receive_buf, '\0', sizeof(receive_buf));
c_fd = accept(s_fd, (struct sockaddr *)&c_addr, &addrlen);
if(c_fd == -1)
{
perror("accept");
continue;
}
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));
//5.read
while(1)
{
memset(receive_buf, '\0', sizeof(receive_buf));
n_receive = recv(c_fd, receive_buf, sizeof(receive_buf), 0);
printf("%s|%s|%d : %s\n", __FILE__, __func__, __LINE__, receive_buf);
if(n_receive > 0)
{
if(strstr(receive_buf, "open"))
{
printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);
}
}
/*
if(strstr(receive_buf, "open") && n_receive > 0)
{
pthread_mutex_lock(&mutex);
pthread_cond_(&cond);
pthread_mutex_unlock(&mutex);
}
*/
else if(0 == n_receive || -1 == n_receive)
{
break;
}
}
close(c_fd);
}
pthread_exit(0);
}
int main()
{
int result_detect_process = -1;
char *ret_strstr = (char *)malloc(1024);
pthread_t get_voice_tid;
pthread_t get_category_tid;
pthread_t socket_sever_tid;
rubbish_Init();
if (wiringPiSetup() == -1)
{
exit(1);
}
result_detect_process = detect_process("mjpg_streamer");
if(-1 == result_detect_process)
{
perror("detect_process");
goto END;
}
serial_fd = my_serialOpen(SERIAL_DEV, BAUD);
if(-1 == serial_fd)
{
perror("my_serialOpen");
goto END;
}
pthread_create(&get_voice_tid, NULL, get_voice, NULL);
pthread_create(&get_category_tid, NULL, get_category, NULL);
pthread_create(&socket_sever_tid, NULL, socket_sever, NULL);
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_join(get_voice_tid, NULL);
pthread_join(get_category_tid, NULL);
pthread_join(socket_sever_tid, NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
close(serial_fd);
END:
rubbish_Finalize();
return 0;
}