Engine Demo Examples

Engine Demo Basic

 1from niveristand import nivs_rt_sequence, NivsParam, realtimesequencetools
 2from niveristand.clientapi import BooleanValue, ChannelReference, DoubleValue
 3from niveristand.library import wait
 4
 5""" This module contains a basic example of how to create an RT sequence in Python.
 6
 7This example mirrors the 'Engine Demo Basic' example that installs with VeriStand.
 8Open the 'Engine Demo Basic' stimulus profile to help you understand the following example.
 9"""
10
11
12# You must mark RT sequences with the following decorator:
13@nivs_rt_sequence
14# You must also specify parameter data types, default values, and whether to pass parameters by value or by reference.
15@NivsParam('engine_power', BooleanValue(0), NivsParam.BY_REF)
16@NivsParam('desired_rpm', DoubleValue(0), NivsParam.BY_REF)
17def engine_demo_basic(engine_power, desired_rpm):
18    """Turn on the engine, set the desired_rpm to the passed value for 20 seconds, and shut down the engine.
19
20    You must access parameters through their ".value" property.
21    """
22    # You can access a channel with a ChannelReference
23    engine_power_chan = ChannelReference('Aliases/EnginePower')
24    desired_rpm_chan = ChannelReference('Aliases/DesiredRPM')
25    engine_power_chan.value = engine_power.value
26    desired_rpm_chan.value = desired_rpm.value
27    wait(DoubleValue(20))
28    engine_power_chan.value = False
29    desired_rpm_chan.value = 0
30
31
32@nivs_rt_sequence
33def run_engine_demo():
34    """Sets up channel references and calls the actual test."""
35    # You can call an RT sequence the same way you call a normal Python function.
36    # However, if you pass functions by reference, you must create strongly-typed objects.
37    engine_demo_basic(BooleanValue(True), DoubleValue(2500))
38
39
40def run_non_deterministic():
41    """Runs the sequence non-deterministically.
42
43    This function executes the RT Sequence on the host using the public ClientAPI
44    that installs with VeriStand. This function communicates with the gateway to set and get channel values.
45
46    If you use a Python integrated developer environment (IDE),
47    you can debug this function like a normal Python function.
48    """
49    run_engine_demo()
50
51
52def run_deterministic():
53    """Compiles the sequence and runs it deterministically inside the VeriStand engine.
54
55    You cannot use debugging tools at this stage because VeriStand executes the sequence, not Python.
56    If you do not mark the functions as @nivs_rt_sequence, Python will raise a :any:`niveristand.errors.VeristandError`.
57    """
58    # The run_py_as_rtseq function accepts, as a parameter, the Python function you want to call as an RT sequence.
59    realtimesequencetools.run_py_as_rtseq(run_engine_demo)
60
61
62if __name__ == '__main__':
63    realtimesequencetools.save_py_as_rtseq(run_engine_demo, 'd:\\share\\temp\\demo')
64    run_non_deterministic()
65    print('Finished non-deterministic')
66    run_deterministic()
67    print('Finished deterministic')

Engine Demo Advanced

 1from niveristand import nivs_rt_sequence, NivsParam, run_py_as_rtseq
 2from niveristand.clientapi import BooleanValue, ChannelReference, DoubleValue
 3from niveristand.library import multitask, nivs_yield, stop_task, task, wait_until_settled
 4
 5""" This module adds multitasking, return values, and cleanup tasks to engine_demo_basic.
 6
 7This example mirrors the 'Engine Demo Advanced and Return Value' example that installs with VeriStand.
 8Open the 'Engine Demo Advanced and Return Value' stimulus profile to help you understand the following example.
 9"""
10
11
12@NivsParam('desired_rpm', DoubleValue(0), NivsParam.BY_REF)
13@NivsParam('actual_rpm', DoubleValue(0), NivsParam.BY_REF)
14@NivsParam('engine_temp', DoubleValue(0), NivsParam.BY_REF)
15@nivs_rt_sequence
16def engine_demo_advanced(desired_rpm, actual_rpm, engine_temp):
17    """Turns on the engine, sets it to the desired rpm, and monitors the engine temperature."""
18    # Use the following local variable declarations to keep track of the test's status:
19    warmup_complete = BooleanValue(False)
20    warmup_succeeded = BooleanValue(False)
21
22    # Create a multitask with two tasks: one for setting rpm values and another for monitoring.
23    # In general, a multitask can contain as many tasks as desired. The tasks will all execute asynchronously,
24    # but not in parallel. For more information on multitask behavior, refer to the VeriStand help.
25    with multitask() as mt:
26        # You must decorate tasks using the following notation.
27        # The following code shows example of a task.
28        @task(mt)
29        def engine_warmup():
30            """Spawns a task to wait for the actual rpm signal to settle."""
31            desired_rpm.value = 2500
32            # Waits for up to 120 seconds for the actual RPM to be between 999999 and 2450 for 25 seconds.
33            wait_until_settled(actual_rpm, 9999999, 2450, 25, 120)
34            desired_rpm.value = 8000
35            wait_until_settled(actual_rpm, 9999999, 7800, 25, 120)
36            warmup_complete.value = True
37
38        @task(mt)
39        def monitor_temp():
40            """Spawns a task to monitor engine temperature.
41
42            If the temperature rises above 110 degrees (C), the previous task will stop.
43            """
44            while warmup_complete.value is False:
45                if engine_temp.value > 110:
46                    stop_task(engine_warmup)
47                    warmup_complete.value = True
48                    warmup_succeeded.value = False
49                nivs_yield()
50    # You can use a return value, but some restrictions will apply.
51    # For example, the function may only return previously declared variables.
52    return warmup_succeeded.value
53
54
55@nivs_rt_sequence
56def run_engine_demo_advanced():
57    """Run the engine_demo_advanced example.
58
59    To handle a condition that stops a task (such as, the engine temperature rising above a safe value),
60    use a try/finally block.
61
62    Regardless of the result of the execution, the finally block can be used to safely shut down the engine.
63    """
64    try:
65        warmup_succeeded = BooleanValue(False)
66        engine_power = ChannelReference('Aliases/EnginePower')
67        desired_rpm = ChannelReference('Aliases/DesiredRPM')
68        actual_rpm = ChannelReference('Aliases/ActualRPM')
69        engine_temp = ChannelReference('Aliases/EngineTemp')
70        engine_power.value = True
71        warmup_succeeded.value = engine_demo_advanced(desired_rpm, actual_rpm, engine_temp)
72    finally:
73        engine_power.value = False
74        desired_rpm.value = 0
75    return warmup_succeeded.value
76
77
78def run_deterministic():
79    return run_py_as_rtseq(run_engine_demo_advanced)
80
81
82def run_non_deterministic():
83    return run_engine_demo_advanced()
84
85
86if __name__ == '__main__':
87    # Run the tests.
88    # Note:  We expect the tests to fail because the engine temperature rises above 110 degrees (C),
89    # but the cleanup code at the end turns the engine off.
90    print("Non-Deterministic test:")
91    print("Test Passed!" if run_non_deterministic() else "Test Failed (expected)!")
92    print("Deterministic test:")
93    print("Test Passed!" if run_deterministic() else "Test Failed (expected)!")

