2011年12月20日火曜日

ドコモXiルータLG製L-09Cのファームウェアアップデートで苦戦

いろんなブログで苦情が出ているが、どうにもこうにも、LGのファームウェアアップデートアプリケーションの頑固さには困った。

まず、以下の条件がクリアされていないとファームウェアアップデートのアプリケーションがダウンロードできない。
  1. ルータ機器本体がWindowsマシンにUSB接続されていること
  2. ルータに電源が入ってデータ通信可能な状態になっていること
  3. ルータのUSBストレージから見えるドライバセットアップが完了し、
    • シリアルポート(COMポート)
    • モデムデバイス
    • USBデバイス
    として認識されていること
  4. WindowsマシンがルータとWi-Fi接続して、192.168.2.0/24のIPアドレスをDHCPで設定された状態になっていること
これでようやくファームウェアをダウンロードして書き換えるアプリケーションのインストーラがダウンロードできる。

次に、このインストーラ「B2CAppSsetup.exe」なのだが、これも上記の条件が維持されていないと起動しない。僕はここで詰まってしまった。ドコモに電話しても、わからないという回答の繰り返しでどうにもならない。「ドコモショップでアップデートしてもらう」という最後の選択肢を示唆しながら、それもどうもねぇ的な説明で、すっきりしない。

担当者といろいろ話をしていて、もしやWi-Fi以外の通信があるとだめなのではないかと思い、まずLANを切る前に、最初にPacketiX VPNを停止してみた。すると動かないまま止まっていたプログレスバーがするすると進み、インストールが完了した。そして、「LGMobile update」が勝手に起動して「機器の認識」をしはじめるではないか。

なにはともあれ、この状態で放置していたらファームウェアのダウンロードとルータへの書き込みも終わった。

結論として、教訓というか、この恐るべきパラノイア的なガードはなんなのかと思う。
  • ハードウェアが存在していること
  • データ通信契約が有効であること
  • 余計な通信路が設定されていなこと(盗聴防止?)
  • キャリアの回線からのみファームウェアをダウンロードすること(パケ代は利用者負担)
  • インストーラがWindowsに限られていること
いずれも大きなお世話なのではないだろうか。それほどまでして守りたいファームウェアってなんなのかと。ダウンロードしたファームウェアは書き込み後、即座に消しているようだ。バージョンチェックは、再起動したルータ本体と通信して確認している。

製品として使う分には文句なしだったのだが、こういうことがあると今後はこの手の製品には手を出したくなくなる。ドコモがLTE対応iPhone(iPhone5と噂されているもの)を扱うようになったら、そこからテザリングすることでよしとしようかと思う。

2011年11月16日水曜日

DRMは邪悪なのか

DRMというのは、「Digital Rights Management」の略で、デジタルコンテンツに対する権利保護技術、ということになっている言葉です。

昔、AppleがiTunes Plusという、「従来より値段が高いけれど高音質で、しかもDRMフリー」を謳い文句にした楽曲配信の新サービス開始にあたり、Jobsが「DRM is evil」と宣った件があるのだけれど、つらつら考えているうちに、Jobsの言っていた意味がわからなくなってきたわけです。

というのは、AppleがDRMフリーにしているのは、iTunes Plusになっている楽曲だけで大半は相変わらず1曲120円DRMつきだったりするし(つまり顧客はDRM有無より価格を選んでいる?)、映像はすべて独自の(しかもiTunesのバージョンアップとともにより堅固になっている)DRMつきで、Apple IDで認証され正規購入したものに限って販売(あるいはレンタル販売)していてApple純正のプレイヤーでしか再生できないし、iBookStoreは購入したことがないからわからないけれど、iBooksにサンプルでついてくる「Winnie the Poo」(くまのプーさん)はApple独自のDRMで暗号化されていて、iBooks以外で開くことはできません。サンプルがDRMつきというのは、DRMフリーな本がiBookStoreに存在するのかどうか、疑問に思う次第です。

あと、Kindle Fireはみんなとても気にしていて、出たら買うぞという勢いの人が大勢いるような気配がネットでも漂っているわけですが、Kindle Storeで買った本はKindleでしか読めないんだけどみんな気にしないのかな、と不思議に思ったりするわけです。KindleはMac版もWindows版もiOS版もAndroid版もあるから困らない、とみんな思うんだろうけれど、紙の本なら自分の本棚の整理は自分でできるんだけれど、Kindleしかなかったら、Amazonが扱わない電子書籍は絶対入手できないという点に疑問は感じないのかな、と。ちなみにKindleはAZWというAmazon独自のファイル形式で(なかみはWebをベースとした、EPUBなどと似たもののようですが)、DRMも独自です。

で、楽天が買収したカナダ(トロント)の会社Koboの端末は、DRMなしのいろいろな文書を入れることができて、特にオープンな電子書籍規格であるEPUBに対応していて、DRMについてはAdobeのDRMに対応しているので、SONY ReaderやNOOKのために買った本や、Google Booksで買った本などの「DRMつきEPUB」も入れて開くことができるから、購入の選択肢が広くていいよね、と思っていたわけです。

ところが、AdobeのDRM(Adobe Digital Experience Protection Technology)とはどんなものかと調べてみたら、まず利用者のAdobe IDを登録して、端末やリーダーは6つまでだけれども登録が必要で、その上で認証がとれたらようやく暗号を解いて内容を表示できるようになる仕組みということがわかって、これはどうなのかと思った次第。

特に、DRM管理ツールであるAdobe Contents Server紹介のページで「System Overview」タブを開くと出てくるをじっくり見ていると、どこのオンライン書店であれ、顧客登録したらAdobeにそれが通知され、購買行動を起こしたこともAdobeに通知され、買った本を開くためにまたAdobeと通信するのが示されているのに気づいて、ということは、電子書籍にまつわる利用者の行動大半がAdobeのクラウドに知らず知らずのうちに蓄積されていくのであって、そんなことオンライン書店しか見てない客は知らんよなぁと思ったわけです。この商品についてのAdobeの主張は「自社製品しか認めないAppleやAmazonのシステムよりもfairだ」ということなんですが、「fairの意味ってなによ」と問い詰めたい衝動におそわれたりしました。

著作権の文脈でfairといえば「fair use」であって、著作権所有者と利用者の間で利害が公平であることを指すのですが、ツタヤのTカードよろしく個人情報集めまくりのプラットフォームを構築したAdobeは、著作権所有者と利用者の間の仲介者としてオンライン書店の裏側に潜んで情報を集めているという意味で、同じくあらゆる購買行動をデータ化しているAmazonと、どっこいどっこいなんじゃないかと思うわけです。むしろショップとして対象が見えているAmazonより陰湿な印象すら感じられてもおかしくはないんじゃないかと。

Amazonが顧客情報を持つ強みを発揮して出版社に対し恫喝まがいの営業をかけたり、取り扱いを制限するような報復行動をとっているという話は、探してみると英語や日本語で結構出てきます。サイトでおすすめされる商品、実は裏で巨額のお金がAmazonに渡ってますとか。日本の出版社と書店の間で動いているお金とはちょっと規模が違いますよ的な。

CD、DVD、紙の書籍といった現物は、著作者の意向がある程度反映されたり利用者も匿名で入手できるし保管も移動も自由にできるわけですが(さらに中古市場もあって、文化的なアーカイブの機能も果たしているのですが)、音楽配信や映像配信、電子書籍ではどうも著作者でもなければ利用者でもない、プラットフォームを握っている側の力があまりにも強すぎるのではないかという考えにだんだん傾いてきました。

特にDRMについては、個人の特定が可能な運用が基本にあって、さらに、現物で可能だった保管や移動の自由が制限される可能性が十分にあります。オンライン書店なくなったら本が読めなくなったとか、端末壊れたらデータが再取得できるかはDRMかけた側の都合次第とか、「せっかく買ったのになんだか理不尽な感じ」のことがいろいろと想定できるのです。「絶版」が、本当の意味で世の中から消えることを意味する可能性が十分にあるということです。中古市場がないわけですから。

まぁ、絶版問題については国会図書館とかにはDRMフリーで納入すべしとか法律かなんかで縛るとか手段はあるのかもしれないんですが、「だったら出さない」とか「たっぷりお金はいただきます」とかの本末転倒な話もありそうで、著作者と利用者おいてけぼりという未来が、なんとなく感じられなくもありません。っていうか、古文書とかが発掘されたとして、まぁ未来はいまのDRMなんか瞬時に外せるのかもしれませんけど、解読不能になったら歴史はどうなるのとか血迷ったりしてしまいました。

古書店に行くと、一般には絶対流通しない、関係者限定の本とか、特定の機関が限られた数だけ配布した本とか、地下活動していた人が配布していた冊子とかが何気なくそこにあって、これもすべて文化だよなぁと思うのですが、未来はどうなるのかなぁ、と。

たぶん、そんなあれこれがあって、海外には独立系の電子書籍サイトがいっぱいあるのかもしれません。入ったことはありませんが、プロプライエタリなDRMなんかはついていないんだろうなぁ、とも。

DRMつきの著作物が流通する意義は認めていますので、それはあっていいのですけれど、できればオープンな仕様で、仲介者のビジネスもクリアな形であれば、なんだか不透明な現状よりは、よほどいいとは思うのです。どうもこう、不況だととにかく中身がおんなじなら安けりゃあとはなんでもいいというところに走りがちではあるのですが。我が身を振り返っても。

2011年11月11日金曜日

子どもとケータイの関係が心配な親はiPhoneを選ぶべき

Androidについて知らないのでこういうタイトルになっているんだけれど、もしAndroidでも同じことができるなら「スマホ」と範囲を広げてもいい。

なんでもかんでも、新しいものが出るとすぐに規制したがる人々がいて、もちろん「よくわからないものは信用しない」のは正しい態度なのだけれど、「だからお上がきちんと取り締まらなければならない」という議論に引っ張られるのは、まさに「自由からの逃走」(フロム)だと思う。そんなに管理社会、監視社会が好きなのかね、と。

「子どもとケータイの関係」が問題になっているのは、i-Modeがすべての発端だったのではないだろうか。 ドコモが戦略的に「勝手サイト」への誘導を図った結果、大人がしっかり騙されてエロサイトなどに誘導され、ドコモは通信料がとれて儲かったという話を「しかるべき筋」の話としてきいているので、こう書くわけだけれど。

通話とメールだけなら、ここまでみんなして「困った、困った」と騒がなくてよかったはずで、Webに直通したおかげでいろいろと、ダークだったりグレーだったりするビジネスが生まれたと考えるわけです。

で、スマホは規制がかからないから危ないとか、また大きな勘違いを喧伝している人々がいて、たぶん規制したい側が意図的に流したネタをうっかり信用している人が伝言している状況だと思うのだけれど、どうしたものかと思う。

どうも知らない人が多いようなので、わざわざ書くまでもないことを書くわけだけれど、iOSには、アプリの起動制限をかける機能があります。親がパスワードをかけて、動かしていいアプリを決めることができるのです。

