RaspberryPiでNFCをトリガーにしてサーボモーターを駆動する

フェリーハッカソンでできなかったことをやってみる

以前参加した、フェリーハッカソンでは、QRコードを読み取ってサーボモーターの駆動をしていました。 今回はNFCのリーダーを使用してサーボモーターを駆動させてみたいと思います。時間が余っていればやりきりたかった。

【参考】 uepon.hatenadiary.com

若干異なる点としてはpythonnfcのモジュールが2.7系にまでにしか対応していない点が挙げられます。 とはいえ、今回使用しているRPiのモジュールは2系でも3系でも大きな差がなく使用することができるので 大丈夫ではないかなと。だめであればそれも含めて調査する方向でやっていこうと思います。

nfcモジュールに関して

pythonで使用できるnfcモジュールを使用してトリガーを取得していきたいと思います。

以前も使用しているので細かい部分はそちらをご参考にお願いします。

【参考】

uepon.hatenadiary.com

基本的にはnfcモジュールイベントハンドラを使用して、ループさせ、ReaderからIDmが取得できた場合にサーボ制御を行うものになります。 特に組み合わせれば難しくないかなと思います。こちらの処理は以下のような動きをします。

  1. nfcリーダーでFelicaに含まれたIDmの読み込み待ちをする。(ループ)
  2. IDmが認識できたら、サーボモーターを制御する(鍵を開ける)
  3. 鍵を開けた状態で10秒間ウエイトを行う
  4. サーボモータを再度制御する(鍵を閉める)

コード書いてみた

今回のコードではGPIO4でサーボモータを制御、GPIO17でLEDの制御を行っています。

f:id:ueponx:20190203232411j:plain

import nfc
import binascii
import RPi.GPIO as GPIO
import time

class NFCReader(object):
    def on_connect(self, tag):
        print("touched")
        self.idm = binascii.hexlify(tag.idm)
        return True

    def read_id(self):
        clf = nfc.ContactlessFrontend('usb')
        try:
            clf.connect(rdwr={'on-connect': self.on_connect})
        finally:
            clf.close()

if __name__ == '__main__':
    GPIO.setmode(GPIO.BCM)
    gp_out = 4
    gp_led = 17
    GPIO.setup(gp_out, GPIO.OUT)
    GPIO.setup(gp_led, GPIO.OUT, initial=GPIO.LOW)
    servo = GPIO.PWM(gp_out, 50)

    reader = NFCReader()
    while True:
        print("touch card:")
        reader.read_id()
        print("released")
        print(reader.idm)

        GPIO.output(gp_led, GPIO.HIGH)

        servo.start(0.0)
        servo.ChangeDutyCycle(2.5)
        time.sleep(0.5)
        servo.stop()

        time.sleep(10.0)

        servo.ChangeDutyCycle(7.5)
        time.sleep(0.5)
        servo.stop()

        GPIO.output(gp_led, GPIO.LOW)

        # GPIO.cleanup()

今回はnfcの処理の部分は汎用性をもたせるためにクラス化しています。 また、特定のIDmで開けるといった処理はしていません。リーダーで何らかのデータを読み込めた場合には判断なく処理をする形にしています。 割と簡単にできたなと思います。

おわりに

ある程度組み合わせればなんかできそうなことが増えてきました。今回も2時間もかからず出来上がった感じでした。

できれば、nfcモジュールがそろそろPython3に対応してもらえると…淡い希望でした。

Chrome OS(Chromium OS)にVisual Studio Codeをインストールしてみた

Chrome OSとはいってますけど、Chromium OSの話になります。まあ、純正のChromebookを持っている人にはあんまり関係ない話。

昨年の年末、以前までChromeOSを使用していたノートPCがある日突然電源が入らなくなり、突然のお別れということになってしまった。購入からすでにもう10年ぐらい経っているCeleronなPCなのでそろそろ動作しなくなってもおかしくないので、このときが来たかというレベルでしかなかったです。

Aspire one 753(2010年製) http://www2.acer.co.jp/catalog/1012/FIX_NBALL_0616.pdf

いよいよ廃棄するにあたって、最後に電源でもいれてみるかなと思ったら突然電源が復帰。あれーって感じ。ただ、Windows10Homeは立ち上がらず、シリアルも探さなければならないという状況。結論としてクリーンインストールが必要という状態でした。さすがにWindows10ではパワー不足というのはわかっていたので、別のOSをいれてもいいかなと。候補としてはUbuntuChrome OSを考えました。この2つのOSはUSBメモリでの起動であっても、実用面でも全然問題ないことはわかっていたので、もう好みでしかないかなと。

uepon.hatenadiary.com

前回、USBメモリ起動で設定したのエントリーを書いたときにChrome OSの最新ビルドではLinuxのコンソールが使用可能になったらしいという噂は聞いていたのですが、使用したイメージではちょっと古いもの(CloudReadyのイメージは追いかけるスタイルなので当然といえば当然)だったので、その設定項目はありませんでした。まあ、最新のビルドを追っていくほどの気合がなかっったのでこういうのは仕方ないですけど。

しかしあれから半年ぐらいたったのでそろそろChrome OSを改めてインストールするのもいいかなと。Windows10のHDD温存という意味でのUSBブートにそこまでこだわりがなくなったので、今回はSSDChrome OSをインストールすることにしました。 それだけではブラウジングしかできない感じなのでVisualStudio Code(以降VSCode)をインストールして文書をかけるようなPCへ設定していこうと思います。

USBでインストールメディアを作成する

まずはインストールをするメディアを作成します。

