• 締切済み

下記プログラムについてご教授をお願いいたします

お世話になります。 すいません。下記のプログラムにおいてお聞きしたいことがあります。(プログラムの記述の順は無視してください。) void int_tim_b1(void)がタイマーによって10ms毎に呼ばれ、void control_pid(void)の 関数処理が始まり、float TBL_target(float sec, tbl_target *tbl)にテーブル値を引数として 渡すようなのですが、float TBL_target関数において府に落ちない点があります。 例えば、10ms経ち、引数secに0.01が入り、if(sec > tbl[i].time)の条件においてi = 0なので、 tbl[i].time == 0なので、次のif(0 > tbl[i].time)が判定されますが、これは「偽」ですので、 処理はされず、次のelse if(i == 1)もまだi == 0なので、実行されず、elseの中が処理されると 思うのですが、tbl[i-1].target、tbl[i-2].target等の処理は配列の要素の中身が負となってしまうと思うのですが、 違いますでしょうか? 又、else if(i == 1)の処理もtbl[i-1].target == 0となってしまい、次の割り算処理において 「0/0」の0割り処理となってしまう気がいたします。 自分の理解が間違っていると思うのですが、何分わからず、大変困っております。 何卒ご教授のほどよろしくお願いいたします。 typedef struct { float time; float target; } tbl_target; void control_pid(void); float TBL_target(float sec, tbl_target *tbl); const tbl_target tbl_target_angle[ ] = { /* time[sec], target_angle[m/sec] */ 0, 0, 4.99f,       0, 5, PI/2, 10, PI/2, 15, 0, 20, 0, -1, -1, }; #pragma interrupt(INT_TimerB1) void int_tim_b1(void) { IRR2.BIT.IRRTB1 = 0; /* 割り込み要求フラグクリア*/ if(c_start) { control_pid(); c_time += 10; } } void control_pid(void) { theta_ref = TBL_target((float)c_time / 1000, tbl_target_angle); /* 目標値*/ } float TBL_target(float sec, tbl_target *tbl) { int i; float a, b; i = 0; while(1){ if(sec > tbl[i].time){ if(0 > tbl[i].time){ /* -1:テーブル終端の場合 */ if(i == 0){ /* テーブルデータなし */ return 0; } else if(i == 1){ /* 初期値は0として直線補間 */ a = tbl[i-1].target / tbl[i-1].time; b = 0; return a * sec + b; } else{ /* 前2点で直線補間 */ a = (tbl[i-1].target - tbl[i-2].target) / (tbl[i-1].time - tbl[i-2].time); b = tbl[i-1].target - a * tbl[i-1].time; return a * sec + b; } } i++; /* 次のデータへ */ } else if(sec == tbl[i].time){ /* テーブルデータと同じ場合 */ return tbl[i].target; } else{ if(i > 0){ /* 前1点で直線補間 */ a = (tbl[i].target - tbl[i-1].target) / (tbl[i].time - tbl[i-1].time); b = tbl[i].target - a * tbl[i].time; return a * sec + b; } else{ /* 前1点は0として直線補間 */ a = tbl[i].target / tbl[i].time; b = 0; return a * sec + b; } } } }

みんなの回答

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.3

> ただ、else if(i == 1)の時の処理がいつかのタイミングでされると思うのですが、 > else if(i == 0)の処理が行われるタイミングがこない気がいたします。 たしかに、あまり綺麗なコードではないですが。 このプログラムがどんな原理でどんな処理をしようとしているのか、を考えるのがいいのではないでしょうか? このプログラムの目的は、 tbl_target_angle のtimeで指定された時刻に target になるような出力を得ることです。 sec=tbl[i].timeのときはそのままtbl[i],targetを、 tbl[i-1].time<sec<tbl[i].timeのときは、線形補間します。 そこで、 戦略として、次のようにします。 (1)sec > tbl[i].time の場合: tbl[i-1].time<tbl[i].time<sec の状態です。 一つ隣りの区間(tbl[i].time,tbl[i+1].time)に入っているかどうか調べるために、 i++して次のループへ行きます。 (2) sec=tbl[i].time なら そのまま tbl[i],target をreturnしてループ終了です。 (3) それ以外の場合 残るは、 sec < tbl[i].time しかありません。 また、ループしてここに来ているので、前の段階ではsec > tbl[i-1].time だとわかっています。 つまり、 tbl[i-1].time<sec<tbl[i].time ですので、補間してループ終了です。 ここで、問題になるのは、 secがtblの範囲外だった場合です。 そこで、tblの終端として、time=-1 となる項目が追加されています。 tblの最後まで来てしまったら、特別な処理をしてループを終了させます。 if (0>tbl[i].time)~ は、 tbl[i] が終端だった場合の処理をするためのものです。 となると i==0 が真となるのは tbl[]={{-1,-1}} というデータが空の時だけです。 i==1 が真となるのは tbl[]={ {2,4}, {-1,-1} } というデータが1つしか無い時だけです。

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.2

if ~ else ~ の関係を確実に掴むようにしてください。 整形ツールを使って、字下げをちゃんとつけるのもよいでしょう。 // ここの特性上、空白がまとめられてしまうので、非常にわかりづらくなってしまいます。 if (A) { if(B) { } else { /* ここ */ } } とあったら、 if(A) の後の { と、それに対応する } までが 真のときに実行されるthen節です。 if(A)に対するelseは、上記の } の後に記述されます。 /* ここ */ のelse は、 if(A)の{}の中にあるので、 if(A)に対するelseではありません。 > 例えば、10ms経ち、引数secに0.01が入り、if(sec > tbl[i].time)の条件においてi = 0なので、 > tbl[i].time == 0なので、次のif(0 > tbl[i].time)が判定されますが、これは「偽」ですので、 > 処理はされず まではよいのですが、その後が間違いです > 次のelse if(i == 1) は if(i == 0) { /* テーブルデータなし */ } else if(i == 1) { /* 初期値は0として直線補間 */ } else { /* 前2点で直線補間 */ } となっている i==0に対するelse です。 これらは if(0 > tbl[i].time){ } に対する then節の{}の中に書いてあるので、 偽の場合は実行されません。

bmp919
質問者

補足

お忙しいところご回答いただき誠にありがとうございます。 回答して頂いた内容を拝見させて頂き、まだ完全ではないですが、理解できました。 ただ、else if(i == 1)の時の処理がいつかのタイミングでされると思うのですが、 a = tbl[i-1].target / tbl[i-1].time;において tbl[i-1].target == 0、tbl[i-1].time == 0となってしまうのは間違いないと思うのですが 違いますでしょうか? というよりも、else if(i == 0)の処理が行われるタイミングがこない気がいたします。 以上、何卒よろしくお願いいたします。

回答No.1

違います。 括弧対応を誤解していると思います。 47行目の if (0 > tbl[i].time) {に対応した}は64行目 (i++の直前) の}ですよね。 つまり、i == 0のとき、if (0 > tbl[i].time)がfalseとなるので、i++が実行され、その後にwhileループ内で実行されるべき文がないのでwhileループの先頭から、実行すると思います。 i == 1のとき、46行目 if (sec > tbl[i].time) {がfalseで、66行目 } else if (sec == tbl[i].time) {もfalseなので、69行目のelseが実行され、70行目if (i > 0) {がtrueなので、/* 前1点で直線補間 */のブロックを実行し、値をreturnしていると思います。

関連するQ&A