2013年12月20日金曜日

テンキーでサウンド関係の操作を行う (GNOME)

フルキーボードのテンキーはなかなか使う機会がなく、テンキーレスキーボード欲しい症候群を発症しています。が、お値段を見て腰が引けているところでもあります。今回は不遇なテンキーを音量調整と曲の頭出し、再生停止・開始に割り当てるお話です。

GNOMEだと話はとても簡単で、「設定」→「キーボード」→「独自のショートカット」で好きなコマンドを割り当てるだけで完了です。以下割り当てるコマンドについてのメモ。

amixer

まずは音量調整について。システム音量調整にはamixerコマンドが利用できます。詳しくはman amixerで調べるとよいのですが、今回は結果だけ。

# マスター音量を5%上げる
amixer set 'Master' 5%+
# マスター音量を5%下げる
amixer set 'Master' 5%-

rhythmbox-client

音楽再生にはRhythmboxを使っていますので、rhythmbox-clientコマンドが使えます。

# 一時停止・再生の切り替え
rhythmbox-client --play-pause
# 次の曲を再生
rhythmbox-client --next
# 前の曲を再生
rhythmbox-client --previous

2013年11月27日水曜日

位置座標から3次元グリッドのインデックスを検索する (Python & NumPy)

はじめに

定義:

グリッド
3つのインデックス i, j, k で指定できる3次元位置座標の集合。
セル
グリッドに含まれる座標のうち、
(i, j, k), (i+1, j, k), (i+1, j+1, k), (i, j+1, k), (i, j, k+1), (i+1, j, k+1), (i+1, j+1, k+1), (i, j+1, k+1)
の8つで構成される平面に囲まれた空間。グリッドの最大インデックスが (I, J, K) であるとき、セルの最大インデックスは (I-1, J-1, K-1).

目標:

  • 3次元空間内の任意の位置座標 p を含むセルのインデックス (i, j, k) を求める。

方針

  • p からセルの構成面 s へのベクトル
  • セル構成面の外向き法線ベクトル
の内積を計算します。計算結果がすべて0以上であれば、p はセル内もしくはセル構成面上に存在するはずです。

言語は Python3.3, 数値計算用ライブラリ NumPy を利用します。NumPy の練習も兼ねて。

書いてみた

座標からインデックスを求めるよりも、グリッドと法線ベクトル生成に多く時間が取られるスクリプトになってしまいました…。はたしてこれで正しいのかどうか。

import numpy
import time


def get_normals(face_triangles):
    return numpy.cross(face_triangles[:,:,1] - face_triangles[:,:,0],
                        face_triangles[:,:,2] - face_triangles[:,:,0])


