組み込みAPIでは1か0だけ
Mathematica/Wolfram言語にGPIOへアクセスする方法が書かれている。 →GPIO
標準APIでは1と0しか扱えないようだ。
SPI/I2C/PWMのためには?
MathLinkというプラグイン的なものを使うことで出来そうだ。
Wolframドキュメントセンター上では、MathLinkは WSTP に置き換えられているが、自分のRasbianでは、、mathlinkのまま。最新を取ってくるとまた違うかも。
MathLink開発環境
/opt/Wolfram/WolframEngine/10.0/SystemFiles/Links/MathLink/DeveloperKit/Linux-ARM
に、必要なライブラリやサンプルプログラムが入っている。情報はこれだけで十分。
WiringPi
下回りのライブラリとして、GPIO制御の定番らしいWiringPiを使う。
$ sudo apt-get install wiringpi
で入れてもいいと思うけど、最新がいいらしいので
$ git clone git://git.drogon.net/wiringPi $ cd wiringPi $ sudo ./buildで入れる。
やってみたこと
お試しで買った工作キットに、mcp3002(ADC)とフォトトランジスタ、温度センサーが入っていたので、SPIにmcp3002をつけ、mcp3002にフォトトランジスタと温度センサーをつけて、部屋の明るさと温度をプロットしてみる。そして、それをWebで見れるようにする。という感じ。
SPIプログラム(mcp3002.c)
#includeSPIデータを取得するMathLinkプログラムはこんな感じ。WiringPiのmcp3002 API使うと非常に簡素だ。MathLink対応はmathlink.hをインクルードして、mainでMLMainを呼ぶようにするだけで良い。#include #include #define PINBASE 64 #define SPI_CH 0 #define TO_VOLT (3.3f/1024) extern float spi(int ch) { return TO_VOLT * analogRead(PINBASE + ch); } int main(int argc, char* argv[]) { mcp3002Setup(PINBASE,SPI_CH); return MLMain(argc, argv); }
MathLinkライブラリ化(mcp3002.tm)
float spi P((int)); :Begin: :Function: spi :Pattern: Spi[ch_Integer] :Arguments: { ch } :ArgumentTypes: { Integer } :ReturnType: Float :End: :Evaluate: Spi::usage = "Spi[ch] gives the SPI value."単にプログラムをコンパイルするだけではダメで、上のようなテンプレートファイルを作成して、 mprep ツールで tmからCに変換したものをセットでビルドする。
uuidライブラリがなくて、リンク時にこけたので
$ sudo apt-get install uuid-dev
で入れた。
Makefile
CADDSDIR = /opt/Wolfram/WolframEngine/10.0/SystemFiles/Links/MathLink/DeveloperKit/Linux-ARM/CompilerAdditions INCDIR = ${CADDSDIR} LIBDIR = ${CADDSDIR} MPREP = ${CADDSDIR}/mprep CXX = /usr/bin/c++ RM = rm EXTRA_CFLAGS= -O2 PROGRAM = mcp3002 OBJS = $(PROGRAM).o $(PROGRAM)tm.o all : $(PROGRAM) $(PROGRAM) : $(OBJS) ${CXX} ${EXTRA_CFLAGS} -I${INCDIR} $(OBJS) -L${LIBDIR} -lwiringPi -lML32i4 -lm -lpthread -lrt -lstdc++ -ldl -luuid -o $@ .c.o : ${CXX} -c ${EXTRA_CFLAGS} -I${INCDIR} $< $(PROGRAM)tm.c : $(PROGRAM).tm ${MPREP} $? -o $@ clean : @ ${RM} -rf *.o *tm.c $(PROGRAM)makeビルドすると、mcp3002という実行プログラムが出来上がる。
これをMathematicaでInstallで読み込むと、Spi[0]とSpi[1]でCのspi(int ch)を呼べるようになる。
Mathematicaスクリプト(spi.m)
(* ::Package:: *) (* Load 'mcp3002' MathLink Module *) Install["mcp3002"] (* Function *) lux := {DateList[], Spi[0] * (100/(7500*0.000033))} deg := {DateList[], (Spi[1]-0.5)*100} (* Data List *) luxData = {} degData = {} interval = 5 * 60; (* Plot *) (* Lux *) luxNow = Dynamic[Last[AppendTo[luxData,lux]; If[Length[luxData]>144,luxData=Drop[luxData,1]]; luxData], UpdateInterval->interval, TrackedSymbols->{} ] luxPlot = Dynamic[ DateListPlot[luxData, Joined->True, PlotLabel->"Lux"], SynchronousUpdating->False] (* Tempeture *) degNow = Dynamic[Last[AppendTo[degData,deg]; If[Length[degData]>144,degData=Drop[degData,1]]; degData], UpdateInterval->interval, TrackedSymbols->{} ] degPlot = Dynamic[ DateListPlot[degData, Joined->True, PlotLabel->"Temp"], SynchronousUpdating->False] (* Export *) Dynamic[ Export["lux_now.gif",luxNow]; Export["lux_plot.gif",luxPlot]; Export["temp_now.gif",degNow]; Export["temp_plot.gif",degPlot]; Share[], SynchronousUpdating->False, UpdateInterval->interval]Install["mcp3002"]でMathLinkライブラリを読み込み。これを実行すると実際にmcp3002プログラムがプロセスとして起動する。プロセス間通信でやりとりしているようだ。
その後、明るさ(lux)と温度(deg)関数を定義。Spi[0]とSpi[1]で取得したデータを変換している。
Dynamic[]を使って、5分毎にSPIデータをサンプリングして、Dateリスト型の変数へ追加していく、 さらにそれをプロットする。Mathematicaノートブック上でプロット結果が見れるようになる。
最後が、それぞれの出力結果をGIFイメージへExportする処理。このイメージをWebServerで見れるようにすれば、外のブラウザで結果を見ることができるようになる。
実行
vncサーバーでも立てて、繋いで、プログラムとスクリプトがあるディレクトリから
$ mathematica spi2.m
で起動して、右上の「Run Package」を実行すると、プロットなどのDynamic処理が5分ごとに更新される。
これはこれで問題がある、後述の「考察」が解決策。
軽量Webサーバー立てる
$ sudo apt-get install lighttpd
$ sudo lightly-enable mod userdir
$ sudo /etc/init.d/lighttpd force-reload
で、~/public_htmlにindex.html書いて、http://(pi2)/~pi/ で見れるようになる。
~/public_htmlにmathematicを実行しているカレントフォルダのリンクを貼ってgifへアクセスできるように。
あとは、適当にindex.htmlを用意。
ブラウザからアクセスしてみた結果がこちら
こちらも5分毎に更新される。