mc_rtc::Configuration
設定有限オートマトン(FSM: Finite State Machine)は、有限個の状態のいずれかの状態を取る抽象機械です。この機械の状態は、現在の状態における内部または外部の条件に基づき変化します。そのような変化は状態遷移と呼ばれます。こうした機械は、プログラミングの世界では至る所で使用されています。また、構造が簡単でさまざまな構成が可能であるため、特にロボットに関するシナリオを実現するのに非常に適しています。
状態遷移図の概念を拡張したものが有限オートマトンです。有限オートマトンでは2つの主要な原則が導入されています。
mc_rtcのコントローラーでは、状態遷移図の概念を実装できます。このページでは、有限オートマトンの実装に関する詳細について説明します。
状態の実装については後ほど説明します。ここでは、状態に関する4つの主なメソッドについて説明します。
configure
は、状態を設定するのに使用します。このメソッドは複数回呼ばれます。
Meta
やParallel
)のconfigs
エントリから呼ばれます。config_
オブジェクトにロードします。より複雑なロード機能を実現するために、このメソッドをオーバーライドすることができます。なお、有限オートマトンの実装では、既存の状態と異なる設定を指定することで、新しい状態を作成することができます。そのため、この関数は複数回呼び出されます。
start
は、初期化を実行するのに使用します。1度だけ呼び出されます。run
は、状態で実装されるメインの関数です。その状態の処理が終了するか、状態が変化するまで、ループ処理が実行されるたびに1回ずつ呼び出されます。runの処理が完了したときに、状態の出力として任意の値を設定できます。この値は状態内で明確に定義する必要があります。teardown
は、クリーンアップ関数です。状態が変化したときに呼び出されます。状態遷移は、以下の内容を表す4つの属性で構成されます。
StepByStep
(デフォルト)、Auto
、Strict
のいずれかの値を取ります。それぞれの意味については後ほど説明します。有限オートマトンコントローラーは、マネージドモードまたは非マネージドモードで実行されます。はじめに、非マネージドモードについて見ていきます。
このモードでは、状態の作成・実行と状態間の遷移は有限オートマトンによって処理されます。
有限オートマトンでは、ループ処理内で以下のロジックが実行されます。
Auto
の場合、あるいは状態遷移の種類がStepByStep
かつ有限オートマトンのStepByStep
の設定がfalse
の場合
上記の概要では、ロジックの流れを簡単にするためにいくつかの点が省略されています。
アイドル状態は、それまで実行されていた状態によって実現されていたロボットの状態を維持しようと試みます(アイドル状態が有効の場合)。これは、2つのタスクによって実現されます。
処理の中断がトリガーされた場合、この「状態」は常に実行されます。
このモードに関して説明することはそれほどありません。マネージドモードでは、有限オートマトンは状態遷移を処理しません。この場合、状態遷移は外部のツールによって完全に処理されます。状態の存続期間は上記の場合と同様ですが、状態遷移はすべて外部のツールによってトリガーされます。
ここでは、C++オブジェクトとして記述された状態について説明します。このオブジェクトには、さまざまな設定オプションが用意されています。しかし、わずかな違いしかない2つ以上の状態を定義したい場合、すべてのオプションを毎回設定するのは大変です。そこで、本インターフェイスでは、一連の設定を継承する仕組みが用意されています。
以下の処理を実行する、StateBase
という名前のC++状態があるとします。
MyFirstState: # <-- 新しい状態の名称
base: StateBase # <-- 基底となる状態のC++クラスの名称
# 他のオプション
MySecondState: # <-- 新しい状態名称
base: MyFirstState # <-- テキストで定義した状態を基底として使用することも可能
# 他のオプション
オプションがどのように組み合わされるかは、C++状態の実装方法により異なるため、状態内で明確に定義する必要があります。ただし、mc_rtcで用意されている状態については、一般的な規則が当てはまります。これらの状態については、基本的にmc_rtc::Configuration
オブジェクトのデフォルトの読み込み規則が適用されます。
このセクションでは、mc_rtcで用意されている主な状態について説明します。利用可能な状態とその設定に関する詳細については、状態に関するJSONスキーマを参照してください。
この状態では、しばらく待ってからOK
が出力されます。
duration
: 一時停止する期間(単位: 秒)を浮動小数点数の値で指定します。デフォルトは0です。この状態では、任意の数のMetaTasksが作成され、各タスクの完了基準が満たされるまでそれらのタスクが実行されます。
この状態に含まれるタスクは、JSONオブジェクトであるtasks
エントリを使用して設定します。
タスクの名前をキーとして指定し、MetaTaskLoaderで必要とされるMetaTaskオブジェクトを値として指定します。また、オプションとして、1つ以上の完了基準を"completion"エントリで指定することもできます。
タスクの名前はこの状態でのみ有効です。タスクの設定でnameエントリを使用することで、実際のタスク名を変更できます。
タスクのcompletion
エントリが存在せず、関連するタスクのcompletionエントリが存在しない場合、このタスクは追加されますが、このタスクの完了基準は考慮されません(例えば、CoMTaskとEndEffectorTaskを追加した場合、後者の完了基準のみが考慮されます)。
tasks
エントリが複数回読み込まれた場合の動作は以下のようになります。
tasks
: コントローラーのこの状態に追加するタスクが記述されたオブジェクト接触面を削除または追加できる状態を実装します。
この状態を設定するには、以下の2つのエントリを定義する必要があります。
type
: [addContact
、removeContact
、 compliance
]のいずれかcontact
: 削除または追加する接触面distance
: 接触面とボディがこの距離だけ離れると、この状態が終了します。デフォルトは0.1(10cm)です。velocity
: ComplianceTaskの速度のしきい値。デフォルトは1e-4です。body
エントリが上書きされます。</p>
力覚センサーが取り付けられていない接触面をコンプライアンス制御タスクで削除した場合、この状態は自動的にaddContact
にフォールバックします。
Parallel状態を実装します。
Tこの状態では、複数の状態が同時に実行されます。厳密に言うと、これらの状態は並列ではなくシーケンシャルに実行されます。
この状態によって{state_1, ..., state_N}
という状態が実行された場合、この状態は、すべてのstate_i::run()
関数がtrueを返したときに完了します。このとき、この状態はstate_N
を出力します。
states
: この状態によって実行される状態のリストconfigs
: 各状態に含まれる状態の設定。このconfigs(state)は、各状態をさらに細かく設定するのに使用します。「メタ」状態を実装します。
この状態は、自分自身の有限オートマトンを実行します。
Managed
: trueに設定した場合、状態遷移は処理されません。transitions
: 有限オートマトンコントローラーと同様の状態遷移マップ(Managedをfalseに設定した場合、このオプションを設定する必要があります)。StepByStep
: 内部有限オートマトンの場合、有限オートマトンの設定と同じになります(デフォルトでは親有限オートマトンのStepByStep
設定と同じになります)。configs
: 有限オートマトンに含まれる状態に関する追加の設定を記述できます。一部のオプションはすべての状態に共通です。
AddContacts
/RemoveContacts
: 状態が実行される前に、接触面を追加・削除できます。fsm::Contact
オブジェクトのベクトルとして指定します。AddContactsAfter
/RemoveContactsAfter
: 状態が実行された後に、接触面を追加・削除できます。fsm::Contact
オブジェクトのベクトルとして指定します。RemovePostureTask
: trueに設定すると、デフォルトの姿勢制御タスクが削除されます。状態を作成するには、mc_control::fsm::State
から継承します。最低限のインターフェイスを以下に示します。
namespace mc_control::fsm
{
struct MyState : public State
{
void configure(mc_rtc::Configuration &) override;
void start(Controller &) override;
bool run(Controller &) override;
void teardown(Controller &) override;
};
}
EXPORT_SINGLE_STATE("MyState", mc_control::fsm::MyState);
関数内でController
インスタンスを渡す場合、 mc_control::fsm::Controller
インスタンスとして渡します。
void configure(mc_rtc::Configuration &)
この関数は複数回呼び出されます。この関数では、設定エントリを「定義」するだけとし、タスクは作成しないでください。
void start(Controller &)
この関数は状態の初期化時に1度だけ呼び出されます。ここでは、定義した設定が実行可能な状態に変換されます。
bool run(Controller &)
この関数は、start
ループの実行に続き、ループ処理が実行されるたびに1回ずつ呼び出されます(start
ループからrun
を明示的に呼び出さない限り、start
と同じループ内ではrun
は呼び出されません)。
状態の処理が完了すると、この関数はtrue
を返します。このとき、output(const std::string &)
を呼び出して状態の出力を設定するようにしてください。
void teardown(Controller &)
この関数は、状態が破棄される前に1度だけ呼び出されます。この関数を使用して、状態がコントローラーに影響を与えないようにしてください。
有限オートマトンは、いくつかの点で通常のmc_rtcコントローラーと異なります。
有限オートマトンでは、接触面構造の簡易版が使用されています。これは以下のように定義されています。
struct Contact
{
std::string r1;
std::string r2;
std::string r1Surface;
std::string r2Surface;
Eigen::Vector6d dof; // Eigen::Vector6d::Ones()がデフォルト
};
dof
ベクトルは対角行列に変換され、自由度制約条件として追加されます
有限オートマトンコントローラーで接触面を追加・削除するには、以下の関数を呼び出します。
void addContact(const Contact &);
void removeContact(const Contact &);
衝突メッシュを追加・削除するには、以下の関数を呼び出します。
void addCollisions(const std::string & r1, const std::string & r2,
const std::vector<mc_rbdyn::Collision> & collisions);
void removeCollisions(const std::string & r1, const std::string & r2,
const std::vector<mc_rbdyn::Collision> & collisions);
// r1 と r2 の間の全ての干渉回避拘束を削除
void removeCollisions(const std::string & r1, const std::string & r2);
有限オートマトンによって、必要に応じて衝突制約条件が作成されて追加されます。
有限オートマトンによって、多関節ロボットの姿勢制御タスクが作成されます。このタスクにアクセスするには、以下の関数を呼び出します。
std::shared_ptr<mc_tasks::PostureTask> getPostureTask(const std::string & robot);
このタスクは、通常、状態が存在している間はソルバー内に保持されます。そのようにしたくない場合は、teardown
の呼び出し時にこのタスクをソルバーから取り出して元の場所に戻すことができます。
以下のメソッドは、State
インターフェイス内の仮想メソッドで、ユーザーが定義したメソッドで上書きすることができます。
void stop(Controller &)
Tこれは、状態の処理が中断されたときに呼び出されます。
以下のオプションを使用して有限オートマトンを設定できます。
Managed
: trueの場合、有限オートマトンはマネージド型で、そうでない場合は非マネージド型です。StepByStep
: trueの場合、StepByStep
とタグ付けされた状態遷移はStrict
の状態遷移として動作します。falseの場合、状態遷移はAuto
の状態遷移として動作します。IdleKeepState
: trueの場合、ユーザーによって状態遷移がトリガーされるまで同じ状態が維持されます。StatesLibraries
: 状態ライブラリの参照先StatesFiles
: 状態設定ファイルの参照先VerboseStateFactory
: trueの場合、ライブラリの読み込み中に状態ファクトリによって詳細情報が出力されます。これはデバッグに役立ちます。robots
: JSONオブジェクト。各キーはロボットの名前を表します。値は、メインロボットモジュールのほかに追加で読み込むロボットモジュールを表すオブジェクトです。// Example robots entry
"robots":
{
"ground":
{
"module": "env",
"params": ["@MC_ENV_DESCRIPTION@", "ground"]
}
}
constraints
: 制約条件の配列。各オブジェクトは、JSONスキーマに基づきJSON形式で記述されたmc_solver::ConstraintSet
オブジェクトです。collisions
: mc_solver::CollisionConstraint
JSONスキーマに基づき定義された衝突制約条件の配列contacts
: 初期接触面の配列// contactsエントリの例
"contacts":
[
{
"r1": "jvrc1",
"r2": "ground",
"r1Surface": "LeftFoot",
"r2Surface": "AllGround"
},
{
"r1": "jvrc1",
"r2": "ground",
"r1Surface": "RightFoot",
"r2Surface": "AllGround"
}
]
– 各ロボットにはr
で始まる名前が付けられています。r
で始まるエントリを使用して、アイドル状態で使用される姿勢制御タスクとフリーフライヤータスクを設定できます。
states
: オブジェクト。各キーは状態の名前を表します。値はこの状態の設定を表します。configs
: オブジェクト。各キーは状態の名前を表します。値は、状態がメインの有限オートマトンで実行されたときにその状態に渡される追加の設定値を表します。transitions
: 配列。配列の各要素は状態遷移を表します。init
: 有限オートマトンを起動したときの初期状態init_pos
: メインロボットの初期位置(7次元の配列)次のチュートリアルでは、有限オートマトンを使用した実用的な例を実装します。