Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8836f0a
Revert key-carrying heartbeat, halve drive and arm speed
pawel120 Sep 26, 2026
4984e4a
Add tools/calibrate_joint.py: calibrate one arm joint without lerobot…
pawel120 Sep 26, 2026
3e396b1
Add docs/PANEL.md: connect to Pi and start drive + arm panels
pawel120 Sep 26, 2026
642ced3
docs/PANEL.md: shorten to bare commands per terminal
pawel120 Sep 26, 2026
711174f
calibrate_joint: --joint all records and writes all six joints at once
pawel120 Sep 26, 2026
fe7479a
New arm HOME for the camera-on-arm mount (read with ./arm.sh status)
pawel120 Sep 26, 2026
a530081
Live arm-only grasp experiments: grasp table, WaypointArm.play, tools…
pawel120 Sep 26, 2026
a3d8a01
Live arm-only grasping: demonstrations, teach loop, model, docs to co…
pawel120 Sep 26, 2026
ac51fa5
tools/act_pick.py: chwyt ACT (lerobot-rollout) + wrzut drop_box
pawel120 Sep 27, 2026
db36c7f
docs/ACT_TRAINING.md: nagranie, trening (Franek, RTX 3070), chwyt act…
pawel120 Sep 27, 2026
2a0e1e9
docs/ACT_TRAINING.md: so101_grasp2 gotowy (50 ep.), overload grippera
pawel120 Sep 27, 2026
164cc80
tools/cam_preview.py: podglad kamery w tym samym procesie co lerobot
pawel120 Sep 27, 2026
eefa5a4
WIP tools/drive_calib.py: kalibracja jazdy z glebi RealSense i zyrosk…
pawel120 Sep 27, 2026
d3edc9d
docs: STATUS i LOG - drive_calib, pokrycie z istniejacymi branchami
pawel120 Sep 27, 2026
ad135c2
Merge remote-tracking branch 'origin/master' into pawel/act-pick
pawel120 Sep 27, 2026
076a1d6
Merge remote-tracking branch 'origin/master' into fix/drive-calib
TomkeMonke Sep 27, 2026
d7673c8
Merge remote-tracking branch 'origin/master' into fix/arm-home-cam
TomkeMonke Sep 27, 2026
c34e8a5
Merge remote-tracking branch 'origin/master' into fix/docs-panel-guide
TomkeMonke Sep 27, 2026
3670f7a
Merge remote-tracking branch 'origin/master' into fix/drive-revert-he…
TomkeMonke Sep 27, 2026
1ff1c73
Merge remote-tracking branch 'origin/master' into fix/act-pick
TomkeMonke Sep 27, 2026
695ccc6
Merge remote-tracking branch 'origin/pawel/act-pick' into tomek/merge…
TomkeMonke Sep 27, 2026
60e30cb
Merge remote-tracking branch 'origin/pawel/drive-revert-heartbeat-hal…
TomkeMonke Sep 27, 2026
4563b4c
Merge remote-tracking branch 'origin/pawel/arm-home-cam' into tomek/m…
TomkeMonke Sep 27, 2026
eac010a
Merge remote-tracking branch 'origin/pawel/docs-panel-guide' into tom…
TomkeMonke Sep 27, 2026
6687fc3
Merge remote-tracking branch 'origin/pawel/drive-calib' into tomek/me…
TomkeMonke Sep 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ nieliniowe kola, port szeregowy).
| `bag_to_rtabmap.py`, `render_map_preview.py` | mapa ogrodu RTAB-Map (issue #7, odlozone) |
| `so101_urdf/` | model URDF ramienia |
| `deploy/` | `setup_pi.sh` (instalacja na Pi), `push_to_pi.sh` (wyslanie kodu), udev, autostart panelu |
| `docs/` | STATUS (stan), SETUP, RUNBOOK, HARDWARE, LOG (dziennik sesji), CONTRIBUTING (zasady) |
| `docs/` | STATUS (stan), SETUP, PANEL, RUNBOOK, HARDWARE, LOG (dziennik sesji), CONTRIBUTING (zasady) |
| `legacy/` | odlozone: IK i slepy podjazd, nagrania sprzed naprawy barku, stare skrypty jazdy ([legacy/README.md](legacy/README.md)) |
| `requirements-pinecone.txt` | zaleznosci laptopa (numpy, opencv, pyserial, pytest); Pi: `requirements-pi.txt` |

Expand All @@ -61,6 +61,7 @@ nieliniowe kola, port szeregowy).
- [docs/STATUS.md](docs/STATUS.md): stan projektu, aktualizowany w kazdym PR.
- [docs/LOG.md](docs/LOG.md): dziennik sesji, tylko dopisywanie.
- [docs/RUNBOOK.md](docs/RUNBOOK.md): jak odpalic robota krok po kroku.
- [docs/PANEL.md](docs/PANEL.md): polaczenie z Pi i odpalenie panelu jazdy + ramienia.
- [docs/SETUP.md](docs/SETUP.md): instalacja laptop / Pi.
- [docs/HARDWARE.md](docs/HARDWARE.md): sprzet i pulapki.
- [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md): jak pracujemy.
Expand Down
12 changes: 6 additions & 6 deletions arm_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@
# z fix_shoulder_offset.py (2026-09-25). Po kazdej zmianie kalibracji spisz na nowo
# przez `./arm.sh status` w zlozonej pozie.
HOME_POSE = {
"shoulder_pan": 1.27,
"shoulder_lift": -85.05,
"elbow_flex": 99.0,
"wrist_flex": -102.11,
"wrist_roll": 89.10,
"gripper": 1.69,
"shoulder_pan": -5.45,
"shoulder_lift": 88.92,
"elbow_flex": 7.56,
"wrist_flex": -87.87,
"wrist_roll": 88.88,
"gripper": 41.06,
}

