【得捷电子Follow me第2期】手势识别极简实现&光线传感器数据记录
[复制链接]
本帖最后由 夷则玖 于 2023-11-6 14:32 编辑
//内容一:3-5分钟短视频//
视频链接:得捷电子Follow me第2期 活动视频-得捷电子Follow me第2期-EEWORLD大学堂
//内容二: 任务/项目总结报告//
1. 项目介绍
"Follow me活动”是DigiKey联合EEWORLD发起的为期一年的“跟技术大咖学技术,完成任务返现”活动。2023年共有4期,每3个月技术大咖推荐可玩性与可学性较强的开发板/仪器套件,带着大家实际操作。
本次活动使用Adafruit ESP32-S3 TFT Feather 开发板,使用Circuit Python语言实现。
2. 各任务功能对应的主要代码片段、说明及展示
任务①:控制屏幕显示中文
任务要求:完成屏幕的控制,并且能显示中文 器件:Adafruit ESP32-S3 TFT Feather
代码:
- import board
- import displayio
- import adafruit_imageload
- from adafruit_display_text import label
- from adafruit_bitmap_font import bitmap_font
-
首先导入必要的库和包,其中 adafruit_imageload 用于显示图片,本任务可不必实现。
-
- display = board.DISPLAY
-
- group = displayio.Group()
-
- font = bitmap_font.load_font("/font/Slidexiaxing-32.pcf")
-
- color = 0x000000
-
显示字体必备的语句。
-
- image, palette = adafruit_imageload.load("/images/yuanshen.png")
-
- palette.make_transparent(1)
-
- grid = displayio.TileGrid(image, pixel_shader=palette)
-
- group.append(grid)
显示图片,注意adafruit_imageload.load中路径,对于部分图片 make_transparent 可能不需要
-
- text1 = label.Label(font, text="将进酒", color=color)
-
- text1.x = 0
- text1.y = 15
-
- group.append(text1)
-
- text2 = label.Label(font, text="杯莫停", color=color)
- text2.x = 0
- text2.y = 120
- group.append(text2)
-
- display.show(group)
-
- while True:
- pass
添加文本标签并保持屏幕显示,每次更新文本都需要执行display.show(group)以刷新显示
显示效果:
显示中文需要自建字库,字库的建立参考了交流群大佬们的帖子,在此表示感谢。
任务②网络功能使用(必做任务)
任务要求:完成网络功能的使用,能够创建热点和连接到WiFi 器件:Adafruit ESP32-S3 TFT Feather
首先,连接到WiFi只需要配置“settings.toml”文件即可
-
- CIRCUITPY_WIFI_SSID = "需要连接的WIFI的名称"
-
- CIRCUITPY_WIFI_PASSWORD = "需要连接的WIFI的密码"
-
- CIRCUITPY_WEB_API_PASSWORD = "设置你的web端密码"
-
- CIRCUITPY_WEB_API_PORT = 80
需要注意的是CIRCUITPython提供了WEB访问的功能,CIRCUITPY_WEB_API_PASSWORD 语句所设置的,就是你在网页输入开发板IP地址后,提示你输入的密码。(交流群有过的疑问,在此唠叨一下)
然后,创建热点:
- import os
- import time
- import ssl
- import wifi
- import socketpool
- import microcontroller
- import adafruit_requests
首先是导包
-
- wifi.radio.start_ap("ESP32-WIFI", "00000000")
-
- print("SSID: ESP32-WIFI")
- print("PASSWORD: 00000000")
-
- while True:
- pass
这个很简单,官方文档和乔老师的例程都已经很详细了
效果:
屏幕显示了ip地址,连接上了网络
开启热点
连接上所创建的热点,可以看到获取到了IP地址
以上就是网络功能的使用,得益于CIRCUITPython,使得联网十分便捷
任务③:控制WS2812B(必做任务)
任务要求:使用按键控制板载Neopixel LED的显示和颜色切换 器件:Adafruit ESP32-S3 TFT Feather
代码:
- import time
- import board
- import neopixel
- import digitalio
- from rainbowio import colorwheel
首先是导包,circuitpython,提供了neopixel库,可以很方便地实现RGB的控制,如色轮的多种显示效果
-
- power = digitalio.DigitalInOut(board.NEOPIXEL_POWER)
- power.direction = digitalio.Direction.OUTPUT
- power.value = True
-
- pixel = neopixel.NeoPixel(board.NEOPIXEL, 1)
-
- pixel.brightness = 0.5
然后是neopixel led的配置
-
- button = digitalio.DigitalInOut(board.BUTTON)
- button.switch_to_input(pull=digitalio.Pull.UP)
- status = 1
-
- def rainbow(delay):
- for color_value in range(255):
- pixel[0] = colorwheel(color_value)
- time.sleep(delay)
-
- def trans():
- global status
- if status == 5:
- status = 1
- else:
- status = status + 1
配置按键相关的功能
-
- def RGB():
- global status
- if status == 5:
- print("rainbow")
- rainbow(0.02)
- elif status == 4:
- pixel[0] = 0,0,255
- print("BLUE")
- elif status == 3:
- pixel[0] = 0,255,0
- print("GREEN")
- elif status == 2:
- pixel[0] = 255,0,0
- print("RED")
- else:
- pixel[0] = 0,0,0
- print("OFF")
-
- while True:
- if not button.value:
-
- time.sleep(0.2)
- trans()
- RGB()
- else:
- pass
根据按键次数,循环切换显示效果,time.sleep()是为了去除按键抖动,防止响应过快。
效果:
按键控制NeoPixel LED
④分任务3:数据检测与记录——
要求:按一定时间间隔连续记录温度/亮度信息,保存到SD卡,并可以通过按键调用查看之前的信息,并在屏幕上绘图
搭配器件:Adafruit ESP32-S3 TFT Feather、光传感器、微型 SD卡模块
代码:
由于本任务较难,代码冗杂,故只放出关键代码,完整代码在文末。
记录数据部分代码:
-
- if (i==0 and j==3):
-
- record.text="recording"
- display.show(menu2)
- print("write")
-
- with open("/sd/test.txt", "w") as f:
- stop = True
-
- while stop:
- f.write(str(analog_pin.value))
- f.write("\r\n")
- time.sleep(0.5)
- key = keyvalue()
- if key!= None:
- time.sleep(0.2)
- i,j = key
- key = None
- if (i==1 and j==3):
- print("end")
-
- stop = False
-
- record.text="recorded"
- display.show(menu2)
- else:
-
- pass
- elif(i==2 and j==3):
-
- condition2 = False
- else:
- pass
此段代码实现了数据记录的开始与停止,理论上可以无限制地记录数据但受限于屏幕的像素以及有限的功能,建议只记录10s以内的数据。
绘图代码段:
-
- elif (i==1 and j==3):
-
- print("read")
- with open("/sd/test.txt", "r") as f:
- print("Calculate total lines in file:")
- total = 0
- for line in f:
- total = total +1
- print("total:",total)
-
- delta = math.floor(240/total)
- print("delta:",delta)
-
- dot_list=[]
- with open("/sd/test.txt", "r") as f:
- print("Printing lines in file:")
- for line in f:
- dot_list.append(int(line))
- print("listcomplete")
-
- maxdot = max(dot_list)
-
- index = 0
- for item in dot_list:
- dot_list[index] = math.floor((item/maxdot)*134)
- index = index +1
-
- x=0
- y=135
- axisx = delta
- for n in range(1,total):
-
- line = Line(x0=x, y0=y, x1=axisx, y1=134-dot_list[n], color=0x00FF00)
- x=axisx
- y=134-dot_list[n]
- axisx = axisx + delta
- shape_group.append(line)
-
- display.show(shape_group)
- condition3 = True
-
- while condition3:
- key = keyvalue()
- if key!= None:
- time.sleep(0.2)
- condition3 = False
以上是绘图代码段,实现了图像均匀分布在屏幕上,可避免光线较弱时,图像变化不明显的问题
绘图效果:
分任务5:AI功能应用
任务要求:结合运动传感器,完成手势识别功能,至少要识别三种手势(如水平左右、前后、垂直上下、水平画圈、垂直画圈,或者更复杂手势
器件:Adafruit ESP32-S3 TFT Feather、运动传感器
代码:
- import time
- import math
- import board
- import digitalio
- import adafruit_lis3dh
导包
-
- i2c = board.I2C()
- lis3dh = adafruit_lis3dh.LIS3DH_I2C(i2c)
-
- def recognize_gesture(axi):
- if axi == 1:
- print("left&right")
- elif axi == 2:
- print("front&back")
- elif axi == 3:
- print("up&down")
- else:
- time.sleep(0.01)
-
- init = lis3dh.get_init()
-
前置代码
- while True:
- axis=lis3dh.decide(threshold= 1.0,init_accel= init,wait = 0.3)
- recognize_gesture(axis)
while循环,不断判断加速度改变量是否超出范围threshold,设定的threshold越大则需要越大的加速度才能响应,反之亦然。如果没有超出范围则lis3dh.decide返回数值0,超出范围则返回变化最大的轴,以此判断手势。
- def get_init(
- self, count: int=10, delay: float = 0.1
- ) -> tuple:
- init_accel = (0,0,0)
- for _ in range(count):
- init_accel = tuple(map(sum, zip(init_accel, self.acceleration)))
- time.sleep(delay / count)
- return tuple(value / count for value in init_accel)
在adafruit_lis3dh库中添加如上函数,以获取初始加速度值,参数count是取数据的总数,delay是函数总的延迟。每隔delay/count秒读取一个数据并累加,再取平均值,然后返回一个包含各轴初始加速度元组
- def decide(
- self,threshold:float = 1.1,init_accel: tuple = (1,1,9),wait:float = 0.2
- ) -> int:
- delta_accel = tuple(map(lambda x,y:abs(abs(x-y)-threshold) ,init_accel,self.acceleration))
- ifintsh= tuple(map(lambda x : x < threshold,delta_accel))
- time.sleep(wait)
- if ifintsh[0] == ifintsh[1] == ifintsh[2] == True:
- return 0
- else:
- return delta_accel.index(max(delta_accel)) + 1
在adafruit_lis3dh库中添加如上函数,delta_accel 得到的返回是当前加速度和初始加速的差的绝对值。ifintsh 是一个三元素元组,存储三个布尔值,分别代表x,y,z轴是否超出设定的threshold。如果三轴的变化均没有超出设定范围,则返回零,如果超出范围,则返回delta_accel中的最大值的序号加1。
效果:
这个手势识别的精度有限,本应对加速度求微分再进一步判断手势,由于本人高数水平有限,暂时没能进一步优化,后续水平提高之后再优化一下。
3. 对本活动的心得体会
致谢:
首先,感谢eeworld和digikey,没有你们我就没法参加此次活动,也就没法学到这么多东西;
其次,感谢@HonestQiao 乔老师精心制作的教程以及简明的例程,带我走进了circuitpython的世界;
最后,感谢社区的所有小伙伴,一路走来你们让我不觉得孤独。
收获:
本次活动我学习了circuitpython的开发,见识到了它的便捷性,同时也加深了我对python的理解。在不断学习和探索的过程中激发了我的创造力。
建议
但同时circuitpython的中文资源较少,少有的一个中文站也只是对英文文档的翻译,并不能适应国人的开发习惯,建议官方或者有能力的组织或个人合作起来,完善circuitpython的生态。
//内容三:可编译下载的代码//
打包后的链接:
【得捷电子Follow me第2期】代码-夷则玖
|