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:
- 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.
- Instantiate the Implementation with the parameters:
- answer_size: The expected number of values returned over TCP.
- port: The port number to open. (standard = 6340)
- ip: The ip adress (standard = "localhost")
- byte_swap: Flag whether byte swapping should be activated, as is needed for Labview and Simulink.
- 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 (10
6
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:
- Start the simulation in Ashes
- Start the connector in Python (if not configured to start automatically with Ashes)
- 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.