smellbomb’s blog

主にマイコンと電子工作

ESP32のUDP通信のベンチマーク

  • 目的
    • ESP32でWifiUDP通信を行った場合
      遅延と実効通信レートがどの程度になるか調査をする。
  • 試験環境
    • サーバー側:ESP-WROOM-32
      • ソフト:framework_arduino
      • Wifi設定:STAモード、送信電力19.5dB(MAX)
    • クライアント側:デスクトップPC(AP間は有線1Gbps接続)
      • OS:Windows10 21H2/64bit
      • ソフト:python3.9.2_64bit
    • ESP32放熱対策(シールドにヒートシンク取付)
      • サーマルパッド経由の放熱が無い事もあり、動作異常が発生してしまう為実施。
ESP32放熱対策
  • 試験内容(ソースコードは記事巻末参照。前回SPP通信同様手順とした)
    • 通信手順
      • ASCIIコードを用い、LFで送受信における完了トリガーとする。
    • 通信サイクル
      • ラズパイよりデータを送信し、ESP32が受信データと同一データを送信。
      • ラズパイ上で送受信データの一致確認をもってサイクル完了とした。
    • 測定方法
      • PC側でtime関数を使用し、上記サイクル時間を計測。
      • 1サイクル内の各種オーバーヘッドは含む。但しloopのオーバーヘッドは除く。
      • シリアルポートopen後の初回通信は評価対象としない。(時間が長い為)
      • 通信レートは1000サイクルにおける1サイクル平均値にて算出



  • 試験結果
    • 各送受信データ量における、N=1000の試験結果を示す。
      • 表1:試験結果概要
      • 各転送データ量における通信時間の分布は以下の通り。
        • 図1:1~10byte時の分布
        • 図2:10~100byte時の分布
        • 図3:100~500byte時の分布
        • 図4:500~900byte時の分布

表1:試験結果一覧

送受信データ
(byte)
通信時間
AVE(s)
通信時間
MAX(s)
通信時間
MIN(s)
通信時間
3σ(s)
通信時間
6σ(s)
実効通信レート
(bps)
1 0.006728 0.037318 0.002986 0.011635 0.02327 2378
2 0.006747 0.036077 0.002707 0.011704 0.023407 4743
3 0.006944 0.050978 0.002646 0.012661 0.025323 6912
4 0.00681 0.035284 0.002574 0.011763 0.023526 9398
5 0.007037 0.029986 0.002837 0.012069 0.024138 11368
10 0.006832 0.030259 0.002804 0.011145 0.022291 23419
20 0.006815 0.039036 0.00283 0.011928 0.023855 46955
30 0.00695 0.039083 0.002977 0.010938 0.021876 69065
40 0.00701 0.031827 0.002954 0.0109 0.0218 91298
50 0.006951 0.034668 0.002869 0.011069 0.022138 115091
100 0.007374 0.037092 0.003061 0.012287 0.024574 216979
150 0.007757 0.043328 0.003128 0.013567 0.027133 309398
200 0.007795 0.037367 0.00368 0.01239 0.024781 410520
250 0.007967 0.030451 0.00363 0.011485 0.02297 502071
300 0.008077 0.043682 0.004004 0.01274 0.025481 594280
350 0.008221 0.038176 0.00398 0.012072 0.024143 681182
400 0.008623 0.041072 0.004008 0.012782 0.025565 742201
450 0.009021 0.063308 0.00419 0.014533 0.029065 798138
500 0.009058 0.040857 0.004214 0.013759 0.027518 883197
600 0.009419 0.038899 0.004465 0.01333 0.026661 1019216
700 0.010279 0.083165 0.004678 0.017752 0.035503 1089600
800 0.011781 0.080902 0.004999 0.022093 0.044186 1086495
900 0.011107 0.061182 0.005582 0.018299 0.036598 1296480
図1:1~10byte時の分布
図2:10~100byte時の分布
図3:100~500byte時の分布
図4:500~900byte時の分布
  • 考察
    • 通信時間のバラつき
    • 通信自体のオーバーヘッド(1byte送信時)
      • ワースト29.7.3ms(ave:6.7ms 6σ:23ms) 但し、頻度としては10ms以内が多い。
    • ESP32高温時の動作異常について(温度はtemperatureRead()関数で観測)
      • CPU温度が49℃を超えた際に以下現象が発生した。
        ESP32側はパケット送信を実施しているが、クライアント側が受信できない。
        この時CPUはフリーズやシャットダウンは起きていない。
        クライアント側からのパケット受信はできている。
        温度が下がれば動作は再度安定する。
    • ESP32のSoftAPモードについて
      • 上記高温時の不具合内容が、温度との依存関係なく頻発した。
        電圧ドロップ等も確認したが、3.3~3.4Vは維持出来ており、原因は不明。
  • 結論
    • 制御指令に対する遅延:1指令が100byte以内であれば、ワースト32ms
    • 通信速度:1Mbps以上出る
  • 所感
    • BluetoothのSPP通信と同様の比較を行ったが、性能面だけを比較するのであれば、間違いなくWifiによるUDP通信の方が優れていた。
  • ESP32ソース
