mc_rtc::Configuration
設定mc_rtc::Configuration
設定このページでは以下の情報を提供します。
mc_rtc::Configuration
オブジェクトからデータを読み取る方法mc_rtc::Configuration
オブジェクトにデータを書き込む方法mc_rtc::Configuration
との間でC++オブジェクトの読み込み・保存を行う独自の関数を記述する方法このページの例で使用されているconfig
は、C++の例ではmc_rtc::Configuration
型のC++オブジェクト、Pythonの例ではmc_rtc.Configuration
型のPythonオブジェクトであると仮定しています。
mc_rtc::Configuration
は、JSONオブジェクトまたはYAMLオブジェクトを抽象化したもので、これを使用すると、オブジェクトの操作と、オブジェクトからのC++/Pythonデータの取得が簡単に行えます。.
設定オブジェクトにデータを読み込むには、以下のようにします。
// ファイルから読み込む、JSONデータであることを想定
auto config = mc_rtc::Configuration("myfile.conf");
// YAMLファイルから読み込む、拡張子はymlかyaml
auto config = mc_rtc::Configuration("myfile.yaml");
// すでに読み込まれているJSONデータから読み込む
auto config = mc_rtc::Configuration::fromData(data);
// すでに読み込まれているYAMLデータから読み込む
auto config = mc_rtc::Configuration::fromYAMLData(data);
設定内のデータにアクセスする方法がいくつか用意されています。状況に応じて最も適したものを組み合わせて使用することがきます。以下の3つの方法が用意されています。
最初の方法では、アクセスしたい設定エントリが読み込み済みの設定ファイル内に存在しない場合や、取得したい値の型と保存されている値の型が一致しない場合には、例外がスローされます。
以下のようにエントリにアクセスします。
Eigen::Vector3d v = config("MyVector3d");
設定のサブセクションにアクセスすることもできます。
Eigen::VectorXd v = config("section")("MyVectorXd");
また、これらをネストさせることもできます。
std::vector<std::string> v = config("section")("sub1")("sub2")("SomeStrings");
以下のようにします。
if(conf.has("MyQuaternion"))
{
Eigen::Quaterniond q = config("MyQuaternion");
}
上記のコードでは、設定にMyQuaternion
エントリが存在するものの、Eigen::Quaterniond
オブジェクトを取得するのに必要なデータが含まれていない場合にのみ例外がスローされます(先のセクションを参照)。
この方法を使用すると、設定エントリを安全に取得できます。設定エントリが存在しない場合や、要求した型と実際の型が異なる場合でも、例外はスローされません。
以下のようにエントリにアクセスします。
bool b = false;
config("MyBool", b);
また、上記のコードを以下のように簡潔に記述することもできます。
bool b = config("MyBool", false);
エントリが存在しない場合や、要求した型と実際の型が異なる場合は、指定した変数を変更できません。そうでない場合は、設定に格納されている値が指定した変数にコピーされます。特に、ベクトルを取得する場合はこの点を十分理解してください。
std::vector<double> v = {1., 2., 3.};
config("MyVector", v); // MyVector が有効なエントリである場合、vの初期値は失われる
先の方法と同様に、設定のサブセクションにアクセスすることもできます。
double d = 1.0;
config("section")("sub1")("sub2")("MyDouble", d);
ただし、先の方法のコードでは、設定ファイル内にセクションやサブセクションが1つも存在しない場合、例外がスローされます。
上記の厳格なアクセスとデフォルトのアクセス方法は、mc_rtc::Configuration
オブジェクトのサブセクションへのアクセスに適用できます。例:
// 引数がconfigに存在するオブジェクトやセクションで無い場合はthrowする
auto sub = config("section");
// 引数がconfigに存在しない場合、空のオブジェクトを返す
auto sub = config("section", mc_rtc::Configuration{});
なお、コピーは浅い階層で行われるため、サブセクションへの変更は親セクションから見えます。
Pythonの場合、ユーザーが要求した要素の型をPythonに推測させることはできません。そのため、データを取得する際はPythonの型または値を指定する必要があります。
# c は mc_rtc.Configuration オブジェクト
c = config("key")
# ブーリアン型を取得
b = config("b", bool)
# v は eigen.Vector3d オブジェクト
v = config("v", eigen.Vector3d)
# ブーリアン型をデフォルト値Falseとして取得
b = config("b", False)
# eigen.Vector3d のリストを取得
vlist = config("vlist", [eigen.Vector3d])
# floatのリストをデフォルト値を指定して取得
flist = config("flist", [0., 1., 2.])
mc_rtc::Configuration
オブジェクトにデータを書き込む以下に、オブジェクトAPIと配列APIの違いを示す記述の例を示します。
// -- オブジェクト --
// セクションキーを指定して新たしい空のオブジェクトを生成
auto section = conf.add("section");
// セクションにデータを追加
section.add("v1", Eigen::Vector3d{1,2,3});
section.add("isFixed", true);
// ここでdataは mc_rtc::Configuration でサポートされている型のデータ
section.add("data", data);
// -- 配列 --
// 新しい空の配列を生成
auto array = conf.array("array");
// 新しい空の配列を生成し、10要素分のメモリを確保
auto array10 = conf.array("array10", 10);
// データを配列に追加
array.push(Eigen::Vector3d{1,2,3});
array.push(true);
array.push(data);
PythonのAPIもこれと全く同じです。
上記の例で見たように、Configuration
オブジェクトを使用してさまざまな型のオブジェクトを取得できます。以下の表に、サポートされている型とJSONの要件を示します。
型 | JSONの要件 |
---|---|
bool |
bool型(true /false )または整数(0がfalseに対応し、その他の値がtrueに対応) |
int |
整数 |
unsigned int |
符号なし整数、または0以上の整数 |
double |
数値エントリ |
std::string |
文字列エントリ |
Eigen::Vector3d |
数値要素から成る3次元配列 |
Eigen::Quaterniond |
数値要素から成る4次元配列。正規化された四元数が返されます。 |
Eigen::Vector6d |
数値要素から成る6次元配列 |
Eigen::VectorXd |
数値要素から成る任意の次元の配列 |
Eigen::Matrix3d |
数値要素から成る9次元配列。回転をサポートするため、2種類の代替表現がサポートされています。RPY角度を表す3次元配列、または四元数を表す4次元配列として指定することもできます。 |
std::vector<T> T には上記のいずれかの型を指定できます。 |
各要素が型T の要件を満たす配列 |
std::array<T, N> T には上記のいずれかの型を指定できます。`N`は固定のサイズです。 |
各要素が型T の要件を満たすN 次元配列 |
std::pair<U, V> U とV には上記のいずれかの型を指定できます。 |
各次元の要素がそれぞれ型U と`V`の要件を満たす2次元配列 |
std::map<std::string, T> T には上記のいずれかの型を指定できます。 |
文字列によってインデックスが付けられ、型T の要件を満たす要素から成るマップ |
ほかにも、タスクや制約条件といったさまざまな型がサポートされています。mc_rtcに読み込み可能なオブジェクトについては、こちらのWebサイトにあるドキュメントを参照してください。
設定でサポートされている一般型を、自由に組み合わせて使うことができます。例えば、以下の記述は完全に有効です。
std::vector<std::pair<std::vector<Eigen::Vector3d>, std::vector<double>> inequalities = config("inequalities");
この機能では、独自の型を持つデータの読み込みや保存を行えるようにmc_rtc::Configuration
を特殊化することができます。現在、この機能はC++でのみサポートされています。
次の形式で、mc_rtc名前空間内のConfigurationLoaderテンプレートに特殊化を追加することができます:
template<>
struct ConfigurationLoader<MyType>
{
static MyType load(const mc_rtc::Configuration & config);
static mc_rtc::Configuration save(const MyType & object);
};
この機能は、数多くのSpaceVecAlg
型、RBDyn
型、mc_rbdyn
型をサポートするためにmc_rtc
内で広く使用されています。 宣言についてはmc_rbdyn/configuration_io.h
を参照してください。
保存関数ではオプションの引数がサポートされているため、以下のような特殊化が可能です。
template<>
struct ConfigurationLoader<MyType>
{
static MyType load(const mc_rtc::Configuration & config);
static mc_rtc::Configuration save(const MyType & object, bool verbose = false);
};
また、オブジェクト内にメソッドを実装することもできます。mc_rtc
はこれらのメソッドを自動的に選択します:
struct Foo
{
// ...
// このメソッドは、オブジェクトをConfigurationオブジェクトから読み込むために呼び出されます
static Foo fromConfiguration(const mc_rtc::Configuration & in);
// このメソッドは、オブジェクトをConfigurationオブジェクトに保存するために呼び出されます
mc_rtc::Configuration toConfiguration() const;
// これは引数もサポートしています
mc_rtc::Configuration toConfiguration(bool verbose) const;
};