2014/04/13

Arduino Yún:Bridge程式庫入門(YunServer與YunClient)

這一篇玩玩Bridge程式庫裡的YunServer與YunClient這兩個類別,程式碼主要都來自於Arduino官方文件Guide to the Arduino Yún

我的Yún與開發主機位於同一個區域網路內,我的Arduino軟體開發環境是1.5.6-r2版。首先從瀏覽器登入Yún,開啟REST API存取權限為OPEN。

底下是範例程式碼,這支程式碼的功能是讓我們從別台電腦的瀏覽器控制Arduino的腳位。

#include <Bridge.h>
#include <YunServer.h>
#include <YunClient.h>

YunServer server; // 建立YunServer物件
void setup() {
  Serial.begin(19200);
  Bridge.begin(); // 啟動Bridge
  while(!Serial)
    ;
  server.listenOnLocalhost(); // 設定讓伺服器聆聽本地端IP位址的連線
  server.begin(); // 開始
}
void loop() {
  YunClient client = server.accept(); // 有連線進來了
  if(client){
    process(client); // 開始處理,分析API
    client.stop();
  }
  delay(50);
}
void process(YunClient client){
  String command = client.readStringUntil('/');
  if(command == "digital"){ // 數位輸入輸出
    digitalCommand(client);
  }
  else if(command == "analog"){ // 類比輸入輸出
    analogCommand(client);
  }
  else if(command == "mode"){ // 設定腳位模式
    modeCommand(client);
  }
}
void digitalCommand(YunClient client){
  int pin, value;
  pin = client.parseInt();
  if(client.read() == '/'){ // 數位輸出,設定為1(高電位)或0(低電位)
    value = client.parseInt();
    digitalWrite(pin, value);
    client.print("Pin ");
    client.print(pin);
    client.print(" set to ");
    client.println(value);
  }
  else{ // 數位輸入,讀取該腳位的值
    value = digitalRead(pin);
    client.print("Pin ");
    client.print(pin);
    client.print(" reads ");
    client.println(value);
  }
}
void analogCommand(YunClient client){
  int pin, value;
  pin = client.parseInt();
  if(client.read() == '/'){ // 類比輸出,設定PWM值為0~255
    value = client.parseInt();
    analogWrite(pin, value);
    client.print("Pin ");
    client.print(pin);
    client.print(" set to analog ");
    client.println(value);
  }
  else{ // 類比輸入,讀取該類比腳位的值
    value = analogRead(pin);
    client.print("Pin ");
    client.print(pin);
    client.print(" reads analog ");
    client.println(value);
  }
}
void modeCommand(YunClient client){
  int pin;
  pin = client.parseInt();
  if (client.read() != '/') {
    client.println("error");
    return;
  }
  String mode = client.readStringUntil('\r');
  if(mode == "input"){ // 設為輸入模式
    pinMode(pin, INPUT);
    client.print("Pin ");
    client.print(pin);
    client.print(" configured as INPUT.");
    return;
  }
  else if(mode == "output"){ // 設為輸出模式
    pinMode(pin, OUTPUT);
    client.print("Pin ");
    client.print(pin);
    client.print(" configured as OUTPUT.");
    return;
  }
  client.print("error: invalid mode ");
  client.print(mode);
}

然後從別台電腦的瀏覽器,輸入類似底下的網址,請把arduino.local換成你的Yún的IP位址。

把腳位13設為輸出模式:
http://arduino.local/arduino/mode/13/output
瀏覽器上會看到回應:
Pin 13 configured as OUTPUT.

把腳位13設為高電位,其連接的LED會亮起:
http://arduino.loca/arduino/digital/13/1
瀏覽器上會看到回應:
Pin 13 set to 1

把腳位13設為高電位,其連接的LED會熄滅:
http://arduino.loca/arduino/digital/13/0
瀏覽器上會看到回應:
Pin 13 set to 0

腳位3輸出PWM128:
http://arduino.loca/arduino/analog/3/128
瀏覽器上會看到回應: 
Pin 3 set to analog 128

讀取類比腳位A0(對應腳位編號18)的值:
http://arduino.loca/arduino/analog/18
瀏覽器上類似底下的回應:
Pin 18 reads analog 147

嗯,大概就這樣吧。


參考資料:

