API

GUI

TwinCAT UI Elements

Here we define all the non-implemented TwinCAT stuff, without any platform.

The TcElement class should be extended by a class of another platform, ideally through multiple inheritance.

TcElement

class twinpy.element.TcElement(*args, **kwargs)[source]

Bases: ABC

Abstract class for TwinCAT element.

Must be inherited into a new class for something meaningful.

There are different event types, which determine how and when new remote values are retrieved:

  • EVENT_NOTIFICATION: An ADS notification is created, resulting in a callback on a remote value change. Suitable for rarely changing values or when a very quick response is needed. ADS notifications have some overhead. No more than 200 symbol notifications should exist at the same time.

  • EVENT_TIMER: New values are read at a fixed interval. Useful when remote values change often but no instant response is needed. This method has very little overhead.

  • EVENT_NONE: No attempts are made to update according to remote values.

You can override the defaults for your entire project by changing the TcWidget.DEFAULT_EVENT_TYPE and TcWidget.DEFAULT_UPDATE_FREQ class properties. Make sure to update these before any widgets are created and they will have new standard values.

Variables
  • DEFAULT_EVENT_TYPE – (default: EVENT_NOTIFICATION)

  • DEFAULT_UPDATE_FREQ – (default: 10.0 Hz)

Note: these methods do not affect when or how a value is _written_ to the ADS pool.

Parameters
  • args

  • kwargs – See list below - kwargs are passed along to connect_symbol too

Kwargs
  • symbol: Symbol to link to

    (i.e. to read from and/or write to)

  • format: Formatter symbol, e.g. ‘%.1f’ or ‘%d’ or callable

    (‘%.3f’ by default, ignored when not relevant) Callable must have a single argument

  • event_type: Possible values are EVENT_* constants

    (default: DEFAULT_EVENT_TYPE)

  • update_freq: Frequency (Hz) for timed update

    (for EVENT_TIMER only, default: DEFAULT_UPDATE_FREQ)

  • greyed: When true, the widget is visibly disabled

    When false, the widget is shown normally even when disconnected (default: true)

DEFAULT_EVENT_TYPE = 'notification'
DEFAULT_UPDATE_FREQ = 10.0
EVENT_NONE = 'none'
EVENT_NOTIFICATION = 'notification'
EVENT_TIMER = 'timer'
connect_symbol(new_symbol: Optional[Symbol] = None, **kwargs) bool[source]

Connect a symbol (copy of symbol is left as property).

By default a device callback is created with an on-change event from TwinCAT. Old callbacks are deleted first. Pass None to only clear callbacks. The notification handles are stored locally. Extend (= override but call the parent first) this method to configure more of the widget, useful if e.g. widget callbacks depend on the symbol.

Parameters
  • new_symbol – Symbol to link to (set None to only clear the previous)

  • kwargs – See list below - Keyword arguments are passed along as device notification settings too

Returns

True if new symbol was connected

Kwargs
format(value: Any) str[source]

“Use the stored formatting to created a formatted text.

In case the format specifier is a string and the new value is a list, element-wise string formatting will be concatenated automatically.

static make_timer(plc, interval)[source]

Create timer instance - to be extended by a different implementation

on_mass_timeout()[source]

Callback for the event timer.

This assumes the remote read was already performed!

abstract twincat_receive(value)[source]

Callback attached to the TwinCAT symbol.

Note: changing a state of a widget (e.g. checkbox being checked through setChecked(True)) will typically fire the on-change events again. So be careful to prevent an event loop when updating a widget based on a remote change: a change could result in a state change, which could result in a remote change, etc.

Parameters

value – New remote value

twincat_receive_wrapper(value)[source]

Intermediate twincat_receive callback to prevent event loops.

twincat_send(value: Any)[source]

Set value in symbol (and send to TwinCAT).

Method is safe: if symbol is not connected, nothing will happen.

Qt Widgets

TwinCAT widgets are Qt elements that are easily linked to an ADS symbol.

E.g. a label that shows an output value or an input box which changes a parameter.

The @pyqtSlot() is Qt decorator. In many cases it is not essential, but it’s good practice to add it anyway.

TcWidget

class twinpy.ui.TcWidget(*args, **kwargs)[source]

Bases: TcElement

Abstract class, to be multi-inherited together with a Qt item.

It is important to call this init() as late as possible from a subclass! The order should be:

  1. Subclass specific stuff (e.g. number formatting)

  2. Call to super().__init__(…) - Now the QWidget stuff has been made ready

  3. QWidget related stuff

Parameters
  • args

  • kwargs – See TcElement.__init__()

static close_with_error(err: Exception)[source]

Show an error popup and close the active application.