# Limit ruchu na jedno wywolanie send_action (stopnie / jednostki motoru) - zabezpieczenie
Expand Down
98 changes: 98 additions & 0 deletions docs/ACT_TRAINING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# ACT krok po kroku: nagranie -> trening -> chwyt na robocie

Dwa etapy chwytu: ACT (siec) robi TYLKO chwyt szyszki (HOME -> szyszka -> zamkniecie -> uniesienie),
wrzut do sloika robi nagrany ruch `motions/drop_box.json` (na Pi). Laczy je `tools/act_pick.py`.

Adresy: Pi = `robot@172.20.10.4` (hotspot "iPhone pawel"; gdy nie odpowiada: `hostname -I` na Pi).
Kamera na ramieniu: D435, serial `030522070668`. Datasety na Pi: `~/datasets/`.

## 1. Pi: nagrywanie epizodow (leader)

Leader wpiety w Pi jako `/dev/robot-leader` (zamiast kabla hovera - Pi nie ma wolnego USB).
Sprawdz: `ls -l /dev/robot-*` -> `robot-arm` i `robot-leader`. Zasilanie Pi mocne (`vcgencmd get_throttled` = `0x0`),
inaczej kamera gubi klatki (`frame is too old`), a spadek napiecia potrafi uszkodzic pliki venv.

```
pkill -f lerobot; pkill -f arm_web.py; pkill -f web_control.py
cd ~/hackaton && SVT_LOG=1 .venv/bin/lerobot-record --robot.type=so101_follower --robot.port=/dev/robot-arm --robot.id=so101 --robot.cameras="{ wrist: {type: intelrealsense, serial_number_or_name: 030522070668, width: 640, height: 480, fps: 30}}" --teleop.type=so101_leader --teleop.port=/dev/robot-leader --teleop.id=so101_leader --dataset.repo_id=local/so101_grasp --dataset.root=/home/robot/datasets/so101_grasp2 --dataset.push_to_hub=false --dataset.num_episodes=50 --dataset.episode_time_s=15 --dataset.reset_time_s=5 --play_sounds=false --dataset.single_task="Grasp the pine cone and lift it"
```

- Podglad kamery w czasie nagrania (ten sam proces, kamera nie jest zajmowana drugi raz): zamiast
`.venv/bin/lerobot-record ...` daj `.venv/bin/python tools/cam_preview.py lerobot-record ...` (reszta bez zmian),
w przegladarce `http://<IP_PI>:8081/`. Osobny `rs_mjpeg_server.py` NIE moze chodzic obok lerobot.
- Dokladanie do istniejacego datasetu: ta sama komenda + `--resume=true`, `--dataset.num_episodes=` ile DOLOZYC.
- Ruchy tylko po linii `Recording episode N`. `Reset the environment` = przerwa: szyszka w nowe miejsce, leader do HOME.
- Klawisze: strzalka w prawo = koniec epizodu, w lewo = nagraj od nowa, Esc = koniec (zapisuje).
- 5 miejsc szyszki x 10 epizodow. Koniec epizodu = pozycja startowa `drop_box` (ramie z przodu, nisko, chwytak zamkniety).
- Warningi `libtorchcodec` i `Svt[...]` sa niegrozne (dekoder -> pyav, log kodera wideo).

