t-hom’s diary

主にVBAネタを扱っているブログです。

数学やるならPython。なぜならSympyというチート級のツールがあるから。

今回はPythonのSympyについてご紹介。

今日は有給休暇を取得して朝から微積の学習を始めた。

別に高尚な趣味として数学をやってるわけではなく、電子工作やプログラミングなど趣味のモノづくりに活かしたいという用途なので、詳細を理解したいというよりはツールとして使いたいという動機が大きい。

そこで難しいところはPythonを使ってすっ飛ばしていくことにした。
書籍には例えばこういう解説が出てくる。

 y=ax^2+bx+c と、実測データx,yからa, b, cを導き出すことができるということを書いてあるが、どう求めるのかは分からない。
まぁ何となく連立方程式なんだろうなとは思うのだが。不明な要素が3つあるのか、こまったな。

こういうときは、Sympyの出番。

Google Colaboratoryというサービスで無料でPython Jupyterを使えるのでそこで連立方程式を作って計算させてみる。
Sympyでは右辺が0という前提で右辺を無視した式を作る必要があるので、 y=ax^2+bx+c ⇒⇒⇒  ax^2+bx+c - y と変形しておく。あとはxとyにそれぞれ値を当てはめた式を作ってlinsolve関数でa, b, cの値を計算させる。

これで書籍のとおり、 a = \frac{1}{400} ,  b = 1,  c = 0 と答えが出た。

Sympyすげぇ。

文字式を文字式のまま扱える仕組みがあれば、数学の問題をかなり柔軟にプログラミングで扱うことができる。
つまり、中身や計算手順が分からなくても、教科書に書いてあるような式をとりあえず真似てつくって操作することができる。

こういう学習方法については賛否あるだろう。たとえば、これでは中身が分からなくて身に付かないとか。

でも、私は使ったこともないものに興味を持てというのは無理な話だと思っているので、とりあえず「よく分からないけど利用はできる」という状態を目指すのは正解だと考えている。

たとえば別に車が好きでもなくて運転もできない人が車のエンジンの仕組みに興味もてるか?という話に近いかなぁと思う。

ということで私はこのチート級ツール(褒めてる)であるSympyを使ってショートカットを駆使しつつ、最終的には微積分を使いこなしたい。

以上、Sympyはすげぇ!という話。

ライントレースボットの左右のタイヤスピードから旋回軌道を計算する

今回はレゴのライントレースボットの旋回軌道の理論値を求めてみる。

ライントレースボットを作った記事がこちらで、
thom.hateblo.jp

前回旋回軌道の理論値を求めようとして失敗した記事がこちら。
thom.hateblo.jp

そして今回はやりたいことにピッタリな記事を見つけたのでそちらを参考に計算していこうと思う。

まずはこちら。
www.mech.tohoku-gakuin.ac.jp

色々と難しいことが書いてあるけど、重要なのは「対向2輪型」というキーワード。

キーワードさえ手に入れれば、ググり放題だ。
これでもっと簡単な説明が書いたサイトを探してみよう。

そして見つけたのがこちら。
tajimarobotics.com

残念ながら数式の表記が崩れているけど、2つのサイトの図を見て気づいた。

前回は左タイヤと右タイヤの軌道を別々に考えてたからややこしかったのであって、要は同心円状の軌道になるわけだから、2つの円を描いて考えれば良いのだ。

いつもどおりまずは紙。ごちゃっと書きなぐる。

次にExcelで作図。

円周の長さは2×円周率×半径なので、この2つの円周をタイヤの軌道が通るとすると、内輪は2πR(1)で1週、外輪は2πR(2)で1週することになる。

2πR(1):2πR(2)の両側を2πで割ってR(1):R(2)ということは、タイヤスピードの比と半径の比は同じになりそうだ。

つまりR(2) = R(1) * タイヤ速度比。

一方、R(2)は、R(1) + 車軸の長さ(左右のタイヤ間隔)と考えることもできる。

つまり、

連立方程式爆誕!

