【嵌入式Linux项目】基于Linux的全志H616开发板智能家居项目(语音控制、人脸识别、安卓APP和PC端QT客户端远程操控)有视频功能展示

news2024/9/26 1:22:58

目录

一、功能需求

二、开发环境

1、硬件:

2、软件:

3、引脚分配:

三、关键点

1、设计模式之工厂模式

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

3、语音模块的串口通信

4、线程

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

6、人脸识别

四、编译和运行

五、视频功能展示


一、功能需求

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

二、开发环境

1、硬件:

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

2、软件:

MobaXterm、VS Code、FileZilla

3、引脚分配:

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

由于加了温湿度传感器之后板子上引脚不够,所以在第二个视频演示时会把语言识别模块替换下来。温湿度传感器对应IO为,VCC--5V, GND--GND, DAT--3wPi。

三、关键点

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、线程

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

语音线程(voiceThread):完成串口的配置和初始化,在while循环里每隔0.3s检查串口是否有语音命令词到来,有则执行对应操作。

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

网络线程(socketThread):接收客户端指令,实现上位机远程发送指令完成 [ 功能要求 ] 所述功能;给客户端发送温湿度传感器所测数据,实时显示在QT界面上。

//1、接收客户端的指令控制灯和摄像头 执行指令功能与语音控制复用
//2、向客户端发送温湿度数据 
void *socket_thread(){
    struct sockaddr_in c_addr;
    memset(&c_addr,0,sizeof(struct sockaddr_in));
    int clen = sizeof(struct sockaddr_in);

    socketHandler = findCommandByName("socketServer", pCommandHead);
    if(socketHandler == NULL){
            printf("find socketHandler error\n");
            pthread_exit(NULL);
    }
    printf("%s init success\n", socketHandler->commandName);
    socketHandler->Init(socketHandler, NULL, NULL);

    while(1){
        c_fd = accept(socketHandler->sfd, (struct sockaddr *)&c_addr, &clen);
        piThreadCreate(read_thread);
        pthread_tempAndHumi_create();
    }
}

 在网络线程中,首先对套接字进行初始化配置,包括IPV4因特网协议、TCP协议的配置(socket),绑定IP地址和端口号(bind),通过套接字标识符监听对应端口(listen)并等待客户端接入(accept)。

客户端接入后,即创建读数据线程,在while循环中进程阻塞在read函数,直到客户端发出指令,指令的执行函数与语音模块的语音指令执行函数复用(voiceContrlFunc函数在第4小点展示)。例如:在QT界面按下 [开客厅灯] 按钮,客户端通过网络发出字符串"OLL" ,在服务端read读到指令放入socketHandler->command,调用函数voiceContrlFunc(socketHandler->command)执行指令。

同时客户端在接入之后会调用函数pthread_tempAndHumi_create()创建发数据的线程,即实时发送温湿度的数据,QT中配合信号槽接收数据并在QT界面上显示,代码如下。

void *read_thread(){
    while(1){
        int n_read = 0;
        memset(socketHandler->command, '\0', sizeof(socketHandler->command));
        n_read = read(c_fd, socketHandler->command, sizeof(socketHandler->command));//n_read是读到字节数
        voiceContrlFunc(socketHandler->command);
        if(n_read == -1){
		    perror("read");
	    }
        else if(n_read>0){
		    printf("\nget: %d, %s\n",n_read, socketHandler->command);
	    }
        else{			
		    printf("client quit\n");
            break;
        }
    }
}

 QT程序,控制开关客厅灯的函数:

void Widget::on_livingRoomLight_clicked()
{
    if(livingRoomLightFlag == 1){
        //客户端向服务端发送消息
        if(tcpSocket->state() == QAbstractSocket::ConnectedState){
            ui->livingRoomLight->setText("关客厅灯");
            tcpSocket->write("OLL");
            ui->textBrowser->append("> 客厅灯已打开\n");
            livingRoomLightFlag = 0;
        }
        else{
            ui->textBrowser->append("请先与服务端连接!");
        }
    }
    else{
        if(tcpSocket->state() == QAbstractSocket::ConnectedState){
            ui->livingRoomLight->setText("开客厅灯");
            tcpSocket->write("CLL");
            ui->textBrowser->append("> 客厅灯已关闭\n");
            livingRoomLightFlag = 1;
        }
        else{
            ui->textBrowser->append("请先与服务端连接!");
        }
    }
}

 QT程序中的信号槽连接和TCP网络读函数:

connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(receiveMessages()));

void Widget::receiveMessages()
{
    QByteArray tmpByteArray = tcpSocket->readAll();
    char* tempHumi;
    tempHumi = tmpByteArray.data();
    ui->tempLabel->setText(QString::number(tempHumi[0]));
    ui->humiLabel->setText(QString::number(tempHumi[2]));
}

 

                                                                   PC端QT界面

                                                                         APP界面

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

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

4、语音模块的串口通信

本文用的是全志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;
	}
}

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;
    }
}

7、qt程序跨平台运行(编译成安卓APP)

搭建环境所需的安装包:

四、编译和运行

编译时需要用到一些库文件和该库文件里的头文件,用到温湿度传感器时加上tempAndHumi.c

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

五、视频功能展示

           智能家居功能展示

        PC端QT界面功能展示

            安卓app功能展示

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

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

相关文章

❤️创意网页:炫酷的网页 - 创造华丽粒子动画

✨博主&#xff1a;命运之光 &#x1f338;专栏&#xff1a;Python星辰秘典 &#x1f433;专栏&#xff1a;web开发&#xff08;简单好用又好看&#xff09; ❤️专栏&#xff1a;Java经典程序设计 ☀️博主的其他文章&#xff1a;点击进入博主的主页 前言&#xff1a;欢迎踏入…

操作系统攻击:早期WindowsMS10-046漏洞

目录 概述 漏洞成因 利用过程 漏洞复现 漏洞修复 概述 本次介绍早期的windows高危漏洞——MS10_046_SHORTCUT_ICON_DLLLOADER &#xff0c; 该漏洞可以通过浏览器跳转网络资源的方式利用&#xff0c;结合xss攻击用户的系统 危险性极高。 漏洞成因 漏洞成因&#xff1a; m…

param.grad、requires_grad、grad_fn、grad/梯度为None?

基本概念 1&#xff09;is_leaf 叶子节点和非叶子节点的区别&#xff1a;计算图中的节点分为叶子节点和非叶子节点&#xff0c;叶子节点可以理解成没有其他tensor再利用它进行计算&#xff08;例如b a1&#xff0c;那么b需要a进行计算&#xff0c;那么a就不是叶子结点&…

服务器介绍

本文章转载与b战up主谈三国圈&#xff0c;仅用于学习讨论&#xff0c;如有侵权&#xff0c;请联系博主 机架型服务器 堆出同时服务百万人次机组 刀型服务器 服务器炸了 比如用户访问量暴增 超过机组的峰值处理能力&#xff0c;进而导致卡顿或炸服&#xff0c; 适合企业的塔式…

xilinx FPGA 除法器ip核(divider)的使用(VHDLVivado)

一、创建除法ip核 vivado的除法器ip核有三种类型&#xff0c;跟ISE相比多了一个LuMult类型&#xff0c;总结来说就是 LuMult&#xff1a;使用了DSP切片、块RAM和少量的FPGA逻辑原语&#xff08;寄存器和lut&#xff09;&#xff0c;所以和Radix2相比占用fpga资源更少&#xff…

CS_SAVEBITS 这个样式有什么作用?

简单来说&#xff0c;如果你在创建窗口的时候在窗口类中指定了 CS_SAVEBITS 标志&#xff0c;则窗口管理器会尝试保存此窗口所遮盖的区域的位图数据。 但是&#xff0c;这里比较关键的问题是&#xff1a;为什么要这样做&#xff1f;只有明白了这其中的原理&#xff0c;你才会在…

2023.07.13力扣6题

931. 下降路径最小和 给你一个 n x n 的 方形 整数数组 matrix &#xff0c;请你找出并返回通过 matrix 的下降路径 的 最小和 。 下降路径可以从第一行中的任何元素开始&#xff0c;并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列&#xff08;即位…

Python批量将Excel内指定列的数据向上移动一行

本文介绍基于Python语言&#xff0c;针对一个文件夹下大量的Excel表格文件&#xff0c;对其中的每一个文件加以操作——将其中指定的若干列的数据部分都向上移动一行&#xff0c;并将所有操作完毕的Excel表格文件中的数据加以合并&#xff0c;生成一个新的Excel文件的方法。 首…

