رباتیک با قابلیت پخش جریانی

نقطه پایانی مدل gemini-robotics-er-2-streaming-preview یک نقطه پایانی اختصاصی برای پخش جریان ارائه می‌دهد که با Live API ادغام می‌شود و تعامل دو طرفه و بلادرنگ بین برنامه شما و ربات را امکان‌پذیر می‌سازد. این امر آن را برای عواملی که به حلقه‌های بازخورد سریع و پاسخ‌های واکنشی به محیط نیاز دارند، مناسب می‌سازد.

موارد استفاده

  • هماهنگی چند رباتی : چندین ربات که وضعیت وظایف را با هم در میان می‌گذارند و زیروظایف را از طریق یک جلسه مشترک واگذار می‌کنند.
  • نظارت مداوم : ربات‌هایی که صحنه را مشاهده می‌کنند و در صورت وقوع رویدادهای خاص، مانند رسیدن سطح پر شدن یک کانتینر، اقداماتی را انجام می‌دهند.
  • انبار و تدارکات : ماموران جمع‌آوری و بسته‌بندی که اقلام را به صورت بصری تأیید می‌کنند، پیشرفت بسته‌بندی را پیگیری می‌کنند و خطاها را برطرف می‌کنند.

مشخصات فنی

جدول زیر مشخصات فنی Live API را شرح می‌دهد:

دسته بندی جزئیات
روش‌های ورودی صدا (صدای خام PCM 16 بیتی، 16 کیلوهرتز، little-endian)، تصاویر (JPEG <= 1FPS)، متن
روش‌های خروجی متن
پروتکل اتصال وب سوکت با وضعیت (WSS)

یک مجموعه عامل ایجاد کنید

هر عامل رباتیک ساخته شده بر روی Live API از سه مرحله پیروی می‌کند:

  1. قابلیت‌های ربات را به عنوان ابزار تعریف کنید. هر عملی که ربات می‌تواند انجام دهد - پیمایش، گرفتن، صحبت کردن - به یک تعریف تابع با نام، توضیحات و طرح پارامتر تبدیل می‌شود. اقدامات فیزیکی باید از "behavior": "BLOCKING" تا مدل قبل از انتخاب مرحله بعدی منتظر بماند تا ربات کار خود را تمام کند.
  2. ورودی چندوجهی را به یک جلسه‌ی مداوم منتقل کنید. یک جلسه‌ی live.connect باز کنید و آن را تا پایان عمر وظیفه باز نگه دارید. فریم‌های ویدیویی، صوتی یا متنی را به محض دریافت از حسگرهای ربات خود ارسال کنید.
  3. فراخوانی‌های ابزار را در یک حلقه دریافت مدیریت کنید. هر بار که مدل یک عمل را انتخاب می‌کند، یک پیام tool_call ارسال می‌کند. حلقه دریافت شما تابع را در SDK ربات شما اجرا می‌کند و یک tool_response برمی‌گرداند. جلسه باز می‌ماند و مدل بر اساس نتیجه، عمل بعدی را انتخاب می‌کند.

بخش‌های بعدی نحوه اعمال این مراحل را بر روی سه الگوی رایج نشان می‌دهند: یک حلقه عامل پایه، نظارت پیشگیرانه بر صحنه با ضربان قلب، و مسیریابی گفتار از طریق TTS به عنوان یک ابزار.

هماهنگ‌سازی یک ربات از طریق فراخوانی تابع

مثال زیر هر سه مرحله را که در یک اسکریپت پایتون به هم متصل شده‌اند، نشان می‌دهد.

مرحله ۱ - تعاریف ابزار - قابلیت‌های ربات را به صورت اعلان تابع اعلام می‌کند. تابع navigate از "behavior": "BLOCKING" استفاده می‌کند، بنابراین مدل منتظر می‌ماند تا ربات به نقطه مسیر برسد و سپس ابزار دیگری را فراخوانی کند. اعلان‌های تابع بیشتری را در همان لیست اضافه کنید تا قابلیت‌های اضافی ربات را نمایش دهید.

