« 2014年3月2日 - 2014年3月8日 | トップページ | 2014年4月6日 - 2014年4月12日 »

2014年3月30日 - 2014年4月5日の1件の記事

2014年3月31日 (月)

サーボモーターの制御とUSIを使ったソフトUARTの開発

 何でもないことにこだわって本来のプロジェクトが先に進まない。当研究所では良くあることだが、今度もメカトロニクスに再挑戦などと結構なお題目を唱えながら、この一週間、それとは全く別のAVRのソフト開発に没頭していた。

 はまっていたのは、AVRマイコンのTinyシリーズ独特の汎用シリアルインターフェース(Universal Serial Interface USI)を使ったソフトUARTの開発である。TinyシリーズにはUARTやSPI、I2Cなどのハードはついていないが、そのかわりこのインターフェースがついている石が多い。これで色々な通信インターフェースをソフトで作れということらしい。

 5年以上前、このUSIを使って、I2Cマスター/スレーブのライブラリを作って公開した(Atmelのアプリケーションノートを参考にした)。幸いこのライブラリはいくつかのサイトで紹介され、使ってもらっているようだ。

 ただ、USIはウェブなどでは、「使いにくい」「難解」と余り評判は良くない。今度、開発しようと言うのは、GPIO直か打ちのオーバーヘッドのないソフトUARTをUSIで作ろうというものである。なぜこんなことになったのか。そのわけは、これまでの経緯を含めてこれから説明していくことにする。

Tiny861のPWMピン出力問題が解決。お馬鹿な失敗(3/7/2014)
 市販のサーボモーター(MICRO2BBMG 秋月で¥1080)を、AVRマイコンで制御する実験は、可変抵抗器(10KΩ)からの電圧をADコンバーターで数値化し、これでサーボを動かすことには一応成功した。

 ただ、マイコン(Tiny861)のタイマーについているPWMの出力ピンがどうしても動かず、コンペアマッチ割り込みを使って別のピンを操作し何とかPWM波形を出した。動いたとはいえ、せっかくPWMが標準で持っているピンを使わないままにしておくのは気分が悪い。

 Tiny861は以前、グローバルなピンチェンジ割り込みを有効にしないと(GIMSKのPCIEx)、ピン入力そのものが有効にならない現象(バグ?)に悩まされた石で、それ以外にもTiny26からの継承を意識した変則的なピンチェンジ割り込み初期値設定でO-Familyさんがはまっている。

 こういう前歴があるので、今度も色々疑って調べ始めたが手がかりはない。仕方がないので無駄とは思ったが念のため設定レジスターTCCR1Aの中味をUARTに出してみた。ありゃあ、初期化で設定したはずのPWM出力をenableにするビットが0になっている。これでは出力されないわけだ。誰かが設定してからいじっている。

 試しに動かす直前にもう一度設定し直してみたら、何の問題もなくPWM出力ピンのOC1Aに正常なPWM信号が出た。タイマーの初期化のあとにUARTの初期化をしているので、ここでいじったか。いや大丈夫何もしていない。sleepか。まさか、そんなはずはない。少しづつ設定ステートメントを元のタイマー初期化のところに近づけていく。

 何と、TCCR1Cという別のタイマー設定レジスターが悪さをしていることがわかった。こいつがいけない?このレジスターの意味が良くわからなかったので、TCCR1C=0とクリアした。データシートをあわてて読み直す。何い、頭のビットはTCCR1AのPWM設定ビットの「投影ビット」とある。S_p3296456

 「投影」とは設定した値がここに出てくると言う意味だと思ったが、どうも違うようだ。英語の原文をあたる。「投影」ビットとはshadowビットの意味で、shadowと言ってもここをいじると元が換わると書いてあるではないか。邦文の方はこれが省略されている。

 やれやれ、何と言うことだ。データシートは穴があくまで読めというが、原文まで見ないといけないとは困ったものだ。良い加減な理解でえらい目にあってしまった。

