傾斜計 カルマン・フィルタ アルゴリズムの解きほぐし ー倒立振子への道 2ー

前回トラ技を参考に作ったM5stickCを用いた傾斜計ではカルマン・フィルタの効能を堪能しただけで、そのカルマン・フィルタが何をしているかはすっ飛ばして見てみぬフリをしておりました。

カルマン・フィルタで M5stickC 傾斜計 ー倒立振子への道 1ー

ここでは前回用いたコードのカルマン・フィルタ アルゴリズムを少し解きほぐし何をしているのかをみてみたいと思います。

しかし内容がかなり難しくここでも様々な点をすっ飛ばさなくてはなりません。カルマン・フィルタが制御工学や統計学など様々な基礎学問の上に成り立っているからです。

でも気にしてはいられません。この道の目的はM5stickCを用いたオリジナルの倒立振子の実現です。今から統計や制御理論を1から学ぶのは得策ではありません。挫折するに決まっています(お父ちゃんの場合)。

漫画家見習いが鉛筆の素材の木を植えるところから始めるわけにはいかないのですから。

 

 

傾斜計コード

前回のコードを改めて記載いたします。

トラ技のソースコードInclinometer.cppをほぼ丸々参考にしています(p. 49 – 52)。

ここではカルマン・フィルタ アルゴリズム処理 update_theta()を解きほぐします。

カルマン・フィルタの概要

カルマン・フィルタは”センサの測定値”と”モデルから算出した予測値”を元に真値を推定するフィルタです。下は傾斜計の場合のブロック図です。

実際どういった処理を施して傾斜角の推定値を得ているのかコードより解きほぐしてみましょう。

まずはフィルタに導入する測定値と予測値についてみていきましょう。

センサによる測定値

M5stickCに内蔵されている6軸の慣性センサ(加速度、ジャイロ) SH200Q を使用して傾斜角と角速度を測ります。

傾斜角θは加速度センサから重力加速度の傾きを検出して導出します。

角速度はジャイロセンサの値(x軸)をそのまま使用します。

数理モデルによる予測値

予測値を得るために物理現象を記述する式(数理モデル)を立てます。

傾斜角の関係式は以下の通りです。

$$θ_{k+1} = (ω_k – ω_{offset})・Δt + θ_k$$

$θ_k $は時刻kのときの傾斜角で$ω_k $は時刻kのときの角速度です。$w_{offset}$は角速度のオフセット誤差です。
時間kのときの角速度に微小時間$Δt $(コードでは2.5msec)をかけて$θ_k $を足すと$Δt $後(時間 k+1)の傾斜角$θ_{k+1}$が得られるということを示しています。

またここで簡単のため角速度(ジャイロセンサ)のオフセットは時刻によらず一定と仮定します。

$$ω_{offset}(k+1) = ω_{offset}(k)=ω_{offset}$$

ここですっ飛ばしブチかましますが、現代制御理論では数理モデルを行列で表現する習わしがあるそうです。

状態方程式

物理状態の移り変わりを示すのが状態方程式です。上記2式より以下で表せます。

$$\left( \begin{array}{c}  θ_{k+1}\\ ω_{offset} \end{array} \right)=\left( \begin{array}{cc}  1&-Δt\\0&1 \end{array} \right)\left( \begin{array}{c}  θ_{k}\\ ω_{offset} \end{array} \right)+\left( \begin{array}{c} Δt\\ 0 \end{array} \right)ω_k$$

一般式では以下のように書きます。

$$x_{k+1}=A・x_k+B・u_k$$

ここでの物理状態$x$ ($θ_k$と$ω_{offset}$)は行列Aをかけて2項目の入力$ω_k$(角速度)に関する値を足すと次の状態があられることを示しています。

出力方程式

物理状態で実際に観測できる状態(値)を示す行列式です。

$$θ_k=\left( \begin{array}{cc} 1&0\end{array} \right)\left( \begin{array}{c}  θ_{k}\\ ω_{offset} \end{array} \right)$$

$θ_{k}$だけがセンサから直接得られることを示しています。$ω_{offset}$だけを得ることはできませんのでね。

一般式は以下で書きます。

$$y_k=C・x_k$$

以上で数理モデルが用意できました。また行列A, B, Cは時間依存のない定数でした。

 

カルマン・フィルタ アルゴリズム

やっとコードのカルマン・フィルタ アルゴリズムupdate_theta()が何をやっているかをみてみます。かなりすっ飛ばします。とにかくここではコード上でどんな処理をしているかをみるのが目的です。よく理解できないし。。ここでは丸飲みします。

