Raspberry Pi[56] gpsdライブラリを使ってC言語で緯度・経度を取得
前に作ったGPSデータを取得するプログラムはUSBでNMEAをシリアルで受信して解析するものでした。しかし、GPSの時刻同期で使用した gpsd からNMEAのデータを取得することができるようなので、gpsd から取得してみました。gpsdから取得すると GPS受信機が一つで、時刻同期したり緯度経度取得したりすることができます。また、必要な情報は構造体で取得できるので、変換を自分ですることも必要なくなります。
少し補足です。GPSの出力周期は、一般的には1Hz(1秒ごと)であることが多いです。しかし、これを gpsd
で受信しようとすると、なぜか1秒の間に複数回データが出力されるように見えます。
1秒に1回だけデータが来るものと想定して処理を組むと、思わぬ挙動になることがあります。というのも、GPSはNMEA文を一度にまとめて出力するのではなく、複数の文に分けて順次送信するためです。そのため、各文が届くたびに gps_read()
が true を返します。もし、1秒ごとにデータを更新するような処理をしたい場合は、以下のようなコードにするのが良いでしょう。
#include <gps.h>
#include <time.h>
struct gps_data_t gps_data;
time_t last_time = 0;
void process_gps()
{
if (gps_waiting(&gps_data, 2000000)) {
if (gps_read(&gps_data) == -1) {
fprintf(stderr, "gps_read() failed\n");
} else {
time_t current_time = (time_t)gps_data.fix.time;
if (current_time != last_time &&
gps_data.fix.mode >= MODE_2D &&
!isnan(gps_data.fix.latitude) &&
!isnan(gps_data.fix.longitude)) {
// ここで位置情報を処理
printf("Lat: %.6f, Lon: %.6f\n", gps_data.fix.latitude, gps_data.fix.longitude);
last_time = current_time;
}
}
}
}
ただ、これには欠点があります。デバッグで使用する gpsfake は gps_data.fix.time を出さないのです。ということは、この時刻チェックが使えません。なので、引数かなんかでコード有効・無効にするかなどの方法が必要です。
gpsd の立ち上げはGPSに時刻同期ブログを見てください。
【目的】
Raspberry Pi上で gpsd
ライブラリを使い、C言語でリアルタイムに緯度・経度・速度を取得するプログラムを作成。
✅ ステップ1:gpsd開発ライブラリの確認・導入
sudo apt install libgps-dev gpsd
✅ ステップ2:基本的なCのコードを作成
#include <gps.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
struct gps_data_t gps_data;
if (gps_open("localhost", "2947", &gps_data) != 0) {
fprintf(stderr, "Error: gps_open failed\n");
return 1;
}
gps_stream(&gps_data, WATCH_ENABLE | WATCH_JSON, NULL);
while (1) {
if (gps_waiting(&gps_data, 5000000)) {
if (gps_read(&gps_data, NULL, 0) == -1) {
fprintf(stderr, "Error: gps_read failed\n");
} else {
if (gps_data.fix.mode >= MODE_2D && isnan(gps_data.fix.latitude) == 0) {
printf("Lat: %.8f, Lon: %.8f, Speed: %.2f km/h\n",
gps_data.fix.latitude,
gps_data.fix.longitude,
gps_data.fix.speed * 3.6);
} else {
printf("Waiting for fix...\n");
}
}
}
sleep(1);
}
gps_stream(&gps_data, WATCH_DISABLE, NULL);
gps_close(&gps_data);
return 0;
}
✅ ステップ3:ビルド
gcc gps_read.c -o gps_read -lgps -lm
✅ ステップ4:実行時の注意点と解決法
- 最初
gps_read()
にtoo few arguments
エラー →libgps
v3.22ではgps_read()
は3引数必要(char *message, int len
)
gps_read(&gps_data, NULL, 0);
✅ ステップ5:gps_data.fix
の内容確認
gps_data.fix.latitude
,longitude
,speed
は全て double(単位:度、m/s)- 緯度経度はすでに変換済みの10進度表記 → 自分でNMEAの度分から変換する必要はなし
✅ ステップ6:Fixされない時の条件
gps_data.fix.mode < MODE_2D
の場合、まだ位置取得中(No Fix)- シミュレーションNMEAでも、
GGA
の fix が 1 以上(例:4
)であればMODE_3D
に達する
✅ ステップ7:ボーレート自動設定のための override.conf
[Service]
ExecStartPre=/usr/bin/stty -F /dev/ttyUSB0 115200
→ /etc/systemd/system/gpsd.service.d/override.conf
に保存し、systemctl daemon-reexec
→ daemon-reload
→ restart gpsd
で反映
ボーレートが変わったかを確かめるには。
sudo systemctl stop gpsd
stty -F /dev/ttyUSB0