# المعالجات للروبوتات والمشغّلين عن بُعد

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

نستخدم أمثلة المتبوع Phone إلى SO‑100 للتوضيح، لكن الأنماط نفسها تنطبق على الروبوتات الأخرى.

**ما ستتعلمه**

- التحكم المطلق مقابل التحكم النسبي في EE: ما يعنيه كل منهما، والمقايضات، وكيفية الاختيار لمهمتك.
- نمط ثلاث مراحل: كيفية تحويل إجراءات التشغيل عن بُعد إلى إجراءات مجموعة البيانات ثم إلى أوامر الروبوت، وكيفية تحويل ملاحظات الروبوت إلى ملاحظات مجموعة البيانات.
- Adapters (`to_transition` / `to_output`): كيف تُحوِّل هذه القواميس الخام إلى `EnvTransition` ثم تُرجعها إلى شكلها الأصلي لتقليل التكرار في الكود.
- عقود ميزات مجموعة البيانات: كيف تُعلن الخطوات عن الميزات عبر `transform_features(...)`، وكيفية تجميعها/دمجها للتسجيل.
- اختيار تمثيل: متى نخزّن المفاصل، أو أوضاع الطرف النهائي المطلقة، أو دلتا الطرف النهائي النسبية — وكيف يؤثر ذلك على التدريب.
- إرشادات تخصيص خط الأنابيب: كيفية تبديل الروبوتات/ملفات URDF بأمان وضبط الحدود وحجم الخطوات وخيارات مثل تهيئة IK.

### التحكم المطلق مقابل التحكم النسبي في EE

تستخدم الأمثلة في هذا الدليل أوضاعًا مطلقة لمفصل الطرف النهائي (EE) لأنها يسهل الاستدلال عليها. في الممارسة العملية، يُفضَّل غالبًا استخدام دلتا مفصل الطرف النهائي النسبية أو موضع المفاصل كميزات للتعلم.

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

## ثلاث خطوط أنابيب

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

1. خط أنابيب 1: مساحة أفعال التشغيل عن بُعد → مساحة أفعال مجموعة البيانات (وضعية الهاتف → أهداف الطرف النهائي)
2. خط أنابيب 2: مساحة إجراءات مجموعة البيانات → مساحة أوامر الروبوت (أهداف الطرف النهائي → المفاصل)
3. خط أنابيب 3: مساحة ملاحظة الروبوت → مساحة ملاحظة مجموعة البيانات (المفاصل → وضعية الطرف النهائي)

فيما يلي مثال على خطوط الأنابيب الثلاثة التي نستخدمها في أمثلة المتبوع من الهاتف إلى SO-100:

```python
phone_to_robot_ee_pose_processor = RobotProcessorPipeline[tuple[RobotAction, RobotObservation], RobotAction]( # teleop -> dataset action
    steps=[
        MapPhoneActionToRobotAction(platform=teleop_config.phone_os),
        EEReferenceAndDelta(
            kinematics=kinematics_solver, end_effector_step_sizes={"x": 0.5, "y": 0.5, "z": 0.5}, motor_names=list(robot.bus.motors.keys()),
        ),
        EEBoundsAndSafety(
            end_effector_bounds={"min": [-1.0, -1.0, -1.0], "max": [1.0, 1.0, 1.0]}, max_ee_step_m=0.20,
        ),
        GripperVelocityToJoint(),
    ],
    to_transition=robot_action_observation_to_transition,
    to_output=transition_to_robot_action,
)

robot_ee_to_joints_processor = RobotProcessorPipeline[tuple[RobotAction, RobotObservation], RobotAction]( # dataset action -> robot
    steps=[
        InverseKinematicsEEToJoints(
            kinematics=kinematics_solver, motor_names=list(robot.bus.motors.keys()), initial_guess_current_joints=True,
        ),
    ],
    to_transition=robot_action_observation_to_transition,
    to_output=transition_to_robot_action,
)

robot_joints_to_ee_pose = RobotProcessorPipeline[RobotObservation, RobotObservation]( # robot obs -> dataset obs
    steps=[
        ForwardKinematicsJointsToEE(kinematics=kinematics_solver, motor_names=list(robot.bus.motors.keys()))
    ],
    to_transition=observation_to_transition,
    to_output=transition_to_observation,
)
```

## لماذا to_transition / to_output

لتحويل البيانات من الروبوت/المشغّل عن بُعد إلى خط المعالجة والعكس، نستخدم مُكيّفات خط المعالجة `to_transition` و`to_output`. تُوحّد هذه المُكيّفات عمليات التحويل لتقليل الأكواد المتكررة، وتشكّل الجسر بين القواميس الخام للروبوت والمشغّل عن بُعد وصيغة `EnvTransition` الخاصة بخط المعالجة. في أمثلة المتابعة من الهاتف إلى SO-100، نستخدم المُكيّفات التالية:

