Arduino Ethernetシールド(旧製品)を使ってみました。Arduinoと接続した状態が以下です。おそらく2~3年前ぐらいに買ったものだと思います。どうも自宅以外で有線LANが気軽に使える場所もあまりないかなといった理由で使わなかったと思います。もう既に、Arduino イーサネットシールド2という製品も販売されていますので購入される場合はご注意下さい。
用途としてはもちろん、Ethernetシールドなので有線LAN経由でインターネットに接続して通信が出来ます。プログラミングとしてはライブラリがあるのでそのライブラリを利用すればネットワークプログラムが記述出来ます。
プログラムの前にTCP/IPについて
TCP/IPとはですが、以下から引用させて頂きました。ありがとうございます。
TCP/IP – インターネット用語辞典 –
TCP/IPとは、機種やOSの違いに関係なく、どんなコンピュータでもネットワークに参加させることができる通信プロトコル(通信規約)のこと。 TCP/IPとは、機種やOSの違いに関係なく、どんなコンピュータでもネットワークに参加させることができる、インターネットで標準的に使われている通信プロトコル(通信規約)のことです。 この通信プロトコルに従うことで、機器間での物理形態やOSが異なっていても相互に通信を行うことが可能になります。 TCP/IPのTCPとは、転送制御プロトコル(Transmission Control Protocol)の略で、通信が失敗した時に再送信を試みて回復に努めたり、データを順番に届ける役割を果たします。
要するにインターネットの通信プロトコル(通信規約)のことです。今回のEthernetシールドもこのTCP/IPで通信を行います。大きな特徴として、他の類似の通信プロトコル(osi参照モデルとよく比較されます)と同様に「階層構造」になっていることです。TCP/IPの階層構造は以下です。
アプリケーション層 – アプリケーションプロトコル(HTTP、FTP、SMTP等)
トランスポート層 – プログラム間通信、制御(TCP、UDP等)
ネットワーク層 – ネットワーク層(IP4、IP6等)
リンク層 – Ethernet、Wifi等
階層の構成としては下位の階層が上位へ機能を提供するということと、上位の方がよりユーザに近いということです。階層を提供するということは、上位からすれば下位の構成に関係なく上位の機能を利用することが出来るということです。例えば、パソコンで電子メールを送受信するということを考えると有線LANの接続であろうが、Wifiでの接続であろうがメーラを利用してメールを送受信する動作は変わりません。
比較的基本的なことを書きましたが、書いた理由としては、今回のArduino Ethernetシールドでのプログラミングでは、この階層構造がよく見えるかなと思ったからです。Windows等でのOS上でのプログラミングでは特に最近ではより上位層でのプログラミングが出来ると思います。もちろんそれは便利なことですがわざわざTCP/IPのことは意識しないです。それであれば、今回のArduino Ethernetシールドのサンプルスケッチで少しでもTCP/IP(の階層)を意識しようかと思ったというこです。
サンプルプログラムの実行
ほぼサンプルプログラムのままですが、より単純にシンプルなサイトにHTTPのGETで通信してレスポンスを表示するというプログラムです。http://www.example.comというURLにアクセスしています。普通にPCのブラウザで表示すると以下のような表示になります。
以下がこのように表示されるレスポンスを取得するプログラム(Arduinoではスケッチですね。)です。元がWeb clientというサンプルスケッチでコメントはほぼそのままです。
/* Web client This sketch connects to a website (http://www.google.com) using an Arduino Wiznet Ethernet shield. Circuit: * Ethernet shield attached to pins 10, 11, 12, 13 created 18 Dec 2009 by David A. Mellis modified 9 Apr 2012 by Tom Igoe, based on work by Adrian McEwen */ #include <SPI.h> #include <Ethernet.h> // Enter a MAC address for your controller below. // Newer Ethernet shields have a MAC address printed on a sticker on the shield byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0xA4, 0xC6 }; //ここでの接続先 char server[] = "www.example.com"; // Set the static IP address to use if the DHCP fails to assign IPAddress ip(192, 52, 109, 83); //固定IPアドレス // Initialize the Ethernet client library // with the IP address and port of the server // that you want to connect to (port 80 is default for HTTP): EthernetClient client; void setup() { // Open serial communications and wait for port to open: Serial.begin(19200); while (!Serial) { ; // wait for serial port to connect. Needed for Leonardo only } // start the Ethernet connection: if (Ethernet.begin(mac) == 0) { Serial.println("Failed to configure Ethernet using DHCP"); // no point in carrying on, so do nothing forevermore: // try to congifure using IP address instead of DHCP: Ethernet.begin(mac, ip); return; } //IPアドレスの情報 Serial.print("IP Address: "); Serial.println(Ethernet.localIP()); Serial.print("Subnet Mask: "); Serial.println(Ethernet.subnetMask()); Serial.print("Gateway IP Address: "); Serial.println(Ethernet.gatewayIP()); Serial.print("DNS Server Address: "); Serial.println(Ethernet.dnsServerIP()); Serial.println(); // give the Ethernet shield a second to initialize: delay(1000); Serial.println("connecting..."); // if you get a connection, report back via serial: if (client.connect(server, 80)) { Serial.println("connected"); // Make a HTTP request: //client.println("GET /search?q=arduino HTTP/1.1"); client.println("GET /index.html HTTP/1.1"); client.println("Host: www.example.com"); client.println("Connection: close"); client.println(); } else { // kf you didn't get a connection to the server: Serial.println("connection failed"); } } void loop() { // if there are incoming bytes available // from the server, read them and print them: if (client.available()) { char c = client.read(); Serial.print(c); } // if the server's disconnected, stop the client: if (!client.connected()) { Serial.println(); Serial.println("disconnecting."); client.stop(); // do nothing forevermore: while (true); } }
これを実行すると以下のようにシリアルモニタで確認出来ました。
全文は以下です。
IP Address: 192.52.109.203 Subnet Mask: 255.255.255.0 Gateway IP Address: 192.52.109.54 DNS Server Address: 192.52.109.54 connecting... connected HTTP/1.1 200 OK Accept-Ranges: bytes Cache-Control: max-age=604800 Content-Type: text/html Date: Tue, 28 Jul 2015 03:56:24 GMT Etag: "359670651" Expires: Tue, 04 Aug 2015 03:56:24 GMT Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT Server: ECS (cpm/F9B2) X-Cache: HIT x-ec-custom-error: 1 Content-Length: 1270 Connection: close <!doctype html> <html> <head> <title>Example Domain</title> <meta charset="utf-8" /> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <style type="text/css"> body { background-color: #f0f0f2; margin: 0; padding: 0; font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; } div { width: 600px; margin: 5em auto; padding: 50px; background-color: #fff; border-radius: 1em; } a:link, a:visited { color: #38488f; text-decoration: none; } @media (max-width: 700px) { body { background-color: #fff; } div { width: auto; margin: 0 auto; border-radius: 0; padding: 1em; } } </style> </head> <body> <div> <h1>Example Domain</h1> <p>This domain is established to be used for illustrative examples in documents. You may use this domain in examples without prior coordination or asking for permission.</p> <p><a href="http://www.iana.org/domains/example">More information...</a></p> </div> </body> </html> disconnecting.
IPアドレスの情報とHTTPのレスポンス、それから処理経過を表示しています。
TCP/IPの各層の確認
上記の実行結果とスケッチとをTCP/IPの各層を2階層ずつに分けて、下位層、上位層と位置付けて、それぞれ対比して確認したいと思います。
下位層(リンク層とネットワーク層)
まず、MACアドレス(Media Access Control address)を指定して、Ethernet.begin()でEthernet接続を開始しています。MACアドレスはEthernetシールドの裏側に1台ごとに付与されています。これでDHCPが有効であれば、IPアドレスが割り当てられて、DHCPが有効でなければ指定したIPアドレスでEthernet接続を開始しようとします。
私の実行結果では、”Failed to configure Ethernet using DHCP”が表示されていないのでDHCPが有効で(IP4の)IPアドレスが割り当てられた状態になりました。これで下位層まで確立出来たから「上位層で通信出来ますよ」の状態と考えていいでしょうか。
実行結果では、以下のようにIPアドレス関連が表示されました。
IP Address: 192.52.109.203
Subnet Mask: 255.255.255.0
Gateway IP Address: 192.52.109.54
DNS Server Address: 192.52.109.54
上位層(トランスポート層とアプリケーション層)
それでは、この「上位層で通信出来ますよ」の状態でスケッチ上で実際に通信するのは、EthernetClient client です。これは、TCP(Transmission Control Protocol)通信(トランスポート層)のクラスで信頼性の高いコネクション型の通信方法です。大きな流れは以下のようになると思います。
client.connect(server, 80) コネクション確立
client.println() 必要に応じて、送信と受信の処理
client.read()
client.stop() クライアント終了
最後にそのTCP通信で何をやりとりしているかというのが、最上位のアプリケーション層ですが、ここではHTTPというアプリケーションプロトコルに従って通信しています。以下のあたりの送信している内容がHTTPです。
client.println(“GET /index.html HTTP/1.1”);
client.println(“Host: www.example.com”);
client.println(“Connection: close”);
これで、client.read()でindex.htmlのドキュメント(テキスト)を受信して表示しています。以上、サンプルスケッチをTCP/IPの各層と合わせて確認しました。
※TCP/IPのより詳細が必要な場合は他のサイトや関連する書籍等を参照して頂ければと思います。
その他のサンプルスケッチ
もう一つだけですが、試したサンプルスケッチについてです。WebServerというサンプルスケッチですが、これは私はArduinoらしいと思いました。どういう処理かというと、Analog入力の値をHTTPのレスポンスとして返す処理です。Analog入力の値をネットワーク経由で確認出来るということです。
特にそのまま実行しただけなので、実行結果だけ表示します。但し、Analogに何も接続していないので不定値が表示されただけです。
以上、とりあえずArduino Ethernetシールドを使ってみたというところですが、また何か出来たら書きたいと思います。
Amazon関連商品