Szoftverfejlesztés multinacionális vállalatoknál

A tárgy keretében a hallgatók lehetőséget kapnak megtapasztalni egy multinacionális környezetben történő szoftverfejlesztés mikéntjét és kihívásait. A félév során a hallgatók egy, vezetéstámogató rendszerek működésének demonstrációjára szolgáló játék fejlesztésén keresztül megismerhetik a Scrum Agile metodológiát, kipróbálhatják a Test Driven Developmentet, elsajátíthatják a Clean Code írásának alapelveit, tapasztalatot szerezhetnek a jó Code Review végzésében, továbbá elméleti ismeretet szereznek a Software Craftsmanshipről, Agile-ról általában, a Continuous Integration-ről.

A tárgy kettős felépítésű - minden alkalommal elméleti előadáson mutat be egy új ismeretanyagot, amit aztán a hallgatók a gyakorlatba ültethetnek a saját csapatukon belül. A félév során kis létszámú (3-6 fős) csapatokra bontva három sprintet kell teljesíteni, minden sprintben működő szoftvert szállítani, amit a hallgatók terveznek, implementálnak, integrálnak és verifikálnak majd csapatonként mutatják be saját közreműködésüket. Ez teljes félév során órán kívüli elköteleződést és felelősségvállalást kíván a csapat (és a kurzus) sikere iránt - az értékelés jelentős részét a gyakorlati munka adja. A tárgyhoz alapszintű verziókezelési ismeretek megléte javasolt.

A tantárgy célja, hogy a hallgatók olyan tapasztalatot szerezzenek, amely egy tipikus multinacionális környezetben előfordul: verziókezelés (git) és feladatmenedzsment (GitHub), párhuzamos és komponens alapú szoftverfejlesztés, megrendelő fókusz, határidős fejlesztések, proaktivitás, kommunikációs és (ön)szervező készség, függőségek és blokkoló tényezők feloldása, megoldása.

Mottó

A designer knows he has achieved perfection not when there is nothing left to add, but when there is nothing left to take away.

Antoine de Saint-Exupéry

Ütemezés

Az órák csütörtökönként a BA.F.07-ben vannak (távoktatásban, MS Teams-en), neptun szerint 08:00-10:35 között előadás és 10:45-11:30 között gyakorlat. (Ezek aránya valamint közte a szünet az aktuális előadásanyag és az igények szerint módosulhat). A „gyakorlat” nem labor, hanem sokkal inkább konzultáció!

hétdátumelőadásgyakorlat
1.02. 10.Bevezető, áttekintésfeladat és a munkafolyamat átfogó ismertetése
2.02. 17.Napi munka, verziókezelőkgit, GitHub, IDE ismertetés
3.02. 24.Software Architecture I.csapatsorsolás, warmup
4.03. 03.Software Architecture II.Sprint Planning, Task Definition Workshop
5.03. 10.Agile, SCRUM, Kanbankonzultáció (hozott UML-k megbeszélése)
6.03. 17.Verification & validationkonzultáció
7.03. 24.Continuous Integrationnálunk hogy működik (handout, AutomatedCar), konzultáció
8.03. 31.1. demoretrospektív, Sprint Planning, Task Definition Workshop
9.04. 07.ReviewPR review, konzultáció
10.04. 14.Rektori/dékáni szünet
11.04. 21.Legacy Codekonzultáció
13.04. 28.TBD
12.05. 05.Összefoglalás, 2. demoretrospektív, tárgy feedback
14.05. 12.Zárthelyi dolgozat

Házi feladatok

hétfeladat
1Avalonia Tutorial teljesítése
3Warmup feladat
4modul tervezése, UML (statikus és dinamikus) készítése és feltöltése GitHubra

Gantt diagram

gantt dateFormat YYYY-MM-DD axisFormat %m-%d title 2021/22 tanév II.félév Introduction :milestone, 2022-02-10, 1d section Warm-up Warm-up :active, warmup, 2022-02-24, 1w Team draw :milestone, after warmup, 1d section Sprint 1 Sprint 1 :active, sprint1, after warmup, 4w Demo 1 :milestone, after sprint1, 1d section Sprint 2 Sprint 2 :active, sprint2, after sprint1, 4w Demo 2 :milestone, after sprint2, 1d Midterm :milestone, 2022-05-12, 1d click sprint1 href "./sprint_1.html" click sprint2 href "./sprint_2.html"

Demók

A félév során a csapatok két alkalommal prezentálják az elvégzett munkát. A „demók” az elkészült szoftver megrendelőnek való bemutatását szimulálják. Nem a kódra vagyunk kíváncsiak, hanem működés közben szeretnénk látni, hogy a szoftver teljesíti feladatban foglalt követelményeket. A bemutatás során, a master branchre befogadott kódot vesszük figyelembe, minden egyéb „nem készült el határidőre”, azaz értékelhetetlen.

Bővebben...

Zárthelyi

Ismert, Moodle-ös teszt, 50 kérdéssel, erre 70 perc áll majd a rendelkezésre. Minden kérdéshez 4 válaszlehetőség, amelyek közül pontosan egy a helyes. (Vannak „az alábbiak közül melyik NEM helyes” felépítésű kérdések is.) A rendelkezésre álló idő alatt kérdéseket tetszőleges alkalommal felül lehet vizsgálni, módosítani a teszt „lezárása” után azonnal kiértékelésre is kerül.

Jegy kialakítása

  1. gyakorlati jegy (sprintek átlaga) × 0.7 + ZH jegy × 0.3

  2. Ha nincs gyakorlati teljesítmény, akkor a félév elégtelen, függetlenül attól, hogy a ZH hogy sikerült.

  3. Mivel a sprintekre csapatok kapnak jegyet, mindenki kitölt egy csapattárs értékelő kérdőívet arról, hogy a csapaton belüli munka miképpen oszlott meg.

A ZH százalék jegyre számítását az alábbi intervallumokkal végezzük:

tóligjegy
0491
50592
60693
70794
801005

Felkészülést segítő anyagaok

Ajánlott irodalom

  1. The Software Craftsman: Professionalism, Pragmatism, Pride – Robert C. Martin
  2. The Clean Coder: A Code of Conduct for Professional Programmers – Robert C. Martin
  3. Clean Code: A Handbook of Agile Software Craftsmanship – Robert C. Martin
  4. Working Effectively with Legacy Code - Michael Feathers
  5. TDD by Example – Kent Beck
  6. XP Explained – Kent Beck

Online anyagok fejezetenként

Javasolt (fel)készülési módszer

Mivel a diákat nem adjuk ki, célszerű jegyzetelni: címszavakat, fogalmakat leírni, gondolatmenetet rögzíteni (bár ehhez is kaptok kész anyagot az alábbi mindmap tekintetében). Nem a diát kell lekörmölni (annak ellenére sem, hogy azokat nem kaphatjátok meg), annak nincs értelme! Óra után (az óra hetében), ezekre rákeresni (pl. Google), valamint elolvasni az itteni anyagokat. A hivatkozott linkek mögötti tartalom olyan anyagmennyiséget jelent, amelyet a ZH előtti estén nem lehet feldolgozni.

Mindmap

A témakörök „mindmap” formájú összefoglalása letölthető itt, megnyitáshoz a Freemind nevű javás eszköz szükséges. Vagy közvetlenül innen megnyitható a HTML-re fordított változata.

Címszavak

Címszavak (különösebb sorrend nélkül) amelyek az elméleti anyagot több-kevésbé lefedik. Ha valakinek ezeket a fogalmakat nem tudja kifejteni (nem tiszta mit jelent), akkor célszerű megkérdezni a Googlet vagy a Wikit. ;)

agile, agile manifesto, software craftmanship, SCRUM, user story, backlog (product backlog vs. sprint backlog; ki szerkeszti?), task (hossza, elemei), sprint (hossza), sprint review, sprint planning, burndown chart, scrum of scrums, business value, story point, standup (hossza, mikor van, ki vesz rajta részt, 3 kérdés), blocking issue, retro(spective), backlog refinement (aka backlog grooming), demo, daily cycle, clean code, traceability (eszkaláció), version control (elosztott vs. centralizált), refactoring, review (informal, walkthrough, technical, inspection), pair programming, scrum team tagjai: scrum master, product owner, development team, cross functional team, self-organizing team, stakeholder, kanban, scrumban, waterfall, v-model, scrum of scrums (ambassador), Test-driven development, (software) unit, unit testing (arrange, act, assert, annihilate), test suite, test case, quality assurance, coding kata, code golf, legacy code, code smell, rotting code, dependency reduction, seams, Continuous integration, Test automation, Continuous deployment, minimized context switch, DevOps, coding dojo, SOLID priciples, clean code, definition of done, milestone, deadline, mocking (dummy, stub, spy, mock, fake), requirement, requirement engineering, centralized version control, distributed version control, traceability, finding, bug fixing, optimizing, feature envy, KISS, code complexity, cyclomatic complexity, regression test, deployment strategies/shadow deploy, teszt stratégiák (top-down, bottom-up, sandwich, big-bang, risky-hardest), black-box testing, white-box testing, gray-box testing, nightly build, hardware in the loop (HIL), software in the loop (SIL), SMART objectives, technical debt, effort estimation

Software Architecture

Growing software

Linux kernel - number of lines of code (forrás: Wikipedia)

The more, the better?

if we wish to count lines of code, we should not regard them as "lines produced" but as "lines spent"

E.W. Dijkstra EWD 1036


Every line of code written comes at a price: maintenance. To avoid paying for a lot of code, we build reusable software. The problem with code re-use is that it gets in the way of changing your mind later on.

tef - Write code that is easy to delete, not easy to extend

Complex Software

How to measure? - Cyclomatic complexity

Cyclomatic complexity measures the number of linearly independent paths through the method, which is determined by the number and complexity of conditional branches. A low cyclomatic complexity generally indicates a method that is easy to understand, test, and maintain. The cyclomatic complexity is calculated from a control flow graph of the method and is given as follows:

cyclomatic complexity = the number of edges - the number of nodes + 1

where a node represents a logic branch point and an edge represents a line between nodes.

The rule reports a violation when the cyclomatic complexity is more than 25.

CA1502: Avoid excessive complexity

Issues with cyclomatic complexity

  • Not every statement is equal
    • if, while, for and case statements considered as identical
  • Nesting
    • it doesn’t account for nesting

NPATH complexity

The NPath complexity of a method is the number of acyclic execution paths through that method. A threshold of 200 is generally considered the point where measures should be taken to reduce complexity.

NPathComplexity

Consider writing a unit test and you have a function with an NPath complexity of 16. This means that if you need want 100% code coverage you need to test for 16 possible outcomes and that would end up in pretty messy tests.

Niklas Modess - NPath complexity and cyclomatic complexity explained

Complex vs. complicated

Michael Bykovski: Simple vs. Complicated vs. Complex vs. Chaotic

Complexity: Accidental vs. Essential

Accidental Complexity is something that can be simplified by a new idea, design, technique, procedure or approach. Essential Complexity is something that can't be simpler or something that loses value when it becomes simpler. Identifying the difference between accidental and essential complexity is a fundamental design technique.

John Spacey - Complexity: Accidental vs. Essential

What is Software Architecture

"Architecture" is a term that lots of people try to define, with little agreement. There are two common elements: One is the highest-level breakdown of a system into its parts; the other, decisions that are hard to change.

Martin Fowler - Patterns of Enterprise Application Architecture

All architecture is design but not all design is architecture. Architecture represents the significant design decisions that shape a system, where significant is measured by cost of change.

Grady Booch

In most successful software projects, the expert developers working on that project have a shared understanding of the system design. This shared understanding is called ‘architecture.’ This understanding includes how the system is divided into components and how the components interact through interfaces. These components are usually composed of smaller componnets, but the architecture only includes the components and interfaces that are understood by all the developers.

Ralph Johnson, XP mailing list

Miért kell ez?

Architecture is the decisions that you wish you could get right early in a project

-- Ralph Johnson

  • https://gbksoft.com/blog/why-you-need-a-software-architect-for-your-project/
  • https://www.martinfowler.com/articles/designDead.html#SoIsDesignDead
  • https://www.codeproject.com/Articles/1064240/Introduction-to-Software-Architecture

Hogyan lesz egy ilyenünk?

Architecture decision records

Alább látható a Michael Nygard féle sablon: Documenting Architecture Decisions

# ADR template by Michael Nygard

