![見出し画像](https://assets.st-note.com/production/uploads/images/146627888/rectangle_large_type_2_bf1f898fc7d9bc497ad4fd58e3e6d92b.jpeg?width=1200)
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
この記事が気に入ったらサポートをしてみませんか?