ラベル ロボット の投稿を表示しています。 すべての投稿を表示
ラベル ロボット の投稿を表示しています。 すべての投稿を表示

2017年8月5日土曜日

現代制御勉強メモと倒立振子の制御例

## 概要

現代制御の勉強メモです.実装するまでの過程をトレースしたかったので,それに必要な知識の確認程度に書いたものです.
内容は状態フィードバック則と同一次元状態オブザーバのまとめと,それを使って適当な制御対象を制御してみてみます.
なお授業で扱った内容を思い出すためのものである上,幾つか扱ってない部分があったり間違ってたり省略してたりするので,ちゃんとした説明は教科書見直してください.学部生なんだ許されてくれ.

## 勉強メモ


### メインコンセプト

次のような状態方程式と呼ばれる形で表された微分方程式がある.ただし\(x\)はベクトルで内部状態を表し,\(u\)は入力,\(y\)は出力である.また\(A,B,C,D\)は定数行列である.

\[ \begin{eqnarray} \dot{x}&=&Ax+Bu\\ y&=&Cx+Du \end{eqnarray} \]

メインコンセプトは,この微分方程式の内部状態\(x\)を,0ベクトルにどうやって近づけるかということである.\(x\)が0ベクトルに収束するためには行列「\(A\)の固有値の実部がすべて負」でなければいけない.「\(A\)の固有値の実部がすべて負」の時,\(x\)は指数関数的に減衰していくことが知られているため,\(x\)は0ベクトルに収束する.

さて,実際にモデルを立てた時に「\(A\)の固有値の実部がすべて負」という条件が満たされていなかったとする.その場合,\(x\)は0に収束するどころか発散してしまう場合がある.しかし,このとき入力\(u\)をうまく与えてやることで擬似的に「\(A\)の固有値の実部をすべて負」にできる.その最も単純な方式として状態フィードバックを用いた極配置という方法を取る.

この方法では,入力\(u\)を次のような形で与える.ただし\(K\)は適当な定数行列である.

\[ u=Kx+v \]

これを上式に代入すると次のようになる.

\[ \begin{eqnarray} \dot{x}&=&(A+BK)x+Bv\\ y&=&Cx+Du \end{eqnarray} \]

したがって定数行列\(A\)が,擬似的に\(A+BK\)となった.したがって\(K\)をうまいこと決めてやれば,定数行列\(A\)の固有値を変えられる.固有値の実部が全て負になるような\(K\)にすれば,\(x\)は0ベクトルに収束し目的が達成できる.

さて,現代制御論のメインコンセプトは上に述べたとおりである.しかし上では語弊を承知で具体的な計算などはすべて除いた.そのため実際には安定化させられない条件というのがいくつかある.また,入力\(u\)は\(u=Kx+v\)とすればよいといったが,\(x\)がわからなければ\(u\)を決定できない.そのため\(x\)を推定する必要がある.

以下では制御ができるかできないかを表す指標「可制御性」,状態\(x\)が推定できるかできないかを表す指標「可観測性」について述べる.

### 状態フィードバック則(文献[1]P35)

先程定数行列\(K\)をうまく決めてやれば,定数行列\(A\)の固有値を擬似的に変えられることをのべた.実際には\(K\)はその要素を適当な変数で置いてやって固有値方程式
\[ \det(\lambda I-(A+BK))=0 \]
が,実部が負となる適当な固有値 \(\lambda_1,...,\lambda_n\)を自分で決めてやって,次式のようにその解がその固有値になるようにしてやれば良い.

\[ \det(\lambda I-(A+BK))=\prod_{i=1}^n(\lambda - \lambda_i) \]

ただし\(\lambda_1,...,\lambda_n\)は係数が実数の多項式の解となるような状態(複素平面上においた時に実軸対称)でなければならない.

### 可制御性(文献[1]P35)


さて上記の式を実際に立ててみると連立方程式は\(K\)の要素に関する線形連立方程式になることが保証されているらしい.しかし妥当な解が得られないような場合がある.すなわち,思い通りに制御することができない場合がある.思い通りに制御できないことを不可制御性を持つと良い,逆に思い通りに制御できることを可制御であるという.

可制御であるということの必要十分条件は次の条件が満たされている場合である事が示されている(文献[1]P38).
\[ rank M_c=rank [B \,\, AB\,\,\dots\,\,A^{n-1}B]=n \]

