Spresenseソースコードその2(鉢底面ヒーター温度測定部)

今回、温度センサーにテキサスインスツルメンツのLMT01LPG(秋月電気で一個150円。秋月サイトだと生産中止サインがでてるけどTiのサイトだと普通に生産中の扱いなんだよなぁ)を使用しています。このセンサーはTO-92パッケージにリード線2本が出てるタイプで出力は温度に比例したパルス数で出力されます。電源を接続すれば動作しますが、繰り返しで延々と温度信号パルスが出るだけなのでパルス数の検出が面倒っぽい。同じセンサーを使った前例を探したところいろんな方がいろんな工夫でひと塊のパルスが出終わったところを検出していました。今回の用途的に水温や気温は数秒おき、底面ヒーターはもっと短い周期が欲しいもののそれでも1秒周期もあれば良いので割り切ってこうなりました。

#include <sdk/config.h>
#include <stdio.h>
#include <stdlib.h>
#include <arch/board/board.h>
#include <arch/chip/pin.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <pthread.h>
#include <unistd.h>
#include "heattemp.h"

float temp_h = 0; //ヒーター温度
int heat_err = 1 ,heat_avgerr = 1; //ヒーター測定エラー
int hold_tmp = 0; //停止ボタン押下信号
pthread_mutex_t mutex_ht = PTHREAD_MUTEX_INITIALIZER;

static int pls_temp1 = 0; //温度センサーパルス計測用1


//PIN_UART2_RXDの割り込みが有効な間、パルスが入力されると
//入力されたパルス数を数えます
void plscount1(void)
{
pls_temp1++;
}

void stpbtn(void)
{
if(hold_flg == 0)
{
hold_tmp = 1;
}else
{
hold_tmp = 0;
}
board_gpio_int(PIN_SPI2_MISO, true); //停止ボタン割り込み無効
}

void* heattemp(void *arg) //ヒーター温度測定、動作
{
board_gpio_config(PIN_UART2_RXD, 0, 1, 0, 0); //D00 センサー入力
board_gpio_config(PIN_UART2_TXD, 0, 0, 1, 0); //D01 センサー制御
board_gpio_config(PIN_SPI2_MISO, 0, 1, 0, 1); //D08 非常停止端子
board_gpio_intconfig(PIN_UART2_RXD, INT_FALLING_EDGE, false, plscount1); //D00 パルス計測割り込み設定
board_gpio_intconfig(PIN_SPI2_MISO, INT_FALLING_EDGE, true, stpbtn); //D08 停止ボタン割り込み設定
board_gpio_write(PIN_UART2_TXD, 0); //ヒーター温度センサー停止

int pls_htadd0 = 0, pls_htadd1 = 0; //ヒーター温度測定異常検知用
int pls_avgerr = 0;

usleep(500*1000); //メインの初期設定待ち

while(1){

_strt:

for(int k0 = 0; k0 < 30; k0++)
{

//計測開始//
board_gpio_write(PIN_UART2_TXD, 1); //ヒーター温度センサー有効
usleep(40*000); //センサー電源ONまで待つ(20ms)
board_gpio_int(PIN_UART2_RXD, true); //センサー計数割り込み有効
board_gpio_int(PIN_SPI2_MISO, true); //停止ボタン割り込み有効

usleep(260*1000); //計測時間指定(3回分)

board_gpio_int(PIN_UART2_RXD, false); //センサー計数割り込み無効
board_gpio_write(PIN_UART2_TXD, 0); //ヒーター温度センサー無効

pls_htadd0 += pls_temp1;

#ifndef NOLOCK //変数ロック
pthread_mutex_lock(&mutex_ht);
#endif
if(pls_temp1 < 100) //測定結果フラグ
{
heat_err = 1;
}
else{
heat_err = 0;
}

if(abs(pls_htadd1 - pls_temp1 * 30) > 7000)
{
heat_avgerr = 1;
}else
{
heat_avgerr = 0;
}

temp_h = pls_temp1 / 48.48 - 50.0; //温度計算

#ifndef NOLOCK //変数ロック解除
pthread_mutex_unlock(&mutex_ht);
#endif

pls_avgerr = 0;
pls_temp1 = 0; //パルス数クリア
usleep(100*1000); //計測間隔を0.4秒に調整

if(hold_tmp == 1) //停止ボタン対応
{
#ifndef NOLOCK //変数ロック
pthread_mutex_lock(&mutex_ht);
#endif

hold_flg = 1;

#ifndef NOLOCK //変数ロック解除
pthread_mutex_unlock(&mutex_ht);
#endif
usleep(400*1000);

if(board_gpio_read(PIN_SPI2_MISO) == 1)
{
goto _strt;
}

usleep(1100*1000);

if(board_gpio_read(PIN_SPI2_MISO) == 0) //ボタン長押しで非常停止処理
{
board_gpio_int(PIN_SPI2_MISO, false);
usleep(1000);

#ifndef NOLOCK //変数ロック
pthread_mutex_lock(&mutex_ht);
#endif

emstp = 1;

#ifndef NOLOCK //変数ロック解除
pthread_mutex_unlock(&mutex_ht);
#endif
}

} else{
#ifndef NOLOCK //変数ロック
pthread_mutex_lock(&mutex_ht);
#endif

hold_flg = 0;

#ifndef NOLOCK //変数ロック解除
pthread_mutex_unlock(&mutex_ht);
#endif
}

if(emstp == 1) //非常停止処理
{
board_gpio_int(PIN_UART2_RXD, false);
board_gpio_write(PIN_UART2_TXD, 0);
break;
}
}
pls_htadd1 = pls_htadd0;
pls_htadd0 = 0;
}
return NULL;
}