Stan 2026-09-27 14:00: `so101_grasp2` = 50 ep., 22451 klatek, 30 fps - GOTOWY do pelnego treningu (2b).
`so101_grasp` 7 ep. (do probnego treningu 2a).

## 2. Laptop z RTX 3070 (Franek): trening

Raz: repo i venv wedlug `docs/SETUP.md` sekcja "lerobot do ACT" (torch cu128 + lerobot 0.6.1).

```
cd <repo>
git pull
.venv\Scripts\python -c "import torch; print(torch.cuda.is_available())"
```
Musi byc `True`.

### 2a. Probny trening (7 epizodow, sprawdza sam proces, ~15 min)

```
scp -r robot@172.20.10.4:/home/robot/datasets/so101_grasp C:/datasets/so101_grasp
.venv\Scripts\lerobot-train --dataset.repo_id=local/so101_grasp --dataset.root=C:/datasets/so101_grasp --policy.type=act --policy.device=cuda --policy.push_to_hub=false --steps=5000 --batch_size=8 --output_dir=outputs/act_test --job_name=act_test
```
`loss` w logu ma spadac. Wagi z 7 epizodow nie beda dobrze chwytac - to test procesu.

### 2b. Pelny trening (po 50 epizodach)

Najpierw na Pi nagrywanie zakonczone (Esc albo koniec 50), inaczej kopia bedzie niepelna.

```
scp -r robot@172.20.10.4:/home/robot/datasets/so101_grasp2 C:/datasets/so101_grasp2
.venv\Scripts\lerobot-train --dataset.repo_id=local/so101_grasp --dataset.root=C:/datasets/so101_grasp2 --policy.type=act --policy.device=cuda --policy.push_to_hub=false --steps=50000 --batch_size=8 --save_freq=10000 --output_dir=outputs/act_grasp --job_name=act_grasp
```
Na RTX 3070 kilka godzin; mozna testowac posrednie checkpointy (`outputs/act_grasp/checkpoints/<krok>/`).

### 2c. Wagi na Pi

```
ssh robot@172.20.10.4 "mkdir -p ~/models"
scp -r outputs/act_test/checkpoints/last/pretrained_model robot@172.20.10.4:/home/robot/models/act_grasp
```
(dla pelnego treningu `outputs/act_grasp/...` zamiast `outputs/act_test/...`)

## 3. Pi: chwyt na robocie (wylacznik w rece)

Nic innego nie moze trzymac portu ramienia: `pkill -f lerobot; pkill -f arm_web.py`.

```
cd ~/hackaton
.venv/bin/python tools/act_pick.py --policy ~/models/act_grasp --dry-run # tylko komendy
.venv/bin/python tools/act_pick.py --policy ~/models/act_grasp --skip-drop # sam chwyt ACT
.venv/bin/python tools/act_pick.py --policy ~/models/act_grasp # chwyt + sloik + HOME
.venv/bin/python tools/act_pick.py --policy ~/models/act_grasp --repeat 3
```

Podglad kamery w czasie chwytu: `http://<IP_PI>:8081/` (act_pick puszcza rollout przez `tools/cam_preview.py`,
`--preview-port 0` wylacza). Na czas wrzutu kamera jest zamknieta, obraz wraca przy kolejnym chwycie.

Sam ruch do sloika bez sieci: `.venv/bin/python tools/arm_play.py --motion drop_box --port /dev/robot-arm --home-first`.

## Pulapki (2026-09-27)

- Leader ma kalibracje SKOPIOWANA z followera (decyzja), czesc osi odwrocona. Dane dla ACT i tak poprawne
(akcja = cel followera). Naprawa: `drive_mode: 1` dla odwroconych stawow w
`~/.cache/huggingface/lerobot/calibration/teleoperators/so_leader/so101_leader.json`.
NIGDY `lerobot-calibrate` z `--robot.*` (plik followera ma reczna poprawke barku).
- `lerobot[dataset]` na Pi instalowac z override torcha, inaczej uv sciagnie torch z CUDA:
`printf 'torch==2.14.0+cpu\ntorchvision==0.29.0+cpu\n' > /tmp/ov.txt` i
`~/.local/bin/uv pip install --python .venv/bin/python --override /tmp/ov.txt --index-strategy unsafe-best-match --extra-index-url https://download.pytorch.org/whl/cpu 'lerobot[dataset]==0.6.1'`.
- `Overload error` na `id_=6` przy koncu nagrania = gripper followera dociskal szyszke az zadzialalo zabezpieczenie.
Dataset jest zapisany (finalize idzie przed disconnect). Kasowanie: otworzyc gripper, wylaczyc zasilanie serw na kilka s.
Przy nagrywaniu zamykac leaderem tylko do oporu - ACT nauczy sie docisku z danych.
- Bus error przy imporcie = plik uszkodzony po spadku napiecia; `--reinstall --no-deps --no-cache` tego pakietu.
97 changes: 97 additions & 0 deletions docs/LIVE_GRASP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Chwytanie szyszki samym ramieniem - jak kontynuowac (stan 2026-09-26 wieczor)