基本的には以前書いたエントリーと同じように作成すればOKです。

【参考】 uepon.hatenadiary.com

今回の手順としては

  1. イメージファイルをダウンロードし、USBメモリに書き込み
  2. USBメモリをPCに挿して、PCを起動する
  3. USBメモリから内蔵ディスクにインストール
  4. Chrome OSLinuxコンテナを有効化
  5. VScodeのインストール
  6. 日本語表示・入力の設定

イメージファイルをダウンロードし、USBメモリに書き込み

CloudReadyのイメージをダウンロード

今回も使用するのはNeverware社が製品化しているChromium OSとなります。個人利用は無料なのでビジネス用途、教育用途でなければ大丈夫です。

www.neverware.com

f:id:ueponx:20190202224037p:plain

USBメモリは以下のものを使用していますが、16GBぐらいの容量のものを使えば大丈夫だと思います。

今回使用するイメージは【GET THE FREE VERSION】ボタンを押した先にある

f:id:ueponx:20190202224344p:plain

【DOWNLOAD 64-BIT】ボタンをクリックするとダウンロードできるものを使用します。

f:id:ueponx:20190202224616p:plain

Zipファイルなので伸張してからUSBメモリに書き込みを行います。

USBメモリへの書き込み

書き込みアプリはNeverwareのホームページ内のStep2にあるUSBMakerを使用してもいいと思いますが、私は前回同様にEtcherを使用しました。

www.balena.io

最新のEtcherの見た目のイメージが結構かわっちゃいましたね。

【起動画面】 f:id:ueponx:20190202203235p:plain

【イメージファイルの指定とUSBドライブの選択】 f:id:ueponx:20190202203057p:plain

【書き込み中】 f:id:ueponx:20190202203117p:plain

【完了】 f:id:ueponx:20190202203125p:plain

これで準備完了です。

USBメモリをPCに挿して、PCを起動する

このあたりは問題はないと思います。

起動するとこんな画面になります。まずはここで言語とキーボードの選択をしていきます。【English(United States)】と書いてある左側のボタンをクリックします。

f:id:ueponx:20190202215519j:plain

言語、キーボードを日本語に設定します。設定が終わったら【OK】ボタンをクリックします。

f:id:ueponx:20190202215535j:plain

画面が戻ると選択した言語で表示されるようになります。【続行】ボタンをクリックします。

f:id:ueponx:20190202215610j:plain

次はネットワークの設定になります。ここで接続するネットワークを指定します。WiFiの場合にはSSIDとパスワードを入力していくことになります。

f:id:ueponx:20190202215903j:plain

ネットワーク設定が終わるとデータ取得の許諾画面になりますが、チェックするかどうかは個人のポリシーでってところでしょうか。【Continue】ボタンをクリックします。

f:id:ueponx:20190202215933j:plain

最後はChromeOSでログインするGoogleのアカウントの登録をします。メールアドレス、パスワードなどを使ってログインをします。(2段階認証の方はその処理もここで行われます)

f:id:ueponx:20190202215937j:plain

これが終わると設定が完了となります。

f:id:ueponx:20190202215941j:plain

SSDであればイメージのダウンロードを含めても1時間以内で終わるかなという印象です。

USBメモリから内蔵ディスクにインストール

USBから起動すると起動後のメニューに内蔵ディスクへのインストールが表示されるので、それを選択してインストールを行っていきます。

画面の右下のバーをクリックするととその中にInstallOSというボタンがあるのでクリックします。

f:id:ueponx:20190202215946j:plain

いろいろと確認がでるので画面に従っていきます。

f:id:ueponx:20190202215952j:plain

少し時間がかかりますが終了すると電源がOFFされるので頬っておきましょう。 これでインストール開始となります。

インストールしたPCの起動

USBをコネクタから抜いてPCを起動します。 起動するとUSB起動と同様の設定を行うことになります。ここまでくると説明はなくてもいいかなと。

すべて終わると作業はほぼ終了になります。

f:id:ueponx:20190202234548p:plain

起動したらタイムゾーンだけは直しておいたほうがいいかなと思います。 【設定】の画面で日時を選択すればタイムゾーンを変更できます。

f:id:ueponx:20190202234411p:plain

インストール後の設定

Linuxのコンテナ機能を使えるようにする

続いてはLinuxのコンテナが使えるように設定を行って行きます。 この機能はまだベータ版らしいのですが特に問題はなさそうです。

【設定】の画面のなかからLinuxの項目までスクロールさせて、

f:id:ueponx:20190202234438p:plain

【オンにする】ボタンで機能を有効にすることができます。

f:id:ueponx:20190202234457p:plain

再度インストール確認のダイアログが表示されるので【インストール】ボタンをクリックします。

f:id:ueponx:20190203165608p:plain

これでChromeOSのLinuxコンテナがインストールされます。

f:id:ueponx:20190202235643p:plain

インストールが終わるとコンソールが開きます。

f:id:ueponx:20190202235701p:plain

これで使用できるようにはなりますが、念の為パッケージなどのアップデートは行っておいたほうがいいかなと思います。

Linuxコンテナのバージョンなどを見てみると…

hoge@penguin:~$ uname -a
Linux penguin 4.19.4-02480-gd44d301822f0 #1 SMP PREEMPT Thu Dec 6 17:45:27 PST 2018 x86_64 GNU/Linux

hoge@penguin:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux 9.7 (stretch)
Release:        9.7
Codename:       stretch

Debianであることがわかるので、念の為にaptのアプデートやパッケージのアップグレードはしておいたほうがよいでしょう。

