|
| 1 | +function hebijoyinput(block) |
| 2 | + % hebijoyinput is a HebiJoystick implementation for Simulink |
| 3 | + % |
| 4 | + % hebijoyinput is an alternative to MathWorks's 'Joystick Input' |
| 5 | + % block from 'Simulink 3D Animation' toolbox. 'hebijoyinput' is based |
| 6 | + % on 'HebiJoystick'. 'Simulink 3D Animation' toolbox is not required |
| 7 | + % for usage! |
| 8 | + % |
| 9 | + % See also: |
| 10 | + % HebiJoystick (https://github.com/HebiRobotics/MatlabInput) |
| 11 | + % Level-2 MATLAB S-Function (msfuntmpl) |
| 12 | + |
| 13 | + % Copyright (c) 2023 Jonas Withelm |
| 14 | + % SPDX-License-Identifier: Apache-2.0 |
| 15 | + |
| 16 | + setup(block); |
| 17 | + |
| 18 | +%endfunction |
| 19 | + |
| 20 | + |
| 21 | +function setup(block) |
| 22 | + |
| 23 | + %% Register number of dialog parameters |
| 24 | + block.NumDialogPrms = 3; % joyid |
| 25 | + block.DialogPrmsTunable = {'Nontunable','Nontunable','Nontunable'}; % not tunable during simulation |
| 26 | + |
| 27 | + %% Setup joystick |
| 28 | + joyid = block.DialogPrm(1).Data; |
| 29 | + forcefeed = block.DialogPrm(3).Data; |
| 30 | + |
| 31 | + % initialize joystick |
| 32 | + joy = HebiJoystick(joyid); |
| 33 | + |
| 34 | + % read capabilities of joystick |
| 35 | + caps = joy.caps(); |
| 36 | + |
| 37 | + % store persistent data |
| 38 | + set_param(block.BlockHandle,'UserData',joy); |
| 39 | + |
| 40 | + %% Register number of output ports |
| 41 | + block.NumOutputPorts = 2; |
| 42 | + |
| 43 | + %% Register number of input ports |
| 44 | + if forcefeed && (caps.Forces > 0) |
| 45 | + block.NumInputPorts = 1; |
| 46 | + else |
| 47 | + block.NumInputPorts = 0; |
| 48 | + end |
| 49 | + |
| 50 | + %% Set up the port properties to be inherited or dynamic |
| 51 | + block.SetPreCompInpPortInfoToDynamic; |
| 52 | + block.SetPreCompOutPortInfoToDynamic; |
| 53 | + |
| 54 | + %% Set the output port properties |
| 55 | + block.OutputPort(1).DimensionsMode = 'Fixed'; |
| 56 | + block.OutputPort(1).SamplingMode = 'sample'; |
| 57 | + block.OutputPort(1).Dimensions = caps.Axes; |
| 58 | + block.OutputPort(1).DatatypeID = 0; % double |
| 59 | + block.OutputPort(1).Complexity = 'Real'; |
| 60 | + |
| 61 | + block.OutputPort(2).DimensionsMode = 'Fixed'; |
| 62 | + block.OutputPort(2).SamplingMode = 'sample'; |
| 63 | + block.OutputPort(2).Dimensions = caps.Buttons; |
| 64 | + block.OutputPort(2).DatatypeID = 0; % double |
| 65 | + block.OutputPort(2).Complexity = 'Real'; |
| 66 | + |
| 67 | + if forcefeed && (caps.Forces > 0) |
| 68 | + block.InputPort(1).DimensionsMode = 'Fixed'; |
| 69 | + block.InputPort(1).SamplingMode = 'sample'; |
| 70 | + block.InputPort(1).Dimensions = caps.Forces; |
| 71 | + block.InputPort(1).DatatypeID = 0; % double |
| 72 | + block.InputPort(1).Complexity = 'Real'; |
| 73 | + block.InputPort(1).DirectFeedthrough = false; |
| 74 | + end |
| 75 | + |
| 76 | + %% Set up the continuous states |
| 77 | + block.NumContStates = 0; |
| 78 | + |
| 79 | + %% Set block sample time |
| 80 | + block.SampleTimes = [1/50 0]; % Discrete sample time (50 Hz) |
| 81 | + |
| 82 | + %% Set the block simStateCompliance to default (i.e., same as a built-in block) |
| 83 | + block.SimStateCompliance = 'DefaultSimState'; |
| 84 | + |
| 85 | + %% Register methods |
| 86 | + block.RegBlockMethod('Outputs', @Outputs); |
| 87 | + block.RegBlockMethod('Terminate', @Terminate); |
| 88 | + |
| 89 | +%endfunction |
| 90 | + |
| 91 | + |
| 92 | +function Outputs(block) |
| 93 | + |
| 94 | + joy = get_param(block.BlockHandle,'UserData'); |
| 95 | + |
| 96 | + caps = joy.caps(); |
| 97 | + |
| 98 | + % read force feedback from block input and send to joystick |
| 99 | + forcefeed = block.DialogPrm(3).Data; |
| 100 | + if forcefeed && (caps.Forces > 0) |
| 101 | + for idx=1:caps.Forces |
| 102 | + joy.force(idx, block.InputPort(idx).Data); |
| 103 | + end |
| 104 | + end |
| 105 | + |
| 106 | + % read axes and buttons from joystick and write to block outputs |
| 107 | + [axes, buttons, ~] = joy.read(); |
| 108 | + |
| 109 | + block.OutputPort(1).Data = axes; |
| 110 | + block.OutputPort(2).Data = buttons; |
| 111 | + |
| 112 | +%endfunction |
| 113 | + |
| 114 | + |
| 115 | +function Terminate(block) |
| 116 | + |
| 117 | + joy = get_param(block.BlockHandle,'UserData'); |
| 118 | + |
| 119 | + joy.close(); |
| 120 | + |
| 121 | +%endfunction |
0 commit comments