この行列\(M_c\)は可制御性行列とよばれるもので,微分方程式の解析解を求めると出てくる

\[ \begin{eqnarray} x(t)&=&e^{At}x(0)+\int_0^t e^{A(t-\tau)}Bu(\tau)d\tau\\ &=&e^{At}x(0)+\int_0^t (\beta_0 (t-\tau)I+\beta_1(t-\tau)A+\dots+\beta_{n-1}(t-\tau)A^{n-1})Bu(\tau)d\tau \\ &=&e^{At}x(0)+[B \,\, AB\,\,\dots\,\,A^{n-1}B][\int\beta_0udt \dots\int\beta_{n-1}udt ]^T\\ &=&e^{At}x(0)+M_c [\int\beta_0udt \dots\int\beta_{n-1}udt ]^T \end{eqnarray} \]

不可制御の場合はどうやっても不安定であったりするので,そういう場合は制御対象を何かしら変える必要がある.

### 同一次元状態オブザーバ(文献[1]P121)

状態フィードバック則では,入力\(u\)を決定するのに\(u=Kx+v\)としているから,内部状態\(x\)がわかっている必要がある.

普通は内部状態\(x\)を知ることはできず,ここでは出力\(y\)と入力\(u\),および定数行列\(A,B,C\)のみから推定するしか無い.内部状態を推定する方法はいくつかあるらしいが同一次元状態オブザーバというものを紹介する.

まず\(x\)と同じ次元を持ち,次のような微分方程式で表される関数\(z(t)\)について考える.

\[ \dot{z}=Az+Bu+G(y-Cz) \]

この\(z\)が\(x(t)=z(t)\)となってくれれば内部状態\(x\)がわかったことになる.ここで\(x\)と\(z\)の差\(e(t)=x(t)-z(t)\)について考えると,\(\dot{e}=\dot{x}-\dot{z}\)であるから,

\[ \begin{eqnarray} \dot{e(t)}&=&A(x-z)-G(Cx-Cz)\\ &=&A(x-z)-GC(x-z)\\ &=&(A-GC)e(t) \end{eqnarray} \]

となるから,行列\(A-GC\)の固有値の実部が全て負であれば\(e\)は0に収束する,すなわち\(x=z\)となる.したがって\(A-GC\)の固有値の実部が全て負となるように\(G\)を状態フィードバック則と同じように決めてやればよい.

### 可観測性(文献[1]P41)

ただ同一次元状態オブザーバを作れない場合がある.すなわち,内部状態をどれだけ頑張っても出力\(y\)から知ることができない場合がある.そのようなシステムを不可観測であるといい,逆に内部状態を推定できるシステムを可観測であるという.

システムが可観測であるという必要十分条件は次の可観測性行列\(M_o\)が
\[ rank M_o = rank\begin{bmatrix}C\\CA\\\vdots\\CA^{n-1}\end{bmatrix}=n \]

であることである.この可観測性行列は入力が0である場合の\(y\)の解析解

\[ \begin{eqnarray} y&=&C e^{At}x(0)\\ &=&C(\beta_0 (t)I+\beta_1(t)A+\dots+\beta_{n-1}(t)A^{n-1})x(0)\\ &=&[\beta_0\dots \beta_{n-1}]M_o x(0) \end{eqnarray} \]

に出てくる行列である(文献[1]P43).


## 具体例

### 運動方程式の導出

ここでは台車にくっついた倒立振子について考えます.ただし運動方程式の導出は面倒なので参考文献[2]のモデルを用います(というかこの運動方程式の導出がちゃんとできないとだめというか,現代制御ではモデル化ができてしまえば後は勝手に制御則が出てくるので,でもう少し運動方程式の導出を再勉強するべきな気がする).

参考文献[2]より,台車の位置及び振り子の回転角度の運動方程式は次式のようになる.

\[ \begin{bmatrix} M+m&ml\cos(\theta)\\ ml\cos(\theta)&J+ml^2 \end{bmatrix} \begin{bmatrix} \ddot{x}\\\ddot{\theta} \end{bmatrix} + \begin{bmatrix} -ml\dot{\theta}^2\sin\theta\\ -mlg\sin\theta\end{bmatrix} + \begin{bmatrix} B\dot{x}\\C\dot{\theta} \end{bmatrix} =\begin{bmatrix} u\\0 \end{bmatrix} \]

