🛰️

RTKをUnityでやってみた

2024/12/03に公開

IoTLTのアドベントカレンダー2024の5日目です!
(もしかしたら投稿日より前に記事完成したの初めてかも)

https://qiita.com/advent-calendar/2024/iotlt

RTKってこんな感じ

Videotogif (1).gif

動画ではいい感じのところを切り取っていますが、中央に戻ってくる箇所が結構ずれることがあります。
それでも10cmくらいのずれ(体感)っぽいので、GPSと比べると精度高い

RTK(Real Time Kinematic)とは

ざっくり言えば、高精度になったGPS!

色々な人が解説しているので、ここでは省略
https://www.softbank.jp/biz/blog/business/articles/202009/rtk-gps/
https://www.akasakatec.com/blog/4138/
https://atcl-dsj.com/work/2685/
https://qiita.com/m_take/items/f416b62fb6edfb7a8c4d

自分なりに簡略化しつつ、用語整理もかねて図を作ってみた

Image from Gyazo

この他にもNTRIPって用語とかがあります。

今回はこの中の「Client」部分のみです。
「Caster」は有志の方からもらってます。
https://rtk.silentsystem.jp/

「Server」部分だったり、「Caster」のrtk2go.comを試してみたり、ローカルで構築してみたりってのもやっていますので、いずれ機会があればまた記事書きます。

RTKの用途

  • ドローン
  • 自動運転
  • 測量
    とからしい

Unityでやってみた

買ったやつ

https://www.switch-science.com/products/8288?_pos=3&_sid=3e7756d81

usbケーブルでPCと繋いで、シリアル通信でやりとりできます!すばらしい

大枠の流れ

  1. NTRIPでRTCMデータ受け取り
    1. Unity的に、TcpClient 作って、GetStream();からStreamReader 作って、受け取り
    2. バイナリー形式で受け取ったらうまくいった
  2. (今回は)シリアル通信で、手元のRTCMデバイスへ書き込み
    1. Unity的に、SerialPort 作って、Write();で書き込み
  3. シリアル通信で、読み込み
    1. Unity的に、ReadLine();で読み込み

ソースコード一部

NTRIPの通信準備

client = new TcpClient();
await client.ConnectAsync(host, port);

networkStream = client.GetStream();
reader = new StreamReader(networkStream);
writer = new StreamWriter(networkStream);

await writer.WriteLineAsync("GET /" + mountpoint + " HTTP/1.1");
await writer.WriteLineAsync("Host " + host);
await writer.WriteLineAsync("User-Agent: NTRIP curl/0.0");
await writer.WriteLineAsync("Authorization: " + GetAuthenticate(username, password));
await writer.WriteLineAsync("");
await writer.FlushAsync();

スレッドとか用意して受け取り

byte[] buffer = new byte[1024];
int len = await reader.BaseStream.ReadAsync(buffer, 0, buffer.Length, cancellationTokenSource.Token);

シリアル通信準備して、

serialPort = new SerialPort(portName, baudRate, Parity.None, 8, StopBits.One);

書き込み
タイミングはUpdateとかじゃなく、NTRIP通信で受け取ったタイミングがいい

serialPort.Write(buffer, 0, buffer.Length);

スレッドとか用意して読み込み

message = serialPort.ReadLine();

NMEA形式のデータをいったんGGAだけのものをパースしてみた

public struct GGAData
{
    public string OriginalString;
    public string TimeString;
    public int Hours;
    public int Minits;
    public float Seconds;
    public double Latitude;
    public double Longitude;
    public int Quality;
}

public GGAData ggaData = new GGAData();

public void ParseRoverData(string data)
{
    if (data.Contains("GGA"))
    {
        ggaData.OriginalString = data;
        string[] dataArr = data.Split(',');
        ggaData.TimeString = dataArr[1];
        ggaData.Hours = int.Parse(ggaData.TimeString.Substring(0, 2)) + 9;
        ggaData.Minits = int.Parse(ggaData.TimeString.Substring(2, 2));
        ggaData.Seconds = float.Parse(ggaData.TimeString.Substring(4, 4));
        ggaData.Latitude = double.Parse(dataArr[2].Substring(2, dataArr[2].Length - 2));
        ggaData.Longitude = double.Parse(dataArr[4].Substring(3, dataArr[4].Length - 3));
        ggaData.Quality = int.Parse(dataArr[6]);
    }
}

プロジェクト全体は準備中です

これつかってなにしようかな

  • 床にプロジェクションして、なんかついてくるとか
    • プロジェクションするなら暗い部屋内とかがいいけど、GPSとかには不向きか
    • まだまだ機材が大きいので卓上くらいだと効果的じゃないか
  • 本当の最短距離を測る
    • 徒歩でしか行けない道とか、道幅大きいとアウトインアウトで短くなるとかで、GoogleMapの最短距離の計算とはまた違った結果になるんじゃないかな
    • 毎回の保育園への送り迎えとかで測りたい!
      • でも冬は日が当たるほうを歩きたいっとかってのも思ったりしてる
  • 鬼ごっこのお助けアイテム的な
    • FPSのゲームみたいな壁腰に相手が見えるとか
  • 近距離でも正確なセカイカメラ

Discussion