ソースに絡まるエスカルゴ

貧弱プログラマの外部記憶装置です。

【Arduino/python】Arduino UnoのEthernetシールドでUDP通信

 以下の記事で、とりあえずArduino UnoのEthernetシールドを使ってみました。

 今回はArduino UnoのEthernetシールドとPC(python)とでUDPの送受信の通信をやってみた備忘録になります。ちなみにWindows環境で行う前提なので注意してください。

 では、始めます。


1:MACアドレスIPアドレス、ポートを決める
 UDP通信を行う際には「どの端末からどの端末へ送信するか」の情報が必要なので、それらを決める必要があります。

 PC(MacでもWindowsでも)で以下のコマンドを実行して使用されているIPアドレスを確認し、使っていないIPアドレスを選択します。

$ arp -a

 今回は以下のようにしました。MACアドレスはシールドに記載されいていればそれを使用し、書かれていない場合は使用している機器と被らないようなMACアドレスを使うようにしてください。

項目名 Arduino Uno PC
MACアドレス DE:AD:BE:EF:FE:ED 特に設定なし
IPアドレス 192.168.1.177 192.168.1.178
ポート 8888 5000


2:PC側のIPアドレスを固定する
 過去にWindowsでのIPアドレス固定方法の記事を書いているので、それに従ってIPアドレスを固定してください。


3:Arduino Uno側のプログラム
 書き込むプログラムは以下の通りです。

 MY_MAC_ADDRESS、MY_IP、MY_PORT_NUM、TARGET_SERVER、TARGET_PORTはそれぞれ1で決めたものに適宜書き換えてください。

 またEthernetシールドに搭載されているチップによって読み込むライブラリが違うので、そこも注意してください。

・UnoUdpTest.ino

/**
 * ArduinoのイーサネットシールドでUDP送受信
 */
#include <SPI.h>
#include <Ethernet.h> // W5100の場合はこちらを使う
#include <EthernetUdp.h> // W5100の場合はこちらを使う
// #include <Ethernet2.h> // W5500の場合はこちらを使う
// #include <EthernetUdp2.h> // W5500の場合はこちらを使う

const byte MY_MAC_ADDRESS[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // Arduino Uno側MACアドレス(適宜書き換える)
const byte MY_IP[]          = { 192, 168, 1, 177 }; // Arduino Uno側IPアドレス(適宜書き換える)
const int  MY_PORT_NUM      = 8888;                 // Arduino Uno側のポート(適宜書き換える)

const char TARGET_SERVER[] = "192.168.1.178"; // 送信先のアドレス(適宜書き換える)
const int  TARGET_PORT     = 5000;            // 送信先のポート(適宜書き換える)

EthernetUDP Udp; // パケットの送信と受信をするUDPのインスタンス


void setup() {
  Serial.begin(9600);
  Serial.println("--- setup start ---");

  // イーサネットサーバの開始
  Ethernet.begin(MY_MAC_ADDRESS, MY_IP);

  // イーサネットシールドが付いているかの判定
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1); // do nothing, no point running without Ethernet hardware
    }
  }
  // イーサネットケーブルが接続されているかの判定
  if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
  }

  // UDP通信の開始
  Udp.begin(MY_PORT_NUM);

  Serial.println("--- setup end ---");
}

void loop() {
  int parseSize = Udp.parsePacket();

  if (parseSize) {
    // 受信した内容をそのままUDP送信
    byte sendMessage[parseSize];
    Udp.read(sendMessage,parseSize);
    sendUdp(TARGET_SERVER, TARGET_PORT, sendMessage, parseSize);
  }

  delay(500);
}

/**
 * UDP送信を行う関数
 */
void sendUdp(const char *address, int sendPort, byte *byteArray, int packetSize) {
  Udp.beginPacket(address, sendPort);
  Udp.write(byteArray, packetSize);
  Udp.endPacket();

  Serial.print("sendUdp:[ ");
  for (int i = 0; i < packetSize; i++) {
    Serial.print(char(byteArray[i]));
  }
  Serial.println(" ]");
}

 少し解説すると、UDPでの通信を受信したらその内容をそのまま送り返すという処理をしています。UDPで送信する際には送信する内容をSerialで表示させています。


4:PC側のpythonプログラム
 次にPC側のpythonプログラムです。

 TARGET_PORT、TARGET_ADDRESS、MY_PORTは1で決めたものに適宜書き換えてください。

udp_send_recieve.py

#-*- coding:utf-8 -*-
#
# PC側でのUDP送受信
#
from socket import socket, AF_INET, SOCK_DGRAM
import time

# 送信先の設定(適宜書き換える)
TARGET_PORT    = 8888
TARGET_ADDRESS = "192.168.1.177"

# PC側の設定(適宜書き換える)
MY_HOST = ''
MY_PORT = 5000


def main():
    # UDP通信用のソケット
    udp_socket = socket(AF_INET, SOCK_DGRAM)
    udp_socket.bind((MY_HOST, MY_PORT))

    count = 0
    udp_send_flg = True

    try:
        while True:
            if udp_send_flg:
                msg = "count:{}".format(count)
                # 送信
                udp_socket.sendto(msg.encode(), (TARGET_ADDRESS, TARGET_PORT))

                count = count + 1
                if count >= 10:
                    count = 0
            else:
                # 受信
                msg, address = udp_socket.recvfrom(8192)
                print(f"message: {msg} from: {address}")

            udp_send_flg = not udp_send_flg
            time.sleep(1)
    except Exception as e:
        print(e)
    finally:
        udp_socket.close()

if __name__ == '__main__':
    main()

 少し解説すると、1秒ごとにUDPの送信と受信を繰り返す処理をしています。受信した内容はprintで表示しています。


5:実行して確認
 Arduino Uno側にプログラムを書き込み、各種ケーブルをPCにつないだ状態で4のpythonを実行します。

 すると以下のようにpython側から送られたUDPのメッセージをArduino Uno側で受け取り、それをそのまま送り返していることが確認できます。


 以上がArduino UnoのEthernetシールドとPC(python)とでUDPの送受信の通信をやってみた内容になります。

 UDP通信は相手に届いたかどうかの確認はないので送りっぱなしになりますが、それを問題としないのであれば有用かと思います。

 また今回はArduino UnoのEthernetシールドを使いましたが、同じチップを搭載しているのであればESP32などの他のものでもおそらく同じようにライブラリを使ってできると思われる(未検証)ので、似たような形で実装できるかと思います。


・参考資料