hoge@penguin:~$ sudo apt update
hoge@penguin:~$ sudo apt upgrade

pythonのバージョンは3.5ぐらいが入っていますが、あとはvimなどが入っているかなっと言う程度のレベルでしかありません。 node.jsぐらいはインストールしておいてもいいかなという感じでしょうか。(図らずもnode.jsのインストールを行うと、python2.7もインストールされます)

Visual Studio Codeをインストールし、日本が入力ができるようにする

大きくわけて2つの設定が必要になります。まずはVisual Studio Codeをインストールし設定を行う部分。もう一点は日本語入力を行う設定。 Linuxコンテナでも日本語入力を行うことができるのに、なぜ日本語設定が必要になるかというと、Linuxコンテナ上で起動したアプリケーションでは 日本語の入力がサポートされていないので、そのために別途、入力メソッドと日本語変換システムの橋渡しが必要になります。

Visual Studio Codeをインストールする

基本的には以下のリンク先の操作を行えば問題なくインストールができました。

code.visualstudio.com

まずはこちらからdeb形式のパッケージをダウンロードしaptコマンドでインストールを行います。deb形式だからdpkgかなとも思いますが、 aptで大丈夫です。aptを使用すればパッケージの依存関係も解決してくれます。

code.visualstudio.com

今回ダウンロードしたファイルはcode_1.30.2-1546901646_amd64.debだったので以下のようにインストールを行います。(2019.02.01現在)

f:id:ueponx:20190203161604p:plain

hoge@penguin:~$ sudo apt install ./code_1.30.2-1546901646_amd64.deb

インストールが終わるとコンソール上からはcodeコマンドで実行することができます。

f:id:ueponx:20190203161451p:plain

ランチャーにも登録されています。

f:id:ueponx:20190203161408p:plain

一応、起動はしますが、日本語の表示などに関しては完全にアウトです。日本語が含まれた文字列をペーストすると、フォントがないよんみたいな表示で残念な気持ちになります。

f:id:ueponx:20190203162001p:plain

日本語関連の設定

以下を参考にさせていただきました。

www.taneyats.com

qiita.com

大変助かりましたありがとうございました。

日本語の表示

先程の日本語が表示されていない問題は単に日本語フォントがないというだけの問題です。フォントをインストールさえすれば問題なく表示されます。 Chrome OS側は日本語表示されるのに?というのはありますが、Linuxコンテナから起動されるものは別の扱いがされるということなので諦めるしかないかなと。 ファイルシステムも別れてはいますが、シームレスではないもののマイファイルを表示するとLinuxファイルという形で共有ができるようになっているので、 そのうちシームレスな連携ができるようになるのかなと思います。(Windows Subsystem for Linuxって今どうなってるんでしたっけ?最近使ってないのでよくわからない)

この状態が

f:id:ueponx:20190203162001p:plain

フォントのインストールを行うと表示は解決します。フォントのインストール後にVSCodeを再起動すればOKです。

hoge@penguin:~$ sudo apt install fonts-noto

f:id:ueponx:20190203162315p:plain

一応表示に関してはこれで問題なくなりましたが、やっぱり入力できないとあんまりうれしくない。(この状態でペーストには対応しています。)

日本語入力の設定をする

今回は、入力メソッドにはfcitxを、日本語入力システムにはmozcを使用します。

hoge@penguin:~$ sudo apt install -y fcitx-mozc

インストールしたら動作確認してみます。

hoge@penguin:~$ fcitx -v
fcitx version: 4.2.9.1

正常にインストールできているようです。あとはfcitxmozcとの連携の設定になります。

設定するときによく忘れるのですが、まずランチャーからfcitxを起動します。起動してるぜーってくるくる回るアイコン表示してますが、そのまま次の作業にはいって大丈夫です。

f:id:ueponx:20190203162946p:plain

起動したら設定ツールを起動します。このツールでfcitxmozcを連携させていくことになります。

hoge@penguin:~$ fcitx-configtool

設定ツールが起動したらウインドウの下にある【+(プラス)】ボタンをクリックします。

f:id:ueponx:20190203170716p:plain

すると追加設定のダイアログが表示されるので

f:id:ueponx:20190203170846p:plain

検索の入力ボックスにmozcと入力し、【Only Show Current Page】チェックボックスを外すと【Mozc-Japanese】という候補が現れます。

f:id:ueponx:20190203171121p:plain

リストからそれを選択して【OK】ボタンをクリックします。

f:id:ueponx:20190203174134p:plain

リストが以下のようになればOKです。

f:id:ueponx:20190203174911p:plain

続いてフォントの設定になります。ウインドウの上の方にある【Appearance】タブをクリックします。 この画面ではフォントの設定や起動キーの設定ができます。

f:id:ueponx:20190203191711p:plain

この中から【Font】と【Menu Font】をクリックしてフォントの選択を行います。 フォント選択のダイアログが表示されたらサーチの入力ボックスにNoto Sans CJK JPといれると絞り込みができます。

f:id:ueponx:20190203191922p:plain

これでOKです。

最後に~/.profilefcitxの起動の設定行います。

hoge@penguin:~$ vim ~/.profile 

以下を追加します。

fcitx > /dev/null 2>&1

これで設定は完了です。

ではVSCodeを起動して確認をしてみます。日本語変換の起動は【Ctrl + Space】となります。 無事に起動すると以下のような画面で変換候補が表示されます。

f:id:ueponx:20190203192509p:plain

