09.11
林 正幸
マイコンが計測制御する
「力と運動」実験システム
04年に「力と運動」実験システムを開発したとき
http://www.water.sannet.ne.jp/masasuma/masa/ne11.htm
そのおわりに「私はもう厭だが誰か、制御回路と速度計、そして表示をコンピュータ制御
にしてくれるなら歓迎する」と書いた。
しかしそのあとEHCにおいて、H8マイコンを使った汎用計測制御システム(H8U
MCS)を開発し、プログラミングも有用な関数ができて容易になってきた。そこで一念
発起し、放棄するつもりのこの課題に自ら取り組むことにした。これで計測や制御の幅が
広がり、結果の表示も豊かになり、計測が楽になった。
ここでは前のプリントに追加する形で、新しい部分を記録する。
[a]ハード
力を掛ける前後の速度は、0.100mを通過する時間をデジタルストップウオッチで計
測し、計算して求めていた。H8UMCSでは2つの光センサーの信号を入力すれば、そ
れぞれの時刻を記憶し、時間だけでなく速度なども計算して表示できる。
力をかける時間や距離は、リニアモーターのそばの光センサーでライダー(運動体)の
遮へい板を検出し、専用のデジタル回路を製作してリレーをオン・オフしたり、さらにウ
オッチに接続して計測していた。これもその光センサーの信号を入力し、H8UMCSか
らリレー制御のために信号を送ればよい(分かりやすいように、LED点灯のための信号
も送る)。
光センサーの電源(5V)はH8UMCSから接続する。ただしリレー部はホトカプラ
を通し、12Vの別電源にする(H8UMCSの12Vはパアーがない)。リニアが動作
する初期に発生する鋭い雑音は、ソフトの方でその間の信号を無視することによって回避
する。
なおライダーに鉛板(2×3cmで5.3g)を貼ることによって、エアトラックにバラ
ンスよく乗るように工夫した。
次ページに搭載する「カード」と光センサーの回路を示すが、H8UMCS自身につい
ては次のホームページを参照してほしい。
http://www.wa.commufa.jp/~dentyukb/index.html
[b]計測制御内容
[1]これは次の4つに分けられる。
- 1 -


