ZimnoCieplo: Don't lose your ZimnoCieplo!

ZimnoCieplo runs on a hand-held device powered by balena stack. It navigates a user to his lost objects. This particular implementation uses a BLE transceiver to quantify iBeacons signals. This project’s name comes from the simple game my daughters play. One searches for an object, another navigates with “zimno”, which mean cold in Polish, when the searcher is getting away from the object. The navigator says “cieplo” (warm) when the searchers is approaching to the object.

Here are some materials I used for this project:

  • Raspberry Pi Zero 2 W
  • Micro SD card
  • micro-USB power bank
  • Bluetooth headset
  • iBeacon (simulated by Beacon Simulater Android application on an Android smart phone)


A user should be navigated by voice coming from the handheld device. When the relative position from the searched-for object at t=1 is closer to the user in comparison to the distance at t = 0, the handheld device tells “cieplo” and “zimno” at the opposite case. When the distance does not differ significantly between time adjacent intervals it should keep silent. Within the defined “very close” range, the device should indicate with “cieplo, cieplo” regardless of if the user is getting nearer or farther. See figure below. When the beacon is not found at all, it indicates by “zimno, zimno”.

But what happens if you lose your ZimnoCieplo? That would be horrible.

Though there are a couple of articles on the web on the formulae of calculating distance from bluetooth RSSI values, e.g. android - Estimating beacon proximity/distance based on RSSI - Bluetooth LE - Stack Overflow, which used exponential function, none of them worked for this project. At the end I decided to ignore all physical principles, but statistically fit measurements/distance approximately to a sqrt function, which resulted in simple

distance = sqrt(TX_POWER - RSSI) + 1.

But as those articles mentioned indeed large fluctuations of RSSI measuerment data was making the system nearly useless. Following suggestions, I introduced the kalman-filter JavaScript library GitHub - piercus/kalman-filter: Kalman filter in javascript and built a filter with

const filter = new KalmanFilter({
observation: 1,
init: {
// Initial guess:
// RSSI: -75,
// speed: 10 RSSI/step
mean: [[-75], [10]],
dynamic: {
name: ‘constant-speed’,
// Assume we get 3 measurements between moves.
timeStep: 0.3,
// Assume small measurement errors.
covariance: [0.01, 0.01],

Here is the plot of observed data and interpolation produced by the filter.

One of the most useful literatures I found on Kalman filter was https://cse.sc.edu/~terejanu/files/tutorialEKF.pdf.

Obstacles I encountered so far are

  1. balenaOS did not support Raspberry Zero 2 W
    When I started the project, I purchased Raspberry Zero 2 W, because I thought since balenaOS supports Zero W, Zero 2 @ should be supported as well. It turned out that Zero 2 W required different wifi firmware than that of Zero W. Fortunately the devs reacted quickly and now Zero 2 W is officially supported.

  2. I came across to difficulties in connecting my bluetooth headset with the Pi. After a while of struggling, a colleague advised me that there are audio and bluetooth balenaBlocks, with those I could finally connect the headset and the application. balenaBlocks are neat way of modularizing components even at the embedded scene.

  3. Another trouble I faced was that after several times of flashing the OS image to the SD card and rebooting, my Raspberry Pi at some point stopped appearing on the balena cloud. Once I bought another Raspberry Pi because I suspected that I damaged the hardware, but the same symptom appeared with the new device too. I gave up later in the evening. But when I woke u and turned on the internet router, My Raspberry Pi reappeared on balena cloud. To this date, the cause is unclear.

There is now an emitter service, which scans the iBeacon in search and emits a distance every five seconds to an MQTT broker running inside the Raspberry Pi Zero 2 W. Published messages can be seen with MQTT Explorer. Message format is

export interface Distance {
    type: DistanceType;
    previous: number | null;
    current: number | null;

With this architecture, ZinoCieplo can be used with other types of beacons. The next step is to develop the the navigation part.

Today I implemented the last part of voice navigation. The application stitches following components together:

  • BLE-positioniner/emitter
  • navigation
  • belena audio block
  • balena bluetooth block

The principle works, and the device navigates. However though Kalman filter is applied, it looks like that the system still suffers from fluctuating measurements. It swings between non-detection and 1m -distance most of the time… Hmm…

Today I walked around between rooms, took some measurements and distances between ZimnoCieplo and the beacon to fit parameters of Kalman filter. I updated the equation for calculating distance from RSSI value which ended up again with having no physical meaning, but purely statistical (or visual). I ended up with covariance 0.02 for both position and speed. The distance equation is

function getDistance(rssi: number): number {
  const diff = -50 - rssi;
  const d = 0.3 * Math.pow(diff, 7 / 9) + 0.4
  return diff <= 0 ? 1 : d;

which you can see on the graphs below. The code can be found in the Github repository.

With regard to data fluctuation, or specifically to the problem that at many times the Bluetooth transceiver does not even detect a beacon, I today checked if I made mistakes in one of steps in data processing, but indeed also at the beginning of the pipe, the searched beacon did not appear.

One potential improvements can be to simply replace the transceiver with BLE 5, which would significantly increase the coverage range, from around 10 m to over 100 m. There are more precise locationing technologies, like UWB, some of them are not popular and difficult to obtain required components. With newer BLE 5.1 devices, much more precise locationing can be achieved with AoA (Angle of Arrival) technology, by mounting a couple of antennas on a handheld device. However, it looks like that BLE 5.1 transceivers are currently shipped with high-end devices like laptops in the market. For instance, none of Raspberry Pi models come with BLE 5.1.

Reference (among many):

Nice job finding a distance relationship for something so variable! RSSI tends to vary so much depending on the environment, even without movement. Interested to hear about improved transceiver technology ahead.