【开源/教程】宝可梦图鉴机 制作
考虑被人商业化的可能与项目优化、复刻的需要,同时顾及两边,决定部分开源,但系统所有功能都是具备的
效果展示的视频指路:https://www.bilibili.com/video/BV1nkudzeEwW/?spm_id_from=333.1387.homepage.video_card.click!

前言
并没有那么好,仅仅是勉强做出来自娱自乐的程度。
我是很兴趣使然的人,对于宝可梦图鉴机的兴趣让我去做了这个项目。当时我看到有几个项目都非常好,所以就也去做了。
https://www.bilibili.com/video/BV1bf421S7a9/?share_source=copy_web&vd_source=8b1a596816ed0a1e2e1d28eb0f3fdaee
https://www.eetree.cn/project/detail/1311
我并不是学电子的,所以做的并不是很好,仅仅是勉强做出来自娱自乐的程度。除了外壳的缺陷之外,识别的能力其实没有想象中厉害,很多时候都无法良好地识别,图鉴里面的界面倒是做的还行。
我本并无量产的想法,因为做的真的没有想象中的好。视频里的识别例子其实是经过多次尝试选取的高识别率的例子,识别受光线、目标大小因素、背景等因素影响很大,而且1025只宝可梦,这个类别数量难以有高识别率。识别的局限性太大了,很多时候识别不出来,有时候能识别出来就已经值得高兴了,所以我觉得是"仅仅是勉强做出来自娱自乐的程度"。
我更希望能享受制作的乐趣,不仅是我自己,也是所有人。思考制作比成品要有趣的多。但我也看到了很多人想要量产,也有人想要合作,也想到了开源的弊端。如果说能够交流让这个项目更好的话,并不违背我的兴趣。如果说有人直接拿去卖了,也是让我讨厌的。
于是,我决定在此提供部分开源 ,以及制作教程,同时也作为我个人的制作记录。经过决定,提供大部分信息内容,包括数据集、操作界面的代码、接线的方法等,只是不包括我训练的模型、4-9世代的数据。
不提供模型和完整世代数据的理由有两个:一是我训出的模型并不好,希望有人能改进数据集,训练出更好的模型;二是怕有人直接拿去了做生产售卖,我不希望这种事情发生,没有模型和全部世代的数据,生产出来也是残缺的,但也有完善出来的可能,就算是添上一个小小的障碍吧。这样也能照顾到希望复刻的人,这样还不满足的话就凭自己的能力也可以再收集齐数据,毕竟前几个世代数据的模板都是有的。
如果你有好的改进想法(外壳设计、模型优化之类的),请联系我交流。
以下是教程正文。说是教程,其实是回忆自己的制作经历。
一、材料准备
主要材料
-
Sipeed Maix Bit和配套屏幕
-
ov5640摄像头(可以找更好的)
-
MAX98357 I2S 音频模块
-
3W小喇叭杜邦母头直径23MM
-
拼多多宝可梦图鉴机3D打印成品外壳(可以自己设计)
-
Micro SD卡 32G
-
5V 800mAh小电池 50x31x11mm
-
自锁开关5.8x5.8mm(可以换更合适的)
-
5D摇杆按钮模块
-
一堆杜邦线
-
tpye c 充电线一根
其他工具
- 小打磨机
- 拆接线工具
- 502胶水
二、模型训练
1、数据集
我最开始在网上找数据集,但是只在kaggle上面找到了第一世代的图片数据集,所以我自己组建了1~9世代的1025只宝可梦的数据集,但我能力经验都有限,数据集勉强建好也是不尽人意。所以强烈希望有人能够改进。kaggle指路:https://www.kaggle.com/datasets/unexpectedscepticism/11945-pokemon-from-first-gen
我使用爬虫爬取了一些wiki网站的宝可梦图片,但是太少了,所以我又直接去搜索引擎爬取了,并且人工筛选过滤。但一个人很难搞,结果还是很糟糕,越到后面的世代就越都是质量不高的垃圾图片,而且就算总量感觉很多,每个类别数目其实也不够多。
这里提供一些可以爬取的网站,有但不多,还是需要直接浏览器搜索爬取结果列表的图片。
- https://wiki.52poke.com/wiki/宝可梦列表(按全国图鉴编号)/简单版
- https://pokemon.fandom.com/wiki/List_of_Pokémon
- https://pokemondb.net/pokedex/national
数据集结果部分展示图。

现将我整理的垃圾数据集(第1世代-第4世代)提供于此,希望有人能改进。
链接: https://pan.baidu.com/s/1u6w7RZr602-qP9Q9bWSC4A?pwd=bhv6 提取码: bhv6
(我选用分类识别而不是目标识别,不需要目标标注,省下工作量。)
如果说不满足于此想要完整全部世代的数据集的,我放一点我python爬虫脚本在这里,可以参考着用,自己爬取下来组建数据集。
https://files.cnblogs.com/files/blogs/741628/worm.zip?t=1753180042&download=true
2、训练软件
Mx_yolo 3.0.0

