S SmartDocs
시리즈: Robotaxi-OperatingSystem-Hardware-Interfaces python 267 줄 · 업데이트 2026-03-12

skill.py

Robotaxi-OperatingSystem-Hardware-Interfaces/fmc3-robotics-main/projects/RoboSkill/fourier/gr2/skill.py

import time
import math
import asyncio
import traceback
from mcp.server.fastmcp import FastMCP
from fourier_aurora_client import AuroraClient

# FastMCP server
mcp = FastMCP("fourier_gr2", stateless_http=True, host="0.0.0.0", port=8000)

# Robot configuration
DOMAIN_ID = 123
ROBOT_NAME = "gr2"

# Global client instance
_client = None


async def _get_client():
    global _client
    if _client is None:
        print("[Skill] Initializing AuroraClient...")
        try:
            _client = AuroraClient.get_instance(domain_id=DOMAIN_ID, robot_name=ROBOT_NAME)
            await asyncio.sleep(1)
            print("[Skill] Client initialized.")
        except Exception as e:
            print(f"[Skill] Error initializing client: {e}")
            raise
    return _client


def _interpolate_position(init_pos, target_pos, step, total_steps):
    """Linear interpolation helper function."""
    return [i + (t - i) * step / total_steps for i, t in zip(init_pos, target_pos)]


async def _move_arm_steady(client, group_name, init_pos, target_pos, duration=2.0, frequency=100):
    """Smooth arm movement with interpolation."""
    total_steps = int(frequency * duration)
    print(f"[Skill] Moving {group_name} (duration={duration}s)...")
    for step in range(total_steps + 1):
        pos = _interpolate_position(init_pos, target_pos, step, total_steps)
        client.set_joint_positions({group_name: pos})
        await asyncio.sleep(1 / frequency)
    print(f"[Skill] {group_name} movement done.")


async def _move_sync_steady(client, arm_target, hand_target, duration=2.0, frequency=100):
    """Synchronized arm and hand movement."""
    total_steps = int(frequency * duration)

    # Try to get current state, fallback to 0.0 if failed
    try:
        arm_init = client.get_group_state("right_manipulator")
        if arm_init is None:
            print("[Skill] Warning: Could not get arm state, using default 0.0")
            arm_init = [0.0]*7

        hand_init = client.get_group_state("right_hand")
        if hand_init is None:
            print("[Skill] Warning: Could not get hand state, using default 0.2")
            hand_init = [0.2]*6
    except Exception as e:
        print(f"[Skill] Error getting state in move_sync: {e}")
        arm_init = [0.0]*7
        hand_init = [0.2]*6

    print(f"[Skill] Sync moving arm and hand (duration={duration}s)...")
    for step in range(total_steps + 1):
        arm_pos = _interpolate_position(arm_init, arm_target, step, total_steps)
        hand_pos = _interpolate_position(hand_init, hand_target, step, total_steps)
        client.set_joint_positions({
            "right_manipulator": arm_pos,
            "right_hand": hand_pos
        })
        await asyncio.sleep(1 / frequency)
    print("[Skill] Sync move done.")


async def _wave_motion(client, wave_center_pos, wave_amplitude=0.5, wave_count=5, cycle_time=0.3):
    """Wave motion with sinusoidal interpolation."""
    frequency = 100
    steps_per_cycle = int(frequency * cycle_time)
    wrist_yaw_index = 4

    print(f"[Skill] Starting wave motion ({wave_count} cycles)...")
    for wave_i in range(wave_count):
        for step in range(steps_per_cycle + 1):
            offset = wave_amplitude * math.sin(2 * math.pi * step / steps_per_cycle)
            pos = wave_center_pos.copy()
            pos[wrist_yaw_index] = wave_center_pos[wrist_yaw_index] + offset
            client.set_joint_positions({"right_manipulator": pos})
            await asyncio.sleep(1 / frequency)
    print("[Skill] Wave motion done.")


