【嵌入式Linux项目】基于Linux的全志H616开发板智能家居项目(语音控制、人脸识别)

news2024/11/26 18:20:25

目录

一、功能需求

二、开发环境

1、硬件:

2、软件:

3、引脚分配:

三、关键点

1、设计模式之工厂模式

2、wiringPi库下的相关硬件操作函数调用

3、语音模块的串口通信

4、线程

5、摄像头的实时监控和拍照功能

6、人脸识别

四、编译和运行

五、视频功能展示


一、功能需求

  • 火焰传感器检测到火焰时,蜂鸣器报警,直到无火焰时停止报警
  • 语音控制多个LED灯的开和关(二楼灯、餐厅灯、客厅灯、卫生间灯)
  • 语音开启摄像头,并在对应IP地址的网页上实时监控画面
  • 语音控制摄像头拍摄照片,存在当前文件夹下(通过filezilla将照片传到PC上查看)
  • 语言开启人脸识别功能,将拍摄照片与本人照片对比,识别成功蜂鸣器滴一声,失败滴四声
  • 通过socket网络,实现开发板跑服务端,安卓机跑客户端,实现手机远程发送指令完成以上功能,要做app和学java(未实现)

二、开发环境

1、硬件:

Orangepi Zero2 全志H616开发板,语音模块SU-03T,摄像头模组OV9726,蜂鸣器,火焰传感器,4个LED等,4路继电器组,6v电源,若干杜邦线。

2、软件:

MobaXterm、VS Code、FileZilla

3、引脚分配:

在MobaXterm命令控制终端输入gpio readall可以查看开发板上的所有引脚。语音模块、蜂鸣器、火焰传感器和4路继电器组的引脚接线在下图框出。

三、关键点

1、设计模式之工厂模式

工厂模式提供了一种将对象的实例化过程封装在工厂类中的方式。本文通过使用工厂模式,将对象的创建与使用代码分离,提供一种统一的接口来创建不同类型的对象。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象(链表)。

    //1.指令工厂初始化
    pCommandHead = addVoiceContrlToInputCommandLink(pCommandHead);//串口
    pCommandHead = addSocketContrlToInputCommandLink(pCommandHead);
    
    //2.设备控制工厂初始化
    //四个LED+火灾+蜂鸣器+摄像头
    pdeviceHead = addBathroomLightToDeviceLink(pdeviceHead);
    pdeviceHead = addUpstairLightToDeviceLink(pdeviceHead);
    pdeviceHead = addRestaurantLightToDeviceLink(pdeviceHead);
    pdeviceHead = addLivingroomLightToDeviceLink(pdeviceHead);
    pdeviceHead = addFireToDeviceLink(pdeviceHead);
    pdeviceHead = addBeepToDeviceLink(pdeviceHead);
    pdeviceHead = addCameraToDeviceLink(pdeviceHead);

2、wiringPi库下的相关硬件操作函数调用

包括wiringPi库的初始化,蜂鸣器、火焰传感器、继电器组的输入输出引脚配置和高低电平设置。wiringP库下的串口配置和初始化。

3、语音模块的串口通信

本文用的是全志H616芯片中的串口设备/dev/ttyS5,波特率115200,实现与语音模块的串口通信。语音模块收到我们发出的命令词,将命令词转化为16进制数据通过串口发送到开发板,在程序中完成对串口数据接收、存储、判断是哪种命令、执行对应命令的操作,包括开关二楼灯、餐厅灯、客厅灯、卫生间灯、开启摄像头、拍一张照片和人脸识别。

语音模块SU-03T需要烧入对应命令的SDK,本文配置的SDK是在智能公元/AI产品零代码平台上完成,免费的。

int get_voice_type(char *cmd)
{
	if(!strcmp("OLL", cmd))    return OLL;
	if(!strcmp("ORL", cmd))    return ORL;
	if(!strcmp("OUL", cmd))    return OUL;
    if(!strcmp("OBL", cmd))    return OBL;
    if(!strcmp("CLL", cmd))    return CLL;
    if(!strcmp("CRL", cmd))    return CRL;
    if(!strcmp("CUL", cmd))    return CUL;
    if(!strcmp("CBL", cmd))    return CBL;
    if(!strcmp("OC" , cmd))    return OC ;
    if(!strcmp("TAP", cmd))    return TAP;
    if(!strcmp("OFR", cmd))    return OFR;
    perror("voice recognition failure");
}