iOS: 機能制限について (Apple公式ページ)

極端な話、電話とメールだけにすることも可能なわけです。特に、SafariとApp Storeを動かないようにできるという点がとても大事。これだけで、i-Mode被害のほとんどは回避できるはず。

いみじくも、「ペアレンタルコントロール」という説明になっていることを、ケータイを買う親はかみしめてほしいわけです。自分の子どもがなにをしてはいけないか、それぞれの家の都合で決められるということです。この自由を手放してはいけない。

でもって、もしWebが必要ということがあるなら、それこそ「子ども向けWebブラウザ」アプリを出して、それをインストールして使ってもらうことにすればよい。ビジネスチャンスはここですよ。まぁ、有名企業やキャリアの名前で出さないと商売にならないかもしれないけれど、それならそれ、ソフトバンクさんも、富士通さんも、その他みなさん商売してください。

大人を騙して金を巻き上げる商売する側と、規制したい当局は、いろいろと惑わせるような話を大々的に流してくると思うけれど、大人の皆さんは冷静に考えて、せっかくの自由を売り渡すようなことはゆめゆめしないようにお願いします。

2011年11月8日火曜日

FFmpegとMacPorts

動画変換最強プログラムのffmpeg(巷のGUI動画変換アプリも中身はffmpegのコマンドラインを作っているだけだったりする)だけれど、Lion 10.7.2 + Xcode 4.2では、MacPorts版がコンパイルできない。

LLVM GCCではMMX関係のマクロの展開に失敗しているような感じで、未解決のシンボルがどうのといって止まってしまう。

困っていたのだが、検索してみたところ、configure時に--cc=clangオプションをつけて、clangでコンパイルすればよいという説明があり、試してみたら成功した。

おそらく、コマンドラインはこんな感じだと思う。
port install ffmpeg-devel configure.cc=clang
僕は、最新版のGitリポジトリから入れた。とはいえ、依存ライブラリから全部自前では面倒なので、いったん普通にportでffmpegを入れようとして、依存ライブラリが全て入ったところでffmpegのconfigureに失敗するところから始めた。

まず、
port clean ffmpeg
したあと、適当なディレクトリに
git clone git://git.videolan.org/ffmpeg.git
して最新のソースツリーを取得し、そのあとでMacPortsが与えるオプションを用いてconfigureを実行する。

ただ、気のせいかどうかわからないけれど、gitの結果できるffmpegディレクトリのなかに再びffmpegディレクトリがあったような気がするので、あれば消しておく必要がある(実行ファイル名とディレクトリ名がぶつかり、エラーになるから)。.gitignoreにffmpegと書いてあるので、次回のpull時に復活する可能性はないはず。

与えたオプションは以下の通り。
./configure --prefix=/opt/local --enable-gpl --enable-postproc --enable-swscale --enable-avfilter --enable-libmp3lame --enable-libvorbis --enable-libtheora --enable-libdirac --enable-libschroedinger --enable-libopenjpeg --enable-libmodplug --enable-libxvid --enable-libx264 --enable-libvpx --enable-libspeex --mandir=/opt/local/share/man --enable-shared --enable-pthreads --extra-ldflags="-L/opt/local/lib" --extra-cflags="-I/opt/local/include" --enable-version3 --arch=x86_64 --cpu=x86_64 --cc=clang
あとは、make && make installすれば/opt/local/bin以下にffmpeg関係のバイナリが入る。

MacPortsのffmpeg-develはまだsvnのリポジトリを参照しているようで、まだ0.7あたりのようだ。gitのほうは、すでに0.8は終わってその次になっているので、gitからビルドしたほうが、より高速で高機能かつ高画質なバイナリが得られるはず。ffmpeg-develリストを読む限り、少なくともMacに関しては、「VDA (Video Decode Acceleration Framework)」が最近入ったので、H.264のデコードがGPUによって行われる分、変換が高速になるはず。また、DCTのテーブルも調整されているので、画質向上も図られていると思われる。

なお、MacPortsで入っているx264が古いためか、MP4にエンコードする際にCPUのもつMMX等のスーパースケーラー機能がないと勘違いし、ひどく遅くなる。x264もGitで最新版にしておく必要があるようだ。
git clone git://git.videolan.org/x264.git
configureのオプションは、MacPortsにしたがって、
./configure --prefix=/opt/local --enable-pic --enable-shared
としておいた。make && make install後、ffmpegを再度ビルドしなおせば、例えばCore2Duoの場合なら
[libx264 @ 0x7fee9a0bc800] using cpu capabilities: MMX2 SSE2Fast SSSE3 FastShuffle SSE4.1 Cache64
のように、きちんとCPUに装備されている並列計算機能を利用してくれる。失敗した場合は、この表示が「none!」になってしまう。

2011年10月24日月曜日

I-O DATAのGigaBit Ether USBアダプタをLionで使う

MacBook Air用にGbEのUSBアダプタが各社から出ている。

そして、いずれもSnow Leopardまでの(32bitモードでの)対応となっている。

