pinewell's farmer blog 農業と電子工作、ソフトウェア、バイク、車

2023年2月5日

RasberryPi Picoでの水温計作成 その2

Filed under: その他 — pinewell @ 9:44 PM

DS18B20の取得はOneWireを使うと1つのGPIOで取得できる。

周りの明るさで輝度を調整したかったので、いつ買ったのかもわからないセンサーを接続した。

I2CでRTC。DS1307を用いた。

from machine import Pin, SPI,I2C,PWM
import gc9a01py as gc9a01
import onewire, ds18x20
import time,utime

from ds1307 import DS1307

# from fonts import vga1_8x8 as font
# from fonts import vga2_8x8 as font
# from fonts import vga1_8x16 as font
# from fonts import vga2_8x16 as font
# from fonts import vga1_16x16 as font
# from fonts import vga1_bold_16x16 as font
# from fonts import vga2_16x16 as font
# from fonts import vga2_bold_16x16 as font
# from fonts import vga1_16x32 as font
# from fonts import vga1_bold_16x32 as font
# from fonts import vga2_16x32 as font
# from fonts import vga2_bold_16x32 as font
# from fonts import vga2_bold_16x32 as fontB
# from truetype import NotoSerif_32 as fontC

from fonts import vga2_8x16 as fontA
from fonts import vga2_16x32 as fontB


