スピログラフは半世紀も前に流行ったデザイン用のおもちゃで、色んな模様が描けます。その定規は百均でも売られていますが、もはやこれが何であるか知っている人の方が少ないかもしれません。
小さな円を大きな円に内接させながら穴に鉛筆やボールペンなどを差し込んでぐるぐる回せば模様が描けます。器用な人だと、この模様をいくつか組み合わせて次のようなデザインをします。
上の写真は次に載っています。
この最初の品は1965年に発売され、以後10年以上も世界で大ヒットしていたらしいです。
Denys Fisher original Spirograph 1965 | ralph stephenson | Flickr
実際使ってみればわかりますが、不器用な人はどこかで失敗して線が違う方向へとずれたりします、私もですが^^; やり直すのもたいへん。
そこで、PCで描けばずっと簡単にできそうです。そのために、まず式を考えます。汚いメモ書きですみませんが。
円Bの中心PがΘ回れば、円B自体はがa/b倍だけ逆に回るので、座標軸からみた傾き(Pから穴Qへの向き)としては Θー(a/b)Θ 回ることになります。なので上の式になるわけです。
これさえわかると後は簡単。プログラムで確認すると次のようになります。
画面をカメラで撮ったので少し傾いていてすみません<(_ _)>。
驚くような模様が次々に現れるから不思議です。このプログラム自体は記事の最後の方に載せておきますね。今回はMicrosoft Small Basicでちょこっと作ったシンプルなプログラムです。
さて、これでは当たり前で全然面白くないし、第一に電子工作とは言えませんね。電子工作として子供たちにも見せるには、マウスで描いて見せればよいかなと、忙しいときに余計なことをつい考えついてしまいました。
これならArduinoをマウスとして動かせばすぐにもできそうです。早速作るとしましょう。
前にキーボードを作るために余分に買ったArduino Pro Microが余っていますので、これを使ってみます。このモデルはコンパチ機が流通の主体で、海外だと1つ4ドル前後です。最新のIDEではLeonardoとしてプログラミングします。
考えてみたらこれには特別な回路など殆ど要りませんね。ここでは、単にディジタルピン8にタクトスイッチをつなぐだけにしました。
配線はグランドから右へ出した1本だけです。これにタクトスイッチの片側を接続。ハードウェアはたったのこれだけです。
Arduino IDEでプログラミングする際、ボードはLeonardoを指定。プログラム・スケッチは次のとおりで50行ほどの小さなものです。
/* Spirograph drawing machine. Arduino Pro-Micro as a Mouse
(c)Akira Tominaga June 15th, 2020 */
#include "Mouse.h"
#define Button 8 // Button pin
#define bChatT 100 // chattering time
float rA = 300.0;
float rB = 211.0;
float rC = rB * 0.90;
float KakuHi = (rB - rA) / rB;
float Pi = 3.141593;
float gyakuPi = (1.0 / Pi) / 100.0;
int xX;
int yY;
#define pX 0
#define pY 0
#define rBdecr 0.9
#define rCrate 0.8
void setup() {
pinMode(Button, INPUT_PULLUP);
Serial.begin(9600);
Mouse.begin();
while (digitalRead(Button) == HIGH) {}
delay(bChatT);
while (digitalRead(Button) == LOW) {}
}
void loop() {
int xS = pX;
int yS = pY;
int i = 0;
for (float Theta = 0 ; Theta < 300 * Pi ; Theta = Theta + gyakuPi) {
if (i > 0) {
Mouse.press();
}
xX = (float)( (rA - rB) * cos(Theta) + rC * cos(KakuHi * Theta));
yY = (float)( (rA - rB) * sin(Theta) + rC * sin(KakuHi * Theta));
int Xmove = xX - xS;
int Ymove = yY - yS;
Mouse.move(Xmove, Ymove, 0);
if (digitalRead(Button) == LOW) break;
xS = xX;
yS = yY;
i = 1;
}
while (digitalRead(Button) == LOW) {}
delay(bChatT);
Mouse.release();
while (digitalRead(Button) == HIGH) {}
while (digitalRead(Button) == LOW) {}
delay(bChatT);
rB = rB * rBdecr;
rC = rB * rCrate;
KakuHi = (rB - rA) / rB;
delay(300);
}
操作は次のようにしますが単純です。
お絵描きソフトとして、Windows Paint(マウスで描けるソフトならほかに何でもよいです)を立ち上げ、
①書き始めの地点(出来上がる図形の上下中央の右端になります)にカーソルをもっていく。
②タクトスイッチを押す。するとスピログラフを描き出します。
止めたいところで再び
③タクトスイッチを押せばとまります。
止まっている間にブラシや鉛筆、色などを選んでからカーソルの場所を移動して①②③を繰り返せば色や太さが選べます。
これなら子供達の前で見せたり、どや顔もできそう。色々工夫すれば好きなことができますが、何も役立ちませんね^^
最後にWindowsの一番簡単な言語と思われるSmall Basicで書いたプログラムを入れておきます。outputは最初のほうに出した動画です。もちろん言語は何でもよいです。
myTitle="Automatic Spirograph V00 (c)2020 A.Tominaga "
' GraphicsWindow definition
Gt=10 ' top edge position
Gl=50 ' left edge position
Gw=900 ' window width
Gh=900 ' window height
Ds=1.25 'display scaling rate is 125% in this case
GraphicsWindow.top=Gt
GraphicsWindow.Left=Gl
GraphicsWindow.Width=Gw
GraphicsWindow.Height=Gh
GraphicsWindow.Title=myTitle
' TextWindow definition
Tt=(Gt+Gh)*Ds-377 'adjusted text window's top edge position
Tl=(Gl+Gw)*Ds+2 ' set clearance with graphic window
TextWindow.top=Tt
TextWindow.left=Tl
TextWindow.Title=myTitle
' Radii of Circles
rA=400 'A circle radius
rBdefault=171
Inq:
TextWindow.Write("*** rA=400. Input rB initial size -> ")
rBinit=TextWindow.Read() 'B circle radius specified
If rBinit="" Then
rBinit=rBdefault
EndIf
If rB>rA-1 Then
goto Inq
EndIf
rCdefault=0.7 ' default C radius ratio to rB
' Main processes
For rB= rBinit To 350
rC=Math.Round(rB*rCdefault)
' define pen colors
cR=Math.GetRandomNumber(255)
getcG:
cG=Math.GetRandomNumber(255)
If cR+cG>320 Then
Goto getcG
EndIf
cB=Math.Round(255-(cR+cG)/1.2)
GraphicsWindow.PenColor=GraphicsWindow.GetColorFromRGB(cR,cG,cB)
GraphicsWindow.PenWidth=1
'draw Spirograph
GraphicsWindow.Clear()
XS=Gw/2 ' initial X position
YS=Gh/2 ' initial Y position
' Loop to draw graph
for theta= 0 To 500 Step 0.2
XX=(rA-rB)*Math.Cos(theta)+rC*Math.Cos(theta*(rB-rA)/rB)+Gw/2
YY=(rA-rB)*Math.Sin(theta)+rC*Math.Sin(theta*(rB-rA)/rB)+Gh/2
If theta>0 then ' exclude initial position
GraphicsWindow.DrawLine(XS,YS,XX,YY)
EndIf
XS=XX
YS=YY
EndFor
' Draw legend to show radius values of A, B, and C
fontSize=20
GraphicsWindow.FontSize=fontSize
fontW=fontSize/2 ' font width average to be
Lx=150 ' legend characters' X-position
Ly=65 ' legend characters' Y-position
Legend="Radii A=400 B="
LegLen=Text.GetLength(Legend)
GraphicsWindow.DrawText(Lx,Ly,Legend)
GraphicsWindow.DrawText(Lx+LegLen*fontW+2,Ly,rB)
LegLen2p=Lx+(LegLen+4)*fontW 'Len2 as pixel number
GraphicsWindow.DrawText(LegLen2p,Ly," C=")
GraphicsWindow.DrawText(LegLen2p+4*fontW+2,Ly,rC)
Name="Programmmed by A. Tominaga"
NameLen=Text.GetLength(Name)
fontSize=fontSize*0.6
GraphicsWindow.FontSize=fontSize
fontW=fontSize/2
Lx=Gw-(NameLen*fontW+Lx)
GraphicsWindow.DrawText(Lx,Ly+fontW,Name)
Program.Delay(1000)
EndFor
Sound.PlayBellRing()
Program.Delay(2000)
Program.End()
今回は単純で「どこが工作?」という感じではありますが、このへんで失礼したいと思います。
後で気づいたので補足します:三角関数は中学校で習うものと思っていたら、今は高校のようです。このIT時代に不思議なことですね。
©2020 Akira Tominaga, All rights reserved.