smellbomb’s blog

主にマイコンと電子工作

ESP32とラズパイでBluetoothによるSPP通信のベンチマーク

  • 目的
    • ESP32とラズパイでBluetoothのSPP通信を行った場合
      遅延と実効通信レートがどの程度になるか調査をする。
  • 試験環境
    • サーバー側:ESP-WROOM-32
    • クライアント側:Raspberrypi3b+(内臓Bluetooth使用)
      • OS:bullseye Release11(CLI運用)
      • ソフト:python3.9.2_64bit pyserial
    • "サーバー"・"クライアント"配置
      • 距離:1000mm(遮蔽物無し)
  • 試験内容(ソースコードは記事巻末参照)
    • 通信手順
      • ASCIIコードを用い、LFで送受信における完了トリガーとする。
    • 通信サイクル
      • ラズパイよりデータを送信し、ESP32が受信データと同一データを送信。
      • ラズパイ上で送受信データの一致確認をもってサイクル完了とした。
    • 測定方法
      • ラズパイ側で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.013288 0.071321 0.006205 0.032500 0.065000 1204
2 0.013523 0.081167 0.006226 0.033617 0.067233 2366
3 0.013145 0.058818 0.007148 0.032047 0.064094 3652
4 0.01379 0.063877 0.006835 0.033823 0.067645 4641
5 0.013136 0.057554 0.006931 0.031898 0.063795 6090
10 0.013178 0.057569 0.007301 0.031447 0.062894 12141
20 0.015249 0.065444 0.008145 0.033261 0.066522 20985
30 0.017178 0.066215 0.008599 0.035967 0.071934 27943
40 0.017413 0.090023 0.009469 0.035429 0.070858 36754
50 0.019243 0.08304 0.009867 0.035136 0.070273 41574
100 0.033166 0.085077 0.014676 0.036745 0.073490 48242
150 0.036418 0.096614 0.015962 0.032540 0.065080 65901
200 0.036001 0.082626 0.018734 0.031361 0.062723 88886
250 0.037932 0.087403 0.022059 0.027688 0.055376 105452
300 0.039324 0.093719 0.024318 0.025414 0.050828 122063
350 0.041409 0.076375 0.026813 0.024264 0.048528 135236
400 0.044113 0.086197 0.028701 0.028282 0.056563 145082
450 0.057283 0.098023 0.032105 0.038603 0.077206 125692
500 0.063707 0.110676 0.034387 0.034159 0.068317 125575
600 0.067726 0.137092 0.040482 0.032502 0.065004 141748
700 0.075531 0.173518 0.044626 0.033677 0.067354 148283
800 0.079246 0.128892 0.049892 0.030826 0.061653 161522
900 0.095119 0.166947 0.056227 0.037209 0.074418 151389


図1:1~10byte時の分布

図2:10~100byte時の分布
図3:100~500byte時の分布
図4:500~900byte時の分布
  • 考察
    • 通信時間のバラつき
      • 正規分布ではなく、2山になっている。6σでの想定が妥当である。
    • 通信自体のオーバーヘッド(1byte送信時)
      • ワースト78.3ms(ave:13.3ms 6σ:65ms) 但し、頻度としては10msが多い。
  • 結論(一回辺り100byte以内の送受信による制御を想定)
    • 制御指令に対する遅延:ワースト106ms
  • ESP32ソース
#include <Arduino.h>
#include <BluetoothSerial.h>

BluetoothSerial SerialBT;
String btrx_buff;

void spp_setup(){
  uint8_t macBT[6];
  char btname[11];
  esp_read_mac(macBT, ESP_MAC_BT);
  sprintf(btname, "ESP32-%02X%02X", macBT[4], macBT[5]);
  if (SerialBT.begin(btname)) {
    Serial.println("start_spp");
  }
}

void setup() {
  Serial.begin(115200);
  spp_setup();
}

void loop() {
    btrx_buff = SerialBT.readStringUntil('\n');
    SerialBT.print(btrx_buff + '\n');
    //Serial.println(btrx_buff);
}
  • ラズパイ
import serial
import time
import csv


bt_spp = serial.Serial(port='/dev/rfcomm0', baudrate=115200, timeout=None)

def spp_tx(tx_buff=None,chk=1):
    tx_buff = tx_buff + '\n'
    tx_buff_b = tx_buff.encode('utf-8')
    bt_spp.write(tx_buff_b)
    if chk == 1:
        rx_data_b = bt_spp.readline()
        rx_data = rx_data_b.decode('utf-8')
        if tx_buff == rx_data:
            return True
        else:
            return None
    elif chk == 2:
        rx_data_b = bt_spp.readline()
        rx_data = rx_data_b.decode('utf-8')
        if rx_data == '\n':
            return True
        else:
            return None
    else:
        return True


def spp_benchimark(loop=10,byte=1):
    ct = 0
    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 = spp_tx(tx_buff=send_data)
    for n in range(loop):
        start = time.time()
        tx_result = spp_tx(tx_buff=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]:
    result_ls = spp_benchimark(loop=1000,byte=n)
    with open('data.csv','a') as f:
        writer = csv.writer(f)
        writer.writerow(result_ls)

bt_spp.close()