async def _ensure_control_mode(client):
    """Ensure robot is in UserCmd mode."""
    # Always set to UserCmd mode before action to prevent timeout disconnects
    # Mode 10 = UserCmd
    try:
        client.set_fsm_state(10)
        # Small delay to ensure command takes effect
        await asyncio.sleep(0.1)
    except Exception as e:
        print(f"[Skill] Error setting control mode: {e}")


@mcp.tool()
async def connect_robot() -> str:
    """Connect to Fourier GR2 robot and prepare for control.
    Must be called before any other robot commands.
    """
    print("[Skill] connect_robot called")
    client = await _get_client()
    print("[Skill] Setting velocity source...")
    client.set_velocity_source(2)  # Navigation mode
    print("[Skill] Setting PdStand (2)...")
    client.set_fsm_state(2)  # PdStand
    await asyncio.sleep(3.0)
    print("[Skill] Setting UserCmd (10)...")
    client.set_fsm_state(10)  # UserCmd
    await asyncio.sleep(0.5)
    print("[Skill] Robot connected and ready.")
    return "Fourier GR2 robot connected and ready."


@mcp.tool()
async def disconnect_robot() -> str:
    """Disconnect from Fourier GR2 robot and return to stand mode."""
    print("[Skill] disconnect_robot called")
    global _client
    if _client is not None:
        try:
            _client.set_fsm_state(2)
            _client.close()
        except Exception as e:
            print(f"[Skill] Error during disconnect: {e}")
        _client = None
    return "Fourier GR2 robot disconnected."


@mcp.tool()
async def wave_hand(wave_count: int = 5, wave_speed: float = 0.3) -> str:
    """Make the robot wave its right hand.
        控制机器人执行[挥手]动作。
        打招呼或引起注意的动作。
        早上好,欢迎领导
        Guten Morgen! Herzlich willkommen, liebe Führungskräfte.
    Args:
        wave_count: Number of wave cycles (default: 5)
        wave_speed: Time for one wave cycle in seconds, smaller is faster (default: 0.3)
    """
    print(f"[Skill] wave_hand called: count={wave_count}, speed={wave_speed}")
    try:
        client = await _get_client()
        await _ensure_control_mode(client)

        current_pos = client.get_group_state("right_manipulator")
        if current_pos is None:
            print("[Skill] Failed to get arm state, assuming 0.0")
            current_pos = [0.0]*7

        wave_ready_pos = [-0.8, -0.5, 0.0, -1.4, 0.0, 0.0, 0.0]

        # Raise arm
        await _move_arm_steady(client, "right_manipulator", current_pos, wave_ready_pos, duration=1.8)

        # Wave motion
        await _wave_motion(client, wave_center_pos=wave_ready_pos, cycle_time=wave_speed, wave_amplitude=0.5, wave_count=wave_count)

        # Lower arm
        await _move_arm_steady(client, "right_manipulator", wave_ready_pos, [0.0]*7, duration=1.5)

        print("[Skill] wave_hand completed successfully")
        return f"Wave completed with {wave_count} cycles."
    except Exception as e:
        error_msg = f"Error in wave_hand: {str(e)}\n{traceback.format_exc()}"
        print(error_msg)
        return f"Wave failed: {str(e)}"


@mcp.tool()
async def thumbs_up() -> str:
    """Make the robot give a thumbs up gesture with its right hand.
    
    """
    print("[Skill] thumbs_up called")
    try:
        client = await _get_client()
        await _ensure_control_mode(client)

        wave_ready_pos = [-0.8, -0.5, 0.0, -1.4, 0.0, 0.0, 0.0]
        thumbs_up_hand = [1.5, 1.5, 1.5, 1.5, 0.0, 0.2]  # Fingers closed, thumb extended
        hand_open = [0.2, 0.2, 0.2, 0.2, 0.8, 0.0]

        # Raise arm with open hand
        await _move_sync_steady(client, wave_ready_pos, hand_open, duration=2.0)

        # Make thumbs up gesture
        await _move_sync_steady(client, wave_ready_pos, thumbs_up_hand, duration=0.8)

        # Hold for 2 seconds
        print("[Skill] Holding pose...")
        await asyncio.sleep(2.0)

        # Return to neutral
        await _move_sync_steady(client, [0.0]*7, hand_open, duration=1.5)

        print("[Skill] thumbs_up completed successfully")
        return "Thumbs up gesture completed."
    except Exception as e:
        error_msg = f"Error in thumbs_up: {str(e)}\n{traceback.format_exc()}"
        print(error_msg)
        return f"Thumbs up failed: {str(e)}"