自作サーボのモータードライバー、内径6mmのギアを入手(3/12/2013)
 市販サーボはとりあえず動いた。しかし、8ビットのPWMでは、サーボの可動範囲は16段階くらいしかとれず、動きがぎこちない。16ビットPWMにするのは8ビットのTIMER1から16ビットのTIMER0にコードを移す力仕事だけなので、余り気が進まない。それに、この市販サーボの本来の使用目的がもともと決まっていないので、実験していてもどうも張り合いがない。

 というので、市販サーボの実験はとりあえず棚上げし、サーボモーターの完全自作の方を進めることにした。仕事の帰り、秋葉によってサーボのメカパーツを物色する。ツクモと千石で、ポテンショメーターのギアを探した。

 この間買ったポテンショメーターの軸径は6mmで、こんな大きな内径のギアはないものと思って、ツクモで内径6mmのストッパーを買い、これを加工するつもりでいたら、千石には、ちゃんと内径6mmのハブのついた歯車が売っていた。

 ギアが有ったのは良いが結構な値段だ。ひとつ¥300以上する。2つ買ったので¥700。ポテンショメーターがひとつ¥150。モーターギアセットが¥700なので、これだけで¥1500以上もかかっている。適当な市販サーボが十分買えるコストだ。まあ、実験なのでここは目を瞑ろう。

 秋月では、昔、小さなモータードライバーとして評判の良かった、RohmのBD6231を発見しサーボ用に2つ買った。これはSSOP8ピンの小さなICだが、1Aまでのモーターの前後進と速度制御が出来る優れものだ。

 家に帰ってモーター制御用のチップを部品箱から取り出し揃えてみる。MP4401 IR2011 MP4212 それにフォトボルなど。今の小型モーターにこのあたりの石は役不足(もったいない)で、BD6231あたりで十分である。

 早速テストしてみた。手持ちのモーターの定格は1.5~3Vなので、ミニブレッドボードにタクトスイッチを組み込み、少しへたった電池3つで動かしてみる。あれえ、全く動かない。動作電圧が3Vからというのにおかしい。S_p3166447

 データシートを確かめて愕然となる。3Vからというのは制御電圧の下限で、電源電圧は4.5V以下では動かないリミッターがついているではないか。あらあら、今考えているモーターを動かすには、BD6231ではなく、秋月で売っているもうひとつの石BD6211が必要と言うことが判った。

秋葉原の居酒屋「赤津加」で飲む。BD6211を買い直し(3/14/2014)
 古い友人が訪ねてきたので、かれこれ10年ぶりに秋葉原のレトロな居酒屋「赤津加」を訪ね、一献傾けた。「赤津加」は、メイド喫茶の客引きが密集する部品街のメインストリートを一歩入った横丁にある。

 こんなところに、こんな飲み屋があるとは思えないほど隠れ家的な店で、このあたりが青物市場だった頃から綿々と続く昔ながらの飲み屋である。今も時間になると沢山の客で賑わっている。

 友人(モデムの専門家)は、この店は初めてだそうで喜んでくれた。ちょうど良い機会だったので、日頃の疑問をぶつけてみた。市販サーボの制御信号のPWMのしかけである。PWMの周期が10~20msで、制御中点が1.5msというのが良くわからない。

 このままでロジックを組めば、モーターに通電される時間は最大で3ms、15~30%のduty比ではモーターにかけられる電力は限られてしまうはずだ。何もPWMで面倒な変換をやるより、直接デジタルで数値か何か指示した方が良いような気がするのだが、どうしてだろう。

 彼の答えは明確だった。電力は積分で効いて来るのでこれくらいのduty比は、かける電圧なり電流を調整すれば何も問題ないそうだ。昔は、マイコンなどなかったから、数値入力などは全く考えられず、アナログ的なPWM方式が一番都合が良いというのである。これで何となく納得する。

 秋葉原で会ったついでに、例のモータードライバーBD6211を買いなおした。家に帰って、早速ピッチ変換基板にハンダ付けして、これまでのBD6311と取り替える。おー、動いた。快調だ。こいつは具合が良い。発熱も殆どない。これくらいの(FA130程度)小型モーターならこれで十分である。 5年も前のエレキジャックのサイトに詳しく出ていた。

市販サーボの制御を16ビットPWMにする。動作が安定しない(3/19/2014)

  サーボの自作といっても、何に使うか決めていないので部品が揃っても具体的な工作にはなかなか進めない。で、自然に手は、市販サーボモーターの実験にもどる。やり残していたTiny861の16ビットPWMのソフト開発を始めた。力仕事だからと馬鹿にしていたのだが、これが、結構難しく2日近くかかってしまった。

 16ビットタイマーの仕様がなかなか理解できない。データシートの説明が不親切と言えば不親切である。わかってしまえばどうと言うこともないのだが、もうちょっと要領の良い説明が出来ないのかと八つ当たりしている。

 そうは言っても手間取った原因は16ビットタイマーの自分の不慣れにつきる。いい加減なデータシートの読み込みで思わぬ道草を食わされてしまった。それに、8ビットで不安定だったサーボが安定するかと淡い期待を抱いていたのだが、なんのことはない16ビットカウントにすると、かえって変な振動が出てきて止まらない。

 ADコンバーターで値を取り直すたびに僅かながらモーターが動く。電源を独立させても解決しないので、これはADCでの値が細かく変動しているからに違いない。パルスの巾(μs単位)で3以内では、前の値を保持するというヒステリシスロジックを組み込んでみた。しかし殆ど効果がない。

 そういえば、サンプリングの度にUARTでADCの数値をコンソールに出力している。これが悪さをしているのだろうか。まさか、と思いながら、UARTを試しに止めてみた。何と何とこれでピタッと振動は収まったのである。

 何故?UARTが出力PWMに影響を与えているのか?そんな馬鹿な。しかし止まったことは事実である。こうなると今までの振動の原因はUART以外に考えられない。8ビットで起きなかったのは、分解能が低くパルス巾に影響しなかったのだろう。

