Introduction to Q-script for the QTU

Q-script is the scripting language for the QTU (Quad Throttle Unit). Once you become familiar with the scripting language you can write your own program to control your system in anyway that you desire.
Q-script includes pre-defined functions and variables that you will use to create your own functionality.
The first few examples will help you understand the pre-defined functions of Q-script and thereby minimise the amount of script that you will need to create.

If you have a QTU and have downloaded Tcc, you will be able to compile, download and test each of the programmes on your own hardware as we go along. Once you have downloaded your programme the QTU can run your layout autonomously without a computer connected.
(For instructions on downloading Tcc see XXX)

Example 1 - Speed Control

There are 4 throttles on a QTU. Each is given an identity 0 to 3. We will just use throttle 0 for now.
Lets connect the throttle output of throttle 0 to a circle of track, and connect a speed control to the first analogue input.
Each analogue input has a name AdcUser 0 to 7.

Item

Input /Output on QTU

Q-Script name

Speed Knob

1st analogue input

AdcUser0

Note : Take care to check the position of the input carefully. Each connector port also has power and ground pins and so the first input pin will NOT be the first pin on the connector.

Q-script has a predefined variable speed for each throttle. The variable for throttle 0 is speed0
The script to set the throttle output to be controlled by the speed knob follows.

speed0 = AdcUser0;
end "Speed_example"

Enter this into Tcc - QTU script, compile and download. Now as you vary the speed knob, the speed of the train will vary.
The
end statement tells the Q-script that you have finished, and gives your script a name "Speed_example".

Example 2 - Add Brake and Direction

Just a speed control might stunt your style a little, so lets add 2 new inputs Brake and Reverse. These are ON/OFF switches and so are connected to General Purpose Inputs. These lines are know by the Q-script as input0 to input31. In scripting terms these are binary inputs that can have the value of 0 or 1.

Item

Input /Output on QTU

Q-Script name

Speed Knob

1st analogue input

AdcUser0

Brake switch

1st input (General Purpose)

input0

Direction switch

2nd input

input1

Like speed, Q-script has pre-defined variables for brake and reverse. So we will set these for throtle0.

speed0 = AdcUser0;
brake0 = !input0;
reverse0 = !input1;
end "Brake_example"

Note carefully the NOT symbol which is the ! in the equation for the brake and reverse.
Binary input lines are pulled high, so when the brake switch is applied the line is pulled down to ground.
In our script we want the throttle brake to be applied with value 1 when the input switch is low.

Running this script on your QTU, first try applying the brake.
We have told the QTU that it should use input0 as the brake. Therefore when the brake is applied and the input line goes to zero.
The built-in brake function within the QTU understands, and will apply the brake.
When the brake is removed, the speed of the train will be returned to the speed setting.

Now try applying reverse. When reverse is applied, the built-in QTU functions again provide the required functionality.
The train is stopped and will then start again in the reverse direction returning to the required speed setting.

Example 3 - Add Inertia and Feedback

So the passengers were turned into pancakes when we activated the reversing switch, perhaps the train should have some inertia or momentum.
So far we have used the predefined items:
speed, brake and reverse. Let's use two more :- inertia and feedback.
Lets add a new switch called feedback_control to turn ON or OFF feedback, and a new analogue knob to set the inertia.

Item

Input /Output on QTU

Q-Script name

Speed Knob

1st analogue input

AdcUser0

Brake switch

1st input (General Purpose)

input0

Direction switch

2nd input

input1

Inertia Knob

2nd analogue input

AdcUser1

Feedback switch

3rd input

input2

Again we need to tell the Q-script what inputs are to be used.

speed0 = AdcUser0;
brake0 = !input0;
reverse0 = !input1;
inertia0 = AdcUser1;
feedback0 = !input2;
end "Inertia_example"

So compiling the script and downloading once again, what do inertia and feedback provide?
Inertia is the term used to describe how quickly a speed change takes effect on the train.
In previous examples, when the brake was applied the train was stopped immediately and rather clumsily.
With inertia being applied, the braking function provided by QTU is modified to bring the train to a more gentle stop (dependant upon the inertia setting).

Like inertia, feedback has a modifying effect on how the trains are run by the QTU. If you have gradients or sharp curves in your layout, you may well notice that the speed of the train changes as it traverses the layout. If you switch on feedback, the QTU then uses feedback from the train to monitor the speed, and will adjust the voltage so that a constant speed is maintained.