走进Linux世界【七、Linux网络及快照和克隆】

Linux系统学习 走进Linux世界【一、Linux概述】 走进Linux世界【二、VM与Linux安装】 走进Linux世界【三、Linux文件与路径】 走进Linux世界【四、Linux基本命令一】 走进Linux世界【五、Linux基本命令二】 走进Linux世界【六、Linux编辑器vim】 走进Linux世界【七、Lin…

Nest grpc 实践之调用 python ddddocr 库

我曾经写过一个项目 ddddocr_server&#xff0c;使用 fastapi 提供 http 接口&#xff0c;以此来调用 ddddocr 库。 其他语言想要调用的话&#xff0c;则是通过 http 协议的方式来调用。然而 http 协议的开销不小&#xff0c;而 Websocket 调用又不灵活&#xff0c;此时针对这…

【计网】TCP在可靠传输中都干了啥

文章目录 1、概述2、校验和3、序列号和确认应答机制4、重传机制4.1、介绍4.2、超时重传4.3、快速重传 5、滑动窗口协议5.1、介绍5.2、发送方的滑动窗口5.3、接收方的滑动窗口 6、流量控制7、拥塞控制7.1、介绍7.2、慢开始7.3、拥塞避免7.4、快重传和快恢复 1、概述 TCP 是面向…

Day45 算法记录| 动态规划 12

股票问题 309. 买卖股票的最佳时机含冷冻期714.买卖股票的最佳时机含手续费 309. 买卖股票的最佳时机含冷冻期 这个视频讲解的很好 309.最佳买卖股票时机含冷冻期 class Solution {public int maxProfit(int[] prices) {int day prices.length;int [][] dp new int[day][2…

【雕爷学编程】MicroPython动手做(14)——掌控板之OLED屏幕

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

IOS UICollectionView 设置cell大小不生效问题

代码设置flowLayout.itemSize 单元格并没有改变布局大小&#xff0c; 解决办法如下图&#xff1a;把View flow layout 的estimate size 设置为None&#xff0c;上面设置的itemSize 生效了。

【Spring Boot】实战:实现优雅的数据返回

实战&#xff1a;实现优雅的数据返回 本节介绍如何让前后台优雅地进行数据交互&#xff0c;正常的数据如何统一数据格式&#xff0c;以及异常情况如何统一处理并返回统一格式的数据。 1.为什么要统一返回值 在项目开发过程中经常会涉及服务端、客户端接口数据传输或前后台分…

不同路径 II

一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish”&#xff09;。 现在考虑网格中有障碍物。那么从左上角到右下角…

Android 面试题 ANR 五

&#x1f525; 什么是 ANR &#x1f525; ANR(Application Not Responding )应用无响应的简称&#xff0c;是为了在 APP卡死时&#xff0c;用户 可以强制退出APP的选择&#xff0c;从而避免卡机无响应问题&#xff0c;这是Android系统的一种自我保护机制。 在Android中&#xf…

Vue基础 --- 动态组件 插槽 自定义指令

1. 动态组件 1.1 什么是动态组件 动态组件指的是动态切换组件的显示与隐藏。 1.2 如何实现动态组件渲染 vue 提供了一个内置的 <component> 组件&#xff0c;专门用来实现动态组件的渲染。示例代码如下&#xff1a; data() { <!-- 1.当前要渲染的组件名称 -->…

ad+硬件每日学习十个知识点(13)23.7.24(MOS管纠错!!!)

1.MOS管到底怎么接&#xff1f;&#xff08;我一直都错了&#xff09; 2.MOS管的非饱和区 答&#xff1a; 3.MOS管的饱和区 答&#xff1a; 4.MOS管的截止区和击穿区 答&#xff1a; 5.做开关&#xff0c;让三极管工作在饱和区&#xff0c;让MOS管工作在非饱和区&…

rocketmq rsqldb 简单记录

GitHub 地址 https://github.com/alibaba/rsqldb/tree/main&#xff0c;是和目前stream sql化看齐的Rocketmq的sql&#xff0c;类似还有kafka的sqlDB 和flink sql。 目前版本0.2 &#xff0c;主要提供rest模式调用&#xff0c;controller类为public class RsqlController支持的…