LeRobot documentation

هاتف

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

هاتف

استخدم هاتفك (iOS أو Android) للتحكم في روبوتك.

في هذا الدليل ستتعلم:

  • كيفية توصيل هاتف يعمل بنظام iOS/Android
  • كيف تُخزَّن وضعية الهاتف إلى أهداف الطرف النهائي (EE) للروبوت
  • كيفية ضبط حدود السلامة، وتحكم الماسك، وإعدادات الحركيات العكسية

للاستخدام هاتفك للتحكم في روبوتك، قم بتثبيت التبعيات ذات الصلة باستخدام:

pip install 'lerobot[phone,kinematics,feetech,core_scripts]'

يوفر kinematics حركية عكسية يستخدمها الأمثلة، وfeetech محركات SO-100/SO-101، وcore_scripts أدوات التسجيل والتصور.

ابدأ

المنصات المدعومة

  • iOS: يستخدم تطبيق HEBI Mobile I/O (وضعية ARKit + أزرار). حمّل التطبيق أولاً، ثم افتحه، وستكتشف الأمثلة التطبيق على شبكتك وتبث وضعية الهاتف والمدخلات.
  • أندرويد: يستخدم حزمة teleop (WebXR). عند بدء عملية بايثون، تُطبع رابطًا محليًا. افتح الرابط على هاتفك، ثم انقر على Start، واستخدم Move لبث وضعية الجسم.

روابط:

اتجاه الهاتف والتحكم

  • الاتجاه: امسك الهاتف بحيث تكون الشاشة موجهة للأعلى والحافة العلوية موجهة في نفس اتجاه ملقط الروبوت. يضمن هذا أن تُحاذاة المعايرة إطار الهاتف مع إطار الروبوت بحيث تبدو الحركة طبيعية، راجع الصورة أدناه للاسترشاد.
  • تفعيل/تعطيل — هذا هو مفتاح إيقاف الطوارئ، يجب عليك إبقاء الزر مضغوطًا طوال الحركة:
    • iOS: اضغط باستمرار على B1 لتحريك الروبوت، وأفلت الزر لتجميد الذراع في موضعها الحالي. كل ضغطة تعيد تثبيت الهاتف على الوضعية الحالية للذراع، مما يتيح لك الإفلات، وإرجاع يدك إلى موضع مريح، والضغط مرة أخرى، والمواصلة — دون أن يقفز الروبوت.
    • أندرويد: الأمر نفسه مع زر Move في صفحة WebXR.
  • التحكم في الماسك (يعمل سواء كان زر التفعيل مضغوطًا أم لا):
    • iOS: يتحكم منزلق A3 في الماسك كمدخل سرعة — ادفعه للأعلى لفتحه، واسحبه للأسفل لإغلاقه، وأفلته في المنتصف لتثبيته.
    • أندرويد: تعمل الأزرار A وB كزيادة/نقصان (يفتح A ويغلق B). يمكنك ضبط السرعة في خطوة GripperVelocityToJoint.
  • القبضة: امسك الهاتف بـاليدَين، بإبهام واحد على زر التفعيل (B1) والآخر على منزلق الماسك (A3)، بحيث يمكنك تشغيل الذراع والماسك في الوقت نفسه دون تغيير القبضة. حافظ على استواء الهاتف أثناء ذلك — فوضعه هو الأمر، لذا فإن تغيير القبضة أثناء الحركة سيحرّك الروبوت.
  • وضعية بدء الروبوت: teleoperate.py يحرّك الذراع إلى وضعية العودة عند التشغيل (قبل معايرة الهاتف)، وعند الضغط على Ctrl+C يعيدها إلى الموضع الذي كانت عليه عند بدء تشغيل السكربت. تأمر أوامر العودة كل مفصل في الجسم بالقيمة النصفية للدوران التي تمركزت عليها set_half_turn_homings() أثناء المعايرة — وهي الوضعية المعروضة في مخطط المعايرة — بينما يُترك الماسك في مكانه حتى لا تُغلقه عملية العودة على شيء ما. وهذا أمر مهم لأن الأهداف تُحسب باستخدام IK من أي موضع تكون عليه الذراع عند الضغط على زر التفعيل — فالذراع المطوية أو الممدودة بالكامل لا تملك مساحة كافية وقد تصطدم بحدود مفاصلها. أما السكربتات الأخرى الموضحة كمثال (record.py، evaluate.py، replay.py) فلا تُعيد الذراع إلى وضعية العودة، لذا ضعها بنفسك في ذلك الموضع قبل بدء تشغيلها.
