virt_flyのブログ -3ページ目

virt_flyのブログ

フライトシミュレーターソフトのFlightGearで仮想飛行を楽しむブログです。

Raspberry Pi PicoとOLEDでPFD表示

↑代り映えしない絵柄です せめてRaspberry Pi PicoにかえてRP2040₋Zeroを使用

 

USB接続、0.96インチOLED

USB接続にはバッチファイルがあるとよい

 

■USB接続が通常―Wi-Fi接続との違い

 

Wi-Fi接続は楽で良いのですが、リアルなコクピットを作る場合は有線接続が通常かと思われますので、パソコンにRaspberry Pi PicoをUSB接続してOLED表示を試すことにしました。

 

USBはシリアル通信ですが、FlightGearは対応していませんから、パソコンでチェンジするPC-ブリッジプログラムが間に1枚かます必要があります。

 

【構成の比較】

 

Wi-Fi接続 USB接続
FlightGear
  ↓ UDP
PCブリッジ(Python)
  ↓ USB
Pico
  ↓
OLED
FlightGear
  ↓ UDP
Wi-Fi
  ↓
Rasopberry Pi Pico W
  ↓ I2C
OLED

 

■必要なものと手順

 

Pythonの利用が前提です。Raspberry Pi PicoはMicroPythonの使用が前提です。

 

【ハード】

 

・Raspberry Pi Pico、同互換機…マイクロコントローラーのRaspberry Pi Pico,ならびに互換機RP2400₋Zeroを使用

 

・OLEDディスプレイ…手持ちの0.96インチ4ピンI2C対応 ドライバSSD1306またはSSD1315

 

・他…工作用にブレッドボード、ジャンパー線など

 

OLEDとPico Wとの配線は次の通り

 

OLED Pico W
VCC 3.3V(Pin 36)
GND GND(Pin 38など)
SCL GP1(Pin 2)
SDA GP0(Pin 1)

 

RP2040-ZeroでOLED表示

↑FlightGearが動くPCとUSB接続したRP2040₋ZeroでミニPFD

 

【ソフト】

 

・fgdata.xml

 

プロトコルを記述したこのfgdata.xmlファイルは、前回と同じもの。詳しくは、前回を参照のこと。このファイルを、FlightGearのデータファルダ内のProtocolサブフォルダに置く(C:/Users/virt_fly/FlightGear/Downloads/fgdata_2024_1/Protcol/fgdata.xml)のも同様です。


・main.py

 

Picoにインストールするmain.pyです。

 

import sys from machine import Pin, I2C
import ssd1306
import time
import math

# ---------- OLED ----------

WIDTH = 128
HEIGHT = 64

i2c = I2C(0, scl=Pin(1), sda=Pin(0), freq=400000)
oled = ssd1306.SSD1306_I2C(WIDTH, HEIGHT, i2c)

speed = 0
alt = 0
heading = 0
pitch = 0
roll = 0

# ---------- 速度テープ ----------

def draw_speed_tape():

  center = int(speed/10)*10

  for i in range(-3,4):

    v = center + i*10
    y = 32 - i*8

    if 10 < y < 56:
      oled.text(str(v),0,y,1)

  oled.text(">",24,32,1)
  oled.text("SPD",8,56,1)

# ---------- 高度テープ ----------

def draw_alt_tape():

  center = int(alt/10)*10

  for i in range(-3,4):

    v = center + i*10
    y = 32 - i*8

    if 10 < y < 56:
      oled.text(str(v),96,y,1)

  oled.text("<",88,32,1)
  oled.text("ALT",88,56,1)

# ---------- 方位テープ ----------

def draw_heading():

  center = int(heading/10)*10

  for i in range(-6,7):

     h = (center + i*10) % 360
     x = 64 + i*10

     if 5 < x < 120:

       if h % 30 == 0:
         oled.text(str(h), x-6, 0, 1)

       else:
         oled.pixel(x,6,1)

  oled.text("^",62,10,1)
  oled.text("HDG",54,16,1)

# ---------- 水平儀 ----------

