I tried it out with the code given below.
https://tech.fusic.co.jp/posts/2020-02-23-m5stickc-ibeacon/
What is iBeacon
iBeacon is a type of beacon using BLE (Bluetooth Low Energy) announced by Apple in 2013.
One terminal broadcasts the UUID (advertises), and the other terminal receives it to detect who is approaching.
For example, by installing iBeacon transmitters at three points in a shopping mall and receiving them with a smartphone app, you can notify the sale information of nearby stores.
In this case, the smartphone does not necessarily have to be the receiving side, but it is also possible to trace the movement of the smartphone by reversing the transmission and reception.
Based on the above, this time, using M5StickC, we received the advertisement from the smartphone and verified that the UUID, address, and RSSI are acquired.
The iBeacon packet is shown below.
When you receive the packet, verify the following:
The first 2 bytes of the received packet is called "Info Header", and in the case of BLE it is "0x1A, 0xFF". Up to this point, it seems that the BLE library makes the decision.
The next 2 bytes are the "Apple Company ID", which is "0x4C00". The next 2 bytes should be "iBeacon identifier" and should be "0x1502".
If there is no particular problem in the verification so far, it can be determined as an iBeacon advertisement packet, so proceed to the subsequent processing.
Read information from the advertisement packetaddress
The address can be obtained by calling getAddress() of BLEAdvertisedDevice which is an argument of the callback function.
RSSI
RSSI can be obtained by calling getRSSI() of BLEAdvertisedDevice.
UUID
UUID obtains manufacturer-specific information by calling getManufacturerData() of BLEAdvertisedDevice, and is stored in the 4th and subsequent bytes from the beginning.
program
The program created for reference is posted. Probably the same program works on M5Stack.
#include <M5StickC.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
class IBeaconAdvertised: public BLEAdvertisedDeviceCallbacks {
public:
// Callback when BLE is detected
void onResult(BLEAdvertisedDevice device) {
if (!isIBeacon(device)) {
return;
}
printIBeacon(device);
}
private:
// iBeacon packet judgment
bool isIBeacon(BLEAdvertisedDevice device) {
if (device.getManufacturerData().length() < 25) {
return false;
}
if (getCompanyId(device) != 0x004C) {
return false;
}
if (getIBeaconHeader(device) != 0x1502) {
return false;
}
return true;
}
// CompanyId acquisition
unsigned short getCompanyId(BLEAdvertisedDevice device) {
const unsigned short* pCompanyId = (const unsigned short*)&device
.getManufacturerData()
.c_str()[0];
return *pCompanyId;
}
// Get iBeacon Header
unsigned short getIBeaconHeader(BLEAdvertisedDevice device) {
const unsigned short* pHeader = (const unsigned short*)&device
.getManufacturerData()
.c_str()[2];
return *pHeader;
}
// Get UUID
String getUuid(BLEAdvertisedDevice device) {
const char* pUuid = &device.getManufacturerData().c_str()[4];
char uuid[64] = {0};
sprintf(
uuid,
"%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
pUuid[0], pUuid[1], pUuid[2], pUuid[3], pUuid[4], pUuid[5], pUuid[6], pUuid[7],
pUuid[8], pUuid[9], pUuid[10], pUuid[11], pUuid[12], pUuid[13], pUuid[14], pUuid[15]
);
return String(uuid);
}
// Get TxPower
signed char getTxPower(BLEAdvertisedDevice device) {
const signed char* pTxPower = (const signed char*)&device
.getManufacturerData()
.c_str()[24];
return *pTxPower;
}
// Serial output of iBeacon information
void printIBeacon(BLEAdvertisedDevice device) {
Serial.printf("addr:%s rssi:%d uuid:%s power:%d\r\n",
device.getAddress().toString().c_str(),
device.getRSSI(),
getUuid(device).c_str(),
*(signed char*)&device.getManufacturerData().c_str()[24]);
}
};
void setup() {
M5.begin();
Serial.begin(115200);
BLEDevice::init("");
M5.Lcd.setCursor(0, 30);
M5.Lcd.print("Ready");
}
void loop() {
M5.Lcd.print("start.");
Serial.println("start.");
BLEScan* scan = BLEDevice::getScan();
scan->setAdvertisedDeviceCallbacks(new IBeaconAdvertised(), true);
scan->setActiveScan(true);
scan->start(60);
Serial.println("complete.");
M5.Lcd.print("complete.");
}
resultIt's easy to get like this.
*Two Aplix terminals are used to send iBeacon.
After doing so, check the contents of processing and output again.
addr: Information unique to the BLE output terminal (advertisement side)
uuid: Information specific to the service UUID
rssi: Strength of radio wave received by BLE receiving terminal (central)
power: TxPwoer. The strength of the signal emitted by the BLE output terminal.
In the case of iBeacon, it seems to indicate the received signal strength at a point 1 m away.
So, if rssi is the same as this pTxPower, you can see that it is 1 m away
*Premise that there is no shield
I don't know why you are using negative values,
Roughly speaking, if rssi is smaller than power (is it large because it is a negative value?), it means that you are closer than 1m.
Try to calculate the distanceIt seems that you can calculate the distance from RSSI and TxPower, so give it a try.
reference
Estimate beacon distance and proximity (Proximity) from RSSI and TxPower
d = 10 ^ ((TxPower - RSSI) / 20)
The previous example
addr:c0:1c:4d:42:11:30 rssi:-56 uuid:00000000-9706-1001-B000-001C4D0E77D0 power:-69
TxPower: -69, RSSI: -56, so
d : 10 ^ ((-69 - -56) / 20) = 0.22m
Since it was near a complete set of PCs, I feel like this is the case.
A little distantaddr:c0:1c:4d:42:11:30 rssi:-77 uuid:00000000-9706-1001-B000-001C4D0E77D0 power:-69
TxPower:-69, RSSI:-77, so the following.
d : 10 ^ ((-69 - -77) / 20) = 2.51m
It's a visual measurement, but I feel like this.
Beacon terminal on top of M5StickC
addr:c0:1c:4d:42:1e:74 rssi:-36 uuid:00000000-9706-1001-B000-001C4D0E77D0 power:-69
TxPower:-69, RSSI:-36, so the following.
d : 10 ^ ((-69 - -36) / 20) = 0.02m
This is because the devices are in contact with each other.
It is a number that seems to fit all.
How do you use itHowever, if this is the case, the result of SCAN will be obtained by the console and it will be difficult to use. After reading some, it seems correct to use the averaged values.
As it stands
scan->start(60);
This seems to be scanning for 60 seconds.
So it's a good idea to set this to a short time, such as 1 second, and then take the average of that to get the accuracy of the result that is near/far or the result.
Apparently it seems that this area is an iOS framework.
Other than the above, it seems that it also has the following as an iOS framework
•Proximity
CLProximityImmediate (very close)
CLProximityNear (close)
CLProximityFar (far)
•accuracy
A value that indicates the variation in the estimated distance. A value that indicates how likely it is.
ryo_naka
Comments