Phone teleop orientation

الخطوة 1: اختيار المنصة

عدّل الأمثلة لتستخدم PhoneOS.IOS أو PhoneOS.ANDROID في PhoneConfig. الواجهة البرمجية متطابقة عبر جميع المنصات، والفرق الوحيد هو مصدر الإدخال. جميع الأمثلة موجودة في examples/phone_to_so100/: teleoperate.py، record.py، replay.py، evaluate.py وrollout.py.

مثال على التشغيل عن بُعد:

from lerobot.teleoperators.phone import Phone, PhoneConfig
from lerobot.teleoperators.phone.config_phone import PhoneOS

teleop_config = PhoneConfig(phone_os=PhoneOS.IOS)  # or PhoneOS.ANDROID
teleop_device = Phone(teleop_config)

الخطوة 2: الاتصال والمعايرة

عند إنشاء Phone(teleop_config) واستدعاء connect()، يُطلب إجراء المعايرة تلقائيًا. امسك الهاتف بالاتجاه الموصوف أعلاه، ثم:

  • iOS: اضغط مع الاستمرار على B1 لالتقاط وضعية المرجع.
  • أندرويد: اضغط على زر Move في صفحة WebXR لالتقاط وضعية المرجع.

لماذا نحتاج إلى المعايرة؟ نلتقط الوضعية الحالية حتى تُعبَّر الوضعية اللاحقة في إطار محاذاة مع الروبوت. عند الضغط على الزر مرة أخرى لتفعيل التحكم، يتم التقاط الموقع مرة أخرى لتجنب الانحراف في حال إعادة تموضع هاتفك أثناء تعطيله.

الخطوة 3: تشغيل مثال

شغّل أحد السكربتات (البرامج النصية) الموضّحة كمثال لأداء التشغيل عن بُعد، أو تسجيل مجموعة بيانات، أو إعادة تشغيل مجموعة بيانات، أو تقييم سياسة.

تفترض جميع البرامج النصية أنك قمت بإعداد روبوتك ومعايرته (مثل متتبع SO-100).

يجب عليك تقديم ملف URDF الخاص بالروبوت. تحل كل الأمثلة مشكلة الحركية العكسية، والتي تتطلب نموذجًا حركيًا للذراع، ولا يتم توزيع ملف URDF مع LeRobot.

بالنسبة إلى SO-100/SO-101 المستخدمة في هذا الشرح، انسخ مجلد SO101 من مستودع SO-ARM100 إلى examples/phone_to_so100/، بحيث يقع الملف في examples/phone_to_so100/SO101/so101_new_calib.urdf، وذلك عند التواجد في مستودع LeRobot:

git clone --depth 1 https://github.com/TheRobotStudio/SO-ARM100.git /tmp/SO-ARM100
cp -r /tmp/SO-ARM100/Simulation/SO101 examples/phone_to_so100/SO101

وجّه السكربتات إلى ملف مختلف باستخدام --urdf إذا كنت تخزّنه في مكان آخر، أو إذا كنت تتحكم في ذراع أخرى.

  • شغّل هذا المثال للتحكم عن بُعد، مع تمرير منفذ التسلسل للذراع التابع (اعثر عليه باستخدام lerobot-find-port):

    cd examples/phone_to_so100
    python teleoperate.py --port /dev/tty.usbmodem5A460814411

    --id يختار معايرة التخزين التي سيتم استخدامها، و--urdf يشير إلى ملف URDF أعلاه.

