LeRobot documentation
هاتف
هاتف
استخدم هاتفك (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 لبث وضعية الجسم.
روابط:
- مكتبة Android WebXR:
teleopعلى PyPI - تطبيق iOS: HEBI Mobile I/O
اتجاه الهاتف والتحكم
- الاتجاه: امسك الهاتف بحيث تكون الشاشة موجهة للأعلى والحافة العلوية موجهة في نفس اتجاه ملقط الروبوت. يضمن هذا أن تُحاذاة المعايرة إطار الهاتف مع إطار الروبوت بحيث تبدو الحركة طبيعية، راجع الصورة أدناه للاسترشاد.
- تفعيل/تعطيل — هذا هو مفتاح إيقاف الطوارئ، يجب عليك إبقاء الزر مضغوطًا طوال الحركة:
- iOS: اضغط باستمرار على
B1لتحريك الروبوت، وأفلت الزر لتجميد الذراع في موضعها الحالي. كل ضغطة تعيد تثبيت الهاتف على الوضعية الحالية للذراع، مما يتيح لك الإفلات، وإرجاع يدك إلى موضع مريح، والضغط مرة أخرى، والمواصلة — دون أن يقفز الروبوت. - أندرويد: الأمر نفسه مع زر
Moveفي صفحة WebXR.
- iOS: اضغط باستمرار على
- التحكم في الماسك (يعمل سواء كان زر التفعيل مضغوطًا أم لا):
- iOS: يتحكم منزلق
A3في الماسك كمدخل سرعة — ادفعه للأعلى لفتحه، واسحبه للأسفل لإغلاقه، وأفلته في المنتصف لتثبيته. - أندرويد: تعمل الأزرار
AوBكزيادة/نقصان (يفتح A ويغلق B). يمكنك ضبط السرعة في خطوةGripperVelocityToJoint.
- iOS: يتحكم منزلق
- القبضة: امسك الهاتف بـاليدَين، بإبهام واحد على زر التفعيل (
B1) والآخر على منزلق الماسك (A3)، بحيث يمكنك تشغيل الذراع والماسك في الوقت نفسه دون تغيير القبضة. حافظ على استواء الهاتف أثناء ذلك — فوضعه هو الأمر، لذا فإن تغيير القبضة أثناء الحركة سيحرّك الروبوت. - وضعية بدء الروبوت:
teleoperate.pyيحرّك الذراع إلى وضعية العودة عند التشغيل (قبل معايرة الهاتف)، وعند الضغط على Ctrl+C يعيدها إلى الموضع الذي كانت عليه عند بدء تشغيل السكربت. تأمر أوامر العودة كل مفصل في الجسم بالقيمة النصفية للدوران التي تمركزت عليهاset_half_turn_homings()أثناء المعايرة — وهي الوضعية المعروضة في مخطط المعايرة — بينما يُترك الماسك في مكانه حتى لا تُغلقه عملية العودة على شيء ما. وهذا أمر مهم لأن الأهداف تُحسب باستخدام IK من أي موضع تكون عليه الذراع عند الضغط على زر التفعيل — فالذراع المطوية أو الممدودة بالكامل لا تملك مساحة كافية وقد تصطدم بحدود مفاصلها. أما السكربتات الأخرى الموضحة كمثال (record.py،evaluate.py،replay.py) فلا تُعيد الذراع إلى وضعية العودة، لذا ضعها بنفسك في ذلك الموضع قبل بدء تشغيلها.
الخطوة 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 من التكوين الحالي للذراع.