def draw_horizon():

  cx = 64
  cy = 36

  r = math.radians(-roll)

  length = 80

  x1 = int(cx - length*math.cos(r))
  y1 = int(cy - length*math.sin(r) + pitch)

  x2 = int(cx + length*math.cos(r))
  y2 = int(cy + length*math.sin(r) + pitch)

  oled.line(x1,y1,x2,y2,1)

  # 機体マーク
  oled.line(cx-6,cy,cx+6,cy,1)

# ---------- メインループ ----------

while True:

  try:

    line = sys.stdin.readline().strip()

    parts = line.split(",")

    speed = float(parts[0])
    alt = float(parts[1])
    heading = float(parts[2])
    pitch = float(parts[3])
    roll = float(parts[4])

  except:
    pass

  oled.fill(0)

  draw_heading()
  draw_speed_tape()
  draw_alt_tape()
  draw_horizon()

  oled.show()


・FlightGearの起動オプション

 

(起動はGUIに書き込んでOK)
 

--generic=socket,out,10,127.0.0.1,5501,udp,fgdata

 

・fg-pc_bridge.py

 

FlightGear側Pythonプログラムであるfg-pc_bridge.pyは、 C:/Users/virt_fly/desktopに置くのも楽です。なお、CMD(コマンドプロンプト)から起動してもよいのですが、FlightGearの起動と同時に自動起動するバッチファイルを用意した方が楽でしょう。次項に記します。

 

import socket
import serial

# PicoのCOMポート
ser = serial.Serial("COM10",115200)

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(("127.0.0.1",5501))

print("Bridge start")

while True:

  data, addr = sock.recvfrom(1024)

  ser.write(data)

 

※注意 PicoのCOMポートとfg-pc_bridge.pyで指定するCOMポートが一致しているかあらかじめ確認が大事です。Picoやその互換機によりCOMポートは異なるため、違っていればポート番号を書き改めることが必要です。

 
・start_fg.bat

 

バッチファイルです。C:/Users/virt_fly/desktopに置きます。このバッチファイルをダブルクリックすれば、FlightGearの起動と同時に先のパイソンプログラムfg-pc_bridge.pyも自動起動します。

 

@echo off
echo Checking FlightGear bridge...

tasklist | find /i "python.exe" | find /i "fg-pc_bridge.py" >nul

if %errorlevel%==0 (
  echo Bridge already running
) else (
  echo Starting bridge
  start /min python C:\Users\virt_fly\desktop\fg-pc_bridge.py
)

echo Starting FlightGear...

"C:\Program Files\FlightGear 2024.1\bin\fgfs.exe" ^
--fg-root="C:/Users/virt_fly/FlightGear/Downloads/fgdata_2024_1" ^
--fg-aircraft="C:/Users/virt_fly/FlightGear/Custom Aircraft" ^
--aircraft=F1M2 ^
--airport=RJBB ^
--runway=24L ^
--generic=socket,out,30,127.0.0.1,5501,udp,fgdata

 

 

※ここで示したプログラムはCopilotとChatGPTの助けを借りて作成しています。

 

 

《関連》

 

 

 

 

 

 

 

 

 

Pico WでPFD作成!FlightGearデータで水平儀が動く

↑Pico Wを使ったミニPFDができました Wi-Fiで届いたFlightGearのデータをもとに水平儀が動くのは楽しい

 

Wi-Fi接続、0.96インチOLED表示、ミニPFD

操縦がしやすいのはテープ式表示の計器

 

前回の当ブログでは、FlightGearのデータを引き出してRaspberry Pi Pico WによりOLED画面に速度と高度、方位の値が表示できたことを取り上げました。

 

しかし、数字だけのデジタル表示では、リアルタイムであっても変化が速すぎる場合には、数値が読み取れないことがしばしばで、これでは気が付けば墜落にもなりかねず、計器としては何の役にも立たないことになります。

 

もう少し使い勝手の良い表示形式を検討することにしました。

 

■異なる表示形式を試す

 

・バー形式はする意味がない

 

テープ式計器表示のフライトディスプレイ

↑OLED画面上部の横のバーが速度、右端の縦のバーが高度

 

