2013年12月28日土曜日

RasPi+OpenCV+WebCamera

Raspberry PiにUSBカメラを接続してOpenCVで撮影してみました


とりあえずこんな感じになっています

流れとしては
10行目)カメラを探す
12行目)ポインタアドレスを表示(デバッグ用 0位外であれば正常という判断)
14行目)ヌルポインタ(カメラが見つからない)以外であれば処理
15-16行目)デフォルトの画面解像度を獲得
20行目)画像をキャプチャ
21行目)画像を保存
23行目)保存した画像をsystem関数を使いscpで画面の有るマシンに転送
25-26行目)構造体を解放
だと思います(てきとーにそれらしい関数を引っ張ってきてるだけなので微妙

僕の環境はRasPiに画面が無いので、scpで他のマシンに飛ばしていますが
RasPiに画面が接続されているなら23行目及び4行目は削除しても問題ありません


コンパイルは
$ gcc hoge.c `pkg-config --cflags --libs opencv`
で通ります
めちゃくちゃ時間かかりますが。。


当初はRasPi用カメラモジュールを使おうかと思って、可視光のモジュールも購入済みですが
raspistillが地味に面倒なのでOpenCVを使ってしまいました
あとOpenCVだといろいろ参考になりそうな情報が多い というのも理由です


今のところカメラモジュールを使って何かをつくろうというネタは2個ほどありますが、優先度はかなり低いので気分転換に進める 程度になりそうです
その前にOpenCV本も1冊買っておかないと(ネット情報だと頭にはいらない性格)(本を買っても読まない性格だけど)


いろいろやりたいことはありますが、優先度が低かったり、恐ろしく面倒だったり、高コストだったり、それらのフルコンボだったりでいまいちやる気が出てこない今日このごろです

SDR?

かなり前に買っていた、SparkfunのSDRシールドを試してみました
http://strawberry-linux.com/catalog/items?code=18193


スイッチサイエンスより数円高い程度でアンテナとコネクタが付属しています
このシールドはすでに製造終了しています

サンプルはSparkfunのページからダウンロードできます
https://www.sparkfun.com/products/retired/10342

Documentsの最後にGitHubへのリンクが有りますが、GitHubにはEAGLEファイルがあったりくらいです
Arduino Libraryリンクからライブラリを落とす必要があります

ストリナで買った時の構成は
1)Sparkfunでよくある赤っぽい袋に入ったシールド
2)ピンヘッダ4個
3)バーアンテナ
という感じでした
おそらくスイッチサイエンスで買った場合は1のみで、2と3は自分で用意する必要があったと思います

自分で実装するのはコネクタとバーアンテナ
それからついでにワイヤアンテナもつけておきます
このSDRの受信帯域が64-108MHzで、4分の1波長では70cmから120cmといったところです
ということで今回は1m程度のワイヤをつけておきました

試しに使用したサンプルはライブラリに入っているものです

Arduinoにプログラムを書き込んだら適当なシリアルターミナルで接続します
操作は
8)音量を上げる
2)音量を下げる
4)シーク(周波数下げ)
6)シーク(周波数揚げ)
M)ミュート
U)ミュート解除
S)ステータス
という感じです
ミュート操作以外はテンキーを想定しているっぽいです

setupのなかで tuneFrequencyで最初の周波数を設定できます
引数は10kHz単位です
僕はラジオふらのの77.1MHzにするため、7710を設定しました

このラジオモジュールは出力インピーダンス10kOhmと非常に高く、ハイインピーダンス受けのアンプが必要になります

で、ちゃんとスピーカーを接続して電源を入れたところ
ノイズしか聞こえない!!
うっすらとなにか聞こえてきますが、僕の部屋ノイズ多すぎ

持ち運びできるHighZi受けなアンプが手持ちに無いため、ノイズの少ない環境に移動して試すのは難しそうです
次の課題はこの辺りですね
あと自室のノイズを減らす努力も…

2013年12月22日日曜日

GTKでメニューバー

最近、GTK本を買ったので、色々遊んでいます
といってもまだ第2章の最初の方までしかやっていませんが

で、Nexus7+Ubuntu13.04にGTK2.0を突っ込んだので、非常に可搬性の高いGTK環境ができたため、主にNexus7で試しているのですが、メニュー周りがどうしても動きません

で、色々試していたのですが
結論から先に示すと
最近のUbuntuはWindowsのようなそれぞれのウインドウ上ではなく、MacOSのような、上に表示されるような感じになっているようです

しかも表示されるのがマウスオーバー時限定なので、気がつくのに時間がかかった という感じでした
(通常はこのように何も表示されていない)

Nexus7の画面解像度だとウインドウ上のボタンはタップできますが、上の方にあるメニューは小さくて操作できません
なのでしばらくメニュー周りは放置になりそうです


あと、Nexus7をスリープに突っ込むと、復帰時にタッチパネルの反応が悪い気がします
ざっくり説明すると、スクリーンキーボード以外ほとんど操作できなくなります
スクリーンキーボードは問題なく操作できるので、端末からsudo rebootを叩けばちゃんとタッチが反応するし、端末から操作できることしかやらないならそもそもタップの反応が無くても問題ないわけですが なんだかなぁ という感じです
タッチパネル周りのモジュールをスリープから復帰後にリセット みたいなことができれば便利かも
Ubuntuを起動した時に「エラーが発生しました」的なダイアログが出る以外は結構安定して動いているので、その周りさえ解決できれば結構便利そうです

2013年12月16日月曜日

Nexus7にUbuntu13.04

今更な感じもしますが、手持ちのNexus7にUbuntuを入れてみました

そもそもNexus7を買った理由が
「iPhoneもiPadもKindleも有るなら次はAndroidだろ」
という短絡的な発想で
札幌に行った時に立ち寄った中古PC屋でNexus7が置いてあったからなわけですが

ArduinoDoroidoとか、Processingとか、KitKatとか とりあえずひと通りAndoroidoで動く遊びは試したのと、Android自体はほとんど使っておらず、Kindleくらいしか入れていなかった というのもあります
なのでデータ移行とかも気にせずに「試してみるか~」という衝動でUbuntuを入れた次第です

今回は
http://unizoff.net/blog/315
を参考にしました
イメージのDLに多少時間がかかりましたが、それ以外はあまり問題なくサクッとインストール出来ました
さすがKitKatです 他のOSをインストールするのもサクサク(関係ない


とりあえず、一部タッチ操作が不安定だったり、1280x800という解像度のせいでアイコンが小さくタップしづらかったり と言うのはありますが 一応動いています
もちろんUSBメモリやUSBマウスなども使えます
デスクトップ版Ubuntuなので、通常のUbuntuと同様の操作が可能です

GCCは最初から入っており、G++もapt-getでインストールできます
SSHも同様にインストールすることができ、他のPCやiPhoneなどから操作することができます

GTK2.0はとりあえずWindowの表示とButtonの動作だけは確認しました

しかしOpenCVは動作が微妙で、そもそもOpenCVはIntelが作っているため、ARM版は結構面倒らしいです
ただ全く使えないわけではなく、ちゃんと設定してコンパイルすれば使えるっぽいです
Webカメラもdmesgを見る限りちゃんと認識しているので、画像処理とかもできそうです


さて、タブレットにUbuntuを入れた時におそらく一部の紳士淑女の皆様が一番気になる件
遊べるのか!?

ということについてですが
結論から言うと ダメです><


いくらデスクトップ版とは言え、そもそもOSがARM版なのでFlash Playerがありません
これは艦これがHTML5等に対応するorAdobeがARM版Flash Playerを作る のどちらかを行う必要が有るため、一両日中に対応するのは不可能でしょう


そして、組み込み屋として結構気になるFT232のサポートですが
コレも不可のようです
FTDIはLinuxのドライバを作っていて、カーネル2.4(?)の頃にOSに組み込まれましたが、ARM版のドライバは作っておらず、そのためNexus7に入れたUbuntuからFT232を使ったシリアル変換モジュールは使えません

OpenCVやFT232など、Ras Pi(Raspbian)では動くのにUbuntuでは動かない というのが結構あります
この辺りもっと詳しく探せば動くようになるのかも

とりあえず目安として GTKのような比較的高レベルなライブラリは問題なく動くようです
しかしOpenCVやドライバ等の低レベルへのアクセスを要求するライブラリは動作しないようです


ソフトウェアとしては上記のような問題はありますが、GTKで遊ぶ程度なら十分に使えると言えると思います

しかしハードウェアとしてはまだ微妙なところで、例えば外付けキーボードやマウスがあったほうが快適に操作できます
動作がもっさりしてるのは諦めるとして、タッチパネル周りがもう少し反応が良くなれば使いやすいなぁ という感じです

あと、まだあまり動作が安定しておらず、結構落ちます

まぁ安定性を求める用途などに使うようなシロモノでもないので、総評としては「使える」でしょう
もうちょっと遊んでみたいと思います

2013年12月12日木曜日

OpenCVでキャプチャ

基本的なコードは前回のエントリ参照

画像を獲得するには
IplImage *img = cvQueryFrame(capture);
で画像のポインタを受け取る

保存するには
cvSaveImage("img.png", img, 0);
とする
Webのサンプルを見るとcvSaveImageの引数は2個なんだけど
これはC++で使う前提で、Cだと最後まで引数を指定する必要がある

ファイルのフォーマットはファイル名の拡張子で識別される
bmpとかpngとか、たいていは対応してそう


ノイズとか解像度はカメラによって異なるので、綺麗な画像が欲しければちゃんとしたカメラを探したりとかする必要がある
あとカメラによって解像度が違う とかの可能性もあるので、ちゃんと動くプログラムを作るならその辺りも作りこむ必要がある
(それが嫌でRasPi用のカメラを買ってみたりしたのだけど)

一旦IplImageになってしまえば顔検出とか色々できるので、煮るなり焼くなり好きにできる

RasPiでWebカメラ

今回はラズパイ用カメラじゃないです

前回の続き OpenCVを使ったプログラムのコンパイル方法
$ gcc main.c `pkg-config --libs opencv`
でa.outが作成される
ちょっと時間がかかるんで頻繁にコンパイルしてエラー吐かせる とかはむりぽ

テストコード
      1 #include <opencv/cv.h>
      2 #include <opencv/highgui.h>
      3 #include <ctype.h>
      4 #include <stdio.h>
      5
      6 int main(int argc, char **argv) {
      7     const int cCameraNum = 0;
      8     CvCapture *capture = 0;
      9
     10     capture = cvCreateCameraCapture(cCameraNum);
     11
     12     printf("capt  :%d\n", (int)capture);
     13     printf("width :%d\n", (int)cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH));
     14     printf("height:%d\n", (int)cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT));
     15
     16     cvReleaseCapture(&capture);
     17
     18     return(0);
     19 }
     20