ヘッダファイルの中身

#ifndef _INCLUDE_HEATTEMP_
#define _INCLUDE_HEATTEMP_
void* heattemp(void *arg);
#endif

float temp_h; //ヒーター温度
int heat_err; //ヒーター測定エラー
int heat_avgerr;
int emstp; //非常停止フラグ
int hold_flg; //一時停止フラグ

このコードでは3回分のパルス数をカウントし、その平均で温度を算出しています。計測間隔は0.5秒です。これ以外に

  1. 測定エラー検出(パルス数が100未満の時にフラグ立て)
  2. 平均エラー検出(前30回分の平均に対して約15℃分ズレている時にフラグ立て)
  3. 一時停止機能(停止ボタンを短く押すと計測を一時中断。もう一回押すと再開)
  4. 非常停止機能(停止ボタン長押しで計測を停止し数値等全部クリア)

の機能があります。鉢底ヒーターの温度を管理するためのものなので、計測値自体は特に加工せず0.4秒おきに淡々と数値を更新します。

実際の鉢底ヒーターはこんなふうに作っています。

①ヒーターそのものはシートヒーターをA4サイズのアルミ板(1.5mm厚)で挟んでいます
②LMT01LPGを熱伝導性両面テープで貼り付けた上でエポキシでポッティング
③シールド線を接続し熱収縮チューブで保護しました
このヒーターをトロ箱の底に配置、断熱材で覆いました。

Posted in プログラミング, ベランダビオトープ, 園芸, 睡蓮水槽管理装置, 電子工作 | Tagged , , | Leave a comment

Spresense ソースコードその1(メイン(設定部分))

※2020年10月13日修正(設定温度改良に伴う)

某ブラウザゲームのイベントとかやっていて間が空いてしまいましたが、ソースコードです。開発環境は主流ではないですがSpresense SDKを使用しています。理由は拡張性が高そうに見えたことと、Arduino IDE環境だとチャタリング防止機構を無効にできず使用している温度センサーが上手く使えなかったためです。ただ、主流ではないだけに資料があまりにも少なくLチカまではそこそこできたものの、その先はほぼ完全に手探り。結局モニター用の液晶は最後まで表示できませんでした。一方で、SDK環境で用いるNuttx OSはマルチスレッドに対応しておりSpresenseのマルチコアCPUと合わせて拡張性の高さの片鱗を見ることもできました。

能書きは終わりにして、まずはメインの部分から。ここに肝心な部分はあまりありませんが、マルチスレッドの設定や各プログラムの呼び出しなんかをやっています。

#include <sdk/config.h>
#include <stdio.h>
#include <arch/board/board.h>
#include <arch/chip/pin.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <arch/chip/gnss.h>

