ラベル RaspberryPi の投稿を表示しています。 すべての投稿を表示
ラベル RaspberryPi の投稿を表示しています。 すべての投稿を表示

2016年12月4日日曜日

トイレまきまきくんその後

概要

昔トイレの IoT 化ということでトイレットペーパーホルダーを IoT 化しました
http://www.slideshare.net/kakakikikeke/ss-64768171

ちょろっとエンハンスしたので紹介します

環境

  • RaspberryPi Zero ( Jessie 8.0 )

7 セグ LED をシールド化しました

元々ブレッドボード上に配線しており見た目が非常に悪かったのでユニバーサル基板上に実装することでスッキリさせました
作成した基板がこちら


makimaki_board1.jpg

合体後裏
makimaki_board2.jpg

合体後表
makimaki_board3.jpg

まず一番苦労したというかポイントだったのは片面のユニバーサル基板にどうやってシールドを実装するかでした
RaspberryPi の場合ピンがオスピンになっているためシールド側はメスソケットにしなければなりません
そしてユニバーサル基板が片面のため 7 セグの LED やフルカラーの LED もメスソケットの方に実装しなければなりません
そうすると RaspberryPi に指したときに向きが逆になってしまいます
本来なら 7 セグはメスソケットを逆の面に実装して実装面は 7 セグだけが見えるようにしたかったのですが、片面だとそれができませんでした

なので、写真にあるように 7 セグ部分が RaspberryPi Zero の頭の部分からちょうど飛び出すように作ることでとりあえず解決させました

本当は写真でいうところの白い面が RaspberryPi Zero の表の部分になるので、そっちに 7 セグを出したかったのですが片面だとそれが厳しかったということです

回路図

一応回路図を作成したので掲載しておきます
makimaki_circuit.png

フルカラーの LED の全ピンに 470kΩ の抵抗があるのは実は不要です
赤色 LED を制御するピンは入力電圧が確か低かったのでそこは抵抗を入れる必要があると思います
参考 : http://kakakikikeke.blogspot.jp/2016/01/raspberrypi-full-color-led.html
特に GND ピンは完全に不要です
他のピンで抵抗を挟んでいるのは LED の明るさをちょっと暗くしたかったので LED にかかる電圧を下げるために入れました
なので、LED が「ピカーッ!」と光っても問題ない場合は抵抗は不要です

7 セグを制御しているピンは過去の記事で使用したピンをそのまま使用しているだけなので、別に他のピンでも OK です
もう少し違うピンを使って余裕を持ってハンダできるようにすればハンダ付けももっと楽だったかもしれません
参考 : http://kakakikikeke.blogspot.jp/2016/01/raspberrypi-7-seg-led.html

長さを計測するホイールの土台を自作しました

トイレの長さを計測する部分にフォトインタラプタ+スリット付きのホイールを使っています
これは元々ジャンクのホイールマウスの部分を再利用しています

土台もマウスの土台を適当に加工したものを使っていたのですが、見た目が悪かったので 3D プリンタを使って土台の作成まで行ってみました

自作するときに土台の長さを長くすることでペーパーが少なくなってもホイールがペーパーに当たるようになったので最後まで長さを計測できるようになりました


makimaki_base1.jpg

基板とドッキング
makimaki_base2.jpg

ペーパーホルダーとドッキング
makimaki_base3.jpg

難しかったのはホイールを支える柱のところで中に溝を作らなければいけないのですが、この溝のサイズがホイールと中々合わずに苦労しました
また、基板と土台を固定化するのに小さいな穴があるのですが、その穴にちょうど入るようにピンみたいなのも作りました (写真 2 枚目)
これは見事寸法どおりに作成できました

最後に

以上まきまきくんのエンハンスでした

実はここには掲載してないですが、最近まきまきくん用の RaspberryPi Zero に HDD を挿して自宅 NAS としても使っています
もはやトイレを IoT 化するための RaspberryPi 感がゼロになってしまっていますが、別の RaspberryPi を自宅に設置するのも面倒だったので兼用にしています

USB のバスパワーもフルで供給して基板側のピン制御もして、内部でいろいろとプログラムが動いても問題なく動作している RaspberryPi Zero のポテンシャルは改めてすごいなと感じました

2016年1月15日金曜日

RaspberryPi でダイナミック方式の 7 セグ LED を使ってみた

概要

RaspberryPi を起動した時に取得できた IP アドレスを 7 セグに表示したいなと思っていて、ずばりな記事を見つけたので試してみました
配線や Python スクリプトは、そのまま参考にさせていただきました

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)
  • Kernel Version 4.1.7+
  • Python 2.7.9
  • 7 セグ LED カソードコモン
  • ジャンパケーブル オスxメス 12 本
  • 抵抗 27オーム 4 個

配線

rpi_7_seg_led.jpg

参考サイトを元に実線してみましたが、各桁の表示 ON/OFF 用のジャンパで 4 本、7 セグの各セグメントを制御するためのジャンパが 8 本で、合計 12 本のジャンパと GPIO を使うのでかなりごちゃごちゃになってしまいました
もう少し GPIO に余裕のあるボードだともっと綺麗に配線できるかもしれません

抵抗は 27 オームの抵抗を使っていますが 47 オームの抵抗でも OK です

制御用の Python スクリプト

こちらも参考サイトのコードをそのまま使用させていただきました
今回は使っている GPIO も全く同じにしたのでそのまま動作します

  • mkdir -p ~/work/7_seg_led
  • cd ~/work/7_seg_led
  • vim turn_on_ip.py
!/usr/bin/env python
# -*- coding: utf-8 -*-

import RPi.GPIO as GPIO
import threading
import time
import socket

ledport = (14, 15, 18, 23)
segport = (4, 17, 27, 22, 10, 9, 11, 7)
digit = ((1, 1, 1, 1, 1, 1, 0),     # 0
         (0, 1, 1, 0, 0, 0, 0),     # 1
         (1, 1, 0, 1, 1, 0, 1),     # 2
         (1, 1, 1, 1, 0, 0, 1),     # 3
         (0, 1, 1, 0, 0, 1, 1),     # 4
         (1, 0, 1, 1, 0, 1, 1),     # 5
         (1, 0, 1, 1, 1, 1, 1),     # 6
         (1, 1, 1, 0, 0, 0, 0),     # 7
         (1, 1, 1, 1, 1, 1, 1),     # 8
         (1, 1, 1, 1, 0, 1, 1),     # 9
         (0, 0, 0, 0, 0, 0, 0),     # Blank
         (0, 0, 0, 0, 0, 0, 1))     # Minus

class DynamicLed:
    def __init__(self):
        for n in range(8):
            GPIO.setup(segport[n], GPIO.OUT)
            GPIO.output(segport[n], False)
        for n in range(4):
            GPIO.setup(ledport[n], GPIO.OUT)
            GPIO.output(ledport[n], True)
    def set_digit(self, no, num):
        dot = num & 0x80
        num = num & 0x7F
        if(no == 0):
            GPIO.output(ledport[3], True)
        else:
            GPIO.output(ledport[no - 1], True)
        for n in range(7):
            GPIO.output(segport[n], digit[num][n])
        GPIO.output(segport[7], dot)
        GPIO.output(ledport[no], False)

rlock = threading.RLock()

class LedThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.ss = DynamicLed()
        self.dig = [0, 0, 0, 0]
        self.running = True
    def run(self):
        while self.running:
            rlock.acquire()
            for n in range(0, 4):
                self.ss.set_digit(n, self.dig[n])
                time.sleep(0.005)
            rlock.release()
    def stop(self):
        self.running = False
    def set(self, a, b, c, d):
        rlock.acquire()
        self.dig[0] = a
        self.dig[1] = b
        self.dig[2] = c
        self.dig[3] = d
        rlock.release()
    def set_num(self, num, width=0, dot=-1):
        str = '{0:>.{width}f}'.format(num, width=width)
        dp = 0;
        pos = 3;
        rlock.acquire()
        for n in range(len(str) - 1, -1, -1):
            if str[n] == '.':
                dp = 0x80
            elif str[n] == '-':
                self.dig[pos] = 11  # MINUS
                pos = pos - 1
            else:
                self.dig[pos] = int(str[n]) | dp
                dp = 0
                pos = pos - 1
            if pos < 0:
                break
        for n in range(0, pos + 1):
            self.dig[n] = 10    # BLANK
        if dot >= 0:
            self.dig[dot] = self.dig[dot] | 0x80
        rlock.release()

if __name__ == "__main__":
    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)
    # get ip address
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.connect(('google.com', 0)) # dummy connect
    ip = sock.getsockname()[0]
    sock.close()
    array = ip.rsplit('.')
    # led thread start
    led = LedThread()
    led.start();
    try:
        while True:
            led.set_num(int(array[0]), dot=3)
            time.sleep(1)
            led.set_num(int(array[1]), dot=3)
            time.sleep(1)
            led.set_num(int(array[2]), dot=3)
            time.sleep(1)
            led.set_num(int(array[3]))
            time.sleep(1)
    except KeyboardInterrupt:
        print '\nbreak'
    led.stop()
    led.join()
    GPIO.cleanup()

実行

作成したスクリプトを実行してみましょう

  • cd ~/work/7_seg_led
  • python turn_on_ip.py

これでグローバル IP に接続するために割り振られた IP アドレスが 7 セグに順番に表示されると思います
使っている RPi が古めの低スペックなので、若干表示がチラつくときもありましたが、読み取れないレベルではなかったです

無限に表示し続けるので終了したい場合は Ctrl + c で終了させてください

cron に登録する

一箇所だけソースを修正します
cron にする場合に無限ループになっていると次回動作したときに GPIO を取り合いうまく表示されません
104 行目にある無限ループをコメントアウトしてあげましょう

103     try:
104         # while True:
105             led.set_num(int(array[0]), dot=3)
106             time.sleep(1)
107             led.set_num(int(array[1]), dot=3)
108             time.sleep(1)
109             led.set_num(int(array[2]), dot=3)
110             time.sleep(1)
111             led.set_num(int(array[3]))
112             time.sleep(1)

これで cron に以下のように設定します
とりあえず 1 分ごとに表示してくれます

*/1 * * * * python /home/pi/work/7_seg_led/turn_on_ip.py

最後に

IP アドレス情報を取得して順番に 7 セグ LED に表示してみました
cron に登録しておけば、配線さえしておけばいつでも IP を確認することができるようになりました

まぁでも、RPi を起動するたびにこの配線をするのは面倒なので、やっぱり fping とかで検知して接続したほうが簡単かもしれません

2016年1月14日木曜日

RaspberryPi でフルカラー LED を制御してみた

概要

タイトル通り
RaspberryPi でフルカラー LED を制御してみました

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)
  • Kernel Version 4.1.7+
  • WiringPi
  • フルカラー LED

配線

実際の写真はこちら
rpi_full_color_led_circuit.jpg

frizing で作成した配線はこちら
rpi_full_color_led_circuit.png

赤の制御は GPIO 17
青の制御は GPIO 22
緑の制御は GPIO 27

で行います
足と色のひも付けは左から「赤」「カソード」「緑」「青」になります
http://akizukidenshi.com/download/ds/optosupply/OSTA5131A.pdf

テスト

配線ができたらあとは WiringPi で GPIO に信号を送信して動作を確認します


    • gpio -g mode 17 out
    • gpio -g write 17 1
    • gpio -g write 17 0

    • gpio -g mode 22 out
    • gpio -g write 22 1
    • gpio -g write 22 0

    • gpio -g mode 27 out
    • gpio -g write 27 1
    • gpio -g write 27 0

今回の配線だと、どの色もかなり明るく発光するので、まぶしい場合は適当に抵抗を挟んで明るさを調整してください
( 本当はちゃんと電源電圧や順方向電圧、順方向電流を考慮して抵抗を選択する必要があります )

参考サイト

2016年1月12日火曜日

RaspberryPi で人感センサーを使ってみた

概要

RaspberryPi で人感センサーを使ってみました
その名の通り人が近づくと反応するセンサーです

環境

配線

rpi_motion_sensor_circuit.png

プラスとマイナスがあるので注意してください
真ん中が信号を送信するピンになります

テスト

今回、センサが反応した際の信号は GPIO 17 番で受信します

  • gpio -g mode 17 in
  • while :; do gpio -g read 17; sleep 1; done;

で手を近づけると 0 が 1 に変わると思います
手を話すと 0 に戻りますが、瞬時に切り替わるわけではなく少し待ってから 0 になるようです

最後に

やはりデジタル信号を送ってくれるセンサは簡単に使えます
またセンサ側で電圧降下も対策してくれているので、回路を組むのに抵抗やコンデンサを使わないのも嬉しい点です

2016年1月8日金曜日

RaspberryPi で PWM の制御をしてみた

概要

PWM (パルス幅変調) はある一定周期の間隔で動的に変化するパルスを送信することができる仕組みです
モーターの制御や光の強弱の変化などに使われます
RaspberryPi でも PWM が使えるようなので LED を使って試してみました

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)
  • Kernel Version 4.1.7+
  • WiringPi
  • wiringpi2 (Python) 1.1.1

事前準備

今回は WiringPi を使って PWM 制御を行うので事前にインストールしておいてください

wiringpi2 のインストール

wiringpi2 は WiringPi 用の Python ライブラリです
pip を使えば簡単にインストールできます

  • sudo pip install wiringpi2

今回は Python スクリプトから PWM を制御します

配線

今回は LED の調光を PWM で変化させてみます
なので、L チカ配線をしてください
L チカ配線の方法はこちらを参考にしてください
wiring_bread_board.png

一点ポイントとしては RaspberryPi 上で PWM の信号を送信するためには GPIO 18 番を使う必要があります
なので、アノード ( + ) 側の GPIO は 18 番に接続するようにしてください

PWM 送信用スクリプトのデプロイ

  • cd work/
  • mkdir python_wiringpi_pwm
  • cd python_wiringpi_pwm
  • vim controls_pwm.py
import wiringpi2 as wiringpi
import time

OUTPUT = 2
PWM_PIN = 18
SLEEP_TIME = 0.03

wiringpi.wiringPiSetupGpio()
wiringpi.pinMode(PWM_PIN, OUTPUT)

for i in range(0, 1024, 16):
    print(i)
    wiringpi.pwmWrite(PWM_PIN, i)
    time.sleep(SLEEP_TIME)

