スキップしてメイン コンテンツに移動

ClojureScriptとBLE

2017年Clojure Advent Calendar 15日目の記事として書きました。

今年、ニャンパスとして、またプライベートでいろいろとBLEを扱うコードをClojureScriptで書きましたので、まとめてみます。

使用したデバイスは、micro:bitです。秋葉原や通販等で手に入り、BLE、25個のLED、加速度センサーがついている学習用のボードです。ブラウザ上でビジュアルプログラミングでの開発ができたりと面白いので、年末年始に遊んでみてください。

ClojureScriptでの環境の作り方から始まって、micro:bitとPCとの接続、リモートでのLチカを試すというIoTなClojureScriptの内容となってます。

1. ClojureScriptで、BLEな環境を作る


Node.js、npm、Leiningenを入れておいてください。プロジェクトを作ります。

  $ lein new figwheel-node ble

figwheel-nodeテンプレートを使い、できたファイルはこんな感じです。

./project.clj
./README.md
./package.json
./.gitignore
./src
./src/ble
./src/ble/core.cljs
./dev
./dev/user.clj

今回、PC側をBLEのセントラルとして振る舞わせ、micro:bitをペリフェラルとして操作しますので、そのためセントラル側のプログラムとしてnobleというライブラリを使います。
OS毎に依存するものが違いますので、サイトで事前に確認しておいたほうが良いです。


※nobleはMac、Linux、Windows、FreeBSDをサポートしており、僕自身今年nobleを使ったコードをClojureScriptを使って、Windos、Mac、Linuxそれぞれで動かしていて動作は安定していました。

では、nobleを以下のコマンドを実行しておきます。

  $ npm install noble

※普段はlein-npm等を使ってproject.cljでnpmライブラリの依存を管理していますが、今回説明の都合上素直にnpm経由でインストールしています。

nobleのインストールさえ成功すればあとは、ClojureScriptでの開発の準備が整ったことになります。
Figwheelがすでに入っていますので、EmacsからCIDERを使った開発を行う手順は以下のようになります。
  1. Emacsからcider-jack-inでnREPLサーバーを起動
  2. REPL上から、
    (fig-start)
    (cljs-repl)
    と入力。
  3. ターミナルから以下のコマンドを実行。(root権限が必要だったので、"sudo"をつけています。)
    sudo node ./target/js/compiled/ble.js
これで、BLEを操作するためのClojureScriptのREPL環境が整いましたのでレッツ・ハックしていってください。



試しに、周りのBLEデバイスを見つけてくるサンプルです。

  (ns ble.core
    (:require [cljs.nodejs :as nodejs]))

  (def noble (nodejs/require "noble"))

  (nodejs/enable-util-print!)

  (.on noble "stateChange" (fn [state]
                             (if (= state "poweredOn")
                               (.startScanning noble)
                               (.stopScanning noble))))

  (.on noble "discover" (fn [peripheral]
                          (prn peripheral)))

2. micro:bitにClojureScriptからつないでみる


micro:bitのBLEでの接続は、nobleのライブラリを使っても実現できるのですが、JavaScriptのライブラリとして、micro:bit用に特化したライブラリが用意されておりこちらを利用するとさくっとmicro:bitとつなぐことができます。
micro:bit側にまずはファームウェアを書き込みますのでここからhexファイルをダウンロードし、PCとUSBケーブルで繋いだ状態で表示される"MICROBIT"フォルダへhexファイルを放り込んでください。

ClojureScript側は、node-bbc-microbitをまずインストールします。

  $ npm install bbc-microbit

node-bbc-microbitの依存ライブラリでnobleが使われており、すでにnobleを入れていますので、必要な依存関係は解決されているはずです。

さきほど書いたcore.cljsは以下のように書き換えます。

  (ns ble.core
    (:require [cljs.nodejs :as nodejs]))

  (def microbit (nodejs/require "bbc-microbit"))

  (nodejs/enable-util-print!)

  (.discoverAll microbit (fn [bit]
                           (println "id:" (.-id bit) ", addr:" (.-address bit))))

うまくいけば、周囲のmicro:bitを拾って以下のようになるはずです。

  $ sudo node ./target/js/compiled/ble.js
  id: xxxxx, addr: xx:xx:xx:xx:xx:xx

3. Lチカ

この段階でただ繋がっただけなので、せっかくなのでLチカ(LEDを点滅)して終わりにしたいと思います。

micro:bitは、0から3番までのGPIOが扱いやすい形で出ていますので、ワニ口クリップ等で、写真のように配線してください。