def get_cells(points, grid_shape):
    cells_shape = numpy.array(grid_shape[:3]) - 1
    num_of_cells = numpy.multiply.reduce(cells_shape)
    face_triangles = numpy.zeros([num_of_cells, 12, 3, 3], dtype=numpy.float)
    points_on_face = numpy.zeros([num_of_cells, 12, 3], dtype=numpy.float)
    i, j, k = (0, 0, 0)
    dj, dk = (grid_shape[0], grid_shape[0] * grid_shape[1])
    for index in range(num_of_cells):
        if i == cells_shape[0]:
            i = 0
            j += 1
        if j == cells_shape[1]:
            j = 0
            k += 1
        base_i = i
        base_j = dj * j
        base_k = dk * k
        next_i = i + 1
        next_j = dj * (j + 1)
        next_k = dk * (k + 1)
        face_triangles[index] = ((points[i + base_j + base_k],
                                  points[next_i + next_j + base_k],
                                  points[next_i + base_j + base_k]),
                                 (points[i + base_j + base_k],
                                  points[i + next_j + base_k],
                                  points[next_i + next_j + base_k]),
                                 (points[i + base_j + next_k],
                                  points[next_i + base_j + next_k],
                                  points[next_i + next_j + next_k]),
                                 (points[i + base_j + next_k],
                                  points[next_i + next_j + next_k],
                                  points[i + next_j + next_k]),
                                 # y-z
                                 (points[i + base_j + base_k],
                                  points[i + next_j + next_k],
                                  points[i + next_j + base_k]),
                                 (points[i + base_j + base_k],
                                  points[i + base_j + next_k],
                                  points[i + next_j + next_k]),
                                 (points[next_i + base_j + base_k],
                                  points[next_i + next_j + base_k],
                                  points[next_i + next_j + next_k]),
                                 (points[next_i + base_j + base_k],
                                  points[next_i + next_j + next_k],
                                  points[next_i + base_j + next_k]),
                                 # z-x
                                 (points[i + base_j + base_k],
                                  points[next_i + base_j + next_k],
                                  points[i + base_j + next_k]),
                                 (points[i + base_j + base_k],
                                  points[next_i + base_j + base_k],
                                  points[next_i + base_j + next_k]),
                                 (points[i + next_j + base_k],
                                  points[i + next_j + next_k],
                                  points[next_i + next_j + next_k]),
                                 (points[i + next_j + base_k],
                                  points[next_i + next_j + next_k],
                                  points[next_i + next_j + base_k]))
        points_on_face[index, 0::4] = points[i + base_j + base_k]
        points_on_face[index, 1::4] = points[i + base_j + base_k]
        points_on_face[index, 2::4] = points[next_i + next_j + next_k]
        points_on_face[index, 3::4] = points[next_i + next_j + next_k]
        i += 1
    normals = get_normals(face_triangles)
    return (normals, points_on_face)


def get_indices_from_coordinate(coordinate, normals, points_on_face):
    vectors = points_on_face - coordinate
    dotprods = numpy.einsum('ijk, ijk->ij', vectors, normals)
    is_coord_back_of_face = numpy.greater_equal(dotprods, [0])
    return numpy.where(numpy.all(is_coord_back_of_face, 1))[0]


if __name__ == "__main__":
    grid_shape = [37, 25, 54]
    num_of_points = numpy.multiply.reduce(grid_shape)
    delta = [1.0, 1.0, 1.0]
    points = numpy.zeros([num_of_points, 3])
    i, j, k = (0, 0, 0)
    start = time.clock()
    for index in range(num_of_points):
        if i == grid_shape[0]:
            i = 0
            j += 1
        if j == grid_shape[1]:
            j = 0
            k += 1
        points[index] = (delta[0] * i, delta[1] * j, delta[2] * k)
        i += 1
    lap1 = time.clock()
    normals, points_on_face = get_cells(points, grid_shape)
    testpoint = numpy.random.rand(3) * 100
    lap2 = time.clock()
    indices = get_indices_from_coordinate(testpoint, normals, points_on_face)
    lap3 = time.clock()
    if len(indices) is 0:
        print(" ".join(["({0[0]}, {0[1]}, {0[2]})".format(testpoint),
                         "is not included in the cells."]))
    for index in indices:
        print(" ".join(["({0[0]}, {0[1]}, {0[2]})".format(testpoint),
                         "is included in cell {}".format(index)]))
    print("lap1: {}\nlap2: {}\nlap3: {}".format(lap1 - start,
                                                 lap2 - lap1,
                                                 lap3 - lap2))

次回、壁面衝突判定の予定

2013年10月14日月曜日

Multiple Dygraph in Twitter Bootstrap based Tab

This post is a response to "Multiple Dygraph is not working in Twitter bootstrap based Tab !"

Bootstrap の tab に dygraph.js でグラフを描画している時に、「タブを切り替えるとグラフが正しく描画されない」という問題があります。より正確に言えば、「初期状態で非表示の領域にグラフを描画すると問題がおきる」でしょうか。

参考:Issue 238 - dygraphs - Canvas & container div have zero height and width when parent is invisible.

対策としてはリンク先でも述べられている通り、グラフが格納された div 要素が表示されたら、 Dygraph インスタンスの .resize() メソッドを実行すれば表示はされます。ただし、高さと幅が初期値に固定されてしまいます。これを防ぐために、描画領域の要素から style プロパティを削除しています。

Nginx 最新版を Raspberry Pi にインストールする

