- 项目介绍
2024艾迈斯欧司朗dToF传感器光电设计竞赛是由艾迈斯欧司朗赞助硬禾科技举办。本次项目,首先编译适配了RP2040游戏机套件的CircuitPython 镜像,依托开源的TMF8821 dToF传感器驱动,实现在RP2040游戏机套件上进行使用TMF8821 dToF传感器 进行被测平面的 与 设备间夹角的动态变化。
-使用到的硬件介绍
树莓派RP2040游戏机套件 和 TMF8821 dToF传感器模块.
树莓派RP2040游戏机套件,不仅拥有丰富的传感器,还带有屏幕和案件,背面还有扩展接口。方便扩展
dToF模块是基于 TMF8821 设计的直接飞行时间 (dToF) 传感器模块,TMF8821采用单个模块化封装,带有相关的 VCSEL(垂直腔面发射激光器)
- 方案框图和项目设计思路介绍
几何抽象
- 传感器会获得 三个到平面的距离 OA OB OC,
- 根据数据手册,可以知道∠AOC为32°,且 ∠AOB = ∠BOC,∴ ∠AOB = ∠BOC=16°
- 传感器垂直固定于底板,所以OB⊥OM,三角形OMB是直角三角形
- ∠OMB的角度就是 开发板与墙面的夹角(OA 和 OC 中较短的 会和墙面形成夹角)
- ∠BOM 在 三角形 AOB 中
- 三角形 AOB 中 已知了OA 和 OB的长,∠AOB =16
- 第一次三角函数,三角形 AOB 中,计算 AB 长度
- 第二次三角函数,三角形 AOB 已知三边长,计算∠BOM 度数
- 在直角三角形OMB中,∠OMB = 90 - ∠BOM
主要实现的方案逻辑如下
- 传感器获取三个角度的到被测平面的距离
- 利用几何余弦定理,计算角度
具体设计和实现步骤
- 适配了树莓派RP2040游戏机 的CircuitPython(以下称 CPY) 固件
- 找到了合适的CPY 驱动
- 两次 余弦定理计算夹角
- 屏幕输出实时计算结果
- 软件流程图和关键代码介绍
- lib是主要驱动库和依赖库
- main文件是入口文件
- consie_law 是 余弦定理函数
- i2c_0 不是项目必须文件( 因为开发有2路I2C,项目中使用的是GP16/17)
主要代码:
- consie_law.py
import math
def calculate_angle_A(a, b, C_deg= 16):
"""
计算三角形的角 A,给定边 a, b 和夹角 C(度数)。
参数:
a (float): 边 a 的长度
b (float): 边 b 的长度
C_deg (float): 夹角 C 的角度(度数)
返回:
float: 角 A 的角度(度数)
"""
# 将角度 C 转换为弧度
C_rad = math.radians(C_deg)
# 使用余弦定理计算边 c 的长度
c = math.sqrt(a**2 + b**2 - 2 * a * b * math.cos(C_rad))
# 使用余弦定理计算角 A
cos_A = (b**2 + c**2 - a**2) / (2 * b * c)
# 确保余弦值在[-1, 1]的范围内,防止由于浮动误差导致的 math domain error
cos_A = max(-1, min(1, cos_A))
A_rad = math.acos(cos_A) # 反余弦,得到角 A 的弧度
# 将角 A 转换为度数
A_deg = math.degrees(A_rad)
return A_deg
if __name__ == '__main__':
# 示例使用:
a = 366
b = 390
C_deg = 16
angle_A = calculate_angle_A(a, b,C_deg)
print(f"角 A 的角度为: {angle_A:.2f}°")
print(90-angle_A )
函数前半部分是第一次余弦定理 计算 第三条边的长度,然后后半部门计算 角度
对应的两个公式如下
- 程序入口文件main.py
import time
import board
from adafruit_ticks import ticks_ms, ticks_diff
from busio import I2C
from lib.tmf8821 import TMF8821
from cosine_law import calculate_angle_A
i2c = I2C(scl=board.GP17, sda=board.GP16, frequency=125000)
tof = TMF8821(i2c, verbose=True)
tof.config.iterations = 5.5e5 # PDF page 21:550k
tof.config.period_ms = 32 # PDF page 21:32.2 ms
'''
'3x3_normal_mode': 1,
'3x3_macro_mode_upper': 2,
'3x3_macro_mode_lower': 3,
'3x3_wide_mode': 6,
'3x3_checkerboard_mode': 11,
'3x3_inverted_checkerboard_mode': 12,
'4x4_normal_mode': 7,
'4x4_macro_mode_upper': 4,
'4x4_macro_mode_lower': 5,
'4x4_narrow_mode': 13,
'3x6_mode': 10,
'''
tof.config.spad_map = '3x3_normal_mode'
tof.config.spread_spectrum_factor = 5
tof.write_configuration()
tof.active_range = 'short'
第一部分主要是根据数据手册进行初始化
if True:
print('Starting measurements...')
tof.start_measurements()
while True:
t_start = ticks_ms()
measurement = tof.wait_for_measurement(timeout_ms=500)
# PDF page 26
out_dis_2 = measurement.distances[1]
out_dis_5 = measurement.distances[4]
out_dis_8 = measurement.distances[7]
if (measurement.confidences[1] == 255 and
measurement.confidences[4] == 255 and
measurement.confidences[7] == 255):
# print(out_dis_2,out_dis_5,out_dis_8)
out_wall_angle = 90 - calculate_angle_A(min(out_dis_2,out_dis_8),out_dis_5)
print('Angle to the wall :',round(out_wall_angle,2),' and distance is ',out_dis_5,' mm')
else:
print('Out of measurements.')
time.sleep(1)
主循环中,选择了 2/5/8 三个SPAD 点的距离(高置信度为255),对应是三个点到墙面距离。
为什么,没有选择数据手册中的水平的 4/5/6?
因为数据手册中是水平摆放,但是传感器模块在开发板使用时,是垂直放置。
在测量结果中,5号位就是 垂直到墙面的距离。 2和8 中较短的是计算边
在Line# 中使用 calculate_angle_A 计算后,得出夹角。
- 功能展示图及说明
通电后就开始测量和输出计算结果在屏幕上
改变角度
右侧角度
角度过大,会超出量程
动态效果,请看视频比较清楚
- 项目中遇到的难题和解决方法
- 首先遇到的是没有MPY的驱动,只找到CPY的驱动,所以自己手动适配了MPY
- 开发板进入UF2 的按钮和其他略有不同,对应按键为B
- 对本次竞赛的心得体会(包括意见或建议)
1. 学习了适配CircuitPython
2. 了解了dToF传感器
3. Game kit 麻雀虽小,五脏俱全
4. TMF8821 文档详细
5. MicroPython的支持
1. 基于RP2040,不支持Wi-Fi
2. dToF传感器,缺乏MicroPython 库支持
- 可编译下载的代码文件(在电子森林我的项目-设计资源-附件处)