for i in range(1024, 0, -16):
    print(i)
    wiringpi.pwmWrite(PWM_PIN, i)
    time.sleep(SLEEP_TIME)
  • sudo python controll_pwm.py

で実行すると LED が明るくなった後に徐々に暗くなると思います

ポイント

wiringPiSetupGpio で 18 番の GPIO を初期化します
実は初期化の方法には 3 通りあり他に「wiringPiSetup」「wiringPiSetupSys」があります
前者で初期化した場合は 1 番を指定する必要があり、後者で初期化した場合は 12 番を指定する必要があります
どれを使って初期化しても同じ GPIO を指すことになりますが、コールするメソッドによって初期化する GPIO の番号が違うので注意してください

range で 0 から 1024 の範囲でパルス幅を変化させています
RaspberryPi の場合指定できるパルス幅の範囲が 0 から 1024 のためそうしています
他のマイコンボードなどではもっと広い範囲の指定ができる場合があり、その場合にはより精度の高い制御ができます

二つ目の for 文は LED の明るさを暗くするために用意しています

最後に

紹介は以上です
PWM を使うと、このような動的な制御がプログラム上でできるようになります
PWM の王道といえばおそらくサーボモータだと思うので次回はサーボモータの制御をしてみたいと思います

2016年1月6日水曜日

RaspberryPi でタクトスイッチの信号を受信してみた

概要

タクトスイッチ (タクタイルスイッチ) の信号を RaspberryPi で受信してみました
タクトスイッチはいわゆる普通のスイッチで押した状態 (1) or 押していない状態 (0) を制御することができます

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)
  • Kernel Version 4.1.7+
  • Python 2.7.9
  • タクトスイッチ

配線

実際に配線した写真は以下の通り
rpi_tact_switch.jpg

fritzing で書いた配線図は以下の通り
rpi_tact_switch_circuit.png

今回はプルダウンスイッチをソフトウェア側ではなくハード側で制御するので GPIO で信号を受け取る前に 10kオームの抵抗を配置しています
これがプルダウン抵抗です

タクトスイッチのサンプルは他にもいろいろと情報が転がっているので、調べればプルダウン抵抗なし版の回路も簡単に見つかると思います

ソースコードデプロイ

  • mkdir -p ~/work/tact_switch
  • vim ~/work/tact_switch/receive_signal.py
#!/usr/local/bin/python
# -*- coding: utf-8 -*-

import RPi.GPIO as GPIO

pin = 17

def setup(): 
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(pin, GPIO.IN)

def main(): 
    try:
        GPIO.wait_for_edge(pin, GPIO.FALLING)
        print(GPIO.input(pin))
        print("pushed")
    except KeyboardInterrupt:
        print "KeyboardInterrupt"
    except:
        print "Quit"
    finally:
        print "clean up"
        GPIO.cleanup()

if __name__=="__main__":
    setup()
    main()

GPIO は 17 番を使っています
ポイントは wait_for_edge というメソッドでこれを使うことで指定された GPIO が FALLING (押された) 状態になったら次の処理に進むことができます

スクリプトを実行するとスイッチからは 0 が送信されているため入力待ち状態になるはずです
その状態でスイッチを押すと「pushd」と表示されスクリプトが終了します

自分がハマったのは信号が 0 と 1 を繰り返してしまい、待ち状態に入らない現象が発生しました
原因は超単純で別のスクリプトが同じ GPIO を制御しており、そのスクリプトを停止したら正常に動きました
回路がおかしい場合や、抵抗の値が小さい場合にも正常に動かないようです

参考サイト

2016年1月2日土曜日

RaspberryPi で圧力センサー を使ってみた

概要

前回 MCP3002 を使って温度センサーを使ってみました
今回は圧力センサーの情報を MCP3002 を使って取得してみました

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)
  • Kernel Version 4.1.7+
  • Python 2.7.9
  • pip 7.1.2
  • spidev 3.1
  • 圧力センサー -> 感圧センサ円形0.5インチ

事前準備

SPI を有効にする方法や Python 用のドライバは前回と同様です
あらかじめインストールしておいてください

配線

RaspberryPi + ブレッドボードを使った配線です
rpi_pressure_circuit.jpg

fritzing を使った配線図は以下の通りです
rpi_pressure_circuit_fritzing.png

ポイント

圧力センサーにジャンパを接続するにはハンダごてとハンダが必要になります
とりあえず接触させておけば OK なので、ハンダじゃなくてもいいですが、固定したかったので自分はハンダを使いました

MCP 3002 で信号を受信する部分は前回と一緒です
違うのは圧力センサーでアナログ信号を受信する部分です
片方は電源 3.3V に接続します
もう片方は信号を出力するジャンパとして使います
受信する前に 10K オームの抵抗を接続して回路を安定させています

回路が作成できたら RaspberryPi の電源を入れます

ソースコードのデプロイ

  • cd ~
  • mkdir -p work/mcp3002_pressure
  • cd work/mcp3002_pressure
  • touch pressure_sample.py
#!/usr/bin/env python
# Read the analog sensor value via MCP3002.

import spidev
import time
import subprocess

# open SPI device 0.0
spi = spidev.SpiDev()
spi.open(0, 0)

try:
    while True:
        resp = spi.xfer2([0x68, 0x00])
        value = (resp[0] * 256 + resp[1]) & 0x3ff
        print value
        time.sleep(1)
except KeyboardInterrupt:
    spi.close()
  • python pressure_sample.py

1 秒おきにセンサーで受信したデータを表示します
強く押した場合に値が上昇します
10bit の A/D コンバータなので最大値は 1024 になります
この値を if 分等で切り分けて強弱を判断する感じです

2015年12月31日木曜日

RaspberryPi で温度センサー + MCP3002 を使って室内の温度を計測してみた

概要

アナログ温度センサー + MCP3002 を使って室内の温度を計測してみました
RaspberryPi はアナログ温度センサーのアナログ信号を直接受け取ることはできません
そこで、A/Dコンバータである MCP3002 を使ってアナログ信号をデジタル信号に変換し RaspberryPi で取得します

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)
  • Kernel Version 4.1.7+
  • Python 2.7.9
  • pip 7.1.2
  • spidev 3.1

SPI を有効にする

RaspberryPi の SPI (Serial Peripheral Interface Bus) を有効にします
デフォルトでは無効になっているので有効にして再起動する必要があります

SPI を有効にすることで A/D コンバータ (MCP3002) を使うことができるようになります

  • sudo cp /boot/config.txt{,.back}
  • sudo vim /boot/config.txt

以下のような差分になるように修正します

48c48
< dtparam=spi=on
---
> #dtparam=spi=on

dtparam=spi という項目があるので、それをコメントアウトすれば OK です
コメントアウトしたら RaspberryPi を一旦再起動します

  • sudo reboot

再起動したら SPI が有効になっているか確認します

  • lsmod | grep spi
spi_bcm2835             7980  0

上記のようになっていれば OK です

spidev をインストールする

spidev は Python 用の SPI ライブラリです
pip を使ってインストールすれば OK です

  • sudo pip install spidev

配線

RaspberryPi とブレッドボードを使って配線します
実際の配線全体図は以下の通りです
rpi_temp_circuit.jpg

写真だと分かりづらいのでツールを使って書いた配線図は以下の通りです
rpi_temp_circuit_fritzing.png

ポイント

