# בנימין, בוא נפעיל את שתי הזרועות

## מדריך עבודה ל־SO-101 — מהחיבור הראשון ועד leader → follower

אני Claude, העוזר של יוסף. יוסף ביקש ממני לעזור לך; קראתי את כל השיחה ביניכם, הקשבתי להודעה הקולית שלך (דרך התמלול שלה) וראיתי את שלושת הצילומים — ואני מכיר את הפרויקט.

יוסף ביקש שאמסור לך שהוא מצטער שזה לוקח כל כך הרבה זמן. הוא מגיע מחר, **7.10.2026, בשעה 11:00**, ונעבוד על שתי הזרועות יחד.

עברתי על כל השיחה הזמינה ביניכם, מתחילתה, על שלושת הצילומים ועל התמלול המלא של ההודעה הקולית שלך מ־4.10 בשעה 11:20. את ההקלטה בדקתי דרך התמלול; במקום שבו המילה אינה ברורה, לא אנחש. קראתי גם את תיעוד SO-101, הוראות Feetech וקוד LeRobot שאליו מתייחס המדריך.

כבר בנית את ה־leader ואת ה־follower. אתה לא צריך להתחיל מחדש, ולא צריך ללמוד עכשיו את כל Python. צריך להפריד בין שתי התקלות שתיארת, להגיע לתקשורת יציבה עם כל זרוע, ואז לכייל ולהפעיל מעקב. כתבת שאתה מכיר C#; לכן הפקודות כאן מוסברות כמו כלי עבודה, עם מה מקלידים, מה מצפים לראות ומה עושים אם זה נכשל.

**המסלול שלך:** זיהוי מתח וחיווט → זיהוי COM → קריאת מנועים → תיקון כתובות או קושחה לפי הממצא → כיול → תנועה ראשונה. בזרוע שבה כבר ראית שש גרסאות, מתחילים מבעיית הקושחה. בזרוע שמחזירה רשימה ריקה, מתחילים מתקשורת והזנת מתח. אין טעם לצרוב מנוע שעדיין לא מצליחים לקרוא ממנו.

> המסמך הוא תוכנית עבודה המבוססת על מה ששלחת ועל המקור הרשמי. הפקודות נבדקו מול קוד המקור; הן עדיין לא נוסו כאן על מחשב Windows והזרועות שלך. תוצאות לדוגמה מסומנות כדוגמאות, ולא כהצלחה שכבר הושגה.

[TOC]

## 1. מה בנית, ומה התוכנה אמורה לעשות

ה־**leader** הוא הזרוע שאתה מזיז ביד. חיישני המיקום שבמנועים שלה מודדים את מצב המפרקים. ה־**follower** הוא הזרוע המונעת: היא מקבלת מהמחשב מטרות מיקום ומנסה להגיע אליהן. המחשב מריץ את LeRobot, שקורא את המפרקים בצד הראשון ושולח פקודות למפרקים המקבילים בצד השני.

```text
Your hand -> Leader joints -> USB board L -> Windows / LeRobot
                                                   |
                                                   v
                                    USB board F -> Follower joints

Power supply L -> Board L -> Leader motors 1..6
Power supply F -> Board F -> Follower motors 1..6
```

בתוך כל זרוע יש שישה מנועים על אפיק תקשורת משותף, bus. לכל מנוע יש כתובת, ID, כדי שהמחשב יוכל לפנות אליו. המנוע כולל גם בקר פנימי: הוא מקבל יעד מיקום ועושה את העבודה החשמלית הדרושה כדי להגיע אליו. LeRobot אינו מזין ישירות את סלילי המנוע דרך USB.

המעקב הראשון אינו דורש מצלמה, אימון מודל, GPU או ROS. גם אין צורך בחיבור אינטרנט בזמן מעקב בסיסי שכבר הותקן. אינטרנט כן נדרש להורדת התוכנות ולעדכון מקוון של קושחה.

הכיול נותן לשני הצדדים שפה משותפת: מהי תנוחת אמצע ומהו הטווח של כל מפרק. בלי כיול מתאים, אותו מספר יכול לייצג תנוחות שונות. לכן העובדה שכל המנועים מופיעים ברשימה היא שער חשוב, אבל אינה אישור לשלוח מיד תנועות גדולות.

### חמישה מספרים ושמות שונים

| מה רואים | מה המשמעות | מה זה לא |
|---|---|---|
| `COM5` | הפורט הטורי של בקר USB במחשב מסוים | מספר של מנוע |
| `ID 3` | הכתובת של מנוע אחד באפיק של זרוע אחת | גרסת תוכנה |
| `3.10` | גרסת הקושחה שבתוך המנוע | Python 3.10 |
| `777` | מספר הדגם הצפוי ל־STS3215 בתשובת המנוע | קוד תקלה שצריך לתקן |
| `benjamin_follower` | שם שבחרנו לזרוע לצורך זיהוי ושמירת כיול | כתובת שנכתבת לכל מנוע |

לשתי הזרועות מותר להשתמש ב־IDs ‏1–6, כי לכל אחת בקר ואפיק נפרדים. לא מחברים את שתי שרשראות המנועים זו לזו. שם הזרוע בפקודה נשאר קבוע גם אם Windows משנה את מספר COM לאחר מעבר לשקע USB אחר.

## 2. מה אמרת בהקלטה — ומה עושים עם כל נקודה

ההקלטה שלך מ־4.10, בשעה 11:20, אורכה כ־62 שניות. להלן תוכן הדברים לפי התמלול, והתגובה המעשית לכל נקודה. הצבעים עוזרים לזהות את הזרועות, אבל לא קבעת בהקלטה איזו מהן leader ואיזו follower; לכן אני לא משייך להן תפקיד לפי צבע.

### א. יש שני רובוטים, כחול ולבן, ובשניהם בעיה

ננהל שתי בדיקות נפרדות. הדבק ליד כל בסיס פתק עם צבע ותפקיד. ליד כל בקר רשום את הפורט שמצאת, ואת הספק המיועד לו. כך לא נתקן את הגדרות ה־leader כשאנחנו חושבים שאנחנו מחוברים ל־follower.

כשהשלב הראשון נכשל, עובדים עם בקר אחד מחובר למחשב. אחרי שכל צד עובד בנפרד מחברים את שניהם. זה מצמצם בלבול בפורטים וגם מונע מסקנה שגויה מהחלפת כבלים בין הצדדים.

### ב. בראשון המחשב כן מזהה את הרובוט ואת המנועים

זה מתאים לתמונה הראשונה: מופיעה רשימה עם גרסת קושחה עבור כל אחת משש הכתובות. לכן בהרצה המצולמת הייתה תקשורת מספקת לקריאת הגרסאות. התקלה שם אינה פשוט ״Python לא מותקן״ או ״אין COM״.

הצעד הבא באותה זרוע הוא לקרוא את הגרסאות שוב בכלי Feetech ולבדוק מדוע העדכון לא הושלם. אין צורך למחוק את ההתקנה או לשנות את כל ה־IDs רק כי הכיול נעצר בבדיקת גרסאות.

### ג. חלק מהמנועים ב־3.10 וחלק ב־3.9

בתמונה המיפוי חד־משמעי: מנועים **3 ו־4** מדווחים 3.9; מנועים **1, 2, 5 ו־6** מדווחים 3.10. אלה גרסאות של הקושחה בתוך הסרוואים. התקנת Python אחר או עדכון חבילת pip לא צורבים אותן.

LeRobot בודק שהגרסאות באותו bus אחידות ועוצר כשיש ערבוב. המטרה היא גרסה משותפת שמתאימה לחומרה של כל המנועים באותה זרוע. נבדוק אם היצרן מציע למנועים 3 ו־4 עדכון תואם ל־3.10; עצם קיומו של המספר אצל ארבעת האחרים אינו אישור להשתמש בקובץ אקראי.

### ד. ניסית להשוות את הגרסאות וזה לא עבד

קראתי גם את ההודעה שלך שבה כתבת שכבר ניסית FT SCServo Debug. לכן ״תוריד את התוכנה״ לבדו אינו פתרון מספק. צריך לזהות **איפה** הניסיון נעצר: האם Search לא מצא מנוע? האם Online לא מציג עדכון? האם כפתור Upgrade לא זמין? האם הצריבה התחילה ונכשלה? האם הסתיימה אך בקריאה חוזרת נשארה 3.9?

בפרק הקושחה יש מסלול לכל אחד מהמקרים האלה. צלם את חלון התוכנה באותו שלב, עם המנוע הנבחר וגרסתו. זה מידע הרבה יותר שימושי מאשר ניסיון צריבה נוסף ללא שינוי ידוע.

