【PaddleDetection】结合51单片机搭建微信跳一跳物理外挂

P粉084495128
发布: 2025-07-18 10:46:23
原创
904人浏览过
本文介绍了一个基于深度学习的跳一跳物理外挂制作过程。先准备PaddleDetection,自制199张图片数据集并标注,转成COCO格式。用PPYOLO_Tiny训练模型,经验证、导出后部署。电脑将坐标距离转成按压时间,通过上位机代码向51单片机发指令,单片机按指令操作,还提供了相关代码。

☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

【paddledetection】结合51单片机搭建微信跳一跳物理外挂 - php中文网

前言

 单片机原理课的作业做了一个OpenCV+汇编51的没啥用的跳一跳物理外挂,觉得可以换成用深度学习进行目标检测,于是就来试一试

效果图:

【PaddleDetection】结合51单片机搭建微信跳一跳物理外挂 - php中文网

效果动图:

【PaddleDetection】结合51单片机搭建微信跳一跳物理外挂 - php中文网

一、准备工作

1. 准备PaddleDetection

In [ ]
#安装PaddleDetection!git clone https://gitee.com/paddlepaddle/PaddleDetection.git work/PaddleDetection
登录后复制
In [ ]
#安装前置!pip install --upgrade -r work/PaddleDetection/requirements.txt -i https://mirror.baidu.com/pypi/simple
登录后复制

2. 自制数据集

 采集199张图片并剪裁(差一张强迫症狂喜(狗头)),使用EasyData平台进行数据标注(他那个智能标注还挺好用的,标完直接传到AIstudio上)

微信 WeLM
微信 WeLM

WeLM不是一个直接的对话机器人,而是一个补全用户输入信息的生成模型。

微信 WeLM 33
查看详情 微信 WeLM

【PaddleDetection】结合51单片机搭建微信跳一跳物理外挂 - php中文网

