大学の卒業研究の一環で、オープンソースカンファレンス(OSC)向けの体験型展示デモを開発しました。
このデモは、Terraformを使ってDockerコンテナに割り当てるCPUリソースを制限し、そのコンテナ内で走る円周率の計算速度に同期させて、Raspberry Piに接続したモーターの回転速度をリアルタイムに変化させる仕組みとなっています。
本記事では、デモの内容とその他色々を書こうと思います。
デモの内容
pi5の性能を制限してpi3の性能に近づけることが目標です。
デモのキャッチコピーは「モーターの速度を調整して、爆弾からペンギンを守ろう!」です🐧(Linuxなので🐧)
デモ装置
展示ブースには、以下のようなデモを用意しました。(ペンギンなしver.)

ギヤードモーターの回転軸となる棒に、紙やすりを巻き付け、ボンドで固定したものです。
この棒が回転することで、プレートに摩擦で力を伝え、左右に動かしたりします。
左右のモーターの速度を合わせることで、上に乗せた板が真ん中で安定します。
内容
下記のコマンドを実行することで、pi 5上にdockerコンテナがデプロイされます。
$ terraform apply -auto-approve -var="target_cpus=1.0"
target_cpusという引数で、コンテナが利用可能なCPUリソースのうち、どれだけ使用できるかを制限します。(Resource (docker_container))
pi3, pi5の上で円周率計算を行い、その計算速度をモーターの速度に変換しています。
もっと詳しく
円周率計算
それぞれのラズパイの上で一定桁数(30,000桁)の円周率計算をしています(マチンの公式)。単純に上の桁から確定していく方法も考えましたが、計算速度をモーターの速度に変換しているという構造上、時間がたつにつれて計算量も増えていき、モーターの速度も遅くなっていくという欠点があったので却下しました。
// arctan(1/x)のテイラー展開を計算
static void arctan_scaled(mpz_t res, long x, const mpz_t scale)
{
mpz_t power, term, x_sq;
mpz_inits(power, term, x_sq, NULL);
/* power = scale / x */
mpz_tdiv_q_ui(power, scale, (unsigned long)x);
/* x_sq = x^2 */
mpz_set_si(x_sq, x * x);
mpz_set(res, power); /* result = power (n=1 の項) */
long n = 3;
while (1) {
/* power = power / x^2 (符号反転含む) */
mpz_tdiv_q(power, power, x_sq);
if (mpz_sgn(power) == 0) break;
/* term = power / n */
mpz_tdiv_q_ui(term, power, (unsigned long)n);
if (mpz_sgn(term) == 0) break;
/* 交互加算 */
if (((n - 1) / 2) % 2 == 0) /* n=3,7,11,... は引く */
mpz_sub(res, res, term);
else
mpz_add(res, res, term);
n += 2;
}
mpz_clears(power, term, x_sq, NULL);
}
また、もともとpythonを用いて計算していましたが、コンパイラ言語であるためか、理論値よりもかなり下回ったため、C言語に変更しました。
計算の結果をディスプレイに出力することで、「なんかやってる」感を出してました。(よく見ると3.22~~とかで意外と精度がよろしくない...)
ハード面
初電子工作だったので苦労しました。モータードライバって何?というところからどこに何をつなげればいいんだろうなど。
モータドライバはMESH GPIO用のモータードライバを使用しています。
土台部分はレーザーカッターを用いて集成材を加工しました。
使った技術
- Raspberry Pi zero/3/5
- MESH GPIOキット
- Terraform
- Docker
とてもいい体験でした。運営の皆様、ブースに足を運んでくださった方ありがとうございました。