組み込み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分毎に更新される。


