0. 简介

我们在前面一节介绍了Matlab与Message的通信,而我们这一节主要来介绍发布者和订阅者在Matlab中的操作。这部分我们主要来看一下ROS1和ROS2中分别是如何使用Topic的

1. ROS1的消息订阅与发布

1.1 ROS1的消息订阅

在Matlab中一般使用rossubscriber订阅/scan主题。如果主题已经存在于ROS网络中(就像这里的情况一样),rossubscriber会自动检测它的消息类型,因此不需要指定它。为了提高效率,使用struct格式的消息。

laser = rossubscriber("/scan","DataFormat","struct");
pause(2)

然后使用receive来等待新消息。(第二个参数是一个以秒为单位的超时。)输出丑闻包含接收到的消息数据。

scandata = receive(laser,10)

scandata = struct with fields:
MessageType: ‘sensor_msgs/LaserScan’
Header: [1x1 struct]
AngleMin: -0.5467
AngleMax: 0.5467
AngleIncrement: 0.0017
TimeIncrement: 0
ScanTime: 0.0330
RangeMin: 0.4500
RangeMax: 10
Ranges: [640x1 single]
Intensities: []

某些消息类型具有与之关联的可视化方法。例如LaserScan消息,可以使用rosPlot绘制扫描数据。其中MaximumRange名称-值对指定最大绘图范围。

figure
rosPlot(scandata,"MaximumRange",7)


同时对于订阅者来说同样可以设置一个callback函数来触发,因为这样的形式允许在订阅者等待新消息时执行其他MATLAB代码。如果要使用多个订阅者,回调是必不可少的。

robotpose = rossubscriber("/pose",@exampleHelperROSPoseCallback,"DataFormat","struct")

robotpose =
Subscriber with properties:
TopicName: ‘/pose’
LatestMessage: []
MessageType: ‘geometry_msgs/Twist’
BufferSize: 1
NewMessageFcn: @exampleHelperROSPoseCallback
DataFormat: ‘struct’

在主工作区和回调函数之间共享数据的一种方法是使用全局变量。定义两个全局变量pos和orient。

global pos
global orient

当在/pose主题上接收到新的消息数据时,全局变量pos和orient exampleHelperROSPoseCallback函数中被赋值。

一般的会等待几秒钟,以确保订阅者能够收到消息。

pause(2) 
pos

pos = 1×3
-0.0133 0.0488 -0.0462

如果想要关闭订阅者,一般的操作方法是通过清除订阅者变量停止姿势订阅者

clear robotpose

这里我们举个例子,首先会创建一个名为figureCallback的新文件。m并定义一个名为figureCallback的回调函数。回调函数处理用户在图形窗口中按下键时的动作。定义回调函数以接受两个输入参数:

  • src:使用第一个参数引用正在执行回调以查找图中绘制的Line对象的特定图形。
  • event:使用第二个参数访问关于按键用户操作的特定信息。如果按下的键是+,则增加该行的宽度,如果是-,则减少该行的宽度。
function figureCallback(src,event)
line = findobj(src,"Type","Line");
if event.Character == "+"
    line.LineWidth = line.LineWidth+1;
elseif event.Character == "-"
    line.LineWidth = max(line.LineWidth-1,0.5);
end
end

在命令窗口中,创建一个图对象。使用@操作符将函数句柄分配给图形的WindowKeyPressFcn属性。当用户在图形窗口中按下一个键时执行此回调。然后,在当前图中绘制一些数据。这类一般的是通用的函数,

f = figure(WindowKeyPressFcn=@figureCallback);
plot(1:10)

如果说我们还需要添加一些其他的参数作为输入,我们创建一个displayCoordinates函数以接受事件数据输入。
src:使用第一个参数引用正在执行回调的特定图形对象。
~:使用该字符表示输入未被使用。
ax:使用第二个参数访问鼠标指针在坐标轴上的位置。

