Tram bus et voitures avec Lua

Dans cet article, un de nos utilisateurs m’a demandé de trouver une solution pour son petit projet Lua suite à quelques dysfonctionnement dans le trafic des véhicules. Nous allons voir ensemble une des solutions pour corriger le problème.

Présentation

Ce projet est composé des éléments suivants :

  1. Une gare avec 2 tramways circulant à tour de rôle sur une voie unique,
  2. Une gare routière avec 2 bus circulant sur une route à double sens. Un bus jaune dans le sens des aiguilles d’une montre, un bus blanc dans le sens inverse des aiguilles d’une montre,
  3. Des voitures qui roulent toujours sur la route principale.

Dans le script initial reçu avec ce projet, les bus démarraient inopinément et percutaient les tramways ou les voitures. De plus, la fonction EEPMain() vérifiait 5 fois par secondes deux tableaux associatifs totalisant 51 segments de voies. Un rapide calcul donnait ceci : 51 x 5 x 60 = 15 300 vérifications à la minute, ce qui représentait une charge de travail supplémentaire pour EEP.

Alors comment faire ? Nous allons voir que rien ne vaut la simplicité et un peu de logique pour réaliser ce travail. Ne vous fiez pas à la longueur du tutoriel car le script n’est pas très long. Nous avons essayé plutôt d’apporter des réponses à des questions que vous pourriez légitimement vous poser.

Vous avez la possibilité de télécharger ce projet en cliquant sur le bouton ci-dessous. Celui-ci a été réalisé avec la version EEP16. Une fois le téléchargement terminé, décompressez le fichier archive. Ensuite, ouvrez EEP et chargez le projet.

Tram-Bus-Voitures

Projet de démonstration Lua avec circulation de différents véhicules.
Description en image
Tram Bus et Voitures avec Lua, figure 1
Figure n° 1 - Présentation du réseau

Comme vous pouvez le constater, le réseau se divise en deux parties principales : la partie située à gauche (côté Ouest) et la partie à droite (côté Est).

Pour le moment, ne vous préoccupez pas des info-bulles, nous allons y revenir plus tard. Vous remarquerez dans la partie supérieure, une bifurcation vers laquelle se situe la gare routière avec les arrêts de bus. La gare des tramways jouxte la gare routière (Pour une meilleure lisibilité, les gares ne sont pas représentées).

Nous allons maintenant zoomer sur la partie Est dans la vue 2D :

Tram Bus et Voitures avec Lua, figure 2
Figure n° 2

Les règles de circulation sont les suivantes :

  1. Les tramways sont prioritaires par rapport aux bus et aux voitures. Lorsqu’un tramway entre dans la gare, il donne l’ordre à l’autre tramway de démarrer dans le sens opposé et ainsi de suite.
  2. Les bus sont prioritaires par rapport aux voitures. Comme pour les tramways, lorsqu’un bus entre dans la gare routière, ordre est donné à l’autre bus de démarrer dans le sens opposé.
  3. Les voitures n’influent en rien le comportement des bus et tramways et restent toujours sur l’axe routier principal.

Bien entendu, les mêmes règles de circulation s’appliquent pour la partie Ouest.

L'ajout des véhicules dans le projet

Dans EEP, lors de l’ajout d’un matériel roulant, une fenêtre s’ouvre dans laquelle vous pouvez modifier le nom par défaut (voir figure n° 3). L’idéal étant de donner des noms de véhicules explicites et simples. Pour les bus, nous avons choisi Bus_Jaune et Bus_Blanc. Après le trait de soulignement (chiffre 8 du clavier alphanumérique), vous pouvez écrire une dénomination quelconque comme la couleur par exemple ou encore une ville, un n° de ligne, etc. L’important est de bien commencer par Bus_ce-que-vous-voulez. Nous verrons par la suite comment extraire dans le script, la partie située à gauche du trait de soulignement.

Tram Bus et Voitures avec Lua, figure 3
Figure n° 3

Pour les voitures et les tramways, vous pouvez laisser les noms par défaut car ils ne sont pas pertinents dans le cadre de notre tutoriel.

Le script

Vous pouvez cliquer sur le bouton ci-dessous pour afficher le script en entier dans une fenêtre séparée :

Cliquez sur le bouton à droite pour copier ce code dans le presse-papier
-- Efface la fenêtre d'évènements
clearlog()

-- Constantes des différents statuts des parcours
CONST_PARCOURS_DEBUT = 1
CONST_PARCOURS_TERMINE = 10
-- Constantes pour les signaux
CONST_VOIE_LIBRE = 1
CONST_ARRET = 2
-- Constantes pour les aiguillages
CONST_BRANCHE_PRINCIPALE = 1
CONST_EMBRANCHEMENT = 2


-- Variables pour les mouvements des véhicules (Bus et Tramways)
-- Par défaut, tous les parcours sont positionnés sur TERMINE
-- (Partie Est = partie droite du réseau)
DEPART_Bus_Est = CONST_PARCOURS_TERMINE
DEPART_Tram_Est = CONST_PARCOURS_TERMINE
ARRIVEE_Tram_Est = CONST_PARCOURS_TERMINE
ARRIVEE_Bus_Est = CONST_PARCOURS_TERMINE
-- (Partie Ouest = partie gauche du réseau)
DEPART_Bus_Ouest = CONST_PARCOURS_TERMINE
DEPART_Tram_Ouest = CONST_PARCOURS_TERMINE
ARRIVEE_Bus_Ouest = CONST_PARCOURS_TERMINE
ARRIVEE_Tram_Ouest = CONST_PARCOURS_TERMINE


-- ENREGISTREMENT DES 6 SEGMENTS DE VOIES --
-- Segment devant le feu tricolore Entree bus côté Ouest
EEPRegisterRoadTrack(30)
-- Segment devant le feu tricolore Entree bus côté Est
EEPRegisterRoadTrack(42)
-- Segment devant le feu tricolore sortie bus côté Est
EEPRegisterRoadTrack(66)
-- Segment devant le feu tricolore sortie bus côté Ouest
EEPRegisterRoadTrack(70)

-- Segment devant le signal du tramway côté Est dans la gare routière
EEPRegisterTramTrack(31)
-- Segment devant le signal du tramway côté Ouest dans la gare routière
EEPRegisterTramTrack(22)

-- Enregistrement des signaux pour gérer les évènements
-- dans les fonctions de rappel
EEPRegisterSignal(4)
EEPRegisterSignal(7)
EEPRegisterSignal(9)
EEPRegisterSignal(12)


-- Fonction EEPMain
function EEPMain()
    return 1
end


									----------------
									-- PARTIE EST --
									----------------
									
-- Cette fonction est activée par le tramway jaune via un point de contact à l'entrée de la gare côté est
function fncTramEntreeEst()

	-- Positionne le parcours ARRIVEE_Tram_Est sur DEBUT
	ARRIVEE_Tram_Est = CONST_PARCOURS_DEBUT

	-- Si aucun bus ne quitte ou n'arrive dans la gare routière alors...
	if DEPART_Bus_Est == CONST_PARCOURS_TERMINE and ARRIVEE_Bus_Est == CONST_PARCOURS_TERMINE then
			-- Le tramway jaune peut rentrer dans la gare routière
			-- Commute le signal n° 10 du tramway sur voie Libre
			EEPSetSignal(10, CONST_VOIE_LIBRE, 1)
			-- Commute l'aiguillage n° 5 sur Branche Principale
			EEPSetSwitch(5, CONST_BRANCHE_PRINCIPALE)
		else
			-- ...sinon un bus quitte ou arrive dans la gare routière
			-- et commute le signal n° 10 du tramway sur arrêt
			EEPSetSignal(10, CONST_ARRET, 1)
	end	

end	-- Fin de la fonction fncTramEntreeEst


-- Cette fonction est activée via un point de contact par le tramway jaune
-- lorsque celui-ci rentre dans la gare côté est
function fncFinTramEntreeEst()

	-- Positionne le parcours ARRIVEE_Tram_Est sur TERMINE
	ARRIVEE_Tram_Est = CONST_PARCOURS_TERMINE
	
	-- Si aucun bus ne quitte ou n'arrive dans la gare routière alors...
	if DEPART_Bus_Est == CONST_PARCOURS_TERMINE and ARRIVEE_Bus_Est == CONST_PARCOURS_TERMINE then
		-- Commute le signal n° 9 du tramway sur voie Libre
		EEPSetSignal(9, CONST_VOIE_LIBRE, 1)
		-- Les autres signaux sont commutés directement dans la fonction de rappel du signal n° 9
	end

end	-- Fin de la fonction fncFinTramEntreeEst