左上の三本足の黒いセンサーがアナログ温度センサーです
VDD と GND そして信号を出力する三本があります
平面左から VDD、出力、GND になります
順番を間違えずに配線する必要があります

真ん中から出力された信号を MCP3002 で受信します
受信するピンは決まっており MCP3002 の場合は 2 箇所 ( 2ch ) で受信することができます
今回は 1 つしかセンサーを使っていないので 1 ch 使えば OK です

あとは MCP3002 の出力を RaspberryPi の SPI 用の GPIO で信号を受信すれば OK です
RaspberryPi 側で使用する SPI 用の GPIO は「CS0」「SCLK」「MISO」「MOSI」になります

配線が完了したら RaspberryPi の電源を入れましょう

ソースコードデプロイ

あとは受信したデータを表示するプログラムをデプロイすれば OK です

  • cd ~
  • mkdir -p work/mcp3002_temperature
  • cd work/mcp3002_temperature
  • touch temperature_sample.py
#!/usr/bin/env python

import time
import sys
import spidev

spi = spidev.SpiDev()
spi.open(0,0)

def readAdc(channel):
    adc = spi.xfer2([1, (2 + channel) << 6,0])
    data = ((adc[1] & 31) << 6) + (adc[2] >> 2)
    return data

def convertVolts(data):
    volts = (data * 3.3) / float(1024)
    volts = round(volts, 4)
    return volts

def convertTemp(volts):
    temp = (100 * volts) - 50.0
    temp = round(temp,4)
    return temp

if __name__ == '__main__':
    try:
        while True:
            data = readAdc(0)
            print("adc  : {:8} ".format(data))
            volts = convertVolts(data)
            temp = convertTemp(volts)
            print("volts: {:8.2f}".format(volts))
            print("temp : {:8.2f}".format(temp))

            time.sleep(5)
    except KeyboardInterrupt:
        spi.close()
        sys.exit(0)

実行してみましょう

  • python temperature_sample.py

でうまく配線できていれば以下のように出力してくれます

adc : 222
volts: 0.72
temp : 21.54
adc : 219
volts: 0.71
temp : 20.58

温度は一番したの 21.54, 20.58 になります
摂氏で出力するようにプログラムしています

ポイントは readAdc でここで spidev を使って変換したアナログ信号をデジタル信号で取得します
実行した際の adc がその値になります
今回使っている MCP3002 は 10 bit 2ch の A/D コンバータでデジタル信号に変更すると 0 - 1024 の範囲 ( 10bit の範囲 ) で値を変換してくれます
最近だと 12bit の A/D コンバータもありビット数が増えれば増えるほどより精度の高い信号を取得できるようになります

最後に

MCP3002 という A/D コンバータを使ってアナログ信号をデジタル信号に変換してみました
センサー系のデバイスは基本的にアナログ信号で受信するしかないので A/D コンバータが必須になります
次は圧力センサーの値でも取得してみたいと思います

参考サイト

2015年12月3日木曜日

RaspberryPi で Huawei の HWD12 を使う方法

概要

過去に Yosemite で使えるようにした HWD12 ですが、今度は RaspberryPi (RPi) で使ってみました

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)
  • Kernel Version 4.1.7+

設定方法

とりあえず何も考えずに以下のコマンドを実行すれば使えるようになると思います

  • sudo apt-get install usb-modeswitch
  • sudo cp /etc/usb_modeswitch.conf{,.back}
  • sudo vim /etc/usb_modeswitch.conf
DefaultVendor=0x12d1
DefaultProduct=0x1f03

TargetVendor=0x12d1
TargetProduct=0x14db

MessageContent="55534243123456780000000000000a11062000000000000100000000000000"
  • sudo modprobe usbserial vendor=0x12d1 product=0x14db
  • sudo usb_modeswitch -c /etc/usb_modeswitch.conf

usb_modeswitch.conf は一番下に内容を追記すれば OK です

何をしているのか

usb_modeswitch というツールを使って、USBストレージとして認識されてしまった HWD12 を USBモデムとして認識させ直しています
最後の sudo usb_modeswitch -c /etc/usb_modeswitch.conf のあとで HWD12 のランプが紫になりインターネットに接続できることが確認できると思います

本来は USB を接続した際に VendorID が 0x12d1, ProductID が 0x14db として認識されなければいけないのに、それぞれ 0x12d1, 0x1f03 として認識されているせいで Wifi モデムとして動作していません

設定ファイル ( /etc/usb_modeswitch.conf ) に正しい ID 情報を記載して、usb_modeswitch コマンドを実行することで正しい ID として認識させます

本来正しく認識させなければいけない ID や MessageContentここ に記載されているものを使いました

Tips

  • IPv4 の IP アドレスを取得できない場合

以下のコマンドを試してみたください

sudo dhclient -4 -v usb0

RPi 自体で IPv4 を切る方法もありそうなのでそれを設定して再起動でもいいかもしれません
というのも今回の HWD12 を使えるようにする設定を行った後に RPi 自体を再起動すると HWD12 を挿してもうまくインターネットに接続できない現象が発生しました
自分の場合ですが、調べてみると USB はモデムとして認識されているものの IPv4 がうまく取得できていなかったようで、RPi を再起動するたびに dhclient のコマンドを実行していました
コマンドを 1 個実行するだけなのでそこまで大変ではないですが、そもそも IPv4 を切っておけば、そのコマンドすら実行する必要がなくなるのかなと思った感じです

  • そもそも他のネットワークがない人はどうすればいいか

今回のコマンドは一発目に apt-get コマンドがあります
つまりネットワークに繋がっていなければなりません
自分はスマホのテザリングを使って RPi をネットに繋いて実行しましたが、そもそもその環境すらない場合は詰んじゃうかもしれません

参考サイト

2015年12月1日火曜日

RaspberryPi で CUI モード時にフォントサイズを大きくする方法

概要

CUI モードで起動した RaspberryPi ( 以下 RPi ) を起動しモニタに HDMI 接続のモニタ ( 例えばテレビなど ) を使っていると文字が小さすぎることがあります

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)
  • Kernel Version 4.1.7+

対応方法

1つ設定ファイルを編集し、再起動します

  • sudo vi /boot/config.txt

でコメントアウトされている以下の 2 つの設定をコメントインし再起動します

hdmi_group=1
hdmi_mode=4
  • sudo reboot

でいい感じのサイズの綺麗なフォントが映るはず

参考サイト

2015年11月26日木曜日

RaspberryPi で無線 LAN のアクセスポイントを追加する方法

概要

過去に WiMax2 に接続する方法を紹介しました
WiMax2 が使えない状況が発生し iPhone のテザリングしかネットワークがなく、デザリングを新しい無線 LAN のアクセスポイントとして追加してみました

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)
  • Kernel Version 4.1.7+

手順

新規に network の定義を追加する

  • sudo cp /etc/wpa_supplicant/wpa_supplicant.conf{,.back}
  • sudo chmod 666 /etc/wpa_supplicant/wpa_supplicant.conf
  • sudo wpa_passphrase ssid ssid-password >> /etc/wpa_supplicant/wpa_supplicant.conf

ssid と ssid-password は今回は iPhone のテザリング情報を入力しました

追加した network 定義を編集する

  • sudo vim /etc/wpa_supplicant/wpa_supplicant.conf