Cel: robot stoi (baza sie nie rusza), ramie SO-101 z kamera D435 na przedramieniu widzi szyszke
w pozycji HOME, samo ja chwyta, wrzuca do sloika i wraca do HOME. Deterministycznie: model z demonstracji
reka (regresja), bez ML/LLM w petli.

Kod: `tools/live_grasp/` (branch `pawel/arm-home-cam`). Skrypty ida na Pi przez `ssh ... python -`
(stdin), nic nie jest kopiowane na Pi. Uruchamiasz je z laptopa (git-bash, katalog repo)
przez `bash tools/live_grasp/pi.sh <skrypt> [VAR=plik] [--bg nazwa]`.

## Co jest zrobione i co wiemy

- HOME = poza `arm_control.HOME_POSE` (pan -5.45, lift 88.3, elbow 7.56, wrist -87.87, roll 88.88).
UWAGA: nowy HOME jest w repo, ale NIE wgrany na Pi (`arm_control.py`, `pinecone_bot/arm.py`, `motions/home.json`).
Skrypty w `tools/live_grasp/` maja HOME wpisany na sztywno, wiec dzialaja bez tego.
- Wykrywanie szyszek w HOME z glebi dziala (plaszczyzna ziemi RANSAC, szyszka = wybrzuszenie 1.2-8 cm,
chwytak wyciety maska koloru niebieskiego, kabel serwa wyciety prostokatem). Po zmroku kolor nie dziala:
maska chwytaka i wykrywanie reki potrzebuja swiatla w pokoju.
- Ruch do sloika i z powrotem: nagrany reka, dziala przy odtwarzaniu (`data/jar_cycle.json`,
`pick.py` ma go jako `JAR_UP` / `JAR_BACK`). Sloik musi stac tam, gdzie przy nagraniu (podstawa ok. -22 st).
- Model "szyszka w kamerze -> stawy chwytu" (`data/grasp_model.json`, 8 probek) jest ZA SLABY:
blad ok. 6 cm, w probach szczeki trafialy obok szyszki albo ja spychaly. Powody: polowa etykiet
z sesji 1-2 niepewna (znikalo kilka szyszek naraz), rozne style chwytu (bark 61-92 st).
- Pulapki sprzetu: serwa maja niskie P (16) - bez korekty calkujacej zostaje 2-4 st bledu (funkcja `go()`
w skryptach ja robi); podstawa ma w EEPROM zakres tylko +-23 st (1786-2308); bark stoi przy
Max_Position_Limit (88.4 st); serwo chwytaka przy scisku do 0 potrafi zniknac z magistrali - trzymac cel 3-4
ponizej odczytu; Pi na powerbanku raz sie zrestartowal (zasilanie).
- Kamera na przedramieniu: gdy szczeki sa nad szyszka, zaslaniaja ja - korekta ze zdjec przy samym chwycie
nie dziala (probowane: `grasp_servo.py`, `servo.py`, `attempt.py`). Wyjscie: dobry model z czystych danych
(ponizej) albo kamera na maszt (STATUS, krok 1).

## Nastepny krok: czyste uczenie (ok. 15 min) -> model -> test

Warunki: swiatlo w pokoju, laptop i Pi w tej samej sieci (hotspot), sloik w tym samym miejscu.

1. Sprawdz, ze Pi odpowiada i co widzi kamera:
```
ssh robot@robot.local uptime
bash tools/live_grasp/pi.sh snap_only.py
```
Zdjecie: `tools/live_grasp/out/snap_only.jpg` (lewo kolor, prawo wysokosc nad ziemia 0-6 cm).
Przed uczeniem nic nie moze trzymac kamery ani ramienia (`ssh robot@robot.local 'pgrep -af python'`).

