Showing posts with label Python. Show all posts
Showing posts with label Python. Show all posts

20170618

ターミナルで図の表示

C100PAでPythonを使えるようになったは良いけど、図の表示が出来なかったのでアスキーアート的な?解決策を取ることにしました。
結構頑張ったので、折角なのでUP。


CUI + PythonでCUPyと名付けました。
適当にパスの通っているところにコピーしてインポート。
プログレスバー、プロット、バープロット、ヒストグラム、画像表示をターミナル上で行えるようになります。
他のモジュールのインストールをせずに済むように、内部ではsysとmathだけ使っています。
色付けはANSI escape codeというのを使ってフルカラーになっていますが、この方法だとWindows環境では表示されないです。
でも、Chromebook以外にもLinux Mint上でもフルカラーになることは確認済み。
皆さんもLinux環境へ是非どうぞ。

プログレスバー
0~1の範囲で長さが変わって、色やシンボルの変更が可能。

プロット
こちらも色やシンボルの変更が可能。シンボル間を線でつなぐとか、そんな高等なことはムリなので単なる散布図となります。

バープロット
個別の色付けもOK

ヒストグラム
ビン数を指定しなければ自動で良い感じの数にします。(中学だったか高校だったかで習ったスタージェスの公式。他のでもよかったですが、何となくコレで。)

画像表示
カラーマップはjet, hsv, bkr, bwr, gray, red, green, blue, cyan, magenta, yellowを用意。
N x M x 3のようなRGB画像も表示可能です。

とまあ、こんな具合です。プロットなどの表示を軽くしたり、軸をつけたりするのが今後の目標ですが、いったん作って欲も満たされたのでそのうちやるかやらないか、と言った感じです。

20140310

ステロイド凄いね!

痒くてしょうがなかったのが、みるみる治っていくよ!

さて、准教授へのプログラムetcの納品、ひとまず完了しました。
が、すかさず「○○も見れるようにして」と追加依頼を言われたり、ちょっと動作の不安定なのがあったりと、どうもスッキリしない結果です。
というかもともと准教授自身が「解析はMatlabでやるから」と言ってたはずなんですけども!
だからPythonで作ってるのにわざわざmatで出力してるんですけども!
自分でいじらないなら「みんなのPython」返して欲しいんですけども!


20120405

なんちゃってオシロスコープ

久しぶりのUSB-1608FSネタ。