update_theta()は以下の5つの処理を実行しています。

  1. カルマン・ゲイン$G_k$の算出
  2. 現時点kの推定値$\hat x_k$の算出
  3. 現時点kの共分散行列$P_k$の算出
  4. 次時刻k+1の予測値$\tilde x_{k+1}$の算出
  5. 次時刻k+1の共分散行列$P’_{k+1} $の算出

1. カルマン・ゲイン算出

カルマン・ゲイン$G_k$とはモデルによる予測値$\tilde x_k$とセンサによる測定値$y_k$を混ぜ合わせて推定値$\hat x_k$を求める際の重みづけ配分比を意味します。

そして詳細は分かりませんが$G_k$は以下の式で得られます。

$$G_k=P’_k C^T(W + C P’_k C^T)^{-1}$$

   $P’_k$:前時刻に算出された共分散行列(5. で算出)
   $C^T$:出力方程式の係数行列C = $\left( \begin{array}{cc} 1&0\end{array} \right)$の転置。つまり$\left( \begin{array}{c} 1\\0\end{array} \right)$
   $W$:観測雑音の程度を表す量。つまり加速度センサによる角度の分散(theta_variance)

2. 推定値算出

前時刻に算出された予測値(4. で算出)$\tilde x_{k}$と測定値$y_k = θ_{k}$からカルマン・ゲイン$G_k$を絡めて推定値$\hat x_k$を求めます。

$$\hat x_k=\tilde x_k+G_k(y_k – C \tilde x_k)$$

3. 共分散行列算出

共分散行列とはデータをxとyとすると$\left( \begin{array}{cc}  {σ_x}^2 & {σ_{xy}}^2\\ {σ_{xy}}^2 & {σ_y}^2\end{array} \right)$で表されます。

要するにデータをxとyの変動の相関を表します。
データxとyに相関がない場合は分散$ {σ_{xy}}^2 = 0$となります。

物理状態$θ_k$の共分散行列$P_k$は以下で表されます。例によってなんでかは知りません。

$$P_k = (I_2 – G_k C) P’_k$$

   $I_2$:2行2列の単位行列$\left( \begin{array}{cc} 1&0\\0&1\end{array} \right)$
   $G_k$:カルマン・ゲイン
   $C$:出力方程式の係数行列C = $\left( \begin{array}{cc} 1&0\end{array} \right)$
   $P’_k$:前時刻に算出された共分散行列(5. で算出)

4. 次時刻の予測値算出

モデルを用いて次時刻k+1の傾斜角予測値$\tilde x_{k+1}$を算出します。

$$\tilde x_{k+1} = A \hat x_k + B \bar u_k$$

   $A$:状態方程式の係数行列$\left( \begin{array}{cc}  1&-Δt\\0&1 \end{array} \right)$
   $B$:状態方程式の係数行列$\left( \begin{array}{c}  Δt\\0\end{array} \right)$
   $ \hat x_k$:現時刻の傾斜角推定値(2. で算出)
   $ \bar u_k$:入力(角速度)の平均。ここでは現時刻の角速度測定値$ω_k$で近似。

5. 次時刻の共分散行列算出

これもよくわかりませんが次時刻k+1の共分散行列は以下で得られます。

$$P’_{k+1} = A P_k A^T + B U B^T$$

   $P_k$:現時刻に算出された共分散行列(3. で算出)
   $U$:入力雑音の程度を表す量。つまり角速度の分散(theta_dot_variance)

カルマン・フィルタの初期設定

カルマン・フィルタの処理は前回算出した予測値と共分散行列を用いて推定を行います。常に前のデータを必要とするので最初に起動(k=0)する際には手動で初期値を指定する必要があります。

アルゴリズムの4. と5. で算出する次時刻の予測値が時刻0の時点ではないのであらかじめそれらしい値を決める必要があるということです。

コードでは初期の傾斜は直立であると条件付けして初期値を与えています。

状態予測値の初期設定

$\tilde x_0 = \left( \begin{array}{c}  θ\\ ω_{offset} \end{array} \right)  = \left( \begin{array}{c}  0\\ \bar ω \end{array} \right)$

直立を仮定しているため $θ = 0$、 動かしていないと仮定して$ω_{offset}$をジャイロの平均値としています。

共分散行列の初期設定

$P’_{0} =\left( \begin{array}{cc}  {σ_θ}^2&0\\0&{σ_{ω_{offset}}}^2 \end{array} \right) =\left( \begin{array}{cc} 1&0\\0&{σ_ω}^2 \end{array} \right)$

