树莓派读取条码扫码枪

        平时用的最多的扫描枪通常只是一个简单的输入设备(好比键盘,鼠标), 另一头需要连接电脑, 用的 usb 或者串口. 扫描枪负责识别条码, 电脑收到后执行业务的逻辑. 有时候只是简单的数据采集工作, 数据传到服务器云端, 放台电脑在那儿显得浪费而且需要昂贵的维护. 而小巧灵活而且价格低廉的树莓派同学马上举手说: “我可以!”

        可能你已经想到了, 用图形界面不是很 easy 吗? 是的, 但不是最好的办法. 即使目前最新版树莓派 4B 的性能对于图形界面来说只能算得上及格. 我们的目标是后台进程接受录入, 开机即用.

实验用到的设备

带 USB 接收器的条码扫描枪 

带 USB 接收器的条码扫描枪

树莓派 4b

树莓派 4b

我们将用到 python-evdev 程序库, 封装了对 usb 设备的读写操作. 官网 https://python-evdev.readthedocs.io/

安装 evdev

sudo pip install evdev

编写代码

简单几行代码检测 usb 设备:

#!/usr/bin/python3

import evdev

# 列出 usb 设备
devices = [evdev.InputDevice(path) for path in evdev.list_devices()]

print('发现设备: ')
for device in devices:
  print(device.path, device.name, device.phys)

执行结果:

发现设备:
/dev/input/event0 Netum. HIDKB usb-0000:01:00.0-1.3/input0

显示成功读到了扫描枪设备. 接下来要读取扫描枪的输入了. 修改前面的代码

#!/usr/bin/python3

import asyncio, evdev

# 检测到输入时触发
async def print_events(device):
  async for event in device.async_read_loop():
    print(device.path, evdev.categorize(event), sep=': ')

# 列出 usb 设备
devices = [evdev.InputDevice(path) for path in evdev.list_devices()]

print('发现以下设备: ')
for device in devices:
  print(device.path, device.name, device.phys)

for device in devices:
  # 用 asyncio 同时接受多个设备的录入
  asyncio.ensure_future(print_events(device))

loop = asyncio.get_event_loop()
loop.run_forever()
为了兼容多个设备的输入用到了  asyncio, 异步执行单个设备的事件循环, 这样就不会因为一个设备的输入 block 住其他设备.
运行看看效果:
发现以下设备: 
/dev/input/event0 Netum. HIDKB usb-0000:01:00.0-1.3/input0
/dev/input/event0: event at 1584874459.655187, code 00, type 17, val 01
/dev/input/event0: event at 1584874459.655187, code 04, type 04, val 458787
/dev/input/event0: key event at 1584874459.655187, 7 (KEY_6), down
/dev/input/event0: synchronization event at 1584874459.655187, SYN_REPORT 
/dev/input/event0: event at 1584874459.656157, code 04, type 04, val 458787
/dev/input/event0: key event at 1584874459.656157, 7 (KEY_6), up
/dev/input/event0: synchronization event at 1584874459.656157, SYN_REPORT 
/dev/input/event0: event at 1584874459.657169, code 04, type 04, val 458790
/dev/input/event0: key event at 1584874459.657169, 10 (KEY_9), down
/dev/input/event0: synchronization event at 1584874459.657169, SYN_REPORT 
/dev/input/event0: event at 1584874459.658158, code 04, type 04, val 458790
/dev/input/event0: key event at 1584874459.658158, 10 (KEY_9), up
………….

把每个按键的详细事件打印出来了. 说明成功接收到输入了. 还差一步, 把按键的内容转换成字符串. 继续修改代码:

#!/usr/bin/python3

import asyncio, evdev

# 按键转字符表 只列出了常用的字符
keymap = {
    'KEY_0': u'0',
    'KEY_1': u'1',
    'KEY_2': u'2',
    'KEY_3': u'3',
    'KEY_4': u'4',
    'KEY_5': u'5',
    'KEY_6': u'6',
    'KEY_7': u'7',
    'KEY_8': u'8',
    'KEY_9': u'9',
    'KEY_A': u'A',
    'KEY_B': u'B',
    'KEY_C': u'C',
    'KEY_D': u'D',
    'KEY_E': u'E',
    'KEY_F': u'F',
    'KEY_G': u'G',
    'KEY_H': u'H',
    'KEY_I': u'I',
    'KEY_J': u'J',
    'KEY_K': u'K',
    'KEY_L': u'L',
    'KEY_M': u'M',
    'KEY_N': u'N',
    'KEY_O': u'O',
    'KEY_P': u'P',
    'KEY_Q': u'Q',
    'KEY_R': u'R',
    'KEY_S': u'S',
    'KEY_T': u'T',
    'KEY_U': u'U',
    'KEY_V': u'V',
    'KEY_W': u'W',
    'KEY_X': u'X',
    'KEY_Y': u'Y',
    'KEY_Z': u'Z',
    'KEY_TAB': u'\t',
    'KEY_SPACE': u' ',
    'KEY_COMMA': u',',
    'KEY_SEMICOLON': u';',
    'KEY_EQUAL': u'=',
    'KEY_LEFTBRACE': u'[',
    'KEY_RIGHTBRACE': u']',    
    'KEY_MINUS': u'-',
    'KEY_APOSTROPHE': u'\'',
    'KEY_GRAVE': u'`',
    'KEY_DOT': u'.',
    'KEY_SLASH': u'/',
    'KEY_BACKSLASH': u'\\',
    'KEY_ENTER': u'\n',
}

# 检测到输入时触发
async def print_events(device):
    buf = ''
    async for event in device.async_read_loop():
        # key_up= 0 key_down= 1 key_hold= 2
        if event.type == evdev.ecodes.EV_KEY and event.value == 1:
            kv = evdev.events.KeyEvent(event)
            # 本次修改的地方, 把事件映射到字符表
            if (kv.scancode == evdev.ecodes.KEY_ENTER):
              print('读到输入: ', buf)
                '''
                业务逻辑
                '''
                # 清空 buffer
                buf = ''
            else:
                buf += keymap.get(kv.keycode)

devices = [evdev.InputDevice(path) for path in evdev.list_devices()]
print('发现以下设备: ')
for device in devices:
print(device.path, device.name, device.phys)

for device in devices:
asyncio.ensure_future(print_events(device))

loop = asyncio.get_event_loop()
loop.run_forever()

再来运行代码, 顺利拿到条码内容了.

增加点难度, 这次测试还加入了键盘, 效果棒棒哒.

以上实验全部代码都在 https://gitee.com/csling/ban-scanner

写在最后

如果你想把这个用到实际生产中, 然而还有许多问题要考虑, 比如动态添加和移除 usb 设备. 了解更多请关注我的公众号, 也欢迎留下你的想法.

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页