これを解けば、車軸の長さと左右タイヤの速度比から旋回軌道を計算できることになる。

Excelを起動してるので、そのままVBAでやってみた。
タイヤの速度比は4、車軸の長さは10とした。

Const HUGE_NUMBER = 1E+308
Sub 旋回軌道計算()
    velocity_ratio = 4
    shaft_width = 10
    minimal = HUGE_NUMBER
    For inner_radius = 0 To shaft_width Step 0.01
        tmp_diff = Abs(inner_radius * velocity_ratio - (inner_radius + shaft_width))
        If minimal >= tmp_diff Then
            minimal = tmp_diff
        Else
            Debug.Print "Inner_Radius: "; inner_radius
            Debug.Print "Outer_Radius: "; inner_radius + shaft_width
            Exit For
        End If
    Next
End Sub

結果は次のとおり。

Inner_Radius:  3.33999999999997 
Outer_Radius:  13.34 

内輪は半径3.3の弧を描くように移動し、外輪は13.34の弧を描くように移動することが分かる。

単位は車軸に依存するので今回はセンチメートルで考える。

疑り深い私は、念のため製図ソフトFusion360でも同心円を書いて寸法を入れてみた。
こっちは直径になるので倍にしているが、誤差はあるものの概ね正しい値が出ている。


よし、ということで先日作った実機↓でやってみた。
(写真は先日の動画から使いまわし)


ところが、全然理論値どおりになってない。
だいたい3~4cmは大回りしている印象。

なんで????と思ってよく見たら。。

タイヤ滑ってる!!

外輪のグリップが強いので内輪が少し引きずられているのか、あるいは後輪がカーブについてこれてないせいかは不明。

ということで、現実の物理法則から主要素だけ取り出しても、他の要素の影響が大きくて計算通りには動かないという結果に終わった。

しかしこうやって考察を積み重ねて色々調べることで知識も付くし、その知識がまた面白いことをするのにいつか役立ったりするし、今回も結果として楽しめたからそれで良かったかなと思う。

以上

「単位円」とは?

最近とある目的で数学を学習している中で、「単位円」という言葉に引っかかったのでちょっと調べてみた。

単位円とは、原点を中心とする半径1の円のことだそうで、三角比の計算に便利なのでよく用いられるとのこと。

ここまでは大体どのサイトでも書かれている。
しかし、ほとんどのサイトにおいて説明はそこで止まっているのだ。

単位ってなんやねん?

単位とは、長さ、重さ、量などの数量を計算するときの基準となるもの。
つまり単位円というからには、それらが複数個集まって何かしら量的意味を成すという感覚がつきまとう。
でも単位円で求めたものに対して何かをかけ合わせたりという例は見かけない。

三角比の計算だって、単位円が単体で使われているような印象だ。


単位円、おまえどのへんが単位なんだ?言ってみ?


私は昔から数学が苦手だけど、親が読書家で自分も多読派だったので、国語は得意だった。
これもしかして、国語が得意だから数学が苦手になったのでは!?
名は体を表すべきという国語感覚が理解にブレーキをかけているような気がする。

そんで英語版を調べてみると「Unit Circle」。
ふむ、直訳か。

そんでUnitの語源を辿ると、Un、Uniなど、「One」の意味が色濃く出ている。

おそらく日本人が「単位」と聞いたときと、英語話者が「Unit」と聞いたときのイメージが若干違っていて、Unitは「単」とか「1」に近いんじゃないかと思う。

英語話者がUnit Circleと聞けば、半径を1とした円ということでストレートな名称に感じる反面、日本語で「単位円」と言われるとしっくりこない。

↓こう書いてくれたらめっちゃ分かりやすいのに。(ほんとかどうかは分からんけどもしそうであれば。)
「単位円とは半径を1とした円のことで、三角比等の計算に便利に用いられる。単位円という言葉はUnit Circleの直訳で、この場合のUnitは単位というよりは「1」のイメージに近い。」

数学が得意な人はこういうことって逐一疑問に思わないんだろうか。