78 comments:

  1. 請問這是有加入網路裝置嗎?!

    ReplyDelete
    Replies
    1. 什麼網路裝置?
      此範例中的Yun跟瀏覽器端的電腦位於同一個區域網路內。

      Delete
  2. Anonymous21/5/14 17:04

    請問YunServer與YunClient這兩個類別,能不能只有指定的電腦或手機設備連接的方法?(比如說利用綁定mac或是ip的方法)

    ReplyDelete
    Replies
    1. 剛查了一下YunClient與YunServer提供的介面和原始碼,沒找到可以取得IP位址的方法。
      嗯,看起來Linux方的Bridge應該沒把相關資訊傳給Arduino方。

      目前不知道怎麼做,或許可以自己動手修改Linux那一端,不過難度很高,這部份官方也沒釋出什麼資料。

      Delete
    2. Anonymous21/5/14 17:54

      我有點不太了解在Yunclient函式庫中的connect()與connected(),是用來連接server端的設定嗎?

      Delete
    3. YunClient的connect是作為客戶端連接到網路上的某台伺服器,需傳入另一端的IP位址與連接埠(port)。
      connected則是回傳是否處於連線狀態中。

      Delete
    4. Anonymous23/5/14 15:36

      我想請問arduino yun的port能夠資源幾個功能?(比如基本開關控制+RFID+影像處理)一片開發板夠支援嗎?

      Delete
    5. 你說的都做得到吧。
      幾個功能?這怎麼計算。

      影像處理,通常會加另一塊擴充板由它負責。

      Delete
    6. Anonymous23/5/14 18:25

      因為還沒了解RFID那一部分,所以想了解,這些功能(開關控制+RFID+影像處理)都能同時在一個板子上實現這些功能(除了你說影像處理那一塊)?還有對於Linino那一塊基於OpenWRT的LAMP stack教學(如何架起php+mysql)

      Delete
    7. 應該都能同時在一個板子上實現這些功能,不知道你有什麼顧慮嗎?
      OpenWRT的LAMP stack教學,我沒試過,好像也沒有這方面的分享文;
      我個人覺得,這種作法不是Yun的本意,如果要直接架php+mysql+apache的話,應可改用beaglebone、raspberry pi、Intel的Galileo、等32位元的ARM板子。

      Delete
    8. Anonymous23/5/14 19:47

      因為之前想做關於網路方面的控制,看到這個實驗板有網路功能所以就買來試試看,好的,寫寫您的建議=)

      Delete
    9. 在firewall,裡面可以設定,類似ACL的存取控制。

      至於是要在外部的ip分享器或者路由器等裝置或者在yun本身os上都可以設定。

      Delete
  3. 錯誤訊息如右Could not connect to YunServer 146 Connection refused
    請問有遇過嗎?如何解?謝謝您!

    ReplyDelete
    Replies
    1. 沒遇見過。
      網路上沒太多資訊,你的程式碼是否有server.listenOnLocalhost();這一行,
      可拿掉試試看。

      Delete
  4. dear yehnan:
    你好有些問題想要請教你一下,
    就是我的yun版接上了一個小馬達(可以從0轉到180度)
    然後我手機端可以控制arduino去啟動馬達轉多少度(手機APP--->AP--->arduino---->馬達轉動)
    這邊都是在無線的環境下傳遞控制訊息
    但我不知道要怎麼讓目前轉到幾度的訊息回傳給手機端
    這部分可以給我一些建議嗎? 謝謝您!

    ReplyDelete
    Replies
    1. 目前轉到幾度?
      你要買有回饋轉動角度資訊的伺服馬達才辦得到吧。

      至於從yun傳送出去,就是這一篇的YunClient負責的功能吧,
      譬如client.print("Pin ");


      Delete
  5. 請問 我要如何透過網際網路去控制它?

    ReplyDelete
    Replies
    1. 使用YunServer吧,請參考這一篇http://yehnan.blogspot.tw/2014/04/arduino-yunbridgeyunserveryunclient.html

      Delete
  6. 您好,想請問一下我在輸入網址後也出現相同的問題
    Could not connect to YunServer 146 Connection refused
    也試過將server.listenOnLocalhost();這行拿掉,但還是行不通
    請問還有其他方法可以解決的嗎? 謝謝你!

    ReplyDelete
    Replies
    1. 更新韌體。
      把REST API設為OPEN。
      reset板子。
      試試看吧。

      Delete
    2. 好的 謝謝您 :D
      不好意思,想再請問一下
      目前我是使用筆電(網路來自於IP分享器,網路線插上就有網路的那種)
      當作WIFI基地台讓arduino Yun連線 , 請問這種連線方法是對的嗎?
      非常謝謝你!

      Delete
    3. 對的嗎?
      對還是不對,都是由你決定。

      Delete
    4. 好的!因為不確定連線的部分是否正確
      我會再試試看,謝謝您!

      Delete
    5. 呃,我有點誤會你的意思了。

      你這麼做感覺很複雜,感覺裡頭很多哩哩摳摳。
      何不直接使用網路線連接Yun跟IP分享器?

      Delete
  7. 你好!我現在利用arduino Yun溫度感測,
    才用xbee傳輸溫度感測數據到雲端
    請問這部分可以給我建議和方向嗎? 謝謝您

    ReplyDelete
  8. Anonymous3/6/15 16:23

    Remove while (!Serial) and then work well.

    ReplyDelete
  9. This comment has been removed by the author.

    ReplyDelete
  10. This comment has been removed by the author.

    ReplyDelete
  11. 不好意思想請問老師是否有人將yun 作為server然後使用processing溝通使用呢?
    我是參考processing範例
    https://processing.org/refer…/libraries/…/Client_write_.html
    但我只收得到arduino傳來的訊號但是傳不過去arduino yun
    不知道有沒有前輩們可以解惑?

    ReplyDelete
    Replies
    1. 你給的網址是錯的。
      你想要的,理論上都辦得到,但我沒做過。
      至於有沒有人做過,我也只能上網搜尋,跟你一樣。

      PS 有問題我會盡量回答,不知道我也會說不知道,多次留言並無效用。

      Delete
  12. 老師您好,請問如何能夠在"http://arduino.loca/arduino/digital/13/1"增加其他接腳讓其他燈亮呢?
    例如"http://arduino.loca/arduino/digital/13,12,11,10/1"學生試過但不可行,不知是否還有其他辦法呢?

    ReplyDelete
    Replies
    1. http://arduino.local/arduino/mode/12/output 把數位腳位12設為輸出模式,
      http://arduino.local/arduino/digital/12/1 把數位腳位12的輸出狀態設為1(也就是HIGH)。

      Delete
    2. 老師,不好意思。
      學生是希望能夠可能在網址上輸入12與11腳一起亮,或者10與13腳一起亮,
      但是如何在網址上呈現這個需求呢?(例如"http://arduino.loca/arduino/digital/13,12,11,10/1"但這學生試過是不行這樣),還是說只能單點腳位亮呢?

      Delete
    3. 這篇文章裡的程式碼,沒有你說的功能。
      請自行修改,大概要改void digitalCommand(YunClient client)。

      Delete
  13. 感謝老師協助!學生試著嘗試

    ReplyDelete
  14. 您好
    Could not connect to YunServer 146 Connection refused的問題
    我把setup()裡面的while(!Serial)拿掉就成功了
    請問這樣會發生什麼潛在問題嗎?
    謝謝

    ReplyDelete
    Replies
    1. 嗯,我也覺得很奇怪,while(!Serial);是等待Arduino IDE的serial monitor連線(透過usb線),照理說應該沒關係。
      但是有人拿掉後就成功了,可是我不必。

      > 潛在問題嗎?
      應該沒有。只不過看不到setup()裡吐出的訊息。

      Delete
  15. This comment has been removed by the author.

    ReplyDelete
  16. This comment has been removed by the author.

    ReplyDelete
  17. 葉大您好 請問 我想從網頁去讀取插在yun上的SD卡
    直接使用您的範例去修改 以下為程式碼

    #include
    #include
    #include
    #include

    YunServer server;

    void setup() {
    Bridge.begin();
    FileSystem.begin();
    server.listenOnLocalhost(); // 設定讓伺服器聆聽本地端IP位址的連線
    server.begin(); // 開始

    }

    void loop() {
    YunClient client = server.accept(); // 有連線進來了
    if(client){
    process(client); // 開始處理,分析API
    client.stop();
    }
    delay(50);



    }

    void process(YunClient client){
    String command = client.readStringUntil('/');
    if(command == "sid"){ // 數位輸入輸出
    sid(client);
    }

    }

    void sid(YunClient client){

    File dataFile = FileSystem.open("/mnt/sda1/test.txt", FILE_READ);
    if(dataFile){
    String result;
    client.println("opening test.txt");
    while(dataFile.available()) {
    char c = dataFile.read();
    if(c != '\n')
    result += c;
    }
    client.println(result);

    dataFile.close();
    }
    else{
    client.println("error opening test.txt");
    }

    delay(3000);

    }
    ----------------------------------------------------------------------------
    輸出的結果是一片空白 請問葉大哪邊有錯還是觀念上不對?

    ReplyDelete
  18. 最上面的include 分別為(FileIO.h) (Bridge.h) (YunServer.h) (YunClient.h)

    ReplyDelete
    Replies
    1. 葉大您好 我想將插在yun上的SD卡資料讀出 在網頁顯示
      可是出來的畫面是空白的 下面是我的程式碼
      請問那個地方錯誤?還是我有觀念上的不對?

      include
      include
      include
      include

      YunServer server;

      void setup() {
      Bridge.begin();
      FileSystem.begin();
      server.listenOnLocalhost(); // 設定讓伺服器聆聽本地端IP位址的連線
      server.begin(); // 開始

      }

      void loop() {
      YunClient client = server.accept(); // 有連線進來了
      if(client){
      process(client); // 開始處理,分析API
      client.stop();
      }
      delay(50);



      }

      void process(YunClient client){
      String command = client.readStringUntil('/');
      if(command == "sid"){ // 數位輸入輸出
      sid(client);
      }

      }

      void sid(YunClient client){

      File dataFile = FileSystem.open("/mnt/sda1/test.txt", FILE_READ);
      if(dataFile){
      String result;
      client.println("opening test.txt");
      while(dataFile.available()) {
      char c = dataFile.read();
      if(c != '\n')
      result += c;
      }
      client.println(result);

      dataFile.close();
      }
      else{
      client.println("error opening test.txt");
      }

      delay(5000);
      }

      Delete
    2. 葉大您好 我想將插在yun上的SD卡資料讀出 在網頁顯示
      可是出來的畫面是空白的 下面是我的程式碼
      請問那個地方錯誤?還是我有觀念上的不對?

      include
      include
      include
      include

      YunServer server;

      void setup() {
      Bridge.begin();
      FileSystem.begin();
      server.listenOnLocalhost(); // 設定讓伺服器聆聽本地端IP位址的連線
      server.begin(); // 開始

      }

      void loop() {
      YunClient client = server.accept(); // 有連線進來了
      if(client){
      process(client); // 開始處理,分析API
      client.stop();
      }
      delay(50);



      }

      void process(YunClient client){
      String command = client.readStringUntil('/');
      if(command == "sid"){ // 數位輸入輸出
      sid(client);
      }

      }

      void sid(YunClient client){

      File dataFile = FileSystem.open("/mnt/sda1/test.txt", FILE_READ);
      if(dataFile){
      String result;
      client.println("opening test.txt");
      while(dataFile.available()) {
      char c = dataFile.read();
      if(c != '\n')
      result += c;
      }
      client.println(result);

      dataFile.close();
      }
      else{
      client.println("error opening test.txt");
      }

      delay(5000);
      }

      Delete
    3. This comment has been removed by the author.

      Delete
    4. #include
      #include
      #include
      #include

      YunServer server;

      void setup() {
      Bridge.begin();
      FileSystem.begin();
      server.listenOnLocalhost(); // 設定讓伺服器聆聽本地端IP位址的連線
      server.begin(); // 開始

      }

      void loop() {
      YunClient client = server.accept(); // 有連線進來了
      if(client){
      process(client); // 開始處理,分析API
      client.stop();
      }
      delay(50);



      }

      void process(YunClient client){
      String command = client.readStringUntil('\r');
      if(command == "sid"){ // SD卡
      sid(client);
      }
      else if (command == "test"){ // test
      test(client);
      }

      }

      void sid(YunClient client){

      File dataFile = FileSystem.open("/mnt/sda1/test.txt", FILE_READ);
      if(dataFile){
      String result;
      client.println("opening test.txt");
      while(dataFile.available()) {
      char c = dataFile.read();
      if(c != '\n')
      result += c;
      }
      client.println(result);

      dataFile.close();
      }
      else{
      client.println("error opening test.txt");
      }

      delay(5000);
      }


      void test(YunClient client){
      client.print("TEST,1,2,3");

      }

      Delete
    5. > client.readStringUntil('\r');
      為什麼是 '\r' ?

      你輸入什麼網址給瀏覽器?

      Delete
    6. 輸入192.168.1.X/arduino/sid 出現一片空白
      但是192.168.1.X/arduino/test 就測試的那個可以看到畫面有TEST1 2 3

      如果使用 client.readStringUntil('/'); test這個網頁會沒有內容,空白的。

      Delete
    7. 既然如此,問題應該出在void sid(YunClient client)吧,
      何不在開頭先寫上 client.println("in sid"); 看看是否成功進入這支函式,

      你讀取檔案部分的程式碼,確認可正常運作嗎?

      Delete
  19. 找到問題了 出在最後的delay 我慢慢地一行一行插入client.println 去測 發現前面都很正常的可以印出 SD也可以讀出
    就出在delay 如果我設 delay4990 以上 網頁就會空白 以下就沒問題。不知道為什麼會這樣?


    抱歉昨天的網路怪怪 留言一直沒出現重複留了好幾次。

    ReplyDelete
    Replies
    1. 不是網路怪怪的,是Blogger系統把你的留言當做spam,我剛剛才知道並恢復。

      嗯,原來如此,因為print有緩衝區的機制吧,可能過太久,之前的資料就不見了。
      或者是http溝通雙方因逾時太久而斷線了。

      Delete
  20. 請問葉大 我有一個4~20mA輸出的設備,使用arduino+W5100,簡單的將設備數值顯示在網頁上,
    可是想從外網去看這個網頁是不是自己一定要有固定IP去NAT才有辦法看,
    還是有其他方式可以去看?
    假如使用樹莓派+arduino也是一樣需要固定IP嗎?

    ReplyDelete
    Replies
    1. 想上網,就要有公開IP。
      若你的設備在區域網路內,拿到的是私有IP,就要「設定」。

      如果你的公開IP會變,那從外網怎麼知道要連哪個IP呢?
      可以使用「動態DNS」,IP一變就更新,便能以同樣的網域名稱連線。

      Delete
  21. 不好意思這邊可以做其他問題的動作嗎?
    關於arduino yun
    請問 yun 裡面的linux 的介面上
    他核心的系統中 有 openwrt 與 linino
    這兩者有差異嗎?
    我知道 linino 是 openwrt 下的一個系統而已

    第二個問題是
    我想運用yun內的linux部份去讀取ez100晶片卡的資料
    但是在安裝相關套件的時候頻頻出問題
    他update 後 可以安裝,pcscd 但是主要套件如pcsc-lite 跟pcsc-tools這些都無法在資料庫中找到(Unknown package 'pcsc-tools'.)這樣使得我不知道如何才能讓他去達到我要的功能。

    ReplyDelete
    Replies
    1. OpenWrt-Yun是arduino.cc的,linino是arduino.org的。

      ez100是個裝置,需要驅動程式與相關程式庫與工具,如果沒有的話,那就不能用。
      不過在這https://github.com/arduino/linino/tree/master/packages/utils/pcsc-lite/files有看到,或許要自己想辦法弄出來吧。我不清楚。

      寫信給arduino.org,詢問,或是請他們準備該套件。

      Delete
  22. 老師你好,在同樣的無線網路中,如何使兩台Arduino 互相傳遞資料呢?

    ReplyDelete
    Replies
    1. 一台作為伺服器,使用YunServer,
      另一台作為客戶端,使用YunClient,
      以此作法而言,由客戶端發起連線。
      範例請參考
      https://www.arduino.cc/en/Tutorial/TemperatureWebPanel

      https://www.arduino.cc/en/Tutorial/HttpClient

      Delete
    2. This comment has been removed by the author.

      Delete
    3. 老師我還是不太了解Yunaever and Yunclient的使用方式 範例 https://www.arduino.cc/en/Tutorial/HttpClient 我試過了
      但好像沒有兩台互傳的感覺?

      Delete
    4. 嗯,那看看這篇最後的程式碼吧
      http://forum.arduino.cc/index.php?PHPSESSID=sh8oc448lt4tffivf0ooiqp5u7&topic=236467.0

      Delete
    5. This comment has been removed by the author.

      Delete
    6. 我試了最後的程式碼,發現在sever端的序列阜監控視窗持續跑出42的數字,這是因為client有與sever互相傳遞嗎?

      Delete
    7. 沒有互相傳遞,
      只有client端不斷送出42給server。

      Delete
    8. 老師您好,我想了解程式的內容,想請你幫我描述一下! void loop 迴圈的意思

      #include
      #include
      #include
      YunServer server;
      void setup() {
      Bridge.begin(); 開始建立Bridge物件
      server.begin(); 開始建立server物件
      Console.begin(); 開始建立console物件

      void loop() {
      YunClient client = server.accept();
      if(client){
      while(client.available()<1);
      Console.println(client.read()); // this should print out 42[/color]
      client.stop();
      }
      }

      Delete
    9. 請找本C語言入門書,自行研習。

      Delete
    10. This comment has been removed by the author.

      Delete
    11. 請問client.available()<1 為甚麼後面會有 <1 呢?

      Delete
    12. 反問client.available()的回傳值代表什麼意思?

      Delete
    13. Anonymous25/8/16 11:28

      通過連接到Server寫入到Client端的數據量

      Delete
    14. 那麼,< 1就代表數據量小於1。
      一般來說應只有0與大於0兩種可能,所以小於1就代表0,也就是沒有數據。

      Delete
  23. Anonymous8/8/16 18:32

    老師你好,
    請問我可以用YUN來控制XBee嗎?
    就是用APP透過WEB來控制YUN,
    YUN再透過無線傳輸控制遠端的Device.
    這樣的方法是可行的嗎?
    謝謝

    ReplyDelete
  24. Anonymous11/8/16 14:21

    老師您好:我想請問arduino yun 跟 iduino yun shield 相同嗎?此程式碼可以用在iduino yun shield嗎?

    ReplyDelete
    Replies
    1. Basically, Yun Shield + Leonardo equally to the official Arduino Yun.

      根據規格,yun shield就是yun板拔掉微控制器那一塊,作用是可插入其他arduino板子,加上yun的功能。

      所以你的問題的答案是: 可以。

      Delete
    2. Anonymous11/8/16 14:58

      不是Yun Shield + Leonardo而是Yun Shield + Arduino Uno R3可以嗎?
      我燒入此程式 網頁會顯示Could not connect to YunServer 146 Connection refused 更設定該拿掉的地方也有試過,但試都不行呢!想請問老師還有什麼方法可以嘗試?

      Delete
  25. Anonymous11/8/16 15:15

    老師您好:我使用的是arduino Uno R3不是Leonardo會有影響嗎?
    程式燒入之後 出現Could not connect to YunServer 146 Connection refused
    setup()裡面的while(!Serial)拿掉不行
    拿掉server.listenOnLocalhost();也不行
    韌體也從dragino2-yun-geeetech-v2.0.2更新到dragino2-yun-common-v2.0.7
    把REST API設為OPEN也不行呢
    想請問老師還有什麼方式可以處理這個問題嗎?

    ReplyDelete
  26. Anonymous11/8/16 15:23

    老師您好:我使用的是arduino Uno R3不是Leonardo會有影響嗎?
    程式燒入之後 出現Could not connect to YunServer 146 Connection refused
    setup()裡面的while(!Serial)拿掉不行
    拿掉server.listenOnLocalhost();也不行
    韌體也從dragino2-yun-geeetech-v2.0.2更新到dragino2-yun-common-v2.0.7
    把REST API設為OPEN也不行呢
    想請問老師還有什麼方式可以處理這個問題嗎?

    ReplyDelete
  27. Anonymous11/8/16 15:25

    老師您好:我使用的是arduino Uno R3不是Leonardo會有影響嗎?
    程式燒入之後 出現Could not connect to YunServer 146 Connection refused
    setup()裡面的while(!Serial)拿掉不行
    拿掉server.listenOnLocalhost();也不行
    韌體也從dragino2-yun-geeetech-v2.0.2更新到dragino2-yun-common-v2.0.7
    把REST API設為OPEN也不行呢
    想請問老師還有什麼方式可以處理這個問題嗎?

    ReplyDelete