本部分介绍如何在树莓派中捕获键盘输入 配上运动控制,达成无线键盘遥控小车

#####硬件准备
一块无线键盘。当时买了套餐里面的一块非常小巧的无线键盘 + 触摸板:

#####获取输入设备
虽然文章的标题是 Raspberry Pi,不过其实这部分内容适用于大多数 Linux 系统。


在 Linux 中,一切皆文件,包括我们的硬件设备。键盘鼠标等作为一种标准输入输出设备,在Linux 系统中也同样是以文件的形式存在的。这些设备文件,就存在于 /dev/ 下,所以我们需要做的就是从这里读取指定的键盘设备文件了。


这里需要使用到linux的驱动–input输入子系统evdev。evdev 输入事件驱动,为输入子系统提供了一个默认的事件处理方法。其接收来自底层驱动的大多数事件,并使用相应的逻辑对其进行处理。evdev 输入事件驱动从底层接收事件信息,将其反映到 sys 文件系统中,用户程序通过对 sys 文件系统的操作,就能够达到处理事件的能力。(from s0nnet.com)


在 Linux 内核中,input 设备用 input_dev 结构体描述,使用 input 子系统实现输入设备驱动的时候,驱动的核心工作就是向系统报告按键、触摸屏、键盘、鼠标等输入事件(event,通过 input_event 结构体描述),不再需要关心文件操作接口,因为 Input 子系统已经完成了文件操作接口。


在系统的 input.h 这个文件(/usr/include/linux/input.h)里面,定义了 event 事件的结构体,API 跟标准按键的编码:

1
2
3
4
5
6
struct input_event {
struct timeval time; //按键时间
__u16 type; //事件类型
__u16 code; //模拟的按键
__s32 value; //是按下还是释放
};
  • type:指事件类型。在这里咱们研究的是:按键事件,当然还有其他事件(比如鼠标事件等)
  • code:事件的代码。这里只讨论按键事件,其类型代码code是EV_KEY,该代码为设备键盘代码。在该文头文件中已经定义的0~248种不同的键盘按键代码(详细见linux/input.h文件)
  • value:事件的值。同样,咱们讨论事件的类型代码是EV_KEY,当按键按下时值为1,松开时值为0


接下来需要安装 python 的 evdev 模块来获取设备输入。根据官方文档说明,evdev模块使用比较简单。最新版本的python-evdev模块可以使用pip安装。pip 是安装各种 python 库的好工具:

1
sudo pip install evdev

当然,安装之前需要Linux系统具有gcc/clang,并具有python环境和Linux内核头文件支持,官方文档中有详细介绍。


安装完成之后,可以测试一下。在管理员权限下运行 python 交互式输入程序,列举所有事件驱动设备:


更多详细的使用例子可以参考 https://python-evdev.readthedocs.org 网站上给的样例教程,很常全面。利用这些设备文件可以做很多硬件调用方面的开发,当然写个远程控制都可以,比如控制摄像头、麦克风、鼠标、键盘等等。

#####捕获键盘输入
由于我的设备是键盘跟鼠标一体的,所以鼠标输入事件跟键盘输入事件对应的 device name 是一样的,于是我还得写个程序具体测试一下,看读取哪个 event 时会对键盘操作做出响应:

1
2
3
4
5
6
7
8
9
#from s0nnet.com
from evdev import InputDevice
from select import select

dev = InputDevice('/dev/input/event0')
while True:
select([dev], [], [])
for event in dev.read():
print 'code:%s value:%s' % (event.code, event.value)

其中select的作用是等待dev改变后再运行后面的代码,dev.read()返回的是buffer数组,里面存有input_event类型数据。


root权限运行,发现上面代码运行时的结果很难识别出来,因为按一个键会出现6组结果。它的code值就是输入的键值,键盘上的每一个按键都对应了一个键值码。而value就是其对应的状态,当按下一个键时,value为1,松开时value值为0。所以这里我们可以做个简单的处理:

1
2
3
4
5
6
7
8
9
from evdev import InputDevice
from select import select

dev = InputDevice('/dev/input/event0')
while True:
select([dev], [], [])
for event in dev.read():
if (event.value == 1 or event.value == 0) and event.code != 0:
print "Key:%s Status:%s" % (event.code, "pressed." if event.value else "release.")

在这个核心代码的基础上做修改,就可以实现键盘记录程序了,原文作者已经编写了一个 smaple,放在了 Github 上面


于是再结合上一篇文章介绍的小车运动控制,就可以做出无线键盘遥控小车了。注意这里有个小问题,因为一旦开始键盘监控,程序就会进入循环,退出只能利用 ctrl+c 的方式,那么怎么执行 gpio.cleanup() 来清理 gpio 呢。可以这样:

1
2
3
4
5
6
7
if __name__ == '__main__':
try:
#run your code
except BaseException, e:
print(e)
finally:
gpio.cleanup()


下一篇介绍利用 Socket 在手机跟 Pi 之间通信,达成远程操控。

#####参考资料
1.Linux下的键盘记录程序
2.使用Python获取/dev/input目录下event对应的设备
3.使用 /sys 文件系统访问 Linux 内核


系列上一篇:Raspberry Pi 小车移动监控II — 运动控制
工程源代码:Github地址