improve questions 13 14 15 16 19 26
@ -3331,11 +3331,53 @@ Poniższe diagramy ilustrują kluczowe frameworki i modele omówione w pytaniu.
|
||||
|
||||
---
|
||||
|
||||
**Christopher Alexander** — architekt budynków (nie programista!), ojciec idei wzorców w inżynierii. W książce „A Pattern Language" (1977) opisał 253 wzorców architektonicznych — budowlanych. GoF zaadaptowali jego format do oprogramowania. Kluczowa idea: wzorzec to nie luźna rada, ale skodyfikowane rozwiązanie z ustandaryzowanym opisem.
|
||||
|
||||
**Forma opisu wzorca (pattern template)** — standardowy szablon, w jakim kataloguje się każdy wzorzec. To serce odpowiedzi na „JAK są katalogowane?" — każdy wzorzec opisany jest według ustalonej struktury, dzięki czemu można je porównywać, przeszukiwać i komponować. Pola szablonu: Nazwa → Kontekst/Problem → Siły (forces) → Rozwiązanie → Konsekwencje → Powiązane wzorce → Znane zastosowania. Różne katalogi mają różne warianty szablonu (GoF ma 13 pól, forma Aleksandryjska jest bardziej narracyjna), ale rdzeń jest wspólny.
|
||||
|
||||
**Siły (forces)** — konkurencyjne wymagania, które wzorzec próbuje pogodzić. Np. wzorzec Layered godzi testowalność vs wydajność: warstwy ułatwiają testowanie, ale dodają overhead. Siły to serce wzorca — wyjaśniają DLACZEGO dane rozwiązanie jest kompromisem, a nie „idealnym rozwiązaniem na wszystko".
|
||||
|
||||
**Klasyfikacja wzorców (pattern classification)** — sposób organizacji wzorców wewnątrz katalogu. Główne osie klasyfikacji:
|
||||
- **Skala/zasięg**: architektoniczny (cały system) → projektowy (klasa/obiekt) → idiomatyczny (linia kodu)
|
||||
- **Domena problemu**: np. GoF dzieli 23 wzorce na kreacyjne (5), strukturalne (7), behawioralne (11)
|
||||
- **Atrybut jakościowy**: wydajność, skalowalność, dostępność, testowalność
|
||||
- **Domena zastosowania**: enterprise, chmura, integracja, embedded
|
||||
|
||||
**Język wzorców (pattern language)** — zbiór wzorców, które wzajemnie się referują, tworząc nawigacyjną sieć. Wzorzec „Microservices" referuje „API Gateway", „Service Discovery", „Circuit Breaker". Można „czytać" język wzorców jak przepis: „zacznij od X → jeśli problem Y → zastosuj Z". To trzeci filar katalogowania obok szablonu opisu i klasyfikacji.
|
||||
|
||||
---
|
||||
|
||||
### Cel: reużywalne rozwiązania typowych problemów, wspólne słownictwo, dokumentacja wiedzy
|
||||
|
||||
### Powstawanie: Problem powtarzalny → Podobne rozwiązania → Uogólnienie → Dokumentacja → Walidacja → Katalogowanie
|
||||
|
||||
### Katalogi: POSA (wzorce architektoniczne), GoF (projektowe), EIP (integracja), PoEAA (Fowler), Cloud Patterns
|
||||
### Katalogowanie — trzy filary metodologii
|
||||
|
||||
**1. Ustandaryzowany szablon opisu** — każdy wzorzec opisany wg tego samego formatu:
|
||||
- **Nazwa** — jedno słowo/fraza: „Layered", „Observer"
|
||||
- **Problem/Kontekst** — kiedy stosować
|
||||
- **Siły (forces)** — konkurencyjne wymagania do pogodzenia
|
||||
- **Rozwiązanie** — struktura, diagram, zachowanie
|
||||
- **Konsekwencje** — tradeoffs: co zyskujemy, co tracimy
|
||||
- **Powiązane wzorce** — jakie wzorce współgrają lub konkurują
|
||||
- **Znane zastosowania** — real-world examples
|
||||
|
||||
**2. Klasyfikacja wieloosiowa** — wzorce organizowane wzdłuż kilku osi jednocześnie:
|
||||
- **Skala**: architektoniczny (cały system) → projektowy (klasa) → idiomatyczny (linia kodu)
|
||||
- **Domena problemu**: kreacyjne / strukturalne / behawioralne (GoF) albo warstwy / komunikacja / dekompozycja (POSA)
|
||||
- **Atrybut jakościowy**: wydajność, skalowalność, testowalność, dostępność
|
||||
|
||||
**3. Język wzorców (pattern language)** — wzorce referują się wzajemnie, tworząc graf:
|
||||
- Microservices → wymaga → API Gateway, Service Discovery, Circuit Breaker
|
||||
- Observer → wariant architektoniczny → Event-Driven Architecture
|
||||
- Nawigacja: „mam problem X → wzorzec A → prowadzi do problemu Y → wzorzec B"
|
||||
|
||||
**Konkretne katalogi:**
|
||||
- **POSA** (1996) — wzorce architektoniczne: Layers, Pipes & Filters, Broker, MVC, Microkernel
|
||||
- **GoF** (1994) — 23 wzorce projektowe: kreacyjne (5), strukturalne (7), behawioralne (11)
|
||||
- **EIP** (2003) — wzorce integracji: Message Channel, Router, Aggregator
|
||||
- **PoEAA** (2002) — enterprise: Repository, Unit of Work, Domain Model, Active Record
|
||||
- **Cloud Patterns** (~2015) — chmurowe: Circuit Breaker, Sidecar, Saga, Strangler Fig
|
||||
|
||||
### Przykładowe wzorce
|
||||
|
||||
@ -3362,9 +3404,18 @@ Poniższe diagramy ilustrują kluczowe frameworki i modele omówione w pytaniu.
|
||||
|
||||
### Jak zapamiętać
|
||||
|
||||
- **Mnemonik katalogów „PGEP+C"**: **P**OSA → **G**oF → **E**IP → **P**oEAA + **C**loud
|
||||
- Historia: „**P**aweł **G**rał **E**fektownie **P**od **C**hmurami"
|
||||
- Chronologicznie: GoF '94 → POSA '96 → PoEAA '02 → EIP '03 → Cloud ~'15
|
||||
- **Szablon wzorca „NaPSiRoKo"**: **Na**zwa, **P**roblem, **Si**ły, **Ro**związanie, **Ko**nsekwencje
|
||||
- Wyobraź sobie kartonowe pudełko: etykieta (Nazwa) → co nie działa (Problem) → wagi na szalce (Siły) → instrukcja montażu (Rozwiązanie) → lista „+" i „−" na boku (Konsekwencje)
|
||||
- **3 filary katalogowania**: Szablon + Klasyfikacja + Język wzorców
|
||||
- Analogia do encyklopedii: każde hasło ma ten sam format (szablon), jest w kategorii z innymi hasłami tego typu (klasyfikacja), i ma „zobacz też" (język wzorców)
|
||||
- **„Monolith first"** — rozdzielaj gdy znasz granice domen
|
||||
- **Wzorzec = Nazwa + Problem + Rozwiązanie + Konsekwencje**
|
||||
- Katalogi: POSA = architektura, GoF = klasy/obiekty, EIP = messaging
|
||||
- **Wzorzec = Nazwa + Problem + Rozwiązanie + Konsekwencje** (minimum do zapamiętania z dowolnego katalogu)
|
||||
- Katalogi wg skali: POSA = systemy, GoF = obiekty, EIP = komunikacja międzysystemowa
|
||||
|
||||
→ Diagramy do druku: `pytania/img/q14_pattern_template.png`, `pytania/img/q14_catalog_map.png`
|
||||
|
||||
\newpage
|
||||
|
||||
@ -3449,6 +3500,82 @@ Przykład: Robot-dostawca. Belief: „drzwi zamknięte". Desire: „dostarczyć
|
||||
|
||||
---
|
||||
|
||||
### Odpowiedź wprost: jak agent upostaciowiony specyfikuje sterownik robota
|
||||
|
||||
**Definicja:** Agent upostaciowiony (embodied agent) to formalny model konceptualny robota — bytu posiadającego ciało fizyczne, sensory i efektory, działającego w rzeczywistym środowisku. Wykorzystanie tego modelu do specyfikacji sterowników polega na tym, że **architektura sterownika robota jest bezpośrednim odwzorowaniem struktury agenta**: cykl percepcja–deliberacja–akcja staje się pętlą sterowania, a formalne modele agenta (BDI, LTL) stają się specyfikacją wymagań dla oprogramowania robota.
|
||||
|
||||
**Krótko: model agenta → architektura sterownika → implementacja na robocie.**
|
||||
|
||||
#### Krok 1: Model agenta definiuje CO robot ma robić
|
||||
|
||||
Robot traktujemy jako agenta upostaciowionego. To oznacza, że specyfikujemy:
|
||||
- **Sensory** — jakie dane wejściowe robot otrzymuje (LIDAR, kamera, IMU)
|
||||
- **Efektory** — jakie akcje fizyczne może wykonać (jedź, chwyć, obróć)
|
||||
- **Cel** — co agent ma osiągnąć (dostarczyć paczkę, unikać kolizji)
|
||||
- **Środowisko** — w jakim świecie działa (magazyn, szpital, droga)
|
||||
|
||||
#### Krok 2: Cykl See-Think-Act definiuje JAK działa pętla sterowania
|
||||
|
||||
Każdy sterownik robota realizuje wariant cyklu agenta:
|
||||
1. **See** — odczytaj sensory → zbuduj wewnętrzny model świata (np. mapę)
|
||||
2. **Think** — na podstawie modelu i celu wybierz akcję (planowanie)
|
||||
3. **Act** — wyślij komendy do silników/chwytaków
|
||||
|
||||
Ten cykl powtarza się w pętli z częstotliwością zależną od warstwy (ms → min).
|
||||
|
||||

|
||||
|
||||
#### Krok 3: Architektura 3T dzieli sterownik na warstwy odpowiedzialności
|
||||
|
||||
Praktyczna realizacja agenta upostaciowionego to **architektura trójwarstwowa (3T)**:
|
||||
|
||||
| Warstwa | Rola | Czas reakcji | Przykład |
|
||||
|---------|------|-------------|----------|
|
||||
| **Planner** | planowanie symboliczne (CEL → PLAN) | sekundy–minuty | "Jedź trasą A→B→C" |
|
||||
| **Sequencer** | koordynacja zachowań (PLAN → SEKWENCJA) | 100 ms–sekundy | FSM: IDLE→APPROACH→GRASP |
|
||||
| **Controller** | sterowanie sprzętem (SEKWENCJA → SYGNAŁY) | milisekundy | PID: prędkość = 0.5 m/s |
|
||||
|
||||
Każda warstwa odpowiada innemu aspektowi agenta:
|
||||
- Planner = deliberacja (myślenie długoterminowe)
|
||||
- Sequencer = koordynacja intencji (BDI: Intentions)
|
||||
- Controller = reaktywność (natychmiastowe bezpieczeństwo)
|
||||
|
||||

|
||||
|
||||
#### Krok 4: Formalne modele agenta specyfikują wymagania
|
||||
|
||||
**Model BDI** pozwala formalnie opisać stan wewnętrzny agenta i na tej podstawie generować/weryfikować sterownik:
|
||||
- Beliefs = wiedza robota → baza danych sensorycznych
|
||||
- Desires = cele → warunki sukcesu
|
||||
- Intentions = aktualny plan → sekwencer
|
||||
|
||||

|
||||
|
||||
**Logika temporalna LTL** pozwala specyfikować wymagania bezpieczeństwa i żywotności:
|
||||
- **Bezpieczeństwo:** □(obstacle → ¬move_forward) — "ZAWSZE: jeśli przeszkoda, NIE jedź naprzód"
|
||||
- **Żywotność:** ◇(at_goal) — "KIEDYŚ dotrzyj do celu"
|
||||
|
||||
Formalna specyfikacja LTL → automatyczna synteza/weryfikacja sterownika (model checking).
|
||||
|
||||
#### Krok 5: Behavior Trees implementują specyfikację zachowań
|
||||
|
||||
Nowoczesna metoda implementacji warstwy Sequencer. Modularność, reużywalność, łatwe debugowanie:
|
||||
|
||||

|
||||
|
||||
#### Konkretny przykład: robot-dostawca w szpitalu
|
||||
|
||||
1. **Model agenta:** sensory = LIDAR + kamera; efektory = koła + chwytak; cel = dostarcz lek do pokoju 5
|
||||
2. **BDI:** Belief = "drzwi pokoju 5 zamknięte"; Desire = "dostarczyć lek"; Intention = "jedź do drzwi bocznych"
|
||||
3. **LTL:** □(¬collision) ∧ ◇(at_room5) — "nigdy nie koliduj I w końcu dotrzyj do pokoju 5"
|
||||
4. **3T:**
|
||||
- Planner: A* wyznacza trasę korytarz → winda → piętro 3 → pokój 5
|
||||
- Sequencer: BT: [Jedź do windy → Wjedź → Jedź do pokoju → Otwórz drzwi → Podaj lek]
|
||||
- Controller: PID utrzymuje prędkość 0.3 m/s, emergency stop przy przeszkodzie < 30 cm
|
||||
5. **ROS:** node `/lidar_scan` → topic → node `/path_planner` → topic → node `/motor_driver`
|
||||
|
||||
---
|
||||
|
||||
### Agent upostaciowiony = ciało fizyczne + sensory + efektory + środowisko
|
||||
|
||||
Cykl: **Percepcja → Deliberacja → Akcja** (See-Think-Act)
|
||||
@ -3481,9 +3608,14 @@ Cykl: **Percepcja → Deliberacja → Akcja** (See-Think-Act)
|
||||
|
||||
### Jak zapamiętać
|
||||
|
||||
- **„See-Think-Act"** = Percepcja → Deliberacja → Akcja
|
||||
- **3T = Plan-Sequence-Control** (od abstrakcji do sprzętu)
|
||||
- BDI = Beliefs, Desires, Intentions
|
||||
- **"STA"** = **S**ee → **T**hink → **A**ct (jak STA-bilność — stabilny cykl sterowania)
|
||||
- **3T = "Plan-Seq-Con"** = od abstrakcji do sprzętu, jak w armii: generał (Plan) → oficer (Seq) → żołnierz (Con)
|
||||
- **BDI = "Wiem–Chcę–Robię"**: Beliefs = co Wiem, Desires = co Chcę, Intentions = co Robię
|
||||
- **LTL: □ = "zawsze" (kwadrat = solidny, niezmienny), ◇ = "kiedyś" (diament = cenny cel do zdobycia)**
|
||||
- **Agent→Sterownik w 5 krokach:** CO (model agenta) → JAK (STA) → WARSTWY (3T) → WYMAGANIA (BDI+LTL) → IMPLEMENTACJA (BT+ROS)
|
||||
- **Akronim SPECYFIKACJA:** **S**ensory → **P**ercepcja → **E**fekty → **C**ykl → **I**ntencje → **F**ormalność → **I**mplementacja → **K**ontroler → **A**kcja → **C**el → **J**akość → **A**rchitektura
|
||||
|
||||
→ Diagramy do druku: `pytania/img/agent_see_think_act.png`, `pytania/img/agent_3t_architecture.png`, `pytania/img/agent_bdi_model.png`, `pytania/img/agent_behavior_tree.png`
|
||||
|
||||
\newpage
|
||||
|
||||
@ -3495,7 +3627,7 @@ Cykl: **Percepcja → Deliberacja → Akcja** (See-Think-Act)
|
||||
|
||||
### Tło pojęciowe — słowniczek
|
||||
|
||||
**Robot** — cz. „robota" = ciężka praca; termin ukuty przez Karla Čapka (R.U.R., 1920). W przemyśle: programowalna maszyna wykonująca zadania (spawanie, paletyzacja, montaż). W kontekście pytania: głównie roboty przemysłowe (manipulatory).
|
||||
**Robot** — cz. „robota" = ciężka praca; termin ukuty przez Karla Čapka (R.U.R., 1920). W przemyśle: programowalna maszyna wykonująca zadania (spawanie, paletyzacja, montaż). W kontekście pytania: głównie roboty przemysłowe (manipulatory) — ramiona z 4–7 osiami obrotu, sterowane komputerowo.
|
||||
|
||||
**Język programowania robotów** — język do definiowania zachowania robota: ruchy, logika, I/O. Może być specjalizowany (dedykowany producenta) lub ogólny (C++, Python z bibliotekami). Klasyfikacja wg poziomu abstrakcji — od zadań po sygnały silników.
|
||||
|
||||
@ -3505,88 +3637,455 @@ Cykl: **Percepcja → Deliberacja → Akcja** (See-Think-Act)
|
||||
|
||||
**Task-level (poziom zadania)** — najwyższy: opisujesz CO robot ma zrobić, nie JAK. „Podnieś A, połóż na B." Robot sam planuje ruchy. Przykłady: PDDL, Behavior Trees.
|
||||
|
||||
// Task-level:
|
||||
// Task-level (pseudokod):
|
||||
pick(objectA);
|
||||
place(locationB);
|
||||
// Robot sam oblicza kinematykę, trajektorię, chwyt
|
||||
|
||||
**Robot-level (poziom robota)** — komendy ruchu w przestrzeni kartezjańskiej lub konfiguracyjnej: move_to(x,y,z), grasp(). Programista mówi GDZIE jechać, robot oblicza JAK (kinematyka odwrotna). Przykłady: RAPID (ABB), KRL (KUKA), Karel (FANUC).
|
||||
|
||||
// RAPID (ABB):
|
||||
MoveL p1, v500, fine, tool1; // liniowo do p1, prędkość 500 mm/s
|
||||
**Robot-level (poziom robota)** — komendy ruchu w przestrzeni kartezjańskiej lub konfiguracyjnej: move_to(x,y,z), grasp(). Programista mówi GDZIE jechać, robot oblicza JAK (kinematyka odwrotna). Tu działają języki producentów: RAPID (ABB), KRL (KUKA), Karel (FANUC), PDL2 (Comau), URScript (Universal Robots).
|
||||
|
||||
**Motion-level (poziom ruchu)** — planowanie trajektorii: generowanie ciągu punktów od startu do celu z unikaniem kolizji. Kinematyka odwrotna, interpolacja. Przykłady: MoveIt (ROS), OMPL.
|
||||
|
||||
**Servo-level (poziom serwa)** — najniższy: bezpośrednie sterowanie silnikami/serwomechanizmami. Regulacja PID, sygnały PWM. Języki: C/C++, FPGA. Czas reakcji: mikro-milisekundy.
|
||||
**Servo-level (poziom serwa)** — najniższy: bezpośrednie sterowanie silnikami/serwomechanizmami. Regulacja PID, sygnały PWM. Języki: C/C++, FPGA/VHDL. Czas reakcji: mikro-milisekundy.
|
||||
|
||||
Przykład czasu reakcji na każdym poziomie:
|
||||
Task: "Zamontuj śrubę" (sekundy)
|
||||
Robot: MoveL do_pozycji (100 ms)
|
||||
Motion: Trajektoria 50 pkt/s (20 ms)
|
||||
Servo: PID: PWM silnika = 75% (1 ms)
|
||||
|
||||
---
|
||||
|
||||
**Kinematyka odwrotna (inverse kinematics, IK)** — obliczenie kątów w stawach robota, aby efektor (np. chwytak) znalazł się w zadanej pozycji. Problem odwrotny: znasz cel, szukasz konfiguracji. Może mieć 0, 1 lub wiele rozwiązań.
|
||||
|
||||
**Trajektoria (trajectory)** — zaplanowana ścieżka ruchu w czasie: sekwencja pozycji + prędkości + przyspieszenia. Interpolacja: liniowa (LIN), kołowa (CIRC), punkt-do-punktu (PTP).
|
||||

|
||||
|
||||
---
|
||||
|
||||
**Języki producentów (vendor-specific):**
|
||||
- **RAPID (ABB)** — Robotics Application Programming Interactive Dialogue. Ruchy: MoveJ (joint), MoveL (linear), MoveC (circular).
|
||||
- **KRL (KUKA Robot Language)** — PTP (point-to-point), LIN (linear), CIRC (circular). Pascal-like syntax.
|
||||
- **Karel (FANUC)** — od Karla Čapka. MOVE TO target. Pascal-like.
|
||||
- **PDL2 (Comau)** — MOVE LINEAR TO. Proceduralne.
|
||||
**Kinematyka odwrotna (inverse kinematics, IK)** — obliczenie kątów w stawach robota, aby efektor (np. chwytak) znalazł się w zadanej pozycji. Problem odwrotny: znasz cel (x,y,z + orientacja), szukasz konfiguracji (kąty q₁…qₙ). Może mieć 0, 1 lub wiele rozwiązań. Robot 6-osiowy: zazwyczaj do 8 rozwiązań dla jednej pozycji.
|
||||
|
||||
**Vendor lock-in** — każdy producent ma WŁASNY język. Program napisany w RAPID nie działa na robocie KUKA. To motywacja dla ROS i standardów.
|
||||
Przykład (robot 2-osiowy, ramiona L₁=L₂=1m, cel: x=1.0, y=1.0):
|
||||
q₂ = arccos((x²+y²−L₁²−L₂²) / (2·L₁·L₂))
|
||||
= arccos((1+1−1−1)/2) = arccos(0) = 90°
|
||||
Dwa rozwiązania: „łokieć do góry" i „łokieć na dół"
|
||||
|
||||
**Online vs Offline programming:**
|
||||
- **Online (teach-in)** — operator prowadzi robota „za rękę" (pendant/teach pendant), robot zapamiętuje punkty. Proste, ale wymaga zatrzymania produkcji.
|
||||
- **Offline** — programowanie w symulacji (CAD/CAM), bez zatrzymywania robota. Transferujesz gotowy program.
|
||||
**Trajektoria (trajectory)** — zaplanowana ścieżka ruchu w czasie: sekwencja pozycji + prędkości + przyspieszenia. Trzy typy interpolacji:
|
||||
- **PTP (Point-to-Point)** — najszybsza, ale ścieżka w przestrzeni kartezjańskiej nieprzewidywalna (interpolacja w przestrzeni stawów)
|
||||
- **LIN (Linear)** — prosta linia TCP (Tool Center Point); wymaga obliczenia IK w każdym punkcie
|
||||
- **CIRC (Circular)** — łuk kołowy przez 3 punkty (start, pkt pomocniczy, cel)
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
**ROS (Robot Operating System)** — middleware (nie OS!) do robotyki. Model pub/sub: węzły publikują/subskrybują tematy. Uniwersalny — działa z robotami różnych producentów. Głównie Python/C++. Wada: nie nadaje się do hard real-time (soft real-time OK; ROS 2 poprawia).
|
||||
**Vendor lock-in** — każdy producent ma WŁASNY język. Program napisany w RAPID nie działa na robocie KUKA. To motywacja dla ROS i standardów. Porównanie języków:
|
||||
|
||||
**MoveIt** — biblioteka ROS do planowania ruchu manipulatorów. Obejmuje: IK, collision avoidance, trajectory planning. Open source.
|
||||

