2017年3月19日日曜日

clojureでraspberry piのgpioを操作する方法


手間取ったので情報を共有します。

使ったもの

raspberry pi

今回の動作確認は3で行いました。
raspbianとleiningenのバージョンが古くなければ同じ動作をすると思います。

raspbian

2017.1.11にリリースされたものを使っています。

leiningen

バージョン2.7.1を利用しました。
インストールされていない方は、こちらが参考になると思います。
raspberry piに最新のleiningenをインストールする方法

電子工作部品

ブレッドボード、LED、オスメスジャンパワイヤ、抵抗、スイッチを使いました。

プロジェクトの作成

今回は、~/programsにraspi-testというプロジェクトを作り、そのプロジェクトでgpioの制御を行います。
cd ~/programs/
lein new raspi-test

project.cljの設定
下記のライブラリをdependenciesに追加して利用可能にします。
  • clj-gpio: gpioの制御に利用
  • at-at: 時間に応じて何かをするような処理の定義に利用
[clj-gpio "0.2.0"]
[overtone/at-at "1.2.0"]

~/programs/raspi-test/src/raspi_test/core.cljをmainファイルとして実行できるようにします。
:main raspi-test.core

編集を終えるとこうなりました。
~/programs/raspi-test/project.clj
(defproject raspi-test "1.0.0-SNAPSHOT"
  :description "FIXME: write description"
  :dependencies [[org.clojure/clojure "1.8.0"]
                 [clj-gpio "0.2.0"]
                 [overtone/at-at "1.2.0"]]
  :main raspi-test.core)


下記のコマンドを実行すれば、プロジェクト作成時のサンプルプログラム(多分「Hello, World!」の出力)が実行されます。
cd ~/programs/raspi-test
lein run

サンプルプログラムが実行できれば、project.cljの変更を期待通りにできたと思います。

gpio制御プログラムの作成

下記のようなプログラムを作成しました。
ザックリと説明します。

~/programs/raspi-test/src/raspi_test/core.clj
(ns raspi-test.core
  (:require [gpio.core :as gpio]
            [overtone.at-at :as at-at]))

(def at-at-pool (at-at/mk-pool))

(def button-port (gpio/open-port 22))
(def led1-port (gpio/open-port 23))
(def led2-port (gpio/open-port 24))

(defn close-ports []
  (prn :close-ports)
  (gpio/close! button-port)
  (gpio/close! led1-port)
  (gpio/close! led2-port))

(defn toggle-led []
  (let [button-value (gpio/read-value button-port)]
    (prn :button-value button-value)
    (if (= :high button-value)
      (gpio/toggle! led1-port)
      (gpio/toggle! led2-port))))

(defn -main [& args]
  (.addShutdownHook (Runtime/getRuntime)
                    (Thread. close-ports))
  (prn :start)
  (gpio/set-direction! led1-port :out)
  (gpio/set-direction! led2-port :out)
  (gpio/write-value! led1-port :high)
  (gpio/write-value! led2-port :low)
  (at-at/every 1000 toggle-led at-at-pool))

gpioは22をスイッチの入力、23と24をLEDの出力に利用しています。

gpioを閉じずにプログラムを終えるとgpioピンがbusy状態となり利用しにくくなるので、-mainのRuntimeのshutdownHookとしてgpioを閉じる処理を記述しています。

ちなみに、gpioがbusyになり、操作できなくなった場合
下記のコマンドでgpioピンを開放できます。

22番ピンを開放したい場合(状況によってsudoが必要なこともあります)
echo 22 > /sys/class/gpio/unexport

at-atを使って、1秒ごとにスイッチの値を見て、その結果に応じて点滅させるLEDを決めています。

回路の作成


gpioのピンにスイッチ、LED、抵抗を繋ぎます。

GPIO22 -> 抵抗 -> 3.3V
GPIO22 -> スイッチ -> GND

GPIO23 -> LED(赤) -> 抵抗 -> GND
GPIO24 -> LED (緑)-> 抵抗 -> GND

プログラムの実行

下記のコマンドでプログラムを実行できます。
cd ~/programs/raspi-test
lein run

ボタンを押していなかったら23番ピンに接続した赤のLEDが点滅します。


ボタンを押すと24番ピンに接続した緑のLEDが点滅します。


共有する情報は以上です。

2 件のコメント :

shinseitaro さんのコメント...

参考にさせていただきました!ありがとうございます。

作業中にエラーが発生しましたので、対処法をここに書かせてください。

raspi-testを初めてlein runした時に、

Unrecognized VM option 'UseCGroupMemoryLimitForHeap'
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

というエラーが出まして、なんだろう?と調べましたら
原因はleiningen (というよりJavaのVersion)でした。
対処法は、本家のFAQにありました。
https://github.com/technomancy/leiningen/blob/master/doc/FAQ.md

コンテナは使っていないので、セキュリティの問題はないだろうとおもい、
:jvm-opts ^:replace
オプションを project.clj につけることで回避できました(^^)

ちなみに私のラズパイはRaspbian GNU/Linux 8.0 (jessie)です。









Asuki Kono さんのコメント...

自己解決されたようで良かったです。
自分の環境ではその問題は発生しませんでしたが、情報共有ありがとうございます。