lzhan 发表于 2024-10-31 23:34

【2024 DigiKey 创意大赛】 键鼠统一管家——作品提交

本帖最后由 lzhan 于 2024-11-1 13:40 编辑

<div><strong>键鼠统一管家</strong></div>

<div>作者:lzhan</div>

<div><strong>一、作品简介</strong></div>

<div>本项目为键鼠统一管家,其中使用NUCLEO-L476RG开发板作为主控板,负责与OPENMV H7、自制PCB进行通信,同时作为USB Host用于驱动用户端的键盘和鼠标;OPENMV H7用于采集图像并进行处理,来判断人脸的朝向,将结果上报给主控板;自制PCB包含两个USB Device,根据朝向判决结果,将键鼠数据转发到对应的PC主机上。</div>

<div>设备展示</div>

<div></div>

<div></div>

<div>该产品所使用的物料如下:</div>

<table border="1">
        <tbody>
                <tr>
                        <td>物料名称</td>
                        <td>型号</td>
                        <td>功能</td>
                </tr>
                <tr>
                        <td>OPENMV模组</td>
                        <td>OPENMV CAM H7</td>
                        <td>采集图像、面部朝向判断</td>
                </tr>
                <tr>
                        <td>STM32</td>
                        <td>NUCLEO-L476RG</td>
                        <td>USB Host、主控板</td>
                </tr>
                <tr>
                        <td>STM32</td>
                        <td>STM32F070</td>
                        <td>USB Device</td>
                </tr>
        </tbody>
</table>

<div><strong>二、系统框图</strong></div>

<div>该系统的整体框图如下所示。每个PC电脑各有一个显示器,并排成一定夹角放在一起,将该系统放在两个显示器之间。OPENMV H7和NUCLEO-L476RG都是使用USB各自独立进行供电,自制PCB由NUCLEO-L476RG进行供电。</div>

<div></div>

<div><strong>三、各部分功能说明</strong></div>

<div>OPENMV H7开发板用来实现人脸检测,并根据人脸中心位置与预设标定位置的比较来判断人脸朝向。</div>

<div>当人脸朝左时,蓝色LED亮,同时拉高GPIO P1为高电平,拉低GPIO P2为低电平。</div>

<div></div>

<div>当人脸朝右时,红色LED亮,同时拉高GPIO P2为高电平,拉低GPIO P1为低电平。</div>

<div></div>

<div>OPENMV H7在实现时使用到了OPENMV H7的摄像头、LED和GPIO共三种外设。其实现过程如下:</div>

<ol>
        <li>import摄像头所需要的sensor库、延时所需要的time库、图像处理所需要的image库、GPIO所需要的pyb库和LED所需要的machine库。</li>
        <li>对Sensor进行复位、设置Sensor对比度、设置Sensor增益、设置Sensor捕捉图像大小、设置Sensor输出格式</li>
        <li>初始化标定中点midpoint为0;初始化方向状态变量stat为1,1标志头向左偏,2标志头向右偏;初始化现在中点nowpoint为0。</li>
        <li>初始化蓝色LED灯作为头部转向为左(蓝的拼音为Lan,取L,近似为Left)的指示;初始化红色LED灯作为头部转向为右(红的英文为Red,取R,近似为Right)的指示。</li>
        <li>初始化GPIO P1和P2,设置其为输出,并设置其电平为低电平。</li>
        <li>加载Haar人脸检测模型,然后进行人脸检测。当检测到人脸时,根据人脸的左坐标和宽度计算得到从此时脸的中点坐标。若此时脸的中点坐标小于等于标定中点坐标且stat等于1,说明脸向右偏,则需要通知处理模块,因此先将LED1关闭,然后打开LED2,将stat置为2,拉低GPIO P1,拉高GPIO P2;若此时脸的中点坐标大于标定中点坐标且stat等于2,说明脸向左偏,则需要通知处理模块,因此先将LED2关闭,然后打开LED1,将stat置为1,拉低GPIO P2,拉高GPIO P2。</li>
</ol>

<div>代码如下:</div>

