サイトを再び移転しました。新しいアドレスは http://blog.d-alchemy.xyz/ です。たびたびお手数をおかけしますが、ブックマークの修正をよろしくお願いします。

2016年09月28日

ファイターズ大逆転優勝

 いやーすごいわ。大谷凄すぎる。8回ウラあたりからテレビで観戦した。西武プリンスドームなのに、まるでファイターズのホームのような盛り上がりぶりだった。ライオンズファン入ってたのかな。最後の外崎のレフトフライは、いい角度で上がったように見えて、ちょっと冷やっとした。最近いいところでホームラン打ってたからね。ともあれ、ファイターズファンのみなさん、おめでとうございました。

タグ:野球
posted by toshinagata at 22:31| 日記

2016年09月19日

ラズパイの液晶タッチパネルを使う

 「ラズパイと 3.2 インチタッチパネル付き液晶」の続き。タッチパネルを使ってみた。ググってみると、X window で使う方法はすぐに出てくるのだが、X なしで使う方法を探し出すのに少し手間取った。

 タッチパネルのドライバは Linux Input Subsystem 経由でアクセスできる。次のようにすると、利用できるデバイスの一覧が取得できる。最初の2つが USB キーボード、3つめがタッチパネル。

pi@raspberrypi:~ $ cat /proc/bus/input/devices
I: Bus=0003 Vendor=1c4f Product=0027 Version=0110
N: Name="SIGMACHIP USB Keyboard"
P: Phys=usb-20980000.usb-1/input0
S: Sysfs=/devices/platform/soc/20980000.usb/usb1/1-1/1-1:1.0/0003:1C4F:0027.0001/input/input0
U: Uniq=
H: Handlers=sysrq kbd leds event0 
B: PROP=0
B: EV=120013
B: KEY=10000 7 ff800000 7ff febeffdf f3cfffff ffffffff fffffffe
B: MSC=10
B: LED=7

I: Bus=0003 Vendor=1c4f Product=0027 Version=0110
N: Name="SIGMACHIP USB Keyboard"
P: Phys=usb-20980000.usb-1/input1
S: Sysfs=/devices/platform/soc/20980000.usb/usb1/1-1/1-1:1.1/0003:1C4F:0027.0002/input/input1
U: Uniq=
H: Handlers=kbd event1 
B: PROP=0
B: EV=1f
B: KEY=3007f 0 0 0 0 483ffff 17aff32d bf544446 0 0 1 130c13 b17c000 267bfa d941dfed 9e1680 4400 0 10000002
B: REL=40
B: ABS=1 0
B: MSC=10

I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="ADS7846 Touchscreen"
P: Phys=spi0.1/input0
S: Sysfs=/devices/platform/soc/20204000.spi/spi_master/spi0/spi0.1/input/input2
U: Uniq=
H: Handlers=mouse0 event2 
B: PROP=0
B: EV=b
B: KEY=400 0 0 0 0 0 0 0 0 0 0
B: ABS=1000003

 コーディングは、"Programming for a Touchscreen on the Raspberry Pi" を参考にした。

 まず、タッチパネルのデバイスをオープンする。/dev/input/event* を順に調べて、デバイス名に "Touchscreen" があるものを探す。デバイス名は当然機種依存なので、個別に調査が必要。

static int16_t s_fd = 0;
static int
l_tp_open(lua_State *L, int in_calibration)
{
  char dname[20];
  char name[256] = "Unknown";
  int i;
  if (s_fd == 0) {
    for (i = 0; i < 10; i++) {
      snprintf(dname, sizeof(dname), "/dev/input/event%d", i);
      if ((s_fd = open(dname, O_RDONLY)) < 0)
        continue;
      ioctl(s_fd, EVIOCGNAME(sizeof(name)), name);
      if (strstr(name, "Touchscreen") != NULL)
        break;
      close(s_fd);
      s_fd = -1;
    }
    if (s_fd > 0) {
      /*  Read the configuration data if present  */
      ...
    }
  }
  return s_fd;
}

 イベントを取得する。今回使ったタッチパネルは、X 方向のノイズがひどかったので、フィルタをかける必要があった。また、値が 10 以上変化しなかった場合は無視している。このあたりの設定は、若干の試行錯誤が必要。たぶん、個体差もあると思う。