Webカメラが接続されていればcaptureのポインタと、現在設定されているカメラの解像度が出力される
OpenCVがカメラを検出できなければポインタにはnullが入り、解像度も0になる
ちなみにこのカメラにRasPi用カメラはカウントされない
手持ちのUSBカメラは認識された

画像の獲得とかはこれからやる

ちなみにWebカメラのドライバとかは不要 接続するだけで使える
USBホント便利

2013年12月11日水曜日

RasPiのカメラ

RasPiのカラーカメラを買ってみた
RSで買うものが色々あったのでついでに という感じ
このエントリは備忘録と言うより愚痴に近い

カメラの接続はいたって簡単
カメラから伸びてるFFCをRasPiのコネクタに接続するだけ
ちなみにRasPiには全く同じコネクタが2つ乗っている
カメラで使うのはLANコネクタとかUSBコネクタの側にある方
向きを間違えないように接続
→確かFFCの電極がHDMIコネクタ側に来るように
後は電源を入れてraspi-configからカメラを有効にする
これだけで準備完了
撮影したい場合はraspistillコマンドを使う
最低限必須なオプションは-oでファイル名を指定する これがないと保存されない
その他コマンドは http://www.mztn.org/rpi/rpi23.html にまとまっていて見やすい

raspi-configもraspistillもSSHからできる
なのでRasPiには電源のUSBとLANコネクタを接続するだけで撮影が可能
ただ撮影した画像の確認ができないので、何らかの方法でファイルを転送する必要がある
転送にはscpコマンドが便利(ちょっと面倒だけど


で、あと色々やりたいなとおもってOpenCVを入れた
sudo apt-get install libopencv-dev
で入る(はず)
ヘッダファイルは/usr/include/opencvとか/usr/include/opencv2とかになる
なのでプログラムで読み込むヘッダファイルは<cv.h>ではなく<opencv/cv.h>とかになる
highgui.hも同様

ただ、ネットに転がってるサンプルは画面が接続されていることが前提のコードばっかりで、SSHから試すとかができない
この辺りはもうちょっと調べて見る必要がある

最近のRAMが8GBでCPUが2.5GHzで みたいなマシンばっかり使ってるのでRasPiのワンテンポ遅れたGUIはどうもストレスがたまる。。。(データがたっぷり詰まったiPhone とかも操作の反映が遅くてつらい)


やりたいこととしてはRasPi単体で動作する、画像解析装置 みたいな感じ
15fpsくらいはほしいけど、解像度はそれほど必要ないのでRasPiでも可能なはず

とりあえず今回はこんなところで
今年中にもーちょっと進めたいなぁ

2013年12月10日火曜日

映画フィルムを現像できる?

映画フィルム 劇場特典とか、初回特典についてくるアレです

どうやら現像すると捗るらしい ということでいろいろ試してみました

1.スキャナで読み込む

上はスキャナでスキャンした画像
下はフィルムの反対側から光を当ててスキャンした画像

どちらもうまく獲得できていません

上の画像の失敗した原因は
スキャナは基本的に反射した光を受光素子でデジタル化していますが
映画フィルムは透過した光を使うためです
そのために暗くなってしまいます
また、そもそもスキャナの光量では足りない というのもあります

また、下の画像ですが
僕が使っているH社のスキャナは構造的に他の光源を使うことができません
これは低コスト化のために物理的な解像度が低いのをソフトウェアで補正しているからです
(少し違いますが、まぁ似たようなもんです)
そのために外部の光源を使うと画質が悪化してしまうのです


ってことで
2.スキャナがダメならカメラ作戦
スキャナが外部光源を使えないならカメラを試すまでです
デジカメなら露出量を任意に調整できるのです

すごく…スクリーンキャプチャーっぽいです><

そもそも普通のデジカメでは解像度が圧倒的に足りません


結論:写真屋さん(photoshopじゃないよ!)に頼み込むのが簡単


映画フィルムと写真フィルムは色々と相違点がありますが、やってくれるところも有るようです

でもL版で印刷するくらいならBlu-rayを見たほうが(ry

自宅に写真現像環境が有る人とかは試してみると面白いかも?

2013年12月6日金曜日

C#で定数の配列

C#でconstを付けた配列は初期化することができません

この例の場合
constを使用したint配列のConstantList2は
"'ConstantList2' の型は 'int[]' です。文字列以外の参照型の const フィールドは null でのみ初期化できます。"
というようなエラーが発生します

しかしConstantList1はreadonlyを使っているため初期化することができます
readonlyを使用した場合、特定の条件を除き変更することはできません
そのため擬似的にconst型として使えます


readonlyは特定条件下で変更することができ、それはコンストラクタの中です
例えば上記のように宣言と同時に初期化しても、コンストラクタの中で
ConstantList1 = new int[10];
ConstantList1[0] = 10;
ConstantList1[1] = 20;
...
のようにすれば内容を変更することができます
これは一見便利なように見えますが、コンストラクタ内でreadonlyの変数を使った場合、中身を書き換える気がなくても書き換えてしまう可能性があるということです
この問題を回避する方法についてですが、一番危険な方法は「変数を書き換えないように努力する」ことでしょう
しかしそれでは意味が無いので別の方法を探す必要があります
一番簡単な方法は、例えばFunctionsというクラスがある場合、_Functionsのような関数を作り、コンストラクタFunctions内では_Functionsを呼び出すにとどめ、コンストラクタを使った初期化は_Functions関数内で行う という方法があります
この場合一手間余計に必要なのと、関数を1個呼び出すためのオーバーヘッドが必要になってしまうという問題が有ります
しかし一旦関数を呼び出して、コンストラクタの外側に出てしまえばreadonlyの変数を変更することはできないため、一応効果はあります


いくつかの利点や欠点がありますが、readonlyを使えば変数の定数配列を使うことができるので、状況によってはうまく使うと便利かもしれません

2013年12月3日火曜日

ステッピングモーター

ストロベリーリナックスで売ってるステッピングモータ

12026 12081 12082 18179
トルク 0.23N/m 0.43N/m 1.76N/m 0.48N/m
電圧 12V 2.8V 3V 3V
電流 0.33A 1.68A 3A 1.7A
電力 7.92W 9.408W 18W 10.2W
重量 0.2kg 0.34kg 1.1kg N/A

電流は1相あたりの値です
実際には2倍の電流が必要になります
電力は電圧*電流*2で2相分です

4個目のモーターの重量は調べていません
おそらく500g前後だと予想されますが、性能的に微妙なので無視しました

結局のところ一番大食いで一番重いモーターが一番トルクが有るようです

12026は電圧が12VのためL6470でも制御できます
他のモーターは電圧が低いので不明です
L6480は電圧の低いモーターにも対応できるようですが、6470は未確認です

2013年11月26日火曜日

STM32F1 ピン変化割り込み

STM32F1のピン変化割り込み EXTIの初期化方法について

今回は僕のボードの関係でPD1の立ち上がりエッジで割り込みが入るように設定する

クロックの供給

AFIOとGPIOのクロックを有効化する
一般的な有効化と同じ手順
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,   ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,  ENABLE);

今回はUART5 RXを使うためにGPIODを
JTAGを無効化するためにAFIOを 
それぞれクロックを供給していたので追加のコードは必要なかった
/*
  JTAGを無効化するにはAFIOを初期化して
  AFIO->MAPR = _BV(26);
  として26bitを立ててやればJTAGとSWJの両方を無効化できる
*/


GPIOの初期化

これも一般的な初期化の方法と同じ
GPIO_InitTypeDef GPIO_InitStructure;
で構造体を確保し
GPIO_InitStructure.GPIO_Pin = _BV(1);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOD, &GPIO_InitStructure);
でPD1を入力モードにした
IPUでもIPDでも問題ないはず

EXTIの有効化

GPIO_EXTILineConfig関数を使う
第一引数にポートを 第二引数にピンを指定する
これは一般的なGPIOAや_BV(0)といった指定方法ができない
GPIO_PortSourceGPIOAやGPIO_PinSource0というマクロを使う
今回はGPIODのピン1を使うので
GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource1);
という感じ
/*
  ヘッダファイルを見てみるとGPIO_PortSourceGPIOAは ((uint8_t)0x00) が Bは0x01 Cは0x02
  GPIO_PinSource0は ((uint8_t)0x00) が 1は0x01 2は0x02
  という感じで指定されている

  一般的なGPIOAやGPIOBはペリフェラルのポインタが
  _BVは #define _BV(n) ( 1 << (n) ) という指定でビットシフトしている
  そのため基本的にGPIO_PortSourceとGPIOxの互換性は全くない ピン指定も同じ
*/


