Spr1の使い方/マニュアル

シーングラフのチュートリアルもそろそろリニューアルが必要なので,こちらに書き直します. 古いものは http://springhead.info/src/html/ja/TutorialVC.html にあります.

チュートリアル(Visual C++)

ビルドして実行してみる

まずは,慣れるために既存のプロジェクト(今回は Springhead/src/Samples/DynaHaptic)を実行してみます.

  1. ビルドを行う準備として以下のことを行ってください.
    • 環境変数 Springhead に Springhead をインストールしたディレクトリを 指定して下さい.
    • Windows2000ならば[マイコンピュータ]-[プロパティ]-[詳細]-[環境変数]-[新規]のダイアログに [変数名] Springhead [変数値] インストールしたディレクトリとしてください. DirectX8.1か9.0のSDKをインストールしてください.
  2. Springhead/src/Samples/DynaHaptic/DynaHaptic.dsw を Visual C++ で開いてビルドしてください.
    • ビルドが成功しない方は以下のことを確認してください. DirectX SDKのインクルードファイルとライブラリファイルのディレクトリの設定 [ツール]-[オプション]-[ディレクトリ]の「表示するディレクトリ(S)」を「インクルードファイル」に変え, DirectX SDKのインクルードファイルのディレクトリ(例:"C:\DXSDK\INCLUDE")が設定されているか確認してください. 設定されていなければ設定してください. また,検索の優先順位を上げるために「↑」のボタンを何度かクリックして, 一番上に来るようにしてください. ライブラリファイルについてもインクルードファイルと同様にパスの設定を行ってください (「表示するディレクトリ(S)」を「ライブラリファイル」に変更する).
    • アクティブプロジェクトの設定 [ビルド]-[アクティブな構成の設定]の 「プロジェクトの構成]を "Dynahaptic - Win32 MFC Debug (or Release)" にして下さい.
    • Springheadのページの「今朝のビルド」を見てください. ここにはその日の午前3時の時点でVSSにアップされているプロジェクトのビルド結果が表示されています. ここに載っていないプロジェクトのビルドは通らないということになりますので,過去のビルドが成功するバージョンのファイルを取得してきてください.
  3. 実行します. 実行したら,[ファイル]-[開く]でSpringhead/src/Samples/data/にあるデータファイル(Direct3D Xファイル)を適当にロードしてみてください. 実行時の主なキー操作は以下のようになっています.
    ↑:前進
    ↓:後退
    ←:左回転
    →:右回転
    S:上回転
    X:下回転
    Q:左平行移動
    W:右平行移動
    A:上平行移動
    Z:下平行移動
    R:視点リセット
    F:フルスクリーン
    G:画面をフルスクリーンから元に戻す
    C:SPIDARのグリップのキャリブレーション
    スペース:SPIDARに力を返すか返さないかのON-OFF
    M:マルチメディアタイマーの起動 (精度の高い力覚を提示するためには必要.Release版のみ)

データファイルを編集する

ボールを転がして箱に入れるという仮想世界の作成を通して, Xファイルの編集の方法を簡単に見ていきます

凸物体を作る

まず,仮想世界に必要なオブジェクトとして, 床,ジャンプ台となる三角柱,ボールをモデリングします. .x形式で保存することのできるモデリングソフトを使用して作ってください.

−作成例− floor.x
trianglePole.x
sphere.x

凹物体を作る

仮想世界に登場する物体にはさきほど作成したような直方体,球のような凸物体と, 箱のような凹物体があります. Springheadでは衝突判定に用いているアルゴリズムの性質上, 物体はすべて凸物体でなければなりません. そこで,箱を作るときには,底と四方の壁の5つの直方体を組み合わせて作成します. 作成例では,親フレーム Vessel の下に 子フレームとして VesselFront,Back,Left,Right,Bottom を配置しています. 各フレームにある FrameTransformMatrix は アフィン行列を転置した形で記述されており, 親フレームからのローカル変換を表しています. (VesselFront,Back,left,right はこのローカル変換が異なるだけで, その下に記述されている Mesh の部分は同じものを使用しています)