<div>
<pre>
<code class="language-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+face)/2
      calib = 0
      led3.on()
      pyb.delay(5000)
      led3.off()
    nowpoint = (face+face)/2
    if((nowpoint &lt;= midpoint) and (stat == 1)):
      led1.off()
      led2.on()
      stat = 2
      p1_h.low()
      p2_h.high()
    elif(nowpoint&gt;midpoint) and (stat == 2):
      led2.off()
      led1.on()
      stat = 1
      p2_h.low()
      p1_h.high()</code></pre>

<p>&nbsp;</p>
</div>

<div>
<p>NUCLEO-L476RG开发板用于实现USB Host,操作键鼠一体USB接收器,将USB HID报文中的数据转发到SPI输出。根据OPENMV的GPIO的电平进行处理:若GPIO1的电平为高,则说明此时人脸是朝向左侧的,此时对应左侧电脑的SPI slave (STM32F070,实现左测电脑的USB输入设备)片选信号置为有效,HID报文数据被SPI slave接收后通过USB端点发送出去;若GPIO2的电平为高,则说明此时人脸是朝向右侧的,另一个SPI slave的片选信号有效,HID报文被转发到另一个USB设备发出。</p>

<p>如果键盘鼠标是独立的(要两个USB口),则需要增加一个USB host来处理,就需要再用一块STM32L476或类似的带USB-OTG设备的MCU,将其收到的HID报文发送给主控的STM32L476. 因为大赛物料成本的限制,手上又有无线键鼠套装,就只用了一个USB host.&nbsp;</p>
</div>

<div>部分主要代码如下:</div>

<div>
<pre>
<code class="language-objectivec">int main(void)
{
    gpio_config();
    GPIOB-&gt;OSPEEDR = 2&lt;&lt;30|2&lt;&lt;28|2&lt;&lt;26;
    FLASH-&gt;ACR = FLASH_ACR_ICEN|FLASH_ACR_DCEN|FLASH_ACR_PRFTEN
            |2&lt;&lt;FLASH_ACR_LATENCY_Pos; // 2 wait states, 32~48MHz
    clk_config(); // without this, default SYSCLK is 4MHz
    uart_setup();
    if((RCC-&gt;CFGR &amp; RCC_CFGR_SWS_Msk)!=RCC_CFGR_SWS_PLL)
    {
        uart_wstr("Clock setting to PLL failed. ");
    }
    spi_setup();
    usb_setup();
    RCC-&gt;APB1ENR1 |= RCC_APB1ENR1_TIM6EN;
    __NOP();    
    TIM6-&gt;PSC = 479;    // prescale to 100kHz
    TIM6-&gt;EGR = TIM_EGR_UG;     // generate update
    TIM6-&gt;SR = 0;   // clear interrupt flag
    TIM6-&gt;DIER = TIM_DIER_UIE;  // enable Interrupt
    NVIC_EnableIRQ(TIM6_DAC_IRQn);
    while(1)
    {
        __WFI();
    }
}</code></pre>

<p>&nbsp;</p>
</div>

<div>自制PCB是一个两层板,其主要包含两个F070,用于作对应两台PC电脑的USB Device,其通过两个SPI与NUCLEO-L476RG相连接,接收转发的对应的USB数据,然后对应主机从中获得对应的数据,从而完成一套键鼠控制两台电脑的功能。</div>

<div></div>

<div>PCB顶层</div>

<div></div>

<div>PCB底层</div>

<div>部分主要代码如下:</div>