ただ、これにも問題があってLinuxコンテナでのアプリケーションの設定は起動時に反映されないので、 Linuxコンテナの起動(シェルの起動)に合わせて設定が行われます。(VSCodeは直接起動できるにもかかわらず) なので、VSCodeを起動直後に起動しても日本語入力はできません。シェルを起動すると(.profileに設定を記載しているので当然ですが) fcitxが起動して日本語変換行えるようになります。そのうち、こういう部分も直っていくような気がしますけどね。

おわりに

ChromeOSVSCodeをつかって日本語入力までできるようになりました。Pythonの開発やnode.jsぐらいであれば10年落ちのPCでもいけるかもしれませんね。 Chrome拡張も割と快適に動くものが多いので文書書きの機能であればわりといい感じです。(このエントリーは画像以外の部分はChromeOSyoutubeを見ながら書いています。) 以前のエントリーでもべた褒めだったのですが、今回も非常にいい印象を受けました。(まだまだという部分ももちろんありますが。)

RaspberryPiでサーボモーターを動作させてみる

フェリーハッカソン2019(以降ハッカソン)にてスマートロックっぽいものを作ったので、メモっておきます。

基本的にはサーボモーターをRaspberryPiで駆動させて鍵っぽいものを作る形になります。 ハッカソンではトリガーとなる部分はフロントエンド側の担当の方におまかせしたので、 このエントリーではHTTP経由でアクセスされたらCGIpythonのプログラムを動作させてサーボモータを駆動する形としています。 トリガーになる動作がないので部分の処理がないのですが、その当たりはすいませんです。

f:id:ueponx:20190130165017j:plain

サーボモーターを駆動するのは、検索すると結構いっぱいヒットしますが、自分は以下の方の情報を見ながら作業しました。 ありがとうございます。

【参考】 bufferoverruns.blogspot.com

サーボモーターとしてしようしたのはSG90というモーターになります。

eleshop.jp

割と電子工作界隈では有名なサーボモーターのようです。自分は今回はじめてサーボモーターを使用したので、知りませんでした。 モーター駆動はドライバーICなどが必要になると思っていたので躊躇していたのですが、このSG90はGPIO経由(制御3.3V)でも問題なく動作します。 ということで、参考にした情報をもとに動かしてみます。

GPIOのピンからPWM(Pulse Width Modulation)という信号制御を使用して、特定のパルス幅の信号をモーターに与えて制御を行います。 パルスのHI区間とLOW区間の時間の比率であるDuty Cycleを使っているそうです。 今回はGPIOの4pin目を使用してサーボモーターを制御し、17pin目でLEDの点灯制御を行っています。 RaspberryPiのGPIOをpythonから使用するRPiGPIOモジュールを使用します。(多分、Raspbianにはデフォルトでインストールされているかなと思います)

SG90とRaspberryPiの接続は以下のようになります。

  • オレンジ線:PWM信号
  • 赤線:電源
  • ブラウン線:GND

【open.py】

import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)

gp_out = 4
gp_led = 17

GPIO.setup(gp_out, GPIO.OUT)
GPIO.setup(gp_led, GPIO.OUT)

GPIO.output(gp_led,GPIO.HIGH)

servo = GPIO.PWM(gp_out, 50) 

servo.start(0.0)

servo.ChangeDutyCycle(2.5)
time.sleep(0.5)

servo.stop()

GPIO.output(gp_led, GPIO.LOW)
time.sleep(5.0)

GPIO.cleanup()

こんな感じで問題ないと思います。

ちょっとだけ説明すると

GPIO.setmode(GPIO.BCM)

ここでGPIOのpin指定のモードを設定します。BCMでGPIOのGPIOの番号で指定するモードになります。 他にもボードのピン番号で指定するモードもあります。

GPIO.setmode(GPIO.BCM)   # GPIO番号指定
GPIO.setmode(GPIO.BOARD)   # ボードピン番号指定

以下の部分でGPIOのピンを出力モードに設定しています。

GPIO.setup(gp_out, GPIO.OUT)
GPIO.setup(gp_led, GPIO.OUT)

これで事前設定は終わりです。 あとは、GPIOのピンにPWMの制御をかけることになります。

servo = GPIO.PWM(gp_out, 50) 

servo.start(0.0)

servo.ChangeDutyCycle(2.5)
time.sleep(0.5)

servo.stop()

GPIO.PWM()の設定のところで引数に50とあるのは50Hzを意味します。この周波数の信号にデューティーサイクルを設定して制御信号を出力します。 SG90は2.5から12.5の値のにデューティーサイクルを与えることで0度~180度の角度で回す事ができるようです。 今回はサーボモータが0度の状態を空いた状態とし、90度の状態を閉まった状態として扱うことにします。 サーボモータは駆動する時間が必要があるのでtime.sleep()でウエイトを与えています。

以上のような感じで制御ができます。

鍵を閉める場合にはサーボモータの角度を90度回転すればいいのでservo.ChangeDutyCycle(7.5)とすれば良い感じです。

【close.py】

import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)

gp_out = 4
GPIO.setup(gp_out, GPIO.OUT)
servo = GPIO.PWM(gp_out, 50) 

servo.start(0.0)

servo.ChangeDutyCycle(7.5)
time.sleep(0.5)

servo.stop()
GPIO.cleanup()

これで開け締めはできるようになりました。これをHTTPトリガーで制御できれば良いことになります。

HTTPサーバーの制御

pythonにはHTTPのモジュールがあるのでそれを使用するだけでHTTPサーバを立てる事ができます。 以下のように実行すれば、簡易的なHTTPのサーバとしてすぐに使用することができます。

python -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

