1+ #!/usr/bin/env python
2+ #
3+ # Library for interacting with Grove - HP20x sensor (used to measure temperature, pressure and altitude)
4+ #
5+ # This is the library for Grove Base Hat which used to connect grove sensors for raspberry pi.
6+ #
7+
8+ '''
9+ ## License
10+
11+ The MIT License (MIT)
12+
13+ Grove Base Hat for the Raspberry Pi, used to connect grove sensors.
14+ Copyright (C) [Your Company Name or Relevant Party]
15+
16+ Permission is hereby granted, free of charge, to any person obtaining a copy
17+ of this software and associated documentation files (the "Software"), to deal
18+ in the Software without restriction, including without limitation the rights
19+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20+ copies of the Software, and to permit persons to whom the Software is
21+ furnished to do so, subject to the following conditions:
22+
23+ The above copyright notice and this permission notice shall be included in
24+ all copies or substantial portions of the Software.
25+
26+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32+ THE SOFTWARE.
33+ '''
34+
35+ from grove .i2c import Bus
36+ import time
37+
38+ # Class for interacting with the HP20x sensor
39+ class HP20x :
40+ def __init__ (self ):
41+ # Initialize the I2C bus on Raspberry Pi (bus 1)
42+ self .bus = Bus ()
43+ # I2C address of the HP206F sensor, may need adjustment based on actual situation
44+ self .address = 0x76
45+
46+ # I2C device ID when CSB PIN is at VDD level (address is 0x76)
47+ self .HP20X_I2C_DEV_ID = (0xEC ) >> 1
48+ # I2C device ID when CSB PIN is at GND level (address is 0x77)
49+ self .HP20X_I2C_DEV_ID2 = (0XEE ) >> 1
50+ # Soft reset command for the HP20x sensor
51+ self .HP20X_SOFT_RST = 0x06
52+ # Write conversion command for the HP20x sensor
53+ self .HP20X_WR_CONVERT_CMD = 0x40
54+ # Different oversampling rate (OSR) configurations for conversion
55+ self .HP20X_CONVERT_OSR4096 = 0 << 2
56+ self .HP20X_CONVERT_OSR2048 = 1 << 2
57+ self .HP20X_CONVERT_OSR1024 = 2 << 2
58+ self .HP20X_CONVERT_OSR512 = 3 << 2
59+ self .HP20X_CONVERT_OSR256 = 4 << 2
60+ self .HP20X_CONVERT_OSR128 = 5 << 2
61+
62+ # Commands for reading pressure, altitude, temperature, etc.
63+ self .HP20X_READ_P = 0x30 # Read pressure command
64+ self .HP20X_READ_A = 0x31 # Read altitude command
65+ self .HP20X_READ_T = 0x32 # Read temperature command
66+ self .HP20X_READ_PT = 0x10 # Read pressure and temperature command
67+ self .HP20X_READ_AT = 0x11 # Read altitude and temperature command
68+ self .HP20X_READ_CAL = 0X28 # RE-CAL ANALOG command
69+
70+ # Write register mode for the HP20x sensor
71+ self .HP20X_WR_REG_MODE = 0xC0
72+ # Read register mode for the HP20x sensor
73+ self .HP20X_RD_REG_MODE = 0x80
74+
75+ # Set the oversampling rate configuration
76+ self .OSR_CFG = self .HP20X_CONVERT_OSR1024
77+ # Conversion time corresponding to the oversampling rate (in milliseconds)
78+ self .OSR_ConvertTime = 25
79+
80+ def begin (self ):
81+ # Send a soft reset command to the HP20x sensor
82+ self .HP20X_IIC_WriteCmd (self .HP20X_SOFT_RST )
83+ # Wait for 0.1 seconds to ensure the reset operation is completed
84+ time .sleep (0.1 )
85+
86+ def isAvailable (self ):
87+ # Check if the HP20x sensor is available by reading the register at address 0x0F
88+ return self .HP20X_IIC_ReadReg (0x0F )
89+
90+ def ReadTemperature (self ):
91+ # Send a conversion command with the specified oversampling rate configuration
92+ self .HP20X_IIC_WriteCmd (self .HP20X_WR_CONVERT_CMD | self .OSR_CFG )
93+ # Wait for the conversion time (converted to seconds)
94+ time .sleep (self .OSR_ConvertTime / 1000.0 )
95+ # Read 3 bytes of raw temperature data from the sensor
96+ t_raw = self .bus .read_i2c_block_data (self .address , self .HP20X_READ_T , 3 )
97+ # Combine the 3 bytes of data to form a single value
98+ t = t_raw [0 ] << 16 | t_raw [1 ] << 8 | t_raw [2 ]
99+ # Handle negative values using 2's complement
100+ if t & 0x800000 :
101+ t |= 0xff000000
102+ us = (1 << 32 )
103+ t = - 1 * (us - t )
104+ # Return the temperature value in degrees Celsius (divided by 100)
105+ return t / 100.0
106+
107+ def ReadPressure (self ):
108+ # Send a conversion command with the specified oversampling rate configuration
109+ self .HP20X_IIC_WriteCmd (self .HP20X_WR_CONVERT_CMD | self .OSR_CFG )
110+ # Wait for the conversion time (converted to seconds)
111+ time .sleep (self .OSR_ConvertTime / 1000.0 )
112+ # Read 3 bytes of raw pressure data from the sensor
113+ p_raw = self .bus .read_i2c_block_data (self .address , self .HP20X_READ_P , 3 )
114+ # Combine the 3 bytes of data to form a single value
115+ p = p_raw [0 ] << 16 | p_raw [1 ] << 8 | p_raw [2 ]
116+ # Handle negative values using 2's complement
117+ if p & 0x800000 :
118+ p |= 0xff000000
119+ # Return the pressure value in hectopascals (divided by 100)
120+ return p / 100.0
121+
122+ def ReadAltitude (self ):
123+ # Send a conversion command with the specified oversampling rate configuration
124+ self .HP20X_IIC_WriteCmd (self .HP20X_WR_CONVERT_CMD | self .OSR_CFG )
125+ # Wait for the conversion time (converted to seconds)
126+ time .sleep (self .OSR_ConvertTime / 1000.0 )
127+ # Read 3 bytes of raw altitude data from the sensor
128+ a_raw = self .bus .read_i2c_block_data (self .address , self .HP20X_READ_A , 3 )
129+ # Combine the 3 bytes of data to form a single value
130+ a = a_raw [0 ] << 16 | a_raw [1 ] << 8 | a_raw [2 ]
131+ # Handle negative values using 2's complement
132+ if a & 0x800000 :
133+ a |= 0xff000000
134+ us = (1 << 32 )
135+ a = - 1 * (us - a )
136+ # Return the altitude value in meters (divided by 100)
137+ return a / 100.0
138+
139+ def HP20X_IIC_WriteCmd (self , uCmd ):
140+ # Write a command byte to the specified I2C address
141+ self .bus .write_byte_data (0 ,self .address ,uCmd )
142+
143+ def HP20X_IIC_ReadReg (self , bReg ):
144+ # Read a byte from the specified register address
145+ return self .bus .read_byte_data (self .address , bReg | self .HP20X_RD_REG_MODE )
146+
147+ # Class representing the Kalman filter
148+ class KalmanFilter :
149+ def __init__ (self ):
150+ # Process noise covariance
151+ self .q = 0.01
152+ # Measurement noise covariance
153+ self .r = 0.1
154+ # Initial estimated value
155+ self .x = 0
156+ # Initial estimated error covariance
157+ self .p = 1
158+ # Initial Kalman gain
159+ self .k = 0
160+
161+ def Filter (self , measurement ):
162+ # Prediction step: Update the estimated error covariance
163+ self .p = self .p + self .q
164+ # Update step: Calculate the Kalman gain
165+ self .k = self .p / (self .p + self .r )
166+ # Update step: Update the estimated value based on the measurement
167+ self .x = self .x + self .k * (measurement - self .x )
168+ # Update step: Update the estimated error covariance
169+ self .p = (1 - self .k ) * self .p
170+ # Return the filtered estimated value
171+ return self .x
172+
173+
174+ # Kalman filter for temperature data
175+ t_filter = KalmanFilter ()
176+ # Kalman filter for pressure data
177+ p_filter = KalmanFilter ()
178+ # Kalman filter for altitude data
179+ a_filter = KalmanFilter ()
180+
181+ # Create an instance of the HP20x sensor
182+ hp20x = HP20x ()
183+
184+
185+ # Function to simulate the setup process
186+ def setup ():
187+ print ("****HP20x_dev demo by seeed studio****\n " )
188+ print ("Calculation formula: H = [8.5(101325-P)]/100 \n " )
189+ # Wait for 0.15 seconds after power-on to stabilize the voltage
190+ time .sleep (0.15 )
191+ # Initialize the HP20x sensor
192+ hp20x .begin ()
193+ # Wait for 0.1 seconds
194+ time .sleep (0.1 )
195+ # Check if the HP20x sensor is available
196+ ret = hp20x .isAvailable ()
197+ if ret :
198+ print ("HP20x_dev is available.\n " )
199+ else :
200+ print ("HP20x_dev isn't available.\n " )
201+ return ret
202+
203+
204+ # Function to simulate the loop process
205+ def loop (ret ):
206+ if ret :
207+ while True :
208+ print ("------------------\n " )
209+ # Read the temperature value from the HP20x sensor
210+ temper = hp20x .ReadTemperature ()
211+ print ("Temper:" )
212+ print (f"{ temper } C.\n " )
213+ print ("Filter:" )
214+ # Apply the Kalman filter to the temperature value
215+ print (f"{ t_filter .Filter (temper )} C.\n " )
216+
217+ # Read the pressure value from the HP20x sensor
218+ pressure = hp20x .ReadPressure ()
219+ print ("Pressure:" )
220+ print (f"{ pressure } hPa.\n " )
221+ print ("Filter:" )
222+ # Apply the Kalman filter to the pressure value
223+ print (f"{ p_filter .Filter (pressure )} hPa\n " )
224+
225+ # Read the altitude value from the HP20x sensor
226+ altitude = hp20x .ReadAltitude ()
227+ print ("Altitude:" )
228+ print (f"{ altitude } m.\n " )
229+ print ("Filter:" )
230+ # Apply the Kalman filter to the altitude value
231+ print (f"{ a_filter .Filter (altitude )} m.\n " )
232+ print ("------------------\n " )
233+ # Wait for 1 second before the next reading
234+ time .sleep (1 )
235+
236+
237+ if __name__ == "__main__" :
238+ # Perform the setup process
239+ ret = setup ()
240+ # Start the loop process if the sensor is available
241+ loop (ret )
0 commit comments