This uses QApplication.instance() to find the current application and won’t work perfectly.

connect_symbol(new_symbol: Optional[Symbol] = None, **kwargs) bool[source]

Connect a symbol (copy is left as property).

Parameters
  • new_symbol – Symbol to link to (set None to only clear the previous)

  • kwargs – See TcElement.connect_symbol()

static make_timer(plc, interval) TcTimer[source]

Use QTimer based timer instead.

twincat_send(value: Any)[source]

Set value in symbol (and send to TwinCAT).

Method is safe: if symbol is not connected, nothing will happen.

value_format: Union[str, Callable[[Any], str]]

TcLabel

class twinpy.ui.TcLabel(*args, **kwargs)[source]

Bases: QLabel, TcWidget

Label that shows a value.

Parameters
twincat_receive(value)[source]

Callback attached to the TwinCAT symbol.

Note: changing a state of a widget (e.g. checkbox being checked through setChecked(True)) will typically fire the on-change events again. So be careful to prevent an event loop when updating a widget based on a remote change: a change could result in a state change, which could result in a remote change, etc.

Parameters

value – New remote value

value_format: Union[str, Callable[[Any], str]]

TcLineEdit

class twinpy.ui.TcLineEdit(*args, **kwargs)[source]

Bases: QLineEdit, TcWidget

Readable and writable input box.

Parameters
on_editing_finished()[source]

Called when [Enter] is pressed or box loses focus.

on_text_edited(*_value)[source]

Callback when text was modified (i.e. on key press).

twincat_receive(value) Any[source]

Callback attached to the TwinCAT symbol.

Note: changing a state of a widget (e.g. checkbox being checked through setChecked(True)) will typically fire the on-change events again. So be careful to prevent an event loop when updating a widget based on a remote change: a change could result in a state change, which could result in a remote change, etc.

Parameters

value – New remote value

value_format: Union[str, Callable[[Any], str]]

TcPushButton

class twinpy.ui.TcPushButton(*args, **kwargs)[source]

Bases: QPushButton, TcWidget

Button that sends value when button is held pressed.

Parameters
  • args

  • kwargs

Kwargs
  • value_pressed: Value on press (default: 1), None for no action

  • value_released: Value on release (default: 0), None for no action

  • See TcWidget

on_pressed()[source]

Callback on pressing button.

on_released()[source]

Callback on releasing button.

twincat_receive(value)[source]

Do nothing, method requires definition anyway.

value_format: Union[str, Callable[[Any], str]]

TcRadioButton

class twinpy.ui.TcRadioButton(*args, **kwargs)[source]

Bases: QRadioButton, TcWidget

Radiobutton that updates the symbol when it is selected.

The radiobutton will _not_ update the symbol when another selection is made. Instead a write could be performed if that other radio is also a TcWidget.

Use TcRadioButtonGroupBox instead to create a set of radio buttons together that all update the same ADS symbol.

When connecting to a boolean symbol, use 0 and 1 as values for the best result instead of True and False.

Radios need to be in a QButtonGroup together to link together.

Parameters
  • label (str) – Label of this radio button

  • args

  • kwargs

Kwargs
  • value_checked: Value when radio becomes checked (default: 1)

  • See TcWidget

on_toggled()[source]

Callback when radio state is togged (either checked or unchecked).

twincat_receive(value)[source]

Set checked state if the new value is equal to the is-checked value.

value_format: Union[str, Callable[[Any], str]]

TcRadioButtonGroupBox

class twinpy.ui.TcRadioButtonGroupBox(*args, **kwargs)[source]

Bases: QGroupBox, TcWidget

An instance on this class forms a group of radio buttons.

The group of radio buttons together control a single ADS variable.

Instances of QRadioButton will be automatically created through this class. Using literal instances of TcRadioButton is not efficient because of duplicate callbacks.

When the remote value changes to a value that is not listed as an option in the radio_toggle, the displayed value simply won’t change at all.

The options argument is required.

Parameters
  • title (str) – Title of this QGroupBox

  • args

  • kwargs

Kwargs
  • options: List of tuples that form the label-value pairs of the radio,

    e.g. [(‘Low Velocity’, 0.5), (‘High Velocity’, 3.0)]

  • layout_class: Class of the layout used inside the QGroupBox (default:

    QVBoxLayout)

  • See TcWidget

on_click(button: QAbstractButton)[source]

Callback when a button of the group was pressed.

twincat_receive(value)[source]

Callback for a remote value change.

value_format: Union[str, Callable[[Any], str]]

TcCheckBox

class twinpy.ui.TcCheckBox(*args, **kwargs)[source]

Bases: QCheckBox, TcWidget

