とある実験のーと

趣味ブログ

3Dプリンタで名前ハンコを作る際の調整覚え書き (TPU使用)

この時代にもハンコが必要になる場面がある。

とある事情で名前ハンコが必要になったが、楽天を見ると大きさ違いで数種入って3-4千円するらしい。

折角なので作ってみたが、少し調整が必要だったのでどなたかの参考になればと思い、書き置いておくことにした。

ハンコ部分はTPUフィラメントを用い、柔軟性を持たせ、取っ手部分はPLAで作る事にした。 私が持っているTPUフィラメントはFlashforgeの物↓であるが、特にメーカーは問わないだろう。

flashforge.shop-pro.jp

モデリング

今回サンプルとして作ったのは「やまだ たろう」の 5 mm × 25 mm の名前ハンコ(ちなみに私は山田太郎ではない)。文字は一文字 4 mm角ぐらいだが、これぐらいが最少限界な気がする。スライサーで確認すると、3Dプリンタのノズル一筆書き分である。

Fusion360モデリングした。文字と取っ手に貼り付ける台座部分の厚さが肝で、文字部分を1 mm、台座部分を5 mmにしたところ反りにより上手くいかなかった(何で反るのかは後述)。

よって、文字の浮き上がり 2 mm, 台座部分 2 mm程度が丁度良い塩梅だった。文字に合わせて台座部分の形を最適化すれば反りが克服できるかもしれないが、面倒なので今回は行わなかった。

お分かりだと思うが、文字を左右反転させることを忘れずに・・・。

モデリングしたもの (高さは文字部分 2mm, 台座部分 2mm)

スライサーの設定

スライサーでの設定でポイントは以下の通り。

1. 文字面を底面にする

反りや、ベッドへの定着を考えた場合、文字面を上にして出力しがちである。私も最初それで出力したが、ハンコを押した時に上面の微妙な凸凹が影響して非常に汚い文字となった。これを解決するには、出力後に文字面をヤスリ掛けする必要があるが、面倒なのとTPUはそもそもヤスリが掛からないので無理。

文字面を底面として出力することで、平滑な文字面とすることができる。

ただ文字面は底面積が小さいので端っこが最終的に反って浮き上がる・・・。精神衛生上非常に良くないが、反ることを許容して出力しても大丈夫だった。

2.サポートを付けない

文字から台座の順に出力するとオーバーハングが酷くてサポートを付けたくなるが、TPUはサポートが綺麗に取れないので諦める。TPUは柔軟性と粘着性があるので、これでも何とか出力してくれる。

3. 一層目の厚さとフィラメント量を調整する

基本設定では、定着面となる一層目はフィラメント量が多めに出るようになっていることが多い。ただ、今回の場合、一層目のフィラメント量が多くなると文字が潰れやすくなる。 私のケースでは、デフォルト設定で一層目積層厚さが0.27 mm → 0.20 mmとし、フィラメント押し出し量が109% → 100%に変更して出力してみた。結果を見る限りフィラメント押し出し量はもう少し少なくしても良いかもしれない。そんなに出力に時間がかからないので、トライ&エラーしてみる価値あり。

プリント時

基本設定

*積層厚さ: 0.18 mm

*ノズル: 0.4mm - 230°C, 冷却ファンON

  • ベッド: 60°C

  • 印刷速度: 60 mm/s

  • ラフトなし

3Dプリンタでのポイントは以下の通り。

1. ベッドはできるだけ平滑な物を使う(私はガラス)

マスキングテープ地でも良いと思うが、少し厚さが変わると文字面が潰れたりするので要調整。

2. 反るけど見守る

どうしても台座の出力時に反って隅の部分が剥がれてくる。ただ、まん中部分がひっついてればズレはしないので最後まで見守る。 マスキングテープ地だと、定着力が上がるので反らないかもしれない。

以下にプリント後の様子を写したが、端っこが反って底面から外れていることが分かる・・・。

出力結果(端っこは反って離れているが、最後まで出力できている)

両面テープで別に出力した取っ手部分(PLA)と接着した。

取っ手を付けた様子

フィラメント量の設定の違い。微妙だが少し文字の潰れが緩和している

まとめ