-- Cette fonction est activée via un point de contact par le tramway bleu
-- lorsque celui-ci a dépassé le croisement routier côté est
function fncFinTramSortieEst()

	-- Positionne le parcours DEPART_Tram_Est sur TERMINE
	DEPART_Tram_Est = CONST_PARCOURS_TERMINE

	-- Récupére les informations du segment 42 (ID voie 42 avec signal n° 13)
	Result, Occupe42, Name42 = EEPIsRoadTrackReserved(42, true)
	-- Récupére les informations du segment 66 (ID voie 66 avec signal n° 4)
	Result, Occupe66, Name66 = EEPIsRoadTrackReserved(66, true)
	-- Si un véhicule occupe le segment routier n° 42
	if Occupe42 == true then
			local strCategorieVehicule = string.sub(Name42, string.find(Name42, "%a+"))

			-- Extrait le nom du véhicule (variable Name42) présent sur le segment dans la variable strCategorieVehicule
			-- Explications %a+. %a = N'importe quelle lettre et uniquement que des lettres ! + = un ou plusieurs caractères
			-- Utilisation du mot clé upper pour transformer la chaine de caractères en majuscules quelque soit
			-- la casse des caractères utilisée lors du nom donné au véhicule au moment de sa création (Bus, bUs, buS...)
			-- Si le nom du véhicule commence par Bus alors...
			if string.upper(strCategorieVehicule) == "BUS" then					
					-- Positionne le parcours ARRIVEE_Bus_Est sur DEBUT
					ARRIVEE_Bus_Est = CONST_PARCOURS_DEBUT
					-- Commute le signal n° 11 (feu tricolore) sur arrêt
					EEPSetSignal(11, CONST_ARRET)
					-- Commute l'aiguillage n° 17 sur Embranchement
					EEPSetSwitch(17, CONST_EMBRANCHEMENT)
				else
					-- ...Sinon on teste la condition si le bus jaune était entré juste avant le tramway jaune alors que ce dernier a déjà franchi le point de contact fncTramEntreeEst.
					-- Lorsque le bus jaune avait franchi le point de contact fncFinBusEntreeEst, le bus blanc ne pouvait pas démarrer car le tramway jaune entrait à son tour dans la gare.
					-- Il incombe ainsi au tramway bleu une fois sorti de la gare, de vérifier si le bus blanc est arrêté devant le signal n° 4
					if Occupe66 == true then
						-- Commute le signal n° 4 sur voie libre
						EEPSetSignal(4, CONST_VOIE_LIBRE, 1)
						-- Les autres signaux sont commutés directement dans la fonction de rappel du signal n° 4
					end
			end
			
			-- Dans les 2 cas, commute le signal n° 13 (feu tricolore) sur voie Libre
			EEPSetSignal(13, CONST_VOIE_LIBRE)

		else
		
			-- Idem que le test ci-dessus sauf que le segment n° 42 n'était pas occupé
			if Occupe66 == true then
				-- Commute le signal n° 4 sur voie libre
				EEPSetSignal(4, CONST_VOIE_LIBRE, 1)
				-- Les autres signaux sont commutés directement dans la fonction de rappel du signal n° 4
			end
		
	end
		
end	-- Fin de la fonction fncFinTramSortieEst


-- Cette fonction est activée via un point de contact par le bus jaune
-- lorsque celui-ci doit entrer dans la gare routière
function fncBusEntreeEst()

	-- Si aucun tram quitte ou arrive dans la gare alors...
	if ARRIVEE_Tram_Est == CONST_PARCOURS_TERMINE and DEPART_Tram_Est == CONST_PARCOURS_TERMINE then
			-- Positionne le parcours ARRIVEE_Bus_Est sur DEBUT
			ARRIVEE_Bus_Est = CONST_PARCOURS_DEBUT
			-- Commute le signal n° 11 (feu tricolore) sur arrêt
			EEPSetSignal(11, CONST_ARRET)
			-- Commute l'aiguillage n° 17 sur Embranchement
			EEPSetSwitch(17, CONST_EMBRANCHEMENT)

		else
			-- sinon un tram quitte ou arrive dans la gare et
			-- commute le feu tricolore (signal n° 13) au rouge
			EEPSetSignal(13, CONST_ARRET)			
	end

end	-- Fin de la fonction fncBusEntreeEst


-- Cette fonction est activée via un point de contact par le bus jaune
-- lorsque celui-ci vient juste de rentrer dans la gare routière côté Est
function fncFinBusEntreeEst()

	-- Positionne le parcours ARRIVEE_Bus_Est sur TERMINE
	ARRIVEE_Bus_Est = CONST_PARCOURS_TERMINE

	-- Si le tramway jaune est en attente devant le signal n° 10 alors...
	if ARRIVEE_Tram_Est == CONST_PARCOURS_DEBUT then
			-- ... Commute les signaux 10 et 11 sur Voie Libre
			EEPSetSignal(10, CONST_VOIE_LIBRE)
			EEPSetSignal(11, CONST_VOIE_LIBRE)
			-- Commute l'aiguillage n° 5 sur Branche Principale
			EEPSetSwitch(5, CONST_BRANCHE_PRINCIPALE)

		else
			-- Si pas de tramway en attente devant le signal n° 10 et si pas de bus blanc en attente devant le signal n° 4
			-- alors on commute l'aiguillage n° 17 sur Branche Principale et le signal n° 11 sur Voie Libre
			EEPSetSwitch(17, CONST_BRANCHE_PRINCIPALE)
			EEPSetSignal(11, CONST_VOIE_LIBRE)
	end

	-- Dans les 2 cas, commute le signal n° 13 (feu tricolore) sur voie Libre
	EEPSetSignal(13, CONST_VOIE_LIBRE)

end	-- Fin de la fonction fncBusEntreeEst


-- Cette fonction est activée via un point de contact par le bus jaune lorsque
-- celui-ci est entré dans la gare routière dans le sens droite-gauche
function fncDepartBusEst()
	-- Test si le bus blanc se trouve sur le segment de route devant le feu tricolore (signal n° 4)
	Result, Occupe66, Name66 = EEPIsRoadTrackReserved(66, true)
	-- Si le bus blanc est à l'arrêt et si aucun tram ne quitte ou n'arrive dans la gare alors...
	if Occupe66 == true and DEPART_Tram_Est == CONST_PARCOURS_TERMINE and ARRIVEE_Tram_Est == CONST_PARCOURS_TERMINE then
		-- Commute le signal n° 4 sur voie libre
		EEPSetSignal(4, CONST_VOIE_LIBRE, 1)
		-- Les autres signaux sont commutés directement dans la fonction de rappel du signal n° 4
	end
end	-- Fin de la fonction fncDepartBusEst


-- Cette fonction est activée via un point de contact par le bus blanc
-- lorsque celui-ci vient de rentrer sur la route principale côté Est
function fncFinDepartBusEst()

	-- Positionne le parcours DEPART_Bus_Est sur TERMINE			
	DEPART_Bus_Est = CONST_PARCOURS_TERMINE

	-- Si le tramway jaune a déjà franchi le point de contact fncTramEntreeEst alors...
	if ARRIVEE_Tram_Est == CONST_PARCOURS_DEBUT then
			-- Commute les signaux 10 et 11 sur Voie Libre
			EEPSetSignal(10, CONST_VOIE_LIBRE)
			EEPSetSignal(11, CONST_VOIE_LIBRE)
			-- Commute l'aiguillage n° 5 sur Branche Principale
			EEPSetSwitch(5, CONST_BRANCHE_PRINCIPALE)
		else
			-- sinon on récupére les informations du segment n° 42
			Result, Occupe42, Name42 = EEPIsRoadTrackReserved(42, true)
			
			if Occupe42 == true then
					local strCategorieVehicule = string.sub(Name42, string.find(Name42, "%a+"))

					-- Si un véhicule occupe le segment routier n° 42 et s'il s'agit d'un bus alors...
					if string.upper(strCategorieVehicule) == "BUS" then					
							-- Positionne le parcours ARRIVEE_Bus_Est sur DEBUT
							ARRIVEE_Bus_Est = CONST_PARCOURS_DEBUT
							-- Commute le signal n° 11 (feu tricolore) sur arrêt
							EEPSetSignal(11, CONST_ARRET)
							-- Commute l'aiguillage n° 17 sur Embranchement
							EEPSetSwitch(17, CONST_EMBRANCHEMENT)
						else
							-- Commute le signal n° 11 (feu tricolore) sur Voie Libre
							EEPSetSignal(11, CONST_VOIE_LIBRE)
					end

				else
					-- Commute le signal n° 11 (feu tricolore) sur Voie Libre
					EEPSetSignal(11, CONST_VOIE_LIBRE)
			end
	end

end	-- Fin de la fonction fncFinDepartBusEst



									------------------
									-- PARTIE OUEST --
									------------------

function fncTramEntreeOuest()

	-- Positione le parcours prédéfini n° 25 (Tramway)
	ARRIVEE_Tram_Ouest = CONST_PARCOURS_DEBUT

	if DEPART_Bus_Ouest == CONST_PARCOURS_TERMINE and ARRIVEE_Bus_Ouest == CONST_PARCOURS_TERMINE then
			-- Aucun mouvement de bus au croisement
			EEPSetSignal(1, CONST_VOIE_LIBRE)
			EEPSetSwitch(6, CONST_EMBRANCHEMENT)

		else
			-- Ferme le signal n° 1 du tramway
			EEPSetSignal(1, CONST_ARRET, 1)
	end	
end	-- Fin de la fonction fncTramEntreeOuest


function fncFinTramEntreeOuest()

	ARRIVEE_Tram_Ouest = CONST_PARCOURS_TERMINE

	if DEPART_Bus_Ouest == CONST_PARCOURS_TERMINE and ARRIVEE_Bus_Ouest == CONST_PARCOURS_TERMINE then
		-- DEPART_Tram_Ouest = CONST_PARCOURS_DEBUT
		EEPSetSignal(7, CONST_VOIE_LIBRE, 1)
		-- Les autres signaux sont commutés directement dans la fonction de rappel du signal n° 7
	end

end	-- fin de la fonction fncFinTramEntreeOuest


