Gedistribueerd Verkeersmanagement Tigran Kalaidjan [
[email protected]] 23 Augustus 2007
Begeleider: Maarten Boasson
Universiteit van Amsterdam
Inhoudsopgave Inleiding ………………………………………………………………………………… 3 Global overzicht van het verkeersmanagement systeem ………………………………... 5 Ontwerp voor het model ………………………………………………………………… 9 Globaal overzicht ………………………………………………………………..... 9 Snelwegproces ……………………………………………………………………12 Autoproces …………………………………………………………………..…... 14 Communicatie queue …………………………………………………………...... 18 Methode Beste strook ……………………………………………………………. 19 Methode Optimale snelheid ………………………………………………………. 20 Uitvoering ……………………………………………………………………..… 21 Management ………………………………………………………………….…. 21
Implementatie ………………………………………………………………………….. 23 Resultaten en verder onderzoek ………………………………………………………... 38 Conclusie ……………………………………………………………………………….. 42 Referenties ……………………………………………………………………...……… 42 Appendix ……………………………………………………………………………….. 43 Wireless Access in Vehicular Environments (WAVE) …………………………….. 43 VEMP ……………………………………………………………………….….. 43 JavaSpace (JS) …………………………………………………………………... 43 Periodieke update ……………………………………………………………..…. 44 Onderzoek voorstel ……………………………………………….……..……….. 45 Code …………………………………………………………………………….. 46
2
Inleiding Stelt u zich eens voor u wilt zich van punt A naar punt B verplaatsen met uw auto. Hoe zou dat in zijn werk gaan in het jaar 2020? Als eerste zou u uw wensen in de Verkeer wizard invoeren. Deze wizard is een standaard component van de auto en bevat communicatievoorzieningen, een GPS ontvanger, capaciteit om tamelijk ingewikkelde berekeningen in real-time uit te voeren en een praktische user interface . Vervolgens zal de wizard een verbinding maken met een dicht bijzijnde Verkeers-server. Deze server heeft zowel actuele informatie als statistieken over files. Met deze informatie en de wens van punt A naar punt B te reizen, zal de server een beste route uitrekenen en deze vervolgens terug zenden naar de wizard. Zo‟n beste route wordt niet alleen bepaald aan de hand van de kortste route van punt A naar punt B, maar wordt mede bepaald aan de hand van actuele informatie en statistieken van het verkeer over de verschillende routes van punt A naar punt B. Met andere woorden, de server berekent niet alleen maar de kortste route, hij rekent ook uit wat in de gewenste periode de waarschijnlijk minst drukke route is, dus de route waar minder files voorkomen, waardoor de bestemming sneller bereikt wordt. De server is ook in staat om verkeer te verdelen over verschillende mogelijke routes van punt A naar punt B, zodat de snelwegen in Nederland optimaal gebruikt worden. Merk op dat deze manier van routebepaling al een file-bestrijdende werking heeft, omdat servers auto‟s met dezelfde bestemming over verschillende wegen proberen te verspreiden en files worden niet vergroot doordat auto‟s een omgeleide route krijgen. Een server zou bijvoorbeeld auto‟s die van Amsterdam naar Amersfoort willen rijden verspreiden via de directe snelweg A1 en snelweg A2 (via Utrecht). Dit zal ook voor de bestuurder voordelig zijn, want door de file op de A1 zal hij er langer over doen dan wanneer hij via Utrecht rijdt, als tenminste op die route geen files staan. Na het verkrijgen van de beste route van de server zal de auto de route uitvoeren. Het rijden zelf zal niet meer gebeuren door de eigenaar, maar door de auto zelf1. Doordat auto‟s niet meer door bestuurders worden gereden wordt het risico van het ontstaan van files verkleind. Mensen maken vaak overhaaste beslissingen, of zijn te traag in hun reacties, waardoor ze files alleen maar vergroten. Een voorbeeld: als een bestuurder de remlichten van de auto voor hem ziet oplichten, dan gaan veel bestuurders onnodig remmen of zelfs hard remmen. Daardoor gaan auto‟s erachter ook hard remmen, en hierdoor kan gemakkelijk een file worden veroorzaakt. Dit zal niet gebeuren als de auto zich zelf gaat besturen, mits de auto exact en tijdig te weten kan komen hoe hard een auto voor zich remt; de auto zal soms niet remmen, maar minder accelereren, of remmen zoveel als noodzakelijk is en niet ineens op volle kracht.
1
Er zijn momenteel al auto‟s die zichzelf kunnen besturen, zoals VEMP van MercedesBenz. Ze zijn nog niet helemaal klaar voor dagelijks gebruik, maar dat is een kwestie van tijd en geld. 3
Daarnaast moeten we niet vergeten dat een mens gemiddeld na drie kwartier geconcentreerd bezig te zijn geweest concentratievermogen verliest; dit probleem heeft een besturende computer in een auto niet. Tijdens het rijden zal elke auto, gebruik makend van WAVE (Wireless Access in Vehicular Environments, zie appendix), communiceren met omringende auto‟s en de servers langs de snelweg. Door onderlinge communicatie tussen auto‟s, wordt er een beter beeld gecreëerd van het verkeerd om de auto heen. Dus de beperkingen van het waarnemen met alleen camera‟s zoals door VEMP zullen gecompenseerd worden door informatie die verkregen is via communicatie. Auto‟s zullen niet meer hun beslissingen nemen aan de hand van alleen direct omringende auto‟s, beslissingen worden nu genomen aan de hand van gedrag van auto‟s in een straal van 500 meter, het bereik van WAVE. Dus op het moment dat de tiende auto vóór de huidige auto plotseling moet remmen, komt de huidige auto dit bijna direct te weten via communicatie, en kan er gelijk gereageerd worden. In het geval zonder communicatie zou de auto pas kunnen reageren op het moment dat de auto ervoor hard zou remmen. Dus met communicatie is er tijdwinst te behalen: een auto zal meer tijd hebben om een, voor de afwikkeling van het verkeer, goede beslissing te maken, bijvoorbeeld geleidelijk afremmen in plaats van ineens vol in de remmen. Daarnaast is één van de mogelijkheden om een scan uit te voeren, op basis van deze scan het gedrag van de auto‟s op de snelweg te analyseren en zo bijv. de minst gebruikte rijstrook te bepalen. Door de minst gebruikte rijstrook te nemen wordt verkeer gelijkmatig verspreid over de hele snelweg en dus wordt er beter gebruik gemaakt van de bestaande snelweg. Mijn onderzoek gaat over het laatste onderdeel waarin auto‟s met elkaar communiceren en hierdoor een beter gebruik maken van de bestaande snelweg, wat tot vermindering van files moet leiden (zie Appendix: “Onderzoek voorstel”). Hierbij wil ik ook allereerst mijn begeleider prof. drs. Maarten Boasson bedanken voor zijn begeleiding tijdens het project, commentaar en suggesties bij de ontwerpfase en de correcties bij het schrijven van de scriptie. Daarnaast wil ik ook het afstudeerprojectteam, mw. dr. Inge Bethke, dr. Dick van Albada, dr. ir. Alfons Hoekstra, dr. Rein van den Boomgaard en dr. Andy Pimentel bedanken voor hun inzet en de begeleiding.
4
Globaal overzicht van het verkeersmanagement systeem In een gedistribueerd verkeersmanagement systeem is er communicatie tussen auto‟s onderling en van auto‟s met servers langs de snelweg. De technologie die gebruikt wordt voor het uitwisselen van berichten is WAVE; deze is in staat om berichten in een straal van 500 meter te ontvangen. Elke auto of een server met een WAVE ontvanger zal de berichten via de ether kunnen ontvangen en ze vervolgens intern verwerken. De snelwegen zijn verdeeld in sectoren, elke sector van een kilometer heeft een bijbehorende server. Deze server beschikt over de volgende informatie over die specifieke sector: snelweg en sector id., aantal stroken in de sector en maximale snelheid op bepaalde locaties in de snelweg sector. Deze informatie wordt in een bericht via WAVE continu (eens in 0,25 seconde) verstuurd naar de auto‟s. Auto‟s zullen deze berichten ontvangen en intern verder verwerken. Daarnaast ontvangt de server ook informatie van auto‟s en aan de hand van deze informatie worden statistieken in de server bijgehouden over het verkeer. Auto‟s zelf beschikken ook over WAVE en ze sturen berichten naar servers en andere auto‟s. Er worden regelmatig berichten gestuurd naar de servers, zodat deze informatie over de auto‟s kunnen verwerken voor offline statistieken, die later gebruikt kunnen worden om files te voorspellen. De berichten die gestuurd worden naar andere auto‟s en servers zijn berichten met de volgende inhoud: auto id., snelweg en sector id., rijstrook nummer, huidige snelheid, gewenste snelheid, acceleratie, locatie en status. De snelweg en de sector id. worden bepaald aan de hand van binnen gekomen informatie van de servers langs de weg. Rijstrook nummer, huidige snelheid en acceleratie wordt intern door de auto zelf bijgehouden. Gewenste snelheid wordt door de eigenaar van de auto ingevoerd in het systeem. Locatie van de auto wordt bepaald door GPS systemen die in staat zullen zijn om de locatie van auto in centimeters nauwkeurig te bepalen. De status van de auto geeft aan of de auto stil staat, aan het rijden is of bij een botsing is betrokken. De status wordt intern door de auto zelf bijgehouden. Als de server periodiek (eens in 0,25 seconde) bovengenoemde algemene informatie van alle auto‟s ontvangt, dan is hij in staat om statistieken bij te houden over de drukte op de snelweg, en dus ook op welke tijdstippen files gewoonlijk veroorzaakt worden en hopelijk in sommige gevallen ook waarom de files veroorzaakt worden teneinde dat in de toekomst te voorkomen door betere instructies aan de auto‟s te geven. Ook auto‟s zelf hebben veel aan deze algemene informatie. Elke auto krijgt deze algemene informatie van auto‟s die binnen een straal van 500 meter rijden. Aan de hand van deze algemene informatie is een auto in staat om zijn verplaatsing over de snelweg te optimaliseren. Immers, door deze algemene informatie weten auto‟s waar de andere auto‟s zich bevinden, met welke snelheid ze rijden en tot op zekere hoogte wat ze van plan zijn. De berichten tussen auto‟s worden periodiek (tussen 0,15 en 0,25 seconde, zie Appendix: Periodieke update) uitgewisseld, dus informatie over auto‟s is bijna real-time. Een auto slaat alle binnengekomen algemene informatie over andere auto‟s intern op. Hij is dan ook in staat uit te rekenen welke auto ervoor rijdt, om bijvoorbeeld deze te volgen 5
aan de hand van de snelheid en acceleratie van de voorste auto, of de voorste auto juist in te halen. Bij inhalen moet onderzocht worden of er zich auto‟s bevinden op de linker strook die naast de bewuste auto rijden of dat binnenkort zullen doen. Elke auto weet, als gevolg van de communicatie met de server en met andere auto‟s binnen een straal van 500 m op welke strook en op welke locatie verschillende auto‟s rijden. Als een achterste auto een voorste auto aan het volgen is zal de snelheid bepaald worden aan de hand van de snelheid van de voorste auto. Op grond van de voorste snelheid, de eigen snelheid en het vermogen van de auto wordt de eigen acceleratie bepaald. Elke auto heeft eigen vastgestelde acceleratie mogelijkheden bij een gegeven snelheid. Naast het inlezen van de snelheid van de voorste auto wordt ook de acceleratie van de voorste auto ingelezen. Met deze informatie is de achterste auto in staat om te anticiperen op het gedrag van de voorste auto in geval van onverwachte manoeuvres. Daarmee wordt het volgende bedoeld: als de voorste auto plotseling moet remmen, dan is het direct te zien in de acceleratie, terwijl de snelheid dan nog nauwelijks veranderd zal zijn. Door deze kennis is de achterste auto in staat om tijdig zijn eigen snelheid geleidelijk aan te passen om later niet onnodig hard te hoeven remmen. Aan de hand van de algemene informatie is niet alleen volgen en inhalen mogelijk, een auto is ook in staat vrijuit te rijden indien er geen auto‟s vóór rijden, of proberen rechts te rijden als de rechter rijstrook vrij is. Rechts rijden gebeurt net als inhalen: als er op de rechter strook geen auto‟s zijn dan zal de auto een rijstrook naar rechts nemen. Het bepalen of er zich op de rechter rijstrook auto‟s bevinden die naast de huidige auto rijden, wordt gedaan door het inlezen van locaties van de auto‟s in de algemene informatie array. Vrijuit rijden is ook een kwestie van inlezen van algemeen informatie. Als de auto constateert dat zich op dezelfde rijstrook geen auto‟s bevinden met een locatie die dicht vóór de eigen locatie is, dan betekent dat dat er geen auto‟s vóór rijden, en dus kan de auto gaan rijden op de gewenste snelheid. In dit geval wordt bij de gegeven snelheid de vooraf bepaalde optimale acceleratie gebruikt. De optimale acceleratie is de maximale acceleratie die nog acceptabel is gezien de milieubelasting; bij maximale acceleratie wordt er veel brandstof gebruikt, wat schadelijk is voor het milieu. Aan de hand van algemeen informatie zijn de auto‟s ook in staat een scan uit te voeren over een stukje snelweg waardoor ze in staat zijn om een beste rijstrook uit te kiezen. Het voordeel van het kiezen van de beste strook is dat de auto‟s een beslissing maken die de doorstroming van het verkeer bevordert: er wordt geprobeerd om de snelweg zo goed mogelijk te gebruiken, dus auto‟s te verdelen over de hele snelweg waarbij classificaties gemaakt worden in de snelheiden van de auto‟s. Dus auto‟s die het snelst rijden moeten de meest linkse strook kiezen en auto‟s die het langzaamst rijden worden geacht om helemaal rechts te rijden. Alle auto‟s zullen consistente beslissingen maken, omdat alle auto‟s over dezelfde algemene informatie beschikken en hetzelfde algoritme gebruiken om de beste rijstrook te kiezen. Ook is een auto in staat een optimale snelheid te bepalen aan de hand van algemene informatie. Per rijstrook vormen zich colonnes met een bijbehorende Gids. De Gids zal als eerste informatie lezen van een andere Gids die bij de colonne die vóór de Gids rijdt
6
hoort. Tussen de Gids en de voorste colonne zullen er i.h.a. ook auto‟s aanwezig zijn die de voorste colonne proberen in te halen; de Gids zal ook van deze auto‟s informatie inzamelen om zo ook rekening te houden met het verkeer tussen zichzelf en de voorste colonne. Aan de hand van bovengenoemde informatie zal de Gids de optimale snelheid bepalen. Hiermee wordt bereikt dat alle auto‟s in een colonne niet zelf de optimale snelheid hoeven uit te rekenen, maar dat dat voor hun door de Gids wordt gedaan. Elke auto zal alleen twee seconde afstand houden ten opzichte van de auto er voor, maar feitelijk rijdt de auto met een snelheid die bepaald is door het verkeer dat zich een paar auto‟s verder bevindt. Dus elke auto zal als het ware niet slechts één auto vooruit kijken, maar veel verder, om zo het verkeer beter te laten doorstromen. Naast algemene informatie worden ook specifieke berichten uitgewisseld tussen auto‟s. Deze specifieke berichten zijn gericht van de ene auto naar een andere auto. Een specifiek bericht dat wordt ontvangen wordt de hoogste prioriteit gegeven om het zo snel mogelijk te behandelen. Een voorbeeld van een specifiek bericht is als auto A links naast auto B rijdt en auto A gedwongen word om naar rechts te gaan door een versmalling van de snelweg. In dit gevaal zal auto A een specifiek bericht sturen naar auto B, waarin het type van het specifieke bericht aangeeft dat auto A gedwongen is om rechts te gaan rijden. In dit geval zal auto B met hoogste prioriteit dit bericht verwerken, dus plaats maken voor auto A. Voor alle specifieke berichten wordt één en dezelfde soort bericht gebruikt, terwijl het verschil tussen de berichten te zien is aan het bericht type, dat ook precies aangeeft wat de situatie is en hoe er gehandeld moet worden in zo‟n situatie. Om het rijden zo veilig mogelijk te maken zal er niet alleen gereden worden aan de hand van algemene en specifieke informatie over andere auto‟s, maar er zullen ook infrarood en/of radar sensoren aanwezig zijn die omringende auto‟s kunnen detecteren. Er wordt bij elke snelheid een minimale afstand tussen auto‟s omheen vastgesteld; indien de infrarood of radar sensoren detecteren dat een auto zich dichterbij bevindt dan toegestaan is, zal er een alarm afgaan en zal de auto de snelheid of locatie moeten aanpassen om aan de veiligheidseisen te voldoen. Dit kan natuurlijk een aantal specifieke berichten ten gevolge hebben. Met camera‟s zal de auto op zoek zijn naar rijstroken, waarbij dit proces versimpeld wordt door de verkregen informatie van de snelweg server. Deze informatie bevat het aantal rijstroken dat een snelweg sector heeft; indien het er drie zijn en de auto zich op de derde rijstrook bevind hoeft hij niet naar de vierde rijstrook op zoek te gaan. Dus de auto hoeft niet meer te bepalen hoeveel stroken de snelweg heeft, maar moet alleen de aangegeven stroken met camera‟s vinden. Tenslotte is er een management onderdeel, dat ervoor zorgt dat alle onderdelen, zoals vrij rijden, voorste auto volgen, inhalen, rechts rijden, bepalen van beste strook en bepalen van optimale snelheid, met elkaar gecombineerd worden zodat de auto in staat is om zich op de snelweg voort te bewegen. Het management onderdeel zal de bovengenoemde onderdelen achter elkaar uitvoeren. Indien er van situatie veranderd wordt, bijvoorbeeld van strook veranderd wordt, dan is
7
de bedoeling dat het management systeem de nieuwe voorste auto opvraagt via het onderdeel “vind voorste auto”. Terwijl dat uitgevoerd wordt, gaat het management onderdeel gewoon verder met informeren of rechts rijden of inhalen als dat nodig is, of, als het niet nodig is, het bepalen of er gevolgd moet worden of juist vrijuit gereden kan worden. Het management onderdeel houdt ook de drukte van het verkeer in de gaten, en op het moment dat het kritieke punt (uitleg zie: Implementatie) bereikt wordt zullen de methodes toegepast worden die de beste rijstrook en optimale snelheid kunnen bepalen voor de betreffende auto. In de methode “optimale snelheid” wordt ook bepaald of de betreffende auto een Gids is die de colonne moet leiden, of dat de betreffende auto onderdeel van colonne vormt en de Gids ervan moet volgen. Het management systeem zorgt er ook voor dat informatie regelmatig naar server en andere auto‟s verzonden wordt en dat de binnengekomen specifieke berichten met hoge prioriteit behandeld worden.
8
Ontwerp voor het model Globaal overzicht Het model voor autoverkeer is gemaakt om te onderzoeken of communicatie tussen auto‟s voordelen biedt. Het voordeel zou zijn dat communicatie leidt tot een betere doorstroming van het verkeer op een snelweg, wat op zich een bijdrage kan leveren aan het bestrijden van files. Daarnaast is het waarschijnlijk dat de veiligheid zal toenemen door beter inzicht in het gedrag van andere auto‟s. Bij het maken van het model is zoveel mogelijk gekozen voor oplossingen die het model zo dicht mogelijk bij de realiteit brengen. Er zijn natuurlijk extra onderdelen in het model toegevoegd die de werking van het geheel mogelijk maken, maar niet nodig zijn in een echt systeem. Ook zijn er veel aspecten die in het model niet verwerkt zijn, maar in de werkelijkheid wel degelijk een rol spelen bij het nemen van beslissingen. Dit is gedaan vanwege de beperkte scope van dit onderzoek. Om een realistisch model te bouwen is er voor gekozen om voor elke auto een apart proces te gebruiken. De keuze was tussen een thread en een proces voor elke auto. Nu zijn threads min of meer afhankelijk van elkaar en processen helemaal niet. In werkelijkheid is elke auto onafhankelijk van alle andere auto‟s: als een auto defect is, heeft dat geen direct effect op andere auto‟s; dit is ook het gevaal met een apart proces voor elke auto, en niet het geval voor een thread per auto. Als een van de threads verkeerd loopt, dan kan het zijn dat het proces waarin de thread zich bevindt ook fout loopt, waardoor ook andere auto‟s die als thread gemodelleerd zijn binnen dit proces worden afgebroken. Ook is het mogelijk om met threads direct gegevens uit te wisselen omdat threads gezamenlijke geheugen hebben. Omdat dit natuurlijk onmogelijk is met echte auto‟s, was dit nog een reden om een apart proces voor elke auto te kiezen, want processen moeten net als echte auto‟s via een expliciet communicatiekanaal communiceren. Het communicatiemiddel voor echte auto‟s is natuurlijk de ether: door middel van wireless verbindingen volgens WAVE worden berichten uitgewisseld tussen auto‟s. In het model wordt voor de communicatie gebruik gemaakt van JavaSpace (JS - zie Appendix). JS stelt in het model de ether voor, en alle communicaties tussen processen verloopt via de JS. Er is gekozen voor slechts één JS en niet meerdere JS‟s vanwege de realiteit: er is maar één ether en dus ook één JS in het model. Naast een aantal Autoprocessen bevat het model ook een proces dat de snelweg representeert, het Snelwegproces. In de echte wereld zullen servers langs de weg staan die via de ether informatie verspreiden over het stukje snelweg. In het model wordt voor elke snelweg een Snelwegproces aangemaakt dat informatie over de snelweg verstrekt aan de Autoprocessen. Omdat in het model maar één gedeelte van een snelweg gemodelleerd worden, is het niet nodig om in het model een snelweg in gedeeltes te splitsen zodat voor elke gedeelte een Snelwegproces aanwezig is. Er zal slechts één stukje snelweg van 1000 meter gemodelleerd worden waarbij één Snelwegproces hoort.
9
Zoals hierboven uitgelegd verloopt alle communicatie tussen Autoprocessen en het Snelwegproces via de JS. Zodra er een auto de snelweg oprijdt, zal het Autoproces zich moeten aanmelden bij het Snelwegproces, zodat andere Autoprocessen op de hoogte zijn dat er zich een nieuwe auto op de snelweg bevindt. Dit gebeurt door een Autodata object (dat gegevens van de auto bevat) in de JS te zetten. Het Snelwegproces zal de nieuwe Autodata in JS detecteren en toevoegen aan de snelweg. (zie fig. 1b: stippellijn tussen het Snelwegproces en Autodata geeft de detectie van de auto aan) Het Snelwegproces bevat een integer array (ID-autos), waarin alle ID‟s van de Autoprocessen zijn opgeslagen die zich hebben aangemeld en die dus auto‟s representeren die zich op de snelweg bevinden. Het Snelwegproces leest het nieuwe Autodata object uit JS en zet de ID van het Autoproces in de array ID-autos. Deze array bevindt in Snelwegdata die door het Snelwegproces in de JS wordt geplaatst, zodat Autoprocessen deze informatie kunnen inlezen en zo de IDs kennen van alle op de snelweg rijdende auto‟s. Autoprocessen kunnen de array ID-autos wel inlezen, maar niet zelf veranderen, dit kan alleen maar gedaan worden door het Snelwegproces zelf. Eenmaal aangemeld bij het Snelwegproces, zal het Autoproces informatie opvragen over de snelweg. Deze informatie is weer een object (Snelwegdata) dat zich in de JS bevindt; dit object wordt regelmatig door het Snelwegproces bijgewerkt (zie fig. 1a). In het verkregen Snelwegdata object, kun je vinden hoe hard je op de snelweg mag rijden en welke auto‟s zich op de snelweg bevinden (Zie meer hierover bij Snelwegproces). Om ervoor te zorgen dat je de juiste Snelwegdata uit de JS pakt, moet je de ID van de snelweg matchen (zie Appendix JS) met het ID van de snelweg waarop Autoproces wil rijden. Op het moment dat Autoproces de juiste Snelwegdata heeft opgehaald uit de JS, zal het auto proces informatie van andere auto‟s opzoeken in de JS (zie fig. 1d). Dit gebeurt aan de hand van de integer waardes die in de array ID-autos opgeslagen zijn. Deze integer waardes zijn allemaal verschillende ID waardes van Autoprocessen die zich op de snelweg bevinden. Voor elke auto ID kun je het bijbehorende object vinden dat meer informatie bevat over het betreffende Autoproces; dit object wordt Autodata genoemd. Alle Autodata die door een Autoproces uit de JS worden gelezen zullen opgeslagen worden in een interne array (Globaledata). Aan de hand van verschillende Autodata, dus aan de hand van de informatie over auto‟s die zich op de snelweg bevinden zal het Autoproces beslissingen nemen die ervoor zorgen dat de gemodelleerde auto zich veilig en efficiënt verplaatst over de snelweg.
10
Fig. 1 Globaal overzicht van data stromen (lijnen) tussen JS en Autoproces/Snelwegproces 1.a Snelweg wordt aangemaakt, Snelwegdata wordt in JS gezet en geüpdate 1.b Snelwegproces detecteert nieuw Autoproces en voegt het ID toe aan de Snelwegdata (stippellijn) 1.c Meerdere Autoprocessen en het Snelwegproces updaten hun data in de JS 1.d Autoproces leest Autodata van andere Autoprocessen na het inlezen van Snelwegdata
11
Snelwegproces In het model representeert het Snelwegproces een gedeelte van de snelweg. Het Snelwegproces bevat intern informatie over een gedeelte van de snelweg. Deze informatie is gebundeld in een Snelwegdata object en bestaat uit de volgende gegevens: Snelweg Data: - Snelweg ID - Aantal rijstroken - Maximaal-toegestane-snelheid - Array Auto ID‟s (ID-autos) - Array Invoegstrook De Snelweg ID is bedoeld om een snelweg te identificeren. Autoprocessen zullen op zoek zijn in de JS naar snelwegdata met een Snelweg ID die matcht met de snelweg ID waarop de betreffende auto aan het rijden is. Het is voor elk Autoproces handig om te weten hoeveel rijstroken een snelweg bevat, zodat ze dit niet zelf visueel hoeven waar te nemen. Dit wil nog niet zeggen dat in werkelijkheid niet visueel de rijstroken gezocht moeten worden. Het is alleen maar een versimpeling van het zoekproces naar rijstroken. Als een auto op de hoogte is dat een bepaald snelweggedeelte maar twee rijstroken heeft, dan zal het niet op zoek gaan naar een derde rijstrook, wat tijd kan besparen en bijv. beeldinterpretatiefouten kan voorkomen. Per gedeelte van de snelweg kan het handig zijn om aan te geven hoe hard er gereden mag worden, bijvoorbeeld omdat aan een gedeelte van de snelweg gewerkt wordt. Dit wordt met Maximale-toegestane-snelheid aangegeven. Het is niet de bedoeling dat op een recht stuk snelweg vooraf bepaald wordt wat de maximale snelheid moet zijn. Dit omdat het system zelf in staat is om voor een bepaald moment en een stuk snelweg de optimale snelheid van het verkeer te bepalen. Auto‟s op het betreffende stukje snelweg zullen aan de hand van verkregen informatie over omringende auto‟s en eigen wensen de optimale snelheid bepalen. Met optimale snelheid wordt de snelheid bedoeld waarin het verkeer veilig verloopt, maar tegelijkertijd een goede verkeersdoorstroming realiseert bij een aanvaardbare belasting van het milieu. De optimale snelheid kan ongetwijfeld, onder bepaalde omstandigheden en voor specifieke auto‟s, ook boven 120 km/h liggen. Wil de overheid dat er met optimale snelheden gereden kan worden, dan zal de wetgeving moeten worden aangepast, zodat er geen maximale snelheid van 120 km/h geldt. De array ID-autos bevat de ID van auto‟s die zich op dat moment op de snelweg bevinden. Op een bepaald moment wordt de array ID-autos door het Snelwegproces geüpdate, en de array ID-autos bevat dan dus alle ID‟s van de auto‟s die zich op dat moment op de snelweg bevinden en zich bij het Snelwegproces hebben aangemeld. Dus als door Autoproces de array ID-autos ingelezen wordt dan staan er auto ID‟s in die zich op de snelweg bevinden en die door het Snelwegproces verwerkt zijn. Aangezien de update frequentie van het Snelwegproces hoog is t.o.v. de frequentie waarmee nieuwe auto‟s op de snelweg verschijnen, zullen bijna altijd alle auto‟s in de array voorkomen. Dit is alleen in het model nodig, omdat anders een auto er nooit achter kan komen welke auto‟s zich op een bepaald moment op de snelweg bevinden. In het echt is dat zeker niet
12
nodig: je verstuurt je eigen informatie (bijv. via WAVE) en in een straal van bijvoorbeeld 500 meter kan degene die dat wil je informatie uit de ether halen. Dus je komt er achter wie zich op de snelweg bevindt door de juiste informatie uit de ether te verzamelen (er wordt gekeken of het ontvangen bericht van een auto afkomstig is met snelweg ID die overeenkomt met de snelweg ID waarop de huidige auto zich bevindt). In het model daarentegen kan lang in de JS gezocht worden, maar het kan niet exact achterhaald worden welke auto‟s er zich allemaal op de snelweg bevinden, want elke auto kan een willekeurige ID gebruikt hebben. En zonder een ID en enige structuur in het JS van de Autodata is het onmogelijk om te achterhalen welke auto‟s zich op de snelweg bevinden: als er geprobeerd wordt om Autodata achter elkaar uit de JS te lezen (read) geeft dat geen garantie dat de verkregen Autodata alle Autodata zijn in JS. Dit omdat JS bij het lezen een willekeurige Autodata geeft, dus drie keer opvragen van Autodata kan drie keer dezelfde Autodata opleveren. Het is wel mogelijk om alle Autodata uit de JS te nemen (take) en ze vervolgens allemaal terug in JS te zetten (write), en dan is het wel mogelijk om te achterhalen welke auto‟s zich op de snelweg bevinden. Maar het probleem daarmee is dat tegelijkertijd andere auto‟s ook Autodata uit JS kunnen halen, dus dit geeft weer geen garantie dat alle Autodata uit JS opgehaald worden. Vandaar dat er in een datastructuur bijgehouden wordt welke auto‟s zich op de snelweg bevinden. Array Invoegstrook bevat per invoegstrook het aantal auto‟s dat zich op de betreffende snelwegsector willen invoegen. Deze waardes worden gebruikt bij het bepalen van optimale rijstrook (zie verder: Optimale rijstrook). De array bevat niet alleen invoegstrook data over de huidige sector, maar bevat ook informatie over de invoegstroken van de volgende twee Snelwegsectoren. Deze kunnen onderling tussen servers aangevraagd worden. Dus de server van een Snelwegsector zal bij de volgende Snelwegserver aflezen of er invoegstroken aanwezig zijn en hoeveel invoegende auto‟s er bij horen. Aflezen gebeurt door uitwisseling van directe berichten tussen de servers. Werking van het Snelwegproces Als eerste actie zal de snelweg zijn Snelwegdata in de JS zetten, zodat Autoprocessen er gebruik van kunnen maken (zie fig. 1a). Vervolgens zal Snelwegproces wachten totdat er een nieuwe auto op de snelweg komt rijden: in het model zal een Autoproces dat actief wordt een Autodata object in de JS zetten, zodat Autoproces in het Snelwegproces aangemeld wordt en de auto voor andere auto‟s zichtbaar zal zijn. Het Snelwegproces detecteert het nieuwe Autodata object en voegt het ID toe aan de array ID-autos, waarmee de auto is aangemeld bij het Snelwegproces. Regelmatig (eens per seconde) zal de Snelwegdata, die binnen het Snelwegproces wordt geüpdate, worden geschreven naar de JS. De regelmaat speelt een belangrijke rol, want als Autoproces oude Snelwegdata tot zijn beschikking heeft, dan kan het zijn dat Autoproces verkeerde beslissingen neemt omdat data niet meer klopt. Bijvoorbeeld als auto A een auto B aan het volgen is en auto B besluit om de snelweg te verlaten en dus ook eigen Autodata uit JS te verwijderen. Dan zou auto A vrijuit moeten kunnen rijden omdat de auto ervoor er niet meer is. Maar omdat het Snelwegproces de Snelwegdata in JS nog niet heeft geüpdate weet auto A niet dat auto B niet meer op de snelweg rijdt. Dus
13
verliest auto A tijd bij het zoeken naar de Autodata in JS die niet meer bestaat, en het zoeken in JS kost veel CPU tijd. Ook worden er minder nauwkeurige beslissingen genomen bij het bepalen van optimale snelheid en beste rijstrook, want er wordt geen rekening gehouden met de auto‟s die nog niet verwerkt zijn bij de Snelwegdata. Botsingen tussen auto‟s worden door Snelwegproces gedetecteerd. Dit wordt in de betreffende Autodata in de JS aangegeven. Autoproces handelt de gevolgen verder zelf af. Omdat er op een enkele pc gewerkt wordt (maar één CPU), kan het Snelwegproces ook niet te vaak de Snelwegdata in JS updaten. Het updaten van data kost veel tijd, dus kan er niet te vaak geüpdate worden. Indien het wel vaak gebeurt, dan bestaat er geen mogelijkheid om andere processen tijd te geven om hun werk te doen. De gekozen update frequentie van 1 Hz werkt in het model goed. Omdat er met de beschikbare hardware niet veel auto‟s gelijktijdig kunnen worden gemodelleerd kan dit resultaat echter niet eenvoudig geëxtrapoleerd worden naar andere omstandigheden met krachtiger computers of parallelle implementaties.
Autoproces Per auto wordt er informatie opgeslagen om deze aan andere auto‟s door te sturen en zelf gebruik van te maken. Deze informatie is opgeslagen in Eigendata (Autodata van de eigen auto). De Eigendata wordt periodiek (eens in 0,7 seconde: beperking van één CPU) aan iedereen verstuurd, dat wil zeggen op de JS gezet zodat andere Autoprocessen er gebruik van kunnen maken. In de werkelijkheid moet de frequentie van updaten van Eigendata tussen 4 en 10 Hz liggen. Voor de JS geldt een minimale update frequentie van 2 Hz (voor berekening zie Appendix: Periodieke update). Deze update zorgt ervoor dat auto‟s over bijna real-time informatie beschikken. Dit verkleint de kans op ongelukken en verbetert de kwaliteit van gemaakte beslissingen. In het model is er gekeken naar de frequentie waarin updaten van auto‟s mogelijk is, waarbij er rekening mee is gehouden dat een hoge frequentie van updates ten koste gaat van het aantal Autoprocessen dat aangemaakt kan worden. In het model ligt de nadruk niet op het realiseren van real-time gedrag, maar meer op het creëren van een zo groot mogelijk verkeer waardoor files gecreëerd worden en hiermee verschillende experimenten uitgevoerd kunnen worden. Verschil tussen de werkelijkheid en het model is dat in de werkelijkheid data via de ether wordt ontvangen en in het model de nodige Autodata zelf uitgelezen wordt uit de JS. In principe is het ontvangen van data uit de ether hetzelfde als uitlezen van data uit JS, want data in de ether moet je ook detecteren, dus ook als het ware uitlezen. Een andere mogelijkheid zou kunnen zij dat elk Autoproces eigen informatie direct naar andere auto‟s verstuurd, dus zonder tussenliggende JS. Hiervoor is niet gekozen om de volgende redenen: - Ten eerste zou dit niet met de werkelijkheid kloppen, want auto‟s versturen in het algemeen geen directe informatie naar elkaar, ze sturen ongeadresseerde data de ether in en degene die er gebruik van wil makken pakt de data uit de ether.
14
- Ten tweede is Autoproces niet op de hoogte welke Autoprocessen interesse hebben in de Eigendata van het Autoproces. Dus het Autoproces moet data naar alle andere Autoprocessen opsturen, terwijl elk Autoproces zelf weet welke informatie interessant is, en niet altijd data nodig heeft van alle andere. De volgende gegevens zijn opgeslagen in elke Auto; de verzameling gegevens die bij een Autoproces horen wordt Eigendata genoemd. Eigen Data - Auto-ID - Snelweg-ID - Strook-nummer. - Huidige-snelheid - Gewenste-snelheid - Acceleratie - Locatie - Status Auto ID Om auto‟s te onderscheiden heb je per auto een ID nummer nodig. In de werkelijkheid zou dit nummer bijv. gelijk kunnen zijn aan het kenteken van de auto. Om het model realistisch te maken, worden auto‟s onderscheiden aan de hand van de Auto ID en niet bijvoorbeeld aan de hand van de Proces ID. Snelweg ID In de werkelijkheid zal een auto ook berichten binnen krijgen van auto‟s die op een nabij gelegen (snel)weg rijden. Dit gebeurt omdat met WAVE verzonden informatie binnen een straal van 500 meter kan worden ontvangen. Dus het is volkomen normaal dat je Autodata zal ontvangen van auto‟s die op een andere snelweg rijden. Deze data is voor de betreffende auto niet van belang, dus het is ook de bedoeling dat de auto deze data negeert. Dit wordt gedaan door de Snelweg ID van de verkregen data te matchen met de Snelweg ID waarop de betreffende auto zich bevindt. Indien ze niet matchen dan kan de Autodata genegeerd worden. Daarnaast is het in het model van belang dat elk Autoproces op de hoogte is op welke snelweg het zich bevindt, zodat het via JS de Snelwegdata kan inlezen. Er kunnen verschillende Snelwegdata in de JS zijn, dus je hebt een identificatie nodig. Strook-nummer Een snelweg ID geeft aan op welke snelweg de auto zich bevindt en een Strook-nummer geeft aan op welke rijstrook. Dit is heel handig om te weten omdat dan elke auto niet zelf visueel hoeft waar te nemen waar de auto zich bevindt. Bovendien kan je heel simpel auto‟s op de snelweg classificeren in verschillende rijstroken. Auto‟s gebruiken vaak Autodata per rijstrook, bijvoorbeeld om de gemiddelde snelheid op de linker rijstrook te bepalen als onderdeel van het proces om van rijstrook te veranderen. Er zijn bijzondere gevallen zoals wanneer een auto van rijstrook wisselt: de auto is dan tegelijkertijd op twee verschillende rijstroken; in dat gevaal zal een auto aangeven dat hij
15
zich zowel op de linker als op de rechter rijstrook bevindt. Daar kunnen dan andere auto‟s rekening mee houden. In het model zal dit echter niet het geval zijn, vanwege de beperkte scope van het onderzoek. Indien in het model een auto van rijstrook wil veranderen, dan zal hij zich instantaan van de ene rijstrook naar de andere rijstrook verplaatsen. Huidige snelheid Met Huidige-snelheid wordt de snelheid van de betreffende auto aangegeven. Dus auto‟s hoeven niet meer de snelheid van de voorrijdende auto te bepalen, maar kunnen die gewoon aflezen. In het model wordt snelheid met m/s aangegeven. Gewenste snelheid De gewenste snelheid wordt door de eigenaar van de auto ingevoerd, dus niet door de bestuurder, want die zal er niet zijn: auto‟s zullen zich zelf besturen zoals bijv. VEPS (zie Appendix) van Mercedes-Benz het doet. Als gewenste snelheid zou de door het systeem te berekenen optimale snelheid genomen kunnen worden, maar het kan handig zijn om een waarde op te geven als je bijvoorbeeld met lading of een aanhangwagen aan het rijden bent, of gewoon als je rustig aan wilt doen of juist als je haast hebt. Op basis van de gegevens over de snelheid en de gewenste snelheid kan een Auto concluderen of andere auto‟s op een door hun gewenste snelheid rijden of langzamer. Indien Snelheid lager is dan de gewenste snelheid kan het er op duiden dat auto‟s zich in een file bevinden. Indien er geen Gewenste snelheid bijgehouden wordt is het moeilijker om na te gaan of de auto door eigen wens rustig rijdt of doordat hij zich in een file bevindt. Acceleratie De acceleratie kan heel erg nuttig zijn bij het bepalen van het gedrag van omringende auto‟s. Dus dit is een gegeven dat zeker verstuurd dient te worden naar andere auto‟s. Als bijvoorbeeld Autoproces in de Autodata afleest dat auto‟s vóór hem hard remmen, met andere woorden auto‟s die een hoge vertraging vertonen, dan kan de huidige auto bepalen hoe hij moet afremmen. Dus in plaats van snel afremmen kan de huidige auto wellicht op tijd langzaam afremmen. Daarnaast, als Auto op de hoogte is van de acceleratie van andere auto‟s, dan is het niet meer nodig om zelf in te schatten of uit te rekenen wat de acceleratie is, wat kostbare tijd om te reageren bespaart. In het model wordt de acceleratie met m/s² aangegeven. Locatie Met Snelweg ID wordt per auto aangegeven op welke snelweg de auto zich bevindt, en met Strook-nummer wordt aangegeven op welke rijstrook de auto zich bevindt en uiteindelijk is het de bedoeling dat de precieze locatie van de auto ook bekend wordt. In de werkelijkheid zal er gebruik gemaakt worden van GPS systemen die nauwkeurig de locatie kunnen aangeven. Dit is op het moment nog niet mogelijk vanwege onnauwkeurigheid van GPS systemen, maar de ontwikkeling staat niet stil en er wordt
16
van uitgegaan dat er GPS systemen op de markt zullen komen die wel een precieze locatie kunnen aangeven. In het model zal de locatie anders bepaald worden. Elke Autoproces zal door integratie van versnelling en snelheid van de auto zijn actuele positie op de snelweg bepalen. Locatie wordt zowel in het model als in werkelijkheid gebruikt om er achter te komen waar de Auto zich precies tussen andere auto‟s bevindt. Auto‟s kunnen op basis van Locatie gemakkelijk voor- of achter rijdende auto‟s vinden. In de werkelijkheid zal elke auto ook over radar, akoestische sensoren of infrarood technieken beschikken. Deze technieken zijn in staat om auto‟s om een auto heen waar te nemen. Met deze technieken wordt de veiligheid van de auto gegarandeerd. Dus als auto te dicht bij de voorste auto aankomt, zal er op gereageerd worden. Hoewel de auto over deze technieken beschikt is het toch handig om per auto de bijbehorende Locatie te weten. Dit omdat dan elke auto een globaal overzicht van alle auto‟s op de snelweg heeft. Waardoor je niet alleen overzicht hebt van omringende auto‟s maar ook van auto‟s ver verwijderd. Deze informatie kan handig zijn bij het bepalen van de beste rijstrook. Als een auto kan inzien dat rijstrook drie op een afstand tussen 100 en 200 meter van eigen Locatie leeg is, dan kan auto ervoor kiezen om op die strook te gaan rijden. Deze informatie zou je met andere technieken niet verkrijgen. Locatie in het model wordt met meters aangeduid. Locatie begint bij 0 meter en gaat door tot 1000 meter. Per snelwegsectie is er dus 0 tot 1000 meter mogelijk aan Locaties. Status Met status wordt per auto aangegeven of de auto stil staat, aan het rijden is of bij een botsing is betrokken. In het geval van een botsing, zal deze informatie ook verstuurd worden naar andere Auto‟s, die dan tijdig rekening kunnen houden met een ongeluk. De server langs de snelweg zal deze informatie ook krijgen en kan dus gelijk de hulpdienst inschakelen en het verkeer zo organiseren dat een onbelemmerde toegang tot de plaats van het ongeval ontstaat. Globale Data Alle auto‟s versturen berichten met hun gegevens via Wireless verbinding aan andere auto‟s. De gegevens die verstuurd worden zijn hierboven beschreven. Elke auto zal dus van verschillende auto‟s berichten ontvangen met data erin; data wordt gelijk gesorteerd op Snelweg ID en Strook-nummer. Data die afkomstig is van een andere snelweg, dus data met andere Snelweg ID dan de eigen snelweg wordt genegeerd. Gesorteerde Autodata wordt opgeslagen in de Globale-data Array‟s. In het model zijn er drie verschillende array‟s, namelijk Strook-1, Strook-2 en Strook-3. , deze zijn respectievelijk bedoeld voor meest rechter-, middelste- en linker rijstrook. In de echte wereld heb je natuurlijk meer of minder dan exact drie rijstroken, daarom zal de Globale-data in de echte auto flexibeler zijn: het zal array‟s toevoegen of verwijderen afhankelijk van het aantal rijstroken op de snelweg. Direct omringende auto’s In de Array D-auto‟s worden de gegevens van direct omringende auto‟s bijgehouden. Het gaat om de auto‟s die in de directe omgeving rijden. Auto‟s die een afstand hebben tot de huidige auto van meer dan 300 meter worden niet als direct omringende auto
17
beschouwd. Direct communiceren met auto‟s die verderweg rijden dan 300 meter heeft geen zin, omdat die auto‟s geen directe relatie hebben met de huidige auto; ‟deze beperking beperkt de belasting van het afhandelen van directe berichten waaraan een hoge prioriteit wordt gegeven. De direct omringende auto’s zijn: V-auto - auto voor A-auto - auto achter RV-auto - auto rechts voor RA-auto - auto rechts achter LV-auto - auto links voor LA-auto - auto links achter Op het moment dat een auto een bericht binnen krijgt van een andere auto, wordt als eerst eigen Snelweg ID vergeleken met de Snelweg ID van binnen gekomen bericht. Indien Snelweg ID‟s matchen, wordt het bericht opgeslagen in de bij Strooknummer behorende Array. Tijdens het updaten van Globale-data wordt ook D-auto array geüpdate. In het model worden frequent updates gedaan, waarbij de frequentie weer afhangt van de performance van het systeem. In het model wordt er gewacht tot alle gegevens, dus de Autodata van verschillende Autoprocessen geüpdate worden in de Globale-data, en dan pas wordt de nieuwe D-auto‟s bepaald. In de echte auto zal ook om een bepaalde tijd de D-auto‟s geüpdate moeten worden, bijvoorbeeld om een kwart seconde en wordt aan de hand van de binnen gekomen Autodata de nieuwe D-auto‟s bepaald.
Communicatie queue Auto‟s versturen berichten met algemene Data over zichzelf naar andere auto‟s. Maar naast deze berichten worden ook andere berichten verstuurd. Deze berichten zijn bedoeld om direct met bepaalde auto‟s te communiceren. Deze communicatie berichten worden na ontvangst in een queue opgeslagen, de zo geheten Communicatie-queue. Een auto zou bijv. een communicatie bericht kunnen opsturen naar de auto die zich er naast bevind, indien de auto zich gedwongen van linker rijstrook naar rechter rijstrook moet verplaatsen. De auto op de rechterstrook krijgt het communicatie bericht binnen en slaat het op in de Communicatie-queue op. Het binnengekomen bericht zal door de auto op de rechter rijstrook met hoge prioriteit behandeld worden. De auto op de rechter rijstrook zal plaats moeten maken voor de auto op de linker rijstrook, omdat de auto op linker rijstrook gedwongen is om zich te verplaatsen naar de rechter rijstrook. Op het moment dat auto‟s detecteren dat het op de snelweg druk begint te worden, en er dus een dreiging is tot het ontstaan van een file, worden de volgende twee methodes toegepast totdat de file, of het filegevaar, voorbij is.
18
Methode beste strook Elke auto zal een rijstrook bepalen waarop de auto gaat rijden, niet om een voordeel te behalen voor de betreffende auto, maar wel voor een betere doorstroming van het hele verkeer. Auto‟s verdelen zichzelf gelijkmatig over de hele snelweg zodat de snelweg optimaal benut wordt, en ze classificeren zich op Gewenste-snelheid zodat het verkeer per rijstrook met gelijkwaardige snelheden het beste verloopt. Tijdens het inlezen van alle Autodata door het Autoproces, wordt de Rang van betreffende auto bepaald. Tijdens het inscannen worden alleen Autodata gelezen van auto‟s die in dezelfde snelweg sector rijden. Dit geeft dus gelijk aan dat een Auto in staat moet zijn om alle auto‟s in een sector te kunnen bereiken. Dus het bereik van 500 meter door WAVE is niet voldoende omdat sectors 1000 meter lang zijn. Dus moet ervoor gezorgd dat in de werkelijkheid sectoren kleiner worden of dat er betere WAVE ontvangers gemaakt worden met een groter bereik. Het nadeel van deze ontwerpkeuze is dat de voorste auto‟s in een sector niet vooruit kijken, want de keuze voor de beste rijstrook wordt alleen gemaakt aan de hand van de auto‟s die in de betreffende sector rijden. Een andere ontwerpkeuze zou kunnen zijn dat auto‟s beslissingen nemen voor het bepalen van de beste rijstrook aan de hand van hun bereik, maar in dat geval kunnen er niet-consistente beslissingen genomen worden omdat niet alle auto‟s gegevens krijgen van dezelfde auto‟s en dus bij hetzelfde algoritme verschillende resultaten kunnen hebben. Dit probleem is op te lossen door auto‟s bij elkaar in de buurt de geplande acties te laten communiceren en deze gegevens ook in het algoritme te betrekken. De complexiteit van het algoritme neemt daardoor sterk toe en kon binnen het kader van deze scriptie niet worden onderzocht. Hoe hoger de Gewenste-snelheid des te hoger de Rang. Dus hiermee Classificeer je auto‟s die snel willen rijden of het vermogen hebben om snel te kunnen rijden tegenover langzaam rijdende auto‟s. In het geval van gelijke Gewenste-snelheden wordt gekeken naar Snelheid, Acceleratie en uiteindelijk als deze twee onderdelen van auto‟s gelijk zijn, dan zal de hoogste Id. de hogere Rang geven aan een auto. Wat nog veel belangrijker is in de werkelijkheid en niet geïmplementeerd is in het model door de beperkte scope van het onderzoek zijn de invoeg en uitvoeg stroken. Tijdens het bepalen van de Rang moet zeker gekeken worden naar de bestemming van de auto. Als een auto op het punt staat om de uitrijstrook te nemen, dan zal de rang van de auto lager worden, zodat een auto met lage Rang, die helemaal rechts komt te rijden, gemakkelijk kan uitvoegen. Auto‟s die aan het invoegen zijn hebben nog geen rang; op het moment dat ze op de snelweg komen rijden, bepaalt de auto haar eigen Rang. De verdeling van de Rang gaat als volgt: het totale aantal auto‟s worden gelijkwaardig verdeelt over alle rijstroken. Per rijstrok wordt dus berekend hoeveel auto‟s erop moeten rijden. De verdeling gebeurt aan de hand van de Rang: alle auto‟s hebben zelfde informatie over andere auto‟s, dus dezelfde Autodata en ze gebruiken ook hetzelfde algoritme om de Rang uit te rekenen. Dus moet de verdeling van alle auto‟s over de verschillende rijstroken in de verschillende auto‟s met elkaar overeenkomen. Auto‟s met kleine Rang kiezen de meest rechtse rijstrook en auto‟s met hoge Rang kiezen de meest linkse rijstrook en auto‟s tussenin zullen de middelste rijstroken kiezen.
19
In de werkelijkheid zijn er nog invoeg stoken die een belangrijke rol spelen bij het verdelen van auto‟s per rijstroken. Als er een invoegstrook aanwezig is wordt ingescand hoeveel auto‟s zich willen invoegen, deze informatie is via de server af te lezen. Aan de hand van deze informatie wordt bepaald hoe veel auto‟s op de meest rechtse rijstrook moeten rijden. Op de meest rechtse rijstrook moeten minder auto‟s rijden dan op alle andere rijstroken omdat er auto‟s op deze strook moeten invoegen. Dus als eerste wordt bepaald wat het maximale aantal auto‟s op de rechter rijstrook kan zijn, en dan pas worden de overige auto‟s verdeeld over de andere rijstroken. Zonder verdere maatregelen zou dit toch tot een onvoldoende gebruik van de meest rechtse rijstrook leiden. Daarom wordt tijdens het bepalen van de beste rijstrook 1 á 2 Snelwegsectoren verder gekeken of er invoegstroken aanwezig zijn. Dit zorgt ervoor dat het verkeer van te voren voorbereid wordt op eventueel invoegende auto‟s. Indien er een invoegstrook aanwezig is, dan zal er capaciteit op de rechtse rijstrook vrijgehouden worden, als er geen invoegstroken zijn dan wordt het verkeer gelijkmatig over alle rijstroken verdeeld.
Methode optimale snelheid Optimale snelheid is een snelheid die bepaald wordt bij het bereiken van kritieke punt, d.w.z. op het moment dat 70% van de snelweg capaciteit benut word, waarbij de capaciteit het maximale aantal auto‟s per snelwegsector zonder dat er files ontstaan aangeeft. Deze optimale snelheid wordt dus bepaald voordat er een file ontstaat, waarbij wordt geprobeerd om zo vlot mogelijk door het drukke verkeer heen te rijden, daarbij rekening houdend met het langzaam rijdend verkeer. Het bepalen van de optimale snelheid gebeurt als volgt: per rijstrook wordt er in een snelwegsector een colonne gevormd met een Gids (her proces van colonne vorming en bepalen van de Gids wordt verder uitgelegd, zie: Implementatie: Methode optimaleSnelheid). De Gids bepaald de optimale snelheid aan de hand van ervoor rijdende auto en de verst verwijderde Gids die nog te bereiken is. De auto‟s die de Gids volgen zullen dezelfde snelheid aanhouden als die van de Gids. Op het moment dat een auto in een colonne waarneemt dat hij te dicht bij de auto voor hem rijdt, zal de snelheid aangepast worden om aan veiligheidseisen te voldoen. De Gids zelf bepaald zijn snelheid aan de hand van de Gids die rijdt in de volgende sector binnen zijn bereik van 500 meter valt, waarbij hij ook rekening houdt met de auto die voor hem rijdt (tussen de Gids en de staart van de voorste colonne). Indien er geen colonne vóór rijdt, dus ook geen Gids, dan moet de huidige Gids zelf de optimale snelheid bepalen, wat overeenkomt met de snelheid bij vrij rijden. Voor het geval dat de Gids niet bereikt wordt door een auto in de colonne door de beperking van WAVE (bereik van 500 meter) is een oplossing gegeven in de sectie Implementatie: Methode optimaleSnelheid. In het geval dat er geen auto‟s tussen beide colonnes in rijden zal de achterste Gids de voor rijdende colonne proberen in te halen om zo één colonne te vormen. Als er wel auto‟s tussen rijden dan zal de snelheid aangepast worden aan de ervoor rijdende auto, zodat er een gelijdelijke aansluiting volgt met de ervoor rijdende auto. Mocht vóór de Gids een auto rijden (de Gids volgt als het ware voorste auto), dan zal de Gids zijn taak overdragen aan de auto ervoor. M.a.w. een colonne zal altijd proberen aan de voorkant te groeien, hetzij met individuele auto‟s, hetzij met een voorliggende colonne.
20
De voornaamste taak van een Gids is dus te proberen om een voorliggende colonne in te halen mits het veilig verloopt. Met deze idee wordt ervoor gezorg dat auto‟s verder in het verkeer kijken om hun snelheid te bepalen dan alleen maar naar de voorliggende auto te kijken en die blindelings te volgen. Zo worden er beslissingen genomen aan de hand van het globale verkeer. Bovendien hoeft niet elke auto te bepalen wat de optimale snelheid is, maar alleen de Gids, de overige auto‟s lezen gewoon de snelheid van de Gids af. Dus de taak die tijd vergt om de optimale snelheid te bepalen wordt niet door alle auto‟s gedaan, maar alleen door een aantal auto‟s. Voor de meest rechtse rijstrook moet ook rekening gehouden worden met het invoegende verkeer. Elke invoegende auto maakt een snelheid die gelijk is aan de Gids op de meest rechtse rijstrook. Op het moment dat deze snelheid bereikt is wordt er een Direct bericht verstuurd naar de auto op de meest rechtse rijstrook die qua locatie achter de huidige auto rijdt. Dit bericht zorgt ervoor dat de achterste auto op de rechter rijstrook plaats maakt voor de invoegende auto, dus die auto zal een grotere afstand tot zijn voorligeer creëren zodat invoegen mogelijk wordt. In dit geval zal het voorste gedeelte van de colonne met constante snelheid doorrijden, maar het achterste gedeelte past haar snelheid tijdelijk aan om zo invoegen mogelijk te maken. Vervolgens zal de colonne weer herenigd worden, dus zal de hele colonne weer met dezelfde snelheid rijden. Tijdens uitvoegen zal de ruimte die ontstaan is door uitvoegende auto verkleind worden doordat het achterste gedeelte van de colonne probeert de ruimte te verkleinen tot de standaard afstaan tussen twee rijdende auto‟s in een colonne.
Uitvoering Dit is een onderdeel dat ervoor zorgt dat de auto daadwerkelijk aan het rijden is, en is dus verantwoordelijk voor het uitvoeren van de taken die door het management onderdeel opgedragen worden. Er bestaat al een auto die zonder een bestuurder kan rijden: de VEMP van Mercedes-Benz (zie Appendix: VEMP). In het model zal elke auto vrijuit rijden of een andere auto volgen. Vrijuit rijden wil zeggen dat er geen auto‟s vóór rijden, of auto‟s zijn ver weg, en dus zal de auto streven naar de gewenste snelheid. Indien er wel een auto vóór rijdt, dan wordt er een algoritme toegepast om deze auto te volgen. Ook zal elke auto kunnen inhalen op het moment dat op de huidige strook de gewenste snelheid niet gehaald kan worden maar wel op de linker strook.
Management Dit onderdeel coördineert al het werk dat gedaan moet worden tijdens het rijden van een auto. Het management systeem zorgt ervoor dat de communicatie berichten afgehandeld worden. Dus ook het nemen van beslissingen aan de hand van de communicatie berichten die verkregen worden van andere auto‟s. De uit te voeren taken worden doorgegeven aan het onderdeel uitvoering, dat er voor zorgt dat de taken daadwerkelijk uitgevoerd worden. Tijdens het nemen van besluiten maakt het management systeem gebruik van D-auto
21
Array, Globale Data, Eigen Data en de Snelweg Data. De twee belangrijkste Methodes die Management onderdeel tot haar beschikking heeft zijn “Methode Optimale Snelheid” en “Methode Beste Strook”. Het management onderdeel verstuurt communicatie berichten naar andere auto‟s indien het wil communiceren met andere auto‟s. Ook wordt de Eigen Data periodiek door het Management onderdeel verstuurd naar andere auto‟s en de op dat moment bereikbare server.
22
Implementatie Het model bevat drie verschillende soorten processen: Snelweg proces, Scherm proces en een aantal Auto processen. Snelweg proces zorgt ervoor dat Snelweg gecreëerd wordt. Auto processen kunnen zich vanaf dat moment aanmelden bij Snelweg proces en aflezen welke auto‟s zich nog meer op de snelweg bevinden. Snelweg proces update eigen Snelwegdata in de JS door alle nieuwe auto‟s op de snelweg toe te voegen. Vervolgens worden AutoData van alle auto‟s uitgelezen uit de JS om te achterhalen of er botsingen zijn begaan. Indien er een botsing begaan is, dan wordt de status van betreffende auto in de Autodata veranderd en weer in de JS gezet. Auto proces zal bij het lezen van Eigendata uit de JS merken dat het een botsing heeft begaan en zal de botsing verder afhandelen. Deze taken worden continue in een while loop uitgevoerd met een Sleep statement van 2000 ms. Er zijn ook andere waardes gebruikt voor het Sleep statement, maar 2000 ms is net voldoende om op tijd een update uit te voeren, en waardes die kleiner dan 2000 ms zijn veroorzaken te veel gebruik van CPU waardoor er minder Autoprocessen aangemaakt kunnen worden. Een acceptabele frequentie voor het systeem in de werkelijkheid zou 1 Hz kunnen zijn. De auto‟s in het echte systeem zijn minder afhankelijk van de Snelwegdata; het is belangrijk dat een auto over informatie over de sector beschikt zodra hij zich op de snelwegsector begeeft, maar verder is de Snelwegdata niet zo belangrijk als in het model, want in het model worden alle bijgekomen en verdwijnende auto‟s van de betreffende sector in de Snelwegdata bijgehouden, terwijl in de werkelijkheid auto‟s direct vernemen dat er zich auto‟s op de snelweg hebben begeven. Het Scherm proces zorgt ervoor dat de rijdende auto‟s te zien zijn op een scherm. Dit proces leest alle Autodata uit de JS en plaatst de auto‟s op de betreffende locaties op de snelweg op het scherm. Auto‟s worden van verschillende kleuren voorzien en indien er een botsing begaan is blijven ze vanzelf op hun plaats staan omdat locatie in Autodata niet meer verandert. In een Autoproces wordt Snelwegdata, Eigendata en Globaledata bewaard. Deze centrale data wordt gebruikt door twee threads die elk Autoproces bevat. In fig. 3 is te zien welke onderdelen door welke threads beheerd worden. Autoproces controleert elke keer of er een botsing is gedetecteerd door het Snelwegproces, en in dat geval wordt auto stil gezet. Ook wordt bijgehouden of de bestemming bereikt is: als 1000 meter bereikt wordt, dan zal Autoproces de rit opnieuw beginnen door de auto op de nulde meter te zetten, mits er zich geen auto‟s op die plaats en rijstrook bevinden. Als er zich wel auto‟s op de rijstrook bevinden, dan wordt er naar de volgende rijstrook gekeken, en dit wordt herhaald tot er een vrij plaats gevonden wordt op een van de rijstroken. Autoproces is ook in staat om de auto helemaal uit de JS te verwijderen en zichzelf te beëindigen.
23
Fig. 3 Autoproces verdeeld in twee Threads (Updatedata en Rijden). De dikke pijlen worden als datastromen gezien De dunne lijnen tussen de methodes, uitvoer onderdeel en management onderdeel worden gezien als Proces afhankelijkheden
Eerste thread in het Autoproces is de Updatedata thread, die wordt gebruik om data uit de JS te lezen en te updaten in de centrale opslag ruimte bij Autoproces. Uit de JS wordt Snelwegdata en alle Autodata die aanwezig zijn gelezen. Eigendata van het Autoproces wordt ook door Updatedata in de JS gezet en oude Eigendata wordt er uit gehaald. Directe berichten die in JS zitten en bedoeld zijn voor de huidige auto worden er door
24
Update data uitgehaald en in de Direct-berichten-array (Communicatie queue) in het Autoproces opgeslagen Nadat de Updatedata thread zijn taak in een while loop heeft uitgevoerd wordt thread tot slaap gebracht voor 500 ms. en vervolgens worden de taken in de while loop verder uitgevoerd, zoals aangegeven in onderstaande pseudo-code: While(true) { If(eerste keer){JS.write(Eigendata)} Else { //update Eigendata JS.write(nieuwe Eigendata) JS.take(oude Eigendata) //update Snelwegdata Snelwegdata = JS.read(Snelwegdata) //update Globaledata While(Autodata != NULL) { JS.read(Autodata) Globaledata.add(Autodata) } //update directe berichten While(Bericht != NULL) { JS.read(Bericht) CommunicatieQueue.add(Autodata) } //even niets doen Sleep(500) } }
Tweede thread wordt Rijden genoemd. Deze thread zorgt ervoor dat de auto over de snelweg kan bewegen. In het geval dat er geen files zijn en Direct communiceren met auto‟s niet plaats vindt, is het volgens onderstaande schema te zien hoe thread rijden zich gedraagt.
25
Fig. 1 Procesverloop van Thread Rijden (standaard situatie)
In het verkeer zullen alle auto‟s nog gebruik maken van onderlinge communicatie door met elkaar direct berichten uit te wisselen. In het model heb ik drie scenario‟s gebruikt waarbij direct berichten verstuurd worden. In de werkelijkheid zijn veel meer scenario‟s te bedenken waar direct uitwisselen van berichten nuttig kan zijn. De drie scenario‟s zijn: - Scenario I : achteropkomend verkeer niet belemmeren - Scenario II : gedwongen invoegen - Scenario III : ruimte maken voor de hulpdienst auto Uitgebreide uitleg over deze drie Scenario‟s wordt verderop in de tekst gegeven (zie: Implementatie: Methode berichtAfhandelen ). Om files te vorkomen en ze te bestrijden worden nog twee methodes gebruikt. De eerste methode, de Bestestrook, wordt gebruik om optimaal gebruik te maken van de snelweg, door alle auto‟s gelijkmatig te verdelen over aanwezige rijstroken. In het model zijn er drie rijstroken geïmplementeerd. De tweede methode, de Optimalesnelheid, wordt gebruikt om per rijstrook te bepalen wat de optimale snelheid is, waarbij rekening wordt gehouden met her verkeer dat zich een aantal auto‟s voor de huidige auto afspeelt. Auto‟s vormen een colonne met een Gids, en de Gids zal de optimale snelheid bepalen terwijl auto‟s in de colonne de Gids volgen, dus rijden met dezelfde snelheid als de Gids.
26
Zodra de autodichtheid op de snelweg een kritieke grens bereikt, worden de twee hierboven genoemde methodes toegepast. De kritieke toestand wordt bepaald aan de hand van de capaciteit van de snelweg en het aantal auto‟s dat zich op de snelweg bevindt. Hieronder in het schema is te zien hoe Thread Rijden zich gedraagt met deze twee methodes en directe communicatie mogelijkheden.
Fig. 2 Procesverloop van Thread Rijden (met uitbreiding van direct berichten, Optimale-snelheid en Beste-strook)
Nader uitleg methodes: Autoproces Methode kijkBotsing() Het Snelweg proces detecteert een botsing en verandert de Status en de Kleur (de voorste auto geel, de achterste rood) in de Autodata en zet deze weer terug in de JS. Als Autoproces deze Eigendata ophaalt om het te updaten, wordt eerst met de kijkBotsing methode nagekeken of de Status door het Snelwegproces veranderd is. In het geval dat de Status veranderd is naar toestand botsing, zal deze methode ervoor zorgen dat de snelheid en de versnelling van de auto op 0 gezet worden en dat methode stopAuto wordt aangeroepen die de threads en het Autoproces zelf beëindigt.
27
Methode kijkBestemming() Deze methode, die regelmatig aangeroepen wordt door het management onderdeel, controleert of de bestemming, dus de 1000 meter, door Autoproces bereikt is. Als bestemming bereikt is dan wordt thread Rijden door deze methode stop gezet. Vervolgens probeert de methode om auto weer in het begin van de snelweg te zetten, mits er zich geen auto‟s op de betreffende rijstrook en locatie bevinden. Als rijstrook bezet is, dan wordt er naar een andere rijstrook gekeken tot er een rijstrook gevonden wordt waarop zich de eerste 15 meter geen auto‟s bevinden. Nadat er een rijstrook gevonden is en de Eigendata aangepast is, zal er gewacht worden tot dat thread Updatedata alle data geüpdate heeft uit JS en dan pas wordt thread Rijden weer gestart zodat de auto zich kan verplaatsen naar de nieuwe bestemming met nieuwe gegevens over de snelweg en daarop rijdende auto‟s.
Thread Updatedata Methode updateDirectBerichten() Deze methode wordt toegepast om berichten uit JS te lezen die bedoeld zijn voor de huidige auto. Dit wordt gedaan door de Ontvanger-id te matchen aan eigen Id. Berichten worden gelijk opgeslagen in de berichten array die zich in het Autoproces bevindt. Methode updateAutoData() Indien de Autodata nog niet in de JS zit, dan wordt deze in JS gezet. Als er al een Autodata in de JS zit, dan wordt er eerst een nieuwe versie in de JS gezet, en daarna wordt de oude Autodata uit JS gehaald. Door met verschillende versies te werken wordt ervoor gezorgd dat Autodata zich altijd in JS bevindt. Want als deze methode eerst de oude Autodata uit JS zou halen en dan pas de nieuwe in JS zetten, dan zou in de tussentijd geen Autodata in JS aanwezig zijn, en dus zou in die periode de betreffende auto voor andere auto‟s niet zichtbaar zijn. Methode updateSnelwegData() Deze methode zorgt ervoor dat de Snelwegdata uit JS gelezen wordt; daarmee weten auto‟s welke andere auto‟s zich op de snelweg bevinden. Methode updateGB() Deze methode leest alle Autodata die zich in de JS bevinden. Autodata wordt gezocht gebruik makend van de id. waardes uit de array IdAutos, die is opgeslagen in de Snelwegdata. Autodata wordt verdeeld in rijstroken: elke rijstrook heeft een array waar deze Autodata terecht komen. Alle Autodata behalve eigen Autodata wordt in de Globaledata array opgeslagen.
28
Thread Rijden Methode ruimte() Indien een auto een van de volgende acties wil uitvoeren: inhalen, rechts rijden, uitvoegen of invoegen, dan moet de auto weten tussen welke twee auto‟s het moet gebeuren. Deze methode retourneert een array met Autodata van deze twee auto‟s mits ze bestaan; als één of beide van de auto‟s niet bestaan, dan wordt in de geretourneerde array voor betreffende Autodata de locatie op negatieve waarde (in het model -9) gezet, zodat de andere methodes die van deze methode gebruik maken weten dat één van de auto‟s of beide niet bestaan. Aan de hand van de gegevens van deze twee auto‟s wordt vervolgens bepaald of de actie veilig uitgevoerd kan worden. Methode inhalen() Deze methode wordt aangeroepen op het moment dat auto een andere auto wil inhalen. Deze methode zal beslissen of inhalen mogelijk is, en indien het mogelijk is wordt de inhaalmanoeuvre uitgevoerd en de nieuwe gegevens van Eigendata worden in de centrale opslagruimte in Autoproces opgeslagen, zodat thread Updatedata het ook in de JS kan updaten. De beslissing of inhalen mogelijk is, is afhankelijk van de ruimte tussen de auto‟s die verkregen zijn uit methode Ruimte (zie boven). De beslissing wordt als volgt genomen: indien auto n tussen auto a en b wil invoegen omdat hij de voorliggende auto wil inhalen (zie fig. 5), dan heeft auto n met twee minimale afstanden Gbn en Gna te maken. Waarbij Gbn de afstand is tussen de achterste auto (b) en de achterkant van auto n en Gna is afstand tussen de voorkant van auto n en de voorste auto (a). Inhalen is alleen mogelijk als Gbn en Gna groter zijn dan de minimale waardes voor Gbn en Gna.
Fig. 5 Minimale invoegruimte [a]
De minimale waardes voor Gbn en Gna voor verschillende snelheden worden als volgt berekend: Gbn = maximum ( MinimumGbn, MinimumGbn + βb1 * Vb + βb2 * (Vb-Vn) ) Gna = maximum ( MinimumGna, MinimumGna + βa1 * Vn + βa2 * (Vn-Va) ) Waarbij Va, Vb, Vn de snelheiden zijn voor respectievelijk auto a, b en n. De MinimumGbn en MinimumGna geven de minimale afstand van respectievelijk Gbn en Gna onafhankelijk van de snelheid. De parameters zijn hieronder in de tabel te vinden (Tab. 1).
29
Parameters MinimumGbn MinimumGna βa1 βa2 βb1 Βb2
waarde 5,0 3,0 0,05 0,15 0,15 0,40
Tab. 1 Parameters voor invoegruimte [a]
Methode rechtsRijden() Deze methode bepaalt of rechts rijden mogelijk is en indien het mogelijk is wordt rechts rijden uitgevoerd en de Eigendata in het Autoproces wordt bijgewerkt. Het bepalen of één rijstrook naar rechts mogelijk is wordt bepaald net als in de methode Inhalen (zie hierboven). Aan de hand van twee AutoData die verkregen zijn uit methode Ruimte, wordt er bepaald of de tussenliggende afstand voldoende is om er tussen in te mogen rijden. Als het tussenliggende ruimte voldoende is wordt de actie door deze methode uitgevoerd. Methode updateAutoVoor() Deze methode zoekt in de betreffende rijstrook Autodata van een auto die zich net voor de huidige locatie bevindt. Indien er geen Auto gevonden wordt dan zal AutoVoor een NULL zijn. Methode updateInhaalAuto() Als er een auto ingehaald wordt, dan wordt er niet rechts gereden totdat de auto die ingehaald wordt (InhaalAuto) ingehaald is. Voordat er geprobeerd wordt om weer rechts te rijden wordt eerst deze methode toegepast om te achterhalen of InhaalAuto ingehaald is, of mogelijk InhaalAuto op een andere rijstrook is gaan rijden; in deze gevallen wordt InhaalAuto gelijk aan NULL, dus kan er weer rechts gereden worden. In alle andere gevallen zal er niet rechts gereden worden. Methode volgAutoVoor() Als management onderdeel probeert te rijden, wordt eerst gezocht naar Autovoor; als deze er niet is wordt er vrij gereden, dus met optimale snelheid en acceleratie. Als er wel een Autovoor is en inhalen niet mogelijk is, dan is de auto verplicht om de Autovoor te gaan volgen. In dat geval wordt deze methode toegepast, en de nieuwe acceleratie wordt dus als volgt berekend: Auto n is auto n-1 aan het volgen. Waarbij gn de afstand is tussen beide auto‟s. Vn en Vn-1 zijn de snelheden respectievelijk van achterste(n) en voorste(n-1) auto (zie fig.6).
30
Fig. 6 Bron [a]
Om de acceleratie a van de achterste auto(n) te berekenen zijn de volgende formules gebruikt.[a] Voor Vn ≤ Vn-1
Voor Vn > Vn-1
Experimenteel vastgestelde parameters , en die in de hierboven beschreven formules gebruikt worden zijn gegeven in tab. 2.[a]
Versnelling Vn ≤ Vn-1 Vertraging Vn > Vn-1
α (Alfa)
β (Bèta)
γ (Gamma)
2,15
-1,67
-0,89
1,55
1,08
1,65
Tab. 2 parameters voor acceleratie formule[a] De drie kolommen geven respectievelijk de, en waarde die gebruikt worden in de hierboven genoemde acceleratie formule
Naast het bepalen van de acceleratie en de snelheid wordt in deze methode ook de afgelegde afstand berekend aan de hand van de oude acceleratie en de verstreken tijd sinds het vorige tijdstip van locatie update. De formule die gebruikt wordt om de afgelegde afstand uit te rekenen ziet als volgt uit: Afgelegde afstand = ½ * acceleratie * (delta tijd)² + oude_snelheid * delta_tijd Snelheid = oude_snelheid + acceleratie * delta_tijd
31
Methode vrijRijden() Bij het vrij rijden wordt de al eerder besproken optimale snelheid gebruikt, waarbij in het model voor de snelheidsverandering de maximale versnelling gebruikt wordt. Deze methode bepaalt de maximale versnelling bij verschillende snelheden. De versnelling wordt bepaald om de nieuwe snelheid van de auto vast te stellen. Ook wordt de nieuwe locatie in deze methode vastgesteld. De maximale versnelling die een auto kan hebben wordt gegeven in de onderstaande tabel (tab.3). In de praktijk zijn er natuurlijk verschillende auto‟s met eigen maximale versnelling. De gegevens in de onderstaande tabel gelden alleen voor auto‟s die in het model gebruikt worden (lengte: 10 meter). Deze maximale acceleraties zullen in de werkelijkheid niet gebruikt worden: er wordt een optimale acceleratie gebruikt die beter omgaat met brandstof zodat het milieu minder belast wordt.
Snelheid m/s < 6,0 Versnelling 2,1 m/s²
6,0 – 12,0 1,5
12,0 – 18,0 1,2
18,0 – 24,0 0,5
≥ 24,0 0,3
Tab 3. Maximale versnelling [a]
Methode berichtAfhandelen() Elke keer dat er een update door thread Update uitgevoerd wordt, wordt ook gekeken of er directe berichten zijn die voor de betreffende auto bedoeld zijn. Indien dat zo is worden de berichten uit JS gehaald en vervolgens wordt deze methode toegepast om de berichten af te handelen. Voor elke bericht type is stap voor stap beschreven wat er gedaan moet worden. In het model zijn er 3 scenario‟s waarbij direct berichten verstuurd worden. Voor deze drie scenario‟s zijn aparte bericht type gebruikt. Scenario I Stel auto A rijdt met een snelheid van 10 m/s op een snelweg waar maar één rijstrook vrij is. Dus Auto A is niet in staat om rechts of links te rijden. Een andere auto, de auto B rijdt achter auto A, met een snelheid van 30 m/s. Auto B kan auto A niet inhalen en auto A kan niet rechts rijden om auto B voorbij te laten gaan. Dus auto B is gedwongen om snelheid te verminderen en achter auto A te blijven rijden. In deze situatie zal auto B een bericht versturen naar Auto A, met een verzoek om voorbij te rijden. Auto A zal alles doen om rechts te gaan rijden, maar omdat dat vanwege het verkeer niet lukt en auto B er dan nog steeds niet langs kan, zal auto A zijn eigen Gewenste snelheid verhogen en daarmee dus ook zijn eigen Snelheid, mits het verkeer vóór auto A dat toelaat, totdat auto B er tenslotte toch langs is. Auto B zal auto A passeren op het moment dat hetzij auto A naar rechts kan, hetzij een rijstrook links van auto A beschikbaar komt en auto B door tijdelijk harder te gaan rijden dan zijn eigen Gewenste snelheid auto A kan passeren. Op het moment dat auto B gepasseerd is zal auto A zijn Gewenste snelheid weer tot oude waarde terug brengen.
32
Scenario II Scenario twee wordt toegepast indien auto A gedwongen is om rechts of links van rijstrook te veranderen. Gedwongen veranderen van rijstrook kan voorkomen doordat een auto aan het invoegen is; de invoegstrook heeft een beperkte lengte, dus moet de auto gedwongen invoegen. Als er aan de weg gewerkt wordt zijn soms auto‟s ook genoodzaakt om van rijstrook te veranderen door een wegversmalling. Er zijn ook zonder werkzaamheden versmallingen van snelwegen, in dat gevaal is er ook sprake van gedwongen invoegen. In een van deze situaties zal Auto A een direct bericht sturen naar auto B die qua Locatie vlak achter auto A rijdt en zich bevindt op de rijstrook waar naar toe auto A zich gedwongen moet verplaatsen. Zodra auto B dit bericht ontvangen heeft, zal hij snelheid verminderen om ervoor te zorgen dat de afstand tussen de auto er voor en de eigen voorkant zo groot wordt dat auto A ertussen past. Dus er wordt naar eigen Snelheid en de Lengte van auto A gekeken om een juiste afstand te creëren tot de Autovoor. Scenario III Als er een ongeluk plaats gevonden heeft, dan is het belangrijk dat hulpdiensten snel ter plaatse aanwezig kunnen zijn. Hoe sneller de hulpdienst er bij is des te effectiever is de hulp en des te sneller kan de snelweg vrij gemaakt worden voor het verkeer. Alle auto‟s met sirene hebben de mogelijkheid om berichten te sturen naar de ervoor rijdende auto‟s. Auto‟s die deze “sirene”-berichten ontvangen zullen plaats maken voor de auto met loeiende sirene. De sirene-berichten worden naar auto‟s verstuurd die binnen een afstand van 300 meter rijden. Voor maximaal effect kan door de auto met sirene in samenspraak met de server aan de wegkant worden bepaald over welke rijstrook, dan wel rijstroken, de plaats van het ongeval het snelst kan worden bereikt. Door een combinatie van rijstrookafsluiting door de server en gerichte berichten aan auto‟s op relevante rijstroken wordt zo een vrije baan voor de hulpdienst gecreëerd. MethodeBerichtVersturen() Deze methode maakt het mogelijk om directe berichten te versturen naar andere auto‟s, dus berichten in JS te zetten. De methode zorgt ervoor dat de velden van het bericht goed ingevuld worden. Methode besteStrook() Deze methode zal toegepast worden om alle auto‟s gelijkmatig te verdelen over de beschikbare rijstroken. Voor de betreffende auto zal aan de hand van Gewenste snelheid de Rang van de auto bepaald worden (classificatie in het model is beperkt tot Gewenste snelheid en bij gelijke snelheden wordt de hoogste auto Id als hoogste Rang gebruikt). Ook wordt er geteld hoeveel auto‟s zich op de snelweg bevinden. Aan de hand van deze informatie zal elke auto consistente beslissing maken bij de keuze van een rijstrook. De beslissing wordt tot stand gebracht door het volgende algoritme te gebruiken:
33
Rang=1 aantaAutos = 0 besteRijstrook = this.auto.strookNr //er zijn drie rijstroken maxRijstrook1 = 0 maxRijstrook2 = 0 maxRijstrook3 = 0
//lees alle Autodata uit JS While(Autodata != NULL) { autoX = JS.read(AutoData) aantalAutos ++ If(autoX.snelheid < this.auto.snelheid) { Rang ++ } If(autoX.snelheid == this.auto.snelheid) { If(autoX.id < this.auto.id) { Rang ++ } } } //bepaal auto verdeling over rijstroken If ((aantalAutos % 3) != 0) {maxRijstrook1 = (aantalAutos / 3) + 1} Else { maxRijstrook1= aantalAutos / 3} If ((aantalAutos % 3) == 2) {maxRijstrook2 = (aantalAutos / 3) + 1} Else { maxRijstrook2 = aantalAutos / 3} maxRijstrook3 = aantalAutos / 3 //bepaal de besteRijstrook If(rang <= maxRijstrook1){ besteRijstrook =1} Else { If(rang <= (maxRijstrook1 + maxRijstrook2)){ besteRijstrook = 2} Else{ besteRijstrook = 3} }
Methode optimaleSnelheid() Als eerste wordt de capaciteit van de snelweg berekend (dit gebeurt in het management onderdeel); dit geeft bij verschillende snelheden aan hoeveel auto‟s er op de betreffende snelwegsector passen met een tussenliggende afstand van 2 seconde: door de gemiddelde snelheid per snelwegsector te bepalen kan elke auto uitrekenen hoeveel meter één auto in beslag neemt, deze is gelijk aan: (snelheid * 2 seconde) + lengte van de auto. Als de ruimte per auto uitgerekend wordt, dan kan ook uitgerekend worden hoeveel auto‟s op de snelwegsector op dat moment maximaal kunnen rijden (capaciteit), want de lengte van een snelwegsector en het aantal rijstroken zijn bekend.
34
Dus capaciteit = aantal rijstroken * (sectorlengte / benodigde ruimte per auto). Op het moment dat 70% van de capaciteit bereikt is wordt deze methode toegepast om de optimale snelheid te bepalen. Alle auto‟s zulle op hetzelfde moment deze methode gebruiken, en ze zullen in eerste instantie allemaal een Gids worden. Elke Gids zal binnen zijn bereik de ervoor rijdende auto en de verst verwijderde Gids opzoeken. Op het moment dat de huidige auto de er voor rijdende auto ingehaald heeft (huidige auto rijdt dan precies 2 seconde achter de ervoor rijdende auto), wordt de huidige auto onderdeel van de colonne en is geen Gids meer. Vanaf dat moment volgt de auto de dichtstbijzijnde, voor hem rijdende, Gids (de Gids van de colonne). Het volgen van een Gids betekent dat de auto met dezelfde snelheid rijdt als de Gids. De Gids probeert geleidelijk de voor hem rijdende colonne in te halen en zal uiteindelijk met dezelfde snelheid als de voorste Gids achter de colonne aansluiten. Mochten er binnen 500 meter tussen de huidige Gids en de staart van de met WAVE bereikbare Gids andere colonnes of individuele auto‟s (dat zijn ook Gidsen) zijn, dan zal de huidige Gids deze zien als de ervoor rijdende auto, en dus zal er als eerst geleidelijk aansluiting plaats vinden met deze auto, maar tegelijkertijd wordt er wel verder in het verkeer gekeken voor het bepalen van de optimale snelheid. Mocht er geen Gids aanwezig zijn in 500 meter, dan betekent het ook dat de rijstrook ten minste 500 meter vrij is, dus hoeft er ook tijdelijk geen rekening gehouden te worden met druk verkeer. Het doel van de Gids is aansluiting te zoeken met de voorste colonne, wat betekent dat er colonnes kunnen ontstaan die langer dan 500 meter zijn, waarbij de achterste auto‟s in de colonne de Gids niet meer kunnen bereiken (bereik van WAVE is 500 meter) en dus kunnen ze hem ook niet meer volgen. Om dit te voorkomen moeten de snelwegsectoren, die ongeveer 1000 meter lang zijn, virtueel in twee gelijke delen gesplitst worden, zodat er per z‟n sector gedeelte van max. 500 meter per colonne één Gids aanwezig is. Dus alle auto‟s in de colonne in een bepaald sector gedeelte, kunnen altijd een Gids bereiken, en dus kunnen alle auto‟s in dat sectorgedeelte een Gids volgen. In het geval van de lange colonnes wordt het stokje steeds overgedragen aan de laatste auto die zich in het betreffende sector gedeelte bevindt. Dus elke auto in een colonne controleert of hij zich op de rand van een sector gedeelte bevindt, en indien dat zo is, wordt de auto onmiddellijk een Gids; op het moment dat de Gids niet de laatste auto in een sector gedeelte is, wordt de Gids weer een gewoon onderdeel van de colonne, omdat de auto de voorliegende auto aan het volgen is. Fig. 4 geeft een globaal overzicht over colonnes en Gidsen. Zo stelt fig. 4.1 een snelweg met twee sectoren voor, die weer virtueel verdeeld zijn in de sector gedeeltes. De optimale snelheid methode wordt nog niet toegepast omdat het kritieke punt nog niet bereikt is. Maar er is wel te zien dat er auto‟s elkaar aan het volgen zijn (fig. 4.1 d). Op het moment dat het kritieke punt bereikt wordt, zullen alle auto‟s Gidsen worden. Fig. 4.2 geeft aan welke auto‟s vervolgens Gidsen blijven en welke auto‟s zich realiseren dat ze een Gids volgen, dus onderdeel zijn van een colonne en de Gids moeten volgen. Alle individuele auto‟s zijn Gidsen omdat ze niemand volgen. In fig. 4.3 wordt geïllustreerd dat de colonne meerdere Gidsen heeft, deze omdat er per colonne in elke virtuele sector één Gids aanwezig moet zijn, om zo de bereikbaarheid van een Gids voor alle auto‟s in de colonne te garanderen.
35
Fig. 4 Globaal overzicht Gids/Colonne
Het algoritme voor het bepalen van Gids ziet er in grote lijnen als volgt uit: If(afstand tot voorliggende auto == 2 sec) // als de auto aan het volgen is { If(de auto rijdt als laatste in de sector gedeelte) { auto.gids = true //(snelheid van de dichtstbijzijnde gids) auto.snelheid = Dgids.snelheid } Else { auto.gids = false auto.snelheid = Dgids.snelheid //(snelheid van de dichtstbijzijnde gids) } } Else // afstand tot voorligger > 2 sec en is dus niet aan het volgen { auto.gids = true auto.snelheid = bepalen aan de hand van ervoor rijdende auto en de verst mogelijke Gids }
Tijdens drukte of file wordt de methode optimale Snelheid toegepast. Deze methode bepaalt of de betreffende auto een Gids moet zijn of de colonne moet volgen.
36
Als op de snelweg sector en de rijstrook waarop de auto zich bevindt geen auto‟s ervoor rijden of ze rijden verder weg dan 300 meter, dan is de betreffende auto een Gids. De betreffende Gids zal de ervoor rijdende auto (dat is een Gids indien het een individuele auto is, of de laatste auto van een colonne) en de verste qua locatie met WAVE bereikbare Gids op dezelfde rijstrook opzoeken en aan de hand daarvan de optimale snelheid en acceleratie bepalen. Indien er geen Gids vóór rijdt zal er naar gestreefd worden om met de gewenste snelheid te gaan rijden. De gids zal ook altijd streven om de ervoor rijdende colonne in te halen, zodat het één colonne wordt. Als een auto geen Gids is, dan moet hij de colonne volgen, of deze inhalen. Indien de colonne gevolgd wordt, dan zal de betreffende auto de snelheid van de Gids aanhouden en ervoor zorgen dat er een veilige afstand tussen de auto en die ervoor wordt gehouden. Methode rijden() Deze methode is de samenstelling van de eerder beschreven onderdelen Management en Uitvoering. In deze methode worden alle andere methodes toegepast om ervoor te zorgen dat een auto zich van 0 naar 1000 meter kan verplaatsen. Tijdens het rijden worden alle bovengenoemde methodes toegepast. De structuur van deze methode is te zien in fig. 2 (proces verloop van thread Rijden). Zo is in het schema te zien dat er onderscheid gemaakt wordt tussen druk en rustig verkeer. Indien de capaciteit van een snelweg bereikt wordt, dan zullen de methodes beste strook en optimale snelheid toegepast worden (omdat er in de simulatie geen files gecreëerd kunnen worden is de capaciteit al bereikt bij 6 auto‟s op een rijstrook (zie: Resultaten en verder onderzoek)). Voordat de capaciteit bereikt wordt zal de methode de auto besturen zoals een mens het ook doet, dus zoveel mogelijk rechts rijden, inhalen om vrij te rijden en als er niet ingehaald kan worden wordt de auto ervoor gevolgd. Het grote verschil met een menselijke bestuurder zit in de hoeveelheid informatie die de automaat ter beschikking heeft voor het optimaal gebruik van de weg, en in de betere en vooral ook snellere reactie op manoeuvres van andere auto‟s.
37
Resultaten en verder onderzoek Het implementeren van een model dat zo veel mogelijk op de werkelijkheid moest lijken was bedoeld om met functionele onderdelen te experimenteren die een filevoorkomende werking hebben. Het is gedeeltelijk gelukt om een model te bouwen waarin geëxperimenteerd kan worden. Zo is er een snelwegsector gecreëerd waarin de auto‟s kunnen rijden, inhalen, rechts rijden, volgen en vrijuit rijden (zie fig. 6). Botsingen worden gedetecteerd en de auto‟s worden tot stilstand gebracht. M.a.w. het is gelukt om een auto te laten besturen aan de hand van informatie uitwisseling.
Fig. 6 Geïmplementeerde scherm met rijdende auto’s
Waarin het systeem tekortschiet, is het creëren van druk verkeer: het is niet mogelijk om meer dan 10 auto‟s te creëren vanwege de enorme overhead van JS. Zo blijkt uit metingen dat alleen een update (het lezen en verwijderen uit, en het schrijven naar JS) van de eigen Autodata voor 10 auto‟s al 1 seconde duurt, terwijl voor een goede besluitvorming de Autodata van alle auto‟s nodig is. De enkele CPU kan dus zeker niet een update uitvoeren binnen een seconde, wat een redelijke update frequentie is. Hierdoor is met de onderdelen beste strook en optimale snelheid veel minder geëxperimenteerd dan gewenst is. Desondanks is er geprobeerd om een complete beschrijving te geven hoe deze onderdelen in het echt zouden moeten functioneren. In de onderstaande tab. 4 zijn enige metingen te zien die zijn uitgevoerd om de testen hoe snel lezen, schrijven en uitpakken van Autodata uit JS duurt. Actie Autodata schrijven naar JS (write) Autodata uitlezen uit JS (read) Autodata pakken uit JS (take)
Tijd (100 keer) 2,6
Gem. tijd (1 keer) 0,03
4,9
0,05
7,4
0,07
Tab. 4 Test resultaten voor JS acties (tijd in secondes)
Als er zich op de snelweg 10 auto‟s zouden bevinden dan zou een auto bij elke update het volgende moeten doen: 1 keer Eigendata updaten (kosten: 1 keer write en 1 keer take), 9 keer Autodata uitlezen (kosten: 9 keer read) en 1 Snelwegdata uitlezen (kosten: 1 keer read). De totale kosten per update per auto zijn dan: 1 x write (0,03) + 1 x take (0,07) + 10 x read (0,05) = 0,6 seconde
38
Er zijn in totaal 10 auto‟s die deze kosten hebben waar nog een Snelwegproces en Schermproces bij komen. Aan dit rekenvoorbeeld is te zien waarom één CPU niet veel auto‟s kan creëren. In een volgende stap in het project zouden de auto‟s verspreid kunnen worden over een aantal CPU‟s als oplossing voor het probleem van het creëren van voldoende druk verkeer om files te laten ontstaan. Deze stap kon in dit project niet meer worden gezet. Er is echter wel een andere methode geprobeerd om enige weerstand te bieden aan het verkeer dat zich op de snelweg bevindt: er zijn stilstaande auto‟s op de snelweg toegevoegd (zie fig. 7). De stilstaande auto‟s maken geen gebruik van JS, maar zorgen er wel voor dat de snelwegsector wat drukker wordt.
Fig. 7 Snelwegsector met stilstaande auto’s (lange rechthoeken) als obstakels voor overig verkeer
Beschouwing over specifieke aspecten van het systeem: Autodata Zoals eerder beschreven wordt tijdens het updaten van de Autodata gebruik gemaakt van twee versies van de data, om er voor te zorgen dat er altijd een kopie van de betreffende Autodata aanwezig is in de JS. In een eerdere implementatie kwam het wel eens voor dat de ervoor rijdende auto niet meer in de JS bestond, en de huidige auto dus meende vrijuit te kunnen rijden. Als de auto vervolgens detecteerde dat er wèl een auto voor hem reed, doordat de update van de Autodata van die auto volledig was uitgevoerd en de betreffende data dus weer in JS zat, was het te laat, en was de betreffende auto al gebotst op de ervoor rijdende auto. Na de introductie van de twee versies is het aantal botsingen afgenomen. Auto volgen In het model wordt gebruik gemaakt van de snelheid van de ervoor rijdende auto om de acceleratie van de betreffende auto te bepalen, er wordt dus helemaal niet naar de acceleratie gekeken van de ervoor rijdende auto. Dit zou eigenlijk wel moeten gebeuren, omdat aan hand van de acceleratie beter te zien is wat het gedrag van de auto in nabije tijd zal zijn, dus kan er ook sneller erop gereageerd worden.
Inhalen De methode die ervoor zorgt dat de ervoor rijdende auto ingehaald wordt, werkte in eerste instantie niet zo goed: in sommige gevallen werd er een poging gedaan om de auto in te halen, en vervolgens werd het afgelast, omdat er geen in te halen auto werd vastgesteld. Na verbetering van het vaststellen dat er een auto is om in te halen werkte
39
inhalen altijd goed; het inhalen werd volgens verwachting beëindigd op het moment dat de auto ingehaald was of op en andere rijstrook was gaan rijden. Dit probleem en de oplossing ervoor werd pas gevonden tijdens de experimenten. Methode optimale snelheid Omdat er geen druk verkeer gecreëerd kon worden is er heel weinig geëxperimenteerd met deze methode. Tijdens één van de experimenten werd slechts één rijstrook gebruikt waarbij de voorste auto de Gids van betreffende rijstrook werd. Alle andere auto‟s detecteerden deze Gids en pasten hun Gewenste snelheid aan aan de Gewenste snelheid van de Gids en verandereden hun Kleur. Hieruit blijkt dat het in colonne rijden in principe werkt. De beperkingen van de gebruikte computer lieten helaas niet toe te experimenteren met de interactie tussen de methodes optimale snelheid en beste rijstrook. Ook is geen onderzoek gedaan naar de invloed van de volgorde van aanroepen van de verschillende methodes op het gedrag van het gesimuleerde verkeer. Het is mogelijk deze methode verder uit te bouwen. De methode die in het ontwerp beschreven is maakt gebruik van informatie van de ervoor rijdende auto en van de nog te bereiken Gids en aan de hand daarvan wordt de optimale snelheid berekend. De methode houdt dus totaal geen rekening met de wensen van de auto‟s in de colonne en zou bij het bepalen van de optimale snelheid bijvoorbeeld ook kunnen kijken naar de gewenste snelheid van de auto‟s in de colonne. Directe berichten Ook zijn er experimenten uitgevoerd met het direct uitwisselen van berichten, in het bijzonder voor scenario I (achteropkomend verkeer niet belemmeren) en in mindere maten voor scenario II (gedwongen invoegen). Zo werd er tijdens experimenteren met scenario I voor gezorgd dat auto‟s één verzoekbericht versturen en dan de tijd geven aan de ervoor rijdende auto om de actie uit te voeren. Ondanks de beperkingen van het geringe aantal auto‟s dat gesimuleerd kon worden, kan toch worden gesteld dat deze berichten een gunstige uitwerking lijken te hebben op de doorstroming. Voor scenario II werden twee auto‟s gebruikt waarvan één van de auto‟s een stilstaande auto aantreft, dus hierdoor gedwongen van rijstrook moest veranderen. De experimenten lukten niet altijd en verliepen moeizaam, omdat het niet makkelijk is om twee rijdende auto‟s te creëren die ongeveer op dezelfde tijd bij het opstakel aan kwamen rijden. Een nog niet opgelost probleem doet zich voor wanneer conflicterende berichten naar een auto worden gestuurd waardoor de auto niet in staat is om de standaard handelingen die bij een scenario horen uit te voeren. Als bijvoorbeeld zowel de auto van links als die van recht een bericht naar de middelste auto sturen met het verzoek om gedwongen in te voegen, dan moet de middelste auto ruimte maken voor één van de auto‟s en de andere auto waarschuwen dat het invoegen niet mogelijk is. Dit is niet opgenomen in de standaard handelingen die bij het scenario II horen. Nieuwe Ideeën tijdens het experimenteren Tijdens het schrijven van code en uitvoeren van experimenten zijn er wat ideeën ontstaan waar aanvankelijke niet aan gedacht was. Zo werd het bijvoorbeeld duidelijk dat door
40
groeperen van de auto‟s per rijstrook of per snelweg sector met één en dezelfde algoritme kan gezorgd worden dat auto‟s consistente beslissingen maken. Waardoor de uit te voeren acties van de auto‟s niet van te voren met elkaar afgestemd hoeven te worden. Dit zorgt natuurlijk voor tijdwinst. Ook werd het steeds duidelijker hoe belangrijk het is om informatie van andere auto‟s in het bezit te hebben. Menselijke zintuigen kunnen lang niet concurreren met het verkrijgen van informatie zoals het in dit systeem gebeurt. Ook andere technieken zoals radar en infrarood hebben veel minder informatie tot hun beschikking dat bij een systeem waarbij wireless informatie uitwisseling tot de mogelijkheden behoort. Met de verkregen informatie, die bijna real-time en nauwkeurig is, kunnen er technieken toegepast worden die het gedrag van een auto of zelfs van een gedeelte van het verkeer kunnen voorspellen waardoor er tijdig preventief matregelen genomen kunnen worden. Meerdere computers voor het model Indien er gebruik gemaakt zou worden van meerdere computers, waarbij de auto‟s verdeeld zouden worden over een aantal computers en een aparte computer wordt toegewezen aan het snelwegproces, zou het model meer auto‟s kunnen laten rijden. Het systeem zou dan wel iets aangepast moeten worden om de JS via een netwerk bereikbaar te laten zijn. Hoewel de verbinding met JS via een netwerk wellicht iets trager zal verlopen, kan, door voor de JS instantie te kiezen voor een krachtige computer, de tijd nodig voor updates toch aanzienlijk verkort worden, waardoor er veel meer auto‟s zouden kunnen rijden. Nadere studie van het specifieke gebruik van JS zal wellicht inzicht geven in de mogelijkheid de toegang tot JS te verdelen over meerdere processoren en zo significant meer snelheid te winnen. Uitbreiding van het werkelijke systeem Het systeem in de werkelijkheid zou veel uitgebreider kunnen zijn dan het hier beschreven is. Bijvoorbeeld als het bereik van WAVE van 500 meter niet voldoende blijkt te zijn kan er gekozen worden om informatie door te geven met de tussenliggende auto‟s, of gebruik te maken van servers die berichten kunnen uitwisselen van de ene server naar de andere om zo toch de auto‟s kunnen bereiken verder dan 500 meter. Ook moeten er security onderdelen toegevoegd worden aan het systeem: sauzende beveiliging zou iemand een virtuele vrachtwagen midden op de snelweg stil kunnen zetten door langs de weg met WAVE apparaten berichten uit te zenden. Dit zou bijvoorbeeld opgelost kunnen worden doordat server de identiteit van de auto‟s controleert met encryptie technieken.
41
Conclusie Het ontwerp dat gemaakt is tijdens dit onderzoek laat zien dat het uitwisselen van informatie tussen auto‟s onderling en tussen de auto‟s en de server langs de snelweg een manier is om het verkeer gedistribueerd te regelen. Uit het onderzoek kwamen echter geen harde bewijzen dat deze aanpak een filebestrijdende werking heeft; hiervoor zijn betere testomgevingen vereist. Mede als gevolg van de beperkingen van de beschikbare apparatuur, blijft het een hypothese dat auto‟s beter door een automaat bestuurd kunnen worden en onderling wireless kunnen communiceren voor het maken van consistente en snellere beslissingen die ertoe leiden dat het gehele verkeer er baat bij heeft. In het ontwerp zijn een aantal onderdelen zoals “beste rijstrook” en “optimale snelheid” aan het licht gebracht die een poging doen om files te voorkomen. Naar mate er meer geëxperimenteerd werd met het model, werd het steeds duidelijker hoe veel voordeel er valt te halen met het uitwisselen van informatie. Hopelijk worden er in de toekomst meer en uitgebreidere onderzoeken gedaan naar dit soort systemen.
Referenties [a] Q. Yang, „A Simulation Laboratory for Evaluation of Dynamic Traffic Management Systems‟, Massachusetts Institute of Technology(1993) [b] E. Freeman, S. Hupfer, K. Arnold, „JavaSpaces™ Principles, Patterns, and Practice‟, Addison Wesley (1999), ISBN: 0-201-30955-6 [c] Dr. L. Allison, Dr. R. Pose, „A smarter computer controlled model car‟, Bachelor of Digital Systems (Honours), Clayton Campus (2002) [d] I. Berger, „Standards for car talk‟, (2007) [e] W. Xiang, P. Richardson and J. Guo, „Introduction and Preliminary Experimental Results of Wireless Access for Vehicular Environments (WAVE) Systems‟, University of Michigan, Dearborn (2006) [f] N. Carriero, „Linda in context‟, Yale University, New Haven (1989)
42
Appendix Wireless Access in Vehicular Environments (WAVE) Deze wireless verbinding is voor DOT (US Department of Transportation) ontworpen en voldoet aan IEEE 802.11p standaard. WAVE kan beschouwd worden als een uitbreiding van wireless local area networks (WLAN), van indoor omgeving naar automobiele omgeving. De Wireless verbinding is speciaal ontworpen voor de communicatie tussen auto‟s en auto‟s met infrastructuur langs de snelwegen. Het WAVE protocol gebruikt frequenties in het gebied 5.850-5.925GHz . Door advanced orthogonal frequency-division multiplexing (OFDM) technieken te gebruiken is WAVE in staat om data verkeer van 6-27Mbs/s te halen. De overdracht latency wordt geminimaliseerd door gebruikt te maken van een Mesh netwerk. Bereik van WAVE is ongeveer een straal van 500 meter.[d] [e] VEMP Door Mercedes-Benz ontwikkelde auto VEMP is in staat om zichzelf op de juiste snelheid te brengen en de auto te besturen. De auto doet ongeveer wat een bestuurder doet, waarbij VEMP gebruikt maakt van onder andere radar technologie. De auto is in staat om verkeerstekens te lezen en zich aan te passen aan de hand van het omringende verkeer. De meeste algoritmes die gebuikt worden voor bijvoorbeeld “gedrag van voetgangers” te bepalen en “manoeuvres voor het ontwijken van obstakels” zijn heel erg duur. Het system is in staat om in real-time te werken met drie 200Mhz PC‟s. VEMP is op dit moment de meest geavanceerde zelfbesturende auto. [c] JavaSpace (JS) Door Sun ontwikkelde JS is gebaseerd op de Linda taal [f] en maakt gebruikt van Jini services. JS maakt het mogelijk om objecten tussen processen uit te wisselen. Dit gebeurt in een gezamenlijke opslagruimte. Elke Proces is in staat om een JS te creëren en vervolgens objecten uit de JS te lezen (read), er objecten uit te halen (take) en objecten in JS te zetten (write). Meerdere processen hebben toegang tot verschillende JS. Een proces kan ook verschillende JS creëren. Objecten die zich in de JS bevinden moeten Public zijn en niet primitieve types zoals int of double waardes hebben om lezen mogelijk te maken. Voor waardes als int en double wordt Classes Integer en Double gebruikt. [b] Matchen van Objecten Als er in de JS een Object gezocht wordt met een bepaalde ID waarde, dan ziet het zoekproces er als volgt uit: als eerste wordt er een template aangemaakt van dezelfde soort Object met interne variabelen die naar NULL verwijzen. Alleen de interne variabele ID wordt aangepast met de ID waarde die gezocht wordt. Deze template Object wordt vervolgens in de JS gezet en wordt vergeleken met andere Objecten. Het eerste Object dat overeenkomt met Object type van het template en waarvan de interne niet NULL variabelen ook overeenkomen, zal uit JS gelezen worden. Het gelezen Object is het zoekresultaat. Dus om een Object in JS te vinden met een bepaalde ID waarde, moet de ID waarde matchen met de ID waarde van het Object in JS.
43
Periodieke update Elke auto zal in het systeem een Autodata bericht versturen met behulp van WAVE. Dit bericht zal vijf integer en vijf double waardes bevatten. De grootte van een bericht is dus: 5 integers + 5 doubles = 5 * 32 bits + 5 * 64 bits = 480 bits. Bericht grootte en overhead zullen samen rond 700 bits zijn. De snelheid van een WAVE ontvanger is 6-27Mbs/s[c], dwz minimaal 6291456 bits/s. Dus WAVE is in staat ten minste 6291456 / 700 = 8987 berichten per seconde te ontvangen. Het aantal auto‟s dat een WAVE ontvanger op een snelweg zou moeten verwerken wordt als volgt berekend: Tijdens een file neemt een auto ongeveer 5 meter aan ruimte. Uitgaande van 3 rijstroken en een bereik van 500 meter van WAVE kan je uitrekenen hoeveel auto‟s op de snelweg bevinden dat door de WAVE ontvanger kan bereikt worden: Aantal auto‟s = ((2* bereik)/ ruimte per auto ) * aantal rijstroken = (2*500)/5) * 3 = 600 auto‟s. Het maximale aantal updates per seconde wordt als volgt berekend: Voor een update is het nodig van alle auto‟s in het bereik van WAVE een bericht te ontvangen. Maximaal kan dus, bij volle snelweg, 8987 / 600 = 14 keer per seconde een update worden uitgevoerd. Rekening houdend met enige overhead, betekent dit dat het in principe mogelijk is om per 0,1 seconde een update uit te voeren. Er wordt van uitgegaan dat een update tussen 0,1 en 0,25 seconde uitgevoerd wordt. Voor de veiligheid van het rijden, moet een update binnen 0,5 seconde gebeuren. Dit is als volgt beredeneerd: We gaan uit van 2 seconde als minimale afstand tussen auto‟s, ongeacht de snelheid. Het is algemeen bekend dat 20 % van de bestuurders een reactietijd van 0,2 seconde hebben en 80% van bestuurders een reactie tijd van 0,8 seconde en de tijd tussen indrukken en werking van de rem bedraagt 0,2 seconde, dus wordt er in het algemeen beschouwd dat 1 seconde verloren gaat aan de traagheid van de menselijke reactie. Indien een automat de besturing overneemt, dan heeft de auto een voorsprong van 1 seconde (de computer heeft geen reactie verlies), en de andere seconde wordt gebruikt om de auto tot stilstand te brengen. Dus er moet binnen een seconde minstens een update gedaan worden en een besluit genomen worden om te handelen. Als er minimaal 2 keer per seconde geüpdate wordt, dus een update per ten hoogste 0,5 seconde, dan blijft er nog 0,5 seconde over voor het nemen van een besluit. Gezien de complexiteit van de algoritmes lijkt dit zeker haalbaar.
44
Onderzoek voorstel Titel: Gedistribueerd verkeersmanagement Omschrijving: De verkeerssituatie in Nederland dreigt op korte termijn onmogelijk te worden door de snelle toename van het verkeer t.o.v. de uitbreiding van het wegennet. Er zijn een paar mogelijke oplossingen voor dit probleem: 1. autorijden erg duur maken (de benadering van de overheid) 2. meer wegen aanleggen, maar dat verplaatst het probleem, want het verkeer zal dan nog altijd belemmeringen ondervinden bij de overgang van doorgaande snelweg naar stedelijk gebied 3. adaptieve regeling van de verkeersstromen en van de auto's daarbinnen. Deze opdracht beoogt de 3e oplossing te onderzoeken door een systeem te ontwerpen waarin elke auto autonoom beslist hoe zich te gedragen op basis van gegevens die door communicatie van in de buurt rijdende auto's wordt verkregen. Door gebruik te maken van de resultaten uit het onderzoek naar "gossiping" kan langs die weg een beeld worden gekregen van de globale verkeerssituatie. In aanvulling hierop kan er worden gedacht aan een of meer servers die additionele informatie kunnen verzorgen en eventueel gegevens kunnen opslaan voor off-line evaluatie en studie. De te nemen stappen in het project zijn de volgende: 0. nadere uitwerking van de scope van het project 1. literatuurstudie 2. globaal systeemontwerp 3. implementatie 4. simulatie 5. evaluatie Voor de simulatie zal gezocht worden naar mogelijkheden bestaande simulatieomgevingen te gebruiken zodat het accent ligt op het ontwerp en implementatie van het nieuwe systeem. Begeleider: Maarten Boasson
45
Code Autodata public class AutoData implements Entry{ public Integer id, snelwegId, strookNr; public Double snelheid, snelheidGewenst, versnelling, locatie; public String kleur; public Integer status; // 0= staat stil; 1= rijdt; 5= botsing public Double lengte; public Integer versie; public Integer gids; /** Creates a new instance of AutoData */ public AutoData() {} public AutoData(int id, int snelwegId, int strookNr, double snelheid, double snelheidGewenst, double versnelling, double locatie, String kleur,int status, double lengte,int gids) { this.id=new Integer(id); this.snelwegId=new Integer(snelwegId); this.strookNr=new Integer(strookNr); this.snelheid=new Double(snelheid); this.snelheidGewenst=new Double(snelheidGewenst); this.versnelling=new Double(versnelling); this.locatie=new Double(locatie); this.kleur=new String(kleur); this.status=new Integer(status); this.lengte=new Double(lengte); this.versie=new Integer(1); this.gids=new Integer(gids); } //getter public Integer getId(){return this.id;} public Integer getSnelwegId(){return this.snelwegId;} public Integer getStrookNr(){return this.strookNr;} public Double getSnelheid(){return this.snelheid;} public Double getSnelheidGewenst(){return this.snelheidGewenst;} public Double getVersnelling(){return this.versnelling;} public Double getLocatie(){return this.locatie;} public String getKleur(){return this.kleur;} public Integer getStatus(){return this.status;} public Double getLengte(){return this.lengte;} public Integer getVersie(){return this.versie;} //setter public void setId(Integer id){this.id=id;} public void setSnelwegId(Integer snelwegId){this.snelwegId=snelwegId;} public void setStrookNr(Integer strookNr){this.strookNr=strookNr;} public void setSnelheid(Double snelheid){this.snelheid=snelheid;} public void setSnelheidGewenst(Double snelheidGewenst){this.snelheidGewenst=snelheidGewenst;} public void setVersnelling(Double versnelling){this.versnelling=versnelling;} public void setLocatie(Double locatie){this.locatie=locatie;} public void setKleur(String kleur){this.kleur=kleur;} public void setStatus(Integer status){this.status=status;} public void setLengte(Double lengte){this.lengte=lengte;} public void setVersie(Integer versie){this.versie=versie;} public String toString() { String st ="AutoData: " + "[ " + this.id
46
+ " : " + this.snelwegId + " : " + this.strookNr + " : " + this.snelheid + " : " + this.snelheidGewenst + " : " + this.versnelling + " : " + this.locatie + " : " + this.kleur + " : " + this.status + " ]"; return st; } }
Autoproces public class Auto { private JavaSpace space; private AutoData eigenData; private SnelwegData snelwegData; private GlobaleData gbData; private UpdateData update; private Rijden rijden; private Vector directeBerichten; /** Creates a new instance of Auto */ public Auto() {} //constructor public Auto(AutoData eigenData,JavaSpace space) { this.eigenData=eigenData; this.space=space; this.snelwegData=null; this.gbData=null; this.directeBerichten=new Vector(); } //getter public JavaSpace getSpace(){return this.space;} public UpdateData getUpdate(){return this.update;} public Bericht getBericht() { if(this.directeBerichten!=null) { if(this.directeBerichten.isEmpty()){return null;} else { Bericht br = (Bericht)this.directeBerichten.firstElement(); this.directeBerichten.removeElementAt(0); return br; } } else{return null;} } //setter public void setBericht(Bericht br){this.directeBerichten.add(br);} //synchronized getter-setter public synchronized AutoData getsetEigenData(AutoData autoData) { //set if(autoData==null){return this.eigenData;} //get else{this.eigenData=autoData; return null;} } public synchronized SnelwegData getsetSnelwegData(SnelwegData snelwegData) { //set if(snelwegData==null){return this.snelwegData;}
47
//get else{this.snelwegData=snelwegData; return null;} } public synchronized GlobaleData getsetGbData(GlobaleData gbData) { //set if(gbData==null){return this.gbData;} //get else{this.gbData=gbData; return null;} } public void start() { System.out.println("Auto->start()"); //Thread aanmaken voor updaten van gbData, snelwegData en eigenData update = new UpdateData(this); update.start(); //doe niets tot gbData, eigenData of snelwegData gevuld is door update Thread while(this.gbData==null || this.gbData.getGereed()==0 || this.eigenData==null || this.snelwegData==null){nietsDoen(50);} int strook=-1; //kijk of je een vrije strook kan vinden StartPlaats stPlaats = new StartPlaats(); //synchroniseren door take en write van stPlaats uit de space takeFromSpace(stPlaats); while(strook==-1) { strook = this.gbData.startPlaats(this.eigenData); } writeToSpace(stPlaats); if(this.eigenData.strookNr.intValue()!=strook) { //verander strook indien nodig this.eigenData.setStrookNr(new Integer(strook)); this.getsetGbData(null).setGereed(0); //doe niets voor dat gbData voor de nieuwe strook geupdate is while(this.gbData.getGereed()==0){nietsDoen(50);} } //Thread aanmaken voor het rijden van auto rijden = new Rijden(this); rijden.start(); //en maar door rijden while(true) { //kijk of er botsing is begaan kijkBotsing(); //kijk of de bestemming bereikt is kijkBestemming(); nietsDoen(500); } } public void kijkBotsing() { System.out.println("Auto->kijkBotsing()"); if(this.eigenData.status.intValue()==5) { //fictieve botsing //this.eigenData.setKleur("green"); this.eigenData.setSnelheid(new Double(0.0)); this.eigenData.setVersnelling(new Double(0.0)); System.out.println("BOTSING STOP"); //in de space updaten voor je dood gaat this.update.updateAutoData(this.eigenData);
48
//stop Auto en Threads stopAuto(); } } public void kijkBestemming() { System.out.println("Auto->kijkBestemming()"); if(this.eigenData.locatie.doubleValue()>=1010.0) { System.out.println("Bestemming bereikt"); StartPlaats stPlaats = new StartPlaats(); //synchroniseren door take en write van stPlaats uit de space takeFromSpace(stPlaats); int strook=-1; while(strook==-1) { strook = this.gbData.startPlaats(this.eigenData); } writeToSpace(stPlaats); if(strook==-1) { autoUitSpaceVerwijderen(); //stop Auto en Threads stopAuto(); } //rijden stop zetten this.rijden.stop(); this.eigenData.setStrookNr(new Integer(strook)); this.eigenData.setLocatie(new Double(-1.0)); this.eigenData.setVersnelling(new Double(0.0)); this.eigenData.setSnelheid(new Double(0.0)); this.getsetGbData(null).setGereed(0); //doe niets voor dat gbData voor de nieuwe strook geupdate is while(this.gbData.getGereed()==0){nietsDoen(50);} this.rijden=new Rijden(this); rijden.start(); } } public void autoUitSpaceVerwijderen() { System.out.println("Auto->autoUitSpaceVerwijderen()"); //verwijder AutoData uit de Space AutoData template = new AutoData(); template.id=this.eigenData.id; takeFromSpace(template); //verander idAutos van de SnelwegData in de space SnelwegData templateSnelweg = new SnelwegData(); templateSnelweg.id=this.snelwegData.id; SnelwegData resultaat = null; try { resultaat = (SnelwegData)space.take(templateSnelweg,null,Lease.FOREVER); } catch(Exception e){e.printStackTrace();} boolean verwijderd = resultaat.idAutos.remove(this.eigenData.id); this.snelwegData=resultaat; //snelwegData weer in de space terugzetten try {
49
space.write(resultaat,null,Lease.FOREVER); }catch(Exception e){e.printStackTrace();} } //pak data uit de space public AutoData takeFromSpace(AutoData template) { System.out.println("Auto->takeFromSpace()"); AutoData resultaat=null; try { resultaat = (AutoData)space.take(template,null,space.NO_WAIT); }catch(Exception e){e.printStackTrace();} return resultaat; } public AutoData readFromSpace(AutoData template) { System.out.println("Auto->readFromSpace()"); AutoData resultaat=null; try { resultaat = (AutoData)space.readIfExists(template,null,space.NO_WAIT); }catch(Exception e){e.printStackTrace();} return resultaat; } public void stopAuto() { System.out.println("Auto->stopAuto()"); //Threads stoppen update.stop(); rijden.stop(); System.exit(0); } public void nietsDoen(int milSec) { System.out.println("Auto->nietsDoen()"); try { Thread.sleep(milSec); } catch(Exception e){e.printStackTrace();} } //schrijft StartPlaats naar Space public void writeToSpace(StartPlaats stPlaats) { System.out.println("Auto->writeToSpace(stPlaats)"); try { space.write(stPlaats,null,Lease.FOREVER); }catch(Exception e){e.printStackTrace();} } //pak StartPlaats uit de space public StartPlaats takeFromSpace(StartPlaats template) { System.out.println("Auto->takeFromSpace(stPlaats)"); StartPlaats resultaat=null; try { resultaat = (StartPlaats) space.take(template,null,Lease.FOREVER); }catch(Exception e){e.printStackTrace();} return resultaat; } }
50
Thread Rijden public class Rijden extends Thread { private JavaSpace space; private Auto auto; private AutoData autoData; private SnelwegData snelwegData; private GlobaleData gbData; private long oudeTijd; private AutoData inhaalAuto=null; private double maxVersnelling[]=new double[5]; private AutoData autoVoor; private int verzenden1 = 0; private int verzenden21 = 1; private int verzenden2 = 0; private Double oudeSnelheidGewenst; private String oudeKleur; private AutoData oudeAutoVoor; //default constructor public Rijden(){} //constructor public Rijden(Auto auto) { this.auto=auto; this.autoData=this.auto.getsetEigenData(null); this.snelwegData=this.auto.getsetSnelwegData(null); this.space=auto.getSpace(); this.gbData=this.auto.getsetGbData(null); this.autoVoor=new AutoData(); maxVersnelling[0]=2.1; maxVersnelling[1]=1.5; maxVersnelling[2]=1.2; maxVersnelling[3]=0.5; maxVersnelling[4]=0.3; } public void run() { System.out.println("Rijden->run()"); //kijk of auto niet al in botsing fase is if(this.autoData.status.intValue()==5) { //fictieve botsing this.autoData.setKleur("green"); this.autoData.setSnelheid(new Double(0.0)); this.autoData.setVersnelling(new Double(0.0)); System.out.println("BOTSING STOP"); //in de space updaten voor je dood gaat this.auto.getUpdate().updateAutoData(this.autoData); //stop Auto en Threads this.auto.stopAuto(); } //status van auto op 1==rijden zetten if(this.autoData.status.intValue()==0){this.autoData.status=new Integer(1);} //start de tijd Date d = new Date(); this.oudeTijd = d.getTime(); while(this.autoData.status.intValue()!=5)//niet in botsing { rijden();
51
if(this.autoData.status.intValue()==5){System.out.println("BOTSING STOP");} //even niets doen nietsDoen(500); } } public void rijden() { System.out.println("Rijden->rijden()"); //update Data uit Auto this.snelwegData=this.auto.getsetSnelwegData(null); this.gbData=this.auto.getsetGbData(null); //afhandelen: alle directe berichten berichtAfhandelen(); updateAutoVoor(); //
optimaleSnelheid();
// //bedankt bericht sturen als de auto voor veranderd is // if(this.verzenden21==0 && this.oudeAutoVoor!=null && (this.autoVoor==null || this.autoVoor.id.intValue()!=this.oudeAutoVoor.id.intValue()) ) // { // berichtVersturen(this.oudeAutoVoor.id,21); // this.verzenden21=1; // this.verzenden1=0; // } //update inhaalAuto if(inhaalAuto!=null && this.autoData.strookNr.intValue()!=1) { updateInhaalAuto(); } //kijk of je al ingehaald hebt if(inhaalAuto!=null && (this.autoData.locatie.doubleValue()>=(this.inhaalAuto.locatie.doubleValue()+50.0) ) ) { this.inhaalAuto=null; } //probeer om rechts te rijden als je niet inhaalt if(inhaalAuto==null) { boolean rechts = rechtsRijden(); } //als er geen auto voor is if(this.autoVoor==null) { vrijRijden(); return; } double eigenLoc = this.autoData.locatie.doubleValue(); double afstand=this.autoVoor.locatie.doubleValue() - this.autoVoor.lengte.doubleValue() - eigenLoc; //auto voor is te ver weg if(afstand >= 50.0) { vrijRijden(); return; } //vrij rijden lukt niet,probeer in te hallen boolean inhalen = inhalen(); if(inhalen)
52
{ //als er geen auto voor is if(this.autoVoor==null) { vrijRijden(); return; } eigenLoc = this.autoData.locatie.doubleValue(); afstand=this.autoVoor.locatie.doubleValue() - this.autoVoor.lengte.doubleValue() - eigenLoc; //auto voor is te ver weg if(afstand >= 50.0) { vrijRijden(); return; } } volgAutoVoor(); } public void volgAutoVoor() { System.out.println("Rijden->volgAutoVoor()"); //besteStrook(); // // // // // // // // // // // // // // // // // // // // // //
//volgen dus je bent geen Gids this.autoData.gids=new Integer(0); //update het ook bij Auto zelf this.auto.getsetEigenData(this.autoData); //update Data uit Auto this.snelwegData=this.auto.getsetSnelwegData(null); this.gbData=this.auto.getsetGbData(null); //volg Gids if(this.autoData.gids.intValue()==0) { optimaleSnelheid(); return; }
if(this.verzenden1==0) { //voor je volgt laat weten dat je er langs wilt ==> berichtId==1 berichtVersturen(this.autoVoor.id,1); this.verzenden1=1; this.verzenden21=0; this.oudeAutoVoor=this.autoVoor; } double eigenSnelheid = this.autoData.snelheid.doubleValue(); double gewensteSnelheid = this.autoData.snelheidGewenst.doubleValue(); double autoVoorSnelheid = this.autoVoor.snelheid.doubleValue(); double eigenLoc = this.autoData.locatie.doubleValue(); double afstand=this.autoVoor.locatie.doubleValue()- this.autoVoor.lengte.doubleValue() - eigenLoc; double oudeVersnelling = this.autoData.versnelling.doubleValue(); Date date = new Date(); double afgelegdAfstand=0; double versnelling=0.0; //double T=0.05; float deltaTijd = 0.0f; double alfa, beta, gamma; //aan de hand van autoVoor bereken de versnelling if(eigenSnelheid<=autoVoorSnelheid) { alfa=2.15; beta=-1.67;
53
gamma=-0.89; double teller = java.lang.Math.pow(eigenSnelheid,beta); double noemer = java.lang.Math.pow(afstand,gamma); versnelling = alfa * (teller/noemer) * (autoVoorSnelheid - eigenSnelheid); //versnelling moet niet groter dan maxVersnelling zijn int snelheid = (int)eigenSnelheid; int indexMaxVersnelling=snelheid/6; if(indexMaxVersnelling<0){indexMaxVersnelling=0;} if(indexMaxVersnelling>4){indexMaxVersnelling=4;} if(versnelling>this.maxVersnelling[indexMaxVersnelling]){versnelling=this.maxVersnelling[indexMaxVersnelling];} }//bereken vertragen else { alfa=1.0/1.55; beta=1.0/1.08; gamma=1.0/1.65; double teller = java.lang.Math.pow(eigenSnelheid,beta); double noemer = java.lang.Math.pow(afstand,gamma); versnelling= alfa * (teller/noemer) * (autoVoorSnelheid - eigenSnelheid); //if(versnelling<-10){versnelling=-10;} } //voor zekerheid NaN controle if(Double.isNaN(versnelling)){versnelling=0.0;} //bereken deltaTijd long tijdNu = date.getTime(); deltaTijd = (float)(tijdNu-oudeTijd); deltaTijd = deltaTijd/1000.0f;; //bewaar oudeTijd oudeTijd=tijdNu; //bereken de afgelegde afstand afgelegdAfstand = (0.5 * oudeVersnelling * deltaTijd * deltaTijd) + (eigenSnelheid*deltaTijd); //afgelegdAfstand = (0.5 * oudeVersnelling * T * T) + (eigenSnelheid*T); //bereken nieuwe snelheid eigenSnelheid=eigenSnelheid + (oudeVersnelling * deltaTijd); //eigenSnelheid=eigenSnelheid + (oudeVersnelling * T); if(eigenSnelheid>gewensteSnelheid) { eigenSnelheid=gewensteSnelheid; } //je rijdt dichtbij, dus zelfde snelheid als AutoVoor if(afstand <= 10.0) { eigenSnelheid=this.autoVoor.snelheid.doubleValue(); if(versnelling>0.0){versnelling=0.0;} } //update je eigen data double oudeLocatie = this.autoData.locatie.doubleValue(); this.autoData.setLocatie(new Double(oudeLocatie+afgelegdAfstand)); this.autoData.setSnelheid(new Double(eigenSnelheid)); this.autoData.setVersnelling(new Double(versnelling)); //update het ook bij Auto zelf this.auto.getsetEigenData(this.autoData); //update Data uit Auto this.snelwegData=this.auto.getsetSnelwegData(null); this.gbData=this.auto.getsetGbData(null); updateAutoVoor(); }
54
public void vrijRijden() { System.out.println("Rijden->vrijRijden()"); //besteStrook(); // // // // // // // //
//vrij rijden dus je bent Gids this.autoData.gids=new Integer(1); this.autoData.kleur="red"; //update het ook bij Auto zelf this.auto.getsetEigenData(this.autoData); //update Data uit Auto this.snelwegData=this.auto.getsetSnelwegData(null); this.gbData=this.auto.getsetGbData(null); double eigenLoc = this.autoData.locatie.doubleValue(); double eigenSnelheid = this.autoData.snelheid.doubleValue(); double gewensteSnelheid = this.autoData.snelheidGewenst.doubleValue(); double oudeLocatie = this.autoData.locatie.doubleValue(); double afgelegdAfstand=0; int snelheid = (int)eigenSnelheid; int indexMaxVersnelling=snelheid/6; if(indexMaxVersnelling<0){indexMaxVersnelling=0;} if(indexMaxVersnelling>4){indexMaxVersnelling=4;} double versnelling = this.maxVersnelling[indexMaxVersnelling]; double oudeVersnelling = this.autoData.versnelling.doubleValue(); //voor zekerheid NaN controle if(Double.isNaN(versnelling)){versnelling=0.0;} //bereken deltaTijd float deltaTijd=0.0f; Date dd = new Date(); //double T=0.05; long tijdNu = dd.getTime(); deltaTijd = (float)(tijdNu-oudeTijd); deltaTijd = deltaTijd/1000.0f; //bewaar oudeTijd oudeTijd=tijdNu; //bereken de afgelegde afstand afgelegdAfstand = (0.5 * oudeVersnelling * deltaTijd * deltaTijd) + (eigenSnelheid*deltaTijd); //afgelegdAfstand = (0.5 * oudeVersnelling * T * T) + (eigenSnelheid*T); //bereken nieuwe snelheid eigenSnelheid= eigenSnelheid + (oudeVersnelling * deltaTijd); //eigenSnelheid= eigenSnelheid + (oudeVersnelling * T); if(eigenSnelheid>gewensteSnelheid){eigenSnelheid=gewensteSnelheid;} //update je eigen data this.autoData.locatie=new Double(oudeLocatie+afgelegdAfstand); this.autoData.snelheid=new Double(eigenSnelheid); this.autoData.versnelling=new Double(this.maxVersnelling[indexMaxVersnelling]); //update autoData in Auto this.auto.getsetEigenData(this.autoData); //update Data uit Auto this.snelwegData=this.auto.getsetSnelwegData(null); this.gbData=this.auto.getsetGbData(null); updateAutoVoor(); } public void berichtAfhandelen() { System.out.println("Rijden->berichtAfhandelen()"); Bericht br; while(true)
55
{ br = this.auto.getBericht(); if(br==null){return;} //verzender achter huidige auto, wil er langs if(br.id.intValue()==1) { this.oudeSnelheidGewenst=this.autoData.snelheidGewenst; this.autoData.snelheidGewenst=br.verzender.snelheidGewenst; this.oudeKleur=this.autoData.kleur; this.autoData.kleur=new String("pink"); System.out.println("Nieuwe gewenste snelheid: " + this.autoData.snelheidGewenst); return; } else { //bedankt bericht na bericht 1, auto is er langs, dus kan je gewenste snelheid weer terug if(br.id.intValue()==21) { this.autoData.snelheidGewenst=this.oudeSnelheidGewenst; this.autoData.kleur=this.oudeKleur; this.oudeAutoVoor=null; System.out.println("Terug naar oude gewenste snelheid: " + this.autoData.snelheidGewenst); return; } else { if(br.id.intValue()==2) { this.autoData.snelheid=new Double(0.5*br.verzender.snelheid.doubleValue()); this.autoData.kleur="red"; //update het ook bij Auto zelf this.auto.getsetEigenData(this.autoData); } } } } } public void berichtVersturen(Integer ontvangerId,int id) { System.out.println("Rijden-> berichtVersturen()"); Bericht br= new Bericht(); br.id=new Integer(id); br.verzender=this.autoData; br.ontvangerId=ontvangerId; try { this.space.write(br,null,Lease.FOREVER); }catch(Exception e){e.printStackTrace();} System.out.println("Geschreven"); } public boolean inhalen() { System.out.println("Rijden->inhalen()"); boolean inhalen=false; //op derde strook kan je niet inhalen if(this.autoData.strookNr.intValue()==3){return inhalen;} AutoData loc[] = ruimte(this.autoData, this.autoData.strookNr.intValue()+1); if(loc==null){return inhalen;} double locatie = this.autoData.locatie.doubleValue(); double eigenSnelheid=this.autoData.snelheid.doubleValue(); double afstandVoor=0; double afstandAchter=0;
56
//bereken min invoeg afstanden double minAfstandVoor=6.0; if(loc[0].locatie.doubleValue()!=-9.0) { double minAfstandVoorX = 3.0 + (0.05 * eigenSnelheid)+ (0.15*(eigenSnelheid - loc[0].snelheid.doubleValue())); if(minAfstandVoorX>minAfstandVoor){minAfstandVoor=minAfstandVoorX;} afstandVoor = (loc[0].locatie.doubleValue() - loc[0].lengte.doubleValue() - locatie); } double minAfstandAchter=10.0; if(loc[1].locatie.doubleValue()!=-9.0) { double minAfstandAchterX = 5.0 + (0.15 * loc[1].snelheid.doubleValue())+ (0.40*(loc[1].snelheid.doubleValue() - eigenSnelheid)); if(minAfstandAchterX>minAfstandAchter){minAfstandAchter=minAfstandAchterX;} afstandAchter = (locatie-this.autoData.lengte.doubleValue())-loc[1].locatie.doubleValue(); } if( (afstandVoor>=minAfstandVoor || loc[0].locatie.doubleValue()==-9.0 ) && (afstandAchter>=minAfstandAchter || loc[1].locatie.doubleValue()==-9.0 ) ) { //set de inhaalAuto this.inhaalAuto=this.autoVoor; //verander van strook this.autoData.strookNr=new Integer(this.autoData.strookNr.intValue()+1); //update het ook bij Auto zelf this.auto.getsetEigenData(this.autoData); //update Data uit Auto this.snelwegData=this.auto.getsetSnelwegData(null); this.gbData=this.auto.getsetGbData(null); updateAutoVoor(); inhalen=true; } return inhalen; } public boolean rechtsRijden() { System.out.println("Rijden->rechtsRijden()"); boolean rechts=false; //if(verzenden2 == 0){gedwongenInvoegen();} //op eerste strook kan je niet rechts rijden if(this.autoData.strookNr.intValue()==1){return rechts;} AutoData loc[] = ruimte(this.autoData, this.autoData.strookNr.intValue()-1); if(loc==null){return rechts; } double locatie = this.autoData.locatie.doubleValue(); if(( loc[0].locatie.doubleValue()==-9.0 || (loc[0].locatie.doubleValue() - loc[0].lengte.doubleValue() - 5.0)>=locatie) && ( loc[1].locatie.doubleValue()==-9.0 || (loc[1].locatie.doubleValue()+15.0)<(locatie - this.autoData.lengte.doubleValue()) )) { //verander van strook this.autoData.strookNr=new Integer(this.autoData.strookNr.intValue()-1); //update het ook bij Auto zelf this.auto.getsetEigenData(this.autoData); //update Data uit Auto this.snelwegData=this.auto.getsetSnelwegData(null); this.gbData=this.auto.getsetGbData(null); updateAutoVoor(); rechts = true; } return rechts; } public void updateAutoVoor() {
57
System.out.println("Rijden->updateAutoVoor()"); Vector strook = this.gbData.getStrook(this.autoData.strookNr.intValue()); int eigenLocatie = this.autoData.locatie.intValue(); AutoData autoVoorX=null; double tempLocatie; AutoData tempAutoData; //loop langs hele strook Vector for(int index=0;index<strook.size();index++) { tempAutoData=(AutoData)strook.elementAt(index); tempLocatie=tempAutoData.locatie.doubleValue(); //als de locatie van tempAuto groter is dan locatie van huidige auto if(tempLocatie>eigenLocatie) { //tempAuto is dichterbij dan tijdelijke AutoVoor if(autoVoorX==null || (tempLocatie-tempAutoData.lengte.doubleValue())<(autoVoorX.locatie.doubleValue()autoVoorX.lengte.doubleValue()) ) { autoVoorX=(AutoData)strook.elementAt(index); } } } //verander de autoVoor Data this.autoVoor=autoVoorX; } public AutoData[] ruimte(AutoData autoData,int strook) { System.out.println("Rijden->->ruimte()"); Vector strookX = this.gbData.getStrook(strook); AutoData autoDataX=null; AutoData locatieVoor=new AutoData(); AutoData locatieAchter=new AutoData(); locatieVoor.locatie=new Double(-9.0); locatieAchter.locatie=new Double(-9.0); AutoData loc[]=new AutoData[2]; for(int i=0;i<strookX.size();i++) { autoDataX = (AutoData)strookX.elementAt(i); if(autoData!=null) { //zoek locatieVoor if( (autoDataX.locatie.doubleValue()>=autoData.locatie.doubleValue()) && ((locatieVoor.locatie.doubleValue()==-9.0) || (locatieVoor.locatie.doubleValue()>autoDataX.locatie.doubleValue()) ) ) { locatieVoor=autoDataX; } //zoek locatieAchter if( ( (autoDataX.locatie.doubleValue()<=autoData.locatie.doubleValue()) || ((autoDataX.locatie.doubleValue()-autoDataX.lengte.doubleValue())<=autoData.locatie.doubleValue() ) ) && (locatieAchter.locatie.doubleValue()==-9.0 || locatieAchter.locatie.doubleValue()>autoDataX.locatie.doubleValue()) ) { locatieAchter=autoDataX; } } } loc[0]=locatieVoor; loc[1]=locatieAchter; return loc; } public void updateInhaalAuto() {
58
System.out.println("Rijden->updateInhaalAuto()"); AutoData temp = new AutoData(); AutoData nieuweInhaalAuto=null; AutoData autoDataX; //zoek in nieuwe gbData de nieuwe gegevens van inhaalAuto for(int str=1;str<=3;str++) { Vector strookX = this.gbData.getStrook(str); for(int i=0;i<strookX.size();i++) { autoDataX = (AutoData)strookX.elementAt(i); if(autoData!=null) { //zoek inhaalAuto if(autoDataX.id.intValue()==this.inhaalAuto.id.intValue()) { nieuweInhaalAuto=autoDataX; if(nieuweInhaalAuto.strookNr.intValue()!=(this.autoData.strookNr.intValue()-1)) { this.inhaalAuto=null; return; } } } } if(str==3 && nieuweInhaalAuto==null) { str=0; } } this.inhaalAuto=nieuweInhaalAuto; } public void besteStrook() { int rang=1; Vector strook=null; AutoData auto=null; int aantalAutos=1; int maxAutosStrook1,maxAutosStrook2,maxAutosStrook3; int besteStrook; //bepaal de rang van de auto for(int str=1; str<=3;str++) { strook=this.gbData.getStrook(str); for(int i=0; i<strook.size();i++) { auto=(AutoData)strook.elementAt(i); if(auto!=null) { aantalAutos++; if(auto.snelheidGewenst.doubleValue()
59
if(rang<=maxAutosStrook1){besteStrook=1;} else { if((aantalAutos%3)==2){maxAutosStrook2=(aantalAutos/3)+1;} else{maxAutosStrook2=(aantalAutos/3);} if(rang <= (maxAutosStrook1+maxAutosStrook2)){besteStrook=2;} else{besteStrook=3;} } //verander van strook als nodig is if(this.autoData.strookNr.intValue()>besteStrook) { boolean rechts = rechtsRijden(); if(this.autoData.strookNr.intValue()>besteStrook) { rechts = rechtsRijden(); } return; } if(this.autoData.strookNr.intValue()
=this.autoData.locatie.intValue()) { if(gids!=null) { if(auto.locatie.doubleValue()
60
{ this.autoData.gids=new Integer(1); this.autoData.kleur="yellow"; if(this.oudeSnelheidGewenst!=null) { //this.autoData.gids=new Integer(0); //gewoon een auto die zelf rijdt this.autoData.snelheidGewenst=this.oudeSnelheidGewenst; //this.autoData.kleur="blue"; } } //update het ook bij Auto zelf this.auto.getsetEigenData(this.autoData); //update Data uit Auto this.snelwegData=this.auto.getsetSnelwegData(null); this.gbData=this.auto.getsetGbData(null); System.out.println(this.autoData.toString()); } public void gedwongenInvoegen() { Vector strook; if(this.autoData.strookNr.intValue()==1 || this.autoData.strookNr.intValue()==2) { strook = this.gbData.getStrook(1); } else{strook = this.gbData.getStrook(2);} AutoData auto=null; AutoData gaVoor=null; int leeg=1; int afstand; for(int i=0; i<strook.size();i++) { auto=(AutoData)strook.elementAt(i); if(auto!=null) { afstand = this.autoData.locatie.intValue() - auto.locatie.intValue(); if(auto.locatie.intValue()<=this.autoData.locatie.intValue() && afstand<=300) { if(gaVoor!=null) { if(auto.locatie.doubleValue()>gaVoor.locatie.doubleValue()) { gaVoor=auto; } } else{gaVoor=auto;} } } } if(gaVoor!=null) { berichtVersturen(gaVoor.id,2); verzenden2 = 1; } } public void nietsDoen(int milSec) { try { Thread.sleep(milSec); } catch(Exception e){e.printStackTrace();} } }
61
Globaledata public class GlobaleData { private Vector gdStrook1; private Vector gdStrook2; private Vector gdStrook3; private AutoData autoVoor; private AutoData autoAchter; private int gereed; /** Creates a new instance of GlobaleData */ public GlobaleData() { gdStrook1=new Vector(); gdStrook2=new Vector(); gdStrook3=new Vector(); autoVoor=new AutoData(); autoAchter=new AutoData(); gereed=0; } public Vector getStrook(int strook) { if(strook==1){return this.gdStrook1;} if(strook==2){return this.gdStrook2;} if(strook==3){return this.gdStrook3;} else return null; } public AutoData getAutoVoor(){return autoVoor;} public AutoData getAutoAchter(){return autoAchter;} public void setAutoVoor(AutoData autoData){this.autoVoor=autoData;} public void setAutoAchter(AutoData autoData){ this.autoAchter=autoData;} public int getGereed(){return gereed;} public void setGereed(int gereed){this.gereed=gereed;} public int startPlaats(AutoData autoData) { System.out.println("GlobaleData->startPlaats()"); double locatie = autoData.getLocatie().doubleValue(); int strookX = autoData.getStrookNr().intValue(); Vector strookXX = getStrook(strookX); AutoData autoDataX=null; int out=0; boolean plaats = false; for(int teller=1; plaats==false && teller<=3;teller++) { out=0; for(int i=0;out==0 && i<strookXX.size();i++) { plaats=true; autoDataX = (AutoData)strookXX.elementAt(i); if(autoDataX!=null && (autoDataX.locatie.doubleValue()-autoDataX.lengte.doubleValue() - 5)<=locatie ) { plaats=false; out=1; if(strookX==1){strookX=2;} else { if(strookX==2){strookX=3;} else{strookX=1;} } strookXX = getStrook(strookX); } } }
62
if(out==1 && strookX==autoData.getStrookNr().intValue()) { //geen vrije plaats return -1 return -1; } else{return strookX;} } public String toString() { AutoData a; Integer aId; String s1="strook1 : "; for(int index=0;index
Thread Updatedata public class UpdateData extends Thread { private JavaSpace space; private Auto auto; private AutoData autoData; private SnelwegData snelwegData; private GlobaleData gbData; private int autoToevoegen=0; private int bezet=0; //default constructor UpdateData(){} //constructor UpdateData(Auto auto) { this.auto=auto; this.space=auto.getSpace(); this.autoData=this.auto.getsetEigenData(null); this.snelwegData=zoekSnelweg(autoData.snelwegId); this.gbData=new GlobaleData(); } public int getBezet(){return this.bezet;} public void setBezet(int status){this.bezet=status;}
63
public void run() { while(true) { System.out.println("UpdateData->run()"); //autoData this.autoData=this.auto.getsetEigenData(null); //autoData van de auto in de space updaten //eerste keer zelfs toevoegen updateAutoData(); // //
//kijkt of er directe berichten voor deze auto in de space zijn updateDirecteBerichten(); //haal nieuwe snelwegData uit de space updateSnelwegData(); //haal nieuwe AutoDatas uit de space/update gbData updateGD(); //update de nieuwe snelwegData en gbData bij Auto this.auto.getsetSnelwegData(this.snelwegData); this.auto.getsetGbData(this.gbData); //aangeven dat gbData gereed is==gevuld met data uit de space //voor het eerste keer, zodat auto proces verder kan als gbData gevuld is if(this.auto.getsetGbData(null).getGereed()==0){this.auto.getsetGbData(null).setGereed(1);} //even niets doen nietsDoen(1000); } } public void updateAutoData() { System.out.println("UpdateData->updateAutoData()"); AutoData template=new AutoData(); template.id=this.autoData.id; template.versie=this.autoData.versie; //als het al bestaat AutoData temp = readFromSpace(template); //voor het gevaal dat snelweg de status en kleur heeft veranderd door een botsing if(temp!=null && temp.getStatus()!=null && temp.getStatus().intValue()==5) { this.auto.getsetEigenData(null).setStatus(temp.getStatus()); this.auto.getsetEigenData(null).setKleur(temp.getKleur()); } //andere versie in space zetten if(this.autoData.getVersie().intValue()==1) { this.autoData.setVersie(new Integer(2)); } else{this.autoData.setVersie(new Integer(1));} writeToSpace(this.autoData); //pak oude versie uit de space, als die bestaat if(temp!=null){temp = takeFromSpace(template);} } public void updateDirecteBerichten() { Bericht br=null; while(true) { br= takeFromSpace(); if(br!=null){this.auto.setBericht(br); System.out.println("bericht ID: "+br.id.intValue());}
64
else {return;} } } public void updateSnelwegData() { System.out.println("UpdateData->updateSnelwegData()"); SnelwegData templateSnelweg = new SnelwegData(); templateSnelweg.id=this.autoData.snelwegId; //eerste keer je auto toevoegen bij snelweg if(this.autoToevoegen==0) { try { this.snelwegData = (SnelwegData)space.take(templateSnelweg,null,Lease.FOREVER); } catch(Exception e){e.printStackTrace();} if(snelwegData!=null) { //voeg je eigen id aan isAutos this.snelwegData.idAutos.add(this.autoData.id); } //schrijf SnelwegData terug in de Space try { space.write(this.snelwegData,null,Lease.FOREVER); } catch(Exception e){e.printStackTrace();} this.autoToevoegen=1; }//anders alleen lezen else { try { this.snelwegData = (SnelwegData)space.read(templateSnelweg,null,Lease.FOREVER); } catch(Exception e){e.printStackTrace();} } } public void updateGD() { System.out.println("UpdateData->updateGD()"); Vector strook; AutoData template = new AutoData(); AutoData spaceAuto=null; AutoData autoVoorX=null; int eigenLocatie = this.autoData.locatie.intValue(); int tempLocatie; Vector vector = new Vector(); int teller=1; for(int str=1;str<=3;str++) { //auto's op dezelfde snelweg template.snelwegId=this.autoData.snelwegId; template.strookNr=new Integer(str); //Strook vector leegmaken, er komt nieuwe data in this.gbData.getStrook(str).clear(); //je gaat langs alle autos in de space for(int index=0; index
65
//eigen Data hoef je niet uit de space te halen, de rest wel if(template.id.intValue()!=this.autoData.id.intValue()) { //lees en voeg spaceAuto toe spaceAuto = readFromSpaceX(template); if(spaceAuto==null) { template.versie=new Integer(2); spaceAuto = readFromSpace(template); if(spaceAuto!=null) { this.gbData.getStrook(str).add(spaceAuto); } } else { this.gbData.getStrook(str).add(spaceAuto); } } } //als niet alle autos uit space zijn gehaald doe het opnieuw teller=teller+this.gbData.getStrook(str).size(); if(str==3 && this.snelwegData.idAutos.size()!=teller) { str=0; teller=1; } } } public void nietsDoen(int milSec) { System.out.println("UpdateData->nietsDoen()"); try { Thread.sleep(milSec); } catch(Exception e){e.printStackTrace();} } public void updateAutoData(AutoData autoData) { System.out.println("UpdateData->updateAutoData()"); AutoData template=new AutoData(); template.id=autoData.id; template = takeFromSpace(template); writeToSpace(autoData); } public SnelwegData zoekSnelweg(Integer snelwegId) { System.out.println("UpdateData->zoekSnelweg()"); SnelwegData resultaat=null; SnelwegData snelwegTemplate=new SnelwegData(); snelwegTemplate.id=this.autoData.snelwegId; //pak snelwegData uit de space try { resultaat = (SnelwegData)space.read(snelwegTemplate,null,Lease.FOREVER); } catch(Exception e){e.printStackTrace();} return resultaat; } public AutoData readFromSpace(AutoData template) { System.out.println("UpdateData->readFromSpace()"); AutoData resultaat=null;
66
try { resultaat = (AutoData)space.read(template,null,space.NO_WAIT); }catch(Exception e){e.printStackTrace();} return resultaat; } public AutoData readFromSpaceX(AutoData template) { System.out.println("UpdateData->readFromSpace()"); AutoData resultaat=null; try { resultaat = (AutoData)space.read(template,null,space.NO_WAIT); }catch(Exception e){e.printStackTrace();} return resultaat; } //schrijft Data naar Space public void writeToSpace(AutoData data) { System.out.println("UpdateData->writeToSpace()"); try { this.space.write(data,null,Lease.FOREVER); }catch(Exception e){e.printStackTrace();} } //pak data uit de space public AutoData takeFromSpace(AutoData template) { System.out.println("UpdateData->takeFromSpace(AutoData)"); AutoData resultaat=null; try { resultaat = (AutoData)space.take(template,null,space.NO_WAIT); }catch(Exception e){e.printStackTrace();} return resultaat; } //pak direchte berichten uit de space public Bericht takeFromSpace() { System.out.println("UpdateData->takeFromSpace(Bericht)"); Bericht template = new Bericht(); template.ontvangerId=this.autoData.id; try { template = (Bericht)space.take(template,null,space.NO_WAIT); }catch(Exception e){e.printStackTrace();} return template; } }
Snelwegdata public class SnelwegData implements Entry{ public Integer id, aantalStrooken; public Double maxSnelheid; public Vector idAutos; /** Creates a new instance of SnelwegData */ public SnelwegData() {} //constructor public SnelwegData(int id, int aantalStrooken, double maxSnelheid) {
67
this.id=new Integer(id); this.aantalStrooken=new Integer(aantalStrooken); this.maxSnelheid=new Double(maxSnelheid); this.idAutos=new Vector(); } public String toString() { String st ="\nSnelwegData: " + "id=" + this.id + " * aantalStrookenr=" + this.aantalStrooken + " * maxSnelheid=" + this.maxSnelheid + " * idAutos=" + idAutos.toString(); return st; } }
Snelwegproces public class Snelweg { private JavaSpace space; private SnelwegData eigenSnelwegData; private GlobaleData gbData; /** Creates a new instance of Snelweg */ public Snelweg() {} //constructor public Snelweg(int id, int aantalStrooken, double maxSnelheid,JavaSpace space) { this.space=space; this.eigenSnelwegData = new SnelwegData(id, aantalStrooken, maxSnelheid); this.gbData=new GlobaleData(); } public Snelweg(SnelwegData snelwegData,JavaSpace space) { this.space=space; this.eigenSnelwegData = snelwegData; this.gbData=new GlobaleData(); } public void start() { //snelweg in de space toevoegen SnelwegToevoegen(); while(true) { //update snelwegData updateSnelwegData(); //updaten van gbData updateGD(); //kijk voor botsingen kijkBotsing(); //even niets doen nietsDoen(2000); } } public void SnelwegVerwijderen() { System.out.println("Snelweg->SnelwegVerwijderen()"); //snelweg uit de space verwijderen SnelwegData oudeSnelwegData=null;
68
SnelwegData templateSnelweg=new SnelwegData(); templateSnelweg.id= this.eigenSnelwegData.id; //verwijder oude SnelwegData uit de Space try { oudeSnelwegData = (SnelwegData)space.take(templateSnelweg,null,Lease.FOREVER); } catch(Exception e){e.toString();} oudeSnelwegData=null; } public void SnelwegToevoegen() { System.out.println("Snelweg->SnelwegToevoegen()"); //staartPlaats entry in space zetten writeToSpace(new StartPlaats()); //snelwegdata in de space zetten SnelwegData oudeSnelwegData=null; SnelwegData templateSnelweg=new SnelwegData(); templateSnelweg.id= this.eigenSnelwegData.id; //als er oudeSnelwegData in de Space al aanwezig is, //dan gebruik de oude idAutos Vectror try { oudeSnelwegData = (SnelwegData)space.takeIfExists(templateSnelweg,null,space.NO_WAIT); } catch(Exception e){e.toString();} if(oudeSnelwegData!=null) { this.eigenSnelwegData=oudeSnelwegData; } try { space.write(this.eigenSnelwegData,null,Lease.FOREVER); } catch(Exception e){e.printStackTrace();} } public void autosBijvoegen(Vector autoIDs) { System.out.println("Snelweg->autosBijvoegen()"); SnelwegData templateSnelweg= new SnelwegData(); templateSnelweg.id= this.eigenSnelwegData.id; //haal snelwegData uit de Space try { this.eigenSnelwegData = (SnelwegData)space.take(templateSnelweg,null,Lease.FOREVER); } catch(Exception e){e.printStackTrace();} //voeg de nieuwe autoIDs toe en schrijf het snelwegData terug naar de Space for(int index=0;index
69
Vector strook; AutoData autoI; AutoData autoJ; AutoData autoX; AutoData template=new AutoData(); for(int str=1; str<=3; str++) { strook=this.gbData.getStrook(str); for(int i=0;i<strook.size();i++) { autoI=(AutoData)strook.elementAt(i); if(autoI.locatie.doubleValue()>=0.0) { for(int j=i+1;j<strook.size();j++) { autoJ=(AutoData)strook.elementAt(j); if(autoJ.locatie.doubleValue()>=0.0) { //autoI voor, autoJ achter if(autoJ.getLocatie().doubleValue()<=autoI.getLocatie().doubleValue() && autoJ.getLocatie().doubleValue()>=(autoI.getLocatie().doubleValue()-autoI.getLengte().doubleValue()) ) { //botsing:verander status en kleur van een auto in de space //autoI template.setId(autoI.getId()); autoX = takeFromSpace(template); autoX.setStatus(new Integer(5)); autoX.setKleur("red"); writeToSpace(autoX); //autoJ template.setId(autoJ.getId()); autoX = takeFromSpace(template); autoX.setStatus(new Integer(5)); autoX.setKleur("yellow"); writeToSpace(autoX); } else { //autoJ voor, autoI achter if(autoI.getLocatie().doubleValue()<=autoJ.getLocatie().doubleValue() && autoI.getLocatie().doubleValue()>=(autoJ.getLocatie().doubleValue() - autoJ.getLengte().doubleValue()) ) { //botsing:verander status en kleur van een auto in de space //autoJ template.setId(autoJ.getId()); autoX = takeFromSpace(template); autoX.setStatus(new Integer(5)); autoX.setKleur("red"); writeToSpace(autoX); //autoI template.setId(autoI.getId()); autoX = takeFromSpace(template); autoX.setStatus(new Integer(5)); autoX.setKleur("yellow"); writeToSpace(autoX); } } } } } } } } public void updateGD() { System.out.println("Snelweg->updateGD()"); Vector strook;
70
for(int str=1;str<4;str++) { //auto's op dezelfde strook AutoData template = new AutoData(); template.strookNr=new Integer(str); //Strook vector leegmaken, er komt nieuwe data in this.gbData.getStrook(str).clear(); AutoData spaceAuto=null; //je gaat langs alle autos in de space for(int index=0; indexupdateSnelwegData()"); SnelwegData templateSnelweg = new SnelwegData(); templateSnelweg.id=this.eigenSnelwegData.id; try { this.eigenSnelwegData = (SnelwegData)space.read(templateSnelweg,null,Lease.FOREVER); }catch(Exception e){e.printStackTrace();} } //schrijft Data naar Space public void writeToSpace(AutoData data) { System.out.println("Snelweg->writeToSpace()"); try { this.space.write(data,null,Lease.FOREVER); }catch(Exception e){e.printStackTrace();} } //pak data uit de space public AutoData takeFromSpace(AutoData template) { System.out.println("Snelweg->takeFromSpace()"); AutoData resultaat=null; try { resultaat = (AutoData)space.take(template,null,space.NO_WAIT); }catch(Exception e){e.printStackTrace();} return resultaat; }
71
public AutoData readFromSpace(AutoData template) { System.out.println("Snelweg->readFromSpace()"); AutoData resultaat=null; try { resultaat = (AutoData)space.readIfExists(template,null,space.NO_WAIT); }catch(Exception e){e.printStackTrace();} return resultaat; } //schrijft StartPlaats naar Space public void writeToSpace(StartPlaats stPlaats) { System.out.println("Snelweg->writeToSpace(stPlaats)"); try { space.write(stPlaats,null,Lease.FOREVER); }catch(Exception e){e.printStackTrace();} } public void nietsDoen(int milSec) { System.out.println("Snelweg->nietsDoen()"); try { Thread.sleep(milSec); } catch(Exception e){e.printStackTrace();} } }
72