ここで
\[ T=\begin{bmatrix} M+m&ml\cos(\theta)\\ ml\cos(\theta)&J+ml^2 \end{bmatrix} \]
とおけば


\[ \begin{eqnarray} \begin{bmatrix} \ddot{x}\\\ddot{\theta} \end{bmatrix} &=&T^{-1}\left(\begin{bmatrix} ml\dot{\theta}^2\sin\theta\\ mlg\sin\theta\end{bmatrix} +\begin{bmatrix} -B&0\\0&-C \end{bmatrix}\begin{bmatrix} \dot{x}\\\dot{\theta} \end{bmatrix} +\begin{bmatrix} u\\0 \end{bmatrix}\right) \end{eqnarray} \]


となる.数値解析する分にはこの程度の形で書けていればルンゲクッタでシミュレーションできる.

### 線形化

次に,現代制御を適用するために\(\dot{\theta},\theta\)が微小であるという近似をすると
\[ T=\begin{bmatrix} M+m&ml\\ ml&J+ml^2 \end{bmatrix} \]
であり,微分方程式は次のようになる.

\[ \begin{eqnarray} \begin{bmatrix} \ddot{x}\\\ddot{\theta} \end{bmatrix} &=&T^{-1}\left(\begin{bmatrix} 0&0\\ 0&mlg\end{bmatrix}\begin{bmatrix} {x}\\{\theta} \end{bmatrix} +\begin{bmatrix} -B&0\\0&-C \end{bmatrix}\begin{bmatrix} \dot{x}\\\dot{\theta} \end{bmatrix} +\begin{bmatrix} 1\\0 \end{bmatrix}u\right)\\ &=&\frac{1}{\det T}\left( \left[\begin{matrix}0 & - g l^{2} m^{2}\\0 & g l m \left(M + m\right)\end{matrix}\right]\begin{bmatrix} {x}\\{\theta} \end{bmatrix}\\+\left[\begin{matrix}- B \left(J + l^{2} m\right) & C l m\\B l m & - C \left(M + m\right)\end{matrix}\right]\begin{bmatrix} \dot{x}\\\dot{\theta} \end{bmatrix} +\left[\begin{matrix}J + l^{2} m\\- l m\end{matrix}\right]u \right) \end{eqnarray} \]
ここで状態量を(変数名かぶってますが)\(x=\begin{bmatrix}x&\dot{x}&\theta&\dot{\theta}\end{bmatrix}^T\)とすると
\[ \frac{d}{dt}x=\frac{1}{\det T} \begin{bmatrix} 0&\det T&0&0\\ 0&-B(J+ml^2)&-m^2l^2g&Cml\\ 0&0&0&\det T\\ 0&Blm&mgl(M+m)&-C(M+m) \end{bmatrix}x+ \frac{1}{\det T} \begin{bmatrix} 0\\J+ml^2\\0\\-ml \end{bmatrix}u \]
となるから,
\[ \begin{eqnarray} A&=&\frac{1}{\det T} \begin{bmatrix} 0&\det T&0&0\\ 0&-B(J+ml^2)&-m^2l^2g&Cml\\ 0&0&0&\det T\\ 0&Blm&mgl(M+m)&-C(M+m) \end{bmatrix}\\ B&=& \frac{1}{\det T} \begin{bmatrix} 0\\J+ml^2\\0\\-ml \end{bmatrix}\\ C&=& \begin{bmatrix} 1&0&0&0\\ 0&0&1&0\\ \end{bmatrix}\\ \end{eqnarray} \]
とおけば線形化した場合の状態方程式が書ける.

### オブザーバ,フィードバックゲインの決定

オブザーバ,フィードバックゲインは手計算で求めるとめんどくさそうなのでライブラリを使います.python-controlやmatlabにはplace関数というものがあって,それを用いるとフィードバックゲインなどを求めることができます.

なお,place関数は\(A+BK\)の\(K\)を決めてくれる関数です.したがって状態オブザーバのゲイン\(G\)を決める方法については,\(A-GC\)の転置をとった\(A^T-C^TG^T\)の\(G^T\)を求めることをすれば良いです.