EXTIの初期化

EXTI_Init関数を使う
EXTI_InitTypeDefポインタを引数にする
中身は 
    EXTI_Line
    EXTI_LineCmd
    EXTI_Mode
    EXTI_Trigger
の4個

LineはEXTI_Line0からEXTI_Line19の20個から選択
ピン0がLine0 ピン15がLine15という感じで割り付けられている
また16,17,18,19はそれぞれ電圧計国やRTCのアラーム等に設定されている

LineCmdは有効化するか否かをENABLE/DISABLEで選択
Modeは割り込みかイベントを選択 それぞれEXTI_Mode_InterruptとEXTI_Mode_Event
Triggerはどちらのエッジを使うか 
    EXTI_Trigger_Risingで立ち上がり
    EXTI_Trigger_Fallingで立ち下がり
    EXTI_Trigger_Rising_Fallingで両方
という感じ

今回はピン1の立ち上がりエッジで割り込み という設定なので
EXTI_Line1 ENABLE EXTI_Mode_Interrupt EXTI_Trigger_Rising
で初期化する

// PB1は立ち上がりで PC1は立ち下がりで とかの割り込みはどうするんだろう?

NVICの設定

NVICの設定は一般的な設定と同じ
ここは省略する
NVICのチャンネルはEXTI1_IRQn等を設定する

割り込みハンドラ

割り込みで呼び出される関数
void EXTI1_IRQHandler(void)
となる
中で EXTI_ClearITPendingBit(EXTI_Line1); でペンディングビットをクリアする必要がある
EXTI_GetITStatusを使ってLine1のペンディングビットを確認することができるけど EXTI1_IRQHandlerはLine1割り込みしか呼ばれないはずなのでGetで確認は不要のはず



上記の手順でEXTI割り込みが使えるようになる
しかし、ピン変化割り込みハンドラが呼ばれても、どのラインの割り込みか はわかるが
どのポートが割り込み操作のトリガになったかは判別できない気がする
例えばPA1とPB1の両方に割り込みを設定した場合、Px1が動いた と言うのはわかるんだが、それがAなのかBなのかは判断できない

あとPA1は立ち上がり PB1は立ち下がり とかだとRising_Fallingにして、ハンドラで確認する必要があるのか?

気が向いた時にでも調べておく必要がある

2013年11月20日水曜日

RC-S620/S

いまさらですが FeliCaリーダライタのRC-S620/Sを使ってみました
コレはだいぶ前に買っていて、作ってみたいものも有ったのですが
ズルズルと放置されていました

コレにアクセスするためのAPIはSonyがArduino用に公開していますが
C++のライブラリのため、C言語環境で使いたい時はライブラリを書かなくてはなりません
幸いC++をCに移植するのはC#よりもはるかに簡単なので
とりあえず移植して試してみました

なお、RC-S620/S自体はスイッチサイエンスで販売されています
モジュールの制御方法は法人向けの技術情報ページに記載されています
http://www.sony.co.jp/Products/felica/business/tech-support/index.html
一番下にRC-S620Sの製品情報とコマンドリファレンスの簡易版があります

Arduino向けライブラリは
http://blog.felicalauncher.com/sdk_for_air/?page_id=2699
から規約に同意することでダウンロードできます


STBeeにコードを書いて実行するとIDm等を表示することができます

モジュール自体はユニバーサル基板の裏側にFFCの変換基板と3.3Vレギュレータと共に固定されています

このモジュール自体は5Vと3.3Vの両電源に対応していますが、5Vの範囲がUSBの供給電圧レベルよりも狭いため、念の為に3.3Vにしてから供給しています

今回はIDmを使用した非常に簡易的なカードキーとして使おうと思ったため、ID獲得以上のことはしていませんが
ライブラリの動作確認時にケータイ電話へWebページURLを送信できることも確認しています

なお、FeliCaのIDは比較的簡単に偽装できるため、カードキーとして使う場合にIDm単体を使うことは推奨されていません
ですが今回はとりあえず遊びなので、IDmを使おうと思います


このモジュールはSony製でSonyが日本語情報を公開しているため、非常に簡単に使用することができます
うまく使えば色々と応用できそうなので、興味がある人は試してみてください

2013年11月15日金曜日

GTK

GTKというものを始めてみました
これはLinux等で使えるGUIアプリケーションを作るためのツールキットのようなもので
用意された関数等を呼ぶとGUIアプリが作れるというものです

今回はUbuntu LTS 日本語Remix上に入れたGTK2.0を使いました
UbuntuはWin7x64上のOracle VM VirtualBoxか、Mac 10.8上のParallels8のどちらでも動作を確認しています


GTKのインストールは
$ sudo apt-get install libgtk2.0-dev


ビルドする場合は
$ gcc source.c `pkg-config --cflags --libs gtk+-2.0`
です

pkg-configの前と最後はシングルクォーテーションではなくグレイヴアクセントであることに注意してください
この記号はJISキーボードであればシフトキーを押しながらアットマークキーを USキーボードならESCキーの下のあたりにある波ダッシュキーを押すことにより入力できます


エディタはViを使いましたが、基本的に使いやすいものを使っても大丈夫です

GTKアプリはgtk/gtk.hをインクルードしておく必要があります
CbackButtonClickedとCreateButton関数は放置するとして
main関数は一般的なCUIアプリと同様です
int argcとchar ** argvが引数です

まずローカル変数としてはGtkWidgetポインタ型のwindowという変数を宣言しておきます
これはFILE *fp等と同じように扱います
この変数(が指し示すメモリ)にGUIの様々な設定が入りますが、普段は変数の中身を気にすることは無いでしょう(設定は関数経由で行われる)

次に gtk_init 関数があり、これはargcとargvのポインタを渡します
argcとargvは値渡しではなく参照渡しであることに注意です

次に gtk_window_new 関数でメインのウィンドウを作ります
引数はGTK_WINDOW_TOPLEVELで、ポップアップウィンドウなどではこれが変わります
戻り値を変数windowに入れておきます

次に gtk_widget_set_size_request 関数でウィンドウの大きさを設定します
第一引数に対象のGtkWidgetポインタを 第二引数と第三引数にそれぞれ横解像度と縦解像度を与えます

次にCreateButton関数を読んでいますが、これはボタンを作成するためのサブルーチンです
ウィンドウと同じく GtkWidget *button 変数を作り、gtk_button_new_with_label関数でボタンの雛形を作成します
gtk_button_new...関数の引数はボタンに表示される文字列を与えます

次にgtk_container_add関数を使い、ウィンドウと関連付けをします

最後にg_signal_connect関数でボタンがクリックされた際に呼び出される関数を指定子ます
イベント"clicked"を指定し、関数はCbackButtonClickedです
第四引数にはコールバック関数に与える引数を設定できますが、今回はNULLとしておきます

感覚的にはgtk_container_addよりもg_signal_connectを先にしたほうがいいかもしれません

CbackButtonClecked関数の中身は gtk_main_quit 関数を読んでいるだけです

GtkWindget *buttonは任意のタイミングで破棄して問題ないようです


main関数に戻り
次は g_signal_connect ですが、これはウィンドウが閉じられた際にプログラムを終了するために設定します
これをしておかないとウィンドウを閉じたのにプログラムは終了しない といったことになりかねません
イベント"destroy"でgtk_main_quit関数を呼ぶように設定します

最後に gtk_widget_show_all でウィンドウを表示します
gtk_widget_show という関数もありますが _allを付けない場合はボタンなどが表示されないので注意してください

あとは gtk_main() 関数を呼び出してループに突っ込みます
gtk_main_quit はgtk_main()で呼んだループを終了させる役目があります
gtk_mainを抜けだすとmain関数に戻り、その後は何も処理を書いていないのでreturn(0)で正常終了します

これを上記コマンドでビルドするとa.outというプログラムが作成されます
a.outアイコンをダブルクリックするか、端末でa.outを起動すると上記画面に表示されているボタンが1個あるだけのプログラムが表示されます
☓印をクリックして閉じてもいいですし、ボタンをクリックして終了してもいいです


このコードはGTKの基本的な使い方を学べると思います
ボタンが2つ有るウィンドウ等を作る場合は更に複雑になりますが、基本的に上記の手順で作成することができます


OSをLinuxに限定せず、Windows等を使っていいのならC#等のGUIアプリを作る方法はたくさんありますが、今回はLinux上のGTKを使ってみました

2013年10月29日火曜日

mbeのベタグランド

フリーの基板設計CAD mbeというソフトですが
ガーバー出力ができ、すでに発注を2回していて問題なく使えています

で、今回基板を新しく設計するにあたり
少しはノイズ対策をしよう ということでGNDを強化しようと思いました
本来はちゃんと設計するべきですが、何が影響するのかさっぱりわからないのでとりあえずは気分だけでも ということで



SPIのパターンが上のように並んでいる場合
高周波になると信号が横に並行しているパターンに漏れてしまう可能性があります
これはパターン幅が狭くなれば狭くなるほど強くなる傾向があります
また長距離を伝送した場合はより強くなり
信号周波数が高くなるほど強くなります
この特性は裏面のパターンにも影響されるため非常に複雑で、経験や勘と実際に試した結果を元に最適化していくような場所です

このように並行した長いパターンというのはかなりの数にのぼり、今設計している100x200mmサイズになると相当な長さになってしまいます
一番簡単に対策をするには4層基板等を使って、いわゆる「ストリップライン」という構造にすればいいのですが、今回は2層で設計しているためこの方法は使えません

そのためとりあえず後から追加できる方法として、パターン間にGNDを通すことにしました
この方法ではパラレルATA等のインターフェースで後に採用されています