角度のばらつきは1°程度と想定し、$ω_{offset}$のばらつきはジャイロの測定値のばらつきとしています。傾斜角と$ω_{offset}$に相関はないので対角の値は0です。

初期値の値は多少ずれがあっても時刻が進み測定データが増えると推定値は真値付近に収束するようです。

 

おわりに

傾斜計コードで使用したカルマン・フィルタ アルゴリズムの処理内容を追いかけました。

数式などは分からないことが多々ありますが、確かにその処理をしていい感じの結果を得ているのです。

とにかくカルマン・フィルタ アルゴリズムを飲み込んで数理モデル方程式を立てて初期値の設定をそれらしく実施すればよいとのことなので応用が利くことでしょう。

さて次は倒立振子に向けて動きたいと思います。

日射量データベースから太陽光発電量を算出 ーベランダ太陽光発電所への道6ー

我が家のベランダは西向きであまり日照時間が長くなく、それに伴い発電も主に午前中に実施されることがわかっています(6:00~11:00)。

発電したい電力量がわかっていて、設置場所の日射量がわかっていれば、どのくらいのサイズのソーラーパネルを購入すればいいかが前もって見積もれます。

各地の日射量はデータベースとして公開されていますのでここでは日射量から発電量を見積もる方法を紹介します。

 

 

日射量データベース

国立研究開発法人NEDOは各地の各種日射量データベースを公開しています。

https://appww2.infoc.nedo.go.jp/appww/index.html

  • 年間時別日射量データベース(METPV-11)
    各地の時間、方角、パネル傾斜角度による日射量(M J /$m^2$)が算出できる
     
  • 年間月別日射量データベース(MONSOLA-11)
    各地の方角、パネル傾斜角度による月間平均総日射量(kWh /$(m^2・day)$)が算出できる
     
  • 全国日射量マップ
    射量データを日本地図上にマップ化したものを表示

発電量算出

ここでは年間月別日射量データベース(MONSOLA-11)を用いて一日当たりのソーラーパネル発電量を見積もってみたいと思います。

データベースにアクセスしてMONSOLA-11を選択。場所は札幌にします。

 

表示データ選択で年変動を選択すると月別、年平均、季節別の日射量の最大値、平均値、最小値が表示されます。

パネルの方角や設置角度によって日射量がかわるために最大最小の振れ幅があります。

札幌の場合、年平均で3.37kWh /$(m^2・day)$の日射量となります。つまり1日当たり1$m^2$の敷地に3.37kWhの太陽エネルギーが降る注ぐのです。

ソーラーパネルの定格出力は1kW /$(m^2)$の光を照射したときに出力される電力量を示しています。JISかなんかの規格で決まっているようです。

つまり12Wのソーラーパネルは1kW /$(m^2)$の光を照射すると12W出力します。

発電量算出

発電量は以下の式で算出できます。

 発電量 = 日射量 × ソーラーパネル定格出力 × 損失係数

   損失係数はソーラ定格出力の誤差などで一般的に75%程度で考えるようです。

 

例えば12Wのソーラーパネルを札幌に設置して得られる年平均の発電量を見積もると

発電量 = 3.37kWh /$(m^2・day)$ × $\left(\frac{12W}{1kW /(m^2)}\right)$ × 0.75 = 3.37 h/day × 12W × 0.75 = 30.3 Wh/day

年平均で1日30.3Whの電力の発電が見込めるというわけです。

その他表示データ

表示データを角度指定にするとパネルの方角や傾斜角が指定できそれぞれの日射量がグラフに出力されます。

例えばパネルを西向きにすると上図のようにパネル角度による月別、年平均、季節別の日射量が表示されます。

冬は太陽が低いのでパネルの角度依存は小さいなど様々な情報を得ることができて設置方角や角度の決定に大いに参考になることでしょう。

 

 

おわりに

ここでは日照量データベースから発電量を算出する方法を紹介しました。データベースを使用すれば必要発電量からパネルの定格出力や台数を見積もることもできるでしょう。また設置角度や方角も前もって設計が可能となります。

非常に便利なデータベース。賢く利用したいものです。

 

 

 

カルマン・フィルタで M5stickC 傾斜計 ー倒立振子への道 1ー

今月のトランジスタ技術が非常に興味深い内容でした。

 

確率統計コンピューティング特集ということでカルマン・フィルタの歴史とカルマン倒立振子の作り方を非常に丁寧に紹介しています。

必要な数学や力学の基礎も記載されておりロボット制御の入門として最適なのではと思います。DVDでのセミナーも易しくありがたい限りです。


確率統計コンピュータ - toragi.cqpub.co.jp

