アーカイブ
serial-socket-gateway
よくある シリアル通信 <=> TCP Socket する物を作った。
しばらく使ってて特に問題なかったので、使い方とか書いておく。
Mac OSX LeopardとUbuntu 9.04,と10.04とWindows XPで動作した。
普通のsocketなので大抵のプログラム言語から使えるし、少なくとも10個ぐらいのプログラムを下にぶらさげてマイコンと通信させられる。
最近はコレでsocket化したシリアルデバイスにJRubyで作ったGUIをつないで色々やってる。
■ソースコード
githubにある
http://github.com/shokai/serial-socket-gateway
■インストール
git clone git://github.com/shokai/serial-socket-gateway.git
中のserial-socket-gatewayがそれ。Rubyで書かれている。
単体のファイルで動くので、そのまま /usr/local/bin/ とか適当なパスの通っているディレクトリに cp すればいいと思います
■必要なgemのインストール
ruby-serialportとeventmachineを使っているのでそれぞれインストールする。
gem install eventmachine ArgsParser
ruby-serialportは0.7が動かなかったので、俺は0.6を使っている。MacやUbuntuはソースからビルドしてインストーrうする
wget http://rubyforge.org/frs/download.php/72/ruby-serialport-0.6.tar.gz
tar -zxvf ruby-serialport-0.6.tar.gz
cd ruby-serialport-0.6
ruby extconf.rb
make
sudo make install
Windowsは、http://rubyforge.org/tracker/download.php/61/321/9924/1800/ruby-serialport-0.6.0-mswin32-gem.zipからwindows用のバイナリ(gem)を持ってきて、解凍してインストール。
gem install serialport-0.6.0-mswin32.gem
■起動
Arduino等をMacに接続すると /dev/ の下に、tty.usbなんとかというデバイスができているはず。
serial-socket-gateway /dev/tty.usbserial-A7006Rqnデバイス名を引数に渡して起動。
接続してみる。telnetでok
telnet localhost 8782デフォルトで8782番portで起動している。port番号はソースの上の方をいじれば変えられる。
■通信の仕様
改行(¥n)区切りで、1行毎に通信している。改行が来るまで送受信しない。
■サンプルプログラム Arduinoから送信
こんなかんじでADコンバータで電圧測って、Serial.println()を使って末尾に改行を付けて9600bpsパリティなしストップビット1で送信。
int ad_pin = 0;
void setup(){
Serial.begin(9600);
}
void loop(){
int ad = analogRead(ad_pin);
Serial.println(ad);
}
■サンプルプログラム Rubyで受信
間にserial-socket-gatewayを挟んでシリアルデバイスと通信する。
require 'socket'serial-socket-gatewayはclientとの接続が切れていないか確認する為に、たまに空文字列を送ってくる。
s = TCPSocket.open("192.168.1.100", 8782)
loop do
res = s.gets
if res.to_s.size > 0
puts res
end
end
受信した文字列の長さを見て無視してください
送信は
s.puts "abc abc"rubyのputsは末尾に改行(¥n)が付く。
■サンプルプログラム Rubyで送受信を同時に
標準入力をserial-socket-gatewayにそのまま送る。こういうのeventmachineでやると楽だね
#!/usr/bin/env ruby
require 'rubygems'
require 'socket'
require 'eventmachine'
HOST = 'localhost'
PORT = 8782
begin
s = TCPSocket.open(HOST, PORT)
rescue => e
STDERR.puts e
exit 1
end
EventMachine::run do
EventMachine::defer do
loop do
res = s.gets
exit unless res
if res.to_s.size > 0
puts res
end
end
end
EventMachine::defer do
loop do
s.puts gets
end
end
end
eventmachineが便利!!
BeagleBoard(Ubuntu9.04)とArduinoやmoxaを接続し、シリアル通信でやりとりする
BeagleBoardはTIの作ったオープンソースハードウェア。こっそり春頃からいじっていたんだけど書いてなかった。
スペックに難はあるが、ディスプレイとサウンド出力つきの組み込み環境が俺でも作れるのは魅力。作品のレベルをプロダクトに近い所まで引き上げられる。
最近CRESTでのプロジェクト用にARM版Ubuntu9.04をbuildしてインストールして、Arduinoと接続する所までやったので書いておこう。
今はApache2とruby1.8.7(いずれもaptでインストールした)を使って、外付けしたArduinoとmoxaからデータを読み取っている。とりあえず大学院棟の明るさをCdSで取得してwebに公開している → http://shokai-b.mag.keio.ac.jp/light

