G-Tune 2004F SIPHA CORE | ||||||
SIPHA-COREの回路図 |
ご参考までにって感じですが、これがSIPHA-COREの回路図です。これが、第5回ROBO-ONE出場時に、最後までちゃんと実装されていた回路です。
これ以外には、電源回路が2系統あります。マイコン用とセンサ用です。最初はいろいろ予定…夢があったのです。途中で散っていきましたが。マイコン用の方は、でっかいキャパシティが噛ましてあって、瞬停バックアップができるようになっていた(過去形)もので、センサ用は、容量多めな0.5Aをつけています。シャープの距離センサをつけたかったんです。でもコネクタをつけただけで、それ以上は…。
そういえば、加速度センサもついていますが、値の取り込みまでしかしておらず、制御には使えていません。これからプログラム考えるところです(笑)。あとは…なんか電源電圧監視用の回路を入れていたような…。
でも、書いてみて思いました。「さすが、全部ダイレクトにつながっているだけあって、シンプル!」…ということは、書く必要も無かったような…。
SIPHA-COREソフトウェアテクニック解説 |
SIPHA-COREの制御周期
SIPHA-COREは、基本的に、20msecに一周する制御周期を持っています。この周期は、動作データの時間概念の基準となっているものです。1周期は、2つのフェイズによって構成されています。1つは、「サーボ制御信号出力フェイズ」、2つめは「計算、ROMアクセスフェイズ」です。サーボ制御出力フェイズでは、SIPHA-COREは5回にわけて18本分のサーボ制御信号を出力します。出力は、タイマWを使用している関係上、4つの制御信号を1つのタイミングで出力し、4、4、4、4、2という順番で出力します。このあたりは、ま〜、普通なんですが、後の説明に必要なんで、覚えておいてくださいね。図に描くと、こんな感じです。
サーボ制御信号の出力
H8/3664は、いくつかのタイマがあるのですが、サーボ制御にはタイマWを使用しています。これを使って、2.5、2.5、2.5、2.5、2.5、7.5msecという感じでタイマー割り込みをかけ、2.5msecの割り込みのところでサーボ制御信号を出し、7.5msecのところで、シリアルEEPROMへのアクセス、サーボ軌道計算等を行っています。タイマVは、後で解説しますが、R/C受信機のパルス幅と加速度センサのパルス幅カウントに使用しています。
タイマWには、ジェネラルレジスタと呼ばれる4つのレジスタがあり、タイマ値とのコンペアによって割り込みをかける機能があります。タイマWのオーバーフローによってサーボ制御信号をONし、コンペアマッチ割り込みによってOFFしています。そういった意味では、コンペアマッチ割り込みがぶつかった時に、若干サーボがプルプルしますが、実際のところ、うちのサーボでは、問題になるほどプルプルしません。というのは、OFFする処理をすごく簡単な処理にしているからです。具体的には、あっさりと…
IO.PDR1.BYTE &= 0x03;
TW.TSRW.BIT.IMFA = 0; // 割り込みフラグクリア
といったコードになっています。ピンアサインメント考える時に、こういうシンプルなコードでクリアできるように考慮しました。
シリアル通信
シリアル通信は割り込みを使用せず、スキャンする形で実装しています。これもすべてはサーボ制御信号を正確にするためです。また、ユーザインターフェイス用のソースコードは実装していません。基本的には、メモリ書き込み、読み出し、シリアルEEPROM書き込み、読み出し用の通信手順が用意されているだけです。パソコンから操作する場合、SIPHA-TERMによって、メモリを書き込むことで操作を行っています。この方式を採用している理由は、ROMエリアの節約のためです。メニューなどをシリアル通信によって実装する場合、その表示データはすべてROMに書き込まれるわけですが、これがなかなかメモリ食いです。そんなわけで、さっぱりとやめてしまい、モニタのようなプログラムだけを実装することにしました。ユーザインターフェイス的な要素は、SIPHA-TERM側(パソコン)の方に持たせています(それでもオプティマイズして19Kバイトぐらいあります。三角関数とかを載せているためです)。
通常のメモリ読み書きは、サーボなどを制御していても実行できるようになっています。実際の処理は「計算、ROMアクセスフェイズ」のみで行っています。シリアル通信は、サーボプルプルを防ぐために、割り込みは使用せず、「計算、ROMアクセスフェイズ」の中で、レジスタをチェックすることで行っています。
パソコンとの間は、完全に1バイトずつのハンドシェイク(受信したよ、送ったよと、1バイトずつやる)にて行っています。そのため、データの取りこぼし無く、「計算、ROMアクセスフェイズ」の時間のみを使って通信できるのですが、実は、かなりスループットが良くないです。それでも、制御中でもサーボ指示値などを取り出せるメリットは大きいです。また、実質転送レートは「その他フェイズ」の処理あまり時間に左右されます。最悪ケースで、1制御周期で1バイト、つまり50バイト/秒になることもありますが、データを厳選していれば実用範囲です。転送可能量は、その時々の「計算、ROMアクセスフェイズ」で使用した時間によって変わります。
また、シリアルEEPROMを書き込むときだけは、サーボ制御信号などの処理を全て停止させています。実用上、ぐいぐいロボットを動かしている時に、データ書きとかできなくても困らないので、問題は無いです。
R/C受信機の取り込み
R/C受信機は、もともと、サーボ制御信号を出力するものですので、当然、16msec〜20msecぐらいの周期で、サーボ制御パルスと同じような信号がでてきます。タイマVにて、0.128msecでオーバーフローするようにして、信号がHighになっている時に、何回オーバーフローしたかを計測しています。というわけで、プロポのスティックを動かした時、9〜14カウントぐらいの変化を得ることができます。この数値から、しきい値によって、それぞれのプロポスティックの位置を上中下に分けています。
さて、これをどうやってリアルタイムに取り込んでいるかといいますと、この図を見てください。
R/C受信機の信号は、こんなふうに、少しずれて出力されていますが、ここの話では全然関係ないです(笑)。ウソを書くわけにもいかないので、リアルに書かせていただきました。先に書きましたように、「タイマVオーバーフロー時に、信号がHighになっていたらカウントアップ」という処理をひたすらするソースコードがあります。普通に考えると、HIGHの時、ず〜っとカウントアップ、LOWの時はカウントアップしない…よってまたHIGHになるとカウントアップ…じゃあ、全然、パルス幅がわからない!となってしまいます。
しかし、上の図をよく見てみると…サーボと同じで、パルスが出力されるとその後、大体、14msecぐらいのお休みがあります。これに目をつけました。SIPHA-COREの制御周期タイミングは、2.5msec、2.5msec、2.5msec、2.5msec、2.5msec、7.5msecです。この間隔でカウントアップされている値をチェックすると、「前回チェックした時と同じ時」=「LOWになっている時」ということになります。つまり、シンプルで短い処理である「HIGHならひたすらカウントアップ」という処理をさせておくだけで、制御周期タイミング時にチェックすると、R/C受信機信号の幅を取得できるわけです。具体的には、制御周期タイミングの方で
前回と同じ値かチェック
同じ値なら、それをR/C受信機値として、カウンタをクリア
という処理をします。制御周期タイミングでの処理は、実は比較的、時間が延びたりしても問題がありません。なぜならば、この間はサーボ制御信号を出力していないですし、また実際にはタイマWを止めてしまっています。よって、割と複雑な処理を書いても、プルプルには全く影響はなく、また、全体のパフォーマンスにもそれほど影響が無いです。そんなわけで、制御周期タイミングの割り込み(タイマWのオーバーフロー)では、割と時間がかかるこういった判断の部分を書き、その他の割り込みでは、極力シンプルにしています。この速度(0.128msec)で割り込みをかけると、処理能力がだいたい70〜80%程度になります。そんなわけで、割り込み側の処理を、極力軽くするのは大切なことだと思います。
ところで、これだけだと、実は、サーボ制御信号のOFFタイミングとタイマVの割り込みが一緒に入った時に、サーボがとてもプルプルしてしまいます。ここが最も悩んだところです。いくらタイマV割り込み処理をがんばったとこで効果なく、レジスタ退避をすっとばすなどのウルトラC技を使わないとこれを回避することはできませんが、結構、簡単な方法でこれをクリアしました。それは「タイマVの割り込みを使わない」ということです。「計算、ROMアクセスフェイズ」では、タイマVの割り込みを使ってカウントアップし、「サーボ制御信号出力フェイズ」では割り込みを使わず、メインの方にぐるぐる回りでタイマWのOVFをチェックするようにし、これでカウントアップします。サーボ制御信号OFF処理にとって、自分以外の割り込みは深刻ですが、逆に、0.128msec間隔程度の処理からみれば、サーボ制御信号OFF処理なんて誤差の範囲です。こうしてめでたくリアルタイムにR/C受信機信号を取り込めるようになったのでした。加速度センサも同じアルゴリズムで取り込みを行っています。
シリアルEEPROMアクセスのチューニングポイント
GDLについているライブラリをチューニングさせていただいて使用しています。以前、報告しましたように、そのまま使うと、10バイトぐらいのデータをアクセスしまくるような感じで使用する場合、結構時間がかかります(とは言ってもmsecオーダーですが)ので、どのようにチューニングしたかといいますと…
チューニング対象は、読み込みの
EEPROM_BlockRead()
EEPROM_BlockRead()内の初期化処理を、別関数化
EEPROM_BlockRead()する前に、初期化関数を実行
違うアドレスが欲しい時は、そのままEEPROM_BlockRead()をする。
こんな感じです。SIPHA-COREでは、制御周期の空き時間を使ってEEPROMにアクセスしているため、まとめて取れる時間が少なく、一度に読み出すデータ数を少なくしてマメに読み出す、というスタイルを取っています。そのため、一気に読み込む場合のスループットは、オリジナルのものでも変わりません。しかし、マメに読み出す、アクセスアドレスを変える、といった使い方をする場合、非常に効果があります。具体的な部分は探してみてください。
ヒントは…
アイドルチェック
ポート初期化
IICバスBUSYチェック
ACKBの処理と停止処理
を初期化関数にまとめ、EEPROM_BlockRead()からはずすことです(そのまんまですね…)。イメージ的には、ファイルオープン/クローズな感じです。
使ってみて思ったのは、今のアクセス方法ですと、どうしてもまとまった時間を作らないといけないので、処理全体からみると、ちょっと足かせ気味です。う〜む、これからどうしましょう。
今後の展開
もう、これで手の内は全部明かした〜!って感じですが、いかがでしたでしょうか?コントローラ自作派の方へ、少しでも参考になればと思います。また、説明内容ですが、H8/3664に限定したものではなく、どのマイコンでも実装可能なものだと思います。
そして、今回のネタはばらしてしまいましたので…SIPHA-COREも、次へのステップへの進んでいくのです(SISO = 切羽詰らないとやらないヒト)。
SIPHA SYSTEMのAction Script |
どどんとAction
Script公開(恥ずかし〜)
会場で、一部の方にお見せしたAction
Scriptなるものの仕様を、ドドンと出してしまいます。どのように呼び出されるか等の基本概念抜きで、こういうのをドンと出してしまうのもなんなんですが、同じように自作派で「なんかスクリプトみたいのできないかな〜」という方の参考になればと思います。これが悪い例ですぅ!な〜んて。
そもそもAction Scriptってなんぞや?という話なんですが、簡単に言えば、世に言う「モーションデータ」っていやつで、ロボットの動作を決めるデータを書くための言語です。SISO JUNK STUDIOオリジナル用語?です。SIPHA-COREでは、どのように動作データを扱っているか?というのがわかっていただけるのでは?と思っています。ちなみに、単位が「度」とか「ミリ」と出てきますが、目標位置に小数点以下は指定できませんけど補完動作中はもっと細かくやっています。
どんなふうにこれを動作デバッグしているかというと、基本的には、RAMデバッグしてEEPROMに記録という形でやっています。
こんな感じです。これらのデータは、1レコードあたり4バイトのデータブロックで表現するようにしています。
SIPHA-COREは、実行状態に入ると、サーボ制御の隙間を狙ってシリアルEEPROMからこのデータをRAMに展開し、それを実行しています。本当は、ぐいぐいとシリアルEEPROMから読み出して実行したいんですが、ちょっと苦しいです。動作デバッグ時は、この部分に直接パソコン側からロードすることでRAMによる動作デバッグを実現しています。そんなわけで、補完計算とか、二次元座標→サーボ制御値変換などは、すべてSIPHA-CORE側にて行っています。
気になる容量ですが、RAMの関係上、今は1アクションスクリプト200レコードまで、という形になっています。これが多いか少ないか、という話なんですが、事前審査動作データがアクションスクリプト1発で199レコードでした。また、アクションスクリプト間でジャンプもできますし、なにより趣味ですし(笑)、こんなもんかな〜って思ってます。
アクションスクリプトは、最大200種類、1Action Scriptあたり200命令の設定を行うことができる。これに記述した内容により、サーボ制御、リモート操作(ラジコンプロポ)による条件分岐、センサーチェックなどを行う。
0 |
アクティブモードで起動時に自動的に実行されるアクションスクリプトデータである。これにより、最初のサーボ位置、起動後の状態を決定する。 |
1〜16 |
プロポ指示動作時の、モード切り替え動作(プロポ右スティック)用のアクションスクリプトデータである。 モードはプロポ右スティック位置に対応した、0〜8の9状態によって表されるが、基本姿勢が同じであるいくつかのモードを1モードグループとして扱う。例えば、モード0〜2は直立姿勢、モード3〜5は攻撃姿勢、モード6〜8はしゃがみ姿勢の場合、それぞれをモードグループ0、1、2とし、このモードグループ間を移行するためのアクションスクリプトがこのスクリプトで記述される。 モードグループは0〜3まで設定可能で、対応するAction Scriptは、旧モードグループ*新モードグループで表される。 |
17〜97 |
プロポ指示動作時の、コマンド動作(各モードにおけるプロポ左スティック)用のAction Script
Dataである。各モード毎に9動作ずつ割り振られる。 |
98〜99 | オートプレイ用スクリプト開始アクションスクリプトで、98がAuto Play 0、99がAuto Play 1に対応。 |
100〜199 | ユーザが自由に仕様することができる。主に、オートプレイ用、アクションスクリプト間Jumpを使用した、複数のアクションスクリプトによる動作の実現などに使用する。 |
CEXT: Exit | ||
---|---|---|
アクションスクリプトを終了する。 アクションスクリプトを、任意のラインで終了させる。CRIJ等と組み合わせて使用すると、リモート操作によって終了させるなどのスクリプトを記述することができる。 | ||
Command |
EXLV | |
Parameter |
Nothing |
|
| ||
CSQT: Sequence Timer | ||
次のアクションスクリプトを指定されたステップ後に実行する。 ステップとはサーボ制御周期のことである。サーボ位置制御等、時間指定できるコマンドがこのコマンド以前に実行されている場合、その動作は実行を続ける。 | ||
Command |
CSQT, Step | |
Parameter |
Step |
ステップ数 |
| ||
CPOS: Position Control | ||
サーボ位置を制御する。 前回動作位置からの補完を行って、指定ステップ数で動作を完了する。補完計算は、直線的な単純補完以外に、ゆっくりと動作開始、勢いよく動作開始する動作モードを指定することができる。また、サーボ制御信号OFFをすることもできるが、この場合、BeginMovMode、EndMovMode両方とも「OFF」とすること。 | ||
Command |
CPOS, SrvNo, BeginMovMode, EndMovMode, Step, Degree | |
Parameter |
SrvNo | サーボ番号(またはサーボID) |
BeginMovMode |
サーボ動作開始モード | |
EndMovMode | サーボ動作終了モード MSFT: ソフト動作(ゆっくり動作終了) MLNR: リニア動作 MHRD: ハード動作(勢いよく動作終了) OFF: サーボ制御信号OFF | |
Step |
ステップ数 | |
|
Degree |
目標角度 |
| ||
CDP2: Dimension Position Control for Two | ||
脚のピッチ軸サーボを二次元空間座標で制御する。 X−Z(横から見た座標)を指定することで、脚のピッチ軸サーボを制御する。 | ||
Command |
CDP2, LegID, BeginMovMode, EndMovMode, Step, X, Z | |
Parameter |
LegID |
脚 |
BeginMovMode |
サーボ動作開始モード | |
EndMovMode | サーボ動作終了モード MSFT: ソフト動作(ゆっくり動作終了) MLNR: リニア動作 MHRD: ハード動作(勢いよく動作終了) OFF: サーボ制御信号OFF | |
Step |
ステップ数 | |
X | 高さ座標(ミリメータで指定) | |
|
Z |
奥行き座標(ミリメータで指定) |
| ||
CPLS: Pulse Conrol of Servo | ||
サーボ制御信号をON/OFFする。 サーボ制御信号を一斉にON/OFF指定する。 | ||
Command |
CPLS, PlsFlag, PlsFlag, PlsFlag, ... | |
Parameter |
PlsFlag |
制御信号のON/OFF |
| ||
CRIJ: Remote Interface Jump | ||
リモートI/Fの状態により指定レコードへジャンプする。 | ||
Command |
CRIJ, Stick00Pos, Stick01Pos, Stick02Pos, Stick03Pos, EQJumpRecord, NEJumpRecord | |
Parameter |
Stick00Pos | プロポスティック位置 PLOW: スティック下 PCNT: スティック中央 PHGH: スティック上 PIGN: 無視(評価の対象からはずす) |
Stick01Pos |
プロポスティック位置 | |
Stick02Pos | プロポスティック位置 * 内容についてはStick00Posと同様 | |
Stick03Pos | プロポスティック位置 * 内容についてはStick00Posと同様 | |
EQJumpRecord |
一致時Jump先Action Scirpt Record 0〜199 | |
|
NEJumpRecord | 不一致時Jump先Action Scirpt Ste
0〜199 255の場合は次レコードへ移動する。 * ジャンプ先として自分を指定した場合、1レコード後に再度コマンド評価を行う。 |
| ||
CSEL: Set Execution Level | ||
実行レベルを設定する。 アクションスクリプト実行中に実行レベルを設定(変更)する命令で、任意のタイミングで実行レベルを変更したい場合に使用する。 例えば、動作中に、ある時間帯だけは新しいアクションスクリプトへの移行操作があっても、別のアクションスクリプトへ移行したくない場合に、一時的に実行レベルをあげるといった使い方をする。 | ||
Command |
CSEL, ExecLevel | |
Parameter |
ExecLevel |
実行レベル(0〜3)※モード移行はレベル2である。 |
| ||
CPBJ: Push Button Jump | ||
プッシュボタンの状態によりにより指定レコードへジャンプする。 プッシュボタンの押下状態によってジャンプする命令である。押されていない場合と押されている場合のジャンプ先を指定することができる。 | ||
Command |
CSEL, ButtonNo, PSJumpRecord, NAJumpRecord | |
Parameter |
ButtonNo |
ボタン番号(0、1) |
PSJumpRecord | 押されている時のJump先Action Scirpt Record ※値についてはCRIJを参照のこと。 | |
|
NAJumpRecord |
押されていない時のJump先Action Scirpt Record |
| ||
CLED: LED Control | ||
LEDの点灯状態を制御する。 | ||
Command |
CLED, LEDNo, Flag | |
Parameter |
LEDNo |
LED番号(0、1) |
Flag |
点灯状態 | |
| ||
CJMP: Jump | ||
無条件にAction Script内の任意のレコードにジャンプする。 | ||
Command |
CJMP, ActionScriptRecord | |
Parameter |
ActionScriptRecord |
Action Scriptレコード番号 |
| ||
CASJ: Action Script Jump | ||
無条件に別のAction Scriptにジャンプする。 | ||
Command |
CASJ, ActionScriptID | |
Parameter |
ActionScriptID |
Action Script ID |
| ||
Back to G-Tune 2004F Index