void voiceContrlFunc(char *cmd){
	switch(get_voice_type(cmd)){
		case OLL://OLL ASCII对应的16进制4f 4c 4c
			printf("open livingroom light\n");
			struct Devices *tmpOpenLivingroomLight = findDeviceByName("livingroomLight", pdeviceHead);
			tmpOpenLivingroomLight->open(tmpOpenLivingroomLight->pinNum);
            break;
		case ORL://ORL 4f 52 4c
			printf("open restaurant light\n");
            struct Devices *tmpOpenRestaurantLight = findDeviceByName("restaurantLight", pdeviceHead);
			tmpOpenRestaurantLight->open(tmpOpenRestaurantLight->pinNum);
			break;
		case OUL://OUL 4f 55 4c
			printf("open upstair light\n");
            struct Devices *tmpOpenUpstairLight = findDeviceByName("upstairLight", pdeviceHead);
			tmpOpenUpstairLight->open(tmpOpenUpstairLight->pinNum);
			break;
		case OBL://OBL 4f 42 4c
			printf("open bathroom light\n");
            struct Devices *tmpOpenBathroomLight = findDeviceByName("bathroomLight", pdeviceHead);
			tmpOpenBathroomLight->open(tmpOpenBathroomLight->pinNum);
			break;
		case CLL://CLL 43 4c 4c
			printf("close livingroom light\n");
            struct Devices *tmpCloseLivingroomLight = findDeviceByName("livingroomLight", pdeviceHead);
			tmpCloseLivingroomLight->close(tmpCloseLivingroomLight->pinNum);
			break;
		case CRL://CRL 43 52 4c
			printf("close restaurant light\n");
            struct Devices *tmpCloseRestaurantLight = findDeviceByName("restaurantLight", pdeviceHead);
			tmpCloseRestaurantLight->close(tmpCloseRestaurantLight->pinNum);
			break;
		case CUL://CUL 43 55 4c
			printf("close upstair light\n");
            struct Devices *tmpCloseUpstairLight = findDeviceByName("upstairLight", pdeviceHead);
			tmpCloseUpstairLight->close(tmpCloseUpstairLight->pinNum);
			break;
		case CBL://CBL 43 42 4c
			printf("close bathroom light\n");
            struct Devices *tmpCloseBathroomLight = findDeviceByName("bathroomLight", pdeviceHead);
			tmpCloseBathroomLight->close(tmpCloseBathroomLight->pinNum);
			break;
		case OC://OC 4f 43
			printf("open camera\n");
            printf("   -------------------------------------------------------------------\n");
            printf("   --\033[1;32m 已开启摄像头,请到指定网页观看画面 https//192.168.43.206:8081 \033[0m--\n");//黄色字体
            printf("   -------------------------------------------------------------------\n");
            printf("\n");
			break;
		case TAP://TAP 54 41 50
			printf("take a picture\n");
            struct Devices *tmpTakeAPictureCamera = findDeviceByName("camera", pdeviceHead);
			tmpTakeAPictureCamera->takeAPicture();
			printf("   --------------------------------------\n");
            printf("   --\033[1;32m 已拍照,请在当前文件夹下查看照片 \033[0m--\n");//黄色字体
            printf("   --------------------------------------\n");
            printf("\n");
			break;
		case OFR://OFR 4f 46 52
			printf("open face recognition\n");
            struct Devices *tmpFaceRecCamera = findDeviceByName("camera", pdeviceHead);
			tmpFaceRecCamera->faceRecognition();
			break;
	}
}

4、线程

主函数中创建了三个线程:语音线程、网络线程、火焰检测线程。

语音线程(voiceThread):完成串口的配置和初始化,在while循环里每隔0.3s检查串口是否有数据到来。

网络线程(socketThread):接收客户端指令,实现手机远程发送指令完成以上功能,要做app和学java(未实现)。

火焰检查线程(socketThread):while循环里每隔0.5s检测是否有火焰,有则蜂鸣器发出警报,知道无火焰。

5、摄像头的实时监控和拍照功能

参考这篇文章:(1031条消息) 香橙派Orange Pi Zero 2开发板配置USB摄像头的方法_阿龙还在写代码的博客-CSDN博客

6、人脸识别

