先日、I2Cが無事動いたのでいよいよ真打ち(?)の気圧センサー、LSP25Hを繋いでみることにしました。


例によって資料は英文なので全部読んでから使うという訳にもいかず、取り敢えず秋月のモジュールに付いてきた説明書を見て、Luaでプログラムしました。

 

結果は写真の通り。気圧と気温(室温)を計測してLCDに表示、PCからの問い合わせにも応答、と当初の目標を達成しました。

問題なのは計測結果の精度でして、これはもう、センサーのそれを丸呑みするしか無いかも知れません。特に気圧については台風が来るか、あるいはこれを持って高いところに上がるとかしないとほとんど数字が動かないと思います。天気図と照らし合わせて「まあ、こんなものか」くらいが精々でしょう。

 

温度については、LSP25HもLM61も同じような値を返しているのが気になります。LM61だけの時は、そもそも精度がそんなに良くないので「まあ、こんなものか」だったのですが、2つ揃って同じ傾向となると別の原因を考えなくてはならないでしょう。室温とは3度近く離れて高めに出るのですが、比較用のアルコール温度計や室内のエアコン挙動から判断しても、やはり高めに出ていると判断せざるを得ません。まあ実際、ブレッドボードの上は3度くらい高いのかも知れませんが。

 

それと開発環境について。
「ファイルシステム付きのスクリプト環境」はなかなか快適です。作ってバグ出しが終わったものからどんどん保存していってrequireして使う、これが思っていた以上に効率的でした。惜しむらくはeLuaがLua5.1相当なのでビット演算がモジュール頼みになってしまい、Cに慣れた身としては些か煩わしい感じがした事。


 

赤いのはLPS25Hモジュールのパイロットランプ。赤は最近では珍しいかも知れない。

LPS25HとLCDは両方共プルアップ抵抗(各々10k)を繋いであります。2つくらいなら大丈夫と思いますが、I2Cにたくさんぶら下げるのであれば一つにしないとハード的なバグになるので注意が必要です。

 

せっかくなので少し手直ししてから、モノとしてまとめてみようと思います。

 

 

emacsの親戚かと思ったら、画像ビューワだった。

 

LinuxMint17.3(xfce,amd64)を常用しているが、画像ビューワに関しては決定版といったものがない。

 

導入直後に標準装備のビューアを外してxfce4標準のristrettoを入れてみたが、これは本当に見るだけしかできない。


それでは、とgthumbを入れたのが、ツールキットがgtk3ということもあって見た目とレスポンスが今ひとつ(なお、これはフォークされてMint18以降標準ビューワとしてインストールされた、はず)。

仕方ないのでgtk2時代の最終バージョン(2.14.4)を自前でビルド、静止画専用に仕上げて使っているが、レスポンスが改善されただけで必ずしも使い勝手が良いとはいえない。特にレベル調整を行うのにガンマ調整を使わなくてはならず、間違っていないとはいえ世間の常識[要出典]とは乖離している。

 

さて、表題のnomacsである。ツールキット(というよりプラットフォームと呼ぶべきか)にQt5を使っているので、Windows,mac,Unix Likeに幅広く対応している。表示もヒストグラムなんかは透過表示される等今風[いつ?]であり、日頃gtkの古臭さに辟易しているので気分転換には好都合である。


まだ歴史が浅いのか、Mint17の標準リポジトリには見当たらない。nomacsのサイトにはlaunchpad経由でのインストール方法が示されているので、その通り手順を踏めばインストールされる。

 

問題はUIが文字化けすることで、メニューから起動するとかな文字が豆腐になる。これのせいで、最初wineで動いているのかと勘違いしたくらいである。

 

仕方ないので端末から起動してみるも、やはりかな文字がおかしい。かつて遊びで入れた「きろ字」が割り当てられている。豆腐よりマシだが、違和感ありすぎである。

 

