工作と競馬2

電子工作、プログラミング、木工といった工作の記録記事、競馬に関する考察記事を掲載するブログ

C言語JSONライブラリparsonの使い方 自分用覚書

背景と目的

Arduinoで、JSONを扱いたかったため、parsonというC言語ライブラリを使用した。使い方を自分用にメモする。



使いそうなものを列挙

空の状態"{}"に、データを追加していき、シリアライズするまで、おおむね使いそうなものを列挙。

#include "parson.h"

:

// ルートValueを作成
JSON_Value *rootValue = json_value_init_object();

// ルートObjectを取得
JSON_Object *rootObj = json_object(rootValue);

// 文字列を追加
json_object_set_string(rootObj, "string", "hello");
// 数値を追加
json_object_set_number(rootObj, "number", 1.01);
// ブール値を追加
json_object_set_number(rootObj, "bool", 1);

// 配列を追加 -----------------------------------------------
// 配列Valueを作成
JSON_Value *arrayValue = json_value_init_array();
// JSON_Arrayを取得
JSON_Array *arr = json_value_get_array(arrayValue);
// 配列要素を追加
json_array_append_number(arr, 2.02); // 数値
json_array_append_string(arr, "hello, array."); // 文字列
JSON_Value *objValue = json_value_init_object(); // オブジェクト(空)
json_array_append_value(arr, objValue);
JSON_Value *arrayValue2 = json_value_init_array(); // 配列(空)
json_array_append_value(arr, arrayValue2);
// rootObjに追加
json_object_set_value(rootObj, "array", arrayValue);

// シリアライズ
char *jsonString = json_serialize_to_string(rootValue);
Serial.printf("jsonString=%s\n", jsonString);


シリアライズした結果は、以下。

jsonString={"string":"hello","number":1.01,"bool":1,"array":[2.02,"hello, array.",{},[]]}

参考

https://github.com/kgabis/parson/blob/master/parson.h

家庭菜園の成長記録用カメラの製作(1) --- 構想と設計 ---

概要

家庭菜園の成長記録用カメラの構想と設計を行った。



背景と目的

先日、自動水やり器 ver2では、以下の図のように成長記録用のカメラもシステムに加える構想を考えていた。そして、構想実現のための基礎検討として、こちらの記事で試作を行い準備が整った。そのため、いよいよ本製作に着手する。

aaa



詳細

1. 基本構成

試作を踏まえ、以下の構成とする。

  • カメラモジュール: OV2640
  • マイコン: ESP32-WROVER-E
  • ネットワーク接続: Wi-Fi
  • 基本動作: 定期撮影&クラウド送信
  • 電源: ソーラー+リチウムイオン電池
    • 自動水やり器 ver2と共用する
  • 筐体: 簡易な防水仕様とする
    • ベランダ菜園等に設置し、激しい雨がかからない想定

なお、撮影のターゲットは、

しそのプランター

である。


2. 電気回路

※2021/06/25記述と回路図を修正

基本的に試作と同じ構成だが、待機電力を抑えるのための変更として、

  • OV2640の電源を切れるようにPWDN端子をESP32のIO33に配線
  • 暗電流の小さいレギュレータNJU7223を使用

を行う。また、

  • RST端子をIO4に配線

した。試作の時は直接3.3Vに接続していたが、本来はGPIOでコントロールできるように配線するべきだと思うので。 なお、レギュレータは飽和電圧が小さいので、リチウムイオン電池の電圧が下がってきてもある程度粘ってくれるはず。(Wi-Fiを使うESP32では、NJU7223の出力電流が結構ぎりぎりの気がして心配だったので、事前に動くか確かめておいたが、まあちゃんと動いたので、問題ないだろう。)

f:id:dekuo-03:20210625004646p:plain


3. 筐体

今回はベランダでの使用を想定しているので、直射日光や激しい雨はある程度防げる前提で簡易な防水ができればよい。したがって、あまりお金をかけず100均のタッパとする。液漏れをある程度防げるものであればよいだろう。



