箱庭ドローンシミュレータ v3.7.1 をリリースしました。
今回の目玉は、MuJoCoベースの箱庭ドローンを Python API(fleet_rpc)で複数機体同時操作できるようにしたことです。
v3.7.1 の新機能・変更点
複数機体を扱うための Python API(fleet_rpc)を整備し、MuJoCoベースの箱庭ドローンにも対応しました。
v3.6.1 では、ドローンショー向け機体のシミュレーションは質点ベース(重心のみを考慮した簡易モデル)でしたが、今回から剛体ベース(形状・慣性・干渉を考慮したモデル)に対応しました。
これにより、以下のようなより実運用に近いシミュレーションが可能になります。
- 配送時の物体衝突
- 重心変動を伴うペイロード搭載
- 機体姿勢の精密な再現
なお、fleet_rpc は既存の単機体向け API と併用可能です。
また、今回の対応にあわせて、MuJoCoの対応バージョンを最新版3.7.0へ更新しました。
アップグレード手順・サンプルコードはこちらをご参照ください。
デモ
fleet rpc サンプルコード:mujoco_two_drone_demo.py
各ステップでは _async メソッドを使って複数機体への命令を並列に発行し、wait_and_print で全機体の応答を待ち合わせています。これにより、機体数が増えても同じパターンで制御を拡張できます。
このサンプルコードでは、以下の手順で2台のドローンを同時に制御しています。
- アーム(SetReady) ― 各機体を起動待機状態にします
- テイクオフ ― 指定高度まで同時に離陸させます
- 移動(GoTo) ― それぞれの目標座標へ同時に飛行させます
- 状態取得 ― 最終位置を確認します
- 着陸(Land) ― 同時に着陸させます
def main() -> int:
with FleetRpcController(
drone_names=DRONE_NAMES,
service_config_path=SERVICE_CONFIG_PATH.resolve(),
use_async_shared=True,
) as fleet:
status1 = fleet.get_status("Drone-1")
status2 = fleet.get_status("Drone-2")
print(f"INFO: Drone-1 status={status1}")
print(f"INFO: Drone-2 status={status2}")
# 1. SetReady for each drone, then wait for both responses.
ready_futures = [
fleet.set_ready_async("Drone-1"),
fleet.set_ready_async("Drone-2"),
]
wait_and_print("set_ready", ready_futures, fleet)
# 2. TakeOff for each drone, then wait for both responses.
takeoff_futures = [
fleet.takeoff_async("Drone-1", TAKEOFF_ALT_M),
fleet.takeoff_async("Drone-2", TAKEOFF_ALT_M),
]
wait_and_print("takeoff", takeoff_futures, fleet)
# 3. GoTo for each drone, then wait for both responses.
goto_futures = [
fleet.goto_async(
"Drone-1",
TARGETS["Drone-1"][0],
TARGETS["Drone-1"][1],
TARGETS["Drone-1"][2],
),
fleet.goto_async(
"Drone-2",
TARGETS["Drone-2"][0],
TARGETS["Drone-2"][1],
TARGETS["Drone-2"][2],
),
]
wait_and_print("goto", goto_futures, fleet)
# 4. Read back the final state explicitly.
state1 = fleet.get_state("Drone-1")
state2 = fleet.get_state("Drone-2")
pos1 = state1.current_pose.position
pos2 = state2.current_pose.position
print(f"INFO: Drone-1 final pos=({float(pos1.x):.3f}, {float(pos1.y):.3f}, {float(pos1.z):.3f})")
print(f"INFO: Drone-2 final pos=({float(pos2.x):.3f}, {float(pos2.y):.3f}, {float(pos2.z):.3f})")
# 5. Land for each drone, then wait for both responses.
land_futures = [
fleet.land_async("Drone-1", timeout_sec=5.0),
fleet.land_async("Drone-2", timeout_sec=5.0),
]
wait_and_print("land", land_futures, fleet, return_exceptions=True)
try:
status1 = fleet.get_status("Drone-1")
print(f"INFO: Drone-1 status={status1}")
except Exception as e:
print(f"WARN: Drone-1 status unavailable after land: {e}")
try:
status2 = fleet.get_status("Drone-2")
print(f"INFO: Drone-2 status={status2}")
except Exception as e:
print(f"WARN: Drone-2 status unavailable after land: {e}")
return 0合同会社 箱庭ラボ
担当:森崇

コメントを残す