追加した ssid の network の定義に以下を追加する

  • proto=WPA2
  • key_mgmt=WPA-PSK
  • pairwise=CCMP

記載したら保存して終了する

  • sudo chmod 600 /etc/wpa_supplicant/wpa_supplicant.conf

権限を戻しておく

ネットワークを再起動する

  • sudo systemctl restart networking

でしばらくするとテザリング用の NAT IP が iPhone からもらえると思います

最後に

既存の無線 LAN 設定が記載されている wpa_supplicant.conf に設定を追記するだけなので簡単でした

両方のネットワークにアクセスできる状況で、この設定ファイルを使うとどっちのネットワークを使うのか気になりました
優先度とかを定義することができるのか、単純にファイルの上位に記載されているネットワーク定義から評価していくのか、、、どうなんだろうか

試せる機会があったらやってみよう

2015年11月10日火曜日

スタンドアロンになってしまった RaspberryPi を救う方法

概要

想定ケースとしては

  • RaspberryPi (RPi) は常に無線 LAN に接続しており他のマシンから SSH でログインして操作していた

という状況で突如無線 LAN が停止してログインできなくなったときに救うケースを考えてみます

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)

最終手段

いきなりですが、最終手段です
どうしても RPi を操作できる状況にできない場合は、ネットワークが復旧したあとで電源プラグを引っこ抜いて再起動するしかないと思います

電源を直接抜いてシャットダウンすると SD カードが破損して最悪 OS 起動しなくなったりデータが正確に保存されないなどのリスクがあります
自分は一度だけ OS が起動しなくなり SD カードをフォーマットしなおしたことがありますが、ほぼ遭遇したことはありません
なので「どうしても」というケースでは実施して問題ないと思います

今回は上記を最終手段として、それまでに救えるいくつかの方法を検討していきます

キーボードおよびディスプレイを使って救出する

おそらくこれが一番メジャーだと思います
キーボードしかない場合も想定して復旧方法を検討します

有線のキーボードおよびディスプレイに接続できる状況

この状況があれば一番救える確率が高いです
キーボードは USB でディスプレイは HDMI とします

この場合はまずそのままキーボードとディスプレイを RPi に接続します
で、キーボードから何かしらの信号を送れば HDMI 側にも信号が飛んで RPi の CUI が表示されればそのまま救出完了になります
( RPi の OS のバージョンが Raspbian Jessie だった場合はデフォルトが GUI なのでキーボードの Tab や Alt 十字キーを使ってターミナルを起動するなりして救う必要があります、キーボードが HHK で十字キーボードがないとか OS のキーボード配列の設定が違うとか問題に遭遇する可能性もありますが、そうなったら頑張るしかないです )

ですが、キーボードとディスプレイを接続して信号を送ってみたのにディスプレイ側に信号が来ないなんてことに遭遇すると思います
RPi は起動時にディスプレイが繋がっていれば HDMI の出力を ON にするのですが、HDMI が繋がっていない状態で電源を ON にすると HDMI の出力が行われません
( 自分の場合は上記に該当しており、デフォルト GUI だった OS を CUI の状態にしたら発生しました )
その場合は画面が見えない状態でキーボードで HDMI の出力を ON にするコマンドを実行しなければいけません
コマンドは以下の通り

  • tvservice -o
  • tvservice -p
  • fbset -depth 8
  • fbset -depth 24

簡単に説明するとディスプレイの出力を OFF -> ON して画面のフレームバッファの設定を 8 -> 24 に変更します
このコマンドを画面が真っ暗な状態で、想像しながらタイプする必要があります
間違ってタイプした場合は Ctrl + e -> Ctrl + u を駆使して一旦クリアした後で再度冷静にタイプしましょう
タイプが成功して HDMI への信号が ON になれば画面が表示されて救出完了になります

あとコマンドをいきなり実行できる状態で RPi が起動していればいいのですが、pi ユーザで一度ログインしないとダメな場合には、そこから想像しながらタイプする必要があるので若干難易度があがります

どうしても画面が表示されない場合は「sudo reboot」もありです
もしくは「sudo shutdown -h now」でシャットダウンして RPi 上の LED が点滅しないことを確認して電源を抜いてから再起動でも問題ないと思います

有線のキーボードはあるがディスプレイがない

これは、上記の通り想像しながらキーをタイプするしかないと思います
ディスプレイがないのでディスプレイに出力してもしょうがないのでこの場合は

  • sudo reboot

or

  • sudo shutdown -h now

のどちらかを頑張ってタイプして復旧させるしかないと思います
そしてこの場合は GUI だと終わります
さすがに GUI をキーボード Only で想像しながらタイプするのは無理があります

頑張ってタイプしても再起動しない、停止しないという場合は、キーボード自体の信号が送信されていない可能性があるかもしれません
例えば PPi を電池やモバイルバッテリーで動かしている場合に充電が足りずに RPi に十分な電圧が加わらず USB ポートが正常に動作しないなどが考えられます
RPi は通常 5V (家庭用の電源コンセント) の電圧がかかることを想定しています

ディスプレイはあるが無線キーボードしかない

例えば Bluetooth の無線キーボードだけある状況です
基本は有線と変わらず接続できたら停止 or 再起動コマンドを想像しながら発行するということしかできません

ただ、無線の場合は有線に比べて信号を送るまでの難易度があがります
まず RPi に Bluetooth レシーバが接続されていることが絶対条件です
これがないと終了です
レシーバがあり無線キーボードがアドバタイズできる状況であるならば救える可能性はあります

が、ここからもハードルが高いです
RPi の場合 Bluetooth キーボードと接続するにはキーボードとペアリングするためのコマンドを発行する必要があります
(参考 : RaspberryPi で Bluetooth キーボードを接続する方法, RaspberryPi の bluetoothctl で無線キーボードに接続 )
一度接続したキーボードは trust することで自動で再接続してくれるオプションがあるのですが、このオプションは RPi が起動する場合でないと使えません
なので RPi が起動中に Bluetooth キーボードが接続できる範囲にきても自動で接続してくれません

ではどうするか、ですが自分は以下のスクリプトを cron で回す設定を事前に行っています
bluetoothctl と expect で無線キーボードに定期的に接続するスクリプト

ここまで事前に用意できていて初めて無線キーボードが使えるようになります
有線に比べてかなりハードルが高いので、緊急時はできれば有線キーボードを準備してください

キーボードもディスプレイもない

これは相当厳しいです
最悪 PC があればなんとかなります (後述) が、この場合は電源 OFF をするしかないです

PC を持っている場合

一台 PC を持っている場合に救出できる方法がないか検討します

シリアル通信を使う

RPi の GPIO を使って RPi 上の信号を PC に表示します
ただ、シリアル通信をするのであれば PC 以外に以下の機材が必要になります

  • ジャンパケーブル
  • FTDI シリアル - USB 変換アダプタ
  • USB ケーブル

やり方や機材等の詳細はこちらを御覧ください
シリアル通信に必要な機材はこれ以外のパターンもたくさんあります
が、とりあえず PC だけでは無理です

そしてシリアル通信の最大の弱点は PC を停止した状態で配線しないと信号が受け取れない点にあります
・・・そう、起動している RPi だと結局シリアル信号をモニタすることができないのです

