You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派中Python Mido无法检测MIDI键盘输入问题求助

解决树莓派上MIDI输入无法触发GPIO控制的问题

核心问题定位

你的代码在树莓派上无法触发MIDI消息处理逻辑,大概率是因为mido.open_input()默认连接了Midi Through虚拟设备,而非实际的CASIO MIDI键盘,导致inport.iter_pending()读不到任何真实消息。另外,time.sleep(1)的阻塞式写法也会导致主循环响应异常。


具体修复步骤

1. 显式指定MIDI输入设备

先运行以下代码列出所有可用的MIDI输入设备:

import mido
print(mido.get_input_names())

你会看到类似输出:

['Midi Through Port-0', 'CASIO USB-MIDI MIDI 1']

然后修改原代码中的inport = mido.open_input()为:

inport = mido.open_input("CASIO USB-MIDI MIDI 1")  # 替换为你的设备名称

这样就能确保mido连接到真实的MIDI键盘。

2. 替换阻塞式的time.sleep(1)

原代码中的time.sleep(1)会完全阻塞主循环,导致在这1秒内无法读取新的MIDI消息,改用非阻塞的计时逻辑:

# 初始化计时变量
gpio_on_time = 0
gpio_active = False

while not done:
    # 处理MIDI消息
    for msg in inport.iter_pending():
        print("收到消息:", msg)  # 先打印所有消息,确认能正常接收
        try:
            n = msg.note
        except AttributeError:
            continue
        if msg.type == 'note_on' and msg.velocity > 0 and msg.velocity != 64:
            GPIO.output(4, True)
            gpio_on_time = time.time()
            gpio_active = True
        elif msg.type == 'note_off' or (msg.type == 'note_on' and msg.velocity == 0):
            outport.send(mido.Message('note_off', note=n))
    # 非阻塞判断是否需要关闭GPIO
    if gpio_active and time.time() - gpio_on_time >= 1:
        GPIO.output(4, False)
        gpio_active = False

3. 检查MIDI设备权限

确保运行脚本的用户有访问MIDI设备的权限,执行以下命令将用户加入audio组:

sudo usermod -a -G audio $USER

重启树莓派后生效。

4. 完善Pygame事件处理

原代码初始化了Pygame但未处理事件队列,可能导致主循环异常,添加事件处理逻辑:

while not done:
    # 处理Pygame退出事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True
    # 后续的MIDI和GPIO处理逻辑...

完整修复后的代码

import pygame
import mido
import time
import RPi.GPIO as GPIO

pygame.init()
GPIO.setmode(GPIO.BCM)
GPIO.setup(4, GPIO.OUT)
GPIO.output(4, False)

# 列出并指定MIDI输入设备
input_devices = mido.get_input_names()
print("可用MIDI输入设备:", input_devices)
inport = mido.open_input("CASIO USB-MIDI MIDI 1")
outport = mido.open_output()

done = False
gpio_on_time = 0
gpio_active = False

print("START!")
while not done:
    # 处理Pygame退出事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True
    # 处理MIDI消息
    for msg in inport.iter_pending():
        print("收到MIDI消息:", msg)
        try:
            n = msg.note
        except AttributeError:
            continue
        if msg.type == 'note_on' and msg.velocity > 0 and msg.velocity != 64:
            print("触发GPIO,速度:", msg.velocity)
            GPIO.output(4, True)
            gpio_on_time = time.time()
            gpio_active = True
        elif msg.type == 'note_off' or (msg.type == 'note_on' and msg.velocity == 0):
            outport.send(mido.Message('note_off', note=n))
    # 非阻塞关闭GPIO
    if gpio_active and time.time() - gpio_on_time >= 1:
        GPIO.output(4, False)
        gpio_active = False

# 清理资源
GPIO.cleanup()
pygame.quit()

内容的提问来源于stack exchange,提问作者Monty Swanson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 13:03:10