今回、3Dプリンタで初めて名前ハンコを作ってみたが、一回コツが分かれば今後も色々作れそうな気がした。 勿論、一行だけでなく様々な文字サイズを組み合わせたハンコも可能である。

一方で、細かい文字は苦手で、4 mm角程度の文字が限界である。小文字においてはノズル一筆書きになるので、文字太さはほぼ調整できないと思っておいた方がよさそう。

私は、5mm × 25 mm を1点だけモデリングし、スライサーの拡大機能でXY方向のみ150%, 200%と変更することで大きさを変えて3種類の名前ハンコを揃えた。Z方向だけは文字と台座の高さも変わってしまうので固定である。

もし、自分も作ってみたよっという方がいたらコメントくれたらちょっと嬉しい・・・。

ChromeOSでDVDを再生する

ChromeOSを触る機会を得た。一通りの事はできるのでとても満足度が高いし、流石スマートフォンに搭載するOSをベースにしているだけあって、Android用のアプリがノートブックのスペックだと驚くほどサクサク動いて快適そのものである。

DVDの再生には対応していないが・・・

AndroidアプリでDVD再生に対応していないので、原則DVDの再生には非対応である。ただ、ChromeOS上ではLinuxが動くそうなので、Linux用のソフトで代用することが可能である。似たような記事が幾つかあったが、少し躓いたので、備忘録として残しておく。

1. Linuxを有効にする

これまでLinux環境を一度も利用したことが無い場合、その構築から始まる。プリインストールアプリに「ターミナル」があるのでそれを起動すると、Linux環境を構築していいか問われる。特にいじるところなくそのままLinux環境を構築する(数分)。

2. ターミナルでVLCをインストールする

ターミナルでVLCをインストールする。Ubuntu仮想環境をまず入れないといけない等の記事を見かけたが、特にそのようなことをする必要はなく、以下のコマンドですんなりインストール可能だった。

sudo apt-get update sudo apt-get install vlc

インストールが終わったら、VLCを起動してみる。なお、LinuxのソフトもAndroidアプリみたいに一覧表示に出てくるので起動にいちいちターミナルを開く必要もなく本当にシームレス。凄く使いやすい。

3. USBドライブでDVDを挿入し、Linuxと共有する

一般的なUSBタイプのDVDドライブがほぼ使えるのでは。試してみたDVDはマウントできたが、CDに関してはマウント出来ないものがあった。CDに問題があるのがChromeOSがそういう仕様なのかは追求していないが、認識されたらChromeOS上に認識した旨が表示される。

マウントされたDVDをLinuxと共有する。 これをしないとLinuxVLCでは認識されない。 アプリ「ファイル」を開き、ChromeOSで認識できているとディスクの項目が追加されている。ディスクを右クリックすると、「Linuxと共有する」という項目があるのでそちらをチェック。

