improve questions 13 14 15 16 19 26

This commit is contained in:
Krzysztof kuhy Rudnicki 2026-02-17 21:08:36 +01:00
parent bd6997e58f
commit 2e5121a6f0
33 changed files with 3058 additions and 97 deletions

View File

@ -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 percepcjadeliberacjaakcja 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) | sekundyminuty | "Jedź trasą A→B→C" |
| **Sequencer** | koordynacja zachowań (PLAN → SEKWENCJA) | 100 mssekundy | 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 = "WiemChcę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 47 osiami obrotu, sterowane komputerowo.
**Język programowania robotów** — język do definiowania zachowania robota: ruchy, logika, I/O. Może być specjalizowany (dedykowany producenta) lub ogólny (C++, Python z bibliotekami). Klasyfikacja wg poziomu abstrakcji — od zadań po sygnały silników.
@ -3505,88 +3637,455 @@ Cykl: **Percepcja → Deliberacja → Akcja** (See-Think-Act)
**Task-level (poziom zadania)** — najwyższy: opisujesz CO robot ma zrobić, nie JAK. „Podnieś A, połóż na B." Robot sam planuje ruchy. Przykłady: PDDL, Behavior Trees.
// Task-level:
// Task-level (pseudokod):
pick(objectA);
place(locationB);
// Robot sam oblicza kinematykę, trajektorię, chwyt
**Robot-level (poziom robota)** — komendy ruchu w przestrzeni kartezjańskiej lub konfiguracyjnej: move_to(x,y,z), grasp(). Programista mówi GDZIE jechać, robot oblicza JAK (kinematyka odwrotna). Przykłady: RAPID (ABB), KRL (KUKA), Karel (FANUC).
// RAPID (ABB):
MoveL p1, v500, fine, tool1; // liniowo do p1, prędkość 500 mm/s
**Robot-level (poziom robota)** — komendy ruchu w przestrzeni kartezjańskiej lub konfiguracyjnej: move_to(x,y,z), grasp(). Programista mówi GDZIE jechać, robot oblicza JAK (kinematyka odwrotna). Tu działają języki producentów: RAPID (ABB), KRL (KUKA), Karel (FANUC), PDL2 (Comau), URScript (Universal Robots).
**Motion-level (poziom ruchu)** — planowanie trajektorii: generowanie ciągu punktów od startu do celu z unikaniem kolizji. Kinematyka odwrotna, interpolacja. Przykłady: MoveIt (ROS), OMPL.
**Servo-level (poziom serwa)** — najniższy: bezpośrednie sterowanie silnikami/serwomechanizmami. Regulacja PID, sygnały PWM. Języki: C/C++, FPGA. Czas reakcji: mikro-milisekundy.
**Servo-level (poziom serwa)** — najniższy: bezpośrednie sterowanie silnikami/serwomechanizmami. Regulacja PID, sygnały PWM. Języki: C/C++, FPGA/VHDL. Czas reakcji: mikro-milisekundy.
Przykład czasu reakcji na każdym poziomie:
Task: "Zamontuj śrubę" (sekundy)
Robot: MoveL do_pozycji (100 ms)
Motion: Trajektoria 50 pkt/s (20 ms)
Servo: PID: PWM silnika = 75% (1 ms)
---
**Kinematyka odwrotna (inverse kinematics, IK)** — obliczenie kątów w stawach robota, aby efektor (np. chwytak) znalazł się w zadanej pozycji. Problem odwrotny: znasz cel, szukasz konfiguracji. Może mieć 0, 1 lub wiele rozwiązań.
**Trajektoria (trajectory)** — zaplanowana ścieżka ruchu w czasie: sekwencja pozycji + prędkości + przyspieszenia. Interpolacja: liniowa (LIN), kołowa (CIRC), punkt-do-punktu (PTP).
![Piramida T-R-M-S](img/robot_trms_pyramid.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.
**Kinematyka odwrotna (inverse kinematics, IK)** — obliczenie kątów w stawach robota, aby efektor (np. chwytak) znalazł się w zadanej pozycji. Problem odwrotny: znasz cel (x,y,z + orientacja), szukasz konfiguracji (kąty q₁…qₙ). Może mieć 0, 1 lub wiele rozwiązań. Robot 6-osiowy: zazwyczaj do 8 rozwiązań dla jednej pozycji.
**Vendor lock-in** — każdy producent ma WŁASNY język. Program napisany w RAPID nie działa na robocie KUKA. To motywacja dla ROS i standardów.
Przykład (robot 2-osiowy, ramiona L₁=L₂=1m, cel: x=1.0, y=1.0):
q₂ = arccos((x²+y²L₁²L₂²) / (2·L₁·L₂))
= arccos((1+111)/2) = arccos(0) = 90°
Dwa rozwiązania: „łokieć do góry" i „łokieć na dół"
**Online vs Offline programming:**
- **Online (teach-in)** — operator prowadzi robota „za rękę" (pendant/teach pendant), robot zapamiętuje punkty. Proste, ale wymaga zatrzymania produkcji.
- **Offline** — programowanie w symulacji (CAD/CAM), bez zatrzymywania robota. Transferujesz gotowy program.
**Trajektoria (trajectory)** — zaplanowana ścieżka ruchu w czasie: sekwencja pozycji + prędkości + przyspieszenia. Trzy typy interpolacji:
- **PTP (Point-to-Point)** — najszybsza, ale ścieżka w przestrzeni kartezjańskiej nieprzewidywalna (interpolacja w przestrzeni stawów)
- **LIN (Linear)** — prosta linia TCP (Tool Center Point); wymaga obliczenia IK w każdym punkcie
- **CIRC (Circular)** — łuk kołowy przez 3 punkty (start, pkt pomocniczy, cel)
![Typy ruchu robota](img/robot_movement_types.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).
**Vendor lock-in** — każdy producent ma WŁASNY język. Program napisany w RAPID nie działa na robocie KUKA. To motywacja dla ROS i standardów. Porównanie języków:
**MoveIt** — biblioteka ROS do planowania ruchu manipulatorów. Obejmuje: IK, collision avoidance, trajectory planning. Open source.
![Porównanie języków producentów](img/robot_vendor_comparison.png)
**PDDL (Planning Domain Definition Language)** — język opisu problemów planowania. Definiujesz: stany, akcje, warunki, cel. Planner automatycznie znajduje sekwencję akcji. Task-level.
---
**FPGA (Field-Programmable Gate Array)** — programowalny układ logiczny. Dla servo-level: przetwarzanie sygnałów w nanosekundach. Szybszy niż mikrokontroler, ale trudniejszy w programowaniu.
**TCP (Tool Center Point)** — punkt centralny narzędzia zamontowanego na końcu ramienia (np. czubek spawarki, środek chwytaka). Wszystkie komendy ruchu LIN i CIRC odnoszą się do TCP — robot steruje tak, żeby ten punkt poruszał się po żądanej ścieżce.
Definiowanie TCP w RAPID:
PERS tooldata tGripper := [TRUE, [[0,0,150],[1,0,0,0]],
[2,[0,0,75],[1,0,0,0],0,0,0]];
// TCP jest 150mm nad kołnierzem, masa narzędzia 2kg
**Strefa zbliżenia (zone)** — parametr określający, jak blisko celu robot musi dojechać zanim zacznie ruch do kolejnego punktu. `fine` = dojazd dokładnie do punktu (zatrzymanie), `z10` = robot zaczyna skręcać w stronę następnego punktu gdy jest 10mm od celu (ruch „na okrągło", płynniejszy i szybszy).
MoveL p1, v500, fine, tool1; // zatrzymaj się dokładnie w p1
MoveL p1, v500, z50, tool1; // zacznij skręcać 50mm przed p1
// z50 → szybszy cykl, ale mniejsza precyzja w punkcie
---
### Klasyfikacja wg poziomu abstrakcji: **T-R-M-S**
1. **Task-level** — „Podnieś A, połóż na B" (PDDL, Behavior Trees)
2. **Robot-level** — move_to(), grasp() (RAPID, KRL, Karel, ROS)
2. **Robot-level** — move_to(), grasp() (RAPID, KRL, Karel, URScript)
3. **Motion-level** — trajektorie, kinematyka odwrotna (MoveIt, OMPL)
4. **Servo-level** — PID, sterowanie silnikami (C/C++, FPGA)
### Klasyfikacja wg metody: Online (teach-in, pendant) vs Offline (symulacja, CAD)
### Klasyfikacja wg metody programowania
### Języki producentów
![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

View File

@ -0,0 +1,391 @@
#!/usr/bin/env python3
"""
Generate diagrams for PYTANIE 15: Agent upostaciowiony w robotyce.
Diagrams:
1. See-Think-Act cycle of an embodied agent
2. 3T Architecture (Planner / Sequencer / Controller)
3. Behavior Tree example (robot pick-and-place)
4. BDI model flow
All: A4-compatible, B&W, 300 DPI, laser-printer-friendly.
"""
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.patches import FancyBboxPatch, FancyArrowPatch, Circle
import numpy as np
import os
DPI = 300
BG = 'white'
LN = 'black'
FS = 8
FS_TITLE = 11
OUTPUT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'img')
os.makedirs(OUTPUT_DIR, exist_ok=True)
GRAY1 = '#E8E8E8'
GRAY2 = '#D0D0D0'
GRAY3 = '#B8B8B8'
GRAY4 = '#F5F5F5'
GRAY5 = '#C0C0C0'
def draw_box(ax, x, y, w, h, text, fill='white', lw=1.2, fontsize=FS,
fontweight='normal', ha='center', va='center', rounded=True):
if rounded:
rect = FancyBboxPatch((x, y), w, h, boxstyle="round,pad=0.05",
lw=lw, edgecolor=LN, facecolor=fill)
else:
rect = mpatches.Rectangle((x, y), w, h, lw=lw, edgecolor=LN, facecolor=fill)
ax.add_patch(rect)
ax.text(x + w/2, y + h/2, text, ha=ha, va=va, fontsize=fontsize,
fontweight=fontweight, wrap=True)
def draw_arrow(ax, x1, y1, x2, y2, lw=1.2, style='->', color=LN, label='', label_offset=0.12):
ax.annotate("", xy=(x2, y2), xytext=(x1, y1),
arrowprops=dict(arrowstyle=style, color=color, lw=lw))
if label:
mx, my = (x1 + x2) / 2, (y1 + y2) / 2 + label_offset
ax.text(mx, my, label, ha='center', va='bottom', fontsize=6.5, color=color)
def draw_dashed_arrow(ax, x1, y1, x2, y2, lw=1.0, color=LN, label='', label_offset=0.12):
ax.annotate("", xy=(x2, y2), xytext=(x1, y1),
arrowprops=dict(arrowstyle='->', color=color, lw=lw,
linestyle='dashed'))
if label:
mx, my = (x1 + x2) / 2, (y1 + y2) / 2 + label_offset
ax.text(mx, my, label, ha='center', va='bottom', fontsize=6.5, color=color)
# ─── DIAGRAM 1: See-Think-Act Cycle ──────────────────────────────
def draw_see_think_act():
fig, ax = plt.subplots(1, 1, figsize=(7, 4.5), facecolor=BG)
ax.set_xlim(0, 7)
ax.set_ylim(0, 4.5)
ax.axis('off')
ax.set_title("Cykl agenta upostaciowionego: Percepcja → Deliberacja → Akcja",
fontsize=FS_TITLE, fontweight='bold', pad=10)
# Environment box (large background)
env_rect = FancyBboxPatch((0.2, 0.2), 6.6, 1.0, boxstyle="round,pad=0.08",
lw=1.5, edgecolor=LN, facecolor=GRAY1,
linestyle='--')
ax.add_patch(env_rect)
ax.text(3.5, 0.7, "ŚRODOWISKO FIZYCZNE\n(przeszkody, obiekty, ludzie)",
ha='center', va='center', fontsize=FS, fontstyle='italic')
# Agent body (large rounded box)
agent_rect = FancyBboxPatch((0.5, 1.5), 6.0, 2.6, boxstyle="round,pad=0.1",
lw=2.0, edgecolor=LN, facecolor=GRAY4)
ax.add_patch(agent_rect)
ax.text(3.5, 3.85, "AGENT UPOSTACIOWIONY (robot)", ha='center', va='center',
fontsize=9, fontweight='bold')
# Three main phases
bw = 1.4
bh = 0.7
by = 2.2
# SEE
draw_box(ax, 0.8, by, bw, bh, "SEE\n(Percepcja)", fill=GRAY2,
fontsize=8, fontweight='bold')
ax.text(1.5, by - 0.2, "kamery, LIDAR\nczujniki dotyku", ha='center',
va='top', fontsize=6, fontstyle='italic')
# THINK
draw_box(ax, 2.8, by, bw, bh, "THINK\n(Deliberacja)", fill=GRAY3,
fontsize=8, fontweight='bold')
ax.text(3.5, by - 0.2, "planowanie trasy\nmodel BDI", ha='center',
va='top', fontsize=6, fontstyle='italic')
# ACT
draw_box(ax, 4.8, by, bw, bh, "ACT\n(Akcja)", fill=GRAY2,
fontsize=8, fontweight='bold')
ax.text(5.5, by - 0.2, "silniki, chwytaki\nkomendy PWM", ha='center',
va='top', fontsize=6, fontstyle='italic')
# Arrows between phases
draw_arrow(ax, 0.8 + bw, by + bh/2, 2.8, by + bh/2, lw=1.5,
label='dane sensoryczne')
draw_arrow(ax, 2.8 + bw, by + bh/2, 4.8, by + bh/2, lw=1.5,
label='komendy sterujące')
# Arrows to/from environment
draw_arrow(ax, 1.5, 1.2, 1.5, by, lw=1.3, label='odczyt', label_offset=0.08)
draw_arrow(ax, 5.5, by, 5.5, 1.2, lw=1.3, label='działanie', label_offset=0.08)
# Feedback loop arrow (from ACT back to environment back to SEE)
ax.annotate("", xy=(1.5, 1.15), xytext=(5.5, 1.15),
arrowprops=dict(arrowstyle='->', color='#555555', lw=1.0,
linestyle='dashed',
connectionstyle="arc3,rad=-0.15"))
ax.text(3.5, 0.35, "← sprzężenie zwrotne (efekt akcji zmienia środowisko) →",
ha='center', va='center', fontsize=6, color='#555555')
fig.tight_layout()
path = os.path.join(OUTPUT_DIR, 'agent_see_think_act.png')
fig.savefig(path, dpi=DPI, bbox_inches='tight', facecolor=BG)
plt.close(fig)
print(f"{path}")
# ─── DIAGRAM 2: 3T Architecture ─────────────────────────────────
def draw_3t_architecture():
fig, ax = plt.subplots(1, 1, figsize=(7, 5.5), facecolor=BG)
ax.set_xlim(0, 7)
ax.set_ylim(0, 5.5)
ax.axis('off')
ax.set_title("Architektura 3T sterownika robota (3-Layer Architecture)",
fontsize=FS_TITLE, fontweight='bold', pad=10)
layers = [
{"y": 4.0, "name": "WARSTWA 3: PLANNER\n(Deliberacja)",
"time": "sekundy \u2013 minuty", "fill": GRAY1,
"example": 'Cel: "Jed\u017a do kuchni po kubek"\nPlanowanie trasy A \u2192 B \u2192 C',
"tech": "Planowanie symboliczne\nA*, graf zada\u0144"},
{"y": 2.6, "name": "WARSTWA 2: SEQUENCER\n(Wykonawca)",
"time": "100 ms \u2013 sekundy", "fill": GRAY2,
"example": "Sekwencja: Jed\u017a do drzwi \u2192\nOtw\u00f3rz \u2192 Jed\u017a do blatu \u2192 Chwy\u0107",
"tech": "FSM, Behavior Trees\nkoordynacja zachowa\u0144"},
{"y": 1.2, "name": "WARSTWA 1: CONTROLLER\n(Reaktywny)",
"time": "milisekundy", "fill": GRAY3,
"example": "PID: utrzymaj pr\u0119dko\u015b\u0107 0.5 m/s\nUnikaj kolizji (emergency stop)",
"tech": "PID, regulacja\nbezpo\u015brednie I/O"},
]
bw = 4.0
bh = 0.85
for i, layer in enumerate(layers):
y = layer["y"]
# Main layer box
draw_box(ax, 0.3, y, bw, bh, layer["name"], fill=layer["fill"],
fontsize=8, fontweight='bold')
# Time label (left)
ax.text(0.15, y + bh/2, layer["time"], ha='right', va='center',
fontsize=6, fontstyle='italic', rotation=0,
bbox=dict(boxstyle='round,pad=0.15', facecolor='white', edgecolor=LN, lw=0.5))
# Example (right side)
draw_box(ax, 4.5, y, 2.3, bh, layer["example"], fill='white',
fontsize=6.5)
# Technology used
# ax.text(4.5 + 1.15, y - 0.12, layer["tech"], ha='center', va='top',
# fontsize=5.5, fontstyle='italic', color='#555555')
# Arrows between layers (downward = commands, upward = status)
for i in range(len(layers) - 1):
y_top = layers[i]["y"]
y_bot = layers[i+1]["y"] + 0.85
# Command arrow (down)
draw_arrow(ax, 1.8, y_top, 1.8, y_bot, lw=1.3, label='polecenia ↓', label_offset=0.02)
# Status arrow (up)
draw_arrow(ax, 2.8, y_bot, 2.8, y_top, lw=1.0, style='->', color='#666666',
label='↑ status', label_offset=0.02)
# Environment at bottom
env_rect = FancyBboxPatch((0.3, 0.3), bw, 0.6, boxstyle="round,pad=0.05",
lw=1.5, edgecolor=LN, facecolor=GRAY4, linestyle='--')
ax.add_patch(env_rect)
ax.text(0.3 + bw/2, 0.6, "SPRZĘT: silniki, czujniki, efektory",
ha='center', va='center', fontsize=7, fontstyle='italic')
# Arrow from controller to hardware
draw_arrow(ax, 2.3, 1.2, 2.3, 0.9, lw=1.3)
# Abstraction label on the right
ax.annotate("", xy=(6.9, 4.8), xytext=(6.9, 0.5),
arrowprops=dict(arrowstyle='<->', color='#888888', lw=1.0))
ax.text(6.95, 2.65, "abstrakcja", ha='left', va='center', fontsize=7,
rotation=90, color='#888888')
fig.tight_layout()
path = os.path.join(OUTPUT_DIR, 'agent_3t_architecture.png')
fig.savefig(path, dpi=DPI, bbox_inches='tight', facecolor=BG)
plt.close(fig)
print(f"{path}")
# ─── DIAGRAM 3: Behavior Tree Example ────────────────────────────
def draw_behavior_tree():
fig, ax = plt.subplots(1, 1, figsize=(7.5, 4.5), facecolor=BG)
ax.set_xlim(0, 7.5)
ax.set_ylim(0, 4.5)
ax.axis('off')
ax.set_title("Behavior Tree: robot przenoszący obiekt (pick-and-place)",
fontsize=FS_TITLE, fontweight='bold', pad=10)
# Node positions: (x, y, text, shape_type)
# shape_type: 'seq' = sequence (→), 'sel' = selector (?), 'act' = action, 'cond' = condition
def draw_bt_node(ax, x, y, text, ntype='act', w=1.0, h=0.45):
"""Draw a behavior tree node."""
if ntype == 'seq':
# Sequence = box with →
rect = FancyBboxPatch((x - w/2, y - h/2), w, h,
boxstyle="round,pad=0.06", lw=1.5,
edgecolor=LN, facecolor=GRAY2)
ax.add_patch(rect)
ax.text(x, y, f"{text}", ha='center', va='center',
fontsize=7, fontweight='bold')
elif ntype == 'sel':
# Selector = box with ?
rect = FancyBboxPatch((x - w/2, y - h/2), w, h,
boxstyle="round,pad=0.06", lw=1.5,
edgecolor=LN, facecolor=GRAY3)
ax.add_patch(rect)
ax.text(x, y, f"? {text}", ha='center', va='center',
fontsize=7, fontweight='bold')
elif ntype == 'cond':
# Condition = diamond-ish / oval with dashed border
rect = FancyBboxPatch((x - w/2, y - h/2), w, h,
boxstyle="round,pad=0.06", lw=1.0,
edgecolor=LN, facecolor='white',
linestyle='--')
ax.add_patch(rect)
ax.text(x, y, text, ha='center', va='center',
fontsize=6.5, fontstyle='italic')
else: # action
rect = FancyBboxPatch((x - w/2, y - h/2), w, h,
boxstyle="round,pad=0.06", lw=1.0,
edgecolor=LN, facecolor=GRAY1)
ax.add_patch(rect)
ax.text(x, y, text, ha='center', va='center', fontsize=6.5)
return x, y
# Root: Sequence "Przenieś obiekt"
root = draw_bt_node(ax, 3.75, 3.8, "Przenieś obiekt", 'seq', w=1.6)
# Level 2 children
find = draw_bt_node(ax, 1.2, 2.8, "Znajdź obiekt", 'sel', w=1.3)
nav = draw_bt_node(ax, 3.75, 2.8, "Jedź do obiektu", 'act', w=1.3)
pick = draw_bt_node(ax, 6.3, 2.8, "Chwyć i dostarcz", 'seq', w=1.4)
# Arrows from root
draw_arrow(ax, root[0], root[1] - 0.225, find[0], find[1] + 0.225, lw=1.0)
draw_arrow(ax, root[0], root[1] - 0.225, nav[0], nav[1] + 0.225, lw=1.0)
draw_arrow(ax, root[0], root[1] - 0.225, pick[0], pick[1] + 0.225, lw=1.0)
# Level 3: children of "Znajdź obiekt" (selector)
vis = draw_bt_node(ax, 0.55, 1.7, "Widzę\nobiekt?", 'cond', w=0.85, h=0.5)
scan = draw_bt_node(ax, 1.85, 1.7, "Skanuj\notoczenie", 'act', w=0.85, h=0.5)
draw_arrow(ax, find[0], find[1] - 0.225, vis[0], vis[1] + 0.25, lw=0.8)
draw_arrow(ax, find[0], find[1] - 0.225, scan[0], scan[1] + 0.25, lw=0.8)
# Level 3: children of "Chwyć i dostarcz" (sequence)
grasp = draw_bt_node(ax, 5.4, 1.7, "Chwyć\nobject", 'act', w=0.85, h=0.5)
deliver = draw_bt_node(ax, 6.5, 1.7, "Jedź do\ncelu", 'act', w=0.85, h=0.5)
release = draw_bt_node(ax, 7.2, 1.7, "Puść", 'act', w=0.55, h=0.5)
draw_arrow(ax, pick[0], pick[1] - 0.225, grasp[0], grasp[1] + 0.25, lw=0.8)
draw_arrow(ax, pick[0], pick[1] - 0.225, deliver[0], deliver[1] + 0.25, lw=0.8)
draw_arrow(ax, pick[0], pick[1] - 0.225, release[0], release[1] + 0.25, lw=0.8)
# Legend
leg_y = 0.5
draw_bt_node(ax, 0.8, leg_y, "→ Sequence", 'seq', w=1.1, h=0.35)
draw_bt_node(ax, 2.3, leg_y, "? Selector", 'sel', w=1.0, h=0.35)
draw_bt_node(ax, 3.6, leg_y, "Akcja", 'act', w=0.8, h=0.35)
draw_bt_node(ax, 4.8, leg_y, "Warunek", 'cond', w=0.8, h=0.35)
ax.text(0.3, leg_y, "Legenda:", ha='left', va='center', fontsize=6.5,
fontweight='bold')
# Execution note
ax.text(3.75, 0.05, "Wykonanie: od lewej do prawej. Sequence (→) = wszystkie po kolei. "
"Selector (?) = pierwszy sukces.",
ha='center', va='center', fontsize=6, fontstyle='italic', color='#555555')
fig.tight_layout()
path = os.path.join(OUTPUT_DIR, 'agent_behavior_tree.png')
fig.savefig(path, dpi=DPI, bbox_inches='tight', facecolor=BG)
plt.close(fig)
print(f"{path}")
# ─── DIAGRAM 4: BDI Model ────────────────────────────────────────
def draw_bdi_model():
fig, ax = plt.subplots(1, 1, figsize=(7, 4), facecolor=BG)
ax.set_xlim(0, 7)
ax.set_ylim(0, 4)
ax.axis('off')
ax.set_title("Model BDI agenta (BeliefsDesiresIntentions)",
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)

View File

@ -0,0 +1,297 @@
#!/usr/bin/env python3
"""
Generate pattern cataloguing diagrams for PYTANIE 14 (AIS):
1. Pattern Template Structure the standard fields every pattern has
2. Catalog Classification Map catalogs arranged by scope & domain
3. Pattern Language Network how patterns reference each other
All: A4-compatible, B&W, 300 DPI, laser-printer-friendly.
"""
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.patches import FancyBboxPatch, FancyArrowPatch
import numpy as np
import os
DPI = 300
BG = 'white'
LN = 'black'
FS = 9
FS_TITLE = 13
FS_SMALL = 7.5
OUTPUT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'img')
os.makedirs(OUTPUT_DIR, exist_ok=True)
GRAY1 = '#E8E8E8'
GRAY2 = '#D0D0D0'
GRAY3 = '#B8B8B8'
GRAY4 = '#F5F5F5'
GRAY5 = '#C0C0C0'
def draw_box(ax, x, y, w, h, text, fill='white', lw=1.2, fontsize=FS,
fontweight='normal', ha='center', va='center', rounded=True):
if rounded:
rect = FancyBboxPatch((x, y), w, h, boxstyle="round,pad=0.08",
lw=lw, edgecolor=LN, facecolor=fill)
else:
rect = mpatches.Rectangle((x, y), w, h, lw=lw, edgecolor=LN, facecolor=fill)
ax.add_patch(rect)
ax.text(x + w / 2, y + h / 2, text, ha=ha, va=va, fontsize=fontsize,
fontweight=fontweight, wrap=True)
def draw_arrow(ax, x1, y1, x2, y2, lw=1.2, style='->', color=LN):
ax.annotate("", xy=(x2, y2), xytext=(x1, y1),
arrowprops=dict(arrowstyle=style, color=color, lw=lw))
# ============================================================
# 1. Pattern Template Structure (NaPSiRoKo mnemonic)
# ============================================================
def generate_pattern_template():
fig, ax = plt.subplots(figsize=(8.27, 6))
ax.set_xlim(0, 10)
ax.set_ylim(0, 8)
ax.set_aspect('equal')
ax.axis('off')
fig.patch.set_facecolor(BG)
ax.set_title('Szablon opisu wzorca \u2014 \u201eNaPSiRoKo\u201d',
fontsize=FS_TITLE, fontweight='bold', pad=15)
# Main card outline
card_x, card_y, card_w, card_h = 1.5, 0.5, 7, 7
card = FancyBboxPatch((card_x, card_y), card_w, card_h,
boxstyle="round,pad=0.15", lw=2.5,
edgecolor=LN, facecolor=GRAY4)
ax.add_patch(card)
# Title of card
ax.text(card_x + card_w / 2, card_y + card_h - 0.35,
"KARTA WZORCA", ha='center', va='center',
fontsize=FS_TITLE, fontweight='bold')
# Fields as horizontal bands
fields = [
("Na", "NAZWA", "Layered, Observer, Microservices", GRAY1),
("P", "PROBLEM / KONTEKST", "Kiedy stosować? Jaki problem rozwiązuje?", 'white'),
("Si", "SIŁY (forces)", "Konkurencyjne wymagania do pogodzenia\n(np. testowalność vs wydajność)", GRAY1),
("Ro", "ROZWIĄZANIE", "Struktura, diagram, zachowanie", 'white'),
("Ko", "KONSEKWENCJE", "Tradeoffs: co zyskujemy, co tracimy", GRAY1),
]
band_x = card_x + 0.3
band_w = card_w - 0.6
band_h = 1.05
start_y = card_y + card_h - 1.1
for i, (abbr, title, desc, fill) in enumerate(fields):
by = start_y - i * (band_h + 0.15)
# Abbreviation circle on the left
circle = plt.Circle((band_x + 0.35, by + band_h / 2), 0.28,
lw=1.5, edgecolor=LN, facecolor=GRAY2)
ax.add_patch(circle)
ax.text(band_x + 0.35, by + band_h / 2, abbr, ha='center', va='center',
fontsize=10, fontweight='bold')
# Field box
fx = band_x + 0.8
fw = band_w - 0.8
rect = FancyBboxPatch((fx, by), fw, band_h,
boxstyle="round,pad=0.06", lw=1,
edgecolor=LN, facecolor=fill)
ax.add_patch(rect)
ax.text(fx + 0.15, by + band_h - 0.25, title, ha='left', va='center',
fontsize=FS, fontweight='bold')
ax.text(fx + 0.15, by + 0.25, desc, ha='left', va='center',
fontsize=FS_SMALL, fontstyle='italic', color='#444444')
# Arrow connecting fields
if i < len(fields) - 1:
draw_arrow(ax, band_x + 0.35, by - 0.02,
band_x + 0.35, by - 0.13, lw=1.0)
# Extra fields note at bottom
ax.text(card_x + card_w / 2, card_y + 0.25,
"+ Powiązane wzorce • Znane zastosowania • Warianty",
ha='center', va='center', fontsize=FS_SMALL, fontstyle='italic')
# Mnemonic reminder on the right
ax.text(9.8, 4, "Mnemonik:\nNaPSiRoKo",
ha='center', va='center', fontsize=10, fontweight='bold',
rotation=90, color='#666666')
fig.tight_layout()
out = os.path.join(OUTPUT_DIR, 'q14_pattern_template.png')
fig.savefig(out, dpi=DPI, bbox_inches='tight', facecolor=BG)
plt.close(fig)
print(f" Saved: {out}")
# ============================================================
# 2. Catalog Classification Map
# ============================================================
def generate_catalog_map():
fig, ax = plt.subplots(figsize=(8.27, 7))
ax.set_xlim(0, 12)
ax.set_ylim(0, 9)
ax.set_aspect('equal')
ax.axis('off')
fig.patch.set_facecolor(BG)
ax.set_title('Mapa katalog\u00f3w wzorc\u00f3w \u2014 \u201ePawe\u0142 Gra\u0142 Efektownie Pod Chmurami\u201d',
fontsize=FS_TITLE, fontweight='bold', pad=15)
# Y-axis: Scale (architectural → design → idiom)
ax.text(0.3, 7.8, "SKALA", fontsize=10, fontweight='bold',
ha='center', va='center', rotation=90)
ax.annotate("", xy=(0.3, 2.0), xytext=(0.3, 7.5),
arrowprops=dict(arrowstyle='->', lw=1.5, color=LN))
scale_labels = [
(7.0, "Architektoniczny\n(cały system)"),
(5.0, "Projektowy\n(klasa/obiekt)"),
(3.0, "Idiomatyczny\n(linia kodu)"),
]
for sy, label in scale_labels:
ax.text(1.0, sy, label, fontsize=FS_SMALL, ha='left', va='center',
fontstyle='italic')
ax.plot([0.15, 0.45], [sy, sy], color=GRAY3, lw=0.8, ls='--')
# X-axis: Domain
ax.text(6.5, 1.2, "DOMENA ZASTOSOWANIA", fontsize=10, fontweight='bold',
ha='center', va='center')
ax.annotate("", xy=(11.5, 1.5), xytext=(2.0, 1.5),
arrowprops=dict(arrowstyle='->', lw=1.5, color=LN))
# Catalog boxes positioned by scale × domain
catalogs = [
# (x, y, w, h, name, subtitle, fill, mnemonic_letter)
(2.5, 6.2, 2.5, 1.4, "POSA", "1996 • Buschmann\nLayers, Broker,\nPipes & Filters, MVC", GRAY1, "P"),
(2.5, 4.2, 2.5, 1.4, "GoF", "1994 • Gamma et al.\n23 wzorce:\n5 kreac. / 7 strukt. / 11 behaw.", GRAY2, "G"),
(5.5, 6.2, 2.5, 1.4, "EIP", "2003 • Hohpe & Woolf\nMessage Channel,\nRouter, Aggregator", GRAY1, "E"),
(5.5, 4.2, 2.5, 1.4, "PoEAA", "2002 • M. Fowler\nRepository, Unit of Work,\nDomain Model", 'white', "P"),
(8.5, 6.2, 2.8, 1.4, "Cloud\nPatterns", "~2015 • Azure/AWS\nCircuit Breaker,\nSaga, Sidecar", GRAY1, "C"),
]
for cx, cy, cw, ch, name, sub, fill, ml in catalogs:
rect = FancyBboxPatch((cx, cy), cw, ch, boxstyle="round,pad=0.1",
lw=1.5, edgecolor=LN, facecolor=fill)
ax.add_patch(rect)
ax.text(cx + cw / 2, cy + ch - 0.3, name, ha='center', va='center',
fontsize=10, fontweight='bold')
ax.text(cx + cw / 2, cy + 0.4, sub, ha='center', va='center',
fontsize=FS_SMALL, linespacing=1.3)
# Mnemonic letter in corner
circle = plt.Circle((cx + 0.25, cy + ch - 0.25), 0.2,
lw=1, edgecolor=LN, facecolor=GRAY5)
ax.add_patch(circle)
ax.text(cx + 0.25, cy + ch - 0.25, ml, ha='center', va='center',
fontsize=8, fontweight='bold')
# Mnemonic bar at bottom
mnem_y = 2.2
ax.text(6.0, mnem_y, "PGEP+C → Paweł Grał Efektownie Pod Chmurami",
ha='center', va='center', fontsize=10, fontweight='bold',
bbox=dict(boxstyle='round,pad=0.3', facecolor=GRAY4, edgecolor=LN, lw=1.5))
# Domain labels along x-axis
domains = [
(3.75, 1.7, "Architektura"),
(6.75, 1.7, "Integracja / Enterprise"),
(9.9, 1.7, "Chmura"),
]
for dx, dy, dlabel in domains:
ax.text(dx, dy, dlabel, ha='center', va='center',
fontsize=FS_SMALL, fontstyle='italic')
fig.tight_layout()
out = os.path.join(OUTPUT_DIR, 'q14_catalog_map.png')
fig.savefig(out, dpi=DPI, bbox_inches='tight', facecolor=BG)
plt.close(fig)
print(f" Saved: {out}")
# ============================================================
# 3. Three Pillars of Cataloguing
# ============================================================
def generate_three_pillars():
fig, ax = plt.subplots(figsize=(8.27, 5.5))
ax.set_xlim(0, 12)
ax.set_ylim(0, 7)
ax.set_aspect('equal')
ax.axis('off')
fig.patch.set_facecolor(BG)
ax.set_title("Jak są katalogowane wzorce? — Trzy filary",
fontsize=FS_TITLE, fontweight='bold', pad=15)
# Roof / banner
roof_pts = np.array([[1, 5.5], [6, 6.8], [11, 5.5]])
roof = plt.Polygon(roof_pts, closed=True, lw=2,
edgecolor=LN, facecolor=GRAY4)
ax.add_patch(roof)
ax.text(6, 6.0, "KATALOGOWANIE WZORCÓW",
ha='center', va='center', fontsize=11, fontweight='bold')
# Three pillars
pillars = [
(1.3, "1. SZABLON\nOPISU",
"Każdy wzorzec ma\nte same pola:\nNazwa → Problem\n→ Siły → Rozwiązanie\n→ Konsekwencje",
"Analogia:\nformatka\nencyklopedii"),
(4.8, "2. KLASYFIKACJA\nWIELOOSIOWA",
"Osie podziału:\n• Skala (arch/proj/idiom)\n• Domena problemu\n• Atrybut jakościowy\n• Domena zastosowania",
"Analogia:\nkategorie\nw bibliotece"),
(8.3, "3. JĘZYK\nWZORCÓW",
"Wzorce referują się\nwzajemnie tworząc\nsieć/graf:\nA → wymaga → B\nB → wariant → C",
"Analogia:\n\u201ezobacz te\u017c\u201d\nw encyklopedii"),
]
for px, title, desc, analogy in pillars:
pw, ph = 2.8, 5.0
py = 0.5
# Pillar rectangle
rect = FancyBboxPatch((px, py), pw, ph, boxstyle="round,pad=0.1",
lw=1.8, edgecolor=LN, facecolor='white')
ax.add_patch(rect)
# Title
ax.text(px + pw / 2, py + ph - 0.55, title, ha='center', va='center',
fontsize=9, fontweight='bold')
# Horizontal line under title
ax.plot([px + 0.2, px + pw - 0.2], [py + ph - 1.0, py + ph - 1.0],
color=LN, lw=0.8)
# Description
ax.text(px + pw / 2, py + ph / 2 - 0.3, desc, ha='center', va='center',
fontsize=FS_SMALL, linespacing=1.4)
# Analogy box at bottom
analogy_rect = FancyBboxPatch((px + 0.2, py + 0.15), pw - 0.4, 1.0,
boxstyle="round,pad=0.06", lw=0.8,
edgecolor=GRAY3, facecolor=GRAY1)
ax.add_patch(analogy_rect)
ax.text(px + pw / 2, py + 0.65, analogy, ha='center', va='center',
fontsize=FS_SMALL, fontstyle='italic', color='#555555')
fig.tight_layout()
out = os.path.join(OUTPUT_DIR, 'q14_three_pillars.png')
fig.savefig(out, dpi=DPI, bbox_inches='tight', facecolor=BG)
plt.close(fig)
print(f" Saved: {out}")
# ============================================================
# Main
# ============================================================
if __name__ == '__main__':
print("Generating PYTANIE 14 diagrams...")
generate_pattern_template()
generate_catalog_map()
generate_three_pillars()
print("Done!")

View File

@ -0,0 +1,451 @@
#!/usr/bin/env python3
"""
Generate Pub/Sub diagrams for PYTANIE 19:
Subscription types (4 separate images):
1. Topic-based
2. Content-based
3. Type-based
4. Hierarchical (wildcards)
Delivery guarantees (3 separate images):
5. At-most-once
6. At-least-once
7. Exactly-once
All: A4-width, B&W, 300 DPI, laser-printer-friendly.
One diagram per image no cramming.
"""
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.patches import FancyBboxPatch
import os
DPI = 300
BG = 'white'
LN = 'black'
FS = 9
FS_TITLE = 13
FIG_W = 8.27 # A4 width in inches
OUTPUT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'img')
os.makedirs(OUTPUT_DIR, exist_ok=True)
GRAY1 = '#E8E8E8'
GRAY2 = '#D0D0D0'
GRAY3 = '#B8B8B8'
GRAY4 = '#F5F5F5'
GRAY5 = '#C0C0C0'
def draw_box(ax, x, y, w, h, text, fill='white', lw=1.2, fontsize=FS,
fontweight='normal', ha='center', va='center', rounded=True):
if rounded:
rect = FancyBboxPatch((x, y), w, h, boxstyle="round,pad=0.05",
lw=lw, edgecolor=LN, facecolor=fill)
else:
rect = mpatches.Rectangle((x, y), w, h, lw=lw, edgecolor=LN, facecolor=fill)
ax.add_patch(rect)
ax.text(x + w/2, y + h/2, text, ha=ha, va=va, fontsize=fontsize,
fontweight=fontweight, wrap=True)
def draw_arrow(ax, x1, y1, x2, y2, lw=1.2, style='->', color=LN, label='',
label_offset=0.15, label_fs=8):
ax.annotate("", xy=(x2, y2), xytext=(x1, y1),
arrowprops=dict(arrowstyle=style, color=color, lw=lw))
if label:
mx, my = (x1 + x2) / 2, (y1 + y2) / 2 + label_offset
ax.text(mx, my, label, ha='center', va='bottom', fontsize=label_fs, color=color)
def draw_dashed_arrow(ax, x1, y1, x2, y2, lw=1.0, color=LN, label='',
label_offset=0.15, label_fs=8):
ax.annotate("", xy=(x2, y2), xytext=(x1, y1),
arrowprops=dict(arrowstyle='->', color=color, lw=lw,
linestyle='dashed'))
if label:
mx, my = (x1 + x2) / 2, (y1 + y2) / 2 + label_offset
ax.text(mx, my, label, ha='center', va='bottom', fontsize=label_fs, color=color)
def draw_cross(ax, x, y, size=0.15, lw=2.5, color='black'):
ax.plot([x - size, x + size], [y - size, y + size], color=color, lw=lw)
ax.plot([x - size, x + size], [y + size, y - size], color=color, lw=lw)
def draw_check(ax, x, y, size=0.15, lw=2.5, color='black'):
ax.plot([x - size, x - size*0.2], [y, y - size*0.7], color=color, lw=lw)
ax.plot([x - size*0.2, x + size], [y - size*0.7, y + size*0.5], color=color, lw=lw)
def save(fig, name):
plt.tight_layout()
fig.savefig(os.path.join(OUTPUT_DIR, name), dpi=DPI,
bbox_inches='tight', facecolor=BG)
plt.close(fig)
print(f"{name}")
# ============================================================
# 1. Topic-based subscription
# ============================================================
def draw_sub_topic():
fig, ax = plt.subplots(1, 1, figsize=(FIG_W, 4.0))
ax.set_xlim(0, 12)
ax.set_ylim(0, 5.5)
ax.set_aspect('equal')
ax.axis('off')
ax.set_title('Subskrypcja topic-based — routing po nazwie tematu',
fontsize=FS_TITLE, fontweight='bold', pad=12)
# Publisher + messages
draw_box(ax, 0.2, 3.2, 2.4, 1.1, 'Publisher', fill=GRAY1, fontsize=10, fontweight='bold')
draw_box(ax, 0.3, 1.8, 2.2, 0.8, 'topic: "orders"', fill=GRAY4, fontsize=8)
draw_box(ax, 0.3, 0.7, 2.2, 0.8, 'topic: "payments"', fill=GRAY4, fontsize=8)
# Broker
draw_box(ax, 4.2, 1.5, 2.8, 2.2, 'BROKER\n\ntopic routing', fill=GRAY2, fontsize=10, fontweight='bold')
# Subscribers
draw_box(ax, 8.5, 3.8, 3.0, 1.0, 'Subscriber A\nsubskrybuje: "orders"', fill=GRAY1, fontsize=8.5)
draw_box(ax, 8.5, 2.2, 3.0, 1.0, 'Subscriber B\nsubskrybuje: "payments"', fill=GRAY1, fontsize=8.5)
draw_box(ax, 8.5, 0.6, 3.0, 1.0, 'Subscriber C\nsubskrybuje: "orders"', fill=GRAY1, fontsize=8.5)
# Arrows: publisher → broker
draw_arrow(ax, 2.6, 2.2, 4.2, 2.8, label_fs=8)
draw_arrow(ax, 2.6, 1.1, 4.2, 2.2, label_fs=8)
# Arrows: broker → subscribers
draw_arrow(ax, 7.0, 3.4, 8.5, 4.2, label='"orders"', label_fs=8)
draw_arrow(ax, 7.0, 2.6, 8.5, 2.7, label='"payments"', label_fs=8)
draw_arrow(ax, 7.0, 2.2, 8.5, 1.2, label='"orders"', label_fs=8)
# Explanation
ax.text(6.0, 0.1, 'Subscriber deklaruje nazwę tematu. Broker kieruje wiadomości\n'
'do WSZYSTKICH subscriberów danego tematu. Najprostszy model.',
ha='center', va='bottom', fontsize=8.5, style='italic',
bbox=dict(boxstyle='round,pad=0.3', facecolor=GRAY4, edgecolor=GRAY3))
save(fig, 'pubsub_sub_topic.png')
# ============================================================
# 2. Content-based subscription
# ============================================================
def draw_sub_content():
fig, ax = plt.subplots(1, 1, figsize=(FIG_W, 4.5))
ax.set_xlim(0, 12)
ax.set_ylim(0, 6)
ax.set_aspect('equal')
ax.axis('off')
ax.set_title('Subskrypcja content-based — filtrowanie po treści wiadomości',
fontsize=FS_TITLE, fontweight='bold', pad=12)
# Publisher + message
draw_box(ax, 0.2, 3.5, 2.4, 1.1, 'Publisher', fill=GRAY1, fontsize=10, fontweight='bold')
draw_box(ax, 0.2, 1.8, 2.4, 1.2, 'price: 150\ntype: "book"\ncategory: "IT"', fill=GRAY4, fontsize=8.5)
# Broker
draw_box(ax, 4.0, 2.0, 3.0, 2.5, 'BROKER\n\newaluuje filtry\nkażdego subscribera', fill=GRAY2, fontsize=9, fontweight='bold')
# Subscribers with filters
draw_box(ax, 8.5, 4.2, 3.2, 1.0, 'Sub A\nfiltr: price > 100', fill=GRAY1, fontsize=9)
draw_box(ax, 8.5, 2.6, 3.2, 1.0, 'Sub B\nfiltr: type = "food"', fill=GRAY1, fontsize=9)
draw_box(ax, 8.5, 1.0, 3.2, 1.0, 'Sub C\nfiltr: price < 50', fill=GRAY1, fontsize=9)
# Arrows
draw_arrow(ax, 2.6, 2.4, 4.0, 3.0)
draw_arrow(ax, 7.0, 4.0, 8.5, 4.6, label='150 > 100 ✓ dostarczono', label_fs=8)
draw_dashed_arrow(ax, 7.0, 3.2, 8.5, 3.1, label='"book""food" ✗ odrzucono', label_fs=8)
draw_dashed_arrow(ax, 7.0, 2.5, 8.5, 1.6, label='150 < 50 ✗ odrzucono', label_fs=8)
ax.text(6.0, 0.2, 'Broker analizuje TREŚĆ wiadomości i ewaluuje predykaty.\n'
'Bardziej elastyczny niż topic-based, ale wolniejszy (koszt ewaluacji).',
ha='center', va='bottom', fontsize=8.5, style='italic',
bbox=dict(boxstyle='round,pad=0.3', facecolor=GRAY4, edgecolor=GRAY3))
save(fig, 'pubsub_sub_content.png')
# ============================================================
# 3. Type-based subscription
# ============================================================
def draw_sub_type():
fig, ax = plt.subplots(1, 1, figsize=(FIG_W, 5.0))
ax.set_xlim(0, 12)
ax.set_ylim(0, 6.5)
ax.set_aspect('equal')
ax.axis('off')
ax.set_title('Subskrypcja type-based — routing po typie (klasie) obiektu',
fontsize=FS_TITLE, fontweight='bold', pad=12)
# Publisher
draw_box(ax, 0.2, 4.2, 2.4, 1.1, 'Publisher', fill=GRAY1, fontsize=10, fontweight='bold')
# Messages
draw_box(ax, 0.1, 2.8, 2.6, 0.9, 'new OrderEvent()', fill=GRAY4, fontsize=9)
draw_box(ax, 0.1, 1.5, 2.6, 0.9, 'new PaymentEvent()', fill=GRAY4, fontsize=9)
# Broker
draw_box(ax, 4.0, 2.3, 3.0, 2.4, 'BROKER\n\nrouting po\ntypie klasy', fill=GRAY2, fontsize=10, fontweight='bold')
# Subscribers
draw_box(ax, 8.5, 4.8, 3.2, 1.0, 'Sub A\n→ OrderEvent', fill=GRAY1, fontsize=9)
draw_box(ax, 8.5, 3.2, 3.2, 1.0, 'Sub B\n→ PaymentEvent', fill=GRAY1, fontsize=9)
draw_box(ax, 8.5, 1.6, 3.2, 1.0, 'Sub C\n→ Event (base)', fill=GRAY1, fontsize=9)
# Arrows
draw_arrow(ax, 2.7, 3.2, 4.0, 3.8)
draw_arrow(ax, 2.7, 2.0, 4.0, 3.0)
draw_arrow(ax, 7.0, 4.3, 8.5, 5.2, label='OrderEvent', label_fs=8)
draw_arrow(ax, 7.0, 3.5, 8.5, 3.7, label='PaymentEvent', label_fs=8)
draw_arrow(ax, 7.0, 3.0, 8.5, 2.2, label='oba (dziedziczenie!)', label_fs=8)
# Class hierarchy inset
hx, hy = 0.5, 0.0
draw_box(ax, hx + 2.0, hy + 0.2, 1.8, 0.6, 'Event', fill=GRAY3, fontsize=8, fontweight='bold')
draw_box(ax, hx + 0.0, hy + 0.2, 1.8, 0.6, 'OrderEvent', fill=GRAY4, fontsize=7.5)
draw_box(ax, hx + 4.0, hy + 0.2, 2.0, 0.6, 'PaymentEvent', fill=GRAY4, fontsize=7.5)
draw_arrow(ax, hx + 2.9, hy + 0.2, hx + 0.9, hy + 0.2, lw=1.0, style='->', label='extends', label_offset=-0.3, label_fs=7)
draw_arrow(ax, hx + 2.9, hy + 0.2, hx + 5.0, hy + 0.2, lw=1.0, style='->', label='extends', label_offset=-0.3, label_fs=7)
ax.text(9.5, 0.5, 'Sub C subskrybuje bazowy Event\n→ otrzymuje WSZYSTKIE podtypy',
ha='center', va='center', fontsize=8.5, style='italic',
bbox=dict(boxstyle='round,pad=0.3', facecolor=GRAY4, edgecolor=GRAY3))
save(fig, 'pubsub_sub_type.png')
# ============================================================
# 4. Hierarchical / Wildcards subscription
# ============================================================
def draw_sub_hierarchical():
fig, ax = plt.subplots(1, 1, figsize=(FIG_W, 5.5))
ax.set_xlim(0, 12)
ax.set_ylim(0, 7)
ax.set_aspect('equal')
ax.axis('off')
ax.set_title('Subskrypcja hierarchiczna (wildcards) — wzorce tematów',
fontsize=FS_TITLE, fontweight='bold', pad=12)
# Topic tree
draw_box(ax, 4.5, 5.8, 2.4, 0.8, 'sensors/', fill=GRAY2, fontsize=10, fontweight='bold')
draw_box(ax, 1.5, 4.2, 2.4, 0.8, 'temperature/', fill=GRAY3, fontsize=9)
draw_box(ax, 7.5, 4.2, 2.4, 0.8, 'humidity/', fill=GRAY3, fontsize=9)
draw_box(ax, 0.2, 2.8, 1.8, 0.7, 'room1', fill=GRAY4, fontsize=8.5)
draw_box(ax, 2.4, 2.8, 1.8, 0.7, 'room2', fill=GRAY4, fontsize=8.5)
draw_box(ax, 6.8, 2.8, 1.8, 0.7, 'room1', fill=GRAY4, fontsize=8.5)
draw_box(ax, 9.0, 2.8, 1.8, 0.7, 'room2', fill=GRAY4, fontsize=8.5)
# Tree edges
draw_arrow(ax, 5.7, 5.8, 2.7, 5.0, lw=1.0)
draw_arrow(ax, 5.7, 5.8, 8.7, 5.0, lw=1.0)
draw_arrow(ax, 2.2, 4.2, 1.1, 3.5, lw=1.0)
draw_arrow(ax, 3.2, 4.2, 3.3, 3.5, lw=1.0)
draw_arrow(ax, 8.2, 4.2, 7.7, 3.5, lw=1.0)
draw_arrow(ax, 9.2, 4.2, 9.9, 3.5, lw=1.0)
# Full paths
ax.text(1.1, 2.4, 'sensors/temperature/room1', fontsize=7, ha='center',
fontfamily='monospace', style='italic')
ax.text(3.3, 2.4, 'sensors/temperature/room2', fontsize=7, ha='center',
fontfamily='monospace', style='italic')
# Wildcard examples
ax.text(0.3, 1.5, 'Wzorce subskrypcji (MQTT-style):', fontsize=10, fontweight='bold')
patterns = [
('"sensors/temperature/room1"', '→ TYLKO room1', '(dokładne dopasowanie)'),
('"sensors/temperature/*"', '→ room1, room2', '( * = jeden poziom)'),
('"sensors/#"', '→ WSZYSTKO', '( # = dowolna głębokość)'),
]
for i, (pat, result, note) in enumerate(patterns):
yy = 0.9 - i * 0.55
ax.text(0.5, yy, pat, fontsize=9, fontweight='bold', fontfamily='monospace')
ax.text(7.0, yy, result, fontsize=9, fontweight='bold')
ax.text(9.5, yy, note, fontsize=8, style='italic')
save(fig, 'pubsub_sub_hierarchical.png')
# ============================================================
# 5. At-most-once (QoS 0)
# ============================================================
def draw_qos_at_most_once():
fig, ax = plt.subplots(1, 1, figsize=(FIG_W, 4.5))
ax.set_xlim(0, 12)
ax.set_ylim(0, 6)
ax.set_aspect('equal')
ax.axis('off')
ax.set_title('QoS: At-most-once — „wyślij i zapomnij" (0 lub 1 dostarczenie)',
fontsize=FS_TITLE, fontweight='bold', pad=12)
# Actors
px, bx, sx = 1.0, 4.8, 8.5
pw, bw, sw = 2.0, 2.2, 2.0
bh = 0.8
draw_box(ax, px, 5.0, pw, bh, 'Publisher', fill=GRAY1, fontsize=10, fontweight='bold')
draw_box(ax, bx, 5.0, bw, bh, 'Broker', fill=GRAY2, fontsize=10, fontweight='bold')
draw_box(ax, sx, 5.0, sw, bh, 'Subscriber', fill=GRAY1, fontsize=10, fontweight='bold')
# Timelines
for xc in [px + pw/2, bx + bw/2, sx + sw/2]:
ax.plot([xc, xc], [5.0, 1.2], color=GRAY3, lw=1, linestyle=':')
# Scenario A: success
y = 4.3
ax.text(0.2, y + 0.15, 'Scenariusz A:', fontsize=8.5, fontweight='bold')
draw_arrow(ax, px + pw/2, y, bx + bw/2, y, label='MSG', label_fs=9)
draw_arrow(ax, bx + bw/2, y - 0.6, sx + sw/2, y - 0.6, label='MSG', label_fs=9)
draw_check(ax, sx + sw/2 + 0.4, y - 0.6, size=0.18)
ax.text(sx + sw/2 + 0.7, y - 0.6, 'OK', fontsize=9, fontweight='bold')
# Scenario B: lost
y = 2.6
ax.text(0.2, y + 0.15, 'Scenariusz B:', fontsize=8.5, fontweight='bold')
draw_arrow(ax, px + pw/2, y, bx + bw/2, y, label='MSG', label_fs=9)
draw_dashed_arrow(ax, bx + bw/2, y - 0.6, 7.5, y - 0.6)
draw_cross(ax, 7.8, y - 0.6, size=0.2)
ax.text(8.2, y - 0.55, 'UTRACONA', fontsize=9, fontweight='bold')
ax.text(8.2, y - 1.0, '(brak retransmisji)', fontsize=8, style='italic')
# Summary
ax.text(6.0, 0.5, 'Brak ACK, brak retransmisji. Najszybszy. Use case: logi, metryki, telemetria.',
ha='center', va='center', fontsize=9,
bbox=dict(boxstyle='round,pad=0.4', facecolor=GRAY4, edgecolor=GRAY3))
save(fig, 'pubsub_qos_at_most_once.png')
# ============================================================
# 6. At-least-once (QoS 1)
# ============================================================
def draw_qos_at_least_once():
fig, ax = plt.subplots(1, 1, figsize=(FIG_W, 5.0))
ax.set_xlim(0, 12)
ax.set_ylim(0, 6.5)
ax.set_aspect('equal')
ax.axis('off')
ax.set_title('QoS: At-least-once — „powtarzaj aż potwierdzą" (≥1 dostarczenie)',
fontsize=FS_TITLE, fontweight='bold', pad=12)
bx, bw = 3.5, 2.2
sx, sw = 8.0, 2.2
bh = 0.8
draw_box(ax, bx, 5.5, bw, bh, 'Broker', fill=GRAY2, fontsize=10, fontweight='bold')
draw_box(ax, sx, 5.5, sw, bh, 'Subscriber', fill=GRAY1, fontsize=10, fontweight='bold')
# Timelines
for xc in [bx + bw/2, sx + sw/2]:
ax.plot([xc, xc], [5.5, 0.8], color=GRAY3, lw=1, linestyle=':')
# Step 1: send MSG
y1 = 4.8
draw_arrow(ax, bx + bw/2, y1, sx + sw/2, y1, label='MSG #1', label_fs=9)
draw_check(ax, sx + sw + 0.2, y1, size=0.15)
ax.text(sx + sw + 0.5, y1, 'odebrano', fontsize=8)
# Step 2: ACK lost
y2 = 3.9
draw_dashed_arrow(ax, sx + sw/2, y2, bx + bw + 1.2, y2)
ax.text((bx + bw/2 + sx + sw/2)/2, y2 + 0.18, 'ACK', fontsize=9)
draw_cross(ax, bx + bw + 0.8, y2, size=0.18)
ax.text(bx + 0.3, y2 - 0.35, 'ACK utracony!', fontsize=8.5, style='italic')
# Step 3: timeout → retry
y3 = 2.9
ax.text(bx + bw/2, y3 + 0.45, 'timeout...', fontsize=8.5, style='italic', ha='center')
draw_arrow(ax, bx + bw/2, y3, sx + sw/2, y3, label='MSG #1 (retry)', label_fs=9)
draw_check(ax, sx + sw + 0.2, y3, size=0.15)
ax.text(sx + sw + 0.5, y3, 'odebrano\n(ponownie!)', fontsize=8)
# Step 4: ACK ok
y4 = 2.0
draw_arrow(ax, sx + sw/2, y4, bx + bw/2, y4, label='ACK', label_fs=9)
draw_check(ax, bx + bw/2 - 0.5, y4, size=0.18)
# Duplicate bracket
ax.annotate('', xy=(sx + sw + 1.3, y1), xytext=(sx + sw + 1.3, y3),
arrowprops=dict(arrowstyle='<->', color='black', lw=1.2))
ax.text(sx + sw + 1.6, (y1 + y3)/2, 'DUPLIKAT!\nSubscriber\notrzymał 2×',
fontsize=9, ha='left', va='center', fontweight='bold',
bbox=dict(boxstyle='round,pad=0.25', facecolor=GRAY4, edgecolor=GRAY3))
# Summary
ax.text(6.0, 0.5, 'Broker czeka na ACK, retransmituje po timeout. Mogą być duplikaty!\n'
'Use case: zamówienia, płatności (subscriber musi być idempotentny).',
ha='center', va='center', fontsize=9,
bbox=dict(boxstyle='round,pad=0.4', facecolor=GRAY4, edgecolor=GRAY3))
save(fig, 'pubsub_qos_at_least_once.png')
# ============================================================
# 7. Exactly-once (QoS 2)
# ============================================================
def draw_qos_exactly_once():
fig, ax = plt.subplots(1, 1, figsize=(FIG_W, 5.5))
ax.set_xlim(0, 12)
ax.set_ylim(0, 7)
ax.set_aspect('equal')
ax.axis('off')
ax.set_title('QoS: Exactly-once — 4-krokowy handshake (dokładnie 1 dostarczenie)',
fontsize=FS_TITLE, fontweight='bold', pad=12)
bx, bw = 2.5, 2.2
sx, sw = 7.5, 2.2
bh = 0.8
draw_box(ax, bx, 6.0, bw, bh, 'Broker', fill=GRAY2, fontsize=10, fontweight='bold')
draw_box(ax, sx, 6.0, sw, bh, 'Subscriber', fill=GRAY1, fontsize=10, fontweight='bold')
# Timelines
for xc in [bx + bw/2, sx + sw/2]:
ax.plot([xc, xc], [6.0, 1.0], color=GRAY3, lw=1, linestyle=':')
# 4-step handshake
steps = [
(5.2, 'right', 'PUBLISH (msg_id=42)', 'Broker wysyła wiadomość'),
(4.2, 'left', 'PUBREC (otrzymałem id=42)', 'Sub potwierdza odbiór, zapisuje id'),
(3.2, 'right', 'PUBREL (możesz przetworzyć)', 'Broker zwalnia wiadomość'),
(2.2, 'left', 'PUBCOMP (zakończone)', 'Sub potwierdza przetworzenie'),
]
for i, (y, direction, label, desc) in enumerate(steps):
# Step number
ax.text(bx + bw/2 - 0.7, y, f'{i+1}', fontsize=9,
fontweight='bold', ha='center', va='center',
bbox=dict(boxstyle='circle,pad=0.18', facecolor=GRAY3, edgecolor=LN))
if direction == 'right':
draw_arrow(ax, bx + bw/2, y, sx + sw/2, y, label=label, label_fs=9)
else:
draw_arrow(ax, sx + sw/2, y, bx + bw/2, y, label=label, label_fs=9)
# Side description
ax.text(sx + sw + 0.3, y, desc, fontsize=8, ha='left', va='center', style='italic')
# Summary
ax.text(6.0, 0.6, 'Deduplikacja po msg_id. Sub nie przetwarza przed PUBREL.\n'
'Najkosztowniejszy (4 pakiety). Use case: transakcje finansowe, krytyczne zdarzenia.',
ha='center', va='center', fontsize=9,
bbox=dict(boxstyle='round,pad=0.4', facecolor=GRAY4, edgecolor=GRAY3))
save(fig, 'pubsub_qos_exactly_once.png')
# ============================================================
# Main
# ============================================================
if __name__ == '__main__':
print("Generating Pub/Sub diagrams (7 separate images)...")
draw_sub_topic()
draw_sub_content()
draw_sub_type()
draw_sub_hierarchical()
draw_qos_at_most_once()
draw_qos_at_least_once()
draw_qos_exactly_once()
print("Done!")

