ここでは、赤外線人感センサを試してみます。感知情報をメールやLINEで通知する方法も紹介いたします。





OSをアップデートして、最新の状態にします。
$ sudo apt-get update $ sudo apt-get upgrade
GPIO制御を精度の高いPWM(Pulse Width Modulation)制御が出来る「pigpio」パッケージをインストールします。
$ sudo apt-get install pigpio python3-pigpio
pigpioのデーモンを起動します。
$ sudo systemctl enable pigpiod.service $ sudo systemctl start pigpiod
pigpioのステータスは「sudo systemctl status pigpiod」コマンドで確認が出来ます。
Indoor Corgiさんの赤外線制御ソフトウェア「cgir」をインストールします。ターミナルを開き、以下の$に続くコマンドを実行して下さい。
ソースコードはGitHubに公開されております。
$ sudo python3 -m pip install -U cgir
一般家庭で利用しているシーリングライトのリモコンで試してみます。
中(全灯)、上(保安灯)、下(消灯)、右(明)、左(暗)のボタンがあります。
下記のコマンドでプログラムを起動して、リモコンボタン情報を学習(取得)します。
$ cgir rec light:on -g 26
オプション 意味は下記の通りです。
実行コマンドを入力して、リモコンの該当ボタンを押すと赤外線データが取得出来ます。以下はプログラムの応答例です。
pi@raspberrypi:~ $ cgir rec light:on -g 26 ------------------------------------ 赤外線コード"light:on"を受信中... 受信機に向けて赤外線を送信して下さい. 受信コード [9000, 4400, 640, 480, 640, 1600, 630, 490, 640, 480, 650, 480, 640, 490, 640, 480, 650, 1600, 650, 1600, 650, 480, 640, 1600, 640, 1600, 650, 480, 640, 1600, 650, 1600, 650, 480, 640, 490, 640, 1600, 650, 1600, 640, 480, 640, 490, 640, 1600, 640, 490, 640, 1600, 640, 1600, 650, 490, 640, 490, 640, 1600, 640, 1600, 640, 490, 640, 1600, 650, 480, 640] Format NEC Frame#1 0x82, 0x6D, 0xA6, 0x59 赤外線コード "light:on" を登録しました.
取得情報は下記の通りです。
{"light:on": [9000, 4400, 640, 490, 640, 1600, 640, 500, 640, 490, 640, 490, 640, 490, 640, 490, 640, 1600, 640,
1600, 640, 480, 640, 1600, 640, 1600, 640, 490, 640, 1600, 640, 1600, 640, 490, 640, 490, 630, 1600, 640,
1600, 640, 490, 630, 490, 640, 1600, 640, 490, 640, 1600, 640, 1600, 640, 490, 640, 490, 640, 1600, 640,
1600, 640, 490, 640, 1600, 630, 490, 640]}
この数字の並びは、「赤外線がONの時間, OFFの時間, ONの時間, OFFの時間,...」という意味です。
0,2,4,6,…偶数番目の数値が、38kHzの赤外線が存在する(High状態の)マイクロ秒時間 で
1,3,5,7,…奇数番目の数値が、赤外線が存在しない(Low状態の)マイクロ秒時間です。
学習情報をliht:on(全灯)、 light:off(消灯)、 light:up(明)、 light:dn(暗)、 light:sml(保安灯)で追加した情報は(codes.json)で示します。
下記のコマンドでプログラムを起動して、学習(取得)したデータを使って赤外線データを送信します。
$ gir send light:on -g 13 -c xxx/codes.json
オプション 意味は下記の通りです。
送信しても機器が反応しない場合は以下の対応で確認してください。
学習機能で取得したデータで送信処理して、その送信データで学習データが取得出来るかを確認してください。
送信で使った学習データとその送信データで作成した学習データが一致していれば、正しく動作しております。
この状態で信号が認識出来ない場合は機器との距離や赤外線LEDの送信角度(半減角)を確認してください。
学習データが取得出来て、それぞれの学習データが一致していない場合は何かの不具合があると思われます。
今回は学習データを使って送信処理を行い、その送信データを学習した結果の値が2倍の内容であった為に
学習した送信データの値をプログラムで2分の1の値に変更して対応しました。不具合の詳細は不明です。
データ変更プログラム(cnv.py)を掲載しました。実行は「python cnv.py」のコマンドでできます。変更結果は(
codes.json2)で示します。
※変更前ファイルcodes.jsonはcnv.pyプログラムと同じディレクトリに設置してください。変更後のファイルは、そのディレクトリにcodes2.jsonのファイル名で作成します。
liht:on(全灯)、 light:off(消灯)、 light:up(明)、 light:dn(暗)、 light:sml(保安灯)を登録して、赤外線の自動送信を試して見ました。
学習したデータを指定の時間間隔で送信するプログラムです。赤外線送信の強さ(認識出来る距離)・送信方向の角度などが確認出来ます。
プログラム(rctl.py)は下記に示します。
import subprocess
import time
tbl =[["on",2],["dn",2],["dn",2],["dn",2],["dn",2],
["up",2],["up",2],["up",2],["up",2],
["off",4],["sml",2]]
while True:
for i in range(len(tbl)) :
subprocess.call(["cgir", "send", "light:"+tbl[i][0], "-g", "13"])
time.sleep(tbl[i][1])
Webブラウザをを使って、赤外線LEDを操作出来る様にします。その処理をするサーバを作ります。
Webブラウザより7000ポートを指定してアクセスすると、初期画面を表示して、
そのボタンをクリックすると指定した赤外線信号を出します。処理の概要は下記の通りです。
サンプルプログラム(server.py)は下記の通りです。用途に応じて変更してください。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import subprocess
import http.server as s
from urllib.parse import urlparse
from urllib.parse import parse_qs
RaspberrypiIP = '192.168.0.10'
class MyHandler(s.BaseHTTPRequestHandler):
def do_GET(self):
if str(self.path[1:]) != "favicon.ico" :
self.make_data()
else :
self.send_response(404)
def make_data(self):
cmd = str(self.path[1:])
if cmd != "" :
subprocess.call(["cgir", "send", cmd, "-g", "13"])
body = '<html lang="ja"><head><meta charset="UTF-8"><title></title><link rel="icon" href="data:,">'\
'</head><body onload="history.back();"><h1>送信完了</h1></body><html>'
else :
body = '<html lang="ja"><head><meta charset="UTF-8"><title>リモコン</title><link rel="icon" href="data:,">'\
'<meta name="viewport" content="width=device-width,initial-scale=1">'\
'</head><body><h1>リモコン</h1>'\
'<a href="http://'+RaspberrypiIP+':7000/light:on" ><button>loght:on </button></a> '\
'<a href="http://'+RaspberrypiIP+':7000/light:off"><button>loght:off</button></a> '\
'<a href="http://'+RaspberrypiIP+':7000/light:up" ><button>loght:up </button></a> '\
'<a href="http://'+RaspberrypiIP+':7000/light:dn" ><button>loght:dn </button></a> '\
'<a href="http://'+RaspberrypiIP+':7000/light:sml"><button>loght:sml</button></a> '\
'</body></html>'
self.send_response(200)
self.send_header('Content-type', 'text/html; charset=utf-8')
self.send_header('Content-length', len(body))
self.end_headers()
self.wfile.write(body.encode())
host = '0.0.0.0'
port = 7000
httpd = s.HTTPServer((host, port), MyHandler)
print('サーバを起動しました。ポート:%s' % port)
httpd.serve_forever()
プログラムの実行は「python3 server.py」コマンドで実行してください。実行完了後、Webプラウザから「RaspberryPiのIPアドレス:7000」でアクセスしてください。
認識プログラムはpigpioの作者さんが公開している赤外線信号送受信用のPythonスクリプト(IR Record and Playback(irrp.py))をそのまま流用しております。
また【ラズパイ入門】赤外線リモコンの信号受信、押されたボタンの識別【Python】
のブログを参考にさせて頂きました。
プログラム(rc.py)は下記の通りです。
#!/usr/bin/env python
import time
import os
import json
import sys
#import RPi.GPIO as GPIO
import pigpio # http://abyz.co.uk/rpi/pigpio/python.html
IR_RX_PIN = 26
GLITCH = 100
PRE_MS = 200
POST_MS = 15
FREQ = 38.0
SHORT = 10
TOLERANCE = 15
POST_US = POST_MS * 1000
PRE_US = PRE_MS * 1000
TOLER_MIN = (100 - TOLERANCE) / 100.0
TOLER_MAX = (100 + TOLERANCE) / 100.0
last_tick = 0
in_code = False
code = []
fetching_code = False
def normalise(c):
entries = len(c)
p = [0]*entries # Set all entries not processed.
for i in range(entries):
if not p[i]: # Not processed?
v = c[i]
tot = v
similar = 1.0
# Find all pulses with similar lengths to the start pulse.
for j in range(i+2, entries, 2):
if not p[j]: # Unprocessed.
if (c[j]*TOLER_MIN) < v < (c[j]*TOLER_MAX): # Similar.
tot = tot + c[j]
similar += 1.0
# Calculate the average pulse length.
newv = round(tot / similar, 2)
c[i] = newv
# Set all similar pulses to the average value.
for j in range(i+2, entries, 2):
if not p[j]: # Unprocessed.
if (c[j]*TOLER_MIN) < v < (c[j]*TOLER_MAX): # Similar.
c[j] = newv
p[j] = 1
def compare(p1, p2):
if len(p1) != len(p2):
return False
for i in range(len(p1)):
v = p1[i] / p2[i]
if (v < TOLER_MIN) or (v > TOLER_MAX):
return False
for i in range(len(p1)):
p1[i] = int(round((p1[i]+p2[i])/2.0))
return True
def end_of_code():
global code, fetching_code
if len(code) > SHORT:
normalise(code)
fetching_code = False
else:
code = []
print("Short code, probably a repeat, try again")
def cbf(gpio, level, tick):
global last_tick, in_code, code, fetching_code
if level != pigpio.TIMEOUT:
edge = pigpio.tickDiff(last_tick, tick)
last_tick = tick
if fetching_code:
if (edge > PRE_US) and (not in_code): # Start of a code.
in_code = True
pi.set_watchdog(IR_RX_PIN, POST_MS) # Start watchdog.
elif (edge > POST_US) and in_code: # End of a code.
in_code = False
pi.set_watchdog(IR_RX_PIN, 0) # Cancel watchdog.
end_of_code()
elif in_code:
code.append(edge)
else:
pi.set_watchdog(IR_RX_PIN, 0) # Cancel watchdog.
if in_code:
in_code = False
end_of_code()
pi = pigpio.pi() # Connect to Pi.
if not pi.connected:
exit(0)
args = sys.argv
with open(args[1]) as f:
key_config = json.load(f)
pi.set_mode(IR_RX_PIN, pigpio.INPUT) # IR RX connected to this IR_RX_PIN.
pi.set_glitch_filter(IR_RX_PIN, GLITCH) # Ignore glitches.
cb = pi.callback(IR_RX_PIN, pigpio.EITHER_EDGE, cbf)
try:
while True:
code = []
fetching_code = True
while fetching_code:
time.sleep(0.1)
time.sleep(0.5)
key_name = "-"
for key, val in key_config.items():
if compare(val, code[:]):
key_name = key
print(key_name)
except KeyboardInterrupt:
pass
finally:
pi.stop() # Disconnect from Pi.
※受信した赤外線は、事前に学習したパターンと一致しているかの判定は「irrp.py」の仕様で判定しております。
「python3 rc.py 学習データファイル」コマンドで実行して、リモコン操作すると学習したリモコンボタンの認識が出来ます。実行結果は下記の通りです。
この認識プログラムにより、赤外線リモコンでRaspberryPiの色々な操作が可能になります。
pi@raspberrypi:~ $ python3 rc.py codes.json light:on light:up light:dn light:sml light:off