openrave.org

 全て クラス ネームスペース ファイル 関数 変数 型定義 列挙型 列挙型の値 フレンド マクロ定義 グループ ページ
基本設計概念の紹介

基盤構造

openrave_architecture_jp.png

OpenRAVEは上図で示す4つの主要な構成要素に分けられています.

全ての基本的なプランナーと問題のインターフェースはどんなロボット構造にでも適用可能である必要があります.他のプランニングパッケージと比較してOpenRAVEの大きな強みの1つは,非常に少ない変更でどんなロボットにもそのアルゴリズムを適用できるということです.最近,データベースの構造に凸形状分解,把持セット,逆運動学解析解,運動学的到達範囲などが導入されました.もしロボットが定義されたなら,全てのこれらの機能は実行できなければなりません.

全てのインターフェースhelp命令で,それが提供する命令の詳細と何を実行するかを調べることが可能です.

環境の概念

全てのOpenRAVEのサービスはその環境を通じて提供されます.例えば,'BiRRT'と呼ばれるプランナーインターフェースへの要求はRaveCreatePlanner()を通じて行われます.環境は以下をサポートします.

環境内の物体が読み書きされるときはいつでも,ユーザーはGetMutex()コマンドでロックしなければなりません.これはユーザーが作業している間,他のプロセスから環境が変更されることを防止します.なぜなら環境は再帰的な相互排除を使っているからです.それは同じスレッド内で必要なだけロックをかけることが可能です.さらにユーザーが相互排除をロックしたかどうかに依らず,ロックを要求する全ての環境関数に常に相互排除はロックされることを保証しています.(これは環境関数のみに適用され,インターフェース関数には適用されません)

Locking

Because OpenRAVE is a highly multi-threaded environment, the environment state like bodies and loaded interfaces could be simultaneously accessed. In order to safely write or read the state, a user has to lock the environment, which prevents any other process from modifying the environment while the user is working. By using recursive locks, it allows a lock to be locked as many times as needed within the same thread, greatly reducing the lock management when a state changing function calls another state changing function. This safety measure helps users by always guaranteeing the environment is locked when calling global level environment functions like creating new bodies or loading scenes, regardless if the user has locked it. However, directly accessing the bodies and robots is dangerous without having the environment lock acquired.

Simulation Thread

Every environment has an internal time and a simulation thread directly attached to a physics engine. The thread is always running in the background and periodically steps the simulation time by a small delta for the physics engine and on all the simulation-enabled interfaces. By default, the thread is always running and can always potentially modify the environment state; therefore, users always need to explicitly lock the environment whenever playing with the internal state like modifying bodies by setting joint values or link transformations. If not careful, the controller or physics engine will overwrite them. By default, the simulation thread just sets the object positions depending on their controller inputs, but a physics engine can be attached to integrate velocities, accelerations, forces, and torques.

The simulation thread can feel like a nuisance at first, but its division of robot control into control input computation and execution greatly helps users only concentrate on feeding commands to the robot without worrying about the simulation loop. It also allows a world update to happen in one one discrete time step.

Cloning

One of the strengths of OpenRAVE is in allowing multiple environments work simultaneously in the same process. Environment cloning allows OpenRAVE to become truly parallel by managing multiple environments and running simultaneous planners on top of them.

One of the strengths of OpenRAVE is in allowing multiple environments to work simul- taneously in the same process. Environment cloning allows OpenRAVE to become truly parallel by managing multiple environments and running simultaneous planners on top of them. Because there is no shared state across the clone and the original environment, it is not possible to use an interface created from one environment in another For example, if a planner is created in one environment, it should be used only by objects in that environment. It is not possible to set a planner to plan for objects belonging to a different environment. This is because a planner will lock the environment and expect the objects it controls to be exclusively under its control.

Creating a clone is simple, in C++ just type:

EnvironmentBasePtr pNewEnvironment = GetEnv()->CloneSelf(Clone_Bodies)

to create a clone that copies all the existing bodies (with attachments and grabbed bodies) and their current states. Basically the clone can perform any operations that would have been done with the original enviornment.

Because the environment state is very complex, the cloning process can control how much of it gets transferred to the new clone. For example, all existing bodies and robots can be cloned, their attached controllers can be cloned, the attached viewer can be cloned, the collision checker state can be cloned, and the simulation state can be cloned. Basically the clone should be able to perform any operations that can be done with the original environment without any modification in the input parameters.

When cloning real robots, one extremely important feature that OpenRAVE cloning offers is the ability to maintain a real-time view of the world that sensors continuously update with new information. When a planner is instantiated, it should make a copy of the environment that it can exclusively control without interfering with the updating operations. Furthermore, the real-world environment possibly has robot controllers connected to real robots, having a clone gives the ability to set simulation controllers guarantees robot safety while planning; commands from a cloned environment would not accidentally send commands to the real robot.

Validating Plugins

Every plugin needs to export several functions to notify the core what interfaces it has and to instantiate the interfaces. When a plugin is first loaded, it is validated by the environment and its interface information is queried so the core can register the names.

