【全志H616】【开源】 ARM-Linux 智能分拣项目:阿里云、网络编程、图像识 ...

张春  金牌会员 | 2024-9-11 08:57:00 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 683|帖子 683|积分 2049

【全志H616】【开源】 ARM-Linux 智能分拣项目:阿里云、网络编程、图像识


  
1、实现功能



  • 语音接入控制垃圾分类识别并触发垃圾桶的开关盖,并根据垃圾范例开关不同范例垃圾桶
  • 利用TCP的Socket编程,实现Sockect发送指令远程控制垃圾分类识别,引入心跳包来检测客户端状态,防止客户端非常关闭导致进程堵塞
  • 为什么要用 TCP的socket编程 通过网络来控制呢?
  • 是为了可以通过远程PC来实现对硬件的控制
  • 调用阿里云接口实现 物品的动态识别服务,将识别到的物品范例返回,并终极通过语音模块播报
  • 语音播报垃圾物品范例
  • OLED显示垃圾物品范例
  • 多线程编程 利用多线程编程来办理多并发的问题
   看下面的流程图会更清楚
  2、软件及所需环境

Ubantu-22.04、MoberXterm、arach64-linux-gnu、VCS-ssh、全志开辟板、SU-03T语音模块、OLED显示屏、USB摄像头、SG90舵机
   语音烧入软件&SU-03T语音模块的配置文件:
  链接: https://pan.baidu.com/s/1SfNVrNmBR02YqE7lU2LiVQ?pwd=2222 提取码: 2222 复制这段内容后打开百度网盘手机App,操纵更方便哦
    网络调试助手
  链接: https://pan.baidu.com/s/1HkVjyYVYZ9NdhQNwx-qTGQ?pwd=2222 提取码: 2222 复制这段内容后打开百度网盘手机App,操纵更方便哦
  3、逻辑流程图及简述

3.1 完整逻辑流程图


3.2 硬件接线



  • 下令gpio readall  显示针脚的状态和配置信息。

3.3 功能简述

3.3.1 main()

   我们先通过main函数来了解一下整个程序的概况
  

  • 定义线程在被创造 pthread_create后 ,需要的tid 参数;
           是一个指向 pthread_t 范例变量的指针,用于存储新创建线程的标识符。
  • 先进行初始化,wiringPiSetup() & garbage_init();

    • 对于witingPi库和阿里云接口初始化

  • 判定mjpg_streamer这个进程是否存在;detect_process("mjpg_streamer"); 这个函数是我们本身写的,在后文会提供;

    • mjpg_streamer 是一款开源的流媒体服务器软件,它能够从一系列输入插件(如USB摄像头)捕获视频数据,并通过网络以MJPG(Motion JPEG)格式实时传输

  • 打开串行接口 serial_fd = myserialOpen(SERIAL_DEV,BAUD);//可代替设备节点 & 波特率 返回值fd;判定是否打开乐成
  • 打开语音、网络、阿里云交互线程 pthread_create()
  • 等待指定的线程结束其执行 pthread_join()
  • 烧毁互斥锁(mutex)和条件变量(cond) pthread_mutex_destroy(&mutex); pthread_cond_destroy(&cond);
  • 关闭串口 close(serial_fd);
  1. //main()
  2. int main(int argc, char *argv[])
  3. {
  4.     printf("adsfasdf\n");
  5.     int len = 0;
  6.     int ret = -1;//标识
  7.     char *category = NULL;
  8.     unsigned char buffer[6] = {0xAA,0x55,0x00,0x00,0x55,0xAA};//AA 55 ** 00 55 AA
  9.     pthread_t get_voice_tid, category_tid,get_socket_tid;
  10.     //初始化
  11.     wiringPiSetup();//初始化wiringPi库
  12.     garbage_init(); //初始化阿里云接口
  13.    
  14.     // 用于检测特定进程是否在运行。
  15.     // 它通过调用系统命令ps -ax | grep process_name|grep -v grep来查找包含指定进程名的进程,并返回相应的进程号  
  16.     // mjpg_streamer 是一款开源的流媒体服务器软件,它能够从一系列输入插件(如USB摄像头)捕获视频数据,并通过网络以MJPG(Motion JPEG)格式实时传输
  17.     ret = detect_process("mjpg_streamer");
  18.     if(-1 == ret)
  19.     {
  20.         printf("detect process failed\n");
  21.         goto END;
  22.     }
  23.     //打开设备
  24.     serial_fd = myserialOpen(SERIAL_DEV,BAUD);//可代替设备节点 & 波特率   返回值fd
  25.     if(serial_fd == -1)//是否打开成功
  26.     {
  27.         goto END;   
  28.     }//*pget_voice(void *arg)里面判断
  29.    
  30.     //printf("%s|%s|%d:open serial failed\n",__FILE__,__func__,__LINE__);
  31.     //开语音的线程
  32.     pthread_create(&get_voice_tid,NULL,pget_voice,NULL);
  33.     //开网络线程
  34.     pthread_create(&get_socket_tid,NULL,pget_socket,NULL);
  35.     //开阿里云交互线程
  36.     pthread_create(&category_tid,NULL,pcategory,NULL);
  37.         //get_voice_tid获取语音模块的数据
  38.         //pthread_join用于等待指定的线程结束其执行
  39.     pthread_join(get_voice_tid,NULL);
  40.     pthread_join(category_tid,NULL);
  41.     pthread_join(get_socket_tid,NULL);
  42.     pthread_mutex_destroy(&mutex);
  43.     pthread_cond_destroy(&cond);
  44.     close(serial_fd);
  45. END:
  46.     garbage_final; //释放所有引用的Python对象
  47.     return 0;
  48. }
复制代码
3.3.2 main函数中打开的语音、网络、阿里云交互线程

3.3.2.1 语音线程

   在main()函数中,用 pthread_create(&get_voice_tid,NULL,pget_voice,NULL);来开启语音线程
  

  • 判定该串口是否已经打开,用输入文件|函数|行号的形式来当调试信息
  • 开一个 while(1) 循环

    • 利用串口吸收函数serialGetstring(serial_fd,buffer); //P8 & P10 ==> TXD.5 & RXD.5 //获取(读)传过来的数据
                 这个函数来自 uartTool.c & uartTool.h 文件
    • 读取的数据buffer[2] 是否是 我先要的;
                 0x46下令表现:语音播报了“识别垃圾范例” 可以在语音模块的配置文件里面修改;

      • 得到的信号是我想要的话,便执行 上锁pthread_mutex_lock(&mutex)–buffer[2]复位–发信号(利用条件变量) pthread_cond_signal(&cond)–关锁pthread_mutex_unlock(&mutex)
                       互斥锁(mutex)和条件变量(cond)是多线程编程中常用的同步机制,用于控制对共享资源的访问和线程间的通信。


  • 进程退出pthread_exit(0);
  • main.c里面的函数
  1. //获得 语音线程 pget_voice()
  2. void *pget_voice(void *arg)
  3. {
  4.     unsigned char buffer[6] = {0xAA,0x55,0x00,0x00,0x55,0xAA};//AA 55 ** 00 55 AA
  5.     int len = 0;
  6.     if(serial_fd == -1)//是否打开成功
  7.     {
  8.         printf("%s|%s|%d:open serial failed\n",__FILE__,__func__,__LINE__);//文件名-函数名-行号
  9.         pthread_exit(0);
  10.     }
  11.     printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);
  12.     while(1)
  13.     {
  14.         //获取(读)传过来的数据
  15.         len = serialGetstring(serial_fd,buffer); //P8 & P10 ==> TXD.5 & RXD.5
  16.         printf("%s|%s|%d, len=%d\n", __FILE__, __func__, __LINE__,len);
  17.         if(len>0 && buffer[2]==0x46) //0x46命令:识别垃圾类型
  18.         {
  19.             printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);
  20.             
  21.             //利用 互斥锁(mutex)和条件变量(condition variable)
  22.             //互斥锁(mutex)和条件变量(cond)是多线程编程中常用的同步机制,用于控制对共享资源的访问和线程间的通信。
  23.             //上锁
  24.             pthread_mutex_lock(&mutex);
  25.             buffer[2] = 0x00;
  26.             //给阿里云发信号
  27.             pthread_cond_signal(&cond);//发信号
  28.             pthread_mutex_unlock(&mutex);
  29.         }
  30.     }
  31.     pthread_exit(0);
  32. }
