PiCar - Raspberry Pi Car Radio Project - Part 3
"How about this Heat" or what does temperature sensors have to do with filesystems.
our last adventure, I presented an overview of some of the hardware I shoehorned into my car radio project. A lot of it is working, but some of it is still in flux. I tried to get the hard stuff out of the way first and left some easy stuff for me to do when I needed to step back.
One of the features I use day to day, is the ambient air temperature display. Sometimes it really is useful for me to know that the roads are about to freeze, or that maybe I ought to not push my Jeep too hard on the hot days.
There are a lot of ways you can setup a Pi to sense changes in air temperature.
For example, in my chicken coop project, I use a TMP02 temperature sensor on the I2C bus. I chose this path, not only because I already had a bunch of these devices in my parts bin lying around, but there was also an I2C cable near where I would be reading the temperatures.
However this is automotive environment, its a but tougher than a chicken coop. Expect for possibly when the chickens try and eat the sensor. I need something a bit more rugged, and could survive me or other mechanics wrenching nearby.
If we look at a a stock Jeep, Chrysler chose to locate the sensor just in front of the radiator where it gets lots of exposure to bugs, rocks, the occasional deer, and whatever the environment throws at you.
The Jeep electrical system was designed long before any millennial downloaded their first social media video; it is a simple variable resistance device, varying from something like 300 K ohms at –40°F to 2.5 K ohms at 140°F.
If I chose to use this kind of sensor, I would have to add an Analog to Digital (ADC) converter to the project. The ADC would read the changes in sensor resistance and convert. it to numeric values. For example, the MCP3426 breakout ADC that I used in cistern water level project.
A better way
Maybe there is a better way. Searching the net for “Raspberry Pi temperature sensor” I found hundreds of pages of results. It’s probably one of the most common projects you will find in that realm.
It was also be cool to have the option of multiple sensors, for example to read the cabin temperature. So another project goal, is to make this easily expandable.
One of the easiest ways and probably the most popular way to interface a Raspberry Pi to a temperature sensor is to use the 1-Wire® Interface over the Pi’s GPIO ports. The 1-Wire system was developed by Dallas Semiconductor, (acquired by Maxim Integrated, who later got acquired by Analog Devices).
The one 1-Wire system is an open collector serial data bus. The master device (Raspberry Pi) initiates communications to any of the slave devices (sensors) on the bus. Each slave device has a microcontroller that has a unique 48 bit address burned into its ROM. This allows you to have a number of sensors shared on the same GPIO pin. The protocol is bit tricky, as detailed in this article, but as you will see later the Pi has a driver for this already.
The one wire sensors typically have three wires, power (Vdd) , ground (GND) and data (DQ), so maybe it’s really not one- wire.
The interesting thing about 1-wire is how it can be hooked up. You can run three wires to the devices, Vdd, GND and Data. Since the bus is open collector, you need pull-up resistor.
What is ingenious is that the DS18B20 has circuity that allows the device to steal power from the 1-Wire bus via the DQ pin when the bus is high and charge an internal capacitor to power it when the bus goes low again. Using this parasitic mode you can opt to run only 2 wires (DQ and GND) to the devices.
Images courtesy of tweaking4all
The DS18B20 1-Wire Digital Thermometer
One of the more popular 1-wire devices out there is the DS18B20. Take a minute to look at its datasheet. It can measure from -67°F to +257°F and give you some 12 bits of resolution. Ambient air temperature doesn’t change that rapidly, and so I don’t really need that much resolution or acquisition speed. But the devices are cheap and they work well.
You could but it as a chip or a TO-92 package. There are even a lot of companies that make them available enclosed in a stainless steel tube as a probe.
This form factor makes it convenient for my automotive application. I will probably mount it on a base so it sits similar to the stock unit. I have even seen some folks who have used them in a beer brewing system.
Cavet Emptor
One thing you do need to be aware of, the DS18B20 devices are so popular that there are a huge number of counterfeit devices on the market, cloned by those industrious folks in the PRC. One of the problems evidently common with these clone is they do not do parasitic power mode well, or at all.
I could go on and on about my security issues with equipment from the PRC or the people who support them, but let’s save that for a trip to Brandon Falls.
The Raspberry Pi Interface
Hooking up the DS18B20 sensor to the Pi is pretty easy. Hook up the DS18B20 DQ
line to the GPIO lien you choose to use. Don’t forget to hook up +5v Vcc and ground.
You need to select a GPIO line that you are not using for anything else. I was already using GPIO4 for I2C, so I opted for GPIO6 instead. Then I modified my /boot/config.txt
file as such.
# hook up one-wire for temp sensors on line 6
dtoverlay=w1-gpio,gpiopin=6
And rebooted. Now comes the real magic. After you reboot, open the console and list the directory at /sys/bus/w1/devices/
If your device was successfully hooked up, you will see something like this.
%ls /sys/bus/w1/devices/
28-3c89f6494824 w1_bus_master1
The 28-xxxxxxxx is the unique identification address burned into the DS18B20 ROM.
The driver creates a subdirectory for each sensor found in /sys/bus/w1/devices
. The directory name is based on the device family code of the sensor prepended to the identification number. The DS18B20 uses family code 28. There are a number of files under the device directory.
%ls -l /sys/bus/w1/devices/28-3c89f6494824/
total 0
-rw-r--r-- 1 root root 4096 Jul 29 15:42 alarms
-rw-r--r-- 1 root root 4096 Jul 29 15:42 conv_time
lrwxrwxrwx 1 root root 0 Jul 28 11:28 driver -> ../../../bus/w1/drivers/w1_slave_driver
--w------- 1 root root 4096 Jul 29 15:42 eeprom_cmd
-r--r--r-- 1 root root 4096 Jul 29 15:42 ext_power
-rw-r--r-- 1 root root 4096 Jul 29 15:42 features
drwxr-xr-x 3 root root 0 Jul 28 11:28 hwmon
-r--r--r-- 1 root root 4096 Jul 29 15:42 id
-r--r--r-- 1 root root 4096 Jul 29 15:42 name
drwxr-xr-x 2 root root 0 Jul 29 15:42 power
-rw-r--r-- 1 root root 4096 Jul 29 15:42 resolution
lrwxrwxrwx 1 root root 0 Jul 28 11:28 subsystem -> ../../../bus/w1
-r--r--r-- 1 root root 4096 Jul 28 14:09 temperature
-rw-r--r-- 1 root root 4096 Jul 28 11:28 uevent
-rw-r--r-- 1 root root 4096 Jul 28 11:28 w1_slave
If you display the contents of the w1_slave
file you will see the current sensor status and temperature.
%cat /sys/bus/w1/devices/28-3c89f6494824/w1_slave
2a 02 ff ff 7f a5 a5 66 b9 : crc=b9 YES
2a 02 ff ff 7f a5 a5 66 b9 t=34625
The hex values are the contents of the scratchpad register as defined in the DS18B20 datasheet.
But the driver has done us the service of checking the CRC and decoding the temperature value in millidegrees Celsius. So 34625 is 34.625°C or 94.325°F.
If we just wanted the temperature value we could just look at the file at /sys/bus/w1/devices/28-3c89f6494824/temperature
%cat /sys/bus/w1/devices/28-3c89f6494824/temperature
34625
If we have multiple devices on the bus, they will also show up.
%ls -1 /sys/bus/w1/devices/
28-3c49f64979eb
28-3c89f6494824
w1_bus_master1
Or better yet, if you look at the content of the /sys/bus/w1/devices/w1_bus_master1/w1_master_slaves
file you will get the ID of each device.
$ cat /sys/bus/w1/devices/w1_bus_master1/w1_master_slaves
28-3c89f6494824
28-3c49f64979eb
It is that simple. In fact, just about all of the python code samples on the net use this method. But wait? How exactly did the DS18B20 1-wire devices get mapped into files?
The One Wire File System
When we added the overlay for w1-gpio we hooked up the linux one-wire filesystem (OWFS). OWFS is a series of programs that communicates to 1-wire devices and presents the data through a virtual file system using Filesystem in Userspace (FUSE).
FUSE is a module that allows create a file system without having to write a kernel module running with privileges and thus creating a security risk.
I have built a number of apps with in the past with FUSE including an encrypted cloud based file system. But I will tell you right now that OWFS is an ingenious use of FUSE.
OWFS is actually quite robust, according to the man page it also has the ability to handle 1-Wire devices over serial ports, I2C, USB and Network. As well as simulated devices. Besides temperature sensors OWFS also supports other kinds of 1-Wire devices including:
Clocks
iButton identification device
Memory
Switches
Humidity
Voltage
Resistance
LCD Screen
Crypto
Pressure
I thought this was too good to be true.
Well according to the documentation, “the owfs package itself is NOT recommended for any real use, it has well known issues”..
Well that’s OK, I guess. The temperature display is not mission critical. I took the time to see what issues were reported. None of them seem to overlap my system.
What-more, my code doesn’t depend on the python backend, which can have issues of it’s own. I use C++ and filesystem calls. My 1-wire code also runs in its own thread. I am doing quite a bit of burn in testing on the piCar system and haven’t seen any issues yet.
But if this does become a problem I cam across some code that does direct bit banging to the port, and that worked fabulously.