はっきり言ってお父ちゃんはカルマン・フィルタとは何ぞやというレベルで全く知識のない状況です。そこで倒立振子への道と題してM5StickCを用いた倒立振子の実現を目指して一歩ずつお勉強していこうと思います。

ここではトラ技のコードを参考にカルマン・フィルタを用いた傾斜計を作ってみたいと思います。カルマン・フィルタの素晴らしさをまずは体験してみようと思います。

 

 

M5stickC

M5stickCには6軸の慣性センサ(加速度、ジャイロ) SH200Q が内蔵されていますので、このセンサ値を用いてM5stickC自身の傾きを算出してみます。

6軸センサ SH200Q

SH200Q データシート
 https://github.com/m5stack/M5-Schematic/blob/master/Core/SH200Q.pdf

SH200QのArduino IDEサンプルコードは以下にございます。
 https://github.com/m5stack/M5StickC/blob/master/examples/Basics/SH200I/SH200I.ino 

M5StickCのXYZ軸方向は以下の通りです。

参考:144Labグループ開発者ブログ

センサのデフォルトの設定は以下の通りです。

  • 加速度:16bit ±8 g
  • ジャイロ(角速度):16bit ±2000 deg/sec

 

上の写真のようにM5stickCを置いてSH200Q のサンプルコードを動かすとSH200Qから出力されるデータは以下のようになるはずです。

  • 加速度:AccX = 0,  AccY = 0, AccZ = 4096(+1g)
  • 角速度 : GyroX = 0, GyroY = 0, GyroZ = 0

しかしセンサのオフセットのため実際に出力される値にはずれがありましたので、今回はあらかじめオフセットを測って引いて使用します。

カルマン・フィルタを用いた傾斜計に関してはセンサのデフォルトオフセットの影響はないかもしれませんが今回は生データとの比較も行いたいのでオフセット引いております。

カルマン・フィルタによる傾斜導出の概要

ここではカルマン・フィルタの詳細理解はすっ飛ばして とにかく使ってみてご利益を実感するのを目的としています。ですので詳細はトラ技や他に譲るとしてざっくりとした概要です。

カルマン・フィルタは測定値と数理モデルによる予測値をうまいこと利用してもっともらしい傾斜角を導出します。

加速度センサによる角度

重力加速度のY軸、Z軸の成分よりM5stickCの傾斜角θは以下の式で求められます。

$$θ = tan^{-1}\left(  \dfrac{g_z}{-g_y} \right)$$

しかし加速度センサは振動などの重力加速度以外の加速度も検出してしまう問題があります。

ジャイロセンサによる角度

ジャイロセンサのx軸の角速度$ω_x$を時間積分することでM5stickCの角度を求めることができます。

しかしジャイロは初期姿勢の角度は検出できません。さらにセンサ測定値にはオフセット誤差が含まれるので誤差も積分されて増幅していきます。

モデルによる予測

上記のそれぞれ短所をもった測定値とそのバラつき誤差を加味した数理モデルをつくって傾斜角度の予測値を算出します。

測定バラつきとして予めセンサを複数回測定(ここでは100回)して分散を求めます。

モデルの詳細はまだ理解できてないので割愛します。いつか理解できるその日まで。。。

カルマン・フィルタのアルゴリズム

上記の測定値とその分散そして数理モデルによる予測値をうまいこと用いて角度の推定値を得ます。

内容は全く分からないので後に回します。トラ技紙面に譲ります。。今は分からない。。。今は。。。

傾斜計コード

Arduino IDEをもちいでカルマン・フィルタM5stickC 傾斜計を作製しました。比較のために加速度センサによる傾斜角とカルマン・フィルタによる推定値を出力します。

トラ技のソースコードInclinometer.cppをほぼ丸々参考にしています(p. 49 – 52)。

 

やってることの概要は以下の通りです。

  • センサばらつき算出:加速度とジャイロセンサを100回測って予め分散を導出
  • カルマン・フィルタの初期設定:使用する行列パラメータの初期値設定
  • タイマ割り込み(2.5msecごと)でカルマン・フィルタアルゴリズム発動させて傾斜角の推定値を算出
  • 50msecごとに加速度センサによる傾斜角とカルマン・フィルタによる角度の推定値をシリアル出力

カルマン・フィルタアルゴリズムについての詳細はしつこいですがトラ技紙面か以下の動画を参照ください!

 

 

動作

青線:M5stickCの加速度センサから算出した傾斜角で
赤線:カルマン・フィルタによる角度の推定値

 

