コマンドラインからのスクリプト実行

起動時のスクリプト実行

Choreonoidの起動時に、コマンドラインで指定したPythonスクリプトを実行させることができます。拡張子が .py のファイルをコマンドラインで指定すると、そのスクリプトが起動時に実行されます。

choreonoid sample/python/SR1Walk.py

上記の例では、起動したChoreonoid上でSR1Walk.pyが実行され、スクリプトによって構築されたプロジェクトのシミュレーションが開始されます。

--python (短縮形 -p )オプションで明示的にスクリプトファイルを指定することもできます。

choreonoid --python script.py

プロジェクトファイルとの併用

プロジェクトファイルと同時に指定することも可能です。

choreonoid project.cnoid script.py

この場合、プロジェクトの読み込み後にスクリプトが実行されるため、プロジェクトに含まれるアイテムを操作するスクリプトを実行できます。

バッチ実行と終了の制御

スクリプトで処理を実行させる場合、その処理が終わったらChoreonoidも終了してほしい、ということがよくあります。特にシェルスクリプト等から自動実行する場合は、Choreonoidが終了しないと次の処理に進めません。

ここで注意が必要なのは、 Choreonoidは起動時スクリプトの実行が終わっても自動的には終了しない ということです。ChoreonoidはGUIアプリケーションであり、イベントループを回し続けるからです。通常の対話的な使用ではユーザがウィンドウを閉じることで終了しますが、自動実行ではそれを行う人がいません。

--batchオプション

この用途のために --batch オプションが用意されています。

choreonoid --batch project.cnoid script.py

このオプションを指定すると、Choreonoidは 起動時に指定された処理を全て実行し、自動実行中の処理が無くなった時点で終了します 。上記の例であれば、プロジェクトを読み込み、スクリプトを実行し、スクリプトが開始したシミュレーションが終わったところで自動的に終了します。

--batch はあわせて非対話モード( --non-interactive )も有効にします。これによりメッセージビューの出力が標準出力にも出力され、応答する人がいないと処理が止まってしまう確認ダイアログも表示されなくなります。

ウィンドウの表示・非表示とは独立したオプションなので、ウィンドウを表示したままバッチ実行することもできます。ウィンドウが不要であれば --headless と組み合わせてください。

choreonoid --headless --batch project.cnoid script.py

自動実行中の処理として扱われるもの

--batch が終了を待つ「自動実行中の処理」として、以下のものが自動的に扱われます。

  • 起動時オプションの処理(プロジェクトの読み込み、起動時スクリプトの実行など)

  • シミュレーションの実行

  • アニメーションの再生

  • バックグラウンドモードで実行中のPythonスクリプト

シミュレーションについては、シミュレータアイテムが実行中に関連アイテムを「連続更新状態」にすることを利用して検出しているため、スクリプト側で特別な記述をする必要はありません。

シミュレーションを実行して結果を保存する例

以下は、プロジェクトのシミュレーションを実行し、その結果を動作データのファイルとして保存するスクリプトの例です。

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

rootItem = RootItem.instance
simulatorItem = rootItem.findItem(SimulatorItem)

def onSimulationFinished(isForced):
    motionItem = rootItem.findItem(BodyMotionItem)
    if motionItem.motion.save("result.seq"):
        print("The simulation result has been saved.")
    else:
        MessageView.instance.putln(
            "Failed to save the simulation result.", MessageView.MessageType.Error)

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

これを次のように実行します。

choreonoid --headless --batch project.cnoid script.py

このスクリプトには終了のための記述が一切無いことに注目してください。シミュレーションの終了は sigSimulationFinished で受け取って結果を保存し、Choreonoid自体の終了は --batch に任せています。

setRealtimeSyncModeNonRealtimeSync を指定しているのは、実時間との同期を行わずに可能な限り速くシミュレーションを進めるためです。バッチ実行では通常このほうが望ましいでしょう。

