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 意見:

aoaodi 提到...

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

coopermaa 提到...

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

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

HANK 提到...

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

coopermaa 提到...

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

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

HANK 提到...

恩恩是這樣沒錯

coopermaa 提到...

這樣的話,有兩個方法可以辦到,一個是修改 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,
還能夠用第二個方法嗎

coopermaa 提到...

可以的

coopermaa 提到...

對了,我有寫過兩篇 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,似乎就出現問題,不太知道原因是甚麼,和如何解決

coopermaa 提到...

你 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);