There are many mechanisms in the validation process to prevent old plugins to be loaded by the core. OpenRAVE is updated frequently and all user plugins are not necessarily recompiled when the OpenRAVE API changes. Therefore, we will encounter many cases when a plugin exports the correct functions, but does not implement the correct API. Using interfaces from plugins compiled with a mismatching The API can lead to unexpected crashes that are very difficult to debug, so it is absolutely necessary to detect this condition. One possible solution is to add version numbers to the API to enforce checking before an interface is returned from the plugin to the environment, but this method is brittle. It forces to keep track of a version number for every interface along with a global version number. Furthermore, every developer has to remember to increment the version when something even small changes, which can be easily forgotten and lead to serious errors later on.

We solve interface validation by computing a unique hash of the interface functions and members by running each interface through a C++ lexer, gathering the tokens that affect the C++ code structure, and then creating a 128bit unique MD5 hash. We create a hash for each interface definition and the environment. The hashes are hard coded into the C++ header files and can be queried by two methods: a static function returning the hash of the program calling the function, and a virtual function returning the hash the interface was compiled with. An interface is only valid if its virtual hash is equivalent to the static hash of the core environment. For a plugin to be loaded correctly, first the environment hashes have to match. If they do, then the individual interfaces checked and only matching interfaces are returned to the core, and from there dispatched to other plugins. Such consistency checks ensure that stale plugins will never be loaded.

Parallel Execution

Being able to execute a planner in multiple threads is important for applications that require speed and solution quality Because there is always a trade-off between solution quality and time of computation, some applications like industrial robots require the quickest and smoothest past to their destinations. Fortunately, environment cloning allows planners to create an independent environment for every thread they create, which enables them to call kinematics and collision functions in each respective thread without worrying about data corruption. Growing an RRT tree in a multi-threaded environment just requires one copy of the kd-tree structure to be maintained. The query operations mostly work with Euclidean distance on the configuration space, so are really fast. Furthermore, adding a new point takes O(log) time, so it shouldn’t be a bottleneck in the search process compared to collision checking. Finally, environment locking allows threads to gain exclusive access to the environment. The rule of thumb is that any interface belonging or added to the environment requires an environment lock before any of its methods can be called.

2重のシミュレーション/制御機能

OpenRAVEはシミュレーション,制御,もしくはその両方に対して同時に使うことができます.以下にいくつかの覚えておくべきことを記載します.

このためユーザーは,関節の値やリンクの変換などの内部状態をセットするときにはいつでも,環境相互排除をロックする必要があります.さもなければ,コントローラーもしくは物理エンジンはそれらを上書きしてしまいます.

全てのboostエラー,nullポインタアクセスはopenrave_exceptionを投げます.これによって人々が行っているエラーをチェックするコードの量を大幅に減らすことができます.例えば,Cのコードにはよくこのパターンがあります.

bool somefun(KinBodyPtr pbody)
{
if( !pbody )
return false;
pbody->GetTransform();
...
}

もしくは,

bool somefun(KinBodyPtr pbody)
{
assert( !!pbody );
pbody->GetTransform();
...
}

もしこれらがチェックされなければ,コードはセグメンテーション違反となるでしょう.しかしながら,これらのチェックはコードを乱雑にするだけです.openraveでは,安全にエラー免れることができます.例えば,

bool somefun(KinBodyPtr pbody)
{
pbody->GetTransform();
...
}

エラーを処理するためには以下のようにします.

try {
...
somefun(pbody)
...
}
catch(const openrave_exception& ex) {
RAVELOG_WARN("exception caught: %s\n",ex.what());
if( ex.GetCode() == ORE_EnvironmentNotLocked ) {
RAVELOG_WARN("user forgot to lock environment!\n");
}
...
}

openravepyを使っている場合は,そのような処理されないC++エラーはpythonの例外処理に投げられ,安全にキャッチされてプロセスは進行します.

Hashes for Body Structure

A new concept that came out of OpenRAVE is the idea of creating unique hashes of a body’s structure. Every body has an online state that includes:

All other information is independent of the environment and can be categorized into the kinematics, geometry, and dynamics of the body. Furthermore, robots have categories for attached sensors and manipulators. The planning knowledge-base stores all cached information about a body and a robot, so it needs an consistent way of indexing this information. Indexing by robot names is not reliable because it is very difficult to remind a user to change the name every time the body structure is changed. Therefore, OpenRAVE provides functionality to serialize the different categories of a body and create a 128-bit MD5 hash. Each of the models in the planning knowledge-base relies on different categories of the robot. For example:

There are several challenges to developing a consistent index across all operating systems and compilers since floating point errors could creep in when normalizing floating-point values. However, the idea of such an index could greatly help in developing a worldwide robot database that anyone can use.

Resource File Formats

OpenRAVE defines its own OpenRAVE XML format that allows instantiation of any OpenRAVE interface and quick builing of robots and and kinematics structures. The rigid body geometries resources can be specified in virtually any 3D file format. For example:

These files can be used inside the <geom> tags, or can be read directly into any of the environment ReadRobotX and ReadKinBodyX methods to create a single world body.

OpenRAVE also supports the COLLADA international standard on 3D geometry and modeling. COLLADA is augmented with these OpenRAVE robot-specific extensions.

More information here.