前回の続き。
土壌水分センサーがなんとなくうまく動いていないさそう。ということで、ちょっとコードを追っかけてみた。
公式サンプルコード
Python全然わからないけど、
- get_adcで各センサの電圧値を取得
- valmapに電圧値を渡してパーセンテージ変換
してるように見える。
def valmap(value, istart, istop, ostart, ostop): value = ostart + (ostop - ostart) * ((value - istart) / (istop - istart)) if value > ostop: value = ostop return value
moisture1 = round(valmap(sensor1, 5, 3.5, 0, 100), 0)
5Vなら0%、3.5Vなら100%、というように考えて、センサー値のパーセンテージを算出してるみたいなんだけど、この5
と3.5
はどこから算出された数字なのかな?
soil-moistore-sensors.pyから余計なものを取っ払ってセンサーの電圧値だけを表示するコードを書いてみた。
import signal import sys import time import spidev spi_ch = 0 # Enable SPI spi = spidev.SpiDev(0, spi_ch) spi.max_speed_hz = 1200000 def close(signal, frame): sys.exit(0) signal.signal(signal.SIGINT, close) def get_adc(channel): # Make sure ADC channel is 0 or 1 if channel != 0: channel = 1 # Construct SPI message # First bit (Start): Logic high (1) # Second bit (SGL/DIFF): 1 to select single mode # Third bit (ODD/SIGN): Select channel (0 or 1) # Fourth bit (MSFB): 0 for LSB first # Next 12 bits: 0 (don't care) msg = 0b11 msg = ((msg << 1) + channel) << 5 msg = [msg, 0b00000000] reply = spi.xfer2(msg) # Construct single integer out of the reply (2 bytes) adc = 0 for n in reply: adc = (adc << 8) + n # Last bit (0) is not part of ADC value, shift to remove it adc = adc >> 1 # Calculate voltage form ADC value # considering the soil moisture sensor is working at 5V voltage = (5 * adc) / 1024 return voltage if __name__ == '__main__': # Report the channel 0 and channel 1 voltages to the terminal try: while True: adc_0 = get_adc(0) adc_1 = get_adc(1) sensor1 = round(adc_0, 2) sensor2 = round(adc_1, 2) print("Soil Moisture Sensor 1:", sensor1, " Soil Moisture Sensor 2:", sensor2) time.sleep(0.5) except: KeyboardInterrupt
実行してみた。Sensor 1の方。まず水につけない場合。
$ python test-soil-moistore-sensors.py Soil Moisture Sensor 1: 3.58 Soil Moisture Sensor 2: 0.0 Soil Moisture Sensor 1: 3.57 Soil Moisture Sensor 2: 0.01 Soil Moisture Sensor 1: 3.57 Soil Moisture Sensor 2: 0.01 Soil Moisture Sensor 1: 3.57 Soil Moisture Sensor 2: 0.01 Soil Moisture Sensor 1: 3.57 Soil Moisture Sensor 2: 0.01 Soil Moisture Sensor 1: 3.57 Soil Moisture Sensor 2: 0.01 Soil Moisture Sensor 1: 3.57 Soil Moisture Sensor 2: 0.01 Soil Moisture Sensor 1: 3.58 Soil Moisture Sensor 2: 0.01 Soil Moisture Sensor 1: 3.58 Soil Moisture Sensor 2: 0.01 Soil Moisture Sensor 1: 3.57 Soil Moisture Sensor 2: 0.01 (...snip...)
水につけた場合。
$ python test-soil-moistore-sensors.py Soil Moisture Sensor 1: 1.9 Soil Moisture Sensor 2: 0.0 Soil Moisture Sensor 1: 1.9 Soil Moisture Sensor 2: 0.01 Soil Moisture Sensor 1: 1.9 Soil Moisture Sensor 2: 0.01 Soil Moisture Sensor 1: 1.9 Soil Moisture Sensor 2: 0.01 Soil Moisture Sensor 1: 1.9 Soil Moisture Sensor 2: 0.01 Soil Moisture Sensor 1: 1.89 Soil Moisture Sensor 2: 0.02 Soil Moisture Sensor 1: 1.9 Soil Moisture Sensor 2: 0.01 Soil Moisture Sensor 1: 1.9 Soil Moisture Sensor 2: 0.01 Soil Moisture Sensor 1: 1.9 Soil Moisture Sensor 2: 0.01 Soil Moisture Sensor 1: 1.89 Soil Moisture Sensor 2: 0.01 Soil Moisture Sensor 1: 1.9 Soil Moisture Sensor 2: 0.0 Soil Moisture Sensor 1: 1.9 Soil Moisture Sensor 2: 0.0 (...snip...)
REPLでvalmapを実行してみる。
$ python Python 3.9.2 (default, Mar 12 2021, 04:06:34) [GCC 10.2.1 20210110] on linux Type "help", "copyright", "credits" or "license" for more information. >>> def valmap(value, istart, istop, ostart, ostop): ... value = ostart + (ostop - ostart) * ((value - istart) / (istop - istart)) ... if value > ostop: ... value = ostop ... return value ... >>> print(round(valmap(3.67, 5, 3.5, 0, 100),0)) 95.0 >>> print(round(valmap(1.9, 5, 3.5, 0, 100),0)) 100
うーん、この計算だと、水分0のときでも95%ぐらいになってしまうよね・・・
さすがにget_adcの中を読み解くのは電子工作初心者には厳しいし、何が間違っているのかはわからないけど、とりあえず実際の値を踏まえて算出するように書き換えてみる。
import signal import sys import time import spidev import RPi.GPIO as GPIO # Pin 15 on Raspberry Pi corresponds to GPIO 22 LED1 = 15 # Pin 16 on Raspberry Pi corresponds to GPIO 23 LED2 = 16 MAX=3.57 MIN=1.91 spi_ch = 0 # Enable SPI spi = spidev.SpiDev(0, spi_ch) spi.max_speed_hz = 1200000 # to use Raspberry Pi board pin numbers GPIO.setmode(GPIO.BOARD) GPIO.setwarnings(False) # set up GPIO output channel GPIO.setup(LED1, GPIO.OUT) GPIO.setup(LED2, GPIO.OUT) def close(signal, frame): GPIO.output(LED1, 0) GPIO.output(LED2, 0) sys.exit(0) signal.signal(signal.SIGINT, close) def valmap(value, istart, istop, ostart, ostop): value = ostart + (ostop - ostart) * ((value - istart) / (istop - istart)) if value > ostop: value = ostop if value < ostart: value = ostart return value def get_adc(channel): # Make sure ADC channel is 0 or 1 if channel != 0: channel = 1 # Construct SPI message # First bit (Start): Logic high (1) # Second bit (SGL/DIFF): 1 to select single mode # Third bit (ODD/SIGN): Select channel (0 or 1) # Fourth bit (MSFB): 0 for LSB first # Next 12 bits: 0 (don't care) msg = 0b11 msg = ((msg << 1) + channel) << 5 msg = [msg, 0b00000000] reply = spi.xfer2(msg) # Construct single integer out of the reply (2 bytes) adc = 0 for n in reply: adc = (adc << 8) + n # Last bit (0) is not part of ADC value, shift to remove it adc = adc >> 1 # Calculate voltage form ADC value # considering the soil moisture sensor is working at 5V voltage = (5 * adc) / 1024 return voltage if __name__ == '__main__': # Report the channel 0 and channel 1 voltages to the terminal try: while True: adc_0 = get_adc(0) adc_1 = get_adc(1) sensor1 = round(adc_0, 2) if sensor1 < 0.5: moisture1 = 0 else: moisture1 = round(valmap(sensor1, MAX, MIN, 0, 100), 0) sensor2 = round(adc_1, 2) if sensor2 < 0.5: moisture2 = 0 else: moisture2 = round(valmap(sensor2, 5, 3.5, 0, 100), 0) print(f"Soil Moisture Sensor 1: {moisture1}% ({sensor1}) Soil Moisture Sensor 2: {moisture2}% ({sensor2})") if moisture1 < 40 or moisture2 < 40: GPIO.output(LED1, 1) GPIO.output(LED2, 0) else: GPIO.output(LED1, 0) GPIO.output(LED2, 1) time.sleep(0.5) finally: GPIO.cleanup()
テストで算出した電圧の最大値・最小値を定義しておいて、それに比例したパーセンテージを出すようにしてみた。最大値・最小値の範囲を超えるものはカットしてる。ついでに電圧も表示するようにした。
水につけていない状態。
$ python soil-moistore-sensors.py Soil Moisture Sensor 1: 1.0% (3.56) Soil Moisture Sensor 2: 0% (0.0) Soil Moisture Sensor 1: 1.0% (3.56) Soil Moisture Sensor 2: 0% (0.01) Soil Moisture Sensor 1: 1.0% (3.56) Soil Moisture Sensor 2: 0% (0.01) Soil Moisture Sensor 1: 1.0% (3.56) Soil Moisture Sensor 2: 0% (0.01) Soil Moisture Sensor 1: 1.0% (3.56) Soil Moisture Sensor 2: 0% (0.01) Soil Moisture Sensor 1: 1.0% (3.56) Soil Moisture Sensor 2: 0% (0.0) Soil Moisture Sensor 1: 1.0% (3.56) Soil Moisture Sensor 2: 0% (0.0) Soil Moisture Sensor 1: 1.0% (3.56) Soil Moisture Sensor 2: 0% (0.01) Soil Moisture Sensor 1: 1.0% (3.56) Soil Moisture Sensor 2: 0% (0.01) Soil Moisture Sensor 1: 1.0% (3.56) Soil Moisture Sensor 2: 0% (0.01) Soil Moisture Sensor 1: 1.0% (3.56) Soil Moisture Sensor 2: 0% (0.01)
$ python soil-moistore-sensors.py Soil Moisture Sensor 1: 99.0% (1.93) Soil Moisture Sensor 2: 0% (0.01) Soil Moisture Sensor 1: 99.0% (1.93) Soil Moisture Sensor 2: 0% (0.01) Soil Moisture Sensor 1: 99.0% (1.93) Soil Moisture Sensor 2: 0% (0.01) Soil Moisture Sensor 1: 99.0% (1.93) Soil Moisture Sensor 2: 0% (0.01) Soil Moisture Sensor 1: 99.0% (1.93) Soil Moisture Sensor 2: 0% (0.0) Soil Moisture Sensor 1: 99.0% (1.93) Soil Moisture Sensor 2: 0% (0.0) Soil Moisture Sensor 1: 99.0% (1.93) Soil Moisture Sensor 2: 0% (0.01) Soil Moisture Sensor 1: 98.0% (1.94) Soil Moisture Sensor 2: 0% (0.01) Soil Moisture Sensor 1: 99.0% (1.93) Soil Moisture Sensor 2: 0% (0.01) Soil Moisture Sensor 1: 99.0% (1.93) Soil Moisture Sensor 2: 0% (0.01) Soil Moisture Sensor 1: 99.0% (1.93) Soil Moisture Sensor 2: 0% (0.01)
もうちょっと細かく詰めないといけないと思うけど、とりあえずそれっぽい数字にはなったんじゃないかなー。センサーの値があんまり安定しないけど、まあそんなシビアなものでもないのでこれで十分かなという気がしてる。
Pythonほとんど書かないけど、見様見真似でなんとかなるもんだ。
参考
とても参考になりました。