実は私が嫌っていたのは数学ではなく、人から説明された内容を特に疑問も持たず、表面的な理解で繰り返しまき散らす数学者的行為なのかもしれない。そうでない数学者の方、ごめんなさい!

もしかして私がひねくれてるのか?いや、、そんなはずは。。
うーん。まぁ世間的にはそうなんだろうなぁ。

Stormworksでディーゼル・エレクトリック車作成 ロジックの設計が面白い

今回はStormworksでディーゼル・エレクトリック方式の車を作成した。
その際、Stormworksではロジックを自分で設計できることを知って感動したのでご紹介。

ディーゼルエンジンで発電してその電力でモーターを回すという機構である。

参考にしたのはこちら。
youtu.be

各動力機構のメリット・デメリットは次のとおり。

動力の種類 メリット デメリット
エレクトリックモーター 構成がシンプルで操作しやすい バッテリー残量が減ると出力が下がってくる
ディーゼルエンジン 出力低下が無い 構成が複雑で操作ミスで簡単にエンストする
ディーゼル・エレクトリック方式 クラッチ不要で操作しやすく、出力低下が無く、エンストしにくい 構成がやや複雑

さて、完成品の紹介はメインじゃないのでこんなところにしておいて、今回のメインはロジックパーツ!

まず既存ロジックとして信号反転は入ってきた信号に「-1」を掛けるロジックパーツである。
例えばタイヤにハンドルからの信号を伝達する際、プラスが外曲がり・マイナスが内曲がりになるので、左右とも外にむいたら曲がれない。そこで左タイヤだけ反転ロジックを噛ませることで方向を揃えるという風な使い方をする。

次に関数ロジック。ここは引数を1つとる任意の関数を設定できる。例えば速度計は「秒速/m」形式で信号が出力されるのでこれをメーターに送る前に時速/kmに変換(x * 3.6)してやるなど。

最後に自作ロジック。

なんとこのゲーム、「マイコン作成」と称して任意のロジック作成までできてしまうのだ。

これはすげぇ。

上記は入力1(スロットル)と入力2(速度)があり、入力2が60以下なら入力1をそのまま出力し、60を超えると0を出力するというロジックになっている。

つまりスピードが60キロを超えたらそれ以上アクセルを踏んでも伝達されないような仕組みである。

こんな風に自分で好きなロジックを組めるので工作の幅が広がる。

しかもロジックパーツ一覧をみてると。。Luaがおわす。。

プログラミングまでできんの?まじ?

ゲーム内エディタでてきた!!!

なんだこのゲーム。なんでもありだな。

Python Processing ベクトルの回転を使ったアニメーション(LEGO ライントレースボット研究の副産物)

今回は偶然の産物としてバネ状の軌跡を描くようなアニメーションが出来たのでご紹介。
もともとはLEGO Mindstorm EV3のライントレースボットで左右タイヤの回転比率によってカーブの軌跡がどう変わるかをProcessingでシミュレーションしたかったのだが、そちらはまだ上手くいっていない。

成果物


コード

あんまり綺麗なコードとは言えない。
ProcessingのPythonモードにしたことでsetupとdrawでvelocityなどのオブジェクト変数が共通と見做されなくなったので、とりあえず双方でGlobal宣言するくらいしか方法が思いつかずこうなった。Python知識をもっと磨けば解決すると思われる。

import math
radius = 100
circumference = 2 * radius * math.pi
b = 10
theta = b / circumference * 360

def setup():
    global velocity
    global location
    global acceleration
    size(800, 600)
    frameRate(30)
    location = PVector(0.0, 0.0)
    velocity = PVector(-5.0, -2.0)
    acceleration = PVector(-1.0, -1.0)
    fill(0)
    rect(0, 0, width, height)

def draw():
    #こちらのglobalは必要ないらしい。im_y_oさんありがとうございます。
    #global velocity
    #global location
    #global acceleration
    fill(0, 2)
    rect(0, 0, width, height)
    fill(255)
    noStroke()
    velocity.rotate(-radians(theta))
    location.add(acceleration)
    location.add(velocity)
    translate(width, height)
    ellipse(location.x, location.y, 20, 20)

