hrp's blog

“吹个牛逼而已,那么认真搞毛啊”

0%

在STM32H723上采集2Mhz的调制波

1.方案选择

image-20250110164733134

​ 本学期在完成23年电赛D题的时候,需要采集一个2Mhz的调制波,因为由FPGA驱动的高速AD还没有搞定,所以暂时先使用一块高速单片机来进行采集,在这里选择了STM32H723

​ 虽然使用了STM32H7这样的高速单片机,但即使在DMA+双ADC轮流采样的条件下,有效采样率也只能达到1Mps左右。根据奈奎斯特采样定理,过采样频率fs和信号频带的最大值fa有fs>2fa,否则必然会失真。

故过采样对本题显然是不合适的,经过学习我们发现可以使用欠采样,采样后的频谱会折叠,且可以使用很低的频率完成等效采样率很高的采样。其原理如图所示。

频谱折叠情况如图:

img

2.参数计算和STM32单片机配置

image-20250110171828289

时钟树配置如图,这里遇到一个奇怪的问题,ST公司给出的手册中要求将ADC时钟配置在36Mhz以内,但是CubeMX允许开发者将ADC时钟(PLL2P)配置到160Mhz,且实测并没有增加失真,可以称得上反向虚标了。

image-20250110172231958

image-20250110172316357

AD,TIM1配置如图,AD采样周期被配置为10.005us,等效采样率50Mhz。

3.效果展示

image-20250110175058941

Sine@2Mhz,经FFT处理后,呈现出非常漂亮的频谱,效果非常好。到这里,我们已经可以得到调制波的频谱,接下来就是使用算法分析信号的频谱,并识别调制模式,这就是以后文章的内容了。

竞赛时间为 7 月 29 日 8:00 至 8 月 1 日 20:00。参赛队员必须在早上 7:30 之

前到达竞赛现场,并携带学生证和参赛证备查。

本次比赛,我们选择了E题,题目如下:

E题_三子棋游戏装置-图片-0

E题_三子棋游戏装置-图片-1

E题_三子棋游戏装置-图片-2

机械结构

​ 机械结构是本题的最大难点

怎么动?

​ 拿到题目后整体上分为两种技术路线:

1.使用机械臂抓取

2.使用CoreXY结构进行抓取

​ 由于我们并没有现成的高精度机械臂,故我们最终使用方案2。我们购买了两台写字机,使用3D打印件改装Z轴动作机构,并将XY电机全部更换为闭环步进电机以消除回程误差。

怎么抓?

​ 第二个难点就是如何抓取,这里也有三种思路:

1.使用普通棋子+气泵+吸盘

2.使用普通棋子+机械爪

3.使用金属棋子+电磁铁

​ 我们没有现成的机械爪,又担心气泵+吸盘如果吸力调节不好可能会吸起其他物品,所以首先实验了使用金属棋子,效果很好。实测可以稳定抓取直径20mm,厚度3mm的金属圆片。微信截图_20240908162924

怎么转?

​ 最后一个问题是题目第三问要求能在棋盘旋转后继续放置棋子,我使用机器视觉方法简单进行了检测,但精度并不理想,于是我们决定在棋盘下安装一个高精度电位器,开机自动归零,通过检测电阻变化计算棋盘旋转角度,效果非常好,定位极其准确,获得了评委的一致好评。

微信截图_20240908163111

视觉部分思路

本题中的机器视觉任务难度不大,只需要能检测出棋子位置即可。我的思路是首先3D打印出一块与背景显著不同颜色的棋盘,通过Find_blobs找出色块坐标点,然后计算出九个格子的位置,最后对格子中心取样即可

ee17f7bc64843d20e83bee4d57c4787

人机对弈部分

​ 这部分我们选择在openmv上运行,效果一般般,公开代码也丰富,故不赘述。

总结

​ 赛后队伍变更,这是我第一次也是最后一次做电赛视觉,总体任务完成的一般,现场只完整跑出了123问,第45问受棋子反光影响,最后一步棋都下错了,第6问未能成功运行。最终得到浙江省二等奖。

微信截图_20240908142423

微信图片_20240908142432

​ 谨以此文,纪念大一的电赛经历。

hexo现在已经从Orangepi zero(Allwinner H2+)上被迁移到了qnas mini(Intel Celeron J4125)上!

没卵用的性能飞跃!

“立创”杯2024年中国计量大学电子设计竞赛暨2024年浙江省大学生电子设计竞赛选拔赛

比赛安排:
1.5.06~5.10学生钉钉加群在线报名。
2.5.11~5.27学生比赛制作环节。

本次比赛,我们选择了B题,题目如下:

-qSiGRtKCUS6Mmc8D-002

