Closed masjinno closed 8 years ago
尻尾制御とは何かを定義してもらえないでしょうか?
尻尾制御を下記の通りに定義したいです。
いかがでしょうか。
モーター制御クラスと振り付けクラスの2つに分けて考えるのはどうでしょうか?
「振り付けクラス」というのは何をするクラスでしょうか。 (振り付けとは何でしょうか。)
モーター制御に特化したクラスなのですね。 そうすると、モーター制御を切り出すissueが必要ですね
モーター制御に特化したクラスに、振る舞いを実現する為のコードを入れるのは良くないと思ったので、振る舞いを実現する為のクラスとして「振り付けクラスは、どう?」と聞いた次第です
振る舞いはbehaviorと同義と捉えられるので、別の言葉で表現してみました
次のコンフリクトが発生するので、内容の確認と解消をお願いします。
$\src\EV3way_MonoBrick_Remote\ev3way_monobrick\ev3way_monobrick.csproj
<<<<<<< HEAD
<Compile Include="Motor\MotorTail.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<Folder Include="Motor\" />
=======
<Compile Include="..\..\common\ProtocolProcessor.cs">
<Link>Utils\ProtocolProcessor.cs</Link>
</Compile>
<Compile Include="..\..\common\ProtocolProcessorForEV3.cs">
<Link>Utils\ProtocolProcessorForEV3.cs</Link>
</Compile>
<Compile Include="..\..\common\ProtocolProcessorForPC.cs">
<Link>Utils\ProtocolProcessorForPC.cs</Link>
</Compile>
<Compile Include="..\..\common\PacketDataConverter.cs">
<Link>Utils\PacketDataConverter.cs</Link>
</Compile>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<Folder Include="Utils\" />
>>>>>>> release
尻尾制御が上手く行きません。 該当処理は、MotorTail.csのMotorTailクラスのSetMotorAngleメソッドです。
ループ(4ms周期?)の中で尻尾制御関数を毎回呼び出し、そのときの尻尾位置から、モーターに送るパワーを計算して、目標の角度にセットする。
目標とした動作:一度呼び出すことで、尻尾の角度を目標の角度にセットする。
SpeedProfileメソッドの戻り値、WaitHandleクラスを用いた動作は上手く行きませんでした。gキーの時点で寝かせていても処理を受け付けません。
上手く行かなければ、以前の毎ループ呼び出し制御の処理に戻そうと思います。
コンフリクト対応は、少し待ってください。 (対応方法がよくわかっていません・・・)
目標とした動作:一度呼び出すことで、尻尾の角度を目標の角度にセットする。
ということですが, Main.csでは
ループ(4ms周期?)の中で尻尾制御関数を毎回呼び出し
という用い方をしているようですが...
なんかいろいろ見過ごせない点があります.
motorTail.SpeedProfile (speed, 0, (uint)moveTachoCount, 0, true)
なぜこの引数を選んだのか, 説明できますか?
回答を待たずにコメントしますが, SpeedProfile()の説明 を読む限り,
WaitHandle MonoBrickFirmware.Movement.Motor.SpeedProfile (
sbyte speed,
UInt32 rampUpSteps,
UInt32 constantSpeedSteps,
UInt32 rampDownSteps,
bool brake
)
は, "rampUpStepsステップをかけて速度をspeedまで上げ, そのspeedをconstantSpeedStepsステップの間キープし, その後rampDownStepsステップをかけて元の速度 or 速度0 まで戻る" という動作をするように見えます. (元の速度か, 速度0かは, 読み取れませんが.)
前述の使い方が正しいならば, rampUpSteps に 0 を指定するということは, "0ステップをかけて(一瞬で)速度をspeedまで上げる" ということです. 急激に電流が流れ, デバイスをぶっ壊す可能性があります. (内部でケアしてくれているとは思いますが...) MonobrickのAPIの説明が十分でないということも一因としてありますが, 今後, (特に仕事で) デバイスを扱うときは, 注意してください.
constantSpeedSteps に moveTachoCount を渡していますが, おそらく Step と TachoCount は全くの別物です.
moveTachoCount = Angle - startTachoCount;
で, Angle と startTachoCount との演算を行っていますが, おそらく Angle と TachoCount は全くの別物です.
だと思います. (断言はできませんが)
ちなみに,
LcdConsole.WriteLine("Tacho: " + motorTail.GetTachoCount());
の結果は, 何と表示されますか.
(現在はコメントアウトされていますが,) SetMotorAngle() の中で
/*motorWaitHandle = */motorTail.SpeedProfile (speed, 0, (uint)moveTachoCount, 0, true);
//motorWaitHandle.WaitOne();
のようにWaitHandleを使うと, SetMotorAngle() を呼び出したスレッドが待ち状態になります. 現在のように倒立振子制御をしているスレッドから呼び出すと, 倒立振子制御に影響が出るので, 別スレッドを作成してそのスレッドでWaitOne()した方がよいです.
かといってWaitHandleを使わない場合は, SpeedProfile()によるモーター制御中にさらにSpeedProfile()が呼ばれるのを回避するような仕組みを, 作らなければならないかもしれません. (SpeedProfile()が, そのような呼ばれ方をしても大丈夫なAPIであればいいですが...)
Angle と startTachoCount との演算を行っていますが, おそらく Angle と TachoCount は全くの別物です.
これですが、別物ではないと思います。 Balanser.control()の第5引数、第6引数は
ですが、こちらに代入する際にgetTachoCount()の値が使われています。 Main.cs 184行目
int thetaL = body.motorL.GetTachoCount();
int theTaR = body.motorR.GetTachoCount();
sbyte pwmL, pwmR;
Balancer.control (
(float)forward, (float)turn, (float)gyroNow, (float)GYRO_OFFSET, (float)thetaL, (float)theTaR, (float)battery,
out pwmL, out pwmR
);
またMotorTailクラスでも88行目の従来のソースコードでは、
float pwm = (float)(Angle - this.motorTail.GetTachoCount ()) * P_GAIN; // 比例制御
という計算をしているので、Angle - TachoCount自体は問題ないはずです。 ただし、それがSpeedProfile()の第3引数UInt32 constantSpeedStepsに代入できるかというと疑問です。88行目の計算式は、pwm値を求める計算ですので。
急激に電流が流れ, デバイスをぶっ壊す可能性があります.
根拠としては弱いですが、今までの尻尾制御が急な制御をしていたので、問題ないと思い込んでこの引数を与えていました。見直します。
@mizutayo さんも書いてくれていますが、角度と回転数が別物でないことは確認済みです。
LcdConsole.WriteLine("Tacho: " + motorTail.GetTachoCount());
を使って、尻尾の角度と回転数が同じ値になっていることを確認しました。
ただ、ステップ数については未確認です。
(こちらの行、コミットするつもりではなかったんですが、誤ってコミットしてしまっていました。ローカルでは、ちゃんとusing ・・・を書いています。)
現在のように倒立振子制御をしているスレッドから呼び出すと, 倒立振子制御に影響が出るので, 別スレッドを作成してそのスレッドでWaitOne()した方がよいです.
,
目標とした動作:一度呼び出すことで、尻尾の角度を目標の角度にセットする。 ということですが, Main.csでは ループ(4ms周期?)の中で尻尾制御関数を毎回呼び出し という用い方をしているようですが...
尻尾制御のメソッド、及び内部でのSpeedProfile()の呼出し方を見直します。
Balanser.control()の第5引数、第6引数 MotorTailクラスでも88行目の従来のソースコード LcdConsole.WriteLine("Tacho: " + motorTail.GetTachoCount()); を使って、尻尾の角度と回転数が同じ値になっていることを確認しました。
分かりました. それだけの根拠があれば, TachoCount ≡ 回転角度 と言ってよいと思います.
SpeedProfile()関数をどうしても使いたい場合は、MainをSpeedProfile()だけを呼ぶようにして、パラメータを変えて動作させるという試行を繰り返せば、どの引数にどんな値を設定すればいいか分かるかもしれません。 ※モデル事歴研究の時に、動作確認の際は動画を取って、設定したパラメータとその時の動作を振り返れるようにすればいいかもという話をされていたチームがありました。動画を撮れる環境があれば参考にしてもいいかもです。
「こんな時は、こうするよ」という対応表を
のいずれかで記載し、まとめた方が良さそうですね
取り急ぎ、呼び出し位置を変えたらコンソールの入力を受け付けて走るようになりましたので報告します。
本対応が開発ブランチに入ったのでクローズ.
やること
尻尾制御のクラスを作成する。
背景