Python键盘监听+多线程

Python实现键盘监听与多线程应用
本文详细介绍了如何在Python中实现键盘监听功能,并结合多线程技术,实现同时处理多个任务。通过创建线程,确保在监听键盘事件的同时,不影响其他程序流程的执行。这对于需要实时响应用户输入的项目非常有用。
__author__ = 'tjt'
# bin
import datetime
import threading
import time
from pynput.keyboard import Listener
import kb_upper

event = threading.Event()  # 实例化事件
time_map = {
    'start_time': 0.0,
    'end_time': 0.0,
    'total_time': 0.0,
    'odd_even': True,
    'count': 0
}


def listen_kb():
    ''' 循环监听键盘输入'''
    # while True:
    def on_press(key):
        try:
            nowTime = datetime.datetime.now().strftime('%H:%M:%S')
            s_press = format(key.char)
            print("正在按压:", s_press, "时间:", nowTime)
            if s_press in ('k', 'K'):
                start_time = time.time()
                time_map['start_time'] = start_time
                event.set()  # 设置标志位,以`K`开始
            elif s_press in ('j', 'J'):
                event.clear()  # 清除标志位,以`J`挂起
            # elif key == Key.esc:  # ESC停止
            #     sys.exit()
        except AttributeError:
            print("正在按压:", format(key))

    # 监听释放
    def on_release(key):
        nowTime = 