通过命令词【人脸识别】让摄像头拍摄一张照片并与本地的本人照片做对比,成功则蜂鸣器滴一声,失败则滴四声。人脸识别的处理程序调用的是翔云OCR人脸识别 (netocr.com)的人脸识别API,该接口地址https://netocr.com/api/faceliu.do是https协议的地址,https协议是在http和tcp之间多添加了一层,进行身份验证和数据加密。

若要访问https协议的地址,则需要用到Libcurl这个跨平台的网络协议库,配合OpenSSL库,就可以访问https协议的接口。(编译OpenSSL支持Libcurl的https访问,如果直接编译Libcurl,只能访问http不能访问https,需要OpenSSL库才能访问https)

 camera.c

#include "contrlDevices.h"
#include <stdio.h>
#include <curl/curl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

extern struct Devices *pdeviceHead;//extern表面变量或函数是定义在其他文件中,声明 为全局变量在该源文件使用
struct Devices* findDeviceByName(char *name, struct Devices *phead);

#define true 1
#define false 0
struct Devices camera;
char buf[1024] = {'\0'};//全局

void cameraTakeAPicture(){
    system("(fswebcam -d /dev/video0 --no-banner -r 1280x720 -S 5 ./image.jpg) > tmpFile");//照片存放在当前目录下
}

size_t readData(void *ptr, size_t size, size_t nmemb, void *stream){
    strncpy(buf, ptr, 1024);
}


char *getPicBase64FromFile(char *filePath){
    char *bufPic = NULL;
    char cmd[128] = {'\0'};
    sprintf(cmd, "base64 %s > tmpFile", filePath);
    system(cmd);//图片的base64流数据存入tmpFile文件中

    int fd = open("./tmpFile", O_RDWR);
    int filelen = lseek(fd, 0, SEEK_END);
    lseek(fd, 0, SEEK_SET);//重新让文件的光标回到初始位置
    bufPic = (char *)malloc(filelen + 2);//+1也可以 多加点没毛病
    memset(bufPic, '\0', filelen + 2);
    read(fd, bufPic, filelen);
    close(fd);
    system("rm -f tmpFile");
    return bufPic;
}

void cameraFaceRecognition(){
    camera.takeAPicture();
    CURL *curl;
    CURLcode res;
    char *postString;
    char *img1;
    char *img2;
    char *key = "DYRrmZz2rTwYGywyWdhKzR";
    char *secret = "56bc8e083a9b4d9fbf590413ddcb3a61";
    int  typeId = 21;
    char *format = "xml";
    char *bufPic1 = getPicBase64FromFile("./image.jpg");
    char *bufPic2 = getPicBase64FromFile("./zyl.jpg");

    int len = strlen(key) + strlen(secret) + strlen(bufPic1) + strlen(bufPic2) + 128;
    postString = (char *)malloc(len);
    memset(postString, '\0', len);//sizeof(postString)替换成len,因为postString是指针
    sprintf(postString, "&img1=%s&img2=%s&key=%s&secret=%s&typeId=%d&format=%s", bufPic1, bufPic2, key, secret, 21, format);//拼接字符串


    curl = curl_easy_init();
    if (curl){
        curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "/tmp/cookie.txt"); // 指定cookie文件
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postString);    // 指定post内容
        curl_easy_setopt(curl, CURLOPT_URL,"https://netocr.com/api/faceliu.do");   // 指定url
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, readData);//当有数据回来 调用回调函数
        res = curl_easy_perform(curl);

        struct Devices *beepHandler = findDeviceByName("beep", pdeviceHead);
        if(strstr(buf, "是") != NULL){ 
            beepHandler->open(beepHandler->pinNum); usleep(300000);
            beepHandler->close(beepHandler->pinNum);
            printf("\n");
            printf("   -----------------------------------\n");
            printf("   --\033[1;32m 人脸识别成功: the same person \033[0m--\n");//绿色字体
            printf("   -----------------------------------\n");
            printf("\n");
        }
        else{
            int i = 4;
            while(i--){
                beepHandler->open(beepHandler->pinNum); usleep(200000);
                beepHandler->close(beepHandler->pinNum); usleep(100000);
            }
            printf("\n");
            printf("   ------------------------------------\n");
            printf("   --\033[1;31m 人脸识别失败: different person \033[0m--\n");//红色字体
            printf("   ------------------------------------\n");
            printf("\n");
        }
        curl_easy_cleanup(curl);
    }
}

