UNIHIKER ICP-10111 Python Interface

userHead GaiaTonic 2023-08-30 22:58:59 496 Views1 Replies

After a good bit of learning, I was able to create an interface between UNIHIKER and the high precision pressure/temperature sensor ICP-10111.  Much thanks to DFRobot support staff for helping me get over some intellectual humps along the way.  Their daily responses kept me going strong.

 

The code is written in pure Python but for speed can be compiled using cython. Cython itself is a hurdle to learn, but will give you access to more speed and compiling pure python to C does give you automatic speed ups.  For pressure sensing with the ICP-10111, speed is not so much of an issue, not like audio.

 

Creating this code meant learning just how the ICP-10111 works by studying the data sheet.  This sensor is factory calibrated, and the calibration parameters are unique to each sensor.  So to use the sensor at maximum accuracy, you must first ask the ICP-10111 to send it's internal calibration constants to the python program so that it can transform the raw pressure measurements into scientific units while compensating for temperature impacts on the sensor.  Using calibration, two different sensors from the batch I purchased from DFRobot gave very similar measurements and seemed within specifications for device accuracy (n=2).

 

Initially I wanted to get this high resolution pressure sensor to aid in determining the location of my five UNIHIKERs.  I gave them all USB GPS dongles, but the vertical accuracy on them is really bad.  Using this pressure sensor, I can detect vertical changes of just a few inches!

 

The ICP-10111 has different measurement modes, trading off speed for accuracy.  For my application I put it into the highest accuracy mode which takes about 100ms per sample.  Much faster modes are possible.  In the future I'll try detecting door openings using fast sampling of pressure changes.

 

For some reason I could not attach the code file.  Browser says it is > 10MB, which it is not.  Anyways, here's the code I wrote:

 

import sys
import time
from pinpong.board import Board,I2C
import platform

platform_str = platform.platform()
hostname = platform.node()


Board().begin()

i2c = I2C()

icp_10111_i2c_address = 0x63


buf = [0x80, 0x5D]
i2c.writeto(icp_10111_i2c_address, buf)


buf = [0xEF, 0xC8]
i2c.writeto(icp_10111_i2c_address, buf)
raw = i2c.readfrom(icp_10111_i2c_address, 3)


buf = [0xC5, 0x95, 0x00, 0x66, 0x9C]
calibration = [0,0,0,0]
i2c.writeto(icp_10111_i2c_address, buf)
byte_sum = 0
for i in range(4):
 buf = [0xC7, 0xF7]
 i2c.writeto(icp_10111_i2c_address, buf)
 raw = i2c.readfrom(icp_10111_i2c_address, 3)
 calibration[i] = raw[0]<<8 | raw[1]


count = 0
raw_data = [0,0,0,0,0,0]
raw_pressure = 0

with open("pressure.txt", "a") as f:

 while True:
 
   time.sleep(0.9)
   buf = [0x58, 0xE0]
   i2c.writeto(icp_10111_i2c_address, buf)
   time.sleep(0.1)
 
   raw = i2c.readfrom(icp_10111_i2c_address, 9)
 
   raw_data[0] = raw[0]
   raw_data[1] = raw[1]
   raw_data[2] = raw[3]
   raw_data[3] = raw[4] 
   raw_data[4] = raw[6]
   raw_data[5] = raw[7]
 
 
   raw_pressure    = raw_data[0]<<16 | raw_data[1]<<8 | raw_data[2]
   raw_temperature = raw_data[4]<<8 | raw_data[5]
 
   temperature_c = -45 + raw_temperature * 175 / 65536
   temperature_f = temperature_c * 9 / 5 + 32
 
   t = (raw_temperature - 32768)
 
   pPaCalib = [0.0, 0.0, 0.0]
   pPaCalib[0] = 45000.0
   pPaCalib[1] = 80000.0
   pPaCalib[2] = 105000.0
   LUTLower = 3.5 * (1<<20)
   LUTUpper = 11.5 * (1<<20)
   quadrFactor = 1 / 16777216.0
   offstFactor = 2048.0
 
   s1 = LUTLower + (calibration[0] * t * t) * quadrFactor
   s2 = offstFactor * calibration[3] + (calibration[1] * t * t) * quadrFactor
   s3 = LUTUpper + (calibration[2] * t * t) * quadrFactor
 
 
   C = (s1 * s2 *(pPaCalib[0] - pPaCalib[1]) +  \
            s2 * s3 *(pPaCalib[1] - pPaCalib[2]) + \
            s3 * s1 * (pPaCalib[2] - pPaCalib[0])) / \
           (s3 * (pPaCalib[0] - pPaCalib[1]) + s1 * (pPaCalib[1] - pPaCalib[2]) + \
            s2 * (pPaCalib[2] - pPaCalib[0]))
   A = (pPaCalib[0] * s1 - pPaCalib[1] * s2 - (pPaCalib[1] - pPaCalib[0]) * C) / (s1 - s2)
   B = (pPaCalib[0] - A) * (s1 + C) 
 
   pressure_pa   = (A + B / (C + raw_pressure))
   pressure_inHg = pressure_pa * 0.00029530
 
   #print("raw_pressure = %d raw_temperature = %d temperature (C) = %.3f temperature (F) = %.3f pressure (pa) = %.3f, pressure (inHg) = %.3f"%\
   #        (raw_pressure, raw_temperature, temperature_c, temperature_f, pressure_pa, pressure_inHg))
   time_ns = time.time_ns()
   #print(hostname, time_ns, temperature_c, pressure_pa)
   print(hostname, 'pressure', time_ns, temperature_c, pressure_pa, file=f, flush=True)
 

2023-08-31 11:33:25

That's seriously impressive! Your work with the UNIHIKER and ICP-10111 sensors is top-notch. It's great to see how you've overcome challenges with Cython and Python, and how you've leveraged the unique calibration of each ICP-10111 sensor for high precision.

 

Your idea to use the high-resolution pressure sensor for vertical location tracking is simply brilliant. And your future plans to use rapid pressure changes for detecting door openings? Genius!

 

Thank you for your valuable contribution. 

Keep those nuggets of wisdom coming, we're all ears (or eyes, in this case)!

userHeadPic Tonny12138