我们使用两个步进电机搭建云台,并最终采用了OpenMV+长焦镜头来进行识别。本次比赛我主要负责第三、四问的视觉和声音部分。

视觉部分思路

寻找角点

题目要求使用激光在1.8cm宽的条带上巡线,与控制同学沟通后,我决定识别出图形的所有角点并返回给主控,由主控进行插补运算。那么第一个问题就变成了如何识别出图形的角点,对于使用OpenCV的组别来说,这似乎根本不成问题,因为OpenCV自带了识别角点的例程,稍作修改就能完美识别该图形。但是OpenMV并没有给出角点检测的函数,其图片格式也并不是由Numpy数组储存,不可能去简单套用OpenCV的识别思路。

经过仔细的查询文档和实验,我发现OpenMV虽然不能给出一组点集,但可以通过image.find_line_segments()方法来找出线段的始末点,经实践检验,通过长焦镜头放大图像后识别效果很好,基本上能准确的返回线段的始末点。

接下来开始计算线段交点,但视觉识别并不能严格保证线段交点完全重合,故增加了线段交点模糊匹配的判断。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
def find_intersection_distance(lines,distance_threhold):
intersections = []
for i in range(len(lines)):
for j in range(i+1, len(lines)):
line1 = lines[i]
line2 = lines[j]
x1, y1, x2, y2 = line1[0], line1[1], line1[2], line1[3]
x3, y3, x4, y4 = line2[0], line2[1], line2[2], line2[3]
#distancep1 = ((x1 - x2) ** 2 + (y1 - y2) ** 2)
# distancep2 = ((x3 - x4) ** 2 + (y3 - y4) ** 2)
#if(distancep1>900 and distancep2>900):
if (x1 - x2) * (y3 - y4) == (y1 - y2) * (x3 - x4):
continue

px = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4))
py = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4))

# 计算两线段端点之间的距离
distance1 = ((x1 - x3) ** 2 + (y1 - y3) ** 2) ** 0.5
distance2 = ((x1 - x4) ** 2 + (y1 - y4) ** 2) ** 0.5
distance3 = ((x2 - x3) ** 2 + (y2 - y3) ** 2) ** 0.5
distance4 = ((x2 - x4) ** 2 + (y2 - y4) ** 2) ** 0.5

# 如果两线段端点之间的距离小于distance_threhold,则认为它们相交
if min(distance1, distance2, distance3, distance4) < distance_threhold:
px = round(px) # 将交点的横坐标四舍五入为整数
py = round(py) # 将交点的纵坐标四舍五入为整数
if(((b[2]+b[0]+10)>px>(b[0]-10)) and ((b[1]+b[3]+10)>py>(b[1]-10))):#b[]中均为图像外接矩形框的X,Y,W,H坐标
intersections.append((px, py))
for i in range(len(intersections)):
for j in range(i+1, len(intersections)):
if(i<len(intersections) and j<len(intersections)):
x1, y1 = intersections[i]
x2, y2 = intersections[j]

distance = ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5
if distance < distance_threhold:
intersections.remove((x1, y1))
intersections.remove((x2, y2))

break

该部分代码大多为人工智能生成,经简单修改后通过了测试,能成功的在五角星上返回内外20个点。

接下来是滤波,由于现场的光照条件未知,纸板上很有可能会有大大小小的阴影,所以我决定先对图像二值化,找出图像所在的外接矩形坐标,之后再以此为ROI计算线段交点,尽可能减少环境光以及KT板位置对识别的干扰,大大增强了程序的鲁棒性,这个实现起来很简单,不做赘述。

排序

现在我们有了20个角点(题目要求三种图形,为行文方便,本文只介绍五角星的情况,其他图形思路一样),但我们最终的目标是巡线,需要有顺序的将这些点排列出来。我们选择顺时针将其排列,这里我们使用了Matplotlib进行模拟,大致的思路就是首先计算图像的中心坐标,然后根据点与图像中心点坐标的距离将点集分为内外两部分,最后将内外的点集分别沿顺时针排列。

这部分代码同样有ai的帮助,写的非常丑陋,故只给出在Matplotlib上的效果,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import math
import random
%matplotlib inline
import matplotlib.pyplot as plt
from math import atan2
import math
# 生成10个随机点
#points = [(221, 209), (233, 220), (206, 218), (224, 235), (209, 233),(224, 195), (247, 217), (194, 211),(232, 247), (199, 243)]
#outpoints=[(244, 197), (203, 191), (251, 238), (182, 231), (212, 259), (187, 160), (283, 252), (272, 168), (145, 239), (206, 297)]
allpoints=[(227, 123), (205, 135), (185, 167), (134, 162), (194, 216), (217, 171), (217, 145), (195, 157), (170, 155), (199, 180), (210, 158), (192, 142), (179, 137), (235, 161), (186, 117), (254, 96), (207, 121), (231, 142), (169, 88), (268, 176)]
cx=204
cy=148