WebSocket をリバースプロキシに通す必要がありまして、Nginx を使うことにしました。ただ Raspbian 公式リポジトリではバージョン 1.2 が提供されています。WebSocket のリバースプロキシには Nginx 1.3 以降で対応しているそうなので、以下の方法で最新版をインストールしました。以下の記事が参考になりました。(ほぼそのまま)

/etc/apt/sources.list に以下の2行を追記。

deb http://nginx.org/packages/debian/ wheezy nginx
deb-src http://nginx.org/packages/debian/ wheezy nginx
以下のコマンドを実行。
$ sudo apt-get update
$ sudo apt-get build-dep nginx
$ sudo apt-get source nginx
$ cd nginx-1.4.3
$ sudo dpkg-buildpackage -uc -b
$ sudo dpkg -i nginx_1.4.3-1~wheezy_armhf.deb

2013年10月5日土曜日

ファイルをブラウザにダウンロードさせる (Python, Tornado Web Server)

たとえばCSVファイルをダウンロードさせる場合。

class FileHandler(tornado.web.RequestHandler):
    def get(self):
        self.set_header('Content-Type', "text/csv")
        self.set_header('Content-Disposition',
                        "attachment; filename=\"{}\"".format(filename))
        self.set_header('Content-Length', os.path.getsize(filename))
        with open(filename, 'rb') as fp:
            self.write(fp.read())

2013年9月13日金曜日

Pythonで無線LANのSSIDをスキャン

Raspberry Pi で、無線LANアダプタが認識しているSSIDを調べる必要が出てきたので。

まずはシステムコマンドの確認から。wlan0 について調べる場合は、

$ sudo iwlist wlan0 scan | grep 'ESSID:".\+"'
で一覧が取れます。grep のあとについてる正規表現でESSIDが空になっている行を弾いています。このコマンドで取れる応答は、
    ESSID:"ssid1"
    ESSID:"ssid2"
    ...
のようになっています。これをpythonで受け取り、SSIDだけ抜き出してリストにします。
#!/usr/bin/python3
import subprocess

stdout = subprocess.check_output("iwlist wlan0 scan | grep 'ESSID:\".\+\"',
                                 shell=True)
ssid_list = [line.lstrip('ESSID:').strip('"') for line in stdout.split()]
以上。

2013年8月1日木曜日

Raspberry Pi を有線/無線ネットワークに接続する(DHCP版)

Raspberry Pi の初期ネットワーク設定

初期状態の /etc/network/interfaces は次のようになっています。

auto lo

iface lo inet loopback
iface eth0 inet dhcp

allow-hotplug wlan0
iface wlan0 inet manual
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet dhcp
DHCPで割り当てを受ける場合、この設定を変更する必要はありません。

有線接続

そのままでOK. 何もしなくとも、DHCPでIPアドレスなどの割り当てが受けられます。どうぞネットワークの海原へ。

無線接続の場合

これもひと手間かけるだけです。何が手間かというと、無線LANのSSIDとアクセスキー(パスフレーズ)の設定です。

SSIDとアクセスキーの設定には wpa_passphrase を使います。書式は次の通り。

wpa_passphrase <ssid> [passphrase]

# SSID = hogehoge, アクセスキー = fugafuga の場合は、
$ wpa_passphrase hogehoge fugafuga
# で、出力はこうなる。
network={
        ssid="hogehoge"
        #psk="fugafuga"
        psk=b276f31c7d3c1862c991617334abe708b16c1dcc85c1f1cf5ceae1c15bb75572
}
この出力を /etc/wpa_supplicant/wpa_supplicant.conf に追加すれば、自動的にネットワークが認識されます。手順は次の通り。
# 権限変更
$ sudo chmod 666 /etc/wpa_supplicant/wpa_supplicant.conf
# ネットワークデータの追記
$ wpa_passphrase hogehoge fugafuga >> /etc/wpa_supplicant/wpa_supplicant.conf
# 権限を戻す
$ sudo chmod 600 /etc/wpa_supplicant/wpa_supplicant.conf
もしくは
$ sudo sh -c "wpa_passphrase hogehoge fugafuga >> /etc/wpa_supplicant/wpa_supplicant.conf"
この状態で /etc/wpa_supplicant/wpa_supplicant.conf を表示すると、
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
        ssid="hogehoge"
        #psk="fugafuga"
        psk=b276f31c7d3c1862c991617334abe708b16c1dcc85c1f1cf5ceae1c15bb75572
}
#psk=... は不要なので削除。もしSSIDを通知していない場合(ステルスSSID)には、scan_ssid=1 を追加して次のように変更します。
update_config=1
network={
        ssid="hogehoge"
        psk=b276f31c7d3c1862c991617334abe708b16c1dcc85c1f1cf5ceae1c15bb75572
        scan_ssid=1
}
以上で設定完了。Raspberry Pi を再起動するなり、 networkを再起動するなりして接続できることを確認します。

