Acados and Beckhoff TwinCat

Hi :wave:

for my master’s thesis i want to run my working acados MPC in TwinCat.
As described in their manual, one can just add the s-Function with the source code in the Simulink Model and the Simulink Coder compiles it in C++ for the use in TwinCat. Alternatively one can build the project manually in Visual Studio. Unfortunatelly i get lots of syntax errors like these:

1>C:\Diplomarbeit\_Matlab\acados\include\acados_c/sim_interface.h(36): error C2059: syntax error: 'string'
1>C:\Diplomarbeit\_Matlab\acados\include\acados_c/external_function_interface.h(48): error C2143: syntax error: missing ')' before '*'
1>C:\Diplomarbeit\_Matlab\acados\include\acados_c/external_function_interface.h(48): error C2143: syntax error: missing '{' before '*'
1>C:\Diplomarbeit\_Matlab\acados\include\acados_c/external_function_interface.h(48): error C2059: syntax error: 'type'
1>C:\Diplomarbeit\_Matlab\acados\include\acados_c/external_function_interface.h(48): error C2059: syntax error: ')'
1>C:\Diplomarbeit\_Matlab\acados\include\acados_c/external_function_interface.h(50): error C2143: syntax error: missing ')' before '*'
1>C:\Diplomarbeit\_Matlab\acados\include\acados_c/external_function_interface.h(50): error C2143: syntax error: missing '{' before '*'
1>C:\Diplomarbeit\_Matlab\acados\include\acados_c/external_function_interface.h(50): error C2059: syntax error: ')'

So i wanted to ask the community if someone has experince with TwinCat + Acados?
I would also be very grateful for other suggestions regarding C++ and Acados.

So far i have built acados with the same compiler as is used for TwinCat (MSVC), targets for blasfeo and hpipm are generic and EXT_DEP=OFF for blasfeo. I have added the include folders and adapted the timing.h for the use with time.h from TwinCat.

Thanks and best regards,
Alex :slightly_smiling_face:

Hi @AlexT ,

I’m facing the exact same errors as you described in your post while integrating Acados with TwinCat. Have you managed to resolve them? Any guidance would be greatly appreciated!

Thanks,
Housin

Hi Housin,

actually i got it really running and i wanted to update this post this week.
But be aware, it is quite a time consuming way.

The way to go is:

  • S-Function Builder: You need to use a S-Function Builder block. There you have to activate “Generate wrapper TLC”. The goal is to successfully build the S-Function Builder. So you leave Start, Outputs, Derivatives, Update and Terminate empty. In Data Properties you define your In- and Outputs. Then in Libraries you write in “Includes:” all the headers which are included in the acados-generated S-Function. In the “Library/Object/Source” files you need to include ALL necessary source files (libraries do not work). So you try to build it, you get an error for a missing function, you search where the function is defined, you include the source file.
    In my case it looked like this:
INC_PATHD:\%YOURPATH%\_Matlab\SWR\sFuncBuilder\hpipm\include
INC_PATHD:\%YOURPATH%\_Matlab\SWR\c_generated_code
INC_PATHD:\%YOURPATH%\_Matlab\SWR\sFuncBuilder
INC_PATHD:\%YOURPATH%\_Matlab\SWR\sFuncBuilder\blasfeo\include