速度と高度の表示をバー形式にしてみました。バーにしたから何なのさです。結果として、バー表示は操縦にななんの意味も感じられないものでした。

 

・テープ形式は小さな画面には不向き

 

テープ式計器表示:速度、高度、方位

↑OLED画面の描画のタイミングで、方位の表示が欠けています 左右の速度と高度の数値目盛が上下します

 

計器が数字やバー表示では、機体をどれ位傾けたらよいか、どの程度でやめようかという加減がつかめません。計器がテープ形式で、針が固定に対して目盛りが動く方が、その動きの緩急で微妙な加減ができて格段と操縦がしやすくなるはずです。

 

しかし、今回はOLED画面が小さいために目盛りの間隔が大きく取れず、速度(①)も高度(②)も疑似的とは言わないまでも数値目盛りだけのテープ形式にとどまり、実際のところただ数字が並んで動くだけでは、微妙な目盛りの動きが再現できず、残念ながら操縦に役立ちません。小さい画面にはテープ形式の表示は不向きと言わざるをえません。

 

なお、方位はコンパス(③)にしてみました。

 

・ミニPFD は見て楽しむ分にはよいが

 

PFD表示:速度・高度・方位・水平儀

↑ミニPFDという感じのOLED画面

 

OLED画面が小さくて、計器が3つともなれば、十分なものはできないというのに、勢いでさらに中央に水平儀様のものまで設けて、ちょっとしたPFD(Primary Flight Display)化になりました。

 

左上が速度(①)、右上が高度(②)、一番下が方位(③)を示し、中央が簡素な水平儀(ATI)になっていて、ライン状の地平線(④)と機体のマーク(⑤)が表示されます。写真では、左旋回しながら上昇中であることがわかります。

 

見て楽しむ分にはよいのですが、速度や高度などが数値表示ではやはり実用的ではありません。

 

■水平儀とテープ式計器


・HUD風ミニPFD

 

ミニPFD 速度・高度・方位・水平儀表示

↑ミニPDFをHUD風に

 

PDF化するなら、速度や高度、方位もテープ式表示にして、水平儀の周囲に配置したい。そうすることで、慣れ親しんだFlightGearのHUD(ヘッドアップディスプレイ)風になったら、なんだか操縦も上手くできそうな気がしてきます。

 

とはいえ、0.96インチのOLED画面では狭く、多少は改善しましたが、速度や高度、方位のテープ式表示は、まだまだ実用に及びません。

 

サイズの大きいLCDディスプレイを使うか、PDF形式はやめて一つ一つの計器に独立したディスプレイを割り当てるかすれば改善できるかもしれませんが、0.96インチOLEDではこれくらいがよい塩梅なのかもしれません。

 

《参考》

 

最後にとりあげたHUD風ミニPFDについて、ソフト一式について掲載します。使い方は前回のブログ記事をご覧ください。

 

・fgdata.xml

 

<?xml version="1.0"?>
<PropertyList>
 <generic>
  <output>
   <line_separator>\n</line_separator>
   <var_separator>,</var_separator>
   <chunk>
     <name>groundspeed-kt</name>
     <node>/velocities/groundspeed-kt</node>
   </chunk>
   <chunk>
     <name>altitude-ft</name>
     <node>/position/altitude-ft</node>
   </chunk>
   <chunk>
     <name>true-heading-deg</name>
     <node>/orientation/true-heading-deg</node>
   </chunk>
   <chunk>
     <name>pitch</name>
     <node>/orientation/pitch-deg</node>
   </chunk>
   <chunk>
     <name>roll</name>
      <node>/orientation/roll-deg</node>
   </chunk>
  </output>
 </generic>
</PropertyList>

 

このxmlファイルは、FlightGearのデータファルダ内のProtocolサブフォルダに置きます。

 

・main.py

 

import socket
import network
from machine import Pin, I2C
import ssd1306
import time
import math

# ---------- WiFi ----------
ssid = "
Wi-Fiネットワーク名"
password = "パスワード"

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)

print("Connecting WiFi")

while not wlan.isconnected():
  time.sleep(1)

