Work with ROS Messages in Simulink®
This example illustrates how to work with complex ROS messages in Simulink, such as messages with nested sub-messages and variable-length arrays.
ROS messages are represented as bus signals in Simulink. Each field of a ROS message is mapped to a corresponding field in a Simulink bus, with the following limitations:
- Constants are not supported, and are excluded from the Simulink bus.
- 64-bit Integers (ROS types int64 and uint64) are converted to doubles in the Simulink bus, as Simulink does not natively support 64-bit integer datatypes.
- Variable-length arrays (ROS type ...) are converted to fixed-length array with customizable maximum lengths. By default, the fixed length is 128 for primitive types (e.g., uint8, float32), and 16 for nested arrays of messages (e.g., geometry_msgs/Point).
- Strings (ROS type string) are converted to fixed-length uint8 arrays with customizable maximum lengths, with a default maximum length of 128 characters.
- String arrays (ROS type string) are converted to a fixed-length array of std_msgs/String with a customizable maximum length. The default maximum length is 16 strings.
When a Simulink bus is converted to a ROS message, the message fields are restored to their native ROS types. For example, the ROS message type std_msgs/Header has a field, FrameId, which is a string. In the corresponding Simulink bus, the FrameId field is a uint8 array. When the bus is converted to a ROS message, FrameId is converted back to a string.
The following model has several examples of working with complex ROS messages in Simulink. The rest of the tasks in this example focus on specific scenarios.
Task 1 - Access Data in a Variable-length Array
A ROS message can have arrays whose length (number of elements) cannot be pre-determined. For example, the Position field in a sensor_msgs/JointState message is a variable-length array of 64-bit floats. In any given sensor_msgs/JointState message, the Position array can have no elements or it can have an arbitrarily large number of elements. In Simulink, such arrays are required to have a maximum length.
In this task, you will explore how variable-length arrays in ROS messages are handled in Simulink.
1. Open the example model, and double-click on the Work with Variable-length Arrays subsystem. Note that the Subscribe block is configured to receive messages sent to topic "my_joint_topic", of type "sensor_msgs/JointState".
2. Click on Simulation > Update Diagram, then double-click on the Bus Selector block. There are three variable-length arrays in the message (Position, Velocity, and Effort). Observe that there is a Position_SL_Info field in the bus.
- Position_SL_Info.ReceivedLength holds the length of the Position array in the original received ROS message. This value can be arbitrarily large.
- Position_SL_Info.CurrentLength holds the length of the Position array in the Simulink bus signal. This can vary between 0 and the maximum length of the array (128, in this case).
3. Click on Tools > ROS > Configure Network Addresses, and set ROS Master and Node Host network addresses to Default.
4. Type rosinit at the MATLAB® command line.
5. Set the simulation stop time to inf, and click the Play button to start simulation.
6. Execute the following at the MATLAB command line.
[pub, msg] = rospublisher('/my_joint_state', 'sensor_msgs/JointState'); msg.Position = [11:2:25]; % array of length 8 send(pub, msg);
- In the Simulink model, observe the Display outputs in the Work with Variable-length Arrays subsystem. Note that Current Length and Received Length are equal.
7. Execute the following at the MATLAB command line.
msg.Position = 1:130; % array of length 130 send(pub, msg);
- Observe that a warning is emitted, indicating that a truncation has happened. In the Simulink model, observe that the Received Length is now 130 and Current Length is 128.
- The truncation warning is shown at the command line because the message is being sent interactively. In general, these warnings are routed to the Simulink Diagnostic Viewer (see docid:simulink_ug.btyonb5).
Task 2 - Modify Maximum Size of a Variable-length Array
In this task, you will change the maximum size of a variable-length array in Simulink. As shown in Task 1, the default maximum of the Position array in the sensor_msgs/JointState message type is 128. You will change this limit to 256.
1. Open the example model, and double-click on the Work with Variable-length Arrays subsystem.
2. Click on Tools > Robot Operating System > Manage Array Sizes.
3. From the listbox on the left, click on sensor_msgs/JointState. Then, unselect the checkbox for Use default limits for this message type. Finally, enter the new value (256) in the row for the Position array property, and click OK to close the dialog.
4. Click the Play button in Simulink to start simulation.
5. Copy and paste the following at the MATLAB command line. Observe that a warning is not emitted.
msg.Position = 1:200; % array of length 200 send(pub, msg);
6. Copy and paste the following at the MATLAB command line. Observe that a warning is emitted.
msg.Position = 1:300; % array of length 300 send(pub, msg);
7. Close the model without saving.
- The maximum size information applies to all instances of the sensor_msgs/JointState message type. For example, if other messages used in the model include a sensor_msgs/JointState message, the updated limit of 256 will apply to all those nested instances as well.
- The maximum size information is specific to the model, and is saved with the model. You can have two models open that use sensor_msgs/JointState, with one model using the default limit of 128, and another using a custom limit of 256.
Task 3 - Work with Messages Using MATLAB Function Block
The Bus Assignment block in Simulink does not support assigning to an element inside an array of buses.
For example, a geometry_msgs/PoseArray message has a Poses property, which is required to be an array of geometry_msgs/Pose messages. If you want to assign to specific elements of the Poses array, that is not possible with the Bus Assignment block.
In this task, you will explore how to use the MATLAB Function block for advanced message manipulation such as assignment of nested messages.
1. Open the example model. Select the Work with Nested Arrays of Messages subsystem and select Edit > Copy.
2. Open a new Simulink model. Select Edit > Paste. Save the new model to a temporary location, with the name FunctionTest.slx.
3. Close all models, and clear the base workspace by typing clear
4. Open the FunctionTest.slx model, double-click on the Work with Nested Arrays of Messages subsystem, and open the MATLAB Function - Assign block. Observe that it uses MATLAB notation to assign values inside a nested array.
5. The Function Block requires the datatype of bus outputs (in this case, msg) to be explicitly specified. First create all buses required for this model by typing the following at the MATLAB command line. Note that the bus objects are created in the MATLAB workspace using the name SL_Bus_<modelname>_<messageType> (this may be abbreviated if the model name is too long).
6. Double-click on the MATLAB Function - Assign block. In the MATLAB Editor, click on Edit Data. In Ports and Data Manager, select msg, set its type to SL_Bus_FunctionTest_geometry_msgs_PoseArray. Click Apply and close Ports and Data Manager.
- If you do not see SL_Bus_FunctionTest_geometry_msgs_PoseArray listed as an option in the data type dropdown, select -- Refresh data types --.
7. Click on Tools > ROS > Configure Network Addresses, and set ROS Master and Node Host network addresses to Default.
8. Type rosinit at the MATLAB command line.
9. Set simulation stop time to 1.0, and click the Play button to run the simulation. Verify that the values in the Display blocks are equal to pi/2 and pi/2 + 1.
The robotics.ros.createSimulinkBus(gcs) statement has to be re-run each time the model is loaded or if the workspace is cleared. To avoid these issues, include this statement in the InitFcn callback for the model (see docid:simulink_ug.btoznm0).
Task 4 - Work with String Arrays
A string array in a ROS message is represented in Simulink as an array of std_msgs/String messages. Each std_msgs/String message has a Data property that has the actual characters in the string. Each string is represented as an array of uint8 values.
By default, the maximum number of std_msgs/String messages in a string array is 16, and the maximum length of an individual string is 128 characters. The following steps show how to change these defaults:
1. Open the example model, and double-click on the Work with Strings and String Arrays subsystem.
2. Click on Tools > Robot Operating System > Manage Array Sizes.
3. In the "Message types in model" column, click on the sensor_msgs/JointState entry. Observe that the right-hand pane shows a Name property that is an array of std_msgs/String, with a maximum length of 16. To change the maximum number of strings in Name, deselect the "Use default limits for this message type" checkbox and enter the desired value.
4. In the "Message types in model" column, click on the std_msgs/String entry. Observe that the right-hand pane shows a Data property that is an array of uint8, with a maximum length of 128. To change the maximum length of the string, deselect the "Use default limits for this message type" checkbox and enter the desired value.
5. Once you change the default values, open the Work with Strings and String Arrays subsystem and simulate the model. The Display blocks should now reflect the updated maximum values.
NOTE: The maximum length of Data applies to all instances of std_msgs/String in the model. For example, the Blank String block in Work with Strings and String Arrays subsystem uses a std_msgs/String message, so these messages would inherit the updated maximum length. Likewise, if the model has another ROS message type with a string array property, the individual strings in that array will also inherit the updated maximum length.
This example showed you how to extract signals from a complex ROS message and how to assign signals to it. It also showed you how extract data from variable-length arrays and update the maximum sizes of the arrays.