デフォルトではポートが8000番になります。引数でポート番号を指定する事もできます。 また、オプションで--cgiを指定するとCGIを起動することもできます。CGIはデフォルトでは起動パスに存在するcgi-binというディレクトリに 存在するパスがそれに当たります。

【server.sh】

$ python3 -m http.server --cgi

あるディレクトリにserver.shという形でシェルを作った場合には以下のようにcgi-binディレクトリを作成し、 権限を755などにすればいいかと(実行するpythonで作られたCGIプログラムも実行権限とシバンを記載しておいてください)

ディレクトリ構造】

$ ls -l
合計 24
drwxr-xr-x 2 pi pi 4096  127 09:56 cgi-bin
-rw-r--r-- 1 pi pi  222  126 21:58 close.py
-rw-r--r-- 1 pi pi  343  127 09:00 open.py
-rw-r--r-- 1 pi pi 1240  129 08:27 readNFC.py
-rwxr-xr-x 1 pi pi   29  126 15:17 server.sh
-rw-r--r-- 1 pi pi  208  126 13:56 simpleServer.py

$ ls -l cgi-bin/
合計 8
-rwxr-xr-x 1 pi pi 435  127 09:56 servo_close.py
-rwxr-xr-x 1 pi pi 535  127 09:55 servo_open.py

今回は以下のような感じでCGIのプログラムを作成しています。 servo_open.pyにちょっと変わった部分がありますが、CGIでサーボを駆動させているので、ファイル(ファイル名はlockとしている)による動作のロックをかけています。 他にも方法はあるかなと思いますが、何らかの形でロックの機構をいれていないと制御が微妙になることもあるかと思いますので入れておいたほうが無難です。

ドアをOpenする処理は以下のようになります。

【servo_open.py】

#!/usr/bin/env python3

import os

print('Content-type: text/html; charset=UTF-8\r\n')
print('Open the Door!')

if os.path.exists("lock"):
    exit()

f = open('lock','w')
f.close()

import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
gp_out = 4
gp_led = 17

GPIO.setup(gp_out, GPIO.OUT)
GPIO.setup(gp_led, GPIO.OUT, initial=GPIO.LOW)

servo = GPIO.PWM(gp_out, 50) 

servo.start(0.0)
servo.ChangeDutyCycle(2.5)
time.sleep(0.5)
servo.stop()

GPIO.output(gp_led, GPIO.HIGH)
# time.sleep(3.0)

# GPIO.cleanup()

os.remove('lock')

ドアをCloseするのもほぼ同様で記述できます。

【servo_close.py】

#!/usr/bin/env python3

import os

print('Content-type: text/html; charset=UTF-8\r\n')
print('Close the Door!')

if os.path.exists("lock"):
    exit()

f = open('lock','w')
f.close()

import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
gp_out = 4
gp_led = 17

GPIO.setup(gp_out, GPIO.OUT)
GPIO.setup(gp_led, GPIO.OUT, initial=GPIO.LOW)

servo = GPIO.PWM(gp_out, 50) 

servo.start(0.0)
servo.ChangeDutyCycle(7.5)
time.sleep(0.5)
servo.stop()

GPIO.output(gp_led, GPIO.LOW)
# time.sleep(3.0)

# GPIO.cleanup()

os.remove('lock')

ここまで来れば、ブラウザからURIを入力してアクセスすれば動作できます。

f:id:ueponx:20190130083253p:plain 【開く場合】

f:id:ueponx:20190130083320p:plain 【閉じる場合】

【動作ログ】

$ ./server.sh 
Serving HTTP on 0.0.0.0 port 8000 ...
192.168.0.12 - - [30/Jan/2019 08:30:46] "GET /cgi-bin/servo_close.py HTTP/1.1" 200 -
192.168.0.12 - - [30/Jan/2019 08:30:49] code 404, message File not found
192.168.0.12 - - [30/Jan/2019 08:30:49] "GET /favicon.ico HTTP/1.1" 404 -
192.168.0.12 - - [30/Jan/2019 08:32:09] "GET /cgi-bin/servo_open.py HTTP/1.1" 200 -
/home/pi/20190126/cgi-bin/servo_open.py:21: RuntimeWarning: This channel is already in use, continuing anyway.  Use GPIO.setwarnings(False) to disable warnings.
  GPIO.setup(gp_out, GPIO.OUT)
/home/pi/20190126/cgi-bin/servo_open.py:22: RuntimeWarning: This channel is already in use, continuing anyway.  Use GPIO.setwarnings(False) to disable warnings.
  GPIO.setup(gp_led, GPIO.OUT, initial=GPIO.LOW)

動作ログをみるとWarningが出ていますが、LEDのをつけたままにしておくなどGPIOのCleanupの処理を行っていないので発生しています。 コード内に

GPIO.setwarnings(False)

と記述すればなくなります。気になるようであればコード内に入れておきましょう。

躓いた点

プログラムを作っているときに躓いた点も記載します。

プログラムが実行の度挙動が異なる

最初の数時間これで悩みました。実行する度に挙動が違ったり、RaspberryPiのコンソール接続が切れるという状況になりました。最初はプログラムの設定がおかしいに違いないと思っていたのですが、 電源を変更するとびっくりするほど安定しました。電流値の高いものを使用したほうがいいようです。2.1Aの供給が行われるACアダプタを使用すると正常に動きました。 サーボモーターを動作させる場合にはACアダプターなどはちゃんと確認して使用したほうがいいかなと思います。

個人的には電源に問題があればRaspberryPiがリブートするのではないかと思っていたのですが、結構意外でした。

