2014年12月22日月曜日

工学の終焉と再生

ある研究会での質疑の話を聞いた。フロアから、なぜそのアルゴリズムを使ったのか、と質問があったところ、発表者が
OpenCVにあったから」
と答えた。OpenCVは有名な画像処理のライブラリである。この話は、ツールに依存して基礎を疎かにしている発表者を戒めるための逸話として語られている。しかし最近私は、もう少し大きな流れ、工学の民主化、もしくはコモディティ化、極端に言えば工学の終焉を表す一つの事例と考えるようになった。

デザイナーの奥山清行氏が自著[1]でトヨタのヴィッツと、BMWのニュー・ミニの話をしている。曰く「工業製品として優れているのは間違いなくヴィッツの方である。その差は圧倒的」だ。しかし、氏が選ぶのはミニである。性能が低くて、価格が倍以上するミニを選ぶのは何故か、また氏以外にも選ぶ人が相当数いるのはどういうことか。それはヴィッツがニーズ(Needs)であり、ミニがワンツ(Wants)であるからだ。他でも手に入るが仕方なく必要なものに、人は徹底的に財布の紐を絞る。対して、喜びのためであれば何倍もの金を、人によっては何十倍、何百倍の金を注ぐ。
私はこれを工学の敗北と読んだ。もちろん、高品質で低価格な製品が世の中にあふれることで、社会が得ている利益は莫大である。ただ、コモディティと化した製品は低価格競争に陥り、利益を得ることが難しくなり、やがては開発費用や維持費用を負担できなくなる。
この話を読みながら私は、電気が徹底してコモディティとなっている現状を重ねていた。電気事業の一翼で禄を食む物として、電気の普及による社会的利益の大きさと、それに比して極めて低い、電気に対する人々の価値意識を思っている。あってあたり前のものに高い金を出そうと思う人はいない。

もうかれこれ10年以上前に、渋谷で田中さんという研究者と会った。彼は写真をうまく使った興味深いアプリケーションを作っており、それを手伝えないかという話だった。結局私の技術では支援できないことがわかり、話はそれきりになった。ただ、その時に感じた、良いと感じたものに体ごと飛び込んでいく彼の姿勢は印象的だった。それから数年後、あるワークショップの昼飯時に彼が今どうしているのか、と話に出したら、彼はFabの伝道師になっているよ、その道では有名だ、と聞いた。慶応大学の田中浩也准教授である。彼の武勇伝は「FabLife」に詳しい[2]
Fabは、パーソナルファブリケーションの意味であり、ものづくりをパーソナルに行うことを意味する。この場合、ワンツは自分の中にある。例えば、MITFabLabに来た芸術系の女性ケリーが、自分で部品を組み立てて作り上げた「スクリームボディ」は、前に抱くバッグの形をしている。これは町中で急に叫びたくなった時に、口をあてて思いっきり叫んでも周囲に迷惑がかからない道具である。さらに後から誰もいない場所で再生できる機能まである(注1)。彼女は大勢人がいる場所で急に大声を上げたくなる衝動の持ち主で、その衝動のためずいぶん苦労してきた。しかし彼女のために製品を作ってくれるメーカーは無い。だから作った。
FabLab利用者が物を作れるのは、レーザーカッターや、3Dプリンタ、Python、またそれこそOpenCVなどの、各種装置、部品、ライブラリが普及したことによる。さらに、彼女にとって電子工学やプログラミング、工具の使用方法は、自分自身のワンツを叶えるために必要性の明らかなハードルである。だから乗り越えられる。
パーソナルファブリケーションに関してMITのガーシェンフェルドが書いた「Fab」という本[3]には、自分の必要のために、また楽しみのために、障害を乗り越えてものづくりをする人々が描かれている。例えば、ニコラ・テスラが1913年に発明した、薄い板が重なった低速回転用タービンと太陽熱を使って、動力源を作ろうとしているガーナの人たちが紹介されている。
こういった話はブルーエコノミー[4]や、適正技術[5]という文脈で様々に語られている。現地で手に入る材料や道具を使って、安価かつ簡易に「たどん」を作れる技術の有用性と、取り組みへの現地の人々の熱狂について。どこまでもシンプルに工夫された灌漑用ポンプの、コストパフォーマンスの高さ、また作っている人々の自活力、創造力の高さ。

さらに別の側面から。従来のマーケティングの無力さ、大量のアンケートに基づくデータ分析をしても、また、たくさんのユーザにニーズ調査をしても、なぜ魅力的な新製品を作り出せないのか、という課題に対して色々な提案がなされている。その中に「仮説生成型」とでも言うべき開発方法群がある。
例えば、「デザイン・ドリブン・イノベーション」[6]では、市場自体を変えた複数の製品開発に関して、ヒアリングをもとに議論している。そういった新製品、例えばアレッシーのワインオープナーや、任天堂のWiiを作り出すには、ユーザへの耽溺ではなく、デザインディスコースへの耽溺が必須である。デザインディスコースとは、隠された新しい意味、まだ気付かれていない新しい価値を探り当てようと日々取り組む人々(解釈者)のネットワーク(コミュニティ)である。解釈者の、まだ確信のない仮説、つぶやきに耳を傾けることが最も重要と彼らは主張する。
また、takram design engineeringは「ストーリー・ウィーヴィング」を提案している[7]。これは開発に先駆けて、使われるシーンをイメージした短いストーリーをグループで作るという方法論である。そのストーリーには、調査やプロトタイピング、ユーザビリティテストなどを通じて、常に立ち返って改訂を繰り返していく。モノ主導でも、ユーザ主導でもなく、魅力的なストーリー主導としている点が独特である。例えば、重なった所に虹ができる透明な傘「虹の傘」、雨粒がそのままストッキングの美しい模様になる「Stockings of Splashes」など、斬新な発想のプロトタイプが作られている(注2)
三品らは「リ・インベンション」こそが必要と主張している[8]。この言葉はスティーブ・ジョブズが言った、
“Today, Apple is going to reinvent the phone, and here it is.”
で記憶に残っている方も多いだろう。イノベーションが旧来の価値基準で圧倒的に優れた技術を作ろうとする活動なのに対し、リ・インベンションは評価軸自体を作り替え、誰に・何を・どのように提供するかまで遡って再発明することを意味する。そのためには測定可能な客観指標を捨て、感覚的な理想を明確にイメージし、その理想に至るインテグリティ(一貫性)を貫くことが、容易な追随を許さない製品を生み出す、とする。

