So what is this article all about? Here I will show you guys what I ve learned after days of researching of what is the SensorTile, BLE and how can we receive and use the sensor data, using a Raspberry Pi
You can use that data in a lot of projects, for example, there is one made by me in the video below, where I used the accelerometer data from the SensorTile to plot a graph of the engine vibration of my motorcycle.
So first, lets talk about the two main components of this project: The SensorTile and the Raspberry Pi
ST SensorTileThe SensorTile from ST Microeletronics is an amazing piece of hardware, it incorporates a STM32 microcontroller with a lot of useful sensors like: thermometer, accelerometer, gyroscope, humidity, etc, and BLE, for easy communication.
It comes in 3 forms/variations, the first one is the development kit, with a set of additional boards, the second one is the box version, that literally comes in a box with a battery, and the third one is the SuperBall, which is the same thing as the box version, but inside an american football ball.
When I first got my hands on the SensorTile development kit, I was amazed by its features and how easy was to read its sensor data with the "ST BLE Sensor" app, but all that data would not be useful if I couldn't read it outside of the mobile app.
The first thing we need to receive the SensorTile data is a hardware with Bluetooth 4.0 or above, and a microcontroller to process that data.
I could use an ESP32, that already supports BLE and is inexpensive, BUT, as you will see later, its not that easy to handle BLE GATT protocol, and ST has already developed an python library to communicate with its devices that use BlueST protocol, which make things a lot easier.
That's where the Raspberry Pi comes in, it is a small factor computer, it does have a lot of advantages like: low cost, small factor, linux os support, connectivity features and many more. In this project we need a Raspberry Pi 3 or higher, because the previous versions doesn't have bluetooth.
In my case, I will be using a modified version of the Raspberry Pi 3, it is the Avnet IoT Gateway, it has the exact same hardware as the Raspberry PI 3, but it does add some features like: extended temperature range, industrial interfaces, IoTConnect, and many more. I will make an article about this guy later.
But don't worry, it also runs Raspbian, so you can do pretty much anything you would do in a common Raspberry, and it won't be any differences in this project.
How the SensorTile exports it's sensor data?The first thing we need to understand is how the SensorTile sends out its data through its BLE radio.
When I first developed this project, I had zero knowledge about how BLE works, and I thought it would work like some kind of Bluetooth Serial Port, but that is not the case.
The bluetooth serial port is a protocol named SPP (Serial Port Profile), but ble devices doesn't support this protocol, instead they use a protocol named GATT (Generic Atribute Profile). GATT defines the way two BLE devices transfer data
The typical application is when we have a GATT Server and a GATT Client, I created the schematic below, so you can have an idea of how the project works.
All those services and characteristics have a UUID (Universally unique identifier) attached to them, the UUID in BLE is a 32bit data that identifies services, characteristics and descriptors.
The SensorTile uses the BlueST protocol to standardize its UUIDs, characteristics and how to work with them, you can find the documentation of this protocol here.
So when you connect to a BLE device and ask its characteristics, you wont see a friendly name like "Thermometer data", but instead you will se something like this:
So in this chapter, you will see in detail how a device reads a GATT characteristic data from a ble server device. It is not needed since we are going to use a library that simplifies everything, but it is something interesting that I would like to share.
So, to show a example of how to read the characteristics value, I downloaded the app LightBlue, it is available for Android and IOS, it is an amazing app for those who are developing BLE applications or those who are learning about how it works.
For example: Lets read the SensorTile.box battery info, so lets first take a look at the BlueST documentation and find what is the battery data UUID, and the data format.
So now we know that the characteristic that we are looking for has the UUID = "0x00020000-0001-11e1-ac36-0002a5d5c51b". Lets power on our SensorTile and connect it with the LightBlue app.
The app interface is pretty straight forward, just select your device, click on it, and it will show you all its info, services and characteristics. Then, find the characteristic you are looking for, in this case, the battery characteristic.
After that, click on the subscribe button on the bottom of the screen, what this does is tell the device that you want to receive any modifications on this characteristic value. Later on we will se that this is also called as "enable notifications".
You will see that a lot of data will start showing on your screen, but that doesnt make any sense at all in the first moment, note that the default data format in BLE is hexadecimal. The first thing you need to know is that this data is in the "Little endian" format, in other words, the most significant byte is inverted, so you have to invert the bytes first. Them you can start to decode the information.
This whole process is described in the picture below.
So that's how you can read the characteristic data of a BLE device, of course there is a million of others ways, but I hope hope that with this, you can understand a bit better of how it works.
I know that it sounds a kind hard to deal, and it is, but lucky us, ST has developed the BlueST SDK for python, that makes things a LOT easier, so lets start coding.
Lets connect our Rpi to the SensorTileWith that being said, we know that to receive the SensorTile data, we need to create our GATT client and connect to the GATT server, then we can start receiving any data we want from the server.
First, we need some libraries that will us to work with the BLE and the SensorTile, so open your terminal, and install the Bluepy and the BlueST libraries.
$ sudo pip3 install bluepy
$ sudo pip3 install blue-st-sdk
Then, just make sure that your rpi has bluetooth, and it is enabled, open the terminal and type the following commands:
$ sudo bluetoothctl
$ show
If everything is okay, you probably are going to see something like this.
Then you are ready to connect with your SensorTile, the first thing I recommend you to do is running the example_ble_1.py, from the BlueST library, this example will search for all nearby ble devices, and let you select one. To run the example code just download it here to your Rpi and type the following in the terminal:
$ sudo python3 example_ble_1.py
If everything is okay, you will see a list of devices, and then a list of available sensors ("features"), and you can select one to receive its data.
The list of features may vary to your SensorTile, to select which sensors you want the device to export, you need to download ST Ble Sensor app, as mentioned in the start of the article.
I wanted to log that data to future use, so I simplified the example code, so you only have to enter 3 parameters: The SensorTile mac, which sensor and where you want to save the log.
Take a look at the main function
def main(argv):
# Printing intro.
print_intro()
try:
SENSORTILE_MAC = 'c0:50:1b:32:04:57' #Enter your device MAC adress here
device = connect_ble(SENSORTILE_MAC)
features = listfeatures(device)
#Features SENSORTILE:
#0 Temperature
#1 Humidity
#2 Pressure
#3 Magnetometer
#4 Gyroscope
#5 Accelerometer
accelerometer = features[5] #Change here what feature you want
logger = [] #Array to store log data
logsize = 35 #Change here to increase or decrease logsize
starttime = time.time() #Gets the timestamp reference
path = "/home/avnet/Desktop/projetografico/data.txt" #Path of the log file
while True:
data = readsensor(device, accelerometer)
print(data)
logger= logdata(data,logger,logsize,path,starttime)
except KeyboardInterrupt:
try:
# Exiting.
print('\nExiting...\n')
sys.exit(0)
except SystemExit:
os._exit(0)
So now, you can read all sensor data you want for the SensorTile, and use it as you want in the Rpi.
With all that being sad, I hope you learned a bit more about this device, ble and the Rpi :).
Extra: Create a real time graph to monitor accelerometer dataWhen you read the accelerometer data from the SensorTile, it shows the values for the x y and z axis, using the terminal print, but I don't think that this a cool way to show data.
So lets use the matplotlib to create graphs, and have a final result like the one below.
First, we know that to create this graph, we need to give the matplotlib the xaxis, yaxis, zaxis values and the timestamp, so I modified the logger of my example to only log values, making it easy to handle later.
separate = data.split(' ')
x = round(float(separate[3])*9.8/1000,1)
y = round(float(separate[9])*9.8/1000,1)#Transforms mg to m/s^2
z = round(float(separate[15])*9.8/1000,1)
executiontime = round((time.time() - starttime)*1000)
xyzt = str(x)+" "+str(y)+" "+str(z)+" "+str(executiontime)
So the log file looks like this:
The modified version for this example can be found in the code section.
The code for the graph is really simple, it uses the "FuncAnimation" from matplotlib, so basically it is reading the log continuously and plotting the graph over and over.
The only thing you have to change, is the log path.
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import time
from matplotlib import style
#Graph setup
startime = time.time()
style.use('fivethirtyeight')
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
plt.subplots_adjust(left=0.10, bottom=0.15, right=None, top=None, wspace=None, hspace=None)
lasttime = time.time()
logpath = '/home/avnet/Desktop/projetografico/data.txt'
def getdata():
global logpath
timestamp = [] #Array to store timestamp data
xaxis = [] #Array to store x data
yaxis = [] #Array to store y data
zaxis = [] #Array to store z data
log = open(logpath,'r')
logdata = log.read()
log.close()
lines = logdata.split('\n')
for line in lines:
xyzt = line.split(' ')
if(len(xyzt)!=4):
break
xaxis.append(float(xyzt[0]))
yaxis.append(float(xyzt[1]))
zaxis.append(float(xyzt[2]))
timestamp.append(float(xyzt[3]))
return xaxis,yaxis,zaxis,timestamp
def animate(i):
global lasttime
try:
xaxis,yaxis,zaxis,timestamp = getdata()
ax1.clear()
ax1.plot(timestamp, xaxis, label='X axis')
ax1.plot(timestamp, yaxis, label='Y axis')
ax1.plot(timestamp, zaxis, label='Z axis')
ax1.set_xlabel('Time (ms)')
ax1.set_ylabel('Acceleration m/s2')
ax1.set_title("Accelerometer data")
ax1.legend()
tg = round((time.time() - lasttime)*1000)
print('Plot generated, total spent time: %.1f ms' % (tg))
lasttime = time.time()
except ValueError:
print("Text file is busy")
except IndexError:
print("Text file is busy 1")
ani = animation.FuncAnimation(fig, animate, interval=100)
plt.show()
So just download both codes, run them using Python3, and that's it, you have your accelerometer data being displayed in a realtime graph.
Comments
Please log in or sign up to comment.