The Rainbow HAT is a pretty neat addition to the Raspberry PI model 3 B. It brings the device to life in a way that caught the eye of my children. It has a bunch of sensors (touch, temperature, pressure) as well as a buzzer, bright LEDs and a digital readout. Photos don’t seem to do justice to the LEDs.
The codelab takes a user through: adding required driver artefacts, initialising LEDs and the digital readout, then effecting changes on the LEDs and digital readout.
Next it takes the user through reading in sensor data (temperature and pressure) and displaying it. This is no different from any other sensor in Android, however the result wasn’t quite what I expected. I was getting ~33ºC (~91ºF) when it felt like 23ºC (~73ºF)!
The issue is that the HAT sits so close to the Raspberry PI board that the CPU is heating the sensor. This is noted on the Pimoroni website in the notes:
Temperature readings are affected by heat radiated from your Pi’s CPU and the onboard LEDs; calibration can help to correct temperature readings. bstrobl, on the Raspberry Pi forums, suggests to use the formula: corrected temp. = measured temp. — (CPU temp. — measured temp.) / 2. Using a Mini Black HAT Hack3r can also help.
I tried out the formula recommended, which meant getting the CPU temperature. I couldn’t find an API for this in Android (that wasn’t deprecated). After looking around I did find that there is a file which is updated with the CPU temperature:
This supplies the temperature in “milli”-Celsius.
To get the temperature I decided to use RxJava / RxAndroid to query the file periodically (using a Handler). I would have liked to use a FileObserver but for some reason this didn’t trigger an event when it was modified (although it did when I accessed it).
Unfortunately, the calculated actual temperature was still off by quite a bit when I tried the formula recommended:
Ta = Tm -(Tc -Tm)/2
Ta — actual temperature
Tm — measured temperature
Tc — CPU temperature
Ta was 23, Tm was 39 and Tc was 51 so I was getting ~33.
I have come up with the following to calculate the temperature:
Ta = Tm -C * (Tc -Ta)
C — a constant factor (how much heating is occurring)
which would yield:
Ta = (Tm -C * Tc) / (1 -C)
(if Tc > Tm, which seems reasonable)
For me the factor worked out to something around ~0.6 (I found it takes a little while for the device to reach a steady state). I have my device in a perspex case which may mean there is more heating of the sensor occurring. In other cases, the CPU will affect the sensor more or less.
I would be interested to know if this works for anyone else.
My simple assumption is that the heat loss, from the CPU to the sensor, is dependent on the difference in CPU temperature and actual temperature (given Newton’s law of cooling).
It’s much simpler than reality, with things like airflow and specific heat capacity of the air changing (based on current humidity), but might work as a simple approximation.
If the sensor is not close at all, then C becomes 0 and Ta = Tm. Some bad stuff will go down if it gets to 1…
I’ve created a gist which has the details of changes I’ve made. Make sure you add RxAndroid to your app’s build.gradle:
You may want to change the following for your scenario:
public static final String CPU_FILE_PATH = "/sys/class/thermal/thermal_zone0/temp";
private static final float HEATING_COEFFICIENT = 0.55f;
private static final long UPDATE_CPU_DELAY = 50;
The UPDATE_CPU_DELAY determines how frequently you want to get the latest CPU value.
The file location CPU_FILE_PATH should work for the Raspberry PI, but may change on other hardware.
The HEATING_COEFFICIENT may change for your hardware setup. I’d like to know how other people find this. Or even better… maybe someone has a new equation to try out.
NB: This isn’t production code, but a first look at some small changes I made to make the tutorial a bit more realistic when a user first tries it out.