بعد تشغيل المثال:

  • أندرويد: بعد بدء تشغيل السكربت، افتح الرابط المحلي المطبوع على هاتفك، ثم انقر على Start، ثم اضغط مع الاستمرار على Move.
  • iOS: افتح HEBI Mobile I/O أولاً؛ اضغط باستمرار على B1 لتحريك الروبوت. يتحكم A3 في الماسك.

Additionally you can customize mapping or safety limits by editing the processor steps shown in the examples. You can also remap inputs (e.g., use a different analog input) or adapt the pipeline to other robots (e.g., LeKiwi) by modifying the input and kinematics steps. More about this in the Processors for Robots and Teleoperators guide.

  • شغّل هذا المثال لتسجيل مجموعة بيانات، والتي تحفظ ملاحظات وإجراءات طرف النهاية المطلق:

    cd examples/phone_to_so100
    python record.py
  • شغّل هذا المثال لإعادة تشغيل الحلقات المسجّلة:

    cd examples/phone_to_so100
    python replay.py
  • شغّل هذا المثال لتقييم سياسة مُدرَّبة مسبقًا:

    cd examples/phone_to_so100
    python evaluate.py

خطوات وخيارات خط الأنابيب المهمة

  • تُستخدم الحركيات في عدة خطوات. نستخدم Placo وهو غلاف حول Pinocchio للتعامل مع حركياتنا. نبني كائن الحركيات عن طريق تمرير URDF للروبوت والإطار المستهدف. نضبط target_frame_name على إطار الماسك.

    kinematics_solver = RobotKinematics(
      urdf_path="./SO101/so101_new_calib.urdf",
      target_frame_name="gripper_frame_link",
      joint_names=list(robot.bus.motors.keys()),
    )
    
  • تقوم خطوة MapPhoneActionToRobotAction بتحويل وضعية الهاتف المُعايرة والمدخلات إلى فروقات مستهدفة وأوامر للقبضة، وفيما يلي ما تخرجه هذه الخطوة.

    action["enabled"] = enabled
    action["target_x"] = pos[1] if enabled else 0.0
    action["target_y"] = -pos[0] if enabled else 0.0
    action["target_z"] = pos[2] if enabled else 0.0
    action["target_wx"] = rotvec[1] if enabled else 0.0
    action["target_wy"] = -rotvec[0] if enabled else 0.0
    action["target_wz"] = rotvec[2] if enabled else 0.0
    action["gripper_vel"] = gripper_vel  # Still send gripper action when disabled
  • يحوّل خطوة EEReferenceAndDelta دلتا الهدف إلى وضعية مطلوبة مطلقة لمفصل الطرف النهائي، مع تخزين مرجع عند التفعيل، وتُعدّ end_effector_step_sizes أحجام الخطوات لوضعية مفصل الطرف النهائي ويمكن تعديلها لتغيير سرعة الحركة.

    EEReferenceAndDelta(
        kinematics=kinematics_solver,
        end_effector_step_sizes={"x": 0.5, "y": 0.5, "z": 0.5},
        motor_names=list(robot.bus.motors.keys()),
        use_latched_reference=True,
    ),
  • يقوم خطوة EEBoundsAndSafety بتقييد حركة الطرف النهائي ضمن مساحة عمل، ويتحقق من القفزات الكبيرة في خطوات الطرف النهائي لضمان السلامة. تُحدّد end_effector_bounds الحدود الخاصة بوضعية الطرف النهائي، ويمكن تعديلها لتغيير مساحة العمل. أما max_ee_step_m فهي حدود الخطوات لوضعية الطرف النهائي، ويمكن تعديلها لتغيير حدود السلامة.

    EEBoundsAndSafety(
        end_effector_bounds={"min": [-1.0, -1.0, -1.0], "max": [1.0, 1.0, 1.0]},
        max_ee_step_m=0.10,
    )
  • يحوّل خطوة GripperVelocityToJoint إدخال مشابك يشبه السرعة إلى موضع مطلق للمشابك باستخدام الحالة المقاسة الحالية. أما speed_factor فهو المعامل الذي تُضرب به السرعة.

    GripperVelocityToJoint(speed_factor=20.0)