2. Uczenie w tle na Pi (12 chwytow, max 20 min):
```
bash tools/live_grasp/pi.sh teach_clean.py --bg teach
ssh robot@robot.local tail -f /tmp/teach.err
```
Przebieg jednej rundy (program mowi w logu, co robi):
- robot w HOME czeka, az zobaczy DOKLADNIE 1 szyszke i zadnej reki (2 zgodne zdjecia);
- szeroko otwiera chwytak i wylacza torque = "twoja kolej";
- chwytasz ja reka, ZAWSZE tym samym stylem: bark nisko jak w HOME, pracuja podstawa, lokiec,
nadgarstek, szczeki schodza z gory. Zamkniecie chwytaka (ponizej 25, stabilnie 0.5 s, ramie > 5 st od HOME) = zapis;
- wrzucasz do sloika, otwierasz chwytak, puszczasz ramie; po 5 s robot wraca do HOME;
- kladziesz nastepna szyszke w NOWYM miejscu (blisko/daleko, lewo/srodek/prawo), reka poza kadr.

3. Pobierz dane i dopasuj model (laptop):
```
ssh robot@robot.local cat /tmp/teach.jsonl > tools/live_grasp/data/teach_session3_full.jsonl
python tools/live_grasp/fit.py tools/live_grasp/data/teach_session3_full.jsonl tools/live_grasp/data/grasp_model.json
```
Patrz na wiersz "blad zostaw-jedna [st]": podstawa < 2 st, bark/lokiec/nadgarstek < 4 st = mozna testowac.
Wiekszy blad = wiecej probek w tych samych warunkach albo sprawdz zdjecia HOME (pole `img` w jsonl).
Do repo wrzucaj wersje bez zdjec:
```
python -c "import json,sys;[print(json.dumps({k:v for k,v in json.loads(l).items() if k!='img'})) for l in open(sys.argv[1])]" tools/live_grasp/data/teach_session3_full.jsonl > tools/live_grasp/data/teach_session3.jsonl
```

4. Test: jedna szyszka w polu, ktore bylo w uczeniu (program odmawia poza nim):
```
bash tools/live_grasp/pi.sh pick.py MODEL=data/grasp_model.json
```
Log: wybrana szyszka, poza chwytu, odczyt chwytaka (>= 6 = trzyma), sloik, HOME. Zdjecie: `out/pick.jpg`.
Seria z poprawka po kazdej porazce (szyszka przepchnieta -> cel przesuwa sie o 70% przepchniecia):
```
bash tools/live_grasp/pi.sh pick_loop.py MODEL=data/grasp_model.json
```

## Inne narzedzia w katalogu

- `rec.py` - nagranie ruchu reka (torque off, stawy 30 Hz + zdjecie co 0.5 s): `REC_SECONDS` w env na Pi
nie jest przekazywany przez pi.sh - domyslnie 120 s. W tle: `pi.sh rec.py --bg rec`, potem
`ssh robot@robot.local cat /tmp/rec.out > plik`. Przyklad: `data/rec_demo_120s.jsonl` (9 cykli chwyt -> sloik).
- `replay.py` - odtworzenie nagranego cyklu (tempo x0.5): `pi.sh replay.py CYCLE=data/jar_cycle.json`.
Szyszka musi lezec tam, gdzie przy nagraniu.
- `step.py` - jeden ruch + zdjecie: `pi.sh step.py ARGS=plik.json`, plik np. `{"rel": {"shoulder_pan": 3}, "sec": 1.0}`.
- `snap_only.py` - zdjecie + pozycje stawow, bez ruchu ramienia.
- Eksperymenty, ktore NIE zadzialaly (do wgladu): `attempt.py` (celowanie w pozycji "nad" z koloru+glebi),
`servo.py` (serwo 3D z Jakobianem, zle mierzona koncowka szczeki), `grasp_servo.py` (korekta w pozie chwytu -
szczeki zaslaniaja szyszke).

## Bezpieczenstwo

- Przy kazdym uruchomieniu z ruchem: czlowiek przy robocie, reka przy wylaczniku.
- Przed `teach_clean.py` i `rec.py` torque jest wylaczany - ramie jest luzne, trzymaj je.
- Nie uruchamiaj `lerobot calibrate`. Nie zmieniaj limitow pozycji w EEPROM serw bez decyzji zespolu
(podstawa +-23 st to obecny limit, stare wartosci 1786/2308).
Loading
Loading