しかし、いずれも同じ台湾のASIX(亞信電子社のチップAX88178を使っているようで、チップメーカーから直接ドライバをダウンロードすればLionでも動く。

ちなみに僕がはまったのは、I-O DATAのETG3-US2だ。

Linux用、Windows各種用もここから最新のものをとってくればいいのではないだろうか。

Macの場合、まぁいまどきのUNIXなのでkextなのだが、場所は

/System/Library/Extensions/IONetworkingFamily.kext/Contents/PlugIns/AX88178.kext
にインストールされるようだ。バイナリはi386, ppc, x86_64の3つのユニバーサルバイナリ。Tigerとかにも対応するためだと思う。

2011年10月21日金曜日

Node.jsが面白い

Node.jsは、よく「サーバサイドのJavaScript実行系」と言われるが、よく見ると、Google ChromeのJavaScriptエンジン「V8」を実行する処理系そのもの、といえる。

一般的な説明だけでは、「Apacheに組み込むのか? それともCGIとして実行するのか?」などの疑問が生じるが、生成されたコマンドnodeをただ実行してみると、プロンプトが出ることで、「つまりインタプリタそのもの」ということがわかる。

> 3+5
8
のような具合だ。JavaScriptのコマンドをそのまま受け取って実行結果を返してくる。

プログラムの実行は、ファイル名を引数として与えてやることになる。そして、プログラムのなかで、TCP/IPのサーバやクライアントとなるモジュールを使ったメソッドなどを書いて、それを実行してやることでWebサーバにもなれる、というわけだ。

http://nodejs.org/ のトップページにある1時間程度の講演が、すべてを物語っている。JavaScriptを多少なりとも触ったことがあるプログラマなら必見だと思う。

Macの場合、MacPortsにnodejsとnodejs-develの2つがある。後述するCalipsoは、0.4系のNode.jsでなければ依存するモジュールのバージョンが合わずインストールに失敗するので、nodejsのほうを入れてやることになる。

Node.jsをサポートするモジュール群は、Perlなどのモジュールと似たような管理をされていて、npmというコマンドで管理することになる。といっても、npmは内部でnodeを呼び出しているので、実際にはJavaScriptが動いているということだ。

公式サイトでは、curlを使って直接ソースを取得してインストールする方法が紹介されているが、MacPortsでnpmをインストールするほうがなにかといいだろう。

Node.jsでサーバサイドJavaScriptがプログラムできるのなら、何か適当なサンプルになるものはないかと探したところ、CalipsoというCMSが開発されていることがわかった。CMSはバックエンドにデータベースサーバを持つが、CalipsoはMongoDBだ。MongoDBはいわゆるNoSQL(SQLでクエリしないデータベースサーバ)であり、JSONでデータのやりとりをするので、Node.jsにうってつけといえる。

問題は、今日現在、MacPortsにあるMongoDBはXcode 4.2ではコンパイルできないこと。というより、LLVM GCCに対応していないようで、clangでコンパイルが通らない。そこで、/usr/bin/{gcc,cpp,g++}を使うように、オプションを与えてportコマンドを実行するというkludgeがMacPortsのメーリングリストで紹介されていた。


sudo port install mongodb configure.cc=/usr/bin/gcc configure.cpp=/usr/bin/cpp configure.cxx=/usr/bin/g++
「configure.??=xxx」というオプションで、それぞれを指定するということができるようだ。実際、-vオプションをつけて様子を見ていたところ、clangやclang++が使われることもなく、見慣れたgccによるコンパイルが行われていた。

MacPortsなので、インストールしたMongoDBは、port load mongodbコマンドで起動してやることになる。そのあとで、Calipsoのサイトにあるように、Git cloneしてソースを取得し、npm installすればよい。実行は、node  appでとりあえず、コンソールにログが出る形で試すことができる。ポート番号は3000番になっているので、ブラウザから適当にhttp://127.0.0.1:3000/などとして開いてみれば、動作していることがわかる。

というところまでやったのだが、あとが続かない。とりあえずきょうはここまで。

2011年10月18日火曜日

MacPorts vs. Xcode 4.2

As all whom upgrade Xcode on Lion to version 4.2 suffered a devastating problem, the dramatical change of new Xcode 4.2 is not compatible with past-installed MacPorts binary.

If you meet the problem of MacPorts in configuring, or building, then please try

port upgrade --force installed

first before "port selfupdate".

This command let the MacPorts recompile everything already installed in your Mac.

You may remember when you upgraded your OS to Lion, the MacPorts recompile everything with Xcode 4.1.  This is the same as that time because the compiler configurations are dramatically changed between Xcode 4.1 and 4.2.

Then, you may do "port selfupdate && port upgrade outdated".  Everything must be OK.

----Japanese below:

MacPorts利用者で、Lion 10.7.2とともにXcode 4.2に変更した方は、MacPortsが奇妙な挙動をするのにお困りと思います。

  • upgradeの際、configureが文句を言う
  • 新たにinstallするものがコンパイルできない
  • その他

これは、Xcode 4.2で標準コンパイラが完全にLLVMに移行したことによるものです。

既存のバイナリはXcode 4.2でコンパイルしたバイナリとの互換性がないので、上記のようないろいろなトラブルが発生します。

そこで、まず最初にすべてをリコンパイルしましょう。これは、Snow LeopardからLionにアップグレードしたときに、Xcode 4.1がMacPortsのバイナリをリコンパイルしてくれたのと同じです。

コマンドは、
port upgrade --force installed
です。selfupdateしてしまった人は、outdateなものをいったんuninstallする必要があります。

いったんすべてリコンパイルすれば、問題は解消するはずです。

2011年9月9日金曜日

Firmata-develが喧しい

RやRMeCabについてはまた後日書きます。結構面白い。

いま、ドリトルV2.2のArduino対応を、Firmataという、MIDI(音楽などで使われる、あの通信規格)準拠のプロトコルに置き換えたらどうなるだろうということを考えて、Firmataの拡張性に期待して様子をみているところ。

最新版が、いまいくつなのかわからないけれど、最後にダウンロードしたのは2.2。で、firmata-develのMLを購読し始めたんだけれど、毎日10件ぐらい流れて修正、拡張提案、実際のコードなどがばんばん出てきて、たぶんいまsvnでとれるのは、2.3か2.4だと思う。

2.3はI2C(あい・すくうぇあ・しー)という2 wireのデバイス間シリアル通信プロトコルを正式サポート。送信と受信のポート2つを使うから2 wire。センサICなどでI2C通信するものがよくある。あと、Arduino IDEがいままさに1.0になる寸前で、仕様が変わっている部分があるのでそれへの対応。

2.4という声が出ているのは、なんだったっけ。アナログポートをデジタルポートのように使えるようになるからピン番号をD13の次からに割り当てるとかそんな議論は2.3のときの話だったかな。

というわけで、毎日svn版は変わっているので(しかも、バージョン変更を伴うような仕様変更を含む形で)、やや煩わしく感じてきた。

どうしたものか。デバイスの抽象化など、発想はよいと思うのだけれど。

2011年8月28日日曜日

LionでR

(ふと、昭和軽薄体を思い出したのだが気にせず流す)

Rの現行安定バージョンは、2.13.1(2011年7月8日リリース)だ。ちょうどLionが出る少し前である。ソースからビルドしている人はどうなのかわからないが、Lionユーザは公式のpkgではなく、http://r.research.att.com/ からバイナリをダウンロードせよという指示があった。行ってみると「Patched」な2.13.1のuniversal binaryが置いてある。pkgでも、tar.gzでも結果は同じようだ。

さらに、同じページの下にある「Mac OS X GUI」の「R-GUI-5895-2.13-leopard-Leopard64.dmg」を落としてApplicationsに入れてやる。これでひとまずGUIでRが使えるようになる。

作業ディレクトリがホームなので、適当に文書の下にRなどというフォルダを作って、そこを作業ディレクトリに設定するなどお好みで。GUIメニューから設定できる。

利用目的がRMeCabなので、MeCabのインストールとRMeCabの組み込みを公式ページに従って行う。ただし、Lionは完全64bit化されているので、わざわざ32bit版バイナリを選択する必要はない。64bit版を選ぶこと。

あとはlibrary(RMeCab)すればいいわけだが、QuartzにせよX11にせよ、どうも日本語が文字化ける(白抜きの四角になる)ようだ。これは2008年から指摘されていることのようで、~/.Rprofileにフォントの設定をしてやることで解決するらしい。(設定方法が記述されたページ

2.14の公式版が出る頃にはこれらが統合されていることを期待するけれども、端境期で戸惑う人がいるかもしれないと思って、ここにメモしておく。

2011年8月25日木曜日

LionユーザはChrome Betaチャンネルへ移行すべき

現行の正式バージョンGoogle Chrome 13.0.782.215はLion上ではメモリ管理に問題が生じているように見える。

Late 2010のMacBook Airでは特に意識することはないが、Mid 2009のMac miniでは明確にロードアベレージの上昇、プロセス数の増加(タブを消しても減らない)、アプリケーション終了時のクラッシュなど、メモリまわりが疑われる不具合が見られる。

そこで、ベータチャンネル版(14.0.845.109)に切り替えたところ、すべての問題が解消した。また、Lionの全画面・リストアなどに対応しており、Safariと同等の使い勝手となる。

Chrome 14が正式版になれば、安定版に戻してもよいだろうが、いまLion上でChromeを使用している人は、いちどベータチャンネル版を試してみるとよいと思う。

なお、Google IMEもLion上で入力をしばらく受け付けなくなり意図しない文字があとからあとから入ることがある。また、フォーカスが外れ、インライン変換できなくなる問題もある。使用状況が常にGoogleに送信される点が気になるが、開発版に入れ替えると安定しているように見える。

2011年8月24日水曜日

Acrobat Xの日本語ClearScanの問題

自炊本の文字認識で、Acrobat 9から導入されたClearScanが面白いという話を読んだ。

そこで試してみたのだが、なかなかよい。文字認識と同時に、文字のアウトラインを拾って新たなフォントのようにスキャン画像を置き換えるのだ。確認はしていないが、同じ文字と認識されたものは同じアウトラインを使っているように見える。処理結果が、なんとなく揃った文字のように見えるのだ。

英文書籍で試したところ、たいへん素晴らしい結果を得た。もとからアウトラインフォントで文字組みをしたかのような結果になる。

一方、日本語の文書に関しては必ずしもうまくいかない。

なにより問題なのは、「Acrobatは縦書きを知らない」ということだ。富士通のScanSnapは縦書き文書も縦横混在もうまく分解してそれぞれ適切に処理してくれるし、大昔のスキャナ添付のOCRでも縦書き文書の読み取りは(領域を指定すれば)できていた経験がある。特許の問題があるのかもしれないが、MacのOCRが壊滅的であることもあり、Adobe頼みであるからがんばってほしい。

そして更に今日遭遇したのは、文字認識処理が中断されるページがある、ということだ。これは困る。

このとき、Acrobat Proはこのようなダイアログを出して、いままでの文字認識結果を捨ててしまう。


「Paper Capture認識サービスのエラー」ということだが、せっかく認識した結果まで捨てて欲しくない。

そして、「この文書に今後発生するエラーを無視する」のチェックを入れてもかまわず、何度でもこのダイアログを出して停止してしまうのだ。何のためのチェックボックスなのかわからない。

同じ本で何度も出るため、このエラーを発生させる疑わしい例がなんとなくわかってきたような気がする。いま想定しているのは、以下のような場合だ。


つまり、グレーの背景に白抜きの文字があったとき、アウトラインの生成に失敗するのではないかと疑っている。背景の濃さによって通る場合もあるので、特定の条件で生じるものと思われる。なかにはこうした部分全体を図として、文字認識の対象としない場合もあるので、実験により現象の再現も可能かもしれない。

念のため、以上、ここに記しておく。

なお、動作環境は、Mac OS 10.7.1 Lion上のAcrobat Xバージョン10.1.0。Paper Captureプラグインのバージョンも10.1.0(日付10/10/26 6:34:15)だ。

追記:
Adobeの不具合報告フォームで本ページを報告した。

また、うまくいったケース(文字認識を断念して画像とした場合)を示しておく。

周囲の文字はアウトライン化されているが、網掛け白抜きの部分はビットマップのまま処理されている。

追記2:
類似の例で、テキストとして認識されているものを示す。

これは、Previewで表示して文字選択した場合。画像ではなくテキストになっているので、部分的に選択できる。

2011年8月12日金曜日

LionでEmacs 23.3a

Lionのフルスクリーンモードに対応したパッチが出ているということで、Emacs.appの最新版を自前でビルドしてみることにした。

まずは普通にオリジナルEmacs (Cocoa Emacs)にインラインIMEパッチを入れて作成。
先達の教えに従って、homebrewのRubyスクリプトを参照しながらパッチを集めてうまくビルドできた。C-\でのMacのIMEの切り替えも良好。

しかし、一方で「Emacs Mac Port」という、Carbon Emacsに実装されていたけれどもCocoa版に入っていない機能を組み込む別のパッチもある。ところがこれにインラインIMEパッチをあてても機能しない。"MacOSX"というインプットメソッドがない、といわれるわけだ。

理由は簡単で、インラインIMEパッチはCocoa Emacsに相当する、nextstepを意味するns関係のファイルに手を加えているから。例えばnsterm.h, nsterm.m, nsfns.m, ns-win.elなどだ。一方、Emacs Mac Portは独自にmacというシステムを追加し、独自に表示部分を実装していて互換性がない。どうしてもやりたければ、macfns.m, macterm.h, macterm.m, mac-win.elなどを調べて、必要な変更を加えなければならない。

この違いを確認するのは簡単で、window-systemをevaってやれば、Cocoa版ならnsが返るしEmacs Mac Portならmacが返る。

使い比べてみると、Emacs Mac Portはかなりがんばっていて、好感度が高い。ただ残念なのはうっかりC-\を押すとquailの貧弱なIMが起動して悲しいことになる。

必要性のある人が根性を出すのが正しいのだろうが、いかんせん手がまわらない。当面は、Cocoa Emacsの環境整備でごまかしていくつもり。

2011年8月8日月曜日

Propeller久しぶりで苦闘

夏風邪で1週間身動きできなかった。

ようやくPropeller(Spin言語)の続き。といっても、OSもLionになったし、そもそも基板の使い方も忘れているような調子で、ほとんど、単に思い出すだけで終わってしまった。

とりあえず、bst(開発環境)はLionでも問題なし。5月ぐらいの最新版にしておいた。

だが、USB給電ではPropeller chipは動かないことに気づくまで30分以上苦闘して、やっとACアダプタが必要だったことを思い出した始末。

続いて、単なるLチカが動かず、ほんとにVDDが出てるのかどうか、テスタをあちこち当てながら調べる始末。情けない。

ひとつだけ、Gadget Gangsterのテキストで、入力ピン番号を物理的ピン番号で指定しているが、論理ピン番号が正しいようだ。彼らの開発基板特有のことなのかどうなのか、わからない。少なくともParallaxの開発ボード(やPE Kitなど)では論理番号が正解のようだ。

2011年7月7日木曜日

ドリトルの壁反射をカスタマイズする方法

ドリトルの「ピンポンゲーム」は定番のネタ。教科書の「Activity 6」(34〜38ページ)にも載っている。

移動するタートルや図形の衝突したときに、入射角と反射角が等しいように反射させることで、この手のゲームは成立する。

教科書では、V2.2に対応して、例えばカメ太がタイマーで移動する場合、

カメ太:衝突=タートル:跳ね返る。

と定義する、と書いてある(36ページ)。カメ太の衝突のはずなのに、わざわざその親(プロトタイプ)を指定してメソッド定義する理由はなぜか、気になりませんか。

というわけで、「タートル:」を外して、継承されているはずの「跳ね返る」メソッドを直接実行するようにしてみる。ひとまず、カメ太と壁を描いて、カメ太を直進させてみる。まだ衝突は定義しない。
カメ太=タートル!作る ペンなし。
大工さん=タートル!作る 30 線の太さ (青)線の色。
大工さん!ペンなし 350 300 位置 ペンあり -90 向き 600 歩く 図形を作る。
大工さん!消える。
タイマー!作る 0.01 間隔 5 時間「カメ太!5 歩く」実行。

当然ながら、なにごともなかったかのようにすり抜けていく。

で、衝突の定義を追加。
カメ太=タートル!作る ペンなし。
大工さん=タートル!作る 30 線の太さ (青)線の色。
大工さん!ペンなし 350 300 位置 ペンあり -90 向き 600 歩く 図形を作る。
大工さん!消える。
カメ太:衝突=跳ね返る。
タイマー!作る 0.01 間隔 2 時間「カメ太!5 歩く」実行。
なんと、衝突が発生しない!そこで、メソッド定義に変えてみる。
カメ太=タートル!作る ペンなし。
大工さん=タートル!作る 30 線の太さ (青)線の色。
大工さん!ペンなし 350 300 位置 ペンあり -90 向き 600 歩く 図形を作る。
大工さん!消える。
カメ太:衝突=「!跳ね返る」。
タイマー!作る 0.01 間隔 2 時間「カメ太!5 歩く」実行。 

するとなんと素敵なことに、衝突した瞬間、「"_active"オブジェクトが作られていません("なら")」というエラーが発生する!

普通の人はここで戸惑って「ごめんなさい」と謝るところだけれど、こちらは「なぜタートルのメソッドでなければならないのか」を疑っているので、「これはしめた!」と思うところ。

「なら」というわけで、条件文に使われている変数名だろうとあたりをつけて、ローカル変数(というか引数)を指定してやる。ただし、衝突の引数は、衝突相手のオブジェクトなので、_activeは第二引数にして、以下のように書いてみる。
カメ太=タートル!作る ペンなし。
大工さん=タートル!作る 30 線の太さ (青)線の色。
大工さん!ペンなし 350 300 位置 ペンあり -90 向き 600 歩く 図形を作る。
大工さん!消える。
カメ太:衝突=「|相手 _active|!跳ね返る」。
タイマー!作る 0.01 間隔 2 時間「カメ太!5 歩く」実行。

ナイス!「"_hittarget"オブジェクトが作られていません("向き?")」というエラーメッセージ。名前からしてこれは衝突相手を意図したものということで、第一引数名をこれに変更。

見事に反射する。というわけで、この「_hittarget」と「_active」という、いかにも内部変数な名前が、「跳ね返る」メソッドの引数として使われていて、子ども側でそれに合わせてやらないと、未定義オブジェクトに対するメッセージ送信となってエラーが発生するということがわかる。

ちなみにdolittle.jarをunzipで展開してdolittle.iniファイルを眺めると、高麗大の青木さんががんばって改良した「タートル:跳ね返る」メソッド定義が、まさにこの2つの引数をとるように書かれているのがわかる。青木さんありがとう。

これで、ドリトルの「跳ね返る」メソッドを使いながらオリジナルの衝突メソッドを定義することができるようになった。

例えば壁に反射するときには、「カキン!」という効果音を入れたくなるもの。というか、動きを見ていれば、音が脳内で鳴り響く。そこで、効果音を追加してみる。
カメ太=タートル!作る ペンなし。
大工さん=タートル!作る 30 線の太さ (青)線の色。
大工さん!ペンなし 350 300 位置 ペンあり -90 向き 600 歩く 図形を作る。
大工さん!消える。
壁反射音=メロディ!作る『↑ど16↑ど16』追加
             (楽器!『ウッドブロック』作る)設定。
カメ太:衝突=「|_hittarget _active|!跳ね返る。壁反射音!演奏」。
タイマー!作る 0.01 間隔 2 時間「カメ太!5 歩く」実行。
成功するはず。お試しあれ。

で、効果音つきのスカッシュゲーム風に仕上げてみた。パドルの移動は、マウスカーソルの位置に合わせるようにしている。ご参考まで。

カメ太=タートル!作る ペンなし。

大工さん=タートル!作る ペンなし。
大工さん!30 線の太さ(青)線の色。
大工さん!-300 300 位置 0 向き ペンあり。

壁=大工さん!650 歩く 90 右回り 600 歩く 90 右回り 650 歩く 図形を作る。

パドル=大工さん!ペンなし -350 75 位置 ペンあり -90 向き
    25 線の太さ(ピンク)線の色 150 歩く 図形を作る。

大工さん!消える。

パドル:上下=「パドル!-350 ((マウス!縦の位置?) + 75) 位置」。

壁衝突音=メロディ!作る『↑ど16↑ど〜』追加(楽器!『ウッドブロック』作る)設定。
パドル音=メロディ!作る『↓ど16』追加(楽器!『ミュートギター』作る)設定。

カメ太:衝突=「|_hittarget _active|!跳ね返る。
       「(_hittarget == 壁)」!なら「壁衝突音!演奏」そうでなければ「パドル音!演奏」実行」。

速さ=5。

カメ太!((90!乱数) - 45)向き。

アウト音=メロディ!作る『↓↓↓み8み8』追加(楽器!『シンセベース1』作る)設定。

アウト=「アウト音!演奏。タイマー!作る 3 時間「」実行 待つ。
               カメ太!中心に戻る ((90!乱数) - 45) 向き」。

タイマー!作る 3 間隔 30 時間「速さ=(速さ)+ 1」実行。

タイマー!作る 0.01 間隔 30 時間
       「カメ太!(速さ) 歩く。パドル!上下。
       「(カメ太!横の位置?) < -400」!なら「ルート!アウト」実行。
       」実行。

なお、3秒ごとにカメ太の動きが速くなるようにしてみた。ゲーム時間は30秒で、そのまま終了するので、メッセージを出すなど改良していただけるとありがたい。

Scratchに距離センサをつないでみる

Scratch+Arduinoで次はなにをしようかと考えて、遠隔操縦のロボットカーでもやってみようかと考えてみた。通信はXBeeを使う予定。

ひとまず、ロボットカーの仕様を検討。定番で、障害物回避ロボットを考えて、障害物検知のために距離センサをサーボモータに載せ、首振りさせてやることにしてみた。

きょうはまず、距離センサの実験。

前回試した、port 42001の通信をProcessingあたりでXBeeに流しこむのがいいのだろうけれど、動作確認が主目的なので、きょうはScratchセンサーボードのArduinoコードを改造することにした。

横川さんと阿部さんのコードでは、168のArduinoに合わせて、足りないアナログ入力端子で余った「抵抗D」を、抵抗Cと同じにすることでScratchに合わせている。その余った端子をいただく魂胆。

距離センサは、赤外線を使うPSD測距センサが無難だしそのままArduinoのアナログ入力端子に接続できるので簡単ではあるのだけれど、ちょうど手元に使っていないParallax社の超音波距離センサモジュール「PING)))」があったので、試してみることにした。