まとめと今後の課題

家庭菜園の成長記録用カメラの構想および設計ができた。次回は、電気回路、筐体等のハードウェア製作に取り掛かる。


numpy自分用覚書

自分用numpyメモ。

import numpy as np
x = np.array([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])

スライス

>>> z = np.arange(0, 10)
  • z[start:stop]

start番要素からstop-1番要素まで。

>>> z[3:5]
array([3, 4])
  • z[start:stop:step]
>>> z[3:7:2]
array([3, 5])
  • z[start::step]

指定しなければ、先頭または末尾。

>>> z[3::1]
array([3, 4, 5, 6, 7, 8, 9])

keepdims

配列の次元数を保持する。

>>> y1 = np.sum(x, axis=1, keepdims=True)
>>> y1
>>> array([[ 6],
           [15],
           [24]])
>>> y2 = np.sum(x, axis=1)
>>> y2
>>> array([ 6, 15, 24])


reshapeの引数に-1を指定

自動的に、要素数を計算してくれる。当たり前だが、2つ以上指定してはだめ。

>>> x2 = x.reshape(1, -1)
>>> x2
array([[1, 2, 3, 4, 5, 6, 7, 8, 9]])
>>> x3 = x.reshape(-1, 1)
>>> x3
array([[1],
       [2],
       [3],
       [4],
       [5],
       [6],
       [7],
       [8],
       [9]])
