- 2024-11-05
-
发表了主题帖:
【DigiKey“智造万物,快乐不停”创意大赛】作品总结和提交
本帖最后由 小默叔叔 于 2024-11-5 11:57 编辑
## 一、简介
介绍
ESP32通过TSC3200识别红色、绿色和蓝色,并通过MQTT将数据传输给树莓派,树莓派此时是一个MQTT服务器,接收到MQTT数据后,通过QT界面,在树莓派上显示识别到的颜色;同时ESP32上也有个RGB灯,RGB灯的颜色与识别的颜色相同
这次申请了三块开发板套件,分别是“ESP32-C6-DEVKITC-1-N8”、“TCS3200 RGB COLOR SENSOR BOARD”和“Raspberry Pi5”。
树莓派5 主要介绍
- 2.4GHz 四核 64 位 Arm Cortex-A76 CPU,512KB 二级缓存和 2MB 共享三级缓存
- VideoCore VII GPU @800MHz,支持 OpenGL ES 3.1 和 Vulkan 1.2
- 双 4Kp60 HDMI 显示输出
- 4Kp60 HEVC 解码器
- LPDDR4X-4267 SDRAM (2GB/4GB/8GB 内存可选)
- 2.4GHz/5GHz 双频 802.11ac Wi-Fi
- 蓝牙 5.0 / 低功耗蓝牙 (BLE)
- 高速 Micro SD 卡接口,支持 SDR104 模式
- 2 × USB 3.0 端口,支持 5Gbps 同步运行
- 千兆以太网,支持 PoE+ (需要单独的 PoE+ HAT,即将推出)
- 2 × 4-lane MIPI DSI/CSI 接口
- 用于高速外设的 PCIe 2.0 x1 接口 (需要单独的 M.2 HAT 或其他适配器)
- 通过 USB-C 提供 5V/5A 直流电源,支持 PD
- Raspberry Pi 40PIN GPIO 接口
- 实时时钟 (RTC),由外置电池供电 (需单独购买)
- 板载电源按钮,可以在不断开电源的情况下关机/开机
## 二、系统框图
计划是ESP32通过TCS3200识别不同的颜色,然后控制RGB显示当前识别的颜色,然后通过mqtt发送给树莓派,树莓派这边作为MQTT服务器,接收和显示当前ESP32识别到的颜色。
## 三、各部分功能说明
各部分实现的功能说明及讲解,以图文结合的方式展示
1. ESP32 & TSC3200
1. 识别颜色
```c
void setup() {
pinMode(S0, OUTPUT);
pinMode(S1, OUTPUT);
pinMode(S2, OUTPUT);
pinMode(S3, OUTPUT);
pinMode(sensorOut, INPUT);
digitalWrite(S0,HIGH);
digitalWrite(S1,LOW);
}
int getRed() {
digitalWrite(S2,LOW);
digitalWrite(S3,LOW);
Frequency = pulseIn(sensorOut, LOW); /*Get the Red Color Frequency*/
return Frequency;
}
int getGreen() {
digitalWrite(S2,HIGH);
digitalWrite(S3,HIGH);
Frequency = pulseIn(sensorOut, LOW); /*Get the Green Color Frequency*/
return Frequency;
}
int getBlue() {
digitalWrite(S2,LOW);
digitalWrite(S3,HIGH);
Frequency = pulseIn(sensorOut, LOW); /*Get the Blue Color Frequency*/
return Frequency;
}
```
2. 与MQTT通讯
```c
// 新增MQTT重连函数
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
String clientId = "ESP32ColorSensor-";
clientId += String(random(0xffff), HEX);
if (client.connect(clientId.c_str())) {
Serial.println("connected");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void setup() {
// 新增WiFi和MQTT初始化
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
}
```
2. 树莓派
1. 开启MQTT服务器
sudo apt-get install python3-paho-mqtt
sudo apt-get install mosquitto mosquitto-clients
sudo vim /etc/mosquitto/mosquitto.conf
sudo systemctl restart mosquitto
2. QT显示识别到的颜色
```c
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QVBoxLayout, QWidget
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont
import paho.mqtt.client as mqtt
class ColorDisplay(QMainWindow):
def __init__(self):
super().__init__()
print("初始化程序...")
self.initUI()
self.initMQTT()
print("初始化完成")
def initUI(self):
self.setWindowTitle('Color Detection Display')
self.setGeometry(100, 100, 400, 200)
central_widget = QWidget()
self.setCentralWidget(central_widget)
layout = QVBoxLayout(central_widget)
self.color_label = QLabel('等待颜色数据...')
self.color_label.setFont(QFont('Arial', 24))
self.color_label.setStyleSheet('padding: 20px;')
self.color_label.setAlignment(Qt.AlignCenter)
layout.addWidget(self.color_label)
self.status_label = QLabel('MQTT 状态: 未连接')
self.status_label.setFont(QFont('Arial', 12))
self.status_label.setStyleSheet('padding: 10px;')
layout.addWidget(self.status_label)
def initMQTT(self):
print("初始化MQTT客户端...")
self.mqtt_client = mqtt.Client()
self.mqtt_client.on_connect = self.on_connect
self.mqtt_client.on_message = self.on_message
self.mqtt_client.on_disconnect = self.on_disconnect
try:
print("连接到MQTT服务器...")
self.mqtt_client.connect("localhost", 1883, 60)
self.mqtt_client.loop_start()
except Exception as e:
print(f"MQTT连接错误: {str(e)}")
self.status_label.setText(f'MQTT 连接错误: {str(e)}')
self.status_label.setStyleSheet('color: red; padding: 10px;')
def on_connect(self, client, userdata, flags, rc):
if rc == 0:
self.status_label.setText('MQTT 状态: 已连接')
self.status_label.setStyleSheet('color: green; padding: 10px;')
client.subscribe("color/detection")
print("已成功连接到MQTT服务器并订阅主题")
else:
self.status_label.setText(f'MQTT 连接失败,错误码: {rc}')
self.status_label.setStyleSheet('color: red; padding: 10px;')
print(f"MQTT连接失败,错误码: {rc}")
def on_disconnect(self, client, userdata, rc):
self.status_label.setText('MQTT 状态: 已断开连接')
self.status_label.setStyleSheet('color: red; padding: 10px;')
print("MQTT连接已断开")
def on_message(self, client, userdata, msg):
try:
color = msg.payload.decode()
display_message = f'检测到颜色: {color}'
print(f"收到颜色信息: {color}")
self.color_label.setText(display_message)
style = 'padding: 20px; border-radius: 10px; margin: 10px;'
if color == 'red':
# 纯正的红色背景
self.color_label.setStyleSheet(f'background-color: #FF0000; color: white; {style}')
elif color == 'green':
# 纯正的绿色背景
self.color_label.setStyleSheet(f'background-color: #00FF00; color: black; {style}')
elif color == 'blue':
# 纯正的蓝色背景
self.color_label.setStyleSheet(f'background-color: #0000FF; color: white; {style}')
else:
self.color_label.setStyleSheet(f'background-color: #f0f0f0; color: black; {style}')
except Exception as e:
print(f"处理消息时出错: {str(e)}")
def closeEvent(self, event):
print("正在关闭程序...")
if hasattr(self, 'mqtt_client'):
self.mqtt_client.loop_stop()
self.mqtt_client.disconnect()
event.accept()
print("程序已关闭")
if __name__ == '__main__':
print("\n=== 程序启动 ===")
app = QApplication(sys.argv)
ex = ColorDisplay()
ex.show()
print("=== GUI已启动,等待消息 ===\n")
sys.exit(app.exec_())
```
## 四、作品源码
## 五、作品功能演示视频
[localvideo]82bde498af037349746e6a3746232660[/localvideo]
视频嵌入
## 六、项目总结
本项目成功实现了一个完整的颜色识别与远程显示系统,展示了物联网技术在实际应用中的潜力。通过ESP32和树莓派的协同工作,实现了从数据采集到远程显示的完整流程,为类似应用提供了可靠的参考方案。
应用价值
- 可用于工业自动化的颜色检测
- 适用于智能家居的环境感知
- 教育领域的STEM教学演示
- 物联网应用开发的参考案例
- 2024-10-02
-
回复了主题帖:
【2024 DigiKey创意大赛】 物料开箱
phonone 发表于 2024-9-24 17:32
树莓派是用来玩的?
试着跑个模型,或者接入模型
-
回复了主题帖:
【2024 DigiKey创意大赛】 物料开箱
wangerxian 发表于 2024-9-23 09:09
ESP32和树莓派准备用什么方式进行通信?
用串口吧,最简单了;走网络也可以
-
回复了主题帖:
【2024 DigiKey创意大赛】 物料开箱
lansebuluo 发表于 2024-9-23 08:31
4GB 树莓派,这个是否还要加散热片,防止过热
不用啊,Pi 5上面自带散热片
- 2024-09-22
-
发表了主题帖:
【2024 DigiKey创意大赛】 物料开箱
本帖最后由 小默叔叔 于 2024-9-22 16:03 编辑
这次申请了三块开发板套件,分别是“ESP32-C6-DEVKITC-1-N8”、“TCS3200 RGB COLOR SENSOR BOARD”和“Raspberry Pi5”。
计划是ESP32控制RGB,然后树莓派5与这个通讯,还可以用上位机控制,上图,coding
- 2024-03-29
-
回复了主题帖:
测评入围名单: 米尔-瑞米派Remi Pi(兼容树莓派扩展模块)
个人信息无误,确认可以完成评测计划
- 2024-03-13
-
回复了主题帖:
颁奖礼:平头哥玄铁杯第三届获奖名单揭晓,纪念一起对AI进行小小探索的你们
确认无误,请兑换成等值E金币,谢谢
- 2023-12-16
-
加入了学习《得捷电子Follow me第3期【ESP32-C3 XIAO】总结(驱动Round Display for XIAO)》,观看 得捷电子Follow me第3期【ESP32-C3 XIAO】总结(驱动Round Display for XIAO)
-
上传了资料:
得捷电子Follow me第3期【ESP32-C3 XIAO】总结(驱动Round Display for XIAO)
-
发表了主题帖:
得捷电子Follow me第3期【ESP32-C3 XIAO】总结(驱动Round Display for XIAO)
# 得捷电子Follow me第3期【ESP32-C3 XIAO】物料开箱+总结(驱动Seeed Studio Round Display for XIAO)
## 发现原来我还没有发开箱贴,但我已经写了,所以和总结一起发了
## 一、物料开箱
开箱开箱,再三考虑,还是选择了“SEEED STUDIO XIAO ROUND DISPLAY”和“SEEED STUDIO XIAO ESP32C3 WIFI+B”这个组合,因为这个“SEEED STUDIO XIAO ROUND DISPLAY”是一个圆形的LCD屏幕,可以用来做一些表盘设计和移植一些有趣的GUI界面
1. 上图
2. 计划这次开发,会分成两部分
1. 第一部分完成主线任务(任务1-5),使用Micropython开发。
2. 第二部分“综合实践”会像二期那样,选在PlatformIO+Arduino+Clion的方式开发,尝试驱动驱动Seeed Studio Round Display for XIAO
3. 任务1:使用MicroPython系统
4. 任务2:驱动扩展版上的OLED屏幕
5. 任务3:控制蜂鸣器播放小星星
6. 任务4:连接WiFi网络
7. 任务5:连接环温湿度传感器,获取传感器的数值
## 二、项目描述及各项目说明(含心得体会)
在这次的活动中,我获得了丰富的知识和经验,深入了解了ESP32-C3的应用,并且学习了许多实用的嵌入式开发技巧。我衷心感谢EEWORLD和得捷电子为我提供了这次极具价值的学习机会,使我有幸接触到ESP32-C3,并在此过程中吸收了许多既有趣又实用的知识点。
通过参加这个活动,我成功地操作了ESP32-C3 XIAO开发板,并在Thonny IDE环境下完成了固件的下载与运行。这个经历为我步入嵌入式编程世界打开了大门,加深了我对硬件与软件结合的理解。此外,我还学习了micropython的基础语法,这是一种为嵌入式系统设计的简化Python版本。我掌握了在ESP32-C3上运行micropython代码的技巧,这对我未来的嵌入式开发项目大有裨益。
我还探索了如何驱动各类外设,包括温湿度传感器、OLED显示屏和蜂鸣器。通过编写简单的代码,我成功实现了LED灯的闪烁和蜂鸣器的声音控制。同时,我也学会了如何使用封装好的库来驱动OLED显示屏,使我能够在ESP32-C3上展示和交互各种信息。
此外,我还学习了如何使用网络模块来同步系统时间,这是我在此次活动中的另一个重要收获。我掌握了连接WiFi网络和获取实时时间的方法,这对于需要时间同步的项目来说非常有用。
总结来说,这次ESP32-C3的学习活动对我来说意义非凡。我不仅学会了嵌入式开发的基本技能,还学习了如何在ESP32-C3上操作各种外设和实现网络通信。这为我个人技能的提升和未来职业生涯的发展奠定了坚实的基础。我再次对EEWORLD和得捷电子提供的这次宝贵学习机会表示感谢!
**任务1:使用MicroPython系统**
这次Raspberry Pi Pico w的开发环境是基于Thonny。Thonny 是一个适合初学者的 Python IDE,由爱沙尼亚的 [Tartu 大学](https://link.zhihu.com/?target=https%3A//www.ut.ee/en) 开发,它采用了不同的方法,因为它的调试器是专为学习和教学编程而设计的。它可以用于开发RP2040和ESP32等芯片。
下载地址为:[https://thonny.org/](https://thonny.org/)
Thonny使用说明
1. 配置解释器:运行→配置解释器
2. Thonny窗口的注释和基本用法
3. MicroPython的语法MicroPython使用了类似于Python的语法,但没有其更大的同类中所具有的额外特性的优势。例如,MicroPython无法访问 Python 可用的大量库。但MicroPython 旨在运行在资源有限的硬件上,配备了一组核心库,提供一些基本功能,例如网络、文件 I/O 和有限的数据类型。总结一句话就是:与Python语法基本相同,调用库的话,最好调用MicroPython的。
**任务2:驱动扩展板上的OLED屏幕**
1. 硬件连接
我这里使用的是得捷一期时候购买的树莓派的配件,转接板也使用的树莓派的底板,然后再通过面包板转接供电给底板来使用。我这里使用了他的I2C和OLED相连。
底板原理图
ESP32-C3 引脚图
**任务3:控制蜂鸣器播放音乐**
这里使用18引脚驱动蜂鸣器,使用的是ESP32-C3的 GPIO2来驱动的,还实现了播放”小星星“
**任务4:连接WiFi网络**
WiFi这里我使用了network库,同事在连接上热点并打印出信号强度后,我去连接得捷官网,并打印显示,同时热点的账号密码我写在了当前python文件中
**任务5:使用外部传感器**
这里我本来想用传感器检测距离,但看到要求要使用温湿度传感器这些来测试,所以我就找到以前的一块开发板的配件,它上面有个DHT11,我就基于这个来写了。这里我用的是ESP-C3的GPIO3来获取当前的温湿度。
这里要添加DHT的库
**任务6:驱动Seeed Studio Round Display for XIAO**
**介绍**
Seeed Studio Round Display for XIAO 是一款与所有 XIAO 开发板兼容的扩展板。它的一侧有一个完全覆盖的触摸屏,设计为 39 毫米圆盘。它在紧凑的尺寸内包含板载 RTC、充电芯片、TF 卡插槽,非常适合智能家居、可穿戴设备等中的交互式显示。
**硬件概述**
**代码**
1. 需要下载TFT_eSPI,这个不要官方的库,需要下载专门适配过的库,地址为:[https://github.com/Maxwelltoo/TFT_eSPI](https://github.com/Maxwelltoo/TFT_eSPI)
2. 还需要下载依赖lvgl、Adafruit_busIO、Adafruit_GFX_Library、I2C+BM8563_RTC
3. 修改User_Setup_Select.h
4. platformio.ini 的配置
5. 画表圈
6. 展示
## 代码仓库
https://download.eeworld.com.cn/detail/%E5%B0%8F%E9%BB%98%E5%8F%94%E5%8F%94/630291
## 视频链接
https://training.eeworld.com.cn/video/38825
- 2023-12-06
-
发表了主题帖:
【玄铁杯第三届RISC-V应用创新大赛】Lichee PI 4A 之坐姿识别提醒装置
本帖最后由 小默叔叔 于 2023-12-10 13:05 编辑
# 【玄铁杯第三届RISC-V应用创新大赛】Lichee PI 4A 之坐姿识别提醒装置
往期文章:
【玄铁杯第三届RISC-V应用创新大赛】LicheePi 4A+开箱 https://bbs.eeworld.com.cn/thread-1257258-1-1.html
【玄铁杯第三届RISC-V应用创新大赛】Lichee PI 4A 之OpenCV与摄像头抓拍 https://bbs.eeworld.com.cn/thread-1265914-1-1.html
【玄铁杯第三届RISC-V应用创新大赛】Lichee PI 4A 之编译ncnn&测试simplepose demo https://bbs.eeworld.com.cn/thread-1265915-1-1.html
【玄铁杯第三届RISC-V应用创新大赛】Lichee PI 4A 之编译Ultralight-SimplePose https://bbs.eeworld.com.cn/thread-1265917-1-1.html
# 一.项目介绍
## 1. 背景介绍
每个嵌软点灯工程师,应该都会花长时间坐在工位上,长期以往,我的一个朋友腰也自然突出了。在休息的时候,就在想,也许是适合需要一个能**“识别自己坐姿”**是否正常并且可以**“久坐提醒”**的设备了。有了它,应该就可以提醒自己可以保持好坐姿和按时喝酒了,降低了颈椎、腰椎和结石的风险!o(* ̄▽ ̄*)ブ 多喝水,多喝水~
## 2. 项目介绍
简单来讲:就是通过UVC摄像头每3s获取一张图片,同时LicheePi 4A上跑坐姿估计的推理模型,并分析每张图片对关键点标注,计算关键点的位置,以此来判断是否坐姿标准(例如是否低头)。同时也配合上位机提示自己此时坐姿状态是否标准,还在上位机增加了番茄时钟、当前时间和星期日期等。目的只有一个,就是提高工作效率和优化自己坐姿,减少些“工作负担”!
选择上位机的原因是,我没买屏,其实如果直接在屏幕上开发界面,整体的感官要比配合上位机要好些。
## 3. 项目框架
项目框架很简单,分为硬件框图和软件框图,如下图所示:
硬件框图:
主要分为:摄像头、LicheePi 4A、个人PC
软件框图:
软件数据流的过程
## 4. 硬件介绍
- 摄像头
摄像头用的是之前一个活动测评项目赠送的普通USB摄像头,型号是海康的DS-E11 USB 摄像头,USB 2.0接口,720P高清输出,视频帧率:MJPG (640x480 @30/25 fps )和YUV(640x480 @30 fps )等
- LicheePi 4A
- LicheePi 4A 是基于 [Lichee Module 4A](http://wiki.sipeed.com/hardware/zh/lichee/th1520/lm4a.html) 核心板的 高性能 RISC-V Linux 开发板,以 [TH1520](https://www.t-head.cn/product/yeying) 为主控核心(4xC910@1.85G, RV64GCV,4TOPS@int8 NPU, 50GFLOP GPU),板载最大 16GB 64bit LPDDR4X,128GB eMMC,支持 HDMI+MIPI 双4K 显示输出,支持 4K 摄像头接入,双千兆网口(其中一个支持POE供电)和 4 个 USB3.0 接口,多种音频输入输出(由专用 C906 核心处理)。
LicheePi 4A 可以用作典型的 RISC-V 验证平台,其强大的性能可以较快速地实现本地编译,而无需使用 QEMU 进行编译。
- 硬件资源图
## 5. 软件介绍(项目用到的)
- **ncnn**
**ncnn** 是一个为移动端和嵌入式设备优化的高性能神经网络前向计算框架。它由腾讯公司的优图实验室开发,特别适用于在计算能力有限的设备上运行深度学习模型。ncnn易于部署,支持多种平台,包括Android、iOS以及各种Linux嵌入式平台。它的主要特点包括低内存占用、高效的运行速度以及对多种流行深度学习模型的支持。
- **Ultralight-SimplePose**
**Ultralight-SimplePose** 是一个轻量级的人体姿态估计库。它旨在提供一个高效且精确的方式来检测和分析人体姿态。这个库特别适合用于实时应用,如运动分析、交互设计等场景。Ultralight-SimplePose的主要优势在于其轻量级设计,使其能够在资源受限的设备上运行,同时保持较高的准确性和性能。
- **OpenCV (我使用了的是python3-opencv 控制摄像头抓拍照片)**
**OpenCV**(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库。它包含了众多的视觉处理和计算功能,广泛应用于图像识别、面部识别、对象检测、视频分析等领域。OpenCV支持多种编程语言,如C++、Python、Java,并可在不同的操作系统上运行,包括Windows、Linux和Mac OS。它的强大功能和广泛的应用使其成为计算机视觉领域的一个重要工具。
- **PyQt5(用于Windows的上位机开发)**
**PyQt5** 是一个用于创建图形用户界面(GUI)应用程序的工具集。它是Qt库的Python绑定版本,Qt是一个跨平台的C++应用程序框架。PyQt5允许开发者使用Python语言来创建具有丰富功能和优雅界面的桌面应用程序。它提供了大量的工具和组件,支持事件驱动编程,并且可以轻松地与其他Python库和工具集成。PyQt5广泛用于开发跨平台的桌面应用程序,特别受Python开发者的欢迎。
# 二、方案实现
## 1.姿势估计功能开发
- 这里可以看下往期写的文章,里面详细描述了姿势估计开发的细节和爬坑
【玄铁杯第三届RISC-V应用创新大赛】LicheePi 4A+开箱 https://bbs.eeworld.com.cn/thread-1257258-1-1.html
【玄铁杯第三届RISC-V应用创新大赛】Lichee PI 4A 之OpenCV与摄像头抓拍 https://bbs.eeworld.com.cn/thread-1265914-1-1.html
【玄铁杯第三届RISC-V应用创新大赛】Lichee PI 4A 之编译ncnn&测试simplepose demo https://bbs.eeworld.com.cn/thread-1265915-1-1.html
【玄铁杯第三届RISC-V应用创新大赛】Lichee PI 4A 之编译Ultralight-SimplePose https://bbs.eeworld.com.cn/thread-1265917-1-1.html
- 打开摄像头,并获取每帧图像,并3s保存一张照片,循环存储7张,命名为0-6.jpg
```python
import cv2
import time
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("The camera is not opened")
exit(1)
img_counter = 0
while True:
ret, frame = cap.read()
if not ret:
print("Failed to grab frame")
break
img_name = f"{img_counter % 7}.jpg" # 使用模运算保证图片名称在0-6之间
cv2.imwrite(img_name, frame)
print(f"{img_name} written!")
# 因为只是demo 暂时不考虑img_counter 范围
img_counter += 1
# 等待 3 秒
time.sleep(3)
cap.release()
```
- 编译ncnn,生成ncnn的include和lib
- 下载编译链和配置交叉编译环境
```bash
# 1.下载 Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.4.0 并解压
# 2.设置交叉编译链配置环境
sudo vim ~/.bashrc
# SET C910 ENV by xiebx 2023-11-29
export RISCV_ROOT_PATH=/home/Code/buildtools/Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.4.0
source ~/.bashrc
```
- 编译ncnn
```bash
## 编译licheepi4a(c910)的ncnn
mkdir -p build-c910
cd build-c910
cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/c910-v240.toolchain.cmake \
-DCMAKE_BUILD_TYPE=release -DNCNN_OPENMP=OFF -DNCNN_THREADS=OFF -DNCNN_RUNTIME_CPU=OFF -DNCNN_RVV=ON \
-DNCNN_SIMPLEOCV=ON -DNCNN_BUILD_EXAMPLES=ON ..
cmake --build . -j 4
cmake --build . --target install
```
- 编译Ultralight-SimplePose
- 下载Ultralight-SimplePose
```bash
git clone https://github.com/dog-qiuqiu/Ultralight-SimplePose.git
```
- 将ncnn的include和lib,拷贝到Ultralight-SimplePose的ncnn demo的目录下
```bash
$ cp -rf ncnn/build-c910/install/include ./Ultralight-SimplePose/ncnnsample/
$ cp -rf ncnn/build/install-c910/lib ./Ultralight-SimplePose/ncnnsample/
```
- 修改detectorv2的代码 (还需要增加判断是否低头和坐姿是否前倾之类的判断逻辑)
```bash
# 修改依赖的头文件
#define USE_NCNN_SIMPLEOCV
#if defined(USE_NCNN_SIMPLEOCV)
#include "simpleocv.h"
#else
#include
#include
#include
#endif
# simpleocv.h 和 opencv里面的 rectangle 接口参数不一样
cv::rectangle(image, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(255, 0, 255));
```
- 编译detectorv2(这里使用了licheepi4a板载g++,没使用交叉编译)
```bash
$ g++ -o detectorv2 detectorv2.cpp -I include/ncnn/ -L lib/ -lncnn
$ ./detectorv2
```
- 运行程序
```bash
python camera.py | ./detectorv2
```
## 2. 终端显示上位机开发
- 开发环境和依赖: PyQt5 + Pycharm + Qt Designer + PyUIC
- 开发流程:
- 使用Qt Designer 设计UI和布局,生成 xx.ui 文件
- 使用PyUIC把 xx.ui 文件转换成 [windows.py](http://windows.py) 文件
- 编写mian.py文件,实现上位机代码逻辑,并调用windows.py文件,实现UI界面显示
- 实现的主要功能有:
- 串口通讯,读取LubanCat-2N的终端串口数据,并做数据过滤和处理,对应UI界面有,串口开启和关闭时不同状态显示,以及串口端口号的选择处理。
- 判断串口终端的数据是否有关于例如“`低头`”、“`上半身后倾`”、“`上半身前倾`”、“`姿势正常`”等关键词,对应UI操作,就是姿势正常,对应图标为绿色,姿势不对,图标为红色
- 番茄时钟,可以设置开启、暂停和重置的过程
- 显示当前时间和星期几
- 代码目录:
- [main.py](http://main.py) 关键代码如下
```c
import sys
import serial.tools.list_ports
import serial
class PostureMonitor:
def __init__(self, label_18, label_19, label_22):
self.label_18 = label_18
self.label_19 = label_19
self.label_22 = label_22
def update_posture(self, keyword):
if "head down" in keyword:
self.label_18.setPixmap(QtGui.QPixmap("ui/body_error.png"))
if "head up" in keyword:
self.label_18.setPixmap(QtGui.QPixmap("ui/body_ok.png"))
self.label_19.setPixmap(QtGui.QPixmap("ui/head_ok.png"))
self.label_22.setText("上半身状态")
class PomodoroTimer:
def __init__(self, label, duration=25*60):
self.label = label
self.duration = duration
self.time_left = self.duration
self.timer = QTimer()
self.timer.timeout.connect(self.update_time)
def start(self):
self.timer.start(1000) # 更新频率为1秒
def pause(self):
self.timer.stop()
def reset(self):
self.timer.stop()
self.time_left = self.duration
self.update_display()
def update_time(self):
self.time_left -= 1
if self.time_left
-
发表了主题帖:
【玄铁杯第三届RISC-V应用创新大赛】Lichee PI 4A 之编译Ultralight-SimplePose
# 【玄铁杯第三届RISC-V应用创新大赛】Lichee PI 4A 之编译Ultralight-SimplePose
往期文章:
【玄铁杯第三届RISC-V应用创新大赛】LicheePi 4A+开箱 http://test.bbs.eeworld.com.cn/thread-1257258-1-1.html
【玄铁杯第三届RISC-V应用创新大赛】Lichee PI 4A 之OpenCV与摄像头抓拍 http://test.bbs.eeworld.com.cn/thread-1265914-1-1.html
【玄铁杯第三届RISC-V应用创新大赛】Lichee PI 4A 之编译ncnn&测试simplepose demo http://test.bbs.eeworld.com.cn/thread-1265915-1-1.html
## 前言
之前测试ncnn的simplepose,发现不如预期,然后看ncnn的README,看到还有个**Ultralight-SimplePose**,它也是可以用ncnn来做推理的(我是这么理解的),而且还给了一个ncnn的demo。但其实用起来,也不是一帆风顺。
## 内容正文
### 一、搭建
1. 下载Ultralight-SimplePose
```bash
git clone http://github.com/dog-qiuqiu/Ultralight-SimplePose.git
```
2. 想编译安装ncnn,这个前文有提,这里不赘述,编译完成,会在build-c910目录下发现两个文件夹include和lib,将他们拷贝到Ultralight-SimplePose的ncnn demo的目录下
```bash
$ cp -rf ncnn/build-c910/install/include ./Ultralight-SimplePose/ncnnsample/
$ cp -rf ncnn/build/install-c910/lib ./Ultralight-SimplePose/ncnnsample/
```
3. 编译
我尝试了用Xuantie的编译链交叉编译下面的内容,但发现与libncnn.a 的库编译不过,所以我就直接在licheepi4a板子上编译ncnnpose demo了。
4. 编译命令
官网用的命令是
```bash
$ g++ -o ncnnpose ncnnpose.cpp -I include/ncnn/ lib/libncnn.a `pkg-config --libs --cflags opencv` -fopenmp
$ ./ncnnpose
```
这里有个问题,就是我没找到OpenCV可以跑在rsicv64上的版本,有的只有python版本,这个是我在编译这里遇到的第一个问题,然后我决定不用上面命令,做了修改,命令如下
```bash
$ g++ -o ncnnpose ncnnpose.cpp -I include/ncnn/ -L lib/ -lncnn
$ ./ncnnpose
```
### 二、修改测试demo,使其可以正常编译,否则还是找不到opencv
1. 回头仔细看了下ncnn的simplepose.cpp的代码,发现ncnn自己写一个simpleocv文件,来代替opencv的,所以这里我们也这么用(这个后面还有”坑”,留到下一篇去写吧)
2. 修改的demo代码内容有:
```bash
#if defined(USE_NCNN_SIMPLEOCV)
#include "simpleocv.h"
#else
#include
#include
#include
#endif
# simpleocv.h 和 opencv里面的 rectangle 接口参数不一样
// cv::rectangle (image, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(255, 0, 255), 2, 8, 0);
cv::rectangle(image, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(255, 0, 255));
```
### 三、测试运行命令
1. 运行命令
2. 测试结果
### 四、总结
这个运行起来速度就比ncnn的demo快多了,但也优缺点,比如精准度不够高,暂时不支持视频流,其实它支持,但我这边用的ncnn写的simpleocv不支持,有点局限,其实不是ncnn不好,更多的还是RSIC-V的生态还需要继续完善,但已经很不错了,最后的比赛项目就可以正常开始了。
-
发表了主题帖:
【玄铁杯第三届RISC-V应用创新大赛】Lichee PI 4A 之编译ncnn&测试simplepose demo
本帖最后由 小默叔叔 于 2023-12-6 20:18 编辑
# 【玄铁杯第三届RISC-V应用创新大赛】Lichee PI 4A 之编译ncnn&测试simplepose demo
往期链接:
【玄铁杯第三届RISC-V应用创新大赛】LicheePi 4A+开箱 https://bbs.eeworld.com.cn/thread-1257258-1-1.html
【玄铁杯第三届RISC-V应用创新大赛】Lichee PI 4A 之OpenCV与摄像头抓拍 https://bbs.eeworld.com.cn/thread-1265914-1-1.html
## 前言
因为想基于LicheePi 4A去实现一个简单的姿势识别装置,所有就一直在找姿势识别的模型,希望可以跑在RISC-V上,然后又想到了NCNN,它example里有一个关于姿势估计的demo,所有计划尝试下。
其实还考虑过Mediapipe,但因为bazel貌似不支持RISC-V,而我又担心自己编译bazel是否后续还会有其他问题,所以没有再往下尝试,担心还有其他依赖不支持。
对了,好的代码工程都有好的README,在我们不知道如何入手的时候,都可以再好好看看README.md
## 正文内容
### 一、NCNN
1. NCNN 介绍
ncnn 是一个为手机端极致优化的高性能神经网络前向计算框架。 ncnn 从设计之初深刻考虑手机端的部署和使用。 无第三方依赖,跨平台,手机端 cpu 的速度快于目前所有已知的开源框架。nihui大佬!
2. 交叉编译NCNN
荔枝官网给的指导,我理解是把ncnn下载到开发板,然后再编译。但因为我觉得硬件资源有限,而且编译速度也会受影响的情况下,我决定交叉编译NCNN,然后测试。(后面在LicheePi4A上,还是尝试了编译NCNN(python版本,这个是后话))
- 下载编译链和配置交叉编译环境
```bash
# 1.下载 Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.4.0 并解压
# 2.设置交叉编译链配置环境
sudo vim ~/.bashrc
# SET C910 ENV by xiebx 2023-11-29
export RISCV_ROOT_PATH=/home/Code/buildtools/Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.4.0
source ~/.bashrc
```
- 编译方式参考ncnn编译D1的流程:因为D1也是平头哥的C906,licheepi 4a用的TH1520的核心就是C910,所以我们看README.md,里面有告诉我们了如何编译D1
```bash
## 编译 c906 用来参考
mkdir -p build-c906
cd build-c906
cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/c906-v226.toolchain.cmake \
-DCMAKE_BUILD_TYPE=release -DNCNN_OPENMP=OFF -DNCNN_THREADS=OFF -DNCNN_RUNTIME_CPU=OFF -DNCNN_RVV=ON \
-DNCNN_SIMPLEOCV=ON -DNCNN_BUILD_EXAMPLES=ON ..
cmake --build . -j 4
cmake --build . --target install
## 编译licheepi4a(c910)的ncnn
mkdir -p build-c910
cd build-c910
cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/c910-v240.toolchain.cmake \
-DCMAKE_BUILD_TYPE=release -DNCNN_OPENMP=OFF -DNCNN_THREADS=OFF -DNCNN_RUNTIME_CPU=OFF -DNCNN_RVV=ON \
-DNCNN_SIMPLEOCV=ON -DNCNN_BUILD_EXAMPLES=ON ..
cmake --build . -j 4
cmake --build . --target install
```
- 解决编译报错的问题
我这里出现的错误主要是我的cmake版本太低(3.11.4)导致,无法在“cmake —build” 后面加参数,所以我升级了cmake版本到3.25.2(貌似3.12之后就支持了)
```bash
# 当时的报错日志
/ncnn/build-th1520$ cmake --build . -j 4
Unknown argument -j
Unknown argument 4
Usage: cmake --build <dir> [options] [-- [native-options]]
Options:
<dir> = Project binary directory to be built.
--target <tgt> = Build <tgt> instead of default targets.
May only be specified once.
--config <cfg> = For multi-configuration tools, choose <cfg>.
--clean-first = Build target 'clean' first, then build.
(To clean only, use --target 'clean'.)
--use-stderr = Ignored. Behavior is default in CMake >= 3.0.
-- = Pass remaining options to the native tool.
lance@lance-VirtualBox-ubuntu18:~/Legrand/Code/ncnn/build-th1520$ cmake --version
cmake version 3.11.4
CMake suite maintained and supported by Kitware (kitware.com/cmake).
```
- 这里再说两句@@
- 我看到后面使用OpenCV的wiki上说,他们用的是编译链是Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.6.1,增加了Development for RISC-V with vector support
- 但又看ncnn里面的toolchains里有两个“c910-v240.toolchain.cmake”“th1520-v240.toolchain.cmake”,首先我理解他们是xuantie gcc的2.4.0的版本,我不清楚我用2.6.1的是否会有问题,然后我也对比了下两个文件发现,emmm,差异不大,可能具体的是关于 vector support 的支持
- 所以,,,我选了c910,因为我不清楚th1520和c910的区别,我理解licheepi4a的芯片叫TH1520,核心是c910x4的
- 这里的确我有点懵@@,但我觉得c910-v240.toolchain.cmake也可以用Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.6.1它编译,我也的确这么尝试了,发现貌似没啥问题,可能涉及的就是对 vector 的支持吧?????
- 如前面所写的,我的编译链最后选择的是Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.4.0
- 以上,完成了ncnn的交叉编译
3. 下载相关模型文件以及参数
- 荔枝的指导文档里已经给出了下载地址,但很多人可能只是跑了个nanodet,但如果你好好看README,你就会知道如何使用其他的模型,比如跑simplepose这些
- 下载地址 [https://github.com/nihui/ncnn-assets/tree/master/models](https://github.com/nihui/ncnn-assets/tree/master/models)
### 二、使用测试simplepose demo(C++版本)
1. 将下载好的模型文件和参数,已经编译好的运行文件,还有测试图片,都将一个文件夹,上传到LicheePi 4A上面
| 名称 | 文件名 | 位置 |
| -------- | ---------- | ----------------------------------- |
| 模型文件 | pose.bin | 上文链接里下载 |
| 参数文件 | pose.param | 上文链接里下载 |
| 运行文件 | simplepose | ncnn/build-c910/examples/simplepose |
| 测试图片 | test.jpg | 可以自己上网下载,我用的ncnn提供的 |
2. 运行测试
```bash
chmod +x simplepose
./simplepose test.jpg
```
3. 测试结果
4. 测试过程你会发现,这个时间很长,运行的结果还好,但时间太久了,感觉有5-6s,我判断可能是模型和参数的问题,也需要优化
### 三、使用测试simplepose demo(Python版本)
其实一开始我想要不别交叉编译链了,而且python写起来比c++容易些,我要不就用python吧,所以有这个这个版本,但后来我发现,,速度很慢,不符合我的预期,所以我又尝试了c++的版本。
1. 编译流程
- 将下载好的ncnn拷贝到licheepi4a上(我因为之前测试过交叉编译,所以提前下载好了)
- 开始编译 python setup.py
- 编译报错,缺少依赖,依次添加
2. 运行测试文件 python simplepose.py
测试结果同c++版本,这里就不贴了
### 四、总结
其实事情到这里,我就有点慌了,因为我之前也看过其他姿势评估的,也都不支持RISC-V,而且我也暂时没有时间自己训练模型和修改参数,如果NCNN都跑不通,那我的这次比赛就没戏了,然后我又看了看README.md,发现了 φ(゜▽゜*)♪
下一个帖子,就是讲解怎么使用**[Ultralight-SimplePose](https://github.com/dog-qiuqiu/Ultralight-SimplePose)**(不过也是有些困难)
-
发表了主题帖:
【玄铁杯第三届RISC-V应用创新大赛】Lichee PI 4A 之OpenCV与摄像头抓拍
本帖最后由 小默叔叔 于 2023-12-8 08:28 编辑
# 【玄铁杯第三届RISC-V应用创新大赛】Lichee PI 4A 之OpenCV与摄像头抓拍
往期文章:
【玄铁杯第三届RISC-V应用创新大赛】LicheePi 4A+开箱 https://bbs.eeworld.com.cn/thread-1257258-1-1.html
## 前言
USB视频类(UVC)是一个旨在简化USB连接上视频流功能的标准化协议。这一标准对于确保各类视频设备,如网络摄像头、数码摄像机、模拟视频转换器以及模拟和数字电视调谐器等,能够与计算机和其他主机设备无缝对接起着关键作用。
UVC的一个主要优势在于它对多种视频格式的支持,包括但不限于YUV、MJPEG、MPEG-2 TS、H.264和DV。这种多样性在为视频设备向主机系统传达其功能方面发挥着核心作用。此外,UVC还规定了用于控制视频流的特定参数和特征,提高了数据传输的效率和质量。
我这里使用的摄像头是以前参加活动的一款USB摄像头,然后计划使用OpenCV库去调用摄像头实现抓怕和图片存储,为项目后续的需要做准备。
## 正文内容
1. 发现开发环境已经安装了python3,但还是习惯直接打python运行,而不是python3,所以这里增加个软链接
```c
# 创建新的软链接,这样每次使用python就不用打python3了
sudo ln -s /usr/bin/python3 /usr/bin/python
```
2. 安装 Python 版本的 OpenCV,需要指令如下
```bash
sudo apt install python3 python3-pip
sudo apt install python3-opencv
sudo apt install libqt5gui5-gles
```
3. 确认我们摄像头挂载在哪里,输入ls /dev/video*,看到的结果如下所示
4. 打开摄像头逻辑(基于OpenCV 的 Python版本)
- 打开摄像头 `cap = cv2.VideoCapture(0)`
- 读取摄像头每帧图像 `frame = cap.read()`
- 显示图像`cv2.imshow("USB Camera", frame)`
- 结束循环,释放摄像头关闭所有接口
- `cap.release()`
- `cv2.destroyAllWindows()`
5. 基于上述内容,我们可以做个扩展(其实也是基于我后面项目的需求做了开发)
- 打开摄像头,并获取每帧图像
- 每隔3s保存一张图片,并命名为 x.jpg (x的范围是0-6,x递增)
- 循环保存 0.jpg → 6.jpg (比如超过6,则从0重新开始,覆盖掉之前的0)
- 代码如下
```bash
import cv2
import time
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("The camera is not opened")
exit(1)
img_counter = 0
while True:
ret, frame = cap.read()
if not ret:
print("Failed to grab frame")
break
img_name = f"{img_counter % 7}.jpg" # 使用模运算保证图片名称在0-6之间
cv2.imwrite(img_name, frame)
print(f"{img_name} written!")
# 因为只是demo 暂时不考虑img_counter 范围
img_counter += 1
# 等待 3 秒
time.sleep(3)
cap.release()
```
运行命令
- 2023-12-03
-
发表了主题帖:
第三章 内存管理之预备知识
第三章 内存管理之预备知识 阅读心得
读后感:聚焦Linux内核内存管理的高频面试题
1. UMA和NUMA的区别
在《奔跑吧Linux内核》中,作者详细解释了UMA(统一内存访问)和NUMA(非统一内存访问)的区别。UMA架构中,所有处理器访问统一的内存资源,内存访问时间对所有处理器都是一样的。而在NUMA架构中,系统被划分为多个节点,每个节点有自己的内存,处理器访问本地节点的内存速度更快。这种架构在多处理器系统中尤为重要,因为它可以减少内存访问的延迟,提高系统性能。
2. CPU访问各级存储结构的速度
书中强调了CPU访问不同存储结构(如寄存器、缓存、主存、辅助存储)的速度差异。这些存储结构构成了计算机的存储层次结构,每一层的存储速度和容量都有所不同。理解这一点对于优化程序性能和理解内存管理机制非常重要。
3. 内存管理数据结构的关系图
作者提出了一个关于绘制内存管理中常用数据结构关系图的问题,如mm_struct、VMA、page等。这些数据结构是Linux内存管理的基石,它们之间的关系复杂但有序。例如,mm_struct是进程的内存描述符,包含了该进程的所有虚拟内存区域(VMA)。每个VMA又与特定的物理内存页(page)相关联。理解这些数据结构及其相互关系对于深入理解Linux内核的内存管理至关重要。
4. ARM64内核中,内核映像文件映射到内核空间的位置
这个问题涉及到操作系统的启动和内核映像的加载过程。在ARM64架构中,内核映像文件被映射到特定的内核空间地址。这一过程对于系统的启动和运行至关重要,因为它决定了内核如何与硬件交互,以及如何管理系统资源。
5. 由mm_struct和vaddr找到对应的VMA
这个问题涉及到Linux内核如何管理进程的虚拟内存。在Linux中,每个进程都有一个**mm_struct结构体,它代表进程的整个虚拟内存空间。mm_struct**包含了一个VMA(虚拟内存区域)列表,每个VMA代表进程地址空间中的一个连续区域。要找到特定虚拟地址(vaddr)对应的VMA,内核会遍历这个列表,直到找到包含该地址的VMA。
6. 由page找到所有映射的VMA
这个问题探讨了如何从一个物理内存页(page)找到所有映射到这个页的虚拟内存区域(VMA)。在Linux内核中,每个物理页都有一个或多个VMA与之对应。内核使用反向映射(rmap)机制来跟踪哪些VMA映射到了特定的物理页。这是一个复杂的过程,因为一个物理页可能被多个进程的多个VMA共享。
7. 内存管理中的其他转换关系
书中还提出了其他几个关于内存管理的转换关系问题,如page和PFN(页帧号)之间的互换、PFN和物理地址(paddr)之间的互换、以及page和页表项(PTE)之间的互换等。这些问题深入探讨了Linux内核中虚拟内存和物理内存之间的映射关系。理解这些转换关系对于深入理解Linux内核的内存管理机制至关重要。
结论
通过深入探讨这些高频面试题,《奔跑吧Linux内核》不仅为读者提供了Linux内核内存管理的深刻见解,还展示了作者在解释复杂技术概念方面的能力。这些问题覆盖了从基础到高级的多个方面,为希望深入了解Linux内核的读者提供了宝贵的学习资源。其实对我来说,我目前感兴趣的只有3、6、7、8、9这五章内容,阅读心得计划是:更多的从高频面试题来检测自己阅读成果。
- 2023-11-26
-
回复了主题帖:
阅读打卡第一站:处理器架构——《奔跑吧Linux内核(第2版)卷1:基础架构》
RISC与CISC的区别:
RISC(精简指令集):指令简单,每条指令执行时间短,大多数指令在一个时钟周期内完成。RISC处理器通常具有更少的指令,但更高的执行效率。
CISC(复杂指令集):指令复杂,执行时间长,指令数量多。CISC处理器的指令集设计用于减少程序的长度,但可能导致处理器硬件更复杂。
数值0x12345678在大小端字节序处理器中的存储方式:
大端字节序:高位字节存储在低地址处。因此,0x12存储在最低地址,其次是0x34,0x56,0x78。
小端字节序:低位字节存储在低地址处。因此,0x78存储在最低地址,其次是0x56,0x34,0x12。
双核Cortex-A9处理器中存储读写指令的执行全过程:
该过程涉及指令获取、解码、执行、访问内存和写回阶段。
指令从内存加载到指令寄存器。
指令解码,确定操作类型和操作数。
执行阶段进行算术或逻辑运算。
访问内存阶段,读取或写入数据。
写回阶段,将结果写回寄存器或内存。
内存屏障(memory barrier)产生的原因:
内存屏障用于处理多个CPU间的内存访问顺序问题。
编译器优化和处理器的乱序执行可能导致指令执行顺序与编写顺序不一致,内存屏障用于确保顺序性和一致性。
现代处理器采用超标量架构、乱序发射和乱序执行技术,这使得指令的执行顺序在处理器流水线中可能被打乱,与程序代码编写时序列不一致。此外,现代处理器采用多级存储结构,如何保证处理器对存储子系统访问的正确性也是一个挑战。内存屏障是为了解决这些问题而产生的。
ARM内存屏障指令及其区别:
ARM提供了几种内存屏障指令,如DMB(Data Memory Barrier)、DSB(Data Synchronization Barrier)和ISB(Instruction Synchronization Barrier)。
DMB指令确保其前后的内存访问指令顺序执行。
DSB指令更严格,要求在其前面的所有访问指令完成后才执行后面的指令。
ISB指令用于刷新流水线,确保修改后的指令正确执行。
高速缓存(cache)的工作方式:
高速缓存是一种小容量但高速的存储器,用于存储临时数据,减少CPU访问主存储器的次数。
它利用局部性原理,存储最近访问的数据和指令。
当CPU需要数据时,首先在缓存中查找,如果找到(缓存命中),则直接使用;如果未找到(缓存未命中),则从主存中加载数据到缓存,并更新缓存。
高速缓存的映射方式及其区别:
全关联映射:任何主存中的块都可以放在缓存中的任何位置。
直接映射:每个主存中的块只能映射到缓存中的一个特定位置。
组相联映射:是全关联和直接映射的折中方案,缓存分为多个组,每个主存块可以映射到一个组中的任何位置。
现代处理器使用组相联映射方式,因为它提供了直接映射的简单性和全关联映射的灵活性,平衡了性能和成本。