銀の弾丸

プログラミングに関して、いろいろ書き残していければと思っております。

SQLiteのSQLのパラメータ化できる箇所

SQLiteSQLiteDatabase.rawQueryで、SQLのパラメタライズが、できる場所とできない場所がありまして、調査結果を記しておきます。

「単なる文字列置換」では無いようです(よくよく考えれば当たり前ですね)。

f:id:takamints:20151104125310p:plain


SQLite入門 第2版
SQLite入門 第2版
posted with amazlet at 15.11.04
西沢 直木
翔泳社
売り上げランキング: 293,597

SQLiteDatabase.rawQuery

概要

単純にSQLをそのまま実行するメソッドSQLのパラメタライズも可能です。

プロトタイプ

Cursor SQLiteDatabase.rawQuery(String sql, String[] paramValues);

引数

  1. sql - SQL文を指定。SELECTのみ。
  2. paramValues - sqlの中の?を置き換える文字列の配列。

使い方例

ざっくり以下のような使い方です。

// android.database.
//     Cursor
//     sqlite.
//         SQLiteOpenHelper
//         SQLiteDatabase
SQLiteDatabase db = openHelper.getWritableDatabase();

Cursor cursor = db.rawQuery(
    "SELECT id, description, amount, date"
    + "FROM t_wallet " /*     v               v   */
    + "WHERE description like ? AND amount >= ?",
        new String[] { "'ポテト%'", "100" });

while(cursor.moveToNext()) {
    int id = cursor.getInt(0);    
    String description = cursor.getString(1);    
    int amount = cursor.getInt(2);
    byte[] blobDate = cursor.getBlob(3);
    //      ・
    //      ・
    //      ・
}

WHERE句の条件にある?を置き換えています。 条件式などの値を置換できます。 しかし単に文字列置換をしているのではなさそうでして、

【できない】文字列リテラルの中身は置換されない

たとえば、description like ?の部分を、description like '%?'とはできません。 あくまでもシングルコーテーションで囲まれている部分は、文字列リテラルとして扱われるので、その中の?は置換されず、単に?で終わっているdescriptionを見つけてきます。ただ、第二引数の要素数が合わない場合は例外が投入されます。

【できる】式の一部の置換はOK

以下のように、式の一部は、置換できます。

rawQuery(
    "SELECT id FROM t_wallet " +
    "WHERE amount >= ? + 30",       /* OK */
    new String[] { "100" })`

※ これ、当初「できない」としていましたが、できました。別の要因で例外が出ていたのかも。すみません。

また、以下のように、単独の値でなくてもOKです。

rawQuery(
    "SELECT id FROM t_wallet " +
    "WHERE amount >= ? + 30",       /* OK */
    new String[] { "(80 + 20)" })`

ところが、次のは駄目でした。「構文エラー」になります。

rawQuery(
    "SELECT id FROM t_wallet " +
    "WHERE amount >= ? ) + 30",       /* NG */
    new String[] { "(80 + 20" })`

?を式として扱って、第1引数のSQL単独で構文エラーになるのは駄目っぽいですね。

【できる】カラム名もOKです

以下のようにSELECT句やWHERE句、ORDER BY句の、カラム名は置換可能でした。

db.rawQuery(
    "SELECT ? FROM t_wallet " +
    "WHERE ? <= ? ORDER BY ? DESC",/* OK */
    new String[] { "description",
                   "amount", "100",  "amount"})`

しかし、

【できない】FROM句のテーブル名はダメでした

予想に反して、テーブル名は置換できないようです。

rawQuery(
    "SELECT description FROM ? " + /* NG */
    "WHERE amount <= 100 " +
    "ORDER BY amount",
    new String[] {"t_wallet"})

そして、

【できない】ORDER BY の DESCもダメですね

これ、できても良い気がしましたが、しっかり例外が投入されました。

