modalsoul’s blog

これは“失敗”と呼べるかもしれないが、ぼくは“学習体験”と呼びたい

Luhnアルゴリズムによる誤り検出

Luhnアルゴリズムについてちょっと話題に上がったので書いてみる

Luhnアルゴリズム 1

クレジットカード番号やIMEI番号の検証に使われているアルゴリズム

  • 任意の1桁の間違いや隣接する桁の数字の順序間違いを検出できる
  • 09 から 90 (または逆)という間違いは検出できない
  • 同じ数字が2つ連続する場合の間違いも10種類のうち4種類までは検出できる
    • 22 ⇔ 55、33 ⇔ 66、44 ⇔ 77 は検出できない

記入ミスやタイプミスを検出するもので、クレジットマスターを防ぐことはできない (ここテストにでます

IMEI番号は電話のキーパッド*#06#と入力すると表示される

検証手順

  • 右端のチェックディジットを1番目として、偶数番目の桁を2倍にする。
  • 2倍にしていない桁も含め、各数字の総和を求める(2倍にした桁が2桁になった場合は、それぞれを別々の数字として加える)。
  • この総和の下1桁が0なら(つまり、10で割り切れる場合)、この番号はLuhnアルゴリズムでは正しく、そうでない場合は正しくない。

実装

これをScalaで実装してみた

Raspberry Pi Zeroで車載機をDIYしたときのアレコレとその先

これはRaspberry Pi Advent Calendar 2018の2日目の記事です。

adventar.org


modalsoul.hatenablog.jp

↑の記事のなかで、Raspberry Pi Zero WHを使った車載機を作ったときのアレコレを書いてみます

使ったもの

9軸センサー

modalsoul.hatenablog.com

車両の状態変化を観測するために9軸センサーを使用

小学生のとき以来?のはんだ付け

FaBo9Axis_MPU9250モジュールをPython3系で使ったときに、MPU9250.pyprint "~"Syntax Errorになってハマったのはモニョッたぜ。。

GPS

modalsoul.hatenablog.com

車両の位置情報を取得するのにみちびき対応のGPS受信機キットを使用

配線をミスって、RxD <-> RxD、TxD <-> TxDと繋いでいることに気づかず、設定を何度もチェックするという。。

俺はなぜあんな無駄な時間を・・・

みちびき4機対応のファームアップデートしないとなー

Bluetooth

modalsoul.hatenablog.com

セキュリティのON/OFFを判定するのに、Bluetoothバイスのスキャンを使った

ほんとうはBLEのBeaconタグを使うつもりだったけど、間に合わず

BLE Beaconを受信するところがなんかうまくいかなかったので、もうちょっと調べたい

スピーカー

modalsoul.hatenablog.com

システム音声を再生するのに使った

ほんとうに音量が控えめ、悟りを開きそうになるくらい耳を澄まさないと聞こえない。。

今回のシステム音声は予め用意した音声ファイルを使ったけど、Raspberry Pi音声合成するのも試してみたい

物理ボタン

modalsoul.hatenablog.com

Raspberry Piをいじる上で、物理ブート/シャットダウンボタンはほんとうに役に立った

スイッチはトグルタイプに変えたさある

使いたいもの

電子ペーパー

やっぱりスピーカーとLEDランプ以外の出力が欲しい

けれど、消費電力の都合上ディスプレイは厳しそうなんで、電子ペーパー使ってみたいですね

フリップドットディスプレイ

iizukak.hatenablog.jp

フリップドットディスプレイつけたいんですが、気軽に手に入るのないですかね?

多謝

Raspberry Pi Zeroについて

GPIOのピン、どうやっても並びを覚えられなくて、どっちから数えて何番目だっけ?ってとき、このページのハードウェア図は何度も参照しました

この場を借りて感謝

最後に

今年の秋頃からぽつぽつとRaspberry Piをいじりだして、まだわからないことのほうが多いけど、こんな感じで楽しくやっていきたいですねー

Raspberry Pi Zero WHで、 BLE Beaconを送信する&Bluetoothデバイス名を変更する

Raspberry Pi Zero WHは、Bluetooth4.0/BLE(Bluetooth Low Energy)が使えるので、Beaconの送信をしてみた

Bluez

LinuxオフィシャルなBluetoothスタックのBluezを使います

Bluez-ibeaconのインストール

手っ取り早くBluez-iBeacon github.com

cd /usr/local/src
sudo git clone https://github.com/carsonmcdonald/bluez-ibeacon.git
cd bluez-ibeacon/bluez-beacon/
sudo make

Usage

cd bluez-ibeacon/bluez-beacon/
./ibeacon
Usage: ./ibeacon <advertisement time in ms> <UUID> <major number> <minor number> <RSSI calibration amount>

Beaconの送信

sudo ./ibeacon 200 67567567567567567567567567567567 1 1 -29
param value
advertisement time in ms 200
UUID 67567567567567567567567567567567
majer number 1
minor number 1
RSSI calibration amount -29

※ パラメータはこれを参考に設定

Beaconの受信

BLEスキャナー

今回はこのアプリを使用 play.google.com

受信できました

距離もImmediate(至近距離)と出てます

Bluetoothバイス名の変更

Beaconを受信できたけど、デバイス名が機械的で認識しずらいので、名前を変更する

/etc/machine-info

/etc/machine-infoを作成し、以下の内容を記述する

PRETTY_HOSTNAME=device-name

Bluetooth serviceのrestart

sudo invoke-rc.d bluetooth restart

確認

再度beaconを送信して確認

バイス名が任意の名前に変更できた

Raspberry Pi Zero WHで、みちびき対応GPS受信機キットを使い位置情報を取得する

秋月電子GPS受信機キットを買ったので、位置情報を取得してみた1

GPS受信機キット

akizukidenshi.com

小型高感度GPSモジュールを使ったGPS受信機キットで、バックアップ電池の電池ボックスとピンヘッダのはんだ付けが必要 ※ バックアップ電池を使わない場合、電池ボックスは不要

配線

Raspberry Pi Zero GPSモジュール
5V 5V
GND GND
RxD TxD
TxD RxD
なし 1PPS

とても基本的なことなんですが、RxDとTxDはクロスさせて接続します。これを間違えて、位置情報が取れず何度も設定を見直し、時間を無駄にしてしまった。。※ 上の写真は間違えた状態です

シリアルの有効化

raspi-config

sudo raspi-config
  • P5 Interfacing Options
  • P6 Serial
  • YES

で、Finish

> ls /dev/serial*
/dev/serial0

/dev/serial0があることを確認

/boot/cmdline.txt

sudo vi /boot/cmdline.txt

もとの/boot/cmdline.txtから、console=serial0,115200の記述を削除する

# dwc_otg.lpm_enable=0 console=tty1 console=serial0,115200 root=PARTUUID=b7e00398-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait modules-load=dwc2,g_ether
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles

リブート

sudo reboot

動作確認

pyserialのインストール

シリアルモジュールをインストール

pip install pyserial

repl

~$ python
Python 3.6.6 (default, Oct  7 2018, 12:22:23)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import serial
>>> s = serial.Serial('/dev/serial0', 9600, timeout=10)
>>> s.readline().decode('utf-8')
'$GPGGA,154327.000,,,,,0,1,,,M,,M,,*4F\r\n'

なにか値が取得できた

NMEA0183

モジュールから得られるデータは、NMEA0183に準拠したフォーマットになっている NMEA 0183 - Wikipedia

micropyGPS

取得したデータを扱いやすくするために、NMEAパーサーのmicropyGPSを使う

github.com

repl

Python 3.6.6 (default, Oct  7 2018, 12:22:23)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import serial
>>> from micropyGPS import MicropyGPS
>>> my_gps = MicropyGPS(9, 'dd')
>>> s = serial.Serial('/dev/serial0', 9600, timeout=10)
>>> for x in s.readline().decode('utf-8'):
...     my_gps.update(x)
...
'GPGGA'
>>> my_gps.latitude
[35.658580566666665, 'N']
>>> my_gps.longitude
[139.74323896666668, 'E']

これでいい感じの位置情報が取得できるようになった

Headlessモード時、ChromeDriverでファイルダウンロードに失敗した話

ChromeDriverでファイルダウンロードするSeleniumスクリプトを書いたとき、非Headlessモードでは成功するのに、Headlessモードで失敗した件のメモ

tl;dr

Headlessモードの場合、

  • target=_blankなアンカーをclick()してもファイルダウンロードできない
  • target属性を削除してclick()するとダウンロードできる

前準備

基本は前の記事と同じです

modalsoul.hatenablog.com

当たり前ですが、docker上では非Headlessモードでは動作させられないので注意

スクリプト

コマンドライン引数でHeadlessモードのON/OFFを替えられるようにしています

検証

ex.) 非Headlessモードで動作