LEDのOFFしてもなんかついている(なんとなく点灯してる?)

LED制御のGPIOのピンを3にしていたのですが、LEDのOFFをしてもなんとなくついていました。あれ? よくわからなかったのですが、17に変更すると同じことは発生しなかった。時間がなくて、基本LEDのの直結をしていたのも良くないのですが 3と17の違いは…多分プルアップ、プルダウンの関係ではないかと思います。もう少し調べてみたいです。

LED制御のGPIOのピンをGPIO3にしていたのですが、GPIO.cleanup()をする(初期状態)とLEDがなんとなくついていました。暗く点灯している? 制御を行うと完全に点灯と消灯の状態になります。GPIO17に変更すると同じ減少は発生していませんでした。

以下の情報でGPIO.setup()から初期状態を変えることができるらしいので設定すると

GPIO.setup(gp_led, GPIO.OUT, initial=GPIO.LOW)

GPIO.setup()以降は完全消灯していました。ただGPIO.cleanup()ともとに戻ってしまいます。 原因は以下のページにかかれているのですが、GPIO2とGPIO3は内部に抵抗あり、それが原因かと思います。

tool-lab.com

GPIO2とGPIO3は他のGPIOのpinとは違うというのは覚えて置く必要がありそうです。ちょっとスッキリ。

おわりに

f:id:ueponx:20190130165145j:plain

初めてサーボモーターを触りましたがわりと面白いです。これでアームとかできたら違うアイデアうかぶかも。 今回はQRコードからのトリガー部分はつくっていないのでその部分にチャレンジする?またはFelicaからトリガーを飛ばすのはチャレンジしたいかな~。

QRコードだとカメラの処理…。Felicaだとnfcモジュール…(python2.7系との混在)結構時間かかるかも。

フェリーハッカソン2019に参加してきた

f:id:ueponx:20190130133252p:plain

先日、日本一過酷と言われるハッカソン…フェリーハッカソンに参加してきました。

code4osaka.connpass.com

今夏は2回目で、前回のハッカソンの告知が出たときも、告知即応募終了という状況で大人気のイベントではありました。ただ、その後日談をブログで読んでみると 別府の地獄めぐりもびっくりという過酷な内容のイベントだとわかりました。

【参考】 code4.osaka qiita.com togetter.com

自分もハッカソンはよく参加してはいましたし、Code for Oosakaさんにもお世話になっているので今回は告知されてすぐにエントリーすることにしました。

このときの自分の気持ちを書くならこんな感じ

「せっかくだから、俺はこの赤の扉を選ぶぜ! f:id:ueponx:20190130132326p:plain

船上のハッカソンでネットワークにつながらないといっても、瀬戸内海ならなんとかなると鷹をくくっていたのです。

「みんな盛ってるんじゃね?」

ちなみに自分のハッカソンスタイルは随時ネットでググるタイプの開発スタイルなので、ネットワークにつながらない自分は「刺し身タンポポ技術者」程度のクソ雑魚です。 会場入りしてからわかったのですが、エンジニア枠で参加申し込みをしていたようです。いまから思えばなぜその選択肢を選んだ…馬鹿だ。

スケジュール

スケジュールはこんな感じでした。


DAY1 1月25日 (金)

  • 19:55 大阪港発
  • 20:15 船上でアイデアソン開始
  • 22:00 チームビルディング
  • 23:00 船上でハッカソン開始

DAY2 1月26 日(土)

  • 7:45 別府港
  • 8:30 別府の会場で開発
  • 19:35 別府港
  • 19:35 船上で開発

DAY3 1月27日 (日)

  • 7:35 大阪港着
  • 8:00 大阪の会場で開発
  • 11:00 ハッカソン終了。プレゼン開始
  • 14:00 審査発表

1日目

集合場所のODP大阪デザイン振興プラザまでは新幹線、地下鉄などを乗り継ぎようやく到着。仕事を休んで行きたかったけど 社長にいろいろ説明することがあったので、休めず早退して向かいました。

f:id:ueponx:20190130134736j:plain f:id:ueponx:20190130135941j:plain 【出港前の集合の様子】

開会の挨拶が終わったら、いよいよ出港となります。

以前さんふらわあに乗ったのって前はいつだろう…小さい頃に乗ったような気が

f:id:ueponx:20190130135451j:plain 【いよいよ出港】

他のハッカソンと大きく違ったのは、最初によくあるアイスブレイク&アイデアスケッチの作成をみんなでやらずに各部屋(抽選で選ばれたメンバー)で行うのが少し新鮮。 あと部屋が超微妙なところも・・・。

f:id:ueponx:20190130134930j:plain f:id:ueponx:20190130134633j:plain 【アイデアスケッチをもって食堂に集合】

イデアスケッチを個室で作成したものをもって、フェリー内の食堂に集合し、アイデアをみんなで見てチームビルディングをしていくことになります。 この時点でよる23:30を回っていますが、よくわからないテンションでアイデアのブラッシュアップをしていきます。

自分のチームはIoT系(IはInternetではなくIntranetの意味)なアイデアを実現しようという方向になり、今回はその中でもスマートロックっぽいものを実現するという方向性で進めることになりました。

この日は日本に大寒波が来ていることもあり、船も大揺れで船酔いもプラスされて、みんな生産性だだ下がり。ある程度アイデアが固まったら、チームごとに部屋を割り振り作業開始になります。

あとで聞いた話ですが、去年のチームビルディングの終了は26:00を超えたらしいです。おじいさんな自分には体力的にきつい…

