1.5 基本ROS消息的使用
1.5.1 引言
在ROS数据交换中消息是最主要的容器,主题(通过发布器和订阅器交换数据)和服务(请求和提供服务)都是使用消息在节点之间传递数据。
每个消息都有消息类型来确认数据结构,例如,激光扫描仪的传感器数据通常以“typesensor_msgs/LaserScan”的消息类型传递。每一个消息类型都确定了包含在消息中的数据元素。每个消息类型的名称都由包名、斜杠“/”和类型名组成,如下图5.1所示。
图5.1
MATLAB支持在机器人学应用领域常见的许多ROS消息类型,在本例中,你将会在MATLAB中尝试几种创建、探索和发布ROS消息的方法。
预备知识:开始使用ROS和连接到ROS网络。
1.5.2 查找消息类型
初始化ROS主控节点和全局变量。代码运行如下:rosinit
Initializing ROS master on
http://bat5136glnxa64.mathworks.com:11311/
. Initializing global node /matlab_global_node_8332 with NodeURI
http://bat5136glnxa64:33534/
使用“exampleHelperROSCreateSampleNetwork”指令给ROS网络填充三个节点和发布器、订阅器例子。代码运行示例:exampleHelperROSCreateSampleNetwork
现在系统中有了若干不同的节点和主题以及相关的发布器和订阅器。
你可以使用“rostopic list”查看所有可用的主题,“/scan”存在主题列表当中。rostopic list /pose /rosout /scan
如果你想要进一步了解通过“/scan”主题传递的数据类型,可以使用“rostopic info/scan”指令检查。“/scan”的消息类型是“sensor_msgs/LaserScan”。代码运行示例:rostopic info /scan Type: sensor_msgs/LaserScan
Publishers:
/node_3 (
http://bat5136glnxa64:41995/
)
Subscribers:
/node_1 (
http://bat5136glnxa64:37841/
)
/node_2 (
http://bat5136glnxa64:55609/
)
该指令的输出还可以看出哪些节点发布和订阅该主题,学习更多有关发布器和订阅器,请查阅通过发布器和订阅器交换数据。
为了查找更多有关主题的消息类型,可通过创建相同类型的空消息,使用“rosmessage”函数:scandata = rosmessage('sensor_msgs/LaserScan') scandata =
ROS LaserScan message with properties:
MessageType: 'sensor_msgs/LaserScan'
Header: [1x1 Header]
AngleMin: 0
AngleMax: 0
AngleIncrement: 0 TimeIncrement: 0 ScanTime: 0 RangeMin: 0 RangeMax: 0 Ranges: [0x1 single] Intensities: [0x1 single]
创建的消息“scandata”拥有许多与激光扫描仪接收的数据相关的属性,例如,最小的传感器距离存在“RangeMin”属性,最大传感器距离存储在“RangeMax”属性。
如果你想要定义消息的类型,可以使用“rostype”指令,该指令可以方便的使用一系列消息类型。“rostype”支持tap键填充指令并能够寻找与先前的字符创匹配的消息类型。代码运行示例:scantype = rostype.sensor_msgs_LaserScan scantype =
sensor_msgs/LaserScan
使用这个字符串,可以创建一个与之前的消息相同类型的空消息:scandata = rosmessage(scantype) scandata =
ROS LaserScan message with properties:
MessageType: 'sensor_msgs/LaserScan'
Header: [1x1 Header]
AngleMin: 0
AngleMax: 0
AngleIncrement: 0
TimeIncrement: 0
ScanTime: 0
RangeMin: 0
RangeMax: 0
Ranges: [0x1 single]
Intensities: [0x1 single]
使用“rosmsg list”查看主题和服务所能使用的所有消息类型:rosmsg list ackermann_msgs/AckermannDrive ackermann_msgs/AckermannDriveStamped actionlib_msgs/goalID actionlib_msgs/goalStatus actionlib_msgs/GoalStatusArray adhoc_communication/BroadcastCMgrRobotUpdate adhoc_communication/BroadcastCMgrRobotUpdateRequest adhoc_communication/BroadcastCMgrRobotUpdateResponse adhoc_communication/BroadcastString adhoc_communication/BroadcastStringRequest adhoc_communication/BroadcastStringResponse adhoc_communication/CMgrDimensions adhoc_communication/CMgrRobotUpdate adhoc_communication/ChangeMCMembership adhoc_communication/ChangeMCMembershipRequest adhoc_communication/ChangeMCMembershipResponse adhoc_communication/ExpAuction adhoc_communication/ExpCluster adhoc_communication/ExpFrontier adhoc_communication/ExpFrontierElement adhoc_communication/GetGroupState adhoc_communication/GetGroupStateRequest adhoc_communication/GetGroupStateResponse adhoc_communication/GetNeighbors adhoc_communication/GetNeighborsRequest adhoc_communication/GetNeighborsResponse adhoc_communication/MmControl adhoc_communication/MmListOfPoints adhoc_communication/MmMapUpdate adhoc_communication/MmPoint
1.5.3 探索消息结构和获取消息数据
ROS消息是对象,消息数据存储在属性里,MATLAB提供了方便的方法发现和探索消息里的内容。
如果你要订阅了“/scan”主题,你可以接收和检测被传输的数据。代码运行示例:posesub = rossubscriber('/pose') posesub =
Subscriber with properties: posesub = rossubscriber('/pose')
TopicName: '/pose'
MessageType: 'geometry_msgs/Twist'
LatestMessage: [0x1 Twist]
BufferSize: 1
NewMessageFcn: []
使用“receive”函数,能够从订阅器获得数据,一旦接收到新的消息,函数返回并存储数据到“posedata”变量。代码运行示例:posedata = receive(posesub, 10) posedata =
ROS Twist message with properties:
MessageType: 'geometry_msgs/Twist'
Linear: [1x1 Vector3]
Angular: [1x1 Vector3]
消息的类型是“geometry_msgs/Twist”,消息中含有两个字段:“Linear”和“Angular”,你可以直接地获取消息中这些字段的值,代码运行示例:posedata.Linear ans =
ROS Vector3 message with properties:
MessageType: 'geometry_msgs/Vector3'
X: 0.0438
Y: 0.0385
Z: 0.0520
posedata.Angular ans =
ROS Vector3 message with properties:
MessageType: 'geometry_msgs/Vector3'
X: -0.0288
Y: 0.0484
Z: 0.0528
显然,消息中的字段的每一个数值事实上本身也是个消息,消息类型是“geometry_msgs/Vector3”。“ geometry_msgs/Twist”的消息由两个“geometry_msgs/Vector3”类型的消息组成。
获得这些嵌套的消息的方法其实和获得其它消息一样,例如,获得“Linear”的组成“X”的指令:xpos = posedata.Linear.X xpos =
0.0438
“showdetails”函数可以快速的查看消息中包含的全部数据,“showdetails”对所有消息类型均可用,并且循环地显示消息的数据属性。
showdetails(posedata)Linear X : 0.0438049105 Y : 0.03847741206 Z : 0.052015073 Angular X : -0.02882663895 Y : 0.04838687119 Z : 0.05278724967
“showdetails”能够帮助你在调试的时候,快速地查看消息中的内容。
1.5.4 设定消息数据
你还能够设定消息属性的值,创建“geometry_msgs/Twist”类型的消息:twist = rosmessage(rostype.geometry_msgs_Twist) twist =
ROS Twist message with properties:
MessageType: 'geometry_msgs/Twist'
Linear: [1x1 Vector3]
Angular: [1x1 Vector3]
消息的属性值会被默认设置为“0”,你可以任意的修改消息的属性值,例如设置“Linear.Y”的值为5。twist.Linear.Y = 5;
显示消息的数据确认所做的修改的效果:twist.Linear ans =
ROS Vector3 message with properties:
MessageType: 'geometry_msgs/Vector3'
X: 0
Y: 5
Z: 0
一旦消息被填充数据,你可以通过“publishers”,“ subscribers”,“ services”使用消息。查看通过发布器和订阅器交换数据和请求和提供服务的例子。
1.5.5 复制消息
有两种方式复制消息中的内容:
① 可以创建一个“reference copy”,复制的消息和原消息共享同样的数据
② 可以创建一个“deep copy”,复制的消息和原消息拥有各自的消息。
当想要在不同的函数和对象之间共享消息数据时,“reference copy”是非常有用的,而如果你想要独立的复制消息,“deep copy”是必须的方法。
使用赋值符“=”创建“reference copy”,这种方法创建的变量与原变量拥有一样的消息内容。代码运行示例:twistCopyRef = twist twistCopyRef =
ROS Twist message with properties:
MessageType: 'geometry_msgs/Twist'
Linear: [1x1 Vector3]
Angular: [1x1 Vector3]
修改“twistCopyRef”的字段“Linear.Z”,发现“twist”中的相应字段的内容也发生变化:twistCopyRef.Linear.Z = 7; twist.Linear ans =
ROS Vector3 message with properties:
MessageType: 'geometry_msgs/Vector3'
X: 0
Y: 5
Z: 7
创建一个“twist”的“deep copy”,这样在改变复制消息的内容的时候不会影响原数据。使用“copy”指令创建新消息“twistCopyDeep”:twistCopyDeep = copy(twist) twistCopyDeep =
ROS Twist message with properties:
MessageType: 'geometry_msgs/Twist'
Linear: [1x1 Vector3]
Angular: [1x1 Vector3]
修改“twistCopyDeep”消息的字段“Linear.X”的内容,注意到“twist”中相应的字段没有变化:twistCopyDeep.Linear.X = 100; twistCopyDeep.Linear ans =
ROS Vector3 message with properties:
MessageType: 'geometry_msgs/Vector3'
X: 100
Y: 5
Z: 7
twist.Linear ans =
ROS Vector3 message with properties:
MessageType: 'geometry_msgs/Vector3'
X: 0
Y: 5
Z: 7
1.5.6 保存和下载消息
你可以保存消息的内容用于后期使用。
从订阅器获得新消息:posedata = receive(posesub,10) posedata =
ROS Twist message with properties:
MessageType: 'geometry_msgs/Twist'
Linear: [1x1 Vector3]
Angular: [1x1 Vector3]
使用MATLAB的“save”函数,保存姿态数据到.mat文件。save('posedata.mat','posedata')
在重新加载文件到工作空间之前,清除“posedata”变量:clear posedata
现在可以调用“load”函数载入消息数据,上述“posedata”数据将被载入“messageData”结构中,“posedata”是该结构的数据字段:messageData = load('posedata.mat') messageData =
posedata: [1x1 Twist]
检查“messageData.posedata”查看消息的内容:messageData.posedata ans =
ROS Twist message with properties:
MessageType: 'geometry_msgs/Twist'
Linear: [1x1 Vector3]
Angular: [1x1 Vector3]
删除MAT文件的方法如下:delete('posedata.mat')
1.5.7 消息中的对象阵列
ROS中的一些消息存放在对象阵列中,这与典型的数据阵列不同。
在工作空间中,“tf”变量包含了一些样本消息(“exampleHelperROSCreateSampleNetwork”脚本创建该变量),本例中,这是一个表示坐标变换的:tf tf =
ROS tfMessage message with properties:
MessageType: 'tf/tfMessage'
Transforms: [53x1 TransformStamped]
“tf”拥有两个字段:“MessageType”包含了标准的数据阵列,“Transforms”包含了对象阵列。“Transforms”里包含了53个对象,每一个对象具有相同的结构。
展开“tf”的“Transforms“查看其结构:tf.Transforms ans =
53x1 ROS TransformStamped message array with properties:
MessageType
Header
ChildFrameId
Transform
从代码的运行输出可以看出,“Transforms”里的每一个对象都有四个属性,查看其中的“Transform”字段:tf.Transforms.Transform ans =
ROS Transform message with properties:
MessageType: 'geometry_msgs/Transform'
Translation: [1x1 Vector3]
Rotation: [1x1 Quaternion]
Use showdetails to show the contents of the message
ans =
ROS Transform message with properties:
MessageType: 'geometry_msgs/Transform'
Translation: [1x1 Vector3]
Rotation: [1x1 Quaternion]
Use showdetails to show the contents of the message
ans =
ROS Transform message with properties:
MessageType: 'geometry_msgs/Transform'
Translation: [1x1 Vector3]
Rotation: [1x1 Quaternion]
...
注意,得到53个独立的输出,因为每一个对象都被评估并返回各自的“Transform”字段的值。这种格式并不总是有效,你可以转换如下的方法:cellTransforms = {tf.Transforms.Transform} cellTransforms =
Columns 1 through 4
[1x1 Transform] [1x1 Transform] [1x1 Transform] [1x1 Transform]
Columns 5 through 8
[1x1 Transform] [1x1 Transform] [1x1 Transform] [1x1 Transform]
Columns 9 through 12
[1x1 Transform] [1x1 Transform] [1x1 Transform] [1x1 Transform]
Columns 13 through 16
[1x1 Transform] [1x1 Transform] [1x1 Transform] [1x1 Transform]
Columns 17 through 20
[1x1 Transform] [1x1 Transform] [1x1 Transform] [1x1 Transform]
Columns 21 through 24
[1x1 Transform] [1x1 Transform] [1x1 Transform] [1x1 Transform]
Columns 25 through 28
[1x1 Transform] [1x1 Transform] [1x1 Transform] [1x1 Transform]
...
该方法将53个对象实体放到一个单元阵列中,这允许用户通过索引的方式访问每个对象实体。
此外,用户还可用访问标准的MATLAB向量的方法访问对象阵列的元素。tf.Transforms(5) ans =
ROS TransformStamped message with properties:
MessageType: 'geometry_msgs/TransformStamped'
Header: [1x1 Header]
ChildFrameId: '/imu_link'
Transform: [1x1 Transform]
用户可以通过下述方法访问单个阵列元素的属性:tf.Transforms(5).Transform.Translation ans =
ROS Vector3 message with properties:
MessageType: 'geometry_msgs/Vector3'
X: 0.0599
Y: 0
Z: -0.0141
1.5.8 关闭ROS网络
从ROS网络中移除示例节点、发布器、订阅器:exampleHelperROSShutDownSampleNetwork
关闭ROS主控节点并删除全局节点:rosshutdown Shutting down global node /matlab_global_node_8332 with NodeURI
http://bat5136glnxa64:33534/
Shutting down ROS master on
http://bat5136glnxa64.mathworks.com:11311/
.
1.5.9 下一步
如何处理图像、点云和激光扫描仪的消息,1.6 专业ROS消息的使用(下回分解)。
转自公众号:
Robot404