ラズパイPicoW Wi-Fi通信、遠隔操作&表示 C言語(Arduinoコマンド)編

ラズパイPico W Wi-Fiサーバーで遠隔操作C言語編アイキャッチ

Wi-Fi通信機能付きの「ラズパイ(Raspberry Pi)Pico W」が「技適(技術基準適合証明)」が取得され日本で正式に販売されました。

Wi-Fiが使えるようになったら、やっぱり遠隔操作&表示をしたい!
ということで「M5Stack」系のデバイスで何度もやってますが、だいぶシンプルにできるようになってきたので「ラズパイPico W」で試してみました。

ブラウザで表示させる「html」は苦手ですが最近では「ChatGPT」が作ってくれるので楽になりました。作ってもらった「html」をコピペで「ラズパイPico W」に文字列として埋め込むだけなのでこの方法も詳しく紹介します。


「MicroPython」や「CircuitPython」を使用した「PicoW」のWi-Fi通信の使い方も、以下のリンクで詳しく紹介しています。

ラズパイPicoW Wi-Fi通信、遠隔操作&表示 MicroPython編
Raspberry Pi PicoWのWi-Fi無線通信を使用してMicroPythonでパソコンやスマホのブラウザから遠隔操作,データ表示する方法を詳しく紹介
ラズパイPicoW Wi-Fi通信、遠隔操作&表示 CircuitPython編
Raspberry Pi PicoWのWi-Fi通信機能を使用してサーバー機能を利用した遠隔操作、データ監視する方法をCircuitPythonで詳しく紹介します。

「ラズパイPico W」の基本仕様、開発環境については以下のリンクで詳しく紹介しています。

ラズパイPico/PicoWの使い方を3つの開発環境Python、ArduinoIDE、PlatformIOで紹介
Raspberry Pi Pico/Pico Wの使い方を端子配列からPython(MicroPython)とC言語の開発環境、Lチカ方法まで紹介。PythonはTonny、C言語はArduinoIDEとPlatformIOの3種類で詳しく紹介します。
スポンサーリンク

1.ラズパイPico Wとは

「Raspberry Pi PicoW」とは、イギリスを拠点とする慈善団体によって若者のプログラミング学習を目的に開発されたもので、他の「Raspberry Piシリーズ」とは異なり、OSの機能はありませんが、電源投入ですぐに使用でき、スイッチやLEDランプ、モーター、各種センサー、通信機器を接続して、それらを制御するプログラムを簡単に作成して動作確認できるため、組み込み(制御)系プログラミングの学習に最適です。

「Pico W」にはWi-Fi機能があり、Wi-Fi通信を利用したインターネット経由のデータ収集や遠隔操作等のアイデアを簡単に試すことができます。