最初の感想は”凄い!”でした。振ると当然 加速度の外乱が入るので、加速度センサによる角度(青線)は乱れますがカルマン・フィルタによる角度の推定値(赤線)に大きな乱れはありません。

しかも加算平均とかではなくあくまでリアルタイムのセンサ値と前回算出した予測値で算出されているようなのです。

なんかすごいね。。理解できないけど。

 

今回スタートした 倒立振子への道 。どうなるものか。たどりつけるのか。

全くの未知ですが 今回カルマン・フィルタのご利益を全身で堪能出来て興奮気味なので頑張りたいです!!

M5StickC でスマートな電池を作製 M5Stick-Cell

ついに購入しました!M5StickCを。
M5StickCは大人気のM5Stackの小型版です。M5Stackは持っていなかったのですがM5StickCのカワイイ色やサイズそして何と言っても2千円以下の家計に優しい価格にやられて速攻購入した次第です。

ここではM5StickCを用いて製作した実にスマートな電池 M5Stick-Cell を紹介いたします。
 

 

M5Stick-Cell 構成

I2CモータドライバDRV8830を用いて電圧出力します。BlynkというスマホアプリでBluetoothを介してM5StickCと通信して出力電圧をコントロールできる電池をを実現します。

部品

M5StickCar組み立て

ユニバーサル基板を程度なサイズにカットしてM5StickCとつなぐコネクタとモータドライバを搭載しました。

M5StickC

設計環境にArduino IDEを使用いたしました。設定方法は以下の公式サイトを参照ください。

小型でカワイイですがカラーLCDディスプレイ、マイク、赤外線LED、BLEやWiFi機能など盛りだくさんです。しっかりしたパッケージにコンパクトに収まっているので非常に扱いやすいです。詳細は以下の通りです。

 https://github.com/m5stack/M5StickC

Blynk設定

スマホとM5StickCはスマホアプリのBlynkを用いてBluetooth通信させます。Blynkアプリのバージョンは2.27.6です。

新規プロジェクトを作成します。HARDWRE MODELはESP32 Dev Boardを選択。CONNECTION TYPEはBluetoothを選択。AUTH TOKENはArduinoコード生成時に使用します(アカウント登録したメールに送信されます)。

 

ウィジェットとしてBluetoothとジョイスティックを配置します。
 

ジョイスティックの設定はx軸とy軸の出力をMERGEしてヴァーチャルピンV0に出力させ、それぞれ値は-20~20としました。

I2Cモータードライバ DRV8830

DRV8830はI2C入力によって、モータ供給電圧(スピード)と供給電圧方向(回転方向)を制御するものです。つまり正負の電圧を生成できるということです。

I2Cアドレス設定

本モジュールは基板上のジャンパA1, A0のステートによって以下の表のようにアドレスを指定することができます。

表のアドレス末尾xは読み込み時には1、書き込み時は0をしてします。ここでは書き込みのみ使用します。両方Openのアドレス:0x64としました。

書き込みI2Cデータ

アドレス0x00に8bitの情報を書き込みます。
各ビットの設定は以下の通り。上位6ビットで電圧を設定し、下位2ビットで正負を指定できます。

 
 

Arduino IDEプログラム

以下のBlynkのArduino用ライブラリを使用してプログラムしました。バージョンは0.6.1。
 https://github.com/blynkkk/blynk-library

ライブラリのコード例のESP32_BT.ino を参考にプログラムしました。

ここではBluetoothを使用してM5stickCと通信します。WiFiでもよかったのですが現状まだBlynkが正式にM5stickCをサポートしていないため、Blynk WiFiライブラリとM5stickCライブラリとの併用ができませんでした。Bluetoothは大丈夫でした。

Blynkのジョイスティックの値0~20の数値を受けて0~1.6Vの電圧を出力します。ジョイスティックが上部にあるときは正、下部にあるときは負の電圧となります。

ディスプレイ表示

LCDにはM5stickC本体のバッテリ残量と出力電圧を表示しています。

バッテリ残量は内部のバッテリ電圧を読んで4.2Vを100%、0Vを0%とする簡単で乱暴な表示です。ちょっと使用されている電源ICのAXP192の仕様をみきれておらず。。。(だって漢字だらけなんだもん)。 まぁおいおい改善しますw

電池残量に応じて電池のグラフィックも変化します。電池残量はBlynkのタイマー割り込みで1秒ごとに計測して表示しています。

M5stickCライブラリによるディスプレイ表示に関する関数は以下の通りです。
  https://github.com/m5stack/m5-docs/blob/master/docs/en/api/lcd_m5stickc.md

 

 