じゃあなんで紹介したんだとなりますが、1 つは電源での OFF -> ON 後にとりあえず正常に動作しているか確認したい場合に使えます
もう 1 つは実は起動した状態でシリアル通信できる方法があると誰かが教えてくれのではと、思ったからです
もしかしたら、あとで調べたらあっさり方法がわかるかもしれませんが

最後に

RPi は一度セットアップしてサーバとして動かすのであれば電源だけあれば OK で省スペースなのですが、いざぶっ壊れて対応しなければいけないときに、とたんにハードルと必要になる機材が増えるようなイメージがあります

しょうがないと言えば確かにしょうがないですが、もっとスマートな方法はないものだろうかと思いました

2015年11月2日月曜日

RaspberryPi + FTDI でシリアル通信をやってみた

概要

RaspberryPi に接続するのに SSH や HDMI などでディスプレイの表示ができないときに PC と RaspberryPi だけを使って接続することができます
シリアル通信という技術を使うことで実現することができるのでその方法を紹介します

環境

Mac へのドライバインストール

変換アダプタを Mac 上で使用できるようにするためにドライバをインストールします

http://www.ftdichip.com/Drivers/VCP/MacOSX/FTDIUSBSerialDriver_v2_3.dmg

をダウンロードしてポチポチやっていけばインストールできます
2015/10/30 時点でのドライバの最新版は v2_3 でしたので最新版が他にあればそちらをインストールするようにしてください

配線

まず完成した配線は以下の通りです
overview.jpg

ジャンパワイヤ (ジャンパ) が 3 本必要になります (Mac 側から電源を共有するのであれば更にもう一本ジャンパワイヤが必要になります)
以下配線の説明を簡単にしていきます

RaspberryPi 側の配線

まず、RaspberryPi 側の GPIO にジャンパ(メス)を接続します
GPIO の物理 PIN の番号でいうと 6番(GND), 8番(TX), 10番(RX) に接続します
3 本並んでいるのでわかりやすいと思います
rpi_to_ftdi.jpg

FTDI 側の配線

RaspberryPi(RPi) に配線したジャンパを FTDI のアダプタに接続します
まず、RPi 側の GND に接続したジャンパを FTDI の GND に接続します
アダプタに GPIO の番号が印字されているので GND のところに接続してください

次に RX, TX ですがここがちょっと気をつけるポイントです
RPi の TX に接続したジャンパは アダプタ側の RX に接続します
そして、RPi の RX に接続したジャンパは アダプタ側の TX に接続します
つまり、RX と TX がクロスすることになります
RPi 側のTX (送信) を FTDI 側で RX (受信) する感じです
ftdi_to_mac.jpg

Mac 側の接続

これはアダプタの USB 端子をそのまま PC に接続すればOKです
接続が完了したら以下のコマンドを実行して USB アダプタがちゃんと認識されているか確認してください

  • ls -ltr /dev/tty.*

自分の場合は以下の名前でアダプタが認識されていました

crw-rw-rw- 1 root wheel 18, 4 10 29 20:48 /dev/tty.usbserial-AI02RMKU

こんな感じの結果があれば OK です

screen コマンドでシリアル通信の準備をしておく

先に説明しておくべきでしたが、配線中は RaspberryPi の電源は OFF にしておいてください
ON の状態で実施してもシリアル通信のデータを Mac で受信することができません

USB のアダプタが認識できたら screen コマンドを使ってシリアル通信の準備をします
Mac 上でターミナルを起動します
以下のコマンドでシリアル通信を実現します

  • screen /dev/tty.usbserial-AI02RMKU 115200

最後の「115200」という数字はボーレートという値で RPi 側から送信されるボーレートの値が 115200 なのでそれに合わせる必要があります
とりあえず実行すると真っ暗な画面になりますが、そのまま待機しましょう

RaspberryPi の電源を ON にする

ここまで準備出来たら RaspberryPi の電源を ON にしましょう
今回はコンセントから直接電源を共有しているので、起動するには電源アダプタをコンセントに接続すれば OK です

すると screen で待機していたターミナル上に RaspberryPI の起動ログが流れていることが確認できると思います
起動が完了するとログインプロンプトが表示されるので、普通に Mac のキーボードを使ってログインすれば、RPi 上でコマンドを実行することが可能になります
raspberry_serial_console.png

最後に

紹介は以上です

Wi-Fi 環境があったり有線 LAN 環境があるのであれば SSH で接続することをおすすめします
理由としては機材を用意し配線する必要もないからです

シリアル通信を使うケースとしてはやはり緊急時等のデバッグかなと思います
RPi やネットワークに問題があり SSH できない場合やキーボードやモニタなどの機材が用意できない場合に PC さえあれば接続できるので便利です

今回は FTDI の変換アダプタを使いましたが USB とジャンパが一旦になっている専用のケーブルもあるのでそれを使ってもOKです
どちらにしろ最近の PC であれば USB に変換するのは必要だとは思いますが

2015年11月1日日曜日

RaspberryPi で Lチカをやってみた

概要

今更ながらやってみました
簡単に紹介します

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • 各種DIYキット
    • ブレッドボード
    • ジャンパ (オス - メス) 2 本
    • LED (緑色)

配線

完成図は以下の通りです
enter image description here

enter image description here

まず配線方法についてそれぞれ説明します
以下の作業は電源 ON でも OFF でもどちらでも OK です

RaspberryPi 側の配線

こちらは超簡単です
GPIO の論理 PIN 番号の 6 番(GND), 18番 (GPIO) にジャンパンのメスを接続します
※物理 PIN 番号だと 6 番, 12 番になります
あとはオス側はブレッドボードの同列に適当に差し込んでおけばとりあえず OK です
wiring_rpi.png

ブレッドボード側の配線

こっちが少しだけ大変です
wiring_bread_board.png

まず RaspberryPi (RPi) の GND の同列上に LED のマイナス側を刺します
LED には +/- がありプラスのほうが足が少し長いです
なので短い方を GND の列と合わせてブレッドボードに刺します

次に LED のプラス側の下に抵抗を刺します
今回用意した抵抗は 220 オームの抵抗 (色 : 赤赤茶金) を用意しました
200 から 300 オームくらいの抵抗であれば OK です
1Kオームくらいの抵抗をつなぐと抵抗が強すぎるせいで LED が点灯しないので注意してください

そして抵抗のもう片方の列上に RPi に接続されている GPIO から出いているジャンパを接続します

これで L チカのための配線自体は完了です

信号の送信

たぶんこの状態だと RPi の電源が入っていてもまだ LED は光っていないと思います
理由は GPIO 18 番にまだ電気が流れていないためでその制御を RPi 上でコマンドで制御します

まず GPIO 18 番を使えるようにします

  • sudo echo 18 > /sys/class/gpio/export

次に GPIO 18 番を信号の「出力」として使うことを設定します

  • sudo echo out > /sys/class/gpio/gpio18/direction

あとは、実際に信号を送信します

  • sudo echo 1 > /sys/class/gpio/gpio18/value

すると LED がピカっと光るとおもいます
最後の echo で 0 を送信すると LED が消灯します

最後に

基本はググれば L チカ関係のネタはたくさんでてくると思います

今回自分がはまったポイントは 2 つです

  • 抵抗の値が大きすぎて通電はしていたが LED が光らなかった
  • RPi 上でコマンドで制御する GPIO の番号は物理番号ではなく論理番号を使う