@mcp.tool()
async def move_arm_to_position(positions: list) -> str:
    """Move robot right arm to specified joint positions.

    Args:
        positions: List of 7 joint positions for right_manipulator
    """
    if len(positions) != 7:
        return "Error: positions must be a list of 7 values"

    print(f"[Skill] move_arm_to_position called: {positions}")
    try:
        client = await _get_client()
        await _ensure_control_mode(client)

        current_pos = client.get_group_state("right_manipulator") or [0.0]*7
        await _move_arm_steady(client, "right_manipulator", current_pos, positions, duration=2.0)

        return f"Arm moved to position: {positions}"
    except Exception as e:
        print(f"[Skill] Error in move_arm_to_position: {e}")
        return f"Move failed: {str(e)}"


@mcp.tool()
async def set_hand_gesture(positions: list) -> str:
    """Set robot right hand finger positions.

    Args:
        positions: List of 6 finger joint positions [index, middle, ring, pinky, thumb_rotation, thumb_flex]
    """
    if len(positions) != 6:
        return "Error: positions must be a list of 6 values"

    print(f"[Skill] set_hand_gesture called: {positions}")
    try:
        client = await _get_client()
        await _ensure_control_mode(client)
        client.set_joint_positions({"right_hand": positions})
        return f"Hand gesture set to: {positions}"
    except Exception as e:
        print(f"[Skill] Error in set_hand_gesture: {e}")
        return f"Set gesture failed: {str(e)}"


if __name__ == "__main__":
    print("🚀 Starting Fourier GR2 Skill Server on port 8000...")
    mcp.run(transport="streamable-http")

관련 글

Robotaxi-OperatingSystem-Hardware-Interfaces c 업데이트 2026-02-03

alloc.c

alloc.c — c source code from the Robotaxi-OperatingSystem-Hardware-Interfaces learning materials (Robotaxi-OperatingSystem-Hardware-Interfaces/class001_bundle/alloc.c).

글 읽기 →
Robotaxi-OperatingSystem-Hardware-Interfaces c 업데이트 2026-02-03

hello.c

hello.c — c source code from the Robotaxi-OperatingSystem-Hardware-Interfaces learning materials (Robotaxi-OperatingSystem-Hardware-Interfaces/class001_bundle/hello.c).

글 읽기 →
Robotaxi-OperatingSystem-Hardware-Interfaces c 업데이트 2026-02-03

mlock_demo.c

mlock_demo.c — c source code from the Robotaxi-OperatingSystem-Hardware-Interfaces learning materials (Robotaxi-OperatingSystem-Hardware-Interfaces/class001_bundle/mlock_demo.c).

글 읽기 →
Robotaxi-OperatingSystem-Hardware-Interfaces python 업데이트 2026-03-12

debug_perf.py

debug_perf.py — python source code from the Robotaxi-OperatingSystem-Hardware-Interfaces learning materials (Robotaxi-OperatingSystem-Hardware-Interfaces/fmc3-robotics-main/projects/RoboBrain2.0/debug_perf.py).

글 읽기 →
Robotaxi-OperatingSystem-Hardware-Interfaces python 업데이트 2026-03-12

inference.py

inference.py — python source code from the Robotaxi-OperatingSystem-Hardware-Interfaces learning materials (Robotaxi-OperatingSystem-Hardware-Interfaces/fmc3-robotics-main/projects/RoboBrain2.0/inference.py).

글 읽기 →
Robotaxi-OperatingSystem-Hardware-Interfaces bash 업데이트 2026-03-12

startup.sh

startup.sh — bash source code from the Robotaxi-OperatingSystem-Hardware-Interfaces learning materials (Robotaxi-OperatingSystem-Hardware-Interfaces/fmc3-robotics-main/projects/RoboBrain2.0/startup.sh).

글 읽기 →