INDEX(各項目ごとの目次)

[HOME]  [Processing関係]  [Arduino関係]  [マテリアル関係]  [秋葉原工作マップ]

2008年用ですが、部分的に内容を更新しています(2010/06/14)。
また、[建築農業工作ゼミ2009-2010]とも連動していますので、そちらにも幾つかサンプルがあります。
:

11/01/2008

Arduino Ethernet Shield

今回は、Arduino Ethernet Shieldスイッチサイエンスストロベリーリナックスにて販売)を使って、Arduinoをサーバとして機能させ、Webブラウザ(IE、Safari、FireFoxなど)から閲覧可能なページの表示実験を行いたいと思います。
そのために、Arduino開発環境の最新版「Arduino 0012」に含まれている「Ethernetライブラリ」を使います。
*Arduino MegaとEthernet Shieldを重ねて使う場合の説明はこちら


(Arduino Ethernet Shield)


Arduinoのサイトによれば、デジタルI/Oピンの11、12、13番ピンはSPI通信に使われているようなので、それらのピンにはセンサなどを接続しないことにします。


今回は、Arduino 0012に含まれている「Web Server」というサンプル(File>Sketchbook>Examples>Library-Ethernet>Web Server)を参考にブラウザで閲覧可能なWebベージを表示させます。元々のサンプルでは、アナログ入力値をWebページに表示させていますが、ブラウザのタイトルバーの表示文字、リンクさせた画像の表示など多少変更した内容にしてみます。
基本的な入力情報として、

・MACアドレス
・サーバのIPアドレス
・ポート番号

が必要となります。尚、ローカルネットワーク内から閲覧できる設定にします。

Arduinoのプログラム(サーバ):

//イーサネットライブラリを取り入れる
#include <Ethernet.h>

//MAC ID(各シールドに記載)
byte mac[] = { 0x00, 0x50, 0xC2, 0x97, 0x20, 0x11 };
//サーバ用IPアドレスの設定
byte ip[] = { 192, 168, 3, 100 };
//ポート設定(80:HTTPプロトコル)
Server server(80);

void setup(){
//イーサネット通信開始
Ethernet.begin(mac, ip);
//サーバ開始
server.begin();
}

void loop(){
//クライアントからのデータ受信
Client client = server.available();
//クライアントからの受信がある場合
if (client) {
//ブラウザからのHTTPリクエストの空白行の有無のフラグ
boolean current_line_is_blank = true;

//クライアントとの接続中の処理
while (client.connected()) {
//クライアントから受信データがあるとき
if (client.available()) {
//HTTPリクエスト(受信データ)を一つずつ読み込む
char c = client.read();
//HTTPリクエストにラインフィード(改行)があり、
//現在空白行である場合
if (c == '\n' && current_line_is_blank) {
//HTTPレスポンス(返信)
server.println("HTTP/1.1 200 OK");//リクエスト成功
server.println("Content-Type: text/html");//HTML文書形式
server.println();//空白行を入れる

//タイトルバー表示
server.println("<title>KOUSAKU WEB SITE</title>");
server.print("ANALOG INPUT: ");//文字表示
server.print(analogRead(0));//アナログ入力値
server.println("<br/>");//改行
//リンク画像表示
server.println("<img src=\"http://2.bp.blogspot.com/_7uyXRm_coS4/SQeoW-PJB2I/AAAAAAAAAbA/0Go85aRfLDY/s400/ethernet.png\">");
server.println("<br/>");//改行
//このブログへのリンク
server.println("<a href=\"http://kousaku-kousaku.blogspot.com\">GO TO: KOUSAKU BLOG PAGE<a>");
break;
}
if (c == '\n') {//読み込んだ文字がラインフィードの場合
//現在の行を空白行とみなす
current_line_is_blank = true;
} else if (c != '\r') {//読み込んだ文字がキャリッジリターン以外の場合
//現在の行を空白行としない
current_line_is_blank = false;
}
}
}
delay(1);
client.stop();
}
}


Arduino基板のアナログ入力0番端子に可変抵抗器をひとつ接続し、その読み取り値もページに表示されます。Arduinoのプログラム上では、MACアドレス、IPアドレス、ポート番号をそれぞれ設定しておき(説明以下)、クライアントのブラウザからの「HTTPリクエスト」(説明以下)を受け、「HTTPリクエスト」内の空白行を確認したら、「HTTPレスポンス」(説明以下)を返します。そのとき同時にHTML形式のページ表示内容データも送信されます。送信されたら、client.stop()で、クライアントとの接続を一旦停止します。再度、クライアントから「HTTPリクエスト」があれば、同様に処理されます。

「MACアドレス」:
MACアドレスは、Ethernet Shield固有のアドレスであり(ハードウェアごとに異なる)、スイッチサイエンスから購入したものであれば、Ethernet Shield裏面に貼られたシールに記載されている「00-50-C2-97-20-11」のような16進数の6つの数値です。これらの数値を16進数表記であたまに「0x」を付け加え記入しておきます。
もし、MACアドレスが不明の場合は、MacOSXなら「アプリケーション>ユーティリティ」内にある「ターミナル」を起動し、「ping -c 3 192.168.3.100」(IPアドレスは設定したものを入力してください)というように入力しリターンキーを押してください。その後、「arp -a」を入力しリターンキーを押すと、入力したIPアドレスの右横にMACアドレスが表示されます。
Windowsの場合、アクセサリ内の「コマンドプロンプト」を起動して、「ping 192.168.3.100」(「ping」の後に半角スペースを入れ、設定したEthernet ShieldのIPアドレスを入力)を入力しリターンキーを押すと、返答として「reply from...」などと数行表示されます。その後、すぐに「arp -a」を入力しリターンキーを押せば、Ethernet ShieldのIPアドレスの右横にMACアドレス(Physical Address)が表示されるはずです。