复制代码


  • uartTool.h
  1. //uartTool.h
  2. #ifndef __UARTTOOL_H
  3. #define __UARTTOOL_H
  4. int myserialOpen (const char *device, const int baud);
  5. void serialSendstring (const int fd, unsigned const char *s, int len); //写数据
  6. int serialGetstring (const int fd, unsigned char *buffer); //读数据
  7. #define SERIAL_DEV "/dev/ttyS5" // 可代替设备节点
  8. #define BAUD 115200             // 代替波特率
  9. #endif
  10. //防止头文件中的声明反复区声明
复制代码


  • uartTool.c
  1. //uartTool.c 中的一个函数
  2. int serialGetstring (const int fd, unsigned char *buffer)
  3. {
  4.         int n_read;
  5.     //read() 用于从文件描述符(file descriptor)读取数据的 POSIX 标准函数之一
  6.         n_read = read(fd,buffer,6);
  7.     //printf("fd = %d\n",fd);
  8.     printf("BUFFER = %x,%x,%x\n",buffer[0],buffer[1],buffer[2]);
  9.         return n_read;
  10. }
复制代码
3.3.2.2 网络线程

   main函数中 利用 pthread_create(&get_socket_tid,NULL,pget_socket,NULL);来开启socket网络线程
  

  • 初始化socket,这个就不详细解说了,在前面的文章,socket网络编程有详细解说
           Linux系统编程8–网络编程-CSDN博客
  • 在网络编程文件的基础上,这边还添加了 心跳包功能,

    • Socket客户端得断开有两种情况:

      • 1.客户端能够发送状态给服务器;正常断开,强制关闭客户端等,客户端能够做出反应。
      • 2.客户端不能发送状态给服务器;突然断网,断电,客户端卡死等,客户端根本没机会做出反应, 服务器更不了解客户端状态,导致服务器非常等待。

    • 因此,为了办理上述问题,引入TCP心跳包机制: 心跳包的实现,心跳包就是服务器定时向客户端发送查询信息,如果客户端有回应就代表连接正常, 雷同于linux系统的看门狗机制。心跳包的机制有一种方法就是采用TCP_KEEPALIVE机制,它是一种用于 检测TCP连接是否存活的机制,它的原理是在一定时间内没有数据往来时,发送探测包给对方,如果对方 没有响应,就以为连接已经断开。TCP_KEEPALIVE机制可以通过设置一些参数来调解,如探测时间间 隔、探测次数等。
    • 查看当前系统的TCP KeepAlive参数
      1. sysctl net.ipv4.tcp_keepalive_time
      2. sysctl net.ipv4.tcp_keepalive_probes
      3. sysctl net.ipv4.tcp_keepalive_intvl
      复制代码


   默认等待时间为7200s,查询9次,每次间隔75s
  我们把它修改了,见 main.c 文件里的 void *pget_socket(void *fd) 函数
  

  • while(1)循环

    • 引入心跳包
    • 连接乐成后,输出调试信息
    • while(1)

      • 读数据,如果读取乐成,判定读取的数值是否是 “open”

        • 读取到"open" 便执行 上锁、给阿里云发信号、关锁的操纵(和前文语音模块一样)

      • 没有读取到,大概读取错误,就break;


  • 关闭s_fd (ivp4 TCP)
  • 进程退出 pthread_exit(0);
  • main.c中的pget_socket函数
  1. void *pget_socket(void *fd)
  2. {
  3.     int s_fd = -1;
  4.     int c_fd = -1;
  5.     char buffer[6];
  6.     int nread = -1;
  7.     struct sockaddr_in c_addr;//用于accept
  8.     memset(&c_addr,0,sizeof(struct sockaddr_in));//清零
  9.     s_fd = socket_init(IPADDR,IPPORT);
  10.     printf("%s|%s|%d: s_fd=%d\n",__FILE__,__func__,__LINE__,s_fd);
  11.     if(-1 == s_fd)
  12.     {
  13.         pthread_exit(0);
  14.     }
  15.     sleep(3);
  16.     int clen = sizeof(struct sockaddr_in);
  17.     while(1)
  18.         {
  19.         //accep第三个参数要求是指针//不连接,便堵塞,直到与客户端连接
  20.                 c_fd = accept(s_fd, (struct sockaddr *)&c_addr,&clen);
  21.         // 心包跳
  22.         int keepalive = 1; // 开启TCP KeepAlive功能
  23.         int keepidle = 5; // tcp_keepalive_time 3s内没收到数据开始发送心跳包
  24.         int keepcnt = 3; // tcp_keepalive_probes 每次发送心跳包的时间间隔,单位秒
  25.         int keepintvl = 3; // tcp_keepalive_intvl 每3s发送一次心跳包
  26.         setsockopt(c_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive,
  27.         sizeof(keepalive));
  28.         setsockopt(c_fd, SOL_TCP, TCP_KEEPIDLE, (void *) &keepidle, sizeof
  29.         (keepidle));
  30.         setsockopt(c_fd, SOL_TCP, TCP_KEEPCNT, (void *)&keepcnt, sizeof
  31.         (keepcnt));
  32.         setsockopt(c_fd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepintvl, sizeof
  33.         (keepintvl));
  34.                 //
  35.                
  36.         //连接成功后,输出调试信息
  37.         printf("--------ok?--------\n");
  38.         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));//最后两个window主机的ip和端口号,可以在网络调试助手设置查看,
  39.         printf("-----------ok!-----\n");
  40.         if(c_fd == -1)
  41.                 {
  42.                         perror("accept");//终端打出错误:accept:---
  43.             continue;
  44.                 }
  45.         while(1)
  46.         {
  47.             memset(buffer,0,sizeof(buffer));
  48.             nread = recv(c_fd,buffer,sizeof(buffer),0);// == n_read = read(c_fd,readBuf,sizeof(buffer));
  49.             printf("%s|%s|%d:nread=%d,buffer=%s\n",__FILE__,__func__,__LINE__,nread,buffer);
  50.             if(nread > 0)
  51.             {
  52.                 if(strstr(buffer,"open"))
  53.                 {
  54.                     //上锁
  55.                     pthread_mutex_lock(&mutex);
  56.                     //给阿里云发信号
  57.                     pthread_cond_signal(&cond);//发信号
  58.                     pthread_mutex_unlock(&mutex);
  59.                 }
  60.             }
  61.             else if(0==nread || -1==nread)
  62.             {
  63.                 break;
  64.             }
  65.         }
  66.         close(c_fd);
  67.     }
  68.     pthread_exit(0);
  69. }