print("Connected")
print(wlan.ifconfig())

# ---------- OLED ----------

WIDTH = 128
HEIGHT = 64

i2c = I2C(0, scl=Pin(1), sda=Pin(0), freq=400000)
oled = ssd1306.SSD1306_I2C(WIDTH, HEIGHT, i2c)

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(("0.0.0.0", 5501))
sock.settimeout(0.01)

speed = 0
alt = 0
heading = 0
pitch = 0
roll = 0

# ---------- 速度テープ ----------

def draw_speed_tape():

  center = int(speed/10)*10

  for i in range(-3,4):

    v = center + i*10
    y = 32 - i*8

    if 10 < y < 56:
      oled.text(str(v),0,y,1)

  oled.text(">",24,32,1)
  oled.text("SPD",8,56,1)

# ---------- 高度テープ ----------

def draw_alt_tape():

  center = int(alt/10)*10

  for i in range(-3,4):

    v = center + i*10
    y = 32 - i*8

    if 10 < y < 56:
      oled.text(str(v),96,y,1)
  oled.text("<",88,32,1)
  oled.text("ALT",88,56,1)

# ---------- 方位テープ ----------

def draw_heading():

    center = int(heading/10)*10

    for i in range(-6,7):

    h = (center + i*10) % 360
    x = 64 + i*10

    if 5 < x < 120:

      if h % 30 == 0:
        oled.text(str(h), x-6, 0, 1)

      else:
        oled.pixel(x,6,1)

   oled.text("^",62,10,1)
   oled.text("HDG",54,16,1)

# ---------- 水平儀 ----------

def draw_horizon():

  cx = 64
  cy = 36

  r = math.radians(-roll) # ← rollを反転

  length = 80

  x1 = int(cx - length*math.cos(r))
  y1 = int(cy - length*math.sin(r) + pitch)

  x2 = int(cx + length*math.cos(r))
  y2 = int(cy + length*math.sin(r) + pitch)

  oled.line(x1,y1,x2,y2,1)

  # 機体マーク
  oled.line(cx-6,cy,cx+6,cy,1)

# ---------- メインループ ----------

while True:

  try:
    data, addr = sock.recvfrom(256)

    parts = data.decode().split(",")

    speed = float(parts[0])
    alt = float(parts[1])
    heading = float(parts[2])
    pitch = float(parts[3])
    roll = float(parts[4])

  except:
   pass

  oled.fill(0)

  draw_heading()
  draw_speed_tape()
  draw_alt_tape()
  draw_horizon()

  oled.show()

 

このMicroPythonプログラム(main.py)は、Pico Wに書き込みます。

 

・起動オプション

 

--generic=socket,out,10,192.168.0.xxx,5501,udp,fgdata

 

FlightGearの起動オプションに、上述の通り入力します。,192.168.0.xxx部分には送信先であるPico WのIPを記述します。

 

なお、ここで示したプログラムはCopilotとChatGPTの助けを借りて作成しています。

 

 

《関連》

 

 

 

 

 

 

 

FlightGearシミュレータとOLED表示

↑FlightGearの航空機の速度、高度、方位の変化がOLED上に刻々と示されていきます

 

Wi-Fi接続、0.96インチOLED表示

OLED画面に速度・高度・方位

 

前回の当ブログでは、フライトシミュレーターであるFlightGearのデータを引き出して、Ambientへの送信にとりくみました。

 

FlightGearの飛行中の各計器の示す値をよく見えるようにしたいというのに、Ambientにグラフ表示させていてもしかたがありません。

 

今回は、とりあえずOLEDに数値表示ができないかを試すことにしました。

 

■構成

構成は次のようなものです。

 

 FlightGear

 ↓ UDP

 Wi-Fi

 ↓

 Rasopberry Pi Pico W

 ↓ I2C

 OLED

 

■必要なものと手順

 

注意事項やPythonの利用が前提、Raspberry Pi PicoはMicroPythonの使用が前提という点は、前回同様です。

 

【ハード】

 

今回は、小型ののOLEDディスプレイに表示ということなので、機器の用意が必要になります。

 