//各プログラム呼び出し用ヘッダ//
#include "heattemp.h"
#include "watemp.h"
#include "gnssclk.h"
#include "cntunit.h"
#include "ledout.h"

//測定、更新間隔設定//
int intvlh = 1; //ヒーター測定、判定間隔(秒単位)
int intvla = 3; //水温、気温判定間隔(秒単位)
int sintv = 2; //水温、気温測定間隔(秒単位、2秒以上)
int shour = 60, sday = 24, sweek = 7; //各時間間隔ごとの気温計測数

//温度範囲設定(12ヶ月分+1番目は時刻未取得時の値)//
//月別ヒーター温度上限(ここを越えたら絶対に止める)//
float vtemp_hmax[13] = { 7, 10, 10, 12, 20, 25, 25, 25, 25, 25, 20, 15, 12}; 

//月別ヒーター温度下限(ここを下回ったら絶対に動かす)//
float vtemp_hmin[13] = { 3, 5, 5, 8, 15, 20, 20, 20, 20, 20, 15, 10, 6};
 
//月別ファン制御温度上限(ここを越えたら絶対に動かす)//
float vtemp_wmax[13] = { 25, 15, 15, 20, 25, 26, 26, 26, 26, 26, 24, 20, 18}; 

//月別ファン制御温度下限(ここを下回ったら絶対に止める)//
float vtemp_wmin[13] = { 18, 10, 10, 15, 18, 20, 20, 20, 20, 20, 18, 15, 12}; 

//月別水凍結防止ヒーター温度上限(ここを越えたら絶対に止める)//
float vtemp_h2max[13] = { 5, 7, 7, 10, 15, 15, 18, 18, 18, 15, 15, 10, 7}; 

//月別水凍結防止ヒーター温度上限(ここを下回ったら絶対に動かす)//
float vtemp_h2min[13] = { 2, 2, 2, 5, 10, 15, 15, 15, 15, 15, 10, 3, 2}; 


//温度設定用係数(0〜10で設定。数字が大きいほど温度が高めになる。
//ヒーターとクーラーの設定次第で両方動作する場合がある)

//ヒーターの月別係数設定。
//冬季は冬眠の邪魔をしないように低め、夏季は高めに設定
float ntemp_heat[13] = { 3, 2, 2, 3, 4, 4, 5, 5, 5, 4, 3, 3, 2};

//クーラーの月別係数設定。
//梅雨寒等を想定して6月は高め、猛暑な7〜9月は曝気目的もあって低め
float ntemp_cool[13] = { 7, 5, 5, 6, 7, 7, 7, 6, 6, 6, 6, 5, 5};
//フラグ、変数類// int emstp = 0; //非常停止フラグ int hold_flg = 0; //一時停止フラグ int heat_flg = 0; //ヒーター動作 int cool_flg = 0; //ファン動作 int wthr_flg = 0; //追加ヒーター動作 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // プログラム本体 // #ifdef CONFIG_BUILD_KERNEL int main(int argc, FAR char *argv[]) #else int wtcont_main(int argc, char *argv[]) #endif { //とりあえずLEDの端子属性を指定して全部消灯// board_gpio_config(PIN_I2S1_BCK, 0, false, true, 0); //LED0 board_gpio_config(PIN_I2S1_LRCK, 0, false, true, 0); //LED1 board_gpio_config(PIN_I2S1_DATA_IN, 0, false, true, 0); //LED2 board_gpio_config(PIN_I2S1_DATA_OUT, 0, false, true, 0); //LED3 usleep(200*1000); //LED点滅して起動表示// board_gpio_write(PIN_I2S1_BCK, 1); board_gpio_write(PIN_I2S1_LRCK, 1); board_gpio_write(PIN_I2S1_DATA_IN, 1); board_gpio_write(PIN_I2S1_DATA_OUT, 1); usleep(500*1000); board_gpio_write(PIN_I2S1_BCK, 0); board_gpio_write(PIN_I2S1_LRCK, 0); board_gpio_write(PIN_I2S1_DATA_IN, 0); board_gpio_write(PIN_I2S1_DATA_OUT, 0); usleep(10*1000); //マルチスレッド設定+各プログラム呼び出し//
//スレッド数はコア数(6個)以内にするのが吉っぽい// pthread_t thread_A, thread_B, thread_C, thread_D, thread_E; pthread_create(&thread_A, NULL, heattemp, NULL); pthread_create(&thread_B, NULL, watemp, NULL); pthread_create(&thread_C, NULL, cntunit, NULL); pthread_create(&thread_D, NULL, gnssclk, NULL); pthread_create(&thread_E, NULL, ledout, NULL); pthread_join(thread_A, NULL); pthread_join(thread_B, NULL); pthread_join(thread_C, NULL); pthread_join(thread_D, NULL); pthread_join(thread_E, NULL); usleep(200*1000); //異常終了時LED全部点灯// board_gpio_write(PIN_I2S1_BCK, 1); board_gpio_write(PIN_I2S1_LRCK, 1); board_gpio_write(PIN_I2S1_DATA_IN, 1); board_gpio_write(PIN_I2S1_DATA_OUT, 1); return 0; }