「IPアドレス」:
IPアドレスを設定するには、Ethernet Shieldに接続するイーサネットケーブルをコンピュータに接続し、まずイーサネット経由でのコンピュータのIPアドレスを調べてみます。IPアドレスが「192.168.3.xxx」であれば、最後の桁に任意の数値(他のIPアドレスと重ならないような数値)を入力すれば、大丈夫なはずです(今回の場合は「100」にしました)。同時に、ルータ(gateway)のIPアドレスも調べておくといいでしょう。この場合「192.168.3.1」(最後の桁が「1」)になっているはずです。
「ターミナル(MacOSX)」や「コマンドプロンプト(Windows)」で、MACアドレスを調べると(前述)、ルータのIPアドレスやMACアドレスも表示されるはずです。
尚、「Processing HTTPサーバ/Webページ表示」の冒頭でも、IPアドレスの調べ方について記載しているので参照して下さい。

「ポート」:
ポートは、通常のインターネットで使用している「80」に設定されています(プロトコル:HTTP用)。例えば任意のポート「12345」に設定する場合、ブラウザ上でIPアドレスを入力する際に「http://196.168.3.100:12345」というように「:12345」をIPアドレスの後ろに付け加えます。

「HTTPリクエスト」:

通常、ブラウザからURLを入力しページを表示させる場合、「GET / HTTP/1.1」(HTTPリクエスト)というサーバへの要求内容が送信されます。「GET /index.html HTTP/1.1」にすれば、サーバ上の「index.html」を指定して表示要求することもできます。
実際のブラウザ「Fire Fox 3.0.3」からサーバへ送信されるHTTPリクエストは、以下のような内容になっていました。

GET / HTTP/1.1 (リクエスト行)
Host: 192.168.3.100:12345 (メッセージヘッダ:以下の空白行手前まで)
User-Agent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.4; ja-JP-mac; rv:1.9.0.3) Gecko/2008092414 Firefox/3.0.3
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ja,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Cache-Control: max-age=0
(空白行)
(メッセージボディ:今回は特に何も送るデータは含まれていない)

「リクエスト行」では、サーバへの要求内容が書かれています。
「メッセージヘッダ」では、サポートされるデータ形式や言語などの様々な情報が記載されています。
「空白行」を挿入することで、要求内容の終わり部分を知らせます。
「メッセージボディ」は、サーバに入力情報などを送る際に使われます。
各行末には「\r\n」(CR+LFの改行コード)がついていました。


「HTTPレスポンス」:

サーバはブラウザからのHTTPリクエストを受け取って、「HTTP/1.1 200 OK」という受信確認した返事を返してきます。「200」はHTTPステータスコードと呼ばれ、「Not Found」(ページが見当たらない)の場合は「404」を返します。
「content-type:text/html」は、内容がHTML文書であるという形式について返答しています。
その後で、println()で空白行を送信します(CR+LF/キャリッジリターン+ラインフィードを送信)。
次に、HTMLなどのコンテンツを送ります。
つまり、以下のような内容になります。

HTTP/1.1 200 OK    (ステータス行)
content-type:text/html (メッセージヘッダー)
            (空白行:CR+LF)
<html>         (メッセージボディ)
<head>...</head>
<body>...</body>
</html>

コンテンツはHTML形式で、println()の括弧内に記述します。基本的に<>(タグ)で囲い、ブラウザのタイトルバーを表示させるために「<title>KOUSAKU WEB SITE</title>」としています。ひとつ問題になることは、println()の括弧内に「"..."」ダブルクオーテーションマークで文字列をくくらなければならないのですが、画像リンクやURLリンク先を記入する場合に「"」を文字列として扱いたい時、そのまま入力するとエラーになってしまうので、「"」を「\"」に置き換えて入力します(エスケープシーケンス)。そのため、「println("<img src="リンク先URL">")」(二重に「"」で括られてしまう)を「println("<img src=\"リンク先URL\">")」という表記にします。<br/>は、ブラウザ表示される際の改行です。

「ブラウザ上での閲覧」:
ポートを「80」に設定している場合、「http://192.168.3.100」(設定したIPアドレス)を入力しリターンキーを押せば、Arduino Ethernet Shieldからデータが送られ、ブラウザにコンテンツが表示されるはずです。
ポートを「12345」などの任意の番号にしている場合、「http://192.168.3.100:12345」というように、アドレスの最後に「:12345」(コロンとポート番号)をつけてアクセスして下さい。

「ローカルネットワーク外からのアクセス」:
外部からインターネットによってアクセスする場合は、グローバルIPアドレス、ルータ、ポートマッピングなどの設定が必要になります(「Processing-Arduino ネットワーク制御」の後半に、ポートマッピングなどの設定方法が書いてあるので参照してください)。
尚、LAN内の別のコンピュータからグローバルIPアドレスを使ってアクセスはできないので、実際にLAN外部からアクセスして見てください。

Arduinoイーサネット・シールド
スイッチサイエンス
売り上げランキング: 15483






2 件のコメント:

佐々木 達也 さんのコメント...

本家のフォーラムにも書いたのですが、

delay(1);//この一行を追加
client.stop();

と一行追加すると、Firefoxでアクセスした際のエラーが全く出なくなります。
delayがないと、serverがコネクションを早く閉じすぎるため、Firefoxがプロトコル違反を報告するようです。

kousaku さんのコメント...

佐々木さんへ
佐々木さんのおっしゃる通り、上記プログラムにdelay(1)を付け加えさせて頂きました。大変ありがとうございました。



[目次:Processing関係]  [HOMEへ戻る]  [目次:Arduino関係]