复制代码


  • socket.h socket初始化
  1. //socket.h
  2. #ifndef __SOCKET_H
  3. #define __SOCKET_H
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h> //memset包含头文件
  7. #include <sys/socket.h>
  8. #include <sys/types.h>
  9. //#include <linux/in.h>
  10. #include <arpa/inet.h>
  11. #include <netinet/in.h> //该头文件会与 #include <linux/in.h> 冲突
  12. #include <arpa/inet.h>
  13. #include <unistd.h>
  14. #include <netinet/in.h>
  15. #include <netinet/tcp.h>
  16. #include <arpa/inet.h>
  17. #include <errno.h>
  18. int socket_init(const char *ipaddr,const char *ipport);
  19. #endif
复制代码


  • socket.c socket的初始化
  1. #include "socket.h"
  2. int socket_init(const char *ipaddr,const char *ipport)
  3. {
  4.     int s_fd;
  5.     int ret = -1;
  6.         //sockaddr_in 是一个结构体,包含本机子ip地址和端口号等信息
  7.         struct sockaddr_in s_addr;//用于bind
  8.     memset(&s_addr,0,sizeof(struct sockaddr_in));//进行清空
  9.         //1、socket
  10.         s_fd = socket(AF_INET,SOCK_STREAM,0);  //ivp4,TCP
  11.         if(-1 == s_fd)
  12.         {
  13.                 perror("socket");//将上一个函数错误的原因输出
  14.                 return -1;
  15.         }
  16.         s_addr.sin_family = AF_INET;//ivp4
  17.         s_addr.sin_port = htons(atoi(ipport));//htons() 返回网络字节的端口号 //ipport是第二个参数,端口号
  18.         inet_aton(ipaddr,&s_addr.sin_addr);//字符串类型形式的“192.0.0.1”转换为网络能识别的格式//字符串-指针
  19.         //2、bind
  20.         ret = bind(s_fd, (struct sockaddr *)&s_addr, sizeof(struct sockaddr_in));
  21.     if(-1 == ret)
  22.         {
  23.                 perror("bind");//将上一个函数错误的原因输出
  24.                 return -1;
  25.         }
  26.         //3、listen
  27.         ret = listen(s_fd,1);//同时允许一个监听
  28.     if(-1 == ret)
  29.         {
  30.                 perror("listen");//将上一个函数错误的原因输出
  31.                 return -1;
  32.         }
  33.     return s_fd;
  34. }
复制代码
3.3.2.3 阿里云交互线程

   main()函数中,利用 pthread_create(&category_tid,NULL,pcategory,NULL); 来开阿里云交互线程
  

  • 定义线程在被创造 pthread_create后 ,需要的tid 参数;
           是一个指向 pthread_t 范例变量的指针,用于存储新创建线程的标识符。
  • while(1)循环

    • 线程上锁、等待信号 //cond 会集、关锁
    • buffer[2]复位
    • 照相指令 system(WGET_CMD) 宏定义WGET_CMD:照相下令,garbage.h 文件中
    • 识别垃圾图片是否存在,也就是是否拍摄乐成access(GARBAGE_FILE, F_OK) GARBAGE_FILE 文件位置宏定义
    • 调用阿里云接口判定垃圾范例 category = garbage_category(category); 函数见 garbage.c & garbage.py
    • 判定 对应的垃圾范例,并对buffer[2] 赋不同的值
    • 再开三个线程

      • 开垃圾桶开盖线程:pthread_create(&trash_tid,NULL,psend_voice,(void*)buffer);
      • 开语音播报线程: pthread_create(&send_void_tid,NULL,popen_trash_can,(void*)buffer);
      • 开oled显示线程 :pthread_create(&oled_tid,NULL,poled_show,(void*)buffer);

    • 把识别到的垃圾的图片扫除掉 remove(GARBAGE_FILE); GARBAGE_FILE 文件文章宏定义,见garbage.h

  • 退出进程 pthread_exit(0);
  1. void *pcategory(void *arg)
  2. {
  3.     unsigned char buffer[6] = {0xAA,0x55,0x00,0x00,0x55,0xAA};//AA 55 ** 00 55 AA
  4.     char *category = NULL;
  5.     pthread_t send_void_tid,trash_tid,oled_tid;
  6.     printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);//文件名-函数名-行号
  7.     while(1)
  8.     {
  9.         printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);//文件名-函数名-行号
  10.         pthread_mutex_lock(&mutex);// 锁住
  11.         //给阿里云发信号
  12.         pthread_cond_wait(&cond,&mutex);//等待信号
  13.         pthread_mutex_unlock(&mutex);
  14.         printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);//文件名-函数名-行号
  15.         buffer[2] = 0x00;
  16.         //define WGET_CMD "wget http://127.0.0.1:8080/?action=snapshot -O /tmp/garbage.jpg" //抓拍命令
  17.         system(WGET_CMD);//宏定义:拍照命令,garbage.h 文件中
  18.         // access函数是一个用于测试文件访问权限的函数,它通常用于检查某个文件是否可以被当前用户读取、写入或执行。
  19.         // 包括F_OK(检查文件是否存在)、R_OK(检查读权限)、W_OK(检查写权限)和X_OK(检查执行权限)
  20.         // 该函数返回值为0表示有权限,-1表示无权限或发生错误。
  21.         if(0 == access(GARBAGE_FILE, F_OK))//GARBAGE_FILE 宏定义 识别到的垃圾图片是否存在
  22.         {
  23.             category = garbage_category(category);//调用阿里云接口判断垃圾类型
  24.             if(strstr(category,"干垃圾"))
  25.             {
  26.                 buffer[2] = 0x41;//赋值
  27.             }
  28.             else if(strstr(category,"湿垃圾"))
  29.             {
  30.                 buffer[2] = 0x42;
  31.             }
  32.             else if(strstr(category,"可回收垃圾"))
  33.             {
  34.                 buffer[2] = 0x43;
  35.             }
  36.             else if(strstr(category,"有害垃圾"))
  37.             {
  38.                 buffer[2] = 0x44;
  39.             }
  40.             else
  41.             {
  42.                 buffer[2] = 0x45;
  43.             }
  44.         }
  45.         else
  46.         {
  47.             buffer[2] = 0x45;
  48.         }
  49.         //开三个线程
  50.         //垃圾桶开盖线程
  51.         pthread_create(&trash_tid,NULL,psend_voice,(void*)buffer);
  52.         //开语音播报线程
  53.         pthread_create(&send_void_tid,NULL,popen_trash_can,(void*)buffer);
  54.         //开oled显示线程
  55.         pthread_create(&oled_tid,NULL,poled_show,(void*)buffer);
  56.         // buffer[2]=0x00;//将buffer[2]清零
  57.         remove(GARBAGE_FILE);//garbage.h 的宏定义 把识别到的垃圾的图片清除掉
  58.     }
  59.     pthread_exit(0);
  60. }