この100年、工学が急速に発展し、高度に専門化し、大きな社会的成功を達成した背景には、工学が「クオリティ」を無視したことが大きい、と私は考えている。工学は人間が「すてき」とか「うれしい」と感じるクオリティそのものは無視し、その代わりに精度や、効率、解像度、安定性、再現性などの客観指標を、クオリティに置き換えて追求してきた。それがヴィッツを、また停電のしない電力系統を実現させた。
しかし、そのことが今、工学を苦しめている。技術的に素晴らしい製品をいくら作っても高く買ってくれる人がいない。何故か。それは前述の奥山氏が書いているように、
「身もだえするほどほしい」
と思えないからだ。これを目的関数とする最適化アルゴリズムは無い。その意味で工学はすでに終焉している。
一方で、Fabや適正技術、また仮説生成型の製品開発といった流れが、新しい工学の再生を示唆している。世に無くどうしても自分が必要な、また売れるかどうか自信は無いが腹の底から欲しいと思うものを、自分で作れる環境が、まさに工学の発展のおかげで手に入りつつある。昔は椅子も家も、近所の職人が、また多くは自分で作っていた。一周してそこに戻っていくのだと考えることもできる。
私は、上述した本やウェブサイトで紹介されている、世界中でものづくりをしている子供から老人まで、多数の人々の写真や映像を見ながら、彼らの楽しそうな顔、自信に満ちた顔、ドヤ顔に、工学の新しい未来、再生を感じている。

参考文献:
[1]       奥山 清行「100年の価値をデザインする: 『本物のクリエイティブ力』をどう磨くか」 PHP研究所,2013
[2]       田中 浩也「FabLife ―デジタルファブリケーションから生まれる『つくりかたの未来』」オライリージャパン,2012
[3]       ニール・ガーシェンフェルド「Fab ―パーソナルコンピュータからパーソナルファブリケーションへ」オライリージャパン,2012
[4]       グンター・パウリ「ブルーエコノミーに変えよう」ダイヤモンド社,2012
[5]       シンシア・スミス「世界を変えるデザイン――ものづくりには夢がある」英治出版,2009
[6]       ロベルト・ベルガンティ「デザイン・ドリブン・イノベーション」同友館,2012
[7]       渡邉 康太郎「ストーリー・ウィーヴィング」ダイヤモンド社,2011
[8]       三品 和広, 三品ゼミ「リ・インベンション: 概念のブレークスルーをどう生み出すか」東洋経済新報社, 2013




注2: このURLにプロトタイプが多数紹介されている。
 

2014年12月21日日曜日

Processing で ポップアップスレッド (Pop up dialog thread for Processing sketch)



Processing で drawの中の状態に応じてポップアップダイアログを出す方法。
普通にdraw内に記述すると、drawが止まってしまう。だからスレッドを使う

If you want to use dialog pop up in your draw function,
you should use a thread for the dialog.

-------------
float   percent;    // progress bar
boolean isRunning;  // flag for thread running
Thread thread1; // thread for pop up dialog
boolean answer; // answer of user

void setup() {
  size(400, 300);
  isRunning = false;
  percent = 0;
  answer = false;
}