function fncFinTramSortieOuest()

	DEPART_Tram_Ouest = CONST_PARCOURS_TERMINE

	Result, Occupe30, Name30 = EEPIsRoadTrackReserved(30, true)
	Result, Occupe70, Name70 = EEPIsRoadTrackReserved(70, true)		
	if Occupe30 == true then
			local strCategorieVehicule = string.sub(Name30, string.find(Name30, "%a+"))

			if string.upper(strCategorieVehicule) == "BUS" then
					ARRIVEE_Bus_Ouest = CONST_PARCOURS_DEBUT
					EEPSetSwitch(16, CONST_EMBRANCHEMENT)
					EEPSetSignal(14, CONST_VOIE_LIBRE)

				else
					if Occupe70 == true then
						EEPSetSignal(12, CONST_VOIE_LIBRE, 1)
						-- Les autres signaux sont commutés directement dans la fonction de rappel du signal n° 12
					end
			end
		else
			if Occupe70 == true then
				EEPSetSignal(12, CONST_VOIE_LIBRE, 1)
				-- Les autres signaux sont commutés directement dans la fonction de rappel du signal n° 12
			end
		
	end
	
end	-- Fin de la fonction fncFinTramSortieOuest


function fncBusEntreeOuest()

	if ARRIVEE_Tram_Ouest == CONST_PARCOURS_TERMINE and DEPART_Tram_Ouest == CONST_PARCOURS_TERMINE then
			EEPSetSignal(14, CONST_VOIE_LIBRE)
			EEPSetSwitch(16, CONST_EMBRANCHEMENT)
			ARRIVEE_Bus_Ouest = CONST_PARCOURS_DEBUT
		else
			-- Commute le feu tricolore (signal n° 14) au rouge
			EEPSetSignal(14, CONST_ARRET, 1)
	end

end	-- Fin de la fonction fncBusEntreeOuest


function fncFinBusEntreeOuest()

	ARRIVEE_Bus_Ouest = CONST_PARCOURS_TERMINE

	if ARRIVEE_Tram_Ouest == CONST_PARCOURS_DEBUT and DEPART_Bus_Ouest == CONST_PARCOURS_TERMINE then
			ARRIVEE_Tram_Ouest = CONST_PARCOURS_DEBUT
			EEPSetSignal(1, CONST_VOIE_LIBRE)
			EEPSetSwitch(6, CONST_EMBRANCHEMENT)

		else

			Result, Occupe30, Name30 = EEPIsRoadTrackReserved(30, true)
			if Occupe30 == true then
				local strCategorieVehicule = string.sub(Name30, string.find(Name30, "%a+"))

				if string.upper(strCategorieVehicule) == "BUS" then
						EEPSetSwitch(16, CONST_EMBRANCHEMENT)
						ARRIVEE_Bus_Ouest = CONST_PARCOURS_DEBUT
					else
						EEPSetSwitch(16, CONST_BRANCHE_PRINCIPALE)
				end
			end
			EEPSetSignal(14, CONST_VOIE_LIBRE)
	end

end	-- fin de la fonction fncFinBusEntreeOuest


function fncDepartBusOuest()
	Result, Occupe70, Name70 = EEPIsRoadTrackReserved(70, true)
	if Occupe70 == true and ARRIVEE_Tram_Ouest == CONST_PARCOURS_TERMINE and DEPART_Tram_Ouest == CONST_PARCOURS_TERMINE then
		EEPSetSignal(12, CONST_VOIE_LIBRE, 1)
		-- Les autres signaux sont commutés directement dans la fonction de rappel du signal n° 12
	end
end	-- Fin de la fonction fncDepartBusOuest


function fncFinDepartBusOuest()

	DEPART_Bus_Ouest = CONST_PARCOURS_TERMINE

	EEPSetSwitch(15, CONST_BRANCHE_PRINCIPALE)
	EEPSetSignal(19, CONST_VOIE_LIBRE)

	if ARRIVEE_Tram_Ouest == CONST_PARCOURS_DEBUT and DEPART_Bus_Ouest == CONST_PARCOURS_TERMINE and ARRIVEE_Bus_Ouest == CONST_PARCOURS_TERMINE then
		ARRIVEE_Tram_Ouest = CONST_PARCOURS_DEBUT
		EEPSetSignal(1, CONST_VOIE_LIBRE)
		EEPSetSwitch(6, CONST_EMBRANCHEMENT)
	end
	
	Result, Occupe30, Name30 = EEPIsRoadTrackReserved(30, true)
	if Occupe30 == true then
		local strCategorieVehicule = string.sub(Name30, string.find(Name30, "%a+"))

		if string.upper(strCategorieVehicule) == "BUS" and ARRIVEE_Tram_Ouest == CONST_PARCOURS_TERMINE then
				EEPSetSwitch(16, CONST_EMBRANCHEMENT)
				ARRIVEE_Bus_Ouest = CONST_PARCOURS_DEBUT
			else
				EEPSetSwitch(16, CONST_BRANCHE_PRINCIPALE)
		end
	end
	EEPSetSignal(14, CONST_VOIE_LIBRE, 1)

end	-- Fin de la fonction fncFinDepartBusOuest


							------------------------------------------
							-- FONCTIONS DE RAPPEL POUR LES SIGNAUX --
							------------------------------------------

function EEPOnSignal_7(hEtat)

	if hEtat == CONST_VOIE_LIBRE then
		DEPART_Tram_Ouest = CONST_PARCOURS_DEBUT
		-- Commute l'aiguillage n° 6 sur Branche Principale
		EEPSetSwitch(6, CONST_BRANCHE_PRINCIPALE)
	end

end


function EEPOnSignal_9(hEtat)

	if hEtat == CONST_VOIE_LIBRE then
		-- Le tramway bleu peut quitter la gare routière
		-- Positionne le parcours DEPART_Tram_Est sur DEBUT
		DEPART_Tram_Est = CONST_PARCOURS_DEBUT
		-- Commute l'aiguillage n° 5 sur Embranchement
		EEPSetSwitch(5, CONST_EMBRANCHEMENT)
	end

end


function EEPOnSignal_4(hEtat)

	if hEtat == CONST_VOIE_LIBRE then
		-- Positionne le parcours DEPART_Bus_Est sur DEBUT			
		DEPART_Bus_Est = CONST_PARCOURS_DEBUT
		-- Commute le signal n° 11 sur arrêt
		EEPSetSignal(11, CONST_ARRET)
		-- Commute l'aiguillage n° 18 sur embranchement			
		EEPSetSwitch(18, CONST_EMBRANCHEMENT)
	end

end


function EEPOnSignal_12(hEtat)

	if hEtat == CONST_VOIE_LIBRE then
		EEPSetSignal(1, CONST_ARRET)
		EEPSetSignal(14, CONST_ARRET)
		EEPSetSignal(19, CONST_ARRET, 1)
		EEPSetSwitch(15, CONST_EMBRANCHEMENT)
		DEPART_Bus_Ouest = CONST_PARCOURS_DEBUT
	end

end

Nous allons commencer par détailler les premières parties du script :

  1. La déclaration des constantes,
  2. La déclaration des variables globales,
  3. L’enregistrement des 6 segments de voies et des 4 signaux.
La déclaration des constantes
Cliquez sur le bouton à droite pour copier ce code dans le presse-papier
-- Efface la fenêtre d'évènements
clearlog()

-- Constantes des différents statuts des parcours
CONST_PARCOURS_DEBUT = 1
CONST_PARCOURS_TERMINE = 10
-- Constantes pour les signaux
CONST_VOIE_LIBRE = 1
CONST_ARRET = 2
-- Constantes pour les aiguillages
CONST_BRANCHE_PRINCIPALE = 1
CONST_EMBRANCHEMENT = 2

Ici, nous commençons la déclaration des constantes des parcours, des signaux et des aiguillages.

Note : avec Lua, à l’inverse d’autres langages informatiques, il n’existe pas de mot clé Const pour déclarer les constantes. Toutefois, nous respecterons la convention d’écriture des constantes en majuscules.

Pour les constantes, les numéros des statuts concernant les parcours ont été choisis arbitrairement avec les valeurs 1 et 10. Pour les constantes des signaux et des aiguillages, il faut respecter l’ordre d’affichage des positions des signaux tels qu’ils apparaissent dans la liste déroulante Position dans la fenêtre des propriétés (voir figure n° 4). Ainsi lorsque nous ferons appel aux fonctions EEP, nous passerons en paramètre ces constantes en lieu et place des numéros ce qui sera plus explicite.

Tram Bus et Voitures avec Lua, figure 4
Figure n° 4
Important : Veuillez notez qu’en fonction des signaux installés dans vos réseaux, vous pouvez trouver plusieurs positions possibles. Face à la multitude des signaux, ceux-ci n'ont pas la même position pour une même fonction. Dans ce cas, il convient de s’assurer du numéro exact de la position en regardant directement dans les propriétés du signal correspondant.
La déclaration des variables globales
Cliquez sur le bouton à droite pour copier ce code dans le presse-papier
-- Variables pour les mouvements des véhicules (Bus et Tramways)
-- Par défaut, tous les parcours sont positionnés sur TERMINE
-- (Partie Est = partie droite du réseau)
DEPART_Bus_Est = CONST_PARCOURS_TERMINE
DEPART_Tram_Est = CONST_PARCOURS_TERMINE
ARRIVEE_Tram_Est = CONST_PARCOURS_TERMINE
ARRIVEE_Bus_Est = CONST_PARCOURS_TERMINE
-- (Partie Ouest = partie gauche du réseau)
DEPART_Bus_Ouest = CONST_PARCOURS_TERMINE
DEPART_Tram_Ouest = CONST_PARCOURS_TERMINE
ARRIVEE_Bus_Ouest = CONST_PARCOURS_TERMINE
ARRIVEE_Tram_Ouest = CONST_PARCOURS_TERMINE

