1. 项目介绍
本项目基于RP2040游戏机板卡,搭配的TMF8821 dToF传感器,使用eetree官方提供的rp2040 micropython固件, 使用micropython编写程序。程序从TMF8821 dToF传感器读取到3*3的距离信息,根前后两帧距离信息的差值来判断手势的方向。而后将信息通过ST7789的spi接口将手势的方向转换成菜单上的移动,实现简易的手势识别的功能。
2. 设计思路
本次项目目标主要分为两个部分,即通过RP2040读取TMF8821 dToF传感器信息和显示信息到液晶显示器。
- 使用micropython配置并驱动TMF8821 dTof传感器,配置传感器为3*3模式,读取距离信息;
- 计算前后数据帧的插值,判断出手势的移动方向;
- 配置液晶显示屏,绘制一个简单的菜单;
- 将手势移动方向和菜单关联,手势的移动转换成菜单条目的移动。
3. 硬件介绍
3.1 RP2040游戏机板卡介绍
RP2040 Game Kit是基于树莓派RP2040的嵌入式系统学习平台,USB Type-C供电,采用RP2040作为主控,支持MicroPython、C/C++编程,性能强大。
板上功能:
- 240*240分辨率的彩色IPS LCD,SPI接口,控制器为ST7789
- 四向摇杆 + 2个轻触按键 + 一个三轴姿态传感器MMA7660用做输入控制
- 板上外扩2MB Flash,预刷MicroPython的UF2固件
- 一个红外接收管 + 一个红外发射管
- 一个三轴姿态传感器MMA7660
- 一个蜂鸣器
- 双排16Pin连接器,有SPI、I2C以及2路模拟信号输入
游戏机可玩性极高,可移植多款复古游戏,还可作为电赛的控制、显示接口平台,搭配传感器、模拟电路外还可以完成更多创意项目。该主板的功能框图如下:
有关树莓派RP2040游戏机的详细介绍及原理图,可点击链接查看。
3.2 TMF8821 dToF传感器介绍
dToF模块是基于 TMF8821 设计的直接飞行时间 (dToF) 传感器模块,TMF8821采用单个模块化封装,带有相关的 VCSEL(垂直腔面发射激光器)。dToF 设备基于 SPAD、TDC 和直方图技术,可实现 5000 mm 的检测范围。由于它的镜头位于 SPAD 上,它支持 3x3、4x4 和 3x6 多区域输出数据以及宽广的、动态可调的视野。VCSEL 上方的封装内的多透镜阵列 (MLA) 拓宽了 FoI(照明场)。原始数据的所有处理都在片上进行,TMF8821在其 I2C 接口上提供距离信息和置信度值。
TMF8821具有以下的特点
- 具有高灵敏度SPAD检测的Direct ToF技术
- 4x4 可配置的多区域配置,具有多目标检测功能
- 可调视野(最大63°对角线)
- 快速时间数字转换器(TDC)架构
- 亚纳秒级光脉冲
- 10 – 5000mm 距离感应 @30Hz
- 片上直方图处理
- 940nm VCSEL 1类人眼安全
- 高性能片上阳光阻隔滤波器和算法
- 小型模块化OLGA 2.0mm x 4.6mm x 1.4mm封装
TMF8821的参数如下图
3.3 硬件的连接
TMF8821 dToF传感器模块与RP2040游戏机管脚匹配,插上直接可以使用,并在侧面预留了扩展接口,可以自由焊接/调试/抓取数据。
4.软件架构
项目的模块功能如下图:
软件流程图如下:
5.软件代码
from tmf8821_utility import Tmf8821Utility
from com.i2c_com import I2C_com, I2C_Settings
from tmf8821_device import Tmf8821Device
from tmf8821_app import Tmf8821App
import utime
import math
from machine import Pin, SPI
import test.st7789 as st7789
from test.fonts import vga2_8x8 as font1
from test.fonts import vga1_16x32 as font2
st7789_res = 0
st7789_dc = 1
disp_width = 240
disp_height = 240
CENTER_Y = int(disp_width/2)
CENTER_X = int(disp_height/2)
spi_sck=Pin(2)
spi_tx=Pin(3)
spi0=SPI(0,baudrate=4000000, phase=1, polarity=1, sck=spi_sck, mosi=spi_tx)
display = st7789.ST7789(spi0, disp_width, disp_width,
reset=machine.Pin(st7789_res, machine.Pin.OUT),
dc=machine.Pin(st7789_dc, machine.Pin.OUT),
xstart=0, ystart=0, rotation=0)
display.fill(st7789.BLACK)
display.text(font2, "EETREE", 10, 10)
#display.text(font1, "www.eetree.cn", 80, 20)
# 创建 I2C 通信对象
ic_com = I2C_com()
# 创建 Tmf8821Utility 实例
tof = Tmf8821Utility(ic_com)
if Tmf8821App.Status.OK != tof.open():
tof.error("Error open FTDI device")
raise RuntimeError("Error open FTDI device")
else:
tof.log("Opened connection")
tof.init_bootloader_check()
init_frame_data = []
menu_pos = 0
def get_direction(diff):
#print(diff)
global menu_pos
h_diff = diff[2] - diff[0]
v_diff = diff[6] - diff[0]
if diff[0] > 100:
print("down")
if menu_pos == 0:
menu_pos = 1
return True
elif diff[0] < 100 and diff[0] > 20:
print("up")
if menu_pos == 1:
menu_pos = 0
return True
return False
def update_meun():
global menu_pos
if menu_pos == 0:
display.text(font2, "-> item1", 10 , 70 )
display.text(font2, " item2", 10 , 110)
else:
display.text(font2, " item1", 10 , 70)
display.text(font2, "-> item2", 10 , 110)
while True:
frames = tof.measure_frame(1) # 获取1帧数据
if frames:
for idx, frame in enumerate(frames):
frame_data = []
# 获取前测量结果
for idx, data in enumerate(frame.results):
if idx < 9:
frame_data.append(data.distanceInMm)
#display.text(font2, "%04d" %(data.distanceInMm) , 10 + int(idx%3)*80, 70 + int(idx/3)*40)
else:
break
if len(init_frame_data) == 0:
init_frame_data = frame_data
continue
diff = [init_frame_data[i] - frame_data[i] for i in range(0, len(frame_data))]
#print(diff)
if get_direction(diff) == True:
init_frame_data = []
else:
init_frame_data = frame_data
update_meun()
else:
print("no data received.")
utime.sleep_ms(50) # 延迟
6.总结与展望
本次项目使用micropython语言,得益于python语言的易用性使得开发难度得到一定的降低。配合官方设计的RP2040游戏机板卡使得硬件稳定可靠。在开发过程中也遇到了很多的问题,例如驱动TMF8821 dToF传感器,好在github上有TMF8828的micropython驱动,仅需要移植到rp2040游戏机板卡上就能正常的工作,使得开发变得轻松许多。
总体而言,这次竞赛让我对传感器数据抽象成实际的动作有了一定的认识和了解,但同时也发现从数据转化到稳定可靠的动作并不是一个简简单单的事情。
最后再次感谢官方的活动,让开发者在学习中进步,在项目中锻炼!