自己构建网络之类的还是算了,学着用的yolo的训练软件Mx_yolo,操作比较方便。教程看的网上的。
教程指路:https://blog.csdn.net/m0_73841621/article/details/131855356
训练耗时应该需要一两天,不太记得了,反正我是一直开着电脑(4060)训的,训练的时候显卡被占用,看不了视频打不了游戏。如果只训1-4世代应该会快很多。
训完会给模型文件,需要再转换一下,具体看教程就行。

然后因为内存不足,我不用load()而使用load_flash()加载模型,模型还要继续转换一下,用下面这个代码:
点击查看代码
#################################
# model_le2be.py
#
# run python3 on pc not maixpy
#
# not maixpy !!!!!!!!
#################################
import struct
import sys
import os
# main body
if sys.argv.__len__() > 1:
# 参数获取
src_file = sys.argv[1]
else:
# 文本输入
src_file = "pokemon_all_gen.kmodel"
if not os.path.exists(src_file):
print('File Path Invalid! Exiting...')
exit(1)
dst_file = src_file.split(".")
ext = dst_file.pop()
dst_file = ".".join(dst_file)
dst_file = "{}_be.{}".format(dst_file, ext)
print("Source file: {0}\nTarget File: {1}".format(
src_file, dst_file))
try:
sf = open(src_file, "rb")
df = open(dst_file, "wb")
buf_tmp = [b'0' for x in range(0, 4)]
contents = sf.read()
buf_size = contents.__len__()
# 不足4个字节,自动补0
extra_size = (buf_size % 4)
if extra_size > 0:
buf_size += (4 - extra_size)
contents = contents + b'0000'
for i in range(0, buf_size, 4):
buf_tmp[3] = contents[i]
buf_tmp[2] = contents[i+1]
buf_tmp[1] = contents[i+2]
buf_tmp[0] = contents[i+3]
# pack into bytes flow
tmp_bytes = struct.pack("4B", buf_tmp[0], buf_tmp[1], buf_tmp[2], buf_tmp[3])
df.write(tmp_bytes)
finally:
if sf:
sf.close()
if df:
df.close()
print("Convert Completed!")
最后模型需要烧录进芯片里,用这个就行:

烧录之前记得先清空原本的固件,把下载下来的固件烧录进去,具体看下文。
模型烧录至0x300000的位置。

我不提供我的模型文件,所以劳烦各位重新训练了,希望在改进数据集的基础上能训练出效果更好的模型。
三、图鉴信息与界面代码
1、图鉴信息
全国图鉴信息是从wiki和其他网站上面爬取的。
- 名称、属性等文本数据,以及进化链数据:https://wiki.52poke.com/wiki/宝可梦列表(按全国图鉴编号)/简单版
- gif数据:https://pokemondb.net/sprites/gengar (页面下拉,位置在第五世代) https://projectpokemon.org/home/docs/spriteindex_148/3d-models-generation-1-pokémon-r90/ (3d版本)
- 叫声数据:https://play.pokemonshowdown.com/audio/cries/
- 配音数据:https://zh-cn.text-to-speech.online/ 或者有台版配音音频数据的可以自己训练一个音色。
因为系统需要调用信息进行展示,所以就进行了数据分类,放入不同文件夹,整理装入sd卡以供代码调用。具体情况如图。
- evolution文件夹:进化链图片
- form文件夹:宝可梦形态(地区形态、mega形态、极巨化等)
- gif-jpg文件夹:gif分割为帧,jpg格式保存
- mp3文件夹:宝可梦叫声和播报员播报语音
- evolution.txt:进化链文本信息
- inform.txt:初始化界面信息(刚进入图鉴信息页面展示)
- sprite.jpg:搜索界面展示的小宝可梦图标

- evolution文件夹:进化链图片
包含其他地区形态

- form文件夹:宝可梦形态(地区形态、mega形态、极巨化等)
form_evo:其他地区形态的进化链数据
form_img:其他形态的图片
form_info:其他形态的数据(属性、种族值等)

一些其他地区形态包含于原本的进化链之中,就合并展示,但如果其他地区形态的进化链完整,会在切换形态后切换展示。

form_img:其他形态的图片

- mp3文件夹:宝可梦叫声和播报员播报语音
播报音频爬虫可以参考:https://files.cnblogs.com/files/blogs/741628/tts.zip?t=1753180180&download=true

1-4世代的宝可梦图鉴信息会在下一节结尾一起提供。
2、界面代码
代码方面,因为k210内存很小,模型加载之后就没剩下多少了,所以选了第二小的固件(仅支持Maixpy IDE)。之后就纯靠基础的方法堆功能,像gif动画这种都是靠分解为图片一张张放映实现的。
k210通过Maixpy IDE使用的教程:https://wiki.sipeed.com/soft/maixpy/zh/
就是这个,tpyec把芯片接电脑,进去点连接运行就可以调试了。