复制代码
3.3.2.4 阿里云交互线程pcategory开的3个线程

  1. void *psend_voice(void *arg) //写数据,回传给语音模块
  2. {   
  3.     pthread_detach(pthread_self());
  4.     unsigned char *buffer = (unsigned char *)arg;
  5.     if(serial_fd == -1)//是否打开成功
  6.     {
  7.         printf("%s|%s|%d:open serial failed\n",__FILE__,__func__,__LINE__);//文件名-函数名-行号
  8.         pthread_exit(0);
  9.     }
  10.     if(NULL != buffer)
  11.     {
  12.         serialSendstring(serial_fd,buffer,6);//写数据,回传给语音模块
  13.     }
  14.     pthread_exit(0);
  15. }
  16. void *popen_trash_can(void *arg)//满足条件就开舵机
  17. {
  18.     pthread_detach(pthread_self());
  19.     unsigned char *buffer = (unsigned char *)arg;
  20.     //这意味着线程结束时会自动释放其资源,
  21.     //而不需要其他线程调用 pthread_join() 来等待其结束并回收资源
  22.    
  23.     if(buffer[2] == 0x41)
  24.     {
  25.         pwm_write(PWM_RECOVERABLE_GARBAGE); //对应wPi 5口,接着一个舵机
  26.         printf("---------%x---------\n",buffer[2]);
  27.         delay(2000);
  28.         pwm_stop(PWM_RECOVERABLE_GARBAGE);
  29.     }
  30.     else if(buffer[2] != 0x45)
  31.     {
  32.         printf("%s|%s|%d: buffer[2]=0x%x\n", __FILE__, __func__, __LINE__,buffer[2]);
  33.         printf("start\n");
  34.         pwm_write(PWM_GARBAGE);  //对应wPi 7口,接着另一个舵机
  35.         delay(2000);
  36.         pwm_stop(PWM_GARBAGE);
  37.     }
  38.     pthread_exit(0);
  39. }
  40. void *poled_show(void *arg)//oled显示当前识别的垃圾类型
  41. {
  42.     pthread_detach(pthread_self()); //这意味着线程结束时会自动释放其资源,
  43.     myoled_init();
  44.     oled_show(arg); //buffer
  45.     pthread_exit(0);
  46. }
复制代码
4、实行程序

4.1 uartTool 串口



  • 串口的打开;发送、吸收串口信息
  1. //uartTool.h
  2. #ifndef __UARTTOOL_H
  3. #define __UARTTOOL_H
  4. int myserialOpen (const char *device, const int baud);
  5. void serialSendstring (const int fd, unsigned const char *s, int len); //写数据
  6. int serialGetstring (const int fd, unsigned char *buffer); //读数据
  7. #define SERIAL_DEV "/dev/ttyS5" // 可代替设备节点
  8. #define BAUD 115200             // 代替波特率
  9. #endif
  10. //防止头文件中的声明反复区声明