View File

@ -0,0 +1,558 @@
#!/usr/bin/env python3
"""
Generate diagrams for PYTANIE 16: Języki programowania robotów.
A4-compatible, B&W, 300 DPI, laser-printer-friendly.
Diagrams:
1. T-R-M-S abstraction pyramid
2. Vendor languages comparison chart
3. Robot movement types (PTP, LIN, CIRC)
4. Online vs Offline programming flowchart
5. ROS architecture (pub/sub nodes)
"""
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.patches import FancyBboxPatch, FancyArrowPatch
import numpy as np
import os
DPI = 300
BG = 'white'
LN = 'black'
FS = 8
FS_TITLE = 11
OUTPUT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'img')
os.makedirs(OUTPUT_DIR, exist_ok=True)
GRAY1 = '#E8E8E8'
GRAY2 = '#D0D0D0'
GRAY3 = '#B8B8B8'
GRAY4 = '#F5F5F5'
GRAY5 = '#C0C0C0'
WHITE = 'white'
def draw_box(ax, x, y, w, h, text, fill='white', lw=1.2, fontsize=FS,
fontweight='normal', ha='center', va='center', rounded=True):
if rounded:
rect = FancyBboxPatch((x, y), w, h, boxstyle="round,pad=0.05",
lw=lw, edgecolor=LN, facecolor=fill)
else:
rect = mpatches.Rectangle((x, y), w, h, lw=lw, edgecolor=LN, facecolor=fill)
ax.add_patch(rect)
ax.text(x + w/2, y + h/2, text, ha=ha, va=va, fontsize=fontsize,
fontweight=fontweight, wrap=True)
def draw_arrow(ax, x1, y1, x2, y2, lw=1.2, style='->', color=LN):
ax.annotate("", xy=(x2, y2), xytext=(x1, y1),
arrowprops=dict(arrowstyle=style, color=color, lw=lw))
# ============================================================
# 1. T-R-M-S Abstraction Pyramid
# ============================================================
def draw_trms_pyramid():
fig, ax = plt.subplots(1, 1, figsize=(8.27, 5.5))
ax.set_xlim(0, 10)
ax.set_ylim(0, 8)
ax.set_aspect('equal')
ax.axis('off')
ax.set_title('Poziomy abstrakcji języków programowania robotów (T-R-M-S)',
fontsize=FS_TITLE, fontweight='bold', pad=10)
# Pyramid layers (bottom to top)
layers = [
# (y, left_x, right_x, label, sublabel, fill, examples, timing)
(0.5, 1.0, 9.0, 'SERVO-LEVEL', 'Sterowanie silnikami',
GRAY3, 'C/C++, FPGA, VHDL\nPID, PWM', '~1 ms'),
(2.0, 1.8, 8.2, 'MOTION-LEVEL', 'Planowanie trajektorii',
GRAY2, 'MoveIt, OMPL\nIK, collision avoidance', '~20 ms'),
(3.5, 2.6, 7.4, 'ROBOT-LEVEL', 'Komendy ruchu',
GRAY1, 'RAPID, KRL, Karel\nPDL2, URScript, ROS', '~100 ms'),
(5.0, 3.4, 6.6, 'TASK-LEVEL', 'Opis celu',
GRAY4, 'PDDL, BT, STRIPS\nplanowanie AI', '~sekundy'),
]
h = 1.3
for y, lx, rx, label, sublabel, fill, examples, timing in layers:
w = rx - lx
# Draw trapezoid
trap = plt.Polygon([
(lx, y), (rx, y),
(rx - 0.4, y + h), (lx + 0.4, y + h)
], closed=True, facecolor=fill, edgecolor=LN, lw=1.5)
ax.add_patch(trap)
# Label
ax.text((lx + rx) / 2, y + h * 0.65, label,
ha='center', va='center', fontsize=9, fontweight='bold')
ax.text((lx + rx) / 2, y + h * 0.35, sublabel,
ha='center', va='center', fontsize=7, style='italic')
# Examples - right side
ax.text(rx + 0.2, y + h * 0.5, examples,
ha='left', va='center', fontsize=6.5, color='#333333')
# Timing - left side
ax.text(lx - 0.2, y + h * 0.5, timing,
ha='right', va='center', fontsize=7, fontweight='bold',
color='#333333')
# Arrow on left
ax.annotate('', xy=(0.5, 6.2), xytext=(0.5, 0.8),
arrowprops=dict(arrowstyle='->', color='black', lw=2))
ax.text(0.5, 3.5, 'Abstrakcja\nrośnie',
ha='center', va='center', fontsize=7, rotation=90,
fontweight='bold')
# Arrow on right side for timing
ax.annotate('', xy=(9.7, 0.8), xytext=(9.7, 6.2),
arrowprops=dict(arrowstyle='->', color='black', lw=2))
ax.text(9.7, 3.5, 'Szybkość\nreakcji',
ha='center', va='center', fontsize=7, rotation=270,
fontweight='bold')
# Mnemonic at bottom
ax.text(5.0, 0.0, 'Mnemonik: „Tomek Robi Mechaniczne Serwa" (T→R→M→S, od góry do dołu)',
ha='center', va='center', fontsize=7, style='italic',
bbox=dict(boxstyle='round,pad=0.3', facecolor=GRAY4, edgecolor=LN, lw=0.8))
fig.tight_layout()
fig.savefig(os.path.join(OUTPUT_DIR, 'robot_trms_pyramid.png'), dpi=DPI,
bbox_inches='tight', facecolor=BG)
plt.close(fig)
print(" ✓ robot_trms_pyramid.png")
# ============================================================
# 2. Vendor Languages Comparison
# ============================================================
def draw_vendor_comparison():
fig, ax = plt.subplots(1, 1, figsize=(8.27, 5))
ax.set_xlim(0, 10)
ax.set_ylim(0, 7.5)
ax.axis('off')
ax.set_title('Języki producentów robotów — porównanie',
fontsize=FS_TITLE, fontweight='bold', pad=10)
# Table headers
headers = ['Cecha', 'RAPID\n(ABB)', 'KRL\n(KUKA)', 'Karel\n(FANUC)', 'PDL2\n(Comau)', 'URScript\n(UR)']
col_widths = [1.8, 1.6, 1.6, 1.6, 1.6, 1.6]
col_x = [0.1]
for w in col_widths[:-1]:
col_x.append(col_x[-1] + w)
row_h = 0.7
header_y = 6.3
rows = [
['Składnia', 'typ własny\nstrukturalna', 'Pascal-like\nstrukturalna', 'Pascal-like\nstrukturalna', 'proceduralna\nC-like', 'Python-like\nskryptowy'],
['Ruch liniowy', 'MoveL', 'LIN', 'MOVE TO\nw/LINEAR', 'MOVE\nLINEAR TO', 'movel()'],
['Ruch joint', 'MoveJ', 'PTP', 'MOVE TO', 'MOVE TO', 'movej()'],
['Ruch kołowy', 'MoveC', 'CIRC', '(brak\nwbudow.)', 'MOVE\nCIRCULAR', 'movec()'],
['I/O', 'SetDO/\nWaitDI', 'OUT/IN', 'DOUT/DIN', 'OUT/IN', 'set_digital\n_out()'],
['Zmienne', 'num, robtarget\nstring, bool', 'INT, REAL\nPOS, E6POS', 'INTEGER\nPOSITION', 'INTEGER\nPOSITION', 'int, float\npose'],
['Symulator', 'RobotStudio', 'KUKA.Sim', 'ROBOGUIDE', 'RoboSim', 'URSim\n(darmowy)'],
]
# Draw header row
for j, (hdr, w) in enumerate(zip(headers, col_widths)):
x = col_x[j]
fill = GRAY2 if j == 0 else GRAY1
draw_box(ax, x, header_y, w - 0.05, row_h, hdr, fill=fill,
fontsize=7, fontweight='bold', rounded=False)
# Draw data rows
for i, row in enumerate(rows):
y = header_y - (i + 1) * row_h
for j, (cell, w) in enumerate(zip(row, col_widths)):
x = col_x[j]
fill = GRAY4 if j == 0 else (WHITE if i % 2 == 0 else GRAY4)
fw = 'bold' if j == 0 else 'normal'
draw_box(ax, x, y, w - 0.05, row_h - 0.02, cell, fill=fill,
fontsize=6, fontweight=fw, rounded=False)
# Note
ax.text(5.0, 0.5, 'Vendor lock-in: program w RAPID ≠ działa na KUKA. '
'ROS/ROS 2 jako warstwa unifikująca.',
ha='center', va='center', fontsize=7, style='italic',
bbox=dict(boxstyle='round,pad=0.3', facecolor=GRAY4, edgecolor=LN, lw=0.8))
fig.tight_layout()
fig.savefig(os.path.join(OUTPUT_DIR, 'robot_vendor_comparison.png'), dpi=DPI,
bbox_inches='tight', facecolor=BG)
plt.close(fig)
print(" ✓ robot_vendor_comparison.png")
# ============================================================
# 3. Robot Movement Types (PTP, LIN, CIRC)
# ============================================================
def draw_movement_types():
fig, axes = plt.subplots(1, 3, figsize=(8.27, 3.2))
fig.suptitle('Typy ruchu robota: PTP, LIN, CIRC',
fontsize=FS_TITLE, fontweight='bold', y=0.98)
# --- PTP (Point-to-Point) ---
ax = axes[0]
ax.set_xlim(-0.5, 4.5)
ax.set_ylim(-0.5, 4.5)
ax.set_aspect('equal')
ax.set_title('PTP (Point-to-Point)\nMoveJ / PTP', fontsize=8, fontweight='bold')
ax.grid(True, alpha=0.3)
# Start and end
start = (0.5, 0.5)
end = (3.5, 3.5)
ax.plot(*start, 'ko', ms=10, zorder=5)
ax.plot(*end, 'ks', ms=10, zorder=5)
ax.text(start[0] - 0.3, start[1] - 0.3, 'Start', fontsize=7, ha='center')
ax.text(end[0] + 0.3, end[1] + 0.3, 'Cel', fontsize=7, ha='center')
# Curved path (joint space = not necessarily straight in Cartesian)
t = np.linspace(0, 1, 50)
x_ptp = start[0] + (end[0] - start[0]) * t + 0.8 * np.sin(np.pi * t)
y_ptp = start[1] + (end[1] - start[1]) * t - 0.3 * np.sin(np.pi * t)
ax.plot(x_ptp, y_ptp, 'k-', lw=2)
ax.annotate('', xy=(x_ptp[-1], y_ptp[-1]), xytext=(x_ptp[-3], y_ptp[-3]),
arrowprops=dict(arrowstyle='->', color='black', lw=2))
ax.text(2.8, 1.2, 'Ścieżka\nw kartezjańskiej\nnieokreślona!', fontsize=6,
ha='center', style='italic',
bbox=dict(boxstyle='round', facecolor=GRAY4, edgecolor=GRAY5))
ax.text(2.0, -0.3, 'Najszybszy, ale\nścieżka nieprzewidywalna', fontsize=6,
ha='center', style='italic')
ax.set_xlabel('')
ax.set_ylabel('')
ax.tick_params(labelsize=6)
# --- LIN (Linear) ---
ax = axes[1]
ax.set_xlim(-0.5, 4.5)
ax.set_ylim(-0.5, 4.5)
ax.set_aspect('equal')
ax.set_title('LIN (Linear)\nMoveL / LIN', fontsize=8, fontweight='bold')
ax.grid(True, alpha=0.3)
start = (0.5, 1.0)
end = (3.5, 3.5)
ax.plot(*start, 'ko', ms=10, zorder=5)
ax.plot(*end, 'ks', ms=10, zorder=5)
ax.text(start[0] - 0.3, start[1] - 0.3, 'Start', fontsize=7, ha='center')
ax.text(end[0] + 0.3, end[1] + 0.3, 'Cel', fontsize=7, ha='center')
# Straight line
ax.plot([start[0], end[0]], [start[1], end[1]], 'k-', lw=2)
ax.annotate('', xy=end, xytext=(start[0] + 0.9*(end[0]-start[0]),
start[1] + 0.9*(end[1]-start[1])),
arrowprops=dict(arrowstyle='->', color='black', lw=2))
# Show intermediate points
for frac in [0.25, 0.5, 0.75]:
px = start[0] + frac * (end[0] - start[0])
py = start[1] + frac * (end[1] - start[1])
ax.plot(px, py, 'k.', ms=6)
ax.text(2.0, -0.3, 'Prosta linia TCP\nIK w każdym punkcie', fontsize=6,
ha='center', style='italic')
ax.tick_params(labelsize=6)
# --- CIRC (Circular) ---
ax = axes[2]
ax.set_xlim(-0.5, 4.5)
ax.set_ylim(-0.5, 4.5)
ax.set_aspect('equal')
ax.set_title('CIRC (Circular)\nMoveC / CIRC', fontsize=8, fontweight='bold')
ax.grid(True, alpha=0.3)
# Arc through 3 points
center = (2.0, 1.5)
r = 2.0
theta_start = np.radians(20)
theta_end = np.radians(160)
theta = np.linspace(theta_start, theta_end, 50)
x_circ = center[0] + r * np.cos(theta)
y_circ = center[1] + r * np.sin(theta)
ax.plot(x_circ, y_circ, 'k-', lw=2)
ax.annotate('', xy=(x_circ[-1], y_circ[-1]), xytext=(x_circ[-3], y_circ[-3]),
arrowprops=dict(arrowstyle='->', color='black', lw=2))
# Start, auxiliary, end points
ax.plot(x_circ[0], y_circ[0], 'ko', ms=10, zorder=5)
ax.plot(x_circ[24], y_circ[24], 'k^', ms=8, zorder=5)
ax.plot(x_circ[-1], y_circ[-1], 'ks', ms=10, zorder=5)
ax.text(x_circ[0] + 0.3, y_circ[0] - 0.3, 'Start', fontsize=7)
ax.text(x_circ[24] + 0.05, y_circ[24] + 0.25, 'Pkt\npomocniczy', fontsize=6, ha='center')
ax.text(x_circ[-1] - 0.5, y_circ[-1] - 0.3, 'Cel', fontsize=7)
# Center
ax.plot(*center, 'k+', ms=8, mew=1.5)
ax.text(center[0], center[1] - 0.3, 'środek', fontsize=6, ha='center')
ax.text(2.0, -0.3, 'Łuk wyznaczony\nprzez 3 punkty', fontsize=6,
ha='center', style='italic')
ax.tick_params(labelsize=6)
fig.tight_layout()
fig.savefig(os.path.join(OUTPUT_DIR, 'robot_movement_types.png'), dpi=DPI,
bbox_inches='tight', facecolor=BG)
plt.close(fig)
print(" ✓ robot_movement_types.png")
# ============================================================
# 4. Online vs Offline Programming
# ============================================================
def draw_online_offline():
fig, ax = plt.subplots(1, 1, figsize=(8.27, 4.5))
ax.set_xlim(0, 10)
ax.set_ylim(0, 6.5)
ax.set_aspect('equal')
ax.axis('off')
ax.set_title('Programowanie robotów: Online (teach-in) vs Offline',
fontsize=FS_TITLE, fontweight='bold', pad=10)
# === ONLINE side (left) ===
# Title
draw_box(ax, 0.3, 5.2, 4.2, 0.8, 'ONLINE\n(teach-in / pendant)',
fill=GRAY2, fontsize=9, fontweight='bold')
steps_online = [
(4.2, 'Operator przy robocie\nz teach pendantem'),
(3.2, 'Prowadzi ramię\n„za rękę" do punktów'),
(2.2, 'Robot zapamiętuje\npozycje (record)'),
(1.2, 'Odtwarzanie\nzapisanej ścieżki'),
]
for y, txt in steps_online:
draw_box(ax, 0.5, y, 3.8, 0.8, txt, fill=WHITE, fontsize=7)
for i in range(len(steps_online) - 1):
draw_arrow(ax, 2.4, steps_online[i][0], 2.4, steps_online[i+1][0] + 0.8)
# Pros/cons
ax.text(2.4, 0.6, '✓ Proste, intuicyjne\n✗ Wymaga zatrzymania produkcji\n✗ Niska precyzja',
ha='center', va='center', fontsize=6.5,
bbox=dict(boxstyle='round', facecolor=GRAY4, edgecolor=GRAY5, lw=0.8))
# Divider
ax.plot([4.9, 4.9], [0.3, 6.2], 'k--', lw=1, alpha=0.5)
# === OFFLINE side (right) ===
draw_box(ax, 5.3, 5.2, 4.2, 0.8, 'OFFLINE\n(symulacja / CAD/CAM)',
fill=GRAY2, fontsize=9, fontweight='bold')
steps_offline = [
(4.2, 'Model 3D robota +\nśrodowisko w symulatorze'),
(3.2, 'Programowanie ścieżek\nw środowisku wirtualnym'),
(2.2, 'Weryfikacja kolizji\ni optymalizacja'),
(1.2, 'Transfer na\nrzeczywistego robota'),
]
for y, txt in steps_offline:
draw_box(ax, 5.5, y, 3.8, 0.8, txt, fill=WHITE, fontsize=7)
for i in range(len(steps_offline) - 1):
draw_arrow(ax, 7.4, steps_offline[i][0], 7.4, steps_offline[i+1][0] + 0.8)
ax.text(7.4, 0.6, '✓ Bez zatrzymania produkcji\n✓ Wysoka precyzja, symulacja\n✗ Wymaga kalibracji',
ha='center', va='center', fontsize=6.5,
bbox=dict(boxstyle='round', facecolor=GRAY4, edgecolor=GRAY5, lw=0.8))
fig.tight_layout()
fig.savefig(os.path.join(OUTPUT_DIR, 'robot_online_offline.png'), dpi=DPI,
bbox_inches='tight', facecolor=BG)
plt.close(fig)
print(" ✓ robot_online_offline.png")
# ============================================================
# 5. ROS Architecture (pub/sub)
# ============================================================
def draw_ros_architecture():
fig, ax = plt.subplots(1, 1, figsize=(8.27, 4.5))
ax.set_xlim(0, 10)
ax.set_ylim(0, 6.5)
ax.set_aspect('equal')
ax.axis('off')
ax.set_title('ROS — architektura publish/subscribe',
fontsize=FS_TITLE, fontweight='bold', pad=10)
# Nodes
nodes = [
(1.0, 4.5, 'Czujnik\n(LiDAR)', GRAY1),
(1.0, 2.5, 'Kamera\n(RGB-D)', GRAY1),
(4.0, 4.5, 'Lokalizacja\n(SLAM)', GRAY4),
(4.0, 2.5, 'Percepcja\n(detekcja)', GRAY4),
(7.0, 3.5, 'Planowanie\nruchu (MoveIt)', GRAY2),
(7.0, 1.0, 'Sterownik\nsilników', GRAY3),
]
for x, y, txt, fill in nodes:
draw_box(ax, x, y, 2.2, 1.0, txt, fill=fill, fontsize=7, fontweight='bold')
# Topics (arrows with labels)
topics = [
# (from_x, from_y, to_x, to_y, label)
(3.2, 5.0, 4.0, 5.0, '/scan'),
(3.2, 3.0, 4.0, 3.0, '/image'),
(6.2, 5.0, 7.0, 4.3, '/pose'),
(6.2, 3.0, 7.0, 3.8, '/objects'),
(8.0, 3.5, 8.0, 2.0, '/cmd_vel'),
]
for x1, y1, x2, y2, label in topics:
draw_arrow(ax, x1, y1, x2, y2, lw=1.5)
mx, my = (x1 + x2) / 2, (y1 + y2) / 2
ax.text(mx, my + 0.2, label, ha='center', va='bottom', fontsize=6,
fontweight='bold', style='italic',
bbox=dict(boxstyle='round,pad=0.15', facecolor=WHITE,
edgecolor=GRAY5, lw=0.5))
# ROS Master / roscore
draw_box(ax, 3.5, 0.3, 3.0, 0.8, 'ROS Master (roscore)\nRejestr węzłów i tematów',
fill=GRAY2, fontsize=7, fontweight='bold')
# Dashed lines to master
for x, y, _, _ in nodes[:4]:
ax.plot([x + 1.1, 5.0], [y, 1.1], 'k:', lw=0.5, alpha=0.4)
# Legend
ax.text(0.3, 0.8, 'Węzeł (Node) = proces\n'
'Temat (Topic) = kanał pub/sub\n'
'Wiadomość = typowany komunikat',
ha='left', va='center', fontsize=6,
bbox=dict(boxstyle='round', facecolor=GRAY4, edgecolor=LN, lw=0.8))
fig.tight_layout()
fig.savefig(os.path.join(OUTPUT_DIR, 'robot_ros_architecture.png'), dpi=DPI,
bbox_inches='tight', facecolor=BG)
plt.close(fig)
print(" ✓ robot_ros_architecture.png")
# ============================================================
# 6. RAPID program structure example
# ============================================================
def draw_rapid_structure():
fig, ax = plt.subplots(1, 1, figsize=(8.27, 5.5))
ax.set_xlim(0, 10)
ax.set_ylim(0, 8)
ax.axis('off')
ax.set_title('Struktura programu RAPID (ABB) — przykład pick & place',
fontsize=FS_TITLE, fontweight='bold', pad=10)
# Program structure blocks
y = 7.0
blocks = [
('MODULE MainModule', GRAY2, 0.5, 9.0, [
('! Deklaracja danych', GRAY4, 1.0, 8.5, [
'CONST robtarget pHome := [...];',
'CONST robtarget pPick := [...];',
'CONST robtarget pPlace := [...];',
'VAR num nCycles := 0;',
]),
('PROC main()', GRAY1, 1.0, 8.5, [
'MoveJ pHome, v1000, z50, tool1;',
'WHILE TRUE DO',
' PickPart;',
' PlacePart;',
' Incr nCycles;',
'ENDWHILE',
]),
('PROC PickPart()', GRAY1, 1.0, 8.5, [
'MoveL Offs(pPick,0,0,50), v500, z10, tool1;',
'MoveL pPick, v100, fine, tool1;',
'SetDO doGripper, 1; ! zamknij chwytak',
'WaitTime 0.5;',
'MoveL Offs(pPick,0,0,50), v500, z10, tool1;',
]),
]),
]
# Simplified: just draw code blocks
code_sections = [
('Deklaracje danych (stałe, zmienne)', GRAY4, [
'CONST robtarget pHome := [[500,0,600],[1,0,0,0],...];',
'CONST robtarget pPick := [[400,200,100],[1,0,0,0],...];',
'CONST robtarget pPlace := [[400,-200,100],[1,0,0,0],...];',
'VAR num nCycles := 0;',
'PERS tooldata tGripper := [...];',
]),
('Procedura główna: main()', GRAY1, [
'PROC main()',
' MoveJ pHome, v1000, z50, tGripper;',
' WHILE TRUE DO',
' PickPart;',
' PlacePart;',
' Incr nCycles;',
' ENDWHILE',
'ENDPROC',
]),
('Podprocedura: PickPart()', GRAY1, [
'PROC PickPart()',
' MoveL Offs(pPick,0,0,50), v500, z10, tGripper;',
' MoveL pPick, v100, fine, tGripper;',
' SetDO doGripper, 1; ! zamknij chwytak',
' WaitTime 0.5;',
' MoveL Offs(pPick,0,0,50), v500, z10, tGripper;',
'ENDPROC',
]),
]
y_cur = 7.2
for title, fill, lines in code_sections:
h = 0.25 * len(lines) + 0.5
# Title bar
draw_box(ax, 0.5, y_cur - 0.35, 9.0, 0.35, title, fill=fill,
fontsize=7, fontweight='bold', rounded=False)
y_cur -= 0.35
# Code lines
for i, line in enumerate(lines):
y_cur -= 0.25
ax.text(0.7, y_cur + 0.12, line, fontsize=5.5,
fontfamily='monospace', va='center')
# Border around code
code_h = 0.25 * len(lines)
rect = mpatches.Rectangle((0.5, y_cur - 0.05), 9.0, code_h + 0.15,
lw=0.8, edgecolor=GRAY5, facecolor=WHITE,
zorder=-1)
ax.add_patch(rect)
y_cur -= 0.3
# Annotations on right
annotations = [
(6.5, 'robtarget = pozycja\nkartezjańska + orientacja\n+ konfiguracja ramienia'),
(4.5, 'v500 = prędkość 500 mm/s\nz10 = strefa zbliżenia 10mm\nfine = dokładne dojście'),
(2.5, 'SetDO = Digital Output\nSterowanie I/O\n(chwytak, zawory)'),
]
for yy, txt in annotations:
ax.text(9.8, yy, txt, fontsize=5.5, ha='left', va='center',
bbox=dict(boxstyle='round,pad=0.2', facecolor=GRAY4,
edgecolor=GRAY5, lw=0.5))
fig.tight_layout()
fig.savefig(os.path.join(OUTPUT_DIR, 'robot_rapid_example.png'), dpi=DPI,
bbox_inches='tight', facecolor=BG)
plt.close(fig)
print(" ✓ robot_rapid_example.png")
# ============================================================
# Main
# ============================================================
if __name__ == '__main__':
print("Generating PYTANIE 16 diagrams...")
draw_trms_pyramid()
draw_vendor_comparison()
draw_movement_types()
draw_online_offline()
draw_ros_architecture()
draw_rapid_structure()
print("Done! All diagrams saved to", OUTPUT_DIR)

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