|
||||
|
||||
**PDDL (Planning Domain Definition Language)** — język opisu problemów planowania. Definiujesz: stany, akcje, warunki, cel. Planner automatycznie znajduje sekwencję akcji. Task-level.
|
||||
---
|
||||
|
||||
**FPGA (Field-Programmable Gate Array)** — programowalny układ logiczny. Dla servo-level: przetwarzanie sygnałów w nanosekundach. Szybszy niż mikrokontroler, ale trudniejszy w programowaniu.
|
||||
**TCP (Tool Center Point)** — punkt centralny narzędzia zamontowanego na końcu ramienia (np. czubek spawarki, środek chwytaka). Wszystkie komendy ruchu LIN i CIRC odnoszą się do TCP — robot steruje tak, żeby ten punkt poruszał się po żądanej ścieżce.
|
||||
|
||||
Definiowanie TCP w RAPID:
|
||||
PERS tooldata tGripper := [TRUE, [[0,0,150],[1,0,0,0]],
|
||||
[2,[0,0,75],[1,0,0,0],0,0,0]];
|
||||
// TCP jest 150mm nad kołnierzem, masa narzędzia 2kg
|
||||
|
||||
**Strefa zbliżenia (zone)** — parametr określający, jak blisko celu robot musi dojechać zanim zacznie ruch do kolejnego punktu. `fine` = dojazd dokładnie do punktu (zatrzymanie), `z10` = robot zaczyna skręcać w stronę następnego punktu gdy jest 10mm od celu (ruch „na okrągło", płynniejszy i szybszy).
|
||||
|
||||
MoveL p1, v500, fine, tool1; // zatrzymaj się dokładnie w p1
|
||||
MoveL p1, v500, z50, tool1; // zacznij skręcać 50mm przed p1
|
||||
// z50 → szybszy cykl, ale mniejsza precyzja w punkcie
|
||||
|
||||
---
|
||||
|
||||
### Klasyfikacja wg poziomu abstrakcji: **T-R-M-S**
|
||||
|
||||
1. **Task-level** — „Podnieś A, połóż na B" (PDDL, Behavior Trees)
|
||||
2. **Robot-level** — move_to(), grasp() (RAPID, KRL, Karel, ROS)
|
||||
2. **Robot-level** — move_to(), grasp() (RAPID, KRL, Karel, URScript)
|
||||
3. **Motion-level** — trajektorie, kinematyka odwrotna (MoveIt, OMPL)
|
||||
4. **Servo-level** — PID, sterowanie silnikami (C/C++, FPGA)
|
||||
|
||||
### Klasyfikacja wg metody: Online (teach-in, pendant) vs Offline (symulacja, CAD)
|
||||
### Klasyfikacja wg metody programowania
|
||||
|
||||
### Języki producentów
|
||||

|
||||
|
||||
| Producent | Język | Ruchy |
|
||||
|-----------|-------|--------------------|
|
||||
| ABB | RAPID | MoveJ, MoveL, MoveC|
|
||||
| KUKA | KRL | PTP, LIN, CIRC |
|
||||
| FANUC | Karel | MOVE TO |
|
||||
| Comau | PDL2 | MOVE LINEAR TO |
|
||||
- **Online (teach-in)** — operator z teach pendantem prowadzi robota i zapisuje punkty. Proste, intuicyjne, ale wymaga wyłączenia produkcji.
|
||||
- **Offline** — programowanie w symulatorze 3D (RobotStudio, KUKA.Sim, ROBOGUIDE), bez zatrzymywania robota. Wymaga kalibracji po transferze.
|
||||
- **Hybrid** — w praktyce łączy się oba podejścia: offline do wstępnego programu, online do korekcji punktów.
|
||||
|
||||
### Uniwersalne: ROS + Python/C++, MoveIt (planowanie manipulatora), Orocos (real-time)
|
||||
### Języki producentów — szczegółowo
|
||||
|
||||
### Graficzne: RobotStudio (ABB), ROBOGUIDE (FANUC), Blockly (edukacja)
|
||||
#### RAPID (ABB)
|
||||
|
||||
**Producent:** ABB. **Rozwinięcie:** Robotics Application Programming Interactive Dialogue. **Składnia:** własny typ, strukturalna, wielozadaniowa (RAPID obsługuje wielowątkowość). **Symulator:** RobotStudio (darmowa wersja edukacyjna).
|
||||
|
||||
**Kluczowe cechy:**
|
||||
- Typy danych: `num` (liczba), `string`, `bool`, `robtarget` (pozycja kartezjańska + orientacja + konfiguracja), `jointtarget` (kąty stawów), `tooldata`, `wobjdata` (układ współrzędnych obiektu)
|
||||
- Ruchy: `MoveJ` (joint — PTP), `MoveL` (linear), `MoveC` (circular), `MoveAbsJ` (absolutne kąty)
|
||||
- I/O: `SetDO` (digital output), `WaitDI` (czekaj na digital input), `SetAO` (analog out)
|
||||
- Kontrola przepływu: `IF/ELSEIF/ELSE/ENDIF`, `WHILE/ENDWHILE`, `FOR/ENDFOR`, `TEST/CASE/DEFAULT/ENDTEST`
|
||||
- Obsługa błędów: `TRAP` (przerwania), `ERROR` handler
|
||||
- Wielozadaniowość: wiele tasków wykonywanych równolegle — np. jeden task steruje ruchem, drugi monitoruje czujniki
|
||||
|
||||
**Przykładowy program pick & place:**
|
||||
|
||||
MODULE MainModule
|
||||
! --- Dane ---
|
||||
CONST robtarget pHome := [[500,0,600],[1,0,0,0],[0,0,0,0],[9E9,9E9,9E9,9E9,9E9,9E9]];
|
||||
CONST robtarget pPick := [[400,200,100],[1,0,0,0],[0,0,0,0],[9E9,9E9,9E9,9E9,9E9,9E9]];
|
||||
CONST robtarget pPlace := [[400,-200,100],[1,0,0,0],[0,0,0,0],[9E9,9E9,9E9,9E9,9E9,9E9]];
|
||||
VAR num nCycles := 0;
|
||||
|
||||
! --- Procedura główna ---
|
||||
PROC main()
|
||||
MoveJ pHome, v1000, z50, tGripper; ! jedź do pozycji bazowej (joint)
|
||||
WHILE TRUE DO
|
||||
PickPart;
|
||||
PlacePart;
|
||||
Incr nCycles;
|
||||
TPWrite "Cykl nr: " + ValToStr(nCycles);
|
||||
ENDWHILE
|
||||
ENDPROC
|
||||
|
||||
! --- Podnoszenie ---
|
||||
PROC PickPart()
|
||||
MoveL Offs(pPick,0,0,50), v500, z10, tGripper; ! 50mm nad celem
|
||||
MoveL pPick, v100, fine, tGripper; ! precyzyjnie na cel
|
||||
SetDO doGripper, 1; ! zamknij chwytak
|
||||
WaitTime 0.3; ! czekaj na zamknięcie
|
||||
MoveL Offs(pPick,0,0,50), v500, z10, tGripper; ! podnieś 50mm
|
||||
ENDPROC
|
||||
|
||||
! --- Odkładanie ---
|
||||
PROC PlacePart()
|
||||
MoveL Offs(pPlace,0,0,50), v500, z10, tGripper; ! 50mm nad miejscem
|
||||
MoveL pPlace, v100, fine, tGripper; ! precyzyjnie na cel
|
||||
SetDO doGripper, 0; ! otwórz chwytak
|
||||
WaitTime 0.3;
|
||||
MoveL Offs(pPlace,0,0,50), v500, z10, tGripper; ! podnieś 50mm
|
||||
ENDPROC
|
||||
ENDMODULE
|
||||
|
||||
**Objaśnienie parametrów MoveL:**
|
||||
|
||||
MoveL pPick, v500, z10, tGripper;
|
||||
│ │ │ │ └── narzędzie (tooldata) — definiuje TCP
|
||||
│ │ │ └── strefa zbliżenia: 10mm (nie zatrzymuj się, skręcaj)
|
||||
│ │ └── prędkość TCP: 500 mm/s
|
||||
│ └── cel: robtarget (pozycja + orientacja + konfiguracja)
|
||||
└── typ ruchu: ruch liniowy (TCP jedzie po prostej)
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
#### KRL (KUKA Robot Language)
|
||||
|
||||
**Producent:** KUKA. **Rozwinięcie:** KUKA Robot Language. **Składnia:** Pascal-like (BEGIN/END, deklaracje na początku). **Symulator:** KUKA.Sim Pro, WorkVisual.
|
||||
|
||||
**Kluczowe cechy:**
|
||||
- Program = dwa pliki: `.src` (kod) + `.dat` (dane punktów)
|
||||
- Typy: `INT`, `REAL`, `BOOL`, `CHAR`, `POS` (x,y,z,a,b,c), `E6POS` (+ osie dodatkowe), `AXIS` (kąty stawów)
|
||||
- Ruchy: `PTP` (point-to-point = joint), `LIN` (linear), `CIRC` (circular)
|
||||
- Approximation (odpowiednik zone w RAPID): `C_DIS` — robot nie zatrzymuje się w punkcie
|
||||
- Kontrola przepływu: `IF/ENDIF`, `WHILE/ENDWHILE`, `FOR/ENDFOR`, `SWITCH/CASE/ENDSWITCH`
|
||||
|
||||
**Przykładowy program:**
|
||||
|
||||
DEF PickAndPlace()
|
||||
; --- Deklaracje ---
|
||||
DECL E6POS XHome, XPick, XPlace
|
||||
DECL INT nLoop
|
||||
|
||||
; --- Inicjalizacja ---
|
||||
BAS (#INITMOV, 0) ; inicjalizacja ruchów
|
||||
$VEL.CP = 0.5 ; prędkość kartezjańska 0.5 m/s
|
||||
$APO.CDIS = 10 ; approximacja: 10mm
|
||||
|
||||
; --- Ruch do domu ---
|
||||
PTP XHome ; point-to-point (joint space)
|
||||
|
||||
FOR nLoop = 1 TO 100
|
||||
; Podjedź nad punkt pobrania
|
||||
LIN XPick ; ruch liniowy do punktu
|
||||
; Zamknij chwytak
|
||||
OUT 1 TRUE ; digital output 1 = ON
|
||||
WAIT SEC 0.3
|
||||
; Jedź do miejsca odkładania
|
||||
LIN XPlace
|
||||
OUT 1 FALSE ; otwórz chwytak
|
||||
WAIT SEC 0.3
|
||||
ENDFOR
|
||||
END
|
||||
|
||||
**KRL vs RAPID — kluczowe różnice:**
|
||||
- KRL rozdziela kod (`.src`) od danych (`.dat`); RAPID trzyma wszystko w MODULE
|
||||
- KRL: `$VEL.CP = 0.5` (zmienna systemowa); RAPID: `v500` (nazwany speeddata)
|
||||
- KRL: `C_DIS` approximation; RAPID: `z10` zone
|
||||
- KRL: `OUT 1 TRUE`; RAPID: `SetDO doGripper, 1`
|
||||
|
||||
---
|
||||
|
||||
#### Karel (FANUC)
|
||||
|
||||
**Producent:** FANUC. **Nazwa:** od Karla Čapka. **Składnia:** Pascal-like (PROGRAM/BEGIN/END, VAR). **Symulator:** ROBOGUIDE.
|
||||
|
||||
**Kluczowe cechy:**
|
||||
- Dwa tryby: Karel (tekstowy, pełny język) i TP (Teach Pendant — uproszczony, listowy)
|
||||
- Karel: kompilowany, typowany, procedury/funkcje
|
||||
- Typy: `INTEGER`, `REAL`, `BOOLEAN`, `STRING`, `POSITION`, `XYZWPR`
|
||||
- TP program jest częściej używany w praktyce (prostszy, operatorzy go rozumieją)
|
||||
|
||||
**Przykład Karel:**
|
||||
|
||||
PROGRAM pick_place
|
||||
VAR
|
||||
home_pos : POSITION
|
||||
pick_pos : POSITION
|
||||
place_pos : POSITION
|
||||
cycle_count : INTEGER
|
||||
BEGIN
|
||||
cycle_count = 0
|
||||
-- Jedź do domu
|
||||
MOVE TO home_pos
|
||||
WHILE cycle_count < 100 DO
|
||||
-- Podnoszenie
|
||||
MOVE TO pick_pos
|
||||
DOUT[1] = ON -- zamknij chwytak
|
||||
DELAY 300 -- czekaj 300ms
|
||||
-- Odkładanie
|
||||
MOVE TO place_pos
|
||||
DOUT[1] = OFF -- otwórz chwytak
|
||||
DELAY 300
|
||||
cycle_count = cycle_count + 1
|
||||
ENDWHILE
|
||||
END pick_place
|
||||
|
||||
**Przykład TP (Teach Pendant) — to widzi operator:**
|
||||
|
||||
1: J P[1] 100% FINE ; joint move do Home, 100% speed
|
||||
2: L P[2] 500mm/sec FINE ; linear do Pick
|
||||
3: DO[1]=ON ; chwytak zamknij
|
||||
4: WAIT 0.30(sec)
|
||||
5: L P[3] 500mm/sec FINE ; linear do Place
|
||||
6: DO[1]=OFF ; chwytak otwórz
|
||||
7: WAIT 0.30(sec)
|
||||
8: JMP LBL[1] ; skocz do linii 1
|
||||
|
||||
**Uwaga:** W praktyce fabrycznej TP jest dominujący — operatorzy uczą się numerowanych linii, nie pełnego Karela.
|
||||
|
||||
---
|
||||
|
||||
#### URScript (Universal Robots)
|
||||
|
||||
**Producent:** Universal Robots (coboty — collaborative robots). **Składnia:** Python-like (brak nawiasów klamrowych, wcięcia nie mają znaczenia, ale styl jest skryptowy). **Symulator:** URSim (darmowy, oparty na VM).
|
||||
|
||||
**Kluczowe cechy:**
|
||||
- Skryptowy i prosty — niski próg wejścia (coboty = roboty współpracujące z ludźmi)
|
||||
- Wbudowane funkcje force control (sterowanie siłą) — unikalne dla cobotów
|
||||
- Typy: brak deklaracji typów (dynamiczne), `pose` = [x,y,z,rx,ry,rz]
|
||||
- Polyscope — graficzny interfejs do programowania (drag & drop + URScript)
|
||||
|
||||
**Przykład URScript:**
|
||||
|
||||
def pick_and_place():
|
||||
# Pozycje jako pose: [x, y, z, rx, ry, rz] w metrach i radianach
|
||||
home = p[0.5, 0.0, 0.4, 3.14, 0.0, 0.0]
|
||||
pick = p[0.4, 0.2, 0.1, 3.14, 0.0, 0.0]
|
||||
place = p[0.4, -0.2, 0.1, 3.14, 0.0, 0.0]
|
||||
|
||||
movej(home, a=1.2, v=0.5) # joint move, acc=1.2 rad/s², vel=0.5 rad/s
|
||||
|
||||
i = 0
|
||||
while i < 100:
|
||||
# Podnoszenie
|
||||
movel(pick, a=0.5, v=0.3) # linear move
|
||||
set_digital_out(0, True) # zamknij chwytak
|
||||
sleep(0.3)
|
||||
|
||||
# Odkładanie
|
||||
movel(place, a=0.5, v=0.3)
|
||||
set_digital_out(0, False) # otwórz chwytak
|
||||
sleep(0.3)
|
||||
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
**URScript — unikalne cechy cobotów:**
|
||||
|
||||
# Force mode — wkładanie kołka w otwór z kontrolą siły:
|
||||
force_mode(p[0,0,0,0,0,0], [0,0,1,0,0,0], [0,0,-10,0,0,0], 2, [0.1,0.1,0.05,1,1,1])
|
||||
# Robot naciska z siłą 10N w dół (oś Z), reszt osi blokuje
|
||||
|
||||
# Freedrive — operator prowadzi robota ręcznie:
|
||||
freedrive_mode()
|
||||
sleep(10) # 10 sekund swobodnego prowadzenia
|
||||
end_freedrive_mode()
|
||||
|
||||
---
|
||||
|
||||
#### PDL2 (Comau)
|
||||
|
||||
**Producent:** Comau (Fiat/Stellantis). **Składnia:** proceduralna, C-like. **Symulator:** RoboSim.
|
||||
|
||||
**Przykład:**
|
||||
|
||||
PROGRAM pick_place
|
||||
VAR home_pos, pick_pos, place_pos : POSITION
|
||||
BEGIN
|
||||
MOVE TO home_pos
|
||||
CYCLE
|
||||
MOVE LINEAR TO pick_pos
|
||||
$DOUT[1] := TRUE -- chwytak
|
||||
DELAY 300
|
||||
MOVE LINEAR TO place_pos
|
||||
$DOUT[1] := FALSE
|
||||
DELAY 300
|
||||
END CYCLE
|
||||
END pick_place
|
||||
|
||||
---
|
||||
|
||||
### Porównanie składni — ten sam ruch w 5 językach
|
||||
|
||||
Zadanie: ruch liniowy do punktu pPick z prędkością ~500mm/s
|
||||
|
||||
RAPID (ABB): MoveL pPick, v500, fine, tGripper;
|
||||
KRL (KUKA): LIN XPick
|
||||
Karel (FANUC): MOVE TO pick_pos ; z opcją LINEAR
|
||||
TP (FANUC): L P[2] 500mm/sec FINE
|
||||
URScript (UR): movel(pick, a=0.5, v=0.5)
|
||||
PDL2 (Comau): MOVE LINEAR TO pick_pos
|
||||
|
||||
### Języki uniwersalne i middleware
|
||||
|
||||
#### ROS / ROS 2 (Robot Operating System)
|
||||
|
||||
**ROS** to middleware (NIE system operacyjny!) — warstwa komunikacji między modułami (węzłami). Programuje się w Python lub C++. Architektura publish/subscribe: węzły publikują wiadomości na tematy (topics), inne węzły subskrybują.
|
||||
|
||||

|
||||
|
||||
**ROS 1 vs ROS 2:**
|
||||
- ROS 1: roscore (centralny master), brak real-time, Python 2/3 + C++
|
||||
- ROS 2: DDS (bez centralnego mastera, peer-to-peer), real-time friendly, Python 3 + C++17
|
||||
- ROS 2 dodaje: lifecycle nodes, QoS (Quality of Service), lepsze multi-robot
|
||||
|
||||
**Przykład ROS 2 (Python) — publisher prędkości:**
|
||||
|
||||
import rclpy
|
||||
from geometry_msgs.msg import Twist
|
||||
|
||||
def main():
|
||||
rclpy.init()
|
||||
node = rclpy.create_node('velocity_publisher')
|
||||
pub = node.create_publisher(Twist, '/cmd_vel', 10)
|
||||
|
||||
msg = Twist()
|
||||
msg.linear.x = 0.5 # 0.5 m/s do przodu
|
||||
msg.angular.z = 0.1 # obrót 0.1 rad/s
|
||||
|
||||
timer = node.create_timer(0.1, lambda: pub.publish(msg)) # co 100ms
|
||||
rclpy.spin(node)
|
||||
|
||||
**MoveIt** — biblioteka ROS do planowania ruchu manipulatorów. Obejmuje: IK, collision avoidance, trajectory planning. Wspiera roboty wielu producentów — klucz do przełamania vendor lock-in.
|
||||
|
||||
# MoveIt — planowanie ruchu w Pythonie:
|
||||
move_group = MoveGroupCommander("arm")
|
||||
move_group.set_pose_target(target_pose) # cel w kartezjańskiej
|
||||
plan = move_group.plan() # automatyczny plan trajektorii
|
||||
move_group.execute(plan) # wykonaj
|
||||
|
||||
#### Orocos (Open Robot Control Software)
|
||||
|
||||
Framework C++ do **hard real-time** sterowania robotów. Tam gdzie ROS nie wystarczy (pętle regulacji < 1ms), Orocos wypełnia lukę. Często łączony z ROS: ROS do komunikacji + Orocos do sterowania.
|
||||
|
||||
---
|
||||
|
||||
### Task-level: PDDL i Behavior Trees
|
||||
|
||||
#### PDDL (Planning Domain Definition Language)
|
||||
|
||||
Język opisu problemów planowania. Definiujesz: stany, akcje z warunkami i efektami, cel. Planner (np. Fast Downward) automatycznie znajduje sekwencję akcji.
|
||||
|
||||
; PDDL — domena: robot pick & place
|
||||
(define (domain robot-world)
|
||||
(:predicates
|
||||
(on-table ?obj)
|
||||
(holding ?obj)
|
||||
(arm-empty))
|
||||
(:action pick
|
||||
:parameters (?obj)
|
||||
:precondition (and (on-table ?obj) (arm-empty))
|
||||
:effect (and (holding ?obj) (not (on-table ?obj)) (not (arm-empty))))
|
||||
(:action place
|
||||
:parameters (?obj)
|
||||
:precondition (holding ?obj)
|
||||
:effect (and (on-table ?obj) (arm-empty) (not (holding ?obj)))))
|
||||
|
||||
; Problem: weź obiektA ze stołu
|
||||
(define (problem pick-a)
|
||||
(:domain robot-world)
|
||||
(:init (on-table objectA) (arm-empty))
|
||||
(:goal (holding objectA)))
|
||||
|
||||
; Planner automatycznie znajdzie: pick(objectA)
|
||||
|
||||
#### Behavior Trees (drzewa zachowań)
|
||||
|
||||
Alternatywa dla maszyn stanów w sterowaniu robotów i postaci w grach. Drzewo składa się z:
|
||||
- **Sequence** (→) — wykonuj dzieci po kolei, przerwij jeśli któreś zawiedzie
|
||||
- **Selector** (?) — próbuj dzieci po kolei, przerwij po pierwszym sukcesie
|
||||
- **Action** — liść: wykonaj akcję
|
||||
- **Condition** — liść: sprawdź warunek
|
||||
|
||||
Behavior Tree: „Pick and Place"
|
||||
[→ Sequence]
|
||||
├── [? Selector: FindObject]
|
||||
│ ├── [Condition: ObjectVisible?]
|
||||
│ └── [Action: SearchForObject]
|
||||
├── [Action: MoveToObject]
|
||||
├── [Action: Grasp]
|
||||
├── [Action: MoveToTarget]
|
||||
└── [Action: Release]
|
||||
|
||||
---
|
||||
|
||||
### Środowiska graficzne
|
||||
|
||||
| Narzędzie | Producent | Typ | Koszt |
|
||||
|-------------|-----------|------------------------|------------------|
|
||||
| RobotStudio | ABB | Offline + symulacja 3D | Licencja / edu |
|
||||
| KUKA.Sim | KUKA | Offline + symulacja 3D | Licencja |
|
||||
| ROBOGUIDE | FANUC | Offline + symulacja 3D | Licencja |
|
||||
| URSim | UR | Symulator kontrolera | Darmowy |
|
||||
| Polyscope | UR | GUI na teach pendancie | Wbudowany |
|
||||
| Blockly | Różni | Graficzne (edukacja) | Open source |
|
||||
| Gazebo | ROS/OSRF | Symulacja fizyczna 3D | Open source |
|
||||
|
||||
### Podsumowanie klasyfikacji
|
||||
|
||||
| Kryterium | Kategorie |
|
||||
|--------------------|----------------------------------------------------------|
|
||||
| **Poziom abstrakcji** | Task → Robot → Motion → Servo (T-R-M-S) |
|
||||
| **Metoda** | Online (teach-in) vs Offline (symulacja) vs Hybrid |
|
||||
| **Zakres** | Vendor-specific (RAPID, KRL, Karel) vs Universal (ROS)|
|
||||
| **Interfejs** | Tekstowy (RAPID, KRL) vs Graficzny (Polyscope, Blockly)|
|
||||
| **Real-time** | Hard RT (Orocos, C/FPGA) vs Soft RT (ROS 2) |
|
||||
|
||||
### Etymologia
|
||||
|
||||
**RAPID** — Robotics Application Programming Interactive Dialogue (ABB). **KRL** — KUKA Robot Language. **Karel** — od Karla Čapka, czeskiego pisarza, który ukuł słowo „robot" (cz. „robota" = ciężka/przymusowa praca) w sztuce R.U.R. (1920). **PDDL** — Planning Domain Definition Language. **MoveIt** — open source do planowania ruchu manipulatora (Willow Garage/PickNik). **Robot** — cz. „robota" = pańszczyzna; Karel Čapek, R.U.R. (1920).
|
||||
**RAPID** — Robotics Application Programming Interactive Dialogue (ABB, 1994). **KRL** — KUKA Robot Language (KUKA, Augsburg). **Karel** — od Karla Čapka, czeskiego pisarza, który ukuł słowo „robot" (cz. „robota" = ciężka/przymusowa praca) w sztuce R.U.R. (Rossum's Universal Robots, 1920). **PDL2** — Programming and Data Language 2 (Comau). **URScript** — Universal Robots Script. **PDDL** — Planning Domain Definition Language (Drew McDermott et al., 1998). **MoveIt** — open source, Willow Garage → PickNik Robotics. **ROS** — Robot Operating System (Willow Garage, 2007 → Open Robotics). **Orocos** — Open Robot Control Software (KU Leuven, Belgia). **TCP** — Tool Center Point (nie mylić z Transmission Control Protocol!). **OMPL** — Open Motion Planning Library. **Cobot** — collaborative robot (termin 1996, Northwestern University).
|
||||
|
||||
### Jak zapamiętać
|
||||
|
||||
- **„Od zadania do serwa: T-R-M-S"**
|
||||
- Każdy producent ma WŁASNY język (vendor lock-in)
|
||||
- ROS próbuje ujednolicić, ale nie dla hard real-time
|
||||
- **„Tomek Robi Mechaniczne Serwa" → T-R-M-S** (Task → Robot → Motion → Servo, od abstrakcji do sprzętu)
|
||||
- **„ABB RAPID jak rapier (szybki miecz)" → MoveL, MoveJ, MoveC** — trzy podstawowe ruchy
|
||||
- **„KUKA KRL = Pascal na sterydach"** — PTP, LIN, CIRC; dwa pliki (.src + .dat)
|
||||
- **„FANUC Karel = Čapek" → MOVE TO** — najprostszy składniowo
|
||||
- **„UR = Python robota" → movel(), movej()** — małe litery, skryptowy, coboty
|
||||
- **„ROS = WhatsApp robotów"** — węzły wysyłają wiadomości na tematy (topics), ale to NIE system operacyjny
|
||||
- **Vendor lock-in → „Program w RAPID na KUKA = jak wtyczka EU w gniazdku UK"** — nie pasuje
|
||||
- **Online = „trzymaj robota za rękę", Offline = „rysuj w symulatorze"**
|
||||
- **MoveIt = „GPS dla ramienia robota"** — planuje trasę z unikaniem przeszkód
|
||||
- **Zone/Approximation = „hamowanie przed zakrętem"** — fine = stop, z50 = przejeżdżaj płynnie
|
||||
|
||||
\newpage
|
||||
|
||||
|
||||
391
pytania/generate_agent_diagrams.py
Normal file
@ -0,0 +1,391 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Generate diagrams for PYTANIE 15: Agent upostaciowiony w robotyce.
|
||||
|
||||
Diagrams:
|
||||
1. See-Think-Act cycle of an embodied agent
|
||||
2. 3T Architecture (Planner / Sequencer / Controller)
|
||||
3. Behavior Tree example (robot pick-and-place)
|
||||
4. BDI model flow
|
||||
|
||||
All: A4-compatible, B&W, 300 DPI, laser-printer-friendly.
|
||||
"""
|
||||
|
||||
import matplotlib
|
||||
matplotlib.use('Agg')
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.patches as mpatches
|
||||
from matplotlib.patches import FancyBboxPatch, FancyArrowPatch, Circle
|
||||
import numpy as np
|
||||
import os
|
||||
|
||||
DPI = 300
|
||||
BG = 'white'
|
||||
LN = 'black'
|
||||
FS = 8
|
||||
FS_TITLE = 11
|
||||
OUTPUT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'img')
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
|
||||
GRAY1 = '#E8E8E8'
|
||||
GRAY2 = '#D0D0D0'
|
||||
GRAY3 = '#B8B8B8'
|
||||
GRAY4 = '#F5F5F5'
|
||||
GRAY5 = '#C0C0C0'
|
||||
|
||||
|
||||
def draw_box(ax, x, y, w, h, text, fill='white', lw=1.2, fontsize=FS,
|
||||
fontweight='normal', ha='center', va='center', rounded=True):
|
||||
if rounded:
|
||||
rect = FancyBboxPatch((x, y), w, h, boxstyle="round,pad=0.05",
|
||||
lw=lw, edgecolor=LN, facecolor=fill)
|
||||
else:
|
||||
rect = mpatches.Rectangle((x, y), w, h, lw=lw, edgecolor=LN, facecolor=fill)
|
||||
ax.add_patch(rect)
|
||||
ax.text(x + w/2, y + h/2, text, ha=ha, va=va, fontsize=fontsize,
|
||||
fontweight=fontweight, wrap=True)
|
||||
|
||||
|
||||
def draw_arrow(ax, x1, y1, x2, y2, lw=1.2, style='->', color=LN, label='', label_offset=0.12):
|
||||
ax.annotate("", xy=(x2, y2), xytext=(x1, y1),
|
||||
arrowprops=dict(arrowstyle=style, color=color, lw=lw))
|
||||
if label:
|
||||
mx, my = (x1 + x2) / 2, (y1 + y2) / 2 + label_offset
|
||||
ax.text(mx, my, label, ha='center', va='bottom', fontsize=6.5, color=color)
|
||||
|
||||
|
||||
def draw_dashed_arrow(ax, x1, y1, x2, y2, lw=1.0, color=LN, label='', label_offset=0.12):
|
||||
ax.annotate("", xy=(x2, y2), xytext=(x1, y1),
|
||||
arrowprops=dict(arrowstyle='->', color=color, lw=lw,
|
||||
linestyle='dashed'))
|
||||
if label:
|
||||
mx, my = (x1 + x2) / 2, (y1 + y2) / 2 + label_offset
|
||||
ax.text(mx, my, label, ha='center', va='bottom', fontsize=6.5, color=color)
|
||||
|
||||
|
||||
# ─── DIAGRAM 1: See-Think-Act Cycle ──────────────────────────────
|
||||
def draw_see_think_act():
|
||||
fig, ax = plt.subplots(1, 1, figsize=(7, 4.5), facecolor=BG)
|
||||
ax.set_xlim(0, 7)
|
||||
ax.set_ylim(0, 4.5)
|
||||
ax.axis('off')
|
||||
ax.set_title("Cykl agenta upostaciowionego: Percepcja → Deliberacja → Akcja",
|
||||
fontsize=FS_TITLE, fontweight='bold', pad=10)
|
||||
|
||||
# Environment box (large background)
|
||||
env_rect = FancyBboxPatch((0.2, 0.2), 6.6, 1.0, boxstyle="round,pad=0.08",
|
||||
lw=1.5, edgecolor=LN, facecolor=GRAY1,
|
||||
linestyle='--')
|
||||
ax.add_patch(env_rect)
|
||||
ax.text(3.5, 0.7, "ŚRODOWISKO FIZYCZNE\n(przeszkody, obiekty, ludzie)",
|
||||
ha='center', va='center', fontsize=FS, fontstyle='italic')
|
||||
|
||||
# Agent body (large rounded box)
|
||||
agent_rect = FancyBboxPatch((0.5, 1.5), 6.0, 2.6, boxstyle="round,pad=0.1",
|
||||
lw=2.0, edgecolor=LN, facecolor=GRAY4)
|
||||
ax.add_patch(agent_rect)
|
||||
ax.text(3.5, 3.85, "AGENT UPOSTACIOWIONY (robot)", ha='center', va='center',
|
||||
fontsize=9, fontweight='bold')
|
||||
|
||||
# Three main phases
|
||||
bw = 1.4
|
||||
bh = 0.7
|
||||
by = 2.2
|
||||
|
||||
# SEE
|
||||
draw_box(ax, 0.8, by, bw, bh, "SEE\n(Percepcja)", fill=GRAY2,
|
||||
fontsize=8, fontweight='bold')
|
||||
ax.text(1.5, by - 0.2, "kamery, LIDAR\nczujniki dotyku", ha='center',
|
||||
va='top', fontsize=6, fontstyle='italic')
|
||||
|
||||
# THINK
|
||||
draw_box(ax, 2.8, by, bw, bh, "THINK\n(Deliberacja)", fill=GRAY3,
|
||||
fontsize=8, fontweight='bold')
|
||||
ax.text(3.5, by - 0.2, "planowanie trasy\nmodel BDI", ha='center',
|
||||
va='top', fontsize=6, fontstyle='italic')
|
||||
|
||||
# ACT
|
||||
draw_box(ax, 4.8, by, bw, bh, "ACT\n(Akcja)", fill=GRAY2,
|
||||
fontsize=8, fontweight='bold')
|
||||
ax.text(5.5, by - 0.2, "silniki, chwytaki\nkomendy PWM", ha='center',
|
||||
va='top', fontsize=6, fontstyle='italic')
|
||||
|
||||
# Arrows between phases
|
||||
draw_arrow(ax, 0.8 + bw, by + bh/2, 2.8, by + bh/2, lw=1.5,
|
||||
label='dane sensoryczne')
|
||||
draw_arrow(ax, 2.8 + bw, by + bh/2, 4.8, by + bh/2, lw=1.5,
|
||||
label='komendy sterujące')
|
||||
|
||||
# Arrows to/from environment
|
||||
draw_arrow(ax, 1.5, 1.2, 1.5, by, lw=1.3, label='odczyt', label_offset=0.08)
|
||||
draw_arrow(ax, 5.5, by, 5.5, 1.2, lw=1.3, label='działanie', label_offset=0.08)
|
||||
|
||||
# Feedback loop arrow (from ACT back to environment back to SEE)
|
||||
ax.annotate("", xy=(1.5, 1.15), xytext=(5.5, 1.15),
|
||||
arrowprops=dict(arrowstyle='->', color='#555555', lw=1.0,
|
||||
linestyle='dashed',
|
||||
connectionstyle="arc3,rad=-0.15"))
|
||||
ax.text(3.5, 0.35, "← sprzężenie zwrotne (efekt akcji zmienia środowisko) →",
|
||||
ha='center', va='center', fontsize=6, color='#555555')
|
||||
|
||||
fig.tight_layout()
|
||||
path = os.path.join(OUTPUT_DIR, 'agent_see_think_act.png')
|
||||
fig.savefig(path, dpi=DPI, bbox_inches='tight', facecolor=BG)
|
||||
plt.close(fig)
|
||||
print(f" ✓ {path}")
|
||||
|
||||
|
||||
# ─── DIAGRAM 2: 3T Architecture ─────────────────────────────────
|
||||
def draw_3t_architecture():
|
||||
fig, ax = plt.subplots(1, 1, figsize=(7, 5.5), facecolor=BG)
|
||||
ax.set_xlim(0, 7)
|
||||
ax.set_ylim(0, 5.5)
|
||||
ax.axis('off')
|
||||
ax.set_title("Architektura 3T sterownika robota (3-Layer Architecture)",
|
||||
fontsize=FS_TITLE, fontweight='bold', pad=10)
|
||||
|
||||
layers = [
|
||||
{"y": 4.0, "name": "WARSTWA 3: PLANNER\n(Deliberacja)",
|
||||
"time": "sekundy \u2013 minuty", "fill": GRAY1,
|
||||
"example": 'Cel: "Jed\u017a do kuchni po kubek"\nPlanowanie trasy A \u2192 B \u2192 C',
|
||||
"tech": "Planowanie symboliczne\nA*, graf zada\u0144"},
|
||||
{"y": 2.6, "name": "WARSTWA 2: SEQUENCER\n(Wykonawca)",
|
||||
"time": "100 ms \u2013 sekundy", "fill": GRAY2,
|
||||
"example": "Sekwencja: Jed\u017a do drzwi \u2192\nOtw\u00f3rz \u2192 Jed\u017a do blatu \u2192 Chwy\u0107",
|
||||
"tech": "FSM, Behavior Trees\nkoordynacja zachowa\u0144"},
|
||||
{"y": 1.2, "name": "WARSTWA 1: CONTROLLER\n(Reaktywny)",
|
||||
"time": "milisekundy", "fill": GRAY3,
|
||||
"example": "PID: utrzymaj pr\u0119dko\u015b\u0107 0.5 m/s\nUnikaj kolizji (emergency stop)",
|
||||
"tech": "PID, regulacja\nbezpo\u015brednie I/O"},
|
||||
]
|
||||
|
||||
bw = 4.0
|
||||
bh = 0.85
|
||||
|
||||
for i, layer in enumerate(layers):
|
||||
y = layer["y"]
|
||||
# Main layer box
|
||||
draw_box(ax, 0.3, y, bw, bh, layer["name"], fill=layer["fill"],
|
||||
fontsize=8, fontweight='bold')
|
||||
|
||||
# Time label (left)
|
||||
ax.text(0.15, y + bh/2, layer["time"], ha='right', va='center',
|
||||
fontsize=6, fontstyle='italic', rotation=0,
|
||||
bbox=dict(boxstyle='round,pad=0.15', facecolor='white', edgecolor=LN, lw=0.5))
|
||||
|
||||
# Example (right side)
|
||||
draw_box(ax, 4.5, y, 2.3, bh, layer["example"], fill='white',
|
||||
fontsize=6.5)
|
||||
|
||||
# Technology used
|
||||
# ax.text(4.5 + 1.15, y - 0.12, layer["tech"], ha='center', va='top',
|
||||
# fontsize=5.5, fontstyle='italic', color='#555555')
|
||||
|
||||
# Arrows between layers (downward = commands, upward = status)
|
||||
for i in range(len(layers) - 1):
|
||||
y_top = layers[i]["y"]
|
||||
y_bot = layers[i+1]["y"] + 0.85
|
||||
# Command arrow (down)
|
||||
draw_arrow(ax, 1.8, y_top, 1.8, y_bot, lw=1.3, label='polecenia ↓', label_offset=0.02)
|
||||
# Status arrow (up)
|
||||
draw_arrow(ax, 2.8, y_bot, 2.8, y_top, lw=1.0, style='->', color='#666666',
|
||||
label='↑ status', label_offset=0.02)
|
||||
|
||||
# Environment at bottom
|
||||
env_rect = FancyBboxPatch((0.3, 0.3), bw, 0.6, boxstyle="round,pad=0.05",
|
||||
lw=1.5, edgecolor=LN, facecolor=GRAY4, linestyle='--')
|
||||
ax.add_patch(env_rect)
|
||||
ax.text(0.3 + bw/2, 0.6, "SPRZĘT: silniki, czujniki, efektory",
|
||||
ha='center', va='center', fontsize=7, fontstyle='italic')
|
||||
|
||||
# Arrow from controller to hardware
|
||||
draw_arrow(ax, 2.3, 1.2, 2.3, 0.9, lw=1.3)
|
||||
|
||||
# Abstraction label on the right
|
||||
ax.annotate("", xy=(6.9, 4.8), xytext=(6.9, 0.5),
|
||||
arrowprops=dict(arrowstyle='<->', color='#888888', lw=1.0))
|
||||
ax.text(6.95, 2.65, "abstrakcja", ha='left', va='center', fontsize=7,
|
||||
rotation=90, color='#888888')
|
||||
|
||||
fig.tight_layout()
|
||||
path = os.path.join(OUTPUT_DIR, 'agent_3t_architecture.png')
|
||||
fig.savefig(path, dpi=DPI, bbox_inches='tight', facecolor=BG)
|
||||
plt.close(fig)
|
||||
print(f" ✓ {path}")
|
||||
|
||||
|
||||
# ─── DIAGRAM 3: Behavior Tree Example ────────────────────────────
|
||||
def draw_behavior_tree():
|
||||
fig, ax = plt.subplots(1, 1, figsize=(7.5, 4.5), facecolor=BG)
|
||||
ax.set_xlim(0, 7.5)
|
||||
ax.set_ylim(0, 4.5)
|
||||
ax.axis('off')
|
||||
ax.set_title("Behavior Tree: robot przenoszący obiekt (pick-and-place)",
|
||||
fontsize=FS_TITLE, fontweight='bold', pad=10)
|
||||
|
||||
# Node positions: (x, y, text, shape_type)
|
||||
# shape_type: 'seq' = sequence (→), 'sel' = selector (?), 'act' = action, 'cond' = condition
|
||||
|
||||
def draw_bt_node(ax, x, y, text, ntype='act', w=1.0, h=0.45):
|
||||
"""Draw a behavior tree node."""
|
||||
if ntype == 'seq':
|
||||
# Sequence = box with →
|
||||
rect = FancyBboxPatch((x - w/2, y - h/2), w, h,
|
||||
boxstyle="round,pad=0.06", lw=1.5,
|
||||
edgecolor=LN, facecolor=GRAY2)
|
||||
ax.add_patch(rect)
|
||||
ax.text(x, y, f"→ {text}", ha='center', va='center',
|
||||
fontsize=7, fontweight='bold')
|
||||
elif ntype == 'sel':
|
||||
# Selector = box with ?
|
||||
rect = FancyBboxPatch((x - w/2, y - h/2), w, h,
|
||||
boxstyle="round,pad=0.06", lw=1.5,
|
||||
edgecolor=LN, facecolor=GRAY3)
|
||||
ax.add_patch(rect)
|
||||
ax.text(x, y, f"? {text}", ha='center', va='center',
|
||||
fontsize=7, fontweight='bold')
|
||||
elif ntype == 'cond':
|
||||
# Condition = diamond-ish / oval with dashed border
|
||||
rect = FancyBboxPatch((x - w/2, y - h/2), w, h,
|
||||
boxstyle="round,pad=0.06", lw=1.0,
|
||||
edgecolor=LN, facecolor='white',
|
||||
linestyle='--')
|
||||
ax.add_patch(rect)
|
||||
ax.text(x, y, text, ha='center', va='center',
|
||||
fontsize=6.5, fontstyle='italic')
|
||||
else: # action
|
||||
rect = FancyBboxPatch((x - w/2, y - h/2), w, h,
|
||||
boxstyle="round,pad=0.06", lw=1.0,
|
||||
edgecolor=LN, facecolor=GRAY1)
|
||||
ax.add_patch(rect)
|
||||
ax.text(x, y, text, ha='center', va='center', fontsize=6.5)
|
||||
return x, y
|
||||
|
||||
# Root: Sequence "Przenieś obiekt"
|
||||
root = draw_bt_node(ax, 3.75, 3.8, "Przenieś obiekt", 'seq', w=1.6)
|
||||
|
||||
# Level 2 children
|
||||
find = draw_bt_node(ax, 1.2, 2.8, "Znajdź obiekt", 'sel', w=1.3)
|
||||
nav = draw_bt_node(ax, 3.75, 2.8, "Jedź do obiektu", 'act', w=1.3)
|
||||
pick = draw_bt_node(ax, 6.3, 2.8, "Chwyć i dostarcz", 'seq', w=1.4)
|
||||
|
||||
# Arrows from root
|
||||
draw_arrow(ax, root[0], root[1] - 0.225, find[0], find[1] + 0.225, lw=1.0)
|
||||
draw_arrow(ax, root[0], root[1] - 0.225, nav[0], nav[1] + 0.225, lw=1.0)
|
||||
draw_arrow(ax, root[0], root[1] - 0.225, pick[0], pick[1] + 0.225, lw=1.0)
|
||||
|
||||
# Level 3: children of "Znajdź obiekt" (selector)
|
||||
vis = draw_bt_node(ax, 0.55, 1.7, "Widzę\nobiekt?", 'cond', w=0.85, h=0.5)
|
||||
scan = draw_bt_node(ax, 1.85, 1.7, "Skanuj\notoczenie", 'act', w=0.85, h=0.5)
|
||||
draw_arrow(ax, find[0], find[1] - 0.225, vis[0], vis[1] + 0.25, lw=0.8)
|
||||
draw_arrow(ax, find[0], find[1] - 0.225, scan[0], scan[1] + 0.25, lw=0.8)
|
||||
|
||||
# Level 3: children of "Chwyć i dostarcz" (sequence)
|
||||
grasp = draw_bt_node(ax, 5.4, 1.7, "Chwyć\nobject", 'act', w=0.85, h=0.5)
|
||||
deliver = draw_bt_node(ax, 6.5, 1.7, "Jedź do\ncelu", 'act', w=0.85, h=0.5)
|
||||
release = draw_bt_node(ax, 7.2, 1.7, "Puść", 'act', w=0.55, h=0.5)
|
||||
draw_arrow(ax, pick[0], pick[1] - 0.225, grasp[0], grasp[1] + 0.25, lw=0.8)
|
||||
draw_arrow(ax, pick[0], pick[1] - 0.225, deliver[0], deliver[1] + 0.25, lw=0.8)
|
||||
draw_arrow(ax, pick[0], pick[1] - 0.225, release[0], release[1] + 0.25, lw=0.8)
|
||||
|
||||
# Legend
|
||||
leg_y = 0.5
|
||||
draw_bt_node(ax, 0.8, leg_y, "→ Sequence", 'seq', w=1.1, h=0.35)
|
||||
draw_bt_node(ax, 2.3, leg_y, "? Selector", 'sel', w=1.0, h=0.35)
|
||||
draw_bt_node(ax, 3.6, leg_y, "Akcja", 'act', w=0.8, h=0.35)
|
||||
draw_bt_node(ax, 4.8, leg_y, "Warunek", 'cond', w=0.8, h=0.35)
|
||||
|
||||
ax.text(0.3, leg_y, "Legenda:", ha='left', va='center', fontsize=6.5,
|
||||
fontweight='bold')
|
||||
|
||||
# Execution note
|
||||
ax.text(3.75, 0.05, "Wykonanie: od lewej do prawej. Sequence (→) = wszystkie po kolei. "
|
||||
"Selector (?) = pierwszy sukces.",
|
||||
ha='center', va='center', fontsize=6, fontstyle='italic', color='#555555')
|
||||
|
||||
fig.tight_layout()
|
||||
path = os.path.join(OUTPUT_DIR, 'agent_behavior_tree.png')
|
||||
fig.savefig(path, dpi=DPI, bbox_inches='tight', facecolor=BG)
|
||||
plt.close(fig)
|
||||
print(f" ✓ {path}")
|
||||
|
||||
|
||||
# ─── DIAGRAM 4: BDI Model ────────────────────────────────────────
|
||||
def draw_bdi_model():
|
||||
fig, ax = plt.subplots(1, 1, figsize=(7, 4), facecolor=BG)
|
||||
ax.set_xlim(0, 7)
|
||||
ax.set_ylim(0, 4)
|
||||
ax.axis('off')
|
||||
ax.set_title("Model BDI agenta (Beliefs–Desires–Intentions)",
|
||||
fontsize=FS_TITLE, fontweight='bold', pad=10)
|
||||
|
||||
bw = 1.6
|
||||
bh = 1.4
|
||||
|
||||
# BELIEFS box
|
||||
draw_box(ax, 0.3, 1.3, bw, bh, "", fill=GRAY1, fontsize=8, fontweight='bold')
|
||||
ax.text(0.3 + bw/2, 1.3 + bh - 0.15, "BELIEFS", ha='center', va='top',
|
||||
fontsize=9, fontweight='bold')
|
||||
ax.text(0.3 + bw/2, 1.3 + bh/2 - 0.1,
|
||||
'(wiedza o \u015bwiecie)\n\n\u2022 mapa pokoju\n\u2022 pozycja robota\n\u2022 drzwi zamkni\u0119te\n\u2022 bateria: 45%',
|
||||
ha='center', va='center', fontsize=6.5)
|
||||
|
||||
# DESIRES box
|
||||
draw_box(ax, 2.7, 1.3, bw, bh, "", fill=GRAY2, fontsize=8, fontweight='bold')
|
||||
ax.text(2.7 + bw/2, 1.3 + bh - 0.15, "DESIRES", ha='center', va='top',
|
||||
fontsize=9, fontweight='bold')
|
||||
ax.text(2.7 + bw/2, 1.3 + bh/2 - 0.1,
|
||||
"(cele agenta)\n\n• dostarczyć paczkę\n do pokoju 5\n• naładować baterię\n• unikać kolizji",
|
||||
ha='center', va='center', fontsize=6.5)
|
||||
|
||||
# INTENTIONS box
|
||||
draw_box(ax, 5.1, 1.3, bw, bh, "", fill=GRAY3, fontsize=8, fontweight='bold')
|
||||
ax.text(5.1 + bw/2, 1.3 + bh - 0.15, "INTENTIONS", ha='center', va='top',
|
||||
fontsize=9, fontweight='bold')
|
||||
ax.text(5.1 + bw/2, 1.3 + bh/2 - 0.1,
|
||||
"(aktualny plan)\n\n→ jedź do drzwi\n bocznych\n→ otwórz drzwi\n→ wjedź do pokoju 5",
|
||||
ha='center', va='center', fontsize=6.5)
|
||||
|
||||
# Arrows
|
||||
draw_arrow(ax, 0.3 + bw, 1.3 + bh/2 + 0.15, 2.7, 1.3 + bh/2 + 0.15, lw=1.3,
|
||||
label='informuje', label_offset=0.08)
|
||||
draw_arrow(ax, 2.7 + bw, 1.3 + bh/2 + 0.15, 5.1, 1.3 + bh/2 + 0.15, lw=1.3,
|
||||
label='filtruje → wybiera', label_offset=0.08)
|
||||
|
||||
# Feedback from intentions back to beliefs (update)
|
||||
ax.annotate("", xy=(0.3 + bw/2, 1.3), xytext=(5.1 + bw/2, 1.3),
|
||||
arrowprops=dict(arrowstyle='->', color='#666666', lw=1.0,
|
||||
linestyle='dashed',
|
||||
connectionstyle="arc3,rad=0.3"))
|
||||
ax.text(3.5, 0.75, "aktualizacja wiedzy po wykonaniu akcji",
|
||||
ha='center', va='center', fontsize=6, fontstyle='italic', color='#666666')
|
||||
|
||||
# Sensor input arrow
|
||||
draw_arrow(ax, 0.3 + bw/2, 3.5, 0.3 + bw/2, 1.3 + bh, lw=1.3,
|
||||
label='percepcja (sensory)', label_offset=0.05)
|
||||
ax.text(0.3 + bw/2, 3.55, "ŚRODOWISKO", ha='center', va='bottom',
|
||||
fontsize=7, fontweight='bold',
|
||||
bbox=dict(boxstyle='round,pad=0.2', facecolor=GRAY4, edgecolor=LN, lw=0.8))
|
||||
|
||||
# Action output arrow
|
||||
draw_arrow(ax, 5.1 + bw/2, 1.3 + bh, 5.1 + bw/2, 3.5, lw=1.3,
|
||||
label='akcja (efektory)', label_offset=0.05)
|
||||
ax.text(5.1 + bw/2, 3.55, "EFEKTORY", ha='center', va='bottom',
|
||||
fontsize=7, fontweight='bold',
|
||||
bbox=dict(boxstyle='round,pad=0.2', facecolor=GRAY4, edgecolor=LN, lw=0.8))
|
||||
|
||||
fig.tight_layout()
|
||||
path = os.path.join(OUTPUT_DIR, 'agent_bdi_model.png')
|
||||
fig.savefig(path, dpi=DPI, bbox_inches='tight', facecolor=BG)
|
||||
plt.close(fig)
|
||||
print(f" ✓ {path}")
|
||||
|
||||
|
||||
# ─── MAIN ────────────────────────────────────────────────────────
|
||||
if __name__ == '__main__':
|
||||
print("Generating PYTANIE 15 diagrams...")
|
||||
draw_see_think_act()
|
||||
draw_3t_architecture()
|
||||
draw_behavior_tree()
|
||||
draw_bdi_model()
|
||||
print("Done! All diagrams saved to", OUTPUT_DIR)
|
||||
297
pytania/generate_pattern_diagrams.py
Normal file
@ -0,0 +1,297 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Generate pattern cataloguing diagrams for PYTANIE 14 (AIS):
|
||||
1. Pattern Template Structure — the standard fields every pattern has
|
||||
2. Catalog Classification Map — catalogs arranged by scope & domain
|
||||
3. Pattern Language Network — how patterns reference each other
|
||||
|
||||
All: A4-compatible, B&W, 300 DPI, laser-printer-friendly.
|
||||
"""
|
||||
|
||||
import matplotlib
|
||||
matplotlib.use('Agg')
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.patches as mpatches
|
||||
from matplotlib.patches import FancyBboxPatch, FancyArrowPatch
|
||||
import numpy as np
|
||||
import os
|
||||
|
||||
DPI = 300
|
||||
BG = 'white'
|
||||
LN = 'black'
|
||||
FS = 9
|
||||
FS_TITLE = 13
|
||||
FS_SMALL = 7.5
|
||||
OUTPUT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'img')
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
|
||||
GRAY1 = '#E8E8E8'
|
||||
GRAY2 = '#D0D0D0'
|
||||
GRAY3 = '#B8B8B8'
|
||||
GRAY4 = '#F5F5F5'
|
||||
GRAY5 = '#C0C0C0'
|
||||
|
||||
|
||||
def draw_box(ax, x, y, w, h, text, fill='white', lw=1.2, fontsize=FS,
|
||||
fontweight='normal', ha='center', va='center', rounded=True):
|
||||
if rounded:
|
||||
rect = FancyBboxPatch((x, y), w, h, boxstyle="round,pad=0.08",
|
||||
lw=lw, edgecolor=LN, facecolor=fill)
|
||||
else:
|
||||
rect = mpatches.Rectangle((x, y), w, h, lw=lw, edgecolor=LN, facecolor=fill)
|
||||
ax.add_patch(rect)
|
||||
ax.text(x + w / 2, y + h / 2, text, ha=ha, va=va, fontsize=fontsize,
|
||||
fontweight=fontweight, wrap=True)
|
||||
|
||||
|
||||
def draw_arrow(ax, x1, y1, x2, y2, lw=1.2, style='->', color=LN):
|
||||
ax.annotate("", xy=(x2, y2), xytext=(x1, y1),
|
||||
arrowprops=dict(arrowstyle=style, color=color, lw=lw))
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 1. Pattern Template Structure (NaPSiRoKo mnemonic)
|
||||
# ============================================================
|
||||
def generate_pattern_template():
|
||||
fig, ax = plt.subplots(figsize=(8.27, 6))
|
||||
ax.set_xlim(0, 10)
|
||||
ax.set_ylim(0, 8)
|
||||
ax.set_aspect('equal')
|
||||
ax.axis('off')
|
||||
fig.patch.set_facecolor(BG)
|
||||
ax.set_title('Szablon opisu wzorca \u2014 \u201eNaPSiRoKo\u201d',
|
||||
fontsize=FS_TITLE, fontweight='bold', pad=15)
|
||||
|
||||
# Main card outline
|
||||
card_x, card_y, card_w, card_h = 1.5, 0.5, 7, 7
|
||||
card = FancyBboxPatch((card_x, card_y), card_w, card_h,
|
||||
boxstyle="round,pad=0.15", lw=2.5,
|
||||
edgecolor=LN, facecolor=GRAY4)
|
||||
ax.add_patch(card)
|
||||
|
||||
# Title of card
|
||||
ax.text(card_x + card_w / 2, card_y + card_h - 0.35,
|
||||
"KARTA WZORCA", ha='center', va='center',
|
||||
fontsize=FS_TITLE, fontweight='bold')
|
||||
|
||||
# Fields as horizontal bands
|
||||
fields = [
|
||||
("Na", "NAZWA", "Layered, Observer, Microservices", GRAY1),
|
||||
("P", "PROBLEM / KONTEKST", "Kiedy stosować? Jaki problem rozwiązuje?", 'white'),
|
||||
("Si", "SIŁY (forces)", "Konkurencyjne wymagania do pogodzenia\n(np. testowalność vs wydajność)", GRAY1),
|
||||
("Ro", "ROZWIĄZANIE", "Struktura, diagram, zachowanie", 'white'),
|
||||
("Ko", "KONSEKWENCJE", "Tradeoffs: co zyskujemy, co tracimy", GRAY1),
|
||||
]
|
||||
|
||||
band_x = card_x + 0.3
|
||||
band_w = card_w - 0.6
|
||||
band_h = 1.05
|
||||
start_y = card_y + card_h - 1.1
|
||||
|
||||
for i, (abbr, title, desc, fill) in enumerate(fields):
|
||||
by = start_y - i * (band_h + 0.15)
|
||||
|
||||
# Abbreviation circle on the left
|
||||
circle = plt.Circle((band_x + 0.35, by + band_h / 2), 0.28,
|
||||
lw=1.5, edgecolor=LN, facecolor=GRAY2)
|
||||
ax.add_patch(circle)
|
||||
ax.text(band_x + 0.35, by + band_h / 2, abbr, ha='center', va='center',
|
||||
fontsize=10, fontweight='bold')
|
||||
|
||||
# Field box
|
||||
fx = band_x + 0.8
|
||||
fw = band_w - 0.8
|
||||
rect = FancyBboxPatch((fx, by), fw, band_h,
|
||||
boxstyle="round,pad=0.06", lw=1,
|
||||
edgecolor=LN, facecolor=fill)
|
||||
ax.add_patch(rect)
|
||||
ax.text(fx + 0.15, by + band_h - 0.25, title, ha='left', va='center',
|
||||
fontsize=FS, fontweight='bold')
|
||||
ax.text(fx + 0.15, by + 0.25, desc, ha='left', va='center',
|
||||
fontsize=FS_SMALL, fontstyle='italic', color='#444444')
|
||||
|
||||
# Arrow connecting fields
|
||||
if i < len(fields) - 1:
|
||||
draw_arrow(ax, band_x + 0.35, by - 0.02,
|
||||
band_x + 0.35, by - 0.13, lw=1.0)
|
||||
|
||||
# Extra fields note at bottom
|
||||
ax.text(card_x + card_w / 2, card_y + 0.25,
|
||||
"+ Powiązane wzorce • Znane zastosowania • Warianty",
|
||||
ha='center', va='center', fontsize=FS_SMALL, fontstyle='italic')
|
||||
|
||||
# Mnemonic reminder on the right
|
||||
ax.text(9.8, 4, "Mnemonik:\nNaPSiRoKo",
|
||||
ha='center', va='center', fontsize=10, fontweight='bold',
|
||||
rotation=90, color='#666666')
|
||||
|
||||
fig.tight_layout()
|
||||
out = os.path.join(OUTPUT_DIR, 'q14_pattern_template.png')
|
||||
fig.savefig(out, dpi=DPI, bbox_inches='tight', facecolor=BG)
|
||||
plt.close(fig)
|
||||
print(f" Saved: {out}")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 2. Catalog Classification Map
|
||||
# ============================================================
|
||||
def generate_catalog_map():
|
||||
fig, ax = plt.subplots(figsize=(8.27, 7))
|
||||
ax.set_xlim(0, 12)
|
||||
ax.set_ylim(0, 9)
|
||||
ax.set_aspect('equal')
|
||||
ax.axis('off')
|
||||
fig.patch.set_facecolor(BG)
|
||||
ax.set_title('Mapa katalog\u00f3w wzorc\u00f3w \u2014 \u201ePawe\u0142 Gra\u0142 Efektownie Pod Chmurami\u201d',
|
||||
fontsize=FS_TITLE, fontweight='bold', pad=15)
|
||||
|
||||
# Y-axis: Scale (architectural → design → idiom)
|
||||
ax.text(0.3, 7.8, "SKALA", fontsize=10, fontweight='bold',
|
||||
ha='center', va='center', rotation=90)
|
||||
ax.annotate("", xy=(0.3, 2.0), xytext=(0.3, 7.5),
|
||||
arrowprops=dict(arrowstyle='->', lw=1.5, color=LN))
|
||||
|
||||
scale_labels = [
|
||||
(7.0, "Architektoniczny\n(cały system)"),
|
||||
(5.0, "Projektowy\n(klasa/obiekt)"),
|
||||
(3.0, "Idiomatyczny\n(linia kodu)"),
|
||||
]
|
||||
for sy, label in scale_labels:
|
||||
ax.text(1.0, sy, label, fontsize=FS_SMALL, ha='left', va='center',
|
||||
fontstyle='italic')
|
||||
ax.plot([0.15, 0.45], [sy, sy], color=GRAY3, lw=0.8, ls='--')
|
||||
|
||||
# X-axis: Domain
|
||||
ax.text(6.5, 1.2, "DOMENA ZASTOSOWANIA", fontsize=10, fontweight='bold',
|
||||
ha='center', va='center')
|
||||
ax.annotate("", xy=(11.5, 1.5), xytext=(2.0, 1.5),
|
||||
arrowprops=dict(arrowstyle='->', lw=1.5, color=LN))
|
||||
|
||||
# Catalog boxes positioned by scale × domain
|
||||
catalogs = [
|
||||
# (x, y, w, h, name, subtitle, fill, mnemonic_letter)
|
||||
(2.5, 6.2, 2.5, 1.4, "POSA", "1996 • Buschmann\nLayers, Broker,\nPipes & Filters, MVC", GRAY1, "P"),
|
||||
(2.5, 4.2, 2.5, 1.4, "GoF", "1994 • Gamma et al.\n23 wzorce:\n5 kreac. / 7 strukt. / 11 behaw.", GRAY2, "G"),
|
||||
(5.5, 6.2, 2.5, 1.4, "EIP", "2003 • Hohpe & Woolf\nMessage Channel,\nRouter, Aggregator", GRAY1, "E"),
|
||||
(5.5, 4.2, 2.5, 1.4, "PoEAA", "2002 • M. Fowler\nRepository, Unit of Work,\nDomain Model", 'white', "P"),
|
||||
(8.5, 6.2, 2.8, 1.4, "Cloud\nPatterns", "~2015 • Azure/AWS\nCircuit Breaker,\nSaga, Sidecar", GRAY1, "C"),
|
||||
]
|
||||
|
||||
for cx, cy, cw, ch, name, sub, fill, ml in catalogs:
|
||||
rect = FancyBboxPatch((cx, cy), cw, ch, boxstyle="round,pad=0.1",
|
||||
lw=1.5, edgecolor=LN, facecolor=fill)
|
||||
ax.add_patch(rect)
|
||||
ax.text(cx + cw / 2, cy + ch - 0.3, name, ha='center', va='center',
|
||||
fontsize=10, fontweight='bold')
|
||||
ax.text(cx + cw / 2, cy + 0.4, sub, ha='center', va='center',
|
||||
fontsize=FS_SMALL, linespacing=1.3)
|
||||
|
||||
# Mnemonic letter in corner
|
||||
circle = plt.Circle((cx + 0.25, cy + ch - 0.25), 0.2,
|
||||
lw=1, edgecolor=LN, facecolor=GRAY5)
|
||||
ax.add_patch(circle)
|
||||
ax.text(cx + 0.25, cy + ch - 0.25, ml, ha='center', va='center',
|
||||
fontsize=8, fontweight='bold')
|
||||
|
||||
# Mnemonic bar at bottom
|
||||
mnem_y = 2.2
|
||||
ax.text(6.0, mnem_y, "PGEP+C → Paweł Grał Efektownie Pod Chmurami",
|
||||
ha='center', va='center', fontsize=10, fontweight='bold',
|
||||
bbox=dict(boxstyle='round,pad=0.3', facecolor=GRAY4, edgecolor=LN, lw=1.5))
|
||||
|
||||
# Domain labels along x-axis
|
||||
domains = [
|
||||
(3.75, 1.7, "Architektura"),
|
||||
(6.75, 1.7, "Integracja / Enterprise"),
|
||||
(9.9, 1.7, "Chmura"),
|
||||
]
|
||||
for dx, dy, dlabel in domains:
|
||||
ax.text(dx, dy, dlabel, ha='center', va='center',
|
||||
fontsize=FS_SMALL, fontstyle='italic')
|
||||
|
||||
fig.tight_layout()
|
||||
out = os.path.join(OUTPUT_DIR, 'q14_catalog_map.png')
|
||||
fig.savefig(out, dpi=DPI, bbox_inches='tight', facecolor=BG)
|
||||
plt.close(fig)
|
||||
print(f" Saved: {out}")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 3. Three Pillars of Cataloguing
|
||||
# ============================================================
|
||||
def generate_three_pillars():
|
||||
fig, ax = plt.subplots(figsize=(8.27, 5.5))
|
||||
ax.set_xlim(0, 12)
|
||||
ax.set_ylim(0, 7)
|
||||
ax.set_aspect('equal')
|
||||
ax.axis('off')
|
||||
fig.patch.set_facecolor(BG)
|
||||
ax.set_title("Jak są katalogowane wzorce? — Trzy filary",
|
||||
fontsize=FS_TITLE, fontweight='bold', pad=15)
|
||||
|
||||
# Roof / banner
|
||||
roof_pts = np.array([[1, 5.5], [6, 6.8], [11, 5.5]])
|
||||
roof = plt.Polygon(roof_pts, closed=True, lw=2,
|
||||
edgecolor=LN, facecolor=GRAY4)
|
||||
ax.add_patch(roof)
|
||||
ax.text(6, 6.0, "KATALOGOWANIE WZORCÓW",
|
||||
ha='center', va='center', fontsize=11, fontweight='bold')
|
||||
|
||||
# Three pillars
|
||||
pillars = [
|
||||
(1.3, "1. SZABLON\nOPISU",
|
||||
"Każdy wzorzec ma\nte same pola:\nNazwa → Problem\n→ Siły → Rozwiązanie\n→ Konsekwencje",
|
||||
"Analogia:\nformatka\nencyklopedii"),
|
||||
(4.8, "2. KLASYFIKACJA\nWIELOOSIOWA",
|
||||
"Osie podziału:\n• Skala (arch/proj/idiom)\n• Domena problemu\n• Atrybut jakościowy\n• Domena zastosowania",
|
||||
"Analogia:\nkategorie\nw bibliotece"),
|
||||
(8.3, "3. JĘZYK\nWZORCÓW",
|
||||
"Wzorce referują się\nwzajemnie tworząc\nsieć/graf:\nA → wymaga → B\nB → wariant → C",
|
||||
"Analogia:\n\u201ezobacz te\u017c\u201d\nw encyklopedii"),
|
||||
]
|
||||
|
||||
for px, title, desc, analogy in pillars:
|
||||
pw, ph = 2.8, 5.0
|
||||
py = 0.5
|
||||
|
||||
# Pillar rectangle
|
||||
rect = FancyBboxPatch((px, py), pw, ph, boxstyle="round,pad=0.1",
|
||||
lw=1.8, edgecolor=LN, facecolor='white')
|
||||
ax.add_patch(rect)
|
||||
|
||||
# Title
|
||||
ax.text(px + pw / 2, py + ph - 0.55, title, ha='center', va='center',
|
||||
fontsize=9, fontweight='bold')
|
||||
|
||||
# Horizontal line under title
|
||||
ax.plot([px + 0.2, px + pw - 0.2], [py + ph - 1.0, py + ph - 1.0],
|
||||
color=LN, lw=0.8)
|
||||
|
||||
# Description
|
||||
ax.text(px + pw / 2, py + ph / 2 - 0.3, desc, ha='center', va='center',
|
||||
fontsize=FS_SMALL, linespacing=1.4)
|
||||
|
||||
# Analogy box at bottom
|
||||
analogy_rect = FancyBboxPatch((px + 0.2, py + 0.15), pw - 0.4, 1.0,
|
||||
boxstyle="round,pad=0.06", lw=0.8,
|
||||
edgecolor=GRAY3, facecolor=GRAY1)
|
||||
ax.add_patch(analogy_rect)
|
||||
ax.text(px + pw / 2, py + 0.65, analogy, ha='center', va='center',
|
||||
fontsize=FS_SMALL, fontstyle='italic', color='#555555')
|
||||
|
||||
fig.tight_layout()
|
||||
out = os.path.join(OUTPUT_DIR, 'q14_three_pillars.png')
|
||||
fig.savefig(out, dpi=DPI, bbox_inches='tight', facecolor=BG)
|
||||
plt.close(fig)
|
||||
print(f" Saved: {out}")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Main
|
||||
# ============================================================
|
||||
if __name__ == '__main__':
|
||||
print("Generating PYTANIE 14 diagrams...")
|
||||
generate_pattern_template()
|
||||
generate_catalog_map()
|
||||
generate_three_pillars()
|
||||
print("Done!")
|
||||
451
pytania/generate_pubsub_diagrams.py
Normal file
@ -0,0 +1,451 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Generate Pub/Sub diagrams for PYTANIE 19:
|
||||
Subscription types (4 separate images):
|
||||
1. Topic-based
|
||||
2. Content-based
|
||||
3. Type-based
|
||||
4. Hierarchical (wildcards)
|
||||
Delivery guarantees (3 separate images):
|
||||
5. At-most-once
|
||||
6. At-least-once
|
||||
7. Exactly-once
|
||||
|
||||
All: A4-width, B&W, 300 DPI, laser-printer-friendly.
|
||||
One diagram per image — no cramming.
|
||||
"""
|
||||
|
||||
import matplotlib
|
||||
matplotlib.use('Agg')
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.patches as mpatches
|
||||
from matplotlib.patches import FancyBboxPatch
|
||||
import os
|
||||
|
||||
DPI = 300
|
||||
BG = 'white'
|
||||
LN = 'black'
|
||||
FS = 9
|
||||
FS_TITLE = 13
|
||||
FIG_W = 8.27 # A4 width in inches
|
||||
OUTPUT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'img')
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
|
||||
GRAY1 = '#E8E8E8'
|
||||
GRAY2 = '#D0D0D0'
|
||||
GRAY3 = '#B8B8B8'
|
||||
GRAY4 = '#F5F5F5'
|
||||
GRAY5 = '#C0C0C0'
|
||||
|
||||
|
||||
def draw_box(ax, x, y, w, h, text, fill='white', lw=1.2, fontsize=FS,
|
||||
fontweight='normal', ha='center', va='center', rounded=True):
|
||||
if rounded:
|
||||
rect = FancyBboxPatch((x, y), w, h, boxstyle="round,pad=0.05",
|
||||
lw=lw, edgecolor=LN, facecolor=fill)
|
||||
else:
|
||||
rect = mpatches.Rectangle((x, y), w, h, lw=lw, edgecolor=LN, facecolor=fill)
|
||||
ax.add_patch(rect)
|
||||
ax.text(x + w/2, y + h/2, text, ha=ha, va=va, fontsize=fontsize,
|
||||
fontweight=fontweight, wrap=True)
|
||||
|
||||
|
||||
def draw_arrow(ax, x1, y1, x2, y2, lw=1.2, style='->', color=LN, label='',
|
||||
label_offset=0.15, label_fs=8):
|
||||
ax.annotate("", xy=(x2, y2), xytext=(x1, y1),
|
||||
arrowprops=dict(arrowstyle=style, color=color, lw=lw))
|
||||
if label:
|
||||
mx, my = (x1 + x2) / 2, (y1 + y2) / 2 + label_offset
|
||||
ax.text(mx, my, label, ha='center', va='bottom', fontsize=label_fs, color=color)
|
||||
|
||||
|
||||
def draw_dashed_arrow(ax, x1, y1, x2, y2, lw=1.0, color=LN, label='',
|
||||
label_offset=0.15, label_fs=8):
|
||||
ax.annotate("", xy=(x2, y2), xytext=(x1, y1),
|
||||
arrowprops=dict(arrowstyle='->', color=color, lw=lw,
|
||||
linestyle='dashed'))
|
||||
if label:
|
||||
mx, my = (x1 + x2) / 2, (y1 + y2) / 2 + label_offset
|
||||
ax.text(mx, my, label, ha='center', va='bottom', fontsize=label_fs, color=color)
|
||||
|
||||
|
||||
def draw_cross(ax, x, y, size=0.15, lw=2.5, color='black'):
|
||||
ax.plot([x - size, x + size], [y - size, y + size], color=color, lw=lw)
|
||||
ax.plot([x - size, x + size], [y + size, y - size], color=color, lw=lw)
|
||||
|
||||
|
||||
def draw_check(ax, x, y, size=0.15, lw=2.5, color='black'):
|
||||
ax.plot([x - size, x - size*0.2], [y, y - size*0.7], color=color, lw=lw)
|
||||
ax.plot([x - size*0.2, x + size], [y - size*0.7, y + size*0.5], color=color, lw=lw)
|
||||
|
||||
|
||||
def save(fig, name):
|
||||
plt.tight_layout()
|
||||
fig.savefig(os.path.join(OUTPUT_DIR, name), dpi=DPI,
|
||||
bbox_inches='tight', facecolor=BG)
|
||||
plt.close(fig)
|
||||
print(f" ✓ {name}")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 1. Topic-based subscription
|
||||
# ============================================================
|
||||
def draw_sub_topic():
|
||||
fig, ax = plt.subplots(1, 1, figsize=(FIG_W, 4.0))
|
||||
ax.set_xlim(0, 12)
|
||||
ax.set_ylim(0, 5.5)
|
||||
ax.set_aspect('equal')
|
||||
ax.axis('off')
|
||||
ax.set_title('Subskrypcja topic-based — routing po nazwie tematu',
|
||||
fontsize=FS_TITLE, fontweight='bold', pad=12)
|
||||
|
||||
# Publisher + messages
|
||||
draw_box(ax, 0.2, 3.2, 2.4, 1.1, 'Publisher', fill=GRAY1, fontsize=10, fontweight='bold')
|
||||
draw_box(ax, 0.3, 1.8, 2.2, 0.8, 'topic: "orders"', fill=GRAY4, fontsize=8)
|
||||
draw_box(ax, 0.3, 0.7, 2.2, 0.8, 'topic: "payments"', fill=GRAY4, fontsize=8)
|
||||
|
||||
# Broker
|
||||
draw_box(ax, 4.2, 1.5, 2.8, 2.2, 'BROKER\n\ntopic routing', fill=GRAY2, fontsize=10, fontweight='bold')
|
||||
|
||||
# Subscribers
|
||||
draw_box(ax, 8.5, 3.8, 3.0, 1.0, 'Subscriber A\nsubskrybuje: "orders"', fill=GRAY1, fontsize=8.5)
|
||||
draw_box(ax, 8.5, 2.2, 3.0, 1.0, 'Subscriber B\nsubskrybuje: "payments"', fill=GRAY1, fontsize=8.5)
|
||||
draw_box(ax, 8.5, 0.6, 3.0, 1.0, 'Subscriber C\nsubskrybuje: "orders"', fill=GRAY1, fontsize=8.5)
|
||||
|
||||
# Arrows: publisher → broker
|
||||
draw_arrow(ax, 2.6, 2.2, 4.2, 2.8, label_fs=8)
|
||||
draw_arrow(ax, 2.6, 1.1, 4.2, 2.2, label_fs=8)
|
||||
|
||||
# Arrows: broker → subscribers
|
||||
draw_arrow(ax, 7.0, 3.4, 8.5, 4.2, label='"orders"', label_fs=8)
|
||||
draw_arrow(ax, 7.0, 2.6, 8.5, 2.7, label='"payments"', label_fs=8)
|
||||
draw_arrow(ax, 7.0, 2.2, 8.5, 1.2, label='"orders"', label_fs=8)
|
||||
|
||||
# Explanation
|
||||
ax.text(6.0, 0.1, 'Subscriber deklaruje nazwę tematu. Broker kieruje wiadomości\n'
|
||||
'do WSZYSTKICH subscriberów danego tematu. Najprostszy model.',
|
||||
ha='center', va='bottom', fontsize=8.5, style='italic',
|
||||
bbox=dict(boxstyle='round,pad=0.3', facecolor=GRAY4, edgecolor=GRAY3))
|
||||
|
||||
save(fig, 'pubsub_sub_topic.png')
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 2. Content-based subscription
|
||||
# ============================================================
|
||||
def draw_sub_content():
|
||||
fig, ax = plt.subplots(1, 1, figsize=(FIG_W, 4.5))
|
||||
ax.set_xlim(0, 12)
|
||||
ax.set_ylim(0, 6)
|
||||
ax.set_aspect('equal')
|
||||
ax.axis('off')
|
||||
ax.set_title('Subskrypcja content-based — filtrowanie po treści wiadomości',
|
||||
fontsize=FS_TITLE, fontweight='bold', pad=12)
|
||||
|
||||
# Publisher + message
|
||||
draw_box(ax, 0.2, 3.5, 2.4, 1.1, 'Publisher', fill=GRAY1, fontsize=10, fontweight='bold')
|
||||
draw_box(ax, 0.2, 1.8, 2.4, 1.2, 'price: 150\ntype: "book"\ncategory: "IT"', fill=GRAY4, fontsize=8.5)
|
||||
|
||||
# Broker
|
||||
draw_box(ax, 4.0, 2.0, 3.0, 2.5, 'BROKER\n\newaluuje filtry\nkażdego subscribera', fill=GRAY2, fontsize=9, fontweight='bold')
|
||||
|
||||
# Subscribers with filters
|
||||
draw_box(ax, 8.5, 4.2, 3.2, 1.0, 'Sub A\nfiltr: price > 100', fill=GRAY1, fontsize=9)
|
||||
draw_box(ax, 8.5, 2.6, 3.2, 1.0, 'Sub B\nfiltr: type = "food"', fill=GRAY1, fontsize=9)
|
||||
draw_box(ax, 8.5, 1.0, 3.2, 1.0, 'Sub C\nfiltr: price < 50', fill=GRAY1, fontsize=9)
|
||||
|
||||
# Arrows
|
||||
draw_arrow(ax, 2.6, 2.4, 4.0, 3.0)
|
||||
draw_arrow(ax, 7.0, 4.0, 8.5, 4.6, label='150 > 100 ✓ dostarczono', label_fs=8)
|
||||
draw_dashed_arrow(ax, 7.0, 3.2, 8.5, 3.1, label='"book" ≠ "food" ✗ odrzucono', label_fs=8)
|
||||
draw_dashed_arrow(ax, 7.0, 2.5, 8.5, 1.6, label='150 < 50 ✗ odrzucono', label_fs=8)
|
||||
|
||||
ax.text(6.0, 0.2, 'Broker analizuje TREŚĆ wiadomości i ewaluuje predykaty.\n'
|
||||
'Bardziej elastyczny niż topic-based, ale wolniejszy (koszt ewaluacji).',
|
||||
ha='center', va='bottom', fontsize=8.5, style='italic',
|
||||
bbox=dict(boxstyle='round,pad=0.3', facecolor=GRAY4, edgecolor=GRAY3))
|
||||
|
||||
save(fig, 'pubsub_sub_content.png')
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 3. Type-based subscription
|
||||
# ============================================================
|
||||
def draw_sub_type():
|
||||
fig, ax = plt.subplots(1, 1, figsize=(FIG_W, 5.0))
|
||||
ax.set_xlim(0, 12)
|
||||
ax.set_ylim(0, 6.5)
|
||||
ax.set_aspect('equal')
|
||||
ax.axis('off')
|
||||
ax.set_title('Subskrypcja type-based — routing po typie (klasie) obiektu',
|
||||
fontsize=FS_TITLE, fontweight='bold', pad=12)
|
||||
|
||||
# Publisher
|
||||
draw_box(ax, 0.2, 4.2, 2.4, 1.1, 'Publisher', fill=GRAY1, fontsize=10, fontweight='bold')
|
||||
|
||||
# Messages
|
||||
draw_box(ax, 0.1, 2.8, 2.6, 0.9, 'new OrderEvent()', fill=GRAY4, fontsize=9)
|
||||
draw_box(ax, 0.1, 1.5, 2.6, 0.9, 'new PaymentEvent()', fill=GRAY4, fontsize=9)
|
||||
|
||||
# Broker
|
||||
draw_box(ax, 4.0, 2.3, 3.0, 2.4, 'BROKER\n\nrouting po\ntypie klasy', fill=GRAY2, fontsize=10, fontweight='bold')
|
||||
|
||||
# Subscribers
|
||||
draw_box(ax, 8.5, 4.8, 3.2, 1.0, 'Sub A\n→ OrderEvent', fill=GRAY1, fontsize=9)
|
||||
draw_box(ax, 8.5, 3.2, 3.2, 1.0, 'Sub B\n→ PaymentEvent', fill=GRAY1, fontsize=9)
|
||||
draw_box(ax, 8.5, 1.6, 3.2, 1.0, 'Sub C\n→ Event (base)', fill=GRAY1, fontsize=9)
|
||||
|
||||
# Arrows
|
||||
draw_arrow(ax, 2.7, 3.2, 4.0, 3.8)
|
||||
draw_arrow(ax, 2.7, 2.0, 4.0, 3.0)
|
||||
draw_arrow(ax, 7.0, 4.3, 8.5, 5.2, label='OrderEvent', label_fs=8)
|
||||
draw_arrow(ax, 7.0, 3.5, 8.5, 3.7, label='PaymentEvent', label_fs=8)
|
||||
draw_arrow(ax, 7.0, 3.0, 8.5, 2.2, label='oba (dziedziczenie!)', label_fs=8)
|
||||
|
||||
# Class hierarchy inset
|
||||
hx, hy = 0.5, 0.0
|
||||
draw_box(ax, hx + 2.0, hy + 0.2, 1.8, 0.6, 'Event', fill=GRAY3, fontsize=8, fontweight='bold')
|
||||
draw_box(ax, hx + 0.0, hy + 0.2, 1.8, 0.6, 'OrderEvent', fill=GRAY4, fontsize=7.5)
|
||||
draw_box(ax, hx + 4.0, hy + 0.2, 2.0, 0.6, 'PaymentEvent', fill=GRAY4, fontsize=7.5)
|
||||
draw_arrow(ax, hx + 2.9, hy + 0.2, hx + 0.9, hy + 0.2, lw=1.0, style='->', label='extends', label_offset=-0.3, label_fs=7)
|
||||
draw_arrow(ax, hx + 2.9, hy + 0.2, hx + 5.0, hy + 0.2, lw=1.0, style='->', label='extends', label_offset=-0.3, label_fs=7)
|
||||
|
||||
ax.text(9.5, 0.5, 'Sub C subskrybuje bazowy Event\n→ otrzymuje WSZYSTKIE podtypy',
|
||||
ha='center', va='center', fontsize=8.5, style='italic',
|
||||
bbox=dict(boxstyle='round,pad=0.3', facecolor=GRAY4, edgecolor=GRAY3))
|
||||
|
||||
save(fig, 'pubsub_sub_type.png')
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 4. Hierarchical / Wildcards subscription
|
||||
# ============================================================
|
||||
def draw_sub_hierarchical():
|
||||
fig, ax = plt.subplots(1, 1, figsize=(FIG_W, 5.5))
|
||||
ax.set_xlim(0, 12)
|
||||
ax.set_ylim(0, 7)
|
||||
ax.set_aspect('equal')
|
||||
ax.axis('off')
|
||||
ax.set_title('Subskrypcja hierarchiczna (wildcards) — wzorce tematów',
|
||||
fontsize=FS_TITLE, fontweight='bold', pad=12)
|
||||
|
||||
# Topic tree
|
||||
draw_box(ax, 4.5, 5.8, 2.4, 0.8, 'sensors/', fill=GRAY2, fontsize=10, fontweight='bold')
|
||||
|
||||
draw_box(ax, 1.5, 4.2, 2.4, 0.8, 'temperature/', fill=GRAY3, fontsize=9)
|
||||
draw_box(ax, 7.5, 4.2, 2.4, 0.8, 'humidity/', fill=GRAY3, fontsize=9)
|
||||
|
||||
draw_box(ax, 0.2, 2.8, 1.8, 0.7, 'room1', fill=GRAY4, fontsize=8.5)
|
||||
draw_box(ax, 2.4, 2.8, 1.8, 0.7, 'room2', fill=GRAY4, fontsize=8.5)
|
||||
draw_box(ax, 6.8, 2.8, 1.8, 0.7, 'room1', fill=GRAY4, fontsize=8.5)
|
||||
draw_box(ax, 9.0, 2.8, 1.8, 0.7, 'room2', fill=GRAY4, fontsize=8.5)
|
||||
|
||||
# Tree edges
|
||||
draw_arrow(ax, 5.7, 5.8, 2.7, 5.0, lw=1.0)
|
||||
draw_arrow(ax, 5.7, 5.8, 8.7, 5.0, lw=1.0)
|
||||
draw_arrow(ax, 2.2, 4.2, 1.1, 3.5, lw=1.0)
|
||||
draw_arrow(ax, 3.2, 4.2, 3.3, 3.5, lw=1.0)
|
||||
draw_arrow(ax, 8.2, 4.2, 7.7, 3.5, lw=1.0)
|
||||
draw_arrow(ax, 9.2, 4.2, 9.9, 3.5, lw=1.0)
|
||||
|
||||
# Full paths
|
||||
ax.text(1.1, 2.4, 'sensors/temperature/room1', fontsize=7, ha='center',
|
||||
fontfamily='monospace', style='italic')
|
||||
ax.text(3.3, 2.4, 'sensors/temperature/room2', fontsize=7, ha='center',
|
||||
fontfamily='monospace', style='italic')
|
||||
|
||||
# Wildcard examples
|
||||
ax.text(0.3, 1.5, 'Wzorce subskrypcji (MQTT-style):', fontsize=10, fontweight='bold')
|
||||
|
||||
patterns = [
|
||||
('"sensors/temperature/room1"', '→ TYLKO room1', '(dokładne dopasowanie)'),
|
||||
('"sensors/temperature/*"', '→ room1, room2', '( * = jeden poziom)'),
|
||||
('"sensors/#"', '→ WSZYSTKO', '( # = dowolna głębokość)'),
|
||||
]
|
||||
for i, (pat, result, note) in enumerate(patterns):
|
||||
yy = 0.9 - i * 0.55
|
||||
ax.text(0.5, yy, pat, fontsize=9, fontweight='bold', fontfamily='monospace')
|
||||
ax.text(7.0, yy, result, fontsize=9, fontweight='bold')
|
||||
ax.text(9.5, yy, note, fontsize=8, style='italic')
|
||||
|
||||
save(fig, 'pubsub_sub_hierarchical.png')
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 5. At-most-once (QoS 0)
|
||||
# ============================================================
|
||||
def draw_qos_at_most_once():
|
||||
fig, ax = plt.subplots(1, 1, figsize=(FIG_W, 4.5))
|
||||
ax.set_xlim(0, 12)
|
||||
ax.set_ylim(0, 6)
|
||||
ax.set_aspect('equal')
|
||||
ax.axis('off')
|
||||
ax.set_title('QoS: At-most-once — „wyślij i zapomnij" (0 lub 1 dostarczenie)',
|
||||
fontsize=FS_TITLE, fontweight='bold', pad=12)
|
||||
|
||||
# Actors
|
||||
px, bx, sx = 1.0, 4.8, 8.5
|
||||
pw, bw, sw = 2.0, 2.2, 2.0
|
||||
bh = 0.8
|
||||
draw_box(ax, px, 5.0, pw, bh, 'Publisher', fill=GRAY1, fontsize=10, fontweight='bold')
|
||||
draw_box(ax, bx, 5.0, bw, bh, 'Broker', fill=GRAY2, fontsize=10, fontweight='bold')
|
||||
draw_box(ax, sx, 5.0, sw, bh, 'Subscriber', fill=GRAY1, fontsize=10, fontweight='bold')
|
||||
|
||||
# Timelines
|
||||
for xc in [px + pw/2, bx + bw/2, sx + sw/2]:
|
||||
ax.plot([xc, xc], [5.0, 1.2], color=GRAY3, lw=1, linestyle=':')
|
||||
|
||||
# Scenario A: success
|
||||
y = 4.3
|
||||
ax.text(0.2, y + 0.15, 'Scenariusz A:', fontsize=8.5, fontweight='bold')
|
||||
draw_arrow(ax, px + pw/2, y, bx + bw/2, y, label='MSG', label_fs=9)
|
||||
draw_arrow(ax, bx + bw/2, y - 0.6, sx + sw/2, y - 0.6, label='MSG', label_fs=9)
|
||||
draw_check(ax, sx + sw/2 + 0.4, y - 0.6, size=0.18)
|
||||
ax.text(sx + sw/2 + 0.7, y - 0.6, 'OK', fontsize=9, fontweight='bold')
|
||||
|
||||
# Scenario B: lost
|
||||
y = 2.6
|
||||
ax.text(0.2, y + 0.15, 'Scenariusz B:', fontsize=8.5, fontweight='bold')
|
||||
draw_arrow(ax, px + pw/2, y, bx + bw/2, y, label='MSG', label_fs=9)
|
||||
draw_dashed_arrow(ax, bx + bw/2, y - 0.6, 7.5, y - 0.6)
|
||||
draw_cross(ax, 7.8, y - 0.6, size=0.2)
|
||||
ax.text(8.2, y - 0.55, 'UTRACONA', fontsize=9, fontweight='bold')
|
||||
ax.text(8.2, y - 1.0, '(brak retransmisji)', fontsize=8, style='italic')
|
||||
|
||||
# Summary
|
||||
ax.text(6.0, 0.5, 'Brak ACK, brak retransmisji. Najszybszy. Use case: logi, metryki, telemetria.',
|
||||
ha='center', va='center', fontsize=9,
|
||||
bbox=dict(boxstyle='round,pad=0.4', facecolor=GRAY4, edgecolor=GRAY3))
|
||||
|
||||
save(fig, 'pubsub_qos_at_most_once.png')
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 6. At-least-once (QoS 1)
|
||||
# ============================================================
|
||||
def draw_qos_at_least_once():
|
||||
fig, ax = plt.subplots(1, 1, figsize=(FIG_W, 5.0))
|
||||
ax.set_xlim(0, 12)
|
||||
ax.set_ylim(0, 6.5)
|
||||
ax.set_aspect('equal')
|
||||
ax.axis('off')
|
||||
ax.set_title('QoS: At-least-once — „powtarzaj aż potwierdzą" (≥1 dostarczenie)',
|
||||
fontsize=FS_TITLE, fontweight='bold', pad=12)
|
||||
|
||||
bx, bw = 3.5, 2.2
|
||||
sx, sw = 8.0, 2.2
|
||||
bh = 0.8
|
||||
draw_box(ax, bx, 5.5, bw, bh, 'Broker', fill=GRAY2, fontsize=10, fontweight='bold')
|
||||
draw_box(ax, sx, 5.5, sw, bh, 'Subscriber', fill=GRAY1, fontsize=10, fontweight='bold')
|
||||
|
||||
# Timelines
|
||||
for xc in [bx + bw/2, sx + sw/2]:
|
||||
ax.plot([xc, xc], [5.5, 0.8], color=GRAY3, lw=1, linestyle=':')
|
||||
|
||||
# Step 1: send MSG
|
||||
y1 = 4.8
|
||||
draw_arrow(ax, bx + bw/2, y1, sx + sw/2, y1, label='MSG #1', label_fs=9)
|
||||
draw_check(ax, sx + sw + 0.2, y1, size=0.15)
|
||||
ax.text(sx + sw + 0.5, y1, 'odebrano', fontsize=8)
|
||||
|
||||
# Step 2: ACK lost
|
||||
y2 = 3.9
|
||||
draw_dashed_arrow(ax, sx + sw/2, y2, bx + bw + 1.2, y2)
|
||||
ax.text((bx + bw/2 + sx + sw/2)/2, y2 + 0.18, 'ACK', fontsize=9)
|
||||
draw_cross(ax, bx + bw + 0.8, y2, size=0.18)
|
||||
ax.text(bx + 0.3, y2 - 0.35, 'ACK utracony!', fontsize=8.5, style='italic')
|
||||
|
||||
# Step 3: timeout → retry
|
||||
y3 = 2.9
|
||||
ax.text(bx + bw/2, y3 + 0.45, 'timeout...', fontsize=8.5, style='italic', ha='center')
|
||||
draw_arrow(ax, bx + bw/2, y3, sx + sw/2, y3, label='MSG #1 (retry)', label_fs=9)
|
||||
draw_check(ax, sx + sw + 0.2, y3, size=0.15)
|
||||
ax.text(sx + sw + 0.5, y3, 'odebrano\n(ponownie!)', fontsize=8)
|
||||
|
||||
# Step 4: ACK ok
|
||||
y4 = 2.0
|
||||
draw_arrow(ax, sx + sw/2, y4, bx + bw/2, y4, label='ACK', label_fs=9)
|
||||
draw_check(ax, bx + bw/2 - 0.5, y4, size=0.18)
|
||||
|
||||
# Duplicate bracket
|
||||
ax.annotate('', xy=(sx + sw + 1.3, y1), xytext=(sx + sw + 1.3, y3),
|
||||
arrowprops=dict(arrowstyle='<->', color='black', lw=1.2))
|
||||
ax.text(sx + sw + 1.6, (y1 + y3)/2, 'DUPLIKAT!\nSubscriber\notrzymał 2×',
|
||||
fontsize=9, ha='left', va='center', fontweight='bold',
|
||||
bbox=dict(boxstyle='round,pad=0.25', facecolor=GRAY4, edgecolor=GRAY3))
|
||||
|
||||
# Summary
|
||||
ax.text(6.0, 0.5, 'Broker czeka na ACK, retransmituje po timeout. Mogą być duplikaty!\n'
|
||||
'Use case: zamówienia, płatności (subscriber musi być idempotentny).',
|
||||
ha='center', va='center', fontsize=9,
|
||||
bbox=dict(boxstyle='round,pad=0.4', facecolor=GRAY4, edgecolor=GRAY3))
|
||||
|
||||
save(fig, 'pubsub_qos_at_least_once.png')
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 7. Exactly-once (QoS 2)
|
||||
# ============================================================
|
||||
def draw_qos_exactly_once():
|
||||
fig, ax = plt.subplots(1, 1, figsize=(FIG_W, 5.5))
|
||||
ax.set_xlim(0, 12)
|
||||
ax.set_ylim(0, 7)
|
||||
ax.set_aspect('equal')
|
||||
ax.axis('off')
|
||||
ax.set_title('QoS: Exactly-once — 4-krokowy handshake (dokładnie 1 dostarczenie)',
|
||||
fontsize=FS_TITLE, fontweight='bold', pad=12)
|
||||
|
||||
bx, bw = 2.5, 2.2
|
||||
sx, sw = 7.5, 2.2
|
||||
bh = 0.8
|
||||
draw_box(ax, bx, 6.0, bw, bh, 'Broker', fill=GRAY2, fontsize=10, fontweight='bold')
|
||||
draw_box(ax, sx, 6.0, sw, bh, 'Subscriber', fill=GRAY1, fontsize=10, fontweight='bold')
|
||||
|
||||
# Timelines
|
||||
for xc in [bx + bw/2, sx + sw/2]:
|
||||
ax.plot([xc, xc], [6.0, 1.0], color=GRAY3, lw=1, linestyle=':')
|
||||
|
||||
# 4-step handshake
|
||||
steps = [
|
||||
(5.2, 'right', 'PUBLISH (msg_id=42)', 'Broker wysyła wiadomość'),
|
||||
(4.2, 'left', 'PUBREC (otrzymałem id=42)', 'Sub potwierdza odbiór, zapisuje id'),
|
||||
(3.2, 'right', 'PUBREL (możesz przetworzyć)', 'Broker zwalnia wiadomość'),
|
||||
(2.2, 'left', 'PUBCOMP (zakończone)', 'Sub potwierdza przetworzenie'),
|
||||
]
|
||||
|
||||
for i, (y, direction, label, desc) in enumerate(steps):
|
||||
# Step number
|
||||
ax.text(bx + bw/2 - 0.7, y, f'{i+1}', fontsize=9,
|
||||
fontweight='bold', ha='center', va='center',
|
||||
bbox=dict(boxstyle='circle,pad=0.18', facecolor=GRAY3, edgecolor=LN))
|
||||
|
||||
if direction == 'right':
|
||||
draw_arrow(ax, bx + bw/2, y, sx + sw/2, y, label=label, label_fs=9)
|
||||
else:
|
||||
draw_arrow(ax, sx + sw/2, y, bx + bw/2, y, label=label, label_fs=9)
|
||||
|
||||
# Side description
|
||||
ax.text(sx + sw + 0.3, y, desc, fontsize=8, ha='left', va='center', style='italic')
|
||||
|
||||
# Summary
|
||||
ax.text(6.0, 0.6, 'Deduplikacja po msg_id. Sub nie przetwarza przed PUBREL.\n'
|
||||
'Najkosztowniejszy (4 pakiety). Use case: transakcje finansowe, krytyczne zdarzenia.',
|
||||
ha='center', va='center', fontsize=9,
|
||||
bbox=dict(boxstyle='round,pad=0.4', facecolor=GRAY4, edgecolor=GRAY3))
|
||||
|
||||
save(fig, 'pubsub_qos_exactly_once.png')
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Main
|
||||
# ============================================================
|
||||
if __name__ == '__main__':
|
||||
print("Generating Pub/Sub diagrams (7 separate images)...")
|
||||
draw_sub_topic()
|
||||
draw_sub_content()
|
||||
draw_sub_type()
|
||||
draw_sub_hierarchical()
|
||||
draw_qos_at_most_once()
|
||||
draw_qos_at_least_once()
|
||||
draw_qos_exactly_once()
|
||||
print("Done!")
|
||||
558
pytania/generate_robot_lang_diagrams.py
Normal file
@ -0,0 +1,558 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Generate diagrams for PYTANIE 16: Języki programowania robotów.
|
||||
A4-compatible, B&W, 300 DPI, laser-printer-friendly.
|
||||
|
||||
Diagrams:
|
||||
1. T-R-M-S abstraction pyramid
|
||||
2. Vendor languages comparison chart
|
||||
3. Robot movement types (PTP, LIN, CIRC)
|
||||
4. Online vs Offline programming flowchart
|
||||
5. ROS architecture (pub/sub nodes)
|
||||
"""
|
||||
|
||||
import matplotlib
|
||||
matplotlib.use('Agg')
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.patches as mpatches
|
||||
from matplotlib.patches import FancyBboxPatch, FancyArrowPatch
|
||||
import numpy as np
|
||||
import os
|
||||
|
||||
DPI = 300
|
||||
BG = 'white'
|
||||
LN = 'black'
|
||||
FS = 8
|
||||
FS_TITLE = 11
|
||||
OUTPUT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'img')
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
|
||||
GRAY1 = '#E8E8E8'
|
||||
GRAY2 = '#D0D0D0'
|
||||
GRAY3 = '#B8B8B8'
|
||||
GRAY4 = '#F5F5F5'
|
||||
GRAY5 = '#C0C0C0'
|
||||
WHITE = 'white'
|
||||
|
||||
|
||||
def draw_box(ax, x, y, w, h, text, fill='white', lw=1.2, fontsize=FS,
|
||||
fontweight='normal', ha='center', va='center', rounded=True):
|
||||
if rounded:
|
||||
rect = FancyBboxPatch((x, y), w, h, boxstyle="round,pad=0.05",
|
||||
lw=lw, edgecolor=LN, facecolor=fill)
|
||||
else:
|
||||
rect = mpatches.Rectangle((x, y), w, h, lw=lw, edgecolor=LN, facecolor=fill)
|
||||
ax.add_patch(rect)
|
||||
ax.text(x + w/2, y + h/2, text, ha=ha, va=va, fontsize=fontsize,
|
||||
fontweight=fontweight, wrap=True)
|
||||
|
||||
|
||||
def draw_arrow(ax, x1, y1, x2, y2, lw=1.2, style='->', color=LN):
|
||||
ax.annotate("", xy=(x2, y2), xytext=(x1, y1),
|
||||
arrowprops=dict(arrowstyle=style, color=color, lw=lw))
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 1. T-R-M-S Abstraction Pyramid
|
||||
# ============================================================
|
||||
def draw_trms_pyramid():
|
||||
fig, ax = plt.subplots(1, 1, figsize=(8.27, 5.5))
|
||||
ax.set_xlim(0, 10)
|
||||
ax.set_ylim(0, 8)
|
||||
ax.set_aspect('equal')
|
||||
ax.axis('off')
|
||||
ax.set_title('Poziomy abstrakcji języków programowania robotów (T-R-M-S)',
|
||||
fontsize=FS_TITLE, fontweight='bold', pad=10)
|
||||
|
||||
# Pyramid layers (bottom to top)
|
||||
layers = [
|
||||
# (y, left_x, right_x, label, sublabel, fill, examples, timing)
|
||||
(0.5, 1.0, 9.0, 'SERVO-LEVEL', 'Sterowanie silnikami',
|
||||
GRAY3, 'C/C++, FPGA, VHDL\nPID, PWM', '~1 ms'),
|
||||
(2.0, 1.8, 8.2, 'MOTION-LEVEL', 'Planowanie trajektorii',
|
||||
GRAY2, 'MoveIt, OMPL\nIK, collision avoidance', '~20 ms'),
|
||||
(3.5, 2.6, 7.4, 'ROBOT-LEVEL', 'Komendy ruchu',
|
||||
GRAY1, 'RAPID, KRL, Karel\nPDL2, URScript, ROS', '~100 ms'),
|
||||
(5.0, 3.4, 6.6, 'TASK-LEVEL', 'Opis celu',
|
||||
GRAY4, 'PDDL, BT, STRIPS\nplanowanie AI', '~sekundy'),
|
||||
]
|
||||
|
||||
h = 1.3
|
||||
for y, lx, rx, label, sublabel, fill, examples, timing in layers:
|
||||
w = rx - lx
|
||||
# Draw trapezoid
|
||||
trap = plt.Polygon([
|
||||
(lx, y), (rx, y),
|
||||
(rx - 0.4, y + h), (lx + 0.4, y + h)
|
||||
], closed=True, facecolor=fill, edgecolor=LN, lw=1.5)
|
||||
ax.add_patch(trap)
|
||||
|
||||
# Label
|
||||
ax.text((lx + rx) / 2, y + h * 0.65, label,
|
||||
ha='center', va='center', fontsize=9, fontweight='bold')
|
||||
ax.text((lx + rx) / 2, y + h * 0.35, sublabel,
|
||||
ha='center', va='center', fontsize=7, style='italic')
|
||||
|
||||
# Examples - right side
|
||||
ax.text(rx + 0.2, y + h * 0.5, examples,
|
||||
ha='left', va='center', fontsize=6.5, color='#333333')
|
||||
|
||||
# Timing - left side
|
||||
ax.text(lx - 0.2, y + h * 0.5, timing,
|
||||
ha='right', va='center', fontsize=7, fontweight='bold',
|
||||
color='#333333')
|
||||
|
||||
# Arrow on left
|
||||
ax.annotate('', xy=(0.5, 6.2), xytext=(0.5, 0.8),
|
||||
arrowprops=dict(arrowstyle='->', color='black', lw=2))
|
||||
ax.text(0.5, 3.5, 'Abstrakcja\nrośnie',
|
||||
ha='center', va='center', fontsize=7, rotation=90,
|
||||
fontweight='bold')
|
||||
|
||||
# Arrow on right side for timing
|
||||
ax.annotate('', xy=(9.7, 0.8), xytext=(9.7, 6.2),
|
||||
arrowprops=dict(arrowstyle='->', color='black', lw=2))
|
||||
ax.text(9.7, 3.5, 'Szybkość\nreakcji',
|
||||
ha='center', va='center', fontsize=7, rotation=270,
|
||||
fontweight='bold')
|
||||
|
||||
# Mnemonic at bottom
|
||||
ax.text(5.0, 0.0, 'Mnemonik: „Tomek Robi Mechaniczne Serwa" (T→R→M→S, od góry do dołu)',
|
||||
ha='center', va='center', fontsize=7, style='italic',
|
||||
bbox=dict(boxstyle='round,pad=0.3', facecolor=GRAY4, edgecolor=LN, lw=0.8))
|
||||
|
||||
fig.tight_layout()
|
||||
fig.savefig(os.path.join(OUTPUT_DIR, 'robot_trms_pyramid.png'), dpi=DPI,
|
||||
bbox_inches='tight', facecolor=BG)
|
||||
plt.close(fig)
|
||||
print(" ✓ robot_trms_pyramid.png")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 2. Vendor Languages Comparison
|
||||
# ============================================================
|
||||
def draw_vendor_comparison():
|
||||
fig, ax = plt.subplots(1, 1, figsize=(8.27, 5))
|
||||
ax.set_xlim(0, 10)
|
||||
ax.set_ylim(0, 7.5)
|
||||
ax.axis('off')
|
||||
ax.set_title('Języki producentów robotów — porównanie',
|
||||
fontsize=FS_TITLE, fontweight='bold', pad=10)
|
||||
|
||||
# Table headers
|
||||
headers = ['Cecha', 'RAPID\n(ABB)', 'KRL\n(KUKA)', 'Karel\n(FANUC)', 'PDL2\n(Comau)', 'URScript\n(UR)']
|
||||
col_widths = [1.8, 1.6, 1.6, 1.6, 1.6, 1.6]
|
||||
col_x = [0.1]
|
||||
for w in col_widths[:-1]:
|
||||
col_x.append(col_x[-1] + w)
|
||||
|
||||
row_h = 0.7
|
||||
header_y = 6.3
|
||||
rows = [
|
||||
['Składnia', 'typ własny\nstrukturalna', 'Pascal-like\nstrukturalna', 'Pascal-like\nstrukturalna', 'proceduralna\nC-like', 'Python-like\nskryptowy'],
|
||||
['Ruch liniowy', 'MoveL', 'LIN', 'MOVE TO\nw/LINEAR', 'MOVE\nLINEAR TO', 'movel()'],
|
||||
['Ruch joint', 'MoveJ', 'PTP', 'MOVE TO', 'MOVE TO', 'movej()'],
|
||||
['Ruch kołowy', 'MoveC', 'CIRC', '(brak\nwbudow.)', 'MOVE\nCIRCULAR', 'movec()'],
|
||||
['I/O', 'SetDO/\nWaitDI', 'OUT/IN', 'DOUT/DIN', 'OUT/IN', 'set_digital\n_out()'],
|
||||
['Zmienne', 'num, robtarget\nstring, bool', 'INT, REAL\nPOS, E6POS', 'INTEGER\nPOSITION', 'INTEGER\nPOSITION', 'int, float\npose'],
|
||||
['Symulator', 'RobotStudio', 'KUKA.Sim', 'ROBOGUIDE', 'RoboSim', 'URSim\n(darmowy)'],
|
||||
]
|
||||
|
||||
# Draw header row
|
||||
for j, (hdr, w) in enumerate(zip(headers, col_widths)):
|
||||
x = col_x[j]
|
||||
fill = GRAY2 if j == 0 else GRAY1
|
||||
draw_box(ax, x, header_y, w - 0.05, row_h, hdr, fill=fill,
|
||||
fontsize=7, fontweight='bold', rounded=False)
|
||||
|
||||
# Draw data rows
|
||||
for i, row in enumerate(rows):
|
||||
y = header_y - (i + 1) * row_h
|
||||
for j, (cell, w) in enumerate(zip(row, col_widths)):
|
||||
x = col_x[j]
|
||||
fill = GRAY4 if j == 0 else (WHITE if i % 2 == 0 else GRAY4)
|
||||
fw = 'bold' if j == 0 else 'normal'
|
||||
draw_box(ax, x, y, w - 0.05, row_h - 0.02, cell, fill=fill,
|
||||
fontsize=6, fontweight=fw, rounded=False)
|
||||
|
||||
# Note
|
||||
ax.text(5.0, 0.5, 'Vendor lock-in: program w RAPID ≠ działa na KUKA. '
|
||||
'ROS/ROS 2 jako warstwa unifikująca.',
|
||||
ha='center', va='center', fontsize=7, style='italic',
|
||||
bbox=dict(boxstyle='round,pad=0.3', facecolor=GRAY4, edgecolor=LN, lw=0.8))
|
||||
|
||||
fig.tight_layout()
|
||||
fig.savefig(os.path.join(OUTPUT_DIR, 'robot_vendor_comparison.png'), dpi=DPI,
|
||||
bbox_inches='tight', facecolor=BG)
|
||||
plt.close(fig)
|
||||
print(" ✓ robot_vendor_comparison.png")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 3. Robot Movement Types (PTP, LIN, CIRC)
|
||||
# ============================================================
|
||||
def draw_movement_types():
|
||||
fig, axes = plt.subplots(1, 3, figsize=(8.27, 3.2))
|
||||
fig.suptitle('Typy ruchu robota: PTP, LIN, CIRC',
|
||||
fontsize=FS_TITLE, fontweight='bold', y=0.98)
|
||||
|
||||
# --- PTP (Point-to-Point) ---
|
||||
ax = axes[0]
|
||||
ax.set_xlim(-0.5, 4.5)
|
||||
ax.set_ylim(-0.5, 4.5)
|
||||
ax.set_aspect('equal')
|
||||
ax.set_title('PTP (Point-to-Point)\nMoveJ / PTP', fontsize=8, fontweight='bold')
|
||||
ax.grid(True, alpha=0.3)
|
||||
|
||||
# Start and end
|
||||
start = (0.5, 0.5)
|
||||
end = (3.5, 3.5)
|
||||
ax.plot(*start, 'ko', ms=10, zorder=5)
|
||||
ax.plot(*end, 'ks', ms=10, zorder=5)
|
||||
ax.text(start[0] - 0.3, start[1] - 0.3, 'Start', fontsize=7, ha='center')
|
||||
ax.text(end[0] + 0.3, end[1] + 0.3, 'Cel', fontsize=7, ha='center')
|
||||
|
||||
# Curved path (joint space = not necessarily straight in Cartesian)
|
||||
t = np.linspace(0, 1, 50)
|
||||
x_ptp = start[0] + (end[0] - start[0]) * t + 0.8 * np.sin(np.pi * t)
|
||||
y_ptp = start[1] + (end[1] - start[1]) * t - 0.3 * np.sin(np.pi * t)
|
||||
ax.plot(x_ptp, y_ptp, 'k-', lw=2)
|
||||
ax.annotate('', xy=(x_ptp[-1], y_ptp[-1]), xytext=(x_ptp[-3], y_ptp[-3]),
|
||||
arrowprops=dict(arrowstyle='->', color='black', lw=2))
|
||||
|
||||
ax.text(2.8, 1.2, 'Ścieżka\nw kartezjańskiej\nnieokreślona!', fontsize=6,
|
||||
ha='center', style='italic',
|
||||
bbox=dict(boxstyle='round', facecolor=GRAY4, edgecolor=GRAY5))
|
||||
ax.text(2.0, -0.3, 'Najszybszy, ale\nścieżka nieprzewidywalna', fontsize=6,
|
||||
ha='center', style='italic')
|
||||
ax.set_xlabel('')
|
||||
ax.set_ylabel('')
|
||||
ax.tick_params(labelsize=6)
|
||||
|
||||
# --- LIN (Linear) ---
|
||||
ax = axes[1]
|
||||
ax.set_xlim(-0.5, 4.5)
|
||||
ax.set_ylim(-0.5, 4.5)
|
||||
ax.set_aspect('equal')
|
||||
ax.set_title('LIN (Linear)\nMoveL / LIN', fontsize=8, fontweight='bold')
|
||||
ax.grid(True, alpha=0.3)
|
||||
|
||||
start = (0.5, 1.0)
|
||||
end = (3.5, 3.5)
|
||||
ax.plot(*start, 'ko', ms=10, zorder=5)
|
||||
ax.plot(*end, 'ks', ms=10, zorder=5)
|
||||
ax.text(start[0] - 0.3, start[1] - 0.3, 'Start', fontsize=7, ha='center')
|
||||
ax.text(end[0] + 0.3, end[1] + 0.3, 'Cel', fontsize=7, ha='center')
|
||||
|
||||
# Straight line
|
||||
ax.plot([start[0], end[0]], [start[1], end[1]], 'k-', lw=2)
|
||||
ax.annotate('', xy=end, xytext=(start[0] + 0.9*(end[0]-start[0]),
|
||||
start[1] + 0.9*(end[1]-start[1])),
|
||||
arrowprops=dict(arrowstyle='->', color='black', lw=2))
|
||||
|
||||
# Show intermediate points
|
||||
for frac in [0.25, 0.5, 0.75]:
|
||||
px = start[0] + frac * (end[0] - start[0])
|
||||
py = start[1] + frac * (end[1] - start[1])
|
||||
ax.plot(px, py, 'k.', ms=6)
|
||||
|
||||
ax.text(2.0, -0.3, 'Prosta linia TCP\nIK w każdym punkcie', fontsize=6,
|
||||
ha='center', style='italic')
|
||||
ax.tick_params(labelsize=6)
|
||||
|
||||
# --- CIRC (Circular) ---
|
||||
ax = axes[2]
|
||||
ax.set_xlim(-0.5, 4.5)
|
||||
ax.set_ylim(-0.5, 4.5)
|
||||
ax.set_aspect('equal')
|
||||
ax.set_title('CIRC (Circular)\nMoveC / CIRC', fontsize=8, fontweight='bold')
|
||||
ax.grid(True, alpha=0.3)
|
||||
|
||||
# Arc through 3 points
|
||||
center = (2.0, 1.5)
|
||||
r = 2.0
|
||||
theta_start = np.radians(20)
|
||||
theta_end = np.radians(160)
|
||||
theta = np.linspace(theta_start, theta_end, 50)
|
||||
x_circ = center[0] + r * np.cos(theta)
|
||||
y_circ = center[1] + r * np.sin(theta)
|
||||
|
||||
ax.plot(x_circ, y_circ, 'k-', lw=2)
|
||||
ax.annotate('', xy=(x_circ[-1], y_circ[-1]), xytext=(x_circ[-3], y_circ[-3]),
|
||||
arrowprops=dict(arrowstyle='->', color='black', lw=2))
|
||||
|
||||
# Start, auxiliary, end points
|
||||
ax.plot(x_circ[0], y_circ[0], 'ko', ms=10, zorder=5)
|
||||
ax.plot(x_circ[24], y_circ[24], 'k^', ms=8, zorder=5)
|
||||
ax.plot(x_circ[-1], y_circ[-1], 'ks', ms=10, zorder=5)
|
||||
ax.text(x_circ[0] + 0.3, y_circ[0] - 0.3, 'Start', fontsize=7)
|
||||
ax.text(x_circ[24] + 0.05, y_circ[24] + 0.25, 'Pkt\npomocniczy', fontsize=6, ha='center')
|
||||
ax.text(x_circ[-1] - 0.5, y_circ[-1] - 0.3, 'Cel', fontsize=7)
|
||||
|
||||
# Center
|
||||
ax.plot(*center, 'k+', ms=8, mew=1.5)
|
||||
ax.text(center[0], center[1] - 0.3, 'środek', fontsize=6, ha='center')
|
||||
|
||||
ax.text(2.0, -0.3, 'Łuk wyznaczony\nprzez 3 punkty', fontsize=6,
|
||||
ha='center', style='italic')
|
||||
ax.tick_params(labelsize=6)
|
||||
|
||||
fig.tight_layout()
|
||||
fig.savefig(os.path.join(OUTPUT_DIR, 'robot_movement_types.png'), dpi=DPI,
|
||||
bbox_inches='tight', facecolor=BG)
|
||||
plt.close(fig)
|
||||
print(" ✓ robot_movement_types.png")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 4. Online vs Offline Programming
|
||||
# ============================================================
|
||||
def draw_online_offline():
|
||||
fig, ax = plt.subplots(1, 1, figsize=(8.27, 4.5))
|
||||
ax.set_xlim(0, 10)
|
||||
ax.set_ylim(0, 6.5)
|
||||
ax.set_aspect('equal')
|
||||
ax.axis('off')
|
||||
ax.set_title('Programowanie robotów: Online (teach-in) vs Offline',
|
||||
fontsize=FS_TITLE, fontweight='bold', pad=10)
|
||||
|
||||
# === ONLINE side (left) ===
|
||||
# Title
|
||||
draw_box(ax, 0.3, 5.2, 4.2, 0.8, 'ONLINE\n(teach-in / pendant)',
|
||||
fill=GRAY2, fontsize=9, fontweight='bold')
|
||||
|
||||
steps_online = [
|
||||
(4.2, 'Operator przy robocie\nz teach pendantem'),
|
||||
(3.2, 'Prowadzi ramię\n„za rękę" do punktów'),
|
||||
(2.2, 'Robot zapamiętuje\npozycje (record)'),
|
||||
(1.2, 'Odtwarzanie\nzapisanej ścieżki'),
|
||||
]
|
||||
for y, txt in steps_online:
|
||||
draw_box(ax, 0.5, y, 3.8, 0.8, txt, fill=WHITE, fontsize=7)
|
||||
|
||||
for i in range(len(steps_online) - 1):
|
||||
draw_arrow(ax, 2.4, steps_online[i][0], 2.4, steps_online[i+1][0] + 0.8)
|
||||
|
||||
# Pros/cons
|
||||
ax.text(2.4, 0.6, '✓ Proste, intuicyjne\n✗ Wymaga zatrzymania produkcji\n✗ Niska precyzja',
|
||||
ha='center', va='center', fontsize=6.5,
|
||||
bbox=dict(boxstyle='round', facecolor=GRAY4, edgecolor=GRAY5, lw=0.8))
|
||||
|
||||
# Divider
|
||||
ax.plot([4.9, 4.9], [0.3, 6.2], 'k--', lw=1, alpha=0.5)
|
||||
|
||||
# === OFFLINE side (right) ===
|
||||
draw_box(ax, 5.3, 5.2, 4.2, 0.8, 'OFFLINE\n(symulacja / CAD/CAM)',
|
||||
fill=GRAY2, fontsize=9, fontweight='bold')
|
||||
|
||||
steps_offline = [
|
||||
(4.2, 'Model 3D robota +\nśrodowisko w symulatorze'),
|
||||
(3.2, 'Programowanie ścieżek\nw środowisku wirtualnym'),
|
||||
(2.2, 'Weryfikacja kolizji\ni optymalizacja'),
|
||||
(1.2, 'Transfer na\nrzeczywistego robota'),
|
||||
]
|
||||
for y, txt in steps_offline:
|
||||
draw_box(ax, 5.5, y, 3.8, 0.8, txt, fill=WHITE, fontsize=7)
|
||||
|
||||
for i in range(len(steps_offline) - 1):
|
||||
draw_arrow(ax, 7.4, steps_offline[i][0], 7.4, steps_offline[i+1][0] + 0.8)
|
||||
|
||||
ax.text(7.4, 0.6, '✓ Bez zatrzymania produkcji\n✓ Wysoka precyzja, symulacja\n✗ Wymaga kalibracji',
|
||||
ha='center', va='center', fontsize=6.5,
|
||||
bbox=dict(boxstyle='round', facecolor=GRAY4, edgecolor=GRAY5, lw=0.8))
|
||||
|
||||
fig.tight_layout()
|
||||
fig.savefig(os.path.join(OUTPUT_DIR, 'robot_online_offline.png'), dpi=DPI,
|
||||
bbox_inches='tight', facecolor=BG)
|
||||
plt.close(fig)
|
||||
print(" ✓ robot_online_offline.png")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 5. ROS Architecture (pub/sub)
|
||||
# ============================================================
|
||||
def draw_ros_architecture():
|
||||
fig, ax = plt.subplots(1, 1, figsize=(8.27, 4.5))
|
||||
ax.set_xlim(0, 10)
|
||||
ax.set_ylim(0, 6.5)
|
||||
ax.set_aspect('equal')
|
||||
ax.axis('off')
|
||||
ax.set_title('ROS — architektura publish/subscribe',
|
||||
fontsize=FS_TITLE, fontweight='bold', pad=10)
|
||||
|
||||
# Nodes
|
||||
nodes = [
|
||||
(1.0, 4.5, 'Czujnik\n(LiDAR)', GRAY1),
|
||||
(1.0, 2.5, 'Kamera\n(RGB-D)', GRAY1),
|
||||
(4.0, 4.5, 'Lokalizacja\n(SLAM)', GRAY4),
|
||||
(4.0, 2.5, 'Percepcja\n(detekcja)', GRAY4),
|
||||
(7.0, 3.5, 'Planowanie\nruchu (MoveIt)', GRAY2),
|
||||
(7.0, 1.0, 'Sterownik\nsilników', GRAY3),
|
||||
]
|
||||
|
||||
for x, y, txt, fill in nodes:
|
||||
draw_box(ax, x, y, 2.2, 1.0, txt, fill=fill, fontsize=7, fontweight='bold')
|
||||
|
||||
# Topics (arrows with labels)
|
||||
topics = [
|
||||
# (from_x, from_y, to_x, to_y, label)
|
||||
(3.2, 5.0, 4.0, 5.0, '/scan'),
|
||||
(3.2, 3.0, 4.0, 3.0, '/image'),
|
||||
(6.2, 5.0, 7.0, 4.3, '/pose'),
|
||||
(6.2, 3.0, 7.0, 3.8, '/objects'),
|
||||
(8.0, 3.5, 8.0, 2.0, '/cmd_vel'),
|
||||
]
|
||||
|
||||
for x1, y1, x2, y2, label in topics:
|
||||
draw_arrow(ax, x1, y1, x2, y2, lw=1.5)
|
||||
mx, my = (x1 + x2) / 2, (y1 + y2) / 2
|
||||
ax.text(mx, my + 0.2, label, ha='center', va='bottom', fontsize=6,
|
||||
fontweight='bold', style='italic',
|
||||
bbox=dict(boxstyle='round,pad=0.15', facecolor=WHITE,
|
||||
edgecolor=GRAY5, lw=0.5))
|
||||
|
||||
# ROS Master / roscore
|
||||
draw_box(ax, 3.5, 0.3, 3.0, 0.8, 'ROS Master (roscore)\nRejestr węzłów i tematów',
|
||||
fill=GRAY2, fontsize=7, fontweight='bold')
|
||||
|
||||
# Dashed lines to master
|
||||
for x, y, _, _ in nodes[:4]:
|
||||
ax.plot([x + 1.1, 5.0], [y, 1.1], 'k:', lw=0.5, alpha=0.4)
|
||||
|
||||
# Legend
|
||||
ax.text(0.3, 0.8, 'Węzeł (Node) = proces\n'
|
||||
'Temat (Topic) = kanał pub/sub\n'
|
||||
'Wiadomość = typowany komunikat',
|
||||
ha='left', va='center', fontsize=6,
|
||||
bbox=dict(boxstyle='round', facecolor=GRAY4, edgecolor=LN, lw=0.8))
|
||||
|
||||
fig.tight_layout()
|
||||
fig.savefig(os.path.join(OUTPUT_DIR, 'robot_ros_architecture.png'), dpi=DPI,
|
||||
bbox_inches='tight', facecolor=BG)
|
||||
plt.close(fig)
|
||||
print(" ✓ robot_ros_architecture.png")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 6. RAPID program structure example
|
||||
# ============================================================
|
||||
def draw_rapid_structure():
|
||||
fig, ax = plt.subplots(1, 1, figsize=(8.27, 5.5))
|
||||
ax.set_xlim(0, 10)
|
||||
ax.set_ylim(0, 8)
|
||||
ax.axis('off')
|
||||
ax.set_title('Struktura programu RAPID (ABB) — przykład pick & place',
|
||||
fontsize=FS_TITLE, fontweight='bold', pad=10)
|
||||
|
||||
# Program structure blocks
|
||||
y = 7.0
|
||||
blocks = [
|
||||
('MODULE MainModule', GRAY2, 0.5, 9.0, [
|
||||
('! Deklaracja danych', GRAY4, 1.0, 8.5, [
|
||||
'CONST robtarget pHome := [...];',
|
||||
'CONST robtarget pPick := [...];',
|
||||
'CONST robtarget pPlace := [...];',
|
||||
'VAR num nCycles := 0;',
|
||||
]),
|
||||
('PROC main()', GRAY1, 1.0, 8.5, [
|
||||
'MoveJ pHome, v1000, z50, tool1;',
|
||||
'WHILE TRUE DO',
|
||||
' PickPart;',
|
||||
' PlacePart;',
|
||||
' Incr nCycles;',
|
||||
'ENDWHILE',
|
||||
]),
|
||||
('PROC PickPart()', GRAY1, 1.0, 8.5, [
|
||||
'MoveL Offs(pPick,0,0,50), v500, z10, tool1;',
|
||||
'MoveL pPick, v100, fine, tool1;',
|
||||
'SetDO doGripper, 1; ! zamknij chwytak',
|
||||
'WaitTime 0.5;',
|
||||
'MoveL Offs(pPick,0,0,50), v500, z10, tool1;',
|
||||
]),
|
||||
]),
|
||||
]
|
||||
|
||||
# Simplified: just draw code blocks
|
||||
code_sections = [
|
||||
('Deklaracje danych (stałe, zmienne)', GRAY4, [
|
||||
'CONST robtarget pHome := [[500,0,600],[1,0,0,0],...];',
|
||||
'CONST robtarget pPick := [[400,200,100],[1,0,0,0],...];',
|
||||
'CONST robtarget pPlace := [[400,-200,100],[1,0,0,0],...];',
|
||||
'VAR num nCycles := 0;',
|
||||
'PERS tooldata tGripper := [...];',
|
||||
]),
|
||||
('Procedura główna: main()', GRAY1, [
|
||||
'PROC main()',
|
||||
' MoveJ pHome, v1000, z50, tGripper;',
|
||||
' WHILE TRUE DO',
|
||||
' PickPart;',
|
||||
' PlacePart;',
|
||||
' Incr nCycles;',
|
||||
' ENDWHILE',
|
||||
'ENDPROC',
|
||||
]),
|
||||
('Podprocedura: PickPart()', GRAY1, [
|
||||
'PROC PickPart()',
|
||||
' MoveL Offs(pPick,0,0,50), v500, z10, tGripper;',
|
||||
' MoveL pPick, v100, fine, tGripper;',
|
||||
' SetDO doGripper, 1; ! zamknij chwytak',
|
||||
' WaitTime 0.5;',
|
||||
' MoveL Offs(pPick,0,0,50), v500, z10, tGripper;',
|
||||
'ENDPROC',
|
||||
]),
|
||||
]
|
||||
|
||||
y_cur = 7.2
|
||||
for title, fill, lines in code_sections:
|
||||
h = 0.25 * len(lines) + 0.5
|
||||
# Title bar
|
||||
draw_box(ax, 0.5, y_cur - 0.35, 9.0, 0.35, title, fill=fill,
|
||||
fontsize=7, fontweight='bold', rounded=False)
|
||||
y_cur -= 0.35
|
||||
|
||||
# Code lines
|
||||
for i, line in enumerate(lines):
|
||||
y_cur -= 0.25
|
||||
ax.text(0.7, y_cur + 0.12, line, fontsize=5.5,
|
||||
fontfamily='monospace', va='center')
|
||||
|
||||
# Border around code
|
||||
code_h = 0.25 * len(lines)
|
||||
rect = mpatches.Rectangle((0.5, y_cur - 0.05), 9.0, code_h + 0.15,
|
||||
lw=0.8, edgecolor=GRAY5, facecolor=WHITE,
|
||||
zorder=-1)
|
||||
ax.add_patch(rect)
|
||||
|
||||
y_cur -= 0.3
|
||||
|
||||
# Annotations on right
|
||||
annotations = [
|
||||
(6.5, 'robtarget = pozycja\nkartezjańska + orientacja\n+ konfiguracja ramienia'),
|
||||
(4.5, 'v500 = prędkość 500 mm/s\nz10 = strefa zbliżenia 10mm\nfine = dokładne dojście'),
|
||||
(2.5, 'SetDO = Digital Output\nSterowanie I/O\n(chwytak, zawory)'),
|
||||
]
|
||||
|
||||
for yy, txt in annotations:
|
||||
ax.text(9.8, yy, txt, fontsize=5.5, ha='left', va='center',
|
||||
bbox=dict(boxstyle='round,pad=0.2', facecolor=GRAY4,
|
||||
edgecolor=GRAY5, lw=0.5))
|
||||
|
||||
fig.tight_layout()
|
||||
fig.savefig(os.path.join(OUTPUT_DIR, 'robot_rapid_example.png'), dpi=DPI,
|
||||
bbox_inches='tight', facecolor=BG)
|
||||
plt.close(fig)
|
||||
print(" ✓ robot_rapid_example.png")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Main
|
||||
# ============================================================
|
||||
if __name__ == '__main__':
|
||||
print("Generating PYTANIE 16 diagrams...")
|
||||
draw_trms_pyramid()
|
||||
draw_vendor_comparison()
|
||||
draw_movement_types()
|
||||
draw_online_offline()
|
||||
draw_ros_architecture()
|
||||
draw_rapid_structure()
|
||||
print("Done! All diagrams saved to", OUTPUT_DIR)
|
||||
BIN
pytania/img/agent_3t_architecture.png
Normal file
|
After Width: | Height: | Size: 176 KiB |
BIN
pytania/img/agent_bdi_model.png
Normal file
|
After Width: | Height: | Size: 161 KiB |
BIN
pytania/img/agent_behavior_tree.png
Normal file
|
After Width: | Height: | Size: 164 KiB |
BIN
pytania/img/agent_see_think_act.png
Normal file
|
After Width: | Height: | Size: 163 KiB |
BIN
pytania/img/pubsub_delivery_guarantees.png
Normal file
|
After Width: | Height: | Size: 385 KiB |
BIN
pytania/img/pubsub_qos_at_least_once.png
Normal file
|
After Width: | Height: | Size: 166 KiB |
BIN
pytania/img/pubsub_qos_at_most_once.png
Normal file
|
After Width: | Height: | Size: 128 KiB |
BIN
pytania/img/pubsub_qos_exactly_once.png
Normal file
|
After Width: | Height: | Size: 210 KiB |
BIN
pytania/img/pubsub_sub_content.png
Normal file
|
After Width: | Height: | Size: 192 KiB |
BIN
pytania/img/pubsub_sub_hierarchical.png
Normal file
|
After Width: | Height: | Size: 173 KiB |
BIN
pytania/img/pubsub_sub_topic.png
Normal file
|
After Width: | Height: | Size: 184 KiB |
BIN
pytania/img/pubsub_sub_type.png
Normal file
|
After Width: | Height: | Size: 189 KiB |
BIN
pytania/img/pubsub_subscription_types.png
Normal file
|
After Width: | Height: | Size: 438 KiB |
BIN
pytania/img/q14_catalog_map.png
Normal file
|
After Width: | Height: | Size: 263 KiB |
BIN
pytania/img/q14_pattern_template.png
Normal file
|
After Width: | Height: | Size: 223 KiB |
BIN
pytania/img/q14_three_pillars.png
Normal file
|
After Width: | Height: | Size: 211 KiB |
BIN
pytania/img/robot_movement_types.png
Normal file
|
After Width: | Height: | Size: 138 KiB |
BIN
pytania/img/robot_online_offline.png
Normal file
|
After Width: | Height: | Size: 182 KiB |
BIN
pytania/img/robot_rapid_example.png
Normal file
|
After Width: | Height: | Size: 219 KiB |
BIN
pytania/img/robot_ros_architecture.png
Normal file
|
After Width: | Height: | Size: 149 KiB |
BIN
pytania/img/robot_trms_pyramid.png
Normal file
|
After Width: | Height: | Size: 188 KiB |
BIN
pytania/img/robot_vendor_comparison.png
Normal file
|
After Width: | Height: | Size: 187 KiB |
@ -111,7 +111,236 @@ Poniższe diagramy ilustrują kluczowe frameworki i modele omówione w pytaniu.
|
||||
|
||||
### Jak zapamiętać
|
||||
|
||||
- **TOGAF = JAK** budować architekturę; **Zachman = CO** dokumentować
|
||||
- **C4 = 4 poziomy zoomu** (Context → Container → Component → Code)
|
||||
- **4+1 = LDPP+S** (Logical, Development, Process, Physical + Scenarios)
|
||||
---
|
||||
|
||||
#### 0. LISTA WSZYSTKICH 5 FRAMEWORKÓW
|
||||
|
||||
TOGAF, Zachman, C4, 4+1, ArchiMate
|
||||
|
||||
Mnemonic: **„Tomek Zachował Cztery Ciastka Archimedesowi"**
|
||||
|
||||
T → TOGAF (metodyka — JAK budować)
|
||||
Z → Zachman (taksonomia — CO dokumentować)
|
||||
C4 → C4 Model (4 poziomy zoomu diagramów)
|
||||
C → Cztery+1 (4+1) (5 perspektyw Kruchtena)
|
||||
A → ArchiMate (język/notacja modelowania)
|
||||
|
||||
Podział ról — kto robi co:
|
||||
|
||||
TOGAF = PROCES (jak budować architekturę krok po kroku)
|
||||
Zachman = TAKSONOMIA (co dokumentować — siatka pytań)
|
||||
4+1 = PERSPEKTYWY (kto patrzy na system — 5 widoków)
|
||||
C4 = ZOOM (jak głęboko patrzysz — 4 poziomy)
|
||||
ArchiMate = JĘZYK (jakim językiem rysujesz diagramy)
|
||||
|
||||
Mnemonic ról: **„PTZJZ"** — **„Proces, Taksonomia, Zoom, Jakby-pięć-oczu, Żargon"**
|
||||
|
||||
---
|
||||
|
||||
#### 1. TOGAF — 4 domeny: Business, Data, Application, Technology
|
||||
|
||||
Mnemonic: **„BDAT"** → **„Buduj Domy Ale Tanio"**
|
||||
|
||||
B → Business (procesy organizacji — CO firma robi)
|
||||
D → Data (struktury danych — JAKIE dane)
|
||||
A → Application (aplikacje — CZYM realizujemy)
|
||||
T → Technology (infrastruktura — NA CZYM to stoi)
|
||||
|
||||
Kolejność = od abstrakcji do konkretu:
|
||||
firma → dane → apki → serwery
|
||||
|
||||
---
|
||||
|
||||
#### 2. TOGAF ADM — 8 faz cyklu
|
||||
|
||||
Preliminary → Vision → Business → IS → Technology → Opportunities → Migration → Governance
|
||||
|
||||
Mnemonic: **„PVB-IT-OMG!"**
|
||||
|
||||
P → Preliminary (przygotowanie)
|
||||
V → Vision (wizja architektury)
|
||||
B → Business Arch (architektura biznesowa)
|
||||
I → IS Arch (Information Systems — dane + aplikacje)
|
||||
T → Technology Arch (infrastruktura)
|
||||
O → Opportunities (szanse i rozwiązania)
|
||||
M → Migration (plan migracji)
|
||||
G → Governance (nadzór/zarządzanie)
|
||||
|
||||
Wyobraź sobie: Planujesz wizję biznesu, IT daje możliwości, migrujesz i zarządzasz — **„PVB-IT-OMG!"** (jakbyś krzyknął „OMG!" na koniec projektu)
|
||||
|
||||
---
|
||||
|
||||
#### 3. 4+1 View Model (Kruchten) — 5 widoków
|
||||
|
||||
Logical, Development, Process, Physical + Scenarios
|
||||
|
||||
Mnemonic: **„LoDeProFi + Scenariusz"** albo **„LDPP+S"**
|
||||
|
||||
L → Logical (klasy, moduły — CO system robi)
|
||||
D → Development (pakiety, warstwy — JAK kod zorganizowany)
|
||||
P → Process (współbieżność — JAK przepływają dane)
|
||||
P → Physical (serwery, kontenery — GDZIE wdrożony)
|
||||
S → Scenarios (+1 — use cases łączące wszystko)
|
||||
|
||||
Mnemonic-historia: **„Logik Deweloper Procesuje Fizycznie Scenę"**
|
||||
|
||||
Kto patrzy na który widok — mnemonic par:
|
||||
|
||||
Architekt → Logical „Architekt LOGICZNIE myśli"
|
||||
Programista → Development „Programista DEVELOPUJE"
|
||||
Integrator → Process „Integrator scala PROCESY"
|
||||
Admin → Physical „Admin zarządza FIZYCZNYMI serwerami"
|
||||
Użytkownik → Scenarios „Użytkownik ma SCENARIUSZ użycia"
|
||||
|
||||
---
|
||||
|
||||
#### 4. Zachman — 6 pytań
|
||||
|
||||
What, How, Where, Who, When, Why
|
||||
|
||||
Mnemonic: **„Co Jak Gdzie Kto Kiedy Dlaczego"** → **„CJGKKD"**
|
||||
|
||||
→ **„Co Jan Gotuje? Kurczaka, Kiełbasę i Dynię"**
|
||||
|
||||
Co → What (dane, encje)
|
||||
Jak → How (procesy, funkcje)
|
||||
Gdzie → Where (lokalizacje, sieci)
|
||||
Kto → Who (ludzie, role)
|
||||
Kiedy → When (zdarzenia, cykl)
|
||||
Dlaczego → Why (cele, motywacje)
|
||||
|
||||
Zachman vs TOGAF — klucz: **„Zachman = MAPA (co dokumentować), TOGAF = GPS (jak dojść)"**
|
||||
|
||||
---
|
||||
|
||||
#### 5. C4 Model — 4 poziomy zoomu
|
||||
|
||||
Context → Container → Component → Code
|
||||
|
||||
Mnemonic: **„4 × C = Coraz Ciekawsze Części Codu"**
|
||||
|
||||
C1 → Context (cały system z lotu ptaka — KTO go używa)
|
||||
C2 → Container (zoom: kontenery techniczne — API, DB, SPA)
|
||||
C3 → Component (zoom: moduły wewnątrz kontenera)
|
||||
C4 → Code (zoom: klasy, interfejsy — opcjonalny)
|
||||
|
||||
Wyobraź sobie Google Maps:
|
||||
|
||||
Context = widok kontynentu (cały system w otoczeniu)
|
||||
Container = widok miasta (budynki = kontenery techniczne)
|
||||
Component = widok ulicy (pokoje wewnątrz budynku)
|
||||
Code = widok mebli (detale — klasy, metody)
|
||||
|
||||
---
|
||||
|
||||
#### 6. ArchiMate — 3 warstwy × 3 aspekty
|
||||
|
||||
Warstwy: Business, Application, Technology → **BAT** → **„BATman jest architektem"**
|
||||
|
||||
B → Business (procesy biznesowe)
|
||||
A → Application (aplikacje)
|
||||
T → Technology (infrastruktura)
|
||||
|
||||
Aspekty: Active Structure, Behavior, Passive Structure → **ABP** → **„Aktor Biega Pasywnie"**
|
||||
|
||||
A → Active Structure (KTO działa — aktorzy, komponenty)
|
||||
B → Behavior (CO robi — procesy, usługi)
|
||||
P → Passive Structure (NA CZYM — obiekty danych, artefakty)
|
||||
|
||||
Siatka 3×3 — wyobraź sobie tabelkę:
|
||||
|
||||
Aspekt → Active (KTO) Behavior (CO) Passive (NA CZYM)
|
||||
───────────────────────────────────────────────────────────────
|
||||
Business aktor bizn. proces bizn. obiekt bizn.
|
||||
Application komponent usługa obiekt danych
|
||||
Technology węzeł/serwer infrastruktura artefakt
|
||||
|
||||
---
|
||||
|
||||
#### 7. UML — 3 diagramy architektoniczne
|
||||
|
||||
Component, Deployment, Sequence → **CDS** → **„Co Dzień Sekwencja"**
|
||||
|
||||
C → Component (moduły i zależności między nimi)
|
||||
D → Deployment (mapowanie modułów → serwery/sprzęt)
|
||||
S → Sequence (kto do kogo wysyła komunikaty w czasie)
|
||||
|
||||
Mnemonic-historia: **„Komponent Deploy'ujesz i Sekwencyjnie testujesz"**
|
||||
|
||||
---
|
||||
|
||||
#### 8. Quality Attributes (ISO 25010) — 8 atrybutów
|
||||
|
||||
Performance, Security, Scalability, Maintainability, Reliability, Usability, Portability, Compatibility
|
||||
|
||||
Mnemonic: **„PS SM RUPC"** → **„Pan Stefan Spotkał Małą Rudą Uczącą Polskiego Codziennie"**
|
||||
|
||||
P → Performance (wydajność — jak szybko)
|
||||
S → Security (bezpieczeństwo — jak chroniony)
|
||||
S → Scalability (skalowalność — jak rośnie)
|
||||
M → Maintainability (utrzymywalność — jak łatwo zmienić)
|
||||
R → Reliability (niezawodność — jak rzadko pada)
|
||||
U → Usability (użyteczność — jak łatwy w użyciu)
|
||||
P → Portability (przenośność — jak łatwo przenieść)
|
||||
C → Compatibility (kompatybilność — jak współpracuje)
|
||||
|
||||
Alternatywny podział na pary:
|
||||
|
||||
„Szybki i Bezpieczny" → Performance + Security
|
||||
„Rośnie i Zmienia się" → Scalability + Maintainability
|
||||
„Niezawodny i Łatwy" → Reliability + Usability
|
||||
„Przenośny i Zgodny" → Portability + Compatibility
|
||||
|
||||
---
|
||||
|
||||
#### 9. Cele modelowania — 5 celów
|
||||
|
||||
Komunikacja, Dokumentacja, Analiza jakości, Planowanie, Zarządzanie złożonością
|
||||
|
||||
Mnemonic: **„KDAPZ"** → **„Każdy Dobry Architekt Planuje Złożoność"**
|
||||
|
||||
K → Komunikacja (zespół się rozumie)
|
||||
D → Dokumentacja (wiedza nie ginie)
|
||||
A → Analiza jakości (czy będzie wydajne?)
|
||||
P → Planowanie (co budować dalej)
|
||||
Z → Zarządzanie złożonością (okiełznać chaos)
|
||||
|
||||
---
|
||||
|
||||
#### 10. ADR — struktura
|
||||
|
||||
Kontekst → Decyzja → Konsekwencje → **KDK**
|
||||
|
||||
Mnemonic: **„Kanapka: Kromka – Dżem – Kromka"**
|
||||
|
||||
K → Kontekst (DLACZEGO decydujemy — sytuacja)
|
||||
D → Decyzja (CO zdecydowaliśmy)
|
||||
K → Konsekwencje (CO z tego wynika — plusy i minusy)
|
||||
|
||||
---
|
||||
|
||||
#### 11. ATAM — co robi
|
||||
|
||||
**„ATAM = ATakuj Architekturę Metodycznie"**
|
||||
|
||||
→ Szukasz tradeoffs: „ta decyzja poprawia X kosztem Y"
|
||||
→ Metoda scenariuszowa: wymyślasz scenariusze jakościowe i sprawdzasz, jak architektura sobie z nimi radzi
|
||||
|
||||
---
|
||||
|
||||
#### 12. MASTER MNEMONIC — cały pytanie w jednym zdaniu
|
||||
|
||||
**„Tomek (TOGAF) Zachował (Zachman) Cztery Ciastka (C4) i 4+1 Archimedesowi (ArchiMate), rysując UML-em ADR-y, a ATAM sprawdził jakość ISO."**
|
||||
|
||||
Rozbicie:
|
||||
|
||||
Tomek → TOGAF (proces ADM: PVB-IT-OMG!, domeny BDAT)
|
||||
Zachował → Zachman (siatka 6×6: CJGKKD × abstrakcje)
|
||||
Cztery Ciastka → C4 (4×C: Context→Container→Component→Code)
|
||||
4+1 → Kruchten (LDPP+S: Logical, Dev, Process, Physical + Scenarios)
|
||||
Archimedesowi → ArchiMate (BAT × ABP)
|
||||
UML → 3 diagramy: CDS (Component, Deployment, Sequence)
|
||||
ADR → KDK (Kontekst, Decyzja, Konsekwencje)
|
||||
ATAM → ATakuj Architekturę Metodycznie
|
||||
ISO 25010 → 8 atrybutów: PS SM RUPC
|
||||
|
||||
|
||||
@ -63,11 +63,53 @@
|
||||
|
||||
---
|
||||
|
||||
**Christopher Alexander** — architekt budynków (nie programista!), ojciec idei wzorców w inżynierii. W książce „A Pattern Language" (1977) opisał 253 wzorców architektonicznych — budowlanych. GoF zaadaptowali jego format do oprogramowania. Kluczowa idea: wzorzec to nie luźna rada, ale skodyfikowane rozwiązanie z ustandaryzowanym opisem.
|
||||
|
||||
**Forma opisu wzorca (pattern template)** — standardowy szablon, w jakim kataloguje się każdy wzorzec. To serce odpowiedzi na „JAK są katalogowane?" — każdy wzorzec opisany jest według ustalonej struktury, dzięki czemu można je porównywać, przeszukiwać i komponować. Pola szablonu: Nazwa → Kontekst/Problem → Siły (forces) → Rozwiązanie → Konsekwencje → Powiązane wzorce → Znane zastosowania. Różne katalogi mają różne warianty szablonu (GoF ma 13 pól, forma Aleksandryjska jest bardziej narracyjna), ale rdzeń jest wspólny.
|
||||
|
||||
**Siły (forces)** — konkurencyjne wymagania, które wzorzec próbuje pogodzić. Np. wzorzec Layered godzi testowalność vs wydajność: warstwy ułatwiają testowanie, ale dodają overhead. Siły to serce wzorca — wyjaśniają DLACZEGO dane rozwiązanie jest kompromisem, a nie „idealnym rozwiązaniem na wszystko".
|
||||
|
||||
**Klasyfikacja wzorców (pattern classification)** — sposób organizacji wzorców wewnątrz katalogu. Główne osie klasyfikacji:
|
||||
- **Skala/zasięg**: architektoniczny (cały system) → projektowy (klasa/obiekt) → idiomatyczny (linia kodu)
|
||||
- **Domena problemu**: np. GoF dzieli 23 wzorce na kreacyjne (5), strukturalne (7), behawioralne (11)
|
||||
- **Atrybut jakościowy**: wydajność, skalowalność, dostępność, testowalność
|
||||
- **Domena zastosowania**: enterprise, chmura, integracja, embedded
|
||||
|
||||
**Język wzorców (pattern language)** — zbiór wzorców, które wzajemnie się referują, tworząc nawigacyjną sieć. Wzorzec „Microservices" referuje „API Gateway", „Service Discovery", „Circuit Breaker". Można „czytać" język wzorców jak przepis: „zacznij od X → jeśli problem Y → zastosuj Z". To trzeci filar katalogowania obok szablonu opisu i klasyfikacji.
|
||||
|
||||
---
|
||||
|
||||
### Cel: reużywalne rozwiązania typowych problemów, wspólne słownictwo, dokumentacja wiedzy
|
||||
|
||||
### Powstawanie: Problem powtarzalny → Podobne rozwiązania → Uogólnienie → Dokumentacja → Walidacja → Katalogowanie
|
||||
|
||||
### Katalogi: POSA (wzorce architektoniczne), GoF (projektowe), EIP (integracja), PoEAA (Fowler), Cloud Patterns
|
||||
### Katalogowanie — trzy filary metodologii
|
||||
|
||||
**1. Ustandaryzowany szablon opisu** — każdy wzorzec opisany wg tego samego formatu:
|
||||
- **Nazwa** — jedno słowo/fraza: „Layered", „Observer"
|
||||
- **Problem/Kontekst** — kiedy stosować
|
||||
- **Siły (forces)** — konkurencyjne wymagania do pogodzenia
|
||||
- **Rozwiązanie** — struktura, diagram, zachowanie
|
||||
- **Konsekwencje** — tradeoffs: co zyskujemy, co tracimy
|
||||
- **Powiązane wzorce** — jakie wzorce współgrają lub konkurują
|
||||
- **Znane zastosowania** — real-world examples
|
||||
|
||||
**2. Klasyfikacja wieloosiowa** — wzorce organizowane wzdłuż kilku osi jednocześnie:
|
||||
- **Skala**: architektoniczny (cały system) → projektowy (klasa) → idiomatyczny (linia kodu)
|
||||
- **Domena problemu**: kreacyjne / strukturalne / behawioralne (GoF) albo warstwy / komunikacja / dekompozycja (POSA)
|
||||
- **Atrybut jakościowy**: wydajność, skalowalność, testowalność, dostępność
|
||||
|
||||
**3. Język wzorców (pattern language)** — wzorce referują się wzajemnie, tworząc graf:
|
||||
- Microservices → wymaga → API Gateway, Service Discovery, Circuit Breaker
|
||||
- Observer → wariant architektoniczny → Event-Driven Architecture
|
||||
- Nawigacja: „mam problem X → wzorzec A → prowadzi do problemu Y → wzorzec B"
|
||||
|
||||
**Konkretne katalogi:**
|
||||
- **POSA** (1996) — wzorce architektoniczne: Layers, Pipes & Filters, Broker, MVC, Microkernel
|
||||
- **GoF** (1994) — 23 wzorce projektowe: kreacyjne (5), strukturalne (7), behawioralne (11)
|
||||
- **EIP** (2003) — wzorce integracji: Message Channel, Router, Aggregator
|
||||
- **PoEAA** (2002) — enterprise: Repository, Unit of Work, Domain Model, Active Record
|
||||
- **Cloud Patterns** (~2015) — chmurowe: Circuit Breaker, Sidecar, Saga, Strangler Fig
|
||||
|
||||
### Przykładowe wzorce
|
||||
|
||||
@ -94,7 +136,16 @@
|
||||
|
||||
### Jak zapamiętać
|
||||
|
||||
- **Mnemonik katalogów „PGEP+C"**: **P**OSA → **G**oF → **E**IP → **P**oEAA + **C**loud
|
||||
- Historia: „**P**aweł **G**rał **E**fektownie **P**od **C**hmurami"
|
||||
- Chronologicznie: GoF '94 → POSA '96 → PoEAA '02 → EIP '03 → Cloud ~'15
|
||||
- **Szablon wzorca „NaPSiRoKo"**: **Na**zwa, **P**roblem, **Si**ły, **Ro**związanie, **Ko**nsekwencje
|
||||
- Wyobraź sobie kartonowe pudełko: etykieta (Nazwa) → co nie działa (Problem) → wagi na szalce (Siły) → instrukcja montażu (Rozwiązanie) → lista „+" i „−" na boku (Konsekwencje)
|
||||
- **3 filary katalogowania**: Szablon + Klasyfikacja + Język wzorców
|
||||
- Analogia do encyklopedii: każde hasło ma ten sam format (szablon), jest w kategorii z innymi hasłami tego typu (klasyfikacja), i ma „zobacz też" (język wzorców)
|
||||
- **„Monolith first"** — rozdzielaj gdy znasz granice domen
|
||||
- **Wzorzec = Nazwa + Problem + Rozwiązanie + Konsekwencje**
|
||||
- Katalogi: POSA = architektura, GoF = klasy/obiekty, EIP = messaging
|
||||
- **Wzorzec = Nazwa + Problem + Rozwiązanie + Konsekwencje** (minimum do zapamiętania z dowolnego katalogu)
|
||||
- Katalogi wg skali: POSA = systemy, GoF = obiekty, EIP = komunikacja międzysystemowa
|
||||
|
||||
→ Diagramy do druku: `pytania/img/q14_pattern_template.png`, `pytania/img/q14_catalog_map.png`
|
||||
|
||||
|
||||
@ -79,6 +79,82 @@ Przykład: Robot-dostawca. Belief: „drzwi zamknięte". Desire: „dostarczyć
|
||||
|
||||
---
|
||||
|
||||
### Odpowiedź wprost: jak agent upostaciowiony specyfikuje sterownik robota
|
||||
|
||||
**Definicja:** Agent upostaciowiony (embodied agent) to formalny model konceptualny robota — bytu posiadającego ciało fizyczne, sensory i efektory, działającego w rzeczywistym środowisku. Wykorzystanie tego modelu do specyfikacji sterowników polega na tym, że **architektura sterownika robota jest bezpośrednim odwzorowaniem struktury agenta**: cykl percepcja–deliberacja–akcja staje się pętlą sterowania, a formalne modele agenta (BDI, LTL) stają się specyfikacją wymagań dla oprogramowania robota.
|
||||
|
||||
**Krótko: model agenta → architektura sterownika → implementacja na robocie.**
|
||||
|
||||
#### Krok 1: Model agenta definiuje CO robot ma robić
|
||||
|
||||
Robot traktujemy jako agenta upostaciowionego. To oznacza, że specyfikujemy:
|
||||
- **Sensory** — jakie dane wejściowe robot otrzymuje (LIDAR, kamera, IMU)
|
||||
- **Efektory** — jakie akcje fizyczne może wykonać (jedź, chwyć, obróć)
|
||||
- **Cel** — co agent ma osiągnąć (dostarczyć paczkę, unikać kolizji)
|
||||
- **Środowisko** — w jakim świecie działa (magazyn, szpital, droga)
|
||||
|
||||
#### Krok 2: Cykl See-Think-Act definiuje JAK działa pętla sterowania
|
||||
|
||||
Każdy sterownik robota realizuje wariant cyklu agenta:
|
||||
1. **See** — odczytaj sensory → zbuduj wewnętrzny model świata (np. mapę)
|
||||
2. **Think** — na podstawie modelu i celu wybierz akcję (planowanie)
|
||||
3. **Act** — wyślij komendy do silników/chwytaków
|
||||
|
||||
Ten cykl powtarza się w pętli z częstotliwością zależną od warstwy (ms → min).
|
||||
|
||||