def main():
    modePin=21  #時刻合わせモードに移行スイッチ
    upPin=20    #日付・時計あわせのアップスイッチ

    cds = machine.ADC(0) #明るさセンサー
    # 16bitの数値一単位での電圧値を設定します
    unit = 0.00005035477
    
    kurai = 20000  #暗いとき
    akarui = 65535 #明るいとき
    
    mode    = 0   #0:通常 1:時計合わせ 
    sec     = 0  #時計合わせの時のセクション 0:Year 1:month 2 day 3 hour 4 minute 
    uYear   = 0  #時計あわせようの値
    uMonth  = 0
    uDate   = 0
    uHour   = 0
    uMinute = 0

    swMode = machine.Pin(modePin,machine.Pin.IN,machine.Pin.PULL_DOWN) #スイッチの定義
    swUp   = machine.Pin(upPin,machine.Pin.IN,machine.Pin.PULL_DOWN)   #スイッチの定義

    pushStart =0 #押し始めた時間
    flgPush = False #押しているか
    pushInt = 0 #押されていた時間

    DSPIN = 19 #温度計のPin。onewire
    dsCnt = 0  #温度計の数
    ds_pin = machine.Pin(DSPIN)
    ds_sensor = ds18x20.DS18X20(onewire.OneWire(ds_pin)) #温度計を定義
    
    pw33 = machine.Pin(18,machine.Pin.OUT)   #RTCの3.3Vを得るため
    pw33.value(1)
    
    tokei=True #RTCが取得できたか?
    
    try:
      i2c_rtc = I2C(0,scl = Pin(17),sda = Pin(16),freq = 100000) #RTCの定義
      result = I2C.scan(i2c_rtc)
      #print(result)

      rtc = DS1307(i2c_rtc)
      #print(rtc.datetime())
      (year,month,date,day,hour,minute,second,p1)=rtc.datetime()
      
      if year==2000:#初期時は2000年となるのでその場合に 2023/2/2 12:00:00に設定
          year = 2023
          month = 2 
          date = 2 
          day = 4 
          hour = 12
          minute = 0
          second = 0
        
          now = (year,month,date,day,hour,minute,second,0)
          rtc.datetime(now)
    except:
        #print("not Tokei")  #RTCが取得できなかったら tokei非表示
        tokei=False
        
    o_ds = bytearray(b'(?\x9b8/!\x01\xd4') #温度計の個体を特定 外気温
    w_ds = bytearray(b'(\x07\x83t/!\x01(') #                 水温

    try:
        roms = ds_sensor.scan()  #センサーを取得
        dsCnt=len(roms)          #センサー数を得る
        for rom in roms:
            print('Found DS devices: ', rom)
    except:
        dsCnt = 0
    
    #液晶ディスプレイの定義
    spi = SPI(1, baudrate=60000000, sck=Pin(10), mosi=Pin(11))
    #tft = gc9a01.GC9A01( 
    #    spi,
    #    dc=Pin(8, Pin.OUT),
    #    cs=Pin(9, Pin.OUT),
    #    reset=Pin(12, Pin.OUT),
    #    backlight=Pin(25, Pin.OUT),
    #    rotation=0)
    tft = gc9a01.GC9A01(#バックライトはPWMで調整するので指定しない。
        spi,
        dc=Pin(8, Pin.OUT),
        cs=Pin(9, Pin.OUT),
        reset=Pin(12, Pin.OUT),
        rotation=0)
    
    
    #バックライトはPWMで調整
    pwm = PWM(Pin(25))
    pwm.freq(1000)
    pwm.duty_u16(akarui)
    #pwm.duty_u16(20000)

    tft.fill(gc9a01.WHITE)
    tft.fill_rect(0,0,240,60,gc9a01.RED)
    tft.text(fontB,"HONDA",80,20,gc9a01.WHITE,gc9a01.RED)
              
    while True:
        for i in range(100): #バックライトの明るさ調整
            # ADCの値を読み込みます(16bitの生の数値)
            voltRaw = cds.read_u16()
            #print("voltRaw:" + str(voltRaw))
            volt = voltRaw * unit
            #print( "volt:" + "{:.3f}".format(volt))
        if volt > 2:
            pwm.duty_u16(kurai)
        else:
            pwm.duty_u16(akarui)
 
        #モードスイッチが押されているか?
        if swMode.value() == 1:
            if flgPush :
                pushInt = time.time()-pushStart
            else:
                flgPush = True
                pushStart = time.time()
                pushInt = 0
        else:
            if flgPush :# すでに押されていて離した
                flgPush=False
                pushInt=time.time()-pushStart
                if pushInt > 2: #長押しされた
                    #print("long") 
                    if mode ==0: #時計合わせモードに移行
                        (uYear,uMonth,uDate,day,uHour,uMinute,second,p1)=rtc.datetime() #
                        mode=1
                        sec=0
                    else:   #時計合わせモードで長押し
                        if sec == 4:#分まで設定してたら時計合わせ終了
                            now = (uYear,uMonth,uDate,0,uHour,uMinute,0,0)
                            rtc.datetime(now)
                            sec=0
                            mode=0
                        else:#次のセクションへ移行
                            sec=sec+1
                else:
                    print("short") #短押しはなにもしない

        if swUp.value() == 1:
            if mode == 0: 
                (year,month,date,day,hour,minute,second,p1)=rtc.datetime()
                print(str(year)+"/"+str(month)+"/"+str(date) + "  " + str(hour)+":"+str(minute)+":"+str(second))
            else:
                if sec ==0:
                    uYear=uYear+1
                    if uYear>2100:
                        uYear=2023
                elif sec ==1:
                    uMonth=uMonth+1
                    if uMonth>12:
                        uMonth=1
                elif sec ==2:
                    uDate=uDate+1
                    if uDate>31:
                        uDate=1
                elif sec ==3:
                    uHour=uHour+1
                    if uHour>23:
                        uHour=0
                elif sec ==4:
                    uMinute=uMinute+1
                    if uMinute>59:
                        uMinute=0
                #print(str(uYear)+"/"+str(uMonth)+"/"+str(uDate) + "  " + str(uHour)+":"+str(uMinute)+":00")

        #温度の取得
        oTemp = 999.99
        wTemp = 999.99
        if dsCnt > 0 :
            ds_sensor.convert_temp()
            for rom in roms:
                if rom == o_ds :
                    oTemp = ds_sensor.read_temp(rom)
                else :
                    wTemp = ds_sensor.read_temp(rom)
        
        # 温度の表示
        tft.text(fontA,"WaterTemp",50,62,gc9a01.BLACK,gc9a01.WHITE)
        tft.text(fontB,"{:.2f}".format(wTemp),100,80,gc9a01.BLACK,gc9a01.WHITE)
        tft.text(fontA,"OutTemp",50,122,gc9a01.BLACK,gc9a01.WHITE)
        tft.text(fontB,"{:.2f}".format(oTemp),100,140,gc9a01.BLACK,gc9a01.WHITE)

        
        if mode ==0: #通常表示
            if tokei :
                (year,month,date,day,hour,minute,second,p1)=rtc.datetime()
        
                dateStr = "{0:04d}/ {1:02d}/ {2:02d}".format(year,month,date)
                tft.text(fontA,dateStr,85,190,gc9a01.BLACK,gc9a01.WHITE)
                timeStr = "{0:02d}:{1:02d}:{2:02d}".format(hour,minute,second)
                tft.text(fontA,timeStr,92 ,208,gc9a01.BLACK,gc9a01.WHITE)
                tft.text(fontA,"      ",85 ,174,gc9a01.BLACK,gc9a01.WHITE)
                
        else: #時計合わせ
            dateStr = "{0:04d}/ {1:02d}/ {2:02d}".format(uYear,uMonth,uDate)
            tft.text(fontA,dateStr,85,190,gc9a01.BLACK,gc9a01.WHITE)
            timeStr = "{0:02d}:{1:02d}:00".format(uHour,uMinute)
            tft.text(fontA,timeStr,92 ,208,gc9a01.BLACK,gc9a01.WHITE)
            if sec ==0:
                tft.text(fontA,"year  ",85 ,174,gc9a01.BLACK,gc9a01.WHITE)
            elif sec ==1:
                tft.text(fontA,"month ",85 ,174,gc9a01.BLACK,gc9a01.WHITE)
            elif sec ==2:
                tft.text(fontA,"date  ",85 ,174,gc9a01.BLACK,gc9a01.WHITE)
            elif sec ==3:
                tft.text(fontA,"hour  ",85 ,174,gc9a01.BLACK,gc9a01.WHITE)
            elif sec ==4:
                tft.text(fontA,"minute",85 ,174,gc9a01.BLACK,gc9a01.WHITE)