python scraping.py

ex.) Headlessモードで動作

python scraping.py --headless=True

非Headlessモードでは、sample_zengin.csvがダウンロードできますが、Headlessモードではダウンロードされません。

対処

↓では、同じくアンカーをclick()することでファイルダウンロードに成功しています

modalsoul.hatenablog.com

この違いは、ダウンロードに失敗したページのアンカーにはtarget=_blankがあったことで

target属性を削除し、アンカーをclickするようにします

変更点は、L.35の追加のみです

これで、Headlessモードでもファイルダウンロードができようになりました


あまり良い例じゃないですが、挙動から原因を切り分けにくくなかなか面倒だったので、覚えておくといいことあるかも

HeadlessモードのChromeDriverでファイルダウンロードに失敗する現象のトラブルシューティング

ファイルのダウンロードをするSeleniumスクリプトを、docker上でheadlessモードのChromeDriverで動作させた際、ファイルのダウンロード処理に失敗する現象が起きたので、その対処方法のメモ書き

前準備

基本的なところは前回と同じ modalsoul.hatenablog.com

ファイルのダウンロードをする処理を追加しています(と言っても、anchorをクリックするだけですが

ダウンロード先ディレクトリを掘って

> make scraping
> docker-compose run scraping /bin/sh
> python scraping.py

のような感じで実行できます

現象その1

headlessモードで動作させると、ファイルのダウンロードがされない

  • スクリプトが正常終了しても、保存先パスにファイルが存在しない
  • dockerではなくローカルのmacで非headlessモードで実行すると成功する

対処

ggってこれを見つけました

python - Downloading with chrome headless and selenium - Stack Overflow

セキュリティの制約?で失敗しているようで、chromedriverのコマンドにPage.setDownloadBehaviorを追加する必要があるようです

スクリプトを以下のように変更しました

これを実行すると、今度は別のエラーが

現象その2

selenium.common.exceptions.WebDriverExceptionで失敗する

/opt/app/scraping # python scraping.py
Traceback (most recent call last):
  File "scraping.py", line 33, in <module>
    main()
  File "scraping.py", line 23, in main
    enable_download_in_headless_chrome(driver, DOWNLOAD_PATH)
  File "scraping.py", line 11, in enable_download_in_headless_chrome
    driver.execute("send_command", params)
  File "/usr/local/lib/python3.6/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute
    self.error_handler.check_response(response)
  File "/usr/local/lib/python3.6/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: unknown error: unhandled inspector error: {"code":-32601,"message":"'Page.setDownloadBehavior' wasn't found"}
  (Session info: headless chrome=61.0.3163.100)
  (Driver info: chromedriver=2.30 (30087a73289cd80b9611f658ed81448badaf549e),platform=Linux 4.9.93-linuxkit-aufs x86_64)

原因

Chromedriverのバージョンが古いために、Page.setDownloadBefaviorに対応していなかったようです

この時点でのChromedriverのバージョンは

/opt/app/scraping # chromedriver -v
ChromeDriver 2.30 (30087a73289cd80b9611f658ed81448badaf549e)

対処

alpine3.8を使います

これで2.38がインストールできました

/opt/app/scraping # chromedriver -v
ChromeDriver 2.38 (f91d32489882be7df38da3422a19713bfd113fa5)

スクリプトを実行し、無事ファイルのダウンロードが確認できました


これ以外にもいくつかエラーに遭遇したので、また別にまとめようと思います

Raspberry Pi Zero WHでリレーモジュールを使って電源制御

Raspberry Pi Zero WHで、大きい電圧(ex. 12V)で動作する機器の電源を制御するために、リレーモジュールをつなげてみた。1

リレーモジュール

Raspberry Piでの使用例が多かったこのリレーモジュールをポチった

SODIAL(R) リレーモジュール

SODIAL(R) リレーモジュール

2チャンネルにしたのはなんとなくです

接続機器

リレーモジュールに繋いで動作確認に使ったもの

ケースファン

リレーモジュールで動かす機器は、余っていたケースファンを使用

USBケーブル

USBケーブルでファンに給電し、今回はこれをリレーモジュールで制御する

配線

Raspberry Pi Zero リレーモジュール
5V JD-VCC
GPIO14 VCC
GND GND/GND/IN1/IN2

ファン <-> リレーモジュールCOM1 電源 <-> リレーモジュールNO1 ファン <-> 電源

動作確認

コマンドライン

pi@raspberrypi:~$ echo 14 > /sys/class/gpio/export
pi@raspberrypi:~$ echo out > /sys/class/gpio/gpio14/direction
pi@raspberrypi:~$ echo 1 > /sys/class/gpio/gpio14/value
pi@raspberrypi:~$ echo 0 > /sys/class/gpio/gpio14/value

これで、ファンの電源がON->OFFにかわります

プログラム

pythonで制御するコードを書くとこんな感じ

import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
GPIO.setup(14,GPIO.OUT)
GPIO.output(14, True)
time.sleep(3)
GPIO.output(14, False)
GPIO.cleanup()