void draw() {
  background(255);
  if (answer) stroke(#AA0000);
  else stroke(#0000AA);
  line(10, 10, percent++, 10);

  if (percent == 300) {
    percent = 0;
    if (!isRunning) {
      thread1 = new Thread(new popupThread());
      thread1.start();
    }
  }
}

// pop up thread
class popupThread implements Runnable {
  public synchronized void run() {
    isRunning = true;
    popUpJPanel();
    isRunning = false;
  }
}


import java.awt.*;
import javax.swing.*;

// pop up dialog
int popUpJPanel() {
  JPanel panel = new JPanel();
  BoxLayout layout = new BoxLayout(panel, BoxLayout.Y_AXIS);
  panel.setLayout(layout);
  panel.setPreferredSize(new Dimension(400, 50));

  panel.add(new JLabel("Feel Good?"));
  //checkComment = new JTextField();
  //panel.add(checkComment);

  int r = JOptionPane.showConfirmDialog(
  null,
  panel, "Feel Good", // title of dialog
  JOptionPane.YES_NO_OPTION, // option
  JOptionPane.QUESTION_MESSAGE);  // message type

  if (r == 0) answer = true;
  else answer = false;

  return r;
};

Processing で タイマースレッド (Timer thread programming in your Processing sketch)

Processingでタイマースレッドを使う方法は以下
(How to implement a timer thread in your Processing sketch)

---------------------
Thread thread1; // thread for timer
boolean tick;

void setup() {
  size(400, 300);
  tick = false;
  thread1 = new Thread(new timerThread());
  thread1.start();
}

void draw() {
  background(255);
  if (tick) line(10, 10, 100, 10);
  else line(10, 10, 10, 100);
}

// thread for 1 sec. timer
class timerThread implements Runnable {
  public synchronized void run() {
    while (true) {
      try{
        Thread.sleep(1000);
      } catch (InterruptedException e) {}
      tick = !tick;
    }
  }
}

2014年8月2日土曜日

FirmataとXBee

Firmataについて

Processing 2.0でもFirmataが使える。インポートライブラリで簡単にインストールできる。

Webで検索してみて、FirmataとXBeeの関係が分からなかった。
調べていくにつれて、Firmataで通信するにはXBee Series 1が必要であることがわかった。
Series 2でもATモードで1対1通信ならできないことはないように思う。
しかしAPIモードには対応していないため。1対他通信はATモードでブロードキャストを使うしかない。
動かないことはないかもしれないが、おそらく無理だろう。

Arduino Fio Programmingに
http://arduino.cc/en/Main/ArduinoBoardFioProgramming
You can't use the DigiMesh or ZB series radios (aka Series 2 or 2.5). 
と書かれていた。なるほど。

徐々に分かってきた。
ArduinoのプログラムであるStandardFirmataはSerialで全てのピンのデータを送りつける。
また信号を受け取って、オンオフをするという処理をしている。
Arduino側では一切処理をせずに、シリアルでリモコン制御するようになっている。
よって、これをXbee S2 (ZigBee)用に変えるのは難しくない。
しかし、対応するFirmataライブラリ側も変更しないといけないので、それは面倒である。
そもそもオープンソースだろうか?

オープンソースであった。ソースは
Arduino.javaとFirmata.java
の二つからなる。いずれもシンプルなコードだ。
シリアル通信を中に隠蔽して通信する単純な仕組みである。
デジタル入力、出力、アナログ入力の配列を持っていて、
それをシリアルでArduinoとやり取りしている。
ただ、Processing側からは、つまり外側からは、そのやり取りが隠されていて、
Arduinoというオブジェクトに指示しているように見える。
良く出来ている。私が作るとしてもこう作るだろう。

これはそのままではXBee ZigBeeのAPIモードでは使えない。
ZigBeeのAPIパケットを扱う部分がなく、シリアル通信そのままだからだ。
Arduino.list()という呼び出しも中でシリアル回線をリストアップしているだけだ。

ZigBeeに対応させようとすると、現在ネットワークに接続しているZigBeeノードを
リストできるようにする必要がある。
またシリアルとしては、Coordinatorが接続されているシリアルを接続することになる。
ZigBeeノード毎に、Arduinoというオブジェクトが対応するように、中で橋渡ししてやれば、
Firmataプロトコル自体を、APIパケットに内包させることができるだろう。
できないことはないが、そこまでする必要もないと思う。

Firmataを作っている人たちにまかせておこう。




2014年7月29日火曜日

ClassNotFoundException: processing.core.PAplet への対処

ネットへの恩返しをしておこう。
Processingを利用して、色々といじっている内に
 ClassNotFoundException: processing.core.PAplet
というエラーが出て、Serialライブラリが使えなくなった。
(Mac OS X 10.9.4, Processing 2.0.3)

対処方法は、
 /Library/Java/Extension
に入れたものを出す(空にする)、であった。

以下のサイトには、
http://blog.livedoor.jp/reona396/archives/54536269.html
core.jar
を入れろとある。私の場合は、ArduinoとのZigBee通信のために試行錯誤している途中で、RXTX.jar, Serial.jarなどを上記 Extension フォルダに入れていたのが悪さをしていた。

Javaがどのライブラリを見るか迷ったのが原因のようだ。
上記のサイトに書いてある内容を見てヒントを思いついたので、感謝をこめて、私のメモをアップする。

以上

2014年7月28日月曜日

ZigBee (API)通信用のProcessingプログラム(3台の子機)

ZigBee (API) + Arduino -- ZigBee (API) + Macの通信」でアップしたProcessingプログラムを、3台のZigBee+Arduinoから受信するように改良した。

ZigBeeのアドレステーブルをPCで保持し、アドレスを確認してそれぞれにデータを保持する。

// サンプル
import processing.serial.*;
import java.util.concurrent.*;
import java.util.Queue;
import org.apache.log4j.PropertyConfigurator;

XBee xbee;
Queue<XBeeResponse> queue = new ConcurrentLinkedQueue<XBeeResponse>();
boolean message;
XBeeResponse response;

String senderAddress = "00:13:A2:00:40:B9:3C:CB";
String rxStr = "********";
String txStatus = "";
int rssi = 0;
int rxVarC, rxErrC, tblC;

String[] addressTbl = new String[3];
int[] rxVar = new int[3];
int[] oldrxVar = new int[3];
int[] rxErr = new int [3];

void setup()
{
  size(640,200);
  colorMode(RGB,256);
  background(0,0,0);

  setUpDataTble(); // センサノードに対応した状態管理の初期化
  
  try {
    //optional.  set up logging
    //PropertyConfigurator.configure(dataPath("")+"/log4j.properties");
    xbee = new XBee();
    // replace with your COM port
    xbee.open("/dev/tty.usbserial-A5025X1E", 9600); // xbeeを繋いでいるシリアルポートを指定
    xbee.addPacketListener(new PacketListener() { // xbeeのレスポンスを待つパケット監視を設定
      public void processResponse(XBeeResponse response) {
        queue.offer(response);
      }
    }
    );
  } 
  catch (Exception e) {
    System.out.println("XBee failed to initialize");
    e.printStackTrace();
    System.exit(1);
  }
}

void setUpDataTble() {
  //int[] idTbl = new int[3];
  //int[] rxVar = new int[3];
  //int[] oldrxVar = new int[3];
  //int[] rxErr = new int [3];
  tblC = rxVarC = rxErrC = 0;
}

int setData(String nad, int rx) {
  int id = -1;
  for (int i = 0; i < tblC; i++) {
    if (addressTbl[i].equals(nad)) id = i;
  };
  if (id == -1) {
    addressTbl[tblC] = nad;
    id = tblC++;
  };
  
  rxVar[id] = rx;
  if (rxVar[id] != oldrxVar[id] + 1) rxErr[id]++;
  oldrxVar[id] = rxVar[id];
  
  return id;
};

void draw(){
  // パケット読み取り
  try {
    readPackets();
  }
  catch (Exception e) {
    e.printStackTrace();
  }
  
  background(255);
  textAlign(LEFT);
  textSize(20);
  
  // 受信強度の表示
  fill(0); text("RSSI", 10, 25); fill(0,0,255);
  text(String.format("%d", rssi) + "dB", 100, 25);
  
  // 受信元アドレスを表示
  fill(0); text("Address", 10, 50); fill(0,0,255);
  text(senderAddress, 100, 50);

  // 受信データの表示  
  fill(0);
  text("Rx Data", 10, 75);
  fill(0,0,255);
  //text(rxStr, 100, 75);
  text(rxVarC, 200, 75);
  text("ERR:"+rxErrC, 300, 75);
  
  for (int i = 0; i < tblC; i++) {
    text(addressTbl[i] +" = "+rxVar[i], 110, 100 + i * 25);
  };
  
  // 受信状態の表示
  fill(255,0,0);
  text(txStatus, 10, 100);
}

// パケットの読み込みとエコー、ATDBの送信
void readPackets() throws Exception {

  while ((response = queue.poll()) != null) {
    // we got something!
    try {
      if (response.getApiId() == ApiId.ZNET_RX_RESPONSE && !response.isError()) {
        ZNetRxResponse rxResponse = (ZNetRxResponse) response;
        
        // アドレスをintで取得
        int[] addressArray = rxResponse.getRemoteAddress64().getAddress();
        String[] hexAddress = new String[addressArray.length];
        // 16進数のStringへ
        for(int i=0; i<addressArray.length;i++){
          hexAddress[i] = String.format("%02x",addressArray[i]);
        }
        // 送信元アドレスを文字列で保存
        senderAddress = join(hexAddress,":");
        
        //受信データを取得
        int[] rxData = rxResponse.getData();
        rxStr = "";
        for(int i=0; i<rxData.length; i++){
          rxStr += String.format("%c", rxData[i]);
        }
        // Arduinoのプログラムと対応して、2バイトのintデータを前提にしている。
        rxVarC = rxData[0] << 8 | rxData[1];
        int id = setData(senderAddress, rxVarC);
        rxVarC = rxVar[id];
        rxErrC = rxErr[id];
        
        // エコー (送られてきたデータを、そのまま返信)
        int[] payload = rxData;
        XBeeAddress64 addr64 = new XBeeAddress64(addressArray); // データの送信元アドレスを設定
        ZNetTxRequest request = new ZNetTxRequest(addr64, payload); // 送られてきたデータをAPIパケットに変換
        try {
          // データ送信
          ZNetTxStatusResponse response = (ZNetTxStatusResponse) xbee.sendSynchronous(request);
          txStatus = "";
        } catch (Exception e) {
          txStatus = "tx request timed out";
        }
        
        // ATコマンドを送信し、RSSIを取得
        AtCommand  at = new AtCommand("DB"); // ATDBで、RSSIを取得し、電波強度を調査する。
        AtCommandResponse response = (AtCommandResponse) xbee.sendSynchronous(at, 5000);
        if (response.isOk()) {
          // 成功
          rssi = response.getValue()[0];
          rssi = rssi * (-1);
        }
      }
    }
    catch (ClassCastException e) {
      // not an IO Sample
    }
  }
}

2014年7月27日日曜日

Xbee+ArduinoとXbee+Macを繋ぐ方法(つまづきメモ)

2014年7月27日

XBee+ArduinoとXBee+Macを繋ぐ方法
http://airshipnewsjapan.blogspot.jp/2014/07/xbeearduinoxbeemac.html
をまとめるに至った過程で、苦労したことをメモとして記録しておく。

XBee+Arduino+バッテリーで、センサノードをばらまいて、PCでデータ収集をするシステムを作るのが目的だ。

XBee WIFIで作ろうかと思ったが、インターネットへの接続はPCで集約した方が便利なのと、センサノードの省電力化をはかりたいと思ったため、ZigBeeを扱えるXbee ZBで作ってみることにした。

最初はキーワードが全然わからず苦労した。
XBeeとZigBeeとArduino、さらに懐かしいATコマンドのそれぞれの用語がある。

XBeeをArduinoに搭載するには、XBeeとArduinoを接続する必要がある。簡単なのはシールドを用いることだ。ところが3つ購入したシールドの内の一つが不良であった。4個のXBeeを相互接続したところ、どうしても4つ目が認識せず、Arduinoのせいなのか、XBeeのせいなのか、シールドのせいなのか分からず切り分け試験に苦労した。

ArduinoやXBeeを交換してもなおらないので、シールドが妖しいとにらんだが、プログラムの方も自信がなかったので、確信が持てなかった。シールドの代わりに、XBeeをピッチ変換基板(細かなハンダつけが必要)に載せ変えたところ、問題なく動いた。

3カ所以上のハンダづけは久しぶりだったが、昔取った杵柄なんだね、身体が覚えていた。

なお、ここまでの試験では、ATモードで接続していた。
XBeeに関するATモードでの設定は、スイッチサイエンスのホームページが詳しい。
丁寧に記述されていて、この通りにすれば設定できる。

さてここでATモードというのが出てきたが、XBeeには、ATモードとAPIモードという2種類がある。ATモードは別名「透過モード」とも言う。ZigBeeは本来、規格にあったパケットをやりとりすることで通信する。それがAPIモードである。しかしAPIモードは数字列で普通のプログラマが直接やりとりするには低レベルすぎる。

そこでXBeeでは、APIモードのパケットを独自に変換して、直接シリアルモデムで接続されているかのように見せてくれるモードが用意されている。つまり、ATモードだと、
 PC--シリアル--モデム----モデム--シリアル--Arduino
というイメージで使える。

ただし簡易モードなので、1対1通信程度なら問題ないが、センサノードを複数台扱おうとすると無理がある。ただ、無理がある、といろんなホームページに書かれているが、どの程度無理があるのかと思って、1対3で接続してテストしてみた。PC1台に、センサノード3台をつなげてみた。

PCに繋いだXBeeはCoordinator ATで設定し、ブロードキャスト設定(送信先をDH=0, DL=FFFFにする)で、センサノードは全て、Router ATで設定して、送付先をPCに繋いだCoordinatorにした。


なお、ここでまた新しい用語が出てきた。Coordinatorと Routerである。あとEnd Nodeというのがある。ZigBeeにはこの3種類がある。Coordinatorというのは、一つのネットワークの監視役である。Routerは中継に使われる。End Nodeというのは末端のセンサノードである。End Nodeにはスリープする機能がある。

設定方法は、「Xbee+ArduinoとXbee+Macを繋ぐ方法」に書いた通りで、xctuというソフトを使う。xctuにはWindows版しかない、と多くのホームページで書かれているが、今はちゃんとMac版がある。けっこう使い勝手の良いソフトである。

Coordinatorとか、Routerとか、またはATモードとかAPIモードとかの変更は、ファームを変えることで行う。単に設定変更ではできない。

さて、元に戻って、ATモードの限界についてだが。テストしたのは、Coordinatorから1, 2, 3,...と番号を1秒おきにブロードキャストして、センサノードにそれぞれ番号を割り当てて、自分の番号が送られてきたら、値を返す、という単純なテストである。

最初はうまく行っていた。順調に値が返ってきていた。ところが何十回かやっていると、通信が一時停止することがわかった。細かく追っていないが、ブロードキャストが滞っているものと推察される。その理由はブロードキャストタイミングを早めて、1/10秒ごとに番号を送るようにすると、あっという間に滞るためだ。

滞るのも、1、2秒なら良いが酷い場合には、10秒も20秒も滞る。これでは使い物にならない。ブロードキャストの範囲などを細かく制限すれば、大丈夫になるのかもしれないが、あまり深入りしても時間の無駄なので、ここでATモードとはおさらばすることにした。

さてAPIモードを使おうと思ったが、直接APIパケットを作るのはいくらなんでもやりたくないので、便利なものが無いか探した。最初は小林さん@IAMASたちが作ったfunnelを使おうかと思ったが、Processing 2.0に対応していないというのと、カプセル化が強く、高レベルすぎるのが気になり、もう少し低レベルで扱えるライブラリを探した。

ただ、だいぶ自分の頭が整理できたので、funnelを使うことを再検討してみても良い。

funnelは、小林さんの「Prototyping Lab--「作りながら考える」ためのArduino実践レシピ」の前提とされているライブラリで、未踏で作られたかなりできの良いものだ。2009年に完成しているので、その後のアップデートが滞っているのだろうか?

funnelだと、Arduino側の設定も、PC側からできてしまう。ProcessingでArduinoの入出力まで制御できるというすごいライブラリだ。ただ、このアクロバットをこなすために、ちょっと凝ったことがしてある。私としては、Arduinoは、Arduinoでコーディングして、PCは受信したデータを扱ったり、Arduinoに指令を出すなどの役割分担をする方が、気持ち的に良い。オブジェクト指向的というか。

調べてみると、Arduinoには、XBee-Arduinoというライブラリが、ProcessingというかJavaには、xbee-apiというライブラリがあることがわかった。いずれも

 APIモード
 エスケープモード
を扱えるライブラリである。
今回、「XBee+ArduinoとXBee+Macを繋ぐ方法」で解説しているのは、この方法である。

さて、ここでまた新しい用語「エスケープモード」が出てきた。APIモードでは、すべてのパケットは0x7Eで始まる。よってパケットの中に0x7Eを含むデータがあると、パケットの先頭と間違える可能性がある。そこで、パケット内の0x7Eを別の値に退避(エスケープ)させることで、0x7Eを扱えるようにするモードである。

実はXBeeをこのモードに設定する方法がわからず、けっこう苦労した。結論としてはxctuで、AP-API Enableという設定項目を「2」に変更することで行う。

エスケーブモードにしていないとライブラリは全然動いてくれない。

また二つのライブラリを使うので、どっちのライブラリの使用方法にエラーがあるのか、の切り分け試験ができずに苦労した。

これは結論としては、PC側はシリアルモニタで監視できるので、最初にXBee-Arduino側から確認する、のが良いことに気づいた。

まずXBee-Arduinoをインストールして、データをZigBeeに送り出す簡単なサンプルプログラムをArduinoに転送することとした。XBeeを繋いだPCでシリアルモニタにより、シリアルを監視すると、値が一定時間毎に送られているのを確認できる。

ここでシリアルモニタとしては、Cool Termが良い。HEX表示もあり、使い勝手が良い。

ちゃんと値が送られてこない場合は、XBee-Arduino側に問題がある。私の場合は、エスケープモードになっていなかったためだった。

次に、Processing側のxbee-apiの設定をした。ちなみにxbee-apiに関しては、あまり日本語の情報が多くない。javaでxbeeを使おうという人がまだ多くないということだろうか?

ちなみにProcessingとは、MITで開発された簡易言語である。ここまで読むような人で知らない人はいないよね。javaベースで、javaネイティブで書くより簡単に可視化などのプログラミングができる。ProcessingのIDEは、ArduinoのIDEと見た目や使い勝手がそっくりなのも、Arduinoと一緒に使うときの敷居を下げている。

xbee-apiで苦労したのは、ドキュメントが少なく、未だに更新され続けているためだった。
例えばProcessing 2.0.3までは、私がアップしたコードで動く。しかし、2014年3月の最新のProcessingでは、RXTXというシリアルを扱うライブラリが使われなくなっており、xbee-apiが前提としているため、RXTXを別にインストールしないと使えない。

なおlog4jは使わなくても動く。log4jを使わないようにコメントアウトすると警告(Warning)が出るが、通信自体には影響がない。

Arduinoにモバイルバッテリーを繋いで、PCから離して、寝室に置いてみた。3DKの鉄筋コンクリートで、リビング-寝室間は-92dBとかなり電波状況が悪い。1秒一回の通信で5000回のテストの間に15回エラーが生じている。まぁ、そんなものか。

以上










XBee+ArduinoとXBee+Macを繋ぐ方法

Xbee APIモードの扱い方
なるべく簡単に、かつ間違いなく、安定してXBee+ArduinoとXBee+Macを繋ぐ方法

必要品は、「XBeeをはじめてみよう(ZB編)」
で用いている物に、Mac (MacBook Air)である。

1. xctuのダウンロードとインストール
「ArduinoUnoとXBeeとMac... Mac版のX-CTUを使って設定しちゃおう」
に記載のあるnew xctu for Mac
をダウンロードし、インストールする。

2. XBeeの設定
XBeeをXBee USB アダプターにセットし、それをMacに接続する。
xctuを起動する。
「Add Device」でusbserialを選んで、XBeeを設定できる状態にする。
最終的にMacに接続するXBeeは、
Coordinator API
に設定する。設定方法は、ファーム更新で選択する。

PAN-IDを好きな4桁の数字にする。これがZigBeeネットワークの識別番号、
相互接続する他のXBeeも同じ数字をPAN-IDに入れる。

AP-API Enable 2にする。これでEscモードになる。

一旦、USBを抜いて、XBeeをArduinoに搭載する側に交換する。
Arduino側のXbeeは、
Router API
に設定する。
PAN-IDは上記と同じ数字。AP-API Enableも同じく2とする。

3. XBeeとArduinoの結合
XBeeをXbeeシールドに載せ、XBeeシールドをArduinoに載せる。
XBeeシールドの小さなスイッチをUSB側にする。
ArduinoをUSBで、Macのもう一つのUSBに接続する。
Arduino-IDE(アプリケーション名はArduino)を起動する。

4. XBee-Arduino
XBee-Arduinoのサイトに行き、
xbee-arduino-0.5.zip(番号は更新されているかもしれない)をダウンロードする。
Arduino-IDEの「スケッチ->ライブラリを使用->Add Library...」でダウンロードしたファイルを選択する。

5. サンプルプログラムをArduinoに転送
以下のサンプルプログラムを、Arduino-IDEで「マイコンボードに書き込む」。
一旦ArduinoをUSBから外し、XBeeシールドの小さなスイッチをMICROに変更する。
再びArduinoをUSBでMacに接続する。

----
#include <XBee.h>

XBee xbee = XBee();

// 送付データは1バイトづつの配列に入れる
uint8_t sendData[] = { 'H', 'L' };

// 送付先のXbeeのアドレス (PCに繋いだCoordinatorのアドレスを入れる。アドレスはXbeeの裏に印刷されている。
XBeeAddress64 remoteAddress = XBeeAddress64(0x0013a200, 0x40b93ccb);

// 送付データをAPIパケットに変換する。詳細な説明は以下:
// http://xbee-arduino.googlecode.com/svn/trunk/docs/api/class_z_b_tx_request.html
ZBTxRequest zbTx = ZBTxRequest(remoteAddress, sendData, sizeof(sendData)); 

// counterは送付データの例delay毎に+1する。
int pin5, counter;

void setup() {
  Serial.begin(9600); // シリアルを9600bpsで使用開始
  xbee.setSerial(Serial); // xbeeが受け持つシリアルを設定
  counter=0;
};

void loop() {
  // pin5を使っているのは、Arduinoのpin入力データを送付するイメージだから。今はダミーのcounterを送っている。
  pin5 = counter++;
  
  // 送付データはHigh, Lowの2つに分けて送付する。この作業の役割に関しては以下の解説が詳しい。
  // http://yoppa.org/tau_bmaw13/4832.html
  sendData[0] = pin5 >> 8 & 0xff;
  sendData[1] = pin5 & 0xff;
  
  // データを含んだパケットを送付
  xbee.send(zbTx);
  
  delay(1000); // ちょっと待つ
};

----

6. Cool Termで確認
Macで、Cool Term
を起動する。(入れていないならダウンロードしてインストールする)
Cool Termで、Arduinoではなく、Xbee+USBアダプターが入っている方のシリアルをオープンする。名前はusbserial-...と言った名称である。
文字列が一定時間おきに、ばらばら出てくるようなら接続成功。
Arduino->XBee---->XBee->Mac
という接続がなされている。

7. Processingでサンプルソフトを起動
新しいスケッチ画面を開く。
xbee-apiをダウンロードする。
展開したフォルダの直下にある xbee-api-0.9.jarと、libフォルダに入っているlog4j.jar, RXTXcomm.jarを新しいスケッチ画面にドラッグアンドドロップする。
もしくは、スケッチのcodeフォルダにコピーする。
スケッチのdataフォルダに、xbee-api-0.9フォルダ直下の、log4j.propertiesをコピーする。
以下のサンプルプログラムをスケッチにコピーする。
Runすると、画面に数字などが表示される。数字が更新されていればProcessingでデータを取得できている。

----
// KYDrill氏のコードを元に作成(オリジナルは以下のURL)
import processing.serial.*;
import java.util.concurrent.*;
import java.util.Queue;
import org.apache.log4j.PropertyConfigurator;

XBee xbee;
Queue<XBeeResponse> queue = new ConcurrentLinkedQueue<XBeeResponse>();
boolean message;
XBeeResponse response;

String senderAddress = "00:13:A2:00:40:B9:3C:CB";
String rxStr = "********";
String txStatus = "";
int rssi = 0;
int rxVar, oldrxVar, rxErr;

void setup()
{
  size(640,150);
  colorMode(RGB,256);
  background(0,0,0);
  rxVar = oldrxVar = rxErr = -1;
  
  try {
    //optional.  set up logging
    //PropertyConfigurator.configure(dataPath("")+"/log4j.properties");
    xbee = new XBee();
    // replace with your COM port
    xbee.open("/dev/tty.usbserial-A5025X1E", 9600); // xbeeを繋いでいるシリアルポートを指定
    xbee.addPacketListener(new PacketListener() { // xbeeのレスポンスを待つパケット監視を設定
      public void processResponse(XBeeResponse response) {
        queue.offer(response);
      }
    }
    );
  } 
  catch (Exception e) {
    System.out.println("XBee failed to initialize");
    e.printStackTrace();
    System.exit(1);
  }
}

void draw(){
  // パケット読み取り
  try {
    readPackets();
  }
  catch (Exception e) {
    e.printStackTrace();
  }
  
  background(255);
  textAlign(LEFT);
  textSize(20);
  
  // 受信強度の表示
  fill(0); text("RSSI", 10, 25); fill(0,0,255);
  text(String.format("%d", rssi) + "dB", 100, 25);
  
  // 受信元アドレスを表示
  fill(0); text("Address", 10, 50); fill(0,0,255);
  text(senderAddress, 100, 50);

  // 受信データの表示  
  fill(0);
  text("Rx Data", 10, 75);
  fill(0,0,255);
  //text(rxStr, 100, 75);
  text(rxVar, 200, 75);
  text("ERR:"+rxErr, 300, 75);
  
  // 受信状態の表示
  fill(255,0,0);
  text(txStatus, 10, 100);
}

// パケットの読み込みとエコー、ATDBの送信
void readPackets() throws Exception {

  while ((response = queue.poll()) != null) {
    // we got something!
    try {
      if (response.getApiId() == ApiId.ZNET_RX_RESPONSE && !response.isError()) {
        ZNetRxResponse rxResponse = (ZNetRxResponse) response;
        
        // アドレスをintで取得
        int[] addressArray = rxResponse.getRemoteAddress64().getAddress();
        String[] hexAddress = new String[addressArray.length];
        // 16進数のStringへ
        for(int i=0; i<addressArray.length;i++){
          hexAddress[i] = String.format("%02x",addressArray[i]);
        }
        // 送信元アドレスを文字列で保存
        senderAddress = join(hexAddress,":");
        
        //受信データを取得
        int[] rxData = rxResponse.getData();
        rxStr = "";
        for(int i=0; i<rxData.length; i++){
          rxStr += String.format("%c", rxData[i]);
        }
        // Arduinoのプログラムと対応して、2バイトのintデータを前提にしている。
        rxVar = rxData[0] << 8 | rxData[1];
        if (rxVar != oldrxVar + 1) rxErr++;
        oldrxVar = rxVar;
        
        // エコー (送られてきたデータを、そのまま返信)
        int[] payload = rxData;
        XBeeAddress64 addr64 = new XBeeAddress64(addressArray); // データの送信元アドレスを設定
        ZNetTxRequest request = new ZNetTxRequest(addr64, payload); // 送られてきたデータをAPIパケットに変換
        try {
          // データ送信
          ZNetTxStatusResponse response = (ZNetTxStatusResponse) xbee.sendSynchronous(request);
          txStatus = "";
        } catch (Exception e) {
          txStatus = "tx request timed out";
        }
        
        // ATコマンドを送信し、RSSIを取得
        AtCommand  at = new AtCommand("DB"); // ATDBで、RSSIを取得し、電波強度を調査する。
        AtCommandResponse response = (AtCommandResponse) xbee.sendSynchronous(at, 5000);
        if (response.isOk()) {
          // 成功
          rssi = response.getValue()[0];
          rssi = rssi * (-1);
        }
      }
    }
    catch (ClassCastException e) {
      // not an IO Sample
    }
  }
}



----

以上




2014年4月13日日曜日

論理哲学論考を読んで

『論理哲学論考』(岩波文庫)を読み終えた。単に読み終えただけで、細かく論証を追った訳ではない。とりあえず何が書いてあるか知って、それに対して現時点で自分がどう考えるかを知りたかったからだ。

読み始めてすぐに思ったのは、論理学の教科書のようだということだ。大学で論理プログラミング、ひいては数理論理学を学んだので、懐かしい、という印象が最初にあった。記号論理学の教科書的内容にそれなりに多くの項目が割かれている。

関数の扱いや等号理論にも彼なりの記述があって、それもなかなか面白かった。私が習ったのとは多少違うが、ラッセル・ホワイトヘッドのプリンキピアマテマティカ以降、どういう流れで、現代の数理論理学に来ているのかは知らないため、違いの意味までは追えなかった。ウィトゲンシュタインはゲーデルのことは知っていたのだろうか。

最初は哲学の本だと思って読み始めたら、論理学、それも意味論の話だったので、若干肩すかしであった。ところが全編を読んでみて、なるほどこれは哲学の本だと分かった。その自分の中での変化が面白かった。

私にとっての哲学的意味は、冒頭と最後あたりに現れる、語りえぬもののエッジに関する記載にある。沈黙しなければならない所に、人間は自然と点線を引いてしまう。それは私にとっては、神、美、善、夢想といった域外の何かである。彼は当然何も語らないのだが、ぎりぎりまで追いつめることによって、より鮮明に私の心に浮かぶ何か。ホラー映画で、化け物が登場する直前の、ぎりぎりの瞬間が最も怖いのと同じように。これは人間の思考のどういう仕組みだろうか。

訳者による注釈が丁寧で読みやすい。ラッセルによる解説も、たしかに勘違いはありそうだが、これはこれでラッセルの見方が読み取れて面白い。さらに訳者による解説もいい。さすが岩波文庫だと思う。

この『論理哲学論考』という薄い本にはたしかに、妖しい魅力がつまっている。私にはボルヘスの短編を彷彿とさせた。


2014年3月21日金曜日

気合いの入っていないパン

いま住んでいる東京都世田谷区には、たくさんのパン屋がある。
家の近所にも徒歩圏内に10軒近くはあるだろう。
いろんなパンを食べ比べられる贅沢な場所にいるせいか、
気になることがある。それはパンの「気合い」とでもいうべき味
の違いだ。

まず、その違いに敏感になるのは、大手のパン屋チェーンが新し
く出店した店でパンを買う際だ。

例えば、成城学園前と仙川に、アンデルセンが出店している。
開店当初のパンには「気合い」が入っていて、さすがの味だった。
おそらく本店からベテランの職人さんが、開店に合わせて来て
アントニオ猪木のように気合いを注入しているに違いない。

ところが、開店から半年もすると、徐々に味が「なまってきて」、
「キレがなくなり」、全体にメリハリの無い味になっていく。
皮のパリッとした感じとか、中の水分量とか、フィリングや
混ぜ込まれた材料の感じとか、がダメダメになっていく。

私はパン屋に勤めたことはないので、何が違うとあぁいう風に
なるのか分からないのだけど、味がゆっくりとではある
が明らかに落ちて、「気合い」が感じられなくなってくる。

そして、恐らく、作っている職人たちは、それほど変化がある
ことに気づいていない。毎日作っているので、小さな変化に気づ
かない。

でも、時々買いにくるお客さんには、違いは、久しぶりにあった
親戚の子供の成長のように、この場合は逆だが、衰えぶりが
ハッとするぐらいわかる。

墨繪が豪徳寺に出店していて、そこも、アンデルセンほどでは
ないが、新宿で買うのとは明らかに違って、気合いが足りない。
あの新宿の墨繪で買える、ゴツゴツとした頑固な美味さには少し
届いていない。

硬いから気合いが入っているとか、いうのではない。材料が贅沢
に使われているから良いというものでもない。

例えば近所にオンカという、とても柔らかいパンを作っているパン屋
がある。押し付けるとペシャンコになってしまいそうな柔らかいパン
だが、きちんと角のたった気合いが感じられる。ラ・ヴィ・エクスキ
ーズのパンは弱ハード系で、焦げ目もしっかりしていて、明らかに
キリッとしている。仙川にはムッシュ・ピエールというとても小さな
パンを売っている、小さなパン屋があるが、あのパンの気合いは何か
ご主人の精神が固まったかのような感じすらする。

大手のチェーン店だから駄目という訳ではない。ディーンアンドデル
ーカは比較的味を維持しているし、個人経営のつまらないパン屋もた
くさんある。ただ、なんか作っている人の、配慮というか、バランス
感覚というか、技術と責任感が、一個一個のパンに現れるのだと思う。
大手だと、その配慮が届きにくいのかもしれない。

上述したように、この気合いが、作っている人には分かりづらく、
客には鮮明に分かる、というあたりが、物を売る仕事の難しさだと
思う。

美味しいパンに出会いたいなぁ。