ざっくりと原理を説明すると
高速な信号は周りに影響を与え、その強度は与える側が低インピーダンスなほど そして与えられる側が高インピーダンスなほど強くなります
そして与える側の横に低インピーダンスな配線がればそこで吸収され、その外側へ与える影響は小さくなります
(という感じに理解しています)

この場合の低インピーダンスな配線とは、GNDに落とした配線となり、ほぼゼロ抵抗でGND電位に保たれます

しかし1本1本ラインで作っていると膨大な手間になり、修正も難しくなります
(信号1本の両側にGNDを通すため配線数は最大で3倍になります)


しかしmbeにはポリゴンという機能があり、これを使うと簡単にベタを作ることができます

この例では5本のパターンが有り外側の2本がGND 内側の3本が信号です
またパターン間隔は1.27mmです

ポリゴンの設定はGAP0.3mm Trace Width0.3mmで、Remove floating patternにチェックが入っています
パターン幅が0.3mmの場合 2本のパターンの間は0.97mmとなり、GAP幅0.3mm2本分の0.6mmにTraceW0.3mmを足した0.9mmよりも余裕があります

上画像の中で白いところはGNDと導通しており、信号線の間にGNDパターンが通っていることがわかります

このようにパターン幅を0.3mmで信号を通せばポリゴンでパターン間にGNDを通すことができます

ただしDRC(Design Ruehl Check)ではベタに対しての評価はされないため、注意が必要です
他にもいろいろ注意点がありますが、とりあえず「こんな使い方もできるよ」ということで

2013年10月27日日曜日

時間の単位

タイトルは"フィクションにおける時間の単位"とかにしようと思っていたんですが
現実の地球ベースなので単に"時間の単位"としました

さて、異世界転生モノの小説とかを読んでいるとよく時間が出てきます
「1日は24時間なのか」とか季節を1年で表す時もあります
しかしその時間というのは正確に現代の地球の時間と一致しているのでしょうか?

元々の時間の由来は
1日:太陽が現れてから次に現れるまで
1年:星座が同じ場所に帰ってくるまで
がベースとなり
1時間:1日を正確に24等分した長さ
1分:1時間を正確に60等分した長さ
1秒:1分を正確に60等分した長さ
となります
なぜ24/60等分するのか や1年を12に分けた月は今回は触れません
(まだ調べていないので。。)

この時間の単位で、他の惑星等で相対的に変化させることにより対応できるのは1日をベースにした単位で、日以外には時間・分・秒です
これは太陽が1回廻る時間が基準になるためです
年は相対的に変化させることができず、実際に観測をして1日の回数を数えるしかありません
例えば地球なら1年はおよそ365日ですが、太陽系第四惑星の火星ではおよそ687日です
これは火星が地球よりも公転半径が長いためであり、円周が長い分1周するための時間も長くなるからです

このように惑星の位置に応じて1年の日数は変化するため、例えば転生した先の恒星や惑星が太陽系と違う場合は1年の日数も変化してしまいます

1日の時間は地球では86400秒ですが、火星ではおよそ88950秒です
このように1日の長さは星ごとに違い、おそらく転生先の星も同様に変化すると思われます
また地球の自転速度も少しずつ変化するため、現在では太陽基準ではなく、セシウム133という原子を基準にしています
原子時計は簡単に作れる装置ではないため、おそらく転生先が剣と魔法の世界であった場合は正確な地球基準の秒を作ることは不可能でしょう
それに魔法が存在する世界であれば現代の物理と全く別の法則である可能性もあります


転生先の星の時間を測るには星座の観察で1年の日数を測定するのが一番簡単だと思いますが、それでも1日の長さが異なるので地球との変換はできません
もしも腕時計などを持ち込むことができればそれでおおよその時間はわかりますが、月差20秒の時計であれば365日で5分以上ズレるため、正確な時間は測定できないでしょう


他の物理単位として、距離の単位"メートル"があり、この単位もよく出てきますが、メートルの単位はそもそも1秒に進む光の距離の299792458分の1と定義されているため、時間単位が「日」とそれを数等分した世界では基準として存在できません
他の方法としては子午線を使う方法がありますが、これは惑星の直径に影響を受けるため使うことができません

他の長さの単位としてフィートが有ります
これはヒトの足のかかとからつま先までを基準とした単位なので、比較的異世界でも使いやすい単位といえます
ただし個人差があるので、予め異世界に行く前に自分の換算値を計測しておく必要があります

重さの単位としてキログラム(1000グラム)がありますが、これは1リットルの水の重さで、まず1リットルを測定するための基準(たとえば正確に10cm立方の箱)が必要なため、異世界で使いやすい単位とは言えないでしょう
他の単位としてはポンドがあり、これはひとりの人間が1日に消費する大麦の重さが基準であり、異世界に都合よく麦が主食とされている場合は比較的使いやすい単位です
もしかしたらすでに「1人が1日に消費する食材」という単位があるかもしれません
(そのような単位があったほうが買い物するときに楽だからです)


フィートやポンドは現代日本では使いづらい印象がありますが
SI単位系は相当技術が進んでいる世界でしか使えなく、基準が1つもない世界ではむしろ使いづらい単位となってしまいます

フィクションで他の惑星に移動するような作品を書く/読む場合は単位の違いも考慮にいれる必要が有ります

2013年10月15日火曜日

STM32F1 CANの速度

STM32F1のリファレンスマニュアル RM0008 Rev5 日本語版によるとCANの速度は以下のように説明されています


Rev14でも同じ内容です

実際にBaudRateを計算してみましょう
まずAPBクロックの周期とは
CAN1が接続されているAPB1のMax36MHzです
これでtPCLK = 36MHzの周期 = 0.027778マイクロ秒となります

次にtqですが ここにはBRP[9:0]というのが出てきます
これはCAN_BTRレジスタの中にあり
標準ペリフェラルライブラリ CAN_Initでは
((uint32_t)CAN_InitStruct->CAN_Prescaler - 1)
が他のレジスタとORで代入されています
つまりCAN_InitTypeDef.CAN_Prescalerに入れた値から1を引いた数が入ります
しかし計算時には1を足しているのでCAN_Prescaler*tPCLKとすることができます

Prescalerを6と仮定した場合
tq = Prescaler * tPCLK = 6 * 0.027778 = 0.166668
となります

tBS1とtBS1もTS1とTS2がありますが、これもCAN_BTRの中にあります
それぞれCAN_BS1_xtqとCAN_BS2_xtqという定数で設定し、1tqは0が 2tqは1が 3tqは2が~ という関係です
しかしこのレジスタも計算時に1を足しているので1tqが1 2tqが2として計算できます
CAN_StructInitではCAN_BS1_4tqおよびCAN_BS2_3tqが代入されるため
tBS1 = tq * BS1 = 0.166668 * 4 = 0.666672
tBS2 = tq * BS2 = 0.166668 * 3 = 0.500004
となります

NominalBitTimeはそれぞれを足し算しているだけですので
NominalBitTime = 1 * tq + tBS1 + tBS2 = 0.166668 + 0.666672 + 0.500004 = 1.333344
となります

BaudRateは1をこの数で割っているだけなので
1 / NominalBitTime = 1 / 1.333344 = 0.75
となり、ビットレートは0.75となります
しかし最初にtPCLKをマイクロ秒としているため、ビットレートの単位を合わせると0.75Mで、750kBit/secとなります
この結果はオシロスコープで実測した値とおおよそ一致します

実際にCANbusを使う場合はプリスケーラ10で450kbpsとなり、東陽テクニカのWebページを参考にした場合で100mほど距離の通信ができます
AWG23-24の線材を使った場合のノード数は100で、これは1m間隔に1ノード程度となります

一旦機器を設置してしまうとビットレートの変更は容易では無いため、実際にビットレートを設定する場合は設置する環境を十分に見積もった上で もしくは簡単にビットレートを変更できるように工夫するべきです
同一のCANバス内で複数のビットレートが混在することは許可されていないため、ビットレートの設定は十分に注意する必要があります

2013年10月14日月曜日

1WireのCRC計算

1WireのCRC生成コードです

      4 /* CRCを含めたデータサイズ(バッファサイズ) */
      5 uint8_t CalcCRC(uint8_t *pData, uint8_t DataSize) {
      6   register uint8_t *pCRC = pData + DataSize -1;
      7   register uint8_t dat;
      8   int i;
      9
     10   if (!*pCRC) { DataSize--; }
     11
     12   for (i = 0; i < DataSize; i++) {
     13     dat = pData[i];
     14
     15     *pCRC = ((dat ^ *pCRC) & 1) ? (((*pCRC ^ 0x18) >> 1) | 0x80) : (*pCRC >> 1); dat >>= 1;
     16     *pCRC = ((dat ^ *pCRC) & 1) ? (((*pCRC ^ 0x18) >> 1) | 0x80) : (*pCRC >> 1); dat >>= 1;
     17     *pCRC = ((dat ^ *pCRC) & 1) ? (((*pCRC ^ 0x18) >> 1) | 0x80) : (*pCRC >> 1); dat >>= 1;
     18     *pCRC = ((dat ^ *pCRC) & 1) ? (((*pCRC ^ 0x18) >> 1) | 0x80) : (*pCRC >> 1); dat >>= 1;
     19     *pCRC = ((dat ^ *pCRC) & 1) ? (((*pCRC ^ 0x18) >> 1) | 0x80) : (*pCRC >> 1); dat >>= 1;
     20     *pCRC = ((dat ^ *pCRC) & 1) ? (((*pCRC ^ 0x18) >> 1) | 0x80) : (*pCRC >> 1); dat >>= 1;
     21     *pCRC = ((dat ^ *pCRC) & 1) ? (((*pCRC ^ 0x18) >> 1) | 0x80) : (*pCRC >> 1); dat >>= 1;
     22     *pCRC = ((dat ^ *pCRC) & 1) ? (((*pCRC ^ 0x18) >> 1) | 0x80) : (*pCRC >> 1); dat >>= 1;
     23   }
     24 }