/*  getevent() -> (type, x, y, pressure)  */
/*  type = nil: no input, 1: start touch, 2: drag, 3: end touch  */
int
l_tp_getevent(lua_State *L)
{
  int n, x, y;
  static int s_state = 0, s_x, s_y, s_p, s_count;
  static int s_x0, s_y0, s_p0;
  static int s_xlast, s_ylast;
  if (l_tp_open(L, 0) <= 0)
    return 0;
  while (1) {
    struct pollfd pfd;
    struct input_event ev;
    pfd.fd = s_fd;
    pfd.events = POLLIN;
    pfd.revents = 0;
    n = poll(&pfd, 1, 0);
    if (n < 0)
      return luaL_error(L, "Touchpanel error: poll() failed");
    else if (n == 0)
      return 0;  /*  No input  */
    n = read(s_fd, &ev, sizeof(ev));
    if (n < sizeof(ev))
      return luaL_error(L, "Touchpanel error: read() failed");
    if (ev.type == EV_KEY && ev.code == BTN_TOUCH) {
      if (ev.value == 1) {
        s_state = 1;  /*  Touch start  */
        s_x0 = s_y0 = s_p0 = 0;
        s_count = 0;
      } else {
        s_state = 0;  /*  Touch end  */
        l_tp_convert(s_x0, s_y0, &x, &y);
        lua_pushinteger(L, 3);
        lua_pushinteger(L, x);
        lua_pushinteger(L, y);
        lua_pushinteger(L, s_p);
        return 4;
      }
    } else if (ev.type == EV_ABS) {
      if (ev.code == ABS_X)
        s_x = ev.value;
      else if (ev.code == ABS_Y)
        s_y = ev.value;
      else if (ev.code == ABS_PRESSURE) {
        s_p = ev.value;
        if (s_count == 0) {
          s_x0 = s_x;
          s_y0 = s_y;
          s_p0 = s_p;
        } else {
          /*  Filter sudden noise  */
          s_x0 = (int)(s_x0 * 0.9 + s_x * 0.1);
          s_y0 = (int)(s_y0 * 0.9 + s_y * 0.1);
          s_p0 = (int)(s_p0 * 0.9 + s_p * 0.1);
        }
        s_count++;
        l_tp_convert(s_x0, s_y0, &x, &y);
        if (s_state == 2) {
          /*  If the position is too close, then do not invoke drag event  */
          int dx = s_xlast - s_x0;
          int dy = s_ylast - s_y0;
          const int lim = 10;
          if (dx < lim && dx > -lim && dy < lim && dy > -lim)
            return 0;
        }
        s_xlast = s_x0;
        s_ylast = s_y0;
        lua_pushinteger(L, (s_state == 0 ? 1 : s_state));
        lua_pushinteger(L, x);
        lua_pushinteger(L, y);
        lua_pushinteger(L, s_p);
        if (s_state == 0 || s_state == 1)
          s_state = 2;  /*  The next event will be 'drag'  */
        return 4;
      }
    }
  }
}

 タッチパネルのキャリブレーションのために、中央と四隅に印を出してその位置をタップする。タップ位置を画面座標に変換するには、下図のように中央を頂点とする三角形でタップ位置を含むものを選び、その中で一次変換を行う。3.2 インチ程度の小さなパネルであれば、このような5点のキャリブレーションで十分実用になる。

 コードはこんな感じ。

static int16_t *s_calib_coords;
static int16_t s_calib_npoints;
static void
l_tp_convert(int si, int ti, int *xi, int *yi)
{
  float s, t, s0, t0, s1, t1, s2, t2;
  float x0, y0, x1, y1, x2, y2;
  float v, w;
  float d;
  int i;
  s0 = s_calib_coords[0];
  t0 = s_calib_coords[1];
  x0 = s_calib_coords[2];
  y0 = s_calib_coords[3];
  s = si - s0;
  t = ti - t0;
  for (i = 1; i < s_calib_npoints; i++) {
    int n = i * 4;
    s1 = s_calib_coords[n++] - s0;
    t1 = s_calib_coords[n++] - t0;
    x1 = s_calib_coords[n++] - x0;
    y1 = s_calib_coords[n++] - y0;
    if (i == s_calib_npoints - 1)
      n = 4;
    s2 = s_calib_coords[n++] - s0;
    t2 = s_calib_coords[n++] - t0;
    x2 = s_calib_coords[n++] - x0;
    y2 = s_calib_coords[n++] - y0;
    d = 1.0 / (s1 * t2 - s2 * t1);
    s1 *= d;
    s2 *= d;
    t1 *= d;
    t2 *= d;
    v = t2 * s - s2 * t;
    w = s1 * t - t1 * s;
    if (v >= 0.0 && w >= 0.0) {
      *xi = (int)(x1 * v + x2 * w + x0);
      *yi = (int)(y1 * v + y2 * w + y0);
      return;
    }
  }
}

 Lua のライブラリとして実装して、テストプログラムを書いてみた。