<div>
<pre>
<code class="language-objectivec">int main(void)
{
    int i;
    RCC-&gt;APB2ENR |= RCC_APB2ENR_SYSCFGEN|RCC_APB2ENR_SPI1EN;
    gpio_config();
    FLASH-&gt;ACR=FLASH_ACR_PRFTBS|FLASH_ACR_PRFTBE|FLASH_ACR_LATENCY;
    SYSCFG-&gt;CFGR1 |= SYSCFG_CFGR1_PA11_PA12_RMP;
    clock_setup();
    config_spi_slave();
    uart_setup();
    uart_whex(SPI1-&gt;CR2);
    uart_wstr(" F070 test\r\n");
    NVIC_EnableIRQ(SPI1_IRQn);
    RCC-&gt;APB1ENR |= RCC_APB1ENR_USBEN;
    USB-&gt;CNTR &amp;= ~1;    // remove PDWN
    delay_ms(1);
    USB-&gt;CNTR = 0;  // no reset
    USB-&gt;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-&gt;BCDR = USB_BCDR_DPPU;  // pull-up resistor enable
    while(1)
    {
        static char row=0;
        __WFI();
        if(ep0_state &amp; 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-&gt;bmRequestType);
                    uart_wstr(" Request ");
                    uart_whexb(ep0_std_req-&gt;bRequest);
                    uart_wstr(" Val ");
                    uart_whexh(ep0_std_req-&gt;wValue);
                    uart_wstr(" Ind ");
                    uart_whexh(ep0_std_req-&gt;wIndex);
                    uart_wstr(" Len ");
                    uart_whexh(ep0_std_req-&gt;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 &amp;&amp; ep0_state==0)
            {
                USB-&gt;DADDR = USB_DADDR_EF|usb_address;
                usb_address=0;
            }
        }
    }
}</code></pre>

<p>&nbsp;</p>
</div>

<div><strong>四、作品源码</strong></div>

<div>源码已经上传到下载中心,</div>

<div>图像处理代码:<a href="https://download.eeworld.com.cn/detail/lzhan/634859">download.eeworld.com.cn/detail/lzhan/634859</a></div>

<div>USB Host、Device代码:<a href="https://download.eeworld.com.cn/detail/lzhan/634869">download.eeworld.com.cn/detail/lzhan/634869</a></div>

<div><strong>五、作品功能演示视频</strong></div>

<div>以下是我的作品演示:</div>

<div>
<p><a href="https://training.eeworld.com.cn/course/68764/learn?preview=1#lesson/41505" style="color:blue; text-decoration:underline">键鼠统一管家 - 键鼠统一管家 - EEWORLD大学堂</a></p>
</div>

<div><strong>六、项目总结</strong></div>

<div>我本人非常荣幸能够参加本次大赛,通过这次大赛,让我能够有机会使用到OPENMV H7来完成项目,我从中学习到了如何使用MicroPython方法来进行嵌入式的开发与调试。感谢@cruelfox 为作品提供的USB部分实现的技术支持。</div>

<div>由于平时事情比较繁琐,因此项目做的较为仓促,图像处理算法的复杂度一降再降。目前还存在以下的问题:只允许脑袋进行转向,若身子发生较大的移动,则相对位置关系被破坏,因此就无法获得正确的判别结果,存在一定限制。</div>

<div>帖子分享汇总:</div>

<div>【2024 DigiKey 创意大赛】物料开箱 <a href="https://bbs.eeworld.com.cn/thread-1290478-1-1.html">https://bbs.eeworld.com.cn/thread-1290478-1-1.html</a></div>

<div>【2024 DigiKey 创意大赛】进度分享 <a href="https://bbs.eeworld.com.cn/thread-1292099-1-1.html">https://bbs.eeworld.com.cn/thread-1292099-1-1.html</a></div>

<div>【2024 DigiKey 创意大赛】 键鼠统一管家(1) 软件算法及实现 <a href="https://bbs.eeworld.com.cn/thread-1297454-1-1.html">https://bbs.eeworld.com.cn/thread-1297454-1-1.html</a></div>

<div>【2024 DigiKey 创意大赛】 键鼠统一管家(2) OPENMV调试 <a href="https://bbs.eeworld.com.cn/thread-1297816-1-1.html">https://bbs.eeworld.com.cn/thread-1297816-1-1.html</a></div>

<div>【2024 DigiKey 创意大赛】 键鼠统一管家(3) 扩展板制作 https://bbs.eeworld.com.cn/thread-1297918-1-1.html</div>

<div><strong>七、其他</strong></div>

<div>附件为word版文档</div>

<p><!--importdoc--></p>

秦天qintian0303 发表于 2024-11-1 11:22

<p>一套键鼠控制两个电脑,创意不错&nbsp; &nbsp;</p>
页: [1]
查看完整版本: 【2024 DigiKey 创意大赛】 键鼠统一管家——作品提交