pythonスクリプトpythonインターフェース

Chorenoid、graspPluginでpythonインターフェースが用意されている機能は、pythonスクリプトとしてchoreonoid上で実行可能となります。
ここでは、pythonスクリプトのサンプルと使用方法、pythonインターフェース作成方法を説明します。

準備

Choreonoidのビルド時のCmakeで以下の項目をONにしてビルドする必要あります。
- BUILD_PYTHON_PLUGIN
- ENABLE_PYTHON

Pythonスクリプトの使用方法

Choreonoid起動時にPythonスクリプトファイルを読込む方法

コマンドラインでChorenoidを起動するときにオプションで実行するPythonスクリプトを指定します。

  $ choreonoid [project-file] -p <pythonscriptfile >

Pythonスクリプトファイルにモデルファイルのロード等すべての処理を記述している場合は、上記の[project-file]部分
は不要です。
例として以下のコマンドを実行してみてください。
 $ cd <chorenoidのパス>
 $ bin/chorenoid -p ext/graspPlugin/Grasp/python/script/grasp_example1.py

grasp_exmaple1.pyは、PA10とahiruを読み込みahiruを把持計画する処理が記述されています。

次は、プロジェクトファイルを読み込み、その後Pythonスクリプトを実行する例です。

 $ cd <chorenoidのパス>
 $ bin/chorenoid ext/graspPlugin/Grasp/python/script/grasp_example.cnoid \
   -p ext/graspPlugin/Grasp/python/script/grasp_example2.py

grasp_example2.pyは、PA10がahiruを把持計画する処理が記述されています(PA10、ahiruの読込処理は含まれていません)。

プロジェクトに追加する方法

まず、実行方法を説明します。
プロジェクトに使用するPythonスクリプト情報を保存したファイルとして、
ext/graspPlugin/Grasp/python/script/grasp_example_withpython.cnoid
があります。
これをコレオノイドで起動します。

 $ bin/chorenoid ext/graspPlugin/Grasp/python/script/grasp_example_wihtpython.cnoid

スクリプト実行ボタンを押すとPA10がahiruを把持します。
pythonscript.png

プロジェクトにPythonスクリプト情報を追加する方法を説明します。
 ・まず、もととなるプロジェクトファイル(cnoid)を読み込む、もしくは、まっさらな状態からモデル等をロードしておきます。
 ・メニューの[ファイル]->[読み込み]->[Pythonスクリプト]をクリックすると、ファイル選択ダイアログが表示されるので、対象となるPythonファイルを選択します。
 ・アイテムタブに対象ファイル名のアイテムが追加されます。対象アイテムにチェックが入っていることを確認してください。
 チェックが入っていないとスクリプトが実行されません。
 ・メニューの[ファイル]->[名前を付けてプロジェクトを保存]で保存します。

上記の例では、スクリプト実行タイミングがスクリプト実行ボタンをクリックした時ですが、以下の手順でプロジェクトが読み込まれたとき
に実行するようにできます。
 ・アイテムタブの対象Pythonスクリプトアイテムを選択します。
 ・アイテムタブの下にプロパティタブがあり、その中の「読み込み時に実行」をTrueに変更します。

サンプルPythonスクリプトの説明

- grasp_exmaple1.py
PA10とahiruを読み込み、把持計画する処理

 from cnoid.Util import *
 from cnoid.Base import *
 from cnoid.Body import *
 from cnoid.BodyPlugin import *
 from cnoid.GraspPlugin import *
 
 # choreonoidのディレクトリを取得
 topdir = executableTopDirectory() 
 
 # choreonoidのrootItemを取得
 rootItem = RootItem.instance() 
 
 ## load robot model
 # BodyItemを作成
 robotItem = BodyItem()
 # PA10を読み込む
 robotItem.load(topdir + "/ext/graspPlugin/RobotModels/PA10/PA10.yaml")
 # PA10をrootItemに追加(アイテムタブに表示されるようになる)
 rootItem.addChildItem(robotItem)
 # PA10のアイテムをチェックする(シーンタブにPA10が表示される)
 ItemTreeView.instance().checkItem(robotItem)
 
 ## load object model
 # BodyItemを作成
 objItem = BodyItem()
 # ahiruを読み込む
 objItem.load(topdir + "/ext/graspPlugin/Samples/Object/ahiruLowHrp.wrl")
 # ahiruを移動する
 objItem.body().rootLink().setTranslation([0.59, -0.1, 0.55])
 # ahiruをrootItemに追加(アイテムタブに表示されるようになる)
 rootItem.addChildItem(objItem)
 # ahiruのアイテムをチェックする(シーンタブにahiruが表示される)
 ItemTreeView.instance().checkItem(objItem)
 
 ## set grasping robot
 # PA10に対しSetRobotする(PlannerバーのSetRobot)
 set_robot(robotItem)
 
 ## set target object
 # ahiruに対しSetObjectする(PlannerバーのSetObject)
 set_object(objItem)
 
 ## execute grasp
 # 把持計画を実行(PlannerバーのGrasp)
 grasp()

- grasp_exmaple2.py
PA10がahiruを把持計画する処理

 from cnoid.Util import *
 from cnoid.Base import *
 from cnoid.BodyPlugin import *
 from cnoid.GraspPlugin import *
 
 # choreonoidのrootItemを取得
 rootItem = RootItem.instance()
 
 ## set grasping robot
 # アイテムタブからPA10を探す
 robotItem = rootItem.find("PA10")
 # PA10に対しSetRobotする(PlannerバーのSetRobot)
 set_robot(robotItem)
 
 ## set target object
 # アイテムタブからahiruを探す
 objItem = rootItem.find("ahiru")
 # ahiruに対しSetObjectする(PlannerバーのSetObject)
 set_object(objItem)
 
 ## execute grasp
 # 把持計画を実行(PlannerバーのGrasp)
 grasp()

Pythonインターフェース作成

プラグインにpythonインタフェースの追加方法を説明します。
既にpythonインタフェースがあるプラグインで追加・修正を行う場合は
1. 2. は行う必要はありません。

1.CMakeLists.txtの末尾に以下を追加

  if(ENABLE_PYTHON)
   add_subdirectory(python)
  endif()

2.pythonディレクトリを作成

3.pythonディレクトリにCMakeLists.txtを作成
 Grasp/python/CMakeLists.txtを参考にソースファイルなどを適宜変更

 set(target PyGraspPlugin) # "PyGraspPlugin"を対象プラグインに合わせて名前変更
 
 add_cnoid_python_module(${target}
     PyGraspPluginModule.cpp # 対象プラグインに合わせて名前変更
  # 以下PythonInterfaceを記述したソースファイルを追加
     PyPlanBase.cpp          
     PyGrasp.cpp
     )
 
 target_link_libraries(${target} CnoidGraspPlugin CnoidPyBase PyBody PyBodyPlugin)

4.ソースファイルの追加修正
Graspプラグインを参考にして、追加修正を行ってください。
Boost pythonを使ってPythonインタフェースを作成しているので、
プログラミングの詳細はBoost pythonのドキュメントを参照してください。
ここではGraspプラグインのファイルを例に簡単に説明します。

-PyGraspPluginModule.cpp

 #include <cnoid/PyUtil>
 
 // pythonへエクスポートする処理の関数宣言
 // Graspプラグインでは
 // PyPlanBase.cppに定義されているPlanBaseクラスをエクスポートするexportPlanBase()
 // PyGrasp.cppに定義されているSetRobot,SetObject,Grasp機能をエクスポートするexportGrasp()
 void exportPlanBase();
 void exportGrasp();
 
 BOOST_PYTHON_MODULE(GraspPlugin) { // GraspPlugin部分がモジュール名に相当
     boost::python::import("cnoid.Base");
     boost::python::import("cnoid.Body");
     boost::python::import("cnoid.BodyPlugin");
 
     // pythonへエクスポートする関数を実行
   // 処理はPyPlanBase.cpp,PyGrasp.cppを参照。
     exportPlanBase();
     exportGrasp();
 }

-PyGrasp.cpp

 #include  < iostream>
 ....
 
 using namespace boost::python;
 using namespace grasp;
 
 namespace {
   // 実際に行う処理をここに記述
 
     void Grasp() {
      ....
     }
 
     bool Set_grasping_robot(cnoid::ItemPtr item, int arm_id = 0) {
         cnoid::BodyItemPtr bodyitem = cnoid::dynamic_pointer_cast<cnoid::BodyItem, cnoid::Item>(item);
          ....
     }
 
     BOOST_PYTHON_FUNCTION_OVERLOADS(Set_grasping_robot_overloads, Set_grasping_robot, 1, 2)
 
     void Set_grasped_object(cnoid::ItemPtr item) {
         cnoid::BodyItemPtr bodyitem = cnoid::dynamic_pointer_cast<cnoid::BodyItem, cnoid::Item>(item);
         PlanBase::instance()->SetGraspedObject(bodyitem);
     }
 }
 
 // エクスポートする処理
 void exportGrasp() {
     def("grasp", Grasp);
     def("set_robot", Set_grasping_robot, Set_grasping_robot_overloads());
     def("set_object", Set_grasped_object);
 }

exportGrasp()内のdef関数でpythonに関数をエクスポートしています。
第1引数はPythonでの関数名、第2引数は処理する関数のポインタです。
def("grasp", Grasp);
はpythonでgrasp()が呼ばれたときGrasp()を実行することを表しています。

def("set_robot", Set_grasping_robot, Set_grasping_robot_overloads());
はデフォルト引数がある関数を呼び出している例です。
Set_grasping_robotがデフォルト引数がある関数で、Set_grasping_robot_overloadsがデフォルト引数を扱うためのクラスで

BOOST_PYTHON_FUNCTION_OVERLOADS(Set_grasping_robot_overloads, Set_grasping_robot, 1, 2)

で作成しています。ここで第3引数、第4引数は引数の最小と最大の数です。