记得刷掉原本的固件,换成小固件。
固件下载地址:https://dl.sipeed.com/shareURL/MAIX/MaixPy/release/master/maixpy_v0.6.3_2_gd8901fd22

先擦除

烧录。如果模型训好了,最后模型也烧录就ok了,具体看上文

内存还是很容易不够,动不动报错out of memory,我在网上找到了记录了解决内存不足问题解决方法的宝藏博客,问题才得以解决。
https://neucrack.com/p/325#内存不够 (MemoryError: Out of normal MicroPython Heap Memory!)
主要是以下两点:
最基础的方法就是减少内存的使用,比如全局变量,不使用了尽量删除(通过del 变量名),删除之后还可以手动回收 GC 内存(通过gc.collect())。图片分辨率也可以尽量不要用太大(一般QVGA)
另外,如果模型太大,可以使用kpu.load_flash()函数来加载模型(只支持kmodel):这会在需要模型时实时从flash读取内容,这样就可以装载大模型了,效率会低一点,帧率会有所降低。
现在就不会随随便便爆内存了,但系统操作时间久了还有几率会卡死,断电重启一下就好了。
最后写完也是史山,就不展开细说了,能用就行。
另外,系统代码都在main.py里,但如果只有1-4世代的数据的话,宝可梦数量需要更改,自行查找替换1025即可。

现将整理好的1-4世代的宝可梦图鉴信息提供于此,以及界面运行代码main.py、必要的运行文件,将文件夹中的文件导入Micro SD卡就可以使用了。
链接: https://pan.baidu.com/s/1IdkVmc4nIXdFGGYKjTfGdw?pwd=t3qc 提取码: t3qc
四、其他配件与组装
1、引脚配置(MAX98357A音频模块、按钮模块)
在组装之前,还要说一下引脚配置什么。
k210的配置写在代码里面了。
点击查看代码
def init_uart():
fm.register(34, fm.fpioa.I2S0_OUT_D1, force=True)
fm.register(35, fm.fpioa.I2S0_SCLK, force=True)
fm.register(33, fm.fpioa.I2S0_WS, force=True)
fm.register(15, fm.fpioa.GPIOHS0, force=True)
fm.register(7, fm.fpioa.GPIOHS1, force=True)
fm.register(8, fm.fpioa.GPIOHS2, force=True)
fm.register(9, fm.fpioa.GPIOHS3, force=True)
fm.register(10, fm.fpioa.GPIOHS4, force=True)
uart = UART(UART.UART1, 115200, 8, 0, 0, timeout=1000, read_buf_len=256)
return uart
参考官网的规格书,选空着的引脚分配。

其中33、34、35连接的是MAX98357A音频模块。
关于MAX98357A的使用,我之前参考的这篇:https://m.eeworld.com.cn/bbs_thread-1215475-1-1.html
代码 | k210引脚编号 | MAX98357A接线引脚 |
---|---|---|
fm.register(34, fm.fpioa.I2S0_OUT_D1, force=True) | k210的34引脚 | MAX98357A的DIN |
fm.register(35, fm.fpioa.I2S0_SCLK, force=True) | k210的35引脚 | MAX98357A的BCLK |
fm.register(33, fm.fpioa.I2S0_WS, force=True) | k210的33引脚 | MAX98357A的LRC |
无 | k210的5V引脚 | MAX98357A的VCC |
无 | k210的GND引脚 | MAX98357A的GND |
另外MAX98357A剩下引脚不用管,绿的那里用杜邦线接上小喇叭就能用了。

其中 7、8、9、10、15连接的是按钮模块。
代码 | k210引脚编号 | 按钮接线引脚 |
---|---|---|
fm.register(15, fm.fpioa.GPIOHS0, force=True) | k210的15引脚 | MID |
fm.register(7, fm.fpioa.GPIOHS1, force=True) | k210的7引脚 | RHT |
fm.register(8, fm.fpioa.GPIOHS2, force=True) | k210的8引脚 | UP |
fm.register(9, fm.fpioa.GPIOHS3, force=True) | k210的9引脚 | DWN |
fm.register(10, fm.fpioa.GPIOHS4, force=True) | k210的10引脚 | LET |

最后COM要接到电池的黑线上面,下一节会展示。
2、接线
提供组装接线示意图。(组装需要拆线接线工具)

我用的自锁按钮不是很好,可以换别的按钮,如果要用的话,同侧邻近的两个引脚是一对,试一下就能用了。
有外壳的话,装好就可以用了。我拼多多买的外壳,需要进行切削才能装下。
结
虽说只有1-3世代的数据,但是功能都是完整的。
到此结束。