I use Matlab/Simulink R2012b under Linux to model dynamic systems. In order to perform hardware-in-the-loop testing, I want to run my models in real-time on Linux with rt_preempt patch. Running a Simulink model in real-time can be achieved by converting the model to the C code, compiling it and running the resulting application. Simulink supports this by means of Simulink Coder. Producing a Linux application with Simulink Coder is not as straightforward as one might think, though.
About Simulink Coder
Simulink Coder (formerly called Real-Time Workshop) can generate the code in many styles and for several platforms and operating systems. Surprisingly, Linux is also among supported environments.
Simulink Coder can, by default, generate code for so called Generic Real-Time Target (GRT). Such code should be suitable for running on desktop platforms. If you want to run the code on a more constrained embedded system or you have additional requirements on the code (e.g. compliance with safety standards), there is Embedded Coder for you. Embedded Coder extends Simulink Coder with additional capabilities and targets. The default Embedded Coder target is called Embedded Real-Time Target (ERT).
As it turns out, neither GRT nor ERT target alone can be used to create Linux executable even if documentation says the opposite.
Available options for generating Linux applications
From the documentation it seems that there are several options available out of the box that allow to generate Linux applications from Simulink. They are:
The use of Embedded Real-Time target (
ert.tlc
) and selecting NativeThreadExample as the target operating system in Model Configuration → Code Generation → Templates.When I tried to generate the code, I got this error:
This model specifies the ‘Target operating system’ as ‘NativeThreadsExample’ from the ‘Template’ section of the ‘Code Generation’ pane of the Configuration parameters dialog. This example target is currently supported only when the model is configured for concurrent execution.
After some searching, I figured out how to enable concurrent execution. It can be done at View → Model Explorer → right click on Configuration → Show Concurrent Execution options and then check Allow tasks to execute concurrently on target. Even though I enabled this and configure the tasks, I still got the same error.
- The second option might be using the IDE Link Target that allows to compile the generated code by Eclipse IDE. Even though I don’t like Eclipse, I tried to set it up according to the documentation. Again no success. I ended up with some strange errors suggesting that there is a problem with Eclipse (more precisely its JVM) being a 32 bit application and Matlab a 64 bit application. My guess is that this feature is tested only on Windows. Since Matlab R2012b is not distributed for 32 bit Linux, it is not possible to test this option with 32 bit Matlab. Furthermore, in release notes of R2013a it is announced that Eclipse support will be dropped in future releases.
Custom target for Linux applications
Simple target
Since I failed with both above options I decided to write a custom code generation target for Linux. One option would be to use a target previously developed at our department, but it has several drawbacks:
- The generated code cannot be compiled. It seems that the interface to the generated code changed between Simulink version from 2007 (when the target was developed) and R2012b used by me.
- I don’t like that the target is meant to be used on Windows (hardcoded backslashes etc.) and additionally,
- it contains features that I do not need (CANOpen block set).
Therefore I decided to write my own target that should be as simple as possible.
After creating the target by copying the ert.tlc
file and modifying
it slightly (basically replacing ert
with ert_linux
) and selecting
NativeThreadsExample as in the step 1 above, the code was
successfully generated. You can see this target here. Such a target
has two problems:
- It does not support external mode, i.e. a mode in which Simulink can connect to the running application to provide on-line parameter tuning and real-time data plotting.
- The generated code uses POSIX timers that use signals to wake up the threads. Signals have quite big overhead and there are rumors that their delivery can suffer from priority inversion.
The only way to get Linux application with support for external mode seemed to develop a target with custom main.c file.
Advanced target
I developed the target that provides the main.c file (actually
called ert_main.c
) and supports external mode. Although the
documentation is quite extensive (several thousands pages in total),
if was really hard to figure out how to do it properly. Several times
it was necessary to study awful TLC1 source code which is, IMHO,
very badly structured. Fortunately, I could use Lukáš Hamáček’s target
as an example, which helped me a lot.
The result of my work is can be downloaded from our repository. The target has the following features:
- Support for external mode over TCP.
- Support for both single-rate and multi-rate systems.
- Simulation threads are scheduled as
SCHED_FIFO
(real-time priority). - External mode communication runs in non-real-time thread.
I tested the target on several systems and everything seemed to work as expected. My only concern now is about thread safety. Given that Simulink produces the error messages about concurrent execution of threads (see above), I’m not sure whether the generated code can be safely run in multiple threads. Also the code implementing external mode server contains several semaphores but only when it is compiled for the VxWorks OS. I’ll probably check this later if we encounter any problems that might be caused by the code not being thread safe.
Conclusion
It is surprising how few relevant results Google gives when one asks for ”simulink real-time workshop linux”. It seems that the Embedded Coder target for Linux described in this post might be useful for people waning to run their Simulink models on Linux. Although that the target may not work perfectly and in all configurations, I think it is now good enough for interested people to try. If you experience any problems with the target, let me know.
Footnotes:
Target Language Compiler – the tool used to convert Simulink blocks to C code.
It seems we have the same pain (your last par.) but you’ve ‘created’ a solution. thanks for your work. I didn’t tried yet but I will try and share the results for improvements. our target is to bring simulink model on xenomai linux platform. which is done as said in articles but not documented anywhere. thanks again Mobin motallebizadeh IUST
Hi,
First of all, thanks for this short tutorial on this issue. I did find some information in web: https://www.rtai.org/?About_RTAI-Lab Isn’t it related to the issue ? If I understand correctly, your article does not give a step-by-step solution, but the git source, might give some directions ?
Thank you, Ran
Hi,
I have found the following http://www.clemson.edu/ces/crb/ece496/fall2000/rtlt.pdf
Are you familiar with that ? Do you think it might be a good step-by-step for this issue ?
Thank you, Ran
Hi,
Is there any update for this page ? The conclusion leaves some concern about multiple threads…
Regards, Ran
Hi Ran,
The difference between ert_linux and RTAI-Lab is that for RTAI-Lab, you need to install RTAI in addition to “plain Linux”. ert_linux can be used with plain Linux. Of course, if you need real-time response, you should use rt-preempt kernel. This kernel is already shipped by many distributions and sooner or later it will be merged into mainline Linux.
The difference between rt-preempt and RTAI is that RTAI is able to achieve slightly lower latencies, but it has more limited hardware support. rt-preempt runs almost everywhere, where normal Linux runs.
I don’t know RTLT, but it seems pretty outdated and I doubt it will work today.
We setup ert_linux homepage. You can find more information there. Currently, we do not work on improving ert_linux much, because we do not have any project where it is needed, but we plan to maintain it in a long term.
Reagrding multi-threading support, we are adding it to our another target, which is not public. If there is time, we will add it to ert_linux as well.
– Michal
Hi, I have not yet started working with Embedded coder nor Simulink coder. But I wander what is the exact prcoess of genrating linux application. Is it genrating c code with Embedded coder and then compile it into binary by myself? I will eventually need to work with Altera FPGA. It is described as if embedded coder knows how to generate code for this ARM FPGA. I wander if it will be straitforward or wether Ineed to use sone ert linux target.
Regards Ran
Hi, I have not yet started working with Embedded coder nor Simulink coder. But I wander what is the exact prcoess of genrating linux application. Is it genrating c code with Embedded coder and then compile it into binary by myself? I will eventually need to work with Altera FPGA. It is described as if embedded coder knows how to generate code for this ARM FPGA. I wander if it will be straitforward or wether Ineed to use sone ert linux target.
Regards Ran
Hi Ran,
Embedded coder generates both C code and Makefile. It also calls make to compile the code and optionally it can also download the binary to the target hardware. All of this is controlled by various templates and Matlab functions in the code generation target. The process of creating new code generation target is not conceptually difficult, but you need to read a lot of documentation. Some things are quite tricky to get right.
Hi, My eventual goal is to test my control logic using a standalone executable deployed on a Linux target so that I can send/receive CAN commands/response to/from the executable. I am hoping that your library will allow me to both send/receive on the same Linux target(Ubuntu) without needing an linux embedded target like RPi but I am open to it if no other option is available.
At the moment, I am just testing sending a single raw CAN message using a virtual CAN channel and trying to receive the same CAN Message back. I do not have a separate target at the moment and I am just intending to run this executable standalone on the Linux Ubuntu box so that
Hi, My eventual goal is to test my control logic using a standalone executable deployed on a Linux target so that I can send/receive CAN commands/response to/from the executable. I am hoping that your library will allow me to both send/receive on the same Linux target(Ubuntu) without needing an linux embedded target like RPi but I am open to it if no other option is available.
At the moment, I am just testing sending a single raw CAN message using a virtual CAN channel and trying to receive the same CAN Message back. I do not have a separate target at the moment and I am just intending to run this executable standalone on the Linux Ubuntu box, but, I am getting an error message with the build as follows.
TLC code generation complete.
.
Processing Template Makefile: /fig/home/sriramnarayanan/ert_linux/ert_linux/ert_linux/ert_linux.tmf
test_cantransmit_example.mk which is generated from /fig/home/sriramnarayanan/ert_linux/ert_linux/ert_linux/ert_linux.tmf is up to date
Building test_cantransmit_example: /usr/local/MATLAB/R2017b/bin/glnxa64/gmake -f test_cantransmit_example.mk OPT_OPTS=”-D_BSD_SOURCE -O2 -ggdb -Wall” ISPROTECTINGMODEL=NOTPROTECTING GENERATE_ASAP2=0
gcc -c -std=c99 -pedantic -fwrapv -fPIC -D_BSD_SOURCE -O2 -ggdb -Wall -DMODEL=test_cantransmit_example -DNUMST=1 -DNCSTATES=0 -DUNIX -DMAT_FILE=0 -DINTEGER_CODE=0 -DONESTEPFCN=1 -DTERMFCN=1 -DHAVESTDIO -DMULTI_INSTANCE_CODE=0 -DCLASSIC_INTERFACE=0 -DMT=0 -I. -I.. -I/usr/local/MATLAB/R2017b/extern/include -I/usr/local/MATLAB/R2017b/simulink/include -I/usr/local/MATLAB/R2017b/rtw/c/src -I/usr/local/MATLAB/R2017b/rtw/c/src/ext_mode/common -I/fig/home/sriramnarayanan/socketcan_simulink/socketcan-simulink/blocks -I/fig/home/sriramnarayanan/socketcan_simulink/socketcan-simulink/blocks/test_cantransmit_example_ert_linux -I/usr/local/MATLAB/R2017b/toolbox/shared/can/src/scanutil “can_datatype_ground.c” gcc -c -std=c99 -pedantic -fwrapv -fPIC -D_BSD_SOURCE -O2 -ggdb -Wall -DMODEL=test_cantransmit_example -DNUMST=1 -DNCSTATES=0 -DUNIX -DMAT_FILE=0 -DINTEGER_CODE=0 -DONESTEPFCN=1 -DTERMFCN=1 -DHAVESTDIO -DMULTI_INSTANCE_CODE=0 -DCLASSIC_INTERFACE=0 -DMT=0 -I. -I.. -I/usr/local/MATLAB/R2017b/extern/include -I/usr/local/MATLAB/R2017b/simulink/include -I/usr/local/MATLAB/R2017b/rtw/c/src -I/usr/local/MATLAB/R2017b/rtw/c/src/ext_mode/common -I/fig/home/sriramnarayanan/socketcan_simulink/socketcan-simulink/blocks -I/fig/home/sriramnarayanan/socketcan_simulink/socketcan-simulink/blocks/test_cantransmit_example_ert_linux -I/usr/local/MATLAB/R2017b/toolbox/shared/can/src/scanutil “test_cantransmit_example_data.c” gcc -c -std=c99 -pedantic -fwrapv -fPIC -D_BSD_SOURCE -O2 -ggdb -Wall -DMODEL=test_cantransmit_example -DNUMST=1 -DNCSTATES=0 -DUNIX -DMAT_FILE=0 -DINTEGER_CODE=0 -DONESTEPFCN=1 -DTERMFCN=1 -DHAVESTDIO -DMULTI_INSTANCE_CODE=0 -DCLASSIC_INTERFACE=0 -DMT=0 -I. -I.. -I/usr/local/MATLAB/R2017b/extern/include -I/usr/local/MATLAB/R2017b/simulink/include -I/usr/local/MATLAB/R2017b/rtw/c/src -I/usr/local/MATLAB/R2017b/rtw/c/src/ext_mode/common -I/fig/home/sriramnarayanan/socketcan_simulink/socketcan-simulink/blocks -I/fig/home/sriramnarayanan/socketcan_simulink/socketcan-simulink/blocks/test_cantransmit_example_ert_linux -I/usr/local/MATLAB/R2017b/toolbox/shared/can/src/scanutil “test_cantransmit_example.c” g++ -o ../test_cantransmit_example can_datatype_ground.o test_cantransmit_example.o test_cantransmit_example_data.o -lrt -lpthread -lm /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o: In function
_start': (.text+0x20): undefined reference to
main’ collect2: error: ld returned 1 exit status gmake: *** [../test_cantransmit_example] Error 1Simulink does not care whether the underlying can interface is virtual or not. So yes, it is supported.
And regarding your compile error. For some reason, it cannot find the main() function. Just look whether main() was generated by Simulink. If yes, the comile/link command has to be fixed somehow. If not, the code generation templates have to be fixed.
Hi, With regards to the previous error I am not able to build even the example model “cantransmit_ert.slx” model that is included in the socketcan-simulink git tree and I get the same “undefined reference to main” error.
These are the steps I apply before I build this example model: a. Build all the s-functions. b. add both ert_linux and socketcan-simulink to the path by executing the setup script. c. Ensure the make command, Template makefile and the system target file are set correctly according to your instructions. (haven’t changed this since this is a example model). d. Hit Ctrl+B.
I see that ‘ert_main.c’ gets generated but I get the following error even with the demo model: (I have verified that Embedded Coder/C-compiler is setup correctly because I am able to build demo models using ert.tlc)
Building cantransmit_ert: /usr/local/MATLAB/R2017b/bin/glnxa64/gmake -f cantransmit_ert.mk OPT_OPTS=”-D_BSD_SOURCE -O2 -ggdb -Wall” ISPROTECTINGMODEL=NOTPROTECTING GENERATE_ASAP2=0 OPTS=”-DON_TARGET_WAIT_FOR_START=0”
gcc -c -std=c99 -pedantic -fwrapv -fPIC -D_BSD_SOURCE -O2 -ggdb -Wall -DON_TARGET_WAIT_FOR_START=0 -DEXT_MODE -DGLNXA64 -DMODEL=cantransmit_ert -DNUMST=1 -DNCSTATES=0 -DUNIX -DMAT_FILE=0 -DINTEGER_CODE=0 -DONESTEPFCN=1 -DTERMFCN=1 -DHAVESTDIO -DMULTI_INSTANCE_CODE=0 -DCLASSIC_INTERFACE=0 -DMT=0 -I. -I.. -I/usr/local/MATLAB/R2017b/extern/include -I/usr/local/MATLAB/R2017b/simulink/include -I/usr/local/MATLAB/R2017b/rtw/c/src -I/usr/local/MATLAB/R2017b/rtw/c/src/ext_mode/common -I/fig/home/sriramnarayanan/socketcan_simulink/socketcan-simulink/blocks -I/fig/home/sriramnarayanan/socketcan_simulink/socketcan-simulink/blocks/cantransmit_ert_ert_linux -I/usr/local/MATLAB/R2017b/toolbox/coder/rtiostream/src/utils -I/usr/local/MATLAB/R2017b/toolbox/shared/can/src/scanutil “can_datatype_ground.c” gcc -c -std=c99 -pedantic -fwrapv -fPIC -D_BSD_SOURCE -O2 -ggdb -Wall -DON_TARGET_WAIT_FOR_START=0 -DEXT_MODE -DGLNXA64 -DMODEL=cantransmit_ert -DNUMST=1 -DNCSTATES=0 -DUNIX -DMAT_FILE=0 -DINTEGER_CODE=0 -DONESTEPFCN=1 -DTERMFCN=1 -DHAVESTDIO -DMULTI_INSTANCE_CODE=0 -DCLASSIC_INTERFACE=0 -DMT=0 -I. -I.. -I/usr/local/MATLAB/R2017b/extern/include -I/usr/local/MATLAB/R2017b/simulink/include -I/usr/local/MATLAB/R2017b/rtw/c/src -I/usr/local/MATLAB/R2017b/rtw/c/src/ext_mode/common -I/fig/home/sriramnarayanan/socketcan_simulink/socketcan-simulink/blocks -I/fig/home/sriramnarayanan/socketcan_simulink/socketcan-simulink/blocks/cantransmit_ert_ert_linux -I/usr/local/MATLAB/R2017b/toolbox/coder/rtiostream/src/utils -I/usr/local/MATLAB/R2017b/toolbox/shared/can/src/scanutil “cantransmit_ert_data.c” gcc -c -std=c99 -pedantic -fwrapv -fPIC -D_BSD_SOURCE -O2 -ggdb -Wall -DON_TARGET_WAIT_FOR_START=0 -DEXT_MODE -DGLNXA64 -DMODEL=cantransmit_ert -DNUMST=1 -DNCSTATES=0 -DUNIX -DMAT_FILE=0 -DINTEGER_CODE=0 -DONESTEPFCN=1 -DTERMFCN=1 -DHAVESTDIO -DMULTI_INSTANCE_CODE=0 -DCLASSIC_INTERFACE=0 -DMT=0 -I. -I.. -I/usr/local/MATLAB/R2017b/extern/include -I/usr/local/MATLAB/R2017b/simulink/include -I/usr/local/MATLAB/R2017b/rtw/c/src -I/usr/local/MATLAB/R2017b/rtw/c/src/ext_mode/common -I/fig/home/sriramnarayanan/socketcan_simulink/socketcan-simulink/blocks -I/fig/home/sriramnarayanan/socketcan_simulink/socketcan-simulink/blocks/cantransmit_ert_ert_linux -I/usr/local/MATLAB/R2017b/toolbox/coder/rtiostream/src/utils -I/usr/local/MATLAB/R2017b/toolbox/shared/can/src/scanutil “rtGetInf.c” gcc -c -std=c99 -pedantic -fwrapv -fPIC -D_BSD_SOURCE -O2 -ggdb -Wall -DON_TARGET_WAIT_FOR_START=0 -DEXT_MODE -DGLNXA64 -DMODEL=cantransmit_ert -DNUMST=1 -DNCSTATES=0 -DUNIX -DMAT_FILE=0 -DINTEGER_CODE=0 -DONESTEPFCN=1 -DTERMFCN=1 -DHAVESTDIO -DMULTI_INSTANCE_CODE=0 -DCLASSIC_INTERFACE=0 -DMT=0 -I. -I.. -I/usr/local/MATLAB/R2017b/extern/include -I/usr/local/MATLAB/R2017b/simulink/include -I/usr/local/MATLAB/R2017b/rtw/c/src -I/usr/local/MATLAB/R2017b/rtw/c/src/ext_mode/common -I/fig/home/sriramnarayanan/socketcan_simulink/socketcan-simulink/blocks -I/fig/home/sriramnarayanan/socketcan_simulink/socketcan-simulink/blocks/cantransmit_ert_ert_linux -I/usr/local/MATLAB/R2017b/toolbox/coder/rtiostream/src/utils -I/usr/local/MATLAB/R2017b/toolbox/shared/can/src/scanutil “rtGetNaN.c” gcc -c -std=c99 -pedantic -fwrapv -fPIC -D_BSD_SOURCE -O2 -ggdb -Wall -DON_TARGET_WAIT_FOR_START=0 -DEXT_MODE -DGLNXA64 -DMODEL=cantransmit_ert -DNUMST=1 -DNCSTATES=0 -DUNIX -DMAT_FILE=0 -DINTEGER_CODE=0 -DONESTEPFCN=1 -DTERMFCN=1 -DHAVESTDIO -DMULTI_INSTANCE_CODE=0 -DCLASSIC_INTERFACE=0 -DMT=0 -I. -I.. -I/usr/local/MATLAB/R2017b/extern/include -I/usr/local/MATLAB/R2017b/simulink/include -I/usr/local/MATLAB/R2017b/rtw/c/src -I/usr/local/MATLAB/R2017b/rtw/c/src/ext_mode/common -I/fig/home/sriramnarayanan/socketcan_simulink/socketcan-simulink/blocks -I/fig/home/sriramnarayanan/socketcan_simulink/socketcan-simulink/blocks/cantransmit_ert_ert_linux -I/usr/local/MATLAB/R2017b/toolbox/coder/rtiostream/src/utils -I/usr/local/MATLAB/R2017b/toolbox/shared/can/src/scanutil “rt_nonfinite.c” gcc -c -std=c99 -pedantic -fwrapv -fPIC -D_BSD_SOURCE -O2 -ggdb -Wall -DON_TARGET_WAIT_FOR_START=0 -DEXT_MODE -DGLNXA64 -DMODEL=cantransmit_ert -DNUMST=1 -DNCSTATES=0 -DUNIX -DMAT_FILE=0 -DINTEGER_CODE=0 -DONESTEPFCN=1 -DTERMFCN=1 -DHAVESTDIO -DMULTI_INSTANCE_CODE=0 -DCLASSIC_INTERFACE=0 -DMT=0 -I. -I.. -I/usr/local/MATLAB/R2017b/extern/include -I/usr/local/MATLAB/R2017b/simulink/include -I/usr/local/MATLAB/R2017b/rtw/c/src -I/usr/local/MATLAB/R2017b/rtw/c/src/ext_mode/common -I/fig/home/sriramnarayanan/socketcan_simulink/socketcan-simulink/blocks -I/fig/home/sriramnarayanan/socketcan_simulink/socketcan-simulink/blocks/cantransmit_ert_ert_linux -I/usr/local/MATLAB/R2017b/toolbox/coder/rtiostream/src/utils -I/usr/local/MATLAB/R2017b/toolbox/shared/can/src/scanutil “cantransmit_ert.c” g++ -o ../cantransmit_ert can_datatype_ground.o cantransmit_ert.o cantransmit_ert_data.o ext_svr.o ext_work.o rtGetInf.o rtGetNaN.o rt_nonfinite.o rtiostream_interface.o rtiostream_tcpip.o rtiostream_utils.o updown.o -lrt -lpthread -lm /usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/crt1.o: In function
_start': (.text+0x20): undefined reference to
main’ collect2: error: ld returned 1 exit status gmake: *** [../cantransmit_ert] Error 1Hi Qing,
please, next time post your issues to Github. I’m not sure that your problem has anything to do with ert_linux, since you write that you use GRT, which is something different. Also note that if the computations performed in one period take longer time that the sampling period, your model will never run in real time.
HTH
-Michal