* Raspberry Pi Pico で鉄道模型を動かす
-(by [[K]], 2024.10.22)
** (0) 目的
-小学生にプログラミングを教えようとしても、画面の中でピコピコと動くだけではたいして興味を示さない(場合がある)。
-そんな場合は、おもちゃをPCから制御すればきっと喜んでやる気を出す。
-よし鉄道模型を動かそう!
-もし鉄道模型とラズパイピコと電源アダプタを持っていれば、追加で必要な費用はたったの1230円程度です!(単品では買えないものもあるので、実質的にはもうちょっとかかりますが)
--これはもうやるしかないですよね!!
** (1) pico側に書き込んだスケッチ
#include <hardware/pwm.h>
void pico_analogWriteFreqRang(int pin, float freq, uint32_t rang)
// rang=[0,65535], freq > 125000000.0 / (rang + 1) / 256
// slice0: GP0, GP1, GP16, GP17
// slice1: GP2, GP3, GP18, GP19
// slice2: GP4, GP5, GP20, GP21
// slice3: GP6, GP7, GP22
// slice4: GP8, GP9, GP25
// slice5: GP10, GP11, GP26, GP27
// slice6: GP12, GP13, GP28
// slice7: GP14, GP15
// [註]sliceが同じものは、freqとrangは共通になる.
{
int slice_num = pwm_gpio_to_slice_num(pin);
float tmp = (rang + 1) * freq;
gpio_set_function(pin, GPIO_FUNC_PWM);
pwm_set_clkdiv(slice_num, 125000000.0 / tmp); // 256未満.
pwm_set_wrap(slice_num, rang);
}
void pico_analogWrite(int pin, uint32_t val)
{
int slice_num = pwm_gpio_to_slice_num(pin);
pwm_set_chan_level(slice_num, pin & 1, val);
pwm_set_enabled(slice_num, true);
}
void setup() { Serial.begin(115200); }
int prm_f0[4][4], prm_f1[16][4], prm_f2[3] = { A0, A1, A2 };
int prms[8] = { 4, 4, 1, 0, 1, 2, 1, 1 };
void loop()
{
int c = Serial.read(), ch, p[8], dir, i, j, k, a[5];
if (c < 0) { delay(3); }
if (0xf0 <= c && c <= 0xf7) {
j = prms[c - 0xf0];
for (i = 0; i < j; i++) {
while (Serial.available() < 1) {}
p[i] = Serial.read();
}
ch = p[0] & 63;
dir = (p[0] >> 6) & 3;
}
if (c == 0xf0 && 0 <= ch && ch <= 3) {
prm_f0[ch][0] = p[1]; pinMode(p[1], OUTPUT);
prm_f0[ch][1] = p[2]; pinMode(p[2], OUTPUT);
prm_f0[ch][2] = p[3]; pinMode(p[3], OUTPUT);
pico_analogWriteFreqRang(p[1], 100 * 1000, 255); // 100KHz
pico_analogWrite(p[1], 0);
digitalWrite(p[2], LOW);
digitalWrite(p[3], LOW);
}
if (c == 0xf1 && 0 <= ch && ch <= 15) {
prm_f1[ch][0] = p[1];
prm_f1[ch][1] = p[2]; pinMode(p[2], OUTPUT);
prm_f1[ch][2] = p[3]; pinMode(p[3], OUTPUT);
digitalWrite(p[2], LOW);
digitalWrite(p[3], LOW);
}
if (c == 0xf4 && 0 <= ch && ch <= 3) {
digitalWrite(prm_f0[ch][1], dir & 1);
digitalWrite(prm_f0[ch][2], (dir >> 1) & 1);
}
if (c == 0xf5 && 0 <= ch && ch <= 3) {
pico_analogWrite(prm_f0[ch][0], p[1]);
}
if (c == 0xf6 && 0 <= ch && ch <= 15) {
digitalWrite(prm_f1[ch][1], dir & 1);
digitalWrite(prm_f1[ch][2], (dir >> 1) & 1);
delay(prm_f1[ch][0] * 8); // max 2.0sec.
digitalWrite(prm_f1[ch][1], LOW);
digitalWrite(prm_f1[ch][2], LOW);
}
if (c == 0xf7 && 0 <= ch && ch <= 2) {
i = prm_f2[ch];
a[0] = analogRead(i);
a[1] = analogRead(i);
a[2] = analogRead(i);
a[3] = analogRead(i);
a[4] = analogRead(i);
for (k = 0; k < 3; k++) {
i = 0; j = a[0];
if (j < a[1]) { i = 1; j = a[1]; }
if (j < a[2]) { i = 2; j = a[2]; }
if (j < a[3]) { i = 3; j = a[3]; }
if (j < a[4]) { i = 4; j = a[4]; }
a[i] = -1;
}
Serial.write((j >> 8) & 255);
Serial.write( j & 255);
}
}
-pico_analogWriteFreqRang()やpico_analogWrite()を使わずに、analogWrite()をそのまま使っても制御は問題なくできますが、低速運転のときに不快な「きーーん」音がでます。
--これはデフォルトのfreqが可聴音の周波数になっているせいなので、前述の2関数を使って100KHzという聞こえない周波数に設定します。これで不快な「きーーん」は出なくなります。
** (2) 使っているパーツ類
-[1個1500円程度] Raspberry Pi Pico (たとえば https://www.amazon.co.jp/dp/B0B6NPGH7Z/ )
-[2個1000円程度] L298N モジュール (たとえば https://www.amazon.co.jp/dp/B09TJZ953V/ )
-[1個1900円程度] マルチ電圧アダプター(5V~15V)(たとえば https://www.amazon.co.jp/gp/product/B08Q3T61M6/ )
-[10個400円程度] CdSフォトレジスタ type:5539 (たとえば https://www.amazon.co.jp/dp/B09DYTRPZ7/ )
-[100個850円程度] 可変抵抗(可変じゃなくて1Mオームの固定抵抗でも可) (たとえば https://www.amazon.co.jp/dp/B0B8M91D3T/ )
-[10個900円程度] DC電源コネクタ (たとえば https://www.amazon.co.jp/dp/B077GV4NVY/ )
-picoを1個、L298Nを2個、アダプタ2個、CdSを1個、可変抵抗を1個、コネクタを2個、合計6530円程度。
-picoや電源アダプタは他でも活用できて転用可能なので、もしこれらを費用に含めないとすれば、1230円程度ということになります!
-純正のパワーユニット1個とポイントのコントロールボックス2個を揃えたら合計6000円くらいはかかると思いますが、この回路があればパワーユニットもポイントコントロールボックスもいりません。
-Nゲージの自動運転ではTA7291Pを使う例がたくさん見つかりましたが、TA7291Pはchが1つしかないので、ポイントが多くなるとドライバがたくさん必要になります。L298Nならchが2個あるので半分で済みます。
** (3) 配線例(単線・ポイントを2つ使用の場合)
-picoのGPIO#O~#3、GPIO#8~#10、ADC#0、3V3、VBUS、GNDのみを使用。
--ピン配置はこちらを参照: https://racoubit.org/elec/pico.html
-L298Nは2つ使用。1つはポイント制御用(以降はP298と呼ぶ)。1つは電車制御用(同T298)。
--端子配置はこちらを参照: https://docs.sunfounder.com/projects/3in1-kit/ja/latest/components/component_l298n_module.html
-P298とT298のいずれもジャンパピンを外して、+5Vの自動供給をOFF。そして5V入力に、picoのVBUSを分岐させて結線(たぶんこうしたほうが排熱が少なくて電力効率が良い)。
-P298の12VにはDC電源コネクタの+線と電源アダプタを付けて、7.5Vを給電。
-T298の12VにはDC電源コネクタの+線と電源アダプタを付けて、12Vを給電。
-1Mオーム抵抗の両端に銅線を付けて伸ばす(R1、R2:極性なし)。
-CdSの両端にも銅線を付けて伸ばす(C1、C2:極性なし)
-P298のGND、T298のGND、picoのGND、DC電源アダプタの-線(2個)、R2をすべてつなぐ。
-R1とC2とADC#0をつなぐ。
-C1と3V3につなぐ。
-GPIO#0 : P298のIN1に接続
-GPIO#1 : P298のIN2に接続
-GPIO#2 : P298のIN3に接続
-GPIO#3 : P298のIN4に接続
-GPIO#8 : T298のIN2に接続
-GPIO#9 : T298のIN1に接続
-GPIO#10 : T298のENAに接続
-P298のOUT1とOUT2をポイント1へ(極性が反対だったら後から入れ替えればいい)。
-P298のOUT3とOUT4をポイント2へ(極性が反対だったら後から入れ替えればいい)。
-T298のOUT1とOUT2をDCフィーダへ(極性が反対だったら後から入れ替えればいい)。
** (4) ポイント制御
-TOMIX の N-PL541-15(F)で実験(番号は1272)。 https://www.amazon.co.jp/dp/B001V7YC6Y/
-6.0Vを32ミリ秒だけ印加すると切り替わりました。5.0Vにすると秒数にかかわらず無反応になり、6.0Vでも16ミリ秒とかにすると切り替わりが不安定になりました。
-これを踏まえて、「7.5Vを48ミリ秒印加する」という設定を本番では使おうと思います(マージンを加味して少し値を大きくしています)。
-[参考]
--12V, 200~300ミリ秒が良いという説 : https://inoyoshio.muragon.com/entry/233.html
--純正パワーユニットは18.5Vとコンデンサで切り替えしているという解析記事 : https://rtmrw.parallel.jp/laboratory4/lab-report-88/lab-88.html
--ポイント手動切り替え回路の説明 : https://ngauge.jp/point-sw_1/
** (5) 電車の制御
-12V PWM=144/255 でノロノロと動き始めるが、これは厳密には車両や進行方向によって異なります。
** (9) 先人の知恵
|https://try-widely.com/raspberry-pi-pico-4/ |電車を改造して磁気センサーで在線確認|
|https://fabcross.jp/news/2021/20210701_raspberrypipico_traincontrol.html |L298N使用・在線確認は赤外線センサー|
|https://usaginoharusan.blog.ss-blog.jp/2023-08-16 |PWM制御の話は参考になりそう|
|https://www.itmedia.co.jp/news/articles/2111/29/news008.html |らずてつ シリーズ|