でした
どちらもかなり基本的なところでつまづきました
これを経験して感じたのは

  • 抵抗のオーム数は色からわかるようにしておくとよい
  • GPIO はある程度配置と役割を覚えておいたほうがよい

ということでした
次はセンサーやモーターを GPIO で制御してみたいです

おまけ: Pythonスクリプトで制御

https://github.com/kakakikikeke/python-pybluez-sample/commit/0e69f3a2f606630126b37f722fa185dc244c956e

2015年10月30日金曜日

RaspberryPi に WringPi をインストール

概要

WringPi とは RaspberryPi 上の GPIO を簡単に扱うためのツールです

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)
  • Kernel Version 4.1.7+

インストール方法

  • sudo apt-get install libi2c-dev
  • cd work
  • git clone git://git.drogon.net/wiringPi
  • cd wiringPi/
  • ./build

試す

  • gpio -g mode 24 out
  • gpio -g write 24 1
  • gpio -g read 24
  • gpio -g write 24 0

「-g」オプションで論理 PIN 番号 (BCM-GPIO) 指定ができて
「-1」オプションで物理 PIN 番号 指定ができるみたいです
つまり

  • gpio -g write 24 1
  • gpio -1 write 18 1

は同じことになります
終了する場合は

  • gpio unexport 24

あとの細かい使い方は help か公式 を見てください

参考サイト

2015年10月27日火曜日

bluetoothctl と expect で無線キーボードに定期的に接続するスクリプト

概要

RaspberryPi に無線キーボードの設定をしたあとで無線キーボードからの入力が一定時間ないと bluetooth が切断されてしまう現象が発生しました
切断のたびに bluetoothctl コマンドを実行するのは面倒なので、cron を使って一定間隔で bluetoothctl を実行させるようにしてみました

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)
  • Kernel Version 4.1.10
  • expect 5.45

スクリプト

とりあえず expect スクリプトの全貌です

#!/usr/bin/expect -f

set timemout 5
set prompt "#"
spawn sudo bluetoothctl -a
expect -re $prompt
send "connect xx:xx:xx:xx:xx:xx\r"
expect -re $prompt
send "quit\r"
expect eof

Mac アドレスの部分は接続する無線キーボードの Mac アドレスを入力してください

デプロイする

pi ユーザで実行しています

  • cd
  • mkdir script
  • cd script
  • touch connect_keyboard.sh
    • 上記のスクリプトを記載
  • chmod 755 connect_keyboard.sh
  • crontab -e
    • */1 * * * * /home/pi/script/connect_keyboard.sh

で1分おきに connect の命令が実行されます
切断されたキーボード側をペアリング状態にしておけば5分以内には再接続されて使えるようになるはずです

Tips

postfix のインストール

postfix がインストールされていない場合 cron のログに以下のようなエラーが出てうまく cron が動かないことがあります

CRON[2369]: (CRON) info (No MTA installed, discarding output)

この場合は素直に postfix をインストールしましょう
途中設定するために config 画面に切り替わりますが、ローカル用で設定すればOKです

  • sudo apt-get -y install postfix

また cron のメールが送られているのが嫌な場合は crontab -e の設定に以下を追記してください

MAILTO=”“

手動でスクリプトを実行する場合

最後の expect eof を interact に書き換えて実行してください
それ用のスクリプトを準備しておくのがいいかもしれません

2015年10月19日月曜日

RaspberryPi に fluentd をインストールしてみた

概要

RaspberryPi 上に fluentd をインストールしてみました
バージョン周りがハマりポイントかと思います

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)
  • Kernel Version 4.1.10
  • Ruby 2.1.5p273
  • Gem 2.2.2
  • gcc 4.9.2
  • fluentd 0.12.16

インストール

必要なパッケージのインストール

  • sudo apt-get -y install ruby-dev
  • sudo apt-get -y install ruby1.9.1-dev
  • sudo apt-get install --upgrade gcc

ポイントは 2 つ
ruby-dev 系のインストールがちゃんとできていないと以下のエラーになります

'require': cannot load such file -- mkmf (LoadError)

gcc のバージョンが古いと以下のエラーになります

error: unrecognized command line option '-fstack-protector-strong'

とりあえず自分は上記を解決すれば OK でした
他にも足りないパッケージがあれば基本は apt-get でインストールすれば OK だと思います

fluentd のインストール

  • sudo gem install fluentd

これで問題なくインストールできました
他にも lib なんちゃら系が必要になるかもしれません
おそらく自分は他のインストール作業で lib なんちゃら系をインストールしていたのだと思います

一応インストール成功時の Gem のログを記載しておきます

Building native extensions. This could take a while…
Successfully installed msgpack-0.6.0pre1
Fetching: yajl-ruby-1.2.1.gem (100%)
Building native extensions. This could take a while…
Successfully installed yajl-ruby-1.2.1
Fetching: cool.io-1.4.1.gem (100%)
Building native extensions. This could take a while…
Successfully installed cool.io-1.4.1
Fetching: http_parser.rb-0.6.0.gem (100%)
Building native extensions. This could take a while…
Successfully installed http_parser.rb-0.6.0
Fetching: sigdump-0.2.3.gem (100%)
Successfully installed sigdump-0.2.3
Fetching: thread_safe-0.3.5.gem (100%)
Successfully installed thread_safe-0.3.5
Fetching: tzinfo-1.2.2.gem (100%)
Successfully installed tzinfo-1.2.2
Fetching: tzinfo-data-1.2015.7.gem (100%)
Successfully installed tzinfo-data-1.2015.7
Fetching: string-scrub-0.0.5.gem (100%)
Building native extensions. This could take a while…
Successfully installed string-scrub-0.0.5
Fetching: fluentd-0.12.16.gem (100%)
Successfully installed fluentd-0.12.16
Parsing documentation for cool.io-1.4.1
Installing ri documentation for cool.io-1.4.1
Parsing documentation for fluentd-0.12.16
Installing ri documentation for fluentd-0.12.16
Parsing documentation for http_parser.rb-0.6.0
Installing ri documentation for http_parser.rb-0.6.0
Parsing documentation for msgpack-0.6.0pre1
Installing ri documentation for msgpack-0.6.0pre1
Parsing documentation for sigdump-0.2.3
Installing ri documentation for sigdump-0.2.3
Parsing documentation for string-scrub-0.0.5
Installing ri documentation for string-scrub-0.0.5
Parsing documentation for thread_safe-0.3.5
Installing ri documentation for thread_safe-0.3.5
Parsing documentation for tzinfo-1.2.2
Installing ri documentation for tzinfo-1.2.2
Parsing documentation for tzinfo-data-1.2015.7
Installing ri documentation for tzinfo-data-1.2015.7
Parsing documentation for yajl-ruby-1.2.1
Installing ri documentation for yajl-ruby-1.2.1
Done installing documentation for cool.io, fluentd, http_parser.rb, msgpack, sigdump, string-scrub, thread_safe, tzinfo, tz
info-data, yajl-ruby after 416 seconds
10 gems installed

Tips

ldconfig の追記

もしかしたらやらなくても OK かもしれません

  • sudo touch /etc/ld.so.conf.d/userlocal.conf
  • sudo vim /etc/ld.so.conf.d/userlocal.conf

