Scriptable train control system
#1
Posted 29 January 2014 - 02:51 PM
I tried to implement a scripting framework (X1970) as suggested by James in this post. I would ask if I understood it well, and if the approach I made is right. And I am also curious what do you think about it, especially the lead developers. Should we go this way, or the scripting should be handled totally differently?
I attach a simple test script as well, that can be dropped into any locomotives \Script subdirectory in the Trainset folder (e.g. TRAINS\TRAINSET\ACELA\Script), and referenced in the corresponding eng file as "ORTSTrainControlSystem( EBICAB )". It implements almost the same currently, as the standard MSTS train control system, it is here just for an example.
I assume the scripting implementation might be far from perfect yet, but please keep in mind that this is the first time in my life I try to write such a thing. :sign_thanks:
deleted: EBICAB.zip
Edit: I removed the auto-prefixing of the script with namespace information, so the old script will not work. But attached the new script here:
EBICAB_X1987.zip (1.58K)
Number of downloads: 721
#2
Posted 29 January 2014 - 03:43 PM
Back when Carlo wrote some special code for EBICAB testing with a specific RunActivity.exe file, the system was almost near perfect, and it had already some more further adjustments to it. :sign_thanks:
I like this idea a lot, and when I first saw it on the new experimental versions I thought already about making such a script...
But unfortunatly, speaking for myself, I do not understand how to compile or make such codes/scripts... (Yeah, I did give a look to the file too).
#3
Posted 30 January 2014 - 12:10 AM
#4
Posted 30 January 2014 - 12:35 AM
Do you plan to take into account on board subsystem and on earth subsystem in a modular way?
To Pedro: it's Peter who wrote the special code, I only built it for you :aggressive:
#5
Posted 30 January 2014 - 01:45 AM
you rather over-simplified things when it comes to speed control.
The way you have set up the speedlimit values brings back the old MSTS problem that speed rises are activated immediately as the leading engine passes the signal or speedpost.
Depending on the actual system, that might be wrong - the rise in speed is valid only when the rear of the train passes that location, and some systems (most certainly the more modern systems) take this into account. There should be a script parameter reflecting this, i.e. whether the systems shows the speed immediately or at the proper moment.
For overspeed control as such, you should always use the proper value related to the full train.
For these systems, you should not take speeds directly from signals or speedposts, but use these train variables :
public float AllowedMaxSpeedMpS; // Max speed as allowed public float allowedMaxSpeedSignalMpS; // Max speed as set by signal public float allowedMaxSpeedLimitMpS; // Max speed as set by limit
These are updated according to the position of the complete train with regards to all speed indicators (signals and speedposts) along the way.
For overspeed detection you only should check against AllowedMaxSpeedMpS, which is properly updated according to the train position.
Another point is that speed limits set by signals never overrule line speed limits as set by speedposts. The method you use, this_signal_speed, gives the allowed speed as set in sigcfg.dat for that signal, regardless of line speed limits.
Therefor, you should not use the this_signal_speed method to determine the speed. Instead, you should use the variable actual_speed of the first signal-entry in SignalObjectItems, which is set according to the line speed limit.
Regards,
Rob Roeterdink
#6
Posted 30 January 2014 - 06:16 AM
James Ross, on 30 January 2014 - 12:10 AM, said:
Might be because of practically I rewrote the whole file, because I rebasedthe previous MSTSTrainControlSystem onto the new scripting code. Now it uses the same API as is exposed to the scripts, just it is built in.
James Ross, on 30 January 2014 - 12:10 AM, said:
The scripting framework itself is capable to drive any other area, now it is just a matter of defining a different API for the other stuff. However I'm not intended to drop it in elsewhere currently, but it is there if needed...
Certainly the TCS API is subject to change, so it is far not ready for production. I have a question here: How can the intellisense be exposed to script developers? Even if I add a script to the csproj, the "using ORTS.Scripting.Api;" and "namespace ORTS.Scripting.Script" entries should be there for this to work. Now these are added only at compile-time, as you suggested, to prevent the script-writers to access other namespaces and system services. It is a really good thing, but it disables the intellisense as well...
Rob,
Honestly I was a bit confused how to get the necessary data out of the scripting code, so thank you for clarifying it. I will modify that piece accordingly. Is this data available in all playing modes, so there is no need to trick with it?
#7
Posted 30 January 2014 - 06:29 AM
gpz, on 30 January 2014 - 06:16 AM, said:
That is indeed a problem. In fact, I think that we'll need more than just a namespace around the code, as I've just seen an example that has 'using' inside the namespace. Maybe we need to prevent access in some other way... I will have to think about it. Feel free to see what other people have done in other projects, so long as no incompatibly-licensed code is copied.
#8
Posted 30 January 2014 - 06:41 AM
#9
Posted 30 January 2014 - 06:47 AM
gpz, on 30 January 2014 - 06:16 AM, said:
AllowedMaxSpeedMpS is available in all modes, but SignalObjectItems is available in AUTO mode only.
One option to get all required details is to call Train.GetTrainInfo() - this returns an instance of class TrainInfo which holds all required data (and a bit more). This is the method which is used to 'fill' the TrackMonitor window, and is available in all modes.
Regards,
Rob Roeterdink
#10
Posted 30 January 2014 - 10:31 AM
roeter, on 30 January 2014 - 01:45 AM, said:
public float AllowedMaxSpeedMpS; // Max speed as allowed public float allowedMaxSpeedSignalMpS; // Max speed as set by signal public float allowedMaxSpeedLimitMpS; // Max speed as set by limit
These are updated according to the position of the complete train with regards to all speed indicators (signals and speedposts) along the way.
For overspeed detection you only should check against AllowedMaxSpeedMpS, which is properly updated according to the train position.
The script functions are delegated currently as follows:
Script.TrainSpeedLimitMpS = () => Locomotive.Train.TrainMaxSpeedMpS; Script.CurrentSignalSpeedLimitMpS = () => Locomotive.Train.allowedMaxSpeedSignalMpS;
I should set up one more function to query the "CurrentPostSpeedLimitMpS", which should point to Locomotive.Train.allowedMaxSpeedLimitMpS. (Is it right?)
Is that also right, that if the minimum of the above three will be calculated, then it will be the same as your AllowedMaxSpeedMpS variable? (I'm afraid that one cannot be used, because the different speed limits need to be passed to TCS separately, because any of them might also be needed for various things there. Some systems, mostly the older ones, don't know about speed posts, some others can only consider signals, etc...)
roeter, on 30 January 2014 - 01:45 AM, said:
Therefor, you should not use the this_signal_speed method to determine the speed. Instead, you should use the variable actual_speed of the first signal-entry in SignalObjectItems, which is set according to the line speed limit.
So you say I should remove the test
if (Locomotive.Train.IndexNextSignal >= 0 && Locomotive.Train.ControlMode == Train.TRAIN_CONTROL.AUTO_SIGNAL)from my function UpdateNextSignalFunctions(), and in all cases use the
Script.NextSignalSpeedLimitMpS = () => Locomotive.Train.SignalObjectItems[Locomotive.Train.IndexNextSignal].actual_speed;delegation? It would simplify things greatly! (But if I recall correctly, there were problems with it, and that's why the alternative method was introduced in the past. But now I will remove it, and will see. :good2: )