f:id:ueponx:20190130135024j:plainカップ麺タワー】

割り当てられた部屋でアイデアをまとめて就寝。一日目が終わります。 自分の役割はRaspberryPiでスマートロックを作ることになりました。

フェリー乗船後わかりましたが、携帯のLTEなどはかなりの確率で接続できない様子。 キャリア次第というところもありますが、3Gでようやくつながるという感じでしょうか。

2日目

26時に就寝したものの明朝の7時には既に別府に到着。

f:id:ueponx:20190130140314j:plain

前日からの寒波別府でも吹雪くほどの雪が降っていました。(積もらないけど)

f:id:ueponx:20190130140421j:plain 【ここは北国?】

せっかく別府まできているので、朝イチで温泉に行くことにしました。開発の会場が鉄輪(かんなわ)温泉のすぐ近くのかんぽの宿だったので近くにあったひょうたん温泉にいきました。

www.hyotan-onsen.com

広い!でも眠い!そして外は雪!流石に露天風呂にはいけませんでしたが非常にいい温泉でした。 開発の前に温泉に入ったら眠くなるかと思っていたのですが、意外とそのあとは眠くなることもなく開発は進めることはできました。

構成したメンバーが名古屋、大垣、大阪という感じだったので、ひょうたん温泉の由来が秀吉公の千成瓢箪から来ているということもあり、今回のチーム名は「ひょうたん」となりました。

安定したネットワークが使える陸上開発ができるのは2日目がメインなので、ここである程度目処が建てられないと完成はできないなという感じ。結構頑張りました。

今回のハマりどころはまた別エントリーで紹介しますが、簡単にいうと以下の点です。

  • RaspberryPiの電源はちゃんとしたものを使おう(特にサーボモーターを使用するときには)
  • LEDなどをGPIOで使うときにはデフォルトでプルアップ機能のあるピンとないピンがあるので気をつけよう。
  • サーボモーターの制御は適当にやるとモーターが微妙に動きうるさいので、ちゃんと止めよう。
  • RaspberryPiに入っているpythonのVersionが3.5当たりだとワンライナーのhttpサーバーのサンプルが動かないのでその対応はしよう。

今回のプロダクトとしては、httpサーバーをRaspberryPiで作ってCGI経由でpythonのサーボ制御のプログラムを動作させるということで落ち着きました。

f:id:ueponx:20190130143036j:plain

フロントエンド側でQRコードを読み取り、アクセスしてもらうようにしています。RaspberryPiに接続するカメラがあったらRaspberryPiだけで完結したのかなと思いますが、カメラはなかった(共立電子さんの臨時ショップにはあったが、自分はみないことにしたw)ので、フロントエンド側にお願いしてしまいました。スマヌ。

夕方の段階で大体サーボもHTTP系もできるようになったのであとは、なんとかなるかなと。あとは夕方に大阪に向けて乗船となります。乗船前にダイソーによって工作道具などを購入していきました。

深夜、船上の工作でスマートロックのデモ用のドアを作っていました。

f:id:ueponx:20190130142928j:plain 【デモ用のドア】

可愛い感じできた感じです! いろいろやって大体27時ごろ就寝した感じでしょうか。途中寝落ちしてましたが…

3日目

大阪の到着も7:30ごろ。早い。温泉入りたいと思ってももうない… あとは発表資料などをまとめる感じで作業を進めていきました。

発表は各チーム3分で、発表後にタッチアンドトライをして審査へと進みます。

f:id:ueponx:20190130143744j:plain 【タッチアンドトライの展示の様子】

んで、発表の結果!

f:id:ueponx:20190130143632j:plain

ネットワークチーム賞を受賞しました! 頂いた商品はRaspberryPi Zeroです。あー、継続開発なのかも。

f:id:ueponx:20190130145337j:plain

フェリーハッカソンを終わってみて

前回が地獄だったんだな。今回は過酷ではあったもののそこまででもないのかなと。 これは一重に運営の方々や協力・協賛企業の方々の尽力のおかげなのかなと思いました。 特にネットワーク構築のご担当は参加者が移動するたびにネットワーク構築するという 非常に大変な作業を毎回されていたので、本当に頭の下がる思いです。

自分の中では非常に楽しいハッカソンだったなあーという印象でした。 他のハッカソンイベントに比べるとチーム内のコミュニケーションが多かったなあというイメージでしょうか。 「旅」が一つ大きなファクターになっていること、閉鎖空間であることなどが要因にあるのかななんて思いました。

フェリーハッカソンは大阪ー別府ルート以外でも宮蘭航路でもあったそうなので、また参加してみたいなと思いました。

obnizでLチカしてみた

ようやくobnizが手に入ったのでLチカをやってみました。 Lチカだけで終わらないようにしたい…

詳しくはこちらの動画をみていただくといいかなと思います。

youtu.be

obniz.io

いざ開封

自分はamazonさんから購入しました。

届くと箱に入ってこんな感じ。フリスクケースより一回り小さい感じかなと思います。

f:id:ueponx:20190114190130j:plain

箱開けるとこんな感じになっていました。

f:id:ueponx:20190114190140j:plain

表側(?)にはESP-WROOM32とOLEDが乗っています。

f:id:ueponx:20190114190148j:plain

裏にはメスのピンヘッダーとUSBコネクターがついています。 どのpinからも1A出力できるって本当なんでしょうか?動画ではモータードライバーなしで動いていました。 また、obniz Cloudを経由すればREST経由でもWebSocket経由でもGPIOへアクセスできるようです。 同一LAN内になくてもGPIOへアクセスできるのでわりと敷居が低くなっているのではないかなと思います。 WioNodeとなんとなく似ている感じですが、価格が5倍ぐらい差があるのでそのあたりは作りたいものと時間とのトレードオフかなと思います。

