-
请问AMOP为啥不能连续发数据,消息会进行堆积,接收端接收不到消息
-
一、前言在公共卫生事件频发的当下,尤其是在全球性疫情爆发后,国家对公共空间的健康监测和管理提出了更高的要求。医院、疾病防控中心和发热门诊作为疫情防控的第一线,需要高效且精准地对进出人员进行健康筛查,以防止病毒传播,保障医护人员及患者的安全。传统的手动体温检测方式不仅效率低下,而且存在交叉感染的风险,开发一种能够自动、快速、准确地进行人体温度监测与身份识别的系统显得非常的重要。当前文章会完整的介绍,如何采用香橙派AIpro设计出一套医院人脸红外测温系统。香橙派AIpro是一款高性价比的边缘计算设备,搭载了昇腾 AI 处理器,可提供 8TOPS INT8 的计算能力,能够运行Ubuntu 22.04操作系统,这为部署复杂的深度学习算法提供了硬件基础。本系统利用OpenCV和SSD算法模型进行人脸检测,通过各方面的模型训练,能确保在复杂光线和遮挡条件下仍能有效识别个体;结合红外测温技术,可以非接触式地测量额头温度,避免了传统接触式测文章温可能带来的卫生问题。考虑到环境因素对测温结果的影响,系统还配备了温湿度传感器,以实时监测并校准测温数据。为了实现数据的实时监控与分析,系统通过MQTT协议将收集到的信息上传至华为云物联网云平台,便于远程监控和数据分析,有助于疫情趋势的预测和资源的合理调配。本项目整体提供了一个智能化、自动化的人脸识别与体温监测解决方案,以提高公共卫生领域的响应速度和防控效率,减少人力资源的投入,同时降低潜在的感染风险,为构建安全健康的医疗环境贡献力量。本项目在完成最终的功能开发前,会先单个完成模块的功能开发,实现了单个模块功能之后,最终在整体合在一起实现最终的项目开发。整体项目会从搭建环境开始, 一步一步实现最终的项目效果。下面的开发出来的最终人脸检测设备最终设计效果:二、主控板介绍香橙派 AIpro开发板是香橙派联合华为精心打造的高性能 AI 开发板,搭载了昇腾 AI 处理器,可提供 8TOPS INT8 的计算能力,内存提供了 8GB 和 16GB两种版本。可以实现图像、视频等多种数据分析与推理计算,可广泛用于教育、机器人、无人机等场景。下面是香橙派 AIpro开发板的配置说明:模块规格昇腾 AI 处理器4 核 64 位 Arm 处理器 + AI 处理器AI 算力半精度(FP16):4 TFLOPS整数精度(INT8):8 TOPS内存类型:LPDDR4X 容量:8GB 或 16GB存储板载 32MB 的 SPI FlashMicro SD 卡插槽eMMC 插座:可外接 eMMC 模块M.2 M-Key 接口:可接 2280 规格的 NVMe SSD 或 SATA SSD以太网支持 10/100/1000Mbps板载 PHY 芯片:RTL8211FWi-Fi+蓝牙支持 2.4G 和 5G 双频 WIFIBT4.2模组:欧智通 62221BUUCUSB2 个 USB3.0 Host 接口1 个 Type-C 接口(只支持 USB3.0,不支持 USB2.0)摄像头2 个 MIPI CSI 2 Lane 接口显示2 个 HDMI 接口 1 个 MIPI DSI 2 Lane 接口音频一个 3.5mm 耳机孔,支持音频输入输出2 个 HDMI 音频输出40 pin 扩展口用于扩展 UART、I2C、SPI、PWM 和 GPIO 等接口按键一个复位键,一个关机键,一个升级按键拨码开关2 个拨码开关:用于控制 SD 卡、eMMC 和 SSD 启动选项电源支持 Type-C 供电,20V PD-65W 适配器LED 灯一个电源指示灯和一个软件可控指示灯风扇接口4pin,0.8mm 间距,用于接 12V 风扇,支持 PWM 控制电池接口2pin,2.54mm 间距,用于接 3 串电池,支持快充调试串口Micro USB 接口的调试串口支持的操作系统Ubuntu 22.04 和 openEuler 22.03外观规格介绍产品尺寸:107*68mm 重量:82g下面是香橙派 AIpro开发板的功能模块介绍:三、搭建开发环境3.1 准备需要的配件(1)准备一张至少32G的TFT卡,用来烧写系统。(2)准备一个读卡器,方便插入TFT卡,好方便插入到电脑上拷贝系统(3)香橙派 AIpro 主板一个(4)一根网线(方便插路由器上与香橙派 AIpro 连接)(5)一根type-C的电源线 + 电源插头(3A电流),这个主板买回来是带了电源的。 也可以用自己Android手机的数据线就行,拿手机充电器供电,因为目前Android手机电源线都是都是type-C 也支持快充的,电流也是满足需求的。(6)一个USB摄像头,用于后续项目开发里获取周围的实时图像,识别人脸。 (项目开发需要使用)(7)一个串口协议的红外测温传感器,用于后续项目开发里测量体温。(项目开发需要使用)(8)一个外放音箱,支持3.5mm的耳机插孔,方便后续项目开发里播放语音提示。(项目开发需要使用)(9)一块显示屏(这个不是必须的,可以直接Windows远程桌面访问系统,对前期开发来说没有任何影响,只要做成最终的产品才需要配屏幕)。3.2 开发板实物图拿回来的香橙派 AIpro 开发板实物是这样的。3.3 下载开发板资料拿到板子之后,第一件事肯定是先去官网下载板子对应的相关的资料。比如:用户手册、系统镜像、原理图、开发工具什么的。官网地址:cid:link_1翻到下面,找到资料下载地址,直接下载就行,下载会跳转到网盘。系统镜像我选择的 ubuntu22.04。资料下载下来之后,可以看到有一份官方的说明文档,指导板子的基本使用。如何烧写系统,如何启动系统等等。3.4 下载系统烧写工具链接:cid:link_0下载下来之后,直接双击正常安装,安装好之后打开的界面如下。 (选择本地制作)然后将 TF卡通过读卡器插到电脑上,准备烧写系统(就算有些电脑自带了TF卡的插槽也建议用USB读卡器,这个电脑自带的TF卡槽烧写系统无法启动)。 TF卡的容量至少要32G,最好是64G。选择要烧写的系统镜像文件(就是刚刚通过网盘下载的ubuntu系统镜像)。然后点击烧录镜像。弹出提示框,选择确认。然后可以看到,系统正在烧写中了,精心等待即可。烧录成功之后,会弹窗提示弹出SD卡。将TF卡从电脑上弹出,拔掉就行了。3.5 设置开发板启动模式香橙派 AIpro开发板支持从 TF 卡、eMMC 和 SSD(支持 NVMe SSD 和 SATA SSD)启动。具体从哪个设备启动是由开发板背面的两个拨码(BOOT1 和 BOOT2)开关来控制的。BOOT1 和 BOOT2 两个拨码开关都支持左右两种设置状态,所以总共有 4 种设置状态,开发板目前只使用了其中的三种。不同的设置状态对应的启动设备如下表所示:将BOOT1 和 BOOT2 两个拨码开关 全部拨到靠右的位置就可以选择从TF卡启动了。3.6 启动系统【1】将烧写好的TF卡插在板子上。【2】插好网线。网线一端接开发板的网口,一端接路由器,自己的笔记本电脑也是接的同一个路由器,让板子与电脑在同一个局域网内,方便接下来远程登录开发板的系统。【3】插好电源板子是没有电源开关的,电源线插好之后,系统就启动了。刚启动的时候风扇的声音会比较大,等待几秒就正常了。按下开发板左上角的PWR_OFF可以关闭系统,点击旁边的RESET可以重启系统。3.7 SSH远程登录系统系统启动之后,会自动请求路由器分配IP地址,我们只需要登录到开发板连接的路由器后台,就可以看到新接入的设备。我的用是小米路由器。直接在浏览器里输入:192.168.31.1 即可进入到路由器的后台终端。从下面图片里可以看到,香橙派 AIpro 已经分配到IP地址了,192.168.31.136。为了方便远程登录到系统终端,可以下载安装一个FinalShell 软件。下载地址:cid:link_4软件安装打开后,建立一个新的SSH链接,具体看下图的操作。这里面的主机IP地址就是从路由器后台看到的,分配给香橙派 AIpro开发板的IP地址。 端口号是固定的22,这是SSH协议的固定端口。用户名是root,密码是:Mind@123 这是烧写的香橙派 AIpro系统固定的用户名和密码,也就是系统内置的。双击刚才建立好的链接,就可以登录到系统终端。 进去终端之后基本上就可以进行正常的开发了。3.8 安装xdrp工具为了方便图形化方式开发,可以使用windows系统通过远程桌面登录香橙派 AIpro,就可以看到界面了,不过需要先安装工具。进入到香橙派 AIpro终端之后,输入安装命令:sudo apt-get install xrdp按下回车之后,会弹出确认窗口。输入 y之后,按下回车,继续安装。下面是完整的命令安装过程: 按顺序执行就行了。#安装xrdpsudo apt-get install xrdp#安装vnc4serversudo apt-get install vnc4server tightvncserver#安装xubuntu-desktopsudo apt-get install xubuntu-desktop#向xsession中写入xfce4-sessionecho “xfce4-session” >~/.xsession#开启xrdp服务sudo service xrdp restart注意,如果之后断电了,远程桌面无法链接上。可以先卸载xrdp,再重新安装即可。sudo apt-get remove --purge xrdp3.9 Window远程登录在windows上打开运行命令的窗口,输入mstsc来打开远程桌面。输入mstsc,点击确定。弹出窗口后,填入IP地址(这就是你的香橙派 AIpro 开发板的IP地址),点击连接。正常登录之后,就可以看到远程桌面的界面了。输入账号和密码。用户名是root,密码是:Mind@123 这是烧写的香橙派 AIpro系统固定的用户名和密码,也就是系统内置的。登录之后的界面:好了。接下来就可以进行项目的正式开发了。3.10 取消自动休眠Ubuntu桌面镜像会自动休眠,输入以下指令禁用休眠。sudo systemctl status sleep.targetsudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target四、安装Qt开发环境因为最终的项目需要使用界面,我的项目准备采用Qt进行开发,这一章节进行安装Qt开发环境。4.1 安装qtcreator在命令行终端分别输入以下命令安装qtcreator:root@orangepiaipro:~# sudo apt-get updateroot@orangepiaipro:~# sudo apt-get install qtcreatorroot@orangepiaipro:~# sudo apt-get install qtmultimedia5-devroot@orangepiaipro:~# sudo apt-get install libqt5serialport5-dev4.2 启动qtcreator安装好之后,就可以看到Qt软件了,点击即可打开。这是启动之后的效果。4.3 配置编译器默认安装Qt之后,编译器是配置错误,无法正常使用。【1】打开设置页面【2】选择编译器套件【3】配置编译器套件。将编译器改为GCC。4.4 新建工程Qt环境【1】新建工程【2】设置工程名称和路径(自己单独建立一个文件夹存放工程)【3】选择继承的基类【4】选择编译器套件【5】创建完成这就是创建好的工程。【6】点击左下角绿色三角形编译运行。下面是正常运行的效果,已经弹窗窗口,说明Qt的环境已经OK了。五、开发板初步测试为了了解下开发板本身的性能,先采用开发板开发一些小项目测试测试效果。现在系统根目录创建一个work目录,方便存放接下来的项目文件。5.1 项目1:开发一个基于HTTP协议的网络摄像头【1】项目介绍本项目主要采用C语言开发,实现了一个网络摄像头项目,在橙派 AIpro开发板上实现了一个HTTP服务器,,处理浏览器的请求,当浏览器访问过来时,就将本地采集到的摄像头画面发送给浏览器,与浏览器建立长连接通信,直接传输JPG图片,实现摄像头画面实时显示效果。支持登录页面,做了一个账号登录界面,访问服务器之后需要输入账号密码才可以正常进入服务器查看共享的画面。如果分享个摄像头画面,那是非常的方便的,想要查看分享的摄像头画面只需要浏览器里输入服务器的IP地址登录进去就可以看画面了。通过本项目的测试,可以了解到USB摄像头的读取效果,网络传输的效果。 为后续的其他项目开发做一个参考。【2】编写项目代码项目开发,代码编写先在Windows下进行,开发完毕,再拷贝到橙派 AIpro开发板上。这是在Windows下开发好的项目代码:【3】上传项目代码打开FinalShell终端,可以直接将开发好的项目源码,整个目录上传到香橙派 AIpro系统。通过FinalShell终端可以很方便的将香橙派 AIpro系统文件下载到本地,也可以将本地的文件很方便的上传上去。在开发项目的阶段是很方便的。【4】插入USB摄像头将USB摄像头插入到开发板的USB口,然后ls /dev/video* 查看摄像头的设备节点,确定摄像头是否识别成功。【4】编译运行项目项目里已经构建好了Makefile文件,直接make就可以编译。编译之后,运行项目。(base) root@orangepiaipro:~/work/http_camera# make(base) root@orangepiaipro:~/work/http_camera# ./http_app ./server <server_port> </dev/videoX>(base) root@orangepiaipro:~/work/http_camera# ./http_app 666 /dev/video0 运行命令的含义:./http_app 666 /dev/video0 666表示服务器的端口号。 /dev/video0是摄像头的端口号。【5】浏览器访问在自己电脑浏览器地址栏里输入:http://192.168.31.136:666就可以看到登录页面。登录成功之后,可以看到摄像头的实时画面。5.2 项目2: 基于华为云设计的智能家居控制系统【1】项目介绍基于香橙派 AIpro开发板设计的智能家居控制系统,通过MQTT协议连接华为云物联网云平台;通过DHT11传感器读取环境温湿度,将数据上传到华为云物联网云平台。在华为云云平台上也可以远程控制硬件端连接的LED灯,控制3种颜色显示。通过本项目的完整开发测试,可以掌握香橙派的GPIO口的基本使用以及网络的测试。为后续的其他项目开发做一个参考测试。【2】安装wiringPi(1)安装 wiringOP 前,请先确保 Linux 系统中存在/etc/orangepi-release 这个配置文件,里面的内容为:BOARD=orangepiaipro。(base) root@orangepiaipro:~/work/# cat /etc/orangepi-releaseBOARD=orangepiaipro(2)如果 Linux 中没有/etc/orangepi-release 这个配置文件,可以使用下面的命令创建一个。(base) root@orangepiaipro:~/work/# echo "BOARD=orangepiaipro" | sudo tee /etc/orangepi-release(3)下载 wiringOP 的代码。(base) root@orangepiaipro:~/work/# sudo apt-get update(base) root@orangepiaipro:~/work/# sudo apt-get install -y git(base) root@orangepiaipro:~/work/# git clone https://github.com/orangepi-xunlong/wiringOP.git -b next(4)然后编译安装 wiringOP。(base) root@orangepiaipro:~/work/# sudo apt-get install -y gcc make build-essential(base) root@orangepiaipro:~/work/# cd wiringOP(base) root@orangepiaipro:~/work/wiringOP# sudo ./build clean(base) root@orangepiaipro:~/work/wiringOP# sudo ./build(5)编译完之后,可以看到生成的文件查看GPIO口信息。(base) root@orangepiaipro:~/work/wiringOP# cd gpio/(base) root@orangepiaipro:~/work/wiringOP/gpio# ./gpio readall +------+-----+----------+--------+---+ AI PRO +---+--------+----------+-----+------+ | GPIO | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | GPIO | +------+-----+----------+--------+---+----++----+---+--------+----------+-----+------+ | | | 3.3V | | | 1 || 2 | | | 5V | | | | 76 | 0 | SDA7 | OFF | 0 | 3 || 4 | | | 5V | | | | 75 | 1 | SCL7 | OFF | 0 | 5 || 6 | | | GND | | | | 226 | 2 | GPIO7_02 | OFF | 0 | 7 || 8 | 0 | OFF | UTXD0 | 3 | 14 | | | | GND | | | 9 || 10 | 0 | OFF | URXD0 | 4 | 15 | | 82 | 5 | GPIO2_18 | OFF | 0 | 11 || 12 | 0 | OFF | GPIO7_03 | 6 | 227 | | 38 | 7 | GPIO1_06 | IN | 1 | 13 || 14 | | | GND | | | | 79 | 8 | GPIO2_15 | IN | 1 | 15 || 16 | 1 | IN | GPIO2_16 | 9 | 80 | | | | 3.3V | | | 17 || 18 | 0 | IN | GPIO0_25 | 10 | 25 | | 91 | 11 | SPI0_SD0 | OFF | 0 | 19 || 20 | | | GND | | | | 92 | 12 | SPI0_SDI | OFF | 0 | 21 || 22 | 1 | IN | GPIO0_02 | 13 | 2 | | 89 | 14 | SPI0_CLK | OFF | 0 | 23 || 24 | 0 | OFF | SPI0_CS | 15 | 90 | | | | GND | | | 25 || 26 | 0 | IN | GPIO2_19 | 16 | 83 | | | | SDA6 | | | 27 || 28 | | | SCL6 | | | | 231 | 17 | URXD7 | OFF | 0 | 29 || 30 | | | GND | | | | 84 | 18 | GPIO2_20 | IN | 0 | 31 || 32 | 0 | IN | GPIO1_01 | 19 | 35 | | 128 | 20 | GPIO4_00 | IN | 1 | 33 || 34 | | | GND | | | | 228 | 21 | GPIO7_04 | OFF | 0 | 35 || 36 | 0 | OFF | GPIO2_17 | 22 | 81 | | 3 | 23 | GPIO0_03 | IN | 1 | 37 || 38 | 0 | IN | GPIO7_06 | 24 | 230 | | | | GND | | | 39 || 40 | 0 | OFF | GPIO7_05 | 25 | 229 | +------+-----+----------+--------+---+----++----+---+--------+----------+-----+------+ | GPIO | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | GPIO | +------+-----+----------+--------+---+ AI PRO +---+--------+----------+-----+------+可以通过命令行测试GPIO口:(base) root@orangepiaipro:~/work# ./gpio mode 2 out 设置 wPi 为2的这个IO口为输出模式(base) root@orangepiaipro:~/work# ./gpio write 2 0 设置 wPi 为2的这个IO口输出0 (低电平)(base) root@orangepiaipro:~/work# ./gpio write 2 1 设置 wPi 为2的这个IO口输出1 (高电平)【3】GPIO口布局【4】控制LED灯编写的测试代码:#include <stdio.h>#include <wiringPi.h>#include <stdlib.h>#include <string.h>/*控制继电器高低电平亮灯*/#define LEDG 0#define LEDB 1#define LEDR 2int main(){ wiringPiSetup(); //置引脚编号方式为wiringPi编码 pinMode(LEDG,OUTPUT); pinMode(LEDB,OUTPUT); pinMode(LEDR,OUTPUT); while(1) { //全部关闭 digitalWrite(LEDG,LOW); digitalWrite(LEDB,LOW); digitalWrite(LEDR,LOW); //亮蓝色 digitalWrite(LEDG,HIGH); sleep(1); //全部关闭 digitalWrite(LEDG,LOW); digitalWrite(LEDB,LOW); digitalWrite(LEDR,LOW); //亮绿色 digitalWrite(LEDB,HIGH); sleep(1); //全部关闭 digitalWrite(LEDG,LOW); digitalWrite(LEDB,LOW); digitalWrite(LEDR,LOW); //亮红色 digitalWrite(LEDR,HIGH); sleep(1); } return 0;}编译代码:(base) root@orangepiaipro:~/work# gcc led.c -lwiringPi运行代码:(base) root@orangepiaipro:~/work# ./a.out 运行效果:【5】DHT11温湿度传感器数据读取代码:#include <wiringPi.h>#include <stdio.h>#include <stdlib.h> //编译:gcc -Wall -o dht11 dht11.c -lwiringPi -o app typedef unsigned char uint8;typedef unsigned int uint16;typedef unsigned long uint32; #define HIGH_TIME 32 int pinNumber = 5;uint32 databuf; uint8 readSensorData(void){ uint8 crc; uint8 i; pinMode(pinNumber, OUTPUT); // set mode to output digitalWrite(pinNumber, 0); // output a high level delay(25); digitalWrite(pinNumber, 1); // output a low level pinMode(pinNumber, INPUT); // set mode to input pullUpDnControl(pinNumber, PUD_UP); delayMicroseconds(27); if (digitalRead(pinNumber) == 0) //SENSOR ANS { while (!digitalRead(pinNumber)) ; //wait to high for (i = 0; i < 32; i++) { while (digitalRead(pinNumber)) ; //data clock start while (!digitalRead(pinNumber)) ; //data start delayMicroseconds(HIGH_TIME); databuf *= 2; if (digitalRead(pinNumber) == 1) //1 { databuf++; } } for (i = 0; i < 8; i++) { while (digitalRead(pinNumber)) ; //data clock start while (!digitalRead(pinNumber)) ; //data start delayMicroseconds(HIGH_TIME); crc *= 2; if (digitalRead(pinNumber) == 1) //1 { crc++; } } return 1; } else { return 0; }} int main(void){ printf("PIN:%d\n", pinNumber); wiringPiSetup(); //置引脚编号方式为wiringPi编码 pinMode(pinNumber, OUTPUT); // set mode to output digitalWrite(pinNumber, 1); // output a high level printf("Starting...\n"); while (1) { pinMode(pinNumber, OUTPUT); // set mode to output digitalWrite(pinNumber, 1); // output a high level delay(3000); if (readSensorData()) { printf("Sensor data read ok!\n"); printf("RH:%d.%d\n", (databuf >> 24) & 0xff, (databuf >> 16) & 0xff); printf("TMP:%d.%d\n", (databuf >> 8) & 0xff, databuf & 0xff); databuf = 0; } else { printf("Sensor dosent ans!\n"); databuf = 0; } } return 0;}编译代码:(base) root@orangepiaipro:~/work# gcc dht11.c -lwiringPi运行代码:(base) root@orangepiaipro:~/work# ./a.out PIN:5Starting...RH:68.4TMP:30.4RH:68.5TMP:30.2RH:68.2TMP:30.4RH:68.1TMP:30.3RH:68.1TMP:30.6RH:68.1TMP:30.4实物图:【6】注册华为云设备华为云物联网平台的整体就不再详细展示了,可以直接看视频。B站的视频链接:cid:link_2(1)注册产品(2)注册设备(3)创建命令(4)得到MQTT三元组IP地址:117.78.5.125端口号:1883ClientId 6693872aa559ef6226685350_dev1_0_0_2024071408Username 6693872aa559ef6226685350_dev1Password 8ce1b26a6fac2c52402d2911a9a951efe6026f71041037a963bebdd4a099190f订阅主题:$oc/devices/6693872aa559ef6226685350_dev1/sys/messages/down发布主题:$oc/devices/6693872aa559ef6226685350_dev1/sys/properties/report发布数据:{"services": [{"service_id": "stm32","properties":{"DHT11_T":23,"DHT11_H":80}}]}【7】编写整体项目接下来就编写代码,连接华为云物联网平台,完成数据上传。 将采集的温湿度数据上传到华为云物联网云平台。 同时支持在华为云物联网平台下发命令远程控制设备端的LED灯。代码是采用纯C语言编写,实现了MQTT协议,完成了与物联网云平台交互。关于MQTT协议的整体编写过程,可以直接看视频:cid:link_3(1)这是写好的项目代码完整的代码:#include <stdio.h>#include <sys/types.h> /* See NOTES */#include <sys/socket.h>#include <netinet/in.h>#include <netinet/ip.h> /* superset of previous */#include <arpa/inet.h>#include <poll.h>#include <unistd.h>#include <stdlib.h>#include <pthread.h>#include <signal.h>#include "mqtt.h"#include "main.h"#include <netdb.h>#include <stdio.h>#include <wiringPi.h>#include <stdlib.h>#include <string.h>/*控制继电器高低电平亮灯*/#define LEDG 0#define LEDB 1#define LEDR 2//服务器IP#define SERVER_IP "117.78.5.125"#define SERVER_PORT 1883 //端口号//MQTT三元组#define ClientID "6693872aa559ef6226685350_dev1_0_0_2024071408"#define Username "6693872aa559ef6226685350_dev1"#define Password "8ce1b26a6fac2c52402d2911a9a951efe6026f71041037a963bebdd4a099190f"//密文 //订阅主题:#define SET_TOPIC "$oc/devices/6693872aa559ef6226685350_dev1/sys/messages/down"//订阅//发布主题:#define POST_TOPIC "$oc/devices/6693872aa559ef6226685350_dev1/sys/properties/report"//发布char mqtt_message[1024*1024];//上报数据缓存区char request_id[100];char mqtt_cmd_message[100];char mqtt_cmd_data[100];int sockfd;/*获取平台下发数据*/void *pth_work_func(void *arg){ char buff[1024]; int size=0; int i=0; while(1) { size=Client_GetData(buff); printf("size=%d\r\n",size); if(size<0)break; for(i=0;i<size;i++) { printf("%c ",buff[i]); } buff[size]='\0'; if(size>5) { printf("%s\r\n",buff+5); if(strstr((char*)&buff[5],"sys/commands/request_id=")) { char *p=NULL; p=strstr((char*)&buff[5],"request_id"); if(p) { //解析数据 //$oc/devices/6210e8acde9933029be8facf_dev1/sys/properties/get/request_id=5f359b5c-542f-460e-9f51-85e82150ff4a{"service_id":"gps"} strncpy(request_id,p,47); } //上报数据 sprintf(mqtt_cmd_message,"{\"result_code\":0,\"response_name\":\"COMMAND_RESPONSE\",\"paras\":{\"result\":\"success\"}}"); sprintf(mqtt_cmd_data,"$oc/devices/6693872aa559ef6226685350_dev1/sys/commands/response/%s", request_id); MQTT_PublishData(mqtt_cmd_data,mqtt_cmd_message,0); printf("应答-发布主题:%s\r\n",mqtt_cmd_data); printf("应答-发布数据:%s\r\n",mqtt_cmd_message); } if(strstr((char*)&buff[5],"\"LED_SW\":1")) { //全部关闭 digitalWrite(LEDG,LOW); digitalWrite(LEDB,LOW); digitalWrite(LEDR,LOW); //亮蓝色 digitalWrite(LEDG,HIGH); } if(strstr((char*)&buff[5],"\"LED_SW\":2")) { //全部关闭 digitalWrite(LEDG,LOW); digitalWrite(LEDB,LOW); digitalWrite(LEDR,LOW); //亮绿色 digitalWrite(LEDB,HIGH); } if(strstr((char*)&buff[5],"\"LED_SW\":3")) { //全部关闭 digitalWrite(LEDG,LOW); digitalWrite(LEDB,LOW); digitalWrite(LEDR,LOW); //亮红色 digitalWrite(LEDR,HIGH); } if(strstr((char*)&buff[5],"\"LED_SW\":0")) { //全部关闭 digitalWrite(LEDG,LOW); digitalWrite(LEDB,LOW); digitalWrite(LEDR,LOW); } } printf("\r\n"); }} /*信号处理函数*/ void signal_func(int sig){ //printf("捕获的信号:%d\n",sig); if(sig==SIGALRM) { MQTT_SentHeart();//心跳包 alarm(5); }}typedef unsigned char uint8;typedef unsigned int uint16;typedef unsigned long uint32; #define HIGH_TIME 32 int pinNumber = 5;uint32 databuf; uint8 readSensorData(void){ uint8 crc; uint8 i; pinMode(pinNumber, OUTPUT); // set mode to output digitalWrite(pinNumber, 0); // output a high level delay(25); digitalWrite(pinNumber, 1); // output a low level pinMode(pinNumber, INPUT); // set mode to input pullUpDnControl(pinNumber, PUD_UP); delayMicroseconds(27); if (digitalRead(pinNumber) == 0) //SENSOR ANS { while (!digitalRead(pinNumber)) ; //wait to high for (i = 0; i < 32; i++) { while (digitalRead(pinNumber)) ; //data clock start while (!digitalRead(pinNumber)) ; //data start delayMicroseconds(HIGH_TIME); databuf *= 2; if (digitalRead(pinNumber) == 1) //1 { databuf++; } } for (i = 0; i < 8; i++) { while (digitalRead(pinNumber)) ; //data clock start while (!digitalRead(pinNumber)) ; //data start delayMicroseconds(HIGH_TIME); crc *= 2; if (digitalRead(pinNumber) == 1) //1 { crc++; } } return 1; } else { return 0; }} unsigned int DHT11_T;// 环境温度unsigned int DHT11_H;// 环境湿度int main(){ wiringPiSetup(); //置引脚编号方式为wiringPi编码 pinMode(LEDG,OUTPUT); pinMode(LEDB,OUTPUT); pinMode(LEDR,OUTPUT); //DHT11温湿度初始化 pinMode(pinNumber, OUTPUT); // set mode to output digitalWrite(pinNumber, 1); // output a high level int stat; sockfd=socket(AF_INET,SOCK_STREAM,0); if(sockfd==-1) { printf("网络套接字打开失败\n"); return 0; } signal(SIGPIPE,SIG_IGN);/*忽略SIGPIPE信号*/ signal(SIGALRM,signal_func);/*闹钟信号*/ /*连接服务器*/ struct sockaddr_in addr; addr.sin_family=AF_INET;//IPV4 addr.sin_port=htons(SERVER_PORT);/*端口号*/ addr.sin_addr.s_addr=inet_addr(SERVER_IP);//inet_addr(ip);//服务器IP if(connect(sockfd, (struct sockaddr *)&addr,sizeof(struct sockaddr_in))==0) { printf("server connect ok\n"); MQTT_Init(); while(1) { /*登录服务器*/ if(MQTT_Connect(ClientID,Username,Password)==0) { break; } sleep(1); printf("server connect ....\n"); } printf("MQTT_Connect OK\r\n"); //订阅物联网平台数据 stat=MQTT_SubscribeTopic(SET_TOPIC,1,1); if(stat) { close(sockfd); printf("MQTT_SubscribeTopic ERROR\r\n"); exit(0); } printf("MQTT_SubscribeTopic ok\r\n"); /*创建线程*/ pthread_t id; pthread_create(&id, NULL,pth_work_func,NULL); pthread_detach(id);//设置分离属性 //发送心跳包 // alarm(5);//闹钟函数,时间到达会产生SIGALRM信号 while(1) { //读取DHT11温湿度数据 pinMode(pinNumber, OUTPUT); // set mode to output digitalWrite(pinNumber, 1); // output a high level delay(3000); if (readSensorData()) { printf("DHT11 Sensor data read ok!\n"); printf("RH:%d.%d\n", (databuf >> 24) & 0xff, (databuf >> 16) & 0xff); printf("TMP:%d.%d\n", (databuf >> 8) & 0xff, databuf & 0xff); //温度整数部分 DHT11_H=((databuf >> 24) & 0xff); printf("DHT11_T:%d\r\n",DHT11_T); //湿度整数部分 DHT11_T=((databuf >> 8) & 0xff); printf("DHT11_H:%d\r\n",DHT11_H); databuf = 0; } else { printf("Sensor dosent ans!\n"); databuf = 0; } //组合传感器状态数据 sprintf(mqtt_message,"{\"services\": [{\"service_id\": \"stm32\",\"properties\":{\"DHT11_T\":%d,\"DHT11_H\":%d}}]}",DHT11_T,DHT11_H);//温度 //上报数据 MQTT_PublishData(POST_TOPIC,mqtt_message,0); printf("MQTT_PublishData....\r\n"); sleep(2); } }}(2)这是编译运行后的效果(3)在华为云物联网平台后台,可以看到设备已经在线了,同时也实时收到设备端上传的数据。(4)下发命令测试。 通过命令下发控制设备端的LED灯。5.3 项目3:OpenCV+卷积神经网络实现人脸识别本项目通过OpenCV加载训练好的SSD模型,实现人脸检测,能够在图像中找到并标记出人脸的位置和置信度。通过本项目,可以验证整个系统的算法运行速度。为后续的项目开发做参考。(1)安装python (烧写的系统本身自带了完整的Python环境,可以不需要安装,如果没有才需要安装)sudo apt updatesudo apt install python3(2)编写代码加载模型识别人脸import cv2import numpy as npimport timeprototxt_path = "./deploy.prototxt.txt"model_path = "./res10_300x300_ssd_iter_140000_fp16.caffemodel"image_path = "6.jpg"# 加载模型model = cv2.dnn.readNetFromCaffe(prototxt_path, model_path)# 读取图像image = cv2.imread(image_path)h, w = image.shape[:2]# 准备模型输入的 blobblob = cv2.dnn.blobFromImage(cv2.resize(image, (300, 300)), 1.0, (300, 300), (104.0, 177.0, 123.0), swapRB=False)# 设置 blob 作为模型的输入model.setInput(blob)# 进行推断并获取输出start_time = time.time()output = model.forward()end_time = time.time()# 遍历检测结果font_scale = 1.0for i in range(output.shape[2]): confidence = output[0, 0, i, 2] # 通过置信度阈值过滤弱检测结果 if confidence > 0.5: box = output[0, 0, i, 3:7] * np.array([w, h, w, h]) (start_x, start_y, end_x, end_y) = box.astype("int") # 绘制边界框和置信度 cv2.rectangle(image, (start_x, start_y), (end_x, end_y), (255, 0, 0), 2) text = f"{confidence * 100:.2f}%" cv2.putText(image, text, (start_x, start_y - 10), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (255, 0, 0), 2)# 显示和保存带有检测结果的图像cv2.imwrite("beauty_detected.jpg", image)# 输出识别耗时print(f"识别耗时:{end_time - start_time:.3f} 秒")(3)运行效果(4)将图片下载下来打开5.4 项目4:OpenCV+YOLOv3实现目标检测本项目通过OpenCV加载YOLOV3官方的模型,实现目标。通过本项目,可以验证整个系统的算法运行速度。为后续的项目开发做参考。实现代码:#include <opencv2/opencv.hpp>#include <opencv2/dnn.hpp>#include <fstream>#include <iostream>#include <algorithm>#include <cstdlib>using namespace std;using namespace cv;using namespace cv::dnn;void image_detection();String yolo_cfg = "./yolov3.cfg";String yolo_model = "./yolov3.weights";int main(int argc, char** argv){ image_detection();}void image_detection() { //加载网络模型 Net net = readNetFromDarknet(yolo_cfg, yolo_model); //net.setPreferableBackend(DNN_BACKEND_INFERENCE_ENGINE); net.setPreferableTarget(DNN_TARGET_CPU); std::vector<String> outNames = net.getUnconnectedOutLayersNames(); for (int i = 0; i < outNames.size(); i++) { printf("output layer name : %s\n", outNames[i].c_str()); } vector<string> classNamesVec; ifstream classNamesFile("./coco.names"); if (classNamesFile.is_open()) { string className = ""; while (std::getline(classNamesFile, className)) classNamesVec.push_back(className); } // 加载图像 Mat frame = imread("6.jpg"); Mat inputBlob = blobFromImage(frame, 1 / 255.F, Size(416, 416), Scalar(), true, false); net.setInput(inputBlob); // 检测 std::vector<Mat> outs; net.forward(outs, outNames); vector<double> layersTimings; double freq = getTickFrequency() / 1000; double time = net.getPerfProfile(layersTimings) / freq; ostringstream ss; ss << "detection time: " << time << " ms"; putText(frame, ss.str(), Point(20, 20), 0, 0.5, Scalar(0, 0, 255)); vector<Rect> boxes; vector<int> classIds; vector<float> confidences; for (size_t i = 0; i < outs.size(); ++i) { // Network produces output blob with a shape NxC where N is a number of // detected objects and C is a number of classes + 4 where the first 4 // numbers are [center_x, center_y, width, height] float* data = (float*)outs[i].data; for (int j = 0; j < outs[i].rows; ++j, data += outs[i].cols) { Mat scores = outs[i].row(j).colRange(5, outs[i].cols); Point classIdPoint; double confidence; minMaxLoc(scores, 0, &confidence, 0, &classIdPoint); if (confidence > 0.5) { int centerX = (int)(data[0] * frame.cols); int centerY = (int)(data[1] * frame.rows); int width = (int)(data[2] * frame.cols); int height = (int)(data[3] * frame.rows); int left = centerX - width / 2; int top = centerY - height / 2; classIds.push_back(classIdPoint.x); confidences.push_back((float)confidence); boxes.push_back(Rect(left, top, width, height)); } } } vector<int> indices; NMSBoxes(boxes, confidences, 0.5, 0.2, indices); for (size_t i = 0; i < indices.size(); ++i) { int idx = indices[i]; Rect box = boxes[idx]; String className = classNamesVec[classIds[idx]]; putText(frame, className.c_str(), box.tl(), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(255, 0, 0), 2, 8); rectangle(frame, box, Scalar(0, 0, 255), 2, 8, 0); } # 保存结果图片 cv2.imwrite('detections.jpg', frame) waitKey(0); return;}将识别的图片结果拷贝下来,查看效果。五、测温项目开发5.1 外设模块选型需要用到的传感器如下:(1)LU90614非接触式红外测温模块(串口协议),用于测量体温。(2)DHT11温湿度传感器,用于测量环境的温湿度。(3)USB摄像头,用于捕获图像,检测人脸。(4)一块香橙派 AIpro主控板。(5)一个三色LED灯,用于显示检测的体温状态。 红、绿、蓝 三种颜色。5.2 整体的项目代码整体项目是采用Qt开发的,因为需要通过显示屏展示界面,在界面上显示人脸的识别效果,温度测量效果等信息。【1】技术实现方式说明(1)这里面的LU90614非接触式红外测温模块 采用USB-TTL模块接入系统的。在/dev目录下的节点是ttyUSB0。没有使用开发板本身的IO口。(2)本项目是先在Windows下开发完成后,再上传到香橙派 AIpro开发板运行,在香橙派 AIpro里安装了Qt的开发环境。(3)体温传感器的串口数据读取,没有采用Qt本身的串口接口,而是采用了标准Linux下的方式读取串口数据。(4)摄像头的采集没有采用Qt的内置接口,而是采用了Linux下V4L2框架完成的图像采集。(5)MQTT协议没有采用第三方库,是自己基于Linux下的socket,从0开始编写的。(6)显示屏采用HDMI接口的7寸显示屏。作为整个项目的界面终端。【2】摄像头图像采集代码下面是采集USB实时画面的代码。#include <stdio.h>#include <stdlib.h>#include <string.h>#include <fcntl.h>#include <unistd.h>#include <errno.h>#include <sys/ioctl.h>#include <sys/mman.h>#include <linux/videodev2.h>#define WIDTH 640#define HEIGHT 480struct buffer { void *start; size_t length;};int pthread_run(){ int fd; struct v4l2_format fmt; struct v4l2_requestbuffers req; struct v4l2_buffer buf; enum v4l2_buf_type type; struct buffer *buffers; unsigned char *rgb888_buffer; // 打开摄像头设备 fd = open("/dev/video0", O_RDWR); if (fd == -1) { perror("打开/dev/video0失败"); return 1; } // 设置格式 memset(&fmt, 0, sizeof(fmt)); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = WIDTH; fmt.fmt.pix.height = HEIGHT; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; // 使用YUYV格式,常见于USB摄像头 fmt.fmt.pix.field = V4L2_FIELD_NONE; if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) { perror("设置格式失败"); close(fd); return 1; } // 请求缓冲区 memset(&req, 0, sizeof(req)); req.count = 1; // 缓冲区数量 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) { perror("请求缓冲区失败"); close(fd); return 1; } // 分配并映射缓冲区 buffers = calloc(req.count, sizeof(*buffers)); if (!buffers) { perror("分配缓冲区内存失败"); close(fd); return 1; } // 查询缓冲区 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = 0; if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) { perror("查询缓冲区失败"); close(fd); return 1; } // 内存映射 buffers[0].length = buf.length; buffers[0].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset); if (buffers[0].start == MAP_FAILED) { perror("内存映射失败"); close(fd); return 1; } // 开始流式传输 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(fd, VIDIOC_STREAMON, &type) == -1) { perror("开始流式传输失败"); close(fd); return 1; } // 捕获循环(示例:捕获一帧) while (1) { // 入队缓冲区 if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) { perror("入队缓冲区失败"); close(fd); return 1; } // 出队缓冲区 if (ioctl(fd, VIDIOC_DQBUF, &buf) == -1) { perror("出队缓冲区失败"); close(fd); return 1; } // 处理帧(转换为RGB888格式) // 示例:将YUYV转换为RGB888 rgb888_buffer = (unsigned char *)malloc(WIDTH * HEIGHT * 3); for (int i = 0, j = 0; i < WIDTH * HEIGHT * 2; i += 4, j += 6) { // YUYV到RGB888的简化转换(实际应用中可能需要更复杂的算法) unsigned char Y0 = ((unsigned char *)buffers[0].start)[i + 0]; unsigned char U = ((unsigned char *)buffers[0].start)[i + 1]; unsigned char Y1 = ((unsigned char *)buffers[0].start)[i + 2]; unsigned char V = ((unsigned char *)buffers[0].start)[i + 3]; rgb888_buffer[j + 0] = Y0 + 1.402 * (V - 128); // 红色分量 rgb888_buffer[j + 1] = Y0 - 0.344 * (U - 128) - 0.714 * (V - 128); // 绿色分量 rgb888_buffer[j + 2] = Y0 + 1.772 * (U - 128); // 蓝色分量 rgb888_buffer[j + 3] = Y1 + 1.402 * (V - 128); // 红色分量 rgb888_buffer[j + 4] = Y1 - 0.344 * (U - 128) - 0.714 * (V - 128); // 绿色分量 rgb888_buffer[j + 5] = Y1 + 1.772 * (U - 128); // 蓝色分量 } // 使用rgb888_buffer进行进一步处理(如保存到文件、显示) // 示例:保存到文件 FILE *fp = fopen("frame.rgb", "wb"); if (fp) { fwrite(rgb888_buffer, 1, WIDTH * HEIGHT * 3, fp); fclose(fp); } free(rgb888_buffer); break; // 示例中仅处理一帧,所以退出循环 } // 停止流式传输 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(fd, VIDIOC_STREAMOFF, &type) == -1) { perror("停止流式传输失败"); close(fd); return 1; } // 解除内存映射 munmap(buffers[0].start, buf.length); // 清理和关闭 free(buffers); close(fd); return 0;}【3】体温数据采集(串口)下面是采集体温传感器的代码。#include <stdio.h>#include <stdlib.h>#include <string.h>#include <fcntl.h>#include <unistd.h>#include <errno.h>#include <sys/select.h>#include <poll.h>#define SERIAL_DEVICE "/dev/ttyUSB0"#define BAUDRATE B9600int temp_read_pthread() { int fd; char *sendbuf = "\xFA\xC5\xBF"; // 发送体温模式指令 char recvbuf[8]; struct termios options; struct pollfd pfd; int timeout = 1000; // 超时时间,单位毫秒 // 打开串口设备文件 if ((fd = open(SERIAL_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK)) == -1) { perror("open serial port failed"); exit(1); } // 设置串口参数 tcgetattr(fd, &options); cfmakeraw(&options); options.c_cflag |= (CLOCAL | CREAD); options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; options.c_iflag &= ~(IXON | IXOFF | IXANY); options.c_oflag &= ~OPOST; cfsetispeed(&options, BAUDRATE); cfsetospeed(&options, BAUDRATE); tcsetattr(fd, TCSANOW, &options); // 初始化poll结构体 pfd.fd = fd; pfd.events = POLLIN; // 发送命令 write(fd, sendbuf, 3); while (1) { // 使用poll等待数据 if (poll(&pfd, 1, timeout) > 0) { int nread = read(fd, recvbuf, sizeof(recvbuf)); if (nread > 0) { printf("Received data: "); for (int i = 0; i < nread; i++) { printf("%02x ", recvbuf[i]); } printf("\n"); } else { printf("Read error: %s\n", strerror(errno)); } } else { printf("No data received in %d ms\n", timeout); } } close(fd); return 0;}【4】人脸识别图像处理下面是完成人脸识别处理的代码。#include "image_handle.h"#pragma execution_character_set("utf-8")//关闭线程void ImageHandle::close(){ run_flag=0; this->quit(); this->wait();}//线程执行函数void ImageHandle::run(){ QImage use_image; while(run_flag) { //如果没有图像可以处理 if(start_run==0) { //休眠100毫秒 msleep(100); continue; } //表示已经处理过 start_run=0; //表示开始处理图像 Handle_flag=1; //调用图像处理算法 对 image 的图像进行处理 //1. 人脸识别 opencv_face(m_image); //处理完毕之后 //将图像传出去给UI界面显示 emit HandleSend(m_image); //处理完毕 Handle_flag=0; }}//传入待处理的图片数据void ImageHandle::SetImage(QImage &image){ if(Handle_flag==0) { start_run=1; //表示有图像可以处理了 //保存待处理的原图像 m_image=image; }}void printMatInfo(const cv::Mat& mat){ QTextStream out(stdout); out << "Type: " << mat.type() << endl; out << "Channels: " << mat.channels() << endl; out << "Size: " << mat.size().width << "x" << mat.size().height << endl; out << "Depth: " << mat.depth() << endl; out << "Element Size: " << mat.elemSize() << " bytes" << endl; out << "Total Size: " << mat.total() * mat.elemSize() << " bytes" << endl;}bool saveMatToFile(const cv::Mat& mat, const std::string& filename){ // 将cv::Mat保存为图像文件 bool success = cv::imwrite(filename, mat); if (!success) { // 保存失败时输出错误信息 std::cerr << "Failed to save image: " << filename << std::endl; } return success;}// 绘制马赛克void drawMosaic(Mat& image, Rect roi) { // 将人脸区域缩小为一定比例,以增加马赛克效果 Rect smallRoi = roi; smallRoi.x += smallRoi.width * 0.1; smallRoi.y += smallRoi.height * 0.1; smallRoi.width -= smallRoi.width * 0.2; smallRoi.height -= smallRoi.height * 0.2; // 对缩小后的人脸区域进行马赛克处理 Mat mosaic = image(smallRoi); //可以调整数字,调整马赛克的像素大小 resize(mosaic, mosaic, Size(smallRoi.width / 20, smallRoi.height / 20), INTER_NEAREST); resize(mosaic, image(smallRoi), smallRoi.size(), 0, 0, INTER_NEAREST);}#include "widget.h"//人脸检测代码void ImageHandle::opencv_face(QImage qImage){ QTime time; time.start(); //(1)包含必要的头文件和命名空间: //(2)加载人脸检测模型 std::string cnn_file_path= OpenCV_CNN_MODEL_FILE_PATH; //CNN模型文件路径 std::string prototxt_path = cnn_file_path+"/deploy.prototxt.txt"; std::string model_path = cnn_file_path+"/res10_300x300_ssd_iter_140000_fp16.caffemodel"; cv::dnn::Net model = cv::dnn::readNetFromCaffe(prototxt_path, model_path); //(3)加载图片: //Mat frame = imread("D:\\1.png"); // 替换为你的图片路径 Mat frame = QImage_to_cvMat(qImage); if (frame.empty()) { ss_log_text("待识别的图片加载失败...\n"); // 处理图片加载失败的情况 return; } int h = frame.rows; int w = frame.cols; cv::Mat blob = cv::dnn::blobFromImage(frame, 1.0, cv::Size(300, 300), cv::Scalar(104.0, 177.0, 123.0)); //(4)进行人脸检测: model.setInput(blob); cv::Mat output = model.forward(); cv::Mat detectionMat(output.size[2], output.size[3], CV_32F, output.ptr<float>()); //(5)给每个检测到的人脸绘制马赛克: int face_number=0; for (int i = 0; i < detectionMat.rows; ++i) { float confidence = detectionMat.at<float>(i, 2); if (confidence > 0.5) { //记录人脸数量 face_number++; int start_x = static_cast<int>(detectionMat.at<float>(i, 3) * w); int start_y = static_cast<int>(detectionMat.at<float>(i, 4) * h); int end_x = static_cast<int>(detectionMat.at<float>(i, 5) * w); int end_y = static_cast<int>(detectionMat.at<float>(i, 6) * h); // 马赛克处理 cv::Rect roi(start_x, start_y, end_x - start_x, end_y - start_y); cv::Mat face_roi = frame(roi); cv::resize(face_roi, face_roi, cv::Size(), 0.05, 0.05, cv::INTER_LINEAR); cv::resize(face_roi, frame(roi), roi.size(), 0, 0, cv::INTER_NEAREST); // 绘制边框和文字 cv::rectangle(frame, cv::Point(start_x, start_y), cv::Point(end_x, end_y), cv::Scalar(255, 0, 0), 2); std::ostringstream ss; ss << confidence * 100 << "%"; cv::putText(frame, ss.str(), cv::Point(start_x, start_y - 5), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(255, 0, 0), 2); } } //传递出人脸数量 emit ss_face_number(face_number); // 在图像上显示识别消耗的时间 std::ostringstream time_ss; time_ss << "Time: " << time.elapsed() << " ms"; cv::putText(frame, time_ss.str(), cv::Point(10, 30), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(255, 0, 0), 2); //转为QImage QImage out_image=Mat_to_QImage(frame); ss_log_text(tr("耗时:%1 ms\n").arg(time.elapsed())); //qDebug()<<"子线程:"<<QThread::currentThread(); //保存结果 m_image=out_image.copy();}QImage convertToRGB888(const QImage& image){ if (image.format() == QImage::Format_RGB888) { return image; // Already in RGB888 format } QImage convertedImage = image.convertToFormat(QImage::Format_RGB888); return convertedImage;}//可以用。 OpenCV4.0已测试。//Mat ImageHandle::QImage_to_cvMat(QImage image){ cv::Mat mat; //qDebug() << image.format(); switch(image.format()) { case QImage::Format_ARGB32: case QImage::Format_RGB32: case QImage::Format_ARGB32_Premultiplied: mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine()); break; case QImage::Format_RGB888: mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine()); //opencv 3.x以及一下,颜色用 CV_BGR2RGB cv::cvtColor(mat, mat, COLOR_BGR2RGB); break; case QImage::Format_Indexed8: mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine()); break; } return mat;}QImage ImageHandle::Mat_to_QImage(Mat mat){#if 0 QImage image; // 检查矩阵是否有效 if (!mat.empty()) { // 创建QImage对象,并分配内存 image = QImage(mat.cols, mat.rows, QImage::Format_ARGB32); // 根据Mat的类型和通道数来设置Qt图像格式 switch (mat.type()) { case CV_8UC4: image = QImage(mat.data, mat.cols, mat.rows, static_cast<int>(mat.step), QImage::Format_ARGB32); break; case CV_8UC3: image = QImage(mat.data, mat.cols, mat.rows, static_cast<int>(mat.step), QImage::Format_RGB888); break; case CV_8UC1: image = QImage(mat.data, mat.cols, mat.rows, static_cast<int>(mat.step), QImage::Format_Indexed8); break; } // 对象回收 if (image.format() != QImage::Format_RGB32) { image = image.convertToFormat(QImage::Format_RGB32); } }#else // Check if the image is valid if (mat.empty()) return QImage(); // Convert the image color space cv::Mat rgbMat; cv::cvtColor(mat, rgbMat, cv::COLOR_BGR2RGB); // Create the QImage QImage image(rgbMat.data, rgbMat.cols, rgbMat.rows, static_cast<int>(rgbMat.step), QImage::Format_RGB888);#endif return image.copy();}六、总结本项目利用香橙派 AIpro开发了一个创新的健康监测解决方案,能够提升医院、疾病防控中心和发热门诊等关键场所的公共卫生管理水平。系统利用香橙派AIpro的强大计算能力,搭载Ubuntu 22.04操作系统,实现了高效的人脸识别与非接触式体温测量功能,显著增强了疾病早期预警和控制的能力。通过整体项目开发完成后,这块基于香橙派 AIpro的性能是完全满足了要求;运行了10几个小时, 整个板子不发烫,只是启动的时候风扇有明显噪声,正常进入系统之后,风扇的声音就正常,基本处于静音状态。 板子构造小巧,很容易集成,进行项目开发。
-
数据数据好像只能读取第一个,不能更新,预览后也没用
-
华为云大屏读取obs存储的csv文件为啥数值不动,好像只能读取第一行,请问有啥解决方法?
-
试了好久还是这样,真的不知道咋办了。
-
上三张为对应的属性上报,物理模型定义,下为用arduino的代码,#include <ESP8266WiFi.h>//添加ESP8266用于WiFi的头文件 #include <PubSubClient.h>//添加用于MQTT客户端的头文件 #include <DHTesp.h>//添加dht11头文件char TempHum[]={"{"hum":00}"};//声明1个数组,json格式,用于存放温湿度char num[]={"0123456789"};//声明1个字符数组const char *ssid = "";//wifi的名字const char *password = "";//wifi的密码#define BrokerAddress "" //定义阿里云MQTT服务地址 #define BrokerPort //定义MQTT服务端口 #define ClientID "" //定义MQTT Client ID #define UserName "" //定义MQTT User Name #define Password "" //定义MQTT Password#define SubscribeTopic "$oc/devices//sys/messages/up" //定义订阅的Topic $oc/devices/{device_id}/sys/properties/report #define PublishTopic "$oc/devices//sys/properties/report" //定义发布的Topic $oc/devices//sys/messages/upDHTesp dht; /******************************************************/ void MqttCallback(char* topic, byte* payload, unsigned int length); WiFiClient EspClient; PubSubClient client(BrokerAddress, BrokerPort, &MqttCallback, EspClient);void SetupWifi() { delay(10); Serial.print("Connecting to "); Serial.println(ssid);WiFi.mode(WIFI_STA); WiFi.begin(ssid, password);while(WiFi.status()!=WL_CONNECTED){ delay(500); Serial.print("."); }Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); }void MqttCallback(char* topic, byte* payload, unsigned int length) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); for (int i = 0; i < length; i++) { Serial.print((char)payload[i]); } Serial.println(); }void setup() { Serial.begin(115200);//设置串口 SetupWifi();//设置wifi client.setServer(BrokerAddress,1883);//设置MQTT服务地址和端口 client.setCallback(MqttCallback);//回调函数 client.setClient(EspClient); client.connect(ClientID,UserName,Password);//设备接入物联网云平台 if(!client.connected())//判断是否接入成功 Serial.print("Connected Failed!\n"); else{ Serial.print("Connected Ok!\n"); client.subscribe(SubscribeTopic);//订阅Topic } dht.setup(2, DHTesp::DHT11); }void loop() { client.loop();//关键,可以侦测回调函数中数据是否到来 int h = dht.getHumidity();//读取湿度 int t = dht.getTemperature();//读取温度TempHum[7]=num[h/10];//存放湿度 TempHum[8]=num[h%10];TempHum[17]=num[t/10];//存放温度 TempHum[18]=num[t%10]; client.publish(PublishTopic,TempHum);//每隔一定时间向平台发送1次温湿度数据 delay(10000); }该如何实现属性显示
-
现在硬件能上报属性,转发规则如下,然后我在android studio上写了一个用iam账户获取token 的代码,然后怎么使用这个token请求调用api查询设备影子数据的代码一直不对,请问各路大神这要怎么操作
-
应用使用AMQPS接收消息,为什么好多信息都接收不全,还有AMQP消息队列详情中订阅列表什么意思,我只用一个应用侧,为啥这么多客户端IDimport threadingimport timeimport signalimport sysimport socketimport jsonfrom proton import SSLDomainfrom proton.handlers import MessagingHandlerfrom proton.reactor import Container# 重连次数reconnectTimes = 0# 用于控制主线程的事件循环running = True# TCP/IP 服务器配置tcp_host = '10.16.47.108'tcp_port = 8080def current_time_millis():return str(int(round(time.time() * 1000)))class AmqpClient(MessagingHandler):def __init__(self, host, port, accessKey, accessCode, queueName, instanceId):super(AmqpClient, self).__init__()self.host = hostself.port = portself.accessKey = accessKeyself.accessCode = accessCodeself.queueName = queueNameself.instanceId = instanceIddef on_start(self, event):# 接入域名,请参见AMQP客户端接入说明文档。url = "amqps://%s:%s" % (self.host, self.port)timestamp = current_time_millis()userName = "accessKey=" + self.accessKey + "|timestamp=" + timestamp + "|instanceId=" + self.instanceIdpassWord = self.accessCode# 默认不校验服务端证书sslDomain = SSLDomain(SSLDomain.MODE_CLIENT)sslDomain.set_peer_authentication(SSLDomain.ANONYMOUS_PEER)self.conn = event.container.connect(url, user=userName, password=passWord, heartbeat=60, ssl_domain=sslDomain,reconnect=False)event.container.create_receiver(self.conn, source=self.queueName)def on_connection_opened(self, event):global reconnectTimesreconnectTimes = 0print("Connection established, remoteUrl: %s" % event.connection.hostname)def on_connection_closed(self, event):print("Connection closed: %s" % self)ReconnectThread("reconnectThread").start()def on_connection_error(self, event):print("Connection error: %s" % self)ReconnectThread("reconnectThread").start()def on_transport_error(self, event):if event.transport.condition:if event.transport.condition.info:print("%s: %s: %s" % (event.transport.condition.name, event.transport.condition.description,event.transport.condition.info))else:print("%s: %s" % (event.transport.condition.name, event.transport.condition.description))else:print("Unspecified transport error")ReconnectThread("reconnectThread").start()def on_message(self, event):message = event.messagecontent = message.bodyprint("Received message: content=%s" % content)# 解析消息内容try:data = json.loads(content)services = data.get('notify_data', {}).get('body', {}).get('services', [])for service in services:if service['service_id'] == 'GoodType':good_name = service['properties'].get('GoodName')good_id = service['properties'].get('GoodId')if good_name and good_id:send_tcp_message(good_name, good_id)except json.JSONDecodeError:print("Failed to decode JSON from message content")def send_tcp_message(good_name, good_id):message = {"ReportType": "Send","ReportCategory": "Good","GoodName": good_name,"GoodId": good_id}message_json = json.dumps(message)print(f"Prepared JSON message to send: {message_json}")try:with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:s.connect((tcp_host, tcp_port))s.sendall(message_json.encode('utf-8'))print(f"Sent TCP JSON message: {message_json}")except Exception as e:print(f"Failed to send TCP JSON message: {e}")class ReconnectThread(threading.Thread):def __init__(self, name):threading.Thread.__init__(self)self.name = namedef run(self):global reconnectTimesreconnectTimes += 1time.sleep(15 if reconnectTimes > 15 else reconnectTimes)Container(AmqpClient(amqpHost, amqpPort, amqpAccessKey, amqpAccessCode, amqpQueueName, instanceId)).run()def signal_handler(sig, frame):global runningprint('Exiting...')running = Falsesys.exit(0)# 以下参数配置请参考连接配置说明# AMQP接入域名amqpHost = "95e74068ba.st1.iotda-app.cn-north-4.myhuaweicloud.com"# AMQP接入端口amqpPort = 5671# 接入凭证键值amqpAccessKey = 'ZyjyH9Ax'# 接入凭证密钥amqpAccessCode = 'ghc4ScCaA7vqzgIZqErEezDsvPO5FCaC'# 订阅队列名称amqpQueueName = '12345678'# 实例Id,同一Region购买多个标准版实例时需要填设置该参数。instanceId = '5b6a80f0-75d5-4091-b28a-7809838c524c'# 捕捉SIGINT信号(通常是CTRL+C)signal.signal(signal.SIGINT, signal_handler)# 创建并运行容器container = Container(AmqpClient(amqpHost, amqpPort, amqpAccessKey, amqpAccessCode, amqpQueueName, instanceId))# 启动一个线程来运行AMQP客户端thread = threading.Thread(target=container.run)thread.start()# 保持主线程存活,等待接收消息while running:time.sleep(1)
-
有没有WiFi模组AT命令用MQTT上华为云的AT指令文档,小熊派带的WIFI模块能使用MQTT上华为云吗,一般是使用什么方式上云的
-
新手学习,根据huaweicloud-sdk-nodejs-v3/README_CN.md at master · huaweicloud/huaweicloud-sdk-nodejs-v3 · GitHub 里提供的文档,出现如上问题,求解,
-
之前创建好设备后模拟MQTT客户端登陆能够正确登陆上,显示在线状态,现在不行了,查了异常运行日志显示这个问题已经尝试过换成域名解析IP还是失败
-
应用侧接收MQTT数据流传的信息,有没有例程,我根据教程,时好时坏
-
数据转发,应用侧接收老失败,有时候可以ClientConf.py:from typing import Optionalclass ClientConf:def __init__(self):# mqtt订阅地址self.__host: Optional[str] = "95e74068ba.st1.iotda-app.cn-north-4.myhuaweicloud.com"# mqtt订阅端口号self.__port: Optional[int] = 8883# mqtt接入凭据access_keyself.__access_key: Optional[str] = "glWckaFu"# mqtt接入凭据access_codeself.__access_code: Optional[str] = "x83VLjH7MAPikrIR36916sAStLoPXEK7"# mqtt订阅topicself.__topic: Optional[str] = "topic456"# 实例Id,同一Region购买多个标准版实例时需要填写该参数self.__instance_id: Optional[str] = "5b6a80f0-75d5-4091-b28a-7809838c524c"# mqtt qosself.__qos = 1# tcp 服务器 IPself.__tcp_ip: Optional[str] = "10.16.64.116"# tcp 服务器端口self.__tcp_port: Optional[int] = 11111@propertydef host(self):return self.__host@host.setterdef host(self, host):self.__host = host@propertydef port(self):return self.__port@port.setterdef port(self, port):self.__port = port@propertydef access_key(self):return self.__access_key@access_key.setterdef access_key(self, access_key):self.__access_key = access_key@propertydef access_code(self):return self.__access_code@access_code.setterdef access_code(self, access_code):self.__access_code = access_code@propertydef topic(self):return self.__topic@topic.setterdef topic(self, topic):self.__topic = topic@propertydef instance_id(self):return self.__instance_id@instance_id.setterdef instance_id(self, instance_id):self.__instance_id = instance_id@propertydef qos(self):return self.__qos@qos.setterdef qos(self, qos):self.__qos = qos@propertydef tcp_ip(self):return self.__tcp_ip@tcp_ip.setterdef tcp_ip(self, tcp_ip):self.__tcp_ip = tcp_ip@propertydef tcp_port(self):return self.__tcp_port@tcp_port.setterdef tcp_port(self, tcp_port):self.__tcp_port = tcp_portMqttClient.py:import osimport sslimport threadingimport timeimport tracebackimport secretsimport socketfrom typing import Optionalfrom ClientConf import ClientConfimport paho.mqtt.client as mqttimport jsonclass MqttClient:def __init__(self, client_conf: ClientConf):print("__init__ 66666")self.__host = client_conf.hostself.__port = client_conf.portself.__access_key = client_conf.access_keyself.__access_code = client_conf.access_codeself.__topic = client_conf.topicself.__instance_id = client_conf.instance_idself.__qos = client_conf.qosself.__tcp_ip = client_conf.tcp_ipself.__tcp_port = client_conf.tcp_portself.__paho_client: Optional[mqtt.Client] = Noneself.__connect_result_code = -1self.__default_backoff = 1000self.__retry_times = 0self.__min_backoff = 1 * 1000 # 1sself.__max_backoff = 30 * 1000 # 30sdef connect(self):print("connect 66666")self.__valid_params()rc = self.__connect()while rc != 0:# 退避重连low_bound = int(self.__default_backoff * 0.8)high_bound = int(self.__default_backoff * 1.0)random_backoff = secrets.randbelow(high_bound - low_bound)backoff_with_jitter = int(pow(2, self.__retry_times)) * (random_backoff + low_bound)wait_time_ms = self.__max_backoff if (self.__min_backoff + backoff_with_jitter) > self.__max_backoff else (self.__min_backoff + backoff_with_jitter)wait_time_s = round(wait_time_ms / 1000, 2)print("client will try to reconnect after " + str(wait_time_s) + " s")time.sleep(wait_time_s)self.__retry_times += 1self.close() # 释放之前的connectionrc = self.__connect()# rc为0表示建链成功,其它表示连接不成功if rc != 0:print("connect with result code: " + str(rc))if rc == 134:print("connect failed with bad username or password, ""reconnection will not be performed")passreturn rcdef __connect(self):try:print("__connect 66666")timestamp = self.current_time_millis()user_name = "accessKey=" + self.__access_key + "|timestamp=" + timestampif self.__instance_id:user_name = user_name + "|instanceId=" + self.__instance_idpass_word = self.__access_codeself.__paho_client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, "mqttClient")# 关闭自动重试, 采用手动重试的方式刷新时间戳self.__paho_client._reconnect_on_failure = False# 设置回调函数self._set_callback()# topic放在userdata中,回调函数直接拿topic订阅self.__paho_client.user_data_set(self.__topic)self.__paho_client.username_pw_set(user_name, pass_word)# 当前mqtt broker仅支持TLS1.2context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)# 不校验服务端证书context.verify_mode = ssl.CERT_NONEcontext.check_hostname = Falseself.__paho_client.tls_set_context(context)rc = self.__paho_client.connect(self.__host, self.__port)self.__connect_result_code = rcif rc == 0:threading.Thread(target=self.__paho_client.loop_forever, args=(1, False), name="MqttThread").start()# 等待建链time.sleep(1)except Exception as e:self.__connect_result_code = -1print("Mqtt connection error. traceback: " + traceback.format_exc())if self.__paho_client.is_connected():return 0else:return self.__connect_result_codedef __valid_params(self):print("__valid_params 66666")assert self.__access_key is not Noneassert self.__access_code is not Noneassert self.__topic is not None@staticmethoddef current_time_millis():return str(int(round(time.time() * 1000)))def _set_callback(self):print("_set_callback 6666 ")# 当平台响应连接请求时,执行self._on_connect()self.__paho_client.on_connect = self._on_connectprint("_on_disconnect ")# 当与平台断开连接时,执行self._on_disconnect()self.__paho_client.on_disconnect = self._on_disconnectprint("_on_subscribe ")# 当订阅topic时,执行self._on_subscribeself.__paho_client.on_subscribe = self._on_subscribe# 当接收到一个原始消息时,执行self._on_message()print("_on_message ")self.__paho_client.on_message = self._on_messagedef _on_connect(self, client, userdata, flags, rc: mqtt.ReasonCode, properties):print("_on_connect 66666 ")if rc == 0:print("Connected to Mqtt Broker! topic " + self.__topic)client.subscribe(userdata, 1)else:# 只有当用户名或密码错误,才不进行自动重连。# 如果这里不使用disconnect()方法,那么loop_forever会一直进行重连。if rc == 134:self.__paho_client.disconnect()print("Failed to connect. return code :" + str(rc.value) + ", reason" + rc.getName())def _on_subscribe(self, client, userdata, mid, granted_qos, properties):print("_on_subscribe 66666 ")print("Subscribed: " + str(mid) + " " + str(granted_qos) + " topic: " + self.__topic)def _on_message(self, client, userdata, message: mqtt.MQTTMessage):print("_on_message 66666666666")print("topic " + self.__topic + " Received message: " + message.payload.decode())# 通过TCP发送消息try:with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:s.connect((self.__tcp_ip, self.__tcp_port))s.sendall(message.payload)print("Message sent over TCP")except Exception as e:print("TCP send error. traceback: " + traceback.format_exc())# def _on_message(self, client, userdata, message: mqtt.MQTTMessage):# print("_on_message 66666666666")# print("topic " + self.__topic + " Received message: " + message.payload.decode())## try:# # 解析收到的 JSON 消息# received_msg = json.loads(message.payload.decode())## # 提取需要的部分# extracted_data = received_msg["notify_data"]["body"]## # 添加上报类型和类型# extracted_data["report_type"] = "Send"# extracted_data["type"] = "货物"## # 将提取和修改后的数据转换回 JSON# extracted_data_str = json.dumps(extracted_data)## # 打印发送的信息# print("Message to be sent over TCP: " + extracted_data_str)## # 通过 TCP 发送消息# with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:# s.connect((self.__tcp_ip, self.__tcp_port))# s.sendall(extracted_data_str.encode())# print("Message sent over TCP")# except Exception as e:# print("TCP send error. traceback: " + traceback.format_exc())def _on_disconnect(self, client, userdata, flags, rc, properties):print("Disconnect to Mqtt Broker. topic: " + self.__topic)# 断链后将客户端主动关闭,手动重连刷新时间戳try:self.__paho_client.disconnect()except Exception as e:print("Mqtt connection error. traceback: " + traceback.format_exc())self.connect()def close(self):print("close 66666 ")if self.__paho_client is not None and self.__paho_client.is_connected():try:self.__paho_client.disconnect()print("Mqtt connection close")except Exception as e:print("paho client disconnect failed. exception: " + str(e))else:passMqttDemo.py:import osfrom ClientConf import ClientConffrom MqttClient import MqttClientimport osfrom typing import Optionalfrom huaweicloudsdkcore.auth.credentials import BasicCredentials, DerivedCredentialsfrom huaweicloudsdkcore.region.region import Region as coreRegionfrom huaweicloudsdkcore.exceptions import exceptionsfrom huaweicloudsdkiotda.v5 import *def main():client_conf = ClientConf()client_conf.host = "95e74068ba.st1.iotda-app.cn-north-4.myhuaweicloud.com"client_conf.port = 8883client_conf.topic = "topic456"# mqtt接入凭据access_key可使用环境变量的方式注入client_conf.access_key = "glWckaFu"# mqtt接入凭据a ccess_code可使用环境变量的方式注入client_conf.access_code = "x83VLjH7MAPikrIR36916sAStLoPXEK7"client_conf.instance_id = "5b6a80f0-75d5-4091-b28a-7809838c524c"mqtt_client = MqttClient(client_conf)if mqtt_client.connect() != 0:print("init failed")return# 调用华为IoTDA服务接口if __name__ == "__main__":main()
-
使用pythonSDK示例失败# coding: utf-8import osfrom huaweicloudsdkcore.auth.credentials import BasicCredentialsfrom huaweicloudsdkcore.auth.credentials import DerivedCredentialsfrom huaweicloudsdkcore.region.region import Region as coreRegionfrom huaweicloudsdkcore.exceptions import exceptionsfrom huaweicloudsdkiotda.v5 import *if __name__ == "__main__":# The AK and SK used for authentication are hard-coded or stored in plaintext, which has great security risks. It is recommended that the AK and SK be stored in ciphertext in configuration files or environment variables and decrypted during use to ensure security.# In this example, AK and SK are stored in environment variables for authentication. Before running this example, set environment variables CLOUD_SDK_AK and CLOUD_SDK_SK in the local environmentak = "jfdjkjCjk8C84"sk = "ljkjQjkfdjhvgdfffjWVzJDUB"endpoint = "85e44068ba.st1.iotda-app.cn-north-4.myhuaweicloud.com"credentials = BasicCredentials(ak, sk).with_derived_predicate(DerivedCredentials.get_default_derived_predicate())client = IoTDAClient.new_builder() \.with_credentials(credentials) \.with_region(coreRegion(id="cn-north-4", endpoint=endpoint)) \.build()try:request = UpdatePropertiesRequest()request.body = DevicePropertiesRequest(services="[{\"service_id\":\"Temperature\",\"properties\":{\"value\":57}}, {\"service_id\":\"Battery\",\"properties\":{\"level\":80}}]")response = client.update_properties(request)print(response)except exceptions.ClientRequestException as e:print(e.status_code)print(e.request_id)print(e.error_code)print(e.error_msg)
-
想问一下,这个调用修改设备属性dAPI超时的问题该怎么解决
上滑加载中
推荐直播
-
DTT年度收官盛典:华为开发者空间大咖汇,共探云端开发创新
2025/01/08 周三 16:30-18:00
Yawei 华为云开发工具和效率首席专家 Edwin 华为开发者空间产品总监
数字化转型进程持续加速,驱动着技术革新发展,华为开发者空间如何巧妙整合鸿蒙、昇腾、鲲鹏等核心资源,打破平台间的壁垒,实现跨平台协同?在科技迅猛发展的今天,开发者们如何迅速把握机遇,实现高效、创新的技术突破?DTT 年度收官盛典,将与大家共同探索华为开发者空间的创新奥秘。
去报名 -
GaussDB应用实战:手把手带你写SQL
2025/01/09 周四 16:00-18:00
Steven 华为云学堂技术讲师
本期直播将围绕数据库中常用的数据类型、数据库对象、系统函数及操作符等内容展开介绍,帮助初学者掌握SQL入门级的基础语法。同时在线手把手教你写好SQL。
去报名
热门标签