Checkbox to control a symbol.

Set either value to None to send nothing on that state. For the best results, use 1 and 0 for a boolean variable instead of True and False.

Parameters
  • label (str) – Label of this radio button

  • args

  • kwargs

Kwargs
  • value_checked: Value when checkbox becomes checked (default: 1)

  • value_unchecked: Value when checkbox becomes unchecked (default: 0)

  • See TcWidget

on_toggled()[source]

Callback when box state is togged (either checked or unchecked).

twincat_receive(value)[source]

Set checked state if the new value is equal to the is-checked value.

value_format: Union[str, Callable[[Any], str]]

TcSlider

class twinpy.ui.TcSlider(*args, **kwargs)[source]

Bases: QWidget, TcWidget

Interactive slider.

Also has built-in slider numbers (unlike the basic QSlider). This class extends a plain widget so a layout can be added for any labels.

The basic QSlider only supports integer values. To support floating point numbers too, the slider values are multiplied by a scale (e.g. 100) when writing, and divided again when reading from the slider. Use this with the float and float_scale options. This is done automatically if interval is not an integer.

Variables

slider – QSlider instance

Parameters
  • orientation – Either QtCore.Qt.Horizontal (default) or Vertical

  • args

  • kwargs

Kwargs
  • min: Slider minimum value (default: 0)

  • max: Slider maximum value (default: 100)

  • interval: Slider interval step size (default: 1)

  • show_labels: When true (default), show the min and max values with

    labels

  • show_value: When true (default), show the current slider value with a

    label

  • float: When true, QSlider values are scaled to suit floats (default:

    False)

  • float_scale: Factor between QSlider values and real values (default:
  • See TcWidget

on_value_changed(new_value)[source]

Callback when the slider was changed by the user.

slider_to_value(value: int) Union[float, int][source]
twincat_receive(value) Any[source]

On remote value change.

This will be triggered by on_value_changed too. A small timeout is added to prevent a loop between the two callbacks, received changes right after a user change are ignored.

value_format: Union[str, Callable[[Any], str]]
value_to_slider(value: float) Union[int, float][source]

TcGraph

class twinpy.ui.TcGraph(*args, **kwargs)[source]

Bases: GraphWidget, TcWidget

Draw rolling graph of symbol values.

TcGraph works only well with EVENT_TIMER!

The graph refresh rate is limited to self.FPS, while data is being requested at update_freq. For research measurements, use a log file or a TwinCAT measurement project instead. Even with a high update_freq there is no guarantee all data is captured!

If no symbol for the x-axis is selected, the local time will be used instead. Note that due to how PyQt events are handled, the local time can be slightly warped with respect the ADS symbol values.

See GraphWidget for more options.

Parameters
  • args

  • kwargs

Kwargs
  • symbols: List of symbols to plot (for the y-axis)

  • symbol_x: Symbol to use on the x-axis (optional)

connect_symbol(new_symbol: Optional[Union[Symbol, List[Symbol]]] = None, **kwargs)[source]

Connect to list of symbols (override).

on_mass_timeout()[source]

Callback for the event timer (override).

This assumes the remote read was already performed!

twincat_receive(value)[source]

Abstract implementation.

All useful code is in on_mass_timeout() instead.

value_format: Union[str, Callable[[Any], str]]
class twinpy.ui.GraphWidget(labels: List[str], units: Optional[List[str]] = None, buffer_size: int = 100, values_in_legend: bool = True, *args, **kwargs)[source]

Bases: QWidget

Class to make an rolling plot of some data.

When data comes in faster than FS, the plot won’t be refreshed. The data will still be stored and show up when it’s time.

Variables

FPS – Maximum refresh rate (Hz), faster samples are buffered but not yet plotted.

Parameters
  • labels – List of strings corresponding to plotted variable names

  • units – List of display units for each variable (default: None)

  • buffer_size – Number of points to keep in graph

  • values_in_legend – When True (default), put the last values in the legend

FPS = 30.0
add_data(y_list: List[float], x: Optional[float] = None)[source]

Add new datapoint to the rolling graph.

Parameters
  • y_list – List of new y-values

  • x – New x-value (default: use system time instead)

update_plot()[source]

Refresh the plot based on self.data.

Base GUI

Module containing the Base GUI class.

This class should be extended to make your own GUI.

class twinpy.ui.base_gui.BaseGUI(actuator: Optional[SimulinkModel] = None, controller: Optional[SimulinkModel] = None, **kwargs)[source]

Bases: TcMainWindow

Base TwinCAT GUI, specific for the WE2 actuators and controller model.

Extends this class if you want to use those models. For other models, using twinpy.ui.TcMainWindow might be more appropriate.

The left side of the main window consists of the basic control elements. The right contains a tabs widget, to which you can add your own custom tabs.

An example of an extended GUI could be:

class CustomTab(QWidget):
    # Widget containing a set of TcWidgets

class MyGUI(BaseGUI):

    def __init__():
        super().__init__()

        self.custom_tab = CustomTab()
        # Add new tab to the existing list:
        self.tabs.addTab(custom_tab, "Custom Tab")

        # Make the custom tab the default:
        self.tabs.setCurrentWidget(self.custom_tab)

Note: if the pyqtconsole package is not found, the console won’t be created and the tabs list could be empty.

Parameters
  • actuator – The WE2_actuators model (or a derivative)

  • controller – The WE2_controller model (or a derivative)

  • kwargs

closeEvent(event)[source]

Callback when window is closed.

Base Widgets

These widgets are specific implementations of TcWidgets.

They are not intended to be overridden again. They are separate classes mostly because their specific logic became significant.

TcErrorsLabel

class twinpy.ui.TcErrorsLabel(*args, **kwargs)[source]

Bases: TcLabel

Extension of TcLabel for a list of joint errors.

This is separate class because the amount of logic got a little bit much.

When clicking on the widget, a new window pops up showing the decoded errors.

Parameters
  • args

  • kwargs

Kwargs
  • format: Callback to format errors

    (default: show hexadecimal representation of error values)

  • popup: Whether or not to enable a detailed popup window

    (default: True)

  • play_sound: When True, play a beep sound on a new error

    (default: False)

  • See TcLabel

static format_errors_list(error_list: List[int]) str[source]

Set text for errors label.

mousePressEvent(event: QMouseEvent) None[source]

On clicking on the label.

QLabel does not have an on-click signal already.

static to_hex(value: int) str[source]

Create human-readable hex from integer.

twincat_receive(value)[source]

Callback on remote value change.

value_format: Union[str, Callable[[Any], str]]

DrivesWidget

class twinpy.ui.DrivesWidget(actuator: Optional[SimulinkModel] = None)[source]

Bases: QGroupBox

Group with buttons for the drives.

on_drives_enabled_change(enabled_list: List[float])[source]

An additional callback for the drive state change.

Manual callback instead of TcWidget symbol connection so we can also change button state and label color.

SystemBackpackWidget

class twinpy.ui.SystemBackpackWidget(actuator: Optional[SimulinkModel] = None)[source]

Bases: QGroupBox

Widget containing labels for the temperature and voltages.

This widget is for the old backpack system.

SystemWRBSWidget

class twinpy.ui.SystemWRBSWidget(actuator: Optional[SimulinkModel] = None)[source]

Bases: QGroupBox

Widget containing labels for the temperature and voltages.

This widget is for the new wearable robotics base station.

ErrorsWidget

class twinpy.ui.ErrorsWidget(actuator: Optional[SimulinkModel] = None)[source]

Bases: QWidget

Widget for the current and last errors.

Layout contains two groupboxes, and each can be clicked for a popup with more info.

You might want to call the close_windows() method from inside the closeEvent() function from the main window, to close the popups when closing the GUI.

close_windows()[source]

Close the popup windows in case they were opened.

Tabs

Module containing complete UI tabs.

ConsoleTab

class twinpy.ui.ConsoleTab(actuator: Optional[SimulinkModel] = None, controller: Optional[SimulinkModel] = None)[source]

Bases: PythonConsole

Tab with the Python console.

The clear() command is available in the console.

FirmwareTab

class twinpy.ui.FirmwareTab(actuator: Optional[SimulinkModel] = None)[source]

Bases: QWidget

Widget for the firmware CtrlWord options (Base Station only).

Main - Example

Example of a script using a GUI.

You can run the BaseGUI itself (linked to the WE actuator model) by running

$ python -m twinpy

(I.e. by executing the module.) This provides a quick demo of how such a GUI can work, and a quick check to see everything is working on your system.

This script should not be used in your program! Instead, your application should have it’s own main script and create a GUI instance from there.

class twinpy.__main__.GUI(actuator: Optional[SimulinkModel] = None, controller: Optional[SimulinkModel] = None, **kwargs)[source]

Bases: BaseGUI

Some extension of the BaseGUI.

Custom GUIs should extend the base class.

Parameters
  • actuator – The WE2_actuators model (or a derivative)

  • controller – The WE2_controller model (or a derivative)

  • kwargs

Module Info

TwinPy package.

author

Robert Roos <robert.soor@gmail.com>

license

MIT, see license file or https://opensource.org/licenses/MIT

created on

2021-01-08 16:13:00