−作成例− 

床に三角柱を配置する

では実際に世界を作っていきます. まず,世界の一番の親フレームとして frTop を作成し, その子フレームに床を,そして床の子フレームとして三角柱を配置します.

−作成例− 

床を傾ける

次は,床を傾けます. さきほど,三角柱を床の子フレームとしているので, 床フレームの FrameTransformMatrix を編集するだけで, 三角柱ごと傾けることができます.

−作成例− 

ボールを配置する

ボールを frTop の子フレームとして配置します.

−作成例− 

ライトを追加する

ここまでの状態で実行しても, 暗くてあまり見えないのでライトを追加します. 具体的には,ライトの位置・姿勢を決めるためのフレームと そのライトの性質を示す Light8 を frTop の下に追加します.

−作成例− 

物理法則を追加する

ではいよいよ仮想世界に物理法則を追加します. 具体的には,

  • SolidContainer : 仮想物体の物理的性質
  • GravityEngine : 重力の制御
  • ContactEngine : 衝突判定の制御 を追加することになります. 現在作りたい世界の仕様を,
  • ボールが動く.
  • 重力がボールにはたらく.床にははたらかない.
  • ボールと床の間で衝突が起こり,衝突後ボールは跳ね返るが床は固定. とすると,SolidContainer および GravityEngine にはボールだけを登録し, PenaltyEngine には,ボールと床の衝突判定を行い衝突後はボールだけに反力を加えるという記述をします. なお,ContactEngine では, 親フレームとの衝突判定を行うように記述すれば, 再帰的に子フレームとの衝突判定も行うので, ボールと床との衝突判定を記述しておけば, 床の子フレームである三角柱との衝突判定も自動的に行います.

−作成例− 

フレームに物理マテリアルを追加

物体に摩擦力などのパラメータを追加したい場合、対象のフレームのMeshの下(Meshの{}内)に PhysicalMaterialを追加する。

  • 使用例(値はデフォルトであり、この記述を行わない場合物体にはこの値が入る)-
    Mesh{
    ・・・・・
     PhysicalMaterial{
      1.0f; #抗力のばね係数
      1.0f; #抗力のダンパ係数
      1.0f; #摩擦力のばね係数
      1.0f; #摩擦力のダンパ係数
      0.6f; #最大静止摩擦係数
      0.3f; #動摩擦係数
     }
    ・・・・・
    }

カメラを追加

