FlightGearのデータを外部表示させよう(3) | virt_flyのブログ

virt_flyのブログ

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

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の助けを借りて作成しています。

 

 

《関連》