では設定をしていこうと思います。

obnizを設定する

obnizを使うためには、事前にobniz cloudに登録(無料)する必要があります。

まずは以下のサイトにアクセスします。

obniz.io

ウインドウの上の方にある【登録/ログイン】をクリックします。

f:id:ueponx:20190114193410p:plain

すると、認証画面に遷移します。SNSのアカウント経由で認証してもいいですし、メールアドレスでも登録が可能になっています。 今回はGoogleアカウントで登録することにしました。ボタンの中で一番上にある【Sign in with Google】をクリックします。

f:id:ueponx:20190114193847p:plain

複数アカウントを持っている場合には、アカウントを選択するダイアログが表示されるので、使用したいアカウントを選択します。 アカウントをクリックすれば登録完了になり、次の画面に遷移します。

f:id:ueponx:20190114193913p:plain

アカウント登録が終わると今度はobnizの登録を行うことになります。登録されたobnizにはURLが発行されるのでこの処理が必要になってきます。

f:id:ueponx:20190114194316p:plain

画面に表示されている【obnizを追加】ボタンをクリックします。すると次の画面に遷移します。

f:id:ueponx:20190114194638p:plain

obnizに電源を入れてWiFiの設定をするように指示されています。 では、obnizに電源を入れましょう。すると以下のような画面になると思います。

f:id:ueponx:20190114194832j:plain

画面に指示に従ってobnizのハードボタンを押してください。このハードボタンは押し込みと左右の動きができるようになっています。次の画面で認識されたアクセスポイントの一覧が見えていると思います。(アクセスポイントのSSIDは一部しか見えないのですが、選択して時間が立つとスクロールするので十分に確認をしてください) この中からハードボタンで適切なアクセスポイントを選択します。

f:id:ueponx:20190114195457j:plain

アクセスポイントのパスワードを入力します。(ハードボタンを左右に動かし、押し込むことで入力ができます)

f:id:ueponx:20190114195510j:plain

入力が完了したら【END】でハードボタンをプッシュします。 すると以下のように画面が接続処理を行う画面になります。接続が正常に行われると以下のようにQRコードが表示された画面になります。

f:id:ueponx:20190114195954j:plain

QRコードが表示されたらWeb画面に戻り

f:id:ueponx:20190114194638p:plain

【I'm ready】ボタンをクリックします。入力ボックスが表示された画面に遷移するので、

f:id:ueponx:20190114201151p:plain

obnizのOLEDに表示された数字を入力します。入力したら【Next】ボタンをクリックします。 すると以下のような画面に遷移します。

f:id:ueponx:20190114201559p:plain

obnizのOLEDもQRコードの画面から以下のように変化しています。

f:id:ueponx:20190114201735j:plain

OLEDに6桁の数値が表示されているのでWebの入力ボックスにタイプしていきます。

f:id:ueponx:20190114201624p:plain

入力が終わったら【Validate】ボタンをクリックします。

f:id:ueponx:20190114201850p:plain

以下のような画面になればアカウントにobnizが追加されています。

f:id:ueponx:20190114202132p:plain

以下にような画面になれば、事前設定は完了となります。

f:id:ueponx:20190114203851p:plain

Let's Lチカ

では、Lチカのコードを書こうと思ったのですが、初期テンプレートがWeb画面からON/OFFボタンを押すことでLEDの店頭とOLEDの表示を変化させるコードが出てきます…なにも書かなくてもできるとは。 説明は不要かもしれませんが、念の為に新規作成させてみます。

まず、ホーム画面から【プログラムをする】ボタンをクリックします。

f:id:ueponx:20190114211900p:plain

クリックするとデプロイ先の登録済みのobnizのIDの入力が求められるのでQRコードの隣に表示された数字を入力します。

f:id:ueponx:20190114211921p:plain

入力するとチュートリアルをするか尋ねられますが、そのまま【キャンセル】ボタンをクリックします。

f:id:ueponx:20190114210525p:plain

するとコードが開かれます。HTMLにJavaScriptが含まれたものになりますね。 この画面になったら画面上部にある【保存&開く】をクリックすると実行されます。

f:id:ueponx:20190114221802p:plain

実行すると以下のような画面がポップアップします。Web画面に【ON】ボタンと【OFF】ボタンがあります。

f:id:ueponx:20190114210556p:plain

obnizのOLEDにはHello Worldと表示されています。

f:id:ueponx:20190114214953j:plain

【ON】ボタンをクリックするとOLEDにはONの表示が

f:id:ueponx:20190114215030j:plain

【OFF】ボタンをクリックするとOLEDにはOFFの表示が

f:id:ueponx:20190114215057j:plain

GPIOにLEDを指しておけば【ON】ボタンでLチカできます。 (pinpin0がアノード、pin1がカソードになっているので注意してください。)

f:id:ueponx:20190114215121j:plain

ちなみに画面左側のリストにあるblockprogram.xmlのファイルをクリックすると以下の様な画面で

f:id:ueponx:20190114220555p:plain

ブロックプログラムもできるようになっています。

おわりに

ようやくobnizに手を出すことができました。JS使いの人であれば割といい選択肢かなとは思います。 python経由でのIOアクセスに関してもやってみようと思います。

M5Stackもそろそろ触らないとなあ…積み基板が多すぎる。

/* -----codeの行番号----- */