Ici, nos 8 variables pour les parcours sont globales et visibles dans toutes les fonctions du script. Elles sont définies par défaut sur CONST_PARCOURS_TERMINE. Par la suite il suffira ainsi de cliquer sur un des deux signaux dans la gare des tramways pour initialiser le processus de circulation avec la constante CONST_PARCOURS_DEBUT.

L'enregistrement des 6 segments de voies et des 4 signaux
Cliquez sur le bouton à droite pour copier ce code dans le presse-papier
-- ENREGISTREMENT DES 6 SEGMENTS DE VOIES --
-- Segment devant le feu tricolore Entree bus côté Ouest
EEPRegisterRoadTrack(30)
-- Segment devant le feu tricolore Entree bus côté Est
EEPRegisterRoadTrack(42)
-- Segment devant le feu tricolore sortie bus côté Est
EEPRegisterRoadTrack(66)
-- Segment devant le feu tricolore sortie bus côté Ouest
EEPRegisterRoadTrack(70)

-- Segment devant le signal du tramway côté Est dans la gare routière
EEPRegisterTramTrack(31)
-- Segment devant le signal du tramway côté Ouest dans la gare routière
EEPRegisterTramTrack(22)

-- Enregistrement des signaux pour gérer les évènements
-- dans les fonctions de rappel
EEPRegisterSignal(4)
EEPRegisterSignal(7)
EEPRegisterSignal(9)
EEPRegisterSignal(12)

Nous devons enregistrer les segments à tester pour récupérer certaines informations lorsque les véhicules occuperont ces segments. Nous procédons également à l’enregistrement de 4 signaux pour exploiter les fonctions de rappels correspondantes. En effet, le fait d’intégrer le paramétrage adéquat des signaux et des aiguillages dans les fonctions de rappel, permettra de gérer également la circulation manuellement en cliquant directement sur les signaux concernés.

Avant de nous intéresser aux points de contact, nous allons réfléchir et énumérer où, quand et comment les actions doivent être exécutées par le script (je vous rappelle que nous traitons uniquement le côté Est pour l’instant) :

  1. Nous savons qu’à partir du moment où notre tramway sort de la gare, les bus censés entrer ou sortir de la gare routière doivent attendre que celui-ci quitte la gare, les tramways étant prioritaires par rapport au bus,
  2. Nous devons vérifier au moment qu’un bus veut entrer dans la gare routière si un tramway entre ou sort de la gare et le cas échéant, commuter les signaux en conséquence,
  3. Lorsqu’un bus entre ou sort de la gare, nous devons arrêter la circulation des voitures,
  4. Bien entendu, les tramways ne peuvent pas circuler simultanément hors de la gare vu qu’il n’y a qu’une voie unique.

Finalement, le point commun entre tous ces mouvements est l’entrée et la sortie des tramways et des bus. Il y a bien un début de parcours et une fin de parcours à un moment donné. Voilà pourquoi nous avons nos 2 constantes CONST_PARCOURS_DEBUT et CONST_PARCOURS_TERMINE affectées aux 4 binômes des variables globales DEPART_Bus_Est, ARRIVEE_Bus_Est, etc…

Alors où positionner tous ces points de contacts ? Rien de plus facile, il suffit de regarder attentivement la figure n° 5 ci-dessous (vous pouvez télécharger également l’image grand format) :

Tram Bus et Voitures avec Lua, figure 5
Figure n° 5
Important : dans l’image ci-dessus, remarquez bien le sens de circulation des points de contacts pour les fonctions Lua associées.
Les points de contacts véhicules

Avant de continuer à découvrir le script, attardons-nous sur les points de contacts et pour commencer, regroupons les fonctions classées par binômes :

  1. fncTramEntreeEst : cette fonction est appelée par le point de contact posé sur la voie du tramway tout à droite de l’image,
  2. fncFinTramEntreeEst : cette fonction est appelée par le point de contact posé sur la voie du tramway dans la gare.
  1. fncBusEntreeEst : cette fonction est appelée par le point de contact posé sur l’axe routier principal tout à droite de l’image (devant la voiture rouge),
  2. fncFinBusEntreeEst : cette fonction est appelée par le point de contact posé sur la voie routière dans la gare vers la fin de la courbe.
  1. fncDepartBusEst : cette fonction est appelée par le point de contact posé sur la voie routière dans la gare (au dessus du signal n° 4),
  2. fncFinDepartBusEst : cette fonction est appelée par le point de contact posé sur l’axe routier principal dans le sens de circulation, à droite.

Vous remarquerez également un point de contact (couleur marron) utilisé comme régulateur de vitesse fixée à 30 km/h uniquement pour les tramways. Ce point de contact réagit dans les deux sens de circulation. Ainsi, le tramway entrant voit sa vitesse réduite à 30 km/h pour entrer dans la gare alors que le tramway sortant, au début de son parcours roulera au maximum à cette vitesse.

Tram Bus et Voitures avec Lua, figure 6
Figure n° 6

Concernant le tramway sortant, le point de contact appelant la fonction fncFinTramSortieEst en profite également pour augmenter la vitesse du tramway à 60 km/h, vu que celui-ci se situe maintenant sur le tronçon principal.

Les points de contacts des signaux

Les points de contacts rouges sont là pour commuter les signaux (Tramways et Bus) sur arrêt dès que le signal correspondant a été franchi. Cela nous simplifie la vie et nous évite d’écrire une fonction Lua spécifique pour réaliser ce travail. Bien-sûr, pour les tramways et justement parce qu’il n’y a que des tramways circulant sur les rails, il est inutile de s’intéresser au type de véhicule. Mais qu’en est-il des bus qui partagent l’axe routier principal avec les voitures ?

Il est bien évident que seuls les bus peuvent commuter les signaux vu que les voitures restent toujours sur l’axe principal. Alors comment faire ? Il suffit de regarder la fenêtre des propriétés du signal n° 13 pour obtenir la réponse :

Tram Bus et Voitures avec Lua, figure 7
Figure n° 7

Dans l’encadré rouge, l’utilisation du filtre s’avère particulièrement pertinente dans notre cas. Nous pourrions parfaitement obtenir la même chose à partir d’une fonction Lua spécifique pour filtrer le nom du véhicule et commuter le signal sur Arrêt. Mais ici, notre point de contact exécute le travail à notre place alors nous n’allons pas nous en priver.

Pour que le filtre soit opérationnel, il faut commencer par le signe # suivi des caractères que nous voulons capturer et ça tombe plutôt bien, car nous voulons que le contact réagisse au mot-clé Bus. Donc à chaque passage d’un véhicule sur le contact, celui-ci testera si le nom commence par Bus et ignorera tous les caractères situés à droite à partir du trait de soulignement. La casse des caractères n’a ici aucune importance.

Si le nom du véhicule commence par Bus, alors le contact commutera le signal n° 13 sur la position Arrêt. Dans tous les autres cas, le contact sera purement et simplement ignoré et la position du signal restera inchangée.

A partir de maintenant, nous allons commencer par étudier les fonctions une par une dans l’ordre du script.

Le binôme fncTramEntreeEst - fncFinTramEntreeEst

Ces deux fonctions, travaillent en tandem, c’est-à-dire lorsque le tramway bleu (dans le sens droite-gauche) veut entrer dans la gare, il déclenche l’appel de la fonction fncTramEntreeEst par l’intermédiaire d’un point de contact pour véhicule. Tant que le tramway n’a pas franchi l’autre point de contact (pour appeler la fonction fncFinTramEntreeEst), les bus ne peuvent ni entrer, ni sortir de la gare routière et par conséquent ne peuvent franchir le croisement route-rails du tramway.

Détail de la fonction fncTramEntreeEst
Cliquez sur le bouton à droite pour copier ce code dans le presse-papier
-- Cette fonction est activée par le tramway jaune via un point de contact à l'entrée de la gare côté est
function fncTramEntreeEst()

	-- Positionne le parcours ARRIVEE_Tram_Est sur DEBUT
	ARRIVEE_Tram_Est = CONST_PARCOURS_DEBUT

	-- Si aucun bus ne quitte ou n'arrive dans la gare routière alors...
	if DEPART_Bus_Est == CONST_PARCOURS_TERMINE and ARRIVEE_Bus_Est == CONST_PARCOURS_TERMINE then
			-- Le tramway jaune peut rentrer dans la gare routière
			-- Commute le signal n° 10 du tramway sur voie Libre
			EEPSetSignal(10, CONST_VOIE_LIBRE, 1)
			-- Commute l'aiguillage n° 5 sur Branche Principale
			EEPSetSwitch(5, CONST_BRANCHE_PRINCIPALE)
		else
			-- ...sinon un bus quitte ou arrive dans la gare routière
			-- et commute le signal n° 10 du tramway sur arrêt
			EEPSetSignal(10, CONST_ARRET, 1)
	end	