مرحله ۲ - کمک‌کننده‌های ورودی - سه تابع را نشان می‌دهد که ورودی‌های با کیفیت‌های مختلف را به جلسه ارسال می‌کنند: send_text برای دستورات، send_image برای فریم‌های دوربین با یک اعلان متن اختیاری، و send_audio برای صدای خام PCM از میکروفون.

مرحله ۳ - حلقه دریافت - به صورت همزمان اجرا می‌شود و دو نوع پیام را مدیریت می‌کند: پیام‌های server_content (خروجی متنی مدل) و پیام‌های tool_call (مدلی که درخواست یک اقدام ربات را می‌دهد). وقتی یک فراخوانی ابزار از راه می‌رسد، حلقه execute_tool فراخوانی می‌کند - یک stub که شما آن را با SDK ربات واقعی خود جایگزین می‌کنید - سپس یک tool_response را برمی‌گرداند تا مدل بتواند اقدام بعدی را انتخاب کند.

import asyncio
from google import genai
from google.genai import types

MODEL = "gemini-robotics-er-2-streaming-preview"

# ── Tool definitions ─────────────────────────────────────────────────────────
tools = [
   {
       "function_declarations": [
           {
               "name": "navigate",
               "description": "Navigate the robot to a named waypoint.",
               "behavior": "BLOCKING",
               "parameters": {
                   "type": "OBJECT",
                   "properties": {"name": {"type": "STRING"}},
                   "required": ["name"],
               },
           },
           # Add more function definitions here
       ]
   }
]

# ── Stub tool executor (replace with real robot SDK calls) ───────────────────
def execute_tool(name: str, args: dict) -> dict:
   print(f"  [Tool] {name}({args})")
   return {"status": "success"}

# ── Input helpers ────────────────────────────────────────────────────────────
def send_text(session, text: str):
   """Send a text turn."""
   return session.send_client_content(
       turns=types.Content(role="user", parts=[types.Part(text=text)]),
       turn_complete=True,
   )

def send_image(session, image_bytes: bytes, prompt: str = ""):
   """Send a JPEG image with an optional text prompt."""
   parts = [
       types.Part(
           inline_data=types.Blob(data=image_bytes, mime_type="image/jpeg")
       )
   ]
   if prompt:
       parts.append(types.Part(text=prompt))
   return session.send_client_content(
       turns=types.Content(role="user", parts=parts),
       turn_complete=True,
   )

def send_audio(session, audio_chunk: bytes):
   """Stream a chunk of raw PCM audio (16-bit, 16 kHz, mono)."""
   return session.send_realtime_input(
       media=types.Blob(data=audio_chunk, mime_type="audio/pcm;rate=16000")
   )

# ── Receive loop ─────────────────────────────────────────────────────────────
async def receive_loop(session):
   """Print model text and handle tool calls until the session ends."""
   async for message in session.receive():
       if message.server_content:
           sc = message.server_content
           if sc.model_turn and sc.model_turn.parts:
               for part in sc.model_turn.parts:
                   if part.text:
                       print(f"Model: {part.text}", end="", flush=True)
           if sc.turn_complete:
               print("\n[Turn Complete]")
       elif message.tool_call:
           responses = []
           for call in message.tool_call.function_calls:
               print(f"\n[Tool Call] {call.name}({call.args})")
               result = execute_tool(call.name, call.args)
               responses.append(
                   types.FunctionResponse(
                       name=call.name,
                       response=result,
                       id=call.id,
                   )
               )
           await session.send_tool_response(function_responses=responses)

# ── Main ─────────────────────────────────────────────────────────────────────
async def main():
   client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])
   config = types.LiveConnectConfig(
       response_modalities=["TEXT"],
       tools=tools,
       system_instruction=types.Content(
           parts=[types.Part(text="You are a robot controller. Use tools to execute commands.")]
       ),
   )
   async with client.aio.live.connect(model=MODEL, config=config) as session:
       recv_task = asyncio.create_task(receive_loop(session))
       # Connect robot perception callbacks and user inputs to the helpers above.
       recv_task.cancel()

asyncio.run(main())

حلقه دریافت پس از هر پاسخ ابزار فعال می‌ماند. مدل، بدون اینکه شما کل توالی عمل را از قبل کدگذاری کنید، یک طرح بلندمدت می‌سازد و آن را اصلاح می‌کند.

استدلال فضایی-زمانی پیشگیرانه

