在数据输出方面,TMF8821具备多区域输出能力,支持3x3、4x4和3x6等多种输出模式,可满足不同场景下对多区域距离信息的需求。同时,它拥有宽广且动态可调的视野,能够灵活适应各种复杂环境。该模块通过I2C接口向外提供距离信息以及置信度值,方便与其他设备进行数据交互。此外,其测量频率可达10Hz,能够快速响应并更新测量数据,确保信息的实时性。
主控模块与dToF传感器之间采用I2C连接方式进行通讯。I2C(Inter - Integrated Circuit)总线是一种简单、双向二线制同步串行总线,它仅需两根线(串行数据线SDA和串行时钟线SCL)即可实现主控与传感器之间的数据传输。这种连接方式具有硬件实现简单、占用资源少、通信效率较高等优点,能够有效保障主控与传感器之间稳定、高效的数据交互。
主要的功能具体内容是将板卡组合后进行固定,并确保其与面前的平面形成一定夹角。通过编写程序,利用dToF模块获取相关数据,进而测算出板卡与屏幕之间的夹角以及垂直方向上的最小距离。这一任务旨在充分发挥dToF模块的测量功能以及主控模块的数据处理能力,实现对特定几何参数的精确测量。
拿到硬件时,一眼便见传感器十分小巧,外围元件寥寥无几。电子森林设计的排母插座与 RP2040 Game Kit 完美贴合。官网虽有 TMF8821 说明文档与 Arduino 例程,可老师突然规定不能用 Arduino,一时犯了难。英文文档读得懵懂,好在知乎有相关驱动文章,参照着各方讲解,艰难地用 micropython 啃起了芯片驱动。