### ה. הזרוע השנייה עבדה קודם, והצלחת לחבר אותה

זה מידע חשוב: נחפש מה השתנה בין הפעם שעבדה לבין הפעם שבה לא ענתה — שקע USB, ספק, חיבור בשרשרת, בקר, הגדרות או סביבת Python. בתמלול יש מילה לא ברורה במשפט על הפעולה שהצלחת לבצע. ייתכן שהתכוונת לכיול, אבל לא אקבע שכבר נשמר כיול תקין בלי לראות את הקובץ או את הודעת הסיום.

גם אם קיים כיול מוצלח, הוא אינו יכול לתקן חוסר מתח או כבל נתונים מנותק. לכן לא מוחקים את הכיול הקודם: שומרים אותו, ואז בודקים את התקשורת בנפרד.

### ו. אחרי שעבדת עליה וחיברת מחדש, הוא לא מזהה שום דבר

התמונה השלישית מדייקת את המצב: הבדיקה הגיעה ל־COM5, אבל לא התקבלה תשובת מנוע. זה שונה ממצב שבו Windows כלל לא מציג בקר USB. המחשב יכול לראות את הבקר בזמן שהמנועים שאחריו לא מקבלים מתח, או כשקו הנתונים אליהם לא מחובר.

הבדיקה המועילה ביותר אחרי זיהוי הפורט היא סריקה, ולא כיול חוזר. אם הסריקה ריקה בכל מהירות נתמכת, מבודדים מנוע אחד עם ספק וכבל מתאימים. אם הוא עונה לבד, מוסיפים את שאר השרשרת בהדרגה, כשכל שינוי חיווט נעשה ללא מתח.

### ז. התמונה הראשונה שייכת לראשון, והשנייה והשלישית לשני

אשמור על החלוקה הזאת. הראשונה מתארת **אי־אחידות קושחה אחרי שהמנועים ענו**. השנייה והשלישית מתארות **ניסיון כיול שלא הגיע לתקשורת עם המנועים**. אין כרגע ראיה שלשתיהן אותו גורם, ואין סיבה להניח שכל המנועים בזרוע השנייה נהרסו יחד.

## 3. שלושת הצילומים שלך, עם פענוח מלא

אפשר ללחוץ על כל צילום כדי לפתוח אותו בגודל מלא. מתחתיו יש גם את השורות החשובות כטקסט קריא, כך שלא צריך לפענח כתב קטן בטלפון.

### תמונה 1 — שש כתובות עונות, אבל הגרסאות שונות

[![תמונה 1: עצירת כיול בגלל גרסאות קושחה 3.9 ו־3.10](img1.jpg)](img1.jpg)

השורות שמסבירות את הכשל הן:

```text
RuntimeError: Some Motors use different firmware versions:
{1: '3.10', 2: '3.10', 3: '3.9', 4: '3.9', 5: '3.10', 6: '3.10'}
Update their firmware first using Feetech's software.
```

הרשימה אינה רשימת מנועים חסרים. להפך: התקבלה גרסה מכל ID שמופיע בה. קריאת הכיול עוברת דרך חיבור ההתקן, פתיחת ה־bus ובדיקת התאמה שנקראת handshake. בתוך הבדיקה הזאת, `_assert_same_firmware` מצאה יותר מגרסה אחת ועצרה לפני תהליך הכיול.

`RuntimeError` הוא סוג החריגה ב־Python, בדומה לחריגה שהיית רואה ב־C#. השורות הארוכות שמתחילות ב־`File` הן מסלול הקריאות שהוביל לחריגה. הן לא אומרות שכל הקבצים פגומים. את הסיבה הישירה מחפשים בשורות האחרונות.

שורת `SOFollower disconnected` בתחתית מתעדת סגירת חיבור אחרי הכשל. היא אינה מוכיחה שכבל USB יצא באמצע. התמונה גם אינה מוכיחה שהזרוע נעה נכון או שהספק עומד בעומס; היא מוכיחה שבאותה הרצה הצליחה קריאת גרסאות.

**מה עושים:** עוברים לפרק 8, בודקים ב־FD את IDs ‏3 ו־4 ומבררים אם קיים להם עדכון מתאים. לא מבטלים את בדיקת הקושחה בקוד ולא מחליפים את המספרים בפלט.

### תמונה 2 — איזו פקודה רצה, ומה היא ביקשה לעשות

[![תמונה 2: פקודת lerobot-calibrate עבור so101_follower בפורט COM5](img2.jpg)](img2.jpg)

זו הפקודה הנראית בחלון:

```bat
lerobot-calibrate --robot.type=so101_follower --robot.port=COM5 --robot.id=my_follower_arm
```

היא מבקשת לכייל **follower**, דרך `COM5`, ולשמור זיהוי בשם `my_follower_arm`. היא אינה מפעילה זוג זרועות יחד. השדות `teleop: None` ו־`cameras: {}` מתאימים להרצת כיול בלי leader ובלי מצלמות; אלה אינם כשלים.

`calibration_dir: None` אומר שלא הועבר נתיב כיול מפורש, ולכן התוכנה משתמשת בברירת המחדל. זה לא אומר שאסור לשמור קובץ. `disable_torque_on_disconnect: True` מתייחס לשחרור מומנט בעת ניתוק; לכן צריך לתמוך בזרוע כשהמנועים מפסיקים להחזיק אותה.

בתמונה הזאת רואים את תחילת החריגה ואת `device.connect(calibrate=False)`. הפרמטר הזה אינו אומר שביטלת את הכיול בטעות: כלי הכיול מבצע תחילה חיבור בלי כיול אוטומטי, ואז אמור להפעיל את שלב הכיול המפורש. כאן החיבור עצמו נכשל. הסיבה האחרונה נמצאת בתמונה 3.

**מה עושים:** מאמתים ש־COM5 הוא באמת הבקר של הזרוע הזאת. אם הזרוע אמורה להיות leader, בהמשך משתמשים ב־`--teleop.type=so101_leader`; שינוי התפקיד לבדו עדיין אינו מסביר או מתקן רשימת מנועים ריקה.

### תמונה 3 — המשמעות המדויקת של 777 ושל הרשימה הריקה

[![תמונה 3: חסרים מנועים 1 עד 6; דגם צפוי 777; רשימת מנועים שנמצאו ריקה](img3.jpg)](img3.jpg)

```text
FeetechMotorsBus motor check failed on port 'COM5'
Missing motor IDs:
 - 1 (expected model: 777)
 - 2 (expected model: 777)
 - 3 (expected model: 777)
 - 4 (expected model: 777)
 - 5 (expected model: 777)
 - 6 (expected model: 777)

Full expected motor list (id: model_number):
{1: 777, 2: 777, 3: 777, 4: 777, 5: 777, 6: 777}

Full found motor list (id: model_number):
{}
```

`{}` הוא מילון ריק ב־Python: לא נמצאו כאן זוגות של כתובת ודגם. `777` הוא המספר שהספרייה מצפה לקרוא ממנוע STS3215, ולא מה שהיא מצאה בפועל. לא צריך לשנות כתובות מנועים ל־777; כתובות המפרקים צריכות להיות 1–6.

במסלול הקוד הזה, פתיחת הפורט קודמת לבדיקת המנועים. לכן יש בסיס לומר שההרצה הגיעה מעבר לפתיחת COM, אבל לא שהפורט שייך בהכרח לבקר הנכון. גם בקר אחר יכול לפתוח פורט ולהחזיר אפס תשובות לפרוטוקול הזה.

גורמים אפשריים הם הזנת מנועים חסרה, פורט שגוי, כבל bus ראשון לא מחובר, קו DATA שגוי, מצב ג׳אמפרים לא מתאים, מהירות תקשורת שונה, כתובות כפולות או תקלה בחומרה. התמונה אינה מבחינה ביניהם. כשכל השישה חסרים, כדאי לבדוק קודם את הרכיבים המשותפים לכולם: ספק, בקר וכבל ראשון.

**מה עושים:** פרקים 6–7 ועץ התקלות בפרק 12. לא מתחילים מצריבת קושחה, ולא מסיקים שצריך לקנות שישה מנועים חדשים.

## 4. חומרה, מתח ותמסורות — תשובה לשאלת ה־12V

שאלת אם אפשר להשתמש ב־12V כאשר כתוב 7.4V. צריך להבחין בין **החלפת סוג המנוע** לבין **החלפת המתח שמזינים אליו**.