USI-UART開発に脱線する(3/20/2014)

 暫くして気がついた。サーボがUARTでぶれる症状は、良く考えてみたら自明のことだった。こんなことはもっと早く気が付かねば。気が付かなかった自分に滅入る。

 Tiny861で使っているUARTは、ソフトUARTである。GPIOを直接on/offしてデータを送っている。8ビットの送信の時は、タイミングがずれるのを防ぐため、その間は割り込みを止めている。

 この送信時間中(38.4kbpsで300μs)に、モーターサーボのPWM送信パルスがぶつかれば、当然、決められた時間でパルスを上げることが出来ず、そのときのパルス幅は変わり、サーボは不規則な運動をしてしまうのだ。

 そうか、Tiny861はハードウエアのUARTを持っていないので、PWMなどでモーターを動かしている時にこのUARTは使えない。Tiny2313やMegaシリーズのようにハードのUARTを持っていないとこういうことが起きる。

 しかし、Tniy861で使えないというと、へそ曲がりの性分が久しぶりにむくむくと起き上がった。Tiny861には、USIという汎用シリアルインターフェースというのがある。以前、これでI2Cのライブラリを作った。

 USIそのものは、Tinyシリーズだけの装備で、話題になることもないインターフェースだが、このところソフトの開発は力仕事ばかりで面白いことをやっていない。これを使えば、数μs以下のオーバーヘッドだけでUARTが動き、同時処理にも使える。急にこれを作ってみたくなった。

 サーボモーターのプロジェクトから見れば、完全な脱線だが、こういう脱線は研究所の得意とするところである。久しぶりにTiny861のデータシートを広げて、USI-UARTの制作に取り掛かった。

こいつが手ごわい(3/24/2014)

 これが難儀しているのである。もう4日近くなるが、いまだにまともに動かない。USIはSPIやI2Cなどの通信インターフェースを意識しているらしく、これらには色々な機能が揃っているが、非同期のボーレートだけのタイミングで動くUARTには何のサポートもない。全部、ユーザーで作る必要がある。

 最初は、8ビットのデータ分だけをUSIのシフトレジスターUSIDRにいれ、前後のスタートビットとストップビットを通常のピン操作命令、PORTB |= 1<<PINB;などで出来ると軽く考えていた。

 しかし、オシロを見ると、どうもピンが動いていない。そのうち、USIにピンを指定しまうと、ここでの単純なGPIOのピン操作は全くできないことに気づいた。以前Atmelのアプリケーションノートを参考に、I2Cのライブラリーを作ったとき、1ビット送出をシフトレジスターの操作で出していたのを思い出した。

 そうか、そうやって信号線を上下するのか。あのときは何でこんな面倒なことをやっているのかわからなかったけれど、こういうことだったのだ。あわててスタートビットとストップビットがUSIDRと、USICRの操作で出るようにロジックを加える。

 これで、何とか、スタートビットとストップビットがデータの前後に出るようになった。しかしグリッチがでたり、データの終わりに1ビットの0がでたりしてまともなUARTデータ列になってくれない。勿論、UART端末からは全く無意味な文字列が出るだけである。

 そのうち、UARTがLSBファーストであることに気づいて、ビット順序の逆転ロジックを加えたり、負論理に換えたりしたが、一向にUARTからは、正しい文字列がでてこない。化け化けの記号がでるだけである。完全に暗礁に乗り上げてしまった。

TTLのUARTは正論理が主流なのか(3/27/2014)

 ウェブで調べたが、どうも判然としない。RS232Cでは信号は負論理だが、どうもTTLでは正論理が主流のようだ。少なくとも、CP2101のUSBシリアルアダプターは正論理で、ロジアナのLAP-CのUARTプロトコルでも正論理がdefault(省略値設定)である。

 遂に自力でソフト開発をするのをあきらめ、AtmelのアプリケーションノートAVR307(USIを使った半二重UARTライブラリの開発)のお世話になることにした。ここにソースコード一式があるのは知っていたが、ちょっと意地になって見ないで開発していた。

 背に腹は代えられない。どうも、このUSIのシフトレジスターには癖があって、正攻法ではうまく動かない。説明を読み込む。なになにい、1バイト分を5ビットづつ2回に分けて送信している。なぜだ。さらに読みすすめていって疑問が氷解した。ソースコードを見るまでもない。

 データシートにはDO(送信ライン)とシフトレジスターUSIDRのMSBがトランスペアレントだということをやけに強調しているのだが、これがどういう意味なのか全く理解できていなかった。しかし、このアプリケーションノートの説明ではっきりわかった。

 つまり、シフトレジスターを8ビット読みきると、レジスターの中は空となり、MSBが0になるので出力ラインDOも0になってしまうのだ。8ビット以上のデータを連続して送るためには、シフトレジスターを途中で止め、MSBを保持しながら、次のデータをシフトレジスターにロードしなければならない。

