osa2 memo

自分の記憶のために・・・。

コンテナオブジェクトのgetter/setter

Kotlinを初歩の初歩から勉強中。

値の出し入れだけの getter, setterは書かなくて良い

(カスタムも書こうと思えば書ける)。

fun main(args: Array<String>) {
val bob = Person("Bob", false)
println(bob.name)
println(bob.isMarried)
bob.isMarried = true
println(bob.isMarried)
}

class Person (
val name: String,
var isMarried: Boolean
)

これね。Javaの世界では長らく(もしかすると今も)タブーですよね。勝手にフィールドの値を外から書き換えるな。「カプセル化」しているのだから。でも、データ運ぶだけのオブジェクトなんて、凝ったことしないから getter / setter なんてぜ~んぶパラメータの値のセットと取り出しのreturnだけ。Eclipseとかで自動生成でズラズラとgetter / setter 書けるけどバカバカしくて、最近はもうコンテナだと思えばフィールドは public にしていた。

どこの世界も、一度ドグマ的シキタリができあがっちゃうと、クロフネが来るまで駄目なんだろうな。。

Open JTalk .htsvoiceへの形式変換(htsvconv)

補足、というかこのブログは自分のためのメモ帳なので。

初音ミクのボイスがあるけど、変換はWindowsで、とありましたが、Linux Mint 18.2(Sonya, Ubuntu16.04LTS xenialに相当)でも変換を行えました。

まずソースコードをいただきます。

neu101.seesaa.net上記の中の「htsvconv002.zip」へのリンクをクリックでダウンロード、てきとに解凍。

実行に必要なもの。

  • コンパイル:mcsコマンド(apt install mono-mcsでインストール可能)
  • 実行:monoコマンド

私はmonoコマンドは入ってましたのでmonoコマンド自体はどうやってインストールするか調べてませんが、mono-runtimeというパッケージがあるので、もしかしたらそれかも?インストール、コンパイル〜ミクボイスの変換は以下が参考になります。

karaage.hatenadiary.jpMacと同じようにできます。非常にラフな言い方をしますと、brew → apt に置き換えただけです(笑)

しかし、世の中、欲しいものはまぁほとんど誰かがすでに作ってくれているのですね。
何事も、あらまほしきは先達なり。ありがたや、ありがたや〜、です。

 

RaspberryPiで音声認識→ESP-WROOM-02操作 (後編)

長くなるのでやったことだけ、メモ。

1.プリコマンドによる誤操作防止

直接指示を与えるのではなく、事前に「これからコマンドを送るよ」という前置詞的なコマンドを用意。プリコマンドを発声すると、ready_state → ON となる。各コマンドは ready_state == ON の場合のみ実行され、実行後に ready_state → OFF とする。

2.ロック(アンロック)コマンドによる誤操作防止

長時間不在時のために、もう1段、明示的にロックをかけられるようにする。lock_state == OFF の時だけプリコマンドが成功し、ready_state → ON に変更できる。ロックコマンドで lock_state → ON、アンロックコマンドで lock_state → OFFとする。

3.Open JTalkによるコマンドエコーバックメッセージ

音声操作の場合、モニタなどのディスプレイ装置を観ていないことが多い。このため、エコーバックを音声(WAVファイル)で行うこととし、テキスト文言からWAVファイル作成には Open JTalkを使用した。

