- 2024-10-31
-
发表了主题帖:
【2024 DigiKey 创意大赛】 键鼠统一管家——作品提交
本帖最后由 lzhan 于 2024-11-1 13:40 编辑
键鼠统一管家
作者:lzhan
一、作品简介
本项目为键鼠统一管家,其中使用NUCLEO-L476RG开发板作为主控板,负责与OPENMV H7、自制PCB进行通信,同时作为USB Host用于驱动用户端的键盘和鼠标;OPENMV H7用于采集图像并进行处理,来判断人脸的朝向,将结果上报给主控板;自制PCB包含两个USB Device,根据朝向判决结果,将键鼠数据转发到对应的PC主机上。
设备展示
该产品所使用的物料如下:
物料名称
型号
功能
OPENMV模组
OPENMV CAM H7
采集图像、面部朝向判断
STM32
NUCLEO-L476RG
USB Host、主控板
STM32
STM32F070
USB Device
二、系统框图
该系统的整体框图如下所示。每个PC电脑各有一个显示器,并排成一定夹角放在一起,将该系统放在两个显示器之间。OPENMV H7和NUCLEO-L476RG都是使用USB各自独立进行供电,自制PCB由NUCLEO-L476RG进行供电。
三、各部分功能说明
OPENMV H7开发板用来实现人脸检测,并根据人脸中心位置与预设标定位置的比较来判断人脸朝向。
当人脸朝左时,蓝色LED亮,同时拉高GPIO P1为高电平,拉低GPIO P2为低电平。
当人脸朝右时,红色LED亮,同时拉高GPIO P2为高电平,拉低GPIO P1为低电平。
OPENMV H7在实现时使用到了OPENMV H7的摄像头、LED和GPIO共三种外设。其实现过程如下:
import摄像头所需要的sensor库、延时所需要的time库、图像处理所需要的image库、GPIO所需要的pyb库和LED所需要的machine库。
对Sensor进行复位、设置Sensor对比度、设置Sensor增益、设置Sensor捕捉图像大小、设置Sensor输出格式
初始化标定中点midpoint为0;初始化方向状态变量stat为1,1标志头向左偏,2标志头向右偏;初始化现在中点nowpoint为0。
初始化蓝色LED灯作为头部转向为左(蓝的拼音为Lan,取L,近似为Left)的指示;初始化红色LED灯作为头部转向为右(红的英文为Red,取R,近似为Right)的指示。
初始化GPIO P1和P2,设置其为输出,并设置其电平为低电平。
加载Haar人脸检测模型,然后进行人脸检测。当检测到人脸时,根据人脸的左坐标和宽度计算得到从此时脸的中点坐标。若此时脸的中点坐标小于等于标定中点坐标且stat等于1,说明脸向右偏,则需要通知处理模块,因此先将LED1关闭,然后打开LED2,将stat置为2,拉低GPIO P1,拉高GPIO P2;若此时脸的中点坐标大于标定中点坐标且stat等于2,说明脸向左偏,则需要通知处理模块,因此先将LED2关闭,然后打开LED1,将stat置为1,拉低GPIO P2,拉高GPIO P2。
代码如下:
import sensor
import time
import image
import pyb
from machine import LED
global calib
def callback_p0(line):
calib = 1
def main():
sensor.reset()
sensor.set_contrast(8)
sensor.set_gainceiling(16)
sensor.set_framesize(sensor.HQVGA)
sensor.set_pixformat(sensor.GRAYSCALE)
calib = 0
midpoint = 0
stat = 1
nowpoint = 0
led1 = LED("LED_BLUE")
led2 = LED("LED_RED")
led3 = LED("LED_GREEN")
p0_h = pyb.Pin("P0", pyb.Pin.IN)
p1_h = pyb.Pin("P1", pyb.Pin.OUT_PP)
p2_h = pyb.Pin("P2", pyb.Pin.OUT_PP)
p1_h.low()
p2_h.low()
p0_ext = pyb.ExtInt(p0_h, pyb.ExtInt.IRQ_FALLING,
pyb.Pin.PULL_UP, callback_p0)
face_cascade = image.HaarCascade("frontalface", stages=25)
while True:
img = sensor.snapshot()
objects = img.find_features(face_cascade, threshold=1, scale_factor=1.5)
for face in objects:
if(calib):
nowpoint = (face[0]+face[2])/2
calib = 0
led3.on()
pyb.delay(5000)
led3.off()
nowpoint = (face[0]+face[2])/2
if((nowpoint <= midpoint) and (stat == 1)):
led1.off()
led2.on()
stat = 2
p1_h.low()
p2_h.high()
elif(nowpoint>midpoint) and (stat == 2):
led2.off()
led1.on()
stat = 1
p2_h.low()
p1_h.high()
NUCLEO-L476RG开发板用于实现USB Host,操作键鼠一体USB接收器,将USB HID报文中的数据转发到SPI输出。根据OPENMV的GPIO的电平进行处理:若GPIO1的电平为高,则说明此时人脸是朝向左侧的,此时对应左侧电脑的SPI slave (STM32F070,实现左测电脑的USB输入设备)片选信号置为有效,HID报文数据被SPI slave接收后通过USB端点发送出去;若GPIO2的电平为高,则说明此时人脸是朝向右侧的,另一个SPI slave的片选信号有效,HID报文被转发到另一个USB设备发出。
如果键盘鼠标是独立的(要两个USB口),则需要增加一个USB host来处理,就需要再用一块STM32L476或类似的带USB-OTG设备的MCU,将其收到的HID报文发送给主控的STM32L476. 因为大赛物料成本的限制,手上又有无线键鼠套装,就只用了一个USB host.
部分主要代码如下:
int main(void)
{
gpio_config();
GPIOB->OSPEEDR = 2<<30|2<<28|2<<26;
FLASH->ACR = FLASH_ACR_ICEN|FLASH_ACR_DCEN|FLASH_ACR_PRFTEN
|2<<FLASH_ACR_LATENCY_Pos; // 2 wait states, 32~48MHz
clk_config(); // without this, default SYSCLK is 4MHz
uart_setup();
if((RCC->CFGR & RCC_CFGR_SWS_Msk)!=RCC_CFGR_SWS_PLL)
{
uart_wstr("Clock setting to PLL failed. ");
}
spi_setup();
usb_setup();
RCC->APB1ENR1 |= RCC_APB1ENR1_TIM6EN;
__NOP();
TIM6->PSC = 479; // prescale to 100kHz
TIM6->EGR = TIM_EGR_UG; // generate update
TIM6->SR = 0; // clear interrupt flag
TIM6->DIER = TIM_DIER_UIE; // enable Interrupt
NVIC_EnableIRQ(TIM6_DAC_IRQn);
while(1)
{
__WFI();
}
}
自制PCB是一个两层板,其主要包含两个F070,用于作对应两台PC电脑的USB Device,其通过两个SPI与NUCLEO-L476RG相连接,接收转发的对应的USB数据,然后对应主机从中获得对应的数据,从而完成一套键鼠控制两台电脑的功能。
PCB顶层
PCB底层
部分主要代码如下:
int main(void)
{
int i;
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN|RCC_APB2ENR_SPI1EN;
gpio_config();
FLASH->ACR=FLASH_ACR_PRFTBS|FLASH_ACR_PRFTBE|FLASH_ACR_LATENCY;
SYSCFG->CFGR1 |= SYSCFG_CFGR1_PA11_PA12_RMP;
clock_setup();
config_spi_slave();
uart_setup();
uart_whex(SPI1->CR2);
uart_wstr(" F070 test\r\n");
NVIC_EnableIRQ(SPI1_IRQn);
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
USB->CNTR &= ~1; // remove PDWN
delay_ms(1);
USB->CNTR = 0; // no reset
USB->CNTR = USB_CNTR_CTRM|USB_CNTR_WKUPM|USB_CNTR_ERRM
|USB_CNTR_SUSPM|USB_CNTR_RESETM;
uart_wstr("Configured USB_CNTR\r\n");
NVIC_EnableIRQ(USB_IRQn);
USB->BCDR = USB_BCDR_DPPU; // pull-up resistor enable
while(1)
{
static char row=0;
__WFI();
if(ep0_state & 0x80) // request data processing
{
if(ep0_state==0x80) // SETUP phase
{
if(!setup_packet_service())
{
ep0_state=0;
uart_wstr("NOT_SUPPORTED [Type ");
uart_whexb(ep0_std_req->bmRequestType);
uart_wstr(" Request ");
uart_whexb(ep0_std_req->bRequest);
uart_wstr(" Val ");
uart_whexh(ep0_std_req->wValue);
uart_wstr(" Ind ");
uart_whexh(ep0_std_req->wIndex);
uart_wstr(" Len ");
uart_whexh(ep0_std_req->wLength);
uart_wstr("] ");
}
// ep0_state should be set to 1 or 2, if processed
}
else // OUT phase
{
ep0_state=4;
ep0_reenable_tx(0); //zero data, status stage
}
}
else
{
if(usb_address && ep0_state==0)
{
USB->DADDR = USB_DADDR_EF|usb_address;
usb_address=0;
}
}
}
}
四、作品源码
源码已经上传到下载中心,
图像处理代码:download.eeworld.com.cn/detail/lzhan/634859
USB Host、Device代码:download.eeworld.com.cn/detail/lzhan/634869
五、作品功能演示视频
以下是我的作品演示:
键鼠统一管家 - 键鼠统一管家 - EEWORLD大学堂
六、项目总结
我本人非常荣幸能够参加本次大赛,通过这次大赛,让我能够有机会使用到OPENMV H7来完成项目,我从中学习到了如何使用MicroPython方法来进行嵌入式的开发与调试。感谢@cruelfox 为作品提供的USB部分实现的技术支持。
由于平时事情比较繁琐,因此项目做的较为仓促,图像处理算法的复杂度一降再降。目前还存在以下的问题:只允许脑袋进行转向,若身子发生较大的移动,则相对位置关系被破坏,因此就无法获得正确的判别结果,存在一定限制。
帖子分享汇总:
【2024 DigiKey 创意大赛】物料开箱 https://bbs.eeworld.com.cn/thread-1290478-1-1.html
【2024 DigiKey 创意大赛】进度分享 https://bbs.eeworld.com.cn/thread-1292099-1-1.html
【2024 DigiKey 创意大赛】 键鼠统一管家(1) 软件算法及实现 https://bbs.eeworld.com.cn/thread-1297454-1-1.html
【2024 DigiKey 创意大赛】 键鼠统一管家(2) OPENMV调试 https://bbs.eeworld.com.cn/thread-1297816-1-1.html
【2024 DigiKey 创意大赛】 键鼠统一管家(3) 扩展板制作 https://bbs.eeworld.com.cn/thread-1297918-1-1.html
七、其他
附件为word版文档
-
加入了学习《【2024 DigiKey创意大赛】- 基于毫米波雷达的生命体征检测及健康监护系统》,观看 【2024 DigiKey创意大赛】- 基于毫米波雷达的生命体征检测及健康监护系统-作品提交
-
上传了资料:
usb_host_device_code
-
回复了主题帖:
【2024 DigiKey 创意大赛】 键鼠统一管家(3) 扩展板制作
wangerxian 发表于 2024-10-31 19:21
我觉得直接把芯片做到板子上会不会更好一些嘞
L476是必须比赛选的物料
-
加入了学习《【2024DigiKey创意大赛】基于AIOT的智能家居设备开发演示视频》,观看 【2024DigiKey创意大赛】基于AIOT的智能家居设备开发
-
上传了资料:
键鼠统一管家OPENMV源码
-
发表了主题帖:
【2024 DigiKey 创意大赛】 键鼠统一管家(3) 扩展板制作
本帖最后由 lzhan 于 2024-10-31 16:45 编辑
## 1. 引言
本文将介绍设计并实现了一个基于NUCLEO-L476RG开发板及其扩展板的USB数据传输系统。L476RG开发板作为USB host与外部设备如鼠标和键盘进行交互,而扩展板则集成了两块F070作为USB device与PC通信。
## 2. 扩展板
扩展板整体原理图如下所示,其主要通过排针与NUCLEO-L476RG开发板进行连接并接受其控制;二合一的键盘鼠标的USB插入到USB-231-BRW接口中进行连接;使用两块F070通过SPI总线协议与NUCLEO-L476RG进行通信,两个SPI从设备的MISO、MOSI、SCK均分别使用同一根线,NSS使用独立的线,当选中某一个SPI设备时,拉低对应的NSS即可。
F070子模块的原理图如下所示,主控是一个stm32 F070,外部连接一块12Mhz的晶振,其作为USB device通过USBMINIABConnector与PC主机进行通信。
板子是两层板,其顶层和底层layout如下所示。
3D效果展示下图所示
最终打板结果如下图所示
## 3. 整体连接
L476RG与扩展板整体连接图如下所示,
## 1. 引言
本文将介绍设计并实现了一个基于NUCLEO-L476RG开发板及其扩展板的USB数据传输系统。L476RG开发板作为USB host与外部设备如鼠标和键盘进行交互,而扩展板则集成了两块F070作为USB device与PC通信。
## 2. 扩展板
扩展板整体原理图如下所示,其主要通过排针与NUCLEO-L476RG开发板进行连接并接受其控制;二合一的键盘鼠标的USB插入到USB-231-BRW接口中进行连接;使用两块F070通过SPI总线协议与NUCLEO-L476RG进行通信,两个SPI从设备的MISO、MOSI、SCK均分别使用同一根线,NSS使用独立的线,当选中某一个SPI设备时,拉低对应的NSS即可。
F070子模块的原理图如下所示,主控是一个stm32 F070,外部连接一块12Mhz的晶振,其作为USB device通过USBMINIABConnector与PC主机进行通信。
板子是两层板,其顶层和底层layout如下所示。
3D效果展示下图所示
最终打板结果如下图所示
## 3. 整体连接
L476RG与扩展板整体连接图如下所示,
-
发表了主题帖:
【2024 DigiKey 创意大赛】 键鼠统一管家(2) OPENMV调试
# 1. 引言
在使用嵌入式开发时,调试和程序固化是两个关键步骤。本文将简要介绍如何在OPENMV-H7上进行调试,然后介绍如何将程序固化到FLASH上进行脱机运行。
# 2. 调试模式
OPENMV-H7是使用基于QT开发的、自研的IDE,其界面如下。
主要分为四个部分:
第一部分是代码区,在该部分主要进行代码的编写,OPENMV能够支持直接使用Python进行开发。
第二部分是图像区,在该部分可以在PC电脑端实时看到摄像头采集到的图像以及色彩的分布直方图。
第三部分是串口终端,在该部分能够接收到板子发送到PC端的串口打印信息以及在运行过程中IDE编译的信息。
第四部分是连接/运行,在该部分可以实现板卡与PC电脑端的连接以及启动调试。
# 3. 脱机运行
OPENMV支持代码脱机运行,只需将代码固化到内置Flash中即可。其具体操作过程如下,
首先编写好程序后,点击工具栏中的工具->将打开的脚本保存到OpenMV Cam(作为main.py)。
然后在弹出的窗口“去除注释并将空格转换为制表符”中选择Yes或者No。
之后OPENMV会开始亮红灯,指示开始烧录程序,灯灭后指示烧录完成。
弹出板子,然后再重新插入板子,OPENMV会自动运行烧录的程序
注意,由于OPENMV设置原因,它会主动搜索名称为main的文件并进行执行,因此主程序的文件名称一定要是main.py。
- 2024-10-28
-
发表了主题帖:
【2024 DigiKey 创意大赛】 键鼠统一管家(1) 软件算法及实现
# 【2024 DigiKey 创意大赛】 键鼠统一管家(1) 软件算法及实现
## 1.引言
我此次使用OPENMV H7开发板来实现人脸检测,并根据人脸中心位置与预设标定位置的比较来判断人脸朝向。因此在本文将介绍人脸识别算法原理、算法实现流程以及测试结果。
## 2.算法原理
Haar级联分类器是一种用于对象检测的机器学习算法,由Paul Viola和Michael Jones在2001年提出。它的核心思想是使用大量的正样本(包含人脸的图像)和负样本(不包含人脸的图像)来训练一个级联函数,这个函数能够高效地检测出图像中的人脸。
算法的工作原理可以概括为以下几个步骤:
1. 特征提取:算法首先需要从训练样本中提取特征。这些特征是基于Haar特征的,它们可以被看作是一种卷积核。每个特征的值是通过计算黑色矩形区域的像素值之和减去白色矩形区域的像素值之和得到的。
2. 积分图像:为了提高特征计算的速度,Viola和Jones引入了积分图像的概念。积分图像允许算法在常数时间内计算出任意矩形区域内的像素和,从而大大加快了特征提取的速度。
3. 级联分类器:通过训练,算法会构建一个级联的分类器,这个分类器由多个阶段组成,每个阶段都包含一系列弱分类器。这些弱分类器通常是基于单个或多个Haar特征的。级联分类器的工作方式是,首先通过第一阶段的所有弱分类器,然后是第二阶段,依此类推,直到最后一个阶段。如果一个候选区域通过了所有阶段的检测,那么它就被认为是一个有效的人脸。
4. 多尺度检测:由于人脸在图像中的大小可能不同,Haar级联分类器需要能够在不同的尺度上检测人脸。这是通过在不同的尺度上滑动窗口并应用分类器来实现的。
5. 参数调整:在实际应用中,可以通过调整参数如scaleFactor(尺度因子)和minNeighbors(最小邻居数)来控制检测的精度和速度。scaleFactor决定了在每次图像尺度变化时窗口的大小,而minNeighbors则决定了在当前窗口中需要检测到的最小人脸数量。
Haar级联分类器的优点在于其速度较快,适合实时应用。但它的缺点是检测精度相对较低,容易受到光照、表情和遮挡等因素的影响
## 3.算法实现流程及源码
本算法在实现时使用到了OPENMV H7的摄像头、LED和GPIO共三种外设。
1. import摄像头所需要的sensor库、延时所需要的time库、图像处理所需要的image库、GPIO所需要的pyb库和LED所需要的machine库。
2. 声明一个全局变量calib,用于处理标定
3. 对Sensor进行复位、设置Sensor对比度、设置Sensor增益、设置Sensor捕捉图像大小、设置Sensor输出格式
4. 初始化变量calib为0;初始化标定中点midpoint为0;初始化方向状态变量stat为1,1标志头向左偏,2标志头向右偏;初始化现在中点nowpoint为0。
5. 初始化蓝色LED灯作为头部转向为左(蓝的拼音为Lan,取L,近似为Left)的指示;初始化红色LED灯作为头部转向为右(红的英文为Red,取R,近似为Right)的指示;初始化绿色LED灯作为标定成功的指示。
6. 初始化GPIO P0,设置其为输入;并为其启动中断,触发条件为下降沿触发;绑定中断回调函数,触发时将calib置为1。
7. 初始化GPIO P1和P2,设置其为输出,并设置其电平为低电平。
8. 加载Haar人脸检测模型,然后进行人脸检测
9. 当检测到人脸时,如果calib为1时,说明需要标定,则根据检测到人脸的左坐标和宽度计算得到中点坐标,然后将calib置为0,避免重复标定,然后打开绿色LED灯,用于提示标定成功,延迟5s后关闭绿色LED灯,标定完成。
10. 根据人脸的左坐标和宽度计算得到从此时脸的中点坐标。若此时脸的中点坐标小于等于标定中点坐标且stat等于1,说明脸向右偏,则需要通知处理模块,因此先将LED1关闭,然后打开LED2,将stat置为2,拉低GPIO P1,拉高GPIO P2;若此时脸的中点坐标大于标定中点坐标且stat等于2,说明脸向左偏,则需要通知处理模块,因此先将LED2关闭,然后打开LED1,将stat置为1,拉低GPIO P2,拉高GPIO P2。
具体代码如下所示:
```python
import sensor
import time
import image
import pyb
from machine import LED
global calib
def callback_p0(line):
calib = 1
def main():
sensor.reset()
sensor.set_contrast(8)
sensor.set_gainceiling(16)
sensor.set_framesize(sensor.HQVGA)
sensor.set_pixformat(sensor.GRAYSCALE)
calib = 0
midpoint = 0
stat = 1
nowpoint = 0
led1 = LED("LED_BLUE")
led2 = LED("LED_RED")
led3 = LED("LED_GREEN")
p0_h = pyb.Pin("P0", pyb.Pin.IN)
p1_h = pyb.Pin("P1", pyb.Pin.OUT_PP)
p2_h = pyb.Pin("P2", pyb.Pin.OUT_PP)
p1_h.low()
p2_h.low()
p0_ext = pyb.ExtInt(p0_h, pyb.ExtInt.IRQ_FALLING,
pyb.Pin.PULL_UP, callback_p0)
face_cascade = image.HaarCascade("frontalface", stages=25)
while True:
img = sensor.snapshot()
objects = img.find_features(face_cascade, threshold=1, scale_factor=1.5)
for face in objects:
if(calib):
nowpoint = (face[0]+face[2])/2
calib = 0
led3.on()
pyb.delay(5000)
led3.off()
nowpoint = (face[0]+face[2])/2
if((nowpoint midpoint) and (stat == 2):
led2.off()
led1.on()
stat = 1
p2_h.low()
p1_h.high()
if __name__ == "__main__":
main()
```
## 4.实现效果
向左看,如下图
向右看,如下图
## 5.其他
OPENMV支持将使用OPENCV进行训练的HaarCascade的xml文件转换为所支持的Cascade文件,具体转换脚本代码详见附件。
注意并不是所有的xml文件都能够转换成功,该脚本存在一定的兼容性问题。
## 6.不足及待改进之处
该种方法是通过比较脸部的中点位置与标定中点位置的大小来判断脸部的朝向的。该种办法虽然简便、快捷,但是在进行完一次标定后,只允许脑袋进行转向,若身子发生较大的移动,则相对位置关系被破坏,因此就无法获得正确的判别结果,存在一定限制,需要再次匹配。因此可以考虑使用人脸立体模型来进行匹配,从而解决身子不可移动的问题。
## 7.参考
1. http://www.micropython.com.cn/en/latet/library/pyb.ExtInt.html
2. https://book.openmv.cc/image/sensor.html
3. https://docs.openmv.io/openmvcam/tutorial/gpio_control.html
- 2024-08-31
-
发表了主题帖:
【2024 DigiKey 创意大赛】进度分享
# 【2024 DigiKey 创意大赛】 键鼠统一管家(0) 引言
## 1.背景
在日常工作中,一般使用多台电脑时需要配备相对应的键盘与鼠标,而频繁切换键鼠会非常不便。为了提高效率并减少操作失误,本作品设计了一款智能键鼠系统,使用户只使用一套键鼠就可以轻松控制两台电脑,在一定程度上解决上述问题。该系统利用OPENMV4 CAM H7进行面部朝向检测,判断用户想要操控哪台电脑,然后借助NUCLEO-L476RG开发板将从键鼠获取的数据转发到相应的电脑上,从而实现对多台电脑的无缝切换与控制,简化操作流程,从而大幅提升用户的工作效率和使用体验,旨在帮助用户摆脱复杂的物理连接和繁琐的软件设置,提供一种简单、高效的一体化设备管理方案,提供更加人性化和智能化的工作环境。
## 2.实现方案
### 2.1 硬件结构
硬件连接方式如图所示,OpenMV-H7运行面部朝向算法检测人目前在看哪个屏幕即人脸朝向,然后将朝向结果发送到L476及其他自制板卡上,根据朝向将使用的键盘及鼠标数据转发到对应的电脑上。
### 2.2 软件算法
软件算法流程如图所示:
(1)首先通过摄像头获取图像;
(2)然后将图像转换为灰度图,降低计算量以提高后续检测速度;
(3)使用Haar算子进行人脸检测
(4)然后将得到的人脸根据模板进行拟合,获取眼、鼻子、嘴等器官的位置
(5)然后根据器官的位置进行姿势估计,获得旋转向量
(6)将旋转向量转换为四元数从而获取欧拉角得到朝向。
- 2024-08-13
-
发表了主题帖:
【2024 DigiKey 创意大赛】物料开箱
感谢EEWORLD和Digikey举办的 【2024 DigiKey 创意大赛】,下面是本次使用物料
0. 总览
1. NUCLEO-L476 RG
2. OPENMV4
- 2024-06-12
-
加入了学习《【DigiKey“智造万物,快乐不停”创意大赛】无线ToF室内定位小车》,观看 无线ToF室内定位小车