>>> x4 = x.reshape(-1)
>>> x4
array([1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> x5 = x.reshape(-1, -1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: can only specify one unknown dimension

dot

ベクトルの内積または行列の積を計算する。内積はドット記号を使うので、dotという名前の関数になっていると思われる。通常の * は、要素同士の積(アダマール積)。

>>> y = np.dot(x[0], x[:, 0])
>>> y
30
>>> y = np.dot(x, x)
>>> y
array([[ 30,  36,  42],
       [ 66,  81,  96],
       [102, 126, 150]])

pad

ある値でパディングを行う。第2引数でパディングのサイズ、形状を指定。

全次元の先頭、末尾に同じだけパディング。

>>> np.pad(x, 2, "constant", constant_values=1)
array([[1, 1, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 1, 1],
       [1, 1, 1, 2, 3, 1, 1],
       [1, 1, 4, 5, 6, 1, 1],
       [1, 1, 7, 8, 9, 1, 1],
       [1, 1, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 1, 1]])
  • 1つのタプルを指定

各次元の先頭と末尾に対応。

>>> np.pad(x, (1,2), "constant", constant_values=1)
array([[1, 1, 1, 1, 1, 1],
       [1, 1, 2, 3, 1, 1],
       [1, 4, 5, 6, 1, 1],
       [1, 7, 8, 9, 1, 1],
       [1, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 1]])
  • 2つのタプルのリストを指定

リスト要素が各次元に対応。タプルの要素順はその次元の先頭、末尾パディングサイズに対応。 np.pad(x, [(0,0), (0,0), (pad, pad), (pad, pad)], "constant", constant_values=1)

>>> np.pad(x, [(0,2), (1,3)], "constant", constant_values=1)
array([[1, 1, 2, 3, 1, 1, 1],
       [1, 4, 5, 6, 1, 1, 1],
       [1, 7, 8, 9, 1, 1, 1],
       [1, 1, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 1, 1]])

repeat

繰り返し同じ要素の配列生成する

>>> x.repeat(3, axis=0)
array([[1, 2, 3],
       [1, 2, 3],
       [1, 2, 3],
       [4, 5, 6],
       [4, 5, 6],
       [4, 5, 6],
       [7, 8, 9],
       [7, 8, 9],
       [7, 8, 9]])
>>> x.repeat(3, axis=1)
array([[1, 1, 1, 2, 2, 2, 3, 3, 3],
       [4, 4, 4, 5, 5, 5, 6, 6, 6],
       [7, 7, 7, 8, 8, 8, 9, 9, 9]])

random

np.random.permutation

ランダムに並べて返す

# 整数をランダムに並べて返す
>>> np.random.permutation(10)
array([9, 1, 5, 8, 3, 0, 4, 7, 2, 6])

# 配列aをランダムに並べて返す
>>> a = [1,2,3,4,5,6]
>>> np.random.permutation(a)
array([3, 4, 6, 2, 1, 5])

np.random.choice

指定した数だけランダムに選んで返す 標準モジュールrandomのchoiceとは引数構成が違うので注意。

# aは1次元のシーケンス(配列)とする

# aから1つの要素を選択
np.random.choice(a)

# aから2個選択
np.random.choice(a, size=2)
# (2,3)のタプルが返り値
np.random.choice(a, size=(2,3))

# 重複有無(replace)
np.random.choice(a, size=3, replace=True) # 重複あり
np.random.choice(a, size=3, replace=False) # 重複なし

# 選択確率(p)
# 長さがaと同じで合計1となるリストにすること
np.random.choice(a, 3, replace=False, p=[0.1, 0.1, 0.3, 0.3, 0.1, 0.1])

empty

配列を初期化せずに確保する。

# np.empty(shape, dtype=float)
>>> np.empty((3,3))
array([[0.000e+000, 0.000e+000, 0.000e+000],
       [0.000e+000, 0.000e+000, 1.877e-321],
       [0.000e+000, 0.000e+000, 0.000e+000]])
>>> np.empty((3,3), dtype=np.int32)
array([[1697542254, 2037674093,  741550120],
       [ 539765043, 1887007844, 1886272869],
       [1953392942,  220803635,         10]])

zeros_like

引数の配列と同じ形のゼロ配列を作る。

>>> a
array([[0.3720223 , 0.49858174, 0.79575115],
       [0.32627888, 0.57125729, 0.25105339],
       [0.32911995, 0.5271041 , 0.78931682]])
>>> np.zeros_like(a)
array([[0., 0., 0.],
       [0., 0., 0.],
       [0., 0., 0.]])

自動水やり器 ver2 --- (2)製作、完成 ---

概要

自動水やり器の製作を行い、無事完成した。



背景と目的

前回の設計に従い、製作を行い、完成させる。



詳細

1. 回路基板の作成

以下のように、ver1と同様に、ベースとなる木の板に対して、マイコン(ESP32)が載ったメインの基板、リチウムイオン電池充電回路基板、リレーモジュール基板を固定した。

f:id:dekuo-03:20210530230344j:plain

なお、リレーモジュールの背面には、モータ負荷をスイッチングする関係上逆起電力を抑えるためのフライホイールダイオードを装着した。

f:id:dekuo-03:20210530231425j:plain


2. 貯水ボトルとポンプ

4チャンネル化したため、ポンプも貯水ボトルに4つを固定した。水位センサは従来同様。

f:id:dekuo-03:20210530230500j:plain


3. 筐体

回路基板を収納する筐体は、リングスターのスーパーピッチシリーズSP-1500F。簡単な防水施工として、蓋の接触部分にエプトシーラー10mm幅×10mm厚を1周貼った。本当は防水ボックスを使用したいが、まああまり雨もかからない場所に置くのでこの程度。下に飛び出ているスペーサは、後述の固定用ネジ穴。

f:id:dekuo-03:20210530230720j:plain


そして、貯水ボトルと筐体の底面から出ているスペーサを、アングルにネジでそれぞれ固定して全体は完成。

f:id:dekuo-03:20210530230921j:plain


4. ソフトウェア

全体処理は、前回と同様なので詳細は割愛するが、1点だけWi-FiとADC2の同時使用に関して注意点があった。 ESP-WROOM-32は、Wi-Fiを使用するときは、ADC2が使用できない。なので、今回のシステムでは、土壌水分センサの入力として使用しているIO25、IO26、IO27は、Wi-Fiを有効化してしまうと使用できなくなるので、

  • 土壌水分センサの値を読み取ってから、Wi-Fiを有効化する

という順序で処理することにした。今後、クラウド側からの指示を受けて動作させるようにしたい場合などは、センサ値読み取り前にWi-FiをONせざるを得ない状況がありそうなので、その場合どうしようか悩む。


5. 設置した様子

以下の通り、設置し動作することを確認した。ブルーベリー(黒の鉢)、ベゴニア(白の鉢)と、先日種まきをしたしそにそれぞれみずやりができる。しそは細長いのでセンサとポンプそれぞれ2ch分を割り当てている。(実際は、1系統でも十分かもしれないが。)

f:id:dekuo-03:20210530235216j:plain



まとめと今後の課題

自動水やり器 ver2が無事完成した。家庭菜園が捗りそうだ。


しそを育てる(1) --- 材料調達と種まき ---

概要

しその種まきを行った。



背景と目的

昨年製作した自動水やり器は、そこそこうまく稼働してくれている。そのおかげか、自動で水やりをしていたブルーベリーが結構ちゃんと育っている。なので、他にも育てたいなと思い始めた。そして、せっかくなら食べられるものがよいので、いろいろ検討した結果、ちょうど今の時期に初心者でも育てやすいらしく、しかも夏場に麺類の薬味などで使う場面が多い しそ を育てることにした。早速、材料を調達し種をまく。



詳細

1. 材料調達

1.1 プランター

サイズはおよそ45cm * 20cm * 20cm程度。種まきの間隔から2つか3つくらいの苗が育てられる大きさ。ホームセンターで300円程度の格安のモノ。これに合わせて、受け皿も購入。

f:id:dekuo-03:20210523222837j:plain

1.2 種

種は、以下。これもホームセンターで購入。150円程度。

https://www.amazon.co.jp/%E6%98%A5%E8%92%94%E3%81%8D-%E6%9C%89-%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%95%E3%82%A7%E3%83%BC%E3%82%B9-%E9%9D%92%E3%81%97%E3%81%9D%E5%A4%A7%E8%91%89-324/dp/B00EQ398MI/ref=sr_1_8?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=%E3%81%97%E3%81%9D+%E3%82%BF%E3%82%AD%E3%82%A4&qid=1621776284&sr=8-8

1.3 土と肥料

これもホームセンターで購入。土は、300円程度と安かったが肥料の方は700円くらい。

f:id:dekuo-03:20210523222854j:plain f:id:dekuo-03:20210523222902j:plain

1.4 プランター

プランターを置くため、プランター台も必要。以前作成したプランター台は、すでにほかの植木鉢で埋まっているので、これを機にもう1台増設することにした。非常にローコストで丈夫なものができるので、我ながらなかなかよい設計だったと改めて実感。


2. 種まき

2.1 土を入れる

鉢底石、培養土の順で入れる。

f:id:dekuo-03:20210524211546j:plain

2.2 種を水に浸す

種の袋の裏に、1昼夜水に浸せと説明が書いてあったのでその通り、水に浸した。

f:id:dekuo-03:20210524211551j:plain

2.3 種をまく

約14cm程度の間隔で3か所に蒔いた。種と土の色が同化していて、一度土の上に置くとどこに置いたか全くわからなくなるのが難点。参考リンクには、1か所に4粒の種を植えろとあった。これは、種の発芽率60%とすれば4粒なら1つも発芽しない確率は、

となってほぼ発芽すると考えられる。しかし、より確実にするため6粒にしておいた。これでもしも発芽しなかったら、自分のやり方がよほど悪いのだろう。

最後に、水をたっぷりあげて完了。発芽まで1~2週間くらいかかるらしいので、それまで日当たりのよい場所に置いて毎日水やりする。

f:id:dekuo-03:20210524211537j:plain



まとめと今後の課題

しその種まきができた。無事発芽してくれることを祈る。


自動水やり器 ver2 --- (1)構想、設計、材料調達 ---

概要

ソーラー発電式自動水やり器の新バージョンについて、構想を整理した。



背景と目的

昨年8月に製作した自動水やり器1は、多少トラブルはあったものの、これまでの約9か月間そこそこうまく稼働してくれた。しかし、作成したものは土壌水分センサと給水ポンプが1系統しかないため、1つのプランターにしか水やりができていない。そして、今年はベランダ菜園を始めようと企んでいる。そこで、同時にいくつかのプランターに水やりができるバージョン2を製作する。



詳細

1. 構想

いろいろ考えた結果、基本的な仕組みはバージョン1を引き継ぐとして、

  • 土壌水分センサと給水ポンプは4系統にして、別々のプランターに給水できるようにする

ことにした。また、成長記録用に、別途カメラを設置し、定期撮影することを考えている。(別途製作予定)

f:id:dekuo-03:20210523220203p:plain f:id:dekuo-03:20210523220200p:plain


2. 設計

以下のように昨年の回路を少し変更して4系統に拡張。

f:id:dekuo-03:20210531000440p:plain


3. 材料調達

3.1 給水ポンプと土壌水分センサ

昨年は単品で購入したが、Amazonにまさに4系統分がまとまったセットが売っているので、それを使う。

www.amazon.co.jp

リレーモジュールは、写真と違う型番が実装されていたのが納得いかないが、試しに動作させたところ同じ仕様のようだったので、まあ問題ない。それと、以前と同じく小型ポンプは1つ多く入っていた。よほど不良率が高いのだろう。(実際、私の手元に届いた5つのうち1つは動きが明らかにおかしかった。)

3.2 ケース

電子基板本体を収める部分が一回り大きくなるので、今回はリングスターのスーパーピッチシリーズSP-1500Fにする。防水機能はないので、自分で防水施工する。(ベランダの雨がかかりづらい部分に置くので、厳密でなくてもよい)

www.ringstar.co.jp

3.3 貯水ボトル

前回のモノを流用する。



まとめと今後の課題

自動水やり器 ver2の構想、設計、材料調達ができた。次回は製作を行う。


Lookout for Equipmentで、推論(inference)対象となるCSVファイルの名前と内容について

はじめに

Lookout for Equipmentで、inference scheduleを作成して、推論対象となるCSVファイルをS3に置こうとしたのだが、csvファイルの名前と内容をどうすればよいかわからず、失敗しまくったのでメモる。

※公式ドキュメントをいくら見ても載っていない。(今後記載されるかもしれないが。)

What is Amazon Lookout for Equipment? - Amazon Lookout for Equipment


ファイル名

{ComponentName}{delimiter}{Timestamp}.csv

# 例
# ComponentName = Pump1
# delimiter = _ (アンダーバー)
# Timestamp = 2021/05/20 11:30

Pump1_20210520113000.csv
  • {ComponentName}

下の画像のPump1に相当する。

f:id:dekuo-03:20210520114909p:plain

  • {delimiter}

    Inference scheduleを作成する際に入力するdelimiterに対応する。

f:id:dekuo-03:20210520114848p:plain

  • {Timestamp}

    Inference scheduleを作成する際に入力するTimestamp formatに従ったタイムスタンプ。

読み取り対象のファイル

推論の対象となるファイルは、実行時刻から実行周期分を引いた時刻のタイムスタンプを持つファイル。

例を挙げると、

  • 実行時刻 = 2021/05/20 11:35
  • 実行周期 = 5分

→ 2021/05/20/ 11:30のファイルが対象となる。すなわち、

Pump1_20210520113000.csv

が読み取られる。

f:id:dekuo-03:20210520115104p:plain


ファイルの内容

基本的に、学習に用いたものと同じ形式でよい。

  • 実行時刻 = 2021/05/20 11:35
  • 実行周期 = 5分

であれば、Pump1_20210520113000.csvには、

2021/05/20 11:30 ~ 2021/05/20 11:34:59

までのデータを記載しておく。

f:id:dekuo-03:20210520114744p:plain


参考資料