main()

これでスイッチ2個で外気温、水温、時計と照度計を用いた水温計が実現できる。

2023年1月29日

OrangePi zero2を用いた基準局設備

Filed under: GNSS — pinewell @ 9:31 PM

本来ならRaspberryPiを使いたいのだが入手困難な上、高額となってしまったため試行錯誤。

機能的には充分なOrangePi zero2にしてみた。お値段も手頃。

OSにはarmbianを選択。これとPX1122R-EVBをTX/RXで接続して基準局データを送信することができることを確認。

で、ケースをRaspberryPiと同じサイズにで作成すると上部に余ったスペースが出来た。

まぁケースを小くすることも考えたが、折角なのでOLEDの液晶とタクトスイッチをユニバーサル基板に半田付けして、と。

OLEDの液晶はSSD1306を用いたi2c接続で128×64の解像度。アマゾンでも買える。

まぁ、難儀しましたよ。Raspiと違って圧倒的に情報量が少ない。しかもOrangepi は種類が多くてサンプルがあってもzero2では動かないとか。

pythonのOPi.GPIOも結局まともに動作させられず、pythonからsubprocessを呼び出すなんて美しくない方法でタクトスイッチのON/OFFを取得せざるを得ず。

LCDにはIPアドレスと現在時刻。タクトスイッチの状態を表示。スイッチを5秒以上長押しでシャットダウンできるようにしてみた。

キモはWiringOPでのGPIOコマンドとタクトスイッチの状態を確定させるための10kΩプルダウン抵抗。

#!/usr/bin/env python                                             

import subprocess                                                 
import datetime                                                   
import time                                                       
from oled.device import ssd1306                                   
from oled.render import canvas                                    
from PIL import ImageFont                                         
                                                                  
import ipget                                                      
                                                                  
while True:                                                       
  try:                                                            
    target_ip = ipget.ipget()                                     
    ip = target_ip.ipaddr("eth0")                                 
    break;                                                        
  except:                                                         
    time.sleep(5)                                                 
                                                                                                                                   
device = ssd1306(port=3, address=0x3C)  # rev.1 users set port=0  
                                                                  
font = ImageFont.load_default()                                   

flgPush = False #押されているか                                      
pushStart =0 #押された時間                                           
pushInt = 0                                                          
onStr="OFF"                                                          
                                                                     
flgShutdown = False                                                  
                                                                     
