Pythonスクリプトの記述

基本事項

Choreonoid上で実行されるPythonスクリプトは、Choreonoid内蔵のPythonインタプリタで実行されます。そこでは動作中のChoreonoid上のアイテムやビューといったオブジェクトに直接アクセスすることができます。

スクリプトではまず、使用する機能に対応するcnoidパッケージのモジュールをインポートします。

from cnoid.Util import *
from cnoid.Base import *
from cnoid.Body import *
from cnoid.BodyPlugin import *

各モジュールの概要については Pythonスクリプト機能の概要 の「Pythonバインディング」を参照してください。Choreonoid上で実行する場合、cnoidパッケージのパスはあらかじめモジュール検索パスに設定されているため、そのままインポートすることができます。

PythonバインディングのクラスやメソッドはC++ライブラリのものにほぼ対応しており、基本的にC++と同じ名前で利用できます。またC++で getX / setX となっているアクセサの一部は、Pythonではプロパティとして参照・代入できるようになっています(例: body.numJointsitem.name )。

アイテムの操作

Choreonoidの操作を自動化する上で基本となるのは、アイテムの操作です。

アイテムツリーの最上位にあるルートアイテムは以下で取得できます。

from cnoid.Base import *

rootItem = RootItem.instance

新たなアイテムを生成してツリーに配置するには、アイテムクラスのオブジェクトを生成して addChildItem で親アイテムに追加します。

from cnoid.BodyPlugin import *

worldItem = WorldItem()
RootItem.instance.addChildItem(worldItem)

既存のアイテムを取得するには findItem を使用します。アイテムの名前(階層をたどる場合はパス)で検索する方法と、アイテムの型で検索する方法があります。

# 名前・パスによる検索
robotItem = RootItem.instance.findItem("World/SR1")

# 型による検索(最初に見つかったアイテムを返します)
simulatorItem = RootItem.instance.findItem(SimulatorItem)

アイテムの選択状態やチェック状態も以下のように操作できます。

simulatorItem.setSelected(True)
robotItem.setChecked(True)

ファイルに対応するアイテムでは load でファイルを読み込むことができます。ファイルパスには ${SHARE} (Choreonoidのshareディレクトリ)、 ${HOME} (ユーザのホームディレクトリ)、 ${PROJECT_DIR} (プロジェクトファイルのディレクトリ)といったパス変数を使用できます。

robotItem = BodyItem()
robotItem.load("${SHARE}/model/SR1/SR1.body")

プロジェクト構築の例

以下は、SR1モデルの歩行シミュレーションのプロジェクトをスクリプトで構築して、シミュレーションを開始する例です。Choreonoidのサンプルに含まれるスクリプト sample/python/SR1Walk.py の内容となります。

from cnoid.Util import *
from cnoid.Base import *
from cnoid.Body import *
from cnoid.BodyPlugin import *
import math

worldItem = WorldItem()
RootItem.instance.addChildItem(worldItem)

robotItem = BodyItem()
robotItem.load("${SHARE}/model/SR1/SR1.body")

robot = robotItem.body
robot.rootLink.setTranslation([0.0, 0.0, 0.7135])

q = [  0.0, -2.1, 0.0,   4.5, -2.4, 0.0,
      10.0, -0.2, 0.0, -90.0,  0.0, 0.0, 0.0,
       0.0, -2.1, 0.0,   4.5, -2.4, 0.0,
      10.0, -0.2, 0.0, -90.0,  0.0, 0.0, 0.0,
       0.0,  0.0, 0.0  ]

for i in range(robot.numJoints):
    robot.joint(i).q = math.radians(q[i])

robot.calcForwardKinematics()
robotItem.storeInitialState()

controllerItem = SimpleControllerItem()
controllerItem.setController("SR1WalkPatternController")
robotItem.addChildItem(controllerItem)
robotItem.setChecked(True)
worldItem.addChildItem(robotItem)

floorItem = BodyItem()
floorItem.load("${SHARE}/model/misc/floor.body")
worldItem.addChildItem(floorItem)

simulatorItem = AISTSimulatorItem()
simulatorItem.setTimeStep(0.002)
simulatorItem.setActiveControlTimeRangeMode(True)
worldItem.addChildItem(simulatorItem)
simulatorItem.setSelected(True)

