Documentation > nControl > Train Automation Course
Train - Speed
For nControl™ 2019.2 or higher

What does this project do?
In this project we will measure the time it takes to complete one lap and use that to compute the average speed of the train.
What will you need to build this project?
  • 1x LEGO® PF or PU train
  • a loop of LEGO® train tracks
  • 1x 4DBrix™ IR train detection sensor and USB controller for the sensor
  • nControl 2019.2 or higher
What will we focus on?
  • Use the Activate Tile script to initialize processes
  • Create and use global variables
Project File
Estimating the Train Speed
To estimate the speed of the train we need the time it takes to complete a lap and the length of the track. We can measure the lap time by recording when the sensor sees the train and compute the time that passed between two consecutive detections of the train. The speed can only be estimated the second time the sensor detects the train.
We'll need two event scripts: the Activate Tile event to initialize the process and the Trigger event script to estimate the speed.
Writing Activate Tile Event Script
The Activate Tile event script is executed when you switch to Simulation or Operational mode. It's the ideal event to initialize your process as it's only executed when you activate your layout.
In this project we'll use it to initialize two global variables. Global variables are variables that do not disappear when the event script is finished and they can be accessed from other event script and/or other tiles. We'll create a variable to keep track of the number of laps the train has completed. We'll also create a variable to store when the sensor last detected the train. We'll initialize both variable with the value 0. You can create a global variable by defining it as a property of the tile you're working in. You do this by adding self. in front of the name of the variable. As such out Activate Tile event script becomes:
#Initialization
self.previousTime = 0
self.lapCount = 0
Writing the Trigger Event Script
We want log when the sensor detects the train and use that data to derive the lap time. So the first thing we have to do when we detect a train is to get a time stamp for the event. We can do this with the .timeStamp() function of the sensor tile. This function returns the number of seconds that have passed since we launched nContol™. Note that the elapsed time is expressed as a floating number so it has a resolution much finer than one second. We'll store the time stamp in the local variable time:
time = self.timeStamp()
Note that we need to detect the train twice before we can compute the lap time. We'll use the global variable lapCount to track the number of laps the train has completed. We can only compute the lap time once the number of laps is larger than zero so we need to use the following if statement.
if self.lapCount > 0:
We can compute the lap time by subtracting the time stamp of the previous train detection, which is stored in the global variable previousTime, from the time stamp of the current train detection, which is stored in the local variable time. This will give us the lap time in seconds.
lapTime = time-self.previousTime
The distance of the loop can be derived from the length of the track segments. Our layout consists out of 16 standard LEGO® curves and 10 standard straight segments. A straight segment has a length of 0.128 meters so our 10 straight segments have a combined length of 1.280 meters. A full circle of 16 curved segments has a length of 2.011 meters. As such the length of the layout in meters is computer as
distance = 2.011 + 1.280
Dividing the distance by the lap time gives us a speed in meters/second.
speed = distance/lapTime
We can convert this speed to miles per hour, kilometers per hour or studs per seconds as:
speedKmh = 3.6*speed   #Speed in Km/h
speedMPH = 2.236*speed #Speed in miles per hour
speedSPS = 125*speed   #Speed in studs per second
We can now print the speed in the console window. We'll use standard Python™ formatting commands to print the time and speed with 2 decimal digits. The code below prints the speed in meter/second. Use one of the converted variables above to print the speed in km/h, mph or sps.
lapTimeText = '{:.2f}'.format(lapTime)
speedText = '{:.2f}'.format(speed)
speedUnits = 'm/s'
self.print('Lap ' + str(self.lapCount))
self.print(' - Duration: ' + lapTimeText + 's')
self.print(' - Speed: ' + speedText + speedUnits)
self.print('')
The code above is executed once we have completed a lap, i.e. once the sensor has detected the train twice. The first time the sensor detects the train we cannot yet compute the lap time, so we want to print a warning message. We can do that by adding an else code block to the if statement.
else:
   self.print('Starting speed monitoring...')
   self.print('')
We still need to add two additional operations that have to be executed every time the sensor detects a train, also the first time. We need to increase the lap counter. This can be done with the += operator; this adds the specified value to the variable. So to increase the lap counter with 1 use
self.lapCount += 1
The only thing that still has to be done is to store the current time stamp in the global variable previousTime. As such, the next time the trigger script is executed the time stamp of this detection can be retrieved.
self.previousTime = time
The full trigger script thus becomes:
#Get the timestamp of when the train was seen by the sensor
time = self.timeStamp()

#Check if the train has already made lap
if self.lapCount > 0:
  #Compute the speed in meter / second
   lapTime = time-self.previousTime
   distance = 2.011 + 1.280 #Distance of the track in meter
   speed = distance/lapTime #Speed in m/s

  #Change the units of the speed
   speedKmh = 3.6*speed #Speed in Km/h
   speedMPH = 2.236*speed #Speed in miles per hour
   speedSPS = 125*speed #Speed in studs per second

  #Format the output
   lapTimeText = '{:.2f}'.format(lapTime) #Format the lap time with 2 decimal digits
   speedText = '{:.2f}'.format(speed) #Format the speed with 2 decimal digits
   speedUnits = 'm/s'

  #Print the output
   self.print('Lap ' + str(self.lapCount))
   self.print(' - Duration: ' + lapTimeText + 's')
   self.print(' - Speed: ' + speedText + speedUnits)
   self.print('')

else:
  #This is the beginning of the first full lap
   self.print('Starting speed monitoring...')
   self.print('')

#Update the lap counter
self.lapCount += 1

#Update the starting time of the new lap
self.previousTime = time

#End-of-Script
Validating the Process in Simulation Mode
To validate your scripts, switch to Simulation mode and click the sensor tile. The first time you Click the sensor tile you should see the message Starting speed monitoring… in the console window. The next time you click the sensor tile you should get the time and speed of the first lap. Every time you click the sensor tile you should get an additional lap. If you leave simulation mode and then return, the process should reinitialize and start the speed monitoring from scratch.
What Did We Learn?
In this project we learned:
  • to define and initialize global variables.
  • to use standard Python™ formatting command to print number.
Documentation > nControl > Train Automation Course