このままでは画面に映る範囲が狭いので, 少しひいた(ズームアウトした)位置に視点を動かします. 視点の位置を設定するためには,frTop の下に Camera を追加します. Camera がない場合はデフォルトのカメラ位置になります. (デフォルトのカメラ設定については http://springhead.info/src/src/Graphics/GRCamera.cpp の GRCameraData::InitData() を参照) これまではカメラの設定をしていなかったので, デフォルトのカメラ位置になっていたということになります. カメラの位置の設定には,保存の機能を使うと便利です. 保存を行うと,そのときのカメラの設定をXファイルに書き出してくれます. よって,

実行 → キー操作により任意の視点位置に移動 → “名前を変えて”保存 → 保存したXファイルのカメラ設定を元のファイルにコピー

という手順で行うと楽です. 保存する際,ボールの位置など仮想世界の状態も一緒に保存してしまうので, 別の名前で保存する必要があります.

−作成例− 

床を広くしてボールを移動

次は,床を広くして,ボールももっと上から転がるように変更します. 床を広くするためには物体の頂点座標を管理している Mesh を変更します. ボールの位置の変更は FrameTransformMatrix の平行移動成分を変更して行います.

−作成例− 

箱を配置

ボールをキャッチする箱を配置します. 凹物体を作る で作成した箱フレームを追加し, ボールとの衝突判定を行うように Penalty も追加します.

−作成例− 

ボールの初期速度を大きくする

箱にボールが入らなかったので,ボールがもっと遠くへ飛んでいくように, Solid を編集して初期速度を大きくします.

−作成例− 

背景をつけ,テクスチャを貼る.

箱にボールが入るところまでできたので,少し見た目を向上させるために, 背景を付け,テクスチャも貼ります. 背景は,世界の後方に大きな平面オブジェクトを置いて作ることにします. テクスチャは,Material の中の TextureFilename で指定します.

−作成例− 

  • rollingBall.x これでひとまず rollingBall は完成です.

各オブジェクト位置の変更

つづいて rollingBall を改良して golf を作っていきます. まずは,世界をgolf用に変更します.

−作成例− 

  • golf1.x 行った作業は以下の通りです.
  • 床の変更
    • 傾きを水平にした
    • カップを作るために床を4分割した(そのうちの一つには傾斜をつけた)
    • ジャンプ台を低くした
  • 球の初期位置,初期速度の変更
  • 箱の位置の変更

力覚ポインタを作る

SPIDARのグリップ部分に対応するポインタを作ります. まずは,ポインタのフレームを作成します. そして,ポインタの物理(Solid,Penalty)を追加します. データファイル側の作業は以上で終わりです.

−作成例− 

  • golf.x あとはSPIDARの設定等,プログラムを編集する作業になります.

SPIDAR

もうしばらくおまちください....

新しくプロジェクトを作る

自分用に新しくプロジェクトを作ります. プログラムに変更を加えていく場合は, 新しいプロジェクトを作ることをお勧めします. 今回は,簡単な方法ということで既存のプロジェクト(Springhead/src/Samples/DynaHaptic)を コピーして名前だけ変更するという方法を取ることにします.

  1. VSSから $/Project/Springhead/src/Samples/DynaHaptic 以下を取得する.
  2. DynaHapticフォルダをコピーし, 適当なところ(Samplesの下でいいと思います)に貼り付ける.
  3. 貼り付けたフォルダ内のすべてのファイルの読み取り専用のチェックをはずし, ファイル名及び各ファイルの中に登場する "DynaHaptic" を すべて新しいプロジェクト名に置換する. .dsp, dsw, rc, sccファイルなんかもテキストエディタで開いて置換してください. -# ビルドして実行する. ビルドがうまくいかない方は,名前がすべて変更されているか, またはビルドして実行してみるのビルドのところを確認してください.

関節エンジン

Springheadは関節を持つ物体をFeatherstoneの方法を使ってシミュレーションします.

関節の作り方

関節を作るには,次のようにします.

JointEngine  {
 { soBody }			//	ルートの剛体,固定する場合は,Frameにする.
 JointHinge joUpper {	//	蝶番関節の定義.スライダーの場合は,JointSlider
  1.000000,0.000000,0.000000,		
  0.000000,1.000000,0.000000,		
  0.000000,0.000000,1.000000;;				//	親剛体のフレームから見たジョイントの向き
  0.800000;0.400000;0.000000;;				//	親剛体のフレームから見たジョイントの位置
  1.000000,0.000000,0.000000,
  0.000000,1.000000,0.000000,
  0.000000,0.000000,1.000000;;				//	子剛体のフレームから見たジョイントの向き
  -0.500000;0.000000;0.000000;;;			//	子剛体のフレームから見たジョイントの位置
  0.000000;0.000000;-0.143350;-0.715527;;	//	位置・速度・可動範囲(最小,最大)
  { soUpper }			//	joUpperの子剛体,joSideの親剛体
  JointHinge joSide {
   0.000000;0.000000;0.000000;;
   0.000000,0.000000,-1.000000, 0.000000,1.000000,0.000000, 1.000000,0.000000,0.000000;;
   0.000000;0.000000;0.000000;;
   0.000000,0.000000,-1.000000, 0.000000,1.000000,0.000000, 1.000000,0.000000,0.000000;;;
   0.000000;0.000000;0.106441;-0.336312;;
   { soSide }
   JointHinge joLower {
    1.000000,0.000000,0.000000,0.000000,1.000000,0.000000,0.000000,0.000000,1.000000;;
    0.000000;-0.400000;-0.200000;;
    1.000000,0.000000,0.000000,0.000000,1.000000,0.000000,0.000000,0.000000,1.000000;;
    0.000000;0.400000;0.000000;;;
    0.000000;0.000000;-0.613165;-2.209808;;
    { soLower }
   }
  }
 }
 //...(以下,右前足,左後ろ足,右後ろ足の記述が続きます.)
}
JointPid pidUpper {	//	joUpper用のPIDコントローラ
 0;					//	軸の番号いまのところ0〜3.ボールジョイントはたぶんうまく制御できない.
 0;					//	制御対象:0:位置, 1:速度
 1000.000000;			//	比例制御係数:PIDのP
 0.000000;				//	積分制御係数:PIDのI
 20.000000;			//	微分制御係数:PIDのD
 0.276041;				//	制御目標位置
 { joUpper }			//	対象関節
}
JointPid pidSide {
 0;0; 1000.000000; 0.000000; 20.000000; 0.100000;
 { joSide }
}
JointPid pidLower {
 0;0; 150.000000; 0.000000; 5.000000; -0.544807;
 { joLower }
}
  • SpringheadではRoy Fetherstone のアルゴリズムを使っているため,木構造のリンクを扱うことができます.輪をもつ機構は扱えません.どこかで切ってバネダンパでつないでください.

関節ノード

関節エンジンPHJointEngine はひとつのリンク機構(Articulated Body)をあらわします.2つ以上の機構を作りたい場合は,PHJointEngineを2つ以上書いてください.

関節エンジンPHJointEngineの中には,ひとつの剛体 or フレームとひとつの関節ノードを書きます. 関節ノードの中には,ひとつの剛体と複数の関節ノードをかけます.

以下関節ノードを列挙,説明します.

1自由度PHJointHinge, PHJointSlide
2自由度PHJointUniversal
3自由度PHJointBall
PHJointHinge
1自由度の回転関節=蝶番.関節フレームのZ軸が回転軸
PHJointSlider
1自由度の並進関節=スライダー.関節フレームのZ軸向きにスライドする.
PHJointUniversal
2自由度の回転関節=ユニバーサルジョイント. 親剛体側と関節フレームがX軸で,子剛体と関節フレームがY軸で結ばれる.
PHJointBall
3自由殿回転関節=ボールジョイント.関節軸は親剛体に固定. 軸の速度・加速度・トルクは,親剛体に取り付けられた関節軸を基準としている.
関節の姿勢はQuaterionで保持しています. 関節のフレームが2つあり,それぞれ親剛体,子剛体に取り付かれていて, 2つのフレームの関係(親から見た子)がQuaternionであらわされると考えてください.

関節の制御

関節軸を制御するノードとして,PHJointPidとPHJointBallPidがある.PHJointPidは関節の軸1つに対してPID制御をかけます.そのため,ボールジョイントの制御には使えません. PHJointBallPidは,ボールジョイントが目標姿勢に向かいように制御をかけます.

JointPid {
	0;			#軸の番号 JointUnivの場合,0と1両方に制御をかけなければならない.
	0;			#0:位置制御, 1:速度制御
	10.0;		//	PID の P 比例係数
	1.0;		//	PID の I 積分係数
	1000.0;		//	PID の D 微分係数
	1.57;		//	PIDの目標値
	{jnt01}
}
JointBallPid {
	100.0; 0.0; 100.0;		#PID
	0.0; 1.0; 0.0; 0.0;;	#目標姿勢(Quaternion w x y z)
	{jnt01}
}

制御目標に変動を与える.

関節を動かすのは,C++のプログラムで行うほうが便利ですが,ちょっと試すために周期的に動かす ためのエンジンを用意しました.

JointControlEngine{
   1.0; 1.0;           #   周期(s),    速度の倍率
   JointControl{
       0.0; 35.0;      60.0; 1.0;  
       #   始点(deg),終点(deg),位相(deg), 速度の倍率
       {joUpperPid}    #   適用するJointPidノードの名前
   }
   JointControl{
       -10.0; -40.0;   90.0; 1.0;
       {joLowerPid}
   }
}

これはジョイントの目標角度を変化させますので,Jointの入力を位置にしておく必要があります

サンプル

古い形式

改良を続けているため,フォーマットが複数あります. 古いXファイルは次のようになっているかもしれません. 一度ロードしてセーブすると新しい書き方に書き換わります.

JointEngine{
    {soBody}
    Joint joUpper{
        0;                      #関節の種類 0:蝶番, 1:スライド
        0.8; 0.0; 0.6;;         #親剛体から見た関節の位置
        1.0, 0.0, 0.0,          #親剛体から見た関節の向き(3x3行列)
        0.0, 1.0, 0.0,          
        0.0, 0.0, 1.0;;         
        0.0; 0.4; 0.0;;         #子剛体から見た関節の位置
        1.0, 0.0, 0.0,          #子剛体から見た関節の向き(3x3行列)
        0.0, 1.0, 0.0,
        0.0, 0.0, 1.0;;         
        #変位, 速度, 最大トルク, 可動範囲-, 可動範囲+ (可動範囲は未実装)
        0.0; 0.0; 20000000.0; 0.0; 0.0; 
        #入力の種類(0:トルク, 1:加速度, 2:速度, 3:変位), 入力値,P,I,D
        3; 0.1; 1000.0; 0.0; 20.0;      #位置入力の例
#       2; 2.0; 100.0; 0.01; 0.5;       #速度入力の例
#       3; 0.0; 0.0; 0.0; 0.0;
        {soSide}
        Joint joSide{             #左前足
            0;
            0.0; 0.0; 0.0;;
            0.0, 0.0, 1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 0.0;;
            0.0; 0.0; 0.0;;
            0.0, 0.0, 1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 0.0;;
            0.0; 0.0; 20000000.0; 0.0; 0.0; 
            3; 0.1; 1000.0; 0.0; 20.0;
            {soUpper}
            Joint joLower{
                0;
                0.0; -0.4; 0.2;;
                1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0;;
                0.0; 0.4; 0.0;;
                1.0, 0.0, 0.0,  0.0, 1.0, 0.0, 0.0, 0.0, 1.0;;
                0.0; 0.0; 20000000.0; 0.0; 0.0; 
                3; 0.0; 150.0; 0.0; 5.0;
                {soLower}
            }
        }
    }
以下,右前足,左後ろ足,右後ろ足の記述が続きます.

人体モデルについて

2重3重関節(ボールジョイント)

人体のモデルを作る場合,2,3重関節が必要になります.

%%現状では,Solidの指定なしの単関節を組み合わせて実現しています. 本来は質量0でなければなりませんが,現在のJointEngineでは質量0のリンクを作ると計算できなくなります.そのため,Jointの中に{Solidの名前}がない場合,適当な質量のSolidが自動的に割り当てられます.%%

将来的には,Jointの種類として,2重,3重関節を用意する予定です. 用意しました.

ジョイントのバネダンパ定数

ジョイントのバネダンパ定数は注意深く指定しないと発振などの問題が起こり, シミュレータを不正終了させてしまいます. その関節が支えている部分の質量を基準にして,バネダンパ定数を設定すると良いようです.

現在,佐藤研でも人体モデルとその関節の制御をするプログラムを開発中です. (できるだけ速やかに公開したいと考えています.)