私の環境(macOS HIghSierra, Fusion 360 2.03800, Ultimate, 学生版)ではメニューバーのファイル→スクリプトとアドインからスクリプトの編集を押すとSpyder IDEが起動し、Fusionと紐付けられたpython 3.5 が使用可能です。
ここから
こうする
このpythonの環境はシステム固有のpythonとは別の環境になっているので、numpy、opencv、scikit-learnなどなど、鉄板のpackageをimportしても使用できません。
今回は、このFusionに固有のpython環境に外部パッケージを追加し、使用してみるところまでをやってみます。
さて突然ですが、これは何でしょうか。
棒ですか?
いえ、これはなんと二自由度を有するアームロボットです。
根本、それから、中間の関節にモーターが入っています。
(実際にはアセンブリ機能で回転ジョイントを入れています。)
Fusionでpythonプログラムを動かすサンプルとして、このアームを作成し、動かします。
まずは、それぞれの関節の角度をプログラム上で決定し、Animateさせてみます。
サンプル1 回転ジョイントの角度をプログラムで指定する
import math
import adsk.core, adsk.fusion, adsk.cam, traceback
def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        
        des = adsk.fusion.Design.cast(app.activeProduct)
        root = des.rootComponent        
        
        arm = root.occurrences.itemByName('armtest v3:1')
        
        armComp = arm.component
        
        motorJoint1 = armComp.joints.itemByName('motor1')
        motorJoint2 = armComp.joints.itemByName('moter2')
        
        motor1 = motorJoint1.createForAssemblyContext(arm)
        motor2 = motorJoint2.createForAssemblyContext(arm)
        
        revJointMotion1 = motor1.jointMotion
        revJointMotion2 = motor2.jointMotion
        
        # Drive the joints.
        for k in range(0,2,1):
            for j in range(0,101,1):
                revJointMotion1.rotationValue = j*(math.pi/180.0)
                revJointMotion2.rotationValue = (90-j*2)* (math.pi/180.0)
                adsk.doEvents()
            if j>=100:               
                for j in reversed(range(0,101,1)):
                     revJointMotion1.rotationValue = j * (math.pi/180.0)
                     revJointMotion2.rotationValue = (90-j*2) * (math.pi/180.0)
                     adsk.doEvents()
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
}
このプログラムの動作を簡単に説明すると
まず、①現在開いているCADプロジェクトのファイルからオブジェクト(ボディ)を識別する情報を入力し②ボディの中に含まれるジョイントの情報を入力し、③ジョイントを回転させるためのインスタンスを生成します。その後、それぞれの軸のインスタンスを利用して回転角度をプログラムから操作します。
実行してみましょう。
わーお。動きました。でも単純な反復運動ですね。。。
せっかくプログラムで動かしているのだから、もっとランダム性を追加し、生き物のように動かしてみたいと思いませんか?
そういった要素に適しているのはパーリンノイズというノイズ生成アルゴリズムです。
パーリンノイズはCGエフェクトに使用されるプロシージャルテクスチャを生成するため、第一作目の映画Tronにも関わっているKen Perlinが開発しました。
Ref
The Book of Shaders: Noise
パーリンノイズを理解する | プログラミング | POSTD
pythonではpackageを使うだけでこのノイズ生成関数を使用することができます。
noise 1.2.2 : Python Package Index
今回は、このnoise packageをimportし、各軸の角度をパーリンノイズを利用してまるで生き物のような動きをさせてみます。
本題です。
なぜか(ふつうに?)Fusionに固有のpythonでは、pipをインストールしても使用できませんでした。pipが使用できるならば、 pip install noise で終わりです。
しかし、できないので手動でビルドしてインストールまで持っていきます。
まず、Fusionがどこにpythonの実体をおいているかを把握します。
私の環境では
/Users/USERNAME/Library/Application\ Support/Autodesk/webdeploy/shared/PYTHON/3.5.3c/MAC64/Python.framework/Versions/3.5/binにありました。
手順
1.先ほど示したURL or GitHubからnoiseのソースコード一式を入手する。
2.デスクトップ等に置いてみる。
3.pythonが実行できるターミナルを起動する。
4.noiseディレクトリ内部に移動。
その中で
sudo /Users/USERNAME/Library/Application\ Support/Autodesk/webdeploy/shared/PYTHON/3.5.3c/MAC64/Python.framework/Versions/3.5/bin/python setup.py build
次に
sudo /Users/USERNAME/Library/Application\ Support/Autodesk/webdeploy/shared/PYTHON/3.5.3c/MAC64/Python.framework/Versions/3.5/bin/python setup.py install
すると、
/Users/USERNAME/Library/Application\ Support/Autodesk/webdeploy/shared/PYTHON/3.5.3c/MAC64/Python.framework/Versions/3.5/lib/python3.5/site-packages/にnoise-1.2.2-py3.5-macosx-10.6-intel.egg
↑こんなようなのが生成されます。
これで良しです。
私は色々ハマってしまったので、
/Users/USERNAME/Library/Application\ Support/Autodesk/webdeploy/production/2a93884b46c5eedb87c1f008a9d77b138ef905db/Api/Python/packages/に入れなきゃいけないのではないかー。とかなんとかpipを使えるようにできないかー。
などやってしまったのですが、やり方がわかれば10分もかからずに終わるはずです。
それではおもむろにFusionを再起度しましょう。
そして、スクリプトとアドインからSpyderを起動しましょう。
先ほど示した、軸の角度をfor文で変えていくスクリプトにnoiseを追加すると
サンプル2 パーリンノイズでロボットを動かす
import math
import noise
import random
import adsk.core, adsk.fusion, adsk.cam, traceback
def run(context):
    ui = None
    try:    
        
        app = adsk.core.Application.get()
        ui  = app.userInterface
        
        des = adsk.fusion.Design.cast(app.activeProduct)
        root = des.rootComponent        
        
        arm = root.occurrences.itemByName('armtest v3:1')
        
        armComp = arm.component
        
        motorJoint1 = armComp.joints.itemByName('motor1')
        motorJoint2 = armComp.joints.itemByName('moter2')
        
        motor1 = motorJoint1.createForAssemblyContext(arm)
        motor2 = motorJoint2.createForAssemblyContext(arm)
        
        revJointMotion1 = motor1.jointMotion
        revJointMotion2 = motor2.jointMotion
        
        # Drive the joints.
        xt = random.random()*1000
        yt = 0
        for k in range(0,4,1):
            for j in range(0,101,1):
                i1 = noise.pnoise1(xt)
                i1 = (i1+1)*90
                i2 = noise.pnoise1(yt)
                i2 = (i2+1)*90
                xt += 0.01
                yt += 0.01
                revJointMotion1.rotationValue = i1*(math.pi/180.0)
                #revJointMotion2.rotationValue = (90-i2*2)* (math.pi/180.0)
                revJointMotion2.rotationValue = i2* (math.pi/180.0)
                adsk.doEvents()
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
上記のようにすると、パーリンノイズアルゴリズムで生成した乱数を基に各関節の角度を指定することができます。
これだけ簡単に3D Viewに反映させることができるなら、ものすごく役立ちますね。
pythonで運動学を解くプログラムを作って、Fusionで動かしてデバッグ→実機へ
みたいなのが便利そうです。
ほかのpackage、numpyなども追加することができています。
パッケージ同士の依存関係などあるので方法は少し複雑になりますが。