/usr/local/lib

  • sudo ldconfig

td-agent はインストールできなかった

公式サイトを見ると Debian の最新版の Jessie 用のインストールコマンドが載っていました

  • curl -L https://toolbelt.treasuredata.com/sh/install-debian-jessie-td-agent2.sh | sh

しかしこれでインストールしようとしても

W: http://packages.treasuredata.com/2/debian/jessie/dists/jessie/InRelease の取得に失敗しました 期待されるエントリ 'contrib/binary-armhf/Packages' が Release ファイル内に見つかりません (誤った sources.list エントリか、壊れたファイル)

というエラーになりインストールできません
RaspberryPi 上で動作している ARM の CPU アーキテクチャはサポートしていないようでインストールできませんでした

上記でインストールできたほうが、service コマンドで起動できたるので嬉しかったのですが

2015年10月18日日曜日

gatttool で Bluetooth デバイスの情報を取得する方法

概要

RaspberryPi 上に BlueZ をインストールして gatttool でデバイスの情報を取得する方法を紹介します
また今回使用した BLE デバイスは BL600 です

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)
  • Kernel Version 4.1.10
  • BlueZ 5.23-2+b1

BLEデバイスをスキャンし接続する

  • sudo hcitool -i hci0 lescan

でまずは Mac アドレスを調べます
対象の Mac アドレス (今回は xx:xx:xx:xx:xx:xx) が判明したら gatttool で接続します
これで gatttool のインタラクティブモードになります

  • gatttool -t random -b xx:xx:xx:xx:xx:xx -I

あとは connect コマンドを実行しましょう

[xx:xx:xx:xx:xx:xx][LE]> connect
Attempting to connect to xx:xx:xx:xx:xx:xx
Connection successful
[xx:xx:xx:xx:xx:xx][LE]>

connect に成功するとプロンプトの色が青色に変化すると思います

値を取得する

まず primary というコマンドを実行しましょう

[xx:xx:xx:xx:xx:xx][LE]> primary
attr handle: 0x0001, end grp handle: 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x0008, end grp handle: 0x0008 uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x0009, end grp handle: 0x000e uuid: 0000180d-0000-1000-8000-00805f9b34fb
attr handle: 0x000f, end grp handle: 0x0012 uuid: 0000180f-0000-1000-8000-00805f9b34fb
attr handle: 0x0013, end grp handle: 0xffff uuid: 0000180a-0000-1000-8000-00805f9b34fb

すると謎の文字列がずらーっと出てくると思います
これがこのデバイスから取得できるサービスの一覧です
サービスとは BLE が定めたもので各種値は必ずどこかのサービスに属しています

着目するのはこの中の uuid という項目でこの uuid を元にどんなデータが取得できるサービスなのか判断します

例えば一番上の uuid 00001800-0000-1000-8000-00805f9b34fb の初めの8桁の下4桁 1800 に着目します
この 1800 を先ほどの URL の中で探すと Generic Access という項目に該当することがわかります
そして Generic Access の中に Device Name という項目がありここの問い合わせることでデバイス名を取得することができます
では具体的に値を取得してみましょう

デバイス名を取得する

1800 のサービスの中でどの項目がデバイス名なのか調べる必要があります
どんな項目があるかは char-desc というコマンドを使用します

[xx:xx:xx:xx:xx:xx][LE]> char-desc 0x0001 0x0007
handle: 0x0001, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0002, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0003, uuid: 00002a00-0000-1000-8000-00805f9b34fb
handle: 0x0004, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0005, uuid: 00002a01-0000-1000-8000-00805f9b34fb
handle: 0x0006, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0007, uuid: 00002a04-0000-1000-8000-00805f9b34fb

するとまたずらーっと謎の文字列が登場します
この中のどれかがデバイス名になります
ここでまた登場するのが uuid です
先ほど紹介した Generic Access の詳細を説明するページに移動します
この中の「Device Name」をクリックすると「 Assigned Number: 0x2A00」というのが記載されていると思います
ble_device_name_number.png

この「2A00」を先ほどの char-desc の uuid 下4桁と照らし合わせると以下が該当することがわかります

handle: 0x0003, uuid: 00002a00-0000-1000-8000-00805f9b34fb

ここにアクセスするとデバイス名を取得できそうです
で、アクセスする方法は以下になります

[xx:xx:xx:xx:xx:xx][LE]> char-read-hnd 0x0003
Characteristic value/descriptor: 46 5f 49 49 49

取得できたと思ったら謎の文字列がまた返ってきました
先ほどの Device Name の説明のページを見ると「Format」という欄がありそこに「utf8s」と記載されているのがわかると思います
つまりこの16進数の数字の羅列を utf8s に変換する必要があるのです(面倒くさい!)
そして utf8s への変換方法は以下の通り

  • echo ” 46 5f 49 49 49” | tr \ = | nkf -WwmQ

ちなみにこの文字列は「F_III」に変換されます
ちょっとわかりづらいですが、echo している文字列の先頭にはスペースが入っています
tr コマンドの変換元の文字列はスペースをエスケープしているため「\」が変換元の文字列になります

こんな感じでデバイス名は取得することができます

バッテリ残量を取得する

バッテリ残量も同様の方法で取得することができます
uuid は「0x180F Battery Service」になります

[xx:xx:xx:xx:xx:xx][LE]> connect
Attempting to connect to xx:xx:xx:xx:xx:xx
Connection successful
[xx:xx:xx:xx:xx:xx][LE]> primary
attr handle: 0x0001, end grp handle: 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x0008, end grp handle: 0x0008 uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x0009, end grp handle: 0x000e uuid: 0000180d-0000-1000-8000-00805f9b34fb
attr handle: 0x000f, end grp handle: 0x0012 uuid: 0000180f-0000-1000-8000-00805f9b34fb
attr handle: 0x0013, end grp handle: 0xffff uuid: 0000180a-0000-1000-8000-00805f9b34fb
[xx:xx:xx:xx:xx:xx][LE]> char-desc 0x000f 0x0012
handle: 0x000f, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0010, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0011, uuid: 00002a19-0000-1000-8000-00805f9b34fb
handle: 0x0012, uuid: 00002902-0000-1000-8000-00805f9b34fb
[xx:xx:xx:xx:xx:xx][LE]> char-read-hnd 0x0011
Characteristic value/descriptor: 52

Format を見ると uint8 なので符号なし整数です
値はもちろん16進数なのでこれを10進数に変換すると

52(16) = 82(10)

になります
単位はパーセンテージなので電池残量は残り 82 %だとわかります

最後に

紹介は以上です
取得の仕組みがわかるとスイスイ値を取得できますが、わかるまでが大変でした
基本的に英語の文献ばかりなので英語が読めないと辛いです

Tips

  • UUID を直接指定して値を取得する方法
    例えばデバイス名を取得する場合

char-read-uuid 2a00

でも取得することができます

  • インタラクティブモードじゃない方法で取得する方法

gatttool -t random -b xx:xx:xx:xx:xx:xx –char-read –uuid=0x2a00

この場合 connect -> disconnect も勝手に行ってくれます

  • 存在しない UUID もあります
    UUID は決められてはいますがデバイスによってはカスタマイズされており、存在していないものもあります
    なのでサービスの一覧と primary コマンド等で UUID を照らし合わせつつ値の取得を行ってください