ATmega128のタイマ捕獲機能を使ってジャイロ値読み取り

公開日:  最終更新日:2014/06/05

すいません m(_ _)m、本記事はブログ引越時に書式が崩れました。順次修正中です。

さてっと、というわけで、ATmega128、早速、基礎実験です。


ATmega128には、タイマ0~3まで、4種類のタイマが搭載されていますが、このうち、サーボPWM出力やジャイロ取り込みに使えそうなタイマは、タイマ1とタイマ3です。この2つのタイマは16ビットで動作しますので、サーボPWMの分解度から考えると、一番素直な選択だと思います。というわけで、まずは一発もの、ということで、このタイマを使ってジャイロのインプットキャプチャをやってみようと思います(経験上、ジャイロ取り込みには苦労した事が無いのですが、サーボPWMはよく泣かされていますので…)。


一般的なラジコン用ジャイロは、サーボ信号の補正が目的であるため、サーボ制御信号を入れると、ジャイロの状態によって補正した信号が出力されます。ロボットに使用する場合も、ただ補正に使用するためだけに入れるのであれば、同じようにコントローラとサーボの間に接続すればいいのですが、実際には、状況によってジャイロの効きを変えたり、オフしたりしたくなります。そんなわけで、一旦、コントローラで取りこんで、コントローラ内でサーボ制御に反映するほうがスマートです。


最近は、ロボット専用という感じで、入力信号が無くてもパルスを出すものや、アナログ出力するものがありますが、ここでは手持ちのKRG-1をATmega128に接続してみます。



KRG-1
KRG-1は、近藤化学のロボット用ジャイロです。モードは2つあり、入力信号を補正するモードと、1500usを中心にして各速度に応じたパルスを出力するモードがあります。デフォルトでは、出力するだけのモード(ロボットモードだったかな)になっています。今回は、入力信号を与えなくても動作するということから、デフォルトで使用します。


他にも、パルスを出す周期を変える事ができるみたいですが、変更には、「ICS PCインターフェイス Red Version」というケーブルが必要になります(これが6,000円と、結構なお値段で…自作できないのかなー、ほしいなー、ほしいなー、誰か不要になった人いないかなー)。


パルス幅の計測
ATmega128のタイマ1/3には、捕獲機能があります。いわゆるインプットキャプチャという機能です。外部から信号変化を与えると、タイマカウンタの値をレジスタにコピーします。


信号変化は、LOW→HIGHとHIGH→LOWを切りかえることができます。そのため、この機能でジャイロのパルス幅を計測しようと思うと、LOW→HIGHの値を取得したら、今度は切り変えてHIGH→LOWの変化を取得できるように設定する必要があります。この切り替えタイミングは、計測完了(タイマカウンタの値をレジスタにコピー)した時に割り込みを発生することができますので、これを使います。


また、シンプルにはタイマカウンタを毎回クリアする方がわかりやすいのですが、次のステップで同じタイマを使ってサーボPWM信号も出すことも考慮し、タイマカウンタは走らせっぱなしにして使用します。


そうすると、パルス幅を計算するときにちょっと工夫が必要になります。LOW→HIGHの時に取得した値が、HIGH→LOWで取得した時の値より小さければ、そのまま「2つめの値 – 1つめの値」がそのままパルス幅になるのですが、最初に取った値より後に取った値の方が小さくなることがあります。


これは、タイマカウンタが16ビットなため、65535の次は0になります。例えば、最初に取った値が「65000」、そして後に取った値が「1000」になる、ということがあります。でも、これはちょっと計算を工夫してやれば解決できます。具体的にはこんな式になります。


( 65535 – 最初の値 ) + 後の値


これをif文で切り変えてやれば大丈夫です。


プログラム
動作確認はベストテクノロジのGDL1.7.0.4を使用しました。ATmega128でのプログラミングはまだ始めたばかりなので、いろいろ危ないところがあるかもしれません。今のところ、ベストテクノロジのサンプルプログラム、HERO’S Downloadで日本語化されたATmega128のマニュアル、Front Page – AVR WikiAVR Libc日本語翻訳、HIDEさんのHIDEロボ、あとはMAGOさん(RE001使いの友人です)のMAGO Labsを参考にさせていただいてやっています。ATmega128を使っている方は多そうなんですが、意外と情報が少ない感じです。


さて、プログラムのほうですが、まずはハードウェアの初期化です。今回、タイマ1を使用しますので、タイマ1を初期化します。BTC068は16MHzで動作していますので、8分周で使用します。これで、16ビットカウンタですと、最大、32ms程度まで計測できることになりますので、「20ms毎に入ってくるパルスを計測する」には十分だと思います。



TCCR1A = 0x00;                // タイマ標準動作モード
TCCR1B = _BV( CS11 );   // クロック選択(8分周)カウント0.5us


捕獲入力を使うためには、まずは該当するI/Oポートを入力方向に設定します。実際には入力がデフォルトなので、初期化は不要と言えば不要です。



DDRD = 0x00;                    // PD入力