API زنده، ویدیو را پخش می‌کند، اما فریم‌های ویدیویی به تنهایی باعث ایجاد یک چرخش استدلال جدید نمی‌شوند. فریم‌های ویدیویی باید با یک پیام متنی یا صوتی همراه باشند تا پاسخ مدل را فعال کنند. برای پس‌زمینه به قابلیت‌های Live API مراجعه کنید.

برای فعال کردن استدلال پیشگیرانه، یک ضربان قلب (heartbeat) پیاده‌سازی کنید: به صورت دوره‌ای آخرین فریم دوربین را ارسال کنید و به دنبال آن یک پیام متنی کوتاه ارسال کنید که مدل را مجبور به بررسی صحنه و تصمیم‌گیری صریح می‌کند. ورودی ویدیو به یک فریم در ثانیه محدود شده است.

این کوروتین را در کنار حلقه دریافت از بخش قبلی اضافه کنید. این به عنوان یک وظیفه asyncio جداگانه در همان جلسه اجرا می‌شود:

async def heartbeat(session, camera):  # camera is your robot camera API
    while True:
        frame = await camera.latest_jpeg()
        await session.send_realtime_input(
            video=types.Blob(data=frame, mime_type="image/jpeg")
        )
        await session.send_realtime_input(
            text=(
                "[HEARTBEAT] If no task is active, call 'ack' and wait for user"
                " input. If a task is active: observe the scene. If the current"
                " step is progressing correctly, call 'ack'. If the current step"
                " is complete, call 'run_instruction' with the next step. If the"
                " overall goal is achieved, call 'reset' and inform the user."
            )
        )
        await asyncio.sleep(1)

نیازی نیست در طول اقدامات ربات، ضربان قلب را متوقف کنید. وقتی به عنوان یک آشکارساز موفقیت ضمنی استفاده می‌شود، فعال نگه داشتن آن به مدل اجازه می‌دهد تا به طور مداوم عمل در حال انجام را مشاهده کند - ردیابی اینکه آیا گرفتن محکم است، ریختن به هدف است یا یک شیء به درستی قرار می‌گیرد - و به محض مشخص شدن نتیجه واکنش نشان دهد.

خروجی صدا از طریق TTS خارجی

Gemini Robotics ER 2 متن را برمی‌گرداند. برنامه شما پاسخ‌های تکمیل‌شده را از طریق یک فراخوانی تزریق‌شده به یک ارائه‌دهنده TTS جداگانه (مانند Gemini TTS ) هدایت می‌کند. این کار تأخیر گفتار، انتخاب صدا و رفتار وقفه را تحت کنترل شما نگه می‌دارد و به شما امکان می‌دهد بدون تغییر منطق عامل، بک‌اندهای TTS را تغییر دهید.

همچنین می‌توانید TTS را به عنوان یک ابزار تعریف کنید تا مدل با «گفتن چیزی» مانند «حرکت دادن بازو» رفتار کند. تعریف تابع زیر را از بخش اول به لیست tools خود اضافه کنید:

TOOLS = [
    {
        "name": "send_message",
        "description": (
            "Speak a message aloud via TTS, then deliver it to the"
            " specified target. Use target='user' to speak directly"
            " to the user, or a peer agent name (e.g., 'duo') to"
            " communicate with another robot."
        ),
        "parameters": {
            "type": "object",
            "properties": {
                "target": {
                    "type": "string",
                    "description": "Recipient: 'user' or a peer agent name.",
                },
                "message": {
                    "type": "string",
                    "description": "The message to speak and deliver.",
                },
            },
            "required": ["target", "message"],
        },
    },
]

با قرار دادن TTS در یک اعلان تابع، مدل، گفتار را از طریق همان مسیر فراخوانی ابزار مانند هر اقدام ربات دیگری مدیریت می‌کند. برنامه شما این فراخوانی را با یک فراخوانی برگشتی تزریق‌شده انجام می‌دهد.

مثال‌ها در گیت‌هاب

برای مثال‌های کاربردی کامل، از جمله دموی دریافت میان وعده توسط ربات Spot و سلام دنیا توسط Tinybot، به مثال‌های Robotics Live API مراجعه کنید.

قدم بعدی چیست؟