迷ったら man wpa_supplicant.conf を参照で。

2013年7月24日水曜日

Raspberry Pi を簡易DNSとDHCPサーバに

概要

Raspberry Pi (Raspbian) に dnsmasq をインストールして、LAN内のDNS&DHCPサーバーにします。LAN内のコンピュータへ、ホスト名の指定でアクセスできるようにするのが目的です。要するにLAN内限定のDDNSサーバのようなものです。

ネットワーク構成

  • ルータ & ゲートウェイ: 192.168.0.1
  • Raspberry Pi (DNS&DHCP server): 192.168.0.2
  • Raspberry Pi のIPアドレスは固定
  • Raspberry Pi は自力で名前解決ができる(外部DNSサーバが /etc/network/interfaces で指定されている)

手順

dnsmasqをインストール。

sudo apt-get install dnsmasq
次に /etc/dnsmasq.conf を編集します。設定方法はファイル内にかなり親切にコメントされています。今回は外部ファイルに設定を記述するため、次の行をコメントアウトします。
#conf-file=/etc/dnsmasq.more.conf
conf-file=/etc/dnsmasq.more.conf
設定事項は /etc/dnsmasq.more.conf に書き込みます。
domain-needed
bogus-priv

# LAN内で使用するドメインを指定。
# このドメインに対する正引き要求は、
# 1. /etc/hosts
# 2. dnsmasq のDHCP機能によって割り当てられたIPアドレス
# のみを検索して応答する。
local=/raspberry.local/

# 正引き要求に対して /etc/hosts 内にあるホスト名を回答するとき、
# ホスト名の末尾に下記で設定されたドメイン名を付加して応答する。
expand-hosts

# ドメイン名の指定。
# このドメイン名は以下のように利用される。
# 1. "expand-hosts" を設定した場合に付加されるドメイン名
# 2. DHCPクライアントが取得するドメイン名
domain=raspberry.local

# DHCPクライアントへ割り当てるIPアドレスの範囲とリース時間の指定。
# このオプションを設定するとDHCPサーバ機能が有効となる。
dhcp-range=192.168.0.10,192.168.0.80,12h

# DHCPクライアントに通知するルータ、DNSサーバ、NTPサーバの指定。
# 今回は、DNS, NTPサーバとして自身を指定する。
# NTPサーバの設定が必要。 (/etc/ntp.conf)
dhcp-option=option:router,192.168.0.1
dhcp-option=option:dns-server,192.168.0.2
dhcp-option=option:ntp-server,192.168.0.2
設定が完了したら、dnsmasq を再起動します。なお、別のDHCPサーバがすでにネットワーク上にある場合は、そのサービスを停止する必要があります。
sudo service dnsmasq restart
dnsmasq が稼働しているコンピュータ自身の名前を解決するため、/etc/hosts にIPアドレスとホスト名の対応を追記します。
# /etc/hosts に追記
192.168.0.2    raspiname
以上でLAN内のコンピュータに対して、ホスト名でアクセスできるようになりました。

取得済みIPアドレスのリリース

WindowsでDHCPクライアントの情報を更新するため、取得済みIPアドレスのリリースと再取得を行います。

