Pico-ResTouch-LCD-2.8のケースを造形。
↓ マグネットである必要は無いのですが、RPi5に使用する前はWindows PCに接続されていて、そのマグネットでPCの側面に貼り付けてあったのです。マグネットが引っかかりUSB HDDがズレ無い様に造形しました。
↑ Onshapeの断面ビューも便利です。
CAD素人の私が、Onshapeの使用感をFreeCADと比べると。断然Onshapeの勝ちです!
FreeCADは作業内容に適したワークベンチを選択して作業を進めて行くんですが、その幾つもあるワークベンチは、ワークベンチ毎に操作性と言うか、ワークベンチ毎にソフト開発者が異なる様な、ワークベンチ毎に考え方が異なる様な。CAD素人の私には取っ付き難い物でした。
CAD素人の私が使いたい3D CADはFusion 360なんです。PCBも出来て凄く良いと思いながらも、個人で無料使用だと制限が多く、特にPCBの基板サイズが小さ過ぎるので、仕方無くPCBはKiCadを使用しています。
現在、3Dプリンター用のデータはOnshape(無料だけどデータ公開)を気持ち良く使用しています。
2024年9月6日ごろ、ラズパイ5を sudo apt upgrade したら?
gpiochip4が無い。
ソースコードのchipname部分をgpiochip4からgpiochip0に変更しました。
const char *chipname = “gpiochip4”;
↓
const char *chipname = “gpiochip0”;
gpioinfo で確認すると ↓
アップグレード前のgpiochip0は32linesだけど、アップグレード後は54linesになっている。これはgpiochip4と同じ数。
2024年9月7日上記追記。以下、元記事のまま変更していません。ソースコードは上記を参考に変更して下さい。
外国のYouTuberの動画と、そこからのリンク先のページが参考になります。
外国のYouTuberの動画
Use Raspberry Pi 5 GPIO – Push button input – LED output – ChatGTP for code – GPIOD [PART 2 OF 2]
以下、素人の私が書く事ですので、何処かに誤りがあるかも知れません。C言語のソースコードなのに、拡張子がCPPである事を指摘しないで下さい。それに、私本人は以下のプログラムが動くので、取り敢えずこれで良しと思っています。それを承知の上で参考にして下さい。
ラズパイ5のGPIOはgpiodで使うみたい。ラズパイ4まではpigpioでLチカ出来ていた。pigpioを使用したソースコードでもラズパイ5でコンパイルは成功する。だけど、そのソフトを走らせると不動作で「ラズパイでは無いようです」みたいに言われてしまう。
↓ この画像は、ラズパイ5にgpiod等をインストールして、/dev/gpiochip4を利用してLチカしている所です。
↓ C言語でGPIOを使用したい時に必要。
$ sudo apt install gpiod libgpiod2 libgpiod-dev
↓ chronyc sources
↑ PPSはこのラズパイ5。pi4やzero2にpi2は同じLAN内のラズパイで、どれもNTPサーバーです。PPSのラズパイ5、pi4、zero2の3つのラズパイは各々に繋がれたGPSの1PPSに同期中。pi2はLAN内のNTPサーバーを参照しています。
↓ 3つのLEDをchronyc sourcesの結果に応じて点灯させるプログラムのソースコード。
// Raspberry Pi 5
// pi@pi5:~ $ g++ -Wall -o chronyCheck chronyCheck.cpp -l gpiod
#include <err.h>
#include <cstring>
#include <iostream>
#include <gpiod.h>
#include <unistd.h>
#include <stdio.h>
#define BUF 256
#define H 1
#define L 0
#define PPS 10
#define NTP 9
#define NG 11
using namespace std;
enum kekka{
pps_hantei = 10,
pps_ntp_hantei,
ntp_hantei,
ng_hantei
};
int mainLoop(void);
int main(void)
{
if(daemon(0, 0) == 0) { // デーモン関数
mainLoop();
} else {
cout << "error" << endl;
}
return 0;
}
int mainLoop(void)
{
FILE *fp;
char *ret;
char str[512], *ptr;
const char* cmdline = "chronyc sources";
enum kekka hantei;
gpiod_chip *chip;
gpiod_line *line_PPS, *line_NTP, *line_NG;
//For Raspberry Pi 5 use gpiochip4 (For Raspberry Pi 4 use gpiochip0)
const char *chipname = "gpiochip4";
// Open GPIO chip
chip = gpiod_chip_open_by_name(chipname);
// Open GPIO lines
line_PPS = gpiod_chip_get_line(chip, PPS);
line_NTP = gpiod_chip_get_line(chip, NTP);
line_NG = gpiod_chip_get_line(chip, NG);
// Open LED lines for output
gpiod_line_request_output(line_PPS, "chronyCheck", 0);
gpiod_line_request_output(line_NTP, "chronyCheck", 0);
gpiod_line_request_output(line_NG, "chronyCheck", 0);
// 無限ループ
while (1) {
// コマンドの chronyc sources 実行
if ((fp=popen(cmdline,"r")) == NULL) {
err(EXIT_FAILURE, "%s", cmdline);
}
// chronyc sources 実行結果を1行づつチェックする
// それを必要なら最後の行まで繰り返す。
do {
ret = fgets(str, BUF, fp); // 1行読み取り
ptr = strstr(str, " 377 "); // 377 を検索(377前後のスペースも含む)
if (ptr != NULL) {
ptr = strstr(str, "#*"); // #* を検索
if (ptr != NULL) { // 検索行に #* と 377 があった時だけ1PPS同期判定とする
hantei = pps_hantei;
// cout << "Synchronizing to 1PPS & 377" << endl;
ret = NULL; // ここに来たらdo-whileから抜けて1行読み取りを終了する
} else {
ptr = strstr(str, "^*");
if (ptr != NULL) {
hantei = ntp_hantei;
// cout << "Synchronizing to NTP" << endl;
ret = NULL; // ここに来たらdo-whileから抜けて1行読み取りを終了する
} else {
ptr = strstr(str, "^+");
if (ptr != NULL) {
hantei = ntp_hantei;
// cout << "Synchronizing to NTP" << endl;
ret = NULL; // ここに来たらdo-whileから抜けて1行読み取りを終了する
} else {
ptr = strstr(str, "^-");
if (ptr != NULL) {
hantei = ntp_hantei;
// cout << "Synchronizing to NTP" << endl;
ret = NULL; // ここに来たらdo-whileから抜けて1行読み取りを終了する
} else {
hantei = ng_hantei; // ここに来た場合は、1PPSにもNTPにも同期せず
// cout << "NG" << endl;
}
}
}
}
} else {
ptr = strstr(str, "#*");
if (ptr != NULL) {
hantei = pps_ntp_hantei; // 377は無いが #* の場合
ret = NULL;
} else {
ptr = strstr(str, "^*");
if (ptr != NULL) {
hantei = ntp_hantei;
ret = NULL;
} else {
hantei = ng_hantei;
}
}
}
} while (ret != NULL);
// 全LEDを消灯
gpiod_line_set_value(line_PPS, L);
gpiod_line_set_value(line_NTP, L);
gpiod_line_set_value(line_NG, L);
// hanteiに応じてLEDを点灯
switch (hantei) {
case pps_hantei:
gpiod_line_set_value(line_PPS, H);
sleep(70); // PPS同期判定時は70秒待機
break;
case pps_ntp_hantei: // PPS? NTP? どっちの時は、PPS用LED、NTP用LED両方とも点灯
gpiod_line_set_value(line_PPS, H);
gpiod_line_set_value(line_NTP, H);
sleep(16); // PPS? NTP? 同期判定時は16秒待機
break;
case ntp_hantei:
gpiod_line_set_value(line_NTP, H);
sleep(16); // NTP同期判定時は16秒待機
break;
case ng_hantei:
gpiod_line_set_value(line_NG, H);
sleep(4); // NG判定時は4秒待機
break;
default: // ここに来るはず無いので意味合いとしては異常表示
gpiod_line_set_value(line_PPS, H);
gpiod_line_set_value(line_NTP, H);
gpiod_line_set_value(line_NG, H);
}
pclose(fp);
}
// 以下は無限ループ外なので不要?
gpiod_line_release(line_PPS);
gpiod_line_release(line_NTP);
gpiod_line_release(line_NG);
gpiod_chip_close(chip);
return 0;
}
↑ デーモン関数はOS起動と共に起動して常に作動する為の物。それにはユニットファイル作成等も必要だけど。ここには記載していません。
コンパイル
$ g++ -Wall -o chronyCheck chronyCheck.cpp -l gpiod
RPi5(ラズパイ5)にGNSSモジュールを繋げました。そのモジュールなんですが、欲しいGNSSモジュールが秋月電子に無いので、今回はアマゾンでポチりました。
ラズパイ5をNTPサーバーにする為のインストールは。↓
$ sudo apt update
$ sudo apt install chrony
$ sudo apt install gpsd gpsd-clients pps-tools
↓ 三次元測位中で赤LEDが点滅して1PPS出力しています。これで一応、Stratum 1相当のNTPサーバーになっています。
↑ 白色のケースやねじ類は、3DプリンターEnder-3 V3 SEとPLAフィラメントで造形しました。
アマゾンで入手したのは3点で、GNSSモジュールGY-NEO-6MV2(税込999円)とGPS外付けアンテナ線長3m(税込980円)とSMA延長ケーブル5m(税込799円)です。
NEO-6MのVCCにラズパイ1番ピン3.3Vを印加。他の配線は秋月電子のGNSSモジュールと同じ。外部アンテナは延長ケーブル込みの長さ8mのケーブルを繋げて外に出しています。
↓ ラズパイ5とNEO-6Mの配線は画像の通り。There is a wire that looks like it might be tangled in the picture, but we have not misplaced the connection, so there is nothing for you to worry about.
それに、秋月電子で販売されていたGNSSモジュール、K-13849やK-09991などの1PPSはアクティブLowだけど、NEO-6Mの1PPSは、それとは反対のアクティブHighみたいです。なのでconfig.txtの設定が一部異なる。
dtparam=assert_falling_edge=true が不要。↓
$ sudo vi /boot/firmware/config.txt
[all]
dtparam=uart0=on
# GPS 1PPS /dev/serial0 -> ttyAMA0
dtparam=uart0_console
enable_uart=1
dtoverlay=pps-gpio
dtparam=gpioin=18
#dtparam=assert_falling_edge=true