後は、タイマ1の捕獲入力の設定ですが、まずは立ち上がりエッジで最初の部分を検出する必要がありますので、立ち上がり検出設定をします。また、割り込みによって値の取得などを行いますので、捕獲入力による割り込みを許可します。



TCCR1B |= _BV( ICES1 );   // タイマ1捕獲立ち上がりエッジ
TIMSK |= _BV( TICIE1 );    // タイマ1捕獲割り込み許可


あとは適当にグルグル回りながら、ジャイロ値を表示でもしていればいいんですが…っと。肝心の割り込み処理の方を忘れました。割り込みを使用するには、「SIGNAL()」という関数を使用します。この関数に「SIG_INPUT_CAPTURE1」という値を設定すると、入力捕獲の割り込みルーチンになるようです。「SIG_INPUT_CAPTURE1」なんてどこから出てきたの?と疑問が出てくるかもしれません。コンパイラに同梱されているヘッダファイルから見つけました。iom128.hというヘッダファイルを、「SIG_」で検索するといろいろでてきます。定義名とマニュアルに書いてある用語を照らし合わせて、きっとこれだろうーって感じで使ってます。


というわけで、割り込み関数の宣言はこんな感じです。



SIGNAL( SIG_INPUT_CAPTURE1 )


※2006/09/15 0:26追記:その後の調査で、SIGNAL()はWinAVR 20050214以前のもので、WinAVR 20060125以降は、ISR()を使用することが推奨されていることがわかりました。GDL1.7.0.4で確認したところ、使用できました。


そして、立ち上がりエッジと立ち下がりエッジの切り替えは、値を読み出したときに信号の状態をチェックして、「読んだ時HIGHならば立ち下がりエッジにして、次の立ち下がり時にカウント」という感じにしました。また、立ち下がりエッジ検出時は、ジャイロ値の計算をして、値を設定するようにしています。



if(( PIND & _BV( PIND4 )) != 0 ){
    TCCR1B &= ~(_BV( ICES1 ));   // 捕獲入力エッジを立ち下がりに変更
    GDusIcr1Up = ICR1;                    // ICR1値を読み出す。
}
else{
    TCCR1B |= _BV( ICES1 );    // 捕獲入力エッジを立ち上がりに変更
    GDusIcr1Dn = ICR1;     // ICR1値を読み出す。
    // ジャイロ信号幅の計算と設定
    if( GDusIcr1Up < GDusIcr1Dn ) GDusGyro = GDusIcr1Dn – GDusIcr1Up;
    else       GDusGyro = ( 0xFFFF – GDusIcr1Up ) + GDusIcr1Dn;
}


これでジャイロのパルス幅を読み取ることができます。というわけで、全プログラムを見たい方は、以下のリンクよりソースコードをダウンロードして下さい。


PulseWidthCheckTest.zip


プログラムをみると「uint8_t」といったデータ型が使われているのがわかりますが、この環境ではこれを使うことがお作法のようです(こういうのが、標準的なライブラリとかを開発するときの障害になったりするんだよねー)。


というわけで、「ICS PCインターフェイス Red Version」があまっている、不要になったという方、いらっしゃいましたら連絡ください(結構、真剣)。

  • このエントリーをはてなブックマークに追加
  • Pocket

関連前後記事