SRC_PATHD:\%YOURPATH%\_Matlab\SWR\sFuncBuilder
SRC_PATHD:\%YOURPATH%\_Matlab\SWR\c_generated_code\
SRC_PATHD:\%YOURPATH%\_Matlab\SWR\c_generated_code\SWR_min_2_model
SRC_PATHD:\%YOURPATH%\_Matlab\SWR\sFuncBuilder\acados\ocp_nlp
SRC_PATHD:\%YOURPATH%\_Matlab\SWR\sFuncBuilder\acados\ocp_qp
SRC_PATHD:\%YOURPATH%\_Matlab\SWR\sFuncBuilder\acados\sim
SRC_PATHD:\%YOURPATH%\_Matlab\SWR\sFuncBuilder\acados\utils
SRC_PATHD:\%YOURPATH%\_Matlab\SWR\sFuncBuilder\acados\dense_qp
SRC_PATHD:\%YOURPATH%\_Matlab\SWR\sFuncBuilder\acados_c
SRC_PATHD:\%YOURPATH%\_Matlab\SWR\sFuncBuilder\blasfeo\blasfeo_hp_pm
SRC_PATHD:\%YOURPATH%\_Matlab\SWR\sFuncBuilder\blasfeo\blasfeo_ref
SRC_PATHD:\%YOURPATH%\_Matlab\SWR\sFuncBuilder\blasfeo\kernel\generic
SRC_PATHD:\%YOURPATH%\_Matlab\SWR\sFuncBuilder\blasfeo\auxiliary
SRC_PATHD:\%YOURPATH%\_Matlab\SWR\sFuncBuilder\hpipm\ocp_qp
SRC_PATHD:\%YOURPATH%\_Matlab\SWR\sFuncBuilder\hpipm\cond
SRC_PATHD:\%YOURPATH%\_Matlab\SWR\sFuncBuilder\hpipm\dense_qp
SRC_PATHD:\%YOURPATH%\_Matlab\SWR\sFuncBuilder\hpipm\auxiliary
SRC_PATHD:\%YOURPATH%\_Matlab\SWR\sFuncBuilder\hpipm\ipm_core


-DLA=HIGH_PERFORMANCE
-DTARGET_GENERIC
-DK_MAX_STACK=300
-DOS_WINDOWS
-DSAMPLINGTIME=0.05

my_exit.c

acados_solver_SWR_min_2.c
SWR_min_2_expl_ode_fun.c
SWR_min_2_expl_ode_hess.c
SWR_min_2_expl_vde_adj.c
SWR_min_2_expl_vde_forw.c


ocp_nlp_common.c
ocp_nlp_constraints_bgh.c
ocp_nlp_constraints_bgp.c
ocp_nlp_constraints_common.c
ocp_nlp_cost_common.c
ocp_nlp_cost_conl.c
ocp_nlp_cost_external.c
ocp_nlp_cost_ls.c
ocp_nlp_cost_nls.c
ocp_nlp_dynamics_common.c
ocp_nlp_dynamics_cont.c
ocp_nlp_dynamics_disc.c
ocp_nlp_reg_common.c
ocp_nlp_reg_convexify.c
ocp_nlp_reg_mirror.c
ocp_nlp_reg_noreg.c
ocp_nlp_reg_project.c
ocp_nlp_reg_project_reduc_hess.c
ocp_nlp_sqp.c
ocp_nlp_sqp_rti.c


ocp_qp_common.c
ocp_qp_common_frontend.c
ocp_qp_full_condensing.c
ocp_qp_hpipm.c
ocp_qp_partial_condensing.c
ocp_qp_xcond_solver.c


sim_collocation_utils.c
sim_common.c
sim_erk_integrator.c
sim_gnsf.c
sim_irk_integrator.c
sim_lifted_irk_integrator.c


external_function_generic.c
math.c
mem.c
print.c
timing.c


dense_qp_common.c
dense_qp_hpipm.c


condensing_interface.c
dense_qp_interface.c
external_function_interface.c
ocp_nlp_interface.c
ocp_qp_interface.c
sim_interface.c



d_blas1_lib4.c
d_blas2_diag_lib.c
d_blas2_lib4.c
d_blas3_diag_lib4.c
d_blas3_lib4.c
d_lapack_lib4.c


d_blas1_ref.c
d_blas2_diag_ref.c
d_blas2_ref.c
d_blas3_diag_ref.c
d_blas3_ref.c
d_blas3_ref_blas.c
d_lapack_ref.c
d_lapack_ref_blas.c