設定するツールもあるらしいがUbuntuだとXenial以降になるようだ。LinuxMint17の上流はtrustyだから、そのまま使う訳にはいかない。

 

まあ、使えないことはないのでこのまま試してみようと思う。

 

ヒストグラムと画像情報を表示。ストロボは焚いてないぞ。バグかしらん?

 

絶賛文字化け中。久しぶりだよな、こういうの。Linux使い始めた頃はちょくちょく遭遇したもんです。

 

先日設定を変えたばかりだったが、再度、一昨日あたりからこの設定に変えてみた。常用しているPCはRAM2GB、Swap2GBで、メモリが尽きてくると延々とスワップし始めて仕事にならない。
ので、早い段階からこまめにスワップすることでダメージを減らそうという目論見。


取り敢えず様子を見る。

温度センサーを繋いだので次は気圧センサーを、と目論んでいるのだがこれのインターフェースはI2C(もしくはSPI)。I2Cには余り良い思い出がない。とにかく、一発で動いた試しがない。

 

そこで最初からセンサーを繋がないで、取り敢えず見た目にも挙動を確認しやすいLCDで始めることにした。このLCDは以前H8/Tinyで試したことがある。

 

H8/Tinyの時のCで書いたコードを元に、nodemcuのeLuaで書き始めたのだけれど例によって動作しない。先行事例を求めてネットを漁ってみるもほとんどがaruduinoばかりで、nodemcuのluaで動かしている例に巡り合わない。

 

ねちっこく検索してようやく見つけたのがこちら。モジュールとして完結しているのでrequireすれば使える。ありがたや。

 

[技術ネタ]ESP8266+NodeMCUでI2Cのキャラクタ液晶に表示させる
http://d.hatena.ne.jp/chakoku/20160429/1461926389

 

 

早速ダウンロードして、I2Cのピン割当を自前の設定に修正して、いざ点灯!って動かない。なぜ?

 

途中の試行錯誤を飛ばして結果を書くと、

 

ピンの割当設定を間違えていた
esp8266のI2Cはその信号線2本を任意のGPIOに割り当てることができるのだけれど、そのピンアサインというのが1〜12。てっきり回路上のGPIOnにおけるnのことだと思っていたのだが、違った。対応表はNodeMCUドキュメントのGPIOの欄にある。

 

コントラストの設定値が間違っていた
この辺の値は製品によって違いがある(前述のURLで使っているLCDはStrawberry Linux、手元にあるのは秋月電子)ので、H8/Tinyで使った値を持ってきたのだが、H8/Tinyは5V、esp8266は3.3Vである。これが原因で点灯に至らなかった模様。値を元に戻して事なきを得た。

 


 

今まで温度が知りたい時はいちいちPCから問い合わせていたのだが、こうやって単独表示されているのを見ると、ものすごく実用的に思えてくる。

 

 

おまけ。今夜の室温。VFOの試験には絶好のコンデション!(違

 

室温記録の続き。

 

きょうび、何らかのライブラリを使って自力でグラフを描くというのは流行らないのかも知れない。使ったことはないが、gnuplotとかいう有名なツールがあるし、何より表計算ソフトを使えば実に手軽に掛けてしまう。

 

しかしながら、表計算ソフトは起動が遅い、ファイルを開くのがだるい、という問題(?)もある。折れ線グラフくらいなら簡単なので自前で書いてみようと思ってプログラムを書いてみたのだが、案の定、思うようなものは直ぐにはできないのであった。

 

慣れている(といっても纏まったプログラムは数えるほどしか書いていないが)PythonとPyCairoを使っている。Pangoの扱いを失念していて、文字を書いていくと次々に座標がづれていくことの原因になかなか気づかず、思わぬところで手間取ってしまった。(ちなみにCairoのインスタンスを使いまわしていたのが原因)。

 

tailでログファイルを適当に切り出し、所定のファイル名で保存。その後、作ったプログラムでグラフを描かせている。何の汎用性もないが、スケール調整くらいはできるようにしたいなあ。

 

今晩はエアコン無しでも27℃前後で安定している。わずかに下がっている箇所は窓開け換気によるもの。

UIにはGTKを使っているが、png出力なので画像ビューアで見ても良いし、ブラウザでも構わない。便利といえば便利。

 

esp8266(以下子機)のほうがどうにか一段落したので、次はデータ収集の方法について。

 

とりあえず、音出しサーバ(以下親機)から問い合わせすることにし、cronを仕掛ける。

 

Slitazのcronは例によってbusyboxである。毎度機能不足で問題を起こすBusyboxのアプレットだけど今回は大丈夫(多分)。

 

デーモンの起動|停止|再起動
sudo /etc/init.d/crond start|stop|restart

恒常的に動かすには /etc/rcS.conf を編集して、RUN_DAEMONS=にcrondを書き加える。

 

crontabの編集
crontab -e

尚、デフォルトの格納先は /var/spool/cron/crontabsである。

 

crontabの中身
今回のように一定時間おきに何か実行する場合
例)2分おき
*/2 * * * * command

 

