見出し画像

M5とPCでUDP通信する

以下のつづきです。

  • M5 CapsuleでUSB-OTGでUSBを利用すると、シリアル通信によるデバッグプリントが行えない

  • シリアル通信でデバッグプリントを行う代わりに、Wi-Fiで通信して、M5 CapsuleからPCにデバッグ用のメッセージを送信し、PCで表示することを試した

  • 単純にWi-FiでUDP通信を行っているだけなので、デバッグ以外の用途にも使える

PC側のPythonのプログラム

  • UDPサーバーを起動して、メッセージを待ち受ける

  • キーボードで強制終了(Windowsでは、Ctrl-C)で終了できるようにした

  • IPアドレスが正しく表示、設定されないことがあるかもしれない(複数のIPアドレスが設定されているなど)

    • その場合、手動で ip_addr を設定する

  • is_string_or_binaryで、文字列として表示するか、バイナリデータとして表示するか選択する

import socket
import time

# Configuration
port = 10000
is_string_or_binary = True # True is to show as string.

print(f"Running at {socket.gethostbyname(socket.gethostname())}:{port}")
ip_addr = "0.0.0.0"
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((ip_addr, port))
sock.settimeout(0.1)
while True:
    try:
        data, addr = sock.recvfrom(1024)
        if is_string_or_binary:
            print("%s" % data.decode("utf-8")) # string
        else:
            print(''.join('{:02x} '.format(a) for a in data)) # binary
        time.sleep(0.1)
    except KeyboardInterrupt:
        sock.close()
        break
    except TimeoutError:
        continue

M5 Capsule側のC++のプログラム

  • M5 CapsuleでWi-Fiを起動して、メッセージを送信するプログラム

  • RGB LEDでステータスを表示

    • 起動時に白くLEDが点灯して

    • Wi-Fiの準備ができるまで赤く点灯して

    • 準備ができると緑に点灯する

  • その後、PC側にメッセージを送信する

  • PC側のアプリが起動していれば、デバッグプリントが確認できる

#include <Arduino.h>
#include <WiFi.h>
#include <WiFiUdp.h>
#include <Adafruit_NeoPixel.h>

#define NUM_OF_LEDS 1
#define NEOPIXELS_PIN 21

// Configuration
static const char *remoteAddr = "192.168.0.255";
static const int remotePort = 10000;
static const int localPort = 40000;
const char ssid[] = "SSID_NAME";
const char password[] = "MY_PASSWORD_IS_1234";
const int num_of_try_wifi = 300;


static WiFiUDP wifiUdp;
Adafruit_NeoPixel pixels(NUM_OF_LEDS, NEOPIXELS_PIN, NEO_GRB + NEO_KHZ800);

void sendUdpMessage(const char *s);

void setup()
{
    pixels.setPixelColor(0, pixels.Color(32, 32, 32)); # White
    pixels.show();

    WiFi.begin(ssid, password);
    for (int i = 0; i < num_of_try_wifi; i++) {
        if (WiFi.isConnected()) {
            wifiUdp.begin(localPort);
            break;
        }
        delay(100);
    }

    uint32_t color = WiFi.isConnected() ? pixels.Color(0, 32, 0) : pixels.Color(32, 0, 0); # If Wi-Fi is ready, led is green otherwise red.
    pixels.setPixelColor(0, color);
    pixels.show();

    sendUdpMessage("WiFi is ready.");
}

void loop() {
    delay(1000);
}

void sendUdpMessage(const char *s)
{
    if (WiFi.isConnected())
    {
        wifiUdp.beginPacket(remoteAddr, remotePort);
        wifiUdp.print(s);
        wifiUdp.endPacket();
    }
}

勘違いしていた点

  • 最初、127.0.0.1というループバックアドレスでテストしていた

  • サーバーとクライアントが同一のマシンの場合は、ループバックアドレスが使えるので問題が起きなかったが

  • 今回は、2つのマシン間の通信なので(M5 CapsuleからPCに送信するので)、ループバックアドレスでは動作しない

    • 127.0.0.1は、マシンに割り振られているIPアドレスを自動で設定する、という意味ではない

  • 0.0.0.0に設定すると外部からのアクセスが可能になる(マシンに割り振られているIPアドレスを自動で設定と捉えても大きな間違いではないと思う)(正確な表現ではないとは思うが)

    • PCに複数のIPアドレスがある場合、どのアドレスでもアクセスできると思われる(テストしてはいない)

    • 1270.0.0.1と0.0.0.0を混同して覚えていた

ネットワーク関連の調査に関するメモ

  • つながらないときに調査する方法をメモしておく

コマンドプロンプトでUDPのリッスン状況を確認

  • ループバックアドレスなので外部からは、つながらない

netstat -nao

  プロトコル  ローカル アドレス      外部アドレス           状態            PID
  UDP         127.0.0.1:10000        *:*                                    4501


Power ShellでUDPのリッスン状況を確認

  • ループバックアドレスなので外部からは、つながらない

Get-NetUDPEndpoint -LocalPort 10000

LocalAddress                             LocalPort
------------                             ---------
127.0.0.1                                10000

パケットのキャプチャ

  • WiresharkなどのキャプチャソフトをPCにインストールすれば、M5 Capsuleから送信されたUDPパケットが、PCに届いているかを確認することができる

  • 「PCには届いた上で、Pythonで受信できていない」のか、「そもそも、PCに届いていないのか」を切り分けることができる

トラブルシューティングメモ

  • PCでWiresharkを起動して、PCにパケットが届いているかを確認

    • 送信先のアドレス、ポートが正しいかを確認

    • パケットが届いていない場合は送信側を疑う

    • ファイアーウォールが遮断している可能性があるので、ファイヤーウォールをオフにしてみる

  • PCでnetstatを使って、サーバーが起動しているか、アドレス、ポート番号が正しいかを確認

    • 127.0.0.1、ループバックアドレスになっていたら、外部からは通信できないので変更する

  • いきなり2つのデバイスでテストするのではなく、サーバーとクラインを同一マシンにしてテストしてみる

    • 今回の場合だと、クライアントの実装をPCのPythonで行う必要がある

    • 同じソースコードが動けばよいが、M5のC++は、Windowsでは動作しない(筆者が把握している限り)


環境

  • PlatformIO Core 6.1.15, Home 3.4.4

    • platform

      • espressif32

    • board:

      • m5stack-stamps3

    • framework:

      • arduino

    • Libs

      • adafruit/Adafruit NeoPixel@^1.12.2

この記事が気に入ったらサポートをしてみませんか?