Skip to content

Simulation をテストに使う

Fibril Simulation の reusable test は、full robot launch を毎回起動する構成よりも、小さな Plan と独立した Instance を直接扱う構成が基本です。 fibril_sim_testing はそのための fixture と標準 bench asset を提供します。

SimulationFixture の使い方

fibril::sim::testing::SimulationFixture は一つの immutable Plan と一つの replaceable Instance を保持します。 GTest 自体には依存しないため、TEST や TEST_F の内部から通常の C++ helper として利用できます。

#include <gtest/gtest.h>

#include "fibril_sim_testing/rangefinder_bench.hpp"
#include "fibril_sim_testing/simulation_fixture.hpp"

TEST(MySimulationTest, RunsDeterministically)
{
  auto plan = std::make_shared<const fibril::sim::SimulationPlan>(
    fibril::sim::testing::make_rangefinder_bench_plan());
  fibril::sim::testing::SimulationFixture fixture(plan);

  fixture.step(10);
  const auto snapshot = fixture.instance().snapshot();
  EXPECT_GT(snapshot.time.nanoseconds(), 0);
}

実際の test では Plan の構築方法に合わせて ownership を組み立ててください。 SimulationFixture が提供する中心的な操作は instance()、reset_run()、reset_run(seed)、step(count) です。

小さい bench を使う

fibril_sim_testing には rangefinder、controller SIL などの reusable bench があります。 たとえば rangefinder bench は full robot や extension を必要とせず、Device output だけを検証できます。

小さい bench を使う理由は performance だけではありません。 失敗したときに physics、sensor semantics、controller、ROS integration のどの層が原因かを限定できます。

Controller SIL の構成

controller を ROS graph から切り離して検証できる場合も、controller 自体は SimulationInstance の外側に置きます。 controller_sil bench は DeviceOutput を production controller 相当の callable に渡し、その出力を ExternalInput として simulation に戻す最小構成です。

MuJoCo plant
    |
    v
  Device
    |
    v
controller
    |
    v
ExternalInputCommit
    |
    v
ActuatorDriver
    |
    v
actuator endpoint
    |
    +------> MuJoCo plant

controller の production logic を simulation 専用の別実装に置き換えると SIL の意味が弱くなります。 可能な範囲で production controller を同じ callable から利用し、simulation への入力は production integration と同じ ExternalInput contract を通します。

Seed を固定する

noise を含む test では episode seed を test input の一部として固定します。 同じ Plan に対して reset_run(seed) を使えば、別 seed の run を同じ fixture で作り直せます。

randomness を消して test を安定化する方法もありますが、noise semantics 自体を検証したい test では seed 固定の方が contract を保持できます。

Snapshot と DeviceOutput

physics state の assertion には SimulationInstance::snapshot() を使います。 snapshot は qpos、qvel、MuJoCo sensordata を copied immutable value として返します。

virtual sensor の assertion には drain_device_outputs() を使います。 DeviceOutput は delivery 済みの sample だけを返すため、acquisition 直後で latency が残っている sample はまだ現れません。

Record/replay test の作り方

ExternalInput を含む test では trace を保存し、その committed input と commit tick を新しい Instance へ replay できます。 単純に同じ wall-clock 順で callback を再送するのではなく、simulation から見えた commit boundary を再現する点が異なります。

再現性の問題を調べる場合は Tracing と replay を使い、parameter variant の比較が必要なら Parameter Experiments へ進んでください。