前回LEDを点滅させた頃には、実は既に取り込み自体は出来てたんですよ。
SnoopyProの結果から「使用チャンネル: 0番、サンプリングレート: 1Hz、レンジ: 10V」で取り込む場合には、色々省略すると
USB1608FS.ctrl_transfer(0x21, 0x09, 0x0, 0x0, [0x43, 0x01])
USB1608FS.ctrl_transfer(0x21, 0x09, 0x0, 0x0, [0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
USB1608FS.ctrl_transfer(0x21, 0x09, 0x0, 0x0, [0x11, 0x00, 0x00, 0xc0, 0x03, 0x10, 0x00, 0x08, 0x95, 0x98, 0x04])
取り込みストップ、レンジ設定、チャンネル・サンプリングレート設定?した後に
USB1608FS.read(0x83, size, interface=1)
ただ、これで返ってくる値は
array('B', [238, 141, 240, 141, 240, 141, 239, 141, 239, 141, 239, 141, 239, 141, 239, 141, 239, 141, 239, 141, 240, 141, 87, 138, 203, 4, 117, 7, 171, 8, 248, 8, 129, 9, 42, 10, 161, 10, 219, 10, 99, 11, 33, 14, 0, 14, 159, 14, 9, 14, 133, 13, 99, 13, 170, 10, 143, 10, 8, 11, 11, 11, 134, 1])
例えばこんな感じで、どれが目的の値なのか分からない。
というのも、今回用いているUSB-1608FSは解像度?量子化レベル数?が16bitなもんで、2進数なら16桁、16進数なら4桁、10進数なら…まあ桁で表現しづらいですが0-65535の値を取り得る訳ですよ。
どうみても過剰な要素数(=64)の値が返ってきてるんですよ。


ここでSnoopyProに戻ると、値は異なりますが、先程の値に対応しそうな結果はこちら。


どうやら、個々の要素は16進数の2桁分みたい。
ということは、2個の要素をくっつければ1個分になるのではないかと。
それでも32個分のデータがあるわけですが…アナログ8チャンネル+デジタル8チャンネル…で、あ〜まだまだ余りますね。
よく分からないので、この点に関してはまた追々。


さてPythonの方に話を戻すと、目指すは、10進数*2要素→8bitの2進数*2要素に変換・結合→10進数(0-65535)→電位(V)。
10→2進数変換はbinを用いていい感じのヤツ作りました(下記のソースコードのdec2bin参照)。
2→10進数変換はPythonが勝手にやってくれる(0b10とか入力すると2とみなして処理してくれる)ので気にする必要はなし。
0-65535の値を電位に変換するにはサードパーティ製ドライバのソースコード(C言語)を参考に
Volt = (Decimal-32768)*10.0/32767
すると良さ気。
つまり32768(65535+1の半分)が0になるようにベースを調節してやって、レンジに合わせて1量子化レベルあたりの電位を掛けてやる、という具合。
図解するこんな具合。
公式の取扱説明書から拝借。


本当は、ソースコードでは更に補正値として1.17が掛けてあったのですが…まあとりあえず無視。


以上を踏まえ、サードパーティ製ドライバのソースコードを参考にしまくって作ってみたのが、タイトルにある「なんちゃってオシロスコープ」

usb1608fs_oscillo.py
import usb

def Initial():
     USB1608FS = usb.core.find(idVendor=0x09db, idProduct=0x007d)
     for i in range(7):
     if USB1608FS.is_kernel_driver_active(i):
          USB1608FS.detach_kernel_driver(i)
     USB1608FS.set_configuration()
     # ch0-0 1Hz 1sample 10V
     USB1608FS.ctrl_transfer(0x21, 0x09, 0x0, 0x0, [0x43, 0x01])
     USB1608FS.ctrl_transfer(0x21, 0x09, 0x0, 0x0, [0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
     USB1608FS.ctrl_transfer(0x21, 0x09, 0x0, 0x0, [0x11, 0x00, 0x00, 0xc0, 0x03, 0x10, 0x00, 0x08, 0x95, 0x98, 0x04])
     return USB1608FS

def dec2bin(decimal, digits):
     binary = bin(decimal)[2:]
     if len(binary) < digits:
          binary = '0'*(digits-len(binary))+binary
     return binary

USB1608FS = Initial()

i = 0
while True:
     PIPE = i%6+1
     O = USB1608FS.read(0x80+PIPE+2, 0x40, interface=PIPE, timeout=1000+100)
     V = (int(dec2bin(O[1],8)+dec2bin(O[0],8),2)-0x8000)*10.0/0x7fff
     Vdisp = int(round(V*5.0+50))

     print ' '*(Vdisp-1)+'|'

     i = i+1


取り込みで沢山返ってくる値の内の第1、第2要素だけを抜き出してきてます。
ただ、他の要素も大体連動して同じような値になるので、結局のところどの要素に着目すればいいのやら…
チャンネル数を増やして、別々の値を掛けて…とかすれば分かるのでしょうけれども…それもまた追々。


matplotlibとか使って見栄えよく作ろうとしたんですけどね…アニメーション化の方法分からない…
でも、これはこれでシンプルでいいですよね?
16bitを全く活かせていない、7bit程度で十分な感じですけど。
ただ、こうなると、横スクロールさせたくなってしまいます。

20120225

Blink the LED!


前回に引き続きUSB-1608FSネタ。

あの後、取り込みを行おうと色々やってみても上手くいかなかったので、とりあえずより簡単そうな「LEDの点滅」でヒントを手に入れようと。
参考にしたのはSnoopyProの出力とUSB-1608FSのLinux向けサードパーティ製ドライバのソースコード(C言語)
それと、数々の先人達のページ等々(最後に列挙)。

SnoopyProは、PCとUSB機器の間で行われる通信を「嗅ぎ回る(snoop)」ソフトウェア。
上の画像のような結果が得られます。
因みにアイコンはスヌーピー。
ヘルプも読まず、しばらく使い方が分からずにいたのは自分です。
これは残念ながらLinuxでは使えなかったのでWindowsでsnoopしました。

ドライバのほうは、これを入れてしまえばPythonからC言語のライブラリを扱えるctypeで使うことが出来る、と踏んでいたのに上手いことインストール出来ず断念。
中でやっていることをPyUSB的に書き直す、という具合のことをやっております。

さて、USB-1608FSに付属のInstaCalでインジケータLEDを点滅させたところまでのsnoop結果が上の画像になります。
初期化云々で436パケット、その後のLED点滅で2パケット増加しましたので、その最後の2パケットに「LED点滅命令」が含まれているはず!
「TransferBuffer」のある227 out downが怪しいと考え、各種引数に対応する(と思う)値を代入して

USB1608FS.ctrl_transfer(0x22, 0x09, 0x40, 0x02, [0x40, 0x00])

しましたが

USBError: Input/output error

ここでまたもやしばらく悩むことに。
しかしながら何故か閃き

USB1608FS.ctrl_transfer(0x21, 0x09, 0x40, 0x02, [0x40, 0x00])

という具合に第1引数(bmRequestType)を227 out downに続く227 out upで使われている値に変更したところ、通った!点滅した!


よし、この勢いで取り込み!
とはいきません…


因みに

USB1608FS.ctrl_transfer(0x21, 0x09, 0x0, 0x0, [0x40, 0x00])



USB1608FS.ctrl_transfer(0x21, 0x09, 0x40, 0x02, [0x40])

でも点滅したので実際のところ重要なのは「0x21」「0x09」「[0x40]」っぽいです。
最後の引数はリストにしないと「繰り返し不可」みたいなエラーが返ってきます。



参考ページ

libusbについて - Linux工作室
技術資料 - C言語 演算子
libusb: Synchronous device I/O
libusb-1.0 – libUSBとは 技術解説 電子デバイス・半導体 : 富士通usb
Hacking the Kinect - How to hack USB device drivers

20120216

detach_kernel_driverしまくってやればset_configurationが上手くいく



久々に真面目な話。
現在進行中の作業を公にすれば途中で投げ出すこともなかろうと。
それと、作業中にリファレンスが少なくてうがぁぁぁぁ!!となったので、このログが誰かの参考になれば幸い。


ここ最近、新しい実験システムの構築に取り組んでおります。
”出来るだけ安く”を目標にUbuntu+Pythonで作ろうとしているのですが、データ取り込み・A/Dコンバータ操作でハマり気味。
因みに現在はWindows XP+MATLABで実験しています。
MATLABなんて大体の研究室にあるんじゃないの?なんて考えていますが、今後それのない研究室にも移ることの出来るように、先にフリーのプログラミング環境であるPythonの勉強をしておこうかと。
それと趣味。
まあいくら金をかけたくなくてもPCだったり、アンプだったり、モニタだったり、今詰まってるA/Dコンバータだったりは必要なわけですが。
そもそも、今後移る先が電気生理の研究室では無い可能性もありますが。
そんな時でも、どんな時でも、出来る事は多いに越したことはあるまい。


さて本題。
開発環境はUbuntu 11.10 64bit。
使用するA/DコンバータはMeasurement Computing USB-1608FS
USB接続のこいつには公式のUbuntu(というかLinux)用ドライバが存在しないので、PythonからUSBを操作するPyUSBを用いて

import usb
USB1608FS = usb.core.find(idVendor = 0x09db, idProduct = 0x007d)
USB1608FS.set_configuration()

なんてやるとまずはPermission Deniedになりましたので、/etc/udev/rules.d/に中身が以下の60-mcc-usb1608fs.rulesなるファイルを作ってやりました。

BUS=="usb", SYSFS{idVendor}=="09db", SYSFS{idProduct}=="007d", MODE="0666"

Measurement Computing社(SYSFS{idVendor}=="09db")のUSB規格(BUS=="usb")のUSB-1608FS(SYSFS{idProduct}=="007d")が接続されたら、そいつの読み書きを許可(MODE="0666")しますよ、ということらしいです。
この会社の装置用の、Linux向けドライバを作ってるところ(ココ)を参考、というか必要部分だけをわざわざ抜き出しただけなのであまり理解出来ておりません。
まあでも一応こういうサイトは読みました。
SYSFS{idVendor}=="09db", SYSFS{idProduct}=="007d"だけで装置は一意に定まるのでBUS=="usb"は不要な気はしますが試していません。

さて、このファイルを作ったらTerminalで

/sbin/udevadm control --reload-rules

をやって、rulesファイルを読み込ませてやって、再度

import usb
USB1608FS = usb.core.find(idVendor = 0x09db, idProduct = 0x007d)
USB1608FS.set_configuration()

で今度は

USBError: Resource busy

と言われ、数日ハマってしまいました。
ググッてみるとdetach_kernel_driver()すればいいということは分かったのですが、引数がよく分からない。
interfaceってそれなんぞや?
とりあえず適当に0を入れてみたら

USB1608FS.detach_kernel_driver(0)

回りはしたのですが、それでも依然Resource Busy。
set_configuration()と同じ引数(装置依存のbConfigurationValueなる値、USB-1608FSの場合は1だが、指定しなければ内部で適当な値を見繕ってくれる)を入れて回してもResource Busy。

じゃあ色々な値を引数に取り得るので、片っ端からdetachしてやろうじゃないかと。

for i in range(100):
    if USB1608FS.is_kernel_driver_active(i):
        USB1608FS.detach_kernel_driver(i)

0-99の引数でdetach。
この値のレンジに特別意味はありません。
if USB1608FS.is_kernel_driver_active(i):で元々detachされてる数字は除外。
これでResource Busyにならなくなりました!
因みに、どの引数でdetachされるのかを見るためにprint iをつけてみると

0
1
2
3
4
5
6

が出力されましたので、forループはrange(7)で良さ気?
そもそも、この中のどの値のせいでResource Busyだったのかは調べていません。
たぶんどれか一つでいいのでしょうね〜

さて、これで早速記録可能か!?と喜びも束の間、なかなか先に進めずにまたもや数日ハマっているのが現在の状況です…
うがぁぁぁぁ!!