2011年3月11日 星期五

使用 Firmata 協定連接 Processing 與 Arduino

實驗目的

練習使用 Firmata 協定把 Processing 與 Arduino 連接起來,使用可變電阻 (potentiometer) 來控制 Processing 畫面上的矩形的水平移動。

image

註: 這篇跟「透過序列通訊把 Processing 與 Arduino 連接起來」一文所用的例子是一樣的,文中部份內容會重覆,對沒有看到該文的朋友來說,這樣比較方便閱讀。

材料與接線
  • 麵包板 x 1
  • Arduino 板子 x 1
  • 可變電阻 x 1
  • 單心線 x N

接線很簡單,參考下圖,把可變電阻中間腳位接到類比輸入(Analog Input) pin 0,剩下的兩支腳位,一支接到 5V,另外一支接到 GND:

image

Arduino 程式

打開 Arduino IDE,點選 File > Examples > Firmata > StandardFirmata 並將程式上傳到 Arduino 板子上:

image
▲ Arduino IDE

要注意一件事,StandardFirmata 這支 Arduino 程式所用的序列通訊速率是 57600 bps,所以當你在寫 Processing 端的程式在開啟 Serial port 時,記得也要把通訊速率設成 57600 bps,這樣 Arduino 跟 Processing 兩邊才能溝通。

image

安裝給 Processing 用的 Arduino 函式庫

為了讓 Processing 有能力跟 Arduino 使用 Firmata 協定通訊,你必須安裝給 Processing 用的 Arduino 函式庫。

Arduino 函式庫的安裝辦法很簡單。首先,到 arduino.cc 官網這個頁面或直接點這裏 (2009/9/22 的版本) 下載 Arduino 函式庫。如下圖,函式庫壓縮檔裏只有一個 arduino 資料夾:

image 

接著,你只要把 arduino 資料夾解壓縮到 Processing 速寫簿 (Sketchbook) 資料夾的 Libraries 資料夾底下即可。Processing 速寫簿 (Sketchbook) 資料夾的預設位置是在「我的文件 > Processing」這個地方:

image

Processing 程式

Processing 程式如下 (Rect_Firmata.pde),程式的邏輯是讀取 Arduino 類比輸入 pin 1 的 Sensor 讀值,然後利用 Sensor 的讀值控制矩形的水平移動:

可變電阻的讀值會存放在 sensorValue 裏。rect(sensorValue, 80, 50, 50); 這一行會在 (x, y) 座標為 (sensorValue, 80) 的位置畫出一個 50 x 50 的矩形。因為是水平移動,所以我們把 sensorValue 當作是 x 軸的位置變數,而 y 軸固定在 80 的位置。

Arduino函式庫的用法也很簡單,步驟大概如下:

  1. import cc.arduino.*;  指令載入 Arduino 函式庫
  2. Arduino arduino; 指令宣告一個 arduino 物件參考
  3. arduino = new Arduino(this, "COM4", 57600); 指令建立 arduino 物件。如果你 Arduino 不是接在 COM4,請做適當調整。注意!記得通訊速率要跟 Arduino 端一樣使用 57600 bps。
  4. 最後,用 sensorValue = arduino.analogRead(potPin); 指令來讀取可變電阻的讀值。
範例照片/影片

先把 Arduino 程式(StandardFirmata ) 上傳到 Arduino 板子上,接著執行 Processing 程式 (Rect_Firmata.pde),然後你就會看到一個「背景為白色,視窗中有一個紅色的矩形」的視窗,如下:

image
▲ 旋轉可變電阻可以讓矩形水平移動

因為 Processing 程式裏有 println(sensorValue); 這一行指令,所以當你旋轉可變電阻時 Processing IDE 下方的狀態視窗也會即時顯示可變電阻的讀值:

image

動動腦

給 Processing 用的 Arduino-Firmata 函式庫中附有三個範例,請玩看看並寫下你的心得。

延伸閱讀

17 意見:

匿名 提到...

我可以用光敏電阻設定電視開關嗎?程式不是很行的說
謝謝你

Cooper Maa 提到...

設定電視開關? 咦? 這跟我這一篇文章有什麼關係嗎?
要控制電視,最簡單的方法是利用紅外線。

我有寫過一篇「用光敏電阻切換電視頻道」,參考看看,也許剛好是你想找的。http://coopermaa2nd.blogspot.com/2011/04/23.html

HANK 提到...

