loading

arduinoを使った工作を幾つかやった後、倒立振子の作成を思い立ちました。今回の方針は次の2つです。

  • 極力シンプルな構成
  • 自力で作る(webの先人に頼らない)


立たせるのにまるまる1週間以上かかりましたが、なんとか当初の方針を守りながら、上の写真の倒立ロボットを作りました(下の動画は動作のデモです)。

(*1)制御の方程式とジャイロのトラブルシュートはwebを参照しました
(*2)動画では9V電池に代えてUSB出力のバッテリでarduinoに給電してます

この倒立ロボットですが、構造、電装、スケッチ(プログラム)ともにとても簡素です。使用するセンサは1つだけ(200~400円)で、モータは普通に手に入る一番安いヤツでOKです。なのでarduinoでLEDを点滅させたことがあれば、あとは材料とプログラムさえ揃えば、半日もかからずに作ることができると思います。

それで作成後の感想ですが、倒立振子の作成は、ちょっと難しいパズルを解くのに似ているように思います。答えが分かってしまえば簡単、というかパズルの意味がないので、そこに注意して話を進めます。

*An English version of this instructable is available.

** 日本語版では幾つかのコンテンツ(※)が表示されないようです。その場合、ブラウザのアドレスバーに表示されているURLの末尾「?lang=ja」を削除して画面を更新してください。それでも上手く表示されない場合は、英語版をご覧ください。
(※:各ステップの代表写真下の参考写真、PDFファイルのアイコン等)

*** ジャイロをSTマイクロ社製のデジタル出力センサに代えた新バージョン「もう一つの倒立振子(デジタル版)※」と、これらの倒立ロボットを用いた「倒立振子の研究」をアップしました(2014年9月)。それに伴い、本バージョン(オリジナル版)の最後にステップ12を追加し、これの記事で使うスケッチのリンクを添付しています。(※Step.2の微細なはんだ付けが不要です)

Step 1: 材料をそろえる

(1)躯体

 タミヤの「楽しい工作シリーズ」を使用します。