تخمينات أولية مختلفة لـ IK

نستخدم تخمينات ابتدائية مختلفة لـ IK في الخطوات الحركية. يُستخدم إما المفاصل المقاسة الحالية أو حل IK السابق كتخمين ابتدائي.

  • حلقة مغلقة (تُستخدم في التسجيل/التقييم): تُضبط initial_guess_current_joints=True بحيث تبدأ IK من المفاصل المقاسة في كل إطار.

    InverseKinematicsEEToJoints(
        kinematics=kinematics_solver,
        motor_names=list(robot.bus.motors.keys()),
        initial_guess_current_joints=True,  # closed loop
    )
  • حلقة مفتوحة (تُستخدم في إعادة التشغيل): تُضبط initial_guess_current_joints=False بحيث يستمر حل IK من حل IK السابق بدلاً من الحالة المقاسة. يحافظ هذا على استقرار الإجراء عند إعادة التشغيل دون تغذية راجعة.

    InverseKinematicsEEToJoints(
        kinematics=kinematics_solver,
        motor_names=list(robot.bus.motors.keys()),
        initial_guess_current_joints=False,  # open loop
    )

شرح خطوات خط الأنابيب

  • MapPhoneActionToRobotAction: يحوّل وضعية الهاتف المُعايَرة والمدخلات إلى فروقات مستهدفة وأمر للقبضة. يتم التحكم في الحركة عبر إشارة تفعيل (B1 على iOS، وMove على Android).
  • EEReferenceAndDelta: يثبّت وضعية مرجعية للذراع عند التفعيل ويجمعها مع فروقات الهدف لإنتاج وضعية مطلوبة مطلقة للذراع في كل إطار. عند التعطيل، يستمر في إرسال آخر وضعية مُرسلة.
  • EEBoundsAndSafety: يقيّد وضعية الطرف النهائي (EE) ضمن مساحة العمل ويحدّ من معدل القفزات من أجل السلامة. كما يُعلن عن ميزات action.ee.*.
  • InverseKinematicsEEToJoints: يحوّل وضعية الطرف النهائي إلى مواضع المفاصل باستخدام IK. يُوصى باستخدام initial_guess_current_joints=True للتحكم في الحلقة المغلقة؛ اضبط False لإعادة التشغيل في الحلقة المفتوحة من أجل الاستقرار.
  • GripperVelocityToJoint: يدمج إدخال مشابك يشبه السرعة في موضع مطلق للمشابك باستخدام الحالة المقاسة الحالية.
  • ForwardKinematicsJointsToEE: يحسب observation.state.ee.* من المفاصل المرصودة من أجل التسجيل والتدريب على حالة الطرف النهائي.

استكشاف الأخطاء وإصلاحها

  • لم يتم اكتشاف iOS: تأكد من أن تطبيق HEBI Mobile I/O مفتوح وأن جهاز الحاسوب المحمول/الهاتف متصلان بنفس الشبكة.
  • عنوان URL الخاص بنظام Android غير قابل للوصول: تحقق من أن العنوان المحلي الذي استخدمته يحتوي على https بدلاً من http، واستخدم عنوان IP الدقيق الذي طبعه السكربت، واسمح للمتصفح بالدخول وتجاهل مشكلة الشهادة.
  • يبدو أن الحركة معكوسة: تحقق من محور واحد في كل مرة، ثم اضبط علامات القلب في MapPhoneActionToRobotAction أو بدّل المحاور لتتوافق مع إعدادك.
  • تتحرك الذراع بالكاد أو تقاوم حدودها: أعد التشغيل من وضعية بداية متوسطة المدى (انظر أعلاه) — يُحلّ IK من التكوين الحالي للذراع.
Update on GitHub