端子配列は下画像のようになります(公式サイトより抜粋

ラズパイPico/Pico Wの端子配列
スポンサーリンク

2.動作紹介

今回制作したものの動作については以下のようになります。
「ラズパイPico W」の電源を入れると本体のLED(緑)が点灯し、ArduinoIDE等のシリアルモニタで確認したIPアドレスをスマホやパソコンのアドレスバーに入力すると、下画像のような画面が表示されます。

この画面から本体LEDのON/OFFと同時に、出力端子(GP0)のON/OFFができるようにしています。
また、基板本体の温度を取得して画面上に1秒ごとに更新して表示させています。

ラズパイPico W Wi-Fiサーバーで遠隔操作C言語編

プログラムは下の方に「サンプルプログラム」を準備していますので、ArduinoIDE等にコピペで貼り付けて書き込みます。

ArduinoIDEのインストール方法や使い方は以下のリンクで詳しく紹介しています。

ラズパイPico/Pico2/PicoWのArduinoIDE2のインストール方法や使い方紹介
Raspberry Pi Pico/Pico2/PicoWのC言語での開発環境 ArduinoIDE2のインストールから初期設定、使い方、Lチカで動作確認まで詳しく紹介

以下が開発環境「ArduinoIDE」の画面です。

ラズパイPico W Wi-Fiサーバーで遠隔操作C言語編

書き込んだら、シリアルモニタで「IPアドレス」の確認を行いますが「ArduinoIDE」の場合は上画像右上の[シリアルプロッタ]をクリックすると下画像のようにシリアルモニタが表示されます。

「ラズパイPico W」の電源を入れ直すと、下画像のように上から順にWi-Fi接続先の「SSID」と「IPアドレス」が表示されます。

ラズパイPico W Wi-Fiサーバーで遠隔操作C言語編

ブラウザの検索窓に「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を付けると簡単に確認できます。

ラズパイPico W Wi-Fiサーバーで遠隔操作C言語編

基板のスルーホールを挟み込むように取り付けられるので、基板裏の端子番号を見ながら接続できて、自由度もあり、抜けることもないので便利です。
下画像では出力端子(GP0)にLEDの+、GNDにLEDのーを接続しています。

ラズパイPico W Wi-Fiサーバーで遠隔操作C言語編

以下のテストクリップは反対側のピンがメスだけでなくオスピンのものもセットになっており、ブレッドボドに差し込むことができて便利です。


今回のプログラムについては、サーバーの動作について知っておくと理解が早いです。
サーバーについては以下のリンクで詳しく紹介しています。

WiFi(ローカル接続、サーバー)で遠隔操作する方法(Arduinoプログラミング)
Wi-Fi通信でスマホから遠隔操作を行う方法を詳しく紹介。サーバーの仕組みを利用することで簡単にブラウザからの遠隔操作が実現できます。ATOM LITE使用
スポンサーリンク

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」への質問は以下のようにしました。

以下の仕様を満たすHTMLタグをCSS、JavaScriptを含めて書いて
1. ブラウザにONボタン(緑色)とOFFボタン(赤色)を横並びに配置して、その下に隙間を開けて項目を温度表示としたテキストボックスを配置して、全体を上中央に表示する。
2. ONボタンを押すと非同期通信のfetchで”/get/btn_on”へリクエストを送信し、受信したレスポンスをテキストで取得してコンソールログに表示する。
3. OFFボタンを押すと非同期通信のfetchで”/get/btn_off”へリクエストを送信し、受信したレスポンスをテキストで取得してコンソルログに表示する。
4. 1秒ごとに”/get/data”へリクエストを送信し、レスポンスを温度表示用のテキストボックスに表示する。

回答は以下のようになりました。

以下が仕様を満たすHTML、CSS、JavaScriptのコードです。
<!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>
このコードでは、<div>要素を使用してON/OFFボタンを横並びに配置し、<input>要素を使用して温度を表示するテキストボックスを下に配置しました。
CSSでは、Flexboxを使用して要素を中央配置し、ボタンのスタイルとテキストボックスのスタイルを設定しました。
JavaScriptでは、fetchを使用してリクエストを送信し、レスポンスを取得してコンソールログに表示したり、温度表示用のテキストボックスに表示したりしています。
また、setIntervalを使用して、1秒ごとにデータを更新します。

「ChatGPT」が書いてくれたコードを、サンプルプログラムの「17〜66行目」と置き換えて書き込んで「Pico W」の「IPアドレス」にアクセスすると下画像のようなページが表示されます。

ChatGPTでラズパイPico W Wi-Fiサーバーで動作確認

「温度表示」の項目がないですが「ON/OFFボタン」を押すと「PicoW」本体のLEDが点灯/消灯するのが確認でき、温度も更新して表示されることが確認できました。

「ChatGPT」への質問を正しくしてやれば1回で使えるコードを書いてくれます。
動かなかったとしても、症状や発生したエラーを続けて聞けば正しいものに書き換えてくれます。
とても便利になりました。もうHTMLに悩まされることはありません♪
今回使用した「ChatGPT」のAIは「ChatGPT-3.5 Turbo」です。
無料の「Text-davinci-003」では、「html」「JavaScript」「CSS」を個別で回答してきたので、それぞれを自分で組み合わせる必要がありました。
回答のコードは聞くごとに微妙に異なります。何度か聞いて一番良いものを使用しましょう。

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通信の使い方も、以下のリンクで詳しく紹介しています。

ラズパイPicoW Wi-Fi通信、遠隔操作&表示 MicroPython編
Raspberry Pi PicoWのWi-Fi無線通信を使用してMicroPythonでパソコンやスマホのブラウザから遠隔操作,データ表示する方法を詳しく紹介
ラズパイPicoW Wi-Fi通信、遠隔操作&表示 CircuitPython編
Raspberry Pi PicoWのWi-Fi通信機能を使用してサーバー機能を利用した遠隔操作、データ監視する方法をCircuitPythonで詳しく紹介します。

「ChatGPT」を使用したArduinoプログラミングについては、以下のリンクで詳しく紹介しています。

Arduinoプログラミング初心者必見!ChatGPTがもたらす新しい可能性
ChatGPTがプログラミングの考え方を変えました「こんなプログラムを書いて」と聞けばコード作成から説明、エラーの指摘までしてくれる。ChatGPTがもたらす新しい可能性を探ってみたいと思います。

コメント

タイトルとURLをコピーしました