result = subprocess.run(                                             
        "/usr/local/bin/gpio mode 2 in",shell=True,                  
        stdout=subprocess.PIPE,stderr=subprocess.PIPE,text=True)     

while True:                                                                              
    result = subprocess.run(                                                             
            "/usr/local/bin/gpio read 2",shell=True,                                     
            stdout=subprocess.PIPE,stderr=subprocess.PIPE,text=True)                     
    val=result.stdout[0:1]                                                               
    if val == "1" :                                                                      
        if flgPush : #既におされているか?                                               
          pushInt = time.time()-pushStart                                                
        else :                                                                           
          flgPush=True                                                                   
          pushStart = time.time()                                                        
          pushInt = 0                                                                    
        onStr="ON"                                                                       
    else:                                                                                
        if flgPush :#既におされていて離した                                              
          flgPush=False                                                                  
          pushInt = time.time()-pushStart                                                
          onStr="OFF"                                                                    
          if pushInt > 5 :                                                               
              flgShutdown = True                                                         
              onStr="Shutdown..."                                                        
        else :                                                                           
          flgPush=False
          pushInt = 0
          onStr="OFF"

    with canvas(device) as draw:
       font = ImageFont.load_default()
       draw.text((0, 0), ip   ,  font=font, fill=255)
       t_delta = datetime.timedelta(hours=9)
       JST = datetime.timezone(t_delta,'JST')
       now = datetime.datetime.now(JST)
       d=now.date().strftime('%Y/%m/%d')
       draw.text((0, 12),d  ,  font=font, fill=255)
       t=now.time().strftime('%X')
       draw.text((0, 24),t  ,  font=font, fill=255)

       draw.text((0, 40),onStr  ,  font=font, fill=255)
       if not flgShutdown :
         if pushInt>0:
           draw.text((40,40),'{:.2f}'.format(pushInt),font=font,fill=255)
    if flgShutdown :
        break
    time.sleep(0.3)

time.sleep(3)
with canvas(device) as draw:
  draw.rectangle((0, 0, device.width-1, device.height-1), outline=0, fill=0)

print("shutdown")
result = subprocess.run(
         "/usr/sbin/shutdown -h now",shell=True,
         stdout=subprocess.PIPE,stderr=subprocess.PIPE,text=True)

2023年1月26日

RasberryPi Picoでのメーター作成

Filed under: その他 — pinewell @ 2:01 PM

バイクの水温計を作成したい。

ついては以下の要件

1.水温

2.外気温

3.時計

4.振動センサーによる盗難防止ブザー

Waveshare RP2040-LCD-1.28 というものを購入した。

温度計のために GPIO 2つ

時計合わせのためのボタンに2つ。

RTCのI2Cに2つ。

6つの空きGPIOが必要。

2022年7月16日

NTRIP Caster SNIPの購入

Filed under: GNSS — pinewell @ 10:32 PM

基準局が3つになったのでLite版ではいろいろと使い辛く、BASICを購入。

実は2021/4/1に研究用として購入していたライセンスがある。この時は$851で購入。

2つのサーバーに使用するため今回追加で1ライセンスと思ったら$950に値上げされていた。円安も伴い、実際の請求はいくらになることやら。

PX1122Rでの5波対応基準局は上手く動いている。みちびき対応トリンブルで確認してもらったところ、QZSSを使用して補正されているとのこと。

GPS7500を使用した基準局をPX1122Rに置き換えるために「NS-HP-GN2 : PX1122R MULTI-BAND QUAD-GNSS RTK BREAKOUT BOARD」を発注。

こちらは$99。必要十分。

2022年6月29日

PX1122R を使用してのRTK基準局

Filed under: GNSS — pinewell @ 4:47 PM

NavSpark Store で購入したPX1122R-EVB が届いた。

早速自局の位置をRTKでFIX。そしてBaseモードにして基準局が設定できた。

ZED-F9PではできなかったGPS,GLONASS,QZSS,Galileo,Beidouの5波対応基準局となる。

AgLeaderにてFIXできることを確認。悲しい事にAgLeaderではGPSとGLONASSのみなので恩恵はまったくなし。

後日TrimbleなりのQZSSに対応したROVERで確認してみないと。

2021年1月18日