PING)))をArduinoで使うコードは、本家のチュートリアルにあるので、そのままいただいた。

PING)))の仕様では、ソナーの発信を2μ秒以上行ってから、反射音が受信されるまでの時間をマイクロ秒単位で計測する。上のコードでは、5μ秒の発信をしてから、ArduinoのpulseIn()関数で受信までの時間を計測している。その結果を29で割ってさらに2で割ると、cm単位のリニアな距離になるそうだ。PING)))の仕様書を見ると、3mまで測定できるらしい。

というわけで、借りたコードをそのままチャンネルDに突っ込んだコードが以下のもの。

SensorBoardWithMotorAndPing.pde

まったくもって何の工夫もない。 PING)))は、D5に接続することにしてある。

Scratch側でセンサーボードを表示すると、Dの値がcm単位で出る。しかし、センサーボードは0〜100までの整数値しか扱えないので、最大1mまでの計測ということになる。

きょうはとりあえずここまで。

続く首振りのためのサーボモータはServo関数があるので、例えばモータ用のPWM端子であるD11をanalogWrite()からServo.write()に置き換えればそれで済んでしまうけれど、そこまでやると、もとのセンサーボードとの互換性の問題があるので、やっぱり外部通信でやるべきかなと思う。

2011年6月30日木曜日

ScratchとProcessingの通信に成功

以前書いた、Scratchの「遠隔センサー接続」で、Processingのプログラムとの間で相互通信できることを確認しました。

まず、Scratchのスクリプトはこんな感じ。わりと適当。


Processing側から"mew"というメッセージが届いたら、「ニャー」と鳴きます。
また、ステージ上ではスクリプト1が回転していて、上を向いたらProcessing側へ"Turned!"というメッセージを送ります。

Processingのプログラムは以下の通り。

import processing.net.*;
Client ScratchClient;
PFont f;
int cnt = 0;
void sendtoscratch(String dataOut) {
byte [] sizeBytes = { 0, 0, 0, 0 };
  sizeBytes[3] = byte(dataOut.length());
  for (int i=0; i<4; i++) {
    ScratchClient.write(sizeBytes[i]);
  }
  ScratchClient.write(dataOut);
}
String recieveFromScratch() {
  String inString = ScratchClient.readString();
  return inString;
}
void setup() {
  ScratchClient = new Client (this, "127.0.0.1", 42001);
  f = loadFont("HiraKakuProN-W3-16.vlw");
  textFont(f);
  size(640, 480);
  background(255);
  fill(0);
}
void draw() {
  sendtoscratch("sensor-update " + "\"mouseX\"" + str(mouseX));
  sendtoscratch("sensor-update " + "\"mouseY\"" + str(mouseY));
  delay(50);
  if (ScratchClient.available() > 0) {
    text(recieveFromScratch(), 10, (cnt++)*20);
  }
}
void mouseClicked() {
  sendtoscratch("broadcast " + "\"mew\"");
}
やってることは、127.0.0.1(local loopbackですな)の42001ポートに接続して、Scratch側に送信するフォーマット(32bit長の、メッセージのバイト数+実際の文字列)を作ってやる「sendtoscratch()」という関数と、Scratch側からは単純に文字列が送られてくるのでそれを受け取る「recieveFromScratch()」という関数を用意しただけ。

で、センサ名「mouseX」と「mouseY」を用意して、Processingのウインドウ上のマウスの座標をScratch側に送りつつ、また、ウインドウ上でマウスクリックすると「mew」というメッセージを送るというお仕事。また、もしScratch側からデータがきていたら、それをウインドウ上に描くというお仕事。

動かす手順は先にScratchで「遠隔センサー接続を許可する」してポートを開いてから、Processingのほうを起動します。でないと、クライアント接続のエラーチェックしていないので、接続できないままdraw()のループに入り、Javaのexceptionが出まくってしまいます。

Scratch側でも一応センサ値も表示しておきました。これは「センサーボード」ではなくて、「[スライダー▼]の値」ブロックのセンサー名をmouseXにして、右のチェックボックスをチェックするとステージ上に現れます。mouseYも同様にすると、以下のような画面になります。

でもって、猫が回転して上向きになると、Processingのウインドウに届いたメッセージが出ます。
よくわからないけれど、日本語のメッセージはScratch側からは出せない仕様なのか、受け取ると文字化けします。ProcessingはJavaベースなのでUTF-8ならいいのかと思いましたし、Scratchの国際化もUTF-8ベースらしいので大丈夫なはずなんですが、なにかが間違っているみたい。.readString()をいろいろ変えてみたりしたけどうまくない。ヒラギノを指定したけどそれでもだめ。わからん。

2011年6月29日水曜日

ドリトルのArduino対応のバグとったつもり

先日報告した、「アナログ入力」で読んだ値が128以上で65535以下になる件、とりあえずのquick hack。

問題は、intの値をSerial.write()する際にUTF-8でどうやらドリトル側が受け取っているらしいということ。そこでいくつか試したけれど、数値を文字列化して送ってやればいいということになった。

まず、arduino_dolittle.pde側(Arduinoのスケッチ)。