使った資料はSpresense公式ページとどこかは失念しましたがブログサイト様、Nuttx OSを扱ったページいくつかです。マイコンを扱うというのが頭に強くこびりついていて最初苦労しましたが、OSを介して動かすことからPCの扱いに近い部分があることに気づくと幾らか楽になりました。接続するデバイスはドライバが見つかればかなり簡単に扱えるようです。

マルチスレッド対応ですが、スレッド数はコア数以内で抑えないとリアルタイム制御が上手くいかなくなるようです。当初、停止ボタンの動作管理も別スレッドで記述していましたが、センサーの動作時間制御が不安定になり温度をまともに検出できなくなったので各プログラムに潜り込ませて対応しました。停止ボタン押下検出の間隔を変化させても問題が解決せず、スレッド数をコア数以内で収めることで動作が安定しました。

Posted in プログラミング, ベランダビオトープ, 園芸, 睡蓮水槽管理装置, 電子工作 | Tagged , | Leave a comment

睡蓮水槽管理装置の効果

コロナウィルス禍に伴う在宅勤務の傍らで睡蓮水槽管理装置の夏場の効果を測定してみました。結論から書くと、猛暑日が起きる環境では二枚貝(※1)を飼育するのは無理ですが周囲温度が40℃に達する環境でも水温を30℃程度に抑える事ができる(※2)ので、飼育している生物の負担をかなり抑えることができそうです。

※1淡水しじみは対策なしでも何とか飼育可能だった
※2水槽や水タンクの壁面等を断熱材で覆うこと

細かい条件は省略して測定結果は以下の通り。

本日の直近のアメダスにおける最高気温は32℃でしたが、この水槽が置いてあるベランダは南側にある駐車場の照り返しなどにより、風通しの良いところに置いた温湿度計(ウェザーニューズ社WxBeacon2)で39.0℃、水タンク直上の温度計で測定した最高気温は41.5℃(※3)に達しました。一方で水温は最高29.9℃でした。

水温の変化(※4)から、水温は気温よりも露点の影響を受けることが分かります。長野の夏は南関東よりは乾燥していることを考えると、同じ装置を南関東に持っていってもこの結果よりは水温が高くなる事が多いと思います。逆に高温でも湿度が低い場合は気化熱式で充分という予測(※5)もできます。

※3エアコン室外機の排気が水槽周辺に滞留しないよう導風板を設置しているので、室外機吸気側に面している調温箱の吸気口温度はもう少し低い(かも)。
※4周囲温度が水温より高くても露点が下がると水温が下がる。
※5例:気温40℃、湿度20%の場合、露点は12.8℃。
 上記グラフの収束温度?と同じところに落ち着くとすると水温26.4℃
 なのでどうにか大型の2枚貝も飼育できそうな温度に収まる。

睡蓮水槽はエアコンの室外機のすぐそば(温度管理装置兼濾過器に至っては室外機の上)にあり、その中で気化熱のみで冷却していたことを考えると健闘していたと言えると思います。ただし、条件が条件なので、エアコンの室外機から離した上で水槽周りの断熱を改善すると、あと1〜2℃程度稼げると予想します。また、二枚貝を飼育したいなどの理由で水温を25℃程度までに抑えたい場合はペルチェ式もしくは冷凍機式のクーラーが別途必要と思われます。