経緯

話はまったくの別件から始まる。

先日LEGO Mindstorm EV3でライントレースボットを作ったが、動かす前にバッテリー切れで検証できていなかった。
thom.hateblo.jp

今日はちょっと後輪に手を加えてカーブに追随しやすくしてみた。

実際に動かしてみたのがこちら(割とうるさいので音量注意)
youtu.be

トレースは出来ているけど、カーブで曲がり切れておらず大回りした結果最後はラインへの新入角が大きくなりすぎてコースアウト。
カーブ処理は内輪が36度回転する間に外輪が360度、つまり1対10の比率としている。

この比率は適当に決めたものだが、実機だと変数(摩擦とか)が多くて比率と描かれるカーブの関係性がいまひとつ理解しづらいので、シミュレーションしてみようということを思いついた。

そこでVisual Programmingといえば、Processing!

いやぁ、学んだことってこう繋がるんだなぁと感激しながらちょっと考えてみた。

しかしすぐにこの問題の難しさに気づく。
内輪が1進む間に外輪が。。しかし車軸で繋がっているのでまっすぐは進めず角度が付く、そこで内輪・外輪ともに進行方向が変わるので。。。あれ?どうなるんだ?とか。

内輪の移動距離を微小な単位に落とし込むと外輪の移動距離が求まりその結果として角度θが求まるのでは。。あれ?もしかして微分ってここで使うものなの?あでも微細化しすぎるとコンピューターの最小座標単位である1ピクセルを下回るしなぁ。。あ、それで積分なのか?。。でもそもそも微積分よく分かってないので適用範囲なのかどうか不明。。とか。

でも厳密には外輪の移動って直線ではなくて円周上だよなぁ、だったら車軸距離を半径とした円周距離の比率に360度を掛けると角度θが求まるか。。でも求めた後、進行方向変わったあとってどうやって座標に落とし込むんだ。。とか。

まぁ、ごちゃごちゃとメモしながらひとしきり考えみたんだけど。。

うん、わからん!

そんで、とりあえず動かしながら考えてみようとなった。

そしたら新発見、なんとProcessingのPVectorクラスには、rotateという命令があることを知る。
もともと悩んでたのは、回転したらベクトルの向きが変わるけどベクトルって座標系だから回転をくわえた座標を三角関数でもとめ。。うわどうやるんだこれ!?だったので、なんだ、rotateあるなら簡単にできるやん!となった訳だ。

そして!

できなかった!!!

代わりにできたのが。。冒頭に戻る。

もうちょい考えないとダメみたいだ。

以上

Stomworksのエンジン完全に理解した。

最近始めたStormworksというゲーム。
いろんな乗り物を自分で設計できて、それを使ってレスキュー任務をこなすのが目的なんだけど目的そっちのけで設計にのめり込む。

参考動画を見ながら基本的なエンジンの構成を組んでみて、よく理解できた。

このゲームを構成する最も重要なパーツは、パイプだ。
パイプは気体・液体・動力を運ぶ役割を持っていて、とにかくパイプをつなぐことでモノが動きだす。
※図のパイプは塗り分けているだけで同じもの。

動力の伝達にパイプってのが変だけど、そういうゲームだしむしろシンプルで面白い。
グネグネと曲がりくねったようにパイプをつなげても、繋がってさえいれば動力伝達されるのだ。

また液体も重力無視でつながってさえいれば流れる。

あとはバッテリーから各コンポーネントへ電力を供給し、

コンポーネント同士を信号線で繋げば完成。

信号は、ポチから輪っかへという一方通行。
オンオフ信号が赤で、数値信号-1~1が緑である。


この世界の基本原理が理解できたので、あとは山ほどある部品を少しずつ使うものから理解していけば自由にマシンが作れそうだ。

ということで、しばらくStormworks続けてみようかと思う。

LEGO Mindstorm EV3でライントレースボットを作ってみる。