|
||||
|
||||
#### Krok 3: Architektura 3T dzieli sterownik na warstwy odpowiedzialności
|
||||
|
||||
Praktyczna realizacja agenta upostaciowionego to **architektura trójwarstwowa (3T)**:
|
||||
|
||||
| Warstwa | Rola | Czas reakcji | Przykład |
|
||||
|---------|------|-------------|----------|
|
||||
| **Planner** | planowanie symboliczne (CEL → PLAN) | sekundy–minuty | "Jedź trasą A→B→C" |
|
||||
| **Sequencer** | koordynacja zachowań (PLAN → SEKWENCJA) | 100 ms–sekundy | FSM: IDLE→APPROACH→GRASP |
|
||||
| **Controller** | sterowanie sprzętem (SEKWENCJA → SYGNAŁY) | milisekundy | PID: prędkość = 0.5 m/s |
|
||||
|
||||
Każda warstwa odpowiada innemu aspektowi agenta:
|
||||
- Planner = deliberacja (myślenie długoterminowe)
|
||||
- Sequencer = koordynacja intencji (BDI: Intentions)
|
||||
- Controller = reaktywność (natychmiastowe bezpieczeństwo)
|
||||
|
||||

|
||||
|
||||
#### Krok 4: Formalne modele agenta specyfikują wymagania
|
||||
|
||||
**Model BDI** pozwala formalnie opisać stan wewnętrzny agenta i na tej podstawie generować/weryfikować sterownik:
|
||||
- Beliefs = wiedza robota → baza danych sensorycznych
|
||||
- Desires = cele → warunki sukcesu
|
||||
- Intentions = aktualny plan → sekwencer
|
||||
|
||||