In [ ]
#解压数据集!unzip -q 'data/data109105/JumpData V1.zip' -d data/
!mkdir data/JumpData
!mkdir data/JumpData/Image
!mkdir data/JumpData/Label
!mkdir data/JumpData/Anno
!mv data/DatasetId_230079_1631965091/*.json data/JumpData/Label
!mv data/DatasetId_230079_1631965091/*.jpg data/JumpData/Image
!rm -rf data/DatasetId_230079_1631965091
!rm -rf data/JumpData/Label/screen2.json
登录后复制

 转成COCO格式的标注文件(这地方之前搞错了,训练半天精度上不去,后面才发现是我标注文件做错了)

In [ ]
#整理Json文件import osimport json

classlist = [{'supercategory': 'none', 'id': 1, 'name': 'player'}, 
             {'supercategory': 'none', 'id': 2, 'name': 'platform'}]#trainidxcount = 0imgcountidx = 0JumpData_train = {}
imagelist_train = []
labellist_train = []for idx, imagename in enumerate(os.listdir('data/JumpData/Image')[0:179]):
    imagelist_train.append({'file_name': imagename, 'height': 600, 'width': 1080, 'id': idx})
    jsonname = os.path.splitext(imagename)[0] + '.json'
    with open(os.path.join('data/JumpData/Label', jsonname)) as f:
        data = json.load(f)        for label in data['labels']:
            x1 = label['x1']
            y1 = label['y1']
            w = label['x2'] - label['x1']
            h = label['y2'] - label['y1']
            area = (w * h)            if label['name'] == 'platform':
                classidx = 2
            else:
                classidx = 1
            idxcount += 1
            labellist_train.append({'area': area, 
                              'iscrowd': 0, 
                              'bbox': [x1, y1, w, h], 
                              'category_id': classidx, 
                              'ignore': 0, 
                              'segmentation': [], 
                              'image_id': imgcountidx, 
                              'id': idxcount})
        imgcountidx += 1#validxcount = 0imgcountidx = 0JumpData_val = {}
imagelist_val = []
labellist_val = []for idx, imagename in enumerate(os.listdir('data/JumpData/Image')[179:199]):
    imagelist_val.append({'file_name': imagename, 'height': 600, 'width': 1080, 'id': idx})
    jsonname = os.path.splitext(imagename)[0] + '.json'
    with open(os.path.join('data/JumpData/Label', jsonname)) as f:
        data = json.load(f)        for label in data['labels']:
            x1 = label['x1']
            y1 = label['y1']
            w = label['x2'] - label['x1']
            h = label['y2'] - label['y1']
            area = (w * h)            if label['name'] == 'platform':
                classidx = 2
            else:
                classidx = 1
            idxcount += 1
            labellist_val.append({'area': area, 
                              'iscrowd': 0, 
                              'bbox': [x1, y1, w, h], 
                              'category_id': classidx, 
                              'ignore': 0, 
                              'segmentation': [], 
                              'image_id': imgcountidx, 
                              'id': idxcount})
        imgcountidx += 1JumpData_train['images'] = imagelist_train
JumpData_train['type'] = 'instances'JumpData_train['annotations'] = labellist_train
JumpData_train['categories'] = classlist

JumpData_val['images'] = imagelist_val
JumpData_val['type'] = 'instances'JumpData_val['annotations'] = labellist_val
JumpData_val['categories'] = classlist
json.dump(JumpData_train, open('data/JumpData/Anno/JumpData_train.json', 'w'), indent=4)
json.dump(JumpData_val, open('data/JumpData/Anno/JumpData_val.json', 'w'), indent=4)
登录后复制

二、开始训练

 使用PPYOLO_Tiny进行训练,配置文件请见work/Config/Yml文件夹

In [29]
#模型训练!export CUDA_VISIBLE_DEVICES=0!python work/PaddleDetection/tools/train.py 
    -c work/Config/Yml/PPYOLO_TINY_JUMP.yml 
    --eval
登录后复制

三、效果验证

In [31]
#模型预测!python work/PaddleDetection/tools/infer.py 
    -c work/Config/Yml/PPYOLO_TINY_JUMP.yml 
    -o weights=work/output/PPYOLO_TINY_JUMP/best_model.pdparams 
    --infer_img=work/Config/screen.png 
    --draw_threshold=0.5 
    --output_dir=work/imgresult
登录后复制

四、模型导出

In [ ]
#导出模型!python work/PaddleDetection/tools/export_model.py 
    -c work/Config/Yml/PPYOLO_TINY_JUMP.yml 
    -o weights=work/output/PPYOLO_TINY_JUMP/best_model.pdparams 
    --output_dir=work/inference_model
登录后复制
In [ ]
#模型预测(导出后)!python work/PaddleDetection/deploy/python/infer.py 
    --model_dir=work/inference_model/PPYOLO_TINY_JUMP 
    --image_file=work/Config/screen.png 
    --output_dir=work/inferenceresult
登录后复制

五、模型部署

电脑根据模型得出的结果将坐标距离转化为屏幕按压时间,然后对51单片机发出指令,下面给出上位机代码以及51单片机的汇编代码,完整上位机包已在work/UARTServo.zip给出,汇编代码直接导进Keil中编译成HEX文件烧录至单片机内即可

1. 上位机代码

In [ ]
import osimport cv2import timeimport serialimport paddlefrom Predict import PredictConfig, Detector, predict_imagedef getscreen():
    os.system("adb shell rm /sdcard/screen.png")
    os.system("del C:\Users\Blang\Desktop\screen.png") 
    os.system("adb shell screencap -p /sdcard/screen.png")      
    os.system("adb pull /sdcard/screen.png C:/Users/Blang/Desktop")
    img = cv2.imread('C:/Users/Blang/Desktop/screen.png')
    img = img[850:1450, :]    return img    
def getposition(image_file):
    paddle.enable_static()
    threshold = 0.5
    model_dir = 'inference_model/PPYOLO_TINY_JUMP'
    pred_config = PredictConfig(model_dir)
    detector = Detector(pred_config, model_dir)
    results = predict_image(detector, image_file, threshold)    return results    
def calculate(results):
    player_position = []
    platform_position = []    for result in results:
        classid = result[0]
        xmin = result[2]
        ymin = result[3]
        xmax = result[4]
        ymax = result[5]
        w = xmax - xmin
        h = ymax - ymin        if classid == 0:
            player_x = xmin + w / 2
            player_y = ymax
            player_position.append([player_x, player_y])        else:
            platform_x = xmin + w / 2
            platform_y = ymax
            platform_position.append([platform_x, platform_y])    for player in player_position:        for platform in platform_position:            if player[1] < platform[1]:                continue
            else:
                player_x = player[0]
                player_y = player[1]
                platform_x = platform[0]
                platform_y = platform[1]
    distance = ((platform_x - player_x)**2 + (platform_y - player_y)**2)**0.5
    presstime = distance * 1.5 + 200
    presstime = presstime * 0.001
    return presstimedef sendcommand(presstime):
    ser=serial.Serial("COM5", 2400, timeout=5)
    result=ser.write(chr(0x32).encode("utf-8"))
    time.sleep(presstime)
    result=ser.write(chr(0x31).encode("utf-8"))
    ser.close()
    time.sleep(1)    
while True:
    img = getscreen()
    results = getposition(img)
    presstime = calculate(results)
    sendcommand(presstime)
登录后复制

2. 汇编代码

In [ ]
	ORG 	0000H
	LJMP 	MAIN
	ORG		000BH
	LJMP	Timer0Interrupt
	ORG 	0023H
	LJMP 	UARTInterrupt
	ORG     0100H
MAIN:
	LCALL	InitAll
	LCALL 	InitTimer0
	LCALL 	InitUART
	LCALL	PWM
	LJMP MAIN
/***********************************/
InitAll:
	MOV		R7, #50D
	MOV 	SP, #60H
	MOV 	TMOD, #22H/***********************************/