end	-- Fin de la fonction fncTramEntreeEst
  1. Le tramway arrive du côté Est pour préparer son entrée dans la gare. On renseigne la variable ARRIVEE_Tram_Est avec la constante CONST_PARCOURS_DEBUT (ligne n° 66),
  2. La priorité est donnée aux tramways, néanmoins, nous devons tester si les bus ne sont pas déjà en mouvement pour sortir ou entrer dans la gare côté Est. Si tel était le cas, les deux variables DEPART_Bus_Est ou ARRIVEE_Bus_Est seraient égales à CONST_PARCOURS_DEBUT. Ici, dans le cas contraire, elles doivent être toutes les deux égales à CONST_PARCOURS_TERMINE. Remarquez le mot clé and dans la condition du test (ligne n° 69). Ce mot clé indique que les deux variables testées doivent retourner toutes les deux la valeur true (vraie) pour que le bloc qui suit immédiatement le test soit exécuté.
  3. Ainsi si nos deux variables sont égales à CONST_PARCOURS_TERMINE, on commute le signal n° 10 sur Voie libre ainsi que l’aiguillage n° 5 sur Branche Principale (lignes n° 72 et 74),
  4. Sinon, si une ou les deux variables ne sont pas égales à CONST_PARCOURS_TERMINE, le programme passe au bloc suivant situé immédiatement après le mot clé else et le signal n° 10 est commuté sur Arrêt (ligne n° 78),
  5. La fonction est maintenant terminée.
Détail de la fonction fncFinTramEntreeEst
Cliquez sur le bouton à droite pour copier ce code dans le presse-papier
-- Cette fonction est activée via un point de contact par le tramway jaune
-- lorsque celui-ci rentre dans la gare côté est
function fncFinTramEntreeEst()

	-- Positionne le parcours ARRIVEE_Tram_Est sur TERMINE
	ARRIVEE_Tram_Est = CONST_PARCOURS_TERMINE
	
	-- Si aucun bus ne quitte ou n'arrive dans la gare routière alors...
	if DEPART_Bus_Est == CONST_PARCOURS_TERMINE and ARRIVEE_Bus_Est == CONST_PARCOURS_TERMINE then
		-- Commute le signal n° 9 du tramway sur voie Libre
		EEPSetSignal(9, CONST_VOIE_LIBRE, 1)
		-- Les autres signaux sont commutés directement dans la fonction de rappel du signal n° 9
	end

end	-- Fin de la fonction fncFinTramEntreeEst
  1. Le tramway est maintenant entré complètement dans la gare. On renseigne la variable ARRIVEE_Tram_Est avec la constante CONST_PARCOURS_TERMINE (ligne n° 89),
  2. La priorité est donnée aux tramways, néanmoins, nous devons tester si les bus ne sont pas déjà en mouvement pour sortir ou entrer dans la gare côté Est. Si tel était le cas, les deux variables DEPART_Bus_Est ou ARRIVEE_Bus_Est seraient égales à CONST_PARCOURS_DEBUT. Remarquez le mot clé and dans la condition du test (ligne n° 92). Ce mot clé indique que les deux variables testées doivent retourner toutes les deux la valeur CONST_PARCOURS_TERMINE pour que la condition soit vrai et le bloc qui suit immédiatement soit exécuté,
  3. Ainsi, si nos deux variables sont égales à CONST_PARCOURS_TERMINE, on commute le signal n° 9 sur Voie libre (ligne n° 94). Dans le cas contraire, rien ne se passe et la fonction se termine.

Il est temps maintenant de s’intéresser aux fonctions de rappel. A quoi servent-elles et pourquoi. Ici les deux conditions qui constituent le test retournent la valeur true (vraie), ce qui a pour effet de commuter le signal n° 9 sur Voie Libre. Rappelez-vous au début du script, nous avions enregistré 4 signaux dont le n° 9. En effet, EEP nous permet d’enregistrer grâce à la fonction EEPRegisterSignal, n’importe quel signal d’un projet. Il suffit juste d’indiquer le n° du signal correspondant entre parenthèses et le tour est joué.

Or, lorsqu’un signal est enregistré, chaque changement de son état induit l’appel automatique à la fonction dite de rappel EEPOnSignal_9(hEtat). Vous l’aurez compris, le chiffre 9 correspond au n° du signal concerné. La variable hEtat entre parenthèse retourne l’état (la position) du signal à chaque fois que celui-ci est modifié.

Pour reprendre le fil de notre fonction fncFinTramEntreeEst, le signal n° 9 a été commuté sur Voie libre. Donc à ce moment précis, la fonction de rappel EEPOnSignal_9(hEtat) a été exécutée. Voyons maintenant ce qu’elle contient :

Cliquez sur le bouton à droite pour copier ce code dans le presse-papier
function EEPOnSignal_9(hEtat)

	if hEtat == CONST_VOIE_LIBRE then
		-- Le tramway bleu peut quitter la gare routière
		-- Positionne le parcours DEPART_Tram_Est sur DEBUT
		DEPART_Tram_Est = CONST_PARCOURS_DEBUT
		-- Commute l'aiguillage n° 5 sur Embranchement
		EEPSetSwitch(5, CONST_EMBRANCHEMENT)
	end

end

Ici on teste dans un premier temps si le signal est commuté sur Voie Libre. Si c’est le cas alors on renseigne la variable DEPART_Tram_Est avec la constante CONST_PARCOURS_DEBUT et on commute l’aiguillage n° 5 sur embranchement. A ce stade, on peut se demander pourquoi ne pas écrire également ces lignes de code dans la fonction fncFinTramEntreeEst ? Et bien tout simplement parce que vous allez pouvoir exécuter directement cette fonction si vous commutez manuellement le signal dans EEP en cliquant sur celui-ci tout en maintenant la touche Shift enfoncée.

Si le code de la fonction de rappel était restée dans la fonction fncFinTramEntreeEst, seul le tramway bleu pourrait l’exécuter. Le fait de déplacer le code dans la fonction de rappel nous offre une souplesse d’utilisation et des possibilités d’exploitation plus larges.

Détail de la fonction fncFinTramSortieEst
Cliquez sur le bouton à droite pour copier ce code dans le presse-papier
-- Cette fonction est activée via un point de contact par le tramway bleu
-- lorsque celui-ci a dépassé le croisement routier côté est
function fncFinTramSortieEst()

	-- Positionne le parcours DEPART_Tram_Est sur TERMINE
	DEPART_Tram_Est = CONST_PARCOURS_TERMINE

	-- Récupére les informations du segment 42 (ID voie 42 avec signal n° 13)
	Result, Occupe42, Name42 = EEPIsRoadTrackReserved(42, true)
	-- Récupére les informations du segment 66 (ID voie 66 avec signal n° 4)
	Result, Occupe66, Name66 = EEPIsRoadTrackReserved(66, true)
	-- Si un véhicule occupe le segment routier n° 42
	if Occupe42 == true then
			local strCategorieVehicule = string.sub(Name42, string.find(Name42, "%a+"))

			-- Extrait le nom du véhicule (variable Name42) présent sur le segment dans la variable strCategorieVehicule
			-- Explications %a+. %a = N'importe quelle lettre et uniquement que des lettres ! + = un ou plusieurs caractères
			-- Utilisation du mot clé upper pour transformer la chaine de caractères en majuscules quelque soit
			-- la casse des caractères utilisée lors du nom donné au véhicule au moment de sa création (Bus, bUs, buS...)
			-- Si le nom du véhicule commence par Bus alors...
			if string.upper(strCategorieVehicule) == "BUS" then					
					-- Positionne le parcours ARRIVEE_Bus_Est sur DEBUT
					ARRIVEE_Bus_Est = CONST_PARCOURS_DEBUT
					-- Commute le signal n° 11 (feu tricolore) sur arrêt
					EEPSetSignal(11, CONST_ARRET)
					-- Commute l'aiguillage n° 17 sur Embranchement
					EEPSetSwitch(17, CONST_EMBRANCHEMENT)
				else
				-- ...Sinon on teste la condition si le bus jaune était entré juste avant le tramway jaune alors que ce dernier a déjà franchi le point de contact fncTramEntreeEst.
					-- Lorsque le bus jaune avait franchi le point de contact fncFinBusEntreeEst, le bus blanc ne pouvait pas démarrer car le tramway jaune entrait à son tour dans la gare.
					-- Il incombe ainsi au tramway bleu une fois sorti de la gare, de vérifier si le bus blanc est arrêté devant le signal n° 4
					if Occupe66 == true then
						-- Commute le signal n° 4 sur voie libre
						EEPSetSignal(4, CONST_VOIE_LIBRE, 1)
						-- Les autres signaux sont commutés directement dans la fonction de rappel du signal n° 4
					end
			end
			
			-- Dans les 2 cas, commute le signal n° 13 (feu tricolore) sur voie Libre
			EEPSetSignal(13, CONST_VOIE_LIBRE)

		else
		
			-- Idem que le test ci-dessus sauf que le segment n° 42 n'était pas occupé
			if Occupe66 == true then
				-- Commute le signal n° 4 sur voie libre
				EEPSetSignal(4, CONST_VOIE_LIBRE, 1)
				-- Les autres signaux sont commutés directement dans la fonction de rappel du signal n° 4
			end
		
	end
		
end	-- Fin de la fonction fncFinTramSortieEst

Cette fonction est appelée (via un point de contact véhicule) lorsque le tramway bleu a rejoint le tronçon principal et comme déjà énoncé plus haut, la vitesse du tramway est fixée à 60 km/h. Nous allons maintenant découvrir de nouvelles fonctionnalités intéressantes !

  • Le tramway a dépassé le croisement côté Est et a rejoint le tronçon principal. On renseigne la variable DEPART_Tram_Est avec la constante CONST_PARCOURS_TERMINE (ligne n° 106),
  • Désormais, nous devons tester quel type de véhicule est arrêté devant le feu rouge (signal n° 13). En effet, le temps que notre tramway démarre et sort de la gare, peut-être que notre bus jaune a pu se présenter devant la bifurcation pour entrer dans la gare, mais comme le signal n° 13 (feu tricolore), est positionné sur Arrêt (au feu rouge), grâce à la fonction fncBusEntreeEst (à venir plus bas), nous devons maintenant laisser notre bus jaune entrer dans la gare routière.