|
||||
|
||||
**Logika temporalna LTL** pozwala specyfikować wymagania bezpieczeństwa i żywotności:
|
||||
- **Bezpieczeństwo:** □(obstacle → ¬move_forward) — "ZAWSZE: jeśli przeszkoda, NIE jedź naprzód"
|
||||
- **Żywotność:** ◇(at_goal) — "KIEDYŚ dotrzyj do celu"
|
||||
|
||||
Formalna specyfikacja LTL → automatyczna synteza/weryfikacja sterownika (model checking).
|
||||
|
||||
#### Krok 5: Behavior Trees implementują specyfikację zachowań
|
||||
|
||||
Nowoczesna metoda implementacji warstwy Sequencer. Modularność, reużywalność, łatwe debugowanie:
|
||||
|
||||

|
||||
|
||||
#### Konkretny przykład: robot-dostawca w szpitalu
|
||||
|
||||
1. **Model agenta:** sensory = LIDAR + kamera; efektory = koła + chwytak; cel = dostarcz lek do pokoju 5
|
||||
2. **BDI:** Belief = "drzwi pokoju 5 zamknięte"; Desire = "dostarczyć lek"; Intention = "jedź do drzwi bocznych"
|
||||
3. **LTL:** □(¬collision) ∧ ◇(at_room5) — "nigdy nie koliduj I w końcu dotrzyj do pokoju 5"
|
||||
4. **3T:**
|
||||
- Planner: A* wyznacza trasę korytarz → winda → piętro 3 → pokój 5
|
||||
- Sequencer: BT: [Jedź do windy → Wjedź → Jedź do pokoju → Otwórz drzwi → Podaj lek]
|
||||
- Controller: PID utrzymuje prędkość 0.3 m/s, emergency stop przy przeszkodzie < 30 cm
|
||||
5. **ROS:** node `/lidar_scan` → topic → node `/path_planner` → topic → node `/motor_driver`
|
||||
|
||||
---
|
||||
|
||||
### Agent upostaciowiony = ciało fizyczne + sensory + efektory + środowisko
|
||||
|
||||
Cykl: **Percepcja → Deliberacja → Akcja** (See-Think-Act)
|
||||
@ -111,7 +187,10 @@ Cykl: **Percepcja → Deliberacja → Akcja** (See-Think-Act)
|
||||
|
||||
### Jak zapamiętać
|
||||
|
||||
- **„See-Think-Act"** = Percepcja → Deliberacja → Akcja
|
||||
- **3T = Plan-Sequence-Control** (od abstrakcji do sprzętu)
|
||||
- BDI = Beliefs, Desires, Intentions
|
||||
- **"STA"** = **S**ee → **T**hink → **A**ct (jak STA-bilność — stabilny cykl sterowania)
|
||||
- **3T = "Plan-Seq-Con"** = od abstrakcji do sprzętu, jak w armii: generał (Plan) → oficer (Seq) → żołnierz (Con)
|
||||
- **BDI = "Wiem–Chcę–Robię"**: Beliefs = co Wiem, Desires = co Chcę, Intentions = co Robię
|
||||
- **LTL: □ = "zawsze" (kwadrat = solidny, niezmienny), ◇ = "kiedyś" (diament = cenny cel do zdobycia)**
|
||||
- **Agent→Sterownik w 5 krokach:** CO (model agenta) → JAK (STA) → WARSTWY (3T) → WYMAGANIA (BDI+LTL) → IMPLEMENTACJA (BT+ROS)
|
||||
- **Akronim SPECYFIKACJA:** **S**ensory → **P**ercepcja → **E**fekty → **C**ykl → **I**ntencje → **F**ormalność → **I**mplementacja → **K**ontroler → **A**kcja → **C**el → **J**akość → **A**rchitektura
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
### Tło pojęciowe — słowniczek
|
||||
|
||||
**Robot** — cz. „robota" = ciężka praca; termin ukuty przez Karla Čapka (R.U.R., 1920). W przemyśle: programowalna maszyna wykonująca zadania (spawanie, paletyzacja, montaż). W kontekście pytania: głównie roboty przemysłowe (manipulatory).
|
||||
**Robot** — cz. „robota" = ciężka praca; termin ukuty przez Karla Čapka (R.U.R., 1920). W przemyśle: programowalna maszyna wykonująca zadania (spawanie, paletyzacja, montaż). W kontekście pytania: głównie roboty przemysłowe (manipulatory) — ramiona z 4–7 osiami obrotu, sterowane komputerowo.
|
||||
|
||||
**Język programowania robotów** — język do definiowania zachowania robota: ruchy, logika, I/O. Może być specjalizowany (dedykowany producenta) lub ogólny (C++, Python z bibliotekami). Klasyfikacja wg poziomu abstrakcji — od zadań po sygnały silników.
|
||||
|
||||
@ -16,86 +16,453 @@
|
||||
|
||||
**Task-level (poziom zadania)** — najwyższy: opisujesz CO robot ma zrobić, nie JAK. „Podnieś A, połóż na B." Robot sam planuje ruchy. Przykłady: PDDL, Behavior Trees.
|
||||
|
||||
// Task-level:
|
||||
// Task-level (pseudokod):
|
||||
pick(objectA);
|
||||
place(locationB);
|
||||
// Robot sam oblicza kinematykę, trajektorię, chwyt
|
||||
|
||||
**Robot-level (poziom robota)** — komendy ruchu w przestrzeni kartezjańskiej lub konfiguracyjnej: move_to(x,y,z), grasp(). Programista mówi GDZIE jechać, robot oblicza JAK (kinematyka odwrotna). Przykłady: RAPID (ABB), KRL (KUKA), Karel (FANUC).
|
||||
|
||||
// RAPID (ABB):
|
||||
MoveL p1, v500, fine, tool1; // liniowo do p1, prędkość 500 mm/s
|
||||
**Robot-level (poziom robota)** — komendy ruchu w przestrzeni kartezjańskiej lub konfiguracyjnej: move_to(x,y,z), grasp(). Programista mówi GDZIE jechać, robot oblicza JAK (kinematyka odwrotna). Tu działają języki producentów: RAPID (ABB), KRL (KUKA), Karel (FANUC), PDL2 (Comau), URScript (Universal Robots).
|
||||
|
||||
**Motion-level (poziom ruchu)** — planowanie trajektorii: generowanie ciągu punktów od startu do celu z unikaniem kolizji. Kinematyka odwrotna, interpolacja. Przykłady: MoveIt (ROS), OMPL.
|
||||
|
||||
**Servo-level (poziom serwa)** — najniższy: bezpośrednie sterowanie silnikami/serwomechanizmami. Regulacja PID, sygnały PWM. Języki: C/C++, FPGA. Czas reakcji: mikro-milisekundy.
|
||||
**Servo-level (poziom serwa)** — najniższy: bezpośrednie sterowanie silnikami/serwomechanizmami. Regulacja PID, sygnały PWM. Języki: C/C++, FPGA/VHDL. Czas reakcji: mikro-milisekundy.
|
||||
|
||||
Przykład czasu reakcji na każdym poziomie:
|
||||
Task: "Zamontuj śrubę" (sekundy)
|
||||
Robot: MoveL do_pozycji (100 ms)
|
||||
Motion: Trajektoria 50 pkt/s (20 ms)
|
||||
Servo: PID: PWM silnika = 75% (1 ms)
|
||||
|
||||
---
|
||||
|
||||
**Kinematyka odwrotna (inverse kinematics, IK)** — obliczenie kątów w stawach robota, aby efektor (np. chwytak) znalazł się w zadanej pozycji. Problem odwrotny: znasz cel, szukasz konfiguracji. Może mieć 0, 1 lub wiele rozwiązań.
|
||||
|
||||
**Trajektoria (trajectory)** — zaplanowana ścieżka ruchu w czasie: sekwencja pozycji + prędkości + przyspieszenia. Interpolacja: liniowa (LIN), kołowa (CIRC), punkt-do-punktu (PTP).
|
||||