今回はLEGO Mindstorm EV3でライントレースボットを作ってみた。

ライン(線)をトレース(追いかける・辿る)するロボットだ。

絵面はこんな感じ。

このためにわざわざライントレース用のパネルを購入。
普通にAmazonで検索するとなんと1万7千円とか馬鹿げた値段のものが出てきたんだけど、競技用の公式品か何かだろうか。。

白地に黒線描いただけやん!

まじかよ。

私が買ったのは4000円くらいの良心的なやつ。

??良心的??

白地に(略!

目的

PID制御を用いたスムーズなライントレースを目指すことで、微積分の重要さを改めて認識して学習のモチベーションとしたい。
ただセンサー1個では難しいので、まずは簡単なジグザグ方式のボットから。追加のセンサーはメルカリ済み。

雰囲気

LEGO Mindstorm EV3ではサーボと、カラーセンサーを本体(コンピュータ)をから制御することができ、この機能を使うとレゴで本当に動作するロボットを作ることができる。

本体に専用のOSを書き込んだMicroSDカードを挿すことでPythonコードを動かすことができるようになるという仕組み。
起動中のスクリーンをみてみた。見る人が見れば一発で分かると思うけど、これ多分Linuxだな。

さて、ちゃんとしたタイヤは2個しか入ってないけどとりあえず適当に組み立ててみたところ、本体どう乗せるんだこれ問題に直面。

一旦ばらし。

気を取り直して再度手持ちのパーツでがちゃがちゃいじる。

できた!

こいつは、ドラゴンスネイク1号と名付けよう。

竜頭蛇尾だから。

LEGOさん。。タイヤ2個入りってひどくないっすか。

USBでパソコンに繋いで、

VS Codeでプログラムを書く。

プログラム

#!/usr/bin/env pybricks-micropython
import time
from pybricks.hubs import EV3Brick
from pybricks.ev3devices import (Motor, TouchSensor, ColorSensor,
                                 InfraredSensor, UltrasonicSensor, GyroSensor)
from pybricks.parameters import Port, Stop, Direction, Button, Color
from pybricks.tools import wait, StopWatch, DataLog
from pybricks.robotics import DriveBase
from pybricks.media.ev3dev import SoundFile, ImageFile

# This program requires LEGO EV3 MicroPython v2.0 or higher.
# Click "Open user guide" on the EV3 extension tab for more information.

# Create your objects here.
ev3 = EV3Brick()


# Write your program here.
ev3.speaker.beep()

a_motor = Motor(Port.A)
d_motor = Motor(Port.D)
cs = ColorSensor(Port.S1)
a_motor.reset_angle(0)
d_motor.reset_angle(0)

a_motor.run(36)
d_motor.run(36)

while True:
    if cs.reflection() < 50:
        a_motor.run(36*10)
        d_motor.run(36)
    else:
        d_motor.run(36*10)
        a_motor.run(36)

説明

メインループはこの部分

while True:
    if cs.reflection() < 50:
        a_motor.run(36*10)
        d_motor.run(36)
    else:
        d_motor.run(36*10)
        a_motor.run(36)

カラーセンサーの反射値で黒線と白地の境界が50くらいなので、50より暗ければ左タイヤの回転を上げて右カーブ、明るければ右タイヤの回転を上げて左カーブという方法で1つのセンサーでライントレースを行っている。

ちなみに何度も曲がり切れずにコードを調整している途中でバッテリー切れを迎えたので上記コードになってからテストはまだしてない。

まぁそもそもセンサー1個では限界あるしな。
3つ使って綺麗にライントレースしている動画を見たので2個メルカっておいた。

ちなみにAmazonでカラーセンサーの新品を見ると2万近くしてて、なんでこんな高騰してんのか調べてみたらLEGO Mindstorm EV3てもう廃盤なんだということが分かった。

ああ、もう新品はなかなか手に入らないのか。なら1セット7万とかしているのも頷ける。

後継はLEGO SPIKEというらしい。

どれどれ。。

6万!おまえもかよ。(白目)

以上

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。