Arduino Playground - Rubyに載ってた方法をそれぞれ試したのでメモ。
いずれもCRubyが動くコンピュータをArduinoに接続して動かす想定です。
- serialport gem
- arduino_firmata gem
- dino gem
今回、Windows 10に接続したArduinoで試してみたので、その備忘録です。
serialport gem
- シリアルポート入出力するスケッチを自分で作ってArduinoに書き込む
- 一般的なシリアルポート入出力でRubyを書く
なお、Windowsの場合は事前にDevKitのインストールが必要です。
感想
よい
- 低レベルな実装なので、gemの機能的制限やバージョンなどを気にしなくて良い
- 制御がArduino側にあるので速そう
いまいち
- スケッチを書くの軟弱Rubyistには辛い
- シリアルポートとの通信を意識したコードを書くのが面倒
arduino_firmata gem
Firmata(ふぁるまーた)というArduinoを制御するためのプロトコルをRubyに移植したもの、らしい。内部でserialport gemを使用している。
橋本商会 - RubyからArduinoを操作できるようにFirmataプロトコルを移植した
- FirmataをArduinoに書き込む(Arduino IDEのスケッチの例にあります)
- 制御コードをRubyで書く
感想
よい
- Rubyで制御できるのでRubyist的には嬉しい
- シリアル通信などライブラリが面倒見てくれて楽
- 公式のIDEに入ってる安心感はある
いまいち
- 制御がPC側にあるので通信する分遅そう
dino gem
基板上のLED、ボタン、サーボなどをオブジェクトとして捉え、メッセージパッシングで動作を書く、よりオブジェクト指向的なアプローチ。
内部でarduino_firmataを使用している。
-
dino generate-sketch serial
コマンドで作成されるスケッチをArduinoに書き込む - 制御コードをRubyで書く
感想
よい
- Rubyで制御できるのでRubyist的には嬉しい
- シリアル通信などライブラリが面倒見てくれて楽そう
- オブジェクト指向たのしいそうです。
いまいち
- 制御がPC側にあるので通信する分遅そう
- 他とあまりに考え方が異なるのでちょっと変わったことをしようとすると辛そう
- Windowsで上手く動かなかった
- 機能的な不備はまだありそうなのに長らくmasterが更新されていないのが気になる
サンプルコード
以下の2つをそれぞれのgemで書いてみた。
- Arduino上のスイッチの押し下げ回数をコンソールに表示する
- Arduino上のLEDをコンソール入力に従って付けたり消したりする
serialport gem
Read
# Arudino受信サンプル
# Arduinoからのシリアルポート出力を受け取って表示するRubyスクリプトサンプル
#
# C:\Ruby22-x64\bin\ruby.exe -e $stdout.sync=true;$stderr.sync=true;load($0=ARGV.shift) C:/Users/Yuichi/IdeaProjects/Arduino/serialport_sample/sample.rb
# Count : 1
# Count : 2
# Count : 3
# Count : 4
# Count : 5
# Count : 6
# Count : 7
# Count : 8
# Count : 9
# Count : 10
require 'serialport'
port = 'COM3'
baud_rate = 9600
STDOUT.sync = true
SerialPort.open(port, baud_rate) do |sp|
sp.read_timeout = 10
loop do
begin
puts sp.readline
rescue EOFError
retry
end
end
end
int SWITCH_SOCKET = 2;
int count = 0;
void setup() {
pinMode(SWITCH_SOCKET, INPUT);
Serial.begin(9600);
}
void loop() {
if (digitalRead(SWITCH_SOCKET) == 1) {
count = count + 1;
Serial.print("Count : ");
Serial.println(count);
while(digitalRead(SWITCH_SOCKET) == 1) {
delay(100);
}
}
}
Write
# Arudino送信サンプル
# Arduinoへのシリアルポート入力でLEDを付けたり消したりするサンプル
#
# C:\Ruby22-x64\bin\ruby.exe -e $stdout.sync=true;$stderr.sync=true;load($0=ARGV.shift) C:/Users/Yuichi/IdeaProjects/Arduino/serialport_sample/write_sample/write_sample.rb
# "ON" or "OFF"
# INPUT> ON
# Turn on
# INPUT> OFF
# Turn off
# INPUT> ON
# Turn on
# INPUT> OFF
# Turn off
# INPUT>
require 'serialport'
port = 'COM3'
baud_rate = 9600
$stdout.sync = true
SerialPort.open(port, baud_rate) do |sp|
puts '"ON" or "OFF"'
print 'INPUT> '
while input = readline
input.chomp!
case input
when 'ON'
puts 'Turn on'
sp.write '1'
when 'OFF'
puts 'Turn off'
sp.write '0'
else
puts 'Invalid'
end
print 'INPUT> '
end
end
int LED_SOCKET = 13;
char ch = '0';
void setup() {
Serial.begin(9600);
pinMode(LED_SOCKET, OUTPUT);
}
void loop() {
if(Serial.available() > 0){
ch = Serial.read();
if (ch == '1') {
digitalWrite(LED_SOCKET, HIGH);
} else if (ch == '0') {
digitalWrite(LED_SOCKET, LOW);
}
}
}
arduino_firmata gem
Read
# Arudino受信サンプル
# スイッチの押し下げ回数を arduino_firmata gem でカウントする
#
# C:\Ruby22-x64\bin\ruby.exe -e $stdout.sync=true;$stderr.sync=true;load($0=ARGV.shift) C:/Users/Yuichi/IdeaProjects/Arduino/arduino_firmata_sample/read_sample/read_sample.rb
# Count : 1
# Count : 2
# Count : 3
# Count : 4
# Count : 5
require 'arduino_firmata'
PORT = 'COM3'
SWITCH_SOCKET = 2
arduino = ArduinoFirmata.connect(PORT)
arduino.pin_mode(SWITCH_SOCKET, ArduinoFirmata::INPUT)
$stdout.sync = true
count = 0
loop do
if arduino.digital_read(SWITCH_SOCKET)
count = count.succ
puts "Count : #{count}"
while arduino.digital_read(SWITCH_SOCKET)
sleep 0.1
end
end
end
Write
# Arudino送信サンプル
# PCでの入力に基づいてLEDを付けたり消したりする
require 'arduino_firmata'
PORT = 'COM3'
LED_SOCKET = 13
arduino = ArduinoFirmata.connect(PORT)
arduino.pin_mode(LED_SOCKET, ArduinoFirmata::OUTPUT)
loop do
puts '"ON" or "OFF"'
print 'INPUT> '
while input = readline
input.chomp!
case input
when 'ON'
puts 'Turn on'
arduino.digital_write(LED_SOCKET, true)
when 'OFF'
puts 'Turn off'
arduino.digital_write(LED_SOCKET, false)
else
puts 'Invalid'
end
print 'INPUT> '
end
end
dino gem
手元の環境で動かなかった(シリアルポート接続のあたりで止まる)ので、サンプルを用意できませんでした。
僕の結論
arduino_firmata gem
あたりが丁度よいバランスな気がします。
でもちゃんと書くなら、dinoのような設計がよさそうなので、そういう実装をしたいです。