View File

@ -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

View File

@ -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`

View File

@ -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 percepcjadeliberacjaakcja 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) | sekundyminuty | "Jedź trasą A→B→C" |
| **Sequencer** | koordynacja zachowań (PLAN → SEKWENCJA) | 100 mssekundy | 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 = "WiemChcę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

View File

@ -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 47 osiami obrotu, sterowane komputerowo.
**Język programowania robotów** — język do definiowania zachowania robota: ruchy, logika, I/O. Może być specjalizowany (dedykowany producenta) lub ogólny (C++, Python z bibliotekami). Klasyfikacja wg poziomu abstrakcji — od zadań po sygnały silników.
@ -16,86 +16,453 @@
**Task-level (poziom zadania)** — najwyższy: opisujesz CO robot ma zrobić, nie JAK. „Podnieś A, połóż na B." Robot sam planuje ruchy. Przykłady: PDDL, Behavior Trees.
// Task-level:
// Task-level (pseudokod):
pick(objectA);
place(locationB);
// Robot sam oblicza kinematykę, trajektorię, chwyt
**Robot-level (poziom robota)** — komendy ruchu w przestrzeni kartezjańskiej lub konfiguracyjnej: move_to(x,y,z), grasp(). Programista mówi GDZIE jechać, robot oblicza JAK (kinematyka odwrotna). Przykłady: RAPID (ABB), KRL (KUKA), Karel (FANUC).
// RAPID (ABB):
MoveL p1, v500, fine, tool1; // liniowo do p1, prędkość 500 mm/s
**Robot-level (poziom robota)** — komendy ruchu w przestrzeni kartezjańskiej lub konfiguracyjnej: move_to(x,y,z), grasp(). Programista mówi GDZIE jechać, robot oblicza JAK (kinematyka odwrotna). Tu działają języki producentów: RAPID (ABB), KRL (KUKA), Karel (FANUC), PDL2 (Comau), URScript (Universal Robots).
**Motion-level (poziom ruchu)** — planowanie trajektorii: generowanie ciągu punktów od startu do celu z unikaniem kolizji. Kinematyka odwrotna, interpolacja. Przykłady: MoveIt (ROS), OMPL.
**Servo-level (poziom serwa)** — najniższy: bezpośrednie sterowanie silnikami/serwomechanizmami. Regulacja PID, sygnały PWM. Języki: C/C++, FPGA. Czas reakcji: mikro-milisekundy.
**Servo-level (poziom serwa)** — najniższy: bezpośrednie sterowanie silnikami/serwomechanizmami. Regulacja PID, sygnały PWM. Języki: C/C++, FPGA/VHDL. Czas reakcji: mikro-milisekundy.
Przykład czasu reakcji na każdym poziomie:
Task: "Zamontuj śrubę" (sekundy)
Robot: MoveL do_pozycji (100 ms)
Motion: Trajektoria 50 pkt/s (20 ms)
Servo: PID: PWM silnika = 75% (1 ms)
---
**Kinematyka odwrotna (inverse kinematics, IK)** — obliczenie kątów w stawach robota, aby efektor (np. chwytak) znalazł się w zadanej pozycji. Problem odwrotny: znasz cel, szukasz konfiguracji. Może mieć 0, 1 lub wiele rozwiązań.
**Trajektoria (trajectory)** — zaplanowana ścieżka ruchu w czasie: sekwencja pozycji + prędkości + przyspieszenia. Interpolacja: liniowa (LIN), kołowa (CIRC), punkt-do-punktu (PTP).
![Piramida T-R-M-S](img/robot_trms_pyramid.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.
**Kinematyka odwrotna (inverse kinematics, IK)** — obliczenie kątów w stawach robota, aby efektor (np. chwytak) znalazł się w zadanej pozycji. Problem odwrotny: znasz cel (x,y,z + orientacja), szukasz konfiguracji (kąty q₁…qₙ). Może mieć 0, 1 lub wiele rozwiązań. Robot 6-osiowy: zazwyczaj do 8 rozwiązań dla jednej pozycji.
**Vendor lock-in** — każdy producent ma WŁASNY język. Program napisany w RAPID nie działa na robocie KUKA. To motywacja dla ROS i standardów.
Przykład (robot 2-osiowy, ramiona L₁=L₂=1m, cel: x=1.0, y=1.0):
q₂ = arccos((x²+y²L₁²L₂²) / (2·L₁·L₂))
= arccos((1+111)/2) = arccos(0) = 90°
Dwa rozwiązania: „łokieć do góry" i „łokieć na dół"
**Online vs Offline programming:**
- **Online (teach-in)** — operator prowadzi robota „za rękę" (pendant/teach pendant), robot zapamiętuje punkty. Proste, ale wymaga zatrzymania produkcji.
- **Offline** — programowanie w symulacji (CAD/CAM), bez zatrzymywania robota. Transferujesz gotowy program.
**Trajektoria (trajectory)** — zaplanowana ścieżka ruchu w czasie: sekwencja pozycji + prędkości + przyspieszenia. Trzy typy interpolacji:
- **PTP (Point-to-Point)** — najszybsza, ale ścieżka w przestrzeni kartezjańskiej nieprzewidywalna (interpolacja w przestrzeni stawów)
- **LIN (Linear)** — prosta linia TCP (Tool Center Point); wymaga obliczenia IK w każdym punkcie
- **CIRC (Circular)** — łuk kołowy przez 3 punkty (start, pkt pomocniczy, cel)
![Typy ruchu robota](img/robot_movement_types.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).
**Vendor lock-in** — każdy producent ma WŁASNY język. Program napisany w RAPID nie działa na robocie KUKA. To motywacja dla ROS i standardów. Porównanie języków:
**MoveIt** — biblioteka ROS do planowania ruchu manipulatorów. Obejmuje: IK, collision avoidance, trajectory planning. Open source.
![Porównanie języków producentów](img/robot_vendor_comparison.png)
**PDDL (Planning Domain Definition Language)** — język opisu problemów planowania. Definiujesz: stany, akcje, warunki, cel. Planner automatycznie znajduje sekwencję akcji. Task-level.
---
**FPGA (Field-Programmable Gate Array)** — programowalny układ logiczny. Dla servo-level: przetwarzanie sygnałów w nanosekundach. Szybszy niż mikrokontroler, ale trudniejszy w programowaniu.
**TCP (Tool Center Point)** — punkt centralny narzędzia zamontowanego na końcu ramienia (np. czubek spawarki, środek chwytaka). Wszystkie komendy ruchu LIN i CIRC odnoszą się do TCP — robot steruje tak, żeby ten punkt poruszał się po żądanej ścieżce.
Definiowanie TCP w RAPID:
PERS tooldata tGripper := [TRUE, [[0,0,150],[1,0,0,0]],
[2,[0,0,75],[1,0,0,0],0,0,0]];
// TCP jest 150mm nad kołnierzem, masa narzędzia 2kg
**Strefa zbliżenia (zone)** — parametr określający, jak blisko celu robot musi dojechać zanim zacznie ruch do kolejnego punktu. `fine` = dojazd dokładnie do punktu (zatrzymanie), `z10` = robot zaczyna skręcać w stronę następnego punktu gdy jest 10mm od celu (ruch „na okrągło", płynniejszy i szybszy).
MoveL p1, v500, fine, tool1; // zatrzymaj się dokładnie w p1
MoveL p1, v500, z50, tool1; // zacznij skręcać 50mm przed p1
// z50 → szybszy cykl, ale mniejsza precyzja w punkcie
---
### Klasyfikacja wg poziomu abstrakcji: **T-R-M-S**
1. **Task-level** — „Podnieś A, połóż na B" (PDDL, Behavior Trees)
2. **Robot-level** — move_to(), grasp() (RAPID, KRL, Karel, ROS)
2. **Robot-level** — move_to(), grasp() (RAPID, KRL, Karel, URScript)
3. **Motion-level** — trajektorie, kinematyka odwrotna (MoveIt, OMPL)
4. **Servo-level** — PID, sterowanie silnikami (C/C++, FPGA)
### Klasyfikacja wg metody: Online (teach-in, pendant) vs Offline (symulacja, CAD)
### Klasyfikacja wg metody programowania
### Języki producentów
![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

View File

@ -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 |

View File

@ -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