(2)電装

  • arduino UNO
  • ブレッドボード(小)
  • ジャンパ・ケーブル(20本ほど)
  • モータ・ドライバIC(TOSHIBA TA7291P)を2個
  • ジャイロ・モジュール(秋月電子 K-04912
  • 単3電池を4本
  • 9V電池(006P形)
  • 電池ホルダ(単3×4本用)
  • 電池スナップを2個
  • 輪ゴム(数本)


材料紹介の動画(Step.1)


<補足>
ジャイロ・モジュールは個体のばらつきがあるようなので、2~3個買っておいた方が良いかもしれません。また最後に簡単に紹介しますが、モジュールを2つ使うと、倒立振子の動作が安定する気がします。

Step 2: 電装の準備

電装部品にピンとワイヤを取りつけます。

  1. モータにリード線を取り付ける(はんだ付け)
  2. ブレッドボード用のジャンパ・ケーブル(4本)を2つに切る
  3. モータと電池スナップのリード線(全部で8本)に、この切断したケーブルをはんだ付けする
  4. はんだ付けした箇所をテープで覆う(絶縁処理)
  5. 秋月電子製のジャイロ・モジュールにピンをはんだ付けする
  6. このモジュールのコンデンサ(C6)の両端を細いワイヤでつなぐ(はんだ付け)


作業の解説動画(Step.2)


■解説(1)
使用するジャイロ・モジュールは、村田製作所のジャイロ・センサ(ENC-03R)を2つ実装しています。今回使うのはこの内1つだけです。このセンサは単位角速度(1deg/sec)あたり0.67mVを出力(Vo)し、モジュールのオペアンプ(NJM2155)でこれを10倍に増幅して1番ピンから出力します(6.7mV/dig/sec)。

問題は、このモジュールに付けられた2つのフィルタの高い方(HPF)で、これが角速度の変化率(角加速度)を混入させます。そこでこのフィルタを無効にするため、モジュールのコンデンサ(C6:4.7uF)の両端をショートさせて角加速度の混入を回避します。
(*1)参考サイト1
(*2)参考サイト2

Step 3: 躯体の組み立て

タミヤの「楽しい工作シリーズ」を使って車体部分を組み立てます。

  1. ユニバーサルプレートにV字の切れ込みを作る(2か所)
  2. ユニバーサルアームセットのL字アングル(4個)をユニバーサルプレートに取り付ける
  3. ダブルギヤボックスを組み立てる(ギア比は114.7:1
  4. ダブルギヤボックスに付属モータ(2個)を取り付ける
  5. ダブルギヤボックスをユニバーサルプレートに取り付ける
  6. スリムタイヤセットの大径ホイールを組み立てる
  7. スリムタイヤをダブルギアボックスに取り付ける


作業の解説動画(Step.3)

Step 4: 電装の組み立て

電装部品を組み立てて、躯体に取り付けます。

  1. ブレッドボードにモータ・ドライバIC(2個)とジャイロ・モジュールを写真の通りに取り付ける
  2. ブレッドボードに輪ゴムを巻き、躯体のL字アングル(下の方)に取り付ける
  3. 上の配線図を見ながらブレッドボードにジャンパ・ケーブルを刺していく
  4. 配線図を見ながらブレッドボードに電池スナップ(単3ホルダに接続する方)のピン(2本)を刺す
  5. arduinoに輪ゴムを巻き、躯体のL字アングル(上の方)に取り付ける
  6. 配線図を見ながらarduinoにジャンパ・ケーブルを刺し、ブレッドボードと接続する
  7. 電池ホルダーに電池(4本)を入れる
  8. 躯体に輪ゴムを巻き、電池ホルダを取り付ける


作業の解説動画(Step.4)


■解説(2)
ここで作った倒立ロボットにはスイッチが付いていません。電源のON/OFFは電池スナップの接続/取り外しで行ってください。

Step 5: プログラムの書き込み

IDEを使ってarduinoにスケッチ(プログラム)を書き込みます。

  1. IDEに「MsTimer2」が見当たらない場合(上の写真参照)、ダウンロードしてインストールする(*追記:タイマを使わない簡素版(ver.2.0)を追加しました(2014/06/06)。こちらを使用する場合、MsTimer2は不要です) 
  2. arduinoとPCをUSBケーブルでつなぐ
  3. 電池ホルダに接続した電池スナップを外しておく
  4. 躯体を寝かせて静止状態にする
  5. 本ステップの最後にある「■サンプル・スケッチ(プログラム)」以下の内容を読む
  6. サンプル・スケッチを収めたpdfファイル「invertedRobot.pdf」(もしくは「invertedRobot_v20_noTimer.pdf」)をPCに保存して(*)、その内容を全てコピーし、IDEでarduinoに書き込む (* ブラウザで開いてコピーすると、スケッチの体裁が乱れて上手くいきません)


■解説(3)
倒立振子の制御は、モータの回転力の調整で行います。この調整は、振子の状態を表す4つの変数を使った簡単な数式で表されます。
モータの回転力= k1 × 躯体の傾き(角度)
          +k2 × 躯体の傾きの変化率(角速度)
          +k3 × 車輪軸の移動速度
          +k4 × 車輪軸の移動距離

ここでk1~k4は、これら4つの変数の重視の程度を表す定数です。末尾のpdfファイルのプログラムでは、72行目の長い式がこの調整式に相当します。倒立振子を立てるには、これら4つの変数を適切に評価するとともに、これらに掛る4つの係数の値を上手く決める必要があります。

ジャイロ・センサは、この式の2番目の変数(躯体の傾きの変化率)を計測し、これを電圧の高低で出力します。そして、この出力値をarduinoが積算することで1番目の変数(躯体の傾き)を評価します。

一方、3つ目の変数と4つ目の変数の評価は、モータもしくは車輪の回転速度を計測して行うのが標準的です。このため、ジャイロ・センサとは別のセンサ(回転計)か物理的なメータ(電流計やステッピング・モータ)を用います。

しかしここで作ったロボットは、ジャイロ・センサしか使っていないので、3番目と4番目の変数の評価が問題になります。末尾のpdfファイルのプログラムでは、76行目と77行目の式で、これら2つの変数の評価するのですが、とりあえずパズルとして空白にしています。

■解説(4)
もし、ここで紹介したジャイロ・モジュール以外のモジュールを使う場合、k1およびk2に相当する係数(プログラムの10行目と11行目)の値を変えてください。例えば、オペアンプ(NJM2155)をつけずにセンサ(ENC-03R)単独で使う場合、arduinoへの入力値は1/10になるので、係数k1とk2は10倍の値に変える必要があります。

■サンプル・スケッチ(プログラム)
まず下の「invertedRobot.pdf」もしくは「invertedRobot_v20_noTimer.pdf(*5)」をPCに保存し、これをadobe Reader等のアプリで開いてください。次にその中身(全部で3ページ)を全てコピーしてIDEに張り付け、下記の注記のようなミスプリを修正した上でarduinoに書き込んでください。

(*1)ファイルをブラウザで開いてコピーすると、スケッチの体裁が乱れます。必ずダウンロードしてからコピーしてください
(*2)72行目が切れている場合、次に置き換えてください
powerScale = ( kAngle * thetaI / 200 ) + ( kOmega * omegaI / 78 ) + ( kSpeed * vE5 / 1000 ) + ( kDistance * xE5 / 1000 ); //72
(*3)IDEやエディタにコピーすると、「//」の間にスペースが入る(「/ /」)ことがあるので修正してください
(*4)気温により動作が不安定になる可能性があります。夏期にバランスが上手くとれない場合、10~12行目の係数の値(45、85、57)を、それぞれ「52、95、53」あたりに変えてみてください(2014/06/06:追記)
(*5)「invertedRobot_v20_noTimer.pdf」はタイマ(MsTimer2)を使わない簡素版です。安定性も改善しているはずです(2014/06/06:追加)

(*6)Copyright (C) 2014 ArduinoDeXXX All Rights Reserved.

Step 6: 動作の確認

振子(倒立ロボット)の動作を確認します。

  1. プログラムの書き込みが終わったら、5秒ほど静止状態で放置する(写真①)
  2. その後、躯体を起こして電池スナップを接続する(写真②)
  3. 車輪が回転を始めるので、両手でその回転を止める
  4. 車輪を床に接地させ、躯体重心が車輪軸上に乗るあたりで、躯体が動かないように静止させる(写真③)
  5. ロボットが静止を確認すると、モーターの回転が緩み、「ミー」という小さなノイズがモータから出る
  6. そっと手を離し(写真④)、ロボットの上端を指で軽く押さえる
  7. この指を前後させ、ロボットが追従して動くことを確認する
  8. 押さえていた指を離すと、ロボットが少しバランスを取ろうとした後、転倒するのを確認する


作業の解説動画(Step.5~6)


■解説(5)
使用したジャイロ・センサは、躯体が動かない状態(角速度=ゼロ)での出力値が決まっていません。このためarduinoの電源を入れた後(もしくはリセット・ボタンを押した後)、躯体を寝かせたまま5秒ほど放置してください。この間に静止状態での出力値を評価します。

■解説(6)
解説(5)の後、躯体を起こすと角度の変化を感知して車輪が回転し始めます。そこでロボットに、倒立時の標準的な姿勢(角度)を覚えさせる必要があります。このロボットは、躯体が0.05秒間静止していたら、その時の角度を標準とするようプログラムされています。

したがって、躯体を起こして車輪が回り始めたら、両手でロボットの下部を持って車輪の回転を強制的に止め、Step.6の4段目以降の操作を実行してください。

なお、しばらく静止させてもモーターの回転が緩まない場合、解説(5)の評価が上手くいっていない可能性があります。この場合、arduinoのリセット・ボタンを押して車輪の回転を止め、躯体を寝かせて静止させた後、再度リセット・ボタンを押してからStep.6を再実行してください。

■トラブルシューティング(1)
躯体を起こしても車輪が回転しない場合、もっとも疑われるのは配線の誤りです。Step.4に戻って慎重に確認して下さい。あと考えられるのはジャイロ・モジュールの不良です。私が最初に使ったモジュールはVccとGNDが短絡しており、配線をつなぐたびにarduinoとPCの接続が切れました。

また、車輪は回っても指の動きに追従しない場合、もっとも疑われるのは、モータのリード線もしくはジャイロ・モジュールの配置が逆になっているケースです。さらに、モータ・ドライバICとarduinoのデジタル・ピンの配線に誤りがあるケースもこれに準じます。Step.4に戻って慎重に確認してください。

Step 7: パズルを解く

転倒振子から倒立振子になるための壁をスケッチ(プログラム)の修正でクリアします。

  1. ロボットが転倒する理由を考える
  2. Step.5のプログラムに修正を加えて、転倒が防げるかどうか試す
  3. 試行錯誤が上手くいけば、転倒振子から倒立振子に脱皮して完成! (おめでとうございます)
  4. 完成したらStep.8を覗いた後、Step.9のロボット操作を試してみる
  5. 試行錯誤が上手くいかなかったら、「1.」に戻るかStep.8(解答案)を見るかどうか悩む

Step 8: パズルの解答案

プログラムを修正して、振子を倒立させます。

  • Step.5のプログラムの76行目と77行目を次の3行に書き換える(上書きする)

vE5 = sumPower; //76a
xE5 = sumSumP / 1000; //77a
// Copyright (C) 2014 ArduinoDeXXX All Rights Reserved.

  • Step.6を実行する(8行目以降の指による支持は不要)
  • 手で静止させた状態で躯体の重心が車輪の軸上に近いところにあれば、ロボット(振子)は前後に少し往復した後で倒立状態に移行する
  • 振子がバランスをとりながら倒れないことを確認する
  • 振子がバランスを取りながら、少しずつ移動していく場合、74行目の「power」の後に、適当な数値(1~5程度の整数)を足し引きしてみる


作業の解説動画(Step.8)


■トラブルシューティング(2)
Step.6をクリアしたにもかかわらず、振子が倒立せずに倒れてしまう場合、まず電池(単3×4本)を新しいものに換えてみてください。それで解決しない場合、Step.5のプログラムの10行目から13行目の数値を変えてみてください。この内、最も効果があるのはたぶん12行目の数値だと思います。

Step 9: シリアル・モニタを使った振子の操縦

シリアル・モニタを使って、振子の向きと前進/後退の操縦を行います。

  1. Step.8で修正したプログラムに後述の修正(4か所)を追加する
  2. 追加修正したプログラムをIDEでarduinoに書き込む
  3. 書き込みが終了したら、IDEからシリアル・モニタを起動する
  4. シリアル・モニタの右下を確認し「LFのみ」「115200 baud」に変更する
  5. 5秒ほど振子を放置する
  6. Step.6を実行して振子を倒立させる(8行目以降の指による支持は不要)
  7. シリアル・モニタの上部の入力窓に、0〜3の数字を入力して送信ボタン(もしくはEnterキー)を押す
  8. 振子の姿勢や動作が変わることを確認する


作業の解説動画(Step.9)


■解説(7)
シリアルモニタを使って、振子を回転させたり前後に移動させたりします。例えば、「00」と入力すると、「0」を2回入力したことになり回転幅が大きくなります。
・右回転・・・「0」を入力
・左回転・・・「1」を入力
・前進・・・「2」を連続して入力すると前方向に加速します
・後退・・・「3」を連続して入力すると後方向に加速します

■スケッチ(プログラム)の追加修正(4か所)

(1)Step.8で修正したプログラムの17行目と18行目(*)の間に、次の5行を追加(コピー)する (*行番号は、Step.5のpdfファイルで各行右側に付記している行番号(//xx)に準じます)

volatile int drct = 0;
volatile boolean right = false;
volatile boolean left = false;
volatile int fwdBck = 0;
// Copyright (C) 2014 ArduinoDeXXX All Rights Reserved.


(2)さらに元のプラグラムの32行目を削除し、代わりに次の26行を追加(コピー)する

if ( Serial.available() ) {
drct = Serial.read();
Serial.println(drct);
}
if( drct == 48 ) { right = true; }
else if ( drct == 49 ) { left = true; }
else if (drct == 50 ) { fwdBck++; drct = 0; }
else if (drct == 51 ) { fwdBck--; drct = 0; }
if ( right == true ) {
analogWrite( 6, 140 );
digitalWrite( 4, HIGH );
digitalWrite( 5, LOW );
analogWrite( 9, 140 );
digitalWrite( 7, LOW );
digitalWrite( 8, HIGH );
delay(40);
} else if ( left == true ) {
analogWrite( 6, 140 );
digitalWrite( 4, LOW );
digitalWrite( 5, HIGH );
analogWrite( 9, 140 );
digitalWrite( 7, HIGH );
digitalWrite( 8, LOW );
delay(40);
} else if ( power > 0 ) {
// Copyright (C) 2014 ArduinoDeXXX All Rights Reserved.

(3)さらに元のプラグラムの55行目と56行目の間に、次の4行を追加(コピー)する

drct = 0;
right = false;
left = false;
// Copyright (C) 2014 ArduinoDeXXX All Rights Reserved.

(4)最後に元のプラグラムの74行目を削除し、代わりに次の2行を追加(コピー)する

sumPower = sumPower + power + fwdBck * 4; // 74a
// Copyright (C) 2014 ArduinoDeXXX All Rights Reserved.

Step 10: USBケーブルの切り離し

arduinoの電源を電池に代えて、倒立振子を完成させます。

  1. arduinoからUSBケーブルを抜く
  2. 2つ目の電池スナップに9V電池を接続する
  3. この電池をロボットの背部に、電池ホルダと共に輪ゴムで取り付ける
  4. この電池スナップのプラス側の線をarduinoのVinピンに刺す
  5. この電池スナップのマイナス側の線をarduinoのGNDピンに刺す
  6. 電池ホルダー(単3×4本)に1つ目の電池スナップが接続されていれば、車輪が回転し始める
  7. Step.6を実行して振子を倒立させる(完全な自立)
  8. 完成


作業の解説動画(Step.10)

Step 11: 発展

完成したロボット(倒立振子)を改良してみましょう。(二つ目の改良まで半日で行うのは、さすがに難しいと思います)

(1)ジャイロ・モジュールを追加

ジャイロ・モジュールをもう一つ追加して、倒立の姿勢や操縦の安定が改善するか確認します。

確認動画(Step.11-1)



(2)無線で倒立ロボットを遠隔操作

部品点数を増やさないようにテレビの赤外線リモコンを使います。

操縦動画(Step.11-2)



(3)Excelでシミュレーション

振子を車輪と胴体と頭の3つに簡略化して考えると、高校物理の範囲で運動方程式が書けます。これもパズル感覚ですが、運動方程式が書ければ、Excelでシミュレータを作れます。Step.5の2つの係数(k1とk2)の大きさは、これで概略あたりを付けることができます。

Step 12: 「もう一つの倒立振子(デジタル版)」と「倒立振子の研究」の資料

使用するジャイロ・モジュールとモータ・ドライバーICを変更した別バージョン(改良版)を、別のインストラクタブルとして追加しました(2014年9月)。そのステップ5で用いる2つのスケッチを収めたpdfファイルを添付します。

  • invertedRobot_v20d_noTimer.pdf
  • digtlGYRO_L3GD20_SPI_recover.pdf


さらに同月、これらの倒立ロボットの動作を分析し、PC上で「仮想振子」を描く方法を、「倒立振子の研究」のタイトルで別途投稿しました。そのステップ3ステップ9で用いる2つのケッチを収めたpdfファイルも併せて添付します。

  • virtualPendulum_processing.pdf ・・・ Processingのスケッチ
  • invertedRobot_v21d_crrnt_accl.pdf ・・・ Arduinoのスケッチ

なお、これらpdfファイルのアイコンが表示されない場合、アドレス・バーのURLの末尾の「?lang=ja」を削除して、ページを更新してください。

c6をはんだ付けしたのですが、タイヤがうまく回らなくなり、前に傾けると同時にしか回転しなくなりました。<br>どうしたら良いでしょうか?
<p>1~2ヶ月前に同様のコメントがあったので、それらの回答をご参照ください。</p>
<p>step6の動作確認までできるようになったのですが、自立させるための追加文を付け加えて実行してみたところ自立することができませんでした。プログラムの10行目~13行目の値の求め方があれば教えてほしいです。</p><p>後、同じ部品を使っていると言いましたがタイヤだけSPORTS TIRE(56mm)を使用しています。そこにも問題があるのでしょうか?</p>
<p>タイヤの半径が同程度なら、幅や質量の違いははあまり問題にならないと思います。ステップ8のプログラム修正を行えば、安定性に多少の違いはあれ、自立の気配は感じられるはずです。全く自立の気配がない場合、配線や部品の不良といった工作の問題を疑った方が良いかもしれません。</p><p>また、ご照会の係数の値については、半月ほど前に同様の質問があったのでそちらを参照してください。、</p>
<p>step6の動作確認の追従までできました、プログラムの10行目~13行目をいろいろ試行錯誤で試した後、わずか1、2秒ぐらいは自立しました。しかし、昨日step2 ジャイロセンサーのC6をショートさせる をやってなかったことに気づき、C6をはんだ付けしましたが、後ろの傾きしか感知できなくなりました(タイヤが後ろにしか回らない)。今までは追従できましたので、回路の間違いがないと判断してもいいでしょうか?</p>
<p>&gt; 回路の間違いがないと判断してもいいでしょうか?</p><p>何とも言えませんが、そうなのかもしれません。いずれにせよトラブル・シューティングに関しては、これまでのQ&amp;A、および他の方々とのやりとりを参照してください。</p>
<p>なぜジャイロセンサのC6の両端をショートさせるのですか?</p>
<p>ステップ2で紹介した参考サイトを見てください。ネットで調べると他にも分かるはずです。</p>
<p>同じ部品を使って同じように回路を組んだのですが、Step 6の動作の確認のところで、空中のときは動画のようにタイヤが回転しますが、ロボットを地面に静止した後うまく追従できません(後ろに倒れたらタイヤが前に進む)。回路は念入りに確認しましたが、プログラムもどこか修正が必要ですか。プログラム初心者です、アドバイスをいただけると幸いです。よろしくお願いします。</p>
<p>これまでの投稿の内、上手く行かない原因のほぼすべては誤配線だった気がします。デジタル版のステップ6に、<a href="https://www.youtube.com/watch?v=BY9Sx46eD5s" rel="nofollow">動作確認の動画</a>を追加しているので、まずはこの動きを参照してください。その上で、もし意図した方向と逆に車輪が回転するようであれば、(1)モータの配線を逆にする(2つとも)、もしくは(2)スケッチの「analogRead(A5)」の符号を「-」に変える(たぶん2か所)、ことで回転方向を変えられるはずです。</p>
<p>プログラムの10〜12行目の係数のちょうど良い値を見つけるコツとかありますか?</p>
<p>&gt; 重さを変えるとうまく自立しなくなります。プログラムのどこが悪いのですか?</p><p>重量が増える分には比較的頑健な作りになっていると思います。イントロのデモ・ビデオで、鉄製の工具を2つ載せる所がありますが安定性の悪化は特に認められません。</p><p>&gt; プログラムの10〜12行目の係数のちょうど良い値を見つけるコツとかありますか?</p><p>この2つの係数の値選択は試行錯誤で決めるのが一番簡単だと思います。</p>
<p>重さを変えるとうまく自立しなくなります。</p><p>プログラムのどこが悪いのですか?</p>
プログラムの73行目の<br>power=<br>のところがいつもうまくいきません。(ずっと255の値になります)<br><br>
<p>状況が良く分からないのですが、シリアルモニターで変数powerの値を見ているのでしょうか?</p><p>もしそうならば、一行上の変数powerScaleの値が常に255を超えていることになります。その場合、ジャイロの出力値の異常が考えられます。</p>
ギアボックスを楽しい工作シリーズNo.97のツインモーターギヤーボックスで代用したのですが上手く倒立しません、プログラムのどこを変えたら良いですか?
<p>選択できるギア比が異なるので何とも言えないですが、10~13行目の係数の値の変更は必要だと思います。この記事のタイトル「半日で・・・」と「ツインモーター・・・」等のキーワードで検索して情報を集めてはいかがでしょうか。</p>
void training()とvoid chkAndCrl()はどんな働きをしてるのですか?
<p>短いプログラムなので内容を良く見てください。たぶん分かると思います。</p><p>一度組み立てた後、プログラムの一部を省略したり数値を変えたりすれば、直観的な理解も容易になると思います。</p>
プログラムは何の言語を使っていますか?
<p><a href="http://www.musashinodenpa.com/arduino/ref/" rel="nofollow">Arduino言語</a>(以下引用)</p><p>「Arduino言語はC/C++をベースにしており、C言語のすべての構造と、いくつかのC++の機能をサポートしています。また、AVR Libcにリンクされていて、その関数を利用できます。」</p><p><a href="http://garretlab.web.fc2.com/arduino/introduction/programming/" rel="nofollow">リンク:参考サイト</a></p>
ご見解をいただきましてありがとうございます。ぜひ、ステップ5の制御方程式の各変数の評価と役割について、熟読させていただきます!<br>より安定化できましたら、結果は共有させていただきます。<br>丁寧なご回答ありがとうございました。
You tube に動画をアップいたしました。<br>https://youtu.be/KChPi5iqG3U<br>よろしくお願いします。<br>
本当にすばらしいサイトありがとうございます!趣味で倒立振子を作ってます。<br>ほとんどの部分を参考にさせていただき、ようやく倒立するところまでこぎつけました。しかし、ArduinoDeXXXさんの紹介動画のような機敏な復帰の動作が見られないようなのですが、添付の動画はたまたまバランスしてるだけで、いわゆる制御工学の倒立振子の動作には至っていないのでしょうか?動画の動きからアドバイスをいただけると幸いです。よろしくお願いします。<br>角度検出はジャイロのゼロ点ズレや、ドリフトが大きくなかなか上手くいかなかったため、試行錯誤の上、加速度センサとの組み合わせによる相補フィルターで計算させています。
<p>こんにちは</p><p>動画はダウンロード(「名前を付けてリンク先を保存」)して拝見しました。倒立のバランスはとれているように見えます。係数等を調整すれば動作も変わるので、安定性を改善できるのではないでしょうか。ステップ5の制御方程式の各変数の評価と役割については、<a href="https://www.instructables.com/id/%E5%80%92%E7%AB%8B%E6%8C%AF%E5%AD%90%E3%81%AE%E7%A0%94%E7%A9%B6/">別の記事</a>にまとめましたのでよろしければご参照ください。</p>
動画のuploadが失敗しているようなので後程改めてuploadさせていただきます。
課題研究で倒立振子の研究をしています!<br>同じように回路を組んだのですが上手くいきません。<br>プログラムは上手く書き込めたと思います
<p>こんにちは<br>サポートには情報が足りないので、とりあえず経過報告と考えます。<br>ちなみに不具合の原因多くは配線ミスです。ご参考まで。</p>
本当に返事遅れまして申し訳ございません。<br>配線ミスでした!<br>ありがとうございます!<br>倒立させるにはどの値を変化させるのが効果的ですか?プログラムの中から具体的に教えていただきたいです。
<p>状況が分からないので何とも言えませんが、まずはステップ5の解説3、同末尾の注記*2と*4、ステップ8のトラブルシューティング(2)をご覧ください。また「倒立振子の研究」のステップ1にも関連の話があるのでご参照ください。</p>
情報が少なく申し訳ございません。プログラムの72行目の値を変えてみたところ、数秒自立するようになりました。しかし、モーターの前に進む出力と後ろへ進む出力が違うようで、手で押さえて車体を静止させた時に片一方への傾きを異常に検知してしまいます。知識が少なく申し訳ございません。アドバイスを頂けたら幸いです。
<p>まず、<a href="https://www.instructables.com/id/Another-Easier-Inverted-Pendulum-in-Japanese/step6/%E5%8B%95%E4%BD%9C%E3%81%AE%E7%A2%BA%E8%AA%8D/" rel="nofollow">デジタル版のステップ6</a>に添付した動画「■参考:追従振子の動作確認の動画」を参照して、同様の動きを再現できるか確認してみてください。なおこの時に用いるスケッチは、ステップ8の修正を行う前のものにしてください(ステップ5に添付)。</p><p>もしこの動きを再現できているにもかかわらず、ステップ8の修正で倒立に至らない場合、動作の様子が分かる動画をアップロードしてください。</p>
<p>アドバイスありがとうございます。少し安定するようになりました。そこで、ジャイロセンサを2つにし、より精度の高いものを作ろうとしているのですが、2つ使用した際にはプログラムに変更しなければいけないところはありますか?また、追加したジャイロセンサの出力端子はどこに接続すればよろしいでしょうか?</p><p>そして、倒立振子の倒立する場所でのジャイロセンサの出力値を固定し、ステップ6の解説6にある0.05秒間秒間静止というのを省くことはできますでしょうか。</p><p>知識不足で質問ばかりですみません。</p>
<p>&gt; ジャイロセンサを2つにし、・・・<br>追加ジャイロは最初のジャイロと逆向きに取り付けてください(ステップ11の写真参照)。</p><p>&gt; 2つ使用した際にはプログラムに変更しなければいけないところはありますか?<br>「 anlogRead(A5) 」を「 ( anlogRead(A5) - analogRead(A4) ) / 2 」に書き換えてください。たぶん2ヶ所あると思います。</p><p>&gt; 追加したジャイロセンサの出力端子はどこに接続すればよろしいでしょうか?<br>ArduinoのA4ピンに接続してください。</p><p>&gt; 倒立振子の倒立する場所でのジャイロセンサの出力値を固定し、ステップ6の解説6にある0.05秒間秒間静止というのを省くことはできますでしょうか。<br>難しいと思います。</p>
ご回答ありがとうございます!0.05秒間静止のところの感覚を伸ばすことはできますか?
<p>スケッチはいろいろ変えて試してみてください。<br>ただ、ご照会の箇所が安定性の向上につながるか疑問です。<br>配線や部品動作を改めて確認した方が良い気がします。</p>
<p>ありがとうございます!</p><p>解説6の0.05秒間はどこにプログラムされているかだけ教えていただきたいです。</p><p>なんども申し訳ありません。</p>
<p>60行目から71行目が該当部分です。<br>削除すると、ステップ6の5の回転停止がなくなるので、別途手当てが必要になります。</p>
<p>void setup() {</p><p> // put your setup code here, to run once:</p><p>}</p><p>/* &quot;A very easy and simple inverted pendulum balancing robot&quot;</p><p>You need only half a day to make it, if you have some Materials.</p><p>Copyright (C) 2014 ArduinoDeXXX All Rights Reserved. */</p><p>#include &lt;MsTimer2.h&gt; //01</p><p>volatile int i = 0; //02</p><p>volatile byte countS = 0; //03</p><p>long zeroOmegaI = 0;// 04</p><p>volatile int recOmegaI[10]; //05</p><p>volatile int omegaI = 0; //06</p><p>volatile long thetaI = 0; //07</p><p>volatile long sumPower = 0; //08</p><p>volatile long sumSumP = 0; //09</p><p>const int kAngle = 45; //10</p><p>const int kOmega = 85; //11</p><p>const long kSpeed = 57; //12</p><p>const long kDistance = 60; //13</p><p>volatile long powerScale; //14</p><p>volatile int power; //15</p><p>volatile long vE5 = 0; //16</p><p>volatile long xE5 = 0; //17</p><p>void setup () { //18</p><p> Serial .begin(115200); //19</p><p> pinMode(4, OUTPUT); //20</p><p> pinMode(5, OUTPUT);</p><p> pinMode(6, OUTPUT);</p><p> pinMode(7, OUTPUT);</p><p> pinMode(8, OUTPUT);</p><p> pinMode(9, OUTPUT);</p><p> for ( i = 0 ; i &lt; 10 ; i++ ) { recOmegaI[i] = 0; } //25</p><p> delay(300);</p><p> training();</p><p> MsTimer2::set(5, chkAndCtl);</p><p> MsTimer2::start();</p><p>} //30</p><p>void loop () { //31</p><p> if ( power &gt; 0 ) {</p><p> analogWrite( 6, power );</p><p> digitalWrite( 4, HIGH );</p><p> digitalWrite( 5, LOW ); //35 </p><p> analogWrite( 9, power );</p><p> digitalWrite( 7, HIGH );</p><p> digitalWrite( 8, LOW );</p><p> } else {</p><p> analogWrite( 6, - power ); //40</p><p> digitalWrite( 4, LOW );</p><p> digitalWrite( 5, HIGH );</p><p> analogWrite( 9, - power );</p><p> digitalWrite( 7, LOW );</p><p> digitalWrite( 8, HIGH ); //45</p><p> }</p><p>} //47</p><p>void training(){ //48</p><p> delay (1000);</p><p> for ( i = 0 ; i &lt; 500 ; i++ ){ //50</p><p> zeroOmegaI = zeroOmegaI + analogRead(A5);</p><p> }</p><p> zeroOmegaI = zeroOmegaI / i;</p><p>} //54</p><p>void chkAndCtl() { //55</p><p> omegaI = analogRead(A5) - zeroOmegaI;</p><p> if ( abs( omegaI ) &lt; 5 ) { omegaI = 0; }</p><p> recOmegaI[0] = omegaI;</p><p> thetaI = thetaI + omegaI;</p><p> countS = 0; //60</p><p> for ( i = 0 ; i &lt; 10 ; i++ ) {</p><p> if ( abs( recOmegaI[i] ) &lt; 8 ) { countS++; }</p><p> }</p><p> if ( countS &gt; 9 ) {</p><p> thetaI = 0; //65</p><p> vE5 = 0;</p><p> xE5 = 0;</p><p> sumPower = 0;</p><p> sumSumP = 0;</p><p> } //70</p><p> for ( i = 9 ; i &gt; 0 ; i-- ) { recOmegaI[ i ] = recOmegaI[ i-1 ]; }</p><p> powerScale = ( kAngle * thetaI / 200 ) + ( kOmega * omegaI / 78 ) + ( kpowerScale = ( kAngle * thetaI / 200 ) + ( kOmega * omegaI / 78 ) + ( kSpeed * vE5 / 1000 ) + ( kDistance * xE5 / 1000 ); //72</p><p> power = max ( min ( 95 * powerScale / 100 , 255 ) , -255 );</p><p> sumPower = sumPower + power;</p><p> sumSumP = sumSumP + sumPower; //75</p><p>// vE5 = ??? //76</p><p>// xE5 = ??? //77</p><p>} //78</p><p>// Copyright (C) 2014 ArduinoDeXXX All Rights Reserved. //79</p><p>void loop() {</p><p> // put your main code here, to run repeatedly:</p><p>}</p><p>このプログラムで検証にかけるとコインパル時にエラーが発生しましたっとなりますが、どこが間違ってますかm(_ _)mアドバイスお願いします。</p>
最初の3行と最後の3行を削除してみてください。<br>あと、ご照会のスケッチを動かすには、タイマ・ライブラリ(MsTimer2)が別途必要です。このライブラリを使わないスケッチも用意しています。いずれもステップ5を参照してください。
<p>倒立振子は初めてです。</p><p>倒立振子には PID制御を使っていますか?</p>
こんにちは<br> PID制御、英語版では何度か話が出ましたが、日本語版では初めてかもしれません。ちなみに英語版のやりとりはこちら(&darr;)。<br> <a href="https://www.instructables.com/id/A-Simple-and-Very-Easy-Inverted-Pendulum-Balancing/?comments=all#CJMLYCMHYZO09XC" rel="nofollow">(1)vasoula</a>,&nbsp; <a href="https://www.instructables.com/id/A-Simple-and-Very-Easy-Inverted-Pendulum-Balancing/?comments=all#CGWZQISHT5CPRA0" rel="nofollow">(2)BigMig</a><br> <br> また、その後投稿した<a href="https://www.instructables.com/id/%E5%80%92%E7%AB%8B%E6%8C%AF%E5%AD%90%E3%81%AE%E7%A0%94%E7%A9%B6/" rel="nofollow">別の記事(倒立振子の研究)</a>のステップ1にも関連の解説を載せたのでご参照ください。見かけはPD制御ですが実体はPIDに準じる、はずです。
<p>早々にコメント頂きありがとうございます。ご紹介の動画やサイト、大変興味深く拝見しました。</p><p>思えば昨年の正月休みは、この倒立振子を立たせるのに全力でした。今年も何かやってみようと、ブラシレスモータを試してみました。行く行くはカメラ用のジンバルを作ってみたいところですが、先は長そうです。</p><p>試行1:サーボ的な運用</p><p> <br><iframe allowfullscreen="" frameborder="0" height="281" src="//www.youtube.com/embed/6cYyLiSGuhE" width="500"></iframe></p><p>試行2:一軸ジンバル的な運用<br> <br><iframe allowfullscreen="" frameborder="0" height="281" src="//www.youtube.com/embed/IB_O69B8D-c" width="500"></iframe></p>
<p>昨年末に始めた<strong>ブラシレス・ジンバル</strong>がようやく形になったので、5月の連休を使って<a href="https://www.instructables.com/id/DIY-Brushless-Gimbal-with-Arduino-in-Japanese/" rel="nofollow">開発経緯をまとめました</a>。ジャイロを使ったArduino工作に興味のある方、もしくはブラシレスモータをArduinoで制御したい方はご参照ください。</p><p><iframe allowfullscreen="" frameborder="0" height="281" src="//www.youtube.com/embed/0wAiGEn1WRo" width="500"></iframe></p>
<p>こんにちは、ブラシレスジンバルの実験とても興味があり、動画を楽しく拝見しました。</p><p>私は工作の他に野鳥観察と撮影が趣味で、天体望遠鏡を流用した超望遠レンズの</p><p>AF化や雲台の改造なども楽しんでいまです。</p><p>野鳥は人の姿を見ると逃げたり姿を隠します。リモコン雲台を使えば野鳥に脅威を</p><p>与えずに撮影が可能です。ブラシレスジンバルの成果を期待しています。</p><p>(御免なさい。返信方法が判らず、英語版に書き込んでました)</p>
<p>現在、人間が乗ることができる倒立振子を製作するべく、モータードライバの代わりとしてRCラジコンの スピードコントローラーを使用して試作しているのですが、不明な点が幾つかあるので、質問させて頂きたく思います。</p><p>まず、ジャイロセンサーの出力値は何を表しているのでしょうか?詳しく教えてください。</p><p>それと、何度やってもモーターの動きが挙動不審です。原因は何処にあるのでしょうか&hellip;</p><p>アドバイスお願いします。</p><p>以下プログラムです。</p><p>コメント等めちゃくちゃですがご容赦ください&hellip;</p><p>#include&lt;Servo.h&gt;<br>int i = 0; <br>byte countS = 0; <br>long zeroOmegaI = 0;<br>int recOmegaI[10];<br>int omegaI = 0;<br>long thetaI = 0;<br>long sumPower = 0;<br>long sumSumP = 0;<br>const int kAngle = 54;<br>const int kOmega = 170;<br>const long kSpeed = 60;<br>const long kDistance = 60;<br>long powerScale;<br>int power;<br>long vE5 = 0;<br>long xE5 = 0;<br>Servo myservoL;<br>Servo myservoR;</p><p>void setup () { <br> myservoL.attach(10);<br> myservoR.attach(11);<br> myservoL.write(90);<br> myservoR.write(90);<br> delay(30000);<br>for ( i = 0 ; i &lt; 10 ; i++ ) { recOmegaI[i] = 0; }<br>delay(300);<br>training();<br>// MsTimer2::set(5, chkAndCtl); // (This line is omitted in this version.)<br>// MsTimer2::start(); // (This line is omitted in this version.)<br>}<br>void loop () {<br>chkAndCtl();// NL1 (This is a new line in this version.)<br>if ( power &gt; 0 ) {<br> myservoL.write(90+power/2);<br> myservoR.write(90-power/2);<br>} else {<br> myservoL.write(90+power/2);<br> myservoR.write(90-power/2);<br>}<br>delayMicroseconds(3600); // NL2 (This is a new line in this version.)<br>} //47<br>void training(){ //48<br>delay (1000);<br>for ( i = 0 ; i &lt; 500 ; i++ ){ //50<br>zeroOmegaI = zeroOmegaI + analogRead(A5);<br>}<br>zeroOmegaI = zeroOmegaI / i;<br>} //54<br>void chkAndCtl() { //55<br>omegaI = 0; // NL3 (These 6 lines, NL3-NL8, are added in this version.)<br>for ( i = 0 ; i &lt; 10 ; i++ ) { //NL4<br>omegaI = omegaI + analogRead(A5) - zeroOmegaI; //NL5<br>delayMicroseconds(10); //NL6<br>}// NL7<br>omegaI = omegaI / 10;// NL8<br>// omegaI = analogRead(A5) - zeroOmegaI; // (This line is omitted in this<br>if ( abs( omegaI ) &lt; 3 ) { omegaI = 0; } // (The lower bound is less than<br>recOmegaI[0] = omegaI;<br>thetaI = thetaI + omegaI;<br>countS = 0; //60<br>for ( i = 0 ; i &lt; 10 ; i++ ) {<br>if ( abs( recOmegaI[i] ) &lt; 8 ) { countS++; }<br>}<br>if ( countS &gt; 9 ) {<br>thetaI = 0;// 65<br>vE5 = 0;<br>xE5 = 0;<br>sumPower = 0;<br>sumSumP = 0;<br>} //70<br>for ( i = 9 ; i &gt; 0 ; i-- ) { recOmegaI[ i ] = recOmegaI[ i-1 ]; }<br>powerScale = ( kAngle * thetaI / 200 ) + ( kOmega * omegaI / 78 ) + ( kSpeed * vE5 / 1000 ) + ( kDistance * xE5 / 1000 ); //72<br>power = max ( min ( 95 * powerScale / 100 , 255 ) , -255 );<br>sumPower = sumPower + power-5;<br>sumSumP = sumSumP + sumPower;// 75<br>vE5 = sumPower; //76a<br> xE5 = sumSumP / 1000; //77a <br>} //78</p>
<p>説明不足ですみません。補足させていただきます。</p><p>はじめのdelay(30000);云々のところですが、スピードコントローラーにニュートラルの信号を送るためのプログラムです。動作は確認済みなので、この部分は問題ないはずです。</p>
<p>ラジコンはやったことがないのでよく分かりませんが、スケッチではサーボ・ライブラリをお使いのようですね。普通の<strong>サーボ・モータ</strong>は次の2点で倒立振子の動力には向いていないと思います。</p><p>・減速が大きい(最大回転数が低い)</p><p>・制御の入力が角度(位置情報)で与えられる</p><p>もしかしたら、サーボ・モータのPWM情報を利用した<strong>ブラシレス・モータ</strong>をお使いかもしれませんが、ブラシレス・モータの制御は簡単ではありません。人が乗るのであれば、扱いやすい高出力のブラシ付きモータを利用するのが早道だと思います。</p><p>英語版のInstructablesにご趣旨に近い記事がありました。私は良く見てませんが、扱いやすい材料とarduinoで上手く動いているようです。かなり丁寧に説明されているようなので、これをテキストにしてはいかがでしょうか。なお、この規模の工作になると、作業時に大きな事故が起きる可能性があります。十分注意してください。</p><p><a href="https://www.instructables.com/id/Rideable-Segway-Clone-Low-Cost-and-Easy-Build/" rel="nofollow">https://www.instructables.com/id/Rideable-Segway-Cl...</a></p>
<p>ご指摘ありがとうございます。</p><p>モーター周りですが、少し特殊なものを使用していて精度・出力に関しては申し分ありません。</p><p>この製作において、ジャイロセンサーからどのように角度を算出しているのか詳しく教えていただけないでしょうか?</p>
<p>ジャイロ・センサは角速度を計測します。「距離=速さ&times;時間」と同じく「角度=角速度&times;時間」です。より詳細な話は別の記事にまとめたのでそちらを参照してください。</p><p><a href="https://www.instructables.com/id/倒立振子の研究/" rel="nofollow">https://www.instructables.com/id/倒立振子の研究/</a></p>

About This Instructable

184,197views

27favorites

More by ArduinoDeXXX:A Levitating Sphere Rotates Glows and Blinks with Arduino Arduinoで作る浮遊光球 Another Easier Inverted Pendulum Robot 
Add instructable to: