MatVo1992 / Simulink-XInput-Controller

Simulink Block / S-Function for Windows XInput API (XBOX Controller)
GNU General Public License v3.0
8 stars 1 forks source link

Support for mixed Windows/Arduino models #1

Closed johanlofberg closed 4 years ago

johanlofberg commented 5 years ago

Any idea on how I could use your code in a Simulink scheme containing a model which is compiled to an Arduino, but running in external mode?

The problem: The configuration specifies the ert.tlc toolchain as it is compiled to an Arduino, but MATLAB supports that some blocks aren't compiled to the arduino but are there only for display and input on the Host machine.

I would like to use Xinput to connect a joystick via the desktop machine, but when in an S-function block, it will not compile, as it requires the grt.tlc environment as it uses Windows.h etc (i.e. during compilation it fails as it cannot find Windows.h and iostream)

Any clever way of dealing with this?

  1. Generate the mexw64 first in another model, and then somehow mask and call that one directly? No idea on how to call the generated mexw64 though...

  2. Move everything to an S-builder block, and then build that block first, and then compile the model (this appears to work conceptually. I took the S-function builder example and put it in my Arduino model, build the block, and the compiled the model, and it worked. No idea how to move your stuff to an S-function builder block though

Long question, indicating my complete lack of competence in the mex/c/compuilation world

MatVo1992 commented 5 years ago

So your model looks like this: Windows PC + Gamepad -- Inerface -- Arduino ?

For this kind of setup i'd put up two Simulink models. Model A for your PC with the XInput Code and another model for your Arduino. In each model some sort of Interface Block. Maybe this can help you as an interface between two models: https://de.mathworks.com/help/supportpkg/arduino/ref/send-and-receive-serial-data-using-arduino-hardware.html

Nonetheless i can help you with the S-Function builder. Create a new folder including _XInputController.h and _XInputController.cpp. Create a new Simulink model here and start up the S-Function builder Block. Just need to Copy and Paste Code from _XInput_ControllerSFun.cpp methods to the corresponding S-Fun_Builder tabs.

  1. In the top window give the function a name and set language to C++
  2. Go to Data Properties. Delete Input Port and set up 3 Output Ports and 1 Parameter. The names and sizes need to match the following code. All Signals/Parameters 1-D, complexity:real and Bus:off. In the top tab you can set the Parameter to 1 (Controller_ID)
  3. Go to Libraries. Copy Includes from _XInput_ControllerSFun.cpp to Includes:
  4. Go to Outputs: Copy the Code from mdlOutputs method here (try to uncheck direct feedthrough at the bottom)
  5. Go to Terminate: Copy the Code from mdlTerminate method here
  6. Go to Build Info: Check Generate wrapper TLC, then build.

Let me know if this works. If it does, you can add Feddback (Vibration) from here.

johanlofberg commented 5 years ago

Great, I'll have a go at it

johanlofberg commented 5 years ago

Hmm. I got (cutting out what I guess is most important)

\Joystickexperiments\XboxController_wrapper.cpp: In function 'void XboxController_Outputs_wrapper(real_T*, real_T*, real_T*, const real_T*, int_T)': \Joystickexperiments\XboxController_wrapper.cpp:52:12: error: declaration of 'real_T* axes' shadows a parameter real_T *axes = (real_T *) ssGetOutputPortRealSignal(S, 0);

and

In file included from C:\Program Files\Matlab\R2019a/simulink/include/simstruc_internal.h:14:0, from C:\Program Files\Matlab\R2019a/simulink/include/simstruc.h:4560, from \Joystickexperiments\XboxController_wrapper.cpp:16: \Joystickexperiments\XboxController_wrapper.cpp:131:61: error: 'S' was not declared in this scope real_T *Controller_ID = (real_T *) mxGetPr(ssGetSFcnParam(S,0)); ^

I named the three outputs axes, buttons, info (not specified in your list, size not specifed either)

The first error disappeared when I checked the box "Enable access to Simstruct"

The second error disappeared when I changed names to axes1,buttons1,info1,Controller_ID1, and then it appears to compile, but linking failed?

### 'XboxController.cpp' created successfully ### 'XboxController_wrapper.cpp' created successfully C:\Users\johlo46\AppData\Local\Temp\mex_1877586813183704_10360\XboxController_wrapper.obj: In functionXInput_Controller::GetState()': /Joystickexperiments/XInput_Controller.cpp:57: undefined reference to XInputGetState' C:\Users\johlo46\AppData\Local\Temp\mex_1877586813183704_10360\XboxController_wrapper.obj: In functionXInput_Controller::IsConnected()': Joystickexperiments/XInput_Controller.cpp:92: undefined reference to XInputGetState' C:\Users\johlo46\AppData\Local\Temp\mex_1877586813183704_10360\XboxController_wrapper.obj: In functionXInput_Controller::GetBatteryLevel()': /Joystickexperiments/XInput_Controller.cpp:112: undefined reference to XInputGetBatteryInformation' C:\Users\johlo46\AppData\Local\Temp\mex_1877586813183704_10360\XboxController_wrapper.obj: In functionXInput_Controller::SetForceFeedback(double, double)': /Joystickexperiments/XInput_Controller.cpp:243: undefined reference to XInputSetState' collect2.exe: error: ld returned 1 exit status

I've placed the XInput_Controller .cpp and .h in the directory where I am working , and that directory is in the path

Appreciate all ideas....

MatVo1992 commented 5 years ago

Hi again,

To your first and second problem: I forgot to mention, that you dont need to copy the variable initialization. They are declared in the S-Function Builder tab and not in the method again. First error seems to be double declaration. (Error disappears after rename varaibels axes -> axes1) Second error is unnecessary, because SimStruc doesnt need to be called at all. (Dont need ssGetOutputPortRealSignal and so on)

I think the third error is due to the compiler. For compiling the XInput API you need the DirectX SDK. Do you have that installed (in Visual Studio) ?

I just compiled it myself real quick. There should be a new folder in the repository.

Let me know if it works now.

johanlofberg commented 5 years ago

Nope, cannot get it to work (compiles nicely in standard S-function)

Can you send the test slx you created to johan.lofberg@liu.se and I would be very grateful.

MatVo1992 commented 5 years ago

The .slx is in the folder _SFun_Builder_version/XInput_Controller_SFunBuilder.slx It works on my PC. What are your MATLAB /Visual Studio versions? Can you share the Error report?

johanlofberg commented 5 years ago

Indeed appears to be a consequence of us using the mingw-w64 compiler (it includes xinput.h file etc so somehow I guess it is supposed to work)

MatVo1992 commented 5 years ago

I am no expert on compilers but i think it should work, but only if you can get all the Software Develpment Kits needed for xinput. Also i am not sure if you need to compile the Xbox Controller block at all, since you can download the compiled .mexw64 files here.

That brings me back to my initial idea: split your model in two models. 1 running on windows (using the precompiled block from here) and 1 running on your arduino.

johanlofberg commented 5 years ago

The problem is that I wanted to see if this could be done using a minimal amount of stuff, combined with the fact that we are running things in external mode thus having communication channels already.

A trivial hack was to have one model with a joystick block which simply wrote into constant blocks of the model communicating with the Arduino. Sort of worked but had too much lag (we are talking large-scale student labs with an already available hardware infrastructure, so avoiding to add anything which can fail such as wifi or bluetooth or even an extra simulink model is priceless)

Yes, I am using the mexw64, but it fails in this combined mode as it appears it has to be in-lined level 2 S-function for it to compile when compiling the whole thing for external mode communication with the arduino or something like that (not at the office and cannot remember the error message)

johanlofberg commented 5 years ago

Got it to compile now with mingw by hard-coding some directories for the xinput.lib files, so something fishy with paths on this machine.

I also have sufficient performance via the two scheme hack (tries various udp strategies etc but they simply don't work with real-time external model).

Good enough for now!