ChimeraTK-ApplicationCore 04.06.00
Loading...
Searching...
No Matches
userAppModules.py
Go to the documentation of this file.
1#!/usr/bin/python3
2
3import sys
4import os
5import os.path
6import traceback
7
8import PyApplicationCore as ac
9
10# It is now possible to define ApplicationCore application modules in Python. This relies on system-installed python interpreter
11# and python modules. The implementation makes use of pybind11, in order to bind C++ library functions. The function signatures
12# were chosen to match their C++ origin as far as possible.
13# Limitations are:
14# In python, there can be only a single interpreter instance used commonly by all threads. Although each
15# application module gets its own thread - like when you implement it in C++ - you should be aware that they share the same global
16# python context, in particular they share import statements and may block each other, in case you do not release the global
17# interpreter lock.
18
19
20# application module that can be used as drop-in replacement C++-defined SetpointRamp
21class SetpointRamp(ac.ApplicationModule):
22
23 # we must define __init__ in order to define owner, name, and decription of this application module
24 # this is also the place to define inputs and outputs as ChimerTK accessors.
25 def __init__(self, owner):
26 super().__init__(owner, "SetpointRamp", "Slow ramping of temperator setpoint")
27
28 self.operatorSetpoint = ac.ScalarPollInput(ac.DataType.float32, self, "operatorSetpoint", "degC", "description")
29
30 self.ctrl = ac.VariableGroup(self, "/ControlUnit/Controller", "")
31 # elements of the VariableGroup can be added as dynamic attributes
32 # (alternatively, it would be possible to sub-class VariableGroup)
33 self.ctrl.actualSetpoint = ac.ScalarOutput(ac.DataType.float32, self.ctrl, "temperatureSetpoint", "degC", "...")
34
35 self.trigger = ac.ScalarPushInput(ac.DataType.uint64, self, "/Timer/tick", "", "...")
36
37 def mainLoop(self):
38 # at this point, initial values for inputs are already available
39
40 maxStep = 1 # choose a different step-size than in C++ example so we can see some difference
41 while True:
42 # note, scalar accessors automatically convert to their corresponding python value type (float in our case), while
43 # array accessors automatically convert to numpy arrays.
44 # note, += operator is (yet?) available, so need to use .set()
45 # syntax like self.ctrl.actualSetpoint = self.ctrl.actualSetpoint+1 does _not_ work since it overwrites the accessor reference by a float.
46 self.ctrl.actualSetpoint.set( self.ctrl.actualSetpoint + max( min(self.operatorSetpoint - self.ctrl.actualSetpoint, maxStep), -maxStep) )
47
48 # print("new setpoint value : " + str(self.ctrl.actualSetpoint))
49 self.writeAll()
50
51 self.readAll() # waits until next trigger received, then reads operatorSetpoint
52
53# Finally, instantiate user-defined application modules and reference them somehow from ac.app so they don't get deleted
54# owner = ac.app means the module is mounted at the root of the process variable household.
55# Differently from usual python semantics, the owner will manage lifetime of its owned elements.
56ac.app.module1 = SetpointRamp(ac.app)
57
58# we could also put the whole application module 'SetpointRamp' into a module group 'SomeGroup' like this:
59#ac.app.someGroup = ac.ModuleGroup(ac.app, "SomeGroup", "group description")
60#ac.app.someGroup.module1 = SetpointRamp(ac.app.someGroup)
void mainLoop() override