MV-9001:シンプルな振子のチュートリアル

本チュートリアルでは、Msolve MotionSolve Python APIを用いてシンプルな自由度1の機構をモデル化する方法を学びます。

本チュートリアルをIPython notebookとして実施している場合、SHIFT-ENTERをクリックすることにより、各コードセルを内部的に実行することが可能です。Pythonコードの出力(存在する場合)が表示され、実行すると次のセルにジャンプします。

下の画像は、これから構築しようとしているシステムをグラフィカルに表したものです。


図 1.

剛体は質量0のワイヤーで吊り下げられており、ヒンジジョイントを介して地面に接続されています。システムに作用する唯一の力は、負の垂直方向に沿って指示された重力です。シミュレーションでは、初期の静止位置からパートが揺れる様子を示しています。ジョイントには摩擦力がなく、また、その部分に作用するエネルギー散逸力のいずれのタイプもないため、ボールはフルスイングごとに180度の角変位に達します。

ジョイントの反力を調べます。

msolveモジュールの読み込み

msolveモジュールを読み込むには、以下のコマンドを実行します:
In [1]: from msolve import*

上記のコマンドを実行するには、msolveモジュールがコンピュータのパスになければなりません。上記が成功したと仮定すると、msolveの名称は現在のネームスペースにインポートされています。これにより、msolveで定義されているすべてのクラスと関数にアクセスできるようになり、シンプルな振子の作成を開始することができます。

モデルの作成

振子の機構を作成するにはまず、モデルを作成する必要があります。モデルは、すべてのエンティティの親として機能するコンテナに他なりません。モデルクラスは、MotionSolveの出力ファイル名を指定するためのキーワード引数を取ります。名称pendulumを使用することが可能です。

このコマンドを実行します:
In [2]: model = Model(output='pendulum') 
MotionSolveは、ルート名pendulumで一連の出力ファイル(.mrf.abf.h3d)を生成します。

単位と重力の追加

モデルを作成した後、単位、重力や地面などのエンティティを追加することができます。ほとんどのエンティティはデフォルトのプロパティを有しています。たとえば、引数を指定せずにソルバーの単位セットを作成する場合、基本的にはSI単位を作成していることになります。

  1. このコマンドを実行します:
    In [3]: units= Units () 
  2. mmksでモデル化したいので、単位のlengthプロパティを変更し、"MILLIMETERS"の値を割り当てます。簡単に直接割り当てることができます。
    In [4]: units.length="MILLIMETER"
  3. 同様に、Accgravクラスを使って重力加速度場を作ることができます。
    In [5]: gravity=Accgrav(kgrav=-9810)

    Accgravの作成結果は、gravityという変数に格納されます。それが等号の左に出てくる名称です。これは現在のネームスペース内のPython変数であり、スコープ内のどこでも使用できます。

msolveのクラス名ではCapWordsの規約を使用し、Pythonのヘルプシステムを使用して各msolveクラス、その使用方法、プロパティについて学ぶことができます。例として以下の手順を実行してください。

  1. Accgravクラスと対話するには、クラス名を入力引数として、help ( )関数を呼び出します。
    In [6]: help(Accgrav)
    Help on class Accgrav in module msolve.Model:
    class Accgrav(Force)
     |  Accgrav defines the acceleration due to gravity along the global X, Y, and Z directions.
     |
     |  Method resolution order:
     |      Accgrav
     |      Force
     |      msolve.Base.SolverObject
     |      __builtin__.object
     |
     |  Methods defined here:
     |
     |  sendToSolver(self)
     |      Send the object to the solver
     |
     |  setSolverValue(self, name, value)
     |      Set the property 'name' to 'value' between simulations
     |
     |  ----------------------------------------------------------------------
     |  Data descriptors defined here:
     |
     |  igrav
     |      Gravity in the global X direction
     |      Type=Double, Optional, Default=0
     |      Modifiable during simulation
     |
     |  jgrav
     |      Gravity in the global Y direction
     |      Type=Double, Optional, Default=0
     |      Modifiable during simulation
     |
     |  kgrav
     |      Gravity in the global Z direction
     |      Type=Double, Optional, Default=0
     |      Modifiable during simulation
    
    ヘルプ関数が呼び出されると、多くの情報が表示されます。情報の中で最も重要なのは、クラスとそのプロパティの記述です。例えば、データ記述子は以下のコードで定義されています:
    igrav
        Gravity in the global X direction
        Type=Double, Optional, Default=0
        Modifiable during simulation

    msolveでは、クラスのインスタンスを作成すると必ずオブジェクトが返されます。これにより、オブジェクトの名称、この場合は重力を使用して参照する機能が得られます。 重力とその特性はモデル内のどこでも使用できます。例えば、モデル構築の段階、もしくはMotionSolveシミュレーションの間でプロパティを変更することができます。このアプローチの利点については、本チュートリアル内で後程説明します。

    一般的なルールとして、作成されたオブジェクトをローカル変数を使って保存するのは有益です。この時点で、モデルの作成に進むことができます。

  2. 地面のパートを作成し、Partクラスを使用して、地面のBoolean属性を'True’に指定します。
    In [7]: ground=Part(ground=True) 