simulatorItem.startSimulation()

このスクリプトでは以下の処理を行っています。

  1. ワールドアイテムを生成してルートアイテムの下に配置する

  2. ボディアイテムを生成してSR1のモデルファイルを読み込む

  3. ボディアイテムからボディモデル(Bodyオブジェクト)を取得し、ルートリンクの位置と各関節の関節角を設定して、順運動学計算( calcForwardKinematics )で全身の姿勢を更新する

  4. storeInitialState で現在の姿勢をシミュレーションの初期状態として記憶させる

  5. 歩行パターンを再生するシンプルコントローラを設定したコントローラアイテムをロボットの子アイテムとして配置する

  6. 床モデルとAISTシミュレータアイテムを配置する

  7. startSimulation でシミュレーションを開始する

このように、GUI上で行うプロジェクト構築の操作は、おおよそスクリプトでも記述することが可能です。

シミュレーションとの連携

読み込み済みのプロジェクトに対してシミュレーションの実行を制御することもできます。以下はサンプル sample/python/StartSimulationAndQuitWhenFinished.py の内容で、シミュレーションを開始し、シミュレーションが終了したらChoreonoid自体を終了するスクリプトです。

from cnoid.Base import *
from cnoid.BodyPlugin import *

def onSimulationFinished(isForced):
    App.exit()

simulatorItem = RootItem.instance.findItem(SimulatorItem)
if not simulatorItem:
    App.exit()

simulatorItem.sigSimulationFinished.connect(onSimulationFinished)
simulatorItem.setRealtimeSyncMode(SimulatorItem.NonRealtimeSync)
simulatorItem.setSelected()
simulatorItem.startSimulation()

ここではシミュレータアイテムの持つシグナル sigSimulationFinished に関数を接続することで、シミュレーション終了時の処理を記述しています。このように、C++のAPIと同様に、シグナルに対して関数を接続してイベント駆動の処理を記述することができます。

このスクリプトを後述の コマンドラインからのスクリプト実行 と組み合わせることで、シミュレーションをバッチ的に実行することが可能となります。また、シミュレーションの開始・終了と連動してスクリプトを実行したい場合は、 Pythonシミュレーションスクリプト も利用できます。

Qtのクラスの利用

cnoid.QtCorecnoid.QtGuicnoid.QtWidgets の各モジュールを用いると、Qtの主要なクラスをスクリプトから利用できます。以下はサンプル sample/python/TimerSample.py の内容で、QTimerを用いて1秒ごとに処理を実行する例です。

from cnoid.QtCore import *

class TimerSample:
    def __init__(self):
        self.timer = QTimer()
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.doSomething)
        self.timer.start()
        self.counter = 0

    def doSomething(self):
        print("do something %d" % self.counter)
        self.counter += 1
        if self.counter == 10:
            self.timer.stop()

timerSample = TimerSample()

このほか、QtWidgetsのウィジェット類を用いて、ボタンやダイアログ等からなる独自のGUIをスクリプトで構築することも可能です。

クラスや関数の調べ方

Pythonスクリプトの記述に使用できるクラスや関数については、Pythonコンソール上で各モジュールをインポートし、Python標準の dir() 関数や help() 関数で確認することができます。

>>> import cnoid.Body
>>> dir(cnoid.Body)
>>> help(cnoid.Body.Body)

Pythonコンソール の入力補完(Tabキー)を用いて、クラスの持つメソッドをその場で確認しながら試すこともできます。

サンプルスクリプト

Choreonoidのソースの sample/python/ ディレクトリに、Pythonスクリプトのサンプルが格納されています。スクリプトを記述する際の参考にしてください。以下はその一部です。

ファイル

内容

SR1Walk.py

SR1モデルの歩行シミュレーションのプロジェクトを構築して実行します。

StartSimulation.py

読み込み済みプロジェクトのシミュレーションを開始します。

StartSimulationAndQuitWhenFinished.py

シミュレーションを開始し、終了したらChoreonoidを終了します。

KinematicsTest.py

ボディモデルに対する運動学計算のテストを行います。

BodyShaker.py

選択されたボディモデルを振動させます。独自ツールバーの追加やシグナル、タイマーの利用例にもなっています。

TimerSample.py

QTimerを用いた周期処理の例です。