Measuring distance with Bluetooth in indoor environment using PythonJune 13, 2022
Bluetooth ranging technology is very popular. There are many localization systems that exist based on beacons. Beacon technology usually estimates the distance between devices using the received signal strength (RSSI).
Bluetooth can be an excellent way to narrow down a search area at close distances when tracking something. This feature can be used in several fields. such as Secure Locks for Buildings and Automotive, Asset localization & tracking, Indoor navigation etc
GPS tracking isn’t excellent at giving accurate measurements of the close distance, especially in the indoor environment. On the other hand, Bluetooth is excellent in short ranges because the waves can go through walls. This might fill the gap that GPS tracking has when tracking devices in indoor spaces.
However, most calculations of the distance between two Bluetooth devices are estimates. It’s hard to determine the exact distance between two Bluetooth devices because many factors affect the calculations. Despite the challenges, there are methods to determine the distance between two Bluetooth devices with an accuracy of at least 80%.
The ranging method is simple to implement, and it has the formula to calculate the distance between two Bluetooth devices. As the name suggests, both devices need to be within Bluetooth range to estimate the distance.
This article will share a simple python script to determine nearby Bluetooth devices and their distance in meters.
This script scans for nearby Bluetooth devices and gets an approximation of the distance by using the well-known RSSI to distance formula.
Read more about how to calculate the distance
- Get the script from GitHub at https://github.com/smart-sensor-devices-ab/python_bluetooth_device_distance_meter.git
- Connect the BleuIO to your computer. The script uses pyserial to connect to the Bluetooth USB dongle BleuIO.
- Update the script and write the correct COM port, where the dongle is connected.
- After connecting to the dongle, we put the dongle into the central role so that it can scan for nearby Bluetooth devices.
- Then we do a simple Gap scan using AT+GAPSCAN=3 command to scan for nearby Bluetooth devices for 3 seconds.
- After that, we read the output from the serial port and use our RSSI to distance formula to get the distance in meters.
- Finally, we sort the result by distance before printing it out on screen.
Here is the final script file.
import serial import time your_com_port = "COM18" # Change this to the com port your dongle is connected to. connecting_to_dongle = True print("Connecting to dongle...") # Trying to connect to dongle until connected. Make sure the port and baudrate is the same as your dongle. # You can check in the device manager to see what port then right-click and choose properties then the Port Settings # tab to see the other settings while connecting_to_dongle: try: console = serial.Serial( port=your_com_port, baudrate=57600, parity="N", stopbits=1, bytesize=8, timeout=0, ) if console.is_open.__bool__(): connecting_to_dongle = False except: print("Dongle not connected. Please reconnect Dongle.") time.sleep(5) print("Connected to Dongle.") # function to convert rssi to distance in meter def rssiToDistance(rssi): n=2 mp=-69 return round(10 ** ((mp - (int(rssi)))/(10 * n)),2) #put the dongle in dual role, so we can scan for nearby device console.write(str.encode("AT+CENTRAL")) console.write("\r".encode()) print("Putting dongle in Central role.") time.sleep(0.1) # Scan for nearby devices for 3 seconds console.write(str.encode("AT+GAPSCAN=3")) console.write("\r".encode()) time.sleep(0.1) print("Looking for nearby Bluetooth devices ...") dongle_output2 = console.read(console.in_waiting) time.sleep(3) print("Scan Complete!") filtered =  # Filter out unncecssary outputs and keep only the list of devices (also remove index) for dev in dongle_output2.decode().splitlines(): if len(dev)>20: filtered.append(dev.split(maxsplit=1)) # Get unique device by device id and add distance to each raw seen = set() out =  for elem in filtered: prefix = elem.split(' ') if prefix not in seen: seen.add(prefix) out.append(elem + " Distance: "+str(rssiToDistance(elem.split()))+" meter") # sort list by closest device out.sort(key=lambda x:int(x.split()),reverse=True) # print(out) for i in range(0, len(out)): print (out[i]) time.sleep(0.1) console.close()
After running the script, we see a total 20 devices found nearby. The list shows their distance in meter from the central device.