ポイントの定義

MBSの中には、ポイントを使って定義されているモデルもあります。ポイントは、x、y、zの位置と便利な手法を擁する特別な補助オブジェクトです。これらはメカニズムを定義する強力な方法であり、モデル内でX、Y、Z量が必要な場所であればどこでも使用できます(例えば、パーツの位置決めやマーカーの原点の位置決めなど)。

この例では、ポイントを使用して、3次元空間内の様々なオブジェクト(マーカーなど)の位置を特定します。マーカーの位置や向きを定義するときにポイントを使用できます。

全体座標系原点にポイントを作成するには、引数を含めないでください。Pointクラスで引数を持たないことは、x,y,z座標がデフォルトの0,0,0に設定されていることを意味します。以下のコマンドを実行します:
In [8]: p0=Point() 

マーカーの作成

このポイントを利用して、地面マーカーの原点を特定することができます。マーカーは、空間内の幾何学的なポイントと、その点から出ている互いに直交する3つの座標軸のセットによって定義されます。

マーカークラスでは、プロパティqpは、ボディ参照フレーム内のマーカー原点の位置に対応します。ボディとして地面を使用しているため、qpは全体参照フレーム内のマーカーの位置です。zp, xpメソッドを使用して、Z軸とX軸を方向付けします。

  1. 以下のコマンドで、 2つの軸のそれぞれの方向付けに用いられる空間内のポイントを与えると、3番目は直交右手座標系として自動的に計算されます。
    In [9]: ground_mar=Marker (body=ground, qp=p0, zp=[0,100,0], xp=[100,0,0]) 
  2. これで、振子ボディを作成することができます。質量が2kgで、対角項のみに慣性特性のある剛体パートです。
    In [10]: part=Part(mass=2.0, ip=[1e3,1e3,1e3]) 
  3. オプション: コードセルにpartとTABキーを入力すると、partに適用されるすべての機能とプロパティがドロップダウンリストとして表示されます。

パート作成の検証

各エンティティは、インタラクティブに検証することが可能です。これは、正しいモデルだけがシミュレーションされるようにするための方法です。上のコードセルで作成したパートには質量プロパティがありますが、重心マーカーを有しません。したがって、これは正しくありません。以下を行うことができます:

  1. validate関数を呼び出してパートを検証します:
    In [11]: part.validate() 
    Part/2
    ERROR:: Mass is specified but cm is not specified.
    ERROR:: There are no markers on this part.
    Out[11]:
    False
    エラーメッセージは、パートの重心(cm)が欠落していることを告げています。
  2. この問題を修正するには、(100, 0, 0)の位置にパートの重心マーカーを作成します。このポイントは、振子パートの位置を表しています。
    In [12]: p1 = Point(100,0,0)
    # create the marker as the part.cm 
    # note that the '.' operator allows us to define a the 'cm' property of the part object. 
    # the marker will be positioned at (100,0,0), the X axis is pointing towards the point (200, 0,0) 
    # and the z axis points to (200, 100, 0)
     
    part.cm = Marker(body=part, qp=p1, zp=[200,100,0], xp=[200,0,0]) 
    

形状オブジェクトの作成

アニメーションのために、形状オブジェクト、ここでは球体を作成することができます。ドキュメントによると、球体には重心マーカーとその半径が必要とされます。

このコマンドを実行します:
In [13]: sphere=Sphere (cm=part.cm, radius=20) 

ジョイントとリクエストの追加

球体は、適切に拘束する必要があります。そうしないと落下します。振子は、ヒンジ点p0の回転ジョイントを使用してモデル化することができます。これにより、振子ボディの変形不可能で地面への剛性無限大かつ質量0の接続を効果的に捉えることが可能です。回転ジョイントは、振子の球体上と地面上の2つのマーカーを接続し、これらのマーカーを3次元空間内に適切に配置する必要があります。

回転ジョイントの要件は、iとjのマーカーが一致していることと、そのZ軸が適切に配置されていることです。

リクエストも作成します。リクエストはMotionSolveの出力チャンネルを定義し、MotionSolveの出力ファイルに書き込まれ、HyperGraphによるプロッティングや信号処理に使用されます。リクエストは、ランタイム式、組み込み関数(MOTION、FORCE、FIELDなど)、またはユーザーが作成した関数を使用して定義することができます。

