الروبوتات مع البث

تعرض نقطة نهاية نموذج gemini-robotics-er-2-streaming-preview نقطة نهاية مخصّصة للبث تتكامل مع Live API، ما يتيح التفاعل الثنائي الاتجاه في الوقت الفعلي بين تطبيقك والروبوت. ويجعل ذلك هذه النقطة مناسبة للوكلاء الذين يحتاجون إلى حلقات ملاحظات سريعة وردود فعل تفاعلية على البيئة.

حالات الاستخدام

  • تنسيق عدة روبوتات: تتواصل روبوتات متعددة بشأن حالة المهمة وتفوّض المهام الفرعية من خلال جلسة مشترَكة.
  • المراقبة المستمرة: تراقب الروبوتات مشهدًا وتفعِّل الإجراءات عند وقوع أحداث معيّنة، مثل وصول حاوية إلى مستوى معيّن من الملء.
  • المستودعات والخدمات اللوجستية: وكلاء الانتقاء والتعبئة الذين يتحقّقون من العناصر مرئيًا ويتتبّعون تقدّم التعبئة ويستردّون البيانات من الأخطاء.

المواصفات الفنية

يُوضّح الجدول التالي المواصفات الفنية لـ Live API:

الفئة التفاصيل
طرق الإدخال الصوت (صوت PCM غير معالَج بمعدّل 16 بت، و16 كيلوهرتز، وترتيب البايتات الصغير)، والصور (JPEG بمعدّل لقطة واحدة في الثانية أو أقل)، والنص
طرق الإخراج نص
البروتوكول اتصال WebSocket ذو حالة (WSS)

إنشاء إعداد وكيل

تتّبع كل وكيل روبوتات تم إنشاؤه على Live API ثلاث خطوات:

  1. التعريف بإمكانات الروبوت كأدوات يصبح كل إجراء يمكن للروبوت تنفيذه، مثل التنقّل أو الإمساك أو التحدّث، إعلانًا عن دالة باسم ووصف ومخطط للوسيطات. يجب أن تستخدم الإجراءات المادية "behavior": "BLOCKING" حتى ينتظر النموذج انتهاء الروبوت قبل اختيار الخطوة التالية.
  2. بث الإدخال المتعدد الوسائط في جلسة مستمرة : يجب فتح جلسة live.connect وإبقاؤها مفتوحة طوال مدة المهمة. يجب إرسال لقطات الفيديو أو الصوت أو النص عند وصولها من أجهزة استشعار الروبوت.
  3. التعامل مع طلبات الأدوات في حلقة الاستلام : في كل مرة يختار فيها النموذج إجراءً، يرسل رسالة tool_call. تنفِّذ حلقة الاستلام الدالة على حزمة تطوير البرامج (SDK) للروبوت وترسل ردًا tool_response. تبقى الجلسة مفتوحة، ويختار النموذج الإجراء التالي استنادًا إلى النتيجة.

توضّح الأقسام التالية كيفية تطبيق هذه الخطوات على ثلاثة أنماط شائعة: حلقة وكيل أساسية، ومراقبة استباقية للمشهد باستخدام إشارة نبض، وتوجيه الكلام من خلال تحويل النص إلى كلام (TTS) كأداة.

تنسيق الروبوت من خلال استدعاء الدوال

يُوضّح المثال التالي جميع الخطوات الثلاث معًا في نص برمجي واحد بلغة Python.

تعلن الخطوة 1، وهي تعريفات الأدوات، عن إمكانات الروبوت كإعلانات عن الدوال. تستخدم الدالة navigate السمة "behavior": "BLOCKING" حتى ينتظر النموذج وصول الروبوت إلى نقطة الطريق قبل استدعاء أداة أخرى. يجب إضافة المزيد من إعلانات الدوال في القائمة نفسها لعرض إمكانات إضافية للروبوت.

توضّح الخطوة 2، وهي أدوات مساعدة الإدخال، ثلاث دوال تبث مدخلات مختلفة من الوسائط إلى الجلسة: send_text للأوامر، وsend_image للقطات الكاميرا مع طلب نصي اختياري، وsend_audio للصوت الخام بتنسيق PCM من ميكروفون.

تعمل الخطوة 3، وهي حلقة الاستلام، بشكل متزامن وتتعامل مع نوعَين من الرسائل: رسائل server_content (الناتج النصي للنموذج) ورسائل tool_call (النموذج الذي يطلب إجراءً من الروبوت). عند وصول طلب أداة، تستدعي الحلقة execute_tool، وهو رمز بديل يتم استبداله بحزمة تطوير البرامج (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())

تبقى حلقة الاستلام نشطة بعد كل رد على الأداة. ينشئ النموذج خطة طويلة الأجل ويعدّلها بدون أن يتم ترميز تسلسل الإجراء بأكمله مسبقًا.

الاستدلال الاستباقي المكاني الزماني

يبث Live API الفيديو، ولكن لقطات الفيديو وحدها لا تؤدي إلى بدء دورة استدلال جديدة. يجب أن تكون لقطات الفيديو مصحوبة بطلب نصي أو صوتي لتفعيل ردّ النموذج. يُرجى الاطّلاع على إمكانات Live API لمزيد من التفاصيل.

لتفعيل الاستدلال الاستباقي، يجب تنفيذ إشارة نبض: إرسال أحدث لقطة من الكاميرا بشكل دوري متبوعة بطلب نصي قصير يجبر النموذج على فحص المشهد واتخاذ قرار صريح. يتم تحديد معدّل إدخال الفيديو بلقطة واحدة في الثانية.

أضف هذا الكوروتين إلى جانب حلقة الاستلام من القسم السابق. ويتم تشغيلها كمهمة 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)

لا حاجة إلى إيقاف إشارة النبض مؤقتًا أثناء إجراءات الروبوت. عند استخدامها كـ أداة رصد النجاح الضمني، يتيح إبقاؤها قيد التشغيل للنموذج مراقبة الإجراء قيد التنفيذ باستمرار (تتبُّع ما إذا كانت عملية الإمساك آمنة أو كان الصب على الهدف أو كان وضع العنصر صحيحًا) والرد في اللحظة التي تصبح فيها النتيجة واضحة.

تعمل رسائل إشارة النبض كدورات للمستخدم وتقاطع عملية إنشاء النموذج قيد التنفيذ. يُرجى الاطّلاع على دليل Live API بشأن الانقطاعات لفهم كيفية تعامل Live API مع هذا السلوك.

مصدر إخراج الصوت من خلال تحويل النص إلى كلام (TTS) خارجي

تعرض Gemini Robotics ER 2 نصًا. يوجه تطبيقك الردود المكتملة إلى مزوّد منفصل لخدمة تحويل النص إلى كلام (مثل Gemini 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"],
        },
    },
]

من خلال تضمين تحويل النص إلى كلام في إعلان دالة، يعالج النموذج الكلام من خلال مسار طلب الأداة نفسه الذي يتم من خلاله معالجة أي إجراء آخر من إجراءات الروبوت. ينفِّذ تطبيقك الطلب باستخدام معاودة الاتصال التي يتم إدخالها.

أمثلة على GitHub

للاطّلاع على أمثلة عملية كاملة، بما في ذلك العرض التوضيحي لجلب الوجبات الخفيفة لروبوت Spot والعرض التوضيحي "مرحبًا بالعالم" لروبوت Tinybot الذي يمكنه الإمالة والتدوير، يُرجى الاطّلاع على أمثلة Robotics Live API.

الخطوات التالية