Test Engine Set Points

 1from niveristand import nivs_rt_sequence, NivsParam, run_py_as_rtseq
 2from niveristand.clientapi import BooleanValue, ChannelReference, DoubleValue, DoubleValueArray
 3from niveristand.library import localhost_wait, seqtime, wait_until_settled
 4
 5
 6""" This module contains a complex example for running multiple tests in sequence.
 7
 8This example mirrors the 'Test Engine Setpoints' stimulus profile found in the examples that install with VeriStand.
 9
10Instead of using a stimulus profile to report results, this example uses the py.test
11unit-testing framework that is commonly used for running Python tests.
12"""
13
14
15@nivs_rt_sequence
16@NivsParam('on_off', BooleanValue(False), NivsParam.BY_VALUE)
17def set_engine_power(on_off):
18    """Turns the engine on or off."""
19    engine_power = ChannelReference('Aliases/EnginePower')
20    engine_power.value = on_off.value
21
22
23# If you do not specify a parameter decorator, the parameter defaults to the following:
24# Type=DoubleValue
25# Default Value = 0
26# Passed by reference.
27# In this case, the default is adequate, so you do not need to specify the decorator.
28@nivs_rt_sequence
29def measure_set_point_response(setpoint, timeout, tolerance):
30    """Sets the desired rpm to the specified setpoint and wait until the signal settles.
31
32    The tolerance is used to create upper and lower boundaries for the signal.
33    Returns the amount of time it takes the signal to settle or timeout.
34    """
35    actual_rpm = ChannelReference('Aliases/ActualRPM')
36    desired_rpm = ChannelReference('Aliases/DesiredRPM')
37    start_time = DoubleValue(0)
38    settle_time = DoubleValue(0)
39
40    desired_rpm.value = setpoint.value
41    # Waits .5 seconds, so the gateway has time to update.
42    localhost_wait(0.5)
43
44    start_time.value = seqtime()
45    wait_until_settled(actual_rpm,
46                       desired_rpm.value + tolerance.value,
47                       desired_rpm.value - tolerance.value,
48                       DoubleValue(2.0),
49                       timeout.value)
50    settle_time.value = seqtime() - start_time.value
51    return settle_time.value
52
53
54@nivs_rt_sequence
55def inbounds_check(test_value, upper, lower):
56    """Returns True if lower <= value <= upper.
57
58    Performs an inbounds check.
59    """
60    result = BooleanValue(False)
61    # Typically, you could write this instruction as lower.value <= test_value.value <= upper.value
62    # because Python supports cascading operators. However, for real-time sequences,
63    # you must write all comparisons using only two operands.
64    result.value = test_value.value >= lower.value and test_value.value <= upper.value
65    return result.value
66
67
68# The following function runs the profile above deterministically.
69# A unit test framework, such as py.test, can find the function.
70def test_run_engine_set_points_profile_deterministic():
71    set_engine_power(True)
72    setpoints = DoubleValueArray([2500, 6000, 3000])
73    try:
74        for setpoint in setpoints:
75            test_passed = run_py_as_rtseq(measure_set_point_response,
76                                          {
77                                              "setpoint": setpoint,
78                                              "timeout": DoubleValue(60),
79                                              "tolerance": DoubleValue(100)
80                                          })
81            assert 0 < test_passed <= 60, "Setpoint %d failed" % setpoint
82    finally:
83        set_engine_power(False)
84
85
86# If you do not need to run the profile deterministically, you can run this function as part of a py.test run.
87def test_run_engine_set_points_python():
88    set_engine_power(True)
89    setpoints = DoubleValueArray([2500, 6000, 3000])
90    try:
91        for setpoint in setpoints:
92            assert 0 < measure_set_point_response(setpoint,
93                                                  DoubleValue(60),
94                                                  DoubleValue(100)) <= 60, "Setpoint %d failed" % setpoint
95    finally:
96        set_engine_power(False)