Blynk Bluetooth接続

BlynkプロジェクトのBluetoothウェジットをクリックして設定します。

“Connect Bluetooth device”をクリックして “Blynk”が表示されたらOKをクリックして接続する。

動作

スマートな電池ができました♪極性を変えれるのでモータ動くおもちゃだとスピード制御に加えて逆走もできちゃいます。

 

いやーM5stickCマジで買ってよかった。中身見えないから扱いにくかったりカスタマイズしにくいのではないかと思ったけど全然逆。超使いやすいし故に色々アイディア浮かぶの。

うれしい!今後のヘビーユーズ必至。

追記 (19/6/20)

本体バッテリ残量表示を修正

 

 

ミニ四駆に載せてみた

出力を±3.0Vまで拡げました。

めっちゃすぐ電池なくなる。。。

SPRESENSE のマルチコアプログラミングで バーサライタ

ついにSPRESENSE にArduino IDEでのマルチコアプログラミング環境が誕生しました。

 

前回SPRESENSEを使用して製作したバーサライタ(POVディスプレイ)にマルチコアを導入してどれほどの高速動作が達成されるのか観てみました!

スマート靴占い 『 IしたoTんきになぁ〜れ 』

 

 

マルチコアプログラミング

SPRESENSEは6つのCPUを搭載しております。Arduino  IDE環境でのプログラミング詳細は以下の公式のドキュメントの記載の通りです。

 
MPライブラリというマルチコア用のライブラリが今回追加となりました。Mainコアと5つのSubコアの制御やコア間の通信を司ります。

コアごとにArduinoプログラムを用意して、コアを指定してコンパイルというなかなかの力技です(;^ω^)

構成の概要

3つのCPUを使用してバーサライタしてみました。

  • Mainコア:フォトリフレクタで回転を検出して2つのSubコアに発光タイミングを送信
  • Sub1, 2コア:Mainコアからのタイミングを受けてSPIテープLED Dotstarを発光

 

Arduino IDEコード

Mainコア

フォトリフレクタでバーサライタ装置のマーカを検出して割り込みで回転時間を測定してMP.Send関数で表示すべき画像のアドレスを各Subコアに渡しています。

コア間でメモリが共有されているので表示データのアドレスだけを渡しています。

 

LED表示画像データ graphics.h は画像やGIFからpythonで生成しています。画像の色データを極座標変換してLED用に配列にしています。またLED位置によって輝度を線型的に調整してバーサライタ表示時に明るさが均等になるようにしています。Divで1周当たりの画像分解能を指定しています。

 

Sub1コア

Mainコアからの画像アドレスをMP.Recv関数で受けてLED発光させます。MP.RecvTimeout関数でデータ受信の待ちモードを指定しており、ここではMP_RECV_BLOCKINGでデータを受信するまで永久に受信待ちに入るモードにしています。

Adafruitが提供するライブラリのハードウェアSPI使用では拡張ボードのSPI4しか使用できないためAdafruit_DotStar.cpp と Adafruit_DotStar.h をメインボード用に改造して
Adafruit_DotStar_SPI5.h、Adafruit_DotStar_SPI5.cpp
をつくってSPI5でLEDテープを制御できるようにしました。

 

Sub2コア

Mainコアからの画像アドレスをMP.Recv関数で受けてSPI4でLEDテープを発光させます。

 

 

動作

1コアから3コアにすることで1周での画像分解能が120から400にまで向上しました!わーい!!

性能指数:LED 57個 × 回転速度 730rpm × 400分解能 ÷ 100 = 166440 hPOV

 
ちなみに性能指数とはバーサライタの性能を示す独自の指標です。

 性能指数  [hPOV(ヘクトポブ)] = LED数 × 回転数 × 一周の分解能 ÷ 100

次は今回のアップデートでフラッシュメモリへの読み書きのライブラリも追加されたので長尺の動画表示にトライしたいです。

マルチコアへの道

シングルコア

性能指数:LED 58個 × 回転速度 730rpm × 120分解能 ÷ 100 = 50808 hPOV

デュアルコア

性能指数:LED 58個 × 回転速度 730rpm × 220分解能 ÷ 100 = 93148 hPOV

その後の話

フラッシュ仕様検討

分解能が上がったことによって表示データが大きくなり、現状ですと5フレームしか書き込めない状態です。

SPRESENSEのコンパイルされたコードはフラッシュメモリにインストールされ、実行されるときにSRAMに展開されて実行されます。
SRAMは1.5MBのうちのMineコアが768kB、Subコアが128kB割り当てられます。