■準備
BeagleBoardと、インストール時にパソコンとBeagleBoard間でシリアルコンソールを使うのに必要なBeagleケーブルはdigikeyで購入できる。他の部品は国内で全て入手可能。

■Ubuntu9.04をBeagleBoardにインストール
OSはSDカードにインストールする。
最初デスクトップ版をインストールしてみたけど重すぎた。AngstromやHandheld Mojoならそれなりに動くけど、フルのUbuntuデスクトップはウィンドウマネージャをtwmにしても無理だった。
今回の用途にはCUIがあれば十分だったので、最低限のbuildツールを含んだARM用イメージを作って起動させた。
なお作業はext3のファイルシステムが読み書きできる必要があるので全て別のUbuntu Desktopで行った。
- BeagleBoardにUbuntu Desktop版インストール – 橋本詳解
- BeagleBoardにUbuntuセットアップ(GUIなし)、sshdを入れてリモートログインしてみる – 橋本詳解
- いろいろインストールして環境を整える – 橋本詳解
- Rubyまわりをインストール – 橋本詳解
これで、ApacheやRubyやsshdはもちろん、emacsと各種elisp、gemとeasy_install、rails2やsinatra、mongrel_clusterとapache2でmod_proxy_balancerなどがaptとgemでさくっとインストールできた。
このへんのサーバサイドアプリ開発環境のセットアップの容易さはubuntuさすが。
処理速度は体感でDebian化した白箱より速い。SDカードなのであまりR/Wしたくないがたぶん外付けUSB-HDDも認識できるんじゃないだろうか。そうすると、クローラ作ったり簡単なbotを動かす程度の俺は自宅サーバ環境はBeagleBoardで十分という可能性もある。
処理速度とストレージ読み書きに不安はあるが小型かつバッテリーでも動かせるUbuntu Linux環境ができた。
■Arduino / moxaとの通信
BeagleBoard基板上のシリアルコンソールに使ったポートをArduinoやmoxaとの通信を使った。
本当はUSBで接続したかったけどできなかった。
FTDIチップのドライバはaptでインストールできるが、USBに接続しても認識されない(/dev/ttyUSB0に現れない)
同じバージョンのUbuntuデスクトップを別のAMD64マシンで用意して、同じようにセットアップをしたがこちらは認識した。ARM版Ubuntuが何かおかしいのかもしれない。
64bitAMDマシンではlsmodした時にFTDIチップを監視してるプロセスがいるんだけど、BeagleBoardではlsmodしてもいない。
誰かLinux詳しい人教えてくれるとうれしいです・・・
しかたないのでセットアップに使ったBeagleケーブルのオス版を作って通信に使う。
シリアルポートの9つのピンにはよく見ると番号が振ってあり、それをBeagleBoardの基板上の1~9ピン(10は無視する)と接続する。
シリアルポート側は
12345
6789
のようになるが、BeagleBoard上のコネクタは
13579
2468
となっているのでとても捻れる。気合いではんだづけする。基板上のシルク印刷をよく見てね。




これで、Arduinoの外側にあるRX / TXピンにMAX232(ADM3202)を接続すればBeagleBoardとシリアル通信できる。