時刻と温度(室温)を記録すれば良いので、適当にシェルスクリプトを書く。

#! /bin/sh
wget --directory-prefix=/home/tux/Downloads 192.168.11.10 > /dev/null 2>&1
tempt=`cat /home/tux/Downloads/index.html|cut -d" " -f2`
tm=`date|cut -d" " -f5`
echo $tm" "$tempt >> /home/tux/Downloads/log.txt
rm /home/tux/Downloads/index.html

子機側で真面目にHTTPを返しているのでwgetでファイルに落としている。面倒なのとストレージの無駄なので後日修正予定。

 

 

せっかくなので、測定記録をLibreofficeでグラフにしてみた。

 

21時38分からの室温の記録。得られたデータをそのままグラフにしてみたが、この程度の用途なら精度は0.5℃もあれば充分なので、データは加工すべきだった。

 

 

流石に29度は暑いので23時15分頃、エアコンのスイッチを入れた。設定温度は28℃、風量は微風で固定。一気に26.5℃まで下げた後上昇しているが、それでも28℃は超えていないのが判る。旧式(20年位前)のエアコンだが、それなりに制御されているようだ。

 

ファーム(SDK)のソースを読んだ訳ではないので、下記は全て演繹(単なる憶測とも)による。

 

参考及び引用URL

https://nodemcu.readthedocs.io/en/master/en/modules/net/#netsocketsend
https://github.com/nodemcu/nodemcu-firmware/issues/730#issuecomment-154241161

 

 

ここ2,3日かけてNodeMCUのドキュメントを読んでいた。英文読解力が無いのでGoogle翻訳に頼りきりなのだけれど、そのままだと5000文字迄しか受け付けないので要所要所カット&ペーストで読み進めなくてはならず、なかなか捗らない。

 

さて、懸案だったnet.socket:send()の挙動について、ようやく氷解した。


結論:NodeMCUはイベント駆動モデルなので、何をするにもイベントを使え。

 

 

動かないコードの例(抄)

sv = net.createServer(net.TCP, 30)

 

function receiver(sck, data)
  print(data)
  sck:send("hello world")

end

 

if sv then
  sv:listen(80, function(conn)
    conn:on("receive", receiver)
  end)
end

サーバー(sv)はポート80でlistenで待機、受信時のコールバックにreceiver()を結びつけている。
アクセスがあると、クライアントのWebブラウザにHello worldと表示される、というのが期待した動作であるが、表示されず待ちループになってしまう。
サーバー側はコンソールにdata(クライアントからのリクエスト文字列)を表示するので、サーバーの受信イベントは正しく動作している。sck:send()は、イベント(サーバーではなくソケットに対する)によらず直接呼び出しているので動作しないものと思われる。

 

 

動作するコード(抄)

 

