August 17, 2016

Automatic orientation of Sense HAT display

In this post I will show you how to automatically detect the position of the Raspberry PI using the Sense HAT accelerometer sensor and rotate the display accordingly.

The auto_rotate_display function in the script below is doing all the logic. It's reading sensors data to detect the orientation and rotating the Sense HAT display by calling the set_rotation function.

import time
from sense_hat import SenseHat

MSG_COLOR = [200,0,160]
BKG_COLOR = [0,0,0]
SCROLL_SPEED = 0.06
MESSAGE = "Can't loose my head"


def auto_rotate_display():
  # read sensors data to detect orientation
  x = round(sense.get_accelerometer_raw()['x'], 0)
  y = round(sense.get_accelerometer_raw()['y'], 0)

  rot = 0
  if x == -1:
    rot=90
  elif y == -1:
    rot=180
  elif x == 1:
    rot=270

  # rotate the display according to the orientation
  print ("Current orientation x=%s y=%s  rotating display by %s degrees" % (x, y, rot))
  sense.set_rotation(rot)


sense = SenseHat()

while True:
  auto_rotate_display()
  sense.show_message(MESSAGE, scroll_speed=SCROLL_SPEED, text_colour=MSG_COLOR, back_colour=BKG_COLOR)
  time.sleep(1)


Accurate temperature reading from Raspberry PI Sense HAT

When I first received the Sense HAT for my Raspberry PI 3 I decided to start building a nice weather station using the embedded environmental sensors and RGB LED matrix.
From a quick experiment it turns out that the temperature readings are not accurate. The problem is caused by thermal conduction from the Pi CPU to the humidity and pressure sensors on the Sense HAT.
I have experimented few algorithms and I have found the following formula to be the most reliable. It basically compensate the temperature reading (t) with the CPU temperature (tCpu).
tCorr = t - ((tCpu-t)/1.5)

Here is the full script to print each 5 seconds the environmental data including the corrected temperature.

import os
import time
from sense_hat import SenseHat

def get_cpu_temp():
  res = os.popen("vcgencmd measure_temp").readline()
  t = float(res.replace("temp=","").replace("'C\n",""))
  return(t)


sense = SenseHat()

while True:
  t = sense.get_temperature_from_humidity()
  t_cpu = get_cpu_temp()
  h = sense.get_humidity()
  p = sense.get_pressure()

  # calculates the real temperature compesating CPU heating
  t_corr = t - ((t_cpu-t)/1.5)
  
  print("t=%.1f  t_cpu=%.1f  t_corr=%.1f  h=%d  p=%d" % (t, t_cpu, t_corr, round(h), round(p)))
  
  time.sleep(5)

Running this script I have noticed that the CPU temperature reading is not very stable making the corrected temperature a little bit unstable. To fix this issue I have decided to apply a moving average to the temperature reading.
As a further improvement I'm also the temperature both from the humidity and pressure sensors and calculating the average.

import os
import time
from sense_hat import SenseHat

# get CPU temperature
def get_cpu_temp():
  res = os.popen("vcgencmd measure_temp").readline()
  t = float(res.replace("temp=","").replace("'C\n",""))
  return(t)

# use moving average to smooth readings
def get_smooth(x):
  if not hasattr(get_smooth, "t"):
    get_smooth.t = [x,x,x]
  get_smooth.t[2] = get_smooth.t[1]
  get_smooth.t[1] = get_smooth.t[0]
  get_smooth.t[0] = x
  xs = (get_smooth.t[0]+get_smooth.t[1]+get_smooth.t[2])/3
  return(xs)


sense = SenseHat()

while True:
  t1 = sense.get_temperature_from_humidity()
  t2 = sense.get_temperature_from_pressure()
  t_cpu = get_cpu_temp()
  h = sense.get_humidity()
  p = sense.get_pressure()

  # calculates the real temperature compesating CPU heating
  t = (t1+t2)/2
  t_corr = t - ((t_cpu-t)/1.5)
  t_corr = get_smooth(t_corr)
  
  print("t1=%.1f  t2=%.1f  t_cpu=%.1f  t_corr=%.1f  h=%d  p=%d" % (t1, t2, t_cpu, t_corr, round(h), round(p)))
  
  time.sleep(5)

Display two digits numbers on the Raspberry PI Sense HAT

Here is a small Python script to display two digits numbers on the Raspberry PI Sense HAT led matrix.

The script is very useful if you want to display humidity and temperature without scrolling.


The show_number function accepts the number to be displayed and RGB values of the color to be used.
Here is the full script.

from sense_hat import SenseHat
import time

OFFSET_LEFT = 1
OFFSET_TOP = 2

NUMS =[1,1,1,1,0,1,1,0,1,1,0,1,1,1,1,  # 0
       0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,  # 1
       1,1,1,0,0,1,0,1,0,1,0,0,1,1,1,  # 2
       1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,  # 3
       1,0,0,1,0,1,1,1,1,0,0,1,0,0,1,  # 4
       1,1,1,1,0,0,1,1,1,0,0,1,1,1,1,  # 5
       1,1,1,1,0,0,1,1,1,1,0,1,1,1,1,  # 6
       1,1,1,0,0,1,0,1,0,1,0,0,1,0,0,  # 7
       1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,  # 8
       1,1,1,1,0,1,1,1,1,0,0,1,0,0,1]  # 9

# Displays a single digit (0-9)
def show_digit(val, xd, yd, r, g, b):
  offset = val * 15
  for p in range(offset, offset + 15):
    xt = p % 3
    yt = (p-offset) // 3
    sense.set_pixel(xt+xd, yt+yd, r*NUMS[p], g*NUMS[p], b*NUMS[p])

# Displays a two-digits positive number (0-99)
def show_number(val, r, g, b):
  abs_val = abs(val)
  tens = abs_val // 10
  units = abs_val % 10
  if (abs_val > 9): show_digit(tens, OFFSET_LEFT, OFFSET_TOP, r, g, b)
  show_digit(units, OFFSET_LEFT+4, OFFSET_TOP, r, g, b)


################################################################################
# MAIN

sense = SenseHat()
sense.clear()

for i in range(0, 100):
  show_number(i, 200, 0, 60)
  time.sleep(0.2)

sense.clear()