NtripCasterのロードバランサー

Filed under: GNSS — pinewell @ 11:01 PM

NtipCasterにSNIPを使用している。これはさくらのVPSでWindowsServerを借りての運用。耐障害性を考えて2台での運用していた。

2020年はそれぞれrtk1 とか rtk2 として接続先を変えていたのだが、本年より接続ユーザー数が30、クライアントとしては50台くらいにはなるのだろうか?

負荷分散を考えるに手動で設定するのは面倒。なのでロードバランサーの検討/導入となった。

単純にDNSラウンドロビンでも良いのだが、サーバーダウン時には対応が出来ないとなると二の足を踏んだ。

CentOSにてLVSとKeepalivedでの構築も考えたのだが(全て石狩データセンターなのでそれぞれがローカルでも繋っている)、ntripcasterはただのhttpサーバーとは違い、NtripServerからの基準局データを受け付けなければならず、これも断念。(実サーバーのdefaultgatewayがロードバランサーにしなければならず、globalIPでのntripserverの受付ができない。)

そこでさくらのクラウドにあるGSLB(広域負荷分散)を用いることとした。

NtripServerからの基準局データ送信は caster1.example.com と caster2.example.comとしてDNSにて登録されたglobalIPへ送信する。

NtripClientからは rtk.example.com としてDNSにてCNAMEされた GSLBのFQDNへ変換。さくらのGSLBに登録されている実サーバーのうち、適切なサーバーのglobalIPをクライアントに返すように設定ができた。

料金は月額550円。これは安い!

2021年1月16日

NTRIP 接続

Filed under: GNSS — pinewell @ 2:24 PM

ntripcaster 0.1.5 を使用してlinux鯖によるrtk配信サービスを構築するつもり。

”Lefebure NTRIP Client”での接続でローカル環境でのテストではOKなのにインターネット上のサーバーに接続すると認証エラーでつながらない。

ソースから main.c のinfo.logfiledebuglevel = 0 を 9にして全デバッグ情報を確認すると どういうわけか接続時の文字列の分解に失敗しているよう。

[Authorization] == [Basic XXXXXXXXXXXXXXXX] が取得できていない。

[Connectiotion] == [Basic XXXXXXXXXXXXXXXX]になってしまっているので client.c をいじって [Authorization]の取得に失敗していたら [Connectiotion]の値を使って認証させるように(場当たり的ではあるが)修正した。

AgLeaderではどうかと思い確認すると[Authorization] == [Basic XXXXXXXXXXXXXXXX]が無事取得できているのでまぁよし。

GET /AGS HTTP/1.0
User-Agent: NTRIP AgLeader/1.0 (InCommand)
Host: 192.168.1.254
Authorization: Basic XXXXXXXXXXXX

[16/Jan/2021:13:57:58] [4:Connection Handler] DEBUG: Building request out of [GET /AGS HTTP/1.0]
[16/Jan/2021:13:57:58] [4:Connection Handler] DEBUG: Building clean request from [/AGS]
[16/Jan/2021:13:57:58] [4:Connection Handler] DEBUG: Adding varpair [User-Agent] == [NTRIP AgLeader/1.0 (InCommand)]
[16/Jan/2021:13:57:58] [4:Connection Handler] DEBUG: Building request out of [Host: 192.168.1.254]
[16/Jan/2021:13:57:58] [4:Connection Handler] DEBUG: Adding varpair [Authorization] == [Basic XXXXXXXXXXXX]
[16/Jan/2021:13:57:58] [4:Connection Handler] DEBUG: Checking need for authentication on mount /AGS

 

GET /AGS HTTP/1.0
User-Agent: NTRIP LefebureAndroidIntNTRIPClient/20200406
Accept: */*
Connection: close
Authorization: Basic XXXXXXXXXXXX

[15/Jan/2021:14:48:04] [3:Connection Handler] DEBUG: Building request out of [GET /AGS HTTP/1.0]
[15/Jan/2021:14:48:04] [3:Connection Handler] DEBUG: Building clean request from [/AGS]
[15/Jan/2021:14:48:04] [3:Connection Handler] DEBUG: Adding varpair [User-Agent] == [NTRIP LefebureAndroidIntNTRIPClient/20200406]
[15/Jan/2021:14:48:04] [3:Connection Handler] DEBUG: Adding varpair [Accept] == [*/*]
[15/Jan/2021:14:48:04] [3:Connection Handler] DEBUG: Adding varpair [Connectiotion] == [Basic XXXXXXXXXXXX]
[15/Jan/2021:14:48:04] [3:Connection Handler] WARNING: Invalid header line [XXXXXXXXXXXX] without colon
[15/Jan/2021:14:48:04] [3:Connection Handler] DEBUG: Checking need for authentication on mount /AGS

 

