# HopeJR

## Yêu cầu tiên quyết

- [Cấu hình phần cứng](https://github.com/TheRobotStudio/HOPEJr)

## Cài đặt LeRobot

Làm theo [các hướng dẫn cài đặt](https://github.com/huggingface/lerobot#installation) để cài đặt LeRobot.

Cài đặt LeRobot với các phụ thuộc của HopeJR:

```bash
pip install -e ".[hopejr]"
```

## Cấu hình thiết bị

Trước khi bắt đầu hiệu chuẩn và vận hành, bạn cần xác định các cổng USB cho từng thành phần của HopeJR. Chạy script này để tìm các cổng USB cho cánh tay, bàn tay, găng tay và bộ khung ngoài:

```bash
lerobot-find-port
```

Điều này sẽ hiển thị các cổng USB khả dụng và các thiết bị liên quan. Hãy ghi chú lại đường dẫn của các cổng (ví dụ: `/dev/tty.usbmodem58760433331`, `/dev/tty.usbmodem11301`) vì bạn sẽ cần chỉ định chúng trong các tham số `--robot.port` và `--teleop.port` khi ghi dữ liệu, phát lại các episode, hoặc chạy các script teleoperation.

## Bước 1: Hiệu chuẩn

Trước khi thực hiện điều khiển từ xa, các chi của HopeJR cần được hiệu chuẩn. Các tệp hiệu chuẩn sẽ được lưu trong `~/.cache/huggingface/lerobot/calibration`

### 1.1 Hiệu chuẩn tay robot

```bash
lerobot-calibrate \
    --robot.type=hope_jr_hand \
    --robot.port=/dev/tty.usbmodem58760432281 \
    --robot.id=blue \
    --robot.side=right
```

Khi chạy script hiệu chuẩn, một GUI hiệu chuẩn sẽ bật lên. Các khớp ngón tay được đặt tên như sau:

**Ngón cái**:

- **CMC**: khớp cơ bản nối ngón cái với bàn tay
- **MCP**: khớp ngón
- **PIP**: khớp ngón tay thứ nhất
- **DIP** : khớp ngón tay

**Ngón trỏ, ngón giữa, ngón áp út và ngón út**:

- **Cơ gấp hướng tâm**: Di chuyển gốc ngón tay về phía ngón cái
- **Cơ gấp trụ**: Di chuyển gốc ngón tay về phía ngón út
- **PIP/DIP**: Gập khớp đốt xa và đốt gần của ngón tay

Mỗi một trong số này sẽ cần được hiệu chỉnh riêng biệt thông qua GUI. Lưu ý rằng cơ gấp trụ và cơ gấp quay nên có phạm vi kích thước như nhau (nhưng với các độ lệch khác nhau) để đạt được chuyển động đối xứng.

  <img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/calibration_gui_1.png" alt="Đặt ranh giới trong GUI hiệu chỉnh tay" title="Đặt ranh giới trong GUI hiệu chỉnh tay" width="100%"
  >

Sử dụng giao diện hiệu chuẩn để đặt các giới hạn phạm vi cho từng khớp như đã hiển thị ở trên.

  <img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/calibration_gui_2.png" alt="Lưu giá trị hiệu chuẩn" title="Lưu giá trị hiệu chuẩn" width="100%"
  >

Sau khi bạn đã thiết lập các giới hạn phù hợp cho tất cả các khớp, hãy nhấp vào "Save" để lưu các giá trị hiệu chuẩn vào động cơ.

### 1.2 Hiệu chuẩn găng tay điều khiển từ xa

```bash
lerobot-calibrate \
    --teleop.type=homunculus_glove \
    --teleop.port=/dev/tty.usbmodem11201 \
    --teleop.id=red \
    --teleop.side=right
```

Di chuyển từng ngón tay qua toàn bộ phạm vi chuyển động của nó, bắt đầu từ ngón cái.

```
Move thumb through its entire range of motion.
Recording positions. Press ENTER to stop...

-------------------------------------------
NAME      |    MIN |    POS |    MAX
thumb_cmc |   1790 |   1831 |   1853
thumb_mcp |   1497 |   1514 |   1528
thumb_pip |   1466 |   1496 |   1515
thumb_dip |   1463 |   1484 |   1514
```

Tiếp tục với từng ngón tay:

```
Move middle through its entire range of motion.
Recording positions. Press ENTER to stop...

-------------------------------------------
NAME                 |    MIN |    POS |    MAX
middle_mcp_abduction |   1598 |   1718 |   1820
middle_mcp_flexion   |   1512 |   1658 |   2136
middle_dip           |   1484 |   1500 |   1547
```

Khi hiệu chuẩn hoàn tất, hệ thống sẽ lưu hiệu chuẩn vào `/Users/your_username/.cache/huggingface/lerobot/calibration/teleoperators/homunculus_glove/red.json`

### 1.3 Hiệu chuẩn cánh tay robot

```bash
lerobot-calibrate \
    --robot.type=hope_jr_arm \
    --robot.port=/dev/tty.usbserial-1110 \
    --robot.id=white
```

Điều này sẽ mở một GUI hiệu chuẩn, nơi bạn có thể đặt giới hạn phạm vi cho mỗi động cơ. Các chuyển động của cánh tay được tổ chức như sau:

- **Vai**: pitch, yaw và roll
- **Khuỷu tay**: gập
- **Cổ tay**: pitch, yaw và roll

  <img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/calibration_gui_2.png" alt="Đặt giới hạn trong GUI hiệu chuẩn cánh tay" title="Đặt giới hạn trong GUI hiệu chuẩn cánh tay" width="100%"
  >

Sử dụng giao diện hiệu chuẩn để đặt các ranh giới phạm vi cho từng khớp. Di chuyển từng khớp qua toàn bộ phạm vi chuyển động của nó và điều chỉnh các giá trị tối thiểu và tối thiểu tương ứng. Sau khi bạn đã đặt các ranh giới phù hợp cho tất cả các khớp, hãy lưu hiệu chuẩn.

### 1.4 Hiệu chuẩn bộ xương ngoài cho người vận hành

```bash
lerobot-calibrate \
    --teleop.type=homunculus_arm \
    --teleop.port=/dev/tty.usbmodem11201 \
    --teleop.id=black
```

Bộ khung ngoài cho phép điều khiển cánh tay robot. Trong quá trình hiệu chuẩn, bạn sẽ được yêu cầu di chuyển tất cả các khớp qua toàn bộ phạm vi chuyển động của chúng:

```
Move all joints through their entire range of motion.
Recording positions. Press ENTER to stop...

-------------------------------------------
-------------------------------------------
NAME            |    MIN |    POS |    MAX
shoulder_pitch  |    586 |    736 |    895
shoulder_yaw    |   1257 |   1374 |   1390
shoulder_roll   |    449 |   1034 |   2564
elbow_flex      |   3023 |   3117 |   3134
wrist_roll      |   3073 |   3096 |   3147
wrist_yaw       |   2143 |   2171 |   2185
wrist_pitch     |   1975 |   1993 |   2074
Calibration saved to /Users/your_username/.cache/huggingface/lerobot/calibration/teleoperators/homunculus_arm/black.json
```

## Bước 2: Điều khiển từ xa

Do xung đột biến toàn cục trong middleware Feetech, teleoperation cho cánh tay và bàn tay phải chạy trong các phiên shell riêng biệt:

### Tay

```bash
lerobot-teleoperate \
    --robot.type=hope_jr_hand \
    --robot.port=/dev/tty.usbmodem58760432281 \
    --robot.id=blue \
    --robot.side=right \
    --teleop.type=homunculus_glove \
    --teleop.port=/dev/tty.usbmodem11201 \
    --teleop.id=red \
    --teleop.side=right \
    --display_data=true \
    --fps=30
```

### Arm

```bash
lerobot-teleoperate \
    --robot.type=hope_jr_arm \
    --robot.port=/dev/tty.usbserial-1110 \
    --robot.id=white \
    --teleop.type=homunculus_arm \
    --teleop.port=/dev/tty.usbmodem11201 \
    --teleop.id=black \
    --display_data=true \
    --fps=30
```

## Bước 3: Ghi, Phát lại, Huấn luyện

Hope-JR vẫn đang ở giai đoạn thử nghiệm.

### Ghi

Bước này ghi lại bộ dữ liệu, có thể xem như một ví dụ [tại đây](https://huggingface.co/datasets/nepyope/hand_record_test_with_video_data).

```bash
lerobot-record \
    --robot.type=hope_jr_hand \
    --robot.port=/dev/tty.usbmodem58760432281 \
    --robot.id=right \
    --robot.side=right \
    --robot.cameras='{"main": {"type": "opencv", "index_or_path": 0, "width": 640, "height": 480, "fps": 30}}' \
    --teleop.type=homunculus_glove \
    --teleop.port=/dev/tty.usbmodem1201 \
    --teleop.id=right \
    --teleop.side=right \
    --dataset.repo_id=<USER>/hand_record_test_with_video_data \
    --dataset.single_task="Hand recording test with video data" \
    --dataset.num_episodes=1 \
    --dataset.episode_time_s=5 \
    --dataset.push_to_hub=true \
    --dataset.private=true \
    --dataset.streaming_encoding=true \
    --dataset.encoder_threads=2 \
    --display_data=true
# Optional: --dataset.rgb_encoder.vcodec=auto
```

### Phát lại

```bash
lerobot-replay \
    --robot.type=hope_jr_hand \
    --robot.port=/dev/tty.usbmodem58760432281 \
    --robot.id=right \
    --robot.side=right \
    --dataset.repo_id=<USER>/hand_record_test_with_camera \
    --dataset.episode=0
```

### Huấn luyện

```bash
lerobot-train \
  --dataset.repo_id=<USER>/hand_record_test_with_video_data \
  --policy.type=act \
  --output_dir=outputs/train/hopejr_hand \
  --job_name=hopejr \
  --policy.device=mps \
  --trackio.enable=true \
  --policy.repo_id=<USER>/hand_test_policy
```

### Đánh giá

```bash
lerobot-record \
  --robot.type=hope_jr_hand \
  --robot.port=/dev/tty.usbmodem58760432281 \
  --robot.id=right \
  --robot.side=right \
  --robot.cameras='{"main": {"type": "opencv", "index_or_path": 0, "width": 640, "height": 480, "fps": 30}}' \
  --display_data=false \
  --dataset.repo_id=<USER>/eval_hopejr \
  --dataset.single_task="Evaluate hopejr hand policy" \
  --dataset.num_episodes=10 \
  --dataset.streaming_encoding=true \
  --dataset.encoder_threads=2 \
  --policy.path=outputs/train/hopejr_hand/checkpoints/last/pretrained_model
# Optional: --dataset.rgb_encoder.vcodec=auto
```