|
||||
|
||||
---
|
||||
|
||||
**Języki producentów (vendor-specific):**
|
||||
- **RAPID (ABB)** — Robotics Application Programming Interactive Dialogue. Ruchy: MoveJ (joint), MoveL (linear), MoveC (circular).
|
||||
- **KRL (KUKA Robot Language)** — PTP (point-to-point), LIN (linear), CIRC (circular). Pascal-like syntax.
|
||||
- **Karel (FANUC)** — od Karla Čapka. MOVE TO target. Pascal-like.
|
||||
- **PDL2 (Comau)** — MOVE LINEAR TO. Proceduralne.
|
||||
**Kinematyka odwrotna (inverse kinematics, IK)** — obliczenie kątów w stawach robota, aby efektor (np. chwytak) znalazł się w zadanej pozycji. Problem odwrotny: znasz cel (x,y,z + orientacja), szukasz konfiguracji (kąty q₁…qₙ). Może mieć 0, 1 lub wiele rozwiązań. Robot 6-osiowy: zazwyczaj do 8 rozwiązań dla jednej pozycji.
|
||||
|
||||
**Vendor lock-in** — każdy producent ma WŁASNY język. Program napisany w RAPID nie działa na robocie KUKA. To motywacja dla ROS i standardów.
|
||||
Przykład (robot 2-osiowy, ramiona L₁=L₂=1m, cel: x=1.0, y=1.0):
|
||||
q₂ = arccos((x²+y²−L₁²−L₂²) / (2·L₁·L₂))
|
||||
= arccos((1+1−1−1)/2) = arccos(0) = 90°
|
||||
Dwa rozwiązania: „łokieć do góry" i „łokieć na dół"
|
||||
|
||||
**Online vs Offline programming:**
|
||||
- **Online (teach-in)** — operator prowadzi robota „za rękę" (pendant/teach pendant), robot zapamiętuje punkty. Proste, ale wymaga zatrzymania produkcji.
|
||||
- **Offline** — programowanie w symulacji (CAD/CAM), bez zatrzymywania robota. Transferujesz gotowy program.
|
||||
**Trajektoria (trajectory)** — zaplanowana ścieżka ruchu w czasie: sekwencja pozycji + prędkości + przyspieszenia. Trzy typy interpolacji:
|
||||
- **PTP (Point-to-Point)** — najszybsza, ale ścieżka w przestrzeni kartezjańskiej nieprzewidywalna (interpolacja w przestrzeni stawów)
|
||||
- **LIN (Linear)** — prosta linia TCP (Tool Center Point); wymaga obliczenia IK w każdym punkcie
|
||||
- **CIRC (Circular)** — łuk kołowy przez 3 punkty (start, pkt pomocniczy, cel)
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
**ROS (Robot Operating System)** — middleware (nie OS!) do robotyki. Model pub/sub: węzły publikują/subskrybują tematy. Uniwersalny — działa z robotami różnych producentów. Głównie Python/C++. Wada: nie nadaje się do hard real-time (soft real-time OK; ROS 2 poprawia).
|
||||
**Vendor lock-in** — każdy producent ma WŁASNY język. Program napisany w RAPID nie działa na robocie KUKA. To motywacja dla ROS i standardów. Porównanie języków:
|
||||
|
||||
**MoveIt** — biblioteka ROS do planowania ruchu manipulatorów. Obejmuje: IK, collision avoidance, trajectory planning. Open source.
|
||||

|
||||
|
||||
**PDDL (Planning Domain Definition Language)** — język opisu problemów planowania. Definiujesz: stany, akcje, warunki, cel. Planner automatycznie znajduje sekwencję akcji. Task-level.
|
||||
---
|
||||
|
||||
**FPGA (Field-Programmable Gate Array)** — programowalny układ logiczny. Dla servo-level: przetwarzanie sygnałów w nanosekundach. Szybszy niż mikrokontroler, ale trudniejszy w programowaniu.
|
||||
**TCP (Tool Center Point)** — punkt centralny narzędzia zamontowanego na końcu ramienia (np. czubek spawarki, środek chwytaka). Wszystkie komendy ruchu LIN i CIRC odnoszą się do TCP — robot steruje tak, żeby ten punkt poruszał się po żądanej ścieżce.
|
||||
|
||||
Definiowanie TCP w RAPID:
|
||||
PERS tooldata tGripper := [TRUE, [[0,0,150],[1,0,0,0]],
|
||||
[2,[0,0,75],[1,0,0,0],0,0,0]];
|
||||
// TCP jest 150mm nad kołnierzem, masa narzędzia 2kg
|
||||
|
||||
**Strefa zbliżenia (zone)** — parametr określający, jak blisko celu robot musi dojechać zanim zacznie ruch do kolejnego punktu. `fine` = dojazd dokładnie do punktu (zatrzymanie), `z10` = robot zaczyna skręcać w stronę następnego punktu gdy jest 10mm od celu (ruch „na okrągło", płynniejszy i szybszy).
|
||||
|
||||
MoveL p1, v500, fine, tool1; // zatrzymaj się dokładnie w p1
|
||||
MoveL p1, v500, z50, tool1; // zacznij skręcać 50mm przed p1
|
||||
// z50 → szybszy cykl, ale mniejsza precyzja w punkcie
|
||||
|
||||
---
|
||||
|
||||
### Klasyfikacja wg poziomu abstrakcji: **T-R-M-S**
|
||||
|
||||
1. **Task-level** — „Podnieś A, połóż na B" (PDDL, Behavior Trees)
|
||||
2. **Robot-level** — move_to(), grasp() (RAPID, KRL, Karel, ROS)
|
||||
2. **Robot-level** — move_to(), grasp() (RAPID, KRL, Karel, URScript)
|
||||
3. **Motion-level** — trajektorie, kinematyka odwrotna (MoveIt, OMPL)
|
||||
4. **Servo-level** — PID, sterowanie silnikami (C/C++, FPGA)
|
||||
|
||||
### Klasyfikacja wg metody: Online (teach-in, pendant) vs Offline (symulacja, CAD)
|
||||
### Klasyfikacja wg metody programowania
|
||||
|
||||
### Języki producentów
|
||||

|
||||
|
||||
| Producent | Język | Ruchy |
|
||||
|-----------|-------|--------------------|
|
||||
| ABB | RAPID | MoveJ, MoveL, MoveC|
|
||||
| KUKA | KRL | PTP, LIN, CIRC |
|
||||
| FANUC | Karel | MOVE TO |
|
||||
| Comau | PDL2 | MOVE LINEAR TO |
|
||||
- **Online (teach-in)** — operator z teach pendantem prowadzi robota i zapisuje punkty. Proste, intuicyjne, ale wymaga wyłączenia produkcji.
|
||||
- **Offline** — programowanie w symulatorze 3D (RobotStudio, KUKA.Sim, ROBOGUIDE), bez zatrzymywania robota. Wymaga kalibracji po transferze.
|
||||
- **Hybrid** — w praktyce łączy się oba podejścia: offline do wstępnego programu, online do korekcji punktów.
|
||||
|
||||
### Uniwersalne: ROS + Python/C++, MoveIt (planowanie manipulatora), Orocos (real-time)
|
||||
### Języki producentów — szczegółowo
|
||||
|
||||
### Graficzne: RobotStudio (ABB), ROBOGUIDE (FANUC), Blockly (edukacja)
|
||||
#### RAPID (ABB)
|
||||
|
||||
**Producent:** ABB. **Rozwinięcie:** Robotics Application Programming Interactive Dialogue. **Składnia:** własny typ, strukturalna, wielozadaniowa (RAPID obsługuje wielowątkowość). **Symulator:** RobotStudio (darmowa wersja edukacyjna).
|
||||
|
||||
**Kluczowe cechy:**
|
||||
- Typy danych: `num` (liczba), `string`, `bool`, `robtarget` (pozycja kartezjańska + orientacja + konfiguracja), `jointtarget` (kąty stawów), `tooldata`, `wobjdata` (układ współrzędnych obiektu)
|
||||
- Ruchy: `MoveJ` (joint — PTP), `MoveL` (linear), `MoveC` (circular), `MoveAbsJ` (absolutne kąty)
|
||||
- I/O: `SetDO` (digital output), `WaitDI` (czekaj na digital input), `SetAO` (analog out)
|
||||
- Kontrola przepływu: `IF/ELSEIF/ELSE/ENDIF`, `WHILE/ENDWHILE`, `FOR/ENDFOR`, `TEST/CASE/DEFAULT/ENDTEST`
|
||||
- Obsługa błędów: `TRAP` (przerwania), `ERROR` handler
|
||||
- Wielozadaniowość: wiele tasków wykonywanych równolegle — np. jeden task steruje ruchem, drugi monitoruje czujniki
|
||||
|
||||
**Przykładowy program pick & place:**
|
||||
|
||||
MODULE MainModule
|
||||
! --- Dane ---
|
||||
CONST robtarget pHome := [[500,0,600],[1,0,0,0],[0,0,0,0],[9E9,9E9,9E9,9E9,9E9,9E9]];
|
||||
CONST robtarget pPick := [[400,200,100],[1,0,0,0],[0,0,0,0],[9E9,9E9,9E9,9E9,9E9,9E9]];
|
||||
CONST robtarget pPlace := [[400,-200,100],[1,0,0,0],[0,0,0,0],[9E9,9E9,9E9,9E9,9E9,9E9]];
|
||||
VAR num nCycles := 0;
|
||||
|
||||
! --- Procedura główna ---
|
||||
PROC main()
|
||||
MoveJ pHome, v1000, z50, tGripper; ! jedź do pozycji bazowej (joint)
|
||||
WHILE TRUE DO
|
||||
PickPart;
|
||||
PlacePart;
|
||||
Incr nCycles;
|
||||
TPWrite "Cykl nr: " + ValToStr(nCycles);
|
||||
ENDWHILE
|
||||
ENDPROC
|
||||
|
||||
! --- Podnoszenie ---
|
||||
PROC PickPart()
|
||||
MoveL Offs(pPick,0,0,50), v500, z10, tGripper; ! 50mm nad celem
|
||||
MoveL pPick, v100, fine, tGripper; ! precyzyjnie na cel
|
||||
SetDO doGripper, 1; ! zamknij chwytak
|
||||
WaitTime 0.3; ! czekaj na zamknięcie
|
||||
MoveL Offs(pPick,0,0,50), v500, z10, tGripper; ! podnieś 50mm
|
||||
ENDPROC
|
||||
|
||||
! --- Odkładanie ---
|
||||
PROC PlacePart()
|
||||
MoveL Offs(pPlace,0,0,50), v500, z10, tGripper; ! 50mm nad miejscem
|
||||
MoveL pPlace, v100, fine, tGripper; ! precyzyjnie na cel
|
||||
SetDO doGripper, 0; ! otwórz chwytak
|
||||
WaitTime 0.3;
|
||||
MoveL Offs(pPlace,0,0,50), v500, z10, tGripper; ! podnieś 50mm
|
||||
ENDPROC
|
||||
ENDMODULE
|
||||
|
||||
**Objaśnienie parametrów MoveL:**
|
||||
|
||||
MoveL pPick, v500, z10, tGripper;
|
||||
│ │ │ │ └── narzędzie (tooldata) — definiuje TCP
|
||||
│ │ │ └── strefa zbliżenia: 10mm (nie zatrzymuj się, skręcaj)
|
||||
│ │ └── prędkość TCP: 500 mm/s
|
||||
│ └── cel: robtarget (pozycja + orientacja + konfiguracja)
|
||||
└── typ ruchu: ruch liniowy (TCP jedzie po prostej)
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
#### KRL (KUKA Robot Language)
|
||||
|
||||
**Producent:** KUKA. **Rozwinięcie:** KUKA Robot Language. **Składnia:** Pascal-like (BEGIN/END, deklaracje na początku). **Symulator:** KUKA.Sim Pro, WorkVisual.
|
||||
|
||||
**Kluczowe cechy:**
|
||||
- Program = dwa pliki: `.src` (kod) + `.dat` (dane punktów)
|
||||
- Typy: `INT`, `REAL`, `BOOL`, `CHAR`, `POS` (x,y,z,a,b,c), `E6POS` (+ osie dodatkowe), `AXIS` (kąty stawów)
|
||||
- Ruchy: `PTP` (point-to-point = joint), `LIN` (linear), `CIRC` (circular)
|
||||
- Approximation (odpowiednik zone w RAPID): `C_DIS` — robot nie zatrzymuje się w punkcie
|
||||
- Kontrola przepływu: `IF/ENDIF`, `WHILE/ENDWHILE`, `FOR/ENDFOR`, `SWITCH/CASE/ENDSWITCH`
|
||||
|
||||
**Przykładowy program:**
|
||||
|
||||
DEF PickAndPlace()
|
||||
; --- Deklaracje ---
|
||||
DECL E6POS XHome, XPick, XPlace
|
||||
DECL INT nLoop
|
||||
|
||||
; --- Inicjalizacja ---
|
||||
BAS (#INITMOV, 0) ; inicjalizacja ruchów
|
||||
$VEL.CP = 0.5 ; prędkość kartezjańska 0.5 m/s
|
||||
$APO.CDIS = 10 ; approximacja: 10mm
|
||||
|
||||
; --- Ruch do domu ---
|
||||
PTP XHome ; point-to-point (joint space)
|
||||
|
||||
FOR nLoop = 1 TO 100
|
||||
; Podjedź nad punkt pobrania
|
||||
LIN XPick ; ruch liniowy do punktu
|
||||
; Zamknij chwytak
|
||||
OUT 1 TRUE ; digital output 1 = ON
|
||||
WAIT SEC 0.3
|
||||
; Jedź do miejsca odkładania
|
||||
LIN XPlace
|
||||
OUT 1 FALSE ; otwórz chwytak
|
||||
WAIT SEC 0.3
|
||||
ENDFOR
|
||||
END
|
||||
|
||||
**KRL vs RAPID — kluczowe różnice:**
|
||||
- KRL rozdziela kod (`.src`) od danych (`.dat`); RAPID trzyma wszystko w MODULE
|
||||
- KRL: `$VEL.CP = 0.5` (zmienna systemowa); RAPID: `v500` (nazwany speeddata)
|
||||
- KRL: `C_DIS` approximation; RAPID: `z10` zone
|
||||
- KRL: `OUT 1 TRUE`; RAPID: `SetDO doGripper, 1`
|
||||
|
||||
---
|
||||
|
||||
#### Karel (FANUC)
|
||||
|
||||
**Producent:** FANUC. **Nazwa:** od Karla Čapka. **Składnia:** Pascal-like (PROGRAM/BEGIN/END, VAR). **Symulator:** ROBOGUIDE.
|
||||
|
||||
**Kluczowe cechy:**
|
||||
- Dwa tryby: Karel (tekstowy, pełny język) i TP (Teach Pendant — uproszczony, listowy)
|
||||
- Karel: kompilowany, typowany, procedury/funkcje
|
||||
- Typy: `INTEGER`, `REAL`, `BOOLEAN`, `STRING`, `POSITION`, `XYZWPR`
|
||||
- TP program jest częściej używany w praktyce (prostszy, operatorzy go rozumieją)
|
||||
|
||||
**Przykład Karel:**
|
||||
|
||||
PROGRAM pick_place
|
||||
VAR
|
||||
home_pos : POSITION
|
||||
pick_pos : POSITION
|
||||
place_pos : POSITION
|
||||
cycle_count : INTEGER
|
||||
BEGIN
|
||||
cycle_count = 0
|
||||
-- Jedź do domu
|
||||
MOVE TO home_pos
|
||||
WHILE cycle_count < 100 DO
|
||||
-- Podnoszenie
|
||||
MOVE TO pick_pos
|
||||
DOUT[1] = ON -- zamknij chwytak
|
||||
DELAY 300 -- czekaj 300ms
|
||||
-- Odkładanie
|
||||
MOVE TO place_pos
|
||||
DOUT[1] = OFF -- otwórz chwytak
|
||||
DELAY 300
|
||||
cycle_count = cycle_count + 1
|
||||
ENDWHILE
|
||||
END pick_place
|
||||
|
||||
**Przykład TP (Teach Pendant) — to widzi operator:**
|
||||
|
||||
1: J P[1] 100% FINE ; joint move do Home, 100% speed
|
||||
2: L P[2] 500mm/sec FINE ; linear do Pick
|
||||
3: DO[1]=ON ; chwytak zamknij
|
||||
4: WAIT 0.30(sec)
|
||||
5: L P[3] 500mm/sec FINE ; linear do Place
|
||||
6: DO[1]=OFF ; chwytak otwórz
|
||||
7: WAIT 0.30(sec)
|
||||
8: JMP LBL[1] ; skocz do linii 1
|
||||
|
||||
**Uwaga:** W praktyce fabrycznej TP jest dominujący — operatorzy uczą się numerowanych linii, nie pełnego Karela.
|
||||
|
||||
---
|
||||
|
||||
#### URScript (Universal Robots)
|
||||
|
||||
**Producent:** Universal Robots (coboty — collaborative robots). **Składnia:** Python-like (brak nawiasów klamrowych, wcięcia nie mają znaczenia, ale styl jest skryptowy). **Symulator:** URSim (darmowy, oparty na VM).
|
||||
|
||||
**Kluczowe cechy:**
|
||||
- Skryptowy i prosty — niski próg wejścia (coboty = roboty współpracujące z ludźmi)
|
||||
- Wbudowane funkcje force control (sterowanie siłą) — unikalne dla cobotów
|
||||
- Typy: brak deklaracji typów (dynamiczne), `pose` = [x,y,z,rx,ry,rz]
|
||||
- Polyscope — graficzny interfejs do programowania (drag & drop + URScript)
|
||||
|
||||
**Przykład URScript:**
|
||||
|
||||
def pick_and_place():
|
||||
# Pozycje jako pose: [x, y, z, rx, ry, rz] w metrach i radianach
|
||||
home = p[0.5, 0.0, 0.4, 3.14, 0.0, 0.0]
|
||||
pick = p[0.4, 0.2, 0.1, 3.14, 0.0, 0.0]
|
||||
place = p[0.4, -0.2, 0.1, 3.14, 0.0, 0.0]
|
||||
|
||||
movej(home, a=1.2, v=0.5) # joint move, acc=1.2 rad/s², vel=0.5 rad/s
|
||||
|
||||
i = 0
|
||||
while i < 100:
|
||||
# Podnoszenie
|
||||
movel(pick, a=0.5, v=0.3) # linear move
|
||||
set_digital_out(0, True) # zamknij chwytak
|
||||
sleep(0.3)
|
||||
|
||||
# Odkładanie
|
||||
movel(place, a=0.5, v=0.3)
|
||||
set_digital_out(0, False) # otwórz chwytak
|
||||
sleep(0.3)
|
||||
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
**URScript — unikalne cechy cobotów:**
|
||||
|
||||
# Force mode — wkładanie kołka w otwór z kontrolą siły:
|
||||
force_mode(p[0,0,0,0,0,0], [0,0,1,0,0,0], [0,0,-10,0,0,0], 2, [0.1,0.1,0.05,1,1,1])
|
||||
# Robot naciska z siłą 10N w dół (oś Z), reszt osi blokuje
|
||||
|
||||
# Freedrive — operator prowadzi robota ręcznie:
|
||||
freedrive_mode()
|
||||
sleep(10) # 10 sekund swobodnego prowadzenia
|
||||
end_freedrive_mode()
|
||||
|
||||
---
|
||||
|
||||
#### PDL2 (Comau)
|
||||
|
||||
**Producent:** Comau (Fiat/Stellantis). **Składnia:** proceduralna, C-like. **Symulator:** RoboSim.
|
||||
|
||||
**Przykład:**
|
||||
|
||||
PROGRAM pick_place
|
||||
VAR home_pos, pick_pos, place_pos : POSITION
|
||||
BEGIN
|
||||
MOVE TO home_pos
|
||||
CYCLE
|
||||
MOVE LINEAR TO pick_pos
|
||||
$DOUT[1] := TRUE -- chwytak
|
||||
DELAY 300
|
||||
MOVE LINEAR TO place_pos
|
||||
$DOUT[1] := FALSE
|
||||
DELAY 300
|
||||
END CYCLE
|
||||
END pick_place
|
||||
|
||||
---
|
||||
|
||||
### Porównanie składni — ten sam ruch w 5 językach
|
||||
|
||||
Zadanie: ruch liniowy do punktu pPick z prędkością ~500mm/s
|
||||
|
||||
RAPID (ABB): MoveL pPick, v500, fine, tGripper;
|
||||
KRL (KUKA): LIN XPick
|
||||
Karel (FANUC): MOVE TO pick_pos ; z opcją LINEAR
|
||||
TP (FANUC): L P[2] 500mm/sec FINE
|
||||
URScript (UR): movel(pick, a=0.5, v=0.5)
|
||||
PDL2 (Comau): MOVE LINEAR TO pick_pos
|
||||
|
||||
### Języki uniwersalne i middleware
|
||||
|
||||
#### ROS / ROS 2 (Robot Operating System)
|
||||
|
||||
**ROS** to middleware (NIE system operacyjny!) — warstwa komunikacji między modułami (węzłami). Programuje się w Python lub C++. Architektura publish/subscribe: węzły publikują wiadomości na tematy (topics), inne węzły subskrybują.
|
||||
|
||||

|
||||
|
||||
**ROS 1 vs ROS 2:**
|
||||
- ROS 1: roscore (centralny master), brak real-time, Python 2/3 + C++
|
||||
- ROS 2: DDS (bez centralnego mastera, peer-to-peer), real-time friendly, Python 3 + C++17
|
||||
- ROS 2 dodaje: lifecycle nodes, QoS (Quality of Service), lepsze multi-robot
|
||||
|
||||
**Przykład ROS 2 (Python) — publisher prędkości:**
|
||||
|
||||
import rclpy
|
||||
from geometry_msgs.msg import Twist
|
||||
|
||||
def main():
|
||||
rclpy.init()
|
||||
node = rclpy.create_node('velocity_publisher')
|
||||
pub = node.create_publisher(Twist, '/cmd_vel', 10)
|
||||
|
||||
msg = Twist()
|
||||
msg.linear.x = 0.5 # 0.5 m/s do przodu
|
||||
msg.angular.z = 0.1 # obrót 0.1 rad/s
|
||||
|
||||
timer = node.create_timer(0.1, lambda: pub.publish(msg)) # co 100ms
|
||||
rclpy.spin(node)
|
||||
|
||||
**MoveIt** — biblioteka ROS do planowania ruchu manipulatorów. Obejmuje: IK, collision avoidance, trajectory planning. Wspiera roboty wielu producentów — klucz do przełamania vendor lock-in.
|
||||
|
||||
# MoveIt — planowanie ruchu w Pythonie:
|
||||
move_group = MoveGroupCommander("arm")
|
||||
move_group.set_pose_target(target_pose) # cel w kartezjańskiej
|
||||
plan = move_group.plan() # automatyczny plan trajektorii
|
||||
move_group.execute(plan) # wykonaj
|
||||
|
||||
#### Orocos (Open Robot Control Software)
|
||||
|
||||
Framework C++ do **hard real-time** sterowania robotów. Tam gdzie ROS nie wystarczy (pętle regulacji < 1ms), Orocos wypełnia lukę. Często łączony z ROS: ROS do komunikacji + Orocos do sterowania.
|
||||
|
||||
---
|
||||
|
||||
### Task-level: PDDL i Behavior Trees
|
||||
|
||||
#### PDDL (Planning Domain Definition Language)
|
||||
|
||||
Język opisu problemów planowania. Definiujesz: stany, akcje z warunkami i efektami, cel. Planner (np. Fast Downward) automatycznie znajduje sekwencję akcji.
|
||||
|
||||
; PDDL — domena: robot pick & place
|
||||
(define (domain robot-world)
|
||||
(:predicates
|
||||
(on-table ?obj)
|
||||
(holding ?obj)
|
||||
(arm-empty))
|
||||
(:action pick
|
||||
:parameters (?obj)
|
||||
:precondition (and (on-table ?obj) (arm-empty))
|
||||
:effect (and (holding ?obj) (not (on-table ?obj)) (not (arm-empty))))
|
||||
(:action place
|
||||
:parameters (?obj)
|
||||
:precondition (holding ?obj)
|
||||
:effect (and (on-table ?obj) (arm-empty) (not (holding ?obj)))))
|
||||
|
||||
; Problem: weź obiektA ze stołu
|
||||
(define (problem pick-a)
|
||||
(:domain robot-world)
|
||||
(:init (on-table objectA) (arm-empty))
|
||||
(:goal (holding objectA)))
|
||||
|
||||
; Planner automatycznie znajdzie: pick(objectA)
|
||||
|
||||
#### Behavior Trees (drzewa zachowań)
|
||||
|
||||
Alternatywa dla maszyn stanów w sterowaniu robotów i postaci w grach. Drzewo składa się z:
|
||||
- **Sequence** (→) — wykonuj dzieci po kolei, przerwij jeśli któreś zawiedzie
|
||||
- **Selector** (?) — próbuj dzieci po kolei, przerwij po pierwszym sukcesie
|
||||
- **Action** — liść: wykonaj akcję
|
||||
- **Condition** — liść: sprawdź warunek
|
||||
|
||||
Behavior Tree: „Pick and Place"
|
||||
[→ Sequence]
|
||||
├── [? Selector: FindObject]
|
||||
│ ├── [Condition: ObjectVisible?]
|
||||
│ └── [Action: SearchForObject]
|
||||
├── [Action: MoveToObject]
|
||||
├── [Action: Grasp]
|
||||
├── [Action: MoveToTarget]
|
||||
└── [Action: Release]
|
||||
|
||||
---
|
||||
|
||||
### Środowiska graficzne
|
||||
|
||||
| Narzędzie | Producent | Typ | Koszt |
|
||||
|-------------|-----------|------------------------|------------------|
|
||||
| RobotStudio | ABB | Offline + symulacja 3D | Licencja / edu |
|
||||
| KUKA.Sim | KUKA | Offline + symulacja 3D | Licencja |
|
||||
| ROBOGUIDE | FANUC | Offline + symulacja 3D | Licencja |
|
||||
| URSim | UR | Symulator kontrolera | Darmowy |
|
||||
| Polyscope | UR | GUI na teach pendancie | Wbudowany |
|
||||
| Blockly | Różni | Graficzne (edukacja) | Open source |
|
||||
| Gazebo | ROS/OSRF | Symulacja fizyczna 3D | Open source |
|
||||
|
||||
### Podsumowanie klasyfikacji
|
||||
|
||||
| Kryterium | Kategorie |
|
||||
|--------------------|----------------------------------------------------------|
|
||||
| **Poziom abstrakcji** | Task → Robot → Motion → Servo (T-R-M-S) |
|
||||
| **Metoda** | Online (teach-in) vs Offline (symulacja) vs Hybrid |
|
||||
| **Zakres** | Vendor-specific (RAPID, KRL, Karel) vs Universal (ROS)|
|
||||
| **Interfejs** | Tekstowy (RAPID, KRL) vs Graficzny (Polyscope, Blockly)|
|
||||
| **Real-time** | Hard RT (Orocos, C/FPGA) vs Soft RT (ROS 2) |
|
||||
|
||||
### Etymologia
|
||||
|
||||
**RAPID** — Robotics Application Programming Interactive Dialogue (ABB). **KRL** — KUKA Robot Language. **Karel** — od Karla Čapka, czeskiego pisarza, który ukuł słowo „robot" (cz. „robota" = ciężka/przymusowa praca) w sztuce R.U.R. (1920). **PDDL** — Planning Domain Definition Language. **MoveIt** — open source do planowania ruchu manipulatora (Willow Garage/PickNik). **Robot** — cz. „robota" = pańszczyzna; Karel Čapek, R.U.R. (1920).
|
||||
**RAPID** — Robotics Application Programming Interactive Dialogue (ABB, 1994). **KRL** — KUKA Robot Language (KUKA, Augsburg). **Karel** — od Karla Čapka, czeskiego pisarza, który ukuł słowo „robot" (cz. „robota" = ciężka/przymusowa praca) w sztuce R.U.R. (Rossum's Universal Robots, 1920). **PDL2** — Programming and Data Language 2 (Comau). **URScript** — Universal Robots Script. **PDDL** — Planning Domain Definition Language (Drew McDermott et al., 1998). **MoveIt** — open source, Willow Garage → PickNik Robotics. **ROS** — Robot Operating System (Willow Garage, 2007 → Open Robotics). **Orocos** — Open Robot Control Software (KU Leuven, Belgia). **TCP** — Tool Center Point (nie mylić z Transmission Control Protocol!). **OMPL** — Open Motion Planning Library. **Cobot** — collaborative robot (termin 1996, Northwestern University).
|
||||
|
||||
### Jak zapamiętać
|
||||
|
||||
- **„Od zadania do serwa: T-R-M-S"**
|
||||
- Każdy producent ma WŁASNY język (vendor lock-in)
|
||||
- ROS próbuje ujednolicić, ale nie dla hard real-time
|
||||
- **„Tomek Robi Mechaniczne Serwa" → T-R-M-S** (Task → Robot → Motion → Servo, od abstrakcji do sprzętu)
|
||||
- **„ABB RAPID jak rapier (szybki miecz)" → MoveL, MoveJ, MoveC** — trzy podstawowe ruchy
|
||||
- **„KUKA KRL = Pascal na sterydach"** — PTP, LIN, CIRC; dwa pliki (.src + .dat)
|
||||
- **„FANUC Karel = Čapek" → MOVE TO** — najprostszy składniowo
|
||||
- **„UR = Python robota" → movel(), movej()** — małe litery, skryptowy, coboty
|
||||
- **„ROS = WhatsApp robotów"** — węzły wysyłają wiadomości na tematy (topics), ale to NIE system operacyjny
|
||||
- **Vendor lock-in → „Program w RAPID na KUKA = jak wtyczka EU w gniazdku UK"** — nie pasuje
|
||||
- **Online = „trzymaj robota za rękę", Offline = „rysuj w symulatorze"**
|
||||
- **MoveIt = „GPS dla ramienia robota"** — planuje trasę z unikaniem przeszkód
|
||||
- **Zone/Approximation = „hamowanie przed zakrętem"** — fine = stop, z50 = przejeżdżaj płynnie
|
||||
|
||||
|
||||
@ -86,8 +86,22 @@ Publishers → **Broker** (router/message bus) → Subscribers
|
||||
|
||||
### Typy subskrypcji: topic-based, content-based, type-based, hierarchical (wildcards)
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### Gwarancje dostarczenia (QoS): At-most-once, At-least-once, Exactly-once
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### Rozwiązania techniczne
|
||||
|
||||
| Technologia | Model | Persistence | Throughput | Use Case |
|
||||
|
||||
@ -36,6 +36,31 @@
|
||||
// ... rób inne obliczenia ...
|
||||
MPI_Wait(&request) ← czekaj na zakończenie
|
||||
|
||||
**Prefiks „I" w MPI_Isend / MPI_Irecv** — oznacza **Immediate** (natychmiastowy). Funkcja wraca natychmiast, bez czekania na zakończenie operacji. Konwencja nazewnicza MPI: prefiks „I" = wersja nieblokująca danej operacji (np. MPI_Send → MPI_**I**send, MPI_Recv → MPI_**I**recv). Analogicznie „S" = Synchronous (MPI_**S**send), „B" = Buffered (MPI_**B**send).
|
||||
|
||||
**Dlaczego Isend/Irecv mogą wrócić natychmiast, skoro dane nie zostały jeszcze przesłane?** — Bo te funkcje NIE wykonują transferu danych. One jedynie **rejestrują żądanie** w bibliotece MPI i wracają. Konkretnie:
|
||||
|
||||
- **MPI_Isend** mówi bibliotece MPI: „chcę wysłać te dane z tego adresu pamięci". MPI zapisuje sobie wskaźnik na bufor, rozmiar, odbiorcę i tag w wewnętrznej strukturze (request object). Transfer nastąpi PÓŹNIEJ — w tle (np. przez osobny wątek komunikacyjny, DMA, lub sprzęt sieciowy RDMA), albo dopiero gdy programista wywoła MPI_Wait/MPI_Test.
|
||||
- **MPI_Irecv** mówi bibliotece MPI: „przygotuj miejsce — gdy dane nadejdą, wpisz je pod ten adres". MPI rejestruje „oczekiwanie na wiadomość" i wraca. Dane mogą jeszcze nie istnieć — to nie problem, bo odbiór nastąpi gdy nadawca faktycznie wyśle.
|
||||
|
||||
Analogia: Isend/Irecv to jak złożenie zamówienia w restauracji — kelner zapisuje zamówienie (wraca natychmiast), ale jedzenie pojawi się dopiero później. MPI_Wait to moment, gdy czekasz na talerz.
|
||||
|
||||
MPI_Isend(buf, n, type, dest, tag, comm, &req)
|
||||
↓
|
||||
[Wewnątrz MPI: zapisz {buf, n, type, dest, tag} w req]
|
||||
↓
|
||||
return; ← NATYCHMIAST — żaden bajt nie został jeszcze wysłany!
|
||||
↓
|
||||
... aplikacja robi obliczenia ...
|
||||
↓
|
||||
MPI_Wait(&req)
|
||||
↓
|
||||
[MPI teraz FAKTYCZNIE przesyła dane / czeka na zakończenie transferu]
|
||||
↓
|
||||
return; ← TERAZ dane są bezpiecznie wysłane, bufor można ponownie użyć
|
||||
|
||||
**UWAGA:** Między Isend a Wait programista NIE MOŻE modyfikować bufora wysyłkowego (buf) — MPI może w dowolnym momencie rozpocząć kopiowanie z tego adresu. Między Irecv a Wait programista NIE MOŻE czytać bufora odbiorczego — dane mogą być jeszcze niekompletne.
|
||||
|
||||
**Kluczowe: synchroniczność ≠ blokowanie!**
|
||||
|
||||
Cecha Synchroniczna Asynchroniczna
|
||||
|
||||