新たなロボットをmc_rtcでサポートする方法

mc_rtcには、以下の3つの方法でロボットを組み込むことができます。

  1. env/objectローダーを使用する
  2. JSON/YAMLファイルとjsonローダーを使用する
  3. C++でRobotModuleの実装を記述する

ローダーの概要

  • env/objectローダー:
    センサーなどが付いていない、シンプルなロボットや静的オブジェクト・環境向け。
    URDFに定義されたメッシュから自動的に凸包を生成することが可能です。
  • jsonローダー:
    関節、センサー、グリッパーなどの構造化されたメタデータを追加できます。
    自動凸包生成をサポートします。
  • C++ RobotModule:
    最も柔軟で、構成やロジックを細かく制御可能。
    凸包の自動生成およびキャッシュ機能を完全にサポートします。

env/objectローダーを使用する

ロボットを読み込むには、以下のように呼び出しを行います。

#include <mc_rbdyn/RobotLoader.h>

std::string path = "/path/to/description";
std::string name = "name";
auto env = mc_rbdyn::RobotLoader::get_robot_module("env", path, name);

// オブジェクトによってロボットと浮遊ベースが読み込まれる
auto object = mc_rbdyn::RobotLoader::get_robot_module("object", path, name);
import mc_rbdyn

path = "/path/to/description"
name = "name"
env = mc_rbdyn.get_robot_module("env", path, name)

# オブジェクトによってロボットと浮遊ベースが読み込まれる
object = mc_rbdyn.get_robot_module("object", path, name)
["env", "/path/to/description", "name"]

// オブジェクトによってロボットと浮遊ベースが読み込まれる
["object", "/path/to/description", "name"]
[env, /path/to/description, name]

# オブジェクトによってロボットと浮遊ベースが読み込まれる
[object, /path/to/description, name]

ロボット記述パッケージを整理する

ロボット記述フォルダーがLOCATIONにあり、ロボットの名前がNAMEであるとき、mc_rtcは、データが以下のように整理されているはずです。

  • URDFが $LOCATION/urdf/$NAME.urdf にある
  • RSDFファイルが $LOCATION/rsdf/$NAME/ フォルダーにある(任意)
  • 凸包ファイルが $LOCATION/convex/$NAME/ フォルダーにある(任意)

たとえば、ボディ名が BODY の場合、対応する凸包ファイル名は:

BODY-ch.txt

補足事項:

  • RSDFフォルダーは空であってもよい、または存在しなくてもよい
  • すべてのボディに凸包ファイルを用意する必要はない
  • 対応するボディが見つからない凸包ファイルは無視される
  • 凸包ファイルが存在しない場合でも、自動生成がすべてのローダータイプで可能です

凸包の自動生成について

mc_rtcでは、すべてのローダー方式(env、JSON、C++)において、URDFまたはSRDF内に定義されたメッシュから 衝突用凸包を自動生成できます。

動作概要

  • ロボットのURDF/SRDFに含まれるメッシュをサンプリングして凸包を構築
  • 生成された凸包はローカルキャッシュされ、再利用されます
  • キャッシュが存在しない場合や、明示的に再生成する場合は再計算されます

キャッシュ保存場所

生成された凸包は、ユーザー環境ごとのローカル共有ディレクトリに保存されます。
このパスは local_share_directory() 関数により構築され、プラットフォームによって異なります。

  • Windows: %APPDATA%/mc_rtc/<robot_name>/
  • Linux/macOS: $HOME/.local/share/mc_rtc/<robot_name>/

ファイル命名規則

  • ボディにメッシュが1つだけある場合: BODY-ch.txt
  • 複数メッシュがある場合: BODY_0-ch.txt, BODY_1-ch.txt のように番号付きで生成

jsonローダーを使用する

ロボットを読み込むには、以下のように呼び出しを行います。

#include <mc_rbdyn/RobotLoader.h>

std::string json_path = "/path/to/file.json";
auto rm_json = mc_rbdyn::RobotLoader::get_robot_module("json", json_path);

std::string yaml_path = "/path/to/file.yaml";
auto rm_yaml = mc_rbdyn::RobotLoader::get_robot_module("json", yaml_path);
import mc_rbdyn

json_path = "/path/to/file.json"
rm_json = mc_rbdyn.get_robot_module("json", json_path)

yaml_path = "/path/to/file.yaml"
rm_yaml = mc_rbdyn.get_robot_module("json", yaml_path)
["json", "/path/to/file.json"]

["json", "/path/to/file.yaml"]
[json, /path/to/file.json]

[json, /path/to/file.yaml]

JSON/YAMLファイルで必要とされるデータ

jsonモジュールは、envモジュールと同じようにデータが整理されていることを想定しています。ただし、ユーザーがデータを与えることで、それらの要件のいくつかは無視できます。また、力覚センサー、ボディセンサー、最小限の自己衝突メッシュセットなどのデータをモジュールに与えることができます。

