メむンコンテンツぞスキップ
芋出し画像

Genesis 入門 (3) - ロボットの操䜜

    「Genesis」のロボットの操䜜に぀いおたずめたした。

    ・Control Your Robot

    前回

    1. ロボットの操䜜

    ロボットアヌムは「制埡力」(actuation force) を䞎えないず、重力で萜䞋したす。Genesisには、「目暙関節䜍眮」たたは「速床」を入力ずしお受け取る「PDコントロヌラ」が組み蟌たれおいたす。たた、各関節に盎接「トルク/力」を蚭定するこずもできたす。

    2. 関節ず自由床

    2-1. 関節ず自由床

    ロボットシミュレヌションの文脈では、「関節」(joint)ず「自由床」(dof : degree-of-freedom) は関連しおいるものの異なる抂念です。

    ・関節 (joint)
    ロボットの2぀のリンク剛䜓を接続し、盞察的な動きを可胜にする機構。動きを特定の皮類回転、䞊進などに限定。
    ・自由床 (dof : degree-of-freedom)
    動力孊的たたは運動孊的に独立しお制埡可胜な動きの数。ロボットが環境内で取れる可胜な動きの幅を瀺す。

    今回扱うFrankaアヌムは、アヌムに7぀の回転関節、グリッパヌに2぀の䞊進関節を持っおいたす。すべおの関節は1自由床のため、9自由床の関節䜓ずなっおいたす。より䞀般的なケヌスでは、フリヌゞョむント (6自由床) やボヌルゞョむント (3自由床) のように、耇数の自由床を持぀関節タむプも存圚したす。䞀般的に、各自由床はモヌタヌずしお考えるこずができ、独立制埡できたす。

    2-2. 関節名を自由床のむンデックスにマッピング

    どの関節自由床を制埡するかを知るために、URDF/MJCFファむルでナヌザヌずしお定矩した関節名をシミュレヌタ内の実際の自由床むンデックスにマッピングする必芁がありたす。

    # 関節名を自由床のむンデックスにマッピング
    jnt_names = [
        'joint1',
        'joint2',
        'joint3',
        'joint4',
        'joint5',
        'joint6',
        'joint7',
        'finger_joint1',
        'finger_joint2',
    ]
    dofs_idx = [franka.get_joint(name).dof_idx_local for name in jnt_names]

    「joint.dof_idx_local」で、ロボット゚ンティティ自䜓に察する自由床のロヌカルむンデックスを取埗しおいたす。「joint.dof_idx」で、シヌン内の各関節のグロヌバル自由床むンデックスにアクセスするこずもできたす。

    2-3. 各自由床の制埡ゲむンの蚭定

    「制埡ゲむン」 (Gain) は、制埡システムにおいお、入力ず出力の関係を調敎するための係数です。制埡量トルクや力を目暙倀ず珟圚の倀の差偏差に比䟋しお蚈算したす。偏差が倧きい堎合、倧きな力で目暙倀に近づけようずし、偏差が小さくなるに぀れお、出力する力も小さくなりたす。

    通垞、これらの情報は「MJCF」たたは「URDF」から解析されたすが、手動でチュヌニングするか、オンラむンで十分にチュヌニングされた倀を参照するこずを掚奚したす。

    # ゚ンティティの自由床の䜍眮ゲむンを蚭定
    franka.set_dofs_kp(
        kp             = np.array([4500, 4500, 3500, 3500, 2000, 2000, 2000, 100, 100]),
        dofs_idx_local = dofs_idx,
    )
    
    # ゚ンティティの自由床の速床ゲむンを蚭定
    franka.set_dofs_kv(
        kv             = np.array([450, 450, 350, 350, 200, 200, 200, 10, 10]),
        dofs_idx_local = dofs_idx,
    )
    
    # ゚ンティティの自由床の力の範囲を蚭定 (安党のため)
    franka.set_dofs_force_range(
        lower          = np.array([-87, -87, -87, -87, -12, -12, -12, -100, -100]),
        upper          = np.array([ 87,  87,  87,  87,  12,  12,  12,  100,  100]),
        dofs_idx_local = dofs_idx,
    )

    これらのAPIは、蚭定する実際の倀ず、察応する自由床のむンデックスを受け取りたす。ほずんどの制埡関連APIはこの芏則に埓っおいたす。

    3. ハヌドリセットによるロボット操䜜

    物理的に珟実的な「PDコントロヌラ」を䜿甚する代わりに、ロボットの構成を手動で蚭定しおみたす。これらのAPIは物理法則に埓わずにロボットの状態を突然倉曎するこずができたす。

    # ハヌドリセット
    for i in range(150):
        if i < 50:
            # ゚ンティティの自由床の䜍眮を蚭定
            franka.set_dofs_position(np.array([1, 1, 0, 0, 0, 0, 0, 0.04, 0.04]), dofs_idx)
        elif i < 100:
            # ゚ンティティの自由床の䜍眮を蚭定
            franka.set_dofs_position(np.array([-1, 0.8, 1, -2, 1, 0.5, -0.5, 0.04, 0.04]), dofs_idx)
        else:
            # ゚ンティティの自由床の䜍眮を蚭定
            franka.set_dofs_position(np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]), dofs_idx)
    
        scene.step()

    ビュヌアヌをオンにしおいる堎合、50ステップごずにロボットの状態が倉化するのが芋えたす。

    4. PDコントロヌラによるロボット操䜜

    組み蟌みの「PDコントロヌラ」を䜿っおロボットを制埡しおみたす。「Genesis」のAPI蚭蚈は構造化されたパタヌンに埓っおいたす。set_dofs_positionを䜿っお自由床の䜍眮を盎接蚭定したした。ここでは、set_*をcontrol_*に倉曎しお、察応する制埡噚APIを䜿甚したす。以䞋で、ロボットを制埡するさたざたな方法を瀺したす。

    # PDコントロヌラ
    for i in range(1250):
        if i == 0:
            # ゚ンティティの自由床の目暙䜍眮を蚭定
            franka.control_dofs_position(
                np.array([1, 1, 0, 0, 0, 0, 0, 0.04, 0.04]),
                dofs_idx,
            )
        elif i == 250:
            # ゚ンティティの自由床の目暙䜍眮を蚭定
            franka.control_dofs_position(
                np.array([-1, 0.8, 1, -2, 1, 0.5, -0.5, 0.04, 0.04]),
                dofs_idx,
            )
        elif i == 500:
            # ゚ンティティの自由床の目暙䜍眮を蚭定
            franka.control_dofs_position(
                np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]),
                dofs_idx,
            )
        elif i == 750:
            # ゚ンティティの自由床の目暙䜍眮を蚭定
            franka.control_dofs_position(
                np.array([0, 0, 0, 0, 0, 0, 0, 0, 0])[1:],
                dofs_idx[1:],
            )
            # ゚ンティティの自由床の目暙速床を蚭定
            franka.control_dofs_velocity(
                np.array([1.0, 0, 0, 0, 0, 0, 0, 0, 0])[:1],
                dofs_idx[:1],
            )
        elif i == 1000:
            # ゚ンティティの自由床の目暙制埡力を蚭定
            franka.control_dofs_force(
                np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]),
                dofs_idx,
            )
    
        # 制埡コマンドを元に蚈算された制埡力
        print('control force:', franka.get_dofs_control_force(dofs_idx))
    
        # 実際に受ける力
        print('internal force:', franka.get_dofs_force(dofs_idx))
    
        scene.step()

    ・ステップ0から500たで
    すべおの自由床に察しお䜍眮制埡を䜿甚し、ロボットを3぀の目暙䜍眮に順次移動させおいたす。control_* APIでは、目暙倀が䞀床蚭定されるず、内郚に保存されるため、目暙が同じである限り、以降のステップで繰り返しコマンドをシミュレヌションに送る必芁はありたせん。
    ・ステップ750
    異なる自由床に察しお異なる制埡が可胜であるこずを瀺しおいたす最初の自由床dof 0には速床コマンドを送り、残りは䜍眮制埡コマンドに埓いたす
    ・ステップ1000
    トルク力制埡に切り替え、すべおの自由床にれロ力コマンドを送るず、ロボットは再び重力によっお床に萜䞋したす。

    各ステップの最埌に、get_dofs_control_force() ず get_dofs_force() の2皮類の力を出力したす。

    ・get_dofs_control_force()
    PDコントロヌラによっお適甚される力を返したす。䜍眮制埡や速床制埡の堎合、これは目暙コマンドず制埡ゲむンを䜿甚しお蚈算したす。力トルク制埡の堎合、これは入力制埡コマンドず同じになりたす。
    ・get_dofs_force()
    各自由床が実際に経隓する力を返したす。これはPDコントロヌラによっお適甚される力ず、衝突力やコリオリ力などの他の内郚力の組み合わせになりたす。

    ・衝突力 (Impact Force)
    物䜓同士が接觊する際に生じる力。短い時間で倧きな力が発生するのが特城。
    ・コリオリ力 (Coriolis Force)
    回転する参照フレヌム内で芳枬される芋かけの力の䞀皮で、物䜓が移動する際に、その動きが曲げられるように芋える原因ずなる。

    画像

    Genesisの動䜜確認 (3)https://t.co/BVNlo2UsXA pic.twitter.com/Oa8gofc5UZ

    — 垃留川英䞀 / Hidekazu Furukawa (@npaka123) December 21, 2024

    5. 完党なコヌド

    以䞋は、完党なコヌドです。

    import numpy as np
    import genesis as gs
    
    # 初期化
    gs.init(backend=gs.gpu)
    
    # シヌンの䜜成
    scene = gs.Scene(
        viewer_options = gs.options.ViewerOptions(
            camera_pos    = (0, -3.5, 2.5),
            camera_lookat = (0.0, 0.0, 0.5),
            camera_fov    = 30,
            res           = (960, 640),
            max_FPS       = 60,
        ),
        sim_options = gs.options.SimOptions(
            dt = 0.01,
        ),
        show_viewer = True,
    )
    
    # シヌンに゚ンティティを远加
    plane = scene.add_entity(
        gs.morphs.Plane(),
    )
    franka = scene.add_entity(
        gs.morphs.MJCF(
            file  = 'xml/franka_emika_panda/panda.xml',
        ),
    )
    
    # シヌンのビルド
    scene.build()
    
    # 関節名を自由床のむンデックスにマッピング
    jnt_names = [
        'joint1',
        'joint2',
        'joint3',
        'joint4',
        'joint5',
        'joint6',
        'joint7',
        'finger_joint1',
        'finger_joint2',
    ]
    dofs_idx = [franka.get_joint(name).dof_idx_local for name in jnt_names]
    
    # ゚ンティティの自由床の䜍眮ゲむンを蚭定
    franka.set_dofs_kp(
        kp             = np.array([4500, 4500, 3500, 3500, 2000, 2000, 2000, 100, 100]),
        dofs_idx_local = dofs_idx,
    )
    
    # ゚ンティティの自由床の速床ゲむンを蚭定
    franka.set_dofs_kv(
        kv             = np.array([450, 450, 350, 350, 200, 200, 200, 10, 10]),
        dofs_idx_local = dofs_idx,
    )
    
    # ゚ンティティの自由床の力の範囲を蚭定 (安党のため)
    franka.set_dofs_force_range(
        lower          = np.array([-87, -87, -87, -87, -12, -12, -12, -100, -100]),
        upper          = np.array([ 87,  87,  87,  87,  12,  12,  12,  100,  100]),
        dofs_idx_local = dofs_idx,
    )
    
    # ハヌドリセット
    for i in range(150):
        if i < 50:
            # ゚ンティティの自由床の䜍眮を蚭定
            franka.set_dofs_position(np.array([1, 1, 0, 0, 0, 0, 0, 0.04, 0.04]), dofs_idx)
        elif i < 100:
            # ゚ンティティの自由床の䜍眮を蚭定
            franka.set_dofs_position(np.array([-1, 0.8, 1, -2, 1, 0.5, -0.5, 0.04, 0.04]), dofs_idx)
        else:
            # ゚ンティティの自由床の䜍眮を蚭定
            franka.set_dofs_position(np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]), dofs_idx)
    
        scene.step()
    
    # PDコントロヌル
    for i in range(1250):
        if i == 0:
            # ゚ンティティの自由床の目暙䜍眮を蚭定
            franka.control_dofs_position(
                np.array([1, 1, 0, 0, 0, 0, 0, 0.04, 0.04]),
                dofs_idx,
            )
        elif i == 250:
            # ゚ンティティの自由床の目暙䜍眮を蚭定
            franka.control_dofs_position(
                np.array([-1, 0.8, 1, -2, 1, 0.5, -0.5, 0.04, 0.04]),
                dofs_idx,
            )
        elif i == 500:
            # ゚ンティティの自由床の目暙䜍眮を蚭定
            franka.control_dofs_position(
                np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]),
                dofs_idx,
            )
        elif i == 750:
            # ゚ンティティの自由床の目暙䜍眮を蚭定
            franka.control_dofs_position(
                np.array([0, 0, 0, 0, 0, 0, 0, 0, 0])[1:],
                dofs_idx[1:],
            )
            # ゚ンティティの自由床の目暙速床を蚭定
            franka.control_dofs_velocity(
                np.array([1.0, 0, 0, 0, 0, 0, 0, 0, 0])[:1],
                dofs_idx[:1],
            )
        elif i == 1000:
            # ゚ンティティの自由床の目暙制埡力を蚭定
            franka.control_dofs_force(
                np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]),
                dofs_idx,
            )
    
        # 制埡コマンドを元に蚈算された制埡力
        print('control force:', franka.get_dofs_control_force(dofs_idx))
    
        # 実際に受ける力
        print('internal force:', franka.get_dofs_force(dofs_idx))
    
        scene.step()

    【おたけ】 Mac版のコヌド

    import genesis as gs
    import numpy as np
    
    def main():
        # 初期化
        gs.init(backend=gs.cpu)
    
        # シヌンの䜜成
        scene = gs.Scene(
            viewer_options = gs.options.ViewerOptions(
                camera_pos    = (0, -3.5, 2.5),
                camera_lookat = (0.0, 0.0, 0.5),
                camera_fov    = 30,
                res           = (960, 640),
                max_FPS       = 60,
            ),
            sim_options = gs.options.SimOptions(
                dt = 0.01,
            ),
            show_viewer = True,
        )
    
        # シヌンに゚ンティティを远加
        plane = scene.add_entity(
            gs.morphs.Plane(),
        )
        franka = scene.add_entity(
            gs.morphs.MJCF(
                file  = 'xml/franka_emika_panda/panda.xml',
            ),
        )
    
        # シヌンのビルド
        scene.build()
    
        # スレッドの開始
        gs.tools.run_in_another_thread(fn=run_sim, args=(scene, franka))
    
        # シミュレヌタの開始
        scene.viewer.start()
    
    
    def run_sim(scene, franka):
        # 関節名を自由床のむンデックスにマッピング
        jnt_names = [
            'joint1',
            'joint2',
            'joint3',
            'joint4',
            'joint5',
            'joint6',
            'joint7',
            'finger_joint1',
            'finger_joint2',
        ]
        dofs_idx = [franka.get_joint(name).dof_idx_local for name in jnt_names]
    
        # ゚ンティティの自由床の䜍眮ゲむンを蚭定
        franka.set_dofs_kp(
            kp             = np.array([4500, 4500, 3500, 3500, 2000, 2000, 2000, 100, 100]),
            dofs_idx_local = dofs_idx,
        )
    
        # ゚ンティティの自由床の速床ゲむンを蚭定
        franka.set_dofs_kv(
            kv             = np.array([450, 450, 350, 350, 200, 200, 200, 10, 10]),
            dofs_idx_local = dofs_idx,
        )
    
        # ゚ンティティの自由床の力の範囲を蚭定 (安党のため)
        franka.set_dofs_force_range(
            lower          = np.array([-87, -87, -87, -87, -12, -12, -12, -100, -100]),
            upper          = np.array([ 87,  87,  87,  87,  12,  12,  12,  100,  100]),
            dofs_idx_local = dofs_idx,
        )
    
        # ハヌドリセット
        for i in range(150):
            # ゚ンティティの自由床の䜍眮を蚭定
            if i < 50:
                franka.set_dofs_position(np.array([1, 1, 0, 0, 0, 0, 0, 0.04, 0.04]), dofs_idx)
            # ゚ンティティの自由床の䜍眮を蚭定
            elif i < 100:
                franka.set_dofs_position(np.array([-1, 0.8, 1, -2, 1, 0.5, -0.5, 0.04, 0.04]), dofs_idx)
            # ゚ンティティの自由床の䜍眮を蚭定
            else:
                franka.set_dofs_position(np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]), dofs_idx)
    
            scene.step()
    
        # PDコントロヌル
        for i in range(1250):
            if i == 0:
                # ゚ンティティの自由床の目暙䜍眮を蚭定
                franka.control_dofs_position(
                    np.array([1, 1, 0, 0, 0, 0, 0, 0.04, 0.04]),
                    dofs_idx,
                )
            elif i == 250:
                # ゚ンティティの自由床の目暙䜍眮を蚭定
                franka.control_dofs_position(
                    np.array([-1, 0.8, 1, -2, 1, 0.5, -0.5, 0.04, 0.04]),
                    dofs_idx,
                )
            elif i == 500:
                # ゚ンティティの自由床の目暙䜍眮を蚭定
                franka.control_dofs_position(
                    np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]),
                    dofs_idx,
                )
            elif i == 750:
                # ゚ンティティの自由床の目暙䜍眮を蚭定
                franka.control_dofs_position(
                    np.array([0, 0, 0, 0, 0, 0, 0, 0, 0])[1:],
                    dofs_idx[1:],
                )
                # ゚ンティティの自由床の目暙速床を蚭定
                franka.control_dofs_velocity(
                    np.array([1.0, 0, 0, 0, 0, 0, 0, 0, 0])[:1],
                    dofs_idx[:1],
                )
            elif i == 1000:
                # ゚ンティティの自由床の目暙制埡力を蚭定
                franka.control_dofs_force(
                    np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]),
                    dofs_idx,
                )
    
            # 制埡コマンドを元に蚈算された制埡力
            print('control force:', franka.get_dofs_control_force(dofs_idx))
    
            # 実際に受ける力
            print('internal force:', franka.get_dofs_force(dofs_idx))
    
            scene.step()
    
    
    if __name__ == "__main__":
        main()

    次回



     
     

    npaka

     
     
    プログラマヌ。iPhone / Android / Unity / ROS / AI / AR / VR / RasPi / ロボット / ガゞェット。幎2冊ペヌスで技術曞を執筆。アニ゜ン / カラオケ / ギタヌ / 猫 twitter : @npaka123

    あなたぞのおすすめ