Pour tester quel type de véhicule est arrêté devant le feu rouge, nous allons faire appel à la fonction EEP EEPIsRoadTrackReserved. Tout d’abord, pour que cette fonction retourne les valeurs souhaitées, il faut enregistrer l’ID du segment concerné. Ici dans notre cas, il s’agit du segment n°42 (celui du signal n° 13). Comment EEP enregistre t’il le segment ? Tout simplement en utilisant la fonction EEP EEPRegisterRoadTrack(42) comme nous l’avons fait dans la section enregistrement des segments de voies et des signaux au début du script.

Alors que fait exactement cette fonction EEPIsRoadTrackReserved(42, true) ? C’est simple, elle contient 2 arguments (entre les parenthèses) et retourne 3 valeurs qui seront stockées dans les 3 variables suivantes : Result, Occupe42, Name42 (ligne n° 109).

Explication : pour commencer, nous devons passer deux arguments qui sont, l’ID du segment concerné (ici, le n° 42) et le mot clé true. Pourquoi true ? pour récupérer dans la 3ème variable Name42, le nom du véhicule occupant le segment. Si vous omettez ce 2ème argument, le nom du véhicule ne sera pas retourné. A ce stade, nous avons récupéré les valeurs retournées dans nos 3 variables alors regardons de plus près quelles sont les informations contenues à l’intérieur de celles-ci :

  1. La valeur retournée dans la variable Result est égale à true si le segment existe sinon false dans le cas contraire. naturellement dans notre cas, le segment existe bel et bien. Ce qui explique pourquoi nous n’avons pas l’utilité de tester le résultat. Même si nous n'avons pas besoin de tester la valeur de cette variable, elle doit quand même être présente lors de l'appel de la fonction EEPIsRoadTrackReserved.
  2. La valeur retournée dans la variable Occupe42 va nous indiquer si le segment est occupé par un véhicule. Cette valeur est importante pour notre fonction donc nous allons la tester après,
  3. La valeur retournée dans la variable Name42 va nous donner le nom du véhicule si celui-ci occupe le segment n°42. Dans le cas contraire, la valeur retournée sera une chaine vide.

Nous allons faire la même chose que ci-dessus avec le segment de voie numéro 66. La valeur retournée dans la variable Occupe66 va nous indiquer si le segment situé dans la gare routière à la position du signal n° 4, est occupé par le bus blanc (ligne n° 111).

C’est parti ! à la ligne n° 113 nous testons la valeur de la variable Occupe42. Si la valeur est égale à true alors un véhicule occupe le segment n° 42, mais nous avons besoin de connaitre quel type de véhicule se trouve sur ce segment. En effet, rappelez-vous, seuls les bus sont habilités à rentrer dans la gare routière, les voitures quant à elles restent toujours sur l’axe routier principal.

Alors comment allons-nous faire pour récupérer le nom du véhicule stocké dans la variable Name42 ? Tout d’abord, voici à nouveau la ligne n° 114 :

local strCategorieVehicule = string.sub(Name42, string.find(Name42, "%a+"))

Ici plusieurs paramètres méritent quelques explications :

  1. Tout d’abord, on déclare une variable locale nommée strCategorieVehicule. Elle va nous servir tout simplement à stocker le nom du véhicule,
  2. Ensuite, on utilise la fonction du langage Lua string.sub qui contient 2 arguments. Le premier est le nom de la variable à tester, ici il s’agit bien entendu de Name42. Ensuite, le 2ème argument contient une autre fonction Lua string.find qui va nous permettre de rechercher une chaine de caractères à partir du motif ‘%a+’ contenu entre guillemets. Euh… quel est cet intru ? continuons l’explication...
  3. La fonction string.sub retourne une sous-chaine contenue dans la variable Name42 correspondant au motif trouvé par la fonction Lua string.find. Cette dernière, recherche des caractères dans la variable Name42. Mais pas n’importe quels caractères ! Uniquement des lettres et seulement des lettres grâce au motif %a+ !
  4. Décomposition du motif : %a+ = n’importe quelle lettre et uniquement des lettres, le signe + demande à la fonction string.find de continuer la recherche tant que des lettres sont trouvées. Par contre, dès qu’un caractère autre qu'une lettre comme le trait de soulignement ou même un chiffre est rencontré, la fonction arrête immédiatement la recherche et retourne uniquement tout ce qu’elle a trouvé avant de rencontrer le trait de soulignement. Bref, tout ça pour dire ceci : tout ce qui ne correspond plus à des lettres est ignoré et la fonction arrête net sa recherche. Le résultat retourné est ensuite stocké dans la variable locale strCategorieVehicule.
  5. Ici le motif (ou pattern) %a+ est ni plus ni moins qu’une Regex ou expression régulière. Tapez expression régulière ou regex dans un moteur de recherche et vous serez surpris des possibilités offertes par cette fonctionnalité.
Note : pour information, toutes les variables déclarées avec le mot clé local sont uniquement locales à la fonction. Ce qui veut dire que la variable ne sera pas visible et utilisable dans une autre partie du script. Les variables locales sont moins gourmandes en ressources que les variables globales.

Lorsque nous avons ajouté les bus pour la première fois sur le réseau, EEP nous a demandé de les nommer. Ils s’appellent Bus_Jaune et Bus_Blanc. Maintenant, la réponse devient évidente, tout ce qui était avant le trait de soulignement a été capturé, donc si un bus occupait le segment n° 42 à l’arrêt au feu rouge, notre variable strCategorieVehicule contient uniquement le mot Bus.

Maintenant, nous allons anticiper et éliminer un problème éventuel : imaginons que nous avons nommé notre modèle bUs_Jaune ou buS_Jaune ou encore bUS_Jaune, comme le test d’égalité est sensible à la casse des caractères, bUs ne sera jamais égal à Bus ou buS ! Donc, pour éviter tout dysfonctionnement, nous allons dans le test d’égalité, utiliser la fonction Lua string.upper(strCategorieVehicule) dans l’opérande de gauche qui va transformer automatiquement notre chaine de caractères en majuscules indépendamment de la saisie. Ainsi, il nous reste plus qu’à indiquer dans l’opérande de droite, la chaine BUS en majuscules et entre guillemets pour tester à coup sûr qu’il s’agit bien du mot clé Bus (ligne n° 121).

Ainsi, si strCategorieVehicule contient le mot clé Bus alors la condition if string.upper(strCategorieVehicule) == « BUS » then est vraie (ligne n° 121), l’exécution continue immédiatement au bloc d’instructions situé juste en dessous de la ligne et effectue les opérations suivantes (lignes n° 122 à 127) :

  1. On renseigne la variable ARRIVEE_Bus_Est avec la constante CONST_PARCOURS_DEBUT. En effet, le bus va entrer dans la gare routière,
  2. Commute le signal n° 11 (feu tricolore) sur Arrêt grâce à la fonction EEP EEPSetSignal(11, CONST_ARRET). En effet, les voitures circulant en sens inverse doivent s’arrêter au feu rouge pour laisser entrer le bus jaune dans la gare routière,
  3. Commute l’aiguillage n° 17 sur Embranchement grâce à la fonction EEPSetSwitch(17, CONST_EMBRANCHEMENT).

Dans les 2 cas, bus ou pas, la ligne n° 140 commute le signal n° 13 (feu tricolore) sur Voie Libre grâce à la fonction EEP EEPSetSignal(13, CONST_VOIE_LIBRE).

Si le mot clé stocké dans la variable strCategorieVehicule n’était pas égal à Bus alors la deuxième partie du test située après le mot clé else serait exécutée. 

Important : Comparons la lignes n° 125 : EEPSetSignal(11, CONST_ARRET) et la ligne n° 134 : EEPSetSignal(4, CONST_VOIE_LIBRE, 1). La deuxième utilise un 3ème argument facultatif (avec le chiffre 1) qui appelle automatiquement la fonction de rappel EEP EEPOnSignal_4(hEtat) à chaque fois que la position du signal change. Si vous omettez ce 3ème argument, la fonction de rappel ne sera jamais exécutée. Référez-vous au manuel Lua pour plus d'informations.

Nous allons maintenant considérer l’éventualité suivante : si le bus jaune franchi le point de contact fncBusEntreeEst quelques mètres avant le franchissement du point de contact fncTramEntreeEst par le tramway jaune, que se passe-il ? La fonction fncBusEntreeEst appelée en premier par le bus jaune affecte à la variable ARRIVEE_Bus_Est la valeur de la constante CONST_PARCOURS_DEBUT et commute en conséquence le signal n° 10 sur Arrêt.

Il faut bien comprendre ici que notre bus jaune a ‘volé‘ la priorité du tramway jaune et donc celui-ci va entrer dans la gare routière en premier et va franchir ensuite le point de contact fncFinBusEntreeEst. Nous allons détailler cette fonction plus loin dans ce tutoriel mais retenez pour le moment que celle-ci est chargée de tester la variable ARRIVEE_Tram_Est. Dans ce cas précis, cette variable contient tout naturellement la valeur de la constante CONST_PARCOURS_DEBUT vu que notre tramway jaune a lui aussi franchi le point de contact fncTramEntreeEst avant d’être stoppé devant le signal n° 1.