女性ボイスデータ:meiちゃん(mmdagent.jp

qiita.commoblog.absgexp.net

ちなみに、私のパラメータ設定は以下の通り。割とキビキビした明るい女の子。ちなみに、アクセントの制御は難しいが、「、」や空白を入れて読み上げを区切るとアクセントが変わる(かなりの違和感をこの方法で解決できた)。

open_jtalk -m /usr/share/hts-voice/mei/mei_happy.htsvoice -x /var/lib/mecab/dic/open-jtalk/naist-jdic -a 0.55 -fm 4.0 -r 1.0 -jf 1.2 -ow test.wav voice.txt

4.マイクレベル・音声認識の調整

マイクレベルが高いと常に入力信号を拾い、音声認識(Julius)のバッファあふれや頻繁なエラーが起きる。マイクレベルは使用機器により異なると思うが家にあったマイクでは30%程度で適正であった。

また、音声認識のカットオフを800msec(結局はインストール時の初期値)に変更した。

5.TODO

 

 

RaspberryPiで音声認識→ESP-WROOM-02操作 (前編)

先週末の、ESP-WROOM-02 (以下ESP)らくちんリモコンの続編。

自宅に眠っていたRaspberry Pi2 B+ (以下、RasPi) にWiFiドングルを挿して、RasPiで音声認識、ESPに指示を送る形で、音声のみでの照明・エアコン操作をしてみました。

RasPiのセットアップやWiFiドングル(IO-DATA WN-G150UMK)の設定は検索すれば多く見つかりますし、RasPiではこのドングルはすぐ認識されましたので特別なことはないです。

音声認識は以下のサイトの通りやっただけ(ありがたや)。ただ後半は自分のリモコンへの接続をしているので、もちろん違ってきます。

raspibb2.blogspot.jp後半の差分部分は、とりあえずESPのWEBサーバーにPOSTで(前回のWEB画面でボタンを押した時にサブミットされる文字列を入れた)JSONを送る。上記サイトで使っているPythonプログラムにPOST送信のコードを埋めただけ。なので、コードも省略。

ひとつわかったことは、上のサイトではJuliusの音声認識の時間を800msecから400msecに短縮しているが、辞書を絞った上に認識時間を短縮すると、些細な言葉(例えば「ねむい」)も誤変換されて、コマンドが発行され、うっかりすると照明もエアコンもぐちゃぐちゃに動き出すのです。

とりあえずの対策は、逆に認識の時間を1500msecと長く設定して、辞書の単語も1ワードを長くする(例:「しょうめいあかるく」とか)して、命令以外の言葉を引っかかりにくくしてみました。が、辞書を絞っているので、長い言葉を掴むと無理やりコマンドに変換してしまいます・・。

なので根本的には、「事前にこの後、命令を発することをRasPiに教える」必要がありそうです。というわけで、「OK, Google」の意味がわかりました。これが前置詞で、これで待機状態に入ったところで、命令を発行するわけですね。

ならばもちろん「Nope, Google!」としたいところですが(笑)せっかくなので、このコンシェルジュにお名前を付けてあげて、その名前で呼んであげることにしたいと思います。

== TO BE CONTINUED ==

 

ん?

はて。なんでこのブログを購読してるのだろう??

むかし何かの記事でリンクしたっけ。

minamii.hatenablog.com

 ま、いっか。

ESPr(R) IR 赤外線リモコンで楽ちんリモコン

お題だけみると楽ちんですが、日頃「基礎学習」を怠っているぐうたらホビィストにはなかなか越える山が多かったので、メモを残します(今日はこのメモ書きだけで終わりそうだ・・)。きょうび、デキる小学生ならあっという間なんじゃないかな。

はじめに成果。

まだブラウザの中で動いております。個人利用ならてきとにapkにすればいいのかなと思ってます。

f:id:osa2:20171202111013p:plain

以下、ドロドロ、ノロノロの試行錯誤。

(1)部品調達

これは買うだけですから、取りこぼしがなければなんとかなるところ。ESP(R) IR 赤外線リモコン(ESP-WROOM-02:スイッチサイエンス)はWiFiも赤外線受光センサも赤外線LEDも全部入りのとっても初心者に優しい小型ボードです。運用は電源さえ繋げばOKで、縦横3〜4cm程度ですから場所も選びやすいです。

www.switch-science.comこのページに、

プログラムの書き込みにはFTDI USBシリアル変換アダプター
(5V/3.3V切り替え機能付き)が必要です。

とありますが、スイッチサイエンスさんでは「在庫切れ」。在庫のあった他社さんでポチ。

www.switch-science.com※あくまでもブツがスイッチサイエンスさんのものなので、引用(リンク)はスイッチサイエンスさんからとしました。

これと、PCとUSBケーブル(TYPE-Bのスマホ充電用)とスマホ充電器(5Vで1A出れば大丈夫)だけで、はんだもブレットボードも一切不要です。この選択は初心者には悪くないと思います。なんと商品ページに説明のWikiまでありますし。

http://trac.switch-science.com/wiki/ESP-IR

というわけであっさり2,3時間で、というのが「あさはかなり。」ですよ。2日かかりましたね。これだから基礎のなってない奴はダメですね。

(2)Wikiの通り淡々と・・?

部品が揃ったので、開封の儀、の後、上のWikiを観ながら進めます。シリアル変換の方のジャンパは3.3Vに、ESP-WROOM-2のジャンパは以後、PROG(プログラム書込み)とRUN(実行)で挿し替えます。ジャンパを外すとRUNなので、書き込む時だけジャンパを挿してもいいかもです。

自分のPC用のArduino IDEをダウンロードします。私はLinux Mint 18.2 (Ubuntu 16.04LTS相当)ですので、Linux版を。よくできたIDEなので、数ドルでもDonateしましょうね。

Arduino IDEにESP8266ボードの開発環境を整える方法はこちらを参照してください。

とあり、まずはArduino IDEの設定に入ります。さくっと書くと

  1. IDEを開く。環境設定で開いた画面で、ESP8266用のモジュールURLを設定
  2. 上記設定の後に、「ボードマネージャー」でesp8266で検索するとESP8266用のプラグイン?各種設定がIDEに展開可能となる
  3. 再度、今度は「ボードマネージャー」と同列で表示される「Generic ESP8266 Module」を選択する。これでIDEくんはESP8266開発をやる気になってくれます
  4. 開発設定を後述の表の通りにします。Flash Sizeを当初4Mと書いていたようで、あちこちに訂正が出ています。2Mが正しいようです。
  5. シリアルポートは「シリアルポート」というメニュー項目をクリックすると右側に選択肢が(おそらく大抵は1つだけ)でます。COMxxxはWindowsのケースでしょう。LinuxではttyUSB0となることがほとんどです(ここでなんでかなーと15分くらいロス)
  6. さらに下のメニュー「書き込み装置」はいじらなくてOKです。余計なことはしないのが、できるエンジニアの条件??
  7. 最後のスケッチ書き込みはいずれやるので、ま、いいのかな、と。(まぁハマったわけですが)
Flash Mode QIO
Flash Frequency 40MHz
Upload Using Serial
CPU Frequency 80MHz
Flash Size 2M(1M SPIFFS)
Reset Method nodemcu
Upload Speed 115200
シリアルポート 開発ボードのシリアルポート番号

 (3)リモコンの信号(発光)の読み取り

ここらからだいぶシロートは苦戦しました。Wikiの5.サンプルスケッチですが、以下のように「ライブラリ」を使用します。

リモコンのコード解析のためにIRremoteESP8266というライブラリを使用しました

これは「使用します」からにはコンパイラに認識させる必要がありまして、まず、上記IRemoteRSP8266のGitHubサイトから一式をzipでダウンロードします。で、そのzipファイルをいかのようにして取り込みます。たぶん基礎をちゃんと学んでいるArduino使いには「常識」なのでしょう。これをしないとヘッダファイルのincludeもされないので(リンクの前の)コンパイルすら通りません。

ライブラリのインクルードの仕方:

f:id:osa2:20171202115612p:plain

 で、~/Arduinoディレクトリの下に、librariesというのがあって、そこにzipファイルが展開されています。その中にexamplesもあるので、そこをオープンしても良いのですが、なんとなくlibの下を触りたくなかった、というだけで、同じzipファイルを~/Arduino直下にも展開しまして、その中のexamplesからIRrecvDump.inoを「これかなぁ」とOpen。ひどい話だ。

そして、これはこれで動くのですが、コードの中にガッツリと

DEPRECATED: Please use IRrecvDumpV2.ino instead!

とあります。試行錯誤で動いた末にこれを見ると、泣けます。しかし気を取り直して、IRrecvDumpV2.inoを開きます。こちらも手を入れるのはPIN番号を5にすることくらいです。

しかし動かすと、2なし版とは違い、大量に数字が出てきて、挫けそうになります。IRrecvDump, IRrecvDumpV2、どちらのどの部分を使ってIR LEDを発光させるのか。。

物語じゃないので(笑)私の得た結論はというと、

  • 作成者の指示通り、DumpV2を使うこと。
  • DumpV2でベンダー名とヘキサのコードがはっきりとれて、irsend.sendNEC(0x999999999) のようにそのベンダーのメソッドで送信ができるならヘキサのコードを利用する。
  • ベンダー名が UNKNOWN の場合は、irsend.sendRaw(rawData, 111, 38) のようにDumpで取れた配列を直接渡す

です。私の場合、部屋の照明は、

Encoding : NEC
Code : 0x218A54AB (32 bits)
Timing[67]:
+ 10242, - 5024, + 756, - 526, + 752, - 526, + 730, - 1808,
+ 752, - 528, ...

なので、

irsend.sendNEC(0x218A54AB);

のように取れましたので、irsend.sendNEC()にヘキサのコードを渡してコントロールでき、エアコンは、DumpではPanasonicと出たものの、DumpV2では UNKNOWNでしたので、439個の (uint_t)を渡しています。

Encoding : UNKNOWN
Code : 0x3109B479 (220 bits)
Timing[439]:
+ 3586, - 1652, + 510, - 368, + 506, - 1248, + 504, - 372,
+ 506, - 378, ...

・・・(中略)・・・

uint16_t rawData[439] = {3586, 1652, 510, ...

なので、Sendのコードに上記を(IRsend irsend(14);の直後に)コピペし、

irsend.sendRaw(rawData, 439, 38); として全部送信

うちのエアコンの場合、運転モード・温度・風向き・風量など都度、リモコン上の値をまるっと送ってました。まぁこの方が差分だけ送るよりずっと楽ですよね。なので、あとは、照明はOFFも含めた4つのボタンをサンプリング、エアコンは最近お気に入りの3つのパターンとOFFだけサンプリングして、画面を整えて終わりです。

あ、送信のサンプルは展開した中のIRSendDemoなどをみつつ、Wikiのコードを加工して作っています。画面レイアウト以外の主な修正点は、

  1. IR LEDのPIN番号を14に変更(Wikiと並んでいる回路図でも確認できます)
  2. WiFi.mode(WIFI_STA); の1行を追加
    (追加しないとAPモードで「認証なしのWiFiスポット」と化します・・)
  3. tempのサイズを800から3000まで拡張
    (冒頭に貼った程度の画面でもコピペで作るとあっという間に800を超えてしまいます)

です。とりあえずこれでいつもベッドで「何処に行ったぁぁ〜!?」と探しまくってた2つのリモコンは不要になりました。稼働はUSB給電でも、乾電池でもOKですね(シリアルアダプターは当然ながら実運用中は不要です)。4LEDでご丁寧に扇型に広がってますので、置く場所によってはかなりの範囲をカバー可能。IR LEDは照明やエアコンから見える場所に置く必要がありますが、操作の指示自体はWiFiなので、玄関で靴履いてから「あ、エアコン・・」というときも、スマホからOFFにできます。とぉ〜〜っても便利、ですよ!

== END ==

 

 

 

Kotlin + POI で Excelシート読み込み

のんきにお昼間にやってみましたが、、これは素敵ですね。

package com.example.demo

import java.io.File
import org.apache.poi.ss.usermodel.WorkbookFactory

fun main(args : Array<String>) {
     val inputFile = File("C:\\Users\\user\\Desktop\\sample.xlsx")
     val inputStream = inputFile.inputStream()
     val workbook = WorkbookFactory.create(inputStream);
     val firstSheet = workbook.getSheetAt(0)

     firstSheet.forEach {
         it.forEach {
             if (it.columnIndex > 0) print(",")
             print(it)
         }
         println()
     }

明示的に記述していないクラスは import なくてもエラーにならないという・・。まぁコンフリクトするなら書かなきゃでしょうけど。

ちゃんと型推論してくれるので、2段目の it では Cell を前提にメソッドの候補も挙げてくれる。ビルド前のことなので多少時間がかかってもありがたい。勝手な推測ですが、コンパイル時に型を暗黙にであれ決めているので、実行時に型推論し(て実行速度が落ち)たり、型違いで落ちることが少ないと思われる。

POIもそのまま使えてこんなにシンプルなコード。これはいいなぁ。