ROS-MATLAB Communication
In this section, you will learn how to connect two powerful environments: MATLAB and ROS. The knowledge that you will gain in this section will be highly used in the Open Manipulator Lab and in your semester project.
The ROS-Matlab communication is way easier than many of you might think. What you need is just MATLAB ROS Toolbox. Please make sure that you have the toolbox installed: Home > Add-Ons > Manage Add-Ons:
Prepare Virtual Machine
Connections
- Select your virtual machine on the left bar
- Click Edit virtual machine settings
- Select Network Adapter
- Select the first option Bridged: Connected directly to the physical network also check the Replicate physical network connection state
- Go to Configure Adapters and ONLY select the wireless adapter which your PC has. In our case it is “Killer(R) Wi-Fi 6 AX1650 160MHz Wireless Network Adapter”
- Save everything and start your virtual machine.
Next:
- Start your virtual machine and open a new terminal: ``Ctrl + Alt + T`
- Open the .bashrc using your favorite text editor:
gedit .bashrc
- Find the line where ROS_DOMAIN_ID is set: (for me: line 121:
export ROS_DOMAIN_ID=24
) - Note the number somewhere. You will use this number in MATLAB.
Publish a topic from MATLAB
At this point, you are quite free to choose what you want to control. It can be turtlesim
, your custom robot or Open Manipulator joints. For simplicity, we will only control the turtlesim
here but the concept is the same for all.
- Start your node that you want to communicate:
ros2 run turtlesim turtlesim node
- Note the ROS topic that you want to publish/subscribe:
ros2 topic list
- Note the type of the message of this topic:
ros2 topic info /turtle1/cmd_vel
Now, go back to MATLAB and create a script. Paste the code below:
MATLAB_WORKSPACE/matlab_ros_publisher.m
test_publisher = ros2node("/test_vm_ros", 24);
cmdPub = ros2publisher(test_publisher, "turtle1/cmd_vel", "geometry_msgs/Twist");
cmdMsg = ros2message(cmdPub);
cmdMsg.linear.x = -0.2;
cmdMsg.linear.y = 0.0;
cmdMsg.linear.z = 0.0;
cmdMsg.angular.x = 0.0;
cmdMsg.angular.y = 0.0;
cmdMsg.angular.z = 0.0;
for cnt = 1:10
send(cmdPub,cmdMsg)
pause(1)
end
This script creates a node in domain number 24 and defines it as a publisher that publishes to the topic turtle1/cmd_vel
for 10 seconds. You should modify this code according to your ROS_DOMAIN_ID and the topic you want to interact.
If you want to use common ROS terminal commands such as ros2 topic list
then you can use setenv("ROS_DOMAIN_ID","24")
in your MATLAB terminal.
Subscribe a topic by MATLAB
For this part, we will use the simple publisher that we created in the ROS Intro.
- Start your publisher:
ros2 run my_package my_publisher
- Decide which topic you want to subscribe to:
ros2 topic list
,ros2 topic info
The subscriber MATLAB script would look like:
MATLAB_WORKSPACE/matlab_ros_subscriber.m
test_subscriber = ros2node("/test_vm_ros", 24);
msgSub = ros2subscriber(test_subscriber, "/topic", "std_msgs/String");
for cnt = 1:10
receivedData = receive(msgSub, 10)
end
Limitations
Imagine that you want to obtain the pose of the turtlesim on MATLAB. Then you need to subscribe to turtle1/pose
topic which has turtlesim/msg/Pose message type. This message type is not available in ROS Toolbox. There are two things that you can do in this case:
Option-1: Create a middleware node
You can create a middleware node in the ROS environment that subscribes to the exotic topic and publishes the information in it using more generic message type.
In turtle1/pose
example, th middleware node might look like this:
YOUR_PREFERED_PACKAGE/turtle_pose_converter.py
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
## Pose msg type is very common in ROS but it uses quaternions for orientation
# If you want to skip the euler to quaternion conversion
# you can use Pose2D for simplicity
from geometry_msgs.msg import Pose
from turtlesim.msg import Pose as Turtlesim_pose
import transforms3d
class myConverterNode(Node):
def __init__(self) -> None:
super().__init__("turtlesim_pose_converter")
self.sub = self.create_subscription(Turtlesim_pose, '/turtle1/pose', self.listener_callback, 10)
self.pub = self.create_publisher(Pose, '/turtle1/pose_converted', 10)
self.create_timer(1.0, self.timer_callback)
self.listened_pose = Turtlesim_pose()
self.published_pose = Pose()
def listener_callback(self, msg):
# self.get_logger().info('turtlesim pose received')
self.listened_pose = msg
def timer_callback(self):
self.published_pose.position.x = self.listened_pose.x
self.published_pose.position.y = self.listened_pose.y
self.published_pose.position.z = 0.0
q = transforms3d.euler.euler2quat(0, 0, self.listened_pose.theta, 'rxyz')
print(q[0],q[1], q[2], q[3]) # The order: q.w - q.x - q.y - q.z
self.published_pose.orientation.w = q[0]
self.published_pose.orientation.x = q[1]
self.published_pose.orientation.y = q[2]
self.published_pose.orientation.z = q[3]
self.pub.publish(self.published_pose)
self.get_logger().info('converted turtlesim pose published')
def main(args=None):
rclpy.init(args=args)
node = myConverterNode()
rclpy.spin(node)
rclpy.shutdown()
if __name__ == '__main__':
main()
And then, the MATLAB subscriber for this would be like:
MATLAB_WORKSPACE/matlab_turtlesim_pose_subscriber.m
test_subscriber = ros2node("/test_vm_ros", 24);
msgSub = ros2subscriber(test_subscriber, "/turtle1/pose_converted", "geometry_msgs/Pose");
for cnt = 1:10
poseData = receive(msgSub, 10)
poseData.position
poseData.orientation
end
Option-2: Create custom message from ROS package
This is a better and systematic option, however, it is more cumbersome. You can learn the procedure following the documentation.