表示データに使用できる容量はSRAMサイズを超えられないのです。。。

そこで8MBもあるフラッシュを有効に使用できないか検討しました。
Fileライブラリを使用するとフラッシュにファイル形式でデータを保存できます。

そこで表示データ(LED57個 × 分解能400の32ビットデータ)をテキストデータとしてフラッシュに保存して、再度読み込んで配列にする実験をしました。
テキストデータを1文字づつ読んで32ビット分で文字列にして16進数に変換して配列化しました。

1フレーム分の配列を読み込むのに3分20秒もかかりました。。。。

マルチコアで読み込んで配列生成しながら、長尺の動画を表示したかったのですが時間がかかり過ぎのため断念しました。。。

参考

装置構成の変更

2本のLEDテープの配置を2本平行ではなく、1直線に並べました。回転の際の表示のずれを抑えるためです。

 

ずれが軽減され精度が増しました。でももっとやりたくなっちゃう。。キリがないww

 

さいごに

今回のSPRESENSEバージョンアップによってバーサライタの性能が大きく向上しました。

いつかフラッシュメモリの使用も気軽にできるようになるかと思います。今回のバージョンアップのように。

祈りを込めて。。。

そして バーサライタ装置をステージ上にそっと置き
 地を引きずりながら漂う煙のようにその場を後にした。

しかし その表情はどこか誇らしげであったという

太陽光発電でタイムラプス撮影 ーベランダ太陽光発電所への道5ー

いよいよ太陽光発電を本格運用します。ここではラズパイカメラをつないでタイムラプス撮影を実施したのでご報告します。

 

 
 

構成

ソーラーパネルと鉛蓄電池をチャージコントローラに接続します。負荷としてラズパイカメラをつなげました。

部品

 

発電システム

Indoor Corgi Elec.社製のマイコンとしてESP32を使用した太陽光発電充電コントローラを使用します。マイクロSDカードスロットもありデータログを記録できます。

システムは以下の通りでESP32用Arduinoコードが提供されています。

概要

  • バッテリの電圧と充電電流を監視してPWM制御します。
  • 液晶ディスプレイにバッテリ電圧・電流、ソーラパネル発電電圧、動作モードを表示
  • 測定値のログをSDカードに保存。
  • 負荷とバッテリ間のスイッチでバッテリ電圧が低下した際に負荷の切断が可能。
  • ソーラパネル発電電圧を観測して8Vを下回るとコントローラをディープスリープさせて消費電力を抑える。
  • ESP32のWiFi機能でブラウザで各種数値表示や動作モード変更が可能

めっちゃ高機能で便利!!Arduinoコードなのでカスタマイズも比較的簡単にできます。

ブラウザ表示 (設定)

ここではターゲットとするバッテリ充電電圧を13.8V、充電電流を1Aとしました。スリープモードは有効にしています。負荷の切り離しは無効にしてスリープ時もバッテリの電気でラズパイを動かします。

無負荷時の発電動作

まずは負荷なしでチャージ動作を観測してみました。

日が当たるとソーラパネル発電電圧が18V程度になりバッテリに充電されます。バッテリ電圧はほぼターゲットの13.8Vを維持しています。
家は西向きのベランダのため直射日光は6~11時くらいしか得られていません。。。

夜間になりパネル電圧が8V以下になるとコントローラはDeep Sleepモードとなり15分おきに起動して電圧観測し、日の出でパネル電圧が上昇するとスリープを解除します。

 

タイムラプス撮影

丸一日ラズパイカメラをつないで写真撮影してみました。

Node-RED

ラズパイカメラの定期撮影はNode-REDで実施しました。2分おきに撮影します。

 

①撮影トリガ インジェクトノード

カメラ撮影のためのトリガです。2分おきに定期的に動くようにしています。また撮影したjpegファイル名を1づつ増やすためにPayloadに”1″を指定しています。

 

②jpegファイル名生成 ファンクションノード

グローバル変数sumに前段ペイロードの”1″を足して4桁の連番jpegファイル名を生成しています。

 

③カメラ撮影ノード

カメラ撮影を実行する node-red-contrib-camerapi を使用しました。
 https://www.npmjs.com/package/node-red-contrib-camerapi

輝度や画像サイズなどもろもろ設定可能です。前段の連番ファイル名msg.filenameを受けて撮影実施ます。

 

④ファイル名 連番リセット

前段のインジェクトノードをクリックするとこのファンクションが起動して、グローバル変数sumをリセットします。

タイムラプス

撮影した写真をつないで動画にしました。

おもしろい。しかも電気代タダ!!