・Raspberry Pi Pico W…Wi-Fi機能付きマイクロコントローラー

 

・OLEDディスプレイ…手持ちの0.96インチ4ピンI2C対応 ドライバSSD1306またはSSD1315

 

・他…工作用にブレッドボード、ジャンパー線など

 

OLEDとPico Wとの配線は次の通り

 

OLED Pico W
VCC 3.3V(Pin 36)
GND GND(Pin 38など)
SCL GP1(Pin 2)
SDA GP0(Pin 1)

 

Raspberry Pi Pico WとOLEDでFlightGearの飛行データを表示

↑一部隠れていますが、ブレッドボードに組まれた回路

 

【ソフト】

 

・fgdata.xml

 

プロトコルを記述したこのxmlファイルについても、前回とまったく同じものを使います。省略しますので、前回を参照こと。このファイルを、FlightGearのデータファルダ内のProtocolサブフォルダに置くのも前回同様です。

 

・main.py

 

Pico Wに書き込むMicroPythonプログラム(main.py)は、Wi-Fi接続とUDP受信の設定を記述しています。Pico Wへの書き込みはThonnyが便利です。

 

import socket
import network
from machine import Pin, I2C
import ssd1306
import time

# WiFi
ssid = "Wi-Fiネットワーク名"
password = "パスワード"

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)

while not wlan.isconnected():
  time.sleep(0.5)

print("IP:", wlan.ifconfig()[0])

# OLED
i2c = I2C(0, scl=Pin(1), sda=Pin(0), freq=400000)
oled = ssd1306.SSD1306_I2C(128, 64, i2c)

# UDP sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(("0.0.0.0", 5501))

oled.fill(0)
oled.text("Waiting FG...", 0, 0)
oled.show()

while True:
  data, addr = sock.recvfrom(1024)
  text = data.decode().strip()
  values = text.split(",")

  if len(values) >= 3:
    spd = values[0]
    alt = values[1]
    hdg = values[2]

    oled.fill(0)
    oled.text("SPD {:>6}".format(spd), 0, 0)
    oled.text("ALT {:>6}".format(alt), 0, 16)
    oled.text("HDG {:>6}".format(hdg), 0, 32)
    oled.show()

 

・起動オプション

 

FlightGearの起動オプションには、送信先であるPico WのIPを記述します。

実行は、CMD(コマンドプロンプト)にて次の通り入力して行います。なお、path

や飛行機名、空港名、Pico WのIPは例です。

 

"C:\Program Files\FlightGear 2024.1\bin\fgfs.exe" ^
--fg-root="C:/Users/自分のフォルダ名/FlightGear/Downloads/fgdata_2024_1" ^
--fg-aircraft="C:/Users/自分のフォルダ名/FlightGear/Custom Aircraft" ^
--aircraft=F1M2 ^
--airport=RJBB ^
--runway=24L ^
--generic=socket,out,10,192.168.0.xxx,5501,udp,fgdata

 

ちなみに、Pico WのIPの確認は、Thonnyのシェルにて以下の通り入力し実行すれば、シェルに表示されます。

 

import network
wlan = network.WLAN(network.STA_IF)
wlan.ifconfig()

 

■リアルに変化するOLED画面

 

結果、OLED画面では流れるように数字が変化していきます。その数字はFlightGear画面のHUDの目盛りから読み取れるものとまさに一致しており正確です。

 

これはいいですね。もっと見やすく大きくて計器風のディスプレイをならべたら、フライトシミュレーターの実体化ができそうじゃありませんか。

 

 

《追記》

FlightGearの/protocolに置いたfgdata.xmlは、FlightGearのpropertyから目的の状態変数を取り出してUDPで送信するために書いたものです。速度と高度、方位を取り上げましたが、実際には速度には対気速度と対地速度、方位には磁方位と真方位の違いがあり、これはFlightGearでも同じ。今回fgdata.xmlには、試行錯誤の都合でgroundspeed-kt(対地速度)とtrue-heading-deg(真方位)を記述しました。気になる方は、当該箇所のそれぞれ2か所をairspeed-ktやheading-degに書き改めてください。

 

 

《関連》