34c34
<       Serial.write(analogRead(port)/4);
---
>       Serial.print(analogRead(port)/4,DEC);

というわけで、Serial.print()命令で、10進の文字列出力することにした。

続いてarduino.ini(ドリトルのオブジェクト定義)側。

26c26
<     「c>0」!なら「(_arduino!(c)値?)!文字コード」そうでなければ「0」実行。
---
>     「c>0」!なら「(0!(_arduino!(c)値?)add)」そうでなければ「0」実行。

変数「c」の値は到着したバイト数を表しているので、「(c)値」でその文字数分だけ読み込んでくれるから、そのままでもよさそうだけれど、念のため数値に変換するつもりで、整数0を足してみた。

一応、以下のような適当なプログラム

システム! "arduino"使う。
a=arduino! 作る "/dev/tty.usbmodem26221"ひらけごま。
アナログ値=フィールド!作る。
pot = a!0 アナログ入力。
タイマー!作る  「アナログ値!(pot!読む)書く」実行。

でなんとかなっている感じ。

2011年6月23日木曜日

Wiimote手ごわい

自宅からWiimoteとNunchakを持参してMacとペアリングしようとしたのだが、できない。

名前は出るのだが、Webでは機器の種類として「ジョイスティック」と出るとあるが、「不明なデバイス」と出てしまい、その先に進めない。passcodeについて、4択あるのだがどれも不可。

とりあえずきょうは諦めた。

ちなみに、Mac上でWiimoteと通信するJavaのライブラリは動いているみたい(後日ちゃんと書きます)。

それではとArduinoのUSB Host Shieldにたまたま持っていた非常に古い(Vista以後のドライバが存在しない)BTドングルを接続して、シリアルコンソールにパラメータの表示ができたところで今日は時間切れ。USB深い。

ドリトルのArduino対応のバグ?

ドリトルV2.2のArduinoからのアナログ入力で、127を超えると65535になるのを確認。

byteで送られたデータを符号付きで解釈して16bitのintにしているのかな、と想像。

ちょっときょうはバグ取りの時間がなかった。

2011年6月20日月曜日

ゲームコントローラ関係のブックマーク

PS2コントローラとWiimote/ヌンチャク等のArduinoライブラリへのリンクを記録。

PS2コントローラ

もはやなんでもありですな。

Kinectまでくると、ちょっとした実験というレベルじゃなくなりそう。 

Scratchの外部通信機能を参考にする

Wiimore(Wiiリモコン)関係を調べていて、ScratchではTCP 42001 portで双方向通信する機能が1.3版から含まれていることを知った。

参考:「Scratchに外から値を送ってみた」by いー ドット ぷりんとすったくとれーす さん

これを有効にするには、例によって「[スライダー▼]センサーの値」ブロックを長押しして現れる以下のメニュー


で「遠隔センサー接続を有効にする」を選択する。と、画面中央にこんなダイアログ


が出て、Scratchが42001番ポートをlistenするようになる。

フォーマットは単純な文字列(UTF-8エンコード)なのだが、その前に32bit幅のデータ長をペイロードとしてつけてやる必要がある。

通信は、以下のコマンドが定義されているので、それを文字列の最初に置く(大文字小文字区別なし、コマンドと引数の間は空白文字0x20)。

  • broadcast
  • update-sensor
「broadcast」コマンドは、Scratchにおけるメッセージ送信になる。外部からScratchのスクリプトを起動するのに使う。一方、「update-sensor」コマンドは、引数にとった文字列名の変数に、続く引数の値を代入する指令を送信する。例えばこんな感じ。Wiimoteの3軸加速度センサーの値を送るコマンドの例。

update-sensor "X軸傾き" 20 "Y軸傾き" -120 "Z軸傾き" 45