<think> 我们正在处理一个关于Python多线程环境下实现键盘控制机器人的问题。根据用户提供的引用,特别是引用[1]和引用[2],我们可以从中提取有用的信息。 引用[1]提到了PyQt和QML中的键盘过滤器,用于捕获Ctrl键作为紧急停止功能,并实现了三层键盘事件处理机制。这提示我们在GUI环境下(如PyQt)可以通过键盘事件过滤机制来处理键盘输入。 引用[2]提到了使用pywin32实现键盘监听,并且作者认为pywin32的方法比PLC+opencv和pyqt5+opencv更快。这为我们提供了另一种在Windows平台下监听键盘事件的方法。 然而,用户的问题是多线程环境下实现键盘控制机器人。这意味着我们需要考虑如何在多线程中处理键盘输入,同时控制机器人(可能是通过另一个线程发送控制指令)。 考虑到机器人控制通常需要实时响应,我们可能需要一个线程专门监听键盘输入,另一个线程执行机器人控制指令。同时,需要注意线程间的通信(例如使用队列)以及避免资源竞争。 我们可以设计如下: 1. 创建一个键盘监听线程,用于捕获用户的键盘输入(例如使用pywin32或PyQt的键盘事件)。 2. 创建一个机器人控制线程,根据键盘监听线程传来的指令控制机器人。 3. 使用线程安全的队列(如queue.Queue)在两个线程之间传递指令。 但是,需要注意的是,在GUI程序中(如PyQt),主线程通常用于处理GUI事件,而键盘事件处理通常也在主线程中。如果我们使用非GUI的方式(如控制台应用),则可以使用pywin32或keyboard模块(非标准库)来监听键盘事件。 这里我们选择使用`keyboard`模块,因为它是一个跨平台的Python库,可以监听和发送键盘事件,并且支持多线程。如果用户没有安装,可以通过`pip install keyboard`安装。 下面是一个示例代码框架: ```python import threading import queue import keyboard # 需要安装 # 机器人控制类,这里用模拟的控制方法 class RobotController: def __init__(self): self.running = True def execute_command(self, command): # 根据命令执行相应的机器人控制 if command == 'up': print("前进") elif command == 'down': print("后退") elif command == 'left': print("左转") elif command == 'right': print("右转") elif command == 'stop': print("停止") # 其他命令... # 键盘监听函数,将按键映射为命令 def keyboard_listener(command_queue): # 设置按键映射 key_map = { 'up': 'up', 'down': 'down', 'left': 'left', 'right': 'right', 'space': 'stop' } # 注册按键事件 for key, command in key_map.items(): keyboard.add_hotkey(key, lambda c=command: command_queue.put(c)) # 阻塞当前线程,直到按下esc键 keyboard.wait('esc') # 机器人控制线程函数 def robot_control_thread(command_queue, controller): while controller.running: try: # 从队列中获取命令,阻塞时间为0.1秒 command = command_queue.get(timeout=0.1) controller.execute_command(command) except queue.Empty: # 如果队列为空,继续循环 continue if __name__ == "__main__": command_queue = queue.Queue() controller = RobotController() # 启动键盘监听线程 listener_thread = threading.Thread(target=keyboard_listener, args=(command_queue,)) listener_thread.daemon = True # 设置为守护线程,主程序结束则结束 listener_thread.start() # 启动机器人控制线程 control_thread = threading.Thread(target=robot_control_thread, args=(command_queue, controller)) control_thread.start() # 主线程等待键盘监听线程结束(按esc键) listener_thread.join() # 停止机器人控制器 controller.running = False # 等待控制线程结束 control_thread.join() print("程序已退出") ``` 上述代码中: - 使用`keyboard`模块来监听按键,当按下方向键或空格键时,将对应的命令放入队列。 - 机器人控制线程不断从队列中取出命令并执行。 - 按下ESC键后,键盘监听线程结束,进而主线程设置控制器停止标志,等待控制线程结束。 注意:`keyboard`模块在Linux系统可能需要root权限,在Windows和macOS上通常不需要。 另外,用户提到引用[1]中的紧急停止功能(Ctrl键)。我们可以扩展上面的代码,添加一个全局的紧急停止事件。当按下Ctrl键时,触发紧急停止,所有线程立即停止并退出。 改进后的代码: ```python import threading import queue import keyboard import time # 全局紧急停止事件 emergency_stop = threading.Event() class RobotController: def __init__(self): pass def execute_command(self, command): if emergency_stop.is_set(): return # 如果紧急停止被触发,忽略所有命令 if command == 'up': print("前进") elif command == 'down': print("后退") elif command == 'left': print("左转") elif command == 'right': print("右转") elif command == 'stop': print("停止") # 其他命令... def keyboard_listener(command_queue): key_map = { 'up': 'up', 'down': 'down', 'left': 'left', 'right': 'right', 'space': 'stop' } for key, command in key_map.items(): keyboard.add_hotkey(key, lambda c=command: command_queue.put(c)) # 注册紧急停止快捷键,例如Ctrl+E keyboard.add_hotkey('ctrl+e', emergency_stop.set) # 等待紧急停止事件或者按下esc while not emergency_stop.is_set(): time.sleep(0.1) # 这里我们也可以等待ESC键,但为了简单,我们通过紧急停止事件来退出 print("紧急停止已触发") def robot_control_thread(command_queue, controller): while not emergency_stop.is_set(): try: command = command_queue.get(timeout=0.1) controller.execute_command(command) except queue.Empty: continue # 紧急停止后执行清理操作 print("机器人停止") if __name__ == "__main__": command_queue = queue.Queue() controller = RobotController() listener_thread = threading.Thread(target=keyboard_listener, args=(command_queue,)) listener_thread.daemon = True listener_thread.start() control_thread = threading.Thread(target=robot_control_thread, args=(command_queue, controller)) control_thread.start() # 等待紧急停止事件 emergency_stop.wait() # 设置后,所有线程将自行退出 listener_thread.join(timeout=0.1) # 由于是守护线程,通常会很快退出 control_thread.join(timeout=0.1) print("程序已退出") ``` 这样,我们就实现了多线程下的键盘控制机器人,并增加了紧急停止功能。 需要注意的是,实际机器人控制中,执行命令可能涉及到硬件操作,因此在紧急停止时,除了忽略命令队列,可能还需要立即发送一个停止指令给机器人(例如在触发紧急停止事件时,在`RobotController`中添加一个`emergency_stop`方法,并在设置全局事件后立即调用该方法)。此外,线程间的同步和资源释放也需要仔细考虑。 最后,根据引用[4]中提到的跨平台兼容性,我们使用的`keyboard`模块是跨平台的,因此该方案可以在Windows、Linux和macOS上运行(注意权限问题)。 以上代码提供了一种实现方式,用户可以根据实际机器人的控制接口进行调整。 </think> ### Python多线程实现键盘控制机器人的方法 在Python中实现多线程环境下的键盘控制机器人,需要结合**键盘监听**和**多线程协同**技术。以下是详细实现方案: #### 1. 键盘监听线程实现 ```python import threading import keyboard # 需安装:pip install keyboard def key_listener(stop_event, command_queue): """键盘监听线程函数""" key_bindings = { 'w': 'forward', 's': 'backward', 'a': 'left', 'd': 'right', 'space': 'stop', 'ctrl': 'emergency_stop' } while not stop_event.is_set(): key = keyboard.read_event(suppress=True).name if key in key_bindings: command = key_bindings[key] command_queue.put(command) # 将命令放入队列 if command == 'emergency_stop': stop_event.set() # 触发紧急停止 ``` #### 2. 机器人控制线程实现 ```python def robot_controller(stop_event, command_queue): """机器人控制线程函数""" from explorerhat import motor # 假设使用Explorer HAT Pro控制电机[^3] while not stop_event.is_set(): if not command_queue.empty(): cmd = command_queue.get() if cmd == 'forward': motor.one.forward(100) # 前进 elif cmd == 'backward': motor.one.backward(100) # 后退 elif cmd == 'left': motor.two.forward(100) # 左转 elif cmd == 'right': motor.two.backward(100) # 右转 elif cmd == 'stop': motor.one.stop() # 停止 motor.two.stop() elif cmd == 'emergency_stop': motor.one.stop() motor.two.stop() break # 立即退出线程 ``` #### 3. 主程序框架 ```python if __name__ == "__main__": import queue from explorerhat import touch # 电容式触摸板初始化[^3] # 创建线程间通信组件 stop_event = threading.Event() command_queue = queue.Queue(maxsize=10) # 创建线程 keyboard_thread = threading.Thread( target=key_listener, args=(stop_event, command_queue), daemon=True ) robot_thread = threading.Thread( target=robot_controller, args=(stop_event, command_queue) ) # 启动线程 keyboard_thread.start() robot_thread.start() # 主线程监控 try: robot_thread.join() print("机器人控制已安全停止") except KeyboardInterrupt: stop_event.set() print("程序被用户中断") ``` #### 关键技术点: 1. **多线程通信**: - 使用`queue.Queue`实现线程安全的命令传递 - 采用`threading.Event`进行全局状态同步 2. **冗余安全机制**: - 三层停止保障:常规停止(`space`)、程序中断(`Ctrl+C`)、紧急停止(`Ctrl`)[^1] - 电容式触摸板作为物理急停备用方案[^3] 3. **实时响应优化**: ```python keyboard.add_hotkey('ctrl', lambda: command_queue.put('emergency_stop')) ``` 为紧急停止注册独立热键,避免按键检测延迟 4. **资源管理**: - 设置队列容量防止内存溢出 - 使用`daemon=True`确保监听线程随主程序退出 #### 扩展建议: 1. 添加**操作日志**记录关键指令和时间戳 2. 实现**速度分级控制**(如`Shift`+方向键加速) 3. 增加**网络通信模块**支持远程监控[^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值