ArduinoにCdS(明るさのセンサ)なんかを接続して数値をBeagleBoardに送り続ければいい。
/etc/event.d/ttyS2 を削除して再起動すると、/dev/ttyS2がシリアルコンソールではなくシリアルポートとして開ける。
screen /dev/ttyS2
でモニタできる。
UNIX系なので、シリアルポートもFileとして簡単に読み出せた。
Arduino + BeagleBoard(Ubuntu) シリアルポートを読んでたまにファイルに書き出す – 橋本詳解
通信できる手段が整えばあとは好きにできる。
Mac版Arduino IDEがlibrxtxSerial.jnilibが見つからないエラーで起動しないのを対処
起動時にこんなエラーが出た。環境はMacbook pro 17インチ OSX LeopardでXCodeなどもたぶん全部入れてあるメイン開発環境。
java.lang.UnsatisfiedLinkError: /Applications/arduino/Arduino.app/Contents/Resources/Java/librxtxSerial.jnilib: no suitable image found.

原因は64bit環境で実行されようとしているかららしい。
対処法は2つ。
■Arduinoを32bit版で起動させる
Arduino実行ファイルを右クリックして「情報を見る」
「32ビットモードで開く」にチェック入れる
(hitoriblogさんより)
■64bit版rxtxSerial.jnilibをインストールする
http://iharder.sourceforge.net/current/java/librxtxSerial.jnilib を
/Arduino 16.app/Contents/Resources/Java/
の中にある librxtxSerial.jnilib と入れ替える。
これはTechnobabble: Arduino: Problems With librxtxSerial.jnilibに書いてあった方法。
両方ともIDEの起動までは試した。
Arduinoの実機が今ないので動作は試していない。まあどっちかで動くだろう。
他にもフォーラムでも同様の質問が出ていて、こちらでは
アプリケーション/ユーティリティ/Java Preferences
でJavaアプリケーションの方でJ2SE5.0の32bit版が優先されるように上の方にもってこいという指示が出ていた。質問者はこれで解決したらしいけど俺の環境では駄目だった。
これはArduinoがJ2SE6向けに作られていないため。
Arduinoが流行っている
日本語Twitter検索でarduinoのRSSを監視しているんだけど、最近はかなりの頻度で誰かがArduinoをいじっているのでGoogle Trendsでも見てみた
まずは世界全体。2005年ごろに出てから毎年倍々になってきている。
Google Trends: arduino (世界全体)

続きを読む…
Arduino – ロータリーエンコーダ改
Arduino – ロータリーエンコーダを回すのコードがアレだったのでシンプルに書き直した。回路はそのままで。
char rot_state; // 状態 0~3
char rot_pinA = 8; // PinA of RotaryEncoder
char rot_pinB = 9; // PinB
void setup()
{
Serial.begin(9600);
pinMode(rot_pinA, INPUT);
pinMode(rot_pinB, INPUT);
rot_state = rotary_getState(rot_pinA, rot_pinB); // 現在の状態を保存しておく
}
void loop()
{
// ロータリーエンコーダの状態を監視して、PCにシリアル通信で送る
char rot_past = rot_state;
rot_state = rotary_getState(rot_pinA, rot_pinB); // 今の状態
char rot_dir = rotary_getDir(rot_state, rot_past); // 回転方向
switch(rot_dir){
case 2:
Serial.println("R"); // 右回転
break;
case 1:
Serial.println("L"); // 左回転
break;
}
delayMicroseconds(10);
}
/* ロータリーエンコーダの状態番号0~3を取得する */
char rotary_getState(char pinA, char pinB){
// 2つのピンからの入力状態をチェック
if(digitalRead(pinA)){
if(digitalRead(pinB)) return 2;
else return 0;
}
else{
if(digitalRead(pinB)) return 1;
else return 3;
}
}
/* 1つ前の状態と比較して、回転方向を取得する */
char rotary_getDir(int state, int past_state){
if((state+3+1)%3 == past_state) return 1; // 左回り
else if((state+3-1)%3 == past_state) return 2; // 右回り
return 0; // 変化無し
}

最近のコメント