kernel_align_generic.c
kernel_d_aux_lib.c
kernel_daxpy_lib.c
kernel_ddot_lib.c
kernel_dgecp_lib4.c
kernel_dgemm_4x4_lib.c
kernel_dgemm_4x4_lib4.c
kernel_dgemm_diag_lib4.c
kernel_dgemv_4_lib.c
kernel_dgemv_4_lib4.c
kernel_dgeqrf_4_lib4.c
kernel_dger_lib.c
kernel_dger_lib4.c
kernel_dgetr_lib.c
kernel_dgetr_lib4.c
kernel_dgetrf_pivot_lib.c
kernel_dgetrf_pivot_lib4.c
kernel_dpack_buffer_lib4.c
kernel_dpack_lib4.c
kernel_dsymv_4_lib.c
kernel_dsymv_4_lib4.c


blasfeo_processor_features.c
blasfeo_stdlib.c
d_aux_common.c
d_aux_lib4.c
d_aux_ext_dep.c
i_aux_ext_dep_lib.c



d_ocp_qp.c
d_ocp_qp_dim.c
d_ocp_qp_sol.c
d_ocp_qp_kkt.c
d_ocp_qp_ipm.c
d_ocp_qp_res.c
d_ocp_qp_utils.c
d_ocp_qp_red.c


d_cond.c
d_cond_aux.c
d_part_cond.c


d_dense_qp.c
d_dense_qp_dim.c
d_dense_qp_sol.c
d_dense_qp_kkt.c
d_dense_qp_ipm.c
d_dense_qp_res.c
d_dense_qp_utils.c


aux_string.c
aux_mem.c


d_core_qp_ipm.c
d_core_qp_ipm_aux.c
  • INC_PATH - Folder with header files
  • SRC_PATH - Folder with source files (which are in the list)
  • (there are no spaces between INC_PATH and the PATH because of a bug of 2018b.)
  • -D… - Directives for the compiler
  • my_exit.c is a self written file. Since the real-time pc does not have an exit function (what should he do after exit anyways), you have to define a exit or otherwise you get a linker error.
#include <stdlib.h>

#ifdef TARGET_TWINCAT

int __cdecl exit(int a)
{
	return a;
}

#endif
  • If you can build your empty S-Function Builder, you can copy the code from the acados-generated S-Function. But you have to use a PWorks instead of S (Simu Struct). For example in the Start:
// Instead of
//ssSetUserData(S, (void*)capsule);

// you use
pW[0] = (void*)malloc( sizeof(capsule) );
pW[0] = capsule;
  • If you can build your S-Function Builder with the code, you need to build the whole Simulink model for TwinCat. Assuming you have installed TwinCat and the Simulink package, you need to configure under “Code Generation” the system target file as TwinCAT.tlc. The used directives in the S-Function Builder block have to be copied to “Code Generation/Custom Code/Additional build information/Defines”.
    After a successfull build of the S-Function Builder it might be necessary to temporary change the system target file to anything else and then back to TwinCAT.tlc. (When you get the error because of the change of the make command)

Then you need to address the errors one after one, similar to the build of the S-Function Builder. For example i did rewrite the timing.c of acados, to always return 1. I guess it is only used for analyzing anyways.

  • If you can build your Simulink model, you get your Model for TwinCat, which you can add in the TwinCat project. If it does run in TwinCat but does not compute anything, you should deactivate the optimization flags for the c compiler. Either by adding -DNDEBUG in the Defines or by adding the *.vcproj file in VisualStudio under the C++ category and then you can build and publish your module with further settings.

  • It did run in my case, but in comparison to Simulink it did run much slower.

Hope i could help you and others who try this :slight_smile:

Best regards, Alex

1 Like

Hi Alex,

Great that you made it work and thanks for sharing the information on the process! :slight_smile:
I don’t have experience with compilation for Beckhoff systems, but would like to comment.

It sounds a bit weird that libraries do not work.
Did you try to cross compile the acados core library?
Could it be that there was something wrong in that process?

Of course, it would be useful to implement this correctly.
A pull request on this would be very welcome.

Probably it is interesting for you to assess this further.
Things to look into:

  • The debug flags that you added, I am not sure what there were needed for or how you got the behavior.

    If it does run in TwinCat but does not compute anything

  • What CPU is in your system? What would be the dedicated BLASFEO target, this could give a significant speedup compared to the GENERIC target.

Best,
Jonathan