Par déduction, comme les tramways sont prioritaires sur les bus, la fonction fncFinBusEntreeEst va prioriser l’entrée du tramway en lieu et place du bus blanc comme dans le schéma de circulation habituel. Bien-sûr, dans le cas contraire, la fonction aurait validé le départ du bus blanc.

Il incombe ainsi au tramway bleu une fois sorti de la gare, de vérifier si le bus blanc est arrêté devant le signal n° 4. Si la variable Occupe66 est égale à true (vrai) alors on commute le signal n° 4 sur Voie Libre (qui au passage va appeler la fonction de rappel du signal n° 4) et le bus blanc va démarrer (ligne n° 134).

Maintenant, il nous reste à traiter le dernier cas ! En fait, il est strictement identique à la seconde partie du test ci-dessus. La seule différence (au moment où le tramway bleu franchi le point de contact lié à notre fonction fncFinTramSortieEst) réside dans le fait que le segment n° 42 précisément à ce moment là, est libre de toute occupation de véhicule.

Arrivé à ce stade, nous avons atteint la fin de la fonction.

Information : avant de continuer, retenons bien ceci : nous avons 3 fonctions pour la gestion des tramways et 4 fonctions pour la gestion des bus. En effet, pour les tramways, la fonction fncFinTramEntreeEst gère l’arrivée du tramway jaune et le départ du tramway bleu. Pour les bus, l’arrivée et le départ sont séparés via deux fonctions distinctes. Pourquoi ? pour démontrer plusieurs méthodes possibles afin d’ajouter par exemple, de nouvelles fonctionnalités. Ici, on pourrait par exemple (pour les bus), introduire des possibilités supplémentaires (comme l’affichage des destinations dans des panneaux d’information) entre l’arrivée et le départ d’un bus. Evidemment, cela induirait des lignes de codes additionnelles et vouloir tout écrire dans une seule fonction nuirait à la lisibilité du code.

Nous avons terminé avec les fonctions des tramways. Nous allons maintenant nous intéresser aux fonctions qui gèrent les mouvements des bus.

Le binôme fncBusEntreeEst - fncFinBusEntreeEst

Ces deux fonctions, travaillent en tandem, c’est-à-dire lorsque le bus jaune (dans le sens droite-gauche) veut entrer dans la gare routière, il déclenche l’appel de la fonction fncBusEntreeEst par l’intermédiaire d’un point de contact pour véhicule. Tant que le bus n’a pas franchi l’autre point de contact (appelle la fonction fncFinBusEntreeEst), les tramways doivent attendre pour entrer ou sortir de la gare et par conséquent ne peuvent franchir le croisement route-rails du tramway.

Détail de la fonction fncBusEntreeEst
Cliquez sur le bouton à droite pour copier ce code dans le presse-papier
-- Cette fonction est activée via un point de contact par le bus jaune
-- lorsque celui-ci doit entrer dans la gare routière
function fncBusEntreeEst()

	-- Si aucun tram quitte ou arrive dans la gare alors...
	if ARRIVEE_Tram_Est == CONST_PARCOURS_TERMINE and DEPART_Tram_Est == CONST_PARCOURS_TERMINE then
			-- Positionne le parcours ARRIVEE_Bus_Est sur DEBUT
			ARRIVEE_Bus_Est = CONST_PARCOURS_DEBUT
			-- Commute le signal n° 11 (feu tricolore) sur arrêt
			EEPSetSignal(11, CONST_ARRET)
			-- Commute l'aiguillage n° 17 sur Embranchement
			EEPSetSwitch(17, CONST_EMBRANCHEMENT)

		else
			-- sinon un tram quitte ou arrive dans la gare et
			-- commute le feu tricolore (signal n° 13) au rouge
			EEPSetSignal(13, CONST_ARRET)			
	end

end	-- Fin de la fonction fncBusEntreeEst
  1. La priorité étant donnée aux tramways, nous devons tester si ceux-ci ne sont pas déjà en mouvement pour sortir ou entrer dans la gare côté Est. Si tel était le cas, les deux variables DEPART_Tram_Est ou ARRIVEE_Tram_Est seraient égales à CONST_PARCOURS_DEBUT. Ici dans le cas contraire, elles doivent être toutes les deux égales à CONST_PARCOURS_TERMINE. Remarquez le mot clé and dans la condition du test. Ce mot clé indique que les deux variables testées doivent retourner toutes les deux la valeur true (vraie) pour que le bloc d’instructions qui suit immédiatement le test soit exécuté (ligne n° 161).
  2. Ainsi, si nos deux variables sont égales à CONST_PARCOURS_TERMINE, on renseigne la variable ARRIVEE_Bus_Est avec la constante CONST_PARCOURS_DEBUT (ligne n° 163),
  3. On commute le signal n° 11 sur Voie libre ainsi que l’aiguillage n° 17 sur Embranchement (lignes n° 165 et 167),
  4. Inversement, si une ou les deux variables ne sont pas égales à CONST_PARCOURS_TERMINE, le programme passe au bloc suivant situé immédiatement après le mot clé else et le signal n° 13 est commuté sur Arrêt (feu rouge)  à la ligne n° 172,
  5. La fonction est maintenant terminée.
Détail de la fonction fncFinBusEntreeEst
Cliquez sur le bouton à droite pour copier ce code dans le presse-papier
-- Cette fonction est activée via un point de contact par le bus jaune
-- lorsque celui-ci vient juste de rentrer dans la gare routière côté Est
function fncFinBusEntreeEst()

	-- Positionne le parcours ARRIVEE_Bus_Est sur TERMINE
	ARRIVEE_Bus_Est = CONST_PARCOURS_TERMINE

	-- Si le tramway jaune est en attente devant le signal n° 10 alors...
	if ARRIVEE_Tram_Est == CONST_PARCOURS_DEBUT then
			-- ... Commute les signaux 10 et 11 sur Voie Libre
			EEPSetSignal(10, CONST_VOIE_LIBRE)
			EEPSetSignal(11, CONST_VOIE_LIBRE)
			-- Commute l'aiguillage n° 5 sur Branche Principale
			EEPSetSwitch(5, CONST_BRANCHE_PRINCIPALE)

		else
			-- Si pas de tramway en attente devant le signal n° 10 et si pas de bus blanc en attente devant le signal n° 4
			-- alors on commute l'aiguillage n° 17 sur Branche Principale et le signal n° 11 sur Voie Libre
			EEPSetSwitch(17, CONST_BRANCHE_PRINCIPALE)
			EEPSetSignal(11, CONST_VOIE_LIBRE)
	end

	-- Dans les 2 cas, commute le signal n° 13 (feu tricolore) sur voie Libre
	EEPSetSignal(13, CONST_VOIE_LIBRE)

end	-- Fin de la fonction fncBusEntreeEst
  1. Le bus est désormais totalement entré dans la gare routière. On renseigne la variable ARRIVEE_Bus_Est avec la constante CONST_PARCOURS_TERMINE (ligne n° 183),
  2. La priorité étant donnée aux tramways, nous allons tester si le tramway jaune est en attente derrière le signal n° 10 (ligne n° 188). Si tel est le cas, la variable ARRIVEE_Tram_Est est égale à la valeur de la constante CONST_PARCOURS_DEBUT car le tramway a déjà franchi le point de contact fncTramEntreeEst quelques secondes après le bus. Il nous alors reste à commuter les signaux 10 et 11 sur Voie Libre et l’aiguillage n° 5 sur Branche Principale (lignes n° 189 à 191),
  3. Dans le cas contraire, s’il n’y a pas de tramway en attente devant le signal n° 10 alors on commute l’aiguillage n° 17 sur Branche Principale et le signal n° 11 sur Voie Libre (lignes n° 196 et 197),
  4. Dans les 2 cas, bus ou pas, la ligne n° 201 commute le signal n° 13 (feu tricolore) sur Voie Libre grâce à la fonction EEP EEPSetSignal(13, CONST_VOIE_LIBRE).
  5. La fonction est maintenant terminée.
Le binôme fncDepartBusEst - fncFinDepartBusEst

Ces deux fonctions travaillent en tandem. Le processus est enclenché lorsque le bus jaune (dans le sens droite-gauche) est entré dans la gare routière, après avoir franchi le 1er point de contact fncBusEntreeEst.

Détail de la fonction fncDepartBusEst
Cliquez sur le bouton à droite pour copier ce code dans le presse-papier
-- Cette fonction est activée via un point de contact par le bus jaune lorsque
-- celui-ci est entré dans la gare routière dans le sens droite-gauche
function fncDepartBusEst()
	-- Test si le bus blanc se trouve sur le segment de route devant le feu tricolore (signal n° 4)
	Result, Occupe66, Name66 = EEPIsRoadTrackReserved(66, true)
	-- Si le bus blanc est à l'arrêt et si aucun tram ne quitte ou n'arrive dans la gare alors...
	if Occupe66 == true and DEPART_Tram_Est == CONST_PARCOURS_TERMINE and ARRIVEE_Tram_Est == CONST_PARCOURS_TERMINE then
		-- Commute le signal n° 4 sur voie libre
		EEPSetSignal(4, CONST_VOIE_LIBRE, 1)
		-- Les autres signaux sont commutés directement dans la fonction de rappel du signal n° 4
	end