注釈

上記のスクリプトは、シミュレーションの結果が記録されることを前提としています。シミュレータアイテムの記録モードが「記録しない」に設定されている場合は BodyMotionItem が生成されないため、プロジェクト側の設定を確認してください。

イベント駆動で書く

上の例のように、スクリプトでは 処理の完了をシグナルで受け取るイベント駆動の形で記述してください 。以下のように完了をポーリングで待つ書き方をしてはいけません。

# このような書き方をしてはいけません
simulatorItem.startSimulation()
while simulatorItem.isRunning():
    time.sleep(0.001)
# ここで結果を取り出しても正しい結果は得られない

起動時スクリプトはChoreonoidのイベントループの中から呼び出されています。スクリプトが制御を返さない限りイベント処理が進まないため、上記のようなループを書くと、シミュレーション結果の記録やシミュレーション終了時の処理そのものが実行されません。結果として、取り出したデータが空になるなどの問題が起こります。

必要な処理はシグナルに接続した関数の中に書き、スクリプト本体は速やかに制御を返すようにしてください。

独自の処理を待たせる

タイマーによる周期処理など、Choreonoidが自動的には検出できない処理を行う場合、そのままでは処理の途中でChoreonoidが終了してしまいます。この場合は App.beginOngoingProcess で処理の実行を宣言してください。

from cnoid.Base import *
from cnoid.QtCore import *

process = App.beginOngoingProcess("periodic processing of the script")
counter = 0

def onTimeout():
    global counter
    counter += 1
    print("count = %d" % counter)
    if counter == 5:
        timer.stop()
        process.finish()

timer = QTimer()
timer.setInterval(200)
timer.timeout.connect(onTimeout)
timer.start()

beginOngoingProcess に渡す文字列は、その処理の内容を表す説明です。これは後述の診断メッセージで使用されます。宣言した処理は、返されたハンドルの finish を呼ぶか、ハンドルが解放された時点で終了したものとして扱われます。

終了コード

Choreonoidの終了コードは、 エラーメッセージが一つでも出力されていれば1、そうでなければ0 となります。これは --batch の有無に関わらず有効です。したがって、シェルスクリプトからは通常のコマンドと同様に成否を判定できます。

ここで判定の対象となるのはエラーメッセージだけで、 警告メッセージは終了コードに影響しません 。Choreonoidのメッセージは以下のように使い分けられています。

  • エラー … 処理が失敗し、目的が達成されなかったことを表します。例えばファイルの読み込みに失敗した場合などです。メッセージビューには「エラー:」という接頭辞が付いて赤色で表示されます。

  • 警告 … 処理自体は続行できたものの、注意すべき点があることを表します。例えば設定の一部が想定と異なっていて既定値で代替した場合などです。メッセージビューには「警告:」という接頭辞が付きます。

したがって、警告が出ていても処理が最後まで完了していれば終了コードは0になります。警告も検出したい場合は、標準出力に出力されるメッセージを解析してください。

#!/bin/bash

choreonoid --headless --batch project.cnoid script.py

if [ $? -ne 0 ]; then
    echo "The simulation failed."
    exit 1
fi

スクリプト側から終了コードを明示したい場合や、処理の途中で終了させたい場合は、 App.exit を使用します。

from cnoid.Base import *

App.exit(2)

注釈

App.exit はイベントループに終了を要求するもので、その場でプロセスを終了させるわけではありません。呼び出した後もスクリプトの実行は続くので、 スクリプトの最後で呼ぶようにしてください

終了しない場合

--batch を指定してもChoreonoidが終了しない場合は、終わらない処理が残っています。端末で Ctrl+C を入力すると、何を待っていたのかが出力されます。

バッチモードは以下の処理の終了を待っていました:アイテムの連続更新