コードはこんな感じです.

### シミュレーション

シミュレーションはProcessingで行いました.自分用の行列ライブラリ,ODEライブラリを作っておきたかったので読みにくいかもしれないです.

コードはここに上げてあります.
上が制御対象(RK4でシミュレーションした非線形微分方程式),下がオブザーバの出力を可視化したものです.初期値は0にしてあり,キーボードの矢印キーで外乱(入力)を与えてやれば動きます.
制御していない場合は発散し,制御している場合にはちゃんと倒立していることがわかります.オブザーバの出力もだいたい上のと同じ感じになってます.

## 感想

大変だったけどいい経験になりました.あと先輩に聞くと結構授業では端折っているところがあったりするらしいので,もっと勉強しないとなと思いました.

## 参考文献

[1] 吉川恒夫,井村順一,現代制御論,(2014),コロナ社
[2] http://www.robot.mach.mie-u.ac.jp/~nkato/class/sc/Invpend_eq3.pdf
[3] Python で任意極配置のフィードバックゲインを求める | org-技術, http://org-technology.com/posts/pole-placement.html
[4] python-controlを利用する際に直面したエラー - szmlb.net, http://szmlb.hatenablog.com/entry/2015/09/08/203643

2016年9月18日日曜日

パラレルリンクロボットの逆運動学のお話

期末試験や大会などでゴタゴタしていたためか,4ヶ月ぶりの更新です.

現在自分はパラレルリンクロボットというロボットを勉強がてら作っています.以下のような機体です.


よく見かけるロボットアーム(多関節ロボット)とはだいぶ様相が異なっています.

最下部の移動する部分が常に地面に対して水平になるような構造となっています.

ちまちま開発していたのですが,疲れてしまったので気分転換がてらブログを更新することにしました.

実機製作の話やプログラムの話は今後に回すとして,今回はモーターの角度と移動する部分の位置の関係式を導出する逆運動学の話を書くことにします.

1.イントロダクション

実際に機体を作ったとしても,プログラムが書けなければ動かすことが出来ません.
その際にはこのロボットの動きを数式で表す必要があります,

ただ,機構学をまだ履修しておらず,運動学についてはさっぱりわからないので,こちらのPDFをトレースする形になりました.
The Delta Parallel Robot: Kinematics Solutions
Robert L. Williams II, Ph.D
http://www.ohio.edu/people/williar4/html/pdf/DeltaKin.pdf
パラレルリンクロボットの運動学について,数式や図を用いて解説しているPDFです.
多分僕の記事はどこか必ず間違いがあるのでこのPDFを見れば間違いないかと思います.


加えて,今回GitHubの方にリポジトリを作成しました.計算の殆どはsympyに計算は投げてまして,その過程も載せてありますので参考になるかと思います.
パラレルリンクロボットの逆運動学問題の導出過程
PLR_Controller/InversePositionKinematics.ipynb at master · TonyMooori/PLR_Controller

どういう機体であるのかという詳細な説明を書くべきですが,面倒なので省略します.上記PDFの最初で扱われているデルタロボットがそれに当たると思うのですがちゃんとした本を見つけられなかったのでなんとも…….

2.各座標の定義

実際に計算を始める前に座標系や各部の名称を決めていきます.まず各部の名称です.
上のモーターや電装部品がある部分を「胴体」,モーターの取り付け部分を「肩」,その先の関節を「肘」,更にその先を「手首」,一番下の部分を「移動体」と名前をつけます.
また,肩から肘の部分を上腕,肘から手首の部分を下腕と名付けます.
※一般的な名前ではなく僕が勝手につけた名前です

また各腕は,反時計回りに0,1,2と番号を振ります.

座標系は次のように取ります.胴体の中央を原点としていますが,胴体は移動しないためこれがワールド座標系となります.
胴体中央部を原点(0,0,0)としてとり,z方向が上方向が正である点に注意してください.

次に,各部分の原点からの位置ベクトルの名称を定義します.iは添字(0,1,2)です.
\( \vec{A_i} \) …… 肩の位置ベクトル
\( \vec{B_i} \) …… 肘の位置ベクトル
\( \vec{C_i} \) …… 手首の位置ベクトル
\( \vec{D} \) …… 移動体の中央部分の位置ベクトル
\( \vec{e_i} \) …… \( \vec{A_i} \)方向の単位ベクトル.互いに120度向きが異なります.
\( \phi_i \) …… \( \vec{e_i} \) の角度.\( \frac{2 \pi}{3}i \).
\( \vec{e_z} \) …… z方向の単位ベクトル

