Wi-Fi通信機能付きの「ラズパイ(Raspberry Pi)Pico W」が「技適(技術基準適合証明)」が取得され日本で正式に販売されました。
Wi-Fiが使えるようになったら、やっぱり遠隔操作&表示をしたい!
ということで「M5Stack」系のデバイスで何度もやってますが、だいぶシンプルにできるようになってきたので「ラズパイPico W」で試してみました。
ブラウザで表示させる「html」は苦手ですが最近では「ChatGPT」が作ってくれるので楽になりました。作ってもらった「html」をコピペで「ラズパイPico W」に文字列として埋め込むだけなのでこの方法も詳しく紹介します。
「MicroPython」や「CircuitPython」を使用した「PicoW」のWi-Fi通信の使い方も、以下のリンクで詳しく紹介しています。
「ラズパイPico W」の基本仕様、開発環境については以下のリンクで詳しく紹介しています。
1.ラズパイPico Wとは
2.動作紹介
3.サンプルプログラム(コピペ)
4.プログラムの詳細
・Wi-Fi設定
・サーバー設定
・ブラウザ表示ページ(html)の埋め込み
・メイン処理
5.ChatGPTが書いたhtmlで動作確認
6.まとめ
1.ラズパイPico Wとは
「Raspberry Pi PicoW」とは、イギリスを拠点とする慈善団体によって若者のプログラミング学習を目的に開発されたもので、他の「Raspberry Piシリーズ」とは異なり、OSの機能はありませんが、電源投入ですぐに使用でき、スイッチやLEDランプ、モーター、各種センサー、通信機器を接続して、それらを制御するプログラムを簡単に作成して動作確認できるため、組み込み(制御)系プログラミングの学習に最適です。
「Pico W」にはWi-Fi機能があり、Wi-Fi通信を利用したインターネット経由のデータ収集や遠隔操作等のアイデアを簡単に試すことができます。
端子配列は下画像のようになります(公式サイトより抜粋)
2.動作紹介
今回制作したものの動作については以下のようになります。
「ラズパイPico W」の電源を入れると本体のLED(緑)が点灯し、ArduinoIDE等のシリアルモニタで確認したIPアドレスをスマホやパソコンのアドレスバーに入力すると、下画像のような画面が表示されます。
この画面から本体LEDのON/OFFと同時に、出力端子(GP0)のON/OFFができるようにしています。
また、基板本体の温度を取得して画面上に1秒ごとに更新して表示させています。
プログラムは下の方に「サンプルプログラム」を準備していますので、ArduinoIDE等にコピペで貼り付けて書き込みます。
ArduinoIDEのインストール方法や使い方は以下のリンクで詳しく紹介しています。
以下が開発環境「ArduinoIDE」の画面です。
書き込んだら、シリアルモニタで「IPアドレス」の確認を行いますが「ArduinoIDE」の場合は上画像右上の[シリアルプロッタ]をクリックすると下画像のようにシリアルモニタが表示されます。
「ラズパイPico W」の電源を入れ直すと、下画像のように上から順にWi-Fi接続先の「SSID」と「IPアドレス」が表示されます。
ブラウザの検索窓に「IPアドレス(192.168.0.25)」を入力すると操作画面が表示されシリアルモニタに「200, Root Access!」が表示されます。
操作画面が表示されると1秒ごとに「ラズパイPico W」本体の温度が取得され、ブラウザ上に表示されます。同時にシリアルモニタにも表示されます。
操作画面の「ON/OFF」ボタンを押すと「ラズパイPico W」本体のLEDがON/OFFできます。
同時に出力端子(GP0)もON/OFFさせています。
シリアルモニタにも「200, ON!/200, OFF!」が表示されます。
「ラズパイPico W」本体のLEDのON/OFFと同時にON/OFFしている出力端子(GP0)の動作確認は以下のように行いました。
「ラズパイPico W」本体にピンヘッダーを実装してあればブレッドボードを使用すればいいのですが、端子番号が基板裏に表示されていることもあって意外と不便です。
こんな時は下画像のように、テストクリップを使用してLEDを付けると簡単に確認できます。
基板のスルーホールを挟み込むように取り付けられるので、基板裏の端子番号を見ながら接続できて、自由度もあり、抜けることもないので便利です。
下画像では出力端子(GP0)にLEDの+、GNDにLEDのーを接続しています。
以下のテストクリップは反対側のピンがメスだけでなくオスピンのものもセットになっており、ブレッドボドに差し込むことができて便利です。
今回のプログラムについては、サーバーの動作について知っておくと理解が早いです。
サーバーについては以下のリンクで詳しく紹介しています。
3.サンプルプログラム(コピペ)
サンプルプログラムは以下のようになります。コピペで貼り付けて書き込んでください。
※下コード(黒枠)内の右上角にある小さなアイコンのクリックでコピーできます。
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
// サーバー設定ポート80で接続
WebServer server(80);
// 入出力ピン番号設定
#define OUTPUT_PIN0 0 //出力ピン
// WiFi SSID パスワード設定(自分の環境に合わせて設定)
const char* ssid = "Wi-Fi接続先SSIDを記入";
const char* password = "Wi-F-パスワードを記入";
// 変数宣言
float data;
// htmlデータを文字列に格納 ※R"(ここに書いた文字列は改行を無視して1行の文字列として扱える)"
String html = R"(
<!DOCTYPE html><html lang="jp"><head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>REMOTE-CONTROLLER</title>
<style>
body{font-family: sans-serif; background-color: #fff; max-width: 480px; margin: 0 auto; align-items: center;}
h1 {color:#333; text-align: center; font-size: 28px; margin: 10px auto;}
div {display: flex; flex-direction: row; justify-content: center;}
.btn {height: 70px; width: 100px; color: rgb(44, 43, 43); background-color: #dddde9; font-size: 18px; font-weight: bold; border-radius: 7%; margin: 0 10px; -webkit-appearance: none;}
td {width: 110px; color:#333; text-align: center; font-size: 18px;}
</style></head><body>
<h1>REMOTE-CONTROLLER</h1>
<div>
<button class="btn" id="btn0" onclick="getBtnOn(0) ">ON</button>
<button class="btn" id="btn1" onclick="getBtnOn(1) ">OFF</button>
</div>
<div style = "margin-top: 20px;">
<table border = "1">
<tr><td>本体温度</td><td><p id="output"></p></td></tr>
</table>
</div>
</body>
<script type="text/javascript">
// ON/OFFボタン操作処理
async function getBtnOn(i) {
let link;
switch (i) {
case 0: link = "/get/btn_on"; break;
case 1: link = "/get/btn_off"; break;
}
try {
const response = await fetch(link);
if (response.ok) {
const text = await response.text();
console.log(text);
}
} catch (error) { console.log(error); }
}
// データ取得、output表示更新
async function updateOutput() {
const output = document.getElementById("output");
try {
const response = await fetch("/get/data");
if (response.ok) {
output.textContent = await response.text();
} else { throw new Error(); }
} catch (error) { console.log(error); }
}
setInterval(updateOutput, 1000);
</script></html>
)";
// 関数 ------------------------------------------------------------
/********* クライアントにWebページ(HTML)を返す関数 *********/
void handleRoot() {
server.send(200, "text/html", html); //レスポンス200を返し、htmlデータ送信
Serial.println("200, Root Access!");
}
/********** クライアントにエラーメッセージを返す関数 **********/
void handleNotFound() { //ファイルが見つかりません
server.send(404, "text/plain", "File not found!");
Serial.println("404, File not found!");
}
/********** ブラウザボタンON/OFF、温度データのレスポンスを返す関数 **********/
// ブラウザボタンON
void BtnOn() {
digitalWrite(LED_BUILTIN, HIGH); // 本体LED ON
digitalWrite(OUTPUT_PIN0, HIGH); // GPIO0 HIGH
server.send(200, "text/html", "ON!"); // レスポンス200を返し、ON!を送信
Serial.println("200, ON!");
}
// ブラウザボタンOFF
void BtnOff() {
digitalWrite(LED_BUILTIN, LOW); // 本体LED OFF
digitalWrite(OUTPUT_PIN0, LOW); // GPIO0 LOW
server.send(200, "text/html", "OFF!"); // レスポンス200を返し、OFF!を送信
Serial.println("200, OFF!");
}
// ブラウザデータ表示更新
void getData() {
char buf[10]; // data文字列格納バッファ
sprintf(buf, "%.1f℃", data); // dataの値を文字列として格納
server.send(200, "text/html", buf); // レスポンス200を返し、dataを文字列で送信
Serial.printf("Temp: %.1f'C\n", data);
}
/********************* Webサーバー設定 ********************/
void serverSetting() {
server.on("/", handleRoot); // ルートアクセス時の応答関数を設定
server.onNotFound(handleNotFound); // 不正アクセス時の応答関数を設定
server.on("/get/btn_on", BtnOn); // ボタンON受信処理
server.on("/get/btn_off", BtnOff); // ボタンOFF受信処理
server.on("/get/data", getData); // データ表示更新受信処理
server.begin(); // Webサーバー開始
}
// 初期設定 ------------------------------------------------
void setup() {
// WiFi接続開始
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { //接続完了してなければ
delay(500);
Serial.print(".");
}
Serial.print("\nSSID: "); // SSID表示
Serial.println(WiFi.SSID());
Serial.print("IP: "); // IPアドレス表示
Serial.println(WiFi.localIP());
// サーバー設定
serverSetting();
// 出力端子設定
pinMode(LED_BUILTIN, OUTPUT); // 本体LEDは「LED_BUILTIN」で指定(ピン番号だと32で指定)
digitalWrite(LED_BUILTIN, HIGH); // 本体LED ON
pinMode(OUTPUT_PIN0, OUTPUT); // LED GP0を出力端子に設定(LEDのWL_GPIO0とは別物)
}
// メイン --------------------------------------------------
void loop() {
server.handleClient(); //クライアントからのアクセス処理
data = analogReadTemp(); // 本体温度データ取得
delay(100);
}
4.プログラムの詳細
プログラムの詳細について、サンプルプログラムから抜粋して紹介します。
・Wi-Fi設定
まず、「11,12行目」で「SSID」と「パスワード」をご自身のネットワーク環境(ワイヤレスLAN設定)に合わせて設定してから書き込んでください。
・サーバー設定
サーバー設定は「7行目」でポート「80(標準なので入力不要)」として設定します。
ポート番号を変更する場合は「81」のようにして「IPアドレス:81」のようにブラウザから指定します。
「102〜110行目」で「IPアドレス」を入力したときの「ルートアクセス」時に呼び出す関数や、「IPアドレス」に続けて「/get/btn_on」等でアクセスした時のボタンON/OFFや、本体温度を1秒ごとに取得する「/get/data」にアクセスがあった時に呼び出す関数を指定します。
これで、それぞれのアドレスにアクセスがあったときに設定した関数が実行されるようになります。
・ブラウザ表示ページ(html)の埋め込み
ブラウザで表示させる「html(CSS、JavaScript)」は文字列として埋め込みます。
文字列として埋め込むには通常「”」を「\”」のようにエスケープ文字で処理しますが、以下のように指定することで、作成したhtmlのページを改行も無視して1行の文字列として、そのまま貼り付けられるため便利です。
String html = R"(
ここにコピペで貼り付ける
)"
メイン処理
メイン処理はシンプルです。「132行目」のように「server.handleClient()」を書いておくことで、ブラウザからのアクセスを常に待ち受けて処理することができます。
「133行目」のように「analogReadTemp()」で温度を取得することができるため常時温度を取得しています。
5.ChatGPTが書いたhtmlで動作確認
動作確認用ブラウザページの「html、JavaScript、CSS」は私は苦手なので毎回苦労しますが、今は「ChatGPT」に聞けば全部書いてくれて、コピペで貼り付けるだけなので便利になりました。
今回使用したサンプルプログラムは、いつも動作確認に使用しているもので自分で作りましたが、同じ動作をするものを「ChatGPT」に書いてもらうとどうなるか確認してみました。
「ChatGPT」への質問は以下のようにしました。
回答は以下のようになりました。
<!DOCTYPE html>
<html>
<head>
<title>ON/OFF Button</title>
<style>
#container {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
margin-top: 50px;
}
.button {
width: 100px;
height: 50px;
border-radius: 5px;
margin: 10px;
cursor: pointer;
font-size: 20px;
font-weight: bold;
color: white;
text-align: center;
line-height: 50px;
}
#on-button {
background-color: green;
}
#off-button {
background-color: red;
}
input[type="text"] {
width: 200px;
padding: 5px;
font-size: 20px;
text-align: center;
margin: 20px;
}
</style>
</head>
<body>
<div id="container">
<div>
<button id="on-button" class="button">ON</button>
<button id="off-button" class="button">OFF</button>
</div>
<input type="text" placeholder="Temperature" />
</div>
<script>
const onButton = document.getElementById("on-button");
const offButton = document.getElementById("off-button");
const textBox = document.querySelector("input[type='text']");
onButton.addEventListener("click", async () => {
const response = await fetch("/get/btn_on");
const text = await response.text();
console.log(text);
});
offButton.addEventListener("click", async () => {
const response = await fetch("/get/btn_off");
const text = await response.text();
console.log(text);
});
setInterval(async () => {
const response = await fetch("/get/data");
const text = await response.text();
textBox.value = text;
}, 1000);
</script>
</body>
</html>
「ChatGPT」が書いてくれたコードを、サンプルプログラムの「17〜66行目」と置き換えて書き込んで「Pico W」の「IPアドレス」にアクセスすると下画像のようなページが表示されます。
「温度表示」の項目がないですが「ON/OFFボタン」を押すと「PicoW」本体のLEDが点灯/消灯するのが確認でき、温度も更新して表示されることが確認できました。
6.まとめ
Wi-Fi通信機能付きの「ラズパイ(Raspberry Pi)Pico W」で遠隔操作&表示をする方法を詳しく紹介しました。
「PicoW」をサーバーとして設定することで「html」コードを埋め込んで、パソコンやスマホのブラウザからアクセスすることで遠隔操作やデータ表示を簡単に行うことができます。
「ラズパイ」といえば「python」を使用するイメージですが「C言語」でもArduinoのコマンドを使用することで比較的簡単に制御することができます。
ブラウザで表示させる「html」は、私は苦手ですが「ChatGPT」に聞けば作ってくれるので楽になりました。
正しいコードを書いてもらうには質問の仕方が大切なので「html」や「javascript」の使い方を知っておくことは必要になります。
C言語を使用したArduinoのコードも「ChatGPT」が書いてくれると楽なのですが、使用するデバイスによって異なる端子等の情報は持っていないので逆に時間がかかることがあり、参考程度に使用しています。
個人的には「python」を使う機会はあまりないですが「PicoW」が使えるようになったので「ChatGPT」を活用しながら「python」を使用した遠隔操作や他のプログラムも紹介していければと思います。
「MicroPython」や「CircuitPython」を使用した「PicoW」のWi-Fi通信の使い方も、以下のリンクで詳しく紹介しています。
「ChatGPT」を使用したArduinoプログラミングについては、以下のリンクで詳しく紹介しています。
コメント