ROS与Matlab语言入门教程-基本ROS消息的使用
在ROS数据交换中消息是最主要的容器,主题(通过发布器和订阅器交换数据)和服务(请求和提供服务)都是使用消息在节点之间传递数据。每个消息都有消息类型来确认数据结构,例如,激光扫描仪的传感器数据通常以“typesensor_msgs/LaserScan”的消息类型传递。每一个消息类型都确定了包含在消息中的数据元素。每个消息类型的名称都由包名、斜杠“/”和类型名组成
MATLAB支持在机器人学应用领域常见的许多ROS消息类型,在本例中,你将会在MATLAB中尝试几种创建、探索和发布ROS消息的方法。预备知识:1.2开始使用ROS和1.3连接到ROS网络。
查找消息类型
初始化ROS主控节点和全局变量。代码运行如下:
rosinit Initializing ROS master onhttp://bat5136glnxa64.mathworks.com:11311/.
Initializing global node /matlab_global_node_8332 with NodeURIhttp://bat5136glnxa64:33534/
使用“exampleHelperROSCreateSampleNetwork”指令给ROS网络填充三个节点和发布器、订阅器例子。代码运行示例:
exampleHelperROSCreateSampleNetwork
现在系统中有了若干不同的节点和主题以及相关的发布器和订阅器。你可以使用“rostopic list”查看所有可用的主题,“/scan”存在主题列表当中。
rostopic list /pose /rosout /scan
如果你想要进一步了解通过“/scan”主题传递的数据类型,可以使用“rostopic info/scan”指令检查。“/scan”的消息类型是“sensor_msgs/LaserScan”。代码运行示例:
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
探索消息结构和获取消息数据
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”能够帮助你在调试的时候,快速地查看消息中的内容。
设定消息数据
你还能够设定消息属性的值,创建“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”使用消息。查看通过发布器和订阅器交换数据和请求和提供服务的例子。
复制消息
有两种方式复制消息中的内容:
① 可以创建一个“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
保存和下载消息
你可以保存消息的内容用于后期使用。
从订阅器获得新消息:
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')
消息中的对象阵列
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
关闭ROS网络
从ROS网络中移除示例节点、发布器、订阅器:
exampleHelperROSShutDownSampleNetwork
关闭ROS主控节点并删除全局节点:
rosshutdown Shutting down global node /matlab_global_node_8332 with
NodeURIhttp://bat5136glnxa64:33534/Shutting down ROS master
onhttp://bat5136glnxa64.mathworks.com:11311/
获取最新文章: 扫一扫右上角的二维码加入“创客智造”公众号