よくある原因は、シミュレータアイテムの時間範囲の設定が「無制限」になっていることです。この設定ではシミュレーションが自動的には終了しないため、バッチ実行には向きません。プロジェクト側で時間範囲を指定するか、「コントローラが有効な範囲」に設定してください。

上記の App.beginOngoingProcess で宣言した処理を終了させ忘れている場合も同様です。

ウィンドウを表示しないヘッドレス実行

--headless オプションを使用すると、Choreonoidはメインウィンドウを表示せずに起動します(このモードの基本については ウィンドウを表示しない起動モード を参照してください)。このモードではメッセージビューへの出力が標準出力に出力されるため、スクリプトによる出力やエラーメッセージ等の実行状況は端末上で確認できます。スクリプトの実行と組み合わせることで、Choreonoidをコマンドラインツールのように利用することが可能となります。

choreonoid --headless project.cnoid script.py

このようなヘッドレス実行は、例えば以下のような用途で活用できます。

  • シミュレーションのバッチ実行

プロジェクトを読み込んでシミュレーションを実行し、結果をログや動作データのファイルとして保存して終了する、という一連の処理を全て自動で行うことができます。GUIの描画を行わない分、実行のオーバーヘッドも小さくなります。

  • 多数の条件による繰り返し実行

シェルスクリプト等からChoreonoidを繰り返し起動することで、モデルやコントローラのパラメータを変えながら多数のシミュレーションを自動実行し、結果をまとめて収集するといったことができます。実行条件の受け渡しには環境変数などが利用できます。

  • モデルやプロジェクトを対象とした処理の自動化

モデルファイルを読み込んで内容の検査や変換、運動学計算等を行う処理をスクリプト化し、通常のコマンドのように実行することができます。

  • GUIのないリモート環境での実行

計算サーバやCI環境など、ウィンドウシステムのない環境でシミュレーションを実行できます。

ウィンドウを表示しない起動モード で述べているように、ウィンドウシステムが存在しない環境では --headless を指定しなくても自動的にこのモードに切り替わります。その場合でも、GLVisionSimulatorによる視覚センサのシミュレーションは、EGLを用いたレンダリングによってウィンドウシステム無しで実行することができ、GPUによるハードウェアアクセラレーションも有効となります。カメラ画像や距離画像を使用するシミュレーションも、GUI無しの環境でそのまま実行できるということです。

ヘッドレス実行にあたっては以下の点にも留意してください。

  • シーンビュー等のGUI上の描画は行われません。GUIの描画を伴う処理(シーンビューの描画結果の取得等)をウィンドウを表示せずに自動化したい場合は、仮想ディスプレイを利用する方法があります。これについては 仮想ディスプレイによるウィンドウを表示しないGUI実行 を参照してください。

  • --headless は非対話モード( --non-interactive )も有効にします。確認ダイアログは表示されず、対応する処理は既定の動作で進みます。

  • あわせて以下のオプションも活用できます。

  • --batch … 自動実行される処理が全て終わった時点でChoreonoidを終了します。( バッチ実行と終了の制御 参照)

  • --start-simulation … 起動時にシミュレーションを自動で開始します。

例えば以下のコマンドは、ウィンドウを表示せずにプロジェクトのシミュレーションを実行し、シミュレーションが終了したところでChoreonoidも終了します。スクリプトは必要ありません。

choreonoid --headless --batch --start-simulation project.cnoid

スクリプトをアイテムとして読み込むオプション

--python-item オプションを使用すると、スクリプトは起動時に実行されるのではなく、Pythonスクリプトアイテムとしてアイテムツリーに読み込まれます。

choreonoid --python-item script.py

読み込まれたアイテムにはチェックが入った状態となっているので、スクリプトバーのボタンを押すことで実行できます。また、アイテムツリービュー上でアイテムを右クリックして表示されるコンテキストメニューからも、「実行」を選択することで実行できます。同メニューの「停止」で実行中のスクリプトを停止することもできます。詳細は Pythonスクリプトアイテム を参照してください。