jsonローダーで必要とされるデータの詳細については、JSON/YAMLのドキュメントを参照してください。

独自のRobotModuleを実装する

この方法では、ロボットのRobotModuleを定義するためのC++クラスを記述し、ユーザーが指定したいデータメンバーをそのクラスのデータメンバーに置き換えます。最小限のサンプルを以下に示します。

cmake_minimum_required(VERSION 3.1)

find_package(mc_rtc REQUIRED)

add_robot_simple(MyRobot)
# 以下のためのショートカット:
#
# add_robot(MyRobot MyRobot.h MyRobot.cpp)
#pragma once

#include <mc_rbdyn/RobotModule.h>
#include <mc_robots/api.h>

struct MC_ROBOTS_DLLAPI MyRobotModule : public mc_rbdyn::RobotModule
{
public:
  MyRobotModule(bool fixed);
};

extern "C"
{
  ROBOT_MODULE_API void MC_RTC_ROBOT_MODULE(std::vector<std::string> & names)
  {
    // このモジュールによってエクスポートされるロボットの名前
    names = {"MyRobot", "MyRobotFixed"};
  }
  ROBOT_MODULE_API void destroy(mc_rbdyn::RobotModule * ptr)
  {
    delete ptr;
  }
  ROBOT_MODULE_API mc_rbdyn::RobotModule * create(const std::string & name)
  {
    // 現時点ではサポートされているいずれかのロボットの名前を使用する必要がある
    if(name == "MyRobot") { return new MyRobot(false); }
    else
    {
      return new MyRobot(true);
    }
  }
}
#include "MyRobot.h"

#include <RBDyn/parsers/urdf.h>

// MY_PATHはCMakeなどで与えることができる
MyRobotModule::MyRobotModule(bool fixed) : mc_rbdyn::RobotModule(MY_PATH, "my_robot")
{
  init(rbd::parsers::from_urdf_file(urdf_path));

  std::vector<double> default_q = {-0.38, -0.01, 0., 0.72, -0.01, -0.33,  -0.38, 0.02, 0.,    0.72, -0.02, -0.33, 0.,
                                   0.13,  0.,    0., 0.,   0.,    -0.052, -0.17, 0.,   -0.52, 0.,   0.,    0.,    0.,
                                   0.,    0.,    0., 0.,   0.,    -0.052, 0.17,  0.,   -0.52, 0.,   0.,    0.,    0.,
                                   0.,    0.,    0., 0.,   0.,    0.,     0.,    0.,   0.,    0.,   0.};
  const auto & rjo = ref_joint_order();
  for(size_t i = 0; i < rjo.size(); ++i) { _stance[rjo[i]] = {default_q[i]}; }
  _default_attitude = {{1., 0., 0., 0., 0., 0., 0.8275}};
  _forceSensors.push_back(mc_rbdyn::ForceSensor("RightFootForceSensor", "R_ANKLE_P_S", sva::PTransformd::Identity()));
  _forceSensors.push_back(mc_rbdyn::ForceSensor("LeftFootForceSensor", "L_ANKLE_P_S", sva::PTransformd::Identity()));
  _forceSensors.push_back(mc_rbdyn::ForceSensor("RightHandForceSensor", "R_WRIST_Y_S", sva::PTransformd::Identity()));
  _forceSensors.push_back(mc_rbdyn::ForceSensor("LeftHandForceSensor", "L_WRIST_Y_S", sva::PTransformd::Identity()));

  _bodySensors.emplace_back("Accelerometer", "PELVIS_S", sva::PTransformd(Eigen::Vector3d(-0.0325, 0, 0.1095)));
  _bodySensors.emplace_back("FloatingBase", "PELVIS_S", sva::PTransformd::Identity());

  _minimalSelfCollisions = {
      {"WAIST_R_S", "L_SHOULDER_Y_S", 0.02, 0.001, 0.}, {"WAIST_R_S", "R_SHOULDER_Y_S", 0.02, 0.001, 0.},
      {"PELVIS_S", "R_ELBOW_P_S", 0.05, 0.001, 0.},     {"PELVIS_S", "L_ELBOW_P_S", 0.05, 0.001, 0.},
      {"R_WRIST_Y_S", "R_HIP_Y_S", 0.05, 0.025, 0.},    {"L_WRIST_Y_S", "L_HIP_Y_S", 0.05, 0.025, 0.}};
  _commonSelfCollisions = _minimalSelfCollisions;
  _grippers = {{"l_gripper", {"L_UTHUMB"}, true}, {"r_gripper", {"R_UTHUMB"}, false}};
}

指定可能なメンバーについては、mc_rbdyn::RobotModuleのドキュメントを参照してください。

さあ始めましょう

mc-rtc/new-robot-moduleテンプレートプロジェクトを使用すると、すぐに始められます。このテンプレートには、C++またはYAMLのRobotModule用の必要最小限の構造が記述されています。