各部の長さは次のように定義します.
\( A \) …… 原点から肩への距離( \( \|\vec{A_i}\| \) ) 
\( B \) …… 肩から肘への距離(上腕の長さ, \( \| \vec{A_i} - \vec{B_i} \| \) ) 
\( C \) …… 肘から手首への距離(下腕の長さ, \( \| \vec{B_i} - \vec{C_i} \| \) ) 
\( D \) …… 手首から移動体の中央部分への距離( \( \| \vec{C_i} - \vec{D_i} \| \) ) 
サーボモータの角度は次のように定義します.
\( \theta_i \) …… i番目の腕につけられたサーボモーターの角度.±90°とする.正なら上腕が胴体よりも下に行く.


3.逆運動学

ではまず逆運動学から考えていきます.補足ですが,
・サーボモーターを動かしたら移動体の位置がどうなるかを求めるのが順運動学
・移動体の位置を決めたときのサーボモーターの角度を求めるのが逆運動学
と考えて問題ないと思います.

ネットの記事や1で挙げたPDFなどにも書かれているように,パラレルリンクロボットでは逆運動学の方が順運動学よりも求めやすいそうです.
逆に,シリアルリンクロボット(多関節ロボット)では逆運動学のほうが順運動学よりも求めやすいとのこと.

なのでとりあえず逆運動学問題について考えていきます.
ただ,繰り返すようですが運動学を学んでいないので高校レベルのベクトルで考えていきますのでこの道のプロがやる方法とは異なるかもしれないです.

まず\( \vec{e_i} \)について考えると,肩は3つ均等に並べられていることから,
\[ e_i = \left[\begin{matrix}\cos{\left (\phi_{i} \right )}\\\sin{\left (\phi_{i} \right )}\\0\end{matrix}\right] \]
となります.ただし \( \phi_{i} = \frac{2 \pi}{3}i \) , \( i \) は0,1,2のいずれかです.さらに,\( \vec{A_i} \)は \( \vec{e_i} \) と同じ方向で長さが異なるだけなので,
\[ \vec{A_i} = A \vec{e_i} \]
です.スカラーのAとベクトルのAが紛らわしいので注意してください.

次に \( \vec{B_i} \) について考えます.\( \vec{B_i} \) は \( \vec{A_i} \) から伸びており,\( \vec{e_i} \) と \( \vec{e_z} \) 成分しかありません.
したがって,\( \vec{B_i} \) は次のように表されます.\[ \vec{B_i} = \vec{A_i} + B( \vec{e_i}cos(\theta) - \vec{e_z}sin(\theta) ) \]
次に,\( \vec{C_i} \) を考える前\( \vec{D} \)を定義します.逆運動学問題では移動体の位置を決めた上で角度\( \theta_i \) を求めるので,移動体の位置は,\[ \vec{D} = \left[\begin{matrix}x\\y\\z\end{matrix}\right] \]という値が予めわかった上で考えていきます.

これを使うと\( \vec{C_i} \)は移動体がねじれずに(z軸に対して回転することなく)移動するため, \[ \vec{C_i} = \vec{D} + D\vec{e_i} \]となります.