NodeMCUのドキュメントのExample、及び上記参考URL(旧バージョン当時のgithub上でのやりとり、但し途中からネンチャクに絡まれてグダる。この手の輩はどこにでもいるんだなあ。)を元に改変したもの。ADCには温度センサーを接続してあり、クライアント側に室温を表示する。

srv = net.createServer(net.TCP)

function receiver(sck, data)
  print(data)

 

  local response = {"HTTP/1.0 200 OK¥r¥nServer: NodeMCU on ESP8266¥r¥nContent-Type: text/html¥r¥n¥r¥n"}
  response[#response + 1] = string.format("Now %f C¥n",(adc.read(0)/1024-0.6)*100-3)

  -- sends and removes the first element from the 'response' table
 

  local function send(localSocket)
    if #response > 0 then
      localSocket:send(table.remove(response, 1))
    else
      localSocket:close()
      response = nil
    end
  end

 

  -- triggers the send() function again once the first chunk of data was sent
  sck:on("sent", send)

  send(sck)
end

 

srv:listen(80, function(conn)
  conn:on("receive", receiver)
end)

コールバック関数 receiver の最後のほうで、ソケットsckのイベント"sent"に、関数内関数のsend()を結びつけている。そして、最期にそのsend()を呼び出して終わる。
これでソケットにイベントが生じ、コールバック関数 send()が再帰的に動作する。

 

こんなところではなかろうか。

 


(いつ?)、8ビットPC(NEC PC-6001Mk2)でキーボード割り込みを弄っていて、ROM内の割り込みルーチンを直接呼び出してもうまくいかなかったことを思い出した。

 

マルチタスクモニタと呼ばれる処理系の場合、タスクの処理方法として待ち行列があって、その順番を回すのが(貴重な)ハードウェアタイマによる定時割り込みだったりする。
あるいは、タスク1つあたりの処理時間を厳密に管理し、全体のパフォーマンスに影響がない範囲に収め、タスク終了時に順番を回して終わる、というものもある。
これらはイベント応答時間に余裕がなかったり、イベントが頻発する(ほとんどはハードウェア割込、以下割込)ような場合、あっさりと暴走(但し走るのではなく固まって見える)することが多かった。コンテキスト(だいたいレジスタのみだけど)の退避と復旧に際し割り込みをマスクしなくてはならない為、この時間がばかにならなかった。比較的低速なシステム(前述のPC-6001Mk2とか)では割込要因とハンドラを対にして、逐次処理するのが精々である。このままだと割込順序や発生・停止を制御できないので8ビットCPUではチップ系列に割込コントローラが用意されていた。Z80では系列I/Oそのものに機能を持たせており、上位のチップが下位のチップの割込を抑制する(デイジーチェイン)が物理的な配線が必要なので、別途割り込みコントローラを用意するシステムも多かったように思う。

 

なお、コンテキスト退避に配慮してかZ80は汎用レジスタを2組持っていた(いわゆる裏レジスタ)が使いどころは限定された(どちらを使っているか知る方法が無かったはず)。NECのV25だったかはレジスタファイルと称して大量に持っていて、結構使えそうな感じだったが開発ボードが(素人が手を出すには)高価(要出典)で仕様書を眺めただけで終わってしまった。

 

かように、イベントを破綻なく捌くには相当のコストを要するのである。NodeMCUでは処理時間はもとより、おそらくはメモリ消費量を抑える意味から待ち行列の類は最小限にしているのかも知れない。イベント駆動モデルなのでタスクは必ずイベントで起動して下さい、というのは、それはそれで筋が通っており理解してしまえば話は簡単である。アセンブラ等の低水準言語では煩わしい思いをするだろうが、我々(誰?)にはLuaがある。

 

 


Search

Calendar

S M T W T F S
  12345
6789101112
13141516171819
20212223242526
2728293031  
<< August 2017 >>

Archive

Mobile

qrcode

Selected Entry

Link

Profile

Search

Other

Powered

無料ブログ作成サービス JUGEM