請問使用 StandardFirmata 上傳到Arduino上與Processing溝通,能否添加一些程式讓arduino可以自己有一些開關動作,因為我是想要
用開關控制LED然後用processing 也可以控制同一個LED,不好意思打擾你

Cooper Maa 提到...

「用開關控制LED然後用processing 也可以控制同一個LED」不太懂你這句話的意思。

你的意思是不是在 Arduino 上接個 Button 控制 LED,然後也希望可以用 Processing 在電腦上控制同一顆 LED?

HANK 提到...

恩恩是這樣沒錯

Cooper Maa 提到...

這樣的話,有兩個方法可以辦到,一個是修改 standardfirmata 把偵測 button 狀態的 code 加到 loop(),例如:

while(Firmata.available())
Firmata.processInput();

...
if (digitalRead(btnPin) == HIGH)
digitalWrite(ledPin, HIGH);
else
digitalWrite(ledPin, LOW);

第二個方法是不動 StandardFirmata,直接利用 Processing 來做:

void draw() {

...

if (arduino.digitalRead(btnPin) == Arduino.HIGH)
arduino.digitalWrite(ledPin, Arduino.HIGH);
else
arduino.digitalWrite(ledPin, Arduino.LOW);
}

應該是這樣吧,我想。

HANK 提到...

若是用Xbee溝通兩組arduino 的serial port,
還能夠用第二個方法嗎

Cooper Maa 提到...

可以的

Cooper Maa 提到...

對了,我有寫過兩篇 XBee 的筆記,你參考看看:

http://coopermaa2nd.blogspot.com/2011/08/arduino-and-xbee-series-2.html

http://coopermaa2nd.blogspot.com/2011/08/xbee-light-sensor.html

HANK 提到...

感謝你,不好意思在問一下,用serial port連接起arduino和processing後,再想要用Xbee溝通兩個不同arduino,似乎就出現問題,不太知道原因是甚麼,和如何解決

Cooper Maa 提到...

你 Coordinator 端是接在電腦對嗎?
我建議 Coordinator 這端不要用 Arduino+XBee,改用 XBee Explorer USB(http://www.sparkfun.com/products/8687) 會比較好。

另外,在用 XBee 通訊的時候,有一個要特別注意的事,就是 XBee 會有睡著的問題,如果通訊是持續的,也就是 XBee 一直在傳輸資料,是不會有問題,可是如果 XBee 不會一直傳輸資料,那麼只要ee 超過時間沒在通訊(我記得好像是 5 秒),XBee 自己就會跑去睡著,導致 Arduino 當掉。

小柯 提到...

C大請問一下範例的arduino = new Arduino(this, "COM4", 57600);這段我的com點是3 但我改掉之後他還是出現error:tried to access class processing.core.PApple$RegistereMethods form class cc.arduino.Arduino$SerialProxy
前面的涵式步驟也都有做了

Cooper Maa 提到...

不確定是哪裏的問題,不過有個老外也遇到同樣的問題:
http://arduino.cc/forum/index.php?topic=122177.0

有位網友上傳了一個修正版的 library,也許你可以試試:
https://github.com/pardo-bsso/processing-arduino

小柯 提到...

C大 我卡關了! 但是我做監控好像出了點問題@@
可能是我邏輯錯誤(我想要讀到0腳HIGH位時它變黑色則low時變灰色)照第二個方法是不是一定需要按鈕呢?

Arduino arduino;
int ledPin0 = 0;
void setup(){
size(400, 400);
background(100);
arduino = new Arduino(this, "COM3", 57600);}
void draw(){
if (arduino.digitalRead(ledPin0) == Arduino.HIGH){
fill(0);}
else if (arduino.digitalRead(ledPin0) == Arduino.LOW){
fill(126);}
else {
fill(126);}
ellipse(25, 25, 50, 50);}

Cooper Maa 提到...

我沒試過你的程式
不過,你用 ledPin0 會不會跟 RX 衝到?

小柯 提到...

我試著換過別隻腳位了! 可是一樣都沒變只會讀取到low...還是說我程式有問題ㄋ? C大我如果用第一個方法 在loop那加筆記二的PushButton的程式
可是在void setup() {
pinMode(ledPin, OUTPUT);
pinMode(buttonPin, INPUT);}這裡會顯示錯誤@@"

Cooper Maa 提到...

Arduino 的 code 要改一下才行,不能直接搬到 Processing:

arduino.pinMode(buttonPin, Arduino.INPUT);