Comment

  1. いずみかわ より:

    こんにちは。いずみかわです。
    昔私もKRG2買ったときに一緒に「ICS PC I/F Red Version」買ったのですが、正直なところ、SISOさんなら自作可能な代物です。
    設定用ソフトはKOのサイトでダウンロードだし。
    え~これが6000円!?って感じの。
    公開したらまずいんだとは思いますが...

  2. SiSO より:

    情報ありがとうございます。たぶん、公開したらまずいものだと思いますので中古品探しますね。
    見た目の雰囲気から想像はついているんですけど、怖くて試せない状態です。すごーくシンプルな部品を使ってRS232Cの信号をこうしたらいいんだろうなーとは思っているんですが、対象が高価な部品だけにやっぱり純正品がいいかなーと。
    誰か不用品、無いかなー。

  3. ほり より:

    メカ仙のほりです。
    お子様のお誕生おめでとうございます。
    今日までネットの無いような所へ出張していたので
    出遅れました。
    ICS-PCインターフェイス2の件で、KRT-1もサーボ設定用インターフェイスも購入したので、もしかしたら同じ物が2個転がっているかもしれません。
    ちょっと休みの間に探して見ます。
    もし、2個あればお祝いに一つお譲りします。

  4. SiSO より:

    ほりさん、こんばんは!ありがとうございます。父ちゃんとしてがんばりますー。
    ICS-PCインターフェイス、もし余っていたら、ぜひともよろしくお願い致します。KRG-1の設定を変更してみたくて。
    それでは!

  5. TONII より:

    RC受信機からのPWM信読み込み データ値とする プログラム ジャイロ読み取りプログラムで組めるんでしょうか ATmega88を使用し体のですが
    AVR Studio4で ビルドするとATmega88では
    TICIE1 |= _BV( TICIE1 ); // タイマ1捕獲割り込み許可に エラーが出ます。
    ../5006.c:67: error: `TICIE1′ undeclared (first use in this function)
    これどうすればよいのでしょう
    ジャイロも RCサーボPWM信号と同じだと
    思い データ値に変換できれば それを
    演算 新たなる 混ぜ合わせた RCサーボ用
    PWM信号を 出せると思ったのですが
    無理でしょうか。 なにせ プログラム製作は
    初心者ですから 難しく困って降ります。
    お力を お貸しください。

  6. SiSO より:

    TONIIさん、初めまして。書き込みありがとうございます。
    TICIE1は、ATmega128のタイマ1キャプチャ割り込み許可になります。ATmega88は触ったとこがないのですが、マニュアルを読むと、TIMSK1というレジスタに対して、ICIE1というビットで設定するようです。
    ネットで検索してみたところ、
    http://reef.path.ne.jp/~hero/pdf/
    に日本語訳したマニュアルがありました。参考にしてみてください。

  7. TONII より:

    有難うございます。
    とにかく プログラム初心者の私ですから
    マニアル自体 難しくこまっております。
    AVR Studio4で ATmega128設定 ビルドすると
    ../5007.c:10:16: rs.h: No such file or directory最初にエラーが出ます 
    シリアル通信の部分が エラーが出てきますが
    ../5007.c:73: error: `br57600′ undeclared (first use in this function)
    ../5007.c:73: error: (Each undeclared identifier is reported only once
    ../5007.c:73: error: for each function it appears in.)
     
    どこを どのように変えれば 良いのでしょう
    初心者です。

  8. SiSO より:

    TONIIさん>
    マニュアルは、何かと特別な用語が出てきますので、あれこれ実際にプログラムしながら試し、100回読むつもりでがんばるしかないかと思います。
    rs.hですが、これはBest Technology社が配布しているGDLという開発環境に同梱されているものでWinAVRなどでは使用できませんので、inlucde自体を削除し、RS232C通信関係を削除する必要があります。また、ATmega88でRS232C通信を使用する場合、独自のライブラリを入れる必要があるかと思います。確か、1バイトだけの送受信関数を準備すればそれをライブラリに登録するすることで、文字列出力や入力を行う方法があったかと思いますので、調べてみてもらえませんか?
    がんばってくださいね!

  9. GTR より:

    ジャイロ信号は RCサーボ信号と同じですね?
    RCジャイロ信号を 5チャンネル分 検出を
    したいのですが ポートを高速でスキャンすれば
    と思うのですが そのプログラムがさっぱり
    わからず困っております。
    制作された このプログラムソースを どのように
    直せが RCサーボ 5ch分 検出できるのでしょう。 教えていただけませんか。

  10. SiSO より:

    GTRさん>
    書き込みありがとうございます。
    ジャイロ信号ですが、信号そのものは同じです。ただ、普通のラジコン用ジャイロは、基準PWMを入れないとジャイロ補正された信号が出力されません。ここで使っていたKRG-1は、基準PWMを入れなくても出力を得ることができます。
    また、このプログラムは、ATmega128のタイマー機能を使っていますので、単純には1ch、同じ仕組みで取り込もうとすると、2chまでしか取り込むことができません。ただ、グルグル回ってスキャンするようなプログラムよりも精度が良く、他の処理(シリアル通信とか)の影響を受けません。
    もし5ch分取り込むのであれば、アナログ出力のジャイロを使い、A/D変換で取り込む方が簡単だと思いますよ。KONDOのKRG-3がそうです。

  11. GTR より:

    有難うございます。
    RCサーボ信号(PWM)読み取りをしたいのですが
    6ch分の信号を検出するには 無理なんでしょうか
    やはり ぐるぐる ポートのピンをスキャンするしかないのでしょうか 検出したデータを 他のAVRチップに送り それをもとに 10ch分のRCサーボを
    コントロールするのですが (PWMの検出部分と
    そのデータをもとに 制御しPWM信号を出す部分を
    別にプログラムを組むことはできないのでしょうか
    このサンプルプログラムは シリアル通信として
    出力していますが 他のチップにデータとして
    出力するには このプログラムを どのように
    変更すればよいのでしょう….
     

  12. SiSO より:

    GTRさん
    ロジックIC(OR)回路でまとめるか、RC受信機の6chに分解する前の部分から信号を取り出すかすれば、1ポートでいけると思います(RC受信機がシフト処理のロジックICで構成されている場合は、割と取り出せる可能性大です)。
    6ch、グルグル回しだと、少し精度が出ないかもしれません。そのあたりの精度と手軽さのバランスでしょうね。経験上、6chの信号は、必ずタイミングがずれて、6ch目→1ch目に信号が変わるときは、少し間が空きます。ここをどう、うまく使うかがポイントかと思います。
    ちなみに、マイコン同士の通信は、そのままシリアル通信でよいかと思います。相手方のマイコンにもUSARTがあれば、ですけど。ほかの方法を取るならば、I2C、SCIなど、いくつか方法は考えられます。

Your Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*

PAGE TOP ↑