Example 4 - Four Manual throttles running 4 independent loops

So far we have only used the first throttle - throttle0. So lets expand our system to have 4 throttles each running a train on an independent loop.
So we wire up the 4 throttles and then once again tell the QTU how the system is wired up.
To make our code more readable we will add some equate statements (equ) so that we can use more readable names

Throttle Number

Item

Input /Output on QTU

Q-Script name

0

Speed Knob

1st analogue input

AdcUser0

0

Brake switch

1st input (General Purpose)

input0

0

Direction switch

2nd input

input1

 

Inertia Knob

2nd analogue input

AdcUser1

 

Feedback switch

3rd input

input2

1

Speed Knob

3rd analogue input

AdcUser2

1

Brake switch

4th input (General Purpose)

input3

1

Direction switch

5th input

input4


  equ Inertia_Setting = AdcUser1;
  
  inertia0 = Inertia_Setting;
  inertia1 = Inertia_Setting;
  speed0 = AdcUser0;
  brake0 = !input0;
  reverse0 = !input1;
  feedback0 = !input2;

  speed1 = AdcUser2;
  brake1 = !input3;
  reverse1 = !input4;
           //ADD THE EQUATIONS FOR TROTTLE 2 AND 3 HERE
  end "QTU_example_4"

We have added throttle1 to the connection table and the code. You should add the connection information for throttles 2 & 3 and then add the new equations where the comment line in the code indicates.
Note that all lines starting with // are comment lines and that comments may also be put at the end of lines using the // marker.
Also note that we have decided not to add another inertia input for throttle1. We have used the same inertia input as throttle0.
(Assuming that your engines have similar characteristics and will slow down in a similar fashion - then we don't really need an inertia setting per loop.)
After completing the code for all 4 throttles you should have "manual control" over your each train on each of your 4 loops.

Example 5 - Change direction

So most of the "work" has so far been done for you. Lets actually write a script to do something different: A script to stop each train in turn and change it's direction with about 1 minute between trains.
In order to keep track of the time, we will need a counter. This needs to be a byte (analogue) variable ie. a variable with a range 0- 255.
The general purpose analogue variables available to us in Q-script are called
ByteMemory
There are 14 of these general purpose variables, the first being ByteMemory0 and the last ByteMemory13
So lets make a half_minute_counter using ByteMemory8.

equ half_minute_counter = ByteMemory8;

We are also going to use some more Q-script function which uses the specialised variables: Duration and period.
Duration sets how long a time delay should last in the range 0 to 255 and in units of 100ms, so the maximum time is 255 * 100ms = 25.5 seconds.
period is a flag which if set to 1 (TRUE) will be cleared to 0 (FALSE) after Duration expires.
There are 4 Duration/ Period pairs available. For this example we will use the pair Duration0 and Period0.
(Note: that the number associated with Duration, period or ByteMemory does not equate to a throttle number. You can use any of these as you wish)

equ half_minute_counter = ByteMemory8; // Create minute_counter from general purpose memory
Duration0 = 255;      // This gives a time of 255*100ms = 25.5s (close enough to a half_minute)

if (!period0) {              // Period0 flag is FALSE showing that duration has expired
 period0 = TRUE;             // Restart the timer 
 half_minute_counter += 1;   // Increment the half_minute_counter
 
 if (half_minute_counter == 2) { reverse0 = !reverse0; } // After 1 min change throttle0 direction
 if (half_minute_counter == 4) { reverse1 = !reverse1; }
 if (half_minute_counter == 6) { reverse2 = !reverse2; }
 if (half_minute_counter == 8) {
   reverse3 = !reverse3;         
   half_minute_counter = 0; }      //Reset the half_minute counter
}
end "Change_Train_Direction"

Add the above code to your code in Example4.
A number of new code constructs are used in this example which we try to outline below.

Code Item

Explanation

equ a=b;

equate the name 'a' with the Q-script variable 'b'

a = b

Binary or analogue variable 'a' is set to be the same as the value of 'b'

a == b

'a' is compared with 'b' to see if they are the same value

TRUE

FALSE

The binary values TRUE and FALSE are defined by Q-script.

They can be used to set binary variables

!

For a binary item which can have the values TRUE or FALSE, then the ! (NOT) sign means the inverse.
So !reverse gives the opposite of reverse

if (test) { ...... }

if the result of the test is true then execute one or more statements that are inside the brackets {}
'if' statements can be nested one inside another.

Example 6 - Add a master brake

In example 4 we controlled each of our 4 trains individually. Lets now add a master brake switch that will stop all trains at once.

Item

Input /Output on QTU

Q-Script name

Master brake switch

11th input (General Purpose)

input10

We will give names to all the brake inputs as well as our new master brake switch:

  equ Manual_brake_0 = !input0;
  equ Manual_brake_1 = !input3;
  equ Manual_brake_2 = !input5
  equ Manual_brake_3 = !input7;
  equ Master_brake = !input10;
  equ Emergency_brake = !input11;
  
  brake0 = Manual_brake_0 | Master_brake;
  brake1 = Manual_brake_1 | Master_brake;
  brake2 = Manual_brake_2 | Master_brake;
  brake3 = Manual_brake_3 | Master_brake;

  end "QTU_example_6"

The brake on each throttle is now controlled by either the manual brake and the master brake: The '|' symbol means 'OR'. So if the manual brake OR the Master brake are activated then the brake is applied.

Example 7 - Add an emergency stop function

The master brake added in example 6 will stop all the trains using the inertia setting (if any) to bring the trains to a gradual stop.

Now lets add an emergency stop function. When an individual train brake is applied OR the master brake is applied, we want the inertia setting to be used. However for an emergency stop function we want to override the inertia setting. and bring all the trains to an immediate stop.

Item

Input /Output on QTU

Q-Script name

Emergency Stop switch

12th input (General Purpose)

input11

Code example given for throttle0 with emergency brake

  equ Manual_brake_0 = !input0;
  equ Inertia_Setting = AdcUser0;
  equ Master_brake = !input10;
  equ Emergency_brake = !input11;
  
  if (Emergency_brake) {
    inertia0 =FALSE;     //Turn off inertia 
  }
  else { 
    inertia0 = Inertia_Setting;  //Turn inertia to users settings
  }
  brake0 = Manual_brake_1 | Master_brake | Emergency_brake;

  end "QTU_example_7"

Previously we had set inertia0 directly to the analogue input AdcUser0. For normal running we want to use inertia, but for the emergency stop we want to turn it off. Therefore we now need two inertia settings :- the manual setting this time given the name Inertia_Setting which is read from port AdcUser0 and the throttle inertia - inertia0 which will be set as required.

Example 8- Overload indication

So far we have had independent loops of track each running a single train.

Lets now change to have a loop consisting of 4 sections. Each section is connected to a QTU throttle. So we want to detect where the train is and apply current to that section to drive the train forward.

NOTE : When using multiple QTU throttles to run sections of track, each section needs to be isolated on both rails from the section.

We do not use a common return line.

So having connected the sections of track, how will we know on which section of track the engine is placed.

The QTU provides current detection circuitry and can detect a train on the track.

The current detection works even when the train is stopped by using very low currents.

Q-script holds a 'state' variable for each throttle which includes a occupied and overload indicator.
So for throttle0, state0.occupied indicates whether the section throttle 0 is connected to is occupied by a train

state0.overload indicates whether there is an overload condition (normally caused by a derailment, a short or perhaps a stalled loco)


So lets say we want some LEDs to show if there is an overload on the system, and where is the overload has occurred.

Item

Input /Output on QTU

Q-Script name

Current Overload lamp

1st output (General Purpose)

output0


 equ Current_overload = output4;

if (state0.overload | state1.overload | state2.overload | state3.overload) {
Current_overload =1; // light the overload lamp
}
end "QTU_example_7"


Example 9 - Section Occupied

As mentioned in example 8, the state variable for a throttle includes an occupied indicator eg. state0.occupied
So with 4 sections in a loop, we want to see if the section ahead is clear before moving a train forward.

Item

Input /Output on QTU

Q-Script name

Current detect lamp

1st output (General Purpose)

output0

Current Overload lamp

2nd output

output0


  
  brake0 = state1.occupied;    //track ahead is occupied 
  brake1 = state2.occupied; 
  brake2 = state3.occupied;
  brake3 = state0.occupied;
  end "QTU_example_7"