- 2 -
1:力を掛ける 時間を決めて計測する
2: 〃 距離を決めて計測する(同時に力が掛かる時間も計測する)
0:エアトラックの水平(等速度で運動する状態)を確保する
そして2はさらに
2−1:距離と速度変化の関係を表示する
2−2:距離と時間の 〃
に分かれる。
1,2のいずれにおいても、初速度を0にしても計測できる(分かりやすい)。
[2]1は次の関係式を確認する。
Δv = k1t (F,m:一定)
またはライダーを換えて質量(0.075,0.100,0.125 or
0.150kg)を変えれば
a = k2/m (F,t:一定)
表示されるのは
力を掛ける時間:t 初速度:v1 終速度:v2
速度差:v2−v1 加速度:a
である。
さらに携帯電子てんびんを使って力を計測すれば(リニアを直接駆動)
k2 =F
つまり
F = ma
も確認できる(これを前提に、ライダーの質量から掛かる力を計算することもできる)。
[3]2−1は次の関係式を確認する。距離は0.1,0.2,0.3,0.4,0.5 or
0.6mから選ぶのが基本である。
Δv2 = k3S (F,t,m:一定)
表示されるのは
力を掛ける距離:S 初速度:v1 初速度の2乗:v1*
終速度:v2 終速度の2乗:v2* 速度の2乗の差:v2*−v1*
なお予め1で加速度を計測しておけば
k3 = 2a
であることも確認できる。
[4]2−2は次の関係式を確認する。
S−v1×t = k4t2 (F,m:一定)
表示されるのは
力が掛かる時間:t 時間の2乗:t*
初速度:v1 力を掛ける距離 − 初速度×時間:S−v1*t
これも予め加速度計測しておけば
k4 = (1/2)a
- 3 -
であることも確認できる。
[5]0はライダーを走らせて、初速度と終速度が同じになるかを確認する。これは計測
の前提である。
[c]ソフト(使い方)
@スイッチを入れると名称に続いて
「チカラ ヲ カケル
1:ジカン ヲ キメル
2:キョリ ヲ キメル
0:スイヘイ ヲ カクホ スル」と表示されるので、選択する。
A1なら
「ナン ds(0.1s) カ
(1 カラ 99 ds)
ジカン= (ds)」と表示されるので
数字を入力し '#’を押す。
B2なら
「ナン dm(0.1m) カ
(1 カラ 6 dm)
キョリ= (ds)」と表示されるので
数字を入力し '#’を押す。
続いて
「ドチラ ヲ ヒョウジ スルカ
1:キョリ ト ソクド ノ カンケイ
2:キョリ ト ジカン ノ カンケイ」と表示されるので、選択する。
Cそして0でないなら
「ショソクド ハ ?
1:ハカル
0: 0m/s ニ スル」と表示されるので、選択する。
0m/sなら、実験ではごく小さい初速度でスタートする(センサー1は外してよい)。
D目的のセンサーが動作しているかチェックして、もし動作していないならたとえば
「センサー1 ガ フチョウ
テンケン シテ #キー ヲ オセ」と表示されるので、指示に従う。すると再点検して異常がなければ
たとえば
「ジッケン ヲ ハジメテ クダサイ
ジカン ト ソクド ノ カンケイ
ジカン= 20ds」
- 4 -
というメッセージが表示される。
<1:時間と速度変化の関係あるいは質量と加速度の関係の場合>
Eある質量のライダーを選び、力の大きさ(リニアに掛けるスライダックの電圧)を決め、
ライダーを走らせる。
もし力が大き過ぎたり、掛ける時間が長過ぎた場合(あるいはライダーが短過ぎる)は、
「チカラ ガ オオキスギル
ジカン ガ ナガスギル」とエラーが表示されて、計測が終了する。
うまく計測できればたとえば
「t= 1.6s(ソクドタンイ:m/s)
v1= 0.147 v2= 0.260
v2-v1=0.113
a= 0.071m/s^2」
などと表示される。
たとえば時間を変えてくり返し計測すれば、グラフが描け、関係式が確認できる。
<2:距離と、速度変化ないし時間の関係の場合>
F0.1mごとに遮へい板を付けた長い(質量が大きい)ライダーを選び、力の大きさを決
め、ライダーを走らせる。
計測が終わると、距離と速度変化の関係の場合はたとえば
「S=0.5m (ソクドタンイ:m/s)
v1= 0.163 v2= 0.288
v1*= 0.027v2*= 0.083
v2* - v1* = 0.056」
などと表示される。
距離を変えてくり返し計測すれば、グラフが描け、関係式が確認できる。
<0:水平を確保するの場合>
G計測すると2つの速度が表示されるので、傾きを調節し色々な速度でライダーを走らせ
て水平を確保する。通常は0.2m/sあたりで調節する。
[d]計測事例
改めていくつか計測してみた。いずれもほぼ原点を通る直線になった(最後にあるグラ
フを参照)。
[1]Δv = k1t
水平確保:0.259 → 0.258m/s
質量:0.150(+0.011)kg
リニアモーター:40V
t v1 v2 Δv
0.4s 0.217m/s 0.245m/s 0.028m/s
0.8 0.203 0.257 0.054
- 5 -
1.2 0.174 0.258 0.084
1.6 0.147 0.260 0.113
2.0 0.126 0.268 0.142
2.4 0.120 0.284 0.164
最小2乗法による1次関係式
Δv = 0.0695t + 0.0002
[2]a = k2/m
水平確保:0.207 → 0.207m/s(0150kgのライダーで)
リニアモーター:40V
力をかける時間:1.0s
1/m[1/kg] v1 v2 a
1/0.166= 6.02 0.166m/s 0.225m/s 0.059m/s2
1/0.136= 7.35 0.151 0.227 0.076
1/0.100=10.0 0.145 0.246 0.101
1/0.075=13.3 0.097 0.234 0.137
最小2乗法による1次関係式
Δv = 0.01049×(1/m) + 0.003
[3]Δv2 = k3S
水平確保:0.199 → 0.198m/s
質量:0.150(+0.011)kg
リニアモーター:40V
S v1 v2 Δv2
0.1m 0.178m/s 0.209m/s 0.011m2/s2
0.2 0.182 0.236 0.022
0.3 0.135 0.235 0.037
0.4 0.144 0.261 0.047
0.5 0.163 0.288 0.056
0.6 0.130 0.294 0.069
最小2乗法による1次関係式
Δv2 = 0.1149S + 0.0001
[4]S−v1×t = k4t2
水平確保:0.195 → 0.195m/s
質量:0.150(+0.011)kg
リニアモーター:60V
S t2 v1 S−v1×t
0.1m 0.235s2 0.179m/s 0.014m
0.2 0.898 0.149 0.059
0.3 1.703 0.141 0.116
- 6 -
0.4 3.024 0.105 0.218
0.5 4.157 0.102 0.293
0.6 5.234 0.104 0.363
最小2乗法による1次関係式
S−v1×t = 0.0706t2 − 0.002
[e]プログラム
このプログラムは、H8UMCSのベーシック・ソフト genkei の上に載せて動
作させる。つまりこのソフトが持つ関数を利用している。
/*///////////////////////////////////////////////////////////////////
「力と運動」実験システムの
マイコン制御プログラム
ForceMotion
林 正幸
///////////////////////////////////////////////////////////////////*/
//汎用変数
unsigned char modo,jikan,kyori;
//追加の関数
//計測モードなどの選択
void sentaku(void)
{
char ki;
//タイトル表示
lcdclr();
lcdyx(1,1);
lcd1g("チカラ ト ウンドウ");
lcdyx(2,3);
lcd1g("ジッケン システム");
lcdyx(3,5);
lcd1g("(09.9 ハヤシ マサユキ)");
waitms(1000);
//選択
- 7 -
lcdclr();
lcdyx(1,1);
lcd1g("チカラ ヲ カケル");
lcdyx(2,1);
lcd1g("1:ジカン ヲ キメル");
lcdyx(3,1);
lcd1g("2:キョリ ヲ キメル");
lcdyx(4,1);
lcd1g("0:スイヘイ ヲ カクホ スル");
while(1)
{
ki = keyyomi(0);
if(ki < 0x33)
{
modo = ki-0x30;
break;
}
}
if(modo == 1)
{
lcdclr();
lcdyx(1,1);
lcd1g("ナン ds(0.1s) カ");
lcdyx(2,3);
lcd1g("(1 カラ 99 ds)");
lcdyx(3,1);
lcd1g("ジカン= (ds)");
while(1)
{
jikan = keynyuryoku2(3,6);
if(jikan > 0 & jikan < 100)
break;
}
}
if(modo == 2)
{
lcdclr();
lcdyx(1,1);
- 8 -
lcd1g("ナン dm(0.1m) カ");
lcdyx(2,3);
lcd1g("(1 カラ 6 dm)");
lcdyx(3,1);
lcd1g("キョリ= (ds)");
while(1)
{
kyori = keynyuryoku2(3,5);
if(kyori > 0 & kyori < 7)
break;
}
lcdclr();
lcdyx(1,1);
lcd1g("ドチラ ヲ ヒョウジ スルカ");
lcdyx(2,1);
lcd1g("1:キョリ ト ソクド ノ カンケイ");
lcdyx(3,1);
lcd1g("2:キョリ ト ジカン ノ カンケイ");
while(1)
{
ki = keyyomi(0);
if(ki == 0x31 | ki == 0x32 )
{
if(ki == 0x32)
modo = 3;
break;
}
}
}
if(modo > 0)
{
lcdclr();
lcdyx(1,1);
lcd1g("ショソクド ハ ?");
lcdyx(2,1);
lcd1g("1:ハカル");
lcdyx(3,1);
lcd1g("0: 0m/s ニ スル");
- 9 -
while(1)
{
ki = keyyomi(0);
if(ki < 0x32)
{
if(ki == 0x30)
modo = modo*10; //初速度を0m/sにする場合
break;
}
}
}
}
//装置の点検
void tenken(void)
{
//点検
modori:;
char hutyo = 0;
lcdclr();
if(modo < 9)
{
if(pb2 == 0 | pb3 == 0)
{
lcdyx(1,1);
lcd1g("センサー1 ガ フチョウ");
hutyo = 1;
}
}
if(modo != 0 & pb4 == 0)
{
lcdyx(2,1);
lcd1g("センサー0 ガ フチョウ");
hutyo = 1;
}
if(pb6 == 0 | pb7 == 0)
{
lcdyx(3,1);
- 10 -
lcd1g("センサー2 ガ フチョウ");
hutyo = 1;
}
if(hutyo == 1)
{
lcdyx(4,3);
lcd1g("テンケン シテ #キー ヲ オセ");
while(1)
{
hutyo = keyyomi(0);
if(hutyo == '#')
break;
}
goto modori;
}
//メッセージ
lcdclr();
lcdyx(1,1);
lcd1g("ジッケン ヲ ハジメテ クダサイ");
lcdyx(2,3);
if(modo == 0)
lcd1g("スイヘイ ヲ カクホ");
if(modo == 1 | modo == 10)
lcd1g("ジカン ト ソクド ノ カンケイ");
if(modo ==2 | modo == 20)
lcd1g("キョリ ト ソクド ノ カンケイ");
if(modo == 3 | modo == 30)
lcd1g("キョリ ト ジカン ノ カンケイ");
if(modo >9)
{
lcdyx(3,3);
lcd1g("(ショソクド ハ 0m/s)");
}
lcdyx(4,3);
if(modo == 1 | modo == 10)
{
lcd1g("ジカン=");
suuhyozi(4,8,jikan,0,0);
- 11 -
lcdyx(4,11);
lcd1g("ds");
}
if(modo > 1 & modo != 10)
{
lcd1g("キョリ= dm");
lcdyx(4,8);
lcdo4(kyori + 0x30);
}
}
//計測表示0
void keisoku0(void)
{
unsigned int SP1,SG1,SG2,ST2,SP2;
int sokudo1,sokudo2;
//計測
SP1 = kaunta32(0,1,'m');
while(1) //センサー1
{
if(pb2 == 0)
{
SP1 = kaunta32(1,1,'m');
break;
}
}
while(1)
{
if(pb3 == 0)
{
SP1 = kaunta32(2,1,'m');
break;
}
}
while(1) //センサー2
{
if(pb6 == 0)
{
- 12 -
ST2 = kaunta32(2,1,'m');
break;
}
}
while(1)
{
if(pb7 == 0)
{
SP2 = kaunta32(3,1,'m');
break;
}
}
//表示
lcdclr();
lcdyx(1,1) //初速度
lcd1g("v1= m/s");
sokudo1 = 100000/SP1;
suuhyozi(1,4,sokudo1,3,3);
lcdyx(2,1); //終速度
lcd1g("v2= m/s");
sokudo2 = SP2-ST2;
sokudo2 = 100000/sokudo2;
suuhyozi(2,4,sokudo2,3,3);
}
//計測表示1
void keisoku1(void)
{
unsigned int SP1,SG1,SG2,ST2,SP2;
int sokudo1,sokudo2,kasoku;
//計測
SP1 = kaunta32(0,1,'m');
if(modo == 1)
{
while(1) //センサー1
{
if(pb2 == 0)
{
- 13 -
SP1 = kaunta32(1,1,'m');
break;
}
}
while(1)
{
if(pb3 == 0)
{
SP1 = kaunta32(2,1,'m');
break;
}
}
while(1) //センサー0
{
if(pb4 == 0)
{
if (modo == 10)
SG1 = kaunta32(1,1,'m');
else
SG1 = kaunta32(2,1,'m');
pb0 = 1; pb1 = 1;
waitms(30); //チャタリング防止 & 初期雑音のやり過ごし
while(1) //遮蔽の通過を確認
{
if(pb4 == 1)
{
waitms(5);
break;
}
}
break;
}
}
while(1)
{
if(pb4 == 0) //力が大き過ぎるなら
{
- 14 -
pb0 =0; pb1 = 0;
jikan = 100;
goto OWARI;
}
SG2 = kaunta32(2,1,'m');
if(SG2 >= SG1 + jikan*100)
{
pb0 =0; pb1 = 0;
break;
}
}
while(1) //センサー2
{
if(pb6 == 0)
{
ST2 = kaunta32(2,1,'m');
break;
}
}
while(1)
{
if(pb7 == 0)
{
SP2 = kaunta32(3,1,'m');
break;
}
}
OWARI:;
//表示
lcdclr();
if(jikan == 100) //力が大き過ぎるなら
{
lcdyx(1,1);
lcd1g("チカラ ガ オオキスギル");
lcdyx(2,1);
lcd1g("(ジカン ガ ナガスギル)");
goto TOBI;
}
- 15 -
lcdyx(1,1);
lcd1g("t= s(ソクドタンイ:m/s)"); //時間
suuhyozi(1,3,jikan,1,1);
lcdyx(2,1); //初速度
lcd1g("v1=");
if(modo == 10)
{
lcdyx(2,5);
lcdo4('0');
}
else
{
sokudo1 = 100000/SP1;
suuhyozi(2,4,sokudo1,3,3);
}
lcdyx(2,11); //終速度
lcd1g("v2=");
sokudo2 = 100000/(SP2-ST2);
suuhyozi(2,14,sokudo2,3,3);
lcdyx(3,1);
lcd1g("v2-v1=");
if(modo == 10)
suuhyozi(3,7,sokudo2,3,3);
else
suuhyozi(3,7,sokudo2-sokudo1,3,3);
lcdyx(4,1); //加速度
lcd1g("a= m/s^2");
kasoku = (sokudo2 - sokudo1)*10/jikan;
suuhyozi(4,3,kasoku,3,3);
TOBI:;
}
//計測表示2
void keisoku2(void)
{
unsigned int SP1,SG1,SG2,ST2,SP2;
char kai = 0;
long sokudo1,sokudo2,sokusa,jikanms,kyorisa;
- 16 -
//計測
SP1 = kaunta32(0,1,'m');
if(modo == 2 | modo == 3)
{
while(1) //センサー1
{
if(pb2 == 0)
{
SP1 = kaunta32(1,1,'m');
break;
}
}
while(1)
{
if(pb3 == 0)
{
SP1 = kaunta32(2,1,'m');
break;
}
}
}
while(1) //センサー0
{
if(pb4 == 0)
{
if (modo == 20 | modo == 30)
SG1 = kaunta32(1,1,'m');
else
SG1 = kaunta32(2,1,'m');
pb0 = 1; pb1 = 1;
waitms(5); //チャタリング防止
while(1) //遮蔽の通過を確認
{
if(pb4 == 1)
{
waitms(5);
break;
}
- 17 -
}
break;
}
}
while(1)
{
if(pb4 == 0)
{
kai = kai + 1;
if(kai == kyori)
{
SG2 = kaunta32(2,1,'m');
pb0 = 0; pb1 = 0;
break;
}
waitms(30); //チャタリング防止 & 初期雑音のやり過ごし
while(1) //遮蔽の通過を確認
{
if(pb4 == 1)
{
waitms(5);
break;
}
}
}
}
while(1) //センサー2
{
if(pb6 == 0)
{
ST2 = kaunta32(2,1,'m');
break;
}
}
while(1)
{
if(pb7 == 0)
{
- 18 -
SP2 = kaunta32(3,1,'m');
break;
}
}
//表示
lcdclr();
lcdyx(1,1);
lcd1g("S= m (ソクドタンイ:m/s)"); //距離
suuhyozi(1,3,kyori,1,1);
if(modo == 2 | modo == 20)
{
lcdyx(2,1); //初速度
lcd1g("v1=");
if(modo == 20)
{
lcdyx(2,5);
lcdo4('0');
}
else
{
sokudo1 = 100000/SP1;
suuhyozi(2,4,sokudo1,3,3);
}
lcdyx(2,11); //終速度
lcd1g("v2=");
sokudo2 = 100000/(SP2-ST2);
suuhyozi(2,14,sokudo2,3,3);
lcdyx(3,1); //初速度^2
lcd1g("v1*=");
if(modo == 20)
{
lcdyx(3,6);
lcdo4('0');
}
else
{
sokudo1 = sokudo1*sokudo1;
suuhyozi(3,5,sokudo1,6,3);
- 19 -
}
lcdyx(3,11); //終速度^2
lcd1g("v2*=");
sokudo2 = sokudo2*sokudo2;
suuhyozi(3,15,sokudo2,6,3);
lcdyx(4,1); //速度^2の差
lcd1g("v2* - v1* =");
sokusa = sokudo2 - sokudo1;
suuhyozi(4,12,sokusa,6,3);
}
if(modo == 3 | modo == 30)
{
lcdyx(2,1); //時間
lcd1g("t= s");
jikanms = SG2 - SG1;
suuhyozi(2,3,jikanms,3,3);
lcdyx(2,11); //時間^2
lcd1g("t*=");
jikanms = jikanms*jikanms;
suuhyozi(2,14,jikanms,6,3);
lcdyx(3,1); //初速度
lcd1g("v1=");
if(modo == 30)
{
lcdyx(3,5);
lcd1g("0");
goto TOBE;
}
else
{
sokudo1 = 100000/SP1;
suuhyozi(3,4,sokudo1,3,3);
lcdyx(3,10); //初速度×時間
lcd1g("v1*t=");
jikanms = SG2 - SG1;
sokudo1 = sokudo1*jikanms/1000;
suuhyozi(3,15,sokudo1,3,3);
}
- 20 -
lcdyx(4,1); //距離 −(初速度×時間)
lcd1g("S - v1*t =");
kyorisa = kyori*100 - sokudo1;
suuhyozi(4,11,kyorisa,3,3);
TOBE:;
}
}
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
////////////メインプログラム ///////////////////////////////////////
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
int main(void)
{
//使用変数の宣言
//ポート、液晶表示、I2CEEPROM、RS232C通信(大型表示用)などの初期化関数
potosyokika();
// IOsyokika();
lcdsyokika();
i2csyokika();
i2caddress(0);
sci0syokika(BR9600);
sci1syokika(BR9600);
//ここからメインプログラムを書く
//PB0:出力 1でリレーがON
//PB1:出力 1でLEDがON
//PB2:入力 センサー1のST検出で0
//PB3:入力 センサー1のSP検出で0
//PB4:入力 センサー0のシグナル検出で0
//PB5:入力 プルアップ 常に1
- 21 -
//PB6:入力 センサー2のST検出で0
//PB7:入力 センサー2のSP検出で0
//モード0:水平を確保
//モード1:時間と速度の関係または質量と加速度の関係
//モード2−1:距離と速度変化の関係
//モード2−2:距離と時間の関係
//うしろに0を加えると初速度が0m/s
//ライダーの質量は 0.075,0.100,0.125,0.150kg
//リニアモーターの力の計測は、このプラグラム抜きで行う。
PB.DDR = 0x03; //pbの設定
pb0 =0; pb1 = 0; //リニアをOFF
sentaku();
tenken();
if(modo == 0)
keisoku0();
if(modo == 1 | modo == 10)
keisoku1();
if(modo > 1 & modo != 10)
keisoku2();
return 0;
}
- 22 -

- 23 -

- 24 -
林 正幸と主万子の始めの
ホームページ(to our initial Home Page)
にもどる。