すると、これを受け取ったScratchは3つのセンサーに対応する変数「X軸傾き」「Y軸傾き」「Z軸傾き」を内部に作成し、値をそれぞれ20, -120, 45にする。値が数値の場合は10進数、文字列の場合はダブルクォート(")で囲む、真偽値の場合は直接trueまたはfalseと書く。また、上の例のように複数の変数の値をいちどに変更することができる。

使い方としては、まず「update-sensor」で値を送っておいて、「broadcast」で指示を送る。Scratchのブロックで、「[ ▼]を受け取ったとき」というもの


があるが、この下に、受け取った値を使って処理すべきことを書くことになる。例えば、
broadcast "移動"
というメッセージが外から送られてきたら、対応するスプライトをさきほどのX, Y, Zの傾きにしたがってすべるような移動をさせる、という感じ。

Scratchは、メッセージを使うことでイベント駆動のようなプログラムを作ることができる。だから、Wiimoteのボタンを押したら何かが起きる、といったスクリプトを作成するのは簡単だ。

一方ドリトルは、メッセージを監視するような機能を持たないので、例えばタイマーなどを使ってポーリングすることになる。それでもよければ、サーバ機能をオンにしたドリトルを立てておけば、そこが共有黒板になるので、Scratchと同じような形で値の受け渡しやコマンド送信ができるだろう。ScratchはP2Pで直接通信できるのに対して、ドリトルはサーバを介する必要がある点が異なる。

2011年6月14日火曜日

ArduinoとGPS

先日のエントリで広げた風呂敷を徐々に実現していく段階。

ひとまず、NewSoftSerialから。GPSを接続して、NEMA形式のデータが取得できることを確認。これでシリアル接続のデバイスが試せることと、GPSをどう扱うかの検討課題が見えてきた。

まず、ドリトルのいまの実装に対する課題が、引数がひとつしかとれないこと。現在は1バイトのコマンドに1バイトの返答をする実装のため、新しいシリアルポートを作成するために必要な、RX, TXの2つの引数を渡すことができない。

もうひとつ重要なのは、返答も1バイトなので、GPSのデータのような不定長の文字列をドリトル側に渡すことができない。

また、例えばシリアルLCDなどに文字列を出力することを考えれば、ドリトルから送信するデータも不定長を許すことにしなければならない。

というわけで、まずコマンド(というよりもバイトコード)の再設計と、ハンドシェイクを行い確実に通信できる実装が課題ということがわかった。ドリトル側の送信タイミングは環境によっていろいろあることが予想されるので、あまりナイーブな実装はするべきではなさそうに思う。

次にGPSなのだが、生のNEMAフォーマットの文字列をドリトル側で処理するのはコストが見合うのかどうか考えたほうがよいと思った。なぜなら、GPSが1度に送信するデータの行数は様々で、補足できる衛星の数も機種によって様々、ロックできる衛星の数は場所による、データ送信間隔も毎秒1セットから5セット(1/5秒ごとに送信)までいろいろあるから。

率直なところ、屋内で衛星が見えない状態では意味のある情報は得られない。だから、衛星をロックしたかどうかを確認してから値を取得する必要がある。ドリトル側にそれを調べる命令を用意すべきか、Arduino側がお世話を焼くかも検討課題。

また、コンマ区切りの長い文字列をドリトルが受け取っても、いくらV2.2で文字列処理命令が充実したといっても効率的にどうか、ということもある。実用を考えればすべての情報はドリトル側には不要なのではないか、というのが現在の予想。日付、時刻、緯度、経度、高度、方角ぐらいあれば十分ではないだろうか。速度などは車載でもしなければ不要ではないか、など。そうなると、Arduino側で実用的なデータに整理してから単純なフォーマットで送るべきではないか、ということになる。幸いNewSoftSerialの作者がTinyGPSというライブラリを作成していて、これを追加したペナルティは100バイト程度とのことだから、これを使ってみたいと思っている。

とりあえずいまの段階はそこまで。あとはあした考えるつもり。

2011年6月3日金曜日

ドリトルのArduino対応を改善するたくらみ(まだ構想段階)

たまには自作の話も書かねばと。

以前のエントリでも書いたけれど、ドリトルのArduino対応の改善について。

1. シリアルデバイスの接続

GPSを想定しているけれど、シリアルLCDとかも入るかもしれない。

AVRのサポートする端子以外でのシリアル接続は、NewSoftwareSerialを使うのが定番みたい。関数は標準のSerial互換にしてあるようなので、
  1. シリアルポート作成(ついでにbegin()してしまおうか)
  2. available()
  3. read()
  4. write()
に対応する4つのコマンドを作ればいいような気がする。デジタル/アナログ入出力の設定コマンドで上書きしても壊れないように、ポート番号の管理と、上書きするときには作ったシリアルポートオブジェクトをdealloc()しないといけないかもしれない。

2. I2C, SPI対応

悩ましいのだが、そういうデバイスをたくさん持っているので使えるようにしなければならない。SPIは設定と転送の2つのコマンドだけでよさそう。I2CはWireライブラリを使うようだがちょっと面倒そうだ。今後検討。

3. 音命令

スピーカーから音が出ないと子どもが楽しくないだろうから、Toneライブラリを入れてみるつもり。所詮Arduinoなので、これ以上の機能は入れられないだろう。

5. SDカード

GPS使う場合、結構なデータ量になるのでSDカードは必要かなと。データロガーに徹するなら命令数は減らせそう。汎用にすると面倒そうだ。

6. EEPROM

AVR上の未使用のEEPROM領域にアクセスするライブラリが標準であるので、命令列をここに書きこんで、リセット時に何らかの操作で再生するようにすれば自律モードのできあがり。これでPCから切り離しができる。あるいは、簡易データロガーの領域にする手もあるかも。

ただ問題は、上記のライブラリを全部入れても168のArduino(Unoとか)に入るのかどうか。やってみないとわからない。

2011年6月2日木曜日

Scratch+Arduinoを試してみた(追記あり2015年2月17日)

(2015年2月17日追記:たいへん古いエントリですが検索上位に上がるため、いまでもよく読まれているようです。現在ではいろいろと相違がありますので、阿部先生が配布されているScratchへのチェンジファイルとArduinoに書き込むスケッチがセットになった「SensorBoardWirhMotor」(ページの上から6番目の項目です)をご利用ください。下記の問題も解決しているとのことです。阿部先生の所属もかわっており、現在津田塾大学のほか多くの活動をされています。詳しくは最近の各著書「わくプロ」「どきプロ」「すくプロ」などを参照してください。)


ArduinoをPicoBoard互換にしてさらにWeDo的使い方もできる、というScratchの拡張(サイバー大の阿部和広先生作)を試してみました。

使い方は、ヱンガワシステムズさんのエントリにある通りなのですが、このページに置かれている「全部入り」をダウンロードして、それに含まれているArduinoのスケッチをArduino IDEで書きこんで、いっしょに入っているScratch 1.4 modを起動するという手順です。

標準のScratchでも、PicoBoard用の

  • スライダー
  • ボタン
  • 光センサ
  • マイク

入力に対応しているので、入力装置にするだけなら同ページにあるスケッチ(SensorBoardWithMotor.pde)の書き込みだけでよいのですが、「Lチカ」をやりたかったので、WeDo拡張を含むこのパッケージにしました。

Arduinoを接続して、手順通りに「調べる」タブの「センサーの値」ブロックを長押しするとメニューが出て、たしかにステージに、センサの値をリアルタイム表示する「ScratchBoard監視盤」が現れました。なかなか感激です。

Arduinoの端子との対応は、

  • スライダー - A0
  • 明るさ - A1
  • 音 - A2
  • 抵抗A - A3
  • 抵抗B - A4
  • 抵抗C - A5
  • 抵抗D - A5 (抵抗Cと同じ)
  • ボタン - D2


なので、それにしたがってボタンの回路やPOD(半固定抵抗)などをブレッドボードで組んでやると、ちゃんと値が出ます。

ちなみに、ボタンは押すとGNDに落ちる回路。つまり、LOWのときにScratchはtrueを返します(HIGHがfalse)。PODの値は適当なのを適当につないでも0〜100になるようになっていて、よくできてるなーと思いました。

で、Lチカさせるために、
  • モーター - D11-(PWM)

に接続して、こんなスケッチ

を書いてみたんですが、LEDは点きっぱなしで、チカチカしてくれません。

おかしいなーと思って他のモーター関係の命令を試していて気づきました。例えばこんなのだったらうまく動きます。

PODを回すと、LEDの明るさがそれに応じてかわります。

それでようやく気づいたのですが、ミソは「PWM」ということなんですね。つまり、こんなスクリプトならLチカします。

Arduinoのプログラミングをある程度やった人ならわかると思いますが、この「モーターのパワーを( )にする」というブロックは、analogWrite()に相当するわけです。つまり、Lチカの例題
#define LED 11
void setup() {
   pinMode(LED, OUTPUT);
}
void loop() {
  digitalWrite(LED, HIGH);
  wait(1000);
  digitalWrite(LED, LOW);
  wait(1000);
}
これとは違うわけです。

念のために、スケッチを確認したところ、setup()のなかではpinMode(PWM_PIN, OUTPUT);しているのですが、loop()のなかはanalogWrite(PWM_PIN, motorPower);としか書いていないので、「D11-」ではないのですね。でもその直後に、

      digitalWrite(THISWAY_PIN, motorDirection & isMotorOn);
      digitalWrite(THATWAY_PIN, ~motorDirection & isMotorOn);
と書いてあります。つまり、「モーターの回転を[ こちら向き ▼]にする」ブロックに対応する、この記述が「モーターをオンにする」「モーターをオフにする」ブロックに効いてくるわけです。

ちなみに、

  • THISWAY_PIN - D4
  • THATWAY_PIN - D7

なので、D4にLEDをつなぎなおして確かめてみると、
うまいぐあいにLチカしてくれました。

このあたり、PWM端子でもdigitalWrite()するように書くことができるドリトルのほうがわかりやすいのかな、と思いました。(前回のエントリ参照)

2011年5月22日日曜日

ドリトルV2.2のArduino対応がニクイ

もはや旧聞に属する話題ではありますが、去る4月11日、ドリトルの久々のバージョンアップ、2.2版が出ました。

あわせて第2版のテキストも出版されていますので、ぜひお求めになるとよいと思います。初版よりも、断然実用的な教科書になっていますし、自習書としての使いやすさも格段によくなっています。なお、お金のない学生さん、立ち読みしてみたい先生方は、V2.2の配布パッケージに本文まるごと入ったPDF(表紙を除く全て)が含まれていますので、そちらを見ていただくとよいのではないかと思います。ただし、B5版の書籍に合わせて作られていますので、そのままA4の用紙に印刷するととても大きな文字になってしまいますので、印刷するときにはご注意を。

ところで、V2.2では、外部接続できる機器として、従来のMYUロボ基板に加えて、Arduinoが扱えるようになりました。今回は、このArduino対応のしくみを覗いて、ドリトルの奥深さに触れてみようという趣旨です。

MYUロボ基板では、基板上のPICに書きこまれたファームウェアが実装した命令を、シリアルポート経由で送信したり、結果を受け取ったり、また自律動作させられるプログラムを書き込むことができました。

V2.2のArduino対応では、この、最後の「Arduinoへのプログラムの書き込み」は実現されていません。したがって、Arduinoとドリトルを動かすコンピュータとの間は、つねにUSBケーブルで接続されている必要があります。形態としては、ドリトルから、Arduinoに接続されたデバイスから値を読んだり、デバイスを制御したりするというものです。ScratchにおけるPicoBoard(他に、Sparkfun製互換品, 韓国のPinyチームが作った互換品Helloboard)のような位置づけです。

したがって、「Arduinoにつながる膨大に存在するデバイスを、Arduino IDEの言語を使わずに簡単に書きたい!」という期待には、いまのところModKitしかない(しかもまだ開発中)というところです。

それはともかく、ドリトルとArduinoをつなぐ、「ニクイ」しくみについてみていくことにしましょう。

Arduinoのスケッチ


ドリトルとArduinoがお話できるようにするために、Arduinoに専用のスケッチを書きこむようになっています。このスケッチを書き込むことで、ドリトルV2.2用Arduinoができあがるというわけです。もちろん別のスケッチを書き込んで、いつでも本来のArduinoに戻すこともできます。詳しくは、第2版テキストの105ページを参照してください。

スケッチは、ドリトルのフォルダ(Windowsの場合、dolittle.jarがあるフォルダ。Macの場合、~/Library/Dolittleの下)にある、arduino_dolittleというフォルダの下にある、"arduino_dolittle.pde"が本体です。なんと、たった41行しかありません。

Arduinoのスケッチは、2つのvoid型の関数からなります。ひとつは、リセット時に一度だけ実行されるsetup()関数、もうひとつは無限ループするloop()関数です。他に下請けとなる関数を自由に定義することもできますが、ドリトルV2.2では、この2つだけを使っています。

ではまず、setup()関数からみていきましょう。
void setup(){
  Serial.begin(9600);
  Serial.write(' ');
}
たった2行です。1行目は、標準のシリアルオブジェクトの初期設定をしています。このオブジェクトは、USBで接続されているPCと通信するほか、Arduino基板のデジタルポートD0, D1のRX, TXにも対応しています(並列接続です)。これを標準的な9600bpsの速度で設定しているというわけです。2行目では、このシリアルオブジェクトに半角空白(文字コード0x20)をひとつ送信しています。これは、ドリトル側に、「初期設定が終わったよ」ということを知らせていると考えられます(あとで確かめましょう)。

次に、loop()関数です。少々長いので、少しずつみていきます。まず最初の部分。

void loop(){
  int wait=5;
  if (Serial.available() > 0) {
    int in = Serial.read();
    int cmd = in & 0xf0;
    int port = in & 0xf;
整数型変数waitの値を5に設定しています。そのあと、シリアルオブジェクトが何か受信しているかどうかをif文で確かめています。このif文は、loop()関数の最後で閉じられているので、シリアルオブジェクトが何も受信していなければ、以下なにもせずにloopを繰り返します。

受信した場合、先頭の1文字(1バイト)を整数型の変数inに読み込みます(read())。そして、その結果を、1バイト(8bit)の上半分と下半分に分割しています。

「in & 0xf0」というのは、0xf0が二進数で0b11110000ですから、それと論理積をとることによって、上4bitだけをそのままに、下4bitは0b0000に置き換えて、変数cmdに記憶することになります。そして、「in & 0xf」で、つまり0b00001111ですから、下4bitだけをそのままに、上4bitを0b0000に置き換えて変数portに記憶しています。

これで、ドリトル側から送られてきた1バイトのデータを、cmdとportの2つに分割して得たことになります。では残り。
    switch (cmd) {
    case 0x20: // pinMode(Dout)
      pinMode(port ,OUTPUT);
      delay(wait);
      break;
    case 0x30: // pinMode(Din)
      pinMode(port ,INPUT);
      delay(wait);
      break;
    case 0x40: // Dout
      delay(wait);
      if (Serial.read() == 1) { digitalWrite(port, HIGH); } else { digitalWrite(port, LOW); }
      break;
    case 0x50: // Din
      Serial.write(digitalRead(port));
      break;
    case 0x60: // Aout
      delay(wait);
      analogWrite(port, Serial.read());
      break;
    case 0x70: // Ain
      Serial.write(analogRead(port)/4);
      break;
    default :
      break;
    }
  }
}
長くなりましたが、1行目のswitch文がこの部分のすべてです。

つまり、cmdに記憶された値によって、どんな動作をするかを分岐しているというわけです。cmdは「コマンド」の意味だと思われます。

そして、対応するcase文が6つありますから、6種類のコマンドが定義されている、ということがわかります。では、順にみていきましょう。

case 0x20ということですが、以下、下半分の4bitは省略して、「2番コマンド」などと書くことにします。

2番は、コメント(//記号以後、行末まで)にあるように、Arduinoの入出力ピンの方向(入力か、出力か)を決めているようです。実際に実行されているのは
pinMode(port, OUTPUT);
delay(wait);
 だけですから、さきほど記憶した、下4bitがポート番号(port)として使われ、対応する番号のピンを「出力」に設定していることがわかります。Arduinoのデジタル出力は13番までしかありませんから、4bitあれば足りるという設計だったわけですね。そして、設定したあと、変数waitに記憶した分だけちょっと待ちます。Arduino搭載のAVR CPUがきちんとポート設定をする時間をみているわけですね。waitの値は5だったので、5マイクロ秒待つことになります。

次に、3番コマンドを見てみましょう。
      pinMode(port ,INPUT);
      delay(wait);
今度は「入力」に設定していますね。

4番コマンドはどうでしょう。
      delay(wait);
      if (Serial.read() == 1) { digitalWrite(port, HIGH); } else { digitalWrite(port, LOW); }
ちょっと長くなっています。

先に5マイクロ秒待ってから、シリアルオブジェクトから1バイト値を取り出し、その値が1であれば、指定されたポートをHIGHに設定し、そうでなければLOWに設定する動作をしています。つまり、出力に設定したデジタルポートの状態を変更しているというわけです。1ならHIGHですから、普通なら0が指定されたときLOWにする、ということが予想されます(これは、ドリトル側がどうなっているかをみて、確かめましょう)。

5番コマンドは、
      Serial.write(digitalRead(port));
入力に設定されたデジタルポートの状態を読み取って、シリアルオブジェクトに送信しています。これは、HIGHなら1、LOWなら0がドリトル側に送信されるということになるでしょう。

6番コマンドは、
      delay(wait);
      analogWrite(port, Serial.read());
5マイクロ秒待ってから、ドリトルから送られてきた値をアナログ出力ポートに送信しています。Arduinoでは、アナログ値をポートに書きこむ命令は、PWM(パルス幅変調)を実行します。値が小さければ、1周期の間でHIGHになっている時間が少なく、大きければHIGHの時間が多くなります。これを使って、モータの速度調整をしたり、LEDの明るさをかえたりすることができるのです。先に待ち時間を入れているのは、ドリトルが値を送信する時間を待つためと考えていいでしょう。

最後の7番コマンドは、
      Serial.write(analogRead(port)/4);
こうなっています。アナログポートが入力した値を4で割って、それをシリアルオブジェクトに送信しています。これは、アナログポートに接続されたセンサーなどの値を読み取って、ドリトルに送信する役割を果たしていると考えられます。ちなみに、4で割っている理由ですが、ArduinoのA/Dコンバータ(電圧の高さをデジタル値の大きさに変換する回路)は、10bitの分解能をもっています。しかし、ドリトルとの通信は1バイト(8bit)でやりたい。そのために、10bitの分解能を8bitに減らす必要があります。そのために、10bitの数値を2bit分右シフトして8bitにするわけです。4で割るのは、2の2乗で割るということなので、要するに2bit右シフトすることと同じです。個人的には、「>>」という右シフト演算子を使って、「analogRead(port) >> 2」と書きたいところです。いずれにせよ、同じ意味です。

残るdefaultは、上記にあてはまらない場合、ということですから、0番、1番のコマンドということになります。なにもせずにbreak;していますから、未定義というわけです。

ドリトルのプログラム


ドリトルV2.1以後、外部機器に関する定義は、.iniの拡張子をもつファイルに記述するようになりました。いままではmyu.iniだけがあり、ミュウロボ基板に関する定義が書かれていました。V2.2では、arduino.iniというファイルがドリトルのフォルダにあります。

また、今後iniファイルの数が増えていく可能性がありますので、すべてを読み込むとドリトルが不必要にメモリを消費してしまうため、どのiniファイルを読み込むか、ということを最初に指定することになりました。これは、「システム」オブジェクトに「使う」という命令が定義されています。したがって、arduino.iniを読み込むためには、みなさんが作成するプログラムの最初に、
システム!"arduino" 使う。
 と書かなければなりません(テキスト106ページ参照)。

というわけで、arduino.iniファイルはドリトルの命令が書かれていて、それを読めば、上で説明した、Arduinoのスケッチに対応したどんな命令が使えるようになるのかがわかる、ということになります。

arduino.iniは、59行あります。以下、先頭から少しずつ読んでみましょう。

まず1行目です。
「シリアルポート == 未定義」!なら「システム!"エラー: Arduinoオブジェクトを作れません。" messagedialog」そうでなければ「Arduino=シリアルポート!作る。
 一般のドリトルのプログラムでは見慣れない記述で少々戸惑うかもしれません。しかし、テキストの付録をよく調べていただければ、意味はわかっていただけると思います。ここでは、「だいたいなにが書かれているか」の説明にとどめます。原理は、テキストの付録で勉強してください。

この条件文ですが、“「シリアルポート == 未定義」!なら”という条件になっています。ドリトルは、起動時にOSにシリアルポートがあるかどうかを問い合せて、あれば「シリアルポートオブジェクト」が作られます。なかった場合、つまり、Arduinoに対応したUSB-シリアル変換のデバイスドライバが正しくインストールされていないとか、そもそもUSBにArduinoが接続されていない場合には、シリアルポートオブジェクトが作られません。これを確かめている、というわけです。もし存在しなければ以後のプログラムは動かすだけ無駄なので、ユーザに警告を出します。“システム!... messagedialog.”という命令で、ダイアログに警告メッセージを出しています。そうでなければ、“Arduino=シリアルポート!作る。”命令で、Arduinoという名前で以後通信するシリアルポートにアクセスできるようにします。


空白行をひとつおいて、3行目以後は、このArduinoオブジェクトに追加するメソッド定義です。つまり、Arduinoオブジェクトの命令定義となります。まず、「ひらけごま」命令から。
Arduino:ひらけごま=「|_port|
  自分!(_port)開く。
  w=0.01。r=undef.
  「c=自分!データ数?。「(c)>0」!なら「w=0」実行。自分!(w)待つ」!20 繰り返す。
  「c>0」!なら「r=自分!(c)値?」実行。
  w=0.01。r=undef.
  「c=自分!データ数?。「(c)>0」!なら「w=0」実行。自分!(w)待つ」!100 繰り返す。
  「c>0」!なら「r=自分!(c)値?」実行。
  自分。
」。
「ひらけごま」命令は、引数をひとつとります。ポート名です。これは、ドリトルがインストールされているコンピュータにArduinoを接続しているとき、OSが認識しているポートの名前です。例えばWindowsなら「COM5」とか、MacにArduino Unoをつないでいる場合なら「/dev/cu.usbmodem26231」のようなものです。これを、_portという変数で受け取ります。

しばらくなにやら値を読むことを繰り返していますが、最終的に読んだ値を使っている形跡はありません。ここで、Arduinoのスケッチのsetup()関数のなかで、最後に空白文字をドリトル側に送信していたことを思い出してください。とにかくこれがやってくるまではArduino側の準備はできていませんから、それが届くまではゆっくりと待ち、届いたら待ちなしでさっさと繰り返しを終わるようなことをしているのではないかと思われます。

そして、肝心なのは、最後の“自分。”です。これを最後に書くことで、「ひらけごま」命令を実行したときに、Arduinoオブジェクトを返します。なんのことやらわからないと思いますが、ドリトルで「カスケード」と呼ぶ文法、つまり、同じオブジェクト(例えばカメ太)に連続して命令を書く記述方法がありますが、これを実現するために必要なことです。ドリトルは、カスケードしている場合、左からひとつ命令を実行して、その結果返ってきたオブジェクトに対して次の命令を与えることを文末まで繰り返すのです。
Arduino:とじろごま=「!とじる」。
これはあっさりと、シリアルポートオブジェクトが持っている「閉じる」命令をそのまま「とじろごま」命令に定義してます。

次から面倒な話が続きますが、ご容赦ください。どんどんドリトルの内部に入っていきます。
Arduino:newobj=「|a|
  obj=""。
  obj:_arduino=a。
  obj:getcmd=「|base port| obj:base=base。(base+port)!コード文字」。
  obj:待つ=「|t|_arduino!(t)待つ」。
  obj:書く=「|v|_arduino!(cmd) 出力。_arduino! (v) 出力。!0.001 待つ。」。
  obj:読む=「
    _arduino!(cmd) 出力。
    w=0.01。
    「c=_arduino!データ数?。「(c)>0」!なら「w=0」実行。_arduino!(w)待つ」!20 繰り返す。
    「c>0」!なら「(_arduino!(c)値?)!文字コード」そうでなければ「0」実行。
  」。
  obj。
」。
「newobj」命令を定義していますが、これは日本語では「作る」命令に対応しています。“a=Arduino!作る。”と書いたときの「作る」です。最初に“|a|”と、変数宣言されていますが、これは親オブジェクトを受け取るための引数だと思ってください。Arduinoオブジェクトの親オブジェクトはシリアルポートオブジェクトです。

次にわかりにくいのは、“obj=""。”でしょう。空の文字列をobjという変数に代入しています。これは実はドリトルで、全く新種のオブジェクトを定義するときの常套句で、「特にどれということはないが何か新しいオブジェクトを作ります」というときには、文字列オブジェクトの子どもとして作ることになっています。ドリトルはプロトタイプベースのオブジェクト指向言語なので、システムが用意しているオブジェクトの子ども以外のオブジェクトを作ることができません。そこで、「なんでもいいけど、印刷とかすぐできるし文字列の子どもにでもしておこうか」ということが多いのです。

というわけで、仮のオブジェクトであるobjに以下、属性(変数やメソッド)を定義しています。まず、親オブジェクト(シリアルポートオブジェクト)を_arduinoとして覚えることにして、以下使えるようにします。次にgetcmd命令を定義して、コマンドを表す上4bitとポート番号を表す下4bitを結合する作業を定義しています。引数baseがArduino側で解釈されるコマンド番号、portがArduinoの入出力ポートの番号です。足した値を「コード文字」で文字に変換することで、シリアルポートオブジェクトの「出力」命令に対応しています。次の「待つ」命令は、シリアルポートオブジェクトの「待つ」命令をそのまま使っています。次の「書く」命令ですが、cmdという変数が登場します。しかし、ここではこの変数の値は未定義です。別の命令で、この値を設定してから「書く」命令を呼び出す必要があるということです。次の「読む」命令は少し長いので、段落を改めることにします。

「読む」命令では、最初にcmdの値を出力しています。デジタル入力かアナログ入力か、どちらかわかりませんが、どちらかに対応したコマンド番号が送られるはずです。続く2行は「ひらけごま」命令にもありましたが、20回データが届くまで待ってから、届いた1つの値を「文字コード」命令で数値に変換し、もし値が返ってきていなければ0を値としています。そして、最後の“obj。”で、「作る」したオブジェクトを返します。

以下、Arduinoのポートを入力・出力のどちらかに設定する命令の定義になります。
Arduino:デジタル出力=「|portstr|
  obj=Arduino!(自分)newobj。
  obj:cmd=obj!0x40 (portstr) getcmd。
  自分!(obj!0x20 (portstr) getcmd) 出力。
  !0.01 待つ。
  obj。
」。
「デジタル出力」命令は、ポート番号を引数にとり、それと、デジタル出力への設定を行います。ただ、予め(通常、続けて実際に値を出力する「書く」命令が実行されるはずなので)デジタル値の出力に対応するコマンド番号4(0x40)をgetcmdで組み合わせてcmdに設定し、続けてデジタル出力設定のコマンド番号2(0x20)をArduinoに送っています。ここでも最後にobj。を書いて、カスケードに対応します。
Arduino:デジタル入力=「|portstr|
  obj=Arduino!(自分)newobj。
  obj:cmd=obj!0x50 (portstr) getcmd。
  自分!(obj!0x30 (portstr) getcmd) 出力。
  !0.01 待つ。
  obj。
」。
「デジタル入力」命令でも同様に、cmdに値を読むコマンド5(0x50)を設定してから、ポートをデジタル入力に設定するコマンド番号3(0x30)をArduinoに送っています。
Arduino:アナログ出力=「|portstr|
  obj=Arduino!(自分)newobj。
  obj:cmd=obj!0x60 (portstr) getcmd。
  obj。
」。
「アナログ出力」コマンドは、ArduinoでPWM出力できるピンは決まっていて、予め出力の設定が不要なので、単にコマンド番号6(0x60)をcmdに設定するだけです。値を出力するのは、newobj命令のなかで定義した「書く」命令が実行します。
Arduino:アナログ入力=「|portstr|
  obj=Arduino!(自分)newobj。
  obj:cmd=obj!0x70 (portstr) getcmd。
  obj。
」。
「アナログ入力」コマンドも、単にコマンド番号7(0x70)をcmdに設定しているだけです。実際に値を読むのは、「読む」命令が担当します。

最後の
」実行。
は、なんと1行目の条件分岐に対応しています。つまり、ここまでを、シリアルポートがOSにあった場合にやりますよ、というわけです。

これで、すべての解説が終わりました。実際にみなさんがArduinoでセンサーの値を調べたり、出力デバイスを制御したりするプログラムの書き方は、テキストの105ページから110ページまでに書かれています。ぜひ試してみてください。また、Arduino以外の別のデバイスをドリトルと通信させることも、ここで解説した内容の応用でできるかもしれません。

参考になれば幸いです。

やや蛇足


最後に、蛇足になりますが、Arduinoに接続するデバイスで、高級なもの(LCDや7seg LED、SDカードやGPSなど)は、いまのところ厳密には対応していません。特に、GPSのようにシリアルポートが必要なデバイスは、Arduino標準のSerialオブジェクトがドリトルとの双方向通信でふさがっているため、そこには接続できません。Arduinoのスケッチ側で、別のデジタル入出力ポートを指定したSerialオブジェクトを作成して、そこで通信しなければなりません。

これを実現するためには、「新しいシリアルポートを追加する」コマンドの追加と、「シリアルポートを指定して値を読み書きする」コマンド2つの、全部で3つのコマンドが必要です。

幸い、コマンドには4bitが割り当てられており、まだ6つしか使っていませんから、10個のコマンドが原理的には追加できるはずです。そのため、まずArduinoのスケッチで変数cmdをintではなく、unsigned intで定義しておくのが無難ではないかと思います。

Arduinoに接続するデバイスのうち、I2CやSPIプロトコルで接続するものも、ドリトル側でクロック生成するのは難があるかもしれません。その場合はまた、コマンドの追加ということになるかもしれません。

ただ、いずれにせよ、Arduino側にインタプリタを置いて、ドリトルとインテリジェントに通信するというアイディアは実にナイスだと思います。

2011年1月28日金曜日

低予算で小学生にも組み立てられる「あの楽器」作りました

教員養成が仕事なのですが、中学校の技術・家庭科で「計測と制御に関するプログラム」という項目が必修になり、関係者の間でどうすべきかということが盛んに議論されているところです。

そんななか、これまで僕は自律ロボットの製作とプログラミングを実習授業でやってきていたのですが、お金の問題とか、いろいろ行き詰まりを感じて、単純に楽しめて工夫できる題材を考えていました。

そして、そのひとつの提案が、ここで紹介させていただく「あの楽器」です。

そうです、「あの楽器」です。ネギとかいう人もいます。余談ですが。

とにかく安くて子どもが持って帰ることができること、それから、プログラムで工夫して変化をつけられること、最後に、家で当分遊べることを目標にしました。

以下、仕様:
  1. 黒くてショルダーキーボードのような形状
  2. 手を触れると音が出る
  3. 音に合わせてなにやらビジュアル効果が表示される
1.は問題なし。子どもの体型に合っていればよい。2.で、センサーの登場です。計測するわけです。3.はたいへん敷居が高いところです。「ニコニコ動画」の「作ってみた」カテゴリの方々は、ここに高価な液晶ディスプレイなどを使って、Flashの動画を出したりしているようです。

しかし、「あの楽器」特有の幾何学模様を妥協すれば、単純にLEDを光らせるだけで相当な効果が出そうです。音に合わせてぱらぱらと複数のLEDがいろいろな色で光れば、結構インパクトが出ることが期待できます。

そして設計したのが以下の内容です。
  • 手のセンサーに、シャープのPSD測距センサーを使う
  • 楽器の裏からLEDをいくつか出して、アクリル板で散光させる
アクリル板に、蛍光マーカーで絵を描けばきれいで、子どもも喜びそうです。

さて、マイコンですが、僕は大阪電気通信大学教授の兼宗先生のお仕事に関係していて、学生へのプログラミング実習でも、彼の「ドリトル」を使っています。いまのところ、ドリトルでプログラムできるマイコンボードとしては、静岡のスタジオミュウさんの「ミュウロボ基板」とArduinoの2つがあります。といっても、Arduinoは独立して動かすのではなく、I/OとしてPCに接続したままPC上のドリトルで値を読んだり書き込んだりするために使うようになっています。

そこで、ミュウロボ基板にドリトルでプログラムを書きこんで楽器に仕立てようということになります。ミュウロボ基板にはピエゾスピーカーが搭載されていて、ドリトルからは「電子音」命令で、指定した時間の長さだけ、指定した波長の矩形波を出すことができます。

センサーからの入力は、PIC 16F688搭載のミュウロボ基板では、10bitのA/Dコンバータを通したアナログ入力ができるので、これを使います。

試しに、秋月で買ってきた1個400円のPSD「GP2Y0A21YK」の出力をミュウロボ基板のアナログ入力端子に直接入れてみました。よくしたもので、定格範囲内で、20〜130ぐらいの値としてみえているようです。そこで、その値を直接「電子音」命令のパラメータに入れてみました。音の長さは最短の0.1秒です。

すると、音が連続しないように、0.01秒程度の無音期間が入りますが、距離に応じて、遠ければ低い音、近ければ高い音が出ます。手を動かすと、断続的ではありますが、音程の変化がわかり、慣れてくると、ある程度の音階も表現できそうなことがわかりました。

というわけで、音はOK。あとはビジュアルエフェクトです。複数のLEDをランダムに光らせたいわけですが、測定値の2進の値をそのまま出力ポートに出せば、LEDがビットの順にさえなっていなければランダムに見えそうです。

よくしたもので、ミュウロボ基板はPICを使っていますから、LEDぐらいなら直接ドライブできます。高輝度で光軸の角度が広い(拡散を狙うため)LEDを何色か買ってきて、つないでみました。いい感じです。

ここまで確認ができたところで、研究室の卒業研究の題材として与えることにしました。教材開発ということになります。対象は本来なら中学生でしょうが、職場で工作教室のイベントを年間を通して実施していて、小学生がたくさんきます。そこで、このイベント向けに、小学生サイズの、小学生ができる工作の範囲で作るということを目標にさせました。

まあそれはともかく、作品を見てください。

いい感じでしょう。

演奏をよく見ると、右手で音を出しているのですが、左手親指を動かすと、音が変化しているのがわかると思います。ここが、第2のセンサーです。

価格的に、ミュウロボ基板とPSD測距センサーで工作教室の予算はいっぱいなのですが、「より楽しい演奏」のためのオプションを試してみたのです。

これも秋月で1個500円で売っているFSR(力感知抵抗)という、力を加えることによって抵抗値が下がる受動素子です。データシートを見る限り、抵抗膜方式のタッチパネルと同じ原理といってもよさそうです。

抵抗値は、無負荷で1MΩ、100gあたりで一気に10kΩまで下がり、そこから10kgぐらいまで、「逆べき乗」の関係で0Ωに近づいていきます。この変化は、抵抗膜と導体の間にポリウレタンのドームが60個、面状に配置されているため、これが潰れて両者が接触するまで抵抗値がかわらないということです。実際にテスタで変化を確かめると、データシートに似た変化をすることが確認できました。

PICのAポートは設定によって、10kΩの抵抗でプルアップされます。ミュウロボ基板は、入力端子がすべてこの設定になっています。ですから、FSRを直結しても、A/D値は0から半分までの値をスイングしそうです。

ところが試してみると、100gのポイントで一気に0になってしまいました。これではスイッチとしてしか使えません。そこで真面目に、オペアンプを使って電流-電圧変換させてやることにしました。うまいことに、データシートにLM358を使った単電源の電流-電圧変換回路の例が載っています。

この通りの回路をブレッドボードで実験し、負帰還のRを10kΩにしてやると、押した感触をうまく反映した値が出ることがわかりました。実測で、183〜230ぐらいの値です。

これをどう使うか、ミュウロボ命令の「電子音」は、音の長さ(0.1秒単位)と波長(8bit)しかありません。そこで、両方を試してみることにしました。

まず、音の長さを変化させることを考えます。右手を距離センサにかざしても音は出ず、左手の押す力の大きさで音の長さを変化させます。イメージは、ピアノのサステインペダルです。かといって、単音しか出せないので、あまり長い音が出ても困ります。そこで、何回か試したところ、185を引いて負になったら0にして、その結果を4で割ると、それなりのニュアンスが出せました。

もうひとつ、波長の変化です。シンセについているベンドをイメージしました。押して音程を下げるよりは、上げたほうが雰囲気が出そうです。ギターのチョーキングのイメージです。

「電子音」命令の、波長のパラメータは、30ぐらいで1度ぐらいの差になります。では、ということで、185を引いて負にならないようにした値を、距離センサの値から引いてやりました。ただ、どうしても音が0.1秒単位で切れるので、ポルタメント的な変化は感じられません。最初は値を割ったりしましたが、極端に変化したほうがわかりやすいだろうと判断しました。最終的には、4倍しています。また、距離センサの値が小さく圧力センサの値が大きいと、引いた結果が負になりますが、試してみるとそれはそれで意外性があっていいや、という気分になりました。

この結果が、上記のビデオの音です。

まともな楽器というよりは、ガジェットといったほうがふさわしそうな仕上がりになりました。「楽しければいい」という意味では、これぐらいがちょうどいいのかもしれません。

肝心のボディですが、学生が工夫して、表面は黒と決めたので(なんせ「あの楽器」ですから)、小学生が持てる重さを考えて、黒のスチロールボードを使っています。外周は木材を使って剛性を保っています。小学生が多少乱暴に扱っても壊れないことを目指しました。LEDの光を散光させる透明板ですが、アクリルは重いのと高価なことで、プラスチック板としました。おかげで加工が簡単になりました。

最後にプログラムリストをご紹介します。ミュウロボ基板でロボットのプログラムを書いたことがある人には、センサの値を演算したり、条件分岐したりすることを意外に思うかもしれません。

実は、ミュウロボ基板のファームウェアで実現されたVMのバイトコードを直接プログラムしています。簡単なレジスタマシンを実現していて、限られてはいますが最低限必要な演算や分岐命令を持っています。また、引数をレジスタに指定して、指定したバイトコードを直接実行させる命令があり、evalというかexecというか、非常に自由度が高くなっています。「計測値を使って音を鳴らす命令」のためには必須の命令です。

結果、ぱっと見てどんなプログラムか理解するのは難しそうな、変態プログラムができました。でもこういうことに悦びを感じるのですよ、どうしても。

というわけで、リストを掲げてご紹介を終わります。


システム!"MYU"使う。

ロボ太=MYU!"COM5"作る。
ロボ太:演奏=「!はじめロボット
パワーオンスタート
「!
4 AN // In4の圧力センサの値をAに保存
「!30 以上のA」なら「!185 SUB」実行 // 183~230あたりの値が出るので調整
「!CFLAG」なら「!CLA」実行 // 念のため負になったら0にする
RLA // 2倍する
RLA // さらに2倍
EXARG1 // Aの値をARG1レジスタに退避
2 AN // In2の距離センサの値をAに保存
「!80 以上のA」なら // 値が80未満なら音を出さない
「!
SUBARG1 // Aから計算結果(ARG1にある)を引く
AARG2 // その結果を音程に設定
1 ARG1 // 時間は0.1秒固定
APC // LEDを光らせる
105 CMD // 電子音命令実行
CLPC // LEDを消す
」実行
」繰り返す
おわりロボット」。
ロボ太!演奏。