タイムラプス動画生成は以下を参考にしました。
 http://sozaing.com/technique/timelapse_movie/

各電圧変化は以下の通りです。

日の出後は曇りのためほとんどチャージできていませんが、さほどバッテリは減りませんでした。

ラズパイカメラ定期撮影くらいなら余裕で長期運用できそうです。引き続き実験していきます。

E32-SolarCharger の PWM制御 ーベランダ太陽光発電所への道4ー

さてこれまでソーラー充電コントローラの基本機能を学んできましたが、いよいよ発電開始!です。

実際にソーラーパネルとバッテリをつないで動かしていきましょう。

構成

ソーラーパネルと鉛蓄電池をコントローラに接続します。今回は負荷はつなげていません。

 

コントローラと蓄電池の+側の配線には3Aヒューズを挿入しています。

部品

PWM充電方式

以下のサンプルコードを使用しました。
 http://indoor.lolipop.jp/IndoorCorgiElec/E32-SolarCharger/PWM.zip

システム概要

電力モニタ INA219でバッテリの電圧と電流を観測して、スイッチング回路のスイッチングパルス幅を制御(パルス幅変調 PWM)します。

電流はINA219のIN+, IN-ピン間の抵抗0.01Ωの電圧降下で測定します。今回は負荷は接続しないので観測される電流はバッテリへのチャージ電流となります。
負荷が接続されてチャージ電流より負荷電流のほうが大きくなると観測電流は負の値となります。

サンプルコードPWM制御部

以下がサンプルコードのPWM制御部の記述です。

PWM信号はESP32のledcxxxx関数で生成します。ここではESP32のIO32ピンから周波数3kHzのスイッチング信号を出力します。パルス幅は8ビット(0-255)で指定します。

INA219でバッテリの電圧と電流を観ながらパルス幅をコントロールします。バッテリ電圧目標値は13.8V、チャージ電流 1Aとしています。

  • バッテリ電圧が14.6Vより大きいか、バッテリチャージ電流が1.5A以上であればパルス幅を10減らす。
  • バッテリ電圧が13.8Vより大きいか、バッテリチャージ電流が1.1A以上であればパルス幅を1減らす。
  • バッテリ電圧が13.0Vより小さくバッテリチャージ電流が0.5以下であればパルス幅を10増やす。
  • バッテリ電圧が13.6Vより小さくバッテリチャージ電流が0.9以下であればパルス幅を1増やす。

上記のPWM制御を施してバッテリ電圧を13.8Vにします。

動作

バッテリがほぼターゲット電圧である13.8V付近までジャージされているのでパルス幅はほぼ0に近い状態です。

ソーラーパネルを手で隠すと電圧降下してパルス幅が少し大きくなります。

チャージ時初めのころはバッテリ電圧が12V程度でしたのでスイッチングはフルオン(パルス幅Max 255)でソーラーパネルからの電圧が直接バッテリに供給されていました。

これでソーラー発電でバッテリ充電できることが確認できました。

ソーラーパネル

今回使用したソーラーパネルのSY-M12W-12の仕様は以下の通りです。

  • 最大出力電力 :12W
  • 開放電圧   :21.8V
  • 短絡電流   :0.73A
  • 最大出力時電圧:17.4V
  • 最大負荷時電流:0.69A

最大で12W出力します。最大出力が17.4Vですのでコントローラやバッテリの耐圧はこれ以上にする必要があります。

最大電流値をもとにヒューズやPWM制御時のしきい値も考慮が必要です。

参考

バッテリ

今回は定格容量 12Ah(12V)の完全密封型鉛蓄電池 WP12-12を使用しました。仕様は以下の通りです。

  • 定格容量:12V 12Ah
  • 充電電圧:14.4~15.0V(サイクルユース)、13.5~13.8V(スタンバイユース)

サイクルユースとは普通の充電池のように満充電状態から放電をして一定まで放電後に再充電をくり返す使用で、
スタンバイユースとは常に充電しておいて停電などの非常時に使用する方法です。

WP12-12の寿命はデータシート上は以下のとおりです。

サイクルユース

  • 100% 放電 250 cycles
  • 80% 放電 350 cycles
  • 50% 放電 550 cycles
     

スタンバイユース

  •  3~5年
     

バッテリ寿命は外気温などでも変わるようですし、スタンバイユースは非常時の放電量によっても寿命が変わりそうですね。

今回のベランダ発電では日照時はバッテリチャージしつつソーラーからの電気を使用し、無日照時はバッテリの電気を使用するのでスタンバイユースになります。

無日照時の放電量もケアする必要ありそうです。

参考