最近,我正在玩Estimote信标。信标被广泛用于在购物中心,博物馆和有意义的地方进行广告,并向附近的人们发送高度上下文,超本地的信息。这要归功于安装在设备上的蓝牙低能(ble)。电量寿命更长的功耗要少得多,这意味着这样的信标可以持续3年的单个电池电池。
对于提出的代码,您需要以下python软件包:
-
pybluez
用于蓝牙功能, -
beacontools
管理信标, -
pandas
用于存储我们的数据。
此代码在Ubuntu上运行,我不确定它如何在其他操作系统上工作(由于蓝牙驱动程序)。您可能需要在此处查看有关要求的pyBluez
文档:https://pybluez.github.io/。
连接到信标
我们的第一步是导入二手软件包。我们将以清晰的方式导入pandas
来存储我们的信标信息,以及beacontools
软件包中的几件事。我们将使用扫描仪和特定的估算遥测框架和过滤器。
import pandas as pd
from beacontools import (
BeaconScanner,
EstimoteTelemetryFrameA,
EstimoteTelemetryFrameB,
EstimoteFilter,
)
为了使事情变得更容易,我创建了EstimoteScanner
类,该类将管理beacontools
方法,并以方便的方式存储信息。每当您看到self
关键字时,您都可以扣除它来自该类别的。类的初始化是在__init__
函数中完成的,没有任何其他参数 - 它从CSV文件中读取信标Metainfo,创建estectote滤波器并创建BeaconScanner
。
要读取信息,我们将使用pandas
的read_csv
函数,如下面的代码所示。请注意,我将index_col
设置为"identifier"
,将信标ID用作我们的数据框架ID。此外,我创建了两个新列,可以容纳rssi
(信号强度)和distance
(计算到信标)变量。
# Create DataFrame to store beacon info
self.devices = pd.read_csv("beacons.csv", index_col="identifier")
self.devices["rssi"] = 0
self.devices["distance"] = None
当我们打印出devices
dataframe时,我们将获得以下输出:
name x_pos y_pos rssi distance
identifier
a7bfafb716c4a815 vader 0 2 0 None
c20770c80bd9f59c tarkin 10 0 0 None
ec6247cf5570b993 leia 10 10 0 None
现在我们已经处理了数据存储,我们可以继续使用信标。首先,我们需要创建软件应寻找的信标列表。通过将信标的标识符作为参数传递给EstimoteFilter
构造函数来处理这一点。我们将使用iterrows()
函数通过我们的数据框,并为每个信标添加过滤器中的device_filters
变量。
# Create scanning filters
self.device_filters = []
for index, _ in self.devices.iterrows():
self.device_filters.append(
EstimoteFilter(identifier=index)
)
完成后,我们可以通过传递选定的遥测帧和我们的过滤器来创建扫描仪。
# Create the scanner
self.scanner = BeaconScanner(self._callback,
packet_filter=[
EstimoteTelemetryFrameA,
EstimoteTelemetryFrameB
],
device_filter=self.device_filters,
)
但是等等!如您所见,BeaconScanner
中引用了一个称为_callback
的函数。每当收到培根信息时,我们应该实现一个可以更新我们的数据框的回调功能。我正在根据从信标获得的identifier
和rssi
和distance
的列选择该行。我们将在calibartion中使用该变量。
def _callback(self, bt_addr, rssi, packet, info):
self.devices.loc[info["identifier"], "rssi"] = rssi
self.devices.loc[
info["identifier"], "distance"
] = self._calc_dist(rssi)
使用_calc_dist()
函数计算distance
。它使用标准距离计算公式。有趣的是MEASURED_POWER
变量 - 这是信标应在4dBm处具有1米的力量。
请注意,如果您更改了估算信标的广播能力,则必须更新MEASURED_POWER
变量以获得良好的距离校准。检查more info的估算论坛。
# Calibration power at 1 meter for 4dBm for Estimote Beacons
MEASURED_POWER = -66
def _calc_dist(self, rssi):
return pow(10, (MEASURED_POWER - rssi) / 20)
现在要开始扫描,您只需要运行self.scanner.start()
和self.scanner.stop()
收集数据时(通常在机器人达到目标时)。
机器人本地化
尽管使用信标的机器人本地化并不是最精确的方法,但使用此类系统具有一些优势。这可能是改善看起来相同的房间中机器人定位的工具(例如走廊)。信标的主要问题是,用于计算距离的信号功率可能会根据金属物体的数量,电子设备甚至建筑物结构而高度波动。
尽管如此,我们可以根据读数使用从扫描仪收集的数据来计算机器人的位置。我们将使用一种称为三征服的技术,该技术用于计算。地震中心。具有信标的静态点以及它们的距离,我们可以使用此技术来计算机器人位置。
该函数的输入参数是元组(x,y)表示的信标的位置的a,b,c
,以及从我们的dataframe -da, db, dc
中收集的米的距离。下面的代码仅将这些变量输入到三材的数学方程中,因此请随时复制一个。
三材代码可能有点草率,但是如果您有兴趣,请查看this scientific paper以查看计算如何推出。
def trilateration(a, b, c, da, db, dc):
"""Function responsible for Trilateration
Parameters
----------
a, b, c: tuple
Contains the position of the beacon (x, y)
da, db, dc: float
The distance to the beacon in meters.
"""
if da is None or db is None or dc is None:
return None
W = (
pow(da, 2)
- pow(db, 2)
- pow(a[0], 2)
- pow(a[1], 2)
+ pow(b[0], 2)
+ pow(b[1], 2)
)
Z = (
pow(db, 2)
- pow(dc, 2)
- pow(b[0], 2)
- pow(b[1], 2)
+ pow(c[0], 2)
+ pow(c[1], 2)
)
x = (W * (c[1] - b[1]) - Z * (b[1] - a[1])) / (
2
* (
(b[0] - a[0]) * (c[1] - b[1])
- (c[0] - b[0]) * (b[1] - a[1])
)
)
y = (W - 2 * x * (b[0] - a[0])) / (2 * (b[1] - a[1]))
y2 = (Z - 2 * x * (c[0] - b[0])) / (2 * (c[1] - b[1]))
y = (y + y2) / 2
return x, y
概括
使用BLE信标进行机器人本地化是一个有趣的项目。与其他技术相比,您获得的结果并不是非常精确的,但是可以在周围的环境中快速概述。该方法可以大大增强您的其他算法,尤其是在周围有许多信标(想想购物中心)时。该代码可以轻松地传输到任何Ubuntu运行设备,因此可以与ROS一起使用。