Routing Labview and Simulink Controllers through Python

The Simis package provides the possibility to easily connect other external softwares to Python. This has been tested with Labview and Simulink but other softwares and programming languages can easily be connected in a similar way.

1 Python side 

On the python side the following steps have to be made:
  1. Implementation of the abstract TcpConnector class. For this the methods process_input and process_output have to be implemented. The process_input method should extract the wanted data from the Ashes model that gets sent through the Python interface. The process_output method should accept the values returned over the TCP connection and insert them into the Ashes model so that it can be returned to Ashes. 
  2. Instantiate the Implementation with the parameters:
    1. answer_size: The expected number of values returned over TCP.
    2. port: The port number to open. (standard = 6340)
    3. ip: The ip adress (standard = "localhost")
    4. byte_swap: Flag whether byte swapping should be activated, as is needed for Labview and Simulink.
  3. Run DataStore.start_connection()
An example implementation can be found in the examples folder C:\Users\UserName\Documents\Ashes X.xx\Python examples.

2  External side

Any Framework that can communicate over TCP can connect to the opened Connection in Python. This has been tested both with Simulink as well as with Labview. Examples for both of these environments can be found in the Ashes example folder (C:\Users\UserName\Documents\Ashes X.xx\Python examples). It is important to make sure that the expected data size that gets sent from Python is correct and that the port numbers are the same for both Python and the external software. In addition byte_swap has to be set to the correct value.

If the values either on the External or on the Python side are much too high (106 too high for example) then check whether byte_swap is correctly configured.


It is important that the Nagle algorithm is disabled in this case as the resulting idle times significantly slow down the connection. In Simulink this can be done in the TCP/IP Send block with the Transferdelay parameter set to 'off'. In LabView the TCP connection has to be configured using the TCP_NODELAY flag (See example file).

3  Running the controller

To run an external controller a certain sequence has to be obeyed:
  1. Start the simulation in Ashes
  2. Start the connector in Python (if not configured to start automatically with Ashes)
  3. Start the external controller

4         Simulink examples

A video explaining how to use the Simulink cnontrollers in Ashes is available from this link: https://www.youtube.com/watch?v=pGSgTkbhKCs

Two Simulink controllers are provided with Ashes, namely the SimulinkPythonPitchToFeather.slx  and the SimulinkPythonMultiple_in_out.slx , which you will find in their respective folders in the \Documents\Ashes X.xx\Python examples\Python controllers\Simulink Controller  folder.

These two examples can be used as starting points for your Simulink controllers. Both examples can be run by selecting the run_tcp_controller.py  (which can be run either Automatically or Manually, see Python script controller) from Ashes. This script will then create an instance of the ExampleTcpController  class from the example_tcp_controller.py file.

4.1 Pitch to feather example

The Pitch to feather example simply takes the simulation time as an input and calculates a pitch angle so that the demanded collective pitch will go from 0 to 90 degrees, starting at 5 seconds and finishing at 20 seconds. For that, it is important to correctly define the two following routines:

process_input will define what data from Ashes is sent to Simulink as a list of floaters. In the current case, the simulation time (accessed through the variable model.time ) is the only input from Ashes to Simulink.
process_output will receive data from Simulink and send it back into Ashes. The data from Simulink is received as a list of floaters called values . In the current case, the first (and only) element of the list values will be sent to Ashes as the demanded pitch angle.

The list of variables that can be received from and sent to Ashes i given in Python API in Ashes.

 


Note: the size of the list values  is defined before the simulation and cannot be modified during the simulation. If more than one variable will be sent back from Simulink, it is importnt to correctly set the size of the list with the set_answer_size  function (see multiple_in_out_controller example below)


The image below shows the controller in Simulink. It can be seen how the block From Python (left) sends the simulation time, which is used as an input to the algorithm to calculate the demanded pitch. The demanded pitch is then sent back through the block To Python (right)



4.2 Multiple input/output controller

This controller (in the folder Multiple_in_out_controller) is a mock controller, not intended to reproduce any real wind turbine behaviour. It is just there to show how multiple variables can be sent to and received from Ashes. In this example:
 - Ashes will send three variables to Simulink
  • the simulation time (model.time )
  • the current pitch angle (model.RNA.current_pitch )
  • the generator RPM (model.RNA.v_gen )
Simulink will send back two variables to Ashes:
  • the demanded pitch (model.RNA.demanded_pitch_angle )
  • the generator torque (model.RNA_demanded_generator_torque )


The first step is to define how many variables from Simulink will be sent back to Ashes. In this case, Simulink will send back two variables. Therefore, in the constructor of the ExampleTcpController  class, we have to pass the parameter 2 to the set_answer_size  function (if this function is not called, the Python script will expect that one variable is sent back from Simulink).



This means that the list values  will contain two elements. These two elements can then be accessed in the process_output routine, as illustrated below:



Similarly, the list of variables sent by Ashes to Simulink will be define as a list in the routine process_input, as shown in the image below:




Note: in this example, the generator speed is received as RPM from Ashes but sent as degrees per seconds to Simulink. This is achieved by defining a static method rpm_to_degreepers .


The image below shows the controller in Simulink. You can see that the block From Python on the left and To Python on the right are disconnected, which indicates that the values received from Ashes are not used to calculate the values sent to Ashes.



Since a three-element list is received by the From Python block, we use three Selector blocks to extract each of the variables (namely time, current pitch and Generator speed). Simiarly, the two variables sent by the To Python block (namely Demanded pitch and Demanded gen torque) are grouped into a two-element list by the bus creator block.