gcolor(rgb(1, 1, 1))
xx = 0
yy = 0
while true do
  st, x, y, p = tp.getevent()
  if st == 1 or st == 2 then
    locate(0, 0); clearline()
    print(st, x, y, p)
  end
  if st == 1 then
    xx = x
    yy = y
  elseif st == 2 then
    line(xx, yy, x, y)
    xx = x
    yy = y
  else
    if inkey(1) == 27 then break end
  end
end

 GitHub に公開しました。→ https://github.com/toshinagata/luaconsole

タグ:Lua Raspberry Pi
posted by toshinagata at 12:13| 日記

2016年09月15日

常温核融合?

 日経新聞の記事、「米で特許 再現成功で『常温核融合』、再評価が加速」。ビジネスパーソンにとっては「特許がとれた」=「価値ある成果」ということになるのだろうけど、本当に宣伝通りの成果なのかどうか、どうも疑問が残る。この記事で紹介されている実験内容を見る限り、熱が発生するのは当然で、核反応ではなく重水素と金属の普通の化学反応熱が出る。ニッケル・パラジウム・白金の10族金属は特に水素や重水素と強い結合を作る。また、ナノ構造を作った方が反応熱が大きいのも、化学分野では普通に知られている現象で、それ自体に新規性は全くない。ここでの最大の問題は、ヘリウムが有意な量生成しているのかどうか。記事によれば、ある実験結果ではヘリウムが確かに検出されているようだけど、その実験に再現性があるのか、不純物などの影響ではないのか、というところが決定的に重要。この点を追求しないと、本当に価値のある成果とは言えない。

 ビジネスパーソンの皆様におかれましては、この手の研究で「ヘリウム生成量の再現性や精度」について突っ込んだ議論をしない研究者は、あまり信用しない方がよろしいかと思います。もっと有効な投資先を探した方がいいでしょう。研究者のみなさまにおかれましては、「熱が出た」ことなんてどうでもいいので、ヘリウムが発生したかどうか、また核反応の余剰エネルギーが放射線で検出されたかどうか、ということをちゃんと検証してください。そうでないと、信頼に値しない与太話になってしまうから。

タグ:科学
posted by toshinagata at 23:08| 日記

2016年09月12日

ラズパイにリアルタイムクロックをつける

 ラズパイは時計を内蔵していないので、ネットワークにつながっていないと現在時刻が取得できない。あるプロジェクトにラズパイを使うことを考えていて、時計がないのはちょっと悲しいので、リアルタイムクロック (RTC) をつけてみた。使ったのは秋月の「DS1307 I2Cリアルタイムクロックモジュール」。SainSmart 社の製品です。秋月の他の RTC モジュールと比べると少しお高いのだが、実は電池ホルダーと充電式リチウム電池がおまけについてくるので、お買い得だし、実装スペースも節約できる。

 この RTC モジュールは 5V 動作である。I2C 信号線を 3.3V でプルアップすればラズパイに直結できるのだが、モジュール内で 5V にプルアップされているので、まずその抵抗を取り外す。下の赤丸で囲んだ集合抵抗(4.7 KΩ×4)です。きれいに取り外す技術力がないので、足を傷つけて強引に折り取ってしまった。痛々しくなってしまったので、取った後の写真はナシです。

 ピンヘッダをハンダ付けして、ラズパイと接続。5V (2ピン), GND (6ピン), SDA (3ピン), SCL (4ピン) の4本をつなぐ(写真撮り忘れた)。ハードウェアの設定はこれだけ。

 次はソフトウェアの設定。Raspbian Jessie には DS1307 用のドライバが含まれているので、あんまり難しいところはない。まず、raspi-config で I2C を有効にする。"Advanced Options" の中にある。

 リブート後、sudo apt-get install i2c-tools とする。i2cdetect -y 1 で "68" が表示されれば OK。

$ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                         

 ドライバを読み込む。(3行とも必要なのかどうか、自信なし)

$ sudo modprobe i2c-bcm2708
$ sudo modprobe i2c-dev
$ sudo modprobe rtc-ds1307

 DS1307 の在処をシステムに教えてやる。

$ sudo bash
# echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device 
# exit

sudo echo ... > ... ではうまくいかない。リダイレクト先への書き込みが sudo 権限なしに行われるため、権限がないと言われる。)

 読み出しテスト。

$ sudo hwclock -r
Sat 01 Jan 2000 09:00:10 AM JST  -0.417185 seconds

 年月日が 2000年1月1日になっている。今はラズパイの時計がネットワークと同期しているので、ラズパイの時計から RTC へ現在時刻を書き込む。

$ sudo hwclock -w
$ sudo hwclock -r
Sun 11 Sep 2016 01:44:47 PM JST  -0.371574 seconds

 /etc/rc.local の最後 (exit 0 の前)に次のように書き込んでおくと、起動時に自動的に RTC から時刻をセットしてくれる。ただし、この方法だと、起動時のログは RTC を使わない時刻になってしまう。今回は起動ログの時刻は気にしないことにした。

echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device
sleep 0.5
hwclock -s

 前回試した液晶と同時に使おうとすると、液晶のピンソケットで I2C のピンが隠れてしまうという問題が発生する。連結ピンソケットで2階建てにするなど、I2C 信号線を引き出す工夫が必要。

タグ:Raspberry Pi
posted by toshinagata at 00:37| 日記

2016年09月06日

ラズパイと 3.2 インチタッチパネル付き液晶

 ラズパイの続き。ベアメタルは一休みして、Raspbian Jessie に戻ってきた。今回は、3.2 インチタッチパネル付き液晶を接続した話。Amazon や、aitendo で購入できる。元は Waveshare 3.2inch RPi LCD (B), 320×240 という商品。ラズパイ用と称する液晶パネルもいろいろ種類があるので、よく調査しましょう。

 セットアップは、http://www.waveshare.com/wiki/3.2inch_RPi_LCD_(B) に沿って行う。まず、Raspbian Jessie をインストールして、raspi-config でファイルシステムの拡張・コンソール (CLI) への自動ログインを設定。そのあと、再起動してコンソールでログインして、次のように進める。

$ wget http://www.waveshare.com/w/upload/3/3d/LCD-show-160811.tar.gz
$ tar xvfz LCD-show-160811.tar.gz
$ cd LCD-show
$ ./LCD32-show

 LCD32-show コマンドは、起動時から 3.2 インチ液晶を使うように設定して、自動的に再起動する。起動メッセージは途中までは HDMI モニタに出るが、途中から 3.2 インチ液晶に表示されるようになり、コマンドプロンプトも 3.2 インチ液晶上で出る。

 「さめがめ」を動かしてみた。画面が小さいのであんまり面白くない。キャラクタ単位じゃなくて、グラフィックで書き直さないといけないな。

 今回はちょっと頑張って、OpenVG でグラフィック描画をやってみた。これは楕円の塗りつぶしをやってみたもの。アルファ値を使った色の重ね合わせもできるので、二次元の描画としてはまずまずである。メモリ上に描画したあと液晶用のフレームバッファにまとめて転送する、というシンプルな実装だが、描画スピードもそう遅くはない。

 なお、waveshare32b-overlay.dtbswkim01 氏の github ページ にあるもので置き換えると、SPI 転送のバッファのサイズが大きくなるため、少し動作が速くなるみたい。さらに、/boot/config.txtwaveshare32b の行を dtoverlay=waveshare32b:rotate=270,speed=48000000 としてみた。これで SPI の転送スピードが 48 MHz になる。確かに速くなったような気もするけど、体感的にはそんなに変わらんかも…

 なお、液晶のタッチパネルも認識していることは確認できた。タッチパネルの入力を受け付けるようにすれば、ラズパイ+液晶だけで動かせるので、プログラミングできる携帯ゲーム機にもなりそう。これはまた後日。 (追記:「ラズパイの液晶タッチパネルを使う」書きました)

タグ:Lua Raspberry Pi
posted by toshinagata at 00:25| 日記