end	-- Fin de la fonction fncDepartBusEst
  1. La priorité étant donnée aux tramways, nous devons tester si ceux-ci ne sont pas déjà en mouvement pour sortir ou entrer dans la gare côté Est. Si tel était le cas, les deux variables DEPART_Tram_Est ou ARRIVEE_Tram_Est seraient égales à CONST_PARCOURS_DEBUT. Ici dans le cas contraire, elles doivent être toutes les deux égales à CONST_PARCOURS_TERMINE. Remarquez le mot clé and dans la condition du test. Ce mot clé indique que les deux variables testées doivent retourner toutes les deux la valeur true (vraie) pour que le bloc d’instructions qui suit immédiatement le test soit exécuté (ligne n° 214),
  2. Ainsi, si nos deux variables sont égales à CONST_PARCOURS_TERMINE, on commute le signal n° 4 sur Voie Libre, ce qui aura pour effet d’appeler la fonction de rappel du signal n° 4 EEPOnSignal_4 (voir ci-dessous) et de commuter correctement les éléments concernés,
  3. La fonction est maintenant terminée.
Détail de la fonction de rappel EEPOnSignal_4
Cliquez sur le bouton à droite pour copier ce code dans le presse-papier
function EEPOnSignal_4(hEtat)

	if hEtat == CONST_VOIE_LIBRE then
		-- Positionne le parcours DEPART_Bus_Est sur DEBUT			
		DEPART_Bus_Est = CONST_PARCOURS_DEBUT
		-- Commute le signal n° 11 sur arrêt
		EEPSetSignal(11, CONST_ARRET)
		-- Commute l'aiguillage n° 18 sur embranchement			
		EEPSetSwitch(18, CONST_EMBRANCHEMENT)
	end

end

Cette fonction est appelée (d’où son nom : fonction de rappel) automatiquement à chaque fois que l’état du signal n° 4 change. Ce comportement est rendu possible étant donné que :

  1. Nous avons enregistré le signal n° 4 grâce à la fonction EEP EEPRegisterSignal(4) au début du script,
  2. Nous passons en 3ème paramètre le chiffre 1 dans tous les fonctions EEP EEPSetSignal(N° du signal, CONST_VOIE_LIBRE ou CONST_ARRET, 1)

Si ces deux conditions ne sont pas respectées, la fonction de rappel sera purement et simplement ignorée.

Important : Si vous entrez en 3ème paramètre le chiffre 1 alors que le signal correspondant n’a pas été préalablement enregistré au début du script, vous pouvez créer des dysfonctionnements voire à un plantage d’EEP. Pensez toujours à bien enregistrer vos signaux si vous utilisez les fonctions de rappel correspondantes !

L'argument hEtat entre parenthèses dans la déclaration de la fonction retourne l’état du signal lorsque la fonction est appelée.

Détail de la fonction fncFinDepartBusEst
Cliquez sur le bouton à droite pour copier ce code dans le presse-papier
-- Cette fonction est activée via un point de contact par le bus blanc
-- lorsque celui-ci vient de rentrer sur la route principale côté Est
function fncFinDepartBusEst()

	-- Positionne le parcours DEPART_Bus_Est sur TERMINE			
	DEPART_Bus_Est = CONST_PARCOURS_TERMINE

	-- Si le tramway jaune a déjà franchi le point de contact fncTramEntreeEst alors...
	if ARRIVEE_Tram_Est == CONST_PARCOURS_DEBUT then
			-- Commute les signaux 10 et 11 sur Voie Libre
			EEPSetSignal(10, CONST_VOIE_LIBRE)
			EEPSetSignal(11, CONST_VOIE_LIBRE)
			-- Commute l'aiguillage n° 5 sur Branche Principale
			EEPSetSwitch(5, CONST_BRANCHE_PRINCIPALE)
		else
			-- sinon on récupére les informations du segment n° 42
			Result, Occupe42, Name42 = EEPIsRoadTrackReserved(42, true)
			
			if Occupe42 == true then
					local strCategorieVehicule = string.sub(Name42, string.find(Name42, "%a+"))

					-- Si un véhicule occupe le segment routier n° 42 et s'il s'agit d'un bus alors...
					if string.upper(strCategorieVehicule) == "BUS" then					
							-- Positionne le parcours ARRIVEE_Bus_Est sur DEBUT
							ARRIVEE_Bus_Est = CONST_PARCOURS_DEBUT
							-- Commute le signal n° 11 (feu tricolore) sur arrêt
							EEPSetSignal(11, CONST_ARRET)
							-- Commute l'aiguillage n° 17 sur Embranchement
							EEPSetSwitch(17, CONST_EMBRANCHEMENT)
						else
							-- Commute le signal n° 11 (feu tricolore) sur Voie Libre
							EEPSetSignal(11, CONST_VOIE_LIBRE)
					end

				else
					-- Commute le signal n° 11 (feu tricolore) sur Voie Libre
					EEPSetSignal(11, CONST_VOIE_LIBRE)
			end
	end

end	-- Fin de la fonction fncFinDepartBusEst
  1. Le bus blanc est maintenant totalement sorti de la gare routière et a rejoint l’axe routier principal. On renseigne la variable ARRIVEE_Bus_Est avec la constante CONST_PARCOURS_TERMINE (ligne n° 225),
  2. La priorité étant donnée aux tramways, nous allons tester si le tramway jaune est en attente derrière le signal n° 10. Si tel est le cas, la variable ARRIVEE_Tram_Est est égale à la valeur de la constante CONST_PARCOURS_DEBUT car le tramway a déjà franchi le point de contact fncTramEntreeEst quelques secondes après le départ du bus. Il nous reste à commuter les signaux 10 et 11 sur Voie Libre et l’aiguillage n° 5 sur Branche Principale (lignes n° 230 à 233).
  3. Sinon, on récupère les informations du segment n° 42 pour vérifier s’il est occupé par un véhicule (ligne n° 236). Si le segment est occupé, on récupère le nom du véhicule dans la variable strCategorieVehicule (ligne n° 239).
  4. Si le test retourne true (vraie) alors on renseigne la variable ARRIVEE_Bus_Est avec la constante CONST_PARCOURS_DEBUT (ligne n° 244),
  5. On commute le signal n° 11 (feu tricolore) sur Arrêt grâce à la fonction EEPSetSignal(11, CONST_ARRET) à la ligne n° 246. En effet, les voitures circulant en sens inverse doivent impérativement s’arrêter au feu rouge pour laisser entrer le bus jaune dans la gare routière.
  6. On commute l’aiguillage n° 17 sur Embranchement grâce à la fonction EEPSetSwitch(17, CONST_EMBRANCHEMENT) à la ligne n° 248. Le bus va ainsi pouvoir entrer dans la gare routière,
  7. Sinon, le bus blanc est parti, on commute le signal n° 11 (feu tricolore) sur Voie Libre (ligne n° 251) pour que les voitures puissent redémarrer,
  8. Si le segment n° 42 n’était pas occupé, on commute également le signal n° 11 (feu tricolore) sur Voie Libre (ligne n° 256),
  9. La fonction est maintenant terminée.
Note : Cette fonction peut être optimisée mais dans un but pédagogique, nous avons volontairement détaillée chaque étape séparément.

Une question pourrait nous effleurer l’esprit : Pourquoi le script est-il conçu pour tester uniquement l’occupation des voies pour les bus et pas celles des tramways ?

La réponse est simple : les tramways sont prioritaires avant tout et une fois les points de contacts fncTramEntreeEst et fncTramEntreeOuest franchis, les variables ARRIVEE_Tram_Est et ARRIVEE_Tram_Ouest sont renseignées avec la constante CONST_PARCOURS_DEBUT. Donc, il suffit de tester les valeurs de ces variables sans attendre que les tramways occupent tel ou tel segment de rails pour savoir, s’ils se présentent à l’entrée ou à la sortie de la gare et déclencher une action. Pour les bus, la priorité est inférieure, voilà pourquoi nous n’avons pas besoin de renseigner une variable dans les fonctions d’entrée des bus. Seule, l’information pertinente qui nous intéresse est l’occupation éventuelle des segments 42, 30 et 66, 70.

Bien-sûr, si nous avions utilisé des variables pour les mouvements des bus à l’entrée ou à la sortie de la gare routière, les tests seraient plus nombreux et nous n’aurions pas eu la possibilité de découvrir les fonctions EEP pour l’occupation des voies. En effet, ces fonctions sont régulièrement utilisées, il s’agit de EEPIsRailTrackReserved, EEPIsRoadTrackReserved, EEPIsTramTrackReserved et EEPIsAuxiliaryTrackReserved. Nous vous rappellons que les segments concernés doivent être préalablement enregistrés. Nous vous invitons à consulter le manuel Lua pour EEP16 disponible au téléchargement sur le site pour plus d’informations.

Pour conclure : Nous vous laissons regarder la partie Ouest. Mais il y a quand même une différence, lorsque le bus jaune quitte la gare routière, il doit 'couper' la voie de gauche de l’axe routier principal pour rejoindre la voie de droite. Cela impose une gestion de signaux supplémentaires mais rien de bien compliqué.

Nous espérons que ce tutoriel vous apportera quelques éclaircissements sur la gestion des signaux et des aiguillages dans EEP avec Lua.

Merci d'avoir lu cet article. Si vous avez des questions ou des suggestions, n’hésitez pas à nous en faire part en bas de cette page en commentaires.

Amusez-vous à lire un autre article. A bientôt !

0 0 votes
Évaluation de l'article
S’abonner
Notification pour
guest
0 Commentaires
Commentaires en ligne
Afficher tous les commentaires
Retour en haut