**לא מחברים ספק 12V למנוע בגרסת 7.4V.** זה אינו שינוי תוכנה, וכיול לא מגן מפני מתח לא מתאים. לעומת זאת, קיימת תצורת follower המבוססת על שישה מנועי STS3215 בגרסת 12V עם ספק מתאים. ה־leader בתכנון SO-101 הרשמי משתמש בגרסאות 7.4V וביחסי תמסורת שונים לפי מפרק. [מפרט החומרה של מתכנני הזרוע](https://github.com/TheRobotStudio/SO-ARM100#sourcing-parts).

במפרט הבסיס למנועי 7.4V משתמשים בספק 5V; לחלופת follower של 12V מצוין ספק **12V, לפחות 5A**. אין לבחור ספק רק לפי שם המנוע או לפי מחבר שנכנס. צריך לוודא תת־דגם, התאמת הלוח, קוטביות והנחיות הערכה. ספק בעל יכולת זרם גבוהה יותר אינו דוחף אוטומטית את כל הזרם למנוע, אבל **מתח** גבוה מדי הוא עניין אחר לגמרי.

כתבת שיש לך הרבה מנועי 12V, מנועי 7.4V ביחס 1/147, ומנוע אחד של 7.4V ביחס 1/345. ברשימה הזאת לא הופיעו מנועי 1/191, ולא נמסר יחס התמסורת של ה־12V. היא גם לא אומרת מה הורכב בפועל מאז. לכן לפני הפעלה ממלאים טבלה לפי התוויות שעל המנועים, ולא לפי זיכרון המלאי.

| ID | שם המפרק בפקודות | תפקיד | תמסורת leader | תמסורת follower |
|---|---|---|---|---|
| 1 | `shoulder_pan` | סיבוב הבסיס | 1/191 | 1/345 |
| 2 | `shoulder_lift` | הרמת הכתף | 1/345 | 1/345 |
| 3 | `elbow_flex` | כפיפת המרפק | 1/191 | 1/345 |
| 4 | `wrist_flex` | כפיפת שורש כף היד | 1/147 | 1/345 |
| 5 | `wrist_roll` | סיבוב שורש כף היד | 1/147 | 1/345 |
| 6 | `gripper` | צבת או ידית ההפעלה | 1/147 | 1/345 |

המנוע היחיד של 7.4V ביחס 1/345 יכול להתאים לכתף של ה־leader, אם זה אכן תת־הדגם המתאים. יחס התמסורת הוא מבנה מכני, לא ערך שמשנים ב־FD. גרסת קושחה זהה אינה מוכיחה מתח או תמסורת זהים. [טבלת המפרקים הרשמית](https://huggingface.co/docs/lerobot/so101#step-by-step-assembly-instructions).

### רשימת בדיקה על השולחן

- שתי זרועות מורכבות ומסומנות בתפקידן; ברגים וחיבורים מכניים תקינים.
- שני בקרי USB ל־TTL המתאימים למנועי Feetech, אחד לכל זרוע.
- שני כבלי USB שמעבירים נתונים, ורצוי אחד חלופי ידוע כתקין.
- ספק מתאים לכל צד, עם תווית קריאה של מתח, זרם וקוטביות.
- כבלי bus של שלושה גידים: מהבקר למנוע הראשון ובין המנועים; רצוי כבל חלופי.
- בסיסים מקובעים בקליבות, צבת ריקה ושטח תנועה פנוי.
- מברגים, סימון לכבלים ומולטימטר אם יש אדם שיודע להשתמש בו.

בכבל bus יש מתח, אדמה ונתונים. הלוח לא בהכרח מוריד את מתח הספק לפני שהוא מגיע למנועים. אין לחבר ספקים שונים יחד או לגשר בין הזרועות. בזמן החלפת חיווט מכבים מתח ותומכים בזרוע; בזמן צריבת קושחה דווקא שומרים על מתח ו־USB יציבים עד שהכלי מסיים.

אם מודדים מתח, מודדים רק בצד המתח הנמוך ובנקודות המיועדות לכך, בלי לקצר פינים ובלי לפתוח ספק שמחובר לרשת. אין תווית ברורה או אין התאמה ודאית? מצלמים ומשאירים את בדיקת ההתאמה לפגישה.

## 5. להכין Python ו־LeRobot ב־Windows

### קודם לבדוק את מה שכבר עובד אצלך

בתמונות שלך Python ו־LeRobot כבר רצים ומגיעים לבדיקת המנועים. לכן התקנה מחדש אינה הפעולה הראשונה לתיקון החומרה. פתח את אותו Command Prompt שבו השתמשת, והריץ כל שורה בנפרד:

```bat
where python
python --version
python -m pip show lerobot
where lerobot-calibrate
python -c "import lerobot; print(lerobot.__file__)"
```

שמור את הפלט. הוא אומר איזה Python רץ ומאיפה נטענת הספרייה. אם יש כמה נתיבים, אין להסיק שהראשון הוא העותק שהתכוונת אליו. בפרט, אצלך בתמונה מופיע עותק מקור תחת `C:\Users\USER\lerobot`; סביבה חדשה לא אמורה למחוק או לדרוס אותו.

המדריך נבדק מול קוד LeRobot בגרסה `0.6.2`, ב־commit הבא. זו גרסת המקור שנבדקה, ולא טענה שזה ה־commit שמותקן אצלך:

```text
8c920c4270460851cedd2737657584586d3dc66f
```

המקור הזה דורש Python ‏3.12 ומעלה. לבנייה של סביבה חדשה כאן נבחר **Python 3.12**. מספר זה אינו קשור לקושחות המנועים 3.9 ו־3.10.

### מסלול התקנה חדש באמצעות Miniconda

אם הסביבה הקיימת תקינה, אפשר להמשיך לפרק הפורטים ולשמור את המסלול הזה למקרה הצורך. אם בונים סביבה חדשה, בצע:

1. פתח את [מדריך ההתקנה הרשמי של Miniconda](https://www.anaconda.com/docs/getting-started/miniconda/install), ובחר מתקין Windows המתאים למחשב. במחשב Windows רגיל עם מעבד Intel/AMD זו גרסת 64-bit x86-64.
2. התקן עבור המשתמש שלך. אין צורך להחליף את Python של כל המחשב או להוסיף ידנית רשימות ארוכות ל־PATH.
3. בתפריט התחל פתח **Anaconda Prompt / Miniconda Prompt**, בגרסת Command Prompt. כל פקודות Windows כאן מיועדות ל־CMD, לא ל־PowerShell.
4. הרץ:

```bat
conda create -n so101 python=3.12 pip
conda activate so101
python --version
python -c "import sys; print(sys.executable)"
python -m pip install --upgrade pip
```

אשר את יצירת הסביבה כאשר Conda מבקש. אחרי ההפעלה אתה אמור לראות `(so101)` בתחילת שורת הפקודה, ונתיב Python בתוך הסביבה. בכל חלון חדש מפעילים שוב `conda activate so101`; התקנת החבילות אינה נדרשת מחדש בכל פתיחה.

### התקנת LeRobot עם תמיכה ב־Feetech

פקודת ההתקנה הרגילה מחבילת ההפצה היא:

```bat
python -m pip install "lerobot[feetech]"
```

הסוגריים המרובעים מבקשים גם את תלויות התקשורת של Feetech. המרכאות הן חלק מהפקודה. התקנה עשויה להוריד חבילות גדולות, כולל PyTorch, גם כשהמטרה היא teleop בסיסי; זה לא אומר שצריך לאמן מודל או שיש צורך בכרטיס NVIDIA.

גרסת ההפצה הזמינה עשויה להיות שונה מהמקור שעליו נבדקו ההוראות. כדי להתקין **בדיוק את המקור שנבדק**, אפשר לבחור במקום זאת במסלול הבא, בתוך אותה סביבה. הוא דורש [Git for Windows](https://git-scm.com/downloads/win). השתמש בתיקייה חדשה ופנויה, כדי לא לגעת בעותק הקיים שלך:

```bat
cd /d "%USERPROFILE%"
git clone https://github.com/huggingface/lerobot.git lerobot-so101-checked
cd lerobot-so101-checked
git checkout 8c920c4270460851cedd2737657584586d3dc66f
python -m pip install -e ".[feetech]"
```

אם `lerobot-so101-checked` כבר קיימת, אל תמחק אותה ואל תשכפל לתוכה שוב; בדוק מה יש בה קודם. `git checkout` כאן בוחר גרסת קוד מסוימת לצורך שימוש, בלי שינוי קוד. `-e` אומר שההתקנה מפנה לקבצים בתיקייה הזאת, לכן אין להזיז אותה אחרי ההתקנה. אין צורך להריץ גם את מסלול ההפצה וגם את מסלול המקור; בחר אחד ותעד אותו.

בדוק שההתקנה הגיעה לשלב שימושי:

```bat
python -m pip check
python -c "import scservo_sdk; from lerobot.motors.feetech import FeetechMotorsBus; print('Feetech imports OK')"
lerobot-setup-motors --help
lerobot-calibrate --help
lerobot-teleoperate --help
```

אלה בדיקות תוכנה בלבד. הן לא מפעילות מנועים ולא מוכיחות שהחומרה מחוברת. אם פקודה אינה מוכרת, בדוק קודם הפעלת סביבה עם `where python` ו־`where lerobot-calibrate`. אם חסרה חבילה, שמור את שמה ואת שגיאת ההתקנה; אל תתקין אוסף חבילות אקראי או תשנה קוד כדי לעקוף import שנכשל.

בגרסת המקור שנבדקה, `lerobot-find-port --help` אינו עמוד עזרה: הכלי מתחיל את תהליך זיהוי הפורט. לכן מפעילים אותו רק כשרוצים לבצע את בדיקת הניתוק המתוארת בפרק הבא.

### Python למי שמכיר C# — תיבת התמצאות

> **Python** הוא המפרש שמריץ את הקוד. `pip` מתקין חבילות, בדומה לתפקיד של NuGet בניהול תלויות. **venv** או סביבת **Conda** מפרידים בין החבילות של פרויקטים שונים. סביבת Conda יכולה גם לנהל את גרסת Python. **CLI** הוא תוכנית שמפעילים דרך שורת פקודה — כאן `lerobot-calibrate` הוא כלי מותקן, לא טקסט שצריך להדביק בתוך קובץ Python.
>
> `python -m pip` מבקש להפעיל את pip ששייך ל־Python הנוכחי. `python -c "..."` מריץ קטע Python קצר. `--robot.port=COM5` הוא ארגומנט לתוכנית, כמו פרמטר שמגיע ל־`Main(string[] args)`. סימני `>>>` מציינים שאתה בתוך המפרש האינטראקטיבי; פקודות CMD לא נכתבות שם. אפשר לצאת ממנו עם `exit()`.

אפשר עקרונית לכתוב תוכנת שליטה ב־C# אם מממשים את הפרוטוקול והכיול המתאימים, או מפעילים כלי Python מתוכה. אבל זה פרויקט נוסף. כדי להפעיל את מה שכבר בנית, כלי LeRobot חוסכים כתיבת שכבת תקשורת, בדיקות דגם, כיול ומיפוי מפרקים. אתה יכול להשתמש בהם בלי לכתוב תוכנית Python מלאה.

אם כבר יש לך Python 3.12 מותקן ואתה מעדיף **venv במקום Conda**, זהו מסלול חלופי, לא שלב נוסף:

```bat
py -3.12 -m venv "%USERPROFILE%\so101-venv"
call "%USERPROFILE%\so101-venv\Scripts\activate.bat"
python -m pip install --upgrade pip
python -m pip install "lerobot[feetech]"
```

את Python וה־launcher אפשר להתקין מ[אתר Python הרשמי ל־Windows](https://www.python.org/downloads/windows/). אל תפעיל venv בתוך Conda לצורך המדריך הזה. בחר סביבה אחת כדי שיהיה ברור איפה החבילות והפקודות נמצאות.

## 6. לזהות את הפורטים בלי לנחש COM5

מתחילים מבקר אחד. בודקים את התאמת הספק, תומכים בזרוע, מחברים USB וכוח לפי הוראות הלוח. סגור FD או כל כלי אחר שמחזיק את הפורט.

```bat
python -m serial.tools.list_ports -v
lerobot-find-port
```

הפקודה הראשונה מציגה את הפורטים שהמערכת מכירה. השנייה מבצעת השוואה בין רשימות: היא מבקשת לנתק את USB של הבקר וללחוץ Enter. נתק **רק את USB של הבקר הנבדק**, לא רכזת שלמה ולא שני בקרים יחד. כאשר התוכנה מזהה את הפורט שנעלם, רשום אותו וחבר את ה־USB מחדש.

חזור על הפעולה עבור הבקר השני. כתוב ליד כל זרוע צבע, תפקיד ופורט. `COM5` בתמונות הוא תוצאה מההרצה ההיא; הוא לא הבטחה שהבקר יישאר באותו מספר או ששתי הזרועות משתמשות בו יחד.

בדוגמאות הבאות נניח, **רק לצורך ההסבר**, שה־follower נמצא ב־COM5 וה־leader ב־COM6. החלף את הערכים באלה שמצאת, לפני הרצת פקודות חומרה:

```bat
set "FOLLOWER_PORT=COM5"
set "LEADER_PORT=COM6"
echo %FOLLOWER_PORT%
echo %LEADER_PORT%
```

משתנים אלה חיים בחלון CMD הנוכחי. בכל חלון חדש מגדירים אותם מחדש. ב־PowerShell התחביר שונה; אל תערבב פקודות משני סוגי החלונות.

אם לא מופיע פורט, פתח Device Manager וחפש **Ports (COM & LPT)** או התקן USB לא מזוהה. נסה כבל נתונים ידוע ושקע USB ישיר. דרייבר מתקינים רק אחרי זיהוי שבב הבקר: למשל WCH או Silicon Labs, לפי דגם אמיתי ולא לפי צורת המחבר. אם הפורט קיים אך מתקבלת `Access is denied`, סגור FD והרצות קודמות לפני כל שינוי חומרה.

**תנאי מעבר:** אתה יכול לנתק בקר מסוים, לראות את הפורט שלו נעלם, לחברו ולראות אותו חוזר. עדיין לא הוכחנו שהמנועים עונים; זה השלב הבא.

## 7. סריקת מנועים — הבדיקה הראשונה לזרוע שלא מזוהה

הפקודה הבאה משתמשת ב־API שבמקור שנבדק. היא סורקת מהירויות תקשורת נתמכות וקוראת תשובות זיהוי; היא אינה משנה IDs או קושחה ואינה שולחת יעדי תנועה. הבקר משנה את מהירות התקשורת שלו במהלך החיפוש, לא את ההגדרה הקבועה במנועים.

אחרי הגדרת הפורטים וסגירת FD, הרץ עבור ה־follower:

```bat
python -c "import os; from lerobot.motors.feetech import FeetechMotorsBus; print(FeetechMotorsBus.scan_port(os.environ['FOLLOWER_PORT']))"
```

ועבור ה־leader, בנפרד:

```bat
python -c "import os; from lerobot.motors.feetech import FeetechMotorsBus; print(FeetechMotorsBus.scan_port(os.environ['LEADER_PORT']))"
```

פלט תקין לדוגמה, לא תוצאה שנמדדה אצלך:

```text
Motors found for baudrate=1000000:
{1: 777, 2: 777, 3: 777, 4: 777, 5: 777, 6: 777}
{1000000: [1, 2, 3, 4, 5, 6]}
```

המספר `1000000` הוא baud rate — מהירות התקשורת. הרשימה היא הכתובות שענו. סדר הכתובות אינו חשוב; הימצאות ששת ה־IDs הנכונים כן חשובה. גם הרשימה הזאת עדיין לא מוכיחה ש־ID 3 יושב פיזית במרפק.

| תוצאת הסריקה | הפירוש המעשי | הצעד הבא |
|---|---|---|
| שישה IDs נכונים ב־1,000,000 | תקשורת בסיסית עם כל הכתובות | לקרוא גרסאות ב־FD |
| מנועים עונים במהירות אחרת | יש תקשורת, אך ההגדרות שונות מברירת המחדל | לתעד ואז להסדיר baud עם setup, מנוע בודד |
| רק חלק מהמנועים | הכיסוי חלקי | לבדוק שרשרת, כבל וכתובות |
| `{}` אחרי כל הסריקה | אין תשובות במהירויות שנבדקו | לבדוק ספק, פורט, לוח ומנוע בודד |
| חריגת פתיחת COM | הפורט אינו זמין לפתיחה | לחזור לזיהוי פורט או לסגור תוכנה מתחרה |
| `AttributeError` על `scan_port` | ממשק התוכנה שונה בגרסה שלך | להשתמש ב־FD לקריאה או להתאים לגרסה המתועדת |

### איך מבודדים את הגורם ברשימה ריקה

כבה מתח ותמוך בזרוע. נתק את שרשרת המנועים מהבקר וחבר אליו מנוע אחד בלבד באמצעות כבל ידוע כתקין. ודא שהמנוע מתאים למתח הספק, החזר מתח וסרוק. אם הוא עונה, הכנס לטבלה את כתובתו ואת המהירות שמצאת. חזור באופן מסודר על האחרים.

אם כל מנוע עונה לבדו אך לא כשהם מחוברים יחד, חשוד בכתובות כפולות, בכבל בין מנועים או בנפילת מתח. אם אף מנוע לא עונה באותו בקר וכבל, בדוק את הרכיבים המשותפים. החלף בכל פעם רכיב אחד ורק ברכיב תואם: שינוי של ספק, בקר וכבל יחד לא יגלה איזה מהם גרם לשינוי.

בבקר Waveshare המתואר במדריך הרשמי יש שני ג׳אמפרים שצריכים להיות בערוץ **B עבור USB**. זו הוראה לדגם הזה. אין להזיז ג׳אמפרים בלוח אחר לפי ניחוש. תמונותיך מציגות מסך מחשב, ולכן אי אפשר לזהות מהן את הלוח או את מצב הג׳אמפרים שלך.

## 8. לפתור את 3.9 מול 3.10 באמצעות Feetech FD

### להוריד את הכלי הנכון

פתח את [עמוד התוכנה הרשמי של Feetech](https://www.feetechrc.com/software.html). בזמן הבדיקה מופיעים בו FD ‏1.9.8.3, גרסה 1.9.8.2 המסומנת Offline וקישור נוסף להפצת FD. זהו גם [קישור ZIP ישיר ל־FD 1.9.8.3 באתר היצרן](https://www.feetechrc.com/Data/feetechrc/upload/file/20240622/FD1.9.8.3.zip); אם הקישור משתנה, חוזרים לעמוד הרשמי. חלץ את הארכיון לתיקייה לפני הפעלה ופעל לפי הוראות החבילה.

שים לב: **FD 1.9.8.3 היא גרסת תוכנת המחשב; 3.10 היא גרסת קושחת מנוע.** לא מצפים שהמספרים יהיו זהים. ההוראות הבאות תואמות למסלול המתואר ב[מדריך עדכון הקושחה הרשמי של LeRobot](https://huggingface.co/docs/lerobot/feetech); מיקום הכפתורים עשוי להשתנות בין גרסאות FD.

### לפני שלוחצים Upgrade

1. שמור צילום של המנועים המזוהים: ID, דגם, גרסת קושחה ו־baud. צלם גם את התוויות הפיזיות עם המתח ותת־הדגם.
2. גבה את קובצי הכיול הקיימים. אל תשתמש במחיקת התיקייה כפתרון לתקלה.
3. סגור כל תהליך LeRobot שמשתמש באותו פורט. FD צריך גישה בלעדית אליו.
4. קבע את הזרוע ותמוך בה. לצמצום בחירת מנוע שגוי, אפשר לעבוד עם מנוע אחד מחובר בכל פעם, בהתאם להוראות החומרה והכלי. החלפת חיווט נעשית כשהמתח כבוי.
5. ודא שהספק וה־USB יציבים. במהלך צריבה לא מנתקים אותם, לא סוגרים את הכלי ולא מעבירים את המחשב לשינה.

### רצף הכפתורים, ומה מצפים בכל שלב

**שלב 1 — פתיחת חיבור.** הפעל FD, בחר את COM של הבקר הנכון ובחר baud לפי מה שנמצא בסריקה. בזרוע שהוגדרה ל־LeRobot מצפים בדרך כלל ל־`1000000`. לחץ **Open**. אם הפתיחה נכשלת, עדיין אין טעם ללחוץ Upgrade: בדוק פורט ותוכנה שמחזיקה בו.

**שלב 2 — חיפוש.** לחץ **Search**. אמורה להופיע רשימת מנועים. בחר את שורת המנוע המיועד; אצלך לפי התמונה, שני המועמדים לבדיקה הם IDs ‏3 ו־4. אם עובדים עם מנוע בודד, מזהים גם לפי התווית והפתק, לא רק לפי הכתובת הישנה.

**שלב 3 — קריאת המצב.** קרא את הגרסה הנוכחית והדגם. שמור צילום לפני כתיבה. אם מוצג 3.9, פירושו major ‏3 ו־minor ‏9. כתיבה ידנית לשדות של גרסה אינה עדכון קושחה.

**שלב 4 — חיפוש עדכון.** בחר את לשונית **Upgrade**, ואז **Online**. הכלי אמור להציג עדכון אפשרי אם הוא מוצא כזה. בדוק שההצעה מיועדת לדגם ולגרסת החומרה שלך. אם קיימת הצעה תואמת ל־3.10, זה המסלול הטבעי ליישור מול ארבעת האחרים. אם אין הצעה תואמת, עוצרים בשלב הזה ומתעדים.

**שלב 5 — צריבה.** רק אחרי זיהוי התאמה, לחץ **Upgrade** לביצוע העדכון. המתן להודעת סיום. אין לנתק כוח או USB באמצע, גם אם הפעולה לוקחת יותר מהצפוי. אם מופיעה שגיאה, שמור אותה ואת מצב הכלי לפני כל ניסיון נוסף ופעל לפי הוראות השחזור של היצרן.

**שלב 6 — קריאה חוזרת.** בצע חיפוש או רענון בהתאם לכלי וקרא שוב גרסה, ID ו־baud. סיום פס ההתקדמות לבדו אינו מספיק. צריך לראות שהמנוע עונה בגרסה הרצויה ושהגדרות התקשורת ידועות. רק אחר כך עוברים למנוע הבא.

**שלב 7 — בדיקת הזרוע כולה.** סגור את החיבור ב־FD, כבה מתח לצורך חיבור השרשרת מחדש, ואז חזור לסריקה ב־LeRobot. ודא שישה IDs נכונים באותה מהירות, וקרא ב־FD את שש הגרסאות. תנאי ההמשך הוא גרסה אחידה ותואמת **בתוך כל זרוע**. הבדיקה שמופיעה אצלך אינה השוואה בין כל 12 המנועים בשתי הזרועות יחד.

### כבר ניסית לעדכן — כך מבדילים בין הכשלים

| מה קורה ב־FD | מה צריך לברר | מה לא פותר את זה |
|---|---|---|
| Open נכשל | COM נכון? LeRobot סגור? USB זמין? | שינוי קושחה |
| Open מצליח, Search ריק | הזנה, baud, DATA, מנוע בודד | לחיצה על Upgrade בלי מנוע |
| מנוע נמצא, Online ריק | גרסת הכלי, חיבור רשת וזמינות עדכון תואם מהיצרן | המצאת קובץ או בחירת דגם דומה |
| אין Online בממשק | האם זו מהדורת Offline או כלי אחר? | שינוי ID כדי ״לפתוח״ עדכון |
| Upgrade נכשל באמצע | הודעת השגיאה, יציבות ההזנה והוראות שחזור יצרן | רצף ניסיונות וכיבויים לא מתועד |
| הסתיים, נשאר 3.9 | האם נבחר המנוע הנכון? האם בוצעה קריאה חדשה? מה נכתב ביומן? | להניח ש־pip יעדכן את המנוע |

אם היצרן לא מציע קושחה תואמת, זה חסם ממשי שצריך להביא לפגישה עם צילום, תווית המנוע וגרסת FD. אין כאן הוראה לשנמך ארבעה מנועים, לצרוב קובץ של מנוע אחר או לבטל `_assert_same_firmware`. שינוי הבדיקה בקוד לא הופך את ההתנהגות הפנימית של המנועים לאחידה.

## 9. הגדרת כתובות מנועים — רק אם הן חסרות או שגויות

`lerobot-setup-motors` מגדיר כתובת ומהירות תקשורת בזיכרון הקבוע של המנוע. הוא **אינו** צורב firmware ואינו מבצע כיול מכני. אם כבר נמצאו IDs ‏1–6 ב־1,000,000, וכל ID אכן שייך למפרק המתאים, אין צורך להגדיר אותם מחדש רק משום שהתוכנה נעצרה על גרסאות קושחה.

אם יש מנועים חדשים, כתובות כפולות, מהירות לא מתאימה או מיפוי לא נכון, מבצעים setup. הפקודות הבאות משתמשות במשתני הפורטים שהגדרת; ודא שהם עדיין מוגדרים בחלון הנוכחי.

עבור ה־follower:

```bat
lerobot-setup-motors --robot.type=so101_follower --robot.port=%FOLLOWER_PORT%
```

עבור ה־leader, בנפרד:

```bat
lerobot-setup-motors --teleop.type=so101_leader --teleop.port=%LEADER_PORT%
```

התוכנה מבקשת לחבר מנוע לפי שמו. במקור שנבדק הסדר הוא מהצבת אל הבסיס: `gripper`, אחריו `wrist_roll`, ‏`wrist_flex`, ‏`elbow_flex`, ‏`shoulder_lift`, ולבסוף `shoulder_pan`. התוצאה המתוכננת היא IDs ‏6, 5, 4, 3, 2, 1 בהתאמה.

**בכל צעד צריך להיות מחובר לבקר רק המנוע שהתבקש.** לא מספיק לגעת רק במנוע אחד כשהוא עדיין מחובר בחוטים לחמישה אחרים. נתק את קישוריו לשרשרת, כשהמתח כבוי, וחבר אותו לבקר לבדו.

רצף העבודה לכל מנוע:

1. קרא את שם המנוע שהתוכנה מבקשת וראה לאיזה מפרק הוא שייך בטבלה.
2. תמוך בזרוע וכבה הזנת מנועים לפני שינוי החיווט.
3. חבר את אותו מנוע בלבד, עם כבל וספק מתאימים.
4. החזר מתח, ודא שהחיבור יציב ורק אז לחץ Enter.
5. המתן להודעת הצלחה עם ה־ID שהוגדר. כתוב אותו על פתק ליד המנוע.
6. כשהתוכנה עוברת למנוע הבא, חזור על הרצף.

אם נותק גם USB והכלי איבד את הפורט, עצור ובדוק את המצב לפני המשך. אל תניח שכתיבה התבצעה רק מפני שלחצת Enter. אם מנוע לא נמצא גם לבדו, חזור לבדיקת הזנה ותקשורת; רצף Enter נוסף לא מתקן כבל.

בסיום כבה כוח, חבר מחדש את שרשרת הזרוע, הפעל וסרוק. צריך לראות שש כתובות נכונות ב־1,000,000. מהירות באוגר `Baud_Rate` מיוצגת בקוד פנימי; אין לכתוב את המספר מיליון לשדה אוגר גולמי. כלי setup מבצע את התרגום המתאים.

## 10. לכייל כל זרוע בנפרד

### מה הכיול עושה, ומה צריך לשמור

הכיול מודד היסט לתנוחת האמצע וגבולות תנועה, כותב פרמטרים למנועים ושומר קובץ JSON במחשב. הוא מחבר בין נתוני החיישנים לבין המכניקה של **הזרוע המסוימת**. קובץ מהזרוע השנייה אינו תחליף למדידה שלך.

לפני כיול חדש, גבה קבצים קיימים. אם השתמשת בשם `my_follower_arm`, קובץ שנשמר תחת השם הזה לא נעלם כשבוחרים עכשיו `benjamin_follower`; אלה שני שמות שונים. כאשר רוצים להמשיך עם כיול ישן מאומת, משתמשים בשם ובנתיב המקוריים. בדוגמאות כאן ניצור שמות ונתיבים ברורים כדי שתוכל למצוא את התוצאה.

צור תיקיות עבודה ב־CMD:

```bat
mkdir "%USERPROFILE%\so101-work"
mkdir "%USERPROFILE%\so101-work\calibration\leader"
mkdir "%USERPROFILE%\so101-work\calibration\follower"
```

אם תיקייה כבר קיימת, זה אינו כשל חומרה; אין למחוק אותה. לקבצים הישנים ניתן להגיע דרך הנתיב שהודפס בסיום הכיול הקודם. ברירת המחדל לרוב נמצאת מתחת לתיקייה הבאה, אבל יכולה להשתנות לפי הגדרות המשתמש והגרסה:

```bat
dir /s /b "%USERPROFILE%\.cache\huggingface\lerobot\calibration\*.json"
```

### הכיול של ה־leader

רק אחרי שכל ששת המנועים עונים, שהקושחה אחידה ושהמיפוי מתאים:

```bat
lerobot-calibrate --teleop.type=so101_leader --teleop.port=%LEADER_PORT% --teleop.id=benjamin_leader --teleop.calibration_dir="%USERPROFILE%\so101-work\calibration\leader"
```

### הכיול של ה־follower

לאחר סיום ה־leader, ובדיקת הפורט הנכון:

```bat
lerobot-calibrate --robot.type=so101_follower --robot.port=%FOLLOWER_PORT% --robot.id=benjamin_follower --robot.calibration_dir="%USERPROFILE%\so101-work\calibration\follower"
```

### מה תעשה מול ההנחיות בחלון

אם נמצא קובץ קיים, המקור שנבדק מציע Enter לשימוש בו או `c` ואחריו Enter לכיול חדש. שימוש בקובץ קיים עשוי לכתוב את ערכיו למנועים; זה אינו מסך צפייה בלבד. בחר בו רק אם אתה יודע שהוא שייך לאותה זרוע ובאותה הרכבה. אם מחליפים מנוע או משנים הרכבה המשפיעה על האפס המכני, צריך לבדוק מחדש את תוקפו.

כאשר מתחיל כיול חדש, המומנט משתחרר. החזק ותמוך בזרוע כדי שלא תיפול. התוכנה מציגה תרשים תנוחת אמצע וקישור להדגמה. מקם את המפרקים לפי התרשים, בלי לכפות תנועה דרך מעצור מכני, ואז אשר.

בשלב הבא מזיזים ידנית כל מפרק שהתוכנה מבקשת לאורך טווח התנועה התקין שלו, ורואים את ערכי המינימום והמקסימום משתנים. לא לוחצים Enter מיד: צריך לתת לתוכנה למדוד. במקור שנבדק `wrist_roll` מוחרג מהמדידה ומוגדר לטווח מלא; פעל לפי ההודעה המדויקת של הגרסה שרצה אצלך.

בסיום מצפים להודעה עם הנוסח `Calibration saved to` ולנתיב. בדוק שהקבצים אכן קיימים:

```bat
dir "%USERPROFILE%\so101-work\calibration\leader\*.json"
dir "%USERPROFILE%\so101-work\calibration\follower\*.json"
```

הקבצים בדוגמאות אמורים להיקרא `benjamin_leader.json` ו־`benjamin_follower.json`. שמור עותק גם עם תאריך לאחר שהכיול נבדק בתנועה. אל תערוך ידנית offsets או טווחים כדי להעלים הודעת שגיאה.

### אם הכיול נתקע

- כשל על גרסאות לפני תנוחת האמצע: חוזרים לקריאת firmware; זה עדיין לא כשל מדידת טווח.
- כשל `Missing motor IDs`: חוזרים לתקשורת. קובץ כיול חדש לא יוסיף מתח למנוע.
- מפרק זז אבל המספר נשאר קבוע: בודקים איזה ID קוראים, איזה מפרק זז והאם החיבור המכני נכון.
- טווח קטן מאוד: בודקים אם בוצעה התנועה הנדרשת ואם יש חסימה מכנית; לא מגדילים מספרים בקובץ.
- חריגה כגון `Magnitude ... exceeds 2047`: שומרים את הפלט המלא, את המפרק ואת גרסת LeRobot לבדיקה. לא משנים גבולות קידוד או ביטי הגדרות מתוך ניחוש.
- שגיאת הרשאות בכתיבת JSON: בודקים תיקייה והרשאות משתמש. זו תקלה בדיסק או בנתיב, לא סיבה לעדכן מנוע.

## 11. מעקב ראשון — להזיז מעט ולראות התאמה

מגיעים לכאן רק כששתי הזרועות מזוהות בנפרד, לכל אחת כיול מתאים, והמתחים והמכניקה נבדקו. קבע את הבסיסים, פנה את טווח התנועה והשאר את הצבת ריקה. הנח את הזרועות בתנוחות דומות ובטוחות לפני הפעלת הפקודה. ה־follower עשוי לנוע מיד כדי להתאים את עצמו ל־leader.

לבדיקה הראשונה עדיף ששני אנשים יהיו ליד המערכת: אחד מזיז בעדינות את ה־leader והשני רואה את ה־follower ואת אמצעי ניתוק ההזנה. לא מחזיקים אצבעות בצבת או בין חלקים נעים. תמיכה מתוכננת נדרשת גם כאשר המומנט משתחרר בסיום.

בדוגמה מוגבלת בזמן, ללא מצלמות וללא תצוגת נתונים:

```bat
lerobot-teleoperate --robot.type=so101_follower --robot.port=%FOLLOWER_PORT% --robot.id=benjamin_follower --robot.calibration_dir="%USERPROFILE%\so101-work\calibration\follower" --teleop.type=so101_leader --teleop.port=%LEADER_PORT% --teleop.id=benjamin_leader --teleop.calibration_dir="%USERPROFILE%\so101-work\calibration\leader" --fps=20 --teleop_time_s=30 --display_data=false
```

זו **שורה אחת** להעתקה, גם אם הדפדפן מציג אותה באזור גלילה. `--fps=20` הוא קצב לולאה מבוקש, לא הגבלת מהירות מכנית. `--teleop_time_s=30` מגביל את משך לולאת המעקב; הוא אינו מבטיח בטיחות בשלושים השניות האלה.

ההגדרות של שתי הזרועות צריכות להשתמש באותן יחידות. במקור שנבדק ברירת המחדל במפרקי הגוף היא מעלות, והצבת מנורמלת ל־0–100. אם שינית `use_degrees` בעבר, בדוק התאמה בין הצדדים לפני שימוש בכיול ובפקודה.

התחל בתנועה קטנה של מפרק אחד. ודא שהמפרק המקביל ב־follower נע בכיוון הצפוי ובטווח קטן. החזר למצב ההתחלתי ורק אז עבור למפרק הבא. תנועה חלקה של מפרק אחד אינה עדיין אימות של כל ששת המפרקים.

**עוצרים אם** יש קפיצה, תנועה של מפרק אחר, משיכה של הבסיס, כבל מתוח, חריקה או לחץ על מעצור. `Ctrl+C` הוא עצירת התוכנה הרגילה. אם יש תנועה לא נשלטת, מנתקים את הזנת ה־follower באמצעי הנגיש שנקבע מראש, תוך היערכות לכך שהזרוע תאבד אחיזה. אין לחכות לסיום הטיימר.

אם הכול עובד, הרץ שוב לאחר עצירה מסודרת. לאחר מכן אפשר לבדוק חיבור מחדש, אימות הפורטים ושימוש חוזר בכיול. המטרה היא רצף שאתה יכול לחזור עליו בעצמך, לא רק פעם אחת שבה חלון הפקודה לא הציג שגיאה.

### דוגמת קובץ הפעלה לימים הבאים

רק אחרי בדיקת מעקב מוצלחת אפשר לשמור ב־Notepad קובץ בשם `teleop.cmd`. בחר Save as type: **All files**, כדי שלא יישמר בטעות בשם `teleop.cmd.txt`. הדוגמה מניחה שבחרת סביבת Conda בשם `so101`; הרץ אותה מתוך Miniconda Prompt. החלף את שני הפורטים בערכים שנבדקו אצלך.

```bat
@echo off
call conda activate so101
if errorlevel 1 exit /b 1
set "FOLLOWER_PORT=COM5"
set "LEADER_PORT=COM6"
echo Check power, clamps, calibration and clear space before continuing.
pause
lerobot-teleoperate --robot.type=so101_follower --robot.port=%FOLLOWER_PORT% --robot.id=benjamin_follower --robot.calibration_dir="%USERPROFILE%\so101-work\calibration\follower" --teleop.type=so101_leader --teleop.port=%LEADER_PORT% --teleop.id=benjamin_leader --teleop.calibration_dir="%USERPROFILE%\so101-work\calibration\leader" --fps=20 --teleop_time_s=30 --display_data=false
set "RESULT=%ERRORLEVEL%"
echo Exit code: %RESULT%
pause
exit /b %RESULT%
```

הקובץ אינו מגלה לבד החלפת ספק או שינוי COM. הוא רק חוסך הקלדה ושומר את הפלט מולך בסיום. אל תפעיל אותו אוטומטית בעליית המחשב ואל תיתן לו לרוץ כשאין איש ליד הזרועות.

## 12. עץ תקלות — מאיזה שלב להמשיך

עבור מלמעלה למטה ועצור בשאלה הראשונה שהתשובה עליה שלילית. אין צורך להריץ שוב את כל מסלול ההתקנה כשכבר ידוע היכן הכשל.

```text
Does Windows show the USB controller?
  NO  -> Data USB cable -> direct USB socket -> device/driver identity
  YES -> Does the selected COM port open?
           NO  -> Correct COM -> close FD/other processes -> reconnect
           YES -> Do motors answer a scan?
                    NONE -> Power -> first bus cable -> board mode
                            -> baud scan -> one isolated motor
                    SOME -> IDs -> inter-motor cables -> power stability
                    ALL  -> Correct model and IDs?
                              NO  -> Verify labels -> setup one motor at a time
                              YES -> Same firmware within this arm?
                                       NO  -> FD -> compatible update -> read back
                                       YES -> Calibration completes?
                                                NO  -> physical mapping/range/file error
                                                YES -> Small teleop test
```

### תוצאות שחשוב לא לבלבל ביניהן

**״הפורט נמצא״:** Windows רואה התקן טורי. זה לא מוכיח שהמנועים מוזנים. **״שישה מנועים ענו״:** יש שש תשובות בכתובות שונות. זה לא מוכיח שהתמסורות נכונות. **״הקושחה אחידה״:** בדיקת גרסאות עברה. זה לא מוכיח כיול. **״הכיול נשמר״:** נוצרה תוצאה; צריך לבדוק שהיא מתאימה למכניקה. **״הפקודה רצה״:** התהליך חי; הצלחת המערכת דורשת תנועה נכונה של הזרוע.

אם מנוע עונה לבד ונעלם בשרשרת, הכיוון הוא כתובות, חיווט או עומס על ההזנה. אם הכול עונה במנוחה אך יש ניתוקים בזמן תנועה, בדוק כבלים שנמשכים, ספק וצריכת זרם תחת עומס. אם מפרק אחר זז, בדוק שיוך ID למפרק. אם הכיוון שגוי, בדוק הרכבה וכיול לפני שינוי קוד.

### איך לשמור ראיות שאפשר לעבוד איתן

ב־Windows אפשר להשתמש ב־`Win+Shift+S` לצילום ישיר. צלם את הפקודה ואת סוף החריגה; אם אינה נכנסת, שמור גם את הפלט כטקסט. דוגמה לשמירת **סריקה בלבד** לקובץ, אחרי יצירת `so101-work` והגדרת הפורט:

```bat
python -c "import os; from lerobot.motors.feetech import FeetechMotorsBus; print(FeetechMotorsBus.scan_port(os.environ['FOLLOWER_PORT']))" > "%USERPROFILE%\so101-work\follower-scan.txt" 2>&1
type "%USERPROFILE%\so101-work\follower-scan.txt"
```

בפקודה הזאת הפלט לא מופיע בזמן אמת כי הוא נכתב לקובץ; המתן לסיום. אל תשתמש באותה הפניה לקובץ עבור כיול אינטראקטיבי בלי יכולת לראות את ההנחיות. לכל בדיקה רשום צבע, תפקיד, COM, ספק, שעה ומה שינית מאז הבדיקה הקודמת.

## 13. מה להכין לפני מחר ב־11:00

הפגישה היא **7.10.2026 בשעה 11:00**. הזרועות והמחשב נשארים במעבדה; אין צורך לקחת אותם הביתה. המטרה היא להגיע עם סביבת העבודה והמידע בהישג יד, לא להשלים לבד את כל העדכונים לפני הפגישה.

### להשאיר ליד שתי הזרועות

- שני הספקים המקוריים עם תוויות גלויות; אל תחליף ביניהם לצורך ניסוי.
- שני בקרי ה־USB, הכבלים וכל חלק שניתקת. אם יש כבל USB או bus חלופי, שים גם אותו.
- פתק עם צבע ותפקיד של כל זרוע ופורט של כל בקר, אם כבר זוהה.
- מחשב Windows זמין, Miniconda Prompt או החלון שבו ההתקנה הקיימת פועלת, ו־FD שאיתו ניסית לעדכן.
- קליבות ומברגים. אם יש אריזות מנועים, מק״טים או מסמך מהספק, השאר אותם לצד הציוד.
- עותק קובצי הכיול הקודמים, אם קיימים, והפקודה שפעלה לפני שהזרוע השנייה הפסיקה לענות.

### הבדיקה שכדאי להריץ מראש

אם התאמת החשמל כבר ידועה, הרץ **סריקת מנועים אחת לכל זרוע בנפרד** לפי פרק 7 ושמור את הפלט. זו הבדיקה שתבחין בין COM נגיש לבין מנועים שעונים, ותראה כתובות ומהירויות. אם התאמת המתח אינה ברורה, דלג על הפעלת מנועים והכן את צילומי התוויות.

אפשר גם לפתוח FD, לקרוא גרסאות ולצלם את שלב Online שבו נתקעת — בלי להתחיל צריבה לא ודאית. אין צורך להריץ teleop או לפרק את כל ההרכבה כהכנה. את התנועה הראשונה נעשה אחרי שהבדיקות הקודמות ברורות.

### מה לצלם

1. תמונה רחבה של כל זרוע, כך שרואים את הבקר, הספק ותחילת שרשרת הכבלים.
2. תקריב של תוויות המנועים: דגם, מתח ותמסורת, במיוחד IDs ‏3 ו־4 ובמנועים השונים מהשאר.
3. תוויות הספקים: מתח, זרם וקוטביות, ואת השקע שאליו כל אחד מתחבר.
4. שני צדי הבקר, כולל סימון דגם וג׳אמפרים.
5. חלון FD עם גרסת התוכנה, המנוע הנבחר, הגרסה הנוכחית וההודעה המדויקת בזמן ניסיון העדכון.
6. פלט הסריקה האחרון לכל זרוע, והפקודה שהרצת מעליו.

אל תדחס את כל התמונות לקולאז׳ קטן. צילום חד של תווית אחת מועיל יותר מצילום כל השולחן שבו אי אפשר לקרוא את המתח.

### דף קצר למילוי במהלך העבודה

```text
Arm color:
Role: leader / follower
Motor labels and voltage:
Power supply: voltage / current / polarity
Controller model:
USB port:
Baud rate:
Motor IDs and physical joints:
Firmware versions:
LeRobot version / source commit:
Calibration file:
Last successful command:
Current error:
One change made since the last test:
Next test:
```

בסוף הפגישה נרצה שתוכל לפתוח את הסביבה, לזהות את הפורטים, להריץ את הפקודה שנבדקה ולעצור בבטחה. אם חסר עדכון מתאים או רכיב, נרצה לצאת עם חסם אחד ברור והבדיקה שמוכיחה אותו, במקום ״הרובוט לא עובד״.

## 14. נספח קצר: אם עובדים גם על macOS

הלוגיקה זהה, אבל הפורטים ותחביר המעטפת שונים. ב־macOS משתמשים ב־Terminal ובנתיבים כגון `/dev/tty.usbmodem...` או `/dev/cu.usbserial...`, בהתאם לבקר. אין להעתיק COM5 למק. אם יש כבר התקנת LeRobot מוכנה, מפעילים אותה; אין צורך ליצור סביבה נוספת.

דוגמת התקנה חדשה עם Python 3.12 זמין:

```sh
python3.12 -m venv "$HOME/so101-venv"
source "$HOME/so101-venv/bin/activate"
python -m pip install --upgrade pip
python -m pip install 'lerobot[feetech]'
python -m serial.tools.list_ports -v
lerobot-find-port
```

אם `python3.12` אינו קיים, צריך להתקין גרסת Python מתאימה ממקור רשמי או ליצור סביבת Conda עם Python 3.12. אין לשנות את Python של מערכת ההפעלה. גם כאן גרסת ההפצה עשויה להיות שונה מהמקור שנבדק; מסלול ההתקנה מן ה־commit בפרק 5 חל גם במק עם התאמת נתיבי התיקיות.

החלף את שני הנתיבים הבאים בפורטים שזיהית בפועל:

```sh
export FOLLOWER_PORT='/dev/tty.usbmodem_REPLACE_FOLLOWER'
export LEADER_PORT='/dev/tty.usbmodem_REPLACE_LEADER'
python -c "import os; from lerobot.motors.feetech import FeetechMotorsBus; print(FeetechMotorsBus.scan_port(os.environ['FOLLOWER_PORT']))"
```

דוגמאות לכיול עם נתיבים מפורשים:

```sh
mkdir -p "$HOME/so101-work/calibration/leader" "$HOME/so101-work/calibration/follower"
lerobot-calibrate --teleop.type=so101_leader --teleop.port="$LEADER_PORT" --teleop.id=benjamin_leader --teleop.calibration_dir="$HOME/so101-work/calibration/leader"
lerobot-calibrate --robot.type=so101_follower --robot.port="$FOLLOWER_PORT" --robot.id=benjamin_follower --robot.calibration_dir="$HOME/so101-work/calibration/follower"
```

אחרי אותם שערי בטיחות וכיול, פקודת המעקב היא:

```sh
lerobot-teleoperate \
  --robot.type=so101_follower --robot.port="$FOLLOWER_PORT" \
  --robot.id=benjamin_follower \
  --robot.calibration_dir="$HOME/so101-work/calibration/follower" \
  --teleop.type=so101_leader --teleop.port="$LEADER_PORT" \
  --teleop.id=benjamin_leader \
  --teleop.calibration_dir="$HOME/so101-work/calibration/leader" \
  --fps=20 --teleop_time_s=30 --display_data=false
```

כאן `\` בסוף שורה הוא המשך פקודה ב־shell של המק; הוא **אינו** סימן ההמשך ב־CMD של Windows. לכן פקודות Windows במדריך ניתנו בשורה אחת.

אם הבקר מופיע בהתקני USB אבל אין פורט, מזהים את השבב ובודקים דרייבר מתאים. מקורות יצרן: [WCH ל־macOS](https://www.wch-ic.com/downloads/CH34XSER_MAC_ZIP.html) ו־[Silicon Labs CP210x](https://www.silabs.com/software-and-tools/usb-to-uart-bridge-vcp-drivers). לא מתקינים את שניהם בלי לדעת מהו הבקר.

**צריבת הקושחה המתוארת כאן נעשית ב־Windows עם FD הרשמי.** קיים כלי Qt פתוח לאבחון במק ובלינוקס, אך לפי תיעוד LeRobot הוא אינו תחליף למסלול עדכון הקושחה הרשמי. לפתרון בעיית 3.9/3.10 נשארים עם מחשב Windows שלך.

## 15. מקורות והמשך קריאה

הפקודות וההסברים הטכניים נבדקו מול המקורות הבאים. השיחה, התמלול והצילומים סיפקו את המצב הספציפי שלך; לא הועלה לכאן ארכיון השיחה או קובץ ההקלטה.

- [מדריך SO-101 הרשמי — הרכבה, כתובות וכיול](https://huggingface.co/docs/lerobot/so101).
- [LeRobot — עדכון קושחת Feetech](https://huggingface.co/docs/lerobot/feetech).
- [Feetech — הורדת תוכנות](https://www.feetechrc.com/software.html).
- [SO-ARM100 / SO-101 — מפרט החומרה והספקים](https://github.com/TheRobotStudio/SO-ARM100/blob/a758567c3978dfeefe282ede0500085a48fe8f78/README.md).
- [LeRobot — הגדרת חבילה, Python ותלויות בגרסת המקור שנבדקה](https://github.com/huggingface/lerobot/blob/8c920c4270460851cedd2737657584586d3dc66f/pyproject.toml).
- [Feetech bus — בדיקות הגרסה והתקשורת](https://github.com/huggingface/lerobot/blob/8c920c4270460851cedd2737657584586d3dc66f/src/lerobot/motors/feetech/feetech.py).
- [Motor bus — סריקה, כתובות ומהירויות](https://github.com/huggingface/lerobot/blob/8c920c4270460851cedd2737657584586d3dc66f/src/lerobot/motors/motors_bus.py).
- [מימוש follower — כיול ותנועה](https://github.com/huggingface/lerobot/blob/8c920c4270460851cedd2737657584586d3dc66f/src/lerobot/robots/so_follower/so_follower.py).
- [מימוש leader — כיול וקריאת המפרקים](https://github.com/huggingface/lerobot/blob/8c920c4270460851cedd2737657584586d3dc66f/src/lerobot/teleoperators/so_leader/so_leader.py).
- [כלי teleoperate — הפרמטרים והלולאה](https://github.com/huggingface/lerobot/blob/8c920c4270460851cedd2737657584586d3dc66f/src/lerobot/scripts/lerobot_teleoperate.py).

המטרה הראשונה שלנו פשוטה ומדידה: כל זרוע עונה באופן יציב, הכיול מתאים לה, ואז תנועה קטנה ביד שלך גורמת למפרק הנכון ב־follower לעקוב. משם אפשר להתקדם.