Posted in ベランダビオトープ, 園芸, 睡蓮水槽管理装置, 電子工作 | Tagged , , | Leave a comment

睡蓮水槽管理装置製作その2

今回作った装置の回路図

今回製作した管理装置の回路図です。SpresenseはArduino Unoとピン配置が互換(実際には少し違う)なのでKi CADにあったArduino Unoの回路記号を流用して描いています。

温度センサーはテキサスインスツルメンツのLMT01LPGを使用。癖が強いですが、配線が簡単なこととI2Cなどによる通信の必要がなく200ms周期で温度が取り出せるので採用しました。中途半端な電圧のパルスで出力されるので、コンパレーターを使用してパルスを整形しています。また、雑音に弱そうだったので

  • 基板からセンサーまでの配線にシールド線を使用
  • マイコンボードから供給される+電圧側をシールド側に配線
  • シールド側にコンデンサを付けて高周波的に接地

という処置を追加。コンデンサーの有無での違いを測定したオシロスコープの画面を保存し忘れましたが、シールド側に0.01uFを追加することによりパルスが出力されている区間の+側の波形が安定します。実際には1m程度のシールド線を通して屋外で使用していますが問題はないようです。

実際の出力波形(コンパレーター出力)

センサーの動作結果を検出する方法に迷いましたが、信号長は固定なので時間を決めて5回分の出力パルスを計数して平均を取って温度を測定しています。

Posted in ベランダビオトープ, 園芸, 睡蓮水槽管理装置, 電子工作 | Tagged , , | Leave a comment

睡蓮水槽管理装置製作その1

睡蓮水槽には名前の通り温帯睡蓮が植えられています。凍結防止にヒーターを使っていますが温帯睡蓮は冬季に寒さに当てないと花芽ができません。しかし、水温を一桁に設定できる水槽用ヒーターなんてものはないので自作するしかありません。当初は「水槽が前面凍結しなければいいや」と言った感じで手持ちの半導体サーモスタットと水槽用ヒーターの組み合わせで作り、サーモスタット部をシリコンゴムで防水処理して水槽に放り込む案でぼんやり考えていました。

もらいもののSpresenseマイコンボード。結構多機能

そんなある日、某展示会で応募した抽選でSONYのマイコンボードSpresenseが当選。当たったものの画像処理までこなせるマイコンボードの使い道が余り思い浮かばなかったので睡蓮水槽の管理用に使ってみることにしました。

基本方針はこんな感じで

  • 冬季夜間の水温を2〜5℃程度で維持し配管の凍結を防止すると同時に温帯睡蓮の冬眠条件を満たすようにする
  • 水槽の底に温度センサー付きのヒーターを置き底砂及び睡蓮鉢が下から凍結しないようにする
  • 夏季の水温が上がりすぎないようファンを付ける
  • せっかくのマイコンボードなので使える機能は使う

実際に搭載した機能は以下の通り

  • 水槽凍結防止ヒーター制御(ヒーター自体は金魚用)
  • 底砂凍結防止ヒーター(DC12V用シートヒーターと温度センサーで自作)
  • クーラー(いまのところジャンクPC用ファンを使った気化熱式のみ)
  • 月別温度設定
  • 一週間分の気温情報から自動温度設定
  • 気温の急変時にヒーター・クーラーを早めに起動
  • GNSSを使用した自動日時取得

令和元年冬に一応完成、最低気温−10℃程度であれば貯水タンクの水温を0.5℃以上を維持して凍結を防止、かつ冬季の水温上限を10℃未満に抑えることができた。これを執筆している時点(令和2年6月)は夏季の冷却能力を確認中。暑そうな日に日中の温度データを記録する予定。周辺の温度が約38℃の状態で3時間経った際の水温を26℃に抑えることができている模様。

今回実装できなかったけどそのうち実装したい機能

  • 液晶での温度表示
  • SDカードから設定情報読み取り
  • Wi-Fi接続による外部からの状態監視
Posted in ベランダビオトープ, 園芸, 睡蓮水槽管理装置, 電子工作 | Tagged , , | Leave a comment