InitTimer0:
    MOV TH0, #0A4H
    MOV TL0, #0A4H
    SETB EA
    SETB ET0
    SETB TR0
	SETB P3.5
	SETB P3.6
	RET
PWM:
	MOV 	A, #200D
	SUBB 	A, R1
	MOV 	R2, A
	MOV 	A, R1
	MOV 	R0, A
DELAY:
	CJNE 	R0, #00H, $
	CLR 	P3.5
	CLR 	P3.6
	MOV 	A, R2
	MOV 	R0, A
	CJNE 	R0, #00H, $
	SETB 	P3.5
	SETB	P3.6
	MOV 	A, R1
	MOV 	R0, A
	DJNZ 	R7, DELAY
    RET
Timer0Interrupt:
	DEC 	R0
    RETI
/***********************************/
InitUART:
	MOV 	SCON, #50H
	MOV 	TH1, #0F3H
	MOV 	TL1, TH1
	MOV 	PCON, #00H
	SETB 	EA
	SETB 	ES
	SETB 	TR1
	RET
UARTInterrupt:
	CLR     ES
	PUSH 	ACC
	JB 		RI, Is_Receive
	RETI
Is_Receive:
	CLR 	RI
	MOV 	A, SBUF
	CJNE    A, #31H, NEXT_POSITION
	MOV 	R1, #8D NEXT_POSITION:
	CJNE    A, #32H, GOBACK
	MOV 	R1, #20DGOBACK:
	SETB    ES
	POP 	ACC
	RETI
/***********************************/
END
登录后复制

以上就是【PaddleDetection】结合51单片机搭建微信跳一跳物理外挂的详细内容,更多请关注php中文网其它相关文章!

微信app下载
微信app下载

微信是一款手机通信软件,支持通过手机网络发送语音短信、视频、图片和文字。微信可以单聊及群聊,还能根据地理位置找到附近的人,带给大家全新的移动沟通体验,有需要的小伙伴快来保存下载体验吧!

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号