# 取得済みのIPアドレスを解放
ipconfig /release
# IPアドレスの割り当てを受ける
ipconfig /renew
なぜかWindowsマシンだけDHCPクライアントの情報が更新されない、などの時はお試しください。これに気づくまでに無駄な時間を消費しました…。

2013年7月5日金曜日

メモ:ApeosPort -IV C2275 通信設定について (Windows7 32bit)

LPRプリンタを指定する場合、標準設定ではエラーが発生して印刷が失敗する。対策として、ドライバをインストールした後で通信プロトコルを変更する必要がある。コントロールパネルからプリンタを表示し、AdeosPort-IV のプロパティを選択、「ポートの構成」で変更を行う。通信プロトコルが "Raw" に設定されているので、"LPR" に変更する。

2013年5月29日水曜日

UbuntuでInsertキーを無効にする

Logicool K270 を使っていますが、BackSpaceキーを打とうとしてInsertキーを誤爆してしまうことが多いので無効化しました(CapsLockキーの無効化・割り当て変更なんかは「システム設定→キーボードレイアウト→オプション」でいけるけれど、Insertキーを無効にするオプションが見当たらなかったので)

まずはxevを利用してInsertキーのキーコードを調べます。

xev
キーコードは "118" でした。

次に xmodmap の設定ファイルを作成します。~/.xmodmap を次の内容で作成。

keycode 118 =
確認のため、設定を適用してみます。
xmodmap ~/.xmodmap

最後に、起動時に自動的に設定を適用するように設定します。「自動起動するアプリケーション」(gnome-session-properties) で、

xmodmap /home/username/.xmodmap
を追加すればOK.
※.xmodmap は絶対パスで指定してあげないと動きませんでした。

2013年5月3日金曜日

メモ:PC構成

デスクトップ

2013年4月時点の構成

  • ケース:Antec ISK-110
  • マザーボード:GA-H77N-WIFI (rev. 1.0)
  • CPU: Intel Celeron G1610 Intel Core i3 3220T (2013/6/1 変更)
  • メモリ:W3U1600HQ-4G (4GB*2)
  • HDD: TOSHIBA MK3252GSX 320GB (PHDD-320GBを分解して中身を利用)
  • 電源:ケース付属(90W ACアダプタ)
  • ファン:CPU付属標準ファンのみ
  • OS: Ubuntu 12.10
  • 備考:マザーボード付属の2.4GHz帯アンテナはロッドタイプ(SMAアンテナ)に交換済み。

安くて小さいやつを、ということで、Mini-ITX で。モニタ背面への設置も可能。メモリは4GBだと足りなくなったので8GBに変更。2.4GHz帯用のアンテナはAmazonや秋月電子通商で500円程度。Intel N2230がLinuxでは不安定なようで、IEEE 802.11nを無効化して使っています。

シングルボードコンピュータ

Raspberry Pi が4台(Model A * 2, Model B * 2)。

2013年5月2日木曜日

2013年2月14日木曜日

VNC server on Raspberry Pi (Raspbian)

昨年末に2台購入したRaspberryPi, 元気に稼働中です。1台はLAN内DHCP&DNSサーバ、もう1台は遊び用になっています。サーバの方はdnsmasqを使って、簡易DDNSとしています。LAN内のマシンにホスト名だけでアクセスできて便利です。

RaspberryPiは基本的にSSHでログインして操作していますが、たまにGUIを使いたいときもあります。SSHログインしてVNCサーバを起動すればよいのですが、できればログイン画面からGUIでいきたいものです。こういう場合メジャーなのはxinetdを使う方法ですが、調べてみると別の方法もあったりします。今回はlightdmとTightVNCでいきます。

2013年1月8日火曜日

"bond-give-a-chance" って何だ?

Raspberry PiでUSB-Wifiアダプタを使う」で、bondingを扱いました。そのとき、/etc/network/interfaces に"bond-give-a-chance"というパラメータを設定しています。これについては http://ubuntuforums.org/archive/index.php/t-1515788.html に出てきたものをそのまま使用していました。けっこう重要そうなパラメータの内容が分からないのもアレなので、ちょっと調べてみました。