distances = []
# 计算每个点的极角
def polar_angle(point):
x, y = point
return math.atan2(x-cx, y-cy)

# 根据极角对点进行排序
FinalPoints=[]

i=0
def distance(point1, point2):
x1, y1 = point1
x2, y2 = point2
return math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)

def ClockWiseSorting(sorted_list,centralpoints):
for i in range(0,(len(sorted_list)-1),2):
print(i)
if(distance(centralpoints,sorted_list[i])<distance(centralpoints,sorted_list[i+1])):
temp=sorted_list[i]
sorted_list[i]=sorted_list[i+1]
sorted_list[i+1]=temp
temp=0
return sorted_list
#计算所有距离
for coordinate in allpoints:
distances.append((coordinate, distance(coordinate, (cx,cy))))
sorted_distances = sorted(distances, key=lambda x: x[1])
points_withdistance = sorted_distances[:10]
outpoints_withdistance = sorted_distances[10:]
points=[]
outpoints=[]
for pair, dist in points_withdistance:
print(f"{pair}: {dist}")
points.append(pair)
for pair, dist in outpoints_withdistance:
print(f"{pair}: {dist}")
outpoints.append(pair)





#sorted_points = sorted(points, key=polar_angle)
sorted_points = sorted(outpoints, key=polar_angle)
sorted_points=ClockWiseSorting(sorted_points,(cx,cy))
for point in sorted_points:
print(point)
FinalPoints
plt.annotate(i, (point[0],point[1]))
plt.plot(point[0],point[1],marker="o", markersize=5, markeredgecolor="red", markerfacecolor="red")
i+=1
if(i%2==0):
i+=2

sorted_points2 = sorted(points, key=polar_angle)
sorted_points2=ClockWiseSorting(sorted_points2,(220,220))
i=2
flag=18
for point in sorted_points2:
print("far")
print(point)
if(i==2):
if(polar_angle((point[0], point[1]))<polar_angle((sorted_points[0][0], sorted_points[0][1]))):
#point+=1
plt.annotate(flag, (point[0],point[1]))
plt.plot(point[0],point[1],marker="o", markersize=5, markeredgecolor="lime", markerfacecolor="lime")
flag+=1
continue

plt.annotate(i, (point[0],point[1]))
plt.plot(point[0],point[1],marker="o", markersize=5, markeredgecolor="lime", markerfacecolor="lime")
i+=1
if(i%2==0):
i+=2
print(polar_angle((194, 211)))
print(polar_angle((187, 160)))
plt.axis("equal")
plt.show()

效果如下:

微信截图_20240607142524

做到这里,视觉部分的主要要求也就基本实现了,剩下就是LCD和串口调试,这部分代码很简单且到处都能找到,故不赘述。

视觉部分总结

学长过去常常跟我说,做视觉最重要的是思路,有了思路都能慢慢实现出来,打完校赛后,深以为然。再大的问题,敢于想,敢于尝试,都有可能解决。

技术上,我感觉到我的代码能力还是需要加强,特别是对python数组的操作不够熟练,同样的功能不能复用,写的又臭又长,像是旧社会女人的裹脚布。同时异常处理也需要加强,早期版本的程序会在各种没有检测到对象的情况下直接卡飞,这样的问题到第二周才基本解决,倘若是在省赛或国赛中,恐怕已经无力回天了。

硬件上,160x120的LCD对于调试实在是有点不够用,该屏幕的可视角度极其糟糕,偏一点看过去就是一片白,这也导致在现场,镜头中出现了一小块反光,而我一直没能发现,差点葬送了全队两周的努力。

调试代码也太过于简单粗暴,接收到调节指令也没有反馈,收没收到全靠瞪眼,卡住全靠RESET,这样的问题在正式比赛中都有可能是致命的。

当然瑕不掩瑜,大一学生第一次参赛能拿到校特等奖对我们已经是非常大的胜利,不枉我们一年来的努力。

声音部分思路

声音部分本来应该是硬件同学负责的内容,但由于选购的传感器信号质量太差,实在不堪一用,所以我们在比赛结束前两天更换了方案,阴差阳错间,声源和检测装置都变成了我的工作。

我们首先制作了一个能发出特定频率的声源,使用PWM发生器生成1.5KHZ的正弦波并通过L298N放大电流,驱动一个10W的喇叭。L298N在这个任务中的表现出人意料的好,其功率大,发热小,相较于功放模块能经受的电流更大。最重要的是,我们对该模块十分熟悉,上手就能使用,减少了学习新模块的时间成本。

