「TSR」(2014/08/06 (水) 20:13:56) の最新版変更点
追加された行は緑色になります。
削除された行は赤色になります。
* TSR: Task Space Region
エンドエフェクタの拘束条件を記述する.
** TSR
3つのパートからなる.
$$ ^o T _w $$ : 世界座標系oからTSR座標系wへの座標変換
$$ ^w T _e $$ : TSR座標系wからエンドエフェクタeへの座標変換
$$ ^w B $$ : TSR座標系における拘束条件
$$ ^w B = \left[ \begin{array}{cc} x_{min} & x_{max} \\ y_{min} & y_{max} \\ z_{min} & z_{max} \\ \psi_{min} & \psi_{max} \\ \theta_{min} & \theta_{max} \\ \phi_{min} & \phi_{max} \\ \end{array} \right] $$
回転はRPYで表される.
(この後の検算の結果,おそらく元論文ではRPY = $$ RotZ(\phi) RotY(\theta) RotX(\psi) $$ と思われる.)
** TSRに対する距離の定義
コンフィグレーション空間 $$ q_s $$ に対応するエンドエフェクタの座標を $$ ^o T _s $$とする.
このときのTSR座標系を $$ ^o T _{s'} $$ とすると,次のように逆算できる.
$$ {^o T _{s'}} = {^o T _s} ( {^w T _e} ) ^ {-1} $$
初期のTSR座標系との差分は以下のように計算される.
$$ {^w T _{s'}} = ( { ^o T _w } )^{-1} { ^o T _{s'} } $$
これを拘束 $$ ^w B $$ に合わせた形になおすと,
$$ ^w d = \left[ \begin{array}{c} ^w t _{s'} \\ \arctan ( {^w R _{s'}}(3, 2) / {^w R _{s'}}(3, 3) ) \\ -\arcsin {^w R _{s'}}(3, 1) \\ \arctan ( {^w R _{s'}}(2, 1) / {^w R _{s'}}(1, 1) ) \\ \end{array} \right] $$
拘束に対する距離に直すと,各要素は以下のようになる.
$$ \Delta x _i = \left\{ \begin{array}{cc} {^w d _i} - {^w B}(i, 1) & \mbox{if}({^w d _i} < {^w B}(i, 1)) \\ {^w d _i} - {^w B}(i, 2) & \mbox{if}({^w d _i} > {^w B}(i, 2)) \\ 0 & \mbox{otherwise} \end{array} \right. $$
すなわちTSRの距離は $$ || \Delta x || $$ となる.
*** 回転角度の検算
$$ RotZ(\phi) RotY(\theta) RotX(\psi) = \left[ \begin{array}{ccc} C_{\phi} C_{\theta} & -S_{\phi} C_{\psi} + C_{\phi} S_{\theta} S_{\psi} & S_{\phi} S_{\psi} + C_{\phi} S_{\theta} C_{\psi} \\ S_{\phi} C_{\theta} & C_{\phi} C_{\psi} + S_{\phi} S_{\theta} S_{\psi} & -C_{\phi} S_{\psi} + S_{\phi} S_{\theta} C_{\psi} \\ -S_{\theta} & C_{\theta} S_{\psi} & C_{\theta} C_{\psi}\end{array} \right] $$
ここから,
$$ \psi = \arctan (C_{\theta} S_{\psi}) / (C_{\theta} C_{\psi}) = \arctan ( {^w R _{s'}}(3, 2) / {^w R _{s'}}(3, 3) ) $$
$$ \theta = -\arcsin (-S_{\theta}) = -\arcsin {^w R _{s'}}(3, 1) $$
$$ \phi = \arctan (S_{\phi} C_{\theta}) / (C_{\phi} C_{\theta}) = \arctan ( {^w R _{s'}}(2, 1) / {^w R _{s'}}(1, 1) ) $$
** 拘束多様体への投影
距離を定義できたので,距離を零とするような$$q$$の修正を考える.
ヤコビアンの擬似逆行列を用いて反復的に求めることができる.
$$ \Delta q _{error} = J^T (J J^t) ^{-1} \Delta x $$
$$ q \leftarrow (q - \Delta q_{error}) $$
** TSR Chain
その名の通りTSRを連結したもの.
TSRにおけるエンドエフェクタ座標が次のTSR座標に,
二番目以降のTSR座標がそれ以前のTSRを連結した結果になる.
ここで,仮想関節$$ ^w T _{sample} $$をTSRに付加することを考える.
$$ C_i = [{^o T _w}, {^w T _e}, {^w B}, {^w T _{sample}}] $$
という4つの構成要素から成り立つものをi番目のTSRとすると,
$$ {^o T _w} $$はそれ以前のすべてのTSRの$$ ^w T _{sample} $$の影響を受ける.
つまり,
$$ C_i . {^o T _w} = (C_{i-1} . {^o T _w}) (C_{i-1} . {^w T _{sample}}) (C_{i-1} . {^w T _e}) $$
各TSRの仮想関節$$ ^w T _{sample} $$を決定するような仮想関節角度列cをTSR Chainに持たせる.
** TSR Chain に対する距離の定義
コンフィグレーション空間 $$ q_s $$ に対応するエンドエフェクタの座標を $$ ^o T _s $$とする.
TSR Chain自体をひとつの仮想マニピュレータとして捉え,終端の座標を$$ ^o T _s $$を目標としてIKを使って解く.
その時の両座標の差分が距離として定義される.
* CBiRRT2: Constrained Bidirectional RRT
TSRによる拘束条件を用いて計算可能な拡張型[[RRT]].
CBiRRT2(q_start, q_goal) {
tree_a.Init(q_init); // 初期値q_initをツリーのルートに登録する
tree_b.Init(q_goal); // 目標値q_goalを別のツリーのルートに登録する
while (TimeRemaining()) { // 規定の時間内に計算が終わらなければ失敗
tree_goal = GetBackwardTree(tree_a, tree_b); // ゴールから伸びている方の木を選ぶ
if (tree_goal.empty() || // ゴールから伸びている方の木が空か,
random(0, 1) < P_SAMPLE) { // 確率P_SAMPLEでTSRから直接サンプリング
AddRoot(tree_goal);
} else { // 通常の探索を行う
q_rand = RandomConfig(); // ランダムに目標値を入れる
// ツリーAの探索
q_a_near = NearestNeighbor(tree_a, q_rand);
q_a_rearch = ConstrainedExtend(tree_a, q_a_near, q_rand);
// ツリーBの探索
q_b_near = NearestNeighbor(tree_b, q_rand);
q_b_rearch = ConstrainedExtend(tree_b, q_b_near, q_rand);
if (q_a_reach == q_b_reach) { // 十分近いところに到達したならば
path = ExtractPath(tree_a, q_a_reach, tree_b, q_b_reach); // 2つの木を接続
return ShortenPath(path); // パスを最適化したものが解
} else {
Swap(tree_a, tree_b); // 2つのツリーを入れ替える
}
}
}
return NULL;
}
ConstrainedExtend(tree, q_near, q_target) {
q_s = q_near;
q_s_old = q_near;
while (true) {
if (q_target == q_s) { // 目標に到達している場合
return q_s;
} else if (norm(q_target - q_s) > norm(q_s_old - q_target)) { // 発散する方向に動いている場合
return q_s_old;
}
q_s_old = q_s;
q_s = q_s +
min(DELTA_Q, norm(q_target - q_s) * (q_target - q_s) / norm(q_target - q_s) // ターゲット方向に動く
c = GetConstraintValues(tree, q_s_old); // q_s_oldのときの仮想関節角度列c.同時に格納されているので取り出すのみで良い.
(q_s, c) = ConstrainConfig(q_s_old, q_s, c, NULL); // コンフィグ空間から拘束多様体への投影を行う
if (!q_s.empty()) {
tree.AddVertex(q_s, c);
tree.AddEdge(q_s_old, q_s);
} else {
return q_s_old;
}
}
}
ここまでは細かい差異はあるが基本的にBiRRTと同じ.
直接サンプリングを行う場合
AddRoot(tree) {
for (i = 1 to m) { // mはTSR Chainの数
cc = GetTSRChainsForManipulator(i); // ccはTSR Chain
(t_o_to_targ, c) = SampleFromTSRChains(cc); // 直接サンプリング
targets.AddTarget(t_o_to_targ, i);
}
(q_s, c) = GetInitialGuess(); // 初期値,元論文ではロボットの初期姿勢と零ベクトルと記述されている
(q_s, c) = ConstrainConfig(NULL, q_s, c, targets); // コンフィグ空間から拘束多様体への投影を行う
if (!q_s.empty()) {
tree.AddVertex(q_s, c);
}
}
コンフィグレーションが拘束条件を満たすように毎度修正を行う.
// @brief コンフィグレーションが拘束条件を満たすように,物理拘束を考慮し拘束多様体へ投影する
// @param q_s_old 一手前の関節角度列
// @param q_s 関節角度列
// @param c TSR Chainの仮想関節角度列
// @param targets 目標座標のリスト
ConstrainConfig(q_s_old, q_s, c, targets) {
check_dist = false;
if (targets.empty()) { // ConstrainedExtendから呼ばれた場合
check_dist = true;
for (i = 1 to m) { // mはTSR Chainの数
cc = GetTSRChainsForManipulator(i); // ccはTSR Chain
t_o_to_s = GetEndEffectorTransform(q_s, i); // q_sのときのエンドエフェクタの姿勢
(t_o_to_targ, c) = GetClosestTransform(cc, t_o_to_s, c); // 目標座標をTSR Chainから修正する
targets.AddTarget(t_o_to_targ, i);
}
}
q_s = UpdatePhysicalConstraintDOF(q_s, c); // 物理拘束によりq_sを修正する
q_s = ProjectConfig(q_s, targets); // 多様体への投影を行う
if (q_s.empty() || // 拘束多様体への投影が出来なかった場合か,
(check_dist && // ConstrainedExtendから呼ばれ,
norm(q_s - q_s_old) > 2 * DELTA_Q) { // かつ一手前の値から2*DELTA_Q以上離れた時
return NULL; // 失敗とする.
}
return (q_s, c);
}
うまくつながったら最後はパスを最適化して返す.
ShortenPath(path) {
while (TimeRemaining()) { // 規定の時間内粘る
tree_shortcut = {};
i = (int)(random(1, path.size() - 1));
j = (int)(random(i, path.size()));
q_reach = ConstrainedExtend(tree_shortcut, path[i], path[j]); // iからjまで直通可能か調べる
if (q_reach == path[j] && // jまで到達できて
tree_shortcut.size() < (j - i)) { // かつ元々のパスよりも短ければ
path = {path[0 ... i], tree_shortcut, path[j + 1 ...]}; // i-j間を直通したものに置き換える
}
}
return path;
}
** 参考文献
Dmitry Berenson, Siddhartha Srinivasa, James Kuffner.
"Task Space Regions: A Framework for Pose-Constrained Manipulation Planning",
International Journal of Robotics Research (IJRR), Vol. 30, No. 12, October, 2011, pp. 1435 - 1460.
http://www.ri.cmu.edu/pub_files/2011/10/dmitry_ijrr10-1.pdf
* TSR: Task Space Region
エンドエフェクタの拘束条件を記述する.
** TSR
3つのパートからなる.
$$ ^o T _w $$ : 世界座標系oからTSR座標系wへの座標変換
$$ ^w T _e $$ : TSR座標系wからエンドエフェクタeへの座標変換
$$ ^w B $$ : TSR座標系における拘束条件
$$ ^w B = \left[ \begin{array}{cc} x_{min} & x_{max} \\ y_{min} & y_{max} \\ z_{min} & z_{max} \\ \psi_{min} & \psi_{max} \\ \theta_{min} & \theta_{max} \\ \phi_{min} & \phi_{max} \\ \end{array} \right] $$
回転はRPYで表される.
(この後の検算の結果,おそらく元論文ではRPY = $$ RotZ(\phi) RotY(\theta) RotX(\psi) $$ と思われる.)
** TSRに対する距離の定義
コンフィグレーション空間 $$ q_s $$ に対応するエンドエフェクタの座標を $$ ^o T _s $$とする.
このときのTSR座標系を $$ ^o T _{s'} $$ とすると,次のように逆算できる.
$$ {^o T _{s'}} = {^o T _s} ( {^w T _e} ) ^ {-1} $$
初期のTSR座標系との差分は以下のように計算される.
$$ {^w T _{s'}} = ( { ^o T _w } )^{-1} { ^o T _{s'} } $$
これを拘束 $$ ^w B $$ に合わせた形になおすと,
$$ ^w d = \left[ \begin{array}{c} ^w t _{s'} \\ \arctan ( {^w R _{s'}}(3, 2) / {^w R _{s'}}(3, 3) ) \\ -\arcsin {^w R _{s'}}(3, 1) \\ \arctan ( {^w R _{s'}}(2, 1) / {^w R _{s'}}(1, 1) ) \\ \end{array} \right] $$
拘束に対する距離に直すと,各要素は以下のようになる.
$$ \Delta x _i = \left\{ \begin{array}{cc} {^w d _i} - {^w B}(i, 1) & \mbox{if}({^w d _i} < {^w B}(i, 1)) \\ {^w d _i} - {^w B}(i, 2) & \mbox{if}({^w d _i} > {^w B}(i, 2)) \\ 0 & \mbox{otherwise} \end{array} \right. $$
すなわちTSRの距離は $$ || \Delta x || $$ となる.
*** 回転角度の検算
$$ RotZ(\phi) RotY(\theta) RotX(\psi) = \left[ \begin{array}{ccc} C_{\phi} C_{\theta} & -S_{\phi} C_{\psi} + C_{\phi} S_{\theta} S_{\psi} & S_{\phi} S_{\psi} + C_{\phi} S_{\theta} C_{\psi} \\ S_{\phi} C_{\theta} & C_{\phi} C_{\psi} + S_{\phi} S_{\theta} S_{\psi} & -C_{\phi} S_{\psi} + S_{\phi} S_{\theta} C_{\psi} \\ -S_{\theta} & C_{\theta} S_{\psi} & C_{\theta} C_{\psi}\end{array} \right] $$
ここから,
$$ \psi = \arctan (C_{\theta} S_{\psi}) / (C_{\theta} C_{\psi}) = \arctan ( {^w R _{s'}}(3, 2) / {^w R _{s'}}(3, 3) ) $$
$$ \theta = -\arcsin (-S_{\theta}) = -\arcsin {^w R _{s'}}(3, 1) $$
$$ \phi = \arctan (S_{\phi} C_{\theta}) / (C_{\phi} C_{\theta}) = \arctan ( {^w R _{s'}}(2, 1) / {^w R _{s'}}(1, 1) ) $$
** 拘束多様体への投影
距離を定義できたので,距離を零とするような$$q$$の修正を考える.
ヤコビアンの擬似逆行列を用いて反復的に求めることができる.
$$ \Delta q _{error} = J^T (J J^t) ^{-1} \Delta x $$
$$ q \leftarrow (q - \Delta q_{error}) $$
** TSR Chain
その名の通りTSRを連結したもの.
TSRにおけるエンドエフェクタ座標が次のTSR座標に,
二番目以降のTSR座標がそれ以前のTSRを連結した結果になる.
ここで,仮想関節$$ ^w T _{sample} $$をTSRに付加することを考える.
$$ C_i = [{^o T _w}, {^w T _e}, {^w B}, {^w T _{sample}}] $$
という4つの構成要素から成り立つものをi番目のTSRとすると,
$$ {^o T _w} $$はそれ以前のすべてのTSRの$$ ^w T _{sample} $$の影響を受ける.
つまり,
$$ C_i . {^o T _w} = (C_{i-1} . {^o T _w}) (C_{i-1} . {^w T _{sample}}) (C_{i-1} . {^w T _e}) $$
各TSRの仮想関節$$ ^w T _{sample} $$を決定するような仮想関節角度列cをTSR Chainに持たせる.
** TSR Chain に対する距離の定義
コンフィグレーション空間 $$ q_s $$ に対応するエンドエフェクタの座標を $$ ^o T _s $$とする.
TSR Chain自体をひとつの仮想マニピュレータとして捉え,終端の座標を$$ ^o T _s $$を目標としてIKを使って解く.
その時の両座標の差分が距離として定義される.
* CBiRRT2: Constrained Bidirectional RRT
TSRによる拘束条件を用いて計算可能な拡張型[[RRT]].
CBiRRT2(q_start, q_goal) {
tree_a.Init(q_init); // 初期値q_initをツリーのルートに登録する
tree_b.Init(q_goal); // 目標値q_goalを別のツリーのルートに登録する
while (TimeRemaining()) { // 規定の時間内に計算が終わらなければ失敗
tree_goal = GetBackwardTree(tree_a, tree_b); // ゴールから伸びている方の木を選ぶ
if (tree_goal.empty() || // ゴールから伸びている方の木が空か,
random(0, 1) < P_SAMPLE) { // 確率P_SAMPLEでTSRから直接サンプリング
AddRoot(tree_goal);
} else { // 通常の探索を行う
q_rand = RandomConfig(); // ランダムに目標値を入れる
// ツリーAの探索
q_a_near = NearestNeighbor(tree_a, q_rand);
q_a_rearch = ConstrainedExtend(tree_a, q_a_near, q_rand);
// ツリーBの探索
q_b_near = NearestNeighbor(tree_b, q_rand);
q_b_rearch = ConstrainedExtend(tree_b, q_b_near, q_rand);
if (q_a_reach == q_b_reach) { // 十分近いところに到達したならば
path = ExtractPath(tree_a, q_a_reach, tree_b, q_b_reach); // 2つの木を接続
return ShortenPath(path); // パスを最適化したものが解
} else {
Swap(tree_a, tree_b); // 2つのツリーを入れ替える
}
}
}
return NULL;
}
ConstrainedExtend(tree, q_near, q_target) {
q_s = q_near;
q_s_old = q_near;
while (true) {
if (q_target == q_s) { // 目標に到達している場合
return q_s;
} else if (norm(q_target - q_s) > norm(q_s_old - q_target)) { // 発散する方向に動いている場合
return q_s_old;
}
q_s_old = q_s;
q_s = q_s +
min(DELTA_Q, norm(q_target - q_s) * (q_target - q_s) / norm(q_target - q_s) // ターゲット方向に動く
c = GetConstraintValues(tree, q_s_old); // q_s_oldのときの仮想関節角度列c.同時に格納されているので取り出すのみで良い.
(q_s, c) = ConstrainConfig(q_s_old, q_s, c, NULL); // コンフィグ空間から拘束多様体への投影を行う
if (!q_s.empty()) {
tree.AddVertex(q_s, c);
tree.AddEdge(q_s_old, q_s);
} else {
return q_s_old;
}
}
}
ここまでは細かい差異はあるが基本的にBiRRTと同じ.
直接サンプリングを行う場合
AddRoot(tree) {
for (i = 1 to m) { // mはTSR Chainの数
cc = GetTSRChainsForManipulator(i); // ccはTSR Chain
(t_o_to_targ, c) = SampleFromTSRChains(cc); // 直接サンプリング
targets.AddTarget(t_o_to_targ, i);
}
(q_s, c) = GetInitialGuess(); // 初期値,元論文ではロボットの初期姿勢と零ベクトルと記述されている
(q_s, c) = ConstrainConfig(NULL, q_s, c, targets); // コンフィグ空間から拘束多様体への投影を行う
if (!q_s.empty()) {
tree.AddVertex(q_s, c);
}
}
コンフィグレーションが拘束条件を満たすように毎度修正を行う.
// @brief コンフィグレーションが拘束条件を満たすように,物理拘束を考慮し拘束多様体へ投影する
// @param q_s_old 一手前の関節角度列
// @param q_s 関節角度列
// @param c TSR Chainの仮想関節角度列
// @param targets 目標座標のリスト
ConstrainConfig(q_s_old, q_s, c, targets) {
check_dist = false;
if (targets.empty()) { // ConstrainedExtendから呼ばれた場合
check_dist = true;
for (i = 1 to m) { // mはTSR Chainの数
cc = GetTSRChainsForManipulator(i); // ccはTSR Chain
t_o_to_s = GetEndEffectorTransform(q_s, i); // q_sのときのエンドエフェクタの姿勢
(t_o_to_targ, c) = GetClosestTransform(cc, t_o_to_s, c); // 目標座標をTSR Chainから修正する
targets.AddTarget(t_o_to_targ, i);
}
}
q_s = UpdatePhysicalConstraintDOF(q_s, c); // 物理拘束によりq_sを修正する
q_s = ProjectConfig(q_s, targets); // 多様体への投影を行う
if (q_s.empty() || // 拘束多様体への投影が出来なかった場合か,
(check_dist && // ConstrainedExtendから呼ばれ,
norm(q_s - q_s_old) > 2 * DELTA_Q) { // かつ一手前の値から2*DELTA_Q以上離れた時
return NULL; // 失敗とする.
}
return (q_s, c);
}
うまくつながったら最後はパスを最適化して返す.
ShortenPath(path) {
while (TimeRemaining()) { // 規定の時間内粘る
tree_shortcut = {};
i = (int)(random(1, path.size() - 1));
j = (int)(random(i, path.size()));
q_reach = ConstrainedExtend(tree_shortcut, path[i], path[j]); // iからjまで直通可能か調べる
if (q_reach == path[j] && // jまで到達できて
tree_shortcut.size() < (j - i)) { // かつ元々のパスよりも短ければ
path = {path[0 ... i], tree_shortcut, path[j + 1 ...]}; // i-j間を直通したものに置き換える
}
}
return path;
}
** 参考文献
Dmitry Berenson, Siddhartha Srinivasa, James Kuffner.
"Task Space Regions: A Framework for Pose-Constrained Manipulation Planning",
International Journal of Robotics Research (IJRR), Vol. 30, No. 12, October, 2011, pp. 1435 - 1460.
http://www.ri.cmu.edu/pub_files/2011/10/dmitry_ijrr10-1.pdf
表示オプション
横に並べて表示:
変化行の前後のみ表示: