Writing Python Scripts

Basics

Python scripts executed on Choreonoid run on the Python interpreter embedded in Choreonoid. There they can directly access the objects of the running Choreonoid, such as items and views.

In a script, first import the modules of the cnoid package corresponding to the functions to use.

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

For the overview of each module, refer to “Python Bindings” in Overview of Python Scripting. When a script is executed on Choreonoid, the path of the cnoid package is set in the module search path in advance, so you can import the modules as they are.

The classes and methods of the Python bindings mostly correspond to those of the C++ libraries, and they are basically available with the same names as in C++. Also, some of the accessors written as getX / setX in C++ can be referenced and assigned as properties in Python (e.g. body.numJoints, item.name).

Manipulating Items

The basis of automating Choreonoid operations is the manipulation of items.

The root item at the top of the item tree can be obtained as follows.

from cnoid.Base import *

rootItem = RootItem.instance

To create a new item and place it in the tree, create an object of the item class and add it to the parent item with addChildItem.

from cnoid.BodyPlugin import *

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

To obtain an existing item, use findItem. You can search by the name of the item (or by the path when tracing the hierarchy), or by the type of the item.

# search by name / path
robotItem = RootItem.instance.findItem("World/SR1")

# search by type (the first item found is returned)
simulatorItem = RootItem.instance.findItem(SimulatorItem)

The selection and check states of items can also be manipulated as follows.

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

For items corresponding to files, you can load a file with load. Path variables such as ${SHARE} (the share directory of Choreonoid), ${HOME} (the home directory of the user), and ${PROJECT_DIR} (the directory of the project file) can be used in file paths.

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

Example of Constructing a Project

The following is an example that constructs the project of a walking simulation of the SR1 model with a script and starts the simulation. This is the content of the script sample/python/SR1Walk.py included in the Choreonoid samples.

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()

This script performs the following processes.

  1. Create a world item and place it under the root item

  2. Create a body item and load the model file of SR1

  3. Obtain the body model (Body object) from the body item, set the position of the root link and the angles of the joints, and update the whole body posture with the forward kinematics calculation ( calcForwardKinematics )

  4. Store the current posture as the initial state of the simulation with storeInitialState

  5. Place a controller item to which the simple controller that plays the walking pattern is set, as a child item of the robot

  6. Place the floor model and the AIST simulator item

  7. Start the simulation with startSimulation

In this way, most of the project construction operations performed on the GUI can also be written in scripts.

Working with Simulations

You can also control the execution of simulations for a loaded project. The following is the content of the sample sample/python/StartSimulationAndQuitWhenFinished.py, which is a script that starts a simulation and exits Choreonoid itself when the simulation finishes.

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()

Here, the process at the end of the simulation is written by connecting a function to the signal sigSimulationFinished of the simulator item. In this way, as with the C++ API, you can write event-driven processes by connecting functions to signals.

By combining this script with Executing Scripts from the Command Line, it becomes possible to execute simulations in a batch manner. Also, if you want to execute scripts in conjunction with the start and end of a simulation, the Python Simulation Script is available as well.

Using the Qt Classes

With the cnoid.QtCore, cnoid.QtGui, and cnoid.QtWidgets modules, the major classes of Qt can be used from scripts. The following is the content of the sample sample/python/TimerSample.py, which is an example of executing a process every second using QTimer.

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()

In addition, it is also possible to build your own GUI consisting of buttons, dialogs, and so on with scripts using the widget classes of QtWidgets.

How to Investigate Classes and Functions

For the classes and functions that can be used for writing Python scripts, you can import each module on the Python console and check them with the standard Python functions dir() and help().

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

You can also use the input completion (Tab key) of the Python Console to try things out while checking the methods of a class on the spot.

Sample Scripts

Sample Python scripts are stored in the sample/python/ directory of the Choreonoid source. Refer to them when writing your own scripts. The following are some of them.

File

Contents

SR1Walk.py

Constructs the project of a walking simulation of the SR1 model and executes it.

StartSimulation.py

Starts the simulation of a loaded project.

StartSimulationAndQuitWhenFinished.py

Starts a simulation and exits Choreonoid when it finishes.

KinematicsTest.py

Performs a test of kinematics calculations on a body model.

BodyShaker.py

Shakes the selected body models. This is also an example of adding a custom toolbar and using signals and timers.

TimerSample.py

An example of periodic processing using QTimer.