0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

使用したパーツ

使用したライブラリ

使用したマイコン

今回はRaspberry Pi Picoを使いましたが、ESP32STM32等、MicroPythonが使えるマイコンであればどれでもできます。使用するマイコンに合わせてGPIOピンを変更してください。

スピードの求め方

ハバーサイン(Haversine)の公式を用いて、2地点の緯度・経度と移動時間から対地速度(km/h)を計算します。
GPSモジュールから、1秒間隔で現時点の緯度・経度が得られるので、これを利用します。

Pythonコード

import math
import time
from tm1637 import TM1637
from machine import Pin

from machine import UART
from micropyGPS import MicropyGPS
import gc

gps = MicropyGPS(local_offset=9, location_formatting='dd')

uart = UART(0, 9600) # TX:GP0, RX:GP1

tmClkPin = Pin(2, Pin.IN)
tmDioPin = Pin(3, Pin.IN)
tm = TM1637(clk=tmClkPin, dio=tmDioPin)

def calculate_ground_speed(lat1, lon1, lat2, lon2, seconds=1):
    """
    2地点の緯度・経度と移動時間から対地速度(km/h)を計算する関数
    (Haversineの公式を使用)
    """
    # 地球の平均半径 (km)
    R = 6371.008
    
    # 緯度・経度をラジアンに変換
    lat1_rad = math.radians(lat1)
    lon1_rad = math.radians(lon1)
    lat2_rad = math.radians(lat2)
    lon2_rad = math.radians(lon2)
    
    # 緯度・経度の差分
    dlat = lat2_rad - lat1_rad
    dlon = lon2_rad - lon1_rad
    
    # Haversineの公式による2点間の球面距離計算
    a = math.sin(dlat / 2)**2 + math.cos(lat1_rad) * math.cos(lat2_rad) * math.sin(dlon / 2)**2
    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
    distance_km = R * c
    
    # 秒速(km/s)を時速(km/h)に変換 (1h = 3600s)
    ground_speed_kmh = (distance_km / seconds) * 3600
    
    return ground_speed_kmh


prev_lat, prev_lon = 0, 0
tm.write(tm.encode_string('----'))

smoother = SmootherMicro(window_size=3)

def received_message(uart):
    global prev_lat, prev_lon
    received_txt = uart.read()
    if received_txt is None: return
    #print(received_txt)
    for char in received_txt:
        state = gps.update(chr(char))
        if state == 'GPGGA':
            dt, ts = gps.date, gps.timestamp
            yy = "" if dt[2]==0 else "19" if dt[2]>79 else "20"
            print('------------------')
            print(f'{yy}{dt[2]:02d}/{dt[1]:02d}/{dt[0]:02d} {ts[0]:02d}:{ts[1]:02d}:{ts[2]:04.1f}')        
            print(f'latitude: {gps.latitude[0]}, longitude: {gps.longitude[0]}, altitude: {gps.altitude}')
            print("satellites_used:", gps.satellites_used)
            if prev_lat != 0 and prev_lon != 0:
                spd = calculate_ground_speed(prev_lat, prev_lon, gps.latitude[0], gps.longitude[0])
                spd = min(999.0, spd)
                print(spd, 'km/h')
                tm.number(int(spd))
            else:
                tm.write(tm.encode_string('----'))
                
            prev_lat, prev_lon = gps.latitude[0], gps.longitude[0]

uart.irq(handler=received_message, trigger=UART.IRQ_RXIDLE)

while True:
    time.sleep(10)
    gc.collect()
   

実行ログ

屋内で実行:緯度・経度が暴れる(測位誤差)ため、速度>0のときがあります
(小数点以下は伏せています)

------------------
2026/07/19 16:40:22.0
latitude: 35.9999 , longitude: 139.9999 , altitude: 21.9
satellites_used: [24, 10, 23, 25]
0.0 km/h
------------------
2026/07/19 16:40:23.0
latitude: 35.9999 , longitude: 139.999 , altitude: 21.9
satellites_used: [24, 10, 23, 25]
1.36707 km/h
------------------
2026/07/19 16:40:24.0
latitude: 35.9999 , longitude: 139.999 , altitude: 21.9
satellites_used: [24, 10, 23, 25]
1.36707 km/h
------------------
2026/07/19 16:40:25.0
latitude: 35.9999 , longitude: 139.999 , altitude: 21.9
satellites_used: [24, 10, 23, 25]
0.0 km/h
------------------
2026/07/19 16:40:26.0
latitude: 35.9999 , longitude: 139.999 , altitude: 21.9
satellites_used: [24, 10, 23, 25]
0.0 km/h
------------------
2026/07/19 16:40:27.0
latitude: 35.9999 , longitude: 139.999 , altitude: 21.9
satellites_used: [24, 10, 23, 25]
2.73414  km/h

GPSのデータシートによると『測位確度 : 2m』となっていますが、屋内での利用では精度が落ちるのだと思います。

DOTは使えない

IMG_8540-2.png

今回使用した4桁7セグLEDは、各桁にDOT(DP)が見えるが、光りません。
左から2桁目のDOTを指定すると、中央のコロン(:)が光ります。

5643B.png

使われているLED表示器は5643BGという型番です。データシートを見ると、各桁のDOTと中央のコロンは、すべて 5番ピンに接続されている回路図となっています。
この結線が本当ならDOTも光るハズです。

(TM1637を通さずに)直接ピンに信号を与えて確認したが、どの桁のDOTも光らなかった(DIG2のDPのみ中央のコロンが光った)。上記回路図の誤りではないか、と推測します。

DOTが使えるLED表示器

一例だが、次の商品が見つかった。

使われているLED表示器は5643BGという型番です。

Pinoutが同じ5461BGに入れ替えてみました。
問題なく、各桁のDOTを独立して光らせることができました。

IMG_8778.jpeg

tm1637.pyライブラリを使って浮動小数点を表示する場合は、前述のコードを少し変更する必要があります。

- from tm1637 import TM1637
+ from tm1637 import TM1637Decimal

- tm = TM1637(clk=tmClkPin, dio=tmDioPin)
+ tm = TM1637Decimal(clk=tmClkPin, dio=tmDioPin)

-                 tm.number(int(spd))
+                 tm.write(tm.encode_string(f'{spd:5.1f}'))

自動車なら少数点以下は不要でしょうが、徒歩やマラソンなら知りたいかも??

IMG_8777.jpeg


追伸;
 この装置を屋外に持ち出して歩いてみましたが、晴天昼間だとLEDが光っているのか見づらく視認性が低いです。


以上

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?