复制代码
  1. //uartTool.c
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <stdint.h>
  5. #include <stdarg.h>
  6. #include <string.h>
  7. #include <termios.h>
  8. #include <unistd.h>
  9. #include <fcntl.h>
  10. #include <sys/ioctl.h>
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13. #include "uartTool.h"//先到当前文件夹查看
  14. #include "wiringSerial.h"
  15. int myserialOpen (const char *device, const int baud)
  16. {
  17.         struct termios options ;//这个结构体
  18.   speed_t myBaud ;
  19.   int status, fd ;
  20.   
  21.   switch (baud)
  22.   {
  23.           case    9600:        myBaud =    B9600 ; break ;
  24.           case  115200:        myBaud =  B115200 ; break ;
  25.           default:
  26.   }
  27.   
  28.   if ((fd = open (device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1)
  29.   return -1 ;
  30.   
  31.   fcntl (fd, F_SETFL, O_RDWR) ;
  32. // Get and modify current options:
  33.   tcgetattr (fd, &options) ;//get
  34.   //标准化的操作 一般都是固定的
  35.   cfmakeraw   (&options) ;
  36.   cfsetispeed (&options, myBaud) ;
  37.   cfsetospeed (&options, myBaud) ;//波特率的设置
  38.   options.c_cflag |= (CLOCAL | CREAD) ;
  39.   options.c_cflag &= ~PARENB ;//奇偶校验位
  40.   options.c_cflag &= ~CSTOPB ;//ͣ停止位 一般都是一位的
  41.   options.c_cflag &= ~CSIZE ;
  42.   options.c_cflag |= CS8 ;//数据位 基本都是八位的
  43.   options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ;
  44.   options.c_oflag &= ~OPOST ;
  45.   options.c_cc [VMIN]  =   0 ;
  46.   options.c_cc [VTIME] = 100 ;        // Ten seconds (100 deciseconds)
  47.   //标准化的操作
  48.   tcsetattr (fd, TCSANOW, &options) ;//写入内核
  49.   ioctl (fd, TIOCMGET, &status);//获得整型控制字TIOCMGET get出来
  50.   status |= TIOCM_DTR ;
  51.   status |= TIOCM_RTS ;//控制字加上标志位
  52.   ioctl (fd, TIOCMSET, &status);//写入内核
  53.   usleep (10000) ;        // 10mS
  54.   return fd ;
  55. }
  56. //0XAA 0X55 0X46 0X00 0X55 0XAA
  57. void serialSendstring (const int fd, const unsigned char *s, int len)//去写数据
  58. {
  59.         int ret;
  60.   ret = write (fd, s, len);
  61.   if (ret < 0)
  62.                 printf("Serial Putchar Error\n");
  63. }
  64. int serialGetstring (const int fd, unsigned char *buffer)
  65. {
  66.         int n_read;
  67.   //read() 用于从文件描述符(file descriptor)读取数据的 POSIX 标准函数之一
  68.         n_read = read(fd,buffer,6);
  69.   //printf("fd = %d\n",fd);
  70.   printf("BUFFER = %x,%x,%x\n",buffer[0],buffer[1],buffer[2]);
  71.         return n_read;
  72. }
复制代码
4.2 socket 网络



  • socket网络线程 + 心跳包
  1. //socket.h
  2. #ifndef __SOCKET_H
  3. #define __SOCKET_H
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h> //memset包含头文件
  7. #include <sys/socket.h>
  8. #include <sys/types.h>
  9. //#include <linux/in.h>
  10. #include <arpa/inet.h>
  11. #include <netinet/in.h> //该头文件会与 #include <linux/in.h> 冲突
  12. #include <arpa/inet.h>
  13. #include <unistd.h>
  14. #include <netinet/in.h>
  15. #include <netinet/tcp.h>
  16. #include <arpa/inet.h>
  17. #include <errno.h>
  18. int socket_init(const char *ipaddr,const char *ipport);
  19. #endif
复制代码
  1. //socket.c#include "socket.h"
  2. int socket_init(const char *ipaddr,const char *ipport)
  3. {
  4.     int s_fd;
  5.     int ret = -1;
  6.         //sockaddr_in 是一个结构体,包含本机子ip地址和端口号等信息
  7.         struct sockaddr_in s_addr;//用于bind
  8.     memset(&s_addr,0,sizeof(struct sockaddr_in));//进行清空
  9.         //1、socket
  10.         s_fd = socket(AF_INET,SOCK_STREAM,0);  //ivp4,TCP
  11.         if(-1 == s_fd)
  12.         {
  13.                 perror("socket");//将上一个函数错误的原因输出
  14.                 return -1;
  15.         }
  16.         s_addr.sin_family = AF_INET;//ivp4
  17.         s_addr.sin_port = htons(atoi(ipport));//htons() 返回网络字节的端口号 //ipport是第二个参数,端口号
  18.         inet_aton(ipaddr,&s_addr.sin_addr);//字符串类型形式的“192.0.0.1”转换为网络能识别的格式//字符串-指针
  19.         //2、bind
  20.         ret = bind(s_fd, (struct sockaddr *)&s_addr, sizeof(struct sockaddr_in));
  21.     if(-1 == ret)
  22.         {
  23.                 perror("bind");//将上一个函数错误的原因输出
  24.                 return -1;
  25.         }
  26.         //3、listen
  27.         ret = listen(s_fd,1);//同时允许一个监听
  28.     if(-1 == ret)
  29.         {
  30.                 perror("listen");//将上一个函数错误的原因输出
  31.                 return -1;
  32.         }
  33.     return s_fd;
  34. }
复制代码
4.3 阿里云 garbage 识别

  1. # garbage.py
  2. # -*- coding: utf-8 -*-
  3. # 引入依赖包
  4. # pip install alibabacloud_imagerecog20190930
  5.    
  6. import os
  7. import io
  8. from urllib.request import urlopen
  9. from alibabacloud_imagerecog20190930.client import Client
  10. from alibabacloud_imagerecog20190930.models import ClassifyingRubbishAdvanceRequest
  11. from alibabacloud_tea_openapi.models import Config
  12. from alibabacloud_tea_util.models import RuntimeOptions
  13. config = Config(
  14.   # 创建AccessKey ID和AccessKey Secret,请参考https://help.aliyun.com/document_detail/175144.html。
  15.   # 如果您用的是RAM用户的AccessKey,还需要为RAM用户授予权限AliyunVIAPIFullAccess,请参考https://help.aliyun.com/document_detail/145025.html
  16.   # 从环境变量读取配置的AccessKey ID和AccessKey Secret。运行代码示例前必须先配置环境变量。
  17.   access_key_id=os.environ.get('ALIBABA_CLOUD_ACCESS_KEY_ID'),
  18.   access_key_secret=os.environ.get('ALIBABA_CLOUD_ACCESS_KEY_SECRET'),
  19.   # 访问的域名
  20.   endpoint='imagerecog.cn-shanghai.aliyuncs.com',
  21.   # 访问的域名对应的region
  22.   region_id='cn-shanghai'
  23. )
  24. def alibaba_garbage(): # 封装成一个函数,方便其他文件调用
  25.   #场景一:文件在本地
  26.   # img = open(r'/home/orangepi/garbage/lj/test2.jpg','rb')
  27.   img = open(r'/tmp/garbage.jpg','rb')
  28.   #场景二:使用任意可访问的url
  29.   # url = 'https://viapi-test-bj.oss-cn-beijing.aliyuncs.com/viapi-3.0domepic/imagerecog/ClassifyingRubbish/ClassifyingRubbish1.jpg'
  30.   # img = io.BytesIO(urlopen(url).read())
  31.   classifying_rubbish_request = ClassifyingRubbishAdvanceRequest()
  32.   classifying_rubbish_request.image_urlobject = img
  33.   runtime = RuntimeOptions()
  34.   try:
  35.     # 初始化Client
  36.     client = Client(config)
  37.     response = client.classifying_rubbish_advance(classifying_rubbish_request, runtime)
  38.     # 获取整体结果
  39.     # print(response.body) # 默认
  40.     # print(response.body.to_map()) # 打印出body的类型
  41.     print(response.body.to_map()['Data']['Elements'][0]['Category']) # 打印出body的类型
  42.     return response.body.to_map()['Data']['Elements'][0]['Category']
  43.     # 提供调用方便
  44.   except Exception as error:
  45.     # 获取整体报错信息
  46.     # print(error)
  47.     # 获取单个字段
  48.     # print(error.code)
  49.     print("shibai")
  50.     return '获取失败'
  51. if __name__== "__main__":
  52.   alibaba_garbage()
复制代码
  1. // garbage.h
  2. #ifndef __GARBAGE__H
  3. #define __GARBAGE__H
  4. void garbage_init(void);//第一步做初始化,初始python的编译器包括导入当前路劲到sys.path里面
  5. void garbage_final(void);
  6. char *garbage_category(char *category);
  7. //127.0.0.1
  8. //通常被称为"本地回环地址"或"localhost";
  9. //这个地址经常用于测试网络应用程序和诊断网络问题
  10. //因为它确保数据能够在同一台计算机上进行循环传输,而无需真正通过网络传输。
  11. #define WGET_CMD "wget http://127.0.0.1:8080/?action=snapshot -O /tmp/garbage.jpg" //抓拍命令
  12. #define GARBAGE_FILE "/tmp/garbage.jpg"
  13. #endif
复制代码
  1. //garbage.c
  2. // C语言引用Python文件
  3. #if 0
  4. 1、包含Python.h头文件,以便使用Python API。
  5. 2、使用void Py_Initialize()初始化Python解释器,
  6. 3、使用PyObject *PyImport_ImportModule(const char *name)和PyObject
  7. *PyObject_GetAttrString(PyObject *o, const char *attr_name)获取sys.path对象,并利用
  8. int PyList_Append(PyObject *list, PyObject *item)将当前路径.添加到sys.path中,以便加载
  9. 当前的Python模块(Python文件即python模块)。
  10. 4、使用PyObject *PyImport_ImportModule(const char *name)函数导入Python模块,并检查是否
  11. 有错误。
  12. 5、使用PyObject *PyObject_GetAttrString(PyObject *o, const char *attr_name)函数获取
  13. Python函数对象,并检查是否可调用。
  14. +6、使用PyObject *Py_BuildValue(const char *format, ...)函数将C类型的数据结构转换成
  15. Python对象,作为Python函数的参数,没有参数不需要调用
  16. 7、使用PyObject *PyObject_CallObject(PyObject *callable, PyObject *args)函数调用
  17. Python函数,并获取返回值。
  18. +8、使用int PyArg_Parse(PyObject *args, const char *format, ...)函数将返回值转换为C类
  19. 型,并检查是否有错误,没有返回值时不需要调用。
  20. 9、使用void Py_DECREF(PyObject *o)函数释放所有引用的Python对象。
  21. 10、结束时调用void Py_Finalize()函数关闭Python解释器。
  22. 相关的函数参数说明参考网站(网站左上角输入函数名即可开始搜索):
  23. https://docs.python.org/zh-cn/3/c-api/import.html
  24. #endif
  25. #include <Python.h>
  26. #include "garbage.h"
  27. void garbage_init(void)
  28. {
  29.     Py_Initialize();
  30.     // 将当前路径添加到sys.path中
  31.     PyObject *sys = PyImport_ImportModule("sys");//初始化python解释器
  32.     PyObject *path = PyObject_GetAttrString(sys, "path");
  33.     PyList_Append(path, PyUnicode_FromString("."));
  34. }
  35. void garbage_final(void)
  36. {
  37.     //释放所有引用的Python对象
  38.     Py_Finalize();
  39. }
  40. char *garbage_category(char *category)
  41. {
  42.     // 导入para模块
  43.     PyObject *pModule = PyImport_ImportModule("garbage");//引用的是本目录底下的garbage.py文件
  44.     if (!pModule)
  45.     {
  46.         PyErr_Print();
  47.         printf("Error: failed to load para.py\n");
  48.         goto FAILED_MODULE;
  49.     }
  50.     //获取 alibaba_garbage 函数对象
  51.     PyObject *pFunc = PyObject_GetAttrString(pModule, "alibaba_garbage");//garbage.py文件里的这个函数 alibaba_garbage
  52.     if (!pFunc)
  53.     {
  54.         PyErr_Print();
  55.         printf("Error: failed to load say_funny\n");
  56.         goto FAILED_FUNC;
  57.     }
  58.     //调用alibaba_garbage函数并获取返回值
  59.     PyObject *pValue = PyObject_CallObject(pFunc, NULL);
  60.     if (!pValue)
  61.     {
  62.         PyErr_Print();
  63.         printf("Error: function call failed\n");
  64.         goto FAILED_VALUE;
  65.     }
  66.     //将返回值转换为C类型
  67.     char *result = NULL;  //pValue(py) --> result(c)
  68.     if (!PyArg_Parse(pValue, "s", &result))//PyArg_Parse根据指定的格式字符串将 Python 对象转换为 C 变量
  69.     {
  70.         PyErr_Print();
  71.         printf("Error: parse failed\n");
  72.         goto FAILED_RESULT;
  73.     }
  74.     //打印返回值
  75.     printf("pValue=%s\n", result);
  76.     category = (char*)malloc(sizeof(char)*(strlen(result)+1));//要留一个字节给 \0
  77.     memset(category, 0, (strlen(result)+1));
  78.     strncpy(category, result,(strlen(result)+1));//复制字符串
  79.    
  80. //会用来标识某个测试案例、任务或计划未能通过或达到预期的标准或目标;失败后跳转
  81. FAILED_RESULT:
  82.     Py_DECREF(pValue);
  83. FAILED_VALUE:
  84.     Py_DECREF(pFunc);
  85. FAILED_FUNC:
  86.     Py_DECREF(pModule);
  87. FAILED_MODULE:
  88.     return category;
  89. }
复制代码
4.4 PWM sg90舵机

  1. //pwm.h
  2. #ifndef __PWM__H
  3. #define __PWM__H
  4. #define PWM_GARBAGE 7
  5. #define PWM_RECOVERABLE_GARBAGE 5
  6. void pwm_write(int pwm_pin); // 控制PWM ==> 开盖
  7. void pwm_stop(int pwm_pin);  // 控制PWM ==> 关盖
  8. #endif
复制代码
  1. //pwm.c
  2. #include <wiringPi.h>
  3. #include <softPwm.h>
  4. // 根据公式PWMfreq = (1 × 10^6 )/(100 × range)    1000000/20000=50 Hz  ==> 周期为 1/50 = 0.02s = 20ms
  5. // 要得到PWM频率为50Hz,则range为200,即周期为200步,控制精度相比硬件PWM较低
  6. void pwm_write(int pwm_pin)
  7. {
  8.     pinMode(pwm_pin, OUTPUT);//把引脚设置为输出
  9.     // 软件模拟PWM函数
  10.     softPwmCreate(pwm_pin,0,200);// range设置周期分为200步,周期为20ms
  11.     softPwmWrite(pwm_pin,15); // 200步里面有多少步是高电平 10/200 = 0.05
  12.                               //  15/200 = 0.075
  13.                               // 1.0ms--------------45度; 5.0% 占空比
  14.                               // 1.5ms------------90度; 7.5% 占空比
  15.     delay(1000); //延时1s
  16.     softPwmStop(pwm_pin);//停止,不输出PWM波了
  17. }
  18. void pwm_stop(int pwm_pin)
  19. {
  20.     pinMode(pwm_pin, OUTPUT);
  21.     softPwmCreate(pwm_pin,0,200);
  22.     softPwmWrite(pwm_pin,5);// 200步里面有多少步是高电平 5/200 = 0.025
  23.                             // 0.5ms-------------0度; 2.5% 占空比
  24.     delay(1000);
  25.     softPwmStop(pwm_pin);
  26. }
复制代码
4.5 OLED` 显示

  1. //myoled.h
  2. #ifndef __MYOLED__H
  3. #define __MYOLED__H
  4. int myoled_init(void);
  5. int oled_show(void *arg);
  6. #endif
复制代码
  1. //myoled.c
  2. #include <errno.h>
  3. #include <string.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <time.h>
  7. #include <stdint.h>
  8. #include "oled.h"
  9. #include "font.h"
  10. //包含头文件
  11. #include "myoled.h"
  12. #define FILENAME "/dev/i2c-3"
  13. static struct display_info disp;
  14. int oled_show(void *arg)
  15. {
  16.     unsigned char *buffer = (unsigned char *)arg;
  17.     oled_putstrto(&disp, 0, 9+1, "This garbage is:");
  18.     disp.font = font2; //设置字体
  19.     switch(buffer[2])
  20.     {
  21.         case 0x41:
  22.             oled_putstrto(&disp, 0, 20, "dry waste");
  23.         break;
  24.         case 0x42:
  25.             oled_putstrto(&disp, 0, 20, "wet waste");
  26.         break;
  27.         case 0x43:
  28.             oled_putstrto(&disp, 0, 20, "recyclable waste");
  29.         break;
  30.         case 0x44:
  31.             oled_putstrto(&disp, 0, 20, "hazardous waste");
  32.         break;
  33.         case 0x45:
  34.             oled_putstrto(&disp, 0, 20, "recognition failed");
  35.         break;
  36.     }
  37.     disp.font = font2;
  38.     oled_send_buffer(&disp);
  39.     return 0;
  40. }
  41. int myoled_init(void)
  42. {
  43.     int e;
  44.     disp.address = OLED_I2C_ADDR;
  45.     disp.font = font2;
  46.     e = oled_open(&disp, FILENAME);
  47.     e = oled_init(&disp);
  48.     return e;
  49. }
复制代码
4.6 main.c



  • 定义 mutex(互斥锁) & cond(条件变量)
    1. //main.c 中包含的函数
    2. detect_process(const char *);//用于检测特定进程是否在运行。
    3. pget_voice(void *);                         //获取(读)串口中的数据  0x46 //P8 & P10 ==> TXD.5 & RXD.5
    4. psend_voice(void *);                 //发送数据(写),回传给串口(语音模块) TX RX
    5. popen_trash_can(void *);     //通过 buffer[2]的数据,控制舵机,从而开盖
    6. poled_show(void *);                     //调用 myoled 模块,通过buffer[2]的数据在oled上显示不同数据
    7. pcategory(void *);           //调用阿里云进行识别、通过返回值来对buffer[2] 进行赋值;并且创造3个线程
    8.                                                          //开垃圾桶开盖popen_trash_can、语音播报psend_voice、`oled`显示线程poled_show  
    9. pget_socket(void *);         //开启socket网络线程 和 心跳包
    10. main(int, char*[]);
    复制代码
  • main.c
  1. //main.c
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include <unistd.h>
  6. #include <errno.h>
  7. #include <wiringPi.h>
  8. #include <pthread.h>
  9. #include "uartTool.h"
  10. #include "garbage.h"
  11. #include "pwm.h"
  12. #include "myoled.h"
  13. #include "socket.h"
  14. #define IPADDR "192.168.1.76"
  15. #define IPPORT "8000"//一定不能是8080,摄像头服务已经使用
  16. int serial_fd = -1;//全局变量
  17. pthread_cond_t cond;
  18. pthread_mutex_t mutex;
  19. // 用于检测特定进程是否在运行。
  20. // 它通过调用系统命令ps -ax | grep process_name|grep -v grep来查找包含指定进程名的进程,并返回相应的进程号。
  21. static int detect_process(const char *process_name)
  22. {
  23.     int n = -1; // 初始化进程号为-1
  24.     FILE *strm; // 文件流指针
  25.     char buf[128] = {0}; // 缓冲区
  26.     // 构建命令字符串,查找特定进程名的进程
  27.     sprintf(buf, "ps -ax | grep %s|grep -v grep", process_name);
  28.     // 执行系统命令,并返回文件指针用于读取命令输出
  29.     if ((strm = popen(buf, "r")) != NULL)
  30.     {
  31.         // 读取命令输出到缓冲区中
  32.         if (fgets(buf, sizeof(buf), strm) != NULL)
  33.         {
  34.             printf("buf = %s\n", buf); // 输出读取到的内容
  35.             n = atoi(buf); // 将读取到的内容转换为整数,这里假设内容是进程号
  36.             printf("n=%d\n", n); // 输出转换后的进程号
  37.         }
  38.     }
  39.     else
  40.     {
  41.         return -1; // 如果执行popen失败,则返回-1
  42.     }
  43.     pclose(strm); // 关闭文件流
  44.     return n; // 返回进程号,可能为-1(未找到进程或出现错误)
  45. }
  46. void *pget_voice(void *arg)
  47. {
  48.     unsigned char buffer[6] = {0xAA,0x55,0x00,0x00,0x55,0xAA};//AA 55 ** 00 55 AA
  49.     int len = 0;
  50.     if(serial_fd == -1)//是否打开成功
  51.     {
  52.         printf("%s|%s|%d:open serial failed\n",__FILE__,__func__,__LINE__);//文件名-函数名-行号
  53.         pthread_exit(0);
  54.     }
  55.     printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);
  56.     while(1)
  57.     {
  58.         //获取(读)传过来的数据
  59.         len = serialGetstring(serial_fd,buffer); //P8 & P10 ==> TXD.5 & RXD.5
  60.         printf("%s|%s|%d, len=%d\n", __FILE__, __func__, __LINE__,len);
  61.         if(len>0 && buffer[2]==0x46) //0x46命令:识别垃圾类型
  62.         {
  63.             printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);
  64.             //上锁
  65.             pthread_mutex_lock(&mutex);
  66.             buffer[2] = 0x00;
  67.             //给阿里云发信号
  68.             pthread_cond_signal(&cond);//发信号
  69.             pthread_mutex_unlock(&mutex);
  70.         }
  71.     }
  72.     pthread_exit(0);
  73. }
  74. void *psend_voice(void *arg)
  75. {   
  76.     pthread_detach(pthread_self());
  77.     unsigned char *buffer = (unsigned char *)arg;
  78.     if(serial_fd == -1)//是否打开成功
  79.     {
  80.         printf("%s|%s|%d:open serial failed\n",__FILE__,__func__,__LINE__);//文件名-函数名-行号
  81.         pthread_exit(0);
  82.     }
  83.     if(NULL != buffer)
  84.     {
  85.         serialSendstring(serial_fd,buffer,6);//写数据,回传给语音模块
  86.     }
  87.     pthread_exit(0);
  88. }
  89. void *popen_trash_can(void *arg)
  90. {
  91.     pthread_detach(pthread_self());
  92.     unsigned char *buffer = (unsigned char *)arg;
  93.     //这意味着线程结束时会自动释放其资源,
  94.     //而不需要其他线程调用 pthread_join() 来等待其结束并回收资源
  95.    
  96.     if(buffer[2] == 0x41)
  97.     {
  98.         pwm_write(PWM_RECOVERABLE_GARBAGE); //对应wPi 5口,接着一个舵机
  99.         printf("---------%x---------\n",buffer[2]);
  100.         delay(2000);
  101.         pwm_stop(PWM_RECOVERABLE_GARBAGE);
  102.     }
  103.     else if(buffer[2] != 0x45)
  104.     {
  105.         printf("%s|%s|%d: buffer[2]=0x%x\n", __FILE__, __func__, __LINE__,buffer[2]);
  106.         printf("start\n");
  107.         pwm_write(PWM_GARBAGE);  //对应wPi 7口,接着另一个舵机
  108.         delay(2000);
  109.         pwm_stop(PWM_GARBAGE);
  110.     }
  111.     pthread_exit(0);
  112. }
  113. void *poled_show(void *arg)
  114. {
  115.     pthread_detach(pthread_self()); //这意味着线程结束时会自动释放其资源,
  116.     myoled_init();
  117.     oled_show(arg); //buffer
  118.     pthread_exit(0);
  119. }
  120. void *pcategory(void *arg)
  121. {
  122.     unsigned char buffer[6] = {0xAA,0x55,0x00,0x00,0x55,0xAA};//AA 55 ** 00 55 AA
  123.     char *category = NULL;
  124.     pthread_t send_void_tid,trash_tid,oled_tid;
  125.     printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);//文件名-函数名-行号
  126.     while(1)
  127.     {
  128.         printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);//文件名-函数名-行号
  129.         pthread_mutex_lock(&mutex);// 锁住
  130.         //给阿里云发信号
  131.         pthread_cond_wait(&cond,&mutex);//等待信号
  132.         pthread_mutex_unlock(&mutex);
  133.         printf("%s|%s|%d:\n",__FILE__,__func__,__LINE__);//文件名-函数名-行号
  134.         buffer[2] = 0x00;
  135.         //define WGET_CMD "wget http://127.0.0.1:8080/?action=snapshot -O /tmp/garbage.jpg" //抓拍命令
  136.         system(WGET_CMD);//宏定义:拍照命令,garbage.h 文件中
  137.         // access函数是一个用于测试文件访问权限的函数,它通常用于检查某个文件是否可以被当前用户读取、写入或执行。
  138.         // 包括F_OK(检查文件是否存在)、R_OK(检查读权限)、W_OK(检查写权限)和X_OK(检查执行权限)
  139.         // 该函数返回值为0表示有权限,-1表示无权限或发生错误。
  140.         if(0 == access(GARBAGE_FILE, F_OK))//GARBAGE_FILE 宏定义 识别到的垃圾图片是否存在
  141.         {
  142.             category = garbage_category(category);//调用阿里云接口判断垃圾类型
  143.             if(strstr(category,"干垃圾"))
  144.             {
  145.                 buffer[2] = 0x41;//赋值
  146.             }
  147.             else if(strstr(category,"湿垃圾"))
  148.             {
  149.                 buffer[2] = 0x42;
  150.             }
  151.             else if(strstr(category,"可回收垃圾"))
  152.             {
  153.                 buffer[2] = 0x43;
  154.             }
  155.             else if(strstr(category,"有害垃圾"))
  156.             {
  157.                 buffer[2] = 0x44;
  158.             }
  159.             else
  160.             {
  161.                 buffer[2] = 0x45;
  162.             }
  163.         }
  164.         else
  165.         {
  166.             buffer[2] = 0x45;
  167.         }
  168.         //开三个线程
  169.         //垃圾桶开盖线程
  170.         pthread_create(&trash_tid,NULL,psend_voice,(void*)buffer);
  171.         //开语音播报线程
  172.         pthread_create(&send_void_tid,NULL,popen_trash_can,(void*)buffer);
  173.         
  174.         pthread_create(&oled_tid,NULL,poled_show,(void*)buffer);
  175.         // buffer[2]=0x00;//将buffer[2]清零
  176.         remove(GARBAGE_FILE);//garbage.h 的宏定义 把识别到的垃圾的图片清除掉
  177.     }
  178.     pthread_exit(0);
  179. }
  180. void *pget_socket(void *fd)
  181. {
  182.     int s_fd = -1;
  183.     int c_fd = -1;
  184.     char buffer[6];
  185.     int nread = -1;
  186.     struct sockaddr_in c_addr;//用于accept
  187.     memset(&c_addr,0,sizeof(struct sockaddr_in));//清零
  188.     s_fd = socket_init(IPADDR,IPPORT);
  189.     printf("%s|%s|%d: s_fd=%d\n",__FILE__,__func__,__LINE__,s_fd);
  190.     if(-1 == s_fd)
  191.     {
  192.         pthread_exit(0);
  193.     }
  194.     sleep(3);
  195.     int clen = sizeof(struct sockaddr_in);
  196.     while(1)
  197.         {
  198.         //accep第三个参数要求是指针//不连接,便堵塞,直到与客户端连接
  199.                 c_fd = accept(s_fd, (struct sockaddr *)&c_addr,&clen);
  200.         // 心包跳
  201.         int keepalive = 1; // 开启TCP KeepAlive功能
  202.         int keepidle = 5; // tcp_keepalive_time 3s内没收到数据开始发送心跳包
  203.         int keepcnt = 3; // tcp_keepalive_probes 每次发送心跳包的时间间隔,单位秒
  204.         int keepintvl = 3; // tcp_keepalive_intvl 每3s发送一次心跳包
  205.         setsockopt(c_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive,
  206.         sizeof(keepalive));
  207.         setsockopt(c_fd, SOL_TCP, TCP_KEEPIDLE, (void *) &keepidle, sizeof
  208.         (keepidle));
  209.         setsockopt(c_fd, SOL_TCP, TCP_KEEPCNT, (void *)&keepcnt, sizeof
  210.         (keepcnt));
  211.         setsockopt(c_fd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepintvl, sizeof
  212.         (keepintvl));
  213.         printf("--------ok?--------\n");
  214.         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));
  215.         printf("-----------ok!-----\n");
  216.         if(c_fd == -1)
  217.                 {
  218.                         perror("accept");//终端打出错误:accept:---
  219.             continue;
  220.                 }
  221.         while(1)
  222.         {
  223.             memset(buffer,0,sizeof(buffer));
  224.             nread = recv(c_fd,buffer,sizeof(buffer),0);// == n_read = read(c_fd,readBuf,sizeof(buffer));
  225.             printf("%s|%s|%d:nread=%d,buffer=%s\n",__FILE__,__func__,__LINE__,nread,buffer);
  226.             if(nread > 0)
  227.             {
  228.                 if(strstr(buffer,"open"))
  229.                 {
  230.                     //上锁
  231.                     pthread_mutex_lock(&mutex);
  232.                     //给阿里云发信号
  233.                     pthread_cond_signal(&cond);//发信号
  234.                     pthread_mutex_unlock(&mutex);
  235.                 }
  236.             }
  237.             else if(0==nread || -1==nread)
  238.             {
  239.                 break;
  240.             }
  241.         }
  242.         close(c_fd);
  243.     }
  244.     pthread_exit(0);
  245. }
  246. int main(int argc, char *argv[])
  247. {
  248.     printf("adsfasdf\n");
  249.     int len = 0;
  250.     int ret = -1;//标识
  251.     char *category = NULL;
  252.     unsigned char buffer[6] = {0xAA,0x55,0x00,0x00,0x55,0xAA};//AA 55 ** 00 55 AA
  253.     pthread_t get_voice_tid, category_tid,get_socket_tid;
  254.     //初始化
  255.     wiringPiSetup();//初始化wiringPi库
  256.     garbage_init(); //初始化阿里云接口
  257.    
  258.     // 用于检测特定进程是否在运行。
  259.     // 它通过调用系统命令ps -ax | grep process_name|grep -v grep来查找包含指定进程名的进程,并返回相应的进程号  
  260.     // mjpg_streamer 是一款开源的流媒体服务器软件,它能够从一系列输入插件(如USB摄像头)捕获视频数据,并通过网络以MJPG(Motion JPEG)格式实时传输
  261.     ret = detect_process("mjpg_streamer");
  262.     if(-1 == ret)
  263.     {
  264.         printf("detect process failed\n");
  265.         goto END;
  266.     }
  267.     //打开设备
  268.     serial_fd = myserialOpen(SERIAL_DEV,BAUD);//可代替设备节点 & 波特率   返回值fd
  269.     if(serial_fd == -1)//是否打开成功
  270.     {
  271.         goto END;   
  272.     }//*pget_voice(void *arg)里面判断
  273.    
  274.     //printf("%s|%s|%d:open serial failed\n",__FILE__,__func__,__LINE__);
  275.     //开语音的线程
  276.     pthread_create(&get_voice_tid,NULL,pget_voice,NULL);
  277.     //开网络线程
  278.     pthread_create(&get_socket_tid,NULL,pget_socket,NULL);
  279.     //开阿里云交互线程
  280.     pthread_create(&category_tid,NULL,pcategory,NULL);
  281.         //get_voice_tid获取语音模块的数据
  282.         //pthread_join用于等待指定的线程结束其执行
  283.     pthread_join(get_voice_tid,NULL);
  284.     pthread_join(category_tid,NULL);
  285.     pthread_join(get_socket_tid,NULL);
  286.     pthread_mutex_destroy(&mutex);
  287.     pthread_cond_destroy(&cond);
  288.     close(serial_fd);
  289. END:
  290.     garbage_final; //释放所有引用的Python对象
  291.     return 0;
  292. }
复制代码
5、实行流程和执行结果

5.1 配置客户端和mjpg_Stream



  • 利用网络调试助手



  • 查看Window & linux主机ip
       window IP 查询方法
    Linux orangepi IP 查询方法

5.2 调试和运行

  1. >>> gcc -o category *.c *.h -I /usr/include/python3.10/ -lpython3.10 -lwiringPi
  2. //得到 category 可执行文件
复制代码


  • 输入下令sudo -E ./category
1
2
5.3 开始识别



  • 一切都预备好了,如今可以开始实行了
  •    识别干垃圾(纸巾)
    识别结果


  •    识别可接纳垃圾
    识别结果


  •    识别湿垃圾(一个橘子)
    识别结果

6、总结



  • 在这个基于全志H616 ARM-Linux 的智能分拣项目中,我们利用的是网络调试助手来进行pc与orangepi通信,也就是说,我们可以在实现基于 TCP的socket编程 的远程PC控制;只要orangepi 与PC机的ip是互通的,便可以进行远程操控;
  • 当然我们也可以通过蓝牙模块使得移动端与orangepi进行通信,从而实现移动设备对硬件的控制;但是相比 网络通信,蓝牙通信就显得太局限了,无法做到远距离控制;
  • 我们也可以不消阿里云端识别服务,本身来训练本身的模型,然后写入orangpi里面,从而实现本身想要的智能识别功能;


   欢迎各人一起交换讨论!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

张春

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表