簡単に修正できたように書いているが辿り着くまでは困難だった。

なにせローカルでは問題ないので苦もなく動くものと思いこんでいました。

それにしても[Connectiotion]って?再現性はあるのでもう少しスマートな修正もできるのでしょうが、C言語は不得手で。

2020年12月3日

Windows10のタッチキーボードが勝手にでる

Filed under: 未分類 — pinewell @ 11:02 PM

ウチの環境がやや特殊なのであまり参考にならないかもしれませんが、気になっていたことが解決できたのでメモ。

ArduinoIDE や AndroidStudio でテキストエディタにフォーカスインするといちいちタッチキーボード(スクリーンキーボードではなく)が出現してしまう。

とりあえず、「 Touch Keyboard and Handwriting Panel Service 」のサービスをとめて事なきを得ていたのだが最近のWindows10Pro20H2になるとこのサービスを切ってしまうとIME自体が動かなくなる事態となった。

解決策を模索していたのだが検索をかけるも情報が少ない。どうやらウチの環境が特殊なようだと思い、ふと気づく。キーボードを繋いでいないのである。

Linuxサーバー側に接続しているキーボードを Synergyで運用しているので物理的なキーボードを繋いでいないことに思い至る。実際にキーボードを繋いでみると現象がでないことが確認できた。

さてと、使わないキーボードを無駄に接続するのはイヤ。Arduinoでキーボードのフリをするデバイスでも作ろうかとも思ったが改めて検索。

「キーボードが接続されていないときにタッチキーボードを表示する」という設定がどこかにあることが分かった。しかし、「スタート」「設定」「デバイス」「入力」と進んでもこの設定が無い。

キーボード詳細設定やその他を探し回ったが見つけることができず。試しに「設定の検索」に「タブレット」と入れてみると「タブレット設定」が現れた。ここから更に「タブレットの追加設定を変更する」に進むと漸く「キーボードが接続されて…」の設定が変更できた。

そもそも私のPCでは「タブレットモード」にすることができない。先述の設定画面には「このデバイスにはタッチ機能はありません。」と赤字で表示されていることからタッチデバイスがあるとタブレットとしても機能すると判断しているのか?タッチ機能があるとタブレットモードの設定も表示されることになるのだろう。

それにしても「タブレットモードを使用していないとき」の設定がデスクトップで使用しているPCでは、ずいぶん深~いところから発掘せにゃならないとは。

この設定を探すのに2時間は無駄にしたよ。トホホ。

2020年4月17日

カッティングプランターの欠株センサー

Filed under: 澱原イモ — pinewell @ 10:43 PM

距離センサーをアナログで行うとして。
リセットスイッチ x 1
ブザー x4
ヒゲセンサー x 4
測距 x4
が必要。デジタル入力5 デジタル出力 4 アナログ入力 4。
I2Cで液晶を繋いでもピン自体は間に合いそうだ。

2020年4月15日

カッティングプランターの欠株センサー

Filed under: 澱原イモ — pinewell @ 10:41 PM

要件
リミットスイッチにより距離センサーを作動させカップ迄の距離を測距。
設定値以上ならば種芋が無いとしてブザーを鳴らす(短く)。
欠株が続けて起きた場合(2以上?3以上?)ブザーを鳴らす(ストップボタンが押されるまで)

懸念
4畝を一つのarduinoで実現可能か?
測距モジュールはアナログ?i2c?レーザー?超音波?

展望
欠株がわかれば供給もしたくなる…。
コンベアは大掛かりで嫌。ステッピングモーターで可能か?

« Newer PostsOlder Posts »

Powered by WordPress