この場合、定義済みの"FORCE"メソッドを使用して力のリクエストを作成し、MotionSolveランタイム関数AXを使用して角変位を追跡する別のリクエストを作成することができます。AXは、2つのマーカー間の角変位をラジアン単位で測定します。

  1. 以下のコマンドを実行します:
    In [14]: joint = Joint(type="REVOLUTE", i=ground_mar, j=Marker(body=part, qp=p0, xp=[100,0,0], zp=[0,100,0]))
    force_req = Request(type="FORCE", i=joint.i, j=joint.j, rm=joint.i)
    angle_req = Request(f1="RTOD*AX({I}, {J})".format(I=joint.i.id, J=joint.j.id),                    
                        f2="RTOD*AY({I}, {J})".format(I=joint.i.id, J=joint.j.id),
                        f3="RTOD*AZ({I}, {J})".format(I=joint.i.id, J=joint.j.id)) 
  2. Sforceを呼び出して、ボールが動くときの接触力を計算します。入力関数はMotionSolve式である必要があり、マーカーjのz軸は力がかかる方向を定義します。
    In [15]: input_function =
    "IMPACT(DZ({I}, {J}, {J}),VZ({I}, {J}, {J}),{G},{K},{E},{C},{D})"
    .
    format( I=marker_i.id,J=marker_j.id, K=5e9, G=0.00, E=1.0, C=0.8e5, D=0.0 )
    contact_force = Sforce(i = marker_i.id, j = marker_j.id,
    type=
    "TRANSLATION"
    , function = input_function) 
    

シミュレーションの実行

この時点で、過渡解析を実行する準備が整っています。シミュレート手法はMBSモデル上で呼び出されます。モデルを構成する各エンティティに、検証プロセスが実行されます。これは、正しいモデルのみがシミュレートされていることを確認するために必要なステップです。シミュレートコマンドは、オプションのフラグreturnResultsをTrueに設定して呼び出すことができます。これは以下のコードで示すように、シミュレーションの結果をさらにポスト処理を行うために実行コンテナに保存します。

  1. 以下のコマンドを実行します:
    In [16]: run=model.simulate (type="TRANSIENT", returnResults=True, end=2, dtout=.01)
  2. 直接代入で値を変更することで、パートの質量プロパティを簡単に変更することができます。
    In [17]: part.mass= 12
  3. この時点で、前回の解析の最後から別のシミュレーションを実行することができます。これは単に、新しいシミュレートコマンドを発行し、終了時間を4秒に指定するだけで行えます。なお、このシミュレーションは新しいパートの質量で行われているため、その影響をジョイントの反力で見ることができるはずです。
    In [18]: run=model.simulate (type="TRANSIENT", returnResults=True, end=4, dtout=.01)
  4. 次のコマンドで、実行コンテナからforce_reqを抽出しています。時間変化する結果を抽出するのに便利なデータ構造を持つことが目的です。
    In [19]: force=run.getObject (force_req)
  5. 力のオブジェクトを使用して、縦方向の反力Fxをプロットすることができます。そのために、IPythonノートブックで利用可能なmatplotlibモジュールを使用しています。プロットはインラインで表示されます。時間=2秒での質量変化が反力の大きさに影響を与え、350Nのピークを発生させていることがわかります。
    In [20]: %matplotlib inline
    from matplotlibimport
    pyplot pyplot.plot (force.times, force.getComponent (2), label=force.labels[2])


    図 2. Out[20]: [<matplotlib.lines.Line2D at 0x7142860>]
  6. 同様に、回転角をプロットすることができます。角変位リクエストでは一般的なランタイム式が使われていたため、AY(角リクエストのマーカjのY軸周りの角度)に対応する正しい成分を取得する必要があります。
    In [21]: angle = run.getObject(angle_req)
    pyplot.plot (angle.times, angle.getComponent(2), label="angle [deg]")


    図 3. Out[21]: [<matplotlib.lines.Line2D at 0x72c8fd0>]
    角変位は単純な調和関数であり、接合部に粘性摩擦などの散逸力がないため、振子は180度に達します。振動の周波数はこれらの式に支配されていることにご留意ください。(1) T = 2 π L g (2) f = 1 T
    上のプロットから分かるように、質量は約1.5Hzの周波数で揺れています。以下のgenerateOutput()関数は、HyperViewHyperView Playerで可視化するためのMotionSolve *.pltファイルとH3Dアニメーションファイルを生成します。
    In [22]: model.generateOutput()
以上、簡単な振子モデルの作成、過渡シミュレーションの実行、および結果のプロットを行う方法について学習しました。