This is the template in [Documenting architecture decisions - Michael Nygard](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions).
You can use [adr-tools](https://github.com/npryce/adr-tools) for managing the ADR files.

In each ADR file, write these sections:

# Title

## Status

What is the status, such as proposed, accepted, rejected, deprecated, superseded, etc.?

## Context

What is the issue that we're seeing that is motivating this decision or change?

## Decision

What is the change that we're proposing and/or doing?

## Consequences

What becomes easier or more difficult to do because of this change?

Design Principles

4C: Complete, Compliant, Clear, Concise

Rob Pike's 5 Rules of Programming

  1. You can't tell where a program is going to spend its time. Bottlenecks occur in surprising places, so don't try to second guess and put in a speed hack until you've proven that's where the bottleneck is.
  2. Measure. Don't tune for speed until you've measured, and even then don't unless one part of the code overwhelms the rest.
  3. Fancy algorithms are slow when n is small, and n is usually small. Fancy algorithms have big constants. Until you know that n is frequently going to be big, don't get fancy. (Even if n does get big, use Rule 2 first.)
  4. Fancy algorithms are buggier than simple ones, and they're much harder to implement. Use simple algorithms as well as simple data structures.
  5. Data dominates. If you've chosen the right data structures and organized things well, the algorithms will almost always be self-evident. Data structures, not algorithms, are central to programming.

Pike's rules 1 and 2 restate Tony Hoare's famous maxim "Premature optimization is the root of all evil." Ken Thompson rephrased Pike's rules 3 and 4 as "When in doubt, use brute force.". Rules 3 and 4 are instances of the design philosophy KISS. Rule 5 was previously stated by Fred Brooks in The Mythical Man-Month. Rule 5 is often shortened to "write stupid code that uses smart objects".

forrás

Zen of Python1

The Zen of Python is a collection of 19 "guiding principles" for writing computer programs that influence the design of the Python programming language. 2

  1. Beautiful is better than ugly.
  2. Explicit is better than implicit.
  3. Simple is better than complex.
  4. Complex is better than complicated.
  5. Flat is better than nested.
  6. Sparse is better than dense.
  7. Readability counts.
  8. Special cases aren't special enough to break the rules.
  9. Although practicality beats purity.
  10. Errors should never pass silently.
  11. Unless explicitly silenced.
  12. In the face of ambiguity, refuse the temptation to guess.
  13. There should be one-- and preferably only one --obvious way to do it.
  14. Although that way may not be obvious at first unless you're Dutch.
  15. Now is better than never.
  16. Although never is often better than right now.
  17. If the implementation is hard to explain, it's a bad idea.
  18. If the implementation is easy to explain, it may be a good idea.
  19. Namespaces are one honking great idea -- let's do more of those!

Zen of Zyg3

  • Communicate intent precisely.
  • Edge cases matter.
  • Favor reading code over writing code.
  • Only one obvious way to do things.
  • Runtime crashes are better than bugs.
  • Compile errors are better than runtime crashes.
  • Incremental improvements.
  • Avoid local maximums.
  • Reduce the amount one must remember.
  • Focus on code rather than style.
  • Resource allocation may fail; resource deallocation must succeed.
  • Memory is a resource.
  • Together we serve the users.

3 https://ziglang.org/documentation/0.8.0/#Zen

The 23 Gang of Four Design Patterns

Teljes összefoglaló, ahol mindegyikhez van magyarázat, UML diagram és C# kód.

Abstract FactoryFacadeProxy
AdapterFactory MethodObserver
BridgeFlyweightSingleton
BuilderInterpreterState
Chain of ResponsibilityIteratorStrategy
CommandMediatorTemplate Method
CompositeMementoVisitor
DecoratorPrototype

Topologies

Introduction to Software Architecture

Layered Architechture

Message Bus Architecture

Server-Client Architecture

C4 model

Level 1: System Context diagram

Shows the software system you are building and how it fits into the world in terms of the people who use it and the other software systems it interacts with.

Simon Brown - The C4 Model for Software Architecture

Level 2: Container diagram

Zooms into the software system, and shows the containers (applications, data stores, microservices, etc.) that make up that software system. Technology decisions are also a key part of this diagram.

Simon Brown - The C4 Model for Software Architecture

Level 3: Component diagram

Zooms into an individual container to show the components inside it. These components should map to real abstractions (e.g., a grouping of code) in your codebase.

Simon Brown - The C4 Model for Software Architecture

Level 4: Code

Finally, if you really want or need to, you can zoom into an individual component to show how that component is implemented.

Simon Brown - The C4 Model for Software Architecture

Versioning

Semantic Versioning

Calendar Versioning

  • "CalVer is a versioning convention based on your project's release calendar, instead of arbitrary numbers."
  • YYYY.MINOR.MICRO
  • website

ZeroVer: 0-based Versioning

  • "Your software's major version should never exceed the first and most important number in computing: zero."
  • e.g.: 0.4.1
  • website

Daily Work

Communication

I am only responsible for what I said, not for what you understood

Igaz ez? Miért nem?

Számítsd bele, hogy a másik nem ugyanazzokkal az előismeretekkel rendelkezik, nem ugyanazzal a fogalomkészlettel, terminológiával, esetleg anyanyalvvel.

Requirement Engineering


Coding

A TDD-ről részletesen a TDD fejezetben.

Cserkész szabály

Always leave the campground cleaner than you found it

-- Robert C. Martin (Uncle Bob)

Clean Code

Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. Code for readability. source

A viccet félretéve az egész lényege az érthetőség és a karbantarthatóság. Két hét múlva is meg kell értened a saját kódod és nem csak neked.

Meaningful Names

Az alábbiak Robert C. Martin Clean Code című könyvénből a 2. fejezet (Meaningful Names) alfejezet címei, az idézetek is onnan valók.

  • Use Intention-Revealing Names
    • int d; // elapsed time in days

    • int elapsedTimeInDays;

  • Avoid Disinformation
  • Make Meaningful Distinctions
    • It is not sufficient to add number series or noise words, even though the compiler is satisfied. If names must be different, then they should also mean something different.

  • Use Pronounceable Names
    • If you can’t pronounce it, you can’t discuss it without sounding like an idiot. “Well, over here on the bee cee arr three cee enn tee we have a pee ess zee kyew int, see?”

    • Külön szempont ez nem angol anyanelyvűeknél, némely szavakat bonyolultabb kiejtenünk
  • Use Searchable Names
    • Single-letter names can ONLY be used as local variables inside short methods. The length of a name should correspond to the size of its scope.

  • Avoid Mental Mapping
    • Readers shouldn’t have to mentally translate your names into other names they already know.

    • clarity is king

  • Avoid Encodings
    • a modern IDE-k esetében már teljesen fölösleges típus vagy szerepjelöléseket tenni a nevekbe
  • Pick One Word per Concept
  • Don’t Pun or use humor
  • Add Meaningful Context
    • Imagine that you have variables named firstName, lastName, street, houseNumber, city, state, and zipcode. Taken together it’s pretty clear that they form an address. But what if you just saw the state variable being used alone in a method?


Nincs megjelölve forrás, de ez az összefogleló is ezen a fejezeten alapszik.

Functions

Az alábbiak Robert C. Martin Clean Code című könyvénből a 3. fejezetén alapulnak.

  • A hossza legyen a lehető legrövidebb (akár 2-4 sor, bár személy szerint azt néha túlzásnak tartom)
  • Do One Thing
  • Use Descriptive Names
    • egy metódus valamit csinál, tehát kezdődjön igével, pl. increaseSpeed
    • a nevéből legyen egyértelmű, hogy mit csinál
    • Robert C. Martin The Inverse Scope Law of Function Names: The longer the scope of a function, the shorter its name should be. Functions that are called locally from a few nearby places should have long descriptive names, and the longest function names should be given to those functions that are called from just one place.

  • Function Arguments
    • Lehetőleg ne használj 3-nál több paramétert
    • Flag arguments are ugly [...] loudly proclaiming that this function does more than one thing.

  • Have No Side Effects
    • Wikipédiából: an operation, function or expression is said to have a side effect if it modifies some state variable value(s) outside its local environment, that is to say has an observable effect besides returning a value (the main effect) to the invoker of the operation.

    • Side effects are lies. Your function promises to do one thing, but it also does other hidden things.

  • Prefer Exceptions to Returning Error Codes
    • a korábbiakból már adódik, hogy miért jobb egy FileNotFoundException mint egy ERRCODE_26375

Comments

One of the more common motivations for writing comments is bad code. We write a module and we know it is confusing and disorganized. We know it’s a mess. So we say to ourselves, “Ooh, I’d better comment that!” No! You’d better clean it!

-- Robert C. Martin: Clean Code, pp 55.

  • Gyakori a kód strukturálása kommentekkel, ilyenkor célszerű függvényeket használni inkább
  • Kerülendő a TODO és a FIXME a kommentekben, ez azt jelenti, hogy nem vagy készen
  • Kommentezni ajánlott viszont -szerintem- a domain specifikus részeket, amelyek megértését nem feltétlenül lehet elvárni egy fejlesztőtől. Pl. egy fizikai számítás.
  • Továbbá nem haszontalan a dokumentációs kommentezés pl. Javadoc, kivéve ha egy increaseSpeed metódus kommentje annyi, hogy "this method increases the speed", sokkal többet mondana az, hogy mennyivel, milyen korlátok között stb. amelyek révén aztán hasznos lesz a generált API dokumentáció anélkül, hogy a kódba kellene nézni.


Verziókezelők

Mi a verziókezelő?

Version control, a.k.a. revision control / source code management, is basically a system for recording and managing changes made to files and folders. It is commonly used to manage source code, however, it is also well suited to tracking changes to any kind of file which contains mostly text.

-- forrás

Az ember hajlamos ad-hoc módon is verziózni a munkáját, pl.1:

Több szolgáltatás és szoftver alapból tartalmaz verziókövetést, pl. a Dropbox, Google Drive, stb. is verziózza a feltöltött állományokat; az MS Word még merge-elni is tudja az egyes verziókat.

Michael Ernst összefoglalója alapján:

  • Version control enables multiple people to simultaneously work on a single project. Each person edits his or her own copy of the files and chooses when to share those changes with the rest of the team. Thus, temporary or partial edits by one person do not interfere with another person's work.
  • Version control also enables one person you to use multiple computers to work on a project, so it is valuable even if you are working by yourself.
  • Version control integrates work done simultaneously by different team members. In most cases, edits to different files or even the same file can be combined without losing any work. In rare cases, when two people make conflicting edits to the same line of a file, then the version control system requests human assistance in deciding what to do.
  • Version control gives access to historical versions of your project. This is insurance against computer crashes or data lossage. If you make a mistake, you can roll back to a previous version. You can reproduce and understand a bug report on a past version of your software. You can also undo specific edits without losing all the work that was done in the meanwhile. For any part of a file, you can determine when, why, and by whom it was ever edited.

Mit érdemes verziókezelni

"In practice, everything that has been created manually should be put in version control, including programs, original field observations, and the source files for papers."

-- Best Practices for Scientific Computing; Wilson et al. 2012 (arXiv:1210.0530)

Az ehhez a jegyzethez készített ábrák és azok forrása is verziókezelés alatt van, ezek a .png és .dia állományok a /src/images/ mappában, utóbbiak valójában egy diagramszerkesztő alkalmazás XML alapú forrásfájljai.

  • Ez az írás összefoglalja a verziókezelési modelleket (Lock-Modify-Unlock, Copy-Modify-Merge), emez pedig összehasonlítja a centralizált és az elosztott verziókezelőket.
  • About Version Control
    • a Git könyv első fejezete, rövid összefoglaló
  • gyakorlati oldalról lást Git fejezet
1

http://smutch.github.io/VersionControlTutorial/pages/0-intro.html#what-is-version-control

Centralizált verziókezelő

centralized_version_control

Elosztott verziókezelő

distributed_version_control

Branching

A félév során a GitHubFlow-t használjuk, részletek a GitHub fejezetben.

Commit üzenetek

xkcd 1296

A How to Write a Git Commit Message egy hosszabb, példákkal illusztrált írás a jó commit üzenetekről, amely hét szabályban foglalja össze, hogy mire kell figyelni. Ezt egészíteném ki egy nyolcadikkal.

  1. Separate subject from body with a blank line
  2. Limit the subject line to 50 characters
  3. Capitalize the subject line
  4. Do not end the subject line with a period
  5. Use the imperative mood in the subject line
  6. Wrap the body at 72 characters
    • ez a legkevésbé fontos
  7. Use the body to explain what and why vs. how
  8. Reference the issue!

Miért fontos a 8. pont?

Valójában (bizonyos szempontból) az issue behivatkozása a legfontosabb, méghozzá a visszakövethetőség (traceability) miatt.

Minden módosítás (a verziókövető rendszerben) rendelkezik egy azonosítóval, amelyhez társul, hogy ki és mikor végezte el a módosítást. Valamit egy üzenet, amely -- jó esetben -- leírja, hogy mi volt ez a módosítás. A visszakövethetőség egy adott szintig tehát szerves része a verziókövető rendszereknek.

A módosítások azonban nem csak úgy ötletszerűen történnek, hanem valamilyen feladat által meghatározott célból. Pl. jelenítsd meg a műszerfalon az autó pillanatnyi sebességét (feature), vagy javítsd ki pixel/s -> km/h átváltást, mert kerekítési hiba miatt értelmetlen érték jelenik meg (bugfix).

Ugyanakkor a feladatok (task) sem csak úgy lógnak a levegőben, jellemzően kapcsolódnak egy user story-hoz (különösen a feature-ök), de biztosan kapcsolódnak egy sprinthez (hiszen beütemezték a megoldását valamikorra), van felelősük, határidejük, stb. Úgy általában van véve egy kontextusuk. Az issue (más néven task) tartalmazza az adott feladat pontos részleteit, az issue/task trackerben akár a megoldás teljes vitafolyamata megtalálható. Pl. ki hogyan akarta implementálni, milyen érvek és ellenérvek merültek fel az egyes implementációs lehetőségek mellett/ellen, hogyan jutott a fejlesztőcsapat konszenzusra, vagy ki hagyta jóvá az adott módosítást, ki döntött arról, hogy melyik sprintbe kerüljön be, stb.

A visszakövethetőség nem csak addig a pontig érdekes és fontos, hogy ki írta át a változó típusát (pl.), hanem a teljes tervezési/döntés folyamatig visszamenőleg.

Mi van akkor ha a döntés egy face-to-face meetingen (pl. standup), skype konferenciahíváson vagy egyéb nem írásos formában történt? (A szó elszáll, írás megmarad...)

Ebben az esetben, az issue kiváló hely arra, hogy írásban is rögzítve legyenek az elhangzottak. Pl. YYYY-MM-DD-ei megbeszélés alapján az XY library segítségével fogom implementálni az analóg fordulatszámkijelzőt. Akár explicit írásos jóváhagyást is lehet kérni...

További „iskolák”

  • Az AngularJS Git Commit Message Conventions a commit üzenet fejlécét a <type>(<scope>): <subject> szabály szerint követeli meg.
    • ahol típus lehet build, ci, docs, feat, fix, perf, refactor, style vagy test
    • valójában a 1., 4. és 5. pontot ez is megköveteli; a 3.-al pont szembemegy, aminek oka, hogy a tárgy típusmegjelöléssel kezdődik, nem a tárgy szövegével
    • a tárgy és törzs sorhosszára 100 karakteres limitet ad, szemben a fenti hagyományos (akár úgy is lehet érteni, hogy elavult) terminálméretekre szabott korlátaival
  • Egy másik, az Angularéhoz nagyon hasonló a Conventional Commits
  • Ezek előnye lehet -megfelelő tooling mellett- pl. az automatizált changlelog generálás
    • nálunk nincs ilyesmire beállított eszköz

Mire jó még a commit üzenet?

Például arra is alkalmas, hogy lezárjunk vele egy issue-t. Ha a commit üzenet törzse tartalmazza a close, closes, closed, fix, fixes, fixed, resolve, resolves vagy resolved utasítások egyikét, akkor a GH automatikusan zárja az issue-t amint az a fő ágba (master) került. Pl.

Fix px/s -> km/h conversion #28

Fixes #28

Mikor commit-oljunk?

A fentiekből már látszik, hogy az egésznek akkor van értelme, ha egy-egy commit egy jól megválasztott mértékű módosítást rögzít. Az a megközelítés, hogy a munkanap végén nyomok egy commitot valami olyasféle üzenettel, hogy Changes on YYYY-MM-DD nem nagyon szolgálja a visszakövethetőséget.

Egy taszk hossza 1-4 óra (főállású fejlesztőre értelmezve), de fontos, hogy egy megszakítás nélkül elvégezhető feladat legyen. Ez azt jelenti, hogy egy taszk egyenlő egy committal? Nem. Egy taszk megoldása természetesen több commitból is állhat.

A When to make a Git Commit poszt1 alapján (is), azt mondanám, hogy akkor érdemes commitolni, ha:

  1. Befejeztem egy egységnyi munkát.
  2. Olyan módosítást végeztem, amit esetleg visszavonnék.

Az egységnyi munka módosított sorok és fájlok tekintetében rendkívül változó lehet. Egy bugfix pl. állhat egyetlen karakter módosításából, de egy refaktorálás során egy metódus átnevezése járhat tucatnyi fájl módosításával (ahol az adott metódus használva volt). Ugyanakkor a metódusátnevezés után biztosan érdemes lehet commitolni, egyéb módosítást már nem csapnék hozzá.

Ha a commit üzenetbe azt írnád, hogy Rename foobar method and fix typo in the comment #42 már biztosan két külön commitra lenne szükséged.

1

a hozzá tartozó kommenteket is érdemes átfutni

Review

A tárgy során

review process

Waterfall

  • Sequential design process
  • Next stage can be started after finishing the previous
  • After finishing a step, cannot go back to previous

Waterfall: pros

  • Customer can have clear expectation about the final product
  • Employee turnover does not influence project due to strong documentation
  • Simple, easy to use model

Waterfall: cons

  • Customer can have clear expectation about the final product
  • Employee turnover does not influence project due to strong documentation
  • Simple, easy to use model

Waterfall Vs. Agile

V-Model

Complex Project

  • Complex projects are where requirements and technology are not agreed.
  • Flexibility and frequent feedback loops are needed here.

The Agile Manifesto

We are uncovering better ways of developing software by doing it and helping others do it. Through this work we have come to value:

  • Individuals and interactions over processes and tools
  • Working software over comprehensive documentation
  • Customer collaboration over contract negotiation
  • Responding to change over following a plan

That is, while there is value in the items on the right, we value the items on the left more.

forrás

Agile Principles

  • Frequent delivery
  • Test early, test often
  • Small, incremental releases
  • Development team makes their own decisions
  • Direct communication between customer and development team

Best Practices for Agile

  • Test-Driven Development (TDD)
  • Regular refactoring
  • Continuous integration
  • Simple design
  • Pair programming

SCRUM

A framework within which people can address complex adaptive problems, while productively and creatively delivering products of the highest possible value.

  • Not a process or technique, rather a framework
  • Based on empirical process theory
  • Empiricism assumes that knowledge comes from experience
  • Iterative, incremental approach
  • Consists of
    • Scrum Team/Roles
    • Events
    • Artifacts
    • Rules

Scrum Team & Roles

  • Self-organizing
  • Cross-functional
  • Maximizes opportunities for feedback

Product Owner

  • Responsible for optimizing the value of the work the Development Team does
  • Clarifies product backlog items
  • Product backlog items can only be prioritized by PO
  • Decisions made by PO is respected by everyone in the entire organization

Development Team

  • Self-organizing team – makes its own decisions how to turn Product Backlog into potentially releasable functionalities
  • Cross-functional team – team has all skills needed turn Product Backlog into potentially releasable functionalities
  • No titles inside team
  • No subteams inside team
  • Size can be between 3 and 9

Cross-functional team

Akkor tud egy csapat „cross-functional” lenni, ha minden tagja kellőképpen érti a csapat feladatát, így a tagok képesek egymást helyettesíteni. A fenti ábra a csapattagok tudását szemlélteti. Az első esetben csupán elenyésző általános tudással rendelkező emberekről van szó, akik egy nagyon szűk területet ismernek. A cross-functional team esetében is megvan az egyes tagok specifikus tudása ám az kevésbé nyúlik túl a csapat általános ismeretein és kevésbé specifikusabb is.

Scrum Master

  • Responsible for Scrum to be understood in scrum team
  • Facilitates scrum events
  • Removes impediments from development team
  • Coaches development team for self-organization
  • Coaches organization in Scrum adaptation
  • Not the „boss” of development team
  • Servant leader of the team
  • Can be one team member or common Scrum Master for several teams

Scrum Master - Funny movie about The Power of Scrum

Scrum Events

  • Time boxed events
    • there is a maximal time allowed to keep
  • Regular meetings
    • minimizes the need for other not defined meetings

Sprint

  • Time-boxed for one month or less
  • During the sprint a potentially releasable product increment shall be created
  • Consists of
    • Sprint Planning
    • Daily Scrums (Standup)
    • Development work
    • Sprint Review
    • Sprint Retrospective
  • Each Sprint has a definition what has to be done
  • During Sprint no change can be made that influences the Sprint Goal
  • Can be terminated when Sprint Goal became obsolete
  • Further reading

Sprint Planning

  • The work that should be done in Sprint is planned in Sprint Planning
  • Eight hours for a one-month Sprint, for shorter Sprint it is less
  • Answers for two questions:
    • What will be delivered for the next Sprint?
    • How it will be done?
  • Product Backlog is used as an input, Sprint Backlog (SB) is filled with items from Product Backlog (PB)
  • The number of selected items has to be decided only by development team
  • Product Owner helps to clarify Product Backlog items
  • Scrum Master facilitates the meeting when needed
  • Further reading: Estimations

Daily Scrum

  • Time-boxed to 15 minutes
  • Main goal is to synchronize activities between team members
  • Kept each day at the same time and same place to reduce complexity
  • Every team member participates and answers three questions:
    • What was done by himself/herself by last Daily Scrum?
    • What will be done by himself/herself till next Daily Scrum?
    • Are there any impediments that prevent the work?
  • Scrum Master does not need to participate always, but
    • Ensures that all team members take part
    • Teaches development team to keep the time-box
  • Further reading

Sprint Review

  • Kept at the end of the sprint
  • Time-boxed to four hour for one month sprint
  • Scrum Team and stakeholders attend
  • PO explains the PB items, that are „Done” or not „Done” to stakeholders
  • Development Team demonstrates the work and answers questions
  • Scrum Team gather feedback from stakeholders
  • All participants collaborates on what to do next

Sprint Retrospective

  • For the Scrum Team to inspect and improve itself
  • Three hour time-box after sprint review for one-month Sprint
  • Plan shall be created for implementing improvements of the way of working
  • Further reading

Sprint Artifacts: Product Backlog

  • Ordered list of items needed for the product
  • Dynamically evolves
  • Property of Product Owner
  • PO is responsible for its content and prioritization
  • Further reading

Sprint Artifacts: Sprint Backlog

  • Selected PB items for a certain Sprint in Sprint Planning
  • Development Team is the owner
  • Estimates are made by Development Team

Sprint Artifacts: Product Increment

  • Sum of all PB items completed
  • Has to meet the Definition of "Done"
  • A new increment is delivered after each Sprint

Burndown Chart

  • Expresses the remaining effort for a time period
  • X axis: time left in the Sprint
  • Y axis: remaining effort for the Sprint measured in story points
  • Story points measures how "difficult" a user story is
  • Story points are estimated by Development Team
  • Further reading

AgileMe - Sprint Burndown Chart

Artifact Transparency: Definition of Done

  • Checklist of activities needed for a product increment
  • List of activities such coding, unit testing, documentation, integration test, etc.
  • Has to be understood and followed by all team members

Scaling Scrum: Scrum of Scrums

  • Each Scrum Team delegates an "ambassador" who attends the Scrum of Scrums meeting
  • Ambassadors coordinate the work of multiple Scrum Teams
  • Meetings are not as frequent as Daily Scrum
  • Further reading

Kanban

  • Pull system
  • Eliminate waste
  • Decrease cycle time
  • Should be applied to current processes
  • Rules:
    • Visualize Workflow
    • Limit Work in Process
    • Measure and Improve Flow

Kanban cont.

  • Tasks move left to right
  • Choose the rightest top task to work with
    • to finish it as soon as possible
  • within a column, the task at the top has the highest priority
  • task may contain
    • assignee
    • effort
    • etc.
  • Further reading

Scrum vs. Kanban

SCRUMKanban
CadenceRegular fixed length sprintsContinuous flow
Release methodologyAt the end of each sprint if approved by the product ownerContinuous delivery or at the team's discretion
RolesProduct owner, scrum master, development teamNo existing roles. Some teams enlist the help of an agile coach.
Change philosophyTeams should strive to not make changes to the sprint forecast during the sprint. Doing so compromises learnings around estimation.Change can happen at any time

Scrumban

Further reading about SCRUM

Quiz

--- shuffleQuestions: true shuffleAnswers: true --- ### Scrum does not have a role called "project manager". 1. [x] True 1. [ ] False ### Which statement best describes a Product Owner's responsibility? 1. [x] Optimizing the value of the work the Development Team does. 1. [ ] Directing the Development Team. 1. [ ] Managing the project and ensuring that the work meets the commitments to the stakeholders. 1. [ ] Keeping stakeholders at bay.  ### The Development Team should have all the skills needed to? 1. [ ] Complete the project as estimated when the date and cost are committed to the Product Owner. 1. [ ] Do all of the development work, except for specialized testing that requires additional tools and environments. 1. [x] Turn the Product Backlog items it selects into an increment of potentially releasable product functionality. ### What are the two primary ways a Scrum Master keeps a Development Team working at its highest level of productivity? - [x] By facilitating Development Team decisions. - [x] By removing impediments that hinder the Development Team. - [ ] By starting and ending the meetings at the proper time. - [ ] By keeping high value features high in the Product Backlog. ### What is the main reason for the Scrum Master to be at the Daily Scrum? 1. [ ] To make sure every team member answers the three questions. 1. [x] He or she does not have to be there; he or she only has to ensure the Development Team has a Daily Scrum. 1. [ ] To write down any changes to the Sprint Backlog, including adding new items, and tracking  progress on the burn-down. 1. [ ] To gather status and progress information to report to management. ### The purpose of a Sprint is to produce a done increment of working product. 1. [x] True 1. [ ] False ### The length of a Sprint should be: 1. [ ] Short enough to keep the business risk acceptable to the Product Owner. 1. [ ] Short enough to be able to synchronize the development work with other business events. 1. [ ] No more than one calendar month. 1. [x] All of these answers are correct. ### The time-box for a Daily Scrum is? 1. [ ] The same time of day every day. 1. [ ] Two minutes per person. 1. [ ] 4 hours. 1. [x] 15 minutes. 1. [ ] 15 minutes for a 4 week sprint. For shorter Sprints it is usually shorter. ### Who is required to attend the Daily Scrum? 1. [x] The Development Team. 1. [ ] The Scrum team. 1. [ ] The Development Team and Scrum Master. 1. [ ] The Development Team and Product Owner. 1. [ ] The Scrum Master and Product Owner. ### Which statement best describes Scrum? 1. [ ] A complete methodology that defines how to develop software. 1. [ ] A cookbook that defines best practices for software development. 1. [x] A framework within which complex products in complex environments are developed. 1. [ ] A defined and predictive process that conforms to the principles of Scientific Management. ### Which of the below are roles on a Scrum Team? - [x] Development Team - [ ] Users - [ ] Customers - [x] Product Owner - [x] Scrum Master ### The Product Backlog is ordered by: 1. [ ] Size, where small items are at the top and large items are at the bottom. 1. [ ] Risk, where safer items are at the top, and riskier items are at the bottom 1. [ ] Least valuable items at the top to most valuable at the bottom. 1. [ ] Items are randomly arranged. 1. [x] Whatever is deemed most appropriate by the Product Owner. ### When might a Sprint be abnormally terminated? 1. [ ] When it becomes clear that not everything will be finished by the end of the Sprint. 1. [ ] When the Development Team feels that the work is too hard. 1. [ ] When the sales department has an important new opportunity. 1. [x] When the Sprint Goal becomes obsolete. ### Who has the final say on the order of the Product Backlog? 1. [ ] The Stakeholders 1. [ ] The Development Team 1. [ ] The Scrum Master 1. [x] The Product Owner 1. [ ] The CEO ### The CEO asks the Development Team to add a "very important" item to a Sprint that is in progress. What should the Development Team do? 1. [ ] Add the item to the current Sprint without any adjustments. 1. [ ] Add the item to the current Sprint and drop an item of equal size. 1. [ ] Add the item to the next Sprint. 1. [x] Inform the Product Owner so he/she can work with the CEO.

Test Driven Development

Tesztelés

Az alábbi ábra mutatja a tesztelések eloszlását hagyományos és agilis fejlesztéseknél. Az egész lényege, hogy minél előbb és a fejlesztőhöz a lehető legközelebb derüljön ki a hiba, mert annál gyorsabb és olcsóbb annak javítása. Könnyen belátható, hogy egy leszállított terméket kell visszahívni az körülményesebb mintha a fejlesző a run tests gombra nyomva azonnal, helyben az adott kód részlet írása közben (amikor még az a kontextus van a fejében) kap egy képet arról, hogy mi nem jó. De még midnig jobb ha pl. sprinten belül egy automatizált integrációs teszt fogja meg a hibát, stb.

test pyramids

TDD

TDD cycle

As the tests get more specific, the code gets more generic.

-- Uncle Bob

Red

  • tesztelj egyszerre egy dolgot
  • a teszt legyen nagyon egyszerű
  • folyamatosan növeld teszt(esetek) komplexitását
  • mockold a függőségeket

Writing Unit Tests

Green

  • a lehető legegszerűbb kóddal felelj meg a teszt által támasztott követelménynek
  • nem baj ha csúnya, ebben a lépésben csak az számít, hogy a teszt ne bukjon
  • amint a teszt zöld (és másik sem bukik), ez a fázis kész

Refactor

Transformation Priority Premise

Beragadás esetén visszalépés, vagy másik módszert kell választani. A beragadás megelőzésére van a TPP.

  • Robert C. Martin (Uncle Bob) írása, összefoglalásul pedig a transformációk:
    1. ({} -> nil) no code at all -> code that employs nil
    2. (nil -> constant)
    3. (constant -> constant+) a simple constant to a more complex constant
    4. (constant -> scalar) replacing a constant with a variable or an argument
    5. (statement -> statements) adding more unconditional statements.
    6. (unconditional -> if) splitting the execution path
    7. (scalar -> array)
    8. (array -> container)
    9. (statement -> tail-recursion)
    10. (if -> while)
    11. (expression -> function) replacing an expression with a function or algorithm
    12. (variable -> assignment) replacing the value of a variable.
  • Advanced TDD: The Transformation Priority Premise
    • 1 órás videó, Robert C. Martintól

Coding Dojo

Egyéb a TDD-hez (lazábban) kapcsolódó anyagok

Legacy code

Ez a fejezet gyakorlatilag teljes egészében Michael Feathers Working Efficiently with Legacy Code c. könyvén alapszik. Itt elérhető egy prezentáció a szerzőtől.

Mi a Legacy Code?

Code without tests is bad code. It doesn’t matter how well written it is; it doesn’t matter how pretty or object-oriented or well-encapsulated it is. With tests, we can change the behavior of our code quickly and verifiably. Without them, we really don’t know if our code is getting better or worse.

-- Feathers, M. (2004). Working Effectively with Legacy Code: Preface

The Legacy Code Dilemma

When we change code, we should have tests in place. To put tests in place, we often have to change code.

-- Feathers, M. (2004). Working Effectively with Legacy Code: Part I / Chapter 2

Code Smells

Changing Software

adding a featurefix a bugrefactoroptimizing
structurechangeschangeschanges
functionalitychanges
new funcionalitychanges
resource usagechanges

-- Feathers, M. (2004). Working Effectively with Legacy Code: WORK EFFECT LEG CODE p1. pp 6. Prentice Hall Professional.

The legacy code algorithm

Sensing & Separation

  1. Sensing — We break dependencies to sense when we can’t access values our code computes.
  2. Separation — We break dependencies to separate when we can’t even get a piece of code into a test harness to run.

-- Feathers, M. (2004). Working Effectively with Legacy Code: Part I / Chapter 3

Mocking

Seams

A seam is a place where you can alter behavior in your program without editing in that place.

-- Feathers, M. (2004). Working Effectively with Legacy Code: Part I / Chapter 4

SOLID

Review

Az első két cikk inkább technikai, számokkal meg minden, a harmadik (ez kétrészes), sokkal inkább az emberi oldalt taglalja, igen jól!

Review típusok

Sorrendben

  1. informal
    • Ez akár csak annyi, hogy megkérsz egy kollégát, hogy „nézz már rá erre picit, szerinted ez így jó?”, gyorsan tud valami visszajelzést adni, de semmi nyoma nem marad. A pair programming folyamatos informális review.
  2. walkthrough
    • a GitHub-os review majdnem ezen a szinten van, visszakövethető módon dokumentált a GitHub felületének hála, bár nem egy meeting folyamán történik a review, hanem egyénileg, szigorú protokoll nélkül. (Vezetője sincs, bár lehetne úgy is csinálni.)
  3. technical
  4. inspection

Összefoglaló táblázat a fentebbiek alapján

typeformalityled byeffortdocumentation
informalnot formalnooneminimalundocumented
walkthroughnot formal1authorsvery lownormal, fault-finding
technicalless formaltrained moderator, NOT the authormoderatemore detailed
inspectionmost formaltrained moderatorhighthorough; based on standards, checklists
1

Sometimes it can be somewhat formal.


Continuous Integration

Ennek alapja a verziókövetés, a fejlesztő pusholja a módosításait a szerverre, amely lefordítja a kódot, lefuttatja a teszteket (és egyéb elemzéseket), ezek sikerességéről visszajelzést ad. Kicsit bővebben itt.

Interrupts

interrupt_comic

The Cost of Interruption for Software Developers

Az automatizálás csökkenti az interruptokat, a költségeket és azonnali visszajelzést ad!

Automation

Build scripts

Az egész CI/CD lelke egy adag script, amelyben le vannak írva az automatizált lépések. Úgy mint...

  • kód fordítása (make, maven, stb.)
  • bináris előállítása
  • statikus kódelemzés futtatása, pl. MISRA, Checkstyle
  • tesztlefedettség kiszámolását végző szoftver futtatása
  • riport generálás a feedbackhez a fejlesztőnek, menedzsmentnek, megrendelőnek
  • stb.
  • ezek futása lehet...
    • on demand: jellemzően a CI környezetekben kézzel is újra lehet futtatni egy adott job-ot
    • ütemezett: adott időben ütemezetten fusson (lásd nightly buildek). Pl. egy teljes rendszer teszt, amely akár órákon át is futhat, azt célszerű lehet szó szerint éjjel futtatni, és a reggeli munkakezdésre van egy riport arról, hogy az előző napi változtatások mit törtek el (pl.)
    • triggerelt: valamilyen esemény hatására fusson le. Pl. egy commit-ra, így minden pusholt commit-ra lefuthatnak a különböző szintű tesztek, statikus kódellenőrzés, stb.

Software Testing

Test Strategies

Automated Testing

Integration Testing

Remek összeföglaló a témában, amely kitér a megközelítésekre: Bottom-up, Top-down, Hybrid/Sandwich, Big Bang.

System Testing

Software-in-the-loop (SIL)

forrás: autonóm autofejlesztés tesztelése

Hardware-in-the-loop (HIL)

forrás: autonóm autofejlesztés tesztelése

Acceptance Testing

SMART Objectives

Continuous Deployment

Continuous Delivery

DevOps

Alkalmazott eszközök

A tárgyhoz használt tényleges eszközök, mondhatjuk, hogy a fentiek (egy részének) gyakorlati alkalmazása.

CI környzet

Korábban Travis CI, újabban (mióta van) GitHub Actions.

A commit(ok) pusholása esemény hatására elindul a build környezet, ez egy Ubuntu linux, amely tartalmazza a Java fejlesztői környezetet (JDK) és a fordítást menedzselő eszközt (Maven). Leklónozza a repót, kiválasztja a kérdéses branch-et, lefordítja a kódot, lefuttatja a teszteket, meghívja a statikus kódelemzőt és a tesztlefedettség elemzőt, az előállt riportokat elküldi az ezt nyilvántartó szolgáltatásoknak. Ha valamennyi teszt sikeres, akkor zöld jelzést ad. (A Jenkins időjárásikonokat használ historikusságot is figyelembe véve: sok egymást követő bukó teszt (viharfelhők) után egy sikeres még nem jelent azonnal napocskát...)

CI környezet

A Pull Request-ek elfogadásának feltétele a fordítható kód és a sikeres tesztek, de a statikus kódelemző és a tesztlefedettség elemző visszajelzése is megjelenik (automatizált review formájában). Ugyanilyen automatizált review-nak tekinthető az is, hogy van-e kódütközés.

Ezeken kívül a kollégák manuális review-ja is szükséges (2 approve), lásd review protokol.

Példák

Statikus kódelemzés

A statikus kódelemzést Java nyelvhez a Checkstyle végzetre, C#-hoz a StyleCop, ez lokálisan (lásd fejlesztőeszközök fejezet) is működik, a változások követéséhez és mindenféle riport generálásához (első sorban a Pull Requestekhez) a CoceFactor.io van bekötve. Ez össze van linkelve a GitHubbal repóval, a commit triggerre saját környezetben kicsekkolja az aktuális branchet, lefuttatja a Checkstyle-t (és adott esetben más elemzőket is), majd elkészíti a riportokat.

Tesztlefedettség

A Java kódunk tesztekkel való lefedettségét Java nyelvhez a JaCoCo (Java Code Coverage) nevű szoftver számolta ki, C#-hoz a Coverlet. Szintén működik lokálisan is (lásd fejlesztőeszközök fejezet), a CodeFactorhoz hasonló online riportgeneráló amit a repónkhoz beállítottam az a CodeCov. Az előbbivel analóg módon működik.

Stale bot

A stale bot funkciója, hogy a magára hagyott hibajegyeket (issue) megjelöli „megrekedt” (stale) állapottal (címkével), ha adott ideig (nálunk 1 hét) nem volt vele kapcsolatos aktivitás. Ez alól kivételt képeznek a „user story” címkéjű issue-k.

A konfigurációja a repó .github/stale.yaml fájljában található.

MindMap

Összefoglaláshoz, gyors áttekintéshez használható, az előadásanyagot többé-kevésbé lefedő mindmap. Egérgörgővel nagyítható/távolítható és canvas-on belül szabadon mozgatható.

Célkitűzés

Konvoj

A fenti videó a Hyundai promóciós videója az olyan vezetéstámogató rendszereiről, mint az adaptív sebességtartó automatika, az automata vészfékező vagy a sávtartó automatika. A cél a fenti videón bemutatott tesztet teljesítő funkciók implementálása egy leegyszerűsített, szimulált környezetben.

Szoftver leírása

The program simulates the behavior of a passenger vehicle on the public road, equipped with driver assistance functions.

Equipped driver assistance functions are Parking Assist, Adaptive Cruise Control with Automated Emergency Braking and Lane Keeping Assistance with Traffic Sign Recognition, based on Ultra Sonic, Radar and Video sensors, respectively.

The inputs are categorized into two separate groups: user input, and configuration.

User input consists of the following elements:

  • Throttle button - gradually increasing while pressed, on a 1s duration from 0->100%, if not pressed, returns to idle
  • Brake button - gradually increasing while pressed, on a 0.5s duration from 0->100%, if not pressed, returns to idle
  • Gear Shift - Automated, P/R/N/D available for choosing with a rotary button
  • Steering Buttons - left, right, gradually increasing while pressed on a 1s duration from 0->100%, in idle returns to straight
  • Driver Assistance Function Main Switches - On/Off, flip switch, changes state on press
  • ACC: Set/Resume/Plus/Minus/Time Gap switches, activating the function, changing the chosen reference speed, changing the chosen distance to the target vehicle, respectively
  • PA: Indicators to activate parking spot search, confirmation button to trigger automated parking maneuver

Configuration input consist of the following elements:

  • Description of world in an XML file, in a predefined language
  • "Tiles" - building blocks of the simulated world, such as roads, trees, people, vehicles, buildings, etc.
  • Position and behavior of non-player vehicles and characters
  • Position of the player vehicle

The system processes the input configuration, builds a world from the provided elements after processing the content of the XML file, creating a coordinate system and defining the distances, sizes and positions of the objects in that, places the non-player vehicles and the player in the world, and cyclically updates their position, interrupting or replacing the driver input with the calculated actuation requests from the Driver Assistance systems, whenever applicable. The output consists of two parts: first, the world with all its objects, displayed through a camera view, which centers on the player, and follows its movements, second the feedback about the current state of the vehicle, including the following data:

  • Current speed
  • Current gas, brake pedal position
  • Current steering wheel angle
  • Current gear
  • Indicator status
  • ACC: Set Speed, Time Gap level, Object detected (boolean), main status(on/off/controlling)
  • AEB: on/off status, visual warning signal (Yellow: probable collision, Red: automated braking active)
  • Parking assist: available(yellow),searching for place(blinking yellow), spot found(green), parking (blinking green), off (no signal)
  • LKA/TSR: On/Off, detected speed limit, detected warning sign, controlling steering(green), lane marking not available(yellow)

The driver assistance systems apply actuation requests to the steering, drivetrain(engine, transmission) or both, of the ego vehicle. Said subsystems decide if the actuation request of the player or the driver assistance system shall be executed. The actuation request is calculated from the information detectable by the sensor the DA systems depend on. The Video, Radar and Ultrasonic sensors have specified Fields of View, and view distance, detect a different subset of objects. From the provided object list - simulating the real world hardware detection of radar wave reflection, image processing, ultrasonic reflection - the "software" components evaluate the control relevant subset, and if the conditions are fulfilled (i.e. function activated and driving in lane, object in ego lane in front of vehicle, relative speed negative, distance reducing as time passes by) the function requests actuation (in the above example, requests speed reduction from the drivetrain).

The system decides between the concurrent drivetrain requests based on comfort and safety aspects. The system shall handle and detect collisions between the objects of the world. The simulation is approximating the real world physics, to provide a satisfying driving experience for the player, and an appropriate demonstration of the work of the driver assistance systems. On demand, the field of view of the sensors, and the detected control objects may be marked on the display for debug or demonstration.

Sprintek

A félév során minden csapat 2 sprintet teljesít, minden sprintre egy-egy user story-t kap. 3 csapat esetén így a teljes elkészítendő szoftver 6 részre van bontva. A csapatok feladata a user story-k megértése, felbontása egyhuzamban elvégezhető feladatokra (task), ezekhez felelőst és határidőt rendelve.

Szintén a csapatok feladat a feladatok közötti függőségek azonosítása és az erőforrások (idő, fejlesztő) oly módon történő beosztása, hogy a határidőre minden elkészüljön. Az egyes user story-k között nem csak sprinteken átívelő függőségek lehetnek, hanem sprinten belüliek is. Ilyen esetben az érintett csapattal egyeztetve kell az egyes (rész)feladatok prioritásait meghatározni.

1. Sprint

Mozgatás: hajtáslánc és kormányzás

A mozgatás modul felelőssége a vezérelt autó (egocar) mozgatása, mozgásának számítása. Ez magába foglalja a hajtáslánc és a kormányzás megvalósítását.

A modul a HMI-től kap bemenetet, mindenek előtt váltóállás, gáz- és fékpedálállás valamint kormányelfordulás. A váltó automata, ami azzal jár, hogy a HMI a négy állapot (P, R, N, D) egyikét közli.

  • Park: Ez az egyik olyan állapot amiben a motor beindítható (a másik az N), ez a váltó alapállása, mechanikusan megszünteti az erőátvitelt. A valóságban nem helyettesíti kéziféket, de mivel azt nem kell implementálni a feladat során, lehet úgy tekinteni, hogy P-ben a kézifék is be van húzva. Az autó nem mozdul ebben az állásban.
  • Reverse: hátramenet
  • Neutral: üres, ebben az állásban sem jut a motorerő tengelyekre, a motor nem gyorsíthatja az autót. Ha üresben gázt adunk, a motor felpörög, méghozzá jelentősen, mivel nincs ami ellene dolgozna. Ha az autónak volt lendülete, az még hajtja tovább.
  • Drive: előremenet. A D-m belül definiálni kell 4-5 belső fokozatot (mint ahogy manuális váltónál is lenne), le kell programozni, hogy valamilyen fordulatszám értékeknél a váltó váltson. Ezen értékek meghatározásához lehet találni motorkarakterisztikákat (lehetőség szerint utcai autó kerüljön kiválasztásra, ne valami sportautó). A belső fokozatok a felhasználó interfész szempontjából transzparensek.

A pedál állások [0-100] skálán érkeznek. 0: nincs lenyomva, 1: 1%-ig van lenyomva, 100: tövig (100%-ig) le van nyomva. Minél jobban le van nyomva a gázpedál, annál több teljesítményt kell a motornak kiadnia. A motor belső működését nem kell részletekbe menően implementálni, pláne nem egy belső égésű motorét, egy elektromos hajtáslánc egyszerűbb. A szoftverben üzemanyag-fogyasztást (vagy akkumulátor töltöttséget) és hatótávokat nem kell kezelni.

A kormány jellemzően valamilyen áttétel segítségévél befolyásolja a kormányzott kerekek helyzetét. Ez ebben a szoftverben sokkal egyszerűbb is lehet. Ha 60°-ot tengelyelfordulást feltételezünk és a kormány „nulla” állásból +/- 60-at mozdulhat el, akkor lényegében 1:1-es „áttételünk” van. Ha az input +/- 100-as skálán adja meg a kormányelfordulás mértékét, akkor azt kell a tengelyelfordulásra képzeni. A bemeneti skálával kapcsolatban a HMI csapattal kell egyeztetni.

A úgymond kimenete egy mozgásvektor, vagyis az, hogy a következő ciklusban az autó (referenciapontjának) X, Y koordinátáit mennyivel kell módosítani. A pedálállás és a motor korábbi állapotának függvényében meghatározásra kerül a sebesség, a kormányállás valamint az egocar korábbi orientációjának függvényében meghatározásra kerül, hogy módosul-e az autó iránya, a kettő eredőjeként a teljes vektor.

A modullal kapcsolatban kihívás a hajtáslánc működésének és a mozgás és kanyarodás fizikájának megértése, implementálása. A fizika tekintetében sem kell elaprózni a dolgokat. Két erő elégséges: a motorerő mint gyorsítja a járművet (ez a gázpedállal szabályozható) és egy fékező erő, amelyet a fékpedállal lehet szabályozni, valamint ezen felül egy konstans fékező erőnek is lennie kell, tehát a fékező erő akkor sem nulla, ha a fékpedál állása nulla. Ez utóbbit mindegy minek nevezzük (légellenállás, csúszási-súrlódási erő, a kettő eredője, stb.), nem kell cicomázni, de legyen.

Külön feladat észben tartatni és célszerűen előre felkészülni arra, hogy a 3. sprintes vezetéstámogató modulok (LKA, AAC, AEB, PP) közvetlenül az egocar hajtásláncára és a kormányra hatnak. Fel kell készíteni a modult ilyen, „nem a HMI-ről” érkező inputok kezelésére is, amelyek ráadásul magasabb prioritásúak. Pl. ha a vészfékező rendszer „lenyomja” a fékpedált, akkor magasabb prioritással kell kezelni mint a HMI-ről érkező pedálállást.

Definition of Done

  • Az autó gázpedál állásától függően gyorsul
  • a fék- és gázpedál állapota a billentyű nyomva tartásának idejével szabályozható
    • fék- és gázpedál valamint a kormány sem binárisan működik, a billentyű nyomva tartás idejétől függ az input intenzitása
      • a fék- és gázpedál [0, 100] skálán (ℕ), a kormányelforgatás [-100, 100] skálán (ℤ) kerül meghatározásra
    • fék- és gázpedál valamint a kormány is fokozatosan (1 másodperc) áll vissza alaphelyzetbe a billentyű felengedésével
  • az automata váltó 4 állapota szabályozható
    • szekvenciális váltóról lévén szó, sorban állíthatók a fokozatok: P(ark), R(everse), N(eutral), D(rive)
    • alaphelyzet: P, „felváltás” után R, majd N, majd D. „Leváltás” ugyanez visszafele.
  • A gyorsulás a „belső fokozatok” szerint kerül meghatározásra
  • Az autó a gázpedál felengedésével fokozatosan lassul, majd megáll
  • Az autó R válóállásban tolat
  • Felkészíteni a modult, hogy a vészfékező, az adaptív tempomat vagy a sávtartó automatika is küldhet inputot, melyek magasabb prioritásúak
    • vészfékező értelemszerűen fékezés inputot
    • az adaptív tempomat és a parkoló asszisztens gáz és fék inputot is
    • a sávtartó automatika a kormányállást módosítja
  • Autó kanyarodásának biztosítása valóságos fordulókör szerint
    • ehhez szükséges extra tulajdonságok meghatározása
  • A meghatározott mozgásvektor alapján az autó pozíciójának frissítése
    • ez az AutomatedCar osztály x,y koordinátáinak frissítését jelenti
  • Tolatás során is valósághű kanyarodás történik

Szenzorok (kamera, radar), ütközés detektálás

A kamera modul felelőssége a sávtartó automatika és táblafelismerő alapjául szolgáló kamera szenzor implementációja. Mint minden szenzor, a kamera is érzékeli a világ egy szeletét és eléri a látóterében található objektumokat. A valóságos és szimulált szenzorok működését részletesebben a Szenzorok fejezet mutatja be.

A radar sensor modul felelőssége az adaptív tempomat és az automata vészfékező alapjául szolgáló radar szenzor szimulációjának implementálása. Mint minden szenzor, az radar is érzékeli a világ egy szeletét és eléri a látóterében található objektumokat. A valóságos és szimulált szenzorok működését részletesebben a Szenzorok fejezet mutatja be.

Radar szenzor elhelyezése

Mindkét modul bemenete a világmodell (World objektum), kimeneteit olyan világ objektumok gyűjteménye képezi, amelyek beleesnek a szenzor látóterébe. A világ objektumainak lekérdezésére létre kell hozni egy publikus metódust, amely 3 pontot vár (A szenzor látóterét 3 ponttal kel definiálni.) bemenetként és visszaadja a bele eső objektumokat. Ezekből kell még leválogatni szenzoronként a relevánsakat. Minden szenzor látóterét 3 ponttal kell definiálni. A szenzor látómezejének 3 pontját folyamatosan frissíteni kell az autó pozíciójának függvényében. Vagyis az autó egyébként folyamatosan frissülő referenciapontjához képest kell definiálni. A megjelenítés is felhasználja ezeket a pontokat a háromszög kirajzolására a debuggoláshoz.

Alkalmazás

A sávtartó automatikának meg kell tudni határozni a sávot (ebben segítenek az útelemek részét képező sávokat reprezentáló geometria objektumok). Tehát a világmodell már jól definiált módon rendelkezésre bocsátja a sávinformációkat, de ezeket olyan adatstruktúrába kell rendezni, amely megkönnyíti a sávtartó automata implementálását: a sávtartó automatikának arra lesz majd szüksége, hogy az autó közelít-e a sávját meghatározó felfestésekhez, a sáv határait. Alternatív megközelítésben, hogy mennyire távolodik el a sávközéptől.

A kihívás a radar komponenssel kapcsolatban, hogy nem elég egyszerűen csak visszaadni a látótérben található releváns objektumokat, hanem el kell tudni dönteni, hogy a jelenlegi haladási irányunkat tartva veszélyesek-e. Pl. pontosan előttünk halad (a sávban), vagy oldalról érkezik és keresztezi az utunkat. A legközelebbi releváns objektum az alábbi ábrán az 1-es, a 2-es nem.

Azonos sávban haladó jármű

Itt arról van szó, hogy a a szenzor egy iterációjában megkapjuk a látótérbe került ütközhető objektumokat. Egy fa pl. jellegénél fogva statikus, tehát túlzottan sok figyelmet nem igényel, de ugyanúgy továbbítani kell mint egy autót. Az NPC autó esetében az adott iterációban ismert az autó helyzete, majd ezt össze kell vetni az előző iterációban ismert helyzetével. A kettőből meghatározható egy irányvektor és el lehet dönteni, hogy merre halad (ha halad egyáltalán), előttünk halad, vagy mellettünk (pl. másik sávban), stb. Az ACC az azonos sávban előttünk haladó autó sebességét veszi fel, ezért az autó haladási iránya fontos szempont.

Mindez értelemszerűen egy statikus objektum pl. fa esetében is működik, csak az nem mozog (mert nem Középföldén vagyunk).

Ütközés-detektálás

Folyamatosan vizsgálni kell, hogy a vezérelt autó nekiütközött-e egy ütközhető objektumnak. Ennek vizsgálatához használható a világobjektumok poligon váza. Később majd az automatikus vészfékező modul feladat lesz, hogy ez ne következhessen be. Egy visszajelzést kell adni, amely debuggoláshoz szükséges.

Definition of Done

kamera

  • Elkészült 1 db, a szélvédő mögé elhelyezett kamera implementálása
  • A látószög és távolság által meghatározott területen kérje el a releváns objektumokat
    • külön, a sávtartó szempontjából releváns objektumok, az utak
  • A háromszög koordinátái az autó helyzetétől függően folyamatosan frissülnek
  • A legközelebbi objektum legyen kiemelve (legyen beállítva a „highlighted” tulajdonság)

radar

  • Elkészült 1 db, az autó első lökhárítója mögött elhelyezett radar szenzor
  • A látószög (60°) és távolság (200m) által meghatározott területen kérjék el a releváns objektumokat
  • A háromszög koordinátái az autó helyzetétől függően folyamatosan frissülnek
  • Határozzák meg a legközelebbi, sávon belüli (lateral offset alapján) objektum helyzetét
  • Az automata vészfékező számára releváns objektumok (az autó középvonala felé halad, látjuk) kiválogatása és visszaadása
  • A legközelebbi objektum legyen kiemelve (legyen beállítva a „highlighted” tulajdonság)

ütközés-detektálás

  • A vezérelt autó - tereptárgy ütközésének detektálása és esemény kiváltása
  • A vezérelt autó - NPC-vel való ütközésének detektálása és esemény kiváltása
  • Két objektum akkor ütközött amikor a poligon reprezentációjuk összeért, nem amikor a képfájlok fedik egymást
    • pl. autó a fa lombkoronája alatt, de még nem érte el a törzset
  • Legyen valami visszajelzés felhasználói felületen arról, hogy ütközés történt (pl. alert dialog)

Világ benépesítése mozgó NPC objektumokkal

A modul felelőssége, hogy a kiinduló kódban rendelkezésre álló világot, amelyben már megjelennek a statikus objektumok, további dinamikus objektumokkal kell kiegészíteni. Ezek a nem játszható karakterek (NPC, non player character), amelyekre azért van szükség, hogy a 2. sprintes modulok tesztelhetők legyenek. Például a vészfékező rendszer nem üti el a gyalogost, vagy az adaptív tempomat igazítja az autó sebességét az előtte haladó autóéhoz.

A modul bemenete a világmodell, amely egyrészt elősegíti az implementálást azáltal, hogy a előre definiált helyett az osztályhierarchiában az NPC objektumok számára, másrészt a statikus objektumok, egészen pontosan az út elemek definiálják a pályát amelyen az NPC autónak haladnia kell a KRESZ szabályai szerint: nem tér át az út másik oldalára, nem hajt gyorsan.

A legkézenfekvőbb megoldás, hogy a világban, a világ koordinátáira építve felveszünk vezérpontokat, amelyek kijelölnek egy utat. Ezeket célszerű lehet nem a kódban, hanem valamilyen külső fájlban tárolni. Az NPC objektum pedig ezt az utat követni. Például a parkoló mellől indul az úton megy fölfele (csökken az y koordinátája) a kanyar előtt (x,y) világkoordinátákat elérve lelassul, (x,y)' koordináták elérése esetén elkezd kanyarodni, a sávból nem tér ki, majd (x,y)" koordinátáig halad a fönti egyenesen. És így tovább.

A mozgáshoz sebességet is kell társítani. Két vezérlőpont közötti egyenesen adott idő alatt kell az NPC-nek végighaladnia. Továbbá az egyes vezérlőpontokhoz forgatási műveletet is társítani kell. Ehhez egy mozgás leíró struktúra lesz szükséges, pl. az alábbi elnagyolt példa TOML nyelven, de bármilyen megoldás választható (JSON, XML, YAML vagy teljesen egyedi formátum):

[points]

[points.1]
x = 100
y = 200
rotation = 0
speed = 50 # px/s

[points.2]
x = 100
y = 100
rotation = 15
speed = 30 # px/s

A feladatban az igazi kihívás, hogy az NPC objektumok adaptálódjanak pályához. Az adaptálódást úgy lehet megkerülni, hogy mindkét pályához készül egy-egy útvonal. A test_world pályán egy gyalogos és minimum egy autó, az oval pályán pontosan egy, az óramutató járásával megegyező irányban haladó NPC kell, amely legyen a car_3_black azonosítójú.

Az NPC autónak nincs hajtáslánc modulja, nem szükséges olyan részletes mozgatás sem mint az vezérelt autónál, de azért a kanyarodás legyen több pontból/lépésben megoldva, hogy fokozatosan legyen az autó elforgatva a kanyarodás valósághű leképezése céljából.

Az oval pálya nagy, elnyújtott kanyarokat tartalmaz, hogy ne kelljen különösebben lassítani. A test_world jóval élesebb kanyarokból áll, ehhez igazítani kell az autó sebességét. Az oval pályán körbeérve a furgon erőteljesen, de valóságosan fékez. Nem 0 idő alatt áll meg. Legyen a lassulása 9m/s^2.

Definition of Done:

  • Objektumok előre definiált, értelmes helyen jelennek meg (autók úton, gyalogosok út mellett, a zebra környékén)
  • Objektumok előre szkriptelt útvonalat követnek
  • Gyalogosok az út mentén haladnak, zebrán áthaladnak, megfordulnak majd újra átkelnek az úton
  • Autók az utat - sávot - pontosan követik
  • NPC objektumok egymás mozgásállapotát nem változtatják meg
    • Egy NPC autó gyalogoson akár átmehet, nem kell ütközésnek minősíteni
  • Legalább egy autó végigmegy a pályán a test_world pályán
  • Legalább egy gyalogos mozog és átkel egy zebrán a test_world pályán, a fenti ábrának megfelelően
  • Az oval pálya esetén az NPC objektum az óramutató járásával megegyező irányban megtesz egy kört, majd a STOP táblánál hirtelen megáll
    • nem szükséges folytatnia az útját, a másik pályán viszont folyamatosan köröz

2. Sprint

Vészfékező

A modul felelőssége a radar szenzorra épülő automata vészfékező rendszer megvalósítása. A vészfékező kritikus biztonsági funkció, így nem kapcsolható ki manuálisan, de maximum 70 km/h sebességig működik. A működése két esetre bontható: ütközés statikus vagy dinamikus objektummal.

Az előbbi az egyszerűbb eset, mivel a veszélyt jelentő objektum pozíciója változatlan.

El kell dönteni, hogy az autó az aktuális irányvektort figyelembe véve ütközni fog-e az objektummal. Ha igen, az autó ismert sebességét figyelembe véve kiszámolható, hogy ehhez mennyi időre van szükség és, hogy mekkora mértékű lassulás kell ehhez.

A radar visszaadja az autó előtt levő legközelebbi releváns objektum adatait (táv, sebesség), ezekkel lehet számolni. A távolságból és az autó sebességéből meghatározható, hogy milyen lassulást kell adni az autónak, hogy még megálljon, de ne lépje túl a \( 9 m/s^2 \)-et.

Ha az ütközés elkerülhető, vizuális figyelmeztetést kell elhelyezni a vezetőnek, hogy fékezzen. Ha nem reagál, azaz továbbra is ütközési pályán vagyunk és már csak vészfékezéssel kerülhető el az ütközés, akkor a hajtásláncnak vészfékezési inputot kell adni. Ez a maximálisan megengedett, \( 9 m/s^2 \)-es lassulást (ennél nagyobb lassulás veszélyes az utasokra), akkor

Ha más nem próbálgatással meg kell határozni, hogy adott sebességről egy maximális fékezési input (100% pedál állás) mennyi idő alatt fékezi állóra az autót. A modul olyan triggerekkel vezérli az autót mint amilyenek a billentyűlenyomás kezelőtől jönnek (fékpedál állás).

Dinamikus objektumok esetében a vészfékezés elve azonos, de az ütközési pálya meghatározása összetettebb.

Másik sávban szembe jövő autóra nem kell vészfékezést kiváltani, tehát el kell tudni dönteni, hogy abban az esetben nincs ütközési pálya.

Definition of Done

  • Elkerülhető ütközés esetén vizuális figyelmeztetés a sofőrnek
  • Ha a sofőr nem avatkozik közbe, automatikus fékezés (az utolsó pillanatban, ahol az ütközés még elkerülhető)
  • Az automatikus fékezés mértéke a sebességgel arányos, de nem lehet \( 9 m/s^2 \)-nél nagyobb
  • 70 km/h felett figyelmeztetés, hogy az AEB nem tud minden helyzetet kezelni
  • A vezérelt autó nem üt el gyalogost, nem megy neki fának
  • Nem releváns objektumok esetében (fals pozitív) mint a szembejövő autó nem történik vészfékezés

Sávtartó automatika

A sávtartó automatika modul felelőssége a kamera szenzorra épülő Lane Keeping Assistant funkció megvalósítása.

Ezt két alapvetően kétféleképpen lehet megoldani. Az egyik a sáv széleihez viszonyítva korrigál: ha az autó elérné a sáv szélét, akkor ellenkormányoz. A másik megoldás kiszámolja a sáv közepét és azon tartja az autót.

1. Sáv széleinek használata

Itt azt lehet vizsgálni, hogy a vezérelt autó jövőbeli helyzetében metszi-e a sávot.

2. Sávközép használata

Itt a vezérelt autó középpontját lehet a sávközéphez igazítani.

Csak a 45 foknál enyhébb kanyarodású úton kell működnie, ilyenkor a kocsi a sáv szemmel látható közepét követi. Az LKA működése egy enyhe sávon belüli cikázást eredményez.

Az automatika számára kezelhetetlen forgalmi szituációkban (pl. éles kanyar, kereszteződés) el kell engednie a vezérlést és ezt a vezető tudtára kell hoznia. Legyen hozzá vizuális figyelmeztetés a műszerfalon (pl. LKA visszajelző sárga). Ha újra olyan útszakasz következik, ahol a funkció használható, akkor arról szintén legyen tájékoztatás. Ezen kívül természetesen a funkció ki- és bekapcsolható.

Definition of Done

  • A sávtartó automatika ki- és bekapcsolható
    • állapota a műszerfalon látható
  • Vezetői beavatkozásra kikapcsol
  • 45 foknál enyhébb kanyarodású úton a kocsi a sáv szemmel láthatóan a sáv közepén marad
  • Ha el kell engednie a kontrollt (az automatika számára kezelhetetlen forgalmi szituáció következik, pl. éles kanyar, kereszteződés), vizuális figyelmeztetést ad
  • Ha újra elérhető a funkció (pl. elhagytuk a kanyart) vizuális indikáció (a műszerfalon)

Adaptív tempomat

A modul felelőssége a radar szenzorra épülő adaptív tempomat vezetéstámogató funkció elkészítése. Ennek a funkciónak három felhasználói esetet kell lefednie.

  1. Felhasználó által beállított sebesség tartása
  2. A táblafelismerő által közölt sebességkorlátozás betartása
  3. Az előttünk haladó (NPC) autó sebességének felvétele és egy (időben definiált) beállított követési távolság tartása
    • Valójában ettől lesz adaptív

Az egyes ponthoz szükséges kezelőszervek már elkészültek az első sprintben és a funkcióhoz szükséges bemeneti értékek már a buszon keresztül elérhetőek. A modulnak szabályoznia kell a hajtásláncot, hogy ne léphesse túl a beállított sebességet. Ehhez olyan inputot kel biztosítania mintha az a billentyűzetről érkezne, de a tényleges vezetői input felülírja őket.

A kettes pont egy harmadik sprintes (tehát aktuálisan készülő funkciótól függ), azonban könnyen visszavezethető az első pontra. A közúti szabályozást magasabb prioritásúnak kell minősíteni. Tehát a felhasználó pl. beállít egy 70 km/h-ás célsebességet, majd érkezik egy kérés a táblafelismerőtől, hogy 50km/h a megengedett, akkor azt kell figyelembe venni.

A hármas pont egy második sprintes modultól, az NPC autók meglététől függ. Az előttünk haladó sebességéhez való igazodás a legmagasabb prioritású, hiszen hiába szeretne a vezető 70-el haladni, mikor a tábla szerint 50-nel lehet, de ha az előttünk haladó mindössze 40-el halad, akkor ahhoz kell igazodni, különben nekiütközünk. Oda kell figyelni, hogy csak a sávban előttünk haladó autót vegye figyelembe, a szembejövőt ne.

A követési távolság időben történő megadása azt jelenti, hogy a beállított (pl.) 1 másodperces követés esetén akkora távolságot kell hagyni, hogy az aktuális sebességgel haladva 1 másodperc alatt megtett út legyen a távolság: 10 m/s (36 km/h) esetében 10 méter. Ezen érték beállítására már az első sprintben készült vezérlő.

Definition of Done

  • Ki- és bekapcsolható
  • ACC: Állítható céltávolság (T jelű gombbal, körkörösen 0.8/1.0/1.2/1.4 másodperc)
  • ACC: Állítható célsebesség (+/- gombbal, 30-160, 10-es lépésközzel)
  • Bekapcsoláskor a célsebessége az aktuális sebesség, de a minimum célsebesség 30 km/h
  • Ha nincs saját sávban előttünk autó, akkor a vezérelt autó tartja a kiválasztott célsebességet
  • Ha a saját sávban található autó:
    • Ha az előttünk levő autó lassabb, akkor fel kell venni a sebességét
    • Ha gyorsabb, akkor tartja a kiválasztott sebességet
  • Fékezésre kikapcsol
  • AEB beavatkozásra kikapcsol

Sprintek

A félév során minden csapat 3 sprintet teljesít, minden sprintre egy-egy user story-t kap. 4 csapat esetén így a teljes elkészítendő szoftver 12 részre van bontva. A csapatok feladata a user story-k megértése, felbontása egyhuzamban elvégezhető feladatokra (task), ezekhez felelőst és határidőt rendelve.

Szintén a csapatok feladat a feladatok közötti függőségek azonosítása és az erőforrások (idő, fejlesztő) oly módon történő beosztása, hogy a határidőre minden elkészüljön. Az egyes user story-k között nem csak sprinteken átívelő függőségek lehetnek, hanem sprinten belüliek is. Ilyen esetben az érintett csapattal egyeztetve kell az egyes (rész)feladatok prioritásait meghatározni.

A user story-k függőségi gráfja alább látható, sprintenként színezve.

A következő ábrán pedig a user story-k a felelős csapatok alapján van színezve.

1. Sprint

Human Machine Interface (HMI): Műszerfal, irányítás

A HMI modul felelőssége a vezérelt autó (egocar) kezelőszerveinek és visszajelzőinek megvalósítása. Bemeneti jelként kezelnie kell tehát a billentyűeseményeket, le kell őket fordítani az autó vezérlőszerveire, valamint a műszerfalon meg kell jeleníteni az egocar állapotát leíró értékeket.

A modul kihívása a „bináris állapotú” billentyűesemények „fokozatossá tétele”. A gáz- és fékpedál nyomvatartásának idejét kell leképezni a pedál lenyomás mértékére és egy adott idő alatt kell ennek 100%-ra jutnia. A hajtáslánc a pedálok lenyomásának mértékét használja majd a gyorsítás - és úgy általában az elmozdulás mértékének - meghatározásához. A pedálokhoz hasonlóan a kormány elfordítása sem bináris, ugyanúgy a billentyűlenyomás idejének felhasználásával kell számolni. Ezek skáláját a hajtásláncért modullal egyeztetve kell meghatározni (pl. pedálállás lenyomás 0-100 között).

A szimulált autó automata váltóval rendelkezik, így a váltó P, R, N, D állapotait is is közvetíteni kell a hajtáslánc felé.

A műszerfalnak az alábbi vázlathoz hasonlóan kell felépülnie. A programablak bal oldalán a virtuális világ egy szeletét látjuk ezért felel, a vizualizációs modul. A jobb oldalon a műszerfal található. A műszerfalon nincsenek vezérlőelemek, csak megjelenítés. Az összes kapcsoló a billentyűzettel állítható, a grafikus elemeknek nem kell pl. egérrel kapcsolhatónak lenniük.

gui_plan

A fordulatszám és a sebesség legyen egy analóg órával reprezentálva; a kormány elforgatás, a gáz- és fékpedál állása progressbar-okkal szemléltethető. Az irányjelző visszajelzője és a vezetéstámogató funkciók visszajelzői lámpaszerűek, a sebességváltó állása, és a debug értékek pl. kocsi pozíciója (x, y koordináta) lehet szöveges.

Az utoljára látott tábla -csak úgy mint a többi vezetéstámogató funkció- ugyan csak a 3. sprintben lesz kihasználva, de már most biztosítani kell a visszajelzését. A buszon közölt „utoljára látott tábla” képét ki kell tudni rajzolni (a képek rendelkezésre állnak). Legyen elkülönítve a nincs tábla eset is.

Definition of Done

  • a fék- és gázpedál állapota szabályozható
  • fék- és gázpedál valamint a kormány sem binárisan működik, a billentyű nyomva tartás idejétől függ az input intenzitása
  • fék- és gázpedál valamint a kormány is fokozatosan áll vissza alaphelyzetbe a billentyű felengedésével
  • az automata váltó 4 állapota szabályozható
    • szekvenciális váltóról lévén szó, sorban állíthatók a fokozatok: P(ark), R(everse), N(eutral), D(rive)
    • alaphelyzet: P, „felváltás” után R, majd N, majd D. „Leváltás” ugyanez visszafele.
  • ACC: Állítható céltávolság (T jelű gombbal, körkörösen 0.8/1.0/1.2/1.4 másodperc)
  • ACC: Állítható célsebesség (+/- gombbal, 30-160, 10-es lépésközzel)
  • Lane Keeping bekapcsolás
  • Parkig pilot bekapcsolás
  • irányjelző (jobb, bal) kapcsolható
  • egyszerre több billentyű is használható
    • kanyarodni és gázt adni/fékezni minimum kell tudni egyszerre
  • Megjelenik a fordulatszám mint „analóg óra”
  • Megjelenik a sebesség mint „analóg óra”
  • Megjelenik a kormányállás
    • akár elforgatott kormánykerékként, de minimum szövegként
  • Megjelenik a gáz, fék állapota (progressbar)
  • Megjelenik a sebességváltó állása (szövegesen)
  • Irányjelző visszajelző (egy-egy nyíl kirajzolva)
  • Kocsi pozíció megjelenítése (x, y koordináta debug céllal, szövegesen)
  • Vezetéstámogató funkciók visszajelzései
    • ACC idő és sebesség limit
    • parking pilot és a lane keeping rendszerek állapot visszajelzése
  • az utolsó látott tábla megjelenítése
    • interfész biztosítása, az utolsó látott tábla beállítására
  • F1 billentyű lenyomására üzenetablak megjelenítése a vezérlőbillentyűket felsoroló súgóval

Világ(modell) kialakítása

A világmodell modul felelőssége a játék virtuális terének felépítése, az abban található elemek Objektum Orientált elveknek megfelelő hierarchiába szervezése, a virtuális tér elemeivel való interakciót biztosító (publikus) metódusok implementálása.

A modul bemenete a világ statikus elemeit tartalmazó állomány, amely XML és JSON formátumban is rendelkezésre áll. Ez a leíró fájl azonban csupán az objektumok síkbeli helyzetét, elforgatását és típusát tartalmazza. A modul felelőssége a többi modul igényeivel összhangban az objektumok további tulajdonságokkal történő felruházása. Például a rajzolást megkönnyítő Z index vagy az objektum térbeli kiterjedését szolgáló poligon definiálása.

A modullal kapcsolatos legfontosabb kihívás, hogy más csapatoktól érkező igényeket is teljesíteni kell, és „mindenki ezekre vár”. Így különösen fontos kezelni a sprinten belüli határidőket és prioritásokat. Például a deszerializált világobjektumok az első pillanattól kezdve szükségesek a megjelenítésért felelős csapat számára. Valamint, hogy minden tervezési döntés érinti a többi csapatot is, még ha ők ennek nincsenek is mindig tudatában.

  • Mielőbb el kell dönteni, hogy milyen koordináta-rendszerben dolgozik majd a modell. Teljesen járható út, hogy a modell, az input állományban található koordináta-rendszer egy az egyeben alkalmazásra kerül, ebből adódóan minden számolás abban történik, csak a megjelenítés transzformálja át. (A teljes világ nem fog kiférni a képernyőre.)
  • El kell dönteni, hogy mi legyen az objektumok referenciapontja. A megjelenítés során forgatni kell az objektumokat, a forgatási pont nem egyezik meg a referenciaponttal, de a megjelenítésnek szükséges.
  • A világ objektumokhoz poligonokat kell társítani, ezek szolgálnak majd az ütközés valamint a látótérbe kerülés eldöntésére.
  • Fontos továbbá, hogy ezek a poligonok nem a képfájl szélei. A fa esetében csupán a törzsének lehet nekimenni, nem a lombkoronának, ezért a modellt ekképpen kell megalkotni! A törzsnek használható egy szabályos hasáb az egyszerűség kedvéért.
  • Az autó is egyszerűsíthető, nem kell a grafikai elemet teljes mértékben követni.
  • A kanyarodó útelemeknél is lehet egyszerűsítést használni.
  • A szűréshez használt háromszög esetében a poligonokat kell figyelembe venni, pl. fa törzse, tábla rúdja, de nem csak az „ütközhető” objektumokat kell tudni visszaadni, hanem az útelemeket is. A 2. sprintben a szenzorok majd válogatnak, hogy mire van szükségük ezekből.
  • A poligonok megrajzolásához használható a VGG Image Annotator, amely böngészőből is működik és a megrajzolt polygont JSON-ben le lehet menteni.
    • Korábbi félév során @ArchiCat és @konyarilaszlo ezt már megtette, elérhető a worldobject_polygons.json állományban.
  • A poligonok definiálásához célszerű a java.awt.geom névteret használni. Ezek intersects könnyedén eldönthető, hogy egy objektum a szenzor látóterében van-e (amennyiben a szenzor is egy ilyen poligon).
  • A statikus objektumokon kívül a világ modell részét kell képezzék dinamikus, mozgó objektumok is.

A tervezés során nem elegendő csupán az első sprint (meglehetősen szűk) követelményit figyelembe venni, hanem célszerű ezen túl a későbbi sprintek során valamennyi user story-ban felbukkanó követelmény kezelése. Természetesen nem elvárás a „jövőbe látás”, de törekedni kell minden logikusan előrelátható követelmény kezelésére.

Definition of Done

  • Útelemeket, fákat, táblákat egyéb statikus objektumokat leíró állományok feldolgozása (deszerializálása)
    • kicsi pálya (test_world) és elemeinek megfelelő kezelése
    • nagy pálya (test_world_1kmx1km) és elemeinek megfelelő kezelése
    • ovális pálya (oval) és elemeinek megfelelő kezelése
  • Objektummodell implementálása világ leírására
    • A skeleton World objektuma a tartalmazza a felépített világot, pl. egy heterogén WorldObjects gyűjteményben
  • Objektumok kiterjedését biztosító poligonok beolvasása
  • Minden feldolgozott objektum rendelkezzen pozíció, referencia, orientáció, típusadatokkal
    • legyen olyan tulajdonság is, amellyel egyszerűen kiválogatható, hogy valaminek neki lehet menni (pl. fa) vagy nem (úttest)
  • A modell legyen felkészítve az input fájlból kiolvasott „statikus” objektumokon túl mozgó („dinamikus”) objektumok kezelésére is, amelyek kódból lesznek példányosítva
    • vezérelt autó, NPC (non-player-character) autó, gyalogos
  • A modell tegyen különbséget azon objektumok között amelyeknek egy jármű nekimehet és amelyeknek nem (fa vs. útelem)
  • A modell kezeljen „z-index”-et, hogy a kirajzolás során biztosítható legyen, hogy mely elemet kell előtt kirajzolni a „kitakarások” végett
  • A modell biztosítson egy publikus metódust, amellyel a világ objektumai szűrhetőek. A metódus bemenete 3 pont, amely meghatároz egy háromszög (szenzor látótér), a metódus válogassa ki azokat a világ objektumokat, amelyeket a szenzor „lát”, amelyekkel a háromszög érintkezik
  • A modell tegye elérhetővé a feldolgozott referenciapontokat, és a poligonokat is tulajdonságokon keresztül
  • A modell a beolvasott elforgatási mátrixot dolgozza föl, váltsa át elforgatási szögre és tegye elérhető egy tulajdonságon keresztül

Mozgatás: hajtáslánc és kormányzás

A mozgatás modul felelőssége a vezérelt autó (egocar) mozgatása, mozgásának számítása. Ez magába foglalja a hajtáslánc és a kormányzás megvalósítását.

A modul a HMI-től kap bemenetet, mindenek előtt váltóállás, gáz- és fékpedálállás valamint kormányelfordulás. A váltó automata, ami azzal jár, hogy a HMI a négy állapot (P, R, N, D) egyikét közli.

  • Park: Ez az egyik olyan állapot amiben a motor beindítható (a másik az N), ez a váltó alapállása, mechanikusan megszünteti az erőátvitelt. A valóságban nem helyettesíti kéziféket, de mivel azt nem kell implementálni a feladat során, lehet úgy tekinteni, hogy P-ben a kézifék is be van húzva. Az autó nem mozdul ebben az állásban.
  • Reverse: hátramenet
  • Neutral: üres, ebben az állásban sem jut a motorerő tengelyekre, a motor nem gyorsíthatja az autót. Ha üresben gázt adunk, a motor felpörög, méghozzá jelentősen, mivel nincs ami ellene dolgozna. Ha az autónak volt lendülete, az még hajtja tovább.
  • Drive: előremenet. A D-m belül definiálni kell 4-5 belső fokozatot (mint ahogy manuális váltónál is lenne), le kell programozni, hogy valamilyen fordulatszám értékeknél a váltó váltson. Ezen értékek meghatározásához lehet találni motorkarakterisztikákat (lehetőség szerint utcai autó kerüljön kiválasztásra, ne valami sportautó). A belső fokozatok a felhasználó interfész szempontjából transzparensek.

A pedál állások [0-100] skálán érkeznek. 0: nincs lenyomva, 1: 1%-ig van lenyomva, 100: tövig (100%-ig) le van nyomva. Minél jobban le van nyomva a gázpedál, annál több teljesítményt kell a motornak kiadnia. A motor belső működését nem kell részletekbe menően implementálni, pláne nem egy belső égésű motorét, egy elektromos hajtáslánc egyszerűbb. A szoftverben üzemanyag-fogyasztást (vagy akkumulátor töltöttséget) és hatótávokat nem kell kezelni.

A kormány jellemzően valamilyen áttétel segítségévél befolyásolja a kormányzott kerekek helyzetét. Ez ebben a szoftverben sokkal egyszerűbb is lehet. Ha 60°-ot tengelyelfordulást feltételezünk és a kormány „nulla” állásból +/- 60-at mozdulhat el, akkor lényegében 1:1-es „áttételünk” van. Ha az input +/- 100-as skálán adja meg a kormányelfordulás mértékét, akkor azt kell a tengelyelfordulásra képzeni. A bemeneti skálával kapcsolatban a HMI csapattal kell egyeztetni.

A úgymond kimenete egy mozgásvektor, vagyis az, hogy a következő ciklusban az autó (referenciapontjának) X, Y koordinátáit mennyivel kell módosítani. A pedálállás és a motor korábbi állapotának függvényében meghatározásra kerül a sebesség, a kormányállás valamint az egocar korábbi orientációjának függvényében meghatározásra kerül, hogy módosul-e az autó iránya, a kettő eredőjeként a teljes vektor.

A modullal kapcsolatban kihívás a hajtáslánc működésének és a mozgás és kanyarodás fizikájának megértése, implementálása. A fizika tekintetében sem kell elaprózni a dolgokat. Két erő elégséges: a motorerő mint gyorsítja a járművet (ez a gázpedállal szabályozható) és egy fékező erő, amelyet a fékpedállal lehet szabályozni, valamint ezen felül egy konstans fékező erőnek is lennie kell, tehát a fékező erő akkor sem nulla, ha a fékpedál állása nulla. Ez utóbbit mindegy minek nevezzük (légellenállás, csúszási-súrlódási erő, a kettő eredője, stb.), nem kell cicomázni, de legyen.

Külön feladat észben tartatni és célszerűen előre felkészülni arra, hogy a 3. sprintes vezetéstámogató modulok (LKA, AAC, AEB, PP) közvetlenül az egocar hajtásláncára és a kormányra hatnak. Fel kell készíteni a modult ilyen, „nem a HMI-ről” érkező inputok kezelésére is, amelyek ráadásul magasabb prioritásúak. Pl. ha a vészfékező rendszer „lenyomja” a fékpedált, akkor magasabb prioritással kell kezelni mint a HMI-ről érkező pedálállást.

Definition of Done

  • Az autó gázpedál állásától függően gyorsul
  • A gyorsulás a „belső fokozatok” szerint kerül meghatározásra
  • Az autó a gázpedál felengedésével fokozatosan lassul, majd megáll
  • Az autó R válóállásban tolat
  • Felkészíteni a modult, hogy a vészfékező, az adaptív tempomat vagy a parkoló asszisztens is küldhet inputot, melyek magasabb prioritásúak
    • vészfékező értelemszerűen fékezés inputot
    • az adaptív tempomat és a parkoló asszisztens gáz és fék inputot is
  • Buszról érkező kormányállás felhasználása
  • Autó kanyarodásának biztosítása valóságos fordulókör szerint
    • ehhez szükséges extra tulajdonságot meghatározása
  • Tényleges mozgásvektor meghatározása a motor csapat gyorsulás, lassulás értékének felhasználásával
  • A meghatározott mozgásvektor alapján az autó pozíciójának frissítése
    • az AutomatedCar osztály x,y koordinátáinak frissítése
  • Tolatás során is valósághű kanyarodás történik
  • Felkészíteni a modult, hogy a sávtartó automatika vagy a parkoló asszisztens is küldhet kormányzás inputot

Vizualizáció

A vizualizációs modul felelőssége a játék virtuális terének, pontosabban a képernyőn megjeleníthető részének kirajzolása miután a világ lényegesen nagyobb mint ami a programablakba egyszerre belefér. A modul csak megjelenít, a modellt a világmodellért felelős csapat állítja össze. Ebbe nem csak a pálya statikus elemei tartoznak, hanem értelemszerűen a dinamikus objektumok is. A megjelenítés középpontja az mindenkor vezérelt autó (egocar).

Továbbá, a modul felelőssége a debuggoláshoz és teszteléshez használandó segédobjektumok opcionálisan bekapcsolható megjelenítése. Ide tartozik a szenzorok látómezeje, a világobjektumok „poligon váza”, valamint utóbbiak eseményre történő kiemelésének lehetősége. Ez utóbbi akkor történik, amikor majd a 2. sprintben létrehozandó szenzor látómezejébe kerül pl. egy fa, akkor a szenzor a fa kiemelés tulajdonságát bebillenti és ekkor a megjelenítésnek valami más színt kell tudnia használni (a poligon kirajzolására, esetleg kitöltésére).

A programablaknak az alábbi módon nézni majd ki. Két jól el különülő részre oszlik, a nagyobb baloldali a viewport, amelyen keresztül a világ éppen megjelenített része látható. A jobb oldali a műszerfal, amely nem tartozik e modul felelősségi körébe.

gui_plan

A modullal kapcsolatos kihívása a rajzoláshoz használt keretrendszer megismerése, az objektumtranszformációk megfelelő végrehajtása és az objektummodellért felelős csapattal egyeztetés az objektumok elérését illetően. Bár a modul függ a világmodelltől, a munka értelemszerűen nem akkor kezdődik mikor az a modul elkészült. A világobjektumok képfájljai és a világot leíró állomány kezdettől fogva rendelkezésre áll, nem kell megvárni a teljes modell elkészültét.

Definition of Done

  • a megjelenés villódzásmentes és folyamatos legyen
  • A kirajzolt világ egy része látható csak állandóan a programablakban, a „kamera” a vezérelt autót (egocar) követi
    • világ széleinek kezelése
  • statikus objektumok pozícióhelyes kirajzolása és résmentes illesztése a rendelkezésre álló építőelemekből
  • mozgó objektumok helyes kirajzolása
  • debug célból meg kell tudni jeleníteni az egyes objektumokhoz definiált poligonokat
  • interfészt kell biztosítani, hogy egy megcímzett objektum poligonja eltérő színnel jelenhessen meg (ha kijelölésre kerül)
  • interfészt kell biztosítani a szenzorok látóterét jelképező háromszögek opcionális megjelenítésére
    • típusonként (radar, kamera, ultrahang) külön-külön kapcsolhatónak kell lennie és más-más színnel kell megjelennie (piros, kék, zöld)

2. Sprint

Ultrahang szenzor implementálása

Az ultrasonic sensor modul felelőssége a parkoló automata alapjául szolgáló ultrahang szenzorcsomag szimulációjának implementálása. Mint minden szenzor, az ultrahang is érzékeli a világ egy szeletét és eléri a látóterében található objektumokat.

A valóságos és szimulált szenzorok működését részletesebben a Szenzorok fejezet mutatja be.

A modul bemenete tehát a világmodell, kimenete olyan ütközhető világ objektumok gyűjteménye képezi, amelyek beleesnek a szenzor látóterébe. A világ objektumainak lekérdezésére már léteznie kell egy publikus metódusnak, mely 3 pontot vár bemenetként és visszaadja a bele eső objektumokat. Ezekből kell még leválogatni a relevánsakat. A szenzor látóterét 3 ponttal kel definiálni.

A kamera és a radar szenzorhoz képest a legfőbb különbség, hogy ultrahang szenzorból 8 példány kerül az autóra. Minden példány látómezejének 3 pontját folyamatosan frissíteni kell az autó pozíciójának függvényében. Vagyis az autó egyébként folyamatosan frissülő referenciapontjához képest kell definiálni. A megjelenítés is felhasználja ezeket a pontokat a háromszög kirajzolására a debuggoláshoz.

Ultrahang szenzorok elhelyezése

Definition of Done

  • 8 db ultrahang szenzor, egyenként 3 méter látótávolsággal, 100° látószöggel
  • A 8 darab háromszög koordinátái az autó helyzetétől függően folyamatosan frissülnek
  • A látószög és távolság által meghatározott területen kérjék el a releváns objektumokat
  • Határozzák meg a legközelebbi (ütközés szempontjából) objektum pozícióját, kiterjedését, távolságát
    • külön-külön minden egyes szenzor, majd a rá épülő funkcionalitás fog ezekkel tovább dolgozni, tehát célszerű biztosítani a példányonként legközelebbi objektum továbbadását
  • A legközelebbi objektum legyen vizuálisan kiemelve
    • a kiemelés megjelenítését a vizualizáció intézi az objektum tulajdonsága (kijelöltség) alapján, de azt, hogy éppen ki van-e jelölve a szenzornak kell az objektumon beállítani

Kamera szenzor implementálása, Ütközés detekció (és mozgásállapot-változás szimuláció)

A kamera modul felelőssége a sávtartó automatika és táblafelismerő alapjául szolgáló kamera szenzor implementációja. Mint minden szenzor, a kamera is érzékeli a világ egy szeletét és eléri a látóterében található objektumokat.

A valóságos és szimulált szenzorok működését részletesebben a Szenzorok fejezet mutatja be.

A táblafelismerőnek csak továbbítani kell minden látott táblát, az majd eldönti, hogy melyik miképp releváns a vezérelt autóra nézve.

A sávtartó automatika az összetettebb feladat, ugyanis meg kell tudni határozni a sávot (ebben segítenek az útelemek részét képező sávokat reprezentáló geometria objektumok). Tehát a világmodell már jól definiált módon rendelkezésre bocsátja a sávinformációkat, de ezeket olyan adatstruktúrába kell rendezni, amely megkönnyíti a sávtartó automata implementálását: a sávtartó automatikának arra lesz majd szüksége, hogy az autó közelít-e a sávját meghatározó felfestésekhez, a sáv határait.

A modul bemenete tehát a világmodell, kimenetét olyan világ objektumok gyűjteménye képezi, amelyek beleesnek a szenzor látóterébe. A világ objektumainak lekérdezésére már léteznie kell egy publikus metódusnak, mely 3 pontot vár bemenetként és visszaadja a bele eső objektumokat. Ezekből kell még leválogatni a relevánsakat. A szenzor látóterét 3 ponttal kel definiálni. Miután a szenzor kimenetét két különböző típusú világobjektumokat igénylő funkció használja, a kimenete legyen ennek megfelelően szétválasztva. Így a kimenet valójában két gyűjtemény, az egyik csupán táblákat, a másik útelemeket tartalmaz.

A szenzor látómezejének 3 pontját folyamatosan frissíteni kell az autó pozíciójának függvényében. Vagyis az autó egyébként folyamatosan frissülő referenciapontjához képest kell definiálni. A megjelenítés is felhasználja ezeket a pontokat a háromszög kirajzolására a debuggoláshoz.

Definition of Done

  • 1 db, a szélvédő mögé elhelyezett kamera implementálása
  • A látószög és távolság által meghatározott területen kérje el a releváns objektumokat
    • külön, a táblafelismerő szempontjából releváns objektumok, a táblák
    • külön, a sávtartó szempontjából releváns objektumok, az utak
  • A háromszög koordinátái az autó helyzetétől függően folyamatosan frissülnek
  • a legközelebbi objektum legyen kiemelve

Ütközés-detektálás

Folyamatosan vizsgálni kell, hogy a vezérelt autó nekiütközött-e egy ütközhető objektumnak. Ennek vizsgálatához használható a világobjektumok poligon váza. Később majd az automatikus vészfékező modul feladat lesz, hogy ez ne következhessen be.

  • A vezérelt autó - tereptárgy ütközésének detektálása és esemény kiváltása
  • A vezérelt autó - NPC-vel való ütközésének detektálása és esemény kiváltása
  • Két objektum akkor ütközött amikor a poligon reprezentációjuk összeért, nem amikor a képfájlok fedik egymást
    • pl. autó a fa lombkoronája alatt, de még nem érte el a törzset
  • Legyen valami visszajelzés felhasználói felületen arról, hogy ütközés történt (pl. alert dialog)

Mozgásállapot-változás szimuláció

2021 tavasz: nem feladat

A modul felelőssége, hogy az ütközésben részt vevő objektumok mozgásállapota az ütközés ereje függvényében megváltozzon. Ehhez egyrészt szükséges az objektumok sebessége, irányvektora és tömege is. Tömeg értékekkel a modell még nem rendelkezik ezek hozzáadása szintén a feladat része. Az autó, gyalogos, biciklis objektumokhoz keresni kell egy átlagos értéket. A statikus objektumok esetében azt is figyelembe kell venni vagy a tömeg értéken keresztül vagy ennél realisztikusabban, hogy rögzítettek. Pl. egy épület tömegét meg lehet választani kvázi végtelen nagyra így az nem tud elmozdulni az ütközés hatására. Egy ha esetében is hasonlóan lehet eljárni, egy táblát viszont könnyen elsodorhat egy autó.

  • Az objektumok mozgásállapota az energiamegmaradás törvényeinek megfelelően változik (gyorsul, lassul, irányt vált, megáll)
    • Ha a vezérelt autó nekimegy egy NPC autónak akkor ez legyen rá hatással (lassuljon le)
    • Ha a vezérelt autó nagyobb sebességgel nekimegy egy „stabil” tereptárgynak (pl. fa), akkor álljon meg, érjen véget a játék, tekintsük úgy, hogy totálkáros.
      • egy táblán azonban át tud menni (el tudja sodorni), csak lassuljon le és sérüljön egy kicsit
  • Az objektumok sérülnek, akár megsemmisülnek amennyiben túl nagy energiával ütköznek
  • Ha a vezérelt autó elüt egy gyalogost, akkor érjen véget a játék
  • A játék véget ér, ha a játékos ütközés(ek) következtében mozgásképtelenné válik (megsemmisül)
  • Az NPC - NPC ütközés nem releváns
    • tehát ha NPC autó üti el a gyalogost, akkor nem kell, hogy véget érjen a játék
  • Kisebb sérüléseknél a játékot ne kelljen újraindítani, valami inputra lehessen resetelni akár
    • sérülés visszaállítása nullára, vagy autó pozíciójának módosítása, hogy az ütközés már ne álljon fönt

Világ populálása mozgó NPC objektumokkal

A modul felelőssége, hogy az előző sprintben felépített világot, amelyben már megjelennek a statikus objektumok és van egy működő, vezethető autó, további dinamikus objektumokkal kell kiegészíteni. Ezek a nem játszható karakterek (NPC, non player character), amelyekre azért van szükség, hogy a 3. sprintes modulok tesztelhetők legyenek. Például a vészfékező rendszer nem üti el a gyalogost, vagy az adaptív tempomat igazítja az autó sebességét az előtte haladó autóéhoz.

A modul bemenete a világmodell, amely egyrészt elősegíti az implementálást azáltal, hogy a előre definiált helyett az osztályhierarchiában az NPC objektumok számára, másrészt a statikus objektumok, egészen pontosan az út elemek definiálják a pályát amelyen az NPC autónak haladnia kell a KRESZ szabályai szerint: nem tér át az út másik oldalára, nem hajt gyorsan.

A legkézenfekvőbb megoldás, hogy a világban, a világ koordinátáira építve felveszünk vezérpontokat, amelyek kijelölnek egy utat. Ezeket célszerű nem a kódban, hanem valamilyen fájlban tárolni. Az NPC objektum pedig ezt az utat követni. Például a parkoló mellől indul az úton megy fölfele (csökken az y koordinátája) a kanyar előtt (x,y) világkoordinátákat elérve lelassul, (x,y)' koordináták elérése esetén elkezd kanyarodni, a sávból nem tér ki, majd (x,y)" koordinátáig halad a fönti egyenesen. És így tovább.

A mozgáshoz sebességet is kell társítani. Két vezérlőpont közötti egyenesen adott idő alatt kell az NPC-nek végighaladnia. Továbbá az egyes vezérlőpontokhoz forgatási műveletet is társítani kell. Ehhez egy mozgás leíró struktúra lesz szükséges, pl. az alábbi elnagyolt példa TOML nyelven, de bármilyen megoldás választható (JSON, XML, YAML vagy teljesen egyedi formátum):

[points]

[points.1]
x = 100
y = 200
rotation = 0
speed = 50 # px/s

[points.2]
x = 100
y = 100
rotation = 15
speed = 30 # px/s

A feladatban az igazi kihívás, hogy az NPC objektumok adaptálódjanak pályához. Az adaptálódást úgy lehet megkerülni, hogy mindkét pályához készül egy-egy útvonal.

Az NPC autónak nincs hajtáslánc modulja, nem szükséges olyan részletes mozgatás sem mint az vezérelt autónál, de azért a kanyarpontoknál legyen több lépésben megoldva, hogy fokozatosan legyen az autó elforgatva a kanyarodás valósághű leképezése céljából.

Definition of Done:

  • Objektumok előre definiált, értelmes helyen jelennek meg (autók úton, gyalogosok út mellett, a járda környékén)
  • Objektumok előre szkriptelt útvonalat követnek
  • Gyalogosok az út mentén haladnak, zebrán áthaladnak, megfordulnak majd újra átkelnek az úton
  • Autók az utat - sávot - pontosan követik
  • NPC objektumok egymás mozgásállapotát nem változtatják meg
    • Egy NPC autó gyalogoson akár átmehet, nem kell ütközésnek minősíteni
  • Legalább egy autó végigmegy a pályán
  • Legalább egy gyalogos mozog és átkel egy zebrán
  • Új (a másik) pálya esetén az NPC objektumok adaptálódnak az új környezethez

Radar szenzor

A radar sensor modul felelőssége az adaptív tempomat és az automata vészfékező alapjául szolgáló radar szenzor szimulációjának implementálása. Mint minden szenzor, az radar is érzékeli a világ egy szeletét és eléri a látóterében található objektumokat.

A valóságos és szimulált szenzorok működését részletesebben a Szenzorok fejezet mutatja be.

A modul bemenete tehát a világmodell, kimenetét olyan ütközhető világ objektumok gyűjteménye képezi, amelyek beleesnek a szenzor látóterébe. A világ objektumainak lekérdezésére már léteznie kell egy publikus metódusnak, mely 3 pontot vár bemenetként és visszaadja a bele eső objektumokat. Ezekből kell még leválogatni a relevánsakat. A szenzor látóterét 3 ponttal kel definiálni.

A szenzor látómezejének 3 pontját folyamatosan frissíteni kell az autó pozíciójának függvényében. Vagyis az autó egyébként folyamatosan frissülő referenciapontjához képest kell definiálni. A megjelenítés is felhasználja ezeket a pontokat a háromszög kirajzolására a debuggoláshoz.

Radar szenzor elhelyezése

A kihívás a komponenssel kapcsolatban, hogy nem elég egyszerűen csak visszaadni a látótérben található releváns objektumokat, hanem el kell tudni dönteni, hogy a jelenlegi haladási irányunkat tartva veszélyesek-e. Pl. pontosan előttünk halad (a sávban), vagy oldalról érkezik és keresztezi az utunkat. A legközelebbi releváns objektum az alábbi ábrán az 1-es, a 2-es nem.

Azonos sávban haladó jármű

Itt arról van szó, hogy a a szenzor egy iterációjában megkapjuk a látótérbe került ütközhető objektumokat. Egy fa pl. jellegénél fogva statikus, tehát túlzottan sok figyelmet nem igényel, de ugyanúgy továbbítani kell mint egy autót. Az NPC autó esetében az adott iterációban ismert az autó helyzete, majd ezt össze kell vetni az előző iterációban ismert helyzetével. A kettőből meghatározható egy irányvektor és el lehet dönteni, hogy merre halad (ha halad egyáltalán), előttünk halad, vagy mellettünk (pl. másik sávban), stb. Az ACC az azonos sávban előttünk haladó autó sebességét veszi fel, ezért az autó haladási iránya fontos szempont.

Mindez értelemszerűen egy statikus objektum pl. fa esetében is működik, csak az nem mozog (mert nem Középföldén vagyunk).

Definition of Done

  • Elkészült 1 db, az autó első lökhárítója mögött elhelyezett radar szenzor
  • A látószög (60°) és távolság (200m) által meghatározott területen kérjék el a releváns objektumokat
  • A háromszög koordinátái az autó helyzetétől függően folyamatosan frissülnek
  • Határozzák meg a legközelebbi, sávon belüli (lateral offset alapján) objektum helyzetét
  • Az automata vészfékező számára releváns objektumok (az autó középvonala felé halad, látjuk) kiválogatása és visszaadása
  • A legközelebbi objektum legyen vizuálisan kiemelve
    • a kiemelést a megjelenítés intézi az objektum tulajdonsága (kijelöltség) alapján, de azt, hogy éppen ki van-e jelölve a szenzornak kell az objektumon beállítani

3. Sprint

Parkoló automatika

A modul felelőssége az ultrahang szenzorokra épülő Parking Pilot vezetéstámogató funkció elkészítése. Ennek feladata, hogy a megtalálja a parkolóban a megfelelő nagyságú szabad helyet, majd oda -- vezetői beavatkozás nélkül -- beparkolja az autót.

A parkolóig még a sofőr vezet, megáll az autósor mellett aktiváltja a parkolóhely keresést (bekapcsolja a PP-ot és kiteszi az irányjelzőt abba az irányba ahol a parkolót keresni kell), majd továbbra is "emberi" irányítással el kell haladni a parkolóhelyek mellett. Eközben a funkció kiszámolja a szabad hely méretét. Amikor megvan az alkalmas hely, akkor visszajelzést kell adni a sofőrnek és a hely dimenzióját és az autóhoz viszonyított helyzetét le kell tudni írni (és átadni a buszon, ha a manőver végrehajtását végző komponens el van választva a kereső komponenstől).

A parkolóhely a vezérelt autó (ennek ismert a szélessége és a hosszúsága) referenciapontjához viszonyítva legyen leírva. A parkolóhely hossza nem a felfestett parkolóhely hosszát jelenti. Egyrészt nem garantált, hogy mindenki szabályosan parkol, másrészt azt nem is lehet az ultrahang szenzorral lemérni. Ehelyett két parkoló autó által szabadon hagyott helyet (amely akár két felfestésnyi is lehet) kell detektálni.

A szabad hely szélessége ha egyéb akadályt -- pózna (bollard.png) vagy fa -- nem tesztek külön emiatt, támpontként a pályára, akkor a szenzor látótávolsága, azaz 3 méter. A szabad helyhez egy referenciapontot kell (érdemes) társítani, pl. a helyet leíró téglalap bal felső pontja (ábrán így van) és az autó középpontjával és ezzel a ponttal (ebből számolható a távolság) valamint a hely dimenzióival kielégítően jellemezhető a parkoló hely.

Miután a hely keresése során még a sofőr vezet, a „van szabad parkoló” jelzésre vélhetően nem egy előre definiált pozícióban állítja meg az autót. Ezért fontos, hogy a szabad hely mindig a vezérel autó pozíciójához képest legyen definiálva, mert a parkolási manőver kezdetéig esetleg valamennyit hátra kell majd tolatni.

Ezután, (ha más nem próbálgatásos módszerrel) ki kell tapasztalni, hogy a szükséges "párhuzamos parkolás" manőver hogyan vihető végbe a vezérelt autó irányítószerveivel, majd ezt le kell automatizálni: pl. le kell írni, kormány jobbra teker 100-ra, gáz 25% 1,5s-ig, majd kormány balra 75, gáz 20% 1.25s-ig. Ez hasonló az NPC objektumok szkripteléséhez.

A programozott vezérlést a buszon keresztül kapott szabad helyet leíró adatok függvényében kell elindítani (amelyhez szükséges lehet tehát egy előzetes tolatás is.

Definition of Done

  • Indexkapcsoló állása alapján parkolóhely keresés jobbra vagy balra
  • Autó méretének megfelelő hely beazonosítása
  • Megtalált parkoló jelzése, a hely információinak buszra írása (packet-tel)
  • A parkolóhely megtalálásához szükséges NPC-k példányosítása
  • A parkolás megkezdése külön inputhoz kötött (van erre vonatkozó gomb a műszerfalon, inputtól meg billentyűesemény)
  • A kormány és gáz/fék vezérlésével beparkolás a talált helyre
  • Párhuzamos parkolás sikeres (ütközés nélkül megtörténik)
  • Sofőr beavatkozására (fék, gáz, kormány) kikapcsolás (megszűnik az automata vezérlés)

Sávtartó automatika és táblafelismerés

A sávtartó automatika modul felelőssége a kamera szenzorra épülő Lane Keeping Assistant funkció megvalósítása.

Ezt két alapvetően kétféleképpen lehet megoldani. Az egyik a sáv széleihez viszonyítva korrigál: ha az autó elérné a sáv szélét, akkor ellenkormányoz. A másik megoldás kiszámolja a sáv közepét és azon tartja az autót.

1. Sáv széleinek használata

Itt azt lehet vizsgálni, hogy a vezérelt autó jövőbeli helyzetében metszi-e a sávot.

2. Sávközép használata

Itt a vezérelt autó középpontját lehet a sávközéphez igazítani.

Csak a 45 foknál enyhébb kanyarodású úton kell működnie, ilyenkor a kocsi a sáv szemmel látható közepét követi. Az LKA működése egy enyhe sávon belüli cikázást eredményez.

Az automatika számára kezelhetetlen forgalmi szituációkban (pl. éles kanyar, kereszteződés) el kell engednie a vezérlést és ezt a vezető tudtára kell hoznia. Legyen hozzá vizuális figyelmeztetés a műszerfalon (pl. LKA visszajelző sárga). Ha újra olyan útszakasz következik, ahol a funkció használható, akkor arról szintén legyen tájékoztatás. Ezen kívül természetesen a funkció ki- és bekapcsolható.

A Táblafelismerő modul felelőssége a kamera szenzor látómezejébe kerülő közlekedési táblák közül kiválogatja a relevánsakat (csak az adott irányra/sávra vonatkozó) és a műszerfalnak átadja megjelenítésre az utolsó látott releváns táblát, továbbá beállítja a buszon az aktuális sebességkorlátozást, amelyet az adaptív tempómat modul használ majd. Ez debug információként jelenjen is meg a műszerfalon (szövegesen mint az X,Y koordináták).

Definition of Done

  • A sávtartó automatika ki- és bekapcsolható
    • emberi beavatkozásra kikapcsol
  • 45 foknál enyhébb kanyarodású úton a kocsi a sáv szemmel láthatóan a sáv közepén marad
  • Ha el kell engednie a kontrollt (az automatika számára kezelhetetlen forgalmi szituáció következik, pl. éles kanyar, kereszteződés), vizuális figyelmeztetést ad
  • Ha újra elérhető a funkció (pl. elhagytuk a kanyart) vizuális indikáció (a műszerfalon)

Táblafelismerő:

  • az utolsó látott, releváns tábla megjelenik a műszerfalon
  • az utolsó sebességkorlátozás kiírásra kerül a buszra
    • és megjelenik debug információként a műszerfalon

Adaptív tempomat

A modul felelőssége a radar szenzorra épülő adaptív tempomat vezetéstámogató funkció elkészítése. Ennek a funkciónak három felhasználói esetet kell lefednie.

  1. Felhasználó által beállított sebesség tartása
  2. A táblafelismerő által közölt sebességkorlátozás betartása
  3. Az előttünk haladó (NPC) autó sebességének felvétele és egy (időben definiált) beállított követési távolság tartása
    • Valójában ettől lesz adaptív

Az egyes ponthoz szükséges kezelőszervek már elkészültek az első sprintben és a funkcióhoz szükséges bemeneti értékek már a buszon keresztül elérhetőek. A modulnak szabályoznia kell a hajtásláncot, hogy ne léphesse túl a beállított sebességet. Ehhez olyan inputot kel biztosítania mintha az a billentyűzetről érkezne, de a tényleges vezetői input felülírja őket.

A kettes pont egy harmadik sprintes (tehát aktuálisan készülő funkciótól függ), azonban könnyen visszavezethető az első pontra. A közúti szabályozást magasabb prioritásúnak kell minősíteni. Tehát a felhasználó pl. beállít egy 70 km/h-ás célsebességet, majd érkezik egy kérés a táblafelismerőtől, hogy 50km/h a megengedett, akkor azt kell figyelembe venni.

A hármas pont egy második sprintes modultól, az NPC autók meglététől függ. Az előttünk haladó sebességéhez való igazodás a legmagasabb prioritású, hiszen hiába szeretne a vezető 70-el haladni, mikor a tábla szerint 50-nel lehet, de ha az előttünk haladó mindössze 40-el halad, akkor ahhoz kell igazodni, különben nekiütközünk. Oda kell figyelni, hogy csak a sávban előttünk haladó autót vegye figyelembe, a szembejövőt ne.

A követési távolság időben történő megadása azt jelenti, hogy a beállított (pl.) 1 másodperces követés esetén akkora távolságot kell hagyni, hogy az aktuális sebességgel haladva 1 másodperc alatt megtett út legyen a távolság: 10 m/s (36 km/h) esetében 10 méter. Ezen érték beállítására már az első sprintben készült vezérlő.

Definition of Done

  • Ki- és bekapcsolható
  • Bekapcsoláskor a célsebessége az aktuális sebesség, de a minimum célsebesség 30 km/h
  • Ha nincs saját sávban előttünk autó, akkor a vezérelt autó tartja a kiválasztott célsebességet
  • Ha a saját sávban található autó:
    • Ha az előttünk levő autó lassabb, akkor fel kell venni a sebességét
    • Ha gyorsabb, akkor tartja a kiválasztott sebességet
  • Fékezésre kikapcsol
  • AEB beavatkozásra kikapcsol
  • Ha sebesség korlétozást talál a buszon, azt alkalmazza új célsebességként, amíg a sofőr felül nem írja

Vészfékező

A modul felelőssége a radar szenzorra épülő automata vészfékező rendszer megvalósítása. A vészfékező kritikus biztonsági funkció, így nem kapcsolható ki manuálisan, de maximum 70 km/h sebességig működik. A működése két esetre bontható: ütközés statikus vagy dinamikus objektummal.

Az előbbi az egyszerűbb eset, mivel a veszélyt jelentő objektum pozíciója változatlan.

El kell dönteni, hogy az autó az aktuális irányvektort figyelembe véve ütközni fog-e az objektummal. Ha igen, az autó ismert sebességét figyelembe véve kiszámolható, hogy ehhez mennyi időre van szükség és, hogy mekkora mértékű lassulás kell ehhez.

A radar visszaadja az autó előtt levő legközelebbi releváns objektum adatait (táv, sebesség), ezekkel lehet számolni. A távolságból és az autó sebességéből meghatározható, hogy milyen lassulást kell adni az autónak, hogy még megálljon, de ne lépje túl a \( 9 m/s^2 \)-et.

Ha az ütközés elkerülhető, vizuális figyelmeztetést kell elhelyezni a vezetőnek, hogy fékezzen. Ha nem reagál, azaz továbbra is ütközési pályán vagyunk és már csak vészfékezéssel kerülhető el az ütközés, akkor a hajtásláncnak vészfékezési inputot kell adni. Ez a maximálisan megengedett, \( 9 m/s^2 \)-es lassulást (ennél nagyobb lassulás veszélyes az utasokra), akkor

Ha más nem próbálgatással meg kell határozni, hogy adott sebességről egy maximális fékezési input (100% pedál állás) mennyi idő alatt fékezi állóra az autót. A modul olyan triggerekkel vezérli az autót mint amilyenek a billentyűlenyomás kezelőtől jönnek (fékpedál állás).

Dinamikus objektumok esetében a vészfékezés elve azonos, de az ütközési pálya meghatározása összetettebb.

Másik sávban szembe jövő autóra nem kell vészfékezni, tehát el kell tudni dönteni, hogy abban az esetben nincs ütközési pálya.

Definition of Done

  • Elkerülhető ütközés esetén vizuális figyelmeztetés a sofőrnek
  • Ha a sofőr nem avatkozik közbe, automatikus fékezés (az utolsó pillanatban, ahol az ütközés még elkerülhető)
  • Az automatikus fékezés mértéke a sebességgel arányos, de nem lehet \( 9 m/s^2 \)-nél nagyobb
  • 70 km/h felett figyelmeztetés, hogy az AEB nem tud minden helyzetet kezelni
  • A vezérelt autó nem üt el gyalogost, nem megy neki fának
  • Nem releváns objektumok esetében (fals pozitív) mint a szembejövő autó nem történik vészfékezés

Tolatóradar / Tolatókamera

A modul felelőssége a hátsó két ultrahang szenzorra épülő tolatóradar (és kamera) implementálása, amely visszajelzést ad a vezetőnek, arról, hogy tolatás közben veszélyesen közelre került-e valamilyen objektumhoz. A távolság számoláshoz itt is lehet használni az objektum referenciákat, az objektum koordinátái közvetlenül elérhetőek, de ne az objektum közepéhez, hanem értelem szerűen annak széléhez képest legyen kiszámolva a távolság.

Hozzá tartozó GUI, Valami ehhez hasonlóként lehet elképzelni: YouTube videó. A bal- és jobboldali szenzor legközelebbi objektumának értéke külön-külön kerüljön megjelenítésre.

A tolató radar mellé legyen a tolatókamerák távolságkijelzése is megvalósítva a pályamegjelenítőjén, három lépcsőben 0.5m piros, utána 1m sárga majd az autó hosszáig zöld. Ez hátramenetben kerüljön megjelenítésre, nem debug-funkcióként.

Definition of Done

  • a tolatóradar csak hátramenetben aktív
  • figyelmeztetés megjelenítése a műszerfalon 3 fokozatban
    • nincs akadály (zöld)
    • közel van akadály: 0.8m-en belül (sárga)
    • nagyon közel van akadály 0.4m-en belül (piros)
  • távolság megjelenítése a műszerfalon
  • távolságok kirajzolása a képernyőre
    • az autó pozíciójához képest folyamatosan frissül
    • hátramenetben mindig látszik (nem debug funkció)

Korábbi implementáció (ekkor csak a műszerfalas visszajelzés volt feladat):

Demók

A félév során a csapatok három alkalommal prezentálják az elvégzett munkát. A „demók” az elkészült szoftver megrendelőnek való bemutatását szimulálják. Nem a kódra vagyunk kíváncsiak, hanem működés közben szeretnénk látni, hogy a szoftver teljesíti feladatban foglalt követelményeket. A bemutatás során, a master branchre befogadott kódot vesszük figyelembe, minden egyéb „nem készült el határidőre”, azaz értékelhetetlen.

Ideális eset az első sprint után

A „megrendelő” az aktuális master branchről elindítja a szoftvert, az ablak bal oldalán ott van az autó (középen), az út fölé helyezve, jobb oldalon a műszerfal mutatja az állapotát. Sebességbe teszi az autót, majd gázt ad, elindul, kicsit mászkál a világban, teszteli a gyorsulás, lassulás és kanyarodás „érzetét”, közben megfigyeli a pálya illesztéseit és a „grafika folytonosságát”. Még kipróbálja a debug funkciókat és egyéb kapcsolót a rend kedvéért.

konklúzió: a pálya hibátlanul kirajzolásra került, emögött vélhetően van egy modell világ, hiszen a poligonok is rendben a helyükön vannak, az autó mozgása „rendben van”, nem volt cél egy profi autószimulátor szintű fizika, ha a sebesség-változások és a fordulás nem mutat kiugró rendellenességet, az autó pontosan vezethető (érts, végre tudok hajtani pl. egy párhuzamos parkolást), és a műszerfal közvetíti azt amit látunk, akkor mind a 4 csapat kifogástalan munkát végzett, mindenki teljesítménye 5-ös, lehet foglalkozni érdekesebb témákkal.

Realisztikus demó, sok félév tapasztalata alapján

Eleve még reggel 3/4 8-kor fogadom el az utolsó PR-eket (amik esetenként éjfél után készültek el), tulajdonképp érdemi review nélkül, mert nem akarom, hogy ezen múljon a demó sikeressége, ha fordul, nincs ütközés és az automatizált ellenőrzések sem mutatnak hibát akkor beengedem a masterbe.

A szoftver máskor nem is indul, mert valaki a C:\Users\XYZ\ÓE\AutomatedCar\Assets mappát beégette a kódba. Ezt ott élesben kijavítjuk, végre nem száll el kivétellel. A műszerfal vezérlőinek egy része ott van, de nincs bekötve, nem az autó állapotát, hanem konstans dummy értékeket mutat, rosszabb esetben azért, mert skeleton dummy mozgatása aktív még mindig, jobb esetben azért mert a hajtáslánc ugyan mozgatja az autót, de nem propagálja az állapotát a műszerfal felé. Néha az történik, hogy a hajtáslánc propagálja ezeket, de X csomagban, míg a hajtáslánc Y csomagot vár.

A fordulókör kicsit irreális, de azért kanyarodni lehet, nincs nagy vész, akár 1 óra alatt fixálható; az autó gyorsul, de irreálisan gyorsan vagy lassan. Teljesen egyértelmű, hogy a kollégák alapos munkát végeztek a mozgatás fizikai részének implementálásában, utánaolvastak meg minden, de sosem próbálták ki, hogy milyen érzés vezetni az autót, mert akkor rájöttek volna, hogy pár konstanst finomhangolni kell. Ebben minden bizonnyal az is közrejátszhatott, hogy a kód eleve exception-el elszállt és a hiba nem az ő térfelükön volt, a felelős csapatnak meg, a demó előtti szerda este 8-kor jelentett bugot meg már nem tudta időben javítani.

A képfájlok gyakran nem illeszkednek, némelyik elem nem úgy van elforgatva, ahogy kellene. Ugyanaz a helyzet mint fentebb, valami nem úgy volt kommunikálva, valaki úgy gondolta, hogy fokban van a szög, más meg úgy, hogy radiánban. Látszik, hogy a munka nagyja kész, de a pályára nem lehet azt mondani, hogy ki van rajzolva, mert tulajdonképpen csak összevissza kirakott útdarabokat látni. Mivel már a képek sem kerültek ki hibátlanul, így a poligonokhoz hozzá sem nyúltak, mondván ha a képek jók, akkor a poligonok kirakása gyerekjáték (valóban), de arra nem jutott idő.

Ezek után és közben egy-egy kolléga hevesen elkezdi mutogatni a kódot, hogy de hát itt van az elforgatás implementálva, mindenki lássa bele azt amit ő lát, hogy ez a metódus, amihez még unit tesztet is írt, tényleg hibátlanul el tud forgatni egy útelemet.

Aztán gyakori jelenség még, hogy a csapat jelzi, hogy sajnos odáig nem jutottak el, hogy a masterbe kerüljön a kód, de ők szeretnének saját branch-ről/gépről prezentálni. Ilyenkor rábólintunk, hátha látunk valami lenyűgözőt. A kolléga néha ekkor indítja az IDE-t, de se baj, után a még átváltja a branch-et, elindítja de nem az történik amit várt, majd a csapattársa jelzi, hogy már ne a team3_perfect_steering branchet nézze, hanem a team3_perfect_steering2-t, mert ő fél 2-kor még abban fixálta a hátramenetben történő kanyarodást, de valójában azt nem tudja megmondani, hogy a műszerfalra az fordulatszám miért nem kerül ki. Ugyanis azt a részt XYZ kolléga csinálta, aki most nincs itt, mert dolgozik, de skype-on azt írta, hogy kész van vele, nála működik.

Természetesen, ebben összevontam azokat a hibákat és jelenségeket, amelyeket előfordulnak, nem egy konkrét forgatókönyv volt, hanem állatorvosi ló gyanánt összemosott, ilyen értelemben fiktív történet, de külön-külön minden eleme valóságos, megtörtént eset.

Acceptance test: 'convoy'

Konvoj

A fenti videó a Hyundai promóciós videója az olyan vezetéstámogató rendszereiről, mint az adaptív sebességtartó automatika, az automata vészfékező vagy a sávtartó automatika. A cél a fenti videón bemutatott tesztet teljesítő funkciók implementálása egy leegyszerűsített, szimulált környezetben.

  • A pálya szélessége ~500m, magassága ~300m, a kanyarok 6 fokos elemekből állnak, hogy a sávtartó automatika le tudja kezelni.
  • Az NPC modul (sprint 1 / team 3) implementálja a fekete furgon mozgását, amely a parkoló mellől indul, állandó 50km/h-s sebességgel körbemegy a pályán.
  • A teszt során, a vevő vezeti a fehér (vezérelt) autót, ami egy AutomatedCar példány, besorol a fekete NPC mögé, aktiválja az LKA-t és az ACC-t.
  • Majd átvált a másik AutomatedCar példányra, a pirosra, amikor odaér a konvoj, besorol a fehér AutomatedCar mögé, aktiválja az LKA-t és az ACC-t.
  • Az NPC útvonala szerint mikor megtett egy kört, akkor a stop táblánál nyom egy satuféket (a tábla csak vizuális visszajelzésként céllal van kint a pályán).
  • A satufék nem azt jelenti, hogy 0 másodperc alatt lassul 0-ra a sebessége, hanem egy erőteljes fékezés kerül megvalósításra az NPC szkript segítségével.
  • Az NPC ütközhető objektum, az ACC és a AEB szépen elkerüli az ütközést, mindkét példánynál.

Munkakörnyezet

Git

Interaktív online oktató anyagok

  1. Webes interaktív oktatóanyag
    • GitHub fiókkal -többek közt- a git kurzus ingyenesen végigvihető
    • az első 6 modul mindenképpen ajánlott
  2. Learn Git Branching
    • ez kifejezetten a branchelésre megy rá, szóval nem véletlenül a második!

Online anyagok

Puskák PDF formátumban

Kliensek

A fejlesztői környezetek rendelkeznek Git integrációval, de a parancssoron kívül grafikus kliensek is léteznek, többek között a GitHub saját asztali kliense.

Egyéb

  • Egy commit üzenet utólagos megváltoztatása nem egyszerű (különösen ha pusholva lett, lokálisan még nem is olyan vészes), így eleve írjuk meg korrekten.
  • Ha többen dolgoztok egy módosításon akkor a commit üzenet láblécében tüntessétek föl a társszerzőket is.

GitHub

A félév során a GitHubot használjuk a kód tárolására, a feladatok menedzselésére is és kommunikációra is.

Oktatóanyagok

Áttekintés

Minden hallgató tagja lesz egy GitHub szervezetnek (Organization), és egy-egy csapatnak (Team A[1-4], Team B[1-4]). Minden csapat külön issue board-dal rendelkezik (Projects), ezen kell vezetni a feladatok (issue) megoldását (részletében lásd Munkafolyamat).

Issue-t nem csak feladatra lehet felvenni, akár kérdésre is (felénk vagy más csapatok felé is), probléma megvitatására is. Ez esetben célszerű megjelölni a type: question címkével. 2017 őszétől csapat (team) szintű fórummal (Discussions) is rendelkezik a GitHub. A szervezeten belül a csapatok hierarchikus struktúrában vannak. A gyökér az Everyone, az összes többi csapat ennek tagja (Group A, Group B csapatokon keresztül). Az Everyone falára írt üzeneteket mindenki megkapja. Ezen keresztül fogunk a félév során kurzus szintű közleményeket kiadni, de bárki használhatja kommunikációra. Ugyanilyen üzenőfallal rendelkezik az összes többi csapat is, amelyre szintén bárki írhat. Ha például a Team2-ből szeretné elérni valaki a Team3-at, akkor mindösszesen annyi a dolga, hogy ír a Team3 üzenőfalára. Az Instructors nevű team-en keresztül az oktatókat lehet elérni ugyanilyen módon.

A comment szekciókban is élnek az @ jeles említések, ez a mi esetünkben @ravaszla és @pintergreg, ugyanígy működik csapatra is pl. @szfmv2020-osz/team-a1, illetve @szfmv2020-osz/instructors a mi esetünkben. Csapat esetében a csapat valamennyi tagja kap értesítést az hivatkozásról.

A GitHub valamennyi elemén használhatóak formázási lehetőségek Markdown stílusban, kód kiemelésre is lehetőség van, amelyet több mint célszerű használni. Ehhez csak a nyelv nevét kell csak a nyitó ``` jelek után írni:

```python
def get_random_number():
    return 4;  # chosen by fair dice roll. guaranteed to be random.
```

Eredmény:

def get_random_number():
    return 4;  # chosen by fair dice roll. guaranteed to be random.

Címkék

Létrehozásra kerültek címkék (Labels) négy „dimenzióban” (vagy kategóriában), amelyek használata elvárás a létrehozott issue-khoz a munka áttekinthetőségének javítása miatt. Kell, hogy legyen az issue-nak típusa, állapota, prioritása és legyen megjelölve a feladat nehézsége is.

Típus (type)

  • bug
  • design
  • documentation
  • enhancement
  • integration
  • question
  • user story

Állapot (status)

  • completed
  • duplicate
  • help wanted
  • invalid
  • pending
  • review needed

Prioritás (priority)

  • critical
  • high
  • moderate
  • low

Nehézség (effort)

  • high
  • moderate
  • low

Branching modell

Csoportos munka során fontos tisztázandó kérdés, hogy milyen stratégiával kezeljük a branch-eket. Az egyik legismertebb talán a GitFlow (A successful Git branching model), amelyet mára több kritika is ért.

A legelterjedtebbek tőbb tulajdonságait Scott Shipp War of the Git Flows című cikke nyomán a következő táblázatban foglaltam össze:

GitFlowGitHub FlowOneFlowGitLab FlowTrunk-Based DevelopmentRebasing Flow
Uses feature branchesyesyesyesyesoptionally, if short livedno
Uses release branchesyesnoyesyesyesoptional
Uses rebasingnonooptionaloptionaloptionalyes
Mergesno fast forward mergesunclearup to youup to youoptionalno

A korábbi félévekben a GitFlow szerű megoldást használtuk megbonyolítva azzal, hogy minden csapatnak saját fejlesztői branche-e volt. Ezt jelentősen leegyszerűsítendő a GitHubFlow-ra váltunk.

A master branch védett, nem lehet bele commitolni. Minden feladatohoz tartoznia kell egy issue-nak, és a megoldásához létre kell hozni egy (feature) branchet az aktuális masterről. A feladatot azon kell megoldani, majd PR-et nyitni a masterbe.

Ahhoz, hogy a masterbe kerülhessen a módosítás több követelménynek is teljesülnie kell:

  • a kód fordul
  • az összes teszt sikeres
  • két csapattárs és egy oktató jóvá hagyta (review)
  • nincs ütközés (conflict)

Fontos: Ha egy Pull Request nem fogadható el, akkor sem kell a PR-t lezárni, lehet tovább dolgozni a forrás branchen, az új commit-okkal automatikusan frissül a PR is addig míg a teszteknek meg nem felel és elfogadásra nem került. Sőt, kifejezetten lehet Draft* Pull Request is létrehozni, jelezve, hogy a munka már tartalmaz véleményezhető elemeket, de még nincs kész.

Ha a PR el lett fogadva be kell zárni azt az issue-t is, amihez a branch kapcsolódott. Tehát ideálisan minden (nem user-story és kérdés) issue-hoz készül(t) egy branch.

Forking

A tárgyhoz nem lesz szükség forkok használatára, de a GitHub workflow szerves részét képezi (különösen nyílt forrású projekteknél) így érdemes lehet ismerni.

Review

review required

Erre az „add your review” szolgál. Fájlonként át lehet nézni minden módosítást, soronként kommentelni, illetve egy globális véleményt írni a PR-ről (+1, -1, -2). A comment opció semleges, nem elfogadás, de nem is elutasítás. A másik két opció elég egyértelmű. Ha változtatást kérsz, akkor addig amíg a PR forrásbranche nem módosul nem lehet újra próbálkozni a PR elfogadásával.

review

Ha minden rendben, akkor el lehet fogadni a PR-et:

Elfogadás után így néz ki:

Társszerzők

A munkafolyamat alapvetően egyéni munkára van kitalálva, de legkevésbé sem tilos a pair programming sem. Volt, hogy Skype-os képernyő-megosztásos módszerrel dolgoztak távolról párban... Ilyenkor mindig felvetődik a kérdés, hogy csak az egyik kolléga nevében történhet a commit de mi van a másikkal... A GitHub-nak van egy funkciója ennek orvoslására. Részletek elérhetőek itt.

Ebben az esetben a commit üzenet törzse után 2 üres sorral elválasztva kell a társszerzőket feltüntetni. Pl.:

Commit message header

Commit message body preceded by an empty line and followed by
two empty lines and the trailer.


Co-authored-by: name <name@example.com>
Co-authored-by: another-name <another-name@example.com>"

Ahhoz, hogy a GitHub a társszerzőt össze is tudja rendelni a felhasználói fiókjával fontos, hogy az a name és különösen az az e-mail szerepeljen, amelyet egyébként git beállításként használ!

E-mail cím védelme

A GH minden felhasználónak biztosít egy "proxy ímélcímet", hogy titokban tarthassa a címét, ez xxxxxxx+username@users.noreply.github.com szerkezetű, ahogy xxxxxxx egy hétjegyű felhasználói azonosító. Bővebben itt. Ezt is lehet használni, nem csak társszerzőhöz hanem saját címnek is, csak legyen konzisztens!

Fejlesztői eszközök

Visual Studio Code

Csak a hivatalos Microsoft féle build hajlandó együttműködni a .NET debuggerrel!

EditorConfig for VS Code

This plugin attempts to override user/workspace settings with settings found in .editorconfig files.

A formázási beállításokhoz a MS ajánlása szerinti .editorconfig fájl hozzáadásra került a projekthez.

C#

  • Lightweight development tools for .NET Core.
  • Great C# editing support, including Syntax Highlighting, IntelliSense,Go to Definition, Find All References, etc.
  • Debugging support for .NET Core (CoreCLR).
    • NOTE: Mono debugging is not supported. Desktop CLR debugging has limited support.
  • Support for project.json and csproj projects on Windows, macOS and Linux.

Auto-Using for C#

Auto-imports and provides intellisense for references that were not yet imported in a C# file.

Automatikus kódformázás

StackOverflow://Auto format C# code In Visual Studio Code

.NET Core Test

Unit test támogatás MSTest, xUnit és NUnit keretrendszerekhez.

Ajánlott beállítások, amiket a .vscode/settings.json fájlban kell elhelyezni:

{
    "dotnet-test-explorer.testProjectPath": "**/*Tests.csproj",
    "dotnet-test-explorer.autoWatch": true
}

Code Coverage

A tesztlefedettség számítását a Coverlet végzi, amit a teszt projekthez adtam hozzá. Ennek riportját használja a Codecov is. A riportot cobertura, lcov fomátumban is legeneráltatom, előbbi a Codcov-nak, utóbbi a Coverage Gutters-nak kell, amely a VS Code-on belül ad visszajelzéseket. Utóbbi beállításaiban meg kell adni, hogy a report coverage.info néven áll elő, ezt keresse. Illetve be kell kapcsolni a statusbar „Watch” gombjábal.

Formátumbeállítás runsettings.xml állományon keresztül [forrás]:

<?xml version="1.0" encoding="utf-8" ?>
<RunSettings>
  <DataCollectionRunSettings>
    <DataCollectors>
      <DataCollector friendlyName="XPlat code coverage">
        <Configuration>
          <Format>lcov,cobertura</Format>
        </Configuration>
      </DataCollector>
    </DataCollectors>
  </DataCollectionRunSettings>
</RunSettings>

IntelliJ Rider - C#

Egyetemi e-mail címmel (stud.uni-obuda.hu) igényelhető egy éves hallgatói licenc az IntelliJ termékekhez, így használható a C# fejlesztéshez szánt Rider is.

Code Style

https://www.nuget.org/packages/StyleCop.Analyzers/

Save Actions Reborn

Ezzel automatizálni lehet a Reformat Code meghívásást.

Code Coverage

  • dotCover
  • része a Ridernek
  • aktiválás: Unit Tests fül, Run (zöld háromszög) rejtett menü / Cover Selected Unit Tests

IntelliJ IDEA - Java

A feladat Java nyelvű megoldásához ajánlott és támogatott fejlesztői környezet az IntelliJ IDEA. A Community Edition ingyenes, ez tartalmaz mindent amire szükség lehet a félév során.Egyetemi e-mail címmel elvileg ingyen igényelhető Pro verzió.

Kódformázás

IDEA beállításai alapértelmezetten elvileg megfelelnek az elvárásoknak, így egy fájl befejezése után (de értelem szerűen commit előtt) célszerű egy formázást megejteni: Code > Reformat Code (CTRL+ALT+L)

  • A behúzás beállítása: File > Settings > Editor > Code Style > Java > Tabs and Indents: nem tab, de 4 karakternyi
  • A sorhossz beállítása: File > Settings > Editor > Code Style > Default Options > Right magin (columns) 120 kell, hogy legyen eredetileg
  • Emellett default beállításokban a vessző és kettőspont utáni szóközök, illetve az operátorokat körbevevő szóközök is szerepelnek. Továbbá a kapcsos zárójelek használata is az elvártnak megfelelően van beállítva.

Java kódformázási előírások

Save actions

Mivel a Reformat Code nyomogatását az ember hajlamos elfelejteni, létezik egy IDEA bővítmény a probléma automatizálására. Ez nem más mint a Save Actions plugin, mely lehetővé teszi, hogy az amúgy is használt mentés (CTRL+S) parancshoz lehessen kötni a kódformázási műveletet. A Save Actions plugin konfigurálását az alábbiak szerint kell megejteni. idea_save_action

Zárójeles megjegyzés, hogy ez akkor fog tisztességesen működni, ha az IDEA kódformázási előírásai megfelelően vannak beállítva, vagy legrosszabb esetben default-on lett hagyva minden (már akkor is képes megszüntetni a Checkstyle-ben rögzített problémák jelentős részét).

forrás

Checkstyle plugin

A Checkstyle egy statikus kódelemző szoftver Java nyelvhez, amely egyrészt a kódformázási előírások betartását, másrészt egyéb programozástechnikai előírások betartását is ellenőrzi.

Checkstyle plugin beállítása IntelliJ IDEA környezetbe. A plugin telepíthető a plugin managerből majd a következő beállításokra van szükség:

File > Settings > Other Settings > Checkstyle > Configuration File panelen Add és a projekt gyökérben megtalálható checkstyle.xml fájlt kell neki megadni (és elnevezni valamiként, az alábbi képen szfmv). Innentől a fejlesztői környezeten belül elérhető a kódminőség-ellenőrzés valós időben, warning-okkal jelzi a találatokat.

Tesztlefedettség

A kód „minőség” egy mérőszáma lehet, hogy mekkora része van (unit)tesztekkel lefedve. Ezt a projekt README-ben a Coveralls.io szolgáltatás folyamatosan meg is jeleníti.

Ehhez a JaCoCo-t használjuk, ami Maven-en keresztül (a pom.xml-ben) lett beállítva. A kód tesztekkel történő lefedettségének megjelenítéséhez a fejlesztői környezetek mindenféle okos eszközöket is rendelkezésre bocsátanak.

Az IntelliJ IDEA-ban beépített megoldás is van, illetve olyan külső eszközöket is képes használni mint a JaCoCo. Képes arra, hogy színkódokkal megfesse az egyes metódusokat annak megfelelően, hogy van-e hozzá teszt.

A beállításához meg kell nyitni a Run/debug configuration ablakot, majd a Code Coverage fülön kiválasztani az IntelliJ IDEA-t vagy a JaCoCo-t, előbbi Tracing típusú vizsgálatot is tud (ami jelenleg mindegy). Ezután a Run menü Run 'Main' with Coverage menüpontjával a kódot úgy futtatja, hogy a számításokat el is végzi és megjeleníti az összesítő panelt.

Az IDEA-n kívül más IDE-khez is megtalálhatóak hasonló funkciók: NetBeans, Eclipse

Képernyőképek

Logolás - Log4J

Módfelett udvariatlan, káros és így kerülendő hibakeresési céllal a standard kimenetre (System.out.println) írni. Ettől még sokan megteszik mondván addig nincs baj, míg nem kerül pusholásra a közös repóba. Csakhogy a kódolás hevében könnyen ott felejthet az ember egy-két ilyet, így célszerű eleve bele sem tenni!

Szerencsére több logger is létezik, amik nem csak a System.out.println nem rendeltetés szerű használatát tudják megakadályozni, de bónuszként még egy halom hasznos és kényelmes funkcióval is rendelkeznek. A projektben az Apache log4j 2.8-as verziója került bevezetésre.

Konfigurálás

A logolási beállítások egyrészt helyzetfüggőek, másrészt a fejlesztő magánügyét képezik, így nem kényszerítjük rá a másikra a kedvenc beállításainkat. Ebből következik, hogy a log4j2.xml konfigurációs állomány nincs a git verziókezelő felügyelete alatt. Példa a tartalmára [forrás]:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </Console>
        <!--<File name="MyFile" fileName="all.log" immediateFlush="true" append="false">-->
            <!--<PatternLayout pattern="%d{yyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>-->
        <!--</File>-->
    </Appenders>
    <Loggers>
        <Root level="debug">
            <AppenderRef ref="Console" />
            <!--<AppenderRef ref="MyFile"/>-->
        </Root>
    </Loggers>
</Configuration>

A fenti fájlt a projektmappába pl. a src/main/resources/-be kell elhelyezni. Jelenlegi beállításokkal DEBUG szintű, fájlba nem ment, csupán a fejlesztői környezet konzoljára ír. A fenti fájl hiányában ERROR beállításokkal fog működni.

Szintek

A logolásnak több szintje van attól függően, hogy milyen finomságú részletekre vagyunk kíváncsiak. Ezek a szintek sorban (a legbővebbtől a legszűkebbig): ALL, TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF. Ebből következik, hogy egy INFO szintű log üzenet meg fog jelenni DEBUG beállítások mellett, de nem fog megjelenni ERROR beállításokkal.

Példa a használatára

package hu.oe.nik.automatedcar.demo;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Demo {
  private static final Logger LOGGER = LogManager.getLogger();

  public void demo(){
    LOGGER.debug("Ez egy debug szintű üzenet");
    LOGGER.error("Ez egy error szintű üzenet");
  }
}

További leírás

Maven és a proxy

Ha valaki céges gépen dolgozik előírt proxy mellett, érdemes figyelni arra, hogy a maven-nek külön kell konfigurálni a proxy-t.

Függőségeket tartalmazó futtatható .jar állomány létrehozása

mvn clean compile assembly:single

Az eredmény a target/AutomatedCar-jar-with-dependencies.jar

Kódformázás

Code quality

A kód tisztasága, olvashatósága nem csak szemantikai, de szintaktikai értelemben is fontos. Minden nyelvnek megvannak a maga „nyelvtani”, szintaktikai előírásai, amit a fordító be is tartat. Azonban ezen túl megvannak azok az (íratlan) szabályai is, amiket már nem a fordító feladata betartatni. (A Go fordítónál ez kezd egybemosódni, pl. nem fordul a kód ha van deklarált, de fel nem használt változód, a gofmt, Go format pedig kikényszeríti a kódformázási szabályokat.)

Ezek olyan kódformázási szabályok, amelyek több szinten lehetnek definiálva. Egyrészt (többé-kevésbé) egyezményesen egy-egy nyelv szintjén (pl. PEP8 Python esetében, gofmt), aztán lehetnek vállalati esetleg osztály és projekt szinten is. Például a Linux kernelkez tartozó előírások - többek között - 8 szóköznyi behúzást írnak elő és maximum 80 karakter széles sorokat. A gondolat emögött, hogy maximum három blokk mélységű szerkezet fogadható el, amikor is már a sor 30%-át teszi ki a behúzás. Ennél több behúzás esetén már nem sok hely marad a kódnak.

A Java nyelvhez is van(nak) kódformázási előírás(ok), amelyek egy része teljesen általános. Pl. a csomagnevek kisbetűsek, az osztály nevek mindig nagybetűvel kezdődnek (a fejlesztői környezetek ezt például általánosan számon kérik), a metódusnevek pedig kis betűvel kezdődnek továbbá a szóösszetételeknél nagybetűket használunk pl. metódusNév.

Átfogó ajánlást készített még 2000 környékén a Sun, ám ez mára meglehetősen túlhaladott, vagy ilyen a Google által összeállított Google Java Style Guide. Ez viszont helyenként túl specifikus (nagyvállalati környezetre optimalizált) a tárgy kereteihez, így nem egy az egyben ezt használjuk. A Checkstyle statikus kódanalizátor default értékei vagy a Jetbrains által az IntelliJ IDEA-ba beállított default szabályok is felfoghatók egy ilyen ajánlásnak.

A C#-hoz a Microsoft definiálta a kódformázási szabályokat, ezeket kell követni a tárgy során is.

Statikus program analízis

A statikus analízis során a programkód végrehajtása nélkül, többnyire a forráskód elemzésével - automatizáltan - történik kód hibáinak feltárása.[Wikipédia] Ilyen eszköz Java nyelvhez például a nyílt forrású PMD, vagy a Checkstyle.

A kurzus során az utóbbit használjuk, amely figyeli a fentebb leírt formázási ajánlásokat (teljes használható szabálylista). Ezen túlmenőleg egyéb hibafaktorokat is figyel: magic number-ek alkalmazása, string literál többszöri előfordulása, Ciklomatikus komplexitás, túl sok paraméter a metódusban (5), túl hosszú metódus (20 utasítás), túl hosszú sor (120 karakter) valamint a kódban felejtett TODO és FIXME kommentekre is érzékeny.

A master repók (A és B) össze lett drótozva a CodaFactorral és folyamatosan méri a kód minőségét, valamint egy A-tól F-ig tartó skálán osztályozza is (ahol az A a legjobb).

Kódformázási előírások C# nyelvhez

Work in progress...

Kódformázási előírások Java nyelvhez

„Örök kérdés”, hogy szóközök vagy tabok jelöljék-e a behúzást. Ma már minden normális editor beállítható úgyis, hogy a tab billentyű szóközöket szúrjon be, amelyik erre (sem) képest azt meg nem használjuk. A kérdés, legalábbis ezen tárgy keretein belül azzal zárult, hogy mindenki szóközöket használ, tabok nem lehetnek a fájlban. Pont. Egy rövid (nem túl komoly) videó a témában: Silicon Valley - S03E06

  • a behúzást 4 szóköz jelöli (nincs tab a fájlban)
  • nem lehetnek üres blokkok
  • a nyitó kapcsos zárójel a sor végén található
if (condition) {
    ...
}
  • a záró kapcsos zárójel kulcsszavakkal azonos sorba helyezendő
try {
    ...
} catch (Exception ex) {
    ...
} finally {
    ...
}
  • minden esetben ki kell tenni a blokkjelölő kapcsos zárójeleket
  • osztályon belül meghatározott sorrendben szerepelnek az elemek
    1. Class (static) variables. First the public class variables, then protected, then package level (no access modifier), and then private.
    2. Instance variables. First the public class variables, then protected, then package level (no access modifier), and then private.
    3. Constructors
    4. Methods
  • kerülendő az üres utasítás (;)
  • mindig szükséges default ág a swith-case szerkezetben
  • soronként egy utasítás szerepel
  • kerülendő a return kulcsszavak halmozása egy metóduson belül
  • kerülendőek a *-os importálások
  • kerülendő a nem használt importálás
  • az osztály neve megegyezik a fájl nevével
  • az operátorok körül, valamint a vessző és kettőspont után szóköz kerül

Kulcsszó sorrend

A Javában a metódusok különböző módosítókkal láthatók el mint static, public|private|protected, final ám ezeknek előírt sorrendje is van. Nem a fordító írja elő sajnos, tehát lefordul, de konvenció, hogy ezeket milyen sorrendbe tesszük. Pl. a teljesség igénye nélkül public static oké static public nem. Sajnos a Reformat Code ezt nem rázza gatyába, így az automatizált megoldás sem fogja, de ettől még stílus hiba.

Javítani lehet a helyzeten a File | Settings | Editor | Inspections | Java | Code style issues | Missorted modifiers inspection bepipálásával ÉS az Analyze | Code Cleanup commit előtti alkalmazásával. Sajnálatos módon a Save Actions ezt nem tudja. :sob:

forrás

Javadoc

Javadoc is a tool which comes with JDK and it is used for generating Java code documentation in HTML format from Java source code, which requires documentation in a predefined format.

tutorialspoint / Java - Documentation Comments

Tutorials:

Munkafolyamat

Definiáltunk egy munkafolyamatot, amely követése elvárás a félév során. A munkafolyamat alapvetően feltételezi, hogy egy adott kódrészletet egy kolléga ír, de legkevésbé sem tilos a pair programming sem. Ahhoz, hogy a GitHub rögzítse a mindkét kollégát, a társszerzőt meg kell jelölni. Erről itt lehet olvasni.

A konkrét feladatmegoldáshoz az alábbi folyamat az elvárt:

  • User Story:
    • high level description of sprint goal by customer not complete! Never detailed enough!
  • Component Design:
    • what will realize the functions in the user story You have to recognize the (hidden?) functionality!
  • Requirement Specification:
    • what makes the component work as expected basically the Definition of Done for the component
  • Task Definition:
    • add milestone (there is one for every sprint) to issue
    • add assignee to issue
    • add Definition of Done list to issue
    • add project (there is one for every team) to issue
    • Guide to Splitting User Stories

  • Dod: Definition of Done

Code Review in details

  • Clean Code:
    • no magic numbers
    • no abbreviations
    • no extreme unit lengths
    • talkative names
    • unambiguous code
  • in short:
    • Easy to understand and maintain
    • Reads like well written prose

Commit üzenetek

A How to Write a Git Commit Message egy hosszabb, példákkal illusztrált írás a jó commit üzenetekről, amely hét szabályban foglalja össze, hogy mire kell figyelni. Ezt egészíteném ki egy nyolcadikkal.

  1. Separate subject from body with a blank line
  2. Limit the subject line to 50 characters
  3. Capitalize the subject line
  4. Do not end the subject line with a period
  5. Use the imperative mood in the subject line
  6. Wrap the body at 72 characters
    • ez a legkevésbé fontos
  7. Use the body to explain what and why vs. how
  8. Reference the issue!

Miért fontos a 8. pont?

Valójában (bizonyos szempontból) az issue behivatkozása a legfontosabb, méghozzá a visszakövethetőség (traceability) miatt.

Minden módosítás (a verziókövető rendszerben) rendelkezik egy azonosítóval, amelyhez társul, hogy ki és mikor végezte el a módosítást. Valamit egy üzenet, amely -- jó esetben -- leírja, hogy mi volt ez a módosítás. A visszakövethetőség egy adott szintig tehát szerves része a verziókövető rendszereknek.

A módosítások azonban nem csak úgy ötletszerűen történnek, hanem valamilyen feladat által meghatározott célból. Pl. jelenítsd meg a műszerfalon az autó pillanatnyi sebességét (feature), vagy javítsd ki pixel/s -> km/h átváltást, mert kerekítési hiba miatt értelmetlen érték jelenik meg (bugfix).

Ugyanakkor a feladatok (task) sem csak úgy lógnak a levegőben, jellemzően kapcsolódnak egy user story-hoz (különösen a feature-ök), de biztosan kapcsolódnak egy sprinthez (hiszen beütemezték a megoldását valamikorra), van felelősük, határidejük, stb. Úgy általában van véve egy kontextusuk. Az issue (más néven task) tartalmazza az adott feladat pontos részleteit, az issue/task trackerben akár a megoldás teljes vitafolyamata megtalálható. Pl. ki hogyan akarta implementálni, milyen érvek és ellenérvek merültek fel az egyes implementációs lehetőségek mellett/ellen, hogyan jutott a fejlesztőcsapat konszenzusra, vagy ki hagyta jóvá az adott módosítást, ki döntött arról, hogy melyik sprintbe kerüljön be, stb.

A visszakövethetőség nem csak addig a pontig érdekes és fontos, hogy ki írta át a változó típusát (pl.), hanem a teljes tervezési/döntés folyamatig visszamenőleg.

Mi van akkor ha a döntés egy face-to-face meetingen (pl. standup), skype konferenciahíváson vagy egyéb nem írásos formában történt? (A szó elszáll, írás megmarad...)

Ebben az esetben, az issue kiváló hely arra, hogy írásban is rögzítve legyenek az elhangzottak. Pl. YYYY-MM-DD-ei megbeszélés alapján az XY library segítségével fogom implementálni az analóg fordulatszámkijelzőt. Akár explicit írásos jóváhagyást is lehet kérni...

Vállalati példa

A munkakultúráról egy remek videót tett közzé a Spotify, megtekinthető itt.

Implementáció

C#

A korábbi félévek visszajelzései visszatérő eleme volt, hogy C#-ban is meg lehessen oldani a feladatot. A cross-plastform fejlesztés ugyanúgy feltétel, így „csak” a .NET Core jöhet szóba, ennek is a 3.1-es verziója (LTS).

A .NET 5 egyesíti majd a .NET Framework-öt és a .NET Core-t, majd a .NET 6 be fogja vezetni a MAUI-t mint multiplatform keretrendszert grafikus felületek készítéséhez, ez azonban ma még nem elérhető.

Mivel a CI környezet Linux alapon futott, szükség volt egy áthidaló megoldásra miután a WPF nem használható Windows-on kívül, erre a 3rd party Avalonia keretrendszert használtuk. Az Avalonia a WPF-hez hasonlóan egy XAML alapú Model-View-ViewModel (MVVM) rendszer. Viszont miután már a GitHub Actions ingyenes opció mellett is lehetővé teszi a Windows alapú CI környezetek használatát, a WPF is használható lett.

.NET stack

Használható fejlesztői környezetek: Visual Studio, VS Code (kizárólag a hivatalos, MS változattal működik együtt a .NET debugger), IntelliJ Rider, stb.

Hasznos írások az implementációhoz:

Java

A feladat megoldásához Java nyelvet, annak is a 11-es verzióját kell használni (LTS), Maven projekt menedzsment eszközzel. (A kiinduló projekt ezeket már teljesíti). Egyaránt használható az Oracle JDK 11 vagy az OpenJDK 11 is, operációs rendszer sincs megszabva. Az automatizált CI eszközök jogi okokból az OpenJDK-t használják, linuxon. Szóval már csak emiatt is „érdemes” platformfüggetlen kódot írni!

A kiadott kód csak példa egy alap GUI készítésére Swing-el, ez akár teljesen átírható, más GUI könyvtárak (pl. JavaFx) is használható. Viszont az IntelliJ IDEA GUI Designer-e nem használható, esetleges kompatiblitási okoból.

Hasznos írások az implementációhoz:

Virtuális világ

Az autónak egy virtuális tesztpályán kell végigmennie, amelyhez modellezni a világot. Két teszt pályát biztosítunk, egy egyszerűbbet és egy nagyobbat, bonyolultabbat. Alább látható az egyszerűbb.

A fenti világ elemekből épül föl, amelyek között vannak egyenes útszakaszok, kanyarok (pl. 45° és 90°), T elágazás, gyalogos átkelő, közúti táblák, parkolók és fák. Mindezt egy XML, vagy egy JSON írja le. A feladat megoldásához bármelyik formátum használható.

A számítógépes grafikában megszokott módon, a bal felső sarok jelenti az origót (0,0) koordinátát. Az x tengely tehát jobbra haladva, az y tengely lefelé haladva növekszik. Így kell értelmezni az XML-t és ekképpen működik a megjelenítés is, hiszen a form bal felső sarkánál van a (0, 0) pont. Az alábbi kép forrása.

Objektumok leírása

Egy-egy objektum leírása a következőképpen néz ki (XML-ben):

<Object type="road_2lane_straight">
      <Position x="1700" y="144"/>
      <Transform m11="0" m12="1" m21="-1" m22="0"/>
      <Parameter name="roadpainting_1" value="1"/>
      <Parameter name="roadpainting_2" value="1"/>
      <Parameter name="roadpainting_3" value="1"/>
</Object>
  • A type attribútum írja le, hogy milyen objektumról van szó. A példában egy 2 sávos egyenes útszakaszról.
  • A Position elem megadja az elem viszonyítási pontjának koordinátáját.
  • A Transform elem egy 2×2-es transzformációs mátrix, amely forgatást ír le.
  • A roadpainting megadná, hogy milyen felfestések vannak vannak az úton, de ez nem releváns
  • Egy ilyen egyenes útelem 350×350px, ekkora a kép is és ennek kell lennie az XML-ben is.

Az út elemek viszonyítási pontjai

A képfájlok amikkel a rajzoló csapat dolgozik elég sajátosan működnek. A transzformációs mátrixban leírt elforgatás pl. nem a bal felső sarokkal van értelmezve, hanem elemenként más és más ponttal. Ezek rögzítése szükséges lehet a modellben, a rajzoló csapat munkáját megkönnyítendő. Egyébként korábbi félévekben ezt már összeszedték egzakt módon is.

2_crossroad_1 2_crossroad_2

Minden itt fel nem sorolt esetben feltételezhető, hogy a bal felső sarok a viszonyítási pont.

Egy korábbi félév során a referenciapontokat (részben) már összegyűjtötték (@csabalint, @SiposGergo, @markkurucz), ez elérhető XML vagy JSON formátumban.

A mozgatásra szoruló elemek (vezérelt autó és NPC autók) nem képezik részét a világ leírásának, viszonyítási pontjuk nem definiált. A rendelkezésre bocsátott autó képek méretarányosak az összes többi objektummal.

A világhoz szükséges elemek megtalálhatóak a kiinduló project src/main/resources (Java) vagy src/AutomatedCat/Assets (C#) mappájában.

Objektum poligonok

Minden objektumnak kell, hogy legyen egy poligon váza, amely többek között az ütközéshez vagy a kijelüléshez is használható. Különböző objektumoknak azonban kicsit mást jelent ez a poligon „váz”.

Az autó esetében (pl.) a legfontosabb felhasználása az, hogy nekiment-e valaminek, tehát az autó körvonalát kell megjelölni. Ez leegyszerűsíthető, nem kell a grafikai elemet teljes mértékben követni.

Egyes elemek (fa, tábla) a felülnézet miatt nem azt mutatják, ami az ütközéshez szükséges. Értelem szerűen nem a lombkoronának, hanem a törzsnek lehet nekiütközni. Tehát egy törzset kell ábrázolni a poligonnal.

Az útelemek esetében nem az ütközés a probléma, hanem a sávokat kell kijelölni, amit a a sávtartó automatika fog felhasználni. Ezeket is lehet egyszerűsíteni.

A poligonok megrajzolásához használható a VGG Image Annotator, amely böngészőből is működik és a megrajzolt polygont JSON-ben le lehet menteni.

Korábbi félév során @ArchiCat és @konyarilaszlo ezt már megtette, elérhető a worldobject_polygons.json állományban.

Ennek struktúrája:

{
    "objects": [
        {
            "typename": "car_1_white",
            "polys": [
            {
                "type": "standalone",
                "points": [
                [51, 239],
                [40, 238],
                [26, 236],
                ...
                [51, 239]
                ]
            }
            ]
        },
        ...
    ]
}

Van benne egy objects tömb, minden objektum esetében a typename a képfájl neve (kiterjesztés nélkül), majd egy polygon tömb (mivel a VGG Image Annotator multipoligonokat is elő tud állítani). Azon belül egy points tömb ahol a koordináták a képfájlon koordinátarendszerében értendők.

A fenti példa esetében a képfájl (50, 20) koordinátára van rajzolva, a hatszög benne a képen belüli relatív koordinátákkal van megadva.

"points": [
    [10, 10],
    [15, 8],
    [20, 10],
    [20, 20],
    [15, 22],
    [10, 20],
    [10, 10]
]

Méretarány

Az XML-ben leírt objektumok koordináta-rendszere nem feltétlenül egyezik meg a megjelenítő koordináta-rendszerével, ezt figyelembe véve skálázás, vagy viewport kezelés válhat szükségessé.

A feladat megoldás során jellemzően valóságos mértékegységekben specifikáljuk a feladatot (pl. méter, km/h, m/s^2, stb.) míg az XML és a grafikai elemek értelem szerűen pixellel dolgoznak. Ennek feloldására, illetve az átváltásra az 1m=50px szabályt célszerű használni. Ez egy hozzávetőlegesen arányos érték, amellyel számolni is könnyű.

Az autó fizikája

Az autónak egy leegyszerűsített modellen keresztül ugyan, de mégis valóságosan kell viselkednie, ehhez pedig megfelelő fizikát kell leprogramozni. Az haladásához nyilván sebességre lesz szükség, amit a motorerő gyorsító ereje segítségével kaphatunk, és ami a gázpedál(t helyettesítő billentyű) elengedésével nem szűnik meg azonnal, tehát ha úgy tetszik lendületben marad, viszont a környezet (légellenállás, súrlódás) fokozatosan fékezi (akár egyetlen lassító erő is elegendő). Nem kell az egész univerzumot szimulálni, de legalább egy gyorsító és egy fékező erő például biztosan szükséges lesz.

Ezen jelenségeket (és még sok minden mást) egy autós játék fizikájáról Marco Monster szépen összefoglalta Car Physics for Games című írásában (angol nyelven).

Az autóhoz automata váltót kell megvalósítani, de az automata vátóban is vannak „belső” fokozatok (1, 2, 3, 4 stb. előremenetben), tehát meg kell különböztetni a „külső” fokozatokat (P, R, N, D) és D állapotban a belsőket.

Szintén hasznosak lehetnek még az alábbi írások, természetesen továbbra is angol nyelven, vagy tetszőleges egyéb irodalom (hint: Google, Stackoverflow, Wikipedia).

Fordulókör kiszámítása

Typical Maximum steering angle of a real car

A fordulókör sugarának kiszámításához a fönti linkből származó képlet használható:

atan(wheelbase / (turning circle - car width)) = angle

A car_2_white.png esetében a szélesség kb. 90px, a tengelytáv kb. 130px-nek tekinthető. Tegyük fel, hogy maximum 60°-ban kormányozható, ekkor a fordulókör sugara:

  • atan(130px / (r - 90px)) = 60°

  • tan(60) = 130/(r-90)

  • r = 130/tan(60) + 90

  • r = ~165px

Figyelem, ezek lényegesen valósághűbb autó szimulálását tűzték ki célul mint ami itt minimálisan elvárt!

Szenzorok

A vezetéstámogató rendszerek 3 fő szenzorra épülnek: kamera, radar és ultrahang. A valóságban adott esetben a vezetéstámogató rendszerek több szenzor együttes használatával működnek (a szoftverben ilyet nem kell megvalósítani).

A jegyzetben szereplő ábrák a szenzorok látóterét nem méretarányosan mutatják mivel a radar és a kamera látótere túl nagy, így az igazán lényeges részletek elvesznének.

További olvasmány:

Kamera

A kamera a szélvédő mögött található, 60°-os látószöggel 80 méterre lát el. A táblafelismerő rendszer és a sávtartó automatika használja.

Kamera szenzor látótere, nem méretarányos

Radar

A radar az autó lökhárítóján helyezkedik el, 60°-os látószöggel 200 méterre lát el. Az adaptív tempomat és az autonóm vészfékező rendszer épül rá.

Radai szenzor látótere, nem méretarányos

A valóságban a radar több járművet is azonosít. A azonos sávban közvetlenül előtte haladót, a szomszédos sávokban haladó autókat és a képes az azonos sávban haladó előttit is azonosítani (az autó alatt átverődő jelekkel). Ennek köszönhetően az olyan potenciálisan veszélyes manőverek mint a szomszéd sávból elénk bevágó autó is felismerhető mivel folyamatosan figyeli ezek helyzetét.

Ultrahang

Az ultrahang szenzorból 8 darab van az autón, látótávolsága 3 méter, látószöge 100°, a parkoló asszisztens és a tolatóradar épül rá.

Ultrahang szenzorok látóterei

Szenzorimplementáció működése

A valóságos szenzorokhoz képest az implemtálandó szenzorok jelentősen egyszerűbbek. Értelem szerűen nem kell sem radar, sem ultrahang jeleket szimulálni és a szenzorok látóterét is jelentősen egyszerűsítve reprezentáljuk: egy háromszöggel.

A szenzor látóterét jelképező háromszög a vezérelt autóhoz van rögzítve, vele együtt mozog. Ez az a háromszög amely kijelöli a világ egy szeletét és elérhetővé teszi a szenzornak feldolgozásra. Maga a világ (World osztály) singleton, pontosan egy létezik belőle amelyhez bármely szenzor közvetlenül hozzáfér.

A világ tartalmaz egy WorldObject objektumokból álló gyűjteményt, amelyben minden statikus és dinamikus objektum megtalálható, beleértve a vezérelt autót is.

Az első sprint során a modellező csapat implementál egy lekérdező metódust, amely egy háromszöget (vagy 3 pontot) vár bemenetként és visszadja azon világ objektumok listáját, amelyek beleesnek ebbe a háromszögbe.

Ha a szenzor háromszög ugyanolyan poligonnal van megvalósítva mint a világobjektumok poligonjai, akkor az intersects metódussal könynen eldöntehető, hogy a szenzor látóterének háromszövgébe tartozik-e egy-egy világ objektum.

A szenzorok ez a listát tovább szűrik az alapján, hogy mire érzékenyek. A kamerára a sávtartóautomatika (LKA) és a táblafelismerő (TSR) épül, így annak a szenzornak az útelemek és a táblák relevánsak.

A radar és az ultrahang olyan objektumokra érzékeny, amelynek neki lehet menni, amivel az egocar ütközhet. Ezen kívül a radarra épülő ACC a vezérelt autó előtt (sávon belül) haladó autóra fókuszál, a vészfékező (AEB) bármire ami az egocar útjába esik. Az ultrahang szenzor szintén, csupán az rövidebb távon és a Parking Pilot használja.

Miután a szenzorokhoz konkrét objektum referenciák kerülnek, a szenzor hozzáfér az objektum minden tulajdonságához. Így akár könnyedén lehet számítani távolságot két objektum között (a referenciapontok segítségével).

A szenzorok a feldolgozásuk eredményét a Virtual Function Bus-ra írják packet objektumok segítségével. Aztán ezeket a megfelelő modulok kiolvassák és hasznosítják. Pl. a műszerfalon megjelenik a táblafelismerő által detektált tábla, vagy az AEB által generált vezérlésre a hajtáslánc modul fékezéssel reagál.

Vezetéstámogató funkciók

Adaptív tempomat (Adaptive Cruise Control - ACC)

Az adaptív sebességtartó automatika a hagyományos tempomat továbbfejlesztett változata. Az ACC egy rendkívül precíz radarral, valamint a gázadás és a fékezés elektronikus vezérlésével tartja az előre beállított követési távolságot. Ha a két jármű között csökken a távolság, az ACC mérsékli a sebességet, sőt szükség esetén fékez is, közben pedig aktiválja a féklámpákat. Ha az elöl haladó jármű gyorsít, vagy átsorol a másik sávba, az Ön autója is fokozatosan felgyorsít, amíg el nem éri az előre beállított sebességet. Az adaptív sebességtartó automatikával a kívánt követési távolságot is beállíthatja (hosszú, közepes vagy rövid).

forrás: toyota.hu / Adaptív sebességtartó automatika

Bemutatóvideó (YouTube)

Bemutatóvideó

Implementálás

A kiválasztott célobjektum (autó előtt haladó NPC) sebességéhez igazítja a saját sebességet, vagy tartja a sofőr által kiválasztott sebességhatárt, ha nincs előtte célobjektum.

  • ki- és bekapcsolható, reagál az állapotváltás, alapértelmezetten az aktuális sebesség, de min célsebesség 30 km/h
  • ha nincs saját sávban autó, a játékos autó tartja a kiválasztott célsebességet
  • ha saját sávban található autó:
    • felveszi a sebességét, ha lassabb
    • tartja a kiválasztott sebességet, ha gyorsabb
  • fékezésre kikapcsol
  • AEB beavatkozásra kikapcsol
  • ha speed limitet talál a buszon (táblafelismerő), azt alkalmazza új célsebességként, amíg a sofőr felül nem írja

Kezelőszervek

  • bekapcsoló gomb
  • célsebesség kijelölése
    • léptetés 10 km/h-val
    • 30 és 160 km/h között
  • követési távolság definiálása másodpercben: 0.8, 1.0, 1.2, 1.4
    • sebességfüggő
    • a léptetés körbe jár, tehát 1.4 után 0.8 következik és a 0.8 után az 1.4

Autonóm vészfékező rendszer (Automatic Emergency Brake - AEB)

Az Autonóm Vészfékező Rendszer (AEB) lényege, hogy egy beépített technológia alkalmazásával (általában radar, kamera, vagy lézer segítségével) folyamatosan méri az elöl haladó jármű mögötti távolságot. Ha a rendszer úgy érzi, hogy a gépkocsik közötti távolság veszélyesen csökken, akkor jelzést ad a járművezetőnek, lehetőséget adva a beavatkozásra (pl. fékezésre). Amennyiben a járművezető reakciója elmarad, vagy annak mértékét a rendszer nem tartja elégségesnek, abban az esetben az AEB beavatkozik, s akár vészfékezés alkalmazásával igyekszik a balesetet elkerülni.

forrás: baleset-megelozes.eu / Autonóm Vészfékező Rendszer (AEB)

Bemutatóvideó (YouTube)

Bemutatóvideó

Implementálás

Nyilvánvalóan nem azt kell vizsgálni, hogy az autó ütközik-e az előtte levő objektummal hanem, hogy ütközni fog-e vele. A vészfékezés maximális lassulása 9 m/s^2 lehet. Ha az autó 36 m/s sebességgel halad akkor 4 másodperc kell a nullára fékezéshez (ha 50 km/h sebességgel halad, akkor 20). Az aktuális sebességből meghatározható, hogy mekkora a fékút, a maximális megengedett lassulás mellett. Az is kiszámolható, hogy ez mennyi időt vesz igénybe, így az is, hogy mikor kell elkezdeni a vészfékezést, hogy a gyalogost ne üssük el.

A radar szenzor elég messzire ellát, egy nem mozgó objektum (pl. fa) esetében egyszerű meghatározni, hogy lesz-e ütközés és el kell-e kezdeni vészfékezni. Mozgó objektum (gyalogos) esetében azt is figyelembe kell venni, hogy mire odaérünk még az úton lesz-e.

  • elkerülhető ütközés esetén vizuális figyelmeztetés a sofőrnek
  • 70 km/h felett figyelmeztetés, hogy az AEB nem tud minden helyzetet kezelni
  • ha a sofőr nem avatkozik közbe, automatikus fékezés (az utolsó pillanatban, ahol az ütközés még elkerülhető)
  • az automatikus fékezés mértéke a sebességgel arányos, de nem lehet 9 m/s^2-nél nagyobb
  • gyalogos, fa esetén megáll az autó
  • nincs nem releváns objektumokra való fékezés (fals pozitív) - pl. szembejövő autó

Parkoló asszisztens (Parking Pilot - PP)

A rendszert az erre szolgáló vezérlővel aktiválni kell, majd az irányjelzővel kijelölni, hogy jobbra, vagy balra keressük a parkolóhelyet. Ezután ahogy az autó vezetői irányítás mellett végiggurul a parkoló mellett, a rendszer detektálja az üres parkolóhelyet. Ekkor hátramenetbe kapcsolva az PP vezetői beavatkozás nélkül beáll a szabad pozícióba.

Bemutatóvideók (YouTube)

  • Bemutatóvideó
  • Bemutatóvideó

Implementálás

  • a parkolás megkezdése külön inputhoz kötött
  • a kormány és gáz/fék vezérlésével beparkolás a talált helyre
    • a tolatási manőver lehet egy előre definiált szekvencia, amelyet a parkolóhely (abszolút) pozíciójával lehet paraméterezni
  • ha a PP aktív és a váltó hátramenetben van (és van detektált parkolóhely), akkor parkolási szekvencia végrehajtása
  • a párhuzamos parkolás akkor sikeres, ha ütközés nélkül megtörténik
  • a sofőr beavatkozására (fék, gáz, kormány) kikapcsolás (megszűnik az automata vezérlés)
  1. parkolóhely keresése
    • Az üres hely detektálása lényegébe egy állapotátmenet az első és a hátsó ultrahang szenzor „van-e akadály” visszajelzésében. Amíg egy kocsisor mellett halad az autó mindkét szenzor „van akadály” jelzéssel tér vissza (ez valójában nem boolean állapot, egy objektum listát ad vissza), az üres hely kezdetén a az első „nincs akadály” állapotba megy át (a lista üres), majd ahogy az autó halad tovább a hátsó szenzor is „nincs akadály” állapotba kerül.
    • A szabad terület végén ugyanez fordítva játszódik le.
    • Azonban a parkoló autó objektumot adja vissza a szenzor,a melynek ismert a kiterjedése és a referencia pontja, így a játékszoftverben pontosan „látszik” a foglalt terület. Ahogy az egocar elhalad a parkoló autók mellett mindkét autó által lefoglalt terület pontosan ismert így kiszámítható a közöttük meglevő szabad terület.
  2. Parkolóhely azonosítva
    • Miután sikerült meghatározni a szabad parkolóhely méretét, ezt valamiylen formában le kell írni. Célszerűen az egocar referenciapontjáthoz viszonyítva, hogy milyen távol vagyunk tőle, valamint a méretét/hosszát. Lehet egy téglalappal is reprezentálni ahogy az ábrán is látszik.
  3. Automatikus parkolás
    • A parkolási manőver tökéletes megoldása, hogy a Parking Pilot az autó kezelőszerveire hat. Eltekeri a kormányt, gázt ad, fékez, nem csak úgy módosítgatja az autó koordinátáit és elforgatását. (Mindez precízen szabályozható hajtáslánc és kormánymechanika implementációt igényel.)

Parkolás manőver leírása nagy vonalakban forrás:

  1. Bring your car to a stop alongside the car at the front of the space.
  2. Reverse into the space with an S motion.
  3. Once the car is parallel with the curb, pull forward to center your car within the space.

Kezelőszervek

  • aktiválás billentyűzettel
  • az irányjelzővel jelölhető ki keresési oldal

Sávtartó automatika (Lane Keeping Assistant - LKA)

Bemutatóvideó (YouTube)

Bemutatóvideó

Implementálás

Két jellemző megvalósítása van. Az egyik a sáv széleihez viszonyítva korrigál: ha az autó elérné a sáv szélét, akkor ellenkormányoz. A másik megoldás kiszámolja a sáv közepét és azon tartja az autót.

  • 45 foknál enyhébb kanyarodású úton a kocsi a sáv szemmel látható közepén marad
  • ha el kell engednie a kontrollt (az automatika számára kezelhetetlen forgalmi szituáció következik, pl. éles kanyar, kereszteződés), vizuális figyelmeztetést ad Ha újra elérhető a funkció (pl. elhagytuk a kanyart) vizuális indikáció (a műszerfalon) Be- és kikapcsolható

1. Sáv széleinek használata

2. Sávközép használata

Sávon belüli mozgás: a LKA működése egy enyhe sávon belüli cikázást eredményez.

Kezelőszervek

  • aktiválás a műszerfalról (vagy billentyűzettel)

Táblafelismerő (Traffic Sign Recognition - TSR)

A kamera látóterébe eső és az autó számára releváns (ellentétes irányba közlekedők számára szólóakat nem) közlekedési táblákat fel kell ismerni és a legutolsó relevánsat megjeleníteni a műszerfalon. Ha ez sebességkorlátozás, akkor azt a buszra kiírni (az ACC használja).

Bemutatóvideó (YouTube)

Bemutatóvideó

Implementálás

  • a táblát addig kell megjeleníteni, amíg újabb nem talál a rendszer
  • a sebesség limit mindaddig érvényes, míg feloldásra vagy felülbírálásra nem kerül
  • nem releváns táblák nem kerülhetnek azonosításra
    • mindenek előtt az út bal oldalán levők
  • a kamera látótere elég nagy, a kanyaroknál kialakuló helyzetet is kezelni kell

Tolatóradar

A hátsó ultrahang szenzorokat használja akadály detektálásra. Kiszámolja az akadály távolságát és annak megfelelően figyelmeztető jelzést ad a vezetőnek, megkönnyítve a manuális parkolást, tolatást.

Bemutatóvideó (YouTube)

Bemutatóvideó

Implementálás

  • csak hátramenetben aktív
  • figyelmeztetés megjelenítése a műszerfalon
  • távolság megjelenítése a műszerfalon
  • a buszon keresztül történik a modulok (tolatóradar és műszerfal) kommunikáció
  • a kijelzés 3 fokozatban történik
    • nincs akadály
    • közel van akadály (0.8m-en belül)
    • nagyon közel van akadály (0.4m-en belül)

Referencia architektúra

A repó található kezdeti kódot (skeleton) egységes alapot képez a félév során megvalósítandó szoftver számára, azonban nem kíván tökéletes és teljes megoldást biztosítani a feladat egyetlen elemére sem, mindösszesen példaként szolgál a következőkre:

  • projekt struktúra
  • grafikus felület létrehozása
    • WPF keretrendszerrel
    • Avalonia keretrendszerrel
  • világmodell benépesítése
  • vezérelt autó példányosítása és kiválasztása
  • képfájl betöltése projektkönyvtárból
  • világobjektumok rajzolása MVVM rendszerben
  • vezérelt autó állapotának megjelenítése a műszerfalon
  • ütemező használata
  • billentyű lenyomás és felengedés esemény kezelése
  • szenzor objektum létrehozása
  • adatcsomag küldése és fogadása a Virtual Function Bus-on keresztül

Átfogó kép

A teljes szoftver moduljai 12 user story-ra vannak bontva. Az egyes modulok a teljes szoftver egy-egy komponensét valósítják meg. A legtöbb ilyen komponens a vezérelt autón belül kap majd helyet. Azonban vannak olyan komponensek (irányítás és megjelenítés), amelyek nem csak az autón belül, de azon kívül, a keretszoftverben működnek.

A billentyűzet események kezelése értelemszerűen a szoftverban történik, amelyet aztán a szimulált autó kezelőszerveire (gáz- és fékpedál, kormány) kell leképezni. A megjelenítésnek pedig értelemszerűen a teljes világot, de legalábbis az autó egy környezetét kell, hogy kirajzolnia.

Virtual Function Bus

A VirtualFunctionBus (VFB) egy kommunikációs megoldás az AutomatedCar komponensei (SystemComponent) számára. A komponensek feliratkoznak a buszra és a feliratkozás sorrendjében ciklikusan meghívásra kerül a Process() metódusok.

Ebből következik, hogy a feliratkozást az ábrán látható sorrendben kell megtenni, mivel az adatáramlásnak ilyen irányultsága van. Az ábra a kód kezdeti állapotát szemlélteti, a munka során további modulok (szenzorok, vezetés támogató rendszerek) is csatlakoznak majd. Valamint a hajtáslánc és a kormányzás modult nem kötelező ennyire élesen szétválasztani.

Minden adatközlő modulnak létre kell hoznia egy-egy csomag (packet) típust (és vele párhuzamosan egy az olvasást biztosító interfészt), amely tartalmazza azokat az információkat amelyeket továbbítania kell. Például az input modul a pedál és kormány állásokat. A hajtáslánc a következő, kiolvassa a pedál és váltó állást, számol vele, majd visszaírja a saját csomagjába motor fordulatszámát és az autó sebességét, stb. Ezekre legközelebb a kormányzás modulnak lesz szüksége, az kiolvassa ugyanúgy mint az input modul kormányállás értékét, számol vele, majd visszaírja a autó adott iterációra vonatkozó elmozdulását.

Használata általánosan

  1. Create a new package (e.g. SteeringAnglePacket)
  2. Create a new interface for it (e.g. IReadonlySteeringAnglePacket)
  3. Add reference to the owner component (e.g. SteeringSystem)
  4. Add the interface reference to the VirtualFunctionBus
  5. In the loop method of the writing componenet set the payload value of the packet
  6. In the loop method of the reading compontent read the payload of the packet

Konkrét példán keresztül: DummySensor

A DummySensor egy rendkívül primitív „szenzor”: egyetlen feladata, hogy kiszámolja az egocar ás a Circle objektum közötti távolságot. Pontosabban az egocar és a kör referenciapont X, Y koordinátáinak különbségét. Azonban ez is teljes mértékben képes bemutatni a szenzorok működését és a buszon keresztüli adatcserét.

A példa szempontjából releváns komponensek viszonyát alábbi ábra szemlélteti.

A World singleton osztály tartalmaz minden WorldObject-et és tartalmaz referenciát a vezérelt autóra, amely közvetetten szintén WorldObject, csakúgy mint a Circle. Az AutomatedCar tartalmazza a VirtualFunctionBus-t, mivel ez az autó komponenseinek kommunikációs csatornáját valósítja meg. Szintén az AutomatedCar tartalmazza a szenzorokat, jelen esetben a DummySensor-t.

Ahhoz, hogy a szenzorok (vagy egyéb komponensek mint a hajtáslánc például) adatot cserélhessenek fel kell iratkozniuk a VFB-ra. Miután a feliratkozás megtörtént, a VFB minden ciklusában meghívja a Porcess() metódusát. A DummySensor esetében ez a metódus elkéri a világtól a kör objektumot, kiszámolja a vezérelt autó és a kör távolságát, majd ezt a távolságot eltárolja a DummyPacket objektumban (amely egy IReadOnlyDummyPacket típuson keresztül a VFB-ban van tárolva).

A dummyPacket referenciája eltárolásra került a VirtualFunctionBusban, amely referenciáját a a szenzor konstruktorának biztosítani kell. Ehhez előzetesen létre kell hozni egy IReadOnlyDummyPacket típusú változót a VFB-ban.

Miután a DummyPacket megvalósítja az IReadOnlyDummyPacket interfészt, a VFB-ban az utóbbi típus tárolására szolgáló változó kerül deklarálásra. Ezzel biztosítható, hogy az adott értéket csak a csomag tulajdonosa (jelen esetben a DummySensor) tudja majd írni, de minden más komponens olvashatja a VFB-on keresztül.

Ez lejátszódik minden iterációban, így a kör és a vezérelt autó mindenkori helyzete szerinti távolságot fogja tartalmazni a DummyPacket.

Osztálydiagramok

Megjelenítés

Az elkészítendő szoftver felhasználói felületének az alábbi vázlat felépítését kell követnie.

gui plan

A programablak bal oldalán a virtuális világ egy szeletét látjuk ezért felel a vizualizációs modul. A megjelenítés középpontja az mindenkor vezérelt autó (egocar). A világ minden eleméhez tartozik egy képfájl, ezen elemek megfelelő transzformációk (forgatás, skálázás) végrehajtása után kirajzolásra kerülne a CourseDisplayre.

Továbbá erre a részre kerülnek kirajzolásra a debuggoláshoz és teszteléshez használandó segédobjektumok opcionálisan bekapcsolható megjelenítése. Ide tartozik a szenzorok látómezeje, a világobjektumok „poligon váza”, valamint utóbbiak eseményre történő kiemelésének lehetősége.

A jobb oldalon a műszerfal található. A műszerfalon nincsenek vezérlőelemek, csak megjelenítés. Az összes kapcsoló a billentyűzettel állítható, a grafikus elemeknek nem kell pl. egérrel kapcsolhatónak lenniük.

A fordulatszám és a sebesség legyen egy analóg órával reprezentálva; a kormány elforgatás, a gáz- és fékpedál állása progressbar-okkal szemléltethető. Az irányjelző visszajelzője és a vezetéstámogató funkciók visszajelzői lámpaszerűek, a sebességváltó állása, és a debug értékek pl. kocsi pozíciója (x, y koordináta) lehet szöveges. A buszon közölt „utoljára látott tábla” képét ki kell tudni rajzolni (a képek rendelkezésre állnak). Legyen elkülönítve a nincs tábla eset is.

A megjelenítéshez tetszőleges grafikus keretrendszer választható, alább a skeleton két változatban kerül bemutatásra.

WPF alapú megjelenítés

Az ismert WPF alapú implementáció, amely egyenértékű a később taglalt Avalonia alapú megoldással. Mindkettő XAML alapú, MVVM modellű keretrendszer, előbbi Windows-os, utóbbi platform független.

A főablak két UserControlt tartalmaz, az egyik a CourseDisplay, a másik a Dashboard, azért lettek szétválasztva, hogy a két komponensen dolgozó csapatoknak ne kelljen egymás munkájába nyúlkálniuk.

Például, alább látható a műszerfal, amely egy AutomatedCar objektum megjelenítését végzi. Egészen pontosan a World-ben tárolt controlledCar objektumét. A ControlledCar tulajdonság egy referencia az éppen vezérelt autóra (elvben lehetne a világban több AutomatedCar példány és ezek között váltogathatnánk is. Ilyen esetben a ControlledCar mindeg az aktuálisra mutat, amelyet meg akarunk jeleníteni). A DashboardView a DashboardViewModel-en keresztül a controlledCar-hoz van kötve.

<ContentControl Name="Dashboard" Content="{Binding World.ControlledCar, Mode=OneWay}" >
    <ContentControl.ContentTemplate>
        <DataTemplate DataType="{x:Type models:AutomatedCar}">
            <StackPanel>
                ...
            </StackPanel>
        </DataTemplate>
    </ContentControl.ContentTemplate>
</ContentControl>

A példakód ezt biztosítja, a feladat a konkrét visszajelzőkhöz megfelelő felületi elemek definiálása.

CourseDisplay

A teljes CourseDisplay lényegében egy ItemsControl, amely a világ WorldObjects tulajdonságához van kötve. Ezen belül található egy Canvas, amire a rajzolás történik, valamint egy DataTemplate, amely azt írja le, hogy egy WorldObject típusú objektumok hogyan kell kezelni. A világelemhez tartozó képet kell kirajzolni, így tartalmaz egy Image-et, amelynek forrása a WorldObject Filename tulajdonsága. A Converter attribútumon keresztül meg lehet hívni egy függvényt, amellyel akár befolyásolni lehet a rajzolást (transzformálás).

A WorldObject -az alkalmazás szempontjából- a világ minden elemének őse, de ennél specializáltabban is lehet definiálni template-eket. Az alábbi kódrészlet szétbontja Circle és AutomatedCar típusokra, előbbihez nem is képet tölt be, hanem közvetlenül rajzol a Canvas-re. Az utóbbi esetben egyrészt a fentivel megegyező módon betölt egy képet, valamit arra kirajzol egy poligont (ez a debug funkcióknál kell majd).

<ItemsControl Name="CourseDisplay"
    ItemsSource="{Binding WorldObjects, Mode=OneWay}"
    Width="{Binding Width, Mode=OneWay}"
    Height="{Binding Height, Mode=OneWay}"
    HorizontalAlignment="Left" VerticalAlignment="Top"
    >

     <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Setter Property="Canvas.Left" Value="{Binding X}"/>
            <Setter Property="Canvas.Top" Value="{Binding Y}"/>
            <Setter Property="Canvas.ZIndex" Value="{Binding ZIndex}"/>
        </Style>
    </ItemsControl.ItemContainerStyle>

    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <ItemsControl.Resources>
        <DataTemplate DataType="{x:Type models:Circle}">
            <Canvas>
                <Ellipse Fill="black" Width="{Binding Width}" Height="{Binding Height}" Panel.ZIndex="10"/>
            </Canvas>
        </DataTemplate>
        <DataTemplate DataType="{x:Type models:AutomatedCar}">
            <Canvas>
                <Image Width="{Binding Width}" Height="{Binding Height}"
                    Source="{Binding Filename, Converter={x:Static visualization:WorldObjectTransformer.Instance}}"/>
                <Polyline Stroke="red" Points="{Binding Geometry.Points, Mode=OneWay}" />
            </Canvas>
        </DataTemplate>
    </ItemsControl.Resources>
</ItemsControl>

A skeletonban esetben az objektum nem a képet tárolja, hanem a képfájl nevét (Filename, ez van a Source-hoz kötve), a fájlnévből pedig egy konverter segítségével kap a megjelenítés képet.

Ráadásul nem is tölti be minden esetben a képfájlokat, hanem gyorsító-tárazza azokat fájlnév alapján egy Dictionary segítségével. A WorldObjectTransformer singleton, hogy ez a mechanizmus megfelelően működhessen.

public class WorldObjectTransformer : IValueConverter
{
    private static Dictionary<string, BitmapImage> cache = new Dictionary<string, BitmapImage>();

    public static WorldObjectTransformer Instance { get; } = new WorldObjectTransformer();

    static BitmapImage GetCachedImage(string filename)
    {
        if (!cache.ContainsKey(filename))
        {
            var image = new BitmapImage(new Uri($"src/AutomatedCar/Assets/WorldObjects/{filename}", UriKind.Relative));
            image.Freeze();
            cache.Add(filename, image);
        }
        return cache[filename];
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
        GetCachedImage((string)value);
}

Megfigyelhető továbbá, hogy az AutomatedCar template esetében nem csak a kép van kirajzolva, hanem egy poligon ez, ez az objektum poligon váza, amelyet pl. ütközésekhez kell majd felhasználni. Előbb a kép, majd rá a polyline kerül kirajzolásra. Az ilyen poligonok megjelenítése debug funkciókét a megjelenítés feladata. A rajzolás pedig egy logikai értékhez kapcsolható...

Pozicionálás

Megfigyelhető, hogy a fenti példán, hogy a ItemsControl.ItemContainerStyle rendelkezik az objektumok pozíciójáról. Ezt CSS-szerűen működő stílusokkal lehet megadni. Az ItemsControl elemei (a WorldObject-ek) X, Y és ZIndex tulajdonságához van kötve a ContentPresenter Canvas Left, Top és ZIndex attribútuma.

Az alábbi ábrán látható a futó alkalmazás: bal oldalt a kezdetleges CourseDisplay, jobb oldalt a kezdetleges Dashboard. Az autó az (50, 50) pozícióba van kirajzolva, a kör a (400, 200) koordinátákra (bal felső sarokkal értendő) ezek különbségét pedig kiszámolta a DummySensor és leolvasható a műszerfalról.

Avalonia alapú megjelenítés

Az Avalonia keretrendszer által is használt MVVM modellben az objektumokhoz tartozik egy definiált a megjelenítés.

Jelen esetben például a műszerfal egy AutomatedCar objektum megjelenítése. Egészen pontosan a World-ben tárolt controlledCar objektumé. A DashboardView a DashboardViewModel-en keresztül a controlledCar-hoz van kötve.

<ContentControl Name="Dashboard" Content="{Binding World.ControlledCar, Mode=OneWay}" >
    <ContentControl.ContentTemplate>
        <DataTemplate DataType="{x:Type models:AutomatedCar}">
            <StackPanel>
                ...
            </StackPanel>
        </DataTemplate>
    </ContentControl.ContentTemplate>
</ContentControl>

A példakód ezt biztosítja, a feladat a konkrét visszajelzőkhöz megfelelő felületi elemek definiálása.

CourseDisplay

A teljes CourseDisplay lényegében egy ItemsControl, amely a világ WorldObjects tulajdonságához van kötve. Ezen belül található egy Canvas, amire a rajzolás történik, valamint egy DataTemplate, amely azt írja le, hogy egy WorldObject típusú objektumok hogyan kell kezelni. A világelemhez tartozó képet kell kirajzolni, így tartalmaz egy Image-et, amelynek forrása a WorldObject Filename tulajdonsága. A Converter attribútumon keresztül meg lehet hívni egy függvényt, amellyel befolyásolni lehet a rajzolást (transzformálás).

<ItemsControl Name="CourseDisplay"
    DataContext="{Binding World, Mode=OneWay}"
    Items="{Binding WorldObjects, Mode=OneWay}"
    Width="{Binding Width, Mode=OneWay}"
    Height="{Binding Height, Mode=OneWay}"
    HorizontalAlignment="Left" VerticalAlignment="Top"
    >

    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <ItemsControl.DataTemplates>
        <DataTemplate DataType="{x:Type models:WorldObject}">
            <Image Width="{Binding Width}" Height="{Binding Height}"
                Source="{Binding Filename, Converter={x:Static visualization:WorldObjectTransformer.Instance}}"/>
        </DataTemplate>
    </ItemsControl.DataTemplates>
</ItemsControl>

A WorldObject -az alkalmazás szempontjából- a világ minden elemének őse, de ennél specializáltabban is lehet definiálni template-eket. Az alábbi kódrészlet szétbontja Circle és AutomatedCar típusokra, előbbihez nem is képet tölt be, hanem közvetlenül rajzol a Canvas-re. Az utóbbi esetben egyrészt a fentivel megegyező módon betölt egy képet, valamit arra kirajzol egy poligont (ez a debug funkcióknál kell majd).

<ItemsControl.DataTemplates>
    <DataTemplate DataType="{x:Type models:Circle}">
        <Canvas>
            <Ellipse Fill="black" Width="{Binding Width}" Height="{Binding Height}" ZIndex="10"/>
        </Canvas>
    </DataTemplate>
    <DataTemplate DataType="{x:Type models:AutomatedCar}">
        <Canvas>
            <Image Width="{Binding Width}" Height="{Binding Height}"
                Source="{Binding Filename, Converter={x:Static visualization:WorldObjectTransformer.Instance}}"/>
            <Polyline Stroke="{Binding Brush, Mode=OneWay}" Points="{Binding Geometry.Points, Mode=OneWay}" />
        </Canvas>
    </DataTemplate>
</ItemsControl.DataTemplates>

Pozicionálás

Megfigyelhető, hogy a fenti példák nem rendelkeznek az objektumok pozíciójáról. Ezt CSS-szerűen működő stílusokkal lehet megadni. Az alábbi példa beszínezi zöldre a CourseDisplay-t, valamint a WorldObject-ek Left és Top értékeit beállítja a WorldObject X és Y értének megfelelően.

<UserControl.Styles>
    <Style Selector="ItemsControl#CourseDisplay">
        <Setter Property="Background" Value="#97D1A2"/>
    </Style>
    <Style Selector="ItemsControl#CourseDisplay > ContentPresenter">
        <Setter Property="Canvas.Left" Value="{Binding X, Mode=OneWay}"/>
        <Setter Property="Canvas.Top" Value="{Binding Y, Mode=OneWay}"/>
        <Setter Property="ZIndex" Value="{Binding ZIndex, Mode=OneWay}"/>
    </Style>
</UserControl.Styles>

Az utóbbi verziót használva az alábbi ábrán látható a futó alkalmazás: bal oldalt a kezdetleges CourseDisplay, jobb oldalt a kezdetleges Dashboard. Az autó az (50, 50) pozícióba van kirajzolva, a kör a (400, 200) koordinátákra (bal felső sarokkal értendő) ezek különbségét pedig kiszámolta a DummySensor és leolvasható a műszerfalról.

Forgatás

Az autó forgatása is a pozicionáláshoz hasonló elven történik. Az alábbi példában közvetlenül az egyes elem Canvas-ához csatoljuk a transzformációs utasításokat. Ez azzal is jár, hogy egyszerre lehet transzformálni a képet és a poligont is. Több transzformáció esetén fontos a TransformGroup használata. Például forgatás (szögben) az elem egy változójához kötve. Valamint egy X,Y eltolás az előbbi példában.

<DataTemplate DataType="{x:Type models:AutomatedCar}">
    <Canvas>
        <Canvas.RenderTransform>
            <TransformGroup>
                <RotateTransform Angle="{Binding Angle}" />
                <TranslateTransform  X="54" />
                <TranslateTransform  Y="120" />
            </TransformGroup>
        </Canvas.RenderTransform>
        <Image Source="{Binding Filename, Converter={x:Static visualization:WorldObjectTransformer.Instance}}"/>
        <Polyline Stroke="{Binding Brush, Mode=OneWay}" Points="{Binding Geometry.Points, Mode=OneWay}" />
    </Canvas>
</DataTemplate>