【开源/教程】宝可梦图鉴机 制作

【开源/教程】宝可梦图鉴机 制作

考虑被人商业化的可能与项目优化、复刻的需要,同时顾及两边,决定部分开源,但系统所有功能都是具备的


效果展示的视频指路: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世代的数据

不提供模型和完整世代数据的理由有两个:一是我训出的模型并不好,希望有人能改进数据集,训练出更好的模型;二是怕有人直接拿去了做生产售卖,我不希望这种事情发生,没有模型和全部世代的数据,生产出来也是残缺的,但也有完善出来的可能,就算是添上一个小小的障碍吧。这样也能照顾到希望复刻的人,这样还不满足的话就凭自己的能力也可以再收集齐数据,毕竟前几个世代数据的模板都是有的。

如果你有好的改进想法(外壳设计、模型优化之类的),请联系我交流。

以下是教程正文。说是教程,其实是回忆自己的制作经历。

一、材料准备

主要材料

  1. Sipeed Maix Bit和配套屏幕

  2. ov5640摄像头(可以找更好的)

  3. MAX98357 I2S 音频模块

  4. 3W小喇叭杜邦母头直径23MM

  5. 拼多多宝可梦图鉴机3D打印成品外壳(可以自己设计)

  6. Micro SD卡 32G

  7. 5V 800mAh小电池 50x31x11mm

  8. 自锁开关5.8x5.8mm(可以换更合适的)

  9. 5D摇杆按钮模块

  10. 一堆杜邦线

  11. tpye c 充电线一根

其他工具

  1. 小打磨机
  2. 拆接线工具
  3. 502胶水

二、模型训练

1、数据集

我最开始在网上找数据集,但是只在kaggle上面找到了第一世代的图片数据集,所以我自己组建了1~9世代的1025只宝可梦的数据集,但我能力经验都有限,数据集勉强建好也是不尽人意。所以强烈希望有人能够改进。kaggle指路:https://www.kaggle.com/datasets/unexpectedscepticism/11945-pokemon-from-first-gen

我使用爬虫爬取了一些wiki网站的宝可梦图片,但是太少了,所以我又直接去搜索引擎爬取了,并且人工筛选过滤。但一个人很难搞,结果还是很糟糕,越到后面的世代就越都是质量不高的垃圾图片,而且就算总量感觉很多,每个类别数目其实也不够多。

这里提供一些可以爬取的网站,有但不多,还是需要直接浏览器搜索爬取结果列表的图片。

数据集结果部分展示图。

现将我整理的垃圾数据集(第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和其他网站上面爬取的。

  1. 名称、属性等文本数据,以及进化链数据:https://wiki.52poke.com/wiki/宝可梦列表(按全国图鉴编号)/简单版
  2. gif数据:https://pokemondb.net/sprites/gengar (页面下拉,位置在第五世代) https://projectpokemon.org/home/docs/spriteindex_148/3d-models-generation-1-pokémon-r90/ (3d版本)
  3. 叫声数据:https://play.pokemonshowdown.com/audio/cries/
  4. 配音数据: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世代的数据,但是功能都是完整的。

到此结束。