ROMコードであれば8バイトのバッファとバッファ長8を渡します
バッファはファミリコードが0バイト目 CRCが7バイト目になるような配列です
CRCが0の場合はCRCを生成し
CRCが0以外の場合はCRCを再計算します

CRCを生成する条件で読んだ場合はCRCの部分にCRCデータが入りますが
CRCを再計算する条件の場合は0になれば正常です 0以外の場合はCRCデータを含めいずれかの1つ以上のビットが破壊されています

上の*pCRC = ((dat ^...のコードはforで回すべきですが
今回は8回分ベタ書きしています
この最適化がどれくらいに効果があるかは不明ですが とりあえず気分の問題ってことで

2013年10月10日木曜日

VBAで気圧高度

Excel2007のVBA
Officeファミリはかなり昔から使ってますが
VBAなる機能を初めて使いました

気圧から高度に変換する関数です

Function Alt(気圧 As Double, 温度 As Double, 海面気圧 As Double) As Variant
    Dim h As Double
    h = (1013.25 / 海面気圧) ^ (1 / 5.256) * ((海面気圧 / 気圧) ^ (1 / 5.256) - 1) * (温度 + 273.15) / 0.0065
    Alt = h
End Function

一旦変数を書いてから関数に代入する必要があるらしい

あと冪乗計算がPowerじゃないってのにハマった
Cじゃ^記号はXORだし
Excelだって冪乗計算はPowerを使うのに
VBAは^で冪乗計算になる

VBA 便利のような… 便利じゃないような…

2013年10月8日火曜日

STM32F1 standard peripheral CAN

STM32F1のCAN周り覚書

なお古いライブラリ(少なくとも4年以上)を使っているので、最新とは違うかも

CanRxMsgの中身
    uint32_t StdId;
    uint32_t ExtId;
    uint8_t IDE;
    uint8_t RTR;
    uint8_t DLC;
    uint8_t Data[8];
    uint8_t FMI;

・StdId
標準の識別子 0から0x7FFの範囲

・ExtId
拡張識別子 0から0x1FFFFFFFの範囲

・IDE
受信したメッセージの識別子タイプ CAN_identifier_type

・RTR
受信したメッセージのフレームタイプ CAN_remote_transmission_request

・DLC
受信したフレームの長さ 0から8の範囲

・Data[8]
受信したデータ 配列は8バイト確保されている 有効なデータ数はDLC

・FMI
フィルタ関係?


CAN_identifier_typeについて
    #define CAN_ID_STD
    #define CAN_ID_EXT
    #define IS_CAN_IDTYPE(IDTYPE)
CANID_STDとCANID_EXTがある
それぞれ標準IDと拡張IDを示している
IS_CAN_IDTYPEは「引数がSTDかEXTならば0位外を返す」というマクロ
ただCAN_ID_STDもCAN_ID_EXTも中身はuint32_t
STDかEXTかを調べるには自分でifで判断する必要がある


CAN_remote_transmission_requestについて
    #define CAN_RTR_DATA
    #define CAN_RTR_REMOTE
    #define IS_CAN_RTR(RTR)
CAN_identifier_typeと同様

なお (CAN_RTR_DATA == CAN_ID_STD) == true という関係なので
例えばIS_CAN_IDTYPE(CAN_RTR_DATA)とやるとtrueになる(おそらく
このためIS_CAN_IDTYPEやIS_CAN_RTRはあまり信用しない方がいいはず


CAN_MessagePendingについて
宣言は以下のとおり
uint8_t CAN_MessagePending(CAN_TypeDef* CANx, uint8_t FIFONumber);

説明は以下
  * @brief  Returns the number of pending messages.
  * @param  CANx: where x can be 1 or 2 to to select the CAN peripheral.
  * @param  FIFONumber: Receive FIFO number, CAN_FIFO0 or CAN_FIFO1.
  * @retval NbMessage which is the number of pending message.
要約すると
説明:保留中のメッセージの数を返す
引数:CAN1もしくはCAN2 ペリフェラルを選択
引数:FIFOの選択 FIFO0もしくはFIFO1
戻り値:保留中のメッセージ数

何をする関数かというと、FIFOにたまっているメッセージ数を返す
中身は
(uint8_t)(CANx->RF0R&(uint32_t)0x03)
もしくは
(uint8_t)(CANx->RF1R&(uint32_t)0x03)
を引数に応じて返している

CanRxMsg構造体の中にはデータの有効性を確認するためのレジスタはない
また、CAN_Receive関数の中にもデータの存在を確認する処理はない
FIFOにデータが有ろうが無かろうがReceive関数を呼べばFIFOの中身を返してくる
しかしFIFOの中身が0であれば意味のない値になる
しかし意味がある値日意味のない値かは値から判断することはできない

実際にCANを使う場合は一定期間ごとにCAN_MessagePendingをポーリングして
戻り値>0が真の場合にCAN_Receiveを読んでデータを処理することになる


CANで1つのデータが一番短い時はRTRの37bit
1Mbpsで通信している場合40bitとして1回40マイクロ秒くらい
実際にはもっと長いけど、FIFOが4フレーム分3フレーム分しか無いことを考えるとかなり高速でポーリングする必要があるかも
といってもまぁものすごいクリティカルな用途でもなければ秒数百回程度ポーリングすれば十分なはず

最悪の場合スマートじゃないけどCanRxMsgの配列を作ってCAN受信割り込みでリングバッファに貯めこんで大容量のFIFOを作るってやり方もあるw

2013年10月3日木曜日

Raspberry Piでシリアル通信

Raspberry PiのUSBポートにFT232を接続し、シリアル通信を試してみました

例によってViのキャプチャで申し訳ないです

とりあえずググって出てきたページのコードをほぼそのまま使っていますが
一応通信出来ました

ポート名はcpPortNameに設定され、これは各自の環境で調べてください
例えば ls /dev/tty* コマンドをFT232を接続する前と後に実行し、増えた項目がそのポートのはずです(dmesgでもいいですが)

設定は基本的に初期設定から変更していません
このあたりは追々調べていきます

とりあえずgccでビルドして実行します

正常に通信できれば相手には上のように表示されるはずです


Linuxは最近のパッケージにはFT232のドライバが標準で付属していて、インストールの手間もなくサクッと扱えます これはRasbpianでも同じで、簡単にシリアルポートにアクセスできるようです

USB-TTL UARTの変換にはFT232シリーズがデファクトスタンダードとなっており、秋月のXBeeアダプタストリナのXBeeアダプタはこのICが使用されているため、RaspBiのシリアルポートを消費することなくXBeeを接続することもできるようになります
他にもFT232+レベル変換ICを使えば本来のRS232通信も可能となります

2013年9月29日日曜日

Lightroom4の残念なところ

Lr4の残念なところ というか、「どうしてこの機能はないの?」と思ったところ

Lr4にはスタック機能があって、複数の写真をグループにできたりする機能ですが、コレが弱い


まずスタックしたグループをスタック とかができない
例えば
「イベント○○のプログラム☓☓でグループAが発表している内容」がスタックA
「イベント○○のプログラム☓☓でグループBが発表している内容」がスタックB
とすると 「スタックAとスタックBをまとめたプログラム☓☓のスタック」を作ることができない
やろうとするとスタックAとスタックBが結合されてしまうので、グループAとグループBを分類できなくなってしまう


それと、スタックにタイトルをつけることができない
なので「n枚の写真が含まれたスタック」という情報と あとは周りの写真からそのスタックの内容を推測するしか無い

そもそもLr4の写真の管理の方法が間違っている気がしないでもないけど

もうちょっと写真をグループ分けしやすいようになっていればなぁ と思う次第

Lr5とかではどうなってるのかな?
4からアップグレードするにも微妙な値段で、趣味で写真を撮ってる僕からするとちょっと踏み出せない値段w

大量の写真の分類作業とかしないならLr4は十分に使えるソフトなのよねぇ…
(正直、レンズとか焦点距離で分類とかはいらない機能だと思うんだけどなぁ ズームレンズとか使ってると焦点距離のリストなんてどんどん増えるぞ。。。)

2013年9月28日土曜日

RasPiのピンヘッダ

Raspberry Piの大きなピンヘッダには色々なポートが出力されていますが、基本的には電源とGPIOです
GPIOは例のごとく複数の機能を持ったものがあり、どこに何を繋ぐかが問題になります

僕の例を書いておくと
GPIO25にLEDを吊り下げで接続
GPIO24にタクトスイッチをプルアップ(アクティブL)で接続
GPIO14および15のUARTをピンヘッダに接続
4ピン及び6ピンに電源を接続
という感じになっています
UARTを使うのはSSHで接続できない場合のためで、あまり使うことはありません

電源は通常microUSBコネクタで供給しますが
1) USBポート経由の給電はあまり評判がよろしくない(長時間の安定性がよくないらしい)
2) USB出力の高容量な電源の手持ちが少ない
というような理由により通常のDCジャックから供給しています
ただし電源の逆接や異常な電圧が供給された際の保護がないのでそのあたりは要注意です


他に余ってるポートはSPIやI2Cくらいで、あまり複雑なことはできない、もしくは非常に複雑になってしまいます
例えば、とある応用ページではパラレル接続のモジュールを使うためにシリパラ変換ICを複数個カスケード接続して実現しています
このような規模になってくると、せめて外部に小さなARMマイコンを1個置いてソフトウェアで処理する等の方がはるかにスッキリと実現できますが、そうするとRasPiを使う必要性も薄れるために難しいところではあります

RasPiで実現できる範囲はUSB接続ができるものや、Ethernetを使ったIO それ以外ではRasPi専用に設計されたモジュールくらいが限界のようです

僕の感想としては「帯に短し襷に長し」という感じで
より低レベルなIOが必要なら普通のマイコンで実現したほうが楽だし、データ処理をさせたいなら一般的なPCのほうがはるかに使いやすいです
RasPiの最適な用途はちょっとしたEthernetアクセスのサーバー あたりでしょうか
この場合もあまり高負荷なことはできないはずなので 非常に微妙なところではあります

RasPiをFT232の母艦に

RasPiのUSBポートにFT232を接続してみました
FT232は言わずと知れたシリアル変換ICで、LinuxなどはOSに標準でドライバが入っていたりします
Raspbianでも同じように、ドライバをいれる必要なく接続できました

screenコマンドがなかったため、apt-get install screenで入れてやりましたが、それ以外は特に何も必要ありません
もちろんSSHからscreenを叩いて送受信することもできます

ただ、欠点というかなんというか、僕の環境ではscreenを終了することができませんでした
もちろんsshを終了すれば接続は切れるのですが、デバイスが解放されているわけではないので、次に使うにはrebootが必要になります

ただその辺りを解決できれば ピンヘッダに出ているシリアルポート以外に、USB接続でシリアルポートを使うこともできるはずです


参考
http://tomono.eleho.net/2011/02/28/646/


2013年9月23日月曜日

C語でC++のclassっぽい関数呼び出し

C言語でC++等のclassっぽい関数呼び出しを試してみたので忘れないうちに書いておきます
以下コードが幾つか続くので、"もっと読む"で展開してください


2013年9月22日日曜日

気圧と海抜から海面気圧を求める

現在地の気圧[hPa]と現在地の海抜[m]から海面気圧[hPa]を求める式

P0 = P * pow((1 - (1 / (((T + 273.15) / (0.0065 * H)) + 1))) , -5.257);

P0 : 海面気圧[hPa]
P : 現在地の気圧[hPa]
T : 現在地の気温[degC]
H : 現在地の標高[m]
それぞれdoubleで宣言されています
pow関数を使用しているためmath.hも必要です

例えばmbedにGPSと気圧センサ そして液晶モジュールを接続すれば
GPSの絶対高度を使用して海面気圧を把握することも可能となります
この場合のGPS高度や現在位置の気圧は応答性よりも正確性が優先されるため、適切な平均化処理などが必要とされるはずです

整数で気圧高度の計算

整数だけで気圧高度を計算するライブラリを作ってみました
実際には浮動小数点のようにある程度正確な数値ではなく
予め作られた2つのテーブルを使用しているのでかなり容量を使います
テーブル1が800バイトと少し
テーブル2がおよそ15キロバイト
とかなり大容量になっています(ビルド後のサイズ/ソースはもっとデカい)

精度はどうかというと、さすがにちゃんとした固定小数点数等を使っているわけではないので浮動小数点数(double)には劣りますが、おそらく近似値を使った直線よりは高精度なはずです

縦軸が高さ 横軸が気圧 右軸が高度で左軸が誤差(共にm) です
海面気圧は101325Paを使用しました

er軸はdoubleで計算した値からどれくらいズレているかという数値です
1mから9m程度高くでていますが、
 気圧が低ければ誤差は下の方に集まり、
 気圧が高ければ誤差の振れ幅は少ない
という感じになっています

今回は計算のしやすさのために1hPa単位でテーブルを作りましたが
2hPa単位にするだけでテーブル容量ははるかに小さくなるため、気が向いたらその方向の改良もしていこうかと思います

誤差については、さすがに10m前後は見過ごせない大きさではありますが
しばらくは「そういうもの」と割りきって使うことになりそうです
おそらくこの変動はテーブルによる物だと予想していますが、実際に確かめたわけではないので、結局のところ原因は不明です

不正な値が入力された場合の挙動に対応できないことや、負の高度(P0>P)を正確に処理できないという問題があるので そのあたりも課題です

2013年9月17日火曜日

整数で平方根を計算する

整数で平方根の近似値を出力する関数です

int sqr(int sq) {
int j, i;
for (j = 1, i = 0; sq >= j; sq -= j, j += 2, i++);
if (sq > (j / 2)) { i++; }
return(i);
}

実際の計算結果は
上の図のようにある程度正確になっています
およそ±0.5の範囲です
コード中のif分を外せば+0から-1の範囲になります

計算方法は
http://www.wizforest.com/gear/tiger/sqrt/
を参考にしました

実際は別の方法が良いようですが、とりあえずこのコードでも遅い以外のデメリットは特に無いです

で、実効速度の問題ですが
sqr(自作)及びsqrt(math.h)の実行速度を計測してみました
(図中ではpowと書かれていますがsqrtです)

sqrt関数の処理時間はほぼ一定ですが
sqr関数はforでデクリメントしているため、処理時間は一定の法則で伸びていきます

上記コード中のsq,j,iにregisterをつけるとかなり早くなり、30000を超えてもsqrt関数より早くなります


FPUが使えるシステムでは整数で計算するメリットは全くありませんが、FPUがなく、ソフトウェア的に計算しているCPUや そもそも浮動小数点演算ができない環境ではある程度使えると思います

例えば3軸加速度からその物体にかかっている加速度は
加速度=sqrt((x*x)+(y*y)+(z*z))
で求められるため、缶サットなどで瞬間的にどれくらいの加速度がかかっていたか等を計算することができます
(加速度は単純に x+y+z という計算はしてはいけません)

2013年9月16日月曜日

STM32F1でTIMのパラメータ

STM32F1のTIMのパラメータ
この関数は引数1で与えた周波数になるように引数2と引数3のポインタにパラメーターを書き込む

// 0:成功 
// 1:システムクロックで割り切れない周波数 
// 2:プリスケーラの設定中に丸め誤差が発生した 
uint8_t TIM_GetFreqencyPrameter(uint32_t Freqency, uint16_t *pPeriod, uint16_t *pPrescaler) {
    const uint32_t cSysFreq = 72 * 1000 * 1000;
    uint32_t per, pre;
    
    if (cSysFreq % Freqency) { return(1); }
    
    per = cSysFreq / Freqency;
    pre = 1;
    
    while (per > 0xFFFF) { per /= 10; pre *= 10; }
    
    if ((cSysFreq / per / pre) != Freqency) { return(2); }
    
    *pPeriod    = per - 1;
    *pPrescaler = pre - 1;
    
    return(0);

}

なおシステム周波数はcSysFreq変数に設定され、この例では72MHzとなっている
計算上完璧な周波数以外は1or2が返される
正常な場合は0が返され、ポインタに値が設定される


とりあえず軽く動作確認はしていますが、使うときは自己責任でどーぞ
例えば7Hzや11Hzは作成できません
11Hzは整数で割り切ることができないので1が帰ります
7Hzは整数で割り切ることができますが、0xFFFFより大きな数字になってしまうため、丸め誤差エラーが発生し2が帰ります

ラッパー関数を作ればサクッとタイマの初期化もできますが、信頼性は低いのであまり多様しないように

2013年9月8日日曜日

STM32F103でCAN通信(その2)

CANトランシーバIC"MCP2551"が届いたので
試してみました

ソースコードは以前の流用です


赤がCAN-H 黄色がCAN-L
緑はその差分

上のキャプチャはふたつのMCP2551のTXとRXをキャプチャしたもの

CAN1TXから出力された信号はCAN1RXとCAN2RXから出てきています

上の画像は
000010100101000011010101010010101010000010001111101110000010011000001000111000010110
という感じのビットになっており
分解すると
のようになります

送信したデータは
Idが0xA5のスタンダード
データ長は6で0xAA 0x55 0x00 0xFF 0x01 0x80
です

5bitほど足りませんが、CRCの最後2bitが1であると仮定した場合は辻褄が合います
データの4byte以降が9bitなのはビットスタッフの影響です

今はひとつのマイコンから送信しているだけなので、次は他のマイコンで受信 などをしてみたいですね
それができたらなが~いLANケーブルでも買ってきて長距離通信やってみようかな

2013年9月7日土曜日

文字列バッファの位置を特定する

ある程度長い文字列をテストファイルとして書いたりする場合
「どこまで書けているか」を判断するのは意外と大変です
なぜかというと、charはそもそも8bitとして256種類しか表すことができず、さらに文字となると表すことができる範囲は更に狭くなります

そのため1024byteくらいのバッファをforで0-Fの範囲で埋めると
出てきた文字列がどの場所にいたのか判断しかねる時があります

その時に使える方法

2013年9月2日月曜日

STM32F1で送信バッファ

STM32F103VEで送信バッファを作ってみました
STM以外にも使えると思いますが


ヘッダファイルにdefineでUSART3writeLine(送信バッファを有効化するフラグ)とUSART3writeBufferSizeがあります
また、別の場所では #ifndef USART3writeLine で送信バッファを使わない送信関数もあります

送信バッファは受信バッファと違い、行識別等が不要なので関数2個といくつかの変数だけで実装可能です

2013年8月30日金曜日

STM32F103でCAN通信

STM32F103VE(事実上のSTBee)を使ったCAN通信のメモ
嘘偽りなく調べ物した時のメモとしてそのままブログのエディタを使ってるので可読性とかは気にしていません


2013年8月25日日曜日

PDS5022Sを外部電源で

暇つぶしというか ネタ探しを兼ねて
PDS5022Sのバッテリー機能を試してみます

もともとこのオシロは低価格デジタルストレージオシロスコープとして発売されていました
僕は秋月で書いましたが、すでに型落ちとなっています
amazonとか他のショップでも販売していましたが今はどうなっているかわかりません

100MS/sで25MHzの2ch+1trgという構成です
デジオシなのでFFTとかも使えます
PCとUSB接続してグラフを保存とかもできます
(僕のPCは相性が悪くて使えませんが)

で、このオシロはLiPoによるバッテリー駆動が可能ですが
輸送の関係かわかりませんが国内版は電池がありません
(空輸する場合電池類は基本的に同梱不可能)
しかし違いは電池の有無だけで、機能的には同じ物のようです

ってことで動作電圧のチェック

基本的にFullで8.3V 6.5Vを下回ると警告表示
という感じのようです
また6.5V時では1.2A近く流れています

LiPoは公称電圧3.7Vなので 2セルの公称電圧は7.4V
終止電圧は3.0Vなので セルでは6V

という感じで、警告表示は比較的余裕のある表示となっています
また電池警告が表示されている状態でしばらく放置していると
"LOW BATTERY"という文字も表示されます
ただし自動的に電源がOFFになることはなく
手動で電源を切る必要があります


電池駆動する場合の条件として

  • 7.4V前後(7Vから8V)を供給できる
  • 常時1A以上流しても問題ない
  • 少なくとも2時間くらいは使えるように

をクリアするためには
まっとうな方法で行けば2セルの3AhLiPoを中に仕込む感じになります

ただ、個人的にはこの方法ではなく
Ni-MH等を使いたいと思っており
例えばニッケル水素電池8セル(9.6V)を降圧して7.5Vくらいにしてから端子に入れる
充電は専用回路を用意する
という感じにしたいなと思ってます

一応裏蓋の中には単三型eneloop8本を入れる余裕はありますが
電子回路を入れる余裕が全くありません
逆にeneloop6本程度であれば電子回路を入れる余裕が生まれます
Ni-MH6セルでも動作は可能のはずですが、おそらくバッテリー警告がうるさいはずなので
実際に使う場合は昇圧が必要でしょう

オシロ本体に充電回路が内蔵されてるのになんでわざわざ外付けするのかとか
中でDCDC通してるのになんで外でDCDC通すのかとか
いろいろ突っ込みたいところはありますが
まずは構成を考えるということで


「こんなかんじにしたい」というのは有るんですが
実際にサイズ的な話になると不可能だったり
既成品の改造は結構面倒ですorz

2013年8月1日木曜日

KindlePW 買っちゃいました

Kindle 買っちゃいました
金欠気味だったのでWiFiモデルですが
わっ ワイファイモデルのほうが軽いからいいんだもんっ!

ってことで開封の儀を写真を交えてレポート

Kindleの化粧箱
ほかのモノと一緒に買ったのですが
この箱が普通の商品と一緒にシュリンクされて届きました

この箱は普通の立方体と違って 写真で上部の面が斜めになっています

箱端面には kindle paperwhite とロゴが書いてあります


箱を開封する方法はこんな感じ
いかにも「amazonの箱」らしい方法です
引っ張り始める場所は簡単に見つかります



箱を開けるとこんな感じでKindleが入っています
もうこの箱は閉まりません
何か重りか 輪ゴムが必要


フタ側のポケットには小冊子が2冊入っています
黒いほうが充電方法
白いほうが利用規約等
です
ページ数はありますが 様々な言語が書いてあるだけで
すべてのページがほぼ同じ内容です


Kindle本体の下にはmicroUSBケーブルが入っています
これは何の変哲もない一山いくらのケーブルだと思います
amazonロゴも入っていません
amazon BasicsでmicroUSBも売ってるんだから それを入れてほしかった


Kindleの裏にはこんなかんじにロゴが入っています
Nexus7のウラのロゴとかと同じ感じ
着色したパテで埋めても面白いかもw


箱から出した時点でこのような表示になっています
電源を切っていても画面が保持されるという電子インクの特性を利用した説明

端末の下はこんな感じ
左がmicroUSBコネクタ 右が電源ボタン
Kindleは電源以外にスイッチはひとつもありません
輝度の調整等もすべてソフトウェアで実装されています

起動すると言語選択が出てきます
ここは日本語に設定

少し待つとWi-Fi接続画面が出てきます
SSIDの一覧を選択してパスワードを入力します

設定が終わるとチュートリアルが始まります
とりあえずすぐ終わるので従いましょう
というか途中でやめるとかできないので

チュートリアルが終わればすぐに使いはじめることができます
僕はiPadなどで読んでいた書籍が有ったので
それをKindleに落とせばすぐに読めました
1回もamazonでKindle書籍を買ったことがない場合はなにか買うか
無料の書籍を探しておく必要があります


画面右上には各種情報が表示されます
画像では WiFi強度 電池残量 時間 が表示されています
時間はUTCが表示されいるようです 
日本語に設定されたら日本標準時間(JST/UTC+9)に設定されて然るべきですが
タイムゾーンの変更方法はまだ見つけていません
時間はWiFiで初回接続時にNTPで同期されるようです
この時間は 最後に書籍を読んだ場所を端末間で同期する という機能のために必要なので
手動で合わせることも可能ですが それは最後の手段として使うべきでしょう


やはりE-Inkを使ってる以上画面の切り替えに妙なタイムラグと言うか表示切替がありますが
予想よりもかなり短い時間です
E-Inkはむか~し ソニー製端末をちょっと見ただけなので
かなり印象が悪かったのですが

Kindle PWはめちゃくちゃ軽いし
かなり使いやすいです
ヘタをするとiPod touch 4と同じくらいの重さでしょうか

仰向けで読んでいる時に片手でページ送りをするのが大変な気もしますが
これはKindleに限ったことでもないですし

とりあえずしばらく使ってみようと思います
折しも明日は泊まりで出かけるので 移動時間等に読んでみようかなと思います


2013年7月22日月曜日

Cで固定小数点

C語で固定小数点の文字列化です
string.h関数が必要になります 使ってるのはstrlenだけなので適当に実装してください
関数は2つあります
strAddは再帰を使ってます
場合によっては30回以上再帰します

以下コード

2013年7月13日土曜日

AD9834の制御

AD9834の制御について


AD9834というDDSモジュールを試しています
何かに使う予定があるわけではないですが

とりあえず上記関数ひとつで制御出来ます
定数0x2028というのは
ストリナのサンプルでは0x2020ですし データシートには0x2000が書いてあります
この辺りはフラグになっているのでデータシートで確認する必要があります

この関数はストリナのモジュールに合わせて書いてあるので
発振器が67108864Hz以外の場合は定数を変更する必要があります
またこの関数に与える引数はHzではなく 0.25Hz単位となります

SPIでも制御できると思いますが
それほど面倒ではないのと 送信だけなのでソフトウェアで書いてあります
もっと高速に転送したければ直接レジスタを叩くように書き換えてください


とりあえず備忘録ってことで

2013年7月3日水曜日

XcodeのCommand-BでSTBeeに書き込む

MacでビルドしたコードをSTBeeにDFUを使って書き込むと言うのは以前からできていましたが、いちいちターミナルでMakeを叩いてやる必要がありました
警告やエラーをちゃんと表示してくれるので便利といえば便利ですが、ちょっと面倒になってきたので、雛形を作り直すついでにXcodeからビルドしたり書き込んだりできるようにしてみました

僕はXcode3を使っています

追加するターゲットはExternal Targetです
コイツを追加してやれば特に設定もなくMakefileを叩くことができます
が、これだけではエラーでビルドできません
Makefile内ではGCCは相対パスになっているし、そのほうが色々と便利なのですが 絶対パスで指定してやる必要があります
もちろんDFU-UTILも絶対パスが必要です

僕はターゲットを2つつくり、標準のターゲットがMake clean build もうひとつがMakeでオプション無しです
コードを書きながらMake clean buildでエラー等を確認し、警告が出なくなればオプション無しで書き込み という手順です
ただあまりにも大きなコードになってくると毎回Cleanすると面倒なので そこは追々なんとかします

2013年6月26日水曜日

グラフィックLCD

グラフィックLCDを使ってみました

今回使った液晶は秋月で売っている128x64のタイプです
http://akizukidenshi.com/catalog/g/gP-03413/
TG12864E-01XWBV というやつです

この液晶は電源やバックライトを含めて20本の配線でドライブできます
キャラ液晶と違い常に8bitで通信し
Ena信号だけでなくCS(Chip Select)端子が2本存在します


128x64ピクセルなので、8x8pxの美咲フォント等を使用した場合16文字x8行書くことができます
もちろんグラフィック液晶なので自由な液晶や図形を書くことができます

上の画像のサンプルでは直線を2本 正方形と真円を1個ずつ それから文字列を書いています

この液晶は1ピクセルの大きさが横1対縦1.2程度なので正方形を書いても実際には正方形にはなりません

今回はSTBeeMiniに接続し、美咲フォントと自作のUTF8toShift_JISテーブルを使用しています
とりあえず動作確認が目的なので変換テーブルは第1水準漢字しか実装していませんが、それでも全体で92kにもなり、STBeeMiniのROMギリギリです(DFUの転送には1回30秒もかかってしまいます)

参考までに今回作った基板の実体配線図を添付しておきます
図右上に10kΩのボリュームが有り、コントラストを調整しています
VDD(5V)とVEE(-10V)の間に接続しています
もしもこの図を参考に作ろうという人がいるなら、ボリュームのVDDとVEEを逆にすると幸せになれるはずです

RSをPB0に接続したほうが簡単に作れますが 今回は諸事情でPB2から配線しました

この液晶は常に8+4+2を専有しているくせに、アクセス速度はやたら遅いので
あまり実用的な使い方はできなさそうです

2013年6月25日火曜日

気圧から高度を計算

2箇所の気圧と1箇所の気温から高度を計算する式
C#ですが簡単な手直しでほかのコードでも使えます

/// <summary>
/// 気圧と気温から高度を計算
/// </summary>
/// <param name="p">計測地点での気圧[hPa]</param>
/// <param name="p0">海面での気圧[hPa]</param>
/// <param name="t0">p0を計測した地点での気温[℃]</param>
/// <returns>高度[m]</returns>
double hPa2m(double p, double p0, double t0) { return ((Math.Pow(1013.25 / p0, 1 / 5.256) * ((Math.Pow(p0 / p, 1 / 5.256) - 1) * (t0 + 273.15) / 0.0065))); }

基本的に使い方は特殊な部分は無く、double3個の引数とdoubleの戻り値です

なおこの計算方法では高度10km程度までしか計算出来ません

一応この計算方法で大きく外れた値が出ていないのは確認済みですが各自の責任で使用してください

2013年6月22日土曜日

Blackberry Trackball

ブラックベリーのトラックボール ブレークアウトボードを買ってみました

ちょっと興味があって確保しただけで何かに使う予定はないですが
とりあえずmbedで動作確認をしたので報告

かなり暗い画像ですが、これ以上明るくするとトラックボールのバックライトの色合いがわからなくなってしまいます

このトラックボールはホールセンサを使用して回転を検出するタイプで
チャタリング処理が必要ありません(クリックボタンはタクトスイッチなのでチャタリング処理必須)
しかも回転方向毎で計4出力があるので
変化したピンの方向にインクリメントするだけなのでかなり楽です
今回はTickerを使いましたが、ピン変化割り込み等の方が楽だと思います
変化割り込みの場合は検出は立上がりと立下りの両エッジを検出するほうが無難です

そしてこのトラックボールにはLEDが内蔵されており、
単純な3色フルカラーではなく、Whiteを含んだ計4色となります
上の画像の状態はRGBWそれぞれ100%です
かなり赤っぽい感じになります
クールホワイトを表示したい場合はRGBWでFF,FF,00,FFくらいがちょうどいいくらいです
白だけを点灯させた場合は微妙に黄色っぽい白となります(電球色ではないです)
内蔵LEDはカソードコモンになっているので点灯させる電圧には注意が必要です
一応180Ωの抵抗がそれぞれのLEDに接続されているのでマイコンに直結できますが
3.3V駆動ではかなり暗いです
完全な暗闇で自分の居場所を誇示するには十分ですが
動作状態を示す用途に使用する場合は明るい環境での視認性が悪くなると思います
わざわざ5Vを引っ張ってトランジスタ等でドライブというのも面倒なので
このトラックボールのバックライトを使う場合は5V動作のマイコンを使うといいかもしれません
Arduinoとか そっちの方を


内部処理的には面倒なことはしていないのでソースコードは載せませんが
トラックボールの検出とLEDのPWMをひとつのタイマ割り込みでやろうとすると面倒になります
トラックボール自体の割り込みは数十mSec程度で十分ですが、LEDはPWM分解能に合わせて十分に速い速度で制御する必要があるからです

それとSparkfunの例によって取り付け穴は横方向にハーフピッチずれています
なのでコネクタとネジ穴の両持ちをする場合はハーフピッチのユニ基盤か、自分で基板を作る必要があります
ブレークアウトボードのブレークアウトボードとかいうワケわからないことになりそう。。

コネクタは電源含め11本出ているので、コネクタをつけるのは現実的ではないかもしれません
ピンヘッダを使うか、さもなくばフラットケーブルを直接ハンダ付けというのがいいでしょう
ケースを使わずに直接基板に固定する場合はソケット等を使わずにピンヘッダの両端にハンダ付けするというのもひとつの方法です
ただしネジ側を固定しないとクリックはできません

今回は2個買いましたが、双方の基盤でクリックの感触が異なります
カチッと押した感じがするものと、押したかどうかわからないものです
クリックは微妙に検出しづらい時があるので、あまり多用しないほうがいいかもしれません

値の変化等に使う場合はまっすぐ上に動作させてる気でも実際には横方向にも入力されていたりするので スイッチ入力の代わりにカーソルを移動したり値を変化させたりという用途には向かないですが
GUI上でマウスポインタを移動するような、ある程度遊び幅のある用途に使うことが望ましいでしょう

2013年6月20日木曜日

.NetMicroFramework

諸事情でNetduinoを買いました。正確に書くとNetduino Plus 2となります。
STM32F405RGを使用し、Microsoftの.NetMicroFrameworkが入っているため、Visual C#で開発することができます。
端的に説明すると、Arduinoのような使いやすさで、mbedのような高性能を、Windowsと同じようにコーディングできる。という感じでしょうか。
NetduinoはArduino形状なのでmbedほど使いやすいわけではないですが、EthernetやmicroSDソケットが搭載されていたり、比較的使いやすい形となっています。
VisualC#が標準の開発環境となるため、mbed等のように見づらく操作しづらく使いにくいIDEではなく、非常に高性能な予測入力が使用でき、インデントなども自動で行われ、カスタマイズも容易です。
もちろんソースコード内に日本語を記述でき、printDebugでも日本語や漢字を使用することができます。VisualC#でソースコードレベルでデバッグが可能なのでバグの発見や駆除も容易でしょう。

タイマ割り込みを使用したLチカ
Lチカ程度なら簡単に記述でき、タイマ割り込みを使用するのも宣言を含めて1行でできます。C#なので多重定義も使用でき、簡単に使用したい場合やより高度な設定をしたい場合でも同じ方法で初期化できます。

欠点を挙げるとすれば、Arduinoやmbedほど日本で普及しているわけではなく、情報量がさほど多くないことや、コードを書き込む際の安定性の問題があります(mbedのようにファイルをコピペする形式ではなく、VisualC#から転送する 昔使っていた時に頻繁にエラーが出ていた 最近どうなったかは知らない)。


Timerを使用することによりタイマ割り込みを使うことができますが、.NetMFWのタイマ割り込みはハードウェア処理ではなく、ソフトウェア処理のため、CPUリソースの許す限りいくつでも可能という利点があります。これはコードの動作を短い時間に区切って割り当て、常に時間を監視して、ちょうどいいタイミングが来たら関数を呼び出す、という動作をしているためです。そのため時間の正確性については微妙なところがあります。ただミリ秒やマイクロ秒といったものすごく短時間の精度が要求される場合は普通のマイコンに直接コードを書き込んだほうが安心できるでしょう。

Netduinoの入手ルートは現時点ではスイッチサイエンスが簡単です。
少し遊ぶ程度ならNetduino2でもいいですが、SDカードへのアクセスやEthernetを使おうと思うならNetduinoPlus2が最良の選択だと思われます。
他にも.NetMFWが動くボードはありますが、僕は使ったことがないので評価出来ません。

2013年6月19日水曜日

圧力センサ

気圧センサの次に書くエントリとしてなんとも微妙な感じですが
今回は圧力センサの話です

・気圧センサと圧力センサの違い
基本的に気圧センサというのは読んで字の如く気体の圧力を測定するものですが
狭義では大気圧を測定するためのセンサという認識です(あくまでも僕の考え方)
大気圧というのは数十kPaから130kPa程度の範囲です
対して圧力センサというのはあらゆる圧力を測定できるセンサという認識です
もちろん気圧センサも圧力センサの一部です
基本的に今まで圧力は気圧だけを測定していましたが
次は地球の内部に向かっていく方向も測定したくなり
圧力センサを買う流れとなりました

例えば水は10m毎に1気圧増加するので、現在の水圧を測定すれば現在の深度もわかるというわけです

そこで今回は0MPaから1MPaまで測定できるセンサをRSで買いました
1MPaというのは高圧ガスの問題で校正が面倒というのと
深度100mがおよそ1MPaになるので さすがにそれだけ測れれば十分だろうという考えです

今回買った圧力センサは電流出力で
計測部にかかる圧力に比例して電流が増加していきます
なお計測部の動作電流としてオフセット4mAが設定されています
直接電流を読んでもいいですが、基本的にマイコンのADCは電圧検出のため
一旦抵抗器を介して電圧に変換しています
抵抗器はメーカーPDFの使用可能範囲から、簡単に計算できる100Ωを選択し、センサと一緒にRSで買いました(0.05%品で2800円でした ぼくが普段使っている抵抗の2800倍 もしくは14000倍です コレだからn倍って表現は好きじゃないんだよ。。)

なお、センサの特性上電源電圧が8-30V必要で
抵抗を100Ωとした場合の電圧範囲は10-26Vです
一般的なマイコンの電源範囲ではないので、専用の電源が必要になります
PINフォトの放射線検出から30Vを受け取って7812を介すとか
さもなくば5Vから昇圧DCDCで15Vを作るとかしなければいけません


今回はセンサの動作確認が目的だったのでAC100Vからスイッチング電源で15Vを作成し、値はテスターで読みました

近所の知り合い宅のコンプレッサーを借りて試験しました
0MPa-1MPaだとコンプレッサーの圧力範囲なので楽

センサは開口部がG1/4になっているので市販のG1/4ハイプラグカプラメネジを使えば簡単にコンプレッサーと接続出来ます

0.5MPa単位で測定しプロットしたグラフがこちら
※1) 0.5MPaは測定していないため0V
※2) 動作電流4mAのオフセットとして4Vがあります

良い感じに0から8MPaまで直線になっています
もう少し詳しく計測すればマイコンでADCした結果から圧力を計算することも可能でしょう

とりあえず第一目標「高圧を測れて液体にも耐えられるセンサを探す」はクリアしました


なおこのセンサは専用のケーブルなどと組み合わせた場合に最高の性能を発揮出来ます
上の写真のような使い方はしないほうがいいです