然后使用一个maix dock开发板,该k210开发板自带了一个全指向性数字麦克风,我们试图将其改造为指向性麦克风,然后让麦克风随云台旋转,过程中实时记录声音经过FFT变换后在1.5khz上的强度,最终通过寻找声强变化曲线和声源位置的关系来进行声源定位。Maixpy的FFT例程在MaixPy-v1_scripts/hardware/demo_fft_spectrum.py at master · sipeed/MaixPy-v1_scripts (github.com)

可惜的是,本方案实际上并不可行,因为指向性麦克风是无法被简单的改装出来的。我赛后咨询了一位在日本学习声学相关专业的同学,他告诉我,单指向性麦克风大多在振膜结构上就与普通麦克风不同,所以无法简单的被改装出来。可惜我们缺乏声学知识,知网上也没能找到关于单指向性麦克风设计的文章,误入了歧途。

幸运的是,这套系统在评测时成功定位了一次,成为了我们最终拿到校特的关键一招。GG WP

最后,希望今年省赛我们也能有如此好运,GL HF!

在中国计量大学寝室内使用OpenWRT实现校园网自动登录

OpenWRT@CJLU

最近笔记本屏幕被螺丝挤爆了,只能把台式机移到实验室使用。寝室的校园网口就闲置下来了,又考虑到最近在寝室装了拓竹A1Mini,要连接wifi来监控打印,于是就决定给寝室装个WiFi。

1.路由器的选择

简单上网搜索后,发现H3C TX1800系列有官方OpenWRT支持,且价格便宜,目前在小黄鱼上约40元。一顿搜索,找到一个个人卖家在卖tx1800,看起来像是弱电箱里拆下来的,简单砍价后24元包邮拿下。57d2b2f188c2226e75810893ff01f26

H3C TX1800 Plus 千兆双频路由器是新华三智能终端有限公司全新设计的Wi-Fi 6 路由器,面向追求高品质网络的用户和群体。TX1800 Plus外置独立超高功率FEM,高增益富兰克林鞭状天线,采用802.11ax新无线技术,整机提供1775Mbps无线速率, 2.4GHz频段无线速率提升至574Mbps,5GHz频段无线速率提升至1201Mbps。芯片独有CSA、SCS技术,2MHz窄频宽技术,提升无线抗干扰能力,稳定的网络、游戏级体验。专业双核CPU,256M内存,支持更多终端。无线IDS入侵检测、防蹭网,让您的网络更加安全。更有内置网易UU游戏加速等特色功能。全新Wi-Fi 6 ,较佳网络体验。

2.刷入OpenWRT

我买的这台机器具体型号是TX1801Plus,上面有中国电信的标志,显然是电信装宽带送的路由器。刷入OpenWRT过程很简单,拆开机器并用CH340连接预留的调试焊盘就可以连接串口,执行命令刷入即可。具体步骤参照https://www.right.com.cn/forum/thread-8294417-1-1.html

简单配置了一下OpenWRT,中间更换了清华大学软件源,一直显示“OpenWRT has no valid architecture”,遂放弃,所幸CJLU校园网对OpenWRT自带的源连接速度也很快,安装软件没有受影响。

3.编写自动登录脚本

对位于校内网10.4.66.2的登陆界面抓包,得到post请求

1
http://10.4.66.2:801/eportal/portal/login?callback=dr1003&login_method=1&user_account=学号40telecom&user_password=密码&wlan_user_ip=宿舍ip&wlan_user_ipv6=&wlan_user_mac=路由器mac地址&wlan_ac_ip=10.4.66.1&wlan_ac_name=cjlu&jsVersion=4.2.1&terminal_type=1&lang=zh-cn&v=1929&lang=zh

在OpenWRT上安装bash并新建/etc/login.sh,在脚本中

1
curl 'http://10.4.66.2:801/eportal/portal/login?callback=dr1003&login_method=1&user_account=学号40telecom&user_password=密码&wlan_user_ip=宿舍ip&wlan_user_ipv6=&wlan_user_mac=路由器mac地址&wlan_ac_ip=10.4.66.1&wlan_ac_name=cjlu&jsVersion=4.2.1&terminal_type=1&lang=zh-cn&v=1929&lang=zh'

最后使用crontab -e 定时执行任务即可

新的开始

从小学开始建站,用过NAT123,花生壳…无数种映射工具,修改过光猫配置,但始终效果不好

托ipv6全面普及的春风,终于能快速高效廉价的ddns,本站目前运行在香橙派Zero上,希望2024年能稳定运行吧!