- `robot_action_observation_to_transition`: يحوّل زوج `(action, robot observation)` إلى انتقال في خط الأنابيب (تحتاج خطوتا EE وIK إلى الموضع الحالي لمفاصل الروبوت).
- `transition_to_robot_action`: يحوّل انتقال خط الأنابيب إلى قاموس إجراء للروبوت.
- `observation_to_transition`: يحوّل قاموس ملاحظة الروبوت إلى انتقال في خط الأنابيب.
- `transition_to_observation`: يحوّل انتقال خط الأنابيب إلى قاموس ملاحظة.

اطّلع على [src/lerobot/processor/converters.py](https://github.com/huggingface/lerobot/blob/main/src/lerobot/processor/converters.py) لمزيد من التفاصيل.

## عقود ميزات مجموعة البيانات

تُحدَّد ميزات مجموعة البيانات بالمفاتيح المحفوظة فيها. يمكن لكل خطوة أن تُعلن عن الميزات التي تعدّلها في عقد يُسمّى `transform_features(...)`. بعد بناء المعالج، يمكن للمعالج تجميع جميع هذه الميزات باستخدام `aggregate_pipeline_dataset_features()` ودمج قواميس الميزات المتعددة باستخدام `combine_feature_dicts(...)`.

فيما يلي مثال على كيفية إعلان الميزات باستخدام طريقة `transform_features` في أمثلة المتبوع من الهاتف إلى SO-100:

```python
    def transform_features(
        self, features: dict[PipelineFeatureType, dict[str, PolicyFeature]]
    ) -> dict[PipelineFeatureType, dict[str, PolicyFeature]]:
        # We only use the ee pose in the dataset, so we don't need the joint positions
        for n in self.motor_names:
            features[PipelineFeatureType.ACTION].pop(f"{n}.pos", None)
        # We specify the dataset features of this step that we want to be stored in the dataset
        for k in ["x", "y", "z", "wx", "wy", "wz", "gripper_pos"]:
            features[PipelineFeatureType.ACTION][f"ee.{k}"] = PolicyFeature(
                type=FeatureType.STATE, shape=(1,)
            )
        return features
```

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

فيما يلي مثال على كيفية تجميعنا ودمجنا للميزات في مثال تسجيل الهاتف إلى SO-100:

```python
features=combine_feature_dicts(
        # Run the feature contract of the pipelines
        # This tells you how the features would look like after the pipeline steps
        aggregate_pipeline_dataset_features(
            pipeline=phone_to_robot_ee_pose_processor,
            initial_features=create_initial_features(action=phone.action_features), # <- Action features we can expect, these come from our teleop device (phone) and action processor
            use_videos=True,
        ),
        aggregate_pipeline_dataset_features(
            pipeline=robot_joints_to_ee_pose,
            initial_features=create_initial_features(observation=robot.observation_features), # <- Observation features we can expect, these come from our robot and observation processor
            use_videos=True,
            patterns=["observation.state.ee"], # <- Here you could optionally filter the features we want to store in the dataset, with a specific pattern

        ),
    ),
```

كيف يعمل:

- `aggregate_pipeline_dataset_features(...)`: يطبّق `transform_features` عبر خط الأنابيب ويصفّي حسب الأنماط (تُضمَّن الصور عندما يكون `use_videos=True`، وتُضمَّن ميزات الحالة عندما يُحدَّد `patterns`).
- `combine_feature_dicts(...)`: دمج عدة قواميس ميزات.
- يستخدم التسجيل عبر `record_loop(...)` الدالة `build_dataset_frame(...)` لبناء إطارات متوافقة مع `dataset.features` قبل استدعاء `add_frame(...)` لإضافة الإطار إلى مجموعة البيانات.

## إرشادات عند تخصيص خطوط أنابيب الروبوت

يمكنك تخزين أي من الميزات التالية كمساحة إجراء/ملاحظة:

- مواضع المفاصل
- وضعيات EE المطلقة
- الفروقات النسبية في EE
- مزايا أخرى: السرعة المشتركة، العزوم، وما إلى ذلك.

اختر ما تريد استخدامه لفضاء إجراء السياسة وملاحظة السياسة، ثم اضبط/عدّل خطوط الأنابيب والخطوات وفقاً لذلك.

### روبوتات مختلفة

- يمكنك إعادة استخدام خطوط الأنابيب بسهولة، على سبيل المثال لاستخدام روبوت آخر مع التحكم عن بُعد عبر الهاتف، وذلك بتعديل الأمثلة واستبدال `RobotKinematics` (URDF) و`motor_names` لاستخدام روبوتك الخاص مع التحكم عن بُعد عبر الهاتف. بالإضافة إلى ذلك، يجب عليك التأكد من أن `target_frame_name` يشير إلى قابض/معصم روبوتك.

### الأمان أولاً

- عند تغيير خطوط الأنابيب، ابدأ بحدود صارمة، ونفّذ خطوات السلامة عند العمل مع روبوتات حقيقية.
- يُنصح بالبدء بالمحاكاة أولاً ثم الانتقال إلى الروبوتات الحقيقية.

هذا كل شيء! نأمل أن يساعدك هذا الدليل في البدء بتخصيص خطوط أنابيب روبوتاتك. إذا واجهت أي مشكلات في أي نقطة، فانتقل إلى [مجتمع Discord](https://discord.com/invite/s3KuuzsPFb) لدينا للحصول على الدعم.