/(ユーザ名)/mnt/chromeos/***

にマウントされた旨が表示される。この場所を覚えておく。

4. VLCでマウント先を開く

VLCのメニュー「Media」→「Open Directory」を選択し、先ほどマウントされた場所を指定する。 すると、無事DVDのメニューが再生されはじめるはずである。

最後に

今回試した範囲では、LinuxVLCで特にプラグイン等を入れることも無く再生できました。どなたかのご参考になれば。 ほぼストリーミングで事足りる世の中ですが、これで万が一DVDを再生しなければならなくなった場合にも対応できるようになりました。

ESP32でオンラインデータロガーを作る ④Google spreadsheet側での後処理

経時変化を実際のスケールで表示したい

最後、IFTTTによって送られてきたデータがGoogle driveのSpreadsheetにどんどん溜まっている。ここで一つ問題が発生する。
IFTTTは自動的にタイムスタンプを1列目に挿入してくれるが、このタイムスタンプがGoogle spreadsheetで日時として認識されない。そのままだとx軸が設定できないので何時のデータかよく分かりらず、データに欠損があったり、飛び飛びだった場合に正しく表示できていないことになる。
下図は実際の室温データだが、上が得られたデータそのまま、下が日時を認識可能な状態にして作ったもの。欠損のある部分が分からなくなってしまっている。

f:id:azospiran:20190805051054p:plain
上: x軸そのまま、下: 日時として認識させた正しいスケール, 一定温度になってるところはエアコンが動いてる時間帯

ロギングの停止を自動検出したい

どうしてもWIFI接続なので時々不安定になることは十分考えられる。ロギングが不意に止まった場合、それを自動検出して通知ぐらいはして欲しい。

関数で日時を認識可能な状態にする

タイムスタンプの日時の間に挿入されている"at"が邪魔をしていることになる。 この方法が正しいのかよく分からないが以下の様な関数で文字列を抽出し、連結すると日時として認識された。
一部のブログだと翻訳機能の関数を使って日時として認識させる方法があるみたいだが、私の場合"AM"が翻訳されるときとされないときがあって不安定だったので使えなかった。 f:id:azospiran:20190805051816p:plain

Google scriptの設定と自動実行

ここで一つ問題となるのが、データが新たに追加されたときに、その行に対応する関数を毎回手動で入れる訳にはいかないということである。
IFTTTが投稿する際に関数を予め投稿できる様に書式変更している方もいたが、ちょっと複雑だったので躊躇した。 あと、二つ目の目的であるロギングの停止の検出もできていないので、Google scriptで自動実行させることにした。 Spreadsheetでスクリプトを作成するときは Tools→Script editor で開く。

Javascript・・・全然分からないのですが、一先ずこんな感じで動いた。 f:id:azospiran:20190805055105p:plain 作戦としては、図にある赤枠の部分(日時の書式を整える最終行)に注目。
5分ごと( データが5分間で投稿されてくるので)にスクリプトを自動実行し、上の他セルから書式コピーしてくれば日時が自動計算されるというズボラな考え。 一方、もしここに値が有った場合、前回の実行からデータが更新されていない→IFTTTかESP32に問題があってロギングが止まってることを意味する。
scriptもエラーになることがあるので、冗長性をもたせるため、最終3行の空白を判定することにした。また、gmailでメール送る簡単な関数(GmailApp.sendEmail())があったのでそれでロギングが止まった場合の通知をすることにした。
スクリプト自体のログは自動実行したときに状態を見たいので、console.log()で出力した。

function copylastcolumn2() {
    var spreadsheet = SpreadsheetApp.getActiveSheet();//getRange+変数はsheetクラスじゃないと動作しないよ!!!
    var LastRow = spreadsheet.getLastRow();
    var value = spreadsheet.getRange(LastRow,6).getValues();
    var value2 = spreadsheet.getRange(LastRow-1,6).getValues();
    var value3 = spreadsheet.getRange(LastRow-2,6).getValues();

//  下から3番目のcellが空白かどうか判断、空白だったらコピー
   if(value3 == ""){
      spreadsheet.getRange(2,6).copyTo(spreadsheet.getRange(LastRow-2,6), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
     //logger.log
     console.log("Succeed3");
  }  
//下から2番目のcellが空白かどうか判断、空白だったらコピー
     if (value2 == ""){
      spreadsheet.getRange(2,6).copyTo(spreadsheet.getRange(LastRow-1,6), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
     //logger.log
     console.log("Succeed2");
     } 
//下から1つ目のcellが空白かどうか判断、空白だったらコピー(通常はこれが動く)
     if(value == ""){
  spreadsheet.getRange(2,6).copyTo(spreadsheet.getRange(LastRow,6), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
     //logger.log
     console.log("Succeed1");
     }
//空白のcellがない→ロギングが止まってるのでメールで通知
  else{
    console.log("The logging is stopping");
    //Send email
GmailApp.sendEmail("*******@gmail.com","ESP32","The logging may have stopped.");
  }
}

躓いたところは、"spreadsheet.getRange(LastRow-1,6)" みたいにgetRangeの参照先に変数で指定したい場合、上手くいかなかった。結局冒頭の部分を以下の様に”Spreadsheet”から"Sheet"に書き換えたら上手くいった。勉強不足でここら辺の扱いがどうなっているのか理解はしてない・・・。

var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
↓
var spreadsheet = SpreadsheetApp.getActiveSheet();

自動実行の設定

f:id:azospiran:20190805061039p:plain 詳しくはそれを解説しているサイトを見ていただけたらと思うが、時間指定でこのスクリプトを走らせることができる。Script editorのメニューのところにある時計マークで設定可能。今回は一先ず5分ごとに実行するようにした。

※ ロギングが止まったときメール通知が5分ごとに来ることになるのがちょっとダメ。そして、それが原因でスパムとみなされてスクリプトを強制停止されてしまう。後で要改善。

最後に

これで一先ず、ざっくりだがオンラインロギングシステムができた。センサーは何でも良いので非常に汎用性が高い。今のところ安定性も特に問題ないようである(データが欠損してたところは意図的に電源を切ってた)。メール通知も、例えば異常値などの監視としても使える。
今後色々測っていきたい。

参考にしたサイト

GASでのメール送信についてまとめてみる - Qiita

【arduino農業】ビニールハウスの温度をクラウドで管理する | おうち栽培

これまでの内容はこちら

azospiran.hatenablog.jp

azospiran.hatenablog.jp

azospiran.hatenablog.jp

azospiran.hatenablog.jp

azospiran.hatenablog.jp

ESP32でオンラインデータロガーを作る ③IFTTTに向けてデータをPUSH

Google spreadsheetへの投稿にむけて

f:id:azospiran:20190804042057p:plain 今回はESP32からIFTTTへの投稿です。
やることは以下の通り。説明のときに 一つずつの要素コードを抜き出しますが、最後に全文を張っておきます。

  • ESP32をwifiに繋ぐ
  • Thermistorの電圧を取り温度に変換
  • 一定時間でIFTTTのイベントを呼ぶ  

また、ここで工夫している点は以下になります。

  • IFTTTのイベントを単に呼び出すだけじゃなく、データを載せて送る。
  • delay()を使わないようにして並列処理が可能になっている。
  • 平均値を出すことでノイズを抑える。

WSP32をwifiに繋ぐ

基本的に前回も紹介したここのサイトを参考にしながら進めた。また、ESP32のライブラリをインストールした後ならお試しコードが事前に用意されているのでそれでもいい。 ssidとパスワードを自分の環境に合わせて入力する。また、iftttのイベントを呼ぶためのkeyと、event名を書き換える。
void setup()でwifiへの接続を確立する。ちなみにSerial通信は115200 bpsを指定しているのでArduinoで良く使ってる9600じゃない。ここら辺のコードは先人のコピペです。

#include <WiFi.h>
const char* ssid = "************"; //wifiアクセスポイント
const char* password = "*********"; //wifiパスワード
const char* host = "maker.ifttt.com";
const int httpsPort = 443;
const char* key = "bospC***************"; //iftttのkey
const char* event="esp32_post";//iftttのイベント名

void setup() {
//netwerk settings, wifiへの接続
  Serial.begin(115200);
  Serial.println();
  Serial.print("connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(5000);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  WiFiClientSecure client;
  Serial.print("connecting to ");
  Serial.println(host);
  if (!client.connect(host, httpsPort)) {
    Serial.println("connection failed");
    return;
  }

Thermistorの電圧を取り温度に変換、millis()で投稿時間を制御

wifiに接続した後にTHermistorの電圧値をとって温度に変換する。 この処理はvoid roop()の中行う。関連するコードは以下の通り、GPIO34にThermistorを繋ぎ、電圧値を取得した。以前書いたのと同じ。 azospiran.hatenablog.jp

ここで、投稿するまでの待ち時間をdelay()で指定する例が多かったのだが、delayは処理全て止めてしまうので、その待ち時間の間に他のコードを走らせたいなど汎用性が下がってしまうことが分かった。なので、プログラムが開始時間を0としてカウントしているmillis()という関数を採用して、一定時間毎に色んな処理を並列して進められるようにした。並列処理したいコードの数だけtimerを準備すれば良いと思う。参考にしたサイト。 Arduino - delayを無くしたい|teratail

今回はSerial通信にリアルタイムの値を5秒毎に表示し(timer1)、IFTTTに5分ごとに投げるため(timer)に2つのタイマーを用意した。そしてif文でmillisを監視し、前回の投稿時間から指定秒だけ経つのを待つ。

試行錯誤の結果、IFTTTの時間あたりのイベント呼び出し回数に制限があることが分かった。1分毎だとダメで5分ごとだと引っかからないみたい。

delay()を使ってないので、投稿までのThermistorの値を積算してcounterの値で割ることで平均値を出すことにした。5分間で何千回とloopが回ってるはずなので、これでノイズの影響を大分軽減できるはず。

関連するコードを 一応抜き出した。

#include <math.h> //数値計算する際に必要らしい

//msでプログラムが始まったところからカウント, delayを使わない場合
long dt=300000;//何秒間隔でiftttに投稿するか[ms]
unsigned long timer = millis();
//serialに投稿する間隔の時につかうtimer1 [ms]
unsigned long timer1=millis();


//void setup()内
//input thermistor thermistorの入力
  pinMode(34, INPUT);  

//void roop()内
//iftttに投稿するまでシグナル値平均値を計算させる
thermVal+=analogRead(34);
counter ++;

//シリアルモニタへの現在地の出力 (5秒毎)
if (millis()>timer1+5000){
timer1=millis();
Vout=analogRead(34)*3.3/4095;
R1=(3.3/Vout-1)*R0;
  double R=R1/R25;
  T=1/(1/B*log(R)+1/298.15);
  T=T-273.15;
  Serial.print("Current T: ");
  Serial.println(T);
}

//iftttに投稿, dt時間毎
if (millis()>timer+dt){
  timer=millis();

//read thermistor value
thermValav=thermVal/counter; //平均値を計算
Vout=thermValav*3.3/4095; //Thermistorの電圧値を計算
R1=(3.3/Vout-1)*R0;
  double R=R1/R25;
  T=1/(1/B*log(R)+1/298.15);
  T=T-273.15;

一定時間でIFTTTのイベントを呼ぶ 

先ほどの2つめのif文の中の続きで、計算した値 (今回は電圧値、抵抗値、温度)をIFTTTに送る為に整えていく。 IFTTTはkeyとイベント名が載ったurlを実行することでイベントを発生させられるが、そのままではデータを載せられず、トリガーが実行されるだけである。値も一緒にポストするにはJSON方式で記述しないといけないらしいが、標準ESP32の標準のhttpライブラリはjsonに対応していない。
以下のサイトが大変参考になりました。ありがとうございます。

https://shiiiiiiiii1.tumblr.com/post/178921930788/esp32%E3%81%8B%E3%82%89ifttt%E3%81%AEwebhooks%E3%81%AEapi%E3%82%92%E5%8F%A9%E3%81%84%E3%81%A6%E3%81%BF%E3%82%8B
shiiiiiiiii1.tumblr.com JSONはHTTPCliant.hライブラリの機能を使わないといけないらしいので、他の事例と少し書式が違っている。
このif文の最後でシグナル値の積算とcounterを初期化して次の測定に備えてる。

//loop()内
//ifttへのイベントに一緒に送る値
String val1=String(Vout,5);
String val2=String(R1,5);
String val3=String(T,5);

// iftttのURLを作成 (HTTPClient.hの機能を使う)
// maker.ifttt.com/trigger/{event}/with/key/{key}
String url = "http://maker.ifttt.com/trigger/";
url += event;
url += "/with/key/";
url += key;
String json;
  
// JSON データの作成
json = "{ \"value1\" : " + val1 + ", \"value2\" : " + val2 + ", \"value3\" : " + val3 + " }";  
Serial.print(json);

 HTTPClient http;   // インスタンスの生成
 http.begin(url);   // HTTP リクエストの設定
 http.addHeader("Content-Type", "application/json");   // 送信形式を JSON データに設定
 http.POST(json);   // POST リクエストで送信
 http.end();
Serial.println("_post");

counter=0; //counterとシグナル値の合計値を初期化
thermVal=0;
}

一応、これでコードを構成している内容は網羅しているとおもう。あとLEDをGPIO4に付けてるので、IFTTTに投稿するときだけ光るようにした。

最後に

IFTTT側の制限で一見val1-3の3種類しかデータを載せられないように見えるが、データをカンマ区切りの文字列などにして乗せれば無限にデータを送れると思う。その後の処理はGoogle spreadsheet側の仕事だと思う。 次回はSpreadsheet側での処理が少し必要だったのでそれについて書きます。

以下、コード全文。

#include <HTTPClient.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <math.h>

const char* ssid = "************"; //wifiアクセスポイント
const char* password = "*********"; //wifiパスワード
const char* host = "maker.ifttt.com";
const int httpsPort = 443;
const char* key = "bospC***************"; //iftttのkey
const char* event="esp32_post";//iftttのイベント名

//Thermistor
double Vout;//出力電圧
double R1;//サーミスタ抵抗値
double B=4000.00; //補正係数
double T; //サーミスタ温度
double R0=10.000; //参照抵抗kΩ
double R25=10.000; //25°Cの時の抵抗
double thermVal=0;
double thermValav;
int counter=0;

//msでプログラムが始まったところからカウント, delayを使わない場合
long dt=300000;//何秒間隔で投稿するか[ms]
unsigned long timer = millis();
//serialに投稿する間隔 [ms]
unsigned long timer1=millis();

void setup() {
//netwerk settings, wifiへの接続
  Serial.begin(115200);
  Serial.println();
  Serial.print("connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(5000);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  WiFiClientSecure client;
  Serial.print("connecting to ");
  Serial.println(host);
  if (!client.connect(host, httpsPort)) {
    Serial.println("connection failed");
    return;
  }
//output settings LEDへの出力
  pinMode(4, OUTPUT);

//input thermistor thermistorの入力
  pinMode(34, INPUT);  
}

void loop(){
//iftttに投稿するまでシグナル値平均値を計算させる
thermVal+=analogRead(34);
counter ++;

//シリアルモニタへの現在地の出力 (5秒毎)
if (millis()>timer1+5000){
timer1=millis();
Vout=analogRead(34)*3.3/4095;
R1=(3.3/Vout-1)*R0;
  double R=R1/R25;
  T=1/(1/B*log(R)+1/298.15);
  T=T-273.15;
  Serial.print("Current T: ");
  Serial.println(T);
}

//iftttに投稿, dt時間毎
if (millis()>timer+dt){
  timer=millis();
//LEDの点灯
digitalWrite(4, HIGH);
//read thermistor value
thermValav=thermVal/counter; //平均値を計算
Vout=thermValav*3.3/4095;
R1=(3.3/Vout-1)*R0;
  double R=R1/R25;
  T=1/(1/B*log(R)+1/298.15);
  T=T-273.15;

//ifttへのイベントに一緒に送る値
String val1=String(Vout,5);
String val2=String(R1,5);
String val3=String(T,5);

// iftttのURLを作成 (HTTPClient.hの機能を使う)
// maker.ifttt.com/trigger/{event}/with/key/{key}
String url = "http://maker.ifttt.com/trigger/";
url += event;
url += "/with/key/";
url += key;
String json;
  
// JSON データの作成
json = "{ \"value1\" : " + val1 + ", \"value2\" : " + val2 + ", \"value3\" : " + val3 + " }";  
Serial.print(json);

 HTTPClient http;   // インスタンスの生成
 http.begin(url);   // HTTP リクエストの設定
 http.addHeader("Content-Type", "application/json");   // 送信形式を JSON データに設定
 http.POST(json);   // POST リクエストで送信
 http.end();
Serial.println("_post");

//LED消す
digitalWrite(4, LOW);
counter=0; //counterとシグナル値の合計値を初期化
thermVal=0;
}
}

これまでの内容はこちら

azospiran.hatenablog.jp azospiran.hatenablog.jp azospiran.hatenablog.jp

ESP32でオンラインデータロガーを作る ②IFTTTの設定

前回の内容

azospiran.hatenablog.jp

azospiran.hatenablog.jp

温度データを獲得することができた。次にやりたいことはこのデータの保存である。 保存方法としては、

  1. SDメモリなどの外部記録媒体に保存する。

  2. クラウドにデータを保存する。

の二通りが考えられる。このご時世、SDカードなどのローカルにデータを保存していても取り出しなどが面倒であり活用の幅も制限される。そこで、Google spread sheetを活用したデータ保存方式をとった。Google spread sheetを利用する利点として、 記録時刻が正確、データ消失の心配がない、容量がほぼ無限、処理の自動化やトリガーの設定がとても簡単である事がある。 一先ず、以下の要件を満足することを目標とした。

  • データはできる限りリアルタイムでグラフとして閲覧できるようにする。
  • 以後のセンサー類の増加にも対応できる冗長性を持たせる。
  • ロギングが失敗してる場合などに通知する機能を持たせる。

このシステムの概略図

f:id:azospiran:20190804042057p:plain 取りあえずこんな感じ。シンプルにESP32はデータの収集に特化させ、少し複雑なデータ処理などはGoogle spreadsheetとscriptによって対応するようにした。通信の安定性の問題をある程度解決できると思う。IFTTTの設定をいじって対応してる人も居たが、冗長性がないとおもったので、google scriptで対応した。

IFTTTの設定

このブログはできるだけ省力運用オリジナルの方をリスペクトしているのでリンクで対応するようにている。改変したところや詰まったところを中心に特記する。

randomnerdtutorials.com

やること

  • IFTTTのアカウントを作成 (持っていない場合, 無料)
  • Webhooksの設定
  • イベントの動作確認

webhooksの設定

IFTTTのアカウントを作成が終わって、IFTTTの設定であるが基本的にはリンクを参照されたい。
This: webhooksを検索して選択。"event name"はトリガーを動作させるために必要なので適切な名前をつける。
That: google sheetを検索して選択。その後"add row to spreadsheet"を選択する。
次の設定画面だが、 sheet名はThisでつけた"event name"と同じにする。"Formatted row"は触らない。また、"Drive folder path"の内容は消して空白でOK.
これで一応設定完了。 初めてGoogle spreadsheetを利用する場合、アクセス権の確認が自動であるはず。 f:id:azospiran:20190804045830p:plain

イベントの動作確認

ホーム画面に戻り、"My services"からwebhooksの項目を開く。先ほど作ったeventが記載された画面がでてくる。ここで"Docmentation"を開くとイベントを実行するための情報が記載されている。 f:id:azospiran:20190804052618p:plain "Key"はユーザ毎に違う、且つこれが知られてしまうと外部からPUSHされてしまうため秘匿にしておく。
Make a POST or GET web request to:先ほど作ったイベントの名前を記入する。
With an optional JSON body of:ここで適当に値をだ代入する。
"Test it"で実行。自分のGoogleアカウントのGoogle driveに新しくスプレッドシートが作成され、値が書き込まれていたら成功。作成されなかった場合、設定の間違いか、Google spreadsheetへのアクセス権が上手く設定できていない可能性がるので確認する。 f:id:azospiran:20190804052603p:plain

※ Goole spreadsheetへのアクセス権の再設定

以前からGoogle spreadsheetへアクセスしていたので、今回のイベント作成時にアクセス権の確認がなかった。一方で、テストで上手く動作しないトラブルがあった。
どうも、新しいイベントを作成した際にアクセス権を更新する必要がある場合があるみたい。 f:id:azospiran:20190804055008p:plain "My services"のGoogle sheetの項目を開くと、以上の画面が出てくる。ここで"View activity log"を確認することでイベントがどういうエラーで止まったのか確認できる。アクセス権の問題みたいだったら、Account info横にある"EDIT"でIFTTTからGoogle driveへのアクセス権を再設定できる。

ESP32でオンラインデータロガーを作る ⓪ESP32へのスケッチの書き込みの準備

azospiran.hatenablog.jp

前回これを書いたのだが、その前にスケッチの書き込みに対してちょっと詰まったので簡単に記録しておく。 Arduino IDEを使って書き込んでいる。

Arduino IDEをインストールする(Mac)

ここからダウンロードしてインストール。以外とファイルサイズが大きい。お気持ちがある方は寄付してあげて下さい。 Arduino - Software

ESP32を使うためのadd-onをインストール

randomnerdtutorials.com

このサイトの通りやれば大丈夫でした。基本となるプログラムが用意されているので、wifiの情報を取得する例題を問題無く完了できればESP32を使う用意はできてます。

MacはUSBドライバーをインストールする必要

上記の方法にも記載されてますが、Macの場合はドライバーのインストールが必要(インストール後再起動)。 ツール-シリアルポート-"/dev/cu.SLAB_USBtoUART"が選択可能になってればOK. 再起動しないと出てきませんでした。 www.silabs.com

※スケッチ書き込み時に通信エラーで書き込みできない場合の対処

書き込みが不安定です。良くconnecting....がタイムアウトします。

f:id:azospiran:20190804034440p:plain
こんな感じにタイムアウト・・・
理由はちゃんと理解していないのですが、どうも初期化が上手くいかないバグのようです(この問題が発生しないボードもある?)。海外の掲示板でbootボタンを押しながら通信するとうまくいくよって書いてたのでマジかよって思いましたがマジでした・・・。

  • Connecting......の時にBootボタンを長押し(写真)

  • 暫くすると●%みたいな表示が出たら離してOK. 書き込み→rebootします f:id:azospiran:20190804034433p:plain f:id:azospiran:20190804035152j:plain

ESP32でオンラインデータロガーを作る ①Thermistorから温度の取得

Arduinoを少し前に触っていてすっかりご無沙汰だったが最近はめちゃくちゃ安いのにwifiでオンラインになるESP32というのが出てるっ知って俄然またやる気が出てきたのでポチってみた。

暫く経つと忘れるので、備忘録として残しておく。

手始めに温度ロガーを作る。取り急ぎ手元にThermistorしか無かったので、勉強も兼ねてここから温度を取得してみることにした。 Thermistorの理論や配線は以下のサイトを参照。

ESP32 - Light, Temperature, OLED! » Thoughts and stuff

サーミスタの使い方! その2( 実測編!)

10kΩの参照抵抗を付けるが、上流に着けても下流に付けても大丈夫みたい。ただ、サーミスタの抵抗値(R1)を算出する式が変わると思う。

以下がちょっと詰まった点

計算結果がおかしい

係数に値を代入する時に小数点以下を入力しなかったのが原因。最悪有効数字一桁になってdouble型でも計算が狂った。これはちゃんと勉強した人なら当たり前なことなのだろうが・・・。計算式が間違っているのかと思って時間を浪費した。

測定電圧が変・・・

入力端子をGPIO=1か0を指定したら明らかに値が変だった。どうも他用途に使われてる端子らしい。GPIO34を入力端子にしたところ解決。他にも幾つか予約済みの端子があるみたいなのでちょっと注意したいところ。ちなみにESP32は作ってるメーカやバージョンで少しピン番号も変わってるみたいなので回路図が鵜呑みにできない。

esp32_tips – スイッチサイエンス

電圧3.30V, 分解能は12 bit

Arduinoは通常10 bit?,殆どの解説ブログには電圧値を求めるときにシグナルを1024で割るように書いているが、ESP32は12 bitらしいので4095で割らないといけない。また、通常使う電圧も5Vじゃなくて3.3Vの方を基本使うらしいので式が以下の様になる(端子的には5Vもあるみたいだけど・・・)。解像度が上がってるのでデータの分解能が良かった。

thermVal=analogRead(34);
Vout=thermVal*3.3000/4095.000; //ESP

一応ちゃんと動いたコード(基本借文ですが)。マジで小数点以下の取り扱いが分からなかったので一先ず余剰にゼロを・・・。

#include<math.h>
double Vout;//出力電圧
double R1;//サーミスタ抵抗値[kΩ]
double B=4000.000; //補正係数β
double T; //サーミスタ温度 (これを求める)
double R0=10.000; //参照抵抗[kΩ]小数点以下まで指定
double R25=10.000; //25°Cの時の抵抗

void setup() {
Serial.begin(115200);
pinMode(34, INPUT); //GPIO34を入力端子
}

void loop() {
double thermVal;
//read thermistor value
thermVal=analogRead(34);//シグナル値取得
Vout=thermVal*3.3000/4095.000; //ESP32Ver.電圧に変換
R1=(3.3000/Vout-1)*R0; //サーミスタの電圧を求める I=V/R
double R=R1/R25;
T=1/(1/B*log(R)+1/298.1500);//温度を計算
T=T-273.15;//ケルビンからセルシウス度
//以下出力
Serial.print("Thermistor reading: ");
Serial.println(thermVal);
Serial.print("Vout: ");
Serial.println(Vout);
Serial.print("R1: ");
Serial.println(R1);
Serial.print("T: ");
Serial.println(T, 5); 
Serial.print("B: ");
Serial.println(B);
Serial.print("R: ");
Serial.println(R);
delay(2000) ;//2秒休み
}

f:id:azospiran:20190801013419j:plain
雑な写真で申し訳ない
次はWi-Fi接続とGoogle spread sheetへの投稿に関して書く予定です。