通过Linux::IRPulses解析红外代码来控制疯狂

使用脉冲式不可见光发送信息可能非常复杂。使用LIRC和Linux::IRPulses来解开这个问题。
红外遥控器是那些制造商都认为他们有“唯一真正的方法™”去做的事情之一。你可能认为只有一种或两种简单的方式来脉冲一点红外光。显然,我们都错了,因为家庭娱乐行业一直在发明新的方法。这还不包括其他行业和爱好项目,它们提出了完全不同的方法。
Linux红外遥控 (LIRC) 项目为很多遥控器提供了映射。但这对于一些边缘设备没有帮助。此外,堆栈顶部的某些组件更倾向于在检测到有效的脉冲序列后执行程序。
如果我们更愿意在我们的程序中处理脉冲,那么我们需要忽略LIRC的上层,并直接解析脉冲数据。这正是Linux::IRPulses所做的事情。
我们首先需要硬件来检测脉冲。在普通电脑上,有许多模块可供使用,可以插入USB端口。在像树莓派这样的单板电脑上,我们有通用输入/输出(GPIO)引脚,可以读取脉冲的定时。
设置树莓派
如果你使用的是常规红外设备,请跳过此部分。如果你想设置树莓派GPIO引脚上的模块,请继续阅读。
首先,你需要一个正确频率的模块来接收你正在尝试接收的红外数据。如果你使用的是旧电视的遥控器,那么搜索“
TSOP38138是一个38KHz的红外遥控接收器。它是不同频率设备家族的一部分,其中任何一个都可能足够。
用于拾取遥控数据的红外接收器有三个引脚:电源、接地和数据。将电源连接到树莓派的+3.3V引脚,将接地连接到接地,将数据连接到GPIO 23。有关引脚位置,请参阅树莓派GPIO文档。
现在我们需要配置LIRC。首先,使用apt-get install lirc
进行简单安装。接下来,我们需要加载内核模块,告诉LIRC引脚的位置,并配置一些树莓派启动选项。
在/etc/modules-load.d/modules.conf
中,放入以下内容:
lirc_dev
lirc_rpi gpio_in_pin=23 gpio_out_pin=22
这将使GPIO 23成为你的输入引脚。LIRC也可以设置来发送红外数据,所以我们在这里将GPIO 22设置为该目的。接下来,修改/etc/lirc/hardware.conf
# /etc/lirc/hardware.conf
#
# Arguments which will be used when launching lircd
LIRCD_ARGS="--uinput"
#Don't start lircmd even if there seems to be a good config file
#START_LIRCMD=false
#Don't start irexec, even if a good config file seems to exist.
#START_IREXEC=false
#Try to load appropriate kernel modules
LOAD_MODULES=true
# Run "lircd --driver=help" for a list of supported drivers.
DRIVER="default"
# usually /dev/lirc0 is the correct setting for systems using udev
DEVICE="/dev/lirc0"
MODULES="lirc_rpi"
# Default configuration files for your hardware if any
LIRCD_CONF=""
LIRCMD_CONF=""
这里特别重要的是DEVICE
(设备路径)和MODULES
(树莓派GPIO驱动程序)。
最后,编辑/boot/config.txt
并在文件中添加以下内容:
dtoverlay=lirc-rpi,gpio_in_pin=23,gpio_out_pin=22
然后重启。一旦重启,你可以通过将红外模块插入正确的引脚并对准它来测试它。使用mode2 -d /dev/lirc0
,你应该会看到发送的pulse
和space
数据。
解码不可解码的内容
索尼的遥控器使用40KHz的频率。它通过发送2400μs的脉冲和600μs的空间作为头部开始。在头部之后,通过1200μs的脉冲发送1位,通过600μs的空间发送0。这些1和0之间是600μs的空间。代码的长度可能是12、15或20位,具体取决于遥控器。这已经是相当直接的了。
NEC使用38KHz的载波频率。头部后面跟着9000μs的空间。1位通过562.5μs的脉冲发送。0位也通过562.5μs的脉冲发送。等等,这是什么?不,这不是打字错误。NEC通过脉冲后的空间长度来区分1和0:1为1687.5μs,0为562.5μs。
EasyRaceLapTimer(一个开源的多旋翼赛车计时系统)使用38KHz的频率。它发送300μs的脉冲和300μs的空间。然后交替发送脉冲和空间,1位为600μs,0位为300μs。
上面所有的计时数字都是大错特错。这个嘈杂的、模拟的世界性质意味着来自红外接收器的实际值将与指定值不同,可能多达15%。可以安全地假设反向工程规格只是对制造商意图的实际值进行猜测。
总之,我们面前有一项复杂的工作,上面的内容只是涵盖了其中的一些例子。
Linux::IRPulses
该模块的目标是简化读取这些脉冲和空间的过程,同时容忍数值的不准确。
目前,该模块通过解析LIRC的mode2
程序输出工作。这可能会在未来改为直接从/dev/lirc0
读取。现在,我们将从打开到mode2
的管道开始。
open( my $in, '-|', 'mode2 -d /dev/lirc0' ) or die "Can't exec mode2: $!\n";
我们现在需要定义Linux::IRPulses构造函数的协议。为此,添加use Linux::IRPulses
将导出子例程pulse()
、space()
和pulse_or_space()
。这些用于指定您期望接收的脉冲或空间。
例如,我们知道NEC发送9000μs的脉冲和4500μs的空间作为其头部。我们通过以下方式告诉构造函数:
my $ir = Linux::IRPulses->new({
header => [ pulse 9000, space 4500 ],
...
});
解析器遍历数组的每个条目,检查给定的脉冲或空间数据是否符合预期。一旦它到达头部数组的末尾,它将头部标记为良好,然后寻找1和0的有效数据。我们以相同的方式指定这些。我们还将添加其他构造函数参数。
my $ir = Linux::IRPulses->new({
header => [ pulse 9000, space 4500 ],
zero => [ pulse 563, space 563 ],
one => [ pulse 563, space 1688 ],
bit_count => 32,
callback => sub {
my ($args) = @_;
my $code = $args->{code};
say "Received code $code";
},
});
解析器将继续寻找1和0,直到收集到足够多的bit_count
。一旦达到正确的数量,它将调用在callback
中指定的子例程,并传递一个散列引用。散列引用包含code
(检测到的红外代码)和pulse_obj
(Linux::IRPulses对象)键。所有长度数字都检查20%的容差。
我们不敢保证您在处理红外数据后仍能保持理智,但希望Linux::IRPulses
可以帮助您有尊严地发疯。
(原始照片CC-BY 2.0由Stefanus Ming在https://flic.kr/p/7djHYP提供)
本文最初发表在PerlTricks.com上。
标签
反馈
这篇文章有什么问题吗?请帮助我们通过在GitHub上创建问题或提交拉取请求来解决。