//实例化对象
struct Devices camera = {
    .deviceName = "camera",

    .takeAPicture = cameraTakeAPicture,
    .faceRecognition = cameraFaceRecognition

};

struct Devices* addCameraToDeviceLink(struct Devices *phead){
    if(phead == NULL){
        return &camera;
    }
    else{//头插
        camera.next = phead;
        phead = &camera;
        return phead;
    }
}

四、编译和运行

编译时需要用到一些库文件和该库文件里的头文件。

gcc bathroomLight.c livingroomLight.c restaurantLight.c upstairLight.c socketContrl.c voiceContrl.c fireDetection.c beep.c camera.c usartContrl.c main.c -I ../httpHandler/curl-7.71.1/_install/include/ -L ../httpHandler/curl-7.71.1/_install/lib/ -lcurl -lwiringPi -lpthread

运行

sudo ./a.out

五、视频功能展示

【linux项目】-智能家居

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/794112.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

4个特别使用做图标设计的软件,赶紧收藏

图标设计软件是设计师日常工作中经常使用到的设计软件之一&#xff0c;本文精选了4个好用的图标设计软件为大家推荐&#xff0c;一起来看看吧&#xff01; 1、即时设计 即时设计是一款免费的&#xff0c;支持成员在线协作的图标设计软件&#xff0c;它提供了强大的设计功能和…

Kafka 入门到起飞 - Kafka怎么做到保障消息不会重复消费的? 消费者组是什么?

Kafka怎么做到避免消息重复消费的&#xff1f; 消费者组是什么&#xff1f; 消费者&#xff1a; 1、订阅Topic&#xff08;主题&#xff09; 2、从订阅的Topic消费&#xff08;pull&#xff09;消息&#xff0c; 3、将消费消息的offset&#xff08;偏移量&#xff09;保存在K…

Navicat 设置时间默认值(当前最新时间)

目录 前言1. 原理分析2. datetime和timestamp的区别3. 补充 前言 文章较短&#xff0c;但是体会很深&#xff01;&#xff01;&#xff01;&#xff01; 1. 原理分析 需求任务&#xff1a;填写数据的时候&#xff0c;如果时间不写&#xff0c;数据会默认用最新时间补充 一开…

Vue 本地应用 图片切换 v-show v-bind实践

点击切换图片的本质&#xff0c;其实修改的是img标签的src属性。 图片的地址有很多个&#xff0c;在js当中通过数组来保存多个数据&#xff0c;数组的取值结合索引&#xff0c;根据索引可以来判断是否是第一张还是最后一张。 图片的变化本质是src属性被修改了&#xff0c;属性…

【Python入门【推导式创建序列、字典推导式、集合推导式】(九)

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱敲代码的小王&#xff0c;CSDN博客博主,Python小白 &#x1f4d5;系列专栏&#xff1a;python入门到实战、Python爬虫开发、Python办公自动化、Python数据分析、Python前后端开发 &#x1f4e7;如果文章知识点有错误…

数学随想:轻量级算法服务。

数学随想&#xff1a;轻量级算法服务TOC 通常认为&#xff0c;数列是算法服务的基础。但是&#xff0c;真正用于算法服务的数列只有几个众所周知的基础数列。虽然对于不同的任务可以选择使用数列的一段用于服务&#xff0c;但是数列的使用还是复杂而繁重的。特别是在计算应用日…

工控机有哪些常见的硬件和软件组件?

工控机常用于制造业、自动化控制、机械设备、医疗设备、交通运输、能源管理、环境监测、安防监控等行业和领域。它们可以用于控制、监控、数据采集和处理、自动化生产线等方面。 工控机有哪些常见的硬件和软件组件&#xff1f; 工控机作为一种特殊的计算机设备&#xff0c;通…

《golang设计模式》第一部分·创建型模式-01-单例模式(Singleton)

文章目录 1. 概述1.1 目的1.2 实现方式 2. 代码示例2.1 设计2.2 代码 1. 概述 1.1 目的 保证类只有一个实例有方法能让外部访问到该实例 1.2 实现方式 懒汉式 在第一次调用单例对象时创建该对象&#xff0c;这样可以避免不必要的资源浪费 饿汉式 在程序启动时就创建单例对象…

你真的懂软件测试人员的痛苦吗?——目前软件测试几大误区

