osa2's memo

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

LPC1768からHelloを打ち込んでみた

明けました。特に何もないです。何がめでたいのかもよくわからない。

で、人とは楽な方へと流れるもので(笑)最初に手を付けたのはLPC1768(以下mbed)。といっても昨日、珍しくハンダ付けが調子よく(決め手は老眼鏡!)、転がっていたmbed用のEthernetパーツを作り上げて接続。

f:id:osa2:20180101090027p:plain

しかし、シリアルをつないでないので、つながったかどうかがわからない。それならと、つないだついでにHTTPサーバーにPOSTを投げるところまでやってみた。途中、諸々、省略(笑)最後の方に参考にしたサイトをメモっておく。

mbedのコード。

// main.cpp
#include "mbed.h"
#include "EthernetInterface.h"

EthernetInterface net;

int main() {
    net.set_dhcp(false);
    net.set_network("192.168.1.101","255.255.255.0","192.168.10.1");
    net.connect();

    TCPSocket socket;
    socket.open(&net);
    socket.connect("192.168.1.100", 80);

    char sbuffer[] = "POST /cgi-bin/hello.py HTTP/1.1\r\nHost: 192.168.1.100\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 19\r\n\r\nurname=Mbed_LPC1768\r\n\r\n";
    int scount = socket.send(sbuffer, sizeof sbuffer);

    socket.close();
    net.disconnect();
}

結果(mbedをリセットすると接続→POSTリクエスト送信となる)。

f:id:osa2:20180101090345p:plain

 ま、これであとはセンサでも付けて情報をPOSTすればいいのかな、と。たぶん、Mbed Device Connectorのような、コントロール用のホストを中に立てた方が良さそう。手許には可視光の光センサがある(何故あるのかが不明。)のだが、いかんせんこの子、Wiredなので何処にも連れていけない。いまそこで引っかかっている。なんかWiFiっぽい部品も転がってるんだけど・・・めんどうい。

参考にさせていただいたサイト:

まだ、Hello! の世界。いつもこればっかり(笑)

やっとフォントを変えることができた(2018/1/7更新)

Elephone C1max の中華フォントを国産フォントにやっと置き換えられました。

自分のメモですので、以下のリンクで再実行可能。

2018/1/7更新:
別筐体で試したら、SuperSUの導入で「空振り」があったので、その部分を再確認、以下の記述も更新。

以下、十分ご理解いただいた方以外は、絶対に真似しないでください。けっこうザックリ書いてますので、立ち往生すると端末が使えなくなります。また順調に行ったとしても既存のデータは全て消えてしまいます。

Stock ROMの用意:

以下がElephoneの公式サイトとなる。Support → Downloadsで、いくつかの機種が表示される中に、C1maxもある。焼き込みのツール(FlashTool)とVCOMのドライバーもある(なんて親切)。試行錯誤で失敗してもこれでリカバリ可能。カスタムRecoveryの修正にも必要。

www.elephone.hk

ImageKitchenの準備:

カスタムのTWRPイメージをそのまま焼いても簡単にはTWRPが立ち上がらない。このため、ImageKitchenというツールでrecovery.imgをunpack, 修正, repackする。

forum.xda-developers.com

TWRPの準備:

公式のTWRPサイトからはC1max用のイメージは提供されていない。C1MaxはMediatekのMT6737TというSoCで動作している。また、C1maxは初期の出荷時からNougatであり、上述のStock ROMもNougatのため、TWRPはバージョン3.1が必要(とWEBのどっかに書いてあった)。このため「TWRP MT6737T 3.1」で検索。今回は以下を利用している(他も試したらロシア語のTWRPが出来てしまい、操作に苦労した)。

forum.xda-developers.com

C1max用のrecovery.imgの作成:

上記のTWRP3.1はそのままfastbootで焼いても起動しない。以下の手順にて、Stock ROMの中にあるrecovery.imgの一部分をTWRPのrecovery.imgに取り込む(双方のrecovery.imgをunpackして、TWRP側を修正してrepack)。unpackするとMT6735とかあるが、Stock側も6735とあるので、気にしないで進める。

www.stupdroid.com

FastbootでのTWRP焼き込み:

C1maxの設定で開発者モードの中にOEM UnlockをEnableにするトグルがあるのでこれをEnabledにしておく。また、ファームウェアの自動更新も一応オフにしておく。fastbootモードには、adb reboot bootloaderでもいいし、電源オフ状態から電源ボタン+Volume UPで選択モードに入る(V-Upで選択肢変更、V-Downで選択可能)でもよい。oem unlock → flash recovery → oem lock で、reboot

注意点:flashした後、必ずlockし直すこと。unlockのままではブートループとなる

TWRPでのSuperSU焼き込み:

chainfire氏謹製の、SuperSUを焼き込む(直近では2.82がstableで2.85がbeta。SuperSU焼き込みは大きく2段階の処理。もし1段階のみだと「空振り」。2.82の方が確実な様子)。

また、焼き込む前に dataパーティションext4でフォーマットしておく。焼き込んだ後にcache, Dalvik cacheもクリアする。SuperSUの処理が2段階通ったようなら、RebootReboot Systemで再起動。

forum.xda-developers.com

フォントの変更:

起動後にSuperSUのアイコンがあるのを確認して、adb shell , suを行いシェルでrootで作業できることを確認する。Recoveryモードに戻り、/systemをrwでマウントして(TWRPでマウントするだけ)、以下のサイトの手順で、自分が使いたいフォントの配置と、fonts.xmlの書き換えを行う。Recoveryモードだと、/systemをRWでマウントできるから作業は楽。グループとパーミッションの変更を行う。

blog.hogehoge.com

TWRPからReboot Systemで、完了!

Stockが提供されたので、やっと気合い入れて調査、変更することができました。

== END ==

 

 

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 ==

 

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もそのまま使えてこんなにシンプルなコード。これはいいなぁ。