ESP32のBLEのRSSIを調べてみた
研究の一環として,ESP-WROOM-32を用いてRSSI値の測定をやってみました.
使用機材
- ESP32-DevKitC 4台
- Mac book Pro (Big Sur)
環境構築
筆者は日頃Python3を用いてコードを書いているので,今回はmicropythonを使っています.
ESP32でmicropythonを使う場合はこちらを参照してください.
https://micropython-docs-ja.readthedocs.io/ja/latest/esp32/tutorial/intro.html
エディタやIDEはお好みで大丈夫ですが,作成したコードをESP32に焼く際はesp-idfを用いるのが楽だと感じました.
クイックリファレンスがGithubに上がっていますので,興味がある方はぜひ.
BLEのRSSI取得方法
公式のGithubのコードを参考にさせていただきました.
参考にさせていただいたのは,example > bluetooth
内のコードです.
送信側の処理
送信側はble_advertising.py
とble_temperature.py
をそのまま使用しています.
受信側の処理
まず,ble_advertising.py
のdemo()
を自分の環境に合わせて変更してください.
def demo():
payload = advertising_payload(
name="micropython",
services=[bluetooth.UUID(0x181A), bluetooth.UUID("XXXX")],
) #送信側のUUIDに設定
筆者はMongoDBにデータを格納しているので以下のようなコードになりました.
xxx
の部分は適時変更してください.
import ubluetooth
import utime
import ubinascii
import urequests
import ujson
import network, urequests, utime
from machine import Pin, RTC
from micropython import const
_IRQ_SCAN_RESULT = const(5)
_IRQ_SCAN_DONE = const(6)
def send_db(name,addr,rssi):
url = 'http://xxxxxxx'
now = get_jst()
payload = {
"db": "xxx",
"collection": "xxx",
"datetime": now,
"data": {
"name": name,
"addr": ubinascii.hexlify(addr),
"rssi": rssi,
}
}
header = {
'Content-Type' : 'application/json'
}
res = urequests.post(
url,
data = ujson.dumps(payload).encode("utf-8"),
headers = header
)
res.close()
def get_jst():
rtc = RTC()
url_jst = "http://worldtimeapi.org/api/timezone/Asia/Tokyo"
retry_delay = 5000
response = urequests.get(url_jst)
parsed = response.json()
datetime_str = str(parsed["datetime"])
year = int(datetime_str[0:4])
month = int(datetime_str[5:7])
day = int(datetime_str[8:10])
hour = int(datetime_str[11:13])
minute = int(datetime_str[14:16])
second = int(datetime_str[17:19])
subsecond = int(round(int(datetime_str[20:26]) / 10000))
rtc.datetime((year, month, day, 0, hour, minute, second, subsecond))
daysOfTheWeek = "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
tm = utime.localtime(utime.mktime(utime.localtime()))
date_str = "{0:4d}/{1:02d}/{2:02d}".format(*rtc.datetime())
time_str = "{4:02d}:{5:02d}:{6:02d}".format(*rtc.datetime())
date_ok = date_str + " " + time_str
return date_ok
ble=ubluetooth.BLE()
if ble.active()== False:
ble.active(True)
def bt_irq(event, data):
if event == _IRQ_SCAN_RESULT:
addr_type, addr, connectable, rssi, adv_data = data
name = "xxx"
addr_hex = ubinascii.hexlify(addr)
if '{}'.format(ubinascii.hexlify(addr)) == 'b\'xxxxx\'':
print('addr:{} rssi:{} '.format(ubinascii.hexlify(addr), rssi ))
send_db(name, str(addr_hex), rssi)
elif event == _IRQ_SCAN_DONE:
print('Scan compelete')
pass
ble.irq(bt_irq)
ble.gap_scan(600000, 30000, 30000)
ble.gap_scan()
に関する詳しい説明はubluetoothのリファレンスを読んでみてください.
https://micropython-docs-ja.readthedocs.io/ja/latest/library/ubluetooth.html
RSSIの測定
受信側,送信側それぞれをESP32に焼き,実行してみましょう.
筆者はWebREPLを使用しています.
WebREPLの使用手順
①左上のIPアドレスを変更し,Connect!
②右上からファイルを選択し,Send to device!
③以下のコマンドを実行!
>>> execfile("xxx.py")
3つのビーコンで測定
各ビーコンで1mの時をそれぞれ測定すると以下のような分布になりました!
なお,縦軸は取得回数,横軸はRSSI値です.
しっかり測定はできましたが,それぞれで誤差がかなりありそうですね...
##おわりに
ESP32は機器ごとにも誤差が大きいようで,しっかりとした基準値をうまく決めないと使えないようですね...
位置精度の改善や座標の特定など色々な用途に使用できそうですね!