function displayCoordinates(src,~,ax)
src.MarkerEdgeColor = rand(1,3);
disp(ax.CurrentPoint(1,1:2))
end

然后,您可以使用单元格数组指定ButtonDownFcn回调属性。数组的第一个元素是displayCoordinates函数的句柄,第二个元素是在源和事件参数之后传递给displayCoordinates函数的axes对象。

ax = axes;
x = randn(100,1);
y = randn(100,1);
scatter(x,y,"ButtonDownFcn",{@displayCoordinates,ax})
% scatter(x,y,"ButtonDownFcn",@(src,event)displayCoordinates(src,event,ax))
% scatter(x,y,"ButtonDownFcn",@(src,~)displayCoordinates(src,~,ax))% 外部引入的变量

1.2 ROS1的发布消息

创建一个向/chatter主题发送ROS字符串消息的发布者

chatterpub = rospublisher("/chatter","std_msgs/String","DataFormat","struct")

chatterpub =
Publisher with properties:
TopicName: ‘/chatter’
NumSubscribers: 0
IsLatching: 1
MessageType: ‘std_msgs/String’
DataFormat: ‘struct’

pause(2) % Wait to ensure publisher is registered

创建并填充一个ROS消息以发送到/chatter话题。

chattermsg = rosmessage(chatterpub);
chattermsg.Data = 'hello world'

chattermsg = struct with fields:
MessageType: ‘std_msgs/String’
Data: ‘hello world’

向/chatter主题发布一条消息。该字符串会等待订阅者回调。

send(chatterpub,chattermsg)
pause(2)

2. ROS2的消息订阅与发布

2.1 ROS2的消息订阅

使用ros2subscriber订阅/scan主题。使用订阅者指定节点的名称。如果主题已经存在于ROS 2网络中,那么ros2subscriber会自动检测它的消息类型,因此不需要指定它。

detectNode = ros2node("/detection");
pause(5)
laserSub = ros2subscriber(detectNode,"/scan");
pause(5)

使用receive来等待新消息。指定10秒的超时时间。输出scanata包含接收到的消息数据。Status指示消息是否成功接收,statustext提供有关状态的附加信息。

[scanData,status,statustext] = receive(laserSub,10);

现在可以删除订阅者laserSub和与之关联的节点

clear laserSub
clear detectNode

同样的可以指定在接收到新消息时调用的函数,而不是使用receive来获取数据。这允许在订阅者等待新消息时执行其他MATLAB代码。如果要使用多个订阅者,回调是必不可少的。在主工作区和回调函数之间共享数据的一种方法是使用全局变量。

controlNode = ros2node("/base_station");
pause(5)
poseSub = ros2subscriber(controlNode,"/pose",@exampleHelperROS2PoseCallback);
global pos
global orient

当在/pose主题上接收到新的消息数据时,全局变量pos和orient在exampleHelperROS2PoseCallback函数中被赋值。

function exampleHelperROS2PoseCallback(message)    
    % Declare global variables to store position and orientation
    global pos
    global orient

    % Extract position and orientation from the ROS message and assign the
    % data to the global variables.
    pos = [message.linear.x message.linear.y message.linear.z];
    orient = [message.angular.x message.angular.y message.angular.z];
end

然后网络将发布另一条/pose消息。显示更新后的值。

pause(3)
disp(pos)

-0.0398 -0.0109 -0.0445

2.2 ROS2的消息发布

创建一个向/chatter主题发送ROS 2字符串消息的发布者

chatterPub = ros2publisher(node_1,"/chatter","std_msgs/String");

创建并填充一个ROS 2消息,发送到/chatter主题。

chatterMsg = ros2message(chatterPub);
chatterMsg.data = 'hello world';

向/chatter主题发布一条消息。该字符串会等待订阅者回调。

send(chatterPub,chatterMsg)
pause(3)

3. 参考链接

https://ww2.mathworks.cn/help/ros/ug/exchange-data-with-ros-publishers-and-subscribers.html