ジャンパーワイヤー経由で、LEDと抵抗を繋ぎ、micro:bitの0番ピンと、GNDピンに割り当てています。


最後に、LチカのBLE経由版のコードは以下のとおりです。

(ns ble.core
  (:require-macros [cljs.core.async.macros :refer [go-loop]])
  (:require [cljs.core.async :refer [timeout]]
            [cljs.nodejs :as nodejs]))

(def microbit (nodejs/require "bbc-microbit"))

(def output-pin 0)

(defn toggle-pin [bit]
  (go-loop [seconds 1]
    (prn :seconds seconds)
    (<! (timeout 1000))
    (.writePin bit output-pin (if (= (mod seconds 2) 0) 1 0))
    (recur (inc seconds))))

(defn setup [bit]
  (.pinOutput bit output-pin
              (fn []
                (.pinDigital bit output-pin
                                  (fn [] (toggle-pin bit))))))

(.discover microbit (fn [bit]
                      (println bit)
                      (.connectAndSetup bit #(setup bit))))

まとめ

今回はmicro:bitを使った操作をClojureScriptから試してみました。

Raspberry PiにClojureScriptを入れて、自社で作ったBLEデバイスの制御を行うということも問題なくできています。REPLが使えることは、デバイスの動きを見ながら開発が出来る大変な強みだと思っています。
ぜひIoTな案件でClojureScriptを試してみてください!

コメント

このブログの人気の投稿

ESP8266で書き込めない時に対処したこと

ESP8266のチップで書き込めなかった問題が起こり、それについての対処を参考になる可方がいるかもということでブログにもメモとして残しておきます。 書き込みで失敗したケースとしては、 スイッチサイエンスさんのESP-WROOM-02ピッチ変換済みモジュール《シンプル版》 へのシリアル通信での書き込みができなかった問題 Over The Air(OTA)の機能を使うコードを、同じくESP-WROOM-02に対して転送するも、更新の途中でクラッシュし、書き込みが失敗するという問題 の二つです。 OTAまで使って書き込もうとしている背景は、ニャンパスとして Robip というプログラミング学習環境を作っていて、そのツールの中でWi-Fi経由での書き込み機能を対応することでスマートフォン、タブレットなどでのビジュアルプログラミングしたものが、OTA経由で電子工作のプログラミングができるようという機能があり、いくつかのESP8266を積んだモジュールへのサポートを増やそうとしたところ(ようはRobipとしての対応デバイスを広げたかった)上記の書き込みできない問題にぶつかりました。 Facebookのこちらに書いたことの詳細版です。 ESP-WROOM-02への書き込み出来ない問題 もともと、HaLake KitというコワーキングスペースHaLakeオリジナル基板は、ESP8266を積んでいますので、この書き込みツールとしてClojureで書いた robip-tool というのを用意していました。 このツールであればHaLake Kitには書き込めていたのですが、ESP-WROOM-02ピッチ変換済みモジュール《シンプル版》ですと最初の書き込みの段階で失敗することが分かりました。 そこで世界中で人気のESP8266ですので、色んなバージョンの書き込みツールがありまして、書き込みに成功するツールを探す旅が始まりました。 その際には、シンプル版だけでなく、HaLake Kit、ESPr Developer(ESP-WROOM-02開発ボード)、ESP-WROOM-02ピッチ変換済みモジュール《フル版》でも試して、全てで動くツールを検証しました。 途中、Go言語で書きなおしてみたりいろいろテストもしたのですが、結果的に全て

ClojureでCompojureを使わずにサーブレットを書く方法

Clojureでgen-class、proxyを使ってみようと思い、試しにサーブレットを書くとどうなるかを試してみました。 コンパイルにLeiningenを使うためプロジェクトを作ります。 lein new sample-servlet まずはsrc/sample_servlet/servlet.cljを書いてみます。 (ns sample_servlet.servlet (:gen-class :extends javax.servlet.http.HttpServlet)) (defn -servlet [this request response] (.setContentType response "text/html; charset=UTF-8") (let [out (.getWriter response)] (.. out (println "<html><body>hello world</body></html>")))) (defn -doGet [this request response] (-servlet this request response)) 依存関係とクラスファイル生成のオプションを与えたproject.cljファイルを作りました。 (defproject sample-servlet "1.0.0-SNAPSHOT" :description "FIXME: write" :dependencies [[org.clojure/clojure "1.1.0"] [org.clojure/clojure-contrib "1.1.0"] [javax.servlet/servlet-api "2.5"] ] :namespaces [sample_servlet.servlet]) 必要なライブラリを取得しコンパイル。 lein deps lein compile 無事生成されたことが分かります。 % ls -lr