void wifi_info(){
  uint8_t wifiMac[6];
  esp_read_mac(wifiMac, ESP_MAC_WIFI_STA);
  char wifiMacChar[18] = {0};
  sprintf(wifiMacChar,"%02X:%02X:%02X:%02X:%02X:%02X", wifiMac[0],wifiMac[1],wifiMac[2],wifiMac[3],wifiMac[4],wifiMac[5]);
  Serial.printf("MAC:%s\n",wifiMacChar);
  Serial.print("ip:");
  Serial.println(WiFi.localIP());
  Serial.print("subnet:");
  Serial.println(WiFi.subnetMask());
  Serial.printf("wifiTxPower:%d\n",WiFi.getTxPower());
}

void wifiNonAP_setup(){
  const char ssid[]= "ssid";
  const char pass[]= "sspass";
  WiFi.begin(ssid,pass);
  while (WiFi.status() != WL_CONNECTED);{
    delay(500);
    Serial.println("wifi_connect_ok");
  }
void udp_setup(){
  const int localport = 10000;
  WiFi.setTxPower(WIFI_POWER_19_5dBm);
  wifiNonAP_setup();
  esp_wifi_set_ps(WIFI_PS_NONE);
  wifi_info();
  udp.begin(localport);
}

void setup() {
  Serial.begin(115200);
  Serial.printf("cpuFreq(Mhz):%d\n",ets_get_cpu_frequency());
  Serial.printf("cputemp:%f\n",temperatureRead());
  udp_setup();
  Serial.println("bootUpFin");
}
void loop() {
  const char *remoteIp = "xxx.xxx.xxx.xxx";
  const int remoteUdpPort = 10001;
  String btRxBuff;
  String udpRxBuff;
  while(true){
    if (udp.parsePacket()){
      udpRxBuff = udp.readStringUntil('\n');
      udp.beginPacket(remoteIp, remoteUdpPort);
      udp.print(udpRxBuff + '\n');
      udp.endPacket();
    }
  }
}
  • ラズパイ
import time
import socket
import csv

serv_ip = ("xxx.xxx.xxx.xxx", 10000)
local_ip = ("xxx.xxx.xxx.xxx", 10001)

tx_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
rx_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
rx_sock.bind(local_ip)


def udp_tx(tx_data="", chk=1):
    tx_data = tx_data + '\n'
    tx_data_b = tx_data.encode('utf-8')
    tx_sock.sendto(tx_data_b, serv_ip)
    if chk == 1:
        rx_data_b, add = rx_sock.recvfrom(1024)
        rx_data = rx_data_b.decode('utf-8')
        if tx_data_b == rx_data_b:
            return True
        else:
            print('err')
            return None
    else:
        return True


def udp_benchmark(loop=10, byte=1):
    result_ls = [byte]
    data = 0
    send_data = ""
    for n in range(byte):
        send_data += str(data)
        data += 1
        if data >= 9:
            data = 0
    tx_result = udp_tx(tx_data=send_data)
    for n in range(loop):
        start = time.time()
        tx_result = udp_tx(tx_data=send_data)
        ct = time.time() - start
        if tx_result is None:
            result_ls.append(-1)
        else:
            result_ls.append(round(ct, 6))
    return result_ls


for n in [1, 2, 3, 4, 5, 10, 20, 30, 40, 50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 600, 700, 800, 900, 1000]:
    result_ls = udp_benchmark(loop=1000, byte=n)
    print(result_ls)
    with open('udp_benchmark_pc.csv', 'a', newline='') as f:
        writer = csv.writer(f)
        writer.writerow(result_ls)
        f.close()


tx_sock.close()
rx_sock.close()