回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页

【创意智造组】微信小程序跳一跳游戏——基于二哈2的自动闯关装置 简单

头像 程军老师 2026.04.10 12 0

1.介绍

微信小程序里的“跳一跳”是一款国民级休闲游戏,玩家通过按住屏幕的时间长短来控制棋子跳跃距离,精准落在下一个平台上。游戏规则简单,但要拿到高分却需要极强的节奏感和手眼协调能力。

这个项目不仅是对 AI 视觉识别和嵌入式控制的一次综合实践,更想探索一个有趣的问题:机器能否像人一样“看懂”游戏规则,并用物理动作完成操作? 同时,它也展示了 AI 如何从虚拟世界走向物理交互,为未来人机协同提供一种趣味范本。

2.传感器

硬件型号作用
主控板Arduino Uno上传模式,离线运行
视觉传感器二哈2视觉传感器加载目标检测训练模型
执行器SG90 舵机 180°模拟手指按压屏幕动作
触摸笔头电容笔+接地线
固定结构舵机支架、3D 打印件
其他USB数据线、杜邦线若干、12v锂电池供电与信号连接

3.注意事项

3.1.二哈2需单独供电

连接附赠的转接板,必须单独供电,否则二哈2会绿屏、反复重启。

3.2.电容笔接地

电容笔金属端必须连接导线悬空接地,不然电容笔按下动作失效。

3.3.采集数据处理

通过截图的手机为完全竖版,必须借助ai制作python裁切图片的程序,批量裁切得到正方形数据,进行标注。

4.制作过程

4.1.3D打印外观件

设计外观件,预留线路、传感器位置开槽。

4.2.连接线路

Arduino Uno *1、舵机 *1、数字大按钮模块 *2、二哈2 *1

image.png

4.3.数据采集与裁切

由于得到的是竖版,训练误差较大,因此借助ai设计批量裁切图片程序。

image.png

代码
import os
import sys
import tkinter as tk
from tkinter import filedialog, messagebox, ttk

# 尝试导入 Pillow 库
try:
    from PIL import Image
except ImportError:
    print("错误:未安装 Pillow 库。请运行以下命令安装:")
    print("pip install Pillow")
    try:
        root = tk.Tk()
        root.withdraw()
        messagebox.showerror("缺少依赖", "未安装 Pillow 库,请安装后重试。\n\n命令:pip install Pillow")
        root.destroy()
    except:
        pass
    sys.exit(1)


def crop_center_square(image_path: str, output_path: str, skip_existing: bool = True) -> bool:
    """
    将图片按最短边从正中心裁剪为正方形,并保存到指定路径。

    :param image_path: 原始图片路径
    :param output_path: 输出图片路径
    :param skip_existing: 若输出文件已存在,是否跳过(True=跳过并返回False)
    :return: 是否成功裁剪并保存
    """
    if skip_existing and os.path.exists(output_path):
        return False
    try:
        with Image.open(image_path) as img:
            width, height = img.size
            side = min(width, height)
            left = (width - side) // 2
            top = (height - side) // 2
            right = left + side
            bottom = top + side
            cropped = img.crop((left, top, right, bottom))
            cropped.save(output_path)
        return True
    except Exception as e:
        print(f"处理失败:{image_path} - {e}")
        return False


class BatchCropper:
    def __init__(self, root):
        self.root = root
        self.root.title("批量图片正方形裁剪工具")
        self.root.geometry("500x250")
        self.root.resizable(False, False)

        # 说明标签
        info_label = tk.Label(
            root,
            text="选择多张图片,程序将自动按最短边\n从正中心裁剪出正方形区域",
            justify="center",
            font=("微软雅黑", 10)
        )
        info_label.pack(pady=10)

        # 选择文件按钮
        self.select_btn = tk.Button(
            root,
            text="选择多张图片并裁剪",
            command=self.start_batch,
            width=20,
            height=2,
            bg="#4CAF50",
            fg="white",
            font=("微软雅黑", 10)
        )
        self.select_btn.pack(pady=10)

        # 进度条
        self.progress = ttk.Progressbar(root, orient="horizontal", length=400, mode="determinate")
        self.progress.pack(pady=10)

        # 状态标签
        self.status_label = tk.Label(root, text="就绪", fg="gray")
        self.status_label.pack(pady=5)

        # 退出按钮
        exit_btn = tk.Button(root, text="退出", command=root.quit, width=10)
        exit_btn.pack(pady=5)

    def start_batch(self):
        """选择多张图片并开始批量裁剪"""
        file_paths = filedialog.askopenfilenames(
            title="选择多张图片",
            filetypes=[
                ("图像文件", "*.jpg *.jpeg *.png *.bmp *.tiff *.webp"),
                ("所有文件", "*.*")
            ]
        )
        if not file_paths:
            return

        # 禁用按钮,避免重复点击
        self.select_btn.config(state="disabled", text="处理中...")
        self.progress["value"] = 0
        self.progress["maximum"] = len(file_paths)

        # 使用 update_idletasks 保持界面响应,逐张处理(不另开线程,简单可靠)
        success_count = 0
        for i, file_path in enumerate(file_paths, 1):
            # 更新状态标签
            filename = os.path.basename(file_path)
            self.status_label.config(text=f"正在处理:{filename}")
            self.root.update_idletasks()

            # 生成输出路径(原文件夹,添加 _square 后缀)
            dir_name = os.path.dirname(file_path)
            base_name, ext = os.path.splitext(filename)
            output_name = f"{base_name}_square{ext}"
            output_path = os.path.join(dir_name, output_name)

            # 执行裁剪
            if crop_center_square(file_path, output_path, skip_existing=True):
                success_count += 1
            # 更新进度条
            self.progress["value"] = i
            self.root.update_idletasks()

        # 处理完成,恢复按钮并显示结果
        self.select_btn.config(state="normal", text="选择多张图片并裁剪")
        self.status_label.config(text=f"完成!成功:{success_count} / {len(file_paths)}")
        messagebox.showinfo("批量处理完成", f"共处理 {len(file_paths)} 张图片\n成功裁剪 {success_count} 张\n已跳过已存在的正方形图片。")
        self.progress["value"] = 0


def main():
    root = tk.Tk()
    app = BatchCropper(root)
    root.mainloop()


if __name__ == "__main__":
    main()

4.4.数据标注

标注图片.png

4.5.数据校验

校验结果.png

5.完整积木

完整积木.png

6.改进与不足

6.1.部分模型识别不出

关卡较多,采集的数据近90份有限,仍需要多采集,并标注。

6.2.反光

房间LED灯会反射到手机屏幕导致识别失败,需要遮挡光线直射。

6.3.按下数据不准

变化公式仍然在摸索中,不断调试优化接近数值。.

7.作品全样

图片 (1).jpg
图片 (2).jpg

评论

user-avatar