TMF8821可以提供10Hz的测量速度,为解决传感器获得数据跳动问题,使用50组数据进行均值,也就是当传感器稳定5秒,即可计算出距离和角度信息。mpy中不知道如何使用pandas,手工计算矩阵还是挺烦的。
代码
from tmf8821_utility import Tmf8821Utility
from i2c_com import I2C_com, I2C_Settings
from tmf8821_device import Tmf8821Device
from tmf8821_app import Tmf8821App
import utime
import uos
import machine
import st7789 as st7789
from fonts import vga2_8x8 as font1
from fonts import vga1_bold_16x16 as font2
from fonts import vga1_16x32 as font3
import random
import framebuf
import math
#系统的初始化
st7789_res = 0#定义res引脚
st7789_dc = 1#定义dc引脚
disp_width = 240#设置显示屏的宽度
disp_height = 240#设置显示屏的高度
spi_sck=machine.Pin(2)#定义SPI的SCK引脚
spi_tx=machine.Pin(3)#定义SPI的MOSI引脚
spi0=machine.SPI(0,baudrate=4000000, phase=1, polarity=1, sck=spi_sck, mosi=spi_tx)#初始化spi0
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=1)#初始化我们的显示屏幕
display.fill(st7789.BLACK)
# 创建 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() #载入固件 使用3X3测量方式
#获得距离信息
groupnum=30 #均值组个数
allowdev=0.045 #允许偏差值
maxallowdev=0.08 #最大允许偏差
distancegroup=[] #距离信息数组,使用10组数据,后期做均值处理
distanceinfo={"distance":0} #距离信息
def getDistance():
frames = tof.measure_frame(1) # 获取帧数据
distance=[] #距离信息
framelist=[]
if frames:
for idx, frame in enumerate(frames):
# 获取前 9 个测量结果
for result_idx, result in enumerate(frame.results):
if result_idx < 9: # 只取前 9 个
framelist.append(result.distanceInMm)
#调整一下顺序,使数据顺序与实际情况相符
if len(framelist)==9:
distance.append(framelist[6])
distance.append(framelist[7])
distance.append(framelist[8])
distance.append(framelist[3])
distance.append(framelist[4])
distance.append(framelist[5])
distance.append(framelist[0])
distance.append(framelist[1])
distance.append(framelist[2])
if len(distancegroup)>=groupnum:
distancegroup.pop(0)
distancegroup.append(distance)
#显示距离信息
def dispDistance(offstat):
if len(distancegroup)==groupnum:
distance=[0,0,0,0,0,0,0,0,0] #计算一个均值矩阵 3X3
for pos in range(9):
for i in range(groupnum):
distance[pos]=distance[pos]+distancegroup[i][pos]
for pos in range(9):
distance[pos]=distance[pos]/groupnum
#串口显示 和 屏幕显示
for i in range(3):
for j in range(3):
print("%.1f" % (distance[i*3+j]), end=' ')
if offstat==0:
display.text(font2, "%3.0f" % (distance[i*3+j]/10), i*70+30, j*25+10,color=st7789.GREEN) #使用CM做单位
elif offstat==1:
display.text(font2, "%3.0f" % (distance[i*3+j]/10), i*70+30, j*25+10,color=st7789.YELLOW) #使用CM做单位
else:
display.text(font2, "%3.0f" % (distance[i*3+j]/10), i*70+30, j*25+10,color=st7789.RED) #使用CM做单位
print()
print()
print()
#当所有距离 小于偏差时 返回0 大于偏差小于最大偏差时 返回1 否则返回9
def distanceIsStand():
if len(distancegroup)>=groupnum:
distance=[0,0,0,0,0,0,0,0,0] #计算一个均值矩阵 3X3
for pos in range(9):
for i in range(groupnum):
distance[pos]=distance[pos]+distancegroup[i][pos]
for pos in range(9):
distance[pos]=distance[pos]/groupnum
#print(distancegroup)
#print(distance)
groupavg=sum(distance)/9 #距离均值
groupoffset=groupavg*allowdev #计算偏差值
maxgroupoffset=groupavg*maxallowdev #计算偏差值
print("offset %.1f,%.1f,%.1f" %(groupavg,groupoffset,maxgroupoffset))
#检查平均组里的每个数据 是否是落在偏差值内
echoval=0
for idx in range(9):
if abs(distance[idx]-groupavg)>maxgroupoffset :
distanceinfo["distance"]=0 #偏差太大时就 不可信距离值
distanceinfo["angle"]=0
return 9
if abs(distance[idx]-groupavg)>groupoffset:
echoval=1
#依据偏差值的结果来计算距离和角度
if echoval==0 : #当偏差小于指定值时,就取中心点的距离为距离
if distanceinfo["distance"]==0:
distanceinfo["distance"]=distance[4]
distanceinfo["angle"]=0
else:
if distanceinfo["distance"]<distance[4]:
distanceinfo["angle"]=math.degrees(math.acos(distanceinfo["distance"]/distance[4]))
else:
distanceinfo["distance"]=distance[4]
distanceinfo["angle"]=0
elif echoval==1 : #当偏差值较小,则计算偏角
if distanceinfo["distance"]<distance[4]:
distanceinfo["angle"]=math.degrees(math.acos(distanceinfo["distance"]/distance[4]))
else:
distanceinfo["angle"]=0
return echoval
#显示距离和角度信息
def dispinfo(offstat):
if offstat==0:
display.text(font3, "%3.0f CM" % ((distanceinfo["distance"])/10), 120, 100,color=st7789.GREEN) #使用CM做单位
display.text(font2, " DIST: " , 10, 105,color=st7789.WHITE)
display.text(font3, "%3.0f " % (distanceinfo["angle"]), 120, 160,color=st7789.GREEN)
display.text(font2, "ANGLE: " , 10, 160,color=st7789.WHITE)
elif offstat==1:
display.text(font3, "%3.0f CM" % ((distanceinfo["distance"]+5)/10), 120, 100,color=st7789.YELLOW) #使用CM做单位
display.text(font2, " DIST: " , 10, 105,color=st7789.WHITE)
if distanceinfo["angle"]==0:
display.text(font3, "---", 120, 160,color=st7789.YELLOW)
display.text(font2, "ANGLE: " , 10, 165,color=st7789.WHITE)
else:
display.text(font3, "%3.0f " % (distanceinfo["angle"]), 120, 160,color=st7789.YELLOW)
display.text(font2, "ANGLE: " , 10, 165,color=st7789.WHITE)
else:
display.text(font3, "--- " , 120, 100,color=st7789.RED) #使用CM做单位
display.text(font2, " DIST: " , 10, 105,color=st7789.WHITE)
display.text(font3, "---", 120, 160,color=st7789.YELLOW)
display.text(font2, "ANGLE: " , 10, 165,color=st7789.WHITE)
while True:
getDistance()
offstat=distanceIsStand()
print("echo= ",offstat)
dispDistance(offstat)
#如果计算距离小于预期偏差,则显示距离信息 以均值为距离信息,并且开始计算
dispinfo(offstat)
#print("distanceval=",distanceinfo)
utime.sleep_ms(100) # 延迟 1 秒,便于查看每次显示实现效果
由于使用了50组数据做的均值,所以系统反应是比较缓慢的,需要缓慢移动,直至数据不再跳动,再继续旋转。

小角度旋转,测量角度开始变化。小角度变化,感觉还是比较准确。

我要赚赏金