Usi_bit_sequence  こうすると、値は変わらずに次のデータを連続的に送ることが出来る。UARTは頭は0のスタートビット、最後は1のストップビットで1フレームを構成するから、スタート/ストップビットを前後につけた10ビットのデータストリームを5ビットづつ2回にわけて送信すれば良い。

 なるほど、これはすごい。殆ど手品に近い高等テクニックだ。日本語データシート(原文で読めばもう少しましなのだろうが読みにくい日本語だ)からでは、このテクニックを読み取ることはまず不可能だ。

 早速、5ビットづつ2回にわけてデータを送るコードを書き込む。オシロにはグリッチもなく、もう殆ど問題ないUARTらしいデータ列が出てきた。しかし、UARTコンソールは依然としてゴミデータしかでてこない。何故だあ。スタートビットもストップビットも綺麗に出ているのに。

やっとUSIのUART送信はOKになった(3/28/2014)

 データが化けるのは、負論理でデータを送っていたことがわかり、これを正論理に戻して、遂に、UARTコンソールから久しぶりに正しいオープニングメッセージが出た。やれやれ今回は時間がかかった。成功の喜びに浸る。

Usiuart1  しかし喜びも束の間だった。コンソール出力を良く見ていると、ところどころで文字が化けている。ChaNさんの開発された書式付出力関数xprintfで数字を出すところだけがダメである。えー、これはどういうことだ。こちらが使っているxprintfは昔のバージョンでアセンブラーのプログラムだ。アセンブラープログラムで字化けする?まさか。

 こうなるとオシロではそろそろ限界で、ロジアナの登場である。慎重を期して、プログラムのあちこちにプローブ点を設ける。ブレッドボードにジャンパーをてんこ盛りに盛ってプローブ点をロジアナに接続する。

S_p3296452  ロジアナを動かしてみるとxprintfでの状況はすぐわかった。キャラクターを出すところは連続して送信がされているが、バイナリーをキャラクターに換えるときは時間がかかるので少し送信を休んでいる。そのときの状況はどうだ。おお、送信関数が始まった直後に、ボーレートパルスが動いている。

これでは先にデータが送られてしまい、スタートビットが喰われてしまうので、このあとのデータが文字化けになるはずだ。想定より先に割り込みが起きるのは、ペンディングされていた割り込みリクエストが残っているからに違いない。

 解決策は、割り込み開始の前に、リクエストビットをクリアするだけである。プログラムをコンパイルしなおす。オープニングメッセージを出す。良いぞ。今まで化けていた数字は見事に正しく表示された。

 やった、やった。USIを使ったUART(送信部だけだけど)が遂に完成した。文字はどこまでも正しく表示される。いやあ久しぶりの感動だ。解決までの時間がかかればかかるほどこの感激は大きい。

Kuitubushi  気分が落ち着いたところで、いよいよ最後の検証に入る。もともとはサーボモーターの制御がUARTで乱れるので、その解消にUSIを使ったUARTを開発したのだ。今は、モーター制御中のUART送出は止めているが、これを戻しても制御の乱れがないようにならなければ開発した意味がない。

Photo  どきどきしながら、制御中のUART送出コードを復帰させる。コンパイル。さあ、どうだ。おーし、見事サーボは無音になった。ADコンバーターの入力にコンデンサーをかましたので(ウェブで教わった)、サーボ自体の振動もほぼ収まっている。

 ボリュームを左右に回すと、サーボは「ジジッ」という動作音とともに所定の場所へ移動する。その後はピタッと音が止まる。UARTによるモーターの振動は全くない。良いぞ、良いぞ。これで面倒な開発をしたかいがあったというものだ。

 さあ、次は受信部分の開発である。受信は送信ほど面倒ではない。しかし、ブログの更新が遅れているのでとりあえずこのあたりで報告しておこう。ソースコードの公開は、受信部分の改良が出来てからやることにする。

 TinyシリーズだけのUSIだけれど、Tiny45などの8ピンAVRにも使われているし、USIを使ったUARTの割り込み禁止区間は、ボーレートタイマーの割り込みの部分だけで、マイクロセカンドオーダーで済む。同時処理を行うプログラム(PWMを出しながらLCD表示など)では多いに役に立つはずである。

| | コメント (2) | トラックバック (0)

« 2014年3月2日 - 2014年3月8日 | トップページ | 2014年4月6日 - 2014年4月12日 »