S-Function Block:
Let us now look at the Simulink S-Function in some detail. This is the part of Simulink which handles communication with BeamNG and controls execution in SImulink appropriately. Figure 5 gives an overview of how the S-function has been implemented.
Figure 5: The Simulink S-Function
Inputs and Outputs:
The BeamNG S-function block is shown in Figure 6. The inputs are controlled with a message of fixed format, and the outputs are controlled with another message with a different fixed format. These are both described below in detail.
The input section is split into a core block (containing the core powertrain/vehicle system properties) and a custom block, which can be used by the user to bring any other desired data from BeamNG to Simulink.
The output section contains eight blocks:
The driver controls section has signals for; throttle, brake, clutch, parking brake, and steering.
The body state section has signals for; position, velocity, acceleration, ground speed, roll, pitch, yaw, and altitude.
The status section has signals for; ignition level, gear, fuel, engine load, high beam, low beam, maximum RPM, reverse, RPM, signal L, signal R, and wheel speed.
The wheel sections have signals for each wheel of the vehicle; including angular velocity, wheel speed, braking torque, propulsion torque, friction torque, and downforce.
Finally, the custom section (on the input and output sides) has up to 50 user-defined signals.
The S-function is designed to transfer data between Simulink and BeamNG using these fixed messaged, where every variable always exists at the same position in the message for every send/receive. These signals are contiguous arrays of double-precision numbers.
BeamNG → Simulink Message (Fixed Format):
Bank A: Core Driver Control
Bank | Name | Range |
---|---|---|
A1 | throttle | [0,1] |
A2 | throttle_input | [0,1] |
A3 | brake | [0,1] |
A4 | brake_input | [0,1] |
A5 | clutch | [0,1] |
A6 | clutch_input | [0,1] |
A7 | parkingbrake | [0,1] |
A8 | parkingbrake_input | [0,1] |
A9 | steering | [-1,1] |
A10 | steering_input | [-1, 1] |
Bank B: Vehicle Kinematics
Bank | Name | Range |
---|---|---|
B1 | posX | m |
B2 | posY | m |
B3 | posZ | m |
B4 | velX | m/s |
B5 | velY | m/s |
B6 | velZ | m/s |
B7 | groundspeed | m/s |
B8 | accX | m/s² |
B9 | accY | m/s² |
B10 | accZ | m/s² |
B11 | roll | rad |
B12 | pitch | rad |
B13 | yaw | rad |
B14 | altitude | m |
Bank C: Secondary Vehicle Properties
Bank | Name | Range |
---|---|---|
C1 | ignitionLevel | [0, 1, 2, 3] |
C2 | gear | TBD |
C3 | fuel | [0,1] |
C4 | engineLoad | [0,1] |
C5 | highbeam | [0,1] |
C6 | lowbeam | [0,1] |
C7 | maxrpm | 1/min |
C8 | reverse | [0,1] |
C9 | rpm | 1/min |
C10 | signal_L | [0 or 1] |
C11 | signal_R | [0 or 1] |
C12 | wheelspeed | m/s |
Bank D: Wheel FL (Front-Left)
Bank | Name | Range |
---|---|---|
D1 | wheelFL_angularVelocity | rad/s |
D2 | wheelFL_wheelSpeed | m/s |
D3 | wheelFL_brakingTorque | Nm |
D4 | wheelFL_propulsiontorque | Nm |
D5 | wheelFL_frictionTorque | Nm |
D6 | wheelFL_downForce | Nm |
Bank E: Wheel FR (Front-Right)
Bank | Name | Range |
---|---|---|
E1 | wheelFR_angularVelocity | rad/s |
E2 | wheelFR_wheelSpeed | m/s |
E3 | wheelFR_brakingTorque | Nm |
E4 | wheelFR_propulsiontorque | Nm |
E5 | wheelFR_frictionTorque | Nm |
E6 | wheelFR_downForce | Nm |
Bank F: Wheel RL (Rear-Left)
Bank | Name | Range |
---|---|---|
F1 | wheelRL_angularVelocity | rad/s |
F2 | wheelRL_wheelSpeed | m/s |
F3 | wheelRL_brakingTorque | Nm |
F4 | wheelRL_propulsiontorque | Nm |
F5 | wheelRL_frictionTorque | Nm |
F6 | wheelRL_downForce | Nm |
Bank G: Wheel RR (Rear-Right)
Bank | Name | Range |
---|---|---|
G1 | wheelRL_angularVelocity | rad/s |
G2 | wheelRL_wheelSpeed | m/s |
G3 | wheelRL_brakingTorque | Nm |
G4 | wheelRL_propulsiontorque | Nm |
G5 | wheelRL_frictionTorque | Nm |
G6 | wheelRL_downForce | Nm |
Bank H: Custom User Values
Bank | Name | |
---|---|---|
H1 | custom user values (up to 50) | |
.. | ||
H50 |
Note: Bank H contains the custom user values. These are values over which the user can manually choose properties in BeamNG and send them to Simulink. With some implementation, this could involve readings from sensors, environmental information, or anything else available in BeamNG. We leave this up to the user to decide on what to add, if required.
Simulink → BeamNG Message (Fixed Format):
Bank A: Core Vehicle Data
Bank | Name | Range |
---|---|---|
A1 | engine throttle | [0, 1] |
A2 | brake pedal | [0, 1] |
A3 | steering | [-1, 1] |
A4 | RESERVED | N/A |
A5 | wheelFL_brakingTorque | Nm |
A6 | wheelFR_brakingTorque | Nm |
A7 | wheelRL_brakingTorque | Nm |
A8 | wheelRR_brakingTorque | Nm |
A9 | wheelFL_propulsionTorque | Nm |
A10 | wheelFR_propulsionTorque | Nm |
A11 | wheelRL_propulsionTorque | Nm |
A12 | wheelRR_propulsionTorque | Nm |
A13 | drive mode | bool |
Bank B: Custom User Values
Bank | Name |
---|---|
B1 | custom user values (up to 50) |
.. | |
B50 |
Bank B contains space to allow the user to send any properties from Simulink to BeamNG. Such data could then be processed within BeamNG and used to control some custom code.
Note: for both messages, we expect all values to be double precision (8 bytes). If the user wishes to send other values (eg integer or boolean), they should be converted to double-precision before forming the message. For example, a boolean flag could be sent as 0.0 or 1.0. This is an important consideration to note since some properties are not naturally double-valued. An standard integer, for example, is only 4 bytes - adding this to the message would alter the makeup of the contiguous data in the message, and would lead to errors.
Simulink Memory Block:
We have introduced a memory block as shown in Figure 7. In Simulink, memory blocks are used to store the previous value of a signal or variable, so that it can be accessed in a subsequent iteration of the simulation. They are necessary when modeling systems with delays or feedback loops, where different parts of the model may not process at the same time. Memory blocks enable the storage and retrieval of values across multiple time steps, allowing for the implementation of feedback loops and the handling of delayed responses.
Instructions:
The Lua controller must be loaded in order to start the tight coupling. We can do this with the following three steps:
- First, bring up the Lua console debug window with the
`
key. - The vehicle should then be selected at the bottom-left of this screen (usually this will be
BeamNG - Current Vehicle
). - The following command should be typed into the command bar, to load the controller:
controller.loadControllerExternal('tech/vehicleSystemsCoupling', 'vehicleSystemsCoupling', {})
Figure 8 shows the bar at the bottom of the console window in detail. Note the vehicle selection menu on the left, and the command bar on the right, where one can enter commands.
The Simulink process should also be started. If BeamNG is not running, Simulink will block its execution until it receives a message from BeamNG. The reverse is also true; if Simulink is not executing, BeamNG will block execution.
When communication has been established over the UDP send and recieve sockets (after both ends of the communication have start executing), the tight coupling process will commence.
Figure 8: The Console Window Command Bar
Examples:
We have provided some Simulink code examples to help the user see the BeamNG-Simulink coupling in action. If the user wishes to execute these examples, the three control parameters described in this document (window width, send wait, send offset) should be set up appropriately. The examples can be found in the repository, and are briefly described below:
Figure 9: The controller function of the Simulink model
Example #1:
The user is able to test a basic controller to maintain the speed limit at using pedals of the vehicle. The speed limit can be edited speed_input constant as shown in Figure 9. Switching the vehicle control from torque to pedal by the toggle switch at the bottom of the model.
Example #2:
The user is able to test a basic controller to maintain the speed limit using only the wheel torque. User can switch from the torque control by using the toggle switch at the bottom of the model in Figure 9.
Example #3:
The user is able to test a basic controller to maintain an angle of the vehicle in the map using Desired_steering_angle_input constant as shown in Figure 9. switching the vehicle control from torque to pedal by the toggle switch at the bottom of the model.