前言 随着软件测试对提高软件质量重要性的不断提高&#xff0c;软件测试也不断受到重视。但是&#xff0c;国内软件测试过程的不规范&#xff0c;重视开发和轻视测试的现象依旧存在。因此&#xff0c;对于软件测试的重要性、测试方法和测试过程等方面都存在很多不恰当的认识&a…

[ 容器 ] Docker 网络

目录 一、 Docker 网络实现原理二、Docker 的网络模式三、网络模式讲解1. host 模式2&#xff0e;container模式3&#xff0e;none模式4&#xff0e;bridge模式5&#xff0e;自定义网络 四、资源控制1. CPU 资源控制2 对内存使用限制3. 对磁盘IO配额控制&#xff08;blkio&…

大数据技术之Hive3

目录标题 5、DML 数据操作5.1 数据导入5.1.1 向表中装载数据load5.1.2 通过查询语句向表中插入数据insert5.1.3 查询语句中创建表并加载数据5.1.4 创建表时通过 Location 指定加载数据路径 5.2 数据导出5.2.1 insert导出5.2.2 Hadoop 命令导出到本地 5.3 清除表中数据(Truncate…

剑指offer41.数据流中的中位数

我一开始的想法是既然要找中位数&#xff0c;那肯定要排序&#xff0c;而且这个数据结构肯定要能动态的添加数据的&#xff0c;肯定不能用数组&#xff0c;于是我想到了用优先队列&#xff0c;它自己会排序都不用我写&#xff0c;所以addNum方法直接调用就可以&#xff0c;但是…

多环境配置及配置文件位置

用端口测试了一下&#xff0c;properties>yml>yaml

未运行任何程序,GPU占用却很高

问题&#xff1a;没有运行任何程序&#xff0c;GPU的memory-usage占了很高&#xff0c;导致现在运行模型会cuda out of memory 解决&#xff1a;目前还未解决&#xff0c;希望大佬们可以给一些建议。

成为Pandas专业人士应该掌握的 30 种方法

一、说明 Pandas无疑是Python有史以来最好的库之一&#xff0c;用于表格数据整理和处理任务。但是&#xff0c;如果您是新手并试图牢牢掌握 Pandas 库&#xff0c;那么如果您从 Pandas 的官方文档开始&#xff0c;一开始事情可能会显得非常令人生畏和不知所措。 二、pandas主题…

leetcode每日一练-第98题- 验证二叉搜索树

一、思路 因为要验证多个节点是否是二叉搜索树,因此使用递归 二、解题方法 设计一个递归函数 helper(root, lower, upper) 来递归判断&#xff0c;函数表示考虑以 root 为根的子树&#xff0c;判断子树中所有节点的值是否都在 (l,r)的范围内&#xff08;注意是开区间&#x…

arm 函数栈回溯

大概意思就是arm每个函数开始都会将PC、LR、SP以及FP四个寄存器入栈。 下面我们看一下这四个寄存器里面保存的是什么内存 arm-linux-gnueabi-gcc unwind.c -mapcs -w -g -o unwind&#xff08;需要加上-mapcs才会严格按照上面说的入栈&#xff09; #include <stdio.h> …

Scaling Instruction-Finetuned Language Models

Paper name Scaling Instruction-Finetuned Language Models Paper Reading Note Paper URL: https://arxiv.org/pdf/2210.11416.pdf TL;DR 2022 年谷歌出的文章&#xff0c;对指令微调的影响因素进行分析&#xff0c;提出了一些提升指令微调效果的方案。与该文章一起出品…

AI学习笔记四:yolov5训练自己的数据集

若该文为原创文章&#xff0c;转载请注明原文出处。 一般情况下&#xff0c;大部分人的电脑都是没有cpu的&#xff0c;cpu也是可以训练的&#xff0c;但花费的时间太长&#xff0c;实际200张图片&#xff0c;使用CPU训练300轮花了3天&#xff0c;本章记录使用云服务器来训练自…

【无废话解决bug】python dash库 127.0.0.1 拒绝了我们的连接请求

无废话。 Q: python dash库在127.0.0.1无法打开–访问本地IP时显示拒绝访问 在python3写好了代码&#xff0c;打算运行代码后在浏览器127.0.0.1查看&#xff0c;浏览器提示&#xff1a;127.0.0.1 拒绝了我们的连接请求。 A:【本解决方法对dash库问题适用&#xff0c;其他涉及…