ここで,2で書いた定義,\( C = \| \vec{B_i} - \vec{C_i} \|  \)を用いることで\( \theta_i \)が求まります.この式は求めたい変数\( \theta_i \)ひとつだけなので非常に簡単というか,個人的には驚きです.
この式を両辺を二乗すると次のようになります.
\[ C^{2} = \left(B \sin{\left (\theta_{0} \right )} + z\right)^{2} + \left(- A \sin{\left (\phi_{0} \right )} - B \sin{\left (\phi_{0} \right )} \cos{\left (\theta_{0} \right )} + D \sin{\left (\phi_{0} \right )} + y\right)^{2} + \left(- A \cos{\left (\phi_{0} \right )} - B \cos{\left (\phi_{0} \right )} \cos{\left (\theta_{0} \right )} + D \cos{\left (\phi_{0} \right )} + x\right)^{2} \] 更に展開して, \[ C^{2} = A^{2} + 2 A B \cos{\left (\theta_{0} \right )} - 2 A D - 2 A x \cos{\left (\phi_{0} \right )} - 2 A y \sin{\left (\phi_{0} \right )} + B^{2} - 2 B D \cos{\left (\theta_{0} \right )} - 2 B x \cos{\left (\phi_{0} \right )} \cos{\left (\theta_{0} \right )} - 2 B y \sin{\left (\phi_{0} \right )} \cos{\left (\theta_{0} \right )} + 2 B z \sin{\left (\theta_{0} \right )} + D^{2} + 2 D x \cos{\left (\phi_{0} \right )} + 2 D y \sin{\left (\phi_{0} \right )} + x^{2} + y^{2} + z^{2} \] となります.この辺はsympyという数式処理ソフトに投げてるので手計算ではないです.
この式と2,3分ほどにらめっこすると,こういう式であることに気づきます.
\[ P + Q \sin{\left (\theta_{i} \right )} + R \cos{\left (\theta_{i} \right )} = 0 \] ただし,P,Q,Rは次のような値です. \[ \begin{eqnarray*} P &=& - A^{2} + 2 A D + 2 A x \cos{\left (\phi_{i} \right )} + 2 A y \sin{\left (\phi_{i} \right )} - B^{2} + C^{2} - D^{2} \\ &-& 2 D x \cos{\left (\phi_{i} \right )} - 2 D y \sin{\left (\phi_{i} \right )} - x^{2} - y^{2} - z^{2}\\ Q &=& - 2 B z \\ R &=& - 2 A B + 2 B D + 2 B x \cos{\left (\phi_{i} \right )} + 2 B y \sin{\left (\phi_{i} \right )} \end{eqnarray*} \]

この式から,\( \theta_i \) を求めます.\( t = tan(\frac{\theta_i}{2}) \)を置くことで,この式を2次方程式にすることができ,そこから\( \theta_i \)を求めることが出来ます.

こちらはsympyに投げてるので途中式を省略します.結果は次のようになります. \[ \begin{eqnarray*} \theta_i &=& - 2 \operatorname{atan}{\left (\frac{1}{P - R} \left(Q - \sqrt{- P^{2} + Q^{2} + R^{2}}\right) \right )} \\ \theta_i ' &=& - 2 \operatorname{atan}{\left (\frac{1}{P - R} \left(Q + \sqrt{- P^{2} + Q^{2} + R^{2}}\right) \right )} \end{eqnarray*} \]
2次方程式,と言った時点で気づいた方もいるかもしれませんが,解が2つ出てきます.これは肘が内側に来てる状態も含まれているためです.

因みに,適切な方を選ばなければこのような状態になります.
それぞれの腕に対して2パターンあるので,この条件が成立する状態がこのロボットでは合計8パターン存在します.

加えて,どちらが適切であるかどうかは角度の絶対値が小さい方,すなわち0付近である方を選択することでたいていうまくいきます(理論的な根拠があるわけではないです).
そもそも不適切な方の角度はサーボモーターの移動範囲外である事が多いため,このような状態にはならないはずですが,間違えるとサーボモーターを傷めるので注意してください.

また根号の中が負となる場合がありますが,その場合はこのロボットの移動範囲外であるということを表していると思って問題ないと思います.

4.シミュレーション

シミュレーションというか,可視化というか,ちゃんと数式があっているかの確認を行います.
プログラムは個々に貼り付けると長くなるのでGitHubのリポジトリの方においておきます.

PLR_Controller/IPK_Visualize.ipynb at masterTonyMooori/PLR_Controller

結果はこのようになります.

必要ならば各ベクトルの距離を計算して調べてみるとよいかと思います.


5.実機による実験

Arduino Microを用いて3つのサーボモータを制御します.
Amazonで購入した大きめのトルクの物を動かしています.

回路図はこんな感じです.サーボとマイコンを繋げただけです.
プログラムはこれもGitHubにあげてあります.
PLR_Controller/Arduino/trace_circle at masterTonyMooori/PLR_Controller
実際の動画です.とりあえずサンプルとして円を描くような軌跡で動かしています.
今回は以上ですが,もうしばらく続くかと思います.