diff --git a/pytania/OBRONA_MAGISTERSKA_ODPOWIEDZI.md b/pytania/OBRONA_MAGISTERSKA_ODPOWIEDZI.md index a2ef190..c4aea80 100644 --- a/pytania/OBRONA_MAGISTERSKA_ODPOWIEDZI.md +++ b/pytania/OBRONA_MAGISTERSKA_ODPOWIEDZI.md @@ -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). + +![Cykl See-Think-Act agenta upostaciowionego](img/agent_see_think_act.png) + +#### 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) + +![Architektura 3T sterownika robota](img/agent_3t_architecture.png) + +#### 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 + +![Model BDI agenta](img/agent_bdi_model.png) + +**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: + +![Behavior Tree — robot przenoszący obiekt](img/agent_behavior_tree.png) + +#### 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 (100ms) - Motion: Trajektoria 50 pkt/s (20ms) - Servo: PID: PWM silnika = 75% (1ms) + Robot: MoveL do_pozycji (100 ms) + Motion: Trajektoria 50 pkt/s (20 ms) + Servo: PID: PWM silnika = 75% (1 ms) + +![Piramida T-R-M-S](img/robot_trms_pyramid.png) --- -**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ń. +**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. -**Trajektoria (trajectory)** — zaplanowana ścieżka ruchu w czasie: sekwencja pozycji + prędkości + przyspieszenia. Interpolacja: liniowa (LIN), kołowa (CIRC), punkt-do-punktu (PTP). + 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ół" + +**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) + +![Typy ruchu robota](img/robot_movement_types.png) --- -**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. +**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: -**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. - -**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. +![Porównanie języków producentów](img/robot_vendor_comparison.png) --- -**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). +**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. -**MoveIt** — biblioteka ROS do planowania ruchu manipulatorów. Obejmuje: IK, collision avoidance, trajectory planning. Open source. + 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 -**PDDL (Planning Domain Definition Language)** — język opisu problemów planowania. Definiujesz: stany, akcje, warunki, cel. Planner automatycznie znajduje sekwencję akcji. Task-level. +**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). -**FPGA (Field-Programmable Gate Array)** — programowalny układ logiczny. Dla servo-level: przetwarzanie sygnałów w nanosekundach. Szybszy niż mikrokontroler, ale trudniejszy w programowaniu. + 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 +![Online vs Offline](img/robot_online_offline.png) -| 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) + +![Struktura programu RAPID](img/robot_rapid_example.png) + +--- + +#### 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ą. + +![Architektura ROS](img/robot_ros_architecture.png) + +**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 diff --git a/pytania/generate_agent_diagrams.py b/pytania/generate_agent_diagrams.py new file mode 100644 index 0000000..d1b4869 --- /dev/null +++ b/pytania/generate_agent_diagrams.py @@ -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) diff --git a/pytania/generate_pattern_diagrams.py b/pytania/generate_pattern_diagrams.py new file mode 100644 index 0000000..d57fb7b --- /dev/null +++ b/pytania/generate_pattern_diagrams.py @@ -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!") diff --git a/pytania/generate_pubsub_diagrams.py b/pytania/generate_pubsub_diagrams.py new file mode 100644 index 0000000..3d57a80 --- /dev/null +++ b/pytania/generate_pubsub_diagrams.py @@ -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!") diff --git a/pytania/generate_robot_lang_diagrams.py b/pytania/generate_robot_lang_diagrams.py new file mode 100644 index 0000000..577fcc7 --- /dev/null +++ b/pytania/generate_robot_lang_diagrams.py @@ -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) diff --git a/pytania/img/agent_3t_architecture.png b/pytania/img/agent_3t_architecture.png new file mode 100644 index 0000000..edb25c1 Binary files /dev/null and b/pytania/img/agent_3t_architecture.png differ diff --git a/pytania/img/agent_bdi_model.png b/pytania/img/agent_bdi_model.png new file mode 100644 index 0000000..7eb2f2a Binary files /dev/null and b/pytania/img/agent_bdi_model.png differ diff --git a/pytania/img/agent_behavior_tree.png b/pytania/img/agent_behavior_tree.png new file mode 100644 index 0000000..d2dff09 Binary files /dev/null and b/pytania/img/agent_behavior_tree.png differ diff --git a/pytania/img/agent_see_think_act.png b/pytania/img/agent_see_think_act.png new file mode 100644 index 0000000..257d326 Binary files /dev/null and b/pytania/img/agent_see_think_act.png differ diff --git a/pytania/img/pubsub_delivery_guarantees.png b/pytania/img/pubsub_delivery_guarantees.png new file mode 100644 index 0000000..356b7ca Binary files /dev/null and b/pytania/img/pubsub_delivery_guarantees.png differ diff --git a/pytania/img/pubsub_qos_at_least_once.png b/pytania/img/pubsub_qos_at_least_once.png new file mode 100644 index 0000000..7a6077d Binary files /dev/null and b/pytania/img/pubsub_qos_at_least_once.png differ diff --git a/pytania/img/pubsub_qos_at_most_once.png b/pytania/img/pubsub_qos_at_most_once.png new file mode 100644 index 0000000..aba7436 Binary files /dev/null and b/pytania/img/pubsub_qos_at_most_once.png differ diff --git a/pytania/img/pubsub_qos_exactly_once.png b/pytania/img/pubsub_qos_exactly_once.png new file mode 100644 index 0000000..fb3e0e4 Binary files /dev/null and b/pytania/img/pubsub_qos_exactly_once.png differ diff --git a/pytania/img/pubsub_sub_content.png b/pytania/img/pubsub_sub_content.png new file mode 100644 index 0000000..5f439dc Binary files /dev/null and b/pytania/img/pubsub_sub_content.png differ diff --git a/pytania/img/pubsub_sub_hierarchical.png b/pytania/img/pubsub_sub_hierarchical.png new file mode 100644 index 0000000..fc393c7 Binary files /dev/null and b/pytania/img/pubsub_sub_hierarchical.png differ diff --git a/pytania/img/pubsub_sub_topic.png b/pytania/img/pubsub_sub_topic.png new file mode 100644 index 0000000..1306afe Binary files /dev/null and b/pytania/img/pubsub_sub_topic.png differ diff --git a/pytania/img/pubsub_sub_type.png b/pytania/img/pubsub_sub_type.png new file mode 100644 index 0000000..2db8b51 Binary files /dev/null and b/pytania/img/pubsub_sub_type.png differ diff --git a/pytania/img/pubsub_subscription_types.png b/pytania/img/pubsub_subscription_types.png new file mode 100644 index 0000000..7444931 Binary files /dev/null and b/pytania/img/pubsub_subscription_types.png differ diff --git a/pytania/img/q14_catalog_map.png b/pytania/img/q14_catalog_map.png new file mode 100644 index 0000000..b269481 Binary files /dev/null and b/pytania/img/q14_catalog_map.png differ diff --git a/pytania/img/q14_pattern_template.png b/pytania/img/q14_pattern_template.png new file mode 100644 index 0000000..9f787ae Binary files /dev/null and b/pytania/img/q14_pattern_template.png differ diff --git a/pytania/img/q14_three_pillars.png b/pytania/img/q14_three_pillars.png new file mode 100644 index 0000000..71e4d97 Binary files /dev/null and b/pytania/img/q14_three_pillars.png differ diff --git a/pytania/img/robot_movement_types.png b/pytania/img/robot_movement_types.png new file mode 100644 index 0000000..f1e8604 Binary files /dev/null and b/pytania/img/robot_movement_types.png differ diff --git a/pytania/img/robot_online_offline.png b/pytania/img/robot_online_offline.png new file mode 100644 index 0000000..c2548c0 Binary files /dev/null and b/pytania/img/robot_online_offline.png differ diff --git a/pytania/img/robot_rapid_example.png b/pytania/img/robot_rapid_example.png new file mode 100644 index 0000000..a7c27a5 Binary files /dev/null and b/pytania/img/robot_rapid_example.png differ diff --git a/pytania/img/robot_ros_architecture.png b/pytania/img/robot_ros_architecture.png new file mode 100644 index 0000000..65a96a1 Binary files /dev/null and b/pytania/img/robot_ros_architecture.png differ diff --git a/pytania/img/robot_trms_pyramid.png b/pytania/img/robot_trms_pyramid.png new file mode 100644 index 0000000..c07f16a Binary files /dev/null and b/pytania/img/robot_trms_pyramid.png differ diff --git a/pytania/img/robot_vendor_comparison.png b/pytania/img/robot_vendor_comparison.png new file mode 100644 index 0000000..2e17455 Binary files /dev/null and b/pytania/img/robot_vendor_comparison.png differ diff --git a/pytania/questions/pytanie_13_27.md b/pytania/questions/pytanie_13_27.md index c30535b..8865505 100644 --- a/pytania/questions/pytanie_13_27.md +++ b/pytania/questions/pytanie_13_27.md @@ -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 diff --git a/pytania/questions/pytanie_14_28.md b/pytania/questions/pytanie_14_28.md index 1879daa..8d85dd0 100644 --- a/pytania/questions/pytanie_14_28.md +++ b/pytania/questions/pytanie_14_28.md @@ -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` diff --git a/pytania/questions/pytanie_15.md b/pytania/questions/pytanie_15.md index c970d53..12628e8 100644 --- a/pytania/questions/pytanie_15.md +++ b/pytania/questions/pytanie_15.md @@ -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). + +![Cykl See-Think-Act agenta upostaciowionego](img/agent_see_think_act.png) + +#### 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) + +![Architektura 3T sterownika robota](img/agent_3t_architecture.png) + +#### 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 + +![Model BDI agenta](img/agent_bdi_model.png) + +**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: + +![Behavior Tree — robot przenoszący obiekt](img/agent_behavior_tree.png) + +#### 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 diff --git a/pytania/questions/pytanie_16.md b/pytania/questions/pytanie_16.md index 9469179..2ff9e29 100644 --- a/pytania/questions/pytanie_16.md +++ b/pytania/questions/pytanie_16.md @@ -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 (100ms) - Motion: Trajektoria 50 pkt/s (20ms) - Servo: PID: PWM silnika = 75% (1ms) + Robot: MoveL do_pozycji (100 ms) + Motion: Trajektoria 50 pkt/s (20 ms) + Servo: PID: PWM silnika = 75% (1 ms) + +![Piramida T-R-M-S](img/robot_trms_pyramid.png) --- -**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ń. +**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. -**Trajektoria (trajectory)** — zaplanowana ścieżka ruchu w czasie: sekwencja pozycji + prędkości + przyspieszenia. Interpolacja: liniowa (LIN), kołowa (CIRC), punkt-do-punktu (PTP). + 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ół" + +**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) + +![Typy ruchu robota](img/robot_movement_types.png) --- -**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. +**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: -**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. - -**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. +![Porównanie języków producentów](img/robot_vendor_comparison.png) --- -**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). +**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. -**MoveIt** — biblioteka ROS do planowania ruchu manipulatorów. Obejmuje: IK, collision avoidance, trajectory planning. Open source. + 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 -**PDDL (Planning Domain Definition Language)** — język opisu problemów planowania. Definiujesz: stany, akcje, warunki, cel. Planner automatycznie znajduje sekwencję akcji. Task-level. +**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). -**FPGA (Field-Programmable Gate Array)** — programowalny układ logiczny. Dla servo-level: przetwarzanie sygnałów w nanosekundach. Szybszy niż mikrokontroler, ale trudniejszy w programowaniu. + 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 +![Online vs Offline](img/robot_online_offline.png) -| 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) + +![Struktura programu RAPID](img/robot_rapid_example.png) + +--- + +#### 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ą. + +![Architektura ROS](img/robot_ros_architecture.png) + +**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 diff --git a/pytania/questions/pytanie_19_29.md b/pytania/questions/pytanie_19_29.md index c8bdb13..a61e6f6 100644 --- a/pytania/questions/pytanie_19_29.md +++ b/pytania/questions/pytanie_19_29.md @@ -86,8 +86,22 @@ Publishers → **Broker** (router/message bus) → Subscribers ### Typy subskrypcji: topic-based, content-based, type-based, hierarchical (wildcards) +![Topic-based](img/pubsub_sub_topic.png) + +![Content-based](img/pubsub_sub_content.png) + +![Type-based](img/pubsub_sub_type.png) + +![Hierarchical (wildcards)](img/pubsub_sub_hierarchical.png) + ### Gwarancje dostarczenia (QoS): At-most-once, At-least-once, Exactly-once +![At-most-once](img/pubsub_qos_at_most_once.png) + +![At-least-once](img/pubsub_qos_at_least_once.png) + +![Exactly-once](img/pubsub_qos_exactly_once.png) + ### Rozwiązania techniczne | Technologia | Model | Persistence | Throughput | Use Case | diff --git a/pytania/questions/pytanie_26.md b/pytania/questions/pytanie_26.md index 5e799e9..7ac7fc0 100644 --- a/pytania/questions/pytanie_26.md +++ b/pytania/questions/pytanie_26.md @@ -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