rawQuery(
    "SELECT description FROM t_wallet " +
    "WHERE amount <= 100 " +
    "ORDER BY id ?",               /* NG */
    new String[] {"DESC"})`

まとめ

結果をまとめると、以下のようになりました。

置換可能

置換できない

カラム名も構文的には式ですから、?は式を置換できるということで良いのかな。

キャリブレーションしてステレオマッチングやってみた

例によって、百均で購入した2台のWEBカメラをステレオキャリブレーションして、ステレオマッチングをやってみました。

低価格&低品質のウェブカメラで、マジメにキャリブレーションする意味なんてあるのかどうかわかりませんが、今後とも頑張ってやっていきます。いくつになってお勉強です。

高級ステレオカメラシステム(笑)紹介

今回から以下のように、カメラをキチンと固定しました。位置がずれたらキャリブレーション取り直しですからね。

f:id:takamints:20151013112207j:plain

押入れから引っ張り出してきた金属製のブックエンドに、そこらに転がっていたマスキングテープで固定しました。有り合わせ感たっぷりですが、これで充分機能してます。 カメラの後ろのはキャリブレーション用のチェスボードです。



ソフトウェア

全てGitHubに置いています。

github.com

利用している画像処理ライブラリについては以下を参照してください。

takamints.hatenablog.jp

キャリブレーション機能

ステレオキャリブレーション

ステレオキャリブレーションには、位置関係が固定された2つのカメラと、チェスボードが必要です。 2つのカメラで同時にチェスボードを撮影した複数の画像からキャリブレーションするのです。

stereoShot - ステレオキャリブレーション画像保存ツール

位置関係が固定されているのに、毎回、キャリブレーション画像を撮影しなおすのは無駄ですから、事前に保存した画像を実行時に読み込んで、キャリブレーションするようにしています。

この画像を保存するツールが、stereoShotです。

stereoShotを実行すると左右のカメラ画像が表示されます。各カメラが11x9のチェスボードの内部の交点を検出したら、それぞれ画面に描画します。スペースバーを押せば、両方の画像をファイルへ保存します。

ステレオキャリブレーションのためには、両方のカメラでチェスボードの交点を検出している必要があることに注意してください__

画像ファイルの保存先

画像ファイルの保存先は、既定ではカレントディレクトリとなっています。画像ファイルは、cal_という名前で始まります。これを変更するには-C オプションを使用します。このオプションでサブフォルダに出力することも可能です。たとえば、stereoShot -C sub/cal とすれば、サブディレクトsubcal_で始まるファイルが保存されます。

画像は数10枚必要とのことですが、今のところ15セット(左右あわせて30枚)でなんとかなっているようです。

StereoBlockMatchでキャリブレーションを有効にする

stereoShotで保存したキャリブレーション画像を読み込んで、ステレオマッチングを行うには、StereoBlockMatchに、stereoShotと同様の-Cオプションを指定します。-Cを指定しない場合は、従来通りキャリブレーションなしでマッチングします。

パラメータ表示・変更機能

ステレオブロックマッチに使用するパラメータの多くを、実行中に変更できるようにしました。 変更可能なパラメータは画面の左上に表示されており、左端の一文字をキーボードから入力して、[+][-]で変更できます。変更は即時反映されます。



実行結果

以下は、キャリブレーションなしとありの結果です。パラメータは同一で、「あり」は各々のカメラ画像をキャリブレーション結果でremapしてるかどうかの違いだけです。 ウィンドウの左上が右側カメラで、右上が左側。交差法(より目)で見れば立体的に見えるはず。左下はStereoSGBMで得られた視差画像。右下は視差画像の15回の移動平均画像です。

キャリブレーションなし
f:id:takamints:20151013115218p:plain
キャリブレーションあり
f:id:takamints:20151013115258p:plain

若干細かい部分の精度が改善しているように思いますが、実際のところ、その差は微妙。

カメラの品質によるところが大きいと思いますが、撮影環境やパラメータの調整でも大きく結果が異なります。

あと、キャリブレーションの有無で出力画像のピクセルが反転していますね。

今後の課題

  1. ステレオマッチングのパラメータの理解
  2. キャリブレーションの正当性チェック
  3. 3次元画像の可視化コードのチェック

(1)パラメータは適当に決めているので、細かく調整しながら様子を見てみます。各々のパラメータの意味も、キチンと理解していません。 また、(2)キャリブレーションのやり方によると思うのですが、補正後の画像が大きく回転したりずれていたりすることがあり、その機序を理解していません。 それから、(3)視差画像の可視化についても、なんとなく適当にやっていますので、このあたりのチェックが必要かと思います。

所感など

キャリブレーションの有無で、あまり差が出なかったので、かなり動揺(笑)。

品質の安定したWEBカメラを買うかどうか思案中。百均は限界かな。

参考サイト

russeng.hatenablog.jp



OpenCVステレオキャリブレーション用チェスボードコーナー検出ツール

ステレオカメラのキャリブレーションのために必要になる簡単なツール stereoShot を作りましたので、ご紹介。

stereoShotは、2台のカメラで同時にチェスボードをキャプチャーして、コーナー検出の情報を表示し、複数の画像ファイルを保存します。 複数の画像は、キャリブレーションに使用します。

stereoShot - ステレオキャリブレーション用画像保存ツール

実行中の画面

f:id:takamints:20151009191123j:plain

ちょっと見にくいですが、例によって100均カメラ(笑)。 見ての通り、左右の品質に差がありすぎて、向かって右の品質が悪すぎて検出精度がダメダメです。 ちゃんとしたWEBカメラを使えば問題ないと思います。


OpenCV 3 プログラミングブック
藤本 雄一郎 青砥 隆仁 浦西 友樹 大倉 史生 小枝 正直 中島 悠太 山本 豪志朗
マイナビ (2015-09-29)
売り上げランキング: 7,355

使い方

実行すると、2台のカメラのキャプチャー画像が横に並んで表示されます。

カメラデバイスインデックス

それぞれのカメラの、キャプチャーデバイスインデックスは、右が1、左が2となっていますが、コマンドラインオプションで変更可能。 以下の例では、右を2、左を1に変更しています。

$ ./stereoShot -R2 -L1

専用チェスボード

キャリブレーションには11x9のチェスボードが必要です。GitHubのリポジトリからダウンロードできますので、印刷して使ってください。

チェスボードの認識

各カメラがチェスボードを認識すると、そのコーナー(チェスボード内部の交点)を検出して画面に描画します。(検出時点でフレームレートが低下します)

画像の保存

画像ファイルの保存は、スペースバーを押して実行します。左右のカメラのキャプチャ画像がカレントディレクトリに保存します。ファイル名はcap_<連番>_<L or R>.jpgというようになっています。保存される画像に、画面表示されている検出されたコーナーは描画されません。

この画像を読み込んで、キャリブレーションしステレオマッチングするところは、以下のエントリーで説明しています。

takamints.hatenablog.jp

ビルド方法

ソースは全て以下のGitHubリポジトリに置いてあります。

github.com

メイン関数は stereoShot.cpp。 その他、詳細はREADMEを参照してください。

当初チェスボードを8×8にしていたのですが、コーナーの検出順序が安定しませんでした。縦と横が同じだと縦横の判別がつかなくなるようです。 そこで、11x9に変更したら、問題は完全に解消しました。

制限事項

  • チェスボードは 11×9に固定しています。
  • 今のところ、WindowsVisual Studio 2015でしかビルドが通らない状態です。

関連エントリ

takamints.hatenablog.jp

takamints.hatenablog.jp

takamints.hatenablog.jp

参考サイト

russeng.hatenablog.jp

ほぼ初めてのPLCで感じたラダーの勘所

f:id:takamints:20150912183433j:plain
photo credit: Ladder via photopin (license)

この夏、ラダーが熱かった。7月半ばに、初めて本格的なPLC案件を担当してから、もう2ヶ月か・・・。

本来パソコン側のソフトウェア担当です。PLCと通信して機器設定情報を編集したり、生産実績を収集するよなソフトウェアの経験こそありますが、PLCのソフト(ラダー)の経験はごくわずか。それも組み込みシステムのデバッグ用に接点信号を一定周期でON/OFFするような簡単なものしか作ったことがありません。まあ、ほとんど素人ですね。

7月当初の案件は予定通りのアサインでした。 慣れない作業ですが、盆明けにはなんとか完了。 しかし、その間、隣でくすぶりつづけていた案件が(匂いはしてたw)、ニッチもサッチも行かなくなってドッカンドッカン大炎上。 急遽、消火活動のため、ネコの手よりは役に立つだろう…とアサインされて、半径30km範囲のイッサイガッサイ巻き込んで、ワッショイワッショイの3週間。なんとか鎮火した次第です。

てなことで、今回、本気でPLCに取り組んで経験値が少し上がりましたけど、そのうち忘れてしまいそうだし、もったいないから自分のためにも書き残しておこうと思います。


目次

ところで「ラダー図」知ってますか?

プログラマブルコントローラ原理と設計法 (設計技術シリーズ)
高来一彦 張紅 萩原光則 芦田政之 渡辺康雄 半田執
学情報出版
売り上げランキング: 87,343

いや、ラマーズじゃなくて「ラダー図」です。

「ラダー=ハシゴ」ですね。回路図がハシゴのように見えるからです。

こんな感じ↓
f:id:takamints:20150913202334p:plain

「ラダー回路」と言ったりもしますね。 本質的にはリレー回路を指すのかもしれませんが、ここでは、PLCにプログラムする回路(ソフトウェア)を指しています。

以下、本題に入る前に、ラダーに関する基本事項を箇条書きにしておきます。詳細は調べてみてください。

ラダーの基本

  • リレー - 電磁石でスイッチをON/OFFする電気部品。PLCの中の仮想的なリレーを意味することもあります。また、それを補助リレーとも言います。
  • リレー回路 - 複数のリレーとPLC外部と入出力する信号を目的に応じて接続して、全体で自動的な制御を行うようにする論理回路です。
  • PLC - 「プログラマブル・ロジック・コントローラー(Programmable Logic Controller)」の略。リレー回路をコンピューターでシミュレートしているような機器です。現物は、だいたい小さめのタッパーからお弁当箱くらいまでの大きさの箱です。電気信号の入出力機能を備えた制御用のコンピュータです。
  • コイル - リレーとほぼ同じ意味で使います。通電しているときと通電していないときで、接点の状態が変わります。
  • 接点 - リレーでON/OFFされるスイッチみたいなものです。つながっているか切断しているかという2つの状態があります。接点を1つ以上つないで論理回路を構成します。
  • 論理回路 - 真か偽かを入力して真か偽かを出力する回路ですね。A接点、B接点、論理積(AND)、論理和(OR)を組み合わせて構成します。
  • A接点 - コイルに通電するとつながる接点。
  • B接点 - コイルに通電すると切断される接点。
  • 論理積(AND) - 接点を直列につなげたものです。電池と2つのスイッチと豆電球をつないで、両方のスイッチを押して始めて豆電球が点灯するような回路。
  • 論理和(OR)- 接点を並列につなげたもの。電池と2つのスイッチと豆電球をつないで、どちらか片方を押せば点灯するような回路。
  • 自己保持 - コイルのA接点が、それ自身の条件にORで入っていると、入力接点が一瞬ONになっただけで、その後の入力状態に関わらず、コイルのA接点がつながっている状態を保つ状態。

↓↓↓さてさて、ここからが本題です↓↓↓


「逆よ、全く逆よ。見えてくるわよ、本当のラダーが」もしくは「今考えている事の逆が正解だ」あるいは「右から左へ受け流す」― 解析やデバッグは、出力側から逆向きに追いかける

MOOMIN ムーミン カオ マグカップ ミイ MM622-11
山加商店
売り上げランキング: 10,979

ラダーには、左側に複数の接点、右側に出力コイルが記述されます。接点がつながったら、コイルに通電されるのです。

ところが、これを通常の文書と同じように、左から右へ順に見ても、いまいち理解が進まないと思います。

逆に、コイルの意味を理解した上で「これが出力される条件とはなんなのだ?」という気持ちで、左側の論理回路を見れば、すんなり理解できると思います。

たとえば、自動販売機でコーヒーを買うときの動作は、

「お金を入れて、このボタンを押せば、このコーヒーが出てきます」

ではなく、

「このコーヒーが出てくるのは、このボタンを押したときだな」と。さらに「このボタンを押せるようになるのは、お金を入れた後で、どのボタンも押されていないときなんだな」

と、読み替えるような感じです。

「直接操作は最後の手段。おいらはここで自己保持る」(安易にコイルをセット・リセットしないで出来れば自己保持しましょうね)

PLCでは、コイルへの出力(OUT)命令とは別に、SETやRSTといったコイルの状態を直接指定する命令があります。 これはそのコイルの自己保持と、その解除に相当する命令です。

二重コイル(複数回、同じコイルに対するOUT命令がある状態)はご法度ですが、SETとRSTはいくらでも好きなだけ書けます。 しかし、広い範囲に渡って安易にこれらを使用すると、どこで何が行われているのかわかりにくくなってしまいます。

また、SETとRSTは、処理内容がその順序に依存してしまい、ややこしいことになりやすい。 ラダーは「回路」なので、基本的には順序に関わらないのですが、SET/RSTの使用で、この前提が崩れるからです。

自己保持の為に補助リレーを追加する必要があっても、できる限りOUT命令で構成するほうが望ましいと思います。 その箇所だけでコイルの状態が替わり、全てが、そこに記述されているので、理解しやすく、デバッグも楽になるはず。

「ラダーは開発室で動いているんじゃあない実機で動いているんだっ」(四の五の言わずにモニターする)

デバッグ時など、机上であれこれ考えるより、実際にラダーを動かして接点の状態をモニターするのが一番です。PC持って実機の前へ陣取りましょう。

思ったとおりの出力が得られていないなら、左の論理回路が想定通りになっていないはず。

論理回路が間違っていれば修正しますが、接点の状態が想定と違うなら、その接点の出力部分をモニターして、繰り返しです。

自己保持回路では、自己保持される時に確認する必要があるかもしれません。

このようにタイミングが限られていたり、SET/RSTで状態が変化している場合は、確認用のロジックを追加するといった、ひと工夫が必要かもしれません。

「もう無茶苦茶でござりまするがな(泣」(手動マージで疲労困憊。PLCにはVCSの概念が丸ごと無い)

無茶苦茶でござりまするがな
クーペ
いそっぷ社
売り上げランキング: 1,921,406

今回の消火活動で一番困ったのがこの問題です(未解決)。

この炎上案件、当初担当していた業者さんが、無茶苦茶なラダーを残して納品日を前に逃げちゃったので、複数人でラダーを修正しないと間に合わないという状況でした。

ところがここで、まさかの手動マージ。ラダーのプログラムがバイナリーファイルなんですよ。コンフリクトしたら終わりですから、もう仕方が無いです。

どうやらこのPLCの世界では、バージョンコントロールシステムという概念が無いようです。

複数の人が同時に編集作業を行うのは想定外。必要なら後で慎重に手マージするしかないという風潮(?)でした。

ちなみに「マージ」や「ブランチ」といったVCS語が通じないだけでなく、作業手順的なセオリーとして、コミットをなるべく小さい単位で刻んだり、他の作業者とコンフリクトが発生しにくいように声をかけるといったこともあまり理解されていないようでした。担当者の経験年数によるものかも知れませんが。

普段Gitでなれている私たちにとってはいろんな面で衝撃でした。なので、ラダー用のVCSがあれば、PLCの開発風景がドラスティックに変わる気もします。 というか、PLCプロジェクトの統合環境がテキストファイルを吐いてくれたら全て解決するのですが・・・。

f:id:takamints:20150912183031j:plain
photo credit: Dezomeshiki via photopin (license)

jQueryプラグインを正しく簡単に作る方法

キチンとしたjQueryプラグインを簡単に作れる関数をご紹介。

JavaScriptのクラスをそのままjQueryプラグインに変換しちゃうお手軽関数

ここでは、「jQueryプラグインの作り方」を説明しているのではなくて、JavaScriptのクラスを作れる人なら、「これを使えばすぐできる」って関数を説明しています。


f:id:takamints:20150809144709p:plain

jquery_plugin_class - クラスをjQueryプラグインにする関数

ということで早速、以下の関数。

function jquery_plugin_class(class_name) {
    jQuery.fn[class_name] = function(method_name) {
        var args = Array.prototype.slice.call(arguments, 1);
        var invoke = function(element) {
            var ctor = window[class_name];
            if(element[class_name] == null) {
                element[class_name] = new ctor(element);
            }
            return ctor.prototype[method_name].apply(
                    element[class_name], args);
        };
        if(this.length == 1) {
            return invoke(this[0], class_name, method_name, args);
        }
        return $(this).each(function() {
            invoke(this, class_name, method_name, args);
        });
    };
}

プラグイン化したいクラス名を指定して呼び出しておけば、そのクラスを jQueryプラグインとしても使えるようになります。以下のサンプルをご覧ください。

サンプル

以下はクラスをプラグイン化するサンプルです。

//プラグイン化したいクラス名を指定して呼び出す。
//ここで呼んでるけどクラス定義の後でも良い
jquery_plugin_class("hovercolor");

//以下は普通のクラス定義。
//指定要素にHoverイベントを設定して、マウスホバーで
//色を変化させるクラス
function hovercolor(element) {
    this.element = element;
}
hovercolor.prototype.create = function(option) {
    this.opt = option || {
        bgc:'yellow',
        fgc: 'black'
    };
    this.deg = 0;
    var $obj = $(this.element);
    this.bgc = $obj.css('background-color'); 
    this.fgc = $obj.css('color'); 
    $obj.hover(
        function() {
            $obj.css('background-color', this.opt.bgc)
                .css('color', this.opt.fgc);
        }.bind(this),
        function() {
            $obj.css('background-color', this.bgc)
                .css('color', this.fgc);
        }.bind(this)
    );
    return $(this.element);
};

使用例

以下のようにプラグインとして使用できます。

$(function() {
    $("li").hovercolor("create", {bgc:'cyan', fgc:'#880000'});
    $("p").hovercolor("create", {bgc:'#ffcc66', fgc:'black'});
    $("a").hovercolor("create", {bgc:'yellow', fgc:'red'});
});

※ メソッドチェーンの例を示すべきでしたが、またそのうち。

制限&注意事項

ちょっとした制限として、(1)コンストラクタが必ずDOM要素を受け取らなくてはならないのと、(2)必ず生成のためのメソッドを作るべきという点があります。

「キチンとしたjQueryプラグイン」とは

ここで、「キチンとしたjQueryプラグイン」とは、以下3つの基本的なインターフェースに従っているということです。

  1. 複数要素をまとめて扱える(インスタンス化・メソッド呼び出し)
  2. メソッドチェインできる。
  3. 単一要素については、(メソッドチェインでなく)値を返すことも可能。ゲッターのような使い方ですね。

上の関数は、この3つのインターフェースを、ひとつの関数にまとめているということです。 プラグイン固有の機能は、クラス内に実装できます。

jQueryプラグインのスタイル

これを利用して構築されたプラグインは、__jQuery-UI 的なプラグインになります。つまり、jQuery-UI と同じように使えます。

__プラグインのすべての操作を単一のメソッドで行うもので、プラグインの実質的なインスタンスメソッドは、その第1引数で文字列によって指定します。第2引数以降の解釈はその機能に応じて変化します。

引数リストはクラスの定義に明示できますので、少しだけわかりやすいかも。

ライセンス等

権利についてはオールフリー。何もかも放棄してGitHub Gistに置いていますので、ご自由にコピペでもなんでもヨロシクどうぞという状態。かわりに、なんら責任は負いませんので、そこんとこだけヨロシクです。

所感

夜中に思いついて作ったのですが、自分の中にあったjQueryプラグイン作成に対する敷居が下がりました

プラグインをたくさん作る場合に楽ができます。 クラスを作り慣れている人なら特に。

別サイトMZ-700フルJavaScriptエミュレータ では、画面表示関係全般のプラグインを、これを使って書いています。Z80アセンブラってナニ?って興味のある人も是非どうぞです。

bicycle.life.coocan.jp

動作速度は多少オーバーヘッドがありますね。でも遅すぎて使えないというようなこともありません。 速度を追求するなら、そのように実装したクラスを直接使えば良いだけ。 メソッドチェーンを利用したり、jQuery使ってるぞ感を出す(?)にも便利です。